VU Interpreter Branch Delays: Rethink of this. As it's completely undocumented and nobody seems to know exactly what goes on, i have made my own guess...

If the first branch is a branch instruction, then ignore the second.
If the first branch is a jump instruction, execute 1 instruction from the first jump, then execute the second branch. (This is the only confirmed thing i can find from people testing this)

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@5539 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
refraction@gmail.com 2013-01-28 23:05:18 +00:00
parent 26cac4d837
commit 73a08536d1
4 changed files with 43 additions and 33 deletions

View File

@ -140,7 +140,7 @@ struct __aligned16 VURegs {
u32 branch;
u32 branchpc;
u32 delaybranchpc;
u32 linkreg;
u32 firstbranchisjump;
bool takedelaybranch;
// MAC/Status flags -- these are used by interpreters and superVU, but are kind of hacky

View File

@ -145,24 +145,28 @@ static void _vu0Exec(VURegs* VU)
_vuTestPipes(VU);
if (VU->branch > 0) {
VU->branch--;
if (VU->branch == 0) {
if (VU->branch-- == 1) {
VU->VI[REG_TPC].UL = VU->branchpc;
if(VU->takedelaybranch == true && VU->linkreg == 0)
if(VU->takedelaybranch == true)
{
//DevCon.Warning("Setting VU0 Delay branch to next branch, treating first as delay slot");
//DevCon.Warning("VU0 - Branch/Jump in Delay Slot");
if(VU->firstbranchisjump == 1)
{
//DevCon.Warning("Jump first, so reading 1 instruction from first branch, then jumping second");
VU->branch = 2;
VU->branchpc = VU->delaybranchpc;
VU->branch = 1;
VU->branchpc = VU->delaybranchpc;
}
else
{
//DevCon.Warning("Branch first, so ignoring second branch");
}
VU->delaybranchpc = 0;
VU->takedelaybranch = false;
}
else
{
VU->takedelaybranch = false;
VU->linkreg = 0;
}
VU->firstbranchisjump = 0;
}
}

View File

@ -24,7 +24,7 @@ extern void _vuFlushAll(VURegs* VU);
void _vu1ExecUpper(VURegs* VU, u32 *ptr) {
VU->code = ptr[1];
IdebugUPPER(VU1);
//IdebugUPPER(VU1);
VU1_UPPER_OPCODE[VU->code & 0x3f]();
}
@ -68,7 +68,7 @@ static void _vu1Exec(VURegs* VU)
}
}
VUM_LOG("VU->cycle = %d (flags st=%x;mac=%x;clip=%x,q=%f)", VU->cycle, VU->statusflag, VU->macflag, VU->clipflag, VU->q.F);
//VUM_LOG("VU->cycle = %d (flags st=%x;mac=%x;clip=%x,q=%f)", VU->cycle, VU->statusflag, VU->macflag, VU->clipflag, VU->q.F);
VU->code = ptr[1];
VU1regs_UPPER_OPCODE[VU->code & 0x3f](&uregs);
@ -144,21 +144,26 @@ static void _vu1Exec(VURegs* VU)
if (VU->branch > 0) {
if (VU->branch-- == 1) {
VU->VI[REG_TPC].UL = VU->branchpc;
if(VU->takedelaybranch == true && VU->linkreg == 0)
if(VU->takedelaybranch == true)
{
//DevCon.Warning("Setting VU1 Delay branch to next branch, treating first as delay slot");
//DevCon.Warning("VU1 - Branch/Jump in Delay Slot");
if(VU->firstbranchisjump == 1)
{
//DevCon.Warning("Jump first, so reading 1 instruction from first branch, then jumping second");
VU->branch = 2;
VU->branchpc = VU->delaybranchpc;
VU->branch = 1;
VU->branchpc = VU->delaybranchpc;
}
else
{
//DevCon.Warning("Branch first, so ignoring second branch");
}
VU->delaybranchpc = 0;
VU->takedelaybranch = false;
}
else
{
VU->takedelaybranch = false;
VU->linkreg = 0;
}
VU->firstbranchisjump = 0;
}
}

View File

@ -1872,19 +1872,20 @@ s32 _branchAddr(VURegs * VU) {
return bpc;
}
static __fi void _setBranch(VURegs * VU, u32 bpc, bool islink) {
static __fi void _setBranch(VURegs * VU, u32 bpc, bool isjump) {
if(VU->branch == 1)
{
if(islink)
{
VU->linkreg = _It_;
}
{
//DevCon.Warning("Branch in Branch Delay slot!");
VU->delaybranchpc = bpc;
VU->takedelaybranch = true;
}
else
{
if(isjump)
{
VU->firstbranchisjump = 1;
}
VU->branch = 2;
VU->branchpc = bpc;
}
@ -1943,12 +1944,12 @@ static __ri void _vuBAL(VURegs * VU) {
if (_It_) VU->VI[_It_].US[0] = (VU->VI[REG_TPC].UL + 8)/8;
_setBranch(VU, bpc, true);
_setBranch(VU, bpc, false);
}
static __ri void _vuJR(VURegs * VU) {
u32 bpc = VU->VI[_Is_].US[0] * 8;
_setBranch(VU, bpc, false);
_setBranch(VU, bpc, true);
}
//If this is in a branch delay, the jump isn't taken ( Evil Dead - Fistfull of Boomstick )