/[pcsx2_0.9.7]/trunk/pcsx2/x86/microVU_Compile.inl
ViewVC logotype

Annotation of /trunk/pcsx2/x86/microVU_Compile.inl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (hide annotations) (download)
Tue Sep 7 03:24:11 2010 UTC (9 years, 10 months ago) by william
File size: 16073 byte(s)
committing r3113 initial commit again...
1 william 31 /* PCSX2 - PS2 Emulator for PCs
2     * Copyright (C) 2002-2010 PCSX2 Dev Team
3     *
4     * PCSX2 is free software: you can redistribute it and/or modify it under the terms
5     * of the GNU Lesser General Public License as published by the Free Software Found-
6     * ation, either version 3 of the License, or (at your option) any later version.
7     *
8     * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9     * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10     * PURPOSE. See the GNU General Public License for more details.
11     *
12     * You should have received a copy of the GNU General Public License along with PCSX2.
13     * If not, see <http://www.gnu.org/licenses/>.
14     */
15    
16     #pragma once
17    
18     //------------------------------------------------------------------
19     // Helper Macros
20     //------------------------------------------------------------------
21    
22     #define calcCycles(reg, x) { reg = ((reg > x) ? (reg - x) : 0); }
23     #define optimizeReg(rState) { rState = (rState==1) ? 0 : rState; }
24     #define tCycles(dest, src) { dest = aMax(dest, src); }
25     #define incP() { mVU->p = (mVU->p+1) & 1; }
26     #define incQ() { mVU->q = (mVU->q+1) & 1; }
27     #define doUpperOp() { mVUopU(mVU, 1); mVUdivSet(mVU); }
28     #define doLowerOp() { incPC(-1); mVUopL(mVU, 1); incPC(1); }
29    
30     //------------------------------------------------------------------
31     // Helper Functions
32     //------------------------------------------------------------------
33    
34     // Used by mVUsetupRange
35     _f void mVUcheckIsSame(mV) {
36     if (mVU->prog.isSame == -1) {
37     mVU->prog.isSame = !memcmp_mmx((u8*)mVUcurProg.data, mVU->regs->Micro, mVU->microMemSize);
38     }
39     if (mVU->prog.isSame == 0) {
40     if (!isVU1) mVUcacheProg<0>(*mVU->prog.cur);
41     else mVUcacheProg<1>(*mVU->prog.cur);
42     mVU->prog.isSame = 1;
43     }
44     }
45    
46     // Sets up microProgram PC ranges based on whats been recompiled
47     _f void mVUsetupRange(microVU* mVU, s32 pc, bool isStartPC) {
48     deque<microRange>*& ranges = mVUcurProg.ranges;
49     pc &= mVU->microMemSize - 8;
50    
51     if (isStartPC) { // Check if startPC is already within a block we've recompiled
52     deque<microRange>::const_iterator it = ranges->begin();
53     for ( ; it != ranges->end(); it++) {
54     if ((pc >= it[0].start) && (pc <= it[0].end)) {
55     if (it[0].start != it[0].end)
56     return; // Last case makes sure its not a 1-opcode EvilBlock
57     }
58     }
59     }
60     elif (mVUrange.end != -1) return; // Above case was true
61    
62     mVUcheckIsSame(mVU);
63    
64     if (isStartPC) {
65     microRange mRange = {pc, -1};
66     ranges->push_front(mRange);
67     return;
68     }
69     if (mVUrange.start <= pc) {
70     mVUrange.end = pc;
71     bool mergedRange = 0;
72     s32 rStart = mVUrange.start;
73     s32 rEnd = mVUrange.end;
74     deque<microRange>::iterator it = ranges->begin();
75     for (it++; it != ranges->end(); it++) {
76     if((it[0].start >= rStart) && (it[0].start <= rEnd)) {
77     it[0].end = aMax(it[0].end, rEnd);
78     mergedRange = 1;
79     }
80     elif((it[0].end >= rStart) && (it[0].end <= rEnd)) {
81     it[0].start = aMin(it[0].start, rStart);
82     mergedRange = 1;
83     }
84     }
85     if (mergedRange) {
86     //DevCon.WriteLn(Color_Green, "microVU%d: Prog Range Merging", mVU->index);
87     ranges->erase(ranges->begin());
88     }
89     }
90     else {
91     //DevCon.WriteLn(Color_Green, "microVU%d: Prog Range Wrap [%04x] [%d]", mVU->index, mVUrange.start, mVUrange.end);
92     mVUrange.end = mVU->microMemSize;
93     microRange mRange = {0, pc};
94     ranges->push_front(mRange);
95     }
96     }
97    
98     _f void startLoop(mV) {
99     if (curI & _Mbit_) { Console.WriteLn(Color_Green, "microVU%d: M-bit set!", getIndex); }
100     if (curI & _Dbit_) { DevCon.WriteLn (Color_Green, "microVU%d: D-bit set!", getIndex); }
101     if (curI & _Tbit_) { DevCon.WriteLn (Color_Green, "microVU%d: T-bit set!", getIndex); }
102     memzero(mVUinfo);
103     memzero(mVUregsTemp);
104     }
105    
106     _f void doIbit(mV) {
107     if (mVUup.iBit) {
108     incPC(-1);
109     u32 tempI;
110     mVU->regAlloc->clearRegVF(33);
111    
112     if (CHECK_VU_OVERFLOW && ((curI & 0x7fffffff) >= 0x7f800000)) {
113     Console.WriteLn(Color_Green,"microVU%d: Clamping I Reg", mVU->index);
114     tempI = (0x80000000 & curI) | 0x7f7fffff; // Clamp I Reg
115     }
116     else tempI = curI;
117    
118     MOV32ItoM((uptr)&mVU->regs->VI[REG_I].UL, tempI);
119     incPC(1);
120     }
121     }
122    
123     _f void doSwapOp(mV) {
124     if (mVUinfo.backupVF && !mVUlow.noWriteVF) {
125     DevCon.WriteLn(Color_Green, "microVU%d: Backing Up VF Reg [%04x]", getIndex, xPC);
126     int t1 = mVU->regAlloc->allocReg(mVUlow.VF_write.reg);
127     int t2 = mVU->regAlloc->allocReg();
128     SSE_MOVAPS_XMM_to_XMM(t2, t1);
129     mVU->regAlloc->clearNeeded(t1);
130     mVUopL(mVU, 1);
131     t1 = mVU->regAlloc->allocReg(mVUlow.VF_write.reg, mVUlow.VF_write.reg, 0xf, 0);
132     SSE_XORPS_XMM_to_XMM(t2, t1);
133     SSE_XORPS_XMM_to_XMM(t1, t2);
134     SSE_XORPS_XMM_to_XMM(t2, t1);
135     mVU->regAlloc->clearNeeded(t1);
136     incPC(1);
137     doUpperOp();
138     t1 = mVU->regAlloc->allocReg(-1, mVUlow.VF_write.reg, 0xf);
139     SSE_MOVAPS_XMM_to_XMM(t1, t2);
140     mVU->regAlloc->clearNeeded(t1);
141     mVU->regAlloc->clearNeeded(t2);
142     }
143     else { mVUopL(mVU, 1); incPC(1); doUpperOp(); }
144     }
145    
146     _f void branchWarning(mV) {
147     incPC(-2);
148     if (mVUup.eBit && mVUbranch) {
149     incPC(2);
150     Console.Error("microVU%d Warning: Branch in E-bit delay slot! [%04x]", mVU->index, xPC);
151     mVUlow.isNOP = 1;
152     }
153     else incPC(2);
154     if (mVUinfo.isBdelay) { // Check if VI Reg Written to on Branch Delay Slot Instruction
155     if (mVUlow.VI_write.reg && mVUlow.VI_write.used && !mVUlow.readFlags) {
156     mVUlow.backupVI = 1;
157     mVUregs.viBackUp = mVUlow.VI_write.reg;
158     }
159     }
160     }
161    
162     _f void eBitPass1(mV, int& branch) {
163     if (mVUregs.blockType != 1) {
164     branch = 1;
165     mVUup.eBit = 1;
166     }
167     }
168    
169     _f void eBitWarning(mV) {
170     if (mVUpBlock->pState.blockType == 1) Console.Error("microVU%d Warning: Branch, E-bit, Branch! [%04x]", mVU->index, xPC);
171     if (mVUpBlock->pState.blockType == 2) Console.Error("microVU%d Warning: Branch, Branch, Branch! [%04x]", mVU->index, xPC);
172     incPC(2);
173     if (curI & _Ebit_) {
174     DevCon.Warning("microVU%d: E-bit in Branch delay slot! [%04x]", mVU->index, xPC);
175     mVUregs.blockType = 1;
176     }
177     incPC(-2);
178     }
179    
180     // Optimizes the End Pipeline State Removing Unnecessary Info
181     _f void mVUoptimizePipeState(mV) {
182     for (int i = 0; i < 32; i++) {
183     optimizeReg(mVUregs.VF[i].x);
184     optimizeReg(mVUregs.VF[i].y);
185     optimizeReg(mVUregs.VF[i].z);
186     optimizeReg(mVUregs.VF[i].w);
187     }
188     for (int i = 0; i < 16; i++) {
189     optimizeReg(mVUregs.VI[i]);
190     }
191     if (mVUregs.q) { optimizeReg(mVUregs.q); if (!mVUregs.q) { incQ(); } }
192     if (mVUregs.p) { optimizeReg(mVUregs.p); if (!mVUregs.p) { incP(); } }
193     mVUregs.r = 0; // There are no stalls on the R-reg, so its Safe to discard info
194     }
195    
196     _f void mVUincCycles(mV, int x) {
197     mVUcycles += x;
198     for (int z = 31; z > 0; z--) {
199     calcCycles(mVUregs.VF[z].x, x);
200     calcCycles(mVUregs.VF[z].y, x);
201     calcCycles(mVUregs.VF[z].z, x);
202     calcCycles(mVUregs.VF[z].w, x);
203     }
204     for (int z = 16; z > 0; z--) {
205     calcCycles(mVUregs.VI[z], x);
206     }
207     if (mVUregs.q) {
208     if (mVUregs.q > 4) { calcCycles(mVUregs.q, x); if (mVUregs.q <= 4) { mVUinfo.doDivFlag = 1; } }
209     else { calcCycles(mVUregs.q, x); }
210     if (!mVUregs.q) { incQ(); }
211     }
212     if (mVUregs.p) {
213     calcCycles(mVUregs.p, x);
214     if (!mVUregs.p || mVUregsTemp.p) { incP(); }
215     }
216     if (mVUregs.xgkick) {
217     calcCycles(mVUregs.xgkick, x);
218     if (!mVUregs.xgkick) { mVUinfo.doXGKICK = 1; }
219     }
220     calcCycles(mVUregs.r, x);
221     }
222    
223     #define cmpVFregs(VFreg1, VFreg2, xVar) { \
224     if (VFreg1.reg == VFreg2.reg) { \
225     if ((VFreg1.x && VFreg2.x) \
226     || (VFreg1.y && VFreg2.y) \
227     || (VFreg1.z && VFreg2.z) \
228     || (VFreg1.w && VFreg2.w)) \
229     { xVar = 1; } \
230     } \
231     }
232    
233     _f void mVUsetCycles(mV) {
234     mVUincCycles(mVU, mVUstall);
235     // If upper Op && lower Op write to same VF reg:
236     if ((mVUregsTemp.VFreg[0] == mVUregsTemp.VFreg[1]) && mVUregsTemp.VFreg[0]) {
237     if (mVUregsTemp.r || mVUregsTemp.VI) mVUlow.noWriteVF = 1;
238     else mVUlow.isNOP = 1; // If lower Op doesn't modify anything else, then make it a NOP
239     }
240     // If lower op reads a VF reg that upper Op writes to:
241     if ((mVUlow.VF_read[0].reg || mVUlow.VF_read[1].reg) && mVUup.VF_write.reg) {
242     cmpVFregs(mVUup.VF_write, mVUlow.VF_read[0], mVUinfo.swapOps);
243     cmpVFregs(mVUup.VF_write, mVUlow.VF_read[1], mVUinfo.swapOps);
244     }
245     // If above case is true, and upper op reads a VF reg that lower Op Writes to:
246     if (mVUinfo.swapOps && ((mVUup.VF_read[0].reg || mVUup.VF_read[1].reg) && mVUlow.VF_write.reg)) {
247     cmpVFregs(mVUlow.VF_write, mVUup.VF_read[0], mVUinfo.backupVF);
248     cmpVFregs(mVUlow.VF_write, mVUup.VF_read[1], mVUinfo.backupVF);
249     }
250    
251     tCycles(mVUregs.VF[mVUregsTemp.VFreg[0]].x, mVUregsTemp.VF[0].x);
252     tCycles(mVUregs.VF[mVUregsTemp.VFreg[0]].y, mVUregsTemp.VF[0].y);
253     tCycles(mVUregs.VF[mVUregsTemp.VFreg[0]].z, mVUregsTemp.VF[0].z);
254     tCycles(mVUregs.VF[mVUregsTemp.VFreg[0]].w, mVUregsTemp.VF[0].w);
255    
256     tCycles(mVUregs.VF[mVUregsTemp.VFreg[1]].x, mVUregsTemp.VF[1].x);
257     tCycles(mVUregs.VF[mVUregsTemp.VFreg[1]].y, mVUregsTemp.VF[1].y);
258     tCycles(mVUregs.VF[mVUregsTemp.VFreg[1]].z, mVUregsTemp.VF[1].z);
259     tCycles(mVUregs.VF[mVUregsTemp.VFreg[1]].w, mVUregsTemp.VF[1].w);
260    
261     tCycles(mVUregs.VI[mVUregsTemp.VIreg], mVUregsTemp.VI);
262     tCycles(mVUregs.q, mVUregsTemp.q);
263     tCycles(mVUregs.p, mVUregsTemp.p);
264     tCycles(mVUregs.r, mVUregsTemp.r);
265     tCycles(mVUregs.xgkick, mVUregsTemp.xgkick);
266     }
267    
268     void __fastcall mVUwarning0(mV) { Console.Error("microVU0 Warning: Exiting from Possible Infinite Loop [%04x] [%x]", xPC, mVU->prog.cur); }
269     void __fastcall mVUwarning1(mV) { Console.Error("microVU1 Warning: Exiting from Possible Infinite Loop [%04x] [%x]", xPC, mVU->prog.cur); }
270     void __fastcall mVUprintPC1(u32 PC) { Console.Write("Block PC [%04x] ", PC); }
271     void __fastcall mVUprintPC2(u32 PC) { Console.Write("[%04x]\n", PC); }
272    
273     // vu0 is allowed to exit early, so are dev builds (for inf loops)
274     _f bool doEarlyExit(microVU* mVU) {
275     return IsDevBuild || !isVU1;
276     }
277    
278     // Saves Pipeline State for resuming from early exits
279     _f void mVUsavePipelineState(microVU* mVU) {
280     u32* lpS = (u32*)&mVU->prog.lpState.vi15;
281     for (int i = 0; i < (sizeof(microRegInfo)-4)/4; i++, lpS++) {
282     MOV32ItoM((uptr)lpS, lpS[0]);
283     }
284     }
285    
286     _f void mVUtestCycles(microVU* mVU) {
287     //u32* vu0jmp;
288     iPC = mVUstartPC;
289     mVUdebugNOW(0);
290     if (doEarlyExit(mVU)) {
291     CMP32ItoM((uptr)&mVU->cycles, 0);
292     u32* jmp32 = JG32(0);
293     //if (!isVU1) { TEST32ItoM((uptr)&mVU->regs->flags, VUFLAG_MFLAGSET); vu0jmp = JZ32(0); }
294     MOV32ItoR(gprT2, (uptr)mVU);
295     if (isVU1) CALLFunc((uptr)mVUwarning1);
296     //else CALLFunc((uptr)mVUwarning0); // VU0 is allowed early exit for COP2 Interlock Simulation
297     mVUsavePipelineState(mVU);
298     mVUendProgram(mVU, NULL, 0);
299     //if (!isVU1) x86SetJ32(vu0jmp);
300     x86SetJ32(jmp32);
301     }
302     SUB32ItoM((uptr)&mVU->cycles, mVUcycles);
303     }
304    
305     // Initialize VI Constants (vi15 propagates through blocks)
306     _f void mVUinitConstValues(microVU* mVU) {
307     for (int i = 0; i < 16; i++) {
308     mVUconstReg[i].isValid = 0;
309     mVUconstReg[i].regValue = 0;
310     }
311     mVUconstReg[15].isValid = mVUregs.vi15 >> 31;
312     mVUconstReg[15].regValue = mVUconstReg[15].isValid ? (mVUregs.vi15&0xffff) : 0;
313     }
314    
315     // Initialize Variables
316     _f void mVUinitFirstPass(microVU* mVU, uptr pState, u8* thisPtr) {
317     mVUstartPC = iPC; // Block Start PC
318     mVUbranch = 0; // Branch Type
319     mVUcount = 0; // Number of instructions ran
320     mVUcycles = 0; // Skips "M" phase, and starts counting cycles at "T" stage
321     mVU->p = 0; // All blocks start at p index #0
322     mVU->q = 0; // All blocks start at q index #0
323     if ((uptr)&mVUregs != pState) { // Loads up Pipeline State Info
324     memcpy_const((u8*)&mVUregs, (u8*)pState, sizeof(microRegInfo));
325     }
326     if (doEarlyExit(mVU) && ((uptr)&mVU->prog.lpState != pState)) {
327     memcpy_const((u8*)&mVU->prog.lpState, (u8*)pState, sizeof(microRegInfo));
328     }
329     mVUblock.x86ptrStart = thisPtr;
330     mVUpBlock = mVUblocks[mVUstartPC/2]->add(&mVUblock); // Add this block to block manager
331     mVUregs.blockType = 0;
332     mVUregs.viBackUp = 0;
333     mVUregs.flags = 0;
334     mVUregs.needExactMatch = 0;
335     mVUsFlagHack = CHECK_VU_FLAGHACK;
336     mVUinitConstValues(mVU);
337     }
338    
339     //------------------------------------------------------------------
340     // Recompiler
341     //------------------------------------------------------------------
342    
343     _r void* mVUcompile(microVU* mVU, u32 startPC, uptr pState) {
344    
345     microFlagCycles mFC;
346     u8* thisPtr = x86Ptr;
347     const u32 endCount = (((microRegInfo*)pState)->blockType) ? 1 : (mVU->microMemSize / 8);
348    
349     // First Pass
350     iPC = startPC / 4;
351     mVUsetupRange(mVU, startPC, 1); // Setup Program Bounds/Range
352     mVU->regAlloc->reset(); // Reset regAlloc
353     mVUinitFirstPass(mVU, pState, thisPtr);
354     for (int branch = 0; mVUcount < endCount; mVUcount++) {
355     incPC(1);
356     startLoop(mVU);
357     mVUincCycles(mVU, 1);
358     mVUopU(mVU, 0);
359     if (curI & _Ebit_) { eBitPass1(mVU, branch); }
360     if (curI & _DTbit_) { branch = 4; }
361     if (curI & _Mbit_) { mVUup.mBit = 1; }
362     if (curI & _Ibit_) { mVUlow.isNOP = 1; mVUup.iBit = 1; }
363     else { incPC(-1); mVUopL(mVU, 0); incPC(1); }
364     mVUsetCycles(mVU);
365     mVUinfo.readQ = mVU->q;
366     mVUinfo.writeQ = !mVU->q;
367     mVUinfo.readP = mVU->p;
368     mVUinfo.writeP = !mVU->p;
369     if (branch >= 2) { mVUinfo.isEOB = 1; if (branch == 3) { mVUinfo.isBdelay = 1; } mVUcount++; branchWarning(mVU); break; }
370     else if (branch == 1) { branch = 2; }
371     if (mVUbranch) { mVUsetFlagInfo(mVU); eBitWarning(mVU); branch = 3; mVUbranch = 0; }
372     incPC(1);
373     }
374    
375     // Fix up vi15 const info for propagation through blocks
376     mVUregs.vi15 = (mVUconstReg[15].isValid && CHECK_VU_CONSTPROP) ? ((1<<31) | (mVUconstReg[15].regValue&0xffff)) : 0;
377    
378     mVUsetFlags(mVU, mFC); // Sets Up Flag instances
379     mVUoptimizePipeState(mVU); // Optimize the End Pipeline State for nicer Block Linking
380     mVUtestCycles(mVU); // Update VU Cycles and Exit Early if Necessary
381    
382     // Second Pass
383     iPC = mVUstartPC;
384     setCode();
385     mVUbranch = 0;
386     u32 x = 0;
387     for (; x < endCount; x++) {
388     if (mVUinfo.isEOB) { x = 0xffff; }
389     if (mVUup.mBit) { OR32ItoM((uptr)&mVU->regs->flags, VUFLAG_MFLAGSET); }
390     if (mVUlow.isNOP) { incPC(1); doUpperOp(); doIbit(mVU); }
391     else if (!mVUinfo.swapOps) { incPC(1); doUpperOp(); doLowerOp(); }
392     else { doSwapOp(mVU); }
393     if (mVUinfo.doXGKICK) { mVU_XGKICK_DELAY(mVU, 1); }
394     if (!doRegAlloc) { mVU->regAlloc->flushAll(); }
395     if (isEvilBlock) { mVUsetupRange(mVU, xPC, 0); normJumpCompile(mVU, mFC, 1); return thisPtr; }
396     else if (!mVUinfo.isBdelay) { incPC(1); }
397     else {
398     mVUsetupRange(mVU, xPC, 0);
399     mVUdebugNOW(1);
400     incPC(-3); // Go back to branch opcode
401     switch (mVUlow.branch) {
402     case 1: case 2: normBranch(mVU, mFC); return thisPtr; // B/BAL
403     case 9: case 10: normJump (mVU, mFC); return thisPtr; // JR/JALR
404     case 3: condBranch(mVU, mFC, Jcc_Equal); return thisPtr; // IBEQ
405     case 4: condBranch(mVU, mFC, Jcc_GreaterOrEqual); return thisPtr; // IBGEZ
406     case 5: condBranch(mVU, mFC, Jcc_Greater); return thisPtr; // IBGTZ
407     case 6: condBranch(mVU, mFC, Jcc_LessOrEqual); return thisPtr; // IBLEQ
408     case 7: condBranch(mVU, mFC, Jcc_Less); return thisPtr; // IBLTZ
409     case 8: condBranch(mVU, mFC, Jcc_NotEqual); return thisPtr; // IBNEQ
410     }
411     }
412     }
413     if ((x == endCount) && (x!=1)) { Console.Error("microVU%d: Possible infinite compiling loop!", mVU->index); }
414    
415     // E-bit End
416     mVUsetupRange(mVU, xPC-8, 0);
417     mVUendProgram(mVU, &mFC, 1);
418     return thisPtr;
419     }
420    
421     // Returns the entry point of the block (compiles it if not found)
422     _f void* mVUentryGet(microVU* mVU, microBlockManager* block, u32 startPC, uptr pState) {
423     microBlock* pBlock = block->search((microRegInfo*)pState);
424     if (pBlock) return pBlock->x86ptrStart;
425     else return mVUcompile(mVU, startPC, pState);
426     }
427    
428     // Search for Existing Compiled Block (if found, return x86ptr; else, compile and return x86ptr)
429     _f void* mVUblockFetch(microVU* mVU, u32 startPC, uptr pState) {
430    
431     if (startPC > mVU->microMemSize-8) { DevCon.Error("microVU%d: invalid startPC [%04x]", mVU->index, startPC); }
432     startPC &= mVU->microMemSize-8;
433    
434     blockCreate(startPC/8);
435     return mVUentryGet(mVU, mVUblocks[startPC/8], startPC, pState);
436     }
437    
438     // mVUcompileJIT() - Called By JR/JALR during execution
439     _mVUt void* __fastcall mVUcompileJIT(u32 startPC, uptr pState) {
440     //return mVUblockFetch(mVUx, startPC, pState);
441     return mVUsearchProg<vuIndex>(startPC, pState); // Find and set correct program
442     }

  ViewVC Help
Powered by ViewVC 1.1.22