mirror of https://github.com/PCSX2/pcsx2.git
more microVU stuff...
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@953 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
9c8a9712a9
commit
076e9e5386
|
@ -42,7 +42,6 @@ microVUt(void) mVUinit(VURegs* vuRegsPtr) {
|
|||
mVU->index = vuIndex;
|
||||
mVU->microSize = (vuIndex ? 0x4000 : 0x1000);
|
||||
mVU->progSize = (vuIndex ? 0x4000 : 0x1000) / 4;
|
||||
mVU->cacheAddr = (vuIndex ? 0x1e840000 : 0x0e840000);
|
||||
mVU->cache = NULL;
|
||||
|
||||
mVUreset<vuIndex>();
|
||||
|
@ -62,7 +61,7 @@ microVUt(void) mVUreset() {
|
|||
}
|
||||
|
||||
// Dynarec Cache
|
||||
mVU->cache = SysMmapEx(mVU->cacheAddr, mVU->cacheSize, 0, (vuIndex ? "Micro VU1" : "Micro VU0"));
|
||||
mVU->cache = SysMmapEx((vuIndex ? 0x1e840000 : 0x0e840000), mVU->cacheSize, 0, (vuIndex ? "Micro VU1" : "Micro VU0"));
|
||||
if ( mVU->cache == NULL ) throw Exception::OutOfMemory(fmt_string( "microVU Error: Failed to allocate recompiler memory! (addr: 0x%x)", params (u32)mVU->cache));
|
||||
mVU->ptr = mVU->cache;
|
||||
|
||||
|
@ -70,12 +69,21 @@ microVUt(void) mVUreset() {
|
|||
mVUdispatcherA<vuIndex>();
|
||||
mVUdispatcherB<vuIndex>();
|
||||
|
||||
// Other Variables
|
||||
// Program Variables
|
||||
memset(&mVU->prog, 0, sizeof(mVU->prog));
|
||||
mVU->prog.finished = 1;
|
||||
mVU->prog.cleared = 1;
|
||||
mVU->prog.cur = -1;
|
||||
mVU->prog.total = -1;
|
||||
|
||||
// Setup Dynarec Cache Limits for Each Program
|
||||
u8* z = (mVU->cache + 512); // Dispatcher Code is in first 512 bytes
|
||||
for (int i = 0; i <= mVU->prog.max; i++) {
|
||||
mVU->prog.prog[i].x86start = z;
|
||||
mVU->prog.prog[i].x86ptr = z;
|
||||
z += (mVU->cacheSize / (mVU->prog.max + 1));
|
||||
mVU->prog.prog[i].x86end = z;
|
||||
}
|
||||
}
|
||||
|
||||
// Free Allocated Resources
|
||||
|
@ -111,6 +119,7 @@ microVUt(void) mVUclear(u32 addr, u32 size) {
|
|||
// Clears program data (Sets used to 1 because calling this function implies the program will be used at least once)
|
||||
__forceinline void mVUclearProg(microVU* mVU, int progIndex) {
|
||||
mVU->prog.prog[progIndex].used = 1;
|
||||
mVU->prog.prog[progIndex].x86ptr = mVU->prog.prog[progIndex].x86start;
|
||||
for (u32 i = 0; i < (mVU->progSize / 2); i++) {
|
||||
mVU->prog.prog[progIndex].block[i]->reset();
|
||||
}
|
||||
|
@ -149,7 +158,7 @@ __forceinline int mVUsearchProg(microVU* mVU) {
|
|||
for (int i = 0; i <= mVU->prog.total; i++) {
|
||||
//if (i == mVU->prog.cur) continue; // We can skip the current program. (ToDo: Verify that games don't clear, and send the same microprogram :/)
|
||||
if (!memcmp_mmx(mVU->prog.prog[i].data, mVU->regs->Micro, mVU->microSize)) {
|
||||
if (i == mVU->prog.cur) SysPrintf("microVU: Same micro program sent!\n");
|
||||
if (i == mVU->prog.cur) { mVUlog("microVU: Same micro program sent!"); }
|
||||
mVU->prog.cur = i;
|
||||
mVU->prog.cleared = 0;
|
||||
mVU->prog.prog[i].used++;
|
||||
|
|
|
@ -92,7 +92,10 @@ public:
|
|||
template<u32 progSize>
|
||||
struct microProgram {
|
||||
u32 data[progSize/4];
|
||||
u32 used; // Number of times its been used
|
||||
u32 used; // Number of times its been used
|
||||
u8* x86ptr; // Pointer to program's recompilation code
|
||||
u8* x86start; // Start of program's rec-cache
|
||||
u8* x86end; // Limit of program's rec-cache
|
||||
microBlockManager* block[progSize/8];
|
||||
microAllocInfo<progSize> allocInfo;
|
||||
};
|
||||
|
@ -112,20 +115,24 @@ struct microProgManager {
|
|||
struct microVU {
|
||||
u32 index; // VU Index (VU0 or VU1)
|
||||
u32 microSize; // VU Micro Memory Size
|
||||
u32 progSize; // VU Micro Program Size (microSize/8)
|
||||
u32 cacheAddr; // VU Cache Start Address
|
||||
u32 progSize; // VU Micro Program Size (microSize/4)
|
||||
static const u32 cacheSize = 0x500000; // VU Cache Size
|
||||
|
||||
microProgManager<0x4000> prog; // Micro Program Data
|
||||
|
||||
VURegs* regs; // VU Regs Struct
|
||||
u8* cache; // Dynarec Cache Start (where we will start writing the recompiled code to)
|
||||
u8* startFunct; // Ptr Function to the Start code for recompiled programs
|
||||
u8* exitFunct; // Ptr Function to the Exit code for recompiled programs
|
||||
u8* ptr; // Pointer to next place to write recompiled code to
|
||||
u32 code; // Contains the current Instruction
|
||||
u32 iReg; // iReg (only used in recompilation, not execution)
|
||||
u32 clipFlag[4]; // 4 instances of clip flag (used in execution)
|
||||
u32 divFlag; // 1 instance of I/D flags
|
||||
u32 VIbackup[2]; // Holds a backup of a VI reg if modified before a branch
|
||||
u32 branch; // Holds branch compare result (IBxx) OR Holds address to Jump to (JALR/JR)
|
||||
u32 p; // Holds current P instance index
|
||||
u32 q; // Holds current Q instance index
|
||||
};
|
||||
|
||||
// microVU rec structs
|
||||
|
|
|
@ -52,9 +52,10 @@ template<u32 pSize>
|
|||
struct microAllocInfo {
|
||||
microRegInfo regs; // Pipeline info
|
||||
microTempRegInfo regsTemp; // Temp Pipeline info (used so that new pipeline info isn't conflicting between upper and lower instructions in the same cycle)
|
||||
u8 branch; // 0 = No Branch, 1 = Branch, 2 = Conditional Branch, 3 = Jump (JALR/JR)
|
||||
u8 branch; // 0 = No Branch, 1 = B. 2 = BAL, 3~8 = Conditional Branches, 9 = JALR, 10 = JR
|
||||
u8 maxStall; // Helps in computing stalls (stores the max amount of cycles to stall for the current opcodes)
|
||||
u32 cycles; // Cycles for current block
|
||||
u32 count; // Number of VU 64bit instructions ran (starts at 0 for each block)
|
||||
u32 curPC; // Current PC
|
||||
u32 startPC; // Start PC for Cur Block
|
||||
u32 info[pSize/8]; // Info for Instructions in current block
|
||||
|
|
|
@ -102,6 +102,49 @@ microVUt(void) mVUanalyzeFMAC4(int Fs, int Ft) {
|
|||
analyzeReg4(Ft);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// IALU - IALU Opcodes
|
||||
//------------------------------------------------------------------
|
||||
|
||||
#define analyzeVIreg1(reg) { if (reg) { mVUstall = aMax(mVUstall, mVUregs.VI[reg]); } }
|
||||
#define analyzeVIreg2(reg, aCycles) { if (reg) { mVUregsTemp.VIreg = reg; mVUregsTemp.VI = aCycles; mVUinfo |= _writesVI; mVU->VIbackup[0] = reg; } }
|
||||
|
||||
microVUt(void) mVUanalyzeIALU1(int Id, int Is, int It) {
|
||||
microVU* mVU = mVUx;
|
||||
if (!Id) { mVUinfo |= _isNOP; }
|
||||
analyzeVIreg1(Is);
|
||||
analyzeVIreg1(It);
|
||||
analyzeVIreg2(Id, 1);
|
||||
}
|
||||
|
||||
microVUt(void) mVUanalyzeIALU2(int Is, int It) {
|
||||
microVU* mVU = mVUx;
|
||||
if (!It) { mVUinfo |= _isNOP; }
|
||||
analyzeVIreg1(Is);
|
||||
analyzeVIreg2(It, 1);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// MR32 - MR32 Opcode
|
||||
//------------------------------------------------------------------
|
||||
|
||||
// Flips xyzw stalls to yzwx
|
||||
#define analyzeReg6(reg) { \
|
||||
if (reg) { \
|
||||
if (_X) { mVUstall = aMax(mVUstall, aReg(reg).y); } \
|
||||
if (_Y) { mVUstall = aMax(mVUstall, aReg(reg).z); } \
|
||||
if (_Z) { mVUstall = aMax(mVUstall, aReg(reg).w); } \
|
||||
if (_W) { mVUstall = aMax(mVUstall, aReg(reg).x); } \
|
||||
} \
|
||||
}
|
||||
|
||||
microVUt(void) mVUanalyzeMR32(int Fs, int Ft) {
|
||||
microVU* mVU = mVUx;
|
||||
if (!Ft) { mVUinfo |= _isNOP; }
|
||||
analyzeReg6(Fs);
|
||||
analyzeReg2(Ft);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// FDIV - DIV/SQRT/RSQRT Opcodes
|
||||
//------------------------------------------------------------------
|
||||
|
@ -144,11 +187,18 @@ microVUt(void) mVUanalyzeEFU2(int Fs, u8 xCycles) {
|
|||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// LQx - LQ/LQD/LQI Opcodes
|
||||
// MFP - MFP Opcode
|
||||
//------------------------------------------------------------------
|
||||
|
||||
#define analyzeVIreg1(reg) { if (reg) { mVUstall = aMax(mVUstall, mVUregs.VI[reg]); } }
|
||||
#define analyzeVIreg2(reg, aCycles) { if (reg) { mVUregsTemp.VIreg = reg; mVUregsTemp.VI = aCycles; mVUinfo |= _writesVI; mVU->VIbackup[0] = reg; } }
|
||||
microVUt(void) mVUanalyzeMFP(int Ft) {
|
||||
microVU* mVU = mVUx; // ToDo: Needs special info for P reg?
|
||||
if (!Ft) { mVUinfo |= _isNOP; }
|
||||
analyzeReg2(Ft);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// LQx - LQ/LQD/LQI Opcodes
|
||||
//------------------------------------------------------------------
|
||||
|
||||
microVUt(void) mVUanalyzeLQ(int Ft, int Is, bool writeIs) {
|
||||
microVU* mVU = mVUx;
|
||||
|
@ -183,7 +233,7 @@ microVUt(void) mVUanalyzeR1(int Fs, int Fsf) {
|
|||
|
||||
microVUt(void) mVUanalyzeR2(int Ft, bool canBeNOP) {
|
||||
microVU* mVU = mVUx;
|
||||
if (!Ft) { mVUinfo |= ((canBeNOP) ? _isNOP : _noWriteVF); return; }
|
||||
if (!Ft) { mVUinfo |= ((canBeNOP) ? _isNOP : _noWriteVF); }
|
||||
analyzeReg2(Ft);
|
||||
analyzeRreg();
|
||||
}
|
||||
|
@ -194,11 +244,22 @@ microVUt(void) mVUanalyzeR2(int Ft, bool canBeNOP) {
|
|||
|
||||
microVUt(void) mVUanalyzeSflag(int It) {
|
||||
microVU* mVU = mVUx;
|
||||
if (!It) { mVUinfo |= _isNOP; return; }
|
||||
mVUinfo |= _isSflag;
|
||||
if (!It) { mVUinfo |= _isNOP; }
|
||||
else { mVUinfo |= _isSflag | _swapOps; } // ToDo: set s flag at right time
|
||||
analyzeVIreg2(It, 1);
|
||||
}
|
||||
|
||||
microVUt(void) mVUanalyzeFSSET() {
|
||||
microVU* mVU = mVUx;
|
||||
int i, curPC = iPC;
|
||||
for (i = mVUcount; i > 0; i--) {
|
||||
incPC2(-2);
|
||||
if (isSflag) break;
|
||||
mVUinfo &= ~_doStatus;
|
||||
}
|
||||
iPC = curPC;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// XGkick
|
||||
//------------------------------------------------------------------
|
||||
|
@ -218,7 +279,7 @@ microVUt(void) mVUanalyzeXGkick(int Fs, int xCycles) {
|
|||
//------------------------------------------------------------------
|
||||
|
||||
#define analyzeBranchVI(reg, infoVal) { \
|
||||
if (reg && (mVUcycles > 1)) { /* Ensures branch is not first opcode in block */ \
|
||||
if (reg && (mVUcount > 0)) { /* Ensures branch is not first opcode in block */ \
|
||||
incPC(-2); \
|
||||
if (writesVI && (reg == mVU->VIbackup[0])) { /* If prev Op modified VI reg */ \
|
||||
mVUinfo |= _backupVI; \
|
||||
|
|
|
@ -29,10 +29,25 @@
|
|||
} \
|
||||
}
|
||||
|
||||
#define branchCase(Xcmp) \
|
||||
CMP16ItoM((uptr)mVU->branch, 0); \
|
||||
ajmp = Xcmp((uptr)0); \
|
||||
break
|
||||
|
||||
#define branchCase2() { \
|
||||
incPC(-2); \
|
||||
MOV32ItoR(gprT1, (xPC + (2 * 8)) & ((vuIndex) ? 0x3fff:0xfff)); \
|
||||
mVUallocVIb<vuIndex>(gprT1, _Ft_); \
|
||||
incPC(+2); \
|
||||
}
|
||||
|
||||
#define startLoop() { mVUdebug1(); mVUstall = 0; memset(&mVUregsTemp, 0, sizeof(mVUregsTemp)); }
|
||||
#define calcCycles(reg, x) { reg = ((reg > x) ? (reg - x) : 0); }
|
||||
#define incP() { mVU->p = (mVU->p+1) & 1; }
|
||||
#define incQ() { mVU->q = (mVU->q+1) & 1; }
|
||||
|
||||
microVUt(void) mVUincCycles(int x) {
|
||||
microVU* mVU = mVUx;
|
||||
mVUcycles += x;
|
||||
for (int z = 31; z > 0; z--) {
|
||||
calcCycles(mVUregs.VF[z].x, x);
|
||||
|
@ -45,9 +60,12 @@ microVUt(void) mVUincCycles(int x) {
|
|||
}
|
||||
if (mVUregs.q) {
|
||||
calcCycles(mVUregs.q, x);
|
||||
if (!mVUregs.q) {} // Do Status Flag Merging Stuff?
|
||||
if (!mVUregs.q) { incQ(); } // Do Status Flag Merging Stuff?
|
||||
}
|
||||
if (mVUregs.p) {
|
||||
calcCycles(mVUregs.p, x);
|
||||
if (!mVUregs.p) { incP(); }
|
||||
}
|
||||
calcCycles(mVUregs.p, x);
|
||||
calcCycles(mVUregs.r, x);
|
||||
calcCycles(mVUregs.xgkick, x);
|
||||
}
|
||||
|
@ -57,8 +75,7 @@ microVUt(void) mVUsetCycles() {
|
|||
incCycles(mVUstall);
|
||||
if (mVUregsTemp.VFreg[0] == mVUregsTemp.VFreg[1] && !mVUregsTemp.VFreg[0]) { // If upper Op && lower Op write to same VF reg
|
||||
mVUinfo |= (mVUregsTemp.r || mVUregsTemp.VI) ? _noWriteVF : _isNOP; // If lower Op doesn't modify anything else, then make it a NOP
|
||||
//mVUregsTemp.VF[1].reg = mVUregsTemp.VF[0]; // Just use cycles from upper Op (incorrect?)
|
||||
mVUregsTemp.VF[1].x = aMax(mVUregsTemp.VF[0].x, mVUregsTemp.VF[1].x); // Use max cycles from each vector (correct?)
|
||||
mVUregsTemp.VF[1].x = aMax(mVUregsTemp.VF[0].x, mVUregsTemp.VF[1].x); // Use max cycles from each vector
|
||||
mVUregsTemp.VF[1].y = aMax(mVUregsTemp.VF[0].y, mVUregsTemp.VF[1].y);
|
||||
mVUregsTemp.VF[1].z = aMax(mVUregsTemp.VF[0].z, mVUregsTemp.VF[1].z);
|
||||
mVUregsTemp.VF[1].w = aMax(mVUregsTemp.VF[0].w, mVUregsTemp.VF[1].w);
|
||||
|
@ -72,20 +89,28 @@ microVUt(void) mVUsetCycles() {
|
|||
mVUregs.xgkick = mVUregsTemp.xgkick;
|
||||
}
|
||||
|
||||
microVUx(void) mVUcompile(u32 startPC, u32 pipelineState, microRegInfo* pState, u8* x86ptrStart) {
|
||||
//------------------------------------------------------------------
|
||||
// Recompiler
|
||||
//------------------------------------------------------------------
|
||||
|
||||
microVUx(void*) mVUcompile(u32 startPC, u32 pipelineState, microRegInfo* pState, u8* x86ptrStart) {
|
||||
microVU* mVU = mVUx;
|
||||
microBlock block;
|
||||
u8* thisPtr = mVUcurProg.x86Ptr;
|
||||
iPC = startPC / 4;
|
||||
|
||||
// Searches for Existing Compiled Block (if found, then returns; else, compile)
|
||||
microBlock* pblock = mVUblock[iPC]->search(pipelineState, pState);
|
||||
if (block) { x86SetPtr(pblock->x86ptrEnd); return; }
|
||||
microBlock* pblock = mVUblock[iPC/2]->search(pipelineState, pState);
|
||||
if (block) { return pblock->x86ptrStart; }
|
||||
|
||||
// First Pass
|
||||
setCode();
|
||||
mVUbranch = 0;
|
||||
mVUstartPC = iPC;
|
||||
mVUcount = 0;
|
||||
mVUcycles = 1; // Skips "M" phase, and starts counting cycles at "T" stage
|
||||
mVU->p = 0; // All blocks start at p index #0
|
||||
mVU->q = 0; // All blocks start at q index #0
|
||||
for (int branch = 0;; ) {
|
||||
startLoop();
|
||||
mVUopU<vuIndex, 0>();
|
||||
|
@ -94,11 +119,15 @@ microVUx(void) mVUcompile(u32 startPC, u32 pipelineState, microRegInfo* pState,
|
|||
if (curI & _Ibit_) { incPC(1); mVUinfo |= _isNOP; }
|
||||
else { incPC(1); mVUopL<vuIndex, 0>(); }
|
||||
mVUsetCycles<vuIndex>();
|
||||
if (mVU->p) { mVUinfo |= _readP; }
|
||||
if (mVU->q) { mVUinfo |= _readQ; }
|
||||
else { mVUinfo |= _writeQ; }
|
||||
if (branch >= 2) { mVUinfo |= _isEOB | ((branch == 3) ? _isBdelay : 0); if (mVUbranch) { Console::Error("microVU Warning: Branch in E-bit/Branch delay slot!"); mVUinfo |= _isNOP; } break; }
|
||||
else if (branch == 1) { branch = 2; }
|
||||
if (mVUbranch) { branch = 3; mVUbranch = 0; mVUinfo |= _isBranch; }
|
||||
incPC(1);
|
||||
incCycles(1);
|
||||
mVUcount++;
|
||||
}
|
||||
|
||||
// Second Pass
|
||||
|
@ -109,24 +138,51 @@ microVUx(void) mVUcompile(u32 startPC, u32 pipelineState, microRegInfo* pState,
|
|||
// ToDo: status/mac flag stuff?
|
||||
//
|
||||
if (isEOB) { x = 0; }
|
||||
else if (isBranch) { mVUopU<vuIndex, 1>(); incPC(2); }
|
||||
//if (isBranch2) { mVUopU<vuIndex, 1>(); incPC(2); }
|
||||
|
||||
if (isNop) { mVUopU<vuIndex, 1>(); if (curI & _Ibit_) { incPC(1); mVU->iReg = curI; } else { incPC(1); } }
|
||||
else if (!swapOps) { mVUopU<vuIndex, 1>(); incPC(1); mVUopL<vuIndex, 1>(); }
|
||||
else { incPC(1); mVUopL<vuIndex, 1>(); incPC(-1); mVUopU<vuIndex, 1>(); incPC(1); }
|
||||
|
||||
if (!isBdelay) { incPC(1); }
|
||||
else {
|
||||
incPC(-2); // Go back to Branch Opcode
|
||||
mVUopL<vuIndex, 1>(); // Run Branch Opcode
|
||||
else {
|
||||
u32* ajmp;
|
||||
switch (mVUbranch) {
|
||||
case 1: break;
|
||||
case 2: break;
|
||||
case 3: break;
|
||||
case 3: branchCase(JZ32); // IBEQ
|
||||
case 4: branchCase(JGE32); // IBGEZ
|
||||
case 5: branchCase(JG32); // IBGTZ
|
||||
case 6: branchCase(JLE32); // IBLEQ
|
||||
case 7: branchCase(JL32); // IBLTZ
|
||||
case 8: branchCase(JNZ32); // IBNEQ
|
||||
case 2: branchCase2(); // BAL
|
||||
case 1:
|
||||
// search for block
|
||||
ajmp = JMP32((uptr)0);
|
||||
|
||||
break; // B/BAL
|
||||
case 9: branchCase2(); // JALR
|
||||
case 10: break; // JR/JALR
|
||||
//mVUcurProg.x86Ptr
|
||||
}
|
||||
break;
|
||||
return thisPtr;
|
||||
}
|
||||
}
|
||||
// Do E-bit end stuff here
|
||||
|
||||
incCycles(55); // Ensures Valid P/Q instances
|
||||
mVUcycles -= 55;
|
||||
if (mVU->q) { SSE2_PSHUFD_XMM_to_XMM(xmmPQ, xmmPQ, 0xe5); }
|
||||
SSE_MOVSS_XMM_to_M32((uptr)&mVU->regs->VI[REG_Q], xmmPQ);
|
||||
SSE2_PSHUFD_XMM_to_XMM(xmmPQ, xmmPQ, mVU->p ? 3 : 2);
|
||||
SSE_MOVSS_XMM_to_M32((uptr)&mVU->regs->VI[REG_P], xmmPQ);
|
||||
|
||||
MOV32ItoM((uptr)&mVU->p, mVU->p);
|
||||
MOV32ItoM((uptr)&mVU->q, mVU->q);
|
||||
AND32ItoM((uptr)µVU0.regs.VI[REG_VPU_STAT].UL, (vuIndex ? ~0x100 : ~0x001)); // VBS0/VBS1 flag
|
||||
AND32ItoM((uptr)&mVU->regs->vifRegs->stat, ~0x4); // Not sure what this does but zerorecs do it...
|
||||
MOV32ItoM((uptr)&mVU->regs->VI[REG_TPC], xPC);
|
||||
JMP32((uptr)mVU->exitFunct - ((uptr)x86Ptr + 5));
|
||||
return thisPtr;
|
||||
}
|
||||
|
||||
#endif //PCSX2_MICROVU
|
||||
|
|
|
@ -27,6 +27,7 @@ microVUt(void) mVUdispatcherA() {
|
|||
static u32 PCSX2_ALIGNED16(vuMXCSR);
|
||||
microVU* mVU = mVUx;
|
||||
x86SetPtr(mVU->ptr);
|
||||
mVU->startFunct = mVU->ptr;
|
||||
|
||||
// __fastcall = The first two DWORD or smaller arguments are passed in ECX and EDX registers; all other arguments are passed right to left.
|
||||
if (!vuIndex) { CALLFunc((uptr)mVUexecuteVU0); }
|
||||
|
@ -74,6 +75,7 @@ microVUt(void) mVUdispatcherB() {
|
|||
static u32 PCSX2_ALIGNED16(eeMXCSR);
|
||||
microVU* mVU = mVUx;
|
||||
x86SetPtr(mVU->ptr);
|
||||
mVU->exitFunct = mVU->ptr;
|
||||
|
||||
// __fastcall = The first two DWORD or smaller arguments are passed in ECX and EDX registers; all other arguments are passed right to left.
|
||||
if (!vuIndex) { CALLFunc((uptr)mVUcleanUpVU0); }
|
||||
|
@ -96,9 +98,9 @@ microVUt(void) mVUdispatcherB() {
|
|||
}
|
||||
|
||||
SSE_MOVAPS_XMM_to_M128((uptr)&mVU->regs->ACC, xmmACC);
|
||||
SSE_MOVSS_XMM_to_M32((uptr)&mVU->regs->VI[REG_Q], xmmPQ); // ToDo: Ensure Correct Q/P instances
|
||||
SSE2_PSHUFD_XMM_to_XMM(xmmPQ, xmmPQ, 0); // wzyx = PPPP
|
||||
SSE_MOVSS_XMM_to_M32((uptr)&mVU->regs->VI[REG_P], xmmPQ);
|
||||
//SSE_MOVSS_XMM_to_M32((uptr)&mVU->regs->VI[REG_Q], xmmPQ); // ToDo: Ensure Correct Q/P instances
|
||||
//SSE2_PSHUFD_XMM_to_XMM(xmmPQ, xmmPQ, 0); // wzyx = PPPP
|
||||
//SSE_MOVSS_XMM_to_M32((uptr)&mVU->regs->VI[REG_P], xmmPQ);
|
||||
|
||||
// Restore cpu state
|
||||
POP32R(EDI);
|
||||
|
@ -110,7 +112,7 @@ microVUt(void) mVUdispatcherB() {
|
|||
RET();
|
||||
|
||||
mVU->ptr = x86Ptr;
|
||||
mVUcachCheck(512);
|
||||
mVUcachCheck(mVU->cache, 512);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
|
@ -144,16 +146,16 @@ microVUt(void*) __fastcall mVUexecute(u32 startPC, u32 cycles) {
|
|||
|
||||
microVUt(void) mVUcleanUp() {
|
||||
microVU* mVU = mVUx;
|
||||
mVU->ptr = x86Ptr;
|
||||
mVUcachCheck(1024); // ToDo: Implement Program Cache Limits
|
||||
mVU->ptr = mVUcurProg.x86ptr;
|
||||
mVUcachCheck(mVUcurProg.x86start, (uptr)(mVUcurProg.x86end - mVUcurProg.x86start));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Caller Functions
|
||||
//------------------------------------------------------------------
|
||||
|
||||
void __fastcall startVU0(u32 startPC, u32 cycles) { ((mVUrecCall)microVU0.cache)(startPC, cycles); }
|
||||
void __fastcall startVU1(u32 startPC, u32 cycles) { ((mVUrecCall)microVU1.cache)(startPC, cycles); }
|
||||
void __fastcall startVU0(u32 startPC, u32 cycles) { ((mVUrecCall)microVU0.startFunct)(startPC, cycles); }
|
||||
void __fastcall startVU1(u32 startPC, u32 cycles) { ((mVUrecCall)microVU1.startFunct)(startPC, cycles); }
|
||||
void* __fastcall mVUexecuteVU0(u32 startPC, u32 cycles) { return mVUexecute<0>(startPC, cycles); }
|
||||
void* __fastcall mVUexecuteVU1(u32 startPC, u32 cycles) { return mVUexecute<1>(startPC, cycles); }
|
||||
void mVUcleanUpVU0() { mVUcleanUp<0>(); }
|
||||
|
|
|
@ -545,14 +545,12 @@ microVUf(void) mVU_FSOR() {
|
|||
|
||||
microVUf(void) mVU_FSSET() {
|
||||
microVU* mVU = mVUx;
|
||||
if (!recPass) {}
|
||||
if (!recPass) { mVUanalyzeFSSET<vuIndex>(); }
|
||||
else {
|
||||
int flagReg;
|
||||
getFlagReg(flagReg, fsInstance);
|
||||
MOV16ItoR(gprT1, (_Imm12_ & 0xfc0));
|
||||
//if (_Imm12_ & 0xc00) { mVUdivFlag = _Imm12_ >> 9; }
|
||||
//else { mVUdivFlag = 1; }
|
||||
//mVUdivFlagT = 4;
|
||||
AND32ItoR(flagReg, 0x03f);
|
||||
OR32ItoR(flagReg, (_Imm12_ & 0xfc0));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -562,7 +560,7 @@ microVUf(void) mVU_FSSET() {
|
|||
|
||||
microVUf(void) mVU_IADD() {
|
||||
microVU* mVU = mVUx;
|
||||
if (!recPass) {}
|
||||
if (!recPass) { mVUanalyzeIALU1<vuIndex>(_Fd_, _Fs_, _Ft_); }
|
||||
else {
|
||||
mVUallocVIa<vuIndex>(gprT1, _Fs_);
|
||||
if (_Ft_ != _Fs_) {
|
||||
|
@ -576,7 +574,7 @@ microVUf(void) mVU_IADD() {
|
|||
|
||||
microVUf(void) mVU_IADDI() {
|
||||
microVU* mVU = mVUx;
|
||||
if (!recPass) {}
|
||||
if (!recPass) { mVUanalyzeIALU2<vuIndex>(_Fs_, _Ft_); }
|
||||
else {
|
||||
mVUallocVIa<vuIndex>(gprT1, _Fs_);
|
||||
ADD16ItoR(gprT1, _Imm5_);
|
||||
|
@ -586,7 +584,7 @@ microVUf(void) mVU_IADDI() {
|
|||
|
||||
microVUf(void) mVU_IADDIU() {
|
||||
microVU* mVU = mVUx;
|
||||
if (!recPass) {}
|
||||
if (!recPass) { mVUanalyzeIALU2<vuIndex>(_Fs_, _Ft_); }
|
||||
else {
|
||||
mVUallocVIa<vuIndex>(gprT1, _Fs_);
|
||||
ADD16ItoR(gprT1, _Imm12_);
|
||||
|
@ -596,7 +594,7 @@ microVUf(void) mVU_IADDIU() {
|
|||
|
||||
microVUf(void) mVU_IAND() {
|
||||
microVU* mVU = mVUx;
|
||||
if (!recPass) {}
|
||||
if (!recPass) { mVUanalyzeIALU1<vuIndex>(_Fd_, _Fs_, _Ft_); }
|
||||
else {
|
||||
mVUallocVIa<vuIndex>(gprT1, _Fs_);
|
||||
if (_Ft_ != _Fs_) {
|
||||
|
@ -609,7 +607,7 @@ microVUf(void) mVU_IAND() {
|
|||
|
||||
microVUf(void) mVU_IOR() {
|
||||
microVU* mVU = mVUx;
|
||||
if (!recPass) {}
|
||||
if (!recPass) { mVUanalyzeIALU1<vuIndex>(_Fd_, _Fs_, _Ft_); }
|
||||
else {
|
||||
mVUallocVIa<vuIndex>(gprT1, _Fs_);
|
||||
if (_Ft_ != _Fs_) {
|
||||
|
@ -622,7 +620,7 @@ microVUf(void) mVU_IOR() {
|
|||
|
||||
microVUf(void) mVU_ISUB() {
|
||||
microVU* mVU = mVUx;
|
||||
if (!recPass) {}
|
||||
if (!recPass) { mVUanalyzeIALU1<vuIndex>(_Fd_, _Fs_, _Ft_); }
|
||||
else {
|
||||
if (_Ft_ != _Fs_) {
|
||||
mVUallocVIa<vuIndex>(gprT1, _Fs_);
|
||||
|
@ -639,7 +637,7 @@ microVUf(void) mVU_ISUB() {
|
|||
|
||||
microVUf(void) mVU_ISUBIU() {
|
||||
microVU* mVU = mVUx;
|
||||
if (!recPass) {}
|
||||
if (!recPass) { mVUanalyzeIALU2<vuIndex>(_Fs_, _Ft_); }
|
||||
else {
|
||||
mVUallocVIa<vuIndex>(gprT1, _Fs_);
|
||||
SUB16ItoR(gprT1, _Imm12_);
|
||||
|
@ -653,7 +651,7 @@ microVUf(void) mVU_ISUBIU() {
|
|||
|
||||
microVUf(void) mVU_MFIR() {
|
||||
microVU* mVU = mVUx;
|
||||
if (!recPass) { /*If (!_Ft_) nop();*/ }
|
||||
if (!recPass) { if (!_Ft_) { mVUinfo |= _isNOP; } analyzeVIreg1(_Fs_); analyzeReg2(_Ft_); }
|
||||
else {
|
||||
mVUallocVIa<vuIndex>(gprT1, _Fs_);
|
||||
MOVSX32R16toR(gprT1, gprT1);
|
||||
|
@ -665,7 +663,7 @@ microVUf(void) mVU_MFIR() {
|
|||
|
||||
microVUf(void) mVU_MFP() {
|
||||
microVU* mVU = mVUx;
|
||||
if (!recPass) { /*If (!_Ft_) nop();*/ }
|
||||
if (!recPass) { mVUanalyzeMFP<vuIndex>(_Ft_); }
|
||||
else {
|
||||
getPreg(xmmFt);
|
||||
mVUsaveReg<vuIndex>(xmmFt, (uptr)&mVU->regs->VF[_Ft_].UL[0], _X_Y_Z_W);
|
||||
|
@ -674,7 +672,7 @@ microVUf(void) mVU_MFP() {
|
|||
|
||||
microVUf(void) mVU_MOVE() {
|
||||
microVU* mVU = mVUx;
|
||||
if (!recPass) { /*If (!_Ft_ || (_Ft_ == _Fs_)) nop();*/ }
|
||||
if (!recPass) { if (!_Ft_ || (_Ft_ == _Fs_)) { mVUinfo |= _isNOP; } analyzeReg1(_Fs_); analyzeReg2(_Ft_); }
|
||||
else {
|
||||
mVUloadReg<vuIndex>(xmmT1, (uptr)&mVU->regs->VF[_Fs_].UL[0], _X_Y_Z_W);
|
||||
mVUsaveReg<vuIndex>(xmmT1, (uptr)&mVU->regs->VF[_Ft_].UL[0], _X_Y_Z_W);
|
||||
|
@ -683,7 +681,7 @@ microVUf(void) mVU_MOVE() {
|
|||
|
||||
microVUf(void) mVU_MR32() {
|
||||
microVU* mVU = mVUx;
|
||||
if (!recPass) { /*If (!_Ft_) nop();*/ }
|
||||
if (!recPass) { mVUanalyzeMR32<vuIndex>(_Fs_, _Ft_); }
|
||||
else {
|
||||
mVUloadReg<vuIndex>(xmmT1, (uptr)&mVU->regs->VF[_Fs_].UL[0], (_X_Y_Z_W == 8) ? 4 : 15);
|
||||
if (_X_Y_Z_W != 8) { SSE2_PSHUFD_XMM_to_XMM(xmmT1, xmmT1, 0x39); }
|
||||
|
@ -693,7 +691,7 @@ microVUf(void) mVU_MR32() {
|
|||
|
||||
microVUf(void) mVU_MTIR() {
|
||||
microVU* mVU = mVUx;
|
||||
if (!recPass) {}
|
||||
if (!recPass) { if (!_Ft_) { mVUinfo |= _isNOP; } analyzeReg5(_Fs_, _Fsf_); analyzeVIreg2(_Ft_, 1); }
|
||||
else {
|
||||
MOVZX32M16toR(gprT1, (uptr)&mVU->regs->VF[_Fs_].UL[_Fsf_]);
|
||||
mVUallocVIb<vuIndex>(gprT1, _Ft_);
|
||||
|
@ -706,7 +704,7 @@ microVUf(void) mVU_MTIR() {
|
|||
|
||||
microVUf(void) mVU_ILW() {
|
||||
microVU* mVU = mVUx;
|
||||
if (!recPass) { /*If (!_Ft_) nop();*/ }
|
||||
if (!recPass) { if (!_Ft_) { mVUinfo |= _isNOP; } analyzeVIreg1(_Fs_); analyzeVIreg2(_Ft_, 4); }
|
||||
else {
|
||||
if (!_Fs_) {
|
||||
MOVZX32M16toR( gprT1, (uptr)mVU->regs->Mem + getVUmem(_Imm11_) + offsetSS );
|
||||
|
@ -725,7 +723,7 @@ microVUf(void) mVU_ILW() {
|
|||
|
||||
microVUf(void) mVU_ILWR() {
|
||||
microVU* mVU = mVUx;
|
||||
if (!recPass) { /*If (!_Ft_) nop();*/ }
|
||||
if (!recPass) { if (!_Ft_) { mVUinfo |= _isNOP; } analyzeVIreg1(_Fs_); analyzeVIreg2(_Ft_, 4); }
|
||||
else {
|
||||
if (!_Fs_) {
|
||||
MOVZX32M16toR(gprT1, (uptr)mVU->regs->Mem + offsetSS);
|
||||
|
@ -747,7 +745,7 @@ microVUf(void) mVU_ILWR() {
|
|||
|
||||
microVUf(void) mVU_ISW() {
|
||||
microVU* mVU = mVUx;
|
||||
if (!recPass) {}
|
||||
if (!recPass) { analyzeVIreg1(_Fs_); analyzeVIreg1(_Ft_); }
|
||||
else {
|
||||
if (!_Fs_) {
|
||||
int imm = getVUmem(_Imm11_);
|
||||
|
@ -772,7 +770,7 @@ microVUf(void) mVU_ISW() {
|
|||
|
||||
microVUf(void) mVU_ISWR() {
|
||||
microVU* mVU = mVUx;
|
||||
if (!recPass) {}
|
||||
if (!recPass) { analyzeVIreg1(_Fs_); analyzeVIreg1(_Ft_); }
|
||||
else {
|
||||
if (!_Fs_) {
|
||||
mVUallocVIa<vuIndex>(gprT1, _Ft_);
|
||||
|
@ -1006,7 +1004,7 @@ microVUf(void) mVU_WAITQ() {
|
|||
|
||||
microVUf(void) mVU_XTOP() {
|
||||
microVU* mVU = mVUx;
|
||||
if (!recPass) { if (!_Ft_) { mVUinfo |= _isNOP; return; } analyzeVIreg2(_Ft_, 1); }
|
||||
if (!recPass) { if (!_Ft_) { mVUinfo |= _isNOP; } analyzeVIreg2(_Ft_, 1); }
|
||||
else {
|
||||
MOVZX32M16toR( gprT1, (uptr)&mVU->regs->vifRegs->top);
|
||||
mVUallocVIb<vuIndex>(gprT1, _Ft_);
|
||||
|
@ -1015,7 +1013,7 @@ microVUf(void) mVU_XTOP() {
|
|||
|
||||
microVUf(void) mVU_XITOP() {
|
||||
microVU* mVU = mVUx;
|
||||
if (!recPass) { if (!_Ft_) { mVUinfo |= _isNOP; return; } analyzeVIreg2(_Ft_, 1); }
|
||||
if (!recPass) { if (!_Ft_) { mVUinfo |= _isNOP; } analyzeVIreg2(_Ft_, 1); }
|
||||
else {
|
||||
MOVZX32M16toR( gprT1, (uptr)&mVU->regs->vifRegs->itop );
|
||||
mVUallocVIb<vuIndex>(gprT1, _Ft_);
|
||||
|
@ -1055,64 +1053,90 @@ microVUf(void) mVU_XGKICK() {
|
|||
|
||||
microVUf(void) mVU_B() {
|
||||
microVU* mVU = mVUx;
|
||||
mVUbranch = 1;
|
||||
mVUbranch = 1;
|
||||
if (!recPass) { /*mVUinfo |= _isBranch2;*/ }
|
||||
}
|
||||
microVUf(void) mVU_BAL() {
|
||||
microVU* mVU = mVUx;
|
||||
mVUbranch = 1;
|
||||
if (!recPass) { analyzeVIreg2(_Ft_, 1); }
|
||||
else {
|
||||
MOV32ItoR(gprT1, (xPC + (2 * 8)) & 0xffff);
|
||||
mVUallocVIb<vuIndex>(gprT1, _Ft_);
|
||||
}
|
||||
mVUbranch = 2;
|
||||
if (!recPass) { /*mVUinfo |= _isBranch2;*/ analyzeVIreg2(_Ft_, 1); }
|
||||
else {}
|
||||
}
|
||||
microVUf(void) mVU_IBEQ() {
|
||||
microVU* mVU = mVUx;
|
||||
mVUbranch = 2;
|
||||
mVUbranch = 3;
|
||||
if (!recPass) { mVUanalyzeBranch2<vuIndex>(_Fs_, _Ft_); }
|
||||
else {}
|
||||
else {
|
||||
if (memReadIs) MOV32MtoR(gprT1, (uptr)mVU->VIbackup[0]);
|
||||
else mVUallocVIa<vuIndex>(gprT1, _Fs_);
|
||||
if (memReadIt) XOR32MtoR(gprT1, (uptr)mVU->VIbackup[0]);
|
||||
else { mVUallocVIa<vuIndex>(gprT2, _Ft_); XOR32RtoR(gprT1, gprT2); }
|
||||
MOV32RtoM((uptr)mVU->branch, gprT1);
|
||||
}
|
||||
}
|
||||
microVUf(void) mVU_IBGEZ() {
|
||||
microVU* mVU = mVUx;
|
||||
mVUbranch = 2;
|
||||
mVUbranch = 4;
|
||||
if (!recPass) { mVUanalyzeBranch1<vuIndex>(_Fs_); }
|
||||
else {}
|
||||
else {
|
||||
if (memReadIs) MOV32MtoR(gprT1, (uptr)mVU->VIbackup[0]);
|
||||
else mVUallocVIa<vuIndex>(gprT1, _Fs_);
|
||||
//SHR32ItoR(gprT1, 15);
|
||||
MOV32RtoM((uptr)mVU->branch, gprT1);
|
||||
}
|
||||
}
|
||||
microVUf(void) mVU_IBGTZ() {
|
||||
microVU* mVU = mVUx;
|
||||
mVUbranch = 2;
|
||||
mVUbranch = 5;
|
||||
if (!recPass) { mVUanalyzeBranch1<vuIndex>(_Fs_); }
|
||||
else {}
|
||||
else {
|
||||
if (memReadIs) MOV32MtoR(gprT1, (uptr)mVU->VIbackup[0]);
|
||||
else mVUallocVIa<vuIndex>(gprT1, _Fs_);
|
||||
MOV32RtoM((uptr)mVU->branch, gprT1);
|
||||
}
|
||||
}
|
||||
microVUf(void) mVU_IBLEZ() {
|
||||
microVU* mVU = mVUx;
|
||||
mVUbranch = 2;
|
||||
mVUbranch = 6;
|
||||
if (!recPass) { mVUanalyzeBranch1<vuIndex>(_Fs_); }
|
||||
else {}
|
||||
else {
|
||||
if (memReadIs) MOV32MtoR(gprT1, (uptr)mVU->VIbackup[0]);
|
||||
else mVUallocVIa<vuIndex>(gprT1, _Fs_);
|
||||
MOV32RtoM((uptr)mVU->branch, gprT1);
|
||||
}
|
||||
}
|
||||
microVUf(void) mVU_IBLTZ() {
|
||||
microVU* mVU = mVUx;
|
||||
mVUbranch = 2;
|
||||
mVUbranch = 7;
|
||||
if (!recPass) { mVUanalyzeBranch1<vuIndex>(_Fs_); }
|
||||
else {}
|
||||
else {
|
||||
if (memReadIs) MOV32MtoR(gprT1, (uptr)mVU->VIbackup[0]);
|
||||
else mVUallocVIa<vuIndex>(gprT1, _Fs_);
|
||||
//SHR32ItoR(gprT1, 15);
|
||||
MOV32RtoM((uptr)mVU->branch, gprT1);
|
||||
}
|
||||
}
|
||||
microVUf(void) mVU_IBNE() {
|
||||
microVU* mVU = mVUx;
|
||||
mVUbranch = 2;
|
||||
mVUbranch = 8;
|
||||
if (!recPass) { mVUanalyzeBranch2<vuIndex>(_Fs_, _Ft_); }
|
||||
else {}
|
||||
else {
|
||||
if (memReadIs) MOV32MtoR(gprT1, (uptr)mVU->VIbackup[0]);
|
||||
else mVUallocVIa<vuIndex>(gprT1, _Fs_);
|
||||
if (memReadIt) XOR32MtoR(gprT1, (uptr)mVU->VIbackup[0]);
|
||||
else { mVUallocVIa<vuIndex>(gprT2, _Ft_); XOR32RtoR(gprT1, gprT2); }
|
||||
MOV32RtoM((uptr)mVU->branch, gprT1);
|
||||
}
|
||||
}
|
||||
microVUf(void) mVU_JR() {
|
||||
microVU* mVU = mVUx;
|
||||
mVUbranch = 3;
|
||||
mVUbranch = 9;
|
||||
if (!recPass) { mVUanalyzeBranch1<vuIndex>(_Fs_); }
|
||||
else {}
|
||||
}
|
||||
microVUf(void) mVU_JALR() {
|
||||
microVU* mVU = mVUx;
|
||||
mVUbranch = 3;
|
||||
mVUbranch = 10;
|
||||
if (!recPass) { mVUanalyzeBranch1<vuIndex>(_Fs_); analyzeVIreg2(_Ft_, 1); }
|
||||
else {}
|
||||
}
|
||||
|
||||
#endif //PCSX2_MICROVU
|
||||
|
|
|
@ -143,6 +143,7 @@ declareAllVariables
|
|||
#define mVUallocInfo mVU->prog.prog[mVU->prog.cur].allocInfo
|
||||
#define mVUbranch mVUallocInfo.branch
|
||||
#define mVUcycles mVUallocInfo.cycles
|
||||
#define mVUcount mVUallocInfo.count
|
||||
#define mVUstall mVUallocInfo.maxStall
|
||||
#define mVUregs mVUallocInfo.regs
|
||||
#define mVUregsTemp mVUallocInfo.regsTemp
|
||||
|
@ -153,6 +154,7 @@ declareAllVariables
|
|||
#define curI mVUcurProg.data[iPC]
|
||||
#define setCode() { mVU->code = curI; }
|
||||
#define incPC(x) { iPC = ((iPC + x) & (mVU->progSize-1)); setCode(); }
|
||||
#define incPC2(x) { iPC = ((iPC + x) & (mVU->progSize-1)); }
|
||||
#define incCycles(x) { mVUincCycles<vuIndex>(x); }
|
||||
|
||||
#define _isNOP (1<<0) // Skip Lower Instruction
|
||||
|
@ -181,6 +183,7 @@ declareAllVariables
|
|||
#define _memReadIt (1<<24) // Read If (VI reg) from memory (used by branches)
|
||||
#define _writesVI (1<<25) // Current Instruction writes to VI
|
||||
#define _swapOps (1<<26) // Runs Lower Instruction Before Upper Instruction
|
||||
//#define _isBranch2 (1<<27) // Cur Instruction is a Branch that writes VI regs (BAL/JALR)
|
||||
|
||||
#define isNOP (mVUinfo & (1<<0))
|
||||
#define isBranch (mVUinfo & (1<<1))
|
||||
|
@ -208,6 +211,7 @@ declareAllVariables
|
|||
#define memReadIt (mVUinfo & (1<<24))
|
||||
#define writesVI (mVUinfo & (1<<25))
|
||||
#define swapOps (mVUinfo & (1<<26))
|
||||
//#define isBranch2 (mVUinfo & (1<<27))
|
||||
|
||||
#define isMMX(_VIreg_) (_VIreg_ >= 1 && _VIreg_ <=9)
|
||||
#define mmVI(_VIreg_) (_VIreg_ - 1)
|
||||
|
@ -226,7 +230,7 @@ declareAllVariables
|
|||
#define mVUdebug1() {}
|
||||
#endif
|
||||
|
||||
#define mVUcachCheck(x) { \
|
||||
uptr diff = mVU->ptr - mVU->cache; \
|
||||
if (diff > x) { Console::Error("microVU Error: Program went over it's cache limit. Size = %x", params diff); } \
|
||||
#define mVUcachCheck(start, limit) { \
|
||||
uptr diff = mVU->ptr - start; \
|
||||
if (diff >= limit) { Console::Error("microVU Error: Program went over it's cache limit. Size = %x", params diff); } \
|
||||
}
|
||||
|
|
|
@ -251,7 +251,7 @@ microVUt(void) mVUaddrFix(int gprReg) {
|
|||
u8 *jmpA, *jmpB;
|
||||
CMP32ItoR(EAX, 0x400);
|
||||
jmpA = JL8(0); // if addr >= 0x4000, reads VU1's VF regs and VI regs
|
||||
AND32ItoR(EAX, 0x43f);
|
||||
AND32ItoR(EAX, 0x43f); // ToDo: theres a potential problem if VU0 overrides VU1's VF0/VI0 regs!
|
||||
jmpB = JMP8(0);
|
||||
x86SetJ8(jmpA);
|
||||
AND32ItoR(EAX, 0xff); // if addr < 0x4000, wrap around
|
||||
|
|
Loading…
Reference in New Issue