mirror of https://github.com/PCSX2/pcsx2.git
microVU: 70% implemented Branch in Branch Delay Slots. Hopefully I'll finish tomorrow.
Compare Star Ocean 3 intro with mVU vs sVU, and you can see mVU now correctly renders the title menu/new game startup screen =) git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1652 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
614cc7e55d
commit
0587cdc210
|
@ -159,6 +159,7 @@ struct microVU {
|
|||
u32 VIbackup; // Holds a backup of a VI reg if modified before a branch
|
||||
u32 VIxgkick; // Holds a backup of a VI reg used for xgkick-delays
|
||||
u32 branch; // Holds branch compare result (IBxx) OR Holds address to Jump to (JALR/JR)
|
||||
u32 evilBranch; // For Branches in Branch Delay Slots, holds Address to Jump to
|
||||
u32 p; // Holds current P instance index
|
||||
u32 q; // Holds current Q instance index
|
||||
u32 totalCycles; // Total Cycles that mVU is expected to run for
|
||||
|
|
|
@ -389,30 +389,31 @@ microVUt(void) analyzeBranchVI(mV, int xReg, bool &infoVar) {
|
|||
}
|
||||
|
||||
// Branch in Branch Delay-Slots
|
||||
microVUt(void) mVUbranchCheck(mV) {
|
||||
if (!mVUcount) return;
|
||||
microVUt(int) mVUbranchCheck(mV) {
|
||||
if (!mVUcount) return 0;
|
||||
incPC(-2);
|
||||
if (mVUlow.branch) {
|
||||
incPC(2);
|
||||
Console::Error("microVU%d Warning: Branch in Branch delay slot! [%04x]", params mVU->index, xPC);
|
||||
mVUlow.isNOP = 1;
|
||||
mVUlow.evilBranch = 1;
|
||||
mVUregs.blockType = 2;
|
||||
DevCon::Status("microVU%d Warning: Branch in Branch delay slot! [%04x]", params mVU->index, xPC);
|
||||
return 1;
|
||||
}
|
||||
else incPC(2);
|
||||
incPC(2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
microVUt(void) mVUanalyzeCondBranch1(mV, int Is) {
|
||||
mVUbranchCheck(mVU);
|
||||
analyzeVIreg1(Is, mVUlow.VI_read[0]);
|
||||
if (!mVUstall) {
|
||||
if (!mVUstall && !mVUbranchCheck(mVU)) {
|
||||
analyzeBranchVI(mVU, Is, mVUlow.memReadIs);
|
||||
}
|
||||
}
|
||||
|
||||
microVUt(void) mVUanalyzeCondBranch2(mV, int Is, int It) {
|
||||
mVUbranchCheck(mVU);
|
||||
analyzeVIreg1(Is, mVUlow.VI_read[0]);
|
||||
analyzeVIreg1(It, mVUlow.VI_read[1]);
|
||||
if (!mVUstall) {
|
||||
if (!mVUstall && !mVUbranchCheck(mVU)) {
|
||||
analyzeBranchVI(mVU, Is, mVUlow.memReadIs);
|
||||
analyzeBranchVI(mVU, It, mVUlow.memReadIt);
|
||||
}
|
||||
|
|
|
@ -96,10 +96,25 @@ void normBranchCompile(microVU* mVU, u32 branchPC) {
|
|||
else { mVUcompile(mVU, branchPC, (uptr)&mVUregs); }
|
||||
}
|
||||
|
||||
void normJumpCompile(mV, microFlagCycles& mFC, bool isEvilJump) {
|
||||
using namespace x86Emitter;
|
||||
memcpy_fast(&mVUpBlock->pStateEnd, &mVUregs, sizeof(microRegInfo));
|
||||
mVUsetupBranch(mVU, mFC);
|
||||
mVUbackupRegs(mVU);
|
||||
|
||||
if (isEvilJump) MOV32MtoR(gprT2, (uptr)&mVU->evilBranch);
|
||||
else MOV32MtoR(gprT2, (uptr)&mVU->branch);
|
||||
MOV32ItoR(gprR, (u32)&mVUpBlock->pStateEnd);
|
||||
|
||||
if (!mVU->index) xCALL(mVUcompileJIT<0>); //(u32 startPC, uptr pState)
|
||||
else xCALL(mVUcompileJIT<1>);
|
||||
|
||||
mVUrestoreRegs(mVU);
|
||||
JMPR(gprT1); // Jump to rec-code address
|
||||
}
|
||||
|
||||
void normBranch(mV, microFlagCycles& mFC) {
|
||||
|
||||
incPC(-3); // Go back to branch opcode (to get branch imm addr)
|
||||
|
||||
// E-bit Branch
|
||||
if (mVUup.eBit) { iPC = branchAddr/4; mVUendProgram(mVU, &mFC, 1); return; }
|
||||
|
||||
|
@ -112,6 +127,7 @@ void condBranch(mV, microFlagCycles& mFC, int JMPcc) {
|
|||
using namespace x86Emitter;
|
||||
mVUsetupBranch(mVU, mFC);
|
||||
xCMP(ptr16[&mVU->branch], 0);
|
||||
incPC(3);
|
||||
if (mVUup.eBit) { // Conditional Branch With E-Bit Set
|
||||
mVUendProgram(mVU, &mFC, 2);
|
||||
xForwardJump8 eJMP((JccComparisonType)JMPcc);
|
||||
|
@ -155,8 +171,6 @@ void condBranch(mV, microFlagCycles& mFC, int JMPcc) {
|
|||
|
||||
void normJump(mV, microFlagCycles& mFC) {
|
||||
using namespace x86Emitter;
|
||||
mVUprint("mVUcompile JR/JALR");
|
||||
incPC(-3); // Go back to jump opcode
|
||||
|
||||
if (mVUlow.constJump.isValid) { // Jump Address is Constant
|
||||
if (mVUup.eBit) { // E-bit Jump
|
||||
|
@ -175,18 +189,6 @@ void normJump(mV, microFlagCycles& mFC) {
|
|||
MOV32MtoR(gprT1, (uptr)&mVU->branch);
|
||||
MOV32RtoM((uptr)&mVU->regs->VI[REG_TPC].UL, gprT1);
|
||||
xJMP(mVU->exitFunct);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy_fast(&mVUpBlock->pStateEnd, &mVUregs, sizeof(microRegInfo));
|
||||
mVUsetupBranch(mVU, mFC);
|
||||
|
||||
mVUbackupRegs(mVU);
|
||||
MOV32MtoR(gprT2, (uptr)&mVU->branch); // Get startPC (ECX 1st argument for __fastcall)
|
||||
MOV32ItoR(gprR, (u32)&mVUpBlock->pStateEnd); // Get pState (EDX 2nd argument for __fastcall)
|
||||
|
||||
if (!mVU->index) xCALL(mVUcompileJIT<0>); //(u32 startPC, uptr pState)
|
||||
else xCALL(mVUcompileJIT<1>);
|
||||
mVUrestoreRegs(mVU);
|
||||
JMPR(gprT1); // Jump to rec-code address
|
||||
else normJumpCompile(mVU, mFC, 0);
|
||||
}
|
||||
|
|
|
@ -174,14 +174,15 @@ microVUt(void) branchWarning(mV) {
|
|||
}
|
||||
|
||||
microVUt(void) eBitPass1(mV, int& branch) {
|
||||
if (!mVUregs.blockType) {
|
||||
if (mVUregs.blockType != 1) {
|
||||
branch = 1;
|
||||
mVUup.eBit = 1;
|
||||
}
|
||||
}
|
||||
|
||||
microVUt(void) eBitWarning(mV, u32 endCount) {
|
||||
if (endCount == 1) Console::Error("microVU%d Warning: Branch, E-bit, Branch! [%04x]", params mVU->index, xPC);
|
||||
microVUt(void) eBitWarning(mV) {
|
||||
if (mVUpBlock->pState.blockType == 1) Console::Error("microVU%d Warning: Branch, E-bit, Branch! [%04x]", params mVU->index, xPC);
|
||||
if (mVUpBlock->pState.blockType == 2) Console::Error("microVU%d Warning: Branch, Branch, Branch! [%04x]", params mVU->index, xPC);
|
||||
incPC(2);
|
||||
if (curI & _Ebit_) {
|
||||
DevCon::Status("microVU%d: E-bit in Branch delay slot! [%04x]", params mVU->index, xPC);
|
||||
|
@ -361,7 +362,7 @@ microVUr(void*) mVUcompile(microVU* mVU, u32 startPC, uptr pState) {
|
|||
mVUinfo.writeP = !mVU->p;
|
||||
if (branch >= 2) { mVUinfo.isEOB = 1; if (branch == 3) { mVUinfo.isBdelay = 1; } mVUcount++; branchWarning(mVU); break; }
|
||||
else if (branch == 1) { branch = 2; }
|
||||
if (mVUbranch) { mVUsetFlagInfo(mVU); eBitWarning(mVU, endCount); branch = 3; mVUbranch = 0; }
|
||||
if (mVUbranch) { mVUsetFlagInfo(mVU); eBitWarning(mVU); branch = 3; mVUbranch = 0; }
|
||||
incPC(1);
|
||||
}
|
||||
|
||||
|
@ -385,11 +386,13 @@ microVUr(void*) mVUcompile(microVU* mVU, u32 startPC, uptr pState) {
|
|||
else { doSwapOp(mVU); }
|
||||
if (mVUinfo.doXGKICK) { mVU_XGKICK_DELAY(mVU, 1); }
|
||||
if (!doRegAlloc) { mVU->regAlloc->flushAll(); }
|
||||
if (!mVUinfo.isBdelay) { incPC(1); }
|
||||
if (_isBlock2) { mVUsetupRange(mVU, xPC, 0); normJumpCompile(mVU, mFC, 1); return thisPtr; }
|
||||
else if (!mVUinfo.isBdelay) { incPC(1); }
|
||||
else {
|
||||
mVUsetupRange(mVU, xPC, 0);
|
||||
mVUdebugNOW(1);
|
||||
switch (mVUbranch) {
|
||||
incPC(-3); // Go back to branch opcode
|
||||
switch (mVUlow.branch) {
|
||||
case 1: case 2: normBranch(mVU, mFC); return thisPtr; // B/BAL
|
||||
case 9: case 10: normJump (mVU, mFC); return thisPtr; // JR/JALR
|
||||
case 3: condBranch(mVU, mFC, Jcc_Equal); return thisPtr; // IBEQ
|
||||
|
|
|
@ -44,7 +44,7 @@ __declspec(align(16)) struct microRegInfo { // Ordered for Faster Compares
|
|||
u8 VI[16];
|
||||
regInfo VF[32];
|
||||
u8 flags; // clip x2 :: status x2
|
||||
u8 blockType; // 0 = Normal; 1 = Compile one instruction with E-bit termination
|
||||
u8 blockType; // 0 = Normal; 1 = Compile one instruction (E-bit End); 2 = Compile one instruction (Branch End)
|
||||
u8 padding[5]; // 160 bytes
|
||||
#if defined(_MSC_VER)
|
||||
};
|
||||
|
@ -107,6 +107,7 @@ struct microLowerOp {
|
|||
microVIreg VI_read[2]; // VI regs read by this instruction
|
||||
microConstInfo constJump; // Constant Reg Info for JR/JARL instructions
|
||||
u32 branch; // Branch Type (0 = Not a Branch, 1 = B. 2 = BAL, 3~8 = Conditional Branches, 9 = JALR, 10 = JR)
|
||||
bool evilBranch;// This instruction is a Branch in a Branch Delay Slot
|
||||
bool isNOP; // This instruction is a NOP
|
||||
bool isFSSET; // This instruction is a FSSET
|
||||
bool noWriteVF; // Don't write back the result of a lower op to VF reg if upper op writes to same reg (or if VF = 0)
|
||||
|
|
|
@ -1164,9 +1164,21 @@ void setBranchA(mP, int x, int _x_) {
|
|||
pass4 { if (_Imm11_ == 1 && !_x_) { return; } mVUbranch = x; }
|
||||
}
|
||||
|
||||
void condEvilBranch(mV, int JMPcc) {
|
||||
using namespace x86Emitter;
|
||||
xCMP(ax, 0);
|
||||
xMOV(ptr32[&mVU->evilBranch], branchAddr);
|
||||
xForwardJump8 cJMP((JccComparisonType)JMPcc);
|
||||
incPC(-2); // Branch Not Taken
|
||||
xMOV(ptr32[&mVU->evilBranch], ((branchAddr+8) & (mVU->microMemSize-8)));
|
||||
incPC(2);
|
||||
cJMP.SetTarget();
|
||||
}
|
||||
|
||||
mVUop(mVU_B) {
|
||||
setBranchA(mX, 1, 0);
|
||||
pass1 { mVUanalyzeNormBranch(mVU, 0, 0); }
|
||||
pass2 { if (mVUlow.evilBranch) { MOV32ItoM((uptr)&mVU->evilBranch, branchAddr); } }
|
||||
pass3 { mVUlog("B [<a href=\"#addr%04x\">%04x</a>]", branchAddr, branchAddr); }
|
||||
}
|
||||
|
||||
|
@ -1176,76 +1188,93 @@ mVUop(mVU_BAL) {
|
|||
pass2 {
|
||||
MOV32ItoR(gprT1, bSaveAddr);
|
||||
mVUallocVIb(mVU, gprT1, _It_);
|
||||
if (mVUlow.evilBranch) { MOV32ItoM((uptr)&mVU->evilBranch, branchAddr); }
|
||||
}
|
||||
pass3 { mVUlog("BAL vi%02d [<a href=\"#addr%04x\">%04x</a>]", _Ft_, branchAddr, branchAddr); }
|
||||
}
|
||||
|
||||
mVUop(mVU_IBEQ) {
|
||||
using namespace x86Emitter;
|
||||
setBranchA(mX, 3, 0);
|
||||
pass1 { mVUanalyzeCondBranch2(mVU, _Is_, _It_); }
|
||||
pass2 {
|
||||
if (mVUlow.memReadIs) MOV32MtoR(gprT1, (uptr)&mVU->VIbackup);
|
||||
else mVUallocVIa(mVU, gprT1, _Is_);
|
||||
|
||||
if (mVUlow.memReadIt) XOR32MtoR(gprT1, (uptr)&mVU->VIbackup);
|
||||
else { mVUallocVIa(mVU, gprT2, _It_); XOR32RtoR(gprT1, gprT2); }
|
||||
MOV32RtoM((uptr)&mVU->branch, gprT1);
|
||||
|
||||
if (!mVUlow.evilBranch) { MOV32RtoM((uptr)&mVU->branch, gprT1); }
|
||||
else { condEvilBranch(mVU, Jcc_Equal); }
|
||||
}
|
||||
pass3 { mVUlog("IBEQ vi%02d, vi%02d [<a href=\"#addr%04x\">%04x</a>]", _Ft_, _Fs_, branchAddr, branchAddr); }
|
||||
}
|
||||
|
||||
mVUop(mVU_IBGEZ) {
|
||||
using namespace x86Emitter;
|
||||
setBranchA(mX, 4, 0);
|
||||
pass1 { mVUanalyzeCondBranch1(mVU, _Is_); }
|
||||
pass2 {
|
||||
if (mVUlow.memReadIs) MOV32MtoR(gprT1, (uptr)&mVU->VIbackup);
|
||||
else mVUallocVIa(mVU, gprT1, _Is_);
|
||||
MOV32RtoM((uptr)&mVU->branch, gprT1);
|
||||
if (mVUlow.memReadIs) MOV32MtoR(gprT1, (uptr)&mVU->VIbackup);
|
||||
else mVUallocVIa(mVU, gprT1, _Is_);
|
||||
if (!mVUlow.evilBranch) MOV32RtoM((uptr)&mVU->branch, gprT1);
|
||||
else condEvilBranch(mVU, Jcc_GreaterOrEqual);
|
||||
}
|
||||
pass3 { mVUlog("IBGEZ vi%02d [<a href=\"#addr%04x\">%04x</a>]", _Fs_, branchAddr, branchAddr); }
|
||||
}
|
||||
|
||||
mVUop(mVU_IBGTZ) {
|
||||
using namespace x86Emitter;
|
||||
setBranchA(mX, 5, 0);
|
||||
pass1 { mVUanalyzeCondBranch1(mVU, _Is_); }
|
||||
pass2 {
|
||||
if (mVUlow.memReadIs) MOV32MtoR(gprT1, (uptr)&mVU->VIbackup);
|
||||
else mVUallocVIa(mVU, gprT1, _Is_);
|
||||
MOV32RtoM((uptr)&mVU->branch, gprT1);
|
||||
if (mVUlow.memReadIs) MOV32MtoR(gprT1, (uptr)&mVU->VIbackup);
|
||||
else mVUallocVIa(mVU, gprT1, _Is_);
|
||||
if (!mVUlow.evilBranch) MOV32RtoM((uptr)&mVU->branch, gprT1);
|
||||
else condEvilBranch(mVU, Jcc_Greater);
|
||||
}
|
||||
pass3 { mVUlog("IBGTZ vi%02d [<a href=\"#addr%04x\">%04x</a>]", _Fs_, branchAddr, branchAddr); }
|
||||
}
|
||||
|
||||
mVUop(mVU_IBLEZ) {
|
||||
using namespace x86Emitter;
|
||||
setBranchA(mX, 6, 0);
|
||||
pass1 { mVUanalyzeCondBranch1(mVU, _Is_); }
|
||||
pass2 {
|
||||
if (mVUlow.memReadIs) MOV32MtoR(gprT1, (uptr)&mVU->VIbackup);
|
||||
else mVUallocVIa(mVU, gprT1, _Is_);
|
||||
MOV32RtoM((uptr)&mVU->branch, gprT1);
|
||||
if (mVUlow.memReadIs) MOV32MtoR(gprT1, (uptr)&mVU->VIbackup);
|
||||
else mVUallocVIa(mVU, gprT1, _Is_);
|
||||
if (!mVUlow.evilBranch) MOV32RtoM((uptr)&mVU->branch, gprT1);
|
||||
else condEvilBranch(mVU, Jcc_LessOrEqual);
|
||||
}
|
||||
pass3 { mVUlog("IBLEZ vi%02d [<a href=\"#addr%04x\">%04x</a>]", _Fs_, branchAddr, branchAddr); }
|
||||
}
|
||||
|
||||
mVUop(mVU_IBLTZ) {
|
||||
using namespace x86Emitter;
|
||||
setBranchA(mX, 7, 0);
|
||||
pass1 { mVUanalyzeCondBranch1(mVU, _Is_); }
|
||||
pass2 {
|
||||
if (mVUlow.memReadIs) MOV32MtoR(gprT1, (uptr)&mVU->VIbackup);
|
||||
else mVUallocVIa(mVU, gprT1, _Is_);
|
||||
MOV32RtoM((uptr)&mVU->branch, gprT1);
|
||||
pass2 {
|
||||
if (mVUlow.memReadIs) MOV32MtoR(gprT1, (uptr)&mVU->VIbackup);
|
||||
else mVUallocVIa(mVU, gprT1, _Is_);
|
||||
if (!mVUlow.evilBranch) MOV32RtoM((uptr)&mVU->branch, gprT1);
|
||||
else condEvilBranch(mVU, Jcc_Less);
|
||||
}
|
||||
pass3 { mVUlog("IBLTZ vi%02d [<a href=\"#addr%04x\">%04x</a>]", _Fs_, branchAddr, branchAddr); }
|
||||
}
|
||||
|
||||
mVUop(mVU_IBNE) {
|
||||
using namespace x86Emitter;
|
||||
setBranchA(mX, 8, 0);
|
||||
pass1 { mVUanalyzeCondBranch2(mVU, _Is_, _It_); }
|
||||
pass2 {
|
||||
if (mVUlow.memReadIs) MOV32MtoR(gprT1, (uptr)&mVU->VIbackup);
|
||||
else mVUallocVIa(mVU, gprT1, _Is_);
|
||||
|
||||
if (mVUlow.memReadIt) XOR32MtoR(gprT1, (uptr)&mVU->VIbackup);
|
||||
else { mVUallocVIa(mVU, gprT2, _It_); XOR32RtoR(gprT1, gprT2); }
|
||||
MOV32RtoM((uptr)&mVU->branch, gprT1);
|
||||
|
||||
if (!mVUlow.evilBranch) { MOV32RtoM((uptr)&mVU->branch, gprT1); }
|
||||
else { condEvilBranch(mVU, Jcc_NotEqual); }
|
||||
}
|
||||
pass3 { mVUlog("IBNE vi%02d, vi%02d [<a href=\"#addr%04x\">%04x</a>]", _Ft_, _Fs_, branchAddr, branchAddr); }
|
||||
}
|
||||
|
@ -1254,11 +1283,12 @@ mVUop(mVU_JR) {
|
|||
mVUbranch = 9;
|
||||
pass1 { mVUanalyzeJump(mVU, _Is_, 0, 0); }
|
||||
pass2 {
|
||||
if (!mVUlow.constJump.isValid) {
|
||||
if (!mVUlow.constJump.isValid || mVUlow.evilBranch) {
|
||||
mVUallocVIa(mVU, gprT1, _Is_);
|
||||
SHL32ItoR(gprT1, 3);
|
||||
AND32ItoR(gprT1, mVU->microMemSize - 8);
|
||||
MOV32RtoM((uptr)&mVU->branch, gprT1);
|
||||
if (!mVUlow.evilBranch) MOV32RtoM((uptr)&mVU->branch, gprT1);
|
||||
else MOV32RtoM((uptr)&mVU->evilBranch, gprT1);
|
||||
}
|
||||
}
|
||||
pass3 { mVUlog("JR [vi%02d]", _Fs_); }
|
||||
|
@ -1268,11 +1298,13 @@ mVUop(mVU_JALR) {
|
|||
mVUbranch = 10;
|
||||
pass1 { mVUanalyzeJump(mVU, _Is_, _It_, 1); }
|
||||
pass2 {
|
||||
if (!mVUlow.constJump.isValid) {
|
||||
if (!mVUlow.constJump.isValid || mVUlow.evilBranch) {
|
||||
mVUallocVIa(mVU, gprT1, _Is_);
|
||||
SHL32ItoR(gprT1, 3);
|
||||
AND32ItoR(gprT1, mVU->microMemSize - 8);
|
||||
MOV32RtoM((uptr)&mVU->branch, gprT1);
|
||||
if (!mVUlow.evilBranch) MOV32RtoM((uptr)&mVU->branch, gprT1);
|
||||
else MOV32RtoM((uptr)&mVU->evilBranch, gprT1);
|
||||
}
|
||||
MOV32ItoR(gprT1, bSaveAddr);
|
||||
mVUallocVIb(mVU, gprT1, _It_);
|
||||
|
|
|
@ -206,6 +206,7 @@ typedef u32 (__fastcall *mVUCall)(void*, void*);
|
|||
#define mFLAG mVUinfo.mFlag
|
||||
#define cFLAG mVUinfo.cFlag
|
||||
#define mVUrange mVUcurProg.ranges.range[mVUcurProg.ranges.total]
|
||||
#define _isBlock2 (mVUpBlock->pState.blockType == 2)
|
||||
#define xPC ((iPC / 2) * 8)
|
||||
#define curI ((u32*)mVU->regs->Micro)[iPC] //mVUcurProg.data[iPC]
|
||||
#define setCode() { mVU->code = curI; }
|
||||
|
|
Loading…
Reference in New Issue