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