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