Core: Handle branch/jump in a delay slot in the Interpreter

This commit is contained in:
zilmar 2022-11-01 08:59:15 +10:30
parent 94247ce1a6
commit fd71b2dfcb
6 changed files with 118 additions and 357 deletions

View File

@ -65,6 +65,7 @@ void CInterpreterCPU::ExecuteCPU()
uint32_t & PROGRAM_COUNTER = *_PROGRAM_COUNTER;
R4300iOpcode & Opcode = R4300iOp::m_Opcode;
uint32_t & JumpToLocation = g_System->m_JumpToLocation;
uint32_t & JumpDelayLocation = g_System->m_JumpDelayLocation;
bool & TestTimer = R4300iOp::m_TestTimer;
const int32_t & bDoSomething = g_SystemEvents->DoSomething();
uint32_t CountPerOp = g_System->CountPerOp();
@ -151,6 +152,11 @@ void CInterpreterCPU::ExecuteCPU()
}
}
break;
case PIPELINE_STAGE_JUMP_DELAY_SLOT:
PipelineStage = PIPELINE_STAGE_JUMP;
PROGRAM_COUNTER = JumpToLocation;
JumpToLocation = JumpDelayLocation;
break;
case PIPELINE_STAGE_PERMLOOP_DELAY_DONE:
PROGRAM_COUNTER = JumpToLocation;
PipelineStage = PIPELINE_STAGE_NORMAL;
@ -179,6 +185,7 @@ void CInterpreterCPU::ExecuteOps(int32_t Cycles)
uint32_t & PROGRAM_COUNTER = *_PROGRAM_COUNTER;
R4300iOpcode & Opcode = R4300iOp::m_Opcode;
PIPELINE_STAGE & PipelineStage = g_System->m_PipelineStage;
uint32_t & JumpDelayLocation = g_System->m_JumpDelayLocation;
uint32_t & JumpToLocation = g_System->m_JumpToLocation;
bool & TestTimer = R4300iOp::m_TestTimer;
const int32_t & DoSomething = g_SystemEvents->DoSomething();
@ -255,6 +262,11 @@ void CInterpreterCPU::ExecuteOps(int32_t Cycles)
}
}
break;
case PIPELINE_STAGE_JUMP_DELAY_SLOT:
PipelineStage = PIPELINE_STAGE_JUMP;
PROGRAM_COUNTER = JumpToLocation;
JumpToLocation = JumpDelayLocation;
break;
case PIPELINE_STAGE_PERMLOOP_DELAY_DONE:
PROGRAM_COUNTER = JumpToLocation;
PipelineStage = PIPELINE_STAGE_NORMAL;

View File

@ -707,107 +707,60 @@ R4300iOp::Func * R4300iOp::BuildInterpreter()
void R4300iOp::J()
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
g_System->m_JumpToLocation = ((*_PROGRAM_COUNTER) & 0xF0000000) + (m_Opcode.target << 2);
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
g_System->DelayedJump((*_PROGRAM_COUNTER & 0xF0000000) + (m_Opcode.target << 2));
}
void R4300iOp::JAL()
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
g_System->m_JumpToLocation = ((*_PROGRAM_COUNTER) & 0xF0000000) + (m_Opcode.target << 2);
_GPR[31].DW = (int32_t)((*_PROGRAM_COUNTER) + 8);
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
g_System->DelayedJump((*_PROGRAM_COUNTER & 0xF0000000) + (m_Opcode.target << 2));
_GPR[31].DW = (int32_t)(g_System->m_PipelineStage == PIPELINE_STAGE_JUMP_DELAY_SLOT ? g_System->m_JumpToLocation + 4 : *_PROGRAM_COUNTER + 8);
}
void R4300iOp::BEQ()
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
if (_GPR[m_Opcode.rs].DW == _GPR[m_Opcode.rt].DW)
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + ((int16_t)m_Opcode.offset << 2) + 4;
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
R4300iOpcode DelaySlot;
if (g_MMU->MemoryValue32(*_PROGRAM_COUNTER + 4, DelaySlot.Value) && !R4300iInstruction(*_PROGRAM_COUNTER, m_Opcode.Value).DelaySlotEffectsCompare(DelaySlot.Value))
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
}
g_System->DelayedRelativeJump(((int16_t)m_Opcode.offset << 2) + 4);
}
else
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + 8;
g_System->DelayedJump(*_PROGRAM_COUNTER + 8);
}
}
void R4300iOp::BNE()
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
if (_GPR[m_Opcode.rs].DW != _GPR[m_Opcode.rt].DW)
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + ((int16_t)m_Opcode.offset << 2) + 4;
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
R4300iOpcode DelaySlot;
if (g_MMU->MemoryValue32(*_PROGRAM_COUNTER + 4, DelaySlot.Value) && !R4300iInstruction(*_PROGRAM_COUNTER, m_Opcode.Value).DelaySlotEffectsCompare(DelaySlot.Value))
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
}
g_System->DelayedRelativeJump(((int16_t)m_Opcode.offset << 2) + 4);
}
else
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + 8;
g_System->DelayedJump(*_PROGRAM_COUNTER + 8);
}
}
void R4300iOp::BLEZ()
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
if (_GPR[m_Opcode.rs].DW <= 0)
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + ((int16_t)m_Opcode.offset << 2) + 4;
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
R4300iOpcode DelaySlot;
if (g_MMU->MemoryValue32(*_PROGRAM_COUNTER + 4, DelaySlot.Value) && !R4300iInstruction(*_PROGRAM_COUNTER, m_Opcode.Value).DelaySlotEffectsCompare(DelaySlot.Value))
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
}
g_System->DelayedRelativeJump(((int16_t)m_Opcode.offset << 2) + 4);
}
else
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + 8;
g_System->DelayedJump(*_PROGRAM_COUNTER + 8);
}
}
void R4300iOp::BGTZ()
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
if (_GPR[m_Opcode.rs].DW > 0)
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + ((int16_t)m_Opcode.offset << 2) + 4;
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
R4300iOpcode DelaySlot;
if (g_MMU->MemoryValue32(*_PROGRAM_COUNTER + 4, DelaySlot.Value) && !R4300iInstruction(*_PROGRAM_COUNTER, m_Opcode.Value).DelaySlotEffectsCompare(DelaySlot.Value))
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
}
g_System->DelayedRelativeJump(((int16_t)m_Opcode.offset << 2) + 4);
}
else
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + 8;
g_System->DelayedJump(*_PROGRAM_COUNTER + 8);
}
}
@ -904,16 +857,7 @@ void R4300iOp::BEQL()
{
if (_GPR[m_Opcode.rs].DW == _GPR[m_Opcode.rt].DW)
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + ((int16_t)m_Opcode.offset << 2) + 4;
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
R4300iOpcode DelaySlot;
if (g_MMU->MemoryValue32(*_PROGRAM_COUNTER + 4, DelaySlot.Value) && !R4300iInstruction(*_PROGRAM_COUNTER, m_Opcode.Value).DelaySlotEffectsCompare(DelaySlot.Value))
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
}
g_System->DelayedRelativeJump(((int16_t)m_Opcode.offset << 2) + 4);
}
else
{
@ -926,16 +870,7 @@ void R4300iOp::BNEL()
{
if (_GPR[m_Opcode.rs].DW != _GPR[m_Opcode.rt].DW)
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + ((int16_t)m_Opcode.offset << 2) + 4;
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
R4300iOpcode DelaySlot;
if (g_MMU->MemoryValue32(*_PROGRAM_COUNTER + 4, DelaySlot.Value) && !R4300iInstruction(*_PROGRAM_COUNTER, m_Opcode.Value).DelaySlotEffectsCompare(DelaySlot.Value))
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
}
g_System->DelayedRelativeJump(((int16_t)m_Opcode.offset << 2) + 4);
}
else
{
@ -948,16 +883,7 @@ void R4300iOp::BLEZL()
{
if (_GPR[m_Opcode.rs].DW <= 0)
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + ((int16_t)m_Opcode.offset << 2) + 4;
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
R4300iOpcode DelaySlot;
if (g_MMU->MemoryValue32(*_PROGRAM_COUNTER + 4, DelaySlot.Value) && !R4300iInstruction(*_PROGRAM_COUNTER, m_Opcode.Value).DelaySlotEffectsCompare(DelaySlot.Value))
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
}
g_System->DelayedRelativeJump(((int16_t)m_Opcode.offset << 2) + 4);
}
else
{
@ -970,16 +896,7 @@ void R4300iOp::BGTZL()
{
if (_GPR[m_Opcode.rs].DW > 0)
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + ((int16_t)m_Opcode.offset << 2) + 4;
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
R4300iOpcode DelaySlot;
if (g_MMU->MemoryValue32(*_PROGRAM_COUNTER + 4, DelaySlot.Value) && !R4300iInstruction(*_PROGRAM_COUNTER, m_Opcode.Value).DelaySlotEffectsCompare(DelaySlot.Value))
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
}
g_System->DelayedRelativeJump(((int16_t)m_Opcode.offset << 2) + 4);
}
else
{
@ -1349,16 +1266,14 @@ void R4300iOp::SPECIAL_SRAV()
void R4300iOp::SPECIAL_JR()
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
g_System->m_JumpToLocation = _GPR[m_Opcode.rs].UW[0];
g_System->DelayedJump(_GPR[m_Opcode.rs].UW[0]);
m_TestTimer = true;
}
void R4300iOp::SPECIAL_JALR()
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
g_System->m_JumpToLocation = _GPR[m_Opcode.rs].UW[0];
_GPR[m_Opcode.rd].DW = (int32_t)((*_PROGRAM_COUNTER) + 8);
g_System->DelayedJump(_GPR[m_Opcode.rs].UW[0]);
_GPR[m_Opcode.rd].DW = (int32_t)(g_System->m_PipelineStage == PIPELINE_STAGE_JUMP_DELAY_SLOT ? g_System->m_JumpToLocation + 4 : *_PROGRAM_COUNTER + 8);
m_TestTimer = true;
}
@ -1735,43 +1650,25 @@ void R4300iOp::SPECIAL_DSRA32()
void R4300iOp::REGIMM_BLTZ()
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
if (_GPR[m_Opcode.rs].DW < 0)
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + ((int16_t)m_Opcode.offset << 2) + 4;
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
R4300iOpcode DelaySlot;
if (g_MMU->MemoryValue32(*_PROGRAM_COUNTER + 4, DelaySlot.Value) && !R4300iInstruction(*_PROGRAM_COUNTER, m_Opcode.Value).DelaySlotEffectsCompare(DelaySlot.Value))
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
}
g_System->DelayedRelativeJump(((int16_t)m_Opcode.offset << 2) + 4);
}
else
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + 8;
g_System->DelayedJump(*_PROGRAM_COUNTER + 8);
}
}
void R4300iOp::REGIMM_BGEZ()
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
if (_GPR[m_Opcode.rs].DW >= 0)
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + ((int16_t)m_Opcode.offset << 2) + 4;
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
R4300iOpcode DelaySlot;
if (g_MMU->MemoryValue32(*_PROGRAM_COUNTER + 4, DelaySlot.Value) && !R4300iInstruction(*_PROGRAM_COUNTER, m_Opcode.Value).DelaySlotEffectsCompare(DelaySlot.Value))
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
}
g_System->DelayedRelativeJump(((int16_t)m_Opcode.offset << 2) + 4);
}
else
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + 8;
g_System->DelayedJump(*_PROGRAM_COUNTER + 8);
}
}
@ -1779,16 +1676,7 @@ void R4300iOp::REGIMM_BLTZL()
{
if (_GPR[m_Opcode.rs].DW < 0)
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + ((int16_t)m_Opcode.offset << 2) + 4;
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
R4300iOpcode DelaySlot;
if (g_MMU->MemoryValue32(*_PROGRAM_COUNTER + 4, DelaySlot.Value) && !R4300iInstruction(*_PROGRAM_COUNTER, m_Opcode.Value).DelaySlotEffectsCompare(DelaySlot.Value))
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
}
g_System->DelayedRelativeJump(((int16_t)m_Opcode.offset << 2) + 4);
}
else
{
@ -1801,16 +1689,7 @@ void R4300iOp::REGIMM_BGEZL()
{
if (_GPR[m_Opcode.rs].DW >= 0)
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + ((int16_t)m_Opcode.offset << 2) + 4;
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
R4300iOpcode DelaySlot;
if (g_MMU->MemoryValue32(*_PROGRAM_COUNTER + 4, DelaySlot.Value) && !R4300iInstruction(*_PROGRAM_COUNTER, m_Opcode.Value).DelaySlotEffectsCompare(DelaySlot.Value))
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
}
g_System->DelayedRelativeJump(((int16_t)m_Opcode.offset << 2) + 4);
}
else
{
@ -1821,73 +1700,42 @@ void R4300iOp::REGIMM_BGEZL()
void R4300iOp::REGIMM_BLTZAL()
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
if (_GPR[m_Opcode.rs].DW < 0)
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + ((int16_t)m_Opcode.offset << 2) + 4;
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
R4300iOpcode DelaySlot;
if (g_MMU->MemoryValue32(*_PROGRAM_COUNTER + 4, DelaySlot.Value) && !R4300iInstruction(*_PROGRAM_COUNTER, m_Opcode.Value).DelaySlotEffectsCompare(DelaySlot.Value))
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
}
g_System->DelayedRelativeJump(((int16_t)m_Opcode.offset << 2) + 4);
}
else
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + 8;
g_System->DelayedJump(*_PROGRAM_COUNTER + 8);
}
_GPR[31].DW = (int32_t)((*_PROGRAM_COUNTER) + 8);
_GPR[31].DW = (int32_t)(g_System->m_PipelineStage == PIPELINE_STAGE_JUMP_DELAY_SLOT ? g_System->m_JumpToLocation + 4 : *_PROGRAM_COUNTER + 8);
}
void R4300iOp::REGIMM_BGEZAL()
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
if (_GPR[m_Opcode.rs].DW >= 0)
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + ((int16_t)m_Opcode.offset << 2) + 4;
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
if (CDebugSettings::HaveDebugger())
{
if (g_Reg->m_PROGRAM_COUNTER < 0x80000400)
{
// Break out of possible checksum halt
g_Notify->DisplayMessage(5, "Broke out of permanent loop! Invalid checksum?");
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + 8;
_GPR[31].DW = (int32_t)((*_PROGRAM_COUNTER) + 8);
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
return;
}
}
R4300iOpcode DelaySlot;
if (g_MMU->MemoryValue32(*_PROGRAM_COUNTER + 4, DelaySlot.Value) && !R4300iInstruction(*_PROGRAM_COUNTER, m_Opcode.Value).DelaySlotEffectsCompare(DelaySlot.Value))
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
}
g_System->DelayedRelativeJump(((int16_t)m_Opcode.offset << 2) + 4);
}
else
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + 8;
g_System->DelayedJump(*_PROGRAM_COUNTER + 8);
}
_GPR[31].DW = (int32_t)((*_PROGRAM_COUNTER) + 8);
_GPR[31].DW = (int32_t)(g_System->m_PipelineStage == PIPELINE_STAGE_JUMP_DELAY_SLOT ? g_System->m_JumpToLocation + 4 : *_PROGRAM_COUNTER + 8);
}
void R4300iOp::REGIMM_BGEZALL()
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
if (_GPR[m_Opcode.rs].DW >= 0)
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + ((int16_t)m_Opcode.offset << 2) + 4;
g_System->DelayedRelativeJump(((int16_t)m_Opcode.offset << 2) + 4);
}
else
{
g_System->m_PipelineStage = PIPELINE_STAGE_JUMP;
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + 8;
}
_GPR[31].DW = (int32_t)((*_PROGRAM_COUNTER) + 8);
_GPR[31].DW = (int32_t)(g_System->m_PipelineStage == PIPELINE_STAGE_JUMP_DELAY_SLOT ? g_System->m_JumpToLocation + 4 : *_PROGRAM_COUNTER + 8);
}
void R4300iOp::REGIMM_TEQI()

View File

@ -1,9 +1,9 @@
#include "stdafx.h"
#include "InterpreterOps32.h"
#include <Project64-core/Debugger.h>
#include <Project64-core/Logging.h>
#include <Project64-core/N64System/Interpreter/InterpreterCPU.h>
#include <Project64-core/N64System/Interpreter/InterpreterOps32.h>
#include <Project64-core/N64System/Mips/MemoryVirtualMem.h>
#include <Project64-core/N64System/Mips/R4300iInstruction.h>
#include <Project64-core/N64System/Mips/SystemTiming.h>
@ -99,7 +99,7 @@ R4300iOp32::Func * R4300iOp32::BuildInterpreter()
Jump_Special[10] = R4300iOp::UnknownOpcode;
Jump_Special[11] = R4300iOp::UnknownOpcode;
Jump_Special[12] = R4300iOp::SPECIAL_SYSCALL;
Jump_Special[13] = R4300iOp::UnknownOpcode;
Jump_Special[13] = R4300iOp::SPECIAL_BREAK;
Jump_Special[14] = R4300iOp::UnknownOpcode;
Jump_Special[15] = R4300iOp::SPECIAL_SYNC;
Jump_Special[16] = R4300iOp::SPECIAL_MFHI;
@ -615,97 +615,56 @@ R4300iOp32::Func * R4300iOp32::BuildInterpreter()
void R4300iOp32::JAL()
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
g_System->m_JumpToLocation = ((*_PROGRAM_COUNTER) & 0xF0000000) + (m_Opcode.target << 2);
_GPR[31].UW[0] = (*_PROGRAM_COUNTER) + 8;
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
g_System->DelayedJump((*_PROGRAM_COUNTER & 0xF0000000) + (m_Opcode.target << 2));
g_System->DelayedJump((*_PROGRAM_COUNTER & 0xF0000000) + (m_Opcode.target << 2));
_GPR[31].DW = (int32_t)(g_System->m_PipelineStage == PIPELINE_STAGE_JUMP_DELAY_SLOT ? g_System->m_JumpToLocation + 4 : *_PROGRAM_COUNTER + 8);
}
void R4300iOp32::BEQ()
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
if (_GPR[m_Opcode.rs].W[0] == _GPR[m_Opcode.rt].W[0])
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + ((int16_t)m_Opcode.offset << 2) + 4;
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
R4300iOpcode DelaySlot;
if (g_MMU->MemoryValue32(*_PROGRAM_COUNTER + 4, DelaySlot.Value) && !R4300iInstruction(*_PROGRAM_COUNTER, m_Opcode.Value).DelaySlotEffectsCompare(DelaySlot.Value))
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
}
g_System->DelayedRelativeJump(((int16_t)m_Opcode.offset << 2) + 4);
}
else
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + 8;
g_System->DelayedJump(*_PROGRAM_COUNTER + 8);
}
}
void R4300iOp32::BNE()
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
if (_GPR[m_Opcode.rs].W[0] != _GPR[m_Opcode.rt].W[0])
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + ((int16_t)m_Opcode.offset << 2) + 4;
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
R4300iOpcode DelaySlot;
if (g_MMU->MemoryValue32(*_PROGRAM_COUNTER + 4, DelaySlot.Value) && !R4300iInstruction(*_PROGRAM_COUNTER, m_Opcode.Value).DelaySlotEffectsCompare(DelaySlot.Value))
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
}
g_System->DelayedRelativeJump(((int16_t)m_Opcode.offset << 2) + 4);
}
else
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + 8;
g_System->DelayedJump(*_PROGRAM_COUNTER + 8);
}
}
void R4300iOp32::BLEZ()
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
if (_GPR[m_Opcode.rs].W[0] <= 0)
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + ((int16_t)m_Opcode.offset << 2) + 4;
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
R4300iOpcode DelaySlot;
if (g_MMU->MemoryValue32(*_PROGRAM_COUNTER + 4, DelaySlot.Value) && !R4300iInstruction(*_PROGRAM_COUNTER, m_Opcode.Value).DelaySlotEffectsCompare(DelaySlot.Value))
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
}
g_System->DelayedRelativeJump(((int16_t)m_Opcode.offset << 2) + 4);
}
else
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + 8;
g_System->DelayedJump(*_PROGRAM_COUNTER + 8);
}
}
void R4300iOp32::BGTZ()
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
if (_GPR[m_Opcode.rs].W[0] > 0)
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + ((int16_t)m_Opcode.offset << 2) + 4;
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
R4300iOpcode DelaySlot;
if (g_MMU->MemoryValue32(*_PROGRAM_COUNTER + 4, DelaySlot.Value) && !R4300iInstruction(*_PROGRAM_COUNTER, m_Opcode.Value).DelaySlotEffectsCompare(DelaySlot.Value))
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
}
g_System->DelayedRelativeJump(((int16_t)m_Opcode.offset << 2) + 4);
}
else
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + 8;
g_System->DelayedJump(*_PROGRAM_COUNTER + 8);
}
}
@ -802,16 +761,7 @@ void R4300iOp32::BEQL()
{
if (_GPR[m_Opcode.rs].W[0] == _GPR[m_Opcode.rt].W[0])
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + ((int16_t)m_Opcode.offset << 2) + 4;
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
R4300iOpcode DelaySlot;
if (g_MMU->MemoryValue32(*_PROGRAM_COUNTER + 4, DelaySlot.Value) && !R4300iInstruction(*_PROGRAM_COUNTER, m_Opcode.Value).DelaySlotEffectsCompare(DelaySlot.Value))
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
}
g_System->DelayedRelativeJump(((int16_t)m_Opcode.offset << 2) + 4);
}
else
{
@ -824,16 +774,7 @@ void R4300iOp32::BNEL()
{
if (_GPR[m_Opcode.rs].W[0] != _GPR[m_Opcode.rt].W[0])
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + ((int16_t)m_Opcode.offset << 2) + 4;
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
R4300iOpcode DelaySlot;
if (g_MMU->MemoryValue32(*_PROGRAM_COUNTER + 4, DelaySlot.Value) && !R4300iInstruction(*_PROGRAM_COUNTER, m_Opcode.Value).DelaySlotEffectsCompare(DelaySlot.Value))
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
}
g_System->DelayedRelativeJump(((int16_t)m_Opcode.offset << 2) + 4);
}
else
{
@ -846,16 +787,7 @@ void R4300iOp32::BLEZL()
{
if (_GPR[m_Opcode.rs].W[0] <= 0)
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + ((int16_t)m_Opcode.offset << 2) + 4;
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
R4300iOpcode DelaySlot;
if (g_MMU->MemoryValue32(*_PROGRAM_COUNTER + 4, DelaySlot.Value) && !R4300iInstruction(*_PROGRAM_COUNTER, m_Opcode.Value).DelaySlotEffectsCompare(DelaySlot.Value))
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
}
g_System->DelayedRelativeJump(((int16_t)m_Opcode.offset << 2) + 4);
}
else
{
@ -868,16 +800,7 @@ void R4300iOp32::BGTZL()
{
if (_GPR[m_Opcode.rs].W[0] > 0)
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + ((int16_t)m_Opcode.offset << 2) + 4;
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
R4300iOpcode DelaySlot;
if (g_MMU->MemoryValue32(*_PROGRAM_COUNTER + 4, DelaySlot.Value) && !R4300iInstruction(*_PROGRAM_COUNTER, m_Opcode.Value).DelaySlotEffectsCompare(DelaySlot.Value))
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
}
g_System->DelayedRelativeJump(((int16_t)m_Opcode.offset << 2) + 4);
}
else
{
@ -1003,9 +926,8 @@ void R4300iOp32::SPECIAL_SRAV()
void R4300iOp32::SPECIAL_JALR()
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
g_System->m_JumpToLocation = _GPR[m_Opcode.rs].UW[0];
_GPR[m_Opcode.rd].W[0] = (int32_t)((*_PROGRAM_COUNTER) + 8);
g_System->DelayedJump(_GPR[m_Opcode.rs].UW[0]);
_GPR[m_Opcode.rd].W[0] = g_System->m_PipelineStage == PIPELINE_STAGE_JUMP_DELAY_SLOT ? g_System->m_JumpToLocation + 4 : *_PROGRAM_COUNTER + 8;
m_TestTimer = true;
}
@ -1103,43 +1025,25 @@ void R4300iOp32::SPECIAL_TEQ()
void R4300iOp32::REGIMM_BLTZ()
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
if (_GPR[m_Opcode.rs].W[0] < 0)
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + ((int16_t)m_Opcode.offset << 2) + 4;
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
R4300iOpcode DelaySlot;
if (g_MMU->MemoryValue32(*_PROGRAM_COUNTER + 4, DelaySlot.Value) && !R4300iInstruction(*_PROGRAM_COUNTER, m_Opcode.Value).DelaySlotEffectsCompare(DelaySlot.Value))
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
}
g_System->DelayedRelativeJump(((int16_t)m_Opcode.offset << 2) + 4);
}
else
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + 8;
g_System->DelayedJump(*_PROGRAM_COUNTER + 8);
}
}
void R4300iOp32::REGIMM_BGEZ()
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
if (_GPR[m_Opcode.rs].W[0] >= 0)
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + ((int16_t)m_Opcode.offset << 2) + 4;
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
R4300iOpcode DelaySlot;
if (g_MMU->MemoryValue32(*_PROGRAM_COUNTER + 4, DelaySlot.Value) && !R4300iInstruction(*_PROGRAM_COUNTER, m_Opcode.Value).DelaySlotEffectsCompare(DelaySlot.Value))
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
}
g_System->DelayedRelativeJump(((int16_t)m_Opcode.offset << 2) + 4);
}
else
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + 8;
g_System->DelayedJump(*_PROGRAM_COUNTER + 8);
}
}
@ -1147,16 +1051,7 @@ void R4300iOp32::REGIMM_BLTZL()
{
if (_GPR[m_Opcode.rs].W[0] < 0)
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + ((int16_t)m_Opcode.offset << 2) + 4;
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
R4300iOpcode DelaySlot;
if (g_MMU->MemoryValue32(*_PROGRAM_COUNTER + 4, DelaySlot.Value) && !R4300iInstruction(*_PROGRAM_COUNTER, m_Opcode.Value).DelaySlotEffectsCompare(DelaySlot.Value))
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
}
g_System->DelayedRelativeJump(((int16_t)m_Opcode.offset << 2) + 4);
}
else
{
@ -1169,16 +1064,7 @@ void R4300iOp32::REGIMM_BGEZL()
{
if (_GPR[m_Opcode.rs].W[0] >= 0)
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + ((int16_t)m_Opcode.offset << 2) + 4;
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
R4300iOpcode DelaySlot;
if (g_MMU->MemoryValue32(*_PROGRAM_COUNTER + 4, DelaySlot.Value) && !R4300iInstruction(*_PROGRAM_COUNTER, m_Opcode.Value).DelaySlotEffectsCompare(DelaySlot.Value))
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
}
g_System->DelayedRelativeJump(((int16_t)m_Opcode.offset << 2) + 4);
}
else
{
@ -1189,52 +1075,22 @@ void R4300iOp32::REGIMM_BGEZL()
void R4300iOp32::REGIMM_BLTZAL()
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
if (_GPR[m_Opcode.rs].W[0] < 0)
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + ((int16_t)m_Opcode.offset << 2) + 4;
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
R4300iOpcode DelaySlot;
if (g_MMU->MemoryValue32(*_PROGRAM_COUNTER + 4, DelaySlot.Value) && !R4300iInstruction(*_PROGRAM_COUNTER, m_Opcode.Value).DelaySlotEffectsCompare(DelaySlot.Value))
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
}
g_System->DelayedRelativeJump(((int16_t)m_Opcode.offset << 2) + 4);
}
else
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + 8;
g_System->DelayedJump(*_PROGRAM_COUNTER + 8);
}
_GPR[31].W[0] = (int32_t)((*_PROGRAM_COUNTER) + 8);
_GPR[31].W[0] = g_System->m_PipelineStage == PIPELINE_STAGE_JUMP_DELAY_SLOT ? g_System->m_JumpToLocation + 4 : *_PROGRAM_COUNTER + 8;
}
void R4300iOp32::REGIMM_BGEZAL()
{
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
if (_GPR[m_Opcode.rs].W[0] >= 0)
{
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + ((int16_t)m_Opcode.offset << 2) + 4;
if ((*_PROGRAM_COUNTER) == g_System->m_JumpToLocation)
{
if (CDebugSettings::HaveDebugger())
{
if (g_Reg->m_PROGRAM_COUNTER < 0x80000400)
{
// Break out of possible checksum halt
g_Notify->DisplayMessage(5, "Broke out of permanent loop! Invalid checksum?");
g_System->m_JumpToLocation = (*_PROGRAM_COUNTER) + 8;
_GPR[31].DW = (int32_t)((*_PROGRAM_COUNTER) + 8);
g_System->m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
return;
}
}
R4300iOpcode DelaySlot;
if (g_MMU->MemoryValue32(*_PROGRAM_COUNTER + 4, DelaySlot.Value) && !R4300iInstruction(*_PROGRAM_COUNTER, m_Opcode.Value).DelaySlotEffectsCompare(DelaySlot.Value))
{
g_System->m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
}
g_System->DelayedRelativeJump(((int16_t)m_Opcode.offset << 2) + 4);
}
else
{

View File

@ -43,6 +43,7 @@ CN64System::CN64System(CPlugins * Plugins, uint32_t randomizer_seed, bool SavesR
m_TestTimer(false),
m_PipelineStage(PIPELINE_STAGE_NORMAL),
m_JumpToLocation(0),
m_JumpDelayLocation(0),
m_TLBLoadAddress(0),
m_TLBStoreAddress(0),
m_SyncCount(0),
@ -2420,6 +2421,46 @@ void CN64System::NotifyCallback(CN64SystemCB Type)
}
}
void CN64System::DelayedJump(uint32_t JumpLocation)
{
if (m_PipelineStage == PIPELINE_STAGE_JUMP)
{
m_PipelineStage = PIPELINE_STAGE_JUMP_DELAY_SLOT;
m_JumpDelayLocation = JumpLocation;
}
else
{
m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
m_JumpToLocation = JumpLocation;
}
if ((m_Reg.m_PROGRAM_COUNTER) == m_JumpToLocation)
{
m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
}
void CN64System::DelayedRelativeJump(uint32_t RelativeLocation)
{
if (m_PipelineStage == PIPELINE_STAGE_JUMP)
{
m_PipelineStage = PIPELINE_STAGE_JUMP_DELAY_SLOT;
m_JumpDelayLocation = m_Reg.m_PROGRAM_COUNTER + RelativeLocation + 4;
}
else
{
m_PipelineStage = PIPELINE_STAGE_DELAY_SLOT;
m_JumpToLocation = m_Reg.m_PROGRAM_COUNTER + RelativeLocation;
}
if (m_Reg.m_PROGRAM_COUNTER == m_JumpToLocation)
{
R4300iOpcode DelaySlot;
if (m_MMU_VM.MemoryValue32(m_Reg.m_PROGRAM_COUNTER + 4, DelaySlot.Value) && !R4300iInstruction(m_Reg.m_PROGRAM_COUNTER, R4300iOp::m_Opcode.Value).DelaySlotEffectsCompare(DelaySlot.Value))
{
m_PipelineStage = PIPELINE_STAGE_PERMLOOP_DO_DELAY;
}
}
}
void CN64System::RunRSP()
{
WriteTrace(TraceRSP, TraceDebug, "Start (SP Status %X)", m_Reg.SP_STATUS_REG);

View File

@ -163,6 +163,8 @@ private:
void InitRegisters(bool bPostPif, CMipsMemoryVM & MMU);
void DisplayRSPListCount();
void NotifyCallback(CN64SystemCB Type);
void DelayedJump(uint32_t JumpLocation);
void DelayedRelativeJump(uint32_t RelativeLocation);
// CPU methods
void ExecuteRecompiler();
@ -198,6 +200,7 @@ private:
bool m_TestTimer;
PIPELINE_STAGE m_PipelineStage;
uint32_t m_JumpToLocation;
uint32_t m_JumpDelayLocation;
uint32_t m_TLBLoadAddress;
uint32_t m_TLBStoreAddress;
uint32_t m_SyncCount;

View File

@ -146,6 +146,7 @@ enum PIPELINE_STAGE
PIPELINE_STAGE_END_DELAY_SLOT,
PIPELINE_STAGE_LIKELY_DELAY_SLOT,
PIPELINE_STAGE_JUMP,
PIPELINE_STAGE_JUMP_DELAY_SLOT,
PIPELINE_STAGE_DELAY_SLOT_DONE,
PIPELINE_STAGE_LIKELY_DELAY_SLOT_DONE,
PIPELINE_STAGE_END_BLOCK,