|
|
1.1.1.2 ! root 1: /* Generator is (c) James Ponder, 1997-2001 http://www.squish.net/generator/ */ 1.1 root 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" 1.1.1.2 ! root 15: #include "snprintf.h" ! 16: 1.1 root 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; 1.1.1.2 ! root 32: unsigned int gen_debugmode = 0; ! 33: unsigned int gen_loglevel = 2; /* 2 = NORMAL, 1 = CRITICAL */ 1.1 root 34: t_cartinfo gen_cartinfo; 1.1.1.2 ! root 35: char gen_leafname[128]; 1.1 root 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: 1.1.1.2 ! root 131: /*** gen_softreset - reset system ***/ ! 132: ! 133: void gen_softreset(void) { ! 134: cpu68k_reset(); ! 135: } ! 136: 1.1 root 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: 1.1.1.2 ! root 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: 1.1 root 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])) 1.1.1.2 ! root 308: LOG_REQUEST(("Warning: Checksum does not match in ROM (%04X)", ! 309: (cpu68k_rom[0x18e]<<8 | cpu68k_rom[0x18f]))); 1.1 root 310: 1.1.1.2 ! root 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, 1.1 root 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: 1.1.1.2 ! root 368: if (length & 1) { ! 369: length&= ~1; ! 370: LOG_CRITICAL(("checksum routines given odd length (%d)", length)); ! 371: } ! 372: 1.1 root 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.