|
|
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.