From fa55ee51c9c1d86311fbd90f055a575e4991ac70 Mon Sep 17 00:00:00 2001 From: iLag Date: Sat, 25 Mar 2017 19:29:00 -0700 Subject: [PATCH] Add support for Master System cheats. --- pico/memory.c | 4 +- pico/patch.c | 382 +++++++++++++++++++++++++---------- pico/patch.h | 1 + platform/libretro/libretro.c | 14 +- 4 files changed, 287 insertions(+), 114 deletions(-) diff --git a/pico/memory.c b/pico/memory.c index 4f38e5e..e72628e 100644 --- a/pico/memory.c +++ b/pico/memory.c @@ -459,7 +459,7 @@ static void PicoWrite16_sram(u32 a, u32 d) // z80 area (0xa00000 - 0xa0ffff) // TODO: verify mirrors VDP and bank reg (bank area mirroring verified) -static u32 PicoRead8_z80(u32 a) +u32 PicoRead8_z80(u32 a) { u32 d = 0xff; if ((Pico.m.z80Run & 1) || Pico.m.z80_reset) { @@ -483,7 +483,7 @@ static u32 PicoRead16_z80(u32 a) return d | (d << 8); } -static void PicoWrite8_z80(u32 a, u32 d) +void PicoWrite8_z80(u32 a, u32 d) { if ((Pico.m.z80Run & 1) || Pico.m.z80_reset) { // verified on real hw diff --git a/pico/patch.c b/pico/patch.c index 558658c..f08b370 100644 --- a/pico/patch.c +++ b/pico/patch.c @@ -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); } + } + } + } } diff --git a/pico/patch.h b/pico/patch.h index 6e9420f..9ab86d3 100644 --- a/pico/patch.h +++ b/pico/patch.h @@ -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; diff --git a/platform/libretro/libretro.c b/platform/libretro/libretro.c index f11b5da..a1cf22c 100644 --- a/platform/libretro/libretro.c +++ b/platform/libretro/libretro.c @@ -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,"+"); } } -- 2.39.2