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