psxbios: use noninvasive print for -psxout
[pcsx_rearmed.git] / libpcsxcore / psxbios.c
index c362a75..f57f512 100644 (file)
@@ -1,5 +1,6 @@
 /***************************************************************************
- *   Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team              *
+ *   Copyright (C) 2019 Ryan Schultz, PCSX-df Team, PCSX team, gameblabla, *
+ *      dmitrysmagin, senquack                                                                                            *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   it under the terms of the GNU General Public License as published by  *
  *   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *
  ***************************************************************************/
 
+/* Gameblabla 2018-2019 :
+ * Numerous changes to bios calls as well as improvements in order to conform to nocash's findings
+ * for the PSX bios calls. Thanks senquack for helping out with some of the changes
+ * and helping to spot issues and refine my patches.
+ * */
+
 /*
  * Internal simulated HLE BIOS.
  */
 #include "psxbios.h"
 #include "psxhw.h"
 #include "gpu.h"
+#include "sio.h"
 #include <zlib.h>
 
+#if (defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)
+#pragma GCC diagnostic ignored "-Wpointer-sign"
+#endif
+
 #undef SysPrintf
 #define SysPrintf if (Config.PsxOut) printf
 
@@ -210,7 +222,7 @@ typedef struct {
        u32 func;
 } TCB;
 
-typedef struct {                   
+typedef struct {
        u32 _pc0;
        u32 gp0;
        u32 t_addr;
@@ -245,23 +257,25 @@ static u32 *jmp_int = NULL;
 static int *pad_buf = NULL;
 static char *pad_buf1 = NULL, *pad_buf2 = NULL;
 static int pad_buf1len, pad_buf2len;
+static int pad_stopped = 0;
 
 static u32 regs[35];
-static EvCB *Event;
+static EvCB *EventCB;
 static EvCB *HwEV; // 0xf0
 static EvCB *EvEV; // 0xf1
 static EvCB *RcEV; // 0xf2
 static EvCB *UeEV; // 0xf3
 static EvCB *SwEV; // 0xf4
 static EvCB *ThEV; // 0xff
+static u32 heap_size = 0;
 static u32 *heap_addr = NULL;
 static u32 *heap_end = NULL;
 static u32 SysIntRP[8];
 static int CardState = -1;
-static TCB Thread[8];
+static TCB ThreadCB[8];
 static int CurThread = 0;
 static FileDesc FDesc[32];
-static u32 card_active_chan;
+static u32 card_active_chan = 0;
 
 boolean hleSoftCall = FALSE;
 
@@ -290,14 +304,16 @@ static inline void softCall2(u32 pc) {
 }
 
 static inline void DeliverEvent(u32 ev, u32 spec) {
-       if (Event[ev][spec].status != EvStACTIVE) return;
+       if (EventCB[ev][spec].status != EvStACTIVE) return;
 
-//     Event[ev][spec].status = EvStALREADY;
-       if (Event[ev][spec].mode == EvMdINTR) {
-               softCall2(Event[ev][spec].fhandler);
-       } else Event[ev][spec].status = EvStALREADY;
+//     EventCB[ev][spec].status = EvStALREADY;
+       if (EventCB[ev][spec].mode == EvMdINTR) {
+               softCall2(EventCB[ev][spec].fhandler);
+       } else EventCB[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;
@@ -321,9 +337,10 @@ static inline void LoadRegs() {
        SysPrintf("read %d: %x,%x (%s)\n", FDesc[1 + mcd].mcfile, FDesc[1 + mcd].offset, a2, Mcd##mcd##Data + 128 * FDesc[1 + mcd].mcfile + 0xa); \
        ptr = Mcd##mcd##Data + 8192 * FDesc[1 + mcd].mcfile + FDesc[1 + mcd].offset; \
        memcpy(Ra1, ptr, length); \
+       if (FDesc[1 + mcd].mode & 0x8000) { \
        DeliverEvent(0x11, 0x2); /* 0xf0000011, 0x0004 */ \
        DeliverEvent(0x81, 0x2); /* 0xf4000001, 0x0004 */ \
-       if (FDesc[1 + mcd].mode & 0x8000) v0 = 0; \
+       v0 = 0; } \
        else v0 = length; \
        FDesc[1 + mcd].offset += v0; \
 }
@@ -333,10 +350,12 @@ static inline void LoadRegs() {
        SysPrintf("write %d: %x,%x\n", FDesc[1 + mcd].mcfile, FDesc[1 + mcd].offset, a2); \
        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 */ \
-       FDesc[1 + mcd].offset += length; \
-       if (FDesc[1 + mcd].mode & 0x8000) v0 = 0; \
+       v0 = 0; } \
        else v0 = length; \
 }
 
@@ -354,7 +373,7 @@ void psxBios_getc(void) // 0x03, 0x35
 #endif
        v0 = -1;
 
-       if (pa1) {
+       if (pa1 != INVALID_PTR) {
                switch (a0) {
                        case 2: buread(pa1, 1, 1); break;
                        case 3: buread(pa1, 2, 1); break;
@@ -373,7 +392,7 @@ void psxBios_putc(void) // 0x09, 0x3B
        PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x09]);
 #endif
        v0 = -1;
-       if (!pa1) {
+       if (pa1 == INVALID_PTR) {
                pc0 = ra;
                return;
        }
@@ -540,13 +559,35 @@ void psxBios_strncat() { // 0x16
 
 void psxBios_strcmp() { // 0x17
        char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
-
+       s32 n=0;
+       if (a0 == 0 && a1 == 0)
+       {
+               v0 = 0;
+               pc0 = ra;
+               return;
+       }
+       else if (a0 == 0 && a1 != 0)
+       {
+               v0 = -1;
+               pc0 = ra;
+               return;
+       }
+       else if (a0 != 0 && a1 == 0)
+       {
+               v0 = 1;
+               pc0 = ra;
+               return;
+       }
 #ifdef PSXBIOS_LOG
        PSXBIOS_LOG("psxBios_%s: %s (%x), %s (%x)\n", biosA0n[0x17], Ra0, a0, Ra1, a1);
 #endif
 
        while (*p1 == *p2++) {
+               n++;
                if (*p1++ == '\0') {
+                       v1=n-1;
+                       a0+=n;
+                       a1+=n;
                        v0 = 0;
                        pc0 = ra;
                        return;
@@ -554,13 +595,33 @@ void psxBios_strcmp() { // 0x17
        }
 
        v0 = (*p1 - *--p2);
+       v1 = n;
+       a0+=n;
+       a1+=n;
        pc0 = ra;
 }
 
 void psxBios_strncmp() { // 0x18
        char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
        s32 n = a2;
-
+       if (a0 == 0 && a1 == 0)
+       {
+               v0 = 0;
+               pc0 = ra;
+               return;
+       }
+       else if (a0 == 0 && a1 != 0)
+       {
+               v0 = -1;
+               pc0 = ra;
+               return;
+       }
+       else if (a0 != 0 && a1 == 0)
+       {
+               v0 = 1;
+               pc0 = ra;
+               return;
+       }
 #ifdef PSXBIOS_LOG
        PSXBIOS_LOG("psxBios_%s: %s (%x), %s (%x), %d\n", biosA0n[0x18], Ra0, a0, Ra1, a1, a2);
 #endif
@@ -569,16 +630,30 @@ void psxBios_strncmp() { // 0x18
                if (*p1++ == '\0') {
                        v0 = 0;
                        pc0 = ra;
+                       v1 = a2 - ((a2-n) - 1);
+                       a0 += (a2-n) - 1;
+                       a1 += (a2-n) - 1;
+                       a2 = n;
                        return;
                }
        }
 
        v0 = (n < 0 ? 0 : *p1 - *--p2);
        pc0 = ra;
+       v1 = a2 - ((a2-n) - 1);
+       a0 += (a2-n) - 1;
+       a1 += (a2-n) - 1;
+       a2 = n;
 }
 
 void psxBios_strcpy() { // 0x19
        char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
+       if (a0 == 0 || a1 == 0)
+       {
+               v0 = 0;
+               pc0 = ra;
+               return;
+       }
        while ((*p1++ = *p2++) != '\0');
 
        v0 = a0; pc0 = ra;
@@ -587,7 +662,12 @@ void psxBios_strcpy() { // 0x19
 void psxBios_strncpy() { // 0x1a
        char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
        s32 n = a2, i;
-
+       if (a0 == 0 || a1 == 0)
+       {
+               v0 = 0;
+               pc0 = ra;
+               return;
+       }
        for (i = 0; i < n; i++) {
                if ((*p1++ = *p2++) == '\0') {
                        while (++i < n) {
@@ -604,6 +684,11 @@ void psxBios_strncpy() { // 0x1a
 void psxBios_strlen() { // 0x1b
        char *p = (char *)Ra0;
        v0 = 0;
+       if (a0 == 0)
+       {
+               pc0 = ra;
+               return;
+       }
        while (*p++) v0++;
        pc0 = ra;
 }
@@ -616,7 +701,7 @@ void psxBios_index() { // 0x1c
                pc0 = ra;
                return;
        }
-       
+
        do {
                if (*p == a1) {
                        v0 = a0 + (p - (char *)Ra0);
@@ -788,22 +873,46 @@ void psxBios_bcmp() { // 0x29
 
 void psxBios_memcpy() { // 0x2a
        char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
-       while ((s32)a2-- > 0) *p1++ = *p2++;
-
-       v0 = a0; pc0 = ra;
+       v0 = a0;
+       if (a0 == 0 || a2 > 0x7FFFFFFF)
+       {
+               pc0 = ra;
+               return;
+       }
+       while ((s32)a2-- > 0) {
+               *p1++ = *p2++;
+       }
+       a2 = 0;
+       pc0 = ra;
 }
 
 void psxBios_memset() { // 0x2b
        char *p = (char *)Ra0;
+       v0 = a0;
+       if (a2 > 0x7FFFFFFF || a2 == 0)
+       {
+               v0 = 0;
+               pc0 = ra;
+               return;
+       }
+       if (a0 == 0)
+       {
+               pc0 = ra;
+               return;
+       }
        while ((s32)a2-- > 0) *p++ = (char)a1;
-
        a2 = 0;
        v0 = a0; pc0 = ra;
 }
 
 void psxBios_memmove() { // 0x2c
        char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
-
+       v0 = a0;
+       if (a0 == 0 || a2 > 0x7FFFFFFF)
+       {
+               pc0 = ra;
+               return;
+       }
        if (p2 <= p1 && p2 + a2 > p1) {
                a2++; // BUG: copy one more byte here
                p1 += a2;
@@ -812,8 +921,7 @@ void psxBios_memmove() { // 0x2c
        } else {
                while ((s32)a2-- > 0) *p1++ = *p2++;
        }
-
-       v0 = a0; pc0 = ra;
+       pc0 = ra;
 }
 
 void psxBios_memcmp() { // 0x2d
@@ -823,6 +931,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;
                v0 = a0 + (p - (char *)Ra0 - 1);
@@ -952,12 +1066,17 @@ void psxBios_qsort() { // 0x31
 }
 
 void psxBios_malloc() { // 0x33
-       unsigned int *chunk, *newchunk = NULL;
+       u32 *chunk, *newchunk = NULL;
        unsigned int dsize = 0, csize, cstat;
        int colflag;
 #ifdef PSXBIOS_LOG
        PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x33]);
 #endif
+       if (!a0 || (!heap_size || !heap_addr)) {
+               v0 = 0;
+               pc0 = ra;
+               return;
+       }
 
        // scan through heap and combine free chunks of space
        chunk = heap_addr;
@@ -967,6 +1086,15 @@ void psxBios_malloc() { // 0x33
                csize = ((u32)*chunk) & 0xfffffffc;
                cstat = ((u32)*chunk) & 1;
 
+               // most probably broken heap descriptor
+               // this fixes Burning Road
+               if (*chunk == 0) {
+                       newchunk = chunk;
+                       dsize = ((uptr)heap_end - (uptr)chunk) - 4;
+                       colflag = 1;
+                       break;
+               }
+
                // it's a free chunk
                if(cstat == 1) {
                        if(colflag == 0) {
@@ -998,28 +1126,36 @@ void psxBios_malloc() { // 0x33
 
        // exit on uninitialized heap
        if (chunk == NULL) {
-               SysPrintf("malloc %x,%x: Uninitialized Heap!\n", v0, a0);
+               printf("malloc %x,%x: Uninitialized Heap!\n", v0, a0);
                v0 = 0;
                pc0 = ra;
                return;
        }
 
        // search an unused chunk that is big enough until the end of the heap
-       while ((dsize > csize || cstat == 0) && chunk < heap_end ) {
+       while ((dsize > csize || cstat==0) && chunk < heap_end ) {
                chunk = (u32*)((uptr)chunk + csize + 4);
+
+                       // catch out of memory
+                       if(chunk >= heap_end) {
+                               printf("malloc %x,%x: Out of memory error!\n",
+                                       v0, a0);
+                               v0 = 0; pc0 = ra;
+                               return;
+                       }
+
                csize = ((u32)*chunk) & 0xfffffffc;
                cstat = ((u32)*chunk) & 1;
        }
 
-       // catch out of memory
-       if(chunk >= heap_end) { SysPrintf("malloc %x,%x: Out of memory error!\n", v0, a0); v0 = 0; pc0 = ra; return; }
-       
        // allocate memory
        if(dsize == csize) {
                // chunk has same size
                *chunk &= 0xfffffffc;
-       }
-       else {
+       } else if (dsize > csize) {
+               v0 = 0; pc0 = ra;
+               return;
+       } else {
                // split free chunk
                *chunk = SWAP32(dsize);
                newchunk = (u32*)((uptr)chunk + dsize + 4);
@@ -1027,9 +1163,9 @@ void psxBios_malloc() { // 0x33
        }
 
        // return pointer to allocated memory
-       v0 = ((unsigned long)chunk - (unsigned long)psxM) + 4;
+       v0 = ((uptr)chunk - (uptr)psxM) + 4;
        v0|= 0x80000000;
-       SysPrintf ("malloc %x,%x\n", v0, a0);
+       //printf ("malloc %x,%x\n", v0, a0);
        pc0 = ra;
 }
 
@@ -1041,7 +1177,8 @@ void psxBios_free() { // 0x34
 
        SysPrintf("free %x: %x bytes\n", a0, *(u32*)(Ra0-4));
 
-       *(u32*)(Ra0-4) |= 1;    // set chunk to free
+       if (a0)
+               *(u32*)(Ra0-4) |= 1;    // set chunk to free
        pc0 = ra;
 }
 
@@ -1101,8 +1238,10 @@ void psxBios_InitHeap() { // 0x39
        size &= 0xfffffffc;
 
        heap_addr = (u32 *)Ra0;
-       heap_end = (u32 *)((u8 *)heap_addr + size);
-       *heap_addr = SWAP32(size | 1);
+       heap_size = size;
+       heap_end = (u32 *)((u8 *)heap_addr + heap_size);
+       /* HACKFIX: Commenting out this line fixes GTA2 crash */
+       //*heap_addr = SWAP32(size | 1);
 
        SysPrintf("InitHeap %x,%x : %x %x\n",a0,a1, (int)((uptr)heap_addr-(uptr)psxM), size);
 
@@ -1113,7 +1252,7 @@ void psxBios_getchar() { //0x3b
        v0 = getchar(); pc0 = ra;
 }
 
-void psxBios_printf() { // 0x3f
+static void psxBios_printf_psxout() { // 0x3f
        char tmp[1024];
        char tmp2[1024];
        u32 save[4];
@@ -1122,7 +1261,7 @@ void psxBios_printf() { // 0x3f
        void *psp;
 
        psp = PSXM(sp);
-       if (psp) {
+       if (psp != INVALID_PTR) {
                memcpy(save, psp, 4 * 4);
                psxMu32ref(sp) = SWAP32((u32)a0);
                psxMu32ref(sp + 4) = SWAP32((u32)a1);
@@ -1178,11 +1317,14 @@ _start:
        }
        *ptmp = 0;
 
-       if (psp)
+       if (psp != INVALID_PTR)
                memcpy(psp, save, 4 * 4);
 
        SysPrintf("%s", tmp);
+}
 
+void psxBios_printf() { // 0x3f
+       psxBios_printf_psxout();
        pc0 = ra;
 }
 
@@ -1267,43 +1409,44 @@ void psxBios_FlushCache() { // 44
 #ifdef PSXBIOS_LOG
        PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x44]);
 #endif
-
+       psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_ISOLATED, NULL);
+       psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_UNISOLATED, NULL);
        pc0 = ra;
 }
 
 void psxBios_GPU_dw() { // 0x46
        int size;
-       s32 *ptr;
+       u32 *ptr;
 
 #ifdef PSXBIOS_LOG
        PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x46]);
 #endif
 
        GPU_writeData(0xa0000000);
-       GPU_writeData((a1<<16)|(a0&0xffff));
-       GPU_writeData((a3<<16)|(a2&0xffff));
-       size = (a2*a3+1)/2;
-       ptr = (s32*)PSXM(Rsp[4]);  //that is correct?
-       do {
-               GPU_writeData(SWAP32(*ptr));
-               ptr++;
-       } while(--size);
+       GPU_writeData((a1<<0x10)|(a0&0xffff));
+       GPU_writeData((a3<<0x10)|(a2&0xffff));
+       size = (a2*a3)/2;
+       ptr = (u32*)PSXM(Rsp[4]);  //that is correct?
+       while(size--)
+       {
+               GPU_writeData(SWAPu32(*ptr++));
+       } 
 
        pc0 = ra;
-}  
+}
 
 void psxBios_mem2vram() { // 0x47
        int size;
-
+       gpuSyncPluginSR();
        GPU_writeData(0xa0000000);
-       GPU_writeData((a1<<16)|(a0&0xffff));
-       GPU_writeData((a3<<16)|(a2&0xffff));
-       size = (a2*a3+1)/2;
+       GPU_writeData((a1<<0x10)|(a0&0xffff));
+       GPU_writeData((a3<<0x10)|(a2&0xffff));
+       size = ((((a2 * a3) / 2) >> 4) << 16);
        GPU_writeStatus(0x04000002);
        psxHwWrite32(0x1f8010f4,0);
        psxHwWrite32(0x1f8010f0,psxHwRead32(0x1f8010f0)|0x800);
        psxHwWrite32(0x1f8010a0,Rsp[4]);//might have a buggy...
-       psxHwWrite32(0x1f8010a4,((size/16)<<16)|16);
+       psxHwWrite32(0x1f8010a4, size | 0x10);
        psxHwWrite32(0x1f8010a8,0x01000201);
 
        pc0 = ra;
@@ -1316,22 +1459,26 @@ void psxBios_SendGPU() { // 0x48
 }
 
 void psxBios_GPU_cw() { // 0x49
+       gpuSyncPluginSR();
        GPU_writeData(a0);
+       v0 = HW_GPU_STATUS;
        pc0 = ra;
 }
 
 void psxBios_GPU_cwb() { // 0x4a
-       s32 *ptr = (s32*)Ra0;
+       u32 *ptr = (u32*)Ra0;
        int size = a1;
-       while(size--) {
-               GPU_writeData(SWAP32(*ptr));
-               ptr++;
+       gpuSyncPluginSR();
+       while(size--)
+       {
+               GPU_writeData(SWAPu32(*ptr++));
        }
 
        pc0 = ra;
 }
    
 void psxBios_GPU_SendPackets() { //4b: 
+       gpuSyncPluginSR();
        GPU_writeStatus(0x04000002);
        psxHwWrite32(0x1f8010f4,0);
        psxHwWrite32(0x1f8010f0,psxHwRead32(0x1f8010f0)|0x800);
@@ -1366,7 +1513,7 @@ void psxBios_LoadExec() { // 51
 #endif
        s_addr = a1; s_size = a2;
 
-       a1 = 0xf000;    
+       a1 = 0xf000;
        psxBios_Load();
 
        header->S_addr = s_addr;
@@ -1421,7 +1568,7 @@ void psxBios_SetMem() { // 9f
                        psxHu32ref(0x1060) = SWAP32(new | 0x300);
                        psxMu32ref(0x060) = a0;
                        SysPrintf("Change effective memory : %d MBytes\n",a0);
-       
+
                default:
                        SysPrintf("Effective memory must be 2/8 MBytes\n");
                break;
@@ -1430,20 +1577,27 @@ 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);
 #endif
-       u32 ret;
+       u32 ret, port;
        card_active_chan = a0;
-
-       switch (card_active_chan) 
-       {
-       case 0x00: case 0x01: case 0x02: case 0x03:
-               ret = Config.Mcd1[0] ? 0x2 : 0x8;
-               break;
-       case 0x10: case 0x11: case 0x12: case 0x13:
-               ret = Config.Mcd2[0] ? 0x2 : 0x8;
+       port = card_active_chan >> 4;
+
+       switch (port) {
+       case 0x0:
+       case 0x1:
+               ret = 0x2;
+               if (McdDisable[port & 1])
+                       ret = 0x8;
                break;
        default:
 #ifdef PSXBIOS_LOG
@@ -1452,12 +1606,13 @@ void psxBios__card_info() { // ab
                ret = 0x11;
                break;
        }
-       
-//     DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004
-//     DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004
-       DeliverEvent(0x81, 0x2); // 0xf4000001, 0x0004
-       DeliverEvent(0x81, ret); // 0xf4000001, 0x0004
 
+       if (McdDisable[0] && McdDisable[1])
+               ret = 0x8;
+
+       DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004
+//     DeliverEvent(0x81, 0x2); // 0xf4000001, 0x0004
+       DeliverEvent(0x81, ret); // 0xf4000001, 0x0004
        v0 = 1; pc0 = ra;
 }
 
@@ -1545,14 +1700,14 @@ void psxBios_ResetRCnt() { // 06
 }
 
 
-/* gets ev for use with Event */
+/* gets ev for use with EventCB */
 #define GetEv() \
        ev = (a0 >> 24) & 0xf; \
        if (ev == 0xf) ev = 0x5; \
        ev*= 32; \
        ev+= a0&0x1f;
 
-/* gets spec for use with Event */
+/* gets spec for use with EventCB */
 #define GetSpec() \
        spec = 0; \
        switch (a1) { \
@@ -1590,9 +1745,9 @@ void psxBios_OpenEvent() { // 08
        PSXBIOS_LOG("psxBios_%s %x,%x (class:%x, spec:%x, mode:%x, func:%x)\n", biosB0n[0x08], ev, spec, a0, a1, a2, a3);
 #endif
 
-       Event[ev][spec].status = EvStWAIT;
-       Event[ev][spec].mode = a2;
-       Event[ev][spec].fhandler = a3;
+       EventCB[ev][spec].status = EvStWAIT;
+       EventCB[ev][spec].mode = a2;
+       EventCB[ev][spec].fhandler = a3;
 
        v0 = ev | (spec << 8);
        pc0 = ra;
@@ -1608,7 +1763,7 @@ void psxBios_CloseEvent() { // 09
        PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x09], ev, spec);
 #endif
 
-       Event[ev][spec].status = EvStUNUSED;
+       EventCB[ev][spec].status = EvStUNUSED;
 
        v0 = 1; pc0 = ra;
 }
@@ -1621,17 +1776,17 @@ void psxBios_WaitEvent() { // 0a
 #ifdef PSXBIOS_LOG
        PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x0a], ev, spec);
 #endif
-       if (Event[ev][spec].status == EvStUNUSED)
+       if (EventCB[ev][spec].status == EvStUNUSED)
        {
                v0 = 0;
-               pc0 = ra;       
+               pc0 = ra;
                return;
        }
 
-       if (Event[ev][spec].status == EvStALREADY) 
+       if (EventCB[ev][spec].status == EvStALREADY)
        {
                /* Callback events (mode=EvMdINTR) do never set the ready flag (and thus WaitEvent would hang forever). */
-               if (!(Event[ev][spec].mode == EvMdINTR)) Event[ev][spec].status = EvStACTIVE;
+               if (!(EventCB[ev][spec].mode == EvMdINTR)) EventCB[ev][spec].status = EvStACTIVE;
                v0 = 1;
                pc0 = ra;
                return;
@@ -1647,9 +1802,15 @@ void psxBios_TestEvent() { // 0b
        ev   = a0 & 0xff;
        spec = (a0 >> 8) & 0xff;
 
-       if (Event[ev][spec].status == EvStALREADY) {
-               Event[ev][spec].status = EvStACTIVE; v0 = 1;
-       } else v0 = 0;
+       if (EventCB[ev][spec].status == EvStALREADY)
+       {
+               if (!(EventCB[ev][spec].mode == EvMdINTR)) EventCB[ev][spec].status = EvStACTIVE;
+               v0 = 1;
+       }
+       else
+       {
+               v0 = 0;
+       }
 
 #ifdef PSXBIOS_LOG
        PSXBIOS_LOG("psxBios_%s %x,%x: %x\n", biosB0n[0x0b], ev, spec, v0);
@@ -1668,7 +1829,7 @@ void psxBios_EnableEvent() { // 0c
        PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x0c], ev, spec);
 #endif
 
-       Event[ev][spec].status = EvStACTIVE;
+       EventCB[ev][spec].status = EvStACTIVE;
 
        v0 = 1; pc0 = ra;
 }
@@ -1683,7 +1844,7 @@ void psxBios_DisableEvent() { // 0d
        PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x0d], ev, spec);
 #endif
 
-       Event[ev][spec].status = EvStWAIT;
+       EventCB[ev][spec].status = EvStWAIT;
 
        v0 = 1; pc0 = ra;
 }
@@ -1697,7 +1858,7 @@ void psxBios_OpenTh() { // 0e
 
        for (th=1; th<8; th++)
        {
-               if (Thread[th].status == 0) break;
+               if (ThreadCB[th].status == 0) break;
 
        }
        if (th == 8) {
@@ -1714,10 +1875,10 @@ void psxBios_OpenTh() { // 0e
        PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x0e], th);
 #endif
 
-       Thread[th].status = 1;
-       Thread[th].func    = a0;
-       Thread[th].reg[29] = a1;
-       Thread[th].reg[28] = a2;
+       ThreadCB[th].status = 1;
+       ThreadCB[th].func    = a0;
+       ThreadCB[th].reg[29] = a1;
+       ThreadCB[th].reg[28] = a2;
 
        v0 = th; pc0 = ra;
 }
@@ -1732,12 +1893,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 {
-               Thread[th].status = 0;
-               v0 = 1;
+       /* The return value is always 1 (even if the handle was already closed). */
+       v0 = 1;
+       if (ThreadCB[th].status != 0) {
+               ThreadCB[th].status = 0;
        }
 
        pc0 = ra;
@@ -1753,23 +1912,20 @@ void psxBios_ChangeTh() { // 10
 #ifdef PSXBIOS_LOG
 //     PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x10], th);
 #endif
-
-       if (Thread[th].status == 0 || CurThread == th) {
-               v0 = 0;
-
+       /* The return value is always 1. */
+       v0 = 1;
+       if (ThreadCB[th].status == 0 || CurThread == th) {
                pc0 = ra;
        } else {
-               v0 = 1;
-
-               if (Thread[CurThread].status == 2) {
-                       Thread[CurThread].status = 1;
-                       Thread[CurThread].func = ra;
-                       memcpy(Thread[CurThread].reg, psxRegs.GPR.r, 32*4);
+               if (ThreadCB[CurThread].status == 2) {
+                       ThreadCB[CurThread].status = 1;
+                       ThreadCB[CurThread].func = ra;
+                       memcpy(ThreadCB[CurThread].reg, psxRegs.GPR.r, 32*4);
                }
 
-               memcpy(psxRegs.GPR.r, Thread[th].reg, 32*4);
-               pc0 = Thread[th].func;
-               Thread[th].status = 2;
+               memcpy(psxRegs.GPR.r, ThreadCB[th].reg, 32*4);
+               pc0 = ThreadCB[th].func;
+               ThreadCB[th].status = 2;
                CurThread = th;
        }
 }
@@ -1791,7 +1947,7 @@ void psxBios_StartPAD() { // 13
 #ifdef PSXBIOS_LOG
        PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x13]);
 #endif
-
+       pad_stopped = 0;
        psxHwWrite16(0x1f801074, (unsigned short)(psxHwRead16(0x1f801074) | 0x1));
        psxRegs.CP0.n.Status |= 0x401;
        pc0 = ra;
@@ -1801,10 +1957,9 @@ void psxBios_StopPAD() { // 14
 #ifdef PSXBIOS_LOG
        PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x14]);
 #endif
-       if (pad_buf == 0){
+       pad_stopped = 1;
        pad_buf1 = NULL;
        pad_buf2 = NULL;
-       }
        pc0 = ra;
 }
 
@@ -1838,6 +1993,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) |
@@ -1873,26 +2029,27 @@ void psxBios_UnDeliverEvent() { // 0x20
        PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x20], ev, spec);
 #endif
 
-       if (Event[ev][spec].status == EvStALREADY &&
-               Event[ev][spec].mode == EvMdNOINTR)
-               Event[ev][spec].status = EvStACTIVE;
+       if (EventCB[ev][spec].status == EvStALREADY &&
+               EventCB[ev][spec].mode == EvMdNOINTR)
+               EventCB[ev][spec].status = EvStACTIVE;
 
        pc0 = ra;
 }
 
 char ffile[64], *pfile;
 int nfile;
-static void buopen(int mcd, u8 *ptr, u8 *cfg)
+
+static void buopen(int mcd, char *ptr, char *cfg)
 {
        int i;
-       u8 *fptr = ptr;
+       char *mcd_data = ptr;
 
        strcpy(FDesc[1 + mcd].name, Ra0+5);
        FDesc[1 + mcd].offset = 0;
        FDesc[1 + mcd].mode   = a1;
 
        for (i=1; i<16; i++) {
-               fptr += 128;
+               const char *fptr = mcd_data + 128 * i;
                if ((*fptr & 0xF0) != 0x50) continue;
                if (strcmp(FDesc[1 + mcd].name, fptr+0xa)) continue;
                FDesc[1 + mcd].mcfile = i;
@@ -1901,12 +2058,11 @@ static void buopen(int mcd, u8 *ptr, u8 *cfg)
                break;
        }
        if (a1 & 0x200 && v0 == -1) { /* FCREAT */
-               fptr = ptr;
                for (i=1; i<16; i++) {
                        int j, xor, nblk = a1 >> 16;
-                       u8 *pptr, *fptr2;
+                       char *pptr, *fptr2;
+                       char *fptr = mcd_data + 128 * i;
 
-                       fptr += 128;
                        if ((*fptr & 0xF0) != 0xa0) continue;
 
                        FDesc[1 + mcd].mcfile = i;
@@ -1921,7 +2077,7 @@ static void buopen(int mcd, u8 *ptr, u8 *cfg)
                                int k;
                                for(i++; i<16; i++) {
                                        fptr2 += 128;
-                                       
+
                                        memset(fptr2, 0, 128);
                                        fptr2[0] = j < nblk ? 0x52 : 0x53;
                                        pptr[8] = i - 1;
@@ -1951,8 +2107,6 @@ static void buopen(int mcd, u8 *ptr, u8 *cfg)
  */
 
 void psxBios_open() { // 0x32
-       int i;
-       char *ptr;
        void *pa0 = Ra0;
 
 #ifdef PSXBIOS_LOG
@@ -1961,7 +2115,7 @@ void psxBios_open() { // 0x32
 
        v0 = -1;
 
-       if (pa0) {
+       if (pa0 != INVALID_PTR) {
                if (!strncmp(pa0, "bu00", 4)) {
                        buopen(1, Mcd1Data, Config.Mcd1);
                }
@@ -2015,13 +2169,13 @@ void psxBios_read() { // 0x34
 
        v0 = -1;
 
-       if (pa1) {
+       if (pa1 != INVALID_PTR) {
                switch (a0) {
                        case 2: buread(pa1, 1, a2); break;
                        case 3: buread(pa1, 2, a2); break;
                }
        }
-               
+
        pc0 = ra;
 }
 
@@ -2038,7 +2192,7 @@ void psxBios_write() { // 0x35/0x03
 #endif
 
        v0 = -1;
-       if (!pa1) {
+       if (pa1 == INVALID_PTR) {
                pc0 = ra;
                return;
        }
@@ -2061,6 +2215,25 @@ void psxBios_write() { // 0x35/0x03
        pc0 = ra;
 }
 
+static void psxBios_write_psxout() {
+       if (a0 == 1) { // stdout
+               const char *ptr = Ra1;
+               int len = a2;
+
+               if (ptr != INVALID_PTR)
+                       while (len-- > 0)
+                               SysPrintf("%c", *ptr++);
+       }
+}
+
+static void psxBios_putchar_psxout() { // 3d
+       SysPrintf("%c", (char)a0);
+}
+
+static void psxBios_puts_psxout() { // 3e/3f
+       SysPrintf("%s", Ra0);
+}
+
 /*
  *     int close(int fd);
  */
@@ -2084,10 +2257,18 @@ void psxBios_puts() { // 3e/3f
        pc0 = ra;
 }
 
-char ffile[64], *pfile;
-int nfile;
+
+/* To avoid any issues with different behaviour when using the libc's own strlen instead.
+ * We want to mimic the PSX's behaviour in this case for bufile. */
+static size_t strlen_internal(char* p)
+{
+       size_t size_of_array = 0;
+       while (*p++) size_of_array++;
+       return size_of_array;
+}
 
 #define bufile(mcd) { \
+       size_t size_of_name = strlen_internal(dir->name); \
        while (nfile < 16) { \
                int match=1; \
  \
@@ -2098,8 +2279,8 @@ int nfile;
                if (!ptr[0xa]) continue; \
                ptr+= 0xa; \
                if (pfile[0] == 0) { \
-                       strncpy(dir->name, ptr, sizeof(dir->name)); \
-                       dir->name[sizeof(dir->name) - 1] = '\0'; \
+                       strncpy(dir->name, ptr, sizeof(dir->name) - 1); \
+                       if (size_of_name < sizeof(dir->name)) dir->name[size_of_name] = '\0'; \
                } else for (i=0; i<20; i++) { \
                        if (pfile[i] == ptr[i]) { \
                                                                dir->name[i] = ptr[i]; continue; } \
@@ -2120,7 +2301,7 @@ int nfile;
 /*
  *     struct DIRENTRY* firstfile(char *name,struct DIRENTRY *dir);
  */
+
 void psxBios_firstfile() { // 42
        struct DIRENTRY *dir = (struct DIRENTRY *)Ra1;
        void *pa0 = Ra0;
@@ -2134,10 +2315,10 @@ void psxBios_firstfile() { // 42
 
        v0 = 0;
 
-       if (pa0) {
+       if (pa0 != INVALID_PTR) {
                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);
@@ -2212,7 +2393,7 @@ void psxBios_rename() { // 44
 
        v0 = 0;
 
-       if (pa0 && pa1) {
+       if (pa0 != INVALID_PTR && pa1 != INVALID_PTR) {
                if (!strncmp(pa0, "bu00", 4) && !strncmp(pa1, "bu00", 4)) {
                        burename(1);
                }
@@ -2254,7 +2435,7 @@ void psxBios_delete() { // 45
 
        v0 = 0;
 
-       if (pa0) {
+       if (pa0 != INVALID_PTR) {
                if (!strncmp(pa0, "bu00", 4)) {
                        budelete(1);
                }
@@ -2304,8 +2485,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;
@@ -2314,7 +2498,7 @@ void psxBios__card_write() { // 0x4e
        card_active_chan = a0;
        port = a0 >> 4;
 
-       if (pa2) {
+       if (pa2 != INVALID_PTR) {
                if (port == 0) {
                        memcpy(Mcd1Data + a1 * 128, pa2, 128);
                        SaveMcd(Config.Mcd1, Mcd1Data, a1 * 128, 128);
@@ -2337,8 +2521,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;
@@ -2347,7 +2534,7 @@ void psxBios__card_read() { // 0x4f
        card_active_chan = a0;
        port = a0 >> 4;
 
-       if (pa2) {
+       if (pa2 != INVALID_PTR) {
                if (port == 0) {
                        memcpy(pa2, Mcd1Data + a1 * 128, 128);
                } else {
@@ -2369,6 +2556,13 @@ void psxBios__new_card() { // 0x50
        pc0 = ra;
 }
 
+/* According to a user, this allows Final Fantasy Tactics to save/load properly */
+void psxBios__get_error(void) // 55
+{
+       v0 = 0;
+       pc0 = ra;
+}
+
 void psxBios_Krom2RawAdd() { // 0x51
        int i = 0;
 
@@ -2440,8 +2634,26 @@ void psxBios__card_chan() { // 0x58
 void psxBios_ChangeClearPad() { // 5b
 #ifdef PSXBIOS_LOG
        PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x5b], a0);
-#endif 
+#endif
+
+       pc0 = ra;
+}
+
+void psxBios__card_status() { // 5c
+#ifdef PSXBIOS_LOG
+       PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x5c], a0);
+#endif
+
+       v0 = card_active_chan;
+       pc0 = ra;
+}
+
+void psxBios__card_wait() { // 5d
+#ifdef PSXBIOS_LOG
+       PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x5d], a0);
+#endif
 
+       v0 = 1;
        pc0 = ra;
 }
 
@@ -2490,11 +2702,11 @@ void psxBios_ChangeClearRCnt() { // 0a
        pc0 = ra;
 }
 
-void psxBios_dummy() { 
+void psxBios_dummy() {
 #ifdef PSXBIOS_LOG
        PSXBIOS_LOG("unk %x call: %x\n", pc0 & 0x1fffff, t1);
 #endif
-       pc0 = ra; 
+       pc0 = ra;
 }
 
 void (*biosA0[256])();
@@ -2505,7 +2717,7 @@ void (*biosC0[256])();
 
 void psxBiosInit() {
        u32 base, size;
-       u32 *ptr; 
+       u32 *ptr;
        int i;
        uLongf len;
 
@@ -2514,11 +2726,10 @@ void psxBiosInit() {
                biosB0[i] = NULL;
                biosC0[i] = NULL;
        }
-       biosA0[0x3e] = psxBios_puts;
-       biosA0[0x3f] = psxBios_printf;
-
-       biosB0[0x3d] = psxBios_putchar;
-       biosB0[0x3f] = psxBios_puts;
+       biosA0[0x03] = biosB0[0x35] = psxBios_write_psxout;
+       biosA0[0x3c] = biosB0[0x3d] = psxBios_putchar_psxout;
+       biosA0[0x3e] = biosB0[0x3f] = psxBios_puts_psxout;
+       biosA0[0x3f] = psxBios_printf_psxout;
 
        if (!Config.HLE) return;
 
@@ -2588,7 +2799,7 @@ void psxBiosInit() {
        biosA0[0x39] = psxBios_InitHeap;
        //biosA0[0x3a] = psxBios__exit;
        biosA0[0x3b] = psxBios_getchar;
-       biosA0[0x3c] = psxBios_putchar; 
+       biosA0[0x3c] = psxBios_putchar;
        //biosA0[0x3d] = psxBios_gets;
        //biosA0[0x40] = psxBios_sys_a0_40;
        //biosA0[0x41] = psxBios_LoadTest;
@@ -2604,7 +2815,7 @@ void psxBiosInit() {
        biosA0[0x4b] = psxBios_GPU_SendPackets;
        biosA0[0x4c] = psxBios_sys_a0_4c;
        biosA0[0x4d] = psxBios_GPU_GetGPUStatus;
-       //biosA0[0x4e] = psxBios_GPU_sync;      
+       //biosA0[0x4e] = psxBios_GPU_sync;
        //biosA0[0x4f] = psxBios_sys_a0_4f;
        //biosA0[0x50] = psxBios_sys_a0_50;
        biosA0[0x51] = psxBios_LoadExec;
@@ -2656,10 +2867,10 @@ void psxBiosInit() {
        //biosA0[0x7f] = psxBios_sys_a0_7f;
        //biosA0[0x80] = psxBios_sys_a0_80;
        //biosA0[0x81] = psxBios_sys_a0_81;
-       //biosA0[0x82] = psxBios_sys_a0_82;             
+       //biosA0[0x82] = psxBios_sys_a0_82;
        //biosA0[0x83] = psxBios_sys_a0_83;
        //biosA0[0x84] = psxBios_sys_a0_84;
-       //biosA0[0x85] = psxBios__96_CdStop;    
+       //biosA0[0x85] = psxBios__96_CdStop;
        //biosA0[0x86] = psxBios_sys_a0_86;
        //biosA0[0x87] = psxBios_sys_a0_87;
        //biosA0[0x88] = psxBios_sys_a0_88;
@@ -2692,7 +2903,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;
@@ -2791,15 +3002,15 @@ void psxBiosInit() {
        //biosB0[0x52] = psxBios_sys_b0_52;
        //biosB0[0x53] = psxBios_sys_b0_53;
        //biosB0[0x54] = psxBios__get_errno;
-       //biosB0[0x55] = psxBios__get_error;
+       biosB0[0x55] = psxBios__get_error;
        biosB0[0x56] = psxBios_GetC0Table;
        biosB0[0x57] = psxBios_GetB0Table;
        biosB0[0x58] = psxBios__card_chan;
        //biosB0[0x59] = psxBios_sys_b0_59;
        //biosB0[0x5a] = psxBios_sys_b0_5a;
        biosB0[0x5b] = psxBios_ChangeClearPad;
-       //biosB0[0x5c] = psxBios__card_status;
-       //biosB0[0x5d] = psxBios__card_wait;
+       biosB0[0x5c] = psxBios__card_status;
+       biosB0[0x5d] = psxBios__card_wait;
 //*******************C0 CALLS****************************
        //biosC0[0x00] = psxBios_InitRCnt;
        //biosC0[0x01] = psxBios_InitException;
@@ -2811,7 +3022,7 @@ void psxBiosInit() {
        //biosC0[0x07] = psxBios_InstallExeptionHandler;
        //biosC0[0x08] = psxBios_SysInitMemory;
        //biosC0[0x09] = psxBios_SysInitKMem;
-       biosC0[0x0a] = psxBios_ChangeClearRCnt; 
+       biosC0[0x0a] = psxBios_ChangeClearRCnt;
        //biosC0[0x0b] = psxBios_SystemError;
        //biosC0[0x0c] = psxBios_InitDefInt;
        //biosC0[0x0d] = psxBios_sys_c0_0d;
@@ -2834,14 +3045,14 @@ void psxBiosInit() {
 /**/
        base = 0x1000;
        size = sizeof(EvCB) * 32;
-       Event = (void *)&psxR[base]; base += size * 6;
-       memset(Event, 0, size * 6);
-       HwEV = Event;
-       EvEV = Event + 32;
-       RcEV = Event + 32 * 2;
-       UeEV = Event + 32 * 3;
-       SwEV = Event + 32 * 4;
-       ThEV = Event + 32 * 5;
+       EventCB = (void *)&psxR[base]; base += size * 6;
+       memset(EventCB, 0, size * 6);
+       HwEV = EventCB;
+       EvEV = EventCB + 32;
+       RcEV = EventCB + 32 * 2;
+       UeEV = EventCB + 32 * 3;
+       SwEV = EventCB + 32 * 4;
+       ThEV = EventCB + 32 * 5;
 
        ptr = (u32 *)&psxM[0x0874]; // b0 table
        ptr[0] = SWAPu32(0x4c54 - 0x884);
@@ -2850,9 +3061,10 @@ void psxBiosInit() {
        ptr[6] = SWAPu32(0xc80);
 
        memset(SysIntRP, 0, sizeof(SysIntRP));
-       memset(Thread, 0, sizeof(Thread));
-       Thread[0].status = 2; // main thread
+       memset(ThreadCB, 0, sizeof(ThreadCB));
+       ThreadCB[0].status = 2; // main thread
 
+       pad_stopped = 1;
        jmp_int = NULL;
        pad_buf = NULL;
        pad_buf1 = NULL;
@@ -2860,9 +3072,11 @@ void psxBiosInit() {
        pad_buf1len = pad_buf2len = 0;
        heap_addr = NULL;
        heap_end = NULL;
+       heap_size = 0;
        CardState = -1;
        CurThread = 0;
        memset(FDesc, 0, sizeof(FDesc));
+       card_active_chan = 0;
 
        psxMu32ref(0x0150) = SWAPu32(0x160);
        psxMu32ref(0x0154) = SWAPu32(0x320);
@@ -2876,7 +3090,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);
@@ -2902,6 +3118,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() {
@@ -2987,12 +3219,14 @@ void biosInterrupt() {
                        if (NET_recvPadData(pad_buf2, 2) == -1)
                                netError();
                } else {
-                       if (pad_buf1) {
-                               psxBios_PADpoll(1);
-                       }
+                       if (!pad_stopped)  {
+                               if (pad_buf1) {
+                                       psxBios_PADpoll(1);
+                               }
 
-                       if (pad_buf2) {
-                               psxBios_PADpoll(2);
+                               if (pad_buf2) {
+                                       psxBios_PADpoll(2);
+                               }
                        }
                }
 
@@ -3022,6 +3256,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
@@ -3071,7 +3306,10 @@ void psxBiosException() {
                                        break;
 
                                case 2: // ExitCritical - enable irq's
-                                       psxRegs.CP0.n.Status |= 0x404; 
+                                       psxRegs.CP0.n.Status |= 0x404;
+                                       break;
+                               /* Normally this should cover SYS(00h, SYS(04h but they don't do anything relevant so... */
+                               default:
                                        break;
                        }
                        pc0 = psxRegs.CP0.n.EPC + 4;
@@ -3127,8 +3365,10 @@ void psxBiosFreeze(int Mode) {
        bfreezes(regs);
        bfreezes(SysIntRP);
        bfreezel(&CardState);
-       bfreezes(Thread);
+       bfreezes(ThreadCB);
        bfreezel(&CurThread);
        bfreezes(FDesc);
        bfreezel(&card_active_chan);
+       bfreezel(&pad_stopped);
+       bfreezel(&heap_size);
 }