Annotation of generator/main/generator.c, revision 1.1.1.4

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.