psxbios: implement get/setconf
[pcsx_rearmed.git] / libpcsxcore / psxbios.c
index 0f8beb0..fbd1af4 100644 (file)
@@ -256,7 +256,7 @@ typedef struct {
 // todo: FileDesc layout is wrong
 // todo: get rid of these globals
 static FileDesc FDesc[32];
-static char ffile[64], *pfile;
+static char ffile[64];
 static int nfile;
 
 // fixed RAM offsets, SCPH1001 compatible
@@ -293,6 +293,10 @@ static int nfile;
 #define A_HEAP_SIZE     0x9004
 #define A_HEAP_END      0x9008
 #define A_HEAP_FLAG     0x900c
+#define A_RND_SEED      0x9010
+#define A_CONF_TCB      0xb940
+#define A_CONF_EvCB     0xb944
+#define A_CONF_SP       0xb948
 #define A_CD_EVENTS     0xb9b8
 #define A_EXC_GP        0xf450
 
@@ -393,6 +397,10 @@ static inline void softCallInException(u32 pc) {
        u32 sra = ra;
        u32 lim = 0;
        pc0 = pc;
+
+       assert(ra != 0x80001000);
+       if (ra == 0x80001000)
+               return;
        ra = 0x80001000;
 
        while (!returned_from_exception() && pc0 != 0x80001000 && ++lim < 1000000)
@@ -1080,16 +1088,16 @@ void psxBios_memchr() { // 0x2e
        v0 = 0; pc0 = ra;
 }
 
-void psxBios_rand() { // 0x2f
-       u32 s = psxMu32(0x9010) * 1103515245 + 12345;
-       v0 = (s >> 16) & 0x7fff;
-       psxMu32ref(0x9010) = SWAPu32(s);
-       pc0 = ra;
+static void psxBios_rand() { // 0x2f
+       u32 s = loadRam32(A_RND_SEED) * 1103515245 + 12345;
+       storeRam32(A_RND_SEED, s);
+       v1 = s;
+       mips_return_c((s >> 16) & 0x7fff, 12+37);
 }
 
-void psxBios_srand() { // 0x30
-       psxMu32ref(0x9010) = SWAPu32(a0);
-       pc0 = ra;
+static void psxBios_srand() { // 0x30
+       storeRam32(A_RND_SEED, a0);
+       mips_return_void_c(3);
 }
 
 static u32 qscmpfunc, qswidth;
@@ -1571,7 +1579,7 @@ void psxBios_GPU_dw() { // 0x46
 
 void psxBios_mem2vram() { // 0x47
        int size;
-       gpuSyncPluginSR();
+       gpuSyncPluginSR(); // flush
        GPU_writeData(0xa0000000);
        GPU_writeData((a1<<0x10)|(a0&0xffff));
        GPU_writeData((a3<<0x10)|(a2&0xffff));
@@ -1593,8 +1601,8 @@ void psxBios_SendGPU() { // 0x48
 }
 
 void psxBios_GPU_cw() { // 0x49
-       gpuSyncPluginSR();
        GPU_writeData(a0);
+       gpuSyncPluginSR();
        v0 = HW_GPU_STATUS;
        pc0 = ra;
 }
@@ -1708,6 +1716,23 @@ static void psxBios_CdRemove() { // 56, 72
        use_cycles(30);
 }
 
+static void setup_tt(u32 tcb_cnt, u32 evcb_cnt, u32 stack);
+
+static void psxBios_SetConf() { // 9c
+       PSXBIOS_LOG("psxBios_%s %x %x %x\n", biosA0n[0x9c], a0, a1, a2);
+       setup_tt(a1, a0, a2);
+       psxRegs.CP0.n.SR |= 0x401;
+       mips_return_void_c(500);
+}
+
+static void psxBios_GetConf() { // 9d
+       PSXBIOS_LOG("psxBios_%s %x %x %x\n", biosA0n[0x9d], a0, a1, a2);
+       storeRam32(a0, loadRam32(A_CONF_EvCB));
+       storeRam32(a1, loadRam32(A_CONF_TCB));
+       storeRam32(a2, loadRam32(A_CONF_SP));
+       mips_return_void_c(10);
+}
+
 void psxBios_SetMem() { // 9f
        u32 new = psxHu32(0x1060);
 
@@ -1882,6 +1907,7 @@ static u32 DeliverEvent(u32 class, u32 spec) {
        u32 ret = loadRam32(A_TT_EvCB) + evcb_len;
        u32 i, lim = evcb_len / 0x1c;
 
+       //printf("%s %08x %x\n", __func__, class, spec);
        for (i = 0; i < lim; i++, ev++) {
                use_cycles(8);
                if (SWAP32(ev->status) != EvStACTIVE)
@@ -2071,7 +2097,7 @@ void psxBios_OpenTh() { // 0e
                mips_return_c(0xffffffff, 20);
                return;
        }
-       PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x0e], th);
+       PSXBIOS_LOG("psxBios_%s -> %x\n", biosB0n[0x0e], 0xff000000 + th);
 
        tcb[th].status  = SWAP32(0x4000);
        tcb[th].mode    = SWAP32(0x1000);
@@ -2087,21 +2113,15 @@ void psxBios_OpenTh() { // 0e
  *     int CloseTh(long thread);
  */
 
-void psxBios_CloseTh() { // 0f
-       TCB *tcb = loadRam32ptr(A_TT_TCB);
-       u32 limit = loadRam32(A_TT_TCB + 4) / 0xc0u;
-       u32 th = a0 & 0xff;
+static void psxBios_CloseTh() { // 0f
+       u32 tcb = loadRam32(A_TT_TCB);
+       u32 th = a0 & 0xffff;
 
-#ifdef PSXBIOS_LOG
-       PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x0f], th);
-#endif
-       /* The return value is always 1 (even if the handle was already closed). */
-       v0 = 1;
-       if (th < limit && tcb[th].status == SWAP32(0x4000)) {
-               tcb[th].status = SWAP32(0x1000);
-       }
+       PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x0f], a0);
+       // in the usual bios fashion no checks, just write and return 1
+       storeRam32(tcb + th * sizeof(TCB), 0x1000);
 
-       pc0 = ra;
+       mips_return_c(1, 11);
 }
 
 /*
@@ -2339,9 +2359,7 @@ static void buopen(int mcd, char *ptr, char *cfg)
 void psxBios_open() { // 0x32
        void *pa0 = Ra0;
 
-#ifdef PSXBIOS_LOG
-       PSXBIOS_LOG("psxBios_%s: %s,%x\n", biosB0n[0x32], Ra0, a1);
-#endif
+       PSXBIOS_LOG("psxBios_%s %s %x\n", biosB0n[0x32], Ra0, a1);
 
        v0 = -1;
 
@@ -2498,7 +2516,9 @@ static size_t strlen_internal(char* p)
 
 #define bufile(mcd) { \
        size_t size_of_name = strlen_internal(dir->name); \
+       v0 = 0; \
        while (nfile < 16) { \
+               char *pfile = ffile+5; \
                int match=1; \
  \
                ptr = Mcd##mcd##Data + 128 * (nfile + 1); \
@@ -2531,22 +2551,17 @@ static size_t strlen_internal(char* p)
  *     struct DIRENTRY* firstfile(char *name,struct DIRENTRY *dir);
  */
 
-void psxBios_firstfile() { // 42
-       struct DIRENTRY *dir = (struct DIRENTRY *)Ra1;
-       void *pa0 = Ra0;
+static void psxBios_firstfile() { // 42
+       struct DIRENTRY *dir = (struct DIRENTRY *)castRam8ptr(a1);
+       char *pa0 = castRam8ptr(a0);
        u32 _dir = a1;
        char *ptr;
        int i;
 
-#ifdef PSXBIOS_LOG
-       PSXBIOS_LOG("psxBios_%s: %s\n", biosB0n[0x42], Ra0);
-#endif
-
        v0 = 0;
 
-       if (pa0 != INVALID_PTR) {
-               strcpy(ffile, pa0);
-               pfile = ffile+5;
+       {
+               snprintf(ffile, sizeof(ffile), "%s", pa0);
                nfile = 0;
                if (!strncmp(pa0, "bu00", 4)) {
                        // firstfile() calls _card_read() internally, so deliver it's event
@@ -2558,6 +2573,7 @@ void psxBios_firstfile() { // 42
                        bufile(2);
                }
        }
+       PSXBIOS_LOG("psxBios_%s %s %x -> %x\n", biosB0n[0x42], pa0, a1, v0);
 
        pc0 = ra;
 }
@@ -2572,19 +2588,15 @@ void psxBios_nextfile() { // 43
        char *ptr;
        int i;
 
-#ifdef PSXBIOS_LOG
-       PSXBIOS_LOG("psxBios_%s: %s\n", biosB0n[0x43], dir->name);
-#endif
-
        v0 = 0;
 
        if (!strncmp(ffile, "bu00", 4)) {
                bufile(1);
        }
-
-       if (!strncmp(ffile, "bu10", 4)) {
+       else if (!strncmp(ffile, "bu10", 4)) {
                bufile(2);
        }
+       PSXBIOS_LOG("psxBios_%s %s -> %x\n", biosB0n[0x43], dir->name, v0);
 
        pc0 = ra;
 }
@@ -3102,12 +3114,21 @@ static void write_chain(u32 *d, u32 next, u32 handler1, u32 handler2)
        if (handler2) PSXMu32ref(handler2) = HLEOP(chain_hle_op(handler2));
 }
 
-static void setup_tt(u32 tcb_cnt, u32 evcb_cnt)
+static void setup_tt(u32 tcb_cnt, u32 evcb_cnt, u32 stack)
 {
        u32 *ram32 = (u32 *)psxM;
-       u32 s_excb = 0x20, s_evcb = 0x1c * evcb_cnt;
-       u32 s_pcb = 4, s_tcb = 0xc0 * tcb_cnt;
+       u32 s_excb = 0x20, s_evcb, s_pcb = 4, s_tcb;
        u32 p_excb, p_evcb, p_pcb, p_tcb;
+       u32 i;
+
+       PSXBIOS_LOG("setup: tcb %u, evcb %u\n", tcb_cnt, evcb_cnt);
+
+       // the real bios doesn't care, but we just don't
+       // want to crash in case of garbage parameters
+       if (tcb_cnt > 1024) tcb_cnt = 1024;
+       if (evcb_cnt > 1024) evcb_cnt = 1024;
+       s_evcb = 0x1c * evcb_cnt;
+       s_tcb = 0xc0 * tcb_cnt;
 
        memset(ram32 + 0xe000/4, 0, s_excb + s_evcb + s_pcb + s_tcb + 5*4);
        psxBios_SysInitMemory_(0xa000e000, 0x2000);
@@ -3138,6 +3159,8 @@ static void setup_tt(u32 tcb_cnt, u32 evcb_cnt)
 
        storeRam32(p_pcb, p_tcb);
        storeRam32(p_tcb, 0x4000);          // first TCB
+       for (i = 1; i < tcb_cnt; i++)
+               storeRam32(p_tcb + sizeof(TCB) * i, 0x1000);
 
        // default events
        storeRam32(A_CD_EVENTS + 0x00, OpenEvent(0xf0000003, 0x0010, EvMdMARK, 0));
@@ -3145,7 +3168,10 @@ static void setup_tt(u32 tcb_cnt, u32 evcb_cnt)
        storeRam32(A_CD_EVENTS + 0x08, OpenEvent(0xf0000003, 0x0040, EvMdMARK, 0));
        storeRam32(A_CD_EVENTS + 0x0c, OpenEvent(0xf0000003, 0x0080, EvMdMARK, 0));
        storeRam32(A_CD_EVENTS + 0x10, OpenEvent(0xf0000003, 0x8000, EvMdMARK, 0));
-       DeliverEvent(0xf0000003, 0x0010);
+
+       storeRam32(A_CONF_EvCB, evcb_cnt);
+       storeRam32(A_CONF_TCB, tcb_cnt);
+       storeRam32(A_CONF_SP, stack);
 }
 
 static const u32 gpu_ctl_def[] = {
@@ -3413,8 +3439,8 @@ void psxBiosInit() {
        //biosA0[0x99] = psxBios_EnableKernelIORedirection;
        //biosA0[0x9a] = psxBios_sys_a0_9a;
        //biosA0[0x9b] = psxBios_sys_a0_9b;
-       //biosA0[0x9c] = psxBios_SetConf;
-       //biosA0[0x9d] = psxBios_GetConf;
+       biosA0[0x9c] = psxBios_SetConf;
+       biosA0[0x9d] = psxBios_GetConf;
        //biosA0[0x9e] = psxBios_sys_a0_9e;
        biosA0[0x9f] = psxBios_SetMem;
        //biosA0[0xa0] = psxBios__boot;
@@ -3568,9 +3594,6 @@ void psxBiosInit() {
 
        memset(FDesc, 0, sizeof(FDesc));
 
-       // initial RNG seed
-       psxMu32ref(0x9010) = SWAPu32(0xac20cc00);
-
        // somewhat pretend to be a SCPH1001 BIOS
        // some games look for these and take an exception if they're missing
        rom32 = (u32 *)psxR;
@@ -3619,7 +3642,8 @@ void psxBiosInit() {
        ram32[0x00b0/4] = HLEOP(hleop_b0);
        ram32[0x00c0/4] = HLEOP(hleop_c0);
 
-       setup_tt(4, 16);
+       setup_tt(4, 16, 0x801fff00);
+       DeliverEvent(0xf0000003, 0x0010);
 
        ram32[0x6ee0/4] = SWAPu32(0x0000eff0); // DCB
        strcpy((char *)&ram32[0xeff0/4], "bu");
@@ -3668,7 +3692,6 @@ void psxBiosInit() {
        ram32[0x1000/4] = HLEOP(hleop_dummy);
        ram32[0x2000/4] = HLEOP(hleop_dummy);
        ram32[0x3000/4] = HLEOP(hleop_dummy);
-       ram32[0x4c54/4] = HLEOP(hleop_dummy);   // for B12_InitPad?
        ram32[0x8000/4] = HLEOP(hleop_execret);
 
        ram32[A_EEXIT_PTR/4] = SWAP32(A_EEXIT_DEF);
@@ -3677,14 +3700,20 @@ void psxBiosInit() {
        ram32[A_RCNT_VBL_ACK/4 + 1] = SWAP32(1);
        ram32[A_RCNT_VBL_ACK/4 + 2] = SWAP32(1);
        ram32[A_RCNT_VBL_ACK/4 + 3] = SWAP32(1);
+       ram32[A_RND_SEED/4] = SWAPu32(0x24040001); // was 0xac20cc00
 }
 
 void psxBiosShutdown() {
 }
 
-void psxBiosCnfLoaded(u32 tcb_cnt, u32 evcb_cnt) {
-       if (tcb_cnt != 4 || evcb_cnt != 16)
-               setup_tt(tcb_cnt, evcb_cnt);
+void psxBiosCnfLoaded(u32 tcb_cnt, u32 evcb_cnt, u32 stack) {
+       if (stack == 0)
+               stack = 0x801FFF00;
+       if (tcb_cnt != 4 || evcb_cnt != 16) {
+               setup_tt(tcb_cnt, evcb_cnt, stack);
+               DeliverEvent(0xf0000003, 0x0010);
+       }
+       storeRam32(A_CONF_SP, stack);
 }
 
 #define psxBios_PADpoll(pad) { \
@@ -3755,9 +3784,9 @@ void hleExc0_1_2() // A(90h) - CdromIoIrqFunc1
 
 void hleExc0_2_2_syscall() // not in any A/B/C table
 {
-       u32 code = (psxRegs.CP0.n.Cause & 0x3c) >> 2;
        u32 tcbPtr = loadRam32(A_TT_PCB);
        TCB *tcb = loadRam32ptr(tcbPtr);
+       u32 code = (SWAP32(tcb->cause) & 0x3c) >> 2;
 
        if (code != R3000E_Syscall) {
                if (code != 0) {
@@ -3768,9 +3797,9 @@ void hleExc0_2_2_syscall() // not in any A/B/C table
                return;
        }
 
-       //printf("%s c=%d a0=%d\n", __func__, code, a0);
+       //printf("%s c=%d a0=%d\n", __func__, code, SWAP32(tcb->reg[4]));
        tcb->epc += SWAP32(4);
-       switch (a0) {
+       switch (SWAP32(tcb->reg[4])) { // a0
                case 0: // noop
                        break;
 
@@ -3786,7 +3815,7 @@ void hleExc0_2_2_syscall() // not in any A/B/C table
 
                case 3: { // ChangeThreadSubFunction
                        u32 tcbPtr = loadRam32(A_TT_PCB);
-                       storeRam32(tcbPtr, a1);
+                       storeRam32(tcbPtr, SWAP32(tcb->reg[5])); // a1
                        break;
                }
                default:
@@ -3975,21 +4004,12 @@ void psxBiosException() {
 }
 
 #define bfreezes(ptr) bfreeze(ptr, sizeof(ptr))
-#define bfreezel(ptr) bfreeze(ptr, sizeof(*ptr))
-
-#define bfreezepsxMptr(ptr, type) { \
-       if (Mode == 1) { \
-               if (ptr) psxRu32ref(base) = SWAPu32((s8 *)(ptr) - psxM); \
-               else psxRu32ref(base) = 0; \
-       } else { \
-               if (psxRu32(base) != 0) ptr = (type *)(psxM + psxRu32(base)); \
-               else (ptr) = NULL; \
-       } \
-       base += sizeof(u32); \
-}
+#define bfreezel(ptr) bfreeze(ptr, sizeof(*(ptr)))
 
 void psxBiosFreeze(int Mode) {
        u32 base = 0x40000;
 
        bfreezes(FDesc);
+       bfreezes(ffile);
+       bfreezel(&nfile);
 }