2009-09-07 19:23:46 +00:00
|
|
|
#include "VuBasicBlock.h"
|
|
|
|
#include "MA_VU.h"
|
|
|
|
#include "offsetof_def.h"
|
|
|
|
|
2013-10-27 04:54:28 +00:00
|
|
|
CVuBasicBlock::CVuBasicBlock(CMIPS& context, uint32 begin, uint32 end)
|
|
|
|
: CBasicBlock(context, begin, end)
|
2009-09-07 19:23:46 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
CVuBasicBlock::~CVuBasicBlock()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-09-03 21:13:57 +00:00
|
|
|
void CVuBasicBlock::CompileRange(CMipsJitter* jitter)
|
2009-09-07 19:23:46 +00:00
|
|
|
{
|
|
|
|
assert((m_begin & 0x07) == 0);
|
|
|
|
assert(((m_end + 4) & 0x07) == 0);
|
2016-08-06 22:42:47 -04:00
|
|
|
auto arch = static_cast<CMA_VU*>(m_context.m_pArch);
|
2013-10-27 04:54:28 +00:00
|
|
|
|
|
|
|
uint32 fixedEnd = m_end;
|
|
|
|
bool needsPcAdjust = false;
|
|
|
|
|
|
|
|
//Make sure the delay slot instruction is present in the block.
|
|
|
|
//CVuExecutor can sometimes cut the blocks in a way that removes the delay slot instruction for branches.
|
|
|
|
{
|
|
|
|
uint32 addressLo = fixedEnd - 4;
|
|
|
|
uint32 addressHi = fixedEnd - 0;
|
|
|
|
|
|
|
|
uint32 opcodeLo = m_context.m_pMemoryMap->GetInstruction(addressLo);
|
|
|
|
uint32 opcodeHi = m_context.m_pMemoryMap->GetInstruction(addressHi);
|
|
|
|
|
2015-05-06 00:54:15 -04:00
|
|
|
//Check for LOI
|
|
|
|
if((opcodeHi & 0x80000000) == 0)
|
|
|
|
{
|
|
|
|
auto branchType = arch->IsInstructionBranch(&m_context, addressLo, opcodeLo);
|
|
|
|
if(branchType == MIPS_BRANCH_NORMAL)
|
|
|
|
{
|
|
|
|
fixedEnd += 8;
|
|
|
|
needsPcAdjust = true;
|
|
|
|
}
|
|
|
|
}
|
2013-10-27 04:54:28 +00:00
|
|
|
}
|
|
|
|
|
2016-06-03 23:35:59 +01:00
|
|
|
int delayedReg = 0;
|
|
|
|
int delayedRegTime = -1;
|
|
|
|
int delayedRegTargetTime = -1;
|
|
|
|
int adjustedEnd = fixedEnd - 4;
|
|
|
|
{
|
|
|
|
// Test if the block ends with a conditional branch instruction where the condition variable has been
|
|
|
|
// set in the prior instruction.
|
|
|
|
// In this case, the pipeline shortcut fails and we need to use the value from 4 instructions previous.
|
2016-06-21 22:31:05 +01:00
|
|
|
// If the relevant set instruction is not part of this block, skip the fix and fall back to the broken implementation.
|
2016-06-03 23:35:59 +01:00
|
|
|
int length = (fixedEnd - m_begin) >> 3;
|
2016-06-21 22:31:05 +01:00
|
|
|
if (length > 4)
|
2016-06-03 23:35:59 +01:00
|
|
|
{
|
2016-06-06 22:58:03 +01:00
|
|
|
// Check if we have a conditional branch instruction. Luckily these populate the contiguous opcode range 0x28 -> 0x2F inclusive
|
2016-06-03 23:35:59 +01:00
|
|
|
uint32 opcodeLo = m_context.m_pMemoryMap->GetInstruction(adjustedEnd - 8);
|
|
|
|
uint32 id = (opcodeLo >> 25) & 0x7f;
|
|
|
|
if (id >= 0x28 && id < 0x30)
|
|
|
|
{
|
|
|
|
// We have a conditional branch instruction. Now we need to check that the condition register is not written
|
|
|
|
// by the previous instruction.
|
2016-06-06 22:58:03 +01:00
|
|
|
int priorOpcodeAddr = adjustedEnd - 16;
|
|
|
|
uint32 priorOpcodeLo = m_context.m_pMemoryMap->GetInstruction(priorOpcodeAddr);
|
2016-06-03 23:35:59 +01:00
|
|
|
|
2016-06-06 22:58:03 +01:00
|
|
|
VUShared::OPERANDSET loOps = arch->GetAffectedOperands(&m_context, priorOpcodeAddr, priorOpcodeLo);
|
2016-08-06 00:55:23 -04:00
|
|
|
if ((loOps.writeI != 0) && !loOps.branchValue)
|
2016-06-10 17:04:41 +01:00
|
|
|
{
|
2016-06-03 23:35:59 +01:00
|
|
|
uint8 is = static_cast<uint8> ((opcodeLo >> 11) & 0x001F);
|
|
|
|
uint8 it = static_cast<uint8> ((opcodeLo >> 16) & 0x001F);
|
2016-06-10 17:04:41 +01:00
|
|
|
if (is == loOps.writeI || it == loOps.writeI)
|
|
|
|
{
|
2016-06-06 22:58:03 +01:00
|
|
|
// argh - we need to use the value of incReg 4 steps prior.
|
|
|
|
delayedReg = loOps.writeI;
|
2016-06-21 22:31:05 +01:00
|
|
|
delayedRegTime = adjustedEnd - 5 * 8;
|
2016-06-06 22:58:03 +01:00
|
|
|
delayedRegTargetTime = adjustedEnd - 8;
|
2016-06-03 23:35:59 +01:00
|
|
|
}
|
2016-06-06 22:58:03 +01:00
|
|
|
}
|
2016-06-03 23:35:59 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-27 04:54:28 +00:00
|
|
|
for(uint32 address = m_begin; address <= fixedEnd; address += 8)
|
2009-06-06 15:38:03 +00:00
|
|
|
{
|
2012-03-18 01:52:44 +00:00
|
|
|
uint32 relativePipeTime = (address - m_begin) / 8;
|
|
|
|
|
2009-06-06 15:38:03 +00:00
|
|
|
uint32 addressLo = address + 0;
|
|
|
|
uint32 addressHi = address + 4;
|
|
|
|
|
|
|
|
uint32 opcodeLo = m_context.m_pMemoryMap->GetInstruction(addressLo);
|
|
|
|
uint32 opcodeHi = m_context.m_pMemoryMap->GetInstruction(addressHi);
|
|
|
|
|
|
|
|
VUShared::OPERANDSET loOps = arch->GetAffectedOperands(&m_context, addressLo, opcodeLo);
|
|
|
|
VUShared::OPERANDSET hiOps = arch->GetAffectedOperands(&m_context, addressHi, opcodeHi);
|
|
|
|
|
2011-04-03 05:25:07 +00:00
|
|
|
//No upper instruction writes to Q
|
|
|
|
assert(hiOps.syncQ == false);
|
2012-03-18 01:52:44 +00:00
|
|
|
|
|
|
|
//No lower instruction reads Q
|
|
|
|
assert(loOps.readQ == false);
|
2011-04-03 05:25:07 +00:00
|
|
|
|
2013-10-27 04:54:28 +00:00
|
|
|
if(loOps.syncQ)
|
2009-06-06 15:38:03 +00:00
|
|
|
{
|
2013-10-27 04:54:28 +00:00
|
|
|
VUShared::FlushPipeline(VUShared::g_pipeInfoQ, jitter);
|
2009-06-06 15:38:03 +00:00
|
|
|
}
|
2012-03-18 01:52:44 +00:00
|
|
|
|
2013-10-27 04:54:28 +00:00
|
|
|
if(hiOps.readQ)
|
|
|
|
{
|
|
|
|
VUShared::CheckPipeline(VUShared::g_pipeInfoQ, jitter, relativePipeTime);
|
|
|
|
}
|
2011-04-03 05:25:07 +00:00
|
|
|
|
2013-10-27 04:54:28 +00:00
|
|
|
uint8 savedReg = 0;
|
2009-06-06 15:38:03 +00:00
|
|
|
|
2013-10-27 04:54:28 +00:00
|
|
|
if(hiOps.writeF != 0)
|
|
|
|
{
|
|
|
|
assert(hiOps.writeF != loOps.writeF);
|
|
|
|
if(
|
|
|
|
(hiOps.writeF == loOps.readF0) ||
|
|
|
|
(hiOps.writeF == loOps.readF1)
|
|
|
|
)
|
2009-06-06 15:38:03 +00:00
|
|
|
{
|
2013-10-27 04:54:28 +00:00
|
|
|
savedReg = hiOps.writeF;
|
|
|
|
jitter->MD_PushRel(offsetof(CMIPS, m_State.nCOP2[savedReg]));
|
|
|
|
jitter->MD_PullRel(offsetof(CMIPS, m_State.nCOP2VF_PreUp));
|
2009-06-06 15:38:03 +00:00
|
|
|
}
|
2013-10-27 04:54:28 +00:00
|
|
|
}
|
2009-06-06 15:38:03 +00:00
|
|
|
|
2016-06-03 23:35:59 +01:00
|
|
|
if (address == delayedRegTime) {
|
|
|
|
// grab the value of the delayed reg to use in the conditional branch later
|
|
|
|
jitter->PushRel(offsetof(CMIPS, m_State.nCOP2VI[delayedReg]));
|
|
|
|
jitter->PullRel(offsetof(CMIPS, m_State.savedIntReg));
|
|
|
|
}
|
|
|
|
|
2013-10-27 04:54:28 +00:00
|
|
|
arch->SetRelativePipeTime(relativePipeTime);
|
|
|
|
arch->CompileInstruction(addressHi, jitter, &m_context);
|
2009-06-06 15:38:03 +00:00
|
|
|
|
2013-10-27 04:54:28 +00:00
|
|
|
if(savedReg != 0)
|
|
|
|
{
|
|
|
|
jitter->MD_PushRel(offsetof(CMIPS, m_State.nCOP2[savedReg]));
|
|
|
|
jitter->MD_PullRel(offsetof(CMIPS, m_State.nCOP2VF_UpRes));
|
2009-06-06 15:38:03 +00:00
|
|
|
|
2013-10-27 04:54:28 +00:00
|
|
|
jitter->MD_PushRel(offsetof(CMIPS, m_State.nCOP2VF_PreUp));
|
|
|
|
jitter->MD_PullRel(offsetof(CMIPS, m_State.nCOP2[savedReg]));
|
|
|
|
}
|
2009-06-06 15:38:03 +00:00
|
|
|
|
2016-06-03 23:35:59 +01:00
|
|
|
if (address == delayedRegTargetTime) {
|
|
|
|
// set the target from the saved value
|
|
|
|
jitter->PushRel(offsetof(CMIPS, m_State.nCOP2VI[delayedReg]));
|
|
|
|
jitter->PullRel(offsetof(CMIPS, m_State.savedIntRegTemp));
|
|
|
|
|
|
|
|
jitter->PushRel(offsetof(CMIPS, m_State.savedIntReg));
|
|
|
|
jitter->PullRel(offsetof(CMIPS, m_State.nCOP2VI[delayedReg]));
|
|
|
|
}
|
|
|
|
|
2013-10-27 04:54:28 +00:00
|
|
|
arch->CompileInstruction(addressLo, jitter, &m_context);
|
2009-06-06 15:38:03 +00:00
|
|
|
|
2016-06-03 23:35:59 +01:00
|
|
|
if (address == delayedRegTargetTime) {
|
|
|
|
// put the target value back
|
|
|
|
jitter->PushRel(offsetof(CMIPS, m_State.savedIntRegTemp));
|
|
|
|
jitter->PullRel(offsetof(CMIPS, m_State.nCOP2VI[delayedReg]));
|
|
|
|
}
|
|
|
|
|
2013-10-27 04:54:28 +00:00
|
|
|
if(savedReg != 0)
|
|
|
|
{
|
|
|
|
jitter->MD_PushRel(offsetof(CMIPS, m_State.nCOP2VF_UpRes));
|
|
|
|
jitter->MD_PullRel(offsetof(CMIPS, m_State.nCOP2[savedReg]));
|
2009-06-06 15:38:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//Sanity check
|
2010-09-03 21:13:57 +00:00
|
|
|
assert(jitter->IsStackEmpty());
|
2009-09-07 19:23:46 +00:00
|
|
|
}
|
2012-03-18 01:52:44 +00:00
|
|
|
|
|
|
|
//Increment pipeTime
|
|
|
|
{
|
2013-10-27 04:54:28 +00:00
|
|
|
uint32 timeInc = ((fixedEnd - m_begin) / 8) + 1;
|
2012-03-18 01:52:44 +00:00
|
|
|
jitter->PushRel(offsetof(CMIPS, m_State.pipeTime));
|
|
|
|
jitter->PushCst(timeInc);
|
|
|
|
jitter->Add();
|
|
|
|
jitter->PullRel(offsetof(CMIPS, m_State.pipeTime));
|
|
|
|
}
|
2013-10-27 04:54:28 +00:00
|
|
|
|
|
|
|
//Adjust PC to make sure we don't execute the delay slot at the next block
|
|
|
|
if(needsPcAdjust)
|
|
|
|
{
|
|
|
|
jitter->PushCst(MIPS_INVALID_PC);
|
|
|
|
jitter->PushRel(offsetof(CMIPS, m_State.nDelayedJumpAddr));
|
|
|
|
|
|
|
|
jitter->BeginIf(Jitter::CONDITION_EQ);
|
|
|
|
{
|
2015-05-06 00:54:15 -04:00
|
|
|
jitter->PushCst(fixedEnd + 0x4);
|
2013-10-27 04:54:28 +00:00
|
|
|
jitter->PullRel(offsetof(CMIPS, m_State.nDelayedJumpAddr));
|
|
|
|
}
|
|
|
|
jitter->EndIf();
|
|
|
|
}
|
2009-09-07 19:23:46 +00:00
|
|
|
}
|