CPU: Correct bits for CAUSE.CE, EPC for fetch

This commit is contained in:
Connor McLaughlin 2019-10-04 02:26:37 +10:00
parent 48563c74cf
commit eddd2c1990
5 changed files with 80 additions and 37 deletions

View File

@ -89,10 +89,11 @@ int main(int argc, char* argv[])
// set log flags // set log flags
// g_pLog->SetConsoleOutputParams(true, nullptr, LOGLEVEL_DEBUG); // 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 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 #ifdef Y_BUILD_CONFIG_RELEASE
g_pLog->SetFilterLevel(LOGLEVEL_INFO); g_pLog->SetFilterLevel(LOGLEVEL_INFO);
// g_pLog->SetFilterLevel(LOGLEVEL_DEV);
// g_pLog->SetFilterLevel(LOGLEVEL_PROFILE); // g_pLog->SetFilterLevel(LOGLEVEL_PROFILE);
#else #else
// g_pLog->SetFilterLevel(LOGLEVEL_TRACE); // g_pLog->SetFilterLevel(LOGLEVEL_TRACE);

View File

@ -224,12 +224,25 @@ u32 Core::GetExceptionVector(Exception excode) const
#endif #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<u32>(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.Excode = excode;
m_cop0_regs.cause.BD = m_in_branch_delay_slot; m_cop0_regs.cause.BD = BD;
m_cop0_regs.cause.CE = coprocessor; m_cop0_regs.cause.CE = CE;
// current -> previous, switch to kernel mode and disable interrupts // current -> previous, switch to kernel mode and disable interrupts
m_cop0_regs.sr.mode_bits <<= 2; m_cop0_regs.sr.mode_bits <<= 2;
@ -452,6 +465,25 @@ void Core::DisassembleAndPrint(u32 addr)
PrintInstruction(bits, addr, this); 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() void Core::Execute()
{ {
while (m_downcount >= 0) while (m_downcount >= 0)
@ -460,7 +492,7 @@ void Core::Execute()
m_downcount -= 2; m_downcount -= 2;
// now executing the instruction we previously fetched // 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; m_current_instruction_pc = m_regs.pc;
// handle branch delays - we are now in a delay slot if we just branched // handle branch delays - we are now in a delay slot if we just branched
@ -472,7 +504,7 @@ void Core::Execute()
continue; continue;
// execute the instruction we previously fetched // execute the instruction we previously fetched
ExecuteInstruction(inst); ExecuteInstruction();
// next load delay // next load delay
m_load_delay_reg = m_next_load_delay_reg; m_load_delay_reg = m_next_load_delay_reg;
@ -484,26 +516,29 @@ void Core::Execute()
bool Core::FetchInstruction() 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<MemoryAccessType::Read, MemoryAccessSize::Word>(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; m_regs.pc = m_regs.npc;
if (!DoAlignmentCheck<MemoryAccessType::Read, MemoryAccessSize::Word>(static_cast<VirtualMemoryAddress>(m_regs.npc)))
{
// this will call FetchInstruction() again when the pipeline is flushed.
return false;
}
if (!DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(static_cast<VirtualMemoryAddress>(m_regs.npc),
m_next_instruction.bits))
{
RaiseException(Exception::IBE);
return false;
}
m_regs.npc += sizeof(m_next_instruction.bits); m_regs.npc += sizeof(m_next_instruction.bits);
return true; return true;
} }
void Core::ExecuteInstruction(Instruction inst) void Core::ExecuteInstruction()
{ {
const Instruction inst = m_current_instruction;
#if 0 #if 0
if (inst_pc == 0xBFC06FF0) if (inst_pc == 0xBFC06FF0)
{ {
@ -1039,11 +1074,11 @@ void Core::ExecuteInstruction(Instruction inst)
if (InUserMode() && !m_cop0_regs.sr.CU0) if (InUserMode() && !m_cop0_regs.sr.CU0)
{ {
Log_WarningPrintf("Coprocessor 0 not present in user mode"); Log_WarningPrintf("Coprocessor 0 not present in user mode");
RaiseException(Exception::CpU, 0); RaiseException(Exception::CpU);
return; return;
} }
ExecuteCop0Instruction(inst); ExecuteCop0Instruction();
} }
break; break;
@ -1052,11 +1087,11 @@ void Core::ExecuteInstruction(Instruction inst)
if (InUserMode() && !m_cop0_regs.sr.CU2) if (InUserMode() && !m_cop0_regs.sr.CU2)
{ {
Log_WarningPrintf("Coprocessor 2 not present in user mode"); Log_WarningPrintf("Coprocessor 2 not present in user mode");
RaiseException(Exception::CpU, 2); RaiseException(Exception::CpU);
return; return;
} }
ExecuteCop2Instruction(inst); ExecuteCop2Instruction();
} }
break; break;
@ -1065,7 +1100,7 @@ void Core::ExecuteInstruction(Instruction inst)
if (InUserMode() && !m_cop0_regs.sr.CU2) if (InUserMode() && !m_cop0_regs.sr.CU2)
{ {
Log_WarningPrintf("Coprocessor 2 not present in user mode"); Log_WarningPrintf("Coprocessor 2 not present in user mode");
RaiseException(Exception::CpU, 2); RaiseException(Exception::CpU);
return; return;
} }
@ -1083,7 +1118,7 @@ void Core::ExecuteInstruction(Instruction inst)
if (InUserMode() && !m_cop0_regs.sr.CU2) if (InUserMode() && !m_cop0_regs.sr.CU2)
{ {
Log_WarningPrintf("Coprocessor 2 not present in user mode"); Log_WarningPrintf("Coprocessor 2 not present in user mode");
RaiseException(Exception::CpU, 2); RaiseException(Exception::CpU);
return; return;
} }
@ -1101,7 +1136,7 @@ void Core::ExecuteInstruction(Instruction inst)
case InstructionOp::lwc3: case InstructionOp::lwc3:
case InstructionOp::swc3: case InstructionOp::swc3:
{ {
RaiseException(Exception::CpU, inst.cop.cop_n); RaiseException(Exception::CpU);
} }
break; 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()) if (inst.cop.IsCommonInstruction())
{ {
switch (inst.cop.CommonOp()) 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()) if (inst.cop.IsCommonInstruction())
{ {
// TODO: Combine with cop0. // TODO: Combine with cop0.

View File

@ -75,17 +75,19 @@ private:
bool InKernelMode() const { return !m_cop0_regs.sr.KUc; } bool InKernelMode() const { return !m_cop0_regs.sr.KUc; }
void DisassembleAndPrint(u32 addr); void DisassembleAndPrint(u32 addr);
void DisassembleAndPrint(u32 addr, u32 instructions_before, u32 instructions_after);
// Fetches the instruction at m_regs.npc // Fetches the instruction at m_regs.npc
bool FetchInstruction(); bool FetchInstruction();
void ExecuteInstruction(Instruction inst); void ExecuteInstruction();
void ExecuteCop0Instruction(Instruction inst); void ExecuteCop0Instruction();
void ExecuteCop2Instruction(Instruction inst); void ExecuteCop2Instruction();
void Branch(u32 target); void Branch(u32 target);
// exceptions // exceptions
u32 GetExceptionVector(Exception excode) const; 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(); bool DispatchInterrupts();
// flushes any load delays if present // flushes any load delays if present
@ -119,6 +121,7 @@ private:
Instruction m_next_instruction = {}; Instruction m_next_instruction = {};
// address of the instruction currently being executed // address of the instruction currently being executed
Instruction m_current_instruction = {};
u32 m_current_instruction_pc = 0; u32 m_current_instruction_pc = 0;
// load delays // load delays

View File

@ -109,12 +109,12 @@ bool CPU::Core::DoAlignmentCheck(VirtualMemoryAddress address)
{ {
if constexpr (size == MemoryAccessSize::HalfWord) if constexpr (size == MemoryAccessSize::HalfWord)
{ {
if ((address & UINT32_C(1)) == 0) if (Common::IsAlignedPow2(address, 2))
return true; return true;
} }
else if constexpr (size == MemoryAccessSize::Word) else if constexpr (size == MemoryAccessSize::Word)
{ {
if ((address & UINT32_C(3)) == 0) if (Common::IsAlignedPow2(address, 4))
return true; return true;
} }
else else

View File

@ -73,5 +73,5 @@ private:
GLStats m_stats = {}; GLStats m_stats = {};
GLStats m_last_stats = {}; GLStats m_last_stats = {};
bool m_show_vram = true; bool m_show_vram = false;
}; };