|
|
1.1 ! root 1: /* Generator is (c) James Ponder, 1997-2001 http://www.squish.net/generator/ */ ! 2: ! 3: #include <stdio.h> ! 4: #include <string.h> ! 5: #include <stdlib.h> ! 6: #include <errno.h> ! 7: ! 8: #include "generator.h" ! 9: ! 10: #include "ui.h" ! 11: #include "cpu68k.h" ! 12: #include "patch.h" ! 13: ! 14: /* Merlyn LeRoy's lamp.c comment: */ ! 15: ! 16: /* ! 17: * "Eet ees not *I* who am crazy, eet ees I who am MAD!" - R. Ho"ek ! 18: * ! 19: * lamp.c - a program to control Game Genie for Genesis ! 20: * ! 21: * Translate between Game Genie for Genesis 8-character codes and ! 22: * the 24-bit address & 16-bit value for that address. ! 23: * The format is this: ! 24: * ! 25: * ijklm nopIJ KLMNO PABCD EFGHd efgha bcQRS TUVWX decodes to... ! 26: * ! 27: * ABCDEFGH IJKLMNOP QRSTUVWX: abcdefgh ijklmnop ! 28: * 24-bit address 16-bit data ! 29: * MSB LSB MSB LSB ! 30: * ! 31: * ..where each group of five letters is a Genie code character ! 32: * (ABCDEFGHJKLMNPRSTVWXYZ0123456789, each representing 5 bits 00000-11111), ! 33: * and each 8-character Genie code is the 24-bit address and 16-bit data. ! 34: * ! 35: * For example, SCRA-BJX0 is a game genie code. Each letter is 5 bits from ! 36: * the table ABCDEFGHJKLMNPRSTVWXYZ0123456789, A=00000, B=00001, C=00010... ! 37: * ! 38: * S C R A - B J X 0 ! 39: * 01111 00010 01110 00000 00001 01000 10011 10110 ! 40: * ijklm nopIJ KLMNO PABCD EFGHd efgha bcQRS TUVWX rearrange as... ! 41: * ! 42: * 00000000 10011100 01110110: 01010100 01111000 ! 43: * ABCDEFGH IJKLMNOP QRSTUVWX: abcdefgh ijklmnop ! 44: * 24-bit address 16-bit data ! 45: * MSB LSB MSB LSB ! 46: * ! 47: * Which is 009c76: 5478 ! 48: * ! 49: * See the usage message when run with no arguments... ! 50: * Merlyn LeRoy (Brian Westley), [email protected] 1/4/93 ! 51: */ ! 52: ! 53: static const char *patch_codestring = "ABCDEFGHJKLMNPRSTVWXYZ0123456789"; ! 54: ! 55: /*** externed ***/ ! 56: ! 57: t_patchlist *patch_patchlist; /* patches */ ! 58: ! 59: /*** patch_savefile - save current patches to file ***/ ! 60: ! 61: int patch_savefile(const char *filename) ! 62: { ! 63: FILE *f; ! 64: t_patchlist *ent; ! 65: ! 66: if ((f = fopen(filename, "wb")) == NULL) { ! 67: LOG_CRITICAL(("Failed to open '%s' for writing: %s", ! 68: filename, strerror(errno))); ! 69: return -1; ! 70: } ! 71: for (ent = patch_patchlist; ent; ent = ent->next) ! 72: fprintf(f, "%s %s\r\n", ent->code, ent->action); ! 73: if (fclose(f) == EOF) { ! 74: LOG_CRITICAL(("Failed to close '%s': %s", filename, strerror(errno))); ! 75: return -1; ! 76: } ! 77: return 0; ! 78: } ! 79: ! 80: /*** patch_loadfile - load the patch file ***/ ! 81: ! 82: int patch_loadfile(const char *filename) ! 83: { ! 84: char linebuf[256]; ! 85: char *p; ! 86: FILE *f; ! 87: t_patchlist *ent, **end; ! 88: ! 89: if ((f = fopen(filename, "rb")) == NULL) { ! 90: LOG_CRITICAL(("Failed to open '%s': %s", filename, strerror(errno))); ! 91: return -1; ! 92: } ! 93: patch_clearlist(); ! 94: end = &patch_patchlist; ! 95: while (fgets(linebuf, sizeof(linebuf), f)) { ! 96: if (linebuf[strlen(linebuf)-1] != '\n') { ! 97: LOG_CRITICAL(("Line too long in '%s': %s", filename, strerror(errno))); ! 98: return -1; ! 99: } ! 100: linebuf[strlen(linebuf)-1] = '\0'; /* remove newline */ ! 101: if (*linebuf && linebuf[strlen(linebuf)-1] == '\r') ! 102: linebuf[strlen(linebuf)-1] = '\0'; /* remove optional cr */ ! 103: if (strlen(linebuf) < 11 && linebuf[6] != ':') { ! 104: LOG_CRITICAL(("Invalid patch file '%s'", filename)); ! 105: return -1; ! 106: } ! 107: if ((ent = malloc(sizeof(t_patchlist))) == NULL) ! 108: ui_err("out of memory"); ! 109: snprintf(ent->code, 12, "%s", linebuf); ! 110: for (p = linebuf + 11; *p == ' '; p++) ; ! 111: if ((ent->action = strdup(p)) == NULL) ! 112: ui_err("out of memory"); ! 113: ent->next = NULL; ! 114: *end = ent; ! 115: end = &ent->next; ! 116: } ! 117: if (!feof(f)) { ! 118: LOG_CRITICAL(("Error whilst reading patch file '%s'", filename)); ! 119: return -1; ! 120: } ! 121: if (fclose(f) == EOF) { ! 122: LOG_CRITICAL(("Failed to close '%s': %s", filename, strerror(errno))); ! 123: return -1; ! 124: } ! 125: return 0; ! 126: } ! 127: ! 128: void patch_clearlist(void) ! 129: { ! 130: t_patchlist *ent; ! 131: ! 132: /* clear out old patch list */ ! 133: while (patch_patchlist) { ! 134: ent = patch_patchlist; ! 135: patch_patchlist = patch_patchlist->next; ! 136: free(ent->action); ! 137: free(ent); ! 138: } ! 139: } ! 140: ! 141: void patch_addcode(const char *code, const char *action) ! 142: { ! 143: t_patchlist *ent, **end; ! 144: ! 145: /* where's the end of the list */ ! 146: for (end = &patch_patchlist; *end; end = &((*end)->next)) ; ! 147: ! 148: /* create and insert */ ! 149: if ((ent = malloc(sizeof(t_patchlist))) == NULL) ! 150: ui_err("out of memory"); ! 151: snprintf(ent->code, sizeof(ent->code), "%s", code); ! 152: ent->action = strdup(action); ! 153: ent->next = NULL; ! 154: *end = ent; ! 155: } ! 156: ! 157: int patch_apply(const char *code, const char *action) ! 158: { ! 159: uint32 addr; ! 160: uint32 data; ! 161: char *end; ! 162: ! 163: (void)action; ! 164: addr = strtol(code, &end, 16); ! 165: if (*end++ != ':') ! 166: return -1; ! 167: data = strtol(end, &end, 16); ! 168: if (*end) ! 169: return -1; ! 170: if (addr & ~0xfffffe || data & ~0xffff) ! 171: return -1; ! 172: if (addr < cpu68k_romlen) { ! 173: printf("applied %X = %X\n", addr, data); ! 174: ((uint16 *)cpu68k_rom)[addr >> 1] = LOCENDIAN16((uint16)data); ! 175: gen_modifiedrom = 1; ! 176: } else if ((addr & 0xe00000) == 0xe00000) { ! 177: printf("applied %X = %X\n", addr, data); ! 178: ((uint16 *)cpu68k_ram)[(addr & 0xfff) >> 1] = LOCENDIAN16((uint16)data); ! 179: } else { ! 180: return -1; ! 181: } ! 182: return 0; ! 183: } ! 184: ! 185: /* given a game genie code, convert to 24-bit address, 16-bit data */ ! 186: ! 187: int patch_genietoraw(const char *code, uint32 *addr, uint16 *data) ! 188: { ! 189: char *p; ! 190: uint32 a, d, v; ! 191: int i; ! 192: ! 193: if (strlen(code) != 9 || code[4] != '-') ! 194: return -1; ! 195: for (i = 0; i < 9; i = (i == 3 ? i+2 : i+1)) { ! 196: if ((p = strchr(patch_codestring, code[i])) == NULL) ! 197: return -1; ! 198: v = p - patch_codestring; ! 199: switch (i) { ! 200: case 0: d|= v << 3; break; ! 201: case 1: d|= v >> 2; a|= (v & 3) << 14; break; ! 202: case 2: a|= v << 9; break; ! 203: case 3: a|= (v >> 4) << 8; a|= (v & 15) << 20; break; ! 204: case 5: a|= (v >> 1) << 16; d|= (v & 1) << 12; break; ! 205: case 6: d|= (v >> 1) << 8; d|= (v & 1) << 15; break; ! 206: case 7: d|= (v >> 3) << 13; a|= (v & 7) << 5; break; ! 207: case 8: a|= v; break; ! 208: default: return -1; ! 209: } ! 210: } ! 211: *addr = a; ! 212: *data = d; ! 213: return 0; ! 214: } ! 215: ! 216: /* given a 24-bit address, 16-bit data, create game genie code */ ! 217: ! 218: int patch_rawtogenie(uint32 addr, uint16 data, char *code) ! 219: { ! 220: uint8 v; ! 221: int i; ! 222: ! 223: if (addr & 0xff000000) ! 224: return -1; ! 225: code[4] = '-'; ! 226: for (i = 0; i < 9; i = (i == 3 ? i+2 : i+1)) { ! 227: switch (i) { ! 228: case 0: v = (data >> 3) & 15; break; ! 229: case 1: v = ((data & 7) << 2) | ((addr >> 14) & 3); break; ! 230: case 2: v = (addr >> 9) & 15; break; ! 231: case 3: v = (addr >> 20) | ((addr >> 4) & 0x10); break; ! 232: case 5: v = ((addr >> 15) & 14) | ((data >> 12) & 1); break; ! 233: case 6: v = ((data >> 8) & 14) | (data >> 15); break; ! 234: case 7: v = ((data >> 10) & 0x18) | ((addr >> 5) & 7); break; ! 235: case 8: v = addr & 15; break; ! 236: } ! 237: code[i] = patch_codestring[v]; ! 238: } ! 239: return 0; ! 240: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.