diff --git a/src/backend/Scheduler.cpp b/src/backend/Scheduler.cpp index 80fc7b9c..19b686cd 100644 --- a/src/backend/Scheduler.cpp +++ b/src/backend/Scheduler.cpp @@ -34,9 +34,7 @@ void Scheduler::tick(u64 t, n64::Mem& mem, n64::Registers& regs) { while(ticks >= events.top().time) { switch(auto type = events.top().type) { case SI_DMA: - si.status.dmaBusy = false; si.DMA(mem, regs); - InterruptRaise(mi, regs, n64::Interrupt::SI); break; case PI_DMA_COMPLETE: InterruptRaise(mi, regs, n64::Interrupt::PI); diff --git a/src/backend/core/Mem.cpp b/src/backend/core/Mem.cpp index eab71c2d..4657075c 100644 --- a/src/backend/core/Mem.cpp +++ b/src/backend/core/Mem.cpp @@ -368,7 +368,7 @@ template<> void Mem::Write(Registers& regs, u32 paddr, u32 val) { } } break; case REGION_CART: - Util::debug("BusWrite @ {:08X} = {:02X}", paddr, val); + Util::trace("BusWrite @ {:08X} = {:02X}", paddr, val); mmio.pi.BusWrite(*this, paddr, val); break; case MMIO_REGION: @@ -417,7 +417,7 @@ template<> void Mem::Write(Registers& regs, u32 paddr, u32 val) { } } break; case REGION_CART: - Util::debug("BusWrite @ {:08X} = {:04X}", paddr, val); + Util::trace("BusWrite @ {:08X} = {:04X}", paddr, val); mmio.pi.BusWrite(*this, paddr, val); break; case MMIO_REGION: @@ -464,7 +464,7 @@ template<> void Mem::Write(Registers& regs, u32 paddr, u32 val) { } } break; case REGION_CART: - Util::debug("BusWrite @ {:08X} = {:08X}", paddr, val); + Util::trace("BusWrite @ {:08X} = {:08X}", paddr, val); mmio.pi.BusWrite(*this, paddr, val); break; case MMIO_REGION: @@ -508,8 +508,8 @@ void Mem::Write(Registers& regs, u32 paddr, u64 val) { } } break; case REGION_CART: - Util::debug("BusWrite @ {:08X} = {:016X}", paddr, val); - mmio.pi.BusWrite(*this, paddr, val); + Util::trace("BusWrite @ {:08X} = {:016X}", paddr, val); + mmio.pi.BusWrite(*this, paddr, val); break; case MMIO_REGION: Util::panic("MMIO Write!"); @@ -569,7 +569,8 @@ template <> u8 Mem::BackupRead(u32 addr) { template <> void Mem::BackupWrite(u32 addr, u32 val) { switch(saveType) { 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: Util::panic("Accessing cartridge with save type SAVE_EEPROM in write word"); case SAVE_FLASH_1m: @@ -585,7 +586,8 @@ template <> void Mem::BackupWrite(u32 addr, u32 val) { template <> void Mem::BackupWrite(u32 addr, u8 val) { switch(saveType) { 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: Util::panic("Accessing cartridge with save type SAVE_EEPROM in write word"); case SAVE_FLASH_1m: diff --git a/src/backend/core/mem/Flash.cpp b/src/backend/core/mem/Flash.cpp index 84c67891..9718dd79 100644 --- a/src/backend/core/mem/Flash.cpp +++ b/src/backend/core/mem/Flash.cpp @@ -1,4 +1,5 @@ #include +#include namespace n64 { constexpr auto FLASH_SIZE = 1_mb; @@ -159,10 +160,11 @@ template <> void Flash::Write(u32 index, u8 val) { case FlashState::Idle: Util::panic("Invalid FlashState::Idle with Write"); case FlashState::Status: Util::panic("Invalid FlashState::Status with Write"); case FlashState::Erase: Util::panic("Invalid FlashState::Erase with Write"); + case FlashState::Read: Util::panic("Invalid FlashState::Read with Write"); case FlashState::Write: + assert(index <= 0x7F && "Out of range flash Write8"); writeBuf[index] = val; break; - case FlashState::Read: Util::panic("Invalid FlashState::Read with Write"); default: Util::warn("Invalid flash state on Write: {:02X}", static_cast(state)); } } diff --git a/src/backend/core/mmio/PI.cpp b/src/backend/core/mmio/PI.cpp index 50c59f1c..8eb916ff 100644 --- a/src/backend/core/mmio/PI.cpp +++ b/src/backend/core/mmio/PI.cpp @@ -62,7 +62,7 @@ template<> auto PI::BusRead(Mem& mem, u32 addr) -> u8 { case REGION_PI_ROM: { // round to nearest 4 byte boundary, keeping old LSB 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); return 0xFF; } @@ -92,7 +92,7 @@ template<> auto PI::BusRead(Mem& mem, u32 addr) -> u8 { addr = (addr + 2) & ~2; // round to nearest 4 byte boundary, keeping old LSB 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); return 0xFF; } @@ -103,33 +103,32 @@ template<> auto PI::BusRead(Mem& mem, u32 addr) -> u8 { } } -template<> void PI::BusWrite(Mem& mem, u32 addr, u8 val) { +template<> void PI::BusWrite(Mem& mem, u32 addr, u32 val) { switch (addr) { - case REGION_PI_UNKNOWN: - Util::panic("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr); - case REGION_PI_64DD_REG: - if (addr == 0x05000020) { - fprintf(stderr, "%c", val); - } - else { - Util::warn("Writing byte 0x{:02X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!", val, addr); - } - return; - case REGION_PI_64DD_ROM: - Util::panic("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr); - case REGION_PI_SRAM: - mem.BackupWrite(addr - SREGION_PI_SRAM, val); - return; - case REGION_PI_ROM: - Util::warn("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr); - return; - default: - Util::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); + case REGION_PI_UNKNOWN: + Util::panic("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr); + case REGION_PI_64DD_REG: + if (addr == 0x05000020) { + fprintf(stderr, "%c", val); + } else { + Util::warn("Writing byte 0x{:02X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!", val, addr); + } + break; + case REGION_PI_64DD_ROM: + Util::panic("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr); + case REGION_PI_SRAM: + mem.BackupWrite(addr - SREGION_PI_SRAM, val); + break; + case REGION_PI_ROM: + Util::warn("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr); + break; + default: + Util::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); } } -template<> void PI::BusWrite(Mem& mem, u32 addr, u8 val) { - int latch_shift = 24 - (addr & 1) * 8; +template<> void PI::BusWrite(Mem& mem, u32 addr, u32 val) { + u8 latch_shift = 24 - (addr & 1) * 8; if (!WriteLatch(val << latch_shift) && addr != 0x05000020) [[unlikely]] { return; @@ -169,7 +168,7 @@ template <> auto PI::BusRead(Mem& mem, u32 addr) -> u16 { return BusRead(mem, addr); } -template <> void PI::BusWrite(Mem&, u32 addr, u16 val) { +template <> void PI::BusWrite(Mem&, u32 addr, u32 val) { if (!WriteLatch(val << 16)) [[unlikely]] { return; } @@ -191,7 +190,7 @@ template <> void PI::BusWrite(Mem&, u32 addr, u16 val) { } } -template <> void PI::BusWrite(Mem& mem, u32 addr, u16 val) { +template <> void PI::BusWrite(Mem& mem, u32 addr, u32 val) { BusWrite(mem, addr, val); } @@ -220,8 +219,7 @@ template <> auto PI::BusRead(Mem& mem, u32 addr) -> u32 { return htobe32(Util::ReadAccess(mem.isviewer, addr - SREGION_CART_ISVIEWER_BUFFER)); case CART_ISVIEWER_FLUSH: Util::panic("Read from ISViewer flush!"); - default: - Util::panic("Read from unknown address {:08X} in REGION_PI_ROM!", addr); + default: break; } Util::warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM!", addr, index, index); return 0; @@ -283,6 +281,7 @@ template <> void PI::BusWrite(Mem& mem, u32 addr, u32 val) { } default: if (!WriteLatch(val)) [[unlikely]] { + Util::warn("Couldn't latch PI bus, ignoring write to REGION_PI_ROM"); return; } 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(Mem& mem, u32 addr, u32 val) { } } -template <> void PI::BusWrite(Mem& mem, u32 addr, u32 val) { +template <> +void PI::BusWrite(Mem& mem, u32 addr, u32 val) { BusWrite(mem, addr, val); } @@ -327,7 +327,7 @@ template <> auto PI::BusRead(Mem& mem, u32 addr) -> u64 { return BusRead(mem, addr); } -template <> void PI::BusWrite(Mem&, u32 addr, u64 val) { +template <> void PI::BusWrite(Mem&, u32 addr, u64 val) { if (!WriteLatch(val >> 32)) [[unlikely]] { return; } @@ -349,8 +349,8 @@ template <> void PI::BusWrite(Mem&, u32 addr, u64 val) { } } -template <> void PI::BusWrite(Mem& mem, u32 addr, u64 val) { - BusWrite(mem, addr, val); +template <> void PI::BusWrite(Mem& mem, u32 addr, u64 val) { + BusWrite(mem, addr, val); } auto PI::Read(MI& mi, u32 addr) const -> u32 { diff --git a/src/backend/core/mmio/PI.hpp b/src/backend/core/mmio/PI.hpp index b1befbf5..8577509a 100644 --- a/src/backend/core/mmio/PI.hpp +++ b/src/backend/core/mmio/PI.hpp @@ -14,7 +14,9 @@ struct PI { void Write(Mem&, Registers&, u32, u32); template - void BusWrite(Mem&, u32, T); + void BusWrite(Mem&, u32, u32); + template + void BusWrite(Mem&, u32, u64); template auto BusRead(Mem&, u32) -> T; diff --git a/src/backend/core/mmio/SI.cpp b/src/backend/core/mmio/SI.cpp index 46acc6cd..8a0814d8 100644 --- a/src/backend/core/mmio/SI.cpp +++ b/src/backend/core/mmio/SI.cpp @@ -40,12 +40,12 @@ void SI::DMA(Mem& mem, Registers& regs) const { for(int i = 0; i < 64; 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 { for(int i = 0; i < 64; 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); } InterruptRaise(mem.mmio.mi, regs, Interrupt::SI); diff --git a/src/backend/core/registers/Cop1.hpp b/src/backend/core/registers/Cop1.hpp index a4a85434..93203850 100644 --- a/src/backend/core/registers/Cop1.hpp +++ b/src/backend/core/registers/Cop1.hpp @@ -107,6 +107,7 @@ struct Cop1 { void SetCauseDivisionByZero(); void SetCauseOverflow(); void SetCauseInvalid(); + int fp_class=0; private: template auto FGR(Cop0Status&, u32) -> T&; void decodeInterp(Interpreter&, u32); diff --git a/src/backend/core/registers/cop/cop1instructions.cpp b/src/backend/core/registers/cop/cop1instructions.cpp index 519ec31b..740aa2ec 100644 --- a/src/backend/core/registers/cop/cop1instructions.cpp +++ b/src/backend/core/registers/cop/cop1instructions.cpp @@ -121,7 +121,7 @@ void Cop1::SetCauseInvalid() { #define PUSHROUNDING int orig_round = PushRoundingMode(fcr31) #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 OP(T, op) do { \ @@ -138,7 +138,8 @@ void Cop1::SetCauseInvalid() { template 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_INFINITE: case FP_SUBNORMAL: @@ -161,7 +162,8 @@ FORCE_INLINE void SetCauseByArgWCVT(Registers& regs, T f) { template 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_INFINITE: case FP_SUBNORMAL: @@ -190,7 +192,7 @@ FORCE_INLINE void SetFPUCauseRaised(Registers& regs, int raised) { 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) { regs.cop1.SetCauseUnimplemented(); return; @@ -245,8 +247,8 @@ FORCE_INLINE bool isqnan(T f) { template FORCE_INLINE void SetCauseByArg(Registers& regs, T f) { - int c = std::fpclassify(f); - switch(c) { + regs.cop1.fp_class = std::fpclassify(f); + switch(regs.cop1.fp_class) { case FP_NAN: if(isqnan(f)) { regs.cop1.SetCauseInvalid(); @@ -265,7 +267,7 @@ FORCE_INLINE void SetCauseByArg(Registers& regs, T f) { case FP_NORMAL: break; // No-op, these are fine. 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 FORCE_INLINE void SetCauseOnResult(Registers& regs, T& d) { Cop1& cop1 = regs.cop1; - int classification = std::fpclassify(d); + regs.cop1.fp_class = std::fpclassify(d); T magic, min; if constexpr(std::is_same_v) { u32 c = 0x7FBFFFFF; @@ -285,7 +287,7 @@ FORCE_INLINE void SetCauseOnResult(Registers& regs, T& d) { magic = U64_TO_D(c); min = DBL_MIN; } - switch (classification) { + switch (regs.cop1.fp_class) { case FP_NAN: d = magic; // set result to sNAN break; @@ -324,7 +326,7 @@ FORCE_INLINE void SetCauseOnResult(Registers& regs, T& d) { case FP_NORMAL: break; // No-op, these are fine. default: - Util::panic("Unknown FP classification: {}", classification); + Util::panic("Unknown FP classification: {}", regs.cop1.fp_class); } }