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