PI fixes and various smaller fixes
This commit is contained in:
@@ -34,9 +34,7 @@ void Scheduler::tick(u64 t, n64::Mem& mem, n64::Registers& regs) {
|
|||||||
while(ticks >= events.top().time) {
|
while(ticks >= events.top().time) {
|
||||||
switch(auto type = events.top().type) {
|
switch(auto type = events.top().type) {
|
||||||
case SI_DMA:
|
case SI_DMA:
|
||||||
si.status.dmaBusy = false;
|
|
||||||
si.DMA(mem, regs);
|
si.DMA(mem, regs);
|
||||||
InterruptRaise(mi, regs, n64::Interrupt::SI);
|
|
||||||
break;
|
break;
|
||||||
case PI_DMA_COMPLETE:
|
case PI_DMA_COMPLETE:
|
||||||
InterruptRaise(mi, regs, n64::Interrupt::PI);
|
InterruptRaise(mi, regs, n64::Interrupt::PI);
|
||||||
|
|||||||
@@ -368,7 +368,7 @@ template<> void Mem::Write<u8>(Registers& regs, u32 paddr, u32 val) {
|
|||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case REGION_CART:
|
case REGION_CART:
|
||||||
Util::debug("BusWrite<u8> @ {:08X} = {:02X}", paddr, val);
|
Util::trace("BusWrite<u8> @ {:08X} = {:02X}", paddr, val);
|
||||||
mmio.pi.BusWrite<u8, false>(*this, paddr, val);
|
mmio.pi.BusWrite<u8, false>(*this, paddr, val);
|
||||||
break;
|
break;
|
||||||
case MMIO_REGION:
|
case MMIO_REGION:
|
||||||
@@ -417,7 +417,7 @@ template<> void Mem::Write<u16>(Registers& regs, u32 paddr, u32 val) {
|
|||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case REGION_CART:
|
case REGION_CART:
|
||||||
Util::debug("BusWrite<u8> @ {:08X} = {:04X}", paddr, val);
|
Util::trace("BusWrite<u8> @ {:08X} = {:04X}", paddr, val);
|
||||||
mmio.pi.BusWrite<u16, false>(*this, paddr, val);
|
mmio.pi.BusWrite<u16, false>(*this, paddr, val);
|
||||||
break;
|
break;
|
||||||
case MMIO_REGION:
|
case MMIO_REGION:
|
||||||
@@ -464,7 +464,7 @@ template<> void Mem::Write<u32>(Registers& regs, u32 paddr, u32 val) {
|
|||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case REGION_CART:
|
case REGION_CART:
|
||||||
Util::debug("BusWrite<u8> @ {:08X} = {:08X}", paddr, val);
|
Util::trace("BusWrite<u8> @ {:08X} = {:08X}", paddr, val);
|
||||||
mmio.pi.BusWrite<u32, false>(*this, paddr, val);
|
mmio.pi.BusWrite<u32, false>(*this, paddr, val);
|
||||||
break;
|
break;
|
||||||
case MMIO_REGION:
|
case MMIO_REGION:
|
||||||
@@ -508,8 +508,8 @@ void Mem::Write(Registers& regs, u32 paddr, u64 val) {
|
|||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case REGION_CART:
|
case REGION_CART:
|
||||||
Util::debug("BusWrite<u8> @ {:08X} = {:016X}", paddr, val);
|
Util::trace("BusWrite<u8> @ {:08X} = {:016X}", paddr, val);
|
||||||
mmio.pi.BusWrite<u64, false>(*this, paddr, val);
|
mmio.pi.BusWrite<false>(*this, paddr, val);
|
||||||
break;
|
break;
|
||||||
case MMIO_REGION:
|
case MMIO_REGION:
|
||||||
Util::panic("MMIO Write!");
|
Util::panic("MMIO Write!");
|
||||||
@@ -569,7 +569,8 @@ template <> u8 Mem::BackupRead<u8>(u32 addr) {
|
|||||||
template <> void Mem::BackupWrite<u32>(u32 addr, u32 val) {
|
template <> void Mem::BackupWrite<u32>(u32 addr, u32 val) {
|
||||||
switch(saveType) {
|
switch(saveType) {
|
||||||
case SAVE_NONE:
|
case SAVE_NONE:
|
||||||
Util::panic("Accessing cartridge with save type SAVE_NONE in write word");
|
Util::warn("Accessing cartridge with save type SAVE_NONE in write word");
|
||||||
|
break;
|
||||||
case SAVE_EEPROM_4k: case SAVE_EEPROM_16k:
|
case SAVE_EEPROM_4k: case SAVE_EEPROM_16k:
|
||||||
Util::panic("Accessing cartridge with save type SAVE_EEPROM in write word");
|
Util::panic("Accessing cartridge with save type SAVE_EEPROM in write word");
|
||||||
case SAVE_FLASH_1m:
|
case SAVE_FLASH_1m:
|
||||||
@@ -585,7 +586,8 @@ template <> void Mem::BackupWrite<u32>(u32 addr, u32 val) {
|
|||||||
template <> void Mem::BackupWrite<u8>(u32 addr, u8 val) {
|
template <> void Mem::BackupWrite<u8>(u32 addr, u8 val) {
|
||||||
switch(saveType) {
|
switch(saveType) {
|
||||||
case SAVE_NONE:
|
case SAVE_NONE:
|
||||||
Util::panic("Accessing cartridge with save type SAVE_NONE in write word");
|
Util::warn("Accessing cartridge with save type SAVE_NONE in write word");
|
||||||
|
break;
|
||||||
case SAVE_EEPROM_4k: case SAVE_EEPROM_16k:
|
case SAVE_EEPROM_4k: case SAVE_EEPROM_16k:
|
||||||
Util::panic("Accessing cartridge with save type SAVE_EEPROM in write word");
|
Util::panic("Accessing cartridge with save type SAVE_EEPROM in write word");
|
||||||
case SAVE_FLASH_1m:
|
case SAVE_FLASH_1m:
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include <Mem.hpp>
|
#include <Mem.hpp>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
constexpr auto FLASH_SIZE = 1_mb;
|
constexpr auto FLASH_SIZE = 1_mb;
|
||||||
@@ -159,10 +160,11 @@ template <> void Flash::Write<u8>(u32 index, u8 val) {
|
|||||||
case FlashState::Idle: Util::panic("Invalid FlashState::Idle with Write<u8>");
|
case FlashState::Idle: Util::panic("Invalid FlashState::Idle with Write<u8>");
|
||||||
case FlashState::Status: Util::panic("Invalid FlashState::Status with Write<u8>");
|
case FlashState::Status: Util::panic("Invalid FlashState::Status with Write<u8>");
|
||||||
case FlashState::Erase: Util::panic("Invalid FlashState::Erase with Write<u8>");
|
case FlashState::Erase: Util::panic("Invalid FlashState::Erase with Write<u8>");
|
||||||
|
case FlashState::Read: Util::panic("Invalid FlashState::Read with Write<u8>");
|
||||||
case FlashState::Write:
|
case FlashState::Write:
|
||||||
|
assert(index <= 0x7F && "Out of range flash Write8");
|
||||||
writeBuf[index] = val;
|
writeBuf[index] = val;
|
||||||
break;
|
break;
|
||||||
case FlashState::Read: Util::panic("Invalid FlashState::Read with Write<u8>");
|
|
||||||
default: Util::warn("Invalid flash state on Write<u8>: {:02X}", static_cast<u8>(state));
|
default: Util::warn("Invalid flash state on Write<u8>: {:02X}", static_cast<u8>(state));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ template<> auto PI::BusRead<u8, true>(Mem& mem, u32 addr) -> u8 {
|
|||||||
case REGION_PI_ROM: {
|
case REGION_PI_ROM: {
|
||||||
// round to nearest 4 byte boundary, keeping old LSB
|
// round to nearest 4 byte boundary, keeping old LSB
|
||||||
u32 index = BYTE_ADDRESS(addr) - SREGION_PI_ROM;
|
u32 index = BYTE_ADDRESS(addr) - SREGION_PI_ROM;
|
||||||
if (index > mem.rom.size) {
|
if (index >= mem.rom.size) {
|
||||||
Util::warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM! ({}/0x{:016X})", addr, index, index, mem.rom.size, mem.rom.size);
|
Util::warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM! ({}/0x{:016X})", addr, index, index, mem.rom.size, mem.rom.size);
|
||||||
return 0xFF;
|
return 0xFF;
|
||||||
}
|
}
|
||||||
@@ -92,7 +92,7 @@ template<> auto PI::BusRead<u8, false>(Mem& mem, u32 addr) -> u8 {
|
|||||||
addr = (addr + 2) & ~2;
|
addr = (addr + 2) & ~2;
|
||||||
// round to nearest 4 byte boundary, keeping old LSB
|
// round to nearest 4 byte boundary, keeping old LSB
|
||||||
u32 index = BYTE_ADDRESS(addr) - SREGION_PI_ROM;
|
u32 index = BYTE_ADDRESS(addr) - SREGION_PI_ROM;
|
||||||
if (index > mem.rom.size) {
|
if (index >= mem.rom.size) {
|
||||||
Util::warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM! ({}/0x{:016X})", addr, index, index, mem.rom.size, mem.rom.size);
|
Util::warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM! ({}/0x{:016X})", addr, index, index, mem.rom.size, mem.rom.size);
|
||||||
return 0xFF;
|
return 0xFF;
|
||||||
}
|
}
|
||||||
@@ -103,33 +103,32 @@ template<> auto PI::BusRead<u8, false>(Mem& mem, u32 addr) -> u8 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> void PI::BusWrite<u8, true>(Mem& mem, u32 addr, u8 val) {
|
template<> void PI::BusWrite<u8, true>(Mem& mem, u32 addr, u32 val) {
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case REGION_PI_UNKNOWN:
|
case REGION_PI_UNKNOWN:
|
||||||
Util::panic("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr);
|
Util::panic("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr);
|
||||||
case REGION_PI_64DD_REG:
|
case REGION_PI_64DD_REG:
|
||||||
if (addr == 0x05000020) {
|
if (addr == 0x05000020) {
|
||||||
fprintf(stderr, "%c", val);
|
fprintf(stderr, "%c", val);
|
||||||
}
|
} else {
|
||||||
else {
|
Util::warn("Writing byte 0x{:02X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!", val, addr);
|
||||||
Util::warn("Writing byte 0x{:02X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!", val, addr);
|
}
|
||||||
}
|
break;
|
||||||
return;
|
case REGION_PI_64DD_ROM:
|
||||||
case REGION_PI_64DD_ROM:
|
Util::panic("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr);
|
||||||
Util::panic("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr);
|
case REGION_PI_SRAM:
|
||||||
case REGION_PI_SRAM:
|
mem.BackupWrite<u8>(addr - SREGION_PI_SRAM, val);
|
||||||
mem.BackupWrite<u8>(addr - SREGION_PI_SRAM, val);
|
break;
|
||||||
return;
|
case REGION_PI_ROM:
|
||||||
case REGION_PI_ROM:
|
Util::warn("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr);
|
||||||
Util::warn("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr);
|
break;
|
||||||
return;
|
default:
|
||||||
default:
|
Util::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr);
|
||||||
Util::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> void PI::BusWrite<u8, false>(Mem& mem, u32 addr, u8 val) {
|
template<> void PI::BusWrite<u8, false>(Mem& mem, u32 addr, u32 val) {
|
||||||
int latch_shift = 24 - (addr & 1) * 8;
|
u8 latch_shift = 24 - (addr & 1) * 8;
|
||||||
|
|
||||||
if (!WriteLatch(val << latch_shift) && addr != 0x05000020) [[unlikely]] {
|
if (!WriteLatch(val << latch_shift) && addr != 0x05000020) [[unlikely]] {
|
||||||
return;
|
return;
|
||||||
@@ -169,7 +168,7 @@ template <> auto PI::BusRead<u16, true>(Mem& mem, u32 addr) -> u16 {
|
|||||||
return BusRead<u16, false>(mem, addr);
|
return BusRead<u16, false>(mem, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <> void PI::BusWrite<u16, false>(Mem&, u32 addr, u16 val) {
|
template <> void PI::BusWrite<u16, false>(Mem&, u32 addr, u32 val) {
|
||||||
if (!WriteLatch(val << 16)) [[unlikely]] {
|
if (!WriteLatch(val << 16)) [[unlikely]] {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -191,7 +190,7 @@ template <> void PI::BusWrite<u16, false>(Mem&, u32 addr, u16 val) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <> void PI::BusWrite<u16, true>(Mem& mem, u32 addr, u16 val) {
|
template <> void PI::BusWrite<u16, true>(Mem& mem, u32 addr, u32 val) {
|
||||||
BusWrite<u16, false>(mem, addr, val);
|
BusWrite<u16, false>(mem, addr, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,8 +219,7 @@ template <> auto PI::BusRead<u32, false>(Mem& mem, u32 addr) -> u32 {
|
|||||||
return htobe32(Util::ReadAccess<u32>(mem.isviewer, addr - SREGION_CART_ISVIEWER_BUFFER));
|
return htobe32(Util::ReadAccess<u32>(mem.isviewer, addr - SREGION_CART_ISVIEWER_BUFFER));
|
||||||
case CART_ISVIEWER_FLUSH:
|
case CART_ISVIEWER_FLUSH:
|
||||||
Util::panic("Read from ISViewer flush!");
|
Util::panic("Read from ISViewer flush!");
|
||||||
default:
|
default: break;
|
||||||
Util::panic("Read from unknown address {:08X} in REGION_PI_ROM!", addr);
|
|
||||||
}
|
}
|
||||||
Util::warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM!", addr, index, index);
|
Util::warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM!", addr, index, index);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -283,6 +281,7 @@ template <> void PI::BusWrite<u32, false>(Mem& mem, u32 addr, u32 val) {
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
if (!WriteLatch(val)) [[unlikely]] {
|
if (!WriteLatch(val)) [[unlikely]] {
|
||||||
|
Util::warn("Couldn't latch PI bus, ignoring write to REGION_PI_ROM");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Util::warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr);
|
Util::warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr);
|
||||||
@@ -293,7 +292,8 @@ template <> void PI::BusWrite<u32, false>(Mem& mem, u32 addr, u32 val) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <> void PI::BusWrite<u32, true>(Mem& mem, u32 addr, u32 val) {
|
template <>
|
||||||
|
void PI::BusWrite<u32, true>(Mem& mem, u32 addr, u32 val) {
|
||||||
BusWrite<u32, false>(mem, addr, val);
|
BusWrite<u32, false>(mem, addr, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,7 +327,7 @@ template <> auto PI::BusRead<u64, true>(Mem& mem, u32 addr) -> u64 {
|
|||||||
return BusRead<u64, false>(mem, addr);
|
return BusRead<u64, false>(mem, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <> void PI::BusWrite<u64, false>(Mem&, u32 addr, u64 val) {
|
template <> void PI::BusWrite<false>(Mem&, u32 addr, u64 val) {
|
||||||
if (!WriteLatch(val >> 32)) [[unlikely]] {
|
if (!WriteLatch(val >> 32)) [[unlikely]] {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -349,8 +349,8 @@ template <> void PI::BusWrite<u64, false>(Mem&, u32 addr, u64 val) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <> void PI::BusWrite<u64, true>(Mem& mem, u32 addr, u64 val) {
|
template <> void PI::BusWrite<true>(Mem& mem, u32 addr, u64 val) {
|
||||||
BusWrite<u64, false>(mem, addr, val);
|
BusWrite<false>(mem, addr, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PI::Read(MI& mi, u32 addr) const -> u32 {
|
auto PI::Read(MI& mi, u32 addr) const -> u32 {
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ struct PI {
|
|||||||
void Write(Mem&, Registers&, u32, u32);
|
void Write(Mem&, Registers&, u32, u32);
|
||||||
|
|
||||||
template<typename T, bool isDma>
|
template<typename T, bool isDma>
|
||||||
void BusWrite(Mem&, u32, T);
|
void BusWrite(Mem&, u32, u32);
|
||||||
|
template<bool isDma>
|
||||||
|
void BusWrite(Mem&, u32, u64);
|
||||||
|
|
||||||
template<typename T, bool isDma>
|
template<typename T, bool isDma>
|
||||||
auto BusRead(Mem&, u32) -> T;
|
auto BusRead(Mem&, u32) -> T;
|
||||||
|
|||||||
@@ -40,12 +40,12 @@ void SI::DMA(Mem& mem, Registers& regs) const {
|
|||||||
for(int i = 0; i < 64; i++) {
|
for(int i = 0; i < 64; i++) {
|
||||||
mem.mmio.rdp.rdram[BYTE_ADDRESS(si.dramAddr + i)] = si.pif.Read(si.pifAddr + i);
|
mem.mmio.rdp.rdram[BYTE_ADDRESS(si.dramAddr + i)] = si.pif.Read(si.pifAddr + i);
|
||||||
}
|
}
|
||||||
//Util::debug("SI DMA from PIF RAM to RDRAM ({:08X} to {:08X})", si.pifAddr, si.dramAddr);
|
Util::trace("SI DMA from PIF RAM to RDRAM ({:08X} to {:08X})", si.pifAddr, si.dramAddr);
|
||||||
} else {
|
} else {
|
||||||
for(int i = 0; i < 64; i++) {
|
for(int i = 0; i < 64; i++) {
|
||||||
si.pif.Write(si.pifAddr + i, mem.mmio.rdp.rdram[BYTE_ADDRESS(si.dramAddr + i)]);
|
si.pif.Write(si.pifAddr + i, mem.mmio.rdp.rdram[BYTE_ADDRESS(si.dramAddr + i)]);
|
||||||
}
|
}
|
||||||
//Util::debug("SI DMA from RDRAM to PIF RAM ({:08X} to {:08X})", si.dramAddr, si.pifAddr);
|
Util::trace("SI DMA from RDRAM to PIF RAM ({:08X} to {:08X})", si.dramAddr, si.pifAddr);
|
||||||
si.pif.ProcessCommands(mem);
|
si.pif.ProcessCommands(mem);
|
||||||
}
|
}
|
||||||
InterruptRaise(mem.mmio.mi, regs, Interrupt::SI);
|
InterruptRaise(mem.mmio.mi, regs, Interrupt::SI);
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ struct Cop1 {
|
|||||||
void SetCauseDivisionByZero();
|
void SetCauseDivisionByZero();
|
||||||
void SetCauseOverflow();
|
void SetCauseOverflow();
|
||||||
void SetCauseInvalid();
|
void SetCauseInvalid();
|
||||||
|
int fp_class=0;
|
||||||
private:
|
private:
|
||||||
template <typename T> auto FGR(Cop0Status&, u32) -> T&;
|
template <typename T> auto FGR(Cop0Status&, u32) -> T&;
|
||||||
void decodeInterp(Interpreter&, u32);
|
void decodeInterp(Interpreter&, u32);
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ void Cop1::SetCauseInvalid() {
|
|||||||
|
|
||||||
#define PUSHROUNDING int orig_round = PushRoundingMode(fcr31)
|
#define PUSHROUNDING int orig_round = PushRoundingMode(fcr31)
|
||||||
#define POPROUNDING fesetround(orig_round)
|
#define POPROUNDING fesetround(orig_round)
|
||||||
#define OP_CheckExcept(op) do { PUSHROUNDING; feclearexcept(FE_ALL_EXCEPT); op; SetFPUCauseRaised(regs, fetestexcept(FE_ALL_EXCEPT)); POPROUNDING; } while(0)
|
#define OP_CheckExcept(op) do { feclearexcept(FE_ALL_EXCEPT); PUSHROUNDING; op; SetFPUCauseRaised(regs, fetestexcept(FE_ALL_EXCEPT)); POPROUNDING; } while(0)
|
||||||
#define CVT_OP_CheckExcept(op) do { feclearexcept(FE_ALL_EXCEPT); op; SetFPUCauseCVTRaised(regs, fetestexcept(FE_ALL_EXCEPT)); CheckFPUException(); } while(0)
|
#define CVT_OP_CheckExcept(op) do { feclearexcept(FE_ALL_EXCEPT); op; SetFPUCauseCVTRaised(regs, fetestexcept(FE_ALL_EXCEPT)); CheckFPUException(); } while(0)
|
||||||
|
|
||||||
#define OP(T, op) do { \
|
#define OP(T, op) do { \
|
||||||
@@ -138,7 +138,8 @@ void Cop1::SetCauseInvalid() {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
FORCE_INLINE void SetCauseByArgWCVT(Registers& regs, T f) {
|
FORCE_INLINE void SetCauseByArgWCVT(Registers& regs, T f) {
|
||||||
switch (std::fpclassify(f)) {
|
regs.cop1.fp_class = std::fpclassify(f);
|
||||||
|
switch (regs.cop1.fp_class) {
|
||||||
case FP_NAN:
|
case FP_NAN:
|
||||||
case FP_INFINITE:
|
case FP_INFINITE:
|
||||||
case FP_SUBNORMAL:
|
case FP_SUBNORMAL:
|
||||||
@@ -161,7 +162,8 @@ FORCE_INLINE void SetCauseByArgWCVT(Registers& regs, T f) {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
FORCE_INLINE void SetCauseByArgLCVT(Registers& regs, T f) {
|
FORCE_INLINE void SetCauseByArgLCVT(Registers& regs, T f) {
|
||||||
switch (std::fpclassify(f)) {
|
regs.cop1.fp_class = std::fpclassify(f);
|
||||||
|
switch (regs.cop1.fp_class) {
|
||||||
case FP_NAN:
|
case FP_NAN:
|
||||||
case FP_INFINITE:
|
case FP_INFINITE:
|
||||||
case FP_SUBNORMAL:
|
case FP_SUBNORMAL:
|
||||||
@@ -190,7 +192,7 @@ FORCE_INLINE void SetFPUCauseRaised(Registers& regs, int raised) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (raised & FE_UNDERFLOW) {
|
if (((raised & FE_UNDERFLOW) != 0) || regs.cop1.fp_class == FP_SUBNORMAL) {
|
||||||
if (!regs.cop1.fcr31.fs || regs.cop1.fcr31.enable_underflow || regs.cop1.fcr31.enable_inexact_operation) {
|
if (!regs.cop1.fcr31.fs || regs.cop1.fcr31.enable_underflow || regs.cop1.fcr31.enable_inexact_operation) {
|
||||||
regs.cop1.SetCauseUnimplemented();
|
regs.cop1.SetCauseUnimplemented();
|
||||||
return;
|
return;
|
||||||
@@ -245,8 +247,8 @@ FORCE_INLINE bool isqnan(T f) {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
FORCE_INLINE void SetCauseByArg(Registers& regs, T f) {
|
FORCE_INLINE void SetCauseByArg(Registers& regs, T f) {
|
||||||
int c = std::fpclassify(f);
|
regs.cop1.fp_class = std::fpclassify(f);
|
||||||
switch(c) {
|
switch(regs.cop1.fp_class) {
|
||||||
case FP_NAN:
|
case FP_NAN:
|
||||||
if(isqnan(f)) {
|
if(isqnan(f)) {
|
||||||
regs.cop1.SetCauseInvalid();
|
regs.cop1.SetCauseInvalid();
|
||||||
@@ -265,7 +267,7 @@ FORCE_INLINE void SetCauseByArg(Registers& regs, T f) {
|
|||||||
case FP_NORMAL:
|
case FP_NORMAL:
|
||||||
break; // No-op, these are fine.
|
break; // No-op, these are fine.
|
||||||
default:
|
default:
|
||||||
Util::panic("Unknown floating point classification: {}", c);
|
Util::panic("Unknown floating point classification: {}", regs.cop1.fp_class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,7 +276,7 @@ FORCE_INLINE void SetCauseByArg(Registers& regs, T f) {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
FORCE_INLINE void SetCauseOnResult(Registers& regs, T& d) {
|
FORCE_INLINE void SetCauseOnResult(Registers& regs, T& d) {
|
||||||
Cop1& cop1 = regs.cop1;
|
Cop1& cop1 = regs.cop1;
|
||||||
int classification = std::fpclassify(d);
|
regs.cop1.fp_class = std::fpclassify(d);
|
||||||
T magic, min;
|
T magic, min;
|
||||||
if constexpr(std::is_same_v<T, float>) {
|
if constexpr(std::is_same_v<T, float>) {
|
||||||
u32 c = 0x7FBFFFFF;
|
u32 c = 0x7FBFFFFF;
|
||||||
@@ -285,7 +287,7 @@ FORCE_INLINE void SetCauseOnResult(Registers& regs, T& d) {
|
|||||||
magic = U64_TO_D(c);
|
magic = U64_TO_D(c);
|
||||||
min = DBL_MIN;
|
min = DBL_MIN;
|
||||||
}
|
}
|
||||||
switch (classification) {
|
switch (regs.cop1.fp_class) {
|
||||||
case FP_NAN:
|
case FP_NAN:
|
||||||
d = magic; // set result to sNAN
|
d = magic; // set result to sNAN
|
||||||
break;
|
break;
|
||||||
@@ -324,7 +326,7 @@ FORCE_INLINE void SetCauseOnResult(Registers& regs, T& d) {
|
|||||||
case FP_NORMAL:
|
case FP_NORMAL:
|
||||||
break; // No-op, these are fine.
|
break; // No-op, these are fine.
|
||||||
default:
|
default:
|
||||||
Util::panic("Unknown FP classification: {}", classification);
|
Util::panic("Unknown FP classification: {}", regs.cop1.fp_class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user