Fix corrupted memory card saves when using HLE
[pcsx_rearmed.git] / libpcsxcore / psxbios.c
index 98e467a..ecd4264 100644 (file)
@@ -307,6 +307,8 @@ static inline void DeliverEvent(u32 ev, u32 spec) {
        } else Event[ev][spec].status = EvStALREADY;
 }
 
+static unsigned interrupt_r26=0x8004E8B0;
+
 static inline void SaveRegs() {
        memcpy(regs, psxRegs.GPR.r, 32*4);
        regs[32] = psxRegs.GPR.n.lo;
@@ -344,6 +346,7 @@ static inline void LoadRegs() {
        ptr = Mcd##mcd##Data + offset; \
        memcpy(ptr, Ra1, length); \
        FDesc[1 + mcd].offset += length; \
+       SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, offset, length); \
        if (FDesc[1 + mcd].mode & 0x8000) { \
        DeliverEvent(0x11, 0x2); /* 0xf0000011, 0x0004 */ \
        DeliverEvent(0x81, 0x2); /* 0xf4000001, 0x0004 */ \
@@ -922,6 +925,12 @@ void psxBios_memcmp() { // 0x2d
 
 void psxBios_memchr() { // 0x2e
        char *p = (char *)Ra0;
+       
+       if (a0 == 0 || a2 > 0x7FFFFFFF)
+       {
+               pc0 = ra;
+               return;
+       }
 
        while ((s32)a2-- > 0) {
                if (*p++ != (s8)a1) continue;
@@ -1555,6 +1564,13 @@ void psxBios_SetMem() { // 9f
        pc0 = ra;
 }
 
+/* TODO FIXME : Not compliant. -1 indicates failure but using 1 for now. */
+void psxBios_get_cd_status(void) //a6
+{
+       v0 = 1;
+       pc0 = ra;
+}
+
 void psxBios__card_info() { // ab
 #ifdef PSXBIOS_LOG
        PSXBIOS_LOG("psxBios_%s: %x\n", biosA0n[0xab], a0);
@@ -1578,11 +1594,8 @@ void psxBios__card_info() { // ab
                break;
        }
        
-//     DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004
-//     DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004
-       DeliverEvent(0x81, 0x2); // 0xf4000001, 0x0004
+       DeliverEvent(0x11, 0x2); // 0xf4000001, 0x0004
        DeliverEvent(0x81, ret); // 0xf4000001, 0x0004
-
        v0 = 1; pc0 = ra;
 }
 
@@ -1863,12 +1876,10 @@ void psxBios_CloseTh() { // 0f
 #ifdef PSXBIOS_LOG
        PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x0f], th);
 #endif
-
-       if (Thread[th].status == 0) {
-               v0 = 0;
-       } else {
+       /* The return value is always 1 (even if the handle was already closed). */
+       v0 = 1;
+       if (Thread[th].status != 0) {
                Thread[th].status = 0;
-               v0 = 1;
        }
 
        pc0 = ra;
@@ -1884,14 +1895,11 @@ void psxBios_ChangeTh() { // 10
 #ifdef PSXBIOS_LOG
 //     PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x10], th);
 #endif
-
+       /* The return value is always 1. */
+       v0 = 1;
        if (Thread[th].status == 0 || CurThread == th) {
-               v0 = 0;
-
                pc0 = ra;
        } else {
-               v0 = 1;
-
                if (Thread[CurThread].status == 2) {
                        Thread[CurThread].status = 1;
                        Thread[CurThread].func = ra;
@@ -1968,6 +1976,7 @@ void psxBios_ReturnFromException() { // 17
        LoadRegs();
 
        pc0 = psxRegs.CP0.n.EPC;
+       k0 = interrupt_r26;
        if (psxRegs.CP0.n.Cause & 0x80000000) pc0 += 4;
 
        psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status & 0xfffffff0) |
@@ -2275,7 +2284,7 @@ void psxBios_firstfile() { // 42
        if (pa0) {
                strcpy(ffile, pa0);
                pfile = ffile+5;
-               nfile = 1;
+               nfile = 0;
                if (!strncmp(pa0, "bu00", 4)) {
                        // firstfile() calls _card_read() internally, so deliver it's event
                        DeliverEvent(0x11, 0x2);
@@ -2442,8 +2451,11 @@ void psxBios__card_write() { // 0x4e
 #ifdef PSXBIOS_LOG
        PSXBIOS_LOG("psxBios_%s: %x,%x,%x\n", biosB0n[0x4e], a0, a1, a2);
 #endif
-       /* Function also accepts sector 400h (a bug) */
-       if (!(a1 <= 0x400))
+       /*
+       Function also accepts sector 400h (a bug).
+       But notaz said we shouldn't allow sector 400h because it can corrupt the emulator.
+       */
+       if (!(a1 <= 0x3FF))
        {
                /* Invalid sectors */
                v0 = 0; pc0 = ra;
@@ -2475,8 +2487,11 @@ void psxBios__card_read() { // 0x4f
 #ifdef PSXBIOS_LOG
        PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4f]);
 #endif
-       /* Function also accepts sector 400h (a bug) */
-       if (!(a1 <= 0x400))
+       /*
+       Function also accepts sector 400h (a bug).
+       But notaz said we shouldn't allow sector 400h because it can corrupt the emulator.
+       */
+       if (!(a1 <= 0x3FF))
        {
                /* Invalid sectors */
                v0 = 0; pc0 = ra;
@@ -2595,7 +2610,7 @@ void psxBios__card_status() { // 5c
        PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x5c], a0);
 #endif
 
-       v0 = 1;
+       v0 = card_active_chan;
        pc0 = ra;
 }
 
@@ -2855,7 +2870,7 @@ void psxBiosInit() {
        //biosA0[0xa3] = psxBios_DequeueCdIntr;
        //biosA0[0xa4] = psxBios_sys_a0_a4;
        //biosA0[0xa5] = psxBios_ReadSector;
-       //biosA0[0xa6] = psxBios_get_cd_status;
+       biosA0[0xa6] = psxBios_get_cd_status;
        //biosA0[0xa7] = psxBios_bufs_cb_0;
        //biosA0[0xa8] = psxBios_bufs_cb_1;
        //biosA0[0xa9] = psxBios_bufs_cb_2;
@@ -3042,7 +3057,9 @@ void psxBiosInit() {
 */
        // opcode HLE
        psxRu32ref(0x0000) = SWAPu32((0x3b << 26) | 4);
-       psxMu32ref(0x0000) = SWAPu32((0x3b << 26) | 0);
+       /* Whatever this does, it actually breaks CTR, even without the uninitiliazed memory patch. 
+       Normally games shouldn't read from address 0 yet they do. See explanation below in details. */
+       //psxMu32ref(0x0000) = SWAPu32((0x3b << 26) | 0);
        psxMu32ref(0x00a0) = SWAPu32((0x3b << 26) | 1);
        psxMu32ref(0x00b0) = SWAPu32((0x3b << 26) | 2);
        psxMu32ref(0x00c0) = SWAPu32((0x3b << 26) | 3);
@@ -3068,6 +3085,22 @@ void psxBiosInit() {
        psxHu32ref(0x1060) = SWAPu32(0x00000b88);
 
        hleSoftCall = FALSE;
+       
+       /*      Some games like R-Types, CTR, Fade to Black read from adress 0x00000000 due to uninitialized pointers.
+               See Garbage Area at Address 00000000h in Nocash PSX Specfications for more information.
+               Here are some examples of games not working with this fix in place :
+               R-type won't get past the Irem logo if not implemented.
+               Crash Team Racing will softlock after the Sony logo.
+       */
+       
+       psxMu32ref(0x0000) = SWAPu32(0x00000003);
+       /*
+       But overwritten by 00000003h after soon.
+       psxMu32ref(0x0000) = SWAPu32(0x00001A3C);
+       */
+       psxMu32ref(0x0004) = SWAPu32(0x800C5A27);
+       psxMu32ref(0x0008) = SWAPu32(0x08000403);
+       psxMu32ref(0x000C) = SWAPu32(0x00000000);
 }
 
 void psxBiosShutdown() {
@@ -3190,6 +3223,7 @@ void psxBiosException() {
 
        switch (psxRegs.CP0.n.Cause & 0x3c) {
                case 0x00: // Interrupt
+                       interrupt_r26=psxRegs.CP0.n.EPC;
 #ifdef PSXCPU_LOG
 //                     PSXCPU_LOG("interrupt\n");
 #endif
@@ -3303,4 +3337,5 @@ void psxBiosFreeze(int Mode) {
        bfreezes(FDesc);
        bfreezel(&card_active_chan);
        bfreezel(&pad_stopped);
+       bfreezel(&heap_size);
 }