HLE: Merge HLE BIOS improvements from upstream
authorretro-wertz <retro-wertz@users.noreply.github.com>
Mon, 29 Jul 2019 06:10:54 +0000 (14:10 +0800)
committerretro-wertz <retro-wertz@users.noreply.github.com>
Mon, 29 Jul 2019 06:29:11 +0000 (14:29 +0800)
- Merge update from https://github.com/libretro/pcsx_rearmed

1  2 
libpcsxcore/psxbios.c

@@@ -1,5 -1,6 +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                                                                                            *
++ *   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 : 
++/* 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.
   */
@@@ -211,7 -217,7 +218,7 @@@ typedef struct 
        u32 func;
  } TCB;
  
--typedef struct {                   
++typedef struct {
        u32 _pc0;
        u32 gp0;
        u32 t_addr;
@@@ -495,7 -689,13 +690,13 @@@ void psxBios_strlen() { // 0x1
  
  void psxBios_index() { // 0x1c
        char *p = (char *)Ra0;
 -      
+       if (a0 == 0)
+       {
+               v0 = 0;
+               pc0 = ra;
+               return;
+       }
 +
        do {
                if (*p == a1) {
                        v0 = a0 + (p - (char *)Ra0);
@@@ -678,7 -924,13 +925,13 @@@ void psxBios_memcmp() { // 0x2
  
  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);
@@@ -1131,7 -1423,7 +1424,7 @@@ void psxBios_GPU_dw() { // 0x4
        } while(--size);
  
        pc0 = ra;
--}  
++}
  
  void psxBios_mem2vram() { // 0x47
        int size;
@@@ -1171,8 -1463,8 +1464,8 @@@ void psxBios_GPU_cwb() { // 0x4
  
        pc0 = ra;
  }
--   
--void psxBios_GPU_SendPackets() { //4b:        
++
++void psxBios_GPU_SendPackets() { //4b:
        GPU_writeStatus(0x04000002);
        psxHwWrite32(0x1f8010f4,0);
        psxHwWrite32(0x1f8010f0,psxHwRead32(0x1f8010f0)|0x800);
@@@ -1207,7 -1499,7 +1500,7 @@@ void psxBios_LoadExec() { // 5
  #endif
        s_addr = a1; s_size = a2;
  
--      a1 = 0xf000;    
++      a1 = 0xf000;
        psxBios_Load();
  
        header->S_addr = s_addr;
@@@ -1262,7 -1554,7 +1555,7 @@@ void psxBios_SetMem() { // 9
                        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;
@@@ -1275,17 -1574,16 +1575,16 @@@ void psxBios__card_info() { // a
  #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
                ret = 0x11;
                break;
        }
 -      
 -      DeliverEvent(0x11, 0x2); // 0xf4000001, 0x0004
 +
 +      if (McdDisable[0] && McdDisable[1])
 +              ret = 0x8;
 +
- //    DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004
++      DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004
 +//    DeliverEvent(0x81, 0x2); // 0xf4000001, 0x0004
        DeliverEvent(0x81, ret); // 0xf4000001, 0x0004
        v0 = 1; pc0 = ra;
  }
  
@@@ -1465,11 -1758,24 +1763,24 @@@ void psxBios_WaitEvent() { // 0
  #ifdef PSXBIOS_LOG
        PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x0a], ev, spec);
  #endif
 -              pc0 = ra;       
+       if (Event[ev][spec].status == EvStUNUSED)
+       {
+               v0 = 0;
++              pc0 = ra;
+               return;
+       }
  
-       Event[ev][spec].status = EvStACTIVE;
 -      if (Event[ev][spec].status == EvStALREADY) 
++      if (Event[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;
+               v0 = 1;
+               pc0 = ra;
+               return;
+       }
  
-       v0 = 1; pc0 = ra;
+       v0 = 0;
+       pc0 = ra;
  }
  
  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 (Event[ev][spec].status == EvStALREADY) 
++      if (Event[ev][spec].status == EvStALREADY)
+       {
+               if (!(Event[ev][spec].mode == EvMdINTR)) Event[ev][spec].status = EvStACTIVE;
+               v0 = 1;
 -      } 
 -      else 
++      }
++      else
+       {
+               v0 = 0;
+       }
  
  #ifdef PSXBIOS_LOG
        PSXBIOS_LOG("psxBios_%s %x,%x: %x\n", biosB0n[0x0b], ev, spec, v0);
@@@ -1691,43 -2018,70 +2023,70 @@@ void psxBios_UnDeliverEvent() { // 0x2
        pc0 = ra;
  }
  
- #define buopen(mcd) { \
-       strcpy(FDesc[1 + mcd].name, Ra0+5); \
-       FDesc[1 + mcd].offset = 0; \
-       FDesc[1 + mcd].mode   = a1; \
-  \
-       for (i=1; i<16; i++) { \
-               ptr = Mcd##mcd##Data + 128 * i; \
-               if ((*ptr & 0xF0) != 0x50) continue; \
-               if (strcmp(FDesc[1 + mcd].name, ptr+0xa)) continue; \
-               FDesc[1 + mcd].mcfile = i; \
-               SysPrintf("open %s\n", ptr+0xa); \
-               v0 = 1 + mcd; \
-               break; \
-       } \
-       if (a1 & 0x200 && v0 == -1) { /* FCREAT */ \
-               for (i=1; i<16; i++) { \
-                       int j, xor = 0; \
-  \
-                       ptr = Mcd##mcd##Data + 128 * i; \
-                       if ((*ptr & 0xF0) == 0x50) continue; \
-                       ptr[0] = 0x50 | (u8)(a1 >> 16); \
-                       ptr[4] = 0x00; \
-                       ptr[5] = 0x20; \
-                       ptr[6] = 0x00; \
-                       ptr[7] = 0x00; \
-                       ptr[8] = 'B'; \
-                       ptr[9] = 'I'; \
-                       strcpy(ptr+0xa, FDesc[1 + mcd].name); \
-                       for (j=0; j<127; j++) xor^= ptr[j]; \
-                       ptr[127] = xor; \
-                       FDesc[1 + mcd].mcfile = i; \
-                       SysPrintf("openC %s\n", ptr); \
-                       v0 = 1 + mcd; \
-                       SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, 128 * i, 128); \
-                       break; \
-               } \
-       } \
+ char ffile[64], *pfile;
+ int nfile;
+ static void buopen(int mcd, u8 *ptr, u8 *cfg)
+ {
+       int i;
+       u8 *fptr = 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;
+               if ((*fptr & 0xF0) != 0x50) continue;
+               if (strcmp(FDesc[1 + mcd].name, fptr+0xa)) continue;
+               FDesc[1 + mcd].mcfile = i;
+               SysPrintf("open %s\n", fptr+0xa);
+               v0 = 1 + mcd;
+               break;
+       }
+       if (a1 & 0x200 && v0 == -1) { /* FCREAT */
+               fptr = ptr;
+               for (i=1; i<16; i++) {
+                       int j, xor, nblk = a1 >> 16;
+                       u8 *pptr, *fptr2;
+                       fptr += 128;
+                       if ((*fptr & 0xF0) != 0xa0) continue;
+                       FDesc[1 + mcd].mcfile = i;
+                       fptr[0] = 0x51;
+                       fptr[4] = 0x00;
+                       fptr[5] = 0x20 * nblk;
+                       fptr[6] = 0x00;
+                       fptr[7] = 0x00;
+                       strcpy(fptr+0xa, FDesc[1 + mcd].name);
+                       pptr = fptr2 = fptr;
+                       for(j=2; j<=nblk; j++) {
+                               int k;
+                               for(i++; i<16; i++) {
+                                       fptr2 += 128;
 -                                      
++
+                                       memset(fptr2, 0, 128);
+                                       fptr2[0] = j < nblk ? 0x52 : 0x53;
+                                       pptr[8] = i - 1;
+                                       pptr[9] = 0;
+                                       for (k=0, xor=0; k<127; k++) xor^= pptr[k];
+                                       pptr[127] = xor;
+                                       pptr = fptr2;
+                                       break;
+                               }
+                               /* shouldn't this return ENOSPC if i == 16? */
+                       }
+                       pptr[8] = pptr[9] = 0xff;
+                       for (j=0, xor=0; j<127; j++) xor^= pptr[j];
+                       pptr[127] = xor;
+                       SysPrintf("openC %s %d\n", ptr, nblk);
+                       v0 = 1 + mcd;
+                       /* just go ahead and resave them all */
+                       SaveMcd(cfg, ptr, 128, 128 * 15);
+                       break;
+               }
+               /* shouldn't this return ENOSPC if i == 16? */
+       }
  }
  
  /*
@@@ -1811,25 -2155,12 +2160,12 @@@ void psxBios_read() { // 0x3
  
        if (pa1) {
                switch (a0) {
-                       case 2: buread(pa1, 1); break;
-                       case 3: buread(pa1, 2); break;
+                       case 2: buread(pa1, 1, a2); break;
+                       case 3: buread(pa1, 2, a2); break;
                }
        }
--              
-       pc0 = ra;
- }
 +
- #define buwrite(Ra1, mcd) { \
-       u32 offset =  + 8192 * FDesc[1 + mcd].mcfile + FDesc[1 + mcd].offset; \
-       SysPrintf("write %d: %x,%x\n", FDesc[1 + mcd].mcfile, FDesc[1 + mcd].offset, a2); \
-       ptr = Mcd##mcd##Data + offset; \
-       memcpy(ptr, Ra1, a2); \
-       FDesc[1 + mcd].offset += a2; \
-       SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, offset, a2); \
-       if (FDesc[1 + mcd].mode & 0x8000) v0 = 0; \
-       else v0 = a2; \
-       DeliverEvent(0x11, 0x2); /* 0xf0000011, 0x0004 */ \
-       DeliverEvent(0x81, 0x2); /* 0xf4000001, 0x0004 */ \
+       pc0 = ra;
  }
  
  /*
@@@ -1891,10 -2222,18 +2227,18 @@@ void psxBios_puts() { // 3e/3
        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) 
++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; \
   \
  /*
   *    struct DIRENTRY* firstfile(char *name,struct DIRENTRY *dir);
   */
-- 
++
  void psxBios_firstfile() { // 42
        struct DIRENTRY *dir = (struct DIRENTRY *)Ra1;
        void *pa0 = Ra0;
@@@ -2162,6 -2521,13 +2526,13 @@@ void psxBios__new_card() { // 0x5
        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;
  
@@@ -2233,7 -2599,7 +2604,7 @@@ void psxBios__card_chan() { // 0x5
  void psxBios_ChangeClearPad() { // 5b
  #ifdef PSXBIOS_LOG
        PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x5b], a0);
--#endif        
++#endif
  
        pc0 = ra;
  }
@@@ -2292,11 -2667,11 +2672,11 @@@ void psxBios_ChangeClearRCnt() { // 0
        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])();
@@@ -2307,7 -2682,7 +2687,7 @@@ void (*biosC0[256])()
  
  void psxBiosInit() {
        u32 base, size;
--      u32 *ptr; 
++      u32 *ptr;
        int i;
        uLongf len;
  
        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;
        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;
        //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;
        //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;
  */
        // 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. 
++      /* 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);
        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() {
@@@ -2873,7 -3272,10 +3277,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;