cdrom: fail pausing on seek
[pcsx_rearmed.git] / libpcsxcore / psxbios.c
index af3c55f..e654f7c 100644 (file)
@@ -303,10 +303,10 @@ static u32 floodchk;
 #define A_CD_EVENTS     0xb9b8
 #define A_EXC_GP        0xf450
 
-#define A_A0_DUMMY      0x1010
-#define A_B0_DUMMY      0x2010
-#define A_C0_DUMMY      0x3010
-#define A_B0_5B_DUMMY   0x43d0
+#define A_A0_TRAPS      0x1010
+#define A_B0_TRAPS      0x2010
+#define A_C0_TRAPS      0x3010
+#define A_B0_5B_TRAP    0x43d0
 
 #define HLEOP(n) SWAPu32((0x3b << 26) | (n));
 
@@ -532,12 +532,8 @@ void psxBios_putc(void) // 0x09, 0x3B
        pc0 = ra;
 }
 
-void psxBios_todigit(void) // 0x0a
+static u32 do_todigit(u32 c)
 {
-       int c = a0;
-#ifdef PSXBIOS_LOG
-       PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x0a]);
-#endif
        c &= 0xFF;
        if (c >= 0x30 && c < 0x3A) {
                c -= 0x30;
@@ -549,14 +545,73 @@ void psxBios_todigit(void) // 0x0a
                c = c - 0x41 + 10;
        }
        else if (c >= 0x80) {
+               log_unhandled("todigit %02x\n", c);
                c = -1;
        }
        else
        {
                c = 0x0098967F;
        }
-       v0 = c;
-       pc0 = ra;
+       use_cycles(40);
+       return c;
+}
+
+static void psxBios_todigit(void) // 0x0a
+{
+       mips_return(do_todigit(a0));
+       PSXBIOS_LOG("psxBios_%s '%c' -> %u\n", biosA0n[0x0a], a0, v0);
+}
+
+static void do_strtol(char *p, void *end_, u32 base, int can_neg) {
+       s32 n = 0, f = 0, t;
+       u32 *end = end_;
+
+       use_cycles(12);
+       if (p == INVALID_PTR) {
+               mips_return(0);
+               return;
+       }
+
+       for (; (0x09 <= *p && *p <= '\r') || *p == ' '; p++)
+               use_cycles(9);
+       if (can_neg) {
+               for (; *p == '-'; f = 1, p++)
+                       use_cycles(4);
+       }
+       if (base == 0 || base > 36)
+               base = 10;
+       if (*p == '0') {
+               switch (*p++) {
+               case 'b': case 'B': base = 2; break;
+               case 'x': case 'X': base = 16; break;
+               }
+       }
+       else if (*p == 'o' || *p == 'O') {
+               base = 8;
+               p++;
+       }
+
+       for (; (t = do_todigit(*p)) < base; p++) {
+               n = n * base + t;
+               use_cycles(12);
+       }
+
+       n = (f ? -n : n);
+       if (end != INVALID_PTR)
+               *end = SWAP32(a0 + (p - Ra0));
+       mips_return_c(n, 100);
+}
+
+static void psxBios_strtoul() { // 0x0c
+       do_strtol(a0 ? Ra0 : INVALID_PTR, a1 ? Ra1 : INVALID_PTR, a2, 0);
+       PSXBIOS_LOG("psxBios_%s %s (%x), %x, %x -> 0x%x\n",
+               biosA0n[0x0c], a0 ? Ra0 : NULL, a0, a1, a2, v0);
+}
+
+static void psxBios_strtol() { // 0x0d
+       do_strtol(a0 ? Ra0 : INVALID_PTR, a1 ? Ra1 : INVALID_PTR, a2, 1);
+       PSXBIOS_LOG("psxBios_%s %s (%x), %x, %x -> 0x%x\n",
+               biosA0n[0x0d], a0 ? Ra0 : NULL, a0, a1, a2, v0);
 }
 
 void psxBios_abs() { // 0x0e
@@ -3322,7 +3377,6 @@ void psxBiosSetupBootState(void)
                GPU_writeStatus(gpu_ctl_def[i]);
        for (i = 0; i < sizeof(gpu_data_def) / sizeof(gpu_data_def[0]); i++)
                GPU_writeData(gpu_data_def[i]);
-       HW_GPU_STATUS |= SWAP32(PSXGPU_nBUSY);
 
        // spu
        for (i = 0x1f801d80; i < sizeof(spu_config) / sizeof(spu_config[0]); i++)
@@ -3383,8 +3437,8 @@ void psxBiosInit() {
        biosA0[0x09] = psxBios_putc;
        biosA0[0x0a] = psxBios_todigit;
        //biosA0[0x0b] = psxBios_atof;
-       //biosA0[0x0c] = psxBios_strtoul;
-       //biosA0[0x0d] = psxBios_strtol;
+       biosA0[0x0c] = psxBios_strtoul;
+       biosA0[0x0d] = psxBios_strtol;
        biosA0[0x0e] = psxBios_abs;
        biosA0[0x0f] = psxBios_labs;
        biosA0[0x10] = psxBios_atoi;
@@ -3753,18 +3807,25 @@ void psxBiosInit() {
 
        // fill the api jumptables with fake entries as some games patch them
        // (or rather the funcs listed there)
+       // also trap the destination as some "Cheats Edition" thing overrides the
+       // dispatcher with a wrapper and then jumps to the table entries directly
        ptr = (u32 *)&psxM[A_A0_TABLE];
-       for (i = 0; i < 256; i++)
-               ptr[i] = SWAP32(A_A0_DUMMY);
-
+       for (i = 0; i < 256; i++) {
+               ptr[i] = SWAP32(A_A0_TRAPS + i*4);
+               ram32[A_A0_TRAPS/4 + i] = HLEOP(hleop_a0t);
+       }
        ptr = (u32 *)&psxM[A_B0_TABLE];
-       for (i = 0; i < 256; i++)
-               ptr[i] = SWAP32(A_B0_DUMMY);
+       for (i = 0; i < 256; i++) {
+               ptr[i] = SWAP32(A_B0_TRAPS + i*4);
+               ram32[A_B0_TRAPS/4 + i] = HLEOP(hleop_b0t);
+       }
        // B(5b) is special because games patch (sometimes even jump to)
        // code at fixed offsets from it, nocash lists offsets:
        //  patch: +3d8, +4dc, +594, +62c, +9c8, +1988
        //  call:  +7a0=4b70, +884=4c54, +894=4c64
-       ptr[0x5b] = SWAP32(A_B0_5B_DUMMY);    // 0x43d0
+       ptr[0x5b] = SWAP32(A_B0_5B_TRAP);     // 0x43d0
+       ram32[A_B0_5B_TRAP/4] = HLEOP(hleop_b0t);
+
        ram32[0x4b70/4] = SWAP32(0x03e00008); // jr $ra // setPadOutputBuf
 
        ram32[0x4c54/4] = SWAP32(0x240e0001); // mov $t6, 1
@@ -3775,15 +3836,17 @@ void psxBiosInit() {
        ram32[0x4c68/4] = SWAP32(0xac000000 + A_PAD_IRQR_ENA); // sw $0, ...
 
        ptr = (u32 *)&psxM[A_C0_TABLE];
-       for (i = 0; i < 256/2; i++)
-               ptr[i] = SWAP32(A_C0_DUMMY);
+       for (i = 0; i < 256/2; i++) {
+               ptr[i] = SWAP32(A_C0_TRAPS + i*4);
+               ram32[A_C0_TRAPS/4 + i] = HLEOP(hleop_c0t);
+       }
        ptr[6] = SWAP32(A_EXCEPTION);
 
        // more HLE traps
-       ram32[A_A0_DUMMY/4] = HLEOP(hleop_dummy);
-       ram32[A_B0_DUMMY/4] = HLEOP(hleop_dummy);
-       ram32[A_C0_DUMMY/4] = HLEOP(hleop_dummy);
-       ram32[A_B0_5B_DUMMY/4] = HLEOP(hleop_dummy);
+       ram32[A_A0_TRAPS/4 - 1] = HLEOP(hleop_dummy);
+       ram32[A_B0_TRAPS/4 - 1] = HLEOP(hleop_dummy);
+       ram32[A_C0_TRAPS/4 - 1] = HLEOP(hleop_dummy);
+       ram32[0x7ffc/4] = HLEOP(hleop_dummy);
        ram32[0x8000/4] = HLEOP(hleop_execret);
 
        ram32[A_EEXIT_PTR/4] = SWAP32(A_EEXIT_DEF);
@@ -4098,7 +4161,8 @@ static void hleA0() {
        u32 call = t1 & 0xff;
        u32 entry = loadRam32(A_A0_TABLE + call * 4);
 
-       if (call < 192 && entry != A_A0_DUMMY) {
+       use_cycles(4+7);
+       if (call < 192 && entry != A_A0_TRAPS + call * 4) {
                PSXBIOS_LOG("custom A%02x %s(0x%x, )  addr=%08x ra=%08x\n",
                        call, biosA0n[call], a0, entry, ra);
                softCall(entry);
@@ -4117,10 +4181,11 @@ static void hleB0() {
        u32 entry = loadRam32(A_B0_TABLE + call * 4);
        int is_custom = 0;
 
+       use_cycles(4+7);
        if (call == 0x5b)
-               is_custom = entry != A_B0_5B_DUMMY;
+               is_custom = entry != A_B0_5B_TRAP;
        else
-               is_custom = entry != A_B0_DUMMY;
+               is_custom = entry != A_B0_TRAPS + call * 4;
        if (is_custom) {
                PSXBIOS_LOG("custom B%02x %s(0x%x, )  addr=%08x ra=%08x\n",
                        call, biosB0n[call], a0, entry, ra);
@@ -4139,7 +4204,8 @@ static void hleC0() {
        u32 call = t1 & 0xff;
        u32 entry = loadRam32(A_C0_TABLE + call * 4);
 
-       if (call < 128 && entry != A_C0_DUMMY) {
+       use_cycles(4+7);
+       if (call < 128 && entry != A_C0_TRAPS + call * 4) {
                PSXBIOS_LOG("custom C%02x %s(0x%x, )  addr=%08x ra=%08x\n",
                        call, biosC0n[call], a0, entry, ra);
                softCall(entry);
@@ -4153,6 +4219,47 @@ static void hleC0() {
        psxBranchTest();
 }
 
+static void hleA0t() {
+       u32 call = (pc0 - A_A0_TRAPS) / 4 - 1;
+       if (call >= 256u || !biosA0[call]) {
+               log_unhandled("unexpected A trap @%08x ra=%08x\n", pc0 - 4, ra);
+               mips_return_void_c(1000);
+       }
+       else
+               biosA0[call]();
+
+       //printf("A(%02x) -> %x\n", call, v0);
+       psxBranchTest();
+}
+
+static void hleB0t() {
+       u32 call = (pc0 - A_B0_TRAPS) / 4 - 1;
+       if (pc0 - 4 == A_B0_5B_TRAP)
+               call = 0x5b;
+       if (call >= 256u || !biosB0[call]) {
+               log_unhandled("unexpected B trap @%08x ra=%08x\n", pc0 - 4, ra);
+               mips_return_void_c(1000);
+       }
+       else
+               biosB0[call]();
+
+       //printf("B(%02x) -> %x\n", call, v0);
+       psxBranchTest();
+}
+
+static void hleC0t() {
+       u32 call = (pc0 - A_C0_TRAPS) / 4 - 1;
+       if (call >= 128u || !biosC0[call]) {
+               log_unhandled("unexpected C trap @%08x ra=%08x\n", pc0 - 4, ra);
+               mips_return_void_c(1000);
+       }
+       else
+               biosC0[call]();
+
+       //printf("C(%02x) -> %x\n", call, v0);
+       psxBranchTest();
+}
+
 // currently not used
 static void hleBootstrap() {
        CheckCdrom();
@@ -4174,7 +4281,7 @@ static void hleExecRet() {
        psxRegs.pc = ra;
 }
 
-void (* const psxHLEt[24])() = {
+void (* const psxHLEt[hleop_count_])() = {
        hleDummy, hleA0, hleB0, hleC0,
        hleBootstrap, hleExecRet, psxBiosException, hleDummy,
        hleExc0_0_1, hleExc0_0_2,
@@ -4185,6 +4292,7 @@ void (* const psxHLEt[24])() = {
        hleExc1_3_1, hleExc1_3_2,
        hleExc3_0_2_defint,
        hleExcPadCard1, hleExcPadCard2,
+       hleA0t, hleB0t, hleC0t,
 };
 
 void psxBiosCheckExe(u32 t_addr, u32 t_size, int loading_state)