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

  ViewVC Help
Powered by ViewVC 1.1.22