/[pcsx2_0.9.7]/trunk/pcsx2/R5900.cpp
ViewVC logotype

Annotation of /trunk/pcsx2/R5900.cpp

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: 19456 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    
17     #include "PrecompiledHeader.h"
18     #include "Common.h"
19    
20     #include "R5900.h"
21     #include "R3000A.h"
22     #include "VUmicro.h"
23     #include "COP0.h"
24    
25     #include "System/SysThreads.h"
26     #include "R5900Exceptions.h"
27    
28     #include "Hardware.h"
29    
30     #include "Elfheader.h"
31     #include "CDVD/CDVD.h"
32     #include "Patch.h"
33     #include "DataBase_Loader.h"
34     #include "SamplProf.h"
35    
36     using namespace R5900; // for R5900 disasm tools
37    
38     s32 EEsCycle; // used to sync the IOP to the EE
39     u32 EEoCycle;
40    
41     __aligned16 cpuRegisters cpuRegs;
42     __aligned16 fpuRegisters fpuRegs;
43     __aligned16 tlbs tlb[48];
44     R5900cpu *Cpu = NULL;
45    
46     bool g_SkipBiosHack; // set at boot if the skip bios hack is on, reset before the game has started
47     bool g_GameStarted; // set when we reach the game's entry point or earlier if the entry point cannot be determined
48    
49     static const uint eeWaitCycles = 3072;
50    
51     bool eeEventTestIsActive = false;
52    
53     R5900Exception::BaseExcept::~BaseExcept() throw (){}
54    
55    
56     void cpuReset()
57     {
58     if( GetMTGS().IsOpen() )
59     GetMTGS().WaitGS(); // GS better be done processing before we reset the EE, just in case.
60    
61     memReset();
62     psxMemReset();
63     vuMicroMemReset();
64    
65     memzero(cpuRegs);
66     memzero(fpuRegs);
67     memzero(tlb);
68    
69     cpuRegs.pc = 0xbfc00000; //set pc reg to stack
70     cpuRegs.CP0.n.Config = 0x440;
71     cpuRegs.CP0.n.Status.val= 0x70400004; //0x10900000 <-- wrong; // COP0 enabled | BEV = 1 | TS = 1
72     cpuRegs.CP0.n.PRid = 0x00002e20; // PRevID = Revision ID, same as R5900
73     fpuRegs.fprc[0] = 0x00002e00; // fpu Revision..
74     fpuRegs.fprc[31] = 0x01000001; // fpu Status/Control
75    
76     g_nextBranchCycle = cpuRegs.cycle + 4;
77     EEsCycle = 0;
78     EEoCycle = cpuRegs.cycle;
79    
80     hwReset();
81     rcntInit();
82     psxReset();
83    
84     extern void Deci2Reset(); // lazy, no good header for it yet.
85     Deci2Reset();
86    
87     g_GameStarted = false;
88     g_SkipBiosHack = EmuConfig.UseBOOT2Injection;
89    
90     ElfCRC = 0;
91     DiscID = L"";
92     ElfEntry = -1;
93     LastELF = L"";
94     }
95    
96     __releaseinline void cpuException(u32 code, u32 bd)
97     {
98     bool errLevel2, checkStatus;
99     u32 offset;
100    
101     cpuRegs.branch = 0; // Tells the interpreter that an exception occurred during a branch.
102     cpuRegs.CP0.n.Cause = code & 0xffff;
103    
104     if(cpuRegs.CP0.n.Status.b.ERL == 0)
105     {
106     //Error Level 0-1
107     errLevel2 = FALSE;
108     checkStatus = (cpuRegs.CP0.n.Status.b.BEV == 0); // for TLB/general exceptions
109    
110     if (((code & 0x7C) >= 0x8) && ((code & 0x7C) <= 0xC))
111     offset = 0x0; //TLB Refill
112     else if ((code & 0x7C) == 0x0)
113     offset = 0x200; //Interrupt
114     else
115     offset = 0x180; // Everything else
116     }
117     else
118     {
119     //Error Level 2
120     errLevel2 = TRUE;
121     checkStatus = (cpuRegs.CP0.n.Status.b.DEV == 0); // for perf/debug exceptions
122    
123     Console.Error("*PCSX2* FIX ME: Level 2 cpuException");
124     if ((code & 0x38000) <= 0x8000 )
125     {
126     //Reset / NMI
127     cpuRegs.pc = 0xBFC00000;
128     Console.Warning("Reset request");
129     UpdateCP0Status();
130     return;
131     }
132     else if((code & 0x38000) == 0x10000)
133     offset = 0x80; //Performance Counter
134     else if((code & 0x38000) == 0x18000)
135     offset = 0x100; //Debug
136     else
137     Console.Error("Unknown Level 2 Exception!! Cause %x", code);
138     }
139    
140     if (cpuRegs.CP0.n.Status.b.EXL == 0)
141     {
142     cpuRegs.CP0.n.Status.b.EXL = 1;
143     if (bd)
144     {
145     Console.Warning("branch delay!!");
146     cpuRegs.CP0.n.EPC = cpuRegs.pc - 4;
147     cpuRegs.CP0.n.Cause |= 0x80000000;
148     }
149     else
150     {
151     cpuRegs.CP0.n.EPC = cpuRegs.pc;
152     cpuRegs.CP0.n.Cause &= ~0x80000000;
153     }
154     }
155     else
156     {
157     offset = 0x180; //Override the cause
158     if (errLevel2) Console.Warning("cpuException: Status.EXL = 1 cause %x", code);
159     }
160    
161     if (checkStatus)
162     cpuRegs.pc = 0x80000000 + offset;
163     else
164     cpuRegs.pc = 0xBFC00200 + offset;
165    
166     UpdateCP0Status();
167     }
168    
169     void cpuTlbMiss(u32 addr, u32 bd, u32 excode)
170     {
171     Console.Error("cpuTlbMiss pc:%x, cycl:%x, addr: %x, status=%x, code=%x",
172     cpuRegs.pc, cpuRegs.cycle, addr, cpuRegs.CP0.n.Status.val, excode);
173    
174     if (bd) Console.Warning("branch delay!!");
175    
176     pxFail( "TLB Miss handler is uninished code." ); // temporary
177    
178     cpuRegs.CP0.n.BadVAddr = addr;
179     cpuRegs.CP0.n.Context &= 0xFF80000F;
180     cpuRegs.CP0.n.Context |= (addr >> 9) & 0x007FFFF0;
181     cpuRegs.CP0.n.EntryHi = (addr & 0xFFFFE000) | (cpuRegs.CP0.n.EntryHi & 0x1FFF);
182    
183     cpuRegs.CP0.n.Cause = excode;
184     if (!(cpuRegs.CP0.n.Status.val & 0x2)) { // EXL bit
185     cpuRegs.CP0.n.EPC = cpuRegs.pc - 4;
186     }
187    
188     if ((cpuRegs.CP0.n.Status.val & 0x1) == 0) {
189     cpuRegs.pc = 0x80000000;
190     } else {
191     cpuRegs.pc = 0x80000180;
192     }
193    
194     cpuRegs.CP0.n.Status.b.EXL = 1;
195     UpdateCP0Status();
196     // Log=1; varLog|= 0x40000000;
197     }
198    
199     void cpuTlbMissR(u32 addr, u32 bd) {
200     cpuTlbMiss(addr, bd, EXC_CODE_TLBL);
201     }
202    
203     void cpuTlbMissW(u32 addr, u32 bd) {
204     cpuTlbMiss(addr, bd, EXC_CODE_TLBS);
205     }
206    
207     __forceinline void _cpuTestMissingINTC() {
208     if (cpuRegs.CP0.n.Status.val & 0x400 &&
209     psHu32(INTC_STAT) & psHu32(INTC_MASK)) {
210     if ((cpuRegs.interrupt & (1 << 30)) == 0) {
211     Console.Error("*PCSX2*: Error, missing INTC Interrupt");
212     }
213     }
214     }
215    
216     __forceinline void _cpuTestMissingDMAC() {
217     if (cpuRegs.CP0.n.Status.val & 0x800 &&
218     (psHu16(0xe012) & psHu16(0xe010) ||
219     psHu16(0xe010) & 0x8000)) {
220     if ((cpuRegs.interrupt & (1 << 31)) == 0) {
221     Console.Error("*PCSX2*: Error, missing DMAC Interrupt");
222     }
223     }
224     }
225    
226     void cpuTestMissingHwInts() {
227     if ((cpuRegs.CP0.n.Status.val & 0x10007) == 0x10001) {
228     _cpuTestMissingINTC();
229     _cpuTestMissingDMAC();
230     // _cpuTestTIMR();
231     }
232     }
233    
234     // sets a branch test to occur some time from an arbitrary starting point.
235     __forceinline void cpuSetNextBranch( u32 startCycle, s32 delta )
236     {
237     // typecast the conditional to signed so that things don't blow up
238     // if startCycle is greater than our next branch cycle.
239    
240     if( (int)(g_nextBranchCycle - startCycle) > delta )
241     {
242     g_nextBranchCycle = startCycle + delta;
243     }
244     }
245    
246     // sets a branch to occur some time from the current cycle
247     __forceinline void cpuSetNextBranchDelta( s32 delta )
248     {
249     cpuSetNextBranch( cpuRegs.cycle, delta );
250     }
251    
252     // tests the cpu cycle agaisnt the given start and delta values.
253     // Returns true if the delta time has passed.
254     __forceinline int cpuTestCycle( u32 startCycle, s32 delta )
255     {
256     // typecast the conditional to signed so that things don't explode
257     // if the startCycle is ahead of our current cpu cycle.
258    
259     return (int)(cpuRegs.cycle - startCycle) >= delta;
260     }
261    
262     // tells the EE to run the branch test the next time it gets a chance.
263     __forceinline void cpuSetBranch()
264     {
265     g_nextBranchCycle = cpuRegs.cycle;
266     }
267    
268     __forceinline void cpuClearInt( uint i )
269     {
270     jASSUME( i < 32 );
271     cpuRegs.interrupt &= ~(1 << i);
272     }
273    
274     static __forceinline void TESTINT( u8 n, void (*callback)() )
275     {
276     if( !(cpuRegs.interrupt & (1 << n)) ) return;
277    
278     if( cpuTestCycle( cpuRegs.sCycle[n], cpuRegs.eCycle[n] ) )
279     {
280     cpuClearInt( n );
281     callback();
282     }
283     else
284     cpuSetNextBranch( cpuRegs.sCycle[n], cpuRegs.eCycle[n] );
285     }
286    
287     static __forceinline void _cpuTestInterrupts()
288     {
289     if (!dmacRegs->ctrl.DMAE || psHu8(DMAC_ENABLER+2) == 1)
290     {
291     //Console.Write("DMAC Disabled or suspended");
292     return;
293     }
294     /* These are 'pcsx2 interrupts', they handle asynchronous stuff
295     that depends on the cycle timings */
296    
297     TESTINT(1, vif1Interrupt);
298     TESTINT(2, gsInterrupt);
299     TESTINT(5, EEsif0Interrupt);
300     TESTINT(6, EEsif1Interrupt);
301    
302     // Profile-guided Optimization (sorta)
303     // The following ints are rarely called. Encasing them in a conditional
304     // as follows helps speed up most games.
305    
306     if( cpuRegs.interrupt & 0xF19 ) // Bits 0 3 4 8 9 10 11 ( 111100011001 )
307     {
308     TESTINT(0, vif0Interrupt);
309    
310     TESTINT(3, ipu0Interrupt);
311     TESTINT(4, ipu1Interrupt);
312    
313     TESTINT(8, SPRFROMinterrupt);
314     TESTINT(9, SPRTOinterrupt);
315    
316     TESTINT(10, vifMFIFOInterrupt);
317     TESTINT(11, gifMFIFOInterrupt);
318     }
319     }
320    
321     static __forceinline void _cpuTestTIMR()
322     {
323     cpuRegs.CP0.n.Count += cpuRegs.cycle-s_iLastCOP0Cycle;
324     s_iLastCOP0Cycle = cpuRegs.cycle;
325    
326     // fixme: this looks like a hack to make up for the fact that the TIMR
327     // doesn't yet have a proper mechanism for setting itself up on a nextBranchCycle.
328     // A proper fix would schedule the TIMR to trigger at a specific cycle anytime
329     // the Count or Compare registers are modified.
330    
331     if ( (cpuRegs.CP0.n.Status.val & 0x8000) &&
332     cpuRegs.CP0.n.Count >= cpuRegs.CP0.n.Compare && cpuRegs.CP0.n.Count < cpuRegs.CP0.n.Compare+1000 )
333     {
334     Console.WriteLn( Color_Magenta, "timr intr: %x, %x", cpuRegs.CP0.n.Count, cpuRegs.CP0.n.Compare);
335     cpuException(0x808000, cpuRegs.branch);
336     }
337     }
338    
339     static __forceinline void _cpuTestPERF()
340     {
341     // Perfs are updated when read by games (COP0's MFC0/MTC0 instructions), so we need
342     // only update them at semi-regular intervals to keep cpuRegs.cycle from wrapping
343     // around twice on us btween updates. Hence this function is called from the cpu's
344     // Counters update.
345    
346     COP0_UpdatePCCR();
347     }
348    
349     // Checks the COP0.Status for exception enablings.
350     // Exception handling for certain modes is *not* currently supported, this function filters
351     // them out. Exceptions while the exception handler is active (EIE), or exceptions of any
352     // level other than 0 are ignored here.
353    
354     static bool cpuIntsEnabled()
355     {
356     return cpuRegs.CP0.n.Status.b.EIE && cpuRegs.CP0.n.Status.b.IE &&
357     !cpuRegs.CP0.n.Status.b.EXL && (cpuRegs.CP0.n.Status.b.ERL == 0);
358     }
359    
360     // if cpuRegs.cycle is greater than this cycle, should check cpuBranchTest for updates
361     u32 g_nextBranchCycle = 0;
362    
363     // Shared portion of the branch test, called from both the Interpreter
364     // and the recompiler. (moved here to help alleviate redundant code)
365     __forceinline void _cpuBranchTest_Shared()
366     {
367     eeEventTestIsActive = true;
368     g_nextBranchCycle = cpuRegs.cycle + eeWaitCycles;
369    
370     // ---- Counters -------------
371     // Important: the vsync counter must be the first to be checked. It includes emulation
372     // escape/suspend hooks, and it's really a good idea to suspend/resume emulation before
373     // doing any actual meaninful branchtest logic.
374    
375     if( cpuTestCycle( nextsCounter, nextCounter ) )
376     {
377     rcntUpdate();
378     _cpuTestPERF();
379     }
380    
381     rcntUpdate_hScanline();
382    
383     _cpuTestTIMR();
384    
385     // ---- Interrupts -------------
386     // Handles all interrupts except 30 and 31, which are handled later.
387    
388     if( cpuRegs.interrupt & ~(3<<30) )
389     _cpuTestInterrupts();
390    
391     // ---- IOP -------------
392     // * It's important to run a psxBranchTest before calling ExecuteBlock. This
393     // is because the IOP does not always perform branch tests before returning
394     // (during the prev branch) and also so it can act on the state the EE has
395     // given it before executing any code.
396     //
397     // * The IOP cannot always be run. If we run IOP code every time through the
398     // cpuBranchTest, the IOP generally starts to run way ahead of the EE.
399    
400     EEsCycle += cpuRegs.cycle - EEoCycle;
401     EEoCycle = cpuRegs.cycle;
402    
403     if( EEsCycle > 0 )
404     iopBranchAction = true;
405    
406     psxBranchTest();
407    
408     if( iopBranchAction )
409     {
410     //if( EEsCycle < -450 )
411     // Console.WriteLn( " IOP ahead by: %d cycles", -EEsCycle );
412    
413     // Experimental and Probably Unnecessry Logic -->
414     // Check if the EE already has an exception pending, and if so we shouldn't
415     // waste too much time updating the IOP. Theory being that the EE and IOP should
416     // run closely in sync during raised exception events. But in practice it didn't
417     // seem to make much of a difference.
418    
419     // Note: The IOP is very good about chaining blocks together so it tends to
420     // run lots of cycles, even with only 32 (4 IOP) cycles specified here. That's
421     // probably why it doesn't improve sync much.
422    
423     /*bool eeExceptPending = cpuIntsEnabled() &&
424     //( cpuRegs.CP0.n.Status.b.EIE && cpuRegs.CP0.n.Status.b.IE && (cpuRegs.CP0.n.Status.b.ERL == 0) ) &&
425     //( (cpuRegs.CP0.n.Status.val & 0x10007) == 0x10001 ) &&
426     ( (cpuRegs.interrupt & (3<<30)) != 0 );
427    
428     if( eeExceptPending )
429     {
430     // ExecuteBlock returns a negative value, so subtract it from the cycle count
431     // specified to get the total cycles processed! :D
432     int cycleCount = std::min( EEsCycle, (s32)(eeWaitCycles>>4) );
433     int cyclesRun = cycleCount - psxCpu->ExecuteBlock( cycleCount );
434     EEsCycle -= cyclesRun;
435     //Console.Warning( "IOP Exception-Pending Execution -- EEsCycle: %d", EEsCycle );
436     }
437     else*/
438     {
439     EEsCycle = psxCpu->ExecuteBlock( EEsCycle );
440     }
441    
442     iopBranchAction = false;
443     }
444    
445     // ---- VU0 -------------
446     // We're in a BranchTest. All dynarec registers are flushed
447     // so there is no need to freeze registers here.
448     CpuVU0->ExecuteBlock();
449    
450     // Note: We don't update the VU1 here because it runs it's micro-programs in
451     // one shot always. That is, when a program is executed the VU1 doesn't even
452     // bother to return until the program is completely finished.
453    
454     // ---- Schedule Next Event Test --------------
455    
456     if( EEsCycle > 192 )
457     {
458     // EE's running way ahead of the IOP still, so we should branch quickly to give the
459     // IOP extra timeslices in short order.
460    
461     cpuSetNextBranchDelta( 48 );
462     //Console.Warning( "EE ahead of the IOP -- Rapid Branch! %d", EEsCycle );
463     }
464    
465     // The IOP could be running ahead/behind of us, so adjust the iop's next branch by its
466     // relative position to the EE (via EEsCycle)
467     cpuSetNextBranchDelta( ((g_psxNextBranchCycle-psxRegs.cycle)*8) - EEsCycle );
468    
469     // Apply the hsync counter's nextCycle
470     cpuSetNextBranch( hsyncCounter.sCycle, hsyncCounter.CycleT );
471    
472     // Apply vsync and other counter nextCycles
473     cpuSetNextBranch( nextsCounter, nextCounter );
474    
475     eeEventTestIsActive = false;
476    
477     // ---- INTC / DMAC Exceptions -----------------
478     // Raise the INTC and DMAC interrupts here, which usually throw exceptions.
479     // This should be done last since the IOP and the VU0 can raise several EE
480     // exceptions.
481    
482     //if ((cpuRegs.CP0.n.Status.val & 0x10007) == 0x10001)
483     if( cpuIntsEnabled() )
484     {
485     TESTINT(30, intcInterrupt);
486     TESTINT(31, dmacInterrupt);
487     }
488     }
489    
490     __releaseinline void cpuTestINTCInts()
491     {
492     if( cpuRegs.interrupt & (1 << 30) ) return;
493     //if( (cpuRegs.CP0.n.Status.val & 0x10407) != 0x10401 ) return;
494     if( !cpuIntsEnabled() ) return;
495     if( (psHu32(INTC_STAT) & psHu32(INTC_MASK)) == 0 ) return;
496    
497     cpuRegs.interrupt|= 1 << 30;
498     cpuRegs.sCycle[30] = cpuRegs.cycle;
499     cpuRegs.eCycle[30] = 4; //Needs to be 4 to account for bus delays/pipelines etc
500    
501     // only set the next branch delta if the exception won't be handled for
502     // the current branch...
503     if( !eeEventTestIsActive )
504     cpuSetNextBranchDelta( 4 );
505     else if(psxCycleEE > 0)
506     {
507     psxBreak += psxCycleEE; // record the number of cycles the IOP didn't run.
508     psxCycleEE = 0;
509     }
510     }
511    
512     __forceinline void cpuTestDMACInts()
513     {
514     if ( cpuRegs.interrupt & (1 << 31) ) return;
515     if ((cpuRegs.CP0.n.Status.val & 0x10807) != 0x10801) return;
516    
517     if ( ( (psHu16(0xe012) & psHu16(0xe010)) == 0) &&
518     ( (psHu16(0xe010) & 0x8000) == 0) ) return;
519    
520     cpuRegs.interrupt|= 1 << 31;
521     cpuRegs.sCycle[31] = cpuRegs.cycle;
522     cpuRegs.eCycle[31] = 4; //Needs to be 4 to account for bus delays/pipelines etc
523    
524     // only set the next branch delta if the exception won't be handled for
525     // the current branch...
526     if( !eeEventTestIsActive )
527     cpuSetNextBranchDelta( 4 );
528     else if(psxCycleEE > 0)
529     {
530     psxBreak += psxCycleEE; // record the number of cycles the IOP didn't run.
531     psxCycleEE = 0;
532     }
533     }
534    
535     __forceinline void cpuTestTIMRInts() {
536     if ((cpuRegs.CP0.n.Status.val & 0x10007) == 0x10001) {
537     _cpuTestPERF();
538     _cpuTestTIMR();
539     }
540     }
541    
542     __forceinline void cpuTestHwInts() {
543     cpuTestINTCInts();
544     cpuTestDMACInts();
545     cpuTestTIMRInts();
546     }
547    
548     __forceinline void CPU_INT( u32 n, s32 ecycle)
549     {
550     if( n != 2 && cpuRegs.interrupt & (1<<n) ){ //2 is Gif, and every path 3 masking game triggers this :/
551     DevCon.Warning( "***** EE > Twice-thrown int on IRQ %d", n );
552     }
553    
554     // EE events happen 1 cycle in the future instead of whatever was requested.
555     // This can be used on games with PATH3 masking issues for example, or when
556     // some FMV look bad.
557     if(CHECK_EETIMINGHACK) ecycle = 1;
558    
559     cpuRegs.interrupt|= 1 << n;
560     cpuRegs.sCycle[n] = cpuRegs.cycle;
561     cpuRegs.eCycle[n] = ecycle;
562    
563     // Interrupt is happening soon: make sure both EE and IOP are aware.
564    
565     if( ecycle <= 28 && psxCycleEE > 0 )
566     {
567     // If running in the IOP, force it to break immediately into the EE.
568     // the EE's branch test is due to run.
569    
570     psxBreak += psxCycleEE; // record the number of cycles the IOP didn't run.
571     psxCycleEE = 0;
572     }
573    
574     cpuSetNextBranchDelta( cpuRegs.eCycle[n] );
575     }
576    
577     void __fastcall eeGameStarting()
578     {
579     if (!g_GameStarted && ElfCRC) {
580     wxString gameCRC( wxsFormat( L"%8.8x", ElfCRC ) );
581     wxString gameName = L"Unknown Game (\?\?\?)";
582     wxString gameSerial = L" [" + DiscID + L"]";
583     wxString gameCompat = L" [Status = Unknown]";
584     wxString gamePatch = L"";
585     wxString gameFixes = L"";
586     wxString gameCheats = L"";
587    
588     if (GameDB && GameDB->gameLoaded()) {
589     int compat = GameDB->getInt("Compat");
590     gameName = GameDB->getStringWX("Name");
591     gameName += L" (" + GameDB->getStringWX("Region") + L")";
592     gameCompat = L" [Status = "+compatToStringWX(compat)+L"]";
593     }
594    
595     if (EmuConfig.EnablePatches) {
596     int patches = InitPatches(gameCRC);
597     if (patches) {
598     wxString pString( wxsFormat( L"%d", patches ) );
599     gamePatch = L" [Patches = " + pString + L"]";
600     }
601     int fixes = loadGameSettings(GameDB);
602     if (fixes) {
603     wxString pString( wxsFormat( L"%d", fixes ) );
604     gameFixes = L" [Fixes = " + pString + L"]";
605     }
606     }
607    
608     if (EmuConfig.EnableCheats) {
609     int cheats = InitCheats(gameCRC);
610     if (cheats) {
611     wxString cString( wxsFormat( L"%d", cheats ) );
612     gameCheats = L" [Cheats = " + cString + L"]";
613     }
614     }
615    
616     Console.SetTitle(gameName+gameSerial+gameCompat+gameFixes+gamePatch+gameCheats);
617    
618     GetMTGS().SendGameCRC(ElfCRC);
619     g_GameStarted = true;
620    
621     if (0) ProfilerSetEnabled(true);
622     }
623    
624     if (EmuConfig.EnablePatches) ApplyPatch(0);
625     if (EmuConfig.EnableCheats) ApplyCheat(0);
626     }
627    
628     void __fastcall eeloadReplaceOSDSYS()
629     {
630     g_SkipBiosHack = false;
631    
632     const wxString &elf_override = GetCoreThread().GetElfOverride();
633    
634     if (!elf_override.IsEmpty())
635     cdvdReloadElfInfo(L"host:" + elf_override);
636     else
637     cdvdReloadElfInfo();
638    
639     // didn't recognise an ELF
640     if (ElfEntry == -1) {
641     eeGameStarting();
642     return;
643     }
644    
645     static u32 osdsys = 0, osdsys_p = 0;
646     // Memory this high is safe before the game's running presumably
647     // Other options are kernel memory (first megabyte) or the scratchpad
648     // PS2LOGO is loaded at 16MB, let's use 17MB
649     const u32 safemem = 0x1100000;
650    
651     // The strings are all 64-bit aligned. Why? I don't know, but they are
652     for (u32 i = EELOAD_START; i < EELOAD_START + EELOAD_SIZE; i += 8) {
653     if (!strcmp((char*)PSM(i), "rom0:OSDSYS")) {
654     osdsys = i;
655     break;
656     }
657     }
658     pxAssert(osdsys);
659    
660     for (u32 i = osdsys - 4; i >= EELOAD_START; i -= 4) {
661     if (memRead32(i) == osdsys) {
662     osdsys_p = i;
663     break;
664     }
665     }
666     pxAssert(osdsys_p);
667    
668     string elfname;
669    
670     if (!elf_override.IsEmpty())
671     {
672     elfname += "host:";
673     elfname += elf_override.ToUTF8();
674     }
675     else
676     {
677     wxString boot2;
678     if (GetPS2ElfName(boot2) == 2)
679     elfname = boot2.ToUTF8();
680     }
681    
682     if (!elfname.empty())
683     {
684     strcpy((char*)PSM(safemem), elfname.c_str());
685     memWrite32(osdsys_p, safemem);
686     }
687     // else... uh...?
688     }

  ViewVC Help
Powered by ViewVC 1.1.22