CPU: Correct bits for CAUSE.CE, EPC for fetch
This commit is contained in:
parent
48563c74cf
commit
eddd2c1990
|
@ -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);
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue