Add support for Master System cheats.
authoriLag <ilagdoesntcheckthisemail@gmail.com>
Sun, 26 Mar 2017 02:29:00 +0000 (19:29 -0700)
committeriLag <ilagdoesntcheckthisemail@gmail.com>
Sun, 26 Mar 2017 02:29:00 +0000 (19:29 -0700)
pico/memory.c
pico/patch.c
pico/patch.h
platform/libretro/libretro.c

index 4f38e5e..e72628e 100644 (file)
@@ -459,7 +459,7 @@ static void PicoWrite16_sram(u32 a, u32 d)
 \r
 // z80 area (0xa00000 - 0xa0ffff)\r
 // TODO: verify mirrors VDP and bank reg (bank area mirroring verified)\r
-static u32 PicoRead8_z80(u32 a)\r
+u32 PicoRead8_z80(u32 a)\r
 {\r
   u32 d = 0xff;\r
   if ((Pico.m.z80Run & 1) || Pico.m.z80_reset) {\r
@@ -483,7 +483,7 @@ static u32 PicoRead16_z80(u32 a)
   return d | (d << 8);\r
 }\r
 \r
-static void PicoWrite8_z80(u32 a, u32 d)\r
+void PicoWrite8_z80(u32 a, u32 d)\r
 {\r
   if ((Pico.m.z80Run & 1) || Pico.m.z80_reset) {\r
     // verified on real hw\r
index 558658c..f08b370 100644 (file)
@@ -28,12 +28,13 @@ struct patch
 {
        unsigned int addr;
        unsigned short data;
+       unsigned char comp;
 };
 
 struct patch_inst *PicoPatches = NULL;
 int PicoPatchCount = 0;
 
-static char genie_chars[] = "AaBbCcDdEeFfGgHhJjKkLlMmNnPpRrSsTtVvWwXxYyZz0O1I2233445566778899";
+static char genie_chars_md[] = "AaBbCcDdEeFfGgHhJjKkLlMmNnPpRrSsTtVvWwXxYyZz0O1I2233445566778899";
 
 /* genie_decode
  * This function converts a Game Genie code to an address:data pair.
@@ -47,20 +48,23 @@ static char genie_chars[] = "AaBbCcDdEeFfGgHhJjKkLlMmNnPpRrSsTtVvWwXxYyZz0O1I223
  * by result. If an error results, both the address and data will be set to -1.
  */
 
-static void genie_decode(const char* code, struct patch* result)
+static void genie_decode_md(const char* code, struct patch* result)
 {
   int i = 0, n;
   char* x;
 
-  for(; i < 8; ++i)
+  for(; i < 9; ++i)
   {
+    /* Skip i=4; it's going to be the separating hyphen */
+    if (i==4) continue;
+
     /* If strchr returns NULL, we were given a bad character */
-    if(!(x = strchr(genie_chars, code[i])))
+    if(!(x = strchr(genie_chars_md, code[i])))
     {
       result->addr = -1; result->data = -1;
       return;
     }
-    n = (x - genie_chars) >> 1;
+    n = (x - genie_chars_md) >> 1;
     /* Now, based on which character this is, fit it into the result */
     switch(i)
     {
@@ -81,21 +85,21 @@ static void genie_decode(const char* code, struct patch* result)
       /* BCDE ____ ____ ___A ____ ____ : ____ ____ ____ ____ */
       result->addr |= (n & 0xF) << 20 | (n >> 4) << 8;
       break;
-    case 4:
+    case 5:
       /* ____ ABCD ____ ____ ____ ____ : ___E ____ ____ ____ */
       result->data |= (n & 1) << 12;
       result->addr |= (n >> 1) << 16;
       break;
-    case 5:
+    case 6:
       /* ____ ____ ____ ____ ____ ____ : E___ ABCD ____ ____ */
       result->data |= (n & 1) << 15 | (n >> 1) << 8;
       break;
-    case 6:
+    case 7:
       /* ____ ____ ____ ____ CDE_ ____ : _AB_ ____ ____ ____ */
       result->data |= (n >> 3) << 13;
       result->addr |= (n & 7) << 5;
       break;
-    case 7:
+    case 8:
       /* ____ ____ ____ ____ ___A BCDE : ____ ____ ____ ____ */
       result->addr |= n;
       break;
@@ -113,30 +117,165 @@ static void genie_decode(const char* code, struct patch* result)
 
 static char hex_chars[] = "00112233445566778899AaBbCcDdEeFf";
 
-static void hex_decode(const char *code, struct patch *result)
+static void hex_decode_md(const char *code, struct patch *result)
 {
   char *x;
   int i;
   /* 6 digits for address */
   for(i = 0; i < 6; ++i)
+  {
+    if(!(x = strchr(hex_chars, code[i])))
     {
-      if(!(x = strchr(hex_chars, code[i])))
-      {
-       result->addr = result->data = -1;
-       return;
-      }
-      result->addr = (result->addr << 4) | ((x - hex_chars) >> 1);
+      result->addr = result->data = -1;
+      return;
     }
+    result->addr = (result->addr << 4) | ((x - hex_chars) >> 1);
+  }
   /* 4 digits for data */
-  for(i = 6; i < 10; ++i)
+  for(i = 7; i < 11; ++i)
+  {
+    if(!(x = strchr(hex_chars, code[i])))
+    {
+      if (i==8) break;
+      result->addr = result->data = -1;
+      return;
+    }
+    result->data = (result->data << 4) | ((x - hex_chars) >> 1);
+  }
+}
+
+void genie_decode_ms(const char *code, struct patch *result)
+{
+  char *x;
+  int i;
+  /* 2 digits for data */
+  for(i=0;i<2;++i)
+  {
+    if(!(x = strchr(hex_chars, code[i])))
+    {
+      result->addr = result->data = -1;
+      return;
+    }
+    result->data = (result->data << 4) | ((x - hex_chars) >> 1);
+  }
+  /* 4 digits for address */
+  for(i=2;i<7;++i)
+  {
+    /* 4th character is hyphen and can be skipped*/
+    if (i==3) continue;
+    if(!(x = strchr(hex_chars, code[i])))
+    {
+      result->addr = result->data = -1;
+      return;
+    }
+    result->addr = (result->addr << 4) | ((x - hex_chars) >> 1);
+  }
+  /* Correct the address */
+  result->addr = ((result->addr >> 4) | (result->addr << 12 & 0xF000)) ^ 0xF000;
+  /* Optional: 3 digits for comp */
+  if (code[8]){
+    for(i=8;i<11;++i)
     {
+      if (i==9) continue; /* 2nd character is ignored */
       if(!(x = strchr(hex_chars, code[i])))
       {
        result->addr = result->data = -1;
        return;
       }
-      result->data = (result->data << 4) | ((x - hex_chars) >> 1);
+      result->comp = (result->comp << 4) | ((x - hex_chars) >> 1);
+    }
+    /* Correct the comp */
+    result->comp = ((result->comp >> 2) | ((result->comp << 6) & 0xC0)) ^ 0xBA;
+  }
+}
+
+void ar_decode_ms(const char *code, struct patch *result){
+  char *x;
+  int i;
+  /* 2 digits of padding*/
+  /* 4 digits for address */
+  for(i=2;i<7;++i)
+  {
+    /* 5th character is hyphen and can be skipped*/
+    if (i==4) continue;
+    if(!(x = strchr(hex_chars, code[i])))
+    {
+      result->addr = result->data = -1;
+      return;
+    }
+    result->addr = (result->addr << 4) | ((x - hex_chars) >> 1);
+  }
+  /* 2 digits for data */
+  for(i=7;i<9;++i)
+  {
+    if(!(x = strchr(hex_chars, code[i])))
+    {
+      result->addr = result->data = -1;
+      return;
+    }
+    result->data = (result->data << 4) | ((x - hex_chars) >> 1);
+  }
+}
+
+void fusion_ram_decode(const char *code, struct patch *result){
+  char *x;
+  int i;
+  /* 4 digits for address */
+  for(i=0;i<4;++i)
+  {
+    if(!(x = strchr(hex_chars, code[i])))
+    {
+      result->addr = result->data = -1;
+      return;
+    }
+    result->addr = (result->addr << 4) | ((x - hex_chars) >> 1);
+  }
+  /* Skip the ':' */
+  /* 2 digits for data */
+  for(i=5;i<7;++i)
+  {
+    if(!(x = strchr(hex_chars, code[i])))
+    {
+      result->addr = result->data = -1;
+      return;
+    }
+    result->data = (result->data << 4) | ((x - hex_chars) >> 1);
+  }
+}
+
+void fusion_rom_decode(const char *code, struct patch *result){
+  char *x;
+  int i;
+  /* 2 digits for comp */
+  for(i=0;i<2;++i)
+  {
+    if(!(x = strchr(hex_chars, code[i])))
+    {
+      result->addr = result->data = -1;
+      return;
     }
+    result->comp = (result->comp << 4) | ((x - hex_chars) >> 1);
+  }
+  /* 4 digits for address */
+  for(i=2;i<6;++i)
+  {
+    if(!(x = strchr(hex_chars, code[i])))
+    {
+      result->addr = result->data = -1;
+      return;
+    }
+    result->addr = (result->addr << 4) | ((x - hex_chars) >> 1);
+  }
+  /* 2 digits for data */
+  for(i=7;i<9;++i)
+  {
+    if(!(x = strchr(hex_chars, code[i])))
+    {
+      result->addr = result->data = -1;
+      return;
+    }
+    result->data = (result->data << 4) | ((x - hex_chars) >> 1);
+  }
 }
 
 /* THIS is the function you call from the MegaDrive or whatever. This figures
@@ -144,65 +283,72 @@ static void hex_decode(const char *code, struct patch *result)
  * decoder. */
 void decode(const char* code, struct patch* result)
 {
-  int len = strlen(code), i, j;
-  char code_to_pass[16], *x;
-  const char *ad, *da;
-  int adl, dal;
+  int len = strlen(code);
 
   /* Initialize the result */
-  result->addr = result->data = 0;
+  result->addr = result->data = result->comp = 0;
 
-  /* Just assume 8 char long string to be Game Genie code */
-  if (len == 8)
+  if(!(PicoAHW & PAHW_SMS))
   {
-    genie_decode(code, result);
-    return;
-  }
+    //If Genesis
 
-  /* If it's 9 chars long and the 5th is a hyphen, we have a Game Genie
-   * code. */
+    //Game Genie
     if(len == 9 && code[4] == '-')
     {
-      /* Remove the hyphen and pass to genie_decode */
-      code_to_pass[0] = code[0];
-      code_to_pass[1] = code[1];
-      code_to_pass[2] = code[2];
-      code_to_pass[3] = code[3];
-      code_to_pass[4] = code[5];
-      code_to_pass[5] = code[6];
-      code_to_pass[6] = code[7];
-      code_to_pass[7] = code[8];
-      code_to_pass[8] = '\0';
-      genie_decode(code_to_pass, result);
+      genie_decode_md(code, result);
       return;
     }
 
-  /* Otherwise, we assume it's a hex code.
-   * Find the colon so we know where address ends and data starts. If there's
-   * no colon, then we haven't a code at all! */
-  if(!(x = strchr(code, ':'))) goto bad_code;
-  ad = code; da = x + 1; adl = x - code; dal = len - adl - 1;
+    //Master
+    else if(len >=9 && code[6] == ':')
+    {
+      hex_decode_md(code, result);
+    }
+
+    else
+    {
+      goto bad_code;
+    }
+  } else {
+    //If Master System
 
-  /* If a section is empty or too long, toss it */
-  if(adl == 0 || adl > 6 || dal == 0 || dal > 4) goto bad_code;
+    //Genie
+    if(len == 11 && code[3] == '-' && code[7] == '-')
+    {
+      genie_decode_ms(code, result);
+    }
 
-  /* Pad the address with zeros, then fill it with the value */
-  for(i = 0; i < (6 - adl); ++i) code_to_pass[i] = '0';
-  for(j = 0; i < 6; ++i, ++j) code_to_pass[i] = ad[j];
+    //AR
+    else if(len == 9 && code[4] == '-')
+    {
+      ar_decode_ms(code, result);
+    }
 
-  /* Do the same for data */
-  for(i = 6; i < (10 - dal); ++i) code_to_pass[i] = '0';
-  for(j = 0; i < 10; ++i, ++j) code_to_pass[i] = da[j];
+    //Fusion RAM
+    else if(len == 7 && code[4] == ':')
+    {
+      fusion_ram_decode(code, result);
+    }
 
-  code_to_pass[10] = '\0';
+    //Fusion ROM
+    else if(len == 9 && code[6] == ':')
+    {
+      fusion_rom_decode(code, result);
+    }
 
-  /* Decode and goodbye */
-  hex_decode(code_to_pass, result);
-  return;
+    else
+    {
+      goto bad_code;
+    }
 
-bad_code:
+    //Convert RAM address space to Genesis location.
+    if (result->addr>=0xC000)
+      result->addr= 0xFF0000 | (0x1FFF & result->addr);
+  }
 
-  /* AGH! Invalid code! */
+  return;
+
+  bad_code:
   result->data = result->addr = -1;
   return;
 }
@@ -212,7 +358,9 @@ bad_code:
 unsigned int PicoRead16(unsigned int a);
 void PicoWrite16(unsigned int a, unsigned short d);
 extern unsigned short m68k_read16(unsigned int a);
-extern void m68k_write16(int a, unsigned short d);
+extern void m68k_write16(unsigned int a, unsigned short d);
+extern char PicoRead8_z80(unsigned short a);
+extern void PicoWrite8_z80(unsigned short a, char d);
 
 void PicoPatchUnload(void)
 {
@@ -293,54 +441,84 @@ int PicoPatchLoad(const char *fname)
 /* to be called when the Rom is loaded and byteswapped */
 void PicoPatchPrepare(void)
 {
-       int i;
+  int i;
+  int addr;
 
-       for (i = 0; i < PicoPatchCount; i++)
-       {
-               PicoPatches[i].addr &= ~1;
-               if (PicoPatches[i].addr < Pico.romsize)
-                       PicoPatches[i].data_old = *(unsigned short *)(Pico.rom + PicoPatches[i].addr);
-               else
-                       PicoPatches[i].data_old = (unsigned short) m68k_read16(PicoPatches[i].addr);
-               if (strstr(PicoPatches[i].name, "AUTO"))
-                       PicoPatches[i].active = 1;
-       }
+  for (i = 0; i < PicoPatchCount; i++)
+  {
+    addr=PicoPatches[i].addr;
+    addr &= ~1;
+    if (addr < Pico.romsize)
+      PicoPatches[i].data_old = *(unsigned short *)(Pico.rom + addr);
+    else
+    {
+      if(!(PicoAHW & PAHW_SMS))
+       PicoPatches[i].data_old = (unsigned short) m68k_read16(addr);
+      else
+       PicoPatches[i].data_old = (unsigned char) PicoRead8_z80(addr);
+    }
+    if (strstr(PicoPatches[i].name, "AUTO"))
+      PicoPatches[i].active = 1;
+  }
 }
 
 void PicoPatchApply(void)
 {
-       int i, u;
-       unsigned int addr;
+  int i, u;
+  unsigned int addr;
+
+  for (i = 0; i < PicoPatchCount; i++)
+  {
+    addr = PicoPatches[i].addr;
 
-       for (i = 0; i < PicoPatchCount; i++)
+    if (addr < Pico.romsize)
+    {
+      if (PicoPatches[i].active)
+      {
+       if (!(PicoAHW & PAHW_SMS))
+         *(unsigned short *)(Pico.rom + addr) = PicoPatches[i].data;
+       else if (!PicoPatches[i].comp || PicoPatches[i].comp == *(char *)(Pico.rom + addr))
+         *(char *)(Pico.rom + addr) = (char) PicoPatches[i].data;
+      }
+      else
+      {
+       // if current addr is not patched by older patch, write back original val
+       for (u = 0; u < i; u++)
+         if (PicoPatches[u].addr == addr) break;
+       if (u == i)
        {
-               addr = PicoPatches[i].addr;
-               if (addr < Pico.romsize)
-               {
-                       if (PicoPatches[i].active)
-                               *(unsigned short *)(Pico.rom + addr) = PicoPatches[i].data;
-                       else {
-                               // if current addr is not patched by older patch, write back original val
-                               for (u = 0; u < i; u++)
-                                       if (PicoPatches[u].addr == addr) break;
-                               if (u == i)
-                                       *(unsigned short *)(Pico.rom + addr) = PicoPatches[i].data_old;
-                       }
-                       // fprintf(stderr, "patched %i: %06x:%04x\n", PicoPatches[i].active, addr,
-                       //      *(unsigned short *)(Pico.rom + addr));
-               }
-               else
-               {
-                       if (PicoPatches[i].active)
-                               m68k_write16(PicoPatches[i].addr,PicoPatches[i].data);
-                       else {
-                               // if current addr is not patched by older patch, write back original val
-                               for (u = 0; u < i; u++)
-                                       if (PicoPatches[u].addr == addr) break;
-                               if (u == i)
-                                       m68k_write16(PicoPatches[i].addr,PicoPatches[i].data_old);
-                       }
-               }
+         if (!(PicoAHW & PAHW_SMS))
+           *(unsigned short *)(Pico.rom + addr) = PicoPatches[i].data_old;
+         else
+           *(char *)(Pico.rom + addr) = (char) PicoPatches[i].data_old;
+       }
+      }
+      // fprintf(stderr, "patched %i: %06x:%04x\n", PicoPatches[i].active, addr,
+      //       *(unsigned short *)(Pico.rom + addr));
+    }
+    else
+    {
+      if (PicoPatches[i].active)
+      {
+       if (!(PicoAHW & PAHW_SMS))
+         m68k_write16(addr,PicoPatches[i].data);
+       else
+         PicoWrite8_z80(addr,PicoPatches[i].data);
+      }
+      else
+      {
+       // if current addr is not patched by older patch, write back original val
+       for (u = 0; u < i; u++)
+         if (PicoPatches[u].addr == addr) break;
+       if (u == i)
+       {
+         if (!(PicoAHW & PAHW_SMS))
+           m68k_write16(PicoPatches[i].addr,PicoPatches[i].data_old);
+         else
+           PicoWrite8_z80(PicoPatches[i].addr,PicoPatches[i].data_old);
        }
+      }
+    }
+  }
 }
 
index 6e9420f..9ab86d3 100644 (file)
@@ -13,6 +13,7 @@ struct patch_inst
        unsigned int addr;
        unsigned short data;
        unsigned short data_old;
+       unsigned char comp;
 };
 
 extern struct patch_inst *PicoPatches;
index f11b5da..a1cf22c 100644 (file)
@@ -696,6 +696,7 @@ typedef struct patch
 {
        unsigned int addr;
        unsigned short data;
+       unsigned char comp;
 } patch;
 
 extern void decode(char *buff, patch *dest);
@@ -728,16 +729,10 @@ void retro_cheat_set(unsigned index, bool enabled, const char *code)
        int array_len = PicoPatchCount;
        char codeCopy[256];
        char *buff;
-       bool multiline=0;
 
+       if (code=='\0') return;
        strcpy(codeCopy,code);
-       
-       if (strstr(code,"+")){
-               multiline=1;
-               buff = strtok(codeCopy,"+");
-       } else {
-               buff=codeCopy;
-       }
+       buff = strtok(codeCopy,"+");
 
        while (buff != NULL)
        {
@@ -766,14 +761,13 @@ void retro_cheat_set(unsigned index, bool enabled, const char *code)
                PicoPatches[PicoPatchCount].active = enabled;
                PicoPatches[PicoPatchCount].addr = pt.addr;
                PicoPatches[PicoPatchCount].data = pt.data;
+               PicoPatches[PicoPatchCount].comp = pt.comp;
                if (PicoPatches[PicoPatchCount].addr < Pico.romsize)
                        PicoPatches[PicoPatchCount].data_old = *(uint16_t *)(Pico.rom + PicoPatches[PicoPatchCount].addr);
                else
                        PicoPatches[PicoPatchCount].data_old = (uint16_t) m68k_read16(PicoPatches[PicoPatchCount].addr);
                PicoPatchCount++;
 
-               if (!multiline)
-                       break;
                buff = strtok(NULL,"+");
        }
 }