mirror of https://github.com/PCSX2/pcsx2.git
microVU:
- Cleaned up microVU_Compile - Added file microVU_Branch git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1621 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
ab010b2b4c
commit
18a12b10b0
|
@ -2076,6 +2076,10 @@
|
|||
RelativePath="..\..\x86\microVU_Analyze.inl"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\x86\microVU_Branch.inl"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\x86\microVU_Compile.inl"
|
||||
>
|
||||
|
|
|
@ -206,5 +206,6 @@ typedef void (__fastcall *mVUrecCall)(u32, u32);
|
|||
#include "microVU_Lower.inl"
|
||||
#include "microVU_Tables.inl"
|
||||
#include "microVU_Flags.inl"
|
||||
#include "microVU_Branch.inl"
|
||||
#include "microVU_Compile.inl"
|
||||
#include "microVU_Execute.inl"
|
||||
|
|
|
@ -0,0 +1,201 @@
|
|||
/* Pcsx2 - Pc Ps2 Emulator
|
||||
* Copyright (C) 2009 Pcsx2 Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
microVUt(void) mVUincCycles(mV, int x);
|
||||
microVUr(void*) mVUcompile(microVU* mVU, u32 startPC, uptr pState);
|
||||
|
||||
#define blockCreate(addr) { if (!mVUblocks[addr]) mVUblocks[addr] = new microBlockManager(); }
|
||||
#define sI ((mVUpBlock->pState.needExactMatch & 0x000f) ? 0 : ((mVUpBlock->pState.flags >> 0) & 3))
|
||||
#define cI ((mVUpBlock->pState.needExactMatch & 0x0f00) ? 0 : ((mVUpBlock->pState.flags >> 2) & 3))
|
||||
|
||||
microVUt(void) mVUendProgram(mV, microFlagCycles* mFC, int isEbit) {
|
||||
|
||||
int fStatus = (isEbit) ? findFlagInst(mFC->xStatus, 0x7fffffff) : sI;
|
||||
int fMac = (isEbit) ? findFlagInst(mFC->xMac, 0x7fffffff) : 0;
|
||||
int fClip = (isEbit) ? findFlagInst(mFC->xClip, 0x7fffffff) : cI;
|
||||
int qInst = 0;
|
||||
int pInst = 0;
|
||||
mVU->regAlloc->flushAll();
|
||||
|
||||
if (isEbit) {
|
||||
mVUprint("mVUcompile ebit");
|
||||
memset(&mVUinfo, 0, sizeof(mVUinfo));
|
||||
memset(&mVUregsTemp, 0, sizeof(mVUregsTemp));
|
||||
mVUincCycles(mVU, 100); // Ensures Valid P/Q instances (And sets all cycle data to 0)
|
||||
mVUcycles -= 100;
|
||||
qInst = mVU->q;
|
||||
pInst = mVU->p;
|
||||
if (mVUinfo.doDivFlag) {
|
||||
sFLAG.doFlag = 1;
|
||||
sFLAG.write = fStatus;
|
||||
mVUdivSet(mVU);
|
||||
}
|
||||
if (mVUinfo.doXGKICK) { mVU_XGKICK_DELAY(mVU, 1); }
|
||||
}
|
||||
|
||||
// Save P/Q Regs
|
||||
if (qInst) { SSE2_PSHUFD_XMM_to_XMM(xmmPQ, xmmPQ, 0xe5); }
|
||||
SSE_MOVSS_XMM_to_M32((uptr)&mVU->regs->VI[REG_Q].UL, xmmPQ);
|
||||
if (isVU1) {
|
||||
SSE2_PSHUFD_XMM_to_XMM(xmmPQ, xmmPQ, pInst ? 3 : 2);
|
||||
SSE_MOVSS_XMM_to_M32((uptr)&mVU->regs->VI[REG_P].UL, xmmPQ);
|
||||
}
|
||||
|
||||
// Save Flag Instances
|
||||
mVUallocSFLAGc(gprT1, gprT2, fStatus);
|
||||
MOV32RtoM((uptr)&mVU->regs->VI[REG_STATUS_FLAG].UL, gprT1);
|
||||
mVUallocMFLAGa(mVU, gprT1, fMac);
|
||||
mVUallocCFLAGa(mVU, gprT2, fClip);
|
||||
MOV32RtoM((uptr)&mVU->regs->VI[REG_MAC_FLAG].UL, gprT1);
|
||||
MOV32RtoM((uptr)&mVU->regs->VI[REG_CLIP_FLAG].UL, gprT2);
|
||||
|
||||
if (isEbit || isVU1) { // Clear 'is busy' Flags
|
||||
AND32ItoM((uptr)&VU0.VI[REG_VPU_STAT].UL, (isVU1 ? ~0x100 : ~0x001)); // VBS0/VBS1 flag
|
||||
AND32ItoM((uptr)&mVU->regs->vifRegs->stat, ~0x4); // Clear VU 'is busy' signal for vif
|
||||
}
|
||||
|
||||
if (isEbit != 2) { // Save PC, and Jump to Exit Point
|
||||
MOV32ItoM((uptr)&mVU->regs->VI[REG_TPC].UL, xPC);
|
||||
JMP32((uptr)mVU->exitFunct - ((uptr)x86Ptr + 5));
|
||||
}
|
||||
}
|
||||
|
||||
// Recompiles Code for Proper Flags and Q/P regs on Block Linkings
|
||||
microVUt(void) mVUsetupBranch(mV, microFlagCycles& mFC) {
|
||||
mVUprint("mVUsetupBranch");
|
||||
|
||||
// Flush Allocated Regs
|
||||
mVU->regAlloc->flushAll();
|
||||
|
||||
// Shuffle Flag Instances
|
||||
mVUsetupFlags(mVU, mFC);
|
||||
|
||||
// Shuffle P/Q regs since every block starts at instance #0
|
||||
if (mVU->p || mVU->q) { SSE2_PSHUFD_XMM_to_XMM(xmmPQ, xmmPQ, shufflePQ); }
|
||||
}
|
||||
|
||||
void condBranch(mV, microFlagCycles& mFC, microBlock* &pBlock, int JMPcc) {
|
||||
using namespace x86Emitter;
|
||||
mVUsetupBranch(mVU, mFC);
|
||||
xCMP(ptr16[&mVU->branch], 0);
|
||||
if (mVUup.eBit) { // Conditional Branch With E-Bit Set
|
||||
mVUendProgram(mVU, &mFC, 2);
|
||||
xForwardJump8 eJMP((JccComparisonType)JMPcc);
|
||||
incPC(1); // Set PC to First instruction of Non-Taken Side
|
||||
xMOV(ptr32[&mVU->regs->VI[REG_TPC].UL], xPC);
|
||||
xJMP(mVU->exitFunct);
|
||||
eJMP.SetTarget();
|
||||
incPC(-4); // Go Back to Branch Opcode to get branchAddr
|
||||
iPC = branchAddr/4;
|
||||
xMOV(ptr32[&mVU->regs->VI[REG_TPC].UL], xPC);
|
||||
xJMP(mVU->exitFunct);
|
||||
return;
|
||||
}
|
||||
else { // Normal Conditional Branch
|
||||
microBlock* bBlock;
|
||||
incPC2(1); // Check if Branch Non-Taken Side has already been recompiled
|
||||
blockCreate(iPC/2);
|
||||
bBlock = mVUblocks[iPC/2]->search((microRegInfo*)&mVUregs);
|
||||
incPC2(-1);
|
||||
if (bBlock) { // Branch non-taken has already been compiled
|
||||
xJcc( xInvertCond((JccComparisonType)JMPcc), bBlock->x86ptrStart );
|
||||
|
||||
// Check if branch-block has already been compiled
|
||||
incPC(-3); // Go back to branch opcode (to get branch imm addr)
|
||||
blockCreate(branchAddr/8);
|
||||
pBlock = mVUblocks[branchAddr/8]->search((microRegInfo*)&mVUregs);
|
||||
if (pBlock) { xJMP( pBlock->x86ptrStart ); }
|
||||
else { mVUblockFetch(mVU, branchAddr, (uptr)&mVUregs); }
|
||||
}
|
||||
else {
|
||||
s32* ajmp = xJcc32((JccComparisonType)JMPcc);
|
||||
uptr jumpAddr;
|
||||
u32 bPC = iPC; // mVUcompile can modify iPC and mVUregs so back them up
|
||||
memcpy_fast(&pBlock->pStateEnd, &mVUregs, sizeof(microRegInfo));
|
||||
|
||||
incPC2(1); // Get PC for branch not-taken
|
||||
mVUcompile(mVU, xPC, (uptr)&mVUregs);
|
||||
|
||||
iPC = bPC;
|
||||
incPC(-3); // Go back to branch opcode (to get branch imm addr)
|
||||
jumpAddr = (uptr)mVUblockFetch(mVU, branchAddr, (uptr)&pBlock->pStateEnd);
|
||||
*ajmp = (jumpAddr - ((uptr)ajmp + 4));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void normBranch(mV, microFlagCycles& mFC) {
|
||||
using namespace x86Emitter;
|
||||
microBlock* pBlock;
|
||||
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; }
|
||||
mVUsetupBranch(mVU, mFC);
|
||||
|
||||
// Check if branch-block has already been compiled
|
||||
blockCreate(branchAddr/8);
|
||||
pBlock = mVUblocks[branchAddr/8]->search((microRegInfo*)&mVUregs);
|
||||
if (pBlock) { xJMP(pBlock->x86ptrStart); }
|
||||
else { mVUcompile(mVU, branchAddr, (uptr)&mVUregs); }
|
||||
}
|
||||
|
||||
void normJump(mV, microFlagCycles& mFC, microBlock* &pBlock) {
|
||||
using namespace x86Emitter;
|
||||
mVUprint("mVUcompile JR/JALR");
|
||||
incPC(-3); // Go back to jump opcode
|
||||
|
||||
if (mVUlow.constJump.isValid) {
|
||||
if (mVUup.eBit) { // E-bit Jump
|
||||
iPC = (mVUlow.constJump.regValue*2)&(mVU->progSize-1);
|
||||
mVUendProgram(mVU, &mFC, 1);
|
||||
}
|
||||
else {
|
||||
int jumpAddr = (mVUlow.constJump.regValue*8)&(mVU->microMemSize-8);
|
||||
mVUsetupBranch(mVU, mFC);
|
||||
// Check if jump-to-block has already been compiled
|
||||
blockCreate(jumpAddr/8);
|
||||
pBlock = mVUblocks[jumpAddr/8]->search((microRegInfo*)&mVUregs);
|
||||
if (pBlock) { xJMP(pBlock->x86ptrStart); }
|
||||
else { mVUcompile(mVU, jumpAddr, (uptr)&mVUregs); }
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (mVUup.eBit) { // E-bit Jump
|
||||
mVUendProgram(mVU, &mFC, 2);
|
||||
MOV32MtoR(gprT1, (uptr)&mVU->branch);
|
||||
MOV32RtoM((uptr)&mVU->regs->VI[REG_TPC].UL, gprT1);
|
||||
xJMP(mVU->exitFunct);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy_fast(&pBlock->pStateEnd, &mVUregs, sizeof(microRegInfo));
|
||||
mVUsetupBranch(mVU, mFC);
|
||||
|
||||
mVUbackupRegs(mVU);
|
||||
MOV32MtoR(gprT2, (uptr)&mVU->branch); // Get startPC (ECX first argument for __fastcall)
|
||||
MOV32ItoR(gprR, (u32)&pBlock->pStateEnd); // Get pState (EDX second 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
|
||||
}
|
|
@ -22,23 +22,6 @@
|
|||
// Helper Macros
|
||||
//------------------------------------------------------------------
|
||||
|
||||
#define branchCase(JMPcond) branchCaseFunct(mVU, bBlock, xStatus, xMac, xClip, xCycles, ajmp, JMPcond); break
|
||||
|
||||
#define branchWarning() { \
|
||||
if (mVUbranch) { \
|
||||
Console::Error("microVU%d Warning: Branch in E-bit/Branch delay slot! [%04x]", params mVU->index, xPC); \
|
||||
mVUlow.isNOP = 1; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define startLoop() { \
|
||||
if (curI & _Mbit_) { Console::Status("microVU%d: M-bit set!", params getIndex); } \
|
||||
if (curI & _Dbit_) { DevCon::Status ("microVU%d: D-bit set!", params getIndex); } \
|
||||
if (curI & _Tbit_) { DevCon::Status ("microVU%d: T-bit set!", params getIndex); } \
|
||||
memset(&mVUinfo, 0, sizeof(mVUinfo)); \
|
||||
memset(&mVUregsTemp, 0, sizeof(mVUregsTemp)); \
|
||||
}
|
||||
|
||||
#define calcCycles(reg, x) { reg = ((reg > x) ? (reg - x) : 0); }
|
||||
#define optimizeReg(rState) { rState = (rState==1) ? 0 : rState; }
|
||||
#define tCycles(dest, src) { dest = aMax(dest, src); }
|
||||
|
@ -46,52 +29,11 @@
|
|||
#define incQ() { mVU->q = (mVU->q+1) & 1; }
|
||||
#define doUpperOp() { mVUopU(mVU, 1); mVUdivSet(mVU); }
|
||||
#define doLowerOp() { incPC(-1); mVUopL(mVU, 1); incPC(1); }
|
||||
#define blockCreate(addr) { if (!mVUblocks[addr]) mVUblocks[addr] = new microBlockManager(); }
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Helper Functions
|
||||
//------------------------------------------------------------------
|
||||
|
||||
microVUt(void) doSwapOp(mV) {
|
||||
if (mVUinfo.backupVF && !mVUlow.noWriteVF) {
|
||||
DevCon::Status("microVU%d: Backing Up VF Reg [%04x]", params getIndex, xPC);
|
||||
int t1 = mVU->regAlloc->allocReg(mVUlow.VF_write.reg);
|
||||
int t2 = mVU->regAlloc->allocReg();
|
||||
SSE_MOVAPS_XMM_to_XMM(t2, t1);
|
||||
mVU->regAlloc->clearNeeded(t1);
|
||||
mVUopL(mVU, 1);
|
||||
t1 = mVU->regAlloc->allocReg(mVUlow.VF_write.reg, mVUlow.VF_write.reg, 0xf, 0);
|
||||
SSE_XORPS_XMM_to_XMM(t2, t1);
|
||||
SSE_XORPS_XMM_to_XMM(t1, t2);
|
||||
SSE_XORPS_XMM_to_XMM(t2, t1);
|
||||
mVU->regAlloc->clearNeeded(t1);
|
||||
incPC(1);
|
||||
doUpperOp();
|
||||
t1 = mVU->regAlloc->allocReg(-1, mVUlow.VF_write.reg, 0xf);
|
||||
SSE_MOVAPS_XMM_to_XMM(t1, t2);
|
||||
mVU->regAlloc->clearNeeded(t1);
|
||||
mVU->regAlloc->clearNeeded(t2);
|
||||
}
|
||||
else { mVUopL(mVU, 1); incPC(1); doUpperOp(); }
|
||||
}
|
||||
|
||||
microVUt(void) doIbit(microVU* mVU) {
|
||||
if (mVUup.iBit) {
|
||||
incPC(-1);
|
||||
u32 tempI;
|
||||
mVU->regAlloc->clearRegVF(33);
|
||||
|
||||
if (CHECK_VU_OVERFLOW && ((curI & 0x7fffffff) >= 0x7f800000)) {
|
||||
Console::Status("microVU%d: Clamping I Reg", params mVU->index);
|
||||
tempI = (0x80000000 & curI) | 0x7f7fffff; // Clamp I Reg
|
||||
}
|
||||
else tempI = curI;
|
||||
|
||||
MOV32ItoM((uptr)&mVU->regs->VI[REG_I].UL, tempI);
|
||||
incPC(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Used by mVUsetupRange
|
||||
microVUt(void) mVUcheckIsSame(mV) {
|
||||
|
||||
|
@ -167,6 +109,61 @@ microVUt(void) mVUsetupRange(mV, s32 pc, bool isStartPC) {
|
|||
}
|
||||
}
|
||||
|
||||
microVUt(void) startLoop(mV) {
|
||||
if (curI & _Mbit_) { Console::Status("microVU%d: M-bit set!", params getIndex); }
|
||||
if (curI & _Dbit_) { DevCon::Status ("microVU%d: D-bit set!", params getIndex); }
|
||||
if (curI & _Tbit_) { DevCon::Status ("microVU%d: T-bit set!", params getIndex); }
|
||||
memset(&mVUinfo, 0, sizeof(mVUinfo));
|
||||
memset(&mVUregsTemp, 0, sizeof(mVUregsTemp));
|
||||
}
|
||||
|
||||
microVUt(void) doIbit(mV) {
|
||||
if (mVUup.iBit) {
|
||||
incPC(-1);
|
||||
u32 tempI;
|
||||
mVU->regAlloc->clearRegVF(33);
|
||||
|
||||
if (CHECK_VU_OVERFLOW && ((curI & 0x7fffffff) >= 0x7f800000)) {
|
||||
Console::Status("microVU%d: Clamping I Reg", params mVU->index);
|
||||
tempI = (0x80000000 & curI) | 0x7f7fffff; // Clamp I Reg
|
||||
}
|
||||
else tempI = curI;
|
||||
|
||||
MOV32ItoM((uptr)&mVU->regs->VI[REG_I].UL, tempI);
|
||||
incPC(1);
|
||||
}
|
||||
}
|
||||
|
||||
microVUt(void) doSwapOp(mV) {
|
||||
if (mVUinfo.backupVF && !mVUlow.noWriteVF) {
|
||||
DevCon::Status("microVU%d: Backing Up VF Reg [%04x]", params getIndex, xPC);
|
||||
int t1 = mVU->regAlloc->allocReg(mVUlow.VF_write.reg);
|
||||
int t2 = mVU->regAlloc->allocReg();
|
||||
SSE_MOVAPS_XMM_to_XMM(t2, t1);
|
||||
mVU->regAlloc->clearNeeded(t1);
|
||||
mVUopL(mVU, 1);
|
||||
t1 = mVU->regAlloc->allocReg(mVUlow.VF_write.reg, mVUlow.VF_write.reg, 0xf, 0);
|
||||
SSE_XORPS_XMM_to_XMM(t2, t1);
|
||||
SSE_XORPS_XMM_to_XMM(t1, t2);
|
||||
SSE_XORPS_XMM_to_XMM(t2, t1);
|
||||
mVU->regAlloc->clearNeeded(t1);
|
||||
incPC(1);
|
||||
doUpperOp();
|
||||
t1 = mVU->regAlloc->allocReg(-1, mVUlow.VF_write.reg, 0xf);
|
||||
SSE_MOVAPS_XMM_to_XMM(t1, t2);
|
||||
mVU->regAlloc->clearNeeded(t1);
|
||||
mVU->regAlloc->clearNeeded(t2);
|
||||
}
|
||||
else { mVUopL(mVU, 1); incPC(1); doUpperOp(); }
|
||||
}
|
||||
|
||||
microVUt(void) branchWarning(mV) {
|
||||
if (mVUbranch) {
|
||||
Console::Error("microVU%d Warning: Branch in E-bit/Branch delay slot! [%04x]", params mVU->index, xPC);
|
||||
mVUlow.isNOP = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Optimizes the End Pipeline State Removing Unnecessary Info
|
||||
microVUt(void) mVUoptimizePipeState(mV) {
|
||||
for (int i = 0; i < 32; i++) {
|
||||
|
@ -183,20 +180,6 @@ microVUt(void) mVUoptimizePipeState(mV) {
|
|||
mVUregs.r = 0; // There are no stalls on the R-reg, so its Safe to discard info
|
||||
}
|
||||
|
||||
// Recompiles Code for Proper Flags and Q/P regs on Block Linkings
|
||||
microVUt(void) mVUsetupBranch(mV, int* xStatus, int* xMac, int* xClip, int xCycles) {
|
||||
mVUprint("mVUsetupBranch");
|
||||
|
||||
// Flush Allocated Regs
|
||||
mVU->regAlloc->flushAll();
|
||||
|
||||
// Shuffle Flag Instances
|
||||
mVUsetupFlags(mVU, xStatus, xMac, xClip, xCycles);
|
||||
|
||||
// Shuffle P/Q regs since every block starts at instance #0
|
||||
if (mVU->p || mVU->q) { SSE2_PSHUFD_XMM_to_XMM(xmmPQ, xmmPQ, shufflePQ); }
|
||||
}
|
||||
|
||||
microVUt(void) mVUincCycles(mV, int x) {
|
||||
mVUcycles += x;
|
||||
for (int z = 31; z > 0; z--) {
|
||||
|
@ -269,87 +252,6 @@ microVUt(void) mVUsetCycles(mV) {
|
|||
tCycles(mVUregs.xgkick, mVUregsTemp.xgkick);
|
||||
}
|
||||
|
||||
#define sI ((mVUpBlock->pState.needExactMatch & 0x000f) ? 0 : ((mVUpBlock->pState.flags >> 0) & 3))
|
||||
#define cI ((mVUpBlock->pState.needExactMatch & 0x0f00) ? 0 : ((mVUpBlock->pState.flags >> 2) & 3))
|
||||
|
||||
microVUt(void) mVUendProgram(mV, int isEbit, int* xStatus, int* xMac, int* xClip) {
|
||||
|
||||
int fStatus = (isEbit) ? findFlagInst(xStatus, 0x7fffffff) : sI;
|
||||
int fMac = (isEbit) ? findFlagInst(xMac, 0x7fffffff) : 0;
|
||||
int fClip = (isEbit) ? findFlagInst(xClip, 0x7fffffff) : cI;
|
||||
int qInst = 0;
|
||||
int pInst = 0;
|
||||
mVU->regAlloc->flushAll();
|
||||
|
||||
if (isEbit) {
|
||||
mVUprint("mVUcompile ebit");
|
||||
memset(&mVUinfo, 0, sizeof(mVUinfo));
|
||||
memset(&mVUregsTemp, 0, sizeof(mVUregsTemp));
|
||||
mVUincCycles(mVU, 100); // Ensures Valid P/Q instances (And sets all cycle data to 0)
|
||||
mVUcycles -= 100;
|
||||
qInst = mVU->q;
|
||||
pInst = mVU->p;
|
||||
if (mVUinfo.doDivFlag) {
|
||||
sFLAG.doFlag = 1;
|
||||
sFLAG.write = fStatus;
|
||||
mVUdivSet(mVU);
|
||||
}
|
||||
if (mVUinfo.doXGKICK) { mVU_XGKICK_DELAY(mVU, 1); }
|
||||
}
|
||||
|
||||
// Save P/Q Regs
|
||||
if (qInst) { SSE2_PSHUFD_XMM_to_XMM(xmmPQ, xmmPQ, 0xe5); }
|
||||
SSE_MOVSS_XMM_to_M32((uptr)&mVU->regs->VI[REG_Q].UL, xmmPQ);
|
||||
if (isVU1) {
|
||||
SSE2_PSHUFD_XMM_to_XMM(xmmPQ, xmmPQ, pInst ? 3 : 2);
|
||||
SSE_MOVSS_XMM_to_M32((uptr)&mVU->regs->VI[REG_P].UL, xmmPQ);
|
||||
}
|
||||
|
||||
// Save Flag Instances
|
||||
mVUallocSFLAGc(gprT1, gprT2, fStatus);
|
||||
MOV32RtoM((uptr)&mVU->regs->VI[REG_STATUS_FLAG].UL, gprT1);
|
||||
mVUallocMFLAGa(mVU, gprT1, fMac);
|
||||
mVUallocCFLAGa(mVU, gprT2, fClip);
|
||||
MOV32RtoM((uptr)&mVU->regs->VI[REG_MAC_FLAG].UL, gprT1);
|
||||
MOV32RtoM((uptr)&mVU->regs->VI[REG_CLIP_FLAG].UL, gprT2);
|
||||
|
||||
if (isEbit || isVU1) { // Clear 'is busy' Flags
|
||||
AND32ItoM((uptr)&VU0.VI[REG_VPU_STAT].UL, (isVU1 ? ~0x100 : ~0x001)); // VBS0/VBS1 flag
|
||||
AND32ItoM((uptr)&mVU->regs->vifRegs->stat, ~0x4); // Clear VU 'is busy' signal for vif
|
||||
}
|
||||
|
||||
if (isEbit != 2) { // Save PC, and Jump to Exit Point
|
||||
MOV32ItoM((uptr)&mVU->regs->VI[REG_TPC].UL, xPC);
|
||||
JMP32((uptr)mVU->exitFunct - ((uptr)x86Ptr + 5));
|
||||
}
|
||||
}
|
||||
|
||||
void branchCaseFunct(mV, microBlock* &bBlock, int* xStatus, int* xMac, int* xClip, int &xCycles, s32* &ajmp, int JMPcc) {
|
||||
using namespace x86Emitter;
|
||||
mVUsetupBranch(mVU, xStatus, xMac, xClip, xCycles);
|
||||
xCMP(ptr16[&mVU->branch], 0);
|
||||
if (mVUup.eBit) { // Conditional Branch With E-Bit Set
|
||||
mVUendProgram(mVU, 2, xStatus, xMac, xClip);
|
||||
xForwardJump8 eJMP((JccComparisonType)JMPcc);
|
||||
incPC(1); // Set PC to First instruction of Non-Taken Side
|
||||
xMOV(ptr32[&mVU->regs->VI[REG_TPC].UL], xPC);
|
||||
xJMP(mVU->exitFunct);
|
||||
eJMP.SetTarget();
|
||||
incPC(-4); // Go Back to Branch Opcode to get branchAddr
|
||||
iPC = branchAddr/4;
|
||||
xMOV(ptr32[&mVU->regs->VI[REG_TPC].UL], xPC);
|
||||
xJMP(mVU->exitFunct);
|
||||
}
|
||||
else { // Normal Conditional Branch
|
||||
incPC2(1); // Check if Branch Non-Taken Side has already been recompiled
|
||||
blockCreate(iPC/2);
|
||||
bBlock = mVUblocks[iPC/2]->search((microRegInfo*)&mVUregs);
|
||||
incPC2(-1);
|
||||
if (bBlock) { xJcc( xInvertCond((JccComparisonType)JMPcc), bBlock->x86ptrStart ); }
|
||||
else { ajmp = xJcc32((JccComparisonType)JMPcc); }
|
||||
}
|
||||
}
|
||||
|
||||
void __fastcall mVUwarning0(u32 PC) { Console::Error("microVU0 Warning: Exiting from Possible Infinite Loop [%04x]", params PC); }
|
||||
void __fastcall mVUwarning1(u32 PC) { Console::Error("microVU1 Warning: Exiting from Possible Infinite Loop [%04x]", params PC); }
|
||||
void __fastcall mVUprintPC1(u32 PC) { Console::Write("Block PC [%04x] ", params PC); }
|
||||
|
@ -365,12 +267,13 @@ microVUt(void) mVUtestCycles(mV) {
|
|||
if (isVU1) CALLFunc((uptr)mVUwarning1);
|
||||
//else CALLFunc((uptr)mVUwarning0); // VU0 is allowed early exit for COP2 Interlock Simulation
|
||||
MOV32ItoR(gprR, Roffset); // Restore gprR
|
||||
mVUendProgram(mVU, 0, NULL, NULL, NULL);
|
||||
mVUendProgram(mVU, NULL, 0);
|
||||
x86SetJ32(jmp32);
|
||||
}
|
||||
}
|
||||
|
||||
microVUt(void) mVUinitConstValues(mV) {
|
||||
// Initialize VI Constants (vi15 propagates through blocks)
|
||||
microVUt(void) mVUinitConstValues(microVU* mVU) {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
mVUconstReg[i].isValid = 0;
|
||||
mVUconstReg[i].regValue = 0;
|
||||
|
@ -379,6 +282,24 @@ microVUt(void) mVUinitConstValues(mV) {
|
|||
mVUconstReg[15].regValue = mVUconstReg[15].isValid ? (mVUregs.vi15&0xffff) : 0;
|
||||
}
|
||||
|
||||
// Initialize Variables
|
||||
microVUt(void) mVUinitFirstPass(microVU* mVU, microBlock* &pBlock, uptr pState, u8* thisPtr) {
|
||||
mVUstartPC = iPC; // Block Start PC
|
||||
mVUbranch = 0; // Branch Type
|
||||
mVUcount = 0; // Number of instructions ran
|
||||
mVUcycles = 0; // 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
|
||||
memcpy_fast(&mVUregs, (microRegInfo*)pState, sizeof(microRegInfo)); // Loads up Pipeline State Info
|
||||
mVUblock.x86ptrStart = thisPtr;
|
||||
pBlock = mVUblocks[mVUstartPC/2]->add(&mVUblock); // Add this block to block manager
|
||||
mVUpBlock = pBlock;
|
||||
mVUregs.flags = 0;
|
||||
mVUflagInfo = 0;
|
||||
mVUsFlagHack = CHECK_VU_FLAGHACK;
|
||||
mVUinitConstValues(mVU);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Recompiler
|
||||
//------------------------------------------------------------------
|
||||
|
@ -386,38 +307,20 @@ microVUt(void) mVUinitConstValues(mV) {
|
|||
microVUr(void*) mVUcompile(microVU* mVU, u32 startPC, uptr pState) {
|
||||
|
||||
using namespace x86Emitter;
|
||||
microBlock* pBlock = NULL;
|
||||
u8* thisPtr = x86Ptr;
|
||||
const u32 endCount = (mVU->microMemSize / 8) - 1;
|
||||
|
||||
// Setup Program Bounds/Range
|
||||
mVUsetupRange(mVU, startPC, 1);
|
||||
|
||||
// Reset regAlloc
|
||||
mVU->regAlloc->reset();
|
||||
microFlagCycles mFC;
|
||||
microBlock* pBlock = NULL;
|
||||
u8* thisPtr = x86Ptr;
|
||||
const u32 endCount = (mVU->microMemSize / 8) - 1;
|
||||
|
||||
// First Pass
|
||||
iPC = startPC / 4;
|
||||
setCode();
|
||||
mVUbranch = 0;
|
||||
mVUstartPC = iPC;
|
||||
mVUcount = 0;
|
||||
mVUcycles = 0; // 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
|
||||
memcpy_fast(&mVUregs, (microRegInfo*)pState, sizeof(microRegInfo)); // Loads up Pipeline State Info
|
||||
mVUblock.x86ptrStart = thisPtr;
|
||||
pBlock = mVUblocks[startPC/8]->add(&mVUblock); // Add this block to block manager
|
||||
mVUpBlock = pBlock;
|
||||
mVUregs.flags = 0;
|
||||
mVUflagInfo = 0;
|
||||
mVUsFlagHack = CHECK_VU_FLAGHACK;
|
||||
|
||||
mVUinitConstValues(mVU);
|
||||
|
||||
mVUsetupRange(mVU, startPC, 1); // Setup Program Bounds/Range
|
||||
mVU->regAlloc->reset(); // Reset regAlloc
|
||||
mVUinitFirstPass(mVU, pBlock, pState, thisPtr);
|
||||
|
||||
for (int branch = 0; mVUcount < endCount; mVUcount++) {
|
||||
incPC(1);
|
||||
startLoop();
|
||||
startLoop(mVU);
|
||||
mVUincCycles(mVU, 1);
|
||||
mVUopU(mVU, 0);
|
||||
if (curI & _Ebit_) { branch = 1; mVUup.eBit = 1; }
|
||||
|
@ -430,19 +333,16 @@ microVUr(void*) mVUcompile(microVU* mVU, u32 startPC, uptr pState) {
|
|||
mVUinfo.writeQ = !mVU->q;
|
||||
mVUinfo.readP = mVU->p;
|
||||
mVUinfo.writeP = !mVU->p;
|
||||
if (branch >= 2) { mVUinfo.isEOB = 1; if (branch == 3) { mVUinfo.isBdelay = 1; } mVUcount++; branchWarning(); break; }
|
||||
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); branch = 3; mVUbranch = 0; }
|
||||
incPC(1);
|
||||
}
|
||||
|
||||
// Sets Up Flag instances
|
||||
int xStatus[4], xMac[4], xClip[4];
|
||||
int xCycles = mVUsetFlags(mVU, xStatus, xMac, xClip);
|
||||
|
||||
// Fix up vi15 const info for propagation through blocks
|
||||
mVUregs.vi15 = (mVUconstReg[15].isValid && !CHECK_VU_CONSTHACK) ? ((1<<31) | (mVUconstReg[15].regValue&0xffff)) : 0;
|
||||
|
||||
|
||||
mVUsetFlags(mVU, mFC); // Sets Up Flag instances
|
||||
mVUoptimizePipeState(mVU); // Optimize the End Pipeline State for nicer Block Linking
|
||||
mVUtestCycles(mVU); // Update VU Cycles and Exit Early if Necessary
|
||||
|
||||
|
@ -450,8 +350,8 @@ microVUr(void*) mVUcompile(microVU* mVU, u32 startPC, uptr pState) {
|
|||
iPC = mVUstartPC;
|
||||
setCode();
|
||||
mVUbranch = 0;
|
||||
uint x;
|
||||
for (x = 0; x < endCount; x++) {
|
||||
u32 x = 0;
|
||||
for (; x < endCount; x++) {
|
||||
if (mVUinfo.isEOB) { x = 0xffff; }
|
||||
if (mVUup.mBit) { OR32ItoM((uptr)&mVU->regs->flags, VUFLAG_MFLAGSET); }
|
||||
if (mVUlow.isNOP) { incPC(1); doUpperOp(); doIbit(mVU); }
|
||||
|
@ -459,111 +359,27 @@ 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 (!mVUinfo.isBdelay) { incPC(1); }
|
||||
else {
|
||||
microBlock* bBlock = NULL;
|
||||
s32* ajmp = 0;
|
||||
mVUsetupRange(mVU, xPC, 0);
|
||||
mVUdebugNOW(1);
|
||||
|
||||
switch (mVUbranch) {
|
||||
case 3: branchCase(Jcc_Equal); // IBEQ
|
||||
case 4: branchCase(Jcc_GreaterOrEqual); // IBGEZ
|
||||
case 5: branchCase(Jcc_Greater); // IBGTZ
|
||||
case 6: branchCase(Jcc_LessOrEqual); // IBLEQ
|
||||
case 7: branchCase(Jcc_Less); // IBLTZ
|
||||
case 8: branchCase(Jcc_NotEqual); // IBNEQ
|
||||
case 1: case 2: // B/BAL
|
||||
|
||||
mVUprint("mVUcompile B/BAL");
|
||||
incPC(-3); // Go back to branch opcode (to get branch imm addr)
|
||||
|
||||
if (mVUup.eBit) { iPC = branchAddr/4; mVUendProgram(mVU, 1, xStatus, xMac, xClip); } // E-bit Branch
|
||||
mVUsetupBranch(mVU, xStatus, xMac, xClip, xCycles);
|
||||
|
||||
// Check if branch-block has already been compiled
|
||||
blockCreate(branchAddr/8);
|
||||
pBlock = mVUblocks[branchAddr/8]->search((microRegInfo*)&mVUregs);
|
||||
if (pBlock) { xJMP(pBlock->x86ptrStart); }
|
||||
else { mVUcompile(mVU, branchAddr, (uptr)&mVUregs); }
|
||||
return thisPtr;
|
||||
case 9: case 10: // JR/JALR
|
||||
|
||||
mVUprint("mVUcompile JR/JALR");
|
||||
incPC(-3); // Go back to jump opcode
|
||||
|
||||
if (mVUlow.constJump.isValid) {
|
||||
if (mVUup.eBit) { // E-bit Jump
|
||||
iPC = (mVUlow.constJump.regValue*2)&(mVU->progSize-1);
|
||||
mVUendProgram(mVU, 1, xStatus, xMac, xClip);
|
||||
}
|
||||
else {
|
||||
int jumpAddr = (mVUlow.constJump.regValue*8)&(mVU->microMemSize-8);
|
||||
mVUsetupBranch(mVU, xStatus, xMac, xClip, xCycles);
|
||||
// Check if jump-to-block has already been compiled
|
||||
blockCreate(jumpAddr/8);
|
||||
pBlock = mVUblocks[jumpAddr/8]->search((microRegInfo*)&mVUregs);
|
||||
if (pBlock) { xJMP(pBlock->x86ptrStart); }
|
||||
else { mVUcompile(mVU, jumpAddr, (uptr)&mVUregs); }
|
||||
}
|
||||
return thisPtr;
|
||||
}
|
||||
|
||||
if (mVUup.eBit) { // E-bit Jump
|
||||
mVUendProgram(mVU, 2, xStatus, xMac, xClip);
|
||||
MOV32MtoR(gprT1, (uptr)&mVU->branch);
|
||||
MOV32RtoM((uptr)&mVU->regs->VI[REG_TPC].UL, gprT1);
|
||||
xJMP(mVU->exitFunct);
|
||||
return thisPtr;
|
||||
}
|
||||
|
||||
memcpy_fast(&pBlock->pStateEnd, &mVUregs, sizeof(microRegInfo));
|
||||
mVUsetupBranch(mVU, xStatus, xMac, xClip, xCycles);
|
||||
|
||||
mVUbackupRegs(mVU);
|
||||
MOV32MtoR(gprT2, (uptr)&mVU->branch); // Get startPC (ECX first argument for __fastcall)
|
||||
MOV32ItoR(gprR, (u32)&pBlock->pStateEnd); // Get pState (EDX second 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
|
||||
return thisPtr;
|
||||
case 3: condBranch(mVU, mFC, pBlock, Jcc_Equal); return thisPtr; // IBEQ
|
||||
case 4: condBranch(mVU, mFC, pBlock, Jcc_GreaterOrEqual); return thisPtr; // IBGEZ
|
||||
case 5: condBranch(mVU, mFC, pBlock, Jcc_Greater); return thisPtr; // IBGTZ
|
||||
case 6: condBranch(mVU, mFC, pBlock, Jcc_LessOrEqual); return thisPtr; // IBLEQ
|
||||
case 7: condBranch(mVU, mFC, pBlock, Jcc_Less); return thisPtr; // IBLTZ
|
||||
case 8: condBranch(mVU, mFC, pBlock, Jcc_NotEqual); return thisPtr; // IBNEQ
|
||||
case 1: case 2: normBranch(mVU, mFC); return thisPtr; // B/BAL
|
||||
case 9: case 10: normJump (mVU, mFC, pBlock); return thisPtr; // JR/JALR
|
||||
}
|
||||
// Conditional Branches
|
||||
mVUprint("mVUcompile conditional branch");
|
||||
if (mVUup.eBit) return thisPtr; // Handled in Branch Case
|
||||
if (bBlock) { // Branch non-taken has already been compiled
|
||||
incPC(-3); // Go back to branch opcode (to get branch imm addr)
|
||||
|
||||
// Check if branch-block has already been compiled
|
||||
blockCreate(branchAddr/8);
|
||||
pBlock = mVUblocks[branchAddr/8]->search((microRegInfo*)&mVUregs);
|
||||
if (pBlock) { xJMP( pBlock->x86ptrStart ); }
|
||||
else { mVUblockFetch(mVU, branchAddr, (uptr)&mVUregs); }
|
||||
}
|
||||
else {
|
||||
uptr jumpAddr;
|
||||
u32 bPC = iPC; // mVUcompile can modify iPC and mVUregs so back them up
|
||||
memcpy_fast(&pBlock->pStateEnd, &mVUregs, sizeof(microRegInfo));
|
||||
|
||||
incPC2(1); // Get PC for branch not-taken
|
||||
mVUcompile(mVU, xPC, (uptr)&mVUregs);
|
||||
|
||||
iPC = bPC;
|
||||
incPC(-3); // Go back to branch opcode (to get branch imm addr)
|
||||
jumpAddr = (uptr)mVUblockFetch(mVU, branchAddr, (uptr)&pBlock->pStateEnd);
|
||||
*ajmp = (jumpAddr - ((uptr)ajmp + 4));
|
||||
}
|
||||
return thisPtr;
|
||||
}
|
||||
}
|
||||
if (x == endCount) { Console::Error("microVU%d: Possible infinite compiling loop!", params mVU->index); }
|
||||
|
||||
// E-bit End
|
||||
mVUsetupRange(mVU, xPC-8, 0);
|
||||
mVUendProgram(mVU, 1, xStatus, xMac, xClip);
|
||||
mVUendProgram(mVU, &mFC, 1);
|
||||
return thisPtr;
|
||||
}
|
||||
|
||||
|
@ -584,4 +400,3 @@ microVUt(void*) mVUblockFetch(microVU* mVU, u32 startPC, uptr pState) {
|
|||
microVUx(void*) __fastcall mVUcompileJIT(u32 startPC, uptr pState) {
|
||||
return mVUblockFetch(mVUx, startPC, pState);
|
||||
}
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ int sortFlag(int* fFlag, int* bFlag, int cycles) {
|
|||
#define sFlagCond ((sFLAG.doFlag && !mVUsFlagHack) || mVUlow.isFSSET || mVUinfo.doDivFlag)
|
||||
|
||||
// Note: Flag handling is 'very' complex, it requires full knowledge of how microVU recs work, so don't touch!
|
||||
microVUt(int) mVUsetFlags(mV, int* xStatus, int* xMac, int* xClip) {
|
||||
microVUt(void) mVUsetFlags(mV, microFlagCycles& mFC) {
|
||||
|
||||
int endPC = iPC;
|
||||
u32 aCount = 1; // Amount of instructions needed to get valid mac flag instances for block linking
|
||||
|
@ -95,31 +95,31 @@ microVUt(int) mVUsetFlags(mV, int* xStatus, int* xMac, int* xClip) {
|
|||
// Status/Mac Flags Setup Code
|
||||
int xS = 0, xM = 0, xC = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
xStatus[i] = i;
|
||||
xMac [i] = i;
|
||||
xClip [i] = i;
|
||||
mFC.xStatus[i] = i;
|
||||
mFC.xMac [i] = i;
|
||||
mFC.xClip [i] = i;
|
||||
}
|
||||
|
||||
if (!(mVUpBlock->pState.needExactMatch & 0x00f)) {
|
||||
xS = (mVUpBlock->pState.flags >> 0) & 3;
|
||||
xStatus[0] = -1; xStatus[1] = -1;
|
||||
xStatus[2] = -1; xStatus[3] = -1;
|
||||
xStatus[(xS-1)&3] = 0;
|
||||
mFC.xStatus[0] = -1; mFC.xStatus[1] = -1;
|
||||
mFC.xStatus[2] = -1; mFC.xStatus[3] = -1;
|
||||
mFC.xStatus[(xS-1)&3] = 0;
|
||||
}
|
||||
|
||||
if (!(mVUpBlock->pState.needExactMatch & 0xf00)) {
|
||||
xC = (mVUpBlock->pState.flags >> 2) & 3;
|
||||
xClip[0] = -1; xClip[1] = -1;
|
||||
xClip[2] = -1; xClip[3] = -1;
|
||||
xClip[(xC-1)&3] = 0;
|
||||
mFC.xClip[0] = -1; mFC.xClip[1] = -1;
|
||||
mFC.xClip[2] = -1; mFC.xClip[3] = -1;
|
||||
mFC.xClip[(xC-1)&3] = 0;
|
||||
}
|
||||
|
||||
if (!(mVUpBlock->pState.needExactMatch & 0x0f0)) {
|
||||
xMac[0] = -1; xMac[1] = -1;
|
||||
xMac[2] = -1; xMac[3] = -1;
|
||||
mFC.xMac[0] = -1; mFC.xMac[1] = -1;
|
||||
mFC.xMac[2] = -1; mFC.xMac[3] = -1;
|
||||
}
|
||||
|
||||
int cycles = 0;
|
||||
mFC.cycles = 0;
|
||||
u32 xCount = mVUcount; // Backup count
|
||||
iPC = mVUstartPC;
|
||||
for (mVUcount = 0; mVUcount < xCount; mVUcount++) {
|
||||
|
@ -129,11 +129,11 @@ microVUt(int) mVUsetFlags(mV, int* xStatus, int* xMac, int* xClip) {
|
|||
}
|
||||
else mVUstatusFlagOp(mVU);
|
||||
}
|
||||
cycles += mVUstall;
|
||||
mFC.cycles += mVUstall;
|
||||
|
||||
sFLAG.read = findFlagInst(xStatus, cycles);
|
||||
mFLAG.read = findFlagInst(xMac, cycles);
|
||||
cFLAG.read = findFlagInst(xClip, cycles);
|
||||
sFLAG.read = findFlagInst(mFC.xStatus, mFC.cycles);
|
||||
mFLAG.read = findFlagInst(mFC.xMac, mFC.cycles);
|
||||
cFLAG.read = findFlagInst(mFC.xClip, mFC.cycles);
|
||||
|
||||
sFLAG.write = xS;
|
||||
mFLAG.write = xM;
|
||||
|
@ -143,17 +143,16 @@ microVUt(int) mVUsetFlags(mV, int* xStatus, int* xMac, int* xClip) {
|
|||
mFLAG.lastWrite = (xM-1) & 3;
|
||||
cFLAG.lastWrite = (xC-1) & 3;
|
||||
|
||||
if (sFlagCond) { xStatus[xS] = cycles + 4; xS = (xS+1) & 3; }
|
||||
if (mFLAG.doFlag) { xMac [xM] = cycles + 4; xM = (xM+1) & 3; }
|
||||
if (cFLAG.doFlag) { xClip [xC] = cycles + 4; xC = (xC+1) & 3; }
|
||||
if (sFlagCond) { mFC.xStatus[xS] = mFC.cycles + 4; xS = (xS+1) & 3; }
|
||||
if (mFLAG.doFlag) { mFC.xMac [xM] = mFC.cycles + 4; xM = (xM+1) & 3; }
|
||||
if (cFLAG.doFlag) { mFC.xClip [xC] = mFC.cycles + 4; xC = (xC+1) & 3; }
|
||||
|
||||
cycles++;
|
||||
mFC.cycles++;
|
||||
incPC2(2);
|
||||
}
|
||||
|
||||
mVUregs.flags = ((__Clip) ? 0 : (xC << 2)) | ((__Status) ? 0 : xS);
|
||||
iPC = endPC;
|
||||
return cycles;
|
||||
}
|
||||
|
||||
#define getFlagReg1(x) ((x == 3) ? gprF3 : ((x == 2) ? gprF2 : ((x == 1) ? gprF1 : gprF0)))
|
||||
|
@ -164,11 +163,11 @@ microVUt(int) mVUsetFlags(mV, int* xStatus, int* xMac, int* xClip) {
|
|||
#define shuffleClip ((bClip[3]<<6)|(bClip[2]<<4)|(bClip[1]<<2)|bClip[0])
|
||||
|
||||
// Recompiles Code for Proper Flags on Block Linkings
|
||||
microVUt(void) mVUsetupFlags(mV, int* xStatus, int* xMac, int* xClip, int cycles) {
|
||||
microVUt(void) mVUsetupFlags(mV, microFlagCycles& mFC) {
|
||||
|
||||
if (__Status) {
|
||||
int bStatus[4];
|
||||
int sortRegs = sortFlag(xStatus, bStatus, cycles);
|
||||
int sortRegs = sortFlag(mFC.xStatus, bStatus, mFC.cycles);
|
||||
// DevCon::Status("sortRegs = %d", params sortRegs);
|
||||
// Note: Emitter will optimize out mov(reg1, reg1) cases...
|
||||
if (sortRegs == 1) {
|
||||
|
@ -207,7 +206,7 @@ microVUt(void) mVUsetupFlags(mV, int* xStatus, int* xMac, int* xClip, int cycles
|
|||
|
||||
if (__Mac) {
|
||||
int bMac[4];
|
||||
sortFlag(xMac, bMac, cycles);
|
||||
sortFlag(mFC.xMac, bMac, mFC.cycles);
|
||||
SSE_MOVAPS_M128_to_XMM(xmmT1, (uptr)mVU->macFlag);
|
||||
SSE_SHUFPS_XMM_to_XMM (xmmT1, xmmT1, shuffleMac);
|
||||
SSE_MOVAPS_XMM_to_M128((uptr)mVU->macFlag, xmmT1);
|
||||
|
@ -215,7 +214,7 @@ microVUt(void) mVUsetupFlags(mV, int* xStatus, int* xMac, int* xClip, int cycles
|
|||
|
||||
if (__Clip) {
|
||||
int bClip[4];
|
||||
sortFlag(xClip, bClip, cycles);
|
||||
sortFlag(mFC.xClip, bClip, mFC.cycles);
|
||||
SSE_MOVAPS_M128_to_XMM(xmmT2, (uptr)mVU->clipFlag);
|
||||
SSE_SHUFPS_XMM_to_XMM (xmmT2, xmmT2, shuffleClip);
|
||||
SSE_MOVAPS_XMM_to_M128((uptr)mVU->clipFlag, xmmT2);
|
||||
|
|
|
@ -122,6 +122,13 @@ struct microFlagInst {
|
|||
u8 read; // Points to the instance that should be read by a lower instruction (t-stage read)
|
||||
};
|
||||
|
||||
struct microFlagCycles {
|
||||
int xStatus[4];
|
||||
int xMac[4];
|
||||
int xClip[4];
|
||||
int cycles;
|
||||
};
|
||||
|
||||
struct microOp {
|
||||
u8 stall; // Info on how much current instruction stalled
|
||||
bool isEOB; // Cur Instruction is last instruction in block (End of Block)
|
||||
|
|
Loading…
Reference in New Issue