diff --git a/pcsx2/windows/VCprojects/pcsx2.vcxproj b/pcsx2/windows/VCprojects/pcsx2.vcxproj
index c861950ca7..90045dce9e 100644
--- a/pcsx2/windows/VCprojects/pcsx2.vcxproj
+++ b/pcsx2/windows/VCprojects/pcsx2.vcxproj
@@ -715,11 +715,12 @@
-
+
+
diff --git a/pcsx2/windows/VCprojects/pcsx2.vcxproj.filters b/pcsx2/windows/VCprojects/pcsx2.vcxproj.filters
index 5ebed0d702..843c3c1a72 100644
--- a/pcsx2/windows/VCprojects/pcsx2.vcxproj.filters
+++ b/pcsx2/windows/VCprojects/pcsx2.vcxproj.filters
@@ -1201,6 +1201,9 @@
System\Ps2\GS
+
+ System\Ps2\EmotionEngine\VU\Dynarec\microVU
+
diff --git a/pcsx2/x86/microVU.cpp b/pcsx2/x86/microVU.cpp
index f2b83a7e94..b953e65679 100644
--- a/pcsx2/x86/microVU.cpp
+++ b/pcsx2/x86/microVU.cpp
@@ -86,6 +86,7 @@ void mVUreset(microVU& mVU, bool resetReserve) {
// Clear All Program Data
//memset(&mVU.prog, 0, sizeof(mVU.prog));
memset(&mVU.prog.lpState, 0, sizeof(mVU.prog.lpState));
+ mVU.profiler.Reset(mVU.index);
// Program Variables
mVU.prog.cleared = 1;
diff --git a/pcsx2/x86/microVU.h b/pcsx2/x86/microVU.h
index 30c76a9f55..76c7713496 100644
--- a/pcsx2/x86/microVU.h
+++ b/pcsx2/x86/microVU.h
@@ -15,6 +15,7 @@
#pragma once
//#define mVUlogProg // Dumps MicroPrograms to \logs\*.html
+//#define mVUprofileProg // Shows opcode statistics in console
class AsciiFile;
using namespace std;
@@ -33,6 +34,7 @@ using namespace x86Emitter;
#include "x86emitter/x86emitter.h"
#include "microVU_Misc.h"
#include "microVU_IR.h"
+#include "microVU_Profiler.h"
struct microBlockLink {
microBlock block;
@@ -192,6 +194,7 @@ struct microVU {
u32 cacheSize; // VU Cache Size
microProgManager prog; // Micro Program Data
+ microProfiler profiler; // Opcode Profiler
ScopedPtr regAlloc; // Reg Alloc Class
ScopedPtr logFile; // Log File Pointer
diff --git a/pcsx2/x86/microVU_Alloc.inl b/pcsx2/x86/microVU_Alloc.inl
index 7fea7e4eb6..9bc2ea2dd5 100644
--- a/pcsx2/x86/microVU_Alloc.inl
+++ b/pcsx2/x86/microVU_Alloc.inl
@@ -71,31 +71,34 @@ __ri void mVUallocSFLAGc(const x32& reg, const x32& regT, int fInstance)
}
// Denormalizes Status Flag
+// If setAllflags is false, then returns result in eax (gprT1)
+// else all microVU flag regs (gprF0..F3) get the result.
__ri void mVUallocSFLAGd(u32* memAddr, bool setAllflags) {
- // Cannot use EBP (gprF1) here; as this function is used by mVU0 macro and
- // the EErec needs EBP preserved.
+ // When this function is used by mVU0 macro the EErec
+ // needs EBP (gprF1) and ESI (gprF2) to be preserved.
+ const xAddressReg& t0 = setAllflags ? gprT1 : gprF3;
+ const xAddressReg& t1 = setAllflags ? gprT2 : gprF2;
+ const xAddressReg& t2 = setAllflags ? gprT3 : gprF0;
- xMOV(gprF0, ptr32[memAddr]);
- xMOV(gprF3, gprF0);
- xSHR(gprF3, 3);
- xAND(gprF3, 0x18);
+ xMOV(t2, ptr32[memAddr]);
+ xMOV(t0, t2);
+ xSHR(t0, 3);
+ xAND(t0, 0x18);
- xMOV(gprF2, gprF0);
- xSHL(gprF2, 11);
- xAND(gprF2, 0x1800);
- xOR (gprF3, gprF2);
+ xMOV(t1, t2);
+ xSHL(t1, 11);
+ xAND(t1, 0x1800);
+ xOR (t0, t1);
- xSHL(gprF0, 14);
- xAND(gprF0, 0x3cf0000);
- xOR (gprF3, gprF0);
+ xSHL(t2, 14);
+ xAND(t2, 0x3cf0000);
+ xOR (t0, t2);
if (setAllflags) {
-
// this code should be run in mVU micro mode only, so writing to
- // EBP (gprF1) is ok (and needed for vuMicro optimizations).
-
- xMOV(gprF0, gprF3);
+ // EBP (gprF1) and ESI (gprF2) is ok (and needed for vuMicro).
+ xMOV(gprF0, gprF3); // gprF3 is t0
xMOV(gprF1, gprF3);
xMOV(gprF2, gprF3);
}
diff --git a/pcsx2/x86/microVU_Execute.inl b/pcsx2/x86/microVU_Execute.inl
index 02d39a7812..e65dc9f8f4 100644
--- a/pcsx2/x86/microVU_Execute.inl
+++ b/pcsx2/x86/microVU_Execute.inl
@@ -203,6 +203,7 @@ _mVUt void mVUcleanUp() {
if (!vuIndex || !THREAD_VU1) {
cpuRegs.cycle += std::min(mVU.cycles, 3000u) * EmuConfig.Speedhacks.VUCycleSteal;
}
+ mVU.profiler.Print();
//static int ax = 0; ax++;
//if (!(ax % 100000)) {
// for (u32 i = 0; i < (mVU.progSize / 2); i++) {
diff --git a/pcsx2/x86/microVU_Lower.inl b/pcsx2/x86/microVU_Lower.inl
index 9a9c0288ca..6f337914ad 100644
--- a/pcsx2/x86/microVU_Lower.inl
+++ b/pcsx2/x86/microVU_Lower.inl
@@ -82,6 +82,7 @@ mVUop(mVU_DIV) {
mVU.regAlloc->clearNeeded(Fs);
mVU.regAlloc->clearNeeded(Ft);
mVU.regAlloc->clearNeeded(t1);
+ mVU.profiler.EmitOp(opDIV);
}
pass3 { mVUlog("DIV Q, vf%02d%s, vf%02d%s", _Fs_, _Fsf_String, _Ft_, _Ftf_String); }
}
@@ -99,6 +100,7 @@ mVUop(mVU_SQRT) {
writeQreg(Ft, mVUinfo.writeQ);
mVU.regAlloc->clearNeeded(Ft);
+ mVU.profiler.EmitOp(opSQRT);
}
pass3 { mVUlog("SQRT Q, vf%02d%s", _Ft_, _Ftf_String); }
}
@@ -139,6 +141,7 @@ mVUop(mVU_RSQRT) {
mVU.regAlloc->clearNeeded(Fs);
mVU.regAlloc->clearNeeded(Ft);
mVU.regAlloc->clearNeeded(t1);
+ mVU.profiler.EmitOp(opRSQRT);
}
pass3 { mVUlog("RSQRT Q, vf%02d%s, vf%02d%s", _Fs_, _Fsf_String, _Ft_, _Ftf_String); }
}
@@ -186,6 +189,7 @@ mVUop(mVU_EATAN) {
mVU.regAlloc->clearNeeded(Fs);
mVU.regAlloc->clearNeeded(t1);
mVU.regAlloc->clearNeeded(t2);
+ mVU.profiler.EmitOp(opEATAN);
}
pass3 { mVUlog("EATAN P"); }
}
@@ -206,6 +210,7 @@ mVUop(mVU_EATANxy) {
mVU.regAlloc->clearNeeded(Fs);
mVU.regAlloc->clearNeeded(t1);
mVU.regAlloc->clearNeeded(t2);
+ mVU.profiler.EmitOp(opEATANxy);
}
pass3 { mVUlog("EATANxy P"); }
}
@@ -226,6 +231,7 @@ mVUop(mVU_EATANxz) {
mVU.regAlloc->clearNeeded(Fs);
mVU.regAlloc->clearNeeded(t1);
mVU.regAlloc->clearNeeded(t2);
+ mVU.profiler.EmitOp(opEATANxz);
}
pass3 { mVUlog("EATANxz P"); }
}
@@ -267,6 +273,7 @@ mVUop(mVU_EEXP) {
mVU.regAlloc->clearNeeded(Fs);
mVU.regAlloc->clearNeeded(t1);
mVU.regAlloc->clearNeeded(t2);
+ mVU.profiler.EmitOp(opEEXP);
}
pass3 { mVUlog("EEXP P"); }
}
@@ -296,6 +303,7 @@ mVUop(mVU_ELENG) {
xSQRT.SS (xmmPQ, xmmPQ);
xPSHUF.D (xmmPQ, xmmPQ, mVUinfo.writeP ? 0x27 : 0xC6); // Flip back
mVU.regAlloc->clearNeeded(Fs);
+ mVU.profiler.EmitOp(opELENG);
}
pass3 { mVUlog("ELENG P"); }
}
@@ -311,6 +319,7 @@ mVUop(mVU_ERCPR) {
xMOVSS (xmmPQ, Fs);
xPSHUF.D (xmmPQ, xmmPQ, mVUinfo.writeP ? 0x27 : 0xC6); // Flip back
mVU.regAlloc->clearNeeded(Fs);
+ mVU.profiler.EmitOp(opERCPR);
}
pass3 { mVUlog("ERCPR P"); }
}
@@ -327,6 +336,7 @@ mVUop(mVU_ERLENG) {
xMOVSS (xmmPQ, Fs);
xPSHUF.D (xmmPQ, xmmPQ, mVUinfo.writeP ? 0x27 : 0xC6); // Flip back
mVU.regAlloc->clearNeeded(Fs);
+ mVU.profiler.EmitOp(opERLENG);
}
pass3 { mVUlog("ERLENG P"); }
}
@@ -342,6 +352,7 @@ mVUop(mVU_ERSADD) {
xMOVSS (xmmPQ, Fs);
xPSHUF.D (xmmPQ, xmmPQ, mVUinfo.writeP ? 0x27 : 0xC6); // Flip back
mVU.regAlloc->clearNeeded(Fs);
+ mVU.profiler.EmitOp(opERSADD);
}
pass3 { mVUlog("ERSADD P"); }
}
@@ -358,6 +369,7 @@ mVUop(mVU_ERSQRT) {
xMOVSS (xmmPQ, Fs);
xPSHUF.D (xmmPQ, xmmPQ, mVUinfo.writeP ? 0x27 : 0xC6); // Flip back
mVU.regAlloc->clearNeeded(Fs);
+ mVU.profiler.EmitOp(opERSQRT);
}
pass3 { mVUlog("ERSQRT P"); }
}
@@ -370,6 +382,7 @@ mVUop(mVU_ESADD) {
mVU_sumXYZ(mVU, xmmPQ, Fs);
xPSHUF.D(xmmPQ, xmmPQ, mVUinfo.writeP ? 0x27 : 0xC6); // Flip back
mVU.regAlloc->clearNeeded(Fs);
+ mVU.profiler.EmitOp(opESADD);
}
pass3 { mVUlog("ESADD P"); }
}
@@ -406,6 +419,7 @@ mVUop(mVU_ESIN) {
mVU.regAlloc->clearNeeded(Fs);
mVU.regAlloc->clearNeeded(t1);
mVU.regAlloc->clearNeeded(t2);
+ mVU.profiler.EmitOp(opESIN);
}
pass3 { mVUlog("ESIN P"); }
}
@@ -419,6 +433,7 @@ mVUop(mVU_ESQRT) {
xSQRT.SS(xmmPQ, Fs);
xPSHUF.D(xmmPQ, xmmPQ, mVUinfo.writeP ? 0x27 : 0xC6); // Flip back
mVU.regAlloc->clearNeeded(Fs);
+ mVU.profiler.EmitOp(opESQRT);
}
pass3 { mVUlog("ESQRT P"); }
}
@@ -437,6 +452,7 @@ mVUop(mVU_ESUM) {
xPSHUF.D (xmmPQ, xmmPQ, mVUinfo.writeP ? 0x27 : 0xC6); // Flip back
mVU.regAlloc->clearNeeded(Fs);
mVU.regAlloc->clearNeeded(t1);
+ mVU.profiler.EmitOp(opESUM);
}
pass3 { mVUlog("ESUM P"); }
}
@@ -453,6 +469,7 @@ mVUop(mVU_FCAND) {
xADD(gprT1, 0xffffff);
xSHR(gprT1, 24);
mVUallocVIb(mVU, gprT1, 1);
+ mVU.profiler.EmitOp(opFCAND);
}
pass3 { mVUlog("FCAND vi01, $%x", _Imm24_); }
pass4 { mVUregs.needExactMatch |= 4; }
@@ -466,6 +483,7 @@ mVUop(mVU_FCEQ) {
xSUB(gprT1, 1);
xSHR(gprT1, 31);
mVUallocVIb(mVU, gprT1, 1);
+ mVU.profiler.EmitOp(opFCEQ);
}
pass3 { mVUlog("FCEQ vi01, $%x", _Imm24_); }
pass4 { mVUregs.needExactMatch |= 4; }
@@ -477,6 +495,7 @@ mVUop(mVU_FCGET) {
mVUallocCFLAGa(mVU, gprT1, cFLAG.read);
xAND(gprT1, 0xfff);
mVUallocVIb(mVU, gprT1, _It_);
+ mVU.profiler.EmitOp(opFCGET);
}
pass3 { mVUlog("FCGET vi%02d", _Ft_); }
pass4 { mVUregs.needExactMatch |= 4; }
@@ -490,6 +509,7 @@ mVUop(mVU_FCOR) {
xADD(gprT1, 1); // If 24 1's will make 25th bit 1, else 0
xSHR(gprT1, 24); // Get the 25th bit (also clears the rest of the garbage in the reg)
mVUallocVIb(mVU, gprT1, 1);
+ mVU.profiler.EmitOp(opFCOR);
}
pass3 { mVUlog("FCOR vi01, $%x", _Imm24_); }
pass4 { mVUregs.needExactMatch |= 4; }
@@ -500,6 +520,7 @@ mVUop(mVU_FCSET) {
pass2 {
xMOV(gprT1, _Imm24_);
mVUallocCFLAGb(mVU, gprT1, cFLAG.write);
+ mVU.profiler.EmitOp(opFCSET);
}
pass3 { mVUlog("FCSET $%x", _Imm24_); }
}
@@ -515,6 +536,7 @@ mVUop(mVU_FMAND) {
mVUallocVIa(mVU, gprT2, _Is_);
xAND(gprT1b, gprT2b);
mVUallocVIb(mVU, gprT1, _It_);
+ mVU.profiler.EmitOp(opFMAND);
}
pass3 { mVUlog("FMAND vi%02d, vi%02d", _Ft_, _Fs_); }
pass4 { mVUregs.needExactMatch |= 2; }
@@ -529,6 +551,7 @@ mVUop(mVU_FMEQ) {
xSUB(gprT1, 1);
xSHR(gprT1, 31);
mVUallocVIb(mVU, gprT1, _It_);
+ mVU.profiler.EmitOp(opFMEQ);
}
pass3 { mVUlog("FMEQ vi%02d, vi%02d", _Ft_, _Fs_); }
pass4 { mVUregs.needExactMatch |= 2; }
@@ -541,6 +564,7 @@ mVUop(mVU_FMOR) {
mVUallocVIa(mVU, gprT2, _Is_);
xOR(gprT1b, gprT2b);
mVUallocVIb(mVU, gprT1, _It_);
+ mVU.profiler.EmitOp(opFMOR);
}
pass3 { mVUlog("FMOR vi%02d, vi%02d", _Ft_, _Fs_); }
pass4 { mVUregs.needExactMatch |= 2; }
@@ -558,6 +582,7 @@ mVUop(mVU_FSAND) {
mVUallocSFLAGc(gprT1, gprT2, sFLAG.read);
xAND(gprT1, _Imm12_);
mVUallocVIb(mVU, gprT1, _It_);
+ mVU.profiler.EmitOp(opFSAND);
}
pass3 { mVUlog("FSAND vi%02d, $%x", _Ft_, _Imm12_); }
pass4 { mVUregs.needExactMatch |= 1; }
@@ -569,6 +594,7 @@ mVUop(mVU_FSOR) {
mVUallocSFLAGc(gprT1, gprT2, sFLAG.read);
xOR(gprT1, _Imm12_);
mVUallocVIb(mVU, gprT1, _It_);
+ mVU.profiler.EmitOp(opFSOR);
}
pass3 { mVUlog("FSOR vi%02d, $%x", _Ft_, _Imm12_); }
pass4 { mVUregs.needExactMatch |= 1; }
@@ -602,6 +628,7 @@ mVUop(mVU_FSEQ) {
xSUB(gprT1, 1);
xSHR(gprT1, 31);
mVUallocVIb(mVU, gprT1, _It_);
+ mVU.profiler.EmitOp(opFSEQ);
}
pass3 { mVUlog("FSEQ vi%02d, $%x", _Ft_, _Imm12_); }
pass4 { mVUregs.needExactMatch |= 1; }
@@ -622,6 +649,7 @@ mVUop(mVU_FSSET) {
}
xAND(getFlagReg(sFLAG.write), 0xfff00); // Keep Non-Sticky Bits
if (imm) xOR(getFlagReg(sFLAG.write), imm);
+ mVU.profiler.EmitOp(opFSSET);
}
pass3 { mVUlog("FSSET $%x", _Imm12_); }
}
@@ -640,6 +668,7 @@ mVUop(mVU_IADD) {
}
else xADD(gprT1b, gprT1b);
mVUallocVIb(mVU, gprT1, _Id_);
+ mVU.profiler.EmitOp(opIADD);
}
pass3 { mVUlog("IADD vi%02d, vi%02d, vi%02d", _Fd_, _Fs_, _Ft_); }
}
@@ -650,6 +679,7 @@ mVUop(mVU_IADDI) {
mVUallocVIa(mVU, gprT1, _Is_);
xADD(gprT1b, _Imm5_);
mVUallocVIb(mVU, gprT1, _It_);
+ mVU.profiler.EmitOp(opIADDI);
}
pass3 { mVUlog("IADDI vi%02d, vi%02d, %d", _Ft_, _Fs_, _Imm5_); }
}
@@ -660,6 +690,7 @@ mVUop(mVU_IADDIU) {
mVUallocVIa(mVU, gprT1, _Is_);
xADD(gprT1b, _Imm15_);
mVUallocVIb(mVU, gprT1, _It_);
+ mVU.profiler.EmitOp(opIADDIU);
}
pass3 { mVUlog("IADDIU vi%02d, vi%02d, %d", _Ft_, _Fs_, _Imm15_); }
}
@@ -673,6 +704,7 @@ mVUop(mVU_IAND) {
xAND(gprT1, gprT2);
}
mVUallocVIb(mVU, gprT1, _Id_);
+ mVU.profiler.EmitOp(opIAND);
}
pass3 { mVUlog("IAND vi%02d, vi%02d, vi%02d", _Fd_, _Fs_, _Ft_); }
}
@@ -686,6 +718,7 @@ mVUop(mVU_IOR) {
xOR(gprT1, gprT2);
}
mVUallocVIb(mVU, gprT1, _Id_);
+ mVU.profiler.EmitOp(opIOR);
}
pass3 { mVUlog("IOR vi%02d, vi%02d, vi%02d", _Fd_, _Fs_, _Ft_); }
}
@@ -703,6 +736,7 @@ mVUop(mVU_ISUB) {
xXOR(gprT1, gprT1);
mVUallocVIb(mVU, gprT1, _Id_);
}
+ mVU.profiler.EmitOp(opISUB);
}
pass3 { mVUlog("ISUB vi%02d, vi%02d, vi%02d", _Fd_, _Fs_, _Ft_); }
}
@@ -713,6 +747,7 @@ mVUop(mVU_ISUBIU) {
mVUallocVIa(mVU, gprT1, _Is_);
xSUB(gprT1b, _Imm15_);
mVUallocVIb(mVU, gprT1, _It_);
+ mVU.profiler.EmitOp(opISUBIU);
}
pass3 { mVUlog("ISUBIU vi%02d, vi%02d, %d", _Ft_, _Fs_, _Imm15_); }
}
@@ -733,6 +768,7 @@ mVUop(mVU_MFIR) {
xMOVDZX(Ft, gprT1);
if (!_XYZW_SS) { mVUunpack_xyzw(Ft, Ft, 0); }
mVU.regAlloc->clearNeeded(Ft);
+ mVU.profiler.EmitOp(opMFIR);
}
pass3 { mVUlog("MFIR.%s vf%02d, vi%02d", _XYZW_String, _Ft_, _Fs_); }
}
@@ -743,6 +779,7 @@ mVUop(mVU_MFP) {
const xmm& Ft = mVU.regAlloc->allocReg(-1, _Ft_, _X_Y_Z_W);
getPreg(mVU, Ft);
mVU.regAlloc->clearNeeded(Ft);
+ mVU.profiler.EmitOp(opMFP);
}
pass3 { mVUlog("MFP.%s vf%02d, P", _XYZW_String, _Ft_); }
}
@@ -752,6 +789,7 @@ mVUop(mVU_MOVE) {
pass2 {
const xmm& Fs = mVU.regAlloc->allocReg(_Fs_, _Ft_, _X_Y_Z_W);
mVU.regAlloc->clearNeeded(Fs);
+ mVU.profiler.EmitOp(opMOVE);
}
pass3 { mVUlog("MOVE.%s vf%02d, vf%02d", _XYZW_String, _Ft_, _Fs_); }
}
@@ -765,6 +803,7 @@ mVUop(mVU_MR32) {
else xPSHUF.D(Ft, Fs, 0x39);
mVU.regAlloc->clearNeeded(Ft);
mVU.regAlloc->clearNeeded(Fs);
+ mVU.profiler.EmitOp(opMR32);
}
pass3 { mVUlog("MR32.%s vf%02d, vf%02d", _XYZW_String, _Ft_, _Fs_); }
}
@@ -780,6 +819,7 @@ mVUop(mVU_MTIR) {
xMOVD(gprT1, Fs);
mVUallocVIb(mVU, gprT1, _It_);
mVU.regAlloc->clearNeeded(Fs);
+ mVU.profiler.EmitOp(opMTIR);
}
pass3 { mVUlog("MTIR vi%02d, vf%02d%s", _Ft_, _Fs_, _Fsf_String); }
}
@@ -806,6 +846,7 @@ mVUop(mVU_ILW) {
ptr += getVUmem(_Imm11_);
xMOVZX(gprT1, ptr16[ptr]);
mVUallocVIb(mVU, gprT1, _It_);
+ mVU.profiler.EmitOp(opILW);
}
pass3 { mVUlog("ILW.%s vi%02d, vi%02d + %d", _XYZW_String, _Ft_, _Fs_, _Imm11_); }
}
@@ -825,6 +866,7 @@ mVUop(mVU_ILWR) {
}
xMOVZX(gprT1, ptr16[ptr]);
mVUallocVIb(mVU, gprT1, _It_);
+ mVU.profiler.EmitOp(opILWR);
}
pass3 { mVUlog("ILWR.%s vi%02d, vi%02d", _XYZW_String, _Ft_, _Fs_); }
}
@@ -853,6 +895,7 @@ mVUop(mVU_ISW) {
if (_Y) xMOV(ptr32[ptr+4], gprT1);
if (_Z) xMOV(ptr32[ptr+8], gprT1);
if (_W) xMOV(ptr32[ptr+12], gprT1);
+ mVU.profiler.EmitOp(opISW);
}
pass3 { mVUlog("ISW.%s vi%02d, vi%02d + %d", _XYZW_String, _Ft_, _Fs_, _Imm11_); }
}
@@ -873,6 +916,7 @@ mVUop(mVU_ISWR) {
if (_Y) xMOV(ptr32[ptr+4], gprT1);
if (_Z) xMOV(ptr32[ptr+8], gprT1);
if (_W) xMOV(ptr32[ptr+12], gprT1);
+ mVU.profiler.EmitOp(opISWR);
}
pass3 { mVUlog("ISWR.%s vi%02d, vi%02d", _XYZW_String, _Ft_, _Fs_); }
}
@@ -896,6 +940,7 @@ mVUop(mVU_LQ) {
const xmm& Ft = mVU.regAlloc->allocReg(-1, _Ft_, _X_Y_Z_W);
mVUloadReg(Ft, ptr, _X_Y_Z_W);
mVU.regAlloc->clearNeeded(Ft);
+ mVU.profiler.EmitOp(opLQ);
}
pass3 { mVUlog("LQ.%s vf%02d, vi%02d + %d", _XYZW_String, _Ft_, _Fs_, _Imm11_); }
}
@@ -916,6 +961,7 @@ mVUop(mVU_LQD) {
mVUloadReg(Ft, ptr, _X_Y_Z_W);
mVU.regAlloc->clearNeeded(Ft);
}
+ mVU.profiler.EmitOp(opLQD);
}
pass3 { mVUlog("LQD.%s vf%02d, --vi%02d", _XYZW_String, _Ft_, _Is_); }
}
@@ -937,6 +983,7 @@ mVUop(mVU_LQI) {
mVUloadReg(Ft, ptr, _X_Y_Z_W);
mVU.regAlloc->clearNeeded(Ft);
}
+ mVU.profiler.EmitOp(opLQI);
}
pass3 { mVUlog("LQI.%s vf%02d, vi%02d++", _XYZW_String, _Ft_, _Fs_); }
}
@@ -960,6 +1007,7 @@ mVUop(mVU_SQ) {
const xmm& Fs = mVU.regAlloc->allocReg(_Fs_, 0, _X_Y_Z_W);
mVUsaveReg(Fs, ptr, _X_Y_Z_W, 1);
mVU.regAlloc->clearNeeded(Fs);
+ mVU.profiler.EmitOp(opSQ);
}
pass3 { mVUlog("SQ.%s vf%02d, vi%02d + %d", _XYZW_String, _Fs_, _Ft_, _Imm11_); }
}
@@ -978,6 +1026,7 @@ mVUop(mVU_SQD) {
const xmm& Fs = mVU.regAlloc->allocReg(_Fs_, 0, _X_Y_Z_W);
mVUsaveReg(Fs, ptr, _X_Y_Z_W, 1);
mVU.regAlloc->clearNeeded(Fs);
+ mVU.profiler.EmitOp(opSQD);
}
pass3 { mVUlog("SQD.%s vf%02d, --vi%02d", _XYZW_String, _Fs_, _Ft_); }
}
@@ -997,6 +1046,7 @@ mVUop(mVU_SQI) {
const xmm& Fs = mVU.regAlloc->allocReg(_Fs_, 0, _X_Y_Z_W);
mVUsaveReg(Fs, ptr, _X_Y_Z_W, 1);
mVU.regAlloc->clearNeeded(Fs);
+ mVU.profiler.EmitOp(opSQI);
}
pass3 { mVUlog("SQI.%s vf%02d, vi%02d++", _XYZW_String, _Fs_, _Ft_); }
}
@@ -1017,6 +1067,7 @@ mVUop(mVU_RINIT) {
mVU.regAlloc->clearNeeded(Fs);
}
else xMOV(ptr32[Rmem], 0x3f800000);
+ mVU.profiler.EmitOp(opRINIT);
}
pass3 { mVUlog("RINIT R, vf%02d%s", _Fs_, _Fsf_String); }
}
@@ -1032,7 +1083,11 @@ static __fi void mVU_RGET_(mV, const x32& Rreg) {
mVUop(mVU_RGET) {
pass1 { mVUanalyzeR2(mVU, _Ft_, 1); }
- pass2 { xMOV(gprT1, ptr32[Rmem]); mVU_RGET_(mVU, gprT1); }
+ pass2 {
+ xMOV(gprT1, ptr32[Rmem]);
+ mVU_RGET_(mVU, gprT1);
+ mVU.profiler.EmitOp(opRGET);
+ }
pass3 { mVUlog("RGET.%s vf%02d, R", _XYZW_String, _Ft_); }
}
@@ -1056,6 +1111,7 @@ mVUop(mVU_RNEXT) {
xOR (gprT3, 0x3f800000);
xMOV(ptr32[Rmem], gprT3);
mVU_RGET_(mVU, gprT3);
+ mVU.profiler.EmitOp(opRNEXT);
}
pass3 { mVUlog("RNEXT.%s vf%02d, R", _XYZW_String, _Ft_); }
}
@@ -1070,6 +1126,7 @@ mVUop(mVU_RXOR) {
xXOR(ptr32[Rmem], gprT1);
mVU.regAlloc->clearNeeded(Fs);
}
+ mVU.profiler.EmitOp(opRXOR);
}
pass3 { mVUlog("RXOR R, vf%02d%s", _Fs_, _Fsf_String); }
}
@@ -1080,11 +1137,13 @@ mVUop(mVU_RXOR) {
mVUop(mVU_WAITP) {
pass1 { mVUstall = max(mVUstall, (u8)((mVUregs.p) ? (mVUregs.p - 1) : 0)); }
+ pass2 { mVU.profiler.EmitOp(opWAITP); }
pass3 { mVUlog("WAITP"); }
}
mVUop(mVU_WAITQ) {
pass1 { mVUstall = max(mVUstall, mVUregs.q); }
+ pass2 { mVU.profiler.EmitOp(opWAITQ); }
pass3 { mVUlog("WAITQ"); }
}
@@ -1100,6 +1159,7 @@ mVUop(mVU_XTOP) {
pass2 {
xMOVZX(gprT1, ptr16[&mVU.getVifRegs().top]);
mVUallocVIb(mVU, gprT1, _It_);
+ mVU.profiler.EmitOp(opXTOP);
}
pass3 { mVUlog("XTOP vi%02d", _Ft_); }
}
@@ -1112,6 +1172,7 @@ mVUop(mVU_XITOP) {
xMOVZX(gprT1, ptr16[&mVU.getVifRegs().itop]);
xAND (gprT1, isVU1 ? 0x3ff : 0xff);
mVUallocVIb(mVU, gprT1, _It_);
+ mVU.profiler.EmitOp(opXITOP);
}
pass3 { mVUlog("XITOP vi%02d", _Ft_); }
}
@@ -1155,6 +1216,7 @@ mVUop(mVU_XGKICK) {
elif (mVUinfo.doXGKICK) { mVU_XGKICK_DELAY(mVU, 1); mVUinfo.doXGKICK = 0; }
mVUallocVIa(mVU, gprT1, _Is_);
xMOV(ptr32[&mVU.VIxgkick], gprT1);
+ mVU.profiler.EmitOp(opXGKICK);
}
pass3 { mVUlog("XGKICK vi%02d", _Fs_); }
}
@@ -1204,6 +1266,7 @@ mVUop(mVU_B) {
pass2 {
if (mVUlow.badBranch) { xMOV(ptr32[&mVU.badBranch], branchAddrN); }
if (mVUlow.evilBranch) { xMOV(ptr32[&mVU.evilBranch], branchAddr); }
+ mVU.profiler.EmitOp(opB);
}
pass3 { mVUlog("B [%04x]", branchAddr, branchAddr); }
}
@@ -1216,6 +1279,7 @@ mVUop(mVU_BAL) {
mVUallocVIb(mVU, gprT1, _It_);
if (mVUlow.badBranch) { xMOV(ptr32[&mVU.badBranch], branchAddrN); }
if (mVUlow.evilBranch) { xMOV(ptr32[&mVU.evilBranch], branchAddr); }
+ mVU.profiler.EmitOp(opBAL);
}
pass3 { mVUlog("BAL vi%02d [%04x]", _Ft_, branchAddr, branchAddr); }
}
@@ -1232,6 +1296,7 @@ mVUop(mVU_IBEQ) {
if (!(isBadOrEvil)) xMOV(ptr32[&mVU.branch], gprT1);
else condEvilBranch(mVU, Jcc_Equal);
+ mVU.profiler.EmitOp(opIBEQ);
}
pass3 { mVUlog("IBEQ vi%02d, vi%02d [%04x]", _Ft_, _Fs_, branchAddr, branchAddr); }
}
@@ -1244,6 +1309,7 @@ mVUop(mVU_IBGEZ) {
else mVUallocVIa(mVU, gprT1, _Is_);
if (!(isBadOrEvil)) xMOV(ptr32[&mVU.branch], gprT1);
else condEvilBranch(mVU, Jcc_GreaterOrEqual);
+ mVU.profiler.EmitOp(opIBGEZ);
}
pass3 { mVUlog("IBGEZ vi%02d [%04x]", _Fs_, branchAddr, branchAddr); }
}
@@ -1256,6 +1322,7 @@ mVUop(mVU_IBGTZ) {
else mVUallocVIa(mVU, gprT1, _Is_);
if (!(isBadOrEvil)) xMOV(ptr32[&mVU.branch], gprT1);
else condEvilBranch(mVU, Jcc_Greater);
+ mVU.profiler.EmitOp(opIBGTZ);
}
pass3 { mVUlog("IBGTZ vi%02d [%04x]", _Fs_, branchAddr, branchAddr); }
}
@@ -1268,6 +1335,7 @@ mVUop(mVU_IBLEZ) {
else mVUallocVIa(mVU, gprT1, _Is_);
if (!(isBadOrEvil)) xMOV(ptr32[&mVU.branch], gprT1);
else condEvilBranch(mVU, Jcc_LessOrEqual);
+ mVU.profiler.EmitOp(opIBLEZ);
}
pass3 { mVUlog("IBLEZ vi%02d [%04x]", _Fs_, branchAddr, branchAddr); }
}
@@ -1280,6 +1348,7 @@ mVUop(mVU_IBLTZ) {
else mVUallocVIa(mVU, gprT1, _Is_);
if (!(isBadOrEvil)) xMOV(ptr32[&mVU.branch], gprT1);
else condEvilBranch(mVU, Jcc_Less);
+ mVU.profiler.EmitOp(opIBLTZ);
}
pass3 { mVUlog("IBLTZ vi%02d [%04x]", _Fs_, branchAddr, branchAddr); }
}
@@ -1296,6 +1365,7 @@ mVUop(mVU_IBNE) {
if (!(isBadOrEvil)) xMOV(ptr32[&mVU.branch], gprT1);
else condEvilBranch(mVU, Jcc_NotEqual);
+ mVU.profiler.EmitOp(opIBNE);
}
pass3 { mVUlog("IBNE vi%02d, vi%02d [%04x]", _Ft_, _Fs_, branchAddr, branchAddr); }
}
@@ -1318,7 +1388,7 @@ void normJumpPass2(mV) {
mVUop(mVU_JR) {
mVUbranch = 9;
pass1 { mVUanalyzeJump(mVU, _Is_, 0, 0); }
- pass2 { normJumpPass2(mVU); }
+ pass2 { normJumpPass2(mVU); mVU.profiler.EmitOp(opJR); }
pass3 { mVUlog("JR [vi%02d]", _Fs_); }
}
@@ -1329,7 +1399,7 @@ mVUop(mVU_JALR) {
normJumpPass2(mVU);
xMOV(gprT1, bSaveAddr);
mVUallocVIb(mVU, gprT1, _It_);
+ mVU.profiler.EmitOp(opJALR);
}
pass3 { mVUlog("JALR vi%02d, [vi%02d]", _Ft_, _Fs_); }
}
-
diff --git a/pcsx2/x86/microVU_Macro.inl b/pcsx2/x86/microVU_Macro.inl
index 9e8a6019c4..ffba4bde6e 100644
--- a/pcsx2/x86/microVU_Macro.inl
+++ b/pcsx2/x86/microVU_Macro.inl
@@ -45,14 +45,14 @@ void setupMacroOp(int mode, const char* opName) {
microVU0.prog.IRinfo.info[0].cFlag.lastWrite = 0xff;
}
if (mode & 0x10) { // Update Status/Mac Flags
- microVU0.prog.IRinfo.info[0].sFlag.doFlag = 1;
- microVU0.prog.IRinfo.info[0].sFlag.doNonSticky = 1;
- microVU0.prog.IRinfo.info[0].sFlag.write = 0;
- microVU0.prog.IRinfo.info[0].sFlag.lastWrite = 0;
- microVU0.prog.IRinfo.info[0].mFlag.doFlag = 1;
- microVU0.prog.IRinfo.info[0].mFlag.write = 0xff;
+ microVU0.prog.IRinfo.info[0].sFlag.doFlag = 1;
+ microVU0.prog.IRinfo.info[0].sFlag.doNonSticky = 1;
+ microVU0.prog.IRinfo.info[0].sFlag.write = 0;
+ microVU0.prog.IRinfo.info[0].sFlag.lastWrite = 0;
+ microVU0.prog.IRinfo.info[0].mFlag.doFlag = 1;
+ microVU0.prog.IRinfo.info[0].mFlag.write = 0xff;
- xMOV(gprF0, ptr32[&vu0Regs.VI[REG_STATUS_FLAG].UL]);
+ xMOV(gprF0, ptr32[&vu0Regs.VI[REG_STATUS_FLAG].UL]);
}
}
@@ -304,9 +304,9 @@ static void recCTC2() {
xMOV(ptr32[&vu0Regs.VI[REG_R].UL], eax);
break;
case REG_STATUS_FLAG:
- if (_Rt_) { // Denormalizes flag into gprF3
+ if (_Rt_) { // Denormalizes flag into eax (gprT1)
mVUallocSFLAGd(&cpuRegs.GPR.r[_Rt_].UL[0], 0);
- xMOV(ptr32[&vu0Regs.VI[_Rd_].UL], gprF3);
+ xMOV(ptr32[&vu0Regs.VI[_Rd_].UL], eax);
}
else xMOV(ptr32[&vu0Regs.VI[_Rd_].UL], 0);
break;
diff --git a/pcsx2/x86/microVU_Misc.h b/pcsx2/x86/microVU_Misc.h
index f3f966e5f3..17aed5ed79 100644
--- a/pcsx2/x86/microVU_Misc.h
+++ b/pcsx2/x86/microVU_Misc.h
@@ -170,10 +170,10 @@ typedef Fntype_mVUrecInst* Fnptr_mVUrecInst;
#define _mVUt template
// Define Passes
-#define pass1 if (recPass == 0)
-#define pass2 if (recPass == 1)
-#define pass3 if (recPass == 2)
-#define pass4 if (recPass == 3)
+#define pass1 if (recPass == 0) // Analyze
+#define pass2 if (recPass == 1) // Recompile
+#define pass3 if (recPass == 2) // Logging
+#define pass4 if (recPass == 3) // Flag stuff
// Upper Opcode Cases
#define opCase1 if (opCase == 1) // Normal Opcodes
diff --git a/pcsx2/x86/microVU_Profiler.h b/pcsx2/x86/microVU_Profiler.h
new file mode 100644
index 0000000000..0930bbc2a1
--- /dev/null
+++ b/pcsx2/x86/microVU_Profiler.h
@@ -0,0 +1,143 @@
+/* PCSX2 - PS2 Emulator for PCs
+ * Copyright (C) 2002-2010 PCSX2 Dev Team
+ *
+ * PCSX2 is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU Lesser General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * PCSX2 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 PCSX2.
+ * If not, see .
+ */
+
+#pragma once
+
+enum microOpcode {
+ // Upper Instructions
+ opABS, opCLIP, opOPMULA, opOPMSUB, opNOP,
+ opADD, opADDi, opADDq, opADDx, opADDy, opADDz, opADDw,
+ opADDA, opADDAi, opADDAq, opADDAx, opADDAy, opADDAz, opADDAw,
+ opSUB, opSUBi, opSUBq, opSUBx, opSUBy, opSUBz, opSUBw,
+ opSUBA, opSUBAi, opSUBAq, opSUBAx, opSUBAy, opSUBAz, opSUBAw,
+ opMUL, opMULi, opMULq, opMULx, opMULy, opMULz, opMULw,
+ opMULA, opMULAi, opMULAq, opMULAx, opMULAy, opMULAz, opMULAw,
+ opMADD, opMADDi, opMADDq, opMADDx, opMADDy, opMADDz, opMADDw,
+ opMADDA, opMADDAi, opMADDAq, opMADDAx, opMADDAy, opMADDAz, opMADDAw,
+ opMSUB, opMSUBi, opMSUBq, opMSUBx, opMSUBy, opMSUBz, opMSUBw,
+ opMSUBA, opMSUBAi, opMSUBAq, opMSUBAx, opMSUBAy, opMSUBAz, opMSUBAw,
+ opMAX, opMAXi, opMAXx, opMAXy, opMAXz, opMAXw,
+ opMINI, opMINIi, opMINIx, opMINIy, opMINIz, opMINIw,
+ opFTOI0, opFTOI4, opFTOI12, opFTOI15,
+ opITOF0, opITOF4, opITOF12, opITOF15,
+ // Lower Instructions
+ opDIV, opSQRT, opRSQRT,
+ opIADD, opIADDI, opIADDIU,
+ opIAND, opIOR,
+ opISUB, opISUBIU,
+ opMOVE, opMFIR, opMTIR, opMR32, opMFP,
+ opLQ, opLQD, opLQI,
+ opSQ, opSQD, opSQI,
+ opILW, opISW, opILWR, opISWR,
+ opRINIT, opRGET, opRNEXT, opRXOR,
+ opWAITQ, opWAITP,
+ opFSAND, opFSEQ, opFSOR, opFSSET,
+ opFMAND, opFMEQ, opFMOR,
+ opFCAND, opFCEQ, opFCOR, opFCSET, opFCGET,
+ opIBEQ, opIBGEZ, opIBGTZ, opIBLTZ, opIBLEZ, opIBNE,
+ opB, opBAL, opJR, opJALR,
+ opESADD, opERSADD, opELENG, opERLENG,
+ opEATANxy, opEATANxz, opESUM, opERCPR,
+ opESQRT, opERSQRT, opESIN, opEATAN,
+ opEEXP, opXITOP, opXTOP, opXGKICK,
+ opLastOpcode
+};
+
+static const char microOpcodeName[][16] = {
+ // Upper Instructions
+ "ABS", "CLIP", "OPMULA", "OPMSUB", "NOP",
+ "ADD", "ADDi", "ADDq", "ADDx", "ADDy", "ADDz", "ADDw",
+ "ADDA", "ADDAi", "ADDAq", "ADDAx", "ADDAy", "ADDAz", "ADDAw",
+ "SUB", "SUBi", "SUBq", "SUBx", "SUBy", "SUBz", "SUBw",
+ "SUBA", "SUBAi", "SUBAq", "SUBAx", "SUBAy", "SUBAz", "SUBAw",
+ "MUL", "MULi", "MULq", "MULx", "MULy", "MULz", "MULw",
+ "MULA", "MULAi", "MULAq", "MULAx", "MULAy", "MULAz", "MULAw",
+ "MADD", "MADDi", "MADDq", "MADDx", "MADDy", "MADDz", "MADDw",
+ "MADDA", "MADDAi", "MADDAq", "MADDAx", "MADDAy", "MADDAz", "MADDAw",
+ "MSUB", "MSUBi", "MSUBq", "MSUBx", "MSUBy", "MSUBz", "MSUBw",
+ "MSUBA", "MSUBAi", "MSUBAq", "MSUBAx", "MSUBAy", "MSUBAz", "MSUBAw",
+ "MAX", "MAXi", "MAXx", "MAXy", "MAXz", "MAXw",
+ "MINI", "MINIi", "MINIx", "MINIy", "MINIz", "MINIw",
+ "FTOI0", "FTOI4", "FTOI12", "FTOI15",
+ "ITOF0", "ITOF4", "ITOF12", "ITOF15",
+ // Lower Instructions
+ "DIV", "SQRT", "RSQRT",
+ "IADD", "IADDI", "IADDIU",
+ "IAND", "IOR",
+ "ISUB", "ISUBIU",
+ "MOVE", "MFIR", "MTIR", "MR32", "MFP",
+ "LQ", "LQD", "LQI",
+ "SQ", "SQD", "SQI",
+ "ILW", "ISW", "ILWR", "ISWR",
+ "RINIT", "RGET", "RNEXT", "RXOR",
+ "WAITQ", "WAITP",
+ "FSAND", "FSEQ", "FSOR", "FSSET",
+ "FMAND", "FMEQ", "FMOR",
+ "FCAND", "FCEQ", "FCOR", "FCSET", "FCGET",
+ "IBEQ", "IBGEZ", "IBGTZ", "IBLTZ", "IBLEZ", "IBNE",
+ "B", "BAL", "JR", "JALR",
+ "ESADD", "ERSADD", "ELENG", "ERLENG",
+ "EATANxy", "EATANxz", "ESUM", "ERCPR",
+ "ESQRT", "ERSQRT", "ESIN", "EATAN",
+ "EEXP", "XITOP", "XTOP", "XGKICK"
+};
+
+#ifdef mVUprofileProg
+#include
+#include
+#include
+
+struct microProfiler {
+ static const u32 progLimit = 10000;
+ u64 opStats[opLastOpcode];
+ u32 progCount;
+ int index;
+ void Reset(int _index) { memzero(*this); index = _index; }
+ void EmitOp(microOpcode op) {
+ xADD(ptr32[&(((u32*)opStats)[op*2+0])], 1);
+ xADC(ptr32[&(((u32*)opStats)[op*2+1])], 0);
+ }
+ void Print() {
+ progCount++;
+ if ((progCount % progLimit) == 0) {
+ u64 total = 0;
+ vector< pair > v;
+ for(int i = 0; i < opLastOpcode; i++) {
+ total += opStats[i];
+ v.push_back(make_pair(opStats[i], i));
+ }
+ std::sort (v.begin(), v.end());
+ std::reverse(v.begin(), v.end());
+ double dTotal = (double)total;
+ DevCon.WriteLn("microVU%d Profiler:", index);
+ for(u32 i = 0; i < v.size(); i++) {
+ u64 count = v[i].first;
+ double stat = (double)count / dTotal * 100.0;
+ string str = microOpcodeName[v[i].second];
+ str.resize(8, ' ');
+ DevCon.WriteLn("%s - [%3.4f%%][count=%u]",
+ str.c_str(), stat, (u32)count);
+ }
+ DevCon.WriteLn("Total = 0x%x%x\n\n", (u32)(u64)(total>>32),(u32)total);
+ }
+ }
+};
+#else
+struct microProfiler {
+ __fi void Reset(int _index) {}
+ __fi void EmitOp(microOpcode op) {}
+ __fi void Print() {}
+};
+#endif
diff --git a/pcsx2/x86/microVU_Upper.inl b/pcsx2/x86/microVU_Upper.inl
index 9f97a059f8..5b655fa114 100644
--- a/pcsx2/x86/microVU_Upper.inl
+++ b/pcsx2/x86/microVU_Upper.inl
@@ -110,8 +110,8 @@ enum clampModes {
};
// Prints Opcode to MicroProgram Logs
-static void mVU_printOP(microVU& mVU, int opCase, const char* opName, bool isACC) {
- mVUlog(opName);
+static void mVU_printOP(microVU& mVU, int opCase, microOpcode opEnum, bool isACC) {
+ mVUlog(microOpcodeName[opEnum]);
opCase1 { if (isACC) { mVUlogACC(); } else { mVUlogFd(); } mVUlogFt(); }
opCase2 { if (isACC) { mVUlogACC(); } else { mVUlogFd(); } mVUlogBC(); }
opCase3 { if (isACC) { mVUlogACC(); } else { mVUlogFd(); } mVUlogI(); }
@@ -163,7 +163,7 @@ static void setupFtReg(microVU& mVU, xmm& Ft, xmm& tempFt, int opCase) {
}
// Normal FMAC Opcodes
-static void mVU_FMACa(microVU& mVU, int recPass, int opCase, int opType, bool isACC, const char* opName, int clampType) {
+static void mVU_FMACa(microVU& mVU, int recPass, int opCase, int opType, bool isACC, microOpcode opEnum, int clampType) {
pass1 { setupPass1(mVU, opCase, isACC, ((opType == 3) || (opType == 4))); }
pass2 {
if (doSafeSub(mVU, opCase, opType, isACC)) return;
@@ -195,13 +195,14 @@ static void mVU_FMACa(microVU& mVU, int recPass, int opCase, int opType, bool is
mVU.regAlloc->clearNeeded(Fs); // Always Clear Written Reg First
mVU.regAlloc->clearNeeded(Ft);
+ mVU.profiler.EmitOp(opEnum);
}
- pass3 { mVU_printOP(mVU, opCase, opName, isACC); }
+ pass3 { mVU_printOP(mVU, opCase, opEnum, isACC); }
pass4 { if ((opType != 3) && (opType != 4)) mVUregs.needExactMatch |= 8; }
}
// MADDA/MSUBA Opcodes
-static void mVU_FMACb(microVU& mVU, int recPass, int opCase, int opType, const char* opName, int clampType) {
+static void mVU_FMACb(microVU& mVU, int recPass, int opCase, int opType, microOpcode opEnum, int clampType) {
pass1 { setupPass1(mVU, opCase, 1, 0); }
pass2 {
xmm Fs, Ft, ACC, tempFt;
@@ -236,13 +237,14 @@ static void mVU_FMACb(microVU& mVU, int recPass, int opCase, int opType, const c
mVU.regAlloc->clearNeeded(ACC);
mVU.regAlloc->clearNeeded(Fs);
mVU.regAlloc->clearNeeded(Ft);
+ mVU.profiler.EmitOp(opEnum);
}
- pass3 { mVU_printOP(mVU, opCase, opName, 1); }
+ pass3 { mVU_printOP(mVU, opCase, opEnum, 1); }
pass4 { mVUregs.needExactMatch |= 8; }
}
// MADD Opcodes
-static void mVU_FMACc(microVU& mVU, int recPass, int opCase, const char* opName, int clampType) {
+static void mVU_FMACc(microVU& mVU, int recPass, int opCase, microOpcode opEnum, int clampType) {
pass1 { setupPass1(mVU, opCase, 0, 0); }
pass2 {
xmm Fs, Ft, ACC, tempFt;
@@ -267,13 +269,14 @@ static void mVU_FMACc(microVU& mVU, int recPass, int opCase, const char* opName,
mVU.regAlloc->clearNeeded(Fs); // Always Clear Written Reg First
mVU.regAlloc->clearNeeded(Ft);
mVU.regAlloc->clearNeeded(ACC);
+ mVU.profiler.EmitOp(opEnum);
}
- pass3 { mVU_printOP(mVU, opCase, opName, 0); }
+ pass3 { mVU_printOP(mVU, opCase, opEnum, 0); }
pass4 { mVUregs.needExactMatch |= 8; }
}
// MSUB Opcodes
-static void mVU_FMACd(microVU& mVU, int recPass, int opCase, const char* opName, int clampType) {
+static void mVU_FMACd(microVU& mVU, int recPass, int opCase, microOpcode opEnum, int clampType) {
pass1 { setupPass1(mVU, opCase, 0, 0); }
pass2 {
xmm Fs, Ft, Fd, tempFt;
@@ -294,8 +297,9 @@ static void mVU_FMACd(microVU& mVU, int recPass, int opCase, const char* opName,
mVU.regAlloc->clearNeeded(Fd); // Always Clear Written Reg First
mVU.regAlloc->clearNeeded(Ft);
mVU.regAlloc->clearNeeded(Fs);
+ mVU.profiler.EmitOp(opEnum);
}
- pass3 { mVU_printOP(mVU, opCase, opName, 0); }
+ pass3 { mVU_printOP(mVU, opCase, opEnum, 0); }
pass4 { mVUregs.needExactMatch |= 8; }
}
@@ -307,6 +311,7 @@ mVUop(mVU_ABS) {
const xmm& Fs = mVU.regAlloc->allocReg(_Fs_, _Ft_, _X_Y_Z_W, !((_Fs_ == _Ft_) && (_X_Y_Z_W == 0xf)));
xAND.PS(Fs, ptr128[mVUglob.absclip]);
mVU.regAlloc->clearNeeded(Fs);
+ mVU.profiler.EmitOp(opABS);
}
pass3 { mVUlog("ABS"); mVUlogFtFs(); }
}
@@ -324,6 +329,7 @@ mVUop(mVU_OPMULA) {
mVU.regAlloc->clearNeeded(Ft);
mVUupdateFlags(mVU, Fs);
mVU.regAlloc->clearNeeded(Fs);
+ mVU.profiler.EmitOp(opOPMULA);
}
pass3 { mVUlog("OPMULA"); mVUlogACC(); mVUlogFt(); }
pass4 { mVUregs.needExactMatch |= 8; }
@@ -345,14 +351,14 @@ mVUop(mVU_OPMSUB) {
mVU.regAlloc->clearNeeded(Ft);
mVUupdateFlags(mVU, ACC);
mVU.regAlloc->clearNeeded(ACC);
-
+ mVU.profiler.EmitOp(opOPMSUB);
}
pass3 { mVUlog("OPMSUB"); mVUlogFd(); mVUlogFt(); }
pass4 { mVUregs.needExactMatch |= 8; }
}
// FTOI0/FTIO4/FTIO12/FTIO15 Opcodes
-static void mVU_FTOIx(mP, const float* addr, const char* opName) {
+static void mVU_FTOIx(mP, const float* addr, microOpcode opEnum) {
pass1 { mVUanalyzeFMAC2(mVU, _Fs_, _Ft_); }
pass2 {
if (!_Ft_) return;
@@ -374,12 +380,13 @@ static void mVU_FTOIx(mP, const float* addr, const char* opName) {
mVU.regAlloc->clearNeeded(Fs);
mVU.regAlloc->clearNeeded(t1);
mVU.regAlloc->clearNeeded(t2);
+ mVU.profiler.EmitOp(opEnum);
}
- pass3 { mVUlog(opName); mVUlogFtFs(); }
+ pass3 { mVUlog(microOpcodeName[opEnum]); mVUlogFtFs(); }
}
// ITOF0/ITOF4/ITOF12/ITOF15 Opcodes
-static void mVU_ITOFx(mP, const float* addr, const char* opName) {
+static void mVU_ITOFx(mP, const float* addr, microOpcode opEnum) {
pass1 { mVUanalyzeFMAC2(mVU, _Fs_, _Ft_); }
pass2 {
if (!_Ft_) return;
@@ -390,8 +397,9 @@ static void mVU_ITOFx(mP, const float* addr, const char* opName) {
//mVUclamp2(Fs, xmmT1, 15); // Clamp (not sure if this is needed)
mVU.regAlloc->clearNeeded(Fs);
+ mVU.profiler.EmitOp(opEnum);
}
- pass3 { mVUlog(opName); mVUlogFtFs(); }
+ pass3 { mVUlog(microOpcodeName[opEnum]); mVUlogFtFs(); }
}
// Clip Opcode
@@ -431,6 +439,7 @@ mVUop(mVU_CLIP) {
mVU.regAlloc->clearNeeded(Fs);
mVU.regAlloc->clearNeeded(Ft);
mVU.regAlloc->clearNeeded(t1);
+ mVU.profiler.EmitOp(opCLIP);
}
pass3 { mVUlog("CLIP"); mVUlogCLIP(); }
}
@@ -439,94 +448,94 @@ mVUop(mVU_CLIP) {
// Micro VU Micromode Upper instructions
//------------------------------------------------------------------
-mVUop(mVU_ADD) { mVU_FMACa(mVU, recPass, 1, 0, 0, "ADD", 0); }
-mVUop(mVU_ADDi) { mVU_FMACa(mVU, recPass, 3, 5, 0, "ADDi", 0); }
-mVUop(mVU_ADDq) { mVU_FMACa(mVU, recPass, 4, 0, 0, "ADDq", 0); }
-mVUop(mVU_ADDx) { mVU_FMACa(mVU, recPass, 2, 0, 0, "ADDx", 0); }
-mVUop(mVU_ADDy) { mVU_FMACa(mVU, recPass, 2, 0, 0, "ADDy", 0); }
-mVUop(mVU_ADDz) { mVU_FMACa(mVU, recPass, 2, 0, 0, "ADDz", 0); }
-mVUop(mVU_ADDw) { mVU_FMACa(mVU, recPass, 2, 0, 0, "ADDw", 0); }
-mVUop(mVU_ADDA) { mVU_FMACa(mVU, recPass, 1, 0, 1, "ADDA", 0); }
-mVUop(mVU_ADDAi) { mVU_FMACa(mVU, recPass, 3, 0, 1, "ADDAi", 0); }
-mVUop(mVU_ADDAq) { mVU_FMACa(mVU, recPass, 4, 0, 1, "ADDAq", 0); }
-mVUop(mVU_ADDAx) { mVU_FMACa(mVU, recPass, 2, 0, 1, "ADDAx", 0); }
-mVUop(mVU_ADDAy) { mVU_FMACa(mVU, recPass, 2, 0, 1, "ADDAy", 0); }
-mVUop(mVU_ADDAz) { mVU_FMACa(mVU, recPass, 2, 0, 1, "ADDAz", 0); }
-mVUop(mVU_ADDAw) { mVU_FMACa(mVU, recPass, 2, 0, 1, "ADDAw", 0); }
-mVUop(mVU_SUB) { mVU_FMACa(mVU, recPass, 1, 1, 0, "SUB", (_XYZW_PS)?(cFs|cFt):0); } // Clamp (Kingdom Hearts I (VU0))
-mVUop(mVU_SUBi) { mVU_FMACa(mVU, recPass, 3, 1, 0, "SUBi", (_XYZW_PS)?(cFs|cFt):0); } // Clamp (Kingdom Hearts I (VU0))
-mVUop(mVU_SUBq) { mVU_FMACa(mVU, recPass, 4, 1, 0, "SUBq", (_XYZW_PS)?(cFs|cFt):0); } // Clamp (Kingdom Hearts I (VU0))
-mVUop(mVU_SUBx) { mVU_FMACa(mVU, recPass, 2, 1, 0, "SUBx", (_XYZW_PS)?(cFs|cFt):0); } // Clamp (Kingdom Hearts I (VU0))
-mVUop(mVU_SUBy) { mVU_FMACa(mVU, recPass, 2, 1, 0, "SUBy", (_XYZW_PS)?(cFs|cFt):0); } // Clamp (Kingdom Hearts I (VU0))
-mVUop(mVU_SUBz) { mVU_FMACa(mVU, recPass, 2, 1, 0, "SUBz", (_XYZW_PS)?(cFs|cFt):0); } // Clamp (Kingdom Hearts I (VU0))
-mVUop(mVU_SUBw) { mVU_FMACa(mVU, recPass, 2, 1, 0, "SUBw", (_XYZW_PS)?(cFs|cFt):0); } // Clamp (Kingdom Hearts I (VU0))
-mVUop(mVU_SUBA) { mVU_FMACa(mVU, recPass, 1, 1, 1, "SUBA", 0); }
-mVUop(mVU_SUBAi) { mVU_FMACa(mVU, recPass, 3, 1, 1, "SUBAi", 0); }
-mVUop(mVU_SUBAq) { mVU_FMACa(mVU, recPass, 4, 1, 1, "SUBAq", 0); }
-mVUop(mVU_SUBAx) { mVU_FMACa(mVU, recPass, 2, 1, 1, "SUBAx", 0); }
-mVUop(mVU_SUBAy) { mVU_FMACa(mVU, recPass, 2, 1, 1, "SUBAy", 0); }
-mVUop(mVU_SUBAz) { mVU_FMACa(mVU, recPass, 2, 1, 1, "SUBAz", 0); }
-mVUop(mVU_SUBAw) { mVU_FMACa(mVU, recPass, 2, 1, 1, "SUBAw", 0); }
-mVUop(mVU_MUL) { mVU_FMACa(mVU, recPass, 1, 2, 0, "MUL", (_XYZW_PS)?(cFs|cFt):cFs); } // Clamp (TOTA, DoM, Ice Age (VU0))
-mVUop(mVU_MULi) { mVU_FMACa(mVU, recPass, 3, 2, 0, "MULi", (_XYZW_PS)?(cFs|cFt):cFs); } // Clamp (TOTA, DoM, Ice Age (VU0))
-mVUop(mVU_MULq) { mVU_FMACa(mVU, recPass, 4, 2, 0, "MULq", (_XYZW_PS)?(cFs|cFt):cFs); } // Clamp (TOTA, DoM, Ice Age (VU0))
-mVUop(mVU_MULx) { mVU_FMACa(mVU, recPass, 2, 2, 0, "MULx", (_XYZW_PS)?(cFs|cFt):cFs); } // Clamp (TOTA, DoM, Ice Age (vu0))
-mVUop(mVU_MULy) { mVU_FMACa(mVU, recPass, 2, 2, 0, "MULy", (_XYZW_PS)?(cFs|cFt):cFs); } // Clamp (TOTA, DoM, Ice Age (VU0))
-mVUop(mVU_MULz) { mVU_FMACa(mVU, recPass, 2, 2, 0, "MULz", (_XYZW_PS)?(cFs|cFt):cFs); } // Clamp (TOTA, DoM, Ice Age (VU0))
-mVUop(mVU_MULw) { mVU_FMACa(mVU, recPass, 2, 2, 0, "MULw", (_XYZW_PS)?(cFs|cFt):cFs); } // Clamp (TOTA, DoM, Ice Age (VU0))
-mVUop(mVU_MULA) { mVU_FMACa(mVU, recPass, 1, 2, 1, "MULA", 0); }
-mVUop(mVU_MULAi) { mVU_FMACa(mVU, recPass, 3, 2, 1, "MULAi", 0); }
-mVUop(mVU_MULAq) { mVU_FMACa(mVU, recPass, 4, 2, 1, "MULAq", 0); }
-mVUop(mVU_MULAx) { mVU_FMACa(mVU, recPass, 2, 2, 1, "MULAx", cFs);} // Clamp (TOTA, DoM, ...)
-mVUop(mVU_MULAy) { mVU_FMACa(mVU, recPass, 2, 2, 1, "MULAy", cFs);} // Clamp (TOTA, DoM, ...)
-mVUop(mVU_MULAz) { mVU_FMACa(mVU, recPass, 2, 2, 1, "MULAz", cFs);} // Clamp (TOTA, DoM, ...)
-mVUop(mVU_MULAw) { mVU_FMACa(mVU, recPass, 2, 2, 1, "MULAw", cFs);} // Clamp (TOTA, DoM, ...)
-mVUop(mVU_MADD) { mVU_FMACc(mVU, recPass, 1, "MADD", 0); }
-mVUop(mVU_MADDi) { mVU_FMACc(mVU, recPass, 3, "MADDi", 0); }
-mVUop(mVU_MADDq) { mVU_FMACc(mVU, recPass, 4, "MADDq", 0); }
-mVUop(mVU_MADDx) { mVU_FMACc(mVU, recPass, 2, "MADDx", cFs);} // Clamp (TOTA, DoM, ...)
-mVUop(mVU_MADDy) { mVU_FMACc(mVU, recPass, 2, "MADDy", cFs);} // Clamp (TOTA, DoM, ...)
-mVUop(mVU_MADDz) { mVU_FMACc(mVU, recPass, 2, "MADDz", cFs);} // Clamp (TOTA, DoM, ...)
-mVUop(mVU_MADDw) { mVU_FMACc(mVU, recPass, 2, "MADDw", (isCOP2)?(cACC|cFt|cFs):cFs);} // Clamp (ICO (COP2), TOTA, DoM)
-mVUop(mVU_MADDA) { mVU_FMACb(mVU, recPass, 1, 0, "MADDA", 0); }
-mVUop(mVU_MADDAi) { mVU_FMACb(mVU, recPass, 3, 0, "MADDAi", 0); }
-mVUop(mVU_MADDAq) { mVU_FMACb(mVU, recPass, 4, 0, "MADDAq", 0); }
-mVUop(mVU_MADDAx) { mVU_FMACb(mVU, recPass, 2, 0, "MADDAx", cFs);} // Clamp (TOTA, DoM, ...)
-mVUop(mVU_MADDAy) { mVU_FMACb(mVU, recPass, 2, 0, "MADDAy", cFs);} // Clamp (TOTA, DoM, ...)
-mVUop(mVU_MADDAz) { mVU_FMACb(mVU, recPass, 2, 0, "MADDAz", cFs);} // Clamp (TOTA, DoM, ...)
-mVUop(mVU_MADDAw) { mVU_FMACb(mVU, recPass, 2, 0, "MADDAw", cFs);} // Clamp (TOTA, DoM, ...)
-mVUop(mVU_MSUB) { mVU_FMACd(mVU, recPass, 1, "MSUB", 0); }
-mVUop(mVU_MSUBi) { mVU_FMACd(mVU, recPass, 3, "MSUBi", 0); }
-mVUop(mVU_MSUBq) { mVU_FMACd(mVU, recPass, 4, "MSUBq", 0); }
-mVUop(mVU_MSUBx) { mVU_FMACd(mVU, recPass, 2, "MSUBx", 0); }
-mVUop(mVU_MSUBy) { mVU_FMACd(mVU, recPass, 2, "MSUBy", 0); }
-mVUop(mVU_MSUBz) { mVU_FMACd(mVU, recPass, 2, "MSUBz", 0); }
-mVUop(mVU_MSUBw) { mVU_FMACd(mVU, recPass, 2, "MSUBw", 0); }
-mVUop(mVU_MSUBA) { mVU_FMACb(mVU, recPass, 1, 1, "MSUBA", 0); }
-mVUop(mVU_MSUBAi) { mVU_FMACb(mVU, recPass, 3, 1, "MSUBAi", 0); }
-mVUop(mVU_MSUBAq) { mVU_FMACb(mVU, recPass, 4, 1, "MSUBAq", 0); }
-mVUop(mVU_MSUBAx) { mVU_FMACb(mVU, recPass, 2, 1, "MSUBAx", 0); }
-mVUop(mVU_MSUBAy) { mVU_FMACb(mVU, recPass, 2, 1, "MSUBAy", 0); }
-mVUop(mVU_MSUBAz) { mVU_FMACb(mVU, recPass, 2, 1, "MSUBAz", 0); }
-mVUop(mVU_MSUBAw) { mVU_FMACb(mVU, recPass, 2, 1, "MSUBAw", 0); }
-mVUop(mVU_MAX) { mVU_FMACa(mVU, recPass, 1, 3, 0, "MAX", 0); }
-mVUop(mVU_MAXi) { mVU_FMACa(mVU, recPass, 3, 3, 0, "MAXi", 0); }
-mVUop(mVU_MAXx) { mVU_FMACa(mVU, recPass, 2, 3, 0, "MAXx", 0); }
-mVUop(mVU_MAXy) { mVU_FMACa(mVU, recPass, 2, 3, 0, "MAXy", 0); }
-mVUop(mVU_MAXz) { mVU_FMACa(mVU, recPass, 2, 3, 0, "MAXz", 0); }
-mVUop(mVU_MAXw) { mVU_FMACa(mVU, recPass, 2, 3, 0, "MAXw", 0); }
-mVUop(mVU_MINI) { mVU_FMACa(mVU, recPass, 1, 4, 0, "MINI", 0); }
-mVUop(mVU_MINIi) { mVU_FMACa(mVU, recPass, 3, 4, 0, "MINIi", 0); }
-mVUop(mVU_MINIx) { mVU_FMACa(mVU, recPass, 2, 4, 0, "MINIx", 0); }
-mVUop(mVU_MINIy) { mVU_FMACa(mVU, recPass, 2, 4, 0, "MINIy", 0); }
-mVUop(mVU_MINIz) { mVU_FMACa(mVU, recPass, 2, 4, 0, "MINIz", 0); }
-mVUop(mVU_MINIw) { mVU_FMACa(mVU, recPass, 2, 4, 0, "MINIw", 0); }
-mVUop(mVU_FTOI0) { mVU_FTOIx(mX, NULL, "FTOI0"); }
-mVUop(mVU_FTOI4) { mVU_FTOIx(mX, mVUglob.FTOI_4, "FTOI4"); }
-mVUop(mVU_FTOI12) { mVU_FTOIx(mX, mVUglob.FTOI_12, "FTOI12"); }
-mVUop(mVU_FTOI15) { mVU_FTOIx(mX, mVUglob.FTOI_15, "FTOI15"); }
-mVUop(mVU_ITOF0) { mVU_ITOFx(mX, NULL, "ITOF0"); }
-mVUop(mVU_ITOF4) { mVU_ITOFx(mX, mVUglob.ITOF_4, "ITOF4"); }
-mVUop(mVU_ITOF12) { mVU_ITOFx(mX, mVUglob.ITOF_12, "ITOF12"); }
-mVUop(mVU_ITOF15) { mVU_ITOFx(mX, mVUglob.ITOF_15, "ITOF15"); }
-mVUop(mVU_NOP) { pass3 { mVUlog("NOP"); } }
+mVUop(mVU_ADD) { mVU_FMACa(mVU, recPass, 1, 0, 0, opADD, 0); }
+mVUop(mVU_ADDi) { mVU_FMACa(mVU, recPass, 3, 5, 0, opADDi, 0); }
+mVUop(mVU_ADDq) { mVU_FMACa(mVU, recPass, 4, 0, 0, opADDq, 0); }
+mVUop(mVU_ADDx) { mVU_FMACa(mVU, recPass, 2, 0, 0, opADDx, 0); }
+mVUop(mVU_ADDy) { mVU_FMACa(mVU, recPass, 2, 0, 0, opADDy, 0); }
+mVUop(mVU_ADDz) { mVU_FMACa(mVU, recPass, 2, 0, 0, opADDz, 0); }
+mVUop(mVU_ADDw) { mVU_FMACa(mVU, recPass, 2, 0, 0, opADDw, 0); }
+mVUop(mVU_ADDA) { mVU_FMACa(mVU, recPass, 1, 0, 1, opADDA, 0); }
+mVUop(mVU_ADDAi) { mVU_FMACa(mVU, recPass, 3, 0, 1, opADDAi, 0); }
+mVUop(mVU_ADDAq) { mVU_FMACa(mVU, recPass, 4, 0, 1, opADDAq, 0); }
+mVUop(mVU_ADDAx) { mVU_FMACa(mVU, recPass, 2, 0, 1, opADDAx, 0); }
+mVUop(mVU_ADDAy) { mVU_FMACa(mVU, recPass, 2, 0, 1, opADDAy, 0); }
+mVUop(mVU_ADDAz) { mVU_FMACa(mVU, recPass, 2, 0, 1, opADDAz, 0); }
+mVUop(mVU_ADDAw) { mVU_FMACa(mVU, recPass, 2, 0, 1, opADDAw, 0); }
+mVUop(mVU_SUB) { mVU_FMACa(mVU, recPass, 1, 1, 0, opSUB, (_XYZW_PS)?(cFs|cFt):0); } // Clamp (Kingdom Hearts I (VU0))
+mVUop(mVU_SUBi) { mVU_FMACa(mVU, recPass, 3, 1, 0, opSUBi, (_XYZW_PS)?(cFs|cFt):0); } // Clamp (Kingdom Hearts I (VU0))
+mVUop(mVU_SUBq) { mVU_FMACa(mVU, recPass, 4, 1, 0, opSUBq, (_XYZW_PS)?(cFs|cFt):0); } // Clamp (Kingdom Hearts I (VU0))
+mVUop(mVU_SUBx) { mVU_FMACa(mVU, recPass, 2, 1, 0, opSUBx, (_XYZW_PS)?(cFs|cFt):0); } // Clamp (Kingdom Hearts I (VU0))
+mVUop(mVU_SUBy) { mVU_FMACa(mVU, recPass, 2, 1, 0, opSUBy, (_XYZW_PS)?(cFs|cFt):0); } // Clamp (Kingdom Hearts I (VU0))
+mVUop(mVU_SUBz) { mVU_FMACa(mVU, recPass, 2, 1, 0, opSUBz, (_XYZW_PS)?(cFs|cFt):0); } // Clamp (Kingdom Hearts I (VU0))
+mVUop(mVU_SUBw) { mVU_FMACa(mVU, recPass, 2, 1, 0, opSUBw, (_XYZW_PS)?(cFs|cFt):0); } // Clamp (Kingdom Hearts I (VU0))
+mVUop(mVU_SUBA) { mVU_FMACa(mVU, recPass, 1, 1, 1, opSUBA, 0); }
+mVUop(mVU_SUBAi) { mVU_FMACa(mVU, recPass, 3, 1, 1, opSUBAi, 0); }
+mVUop(mVU_SUBAq) { mVU_FMACa(mVU, recPass, 4, 1, 1, opSUBAq, 0); }
+mVUop(mVU_SUBAx) { mVU_FMACa(mVU, recPass, 2, 1, 1, opSUBAx, 0); }
+mVUop(mVU_SUBAy) { mVU_FMACa(mVU, recPass, 2, 1, 1, opSUBAy, 0); }
+mVUop(mVU_SUBAz) { mVU_FMACa(mVU, recPass, 2, 1, 1, opSUBAz, 0); }
+mVUop(mVU_SUBAw) { mVU_FMACa(mVU, recPass, 2, 1, 1, opSUBAw, 0); }
+mVUop(mVU_MUL) { mVU_FMACa(mVU, recPass, 1, 2, 0, opMUL, (_XYZW_PS)?(cFs|cFt):cFs); } // Clamp (TOTA, DoM, Ice Age (VU0))
+mVUop(mVU_MULi) { mVU_FMACa(mVU, recPass, 3, 2, 0, opMULi, (_XYZW_PS)?(cFs|cFt):cFs); } // Clamp (TOTA, DoM, Ice Age (VU0))
+mVUop(mVU_MULq) { mVU_FMACa(mVU, recPass, 4, 2, 0, opMULq, (_XYZW_PS)?(cFs|cFt):cFs); } // Clamp (TOTA, DoM, Ice Age (VU0))
+mVUop(mVU_MULx) { mVU_FMACa(mVU, recPass, 2, 2, 0, opMULx, (_XYZW_PS)?(cFs|cFt):cFs); } // Clamp (TOTA, DoM, Ice Age (vu0))
+mVUop(mVU_MULy) { mVU_FMACa(mVU, recPass, 2, 2, 0, opMULy, (_XYZW_PS)?(cFs|cFt):cFs); } // Clamp (TOTA, DoM, Ice Age (VU0))
+mVUop(mVU_MULz) { mVU_FMACa(mVU, recPass, 2, 2, 0, opMULz, (_XYZW_PS)?(cFs|cFt):cFs); } // Clamp (TOTA, DoM, Ice Age (VU0))
+mVUop(mVU_MULw) { mVU_FMACa(mVU, recPass, 2, 2, 0, opMULw, (_XYZW_PS)?(cFs|cFt):cFs); } // Clamp (TOTA, DoM, Ice Age (VU0))
+mVUop(mVU_MULA) { mVU_FMACa(mVU, recPass, 1, 2, 1, opMULA, 0); }
+mVUop(mVU_MULAi) { mVU_FMACa(mVU, recPass, 3, 2, 1, opMULAi, 0); }
+mVUop(mVU_MULAq) { mVU_FMACa(mVU, recPass, 4, 2, 1, opMULAq, 0); }
+mVUop(mVU_MULAx) { mVU_FMACa(mVU, recPass, 2, 2, 1, opMULAx, cFs);} // Clamp (TOTA, DoM, ...)
+mVUop(mVU_MULAy) { mVU_FMACa(mVU, recPass, 2, 2, 1, opMULAy, cFs);} // Clamp (TOTA, DoM, ...)
+mVUop(mVU_MULAz) { mVU_FMACa(mVU, recPass, 2, 2, 1, opMULAz, cFs);} // Clamp (TOTA, DoM, ...)
+mVUop(mVU_MULAw) { mVU_FMACa(mVU, recPass, 2, 2, 1, opMULAw, cFs);} // Clamp (TOTA, DoM, ...)
+mVUop(mVU_MADD) { mVU_FMACc(mVU, recPass, 1, opMADD, 0); }
+mVUop(mVU_MADDi) { mVU_FMACc(mVU, recPass, 3, opMADDi, 0); }
+mVUop(mVU_MADDq) { mVU_FMACc(mVU, recPass, 4, opMADDq, 0); }
+mVUop(mVU_MADDx) { mVU_FMACc(mVU, recPass, 2, opMADDx, cFs);} // Clamp (TOTA, DoM, ...)
+mVUop(mVU_MADDy) { mVU_FMACc(mVU, recPass, 2, opMADDy, cFs);} // Clamp (TOTA, DoM, ...)
+mVUop(mVU_MADDz) { mVU_FMACc(mVU, recPass, 2, opMADDz, cFs);} // Clamp (TOTA, DoM, ...)
+mVUop(mVU_MADDw) { mVU_FMACc(mVU, recPass, 2, opMADDw, (isCOP2)?(cACC|cFt|cFs):cFs);} // Clamp (ICO (COP2), TOTA, DoM)
+mVUop(mVU_MADDA) { mVU_FMACb(mVU, recPass, 1, 0, opMADDA, 0); }
+mVUop(mVU_MADDAi) { mVU_FMACb(mVU, recPass, 3, 0, opMADDAi, 0); }
+mVUop(mVU_MADDAq) { mVU_FMACb(mVU, recPass, 4, 0, opMADDAq, 0); }
+mVUop(mVU_MADDAx) { mVU_FMACb(mVU, recPass, 2, 0, opMADDAx, cFs);} // Clamp (TOTA, DoM, ...)
+mVUop(mVU_MADDAy) { mVU_FMACb(mVU, recPass, 2, 0, opMADDAy, cFs);} // Clamp (TOTA, DoM, ...)
+mVUop(mVU_MADDAz) { mVU_FMACb(mVU, recPass, 2, 0, opMADDAz, cFs);} // Clamp (TOTA, DoM, ...)
+mVUop(mVU_MADDAw) { mVU_FMACb(mVU, recPass, 2, 0, opMADDAw, cFs);} // Clamp (TOTA, DoM, ...)
+mVUop(mVU_MSUB) { mVU_FMACd(mVU, recPass, 1, opMSUB, 0); }
+mVUop(mVU_MSUBi) { mVU_FMACd(mVU, recPass, 3, opMSUBi, 0); }
+mVUop(mVU_MSUBq) { mVU_FMACd(mVU, recPass, 4, opMSUBq, 0); }
+mVUop(mVU_MSUBx) { mVU_FMACd(mVU, recPass, 2, opMSUBx, 0); }
+mVUop(mVU_MSUBy) { mVU_FMACd(mVU, recPass, 2, opMSUBy, 0); }
+mVUop(mVU_MSUBz) { mVU_FMACd(mVU, recPass, 2, opMSUBz, 0); }
+mVUop(mVU_MSUBw) { mVU_FMACd(mVU, recPass, 2, opMSUBw, 0); }
+mVUop(mVU_MSUBA) { mVU_FMACb(mVU, recPass, 1, 1, opMSUBA, 0); }
+mVUop(mVU_MSUBAi) { mVU_FMACb(mVU, recPass, 3, 1, opMSUBAi, 0); }
+mVUop(mVU_MSUBAq) { mVU_FMACb(mVU, recPass, 4, 1, opMSUBAq, 0); }
+mVUop(mVU_MSUBAx) { mVU_FMACb(mVU, recPass, 2, 1, opMSUBAx, 0); }
+mVUop(mVU_MSUBAy) { mVU_FMACb(mVU, recPass, 2, 1, opMSUBAy, 0); }
+mVUop(mVU_MSUBAz) { mVU_FMACb(mVU, recPass, 2, 1, opMSUBAz, 0); }
+mVUop(mVU_MSUBAw) { mVU_FMACb(mVU, recPass, 2, 1, opMSUBAw, 0); }
+mVUop(mVU_MAX) { mVU_FMACa(mVU, recPass, 1, 3, 0, opMAX, 0); }
+mVUop(mVU_MAXi) { mVU_FMACa(mVU, recPass, 3, 3, 0, opMAXi, 0); }
+mVUop(mVU_MAXx) { mVU_FMACa(mVU, recPass, 2, 3, 0, opMAXx, 0); }
+mVUop(mVU_MAXy) { mVU_FMACa(mVU, recPass, 2, 3, 0, opMAXy, 0); }
+mVUop(mVU_MAXz) { mVU_FMACa(mVU, recPass, 2, 3, 0, opMAXz, 0); }
+mVUop(mVU_MAXw) { mVU_FMACa(mVU, recPass, 2, 3, 0, opMAXw, 0); }
+mVUop(mVU_MINI) { mVU_FMACa(mVU, recPass, 1, 4, 0, opMINI, 0); }
+mVUop(mVU_MINIi) { mVU_FMACa(mVU, recPass, 3, 4, 0, opMINIi, 0); }
+mVUop(mVU_MINIx) { mVU_FMACa(mVU, recPass, 2, 4, 0, opMINIx, 0); }
+mVUop(mVU_MINIy) { mVU_FMACa(mVU, recPass, 2, 4, 0, opMINIy, 0); }
+mVUop(mVU_MINIz) { mVU_FMACa(mVU, recPass, 2, 4, 0, opMINIz, 0); }
+mVUop(mVU_MINIw) { mVU_FMACa(mVU, recPass, 2, 4, 0, opMINIw, 0); }
+mVUop(mVU_FTOI0) { mVU_FTOIx(mX, NULL, opFTOI0); }
+mVUop(mVU_FTOI4) { mVU_FTOIx(mX, mVUglob.FTOI_4, opFTOI4); }
+mVUop(mVU_FTOI12) { mVU_FTOIx(mX, mVUglob.FTOI_12, opFTOI12); }
+mVUop(mVU_FTOI15) { mVU_FTOIx(mX, mVUglob.FTOI_15, opFTOI15); }
+mVUop(mVU_ITOF0) { mVU_ITOFx(mX, NULL, opITOF0); }
+mVUop(mVU_ITOF4) { mVU_ITOFx(mX, mVUglob.ITOF_4, opITOF4); }
+mVUop(mVU_ITOF12) { mVU_ITOFx(mX, mVUglob.ITOF_12, opITOF12); }
+mVUop(mVU_ITOF15) { mVU_ITOFx(mX, mVUglob.ITOF_15, opITOF15); }
+mVUop(mVU_NOP) { pass2 { mVU.profiler.EmitOp(opNOP); } pass3 { mVUlog("NOP"); } }