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

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

unix.superglobalmegacorp.com

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