/[pcsx2_0.9.7]/trunk/pcsx2/x86/ix86-32/recVTLB.cpp
ViewVC logotype

Contents of /trunk/pcsx2/x86/ix86-32/recVTLB.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: 12908 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
17 #include "PrecompiledHeader.h"
18
19 #include "Common.h"
20 #include "vtlb.h"
21
22 #include "iCore.h"
23 #include "iR5900.h"
24
25 using namespace vtlb_private;
26 using namespace x86Emitter;
27
28 //////////////////////////////////////////////////////////////////////////////////////////
29 // iAllocRegSSE -- allocates an xmm register. If no xmm register is available, xmm0 is
30 // saved into g_globalXMMData and returned as a free register.
31 //
32 class iAllocRegSSE
33 {
34 protected:
35 xRegisterSSE m_reg;
36 bool m_free;
37
38 public:
39 iAllocRegSSE() :
40 m_reg( xmm0 ),
41 m_free( !!_hasFreeXMMreg() )
42 {
43 if( m_free )
44 m_reg = xRegisterSSE( _allocTempXMMreg( XMMT_INT, -1 ) );
45 else
46 xStoreReg( m_reg );
47 }
48
49 ~iAllocRegSSE()
50 {
51 if( m_free )
52 _freeXMMreg( m_reg.Id );
53 else
54 xRestoreReg( m_reg );
55 }
56
57 operator xRegisterSSE() const { return m_reg; }
58 };
59
60 // Moves 128 bits from point B to point A, using SSE's MOVAPS (or MOVDQA).
61 // This instruction always uses an SSE register, even if all registers are allocated! It
62 // saves an SSE register to memory first, performs the copy, and restores the register.
63 //
64 static void iMOV128_SSE( const xIndirectVoid& destRm, const xIndirectVoid& srcRm )
65 {
66 iAllocRegSSE reg;
67 xMOVDQA( reg, srcRm );
68 xMOVDQA( destRm, reg );
69 }
70
71 // Moves 64 bits of data from point B to point A, using either MMX, SSE, or x86 registers
72 // if neither MMX nor SSE is available to the task.
73 //
74 // Optimizations: This method uses MMX is the cpu is in MMX mode, or SSE if it's in FPU
75 // mode (saving on potential EMMS uses).
76 //
77 static void iMOV64_Smart( const xIndirectVoid& destRm, const xIndirectVoid& srcRm )
78 {
79 if( (x86FpuState == FPU_STATE) && _hasFreeXMMreg() )
80 {
81 // Move things using MOVLPS:
82 xRegisterSSE reg( _allocTempXMMreg( XMMT_INT, -1 ) );
83 xMOVL.PS( reg, srcRm );
84 xMOVL.PS( destRm, reg );
85 _freeXMMreg( reg.Id );
86 return;
87 }
88
89 if( _hasFreeMMXreg() )
90 {
91 xRegisterMMX reg( _allocMMXreg(-1, MMX_TEMP, 0) );
92 xMOVQ( reg, srcRm );
93 xMOVQ( destRm, reg );
94 _freeMMXreg( reg.Id );
95 }
96 else
97 {
98 xMOV( eax, srcRm );
99 xMOV( destRm, eax );
100 xMOV( eax, srcRm+4 );
101 xMOV( destRm+4, eax );
102 }
103 }
104
105 /*
106 // Pseudo-Code For the following Dynarec Implementations -->
107
108 u32 vmv=vmap[addr>>VTLB_PAGE_BITS];
109 s32 ppf=addr+vmv;
110 if (!(ppf<0))
111 {
112 data[0]=*reinterpret_cast<DataType*>(ppf);
113 if (DataSize==128)
114 data[1]=*reinterpret_cast<DataType*>(ppf+8);
115 return 0;
116 }
117 else
118 {
119 //has to: translate, find function, call function
120 u32 hand=(u8)vmv;
121 u32 paddr=ppf-hand+0x80000000;
122 //Console.WriteLn("Translated 0x%08X to 0x%08X",params addr,paddr);
123 return reinterpret_cast<TemplateHelper<DataSize,false>::HandlerType*>(RWFT[TemplateHelper<DataSize,false>::sidx][0][hand])(paddr,data);
124 }
125
126 // And in ASM it looks something like this -->
127
128 mov eax,ecx;
129 shr eax,VTLB_PAGE_BITS;
130 mov eax,[eax*4+vmap];
131 add ecx,eax;
132 js _fullread;
133
134 //these are wrong order, just an example ...
135 mov [eax],ecx;
136 mov ecx,[edx];
137 mov [eax+4],ecx;
138 mov ecx,[edx+4];
139 mov [eax+4+4],ecx;
140 mov ecx,[edx+4+4];
141 mov [eax+4+4+4+4],ecx;
142 mov ecx,[edx+4+4+4+4];
143 ///....
144
145 jmp cont;
146 _fullread:
147 movzx eax,al;
148 sub ecx,eax;
149 sub ecx,0x80000000;
150 call [eax+stuff];
151 cont:
152 ........
153
154 */
155
156 namespace vtlb_private
157 {
158 // ------------------------------------------------------------------------
159 // Prepares eax, ecx, and, ebx for Direct or Indirect operations.
160 // Returns the writeback pointer for ebx (return address from indirect handling)
161 //
162 static uptr* DynGen_PrepRegs()
163 {
164 xMOV( eax, ecx );
165 xSHR( eax, VTLB_PAGE_BITS );
166 xMOV( eax, ptr[(eax*4) + vtlbdata.vmap] );
167 xMOV( ebx, 0xcdcdcdcd );
168 uptr* writeback = ((uptr*)xGetPtr()) - 1;
169 xADD( ecx, eax );
170
171 return writeback;
172 }
173
174 // ------------------------------------------------------------------------
175 static void DynGen_DirectRead( u32 bits, bool sign )
176 {
177 switch( bits )
178 {
179 case 8:
180 if( sign )
181 xMOVSX( eax, ptr8[ecx] );
182 else
183 xMOVZX( eax, ptr8[ecx] );
184 break;
185
186 case 16:
187 if( sign )
188 xMOVSX( eax, ptr16[ecx] );
189 else
190 xMOVZX( eax, ptr16[ecx] );
191 break;
192
193 case 32:
194 xMOV( eax, ptr[ecx] );
195 break;
196
197 case 64:
198 iMOV64_Smart( ptr[edx], ptr[ecx] );
199 break;
200
201 case 128:
202 iMOV128_SSE( ptr[edx], ptr[ecx] );
203 break;
204
205 jNO_DEFAULT
206 }
207 }
208
209 // ------------------------------------------------------------------------
210 static void DynGen_DirectWrite( u32 bits )
211 {
212 switch(bits)
213 {
214 //8 , 16, 32 : data on EDX
215 case 8:
216 xMOV( ptr[ecx], dl );
217 break;
218
219 case 16:
220 xMOV( ptr[ecx], dx );
221 break;
222
223 case 32:
224 xMOV( ptr[ecx], edx );
225 break;
226
227 case 64:
228 iMOV64_Smart( ptr[ecx], ptr[edx] );
229 break;
230
231 case 128:
232 iMOV128_SSE( ptr[ecx], ptr[edx] );
233 break;
234 }
235 }
236 }
237
238 // ------------------------------------------------------------------------
239 // allocate one page for our naked indirect dispatcher function.
240 // this *must* be a full page, since we'll give it execution permission later.
241 // If it were smaller than a page we'd end up allowing execution rights on some
242 // other vars additionally (bad!).
243 //
244 static __pagealigned u8 m_IndirectDispatchers[__pagesize];
245
246 // ------------------------------------------------------------------------
247 // mode - 0 for read, 1 for write!
248 // operandsize - 0 thru 4 represents 8, 16, 32, 64, and 128 bits.
249 //
250 static u8* GetIndirectDispatcherPtr( int mode, int operandsize )
251 {
252 // Each dispatcher is aligned to 64 bytes. The actual dispatchers are only like
253 // 20-some bytes each, but 64 byte alignment on functions that are called
254 // more frequently than a hot sex hotline at 1:15am is probably a good thing.
255
256 // 5*64? Because 5 operand types per each mode :D
257
258 return &m_IndirectDispatchers[(mode*(5*64)) + (operandsize*64)];
259 }
260
261 // ------------------------------------------------------------------------
262 // Generates a JS instruction that targets the appropriate templated instance of
263 // the vtlb Indirect Dispatcher.
264 //
265 static void DynGen_IndirectDispatch( int mode, int bits )
266 {
267 int szidx;
268 switch( bits )
269 {
270 case 8: szidx=0; break;
271 case 16: szidx=1; break;
272 case 32: szidx=2; break;
273 case 64: szidx=3; break;
274 case 128: szidx=4; break;
275 jNO_DEFAULT;
276 }
277 xJS( GetIndirectDispatcherPtr( mode, szidx ) );
278 }
279
280 // One-time initialization procedure. Multiple subsequent calls during the lifespan of the
281 // process will be ignored.
282 //
283 void vtlb_dynarec_init()
284 {
285 static bool hasBeenCalled = false;
286 if (hasBeenCalled) return;
287 hasBeenCalled = true;
288
289 // In case init gets called multiple times:
290 HostSys::MemProtectStatic( m_IndirectDispatchers, PageAccess_ReadWrite() );
291
292 // clear the buffer to 0xcc (easier debugging).
293 memset_8<0xcc,0x1000>( m_IndirectDispatchers );
294
295 for( int mode=0; mode<2; ++mode )
296 {
297 for( int bits=0; bits<5; ++bits )
298 {
299 xSetPtr( GetIndirectDispatcherPtr( mode, bits ) );
300
301 xMOVZX( eax, al );
302 xSUB( ecx, 0x80000000 );
303 xSUB( ecx, eax );
304
305 // jump to the indirect handler, which is a __fastcall C++ function.
306 // [ecx is address, edx is data]
307 xCALL( ptr32[(eax*4) + vtlbdata.RWFT[bits][mode]] );
308 xJMP( ebx );
309 }
310 }
311
312 HostSys::MemProtectStatic( m_IndirectDispatchers, PageAccess_ExecOnly() );
313 }
314
315 //////////////////////////////////////////////////////////////////////////////////////////
316 // Dynarec Load Implementations
317 void vtlb_DynGenRead64(u32 bits)
318 {
319 jASSUME( bits == 64 || bits == 128 );
320
321 uptr* writeback = DynGen_PrepRegs();
322
323 DynGen_IndirectDispatch( 0, bits );
324 DynGen_DirectRead( bits, false );
325
326 *writeback = (uptr)xGetPtr(); // return target for indirect's call/ret
327 }
328
329 // ------------------------------------------------------------------------
330 // Recompiled input registers:
331 // ecx - source address to read from
332 // Returns read value in eax.
333 void vtlb_DynGenRead32(u32 bits, bool sign)
334 {
335 jASSUME( bits <= 32 );
336
337 uptr* writeback = DynGen_PrepRegs();
338
339 DynGen_IndirectDispatch( 0, bits );
340 DynGen_DirectRead( bits, sign );
341
342 *writeback = (uptr)xGetPtr();
343
344 // perform sign extension on the result:
345
346 if( bits == 8 )
347 {
348 if( sign )
349 xMOVSX( eax, al );
350 else
351 xMOVZX( eax, al );
352 }
353 else if( bits == 16 )
354 {
355 if( sign )
356 xMOVSX( eax, ax );
357 else
358 xMOVZX( eax, ax );
359 }
360 }
361
362 // ------------------------------------------------------------------------
363 // TLB lookup is performed in const, with the assumption that the COP0/TLB will clear the
364 // recompiler if the TLB is changed.
365 void vtlb_DynGenRead64_Const( u32 bits, u32 addr_const )
366 {
367 u32 vmv_ptr = vtlbdata.vmap[addr_const>>VTLB_PAGE_BITS];
368 s32 ppf = addr_const + vmv_ptr;
369 if( ppf >= 0 )
370 {
371 switch( bits )
372 {
373 case 64:
374 iMOV64_Smart( ptr[edx], ptr[(void*)ppf] );
375 break;
376
377 case 128:
378 iMOV128_SSE( ptr[edx], ptr[(void*)ppf] );
379 break;
380
381 jNO_DEFAULT
382 }
383 }
384 else
385 {
386 // has to: translate, find function, call function
387 u32 handler = (u8)vmv_ptr;
388 u32 paddr = ppf - handler + 0x80000000;
389
390 int szidx = 0;
391 switch( bits )
392 {
393 case 64: szidx=3; break;
394 case 128: szidx=4; break;
395 }
396
397 xMOV( ecx, paddr );
398 xCALL( vtlbdata.RWFT[szidx][0][handler] );
399 }
400 }
401
402 // ------------------------------------------------------------------------
403 // Recompiled input registers:
404 // ecx - source address to read from
405 // Returns read value in eax.
406 //
407 // TLB lookup is performed in const, with the assumption that the COP0/TLB will clear the
408 // recompiler if the TLB is changed.
409 //
410 void vtlb_DynGenRead32_Const( u32 bits, bool sign, u32 addr_const )
411 {
412 u32 vmv_ptr = vtlbdata.vmap[addr_const>>VTLB_PAGE_BITS];
413 s32 ppf = addr_const + vmv_ptr;
414 if( ppf >= 0 )
415 {
416 switch( bits )
417 {
418 case 8:
419 if( sign )
420 xMOVSX( eax, ptr8[(u8*)ppf] );
421 else
422 xMOVZX( eax, ptr8[(u8*)ppf] );
423 break;
424
425 case 16:
426 if( sign )
427 xMOVSX( eax, ptr16[(u16*)ppf] );
428 else
429 xMOVZX( eax, ptr16[(u16*)ppf] );
430 break;
431
432 case 32:
433 xMOV( eax, ptr[(void*)ppf] );
434 break;
435 }
436 }
437 else
438 {
439 // has to: translate, find function, call function
440 u32 handler = (u8)vmv_ptr;
441 u32 paddr = ppf - handler + 0x80000000;
442
443 int szidx = 0;
444 switch( bits )
445 {
446 case 8: szidx=0; break;
447 case 16: szidx=1; break;
448 case 32: szidx=2; break;
449 }
450
451 // Shortcut for the INTC_STAT register, which many games like to spin on heavily.
452 if( (bits == 32) && !EmuConfig.Speedhacks.IntcStat && (paddr == INTC_STAT) )
453 {
454 xMOV( eax, ptr[&psHu32( INTC_STAT )] );
455 }
456 else
457 {
458 xMOV( ecx, paddr );
459 xCALL( vtlbdata.RWFT[szidx][0][handler] );
460
461 // perform sign extension on the result:
462
463 if( bits==8 )
464 {
465 if( sign )
466 xMOVSX( eax, al );
467 else
468 xMOVZX( eax, al );
469 }
470 else if( bits==16 )
471 {
472 if( sign )
473 xMOVSX( eax, ax );
474 else
475 xMOVZX( eax, ax );
476 }
477 }
478 }
479 }
480
481 //////////////////////////////////////////////////////////////////////////////////////////
482 // Dynarec Store Implementations
483
484 void vtlb_DynGenWrite(u32 sz)
485 {
486 uptr* writeback = DynGen_PrepRegs();
487
488 DynGen_IndirectDispatch( 1, sz );
489 DynGen_DirectWrite( sz );
490
491 *writeback = (uptr)xGetPtr();
492 }
493
494
495 // ------------------------------------------------------------------------
496 // Generates code for a store instruction, where the address is a known constant.
497 // TLB lookup is performed in const, with the assumption that the COP0/TLB will clear the
498 // recompiler if the TLB is changed.
499 void vtlb_DynGenWrite_Const( u32 bits, u32 addr_const )
500 {
501 u32 vmv_ptr = vtlbdata.vmap[addr_const>>VTLB_PAGE_BITS];
502 s32 ppf = addr_const + vmv_ptr;
503 if( ppf >= 0 )
504 {
505 switch(bits)
506 {
507 //8 , 16, 32 : data on EDX
508 case 8:
509 xMOV( ptr[(void*)ppf], dl );
510 break;
511
512 case 16:
513 xMOV( ptr[(void*)ppf], dx );
514 break;
515
516 case 32:
517 xMOV( ptr[(void*)ppf], edx );
518 break;
519
520 case 64:
521 iMOV64_Smart( ptr[(void*)ppf], ptr[edx] );
522 break;
523
524 case 128:
525 iMOV128_SSE( ptr[(void*)ppf], ptr[edx] );
526 break;
527 }
528
529 }
530 else
531 {
532 // has to: translate, find function, call function
533 u32 handler = (u8)vmv_ptr;
534 u32 paddr = ppf - handler + 0x80000000;
535
536 int szidx = 0;
537 switch( bits )
538 {
539 case 8: szidx=0; break;
540 case 16: szidx=1; break;
541 case 32: szidx=2; break;
542 case 64: szidx=3; break;
543 case 128: szidx=4; break;
544 }
545
546 xMOV( ecx, paddr );
547 xCALL( vtlbdata.RWFT[szidx][1][handler] );
548 }
549 }
550

  ViewVC Help
Powered by ViewVC 1.1.22