|
|
1.1 root 1: /* Generator is (c) James Ponder, 1997-2001 http://www.squish.net/generator/ */
2:
3: #include <stdlib.h>
4: #include <stdio.h>
5: #include <string.h>
6: #include <sys/stat.h>
7: #include <unistd.h>
8: #include <sys/types.h>
9: #include <fcntl.h>
10: #include <ctype.h>
11: #include <signal.h>
12: #include <errno.h>
13:
14: #include "generator.h"
15: #include "snprintf.h"
16:
17: #include "ui.h"
18: #include "memz80.h"
19: #include "cpu68k.h"
1.1.1.2 root 20: #include "mem68k.h"
1.1 root 21: #include "cpuz80.h"
22: #include "vdp.h"
23: #include "gensound.h"
24:
25: #ifdef ALLEGRO
26: #include "allegro.h"
27: #endif
28:
29: /*** variables externed in generator.h ***/
30:
31: unsigned int gen_quit = 0;
1.1.1.3 root 32: unsigned int gen_debugmode = 0;
33: unsigned int gen_loglevel = 1; /* 2 = NORMAL, 1 = CRITICAL */
34: unsigned int gen_autodetect = 1; /* 0 = no, 1 = yes */
35: unsigned int gen_musiclog = 0; /* 0 = no, 1 = GYM, 2 = GNM */
1.1.1.4 ! root 36: unsigned int gen_modifiedrom = 0; /* 0 = no, 1 = yes */
1.1 root 37: t_cartinfo gen_cartinfo;
38: char gen_leafname[128];
39:
1.1.1.3 root 40: static int gen_freerom = 0;
41:
1.1 root 42: /*** forward references ***/
43:
44: void gen_nicetext(char *out, char *in, unsigned int size);
45: uint16 gen_checksum(uint8 *start, unsigned int length);
1.1.1.3 root 46: void gen_setupcartinfo(void);
1.1 root 47:
48: /*** Signal handler ***/
49:
50: RETSIGTYPE gen_sighandler(int signum)
51: {
52: if (gen_debugmode) {
53: if (signum == SIGINT) {
54: if (gen_quit) {
55: LOG_CRITICAL(("Bye!"));
1.1.1.2 root 56: ui_final();
57: ui_err("Exiting");
1.1 root 58: } else {
1.1.1.2 root 59: LOG_REQUEST(("Ping - current PC = 0x%X", regs.pc));
1.1 root 60: }
61: gen_quit = 1;
62: }
63: } else {
64: ui_final();
65: exit(0);
66: }
67: signal(signum, gen_sighandler);
68: }
69:
70: static char thing[] = ("\n\nIt's the year 2000 is there anyone out there?\n"
1.1.1.2 root 71: "\nIf you're from another planet put your hand in the "
72: "air, say yeah!\n\n");
1.1 root 73:
74: /*** Program entry point ***/
75:
1.1.1.2 root 76: int main(int argc, char *argv[])
77: {
1.1 root 78: int retval;
79: t_sr test;
80:
81: test.sr_int = 0;
82: test.sr_struct.c = 1;
83: if (test.sr_int != 1) {
84: fprintf(stderr, "%s: compilation variable BYTES_HIGHFIRST not set "
1.1.1.2 root 85: "correctly\n", argv[0]);
1.1 root 86: return 1;
87: }
88:
89: /* initialise user interface */
90: if ((retval = ui_init(argc, argv)))
91: return retval;
92:
93: /* initialise 68k memory system */
94: if ((retval = mem68k_init()))
95: ui_err("Failed to initialise mem68k module (%d)", retval);
96:
97: /* initialise z80 memory system */
98: if ((retval = memz80_init()))
99: ui_err("Failed to initialise memz80 module (%d)", retval);
100:
101: /* initialise vdp system */
102: if ((retval = vdp_init()))
103: ui_err("Failed to initialise vdp module (%d)", retval);
104:
105: /* initialise cpu system */
106: if ((retval = cpu68k_init()))
107: ui_err("Failed to initialise cpu68k module (%d)", retval);
108:
109: /* initialise z80 cpu system */
110: if ((retval = cpuz80_init()))
111: ui_err("Failed to initialise cpuz80 module (%d)", retval);
112:
113: /* initialise sound system */
114: if ((retval = sound_init()))
115: ui_err("Failed to initialise sound module (%d)", retval);
116:
117: signal(SIGINT, gen_sighandler);
118:
119: /* enter user interface loop */
120: return ui_loop();
121: }
122:
123: #ifdef ALLEGRO
124: END_OF_MAIN();
125: #endif
126:
127: /*** gen_reset - reset system ***/
128:
1.1.1.2 root 129: void gen_reset(void)
130: {
1.1 root 131: vdp_reset();
132: cpu68k_reset();
133: cpuz80_reset();
134: if (sound_reset()) {
135: ui_err("sound failure");
136: }
137: }
138:
139: /*** gen_softreset - reset system ***/
140:
1.1.1.2 root 141: void gen_softreset(void)
142: {
1.1 root 143: cpu68k_reset();
144: }
145:
146: /*** gen_loadimage - load ROM image ***/
147:
1.1.1.2 root 148: char *gen_loadimage(const char *filename)
149: {
1.1 root 150: int file, imagetype, bytes, bytesleft;
151: struct stat statbuf;
152: const char *extension;
153: uint8 *buffer;
154: unsigned int blocks, x, i;
155: uint8 *new;
156: char *p;
157:
158: /* Remove current file */
159: if (cpu68k_rom) {
1.1.1.3 root 160: if (gen_freerom)
161: free(cpu68k_rom);
1.1 root 162: cpu68k_rom = NULL;
163: }
164:
165: /* Load file */
1.1.1.3 root 166: if (stat(filename, &statbuf) != 0)
1.1.1.2 root 167: return ("Unable to stat file.");
1.1 root 168: cpu68k_romlen = statbuf.st_size;
1.1.1.3 root 169: if (cpu68k_romlen < 0x200)
170: return ("File is too small");
171:
1.1 root 172: /* allocate enough memory plus 16 bytes for disassembler to cope
173: with the last instruction */
1.1.1.2 root 174: if ((cpu68k_rom = malloc(cpu68k_romlen + 16)) == NULL) {
1.1 root 175: cpu68k_romlen = 0;
1.1.1.2 root 176: return ("Out of memory!");
1.1 root 177: }
1.1.1.3 root 178: gen_freerom = 1;
1.1.1.2 root 179: memset(cpu68k_rom, 0, cpu68k_romlen + 16);
1.1 root 180: #ifdef ALLEGRO
1.1.1.2 root 181: if ((file = open(filename, O_RDONLY | O_BINARY, 0)) == -1) {
1.1 root 182: #else
183: if ((file = open(filename, O_RDONLY, 0)) == -1) {
184: #endif
185: perror("open");
186: cpu68k_rom = NULL;
187: cpu68k_romlen = 0;
1.1.1.2 root 188: return ("Unable to open file.");
1.1 root 189: }
190: buffer = cpu68k_rom;
191: bytesleft = cpu68k_romlen;
192: do {
193: if ((bytes = read(file, buffer, bytesleft)) <= 0)
194: break;
1.1.1.2 root 195: buffer += bytes;
196: bytesleft -= bytes;
197: }
198: while (bytesleft >= 0);
1.1 root 199: close(file);
200: if (bytes == -1)
1.1.1.2 root 201: return (strerror(errno));
1.1 root 202: else if (bytes != 0)
1.1.1.2 root 203: return ("invalid return code from read()");
1.1 root 204: if (bytesleft) {
205: LOG_CRITICAL(("%d bytes left to read?!", bytesleft));
1.1.1.2 root 206: return ("Error whilst loading file");
1.1 root 207: }
208:
1.1.1.2 root 209: imagetype = 1; /* BIN file by default */
1.1 root 210:
211: /* SMD file format check - Richard Bannister */
212: if ((cpu68k_rom[8] == 0xAA) && (cpu68k_rom[9] == 0xBB) &&
213: cpu68k_rom[10] == 0x06) {
1.1.1.2 root 214: imagetype = 2; /* SMD file */
1.1 root 215: }
216: /* check for interleaved 'SEGA' */
217: if (cpu68k_rom[0x280] == 'E' && cpu68k_rom[0x281] == 'A' &&
218: cpu68k_rom[0x2280] == 'S' && cpu68k_rom[0x2281] == 'G') {
1.1.1.2 root 219: imagetype = 2; /* SMD file */
1.1 root 220: }
221: /* Check extension is not wrong */
222: extension = filename + strlen(filename) - 3;
223: if (extension > filename) {
224: if (!strcasecmp(extension, "smd") && (imagetype != 2))
225: LOG_REQUEST(("File extension (smd) does not match detected "
1.1.1.2 root 226: "type (bin)"));
1.1 root 227: if (!strcasecmp(extension, "bin") && (imagetype != 1))
228: LOG_REQUEST(("File extension (bin) does not match detected "
1.1.1.2 root 229: "type (smd)"));
1.1 root 230: }
231:
232: /* convert to standard BIN file format */
233:
1.1.1.2 root 234: switch (imagetype) {
235: case 1: /* BIN */
1.1 root 236: break;
1.1.1.2 root 237: case 2: /* SMD */
238: blocks = (cpu68k_romlen - 512) / 16384;
239: if (blocks * 16384 + 512 != cpu68k_romlen)
240: return ("Image is corrupt.");
1.1 root 241:
1.1.1.2 root 242: if ((new = malloc(cpu68k_romlen - 512)) == NULL) {
1.1 root 243: cpu68k_rom = NULL;
244: cpu68k_romlen = 0;
1.1.1.2 root 245: return ("Out of memory!");
1.1 root 246: }
247:
248: for (i = 0; i < blocks; i++) {
249: for (x = 0; x < 8192; x++) {
1.1.1.2 root 250: new[i * 16384 + x * 2 + 0] = cpu68k_rom[512 + i * 16384 + 8192 + x];
251: new[i * 16384 + x * 2 + 1] = cpu68k_rom[512 + i * 16384 + x];
1.1 root 252: }
253: }
254: free(cpu68k_rom);
255: cpu68k_rom = new;
1.1.1.2 root 256: cpu68k_romlen -= 512;
1.1 root 257: break;
258: default:
1.1.1.2 root 259: return ("Unknown image type");
1.1 root 260: break;
261: }
262:
263: /* is this icky? */
264: if ((p = strrchr(filename, '/')) == NULL &&
265: (p = strrchr(filename, '\\')) == NULL) {
266: snprintf(gen_leafname, sizeof(gen_leafname), "%s", filename);
267: } else {
1.1.1.2 root 268: snprintf(gen_leafname, sizeof(gen_leafname), "%s", p + 1);
1.1 root 269: }
270: if ((p = strrchr(gen_leafname, '.')) != NULL) {
271: if ((!strcasecmp(p, ".smd")) || (!strcasecmp(p, ".bin")))
272: *p = '\0';
273: }
274: if (gen_leafname[0] == '\0')
275: snprintf(gen_leafname, sizeof(gen_leafname), "rom");
276:
1.1.1.3 root 277:
278: if (gen_autodetect) {
279: vdp_pal = (!gen_cartinfo.flag_usa && !gen_cartinfo.flag_japan &&
280: gen_cartinfo.flag_europe) ? 1 : 0;
281: }
282:
283: gen_setupcartinfo();
284:
285: /* reset system */
286: gen_reset();
287:
288: if (gen_cartinfo.checksum != (cpu68k_rom[0x18e] << 8 | cpu68k_rom[0x18f]))
289: LOG_REQUEST(("Warning: Checksum does not match in ROM (%04X)",
290: (cpu68k_rom[0x18e] << 8 | cpu68k_rom[0x18f])));
291:
292: LOG_REQUEST(("Loaded '%s'/'%s' (%s %04X %s)", gen_cartinfo.name_domestic,
293: gen_cartinfo.name_overseas, gen_cartinfo.version,
294: gen_cartinfo.checksum, gen_cartinfo.country));
295:
1.1.1.4 ! root 296: gen_modifiedrom = 0;
1.1.1.3 root 297: return NULL;
298: }
299:
300: /* setup to run from ROM in memory */
301:
302: void gen_loadmemrom(const char *rom, int romlen)
303: {
304: cpu68k_rom = (char *)rom; /* I won't alter it, promise */
305: cpu68k_romlen = romlen;
306: gen_freerom = 0;
307: gen_setupcartinfo();
308: gen_reset();
309: }
310:
311: /* setup gen_cartinfo from current loaded rom */
312:
313: void gen_setupcartinfo(void)
314: {
315: unsigned int i;
316: char *p;
317:
1.1 root 318: memset(&gen_cartinfo, 0, sizeof(gen_cartinfo));
1.1.1.2 root 319: gen_nicetext(gen_cartinfo.console, (char *)(cpu68k_rom + 0x100), 16);
320: gen_nicetext(gen_cartinfo.copyright, (char *)(cpu68k_rom + 0x110), 16);
321: gen_nicetext(gen_cartinfo.name_domestic, (char *)(cpu68k_rom + 0x120), 48);
322: gen_nicetext(gen_cartinfo.name_overseas, (char *)(cpu68k_rom + 0x150), 48);
1.1 root 323: if (cpu68k_rom[0x180] == 'G' && cpu68k_rom[0x181] == 'M') {
324: gen_cartinfo.prodtype = pt_game;
325: } else if (cpu68k_rom[0x180] == 'A' && cpu68k_rom[0x181] == 'I') {
326: gen_cartinfo.prodtype = pt_education;
327: } else {
328: gen_cartinfo.prodtype = pt_unknown;
329: }
1.1.1.2 root 330: gen_nicetext(gen_cartinfo.version, (char *)(cpu68k_rom + 0x182), 12);
331: gen_cartinfo.checksum = gen_checksum(((uint8 *)cpu68k_rom) + 0x200,
332: cpu68k_romlen - 0x200);
333: gen_nicetext(gen_cartinfo.memo, (char *)(cpu68k_rom + 0x1C8), 28);
1.1 root 334: for (i = 0x1f0; i < 0x1ff; i++) {
335: if (cpu68k_rom[i] == 'J')
336: gen_cartinfo.flag_japan = 1;
337: if (cpu68k_rom[i] == 'U')
338: gen_cartinfo.flag_usa = 1;
339: if (cpu68k_rom[i] == 'E')
340: gen_cartinfo.flag_europe = 1;
341: }
342: if (cpu68k_rom[0x1f0] >= '1' && cpu68k_rom[0x1f0] <= '9') {
343: gen_cartinfo.hardware = cpu68k_rom[0x1f0] - '0';
344: } else if (cpu68k_rom[0x1f0] >= 'A' && cpu68k_rom[0x1f0] <= 'F') {
345: gen_cartinfo.hardware = cpu68k_rom[0x1f0] - 'A' + 10;
346: }
347: p = gen_cartinfo.country;
348: for (i = 0x1f0; i < 0x200; i++) {
349: if (cpu68k_rom[i] != 0 && cpu68k_rom[i] != 32)
350: *p++ = cpu68k_rom[i];
351: }
352: *p = '\0';
353: }
354:
355: /*** get_nicetext - take a string, remove spaces and capitalise ***/
356:
357: void gen_nicetext(char *out, char *in, unsigned int size)
358: {
359: int flag, i;
1.1.1.3 root 360: int c;
1.1 root 361: char *start = out;
362:
1.1.1.2 root 363: flag = 0; /* set if within word, e.g. make lowercase */
364: i = size; /* maximum number of chars in input */
1.1.1.3 root 365: while ((c = *in++) && --i > 0) {
366: if (isalpha(c)) {
1.1 root 367: if (!flag) {
368: /* make uppercase */
1.1.1.2 root 369: flag = 1;
1.1.1.3 root 370: if (islower(c))
371: *out++ = c - 'z' + 'Z';
372: else
1.1.1.2 root 373: *out++ = c;
1.1 root 374: } else {
1.1.1.2 root 375: /* make lowercase */
1.1.1.3 root 376: if (isupper(c))
377: *out++ = (c) - 'Z' + 'z';
378: else
1.1.1.2 root 379: *out++ = c;
1.1 root 380: }
1.1.1.3 root 381: } else if (c == ' ') {
382: if (flag)
383: *out++ = c;
384: flag = 0;
385: } else if (isprint(c) && c != '\t') {
386: flag = 0;
387: *out++ = c;
1.1 root 388: }
389: }
1.1.1.3 root 390: while (out > start && out[-1] == ' ')
1.1 root 391: out--;
392: *out++ = '\0';
393: }
394:
395: /*** gen_checksum - get Genesis-style checksum of memory block ***/
396:
397: uint16 gen_checksum(uint8 *start, unsigned int length)
398: {
399: uint16 checksum = 0;
400:
401: if (length & 1) {
1.1.1.2 root 402: length &= ~1;
1.1.1.4 ! root 403: LOG_VERBOSE(("checksum routines given odd length (%d)", length));
1.1 root 404: }
405:
1.1.1.2 root 406: for (; length; length -= 2, start += 2) {
407: checksum += start[0] << 8;
408: checksum += start[1];
1.1 root 409: }
410: return checksum;
411: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.