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