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(&reglibs[iNumLibs].name, &psx_ram[a0/4], 8);
3109 reglibs[iNumLibs].name[8] = '\0';
3110 #if DEBUG_HLE_IOP
3111 printf("Lib name [%s]\n", &reglibs[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