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