diff --git a/src/core/bus.cpp b/src/core/bus.cpp index db51ecd05..14375f9df 100644 --- a/src/core/bus.cpp +++ b/src/core/bus.cpp @@ -64,6 +64,11 @@ void Bus::Reset() bool Bus::DoState(StateWrapper& sw) { + sw.Do(&m_exp1_access_time); + sw.Do(&m_exp2_access_time); + sw.Do(&m_bios_access_time); + sw.Do(&m_cdrom_access_time); + sw.Do(&m_spu_access_time); sw.DoBytes(m_ram.data(), m_ram.size()); sw.DoBytes(m_bios.data(), m_bios.size()); sw.DoArray(m_MEMCTRL.regs, countof(m_MEMCTRL.regs)); @@ -223,7 +228,7 @@ void Bus::RecalculateMemoryTimings() m_spu_access_time[2]); } -bool Bus::DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, PhysicalMemoryAddress address, u32& value) +TickCount Bus::DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, PhysicalMemoryAddress address, u32& value) { SmallString str; str.AppendString("Invalid bus "); @@ -247,13 +252,16 @@ bool Bus::DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, Physical if (type == MemoryAccessType::Read) value = UINT32_C(0xFFFFFFFF); - return true; + return 1; } -bool Bus::DoReadEXP1(MemoryAccessSize size, u32 offset, u32& value) +u32 Bus::DoReadEXP1(MemoryAccessSize size, u32 offset) { if (m_exp1_rom.empty()) - return DoInvalidAccess(MemoryAccessType::Read, size, EXP1_BASE | offset, value); + { + // EXP1 not present. + return UINT32_C(0xFFFFFFFF); + } if (offset == 0x20018) { @@ -264,10 +272,10 @@ bool Bus::DoReadEXP1(MemoryAccessSize size, u32 offset, u32& value) const u32 transfer_size = u32(1) << static_cast(size); if ((offset + transfer_size) > m_exp1_rom.size()) { - value = UINT32_C(0); - return true; + return UINT32_C(0); } + u32 value; if (size == MemoryAccessSize::Byte) { value = ZeroExtend32(m_exp1_rom[offset]); @@ -284,36 +292,32 @@ bool Bus::DoReadEXP1(MemoryAccessSize size, u32 offset, u32& value) } // Log_DevPrintf("EXP1 read: 0x%08X -> 0x%08X", EXP1_BASE | offset, value); - return true; + return value; } -bool Bus::DoWriteEXP1(MemoryAccessSize size, u32 offset, u32 value) +void Bus::DoWriteEXP1(MemoryAccessSize size, u32 offset, u32 value) { - return DoInvalidAccess(MemoryAccessType::Write, size, EXP1_BASE | offset, value); + Log_WarningPrintf("EXP1 write: 0x%08X <- 0x%08X", EXP1_BASE | offset, value); } -bool Bus::DoReadEXP2(MemoryAccessSize size, u32 offset, u32& value) +u32 Bus::DoReadEXP2(MemoryAccessSize size, u32 offset) { - offset &= EXP2_MASK; - // rx/tx buffer empty if (offset == 0x21) { - value = 0x04 | 0x08; - return true; + return 0x04 | 0x08; } - return DoInvalidAccess(MemoryAccessType::Read, size, EXP2_BASE | offset, value); + Log_WarningPrintf("EXP2 read: 0x%08X", EXP2_BASE | offset); + return UINT32_C(0xFFFFFFFF); } -bool Bus::DoWriteEXP2(MemoryAccessSize size, u32 offset, u32 value) +void Bus::DoWriteEXP2(MemoryAccessSize size, u32 offset, u32 value) { - offset &= EXP2_MASK; - if (offset == 0x23) { if (value == '\r') - return true; + return; if (value == '\n') { @@ -326,26 +330,26 @@ bool Bus::DoWriteEXP2(MemoryAccessSize size, u32 offset, u32 value) m_tty_line_buffer.AppendCharacter(Truncate8(value)); } - return true; + return; } if (offset == 0x41) { Log_WarningPrintf("BIOS POST status: %02X", value & UINT32_C(0x0F)); - return true; + return; } - return DoInvalidAccess(MemoryAccessType::Write, size, EXP2_BASE | offset, value); + Log_WarningPrintf("EXP2 write: 0x%08X <- 0x%08X", EXP2_BASE | offset, value); } -bool Bus::DoReadMemoryControl(MemoryAccessSize size, u32 offset, u32& value) +u32 Bus::DoReadMemoryControl(MemoryAccessSize size, u32 offset) { + u32 value = m_MEMCTRL.regs[offset / 4]; FixupUnalignedWordAccessW32(offset, value); - value = m_MEMCTRL.regs[offset / 4]; - return true; + return value; } -bool Bus::DoWriteMemoryControl(MemoryAccessSize size, u32 offset, u32 value) +void Bus::DoWriteMemoryControl(MemoryAccessSize size, u32 offset, u32 value) { FixupUnalignedWordAccessW32(offset, value); @@ -357,165 +361,151 @@ bool Bus::DoWriteMemoryControl(MemoryAccessSize size, u32 offset, u32 value) m_MEMCTRL.regs[index] = new_value; RecalculateMemoryTimings(); } - - return true; } -bool Bus::DoReadMemoryControl2(MemoryAccessSize size, u32 offset, u32& value) +u32 Bus::DoReadMemoryControl2(MemoryAccessSize size, u32 offset) { if (offset == 0x00) - { - value = m_ram_size_reg; - return true; - } + return m_ram_size_reg; - return DoInvalidAccess(MemoryAccessType::Read, size, MEMCTRL2_BASE | offset, value); + u32 value = 0; + DoInvalidAccess(MemoryAccessType::Read, size, MEMCTRL2_BASE | offset, value); + return value; } -bool Bus::DoWriteMemoryControl2(MemoryAccessSize size, u32 offset, u32 value) +void Bus::DoWriteMemoryControl2(MemoryAccessSize size, u32 offset, u32 value) { if (offset == 0x00) { m_ram_size_reg = value; - return true; + return; } - return DoInvalidAccess(MemoryAccessType::Write, size, MEMCTRL2_BASE | offset, value); + DoInvalidAccess(MemoryAccessType::Write, size, MEMCTRL2_BASE | offset, value); } -bool Bus::DoReadPad(MemoryAccessSize size, u32 offset, u32& value) +u32 Bus::DoReadPad(MemoryAccessSize size, u32 offset) { - value = m_pad->ReadRegister(offset); - return true; + return m_pad->ReadRegister(offset); } -bool Bus::DoWritePad(MemoryAccessSize size, u32 offset, u32 value) +void Bus::DoWritePad(MemoryAccessSize size, u32 offset, u32 value) { m_pad->WriteRegister(offset, value); - return true; } -bool Bus::DoReadSIO(MemoryAccessSize size, u32 offset, u32& value) +u32 Bus::DoReadSIO(MemoryAccessSize size, u32 offset) { Log_ErrorPrintf("SIO Read 0x%08X", offset); - value = 0; if (offset == 0x04) - value = 0x5; - - return true; + return 0x5; + else + return 0; } -bool Bus::DoWriteSIO(MemoryAccessSize size, u32 offset, u32 value) +void Bus::DoWriteSIO(MemoryAccessSize size, u32 offset, u32 value) { Log_ErrorPrintf("SIO Write 0x%08X <- 0x%08X", offset, value); - return true; } -bool Bus::DoReadCDROM(MemoryAccessSize size, u32 offset, u32& value) +u32 Bus::DoReadCDROM(MemoryAccessSize size, u32 offset) { // TODO: Splitting of half/word reads. Assert(size == MemoryAccessSize::Byte); - value = ZeroExtend32(m_cdrom->ReadRegister(offset)); - return true; + return ZeroExtend32(m_cdrom->ReadRegister(offset)); } -bool Bus::DoWriteCDROM(MemoryAccessSize size, u32 offset, u32 value) +void Bus::DoWriteCDROM(MemoryAccessSize size, u32 offset, u32 value) { // TODO: Splitting of half/word reads. Assert(size == MemoryAccessSize::Byte); m_cdrom->WriteRegister(offset, Truncate8(value)); - return true; } -bool Bus::DoReadGPU(MemoryAccessSize size, u32 offset, u32& value) +u32 Bus::DoReadGPU(MemoryAccessSize size, u32 offset) { Assert(size == MemoryAccessSize::Word); - value = m_gpu->ReadRegister(offset); - return true; + return m_gpu->ReadRegister(offset); } -bool Bus::DoWriteGPU(MemoryAccessSize size, u32 offset, u32 value) +void Bus::DoWriteGPU(MemoryAccessSize size, u32 offset, u32 value) { Assert(size == MemoryAccessSize::Word); m_gpu->WriteRegister(offset, value); - return true; } -bool Bus::DoReadMDEC(MemoryAccessSize size, u32 offset, u32& value) +u32 Bus::DoReadMDEC(MemoryAccessSize size, u32 offset) { Assert(size == MemoryAccessSize::Word); - value = m_mdec->ReadRegister(offset); - return true; + return m_mdec->ReadRegister(offset); } -bool Bus::DoWriteMDEC(MemoryAccessSize size, u32 offset, u32 value) +void Bus::DoWriteMDEC(MemoryAccessSize size, u32 offset, u32 value) { Assert(size == MemoryAccessSize::Word); m_mdec->WriteRegister(offset, value); - return true; } -bool Bus::DoReadInterruptController(MemoryAccessSize size, u32 offset, u32& value) +u32 Bus::DoReadInterruptController(MemoryAccessSize size, u32 offset) { + u32 value = m_interrupt_controller->ReadRegister(offset); FixupUnalignedWordAccessW32(offset, value); - value = m_interrupt_controller->ReadRegister(offset); - return true; + return value; } -bool Bus::DoWriteInterruptController(MemoryAccessSize size, u32 offset, u32 value) +void Bus::DoWriteInterruptController(MemoryAccessSize size, u32 offset, u32 value) { FixupUnalignedWordAccessW32(offset, value); m_interrupt_controller->WriteRegister(offset, value); - return true; } -bool Bus::DoReadTimers(MemoryAccessSize size, u32 offset, u32& value) +u32 Bus::DoReadTimers(MemoryAccessSize size, u32 offset) { + u32 value = m_timers->ReadRegister(offset); FixupUnalignedWordAccessW32(offset, value); - value = m_timers->ReadRegister(offset); - return true; + return value; } -bool Bus::DoWriteTimers(MemoryAccessSize size, u32 offset, u32 value) +void Bus::DoWriteTimers(MemoryAccessSize size, u32 offset, u32 value) { FixupUnalignedWordAccessW32(offset, value); m_timers->WriteRegister(offset, value); - return true; } -bool Bus::DoReadSPU(MemoryAccessSize size, u32 offset, u32& value) +u32 Bus::DoReadSPU(MemoryAccessSize size, u32 offset) { - // 32-bit reads are read as two 16-bit writes. + // 32-bit reads are read as two 16-bit accesses. if (size == MemoryAccessSize::Word) { const u16 lsb = m_spu->ReadRegister(offset); const u16 msb = m_spu->ReadRegister(offset + 2); - value = ZeroExtend32(lsb) | (ZeroExtend32(msb) << 16); + return ZeroExtend32(lsb) | (ZeroExtend32(msb) << 16); } else { - value = ZeroExtend32(m_spu->ReadRegister(offset)); + return ZeroExtend32(m_spu->ReadRegister(offset)); } - - return true; } -bool Bus::DoWriteSPU(MemoryAccessSize size, u32 offset, u32 value) +void Bus::DoWriteSPU(MemoryAccessSize size, u32 offset, u32 value) { // 32-bit writes are written as two 16-bit writes. + // TODO: Ignore if address is not aligned. if (size == MemoryAccessSize::Word) { + Assert(Common::IsAlignedPow2(offset, 2)); m_spu->WriteRegister(offset, Truncate16(value)); m_spu->WriteRegister(offset + 2, Truncate16(value >> 16)); - return true; + return; } + Assert(Common::IsAlignedPow2(offset, 2)); m_spu->WriteRegister(offset, Truncate16(value)); - return true; } -bool Bus::DoReadDMA(MemoryAccessSize size, u32 offset, u32& value) +u32 Bus::DoReadDMA(MemoryAccessSize size, u32 offset) { + u32 value = m_dma->ReadRegister(offset); switch (size) { case MemoryAccessSize::Byte: @@ -529,11 +519,10 @@ bool Bus::DoReadDMA(MemoryAccessSize size, u32 offset, u32& value) break; } - value = m_dma->ReadRegister(offset); - return true; + return value; } -bool Bus::DoWriteDMA(MemoryAccessSize size, u32 offset, u32 value) +void Bus::DoWriteDMA(MemoryAccessSize size, u32 offset, u32 value) { switch (size) { @@ -552,5 +541,4 @@ bool Bus::DoWriteDMA(MemoryAccessSize size, u32 offset, u32 value) } m_dma->WriteRegister(offset, value); - return true; } diff --git a/src/core/bus.h b/src/core/bus.h index c21541924..6456a8df8 100644 --- a/src/core/bus.h +++ b/src/core/bus.h @@ -40,7 +40,7 @@ public: bool WriteWord(PhysicalMemoryAddress address, u32 value); template - bool DispatchAccess(PhysicalMemoryAddress address, u32& value); + TickCount DispatchAccess(PhysicalMemoryAddress address, u32& value); void PatchBIOS(u32 address, u32 value, u32 mask = UINT32_C(0xFFFFFFFF)); void SetExpansionROM(std::vector data); @@ -93,6 +93,7 @@ private: enum : u32 { + RAM_ACCESS_DELAY = 6, // Nocash docs say RAM takes 6 cycles to access. MEMCTRL_REG_COUNT = 9 }; @@ -148,51 +149,51 @@ private: void RecalculateMemoryTimings(); template - bool DoRAMAccess(u32 offset, u32& value); + TickCount DoRAMAccess(u32 offset, u32& value); template - bool DoBIOSAccess(u32 offset, u32& value); + TickCount DoBIOSAccess(u32 offset, u32& value); - bool DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, PhysicalMemoryAddress address, u32& value); + TickCount DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, PhysicalMemoryAddress address, u32& value); - bool DoReadEXP1(MemoryAccessSize size, u32 offset, u32& value); - bool DoWriteEXP1(MemoryAccessSize size, u32 offset, u32 value); + u32 DoReadEXP1(MemoryAccessSize size, u32 offset); + void DoWriteEXP1(MemoryAccessSize size, u32 offset, u32 value); - bool DoReadEXP2(MemoryAccessSize size, u32 offset, u32& value); - bool DoWriteEXP2(MemoryAccessSize size, u32 offset, u32 value); + u32 DoReadEXP2(MemoryAccessSize size, u32 offset); + void DoWriteEXP2(MemoryAccessSize size, u32 offset, u32 value); - bool DoReadMemoryControl(MemoryAccessSize size, u32 offset, u32& value); - bool DoWriteMemoryControl(MemoryAccessSize size, u32 offset, u32 value); + u32 DoReadMemoryControl(MemoryAccessSize size, u32 offset); + void DoWriteMemoryControl(MemoryAccessSize size, u32 offset, u32 value); - bool DoReadMemoryControl2(MemoryAccessSize size, u32 offset, u32& value); - bool DoWriteMemoryControl2(MemoryAccessSize size, u32 offset, u32 value); + u32 DoReadMemoryControl2(MemoryAccessSize size, u32 offset); + void DoWriteMemoryControl2(MemoryAccessSize size, u32 offset, u32 value); - bool DoReadPad(MemoryAccessSize size, u32 offset, u32& value); - bool DoWritePad(MemoryAccessSize size, u32 offset, u32 value); + u32 DoReadPad(MemoryAccessSize size, u32 offset); + void DoWritePad(MemoryAccessSize size, u32 offset, u32 value); - bool DoReadSIO(MemoryAccessSize size, u32 offset, u32& value); - bool DoWriteSIO(MemoryAccessSize size, u32 offset, u32 value); + u32 DoReadSIO(MemoryAccessSize size, u32 offset); + void DoWriteSIO(MemoryAccessSize size, u32 offset, u32 value); - bool DoReadCDROM(MemoryAccessSize size, u32 offset, u32& value); - bool DoWriteCDROM(MemoryAccessSize size, u32 offset, u32 value); + u32 DoReadCDROM(MemoryAccessSize size, u32 offset); + void DoWriteCDROM(MemoryAccessSize size, u32 offset, u32 value); - bool DoReadGPU(MemoryAccessSize size, u32 offset, u32& value); - bool DoWriteGPU(MemoryAccessSize size, u32 offset, u32 value); + u32 DoReadGPU(MemoryAccessSize size, u32 offset); + void DoWriteGPU(MemoryAccessSize size, u32 offset, u32 value); - bool DoReadMDEC(MemoryAccessSize size, u32 offset, u32& value); - bool DoWriteMDEC(MemoryAccessSize size, u32 offset, u32 value); + u32 DoReadMDEC(MemoryAccessSize size, u32 offset); + void DoWriteMDEC(MemoryAccessSize size, u32 offset, u32 value); - bool DoReadInterruptController(MemoryAccessSize size, u32 offset, u32& value); - bool DoWriteInterruptController(MemoryAccessSize size, u32 offset, u32 value); + u32 DoReadInterruptController(MemoryAccessSize size, u32 offset); + void DoWriteInterruptController(MemoryAccessSize size, u32 offset, u32 value); - bool DoReadDMA(MemoryAccessSize size, u32 offset, u32& value); - bool DoWriteDMA(MemoryAccessSize size, u32 offset, u32 value); + u32 DoReadDMA(MemoryAccessSize size, u32 offset); + void DoWriteDMA(MemoryAccessSize size, u32 offset, u32 value); - bool DoReadTimers(MemoryAccessSize size, u32 offset, u32& value); - bool DoWriteTimers(MemoryAccessSize size, u32 offset, u32 value); + u32 DoReadTimers(MemoryAccessSize size, u32 offset); + void DoWriteTimers(MemoryAccessSize size, u32 offset, u32 value); - bool DoReadSPU(MemoryAccessSize size, u32 offset, u32& value); - bool DoWriteSPU(MemoryAccessSize size, u32 offset, u32 value); + u32 DoReadSPU(MemoryAccessSize size, u32 offset); + void DoWriteSPU(MemoryAccessSize size, u32 offset, u32 value); CPU::Core* m_cpu = nullptr; DMA* m_dma = nullptr; @@ -204,6 +205,8 @@ private: SPU* m_spu = nullptr; MDEC* m_mdec = nullptr; + std::array m_exp1_access_time = {}; + std::array m_exp2_access_time = {}; std::array m_bios_access_time = {}; std::array m_cdrom_access_time = {}; std::array m_spu_access_time = {}; diff --git a/src/core/bus.inl b/src/core/bus.inl index ede34c44a..22182cd93 100644 --- a/src/core/bus.inl +++ b/src/core/bus.inl @@ -2,7 +2,7 @@ #include "bus.h" template -bool Bus::DoRAMAccess(u32 offset, u32& value) +TickCount Bus::DoRAMAccess(u32 offset, u32& value) { // TODO: Configurable mirroring. offset &= UINT32_C(0x1FFFFF); @@ -40,11 +40,12 @@ bool Bus::DoRAMAccess(u32 offset, u32& value) } } - return true; + // Nocash docs say RAM takes 6 cycles to access. + return RAM_ACCESS_DELAY; } template -bool Bus::DoBIOSAccess(u32 offset, u32& value) +TickCount Bus::DoBIOSAccess(u32 offset, u32& value) { // TODO: Configurable mirroring. if constexpr (type == MemoryAccessType::Read) @@ -70,11 +71,11 @@ bool Bus::DoBIOSAccess(u32 offset, u32& value) // Writes are ignored. } - return true; + return m_bios_access_time[static_cast(size)]; } template -bool Bus::DispatchAccess(PhysicalMemoryAddress address, u32& value) +TickCount Bus::DispatchAccess(PhysicalMemoryAddress address, u32& value) { if (address < 0x800000) { @@ -86,8 +87,12 @@ bool Bus::DispatchAccess(PhysicalMemoryAddress address, u32& value) } else if (address < (EXP1_BASE + EXP1_SIZE)) { - return (type == MemoryAccessType::Read) ? DoReadEXP1(size, address & EXP1_MASK, value) : - DoWriteEXP1(size, address & EXP1_MASK, value); + if constexpr (type == MemoryAccessType::Read) + value = DoReadEXP1(size, address & EXP1_MASK); + else + DoWriteEXP1(size, address & EXP1_MASK, value); + + return m_exp1_access_time[static_cast(size)]; } else if (address < MEMCTRL_BASE) { @@ -95,39 +100,66 @@ bool Bus::DispatchAccess(PhysicalMemoryAddress address, u32& value) } else if (address < (MEMCTRL_BASE + MEMCTRL_SIZE)) { - return (type == MemoryAccessType::Read) ? DoReadMemoryControl(size, address & PAD_MASK, value) : - DoWriteMemoryControl(size, address & PAD_MASK, value); + if constexpr (type == MemoryAccessType::Read) + value = DoReadMemoryControl(size, address & PAD_MASK); + else + DoWriteMemoryControl(size, address & PAD_MASK, value); + + return 1; } else if (address < (PAD_BASE + PAD_SIZE)) { - return (type == MemoryAccessType::Read) ? DoReadPad(size, address & PAD_MASK, value) : - DoWritePad(size, address & PAD_MASK, value); + if constexpr (type == MemoryAccessType::Read) + value = DoReadPad(size, address & PAD_MASK); + else + DoWritePad(size, address & PAD_MASK, value); + + return 1; } else if (address < (SIO_BASE + SIO_SIZE)) { - return (type == MemoryAccessType::Read) ? DoReadSIO(size, address & SIO_MASK, value) : - DoWriteSIO(size, address & SIO_MASK, value); + if constexpr (type == MemoryAccessType::Read) + value = DoReadSIO(size, address & SIO_MASK); + else + DoWriteSIO(size, address & SIO_MASK, value); + + return 1; } else if (address < (MEMCTRL2_BASE + MEMCTRL2_SIZE)) { - return (type == MemoryAccessType::Read) ? DoReadMemoryControl2(size, address & PAD_MASK, value) : - DoWriteMemoryControl2(size, address & PAD_MASK, value); + if constexpr (type == MemoryAccessType::Read) + value = DoReadMemoryControl2(size, address & PAD_MASK); + else + DoWriteMemoryControl2(size, address & PAD_MASK, value); + + return 1; } else if (address < (INTERRUPT_CONTROLLER_BASE + INTERRUPT_CONTROLLER_SIZE)) { - return (type == MemoryAccessType::Read) ? - DoReadInterruptController(size, address & INTERRUPT_CONTROLLER_MASK, value) : - DoWriteInterruptController(size, address & INTERRUPT_CONTROLLER_MASK, value); + if constexpr (type == MemoryAccessType::Read) + value = DoReadInterruptController(size, address & INTERRUPT_CONTROLLER_MASK); + else + DoWriteInterruptController(size, address & INTERRUPT_CONTROLLER_MASK, value); + + return 1; } else if (address < (DMA_BASE + DMA_SIZE)) { - return (type == MemoryAccessType::Read) ? DoReadDMA(size, address & DMA_MASK, value) : - DoWriteDMA(size, address & DMA_MASK, value); + if constexpr (type == MemoryAccessType::Read) + value = DoReadDMA(size, address & DMA_MASK); + else + DoWriteDMA(size, address & DMA_MASK, value); + + return 1; } else if (address < (TIMERS_BASE + TIMERS_SIZE)) { - return (type == MemoryAccessType::Read) ? DoReadTimers(size, address & TIMERS_MASK, value) : - DoWriteTimers(size, address & TIMERS_MASK, value); + if constexpr (type == MemoryAccessType::Read) + value = DoReadTimers(size, address & TIMERS_MASK); + else + DoWriteTimers(size, address & TIMERS_MASK, value); + + return 1; } else if (address < CDROM_BASE) { @@ -135,18 +167,30 @@ bool Bus::DispatchAccess(PhysicalMemoryAddress address, u32& value) } else if (address < (CDROM_BASE + GPU_SIZE)) { - return (type == MemoryAccessType::Read) ? DoReadCDROM(size, address & CDROM_MASK, value) : - DoWriteCDROM(size, address & CDROM_MASK, value); + if constexpr (type == MemoryAccessType::Read) + value = DoReadCDROM(size, address & CDROM_MASK); + else + DoWriteCDROM(size, address & CDROM_MASK, value); + + return m_cdrom_access_time[static_cast(size)]; } else if (address < (GPU_BASE + GPU_SIZE)) { - return (type == MemoryAccessType::Read) ? DoReadGPU(size, address & GPU_MASK, value) : - DoWriteGPU(size, address & GPU_MASK, value); + if constexpr (type == MemoryAccessType::Read) + value = DoReadGPU(size, address & GPU_MASK); + else + DoWriteGPU(size, address & GPU_MASK, value); + + return 1; } else if (address < (MDEC_BASE + MDEC_SIZE)) { - return (type == MemoryAccessType::Read) ? DoReadMDEC(size, address & MDEC_MASK, value) : - DoWriteMDEC(size, address & MDEC_MASK, value); + if constexpr (type == MemoryAccessType::Read) + value = DoReadMDEC(size, address & MDEC_MASK); + else + DoWriteMDEC(size, address & MDEC_MASK, value); + + return 1; } else if (address < SPU_BASE) { @@ -154,8 +198,12 @@ bool Bus::DispatchAccess(PhysicalMemoryAddress address, u32& value) } else if (address < (SPU_BASE + SPU_SIZE)) { - return (type == MemoryAccessType::Read) ? DoReadSPU(size, address & SPU_MASK, value) : - DoWriteSPU(size, address & SPU_MASK, value); + if constexpr (type == MemoryAccessType::Read) + value = DoReadSPU(size, address & SPU_MASK); + else + DoWriteSPU(size, address & SPU_MASK, value); + + return m_spu_access_time[static_cast(size)]; } else if (address < EXP2_BASE) { @@ -163,8 +211,12 @@ bool Bus::DispatchAccess(PhysicalMemoryAddress address, u32& value) } else if (address < (EXP2_BASE + EXP2_SIZE)) { - return (type == MemoryAccessType::Read) ? DoReadEXP2(size, address & EXP2_MASK, value) : - DoWriteEXP2(size, address & EXP2_MASK, value); + if constexpr (type == MemoryAccessType::Read) + value = DoReadEXP2(size, address & EXP2_MASK); + else + DoWriteEXP2(size, address & EXP2_MASK, value); + + return m_exp2_access_time[static_cast(size)]; } else if (address < BIOS_BASE) { diff --git a/src/core/cpu_core.cpp b/src/core/cpu_core.cpp index 9b2c97420..ac577d6d3 100644 --- a/src/core/cpu_core.cpp +++ b/src/core/cpu_core.cpp @@ -95,12 +95,16 @@ void Core::SetPC(u32 new_pc) bool Core::ReadMemoryByte(VirtualMemoryAddress addr, u8* value) { u32 temp = 0; - const bool result = DoMemoryAccess(addr, temp); + const TickCount cycles = DoMemoryAccess(addr, temp); *value = Truncate8(temp); - if (!result) + if (cycles < 0) + { RaiseException(Exception::DBE); + return false; + } - return result; + AddTicks(cycles - 1); + return true; } bool Core::ReadMemoryHalfWord(VirtualMemoryAddress addr, u16* value) @@ -109,12 +113,16 @@ bool Core::ReadMemoryHalfWord(VirtualMemoryAddress addr, u16* value) return false; u32 temp = 0; - const bool result = DoMemoryAccess(addr, temp); + const TickCount cycles = DoMemoryAccess(addr, temp); *value = Truncate16(temp); - if (!result) + if (cycles < 0) + { RaiseException(Exception::DBE); + return false; + } - return result; + AddTicks(cycles - 1); + return true; } bool Core::ReadMemoryWord(VirtualMemoryAddress addr, u32* value) @@ -122,21 +130,29 @@ bool Core::ReadMemoryWord(VirtualMemoryAddress addr, u32* value) if (!DoAlignmentCheck(addr)) return false; - const bool result = DoMemoryAccess(addr, *value); - if (!result) + const TickCount cycles = DoMemoryAccess(addr, *value); + if (cycles < 0) + { RaiseException(Exception::DBE); + return false; + } - return result; + AddTicks(cycles - 1); + return true; } bool Core::WriteMemoryByte(VirtualMemoryAddress addr, u8 value) { u32 temp = ZeroExtend32(value); - const bool result = DoMemoryAccess(addr, temp); - if (!result) + const TickCount cycles = DoMemoryAccess(addr, temp); + if (cycles < 0) + { RaiseException(Exception::DBE); + return false; + } - return result; + AddTicks(cycles - 1); + return true; } bool Core::WriteMemoryHalfWord(VirtualMemoryAddress addr, u16 value) @@ -145,11 +161,15 @@ bool Core::WriteMemoryHalfWord(VirtualMemoryAddress addr, u16 value) return false; u32 temp = ZeroExtend32(value); - const bool result = DoMemoryAccess(addr, temp); - if (!result) + const TickCount cycles = DoMemoryAccess(addr, temp); + if (cycles < 0) + { RaiseException(Exception::DBE); + return false; + } - return result; + AddTicks(cycles - 1); + return cycles; } bool Core::WriteMemoryWord(VirtualMemoryAddress addr, u32 value) @@ -157,49 +177,53 @@ bool Core::WriteMemoryWord(VirtualMemoryAddress addr, u32 value) if (!DoAlignmentCheck(addr)) return false; - const bool result = DoMemoryAccess(addr, value); - if (!result) + const TickCount cycles = DoMemoryAccess(addr, value); + if (cycles < 0) + { RaiseException(Exception::DBE); + return false; + } - return result; + AddTicks(cycles - 1); + return true; } bool Core::SafeReadMemoryByte(VirtualMemoryAddress addr, u8* value) { u32 temp = 0; - const bool result = DoMemoryAccess(addr, temp); + const TickCount cycles = DoMemoryAccess(addr, temp); *value = Truncate8(temp); - return result; + return (cycles >= 0); } bool Core::SafeReadMemoryHalfWord(VirtualMemoryAddress addr, u16* value) { u32 temp = 0; - const bool result = DoMemoryAccess(addr, temp); + const TickCount cycles = DoMemoryAccess(addr, temp); *value = Truncate16(temp); - return result; + return (cycles >= 0); } bool Core::SafeReadMemoryWord(VirtualMemoryAddress addr, u32* value) { - return DoMemoryAccess(addr, *value); + return DoMemoryAccess(addr, *value) >= 0; } bool Core::SafeWriteMemoryByte(VirtualMemoryAddress addr, u8 value) { u32 temp = ZeroExtend32(value); - return DoMemoryAccess(addr, temp); + return DoMemoryAccess(addr, temp) >= 0; } bool Core::SafeWriteMemoryHalfWord(VirtualMemoryAddress addr, u16 value) { u32 temp = ZeroExtend32(value); - return DoMemoryAccess(addr, temp); + return DoMemoryAccess(addr, temp) >= 0; } bool Core::SafeWriteMemoryWord(VirtualMemoryAddress addr, u32 value) { - return DoMemoryAccess(addr, value); + return DoMemoryAccess(addr, value) >= 0; } void Core::Branch(u32 target) @@ -235,10 +259,13 @@ void Core::RaiseException(Exception excode) void Core::RaiseException(Exception excode, u32 EPC, bool BD, bool BT, u8 CE) { - Log_DebugPrintf("Exception %u at 0x%08X (epc=0x%08X, BD=%s, CE=%u)", static_cast(excode), - m_current_instruction_pc, EPC, BD ? "true" : "false", ZeroExtend32(CE)); #ifdef Y_BUILD_CONFIG_DEBUG - DisassembleAndPrint(m_current_instruction_pc, 4, 0); + if (excode != Exception::INT && excode != Exception::Syscall && excode != Exception::BP) + { + Log_DebugPrintf("Exception %u at 0x%08X (epc=0x%08X, BD=%s, CE=%u)", static_cast(excode), + m_current_instruction_pc, EPC, BD ? "true" : "false", ZeroExtend32(CE)); + DisassembleAndPrint(m_current_instruction_pc, 4, 0); + } #endif m_cop0_regs.EPC = EPC; @@ -499,8 +526,8 @@ void Core::Execute() { while (m_downcount >= 0) { - m_pending_ticks += 2; - m_downcount -= 2; + m_pending_ticks += 1; + m_downcount -= 1; // now executing the instruction we previously fetched m_current_instruction = m_next_instruction; @@ -542,7 +569,7 @@ bool Core::FetchInstruction() RaiseException(Exception::AdEL, m_regs.npc, false, false, 0); return false; } - else if (!DoMemoryAccess(m_regs.npc, m_next_instruction.bits)) + else if (DoMemoryAccess(m_regs.npc, m_next_instruction.bits) < 0) { // Bus errors don't set BadVaddr. RaiseException(Exception::IBE, m_regs.npc, false, false, 0); diff --git a/src/core/cpu_core.h b/src/core/cpu_core.h index ff659087b..7da313134 100644 --- a/src/core/cpu_core.h +++ b/src/core/cpu_core.h @@ -56,7 +56,7 @@ public: private: template - bool DoMemoryAccess(VirtualMemoryAddress address, u32& value); + TickCount DoMemoryAccess(VirtualMemoryAddress address, u32& value); template bool DoAlignmentCheck(VirtualMemoryAddress address); @@ -75,6 +75,13 @@ private: bool InUserMode() const { return m_cop0_regs.sr.KUc; } bool InKernelMode() const { return !m_cop0_regs.sr.KUc; } + // timing + void AddTicks(TickCount ticks) + { + m_pending_ticks += ticks; + m_downcount -= ticks; + } + void DisassembleAndPrint(u32 addr); void DisassembleAndPrint(u32 addr, u32 instructions_before, u32 instructions_after); diff --git a/src/core/cpu_core.inl b/src/core/cpu_core.inl index 708702c9a..1e68ed650 100644 --- a/src/core/cpu_core.inl +++ b/src/core/cpu_core.inl @@ -6,7 +6,7 @@ namespace CPU { template -bool Core::DoMemoryAccess(VirtualMemoryAddress address, u32& value) +TickCount Core::DoMemoryAccess(VirtualMemoryAddress address, u32& value) { switch (address >> 29) { @@ -15,23 +15,17 @@ bool Core::DoMemoryAccess(VirtualMemoryAddress address, u32& value) if constexpr (type == MemoryAccessType::Write) { if (m_cop0_regs.sr.Isc) - return true; + return 1; } const PhysicalMemoryAddress phys_addr = address & UINT32_C(0x1FFFFFFF); if ((phys_addr & DCACHE_LOCATION_MASK) == DCACHE_LOCATION) { DoScratchpadAccess(phys_addr, value); - return true; + return 1; } - if (!m_bus->DispatchAccess(phys_addr, value)) - { - Panic("Bus error"); - return false; - } - - return true; + return m_bus->DispatchAccess(phys_addr, value); } case 0x01: // KUSEG 512M-1024M @@ -39,7 +33,7 @@ bool Core::DoMemoryAccess(VirtualMemoryAddress address, u32& value) case 0x03: // KUSEG 1536M-2048M { // Above 512mb raises an exception. - return false; + return -1; } case 0x04: // KSEG0 - physical memory cached @@ -47,36 +41,24 @@ bool Core::DoMemoryAccess(VirtualMemoryAddress address, u32& value) if constexpr (type == MemoryAccessType::Write) { if (m_cop0_regs.sr.Isc) - return true; + return 1; } const PhysicalMemoryAddress phys_addr = address & UINT32_C(0x1FFFFFFF); if ((phys_addr & DCACHE_LOCATION_MASK) == DCACHE_LOCATION) { DoScratchpadAccess(phys_addr, value); - return true; + return 1; } - if (!m_bus->DispatchAccess(phys_addr, value)) - { - Panic("Bus error"); - return false; - } - - return true; + return m_bus->DispatchAccess(phys_addr, value); } break; case 0x05: // KSEG1 - physical memory uncached { const PhysicalMemoryAddress phys_addr = address & UINT32_C(0x1FFFFFFF); - if (!m_bus->DispatchAccess(phys_addr, value)) - { - Panic("Bus error"); - return false; - } - - return true; + return m_bus->DispatchAccess(phys_addr, value); } break; @@ -90,11 +72,11 @@ bool Core::DoMemoryAccess(VirtualMemoryAddress address, u32& value) else WriteCacheControl(value); - return true; + return 1; } else { - return false; + return -1; } }