/[pcsx2_0.9.7]/trunk/pcsx2/x86/newVif_Dynarec.cpp
ViewVC logotype

Contents of /trunk/pcsx2/x86/newVif_Dynarec.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 280 - (show annotations) (download)
Thu Dec 23 12:02:12 2010 UTC (9 years, 2 months ago) by william
File size: 9573 byte(s)
re-commit (had local access denied errors when committing)
1 /* 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 // newVif Dynarec - Dynamically Recompiles Vif 'unpack' Packets
17 // authors: cottonvibes(@gmail.com)
18 // Jake.Stine (@gmail.com)
19
20 #include "PrecompiledHeader.h"
21 #include "newVif_UnpackSSE.h"
22
23 static __aligned16 nVifBlock _vBlock = {0};
24
25 void dVifReserve(int idx)
26 {
27 if (!nVif[idx].recReserve)
28 nVif[idx].recReserve = new RecompiledCodeReserve(pxsFmt(L"VIF%u Unpack Recompiler Cache", idx));
29
30 nVif[idx].recReserve->Reserve( nVif[idx].recReserveSizeMB * _1mb, idx ? HostMemoryMap::VIF1rec : HostMemoryMap::VIF0rec );
31 }
32
33 void dVifReset(int idx) {
34
35 if( !nVif[idx].vifBlocks )
36 nVif[idx].vifBlocks = new HashBucket<_tParams>();
37 else
38 nVif[idx].vifBlocks->clear();
39
40 nVif[idx].recReserve->Reset();
41 nVif[idx].numBlocks = 0;
42 nVif[idx].recWritePtr = nVif[idx].recReserve->GetPtr();
43 }
44
45 void dVifClose(int idx) {
46 nVif[idx].numBlocks = 0;
47 nVif[idx].recReserve->Reset();
48
49 safe_delete(nVif[idx].vifBlocks);
50 }
51
52 void dVifRelease(int idx) {
53 safe_delete(nVif[idx].recReserve);
54 }
55
56 VifUnpackSSE_Dynarec::VifUnpackSSE_Dynarec(const nVifStruct& vif_, const nVifBlock& vifBlock_)
57 : v(vif_)
58 , vB(vifBlock_)
59 {
60 isFill = (vB.cl < vB.wl);
61 usn = (vB.upkType>>5) & 1;
62 doMask = (vB.upkType>>4) & 1;
63 doMode = vB.mode & 3;
64 vCL = 0;
65 }
66
67 #define makeMergeMask(x) { \
68 x = ((x&0x40)>>6) | ((x&0x10)>>3) | (x&4) | ((x&1)<<3); \
69 }
70
71 __fi void VifUnpackSSE_Dynarec::SetMasks(int cS) const {
72 const vifStruct& vif = v.idx ? vif1 : vif0;
73
74 u32 m0 = vB.mask;
75 u32 m1 = m0 & 0xaaaaaaaa;
76 u32 m2 =(~m1>>1) & m0;
77 u32 m3 = (m1>>1) & ~m0;
78 if((m2&&(doMask||isFill))||doMode) { xMOVAPS(xmmRow, ptr128[&vif.MaskRow]); }
79 if (m3&&(doMask||isFill)) {
80 xMOVAPS(xmmCol0, ptr128[&vif.MaskCol]);
81 if ((cS>=2) && (m3&0x0000ff00)) xPSHUF.D(xmmCol1, xmmCol0, _v1);
82 if ((cS>=3) && (m3&0x00ff0000)) xPSHUF.D(xmmCol2, xmmCol0, _v2);
83 if ((cS>=4) && (m3&0xff000000)) xPSHUF.D(xmmCol3, xmmCol0, _v3);
84 if ((cS>=1) && (m3&0x000000ff)) xPSHUF.D(xmmCol0, xmmCol0, _v0);
85 }
86 //if (doMask||doMode) loadRowCol((nVifStruct&)v);
87 }
88
89 void VifUnpackSSE_Dynarec::doMaskWrite(const xRegisterSSE& regX) const {
90 pxAssumeDev(regX.Id <= 1, "Reg Overflow! XMM2 thru XMM6 are reserved for masking.");
91 xRegisterSSE t = regX == xmm0 ? xmm1 : xmm0; // Get Temp Reg
92 int cc = aMin(vCL, 3);
93 u32 m0 = (vB.mask >> (cc * 8)) & 0xff;
94 u32 m1 = m0 & 0xaa;
95 u32 m2 =(~m1>>1) & m0;
96 u32 m3 = (m1>>1) & ~m0;
97 u32 m4 = (m1>>1) & m0;
98 makeMergeMask(m2);
99 makeMergeMask(m3);
100 makeMergeMask(m4);
101 if (doMask&&m4) { xMOVAPS(xmmTemp, ptr[dstIndirect]); } // Load Write Protect
102 if (doMask&&m2) { mergeVectors(regX, xmmRow, t, m2); } // Merge MaskRow
103 if (doMask&&m3) { mergeVectors(regX, xRegisterSSE(xmmCol0.Id+cc), t, m3); } // Merge MaskCol
104 if (doMask&&m4) { mergeVectors(regX, xmmTemp, t, m4); } // Merge Write Protect
105 if (doMode) {
106 u32 m5 = (~m1>>1) & ~m0;
107 if (!doMask) m5 = 0xf;
108 else makeMergeMask(m5);
109 if (m5 < 0xf) {
110 xPXOR(xmmTemp, xmmTemp);
111 mergeVectors(xmmTemp, xmmRow, t, m5);
112 xPADD.D(regX, xmmTemp);
113 if (doMode==2) mergeVectors(xmmRow, regX, t, m5);
114 }
115 else if (m5 == 0xf) {
116 xPADD.D(regX, xmmRow);
117 if (doMode==2) xMOVAPS(xmmRow, regX);
118 }
119 }
120 xMOVAPS(ptr32[dstIndirect], regX);
121 }
122
123 void VifUnpackSSE_Dynarec::writeBackRow() const {
124 xMOVAPS(ptr128[&((v.idx ? vif1 : vif0).MaskRow)], xmmRow);
125 DevCon.WriteLn("nVif: writing back row reg! [doMode = 2]");
126 // ToDo: Do we need to write back to vifregs.rX too!? :/
127 }
128
129 static void ShiftDisplacementWindow( xAddressVoid& addr, const xRegister32& modReg )
130 {
131 // Shifts the displacement factor of a given indirect address, so that the address
132 // remains in the optimal 0xf0 range (which allows for byte-form displacements when
133 // generating instructions).
134
135 int addImm = 0;
136 while( addr.Displacement >= 0x80 )
137 {
138 addImm += 0xf0;
139 addr -= 0xf0;
140 }
141 if(addImm) xADD(modReg, addImm);
142 }
143
144 void VifUnpackSSE_Dynarec::CompileRoutine() {
145 const int upkNum = vB.upkType & 0xf;
146 const u8& vift = nVifT[upkNum];
147 const int cycleSize = isFill ? vB.cl : vB.wl;
148 const int blockSize = isFill ? vB.wl : vB.cl;
149 const int skipSize = blockSize - cycleSize;
150
151 uint vNum = vB.num ? vB.num : 256;
152 doMode = (upkNum == 0xf) ? 0 : doMode; // V4_5 has no mode feature.
153
154 pxAssume(vCL == 0);
155
156 // Value passed determines # of col regs we need to load
157 SetMasks(isFill ? blockSize : cycleSize);
158
159 while (vNum) {
160
161 ShiftDisplacementWindow( srcIndirect, edx );
162 ShiftDisplacementWindow( dstIndirect, ecx );
163
164 if (vCL < cycleSize) {
165 xUnpack(upkNum);
166 xMovDest();
167
168 dstIndirect += 16;
169 srcIndirect += vift;
170
171 if( IsUnmaskedOp() ) {
172 ++destReg;
173 ++workReg;
174 }
175
176 vNum--;
177 if (++vCL == blockSize) vCL = 0;
178 }
179 else if (isFill) {
180 //DevCon.WriteLn("filling mode!");
181 VifUnpackSSE_Dynarec fill( VifUnpackSSE_Dynarec::FillingWrite( *this ) );
182 fill.xUnpack(upkNum);
183 fill.xMovDest();
184
185 dstIndirect += 16;
186 vNum--;
187 if (++vCL == blockSize) vCL = 0;
188 }
189 else {
190 dstIndirect += (16 * skipSize);
191 vCL = 0;
192 }
193 }
194
195 if (doMode==2) writeBackRow();
196 xRET();
197 }
198
199 _vifT static __fi u8* dVifsetVUptr(uint cl, uint wl, bool isFill) {
200 vifStruct& vif = GetVifX;
201 VIFregisters& vifRegs = vifXRegs;
202 const VURegs& VU = vuRegs[idx];
203 const uint vuMemLimit = idx ? 0x4000 : 0x1000;
204
205 u8* startmem = VU.Mem + (vif.tag.addr & (vuMemLimit-0x10));
206 u8* endmem = VU.Mem + vuMemLimit;
207 uint length = (_vBlock.num > 0) ? (_vBlock.num * 16) : 4096; // 0 = 256
208
209 if (!isFill) {
210 // Accounting for skipping mode: Subtract the last skip cycle, since the skipped part of the run
211 // shouldn't count as wrapped data. Otherwise, a trailing skip can cause the emu to drop back
212 // to the interpreter. -- Refraction (test with MGS3)
213
214 uint skipSize = (cl - wl) * 16;
215 uint blocks = _vBlock.num / wl;
216 length += (blocks-1) * skipSize;
217 }
218
219 if ( (startmem+length) <= endmem ) {
220 return startmem;
221 }
222 //Console.WriteLn("nVif%x - VU Mem Ptr Overflow; falling back to interpreter. Start = %x End = %x num = %x, wl = %x, cl = %x", v.idx, vif.tag.addr, vif.tag.addr + (_vBlock.num * 16), _vBlock.num, wl, cl);
223 return NULL; // Fall Back to Interpreters which have wrap-around logic
224 }
225
226 // [TODO] : Finish implementing support for VIF's growable recBlocks buffer. Currently
227 // it clears the buffer only.
228 static __fi void dVifRecLimit(int idx) {
229 if (nVif[idx].recWritePtr > (nVif[idx].recReserve->GetPtrEnd() - _256kb)) {
230 DevCon.WriteLn("nVif Recompiler Cache Reset! [0x%08x > 0x%08x]", nVif[idx].recWritePtr, nVif[idx].recReserve->GetPtrEnd());
231 nVif[idx].recReserve->Reset();
232 nVif[idx].recWritePtr = nVif[idx].recReserve->GetPtr();
233 }
234 }
235
236 _vifT static __fi bool dVifExecuteUnpack(const u8* data, bool isFill)
237 {
238 const nVifStruct& v = nVif[idx];
239 VIFregisters& vifRegs = vifXRegs;
240
241 if (nVifBlock* b = v.vifBlocks->find(&_vBlock)) {
242 if (u8* dest = dVifsetVUptr<idx>(vifRegs.cycle.cl, vifRegs.cycle.wl, isFill)) {
243 //DevCon.WriteLn("Running Recompiled Block!");
244 ((nVifrecCall)b->startPtr)((uptr)dest, (uptr)data);
245 }
246 else {
247 //DevCon.WriteLn("Running Interpreter Block");
248 _nVifUnpack(idx, data, vifRegs.mode, isFill);
249 }
250 return true;
251 }
252 return false;
253 }
254
255 _vifT __fi void dVifUnpack(const u8* data, bool isFill) {
256
257 const nVifStruct& v = nVif[idx];
258 vifStruct& vif = GetVifX;
259 VIFregisters& vifRegs = vifXRegs;
260
261 const u8 upkType = (vif.cmd & 0x1f) | (vif.usn << 5);
262 const int doMask = (vif.cmd & 0x10);
263
264 _vBlock.upkType = upkType;
265 _vBlock.num = (u8&)vifRegs.num;
266 _vBlock.mode = (u8&)vifRegs.mode;
267 _vBlock.cl = vifRegs.cycle.cl;
268 _vBlock.wl = vifRegs.cycle.wl;
269
270 // Zero out the mask parameter if it's unused -- games leave random junk
271 // values here which cause false recblock cache misses.
272 _vBlock.mask = doMask ? vifRegs.mask : 0;
273
274 //DevCon.WriteLn("nVif%d: Recompiled Block! [%d]", idx, nVif[idx].numBlocks++);
275 //DevCon.WriteLn(L"[num=% 3d][upkType=0x%02x][scl=%d][cl=%d][wl=%d][mode=%d][m=%d][mask=%s]",
276 // _vBlock.num, _vBlock.upkType, _vBlock.scl, _vBlock.cl, _vBlock.wl, _vBlock.mode,
277 // doMask >> 4, doMask ? wxsFormat( L"0x%08x", _vBlock.mask ).c_str() : L"ignored"
278 //);
279
280 if (dVifExecuteUnpack<idx>(data, isFill)) return;
281
282 xSetPtr(v.recWritePtr);
283 _vBlock.startPtr = (uptr)xGetAlignedCallTarget();
284 v.vifBlocks->add(_vBlock);
285 VifUnpackSSE_Dynarec( v, _vBlock ).CompileRoutine();
286 nVif[idx].recWritePtr = xGetPtr();
287
288 // [TODO] : Ideally we should test recompile buffer limits prior to each instruction,
289 // which would be safer and more memory efficient than using an 0.25 meg recEnd marker.
290 dVifRecLimit(idx);
291
292 // Run the block we just compiled. Various conditions may force us to still use
293 // the interpreter unpacker though, so a recursive call is the safest way here...
294 dVifExecuteUnpack<idx>(data, isFill);
295 }
296
297 template void dVifUnpack<0>(const u8* data, bool isFill);
298 template void dVifUnpack<1>(const u8* data, bool isFill);

  ViewVC Help
Powered by ViewVC 1.1.22