From eddd2c1990d099bb2dee1f95879c6eb24889511b Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Fri, 4 Oct 2019 02:26:37 +1000 Subject: [PATCH] CPU: Correct bits for CAUSE.CE, EPC for fetch --- src/pse-sdl/main.cpp | 3 +- src/pse/cpu_core.cpp | 97 +++++++++++++++++++++++++++++------------ src/pse/cpu_core.h | 11 +++-- src/pse/cpu_core.inl | 4 +- src/pse/gpu_hw_opengl.h | 2 +- 5 files changed, 80 insertions(+), 37 deletions(-) diff --git a/src/pse-sdl/main.cpp b/src/pse-sdl/main.cpp index d3433c004..6ff0a977e 100644 --- a/src/pse-sdl/main.cpp +++ b/src/pse-sdl/main.cpp @@ -89,10 +89,11 @@ int main(int argc, char* argv[]) // set log flags // g_pLog->SetConsoleOutputParams(true, nullptr, LOGLEVEL_DEBUG); // g_pLog->SetConsoleOutputParams(true, "GPU GPU_HW_OpenGL SPU Pad DigitalController", LOGLEVEL_DEBUG); - g_pLog->SetConsoleOutputParams(true, "GPU GPU_HW_OpenGL CDROM DMA SPU Pad DigitalController", LOGLEVEL_DEBUG); + g_pLog->SetConsoleOutputParams(true, "GPU GPU_HW_OpenGL SPU Pad DigitalController InterruptController", LOGLEVEL_DEBUG); #ifdef Y_BUILD_CONFIG_RELEASE g_pLog->SetFilterLevel(LOGLEVEL_INFO); + // g_pLog->SetFilterLevel(LOGLEVEL_DEV); // g_pLog->SetFilterLevel(LOGLEVEL_PROFILE); #else // g_pLog->SetFilterLevel(LOGLEVEL_TRACE); diff --git a/src/pse/cpu_core.cpp b/src/pse/cpu_core.cpp index 0f2b4c43a..c70f12c7f 100644 --- a/src/pse/cpu_core.cpp +++ b/src/pse/cpu_core.cpp @@ -224,12 +224,25 @@ u32 Core::GetExceptionVector(Exception excode) const #endif } -void Core::RaiseException(Exception excode, u8 coprocessor /* = 0 */) +void Core::RaiseException(Exception excode) { - m_cop0_regs.EPC = m_in_branch_delay_slot ? (m_current_instruction_pc - UINT32_C(4)) : m_current_instruction_pc; + const bool BD = m_in_branch_delay_slot; + const u32 EPC = BD ? (m_current_instruction_pc - UINT32_C(4)) : m_current_instruction_pc; + RaiseException(excode, EPC, BD, m_current_instruction.cop.cop_n); +} + +void Core::RaiseException(Exception excode, u32 EPC, bool BD, u8 CE) +{ + Log_WarningPrintf("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); +#endif + + m_cop0_regs.EPC = EPC; m_cop0_regs.cause.Excode = excode; - m_cop0_regs.cause.BD = m_in_branch_delay_slot; - m_cop0_regs.cause.CE = coprocessor; + m_cop0_regs.cause.BD = BD; + m_cop0_regs.cause.CE = CE; // current -> previous, switch to kernel mode and disable interrupts m_cop0_regs.sr.mode_bits <<= 2; @@ -452,6 +465,25 @@ void Core::DisassembleAndPrint(u32 addr) PrintInstruction(bits, addr, this); } +void Core::DisassembleAndPrint(u32 addr, u32 instructions_before /* = 0 */, u32 instructions_after /* = 0 */) +{ + u32 disasm_addr = addr - (instructions_before * sizeof(u32)); + for (u32 i = 0; i < instructions_before; i++) + { + DisassembleAndPrint(disasm_addr); + disasm_addr += sizeof(u32); + } + + std::printf("----> "); + + // <= to include the instruction itself + for (u32 i = 0; i <= instructions_after; i++) + { + DisassembleAndPrint(disasm_addr); + disasm_addr += sizeof(u32); + } +} + void Core::Execute() { while (m_downcount >= 0) @@ -460,7 +492,7 @@ void Core::Execute() m_downcount -= 2; // now executing the instruction we previously fetched - const Instruction inst = m_next_instruction; + m_current_instruction = m_next_instruction; m_current_instruction_pc = m_regs.pc; // handle branch delays - we are now in a delay slot if we just branched @@ -472,7 +504,7 @@ void Core::Execute() continue; // execute the instruction we previously fetched - ExecuteInstruction(inst); + ExecuteInstruction(); // next load delay m_load_delay_reg = m_next_load_delay_reg; @@ -484,26 +516,29 @@ void Core::Execute() bool Core::FetchInstruction() { + if (!Common::IsAlignedPow2(m_regs.npc, 4)) + { + // The EPC must be set to the fetching address, not the instruction about to execute. + m_cop0_regs.BadVaddr = m_regs.npc; + RaiseException(Exception::AdEL, m_regs.npc, false, 0); + return false; + } + else if (!DoMemoryAccess(m_regs.npc, m_next_instruction.bits)) + { + // Bus errors don't set BadVaddr. + RaiseException(Exception::IBE, m_regs.npc, false, 0); + return false; + } + m_regs.pc = m_regs.npc; - - if (!DoAlignmentCheck(static_cast(m_regs.npc))) - { - // this will call FetchInstruction() again when the pipeline is flushed. - return false; - } - if (!DoMemoryAccess(static_cast(m_regs.npc), - m_next_instruction.bits)) - { - RaiseException(Exception::IBE); - return false; - } - m_regs.npc += sizeof(m_next_instruction.bits); return true; } -void Core::ExecuteInstruction(Instruction inst) +void Core::ExecuteInstruction() { + const Instruction inst = m_current_instruction; + #if 0 if (inst_pc == 0xBFC06FF0) { @@ -1039,11 +1074,11 @@ void Core::ExecuteInstruction(Instruction inst) if (InUserMode() && !m_cop0_regs.sr.CU0) { Log_WarningPrintf("Coprocessor 0 not present in user mode"); - RaiseException(Exception::CpU, 0); + RaiseException(Exception::CpU); return; } - ExecuteCop0Instruction(inst); + ExecuteCop0Instruction(); } break; @@ -1052,11 +1087,11 @@ void Core::ExecuteInstruction(Instruction inst) if (InUserMode() && !m_cop0_regs.sr.CU2) { Log_WarningPrintf("Coprocessor 2 not present in user mode"); - RaiseException(Exception::CpU, 2); + RaiseException(Exception::CpU); return; } - ExecuteCop2Instruction(inst); + ExecuteCop2Instruction(); } break; @@ -1065,7 +1100,7 @@ void Core::ExecuteInstruction(Instruction inst) if (InUserMode() && !m_cop0_regs.sr.CU2) { Log_WarningPrintf("Coprocessor 2 not present in user mode"); - RaiseException(Exception::CpU, 2); + RaiseException(Exception::CpU); return; } @@ -1083,7 +1118,7 @@ void Core::ExecuteInstruction(Instruction inst) if (InUserMode() && !m_cop0_regs.sr.CU2) { Log_WarningPrintf("Coprocessor 2 not present in user mode"); - RaiseException(Exception::CpU, 2); + RaiseException(Exception::CpU); return; } @@ -1101,7 +1136,7 @@ void Core::ExecuteInstruction(Instruction inst) case InstructionOp::lwc3: case InstructionOp::swc3: { - RaiseException(Exception::CpU, inst.cop.cop_n); + RaiseException(Exception::CpU); } break; @@ -1111,8 +1146,10 @@ void Core::ExecuteInstruction(Instruction inst) } } -void Core::ExecuteCop0Instruction(Instruction inst) +void Core::ExecuteCop0Instruction() { + const Instruction inst = m_current_instruction; + if (inst.cop.IsCommonInstruction()) { switch (inst.cop.CommonOp()) @@ -1148,8 +1185,10 @@ void Core::ExecuteCop0Instruction(Instruction inst) } } -void Core::ExecuteCop2Instruction(Instruction inst) +void Core::ExecuteCop2Instruction() { + const Instruction inst = m_current_instruction; + if (inst.cop.IsCommonInstruction()) { // TODO: Combine with cop0. diff --git a/src/pse/cpu_core.h b/src/pse/cpu_core.h index 4848572bc..c6d1c5941 100644 --- a/src/pse/cpu_core.h +++ b/src/pse/cpu_core.h @@ -75,17 +75,19 @@ private: bool InKernelMode() const { return !m_cop0_regs.sr.KUc; } void DisassembleAndPrint(u32 addr); + void DisassembleAndPrint(u32 addr, u32 instructions_before, u32 instructions_after); // Fetches the instruction at m_regs.npc bool FetchInstruction(); - void ExecuteInstruction(Instruction inst); - void ExecuteCop0Instruction(Instruction inst); - void ExecuteCop2Instruction(Instruction inst); + void ExecuteInstruction(); + void ExecuteCop0Instruction(); + void ExecuteCop2Instruction(); void Branch(u32 target); // exceptions u32 GetExceptionVector(Exception excode) const; - void RaiseException(Exception excode, u8 coprocessor = 0); + void RaiseException(Exception excode); + void RaiseException(Exception excode, u32 EPC, bool BD, u8 CE); bool DispatchInterrupts(); // flushes any load delays if present @@ -119,6 +121,7 @@ private: Instruction m_next_instruction = {}; // address of the instruction currently being executed + Instruction m_current_instruction = {}; u32 m_current_instruction_pc = 0; // load delays diff --git a/src/pse/cpu_core.inl b/src/pse/cpu_core.inl index a22d5dc53..708702c9a 100644 --- a/src/pse/cpu_core.inl +++ b/src/pse/cpu_core.inl @@ -109,12 +109,12 @@ bool CPU::Core::DoAlignmentCheck(VirtualMemoryAddress address) { if constexpr (size == MemoryAccessSize::HalfWord) { - if ((address & UINT32_C(1)) == 0) + if (Common::IsAlignedPow2(address, 2)) return true; } else if constexpr (size == MemoryAccessSize::Word) { - if ((address & UINT32_C(3)) == 0) + if (Common::IsAlignedPow2(address, 4)) return true; } else diff --git a/src/pse/gpu_hw_opengl.h b/src/pse/gpu_hw_opengl.h index 9edd7f995..3efde427f 100644 --- a/src/pse/gpu_hw_opengl.h +++ b/src/pse/gpu_hw_opengl.h @@ -73,5 +73,5 @@ private: GLStats m_stats = {}; GLStats m_last_stats = {}; - bool m_show_vram = true; + bool m_show_vram = false; };