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

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

unix.superglobalmegacorp.com

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