psxbios: implement some cdrom related stuff
[pcsx_rearmed.git] / libpcsxcore / psxbios.c
... / ...
CommitLineData
1/***************************************************************************
2 * Copyright (C) 2019 Ryan Schultz, PCSX-df Team, PCSX team, gameblabla, *
3 * dmitrysmagin, senquack *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA. *
19 ***************************************************************************/
20
21/* Gameblabla 2018-2019 :
22 * Numerous changes to bios calls as well as improvements in order to conform to nocash's findings
23 * for the PSX bios calls. Thanks senquack for helping out with some of the changes
24 * and helping to spot issues and refine my patches.
25 * */
26
27/*
28 * Internal simulated HLE BIOS.
29 */
30
31// TODO: implement all system calls, count the exact CPU cycles of system calls.
32
33#include "psxbios.h"
34#include "psxhw.h"
35#include "gpu.h"
36#include "sio.h"
37#include "psxhle.h"
38#include "psxinterpreter.h"
39#include "psxevents.h"
40#include "cdrom.h"
41#include <stdarg.h>
42#include <zlib.h>
43
44#ifndef PSXBIOS_LOG
45//#define PSXBIOS_LOG printf
46#define PSXBIOS_LOG(...)
47#endif
48
49#define PTR_1 (void *)(size_t)1
50
51char *biosA0n[256] = {
52// 0x00
53 "open", "lseek", "read", "write",
54 "close", "ioctl", "exit", "sys_a0_07",
55 "getc", "putc", "todigit", "atof",
56 "strtoul", "strtol", "abs", "labs",
57// 0x10
58 "atoi", "atol", "atob", "setjmp",
59 "longjmp", "strcat", "strncat", "strcmp",
60 "strncmp", "strcpy", "strncpy", "strlen",
61 "index", "rindex", "strchr", "strrchr",
62// 0x20
63 "strpbrk", "strspn", "strcspn", "strtok",
64 "strstr", "toupper", "tolower", "bcopy",
65 "bzero", "bcmp", "memcpy", "memset",
66 "memmove", "memcmp", "memchr", "rand",
67// 0x30
68 "srand", "qsort", "strtod", "malloc",
69 "free", "lsearch", "bsearch", "calloc",
70 "realloc", "InitHeap", "_exit", "getchar",
71 "putchar", "gets", "puts", "printf",
72// 0x40
73 "SystemErrorUnresolvedException", "LoadTest", "Load", "Exec",
74 "FlushCache", "InstallInterruptHandler", "GPU_dw", "mem2vram",
75 "SendGPUStatus", "GPU_cw", "GPU_cwb", "SendPackets",
76 "sys_a0_4c", "GetGPUStatus", "GPU_sync", "sys_a0_4f",
77// 0x50
78 "sys_a0_50", "LoadExec", "GetSysSp", "sys_a0_53",
79 "_96_init()", "_bu_init()", "_96_remove()", "sys_a0_57",
80 "sys_a0_58", "sys_a0_59", "sys_a0_5a", "dev_tty_init",
81 "dev_tty_open", "sys_a0_5d", "dev_tty_ioctl","dev_cd_open",
82// 0x60
83 "dev_cd_read", "dev_cd_close", "dev_cd_firstfile", "dev_cd_nextfile",
84 "dev_cd_chdir", "dev_card_open", "dev_card_read", "dev_card_write",
85 "dev_card_close", "dev_card_firstfile", "dev_card_nextfile","dev_card_erase",
86 "dev_card_undelete","dev_card_format", "dev_card_rename", "dev_card_6f",
87// 0x70
88 "_bu_init", "CdInit", "CdRemove", "sys_a0_73",
89 "sys_a0_74", "sys_a0_75", "sys_a0_76", "sys_a0_77",
90 "_96_CdSeekL", "sys_a0_79", "sys_a0_7a", "sys_a0_7b",
91 "_96_CdGetStatus", "sys_a0_7d", "_96_CdRead", "sys_a0_7f",
92// 0x80
93 "sys_a0_80", "sys_a0_81", "sys_a0_82", "sys_a0_83",
94 "sys_a0_84", "_96_CdStop", "sys_a0_86", "sys_a0_87",
95 "sys_a0_88", "sys_a0_89", "sys_a0_8a", "sys_a0_8b",
96 "sys_a0_8c", "sys_a0_8d", "sys_a0_8e", "sys_a0_8f",
97// 0x90
98 "sys_a0_90", "sys_a0_91", "sys_a0_92", "sys_a0_93",
99 "sys_a0_94", "CdReset", "AddCDROMDevice", "AddMemCardDevide",
100 "DisableKernelIORedirection", "EnableKernelIORedirection", "sys_a0_9a", "sys_a0_9b",
101 "SetConf", "GetConf", "sys_a0_9e", "SetMem",
102// 0xa0
103 "_boot", "SystemError", "EnqueueCdIntr", "DequeueCdIntr",
104 "sys_a0_a4", "ReadSector", "get_cd_status", "bufs_cb_0",
105 "bufs_cb_1", "bufs_cb_2", "bufs_cb_3", "_card_info",
106 "_card_load", "_card_auto", "bufs_cd_4", "sys_a0_af",
107// 0xb0
108 "sys_a0_b0", "sys_a0_b1", "do_a_long_jmp", "sys_a0_b3",
109 "GetSystemInfo",
110};
111
112char *biosB0n[256] = {
113// 0x00
114 "SysMalloc", "sys_b0_01", "sys_b0_02", "sys_b0_03",
115 "sys_b0_04", "sys_b0_05", "sys_b0_06", "DeliverEvent",
116 "OpenEvent", "CloseEvent", "WaitEvent", "TestEvent",
117 "EnableEvent", "DisableEvent", "OpenTh", "CloseTh",
118// 0x10
119 "ChangeTh", "sys_b0_11", "InitPAD", "StartPAD",
120 "StopPAD", "PAD_init", "PAD_dr", "ReturnFromExecption",
121 "ResetEntryInt", "HookEntryInt", "sys_b0_1a", "sys_b0_1b",
122 "sys_b0_1c", "sys_b0_1d", "sys_b0_1e", "sys_b0_1f",
123// 0x20
124 "UnDeliverEvent", "sys_b0_21", "sys_b0_22", "sys_b0_23",
125 "sys_b0_24", "sys_b0_25", "sys_b0_26", "sys_b0_27",
126 "sys_b0_28", "sys_b0_29", "sys_b0_2a", "sys_b0_2b",
127 "sys_b0_2c", "sys_b0_2d", "sys_b0_2e", "sys_b0_2f",
128// 0x30
129 "sys_b0_30", "sys_b0_31", "open", "lseek",
130 "read", "write", "close", "ioctl",
131 "exit", "sys_b0_39", "getc", "putc",
132 "getchar", "putchar", "gets", "puts",
133// 0x40
134 "cd", "format", "firstfile", "nextfile",
135 "rename", "delete", "undelete", "AddDevice",
136 "RemoteDevice", "PrintInstalledDevices", "InitCARD", "StartCARD",
137 "StopCARD", "sys_b0_4d", "_card_write", "_card_read",
138// 0x50
139 "_new_card", "Krom2RawAdd", "sys_b0_52", "sys_b0_53",
140 "_get_errno", "_get_error", "GetC0Table", "GetB0Table",
141 "_card_chan", "sys_b0_59", "sys_b0_5a", "ChangeClearPAD",
142 "_card_status", "_card_wait",
143};
144
145char *biosC0n[256] = {
146// 0x00
147 "InitRCnt", "InitException", "SysEnqIntRP", "SysDeqIntRP",
148 "get_free_EvCB_slot", "get_free_TCB_slot", "ExceptionHandler", "InstallExeptionHandler",
149 "SysInitMemory", "SysInitKMem", "ChangeClearRCnt", "SystemError",
150 "InitDefInt", "sys_c0_0d", "sys_c0_0e", "sys_c0_0f",
151// 0x10
152 "sys_c0_10", "sys_c0_11", "InstallDevices", "FlushStfInOutPut",
153 "sys_c0_14", "_cdevinput", "_cdevscan", "_circgetc",
154 "_circputc", "ioabort", "sys_c0_1a", "KernelRedirect",
155 "PatchAOTable",
156};
157
158//#define r0 (psxRegs.GPR.n.r0)
159#define at (psxRegs.GPR.n.at)
160#define v0 (psxRegs.GPR.n.v0)
161#define v1 (psxRegs.GPR.n.v1)
162#define a0 (psxRegs.GPR.n.a0)
163#define a1 (psxRegs.GPR.n.a1)
164#define a2 (psxRegs.GPR.n.a2)
165#define a3 (psxRegs.GPR.n.a3)
166#define t0 (psxRegs.GPR.n.t0)
167#define t1 (psxRegs.GPR.n.t1)
168#define t2 (psxRegs.GPR.n.t2)
169#define t3 (psxRegs.GPR.n.t3)
170#define t4 (psxRegs.GPR.n.t4)
171#define t5 (psxRegs.GPR.n.t5)
172#define t6 (psxRegs.GPR.n.t6)
173#define t7 (psxRegs.GPR.n.t7)
174#define t8 (psxRegs.GPR.n.t8)
175#define t9 (psxRegs.GPR.n.t9)
176#define s0 (psxRegs.GPR.n.s0)
177#define s1 (psxRegs.GPR.n.s1)
178#define s2 (psxRegs.GPR.n.s2)
179#define s3 (psxRegs.GPR.n.s3)
180#define s4 (psxRegs.GPR.n.s4)
181#define s5 (psxRegs.GPR.n.s5)
182#define s6 (psxRegs.GPR.n.s6)
183#define s7 (psxRegs.GPR.n.s7)
184#define k0 (psxRegs.GPR.n.k0)
185#define k1 (psxRegs.GPR.n.k1)
186#define gp (psxRegs.GPR.n.gp)
187#define sp (psxRegs.GPR.n.sp)
188#define fp (psxRegs.GPR.n.fp)
189#define ra (psxRegs.GPR.n.ra)
190#define pc0 (psxRegs.pc)
191
192#define Ra0 ((char *)PSXM(a0))
193#define Ra1 ((char *)PSXM(a1))
194#define Ra2 ((char *)PSXM(a2))
195#define Ra3 ((char *)PSXM(a3))
196#define Rv0 ((char *)PSXM(v0))
197#define Rsp ((char *)PSXM(sp))
198
199typedef struct {
200 u32 class;
201 u32 status;
202 u32 spec;
203 u32 mode;
204 u32 fhandler;
205 u32 unused[2];
206} EvCB;
207
208#define EvStUNUSED 0x0000
209#define EvStDISABLED 0x1000
210#define EvStACTIVE 0x2000
211#define EvStALREADY 0x4000
212
213#define EvMdCALL 0x1000
214#define EvMdMARK 0x2000
215
216typedef struct {
217 u32 status;
218 u32 mode;
219 u32 reg[32];
220 u32 epc;
221 u32 hi, lo;
222 u32 sr, cause;
223 u32 unused[9];
224} TCB;
225
226typedef struct {
227 u32 _pc0;
228 u32 gp0;
229 u32 t_addr;
230 u32 t_size;
231 u32 d_addr; // 10
232 u32 d_size;
233 u32 b_addr;
234 u32 b_size; // 1c
235 u32 S_addr;
236 u32 s_size;
237 u32 _sp, _fp, _gp, ret, base;
238} EXEC;
239
240struct DIRENTRY {
241 char name[20];
242 s32 attr;
243 s32 size;
244 u32 next;
245 s32 head;
246 char system[4];
247};
248
249typedef struct {
250 char name[32];
251 u32 mode;
252 u32 offset;
253 u32 size;
254 u32 mcfile;
255} FileDesc;
256
257// todo: FileDesc layout is wrong
258// todo: get rid of these globals
259static FileDesc FDesc[32];
260static char ffile[64];
261static int nfile;
262static char cdir[8*8+8];
263static u32 floodchk;
264
265// fixed RAM offsets, SCPH1001 compatible
266#define A_TT_ExCB 0x0100
267#define A_TT_PCB 0x0108
268#define A_TT_TCB 0x0110
269#define A_TT_EvCB 0x0120
270#define A_A0_TABLE 0x0200
271#define A_B0_TABLE 0x0874
272#define A_C0_TABLE 0x0674
273#define A_SYSCALL 0x0650
274#define A_EXCEPTION 0x0c80
275#define A_EXC_SP 0x6cf0
276#define A_EEXIT_DEF 0x6cf4
277#define A_KMALLOC_PTR 0x7460
278#define A_KMALLOC_SIZE 0x7464
279#define A_KMALLOC_END 0x7468
280#define A_PADCRD_CHN_E 0x74a8 // pad/card irq chain entry, see hleExcPadCard1()
281#define A_PAD_IRQR_ENA 0x74b8 // pad read on vint irq (nocash 'pad_enable_flag')
282#define A_CARD_IRQR_ENA 0x74bc // same for card
283#define A_PAD_INBUF 0x74c8 // 2x buffers for rx pad data
284#define A_PAD_OUTBUF 0x74d0 // 2x buffers for tx pad data
285#define A_PAD_IN_LEN 0x74d8
286#define A_PAD_OUT_LEN 0x74e0
287#define A_PAD_DR_DST 0x74c4
288#define A_CARD_CHAN1 0x7500
289#define A_PAD_DR_BUF1 0x7570
290#define A_PAD_DR_BUF2 0x7598
291#define A_EEXIT_PTR 0x75d0
292#define A_EXC_STACK 0x85d8 // exception stack top
293#define A_RCNT_VBL_ACK 0x8600
294#define A_PAD_ACK_VBL 0x8914 // enable vint ack by pad reading code
295#define A_HEAP_BASE 0x9000
296#define A_HEAP_SIZE 0x9004
297#define A_HEAP_END 0x9008
298#define A_HEAP_INIT_FLG 0x900c
299#define A_RND_SEED 0x9010
300#define A_HEAP_FRSTCHNK 0xb060
301#define A_HEAP_CURCHNK 0xb064
302#define A_CONF_TCB 0xb940
303#define A_CONF_EvCB 0xb944
304#define A_CONF_SP 0xb948
305#define A_CD_EVENTS 0xb9b8
306#define A_EXC_GP 0xf450
307
308#define A_A0_TRAPS 0x1010
309#define A_B0_TRAPS 0x2010
310#define A_C0_TRAPS 0x3010
311#define A_B0_5B_TRAP 0x43d0
312
313#define HLEOP(n) SWAPu32((0x3b << 26) | (n));
314
315static u8 loadRam8(u32 addr)
316{
317 assert(!(addr & 0x5f800000));
318 return psxM[addr & 0x1fffff];
319}
320
321static u32 loadRam32(u32 addr)
322{
323 assert(!(addr & 0x5f800000));
324 return SWAP32(*((u32 *)psxM + ((addr & 0x1fffff) >> 2)));
325}
326
327static void *castRam8ptr(u32 addr)
328{
329 assert(!(addr & 0x5f800000));
330 return psxM + (addr & 0x1fffff);
331}
332
333static void *castRam32ptr(u32 addr)
334{
335 assert(!(addr & 0x5f800003));
336 return psxM + (addr & 0x1ffffc);
337}
338
339static void *loadRam8ptr(u32 addr)
340{
341 return castRam8ptr(loadRam32(addr));
342}
343
344static void *loadRam32ptr(u32 addr)
345{
346 return castRam32ptr(loadRam32(addr));
347}
348
349static void storeRam8(u32 addr, u8 d)
350{
351 assert(!(addr & 0x5f800000));
352 *((u8 *)psxM + (addr & 0x1fffff)) = d;
353}
354
355static void storeRam32(u32 addr, u32 d)
356{
357 assert(!(addr & 0x5f800000));
358 *((u32 *)psxM + ((addr & 0x1fffff) >> 2)) = SWAP32(d);
359}
360
361static void mips_return(u32 val)
362{
363 v0 = val;
364 pc0 = ra;
365}
366
367static void mips_return_void(void)
368{
369 pc0 = ra;
370}
371
372static void use_cycles(u32 cycle)
373{
374 psxRegs.cycle += cycle * 2;
375}
376
377static void mips_return_c(u32 val, u32 cycle)
378{
379 use_cycles(cycle);
380 mips_return(val);
381}
382
383static void mips_return_void_c(u32 cycle)
384{
385 use_cycles(cycle);
386 pc0 = ra;
387}
388
389static int returned_from_exception(void)
390{
391 // 0x80000080 means it took another exception just after return
392 return pc0 == k0 || pc0 == 0x80000080;
393}
394
395static inline void softCall(u32 pc) {
396 u32 sra = ra;
397 u32 ssr = psxRegs.CP0.n.SR;
398 u32 lim = 0;
399 pc0 = pc;
400 ra = 0x80001000;
401 psxRegs.CP0.n.SR &= ~0x404; // disable interrupts
402
403 assert(psxRegs.cpuInRecursion <= 1);
404 psxRegs.cpuInRecursion++;
405 psxCpu->Notify(R3000ACPU_NOTIFY_AFTER_LOAD, PTR_1);
406
407 while (pc0 != 0x80001000 && ++lim < 0x100000)
408 psxCpu->ExecuteBlock(EXEC_CALLER_HLE);
409
410 psxCpu->Notify(R3000ACPU_NOTIFY_BEFORE_SAVE, PTR_1);
411 psxRegs.cpuInRecursion--;
412
413 if (lim == 0x100000)
414 PSXBIOS_LOG("softCall @%x hit lim\n", pc);
415 ra = sra;
416 psxRegs.CP0.n.SR |= ssr & 0x404;
417}
418
419static inline void softCallInException(u32 pc) {
420 u32 sra = ra;
421 u32 lim = 0;
422 pc0 = pc;
423
424 assert(ra != 0x80001000);
425 if (ra == 0x80001000)
426 return;
427 ra = 0x80001000;
428
429 psxRegs.cpuInRecursion++;
430 psxCpu->Notify(R3000ACPU_NOTIFY_AFTER_LOAD, PTR_1);
431
432 while (!returned_from_exception() && pc0 != 0x80001000 && ++lim < 0x100000)
433 psxCpu->ExecuteBlock(EXEC_CALLER_HLE);
434
435 psxCpu->Notify(R3000ACPU_NOTIFY_BEFORE_SAVE, PTR_1);
436 psxRegs.cpuInRecursion--;
437
438 if (lim == 0x100000)
439 PSXBIOS_LOG("softCallInException @%x hit lim\n", pc);
440 if (pc0 == 0x80001000)
441 ra = sra;
442}
443
444static u32 OpenEvent(u32 class, u32 spec, u32 mode, u32 func);
445static void EnableEvent(u32 ev, int do_log);
446static u32 DeliverEvent(u32 class, u32 spec);
447static u32 UnDeliverEvent(u32 class, u32 spec);
448static void CloseEvent(u32 ev);
449
450/* *
451// *
452// *
453// System calls A0 */
454
455
456#define buread(Ra1, mcd, length) { \
457 PSXBIOS_LOG("read %d: %x,%x (%s)\n", FDesc[1 + mcd].mcfile, FDesc[1 + mcd].offset, a2, Mcd##mcd##Data + 128 * FDesc[1 + mcd].mcfile + 0xa); \
458 ptr = Mcd##mcd##Data + 8192 * FDesc[1 + mcd].mcfile + FDesc[1 + mcd].offset; \
459 memcpy(Ra1, ptr, length); \
460 psxCpu->Clear(a1, (length + 3) / 4); \
461 if (FDesc[1 + mcd].mode & 0x8000) { \
462 DeliverEvent(0xf0000011, 0x0004); \
463 DeliverEvent(0xf4000001, 0x0004); \
464 v0 = 0; } \
465 else v0 = length; \
466 FDesc[1 + mcd].offset += v0; \
467}
468
469#define buwrite(Ra1, mcd, length) { \
470 u32 offset = + 8192 * FDesc[1 + mcd].mcfile + FDesc[1 + mcd].offset; \
471 PSXBIOS_LOG("write %d: %x,%x\n", FDesc[1 + mcd].mcfile, FDesc[1 + mcd].offset, a2); \
472 ptr = Mcd##mcd##Data + offset; \
473 memcpy(ptr, Ra1, length); \
474 FDesc[1 + mcd].offset += length; \
475 SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, offset, length); \
476 if (FDesc[1 + mcd].mode & 0x8000) { \
477 DeliverEvent(0xf0000011, 0x0004); \
478 DeliverEvent(0xf4000001, 0x0004); \
479 v0 = 0; } \
480 else v0 = length; \
481}
482
483/* Internally redirects to "FileRead(fd,tempbuf,1)".*/
484/* For some strange reason, the returned character is sign-expanded; */
485/* So if a return value of FFFFFFFFh could mean either character FFh, or error. */
486/* TODO FIX ME : Properly implement this behaviour */
487void psxBios_getc(void) // 0x03, 0x35
488{
489 char *ptr;
490 void *pa1 = Ra1;
491#ifdef PSXBIOS_LOG
492 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x03]);
493#endif
494 v0 = -1;
495
496 if (pa1 != INVALID_PTR) {
497 switch (a0) {
498 case 2: buread(pa1, 1, 1); break;
499 case 3: buread(pa1, 2, 1); break;
500 }
501 }
502
503 pc0 = ra;
504}
505
506/* Copy of psxBios_write, except size is 1. */
507void psxBios_putc(void) // 0x09, 0x3B
508{
509 char *ptr;
510 void *pa1 = Ra1;
511#ifdef PSXBIOS_LOG
512 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x09]);
513#endif
514 v0 = -1;
515 if (pa1 == INVALID_PTR) {
516 pc0 = ra;
517 return;
518 }
519
520 if (a0 == 1) { // stdout
521 char *ptr = (char *)pa1;
522
523 v0 = a2;
524 while (a2 > 0) {
525 printf("%c", *ptr++); a2--;
526 }
527 pc0 = ra; return;
528 }
529
530 switch (a0) {
531 case 2: buwrite(pa1, 1, 1); break;
532 case 3: buwrite(pa1, 2, 1); break;
533 }
534
535 pc0 = ra;
536}
537
538static u32 do_todigit(u32 c)
539{
540 c &= 0xFF;
541 if (c >= 0x30 && c < 0x3A) {
542 c -= 0x30;
543 }
544 else if (c > 0x60 && c < 0x7B) {
545 c -= 0x20;
546 }
547 else if (c > 0x40 && c < 0x5B) {
548 c = c - 0x41 + 10;
549 }
550 else if (c >= 0x80) {
551 log_unhandled("todigit %02x\n", c);
552 c = -1;
553 }
554 else
555 {
556 c = 0x0098967F;
557 }
558 use_cycles(40);
559 return c;
560}
561
562static void psxBios_todigit(void) // 0x0a
563{
564 mips_return(do_todigit(a0));
565 PSXBIOS_LOG("psxBios_%s '%c' -> %u\n", biosA0n[0x0a], a0, v0);
566}
567
568static void do_strtol(char *p, void *end_, u32 base, int can_neg) {
569 s32 n = 0, f = 0, t;
570 u32 *end = end_;
571
572 use_cycles(12);
573 if (p == INVALID_PTR) {
574 mips_return(0);
575 return;
576 }
577
578 for (; (0x09 <= *p && *p <= '\r') || *p == ' '; p++)
579 use_cycles(9);
580 if (can_neg) {
581 for (; *p == '-'; f = 1, p++)
582 use_cycles(4);
583 }
584 if (base == 0 || base > 36)
585 base = 10;
586 if (*p == '0') {
587 switch (*p++) {
588 case 'b': case 'B': base = 2; break;
589 case 'x': case 'X': base = 16; break;
590 }
591 }
592 else if (*p == 'o' || *p == 'O') {
593 base = 8;
594 p++;
595 }
596
597 for (; (t = do_todigit(*p)) < base; p++) {
598 n = n * base + t;
599 use_cycles(12);
600 }
601
602 n = (f ? -n : n);
603 if (end != INVALID_PTR)
604 *end = SWAP32(a0 + (p - Ra0));
605 mips_return_c(n, 100);
606}
607
608static void psxBios_strtoul() { // 0x0c
609 do_strtol(a0 ? Ra0 : INVALID_PTR, a1 ? Ra1 : INVALID_PTR, a2, 0);
610 PSXBIOS_LOG("psxBios_%s %s (%x), %x, %x -> 0x%x\n",
611 biosA0n[0x0c], a0 ? Ra0 : NULL, a0, a1, a2, v0);
612}
613
614static void psxBios_strtol() { // 0x0d
615 do_strtol(a0 ? Ra0 : INVALID_PTR, a1 ? Ra1 : INVALID_PTR, a2, 1);
616 PSXBIOS_LOG("psxBios_%s %s (%x), %x, %x -> 0x%x\n",
617 biosA0n[0x0d], a0 ? Ra0 : NULL, a0, a1, a2, v0);
618}
619
620void psxBios_abs() { // 0x0e
621 if ((s32)a0 < 0) v0 = -(s32)a0;
622 else v0 = a0;
623 pc0 = ra;
624}
625
626void psxBios_labs() { // 0x0f
627 psxBios_abs();
628}
629
630void psxBios_atoi() { // 0x10
631 s32 n = 0, f = 0;
632 char *p = (char *)Ra0;
633
634 if (p == INVALID_PTR) {
635 mips_return(0);
636 return;
637 }
638
639 for (;;p++) {
640 switch (*p) {
641 case ' ': case '\t': continue;
642 case '-': f++;
643 case '+': p++;
644 }
645 break;
646 }
647
648 while (*p >= '0' && *p <= '9') {
649 n = n * 10 + *p++ - '0';
650 }
651
652 v0 = (f ? -n : n);
653 pc0 = ra;
654 PSXBIOS_LOG("psxBios_%s %s (%x) -> 0x%x\n", biosA0n[0x10], Ra0, a0, v0);
655}
656
657void psxBios_atol() { // 0x11
658 psxBios_atoi();
659}
660
661struct jmp_buf_ {
662 u32 ra_, sp_, fp_;
663 u32 s[8];
664 u32 gp_;
665};
666
667static void psxBios_setjmp() { // 0x13
668 struct jmp_buf_ *jmp_buf = castRam32ptr(a0);
669 int i;
670
671 PSXBIOS_LOG("psxBios_%s %x\n", biosA0n[0x13], a0);
672
673 jmp_buf->ra_ = SWAP32(ra);
674 jmp_buf->sp_ = SWAP32(sp);
675 jmp_buf->fp_ = SWAP32(fp);
676 for (i = 0; i < 8; i++) // s0-s7
677 jmp_buf->s[i] = SWAP32(psxRegs.GPR.r[16 + i]);
678 jmp_buf->gp_ = SWAP32(gp);
679
680 mips_return_c(0, 15);
681}
682
683static void longjmp_load(const struct jmp_buf_ *jmp_buf)
684{
685 int i;
686
687 ra = SWAP32(jmp_buf->ra_);
688 sp = SWAP32(jmp_buf->sp_);
689 fp = SWAP32(jmp_buf->fp_);
690 for (i = 0; i < 8; i++) // s0-s7
691 psxRegs.GPR.r[16 + i] = SWAP32(jmp_buf->s[i]);
692 gp = SWAP32(jmp_buf->gp_);;
693}
694
695void psxBios_longjmp() { // 0x14
696 struct jmp_buf_ *jmp_buf = castRam32ptr(a0);
697
698 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x14]);
699 longjmp_load(jmp_buf);
700 mips_return_c(a1, 15);
701}
702
703void psxBios_strcat() { // 0x15
704 u8 *p2 = (u8 *)Ra1;
705 u32 p1 = a0;
706
707 PSXBIOS_LOG("psxBios_%s %s (%x), %s (%x)\n", biosA0n[0x15], Ra0, a0, Ra1, a1);
708 if (a0 == 0 || a1 == 0 || p2 == INVALID_PTR)
709 {
710 mips_return_c(0, 6);
711 return;
712 }
713 while (loadRam8(p1)) {
714 use_cycles(4);
715 p1++;
716 }
717 for (; *p2; p1++, p2++)
718 storeRam8(p1, *p2);
719 storeRam8(p1, 0);
720
721 mips_return_c(a0, 22);
722}
723
724void psxBios_strncat() { // 0x16
725 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
726 s32 n = a2;
727
728#ifdef PSXBIOS_LOG
729 PSXBIOS_LOG("psxBios_%s: %s (%x), %s (%x), %d\n", biosA0n[0x16], Ra0, a0, Ra1, a1, a2);
730#endif
731 if (a0 == 0 || a1 == 0)
732 {
733 v0 = 0;
734 pc0 = ra;
735 return;
736 }
737 while (*p1++);
738 --p1;
739 while ((*p1++ = *p2++) != '\0') {
740 if (--n < 0) {
741 *--p1 = '\0';
742 break;
743 }
744 }
745
746 v0 = a0; pc0 = ra;
747}
748
749void psxBios_strcmp() { // 0x17
750 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
751 s32 n=0;
752 if (a0 == 0 && a1 == 0)
753 {
754 v0 = 0;
755 pc0 = ra;
756 return;
757 }
758 else if (a0 == 0 && a1 != 0)
759 {
760 v0 = -1;
761 pc0 = ra;
762 return;
763 }
764 else if (a0 != 0 && a1 == 0)
765 {
766 v0 = 1;
767 pc0 = ra;
768 return;
769 }
770#ifdef PSXBIOS_LOG
771 PSXBIOS_LOG("psxBios_%s: %s (%x), %s (%x)\n", biosA0n[0x17], Ra0, a0, Ra1, a1);
772#endif
773
774 while (*p1 == *p2++) {
775 n++;
776 if (*p1++ == '\0') {
777 v1=n-1;
778 a0+=n;
779 a1+=n;
780 v0 = 0;
781 pc0 = ra;
782 return;
783 }
784 }
785
786 v0 = (*p1 - *--p2);
787 v1 = n;
788 a0+=n;
789 a1+=n;
790 pc0 = ra;
791}
792
793void psxBios_strncmp() { // 0x18
794 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
795 s32 n = a2;
796 if (a0 == 0 && a1 == 0)
797 {
798 v0 = 0;
799 pc0 = ra;
800 return;
801 }
802 else if (a0 == 0 && a1 != 0)
803 {
804 v0 = -1;
805 pc0 = ra;
806 return;
807 }
808 else if (a0 != 0 && a1 == 0)
809 {
810 v0 = 1;
811 pc0 = ra;
812 return;
813 }
814#ifdef PSXBIOS_LOG
815 PSXBIOS_LOG("psxBios_%s: %s (%x), %s (%x), %d\n", biosA0n[0x18], Ra0, a0, Ra1, a1, a2);
816#endif
817
818 while (--n >= 0 && *p1 == *p2++) {
819 if (*p1++ == '\0') {
820 v0 = 0;
821 pc0 = ra;
822 v1 = a2 - ((a2-n) - 1);
823 a0 += (a2-n) - 1;
824 a1 += (a2-n) - 1;
825 a2 = n;
826 return;
827 }
828 }
829
830 v0 = (n < 0 ? 0 : *p1 - *--p2);
831 pc0 = ra;
832 v1 = a2 - ((a2-n) - 1);
833 a0 += (a2-n) - 1;
834 a1 += (a2-n) - 1;
835 a2 = n;
836}
837
838void psxBios_strcpy() { // 0x19
839 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
840 PSXBIOS_LOG("psxBios_%s %x, %s (%x)\n", biosA0n[0x19], a0, p2, a1);
841 if (a0 == 0 || a1 == 0)
842 {
843 v0 = 0;
844 pc0 = ra;
845 return;
846 }
847 while ((*p1++ = *p2++) != '\0');
848
849 v0 = a0; pc0 = ra;
850}
851
852void psxBios_strncpy() { // 0x1a
853 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
854 s32 n = a2, i;
855 if (a0 == 0 || a1 == 0)
856 {
857 v0 = 0;
858 pc0 = ra;
859 return;
860 }
861 for (i = 0; i < n; i++) {
862 if ((*p1++ = *p2++) == '\0') {
863 while (++i < n) {
864 *p1++ = '\0';
865 }
866 v0 = a0; pc0 = ra;
867 return;
868 }
869 }
870
871 v0 = a0; pc0 = ra;
872}
873
874void psxBios_strlen() { // 0x1b
875 char *p = (char *)Ra0;
876 v0 = 0;
877 if (a0 == 0)
878 {
879 pc0 = ra;
880 return;
881 }
882 while (*p++) v0++;
883 pc0 = ra;
884}
885
886void psxBios_index() { // 0x1c
887 char *p = (char *)Ra0;
888 if (a0 == 0)
889 {
890 v0 = 0;
891 pc0 = ra;
892 return;
893 }
894
895 do {
896 if (*p == a1) {
897 v0 = a0 + (p - (char *)Ra0);
898 pc0 = ra;
899 return;
900 }
901 } while (*p++ != '\0');
902
903 v0 = 0; pc0 = ra;
904}
905
906void psxBios_rindex() { // 0x1d
907 char *p = (char *)Ra0;
908
909 v0 = 0;
910 if (a0 == 0)
911 {
912 pc0 = ra;
913 return;
914 }
915 do {
916 if (*p == a1)
917 v0 = a0 + (p - (char *)Ra0);
918 } while (*p++ != '\0');
919
920 pc0 = ra;
921}
922
923void psxBios_strchr() { // 0x1e
924 psxBios_index();
925}
926
927void psxBios_strrchr() { // 0x1f
928 psxBios_rindex();
929}
930
931void psxBios_strpbrk() { // 0x20
932 char *p1 = (char *)Ra0, *p2 = (char *)Ra1, *scanp, c, sc;
933
934 while ((c = *p1++) != '\0') {
935 for (scanp = p2; (sc = *scanp++) != '\0';) {
936 if (sc == c) {
937 v0 = a0 + (p1 - 1 - (char *)Ra0);
938 pc0 = ra;
939 return;
940 }
941 }
942 }
943
944 // BUG: return a0 instead of NULL if not found
945 v0 = a0; pc0 = ra;
946}
947
948void psxBios_strspn() { // 0x21
949 char *p1, *p2;
950
951 for (p1 = (char *)Ra0; *p1 != '\0'; p1++) {
952 for (p2 = (char *)Ra1; *p2 != '\0' && *p2 != *p1; p2++);
953 if (*p2 == '\0') break;
954 }
955
956 v0 = p1 - (char *)Ra0; pc0 = ra;
957}
958
959void psxBios_strcspn() { // 0x22
960 char *p1, *p2;
961
962 for (p1 = (char *)Ra0; *p1 != '\0'; p1++) {
963 for (p2 = (char *)Ra1; *p2 != '\0' && *p2 != *p1; p2++);
964 if (*p2 != '\0') break;
965 }
966
967 v0 = p1 - (char *)Ra0; pc0 = ra;
968}
969
970void psxBios_strtok() { // 0x23
971 char *pcA0 = (char *)Ra0;
972 char *pcRet = strtok(pcA0, (char *)Ra1);
973 if (pcRet)
974 v0 = a0 + pcRet - pcA0;
975 else
976 v0 = 0;
977 pc0 = ra;
978}
979
980void psxBios_strstr() { // 0x24
981 char *p = (char *)Ra0, *p1, *p2;
982 PSXBIOS_LOG("psxBios_%s %s (%x), %s (%x)\n", biosA0n[0x24], p, a0, Ra1, a1);
983
984 while (*p != '\0') {
985 p1 = p;
986 p2 = (char *)Ra1;
987
988 while (*p1 != '\0' && *p2 != '\0' && *p1 == *p2) {
989 p1++; p2++;
990 }
991
992 if (*p2 == '\0') {
993 v0 = a0 + (p - (char *)Ra0);
994 pc0 = ra;
995 PSXBIOS_LOG(" -> %x\n", v0);
996 return;
997 }
998
999 // bug: skips the whole matched substring + 1
1000 p = p1 + 1;
1001 }
1002
1003 v0 = 0; pc0 = ra;
1004}
1005
1006void psxBios_toupper() { // 0x25
1007 v0 = (s8)(a0 & 0xff);
1008 if (v0 >= 'a' && v0 <= 'z') v0 -= 'a' - 'A';
1009 pc0 = ra;
1010}
1011
1012void psxBios_tolower() { // 0x26
1013 v0 = (s8)(a0 & 0xff);
1014 if (v0 >= 'A' && v0 <= 'Z') v0 += 'a' - 'A';
1015 pc0 = ra;
1016}
1017
1018static void do_memset(u32 dst, u32 v, s32 len)
1019{
1020 u32 d = dst;
1021 s32 l = len;
1022 while (l-- > 0) {
1023 u8 *db = PSXM(d);
1024 if (db != INVALID_PTR)
1025 *db = v;
1026 d++;
1027 }
1028 psxCpu->Clear(dst, (len + 3) / 4);
1029}
1030
1031static void do_memcpy(u32 dst, u32 src, s32 len)
1032{
1033 u32 d = dst, s = src;
1034 s32 l = len;
1035 while (l-- > 0) {
1036 const u8 *sb = PSXM(s);
1037 u8 *db = PSXM(d);
1038 if (db != INVALID_PTR && sb != INVALID_PTR)
1039 *db = *sb;
1040 d++;
1041 s++;
1042 }
1043 psxCpu->Clear(dst, (len + 3) / 4);
1044}
1045
1046static void psxBios_memcpy();
1047
1048static void psxBios_bcopy() { // 0x27 - memcpy with args swapped
1049 //PSXBIOS_LOG("psxBios_%s %x %x %x\n", biosA0n[0x27], a0, a1, a2);
1050 u32 ret = a0, cycles = 0;
1051 if (a0 == 0) // ...but it checks src this time
1052 {
1053 mips_return_c(0, 4);
1054 return;
1055 }
1056 v1 = a0;
1057 if ((s32)a2 > 0) {
1058 do_memcpy(a1, a0, a2);
1059 cycles = a2 * 6;
1060 a0 += a2;
1061 a1 += a2;
1062 a2 = 0;
1063 }
1064 mips_return_c(ret, cycles + 5);
1065}
1066
1067static void psxBios_bzero() { // 0x28
1068 /* Same as memset here (See memset below) */
1069 u32 ret = a0, cycles;
1070 if (a0 == 0 || (s32)a1 <= 0)
1071 {
1072 mips_return_c(0, 6);
1073 return;
1074 }
1075 do_memset(a0, 0, a1);
1076 cycles = a1 * 4;
1077 a0 += a1;
1078 a1 = 0;
1079 // todo: many more cycles due to uncached bios mem
1080 mips_return_c(ret, cycles + 5);
1081}
1082
1083void psxBios_bcmp() { // 0x29
1084 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
1085
1086 if (a0 == 0 || a1 == 0) { v0 = 0; pc0 = ra; return; }
1087
1088 while ((s32)a2-- > 0) {
1089 if (*p1++ != *p2++) {
1090 v0 = *p1 - *p2; // BUG: compare the NEXT byte
1091 pc0 = ra;
1092 return;
1093 }
1094 }
1095
1096 v0 = 0; pc0 = ra;
1097}
1098
1099static void psxBios_memcpy() { // 0x2a
1100 u32 ret = a0, cycles = 0;
1101 if (a0 == 0)
1102 {
1103 mips_return_c(0, 4);
1104 return;
1105 }
1106 v1 = a0;
1107 if ((s32)a2 > 0) {
1108 do_memcpy(a0, a1, a2);
1109 cycles = a2 * 6;
1110 a0 += a2;
1111 a1 += a2;
1112 a2 = 0;
1113 }
1114 mips_return_c(ret, cycles + 5);
1115}
1116
1117static void psxBios_memset() { // 0x2b
1118 u32 ret = a0, cycles;
1119 if (a0 == 0 || (s32)a2 <= 0)
1120 {
1121 mips_return_c(0, 6);
1122 return;
1123 }
1124 do_memset(a0, a1, a2);
1125 cycles = a2 * 4;
1126 a0 += a2;
1127 a2 = 0;
1128 // todo: many more cycles due to uncached bios mem
1129 mips_return_c(ret, cycles + 5);
1130}
1131
1132void psxBios_memmove() { // 0x2c
1133 u32 ret = a0, cycles = 0;
1134 if (a0 == 0)
1135 {
1136 mips_return_c(0, 4);
1137 return;
1138 }
1139 v1 = a0;
1140 if ((s32)a2 > 0 && a0 > a1 && a0 < a1 + a2) {
1141 u32 dst = a0, len = a2 + 1;
1142 a0 += a2;
1143 a1 += a2;
1144 while ((s32)a2 >= 0) { // BUG: copies one more byte here
1145 const u8 *sb = PSXM(a1);
1146 u8 *db = PSXM(a0);
1147 if (db != INVALID_PTR && sb != INVALID_PTR)
1148 *db = *sb;
1149 a0--;
1150 a1--;
1151 a2--;
1152 }
1153 psxCpu->Clear(dst, (len + 3) / 4);
1154 cycles = 10 + len * 8;
1155 } else if ((s32)a2 > 0) {
1156 do_memcpy(a0, a1, a2);
1157 cycles = a2 * 6;
1158 a0 += a2;
1159 a1 += a2;
1160 a2 = 0;
1161 }
1162 mips_return_c(ret, cycles + 5);
1163}
1164
1165void psxBios_memcmp() { // 0x2d
1166 psxBios_bcmp();
1167}
1168
1169void psxBios_memchr() { // 0x2e
1170 char *p = (char *)Ra0;
1171
1172 if (a0 == 0 || a2 > 0x7FFFFFFF)
1173 {
1174 pc0 = ra;
1175 return;
1176 }
1177
1178 while ((s32)a2-- > 0) {
1179 if (*p++ != (s8)a1) continue;
1180 v0 = a0 + (p - (char *)Ra0 - 1);
1181 pc0 = ra;
1182 return;
1183 }
1184
1185 v0 = 0; pc0 = ra;
1186}
1187
1188static void psxBios_rand() { // 0x2f
1189 u32 s = loadRam32(A_RND_SEED) * 1103515245 + 12345;
1190 storeRam32(A_RND_SEED, s);
1191 v1 = s;
1192 mips_return_c((s >> 16) & 0x7fff, 12+37);
1193}
1194
1195static void psxBios_srand() { // 0x30
1196 storeRam32(A_RND_SEED, a0);
1197 mips_return_void_c(3);
1198}
1199
1200static u32 qscmpfunc, qswidth;
1201
1202static inline int qscmp(char *a, char *b) {
1203 u32 sa0 = a0;
1204
1205 a0 = sa0 + (a - (char *)PSXM(sa0));
1206 a1 = sa0 + (b - (char *)PSXM(sa0));
1207
1208 softCall(qscmpfunc);
1209
1210 a0 = sa0;
1211 return (s32)v0;
1212}
1213
1214static inline void qexchange(char *i, char *j) {
1215 char t;
1216 int n = qswidth;
1217
1218 do {
1219 t = *i;
1220 *i++ = *j;
1221 *j++ = t;
1222 } while (--n);
1223}
1224
1225static inline void q3exchange(char *i, char *j, char *k) {
1226 char t;
1227 int n = qswidth;
1228
1229 do {
1230 t = *i;
1231 *i++ = *k;
1232 *k++ = *j;
1233 *j++ = t;
1234 } while (--n);
1235}
1236
1237static void qsort_main(char *a, char *l) {
1238 char *i, *j, *lp, *hp;
1239 int c;
1240 unsigned int n;
1241
1242start:
1243 if ((n = l - a) <= qswidth)
1244 return;
1245 n = qswidth * (n / (2 * qswidth));
1246 hp = lp = a + n;
1247 i = a;
1248 j = l - qswidth;
1249 while (TRUE) {
1250 if (i < lp) {
1251 if ((c = qscmp(i, lp)) == 0) {
1252 qexchange(i, lp -= qswidth);
1253 continue;
1254 }
1255 if (c < 0) {
1256 i += qswidth;
1257 continue;
1258 }
1259 }
1260
1261loop:
1262 if (j > hp) {
1263 if ((c = qscmp(hp, j)) == 0) {
1264 qexchange(hp += qswidth, j);
1265 goto loop;
1266 }
1267 if (c > 0) {
1268 if (i == lp) {
1269 q3exchange(i, hp += qswidth, j);
1270 i = lp += qswidth;
1271 goto loop;
1272 }
1273 qexchange(i, j);
1274 j -= qswidth;
1275 i += qswidth;
1276 continue;
1277 }
1278 j -= qswidth;
1279 goto loop;
1280 }
1281
1282 if (i == lp) {
1283 if (lp - a >= l - hp) {
1284 qsort_main(hp + qswidth, l);
1285 l = lp;
1286 } else {
1287 qsort_main(a, lp);
1288 a = hp + qswidth;
1289 }
1290 goto start;
1291 }
1292
1293 q3exchange(j, lp -= qswidth, i);
1294 j = hp -= qswidth;
1295 }
1296}
1297
1298void psxBios_qsort() { // 0x31
1299 qswidth = a2;
1300 qscmpfunc = a3;
1301 qsort_main((char *)Ra0, (char *)Ra0 + a1 * a2);
1302
1303 pc0 = ra;
1304}
1305
1306static int malloc_heap_grow(u32 size) {
1307 u32 heap_addr, heap_end, heap_addr_new;
1308
1309 heap_addr = loadRam32(A_HEAP_BASE);
1310 heap_end = loadRam32(A_HEAP_END);
1311 heap_addr_new = heap_addr + 4 + size;
1312 if (heap_addr_new >= heap_end)
1313 return -1;
1314 storeRam32(A_HEAP_BASE, heap_addr_new);
1315 storeRam32(heap_addr - 4, size | 1);
1316 storeRam32(heap_addr + size, ~1); // terminator
1317 return 0;
1318}
1319
1320static void psxBios_malloc() { // 0x33
1321 u32 size = (a0 + 3) & ~3;
1322 u32 limit = 32*1024;
1323 u32 tries = 2, i;
1324 u32 ret;
1325
1326 PSXBIOS_LOG("psxBios_%s %d\n", biosA0n[0x33], a0);
1327
1328 if (!loadRam32(A_HEAP_INIT_FLG)) {
1329 u32 heap_addr = loadRam32(A_HEAP_BASE);
1330 storeRam32(heap_addr, ~1);
1331 storeRam32(A_HEAP_FRSTCHNK, heap_addr);
1332 storeRam32(A_HEAP_CURCHNK, heap_addr);
1333 storeRam32(A_HEAP_BASE, heap_addr + 4);
1334 if (malloc_heap_grow(size)) {
1335 PSXBIOS_LOG("malloc: init OOM\n");
1336 mips_return_c(0, 20);
1337 return;
1338 }
1339 storeRam32(A_HEAP_INIT_FLG, 1);
1340 }
1341
1342 for (i = 0; tries > 0 && i < limit; i++)
1343 {
1344 u32 chunk = loadRam32(A_HEAP_CURCHNK);
1345 u32 chunk_hdr = loadRam32(chunk);
1346 u32 next_chunk = chunk + 4 + (chunk_hdr & ~3);
1347 u32 next_chunk_hdr = loadRam32(next_chunk);
1348 use_cycles(20);
1349 //printf(" c %08x %08x\n", chunk, chunk_hdr);
1350 if (chunk_hdr & 1) {
1351 // free chunk
1352 if (chunk_hdr > (size | 1)) {
1353 // split
1354 u32 p2size = (chunk_hdr & ~3) - size - 4;
1355 storeRam32(chunk + 4 + size, p2size | 1);
1356 chunk_hdr = size | 1;
1357 }
1358 if (chunk_hdr == (size | 1)) {
1359 storeRam32(chunk, size);
1360 break;
1361 }
1362 // chunk too small
1363 if (next_chunk_hdr & 1) {
1364 // merge
1365 u32 msize = (chunk_hdr & ~3) + 4 + (next_chunk_hdr & ~3);
1366 storeRam32(chunk, msize | 1);
1367 continue;
1368 }
1369 }
1370 if (chunk_hdr == ~1) {
1371 // last chunk
1372 if (tries == 2)
1373 storeRam32(A_HEAP_CURCHNK, loadRam32(A_HEAP_FRSTCHNK));
1374 tries--;
1375 }
1376 else {
1377 // go to the next chunk
1378 storeRam32(A_HEAP_CURCHNK, next_chunk);
1379 }
1380 }
1381
1382 if (i == limit)
1383 ret = 0;
1384 else if (tries == 0 && malloc_heap_grow(size))
1385 ret = 0;
1386 else {
1387 u32 chunk = loadRam32(A_HEAP_CURCHNK);
1388 storeRam32(chunk, loadRam32(chunk) & ~3);
1389 ret = chunk + 4;
1390 }
1391
1392 PSXBIOS_LOG(" -> %08x\n", ret);
1393 mips_return_c(ret, 40);
1394}
1395
1396static void psxBios_free() { // 0x34
1397 PSXBIOS_LOG("psxBios_%s %x (%d bytes)\n", biosA0n[0x34], a0, loadRam32(a0 - 4));
1398 storeRam32(a0 - 4, loadRam32(a0 - 4) | 1); // set chunk to free
1399 mips_return_void_c(5);
1400}
1401
1402static void psxBios_calloc() { // 0x37
1403 u32 ret, size;
1404 PSXBIOS_LOG("psxBios_%s %x %x\n", biosA0n[0x37], a0, a1);
1405
1406 a0 = size = a0 * a1;
1407 psxBios_malloc();
1408 ret = v0;
1409 if (ret) {
1410 a0 = ret; a1 = size;
1411 psxBios_bzero();
1412 }
1413 mips_return_c(ret, 21);
1414}
1415
1416void psxBios_realloc() { // 0x38
1417 u32 block = a0;
1418 u32 size = a1;
1419#ifdef PSXBIOS_LOG
1420 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x38]);
1421#endif
1422
1423 a0 = block;
1424 /* If "old_buf" is zero, executes malloc(new_size), and returns r2=new_buf (or 0=failed). */
1425 if (block == 0)
1426 {
1427 psxBios_malloc();
1428 }
1429 /* Else, if "new_size" is zero, executes free(old_buf), and returns r2=garbage. */
1430 else if (size == 0)
1431 {
1432 psxBios_free();
1433 }
1434 /* Else, executes malloc(new_size), bcopy(old_buf,new_buf,new_size), and free(old_buf), and returns r2=new_buf (or 0=failed). */
1435 /* Note that it is not quite implemented this way here. */
1436 else
1437 {
1438 psxBios_free();
1439 a0 = size;
1440 psxBios_malloc();
1441 }
1442}
1443
1444
1445/* InitHeap(void *block , int n) */
1446static void psxBios_InitHeap() { // 0x39
1447 PSXBIOS_LOG("psxBios_%s %x %x\n", biosA0n[0x39], a0, a1);
1448
1449 storeRam32(A_HEAP_BASE, a0);
1450 storeRam32(A_HEAP_SIZE, a1);
1451 storeRam32(A_HEAP_END, a0 + (a1 & ~3) + 4);
1452 storeRam32(A_HEAP_INIT_FLG, 0);
1453 storeRam32(a0, 0);
1454
1455 mips_return_void_c(14);
1456}
1457
1458void psxBios_getchar() { //0x3b
1459 v0 = getchar(); pc0 = ra;
1460}
1461
1462static void psxBios_printf_psxout() { // 0x3f
1463 char tmp[1024];
1464 char tmp2[1024];
1465 u32 save[4] = { 0, };
1466 char *ptmp = tmp;
1467 int n=1, i=0, j;
1468 void *psp;
1469
1470 psp = PSXM(sp);
1471 if (psp != INVALID_PTR) {
1472 memcpy(save, psp, 4 * 4);
1473 psxMu32ref(sp) = SWAP32((u32)a0);
1474 psxMu32ref(sp + 4) = SWAP32((u32)a1);
1475 psxMu32ref(sp + 8) = SWAP32((u32)a2);
1476 psxMu32ref(sp + 12) = SWAP32((u32)a3);
1477 }
1478
1479 while (Ra0[i]) {
1480 switch (Ra0[i]) {
1481 case '%':
1482 j = 0;
1483 tmp2[j++] = '%';
1484_start:
1485 switch (Ra0[++i]) {
1486 case '.':
1487 case 'l':
1488 tmp2[j++] = Ra0[i]; goto _start;
1489 default:
1490 if (Ra0[i] >= '0' && Ra0[i] <= '9') {
1491 tmp2[j++] = Ra0[i];
1492 goto _start;
1493 }
1494 break;
1495 }
1496 tmp2[j++] = Ra0[i];
1497 tmp2[j] = 0;
1498
1499 switch (Ra0[i]) {
1500 case 'f': case 'F':
1501 ptmp += sprintf(ptmp, tmp2, (float)psxMu32(sp + n * 4)); n++; break;
1502 case 'a': case 'A':
1503 case 'e': case 'E':
1504 case 'g': case 'G':
1505 ptmp += sprintf(ptmp, tmp2, (double)psxMu32(sp + n * 4)); n++; break;
1506 case 'p':
1507 case 'i': case 'u':
1508 case 'd': case 'D':
1509 case 'o': case 'O':
1510 case 'x': case 'X':
1511 ptmp += sprintf(ptmp, tmp2, (unsigned int)psxMu32(sp + n * 4)); n++; break;
1512 case 'c':
1513 ptmp += sprintf(ptmp, tmp2, (unsigned char)psxMu32(sp + n * 4)); n++; break;
1514 case 's':
1515 ptmp += sprintf(ptmp, tmp2, (char*)PSXM(psxMu32(sp + n * 4))); n++; break;
1516 case '%':
1517 *ptmp++ = Ra0[i]; break;
1518 }
1519 i++;
1520 break;
1521 default:
1522 *ptmp++ = Ra0[i++];
1523 }
1524 }
1525 *ptmp = 0;
1526
1527 if (psp != INVALID_PTR)
1528 memcpy(psp, save, 4 * 4);
1529
1530 if (Config.PsxOut)
1531 SysPrintf("%s", tmp);
1532}
1533
1534void psxBios_printf() { // 0x3f
1535 psxBios_printf_psxout();
1536 pc0 = ra;
1537}
1538
1539static void psxBios_cd() { // 0x40
1540 const char *p, *dir = Ra0;
1541 PSXBIOS_LOG("psxBios_%s %x(%s)\n", biosB0n[0x40], a0, dir);
1542 if (dir != INVALID_PTR) {
1543 if ((p = strchr(dir, ':')))
1544 dir = ++p;
1545 if (*dir == '\\')
1546 dir++;
1547 snprintf(cdir, sizeof(cdir), "%s", dir);
1548 }
1549 mips_return_c(1, 100);
1550}
1551
1552static void psxBios_format() { // 0x41
1553 PSXBIOS_LOG("psxBios_%s %x(%s)\n", biosB0n[0x41], a0, Ra0);
1554 if (strcmp(Ra0, "bu00:") == 0 && Config.Mcd1[0] != '\0')
1555 {
1556 CreateMcd(Config.Mcd1);
1557 LoadMcd(1, Config.Mcd1);
1558 v0 = 1;
1559 }
1560 else if (strcmp(Ra0, "bu10:") == 0 && Config.Mcd2[0] != '\0')
1561 {
1562 CreateMcd(Config.Mcd2);
1563 LoadMcd(2, Config.Mcd2);
1564 v0 = 1;
1565 }
1566 else
1567 {
1568 v0 = 0;
1569 }
1570 pc0 = ra;
1571}
1572
1573static void psxBios_SystemErrorUnresolvedException() {
1574 if (floodchk != 0x12340a40) { // prevent log flood
1575 SysPrintf("psxBios_%s called from %08x\n", biosA0n[0x40], ra);
1576 floodchk = 0x12340a40;
1577 }
1578 mips_return_void_c(1000);
1579}
1580
1581static void FlushCache() {
1582 psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_ISOLATED, NULL);
1583 psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_UNISOLATED, NULL);
1584 k0 = 0xbfc0193c;
1585 // runs from uncached mem so tons of cycles
1586 use_cycles(500);
1587}
1588
1589// you likely want to mask irqs before calling these
1590static u8 cdrom_sync(int do_ack)
1591{
1592 u8 r = 0;
1593 if (psxRegs.interrupt & (1u << PSXINT_CDR)) {
1594 if ((s32)(psxRegs.cycle - event_cycles[PSXINT_CDR]) < 0)
1595 psxRegs.cycle = event_cycles[PSXINT_CDR] + 1;
1596 irq_test(&psxRegs.CP0);
1597 }
1598 if (do_ack) {
1599 cdrWrite0(1);
1600 r = cdrRead3() & 0x1f;
1601 cdrWrite3(0x5f); // ack; clear params
1602 }
1603 return r;
1604}
1605
1606static void cdrom_cmd_and_wait(u8 cmd, int arg_cnt, int resp_cnt, ...)
1607{
1608 va_list ap;
1609
1610 cdrom_sync(0);
1611 cdrWrite0(0);
1612 va_start(ap, resp_cnt);
1613 while (arg_cnt-- > 0)
1614 cdrWrite2(va_arg(ap, u32));
1615 va_end(ap);
1616 cdrWrite1(cmd);
1617
1618 if (resp_cnt > 0) {
1619 u8 r = cdrom_sync(1);
1620 assert(r == 3); (void)r;
1621 cdrRead1();
1622 }
1623 if (resp_cnt > 1) {
1624 u8 r = cdrom_sync(1);
1625 assert(r == 2); (void)r;
1626 cdrRead1();
1627 }
1628}
1629
1630/*
1631 * long Load(char *name, struct EXEC *header);
1632 */
1633
1634void psxBios_Load() { // 0x42
1635 u8 time[3] = { 2, 0, 0x16 };
1636 EXE_HEADER eheader;
1637 char path[256];
1638 char *pa0, *p;
1639 void *pa1;
1640
1641 pa0 = Ra0;
1642 pa1 = Ra1;
1643 PSXBIOS_LOG("psxBios_%s %x(%s), %x\n", biosA0n[0x42], a0, pa0, a1);
1644 if (pa0 == INVALID_PTR || pa1 == INVALID_PTR) {
1645 mips_return(0);
1646 return;
1647 }
1648 if ((p = strchr(pa0, ':')))
1649 pa0 = ++p;
1650 if (*pa0 == '\\')
1651 pa0++;
1652 if (cdir[0])
1653 snprintf(path, sizeof(path), "%s\\%s", cdir, (char *)pa0);
1654 else
1655 snprintf(path, sizeof(path), "%s", (char *)pa0);
1656
1657 if (LoadCdromFile(path, &eheader, time) == 0) {
1658 memcpy(pa1, ((char*)&eheader)+16, sizeof(EXEC));
1659 psxCpu->Clear(a1, sizeof(EXEC) / 4);
1660 FlushCache();
1661 v0 = 1;
1662 } else v0 = 0;
1663 PSXBIOS_LOG(" -> %d\n", v0);
1664
1665 pc0 = ra;
1666
1667 // set the cdrom to a state of just after exe read
1668 psxRegs.CP0.n.SR &= ~0x404;
1669 cdrom_sync(1);
1670 cdrWrite0(1);
1671 cdrWrite2(0x1f); // unmask
1672 cdrom_cmd_and_wait(0x0e, 1, 1, 0x80u); // CdlSetmode
1673 cdrom_cmd_and_wait(0x02, 3, 1, time[0], time[1], time[2]); // CdlSetloc
1674 cdrom_cmd_and_wait(0x15, 0, 2); // CdlSeekL
1675 psxHwWrite16(0x1f801070, ~4);
1676 MTC0(&psxRegs, 12, psxRegs.CP0.n.SR | 0x404);
1677}
1678
1679/*
1680 * int Exec(struct EXEC *header , int argc , char **argv);
1681 */
1682
1683void psxBios_Exec() { // 43
1684 EXEC *header = (EXEC *)castRam32ptr(a0);
1685 u32 ptr;
1686 s32 len;
1687
1688 PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosA0n[0x43], a0, a1, a2);
1689
1690 header->_sp = SWAP32(sp);
1691 header->_fp = SWAP32(fp);
1692 header->_sp = SWAP32(sp);
1693 header->_gp = SWAP32(gp);
1694 header->ret = SWAP32(ra);
1695 header->base = SWAP32(s0);
1696
1697 ptr = SWAP32(header->b_addr);
1698 len = SWAP32(header->b_size);
1699 if (len != 0) do {
1700 storeRam32(ptr, 0);
1701 len -= 4; ptr += 4;
1702 } while (len > 0);
1703
1704 if (header->S_addr != 0)
1705 sp = fp = SWAP32(header->S_addr) + SWAP32(header->s_size);
1706
1707 gp = SWAP32(header->gp0);
1708
1709 s0 = a0;
1710
1711 a0 = a1;
1712 a1 = a2;
1713
1714 ra = 0x8000;
1715 pc0 = SWAP32(header->_pc0);
1716}
1717
1718static void psxBios_FlushCache() { // 44
1719 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x44]);
1720 FlushCache();
1721 mips_return_void();
1722}
1723
1724void psxBios_GPU_dw() { // 0x46
1725 int size;
1726 u32 *ptr;
1727
1728#ifdef PSXBIOS_LOG
1729 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x46]);
1730#endif
1731
1732 GPU_writeData(0xa0000000);
1733 GPU_writeData((a1<<0x10)|(a0&0xffff));
1734 GPU_writeData((a3<<0x10)|(a2&0xffff));
1735 size = (a2*a3)/2;
1736 ptr = (u32*)PSXM(Rsp[4]); //that is correct?
1737 while(size--)
1738 {
1739 GPU_writeData(SWAPu32(*ptr++));
1740 }
1741
1742 pc0 = ra;
1743}
1744
1745static void gpu_sync() {
1746 // not implemented...
1747 // might be problematic to do because of Config.GpuListWalking
1748 if (psxRegs.interrupt & (1u << PSXINT_GPUDMA))
1749 log_unhandled("gpu_sync with active dma\n");
1750 mips_return_c(0, 21);
1751}
1752
1753void psxBios_mem2vram() { // 0x47
1754 int size;
1755 gpuSyncPluginSR(); // flush
1756 GPU_writeData(0xa0000000);
1757 GPU_writeData((a1<<0x10)|(a0&0xffff));
1758 GPU_writeData((a3<<0x10)|(a2&0xffff));
1759 size = ((((a2 * a3) / 2) >> 4) << 16);
1760 GPU_writeStatus(0x04000002);
1761 psxHwWrite32(0x1f8010f4,0);
1762 psxHwWrite32(0x1f8010f0,psxHwRead32(0x1f8010f0)|0x800);
1763 psxHwWrite32(0x1f8010a0,Rsp[4]);//might have a buggy...
1764 psxHwWrite32(0x1f8010a4, size | 0x10);
1765 psxHwWrite32(0x1f8010a8,0x01000201);
1766
1767 pc0 = ra;
1768}
1769
1770void psxBios_SendGPU() { // 0x48
1771 GPU_writeStatus(a0);
1772 gpuSyncPluginSR();
1773 pc0 = ra;
1774}
1775
1776void psxBios_GPU_cw() { // 0x49
1777 GPU_writeData(a0);
1778 gpuSyncPluginSR();
1779 use_cycles(13);
1780 gpu_sync();
1781}
1782
1783void psxBios_GPU_cwb() { // 0x4a
1784 u32 *ptr = (u32*)Ra0;
1785 int size = a1;
1786 gpuSyncPluginSR();
1787 while(size--)
1788 {
1789 GPU_writeData(SWAPu32(*ptr++));
1790 }
1791
1792 pc0 = ra;
1793}
1794
1795void psxBios_GPU_SendPackets() { //4b:
1796 gpuSyncPluginSR();
1797 GPU_writeStatus(0x04000002);
1798 psxHwWrite32(0x1f8010f4,0);
1799 psxHwWrite32(0x1f8010f0,psxHwRead32(0x1f8010f0)|0x800);
1800 psxHwWrite32(0x1f8010a0,a0);
1801 psxHwWrite32(0x1f8010a4,0);
1802 psxHwWrite32(0x1f8010a8,0x010000401);
1803 pc0 = ra;
1804}
1805
1806void psxBios_sys_a0_4c() { // 0x4c GPU relate
1807 psxHwWrite32(0x1f8010a8,0x00000401);
1808 GPU_writeData(0x0400000);
1809 GPU_writeData(0x0200000);
1810 GPU_writeData(0x0100000);
1811 v0 = 0x1f801814;
1812 pc0 = ra;
1813}
1814
1815void psxBios_GPU_GetGPUStatus() { // 0x4d
1816 v0 = GPU_readStatus();
1817 pc0 = ra;
1818}
1819
1820#undef s_addr
1821
1822void psxBios_LoadExec() { // 51
1823 EXEC *header = (EXEC*)PSXM(0xf000);
1824 u32 s_addr, s_size;
1825
1826#ifdef PSXBIOS_LOG
1827 PSXBIOS_LOG("psxBios_%s: %s: %x,%x\n", biosA0n[0x51], Ra0, a1, a2);
1828#endif
1829 s_addr = a1; s_size = a2;
1830
1831 a1 = 0xf000;
1832 psxBios_Load();
1833
1834 header->S_addr = s_addr;
1835 header->s_size = s_size;
1836
1837 a0 = 0xf000; a1 = 0; a2 = 0;
1838 psxBios_Exec();
1839}
1840
1841void psxBios__bu_init() { // 70
1842#ifdef PSXBIOS_LOG
1843 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x70]);
1844#endif
1845
1846 DeliverEvent(0xf0000011, 0x0004);
1847 DeliverEvent(0xf4000001, 0x0004);
1848
1849 pc0 = ra;
1850}
1851
1852static void write_chain(u32 *d, u32 next, u32 handler1, u32 handler2);
1853static void psxBios_SysEnqIntRP_(u32 priority, u32 chain_eptr);
1854static void psxBios_SysDeqIntRP_(u32 priority, u32 chain_rm_eptr);
1855
1856static void psxBios_EnqueueCdIntr_(void)
1857{
1858 u32 *ram32 = (u32 *)psxM;
1859
1860 // traps should already be installed by write_chain()
1861 ram32[0x91d0/4] = 0;
1862 ram32[0x91d4/4] = SWAP32(0xbfc0506c);
1863 ram32[0x91d8/4] = SWAP32(0xbfc04dec);
1864 psxBios_SysEnqIntRP_(0, 0x91d0);
1865 ram32[0x91e0/4] = 0;
1866 ram32[0x91e4/4] = SWAP32(0xbfc050a4);
1867 ram32[0x91e8/4] = SWAP32(0xbfc04fbc);
1868 psxBios_SysEnqIntRP_(0, 0x91e0);
1869 use_cycles(31);
1870}
1871
1872static void setup_cd_irq_and_events(void)
1873{
1874 u16 specs[] = { 0x10, 0x20, 0x40, 0x80, 0x8000 };
1875 size_t i;
1876
1877 psxBios_EnqueueCdIntr_();
1878
1879 for (i = 0; i < sizeof(specs) / sizeof(specs[0]); i++) {
1880 u32 h = OpenEvent(0xf0000003, specs[i], EvMdMARK, 0);
1881 // no error checks
1882 storeRam32(A_CD_EVENTS + i * 4, h);
1883 EnableEvent(h, 0);
1884 }
1885}
1886
1887static void psxBios_CdReset_() {
1888 psxRegs.CP0.n.SR &= ~0x404; // disable interrupts
1889
1890 cdrom_sync(1);
1891 cdrWrite0(1);
1892 cdrWrite2(0x1f); // unmask
1893 cdrom_cmd_and_wait(0x0a, 0, 2); // CdlReset
1894 cdrom_cmd_and_wait(0x0e, 1, 1, 0x80u); // CdlSetmode
1895
1896 // todo(?): should read something (iso root directory?)
1897 // from { 0, 2, 16 } to somewhere and pause
1898
1899 mips_return(1);
1900 psxHwWrite16(0x1f801070, ~4);
1901 MTC0(&psxRegs, 12, psxRegs.CP0.n.SR | 0x404);
1902 DeliverEvent(0xf0000003, 0x0020);
1903}
1904
1905static void psxBios_CdInit() { // 54, 71
1906 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x71]);
1907 setup_cd_irq_and_events();
1908
1909 psxBios_CdReset_();
1910
1911 // this function takes pretty much forever
1912 mips_return_c(0, 50000*11);
1913}
1914
1915static void psxBios_DequeueCdIntr_() {
1916 psxBios_SysDeqIntRP_(0, 0x91d0);
1917 psxBios_SysDeqIntRP_(0, 0x91e0);
1918 use_cycles(16);
1919}
1920
1921static void psxBios_CdReset() { // 95
1922 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x95]);
1923 psxBios_CdReset_();
1924}
1925
1926static void psxBios_EnqueueCdIntr() { // a2
1927 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0xa2]);
1928 psxBios_EnqueueCdIntr_();
1929 // return value comes from SysEnqIntRP() insternal call
1930}
1931
1932static void psxBios_DequeueCdIntr() { // a3
1933 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0xa3]);
1934 psxBios_DequeueCdIntr_();
1935}
1936
1937static void psxBios_CdRemove() { // 56, 72
1938 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x72]);
1939
1940 CloseEvent(loadRam32(A_CD_EVENTS + 0x00));
1941 CloseEvent(loadRam32(A_CD_EVENTS + 0x04));
1942 CloseEvent(loadRam32(A_CD_EVENTS + 0x08));
1943 CloseEvent(loadRam32(A_CD_EVENTS + 0x0c));
1944 CloseEvent(loadRam32(A_CD_EVENTS + 0x10));
1945 psxBios_DequeueCdIntr_();
1946
1947 // EnterCriticalSection - should be done at the beginning,
1948 // but this way is much easier to implement
1949 a0 = 1;
1950 pc0 = A_SYSCALL;
1951 use_cycles(30);
1952}
1953
1954static void setup_tt(u32 tcb_cnt, u32 evcb_cnt, u32 stack);
1955
1956static void psxBios_SetConf() { // 9c
1957 PSXBIOS_LOG("psxBios_%s %x %x %x\n", biosA0n[0x9c], a0, a1, a2);
1958 setup_tt(a1, a0, a2);
1959 psxRegs.CP0.n.SR |= 0x401;
1960 mips_return_void_c(500);
1961}
1962
1963static void psxBios_GetConf() { // 9d
1964 PSXBIOS_LOG("psxBios_%s %x %x %x\n", biosA0n[0x9d], a0, a1, a2);
1965 storeRam32(a0, loadRam32(A_CONF_EvCB));
1966 storeRam32(a1, loadRam32(A_CONF_TCB));
1967 storeRam32(a2, loadRam32(A_CONF_SP));
1968 mips_return_void_c(10);
1969}
1970
1971void psxBios_SetMem() { // 9f
1972 u32 new = psxHu32(0x1060);
1973
1974#ifdef PSXBIOS_LOG
1975 PSXBIOS_LOG("psxBios_%s: %x, %x\n", biosA0n[0x9f], a0, a1);
1976#endif
1977
1978 switch(a0) {
1979 case 2:
1980 psxHu32ref(0x1060) = SWAP32(new);
1981 psxMu32ref(0x060) = a0;
1982 PSXBIOS_LOG("Change effective memory : %d MBytes\n",a0);
1983 break;
1984
1985 case 8:
1986 psxHu32ref(0x1060) = SWAP32(new | 0x300);
1987 psxMu32ref(0x060) = a0;
1988 PSXBIOS_LOG("Change effective memory : %d MBytes\n",a0);
1989
1990 default:
1991 PSXBIOS_LOG("Effective memory must be 2/8 MBytes\n");
1992 break;
1993 }
1994
1995 pc0 = ra;
1996}
1997
1998/* TODO FIXME : Not compliant. -1 indicates failure but using 1 for now. */
1999static void psxBios_get_cd_status() // a6
2000{
2001 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0xa6]);
2002 v0 = 1;
2003 pc0 = ra;
2004}
2005
2006static void psxBios__card_info() { // ab
2007 PSXBIOS_LOG("psxBios_%s: %x\n", biosA0n[0xab], a0);
2008 u32 ret, port;
2009 storeRam32(A_CARD_CHAN1, a0);
2010 port = a0 >> 4;
2011
2012 switch (port) {
2013 case 0x0:
2014 case 0x1:
2015 ret = 0x0004;
2016 if (McdDisable[port & 1])
2017 ret = 0x0100;
2018 break;
2019 default:
2020 PSXBIOS_LOG("psxBios_%s: UNKNOWN PORT 0x%x\n", biosA0n[0xab], a0);
2021 ret = 0x0302;
2022 break;
2023 }
2024
2025 if (McdDisable[0] && McdDisable[1])
2026 ret = 0x0100;
2027
2028 DeliverEvent(0xf0000011, 0x0004);
2029// DeliverEvent(0xf4000001, 0x0004);
2030 DeliverEvent(0xf4000001, ret);
2031 v0 = 1; pc0 = ra;
2032}
2033
2034void psxBios__card_load() { // ac
2035#ifdef PSXBIOS_LOG
2036 PSXBIOS_LOG("psxBios_%s: %x\n", biosA0n[0xac], a0);
2037#endif
2038
2039 storeRam32(A_CARD_CHAN1, a0);
2040
2041// DeliverEvent(0xf0000011, 0x0004);
2042 DeliverEvent(0xf4000001, 0x0004);
2043
2044 v0 = 1; pc0 = ra;
2045}
2046
2047static void psxBios_GetSystemInfo() { // b4
2048 u32 ret = 0;
2049 //PSXBIOS_LOG("psxBios_%s %x\n", biosA0n[0xb4], a0);
2050 SysPrintf("psxBios_%s %x\n", biosA0n[0xb4], a0);
2051 switch (a0) {
2052 case 0:
2053 case 1: ret = SWAP32(((u32 *)psxR)[0x100/4 + a0]); break;
2054 case 2: ret = 0xbfc0012c; break;
2055 case 5: ret = loadRam32(0x60) << 10; break;
2056 }
2057 mips_return_c(ret, 20);
2058}
2059
2060/* System calls B0 */
2061
2062static u32 psxBios_SysMalloc_(u32 size);
2063
2064static void psxBios_SysMalloc() { // B 00
2065 u32 ret = psxBios_SysMalloc_(a0);
2066
2067 PSXBIOS_LOG("psxBios_%s 0x%x -> %x\n", biosB0n[0x00], a0, ret);
2068 mips_return_c(ret, 33);
2069}
2070
2071void psxBios_SetRCnt() { // 02
2072#ifdef PSXBIOS_LOG
2073 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x02]);
2074#endif
2075
2076 a0&= 0x3;
2077 if (a0 != 3) {
2078 u32 mode=0;
2079
2080 psxRcntWtarget(a0, a1);
2081 if (a2&0x1000) mode|= 0x050; // Interrupt Mode
2082 if (a2&0x0100) mode|= 0x008; // Count to 0xffff
2083 if (a2&0x0010) mode|= 0x001; // Timer stop mode
2084 if (a0 == 2) { if (a2&0x0001) mode|= 0x200; } // System Clock mode
2085 else { if (a2&0x0001) mode|= 0x100; } // System Clock mode
2086
2087 psxRcntWmode(a0, mode);
2088 }
2089 pc0 = ra;
2090}
2091
2092void psxBios_GetRCnt() { // 03
2093#ifdef PSXBIOS_LOG
2094 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x03]);
2095#endif
2096
2097 switch (a0 & 0x3)
2098 {
2099 case 0: v0 = psxRcntRcount0(); break;
2100 case 1: v0 = psxRcntRcount1(); break;
2101 case 2: v0 = psxRcntRcount2(); break;
2102 case 3: v0 = 0; break;
2103 }
2104 pc0 = ra;
2105}
2106
2107void psxBios_StartRCnt() { // 04
2108#ifdef PSXBIOS_LOG
2109 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x04]);
2110#endif
2111
2112 a0&= 0x3;
2113 if (a0 != 3) psxHu32ref(0x1074)|= SWAP32((u32)((1<<(a0+4))));
2114 else psxHu32ref(0x1074)|= SWAPu32(0x1);
2115 v0 = 1; pc0 = ra;
2116}
2117
2118void psxBios_StopRCnt() { // 05
2119#ifdef PSXBIOS_LOG
2120 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x05]);
2121#endif
2122
2123 a0&= 0x3;
2124 if (a0 != 3) psxHu32ref(0x1074)&= SWAP32((u32)(~(1<<(a0+4))));
2125 else psxHu32ref(0x1074)&= SWAPu32(~0x1);
2126 pc0 = ra;
2127}
2128
2129void psxBios_ResetRCnt() { // 06
2130#ifdef PSXBIOS_LOG
2131 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x06]);
2132#endif
2133
2134 a0&= 0x3;
2135 if (a0 != 3) {
2136 psxRcntWmode(a0, 0);
2137 psxRcntWtarget(a0, 0);
2138 psxRcntWcount(a0, 0);
2139 }
2140 pc0 = ra;
2141}
2142
2143static u32 DeliverEvent(u32 class, u32 spec) {
2144 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB);
2145 u32 evcb_len = loadRam32(A_TT_EvCB + 4);
2146 u32 ret = loadRam32(A_TT_EvCB) + evcb_len;
2147 u32 i, lim = evcb_len / 0x1c;
2148
2149 //printf("%s %08x %x\n", __func__, class, spec);
2150 for (i = 0; i < lim; i++, ev++) {
2151 use_cycles(8);
2152 if (SWAP32(ev->status) != EvStACTIVE)
2153 continue;
2154 use_cycles(4);
2155 if (SWAP32(ev->class) != class)
2156 continue;
2157 use_cycles(4);
2158 if (SWAP32(ev->spec) != spec)
2159 continue;
2160 use_cycles(6);
2161 ret = SWAP32(ev->mode);
2162 if (ret == EvMdMARK) {
2163 ev->status = SWAP32(EvStALREADY);
2164 continue;
2165 }
2166 use_cycles(8);
2167 if (ret == EvMdCALL) {
2168 ret = SWAP32(ev->fhandler);
2169 if (ret) {
2170 v0 = ret;
2171 softCall(ret);
2172 ret = v0;
2173 }
2174 }
2175 }
2176 floodchk = 0;
2177 use_cycles(29);
2178 return ret;
2179}
2180
2181static u32 UnDeliverEvent(u32 class, u32 spec) {
2182 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB);
2183 u32 evcb_len = loadRam32(A_TT_EvCB + 4);
2184 u32 ret = loadRam32(A_TT_EvCB) + evcb_len;
2185 u32 i, lim = evcb_len / 0x1c;
2186
2187 for (i = 0; i < lim; i++, ev++) {
2188 use_cycles(8);
2189 if (SWAP32(ev->status) != EvStALREADY)
2190 continue;
2191 use_cycles(4);
2192 if (SWAP32(ev->class) != class)
2193 continue;
2194 use_cycles(4);
2195 if (SWAP32(ev->spec) != spec)
2196 continue;
2197 use_cycles(6);
2198 if (SWAP32(ev->mode) == EvMdMARK)
2199 ev->status = SWAP32(EvStACTIVE);
2200 }
2201 use_cycles(28);
2202 return ret;
2203}
2204
2205static void psxBios_DeliverEvent() { // 07
2206 u32 ret;
2207 PSXBIOS_LOG("psxBios_%s %x %04x\n", biosB0n[0x07], a0, a1);
2208
2209 ret = DeliverEvent(a0, a1);
2210 mips_return(ret);
2211}
2212
2213static s32 get_free_EvCB_slot() {
2214 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB);
2215 u32 i, lim = loadRam32(A_TT_EvCB + 4) / 0x1c;
2216
2217 use_cycles(19);
2218 for (i = 0; i < lim; i++, ev++) {
2219 use_cycles(8);
2220 if (ev->status == SWAP32(EvStUNUSED))
2221 return i;
2222 }
2223 return -1;
2224}
2225
2226static u32 OpenEvent(u32 class, u32 spec, u32 mode, u32 func) {
2227 u32 ret = get_free_EvCB_slot();
2228 if ((s32)ret >= 0) {
2229 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB) + ret;
2230 ev->class = SWAP32(class);
2231 ev->status = SWAP32(EvStDISABLED);
2232 ev->spec = SWAP32(spec);
2233 ev->mode = SWAP32(mode);
2234 ev->fhandler = SWAP32(func);
2235 ret |= 0xf1000000u;
2236 }
2237 return ret;
2238}
2239
2240static void psxBios_OpenEvent() { // 08
2241 u32 ret = OpenEvent(a0, a1, a2, a3);
2242 PSXBIOS_LOG("psxBios_%s (class:%x, spec:%04x, mode:%04x, func:%x) -> %x\n",
2243 biosB0n[0x08], a0, a1, a2, a3, ret);
2244 mips_return_c(ret, 36);
2245}
2246
2247static void CloseEvent(u32 ev)
2248{
2249 u32 base = loadRam32(A_TT_EvCB);
2250 storeRam32(base + (ev & 0xffff) * sizeof(EvCB) + 4, EvStUNUSED);
2251}
2252
2253static void psxBios_CloseEvent() { // 09
2254 PSXBIOS_LOG("psxBios_%s %x (%x)\n", biosB0n[0x09], a0,
2255 loadRam32(loadRam32(A_TT_EvCB) + (a0 & 0xffff) * sizeof(EvCB) + 4));
2256 CloseEvent(a0);
2257 mips_return_c(1, 10);
2258}
2259
2260static void psxBios_WaitEvent() { // 0a
2261 u32 base = loadRam32(A_TT_EvCB);
2262 u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
2263 PSXBIOS_LOG("psxBios_%s %x (status=%x)\n", biosB0n[0x0a], a0, status);
2264
2265 use_cycles(15);
2266 if (status == EvStALREADY) {
2267 storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
2268 mips_return(1);
2269 return;
2270 }
2271 if (status != EvStACTIVE)
2272 {
2273 mips_return_c(0, 2);
2274 return;
2275 }
2276
2277 // retrigger this hlecall after the next emulation event
2278 pc0 -= 4;
2279 if ((s32)(next_interupt - psxRegs.cycle) > 0)
2280 psxRegs.cycle = next_interupt;
2281 psxBranchTest();
2282}
2283
2284static void psxBios_TestEvent() { // 0b
2285 u32 base = loadRam32(A_TT_EvCB);
2286 u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
2287 u32 ret = 0;
2288
2289 if (psxRegs.cycle - floodchk > 16*1024u) { // prevent log flood
2290 PSXBIOS_LOG("psxBios_%s %x %x\n", biosB0n[0x0b], a0, status);
2291 floodchk = psxRegs.cycle;
2292 }
2293 if (status == EvStALREADY) {
2294 storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
2295 ret = 1;
2296 }
2297
2298 mips_return_c(ret, 15);
2299}
2300
2301static void EnableEvent(u32 ev, int do_log) {
2302 u32 base = loadRam32(A_TT_EvCB);
2303 u32 status = loadRam32(base + (ev & 0xffff) * sizeof(EvCB) + 4);
2304 if (do_log)
2305 PSXBIOS_LOG("psxBios_%s %x (%x)\n", biosB0n[0x0c], ev, status);
2306 if (status != EvStUNUSED)
2307 storeRam32(base + (ev & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
2308}
2309
2310static void psxBios_EnableEvent() { // 0c
2311 EnableEvent(a0, 1);
2312 mips_return_c(1, 15);
2313}
2314
2315static void psxBios_DisableEvent() { // 0d
2316 u32 base = loadRam32(A_TT_EvCB);
2317 u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
2318 PSXBIOS_LOG("psxBios_%s %x: %x\n", biosB0n[0x0d], a0, status);
2319 if (status != EvStUNUSED)
2320 storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStDISABLED);
2321
2322 mips_return_c(1, 15);
2323}
2324
2325/*
2326 * long OpenTh(long (*func)(), unsigned long sp, unsigned long gp);
2327 */
2328
2329void psxBios_OpenTh() { // 0e
2330 TCB *tcb = loadRam32ptr(A_TT_TCB);
2331 u32 limit = loadRam32(A_TT_TCB + 4) / 0xc0u;
2332 int th;
2333
2334 for (th = 1; th < limit; th++)
2335 {
2336 if (tcb[th].status != SWAP32(0x4000)) break;
2337
2338 }
2339 if (th == limit) {
2340 // Feb 2019 - Added out-of-bounds fix caught by cppcheck:
2341 // When no free TCB is found, return 0xffffffff according to Nocash doc.
2342#ifdef PSXBIOS_LOG
2343 PSXBIOS_LOG("\t%s() WARNING! No Free TCBs found!\n", __func__);
2344#endif
2345 mips_return_c(0xffffffff, 20);
2346 return;
2347 }
2348 PSXBIOS_LOG("psxBios_%s -> %x\n", biosB0n[0x0e], 0xff000000 + th);
2349
2350 tcb[th].status = SWAP32(0x4000);
2351 tcb[th].mode = SWAP32(0x1000);
2352 tcb[th].epc = SWAP32(a0);
2353 tcb[th].reg[30] = SWAP32(a1); // fp
2354 tcb[th].reg[29] = SWAP32(a1); // sp
2355 tcb[th].reg[28] = SWAP32(a2); // gp
2356
2357 mips_return_c(0xff000000 + th, 34);
2358}
2359
2360/*
2361 * int CloseTh(long thread);
2362 */
2363
2364static void psxBios_CloseTh() { // 0f
2365 u32 tcb = loadRam32(A_TT_TCB);
2366 u32 th = a0 & 0xffff;
2367
2368 PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x0f], a0);
2369 // in the usual bios fashion no checks, just write and return 1
2370 storeRam32(tcb + th * sizeof(TCB), 0x1000);
2371
2372 mips_return_c(1, 11);
2373}
2374
2375/*
2376 * int ChangeTh(long thread);
2377 */
2378
2379void psxBios_ChangeTh() { // 10
2380 u32 tcbBase = loadRam32(A_TT_TCB);
2381 u32 th = a0 & 0xffff;
2382
2383 // this is quite spammy
2384 //PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x10], th);
2385
2386 // without doing any argument checks, just issue a syscall
2387 // (like the real bios does)
2388 a0 = 3;
2389 a1 = tcbBase + th * sizeof(TCB);
2390 pc0 = A_SYSCALL;
2391 use_cycles(15);
2392}
2393
2394void psxBios_InitPAD() { // 0x12
2395 u32 i, *ram32 = (u32 *)psxM;
2396 PSXBIOS_LOG("psxBios_%s %x %x %x %x\n", biosB0n[0x12], a0, a1, a2, a3);
2397
2398 // printf("%s", "PS-X Control PAD Driver Ver 3.0");
2399 ram32[A_PAD_DR_DST/4] = 0;
2400 ram32[A_PAD_OUTBUF/4 + 0] = 0;
2401 ram32[A_PAD_OUTBUF/4 + 1] = 0;
2402 ram32[A_PAD_OUT_LEN/4 + 0] = 0;
2403 ram32[A_PAD_OUT_LEN/4 + 1] = 0;
2404 ram32[A_PAD_INBUF/4 + 0] = SWAP32(a0);
2405 ram32[A_PAD_INBUF/4 + 1] = SWAP32(a2);
2406 ram32[A_PAD_IN_LEN/4 + 0] = SWAP32(a1);
2407 ram32[A_PAD_IN_LEN/4 + 1] = SWAP32(a3);
2408
2409 for (i = 0; i < a1; i++) {
2410 use_cycles(4);
2411 storeRam8(a0 + i, 0);
2412 }
2413 for (i = 0; i < a3; i++) {
2414 use_cycles(4);
2415 storeRam8(a2 + i, 0);
2416 }
2417 write_chain(ram32 + A_PADCRD_CHN_E/4, 0, 0x49bc, 0x4a4c);
2418
2419 ram32[A_PAD_IRQR_ENA/4] = SWAP32(1);
2420
2421 mips_return_c(1, 200);
2422}
2423
2424void psxBios_StartPAD() { // 13
2425 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x13]);
2426
2427 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2428 psxBios_SysEnqIntRP_(2, A_PADCRD_CHN_E);
2429 psxHwWrite16(0x1f801070, ~1);
2430 psxHwWrite16(0x1f801074, psxHu32(0x1074) | 1);
2431 storeRam32(A_PAD_ACK_VBL, 1);
2432 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 0);
2433 psxRegs.CP0.n.SR |= 0x401;
2434
2435 mips_return_c(1, 300);
2436}
2437
2438void psxBios_StopPAD() { // 14
2439 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x14]);
2440 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 1);
2441 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2442 psxRegs.CP0.n.SR |= 0x401;
2443 mips_return_void_c(200);
2444}
2445
2446static void psxBios_PAD_init() { // 15
2447 u32 ret = 0;
2448 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x15]);
2449 if (a0 == 0x20000000 || a0 == 0x20000001)
2450 {
2451 u32 dst = a1;
2452 a0 = A_PAD_DR_BUF1; a1 = 0x22;
2453 a2 = A_PAD_DR_BUF2; a3 = 0x22;
2454 psxBios_InitPAD();
2455 psxBios_StartPAD();
2456 storeRam32(A_PAD_DR_DST, dst);
2457 ret = 2;
2458 }
2459 mips_return_c(ret, 100);
2460}
2461
2462static u32 psxBios_PAD_dr_() {
2463 u8 *dst = loadRam32ptr(A_PAD_DR_DST);
2464 u8 *buf1 = castRam8ptr(A_PAD_DR_BUF1);
2465 u8 *buf2 = castRam8ptr(A_PAD_DR_BUF2);
2466 dst[0] = dst[1] = dst[2] = dst[3] = ~0;
2467 if (buf1[0] == 0 && (buf1[1] == 0x23 || buf1[1] == 0x41))
2468 {
2469 dst[0] = buf1[3], dst[1] = buf1[2];
2470 if (buf1[1] == 0x23) {
2471 dst[0] |= 0xc7, dst[1] |= 7;
2472 if (buf1[5] >= 0x10) dst[0] &= ~(1u << 6);
2473 if (buf1[6] >= 0x10) dst[0] &= ~(1u << 7);
2474 }
2475 }
2476 if (buf2[0] == 0 && (buf2[1] == 0x23 || buf2[1] == 0x41))
2477 {
2478 dst[2] = buf2[3], dst[3] = buf2[2];
2479 if (buf2[1] == 0x23) {
2480 dst[2] |= 0xc7, dst[3] |= 7;
2481 if (buf2[5] >= 0x10) dst[2] &= ~(1u << 6);
2482 if (buf2[6] >= 0x10) dst[2] &= ~(1u << 7);
2483 }
2484 }
2485 use_cycles(55);
2486 return SWAP32(*(u32 *)dst);
2487}
2488
2489static void psxBios_PAD_dr() { // 16
2490 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x16]);
2491 u32 ret = psxBios_PAD_dr_();
2492 mips_return(ret);
2493}
2494
2495static void psxBios_ReturnFromException() { // 17
2496 u32 tcbPtr = loadRam32(A_TT_PCB);
2497 const TCB *tcb = loadRam32ptr(tcbPtr);
2498 u32 sr;
2499 int i;
2500
2501 for (i = 1; i < 32; i++)
2502 psxRegs.GPR.r[i] = SWAP32(tcb->reg[i]);
2503 psxRegs.GPR.n.lo = SWAP32(tcb->lo);
2504 psxRegs.GPR.n.hi = SWAP32(tcb->hi);
2505 sr = SWAP32(tcb->sr);
2506
2507 //printf("%s %08x->%08x %u\n", __func__, pc0, tcb->epc, psxRegs.cycle);
2508 pc0 = k0 = SWAP32(tcb->epc);
2509
2510 // the interpreter wants to know about sr changes, so do a MTC0
2511 sr = (sr & ~0x0f) | ((sr & 0x3c) >> 2);
2512 MTC0(&psxRegs, 12, sr);
2513
2514 use_cycles(53);
2515 psxBranchTest();
2516}
2517
2518void psxBios_ResetEntryInt() { // 18
2519 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x18]);
2520
2521 storeRam32(A_EEXIT_PTR, A_EEXIT_DEF);
2522 mips_return_void_c(5);
2523}
2524
2525void psxBios_HookEntryInt() { // 19
2526 PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x19], a0);
2527
2528 storeRam32(A_EEXIT_PTR, a0);
2529 mips_return_void_c(3);
2530}
2531
2532static void psxBios_UnDeliverEvent() { // 0x20
2533 u32 ret;
2534 PSXBIOS_LOG("psxBios_%s %x %x\n", biosB0n[0x20], a0, a1);
2535
2536 ret = UnDeliverEvent(a0, a1);
2537 mips_return(ret);
2538}
2539
2540static void buopen(int mcd, char *ptr, char *cfg)
2541{
2542 int i;
2543 char *mcd_data = ptr;
2544
2545 strcpy(FDesc[1 + mcd].name, Ra0+5);
2546 FDesc[1 + mcd].offset = 0;
2547 FDesc[1 + mcd].mode = a1;
2548
2549 for (i=1; i<16; i++) {
2550 const char *fptr = mcd_data + 128 * i;
2551 if ((*fptr & 0xF0) != 0x50) continue;
2552 if (strcmp(FDesc[1 + mcd].name, fptr+0xa)) continue;
2553 FDesc[1 + mcd].mcfile = i;
2554 PSXBIOS_LOG("open %s\n", fptr+0xa);
2555 v0 = 1 + mcd;
2556 break;
2557 }
2558 if (a1 & 0x200 && v0 == -1) { /* FCREAT */
2559 for (i=1; i<16; i++) {
2560 int j, xor, nblk = a1 >> 16;
2561 char *pptr, *fptr2;
2562 char *fptr = mcd_data + 128 * i;
2563
2564 if ((*fptr & 0xF0) != 0xa0) continue;
2565
2566 FDesc[1 + mcd].mcfile = i;
2567 fptr[0] = 0x51;
2568 fptr[4] = 0x00;
2569 fptr[5] = 0x20 * nblk;
2570 fptr[6] = 0x00;
2571 fptr[7] = 0x00;
2572 strcpy(fptr+0xa, FDesc[1 + mcd].name);
2573 pptr = fptr2 = fptr;
2574 for(j=2; j<=nblk; j++) {
2575 int k;
2576 for(i++; i<16; i++) {
2577 fptr2 += 128;
2578
2579 memset(fptr2, 0, 128);
2580 fptr2[0] = j < nblk ? 0x52 : 0x53;
2581 pptr[8] = i - 1;
2582 pptr[9] = 0;
2583 for (k=0, xor=0; k<127; k++) xor^= pptr[k];
2584 pptr[127] = xor;
2585 pptr = fptr2;
2586 break;
2587 }
2588 /* shouldn't this return ENOSPC if i == 16? */
2589 }
2590 pptr[8] = pptr[9] = 0xff;
2591 for (j=0, xor=0; j<127; j++) xor^= pptr[j];
2592 pptr[127] = xor;
2593 PSXBIOS_LOG("openC %s %d\n", ptr, nblk);
2594 v0 = 1 + mcd;
2595 /* just go ahead and resave them all */
2596 SaveMcd(cfg, ptr, 128, 128 * 15);
2597 break;
2598 }
2599 /* shouldn't this return ENOSPC if i == 16? */
2600 }
2601}
2602
2603/*
2604 * int open(char *name , int mode);
2605 */
2606
2607void psxBios_open() { // 0x32
2608 void *pa0 = Ra0;
2609
2610 PSXBIOS_LOG("psxBios_%s %s %x\n", biosB0n[0x32], Ra0, a1);
2611
2612 v0 = -1;
2613
2614 if (pa0 != INVALID_PTR) {
2615 if (!strncmp(pa0, "bu00", 4)) {
2616 buopen(1, Mcd1Data, Config.Mcd1);
2617 }
2618
2619 if (!strncmp(pa0, "bu10", 4)) {
2620 buopen(2, Mcd2Data, Config.Mcd2);
2621 }
2622 }
2623
2624 pc0 = ra;
2625}
2626
2627/*
2628 * int lseek(int fd , int offset , int whence);
2629 */
2630
2631void psxBios_lseek() { // 0x33
2632#ifdef PSXBIOS_LOG
2633 PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosB0n[0x33], a0, a1, a2);
2634#endif
2635
2636 switch (a2) {
2637 case 0: // SEEK_SET
2638 FDesc[a0].offset = a1;
2639 v0 = a1;
2640// DeliverEvent(0xf0000011, 0x0004);
2641// DeliverEvent(0xf4000001, 0x0004);
2642 break;
2643
2644 case 1: // SEEK_CUR
2645 FDesc[a0].offset+= a1;
2646 v0 = FDesc[a0].offset;
2647 break;
2648 }
2649
2650 pc0 = ra;
2651}
2652
2653
2654/*
2655 * int read(int fd , void *buf , int nbytes);
2656 */
2657
2658void psxBios_read() { // 0x34
2659 char *ptr;
2660 void *pa1 = Ra1;
2661
2662#ifdef PSXBIOS_LOG
2663 PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosB0n[0x34], a0, a1, a2);
2664#endif
2665
2666 v0 = -1;
2667
2668 if (pa1 != INVALID_PTR) {
2669 switch (a0) {
2670 case 2: buread(pa1, 1, a2); break;
2671 case 3: buread(pa1, 2, a2); break;
2672 }
2673 }
2674
2675 pc0 = ra;
2676}
2677
2678/*
2679 * int write(int fd , void *buf , int nbytes);
2680 */
2681
2682void psxBios_write() { // 0x35/0x03
2683 char *ptr;
2684 void *pa1 = Ra1;
2685
2686 if (a0 != 1) // stdout
2687 PSXBIOS_LOG("psxBios_%s: %x,%x,%x\n", biosB0n[0x35], a0, a1, a2);
2688
2689 v0 = -1;
2690 if (pa1 == INVALID_PTR) {
2691 pc0 = ra;
2692 return;
2693 }
2694
2695 if (a0 == 1) { // stdout
2696 char *ptr = pa1;
2697
2698 v0 = a2;
2699 if (Config.PsxOut) while (a2 > 0) {
2700 SysPrintf("%c", *ptr++); a2--;
2701 }
2702 pc0 = ra; return;
2703 }
2704
2705 switch (a0) {
2706 case 2: buwrite(pa1, 1, a2); break;
2707 case 3: buwrite(pa1, 2, a2); break;
2708 }
2709
2710 pc0 = ra;
2711}
2712
2713static void psxBios_write_psxout() {
2714 if (a0 == 1) { // stdout
2715 const char *ptr = Ra1;
2716 int len = a2;
2717
2718 if (ptr != INVALID_PTR)
2719 while (len-- > 0)
2720 SysPrintf("%c", *ptr++);
2721 }
2722}
2723
2724static void psxBios_putchar_psxout() { // 3d
2725 SysPrintf("%c", (char)a0);
2726}
2727
2728static void psxBios_puts_psxout() { // 3e/3f
2729 SysPrintf("%s", Ra0);
2730}
2731
2732/*
2733 * int close(int fd);
2734 */
2735
2736void psxBios_close() { // 0x36
2737#ifdef PSXBIOS_LOG
2738 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x36], a0);
2739#endif
2740
2741 v0 = a0;
2742 pc0 = ra;
2743}
2744
2745void psxBios_putchar() { // 3d
2746 if (Config.PsxOut) SysPrintf("%c", (char)a0);
2747 pc0 = ra;
2748}
2749
2750void psxBios_puts() { // 3e/3f
2751 if (Config.PsxOut) SysPrintf("%s", Ra0);
2752 pc0 = ra;
2753}
2754
2755static void bufile(const u8 *mcd_data, u32 dir_) {
2756 struct DIRENTRY *dir = (struct DIRENTRY *)PSXM(dir_);
2757 const char *pfile = ffile + 5;
2758 const u8 *data = mcd_data;
2759 int i = 0, match = 0;
2760 int blocks = 1;
2761 u32 head = 0;
2762
2763 v0 = 0;
2764 if (dir == INVALID_PTR)
2765 return;
2766
2767 for (; nfile <= 15 && !match; nfile++) {
2768 const char *name;
2769
2770 head = nfile * 0x40;
2771 data = mcd_data + 128 * nfile;
2772 name = (const char *)data + 0x0a;
2773 if ((data[0] & 0xF0) != 0x50) continue;
2774 /* Bug link files show up as free block. */
2775 if (!name[0]) continue;
2776 match = 1;
2777 for (i = 0; i < 20; i++) {
2778 if (pfile[i] == name[i] || pfile[i] == '?')
2779 dir->name[i] = name[i];
2780 else if (pfile[i] == '*') {
2781 int len = strlen(name + i);
2782 if (i + len > 20)
2783 len = 20 - i;
2784 memcpy(dir->name + i, name + i, len + 1);
2785 i += len;
2786 break;
2787 }
2788 else {
2789 match = 0;
2790 break;
2791 }
2792 if (!name[i])
2793 break;
2794 }
2795 PSXBIOS_LOG("%d : %s = %s + %s (match=%d)\n",
2796 nfile, dir->name, pfile, name, match);
2797 }
2798 for (; nfile <= 15; nfile++, blocks++) {
2799 const u8 *data2 = mcd_data + 128 * nfile;
2800 const char *name = (const char *)data2 + 0x0a;
2801 if ((data2[0] & 0xF0) != 0x50 || name[0])
2802 break;
2803 }
2804 if (match) {
2805 // nul char of full lenth name seems to overwrite .attr
2806 dir->attr = SWAP32(i < 20 ? data[0] & 0xf0 : 0); // ?
2807 dir->size = 8192 * blocks;
2808 dir->head = head;
2809 v0 = dir_;
2810 }
2811 PSXBIOS_LOG(" -> %x '%s' %x %x %x %x\n", v0, v0 ? dir->name : "",
2812 dir->attr, dir->size, dir->next, dir->head);
2813}
2814
2815/*
2816 * struct DIRENTRY* firstfile(char *name,struct DIRENTRY *dir);
2817 */
2818
2819static void psxBios_firstfile() { // 42
2820 char *pa0 = Ra0;
2821
2822 PSXBIOS_LOG("psxBios_%s %s %x\n", biosB0n[0x42], pa0, a1);
2823 v0 = 0;
2824
2825 if (pa0 != INVALID_PTR)
2826 {
2827 snprintf(ffile, sizeof(ffile), "%s", pa0);
2828 if (ffile[5] == 0)
2829 strcpy(ffile + 5, "*"); // maybe?
2830 nfile = 1;
2831 if (!strncmp(pa0, "bu00", 4)) {
2832 // firstfile() calls _card_read() internally, so deliver it's event
2833 DeliverEvent(0xf0000011, 0x0004);
2834 bufile((u8 *)Mcd1Data, a1);
2835 } else if (!strncmp(pa0, "bu10", 4)) {
2836 // firstfile() calls _card_read() internally, so deliver it's event
2837 DeliverEvent(0xf0000011, 0x0004);
2838 bufile((u8 *)Mcd2Data, a1);
2839 }
2840 }
2841
2842 pc0 = ra;
2843}
2844
2845/*
2846 * struct DIRENTRY* nextfile(struct DIRENTRY *dir);
2847 */
2848
2849void psxBios_nextfile() { // 43
2850 PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x43], a0);
2851
2852 v0 = 0;
2853 if (!strncmp(ffile, "bu00", 4))
2854 bufile((u8 *)Mcd1Data, a0);
2855 else if (!strncmp(ffile, "bu10", 4))
2856 bufile((u8 *)Mcd2Data, a0);
2857
2858 pc0 = ra;
2859}
2860
2861#define burename(mcd) { \
2862 for (i=1; i<16; i++) { \
2863 int namelen, j, xor = 0; \
2864 ptr = Mcd##mcd##Data + 128 * i; \
2865 if ((*ptr & 0xF0) != 0x50) continue; \
2866 if (strcmp(Ra0+5, ptr+0xa)) continue; \
2867 namelen = strlen(Ra1+5); \
2868 memcpy(ptr+0xa, Ra1+5, namelen); \
2869 memset(ptr+0xa+namelen, 0, 0x75-namelen); \
2870 for (j=0; j<127; j++) xor^= ptr[j]; \
2871 ptr[127] = xor; \
2872 SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, 128 * i + 0xa, 0x76); \
2873 v0 = 1; \
2874 break; \
2875 } \
2876}
2877
2878/*
2879 * int rename(char *old, char *new);
2880 */
2881
2882void psxBios_rename() { // 44
2883 void *pa0 = Ra0;
2884 void *pa1 = Ra1;
2885 char *ptr;
2886 int i;
2887
2888#ifdef PSXBIOS_LOG
2889 PSXBIOS_LOG("psxBios_%s: %s,%s\n", biosB0n[0x44], Ra0, Ra1);
2890#endif
2891
2892 v0 = 0;
2893
2894 if (pa0 != INVALID_PTR && pa1 != INVALID_PTR) {
2895 if (!strncmp(pa0, "bu00", 4) && !strncmp(pa1, "bu00", 4)) {
2896 burename(1);
2897 }
2898
2899 if (!strncmp(pa0, "bu10", 4) && !strncmp(pa1, "bu10", 4)) {
2900 burename(2);
2901 }
2902 }
2903
2904 pc0 = ra;
2905}
2906
2907
2908#define budelete(mcd) { \
2909 for (i=1; i<16; i++) { \
2910 ptr = Mcd##mcd##Data + 128 * i; \
2911 if ((*ptr & 0xF0) != 0x50) continue; \
2912 if (strcmp(Ra0+5, ptr+0xa)) continue; \
2913 *ptr = (*ptr & 0xf) | 0xA0; \
2914 SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, 128 * i, 1); \
2915 PSXBIOS_LOG("delete %s\n", ptr+0xa); \
2916 v0 = 1; \
2917 break; \
2918 } \
2919}
2920
2921/*
2922 * int delete(char *name);
2923 */
2924
2925void psxBios_delete() { // 45
2926 void *pa0 = Ra0;
2927 char *ptr;
2928 int i;
2929
2930#ifdef PSXBIOS_LOG
2931 PSXBIOS_LOG("psxBios_%s: %s\n", biosB0n[0x45], Ra0);
2932#endif
2933
2934 v0 = 0;
2935
2936 if (pa0 != INVALID_PTR) {
2937 if (!strncmp(pa0, "bu00", 4)) {
2938 budelete(1);
2939 }
2940
2941 if (!strncmp(pa0, "bu10", 4)) {
2942 budelete(2);
2943 }
2944 }
2945
2946 pc0 = ra;
2947}
2948
2949void psxBios_InitCARD() { // 4a
2950 u32 *ram32 = (u32 *)psxM;
2951 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x4a], a0);
2952 write_chain(ram32 + A_PADCRD_CHN_E/4, 0, 0x49bc, 0x4a4c);
2953 // (maybe) todo: early_card_irq, etc
2954
2955 ram32[A_PAD_IRQR_ENA/4] = SWAP32(a0);
2956
2957 psxBios_FlushCache();
2958 mips_return_c(0, 34+13+15+6);
2959}
2960
2961void psxBios_StartCARD() { // 4b
2962 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4b]);
2963 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2964 psxBios_SysEnqIntRP_(2, A_PADCRD_CHN_E);
2965
2966 psxHwWrite16(0x1f801074, psxHu32(0x1074) | 1);
2967 storeRam32(A_PAD_ACK_VBL, 1);
2968 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 0);
2969 storeRam32(A_CARD_IRQR_ENA, 1);
2970 psxRegs.CP0.n.SR |= 0x401;
2971
2972 mips_return_c(1, 200);
2973}
2974
2975void psxBios_StopCARD() { // 4c
2976 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4c]);
2977 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 1);
2978 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2979 storeRam32(A_CARD_IRQR_ENA, 0);
2980 psxRegs.CP0.n.SR |= 0x401;
2981 mips_return_void_c(200);
2982}
2983
2984void psxBios__card_write() { // 0x4e
2985 void *pa2 = Ra2;
2986 int port;
2987
2988#ifdef PSXBIOS_LOG
2989 PSXBIOS_LOG("psxBios_%s: %x,%x,%x\n", biosB0n[0x4e], a0, a1, a2);
2990#endif
2991 /*
2992 Function also accepts sector 400h (a bug).
2993 But notaz said we shouldn't allow sector 400h because it can corrupt the emulator.
2994 */
2995 if (!(a1 <= 0x3FF))
2996 {
2997 /* Invalid sectors */
2998 v0 = 0; pc0 = ra;
2999 return;
3000 }
3001 storeRam32(A_CARD_CHAN1, a0);
3002 port = a0 >> 4;
3003
3004 if (pa2 != INVALID_PTR) {
3005 if (port == 0) {
3006 memcpy(Mcd1Data + a1 * 128, pa2, 128);
3007 SaveMcd(Config.Mcd1, Mcd1Data, a1 * 128, 128);
3008 } else {
3009 memcpy(Mcd2Data + a1 * 128, pa2, 128);
3010 SaveMcd(Config.Mcd2, Mcd2Data, a1 * 128, 128);
3011 }
3012 }
3013
3014 DeliverEvent(0xf0000011, 0x0004);
3015// DeliverEvent(0xf4000001, 0x0004);
3016
3017 v0 = 1; pc0 = ra;
3018}
3019
3020void psxBios__card_read() { // 0x4f
3021 void *pa2 = Ra2;
3022 int port;
3023
3024#ifdef PSXBIOS_LOG
3025 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4f]);
3026#endif
3027 /*
3028 Function also accepts sector 400h (a bug).
3029 But notaz said we shouldn't allow sector 400h because it can corrupt the emulator.
3030 */
3031 if (!(a1 <= 0x3FF))
3032 {
3033 /* Invalid sectors */
3034 v0 = 0; pc0 = ra;
3035 return;
3036 }
3037 storeRam32(A_CARD_CHAN1, a0);
3038 port = a0 >> 4;
3039
3040 if (pa2 != INVALID_PTR) {
3041 if (port == 0) {
3042 memcpy(pa2, Mcd1Data + a1 * 128, 128);
3043 } else {
3044 memcpy(pa2, Mcd2Data + a1 * 128, 128);
3045 }
3046 }
3047
3048 DeliverEvent(0xf0000011, 0x0004);
3049// DeliverEvent(0xf4000001, 0x0004);
3050
3051 v0 = 1; pc0 = ra;
3052}
3053
3054void psxBios__new_card() { // 0x50
3055#ifdef PSXBIOS_LOG
3056 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x50]);
3057#endif
3058
3059 pc0 = ra;
3060}
3061
3062/* According to a user, this allows Final Fantasy Tactics to save/load properly */
3063void psxBios__get_error(void) // 55
3064{
3065 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x55]);
3066 v0 = 0;
3067 pc0 = ra;
3068}
3069
3070void psxBios_Krom2RawAdd() { // 0x51
3071 int i = 0;
3072
3073 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x51]);
3074 const u32 table_8140[][2] = {
3075 {0x8140, 0x0000}, {0x8180, 0x0762}, {0x81ad, 0x0cc6}, {0x81b8, 0x0ca8},
3076 {0x81c0, 0x0f00}, {0x81c8, 0x0d98}, {0x81cf, 0x10c2}, {0x81da, 0x0e6a},
3077 {0x81e9, 0x13ce}, {0x81f0, 0x102c}, {0x81f8, 0x1590}, {0x81fc, 0x111c},
3078 {0x81fd, 0x1626}, {0x824f, 0x113a}, {0x8259, 0x20ee}, {0x8260, 0x1266},
3079 {0x827a, 0x24cc}, {0x8281, 0x1572}, {0x829b, 0x28aa}, {0x829f, 0x187e},
3080 {0x82f2, 0x32dc}, {0x8340, 0x2238}, {0x837f, 0x4362}, {0x8380, 0x299a},
3081 {0x8397, 0x4632}, {0x839f, 0x2c4c}, {0x83b7, 0x49f2}, {0x83bf, 0x2f1c},
3082 {0x83d7, 0x4db2}, {0x8440, 0x31ec}, {0x8461, 0x5dde}, {0x8470, 0x35ca},
3083 {0x847f, 0x6162}, {0x8480, 0x378c}, {0x8492, 0x639c}, {0x849f, 0x39a8},
3084 {0xffff, 0}
3085 };
3086
3087 const u32 table_889f[][2] = {
3088 {0x889f, 0x3d68}, {0x8900, 0x40ec}, {0x897f, 0x4fb0}, {0x8a00, 0x56f4},
3089 {0x8a7f, 0x65b8}, {0x8b00, 0x6cfc}, {0x8b7f, 0x7bc0}, {0x8c00, 0x8304},
3090 {0x8c7f, 0x91c8}, {0x8d00, 0x990c}, {0x8d7f, 0xa7d0}, {0x8e00, 0xaf14},
3091 {0x8e7f, 0xbdd8}, {0x8f00, 0xc51c}, {0x8f7f, 0xd3e0}, {0x9000, 0xdb24},
3092 {0x907f, 0xe9e8}, {0x9100, 0xf12c}, {0x917f, 0xfff0}, {0x9200, 0x10734},
3093 {0x927f, 0x115f8}, {0x9300, 0x11d3c}, {0x937f, 0x12c00}, {0x9400, 0x13344},
3094 {0x947f, 0x14208}, {0x9500, 0x1494c}, {0x957f, 0x15810}, {0x9600, 0x15f54},
3095 {0x967f, 0x16e18}, {0x9700, 0x1755c}, {0x977f, 0x18420}, {0x9800, 0x18b64},
3096 {0xffff, 0}
3097 };
3098
3099 if (a0 >= 0x8140 && a0 <= 0x84be) {
3100 while (table_8140[i][0] <= a0) i++;
3101 a0 -= table_8140[i - 1][0];
3102 v0 = 0xbfc66000 + (a0 * 0x1e + table_8140[i - 1][1]);
3103 } else if (a0 >= 0x889f && a0 <= 0x9872) {
3104 while (table_889f[i][0] <= a0) i++;
3105 a0 -= table_889f[i - 1][0];
3106 v0 = 0xbfc66000 + (a0 * 0x1e + table_889f[i - 1][1]);
3107 } else {
3108 v0 = 0xffffffff;
3109 }
3110
3111 pc0 = ra;
3112}
3113
3114void psxBios_GetC0Table() { // 56
3115 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x56]);
3116 log_unhandled("GetC0Table @%08x\n", ra);
3117
3118 mips_return_c(A_C0_TABLE, 3);
3119}
3120
3121void psxBios_GetB0Table() { // 57
3122 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x57]);
3123 log_unhandled("GetB0Table @%08x\n", ra);
3124
3125 mips_return_c(A_B0_TABLE, 3);
3126}
3127
3128static void psxBios__card_chan() { // 0x58
3129 u32 ret;
3130 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x58]);
3131
3132 // todo: should return active slot chan
3133 // (active - which was last processed by irq code)
3134 ret = loadRam32(A_CARD_CHAN1);
3135 mips_return_c(ret, 8);
3136}
3137
3138static void psxBios_ChangeClearPad() { // 5b
3139 u32 ret;
3140 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x5b], a0);
3141 ret = loadRam32(A_PAD_ACK_VBL);
3142 storeRam32(A_PAD_ACK_VBL, a0);
3143
3144 mips_return_c(ret, 6);
3145}
3146
3147static void psxBios__card_status() { // 5c
3148 PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x5c], a0);
3149
3150 v0 = 1; // ready
3151 pc0 = ra;
3152}
3153
3154static void psxBios__card_wait() { // 5d
3155 PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x5d], a0);
3156
3157 v0 = 1; // ready
3158 pc0 = ra;
3159}
3160
3161/* System calls C0 */
3162
3163static void psxBios_InitRCnt() { // 00
3164 int i;
3165 PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x00], a0);
3166 psxHwWrite16(0x1f801074, psxHu32(0x1074) & ~0x71);
3167 for (i = 0; i < 3; i++) {
3168 psxHwWrite16(0x1f801100 + i*0x10 + 4, 0);
3169 psxHwWrite16(0x1f801100 + i*0x10 + 8, 0);
3170 psxHwWrite16(0x1f801100 + i*0x10 + 0, 0);
3171 }
3172 for (i = 0; i < 4; i++)
3173 psxBios_SysEnqIntRP_(a0, 0x6d58 + i * 0x10);
3174 mips_return_c(0, 9);
3175}
3176
3177static void psxBios_InitException() { // 01
3178 PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x01], a0);
3179 psxBios_SysEnqIntRP_(a0, 0x6da8);
3180 mips_return_c(0, 9);
3181}
3182
3183/*
3184 * int SysEnqIntRP(int index , long *queue);
3185 */
3186
3187static void psxBios_SysEnqIntRP_(u32 priority, u32 chain_eptr) {
3188 u32 old, base = loadRam32(A_TT_ExCB);
3189
3190 old = loadRam32(base + (priority << 3));
3191 storeRam32(base + (priority << 3), chain_eptr);
3192 storeRam32(chain_eptr, old);
3193 mips_return_c(0, 9);
3194}
3195
3196static void psxBios_SysEnqIntRP() { // 02
3197 PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x02], a0, a1);
3198 psxBios_SysEnqIntRP_(a0, a1);
3199}
3200
3201/*
3202 * int SysDeqIntRP(int index , long *queue);
3203 */
3204
3205static void psxBios_SysDeqIntRP_(u32 priority, u32 chain_rm_eptr) {
3206 u32 ptr, next, base = loadRam32(A_TT_ExCB);
3207 u32 lim = 0, ret = 0;
3208
3209 // as in original: no arg checks of any kind, bug if a1 == 0
3210 ptr = loadRam32(base + (priority << 3));
3211 while (ptr) {
3212 next = loadRam32(ptr);
3213 if (ptr == chain_rm_eptr) {
3214 storeRam32(base + (priority << 3), next);
3215 ret = ptr;
3216 use_cycles(6);
3217 break;
3218 }
3219 while (next && next != chain_rm_eptr && lim++ < 100) {
3220 ptr = next;
3221 next = loadRam32(ptr);
3222 use_cycles(8);
3223 }
3224 if (next == chain_rm_eptr) {
3225 next = loadRam32(next);
3226 storeRam32(ptr, next);
3227 ret = ptr;
3228 use_cycles(6);
3229 }
3230 break;
3231 }
3232 if (lim == 100)
3233 PSXBIOS_LOG("bad chain %u %x\n", priority, base);
3234
3235 mips_return_c(ret, 12);
3236}
3237
3238static void psxBios_SysDeqIntRP() { // 03
3239 PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x03], a0, a1);
3240 psxBios_SysDeqIntRP_(a0, a1);
3241}
3242
3243static void psxBios_get_free_EvCB_slot() { // 04
3244 PSXBIOS_LOG("psxBios_%s\n", biosC0n[0x04]);
3245 s32 ret = get_free_EvCB_slot();
3246 mips_return_c(ret, 0);
3247}
3248
3249static void psxBios_SysInitMemory_(u32 base, u32 size) {
3250 storeRam32(base, 0);
3251 storeRam32(A_KMALLOC_PTR, base);
3252 storeRam32(A_KMALLOC_SIZE, size);
3253 storeRam32(A_KMALLOC_END, base + (size & ~3) + 4);
3254}
3255
3256// this should be much more complicated, but maybe that'll be enough
3257static u32 psxBios_SysMalloc_(u32 size) {
3258 u32 ptr = loadRam32(A_KMALLOC_PTR);
3259
3260 size = (size + 3) & ~3;
3261 storeRam32(A_KMALLOC_PTR, ptr + 4 + size);
3262 storeRam32(ptr, size);
3263 return ptr + 4;
3264}
3265
3266static void psxBios_SysInitMemory() { // 08
3267 PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x08], a0, a1);
3268
3269 psxBios_SysInitMemory_(a0, a1);
3270 mips_return_void_c(12);
3271}
3272
3273static void psxBios_ChangeClearRCnt() { // 0a
3274 u32 ret;
3275
3276 PSXBIOS_LOG("psxBios_%s: %x, %x\n", biosC0n[0x0a], a0, a1);
3277
3278 ret = loadRam32(A_RCNT_VBL_ACK + (a0 << 2));
3279 storeRam32(A_RCNT_VBL_ACK + (a0 << 2), a1);
3280 mips_return_c(ret, 8);
3281}
3282
3283static void psxBios_InitDefInt() { // 0c
3284 PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x0c], a0);
3285 // should also clear the autoack table
3286 psxBios_SysEnqIntRP_(a0, 0x6d98);
3287 mips_return_c(0, 20 + 6*2);
3288}
3289
3290void psxBios_dummy() {
3291 u32 pc = (pc0 & 0x1fffff) - 4;
3292 char **ntab = pc == 0xa0 ? biosA0n : pc == 0xb0 ? biosB0n
3293 : pc == 0xc0 ? biosC0n : NULL;
3294 PSXBIOS_LOG("unk %x call: %x ra=%x (%s)\n",
3295 pc, t1, ra, ntab ? ntab[t1 & 0xff] : "???");
3296 (void)pc; (void)ntab;
3297 mips_return_c(0, 100);
3298}
3299
3300void (*biosA0[256])();
3301// C0 and B0 overlap (end of C0 is start of B0)
3302void (*biosC0[256+128])();
3303void (**biosB0)() = biosC0 + 128;
3304
3305static void setup_mips_code()
3306{
3307 u32 *ptr;
3308 ptr = (u32 *)&psxM[A_SYSCALL];
3309 ptr[0x00/4] = SWAPu32(0x0000000c); // syscall 0
3310 ptr[0x04/4] = SWAPu32(0x03e00008); // jr $ra
3311 ptr[0x08/4] = SWAPu32(0x00000000); // nop
3312
3313 ptr = (u32 *)&psxM[A_EXCEPTION];
3314 memset(ptr, 0, 0xc0); // nops (to be patched by games sometimes)
3315 ptr[0x10/4] = SWAPu32(0x8c1a0108); // lw $k0, (0x108) // PCB
3316 ptr[0x14/4] = SWAPu32(0x00000000); // nop
3317 ptr[0x18/4] = SWAPu32(0x8f5a0000); // lw $k0, ($k0) // TCB
3318 ptr[0x1c/4] = SWAPu32(0x00000000); // nop
3319 ptr[0x20/4] = SWAPu32(0x275a0008); // addiu $k0, $k0, 8 // regs
3320 ptr[0x24/4] = SWAPu32(0xaf5f007c); // sw $ra, 0x7c($k0)
3321 ptr[0x28/4] = SWAPu32(0xaf410004); // sw $at, 0x04($k0)
3322 ptr[0x2c/4] = SWAPu32(0xaf420008); // sw $v0, 0x08($k0)
3323 ptr[0x30/4] = SWAPu32(0xaf43000c); // sw $v1, 0x0c($k0)
3324
3325 ptr[0x60/4] = SWAPu32(0x40037000); // mfc0 $v1, EPC
3326 ptr[0x64/4] = SWAPu32(0x40026800); // mfc0 $v0, Cause
3327 ptr[0x6c/4] = SWAPu32(0xaf430080); // sw $v1, 0x80($k0)
3328
3329 ptr[0xb0/4] = HLEOP(hleop_exception);
3330}
3331
3332static const struct {
3333 u32 addr;
3334 enum hle_op op;
3335} chainfns[] = {
3336 { 0xbfc050a4, hleop_exc0_0_1 },
3337 { 0xbfc04fbc, hleop_exc0_0_2 },
3338 { 0xbfc0506c, hleop_exc0_1_1 },
3339 { 0xbfc04dec, hleop_exc0_1_2 },
3340 { 0x1a00, hleop_exc0_2_2 },
3341 { 0x19c8, hleop_exc1_0_1 },
3342 { 0x18bc, hleop_exc1_0_2 },
3343 { 0x1990, hleop_exc1_1_1 },
3344 { 0x1858, hleop_exc1_1_2 },
3345 { 0x1958, hleop_exc1_2_1 },
3346 { 0x17f4, hleop_exc1_2_2 },
3347 { 0x1920, hleop_exc1_3_1 },
3348 { 0x1794, hleop_exc1_3_2 },
3349 { 0x2458, hleop_exc3_0_2 },
3350 { 0x49bc, hleop_exc_padcard1 },
3351 { 0x4a4c, hleop_exc_padcard2 },
3352};
3353
3354static int chain_hle_op(u32 handler)
3355{
3356 size_t i;
3357
3358 for (i = 0; i < sizeof(chainfns) / sizeof(chainfns[0]); i++)
3359 if (chainfns[i].addr == handler)
3360 return chainfns[i].op;
3361 return hleop_dummy;
3362}
3363
3364static void write_chain(u32 *d, u32 next, u32 handler1, u32 handler2)
3365{
3366 d[0] = SWAPu32(next);
3367 d[1] = SWAPu32(handler1);
3368 d[2] = SWAPu32(handler2);
3369
3370 // install the hle traps
3371 if (handler1) PSXMu32ref(handler1) = HLEOP(chain_hle_op(handler1));
3372 if (handler2) PSXMu32ref(handler2) = HLEOP(chain_hle_op(handler2));
3373}
3374
3375static void setup_tt(u32 tcb_cnt, u32 evcb_cnt, u32 stack)
3376{
3377 u32 *ram32 = (u32 *)psxM;
3378 u32 s_excb = 0x20, s_evcb, s_pcb = 4, s_tcb;
3379 u32 p_excb, p_evcb, p_pcb, p_tcb;
3380 u32 i;
3381
3382 PSXBIOS_LOG("setup: tcb %u, evcb %u\n", tcb_cnt, evcb_cnt);
3383
3384 // the real bios doesn't care, but we just don't
3385 // want to crash in case of garbage parameters
3386 if (tcb_cnt > 1024) tcb_cnt = 1024;
3387 if (evcb_cnt > 1024) evcb_cnt = 1024;
3388 s_evcb = 0x1c * evcb_cnt;
3389 s_tcb = 0xc0 * tcb_cnt;
3390
3391 memset(ram32 + 0xe000/4, 0, s_excb + s_evcb + s_pcb + s_tcb + 5*4);
3392 psxBios_SysInitMemory_(0xa000e000, 0x2000);
3393 p_excb = psxBios_SysMalloc_(s_excb);
3394 p_evcb = psxBios_SysMalloc_(s_evcb);
3395 p_pcb = psxBios_SysMalloc_(s_pcb);
3396 p_tcb = psxBios_SysMalloc_(s_tcb);
3397
3398 // "table of tables". Some games modify it
3399 assert(A_TT_ExCB == 0x0100);
3400 ram32[0x0100/4] = SWAPu32(p_excb); // ExCB - exception chains
3401 ram32[0x0104/4] = SWAPu32(s_excb); // ExCB size
3402 ram32[0x0108/4] = SWAPu32(p_pcb); // PCB - process control
3403 ram32[0x010c/4] = SWAPu32(s_pcb); // PCB size
3404 ram32[0x0110/4] = SWAPu32(p_tcb); // TCB - thread control
3405 ram32[0x0114/4] = SWAPu32(s_tcb); // TCB size
3406 ram32[0x0120/4] = SWAPu32(p_evcb); // EvCB - event control
3407 ram32[0x0124/4] = SWAPu32(s_evcb); // EvCB size
3408 ram32[0x0140/4] = SWAPu32(0x8648); // FCB - file control
3409 ram32[0x0144/4] = SWAPu32(0x02c0); // FCB size
3410 ram32[0x0150/4] = SWAPu32(0x6ee0); // DCB - device control
3411 ram32[0x0154/4] = SWAPu32(0x0320); // DCB size
3412
3413 storeRam32(p_excb + 0*4, 0x0000); // chain0
3414 storeRam32(p_excb + 2*4, 0x6d88); // chain1
3415 storeRam32(p_excb + 4*4, 0x0000); // chain2
3416 storeRam32(p_excb + 6*4, 0x6d98); // chain3
3417
3418 storeRam32(p_pcb, p_tcb);
3419 storeRam32(p_tcb, 0x4000); // first TCB
3420 for (i = 1; i < tcb_cnt; i++)
3421 storeRam32(p_tcb + sizeof(TCB) * i, 0x1000);
3422
3423 psxBios_SysEnqIntRP_(0, 0x6da8);
3424 setup_cd_irq_and_events();
3425
3426 storeRam32(A_CONF_EvCB, evcb_cnt);
3427 storeRam32(A_CONF_TCB, tcb_cnt);
3428 storeRam32(A_CONF_SP, stack);
3429}
3430
3431static const u32 gpu_ctl_def[] = {
3432 0x00000000, 0x01000000, 0x03000000, 0x04000000,
3433 0x05000800, 0x06c60260, 0x0703fc10, 0x08000027
3434};
3435
3436static const u32 gpu_data_def[] = {
3437 0xe100360b, 0xe2000000, 0xe3000800, 0xe4077e7f,
3438 0xe5001000, 0xe6000000,
3439 0x02000000, 0x00000000, 0x01ff03ff
3440};
3441
3442// from 1f801d80
3443static const u16 spu_config[] = {
3444 0x3fff, 0x37ef, 0x5ebc, 0x5ebc, 0x0000, 0x0000, 0x0000, 0x00a0,
3445 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x00ff, 0x0000, 0x0000,
3446 0x0000, 0xe128, 0x0000, 0x0200, 0xf0f0, 0xc085, 0x0004, 0x0000,
3447 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
3448 0x033d, 0x0231, 0x7e00, 0x5000, 0xb400, 0xb000, 0x4c00, 0xb000,
3449 0x6000, 0x5400, 0x1ed6, 0x1a31, 0x1d14, 0x183b, 0x1bc2, 0x16b2,
3450 0x1a32, 0x15ef, 0x15ee, 0x1055, 0x1334, 0x0f2d, 0x11f6, 0x0c5d,
3451 0x1056, 0x0ae1, 0x0ae0, 0x07a2, 0x0464, 0x0232, 0x8000, 0x8000
3452};
3453
3454void psxBiosSetupBootState(void)
3455{
3456 boolean hle = Config.HLE;
3457 u32 *hw = (u32 *)psxH;
3458 int i;
3459
3460 // see also SetBootRegs()
3461 if (hle) {
3462 v0 = 1; v1 = 4;
3463 a0 = 1; a2 = a3 = 0; a3 = 0x2a;
3464 t2 = 0x2d; t4 = 0x23; t5 = 0x2b; t6 = 0xa0010000;
3465 s0 = 0xa000b870;
3466 k0 = 0xbfc0d968; k1 = 0xf1c;
3467 ra = 0xf0001234; // just to easily detect attempts to return
3468 psxRegs.CP0.n.Cause = 0x20;
3469 psxRegs.CP0.n.EPC = 0xbfc0d964; // EnterCriticalSection syscall
3470
3471 hw[0x1000/4] = SWAP32(0x1f000000);
3472 hw[0x1004/4] = SWAP32(0x1f802000);
3473 hw[0x1008/4] = SWAP32(0x0013243f);
3474 hw[0x100c/4] = SWAP32(0x00003022);
3475 hw[0x1010/4] = SWAP32(0x0013243f);
3476 hw[0x1014/4] = SWAP32(0x200931e1);
3477 hw[0x1018/4] = SWAP32(0x00020943);
3478 hw[0x101c/4] = SWAP32(0x00070777);
3479 hw[0x1020/4] = SWAP32(0x0000132c);
3480 hw[0x1060/4] = SWAP32(0x00000b88);
3481 hw[0x1070/4] = SWAP32(0x00000001);
3482 hw[0x1074/4] = SWAP32(0x0000000c);
3483 hw[0x2040/4] = SWAP32(0x00000900);
3484 }
3485
3486 hw[0x10a0/4] = SWAP32(0x00ffffff);
3487 hw[0x10a8/4] = SWAP32(0x00000401);
3488 hw[0x10b0/4] = SWAP32(0x0008b000);
3489 hw[0x10b4/4] = SWAP32(0x00010200);
3490 hw[0x10e0/4] = SWAP32(0x000eccf4);
3491 hw[0x10e4/4] = SWAP32(0x00000400);
3492 hw[0x10e8/4] = SWAP32(0x00000002);
3493 hw[0x10f0/4] = SWAP32(0x00009099);
3494 hw[0x10f4/4] = SWAP32(0x8c8c0000);
3495
3496 if (hle) {
3497 psxRcntWmode(0, 0);
3498 psxRcntWmode(1, 0);
3499 psxRcntWmode(2, 0);
3500 }
3501
3502 // gpu
3503 for (i = 0; i < sizeof(gpu_ctl_def) / sizeof(gpu_ctl_def[0]); i++)
3504 GPU_writeStatus(gpu_ctl_def[i]);
3505 for (i = 0; i < sizeof(gpu_data_def) / sizeof(gpu_data_def[0]); i++)
3506 GPU_writeData(gpu_data_def[i]);
3507
3508 // spu
3509 for (i = 0x1f801d80; i < sizeof(spu_config) / sizeof(spu_config[0]); i++)
3510 SPU_writeRegister(0x1f801d80 + i*2, spu_config[i], psxRegs.cycle);
3511}
3512
3513static void hleExc0_0_1();
3514static void hleExc0_0_2();
3515static void hleExc0_1_1();
3516static void hleExc0_1_2();
3517
3518#include "sjisfont.h"
3519
3520void psxBiosInit() {
3521 u32 *ptr, *ram32, *rom32;
3522 char *romc;
3523 int i;
3524 uLongf len;
3525
3526 psxRegs.biosBranchCheck = ~0;
3527
3528 memset(psxM, 0, 0x10000);
3529 for(i = 0; i < 256; i++) {
3530 biosA0[i] = NULL;
3531 biosB0[i] = NULL;
3532 biosC0[i] = NULL;
3533 }
3534 biosA0[0x03] = biosB0[0x35] = psxBios_write_psxout;
3535 biosA0[0x3c] = biosB0[0x3d] = psxBios_putchar_psxout;
3536 biosA0[0x3e] = biosB0[0x3f] = psxBios_puts_psxout;
3537 biosA0[0x3f] = psxBios_printf_psxout;
3538
3539 if (!Config.HLE) {
3540 char verstr[0x24+1];
3541 rom32 = (u32 *)psxR;
3542 memcpy(verstr, psxR + 0x12c, 0x24);
3543 verstr[0x24] = 0;
3544 SysPrintf("BIOS: %08x, '%s', '%c'\n", SWAP32(rom32[0x100/4]),
3545 verstr, psxR[0x7ff52]);
3546 return;
3547 }
3548
3549 for(i = 0; i < 256; i++) {
3550 if (biosA0[i] == NULL) biosA0[i] = psxBios_dummy;
3551 if (biosB0[i] == NULL) biosB0[i] = psxBios_dummy;
3552 if (biosC0[i] == NULL) biosC0[i] = psxBios_dummy;
3553 }
3554
3555 biosA0[0x00] = psxBios_open;
3556 biosA0[0x01] = psxBios_lseek;
3557 biosA0[0x02] = psxBios_read;
3558 biosA0[0x03] = psxBios_write;
3559 biosA0[0x04] = psxBios_close;
3560 //biosA0[0x05] = psxBios_ioctl;
3561 //biosA0[0x06] = psxBios_exit;
3562 //biosA0[0x07] = psxBios_sys_a0_07;
3563 biosA0[0x08] = psxBios_getc;
3564 biosA0[0x09] = psxBios_putc;
3565 biosA0[0x0a] = psxBios_todigit;
3566 //biosA0[0x0b] = psxBios_atof;
3567 biosA0[0x0c] = psxBios_strtoul;
3568 biosA0[0x0d] = psxBios_strtol;
3569 biosA0[0x0e] = psxBios_abs;
3570 biosA0[0x0f] = psxBios_labs;
3571 biosA0[0x10] = psxBios_atoi;
3572 biosA0[0x11] = psxBios_atol;
3573 //biosA0[0x12] = psxBios_atob;
3574 biosA0[0x13] = psxBios_setjmp;
3575 biosA0[0x14] = psxBios_longjmp;
3576 biosA0[0x15] = psxBios_strcat;
3577 biosA0[0x16] = psxBios_strncat;
3578 biosA0[0x17] = psxBios_strcmp;
3579 biosA0[0x18] = psxBios_strncmp;
3580 biosA0[0x19] = psxBios_strcpy;
3581 biosA0[0x1a] = psxBios_strncpy;
3582 biosA0[0x1b] = psxBios_strlen;
3583 biosA0[0x1c] = psxBios_index;
3584 biosA0[0x1d] = psxBios_rindex;
3585 biosA0[0x1e] = psxBios_strchr;
3586 biosA0[0x1f] = psxBios_strrchr;
3587 biosA0[0x20] = psxBios_strpbrk;
3588 biosA0[0x21] = psxBios_strspn;
3589 biosA0[0x22] = psxBios_strcspn;
3590 biosA0[0x23] = psxBios_strtok;
3591 biosA0[0x24] = psxBios_strstr;
3592 biosA0[0x25] = psxBios_toupper;
3593 biosA0[0x26] = psxBios_tolower;
3594 biosA0[0x27] = psxBios_bcopy;
3595 biosA0[0x28] = psxBios_bzero;
3596 biosA0[0x29] = psxBios_bcmp;
3597 biosA0[0x2a] = psxBios_memcpy;
3598 biosA0[0x2b] = psxBios_memset;
3599 biosA0[0x2c] = psxBios_memmove;
3600 biosA0[0x2d] = psxBios_memcmp;
3601 biosA0[0x2e] = psxBios_memchr;
3602 biosA0[0x2f] = psxBios_rand;
3603 biosA0[0x30] = psxBios_srand;
3604 biosA0[0x31] = psxBios_qsort;
3605 //biosA0[0x32] = psxBios_strtod;
3606 biosA0[0x33] = psxBios_malloc;
3607 biosA0[0x34] = psxBios_free;
3608 //biosA0[0x35] = psxBios_lsearch;
3609 //biosA0[0x36] = psxBios_bsearch;
3610 biosA0[0x37] = psxBios_calloc;
3611 biosA0[0x38] = psxBios_realloc;
3612 biosA0[0x39] = psxBios_InitHeap;
3613 //biosA0[0x3a] = psxBios__exit;
3614 biosA0[0x3b] = psxBios_getchar;
3615 biosA0[0x3c] = psxBios_putchar;
3616 //biosA0[0x3d] = psxBios_gets;
3617 biosA0[0x3e] = psxBios_puts;
3618 biosA0[0x3f] = psxBios_printf;
3619 biosA0[0x40] = psxBios_SystemErrorUnresolvedException;
3620 //biosA0[0x41] = psxBios_LoadTest;
3621 biosA0[0x42] = psxBios_Load;
3622 biosA0[0x43] = psxBios_Exec;
3623 biosA0[0x44] = psxBios_FlushCache;
3624 //biosA0[0x45] = psxBios_InstallInterruptHandler;
3625 biosA0[0x46] = psxBios_GPU_dw;
3626 biosA0[0x47] = psxBios_mem2vram;
3627 biosA0[0x48] = psxBios_SendGPU;
3628 biosA0[0x49] = psxBios_GPU_cw;
3629 biosA0[0x4a] = psxBios_GPU_cwb;
3630 biosA0[0x4b] = psxBios_GPU_SendPackets;
3631 biosA0[0x4c] = psxBios_sys_a0_4c;
3632 biosA0[0x4d] = psxBios_GPU_GetGPUStatus;
3633 //biosA0[0x4e] = psxBios_GPU_sync;
3634 //biosA0[0x4f] = psxBios_sys_a0_4f;
3635 //biosA0[0x50] = psxBios_sys_a0_50;
3636 biosA0[0x51] = psxBios_LoadExec;
3637 //biosA0[0x52] = psxBios_GetSysSp;
3638 //biosA0[0x53] = psxBios_sys_a0_53;
3639 biosA0[0x54] = psxBios_CdInit;
3640 //biosA0[0x55] = psxBios__bu_init_a55;
3641 biosA0[0x56] = psxBios_CdRemove;
3642 //biosA0[0x57] = psxBios_sys_a0_57;
3643 //biosA0[0x58] = psxBios_sys_a0_58;
3644 //biosA0[0x59] = psxBios_sys_a0_59;
3645 //biosA0[0x5a] = psxBios_sys_a0_5a;
3646 //biosA0[0x5b] = psxBios_dev_tty_init;
3647 //biosA0[0x5c] = psxBios_dev_tty_open;
3648 //biosA0[0x5d] = psxBios_sys_a0_5d;
3649 //biosA0[0x5e] = psxBios_dev_tty_ioctl;
3650 //biosA0[0x5f] = psxBios_dev_cd_open;
3651 //biosA0[0x60] = psxBios_dev_cd_read;
3652 //biosA0[0x61] = psxBios_dev_cd_close;
3653 //biosA0[0x62] = psxBios_dev_cd_firstfile;
3654 //biosA0[0x63] = psxBios_dev_cd_nextfile;
3655 //biosA0[0x64] = psxBios_dev_cd_chdir;
3656 //biosA0[0x65] = psxBios_dev_card_open;
3657 //biosA0[0x66] = psxBios_dev_card_read;
3658 //biosA0[0x67] = psxBios_dev_card_write;
3659 //biosA0[0x68] = psxBios_dev_card_close;
3660 //biosA0[0x69] = psxBios_dev_card_firstfile;
3661 //biosA0[0x6a] = psxBios_dev_card_nextfile;
3662 //biosA0[0x6b] = psxBios_dev_card_erase;
3663 //biosA0[0x6c] = psxBios_dev_card_undelete;
3664 //biosA0[0x6d] = psxBios_dev_card_format;
3665 //biosA0[0x6e] = psxBios_dev_card_rename;
3666 //biosA0[0x6f] = psxBios_dev_card_6f;
3667 biosA0[0x70] = psxBios__bu_init;
3668 biosA0[0x71] = psxBios_CdInit;
3669 biosA0[0x72] = psxBios_CdRemove;
3670 //biosA0[0x73] = psxBios_sys_a0_73;
3671 //biosA0[0x74] = psxBios_sys_a0_74;
3672 //biosA0[0x75] = psxBios_sys_a0_75;
3673 //biosA0[0x76] = psxBios_sys_a0_76;
3674 //biosA0[0x77] = psxBios_sys_a0_77;
3675 //biosA0[0x78] = psxBios__96_CdSeekL;
3676 //biosA0[0x79] = psxBios_sys_a0_79;
3677 //biosA0[0x7a] = psxBios_sys_a0_7a;
3678 //biosA0[0x7b] = psxBios_sys_a0_7b;
3679 //biosA0[0x7c] = psxBios__96_CdGetStatus;
3680 //biosA0[0x7d] = psxBios_sys_a0_7d;
3681 //biosA0[0x7e] = psxBios__96_CdRead;
3682 //biosA0[0x7f] = psxBios_sys_a0_7f;
3683 //biosA0[0x80] = psxBios_sys_a0_80;
3684 //biosA0[0x81] = psxBios_sys_a0_81;
3685 //biosA0[0x82] = psxBios_sys_a0_82;
3686 //biosA0[0x83] = psxBios_sys_a0_83;
3687 //biosA0[0x84] = psxBios_sys_a0_84;
3688 //biosA0[0x85] = psxBios__96_CdStop;
3689 //biosA0[0x86] = psxBios_sys_a0_86;
3690 //biosA0[0x87] = psxBios_sys_a0_87;
3691 //biosA0[0x88] = psxBios_sys_a0_88;
3692 //biosA0[0x89] = psxBios_sys_a0_89;
3693 //biosA0[0x8a] = psxBios_sys_a0_8a;
3694 //biosA0[0x8b] = psxBios_sys_a0_8b;
3695 //biosA0[0x8c] = psxBios_sys_a0_8c;
3696 //biosA0[0x8d] = psxBios_sys_a0_8d;
3697 //biosA0[0x8e] = psxBios_sys_a0_8e;
3698 //biosA0[0x8f] = psxBios_sys_a0_8f;
3699 biosA0[0x90] = hleExc0_1_2;
3700 biosA0[0x91] = hleExc0_0_2;
3701 biosA0[0x92] = hleExc0_1_1;
3702 biosA0[0x93] = hleExc0_0_1;
3703 //biosA0[0x94] = psxBios_sys_a0_94;
3704 biosA0[0x95] = psxBios_CdReset;
3705 //biosA0[0x96] = psxBios_AddCDROMDevice;
3706 //biosA0[0x97] = psxBios_AddMemCardDevide;
3707 //biosA0[0x98] = psxBios_DisableKernelIORedirection;
3708 //biosA0[0x99] = psxBios_EnableKernelIORedirection;
3709 //biosA0[0x9a] = psxBios_sys_a0_9a;
3710 //biosA0[0x9b] = psxBios_sys_a0_9b;
3711 biosA0[0x9c] = psxBios_SetConf;
3712 biosA0[0x9d] = psxBios_GetConf;
3713 //biosA0[0x9e] = psxBios_sys_a0_9e;
3714 biosA0[0x9f] = psxBios_SetMem;
3715 //biosA0[0xa0] = psxBios__boot;
3716 //biosA0[0xa1] = psxBios_SystemError;
3717 biosA0[0xa2] = psxBios_EnqueueCdIntr;
3718 biosA0[0xa3] = psxBios_DequeueCdIntr;
3719 //biosA0[0xa4] = psxBios_sys_a0_a4;
3720 //biosA0[0xa5] = psxBios_ReadSector;
3721 biosA0[0xa6] = psxBios_get_cd_status;
3722 //biosA0[0xa7] = psxBios_bufs_cb_0;
3723 //biosA0[0xa8] = psxBios_bufs_cb_1;
3724 //biosA0[0xa9] = psxBios_bufs_cb_2;
3725 //biosA0[0xaa] = psxBios_bufs_cb_3;
3726 biosA0[0xab] = psxBios__card_info;
3727 biosA0[0xac] = psxBios__card_load;
3728 //biosA0[0axd] = psxBios__card_auto;
3729 //biosA0[0xae] = psxBios_bufs_cd_4;
3730 //biosA0[0xaf] = psxBios_sys_a0_af;
3731 //biosA0[0xb0] = psxBios_sys_a0_b0;
3732 //biosA0[0xb1] = psxBios_sys_a0_b1;
3733 //biosA0[0xb2] = psxBios_do_a_long_jmp
3734 //biosA0[0xb3] = psxBios_sys_a0_b3;
3735 biosA0[0xb4] = psxBios_GetSystemInfo;
3736//*******************B0 CALLS****************************
3737 biosB0[0x00] = psxBios_SysMalloc;
3738 //biosB0[0x01] = psxBios_sys_b0_01;
3739 biosB0[0x02] = psxBios_SetRCnt;
3740 biosB0[0x03] = psxBios_GetRCnt;
3741 biosB0[0x04] = psxBios_StartRCnt;
3742 biosB0[0x05] = psxBios_StopRCnt;
3743 biosB0[0x06] = psxBios_ResetRCnt;
3744 biosB0[0x07] = psxBios_DeliverEvent;
3745 biosB0[0x08] = psxBios_OpenEvent;
3746 biosB0[0x09] = psxBios_CloseEvent;
3747 biosB0[0x0a] = psxBios_WaitEvent;
3748 biosB0[0x0b] = psxBios_TestEvent;
3749 biosB0[0x0c] = psxBios_EnableEvent;
3750 biosB0[0x0d] = psxBios_DisableEvent;
3751 biosB0[0x0e] = psxBios_OpenTh;
3752 biosB0[0x0f] = psxBios_CloseTh;
3753 biosB0[0x10] = psxBios_ChangeTh;
3754 //biosB0[0x11] = psxBios_psxBios_b0_11;
3755 biosB0[0x12] = psxBios_InitPAD;
3756 biosB0[0x13] = psxBios_StartPAD;
3757 biosB0[0x14] = psxBios_StopPAD;
3758 biosB0[0x15] = psxBios_PAD_init;
3759 biosB0[0x16] = psxBios_PAD_dr;
3760 biosB0[0x17] = psxBios_ReturnFromException;
3761 biosB0[0x18] = psxBios_ResetEntryInt;
3762 biosB0[0x19] = psxBios_HookEntryInt;
3763 //biosB0[0x1a] = psxBios_sys_b0_1a;
3764 //biosB0[0x1b] = psxBios_sys_b0_1b;
3765 //biosB0[0x1c] = psxBios_sys_b0_1c;
3766 //biosB0[0x1d] = psxBios_sys_b0_1d;
3767 //biosB0[0x1e] = psxBios_sys_b0_1e;
3768 //biosB0[0x1f] = psxBios_sys_b0_1f;
3769 biosB0[0x20] = psxBios_UnDeliverEvent;
3770 //biosB0[0x21] = psxBios_sys_b0_21;
3771 //biosB0[0x22] = psxBios_sys_b0_22;
3772 //biosB0[0x23] = psxBios_sys_b0_23;
3773 //biosB0[0x24] = psxBios_sys_b0_24;
3774 //biosB0[0x25] = psxBios_sys_b0_25;
3775 //biosB0[0x26] = psxBios_sys_b0_26;
3776 //biosB0[0x27] = psxBios_sys_b0_27;
3777 //biosB0[0x28] = psxBios_sys_b0_28;
3778 //biosB0[0x29] = psxBios_sys_b0_29;
3779 //biosB0[0x2a] = psxBios_sys_b0_2a;
3780 //biosB0[0x2b] = psxBios_sys_b0_2b;
3781 //biosB0[0x2c] = psxBios_sys_b0_2c;
3782 //biosB0[0x2d] = psxBios_sys_b0_2d;
3783 //biosB0[0x2e] = psxBios_sys_b0_2e;
3784 //biosB0[0x2f] = psxBios_sys_b0_2f;
3785 //biosB0[0x30] = psxBios_sys_b0_30;
3786 //biosB0[0x31] = psxBios_sys_b0_31;
3787 biosB0[0x32] = psxBios_open;
3788 biosB0[0x33] = psxBios_lseek;
3789 biosB0[0x34] = psxBios_read;
3790 biosB0[0x35] = psxBios_write;
3791 biosB0[0x36] = psxBios_close;
3792 //biosB0[0x37] = psxBios_ioctl;
3793 //biosB0[0x38] = psxBios_exit;
3794 //biosB0[0x39] = psxBios_sys_b0_39;
3795 //biosB0[0x3a] = psxBios_getc;
3796 //biosB0[0x3b] = psxBios_putc;
3797 biosB0[0x3c] = psxBios_getchar;
3798 biosB0[0x3d] = psxBios_putchar;
3799 //biosB0[0x3e] = psxBios_gets;
3800 biosB0[0x3f] = psxBios_puts;
3801 biosB0[0x40] = psxBios_cd;
3802 biosB0[0x41] = psxBios_format;
3803 biosB0[0x42] = psxBios_firstfile;
3804 biosB0[0x43] = psxBios_nextfile;
3805 biosB0[0x44] = psxBios_rename;
3806 biosB0[0x45] = psxBios_delete;
3807 //biosB0[0x46] = psxBios_undelete;
3808 //biosB0[0x47] = psxBios_AddDevice;
3809 //biosB0[0x48] = psxBios_RemoteDevice;
3810 //biosB0[0x49] = psxBios_PrintInstalledDevices;
3811 biosB0[0x4a] = psxBios_InitCARD;
3812 biosB0[0x4b] = psxBios_StartCARD;
3813 biosB0[0x4c] = psxBios_StopCARD;
3814 //biosB0[0x4d] = psxBios_sys_b0_4d;
3815 biosB0[0x4e] = psxBios__card_write;
3816 biosB0[0x4f] = psxBios__card_read;
3817 biosB0[0x50] = psxBios__new_card;
3818 biosB0[0x51] = psxBios_Krom2RawAdd;
3819 //biosB0[0x52] = psxBios_sys_b0_52;
3820 //biosB0[0x53] = psxBios_sys_b0_53;
3821 //biosB0[0x54] = psxBios__get_errno;
3822 biosB0[0x55] = psxBios__get_error;
3823 biosB0[0x56] = psxBios_GetC0Table;
3824 biosB0[0x57] = psxBios_GetB0Table;
3825 biosB0[0x58] = psxBios__card_chan;
3826 //biosB0[0x59] = psxBios_sys_b0_59;
3827 //biosB0[0x5a] = psxBios_sys_b0_5a;
3828 biosB0[0x5b] = psxBios_ChangeClearPad;
3829 biosB0[0x5c] = psxBios__card_status;
3830 biosB0[0x5d] = psxBios__card_wait;
3831//*******************C0 CALLS****************************
3832 biosC0[0x00] = psxBios_InitRCnt;
3833 biosC0[0x01] = psxBios_InitException;
3834 biosC0[0x02] = psxBios_SysEnqIntRP;
3835 biosC0[0x03] = psxBios_SysDeqIntRP;
3836 biosC0[0x04] = psxBios_get_free_EvCB_slot;
3837 //biosC0[0x05] = psxBios_get_free_TCB_slot;
3838 //biosC0[0x06] = psxBios_ExceptionHandler;
3839 //biosC0[0x07] = psxBios_InstallExeptionHandler;
3840 biosC0[0x08] = psxBios_SysInitMemory;
3841 //biosC0[0x09] = psxBios_SysInitKMem;
3842 biosC0[0x0a] = psxBios_ChangeClearRCnt;
3843 //biosC0[0x0b] = psxBios_SystemError;
3844 biosC0[0x0c] = psxBios_InitDefInt;
3845 //biosC0[0x0d] = psxBios_sys_c0_0d;
3846 //biosC0[0x0e] = psxBios_sys_c0_0e;
3847 //biosC0[0x0f] = psxBios_sys_c0_0f;
3848 //biosC0[0x10] = psxBios_sys_c0_10;
3849 //biosC0[0x11] = psxBios_sys_c0_11;
3850 //biosC0[0x12] = psxBios_InstallDevices;
3851 //biosC0[0x13] = psxBios_FlushStfInOutPut;
3852 //biosC0[0x14] = psxBios_sys_c0_14;
3853 //biosC0[0x15] = psxBios__cdevinput;
3854 //biosC0[0x16] = psxBios__cdevscan;
3855 //biosC0[0x17] = psxBios__circgetc;
3856 //biosC0[0x18] = psxBios__circputc;
3857 //biosC0[0x19] = psxBios_ioabort;
3858 //biosC0[0x1a] = psxBios_sys_c0_1a
3859 //biosC0[0x1b] = psxBios_KernelRedirect;
3860 //biosC0[0x1c] = psxBios_PatchAOTable;
3861//************** THE END ***************************************
3862/**/
3863
3864 memset(FDesc, 0, sizeof(FDesc));
3865 memset(cdir, 0, sizeof(cdir));
3866 floodchk = 0;
3867
3868 // somewhat pretend to be a SCPH1001 BIOS
3869 // some games look for these and take an exception if they're missing
3870 rom32 = (u32 *)psxR;
3871 rom32[0x100/4] = SWAP32(0x19951204);
3872 rom32[0x104/4] = SWAP32(3);
3873 romc = (char *)psxR;
3874 strcpy(romc + 0x108, "PCSX authors");
3875 strcpy(romc + 0x12c, "CEX-3000 PCSX HLE"); // see psxBios_GetSystemInfo
3876 strcpy(romc + 0x7ff32, "System ROM Version 2.2 12/04/95 A");
3877 strcpy(romc + 0x7ff54, "GPL-2.0-or-later");
3878
3879 // fonts
3880 len = 0x80000 - 0x66000;
3881 uncompress((Bytef *)(psxR + 0x66000), &len, font_8140, sizeof(font_8140));
3882 len = 0x80000 - 0x69d68;
3883 uncompress((Bytef *)(psxR + 0x69d68), &len, font_889f, sizeof(font_889f));
3884
3885 // trap attempts to call bios directly
3886 rom32[0x00000/4] = HLEOP(hleop_dummy);
3887 rom32[0x00180/4] = HLEOP(hleop_dummy);
3888 rom32[0x3fffc/4] = HLEOP(hleop_dummy);
3889 rom32[0x65ffc/4] = HLEOP(hleop_dummy);
3890 rom32[0x7ff2c/4] = HLEOP(hleop_dummy);
3891
3892 /* Some games like R-Types, CTR, Fade to Black read from adress 0x00000000 due to uninitialized pointers.
3893 See Garbage Area at Address 00000000h in Nocash PSX Specfications for more information.
3894 Here are some examples of games not working with this fix in place :
3895 R-type won't get past the Irem logo if not implemented.
3896 Crash Team Racing will softlock after the Sony logo.
3897 */
3898
3899 ram32 = (u32 *)psxM;
3900 ram32[0x0000/4] = SWAPu32(0x00000003); // lui $k0, 0 (overwritten by 3)
3901 ram32[0x0004/4] = SWAPu32(0x275a0000 + A_EXCEPTION); // addiu $k0, $k0, 0xc80
3902 ram32[0x0008/4] = SWAPu32(0x03400008); // jr $k0
3903 ram32[0x000c/4] = SWAPu32(0x00000000); // nop
3904
3905 ram32[0x0060/4] = SWAPu32(0x00000002); // ram size?
3906 ram32[0x0068/4] = SWAPu32(0x000000ff); // unknown
3907
3908 ram32[0x0080/4] = SWAPu32(0x3c1a0000); // lui $k0, 0 // exception vector
3909 ram32[0x0084/4] = SWAPu32(0x275a0000 + A_EXCEPTION); // addiu $k0, $k0, 0xc80
3910 ram32[0x0088/4] = SWAPu32(0x03400008); // jr $k0
3911 ram32[0x008c/4] = SWAPu32(0x00000000); // nop
3912
3913 ram32[0x00a0/4] = HLEOP(hleop_a0);
3914 ram32[0x00b0/4] = HLEOP(hleop_b0);
3915 ram32[0x00c0/4] = HLEOP(hleop_c0);
3916
3917 setup_tt(4, 16, 0x801fff00);
3918 DeliverEvent(0xf0000003, 0x0010);
3919
3920 ram32[0x6ee0/4] = SWAPu32(0x0000eff0); // DCB
3921 strcpy((char *)&ram32[0xeff0/4], "bu");
3922
3923 // default exception handler chains
3924 // see also setup_cd_irq_and_events()
3925 write_chain(&ram32[0x91e0/4], 0x91d0, 0xbfc050a4, 0xbfc04fbc); // chain0.e0
3926 write_chain(&ram32[0x91d0/4], 0x6da8, 0xbfc0506c, 0xbfc04dec); // chain0.e1
3927 write_chain(&ram32[0x6da8/4], 0, 0, 0x1a00); // chain0.e2
3928 write_chain(&ram32[0x6d88/4], 0x6d78, 0x19c8, 0x18bc); // chain1.e0
3929 write_chain(&ram32[0x6d78/4], 0x6d68, 0x1990, 0x1858); // chain1.e1
3930 write_chain(&ram32[0x6d68/4], 0x6d58, 0x1958, 0x17f4); // chain1.e2
3931 write_chain(&ram32[0x6d58/4], 0, 0x1920, 0x1794); // chain1.e3
3932 write_chain(&ram32[0x6d98/4], 0, 0, 0x2458); // chain3.e0
3933
3934 setup_mips_code();
3935
3936 // fill the api jumptables with fake entries as some games patch them
3937 // (or rather the funcs listed there)
3938 // also trap the destination as some "Cheats Edition" thing overrides the
3939 // dispatcher with a wrapper and then jumps to the table entries directly
3940 ptr = (u32 *)&psxM[A_A0_TABLE];
3941 for (i = 0; i < 256; i++) {
3942 ptr[i] = SWAP32(A_A0_TRAPS + i*4);
3943 ram32[A_A0_TRAPS/4 + i] = HLEOP(hleop_a0t);
3944 }
3945 ptr = (u32 *)&psxM[A_B0_TABLE];
3946 for (i = 0; i < 256; i++) {
3947 ptr[i] = SWAP32(A_B0_TRAPS + i*4);
3948 ram32[A_B0_TRAPS/4 + i] = HLEOP(hleop_b0t);
3949 }
3950 // B(5b) is special because games patch (sometimes even jump to)
3951 // code at fixed offsets from it, nocash lists offsets:
3952 // patch: +3d8, +4dc, +594, +62c, +9c8, +1988
3953 // call: +7a0=4b70, +884=4c54, +894=4c64
3954 ptr[0x5b] = SWAP32(A_B0_5B_TRAP); // 0x43d0
3955 ram32[A_B0_5B_TRAP/4] = HLEOP(hleop_b0t);
3956
3957 ram32[0x4b70/4] = SWAP32(0x03e00008); // jr $ra // setPadOutputBuf
3958
3959 ram32[0x4c54/4] = SWAP32(0x240e0001); // mov $t6, 1
3960 ram32[0x4c58/4] = SWAP32(0x03e00008); // jr $ra
3961 ram32[0x4c5c/4] = SWAP32(0xac0e0000 + A_PAD_IRQR_ENA); // sw $t6, ...
3962
3963 ram32[0x4c64/4] = SWAP32(0x03e00008); // jr $ra
3964 ram32[0x4c68/4] = SWAP32(0xac000000 + A_PAD_IRQR_ENA); // sw $0, ...
3965
3966 ptr = (u32 *)&psxM[A_C0_TABLE];
3967 for (i = 0; i < 256/2; i++) {
3968 ptr[i] = SWAP32(A_C0_TRAPS + i*4);
3969 ram32[A_C0_TRAPS/4 + i] = HLEOP(hleop_c0t);
3970 }
3971 ptr[6] = SWAP32(A_EXCEPTION);
3972
3973 // more HLE traps
3974 ram32[A_A0_TRAPS/4 - 1] = HLEOP(hleop_dummy);
3975 ram32[A_B0_TRAPS/4 - 1] = HLEOP(hleop_dummy);
3976 ram32[A_C0_TRAPS/4 - 1] = HLEOP(hleop_dummy);
3977 ram32[0x7ffc/4] = HLEOP(hleop_dummy);
3978 ram32[0x8000/4] = HLEOP(hleop_execret);
3979
3980 ram32[A_EEXIT_PTR/4] = SWAP32(A_EEXIT_DEF);
3981 ram32[A_EXC_SP/4] = SWAP32(A_EXC_STACK);
3982 ram32[A_RCNT_VBL_ACK/4 + 0] = SWAP32(1);
3983 ram32[A_RCNT_VBL_ACK/4 + 1] = SWAP32(1);
3984 ram32[A_RCNT_VBL_ACK/4 + 2] = SWAP32(1);
3985 ram32[A_RCNT_VBL_ACK/4 + 3] = SWAP32(1);
3986 ram32[A_RND_SEED/4] = SWAPu32(0x24040001); // was 0xac20cc00
3987}
3988
3989void psxBiosShutdown() {
3990}
3991
3992void psxBiosCnfLoaded(u32 tcb_cnt, u32 evcb_cnt, u32 stack) {
3993 if (stack == 0)
3994 stack = 0x801FFF00;
3995 if (tcb_cnt != 4 || evcb_cnt != 16) {
3996 setup_tt(tcb_cnt, evcb_cnt, stack);
3997 DeliverEvent(0xf0000003, 0x0010);
3998 }
3999 storeRam32(A_CONF_SP, stack);
4000}
4001
4002#define psxBios_PADpoll(pad) { \
4003 int i, more_data = 0; \
4004 PAD##pad##_startPoll(pad); \
4005 pad_buf##pad[1] = PAD##pad##_poll(0x42, &more_data); \
4006 pad_buf##pad[0] = more_data ? 0 : 0xff; \
4007 PAD##pad##_poll(0, &more_data); \
4008 i = 2; \
4009 while (more_data) { \
4010 pad_buf##pad[i++] = PAD##pad##_poll(0, &more_data); \
4011 } \
4012}
4013
4014static void handle_chain_x_x_1(u32 enable, u32 irqbit)
4015{
4016 use_cycles(10);
4017 if (enable) {
4018 psxHwWrite16(0x1f801070, ~(1u << irqbit));
4019 psxBios_ReturnFromException();
4020 }
4021 else
4022 pc0 = ra;
4023}
4024
4025// hleExc0_{0,1}* are usually removed by A(56)/A(72) on the game's startup,
4026// so this is only partially implemented
4027static void hleExc0_0_1() // A(93h) - CdromDmaIrqFunc2
4028{
4029 u32 cdrom_dma_ack_enable = 1; // a000b93c
4030 handle_chain_x_x_1(cdrom_dma_ack_enable, 3); // IRQ3 DMA
4031}
4032
4033static void hleExc0_0_2() // A(91h) - CdromDmaIrqFunc1
4034{
4035 u32 ret = 0;
4036 //PSXBIOS_LOG("%s\n", __func__);
4037
4038 if (psxHu32(0x1074) & psxHu32(0x1070) & 8) { // IRQ3 DMA
4039 psxHwWrite32(0x1f8010f4, (psxHu32(0x10f4) & 0xffffff) | 0x88000000);
4040 //if (--cdrom_irq_counter == 0) // 0xa0009180
4041 // DeliverEvent(0xf0000003, 0x10);
4042 use_cycles(22);
4043 ret = 1;
4044 }
4045 mips_return_c(ret, 20);
4046}
4047
4048static void hleExc0_1_1() // A(92h) - CdromIoIrqFunc2
4049{
4050 u32 cdrom_irq_ack_enable = 1; // a000b938
4051 handle_chain_x_x_1(cdrom_irq_ack_enable, 2); // IRQ2 cdrom
4052}
4053
4054static void hleExc0_1_2() // A(90h) - CdromIoIrqFunc1
4055{
4056 u32 ret = 0;
4057 if (psxHu32(0x1074) & psxHu32(0x1070) & 4) { // IRQ2 cdrom
4058 PSXBIOS_LOG("%s TODO\n", __func__);
4059 ret = 1;
4060 }
4061 mips_return_c(ret, 20);
4062}
4063
4064static void hleExc0_2_2_syscall() // not in any A/B/C table
4065{
4066 u32 tcbPtr = loadRam32(A_TT_PCB);
4067 TCB *tcb = loadRam32ptr(tcbPtr);
4068 u32 code = (SWAP32(tcb->cause) & 0x3c) >> 2;
4069
4070 if (code != R3000E_Syscall) {
4071 if (code != 0) {
4072 DeliverEvent(0xf0000010, 0x1000);
4073 //psxBios_SystemErrorUnresolvedException();
4074 }
4075 mips_return_c(0, 17);
4076 return;
4077 }
4078
4079 //printf("%s c=%d a0=%d\n", __func__, code, SWAP32(tcb->reg[4]));
4080 tcb->epc += SWAP32(4);
4081 switch (SWAP32(tcb->reg[4])) { // a0
4082 case 0: // noop
4083 break;
4084
4085 case 1: { // EnterCritical - disable irqs
4086 u32 was_enabled = ((SWAP32(tcb->sr) & 0x404) == 0x404);
4087 tcb->reg[2] = SWAP32(was_enabled);
4088 tcb->sr &= SWAP32(~0x404);
4089 break;
4090 }
4091 case 2: // ExitCritical - enable irqs
4092 tcb->sr |= SWAP32(0x404);
4093 break;
4094
4095 case 3: { // ChangeThreadSubFunction
4096 u32 tcbPtr = loadRam32(A_TT_PCB);
4097 storeRam32(tcbPtr, SWAP32(tcb->reg[5])); // a1
4098 break;
4099 }
4100 default:
4101 DeliverEvent(0xf0000010, 0x4000);
4102 break;
4103 }
4104 use_cycles(30);
4105 psxBios_ReturnFromException();
4106}
4107
4108static void hleExc1_0_1(void)
4109{
4110 u32 vbl_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x0c); // 860c
4111 handle_chain_x_x_1(vbl_irq_ack_enable, 0); // IRQ0 vblank
4112}
4113
4114static void handle_chain_1_x_2(u32 ev_index, u32 irqbit)
4115{
4116 u32 ret = 0;
4117 if (psxHu32(0x1074) & psxHu32(0x1070) & (1u << irqbit)) {
4118 DeliverEvent(0xf2000000 + ev_index, 0x0002);
4119 ret = 1;
4120 }
4121 mips_return_c(ret, 22);
4122}
4123
4124static void hleExc1_0_2(void)
4125{
4126 handle_chain_1_x_2(3, 0); // IRQ0 vblank
4127}
4128
4129static void hleExc1_1_1(void)
4130{
4131 u32 rcnt_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x08); // 8608
4132 handle_chain_x_x_1(rcnt_irq_ack_enable, 6); // IRQ6 rcnt2
4133}
4134
4135static void hleExc1_1_2(void)
4136{
4137 handle_chain_1_x_2(2, 6); // IRQ6 rcnt2
4138}
4139
4140static void hleExc1_2_1(void)
4141{
4142 u32 rcnt_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x04); // 8604
4143 handle_chain_x_x_1(rcnt_irq_ack_enable, 5); // IRQ5 rcnt1
4144}
4145
4146static void hleExc1_2_2(void)
4147{
4148 handle_chain_1_x_2(1, 5); // IRQ5 rcnt1
4149}
4150
4151static void hleExc1_3_1(void)
4152{
4153 u32 rcnt_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x00); // 8600
4154 handle_chain_x_x_1(rcnt_irq_ack_enable, 4); // IRQ4 rcnt0
4155}
4156
4157static void hleExc1_3_2(void)
4158{
4159 handle_chain_1_x_2(0, 4); // IRQ4 rcnt0
4160}
4161
4162static void hleExc3_0_2_defint(void)
4163{
4164 static const struct {
4165 u8 ev, irqbit;
4166 } tab[] = {
4167 { 3, 2 }, // cdrom
4168 { 9, 9 }, // spu
4169 { 2, 1 }, // gpu
4170 { 10, 10 }, // io
4171 { 11, 8 }, // sio
4172 { 1, 0 }, // vbl
4173 { 5, 4 }, // rcnt0
4174 { 6, 5 }, // rcnt1
4175 { 6, 6 }, // rcnt2 (bug)
4176 { 8, 7 }, // sio rx
4177 { 4, 3 }, // sio
4178 };
4179 size_t i;
4180 for (i = 0; i < sizeof(tab) / sizeof(tab[0]); i++) {
4181 if (psxHu32(0x1074) & psxHu32(0x1070) & (1u << tab[i].irqbit)) {
4182 DeliverEvent(0xf0000000 + tab[i].ev, 0x1000);
4183 use_cycles(7);
4184 }
4185
4186 }
4187 mips_return_c(0, 11 + 7*11 + 7*11 + 12);
4188}
4189
4190static void hleExcPadCard1(void)
4191{
4192 if (loadRam32(A_PAD_IRQR_ENA)) {
4193 u8 *pad_buf1 = loadRam8ptr(A_PAD_INBUF + 0);
4194 u8 *pad_buf2 = loadRam8ptr(A_PAD_INBUF + 4);
4195
4196 psxBios_PADpoll(1);
4197 psxBios_PADpoll(2);
4198 use_cycles(100);
4199 if (loadRam32(A_PAD_DR_DST))
4200 psxBios_PAD_dr_();
4201 }
4202 if (loadRam32(A_PAD_ACK_VBL))
4203 psxHwWrite16(0x1f801070, ~1);
4204 if (loadRam32(A_CARD_IRQR_ENA)) {
4205 // todo, maybe
4206 }
4207
4208 mips_return_c(0, 18);
4209}
4210
4211static void hleExcPadCard2(void)
4212{
4213 u32 ret = psxHu32(0x1074) & psxHu32(0x1070) & 1;
4214 mips_return_c(ret, 15);
4215}
4216
4217void psxBiosException() {
4218 u32 tcbPtr = loadRam32(A_TT_PCB);
4219 u32 *chains = loadRam32ptr(A_TT_ExCB);
4220 TCB *tcb = loadRam32ptr(tcbPtr);
4221 u32 ptr, *chain;
4222 int c, lim;
4223 int i;
4224
4225 // save the regs
4226 // $at, $v0, $v1, $ra already saved by the mips code at A_EXCEPTION
4227 for (i = 4; i < 31; i++) {
4228 if (i == 26) // $k0
4229 continue;
4230 tcb->reg[i] = SWAP32(psxRegs.GPR.r[i]);
4231 }
4232 tcb->lo = SWAP32(psxRegs.GPR.n.lo);
4233 tcb->hi = SWAP32(psxRegs.GPR.n.hi);
4234 //tcb->epc = SWAP32(psxRegs.CP0.n.EPC); // done by asm
4235 tcb->sr = SWAP32(psxRegs.CP0.n.SR);
4236 tcb->cause = SWAP32(psxRegs.CP0.n.Cause);
4237 sp = fp = loadRam32(A_EXC_SP);
4238 gp = A_EXC_GP;
4239 use_cycles(46);
4240 assert(!psxRegs.cpuInRecursion);
4241
4242 // do the chains (always 4)
4243 for (c = lim = 0; c < 4; c++) {
4244 if (chains[c * 2] == 0)
4245 continue;
4246 ptr = SWAP32(chains[c * 2]);
4247 for (; ptr && lim < 100; ptr = SWAP32(chain[0])) {
4248 chain = castRam32ptr(ptr);
4249 use_cycles(14);
4250 lim++;
4251 if (chain[2] == 0)
4252 continue;
4253 softCallInException(SWAP32(chain[2]));
4254 if (returned_from_exception())
4255 return;
4256
4257 if (v0 == 0 || chain[1] == 0)
4258 continue;
4259 softCallInException(SWAP32(chain[1]));
4260 if (returned_from_exception())
4261 return;
4262 }
4263 }
4264 assert(lim < 100);
4265
4266 // return from exception (custom or default)
4267 use_cycles(23);
4268 ptr = loadRam32(A_EEXIT_PTR);
4269 if (ptr != A_EEXIT_DEF) {
4270 const struct jmp_buf_ *jmp_buf = castRam32ptr(ptr);
4271 longjmp_load(jmp_buf);
4272 v0 = 1;
4273 pc0 = ra;
4274 return;
4275 }
4276 psxBios_ReturnFromException();
4277}
4278
4279/* HLE */
4280static void hleDummy() {
4281 log_unhandled("hleDummy called @%08x ra=%08x\n", psxRegs.pc - 4, ra);
4282 psxRegs.pc = ra;
4283 psxRegs.cycle += 1000;
4284
4285 psxBranchTest();
4286}
4287
4288static void hleA0() {
4289 u32 call = t1 & 0xff;
4290 u32 entry = loadRam32(A_A0_TABLE + call * 4);
4291
4292 use_cycles(4+7);
4293 if (call < 192 && entry != A_A0_TRAPS + call * 4) {
4294 PSXBIOS_LOG("custom A%02x %s(0x%x, ) addr=%08x ra=%08x\n",
4295 call, biosA0n[call], a0, entry, ra);
4296 softCall(entry);
4297 pc0 = ra;
4298 PSXBIOS_LOG(" -> %08x\n", v0);
4299 }
4300 else if (biosA0[call])
4301 biosA0[call]();
4302
4303 //printf("A(%02x) -> %x\n", call, v0);
4304 psxBranchTest();
4305}
4306
4307static void hleB0() {
4308 u32 call = t1 & 0xff;
4309 u32 entry = loadRam32(A_B0_TABLE + call * 4);
4310 int is_custom = 0;
4311
4312 use_cycles(4+7);
4313 if (call == 0x5b)
4314 is_custom = entry != A_B0_5B_TRAP;
4315 else
4316 is_custom = entry != A_B0_TRAPS + call * 4;
4317 if (is_custom) {
4318 PSXBIOS_LOG("custom B%02x %s(0x%x, ) addr=%08x ra=%08x\n",
4319 call, biosB0n[call], a0, entry, ra);
4320 softCall(entry);
4321 pc0 = ra;
4322 PSXBIOS_LOG(" -> %08x\n", v0);
4323 }
4324 else if (biosB0[call])
4325 biosB0[call]();
4326
4327 //printf("B(%02x) -> %x\n", call, v0);
4328 psxBranchTest();
4329}
4330
4331static void hleC0() {
4332 u32 call = t1 & 0xff;
4333 u32 entry = loadRam32(A_C0_TABLE + call * 4);
4334
4335 use_cycles(4+7);
4336 if (call < 128 && entry != A_C0_TRAPS + call * 4) {
4337 PSXBIOS_LOG("custom C%02x %s(0x%x, ) addr=%08x ra=%08x\n",
4338 call, biosC0n[call], a0, entry, ra);
4339 softCall(entry);
4340 pc0 = ra;
4341 PSXBIOS_LOG(" -> %08x\n", v0);
4342 }
4343 else if (biosC0[call])
4344 biosC0[call]();
4345
4346 //printf("C(%02x) -> %x\n", call, v0);
4347 psxBranchTest();
4348}
4349
4350static void hleA0t() {
4351 u32 call = (pc0 - A_A0_TRAPS) / 4 - 1;
4352 if (call >= 256u || !biosA0[call]) {
4353 log_unhandled("unexpected A trap @%08x ra=%08x\n", pc0 - 4, ra);
4354 mips_return_void_c(1000);
4355 }
4356 else
4357 biosA0[call]();
4358
4359 //printf("A(%02x) -> %x\n", call, v0);
4360 psxBranchTest();
4361}
4362
4363static void hleB0t() {
4364 u32 call = (pc0 - A_B0_TRAPS) / 4 - 1;
4365 if (pc0 - 4 == A_B0_5B_TRAP)
4366 call = 0x5b;
4367 if (call >= 256u || !biosB0[call]) {
4368 log_unhandled("unexpected B trap @%08x ra=%08x\n", pc0 - 4, ra);
4369 mips_return_void_c(1000);
4370 }
4371 else
4372 biosB0[call]();
4373
4374 //printf("B(%02x) -> %x\n", call, v0);
4375 psxBranchTest();
4376}
4377
4378static void hleC0t() {
4379 u32 call = (pc0 - A_C0_TRAPS) / 4 - 1;
4380 if (call >= 128u || !biosC0[call]) {
4381 log_unhandled("unexpected C trap @%08x ra=%08x\n", pc0 - 4, ra);
4382 mips_return_void_c(1000);
4383 }
4384 else
4385 biosC0[call]();
4386
4387 //printf("C(%02x) -> %x\n", call, v0);
4388 psxBranchTest();
4389}
4390
4391// currently not used
4392static void hleBootstrap() {
4393 CheckCdrom();
4394 LoadCdrom();
4395}
4396
4397static void hleExecRet() {
4398 const EXEC *header = (EXEC *)PSXM(s0);
4399
4400 PSXBIOS_LOG("ExecRet %x: %x\n", s0, header->ret);
4401
4402 ra = SWAP32(header->ret);
4403 sp = SWAP32(header->_sp);
4404 fp = SWAP32(header->_fp);
4405 gp = SWAP32(header->_gp);
4406 s0 = SWAP32(header->base);
4407
4408 v0 = 1;
4409 psxRegs.pc = ra;
4410}
4411
4412void (* const psxHLEt[hleop_count_])() = {
4413 hleDummy, hleA0, hleB0, hleC0,
4414 hleBootstrap, hleExecRet, psxBiosException, hleDummy,
4415 hleExc0_0_1, hleExc0_0_2,
4416 hleExc0_1_1, hleExc0_1_2, hleExc0_2_2_syscall,
4417 hleExc1_0_1, hleExc1_0_2,
4418 hleExc1_1_1, hleExc1_1_2,
4419 hleExc1_2_1, hleExc1_2_2,
4420 hleExc1_3_1, hleExc1_3_2,
4421 hleExc3_0_2_defint,
4422 hleExcPadCard1, hleExcPadCard2,
4423 hleA0t, hleB0t, hleC0t,
4424};
4425
4426void psxBiosCheckExe(u32 t_addr, u32 t_size, int loading_state)
4427{
4428 // lw $v0, 0x10($sp)
4429 // nop
4430 // addiu $v0, -1
4431 // sw $v0, 0x10($sp)
4432 // lw $v0, 0x10($sp)
4433 // nop
4434 // bne $v0, $v1, not_timeout
4435 // nop
4436 // lui $a0, ...
4437 static const u8 pattern[] = {
4438 0x10, 0x00, 0xA2, 0x8F, 0x00, 0x00, 0x00, 0x00,
4439 0xFF, 0xFF, 0x42, 0x24, 0x10, 0x00, 0xA2, 0xAF,
4440 0x10, 0x00, 0xA2, 0x8F, 0x00, 0x00, 0x00, 0x00,
4441 0x0C, 0x00, 0x43, 0x14, 0x00, 0x00, 0x00, 0x00,
4442 };
4443 u32 start = t_addr & 0x1ffffc;
4444 u32 end = (start + t_size) & 0x1ffffc;
4445 u32 buf[sizeof(pattern) / sizeof(u32)];
4446 const u32 *r32 = (u32 *)(psxM + start);
4447 u32 i, j;
4448
4449 if (end <= start)
4450 return;
4451 if (!Config.HLE)
4452 return;
4453
4454 memcpy(buf, pattern, sizeof(buf));
4455 for (i = 0; i < t_size / 4; i += j + 1) {
4456 for (j = 0; j < sizeof(buf) / sizeof(buf[0]); j++)
4457 if (r32[i + j] != buf[j])
4458 break;
4459 if (j != sizeof(buf) / sizeof(buf[0]))
4460 continue;
4461
4462 if ((SWAP32(r32[i + j]) >> 16) != 0x3c04) // lui
4463 continue;
4464 if (!loading_state)
4465 SysPrintf("HLE vsync @%08x\n", start + i * 4);
4466 psxRegs.biosBranchCheck = (t_addr & 0xa01ffffc) + i * 4;
4467 }
4468}
4469
4470void psxBiosCheckBranch(void)
4471{
4472#if 1
4473 // vsync HLE hack
4474 static u32 cycles_prev, v0_prev;
4475 u32 cycles_passed, waste_cycles;
4476 u32 loops, v0_expect = v0_prev - 1;
4477 if (v0 != 1)
4478 return;
4479 execI(&psxRegs);
4480 cycles_passed = psxRegs.cycle - cycles_prev;
4481 cycles_prev = psxRegs.cycle;
4482 v0_prev = v0;
4483 if (cycles_passed < 10 || cycles_passed > 50 || v0 != v0_expect)
4484 return;
4485
4486 waste_cycles = schedule_timeslice() - psxRegs.cycle;
4487 loops = waste_cycles / cycles_passed;
4488 if (loops > v0)
4489 loops = v0;
4490 v0 -= loops;
4491 psxRegs.cycle += loops * cycles_passed;
4492 //printf("c %4u %d\n", loops, cycles_passed);
4493#endif
4494}
4495
4496#define bfreeze(ptr, size) { \
4497 if (Mode == 1) memcpy(&psxR[base], ptr, size); \
4498 if (Mode == 0) memcpy(ptr, &psxR[base], size); \
4499 base += size; \
4500}
4501
4502#define bfreezes(ptr) bfreeze(ptr, sizeof(ptr))
4503#define bfreezel(ptr) bfreeze(ptr, sizeof(*(ptr)))
4504
4505void psxBiosFreeze(int Mode) {
4506 u32 base = 0x40000;
4507
4508 bfreezes(FDesc);
4509 bfreezes(ffile);
4510 bfreezel(&nfile);
4511 bfreezes(cdir);
4512}