psxbios: implement some more memcard details
[pcsx_rearmed.git] / libpcsxcore / psxbios.c
... / ...
CommitLineData
1/***************************************************************************
2 * Copyright (C) 2019 Ryan Schultz, PCSX-df Team, PCSX team, gameblabla, *
3 * dmitrysmagin, senquack *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA. *
19 ***************************************************************************/
20
21/* Gameblabla 2018-2019 :
22 * Numerous changes to bios calls as well as improvements in order to conform to nocash's findings
23 * for the PSX bios calls. Thanks senquack for helping out with some of the changes
24 * and helping to spot issues and refine my patches.
25 * */
26
27/*
28 * Internal simulated HLE BIOS.
29 */
30
31// TODO: implement all system calls, count the exact CPU cycles of system calls.
32
33#include "psxbios.h"
34#include "psxhw.h"
35#include "gpu.h"
36#include "sio.h"
37#include "psxhle.h"
38#include "psxinterpreter.h"
39#include "psxevents.h"
40#include "cdrom.h"
41#include <stdarg.h>
42#include <zlib.h>
43
44#ifndef PSXBIOS_LOG
45//#define PSXBIOS_LOG printf
46#define PSXBIOS_LOG(...)
47#endif
48#ifndef PSXBIOS_EV_LOG
49//#define PSXBIOS_EV_LOG printf
50#define PSXBIOS_EV_LOG(...)
51#endif
52
53#define PTR_1 (void *)(size_t)1
54
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
77 "SystemErrorUnresolvedException", "LoadTest", "Load", "Exec",
78 "FlushCache", "InstallInterruptHandler", "GPU_dw", "mem2vram",
79 "SendGPUStatus", "GPU_cw", "GPU_cwb", "SendPackets",
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
92 "_bu_init", "CdInit", "CdRemove", "sys_a0_73",
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",
103 "sys_a0_94", "CdReset", "AddCDROMDevice", "AddMemCardDevide",
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",
113 "GetSystemInfo",
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",
121 "EnableEvent", "DisableEvent", "OpenTh", "CloseTh",
122// 0x10
123 "ChangeTh", "sys_b0_11", "InitPAD", "StartPAD",
124 "StopPAD", "PAD_init", "PAD_dr", "ReturnFromException",
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)
192#define fp (psxRegs.GPR.n.fp)
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 {
204 u32 class;
205 u32 status;
206 u32 spec;
207 u32 mode;
208 u32 fhandler;
209 u32 unused[2];
210} EvCB;
211
212#define EvStUNUSED 0x0000
213#define EvStDISABLED 0x1000
214#define EvStACTIVE 0x2000
215#define EvStALREADY 0x4000
216
217#define EvMdCALL 0x1000
218#define EvMdMARK 0x2000
219
220typedef struct {
221 u32 status;
222 u32 mode;
223 u32 reg[32];
224 u32 epc;
225 u32 hi, lo;
226 u32 sr, cause;
227 u32 unused[9];
228} TCB;
229
230typedef struct {
231 u32 _pc0;
232 u32 gp0;
233 u32 t_addr;
234 u32 t_size;
235 u32 d_addr; // 10
236 u32 d_size;
237 u32 b_addr;
238 u32 b_size; // 1c
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
261// todo: FileDesc layout is wrong
262// todo: get rid of these globals
263static FileDesc FDesc[32];
264static char ffile[64];
265static int nfile;
266static char cdir[8*8+8];
267static u32 floodchk;
268
269// fixed RAM offsets, SCPH1001 compatible
270#define A_TT_ExCB 0x0100
271#define A_TT_PCB 0x0108
272#define A_TT_TCB 0x0110
273#define A_TT_EvCB 0x0120
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
281#define A_CARD_ISLOT 0x7264 // 0 or 1, toggled by card vint handler
282#define A_KMALLOC_PTR 0x7460
283#define A_KMALLOC_SIZE 0x7464
284#define A_KMALLOC_END 0x7468
285#define A_PADCRD_CHN_E 0x74a8 // pad/card irq chain entry, see hleExcPadCard1()
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
292#define A_PAD_DR_DST 0x74c4
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
297#define A_PAD_DR_BUF1 0x7570
298#define A_PAD_DR_BUF2 0x7598
299#define A_EEXIT_PTR 0x75d0
300#define A_EXC_STACK 0x85d8 // exception stack top
301#define A_RCNT_VBL_ACK 0x8600
302#define A_PAD_ACK_VBL 0x8914 // enable vint ack by pad reading code
303#define A_HEAP_BASE 0x9000
304#define A_HEAP_SIZE 0x9004
305#define A_HEAP_END 0x9008
306#define A_HEAP_INIT_FLG 0x900c
307#define A_RND_SEED 0x9010
308#define A_HEAP_FRSTCHNK 0xb060
309#define A_HEAP_CURCHNK 0xb064
310#define A_CONF_TCB 0xb940
311#define A_CONF_EvCB 0xb944
312#define A_CONF_SP 0xb948
313#define A_CD_EVENTS 0xb9b8
314#define A_EXC_GP 0xf450
315
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
320
321#define CARD_HARDLER_WRITE 0x51F4
322#define CARD_HARDLER_READ 0x5688
323#define CARD_HARDLER_INFO 0x5B64
324
325#define HLEOP(n) SWAPu32((0x3b << 26) | (n));
326
327static u8 loadRam8(u32 addr)
328{
329 assert(!(addr & 0x5f800000));
330 return psxM[addr & 0x1fffff];
331}
332
333static u32 loadRam32(u32 addr)
334{
335 assert(!(addr & 0x5f800000));
336 return SWAP32(*((u32 *)psxM + ((addr & 0x1fffff) >> 2)));
337}
338
339static void *castRam8ptr(u32 addr)
340{
341 assert(!(addr & 0x5f800000));
342 return psxM + (addr & 0x1fffff);
343}
344
345static void *castRam32ptr(u32 addr)
346{
347 assert(!(addr & 0x5f800003));
348 return psxM + (addr & 0x1ffffc);
349}
350
351static void *loadRam8ptr(u32 addr)
352{
353 return castRam8ptr(loadRam32(addr));
354}
355
356static void *loadRam32ptr(u32 addr)
357{
358 return castRam32ptr(loadRam32(addr));
359}
360
361static void storeRam8(u32 addr, u8 d)
362{
363 assert(!(addr & 0x5f800000));
364 *((u8 *)psxM + (addr & 0x1fffff)) = d;
365}
366
367static void storeRam32(u32 addr, u32 d)
368{
369 assert(!(addr & 0x5f800000));
370 *((u32 *)psxM + ((addr & 0x1fffff) >> 2)) = SWAP32(d);
371}
372
373static void mips_return(u32 val)
374{
375 v0 = val;
376 pc0 = ra;
377}
378
379static void mips_return_void(void)
380{
381 pc0 = ra;
382}
383
384static void use_cycles(u32 cycle)
385{
386 psxRegs.cycle += cycle * 2;
387}
388
389static void mips_return_c(u32 val, u32 cycle)
390{
391 use_cycles(cycle);
392 mips_return(val);
393}
394
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) {
408 u32 sra = ra;
409 u32 ssr = psxRegs.CP0.n.SR;
410 u32 lim = 0;
411 pc0 = pc;
412 ra = 0x80001000;
413 psxRegs.CP0.n.SR &= ~0x404; // disable interrupts
414
415 assert(psxRegs.cpuInRecursion <= 1);
416 psxRegs.cpuInRecursion++;
417 psxCpu->Notify(R3000ACPU_NOTIFY_AFTER_LOAD, PTR_1);
418
419 while (pc0 != 0x80001000 && ++lim < 0x100000)
420 psxCpu->ExecuteBlock(EXEC_CALLER_HLE);
421
422 psxCpu->Notify(R3000ACPU_NOTIFY_BEFORE_SAVE, PTR_1);
423 psxRegs.cpuInRecursion--;
424
425 if (lim == 0x100000)
426 PSXBIOS_LOG("softCall @%x hit lim\n", pc);
427 ra = sra;
428 psxRegs.CP0.n.SR |= ssr & 0x404;
429}
430
431static inline void softCallInException(u32 pc) {
432 u32 sra = ra;
433 u32 lim = 0;
434 pc0 = pc;
435
436 assert(ra != 0x80001000);
437 if (ra == 0x80001000)
438 return;
439 ra = 0x80001000;
440
441 psxRegs.cpuInRecursion++;
442 psxCpu->Notify(R3000ACPU_NOTIFY_AFTER_LOAD, PTR_1);
443
444 while (!returned_from_exception() && pc0 != 0x80001000 && ++lim < 0x100000)
445 psxCpu->ExecuteBlock(EXEC_CALLER_HLE);
446
447 psxCpu->Notify(R3000ACPU_NOTIFY_BEFORE_SAVE, PTR_1);
448 psxRegs.cpuInRecursion--;
449
450 if (lim == 0x100000)
451 PSXBIOS_LOG("softCallInException @%x hit lim\n", pc);
452 if (pc0 == 0x80001000)
453 ra = sra;
454}
455
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);
460static void CloseEvent(u32 ev);
461
462/* *
463// *
464// *
465// System calls A0 */
466
467
468#define buread(Ra1, mcd, length) { \
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); \
470 ptr = Mcd##mcd##Data + 8192 * FDesc[1 + mcd].mcfile + FDesc[1 + mcd].offset; \
471 memcpy(Ra1, ptr, length); \
472 psxCpu->Clear(a1, (length + 3) / 4); \
473 if (FDesc[1 + mcd].mode & 0x8000) { \
474 DeliverEvent(0xf0000011, 0x0004); \
475 DeliverEvent(0xf4000001, 0x0004); \
476 v0 = 0; } \
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; \
483 PSXBIOS_LOG("write %d: %x,%x\n", FDesc[1 + mcd].mcfile, FDesc[1 + mcd].offset, a2); \
484 ptr = Mcd##mcd##Data + offset; \
485 memcpy(ptr, Ra1, length); \
486 FDesc[1 + mcd].offset += length; \
487 SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, offset, length); \
488 if (FDesc[1 + mcd].mode & 0x8000) { \
489 DeliverEvent(0xf0000011, 0x0004); \
490 DeliverEvent(0xf4000001, 0x0004); \
491 v0 = 0; } \
492 else v0 = length; \
493}
494
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{
501 char *ptr;
502 void *pa1 = Ra1;
503#ifdef PSXBIOS_LOG
504 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x03]);
505#endif
506 v0 = -1;
507
508 if (pa1 != INVALID_PTR) {
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{
521 char *ptr;
522 void *pa1 = Ra1;
523#ifdef PSXBIOS_LOG
524 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x09]);
525#endif
526 v0 = -1;
527 if (pa1 == INVALID_PTR) {
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}
549
550static u32 do_todigit(u32 c)
551{
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) {
563 log_unhandled("todigit %02x\n", c);
564 c = -1;
565 }
566 else
567 {
568 c = 0x0098967F;
569 }
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);
630}
631
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
646 if (p == INVALID_PTR) {
647 mips_return(0);
648 return;
649 }
650
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;
666 PSXBIOS_LOG("psxBios_%s %s (%x) -> 0x%x\n", biosA0n[0x10], Ra0, a0, v0);
667}
668
669void psxBios_atol() { // 0x11
670 psxBios_atoi();
671}
672
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);
681 int i;
682
683 PSXBIOS_LOG("psxBios_%s %x\n", biosA0n[0x13], a0);
684
685 jmp_buf->ra_ = SWAP32(ra);
686 jmp_buf->sp_ = SWAP32(sp);
687 jmp_buf->fp_ = SWAP32(fp);
688 for (i = 0; i < 8; i++) // s0-s7
689 jmp_buf->s[i] = SWAP32(psxRegs.GPR.r[16 + i]);
690 jmp_buf->gp_ = SWAP32(gp);
691
692 mips_return_c(0, 15);
693}
694
695static void longjmp_load(const struct jmp_buf_ *jmp_buf)
696{
697 int i;
698
699 ra = SWAP32(jmp_buf->ra_);
700 sp = SWAP32(jmp_buf->sp_);
701 fp = SWAP32(jmp_buf->fp_);
702 for (i = 0; i < 8; i++) // s0-s7
703 psxRegs.GPR.r[16 + i] = SWAP32(jmp_buf->s[i]);
704 gp = SWAP32(jmp_buf->gp_);;
705}
706
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);
713}
714
715void psxBios_strcat() { // 0x15
716 u8 *p2 = (u8 *)Ra1;
717 u32 p1 = a0;
718
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)
721 {
722 mips_return_c(0, 6);
723 return;
724 }
725 while (loadRam8(p1)) {
726 use_cycles(4);
727 p1++;
728 }
729 for (; *p2; p1++, p2++)
730 storeRam8(p1, *p2);
731 storeRam8(p1, 0);
732
733 mips_return_c(a0, 22);
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
743 if (a0 == 0 || a1 == 0)
744 {
745 v0 = 0;
746 pc0 = ra;
747 return;
748 }
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;
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 }
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++) {
787 n++;
788 if (*p1++ == '\0') {
789 v1=n-1;
790 a0+=n;
791 a1+=n;
792 v0 = 0;
793 pc0 = ra;
794 return;
795 }
796 }
797
798 v0 = (*p1 - *--p2);
799 v1 = n;
800 a0+=n;
801 a1+=n;
802 pc0 = ra;
803}
804
805void psxBios_strncmp() { // 0x18
806 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
807 s32 n = a2;
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 }
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;
834 v1 = a2 - ((a2-n) - 1);
835 a0 += (a2-n) - 1;
836 a1 += (a2-n) - 1;
837 a2 = n;
838 return;
839 }
840 }
841
842 v0 = (n < 0 ? 0 : *p1 - *--p2);
843 pc0 = ra;
844 v1 = a2 - ((a2-n) - 1);
845 a0 += (a2-n) - 1;
846 a1 += (a2-n) - 1;
847 a2 = n;
848}
849
850void psxBios_strcpy() { // 0x19
851 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
852 PSXBIOS_LOG("psxBios_%s %x, %s (%x)\n", biosA0n[0x19], a0, p2, a1);
853 if (a0 == 0 || a1 == 0)
854 {
855 v0 = 0;
856 pc0 = ra;
857 return;
858 }
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;
867 if (a0 == 0 || a1 == 0)
868 {
869 v0 = 0;
870 pc0 = ra;
871 return;
872 }
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;
889 if (a0 == 0)
890 {
891 pc0 = ra;
892 return;
893 }
894 while (*p++) v0++;
895 pc0 = ra;
896}
897
898void psxBios_index() { // 0x1c
899 char *p = (char *)Ra0;
900 if (a0 == 0)
901 {
902 v0 = 0;
903 pc0 = ra;
904 return;
905 }
906
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;
922 if (a0 == 0)
923 {
924 pc0 = ra;
925 return;
926 }
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;
994 PSXBIOS_LOG("psxBios_%s %s (%x), %s (%x)\n", biosA0n[0x24], p, a0, Ra1, a1);
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;
1007 PSXBIOS_LOG(" -> %x\n", v0);
1008 return;
1009 }
1010
1011 // bug: skips the whole matched substring + 1
1012 p = p1 + 1;
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
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++;
1039 }
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
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);
1077}
1078
1079static void psxBios_bzero() { // 0x28
1080 /* Same as memset here (See memset below) */
1081 u32 ret = a0, cycles;
1082 if (a0 == 0 || (s32)a1 <= 0)
1083 {
1084 mips_return_c(0, 6);
1085 return;
1086 }
1087 do_memset(a0, 0, a1);
1088 cycles = a1 * 4;
1089 a0 += a1;
1090 a1 = 0;
1091 // todo: many more cycles due to uncached bios mem
1092 mips_return_c(ret, cycles + 5);
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
1100 while ((s32)a2-- > 0) {
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
1111static void psxBios_memcpy() { // 0x2a
1112 u32 ret = a0, cycles = 0;
1113 if (a0 == 0)
1114 {
1115 mips_return_c(0, 4);
1116 return;
1117 }
1118 v1 = a0;
1119 if ((s32)a2 > 0) {
1120 do_memcpy(a0, a1, a2);
1121 cycles = a2 * 6;
1122 a0 += a2;
1123 a1 += a2;
1124 a2 = 0;
1125 }
1126 mips_return_c(ret, cycles + 5);
1127}
1128
1129static void psxBios_memset() { // 0x2b
1130 u32 ret = a0, cycles;
1131 if (a0 == 0 || (s32)a2 <= 0)
1132 {
1133 mips_return_c(0, 6);
1134 return;
1135 }
1136 do_memset(a0, a1, a2);
1137 cycles = a2 * 4;
1138 a0 += a2;
1139 a2 = 0;
1140 // todo: many more cycles due to uncached bios mem
1141 mips_return_c(ret, cycles + 5);
1142}
1143
1144void psxBios_memmove() { // 0x2c
1145 u32 ret = a0, cycles = 0;
1146 if (a0 == 0)
1147 {
1148 mips_return_c(0, 4);
1149 return;
1150 }
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;
1173 }
1174 mips_return_c(ret, cycles + 5);
1175}
1176
1177void psxBios_memcmp() { // 0x2d
1178 psxBios_bcmp();
1179}
1180
1181void psxBios_memchr() { // 0x2e
1182 char *p = (char *)Ra0;
1183
1184 if (a0 == 0 || a2 > 0x7FFFFFFF)
1185 {
1186 pc0 = ra;
1187 return;
1188 }
1189
1190 while ((s32)a2-- > 0) {
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
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);
1205}
1206
1207static void psxBios_srand() { // 0x30
1208 storeRam32(A_RND_SEED, a0);
1209 mips_return_void_c(3);
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
1220 softCall(qscmpfunc);
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
1318static int malloc_heap_grow(u32 size) {
1319 u32 heap_addr, heap_end, heap_addr_new;
1320
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;
1350 }
1351 storeRam32(A_HEAP_INIT_FLG, 1);
1352 }
1353
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;
1380 }
1381 }
1382 if (chunk_hdr == ~1) {
1383 // last chunk
1384 if (tries == 2)
1385 storeRam32(A_HEAP_CURCHNK, loadRam32(A_HEAP_FRSTCHNK));
1386 tries--;
1387 }
1388 else {
1389 // go to the next chunk
1390 storeRam32(A_HEAP_CURCHNK, next_chunk);
1391 }
1392 }
1393
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;
1402 }
1403
1404 PSXBIOS_LOG(" -> %08x\n", ret);
1405 mips_return_c(ret, 40);
1406}
1407
1408static void psxBios_free() { // 0x34
1409 PSXBIOS_LOG("psxBios_%s %x (%d bytes)\n", biosA0n[0x34], a0, loadRam32(a0 - 4));
1410 storeRam32(a0 - 4, loadRam32(a0 - 4) | 1); // set chunk to free
1411 mips_return_void_c(5);
1412}
1413
1414static void psxBios_calloc() { // 0x37
1415 u32 ret, size;
1416 PSXBIOS_LOG("psxBios_%s %x %x\n", biosA0n[0x37], a0, a1);
1417
1418 a0 = size = a0 * a1;
1419 psxBios_malloc();
1420 ret = v0;
1421 if (ret) {
1422 a0 = ret; a1 = size;
1423 psxBios_bzero();
1424 }
1425 mips_return_c(ret, 21);
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;
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 }
1454}
1455
1456
1457/* InitHeap(void *block , int n) */
1458static void psxBios_InitHeap() { // 0x39
1459 PSXBIOS_LOG("psxBios_%s %x %x\n", biosA0n[0x39], a0, a1);
1460
1461 storeRam32(A_HEAP_BASE, a0);
1462 storeRam32(A_HEAP_SIZE, a1);
1463 storeRam32(A_HEAP_END, a0 + (a1 & ~3) + 4);
1464 storeRam32(A_HEAP_INIT_FLG, 0);
1465 storeRam32(a0, 0);
1466
1467 mips_return_void_c(14);
1468}
1469
1470void psxBios_getchar() { //0x3b
1471 v0 = getchar(); pc0 = ra;
1472}
1473
1474static void psxBios_printf_psxout() { // 0x3f
1475 char tmp[1024];
1476 char tmp2[1024];
1477 u32 save[4] = { 0, };
1478 char *ptmp = tmp;
1479 int n=1, i=0, j;
1480 void *psp;
1481
1482 psp = PSXM(sp);
1483 if (psp != INVALID_PTR) {
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 }
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':
1519 case 'i': case 'u':
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
1539 if (psp != INVALID_PTR)
1540 memcpy(psp, save, 4 * 4);
1541
1542 if (Config.PsxOut)
1543 SysPrintf("%s", tmp);
1544}
1545
1546void psxBios_printf() { // 0x3f
1547 psxBios_printf_psxout();
1548 pc0 = ra;
1549}
1550
1551static void psxBios_cd() { // 0x40
1552 const char *p, *dir = Ra0;
1553 PSXBIOS_LOG("psxBios_%s %x(%s)\n", biosB0n[0x40], a0, dir);
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 }
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);
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
1585static void psxBios_SystemErrorUnresolvedException() {
1586 if (floodchk != 0x12340a40) { // prevent log flood
1587 SysPrintf("psxBios_%s called from %08x\n", biosA0n[0x40], ra);
1588 floodchk = 0x12340a40;
1589 }
1590 mips_return_void_c(1000);
1591}
1592
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
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
1642/*
1643 * long Load(char *name, struct EXEC *header);
1644 */
1645
1646void psxBios_Load() { // 0x42
1647 u8 time[3] = { 2, 0, 0x16 };
1648 EXE_HEADER eheader;
1649 char path[256];
1650 char *pa0, *p;
1651 void *pa1;
1652
1653 pa0 = Ra0;
1654 pa1 = Ra1;
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
1669 if (LoadCdromFile(path, &eheader, time) == 0) {
1670 memcpy(pa1, ((char*)&eheader)+16, sizeof(EXEC));
1671 psxCpu->Clear(a1, sizeof(EXEC) / 4);
1672 FlushCache();
1673 v0 = 1;
1674 } else v0 = 0;
1675 PSXBIOS_LOG(" -> %d\n", v0);
1676
1677 pc0 = ra;
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);
1689}
1690
1691/*
1692 * int Exec(struct EXEC *header , int argc , char **argv);
1693 */
1694
1695void psxBios_Exec() { // 43
1696 EXEC *header = (EXEC *)castRam32ptr(a0);
1697 u32 ptr;
1698 s32 len;
1699
1700 PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosA0n[0x43], a0, a1, a2);
1701
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);
1708
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);
1718
1719 gp = SWAP32(header->gp0);
1720
1721 s0 = a0;
1722
1723 a0 = a1;
1724 a1 = a2;
1725
1726 ra = 0x8000;
1727 pc0 = SWAP32(header->_pc0);
1728}
1729
1730static void psxBios_FlushCache() { // 44
1731 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x44]);
1732 FlushCache();
1733 mips_return_void();
1734}
1735
1736void psxBios_GPU_dw() { // 0x46
1737 int size;
1738 u32 *ptr;
1739
1740#ifdef PSXBIOS_LOG
1741 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x46]);
1742#endif
1743
1744 GPU_writeData(0xa0000000);
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 }
1753
1754 pc0 = ra;
1755}
1756
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
1765void psxBios_mem2vram() { // 0x47
1766 int size;
1767 gpuSyncPluginSR(); // flush
1768 GPU_writeData(0xa0000000);
1769 GPU_writeData((a1<<0x10)|(a0&0xffff));
1770 GPU_writeData((a3<<0x10)|(a2&0xffff));
1771 size = ((((a2 * a3) / 2) >> 4) << 16);
1772 GPU_writeStatus(0x04000002);
1773 psxHwWrite32(0x1f8010f4,0);
1774 psxHwWrite32(0x1f8010f0,psxHwRead32(0x1f8010f0)|0x800);
1775 psxHwWrite32(0x1f8010a0,Rsp[4]);//might have a buggy...
1776 psxHwWrite32(0x1f8010a4, size | 0x10);
1777 psxHwWrite32(0x1f8010a8,0x01000201);
1778
1779 pc0 = ra;
1780}
1781
1782void psxBios_SendGPU() { // 0x48
1783 GPU_writeStatus(a0);
1784 gpuSyncPluginSR();
1785 pc0 = ra;
1786}
1787
1788void psxBios_GPU_cw() { // 0x49
1789 GPU_writeData(a0);
1790 gpuSyncPluginSR();
1791 use_cycles(13);
1792 gpu_sync();
1793}
1794
1795void psxBios_GPU_cwb() { // 0x4a
1796 u32 *ptr = (u32*)Ra0;
1797 int size = a1;
1798 gpuSyncPluginSR();
1799 while(size--)
1800 {
1801 GPU_writeData(SWAPu32(*ptr++));
1802 }
1803
1804 pc0 = ra;
1805}
1806
1807void psxBios_GPU_SendPackets() { //4b:
1808 gpuSyncPluginSR();
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);
1823 v0 = 0x1f801814;
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
1843 a1 = 0xf000;
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
1853static void psxBios__bu_init() { // 70
1854 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x70]);
1855
1856 DeliverEvent(0xf0000011, 0x0004);
1857 DeliverEvent(0xf4000001, 0x0004);
1858
1859 pc0 = ra;
1860}
1861
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);
1865
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
1925static void psxBios_DequeueCdIntr_() {
1926 psxBios_SysDeqIntRP_(0, 0x91d0);
1927 psxBios_SysDeqIntRP_(0, 0x91e0);
1928 use_cycles(16);
1929}
1930
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
1942static void psxBios_DequeueCdIntr() { // a3
1943 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0xa3]);
1944 psxBios_DequeueCdIntr_();
1945}
1946
1947static void psxBios_CdRemove() { // 56, 72
1948 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x72]);
1949
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));
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);
1962}
1963
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
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;
1992 PSXBIOS_LOG("Change effective memory : %d MBytes\n",a0);
1993 break;
1994
1995 case 8:
1996 psxHu32ref(0x1060) = SWAP32(new | 0x300);
1997 psxMu32ref(0x060) = a0;
1998 PSXBIOS_LOG("Change effective memory : %d MBytes\n",a0);
1999
2000 default:
2001 PSXBIOS_LOG("Effective memory must be 2/8 MBytes\n");
2002 break;
2003 }
2004
2005 pc0 = ra;
2006}
2007
2008/* TODO FIXME : Not compliant. -1 indicates failure but using 1 for now. */
2009static void psxBios_get_cd_status() // a6
2010{
2011 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0xa6]);
2012 v0 = 1;
2013 pc0 = ra;
2014}
2015
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
2029/* System calls B0 */
2030
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
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
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 }
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
2112static u32 DeliverEvent(u32 class, u32 spec) {
2113 EvCB *ev, *ev_first = (EvCB *)loadRam32ptr(A_TT_EvCB);
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;
2117
2118 //printf("%s %08x %x\n", __func__, class, spec);
2119 for (i = 0, ev = ev_first; i < lim; i++, ev++) {
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) {
2132 if (ev->status != SWAP32(EvStALREADY))
2133 PSXBIOS_EV_LOG("DeliverEvent %08x %x (%08zx) set\n",
2134 class, spec, (ev - ev_first) | 0xf1000000u);
2135 ev->status = SWAP32(EvStALREADY);
2136 continue;
2137 }
2138 use_cycles(8);
2139 if (ret == EvMdCALL) {
2140 ret = SWAP32(ev->fhandler);
2141 PSXBIOS_EV_LOG("DeliverEvent %08x %x (%08zx) cb %x\n",
2142 class, spec, (ev - ev_first) | 0xf1000000u, ret);
2143 if (ret) {
2144 v0 = ret;
2145 softCall(ret);
2146 ret = v0;
2147 }
2148 }
2149 }
2150 floodchk = 0;
2151 use_cycles(29);
2152 return ret;
2153}
2154
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;
2160
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;
2177}
2178
2179static void psxBios_DeliverEvent() { // 07
2180 u32 ret;
2181 PSXBIOS_LOG("psxBios_%s %x %04x\n", biosB0n[0x07], a0, a1);
2182
2183 ret = DeliverEvent(a0, a1);
2184 mips_return(ret);
2185}
2186
2187static s32 get_free_EvCB_slot() {
2188 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB);
2189 u32 i, lim = loadRam32(A_TT_EvCB + 4) / 0x1c;
2190
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;
2198}
2199
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}
2213
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}
2220
2221static void CloseEvent(u32 ev)
2222{
2223 u32 base = loadRam32(A_TT_EvCB);
2224 storeRam32(base + (ev & 0xffff) * sizeof(EvCB) + 4, EvStUNUSED);
2225}
2226
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);
2232}
2233
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);
2238
2239 use_cycles(15);
2240 if (status == EvStALREADY) {
2241 storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
2242 mips_return(1);
2243 return;
2244 }
2245 if (status != EvStACTIVE)
2246 {
2247 mips_return_c(0, 2);
2248 return;
2249 }
2250
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();
2256}
2257
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;
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 }
2267 if (status == EvStALREADY) {
2268 storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
2269 ret = 1;
2270 }
2271
2272 mips_return_c(ret, 15);
2273}
2274
2275static void EnableEvent(u32 ev, int do_log) {
2276 u32 base = loadRam32(A_TT_EvCB);
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);
2280 if (status != EvStUNUSED)
2281 storeRam32(base + (ev & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
2282}
2283
2284static void psxBios_EnableEvent() { // 0c
2285 EnableEvent(a0, 1);
2286 mips_return_c(1, 15);
2287}
2288
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);
2295
2296 mips_return_c(1, 15);
2297}
2298
2299/*
2300 * long OpenTh(long (*func)(), unsigned long sp, unsigned long gp);
2301 */
2302
2303void psxBios_OpenTh() { // 0e
2304 TCB *tcb = loadRam32ptr(A_TT_TCB);
2305 u32 limit = loadRam32(A_TT_TCB + 4) / 0xc0u;
2306 int th;
2307
2308 for (th = 1; th < limit; th++)
2309 {
2310 if (tcb[th].status != SWAP32(0x4000)) break;
2311
2312 }
2313 if (th == limit) {
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
2319 mips_return_c(0xffffffff, 20);
2320 return;
2321 }
2322 PSXBIOS_LOG("psxBios_%s -> %x\n", biosB0n[0x0e], 0xff000000 + th);
2323
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
2330
2331 mips_return_c(0xff000000 + th, 34);
2332}
2333
2334/*
2335 * int CloseTh(long thread);
2336 */
2337
2338static void psxBios_CloseTh() { // 0f
2339 u32 tcb = loadRam32(A_TT_TCB);
2340 u32 th = a0 & 0xffff;
2341
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);
2345
2346 mips_return_c(1, 11);
2347}
2348
2349/*
2350 * int ChangeTh(long thread);
2351 */
2352
2353void psxBios_ChangeTh() { // 10
2354 u32 tcbBase = loadRam32(A_TT_TCB);
2355 u32 th = a0 & 0xffff;
2356
2357 // this is quite spammy
2358 //PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x10], th);
2359
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);
2366}
2367
2368void psxBios_InitPAD() { // 0x12
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");
2373 ram32[A_PAD_DR_DST/4] = 0;
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);
2392
2393 ram32[A_PAD_IRQR_ENA/4] = SWAP32(1);
2394
2395 mips_return_c(1, 200);
2396}
2397
2398void psxBios_StartPAD() { // 13
2399 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x13]);
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);
2407 psxRegs.CP0.n.SR |= 0x401;
2408
2409 mips_return_c(1, 300);
2410}
2411
2412void psxBios_StopPAD() { // 14
2413 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x14]);
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);
2418}
2419
2420static void psxBios_PAD_init() { // 15
2421 u32 ret = 0;
2422 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x15]);
2423 if (a0 == 0x20000000 || a0 == 0x20000001)
2424 {
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 }
2449 }
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);
2461}
2462
2463static void psxBios_PAD_dr() { // 16
2464 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x16]);
2465 u32 ret = psxBios_PAD_dr_();
2466 mips_return(ret);
2467}
2468
2469static void psxBios_ReturnFromException() { // 17
2470 u32 tcbPtr = loadRam32(A_TT_PCB);
2471 const TCB *tcb = loadRam32ptr(tcbPtr);
2472 u32 sr;
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);
2479 sr = SWAP32(tcb->sr);
2480
2481 //printf("%s %08x->%08x %u\n", __func__, pc0, tcb->epc, psxRegs.cycle);
2482 pc0 = k0 = SWAP32(tcb->epc);
2483
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
2488 use_cycles(53);
2489 psxBranchTest();
2490}
2491
2492void psxBios_ResetEntryInt() { // 18
2493 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x18]);
2494
2495 storeRam32(A_EEXIT_PTR, A_EEXIT_DEF);
2496 mips_return_void_c(5);
2497}
2498
2499void psxBios_HookEntryInt() { // 19
2500 PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x19], a0);
2501
2502 storeRam32(A_EEXIT_PTR, a0);
2503 mips_return_void_c(3);
2504}
2505
2506static void psxBios_UnDeliverEvent() { // 0x20
2507 u32 ret;
2508 PSXBIOS_LOG("psxBios_%s %x %x\n", biosB0n[0x20], a0, a1);
2509
2510 ret = UnDeliverEvent(a0, a1);
2511 mips_return(ret);
2512}
2513
2514static void buopen(int mcd, char *ptr, char *cfg)
2515{
2516 int i;
2517 char *mcd_data = ptr;
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++) {
2524 const char *fptr = mcd_data + 128 * i;
2525 if ((*fptr & 0xF0) != 0x50) continue;
2526 if (strcmp(FDesc[1 + mcd].name, fptr+0xa)) continue;
2527 FDesc[1 + mcd].mcfile = i;
2528 PSXBIOS_LOG("open %s\n", fptr+0xa);
2529 v0 = 1 + mcd;
2530 break;
2531 }
2532 if (a1 & 0x200 && v0 == -1) { /* FCREAT */
2533 for (i=1; i<16; i++) {
2534 int j, xor, nblk = a1 >> 16;
2535 char *pptr, *fptr2;
2536 char *fptr = mcd_data + 128 * i;
2537
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);
2547 pptr = fptr2 = fptr;
2548 for(j=2; j<=nblk; j++) {
2549 int k;
2550 for(i++; i<16; i++) {
2551 fptr2 += 128;
2552
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;
2567 PSXBIOS_LOG("openC %s %d\n", ptr, nblk);
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 }
2575}
2576
2577/*
2578 * int open(char *name , int mode);
2579 */
2580
2581void psxBios_open() { // 0x32
2582 void *pa0 = Ra0;
2583
2584 PSXBIOS_LOG("psxBios_%s %s %x\n", biosB0n[0x32], Ra0, a1);
2585
2586 v0 = -1;
2587
2588 if (pa0 != INVALID_PTR) {
2589 if (!strncmp(pa0, "bu00", 4)) {
2590 buopen(1, Mcd1Data, Config.Mcd1);
2591 }
2592
2593 if (!strncmp(pa0, "bu10", 4)) {
2594 buopen(2, Mcd2Data, Config.Mcd2);
2595 }
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;
2614// DeliverEvent(0xf0000011, 0x0004);
2615// DeliverEvent(0xf4000001, 0x0004);
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
2627
2628/*
2629 * int read(int fd , void *buf , int nbytes);
2630 */
2631
2632void psxBios_read() { // 0x34
2633 char *ptr;
2634 void *pa1 = Ra1;
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
2642 if (pa1 != INVALID_PTR) {
2643 switch (a0) {
2644 case 2: buread(pa1, 1, a2); break;
2645 case 3: buread(pa1, 2, a2); break;
2646 }
2647 }
2648
2649 pc0 = ra;
2650}
2651
2652/*
2653 * int write(int fd , void *buf , int nbytes);
2654 */
2655
2656void psxBios_write() { // 0x35/0x03
2657 char *ptr;
2658 void *pa1 = Ra1;
2659
2660 if (a0 != 1) // stdout
2661 PSXBIOS_LOG("psxBios_%s: %x,%x,%x\n", biosB0n[0x35], a0, a1, a2);
2662
2663 v0 = -1;
2664 if (pa1 == INVALID_PTR) {
2665 pc0 = ra;
2666 return;
2667 }
2668
2669 if (a0 == 1) { // stdout
2670 char *ptr = pa1;
2671
2672 v0 = a2;
2673 if (Config.PsxOut) while (a2 > 0) {
2674 SysPrintf("%c", *ptr++); a2--;
2675 }
2676 pc0 = ra; return;
2677 }
2678
2679 switch (a0) {
2680 case 2: buwrite(pa1, 1, a2); break;
2681 case 3: buwrite(pa1, 2, a2); break;
2682 }
2683
2684 pc0 = ra;
2685}
2686
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
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
2720 if (Config.PsxOut) SysPrintf("%c", (char)a0);
2721 pc0 = ra;
2722}
2723
2724void psxBios_puts() { // 3e/3f
2725 if (Config.PsxOut) SysPrintf("%s", Ra0);
2726 pc0 = ra;
2727}
2728
2729static void bufile(const u8 *mcd_data, u32 dir_) {
2730 struct DIRENTRY *dir = (struct DIRENTRY *)PSXM(dir_);
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;
2736
2737 v0 = 0;
2738 if (dir == INVALID_PTR)
2739 return;
2740
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;
2774 const char *name = (const char *)data2 + 0x0a;
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);
2787}
2788
2789/*
2790 * struct DIRENTRY* firstfile(char *name,struct DIRENTRY *dir);
2791 */
2792
2793static void psxBios_firstfile() { // 42
2794 char *pa0 = Ra0;
2795
2796 PSXBIOS_LOG("psxBios_%s %s %x\n", biosB0n[0x42], pa0, a1);
2797 v0 = 0;
2798
2799 if (pa0 != INVALID_PTR)
2800 {
2801 snprintf(ffile, sizeof(ffile), "%s", pa0);
2802 if (ffile[5] == 0)
2803 strcpy(ffile + 5, "*"); // maybe?
2804 nfile = 1;
2805 if (!strncmp(pa0, "bu00", 4)) {
2806 // firstfile() calls _card_read() internally, so deliver it's event
2807 DeliverEvent(0xf0000011, 0x0004);
2808 bufile((u8 *)Mcd1Data, a1);
2809 } else if (!strncmp(pa0, "bu10", 4)) {
2810 // firstfile() calls _card_read() internally, so deliver it's event
2811 DeliverEvent(0xf0000011, 0x0004);
2812 bufile((u8 *)Mcd2Data, a1);
2813 }
2814 }
2815
2816 pc0 = ra;
2817}
2818
2819/*
2820 * struct DIRENTRY* nextfile(struct DIRENTRY *dir);
2821 */
2822
2823void psxBios_nextfile() { // 43
2824 PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x43], a0);
2825
2826 v0 = 0;
2827 if (!strncmp(ffile, "bu00", 4))
2828 bufile((u8 *)Mcd1Data, a0);
2829 else if (!strncmp(ffile, "bu10", 4))
2830 bufile((u8 *)Mcd2Data, a0);
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
2857 void *pa0 = Ra0;
2858 void *pa1 = Ra1;
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
2868 if (pa0 != INVALID_PTR && pa1 != INVALID_PTR) {
2869 if (!strncmp(pa0, "bu00", 4) && !strncmp(pa1, "bu00", 4)) {
2870 burename(1);
2871 }
2872
2873 if (!strncmp(pa0, "bu10", 4) && !strncmp(pa1, "bu10", 4)) {
2874 burename(2);
2875 }
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); \
2889 PSXBIOS_LOG("delete %s\n", ptr+0xa); \
2890 v0 = 1; \
2891 break; \
2892 } \
2893}
2894
2895/*
2896 * int delete(char *name);
2897 */
2898
2899void psxBios_delete() { // 45
2900 void *pa0 = Ra0;
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
2910 if (pa0 != INVALID_PTR) {
2911 if (!strncmp(pa0, "bu00", 4)) {
2912 budelete(1);
2913 }
2914
2915 if (!strncmp(pa0, "bu10", 4)) {
2916 budelete(2);
2917 }
2918 }
2919
2920 pc0 = ra;
2921}
2922
2923void psxBios_InitCARD() { // 4a
2924 u8 *ram8 = (u8 *)psxM;
2925 u32 *ram32 = (u32 *)psxM;
2926 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x4a], a0);
2927 write_chain(ram32 + A_PADCRD_CHN_E/4, 0, 0x49bc, 0x4a4c);
2928 //card_error = 0;
2929 ram8[A_CARD_ISLOT] = 0;
2930 ram8[A_CARD_STATUS1] = 1;
2931 ram8[A_CARD_STATUS2] = 1;
2932 // (maybe) todo: early_card_irq, etc
2933
2934 ram32[A_PAD_IRQR_ENA/4] = SWAP32(a0);
2935
2936 psxBios_FlushCache();
2937 mips_return_c(0, 34+13+15+6);
2938}
2939
2940void psxBios_StartCARD() { // 4b
2941 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4b]);
2942 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2943 psxBios_SysEnqIntRP_(2, A_PADCRD_CHN_E);
2944
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);
2952}
2953
2954void psxBios_StopCARD() { // 4c
2955 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4c]);
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);
2961}
2962
2963void psxBios__card_write() { // 0x4e
2964 void *pa2 = Ra2;
2965 int port;
2966
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)
2971 {
2972 /* Invalid sectors */
2973 v0 = 0; pc0 = ra;
2974 return;
2975 }
2976 storeRam32(A_CARD_ACHAN, a0);
2977 port = a0 >> 4;
2978
2979 if (pa2 != INVALID_PTR && a1 < 0x400) {
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 }
2987 }
2988
2989 storeRam8(A_CARD_STATUS1 + port, 4); // busy/write
2990 storeRam32(A_CARD_HANDLER, CARD_HARDLER_READ);
2991
2992 v0 = 1; pc0 = ra;
2993}
2994
2995static void psxBios__card_read() { // 0x4f
2996 void *pa2 = Ra2;
2997 int port;
2998
2999 PSXBIOS_LOG("psxBios_%s %x,%x,%x\n", biosB0n[0x4f], a0, a1, a2);
3000 if (a1 > 0x400)
3001 {
3002 /* Invalid sectors */
3003 v0 = 0; pc0 = ra;
3004 return;
3005 }
3006 storeRam32(A_CARD_ACHAN, a0);
3007 port = a0 >> 4;
3008
3009 if (pa2 != INVALID_PTR && a1 < 0x400) {
3010 if (port == 0) {
3011 memcpy(pa2, Mcd1Data + a1 * 128, 128);
3012 } else {
3013 memcpy(pa2, Mcd2Data + a1 * 128, 128);
3014 }
3015 }
3016
3017 storeRam8(A_CARD_STATUS1 + port, 2); // busy/read
3018 storeRam32(A_CARD_HANDLER, CARD_HARDLER_READ);
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
3031/* According to a user, this allows Final Fantasy Tactics to save/load properly */
3032void psxBios__get_error(void) // 55
3033{
3034 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x55]);
3035 v0 = 0;
3036 pc0 = ra;
3037}
3038
3039void psxBios_Krom2RawAdd() { // 0x51
3040 int i = 0;
3041
3042 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x51]);
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
3084 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x56]);
3085 log_unhandled("GetC0Table @%08x\n", ra);
3086
3087 mips_return_c(A_C0_TABLE, 3);
3088}
3089
3090void psxBios_GetB0Table() { // 57
3091 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x57]);
3092 log_unhandled("GetB0Table @%08x\n", ra);
3093
3094 mips_return_c(A_B0_TABLE, 3);
3095}
3096
3097static void psxBios__card_chan() { // 0x58
3098 // todo: should return active slot channel
3099 // (active - which was last processed by irq code)
3100 u32 ret = loadRam32(A_CARD_ACHAN);
3101 PSXBIOS_LOG("psxBios_%s -> %02x\n", biosB0n[0x58], ret);
3102
3103 mips_return_c(ret, 8);
3104}
3105
3106static void psxBios_ChangeClearPad() { // 5b
3107 u32 ret;
3108 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x5b], a0);
3109 ret = loadRam32(A_PAD_ACK_VBL);
3110 storeRam32(A_PAD_ACK_VBL, a0);
3111
3112 mips_return_c(ret, 6);
3113}
3114
3115static void psxBios__card_status() { // 5c
3116 u8 s = loadRam8(A_CARD_STATUS1 + a0);
3117 PSXBIOS_LOG("psxBios_%s %x -> %x\n", biosB0n[0x5c], a0, s);
3118
3119 mips_return_c(s, 5);
3120}
3121
3122static void psxBios__card_wait() { // 5d
3123 u8 s = loadRam8(A_CARD_STATUS1 + a0);
3124 PSXBIOS_LOG("psxBios_%s %x -> %x\n", biosB0n[0x5d], a0, s);
3125
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 }
3221}
3222
3223/* System calls C0 */
3224
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 }
3234 for (i = 0; i < 4; i++)
3235 psxBios_SysEnqIntRP_(a0, 0x6d58 + i * 0x10);
3236 mips_return_c(0, 9);
3237}
3238
3239static void psxBios_InitException() { // 01
3240 PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x01], a0);
3241 psxBios_SysEnqIntRP_(a0, 0x6da8);
3242 mips_return_c(0, 9);
3243}
3244
3245/*
3246 * int SysEnqIntRP(int index , long *queue);
3247 */
3248
3249static void psxBios_SysEnqIntRP_(u32 priority, u32 chain_eptr) {
3250 u32 old, base = loadRam32(A_TT_ExCB);
3251
3252 old = loadRam32(base + (priority << 3));
3253 storeRam32(base + (priority << 3), chain_eptr);
3254 storeRam32(chain_eptr, old);
3255 mips_return_c(0, 9);
3256}
3257
3258static void psxBios_SysEnqIntRP() { // 02
3259 PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x02], a0, a1);
3260 psxBios_SysEnqIntRP_(a0, a1);
3261}
3262
3263/*
3264 * int SysDeqIntRP(int index , long *queue);
3265 */
3266
3267static void psxBios_SysDeqIntRP_(u32 priority, u32 chain_rm_eptr) {
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
3272 ptr = loadRam32(base + (priority << 3));
3273 while (ptr) {
3274 next = loadRam32(ptr);
3275 if (ptr == chain_rm_eptr) {
3276 storeRam32(base + (priority << 3), next);
3277 ret = ptr;
3278 use_cycles(6);
3279 break;
3280 }
3281 while (next && next != chain_rm_eptr && lim++ < 100) {
3282 ptr = next;
3283 next = loadRam32(ptr);
3284 use_cycles(8);
3285 }
3286 if (next == chain_rm_eptr) {
3287 next = loadRam32(next);
3288 storeRam32(ptr, next);
3289 ret = ptr;
3290 use_cycles(6);
3291 }
3292 break;
3293 }
3294 if (lim == 100)
3295 PSXBIOS_LOG("bad chain %u %x\n", priority, base);
3296
3297 mips_return_c(ret, 12);
3298}
3299
3300static void psxBios_SysDeqIntRP() { // 03
3301 PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x03], a0, a1);
3302 psxBios_SysDeqIntRP_(a0, a1);
3303}
3304
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
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
3336 u32 ret;
3337
3338 PSXBIOS_LOG("psxBios_%s: %x, %x\n", biosC0n[0x0a], a0, a1);
3339
3340 ret = loadRam32(A_RCNT_VBL_ACK + (a0 << 2));
3341 storeRam32(A_RCNT_VBL_ACK + (a0 << 2), a1);
3342 mips_return_c(ret, 8);
3343}
3344
3345static void psxBios_InitDefInt() { // 0c
3346 PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x0c], a0);
3347 // should also clear the autoack table
3348 psxBios_SysEnqIntRP_(a0, 0x6d98);
3349 mips_return_c(0, 20 + 6*2);
3350}
3351
3352void psxBios_dummy() {
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);
3360}
3361
3362void (*biosA0[256])();
3363// C0 and B0 overlap (end of C0 is start of B0)
3364void (*biosC0[256+128])();
3365void (**biosB0)() = biosC0 + 128;
3366
3367static void setup_mips_code()
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
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 },
3412 { 0x49bc, hleop_exc_padcard1 }, // hleExcPadCard1
3413 { 0x4a4c, hleop_exc_padcard2 },
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
3432 // install the hle traps
3433 if (handler1) PSXMu32ref(handler1) = HLEOP(chain_hle_op(handler1));
3434 if (handler2) PSXMu32ref(handler2) = HLEOP(chain_hle_op(handler2));
3435}
3436
3437static void setup_tt(u32 tcb_cnt, u32 evcb_cnt, u32 stack)
3438{
3439 u32 *ram32 = (u32 *)psxM;
3440 u32 s_excb = 0x20, s_evcb, s_pcb = 4, s_tcb;
3441 u32 p_excb, p_evcb, p_pcb, p_tcb;
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;
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
3475 storeRam32(p_excb + 0*4, 0x0000); // chain0
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
3482 for (i = 1; i < tcb_cnt; i++)
3483 storeRam32(p_tcb + sizeof(TCB) * i, 0x1000);
3484
3485 psxBios_SysEnqIntRP_(0, 0x6da8);
3486 setup_cd_irq_and_events();
3487
3488 storeRam32(A_CONF_EvCB, evcb_cnt);
3489 storeRam32(A_CONF_TCB, tcb_cnt);
3490 storeRam32(A_CONF_SP, stack);
3491}
3492
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]);
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
3575static void hleExc0_0_1();
3576static void hleExc0_0_2();
3577static void hleExc0_1_1();
3578static void hleExc0_1_2();
3579
3580#include "sjisfont.h"
3581
3582void psxBiosInit() {
3583 u32 *ptr, *ram32, *rom32;
3584 char *romc;
3585 int i;
3586 uLongf len;
3587
3588 psxRegs.biosBranchCheck = ~0;
3589
3590 memset(psxM, 0, 0x10000);
3591 for(i = 0; i < 256; i++) {
3592 biosA0[i] = NULL;
3593 biosB0[i] = NULL;
3594 biosC0[i] = NULL;
3595 }
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;
3600
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 }
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;
3625 biosA0[0x08] = psxBios_getc;
3626 biosA0[0x09] = psxBios_putc;
3627 biosA0[0x0a] = psxBios_todigit;
3628 //biosA0[0x0b] = psxBios_atof;
3629 biosA0[0x0c] = psxBios_strtoul;
3630 biosA0[0x0d] = psxBios_strtol;
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;
3677 biosA0[0x3c] = psxBios_putchar;
3678 //biosA0[0x3d] = psxBios_gets;
3679 biosA0[0x3e] = psxBios_puts;
3680 biosA0[0x3f] = psxBios_printf;
3681 biosA0[0x40] = psxBios_SystemErrorUnresolvedException;
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;
3695 //biosA0[0x4e] = psxBios_GPU_sync;
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;
3701 biosA0[0x54] = psxBios_CdInit;
3702 biosA0[0x55] = psxBios__bu_init;
3703 biosA0[0x56] = psxBios_CdRemove;
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;
3730 biosA0[0x71] = psxBios_CdInit;
3731 biosA0[0x72] = psxBios_CdRemove;
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;
3747 //biosA0[0x82] = psxBios_sys_a0_82;
3748 //biosA0[0x83] = psxBios_sys_a0_83;
3749 //biosA0[0x84] = psxBios_sys_a0_84;
3750 //biosA0[0x85] = psxBios__96_CdStop;
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;
3761 biosA0[0x90] = hleExc0_1_2;
3762 biosA0[0x91] = hleExc0_0_2;
3763 biosA0[0x92] = hleExc0_1_1;
3764 biosA0[0x93] = hleExc0_0_1;
3765 //biosA0[0x94] = psxBios_sys_a0_94;
3766 biosA0[0x95] = psxBios_CdReset;
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;
3773 biosA0[0x9c] = psxBios_SetConf;
3774 biosA0[0x9d] = psxBios_GetConf;
3775 //biosA0[0x9e] = psxBios_sys_a0_9e;
3776 biosA0[0x9f] = psxBios_SetMem;
3777 //biosA0[0xa0] = psxBios__boot;
3778 //biosA0[0xa1] = psxBios_SystemError;
3779 biosA0[0xa2] = psxBios_EnqueueCdIntr;
3780 biosA0[0xa3] = psxBios_DequeueCdIntr;
3781 //biosA0[0xa4] = psxBios_sys_a0_a4;
3782 //biosA0[0xa5] = psxBios_ReadSector;
3783 biosA0[0xa6] = psxBios_get_cd_status;
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;
3797 biosA0[0xb4] = psxBios_GetSystemInfo;
3798//*******************B0 CALLS****************************
3799 biosB0[0x00] = psxBios_SysMalloc;
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;
3860 biosB0[0x3d] = psxBios_putchar;
3861 //biosB0[0x3e] = psxBios_gets;
3862 biosB0[0x3f] = psxBios_puts;
3863 biosB0[0x40] = psxBios_cd;
3864 biosB0[0x41] = psxBios_format;
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;
3884 biosB0[0x55] = psxBios__get_error;
3885 biosB0[0x56] = psxBios_GetC0Table;
3886 biosB0[0x57] = psxBios_GetB0Table;
3887 biosB0[0x58] = psxBios__card_chan;
3888 //biosB0[0x59] = psxBios_sys_b0_59;
3889 //biosB0[0x5a] = psxBios_sys_b0_5a;
3890 biosB0[0x5b] = psxBios_ChangeClearPad;
3891 biosB0[0x5c] = psxBios__card_status;
3892 biosB0[0x5d] = psxBios__card_wait;
3893//*******************C0 CALLS****************************
3894 biosC0[0x00] = psxBios_InitRCnt;
3895 biosC0[0x01] = psxBios_InitException;
3896 biosC0[0x02] = psxBios_SysEnqIntRP;
3897 biosC0[0x03] = psxBios_SysDeqIntRP;
3898 biosC0[0x04] = psxBios_get_free_EvCB_slot;
3899 //biosC0[0x05] = psxBios_get_free_TCB_slot;
3900 //biosC0[0x06] = psxBios_ExceptionHandler;
3901 //biosC0[0x07] = psxBios_InstallExeptionHandler;
3902 biosC0[0x08] = psxBios_SysInitMemory;
3903 //biosC0[0x09] = psxBios_SysInitKMem;
3904 biosC0[0x0a] = psxBios_ChangeClearRCnt;
3905 //biosC0[0x0b] = psxBios_SystemError;
3906 biosC0[0x0c] = psxBios_InitDefInt;
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/**/
3925
3926 memset(FDesc, 0, sizeof(FDesc));
3927 memset(cdir, 0, sizeof(cdir));
3928 floodchk = 0;
3929
3930 // somewhat pretend to be a SCPH1001 BIOS
3931 // some games look for these and take an exception if they're missing
3932 rom32 = (u32 *)psxR;
3933 rom32[0x100/4] = SWAP32(0x19951204);
3934 rom32[0x104/4] = SWAP32(3);
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");
3940
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
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
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.
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.
3959 */
3960
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
3979 setup_tt(4, 16, 0x801fff00);
3980 DeliverEvent(0xf0000003, 0x0010);
3981
3982 ram32[0x6ee0/4] = SWAPu32(0x0000eff0); // DCB
3983 strcpy((char *)&ram32[0xeff0/4], "bu");
3984
3985 // default exception handler chains
3986 // see also setup_cd_irq_and_events()
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)
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
4002 ptr = (u32 *)&psxM[A_A0_TABLE];
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 }
4007 ptr = (u32 *)&psxM[A_B0_TABLE];
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 }
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
4016 ptr[0x5b] = SWAP32(A_B0_5B_TRAP); // 0x43d0
4017 ram32[A_B0_5B_TRAP/4] = HLEOP(hleop_b0t);
4018
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
4025 ram32[0x4c64/4] = SWAP32(0x03e00008); // jr $ra
4026 ram32[0x4c68/4] = SWAP32(0xac000000 + A_PAD_IRQR_ENA); // sw $0, ...
4027
4028 ptr = (u32 *)&psxM[A_C0_TABLE];
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 }
4033 ptr[6] = SWAP32(A_EXCEPTION);
4034
4035 // more HLE traps
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);
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);
4048 ram32[A_RND_SEED/4] = SWAPu32(0x24040001); // was 0xac20cc00
4049}
4050
4051void psxBiosShutdown() {
4052}
4053
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);
4062}
4063
4064#define psxBios_PADpoll(pad) { \
4065 int i, more_data = 0; \
4066 PAD##pad##_startPoll(pad); \
4067 pad_buf##pad[1] = PAD##pad##_poll(0x42, &more_data); \
4068 pad_buf##pad[0] = more_data ? 0 : 0xff; \
4069 PAD##pad##_poll(0, &more_data); \
4070 i = 2; \
4071 while (more_data) { \
4072 pad_buf##pad[i++] = PAD##pad##_poll(0, &more_data); \
4073 } \
4074}
4075
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}
4086
4087// hleExc0_{0,1}* are usually removed by A(56)/A(72) on the game's startup,
4088// so this is only partially implemented
4089static void hleExc0_0_1() // A(93h) - CdromDmaIrqFunc2
4090{
4091 u32 cdrom_dma_ack_enable = 1; // a000b93c
4092 handle_chain_x_x_1(cdrom_dma_ack_enable, 3); // IRQ3 DMA
4093}
4094
4095static void hleExc0_0_2() // A(91h) - CdromDmaIrqFunc1
4096{
4097 u32 ret = 0;
4098 //PSXBIOS_LOG("%s\n", __func__);
4099
4100 if (psxHu32(0x1074) & psxHu32(0x1070) & 8) { // IRQ3 DMA
4101 psxHwWrite32(0x1f8010f4, (psxHu32(0x10f4) & 0xffffff) | 0x88000000);
4102 //if (--cdrom_irq_counter == 0) // 0xa0009180
4103 // DeliverEvent(0xf0000003, 0x10);
4104 use_cycles(22);
4105 ret = 1;
4106 }
4107 mips_return_c(ret, 20);
4108}
4109
4110static void hleExc0_1_1() // A(92h) - CdromIoIrqFunc2
4111{
4112 u32 cdrom_irq_ack_enable = 1; // a000b938
4113 handle_chain_x_x_1(cdrom_irq_ack_enable, 2); // IRQ2 cdrom
4114}
4115
4116static void hleExc0_1_2() // A(90h) - CdromIoIrqFunc1
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}
4125
4126static void hleExc0_2_2_syscall() // not in any A/B/C table
4127{
4128 u32 tcbPtr = loadRam32(A_TT_PCB);
4129 TCB *tcb = loadRam32ptr(tcbPtr);
4130 u32 code = (SWAP32(tcb->cause) & 0x3c) >> 2;
4131
4132 if (code != R3000E_Syscall) {
4133 if (code != 0) {
4134 DeliverEvent(0xf0000010, 0x1000);
4135 //psxBios_SystemErrorUnresolvedException();
4136 }
4137 mips_return_c(0, 17);
4138 return;
4139 }
4140
4141 //printf("%s c=%d a0=%d\n", __func__, code, SWAP32(tcb->reg[4]));
4142 tcb->epc += SWAP32(4);
4143 switch (SWAP32(tcb->reg[4])) { // a0
4144 case 0: // noop
4145 break;
4146
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);
4159 storeRam32(tcbPtr, SWAP32(tcb->reg[5])); // a1
4160 break;
4161 }
4162 default:
4163 DeliverEvent(0xf0000010, 0x4000);
4164 break;
4165 }
4166 use_cycles(30);
4167 psxBios_ReturnFromException();
4168}
4169
4170static void hleExc1_0_1(void)
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}
4175
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)) {
4180 DeliverEvent(0xf2000000 + ev_index, 0x0002);
4181 ret = 1;
4182 }
4183 mips_return_c(ret, 22);
4184}
4185
4186static void hleExc1_0_2(void)
4187{
4188 handle_chain_1_x_2(3, 0); // IRQ0 vblank
4189}
4190
4191static void hleExc1_1_1(void)
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}
4196
4197static void hleExc1_1_2(void)
4198{
4199 handle_chain_1_x_2(2, 6); // IRQ6 rcnt2
4200}
4201
4202static void hleExc1_2_1(void)
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}
4207
4208static void hleExc1_2_2(void)
4209{
4210 handle_chain_1_x_2(1, 5); // IRQ5 rcnt1
4211}
4212
4213static void hleExc1_3_1(void)
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}
4218
4219static void hleExc1_3_2(void)
4220{
4221 handle_chain_1_x_2(0, 4); // IRQ4 rcnt0
4222}
4223
4224static void hleExc3_0_2_defint(void)
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)) {
4244 DeliverEvent(0xf0000000 + tab[i].ev, 0x1000);
4245 use_cycles(7);
4246 }
4247
4248 }
4249 mips_return_c(0, 11 + 7*11 + 7*11 + 12);
4250}
4251
4252static void hleExcPadCard1(void)
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);
4257
4258 psxBios_PADpoll(1);
4259 psxBios_PADpoll(2);
4260 use_cycles(100);
4261 if (loadRam32(A_PAD_DR_DST))
4262 psxBios_PAD_dr_();
4263 }
4264 if (loadRam32(A_PAD_ACK_VBL))
4265 psxHwWrite16(0x1f801070, ~1);
4266 if (loadRam32(A_CARD_IRQR_ENA))
4267 card_vint_handler();
4268
4269 mips_return_c(0, 18);
4270}
4271
4272static void hleExcPadCard2(void)
4273{
4274 u32 ret = psxHu32(0x1074) & psxHu32(0x1070) & 1;
4275 mips_return_c(ret, 15);
4276}
4277
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;
4285
4286 // save the regs
4287 // $at, $v0, $v1, $ra already saved by the mips code at A_EXCEPTION
4288 for (i = 4; i < 31; i++) {
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);
4295 //tcb->epc = SWAP32(psxRegs.CP0.n.EPC); // done by asm
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);
4301 assert(!psxRegs.cpuInRecursion);
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;
4317
4318 if (v0 == 0 || chain[1] == 0)
4319 continue;
4320 softCallInException(SWAP32(chain[1]));
4321 if (returned_from_exception())
4322 return;
4323 }
4324 }
4325 assert(lim < 100);
4326
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();
4338}
4339
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
4353 use_cycles(4+7);
4354 if (call < 192 && entry != A_A0_TRAPS + call * 4) {
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
4364 //printf("A(%02x) -> %x\n", call, v0);
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
4373 use_cycles(4+7);
4374 if (call == 0x5b)
4375 is_custom = entry != A_B0_5B_TRAP;
4376 else
4377 is_custom = entry != A_B0_TRAPS + call * 4;
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
4388 //printf("B(%02x) -> %x\n", call, v0);
4389 psxBranchTest();
4390}
4391
4392static void hleC0() {
4393 u32 call = t1 & 0xff;
4394 u32 entry = loadRam32(A_C0_TABLE + call * 4);
4395
4396 use_cycles(4+7);
4397 if (call < 128 && entry != A_C0_TRAPS + call * 4) {
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
4407 //printf("C(%02x) -> %x\n", call, v0);
4408 psxBranchTest();
4409}
4410
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
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
4473void (* const psxHLEt[hleop_count_])() = {
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,
4484 hleA0t, hleB0t, hleC0t,
4485};
4486
4487void psxBiosCheckExe(u32 t_addr, u32 t_size, int loading_state)
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;
4525 if (!loading_state)
4526 SysPrintf("HLE vsync @%08x\n", start + i * 4);
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}
4556
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))
4564#define bfreezel(ptr) bfreeze(ptr, sizeof(*(ptr)))
4565
4566void psxBiosFreeze(int Mode) {
4567 u32 base = 0x40000;
4568
4569 bfreezes(FDesc);
4570 bfreezes(ffile);
4571 bfreezel(&nfile);
4572 bfreezes(cdir);
4573}