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

  1.  
  2. /*
  3.         MEMORY.C
  4.         ========
  5.         
  6.         Functions to read/write CPU memory.
  7. */
  8.  
  9. #include <stdio.h>
  10. #include <unistd.h>
  11.  
  12. #include "v9t9_common.h"
  13. #include "roms.h"
  14. #include "memory.h"
  15. #include "vdp.h"
  16. #include "grom.h"
  17. #include "speech.h"
  18. #include "sound.h"
  19.  
  20. #define _L    LOG_MEMORY | LOG_INFO
  21.  
  22. int         isexpram;        /* is there expansion RAM? */
  23. int         isenhconsoleram;    /* is >8000 - >82FF real RAM? */
  24.  
  25. /**********************************************/
  26.  
  27. /*    Physical memory array, used for static ROM and RAM.
  28.     Area handlers may point to other areas of memory,
  29.     to handle things like bank-switching. */
  30.  
  31. //u8          physmemory[PHYSMEMORYSIZE];
  32.  
  33.  
  34. /*
  35.     Below we define a table of mrstructs which map CPU addresses to 
  36.     areas of memory, including means of dealing with special memory
  37.     types through the use of read/write functions.
  38.  
  39.     It is advantageous to store memory in the
  40.     areamemory/arearead/areawrite pointers and let the MEMORY_xxx or
  41.     memory_xxx routines access it directly, for speed purposes, but
  42.     for some memory-mapped areas it is saner to have a routine manage
  43.     reads and writes to the memory.  You must use a memory handling
  44.     routine when:
  45.  
  46.         (1) word accesses are not the same as two simultaneous byte accesses 
  47.         (2) reading memory and writing memory are not orthogonal, i.e.,
  48.         writing/reading memory has side effects (memory-mapped)
  49.         
  50.     If the contents of memory are bank-switched or toggled on and off
  51.     (such as the DSR), it's most speed efficient to change handlers to
  52.     remap the contents (through changing the arearead and areawrite
  53.     pointers) rather than copying contents in and out of a static
  54.     areamemory.
  55.  
  56.     The emulator will make no assumptions about the semantics of
  57.     memory which has read or write routines attached to an area.  */
  58.  
  59. /*
  60.     Area handlers are the main gateway to the memory bus.  Each
  61.     AREASIZE section of memory has various properties which define how
  62.     to read from and write to it.  mrstruct->areamemory contains the
  63.     memory for the area.  Pure RAM will have mrstruct->arearead and
  64.     mrstruct->areawrite be set to this.  Memory mapped I/O areas or
  65.     ROM will leave one or both of the arearead or areawrite pointers
  66.     NULL and instead define a routine, {read|write}_{byte|word} to
  67.     handle the access to areamemory.
  68.  
  69.     Note, that while the arearead or areawrite pointers points to an
  70.     AREASIZE sized block, the read/write byte/word routines are always
  71.     passed a full 16-bit address.  This allows a common function to
  72.     control access to several contiguous areas.
  73. */
  74. mrstruct    __areahandlers[NUMDOMAINS][NUMAREAS];
  75.  
  76. void        set_area_handler(mem_domain md, u16 addr, u32 size, mrstruct * handler)
  77. {
  78.     mrstruct    tmp = *handler;
  79.  
  80.     if ((size < AREASIZE) || (addr & (AREASIZE - 1)))
  81.         logger(_L | LOG_FATAL,
  82.              "set_area_handler:  attempt made to set a memory handler on an illegal boundary\n"
  83.              "(0x%04X...0x%04X), the minimum granularity is %d bytes\n", addr,
  84.              addr + size - 1, AREASIZE);
  85.  
  86.     if (handler->arearead == NULL &&
  87.         handler->read_byte == NULL && handler->read_word != NULL)
  88.         logger(_L | LOG_FATAL,
  89.              "set_area_handler:  cannot have a handler define read_word without read_byte\n");
  90.     if (handler->areawrite == NULL && handler->write_byte == NULL
  91.         && handler->write_word != NULL)
  92.         logger(_L | LOG_FATAL,
  93.              "set_area_handler:  cannot have a handler define read_word without read_byte\n");
  94.  
  95.     if (!handler->areamemory)
  96.         logger(_L | LOG_FATAL,
  97.                 "set_area_handler:  must have areamemory set\n");
  98.                 
  99.     if (md < 0 || md >= NUMDOMAINS) 
  100.         logger(_L | LOG_FATAL,
  101.                "set_area_handler:  domain out of range\n");
  102.  
  103.     if (size > PHYSMEMORYSIZE || 
  104.         addr >= PHYSMEMORYSIZE ||
  105.         addr + size > PHYSMEMORYSIZE)
  106.         logger(_L | LOG_FATAL,
  107.                 "set_area_handler:  illegal address or size\n");
  108.                 
  109.     size = (size + AREASIZE - 1) >> AREASHIFT;
  110.     addr >>= AREASHIFT;
  111.     while (size--) {
  112.         __areahandlers[md][addr++] = tmp;
  113.  
  114.         /* advance memory pointer(s) */
  115.         if (tmp.areamemory)
  116.             tmp.areamemory += AREASIZE;
  117.         if (tmp.arearead)
  118.             tmp.arearead += AREASIZE;
  119.         if (tmp.areawrite)
  120.             tmp.areawrite += AREASIZE;
  121.     }
  122. }
  123.  
  124. /*************/
  125.  
  126. /*  CPU RAM  */
  127.  
  128. /*************/
  129.  
  130. //  This emulates the standard memory.
  131. static void
  132. wwcram(const mrstruct *mr, u32 addr, u16 val)
  133. {
  134.     WORD(mr->areamemory, (addr & 0x00ff) + 0x300) = val;
  135. }
  136.  
  137. static      u16
  138. wrcram(const mrstruct *mr, u32 addr)
  139. {
  140.     return WORD(mr->areamemory, (addr & 0x00ff) + 0x300);
  141. }
  142. static void
  143. bwcram(const mrstruct *mr, u32 addr, s8 val)
  144. {
  145.     BYTE(mr->areamemory, (addr & 0x00ff) + 0x300) = val;
  146. }
  147.  
  148. static      s8
  149. brcram(const mrstruct *mr, u32 addr)
  150. {
  151.     return BYTE(mr->areamemory, (addr & 0x00ff) + 0x300);
  152. }
  153.  
  154. static u8 std_console_ram[0x400];
  155.  
  156. mrstruct    std_console_ram_handler = {
  157.     std_console_ram,
  158.     std_console_ram,
  159.     std_console_ram,
  160.     wrcram,
  161.     brcram,                        /* for reads, only honor low 8 bits of address */
  162.     wwcram,
  163.     bwcram,                        /* for writes, only honor low 8 bits of address */
  164. };
  165.  
  166. /*
  167. //  Geneve memory
  168. static void
  169. wwcrame(const mrstruct *mr, u32 addr, u16 val)
  170. {
  171.     WORD(mr->areamemory, (addr & 0x03ff)) = val;
  172. }
  173.  
  174. static      u16
  175. wrcrame(const mrstruct *mr, u32 addr)
  176. {
  177.     return WORD(mr->areamemory, (addr & 0x03ff));
  178. }
  179. static void
  180. bwcrame(const mrstruct *mr, u32 addr, s8 val)
  181. {
  182.     BYTE(mr->areamemory, (addr & 0x03ff)) = val;
  183. }
  184.  
  185. static      s8
  186. brcrame(const mrstruct *mr, u32 addr)
  187. {
  188.     return BYTE(mr->areamemory, (addr & 0x03ff));
  189. }
  190. */
  191.  
  192. mrstruct    enh_console_ram_handler = {
  193.     std_console_ram,
  194.     std_console_ram,
  195.     std_console_ram,
  196.     NULL, NULL, NULL, NULL        /* allow direct access to memory */
  197. };
  198.  
  199. /******************/
  200.  
  201. /*  expansion RAM */
  202.  
  203. /******************/
  204.  
  205. static void
  206. wweram(const mrstruct *mr, u32 addr, u16 val)
  207. {
  208.     if (isexpram)
  209.         WORD(mr->areamemory, addr & (AREASIZE - 1)) = val;
  210. }
  211.  
  212. static      u16
  213. wreram(const mrstruct *mr, u32 addr)
  214. {
  215.     return (isexpram ? WORD(mr->areamemory, addr & (AREASIZE - 1)) : 0);
  216. }
  217. static void
  218. bweram(const mrstruct *mr, u32 addr, s8 val)
  219. {
  220.     if (isexpram)
  221.         BYTE(mr->areamemory, addr & (AREASIZE - 1)) = val;
  222. }
  223.  
  224. static      s8
  225. breram(const mrstruct *mr, u32 addr)
  226. {
  227.     return (isexpram ? BYTE(mr->areamemory, addr & (AREASIZE - 1)) : 0);
  228. }
  229.  
  230. static u8 low_expansion_memory[0x2000];
  231. mrstruct    low_expansion_memory_handler = {
  232.     low_expansion_memory,
  233.     low_expansion_memory,
  234.     low_expansion_memory,
  235.     wreram,
  236.     breram,                        /* only read if expansion memory is on */
  237.     wweram,
  238.     bweram,                        /* only write if expansion memory is on */
  239. };
  240.  
  241. static u8 high_expansion_memory[0x6000];
  242. mrstruct    high_expansion_memory_handler = {
  243.     high_expansion_memory,
  244.     high_expansion_memory,
  245.     high_expansion_memory,
  246.     wreram,
  247.     breram,                        /* only read if expansion memory is on */
  248.     wweram,
  249.     bweram,                        /* only write if expansion memory is on */
  250. };
  251.  
  252. /****************/
  253.  
  254. /*    zero memory */
  255.  
  256. /****************/
  257.  
  258. u8 zeroes[PHYSMEMORYSIZE];
  259. mrstruct    zero_memory_handler = {
  260.     zeroes, NULL, NULL,            /* can neither read nor write directly */
  261.     NULL,
  262.     NULL,                        /* for reads, return zero */
  263.     NULL,
  264.     NULL                        /* for writes, ignore */
  265. };
  266.  
  267.  
  268. /***************************************************************************/
  269.  
  270. static void
  271. bwsound(const mrstruct *mr, u32 addr, s8 val)
  272. {
  273.     if (0 == (addr & 1))
  274.         sound_mmio_write(val);
  275. }
  276.  
  277. mrstruct    console_sound_handler = {
  278.     zeroes, NULL, NULL,            /* no RAM */
  279.     NULL, NULL,                    /* no reads */
  280.     NULL, bwsound
  281. };
  282.  
  283. static      s8
  284. brrvdp(const mrstruct *mr, u32 addr)
  285. {
  286.     if (0 == (addr & 1))
  287.         return vdp_mmio_read(addr & 2);
  288.     else
  289.         return 0;
  290. }
  291.  
  292. mrstruct    console_vdp_read_handler = {
  293.     zeroes, NULL, NULL,            /* no RAM */
  294.     NULL, brrvdp,
  295.     NULL, NULL                    /* no writes */
  296. };
  297.  
  298. static void
  299. bwwvdp(const mrstruct *mr, u32 addr, s8 val)
  300. {
  301.     if (!(addr & 1))
  302.         vdp_mmio_write(addr & 2, val);
  303. }
  304.  
  305. mrstruct    console_vdp_write_handler = {
  306.     zeroes, NULL, NULL,            /* no RAM */
  307.     NULL, NULL,                    /* no reads */
  308.     NULL, bwwvdp
  309. };
  310.  
  311. static      s8
  312. brrspeech(const mrstruct *mr, u32 addr)
  313. {
  314.     if (0 == (addr & 1))
  315.         return speech_mmio_read();
  316.     else
  317.         return 0;
  318. }
  319.  
  320. mrstruct    console_speech_read_handler = {
  321.     zeroes, NULL, NULL,            /* no RAM */
  322.     NULL, brrspeech,
  323.     NULL, NULL                    /* no writes */
  324. };
  325.  
  326. static void
  327. bwwspeech(const mrstruct *mr, u32 addr, s8 val)
  328. {
  329.     if (0 == (addr & 1))
  330.         speech_mmio_write(val);
  331. }
  332.  
  333. mrstruct    console_speech_write_handler = {
  334.     zeroes, NULL, NULL,            /* no RAM */
  335.     NULL, NULL,                    /* no reads */
  336.     NULL, bwwspeech
  337. };
  338.  
  339. static      s8
  340. brrgrom(const mrstruct *mr, u32 addr)
  341. {
  342.     if (0 == (addr & 1))
  343.         return grom_mmio_read(addr & 2);
  344.     else
  345.         return 0;
  346. }
  347.  
  348. mrstruct    console_grom_read_handler = {
  349.     zeroes, NULL, NULL,            /* no RAM */
  350.     NULL, brrgrom,
  351.     NULL, NULL                    /* no writes */
  352. };
  353.  
  354. static void
  355. bwwgrom(const mrstruct *mr, u32 addr, s8 val)
  356. {
  357.     if (!(addr & 1))
  358.         grom_mmio_write(addr & 2, val);
  359. }
  360.  
  361. mrstruct    console_grom_write_handler = {
  362.     zeroes, NULL, NULL,            /* no RAM */
  363.     NULL, NULL,                    /* no reads [should cause a freeze] */
  364.     NULL, bwwgrom
  365. };
  366.  
  367. /********************************/
  368.  
  369. u16 domain_read_word(mem_domain md, u32 addr)
  370. {
  371.     AREA_SETUP(md, addr);
  372.  
  373.     if (area->read_word)
  374.         return area->read_word(area, addr);
  375.     else if (area->read_byte)
  376.         return (area->read_byte(area, addr) << 8) |
  377.             ((area->read_byte(area, addr + 1)) & 0xff);
  378.     else if (area->arearead)
  379.         if (md == md_cpu)
  380.             return WORD(area->arearead, (addr & (AREASIZE - 1)));
  381.         else {
  382.             return (FLAT_BYTE(area->arearead, (addr & (AREASIZE - 1))) << 8) +
  383.                 FLAT_BYTE(area->arearead, ((addr+1) & (AREASIZE - 1)));
  384.         }
  385.     else
  386.         return 0;
  387. }
  388.  
  389. void
  390. domain_write_word(mem_domain md, u32 addr, u16 val)
  391. {
  392.     AREA_SETUP(md, addr);
  393.  
  394.     if (area->write_word)
  395.         area->write_word(area, addr, val);
  396.     else if (area->write_byte) {
  397.         area->write_byte(area, addr, val >> 8);
  398.         area->write_byte(area, addr + 1, (s8) val);
  399.     } else if (area->areawrite)
  400.         if (md == md_cpu)
  401.             WORD(area->areawrite, (addr & (AREASIZE - 1))) = val;
  402.         else {
  403.             FLAT_BYTE(area->areawrite, (addr & (AREASIZE - 1))) = (val >> 8) & 0xff;
  404.             FLAT_BYTE(area->areawrite, ((addr+1) & (AREASIZE - 1))) = val & 0xff;
  405.         }
  406. }
  407.  
  408. s8 domain_read_byte(mem_domain md, u32 addr)
  409. {
  410.     AREA_SETUP(md, addr);
  411.  
  412.     if (area->read_byte)
  413.         return area->read_byte(area, addr);
  414.     else if (area->arearead)
  415.         if (md == md_cpu)
  416.             return BYTE(area->arearead, (addr & (AREASIZE - 1)));
  417.         else
  418.             return FLAT_BYTE(area->arearead, (addr & (AREASIZE - 1)));
  419.     else
  420.         return 0;
  421. }
  422.  
  423. void
  424. domain_write_byte(mem_domain md, u32 addr, s8 val)
  425. {
  426.     AREA_SETUP(md, addr);
  427.  
  428.     if (area->write_byte)
  429.         area->write_byte(area, addr, val);
  430.     else if (area->areawrite)
  431.         if (md == md_cpu)
  432.             BYTE(area->areawrite, (addr & (AREASIZE - 1))) = val;
  433.         else
  434.             FLAT_BYTE(area->areawrite, (addr & (AREASIZE - 1))) = val;
  435. }
  436.  
  437. /***********************************************************************/
  438.  
  439. MemoryEntry *mementlist;                      /* active memory list */
  440.  
  441. /* user directory lists */
  442. char       *modulespath, *romspath, *ramspath;        // speech.c references romspath
  443. /* system directory lists */
  444. char       *systemmodulespath, *systemromspath, *systemramspath;
  445.  
  446. #define PATH_FOR_ENT(ent)    ((ent->flags & MEMENT_STORED) == MEMENT_STORED ? ramspath : \
  447.                              (ent->addr == 0) ? romspath : \
  448.                              modulespath)
  449. #define SYS_PATH_FOR_ENT(ent)    ((ent->flags & MEMENT_STORED) == MEMENT_STORED ? systemramspath : \
  450.                              (ent->addr == 0) ? systemromspath : \
  451.                              systemmodulespath)
  452.  
  453. #define CPU_MEM_ENT(ent)    (((ent->flags & MEMENT_DOMAIN) == MEMENT_CONSOLE))
  454.                              
  455. u8          modulerom[16384];
  456.  
  457. static void
  458. memory_dump_list(const char *msg)
  459. {
  460.     MemoryEntry *lst;
  461.  
  462.     lst = mementlist;
  463.     logger(LOG_USER, "\nMemory map (%s):\n", msg);
  464.     while (lst) {
  465.         logger(LOG_USER, "'%s': Addr: >%04X, Offs: >%04X, Size: >%04X (>%04X)\n",
  466.                lst->name,
  467.                lst->addr, lst->offs,
  468.                lst->realsize, lst->size);
  469.         if (lst->filename)
  470.             logger(LOG_USER, "\tFilename: '%s'\n", lst->filename);
  471.         logger(LOG_USER, "\tFlags:");
  472.         if ((lst->flags & MEMENT_STORED) == MEMENT_STORED)    logger( LOG_USER, "STORED, ");
  473.         else if (lst->flags & MEMENT_RAM)    logger( LOG_USER, "RAM, ");
  474.         else logger( LOG_USER, "ROM, ");
  475.         if (lst->flags & MEMENT_BANK_1) logger( LOG_USER, "BANK_1, ");
  476.         else if (lst->flags & MEMENT_BANK_2) logger( LOG_USER, "BANK_2, ");
  477.         if (lst->flags & MEMENT_CART) logger( LOG_USER, "CART, ");
  478.         switch (lst->flags & MEMENT_DOMAIN) {
  479.         case MEMENT_CONSOLE:    logger( LOG_USER, "CONSOLE\n"); break;
  480.         case MEMENT_GRAPHICS:    logger( LOG_USER, "GRAPHICS\n"); break;
  481.         case MEMENT_VIDEO:        logger( LOG_USER, "VIDEO\n"); break;
  482.         case MEMENT_SPEECH:        logger( LOG_USER, "SPEECH\n"); break;
  483. //        case MEMENT_DSR:        logger( LOG_USER, "DSR\n"); break;
  484.         default:    logger(LOG_INTERNAL, "invalid MEMENT_xxx: %d\n", (lst->flags & MEMENT_DOMAIN)>>MEMENT_DOMAIN_SHIFT); break;
  485.         }
  486.         lst = lst->next;
  487.     }
  488. }
  489.  
  490.  
  491. /*    Free memory list */
  492. void 
  493. memory_free_list(void)
  494. {
  495.     MemoryEntry *lst = mementlist, *prev = 0L;
  496.  
  497.     while (lst) {
  498.         lst = memory_remove_entry_from_list(prev, lst);
  499.     }
  500.  
  501.     mementlist = NULL;
  502. }
  503.  
  504. /*    Initialize memory list */
  505. int
  506. memory_init_list(void)
  507. {
  508.     memory_free_list();
  509.  
  510.     return 1;
  511. }
  512.  
  513. /*     Remove an entry from the memory map */
  514. MemoryEntry *
  515. memory_remove_entry_from_list(MemoryEntry *prev, MemoryEntry *ent)
  516. {
  517.     MemoryEntry *ret;
  518.  
  519.     if (prev)
  520.         prev->next = ret = ent->next;
  521.     else
  522.         mementlist = ret = ent->next;
  523.  
  524.     if (ent->flags & MEMENT_USER)
  525.         memory_destroy_entry(ent);
  526.     else
  527.         xfree(ent);
  528.  
  529.     if (log_level(LOG_MEMORY) > 1)
  530.         memory_dump_list("memory_remove_entry_from_list");
  531.     return ret;
  532. }
  533.  
  534. /*    Add entry to memory map and destroy entries this overrides */
  535. int
  536. memory_add_entry_to_list(MemoryEntry *ent)
  537. {
  538.     MemoryEntry **lstptr = &mementlist, *lst, *prev = 0L;
  539.     int ret = 1;
  540.  
  541.     /* if size is unknown, assume it covers everything */
  542.     if (!ent->realsize) {
  543.         my_assert(ent->size > 0);
  544.         ent->realsize = ent->size;
  545.     }
  546.  
  547.     while (*lstptr) {
  548.         lst = *lstptr;
  549.  
  550.         /* This magic tells us that we need to obliterate some memory
  551.            segment already here.
  552.            The last two lines say: two different banks can coexist,
  553.            but banking stuff overrides non-banking stuff, and v.v. */
  554.         if ((lst->flags & MEMENT_DOMAIN) == (ent->flags & MEMENT_DOMAIN) &&
  555.             lst->addr >= ent->addr && 
  556.             lst->addr + lst->realsize <= ent->addr + ent->realsize &&
  557.             ((lst->flags & MEMENT_BANKING) == (ent->flags & MEMENT_BANKING) ||
  558.              ((lst->flags ^ ent->flags) & MEMENT_BANKING) != MEMENT_BANKING)) {
  559.  
  560.             /* entry will be destroyed or split, save first */
  561.             /*ret &=*/ memory_save_entry(lst);
  562.  
  563.             /* clear out memory map for new item */
  564.             ent->realsize = ent->realsize;
  565.             memory_unmap_entry(ent);
  566.  
  567.             /* split entry if necessary */
  568.             if (ent->addr > lst->addr && 
  569.                 ent->addr + ent->realsize < lst->addr + lst->realsize) {
  570.  
  571.                 MemoryEntry *nw = (MemoryEntry *)xmalloc(sizeof(MemoryEntry));
  572.                 *nw = *lst;
  573.  
  574.                 /* lst is first chunk */
  575.                 lst->realsize = ent->addr - lst->addr;
  576.  
  577.                 /* nw is last chunk */
  578.                 nw->realsize -= lst->realsize + ent->realsize;
  579.                 nw->offs += (ent->addr + ent->realsize) - nw->addr;
  580.                 nw->addr += ent->addr + ent->realsize;
  581.  
  582.                 lst->addr = ent->addr + ent->realsize;
  583.                 logger(_L | L_2, "Splitting entry '%s' into >%04X (>%04X), "
  584.                        ">%04X (>%04X), and >%04X (>%04X)\n",
  585.                        lst->name,
  586.                        lst->addr, lst->realsize,
  587.                        nw->addr, nw->realsize,
  588.                        ent->addr, ent->realsize);
  589.             } else if (lst->addr < ent->addr && lst->realsize > ent->realsize) {
  590.                 /* new entry covers tail of old entry */
  591.                 lst->realsize = ent->addr - lst->addr;
  592.                 logger(_L | L_2, "Shrinking entry '%s' to >%04X (>%04X)\n",
  593.                        lst->name,
  594.                        lst->addr, lst->realsize);
  595.             } else if (lst->realsize > ent->realsize) {
  596.                 /* new entry covers front of old entry */
  597.                 int shrink = ent->realsize;
  598.                 lst->offs += (ent->addr + ent->realsize) - lst->addr;
  599.                 lst->realsize -= shrink;
  600.                 lst->addr = ent->addr + ent->realsize;
  601.                 logger(_L | L_2, "Shrinking entry '%s' to >%04X (>%04X)\n",
  602.                        lst->name,
  603.                        lst->addr, lst->realsize);
  604.             } else {
  605.                 /* old entry completely overriden */
  606.                 logger(_L | L_2, "Overriding old entry '%s' at >%04X (>%04X)\n",
  607.                        lst->name,
  608.                        lst->addr, lst->realsize);
  609.                 lst = memory_remove_entry_from_list(prev, lst);
  610.                 lstptr = &lst;
  611.                 /* prev is the same */
  612.                 continue;
  613.             }
  614.         }
  615.         prev = lst;
  616.         lstptr = &lst->next;
  617.     }
  618.  
  619.     *lstptr = ent;
  620.     (*lstptr)->next = 0L;
  621.  
  622.     return ret;
  623. }
  624.  
  625. /*    Save an entry in the memory map to disk */
  626. int
  627. memory_save_entry(MemoryEntry *ent)
  628. {
  629.     if ((ent->flags & MEMENT_STORED) == MEMENT_STORED) {
  630.         my_assert(ent->memact.arearead == ent->memact.areawrite &&
  631.                   ent->memact.arearead != NULL &&
  632.                   ent->filename);
  633.  
  634.         logger(_L | LOG_USER, "Saving memory image to '%s'\n", ent->filename);
  635.         return savebinary(ramspath, 
  636.                   systemramspath,
  637.                   "RAM",
  638.                   ent->filename, ent->fileoffs + ent->offs,
  639.                   ent->memact.areawrite + ent->offs, 
  640.                   CPU_MEM_ENT(ent),
  641.                   ent->realsize - ent->offs);
  642.     } else {
  643.         /* others are ROM binaries or empty */
  644.         return 1;
  645.     }
  646. }
  647.  
  648. /*    Load an entry in the memory map from disk */
  649. int
  650. memory_load_entry(MemoryEntry *ent)
  651. {
  652.     if ((ent->flags & MEMENT_STORED) == MEMENT_STORED) {
  653.         my_assert(ent->memact.arearead == ent->memact.areawrite &&
  654.                   ent->memact.arearead != NULL &&
  655.                   ent->filename && 
  656.                   ent->size > 0);
  657.  
  658.         logger(_L | LOG_USER, "Restoring memory image from '%s'\n", ent->filename);
  659.  
  660.         /* okay for this to fail, the first time at least */
  661.         ent->realsize = loadbinary(ramspath, 
  662.                                    systemramspath,
  663.                                    ent->filename, "RAM",
  664.                                    ent->memact.areawrite + ent->offs, 
  665.                                    CPU_MEM_ENT(ent),
  666.                                    ent->offs + ent->fileoffs, 
  667.                                    ent->size - ent->offs, 
  668.                                    ent->size);
  669.  
  670.         if (!ent->realsize) {
  671.             ent->realsize = ent->size;
  672.             logger(_L | LOG_USER, "Image '%s' ('%s') not found, resetting to zero\n",
  673.                    ent->filename, ent->name);
  674.             memset(ent->memact.areawrite, 0, ent->realsize);
  675.         }
  676.  
  677.     } else if (!(ent->flags & MEMENT_RAM)) {
  678.         /* ROM */
  679.  
  680.         if (ent->filename && ent->memact.arearead && ent->realsize) {
  681.  
  682.             logger(_L | L_1, "Reading ROM image '%s' at %d to >%04X, size %d\n",
  683.                    ent->name,
  684.                    ent->fileoffs,
  685.                    ent->addr, ent->size);
  686.  
  687.             if (!loadbinary(
  688.                         PATH_FOR_ENT(ent), 
  689.                         SYS_PATH_FOR_ENT(ent), 
  690.                         ent->filename, "ROM",
  691.                         ent->memact.arearead + ent->offs,
  692.                         CPU_MEM_ENT(ent),
  693.                         ent->fileoffs + ent->offs,
  694.                         ent->realsize - ent->offs,
  695.                         ent->size < 0 ? -ent->size : 
  696.                         ent->size == 0 ? 0x10000 - ent->addr : ent->size))
  697.                 return 0;
  698.         }
  699.  
  700.     } else {
  701.         /* zero memory (RAM or empty ROM) */
  702.         ent->realsize = ent->size < 0 ? 0x10000 - ent->addr : ent->size;
  703.         logger(_L | L_2, "Zeroes for '%s' at >%04X, size %d\n",
  704.                ent->name,
  705.                ent->addr, ent->realsize);
  706.     }
  707.     return 1;
  708. }
  709.  
  710. /*    Unmap an entry from the memory map */
  711. void
  712. memory_unmap_entry(MemoryEntry *ent)
  713. {
  714.     /* reset affected memory */
  715.     logger(_L | L_2, "Resetting memory area from >%04X to >%04X\n",
  716.            ent->addr, ent->addr+ent->realsize-1);
  717.  
  718.     set_area_handler((ent->flags & MEMENT_DOMAIN) >> MEMENT_DOMAIN_SHIFT,
  719.         ent->addr, ent->realsize, &zero_memory_handler);
  720. }
  721.  
  722.  
  723. mrstruct *memory_module_bank_handlers[2];
  724. int memory_module_bank;
  725. void
  726. memory_set_module_bank(u8 bank)
  727. {
  728.     if (bank > 1 || !memory_module_bank_handlers[0] || !memory_module_bank_handlers[1])
  729.         return; //logger(LOG_INTERNAL, "memory_set_module_bank: Invalid bank or call to set %d\n", bank);
  730.     else {
  731.         SET_AREA_HANDLER(0x6000, 0x2000, memory_module_bank_handlers[bank]);
  732.         memory_module_bank = bank;
  733.     }
  734. }
  735.  
  736. static void
  737. bwmrom_bank(const mrstruct *mr, u32 addr, s8 val)
  738. {
  739.     memory_set_module_bank((addr & 2) >> 1);
  740. }
  741.  
  742.  
  743. /*    Map an entry into the memory map */
  744. int
  745. memory_map_entry(MemoryEntry *ent)
  746. {
  747.     if (!(ent->flags & MEMENT_RAM)) {
  748.         /* fudge stuff for the module banks */
  749.         if (ent->addr == 0x6000 && 
  750.             (ent->flags & MEMENT_DOMAIN) == MEMENT_CONSOLE) {
  751.             if (ent->flags & MEMENT_BANK_1) {
  752.                 ent->memact.write_byte = bwmrom_bank;
  753.                 memory_module_bank_handlers[0] = &ent->memact;
  754.             } else if (ent->flags & MEMENT_BANK_2) {
  755.                 ent->memact.write_byte = bwmrom_bank;
  756.                 memory_module_bank_handlers[1] = &ent->memact;
  757.             }
  758.         }
  759.     }
  760.  
  761.     /* setup memory routines for this entry */
  762.     set_area_handler((ent->flags & MEMENT_DOMAIN) >> MEMENT_DOMAIN_SHIFT,
  763.         ent->addr, ent->realsize, &ent->memact);
  764.         
  765.     return 1;
  766. }
  767.  
  768. /*    Save volatile memory associated with loaded module */
  769. void
  770. memory_volatile_save(void)
  771. {
  772.     MemoryEntry *lst = mementlist;
  773.     while (lst) {
  774.         if ((lst->flags & MEMENT_STORED) == MEMENT_STORED) {
  775.             memory_save_entry(lst);
  776.         }
  777.         lst = lst->next;
  778.     }
  779. }
  780.  
  781. /*    Load volatile memory associated with loaded module */
  782. int
  783. memory_volatile_load(void)
  784. {
  785.     MemoryEntry *lst = mementlist;
  786.     while (lst) {
  787.         if ((lst->flags & MEMENT_STORED) == MEMENT_STORED) {
  788. //        if ((lst->flags & MEMENT_RAM) == 0) {
  789.             if (!memory_load_entry(lst))
  790.                 return 0;
  791.         }
  792.         lst = lst->next;
  793.     }
  794.  
  795.     return 1;
  796. }
  797.  
  798. /*    Load all memory associated with loaded module */
  799. int
  800. memory_complete_load(void)
  801. {
  802.     MemoryEntry *lst = mementlist;
  803.     while (lst) {
  804.         if ((lst->flags & MEMENT_RAM) == 0) {
  805.             if (!memory_load_entry(lst))
  806.                 return 0;
  807.         }
  808.         lst = lst->next;
  809.     }
  810.  
  811.     return 1;
  812. }
  813.  
  814.  
  815. /*  Create a new memory entry
  816.  
  817.     flags:     bitmask of MEMENT_xxx
  818.     addr:      address of new memory
  819.     size:    size of memory in bytes, 
  820.                 or if negative, the magnitude is the maximum size
  821.     name:    user name for memory segment
  822.     filename:  location of ROM or RAM on disk (MEMENT_ROM/MEMENT_STORED)
  823.     fileoffs:  offset into file where memory is stored
  824.     memact: actions on memory access to area
  825. */
  826. MemoryEntry *memory_new_entry(int flags, u32 addr, s32 size,
  827.                               char *name, char *filename, u32 fileoffs, 
  828.                               mrstruct *memact)
  829. {
  830.     MemoryEntry *nw = (MemoryEntry *)xmalloc(sizeof(MemoryEntry));
  831.     OSSpec tmpspec;
  832.  
  833.     memset((void *)nw, 0, sizeof(MemoryEntry));
  834.  
  835.     my_assert(addr >= 0 && addr < PHYSMEMORYSIZE &&
  836.               !(addr & (AREASIZE-1)) && !(size & (AREASIZE-1)) &&
  837.               size >= -PHYSMEMORYSIZE && size <= PHYSMEMORYSIZE &&
  838.               !((flags & MEMENT_RAM) && (size <= 0)));
  839.  
  840.     nw->flags = flags;
  841.     nw->fileoffs = fileoffs;
  842.     nw->offs = 0;
  843.     nw->addr = addr;
  844.     nw->size = size;
  845.     nw->realsize = 0;
  846.     nw->filename = filename ? xstrdup(filename) : NULL;
  847.     nw->name = name ? xstrdup(name) : NULL;
  848.     nw->next = 0L;
  849.  
  850.     if (nw->filename) {
  851.         nw->realsize = findbinary(
  852.             PATH_FOR_ENT(nw), 
  853.             SYS_PATH_FOR_ENT(nw), 
  854.             nw->filename, 
  855.             &tmpspec);
  856.         if (!nw->realsize && !(nw->flags & MEMENT_RAM)) {
  857.             logger(_L | LOG_USER | LOG_ERROR, "Can't locate '%s'\n",
  858.                    nw->filename);
  859.             return 0;
  860.         }
  861. //        if (!nw->size && nw->realsize) {
  862. //            nw->size = nw->realsize;
  863. //        }
  864.         /* for large files selected, e.g., by accident */
  865.         if (nw->size > 0 && nw->realsize > nw->size) {
  866.             nw->realsize = nw->size;
  867.         } else if (nw->size < 0 && nw->realsize > -nw->size) {
  868.             nw->realsize = -nw->size;
  869.         } else if (nw->realsize + nw->addr > 0x10000) {
  870.             nw->realsize = 0x10000 - nw->addr;
  871.         }
  872.     }
  873.  
  874.     if (memact) {
  875.         nw->memact = *memact;
  876.     } else {
  877.  
  878.         my_assert(nw->flags & MEMENT_USER);
  879.  
  880.         nw->memact.areamemory = (u8 *)xmalloc(nw->realsize);
  881.         nw->memact.arearead = nw->memact.areamemory;
  882.         if (nw->flags & MEMENT_RAM)
  883.             nw->memact.areawrite = nw->memact.areamemory;
  884.         else
  885.             nw->memact.areawrite = 0L;
  886.     }
  887.  
  888.     return nw;
  889. }
  890.  
  891. void
  892. memory_destroy_entry(MemoryEntry *ent)
  893. {
  894.     if (ent->name)
  895.         xfree(ent->name);
  896.     if (ent->filename)
  897.         xfree(ent->filename);
  898.     if ((ent->flags & MEMENT_USER) && ent->memact.areamemory)
  899.         xfree(ent->memact.areamemory);
  900.  
  901.     xfree(ent);
  902. }
  903.  
  904. /*    Do it all */
  905. int
  906. memory_insert_new_entry(int flags, u32 addr, s32 size,
  907.                         char *name, char *filename, u32 fileoffs, 
  908.                         mrstruct *memact)
  909. {
  910.     MemoryEntry *ent = memory_new_entry(flags, addr, size,
  911.                                         name, filename, fileoffs, memact);
  912.     return (ent && 
  913.             memory_add_entry_to_list(ent) && 
  914.             memory_load_entry(ent) &&
  915.             memory_map_entry(ent));
  916. }
  917.  
  918. DECL_SYMBOL_ACTION(memory_define_entry)
  919. {
  920.     char *flagptr, *fnameptr, *nameptr;
  921.     MemoryEntry *nw;
  922.     long flags;
  923.     int addr, size, fileoffs;
  924.     int state;
  925.  
  926.     if (task == csa_READ) {
  927.         char buf[32], *bptr = buf;
  928.         static MemoryEntry *ptr;
  929.  
  930.         if (iter == 0) {
  931.             ptr = mementlist;
  932.         }
  933.  
  934.         // the non-user memory items are available by
  935.         // default; the cartridge items are defined by
  936.         // ReplaceModule (which also gives the name of the
  937.         // cart for the UI)
  938.         while (ptr 
  939.                && ((ptr->flags & MEMENT_USER) == 0
  940.                    || (ptr->flags & MEMENT_CART) != 0))
  941.             ptr = ptr->next;
  942.  
  943.         if (ptr == 0L) {
  944.             return 0;
  945.         }
  946.  
  947.         if ((ptr->flags & MEMENT_STORED) == MEMENT_STORED)
  948.             *bptr++ = 'S'; 
  949.         else if (ptr->flags & MEMENT_RAM)     
  950.             *bptr++ = 'W'; 
  951.         else
  952.             *bptr++ = 'R';
  953.         
  954.         if (ptr->flags & MEMENT_CART)        *bptr++ = 'M';
  955.         if (ptr->flags & MEMENT_BANK_1)        *bptr++ = '1';
  956.         else if (ptr->flags & MEMENT_BANK_2) *bptr++ = '2';
  957.  
  958.         switch (ptr->flags & MEMENT_DOMAIN) {
  959.         case MEMENT_CONSOLE:    *bptr++ = 'C'; break;
  960.         case MEMENT_GRAPHICS:    *bptr++ = 'G'; break;
  961.         case MEMENT_VIDEO:        *bptr++ = 'V'; break;
  962.         case MEMENT_SPEECH:        *bptr++ = 'S'; break;
  963. //        case MEMENT_DSR:        *bptr++ = 'D'; break;
  964.         default:    logger(LOG_INTERNAL | LOG_FATAL, "invalid MEMENT_xxx: %d\n", (ptr->flags & MEMENT_DOMAIN)>>MEMENT_DOMAIN_SHIFT); break;
  965.         }
  966.         *bptr = 0;
  967.  
  968.         command_arg_set_string(SYM_ARG_1st, buf);
  969.         command_arg_set_num(SYM_ARG_2nd, ptr->addr);
  970.         command_arg_set_num(SYM_ARG_3rd, ptr->size);
  971.         command_arg_set_string(SYM_ARG_4th, ptr->filename);
  972.         command_arg_set_num(SYM_ARG_5th, ptr->fileoffs);
  973.         command_arg_set_string(SYM_ARG_6th, ptr->name);
  974.  
  975.         ptr = ptr->next;
  976.         return 1;
  977.     }
  978.  
  979.     // task == csa_WRITE
  980.  
  981.     command_arg_get_string(SYM_ARG_1st, &flagptr);
  982.     command_arg_get_num(SYM_ARG_2nd, &addr);
  983.     command_arg_get_num(SYM_ARG_3rd, &size);
  984.     command_arg_get_string(SYM_ARG_4th, &fnameptr);
  985.     command_arg_get_num(SYM_ARG_5th, &fileoffs);
  986.     command_arg_get_string(SYM_ARG_6th, &nameptr);
  987.  
  988.     flags = MEMENT_USER;
  989.     state = 0;
  990.     while (*flagptr)
  991.     {
  992.         if (state == 0) {
  993.             switch (toupper(*flagptr))
  994.             {
  995.             case 'S':    flags |= MEMENT_STORED; break;
  996.             case 'W':    flags |= MEMENT_RAM; break;
  997.             case 'R':    flags &= ~MEMENT_RAM; break;
  998.             default:
  999.                 logger(_L | LOG_ERROR | LOG_USER, 
  1000.                        "Unknown memory flag '%c' (at '%s')\n",
  1001.                        *flagptr, flagptr);
  1002.                 return 0;
  1003.             }            
  1004.             state++;
  1005.         } else {
  1006.  
  1007.             switch (toupper(*flagptr)) {
  1008.             case 'M':
  1009.                 {
  1010.                     // this is such a hack.  if we don't clear it
  1011.                     // here, we end up generating session files that
  1012.                     // might have invalid "LoadModule"/"ReplaceModule"
  1013.                     // lines, if v9t9.cnf has a "LoadModule" line,
  1014.                     // a session file is loaded without a "LoadModule"
  1015.                     // line, and it is saved again.
  1016.                     extern void *loaded_module;
  1017.                     flags |= MEMENT_CART; 
  1018.                     loaded_module = 0L;
  1019.                     break;
  1020.                 }
  1021.  
  1022.             case '1':    flags = (flags & ~MEMENT_BANK_2) | MEMENT_BANK_1; break;
  1023.             case '2':    flags = (flags & ~MEMENT_BANK_1) | MEMENT_BANK_2; break;
  1024.  
  1025.             case 'C':    flags = (flags & ~MEMENT_DOMAIN) | MEMENT_CONSOLE; break;
  1026.             case 'G':    flags = (flags & ~MEMENT_DOMAIN) | MEMENT_GRAPHICS; break;
  1027.             case 'V':    flags = (flags & ~MEMENT_DOMAIN) | MEMENT_VIDEO; break;
  1028.             case 'S':    flags = (flags & ~MEMENT_DOMAIN) | MEMENT_SPEECH; break;
  1029. //            case 'D':    flags = (flags & ~MEMENT_DOMAIN) | MEMENT_DSR; break;
  1030.  
  1031.             default:
  1032.                 logger(_L | LOG_ERROR | LOG_USER, 
  1033.                        "Unknown memory flag '%c' (at '%s')\n",
  1034.                        *flagptr, flagptr);
  1035.                 return 0;
  1036.             }
  1037.         }
  1038.         flagptr++;
  1039.     }
  1040.  
  1041.     if (addr < 0 || addr >= 0x10000) {
  1042.         logger(_L | LOG_ERROR | LOG_USER, "Illegal address (>%04x) for entry\n", addr);
  1043.         return 0;
  1044.     }
  1045.     if (addr & 0x1fff) {
  1046.         if (addr & (AREASIZE-1)) {
  1047.             logger(_L | LOG_ERROR | LOG_USER, "Address is impossible to use, "
  1048.                    "minimum granularity is >%04x bytes\n", AREASIZE);
  1049.             return 0;
  1050.         } else {
  1051.             logger(_L | LOG_WARN | LOG_USER, "An address should start on a multiple "
  1052.                    "of >2000 bytes (got >%04x)...\n", addr);
  1053.         }
  1054.     }
  1055.     if (size < -0x10000 || size >= 0x10000) {
  1056.         logger(_L | LOG_ERROR | LOG_USER, "Illegal size (%d) for entry, "
  1057.                "should have magnitude between 0 and >FFFF\n", size);
  1058.         return 0;
  1059.     }
  1060.     if ((flags & MEMENT_RAM) && size <= 0) {
  1061.         logger(_L | LOG_ERROR | LOG_USER, "Illegal size for RAM entry, must be >= 0 (%d)\n", size);
  1062.         return 0;
  1063.     }
  1064.     if (size & 0x1fff) {
  1065.         if (size & (AREASIZE-1)) {
  1066.             logger(_L | LOG_ERROR | LOG_USER, "Entry is impossible to allocate, "
  1067.                    "minimum granularity is >%04X bytes\n", AREASIZE);
  1068.             return 0;
  1069.         } else {
  1070.             logger(_L | LOG_WARN | LOG_USER, "Entry size should be a multiple "
  1071.                    "of >2000 bytes (got >%04x)...\n", size);
  1072.         }
  1073.     }
  1074. ///
  1075.  
  1076.     nw = memory_new_entry(flags, addr, size, nameptr, fnameptr, fileoffs, 0L);
  1077.     if (!nw)
  1078.         return 0;
  1079.  
  1080.     if (memory_add_entry_to_list(nw) && 
  1081.         memory_load_entry(nw) && 
  1082.         memory_map_entry(nw)) {
  1083.         if (log_level(LOG_MEMORY) > 1)
  1084.             memory_dump_list("memory_define_entry");
  1085.         return 1;
  1086.     } else {
  1087.         return 0;
  1088.     }
  1089. }
  1090.  
  1091. DECL_SYMBOL_ACTION(memory_dump)
  1092. {
  1093.     memory_dump_list("memory_dump");
  1094.     return 1;
  1095. }
  1096.  
  1097. static void 
  1098. memory_mmio_init(void);
  1099.  
  1100. DECL_SYMBOL_ACTION(memory_default_list)
  1101. {
  1102.     memory_mmio_init();
  1103.     memory_ram_init();
  1104.     vdp_memory_init();
  1105.     gpl_memory_init();    // does nothing currently
  1106.     speech_memory_init();
  1107.     return 1;
  1108. }
  1109.  
  1110. /***********************************************************************/
  1111.  
  1112. void
  1113. memory_ram_init(void)
  1114. {
  1115. //    if (!low_expansion_memory_handler.areamemory)
  1116. //        low_expansion_memory_handler.areamemory = (u8 *)xmalloc(0x2000);
  1117.  
  1118.     memory_insert_new_entry(MEMENT_CONSOLE | MEMENT_RAM, 0x2000, 0x2000, 
  1119.                             "Low expansion RAM", 
  1120.                             0L /*filename*/, 0L /*fileoffs*/, 
  1121.                             &low_expansion_memory_handler);
  1122.  
  1123. //    if (!std_console_ram_handler.areamemory)
  1124. //        std_console_ram_handler.areamemory = (u8 *)xmalloc(0x400);
  1125.  
  1126.     if (!isenhconsoleram)
  1127.         memory_insert_new_entry(MEMENT_CONSOLE | MEMENT_RAM, 0x8000, 0x0400, 
  1128.                                 "Console RAM (256 bytes)",
  1129.                                 0L /*filename*/, 0L /*fileoffs*/, 
  1130.                                &std_console_ram_handler);
  1131.     else
  1132.         memory_insert_new_entry(MEMENT_CONSOLE | MEMENT_RAM, 0x8000, 0x0400, 
  1133.                                "Console RAM (1K)",
  1134.                                 0L /*filename*/, 0L /*fileoffs*/, 
  1135.                                &enh_console_ram_handler);
  1136.  
  1137. //    if (!high_expansion_memory_handler.areamemory)
  1138. //        high_expansion_memory_handler.areamemory = (u8 *)xmalloc(0x6000);
  1139.  
  1140.     memory_insert_new_entry(MEMENT_CONSOLE | MEMENT_RAM, 0xA000, 0x6000, 
  1141.                             "High expansion RAM",
  1142.                             0L /*filename*/, 0L /*fileoffs*/, 
  1143.                             &high_expansion_memory_handler);
  1144. }
  1145.  
  1146. static void 
  1147. memory_mmio_init(void)
  1148. {
  1149.     memory_insert_new_entry(MEMENT_CONSOLE, 0x8400, 0x400, 
  1150.                            "Sound MMIO", 
  1151.                             0L /*filename*/, 0L /*fileoffs*/, 
  1152.                             &console_sound_handler);
  1153.         
  1154.     memory_insert_new_entry(MEMENT_CONSOLE, 0x8800, 0x400, 
  1155.                            "VDP read MMIO", 
  1156.                             0L /*filename*/, 0L /*fileoffs*/, 
  1157.                             &console_vdp_read_handler);
  1158.  
  1159.     memory_insert_new_entry(MEMENT_CONSOLE, 0x8C00, 0x400, 
  1160.                            "VDP write MMIO",
  1161.                             0L /*filename*/, 0L /*fileoffs*/, 
  1162.                             &console_vdp_write_handler);
  1163.     
  1164.     memory_insert_new_entry(MEMENT_CONSOLE, 0x9000, 0x400, 
  1165.                            "Speech read MMIO", 
  1166.                             0L /*filename*/, 0L /*fileoffs*/, 
  1167.                             &console_speech_read_handler);
  1168.  
  1169.     memory_insert_new_entry(MEMENT_CONSOLE, 0x9400, 0x400, 
  1170.                            "Speech write MMIO", 
  1171.                             0L /*filename*/, 0L /*fileoffs*/, 
  1172.                             &console_speech_write_handler);
  1173.  
  1174.     memory_insert_new_entry(MEMENT_CONSOLE, 0x9800, 0x400, 
  1175.                            "GROM read MMIO", 
  1176.                             0L /*filename*/, 0L /*fileoffs*/, 
  1177.                             &console_grom_read_handler);
  1178.  
  1179.     memory_insert_new_entry(MEMENT_CONSOLE, 0x9C00, 0x400, 
  1180.                            "GROM/GRAM write MMIO", 
  1181.                             0L /*filename*/, 0L /*fileoffs*/, 
  1182.                             &console_grom_write_handler);
  1183. }
  1184.  
  1185. void
  1186. memory_init(void)
  1187. {
  1188.     logger(_L | L_0, "Initializing memory...\n");
  1189.  
  1190.     memset((void *)__areahandlers, 0, sizeof(__areahandlers));
  1191.     memory_init_list();
  1192.  
  1193.     memory_ram_init();
  1194.    
  1195.     memory_mmio_init();
  1196.  
  1197.     vdp_memory_init();
  1198.     gpl_memory_init();
  1199. }
  1200.  
  1201.