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