Mercurial > audlegacy-plugins
comparison src/psf2/psx_hw.c @ 2737:62cc6d667119
Import a bunch of stuff for new psf2 plugin.
author | William Pitcock <nenolod@atheme.org> |
---|---|
date | Mon, 30 Jun 2008 20:20:53 -0500 |
parents | |
children | f1482af6384c |
comparison
equal
deleted
inserted
replaced
2731:324f950774cb | 2737:62cc6d667119 |
---|---|
1 /* | |
2 Audio Overload SDK - PSX and IOP hardware emulation | |
3 | |
4 Copyright (c) 2007 R. Belmont and Richard Bannister. | |
5 | |
6 All rights reserved. | |
7 | |
8 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: | |
9 | |
10 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. | |
11 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. | |
12 * Neither the names of R. Belmont and Richard Bannister nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. | |
13 | |
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
15 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
16 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
17 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | |
18 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
19 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
20 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
21 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
22 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
23 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
24 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
25 */ | |
26 | |
27 /* | |
28 psx_hw.c - Minimal PSX/IOP hardware glue/emulation/whatever | |
29 | |
30 supported: main RAM (2 MB, mirrored to fill an 8 MB space like on real HW) | |
31 DMA channel 4 (SPURAM) in both directions (including completion IRQ) | |
32 VBL IRQ | |
33 Root counters 2 and 3 including completion events and IRQs | |
34 Some BIOS services including exception handling (via HLE) | |
35 HLE emulation of IOP operating system, including multithreading | |
36 SPU(2), SPU(2)RAM (via PEOpS) | |
37 | |
38 | |
39 | |
40 Special notes: | |
41 PSF1 | |
42 - Chocobo's Dungeon 2 contains an illegal code sequence (patched) | |
43 | |
44 PSF2 | |
45 - Shadow Hearts assumes that the wave buffer alloc will go to 0x80060000 and the sequence buffer to 0x80170000. | |
46 Our memory management doesn't work out that way, so we have to (wait for it) cheese it. | |
47 */ | |
48 | |
49 #include <stdio.h> | |
50 #include "ao.h" | |
51 #include "cpuintrf.h" | |
52 #include "psx.h" | |
53 | |
54 #define DEBUG_HLE_BIOS (0) // debug PS1 HLE BIOS | |
55 #define DEBUG_HLE_IOP (0) // debug PS2 IOP OS calls | |
56 #define DEBUG_UNK_RW (0) // debug unknown reads/writes | |
57 #define DEBUG_THREADING (0) // debug PS2 IOP threading | |
58 | |
59 extern void mips_get_info(UINT32 state, union cpuinfo *info); | |
60 extern void mips_set_info(UINT32 state, union cpuinfo *info); | |
61 extern int psxcpu_verbose; | |
62 extern uint16 SPUreadRegister(uint32 reg); | |
63 extern void SPUwriteRegister(uint32 reg, uint16 val); | |
64 extern void SPUwriteDMAMem(uint32 usPSXMem,int iSize); | |
65 extern void SPUreadDMAMem(uint32 usPSXMem,int iSize); | |
66 extern void mips_shorten_frame(void); | |
67 extern int mips_execute( int cycles ); | |
68 extern uint32 psf2_load_file(char *file, uint8 *buf, uint32 buflen); | |
69 extern uint32 psf2_load_elf(uint8 *start, uint32 len); | |
70 void psx_hw_runcounters(void); | |
71 int mips_get_icount(void); | |
72 void mips_set_icount(int count); | |
73 | |
74 extern int psf_refresh; | |
75 | |
76 static int skipyet = 0; | |
77 | |
78 // SPU2 | |
79 extern void SPU2write(unsigned long reg, unsigned short val); | |
80 extern unsigned short SPU2read(unsigned long reg); | |
81 extern void SPU2readDMA4Mem(uint32 usPSXMem,int iSize); | |
82 extern void SPU2writeDMA4Mem(uint32 usPSXMem,int iSize); | |
83 extern void SPU2readDMA7Mem(uint32 usPSXMem,int iSize); | |
84 extern void SPU2writeDMA7Mem(uint32 usPSXMem,int iSize); | |
85 extern void SPU2interruptDMA4(void); | |
86 extern void SPU2interruptDMA7(void); | |
87 | |
88 #define MAX_FILE_SLOTS (32) | |
89 | |
90 static volatile int softcall_target = 0; | |
91 static int filestat[MAX_FILE_SLOTS]; | |
92 static uint8 *filedata[MAX_FILE_SLOTS]; | |
93 static uint32 filesize[MAX_FILE_SLOTS], filepos[MAX_FILE_SLOTS]; | |
94 uint32 psf2_get_loadaddr(void); | |
95 void psf2_set_loadaddr(uint32 new); | |
96 static void call_irq_routine(uint32 routine, uint32 parameter); | |
97 static int intr_susp = 0; | |
98 | |
99 static uint64 sys_time; | |
100 static int timerexp = 0; | |
101 | |
102 typedef struct | |
103 { | |
104 char name[10]; | |
105 uint32 dispatch; | |
106 } ExternLibEntries; | |
107 | |
108 static int32 iNumLibs; | |
109 static ExternLibEntries reglibs[32]; | |
110 | |
111 typedef struct | |
112 { | |
113 uint32 type; | |
114 uint32 value; | |
115 uint32 param; | |
116 int inUse; | |
117 } EventFlag; | |
118 | |
119 static int32 iNumFlags; | |
120 static EventFlag evflags[32]; | |
121 | |
122 typedef struct | |
123 { | |
124 uint32 attr; | |
125 uint32 option; | |
126 int32 init; | |
127 int32 current; | |
128 int32 max; | |
129 int32 threadsWaiting; | |
130 int32 inuse; | |
131 } Semaphore; | |
132 | |
133 #define SEMA_MAX (64) | |
134 | |
135 static int32 iNumSema; | |
136 static Semaphore semaphores[SEMA_MAX]; | |
137 | |
138 // thread states | |
139 enum | |
140 { | |
141 TS_RUNNING = 0, // now running | |
142 TS_READY, // ready to run | |
143 TS_WAITEVFLAG, // waiting on an event flag | |
144 TS_WAITSEMA, // waiting on a semaphore | |
145 TS_WAITDELAY, // waiting on a time delay | |
146 TS_SLEEPING, // sleeping | |
147 TS_CREATED, // newly created, hasn't run yet | |
148 | |
149 TS_MAXSTATE | |
150 }; | |
151 | |
152 typedef struct | |
153 { | |
154 int32 iState; // state of thread | |
155 | |
156 uint32 flags; // flags | |
157 uint32 routine; // start of code for the thread | |
158 uint32 stackloc; // stack location in IOP RAM | |
159 uint32 stacksize; // stack size | |
160 uint32 refCon; // user value passed in at CreateThread time | |
161 | |
162 uint32 waitparm; // what we're waiting on if in one the TS_WAIT* states | |
163 | |
164 uint32 save_regs[37]; // CPU registers belonging to this thread | |
165 } Thread; | |
166 | |
167 static int32 iNumThreads, iCurThread; | |
168 static Thread threads[32]; | |
169 | |
170 #if DEBUG_THREADING | |
171 static char *_ThreadStateNames[TS_MAXSTATE] = { "RUNNING", "READY", "WAITEVFLAG", "WAITSEMA", "WAITDELAY", "SLEEPING", "CREATED" }; | |
172 #endif | |
173 | |
174 #if DEBUG_HLE_IOP | |
175 static char *seek_types[3] = { "SEEK_SET", "SEEK_CUR", "SEEK_END" }; | |
176 #endif | |
177 | |
178 typedef struct | |
179 { | |
180 int32 iActive; | |
181 uint32 count; | |
182 uint32 target; | |
183 uint32 source; | |
184 uint32 prescale; | |
185 uint32 handler; | |
186 uint32 hparam; | |
187 uint32 mode; | |
188 } IOPTimer; | |
189 | |
190 static IOPTimer iop_timers[8]; | |
191 static int32 iNumTimers; | |
192 | |
193 typedef struct | |
194 { | |
195 uint32 count; | |
196 uint32 mode; | |
197 uint32 target; | |
198 uint32 sysclock; | |
199 } Counter; | |
200 | |
201 static Counter root_cnts[3]; // 3 of the bastards | |
202 | |
203 #define CLOCK_DIV (8) // 33 MHz / this = what we run the R3000 at to keep the CPU usage not insane | |
204 | |
205 // counter modes | |
206 #define RC_EN (0x0001) // halt | |
207 #define RC_RESET (0x0008) // automatically wrap | |
208 #define RC_IQ1 (0x0010) // IRQ when target reached | |
209 #define RC_IQ2 (0x0040) // IRQ when target reached (pSX treats same as IQ1?) | |
210 #define RC_CLC (0x0100) // counter uses direct system clock | |
211 #define RC_DIV8 (0x0200) // (counter 2 only) system clock/8 | |
212 | |
213 typedef struct | |
214 { | |
215 uint32 desc; | |
216 int32 status; | |
217 int32 mode; | |
218 uint32 fhandler; | |
219 } EvtCtrlBlk[32]; | |
220 | |
221 static EvtCtrlBlk *Event; | |
222 static EvtCtrlBlk *CounterEvent; | |
223 | |
224 // Sony event states | |
225 #define EvStUNUSED 0x0000 | |
226 #define EvStWAIT 0x1000 | |
227 #define EvStACTIVE 0x2000 | |
228 #define EvStALREADY 0x4000 | |
229 | |
230 // Sony event modes | |
231 #define EvMdINTR 0x1000 | |
232 #define EvMdNOINTR 0x2000 | |
233 | |
234 // PSX main RAM | |
235 uint32 psx_ram[(2*1024*1024)/4]; | |
236 uint32 psx_scratch[0x400]; | |
237 // backup image to restart songs | |
238 uint32 initial_ram[(2*1024*1024)/4]; | |
239 uint32 initial_scratch[0x400]; | |
240 | |
241 static uint32 spu_delay, dma_icr, irq_data, irq_mask, dma_timer, WAI; | |
242 static uint32 dma4_madr, dma4_bcr, dma4_chcr, dma4_delay; | |
243 static uint32 dma7_madr, dma7_bcr, dma7_chcr, dma7_delay; | |
244 static uint32 dma4_cb, dma7_cb, dma4_fval, dma4_flag, dma7_fval, dma7_flag; | |
245 static uint32 irq9_cb, irq9_fval, irq9_flag; | |
246 | |
247 // take a snapshot of the CPU state for a thread | |
248 static void FreezeThread(int32 iThread, int flag) | |
249 { | |
250 int i; | |
251 union cpuinfo mipsinfo; | |
252 | |
253 #if DEBUG_THREADING | |
254 // printf("IOP: FreezeThread(%d)\n", iThread); | |
255 #endif | |
256 | |
257 for (i = 0; i < 32; i++) | |
258 { | |
259 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R0 + i, &mipsinfo); | |
260 threads[iThread].save_regs[i] = mipsinfo.i; | |
261 } | |
262 mips_get_info(CPUINFO_INT_REGISTER + MIPS_HI, &mipsinfo); | |
263 threads[iThread].save_regs[32] = mipsinfo.i; | |
264 mips_get_info(CPUINFO_INT_REGISTER + MIPS_LO, &mipsinfo); | |
265 threads[iThread].save_regs[33] = mipsinfo.i; | |
266 mips_get_info(CPUINFO_INT_REGISTER + MIPS_DELAYV, &mipsinfo); | |
267 threads[iThread].save_regs[35] = mipsinfo.i; | |
268 mips_get_info(CPUINFO_INT_REGISTER + MIPS_DELAYR, &mipsinfo); | |
269 threads[iThread].save_regs[36] = mipsinfo.i; | |
270 | |
271 | |
272 // if a thread is freezing itself due to a IOP syscall, we must save the RA as the PC | |
273 // to come back to or else the syscall will recurse | |
274 if (flag) | |
275 { | |
276 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo); | |
277 } | |
278 else | |
279 { | |
280 mips_get_info(CPUINFO_INT_PC, &mipsinfo); | |
281 } | |
282 threads[iThread].save_regs[34] = mipsinfo.i; | |
283 | |
284 #if DEBUG_THREADING | |
285 { | |
286 char buffer[256]; | |
287 | |
288 DasmMIPS(buffer, mipsinfo.i, &psx_ram[(mipsinfo.i & 0x7fffffff)/4]); | |
289 | |
290 printf("IOP: FreezeThread(%d) => %08x [%s]\n", iThread, threads[iThread].save_regs[34], buffer); | |
291 } | |
292 #endif | |
293 | |
294 // if thread was running, now it's ready | |
295 if (threads[iThread].iState == TS_RUNNING) | |
296 { | |
297 threads[iThread].iState = TS_READY; | |
298 } | |
299 } | |
300 | |
301 // restore the CPU state from a thread's snapshot | |
302 static void ThawThread(int32 iThread) | |
303 { | |
304 int i; | |
305 union cpuinfo mipsinfo; | |
306 | |
307 // the first time a thread is put on the CPU, | |
308 // some special setup is required | |
309 if (threads[iThread].iState == TS_CREATED) | |
310 { | |
311 // PC = starting routine | |
312 threads[iThread].save_regs[34] = threads[iThread].routine-4; // compensate for weird delay slot effects | |
313 // SP = thread's stack area | |
314 threads[iThread].save_regs[29] = (threads[iThread].stackloc + threads[iThread].stacksize) - 16; | |
315 threads[iThread].save_regs[29] |= 0x80000000; | |
316 | |
317 threads[iThread].save_regs[35] = threads[iThread].save_regs[36] = 0; | |
318 | |
319 #if DEBUG_THREADING | |
320 // printf("IOP: Initial setup for thread %d => PC %x SP %x\n", iThread, threads[iThread].save_regs[34]+4, threads[iThread].save_regs[29]); | |
321 #endif | |
322 } | |
323 | |
324 #if DEBUG_THREADING | |
325 { | |
326 char buffer[256]; | |
327 | |
328 mips_get_info(CPUINFO_INT_PC, &mipsinfo); | |
329 DasmMIPS(buffer, mipsinfo.i, &psx_ram[(mipsinfo.i & 0x7fffffff)/4]); | |
330 | |
331 printf("IOP: ThawThread(%d) => %08x [%s] (wake %d)\n", iThread, threads[iThread].save_regs[34], buffer, wakecount); | |
332 } | |
333 #endif | |
334 | |
335 for (i = 0; i < 32; i++) | |
336 { | |
337 mipsinfo.i = threads[iThread].save_regs[i]; | |
338 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R0 + i, &mipsinfo); | |
339 } | |
340 | |
341 mipsinfo.i = threads[iThread].save_regs[32]; | |
342 mips_set_info(CPUINFO_INT_REGISTER + MIPS_HI, &mipsinfo); | |
343 mipsinfo.i = threads[iThread].save_regs[33]; | |
344 mips_set_info(CPUINFO_INT_REGISTER + MIPS_LO, &mipsinfo); | |
345 mipsinfo.i = threads[iThread].save_regs[34]; | |
346 mips_set_info(CPUINFO_INT_PC, &mipsinfo); | |
347 mipsinfo.i = threads[iThread].save_regs[35]; | |
348 mips_set_info(CPUINFO_INT_REGISTER + MIPS_DELAYV, &mipsinfo); | |
349 mipsinfo.i = threads[iThread].save_regs[36]; | |
350 mips_set_info(CPUINFO_INT_REGISTER + MIPS_DELAYR, &mipsinfo); | |
351 | |
352 threads[iThread].iState = TS_RUNNING; | |
353 } | |
354 | |
355 // find a new thread to run | |
356 static void ps2_reschedule(void) | |
357 { | |
358 int i, starti, iNextThread; | |
359 | |
360 iNextThread = -1; | |
361 | |
362 // see if any thread other than the current one is ready to run | |
363 i = iCurThread+1; | |
364 if (i >= iNumThreads) | |
365 { | |
366 i = 0; | |
367 } | |
368 | |
369 starti = i; | |
370 | |
371 // starting with the next thread after this one, | |
372 // see who wants to run | |
373 while (i < iNumThreads) | |
374 { | |
375 if (i != iCurThread) | |
376 { | |
377 if (threads[i].iState == TS_READY) | |
378 { | |
379 iNextThread = i; | |
380 break; | |
381 } | |
382 } | |
383 | |
384 i++; | |
385 } | |
386 | |
387 // if we started above thread 0 and didn't pick one, | |
388 // go around and try from zero | |
389 if ((starti > 0) && (iNextThread == -1)) | |
390 { | |
391 for (i = 0; i < iNumThreads; i++) | |
392 { | |
393 if (i != iCurThread) | |
394 { | |
395 if (threads[i].iState == TS_READY) | |
396 { | |
397 iNextThread = i; | |
398 break; | |
399 } | |
400 } | |
401 } | |
402 } | |
403 | |
404 if (iNextThread != -1) | |
405 { | |
406 #if DEBUG_THREADING | |
407 for (i = 0; i < iNumThreads; i++) | |
408 { | |
409 printf("Thread %02d: %s\n", i, _ThreadStateNames[threads[i].iState]); | |
410 } | |
411 #endif | |
412 | |
413 if (iCurThread != -1) | |
414 { | |
415 FreezeThread(iCurThread, 0); | |
416 } | |
417 ThawThread(iNextThread); | |
418 iCurThread = iNextThread; | |
419 threads[iCurThread].iState = TS_RUNNING; | |
420 } | |
421 else | |
422 { | |
423 // no thread to switch to, is the current one still running? | |
424 if (iCurThread != -1) | |
425 { | |
426 if (threads[iCurThread].iState != TS_RUNNING) | |
427 { | |
428 #if DEBUG_THREADING | |
429 printf("IOP: no threads to run\n"); | |
430 | |
431 for (i = 0; i < iNumThreads; i++) | |
432 { | |
433 printf("Thread %02d: %s\n", i, _ThreadStateNames[threads[i].iState]); | |
434 } | |
435 #endif | |
436 | |
437 mips_shorten_frame(); // kill the CPU | |
438 iCurThread = -1; // no threads are active | |
439 } | |
440 } | |
441 else | |
442 { | |
443 mips_shorten_frame(); // kill the CPU | |
444 iCurThread = -1; // no threads are active | |
445 } | |
446 } | |
447 } | |
448 | |
449 static void psx_irq_update(void) | |
450 { | |
451 union cpuinfo mipsinfo; | |
452 | |
453 if ((irq_data & irq_mask) != 0) | |
454 { // assert the line | |
455 WAI = 0; | |
456 mipsinfo.i = ASSERT_LINE; | |
457 mips_set_info( CPUINFO_INT_INPUT_STATE + MIPS_IRQ0, &mipsinfo ); | |
458 } | |
459 else | |
460 { | |
461 // clear the line | |
462 mipsinfo.i = CLEAR_LINE; | |
463 mips_set_info( CPUINFO_INT_INPUT_STATE + MIPS_IRQ0, &mipsinfo ); | |
464 } | |
465 } | |
466 | |
467 void psx_irq_set(uint32 irq) | |
468 { | |
469 irq_data |= irq; | |
470 | |
471 psx_irq_update(); | |
472 } | |
473 | |
474 static uint32 gpu_stat = 0; | |
475 | |
476 uint32 psx_hw_read(offs_t offset, uint32 mem_mask) | |
477 { | |
478 if (offset >= 0x00000000 && offset <= 0x007fffff) | |
479 { | |
480 offset &= 0x1fffff; | |
481 return LE32(psx_ram[offset>>2]); | |
482 } | |
483 | |
484 if (offset >= 0x80000000 && offset <= 0x807fffff) | |
485 { | |
486 offset &= 0x1fffff; | |
487 return LE32(psx_ram[offset>>2]); | |
488 } | |
489 | |
490 if (offset == 0xbfc00180 || offset == 0xbfc00184) // exception vector | |
491 { | |
492 return FUNCT_HLECALL; | |
493 } | |
494 | |
495 if (offset == 0x1f801014) | |
496 { | |
497 return spu_delay; | |
498 } | |
499 | |
500 if (offset == 0xbf801014) | |
501 { | |
502 return spu_delay; | |
503 } | |
504 | |
505 if (offset == 0x1f801814) | |
506 { | |
507 gpu_stat ^= 0xffffffff; | |
508 return gpu_stat; | |
509 } | |
510 | |
511 if (offset >= 0x1f801c00 && offset <= 0x1f801dff) | |
512 { | |
513 if ((mem_mask == 0xffff0000) || (mem_mask == 0xffffff00)) | |
514 { | |
515 return SPUreadRegister(offset) & ~mem_mask; | |
516 } | |
517 else if (mem_mask == 0x0000ffff) | |
518 { | |
519 return SPUreadRegister(offset)<<16; | |
520 } | |
521 else printf("SPU: read unknown mask %08x\n", mem_mask); | |
522 } | |
523 | |
524 if (offset >= 0xbf900000 && offset <= 0xbf9007ff) | |
525 { | |
526 if ((mem_mask == 0xffff0000) || (mem_mask == 0xffffff00)) | |
527 { | |
528 return SPU2read(offset) & ~mem_mask; | |
529 } | |
530 else if (mem_mask == 0x0000ffff) | |
531 { | |
532 return SPU2read(offset)<<16; | |
533 } | |
534 else if (mem_mask == 0) | |
535 { | |
536 return SPU2read(offset) | SPU2read(offset+2)<<16; | |
537 } | |
538 else printf("SPU2: read unknown mask %08x\n", mem_mask); | |
539 } | |
540 | |
541 if (offset >= 0x1f801100 && offset <= 0x1f801128) | |
542 { | |
543 int cnt = (offset>>4) & 0xf; | |
544 | |
545 switch (offset & 0xf) | |
546 { | |
547 case 0: | |
548 // printf("RC: read counter %d count = %x\n", cnt, root_cnts[cnt].count); | |
549 return root_cnts[cnt].count; | |
550 break; | |
551 case 4: | |
552 // printf("RC: read counter %d mode\n", cnt); | |
553 return root_cnts[cnt].mode; | |
554 break; | |
555 case 8: | |
556 // printf("RC: read counter %d target\n", cnt); | |
557 return root_cnts[cnt].target; | |
558 break; | |
559 } | |
560 | |
561 return 0; | |
562 } | |
563 | |
564 if (offset == 0x1f8010f4) | |
565 { | |
566 return dma_icr; | |
567 } | |
568 else if (offset == 0x1f801070) | |
569 { | |
570 // printf("Read IRQ_data %x (mask %08x)\n", irq_data, mem_mask); | |
571 return irq_data; | |
572 } | |
573 else if (offset == 0x1f801074) | |
574 { | |
575 return irq_mask; | |
576 } | |
577 | |
578 /* if (offset == 0xbf801508) | |
579 { | |
580 return dma7_bcr; | |
581 }*/ | |
582 | |
583 if (offset == 0xbf920344) | |
584 { | |
585 return 0x80808080; | |
586 } | |
587 | |
588 #if DEBUG_UNK_RW | |
589 { | |
590 union cpuinfo mipsinfo; | |
591 | |
592 mips_get_info(CPUINFO_INT_PC, &mipsinfo); | |
593 printf("Unknown read: %08x, mask %08x (PC=%x)\n", offset&~3, mem_mask, mipsinfo.i); | |
594 } | |
595 #endif | |
596 return 0; | |
597 } | |
598 | |
599 static void psx_dma4(uint32 madr, uint32 bcr, uint32 chcr) | |
600 { | |
601 if (chcr == 0x01000201) // cpu to SPU | |
602 { | |
603 // printf("DMA4: RAM %08x to SPU\n", madr); | |
604 bcr = (bcr>>16) * (bcr & 0xffff) * 2; | |
605 SPUwriteDMAMem(madr&0x1fffff, bcr); | |
606 } | |
607 else | |
608 { | |
609 // printf("DMA4: SPU to RAM %08x\n", madr); | |
610 bcr = (bcr>>16) * (bcr & 0xffff) * 2; | |
611 SPUreadDMAMem(madr&0x1fffff, bcr); | |
612 } | |
613 } | |
614 | |
615 static void ps2_dma4(uint32 madr, uint32 bcr, uint32 chcr) | |
616 { | |
617 if (chcr == 0x01000201) // cpu to SPU2 | |
618 { | |
619 #if DEBUG_HLE_IOP | |
620 printf("DMA4: RAM %08x to SPU2\n", madr); | |
621 #endif | |
622 bcr = (bcr>>16) * (bcr & 0xffff) * 4; | |
623 SPU2writeDMA4Mem(madr&0x1fffff, bcr); | |
624 } | |
625 else | |
626 { | |
627 #if DEBUG_HLE_IOP | |
628 printf("DMA4: SPU2 to RAM %08x\n", madr); | |
629 #endif | |
630 bcr = (bcr>>16) * (bcr & 0xffff) * 4; | |
631 SPU2readDMA4Mem(madr&0x1fffff, bcr); | |
632 } | |
633 | |
634 dma4_delay = 80; | |
635 } | |
636 | |
637 static void ps2_dma7(uint32 madr, uint32 bcr, uint32 chcr) | |
638 { | |
639 if ((chcr == 0x01000201) || (chcr == 0x00100010) || (chcr == 0x000f0010) || (chcr == 0x00010010)) // cpu to SPU2 | |
640 { | |
641 #if DEBUG_HLE_IOP | |
642 printf("DMA7: RAM %08x to SPU2\n", madr); | |
643 #endif | |
644 bcr = (bcr>>16) * (bcr & 0xffff) * 4; | |
645 SPU2writeDMA7Mem(madr&0x1fffff, bcr); | |
646 } | |
647 else | |
648 { | |
649 #if DEBUG_HLE_IOP | |
650 printf("DMA7: SPU2 to RAM %08x\n", madr); | |
651 #endif | |
652 bcr = (bcr>>16) * (bcr & 0xffff) * 4; | |
653 // SPU2readDMA7Mem(madr&0x1fffff, bcr); | |
654 } | |
655 | |
656 dma7_delay = 80; | |
657 } | |
658 | |
659 void psx_hw_write(offs_t offset, uint32 data, uint32 mem_mask) | |
660 { | |
661 union cpuinfo mipsinfo; | |
662 | |
663 if (offset >= 0x00000000 && offset <= 0x007fffff) | |
664 { | |
665 offset &= 0x1fffff; | |
666 // if (offset < 0x10000) printf("Write %x to kernel @ %x\n", data, offset); | |
667 | |
668 mips_get_info(CPUINFO_INT_PC, &mipsinfo); | |
669 | |
670 psx_ram[offset>>2] &= LE32(mem_mask); | |
671 psx_ram[offset>>2] |= LE32(data); | |
672 return; | |
673 } | |
674 | |
675 if (offset >= 0x80000000 && offset <= 0x807fffff) | |
676 { | |
677 offset &= 0x1fffff; | |
678 // if (offset < 0x10000) printf("Write %x to kernel @ %x\n", data, offset); | |
679 mips_get_info(CPUINFO_INT_PC, &mipsinfo); | |
680 psx_ram[offset>>2] &= LE32(mem_mask); | |
681 psx_ram[offset>>2] |= LE32(data); | |
682 return; | |
683 } | |
684 | |
685 if (offset == 0x1f801014 || offset == 0xbf801014) | |
686 { | |
687 spu_delay &= mem_mask; | |
688 spu_delay |= data; | |
689 return; | |
690 } | |
691 | |
692 if (offset >= 0x1f801c00 && offset <= 0x1f801dff) | |
693 { | |
694 // printf("SPU2 wrote %x to SPU1 address %x!\n", data, offset); | |
695 if (mem_mask == 0xffff0000) | |
696 { | |
697 SPUwriteRegister(offset, data); | |
698 return; | |
699 } | |
700 else if (mem_mask == 0x0000ffff) | |
701 { | |
702 SPUwriteRegister(offset, data>>16); | |
703 return; | |
704 } | |
705 else printf("SPU: write unknown mask %08x\n", mem_mask); | |
706 } | |
707 | |
708 if (offset >= 0xbf900000 && offset <= 0xbf9007ff) | |
709 { | |
710 if (mem_mask == 0xffff0000) | |
711 { | |
712 SPU2write(offset, data); | |
713 return; | |
714 } | |
715 else if (mem_mask == 0x0000ffff) | |
716 { | |
717 SPU2write(offset, data>>16); | |
718 return; | |
719 } | |
720 else if (mem_mask == 0) | |
721 { | |
722 SPU2write(offset, data & 0xffff); | |
723 SPU2write(offset+2, data>>16); | |
724 return; | |
725 } | |
726 else printf("SPU2: write unknown mask %08x\n", mem_mask); | |
727 } | |
728 | |
729 if (offset >= 0x1f801100 && offset <= 0x1f801128) | |
730 { | |
731 int cnt = (offset>>4) & 0xf; | |
732 | |
733 switch (offset & 0xf) | |
734 { | |
735 case 0: | |
736 root_cnts[cnt].count = data; | |
737 // printf("RC: counter %d count = %x\n", cnt, data); | |
738 break; | |
739 case 4: | |
740 root_cnts[cnt].mode = data; | |
741 // printf("RC: counter %d mode = %x\n", cnt, data); | |
742 break; | |
743 case 8: | |
744 root_cnts[cnt].target = data; | |
745 // printf("RC: counter %d target = %x\n", cnt, data); | |
746 break; | |
747 } | |
748 | |
749 return; | |
750 } | |
751 | |
752 // DMA4 | |
753 if (offset == 0x1f8010c0) | |
754 { | |
755 dma4_madr = data; | |
756 return; | |
757 } | |
758 else if (offset == 0x1f8010c4) | |
759 { | |
760 dma4_bcr = data; | |
761 return; | |
762 } | |
763 else if (offset == 0x1f8010c8) | |
764 { | |
765 dma4_chcr = data; | |
766 psx_dma4(dma4_madr, dma4_bcr, dma4_chcr); | |
767 | |
768 if (dma_icr & (1 << (16+4))) | |
769 { | |
770 dma_timer = 3; | |
771 } | |
772 return; | |
773 } | |
774 else if (offset == 0x1f8010f4) | |
775 { | |
776 dma_icr = ( dma_icr & mem_mask ) | | |
777 ( ~mem_mask & 0x80000000 & dma_icr) | | |
778 ( ~data & ~mem_mask & 0x7f000000 & dma_icr) | | |
779 ( data & ~mem_mask & 0x00ffffff); | |
780 | |
781 if ((dma_icr & 0x7f000000) != 0) | |
782 { | |
783 dma_icr &= ~0x80000000; | |
784 } | |
785 | |
786 return; | |
787 } | |
788 else if (offset == 0x1f801070) | |
789 { | |
790 irq_data = (irq_data & mem_mask) | (irq_data & irq_mask & data); | |
791 psx_irq_update(); | |
792 return; | |
793 } | |
794 else if (offset == 0x1f801074) | |
795 { | |
796 irq_mask &= mem_mask; | |
797 irq_mask |= data; | |
798 psx_irq_update(); | |
799 return; | |
800 } | |
801 | |
802 // PS2 DMA4 | |
803 if (offset == 0xbf8010c0) | |
804 { | |
805 dma4_madr = data; | |
806 return; | |
807 } | |
808 else if (offset == 0xbf8010c8) | |
809 { | |
810 dma4_chcr = data; | |
811 ps2_dma4(dma4_madr, dma4_bcr, dma4_chcr); | |
812 | |
813 if (dma_icr & (1 << (16+4))) | |
814 { | |
815 dma_timer = 3; | |
816 } | |
817 return; | |
818 } | |
819 | |
820 if (offset == 0xbf8010c4 || offset == 0xbf8010c6) | |
821 { | |
822 dma4_bcr &= mem_mask; | |
823 dma4_bcr |= data; | |
824 return; | |
825 } | |
826 | |
827 // PS2 DMA7 | |
828 if (offset == 0xbf801500) | |
829 { | |
830 dma7_madr = data; | |
831 return; | |
832 } | |
833 else if (offset == 0xbf801504) | |
834 { | |
835 dma7_chcr = data; | |
836 ps2_dma7(dma7_madr, dma7_bcr, dma7_chcr); | |
837 return; | |
838 } | |
839 | |
840 if (offset == 0xbf801508 || offset == 0xbf80150a) | |
841 { | |
842 dma7_bcr &= mem_mask; | |
843 dma7_bcr |= data; | |
844 return; | |
845 } | |
846 | |
847 #if DEBUG_UNK_RW | |
848 { | |
849 union cpuinfo mipsinfo; | |
850 | |
851 mips_get_info(CPUINFO_INT_PC, &mipsinfo); | |
852 printf("Unknown write: %08x to %08x, mask %08x (PC=%x)\n", data, offset&~3, mem_mask, mipsinfo.i); | |
853 } | |
854 #endif | |
855 } | |
856 | |
857 // called per sample, 1/44100th of a second (768 clock cycles) | |
858 void psx_hw_slice(void) | |
859 { | |
860 psx_hw_runcounters(); | |
861 | |
862 if (!WAI) | |
863 mips_execute(768/CLOCK_DIV); | |
864 | |
865 if (dma_timer) | |
866 { | |
867 dma_timer--; | |
868 if (dma_timer == 0) | |
869 { | |
870 dma_icr |= (1 << (24+4)); | |
871 psx_irq_set(0x0008); | |
872 } | |
873 } | |
874 } | |
875 | |
876 void ps2_hw_slice(void) | |
877 { | |
878 int i = 0; | |
879 | |
880 timerexp = 0; | |
881 psx_hw_runcounters(); | |
882 | |
883 if (iCurThread != -1) | |
884 { | |
885 mips_execute(836/CLOCK_DIV); | |
886 } | |
887 else // no thread, don't run CPU, just update counters | |
888 { | |
889 if (timerexp) | |
890 { | |
891 ps2_reschedule(); | |
892 | |
893 if (iCurThread != -1) | |
894 { | |
895 mips_execute((836/CLOCK_DIV)-i); | |
896 i = (836/CLOCK_DIV); | |
897 } | |
898 } | |
899 } | |
900 } | |
901 | |
902 static int fcnt = 0; | |
903 | |
904 void psx_hw_frame(void) | |
905 { | |
906 if (psf_refresh == 50) | |
907 { | |
908 fcnt++;; | |
909 | |
910 if (fcnt < 6) | |
911 { | |
912 psx_irq_set(1); | |
913 } | |
914 else | |
915 { | |
916 fcnt = 0; | |
917 } | |
918 } | |
919 else // NTSC | |
920 { | |
921 psx_irq_set(1); | |
922 } | |
923 } | |
924 | |
925 void ps2_hw_frame(void) | |
926 { | |
927 ps2_reschedule(); | |
928 } | |
929 | |
930 // BIOS HLE | |
931 | |
932 // heap block struct offsets | |
933 enum | |
934 { | |
935 BLK_STAT = 0, | |
936 BLK_SIZE = 4, | |
937 BLK_FD = 8, | |
938 BLK_BK = 12 | |
939 }; | |
940 | |
941 static uint32 heap_addr, entry_int = 0; | |
942 | |
943 extern uint32 mips_get_cause(void); | |
944 extern uint32 mips_get_status(void); | |
945 extern void mips_set_status(uint32 status); | |
946 extern uint32 mips_get_ePC(void); | |
947 | |
948 static uint32 irq_regs[37]; | |
949 | |
950 static int irq_mutex = 0; | |
951 | |
952 static void call_irq_routine(uint32 routine, uint32 parameter) | |
953 { | |
954 int j, oldICount; | |
955 union cpuinfo mipsinfo; | |
956 | |
957 if (!irq_mutex) | |
958 { | |
959 irq_mutex = 1; | |
960 } | |
961 else | |
962 { | |
963 printf("IOP: ERROR! IRQ reentry!\n"); | |
964 return; | |
965 } | |
966 | |
967 // save regs for IRQ | |
968 for (j = 0; j < 32; j++) | |
969 { | |
970 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R0 + j, &mipsinfo); | |
971 irq_regs[j] = mipsinfo.i; | |
972 } | |
973 mips_get_info(CPUINFO_INT_REGISTER + MIPS_HI, &mipsinfo); | |
974 irq_regs[32] = mipsinfo.i; | |
975 mips_get_info(CPUINFO_INT_REGISTER + MIPS_LO, &mipsinfo); | |
976 irq_regs[33] = mipsinfo.i; | |
977 mips_get_info(CPUINFO_INT_PC, &mipsinfo); | |
978 irq_regs[34] = mipsinfo.i; | |
979 mips_get_info(CPUINFO_INT_REGISTER + MIPS_DELAYV, &mipsinfo); | |
980 irq_regs[35] = mipsinfo.i; | |
981 mips_get_info(CPUINFO_INT_REGISTER + MIPS_DELAYR, &mipsinfo); | |
982 irq_regs[36] = mipsinfo.i; | |
983 | |
984 // PC = timer handler routine | |
985 mipsinfo.i = routine; | |
986 mips_set_info(CPUINFO_INT_PC, &mipsinfo); | |
987 | |
988 // parameter in a0 | |
989 mipsinfo.i = parameter; | |
990 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R4, &mipsinfo); | |
991 | |
992 // RA = a trap address we can set | |
993 mipsinfo.i = 0x80001000; | |
994 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo); | |
995 | |
996 // make sure we're set | |
997 psx_ram[0x1000/4] = LE32(FUNCT_HLECALL); | |
998 | |
999 softcall_target = 0; | |
1000 oldICount = mips_get_icount(); | |
1001 while (!softcall_target) | |
1002 { | |
1003 mips_execute(10); | |
1004 } | |
1005 mips_set_icount(oldICount); | |
1006 | |
1007 // restore IRQ regs | |
1008 for (j = 0; j < 32; j++) | |
1009 { | |
1010 mipsinfo.i = irq_regs[j]; | |
1011 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R0 + j, &mipsinfo); | |
1012 } | |
1013 | |
1014 mipsinfo.i = irq_regs[32]; | |
1015 mips_set_info(CPUINFO_INT_REGISTER + MIPS_HI, &mipsinfo); | |
1016 mipsinfo.i = irq_regs[33]; | |
1017 mips_set_info(CPUINFO_INT_REGISTER + MIPS_LO, &mipsinfo); | |
1018 mipsinfo.i = irq_regs[34]; | |
1019 mips_set_info(CPUINFO_INT_PC, &mipsinfo); | |
1020 mipsinfo.i = irq_regs[35]; | |
1021 mips_set_info(CPUINFO_INT_REGISTER + MIPS_DELAYV, &mipsinfo); | |
1022 mipsinfo.i = irq_regs[36]; | |
1023 mips_set_info(CPUINFO_INT_REGISTER + MIPS_DELAYR, &mipsinfo); | |
1024 | |
1025 irq_mutex = 0; | |
1026 } | |
1027 | |
1028 void psx_bios_exception(uint32 pc) | |
1029 { | |
1030 uint32 a0, status; | |
1031 union cpuinfo mipsinfo; | |
1032 int i, oldICount; | |
1033 | |
1034 // printf("bios_exception: cause %x\n", mips_get_cause() & 0x3c); | |
1035 | |
1036 // get a0 | |
1037 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R4, &mipsinfo); | |
1038 a0 = mipsinfo.i; | |
1039 | |
1040 switch (mips_get_cause() & 0x3c) | |
1041 { | |
1042 case 0: // IRQ | |
1043 // printf("IRQ: %x, mask %x\n", irq_data, irq_mask); | |
1044 // save all regs | |
1045 for (i = 0; i < 32; i++) | |
1046 { | |
1047 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R0 + i, &mipsinfo); | |
1048 irq_regs[i] = mipsinfo.i; | |
1049 } | |
1050 mips_get_info(CPUINFO_INT_REGISTER + MIPS_HI, &mipsinfo); | |
1051 irq_regs[32] = mipsinfo.i; | |
1052 mips_get_info(CPUINFO_INT_REGISTER + MIPS_LO, &mipsinfo); | |
1053 irq_regs[33] = mipsinfo.i; | |
1054 | |
1055 // check BIOS-driven interrupts | |
1056 if (irq_data & 1) // VSync | |
1057 { | |
1058 if (CounterEvent[3][1].status == LE32(EvStACTIVE)) | |
1059 { | |
1060 // run the handler | |
1061 mipsinfo.i = LE32(CounterEvent[3][1].fhandler); | |
1062 // printf("Cause = %x, ePC = %x\n", mips_get_cause(), mips_get_ePC()); | |
1063 // printf("VBL running handler @ %x\n", mipsinfo.i); | |
1064 mips_set_info(CPUINFO_INT_PC, &mipsinfo); | |
1065 mipsinfo.i = 0x80001000; | |
1066 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo); | |
1067 | |
1068 // make sure we're set | |
1069 psx_ram[0x1000/4] = LE32(FUNCT_HLECALL); | |
1070 | |
1071 softcall_target = 0; | |
1072 oldICount = mips_get_icount(); | |
1073 while (!softcall_target) | |
1074 { | |
1075 mips_execute(10); | |
1076 } | |
1077 mips_set_icount(oldICount); | |
1078 | |
1079 // printf("Exiting softcall handler\n"); | |
1080 | |
1081 irq_data &= ~1; // clear the VBL IRQ if we handled it | |
1082 } | |
1083 } | |
1084 else if (irq_data & 0x70) // root counters | |
1085 { | |
1086 for (i = 0; i < 3; i++) | |
1087 { | |
1088 if (irq_data & (1 << (i+4))) | |
1089 { | |
1090 if (CounterEvent[i][1].status == LE32(EvStACTIVE)) | |
1091 { | |
1092 // run the handler | |
1093 mipsinfo.i = LE32(CounterEvent[i][1].fhandler); | |
1094 // printf("Cause = %x, ePC = %x\n", mips_get_cause(), mips_get_ePC()); | |
1095 // printf("Counter %d running handler @ %x\n", i, mipsinfo.i); | |
1096 mips_set_info(CPUINFO_INT_PC, &mipsinfo); | |
1097 mipsinfo.i = 0x80001000; | |
1098 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo); | |
1099 | |
1100 // make sure we're set | |
1101 psx_ram[0x1000/4] = LE32(FUNCT_HLECALL); | |
1102 | |
1103 softcall_target = 0; | |
1104 oldICount = mips_get_icount(); | |
1105 while (!softcall_target) | |
1106 { | |
1107 mips_execute(10); | |
1108 } | |
1109 mips_set_icount(oldICount); | |
1110 | |
1111 // printf("Exiting softcall handler\n"); | |
1112 irq_data &= ~(1 << (i+4)); | |
1113 } | |
1114 else | |
1115 { | |
1116 // printf("CEvt %d not active\n", i); | |
1117 } | |
1118 } | |
1119 } | |
1120 } | |
1121 | |
1122 if (entry_int) | |
1123 { | |
1124 psx_hw_write(0x1f801070, 0xffffffff, 0); | |
1125 | |
1126 a0 = entry_int; | |
1127 | |
1128 // printf("taking entry_int\n"); | |
1129 | |
1130 // RA (and PC) | |
1131 mipsinfo.i = LE32(psx_ram[((a0&0x1fffff)+0)/4]); | |
1132 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo); | |
1133 mips_set_info(CPUINFO_INT_PC, &mipsinfo); | |
1134 // SP | |
1135 mipsinfo.i = LE32(psx_ram[((a0&0x1fffff)+4)/4]); | |
1136 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R29, &mipsinfo); | |
1137 // FP | |
1138 mipsinfo.i = LE32(psx_ram[((a0&0x1fffff)+8)/4]); | |
1139 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R30, &mipsinfo); | |
1140 | |
1141 // S0-S7 are next | |
1142 for (i = 0; i < 8; i++) | |
1143 { | |
1144 mipsinfo.i = LE32(psx_ram[((a0&0x1fffff)+12+(i*4))/4]); | |
1145 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R16 + i, &mipsinfo); | |
1146 } | |
1147 | |
1148 // GP | |
1149 mipsinfo.i = LE32(psx_ram[((a0&0x1fffff)+44)/4]); | |
1150 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R28, &mipsinfo); | |
1151 | |
1152 // v0 = 1 | |
1153 mipsinfo.i = 1; | |
1154 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
1155 } | |
1156 else | |
1157 { | |
1158 psx_hw_write(0x1f801070, 0, 0xffff0000); | |
1159 | |
1160 // note: the entry_int won't be bailing us out here, so do it ourselves | |
1161 for (i = 0; i < 32; i++) | |
1162 { | |
1163 mipsinfo.i = irq_regs[i]; | |
1164 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R0 + i, &mipsinfo); | |
1165 } | |
1166 | |
1167 mipsinfo.i = irq_regs[32]; | |
1168 mips_set_info(CPUINFO_INT_REGISTER + MIPS_HI, &mipsinfo); | |
1169 mipsinfo.i = irq_regs[33]; | |
1170 mips_set_info(CPUINFO_INT_REGISTER + MIPS_LO, &mipsinfo); | |
1171 mipsinfo.i = mips_get_ePC(); | |
1172 mips_set_info(CPUINFO_INT_PC, &mipsinfo); | |
1173 | |
1174 status = mips_get_status(); | |
1175 status = (status & 0xfffffff0) | ((status & 0x3c)>>2); | |
1176 mips_set_status(status); | |
1177 } | |
1178 break; | |
1179 | |
1180 case 0x20: // syscall | |
1181 // syscall always farks with the status, so get it now | |
1182 status = mips_get_status(); | |
1183 | |
1184 switch (a0) | |
1185 { | |
1186 case 1: // EnterCritical | |
1187 #if DEBUG_HLE_BIOS | |
1188 printf("HLEBIOS: EnterCritical\n"); | |
1189 #endif | |
1190 status &= ~0x0404; | |
1191 break; | |
1192 | |
1193 case 2: // ExitCritical | |
1194 #if DEBUG_HLE_BIOS | |
1195 printf("HLEBIOS: ExitCritical\n"); | |
1196 #endif | |
1197 status |= 0x0404; | |
1198 break; | |
1199 | |
1200 default: | |
1201 #if DEBUG_HLE_BIOS | |
1202 printf("HLEBIOS: Unknown syscall %x\n", a0); | |
1203 #endif | |
1204 break; | |
1205 } | |
1206 | |
1207 // PC = ePC + 4 | |
1208 mipsinfo.i = mips_get_ePC() + 4; | |
1209 mips_set_info(CPUINFO_INT_PC, &mipsinfo); | |
1210 | |
1211 // and update the status accordingly | |
1212 status = (status & 0xfffffff0) | ((status & 0x3c)>>2); | |
1213 mips_set_status(status); | |
1214 break; | |
1215 | |
1216 default: | |
1217 #if DEBUG_HLE_BIOS | |
1218 printf("HLEBIOS: Unknown exception %x\n", mips_get_cause()); | |
1219 #endif | |
1220 break; | |
1221 } | |
1222 } | |
1223 | |
1224 static uint32 calc_ev(uint32 a0) | |
1225 { | |
1226 uint32 ev; | |
1227 | |
1228 ev = (a0 >> 24) & 0xf; | |
1229 if (ev == 0xf) | |
1230 { | |
1231 ev = 0x5; | |
1232 } | |
1233 ev *= 32; | |
1234 ev += (a0 & 0x1f); | |
1235 | |
1236 return ev; | |
1237 } | |
1238 | |
1239 static uint32 calc_spec(uint32 a1) | |
1240 { | |
1241 uint32 spec = 0; | |
1242 int i; | |
1243 | |
1244 if (a1 == 0x301) | |
1245 { | |
1246 spec = 16; | |
1247 } | |
1248 else if (a1 == 0x302) | |
1249 { | |
1250 spec = 17; | |
1251 } | |
1252 else | |
1253 { | |
1254 for (i = 0; i < 16; i++) | |
1255 { | |
1256 if (a1 & (1<<i)) | |
1257 { | |
1258 spec = i; | |
1259 break; | |
1260 } | |
1261 } | |
1262 } | |
1263 | |
1264 return spec; | |
1265 } | |
1266 | |
1267 void psx_hw_init(void) | |
1268 { | |
1269 timerexp = 0; | |
1270 | |
1271 memset(filestat, 0, sizeof(filestat)); | |
1272 memset(filedata, 0, sizeof(filedata)); | |
1273 | |
1274 dma4_cb = dma7_cb = 0; | |
1275 | |
1276 sys_time = 0; | |
1277 | |
1278 // clear registered libraries table | |
1279 memset(reglibs, 0, sizeof(reglibs)); | |
1280 iNumLibs = 0; | |
1281 | |
1282 memset(evflags, 0, sizeof(evflags)); | |
1283 iNumFlags = 0; | |
1284 | |
1285 memset(threads, 0, sizeof(threads)); | |
1286 iNumThreads = 1; // we always have at least one thread | |
1287 | |
1288 memset(semaphores, 0, sizeof(semaphores)); | |
1289 iNumSema = 0; | |
1290 | |
1291 // set the initial thread to "RUNNING" | |
1292 threads[0].iState = TS_RUNNING; | |
1293 iCurThread = 0; | |
1294 | |
1295 memset(iop_timers, 0, sizeof(iop_timers)); | |
1296 iNumTimers = 0; | |
1297 | |
1298 // set PS1 BIOS HLE breakpoints | |
1299 psx_ram[0xa0/4] = LE32(FUNCT_HLECALL); | |
1300 psx_ram[0xb0/4] = LE32(FUNCT_HLECALL); | |
1301 psx_ram[0xc0/4] = LE32(FUNCT_HLECALL); | |
1302 | |
1303 Event = (EvtCtrlBlk *)&psx_ram[0x1000/4]; | |
1304 CounterEvent = (Event + (32*2)); | |
1305 | |
1306 dma_icr = 0; | |
1307 spu_delay = 0; | |
1308 irq_data = 0; | |
1309 irq_mask = 0; | |
1310 softcall_target = 0; | |
1311 gpu_stat = 0; | |
1312 dma4_madr = dma4_bcr = dma4_chcr = 0; | |
1313 heap_addr = 0; | |
1314 entry_int = 0; | |
1315 | |
1316 WAI = 0; | |
1317 | |
1318 root_cnts[0].mode = RC_EN; | |
1319 root_cnts[1].mode = RC_EN; | |
1320 root_cnts[2].mode = RC_EN; | |
1321 root_cnts[0].sysclock = 0; | |
1322 root_cnts[1].sysclock = 0; | |
1323 root_cnts[2].sysclock = 0; | |
1324 } | |
1325 | |
1326 void psx_bios_hle(uint32 pc) | |
1327 { | |
1328 uint32 subcall, status; | |
1329 union cpuinfo mipsinfo; | |
1330 uint32 a0, a1, a2, a3; | |
1331 int i; | |
1332 | |
1333 if ((pc == 0) || (pc == 0x80000000)) // IOP "null" state | |
1334 { | |
1335 #if DEBUG_HLE_IOP | |
1336 printf("IOP 'null' state\n"); | |
1337 #endif | |
1338 // ao_song_done = 1; | |
1339 return; | |
1340 } | |
1341 | |
1342 if (pc == 0xbfc00180 || pc == 0xbfc00184) // exception, not BIOS call | |
1343 { | |
1344 psx_bios_exception(pc); | |
1345 return; | |
1346 } | |
1347 | |
1348 if (pc == 0x80001000) | |
1349 { | |
1350 // printf("hit softcall target\n"); | |
1351 softcall_target = 1; | |
1352 return; | |
1353 } | |
1354 | |
1355 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R9, &mipsinfo); | |
1356 | |
1357 subcall = mipsinfo.i & 0xff; | |
1358 | |
1359 // most calls have a0/a1 as parameters, so prefetch them | |
1360 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R4, &mipsinfo); | |
1361 a0 = mipsinfo.i; | |
1362 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R5, &mipsinfo); | |
1363 a1 = mipsinfo.i; | |
1364 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R6, &mipsinfo); | |
1365 a2 = mipsinfo.i; | |
1366 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R7, &mipsinfo); | |
1367 a3 = mipsinfo.i; | |
1368 | |
1369 // mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo); | |
1370 // printf("HLEBIOS: return is %08x\n", mipsinfo.i); | |
1371 | |
1372 switch (pc) | |
1373 { | |
1374 case 0xa0: // a0 syscalls | |
1375 switch (subcall) | |
1376 { | |
1377 case 0x13: // setjmp | |
1378 // RA | |
1379 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo); | |
1380 psx_ram[((a0&0x1fffff)+0)/4] = LE32(mipsinfo.i); | |
1381 #if DEBUG_HLE_BIOS | |
1382 printf("HLEBIOS: setjmp(%08x) => PC %08x\n", a0, mipsinfo.i); | |
1383 #endif | |
1384 // SP | |
1385 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R29, &mipsinfo); | |
1386 psx_ram[((a0&0x1fffff)+4)/4] = LE32(mipsinfo.i); | |
1387 // FP | |
1388 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R30, &mipsinfo); | |
1389 psx_ram[((a0&0x1fffff)+8)/4] = LE32(mipsinfo.i); | |
1390 | |
1391 // S0-S7 are next | |
1392 for (i = 0; i < 8; i++) | |
1393 { | |
1394 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R16 + i, &mipsinfo); | |
1395 psx_ram[((a0&0x1fffff)+12+(i*4))/4] = LE32(mipsinfo.i); | |
1396 } | |
1397 | |
1398 // GP | |
1399 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R28, &mipsinfo); | |
1400 psx_ram[((a0&0x1fffff)+44)/4] = LE32(mipsinfo.i); | |
1401 | |
1402 // v0 = 0 | |
1403 mipsinfo.i = 0; | |
1404 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
1405 break; | |
1406 | |
1407 case 0x18: // strncmp | |
1408 { | |
1409 uint8 *dst, *src; | |
1410 | |
1411 #if DEBUG_HLE_BIOS | |
1412 printf("HLEBIOS: strncmp(%08x, %08x, %d)\n", a0, a1, a2); | |
1413 #endif | |
1414 | |
1415 dst = (uint8 *)psx_ram; | |
1416 src = (uint8 *)psx_ram; | |
1417 dst += (a0 & 0x1fffff); | |
1418 src += (a1 & 0x1fffff); | |
1419 | |
1420 // v0 = result | |
1421 mipsinfo.i = strncmp((char *)dst, (char *)src, a2); | |
1422 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
1423 } | |
1424 break; | |
1425 | |
1426 case 0x19: // strcpy | |
1427 { | |
1428 uint8 *dst, *src; | |
1429 | |
1430 #if DEBUG_HLE_BIOS | |
1431 printf("HLEBIOS: strcpy(%08x, %08x)\n", a0, a1); | |
1432 #endif | |
1433 | |
1434 dst = (uint8 *)psx_ram; | |
1435 src = (uint8 *)psx_ram; | |
1436 dst += (a0 & 0x1fffff); | |
1437 src += (a1 & 0x1fffff); | |
1438 | |
1439 while (*src) | |
1440 { | |
1441 *dst = *src; | |
1442 dst++; | |
1443 src++; | |
1444 } | |
1445 | |
1446 // v0 = a0 | |
1447 mipsinfo.i = a0; | |
1448 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
1449 } | |
1450 break; | |
1451 | |
1452 case 0x28: // bzero | |
1453 { | |
1454 uint8 *dst; | |
1455 | |
1456 #if DEBUG_HLE_BIOS | |
1457 printf("HLEBIOS: bzero(%08x, %08x)\n", a0, a1); | |
1458 #endif | |
1459 | |
1460 dst = (uint8 *)psx_ram; | |
1461 dst += (a0 & 0x1fffff); | |
1462 memset(dst, 0, a1); | |
1463 } | |
1464 break; | |
1465 | |
1466 case 0x2a: // memcpy | |
1467 { | |
1468 uint8 *dst, *src; | |
1469 | |
1470 #if DEBUG_HLE_BIOS | |
1471 printf("HLEBIOS: memcpy(%08x, %08x, %08x)\n", a0, a1, a2); | |
1472 #endif | |
1473 | |
1474 dst = (uint8 *)psx_ram; | |
1475 src = (uint8 *)psx_ram; | |
1476 dst += (a0 & 0x1fffff); | |
1477 src += (a1 & 0x1fffff); | |
1478 | |
1479 while (a2) | |
1480 { | |
1481 *dst = *src; | |
1482 dst++; | |
1483 src++; | |
1484 a2--; | |
1485 } | |
1486 | |
1487 // v0 = a0 | |
1488 mipsinfo.i = a0; | |
1489 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
1490 } | |
1491 break; | |
1492 | |
1493 case 0x2b: // memset | |
1494 { | |
1495 uint8 *dst; | |
1496 | |
1497 #if DEBUG_HLE_BIOS | |
1498 printf("HLEBIOS: memset(%08x, %08x, %08x)\n", a0, a1, a2); | |
1499 #endif | |
1500 | |
1501 dst = (uint8 *)psx_ram; | |
1502 dst += (a0 & 0x1fffff); | |
1503 | |
1504 while (a2) | |
1505 { | |
1506 *dst = a1; | |
1507 dst++; | |
1508 a2--; | |
1509 } | |
1510 | |
1511 // v0 = a0 | |
1512 mipsinfo.i = a0; | |
1513 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
1514 } | |
1515 break; | |
1516 | |
1517 case 0x2f: // rand | |
1518 #if DEBUG_HLE_BIOS | |
1519 printf("HLEBIOS: rand\n"); | |
1520 #endif | |
1521 | |
1522 // v0 = result | |
1523 mipsinfo.i = 1 + (int)(32767.0*rand()/(RAND_MAX+1.0)); | |
1524 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
1525 break; | |
1526 | |
1527 case 0x30: // srand | |
1528 #if DEBUG_HLE_BIOS | |
1529 printf("HLEBIOS: srand(%x)\n", a0); | |
1530 #endif | |
1531 srand(a0); | |
1532 break; | |
1533 | |
1534 case 0x33: // malloc | |
1535 { | |
1536 uint32 chunk, fd; | |
1537 | |
1538 #if DEBUG_HLE_BIOS | |
1539 printf("HLEBIOS: malloc(%x)\n", a0); | |
1540 #endif | |
1541 | |
1542 chunk = heap_addr; | |
1543 | |
1544 // find a free block that's big enough | |
1545 while ((a0 > LE32(psx_ram[(chunk+BLK_SIZE)/4])) || | |
1546 (LE32(psx_ram[(chunk+BLK_STAT)/4]) == 1)) | |
1547 { | |
1548 chunk = LE32(psx_ram[(chunk+BLK_FD)]); | |
1549 } | |
1550 | |
1551 // split free block | |
1552 fd = chunk + 16 + a0; // free block starts after block record and allocation size | |
1553 psx_ram[(fd+BLK_STAT)/4] = psx_ram[(chunk+BLK_STAT)/4]; | |
1554 psx_ram[(fd+BLK_SIZE)/4] = LE32(LE32(psx_ram[(chunk+BLK_SIZE)/4]) - a0); | |
1555 psx_ram[(fd+BLK_FD)/4] = psx_ram[(chunk+BLK_FD)/4]; | |
1556 psx_ram[(fd+BLK_BK)/4] = chunk; | |
1557 | |
1558 psx_ram[(chunk+BLK_STAT)/4] = LE32(1); | |
1559 psx_ram[(chunk+BLK_SIZE)/4] = LE32(a0); | |
1560 psx_ram[(chunk+BLK_FD)/4] = LE32(fd); | |
1561 | |
1562 mipsinfo.i = chunk + 16; | |
1563 mipsinfo.i |= 0x80000000; | |
1564 #if DEBUG_HLE_BIOS | |
1565 printf("== %08x\n", mipsinfo.i); | |
1566 #endif | |
1567 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
1568 } | |
1569 break; | |
1570 | |
1571 case 0x39: // InitHeap | |
1572 // heap address in A0, length in A1 | |
1573 #if DEBUG_HLE_BIOS | |
1574 printf("HLEBIOS: InitHeap(%08x, %08x)\n", a0, a1); | |
1575 #endif | |
1576 | |
1577 heap_addr = a0 & 0x3fffffff; | |
1578 | |
1579 psx_ram[(heap_addr+BLK_STAT)/4] = LE32(0); | |
1580 psx_ram[(heap_addr+BLK_FD)/4] = LE32(0); | |
1581 psx_ram[(heap_addr+BLK_BK)/4] = LE32(0); | |
1582 | |
1583 // if heap size out of range, clamp it | |
1584 if (((a0 & 0x1fffff) + a1) >= 2*1024*1024) | |
1585 { | |
1586 psx_ram[(heap_addr+BLK_SIZE)/4] = LE32(0x1ffffc - (a0 & 0x1fffff)); | |
1587 } | |
1588 else | |
1589 { | |
1590 psx_ram[(heap_addr+BLK_SIZE)/4] = LE32(a1); | |
1591 } | |
1592 break; | |
1593 | |
1594 case 0x3f: // printf | |
1595 #if DEBUG_HLE_BIOS | |
1596 printf("HLEBIOS: printf(%08x) = %s\n", a0, &psx_ram[(a0&0x1fffff)/4]); | |
1597 #endif | |
1598 break; | |
1599 | |
1600 case 0x72: //__96_remove | |
1601 #if DEBUG_HLE_BIOS | |
1602 printf("HLEBIOS: __96_remove\n"); | |
1603 #endif | |
1604 break; | |
1605 | |
1606 default: | |
1607 #if DEBUG_HLE_BIOS | |
1608 printf("Unknown BIOS A0 call = %x\n", subcall); | |
1609 #endif | |
1610 break; | |
1611 } | |
1612 break; | |
1613 | |
1614 case 0xb0: // b0 syscalls | |
1615 switch (subcall) | |
1616 { | |
1617 case 0x07: // DeliverEvent | |
1618 { | |
1619 int ev, spec; | |
1620 | |
1621 | |
1622 ev = calc_ev(a0); | |
1623 spec = calc_spec(a1); | |
1624 | |
1625 #if DEBUG_HLE_BIOS | |
1626 printf("HLEBIOS: DeliverEvent(ev %d, spec %d)\n", ev, spec); | |
1627 #endif | |
1628 | |
1629 if (Event[ev][spec].status != LE32(EvStACTIVE)) | |
1630 { | |
1631 #if DEBUG_HLE_BIOS | |
1632 printf("event not active\n"); | |
1633 #endif | |
1634 return; | |
1635 } | |
1636 | |
1637 // if interrupt mode, do the call | |
1638 if (Event[ev][spec].mode == LE32(EvMdINTR)) | |
1639 { | |
1640 #if DEBUG_HLE_BIOS | |
1641 printf("INTR type, need to call handler %x\n", LE32(Event[ev][spec].fhandler)); | |
1642 #endif | |
1643 } | |
1644 else | |
1645 { | |
1646 Event[ev][spec].status = LE32(EvStALREADY); | |
1647 } | |
1648 } | |
1649 break; | |
1650 | |
1651 case 0x08: // OpenEvent | |
1652 { | |
1653 int ev, spec; | |
1654 | |
1655 ev = calc_ev(a0); | |
1656 spec = calc_spec(a1); | |
1657 | |
1658 #if DEBUG_HLE_BIOS | |
1659 printf("HLEBIOS: OpenEvent(%08x, %08x, %08x, %08x) = ev %d spec %d\n", a0, a1, a2, a3, ev, spec); | |
1660 if (ev >= 64 && ev <= 67) | |
1661 { | |
1662 printf("HLEBIOS: event %d maps to root counter %d\n", ev, ev-64); | |
1663 } | |
1664 #endif | |
1665 | |
1666 Event[ev][spec].status = LE32(EvStWAIT); | |
1667 Event[ev][spec].mode = LE32(a2); | |
1668 Event[ev][spec].fhandler = LE32(a3); | |
1669 | |
1670 // v0 = ev | spec<<8; | |
1671 mipsinfo.i = ev | (spec<<8); | |
1672 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
1673 } | |
1674 break; | |
1675 | |
1676 case 0x0a: // WaitEvent | |
1677 { | |
1678 int ev, spec; | |
1679 | |
1680 ev = a0 & 0xff; | |
1681 spec = (a0 >> 8) & 0xff; | |
1682 | |
1683 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo); | |
1684 #if DEBUG_HLE_BIOS | |
1685 printf("HLEBIOS: WaitEvent(ev %d spec %d) PC=%x\n", ev, spec, mipsinfo.i); | |
1686 #endif | |
1687 | |
1688 Event[ev][spec].status = LE32(EvStACTIVE); | |
1689 | |
1690 // v0 = 1 | |
1691 mipsinfo.i = 1; | |
1692 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
1693 | |
1694 WAI = 1; | |
1695 mips_shorten_frame(); | |
1696 } | |
1697 break; | |
1698 | |
1699 case 0x0b: // TestEvent | |
1700 { | |
1701 int ev, spec; | |
1702 | |
1703 ev = a0 & 0xff; | |
1704 spec = (a0 >> 8) & 0xff; | |
1705 | |
1706 #if DEBUG_HLE_BIOS | |
1707 printf("HLEBIOS: TestEvent(ev %d spec %d)\n", ev, spec); | |
1708 #endif | |
1709 | |
1710 // v0 = (is event ready?) | |
1711 if (Event[ev][spec].status == LE32(EvStALREADY)) | |
1712 { | |
1713 Event[ev][spec].status = LE32(EvStACTIVE); | |
1714 mipsinfo.i = 1; | |
1715 } | |
1716 else | |
1717 { | |
1718 mipsinfo.i = 0; | |
1719 } | |
1720 | |
1721 WAI = 1; | |
1722 | |
1723 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
1724 | |
1725 // it looks like this sets v1 to something non-zero too | |
1726 // (code in Crash 2 & 3 actually relies on that behavior) | |
1727 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R3, &mipsinfo); | |
1728 } | |
1729 break; | |
1730 | |
1731 case 0x0c: // EnableEvent | |
1732 { | |
1733 int ev, spec; | |
1734 | |
1735 ev = a0 & 0xff; | |
1736 spec = (a0 >> 8) & 0xff; | |
1737 | |
1738 #if DEBUG_HLE_BIOS | |
1739 printf("HLEBIOS: EnableEvent(ev %d spec %d)\n", ev, spec); | |
1740 #endif | |
1741 | |
1742 Event[ev][spec].status = LE32(EvStACTIVE); | |
1743 | |
1744 // v0 = 1 | |
1745 mipsinfo.i = 1; | |
1746 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
1747 } | |
1748 break; | |
1749 | |
1750 case 0x0d: // DisableEvent | |
1751 { | |
1752 int ev, spec; | |
1753 | |
1754 ev = a0 & 0xff; | |
1755 spec = (a0 >> 8) & 0xff; | |
1756 | |
1757 #if DEBUG_HLE_BIOS | |
1758 printf("HLEBIOS: DisableEvent(ev %d spec %d)\n", ev, spec); | |
1759 #endif | |
1760 | |
1761 Event[ev][spec].status = LE32(EvStWAIT); | |
1762 | |
1763 // v0 = 1 | |
1764 mipsinfo.i = 1; | |
1765 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
1766 } | |
1767 break; | |
1768 | |
1769 case 0x17: // ReturnFromException | |
1770 for (i = 0; i < 32; i++) | |
1771 { | |
1772 mipsinfo.i = irq_regs[i]; | |
1773 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R0 + i, &mipsinfo); | |
1774 } | |
1775 | |
1776 mipsinfo.i = irq_regs[32]; | |
1777 mips_set_info(CPUINFO_INT_REGISTER + MIPS_HI, &mipsinfo); | |
1778 mipsinfo.i = irq_regs[33]; | |
1779 mips_set_info(CPUINFO_INT_REGISTER + MIPS_LO, &mipsinfo); | |
1780 mipsinfo.i = mips_get_ePC(); | |
1781 // printf("ReturnFromException: IRQ state %x\n", irq_data & irq_mask); | |
1782 // printf("HLEBIOS: ReturnFromException, cause = %08x, PC = %08x\n", mips_get_cause(), mipsinfo.i); | |
1783 mips_set_info(CPUINFO_INT_PC, &mipsinfo); | |
1784 | |
1785 status = mips_get_status(); | |
1786 status = (status & 0xfffffff0) | ((status & 0x3c)>>2); | |
1787 mips_set_status(status); | |
1788 return; // force return to avoid PC=RA below | |
1789 break; | |
1790 | |
1791 case 0x19: // HookEntryInt | |
1792 #if DEBUG_HLE_BIOS | |
1793 printf("HLEBIOS: HookEntryInt(%08x)\n", a0); | |
1794 #endif | |
1795 entry_int = a0; | |
1796 break; | |
1797 | |
1798 case 0x3f: // puts | |
1799 // printf("HLEBIOS: puts\n"); | |
1800 break; | |
1801 | |
1802 case 0x5b: // ChangeClearPAD | |
1803 #if DEBUG_HLE_BIOS | |
1804 printf("HLEBIOS: ChangeClearPAD\n"); | |
1805 #endif | |
1806 break; | |
1807 | |
1808 default: | |
1809 #if DEBUG_HLE_BIOS | |
1810 printf("Unknown BIOS B0 call = %x\n", subcall); | |
1811 #endif | |
1812 break; | |
1813 } | |
1814 break; | |
1815 | |
1816 case 0xc0: // c0 syscalls | |
1817 switch (subcall) | |
1818 { | |
1819 case 0xa: // ChangeClearRCnt | |
1820 #if DEBUG_HLE_BIOS | |
1821 printf("HLEBIOS: ChangeClearRCnt(%08x, %08x)\n", a0, a1); | |
1822 #endif | |
1823 | |
1824 // v0 = (a0*4)+0x8600 | |
1825 mipsinfo.i = LE32(psx_ram[((a0<<2) + 0x8600)/4]); | |
1826 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
1827 | |
1828 // (a0*4)+0x8600 = a1; | |
1829 psx_ram[((a0<<2) + 0x8600)/4] = LE32(a1); | |
1830 break; | |
1831 | |
1832 default: | |
1833 #if DEBUG_HLE_BIOS | |
1834 printf("Unknown BIOS C0 call = %x\n", subcall); | |
1835 #endif | |
1836 break; | |
1837 } | |
1838 break; | |
1839 } | |
1840 | |
1841 // PC = RA | |
1842 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo); | |
1843 mips_set_info(CPUINFO_INT_PC, &mipsinfo); | |
1844 } | |
1845 | |
1846 // root counters | |
1847 | |
1848 void psx_hw_runcounters(void) | |
1849 { | |
1850 int i, j; | |
1851 union cpuinfo mipsinfo; | |
1852 | |
1853 // don't process any IRQ sources when interrupts are suspended | |
1854 if (!intr_susp) | |
1855 { | |
1856 if (dma4_delay) | |
1857 { | |
1858 dma4_delay--; | |
1859 | |
1860 if (dma4_delay == 0) | |
1861 { | |
1862 SPU2interruptDMA4(); | |
1863 | |
1864 if (dma4_cb) | |
1865 { | |
1866 call_irq_routine(dma4_cb, dma4_flag); | |
1867 } | |
1868 } | |
1869 } | |
1870 | |
1871 if (dma7_delay) | |
1872 { | |
1873 dma7_delay--; | |
1874 | |
1875 if (dma7_delay == 0) | |
1876 { | |
1877 SPU2interruptDMA7(); | |
1878 | |
1879 if (dma7_cb) | |
1880 { | |
1881 call_irq_routine(dma7_cb, dma7_flag); | |
1882 } | |
1883 } | |
1884 } | |
1885 | |
1886 for (i = 0; i < iNumThreads; i++) | |
1887 { | |
1888 if (threads[i].iState == TS_WAITDELAY) | |
1889 { | |
1890 if (threads[i].waitparm > CLOCK_DIV) | |
1891 { | |
1892 threads[i].waitparm -= CLOCK_DIV; | |
1893 } | |
1894 else // time's up | |
1895 { | |
1896 threads[i].waitparm = 0; | |
1897 threads[i].iState = TS_READY; | |
1898 | |
1899 timerexp = 1; | |
1900 | |
1901 ps2_reschedule(); | |
1902 } | |
1903 } | |
1904 } | |
1905 | |
1906 sys_time += 836; | |
1907 | |
1908 if (iNumTimers > 0) | |
1909 { | |
1910 for (i = 0; i < iNumTimers; i++) | |
1911 { | |
1912 if (iop_timers[i].iActive > 0) | |
1913 { | |
1914 iop_timers[i].count += 836; | |
1915 if (iop_timers[i].count >= iop_timers[i].target) | |
1916 { | |
1917 iop_timers[i].count -= iop_timers[i].target; | |
1918 | |
1919 // printf("Timer %d: handler = %08x, param = %08x\n", i, iop_timers[i].handler, iop_timers[i].hparam); | |
1920 call_irq_routine(iop_timers[i].handler, iop_timers[i].hparam); | |
1921 | |
1922 timerexp = 1; | |
1923 } | |
1924 } | |
1925 } | |
1926 } | |
1927 } | |
1928 | |
1929 // PS1 root counters | |
1930 for (i = 0; i < 3; i++) | |
1931 { | |
1932 if ((!(root_cnts[i].mode & RC_EN)) && (root_cnts[i].mode != 0)) | |
1933 { | |
1934 if (root_cnts[i].mode & RC_DIV8) | |
1935 { | |
1936 root_cnts[i].count += 768/8; | |
1937 } | |
1938 else | |
1939 { | |
1940 root_cnts[i].count += 768; | |
1941 } | |
1942 | |
1943 if (root_cnts[i].count >= root_cnts[i].target) | |
1944 { | |
1945 if (!(root_cnts[i].mode & RC_RESET)) | |
1946 { | |
1947 root_cnts[i].mode |= RC_EN; | |
1948 } | |
1949 else | |
1950 { | |
1951 root_cnts[i].count %= root_cnts[i].target; | |
1952 } | |
1953 | |
1954 psx_irq_set(1<<(4+i)); | |
1955 } | |
1956 } | |
1957 } | |
1958 } | |
1959 | |
1960 // PEOpS callbacks | |
1961 | |
1962 void SPUirq(void) | |
1963 { | |
1964 // psx_irq_set(0x200); | |
1965 } | |
1966 | |
1967 // PSXCPU callbacks | |
1968 | |
1969 uint8 program_read_byte_32le(offs_t address) | |
1970 { | |
1971 switch (address & 0x3) | |
1972 { | |
1973 case 0: | |
1974 return psx_hw_read(address, 0xffffff00); | |
1975 break; | |
1976 case 1: | |
1977 return psx_hw_read(address, 0xffff00ff)>>8; | |
1978 break; | |
1979 case 2: | |
1980 return psx_hw_read(address, 0xff00ffff)>>16; | |
1981 break; | |
1982 case 3: | |
1983 return psx_hw_read(address, 0x00ffffff)>>24; | |
1984 break; | |
1985 } | |
1986 } | |
1987 | |
1988 uint16 program_read_word_32le(offs_t address) | |
1989 { | |
1990 if (address & 2) | |
1991 return psx_hw_read(address, 0x0000ffff)>>16; | |
1992 | |
1993 return psx_hw_read(address, 0xffff0000); | |
1994 } | |
1995 | |
1996 uint32 program_read_dword_32le(offs_t address) | |
1997 { | |
1998 return psx_hw_read(address, 0); | |
1999 } | |
2000 | |
2001 void program_write_byte_32le(offs_t address, uint8 data) | |
2002 { | |
2003 switch (address & 0x3) | |
2004 { | |
2005 case 0: | |
2006 psx_hw_write(address, data, 0xffffff00); | |
2007 break; | |
2008 case 1: | |
2009 psx_hw_write(address, data<<8, 0xffff00ff); | |
2010 break; | |
2011 case 2: | |
2012 psx_hw_write(address, data<<16, 0xff00ffff); | |
2013 break; | |
2014 case 3: | |
2015 psx_hw_write(address, data<<24, 0x00ffffff); | |
2016 break; | |
2017 } | |
2018 } | |
2019 | |
2020 void program_write_word_32le(offs_t address, uint16 data) | |
2021 { | |
2022 if (address & 2) | |
2023 { | |
2024 psx_hw_write(address, data<<16, 0x0000ffff); | |
2025 return; | |
2026 } | |
2027 | |
2028 psx_hw_write(address, data, 0xffff0000); | |
2029 } | |
2030 | |
2031 void program_write_dword_32le(offs_t address, uint32 data) | |
2032 { | |
2033 psx_hw_write(address, data, 0); | |
2034 } | |
2035 | |
2036 // sprintf replacement | |
2037 static iop_sprintf(char *out, char *fmt, uint32 pstart) | |
2038 { | |
2039 char temp[64], tfmt[64]; | |
2040 char *cf, *pstr; | |
2041 union cpuinfo mipsinfo; | |
2042 int curparm, fp, isnum; | |
2043 | |
2044 curparm = pstart; | |
2045 cf = fmt; | |
2046 | |
2047 while (*cf != '\0') | |
2048 { | |
2049 if (*cf != '%') | |
2050 { | |
2051 if (*cf == 27) | |
2052 { | |
2053 *out++ = '['; | |
2054 *out++ = 'E'; | |
2055 *out++ = 'S'; | |
2056 *out++ = 'C'; | |
2057 *out = ']'; | |
2058 } | |
2059 else | |
2060 { | |
2061 *out = *cf; | |
2062 } | |
2063 out++; | |
2064 cf++; | |
2065 } | |
2066 else // got format | |
2067 { | |
2068 cf++; | |
2069 | |
2070 tfmt[0] = '%'; | |
2071 fp = 1; | |
2072 while (((*cf >= '0') && (*cf <= '9')) || (*cf == '.')) | |
2073 { | |
2074 tfmt[fp] = *cf; | |
2075 fp++; | |
2076 cf++; | |
2077 } | |
2078 | |
2079 tfmt[fp] = *cf; | |
2080 tfmt[fp+1] = '\0'; | |
2081 | |
2082 isnum = 0; | |
2083 switch (*cf) | |
2084 { | |
2085 case 'x': | |
2086 case 'X': | |
2087 case 'd': | |
2088 case 'D': | |
2089 case 'c': | |
2090 case 'C': | |
2091 case 'u': | |
2092 case 'U': | |
2093 isnum = 1; | |
2094 break; | |
2095 } | |
2096 | |
2097 // printf("]]] temp format: [%s] [%d]\n", tfmt, isnum); | |
2098 | |
2099 if (isnum) | |
2100 { | |
2101 mips_get_info(curparm, &mipsinfo); | |
2102 // printf("parameter %d = %x\n", curparm-pstart, mipsinfo.i); | |
2103 curparm++; | |
2104 sprintf(temp, tfmt, (int32)mipsinfo.i); | |
2105 } | |
2106 else | |
2107 { | |
2108 mips_get_info(curparm, &mipsinfo); | |
2109 curparm++; | |
2110 | |
2111 pstr = (char *)psx_ram; | |
2112 pstr += (mipsinfo.i & 0x1fffff); | |
2113 | |
2114 sprintf(temp, tfmt, pstr); | |
2115 } | |
2116 | |
2117 pstr = &temp[0]; | |
2118 while (*pstr != '\0') | |
2119 { | |
2120 *out = *pstr; | |
2121 out++; | |
2122 pstr++; | |
2123 } | |
2124 | |
2125 cf++; | |
2126 } | |
2127 } | |
2128 | |
2129 *out = '\0'; | |
2130 } | |
2131 | |
2132 // PS2 IOP callbacks | |
2133 void psx_iop_call(uint32 pc, uint32 callnum) | |
2134 { | |
2135 uint32 scan; | |
2136 char *mname, *str1, *str2, *str3, name[9], out[512]; | |
2137 uint32 a0, a1, a2, a3; | |
2138 union cpuinfo mipsinfo; | |
2139 int i; | |
2140 | |
2141 // printf("IOP call @ %08x\n", pc); | |
2142 | |
2143 // prefetch parameters | |
2144 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R4, &mipsinfo); | |
2145 a0 = mipsinfo.i; | |
2146 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R5, &mipsinfo); | |
2147 a1 = mipsinfo.i; | |
2148 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R6, &mipsinfo); | |
2149 a2 = mipsinfo.i; | |
2150 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R7, &mipsinfo); | |
2151 a3 = mipsinfo.i; | |
2152 | |
2153 scan = (pc&0x0fffffff)/4; | |
2154 while ((psx_ram[scan] != LE32(0x41e00000)) && (scan >= (0x10000/4))) | |
2155 { | |
2156 scan--; | |
2157 } | |
2158 | |
2159 if (psx_ram[scan] != LE32(0x41e00000)) | |
2160 { | |
2161 printf("FATAL ERROR: couldn't find IOP link signature\n"); | |
2162 return; | |
2163 } | |
2164 | |
2165 scan += 3; // skip zero and version | |
2166 memcpy(name, &psx_ram[scan], 8); | |
2167 name[8] = '\0'; | |
2168 | |
2169 // printf("IOP: call module [%s] service %d (PC=%08x)\n", name, callnum, pc); | |
2170 | |
2171 if (!strcmp(name, "stdio")) | |
2172 { | |
2173 switch (callnum) | |
2174 { | |
2175 case 4: // printf | |
2176 mname = (char *)psx_ram; | |
2177 mname += a0 & 0x1fffff; | |
2178 mname += (a0 & 3); | |
2179 | |
2180 iop_sprintf(out, mname, CPUINFO_INT_REGISTER + MIPS_R5); // a1 is first parm | |
2181 | |
2182 /* if (out[strlen(out)-1] != '\n') | |
2183 { | |
2184 strcat(out, "\n"); | |
2185 }*/ | |
2186 | |
2187 #if DEBUG_HLE_IOP | |
2188 printf("%s", out); | |
2189 #endif | |
2190 break; | |
2191 | |
2192 default: | |
2193 printf("IOP: Unhandled service %d for module %s\n", callnum, name); | |
2194 break; | |
2195 } | |
2196 } | |
2197 else if (!strcmp(name, "sifman")) | |
2198 { | |
2199 switch (callnum) | |
2200 { | |
2201 case 5: // sceSifInit | |
2202 #if DEBUG_HLE_IOP | |
2203 printf("IOP: sceSifInit()\n"); | |
2204 #endif | |
2205 | |
2206 mipsinfo.i = 0; | |
2207 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2208 break; | |
2209 | |
2210 case 7: // sceSifSetDma | |
2211 #if DEBUG_HLE_IOP | |
2212 printf("IOP: sceSifSetDma(%08x %08x)\n", a0, a1); | |
2213 #endif | |
2214 | |
2215 mipsinfo.i = 1; // nonzero = success | |
2216 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2217 break; | |
2218 | |
2219 case 8: // sceSifDmaStat | |
2220 #if DEBUG_HLE_IOP | |
2221 printf("IOP: sceSifDmaStat(%08x)\n", a0); | |
2222 #endif | |
2223 | |
2224 mipsinfo.i = -1; // dma completed | |
2225 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2226 break; | |
2227 | |
2228 case 29: // sceSifCheckInit | |
2229 #if DEBUG_HLE_IOP | |
2230 printf("IOP: sceSifCheckInit()\n"); | |
2231 #endif | |
2232 | |
2233 mipsinfo.i = 1; | |
2234 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2235 break; | |
2236 | |
2237 default: | |
2238 printf("IOP: Unhandled service %d for module %s\n", callnum, name); | |
2239 break; | |
2240 } | |
2241 } | |
2242 else if (!strcmp(name, "thbase")) | |
2243 { | |
2244 uint32 newAlloc; | |
2245 | |
2246 switch (callnum) | |
2247 { | |
2248 case 4: // CreateThread | |
2249 #if DEBUG_THREADING | |
2250 printf("IOP: CreateThread(%08x)\n", a0); | |
2251 #endif | |
2252 a0 &= 0x1fffff; | |
2253 a0 /= 4; | |
2254 #if DEBUG_THREADING | |
2255 printf(" : flags %x routine %08x pri %x stacksize %d refCon %08x\n", | |
2256 psx_ram[a0], psx_ram[a0+1], psx_ram[a0+2], psx_ram[a0+3], psx_ram[a0+4]); | |
2257 #endif | |
2258 | |
2259 newAlloc = psf2_get_loadaddr(); | |
2260 // force 16-byte alignment | |
2261 if (newAlloc & 0xf) | |
2262 { | |
2263 newAlloc &= ~0xf; | |
2264 newAlloc += 16; | |
2265 } | |
2266 psf2_set_loadaddr(newAlloc + LE32(psx_ram[a0+3])); | |
2267 | |
2268 threads[iNumThreads].iState = TS_CREATED; | |
2269 threads[iNumThreads].stackloc = newAlloc; | |
2270 threads[iNumThreads].flags = LE32(psx_ram[a0]); | |
2271 threads[iNumThreads].routine = LE32(psx_ram[a0+2]); | |
2272 threads[iNumThreads].stacksize = LE32(psx_ram[a0+3]); | |
2273 threads[iNumThreads].refCon = LE32(psx_ram[a0+4]); | |
2274 | |
2275 mipsinfo.i = iNumThreads; | |
2276 iNumThreads++; | |
2277 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2278 break; | |
2279 | |
2280 case 6: // StartThread | |
2281 #if DEBUG_THREADING | |
2282 printf("IOP: StartThread(%d %d)\n", a0, a1); | |
2283 #endif | |
2284 | |
2285 FreezeThread(iCurThread, 1); | |
2286 ThawThread(a0); | |
2287 iCurThread = a0; | |
2288 break; | |
2289 | |
2290 case 20:// GetThreadID | |
2291 #if DEBUG_THREADING | |
2292 printf("IOP: GetThreadId()\n"); | |
2293 #endif | |
2294 | |
2295 mipsinfo.i = iCurThread; | |
2296 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2297 break; | |
2298 | |
2299 case 24:// SleepThread | |
2300 #if DEBUG_THREADING | |
2301 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo); | |
2302 printf("IOP: SleepThread() [curThread %d, PC=%x]\n", iCurThread, mipsinfo.i); | |
2303 #endif | |
2304 | |
2305 FreezeThread(iCurThread, 1); | |
2306 threads[iCurThread].iState = TS_SLEEPING; | |
2307 iCurThread = -1; | |
2308 | |
2309 ps2_reschedule(); | |
2310 break; | |
2311 | |
2312 case 25:// WakeupThread | |
2313 #if DEBUG_THREADING | |
2314 printf("IOP: WakeupThread(%d)\n", a0); | |
2315 #endif | |
2316 | |
2317 // set thread to "ready to go" | |
2318 threads[a0].iState = TS_READY; | |
2319 break; | |
2320 | |
2321 case 26:// iWakeupThread | |
2322 #if DEBUG_THREADING | |
2323 printf("IOP: iWakeupThread(%d)\n", a0); | |
2324 #endif | |
2325 | |
2326 // set thread to "ready to go" if it's not running | |
2327 if (threads[a0].iState != TS_RUNNING) | |
2328 { | |
2329 threads[a0].iState = TS_READY; | |
2330 } | |
2331 break; | |
2332 | |
2333 case 33:// DelayThread | |
2334 { | |
2335 double dTicks; | |
2336 int i; | |
2337 | |
2338 #if DEBUG_THREADING | |
2339 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo); | |
2340 printf("IOP: DelayThread(%d) (PC=%x) [curthread = %d]\n", a0, mipsinfo.i, iCurThread); | |
2341 #endif | |
2342 | |
2343 if (a0 < 100) | |
2344 { | |
2345 a0 = 100; | |
2346 } | |
2347 dTicks = (double)a0; | |
2348 | |
2349 FreezeThread(iCurThread, 1); | |
2350 threads[iCurThread].iState = TS_WAITDELAY; | |
2351 dTicks /= (double)1000000.0; | |
2352 dTicks *= (double)36864000.0; // 768*48000 = IOP native-mode clock rate | |
2353 threads[iCurThread].waitparm = (uint32)dTicks; | |
2354 iCurThread = -1; | |
2355 | |
2356 ps2_reschedule(); | |
2357 } | |
2358 break; | |
2359 | |
2360 case 34://GetSystemTime | |
2361 #if DEBUG_HLE_IOP | |
2362 printf("IOP: GetSystemTime(%x)\n", a0); | |
2363 #endif | |
2364 | |
2365 a0 &= 0x1fffff; | |
2366 a0 /= 4; | |
2367 | |
2368 psx_ram[a0] = LE32(sys_time & 0xffffffff); // low | |
2369 psx_ram[a0+1] = LE32(sys_time >> 32); // high | |
2370 | |
2371 mipsinfo.i = 0; | |
2372 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2373 break; | |
2374 | |
2375 case 39:// USec2SysClock | |
2376 { | |
2377 uint64 dTicks = (uint64)a0; | |
2378 uint32 hi, lo; | |
2379 | |
2380 #if DEBUG_HLE_IOP | |
2381 printf("IOP: USec2SysClock(%d %08x)\n", a0, a1); | |
2382 #endif | |
2383 | |
2384 dTicks *= (uint64)36864000; | |
2385 dTicks /= (uint64)1000000; | |
2386 | |
2387 hi = dTicks>>32; | |
2388 lo = dTicks & 0xffffffff; | |
2389 | |
2390 psx_ram[((a1 & 0x1fffff)/4)] = LE32(lo); | |
2391 psx_ram[((a1 & 0x1fffff)/4)+1] = LE32(hi); | |
2392 | |
2393 mipsinfo.i = 0; | |
2394 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2395 } | |
2396 break; | |
2397 | |
2398 case 40://SysClock2USec | |
2399 { | |
2400 uint64 temp; | |
2401 uint32 seconds, usec; | |
2402 | |
2403 #if DEBUG_HLE_IOP | |
2404 printf("IOP: SysClock2USec(%08x %08x %08x)\n", a0, a1, a2); | |
2405 #endif | |
2406 | |
2407 a0 &= 0x1fffff; | |
2408 a1 &= 0x1fffff; | |
2409 a2 &= 0x1fffff; | |
2410 a0 /= 4; | |
2411 a1 /= 4; | |
2412 a2 /= 4; | |
2413 | |
2414 temp = LE32(psx_ram[a0]); | |
2415 temp |= (uint64)LE32(psx_ram[a0+1])<<32; | |
2416 | |
2417 temp *= (uint64)1000000; | |
2418 temp /= (uint64)36864000; | |
2419 | |
2420 // temp now is USec | |
2421 seconds = (temp / 1000000) & 0xffffffff; | |
2422 usec = (temp % 1000000) & 0xffffffff; | |
2423 | |
2424 psx_ram[a1] = LE32(seconds); | |
2425 psx_ram[a2] = LE32(usec); | |
2426 } | |
2427 break; | |
2428 | |
2429 default: | |
2430 printf("IOP: Unhandled service %d for module %s\n", callnum, name); | |
2431 break; | |
2432 } | |
2433 } | |
2434 else if (!strcmp(name, "thevent")) | |
2435 { | |
2436 switch (callnum) | |
2437 { | |
2438 case 4: // CreateEventFlag | |
2439 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo); | |
2440 #if DEBUG_HLE_IOP | |
2441 printf("IOP: CreateEventFlag(%08x) (PC=%x)\n", a0, mipsinfo.i); | |
2442 #endif | |
2443 | |
2444 a0 &= 0x1fffff; | |
2445 a0 /= 4; | |
2446 | |
2447 evflags[iNumFlags].type = LE32(psx_ram[a0]); | |
2448 evflags[iNumFlags].value = LE32(psx_ram[a0+1]); | |
2449 evflags[iNumFlags].param = LE32(psx_ram[a0+2]); | |
2450 evflags[iNumFlags].inUse = 1; | |
2451 | |
2452 #if DEBUG_HLE_IOP | |
2453 printf(" Flag %02d: type %d init %08x param %08x\n", iNumFlags, evflags[iNumFlags].type, evflags[iNumFlags].value, evflags[iNumFlags].param); | |
2454 #endif | |
2455 | |
2456 mipsinfo.i = iNumFlags+1; | |
2457 iNumFlags++; | |
2458 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2459 break; | |
2460 | |
2461 case 6: // SetEventFlag | |
2462 a0--; | |
2463 #if DEBUG_HLE_IOP | |
2464 printf("IOP: SetEventFlag(%d %08x)\n", a0, a1); | |
2465 #endif | |
2466 | |
2467 evflags[a0].value |= a1; | |
2468 | |
2469 mipsinfo.i = 0; | |
2470 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2471 break; | |
2472 | |
2473 case 7: // iSetEventFlag | |
2474 a0--; | |
2475 #if DEBUG_HLE_IOP | |
2476 printf("IOP: iSetEventFlag(%08x %08x)\n", a0, a1); | |
2477 #endif | |
2478 | |
2479 evflags[a0].value |= a1; | |
2480 | |
2481 mipsinfo.i = 0; | |
2482 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2483 | |
2484 for (i=0; i < iNumThreads; i++) | |
2485 { | |
2486 if ((threads[i].iState == TS_WAITEVFLAG) && (threads[i].waitparm == a0)) | |
2487 { | |
2488 threads[i].iState = TS_READY; | |
2489 } | |
2490 } | |
2491 break; | |
2492 | |
2493 case 8: // ClearEventFlag | |
2494 a0--; | |
2495 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo); | |
2496 #if DEBUG_HLE_IOP | |
2497 printf("IOP: ClearEventFlag(%d %08x) (PC=%x)\n", a0, a1, mipsinfo.i); | |
2498 #endif | |
2499 | |
2500 evflags[a0].value &= a1; | |
2501 | |
2502 mipsinfo.i = 0; | |
2503 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2504 break; | |
2505 | |
2506 case 9: // iClearEventFlag | |
2507 a0--; | |
2508 #if DEBUG_HLE_IOP | |
2509 printf("IOP: iClearEventFlag(%d %08x)\n", a0, a1); | |
2510 #endif | |
2511 | |
2512 evflags[a0].value &= a1; | |
2513 | |
2514 mipsinfo.i = 0; | |
2515 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2516 break; | |
2517 | |
2518 case 10:// WaitEventFlag | |
2519 a0--; | |
2520 #if DEBUG_HLE_IOP | |
2521 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo); | |
2522 printf("IOP: WaitEventFlag(%d %08x %d %08x PC=%x)\n", a0, a1, a2, a3, mipsinfo.i); | |
2523 #endif | |
2524 | |
2525 // if we're not set, freeze this thread | |
2526 if (!(evflags[a0].value & a1)) | |
2527 { | |
2528 FreezeThread(iCurThread, 1); | |
2529 threads[iCurThread].iState = TS_WAITEVFLAG; | |
2530 threads[iCurThread].waitparm = a0; | |
2531 iCurThread = -1; | |
2532 | |
2533 ps2_reschedule(); | |
2534 } | |
2535 else | |
2536 { | |
2537 mipsinfo.i = 0; | |
2538 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2539 } | |
2540 break; | |
2541 | |
2542 default: | |
2543 printf("IOP: Unhandled service %d for module %s\n", callnum, name); | |
2544 break; | |
2545 } | |
2546 } | |
2547 else if (!strcmp(name, "thsemap")) | |
2548 { | |
2549 int foundthread; | |
2550 | |
2551 switch (callnum) | |
2552 { | |
2553 case 4: // CreateSema | |
2554 #if DEBUG_HLE_IOP | |
2555 printf("IOP: CreateSema(%08x)\n", a0); | |
2556 #endif | |
2557 | |
2558 mipsinfo.i = -1; | |
2559 for (i = 0; i < SEMA_MAX; i++) | |
2560 { | |
2561 if (!semaphores[i].inuse) | |
2562 { | |
2563 mipsinfo.i = i; | |
2564 break; | |
2565 } | |
2566 } | |
2567 | |
2568 if (mipsinfo.i == -1) | |
2569 { | |
2570 printf("IOP: out of semaphores!\n"); | |
2571 } | |
2572 | |
2573 a0 &= 0x7fffffff; | |
2574 a0 /= 4; | |
2575 | |
2576 // printf("Sema %d Parms: %08x %08x %08x %08x\n", mipsinfo.i, psx_ram[a0], psx_ram[a0+1], psx_ram[a0+2], psx_ram[a0+3]); | |
2577 | |
2578 if (mipsinfo.i != -1) | |
2579 { | |
2580 semaphores[mipsinfo.i].attr = LE32(psx_ram[a0]); | |
2581 semaphores[mipsinfo.i].option = LE32(psx_ram[a0+1]); | |
2582 semaphores[mipsinfo.i].init = LE32(psx_ram[a0+2]); | |
2583 semaphores[mipsinfo.i].max = LE32(psx_ram[a0+3]); | |
2584 | |
2585 semaphores[mipsinfo.i].current = semaphores[mipsinfo.i].init; | |
2586 | |
2587 semaphores[mipsinfo.i].inuse = 1; | |
2588 } | |
2589 | |
2590 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2591 break; | |
2592 | |
2593 case 6: // SignalSema | |
2594 #if DEBUG_HLE_IOP | |
2595 printf("IOP: SignalSema(%d) (current %d)\n", a0, semaphores[a0].current); | |
2596 #endif | |
2597 | |
2598 foundthread = 0; | |
2599 for (i=0; i < iNumThreads; i++) | |
2600 { | |
2601 if ((threads[i].iState == TS_WAITSEMA) && (threads[i].waitparm == a0)) | |
2602 { | |
2603 threads[i].iState = TS_READY; | |
2604 semaphores[a0].threadsWaiting--; | |
2605 foundthread = 1; | |
2606 break; | |
2607 } | |
2608 } | |
2609 | |
2610 mipsinfo.i = 0; | |
2611 | |
2612 if (!foundthread) | |
2613 { | |
2614 if (semaphores[a0].current < semaphores[a0].max) | |
2615 { | |
2616 semaphores[a0].current++; | |
2617 } | |
2618 else | |
2619 { | |
2620 mipsinfo.i = -420; // semaphore overflow | |
2621 } | |
2622 } | |
2623 | |
2624 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2625 break; | |
2626 | |
2627 case 7: // iSignalSema | |
2628 #if DEBUG_HLE_IOP | |
2629 printf("IOP: iSignalSema(%d)\n", a0); | |
2630 #endif | |
2631 | |
2632 foundthread = 0; | |
2633 for (i=0; i < iNumThreads; i++) | |
2634 { | |
2635 if ((threads[i].iState == TS_WAITSEMA) && (threads[i].waitparm == a0)) | |
2636 { | |
2637 threads[i].iState = TS_READY; | |
2638 semaphores[a0].threadsWaiting--; | |
2639 foundthread = 1; | |
2640 break; | |
2641 } | |
2642 } | |
2643 | |
2644 mipsinfo.i = 0; | |
2645 | |
2646 if (!foundthread) | |
2647 { | |
2648 if (semaphores[a0].current < semaphores[a0].max) | |
2649 { | |
2650 semaphores[a0].current++; | |
2651 } | |
2652 else | |
2653 { | |
2654 mipsinfo.i = -420; // semaphore overflow | |
2655 } | |
2656 } | |
2657 | |
2658 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2659 break; | |
2660 | |
2661 case 8: // WaitSema | |
2662 #if DEBUG_HLE_IOP | |
2663 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo); | |
2664 printf("IOP: WaitSema(%d) (cnt %d) (th %d) (PC=%x)\n", a0, iCurThread, semaphores[a0].current, mipsinfo.i); | |
2665 #endif | |
2666 | |
2667 if (semaphores[a0].current > 0) | |
2668 { | |
2669 semaphores[a0].current--; | |
2670 } | |
2671 else | |
2672 { | |
2673 FreezeThread(iCurThread, 1); | |
2674 threads[iCurThread].iState = TS_WAITSEMA; | |
2675 threads[iCurThread].waitparm = a0; | |
2676 ps2_reschedule(); | |
2677 } | |
2678 | |
2679 mipsinfo.i = 0; | |
2680 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2681 break; | |
2682 | |
2683 default: | |
2684 printf("IOP: Unhandled service %d for module %s\n", callnum, name); | |
2685 break; | |
2686 } | |
2687 } | |
2688 else if (!strcmp(name, "timrman")) | |
2689 { | |
2690 switch (callnum) | |
2691 { | |
2692 case 4: // AllocHardTimer | |
2693 #if DEBUG_HLE_IOP | |
2694 printf("IOP: AllocHardTimer(%d %d %d)\n", a0, a1, a2); | |
2695 #endif | |
2696 // source, size, prescale | |
2697 | |
2698 if (a1 != 32) | |
2699 { | |
2700 printf("IOP: AllocHardTimer doesn't support 16-bit timers!\n"); | |
2701 } | |
2702 | |
2703 iop_timers[iNumTimers].source = a0; | |
2704 iop_timers[iNumTimers].prescale = a2; | |
2705 | |
2706 mipsinfo.i = iNumTimers+1; | |
2707 iNumTimers++; | |
2708 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2709 break; | |
2710 | |
2711 case 6: // FreeHardTimer | |
2712 #if DEBUG_HLE_IOP | |
2713 printf("IOP: FreeHardTimer(%d)\n", a0); | |
2714 #endif | |
2715 mipsinfo.i = 0; | |
2716 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2717 break; | |
2718 | |
2719 case 10:// GetTimerCounter | |
2720 mipsinfo.i = iop_timers[a0-1].count; | |
2721 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2722 break; | |
2723 | |
2724 case 20: // SetTimerHandler | |
2725 #if DEBUG_HLE_IOP | |
2726 printf("IOP: SetTimerHandler(%d %d %08x %08x)\n", a0, a1, a2, a3); | |
2727 #endif | |
2728 // id, compare, handler, common (last is param for handler) | |
2729 | |
2730 iop_timers[a0-1].target = a1; | |
2731 iop_timers[a0-1].handler = a2; | |
2732 iop_timers[a0-1].hparam = a3; | |
2733 | |
2734 mipsinfo.i = 0; | |
2735 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2736 break; | |
2737 | |
2738 case 22: // SetupHardTimer | |
2739 #if DEBUG_HLE_IOP | |
2740 printf("IOP: SetupHardTimer(%d %d %d %d)\n", a0, a1, a2, a3); | |
2741 #endif | |
2742 // id, source, mode, prescale | |
2743 | |
2744 iop_timers[a0-1].source = a1; | |
2745 iop_timers[a0-1].mode = a2; | |
2746 iop_timers[a0-1].prescale = a3; | |
2747 | |
2748 mipsinfo.i = 0; | |
2749 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2750 break; | |
2751 | |
2752 case 23: // StartHardTimer | |
2753 #if DEBUG_HLE_IOP | |
2754 printf("IOP: StartHardTimer(%d)\n", a0); | |
2755 #endif | |
2756 | |
2757 iop_timers[a0-1].iActive = 1; | |
2758 iop_timers[a0-1].count = 0; | |
2759 | |
2760 mipsinfo.i = 0; | |
2761 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2762 break; | |
2763 | |
2764 case 24: // StopHardTimer | |
2765 #if DEBUG_HLE_IOP | |
2766 printf("IOP: StopHardTimer(%d)\n", a0); | |
2767 #endif | |
2768 | |
2769 iop_timers[a0-1].iActive = 0; | |
2770 | |
2771 mipsinfo.i = 0; | |
2772 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2773 break; | |
2774 | |
2775 default: | |
2776 printf("IOP: Unhandled service %d for module %s\n", callnum, name); | |
2777 break; | |
2778 } | |
2779 } | |
2780 else if (!strcmp(name, "sysclib")) | |
2781 { | |
2782 switch (callnum) | |
2783 { | |
2784 case 12: // memcpy | |
2785 { | |
2786 uint8 *dst, *src; | |
2787 | |
2788 #if DEBUG_HLE_IOP | |
2789 printf("IOP: memcpy(%08x, %08x, %d)\n", a0, a1, a2); | |
2790 #endif | |
2791 | |
2792 dst = (uint8 *)&psx_ram[(a0&0x1fffff)/4]; | |
2793 src = (uint8 *)&psx_ram[(a1&0x1fffff)/4]; | |
2794 // get exact byte alignment | |
2795 dst += a0 % 4; | |
2796 src += a1 % 4; | |
2797 | |
2798 while (a2) | |
2799 { | |
2800 *dst = *src; | |
2801 dst++; | |
2802 src++; | |
2803 a2--; | |
2804 } | |
2805 | |
2806 // v0 = a0 | |
2807 mipsinfo.i = a0; | |
2808 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2809 } | |
2810 break; | |
2811 | |
2812 case 13: // memmove | |
2813 { | |
2814 uint8 *dst, *src; | |
2815 | |
2816 #if DEBUG_HLE_IOP | |
2817 printf("IOP: memmove(%08x, %08x, %d)\n", a0, a1, a2); | |
2818 #endif | |
2819 | |
2820 dst = (uint8 *)&psx_ram[(a0&0x1fffff)/4]; | |
2821 src = (uint8 *)&psx_ram[(a1&0x1fffff)/4]; | |
2822 // get exact byte alignment | |
2823 dst += a0 % 4; | |
2824 src += a1 % 4; | |
2825 | |
2826 dst += a2 - 1; | |
2827 src += a2 - 1; | |
2828 | |
2829 while (a2) | |
2830 { | |
2831 *dst = *src; | |
2832 dst--; | |
2833 src--; | |
2834 a2--; | |
2835 } | |
2836 | |
2837 // v0 = a0 | |
2838 mipsinfo.i = a0; | |
2839 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2840 } | |
2841 break; | |
2842 | |
2843 case 14: // memset | |
2844 { | |
2845 uint8 *dst; | |
2846 | |
2847 #if DEBUG_HLE_IOP | |
2848 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo); | |
2849 printf("IOP: memset(%08x, %02x, %d) [PC=%x]\n", a0, a1, a2, mipsinfo.i); | |
2850 #endif | |
2851 | |
2852 dst = (uint8 *)&psx_ram[(a0&0x1fffff)/4]; | |
2853 dst += (a0 & 3); | |
2854 | |
2855 memset(dst, a1, a2); | |
2856 } | |
2857 break; | |
2858 | |
2859 case 17: // bzero | |
2860 { | |
2861 uint8 *dst; | |
2862 | |
2863 #if DEBUG_HLE_IOP | |
2864 printf("IOP: bzero(%08x, %08x)\n", a0, a1); | |
2865 #endif | |
2866 | |
2867 dst = (uint8 *)&psx_ram[(a0&0x1fffff)/4]; | |
2868 dst += (a0 & 3); | |
2869 memset(dst, 0, a1); | |
2870 } | |
2871 break; | |
2872 | |
2873 case 19: // sprintf | |
2874 mname = (char *)psx_ram; | |
2875 str1 = (char *)psx_ram; | |
2876 mname += a0 & 0x1fffff; | |
2877 str1 += a1 & 0x1fffff; | |
2878 | |
2879 #if DEBUG_HLE_IOP | |
2880 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo); | |
2881 printf("IOP: sprintf(%08x, %s, ...) [PC=%08x]\n", a0, str1, (uint32)mipsinfo.i); | |
2882 printf("%x %x %x %x\n", a0, a1, a2, a3); | |
2883 #endif | |
2884 | |
2885 iop_sprintf(mname, str1, CPUINFO_INT_REGISTER + MIPS_R6); // a2 is first parameter | |
2886 | |
2887 #if DEBUG_HLE_IOP | |
2888 printf(" = [%s]\n", mname); | |
2889 #endif | |
2890 break; | |
2891 | |
2892 case 23: // strcpy | |
2893 { | |
2894 uint8 *dst, *src; | |
2895 | |
2896 #if DEBUG_HLE_IOP | |
2897 printf("IOP: strcpy(%08x, %08x)\n", a0, a1); | |
2898 #endif | |
2899 | |
2900 dst = (uint8 *)&psx_ram[(a0&0x1fffff)/4]; | |
2901 src = (uint8 *)&psx_ram[(a1&0x1fffff)/4]; | |
2902 // get exact byte alignment | |
2903 dst += a0 % 4; | |
2904 src += a1 % 4; | |
2905 | |
2906 while (*src != '\0') | |
2907 { | |
2908 *dst = *src; | |
2909 dst++; | |
2910 src++; | |
2911 } | |
2912 *dst = '\0'; | |
2913 | |
2914 // v0 = a0 | |
2915 mipsinfo.i = a0; | |
2916 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2917 } | |
2918 break; | |
2919 | |
2920 case 27: // strlen | |
2921 { | |
2922 char *dst; | |
2923 | |
2924 #if DEBUG_HLE_IOP | |
2925 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo); | |
2926 printf("IOP: strlen(%08x) [PC=%x]\n", a0, mipsinfo.i); | |
2927 #endif | |
2928 | |
2929 dst = (char *)&psx_ram[(a0&0x1fffff)/4]; | |
2930 dst += (a0 & 3); | |
2931 mipsinfo.i = strlen(dst); | |
2932 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2933 } | |
2934 break; | |
2935 | |
2936 case 30: // strncpy | |
2937 { | |
2938 char *dst, *src; | |
2939 | |
2940 #if DEBUG_HLE_IOP | |
2941 printf("IOP: strncpy(%08x, %08x, %d)\n", a0, a1, a2); | |
2942 #endif | |
2943 | |
2944 dst = (char *)&psx_ram[(a0&0x1fffff)/4]; | |
2945 src = (char *)&psx_ram[(a1&0x1fffff)/4]; | |
2946 // get exact byte alignment | |
2947 dst += a0 % 4; | |
2948 src += a1 % 4; | |
2949 | |
2950 while ((*src != '\0') && (a2 > 0)) | |
2951 { | |
2952 *dst = *src; | |
2953 dst++; | |
2954 src++; | |
2955 a2--; | |
2956 } | |
2957 *dst = '\0'; | |
2958 | |
2959 // v0 = a0 | |
2960 mipsinfo.i = a0; | |
2961 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2962 } | |
2963 break; | |
2964 | |
2965 | |
2966 case 36: // strtol | |
2967 mname = (char *)&psx_ram[(a0 & 0x1fffff)/4]; | |
2968 mname += (a0 & 3); | |
2969 | |
2970 if (a1) | |
2971 { | |
2972 printf("IOP: Unhandled strtol with non-NULL second parm\n"); | |
2973 } | |
2974 | |
2975 mipsinfo.i = strtol(mname, NULL, a2); | |
2976 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
2977 break; | |
2978 | |
2979 default: | |
2980 printf("IOP: Unhandled service %d for module %s\n", callnum, name); | |
2981 break; | |
2982 } | |
2983 } | |
2984 else if (!strcmp(name, "intrman")) | |
2985 { | |
2986 switch (callnum) | |
2987 { | |
2988 case 4: // RegisterIntrHandler | |
2989 #if DEBUG_HLE_IOP | |
2990 printf("IOP: RegisterIntrHandler(%d %08x %08x %08x)\n", a0, a1, a2, a3); | |
2991 #endif | |
2992 | |
2993 if (a0 == 9) | |
2994 { | |
2995 irq9_fval = a1; | |
2996 irq9_cb = a2; | |
2997 irq9_flag = a3; | |
2998 } | |
2999 | |
3000 // DMA4? | |
3001 if (a0 == 36) | |
3002 { | |
3003 dma4_fval = a1; | |
3004 dma4_cb = a2; | |
3005 dma4_flag = a3; | |
3006 } | |
3007 | |
3008 // DMA7? | |
3009 if (a0 == 40) | |
3010 { | |
3011 dma7_fval = a1; | |
3012 dma7_cb = a2; | |
3013 dma7_flag = a3; | |
3014 } | |
3015 break; | |
3016 | |
3017 case 5: // ReleaseIntrHandler | |
3018 #if DEBUG_HLE_IOP | |
3019 printf("IOP: ReleaseIntrHandler(%d)\n", a0); | |
3020 #endif | |
3021 break; | |
3022 | |
3023 case 6: // EnableIntr | |
3024 #if DEBUG_HLE_IOP | |
3025 printf("IOP: EnableIntr(%d)\n", a0); | |
3026 #endif | |
3027 break; | |
3028 | |
3029 case 7: // DisableIntr | |
3030 #if DEBUG_HLE_IOP | |
3031 printf("IOP: DisableIntr(%d)\n", a0); | |
3032 #endif | |
3033 break; | |
3034 | |
3035 case 8: // CpuDisableIntr | |
3036 #if DEBUG_HLE_IOP | |
3037 printf("IOP: CpuDisableIntr(%d)\n", a0); | |
3038 #endif | |
3039 break; | |
3040 | |
3041 case 9: // CpuEnableIntr | |
3042 #if DEBUG_HLE_IOP | |
3043 printf("IOP: CpuEnableIntr(%d)\n", a0); | |
3044 #endif | |
3045 break; | |
3046 | |
3047 case 17: // CpuSuspendIntr | |
3048 #if DEBUG_HLE_IOP | |
3049 printf("IOP: CpuSuspendIntr\n"); | |
3050 #endif | |
3051 | |
3052 // if already suspended, return an error code | |
3053 if (intr_susp) | |
3054 { | |
3055 mipsinfo.i = -102; | |
3056 } | |
3057 else | |
3058 { | |
3059 mipsinfo.i = 0; | |
3060 } | |
3061 intr_susp = 1; | |
3062 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
3063 break; | |
3064 | |
3065 case 18: // CpuResumeIntr | |
3066 #if DEBUG_HLE_IOP | |
3067 printf("IOP: CpuResumeIntr\n"); | |
3068 #endif | |
3069 intr_susp = 0; | |
3070 mipsinfo.i = 0; | |
3071 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
3072 break; | |
3073 | |
3074 case 23: // QueryIntrContext | |
3075 #if DEBUG_HLE_IOP | |
3076 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo); | |
3077 printf("IOP: QueryIntrContext(PC=%x)\n", mipsinfo.i); | |
3078 #endif | |
3079 mipsinfo.i = 0; | |
3080 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
3081 break; | |
3082 | |
3083 default: | |
3084 printf("IOP: Unhandled service %d for module %s\n", callnum, name); | |
3085 break; | |
3086 } | |
3087 } | |
3088 else if (!strcmp(name, "loadcore")) | |
3089 { | |
3090 switch (callnum) | |
3091 { | |
3092 case 5: // FlushDcache | |
3093 #if DEBUG_HLE_IOP | |
3094 printf("IOP: FlushDcache()\n"); | |
3095 #endif | |
3096 break; | |
3097 | |
3098 case 6: // RegisterLibraryEntries | |
3099 a0 &= 0x1fffff; | |
3100 #if DEBUG_HLE_IOP | |
3101 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo); | |
3102 printf("IOP: RegisterLibraryEntries(%08x) (PC=%x)\n", a0, mipsinfo.i); | |
3103 #endif | |
3104 | |
3105 if (psx_ram[a0/4] == LE32(0x41c00000)) | |
3106 { | |
3107 a0 += 3*4; | |
3108 memcpy(®libs[iNumLibs].name, &psx_ram[a0/4], 8); | |
3109 reglibs[iNumLibs].name[8] = '\0'; | |
3110 #if DEBUG_HLE_IOP | |
3111 printf("Lib name [%s]\n", ®libs[iNumLibs].name); | |
3112 #endif | |
3113 a0 += 2*4; | |
3114 reglibs[iNumLibs].dispatch = a0; | |
3115 iNumLibs++; | |
3116 } | |
3117 else | |
3118 { | |
3119 printf("ERROR: Entry table signature missing\n"); | |
3120 | |
3121 } | |
3122 | |
3123 mipsinfo.i = 0; | |
3124 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
3125 break; | |
3126 | |
3127 default: | |
3128 printf("IOP: Unhandled service %d for module %s\n", callnum, name); | |
3129 break; | |
3130 } | |
3131 } | |
3132 else if (!strcmp(name, "sysmem")) | |
3133 { | |
3134 uint32 newAlloc; | |
3135 | |
3136 switch (callnum) | |
3137 { | |
3138 case 4: // AllocMemory | |
3139 newAlloc = psf2_get_loadaddr(); | |
3140 // make sure we're 16-byte aligned | |
3141 if (newAlloc & 15) | |
3142 { | |
3143 newAlloc &= ~15; | |
3144 newAlloc += 16; | |
3145 } | |
3146 | |
3147 if (a1 & 15) | |
3148 { | |
3149 a1 &= ~15; | |
3150 a1 += 16; | |
3151 } | |
3152 | |
3153 if (a1 == 1114112) // HACK for crappy code in Shadow Hearts rip that assumes the buffer address | |
3154 { | |
3155 printf("SH Hack: was %x now %x\n", newAlloc, 0x60000); | |
3156 newAlloc = 0x60000; | |
3157 } | |
3158 | |
3159 psf2_set_loadaddr(newAlloc + a1); | |
3160 | |
3161 #if DEBUG_HLE_IOP | |
3162 printf("IOP: AllocMemory(%d, %d, %x) = %08x\n", a0, a1, a2, newAlloc|0x80000000); | |
3163 #endif | |
3164 | |
3165 mipsinfo.i = newAlloc; // | 0x80000000; | |
3166 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
3167 break; | |
3168 | |
3169 case 5: // FreeMemory | |
3170 #if DEBUG_HLE_IOP | |
3171 printf("IOP: FreeMemory(%x)\n", a0); | |
3172 #endif | |
3173 break; | |
3174 | |
3175 case 7: // QueryMaxFreeMemSize | |
3176 #if DEBUG_HLE_IOP | |
3177 printf("IOP: QueryMaxFreeMemSize\n"); | |
3178 #endif | |
3179 | |
3180 mipsinfo.i = (2*1024*1024) - psf2_get_loadaddr(); | |
3181 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
3182 break; | |
3183 | |
3184 case 8: // QueryTotalFreeMemSize | |
3185 #if DEBUG_HLE_IOP | |
3186 printf("IOP: QueryTotalFreeMemSize\n"); | |
3187 #endif | |
3188 | |
3189 mipsinfo.i = (2*1024*1024) - psf2_get_loadaddr(); | |
3190 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
3191 break; | |
3192 | |
3193 case 14: // Kprintf | |
3194 mname = (char *)psx_ram; | |
3195 mname += a0 & 0x1fffff; | |
3196 mname += (a0 & 3); | |
3197 | |
3198 iop_sprintf(out, mname, CPUINFO_INT_REGISTER + MIPS_R5); // a1 is first parm | |
3199 | |
3200 if (out[strlen(out)-1] != '\n') | |
3201 { | |
3202 strcat(out, "\n"); | |
3203 } | |
3204 | |
3205 // filter out ESC characters | |
3206 { | |
3207 int ch; | |
3208 | |
3209 for (ch = 0; ch < strlen(out); ch++) | |
3210 { | |
3211 if (out[ch] == 27) | |
3212 { | |
3213 out[ch] = ']'; | |
3214 } | |
3215 } | |
3216 } | |
3217 | |
3218 #if DEBUG_HLE_IOP | |
3219 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo); | |
3220 printf("KTTY: %s [PC=%x]\n", out, mipsinfo.i); | |
3221 #endif | |
3222 | |
3223 #if 0 | |
3224 { | |
3225 FILE *f; | |
3226 f = fopen("psxram.bin", "wb"); | |
3227 fwrite(psx_ram, 2*1024*1024, 1, f); | |
3228 fclose(f); | |
3229 } | |
3230 #endif | |
3231 break; | |
3232 | |
3233 default: | |
3234 printf("IOP: Unhandled service %d for module %s\n", callnum, name); | |
3235 break; | |
3236 } | |
3237 } | |
3238 else if (!strcmp(name, "modload")) | |
3239 { | |
3240 uint8 *tempmem; | |
3241 uint32 newAlloc; | |
3242 | |
3243 switch (callnum) | |
3244 { | |
3245 case 7: // LoadStartModule | |
3246 mname = (char *)&psx_ram[(a0 & 0x1fffff)/4]; | |
3247 mname += 8; | |
3248 str1 = (char *)&psx_ram[(a2 & 0x1fffff)/4]; | |
3249 #if DEBUG_HLE_IOP | |
3250 printf("LoadStartModule: %s\n", mname); | |
3251 #endif | |
3252 | |
3253 // get 2k for our parameters | |
3254 newAlloc = psf2_get_loadaddr(); | |
3255 // force 16-byte alignment | |
3256 if (newAlloc & 0xf) | |
3257 { | |
3258 newAlloc &= ~0xf; | |
3259 newAlloc += 16; | |
3260 } | |
3261 psf2_set_loadaddr(newAlloc + 2048); | |
3262 | |
3263 tempmem = (uint8 *)malloc(2*1024*1024); | |
3264 if (psf2_load_file(mname, tempmem, 2*1024*1024) != 0xffffffff) | |
3265 { | |
3266 uint32 start; | |
3267 int i; | |
3268 | |
3269 start = psf2_load_elf(tempmem, 2*1024*1024); | |
3270 | |
3271 if (start != 0xffffffff) | |
3272 { | |
3273 uint32 args[20], numargs = 1, argofs; | |
3274 uint8 *argwalk = (uint8 *)psx_ram, *argbase; | |
3275 | |
3276 argwalk += (a2 & 0x1fffff); | |
3277 argbase = argwalk; | |
3278 | |
3279 args[0] = a0; // program name is argc[0] | |
3280 | |
3281 argofs = 0; | |
3282 | |
3283 if (a1 > 0) | |
3284 { | |
3285 args[numargs] = a2; | |
3286 numargs++; | |
3287 | |
3288 while (a1) | |
3289 { | |
3290 if ((*argwalk == 0) && (a1 > 1)) | |
3291 { | |
3292 args[numargs] = a2 + argofs + 1; | |
3293 numargs++; | |
3294 } | |
3295 argwalk++; | |
3296 argofs++; | |
3297 a1--; | |
3298 } | |
3299 } | |
3300 | |
3301 for (i = 0; i < numargs; i++) | |
3302 { | |
3303 #if DEBUG_HLE_IOP | |
3304 // printf("Arg %d: %08x [%s]\n", i, args[i], &argbase[args[i]-a2]); | |
3305 #endif | |
3306 psx_ram[(newAlloc/4)+i] = LE32(args[i]); | |
3307 } | |
3308 | |
3309 // set argv and argc | |
3310 mipsinfo.i = numargs; | |
3311 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R4, &mipsinfo); | |
3312 mipsinfo.i = 0x80000000 | newAlloc; | |
3313 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R5, &mipsinfo); | |
3314 | |
3315 // leave RA alone, PC = module start | |
3316 // (NOTE: we get called in the delay slot!) | |
3317 mipsinfo.i = start - 4; | |
3318 mips_set_info(CPUINFO_INT_PC, &mipsinfo); | |
3319 } | |
3320 } | |
3321 free(tempmem); | |
3322 break; | |
3323 | |
3324 default: | |
3325 printf("IOP: Unhandled service %d for module %s\n", callnum, name); | |
3326 break; | |
3327 } | |
3328 | |
3329 } | |
3330 else if (!strcmp(name, "ioman")) | |
3331 { | |
3332 switch (callnum) | |
3333 { | |
3334 case 4: // open | |
3335 { | |
3336 int i, slot2use; | |
3337 | |
3338 slot2use = -1; | |
3339 for (i = 0; i < MAX_FILE_SLOTS; i++) | |
3340 { | |
3341 if (filestat[i] == 0) | |
3342 { | |
3343 slot2use = i; | |
3344 break; | |
3345 } | |
3346 } | |
3347 | |
3348 if (slot2use == -1) | |
3349 { | |
3350 printf("IOP: out of file slots!\n"); | |
3351 mipsinfo.i = 0xffffffff; | |
3352 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
3353 return; | |
3354 } | |
3355 | |
3356 mname = (char *)psx_ram; | |
3357 mname += (a0 & 0x1fffff); | |
3358 | |
3359 if (!strncmp(mname, "aofile:", 7)) | |
3360 { | |
3361 mname += 8; | |
3362 } | |
3363 else if (!strncmp(mname, "hefile:", 7)) | |
3364 { | |
3365 mname += 8; | |
3366 } | |
3367 else if (!strncmp(mname, "host0:", 6)) | |
3368 { | |
3369 mname += 7; | |
3370 } | |
3371 | |
3372 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo); | |
3373 #if DEBUG_HLE_IOP | |
3374 printf("IOP: open(\"%s\") (PC=%08x)\n", mname, mipsinfo.i); | |
3375 #endif | |
3376 | |
3377 filedata[slot2use] = malloc(6*1024*1024); | |
3378 filesize[slot2use] = psf2_load_file(mname, filedata[slot2use], 6*1024*1024); | |
3379 filepos[slot2use] = 0; | |
3380 filestat[slot2use] = 1; | |
3381 | |
3382 if (filesize[slot2use] == 0xffffffff) | |
3383 { | |
3384 mipsinfo.i = filesize[slot2use]; | |
3385 } | |
3386 else | |
3387 { | |
3388 mipsinfo.i = slot2use; | |
3389 } | |
3390 } | |
3391 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
3392 break; | |
3393 | |
3394 case 5: // close | |
3395 #if DEBUG_HLE_IOP | |
3396 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo); | |
3397 printf("IOP: close(%d) (PC=%08x)\n", a0, mipsinfo.i); | |
3398 #endif | |
3399 free(filedata[a0]); | |
3400 filedata[a0] = (uint8 *)NULL; | |
3401 filepos[a0] = 0; | |
3402 filesize[a0] = 0; | |
3403 filestat[a0] = 0; | |
3404 break; | |
3405 | |
3406 case 6: // read | |
3407 #if DEBUG_HLE_IOP | |
3408 printf("IOP: read(%x %x %d) [pos %d size %d]\n", a0, a1, a2, filepos[a0], filesize[a0]); | |
3409 #endif | |
3410 | |
3411 if (filepos[a0] >= filesize[a0]) | |
3412 { | |
3413 mipsinfo.i = 0; | |
3414 } | |
3415 else | |
3416 { | |
3417 uint8 *rp; | |
3418 | |
3419 if ((filepos[a0] + a2) > filesize[a0]) | |
3420 { | |
3421 a2 = filesize[a0] - filepos[a0]; | |
3422 } | |
3423 | |
3424 rp = (uint8 *)psx_ram; | |
3425 rp += (a1 & 0x1fffff); | |
3426 memcpy(rp, &filedata[a0][filepos[a0]], a2); | |
3427 | |
3428 filepos[a0] += a2; | |
3429 mipsinfo.i = a2; | |
3430 } | |
3431 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
3432 break; | |
3433 | |
3434 case 8: // lseek | |
3435 #if DEBUG_HLE_IOP | |
3436 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo); | |
3437 printf("IOP: lseek(%d, %d, %s) (PC=%08x)\n", a0, a1, seek_types[a2], mipsinfo.i); | |
3438 #endif | |
3439 | |
3440 switch (a2) | |
3441 { | |
3442 case 0: // SEEK_SET | |
3443 if (a1 <= filesize[a0]) | |
3444 { | |
3445 filepos[a0] = a1; | |
3446 } | |
3447 break; | |
3448 case 1: // SEEK_CUR | |
3449 if ((a1 + filepos[a0]) < filesize[a0]) | |
3450 { | |
3451 filepos[a0] += a1; | |
3452 } | |
3453 break; | |
3454 case 2: // SEEK_END | |
3455 filepos[a0] = filesize[a0] - a1; | |
3456 break; | |
3457 } | |
3458 | |
3459 mipsinfo.i = filepos[a0]; | |
3460 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
3461 break; | |
3462 | |
3463 case 20: // AddDrv | |
3464 #if DEBUG_HLE_IOP | |
3465 printf("IOP: AddDrv(%x)\n", a0); | |
3466 #endif | |
3467 | |
3468 mipsinfo.i = 0; | |
3469 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
3470 break; | |
3471 | |
3472 case 21: // DelDrv | |
3473 #if DEBUG_HLE_IOP | |
3474 printf("IOP: DelDrv(%x)\n", a0); | |
3475 #endif | |
3476 | |
3477 mipsinfo.i = 0; | |
3478 mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo); | |
3479 break; | |
3480 | |
3481 default: | |
3482 printf("IOP: Unhandled service %d for module %s\n", callnum, name); | |
3483 } | |
3484 } | |
3485 else | |
3486 { | |
3487 int lib; | |
3488 | |
3489 if (iNumLibs > 0) | |
3490 { | |
3491 for (lib = 0; lib < iNumLibs; lib++) | |
3492 { | |
3493 if (!strcmp(name, reglibs[lib].name)) | |
3494 { | |
3495 #if DEBUG_HLE_IOP | |
3496 uint32 PC; | |
3497 | |
3498 mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo); | |
3499 PC = mipsinfo.i; | |
3500 #endif | |
3501 | |
3502 // zap the delay slot handling | |
3503 mipsinfo.i = 0; | |
3504 mips_set_info(CPUINFO_INT_REGISTER + MIPS_DELAYV, &mipsinfo); | |
3505 mips_set_info(CPUINFO_INT_REGISTER + MIPS_DELAYR, &mipsinfo); | |
3506 | |
3507 mipsinfo.i = LE32(psx_ram[(reglibs[lib].dispatch/4) + callnum]); | |
3508 | |
3509 // (NOTE: we get called in the delay slot!) | |
3510 #if DEBUG_HLE_IOP | |
3511 printf("IOP: Calling %s (%d) service %d => %08x (parms %08x %08x %08x %08x) (PC=%x)\n", | |
3512 reglibs[lib].name, | |
3513 lib, | |
3514 callnum, | |
3515 (uint32)mipsinfo.i, | |
3516 a0, a1, a2, a3, PC); | |
3517 #endif | |
3518 | |
3519 #if 0 | |
3520 if (!strcmp(reglibs[lib].name, "ssd")) | |
3521 { | |
3522 if (callnum == 37) | |
3523 { | |
3524 psxcpu_verbose = 4096; | |
3525 } | |
3526 } | |
3527 #endif | |
3528 | |
3529 mipsinfo.i -= 4; | |
3530 mips_set_info(CPUINFO_INT_PC, &mipsinfo); | |
3531 | |
3532 return; | |
3533 } | |
3534 } | |
3535 } | |
3536 | |
3537 printf("IOP: Unhandled service %d for module %s\n", callnum, name); | |
3538 } | |
3539 } | |
3540 |