/* * ============================================================================ * Title: Configuration Manager * Author: J. Zbiciak * $Id: cfg.c,v 1.11 2001/11/02 02:00:03 im14u2c Exp $ * ============================================================================ * This module manages the machine configuration. It does commandline * parsing and processes the configuration elements that were read in * via the config-file parser. * * CFG owns the entire machine -- it is encapsulated in a cfg_t. * ============================================================================ * CFG_INIT -- Parse command line and get started * CFG_FILE -- Parse a config file and extend the state of the machine. * ============================================================================ */ static const char rcs_id[]="$Id: cfg.c,v 1.11 2001/11/02 02:00:03 im14u2c Exp $"; #include "config.h" #include "file/file.h" #include "periph/periph.h" #include "cp1600/cp1600.h" #include "cp1600/emu_link.h" #include "mem/mem.h" #include "icart/icart.h" #include "bincfg/bincfg.h" #include "bincfg/legacy.h" #include "pads/pads.h" #include "pads/pads_cgc.h" #include "pads/pads_intv2pc.h" #include "gfx/gfx.h" #include "snd/snd.h" #include "ay8910/ay8910.h" #include "demo/demo.h" #include "stic/stic.h" #include "ivoice/ivoice.h" #include "speed/speed.h" #include "debug/debug_.h" #include "event/event.h" #include "joy/joy.h" #include "serializer/serializer.h" #include "mapping.h" #include "cfg.h" #include LOCAL path_t *rom_path; void cfg_default(event_t *event); /* ------------------------------------------------------------------------ */ /* This, my dear friends, is the Intellivision. */ /* ------------------------------------------------------------------------ */ cfg_t intv; #define V(v) ((v_uint_32*)&intv.v) /* ======================================================================== */ /* CFG_GET_EVT -- Convert an event name into an index. This is a */ /* horrible linear search. :-P Hey, it works for now. */ /* ======================================================================== */ int cfg_get_evt(const char *event) { int i; for (i = 0; i < cfg_event_cnt; i++) { if (!strcmp(cfg_event[i].event, event)) return i; } return -1; } /* ======================================================================== */ /* CFG_SETBIND -- Set all of the key-bindings for the Intellivision. */ /* ======================================================================== */ void cfg_setbind(cfg_t *cfg, char *kbdhackfile) { int i, j; int e; FILE *f; char buf[256]; /* -------------------------------------------------------------------- */ /* Iterate over the bindings table. */ /* -------------------------------------------------------------------- */ for (i = 0; cfg->binding[i].key != NULL; i++) { /* ---------------------------------------------------------------- */ /* Iterate over the four possible "event spaces" that the user */ /* may have configured. For instance, the user may have set up */ /* "Normal", "Swapped", "Alpha-numeric", and one other. */ /* ---------------------------------------------------------------- */ for (j = 0; j < 4; j++) { /* ------------------------------------------------------------ */ /* Skip empty event bindings. These keys aren't bound. */ /* ------------------------------------------------------------ */ if (!cfg->binding[i].event[j] || !cfg->binding[i].event[j][0]) continue; /* ------------------------------------------------------------ */ /* Look up the event name, and skip if the name is invalid. */ /* ------------------------------------------------------------ */ e = cfg_get_evt(cfg->binding[i].event[j]); if (e < 0) { fprintf(stderr, "cfg: Invalid event name '%s'\n", cfg->binding[i].event[j]); continue; } /* ------------------------------------------------------------ */ /* Map the key to the event. */ /* ------------------------------------------------------------ */ event_map(&cfg->event, cfg->binding[i].key, j, cfg_event[e].word, cfg_event[e].and_mask, cfg_event[e].or_mask); } } /* -------------------------------------------------------------------- */ /* HACK: If the user specified a keyboard mapping file, read that in. */ /* -------------------------------------------------------------------- */ if (!kbdhackfile) return; if (!(f = fopen(kbdhackfile, "r"))) { fprintf(stderr, "Couldn't open keyboard map file '%s'\n", kbdhackfile); exit(1); } j = 0; while (fgets(buf, 256, f) != NULL) { char *s1, *s2; char cmd[256], arg[256]; if ((s1 = strrchr(buf, ';'))) *s1 = 0; if ((s1 = strrchr(buf, '\r'))) *s1 = 0; if ((s1 = strrchr(buf, '\n'))) *s1 = 0; cmd[0] = 0; arg[0] = 0; s1 = buf; while (*s1 && isspace(*s1)) s1++; s2 = cmd; while (*s1 && !isspace(*s1)) *s2++ = *s1++; *s2 = 0; while (*s1 && isspace(*s1)) s1++; s2 = arg; while (*s1 && !isspace(*s1)) *s2++ = *s1++; *s2 = 0; if (!stricmp(cmd, "map")) { j = atoi(arg); continue; } if (cmd[0] == 0 || arg[0] == 0) { if (cmd[0]) { fprintf(stderr, "unknown command '%s' in %s\n", cmd, kbdhackfile); } continue; } jzp_printf("binding %s to %s in map %d\n", cmd, arg, j); if ((e = cfg_get_evt(arg)) < 0) { fprintf(stderr, "cfg: Invalid event name '%s'\n", arg); continue; } event_map(&cfg->event, cmd, j, cfg_event[e].word, cfg_event[e].and_mask, cfg_event[e].or_mask); } fclose(f); } /* ======================================================================== */ /* CFG_LONGOPT -- Long options for getopt_long */ /* ======================================================================== */ struct option cfg_longopt[] = { { "ecsimg", 1, NULL, 'E' }, { "execimg", 1, NULL, 'e' }, { "gromimg", 1, NULL, 'g' }, { "ecs", 2, NULL, 's' }, { "fullscreen", 2, NULL, 'f' }, { "audiofile", 1, NULL, 'F' }, { "debugger", 0, NULL, 'd' }, { "ratecontrol", 2, NULL, 'r' }, { "macho", 2, NULL, 'r' }, { "fullscreen", 2, NULL, 'x' }, { "displaysize", 2, NULL, 'z' }, { "audio", 1, NULL, 'a' }, { "audiorate", 1, NULL, 'a' }, { "audiowindow", 1, NULL, 'w' }, { "audiobufsize", 1, NULL, 'B' }, { "audiobufcnt", 1, NULL, 'C' }, { "audiomintick", 1, NULL, 'M' }, { "voice", 2, NULL, 'v' }, { "voicewindow", 2, NULL, 'W' }, { "voicefiles", 2, NULL, 'V' }, { "i2pc0", 2, NULL, 'i' }, { "i2pc1", 2, NULL, 'I' }, { "intv2pc0", 2, NULL, 'i' }, { "intv2pc1", 2, NULL, 'I' }, #ifdef CGC_DLL { "cgc0", 2, NULL, 1 }, { "cgc1", 2, NULL, 2 }, #endif #ifdef CGC_THREAD { "cgc0", 1, NULL, 1 }, { "cgc1", 1, NULL, 2 }, #endif { "icartcache", 2, NULL, 'c' }, { "help", 0, NULL, 'h' }, { "license", 0, NULL, 'l' }, { "nobusywait", 0, NULL, '9' }, { "kbdhackfile", 1, NULL, 3 }, { "demofile", 1, NULL, 'D' }, { "js0", 2, NULL, 4 }, { "js1", 2, NULL, 5 }, { "js2", 2, NULL, 6 }, { "js3", 2, NULL, 7 }, #ifdef GP2X { "gp2xclock", 1, NULL, 8 }, { "gp2x-pad-bias",1, NULL, 4 }, #endif { "gfx-swsurf", 2, NULL, 9 }, { "gfx-dblbuf", 2, NULL, 10 }, { "gfx-asyncb", 2, NULL, 11 }, { "gfx-hwpal", 2, NULL, 12 }, { "gui-mode", 0, NULL, 13 }, { "rom-path", 1, NULL, 'p' }, { "quiet", 0, NULL, 'q' }, { NULL, 0, NULL, 0 } }; LOCAL const char *optchars= "E:e:g:s::f::F:?dhqr::x::z::a:w:B:C:M:" "v::W::V::i::I::c:D:p:"; extern char *optarg; extern int optind, opterr, optopt; /* ======================================================================== */ /* Supported I/O addresses for INTV2PC. */ /* ======================================================================== */ const uint_32 i2pc_ports[4] = { 0x0, 0x378, 0x278, 0x3BC }; /* ======================================================================== */ /* Supported display resolutions. */ /* ======================================================================== */ LOCAL const int res_x[] = { 320, 640, 320 }; LOCAL const int res_y[] = { 200, 480, 240 }; LOCAL const int res_d[] = { 8, 8 , 16 }; #define NUM_RES ((int)(sizeof(res_x) / sizeof(res_x[0]))) LOCAL char *joy_cfg[MAX_JOY]; /* ======================================================================== */ /* CFG_INIT -- Parse command line and get started */ /* ======================================================================== */ void cfg_init(int argc, char * argv[]) { int c, option_idx = 0, rx, ry, rd; int exec_type = 0, legacy_rom = 0; int value = 1, busywaits = 1; uint_32 cache_flags = IC_CACHE_DFLT; char *audiofile = NULL, *tmp; char *kbdhackfile = NULL; char *demofile = NULL; FILE *f; ser_hier_t *ser_cfg; int silent = 0; #ifdef GP2X int gp2xclock = 200; #endif /* -------------------------------------------------------------------- */ /* Set up the default state for everything. */ /* -------------------------------------------------------------------- */ memset(&intv, 0, sizeof(cfg_t)); intv.audio_rate = 44100; /* high quality. :-) */ intv.psg_window = -1; /* Automatic window setting. */ intv.ecs_enable = -1; /* Automatic (dflt: ECS off) */ intv.ivc_enable = -1; /* Automatic (dflt: Intellivoice off. */ intv.ivc_window = -1; /* Automatic window setting. */ intv.gfx_flags = GFX_DBLBUF; /* Windowed, double buf, hardware surf */ intv.i2pc0_port = 0; /* No INTV2PC #0 */ intv.i2pc1_port = 0; /* No INTV2PC #1 */ intv.cgc0_num = -1; /* No CGC #0 */ intv.cgc1_num = -1; /* No CGC #1 */ intv.cgc0_dev = NULL; /* No CGC #0 */ intv.cgc1_dev = NULL; /* No CGC #1 */ intv.debugging = 0; /* No debugger. */ intv.rate_ctl = 1.0; /* Rate control enabled. */ intv.disp_res = 0; /* 320x200 */ intv.accutick = 1; /* fully accurate audio. */ intv.binding = cfg_key_bind; /* default key bindings. */ intv.fn_exec = "exec.bin"; /* Default name to look for in src path */ intv.fn_grom = "grom.bin"; /* ... */ intv.fn_game = "game.rom"; /* ... */ intv.fn_ecs = "ecs.bin"; /* ... */ /* -------------------------------------------------------------------- */ /* Figure out out our executable's path. */ /* -------------------------------------------------------------------- */ { char *s; exe_path = strdup(argv[0]); s = strrchr(exe_path, PATH_SEP); if (s) *s = 0; else { free(exe_path); exe_path = NULL; } } /* -------------------------------------------------------------------- */ /* Register our config variables for serialization. */ /* -------------------------------------------------------------------- */ #define SER_REG(x,t,l,f)\ ser_register(ser_cfg, #x, &intv. x, t, l, f) ser_cfg = ser_new_hierarchy(NULL, "cfg"); SER_REG(ecs_enable, ser_s32, 1, SER_INIT|SER_MAND); SER_REG(ivc_enable, ser_s32, 1, SER_INIT|SER_MAND); SER_REG(ivc_tname, ser_string, 1, SER_INIT|SER_MAND); /* -------------------------------------------------------------------- */ /* Parse the commandline flags. */ /* -------------------------------------------------------------------- */ while ((c = getopt_long(argc, argv, optchars, cfg_longopt, &option_idx)) != EOF) { int noarg = 1; double dvalue; value = 1; dvalue = 1.0; if (optarg) { noarg = 0; value = atoi(optarg); sscanf(optarg, "%lf", &dvalue); } switch (c) { case '?': case 'h': jzp_init(0,stdout,NULL,NULL); usage(); break; case 'l': jzp_init(0,stdout,NULL,NULL); license(); break; case 'q': silent = 1; break; case 'B': snd_buf_size = value; break; case 'C': snd_buf_cnt = value; break; case 'M': intv.accutick = value; break; case 'E': intv.fn_ecs = strdup(optarg); break; case 'e': intv.fn_exec = strdup(optarg); break; case 'g': intv.fn_grom = strdup(optarg); break; case 'F': audiofile = strdup(optarg); break; case 's': intv.ecs_enable = value; break; case 'z': intv.disp_res = value; break; case 'd': intv.debugging = 1; break; case 'r': intv.rate_ctl = dvalue; break; case 'a': intv.audio_rate = value; break; case 'w': intv.psg_window = value; break; case 'v': intv.ivc_enable = value; break; case 'W': intv.ivc_window = value; break; case 'V': intv.ivc_tname = strdup(optarg); break; case 'i': intv.i2pc0_port = value; break; case 'I': intv.i2pc1_port = value; break; case 1: intv.cgc0_num = noarg ? 0 : value; intv.cgc0_dev = strdup(optarg); break; case 2: intv.cgc1_num = noarg ? 0 : value; intv.cgc1_dev = strdup(optarg); break; case 3: kbdhackfile = strdup(optarg); break; case 4: case 5: case 6: case 7: joy_cfg[c - 4] = strdup(optarg ? optarg : ""); break; #ifdef GP2X case 8: gp2xclock = value; break; #endif #define CHG_BIT(var, bit, to) (var) = ((var) & ~(bit)) | ((to) ? (bit) : 0) case 'f': case 'x': CHG_BIT(intv.gfx_flags, GFX_FULLSC, value); break; case 9: CHG_BIT(intv.gfx_flags, GFX_SWSURF, value); break; case 10: CHG_BIT(intv.gfx_flags, GFX_DBLBUF, value); break; case 11: CHG_BIT(intv.gfx_flags, GFX_ASYNCB, value); break; case 12: CHG_BIT(intv.gfx_flags, GFX_HWPAL, value); break; case 13: intv.gui_mode = 1; break; case 'D': demofile = strdup(optarg); break; case '9': busywaits = 0; break; case 'c': { char *name = "Default"; switch (value) { default: case 0: cache_flags = IC_CACHE_CABS; name = "Cache bankswitched"; break; case 1: cache_flags = IC_CACHE_NOBS; name = "Don't cache bankswitched"; break; case 2: cache_flags = IC_CACHE_SAFE; name = "Cache read-only, no banksw"; break; case 3: cache_flags = IC_CACHE_NONE; name = "Cache nothing"; break; } break; } case 'p': { rom_path = parse_path_string(rom_path, optarg); break; } default: { fprintf(stderr, "Unrecognized argument: '%c'\n" "Try jzintv --help for usage information.", c); exit(1); } } } if (optind < argc) intv.fn_game = argv[optind]; if (snd_buf_size < 1) snd_buf_size = SND_BUF_SIZE_DEFAULT; if (snd_buf_cnt < 1) snd_buf_size = SND_BUF_CNT_DEFAULT; rom_path = parse_path_string(rom_path, getenv("JZINTV_ROM_PATH")); if (DEFAULT_ROM_PATH) rom_path = parse_path_string(rom_path, DEFAULT_ROM_PATH); /* -------------------------------------------------------------------- */ /* Set up jzp_printf. */ /* -------------------------------------------------------------------- */ if (intv.gui_mode) { intv.debugging = 0; jzp_init(1, 0, NULL, NULL); setvbuf(stdin, NULL, _IONBF, 0); #ifndef NO_FCNTL fcntl(STDIN_FILENO, F_SETFL, O_NDELAY); #endif } else jzp_init(silent, stdout, NULL, NULL); #ifdef GP2X /* -------------------------------------------------------------------- */ /* On GP2X, simply force a few arguments to the only supported vals. */ /* Also, adjust the clock if the user requests it. */ /* -------------------------------------------------------------------- */ intv.gfx_flags |= GFX_FULLSC; intv.gfx_flags &= ~GFX_DBLBUF; intv.disp_res = 2; if (gp2xclock > 0) { extern int gp2x_speed(int); if (gp2x_speed(gp2xclock)) { jzp_printf("Clock rate %d unsupported.\n", gp2xclock); exit(1); } } #endif /* -------------------------------------------------------------------- */ /* Sanity-check some of the flags. Most get checked by peripherals. */ /* -------------------------------------------------------------------- */ if (intv.disp_res >= NUM_RES) { int i; fprintf(stderr, "Display resolution # out of range. " "Valid resolutions:\n"); for (i = 0; i < NUM_RES; i++) { fprintf(stderr, " -z%d: %dx%dx%x\n", i, res_x[i], res_y[i], res_d[i]); } exit(1); } else { rx = res_x[intv.disp_res]; ry = res_y[intv.disp_res]; rd = res_d[intv.disp_res]; } /* -------------------------------------------------------------------- */ /* He's a macho, macho duck. He's a macho, macho duck! */ /* -------------------------------------------------------------------- */ if (intv.rate_ctl < 1.0 && intv.rate_ctl > 0.01) intv.rate_ctl = 1.0; else if (intv.rate_ctl <= 0.01) intv.rate_ctl = 0; #ifdef DIRECT_INTV2PC /* -------------------------------------------------------------------- */ /* Look up INTV2PC port numbers, if any. */ /* -------------------------------------------------------------------- */ if (intv.i2pc0_port > 3 || intv.i2pc1_port > 3) { fprintf(stderr, "ERROR: " "INTV2PC port number out of range. Valid values are 1..3 for\n" "typical ports for LPT1: through LPT3:, and 0 to disable.\n" "\n" "The following port numbers are selected by 1 through 3:\n" " 1 selects 0x%.3X\n" " 2 selects 0x%.3X\n" " 3 selects 0x%.3X\n" "\n", i2pc_ports[1], i2pc_ports[2], i2pc_ports[3]); exit(1); } if (intv.i2pc0_port && intv.i2pc0_port == intv.i2pc1_port) { fprintf(stderr, "ERROR: Cannot enable two INTV2PCs on same port #\n"); exit(1); } intv.i2pc0_port = i2pc_ports[intv.i2pc0_port]; intv.i2pc1_port = i2pc_ports[intv.i2pc1_port]; #endif /* -------------------------------------------------------------------- */ /* Create a new peripheral bus for the Intellivision main console. */ /* -------------------------------------------------------------------- */ intv.intv = periph_new(16, 16, 4); (void)strncpy(intv.intv->periph.name, "Master Component", 16); /* -------------------------------------------------------------------- */ /* Now, configure the Intellivision according to our flags. Start */ /* off by reading in the EXEC, GROM, and GAME images. */ /* -------------------------------------------------------------------- */ f = path_fopen(rom_path, intv.fn_exec, "rb"); exec_type = 0; if (!f || file_read_rom16(f, 4096, intv.exec_img) != 4096) { if (errno) perror("file_read_rom16"); fprintf(stderr, "ERROR: Could not read EXEC image '%s'\n", intv.fn_exec); dump_search_path(rom_path); exit(1); } fseek(f, 0, SEEK_END); if (ftell(f) == 2 * (4096 + 256)) { exec_type = 1; fseek(f, 8192, SEEK_SET); if (file_read_rom16(f, 256, intv.exec_img + 4096) != 256) { if (errno) perror("file_read_rom16"); fprintf(stderr, "ERROR: Could not read EXEC2 image '%s'\n", intv.fn_exec); exit(1); } } fclose(f); f = path_fopen(rom_path, intv.fn_grom, "rb"); if (!f || file_read_rom8 (f, 2048, intv.grom_img) != 2048) { if (errno) perror("file_read_rom8"); fprintf(stderr, "ERROR: Could not read GROM image '%s'\n", intv.fn_grom); dump_search_path(rom_path); exit(1); } fclose(f); /* -------------------------------------------------------------------- */ /* First try to load it as a legacy ROM. If the legacy code decides */ /* it's not actually a BIN+CFG, it'll hand us back a .ROM filename. */ /* -------------------------------------------------------------------- */ tmp = legacy_bincfg(&(intv.legacy), rom_path, intv.fn_game); if (tmp == NULL) { fprintf(stderr, "ERROR: Failed to initialize game\n"); exit(1); } if (tmp == intv.fn_game) legacy_rom = 1; else intv.fn_game = tmp; /* -------------------------------------------------------------------- */ /* If it wasn't a legacy ROM, it must be an Intellicart ROM. */ /* -------------------------------------------------------------------- */ if (!legacy_rom) { /* not path_fopen, because legacy_bincfg should do that for us. */ if (!(f = fopen(intv.fn_game, "rb"))) { perror("fopen()"); fprintf(stderr, "ERROR: Failed to open Intellicart ROM:\n %s\n", intv.fn_game); exit(1); } /* ---------------------------------------------------------------- */ /* Process the Intellicart ROM itself. */ /* ---------------------------------------------------------------- */ if (icart_init(&intv.icart, f, NULL)) { fprintf(stderr, "ERROR: Failed to register Intellicart\n"); exit(1); } /* ---------------------------------------------------------------- */ /* TODO: Process meta-data tags on Intellicart image. */ /* ---------------------------------------------------------------- */ fclose(f); } /* -------------------------------------------------------------------- */ /* Initialize the peripherals. */ /* -------------------------------------------------------------------- */ jzp_printf("jzintv: Initializing Master Component and peripherals...\n"); if (emu_link_init()) { fprintf(stderr, "ERROR: Failed to initialize EMU_LINK\n"); exit(1); } if (demofile && demo_init(&intv.demo, demofile, &intv.psg0, intv.ecs_enable > 0 ? &intv.psg1 : 0)) { fprintf(stderr, "ERROR: Failed to initialize demo recorder\n"); exit(1); } if (gfx_init(&intv.gfx, rx, ry, rd, intv.gfx_flags)) { fprintf(stderr, "ERROR: Failed to initialize graphics\n"); exit(1); } if (intv.audio_rate && snd_init(&intv.snd, intv.audio_rate, audiofile)) { fprintf(stderr, "WARNING: Failed to initialize sound. Disabled.\n"); intv.audio_rate = 0; } if (cp1600_init(&intv.cp1600, 0x1000, 0x1004)) { fprintf(stderr, "ERROR: Failed to initialize CP-1610 CPU\n"); exit(1); } if (mem_make_ram (&intv.scr_ram, 8, 0x0100, 8) || mem_make_ram (&intv.sys_ram, 16, 0x0200, 9) || //mem_make_glitch_ram(&intv.glt_ram, 0xD000, 12) || mem_make_9600a(&intv.sys_ram2, 0x0300, 8)/* || mem_make_ram (&intv.gram, 8, 0x3800, 9)*/) { fprintf(stderr, "ERROR: Failed to initialize RAMs\n"); exit(1); } if (stic_init(&intv.stic, intv.grom_img, &intv.cp1600.req_bus, &intv.gfx, demofile ? &intv.demo : NULL)) { fprintf(stderr, "ERROR: Failed to initialize STIC\n"); exit(1); } if (intv.ecs_enable > 0) { f = path_fopen(rom_path, intv.fn_ecs, "rb"); if (!f || file_read_rom16(f, 12*1024, intv.ecs_img) != 12*1024) { if (errno) perror("errno value e"); fprintf(stderr, "ERROR: Could not read ECS ROM image '%s'\n", intv.fn_ecs); exit(1); } fclose(f); if (mem_make_prom(&intv.ecs0, 16, 0x2000, 12, 1, intv.ecs_img ) || mem_make_prom(&intv.ecs1, 16, 0x7000, 12, 0, intv.ecs_img+4096) || mem_make_prom(&intv.ecs2, 16, 0xE000, 12, 1, intv.ecs_img+8192)) { fprintf(stderr, "ERROR: Can't make Paged ROM from ECS image\n"); exit(1); } if (mem_make_ram(&intv.ecs_ram, 8, 0x4000, 11)) { fprintf(stderr, "ERROR: Can't allocate ECS RAM\n"); exit(1); } } if (ay8910_init(&intv.psg0, 0x1F0, &intv.snd, intv.audio_rate, intv.psg_window, intv.accutick, intv.rate_ctl > 0.0 ? intv.rate_ctl : 1.0)) { fprintf(stderr, "ERROR: Failed to initialize PSG#1 (AY8914)\n"); exit(1); } if (intv.ecs_enable > 0 && ay8910_init(&intv.psg1, 0x0F0, &intv.snd, intv.audio_rate, intv.psg_window, intv.accutick, intv.rate_ctl > 0.0 ? intv.rate_ctl : 1.0)) { fprintf(stderr, "ERROR: Failed to initialize PSG#2 (AY8914)\n"); exit(1); } if (pad_init(&intv.pad0, 0x1F0, PAD_HAND)) { fprintf(stderr, "ERROR: Failed to initialize game pads\n"); exit(1); } if (intv.ecs_enable > 0 && pad_init(&intv.pad1, 0x0F0, PAD_KEYBOARD)) { fprintf(stderr, "ERROR: Failed to ECS input device\n"); exit(1); } #ifdef DIRECT_INTV2PC if (intv.i2pc0_port > 0 && pad_intv2pc_init(&intv.i2pc0, 0x1F0, intv.i2pc0_port)) { fprintf(stderr, "ERROR: Failed to initialize INTV2PC #0 at 0x%.3X\n", intv.i2pc0_port); exit(1); } if (intv.ecs_enable > 0 && intv.i2pc1_port && pad_intv2pc_init(&intv.i2pc1, 0x0F0, intv.i2pc1_port)) { fprintf(stderr, "ERROR: Failed to initialize INTV2PC #1 at 0x%.3X\n", intv.i2pc1_port); exit(1); } #endif if (intv.cgc0_num >= 0 && pad_cgc_init(&intv.cgc0, 0x1F0, intv.cgc0_num, intv.cgc0_dev)) { fprintf(stderr, "ERROR: Failed to initialize CGC #%d as pad pair 0\n", intv.cgc0_num); exit(1); } if (intv.ecs_enable > 0 && intv.cgc1_num >= 0 && pad_cgc_init(&intv.cgc1, 0x0F0, intv.cgc1_num, intv.cgc0_dev)) { fprintf(stderr, "ERROR: Failed to initialize CGC #%d as pad pair 1\n", intv.cgc1_num); exit(1); } if (intv.rate_ctl > 0.0 && speed_init(&intv.speed, &intv.gfx, &intv.stic, busywaits, intv.rate_ctl)) { fprintf(stderr, "ERROR: Failed to initialize rate control.\n"); exit(1); } if (intv.debugging && debug_init(&intv.debug, &intv.cp1600, intv.rate_ctl > 0.0 ? &intv.speed : NULL)) { fprintf(stderr, "ERROR: Failed to initialize debugger\n"); exit(1); } if (joy_init(1, joy_cfg)) { fprintf(stderr, "ERROR: Failed to initialize joystick subsystem.\n"); exit(1); } if (event_init(&intv.event)) { fprintf(stderr, "ERROR: Failed to initialize event subsystem.\n"); exit(1); } cfg_setbind(&intv, kbdhackfile); if (intv.ivc_enable > 0 && intv.audio_rate > 0 && ivoice_init(&intv.ivoice, 0x80, &intv.snd, intv.audio_rate, intv.ivc_window, intv.ivc_tname)) { fprintf(stderr, "ERROR: Failed to initialize Intellivoice\n"); exit(1); } /* -------------------------------------------------------------------- */ /* Note: We handle the EXEC ROM specially, since it's weird on */ /* the Intellivision 2. */ /* -------------------------------------------------------------------- */ if (exec_type == 0) { if (mem_make_rom(&intv.exec, 10, 0x1000, 12, intv.exec_img)) { fprintf(stderr, "ERROR: Failed to initialize EXEC ROM\n"); exit(1); } } else { if (mem_make_rom(&intv.exec, 10, 0x1000, 12, intv.exec_img+256) || mem_make_rom(&intv.exec2, 10, 0x0400, 8, intv.exec_img)) { fprintf(stderr, "ERROR: Failed to initialize EXEC2 ROM\n"); exit(1); } } /* -------------------------------------------------------------------- */ /* Now register all the devices on the Intellivision's bus. */ /* -------------------------------------------------------------------- */ #define P(x) intv.intv, ((periph_p)(&(intv.x))) periph_register (P(cp1600 ), 0x0000, 0x0000, "CP-1610" ); periph_register (P(psg0 ), 0x01F0, 0x01FF, "PSG0 AY8914" ); if (intv.ecs_enable > 0) periph_register(P(psg1 ), 0x00F0, 0x00FF, "PSG1 AY8914" ); if (intv.ivc_enable > 0 && intv.audio_rate) periph_register(P(ivoice ), 0x0080, 0x0081, "Int. Voice" ); periph_register (P(gfx ), 0x0000, 0x0000, "[Graphics]" ); if (intv.audio_rate) periph_register(P(snd ), 0x0000, 0x0000, "[Sound]" ); periph_register (P(scr_ram ), 0x0100, 0x01EF, "Scratch RAM" ); periph_register (P(sys_ram ), 0x0200, 0x035F, "System RAM" ); //periph_register (P(glt_ram ), 0xD000, 0xDFFF, "GLITCH RAM" ); if (exec_type != 0) periph_register(P(sys_ram2 ), 0x0360, 0x03FF, "System RAM B"); if (exec_type == 0) { periph_register(P(exec ), 0x1000, 0x1FFF, "EXEC ROM" ); } else { periph_register(P(exec ), 0x1000, 0x1FFF, "EXEC2 main" ); periph_register(P(exec2 ), 0x0400, 0x04FF, "EXEC2 aux." ); } if (intv.ecs_enable > 0) { periph_register(P(ecs_ram ), 0x4000, 0x47FF, "ECS RAM" ); periph_register(P(ecs0 ), 0x2000, 0x2FFF, "ECS ROM (2xxx)"); periph_register(P(ecs1 ), 0x7000, 0x7FFF, "ECS ROM (7xxx)"); periph_register(P(ecs2 ), 0xE000, 0xEFFF, "ECS ROM (Exxx)"); } /* periph_register (P(grom ), 0x3000, 0x37FF, "GROM" );*/ /* periph_register (P(gram ), 0x3800, 0x3FFF, "GRAM" );*/ periph_register (P(pad0 ), 0x01F0, 0x01FF, "Pad Pair 0" ); if (intv.ecs_enable > 0) periph_register(P(pad1 ), 0x00F0, 0x00FF, "Pad Pair 1" ); if (intv.i2pc0_port) periph_register(P(i2pc0 ), 0x01F0, 0x01FF, "INTV2PC #0" ); if (intv.i2pc1_port && intv.ecs_enable > 0) periph_register(P(i2pc1 ), 0x00F0, 0x00FF, "INTV2PC #1" ); if (intv.cgc0_num >= 0) periph_register(P(cgc0 ), 0x01F0, 0x01FF, "CGC #0" ); if (intv.cgc1_num >= 0 && intv.ecs_enable > 0) periph_register(P(cgc1 ), 0x00F0, 0x00FF, "CGC #1" ); periph_register (P(stic.stic_cr ), 0x0000, 0x007F, "STIC" ); periph_register (P(stic.stic_cr ), 0x4000, 0x403F, "STIC (alias)"); periph_register (P(stic.stic_cr ), 0x8000, 0x803F, "STIC (alias)"); periph_register (P(stic.stic_cr ), 0xC000, 0xC03F, "STIC (alias)"); periph_register (P(stic.snoop_btab), 0x0200, 0x02EF, "STIC (BTAB)" ); periph_register (P(stic.snoop_gram), 0x3000, 0x3FFF, "STIC (GRAM)" ); periph_register (P(event ), 0x0000, 0x0000, "[Event]" ); if (intv.rate_ctl > 0.0) periph_register(P(speed ), 0x0000, 0x0000, "[Rate Ctrl]" ); /* -------------------------------------------------------------------- */ /* Register the game ROMs, or the Intellicart, as the case may be. */ /* -------------------------------------------------------------------- */ if (legacy_rom) { legacy_register(&intv.legacy, intv.intv, &intv.cp1600); } else { icart_register(&intv.icart, intv.intv, &intv.cp1600, cache_flags); } /* -------------------------------------------------------------------- */ /* Mark the ROMs cacheable in the CPU. Mark the 16-bit RAM as cache- */ /* able, but in need of bus-snoop support. */ /* -------------------------------------------------------------------- */ cp1600_cacheable(&intv.cp1600, 0x0200, 0x035F, 1); cp1600_cacheable(&intv.cp1600, 0x1000, 0x1FFF, 0); cp1600_cacheable(&intv.cp1600, 0x3000, 0x37FF, 0); /* -------------------------------------------------------------------- */ /* Register the debugger. This _must_ be done last. */ /* -------------------------------------------------------------------- */ if (intv.debugging) periph_register(P(debug ), 0x0000, 0xFFFF, "[Debugger]" ); #if 0 { f = fopen("ser.txt", "w"); if (f) ser_print_hierarchy(f, NULL, 0, 0); } #endif return; } /* ======================================================================== */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */ /* General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* ======================================================================== */ /* Copyright (c) 1998-2000, Joseph Zbiciak */ /* ======================================================================== */