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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 280 - (show annotations) (download)
Thu Dec 23 12:02:12 2010 UTC (9 years, 1 month ago) by william
File size: 34393 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 // recompiler reworked to add dynamic linking Jan06
17 // and added reg caching, const propagation, block analysis Jun06
18 // zerofrog(@gmail.com)
19
20
21 #include "PrecompiledHeader.h"
22
23 #include "iR3000A.h"
24 #include "BaseblockEx.h"
25 #include "System/RecTypes.h"
26
27 #include <time.h>
28
29 #ifndef _WIN32
30 #include <sys/types.h>
31 #endif
32
33 #include "IopCommon.h"
34 #include "iCore.h"
35
36 #include "NakedAsm.h"
37 #include "AppConfig.h"
38
39
40 using namespace x86Emitter;
41
42 extern u32 g_iopNextEventCycle;
43 extern void psxBREAK();
44
45 u32 g_psxMaxRecMem = 0;
46 u32 s_psxrecblocks[] = {0};
47
48 uptr psxRecLUT[0x10000];
49 uptr psxhwLUT[0x10000];
50
51 #define HWADDR(mem) (psxhwLUT[mem >> 16] + (mem))
52
53 static RecompiledCodeReserve* recMem = NULL;
54
55 static BASEBLOCK *recRAM = NULL; // and the ptr to the blocks here
56 static BASEBLOCK *recROM = NULL; // and here
57 static BASEBLOCK *recROM1 = NULL; // also here
58 static BaseBlocks recBlocks;
59 static u8 *recPtr = NULL;
60 u32 psxpc; // recompiler psxpc
61 int psxbranch; // set for branch
62 u32 g_iopCyclePenalty;
63
64 static EEINST* s_pInstCache = NULL;
65 static u32 s_nInstCacheSize = 0;
66
67 static BASEBLOCK* s_pCurBlock = NULL;
68 static BASEBLOCKEX* s_pCurBlockEx = NULL;
69
70 static u32 s_nEndBlock = 0; // what psxpc the current block ends
71 static u32 s_branchTo;
72 static bool s_nBlockFF;
73
74 static u32 s_saveConstRegs[32];
75 static u32 s_saveHasConstReg = 0, s_saveFlushedConstReg = 0;
76 static EEINST* s_psaveInstInfo = NULL;
77
78 u32 s_psxBlockCycles = 0; // cycles of current block recompiling
79 static u32 s_savenBlockCycles = 0;
80
81 static void iPsxBranchTest(u32 newpc, u32 cpuBranch);
82 void psxRecompileNextInstruction(int delayslot);
83
84 extern void (*rpsxBSC[64])();
85 void rpsxpropBSC(EEINST* prev, EEINST* pinst);
86
87 static void iopClearRecLUT(BASEBLOCK* base, int count);
88
89 static u32 psxdump = 0;
90
91 #define PSX_GETBLOCK(x) PC_GETBLOCK_(x, psxRecLUT)
92
93 #define PSXREC_CLEARM(mem) \
94 (((mem) < g_psxMaxRecMem && (psxRecLUT[(mem) >> 16] + (mem))) ? \
95 psxRecClearMem(mem) : 4)
96
97 // =====================================================================================================
98 // Dynamically Compiled Dispatchers - R3000A style
99 // =====================================================================================================
100
101 static void __fastcall iopRecRecompile( const u32 startpc );
102
103 static u32 s_store_ebp, s_store_esp;
104
105 // Recompiled code buffer for EE recompiler dispatchers!
106 static u8 __pagealigned iopRecDispatchers[__pagesize];
107
108 typedef void DynGenFunc();
109
110 static DynGenFunc* iopDispatcherEvent = NULL;
111 static DynGenFunc* iopDispatcherReg = NULL;
112 static DynGenFunc* iopJITCompile = NULL;
113 static DynGenFunc* iopJITCompileInBlock = NULL;
114 static DynGenFunc* iopEnterRecompiledCode = NULL;
115 static DynGenFunc* iopExitRecompiledCode = NULL;
116
117 static void recEventTest()
118 {
119 _cpuEventTest_Shared();
120 }
121
122 // parameters:
123 // espORebp - 0 for ESP, or 1 for EBP.
124 // regval - current value of the register at the time the fault was detected (predates the
125 // stackframe setup code in this function)
126 static void __fastcall StackFrameCheckFailed( int espORebp, int regval )
127 {
128 pxFailDev( pxsFmt( L"(R3000A Recompiler Stackframe) Sanity check failed on %s\n\tCurrent=%d; Saved=%d",
129 (espORebp==0) ? L"ESP" : L"EBP", regval, (espORebp==0) ? s_store_esp : s_store_ebp )
130 );
131
132 // Note: The recompiler will attempt to recover ESP and EBP after returning from this function,
133 // so typically selecting Continue/Ignore/Cancel for this assertion should allow PCSX2 to con-
134 // tinue to run with some degree of stability.
135 }
136
137 static void _DynGen_StackFrameCheck()
138 {
139 if( !IsDevBuild ) return;
140
141 // --------- EBP Here -----------
142
143 xCMP( ebp, ptr[&s_store_ebp] );
144 xForwardJE8 skipassert_ebp;
145
146 xMOV( ecx, 1 ); // 1 specifies EBP
147 xMOV( edx, ebp );
148 xCALL( StackFrameCheckFailed );
149 xMOV( ebp, ptr[&s_store_ebp] ); // half-hearted frame recovery attempt!
150
151 skipassert_ebp.SetTarget();
152
153 // --------- ESP There -----------
154
155 xCMP( esp, ptr[&s_store_esp] );
156 xForwardJE8 skipassert_esp;
157
158 xXOR( ecx, ecx ); // 0 specifies ESP
159 xMOV( edx, esp );
160 xCALL( StackFrameCheckFailed );
161 xMOV( esp, ptr[&s_store_esp] ); // half-hearted frame recovery attempt!
162
163 skipassert_esp.SetTarget();
164 }
165
166 // The address for all cleared blocks. It recompiles the current pc and then
167 // dispatches to the recompiled block address.
168 static DynGenFunc* _DynGen_JITCompile()
169 {
170 pxAssertMsg( iopDispatcherReg != NULL, "Please compile the DispatcherReg subroutine *before* JITComple. Thanks." );
171
172 u8* retval = xGetPtr();
173 _DynGen_StackFrameCheck();
174
175 xMOV( ecx, ptr[&psxRegs.pc] );
176 xCALL( iopRecRecompile );
177
178 xMOV( eax, ptr[&psxRegs.pc] );
179 xMOV( ebx, eax );
180 xSHR( eax, 16 );
181 xMOV( ecx, ptr[psxRecLUT + (eax*4)] );
182 xJMP( ptr32[ecx+ebx] );
183
184 return (DynGenFunc*)retval;
185 }
186
187 static DynGenFunc* _DynGen_JITCompileInBlock()
188 {
189 u8* retval = xGetPtr();
190 xJMP( iopJITCompile );
191 return (DynGenFunc*)retval;
192 }
193
194 // called when jumping to variable pc address
195 static DynGenFunc* _DynGen_DispatcherReg()
196 {
197 u8* retval = xGetPtr();
198 _DynGen_StackFrameCheck();
199
200 xMOV( eax, ptr[&psxRegs.pc] );
201 xMOV( ebx, eax );
202 xSHR( eax, 16 );
203 xMOV( ecx, ptr[psxRecLUT + (eax*4)] );
204 xJMP( ptr32[ecx+ebx] );
205
206 return (DynGenFunc*)retval;
207 }
208
209 // --------------------------------------------------------------------------------------
210 // EnterRecompiledCode - dynamic compilation stub!
211 // --------------------------------------------------------------------------------------
212
213 // In Release Builds this literally generates the following code:
214 // push edi
215 // push esi
216 // push ebx
217 // jmp DispatcherReg
218 // pop ebx
219 // pop esi
220 // pop edi
221 //
222 // See notes on why this works in both GCC (aligned stack!) and other compilers (not-so-
223 // aligned stack!). In debug/dev builds the code gen is more complicated, as it constructs
224 // ebp stackframe mess, which allows for a complete backtrace from debug breakpoints (yay).
225 //
226 // Also, if you set PCSX2_IOP_FORCED_ALIGN_STACK to 1, the codegen for MSVC becomes slightly
227 // more complicated since it has to perform a full stack alignment on entry.
228 //
229
230 #if defined(__GNUG__) || defined(__DARWIN__)
231 # define PCSX2_ASSUME_ALIGNED_STACK 1
232 #else
233 # define PCSX2_ASSUME_ALIGNED_STACK 0
234 #endif
235
236 // Set to 0 for a speedup in release builds.
237 // [doesn't apply to GCC/Mac, which must always align]
238 #define PCSX2_IOP_FORCED_ALIGN_STACK 0 //1
239
240
241 // For overriding stackframe generation options in Debug builds (possibly useful for troubleshooting)
242 // Typically this value should be the same as IsDevBuild.
243 static const bool GenerateStackFrame = IsDevBuild;
244
245 static DynGenFunc* _DynGen_EnterRecompiledCode()
246 {
247 u8* retval = xGetPtr();
248
249 bool allocatedStack = GenerateStackFrame || PCSX2_IOP_FORCED_ALIGN_STACK;
250
251 // Optimization: The IOP never uses stack-based parameter invocation, so we can avoid
252 // allocating any room on the stack for it (which is important since the IOP's entry
253 // code gets invoked quite a lot).
254
255 if( allocatedStack )
256 {
257 xPUSH( ebp );
258 xMOV( ebp, esp );
259 xAND( esp, -0x10 );
260
261 xSUB( esp, 0x20 );
262
263 xMOV( ptr[ebp-12], edi );
264 xMOV( ptr[ebp-8], esi );
265 xMOV( ptr[ebp-4], ebx );
266 }
267 else
268 {
269 // GCC Compiler:
270 // The frame pointer coming in from the EE's event test can be safely assumed to be
271 // aligned, since GCC always aligns stackframes. While handy in x86-64, where CALL + PUSH EBP
272 // results in a neatly realigned stack on entry to every function, unfortunately in x86-32
273 // this is usually worthless because CALL+PUSH leaves us 8 byte aligned instead (fail). So
274 // we have to do the usual set of stackframe alignments and simulated callstack mess
275 // *regardless*.
276
277 // MSVC/Intel compilers:
278 // The PCSX2_IOP_FORCED_ALIGN_STACK setting is 0, so we don't care. Just push regs like
279 // the good old days! (stack alignment will be indeterminate)
280
281 xPUSH( edi );
282 xPUSH( esi );
283 xPUSH( ebx );
284
285 allocatedStack = false;
286 }
287
288 uptr* imm = NULL;
289 if( allocatedStack )
290 {
291 if( GenerateStackFrame )
292 {
293 // Simulate a CALL function by pushing the call address and EBP onto the stack.
294 // This retains proper stacktrace and stack unwinding (handy in devbuilds!)
295
296 xMOV( ptr32[esp+0x0c], 0xffeeff );
297 imm = (uptr*)(xGetPtr()-4);
298
299 // This part simulates the "normal" stackframe prep of "push ebp, mov ebp, esp"
300 xMOV( ptr32[esp+0x08], ebp );
301 xLEA( ebp, ptr32[esp+0x08] );
302 }
303 }
304
305 if( IsDevBuild )
306 {
307 xMOV( ptr[&s_store_esp], esp );
308 xMOV( ptr[&s_store_ebp], ebp );
309 }
310
311 xJMP( iopDispatcherReg );
312 if( imm != NULL )
313 *imm = (uptr)xGetPtr();
314
315 // ----------------------
316 // ----> Cleanup! ---->
317
318 iopExitRecompiledCode = (DynGenFunc*)xGetPtr();
319
320 if( allocatedStack )
321 {
322 // pop the nested "simulated call" stackframe, if needed:
323 if( GenerateStackFrame ) xLEAVE();
324 xMOV( edi, ptr[ebp-12] );
325 xMOV( esi, ptr[ebp-8] );
326 xMOV( ebx, ptr[ebp-4] );
327 xLEAVE();
328 }
329 else
330 {
331 xPOP( ebx );
332 xPOP( esi );
333 xPOP( edi );
334 }
335
336 xRET();
337
338 return (DynGenFunc*)retval;
339 }
340
341 static void _DynGen_Dispatchers()
342 {
343 // In case init gets called multiple times:
344 HostSys::MemProtectStatic( iopRecDispatchers, PageAccess_ReadWrite() );
345
346 // clear the buffer to 0xcc (easier debugging).
347 memset_8<0xcc,__pagesize>( iopRecDispatchers );
348
349 xSetPtr( iopRecDispatchers );
350
351 // Place the EventTest and DispatcherReg stuff at the top, because they get called the
352 // most and stand to benefit from strong alignment and direct referencing.
353 iopDispatcherEvent = (DynGenFunc*)xGetPtr();
354 xCALL( recEventTest );
355 iopDispatcherReg = _DynGen_DispatcherReg();
356
357 iopJITCompile = _DynGen_JITCompile();
358 iopJITCompileInBlock = _DynGen_JITCompileInBlock();
359 iopEnterRecompiledCode = _DynGen_EnterRecompiledCode();
360
361 HostSys::MemProtectStatic( iopRecDispatchers, PageAccess_ExecOnly() );
362
363 recBlocks.SetJITCompile( iopJITCompile );
364 }
365
366 ////////////////////////////////////////////////////
367 using namespace R3000A;
368 #include "Utilities/AsciiFile.h"
369
370 static void iIopDumpBlock( int startpc, u8 * ptr )
371 {
372 u32 i, j;
373 EEINST* pcur;
374 u8 used[34];
375 int numused, count;
376
377 Console.WriteLn( "dump1 %x:%x, %x", startpc, psxpc, psxRegs.cycle );
378 g_Conf->Folders.Logs.Mkdir();
379
380 wxString filename( Path::Combine( g_Conf->Folders.Logs, wxsFormat( L"psxdump%.8X.txt", startpc ) ) );
381 AsciiFile f( filename, L"w" );
382
383 /*for ( i = startpc; i < s_nEndBlock; i += 4 ) {
384 f.Printf("%s\n", disR3000Fasm( iopMemRead32( i ), i ) );
385 }*/
386
387 // write the instruction info
388 f.Printf("\n\nlive0 - %x, lastuse - %x used - %x\n", EEINST_LIVE0, EEINST_LASTUSE, EEINST_USED);
389
390 memzero(used);
391 numused = 0;
392 for(i = 0; i < ArraySize(s_pInstCache->regs); ++i) {
393 if( s_pInstCache->regs[i] & EEINST_USED ) {
394 used[i] = 1;
395 numused++;
396 }
397 }
398
399 f.Printf(" ");
400 for(i = 0; i < ArraySize(s_pInstCache->regs); ++i) {
401 if( used[i] ) f.Printf("%2d ", i);
402 }
403 f.Printf("\n");
404
405 f.Printf(" ");
406 for(i = 0; i < ArraySize(s_pInstCache->regs); ++i) {
407 if( used[i] ) f.Printf("%s ", disRNameGPR[i]);
408 }
409 f.Printf("\n");
410
411 pcur = s_pInstCache+1;
412 for( i = 0; i < (s_nEndBlock-startpc)/4; ++i, ++pcur) {
413 f.Printf("%2d: %2.2x ", i+1, pcur->info);
414
415 count = 1;
416 for(j = 0; j < ArraySize(s_pInstCache->regs); j++) {
417 if( used[j] ) {
418 f.Printf("%2.2x%s", pcur->regs[j], ((count%8)&&count<numused)?"_":" ");
419 ++count;
420 }
421 }
422 f.Printf("\n");
423 }
424
425 #ifdef __LINUX__
426 char command[256];
427 // dump the asm
428 {
429 AsciiFile f2( L"mydump1", L"w" );
430 f2.Write( ptr, (uptr)x86Ptr - (uptr)ptr );
431 }
432 wxCharBuffer buf( filename.ToUTF8() );
433 const char* filenamea = buf.data();
434 sprintf( command, "objdump -D --target=binary --architecture=i386 -M intel mydump1 | cat %s - > tempdump", filenamea );
435 system( command );
436 sprintf( command, "mv tempdump %s", filenamea );
437 system( command );
438 //f = fopen( filename.c_str(), "a+" );
439 #endif
440 }
441
442 u8 _psxLoadWritesRs(u32 tempcode)
443 {
444 switch(tempcode>>26) {
445 case 32: case 33: case 34: case 35: case 36: case 37: case 38:
446 return ((tempcode>>21)&0x1f)==((tempcode>>16)&0x1f); // rs==rt
447 }
448 return 0;
449 }
450
451 u8 _psxIsLoadStore(u32 tempcode)
452 {
453 switch(tempcode>>26) {
454 case 32: case 33: case 34: case 35: case 36: case 37: case 38:
455 // 4 byte stores
456 case 40: case 41: case 42: case 43: case 46:
457 return 1;
458 }
459 return 0;
460 }
461
462 void _psxFlushAllUnused()
463 {
464 int i;
465 for(i = 0; i < 34; ++i) {
466 if( psxpc < s_nEndBlock ) {
467 if( (g_pCurInstInfo[1].regs[i]&EEINST_USED) )
468 continue;
469 }
470 else if( (g_pCurInstInfo[0].regs[i]&EEINST_USED) )
471 continue;
472
473 if( i < 32 && PSX_IS_CONST1(i) ) _psxFlushConstReg(i);
474 else {
475 _deleteX86reg(X86TYPE_PSX, i, 1);
476 }
477 }
478 }
479
480 int _psxFlushUnusedConstReg()
481 {
482 int i;
483 for(i = 1; i < 32; ++i) {
484 if( (g_psxHasConstReg & (1<<i)) && !(g_psxFlushedConstReg&(1<<i)) &&
485 !_recIsRegWritten(g_pCurInstInfo+1, (s_nEndBlock-psxpc)/4, XMMTYPE_GPRREG, i) ) {
486
487 // check if will be written in the future
488 MOV32ItoM((uptr)&psxRegs.GPR.r[i], g_psxConstRegs[i]);
489 g_psxFlushedConstReg |= 1<<i;
490 return 1;
491 }
492 }
493
494 return 0;
495 }
496
497 void _psxFlushCachedRegs()
498 {
499 _psxFlushConstRegs();
500 }
501
502 void _psxFlushConstReg(int reg)
503 {
504 if( PSX_IS_CONST1( reg ) && !(g_psxFlushedConstReg&(1<<reg)) ) {
505 MOV32ItoM((uptr)&psxRegs.GPR.r[reg], g_psxConstRegs[reg]);
506 g_psxFlushedConstReg |= (1<<reg);
507 }
508 }
509
510 void _psxFlushConstRegs()
511 {
512 int i;
513
514 // flush constants
515
516 // ignore r0
517 for(i = 1; i < 32; ++i) {
518 if( g_psxHasConstReg & (1<<i) ) {
519
520 if( !(g_psxFlushedConstReg&(1<<i)) ) {
521 MOV32ItoM((uptr)&psxRegs.GPR.r[i], g_psxConstRegs[i]);
522 g_psxFlushedConstReg |= 1<<i;
523 }
524
525 if( g_psxHasConstReg == g_psxFlushedConstReg )
526 break;
527 }
528 }
529 }
530
531 void _psxDeleteReg(int reg, int flush)
532 {
533 if( !reg ) return;
534 if( flush && PSX_IS_CONST1(reg) ) {
535 _psxFlushConstReg(reg);
536 return;
537 }
538 PSX_DEL_CONST(reg);
539 _deleteX86reg(X86TYPE_PSX, reg, flush ? 0 : 2);
540 }
541
542 void _psxMoveGPRtoR(x86IntRegType to, int fromgpr)
543 {
544 if( PSX_IS_CONST1(fromgpr) )
545 MOV32ItoR( to, g_psxConstRegs[fromgpr] );
546 else {
547 // check x86
548 MOV32MtoR(to, (uptr)&psxRegs.GPR.r[ fromgpr ] );
549 }
550 }
551
552 void _psxMoveGPRtoM(u32 to, int fromgpr)
553 {
554 if( PSX_IS_CONST1(fromgpr) )
555 MOV32ItoM( to, g_psxConstRegs[fromgpr] );
556 else {
557 // check x86
558 MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[ fromgpr ] );
559 MOV32RtoM(to, EAX );
560 }
561 }
562
563 void _psxMoveGPRtoRm(x86IntRegType to, int fromgpr)
564 {
565 if( PSX_IS_CONST1(fromgpr) )
566 MOV32ItoRm( to, g_psxConstRegs[fromgpr] );
567 else {
568 // check x86
569 MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[ fromgpr ] );
570 MOV32RtoRm(to, EAX );
571 }
572 }
573
574 void _psxFlushCall(int flushtype)
575 {
576 // x86-32 ABI : These registers are not preserved across calls:
577 _freeX86reg( EAX );
578 _freeX86reg( ECX );
579 _freeX86reg( EDX );
580
581 if( flushtype & FLUSH_CACHED_REGS )
582 _psxFlushConstRegs();
583 }
584
585 void psxSaveBranchState()
586 {
587 s_savenBlockCycles = s_psxBlockCycles;
588 memcpy(s_saveConstRegs, g_psxConstRegs, sizeof(g_psxConstRegs));
589 s_saveHasConstReg = g_psxHasConstReg;
590 s_saveFlushedConstReg = g_psxFlushedConstReg;
591 s_psaveInstInfo = g_pCurInstInfo;
592
593 // save all regs
594 memcpy(s_saveX86regs, x86regs, sizeof(x86regs));
595 }
596
597 void psxLoadBranchState()
598 {
599 s_psxBlockCycles = s_savenBlockCycles;
600
601 memcpy(g_psxConstRegs, s_saveConstRegs, sizeof(g_psxConstRegs));
602 g_psxHasConstReg = s_saveHasConstReg;
603 g_psxFlushedConstReg = s_saveFlushedConstReg;
604 g_pCurInstInfo = s_psaveInstInfo;
605
606 // restore all regs
607 memcpy(x86regs, s_saveX86regs, sizeof(x86regs));
608 }
609
610 ////////////////////
611 // Code Templates //
612 ////////////////////
613
614 void _psxOnWriteReg(int reg)
615 {
616 PSX_DEL_CONST(reg);
617 }
618
619 // rd = rs op rt
620 void psxRecompileCodeConst0(R3000AFNPTR constcode, R3000AFNPTR_INFO constscode, R3000AFNPTR_INFO consttcode, R3000AFNPTR_INFO noconstcode)
621 {
622 if ( ! _Rd_ ) return;
623
624 // for now, don't support xmm
625
626 _deleteX86reg(X86TYPE_PSX, _Rs_, 1);
627 _deleteX86reg(X86TYPE_PSX, _Rt_, 1);
628 _deleteX86reg(X86TYPE_PSX, _Rd_, 0);
629
630 if( PSX_IS_CONST2(_Rs_, _Rt_) ) {
631 PSX_SET_CONST(_Rd_);
632 constcode();
633 return;
634 }
635
636 if( PSX_IS_CONST1(_Rs_) ) {
637 constscode(0);
638 PSX_DEL_CONST(_Rd_);
639 return;
640 }
641
642 if( PSX_IS_CONST1(_Rt_) ) {
643 consttcode(0);
644 PSX_DEL_CONST(_Rd_);
645 return;
646 }
647
648 noconstcode(0);
649 PSX_DEL_CONST(_Rd_);
650 }
651
652 // rt = rs op imm16
653 void psxRecompileCodeConst1(R3000AFNPTR constcode, R3000AFNPTR_INFO noconstcode)
654 {
655 if ( ! _Rt_ ) {
656 // check for iop module import table magic
657 if (psxRegs.code >> 16 == 0x2400) {
658 MOV32ItoM( (uptr)&psxRegs.code, psxRegs.code );
659 MOV32ItoM( (uptr)&psxRegs.pc, psxpc );
660 _psxFlushCall(FLUSH_NODESTROY);
661
662 const char *libname = irxImportLibname(psxpc);
663 u16 index = psxRegs.code & 0xffff;
664 #ifdef PCSX2_DEVBUILD
665 const char *funcname = irxImportFuncname(libname, index);
666 irxDEBUG debug = irxImportDebug(libname, index);
667
668 if (SysTraceActive(IOP.Bios)) {
669 xMOV(ecx, (uptr)libname);
670 xMOV(edx, index);
671 xPUSH((uptr)funcname);
672 xCALL(irxImportLog);
673 }
674
675 if (debug)
676 xCALL(debug);
677 #endif
678 irxHLE hle = irxImportHLE(libname, index);
679 if (hle) {
680 xCALL(hle);
681 xCMP(eax, 0);
682 xJNE(iopDispatcherReg);
683 }
684 }
685 return;
686 }
687
688 // for now, don't support xmm
689
690 _deleteX86reg(X86TYPE_PSX, _Rs_, 1);
691 _deleteX86reg(X86TYPE_PSX, _Rt_, 0);
692
693 if( PSX_IS_CONST1(_Rs_) ) {
694 PSX_SET_CONST(_Rt_);
695 constcode();
696 return;
697 }
698
699 noconstcode(0);
700 PSX_DEL_CONST(_Rt_);
701 }
702
703 // rd = rt op sa
704 void psxRecompileCodeConst2(R3000AFNPTR constcode, R3000AFNPTR_INFO noconstcode)
705 {
706 if ( ! _Rd_ ) return;
707
708 // for now, don't support xmm
709
710 _deleteX86reg(X86TYPE_PSX, _Rt_, 1);
711 _deleteX86reg(X86TYPE_PSX, _Rd_, 0);
712
713 if( PSX_IS_CONST1(_Rt_) ) {
714 PSX_SET_CONST(_Rd_);
715 constcode();
716 return;
717 }
718
719 noconstcode(0);
720 PSX_DEL_CONST(_Rd_);
721 }
722
723 // rd = rt MULT rs (SPECIAL)
724 void psxRecompileCodeConst3(R3000AFNPTR constcode, R3000AFNPTR_INFO constscode, R3000AFNPTR_INFO consttcode, R3000AFNPTR_INFO noconstcode, int LOHI)
725 {
726 _deleteX86reg(X86TYPE_PSX, _Rs_, 1);
727 _deleteX86reg(X86TYPE_PSX, _Rt_, 1);
728
729 if( LOHI ) {
730 _deleteX86reg(X86TYPE_PSX, PSX_HI, 1);
731 _deleteX86reg(X86TYPE_PSX, PSX_LO, 1);
732 }
733
734 if( PSX_IS_CONST2(_Rs_, _Rt_) ) {
735 constcode();
736 return;
737 }
738
739 if( PSX_IS_CONST1(_Rs_) ) {
740 constscode(0);
741 return;
742 }
743
744 if( PSX_IS_CONST1(_Rt_) ) {
745 consttcode(0);
746 return;
747 }
748
749 noconstcode(0);
750 }
751
752 static uptr m_ConfiguredCacheReserve = 32;
753 static u8* m_recBlockAlloc = NULL;
754
755 static const uint m_recBlockAllocSize =
756 (((Ps2MemSize::IopRam + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4) * sizeof(BASEBLOCK));
757
758 static void recReserveCache()
759 {
760 if (!recMem) recMem = new RecompiledCodeReserve(L"R3000A Recompiler Cache", _1mb * 2);
761 recMem->SetProfilerName("IOPrec");
762
763 while (!recMem->IsOk())
764 {
765 if (recMem->Reserve( m_ConfiguredCacheReserve * _1mb, HostMemoryMap::IOPrec ) != NULL) break;
766
767 // If it failed, then try again (if possible):
768 if (m_ConfiguredCacheReserve < 4) break;
769 m_ConfiguredCacheReserve /= 2;
770 }
771
772 recMem->ThrowIfNotOk();
773 }
774
775 static void recReserve()
776 {
777 // IOP has no hardware requirements!
778
779 recReserveCache();
780 }
781
782 static void recAlloc()
783 {
784 // Goal: Allocate BASEBLOCKs for every possible branch target in IOP memory.
785 // Any 4-byte aligned address makes a valid branch target as per MIPS design (all instructions are
786 // always 4 bytes long).
787
788 if( m_recBlockAlloc == NULL )
789 m_recBlockAlloc = (u8*)_aligned_malloc( m_recBlockAllocSize, 4096 );
790
791 if( m_recBlockAlloc == NULL )
792 throw Exception::OutOfMemory( L"R3000A BASEBLOCK lookup tables" );
793
794 u8* curpos = m_recBlockAlloc;
795 recRAM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::IopRam / 4) * sizeof(BASEBLOCK);
796 recROM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom / 4) * sizeof(BASEBLOCK);
797 recROM1 = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom1 / 4) * sizeof(BASEBLOCK);
798
799 if( s_pInstCache == NULL )
800 {
801 s_nInstCacheSize = 128;
802 s_pInstCache = (EEINST*)malloc( sizeof(EEINST) * s_nInstCacheSize );
803 }
804
805 if( s_pInstCache == NULL )
806 throw Exception::OutOfMemory( L"R3000 InstCache." );
807
808 _DynGen_Dispatchers();
809 }
810
811 void recResetIOP()
812 {
813 DevCon.WriteLn( "iR3000A Recompiler reset." );
814
815 recAlloc();
816 recMem->Reset();
817
818 iopClearRecLUT((BASEBLOCK*)m_recBlockAlloc,
819 (((Ps2MemSize::IopRam + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4)));
820
821 for (int i = 0; i < 0x10000; i++)
822 recLUT_SetPage(psxRecLUT, 0, 0, 0, i, 0);
823
824 // IOP knows 64k pages, hence for the 0x10000's
825
826 // The bottom 2 bits of PC are always zero, so we <<14 to "compress"
827 // the pc indexer into it's lower common denominator.
828
829 // We're only mapping 20 pages here in 4 places.
830 // 0x80 comes from : (Ps2MemSize::IopRam / 0x10000) * 4
831
832 for (int i=0; i<0x80; i++)
833 {
834 recLUT_SetPage(psxRecLUT, psxhwLUT, recRAM, 0x0000, i, i & 0x1f);
835 recLUT_SetPage(psxRecLUT, psxhwLUT, recRAM, 0x8000, i, i & 0x1f);
836 recLUT_SetPage(psxRecLUT, psxhwLUT, recRAM, 0xa000, i, i & 0x1f);
837 }
838
839 for (int i=0x1fc0; i<0x2000; i++)
840 {
841 recLUT_SetPage(psxRecLUT, psxhwLUT, recROM, 0x0000, i, i - 0x1fc0);
842 recLUT_SetPage(psxRecLUT, psxhwLUT, recROM, 0x8000, i, i - 0x1fc0);
843 recLUT_SetPage(psxRecLUT, psxhwLUT, recROM, 0xa000, i, i - 0x1fc0);
844 }
845
846 for (int i=0x1e00; i<0x1e04; i++)
847 {
848 recLUT_SetPage(psxRecLUT, psxhwLUT, recROM1, 0x0000, i, i - 0x1fc0);
849 recLUT_SetPage(psxRecLUT, psxhwLUT, recROM1, 0x8000, i, i - 0x1fc0);
850 recLUT_SetPage(psxRecLUT, psxhwLUT, recROM1, 0xa000, i, i - 0x1fc0);
851 }
852
853 if( s_pInstCache )
854 memset( s_pInstCache, 0, sizeof(EEINST)*s_nInstCacheSize );
855
856 recBlocks.Reset();
857 g_psxMaxRecMem = 0;
858
859 recPtr = *recMem;
860 psxbranch = 0;
861 }
862
863 static void recShutdown()
864 {
865 safe_delete( recMem );
866
867 safe_aligned_free( m_recBlockAlloc );
868
869 safe_free( s_pInstCache );
870 s_nInstCacheSize = 0;
871 }
872
873 static void iopClearRecLUT(BASEBLOCK* base, int count)
874 {
875 for (int i = 0; i < count; i++)
876 base[i].SetFnptr((uptr)iopJITCompile);
877 }
878
879 static void recExecute()
880 {
881 // note: this function is currently never used.
882 //for (;;) R3000AExecute();
883 }
884
885 static __noinline s32 recExecuteBlock( s32 eeCycles )
886 {
887 iopBreak = 0;
888 iopCycleEE = eeCycles;
889
890 #ifdef PCSX2_DEVBUILD
891 //if (SysTrace.SIF.IsActive())
892 // SysTrace.IOP.R3000A.Write("Switching to IOP CPU for %d cycles", eeCycles);
893 #endif
894
895 // [TODO] recExecuteBlock could be replaced by a direct call to the iopEnterRecompiledCode()
896 // (by assigning its address to the psxRec structure). But for that to happen, we need
897 // to move iopBreak/iopCycleEE update code to emitted assembly code. >_< --air
898
899 // Likely Disasm, as borrowed from MSVC:
900
901 // Entry:
902 // mov eax,dword ptr [esp+4]
903 // mov dword ptr [iopBreak (0E88DCCh)],0
904 // mov dword ptr [iopCycleEE (832A84h)],eax
905
906 // Exit:
907 // mov ecx,dword ptr [iopBreak (0E88DCCh)]
908 // mov edx,dword ptr [iopCycleEE (832A84h)]
909 // lea eax,[edx+ecx]
910
911 iopEnterRecompiledCode();
912
913 return iopBreak + iopCycleEE;
914 }
915
916 // Returns the offset to the next instruction after any cleared memory
917 static __fi u32 psxRecClearMem(u32 pc)
918 {
919 BASEBLOCK* pblock;
920
921 pblock = PSX_GETBLOCK(pc);
922 // if ((u8*)iopJITCompile == pblock->GetFnptr())
923 if (pblock->GetFnptr() == (uptr)iopJITCompile)
924 return 4;
925
926 pc = HWADDR(pc);
927
928 u32 lowerextent = pc, upperextent = pc + 4;
929 int blockidx = recBlocks.Index(pc);
930
931 pxAssert(blockidx != -1);
932
933 while (BASEBLOCKEX* pexblock = recBlocks[blockidx - 1]) {
934 if (pexblock->startpc + pexblock->size * 4 <= lowerextent)
935 break;
936
937 lowerextent = min(lowerextent, pexblock->startpc);
938 blockidx--;
939 }
940
941 while (BASEBLOCKEX* pexblock = recBlocks[blockidx]) {
942 if (pexblock->startpc >= upperextent)
943 break;
944
945 lowerextent = min(lowerextent, pexblock->startpc);
946 upperextent = max(upperextent, pexblock->startpc + pexblock->size * 4);
947 recBlocks.Remove(blockidx);
948 }
949
950 blockidx=0;
951 while(BASEBLOCKEX* pexblock = recBlocks[blockidx++])
952 {
953 if (pc >= pexblock->startpc && pc < pexblock->startpc + pexblock->size * 4) {
954 DevCon.Error("Impossible block clearing failure");
955 pxFailDev( "Impossible block clearing failure" );
956 }
957 }
958
959 iopClearRecLUT(PSX_GETBLOCK(lowerextent), (upperextent - lowerextent) / 4);
960
961 return upperextent - pc;
962 }
963
964 static __fi void recClearIOP(u32 Addr, u32 Size)
965 {
966 u32 pc = Addr;
967 while (pc < Addr + Size*4)
968 pc += PSXREC_CLEARM(pc);
969 }
970
971 void psxSetBranchReg(u32 reg)
972 {
973 psxbranch = 1;
974
975 if( reg != 0xffffffff ) {
976 _allocX86reg(ESI, X86TYPE_PCWRITEBACK, 0, MODE_WRITE);
977 _psxMoveGPRtoR(ESI, reg);
978
979 psxRecompileNextInstruction(1);
980
981 if( x86regs[ESI].inuse ) {
982 pxAssert( x86regs[ESI].type == X86TYPE_PCWRITEBACK );
983 MOV32RtoM((uptr)&psxRegs.pc, ESI);
984 x86regs[ESI].inuse = 0;
985 #ifdef PCSX2_DEBUG
986 xOR( esi, esi );
987 #endif
988 }
989 else {
990 MOV32MtoR(EAX, (uptr)&g_recWriteback);
991 MOV32RtoM((uptr)&psxRegs.pc, EAX);
992
993 #ifdef PCSX2_DEBUG
994 xOR( eax, eax );
995 #endif
996 }
997
998 #ifdef PCSX2_DEBUG
999 xForwardJNZ8 skipAssert;
1000 xWrite8( 0xcc );
1001 skipAssert.SetTarget();
1002 #endif
1003 }
1004
1005 _psxFlushCall(FLUSH_EVERYTHING);
1006 iPsxBranchTest(0xffffffff, 1);
1007
1008 JMP32((uptr)iopDispatcherReg - ( (uptr)x86Ptr + 5 ));
1009 }
1010
1011 void psxSetBranchImm( u32 imm )
1012 {
1013 psxbranch = 1;
1014 pxAssert( imm );
1015
1016 // end the current block
1017 MOV32ItoM( (uptr)&psxRegs.pc, imm );
1018 _psxFlushCall(FLUSH_EVERYTHING);
1019 iPsxBranchTest(imm, imm <= psxpc);
1020
1021 recBlocks.Link(HWADDR(imm), xJcc32());
1022 }
1023
1024 static __fi u32 psxScaleBlockCycles()
1025 {
1026 return s_psxBlockCycles;
1027 }
1028
1029 static void iPsxBranchTest(u32 newpc, u32 cpuBranch)
1030 {
1031 u32 blockCycles = psxScaleBlockCycles();
1032
1033 if (EmuConfig.Speedhacks.WaitLoop && s_nBlockFF && newpc == s_branchTo)
1034 {
1035 xMOV(eax, ptr32[&psxRegs.cycle]);
1036 xMOV(ecx, eax);
1037 xMOV(edx, ptr32[&iopCycleEE]);
1038 xADD(edx, 7);
1039 xSHR(edx, 3);
1040 xADD(eax, edx);
1041 xCMP(eax, ptr32[&g_iopNextEventCycle]);
1042 xCMOVNS(eax, ptr32[&g_iopNextEventCycle]);
1043 xMOV(ptr32[&psxRegs.cycle], eax);
1044 xSUB(eax, ecx);
1045 xSHL(eax, 3);
1046 xSUB(ptr32[&iopCycleEE], eax);
1047 xJLE(iopExitRecompiledCode);
1048
1049 xCALL(iopEventTest);
1050
1051 if( newpc != 0xffffffff )
1052 {
1053 xCMP(ptr32[&psxRegs.pc], newpc);
1054 xJNE(iopDispatcherReg);
1055 }
1056 }
1057 else
1058 {
1059 xMOV(eax, ptr32[&psxRegs.cycle]);
1060 xADD(eax, blockCycles);
1061 xMOV(ptr32[&psxRegs.cycle], eax); // update cycles
1062
1063 // jump if iopCycleEE <= 0 (iop's timeslice timed out, so time to return control to the EE)
1064 xSUB(ptr32[&iopCycleEE], blockCycles*8);
1065 xJLE(iopExitRecompiledCode);
1066
1067 // check if an event is pending
1068 xSUB(eax, ptr32[&g_iopNextEventCycle]);
1069 xForwardJS<u8> nointerruptpending;
1070
1071 xCALL(iopEventTest);
1072
1073 if( newpc != 0xffffffff ) {
1074 xCMP(ptr32[&psxRegs.pc], newpc);
1075 xJNE(iopDispatcherReg);
1076 }
1077
1078 nointerruptpending.SetTarget();
1079 }
1080 }
1081
1082 #if 0
1083 //static const int *s_pCode;
1084
1085 #if !defined(_MSC_VER)
1086 static void checkcodefn()
1087 {
1088 int pctemp;
1089
1090 #ifdef _MSC_VER
1091 __asm mov pctemp, eax;
1092 #else
1093 __asm__ __volatile__("movl %%eax, %[pctemp]" : [pctemp]"m="(pctemp) );
1094 #endif
1095 Console.WriteLn("iop code changed! %x", pctemp);
1096 }
1097 #endif
1098 #endif
1099
1100 void rpsxSYSCALL()
1101 {
1102 MOV32ItoM( (uptr)&psxRegs.code, psxRegs.code );
1103 MOV32ItoM((uptr)&psxRegs.pc, psxpc - 4);
1104 _psxFlushCall(FLUSH_NODESTROY);
1105
1106 xMOV( ecx, 0x20 ); // exception code
1107 xMOV( edx, psxbranch==1 ); // branch delay slot?
1108 xCALL( psxException );
1109
1110 CMP32ItoM((uptr)&psxRegs.pc, psxpc-4);
1111 j8Ptr[0] = JE8(0);
1112
1113 ADD32ItoM((uptr)&psxRegs.cycle, psxScaleBlockCycles() );
1114 SUB32ItoM((uptr)&iopCycleEE, psxScaleBlockCycles()*8 );
1115 JMP32((uptr)iopDispatcherReg - ( (uptr)x86Ptr + 5 ));
1116
1117 // jump target for skipping blockCycle updates
1118 x86SetJ8(j8Ptr[0]);
1119
1120 //if (!psxbranch) psxbranch = 2;
1121 }
1122
1123 void rpsxBREAK()
1124 {
1125 MOV32ItoM( (uptr)&psxRegs.code, psxRegs.code );
1126 MOV32ItoM((uptr)&psxRegs.pc, psxpc - 4);
1127 _psxFlushCall(FLUSH_NODESTROY);
1128
1129 xMOV( ecx, 0x24 ); // exception code
1130 xMOV( edx, psxbranch==1 ); // branch delay slot?
1131 xCALL( psxException );
1132
1133 CMP32ItoM((uptr)&psxRegs.pc, psxpc-4);
1134 j8Ptr[0] = JE8(0);
1135 ADD32ItoM((uptr)&psxRegs.cycle, psxScaleBlockCycles() );
1136 SUB32ItoM((uptr)&iopCycleEE, psxScaleBlockCycles()*8 );
1137 JMP32((uptr)iopDispatcherReg - ( (uptr)x86Ptr + 5 ));
1138 x86SetJ8(j8Ptr[0]);
1139
1140 //if (!psxbranch) psxbranch = 2;
1141 }
1142
1143 void psxRecompileNextInstruction(int delayslot)
1144 {
1145 static u8 s_bFlushReg = 1;
1146
1147 // pblock isn't used elsewhere in this function.
1148 //BASEBLOCK* pblock = PSX_GETBLOCK(psxpc);
1149
1150 if( IsDebugBuild )
1151 MOV32ItoR(EAX, psxpc);
1152
1153 psxRegs.code = iopMemRead32( psxpc );
1154 s_psxBlockCycles++;
1155 psxpc += 4;
1156
1157 g_pCurInstInfo++;
1158
1159 g_iopCyclePenalty = 0;
1160 rpsxBSC[ psxRegs.code >> 26 ]();
1161 s_psxBlockCycles += g_iopCyclePenalty;
1162
1163 if( !delayslot ) {
1164 if( s_bFlushReg ) {
1165 //_psxFlushUnusedConstReg();
1166 }
1167 else s_bFlushReg = 1;
1168 }
1169 else s_bFlushReg = 1;
1170
1171 _clearNeededX86regs();
1172 }
1173
1174 static void __fastcall PreBlockCheck( u32 blockpc )
1175 {
1176 #ifdef PCSX2_DEBUG
1177 extern void iDumpPsxRegisters(u32 startpc, u32 temp);
1178
1179 static int lastrec = 0;
1180 static int curcount = 0;
1181 const int skip = 0;
1182
1183 //*(int*)PSXM(0x27990) = 1; // enables cdvd bios output for scph10000
1184
1185 if( (psxdump&2) && lastrec != blockpc )
1186 {
1187 curcount++;
1188
1189 if( curcount > skip ) {
1190 iDumpPsxRegisters(blockpc, 1);
1191 curcount = 0;
1192 }
1193
1194 lastrec = blockpc;
1195 }
1196 #endif
1197 }
1198
1199 static void __fastcall iopRecRecompile( const u32 startpc )
1200 {
1201 u32 i;
1202 u32 willbranch3 = 0;
1203
1204 if( IsDebugBuild && (psxdump & 4) )
1205 {
1206 extern void iDumpPsxRegisters(u32 startpc, u32 temp);
1207 iDumpPsxRegisters(startpc, 0);
1208 }
1209
1210 pxAssert( startpc );
1211
1212 // if recPtr reached the mem limit reset whole mem
1213 if (recPtr >= (recMem->GetPtrEnd() - _64kb)) {
1214 recResetIOP();
1215 }
1216
1217 x86SetPtr( recPtr );
1218 x86Align(16);
1219 recPtr = x86Ptr;
1220
1221 s_pCurBlock = PSX_GETBLOCK(startpc);
1222
1223 pxAssert(s_pCurBlock->GetFnptr() == (uptr)iopJITCompile
1224 || s_pCurBlock->GetFnptr() == (uptr)iopJITCompileInBlock);
1225
1226 s_pCurBlockEx = recBlocks.Get(HWADDR(startpc));
1227 if(!s_pCurBlockEx || s_pCurBlockEx->startpc != HWADDR(startpc))
1228 s_pCurBlockEx = recBlocks.New(HWADDR(startpc), (uptr)recPtr);
1229
1230 psxbranch = 0;
1231
1232 s_pCurBlock->SetFnptr( (uptr)x86Ptr );
1233 s_psxBlockCycles = 0;
1234
1235 // reset recomp state variables
1236 psxpc = startpc;
1237 g_psxHasConstReg = g_psxFlushedConstReg = 1;
1238
1239 _initX86regs();
1240
1241 if( IsDebugBuild )
1242 {
1243 xMOV(ecx, psxpc);
1244 xCALL(PreBlockCheck);
1245 }
1246
1247 // go until the next branch
1248 i = startpc;
1249 s_nEndBlock = 0xffffffff;
1250 s_branchTo = -1;
1251
1252 while(1) {
1253 BASEBLOCK* pblock = PSX_GETBLOCK(i);
1254 if (i != startpc
1255 && pblock->GetFnptr() != (uptr)iopJITCompile
1256 && pblock->GetFnptr() != (uptr)iopJITCompileInBlock) {
1257 // branch = 3
1258 willbranch3 = 1;
1259 s_nEndBlock = i;
1260 break;
1261 }
1262
1263 psxRegs.code = iopMemRead32(i);
1264
1265 switch(psxRegs.code >> 26) {
1266 case 0: // special
1267
1268 if( _Funct_ == 8 || _Funct_ == 9 ) { // JR, JALR
1269 s_nEndBlock = i + 8;
1270 goto StartRecomp;
1271 }
1272
1273 break;
1274 case 1: // regimm
1275
1276 if( _Rt_ == 0 || _Rt_ == 1 || _Rt_ == 16 || _Rt_ == 17 ) {
1277
1278 s_branchTo = _Imm_ * 4 + i + 4;
1279 if( s_branchTo > startpc && s_branchTo < i ) s_nEndBlock = s_branchTo;
1280 else s_nEndBlock = i+8;
1281
1282 goto StartRecomp;
1283 }
1284
1285 break;
1286
1287 case 2: // J
1288 case 3: // JAL
1289 s_branchTo = _Target_ << 2 | (i + 4) & 0xf0000000;
1290 s_nEndBlock = i + 8;
1291 goto StartRecomp;
1292
1293 // branches
1294 case 4: case 5: case 6: case 7:
1295
1296 s_branchTo = _Imm_ * 4 + i + 4;
1297 if( s_branchTo > startpc && s_branchTo < i ) s_nEndBlock = s_branchTo;
1298 else s_nEndBlock = i+8;
1299
1300 goto StartRecomp;
1301 }
1302
1303 i += 4;
1304 }
1305
1306 StartRecomp:
1307
1308 s_nBlockFF = false;
1309 if (s_branchTo == startpc) {
1310 s_nBlockFF = true;
1311 for (i = startpc; i < s_nEndBlock; i += 4) {
1312 if (i != s_nEndBlock - 8) {
1313 switch (iopMemRead32(i)) {
1314 case 0: // nop
1315 break;
1316 default:
1317 s_nBlockFF = false;
1318 }
1319 }
1320 }
1321 }
1322
1323 // rec info //
1324 {
1325 EEINST* pcur;
1326
1327 if( s_nInstCacheSize < (s_nEndBlock-startpc)/4+1 ) {
1328 free(s_pInstCache);
1329 s_nInstCacheSize = (s_nEndBlock-startpc)/4+10;
1330 s_pInstCache = (EEINST*)malloc(sizeof(EEINST)*s_nInstCacheSize);
1331 pxAssert( s_pInstCache != NULL );
1332 }
1333
1334 pcur = s_pInstCache + (s_nEndBlock-startpc)/4;
1335 _recClearInst(pcur);
1336 pcur->info = 0;
1337
1338 for(i = s_nEndBlock; i > startpc; i -= 4 ) {
1339 psxRegs.code = iopMemRead32(i-4);
1340 pcur[-1] = pcur[0];
1341 rpsxpropBSC(pcur-1, pcur);
1342 pcur--;
1343 }
1344 }
1345
1346 // dump code
1347 if( IsDebugBuild )
1348 {
1349 for(i = 0; i < ArraySize(s_psxrecblocks); ++i) {
1350 if( startpc == s_psxrecblocks[i] ) {
1351 iIopDumpBlock(startpc, recPtr);
1352 }
1353 }
1354
1355 if( (psxdump & 1) )
1356 iIopDumpBlock(startpc, recPtr);
1357 }
1358
1359 g_pCurInstInfo = s_pInstCache;
1360 while (!psxbranch && psxpc < s_nEndBlock) {
1361 psxRecompileNextInstruction(0);
1362 }
1363
1364 if( IsDebugBuild && (psxdump & 1) )
1365 iIopDumpBlock(startpc, recPtr);
1366
1367 pxAssert( (psxpc-startpc)>>2 <= 0xffff );
1368 s_pCurBlockEx->size = (psxpc-startpc)>>2;
1369
1370 for(i = 1; i < (u32)s_pCurBlockEx->size; ++i) {
1371 if (s_pCurBlock[i].GetFnptr() == (uptr)iopJITCompile)
1372 s_pCurBlock[i].SetFnptr((uptr)iopJITCompileInBlock);
1373 }
1374
1375 if( !(psxpc&0x10000000) )
1376 g_psxMaxRecMem = std::max( (psxpc&~0xa0000000), g_psxMaxRecMem );
1377
1378 if( psxbranch == 2 ) {
1379 _psxFlushCall(FLUSH_EVERYTHING);
1380
1381 iPsxBranchTest(0xffffffff, 1);
1382
1383 JMP32((uptr)iopDispatcherReg - ( (uptr)x86Ptr + 5 ));
1384 }
1385 else {
1386 if( psxbranch ) pxAssert( !willbranch3 );
1387 else
1388 {
1389 ADD32ItoM((uptr)&psxRegs.cycle, psxScaleBlockCycles() );
1390 SUB32ItoM((uptr)&iopCycleEE, psxScaleBlockCycles()*8 );
1391 }
1392
1393 if (willbranch3 || !psxbranch) {
1394 pxAssert( psxpc == s_nEndBlock );
1395 _psxFlushCall(FLUSH_EVERYTHING);
1396 MOV32ItoM((uptr)&psxRegs.pc, psxpc);
1397 recBlocks.Link(HWADDR(s_nEndBlock), xJcc32() );
1398 psxbranch = 3;
1399 }
1400 }
1401
1402 pxAssert( xGetPtr() < recMem->GetPtrEnd() );
1403
1404 pxAssert(xGetPtr() - recPtr < _64kb);
1405 s_pCurBlockEx->x86size = xGetPtr() - recPtr;
1406
1407 recPtr = xGetPtr();
1408
1409 pxAssert( (g_psxHasConstReg&g_psxFlushedConstReg) == g_psxHasConstReg );
1410
1411 s_pCurBlock = NULL;
1412 s_pCurBlockEx = NULL;
1413 }
1414
1415 static void recSetCacheReserve( uint reserveInMegs )
1416 {
1417 m_ConfiguredCacheReserve = reserveInMegs;
1418 }
1419
1420 static uint recGetCacheReserve()
1421 {
1422 return m_ConfiguredCacheReserve;
1423 }
1424
1425 R3000Acpu psxRec = {
1426 recReserve,
1427 recResetIOP,
1428 recExecute,
1429 recExecuteBlock,
1430 recClearIOP,
1431 recShutdown,
1432
1433 recGetCacheReserve,
1434 recSetCacheReserve
1435 };
1436

  ViewVC Help
Powered by ViewVC 1.1.22