psxbios: assorted changes
[pcsx_rearmed.git] / libpcsxcore / psxbios.c
index 678377e..734f3e3 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,7 @@ 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_CD_EVENTS     0xb9b8
 #define A_EXC_GP        0xf450
 
@@ -344,6 +345,11 @@ static void mips_return(u32 val)
        pc0 = ra;
 }
 
+static void mips_return_void(void)
+{
+       pc0 = ra;
+}
+
 static void use_cycles(u32 cycle)
 {
        psxRegs.cycle += cycle * 2;
@@ -388,6 +394,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)
@@ -414,6 +424,7 @@ static void CloseEvent(u32 ev);
        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); \
        ptr = Mcd##mcd##Data + 8192 * FDesc[1 + mcd].mcfile + FDesc[1 + mcd].offset; \
        memcpy(Ra1, ptr, length); \
+       psxCpu->Clear(a1, (length + 3) / 4); \
        if (FDesc[1 + mcd].mode & 0x8000) { \
        DeliverEvent(0xf0000011, 0x0004); \
        DeliverEvent(0xf4000001, 0x0004); \
@@ -904,33 +915,69 @@ void psxBios_tolower() { // 0x26
        pc0 = ra;
 }
 
-void psxBios_bcopy() { // 0x27
-       char *p1 = (char *)Ra1, *p2 = (char *)Ra0;
-       v0 = a0;
-       if (a0 == 0 || a2 > 0x7FFFFFFF)
+static void do_memset(u32 dst, u32 v, s32 len)
+{
+       u32 d = dst;
+       s32 l = len;
+       while (l-- > 0) {
+               u8 *db = PSXM(d);
+               if (db != INVALID_PTR)
+                       *db = v;
+               d++;
+       }
+       psxCpu->Clear(dst, (len + 3) / 4);
+}
+
+static void do_memcpy(u32 dst, u32 src, s32 len)
+{
+       u32 d = dst, s = src;
+       s32 l = len;
+       while (l-- > 0) {
+               const u8 *sb = PSXM(s);
+               u8 *db = PSXM(d);
+               if (db != INVALID_PTR && sb != INVALID_PTR)
+                       *db = *sb;
+               d++;
+               s++;
+       }
+       psxCpu->Clear(dst, (len + 3) / 4);
+}
+
+static void psxBios_memcpy();
+
+static void psxBios_bcopy() { // 0x27 - memcpy with args swapped
+       //PSXBIOS_LOG("psxBios_%s %x %x %x\n", biosA0n[0x27], a0, a1, a2);
+       u32 ret = a0, cycles = 0;
+       if (a0 == 0) // ...but it checks src this time
        {
-               pc0 = ra;
+               mips_return_c(0, 4);
                return;
        }
-       while ((s32)a2-- > 0) *p1++ = *p2++;
-       a2 = 0;
-       pc0 = ra;
+       v1 = a0;
+       if ((s32)a2 > 0) {
+               do_memcpy(a1, a0, a2);
+               cycles = a2 * 6;
+               a0 += a2;
+               a1 += a2;
+               a2 = 0;
+       }
+       mips_return_c(ret, cycles + 5);
 }
 
 static void psxBios_bzero() { // 0x28
        /* Same as memset here (See memset below) */
-       u32 ret = a0;
+       u32 ret = a0, cycles;
        if (a0 == 0 || (s32)a1 <= 0)
        {
                mips_return_c(0, 6);
                return;
        }
-       while ((s32)a1-- > 0) {
-               storeRam8(a0++, 0);
-               use_cycles(4);
-       }
+       do_memset(a0, 0, a1);
+       cycles = a1 * 4;
+       a0 += a1;
+       a1 = 0;
        // todo: many more cycles due to uncached bios mem
-       mips_return_c(ret, 5);
+       mips_return_c(ret, cycles + 5);
 }
 
 void psxBios_bcmp() { // 0x29
@@ -949,53 +996,70 @@ void psxBios_bcmp() { // 0x29
        v0 = 0; pc0 = ra;
 }
 
-void psxBios_memcpy() { // 0x2a
-       char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
-       v0 = a0;
-       if (a0 == 0 || a2 > 0x7FFFFFFF)
+static void psxBios_memcpy() { // 0x2a
+       u32 ret = a0, cycles = 0;
+       if (a0 == 0)
        {
-               pc0 = ra;
+               mips_return_c(0, 4);
                return;
        }
-       while ((s32)a2-- > 0) {
-               *p1++ = *p2++;
+       v1 = a0;
+       if ((s32)a2 > 0) {
+               do_memcpy(a0, a1, a2);
+               cycles = a2 * 6;
+               a0 += a2;
+               a1 += a2;
+               a2 = 0;
        }
-       a2 = 0;
-       pc0 = ra;
+       mips_return_c(ret, cycles + 5);
 }
 
 static void psxBios_memset() { // 0x2b
-       u32 ret = a0;
+       u32 ret = a0, cycles;
        if (a0 == 0 || (s32)a2 <= 0)
        {
                mips_return_c(0, 6);
                return;
        }
-       while ((s32)a2-- > 0) {
-               storeRam8(a0++, a1);
-               use_cycles(4);
-       }
+       do_memset(a0, a1, a2);
+       cycles = a2 * 4;
+       a0 += a2;
+       a2 = 0;
        // todo: many more cycles due to uncached bios mem
-       mips_return_c(ret, 5);
+       mips_return_c(ret, cycles + 5);
 }
 
 void psxBios_memmove() { // 0x2c
-       char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
-       v0 = a0;
-       if (a0 == 0 || a2 > 0x7FFFFFFF)
+       u32 ret = a0, cycles = 0;
+       if (a0 == 0)
        {
-               pc0 = ra;
+               mips_return_c(0, 4);
                return;
        }
-       if (p2 <= p1 && p2 + a2 > p1) {
-               a2++; // BUG: copy one more byte here
-               p1 += a2;
-               p2 += a2;
-               while ((s32)a2-- > 0) *--p1 = *--p2;
-       } else {
-               while ((s32)a2-- > 0) *p1++ = *p2++;
+       v1 = a0;
+       if ((s32)a2 > 0 && a0 > a1 && a0 < a1 + a2) {
+               u32 dst = a0, len = a2 + 1;
+               a0 += a2;
+               a1 += a2;
+               while ((s32)a2 >= 0) { // BUG: copies one more byte here
+                       const u8 *sb = PSXM(a1);
+                       u8 *db = PSXM(a0);
+                       if (db != INVALID_PTR && sb != INVALID_PTR)
+                               *db = *sb;
+                       a0--;
+                       a1--;
+                       a2--;
+               }
+               psxCpu->Clear(dst, (len + 3) / 4);
+               cycles = 10 + len * 8;
+       } else if ((s32)a2 > 0) {
+               do_memcpy(a0, a1, a2);
+               cycles = a2 * 6;
+               a0 += a2;
+               a1 += a2;
+               a2 = 0;
        }
-       pc0 = ra;
+       mips_return_c(ret, cycles + 5);
 }
 
 void psxBios_memcmp() { // 0x2d
@@ -1021,16 +1085,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;
@@ -1416,6 +1480,14 @@ static void psxBios_SystemErrorUnresolvedException() {
        mips_return_void_c(1000);
 }
 
+static void FlushCache() {
+       psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_ISOLATED, NULL);
+       psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_UNISOLATED, NULL);
+       k0 = 0xbfc0193c;
+       // runs from uncached mem so tons of cycles
+       use_cycles(500);
+}
+
 /*
  *     long Load(char *name, struct EXEC *header);
  */
@@ -1425,8 +1497,10 @@ void psxBios_Load() { // 0x42
        void *pa1;
 
        pa1 = Ra1;
-       if (pa1 && LoadCdromFile(Ra0, &eheader) == 0) {
+       if (pa1 != INVALID_PTR && LoadCdromFile(Ra0, &eheader) == 0) {
                memcpy(pa1, ((char*)&eheader)+16, sizeof(EXEC));
+               psxCpu->Clear(a1, sizeof(EXEC) / 4);
+               FlushCache();
                v0 = 1;
        } else v0 = 0;
        PSXBIOS_LOG("psxBios_%s: %s, %d -> %d\n", biosA0n[0x42], Ra0, a1, v0);
@@ -1473,13 +1547,10 @@ void psxBios_Exec() { // 43
        pc0 = SWAP32(header->_pc0);
 }
 
-void psxBios_FlushCache() { // 44
-#ifdef PSXBIOS_LOG
+static void psxBios_FlushCache() { // 44
        PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x44]);
-#endif
-       psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_ISOLATED, NULL);
-       psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_UNISOLATED, NULL);
-       pc0 = ra;
+       FlushCache();
+       mips_return_void();
 }
 
 void psxBios_GPU_dw() { // 0x46
@@ -1505,7 +1576,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));
@@ -1527,8 +1598,8 @@ void psxBios_SendGPU() { // 0x48
 }
 
 void psxBios_GPU_cw() { // 0x49
-       gpuSyncPluginSR();
        GPU_writeData(a0);
+       gpuSyncPluginSR();
        v0 = HW_GPU_STATUS;
        pc0 = ra;
 }
@@ -1816,6 +1887,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)
@@ -2273,9 +2345,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;
 
@@ -2432,7 +2502,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); \
@@ -2465,22 +2537,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
@@ -2492,6 +2559,7 @@ void psxBios_firstfile() { // 42
                        bufile(2);
                }
        }
+       PSXBIOS_LOG("psxBios_%s %s %x -> %x\n", biosB0n[0x42], pa0, a1, v0);
 
        pc0 = ra;
 }
@@ -2506,19 +2574,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;
 }
@@ -2615,11 +2679,12 @@ void psxBios_InitCARD() { // 4a
        u32 *ram32 = (u32 *)psxM;
        PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x4a], a0);
        write_chain(ram32 + A_PADCRD_CHN_E/4, 0, 0x49bc, 0x4a4c);
-       // (maybe) todo: early_card_irq, FlushCache etc
+       // (maybe) todo: early_card_irq, etc
 
        ram32[A_PAD_IRQR_ENA/4] = SWAP32(a0);
 
-       mips_return_c(0, 300);
+       psxBios_FlushCache();
+       mips_return_c(0, 34+13+15+6);
 }
 
 void psxBios_StartCARD() { // 4b
@@ -3031,8 +3096,8 @@ static void write_chain(u32 *d, u32 next, u32 handler1, u32 handler2)
        d[2] = SWAPu32(handler2);
 
        // install the hle traps
-       PSXMu32ref(handler1) = HLEOP(chain_hle_op(handler1));
-       PSXMu32ref(handler2) = HLEOP(chain_hle_op(handler2));
+       if (handler1) PSXMu32ref(handler1) = HLEOP(chain_hle_op(handler1));
+       if (handler2) PSXMu32ref(handler2) = HLEOP(chain_hle_op(handler2));
 }
 
 static void setup_tt(u32 tcb_cnt, u32 evcb_cnt)
@@ -3501,9 +3566,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;
@@ -3520,6 +3582,13 @@ void psxBiosInit() {
        len = 0x80000 - 0x69d68;
        uncompress((Bytef *)(psxR + 0x69d68), &len, font_889f, sizeof(font_889f));
 
+       // trap attempts to call bios directly
+       rom32[0x00000/4] = HLEOP(hleop_dummy);
+       rom32[0x00180/4] = HLEOP(hleop_dummy);
+       rom32[0x3fffc/4] = HLEOP(hleop_dummy);
+       rom32[0x65ffc/4] = HLEOP(hleop_dummy);
+       rom32[0x7ff2c/4] = HLEOP(hleop_dummy);
+
        /*      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 :
@@ -3594,7 +3663,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);
@@ -3603,6 +3671,7 @@ 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() {
@@ -3681,9 +3750,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) {
@@ -3694,9 +3763,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;
 
@@ -3712,7 +3781,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:
@@ -3901,21 +3970,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);
 }