/[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 62 - (hide annotations) (download)
Tue Sep 7 11:08:22 2010 UTC (9 years, 10 months ago) by william
File size: 16909 byte(s)
Auto Commited Import of: pcsx2-0.9.7-r3738-debug in ./trunk
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 william 62 #include "IPU/IPUdma.h"
30 william 31
31     #include "Elfheader.h"
32     #include "CDVD/CDVD.h"
33     #include "Patch.h"
34 william 62 #include "GameDatabase.h"
35 william 31 #include "SamplProf.h"
36    
37     using namespace R5900; // for R5900 disasm tools
38    
39     s32 EEsCycle; // used to sync the IOP to the EE
40     u32 EEoCycle;
41    
42     __aligned16 cpuRegisters cpuRegs;
43     __aligned16 fpuRegisters fpuRegs;
44     __aligned16 tlbs tlb[48];
45     R5900cpu *Cpu = NULL;
46    
47     bool g_SkipBiosHack; // set at boot if the skip bios hack is on, reset before the game has started
48     bool g_GameStarted; // set when we reach the game's entry point or earlier if the entry point cannot be determined
49    
50     static const uint eeWaitCycles = 3072;
51    
52     bool eeEventTestIsActive = false;
53    
54     void cpuReset()
55     {
56     if( GetMTGS().IsOpen() )
57     GetMTGS().WaitGS(); // GS better be done processing before we reset the EE, just in case.
58    
59     memReset();
60     psxMemReset();
61     vuMicroMemReset();
62    
63     memzero(cpuRegs);
64     memzero(fpuRegs);
65     memzero(tlb);
66    
67     cpuRegs.pc = 0xbfc00000; //set pc reg to stack
68     cpuRegs.CP0.n.Config = 0x440;
69     cpuRegs.CP0.n.Status.val= 0x70400004; //0x10900000 <-- wrong; // COP0 enabled | BEV = 1 | TS = 1
70     cpuRegs.CP0.n.PRid = 0x00002e20; // PRevID = Revision ID, same as R5900
71     fpuRegs.fprc[0] = 0x00002e00; // fpu Revision..
72     fpuRegs.fprc[31] = 0x01000001; // fpu Status/Control
73    
74 william 62 g_nextEventCycle = cpuRegs.cycle + 4;
75 william 31 EEsCycle = 0;
76     EEoCycle = cpuRegs.cycle;
77    
78     hwReset();
79     rcntInit();
80     psxReset();
81    
82     extern void Deci2Reset(); // lazy, no good header for it yet.
83     Deci2Reset();
84    
85     g_GameStarted = false;
86     g_SkipBiosHack = EmuConfig.UseBOOT2Injection;
87    
88     ElfCRC = 0;
89 william 62 DiscSerial = L"";
90 william 31 ElfEntry = -1;
91 william 62
92     // FIXME: LastELF should be reset on media changes as well as on CPU resets, in
93     // the very unlikely case that a user swaps to another media source that "looks"
94     // the same (identical ELF names) but is actually different (devs actually could
95     // run into this while testing minor binary hacked changes to ISO images, which
96     // is why I found out about this) --air
97 william 31 LastELF = L"";
98     }
99    
100 william 62 __ri void cpuException(u32 code, u32 bd)
101 william 31 {
102     bool errLevel2, checkStatus;
103     u32 offset;
104    
105     cpuRegs.branch = 0; // Tells the interpreter that an exception occurred during a branch.
106     cpuRegs.CP0.n.Cause = code & 0xffff;
107    
108     if(cpuRegs.CP0.n.Status.b.ERL == 0)
109     {
110     //Error Level 0-1
111     errLevel2 = FALSE;
112     checkStatus = (cpuRegs.CP0.n.Status.b.BEV == 0); // for TLB/general exceptions
113    
114     if (((code & 0x7C) >= 0x8) && ((code & 0x7C) <= 0xC))
115     offset = 0x0; //TLB Refill
116     else if ((code & 0x7C) == 0x0)
117     offset = 0x200; //Interrupt
118     else
119     offset = 0x180; // Everything else
120     }
121     else
122     {
123     //Error Level 2
124     errLevel2 = TRUE;
125     checkStatus = (cpuRegs.CP0.n.Status.b.DEV == 0); // for perf/debug exceptions
126    
127     Console.Error("*PCSX2* FIX ME: Level 2 cpuException");
128     if ((code & 0x38000) <= 0x8000 )
129     {
130     //Reset / NMI
131     cpuRegs.pc = 0xBFC00000;
132     Console.Warning("Reset request");
133 william 62 cpuUpdateOperationMode();
134 william 31 return;
135     }
136     else if((code & 0x38000) == 0x10000)
137     offset = 0x80; //Performance Counter
138     else if((code & 0x38000) == 0x18000)
139     offset = 0x100; //Debug
140     else
141     Console.Error("Unknown Level 2 Exception!! Cause %x", code);
142     }
143    
144     if (cpuRegs.CP0.n.Status.b.EXL == 0)
145     {
146     cpuRegs.CP0.n.Status.b.EXL = 1;
147     if (bd)
148     {
149     Console.Warning("branch delay!!");
150     cpuRegs.CP0.n.EPC = cpuRegs.pc - 4;
151     cpuRegs.CP0.n.Cause |= 0x80000000;
152     }
153     else
154     {
155     cpuRegs.CP0.n.EPC = cpuRegs.pc;
156     cpuRegs.CP0.n.Cause &= ~0x80000000;
157     }
158     }
159     else
160     {
161     offset = 0x180; //Override the cause
162     if (errLevel2) Console.Warning("cpuException: Status.EXL = 1 cause %x", code);
163     }
164    
165     if (checkStatus)
166     cpuRegs.pc = 0x80000000 + offset;
167     else
168     cpuRegs.pc = 0xBFC00200 + offset;
169    
170 william 62 cpuUpdateOperationMode();
171 william 31 }
172    
173     void cpuTlbMiss(u32 addr, u32 bd, u32 excode)
174     {
175     Console.Error("cpuTlbMiss pc:%x, cycl:%x, addr: %x, status=%x, code=%x",
176     cpuRegs.pc, cpuRegs.cycle, addr, cpuRegs.CP0.n.Status.val, excode);
177    
178     if (bd) Console.Warning("branch delay!!");
179    
180     pxFail( "TLB Miss handler is uninished code." ); // temporary
181    
182     cpuRegs.CP0.n.BadVAddr = addr;
183     cpuRegs.CP0.n.Context &= 0xFF80000F;
184     cpuRegs.CP0.n.Context |= (addr >> 9) & 0x007FFFF0;
185     cpuRegs.CP0.n.EntryHi = (addr & 0xFFFFE000) | (cpuRegs.CP0.n.EntryHi & 0x1FFF);
186    
187     cpuRegs.CP0.n.Cause = excode;
188     if (!(cpuRegs.CP0.n.Status.val & 0x2)) { // EXL bit
189     cpuRegs.CP0.n.EPC = cpuRegs.pc - 4;
190     }
191    
192     if ((cpuRegs.CP0.n.Status.val & 0x1) == 0) {
193     cpuRegs.pc = 0x80000000;
194     } else {
195     cpuRegs.pc = 0x80000180;
196     }
197    
198     cpuRegs.CP0.n.Status.b.EXL = 1;
199 william 62 cpuUpdateOperationMode();
200 william 31 // Log=1; varLog|= 0x40000000;
201     }
202    
203     void cpuTlbMissR(u32 addr, u32 bd) {
204     cpuTlbMiss(addr, bd, EXC_CODE_TLBL);
205     }
206    
207     void cpuTlbMissW(u32 addr, u32 bd) {
208     cpuTlbMiss(addr, bd, EXC_CODE_TLBS);
209     }
210    
211     // sets a branch test to occur some time from an arbitrary starting point.
212 william 62 __fi void cpuSetNextEvent( u32 startCycle, s32 delta )
213 william 31 {
214     // typecast the conditional to signed so that things don't blow up
215     // if startCycle is greater than our next branch cycle.
216    
217 william 62 if( (int)(g_nextEventCycle - startCycle) > delta )
218 william 31 {
219 william 62 g_nextEventCycle = startCycle + delta;
220 william 31 }
221     }
222    
223     // sets a branch to occur some time from the current cycle
224 william 62 __fi void cpuSetNextEventDelta( s32 delta )
225 william 31 {
226 william 62 cpuSetNextEvent( cpuRegs.cycle, delta );
227 william 31 }
228    
229 william 62 // tests the cpu cycle against the given start and delta values.
230 william 31 // Returns true if the delta time has passed.
231 william 62 __fi int cpuTestCycle( u32 startCycle, s32 delta )
232 william 31 {
233     // typecast the conditional to signed so that things don't explode
234     // if the startCycle is ahead of our current cpu cycle.
235    
236     return (int)(cpuRegs.cycle - startCycle) >= delta;
237     }
238    
239     // tells the EE to run the branch test the next time it gets a chance.
240 william 62 __fi void cpuSetEvent()
241 william 31 {
242 william 62 g_nextEventCycle = cpuRegs.cycle;
243 william 31 }
244    
245 william 62 __fi void cpuClearInt( uint i )
246 william 31 {
247     jASSUME( i < 32 );
248     cpuRegs.interrupt &= ~(1 << i);
249     }
250    
251 william 62 static __fi void TESTINT( u8 n, void (*callback)() )
252 william 31 {
253     if( !(cpuRegs.interrupt & (1 << n)) ) return;
254    
255     if( cpuTestCycle( cpuRegs.sCycle[n], cpuRegs.eCycle[n] ) )
256     {
257     cpuClearInt( n );
258     callback();
259     }
260     else
261 william 62 cpuSetNextEvent( cpuRegs.sCycle[n], cpuRegs.eCycle[n] );
262 william 31 }
263    
264 william 62 // [TODO] move this function to LegacyDmac.cpp, and remove most of the DMAC-related headers from
265     // being included into R5900.cpp.
266     static __fi void _cpuTestInterrupts()
267 william 31 {
268 william 62 if (!dmacRegs.ctrl.DMAE || (psHu8(DMAC_ENABLER+2) & 1))
269 william 31 {
270     //Console.Write("DMAC Disabled or suspended");
271     return;
272     }
273     /* These are 'pcsx2 interrupts', they handle asynchronous stuff
274     that depends on the cycle timings */
275    
276 william 62 TESTINT(DMAC_VIF1, vif1Interrupt);
277     TESTINT(DMAC_GIF, gsInterrupt);
278     TESTINT(DMAC_SIF0, EEsif0Interrupt);
279     TESTINT(DMAC_SIF1, EEsif1Interrupt);
280 william 31
281     // Profile-guided Optimization (sorta)
282     // The following ints are rarely called. Encasing them in a conditional
283     // as follows helps speed up most games.
284    
285     if( cpuRegs.interrupt & 0xF19 ) // Bits 0 3 4 8 9 10 11 ( 111100011001 )
286     {
287 william 62 TESTINT(DMAC_VIF0, vif0Interrupt);
288 william 31
289 william 62 TESTINT(DMAC_FROM_IPU, ipu0Interrupt);
290     TESTINT(DMAC_TO_IPU, ipu1Interrupt);
291 william 31
292 william 62 TESTINT(DMAC_FROM_SPR, SPRFROMinterrupt);
293     TESTINT(DMAC_TO_SPR, SPRTOinterrupt);
294 william 31
295 william 62 TESTINT(DMAC_MFIFO_VIF, vifMFIFOInterrupt);
296     TESTINT(DMAC_MFIFO_GIF, gifMFIFOInterrupt);
297 william 31 }
298     }
299    
300 william 62 static __fi void _cpuTestTIMR()
301 william 31 {
302     cpuRegs.CP0.n.Count += cpuRegs.cycle-s_iLastCOP0Cycle;
303     s_iLastCOP0Cycle = cpuRegs.cycle;
304    
305     // fixme: this looks like a hack to make up for the fact that the TIMR
306 william 62 // doesn't yet have a proper mechanism for setting itself up on a nextEventCycle.
307 william 31 // A proper fix would schedule the TIMR to trigger at a specific cycle anytime
308     // the Count or Compare registers are modified.
309    
310     if ( (cpuRegs.CP0.n.Status.val & 0x8000) &&
311     cpuRegs.CP0.n.Count >= cpuRegs.CP0.n.Compare && cpuRegs.CP0.n.Count < cpuRegs.CP0.n.Compare+1000 )
312     {
313     Console.WriteLn( Color_Magenta, "timr intr: %x, %x", cpuRegs.CP0.n.Count, cpuRegs.CP0.n.Compare);
314     cpuException(0x808000, cpuRegs.branch);
315     }
316     }
317    
318 william 62 static __fi void _cpuTestPERF()
319 william 31 {
320     // Perfs are updated when read by games (COP0's MFC0/MTC0 instructions), so we need
321     // only update them at semi-regular intervals to keep cpuRegs.cycle from wrapping
322     // around twice on us btween updates. Hence this function is called from the cpu's
323     // Counters update.
324    
325     COP0_UpdatePCCR();
326     }
327    
328     // Checks the COP0.Status for exception enablings.
329     // Exception handling for certain modes is *not* currently supported, this function filters
330     // them out. Exceptions while the exception handler is active (EIE), or exceptions of any
331     // level other than 0 are ignored here.
332    
333 william 62 static bool cpuIntsEnabled(int Interrupt)
334 william 31 {
335 william 62 bool IntType = !!(cpuRegs.CP0.n.Status.val & Interrupt); //Choose either INTC or DMAC, depending on what called it
336    
337     return IntType && cpuRegs.CP0.n.Status.b.EIE && cpuRegs.CP0.n.Status.b.IE &&
338 william 31 !cpuRegs.CP0.n.Status.b.EXL && (cpuRegs.CP0.n.Status.b.ERL == 0);
339     }
340    
341 william 62 // if cpuRegs.cycle is greater than this cycle, should check cpuEventTest for updates
342     u32 g_nextEventCycle = 0;
343 william 31
344     // Shared portion of the branch test, called from both the Interpreter
345     // and the recompiler. (moved here to help alleviate redundant code)
346 william 62 __fi void _cpuEventTest_Shared()
347 william 31 {
348 william 62 ScopedBool etest(eeEventTestIsActive);
349     g_nextEventCycle = cpuRegs.cycle + eeWaitCycles;
350 william 31
351 william 62 // ---- INTC / DMAC (CPU-level Exceptions) -----------------
352     // Done first because exceptions raised during event tests need to be postponed a few
353     // cycles (fixes Grandia II [PAL], which does a spin loop on a vsync and expects to
354     // be able to read the value before the exception handler clears it).
355    
356     uint mask = intcInterrupt() | dmacInterrupt();
357     if (cpuIntsEnabled(mask)) cpuException(mask, cpuRegs.branch);
358    
359    
360 william 31 // ---- Counters -------------
361     // Important: the vsync counter must be the first to be checked. It includes emulation
362     // escape/suspend hooks, and it's really a good idea to suspend/resume emulation before
363 william 62 // doing any actual meaningful branchtest logic.
364 william 31
365     if( cpuTestCycle( nextsCounter, nextCounter ) )
366     {
367     rcntUpdate();
368     _cpuTestPERF();
369     }
370    
371     rcntUpdate_hScanline();
372    
373     _cpuTestTIMR();
374    
375     // ---- Interrupts -------------
376 william 62 // These are basically just DMAC-related events, which also piggy-back the same bits as
377     // the PS2's own DMA channel IRQs and IRQ Masks.
378 william 31
379 william 62 _cpuTestInterrupts();
380 william 31
381     // ---- IOP -------------
382 william 62 // * It's important to run a iopEventTest before calling ExecuteBlock. This
383 william 31 // is because the IOP does not always perform branch tests before returning
384     // (during the prev branch) and also so it can act on the state the EE has
385     // given it before executing any code.
386     //
387     // * The IOP cannot always be run. If we run IOP code every time through the
388 william 62 // cpuEventTest, the IOP generally starts to run way ahead of the EE.
389 william 31
390     EEsCycle += cpuRegs.cycle - EEoCycle;
391     EEoCycle = cpuRegs.cycle;
392    
393     if( EEsCycle > 0 )
394 william 62 iopEventAction = true;
395 william 31
396 william 62 iopEventTest();
397 william 31
398 william 62 if( iopEventAction )
399 william 31 {
400     //if( EEsCycle < -450 )
401     // Console.WriteLn( " IOP ahead by: %d cycles", -EEsCycle );
402    
403 william 62 EEsCycle = psxCpu->ExecuteBlock( EEsCycle );
404 william 31
405 william 62 iopEventAction = false;
406 william 31 }
407    
408     // ---- VU0 -------------
409 william 62 // We're in a EventTest. All dynarec registers are flushed
410 william 31 // so there is no need to freeze registers here.
411     CpuVU0->ExecuteBlock();
412    
413     // Note: We don't update the VU1 here because it runs it's micro-programs in
414     // one shot always. That is, when a program is executed the VU1 doesn't even
415     // bother to return until the program is completely finished.
416    
417     // ---- Schedule Next Event Test --------------
418    
419     if( EEsCycle > 192 )
420     {
421     // EE's running way ahead of the IOP still, so we should branch quickly to give the
422     // IOP extra timeslices in short order.
423    
424 william 62 cpuSetNextEventDelta( 48 );
425     //Console.Warning( "EE ahead of the IOP -- Rapid Event! %d", EEsCycle );
426 william 31 }
427    
428     // The IOP could be running ahead/behind of us, so adjust the iop's next branch by its
429     // relative position to the EE (via EEsCycle)
430 william 62 cpuSetNextEventDelta( ((g_iopNextEventCycle-psxRegs.cycle)*8) - EEsCycle );
431 william 31
432     // Apply the hsync counter's nextCycle
433 william 62 cpuSetNextEvent( hsyncCounter.sCycle, hsyncCounter.CycleT );
434 william 31
435     // Apply vsync and other counter nextCycles
436 william 62 cpuSetNextEvent( nextsCounter, nextCounter );
437 william 31 }
438    
439 william 62 __ri void cpuTestINTCInts()
440 william 31 {
441 william 62 // Check the COP0's Status register for general interrupt disables, and the 0x400
442     // bit (which is INTC master toggle).
443     if( !cpuIntsEnabled(0x400) ) return;
444    
445 william 31 if( (psHu32(INTC_STAT) & psHu32(INTC_MASK)) == 0 ) return;
446    
447 william 62 cpuSetNextEventDelta( 4 );
448     if(eeEventTestIsActive && (iopCycleEE > 0))
449 william 31 {
450 william 62 iopBreak += iopCycleEE; // record the number of cycles the IOP didn't run.
451     iopCycleEE = 0;
452 william 31 }
453     }
454    
455 william 62 __fi void cpuTestDMACInts()
456 william 31 {
457 william 62 // Check the COP0's Status register for general interrupt disables, and the 0x800
458     // bit (which is the DMAC master toggle).
459     if( !cpuIntsEnabled(0x800) ) return;
460 william 31
461     if ( ( (psHu16(0xe012) & psHu16(0xe010)) == 0) &&
462     ( (psHu16(0xe010) & 0x8000) == 0) ) return;
463    
464 william 62 cpuSetNextEventDelta( 4 );
465     if(eeEventTestIsActive && (iopCycleEE > 0))
466 william 31 {
467 william 62 iopBreak += iopCycleEE; // record the number of cycles the IOP didn't run.
468     iopCycleEE = 0;
469 william 31 }
470     }
471    
472 william 62 __fi void cpuTestTIMRInts() {
473 william 31 if ((cpuRegs.CP0.n.Status.val & 0x10007) == 0x10001) {
474     _cpuTestPERF();
475     _cpuTestTIMR();
476     }
477     }
478    
479 william 62 __fi void cpuTestHwInts() {
480 william 31 cpuTestINTCInts();
481     cpuTestDMACInts();
482     cpuTestTIMRInts();
483     }
484    
485 william 62 __fi void CPU_INT( EE_EventType n, s32 ecycle)
486 william 31 {
487     if( n != 2 && cpuRegs.interrupt & (1<<n) ){ //2 is Gif, and every path 3 masking game triggers this :/
488     DevCon.Warning( "***** EE > Twice-thrown int on IRQ %d", n );
489     }
490    
491 william 62 // EE events happen 8 cycles in the future instead of whatever was requested.
492 william 31 // This can be used on games with PATH3 masking issues for example, or when
493     // some FMV look bad.
494 william 62 if(CHECK_EETIMINGHACK) ecycle = 8;
495 william 31
496     cpuRegs.interrupt|= 1 << n;
497     cpuRegs.sCycle[n] = cpuRegs.cycle;
498     cpuRegs.eCycle[n] = ecycle;
499    
500     // Interrupt is happening soon: make sure both EE and IOP are aware.
501    
502 william 62 if( ecycle <= 28 && iopCycleEE > 0 )
503 william 31 {
504     // If running in the IOP, force it to break immediately into the EE.
505     // the EE's branch test is due to run.
506    
507 william 62 iopBreak += iopCycleEE; // record the number of cycles the IOP didn't run.
508     iopCycleEE = 0;
509 william 31 }
510    
511 william 62 cpuSetNextEventDelta( cpuRegs.eCycle[n] );
512 william 31 }
513    
514 william 62 // Called from recompilers; __fastcall define is mandatory.
515 william 31 void __fastcall eeGameStarting()
516     {
517 william 62 if (!g_GameStarted)
518     {
519     //Console.WriteLn( Color_Green, "(R5900) ELF Entry point! [addr=0x%08X]", ElfEntry );
520     g_GameStarted = true;
521     GetCoreThread().GameStartingInThread();
522 william 31
523 william 62 // GameStartingInThread may issue a reset of the cpu and/or recompilers. Check for and
524     // handle such things here:
525     Cpu->CheckExecutionState();
526 william 31 }
527 william 62 else
528     {
529     Console.WriteLn( Color_Green, "(R5900) Re-executed ELF Entry point (ignored) [addr=0x%08X]", ElfEntry );
530     }
531 william 31 }
532    
533 william 62 // Called from recompilers; __fastcall define is mandatory.
534 william 31 void __fastcall eeloadReplaceOSDSYS()
535     {
536     g_SkipBiosHack = false;
537    
538     const wxString &elf_override = GetCoreThread().GetElfOverride();
539    
540     if (!elf_override.IsEmpty())
541     cdvdReloadElfInfo(L"host:" + elf_override);
542     else
543     cdvdReloadElfInfo();
544    
545 william 62 // didn't recognize an ELF
546 william 31 if (ElfEntry == -1) {
547     eeGameStarting();
548     return;
549     }
550    
551     static u32 osdsys = 0, osdsys_p = 0;
552     // Memory this high is safe before the game's running presumably
553     // Other options are kernel memory (first megabyte) or the scratchpad
554     // PS2LOGO is loaded at 16MB, let's use 17MB
555     const u32 safemem = 0x1100000;
556    
557     // The strings are all 64-bit aligned. Why? I don't know, but they are
558     for (u32 i = EELOAD_START; i < EELOAD_START + EELOAD_SIZE; i += 8) {
559     if (!strcmp((char*)PSM(i), "rom0:OSDSYS")) {
560     osdsys = i;
561     break;
562     }
563     }
564     pxAssert(osdsys);
565    
566     for (u32 i = osdsys - 4; i >= EELOAD_START; i -= 4) {
567     if (memRead32(i) == osdsys) {
568     osdsys_p = i;
569     break;
570     }
571     }
572     pxAssert(osdsys_p);
573    
574 william 62 std::string elfname;
575 william 31
576     if (!elf_override.IsEmpty())
577     {
578     elfname += "host:";
579     elfname += elf_override.ToUTF8();
580     }
581     else
582     {
583     wxString boot2;
584     if (GetPS2ElfName(boot2) == 2)
585     elfname = boot2.ToUTF8();
586     }
587    
588     if (!elfname.empty())
589     {
590     strcpy((char*)PSM(safemem), elfname.c_str());
591     memWrite32(osdsys_p, safemem);
592     }
593     // else... uh...?
594     }

  ViewVC Help
Powered by ViewVC 1.1.22