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