/* V9t9.C ====== */ #define __V9t9__ #include "v9t9_common.h" #include "memory.h" #include "9900.h" #include "9901.h" #include "vdp.h" #include "video.h" #include "sound.h" #include "speech.h" #include "emulate.h" #include "keyboard.h" #include "dsr.h" #include "v9t9.h" #include "timer.h" #include "cru.h" #include "roms.h" #include "moduledb.h" #include "system.h" #include "command.h" #include "moduleconfig.h" #include "debugger.h" #include "config.h" #ifdef EMU_DISK_DSR #include "fiad.h" #endif DECL_SYMBOL_ACTION(dump_config); OSPathSpec v9t9_homedir; OSSpec v9t9_progspec; int v9t9_argc; char **v9t9_argv; int v9t9_preconfiginit(void); static int preconfiginit(void); static int postconfiginit(void); static void shutdown(void); char *sessionspath, *configspath; #include "v9t9_common.h" static int dying = 0; static void __die(void) { v9t9_term(0); } void v9t9_sigint(int ignored) { stateflag |= ST_STOP | ST_TERMINATE; } void v9t9_sigterm(int ignored) { TM_Stop(); v9t9_restop(); v9t9_term(ignored); exit(ignored); } #define _L LOG_INTERNAL | LOG_INFO static void v9t9_help(void) { logger(LOG_USER|LOG_ERROR, "\n" "V9t9: TI Emulator! v7.0\n" "\n" "v9t9 [options] [file...]\n" "\n" "-h: display help\n" "-r: reboot instead of loading previous 'session.cnf'\n" "-e cmds: execute 'cmds'\n" "file: load config or session file\n" "\n"); } int v9t9_config(int argc, char **argv) { v9t9_argc = argc; v9t9_argv = argv; OS_InitProgram(&v9t9_argc, &v9t9_argv); sessionspath = xstrdup("."); configspath = xstrdup("."); xminit(); OS_GetCWD(&v9t9_homedir); OS_FindProgram(v9t9_argv[0], &v9t9_progspec); return 1; } int v9t9_init(void) { int load_std_session = 1, do_reset = 0; char *last_command; int argc; char **argv; command_init(); log_add_commands(); TM_Init(); vdpinit(); cruinit(); if (!setup_9901()) return 0; sound_init(); modules_init(); debugger_init(); #ifdef EMU_DISK_DSR fiad_set_logger(logger); #endif if (!preconfiginit()) return 0; // try to load config from cwd and then v9t9 home dir if (!config_load_file(".", "v9t9.cnf", false /*session*/)) config_load_file(OS_PathSpecToString1(&v9t9_homedir), "v9t9.cnf", false); // In case they forgot the "ReadModuleDatabase" command if (moddb == NULL && !modules_init_db("modules.inf")) { logger(LOG_ROMS|LOG_USER|LOG_ERROR, "Cannot find 'modules.inf'; no modules available\n"); return 0; } vmClearUserFlagsOnModules(); if (!postconfiginit()) return 0; last_command = 0L; argc = v9t9_argc; argv = v9t9_argv; while (--argc > 0) { if (last_command && !command_parse_text(last_command)) return 0; last_command = 0L; ++argv; if (strncmp(*argv, "-h", 2) == 0) { v9t9_help(); return 0; } else if (strncmp(*argv, "-e", 2) == 0) { if (!argc) { logger(_L|LOG_USER|LOG_ERROR, "The '%s' option needs an argument\n", *argv); v9t9_help(); return 0; } argc--; last_command = *++argv; } else if (strncmp(*argv, "-r", 2) == 0) { do_reset = 1; load_std_session = 0; } else if (**argv == '-') { logger(_L|LOG_USER|LOG_ERROR, "Unknown option '%s'\n", *argv); v9t9_help(); return 0; } else { do_reset = 0; load_std_session = 0; if (!config_load_file(sessionspath, *argv, false) && !config_load_file(configspath, *argv, true)) { do_reset = 1; load_std_session = 1; } } } if (load_std_session) { // try to load session from cwd and v9t9 home if (!config_load_file(sessionspath, "session.cnf", true /*session*/)) { emulate_setup_for_restore(); } } if (last_command && !command_parse_text(last_command)) { return 0; } if (do_reset) { command_parse_text("ResetComputer\n"); } else { emulate_setup_for_restore(); } atexit(__die); dying = 0; return 1; } int v9t9_execute(void) { int ret = vmCPU->m.cpu->execute(); return ret; } void v9t9_term(int exitcode) { if (dying) return; dying = 1; TM_Stop(); v9t9_restop(); shutdown(); termlog(); } static int preconfiginit(void) { static int (*preconfiginitlist[]) (void) = { v9t9_preconfiginit, keyboard_preconfiginit, speech_preconfiginit, /* after sound_... */ NULL }; int (**ptr) (void) = preconfiginitlist; if (!vmModulesInit()) return 0; if (!vmRegisterModules(installed_modules)) return 0; vmAddModuleCommands(); if (!vmDetectModules()) return 0; while (*ptr) if ((**ptr) () == 0) return 0; else ptr++; if (!vmInitModules()) return 0; if (!vmSelectStartupModules()) return 0; return 1; } static int postconfiginit(void) { static int (*postconfiginitlist[]) (void) = { speech_postconfiginit, /* after sound_... */ keyboard_postconfiginit, NULL }; int (**ptr) (void); int ret = 1; if (!vmEnableModules()) ret = 0; ptr = postconfiginitlist; while (*ptr) if ((**ptr) () == 0) ret = 0; else ptr++; return ret; } int restarted = 0; #define RS_VIDEO 0x1 //#define RS_EMULATE 0x2 #define RS_KEYBOARD 0x4 #define RS_SOUND 0x8 #define RS_DSR 0x10 #define RS_SPEECH 0x20 int v9t9_restart(void) { static struct { int (*func) (void); int mask; char *desc; } restartlist[] = { { video_restart, RS_VIDEO, "Video"}, { keyboard_restart, RS_KEYBOARD, "Keyboard"}, { sound_restart, RS_SOUND, "Sound"}, { speech_restart, RS_SPEECH, "Speech"}, /* after sound_... */ { NULL, 0, ""} }, *ptr; int ret = 1; if (!vmRestartModules()) ret = 0; ptr = restartlist; while (ptr->func) { if ((ptr->func) () == 0) ret = 0; else { /* log("Restarted %s\n",ptr->desc);*/ restarted |= ptr->mask; ptr++; } } TM_Start(); vdpcompleteredraw(); return ret; } void v9t9_restop(void) { static struct { void (*func) (void); int mask; char *desc; } restoplist[] = { { video_restop, RS_VIDEO, "Video"}, { keyboard_restop, RS_KEYBOARD, "Keyboard"}, { sound_restop, RS_SOUND, "Sound"}, { speech_restop, RS_SPEECH, "Speech"}, /* after sound_... */ { NULL, 0, ""} }, *ptr; TM_Stop(); vmRestopModules(); ptr = restoplist; while (ptr->func) { if (restarted & ptr->mask) { ptr->func(); /* log("Restopped %s\n",ptr->desc);*/ } ptr++; } restarted = 0; } static void shutdown(void) { vmDisableModules(); TM_Kill(); vmTermModules(); speech_shutdown(); } /****************************************/ static DECL_SYMBOL_ACTION(v9t9_display_help) { command_help(); return 1; } static DECL_SYMBOL_ACTION(v9t9_exit_interactive) { stateflag &= ~ST_INTERACTIVE; return 1; } static DECL_SYMBOL_ACTION(v9t9_die) { stateflag |= ST_TERMINATE; stateflag &= ~ST_INTERACTIVE; return 1; } static DECL_SYMBOL_ACTION(v9t9_quit) { // Save session on a positive exit config_save_file(sessionspath, "session.cnf", true /*session*/); stateflag |= ST_TERMINATE; stateflag &= ~ST_INTERACTIVE; return 1; } int v9t9_preconfiginit(void) { command_symbol_table *v9t9commands = command_symbol_table_new("Major Emulator Commands", "These are general commands to control the emulator", command_symbol_new("Help", "Display command help", c_DONT_SAVE, v9t9_display_help, NULL /* ret */ , NULL /* args */ , command_symbol_new("Interactive", "Control whether emulator waits for user commands", c_DONT_SAVE, NULL /* action */ , RET_FIRST_ARG, command_arg_new_toggle ("on|off", "if 'on', emulation will halt; " "if 'off', emulation continues at end of command list", NULL /* action */ , ARG_NUM(stateflag), ST_INTERACTIVE, NULL /* next */ ) , command_symbol_new("Exit", "Exit from interactive mode (same as 'Interactive=off')", c_DONT_SAVE, v9t9_exit_interactive, NULL /* ret */ , NULL /* args */ , command_symbol_new ("Die", "Exit V9t9 without saving session", c_DONT_SAVE, v9t9_die, NULL /* ret */ , NULL /* args */ , command_symbol_new ("Quit|Bye", "Exit V9t9 and save session", c_DONT_SAVE, v9t9_quit, NULL /* ret */ , NULL /* args */ , command_symbol_new ("HomeDirectory|Home", "Directory where V9t9 started", c_DONT_SAVE, NULL /* action */ , command_arg_new_pathspec ("dir", "directory", NULL /* action */ , &v9t9_homedir, NULL /* next */ ), NULL /* args */ , command_symbol_new ("ConfigsPath", "Set directory list for searching and saving configuration files; " "when saving, new files written to first directory and old files " "are overwritten where found", c_STATIC|c_CONFIG_ONLY, NULL /* action*/, RET_FIRST_ARG, command_arg_new_string ("path", "list of directories " "separated by one of these characters: '" OS_ENVSEPLIST "'", NULL /* action */, NEW_ARG_STRBUF(&configspath), NULL /* next */ ) , command_symbol_new ("SessionsPath", "Set directory list for searching and saving session files; " "when saving, new files written to first directory and old files " "are overwritten where found", c_STATIC|c_CONFIG_ONLY, NULL /* action*/, RET_FIRST_ARG, command_arg_new_string ("path", "list of directories " "separated by one of these characters: '" OS_ENVSEPLIST "'", NULL /* action */, NEW_ARG_STRBUF(&sessionspath), NULL /* next */ ) , command_symbol_new("SaveConfigFile", "Save current configuration settings to 'file'", c_DONT_SAVE, save_config /* action */ , NULL /* ret */, command_arg_new_string ("file", "name of config file", NULL /* action */ , NEW_ARG_STR(256), NULL /* next */ ), command_symbol_new("LoadConfigFile|ReadModuleDatabase", "Load configuration settings from 'file', " "or merge module list from 'file'", c_DONT_SAVE, load_config /* action */ , NULL /* ret */, command_arg_new_string ("file", "name of config file or modules.inf file", NULL /* action */ , NEW_ARG_STR(256), NULL /* next */ ), command_symbol_new("SaveSessionFile", "Save current configuration settings and machine state to 'file'", c_DONT_SAVE, save_session /* action */ , NULL /* ret */, command_arg_new_string ("file", "name of config file", NULL /* action */ , NEW_ARG_STR(256), NULL /* next */ ), command_symbol_new("LoadSessionFile", "Load configuration settings and machine state from 'file'", c_DONT_SAVE, load_session /* action */ , NULL /* ret */, command_arg_new_string ("file", "name of config file", NULL /* action */ , NEW_ARG_STR(256), NULL /* next */ ), command_symbol_new("SaveScreenShot", "Take a screenshot and save to 'file' or an autogenerated name", c_DONT_SAVE, vdp_take_screenshot /* action */ , NULL /* ret */, command_arg_new_string ("file", "name of file to write, or \"\" to use an automatic name " "in the current directory", NULL /* action */ , NEW_ARG_STR(256), NULL /* next */ ), NULL /* next */ ))))))))))))), NULL /* sub */ , NULL /* next */ ); configspath = xstrdup(OS_CWDSTR); sessionspath = xstrdup(OS_CWDSTR); command_symbol_table_add_subtable(universe, v9t9commands); return 1; }