home *** CD-ROM | disk | FTP | other *** search
/ ftp.whtech.com / ftp.whtech.com.7z / ftp.whtech.com / emulators / v9t9 / linux / sources / V9t9 / source / moduledb.c < prev    next >
Encoding:
C/C++ Source or Header  |  2006-10-19  |  26.1 KB  |  1,151 lines

  1.  
  2. /*
  3.     MODULEDB.C
  4.     ===========
  5.  
  6.     This module provides a layer of abstraction to the memory.c
  7.     module by defining a way for the user to redefine parts of
  8.     the 99/4A memory map (usually by filling them in with binary
  9.     images).
  10.  
  11.     "Module" here means, basically, any >2000 byte area of ROM or RAM,
  12.     GROM or GRAM, including console ROMs and GROMs, volatile and
  13.     non-volatile RAM.  
  14. */
  15.  
  16. #include "v9t9_common.h"
  17. #include "memory.h"
  18. #include "command.h"
  19. #include "moduledb.h"
  20. #include "roms.h"
  21.  
  22. #define _L     LOG_ROMS
  23.  
  24. ModuleEntry *moddb;
  25.  
  26. ModuleEntry *loaded_module;    /* last successful module loaded */
  27.  
  28. /*    Free entries in modules database */
  29. static void 
  30. modules_free_db(void)
  31. {
  32.     ModuleEntry *lst = moddb;
  33.  
  34.     while (lst) {
  35.         ModuleEntry *nxt = lst->next;
  36.  
  37.         if (lst->name)
  38.             xfree(lst->name);
  39.         if (lst->tag)
  40.             xfree(lst->tag);
  41.         if (lst->commands)
  42.             xfree(lst->commands);
  43.         xfree(lst);
  44.         lst = nxt;
  45.     }
  46.  
  47.     moddb = NULL;
  48. }
  49.  
  50. /*    Initialize modules database */
  51. int
  52. modules_init_db(char *dbfilename)
  53. {
  54.     loaded_module = NULL;
  55.     modules_free_db();
  56.     command_parse_file(dbfilename);
  57.  
  58.     return 1;
  59. }
  60.  
  61. static ModuleEntry *
  62. modules_find_tag_in_db(const char *tag)
  63. {
  64.     ModuleEntry *lst = moddb;
  65.  
  66.     while (lst && strcasecmp(lst->tag, tag))
  67.         lst = lst->next;
  68.     return lst;
  69. }
  70.  
  71. static ModuleEntry *
  72. modules_search_str_in_db(char *str)
  73. {
  74.     ModuleEntry *lst = moddb;
  75.  
  76.     while (lst && stristr(lst->name, str) == NULL)
  77.         lst = lst->next;
  78.     return lst;
  79. }
  80.  
  81. static void
  82. modules_add_to_db(ModuleEntry * nw)
  83. {
  84.     ModuleEntry **lst = &moddb;
  85.  
  86.     while (*lst && strcasecmp((*lst)->tag, nw->tag))
  87.         lst = &(*lst)->next;
  88.     if (*lst)
  89.         nw->next = (*lst)->next;
  90.     else
  91.         nw->next = NULL;
  92.  
  93.     *lst = nw;
  94. }
  95.  
  96. /*    Free modules loaded in memory  */
  97. static int
  98. module_unload_entries(void)
  99. {
  100.     MemoryEntry *lst = mementlist, *prev = 0L;
  101.  
  102.     while (lst) {
  103.         if (lst->flags & MEMENT_CART) {
  104.             memory_unmap_entry(lst);
  105.             memset(lst->memact.areamemory, 0, lst->realsize);
  106.             lst = memory_remove_entry_from_list(prev, lst);
  107.         } else {
  108.             prev = lst;
  109.             lst = lst->next;
  110.         }
  111.     }
  112.     memory_module_bank_handlers[0] = memory_module_bank_handlers[1] = NULL;
  113.     loaded_module = NULL;
  114.     return 1;
  115. }
  116.  
  117. /*    Free module loaded in memory  */
  118. static int
  119. module_unload_entry(int mement)
  120. {
  121.     MemoryEntry *lst = mementlist, *prev = 0L;
  122.  
  123.     while (lst) {
  124.         if ((lst->flags & MEMENT_CART) &&
  125.             (lst->flags & mement) == mement) 
  126.         {
  127.             memory_unmap_entry(lst);
  128.             memset(lst->memact.areamemory, 0, lst->realsize);
  129.             lst = memory_remove_entry_from_list(prev, lst);
  130.         } else {
  131.             prev = lst;
  132.             lst = lst->next;
  133.         }
  134.     }
  135.     if (mement & MEMENT_BANKING) {
  136.         memory_module_bank_handlers[0] = memory_module_bank_handlers[1] = NULL;
  137.     }
  138.     return 1;
  139. }
  140.  
  141. static int module_change_entry(const char *tag, const char *name, const char *base, const char *cmdbuf)
  142. {    
  143.     ModuleEntry *nw, *it;
  144.  
  145.     it = modules_find_tag_in_db(tag);
  146.     nw = 0L;
  147.  
  148.     // replace existing entry?
  149.     if (it) {
  150.         xfree(it->tag);
  151.         xfree(it->name);
  152.         xfree(it->commands);
  153.     } else {
  154.         nw = it = (ModuleEntry *) xmalloc(sizeof(ModuleEntry));
  155.     }
  156.  
  157.     it->name = xstrdup(name);
  158.     it->tag = xstrdup(tag);
  159.     it->commands = (char *)xmalloc(strlen(cmdbuf)+2);
  160.     sprintf(it->commands, "%s\n", cmdbuf);
  161.  
  162.     if (nw) {
  163.         modules_add_to_db(nw);
  164.     }
  165.     return 1;
  166. }
  167.  
  168. static char *
  169. appendstr(char *strbuf, char *format, ...)
  170. {
  171.     char linebuf[1024];
  172.     char *buf;
  173.  
  174.     va_list va;
  175.     va_start(va, format);
  176.     vsnprintf(linebuf, sizeof(linebuf), format, va);
  177.     va_end(va);
  178.  
  179.     buf = (char *)xmalloc((strbuf ? strlen(strbuf) : 0) + strlen(linebuf) + 1);
  180.     if (strbuf) strcpy(buf, strbuf); else *buf = 0;
  181.     strcat(buf, linebuf);
  182.  
  183.     if (strbuf) xfree(strbuf);
  184.     return buf;
  185. }
  186.  
  187. static bool 
  188. module_find_gram_kracker_segment(char *namebuf, OSSpec *spec, 
  189.                                  gram_kracker_header *header,
  190.                                  bool *had_rom_segment, bool *is_banked,
  191.                                  char **cmdptr)
  192. {
  193.     if (roms_find_gram_kracker(modulespath, systemmodulespath, namebuf, 
  194.                                spec, header))
  195.     {    
  196.         if (header->gk_type == GK_TYPE_ROM_2 || *had_rom_segment)
  197.         {
  198.             // assume so... we go backwards through the types,
  199.             // so we could see #2 before #1
  200.             *is_banked = true;
  201.             *had_rom_segment = true;
  202.         }
  203.  
  204.         // note the extra space, this is to patch the string later
  205.         *cmdptr = appendstr(*cmdptr, "; DefineMemory \"RM%s\"  0x%04x 0x%04x "
  206.                            "\"%s\" %d \"GRAM Kracker segment type %d\"",
  207.                            header->gk_type == GK_TYPE_ROM_1 ? 
  208.                             (*is_banked ? "C1" : "C") :
  209.                             header->gk_type == GK_TYPE_ROM_2 ? "C2" 
  210.                             : "G",
  211.                            header->address,
  212.                            header->length,
  213.                            namebuf, 
  214.                            header->absolute_image_file_offset,
  215.                            header->gk_type);
  216.         return true;
  217.     }
  218.     else
  219.     {
  220.         return false;
  221.     }
  222. }
  223.  
  224. /*
  225.  *    Search for the pieces of a GRAM Kracker file.
  226.  *
  227.  *    "cmdptr" is a pointer to a string filled in with commands used
  228.  *        to load the module later.
  229.  *    "base" is the base filename for all the GRAM kracker files.
  230.  *        This may be "foo" where "foo", "foo1", "foo2", ... exist,
  231.  *        or "foo%dbar" where %d is replaced with ""/"0"/"1", "2", ...
  232.  */
  233. static char *
  234. module_lookup_gram_kracker(char *cmdptr, const char *base)
  235. {
  236.     char *orig = cmdptr;
  237.     char namebuf[OS_NAMESIZE];
  238.     OSSpec spec;
  239.     int part;
  240.     gram_kracker_header header;
  241.     bool had_rom_segment = false, is_banked = false;
  242.  
  243.     const char *percent, *comma;
  244.  
  245.     /* assume 'base' is a printf-style pattern wherein we
  246.        can substitute 'part'. */
  247.     percent = strstr(base, "%d");
  248.     if (percent) {
  249.         if (strstr(percent+1, "%d")) {
  250.             logger(LOG_ERROR|LOG_USER, 
  251.                    "GRAMKRACKER base filename should have at most one '%%d' (got '%s')\n",
  252.                    base);
  253.             return 0L;
  254.         }
  255.     }
  256.  
  257.     /* or, if 'base' has commas in it, we take these to be the actual names */
  258.     comma = strchr(base, ',');
  259.     if (comma && percent) {
  260.         logger(_L|LOG_ERROR|LOG_USER, 
  261.                "GRAMKRACKER base filename cannot have both a ',' and '%' (got '%s')\n",
  262.                base);
  263.         return 0L;
  264.     }
  265.  
  266.     /* given a list of files? */
  267.     if (comma) {
  268.         const char *start = base;
  269.         bool got_any = false;
  270.         do
  271.         {
  272.             strncpy(namebuf, start, comma - start);
  273.             namebuf[comma - start] = 0;
  274.  
  275.             if (module_find_gram_kracker_segment(namebuf, &spec, &header,
  276.                                                  &had_rom_segment, &is_banked,
  277.                                                  &cmdptr))
  278.             {
  279.                 got_any = true;
  280.  
  281.                 // no, the user may be loading them out of order
  282. //                if (!header.more_to_load) {
  283. //                    return cmdptr;
  284. //                }
  285.             }
  286.             else
  287.             {
  288.                 logger(_L|LOG_ERROR|LOG_USER, "Could not find GRAM Kracker segment '%s' (in '%s')\n",
  289.                        namebuf, base);
  290.  
  291.                 if (!got_any) 
  292.                     return 0L;
  293.             }
  294.  
  295.             if (!*comma)
  296.                 break;
  297.             start = comma + 1;
  298.             comma = strchr(start, ',');
  299.             if (!comma)    
  300.                 comma = start + strlen(start);
  301.         } while (1);
  302.  
  303.         return cmdptr;
  304.     }
  305.  
  306.     /* iterate 0 through n finding these files named
  307.              say, 'base', 'base2', ... or
  308.             'base0', 'base1', ... or
  309.             'base1', 'base2' */
  310.     else {
  311.         for (part = -1; part < 10; part++) {
  312.             if (part >= 0)
  313.                 if (percent) 
  314.                     snprintf(namebuf, sizeof(namebuf), base, part);
  315.                 else {
  316.                     // if there's no '%d', append number to end
  317.                     strncpy(namebuf, base, sizeof(namebuf));
  318.                     snprintf(namebuf + strlen(namebuf), 
  319.                              sizeof(namebuf) - strlen(namebuf),
  320.                              "%d", part);
  321.                 }
  322.             else {
  323.                 // remove '%d' for the -1 iteration ('base%d' -> 'base')
  324.                 if (percent) {
  325.                     strcpy(namebuf, base);
  326.                     memmove((char *)((percent - base) + namebuf), 
  327.                             ((percent - base) + namebuf + 2), 
  328.                             strlen(percent + 2) + 1);
  329.                 } else {
  330.                     strcpy(namebuf, base);
  331.                 }
  332.             }
  333.  
  334. //            g_print("namebuf=%s\n", namebuf);
  335.             if (module_find_gram_kracker_segment(namebuf, &spec, &header,
  336.                                                  &had_rom_segment, &is_banked,
  337.                                                  &cmdptr))
  338.             {
  339.                 if (!header.more_to_load)
  340.                     return cmdptr;
  341.             }
  342.             else if (part > 1)
  343.             {
  344.                 logger(_L|LOG_USER|LOG_ERROR, "Could not find expected remaining GRAM Kracker segments\n"
  345.                        "numbered starting at %d", part);
  346.                 return cmdptr;
  347.             }
  348.             else if (part == 1 && orig == cmdptr)
  349.             {
  350.                 logger(_L|LOG_USER|LOG_ERROR, "Could not find first segment of GRAM Kracker file with base '%s'\n",
  351.                        base);
  352.                 return 0L;
  353.             }    
  354.         }
  355.         return cmdptr;
  356.     }
  357. }
  358.  
  359. static
  360. DECL_SYMBOL_ACTION(module_define_entry)
  361. {
  362.     char       *tag, *name, *base;
  363.     int         parts;
  364.     char        *cmdptr = 0L, *retstr;
  365.     int            ret;
  366.  
  367.     command_arg_get_string(SYM_ARG_1st, &tag);
  368.     command_arg_get_string(SYM_ARG_2nd, &name);
  369.     command_arg_get_string(SYM_ARG_3rd, &base);
  370.     command_arg_get_num(SYM_ARG_4th, &parts);
  371.  
  372.     /* Define commands that will load this module */
  373.  
  374.     cmdptr = appendstr(cmdptr, "UnloadModuleOnly");
  375.  
  376.     if (parts & MOD_PART_GRAMKRACKER) {
  377.         /* Do the work to find all the parts */
  378.  
  379.         retstr = module_lookup_gram_kracker(cmdptr, base);
  380.         if (!retstr) {
  381.             xfree(cmdptr);
  382.             return 0;
  383.         }
  384.         cmdptr = retstr;
  385.     }
  386.  
  387.     if (parts & MOD_PART_GROM) {
  388.         cmdptr = appendstr(cmdptr, "; DefineMemory \"RMG\" 0x6000 0x0000 "
  389.                           "\"%sg.bin\" 0x0 \"GROM for %s\"",
  390.                           base, name);
  391.     }
  392.  
  393.     if (parts & MOD_PART_BANKED) {
  394.         cmdptr = appendstr(cmdptr, "; DefineMemory \"RM1C\" 0x6000 0x2000 "
  395.                           "\"%sc.bin\" 0x0 \"Bank 1 for %s\"",
  396.                       base, name);
  397.  
  398.         cmdptr = appendstr(cmdptr, "; DefineMemory \"RM2C\" 0x6000 0x2000 "
  399.                           "\"%sd.bin\" 0x0 \"Bank 2 for %s\"",
  400.                           base, name);
  401.  
  402.     } else if (parts & MOD_PART_ROM) {
  403.         cmdptr = appendstr(cmdptr, "; DefineMemory \"RMC\" 0x6000 0x2000 "
  404.                           "\"%sc.bin\" 0x0 \"ROM for %s\"",
  405.                       base, name);
  406.     }
  407.  
  408.     if (parts & MOD_PART_MINIMEM) {
  409.         cmdptr = appendstr(cmdptr, "; DefineMemory \"SMC\" 0x7000 0x1000 "
  410.                           "\"%sr.bin\" 0x0 \"Mini-Memory RAM for %s\"",
  411.                           base, name);
  412.     }
  413.  
  414.     ret = module_change_entry(tag, name, base, cmdptr);
  415.     xfree(cmdptr);
  416.  
  417.     return ret;
  418. }
  419.  
  420. static
  421. DECL_SYMBOL_ACTION(module_define_entry_memory)
  422. {
  423.     char       *tag, *name, *base;
  424.     char        *commands;
  425.  
  426.     command_arg_get_string(SYM_ARG_1st, &tag);
  427.     command_arg_get_string(SYM_ARG_2nd, &name);
  428.     command_arg_get_string(SYM_ARG_3rd, &base);
  429.     command_arg_get_string(SYM_ARG_4th, &commands);
  430.  
  431.     return module_change_entry(tag, name, base, commands);
  432. }
  433.  
  434. static
  435. DECL_SYMBOL_ACTION(modules_list_db)
  436. {
  437.     ModuleEntry *lst = moddb;
  438.  
  439.     logger(LOG_USER, "List of installed modules:");
  440.     while (lst) {
  441.         logger(LOG_USER, "Tag: '%s', Name: '%s'\n", lst->tag, lst->name);
  442.         logger(LOG_USER, "\tCommands:  '%s'\n", lst->commands);
  443.         lst = lst->next;
  444.     }
  445.     return 1;
  446. }
  447.  
  448. static
  449. DECL_SYMBOL_ACTION(modules_clear_db)
  450. {
  451.     loaded_module = NULL;
  452.     modules_free_db();
  453.     return 1;
  454. }
  455.  
  456. int module_load(ModuleEntry *ent)
  457. {
  458.     int ret;
  459.     my_assert(ent->commands);
  460.     logger(_L | LOG_USER, "Loading module '%s'\n", ent->name);
  461.     logger(_L | L_1, "\t%s", ent->commands);
  462.     ret = command_parse_text(ent->commands);
  463.     if (ret) loaded_module = ent;
  464.     return ret;
  465. }
  466.  
  467. static
  468. DECL_SYMBOL_ACTION(load_module_by_name)
  469. {
  470.     ModuleEntry *ent;
  471.     char       *str;
  472.  
  473.     if (task == csa_READ) {  
  474.         if (!iter && loaded_module) {
  475.             command_arg_set_string(sym->args, loaded_module->name);
  476.             return 1;
  477.         }
  478.         return 0;
  479.     }
  480.  
  481.     command_arg_get_string(sym->args, &str);
  482.     if (!str || !*str)
  483.     {
  484.         module_unload_entries();
  485.         return 1;
  486.     }
  487.  
  488.     ent = modules_find_tag_in_db(str);
  489.     if (ent == NULL)
  490.         ent = modules_search_str_in_db(str);
  491.  
  492.     if (ent == NULL) {
  493.         logger(_L | LOG_ERROR | LOG_USER, "No module matches '%s'\n", str);
  494.         return 0;
  495.     }
  496.  
  497.     return module_load(ent);
  498. }
  499.  
  500. static
  501. DECL_SYMBOL_ACTION(load_module_by_name_and_reset)
  502. {
  503.     if (load_module_by_name(sym, task, 0))
  504.         return command_parse_text("Reset\n");
  505.     else
  506.         return 0;
  507. }
  508.  
  509. static
  510. DECL_SYMBOL_ACTION(module_unload)
  511. {
  512.     return module_unload_entries();
  513. }
  514.  
  515. static
  516. DECL_SYMBOL_ACTION(module_unload_and_reset)
  517. {
  518.     if (module_unload_entries())
  519.         return command_parse_text("Reset\n");
  520.     else
  521.         return 0;
  522. }
  523.  
  524.  
  525. static
  526. DECL_SYMBOL_ACTION(do_memory_ram_init)
  527. {
  528.     memory_ram_init();
  529.     return 1;
  530. }
  531.  
  532. static
  533. DECL_SYMBOL_ACTION(do_memory_complete_load)
  534. {
  535.     return memory_complete_load();
  536. }
  537.  
  538. static
  539. DECL_SYMBOL_ACTION(do_memory_volatile_load)
  540. {
  541.     return memory_volatile_load();
  542. }
  543.  
  544. static
  545. DECL_SYMBOL_ACTION(do_memory_volatile_save)
  546. {
  547.     memory_volatile_save();
  548.     return 1;
  549. }
  550.  
  551. static
  552. DECL_SYMBOL_ACTION(module_define_console_rom)
  553. {
  554.     char cmdbuf[1024];
  555.     char *fname;
  556.     command_arg_get_string(SYM_ARG_1st, &fname);
  557.     if (!fname || !*fname)
  558.         return 1;
  559.     sprintf(cmdbuf, "DefineMemory \"RC\" 0x0000 -0x2000 \"%s\" 0x0 \"Console ROM\"\n", fname);
  560.     return command_parse_text(cmdbuf);
  561. }
  562.  
  563. static
  564. DECL_SYMBOL_ACTION(module_define_console_grom)
  565. {
  566.     char cmdbuf[1024];
  567.     char *fname;
  568.     command_arg_get_string(SYM_ARG_1st, &fname);
  569.     if (!fname || !*fname)
  570.         return 1;
  571.     sprintf(cmdbuf, "DefineMemory \"RG\" 0x0000 -0x6000 \"%s\" 0x0 \"Console GROM\"\n", fname);
  572.     return command_parse_text(cmdbuf);
  573. }
  574.  
  575. static
  576. DECL_SYMBOL_ACTION(module_define_module_grom)
  577. {
  578.     char cmdbuf[1024];
  579.     char *fname;
  580.  
  581.     if (task == csa_READ) {
  582.         command_arg_get_string(SYM_ARG_1st, &fname);
  583.         if (!fname || !*fname)
  584.             return 0;
  585.         else 
  586.             return (iter == 0);
  587.     }
  588.  
  589.     command_arg_get_string(SYM_ARG_1st, &fname);
  590.     if (!fname || !*fname) {
  591.         module_unload_entry(MEMENT_GRAPHICS);
  592.         return 1;
  593.     }
  594.     sprintf(cmdbuf, "DefineMemory \"RMG\" 0x6000 -0xA000 \"%s\" 0x0 \"Module GROM\"\n", fname);
  595.     loaded_module = NULL;
  596.     return command_parse_text(cmdbuf);
  597. }
  598.  
  599. static
  600. DECL_SYMBOL_ACTION(module_define_module_rom)
  601. {
  602.     char cmdbuf[1024];
  603.     char *fname;
  604.  
  605.     if (task == csa_READ) {
  606.         command_arg_get_string(SYM_ARG_1st, &fname);
  607.         if (!fname || !*fname)
  608.             return 0;
  609.         else 
  610.             return (iter == 0);
  611.     }
  612.  
  613.     command_arg_get_string(SYM_ARG_1st, &fname);
  614.     if (!fname || !*fname) {
  615.         module_unload_entry(MEMENT_CONSOLE);
  616.         return 1;
  617.     }
  618.     sprintf(cmdbuf, "DefineMemory \"RMC\" 0x6000 -0x2000 \"%s\" 0x0 \"Module ROM\"\n", fname);
  619.     loaded_module = NULL;
  620.     return command_parse_text(cmdbuf);
  621. }
  622.  
  623. static
  624. DECL_SYMBOL_ACTION(module_define_module_rom_1)
  625. {
  626.     char cmdbuf[1024];
  627.     char *fname;
  628.  
  629.     if (task == csa_READ) {
  630.         command_arg_get_string(SYM_ARG_1st, &fname);
  631.         if (!fname || !*fname)
  632.             return 0;
  633.         else 
  634.             return (iter == 0);
  635.     }
  636.  
  637.     command_arg_get_string(SYM_ARG_1st, &fname);
  638.     if (!fname || !*fname) {
  639.         module_unload_entry(MEMENT_BANK_1 | MEMENT_CONSOLE);
  640.         return 1;
  641.     }
  642.     sprintf(cmdbuf, "DefineMemory \"RM1C\" 0x6000 -0x2000 \"%s\" 0x0 \"Module ROM bank 1\"\n", fname);
  643.     loaded_module = NULL;
  644.     return command_parse_text(cmdbuf);
  645. }
  646.  
  647. static
  648. DECL_SYMBOL_ACTION(module_define_module_rom_2)
  649. {
  650.     char cmdbuf[1024];
  651.     char *fname;
  652.  
  653.     if (task == csa_READ) {
  654.         command_arg_get_string(SYM_ARG_1st, &fname);
  655.         if (!fname || !*fname)
  656.             return 0;
  657.         else 
  658.             return (iter == 0);
  659.     }
  660.  
  661.     command_arg_get_string(SYM_ARG_1st, &fname);
  662.     if (!fname || !*fname) {
  663.         module_unload_entry(MEMENT_BANK_2 | MEMENT_CONSOLE);
  664.         return 1;
  665.     }
  666.     sprintf(cmdbuf, "DefineMemory \"RM2C\" 0x6000 -0x2000 \"%s\" 0x0 \"Module ROM bank 2\"\n", fname);
  667.     loaded_module = NULL;
  668.     return command_parse_text(cmdbuf);
  669. }
  670.  
  671. static
  672. DECL_SYMBOL_ACTION(module_set_module_bank)
  673. {
  674.     int val;
  675.     command_arg_get_num(SYM_ARG_1st, &val);
  676.     if (val < 0 || val > 1) {
  677.         logger(_L|LOG_ERROR|LOG_USER, "memory bank must be 0 or 1 (got %d)\n", val);
  678.         return 0;
  679.     }
  680.     memory_set_module_bank(val);
  681.     return 1;
  682. }
  683.  
  684. int
  685. modules_init(void)
  686. {
  687.     command_symbol_table *modulecommands =
  688.         command_symbol_table_new("Memory Map / ROM / RAM / Module Options",
  689.                                  "These are commands for dealing with the layout of memory in the virtual 99/4A",
  690.  
  691.       command_symbol_new
  692.          ("ModulesPath",
  693.           "Set initial directory list to search for module ROM images",
  694.           c_STATIC|c_SESSION_ONLY,
  695.           NULL /* action*/,
  696.           RET_FIRST_ARG,
  697.           command_arg_new_string
  698.             ("path",
  699.              "list of directories "
  700.              "separated by one of these characters: '"
  701.              OS_ENVSEPLIST "'",
  702.              NULL    /* action */,
  703.              NEW_ARG_STRBUF(&modulespath),
  704.              NULL /* next */ )
  705.           ,
  706.  
  707.       command_symbol_new
  708.          ("SystemModulesPath",
  709.           "Set secondary directory list to search for module ROM images",
  710.           c_STATIC|c_CONFIG_ONLY,
  711.           NULL /* action*/,
  712.           RET_FIRST_ARG,
  713.           command_arg_new_string
  714.             ("path",
  715.              "list of directories "
  716.              "separated by one of these characters: '"
  717.              OS_ENVSEPLIST "'",
  718.              NULL    /* action */,
  719.              NEW_ARG_STRBUF(&systemmodulespath),
  720.              NULL /* next */ )
  721.           ,
  722.  
  723.       command_symbol_new
  724.          ("ROMSPath",
  725.           "Set initial directory list to search for console ROM and GROM images",
  726.           c_STATIC|c_SESSION_ONLY,
  727.           NULL /* action*/,
  728.           RET_FIRST_ARG,
  729.           command_arg_new_string
  730.             ("path",
  731.              "list of directories "
  732.              "separated by one of these characters: '"
  733.              OS_ENVSEPLIST
  734.              "'",
  735.              NULL    /* action */,
  736.              NEW_ARG_STRBUF(&romspath),
  737.              NULL /* next */ )
  738.           ,
  739.  
  740.       command_symbol_new
  741.          ("SystemROMSPath",
  742.           "Set secondary directory list to search for console ROM and GROM images",
  743.           c_STATIC|c_CONFIG_ONLY,
  744.           NULL /* action*/,
  745.           RET_FIRST_ARG,
  746.           command_arg_new_string
  747.             ("path",
  748.              "list of directories "
  749.              "separated by one of these characters: '"
  750.              OS_ENVSEPLIST
  751.              "'",
  752.              NULL    /* action */,
  753.              NEW_ARG_STRBUF(&systemromspath),
  754.              NULL /* next */ )
  755.           ,
  756.  
  757.       command_symbol_new
  758.          ("RAMSPath",
  759.           "Set initial directory list to search for nonvolatile RAM images",
  760.           c_STATIC|c_SESSION_ONLY,
  761.           NULL /* action*/,
  762.           RET_FIRST_ARG,
  763.           command_arg_new_string
  764.             ("path",
  765.              "list of directories "
  766.              "separated by one of these characters: '"
  767.              OS_ENVSEPLIST
  768.              "'",
  769.              NULL    /* action */,
  770.              NEW_ARG_STRBUF(&ramspath),
  771.              NULL /* next */ )
  772.           ,
  773.       command_symbol_new
  774.          ("SystemRAMSPath",
  775.           "Set secondary directory list to search for nonvolatile RAM images",
  776.           c_STATIC|c_CONFIG_ONLY,
  777.           NULL /* action*/,
  778.           RET_FIRST_ARG,
  779.           command_arg_new_string
  780.             ("path",
  781.              "list of directories "
  782.              "separated by one of these characters: '"
  783.              OS_ENVSEPLIST
  784.              "'",
  785.              NULL    /* action */,
  786.              NEW_ARG_STRBUF(&systemramspath),
  787.              NULL /* next */ )
  788.           ,
  789.  
  790.       command_symbol_new
  791.         ("DefineMemory",
  792.          "Specify existence of a memory area",
  793.          c_DYNAMIC|c_SESSION_ONLY,
  794.          memory_define_entry    /* action */,
  795.          NULL /* ret */,
  796.          command_arg_new_string
  797.            ("flags",
  798.             "string of characters defining memory characteristics:\n"
  799.             "first, 'R' for ROM, 'W' for RAM, and 'S' for stored RAM;\n"
  800.             "then, 'M' for a module, or nothing;\n"
  801.             "then, '1' or '2' for banks of a banked module;\n"
  802.             "then, one of 'C'onsole, 'G'raphics, 'V'ideo, 'S'peech, 'D'SR",
  803.             NULL /* action */,
  804.             NEW_ARG_STR(32),
  805.  
  806.          command_arg_new_num
  807.            ("address",
  808.             "starting address of image, should start on a >2000 boundary",
  809.             NULL /* action */,
  810.             NEW_ARG_NUM(u16),
  811.          command_arg_new_num
  812.             ("size",
  813.              "size of ROM, should be a multiple of >2000; "
  814.              "except for 0, which indicates an unknown size, "
  815.              "and a negative number, which indicates the magnitude of the maximum size allowed",
  816.              NULL /* action */,
  817.              NEW_ARG_NUM(u32),
  818.          command_arg_new_string
  819.            ("file",
  820.             "name of binary image to load and/or store, "
  821.             "searched in the ROMSPath or ModulesPath; "
  822.             "if blank, memory is read as zeroes",
  823.             NULL /* action */ ,
  824.             NEW_ARG_NEW_STRBUF,
  825.          command_arg_new_num
  826.            ("offset",
  827.             "byte offset of image, if stored in larger file",
  828.             NULL /* action */,
  829.             NEW_ARG_NUM(u32),
  830.          command_arg_new_string
  831.            ("name",
  832.             "text name of memory area",
  833.             NULL /* action */ ,
  834.             NEW_ARG_NEW_STRBUF,
  835.             NULL    /* next */))))))
  836.      ,
  837.  
  838.       command_symbol_new
  839.         ("DefaultMemoryMap",
  840.          "Setup defaults for a 99/4A memory map",
  841.          c_DONT_SAVE,
  842.          memory_default_list /* action */ ,
  843.          NULL /* ret */,
  844.          NULL /* args */
  845.      ,    
  846.          
  847.       command_symbol_new
  848.         ("MemoryExpansion32K",
  849.          "Use 32K expansion memory (may be overridden by a DefineRAM command)",
  850.          c_STATIC,
  851.          do_memory_ram_init /* action */ ,
  852.          RET_FIRST_ARG,
  853.          command_arg_new_num
  854.             ("on|off", "toggle",
  855.              NULL /* action */ ,
  856.              ARG_NUM(isexpram),
  857.              NULL /* next */ )
  858.          ,    
  859.  
  860.       command_symbol_new
  861.            ("ExtraConsoleRAM",
  862.             "Set up >8000->82FF range as real RAM (like in the Geneve) "
  863.             "instead of mirroring >8300->83FF (the default)",
  864.             c_STATIC,
  865.             do_memory_ram_init /* action */ ,
  866.             RET_FIRST_ARG,
  867.             command_arg_new_num
  868.               ("on|off", "toggle",
  869.                NULL /* action */ ,
  870.                ARG_NUM(isenhconsoleram),
  871.                NULL /* next */ )
  872.         ,
  873.  
  874.       command_symbol_new
  875.           ("ConsoleROMFileName",
  876.            "Name of console ROM which starts at address >0000",
  877.            c_DONT_SAVE/*|c_SESSION_ONLY*/,
  878.            module_define_console_rom /* action */,
  879.            RET_FIRST_ARG,
  880.            command_arg_new_string
  881.              ("file",
  882.               "name of binary image",
  883.               NULL /* action */ ,
  884.               NEW_ARG_NEW_STRBUF,
  885.               NULL    /* next */)
  886.        ,
  887.  
  888.       command_symbol_new
  889.           ("ConsoleGROMFileName",
  890.            "Name of console GROM which starts at address G>0000",
  891.            c_DONT_SAVE/*|c_SESSION_ONLY*/,
  892.            module_define_console_grom /* action */,
  893.            RET_FIRST_ARG,
  894.            command_arg_new_string
  895.              ("file",
  896.               "name of binary image",
  897.               NULL  /* action */ ,
  898.               NEW_ARG_NEW_STRBUF,
  899.               NULL    /* next */ )
  900.        ,
  901.  
  902.       command_symbol_new
  903.           ("ModuleGROMFileName",
  904.            "Name of module GROM which starts at address G>6000",
  905.            c_DYNAMIC|c_DONT_SAVE /*c_SESSION_ONLY*/,
  906.            module_define_module_grom /* action */,
  907.            RET_FIRST_ARG,
  908.            command_arg_new_string
  909.              ("file",
  910.               "name of binary image",
  911.               NULL  /* action */ ,
  912.               NEW_ARG_NEW_STRBUF,
  913.               NULL    /* next */ )
  914.        ,
  915.  
  916.       command_symbol_new
  917.           ("ModuleROMFileName|ModuleROM",
  918.            "Name of module ROM (non-banked) which starts at CPU address >6000",
  919.            c_DYNAMIC|c_DONT_SAVE /*SESSION_ONLY*/,
  920.            module_define_module_rom  /* action */ ,
  921.            RET_FIRST_ARG,
  922.            command_arg_new_string
  923.              ("file",
  924.               "name of binary image",
  925.               NULL /* action */,
  926.              NEW_ARG_NEW_STRBUF,
  927.              NULL /* next */ )
  928.        ,
  929.  
  930.       command_symbol_new
  931.           ("ModuleROM1FileName|ModuleROM1",
  932.            "Name of module ROM (first bank) which starts at CPU address >6000",
  933.            c_DYNAMIC|c_DONT_SAVE /*c_SESSION_ONLY*/,
  934.            module_define_module_rom_1  /* action */ ,
  935.            RET_FIRST_ARG,
  936.            command_arg_new_string
  937.              ("file",
  938.               "name of binary image",
  939.               NULL /* action */,
  940.              NEW_ARG_NEW_STRBUF,
  941.              NULL /* next */ )
  942.        ,
  943.  
  944.       command_symbol_new
  945.           ("ModuleROMBank2FileName|ModuleROM2FileName",
  946.            "Name of module ROM (second bank) which starts at CPU address >6000",
  947.            c_DYNAMIC|c_DONT_SAVE /*c_SESSION_ONLY*/,
  948.            module_define_module_rom_2 /* action */,
  949.            RET_FIRST_ARG,
  950.            command_arg_new_string
  951.              ("file",
  952.               "name of binary image",
  953.               NULL  /* action */,
  954.               NEW_ARG_NEW_STRBUF,
  955.               NULL /* next */)
  956.        ,
  957.  
  958.       command_symbol_new
  959.           ("LoadAllMemory",
  960.            "Load all memory images (ROMs and RAMs) into the emulator",
  961.            c_DONT_SAVE,
  962.            do_memory_complete_load,
  963.            NULL  /* ret */ ,
  964.            NULL    /* args */
  965.        ,
  966.  
  967.       command_symbol_new
  968.           ("LoadMemory",
  969.            "Load the volatile memory images (RAMs) into the emulator",
  970.            c_DONT_SAVE,
  971.            do_memory_volatile_load,
  972.            NULL  /* ret */ ,
  973.            NULL    /* args */
  974.        ,
  975.  
  976.       command_symbol_new
  977.           ("SaveMemory",
  978.            "Save the volatile memory images (RAMs) to disk",
  979.            c_DONT_SAVE,
  980.            do_memory_volatile_save,
  981.            NULL  /* ret */ ,
  982.            NULL    /* args */
  983.        ,
  984.  
  985.       command_symbol_new
  986.             ("ListMemory",
  987.              "List memory map",
  988.              c_DONT_SAVE,
  989.              memory_dump,
  990.              NULL /* ret */ ,
  991.              NULL    /* args */
  992.        ,
  993.  
  994.       command_symbol_new
  995.            ("DefineModule",
  996.             "Define or redefine a standard module/cartridge in the database",
  997.             c_DONT_SAVE,
  998.             module_define_entry,
  999.             NULL /* ret */ ,
  1000.             command_arg_new_string
  1001.                  ("tag",
  1002.                  "short tag for easy reference",
  1003.                  NULL /* action */ ,
  1004.                  NEW_ARG_STR(5),
  1005.             command_arg_new_string
  1006.                  ("name",
  1007.                   "full name of module",
  1008.                   NULL /* action */ ,
  1009.                   NEW_ARG_STR(64),
  1010.             command_arg_new_string
  1011.                   ("base",
  1012.                    "base of module file name",
  1013.                    NULL /* action */ ,
  1014.                    NEW_ARG_STR(64),
  1015.             command_arg_new_num
  1016.                    ("parts",
  1017.                     "sections present (one or more "
  1018.                         "of GROM, ROM, BANKED, MINIMEM)",
  1019.                     NULL /* action */ ,
  1020.                     NEW_ARG_NUM(long),
  1021.                     NULL /* next */ ))))
  1022.             ,
  1023.  
  1024.       command_symbol_new
  1025.            ("DefineModuleMemory",
  1026.             "Define or redefine a module/cartridge in the database, "
  1027.             "giving commands to define its memory configuration",
  1028.             c_DONT_SAVE,
  1029.             module_define_entry_memory,
  1030.             NULL /* ret */,
  1031.             command_arg_new_string
  1032.                 ("tag",
  1033.                  "short tag for easy reference",
  1034.                  NULL /* action */ ,
  1035.                  NEW_ARG_STR(5),
  1036.             command_arg_new_string
  1037.                  ("name",
  1038.                   "full name of module",
  1039.                   NULL /* action */ ,
  1040.                   NEW_ARG_STR(64),
  1041.             command_arg_new_string
  1042.                   ("base",
  1043.                    "base of module file name",
  1044.                    NULL /* action */ ,
  1045.                    NEW_ARG_STR(64),
  1046.             command_arg_new_string
  1047.                    ("commands",
  1048.                     "commands used to define module memory map, e.g., "
  1049.                     "'DefineMemory \"RWMC\" 0x6000 0x2000 \"module_rom.bin\" 0x0 \"Module ROM file\"; "
  1050.                     "DefineMemory \"RMG\" 0x6000 0x6000 \"module_grom.bin\" 0x0 \"Module GRAM file\"'",
  1051.                     NULL /* action */ ,
  1052.                     NEW_ARG_NEW_STRBUF,
  1053.                     NULL /* next */ ))))
  1054.             ,
  1055.  
  1056.       command_symbol_new
  1057.             ("ListModules",
  1058.              "List modules in database",
  1059.              c_DONT_SAVE,
  1060.              modules_list_db,
  1061.              NULL /* ret */ ,
  1062.              NULL /* args */
  1063.        ,
  1064.  
  1065.       command_symbol_new
  1066.             ("InitModuleDatabase",
  1067.              "Initialize current module list to empty "
  1068.              "(use 'ReadModuleDatabase <file>' or LoadConfigFile <file>' "
  1069.              "to add entries)",
  1070.              c_DONT_SAVE,
  1071.              modules_clear_db,
  1072.              NULL /* ret */ ,
  1073.              NULL /* args */
  1074.        ,
  1075.  
  1076.       command_symbol_new
  1077.              ("UnloadModule",
  1078.               "Unload currently loaded module(s) and reset",
  1079.               c_DONT_SAVE,
  1080.               module_unload_and_reset,
  1081.               NULL /* ret */,
  1082.               NULL /* args */
  1083.        ,
  1084.  
  1085.       command_symbol_new
  1086.              ("UnloadModuleOnly",
  1087.               "Unload currently loaded module(s) but do not reset",
  1088.               c_DONT_SAVE,
  1089.               module_unload,
  1090.               NULL /* ret */,
  1091.               NULL /* args */
  1092.        ,
  1093.  
  1094.       command_symbol_new
  1095.              ("LoadModule",
  1096.               "Load a module by tag or name",
  1097.               c_DONT_SAVE,
  1098.               load_module_by_name_and_reset,
  1099.               NULL /* ret */ ,
  1100.               command_arg_new_string
  1101.                   ("tag|name",
  1102.                   "tag or title substring",
  1103.                   NULL /* action */ ,
  1104.                   NEW_ARG_STR(64),
  1105.                    NULL /* next */ )
  1106.       ,
  1107.  
  1108.       command_symbol_new
  1109.               ("ReplaceModule",
  1110.                "Replace current module but do not reset computer",
  1111.                c_DYNAMIC|c_SESSION_ONLY,
  1112.                load_module_by_name,
  1113.                NULL /* ret */ ,
  1114.                command_arg_new_string
  1115.                    ("tag|name",
  1116.                     "tag or title substring",
  1117.                     NULL /* action */ ,
  1118.                     NEW_ARG_STR(64),
  1119.                     NULL /* next */ )
  1120.       ,
  1121.  
  1122.       command_symbol_new
  1123.               ("ChangeModuleBank",
  1124.                "Change active ROM bank of module (only applies to banked modules)",
  1125.                c_STATIC|c_SESSION_ONLY,
  1126.                module_set_module_bank,
  1127.                RET_FIRST_ARG /* ret */ ,
  1128.                command_arg_new_num
  1129.                    ("bank",
  1130.                     "0 or 1",
  1131.                     NULL /* action */ ,
  1132.                     ARG_NUM(memory_module_bank),
  1133.                     NULL /* next */ )
  1134.       ,
  1135.  
  1136.       NULL /* next */ ))))))))))))))))))))))))))))),
  1137.  
  1138.       NULL /* sub */ ,
  1139.  
  1140.       NULL    /* next */
  1141. );
  1142.  
  1143.     command_symbol_table_add_subtable(universe, modulecommands);
  1144.  
  1145.     modulespath = xstrdup(OS_CWDSTR);
  1146.     ramspath = xstrdup(OS_CWDSTR);
  1147.     romspath = xstrdup(OS_CWDSTR);
  1148.  
  1149.     return 1;
  1150. }
  1151.