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