OSDN Git Service

[VM][FMTOWNS] Add FONT ROMS, MSDOS ROM, SYSTEM ROM and SERIAL ROM.
[csp-qt/common_source_project-fm7.git] / source / src / vm / fmtowns / towns_memory.cpp
index bab7c76..e55756f 100644 (file)
@@ -4,63 +4,44 @@
        Author : Kyuma.Ohta <whatisthis.sowhat _at_ gmail.com>
        Date   : 2017.01.01 -
 
-       [ memory]
+       [memory]
 */
 
+#include "../../fileio.h"
 #include "./towns_memory.h"
 #include "../i386.h"
 
+namespace FMTOWNS {
+       
 void TOWNS_MEMORY::initialize()
 {
 
-       bankf8_ram = false;
-       bankd0_dict = false;
-       dict_bank = 0;
+       extra_nmi_mask = true;
+       extra_nmi_val = false;
        
        vram_wait_val = 6;
        mem_wait_val = 3;
+
        
-       memset(page0, 0x00, sizeof(page0));
-       memset(ram_0d0, 0x00, sizeof(ram_0d0));
-       memset(ram_0f0, 0x00, sizeof(ram_0f0));
-       memset(ram_0f8, 0x00, sizeof(ram_0f8));
-       
-       memset(system_rom, 0xff, sizeof(system_rom));
-       memset(font_rom, 0xff, sizeof(font_rom));
-#if 0
-       memset(font_20_rom, 0xff, sizeof(font_20_rom));
-#endif
-       memset(msdos_rom, 0xff, sizeof(msdos_rom));
-       memset(dict_rom, 0xff, sizeof(dict_rom));
+       memset(ram_page0, 0x00, sizeof(ram_page0));
 
        // load rom image
-       FILEIO* fio = new FILEIO();
-       if(fio->Fopen(create_local_path(_T("FMT_SYS.ROM")), FILEIO_READ_BINARY)) { // SYSTEM
-               fio->Fread(system_rom, sizeof(system_rom), 1);
-               fio->Fclose();
-       }
-       if(fio->Fopen(create_local_path(_T("FMT_FNT.ROM")), FILEIO_READ_BINARY)) { // FONT
-               fio->Fread(font_rom, sizeof(font_rom), 1);
-               fio->Fclose();
-       }
 #if 0
        if(fio->Fopen(create_local_path(_T("FMT_F20.ROM")), FILEIO_READ_BINARY)) { // 20 pixels FONT : Optional
-               fio->Fread(font_20_rom, sizeof(font_20_rom), 1);
+               fio->Fread(rom_font20, sizeof(rom_font20), 1);
                fio->Fclose();
        }
 #endif
-       if(fio->Fopen(create_local_path(_T("FMT_DOS.ROM")), FILEIO_READ_BINARY)) { // MSDOS
-               fio->Fread(msdos_rom, sizeof(msdos_rom), 1);
-               fio->Fclose();
-       }
-       if(fio->Fopen(create_local_path(_T("FMT_DIC.ROM")), FILEIO_READ_BINARY)) { // MSDOS
-               fio->Fread(dict_rom, sizeof(dict_rom), 1);
-               fio->Fclose();
-       }
        // ToDo: Will move to config.
-       extram_pages = TOWNS_EXTRAM_PAGES;
-       extram_base = (uint8_t *)malloc(extram_pages * 0x100000);
-
+       extram_size = TOWNS_EXTRAM_PAGES * 0x100000;
+       // ToDo: Limit extram_size per VM.
+       extram = (uint8_t *)malloc(extram_size);
+       // ToDo: More smart.
+       vram_size = 0x80000; // OK?
+       
+       //dma_addr_reg = dma_wrap_reg = 0;
+       dma_addr_mask = 0x00ffffff; // ToDo
+       
        initialize_tables();
 }
 
@@ -74,939 +55,921 @@ void TOWNS_MEMORY::reset()
        d_cpu->set_address_mask(0xffffffff);
 }
 
-void TOWNS_MEMORY::write_page0_8(uint32_t addr, uint32_t data, int *wait)
+bool TOWNS_MEMORY::check_bank(uint32_t addr, uint32_t *mask, uint32_t *offset, void** readfn, void** writefn, void** readp, void** writep)
 {
-       addr = addr & 0x000fffff;
-       if(wait != NULL) *wait = mem_wait_val;
+       uint8_t __type = (uint8_t)(type_bank_adrs_cx[banknum] >> 24);
+       uint32_t __offset = type_bank_adrs_cx[banknum] & 0x00ffffff;
+       if(offset == NULL) return false;
+       if(mask == NULL) return false;
+       if(readfn == NULL) return false;
+       if(writefn == NULL) return false;
+       if(readp == NULL) return false;
+       if(writep == NULL) return false;
 
-       if(addr < 0xc0000) {
-               page0[addr] = (uint8_t)data;
-       } else if(addr < 0xc8000) {
-               if(d_vram != NULL) {
-                       d_vram->write_plane_data8(addr & 0x7fff, data);
-                       if(wait != NULL) *wait = vram_wait_val;
-               }
-       } else if(addr < 0xd0000) {
-               // MMIO, VRAM and ram.
-               if(0xcff80 <= addr && addr < 0xcffe0) {
-#ifdef _DEBUG_LOG
-//                     this->out_debug_log(_T("MW\t%4x, %2x\n"), addr, data);
-#endif
-                       // memory mapped i/o
-                       switch(addr & 0xffff) {
-                       case 0xff80:
-                               // mix register
-                               mix = data;
-                               break;
-                       case 0xff81:
-                               // update register
-                               wplane = data & 7;
-                               rplane = (data >> 6) & 3;
-                               update_bank();
-                               break;
-                       case 0xff82:
-                               // display ctrl register
-                               dispctrl = data;
-                               update_bank();
-                               break;
-                       case 0xff83:
-                               // page select register
-                               pagesel = data;
-                               update_bank();
-                               break;
-                       case 0xff88:
-                               // access start register
-                               accaddr = (accaddr & 0xff) | ((data & 0x7f) << 8);
-                               break;
-                       case 0xff89:
-                               // access start register
-                               accaddr = (accaddr & 0xff00) | (data & 0xfe);
-                               break;
-                       case 0xff8a:
-                               // display start register
-                               dispaddr = (dispaddr & 0xff) | ((data & 0x7f) << 8);
-                               break;
-                       case 0xff8b:
-                               // display start register
-                               dispaddr = (dispaddr & 0xff00) | (data & 0xfe);
-                               break;
-                       case 0xff8e:
-                               // crtc addr register
-                               d_crtc->write_io8(0, data);
-                               break;
-                       case 0xff8f:
-                               // crtc data register
-                               d_crtc->write_io8(1, data);
-                               break;
-                       case 0xff94:
-                               kj_h = data & 0x7f;
-                               break;
-                       case 0xff95:
-                               kj_l = data & 0x7f;
-                               kj_row = 0;
-                               if(kj_h < 0x30) {
-                                       kj_ofs = (((kj_l - 0x00) & 0x1f) <<  5) | (((kj_l - 0x20) & 0x20) <<  9) | (((kj_l - 0x20) & 0x40) <<  7) | (((kj_h - 0x00) & 0x07) << 10);
-                               } else if(kj_h < 0x70) {
-                                       kj_ofs = (((kj_l - 0x00) & 0x1f) <<  5) + (((kj_l - 0x20) & 0x60) <<  9) + (((kj_h - 0x00) & 0x0f) << 10) + (((kj_h - 0x30) & 0x70) * 0xc00) + 0x08000;
-                               } else {
-                                       kj_ofs = (((kj_l - 0x00) & 0x1f) <<  5) | (((kj_l - 0x20) & 0x20) <<  9) | (((kj_l - 0x20) & 0x40) <<  7) | (((kj_h - 0x00) & 0x07) << 10) | 0x38000;
-                               }
-                               break;
-                       case 0xff96:
-                               kanji16[(kj_ofs | ((kj_row & 0xf) << 1)) & 0x3ffff] = data;
-                               break;
-                       case 0xff97:
-                               kanji16[(kj_ofs | ((kj_row++ & 0xf) << 1) | 1) & 0x3ffff] = data;
-                               break;
-                       case 0xff99:
-                               ankcg = data;
-                               update_bank();
-                               break;
-                       case 0xffa0:
-                               cmdreg = data;
-                               break;
-                       case 0xffa1:
-                               imgcol = data;
-                               break;
-                       case 0xffa2:
-                               maskreg = data;
-                               break;
-                       case 0xffa3:
-                       case 0xffa4:
-                       case 0xffa5:
-                       case 0xffa6:
-                       case 0xffa7:
-                       case 0xffa8:
-                       case 0xffa9:
-                       case 0xffaa:
-                               compreg[addr & 7] = data;
-                               break;
-                       case 0xffab:
-                               bankdis = data;
-                               break;
-                       case 0xffac:
-                       case 0xffad:
-                       case 0xffae:
-                       case 0xffaf:
-                               tilereg[addr & 3] = data;
-                               break;
-                       case 0xffb0:
-                               lofs = (lofs & 0xff) | (data << 8);
-                               break;
-                       case 0xffb1:
-                               lofs = (lofs & 0xff00) | data;
-                               break;
-                       case 0xffb2:
-                               lsty = (lsty & 0xff) | (data << 8);
-                               break;
-                       case 0xffb3:
-                               lsty = (lsty & 0xff00) | data;
-                               break;
-                       case 0xffb4:
-                               lsx = (lsx & 0xff) | (data << 8);
-                               break;
-                       case 0xffb5:
-                               lsx = (lsx & 0xff00) | data;
-                               break;
-                       case 0xffb6:
-                               lsy = (lsy & 0xff) | (data << 8);
-                               break;
-                       case 0xffb7:
-                               lsy = (lsy & 0xff00) | data;
-                               break;
-                       case 0xffb8:
-                               lex = (lex & 0xff) | (data << 8);
-                               break;
-                       case 0xffb9:
-                               lex = (lex & 0xff00) | data;
-                               break;
-                       case 0xffba:
-                               ley = (ley & 0xff) | (data << 8);
-                               break;
-                       case 0xffbb:
-                               ley = (ley & 0xff00) | data;
-                               // start drawing line
-                               line();
-                               break;
-                       }
-                       return;
+       *readfn = NULL;
+       *writefn = NULL;
+       *readp = NULL;
+       *writep = NULL;
+       *mask = 0x00;
+       *offset = 0;
+       switch(__type) {
+       case TOWNS_MEMORY_FMR_VRAM:
+               if(!mainmem_enabled) {
+                       *readfn = (void *)d_vram;
+                       *writefn = (void *)d_vram;
+                       *offset = FMTOWNS_VRAM_PLANE_ACCESS;
+                       *mask = 0x7fff;
+               } else {
+                       *readp = (void *)(&(ram_0c0[addr & 0x7fff]));
+                       *writep = (void *)(&(ram_0c0[addr & 0x7fff]));
+                       *mask = 0x7fff;
                }
-       } else if(addr < 0xd8000) {
-               if(!bankd0_dict) {
-                       ram_0d0[addr - 0x0d0000] = (uint8_t)data;
-                       // RAM? DICT?
+               break;
+       case TOWNS_MEMORY_FMR_TEXT:
+               if(!mainmem_enabled) {
+                       if((addr & 0x1000) == 0) {
+                               *readfn = (void *)d_vram;
+                               *writefn = (void *)d_vram;
+                               *offset = FMTOWNS_VRAM_TEXT_VRAM;
+                               *mask = 0x0fff;
+                       } else {
+                               *mask = 0x1fff;
+                               *readp = (void*)(&(ram_0c8[addr & 0x1fff]));
+                               *writedp = (void*)(&(ram_0c8[addr & 0x1fff]));
+                       }                                               
                } else {
-                       // DICT
-                       //dict_rom[addr - 0xd0000 + (((uint32_t)dict_bank) << 15))
+                       *mask = 0x1fff;
+                       *readp = (void*)(&(ram_0c8[addr & 0x1fff]));
+                       *writedp = (void*)(&(ram_0c8[addr & 0x1fff]));
                }
-       } else if(addr < 0xda000) {
-               if(!bankd0_dict) {
-                       // RAM? DICT?
-                       ram_0d0[addr - 0x0d0000] = (uint8_t)data;
+               break;
+       case TOWNS_MEMORY_MMIO_0CC:
+               if(!mainmem_enabled) {
+                       if((addr & 0xfffff) < 0xcff80) {
+                               *mask = 0x3fff;
+                               *readp = (void*)(&(ram_0cc[addr & 0x3fff]));
+                               *writedp = (void*)(&(ram_0cc[addr & 0x3fff]));
+                       }
                } else {
-                       // DICT
-                       if(d_cmos != NULL) d_cmos->write_data8(addr, data);
-                       return;
+                       *mask = 0x3fff;
+                       *readp = (void*)(&(ram_0cc[addr & 0x3fff]));
+                       *writedp = (void*)(&(ram_0cc[addr & 0x3fff]));
                }
-       } else if(addr < 0xf0000) {
-               if(!bankd0_dict) {
-                       ram_0d0[addr - 0x0d0000] = (uint8_t)data;
+               break;
+       case TOWNS_MEMORY_SPRITE_ANKCG1:
+               if(!mainmem_enabled) {
+                       if(ankcg_enabled) {
+                               *offset = 0x000ca000;
+                               *mask = 0x0fff;
+                               *readfn = (void *)d_fonts;
+                               *writefn = (void *)d_fonts;
+                       } else {
+                               *offset = 0x2000 + FMTOWNS_VRAM_TEXT_VRAM;
+                               *mask = 0x0fff;
+                               *readfn = (void *)d_vram;
+                               *writefn = (void *)d_vram;
+                       }
+               } else {
+                       *readp = (void*)(&(ram_0ca[addr & 0xfff]));
+                       *writep = (void*)(&(ram_0ca[addr & 0xfff]));
                }
-       } else if(addr < 0xf8000) {
-               ram_0f0[addr - 0xf0000] = (uint8_t)data;
-       } else if(addr < 0x100000) {
-               if(bankf8_ram) {
-                       // RAM
-                       ram_0f8[addr - 0xf8000] = (uint8_t)data;
+               break;
+       case TOWNS_MEMORY_SPRITE_ANKCG2:
+               if(!(mainmem_enabled) && (ankcg_enabled)) {
+                       *offset = 0x000cb000;
+                       *mask = 0x0fff;
+                       *readfn = (void *)d_fonts;
+                       *writefn = (void *)d_fonts;
                } else {
-                       // BOOT ROM(ro)
-                       //system_rom[addr - 0xf8000 + 0x18000];
+                       *readp = (void*)(&(ram_0cb[addr & 0xfff]));
+                       *writep = (void*)(&(ram_0cb[addr & 0xfff]));
+                       *mask = 0xfff;
+                       *offset = 0;
                }
+               break;
+       default:
+               return false;
+               break;
        }
+       return true;
+       
 }
 
-void TOWNS_MEMORY::initialize_tables(void)
+
+uint32_t TOWNS_MEMORY::read_data_base(uint32_t addr, int* wait, int wordsize)
 {
-       memset(extram_adrs, 0x00, sizeof(extram_adrs));
-       if(extram_base == NULL) {
-               extram_pages = 0;
-       } else {
-               for(uint32_t ui = 0; ui < extram_pages; ui++) {
-                       uint8_t *p;
-                       p = &(extram_base[ui << 20]);
-                       extram_adrs[ui] = p;
-               }
+       uint8_t *maddr;
+       DEVICE *daddr;
+       uint32_t banknum = addr >> 12;
+       uint32_t _naddr;
+       switch(wordsize) {
+       case 2:
+               _naddr = addr & 0xfffffffe;
+               break;
+       case 4:
+               _naddr = addr & 0xfffffffc;
+               break;
+       dafault:
+               _naddr = addr;
+               break;
        }
-       // Address Cx000000
-       memset(write_bank_adrs_cx, 0x00, sizeof(write_bank_adrs_cx));
-       memset(read_bank_adrs_cx, 0x00, sizeof(read_bank_adrs_cx));
-       memset(device_bank_adrs_cx, 0x00, sizeof(device_bank_adrs_cx));
-       
-       for(uint32_t ui = 0x0000; ui < 0x4000; ui++) {
-               if(ui < 0x2000) {
-                       // ROM CARD?
-               } else if(ui < 0x2080) {
-                       read_bank_adrs_cx[ui] = &(msdos_rom[(ui - 0x2000) << 12]);
-               } else if(ui < 0x2100) {
-                       read_bank_adrs_cx[ui] = &(dict_rom[(ui - 0x2080) << 12]);
-               } else if(ui < 0x2140) {
-                       read_bank_adrs_cx[ui] = &(font_rom[(ui - 0x2100) << 12]);
-               } else if(ui < 0x2142) {
-                       devicetype_adrs_cx[ui] = TOWNS_MEMORY_TYPE_DICTLEARN;
-               } eise if(ui < 0x2200) {
-                       // Reserved.
-               } else if(ui < 0x2201) {
-                       devicetype_adrs_cx[ui] = TOWNS_MEMORY_TYPE_WAVERAM;
+               
+       maddr = read_bank_adrs_cx[banknum];
+       if(maddr != NULL)  {
+               // Memory found.
+               if(wait != NULL) *wait = mem_wait_val;
+               uint8_t *p;
+               switch(wordsize) {
+               case 1:
+                       p = &maddr[addr & 0x00000fff];
+                       return (uint32_t)(*p);
+                       break;
+               case 2:
+                       {
+                               pair16_t _d;
+                               p = &maddr[addr & 0x00000ffe];
+#if defined(__LITTLE_ENDIAN__)
+                               uint16_t* pp = (uint16_t*)p;
+                               _d.u16 = *pp;
+#else
+                               _d.l = p[0];
+                               _d.h = p[1];
+#endif
+                               return _d.u16;
+                       }
+                       break;
+               case 4:
+                       {
+                               pair32_t _d;
+                               p = &maddr[addr & 0x00000ffc];
+#if defined(__LITTLE_ENDIAN__)
+                               uint32_t* pp = (uint32_t*)p;
+                               _d.u32 = *pp;
+#else
+                               _d.l  = p[0];
+                               _d.h  = p[1];
+                               _d.h2 = p[2];
+                               _d.h3 = p[3];
+#endif
+                               return _d.u32;
+                       }
+                       break;
+               default:
+                       return 0xffffffff; // Word size error
+                       break;
+               }
+       } else {
+               daddr = device_bank_adrs_cx[banknum];
+               if(daddr != NULL) {
+                       // Device chained.
+                       switch(wordsize) {
+                       case 1:
+                               return daddr->read_data8w(addr, wait);
+                               break;
+                       case 2:
+                               return daddr->read_data16w(addr, wait);
+                               break;
+                       case 4:
+                               return daddr->read_data32w(addr, wait);
+                               break;
+                       default:
+                               return 0xffffffff;
+                               break;
+                       }
                } else {
-                       // Reserved.
+                       uint32_t _mask;
+                       uint32_t _offset;
+                       DEVICE* readfn;
+                       DEVICE* writefn;
+                       uint8_t* readp;
+                       uint8_t* writep;
+                       if(check_bank(_naddr, &_mask, &_offset, (void**)(&readfn), (void**)(&writefn), (void**)(&readp), (void**)(&writep))) {
+                               switch(wordsize)
+                               {
+                               case 1:
+                                       if(readp != NULL) {
+                                               if(wait != NULL) *wait = mem_wait_val;
+                                               return (uint32_t)(*readp);
+                                       } else if(readfn != NULL) {
+                                               return readfn->read_data8w(_naddr, wait);
+                                       } else {
+                                               return 0xff;
+                                       }
+                                       break;
+                               case 2:
+                                       if(readp != NULL) {
+                                               
+                                               if(wait != NULL) *wait = mem_wait_val;
+#if defined(__LITTLE_ENDIAN__)
+                                               uint16_t *pp = (uint16_t*)readp;
+                                               return (uint32_t)(*pp);
+#else
+                                               pair16_t _d;
+                                               pair16_t *pp = (pair16_t*)readp;
+                                               _d.l = pp[0];
+                                               _d.h = pp[1];
+                                               return _d.u16;
+#endif
+                                       } else if(readfn != NULL) {
+                                               return readfn->read_data16w(_naddr, wait);
+                                       } else {
+                                               return 0xffff;
+                                       }
+                                       break;
+                               case 2:
+                                       if(readp != NULL) {
+                                               
+                                               if(wait != NULL) *wait = mem_wait_val;
+#if defined(__LITTLE_ENDIAN__)
+                                               uint32_t *pp = (uint32_t*)readp;
+                                               return (uint32_t)(*pp);
+#else
+                                               pair32_t _d;
+                                               _d.l  = readp[0];
+                                               _d.h  = readp[1];
+                                               _d.h2 = readp[2];
+                                               _d.h3 = readp[3];
+                                               return _d.u32;
+#endif
+                                       } else if(readfn != NULL) {
+                                               return readfn->read_data32w(_naddr, wait);
+                                       } else {
+                                               return 0xffffffff;
+                                       }
+                                       break;
+                               default:
+                                       return 0xffffffff;
+                                       break;
+                               }                                       
+                               // Function or memory don't exist this bank.
+                       } else {
+                               // Bank not registered.
+                               if((addr >= 0x000cff80) && (addr <= 0x000cffff)) {
+                                       bool _hit;
+                                       uint32_t val;
+                                       val = read_mmio(addr, wait, &_hit);
+                                       if(!_hit) {
+                                               ///
+                                       } else {
+                                               return val;
+                                       }
+                               }
+                       }
                }
+               // Neither memory nor device nor bank.
        }
-}
-void TOWNS_MEMORY::write_data8(uint32_t addr, uint32_t data)
+       return 0xffffffff;
+}              
+
+uint32_t TOWNS_MEMORY::read_data8w(uint32_t addr, int *wait)
 {
-       int wait = 0;
-       write_data8w(addr, data, &wait);
+       return read_data_base(addr, wait, 1);
 }
-
-void TOWNS_MEMORY::write_data16(uint32_t addr, uint32_t data)
+uint32_t TOWNS_MEMORY::read_data16w(uint32_t addr, int *wait)
 {
-       int wait = 0;
-       write_data16w(addr, data, &wait);
+       return read_data_base(addr, wait, 2);
 }
 
-void TOWNS_MEMORY::write_data32(uint32_t addr, uint32_t data)
+uint32_t TOWNS_MEMORY::read_data32w(uint32_t addr, int *wait)
 {
-       int wait = 0;
-       write_data32w(addr, data, &wait);
+       return read_data_base(addr, wait, 4);
 }
 
-void TOWNS_MEMORY::write_data8w(uint32_t addr, uint32_t data, int *wait)
+void TOWNS_MEMORY::write_data_base(uint32_t addr, uint32_t data, int* wait, int wordsize)
 {
-       uint32_t addr_head = (addr & 0xf0000000) >> 28;
-       uint32_t addr_mid;
-       uint32_t addr_low;
-       uint32_t ui;
-       uint8_t *pp;
-       
-       if(wait != NULL) *wait = mem_wait_val;
-       switch(addr_head) {
-       case 0x0:
-       case 0x1:
-       case 0x2:
-       case 0x3:
-               if(addr < 0x00100000) {
-                       write_page0_8(addr, data, wait);
-               } else {
-                       ui = (((addr - 0x00100000) & 0x3ff00000) >> 20);
-                       uint8_t *p = extram_adrs[ui];
-                       if(p != NULL) {
-                               addr_low = addr & 0x000fffff;
-                               p[addr_low] = (uint8_t)data;
-                       }
-               }
+       uint8_t *maddr;
+       DEVICE *daddr;
+       uint32_t banknum = addr >> 12;
+       uint32_t _naddr;
+       switch(wordsize) {
+       case 2:
+               _naddr = addr & 0xfffffffe;
                break;
        case 4:
-       case 5:
-       case 6:
-       case 7:
-               if(extio != NULL) extio->write_data8(addr, data);
-               break;
-       case 8:
-               if(d_vram != NULL) {
-                       d_vram->write_data8(addr, data);
-                       if(wait != NULL) *wait = vram_wait_val;
-               }
+               _naddr = addr & 0xfffffffc;
                break;
-       case 9:
-       case 0x0a:
-       case 0x0b:
-               // ??
-               break;
-       case 0x0c:
-               addr_mid = (addr & 0x03fff000) >> 16 ;
-               addr_low = addr & 0x00000fff;
-               pp = write_bank_adrs_cx[addr_mid];
-               if(pp != NULL) {
-                       pp[addr_low] = (uint8_t)data;
-               } else if(device_type_adrs_cx[addr_mid] != 0) {
-                       switch(device_type_adrs_cx[addr_mid]) {
-                       case TOWNS_MEMORY_TYPE_WAVERAM:
-                               if(d_pcm != NULL) {
-                                       d_pcm->write_data8(addr, data);
-                               }
-                               break;
-                       case TOWNS_MEMORY_TYPE_DICTLEARN:
-                               if(d_cmos != NULL) {
-                                       d_cmos->write_data8(addr, data);
-                               }
-                               break;
-                       case TOWNS_MEMORY_TYPE_FORBID:
-                       default:
-                               break;
-                       }
-               }
-               break;
-       case 0x0d:
-       case 0x0e:
-               // ??
-               break;
-       case 0x0f:
-               // ROM, maybe unable to write.
+       dafault:
+               _naddr = addr;
                break;
        }
-}
-
-void TOWNS_MEMORY::write_data16w(uint32_t addr, uint32_t data, int *wait)
-{
-       uint32_t addr_head = (addr & 0xf0000000) >> 28;
-       uint32_t addr_low;
-       uint32_t addr_mid;
-       uint16_t *pp;
-       if(wait != NULL) *wait = mem_wait_val;
-       switch(addr_head) {
-       case 0x0:
-       case 0x1:
-       case 0x2:
-       case 0x3:
-               if(addr < 0x00100000) {
-                       write_page0_16(addr, data, wait);
-               } else {
-                       ui = (((addr - 0x00100000) & 0x3ff00000) >> 20);
-                       uint16_t *p = (uint16_t *)extram_adrs[ui];
-                       if(p != NULL) {
-                               addr_low = (addr & 0x000fffff) >> 1;
-#if __LITTLE_ENDIAN__
-                               p[addr_low] = (uint16_t)data;
+               
+       maddr = write_bank_adrs_cx[banknum];
+       if(maddr != NULL)  {
+               // Memory found.
+               if(wait != NULL) *wait = mem_wait_val;
+               uint8_t *p;
+               switch(wordsize) {
+               case 1:
+                       p = &maddr[addr & 0x00000fff];
+                       *p = (uint8_t)data;
+                       return;
+                       break;
+               case 2:
+                       {
+                               pair16_t _d;
+                               _d.u16 = (uint16_t)data;
+                               p = &maddr[addr & 0x00000ffe];
+#if defined(__LITTLE_ENDIAN__)
+                               uint16_t* pp = (uint16_t*)p;
+                               *pp = _d.u16;
 #else
-                               uint8_t *p8 = (uint8_*)(&(p[addr_low]));
-                               pair_t d;
-                               d.d = data;
-                               d.write_2bytes_le_to(p8);
+                               p[0] = _d.l;
+                               p[1] = _d.h;
 #endif
+                               return;
                        }
-               }
-               break;
-       case 4:
-       case 5:
-       case 6:
-       case 7:
-               if(extio != NULL) extio->write_data16(addr, data);
-               break;
-       case 8:
-               if(d_vram != NULL) {
-                       d_vram->write_data16(addr, data);
-                       if(wait != NULL) *wait = mem_wait_val;
-               }
-               break;
-       case 9:
-       case 0x0a:
-       case 0x0b:
-               // ??
-               break;
-       case 0x0c:
-               addr_mid = (addr & 0x03fff000) >> 16 ;
-               addr_low = addr & 0x00000fff;
-               pp = (uint16_t *)write_bank_adrs_cx[addr_mid];
-               if(pp != NULL) {
-#if __LITTLE_ENDIAN__
-                       pp[addr_low >> 1] = (uint16_t)data;
+                       break;
+               case 4:
+                       {
+                               pair32_t _d;
+                               _d.u32 = data;
+                               p = &maddr[addr & 0x00000ffc];
+#if defined(__LITTLE_ENDIAN__)
+                               uint32_t* pp = (uint32_t*)p;
+                               *pp = data;
 #else
-                       uint8_t *p8 = (uint8_*)(&(pp[addr_low]));
-                       pair_t d;
-                       d.d = data;
-                       d.write_2bytes_le_to(p8);
+                               p[0] = _d.l;
+                               p[1] = _d.h;
+                               p[2] = _d.h2;
+                               p[3] = _d.h3;
 #endif
-               } else if(device_type_adrs_cx[addr_mid] != 0) {
-                       switch(device_type_adrs_cx[addr_mid]) {
-                       case TOWNS_MEMORY_TYPE_WAVERAM:
-                               if(d_pcm != NULL) {
-                                       d_pcm->write_data8(addr, data);
-                               }
+                               return;
+                       }
+                       break;
+               default:
+                       return; // Word size error
+                       break;
+               }
+       } else {
+               daddr = device_bank_adrs_cx[banknum];
+               if(daddr != NULL) {
+                       // Device chained.
+                       switch(wordsize) {
+                       case 1:
+                               daddr->write_data8w(addr, data, wait);
                                break;
-                       case TOWNS_MEMORY_TYPE_DICTLEARN:
-                               if(d_cmos != NULL) {
-                                       d_cmos->write_data8(addr, data);
-                               }
+                       case 2:
+                               daddr->write_data16w(addr, data, wait);
+                               break;
+                       case 4:
+                               daddr->write_data32w(addr, data, wait);
                                break;
-                       case TOWNS_MEMORY_TYPE_FORBID:
                        default:
                                break;
                        }
-               }
-               break;
-       case 0x0d:
-       case 0x0e:
-               // ??
-               break;
-       case 0x0f:
-               // ROM, maybe unable to write.
-               break;
-       }
-}
-
-void TOWNS_MEMORY::write_data32w(uint32_t addr, uint32_t data, int *wait)
-{
-       uint32_t addr_head = (addr & 0xf0000000) >> 28;
-       uint32_t addr_low;
-       uint32_t addr_mid;
-       uint32_t *pp;
-       if(wait != NULL) *wait = mem_wait_val;
-       switch(addr_head) {
-       case 0x0:
-       case 0x1:
-       case 0x2:
-       case 0x3:
-               if(addr < 0x00100000) {
-                       write_page0_32(addr, data, wait);
+                       return;
                } else {
-                       ui = (((addr - 0x00100000) & 0x3ff00000) >> 20);
-                       uint32_t *p = (uint32_t *)extram_adrs[ui];
-                       if(p != NULL) {
-                               addr_low = (addr & 0x000fffff) >> 2;
-#if __LITTLE_ENDIAN__
-                               p[addr_low] = data;
+                       uint32_t _mask;
+                       uint32_t _offset;
+                       DEVICE* readfn;
+                       DEVICE* writefn;
+                       uint8_t* readp;
+                       uint8_t* writep;
+                       if(check_bank(_naddr, &_mask, &_offset, (void**)(&readfn), (void**)(&writefn), (void**)(&readp), (void**)(&writep))) {
+                               switch(wordsize)
+                               {
+                               case 1:
+                                       if(writep != NULL) {
+                                               if(wait != NULL) *wait = mem_wait_val;
+                                               *writep = (uint8_t)data;
+                                       } else if(writefn != NULL) {
+                                               writefn->write_data8w(_naddr, data, wait);
+                                       }
+                                       break;
+                               case 2:
+                                       if(writep != NULL) {
+                                               
+                                               if(wait != NULL) *wait = mem_wait_val;
+#if defined(__LITTLE_ENDIAN__)
+                                               uint16_t *pp = (uint16_t*)writep;
+                                               *pp = (uint16_t)data;
 #else
-                               uint8_t *p8 = (uint8_*)(&(p[addr_low]));
-                               pair_t d;
-                               d.d = data;
-                               d.write_4bytes_le_to(p8);
+                                               pair16_t _d;
+                                               _d.u16 = (uint16_t)data;
+                                               writep[0] = _d.l;
+                                               writep[1] = _d.h;
 #endif
-                       }
-               }
-               break;
-       case 4:
-       case 5:
-       case 6:
-       case 7:
-               if(extio != NULL) extio->write_data32(addr, data);
-               break;
-       case 8:
-               if(d_vram != NULL) {
-                       d_vram->write_data32(addr, data);
-                       if(wait != NULL) *wait = vram_wait_val;
-               }
-               break;
-       case 9:
-       case 0x0a:
-       case 0x0b:
-               // ??
-               break;
-       case 0x0c:
-               addr_mid = (addr & 0x03fff000) >> 16 ;
-               addr_low = (addr & 0x00000fff >> 2);
-               pp = (uint32_t *)write_bank_adrs_cx[addr_mid];
-               if(pp != NULL) {
-#if __LITTLE_ENDIAN__
-                       pp[addr_low >> 2] = data;
+                                       } else if(writefn != NULL) {
+                                               writefn->write_data16w(_naddr, data, wait);
+                                       }
+                                       break;
+                               case 4:
+                                       if(writep != NULL) {
+                                               
+                                               if(wait != NULL) *wait = mem_wait_val;
+#if defined(__LITTLE_ENDIAN__)
+                                               uint32_t *pp = (uint32_t*)writep;
+                                               *pp = (uint32_t)data;
 #else
-                       uint8_t *p8 = (uint8_*)(&(pp[addr_low]));
-                       pair_t d;
-                       d.d = data;
-                       d.write_4bytes_le_to(p8);
+                                               pair32_t _d;
+                                               _d.u32 = data;
+                                           writep[0] = _d.l;
+                                           writep[1] = _d.h;
+                                           writep[2] = _d.h2;
+                                           writep[3] = _d.h3;
 #endif
-               } else if(device_type_adrs_cx[addr_mid] != 0) {
-                       switch(device_type_adrs_cx[addr_mid]) {
-                       case TOWNS_MEMORY_TYPE_WAVERAM:
-                               if(d_pcm != NULL) {
-                                       d_pcm->write_data8(addr, data);
+                                       } else if(writefn != NULL) {
+                                               writefn->write_data32w(_naddr, data, wait);
+                                       }
+                                       break;
+                               default:
+                                       break;
+                               }                                       
+                               return;
+                               // Function or memory don't exist this bank.
+                       } else {
+                               // Bank not registered.
+                               if((addr >= 0x000cff80) && (addr <= 0x000cffff)) {
+                                       bool _hit;
+                                       write_mmio(addr, data, wait, &_hit); // ToDo: Not Hit
                                }
-                               break;
-                       case TOWNS_MEMORY_TYPE_DICTLEARN:
-                               if(d_cmos != NULL) {
-                                       d_cmos->write_data8(addr, data);
-                               }
-                               break;
-                       case TOWNS_MEMORY_TYPE_FORBID:
-                       default:
-                               break;
                        }
                }
-               break;
-       case 0x0d:
-       case 0x0e:
-               // ??
-               break;
-       case 0x0f:
-               // ROM, maybe unable to write.
-               break;
+               // Neither memory nor device nor bank.
        }
+       return;
+}              
+
+void TOWNS_MEMORY::write_data8w(uint32_t addr, uint32_t data, int *wait)
+{
+       write_data_base(addr, data, wait, 1);
 }
 
-uint32_t TOWNS_MEMORY::read_page0_8(uint32_t addr, int *wait)
+void TOWNS_MEMORY::write_data16w(uint32_t addr, uint32_t data, int *wait)
 {
+       write_data_base(addr, data, wait, 2);
+}
 
-       addr = addr & 0x000fffff;
-       if(wait != NULL) *wait = mem_wait_val;
-       if(addr < 0xc0000) {
-               return page0[addr];
-       } else if(addr < 0xc8000) {
-               if(d_vram != NULL) {
-                       if(wait != NULL) *wait = vram_wait_val;
-                       return d_vram->read_plane_data8(addr 0x7fff);
-               }
-               return 0xff;
-       } else if(addr < 0xd0000) {
-               // MMIO, VRAM and ram.
-               if(0xcff80 <= addr && addr < 0xcffe0) {
-#ifdef _DEBUG_LOG
-//                     this->out_debug_log(_T("MR\t%4x\n"), addr);
-#endif
-                       // memory mapped i/o
-                       switch(addr & 0xffff) {
-                       case 0xff80:
-                               // mix register
-                               return mix;
-                       case 0xff81:
-                               // update register
-                               return wplane | (rplane << 6);
-                       case 0xff83:
-                               // page select register
-                               return pagesel;
-                       case 0xff86:
-                               // status register
-                               return (disp ? 0x80 : 0) | (vsync ? 4 : 0) | 0x10;
-                       case 0xff8e:
-                               // crtc addr register
-                               return d_crtc->read_io8(0);
-                       case 0xff8f:
-                               // crtc data register
-                               return d_crtc->read_io8(1);
-                       case 0xff94:
-                               return 0x80;    // ???
-                       case 0xff96:
-                               return kanji16[(kj_ofs | ((kj_row & 0xf) << 1)) & 0x3ffff];
-                       case 0xff97:
-                               return kanji16[(kj_ofs | ((kj_row++ & 0xf) << 1) | 1) & 0x3ffff];
-                       case 0xffa0:
-                               return cmdreg;
-                       case 0xffa1:
-                               return imgcol | 0xf0;
-                       case 0xffa2:
-                               return maskreg;
-                       case 0xffa3:
-                               return compbit;
-                       case 0xffab:
-                               return bankdis & 0xf;
-                       }
-                       return 0xff;
-               }
-       } else if(addr < 0xd8000) {
-               if(!bankd0_dict) {
-                       return ram_0d0[addr - 0x0d0000];
-                       // RAM? DICT?
-               } else {
-                       // DICT
-                       return dict_rom[addr - 0xd0000 + (((uint32_t)dict_bank) << 15))];
-               }
-       } else if(addr < 0xda000) {
-               if(!bankd0_dict) {
-                       // RAM? DICT?
-                       return ram_0d0[addr - 0x0d0000];
-               } else {
-                       // DICT
-                       if(d_cmos != NULL) return d_cmos->read_data8(addr);
-                       return;
-               }
-       } else if(addr < 0xf0000) {
-               if(!bankd0_dict) {
-                       return ram_0d0[addr - 0x0d0000];
-               }
-               return 0xff;
-       } else if(addr < 0xf8000) {
-               return ram_0f0[addr - 0xf0000];
-       } else if(addr < 0x100000) {
-               if(bankf8_ram) {
-                       // RAM
-                       return ram_0f8[addr - 0xf8000];
-               } else {
-                       // BOOT ROM(ro)
-                       return system_rom[addr - 0xf8000 + 0x18000];
-               }
-       }
-       return 0xff;
+void TOWNS_MEMORY::write_data32w(uint32_t addr, uint32_t data, int *wait)
+{
+       write_data_base(addr, data, wait, 4);
 }
 
 
+
 uint32_t TOWNS_MEMORY::read_data8(uint32_t addr)
 {
-       int wait;
-       return read_data8w(addr, &wait);
+       return read_data_base(addr, NULL, 1);
 }
 
 uint32_t TOWNS_MEMORY::read_data16(uint32_t addr)
 {
-       int wait;
-       return read_data16w(addr, &wait);
+       return read_data_base(addr, NULL, 2);
 }
 
 uint32_t TOWNS_MEMORY::read_data32(uint32_t addr)
 {
-       int wait;
-       return read_data32w(addr, &wait);
+       return read_data_base(addr, NULL, 4);
 }
 
-uint32_t TOWNS_MEMORY::read_data8w(uint32_t addr, int *wait)
+void TOWNS_MEMORY::write_data8(uint32_t addr, uint32_t data)
 {
-       uint32_t addr_head = (addr & 0xf0000000) >> 28;
-       uint32_t addr_mid;
-       uint32_t addr_low;
-       uint32_t ui;
-       uint8_t *pp;
-       
-       if(wait != NULL) *wait = mem_wait_val;
-       switch(addr_head) {
-       case 0x00:
-       case 0x01:
-       case 0x02:
-       case 0x03:
-               if(addr < 0x00100000) {
-                       return read_page0_8(addr, wait);
-               } else {
-                       ui = (((addr - 0x00100000) & 0x3ff00000) >> 20);
-                       pp = extram_adrs[ui];
-                       if(pp != NULL) {
-                               addr_low = addr & 0x000fffff;
-                               return pp[addr_low];
-                       }
-               }
-               return 0xff;
+       write_data_base(addr, data, NULL, 1);
+}
+
+void TOWNS_MEMORY::write_data16(uint32_t addr, uint32_t data)
+{
+       write_data_base(addr, data, NULL, 2);
+}
+
+void TOWNS_MEMORY::write_data32(uint32_t addr, uint32_t data)
+{
+       write_data_base(addr, data, NULL, 4);
+}
+
+// Address (TOWNS BASIC):
+// 0x0020 - 0x0022, 0x0030-0x0031,
+// 0x0400 - 0x0404,
+// 0x0480 - 0x0484
+// 0x05c0 - 0x05c2
+// 0x05ec (Wait register)
+// Is set extra NMI (0x05c0 - 0x05c2)?
+uint32_t TOWNS_MEMORY::read_io8(uint32_t addr)
+{
+       uint32_t val = 0xff;
+       switch(addr & 0xffff) {
+       case 0x0020: // Software reset ETC.
+               // reset cause register
+               val = ((software_reset) ? 1 : 0) | ((d_cpu->get_shutdown_flag() != 0) ? 2 : 0);
+               software_reset = false;
+               d_cpu->set_shutdown_flag(0);
+               val =  val | 0x7c;
                break;
-       case 0x04:
-       case 0x05:
-       case 0x06:
-       case 0x07:
-               if(extio != NULL) return extio->read_data8(addr);
+       case 0x0022:
+               // Power register
+               val = 0xff;
                break;
-       case 0x08:
-               if(d_vram != NULL) {
-                       if(wait != NULL) *wait = vram_wait_val;
-                       return d_vram->read_data8(addr);
+       case 0x0030:
+               val = (((machine_id & 0x1f) << 3) | (cpu_id & 7));
+               // SPEED: bit0/Write
+               break;
+       case 0x0031:
+               val = ((machine_id >> 5) & 0xff);
+               break;
+       case 0x0032:
+               {
+                       //bool __cs = (d_serialrom->read_data8(SIG_SERIALROM_CS) == 0);
+                       bool __clk = (d_serialrom->read_data8(SIG_SERIALROM_CLK) != 0);
+                       bool __reset = (d_serialrom->read_data8(SIG_SERIALROM_RESET) != 0);
+                       bool __dat = (d_serialrom->read_data8(SIG_SERIALROM_DATA) != 0);
+                       val = ((__reset) ? 0x80 : 0x00) | ((__clk) ? 0x40 : 0x00) | 0x3e | ((__dat) ? 0x01 : 0x00);
+               }
+               break;
+       case 0x006c: // Wait register.
+               if(machine_id >= 0x0300) { // After UX*/10F/20F/40H/80H
+                       val = 0x7f;
                }
                break;
-       case 0x09:
-       case 0x0a:
-       case 0x0b:
-               return 0xff;
-               // ??
+       case 0x0400: // Resolution:
+               val = 0xfe;
                break;
-       case 0x0c:
-               addr_mid = (addr & 0x03fff000) >> 12 ;
-               pp = read_bank_adrs_cx[addr_mid];
-               if(pp != NULL) {
-                       addr_low = addr & 0x00000fff;
-                       return pp[addr_low];
-               } else if(device_type_adrs_cx[addr_mid] != 0) {
-                       switch(device_type_adrs_cx[addr_mid]) {
-                       case TOWNS_MEMORY_TYPE_WAVERAM:
-                               if(d_pcm != NULL) {
-                                       return d_pcm->read_data8((addr & 0x0ffe));
-                               }
+       case 0x0404: // System Status Reg.
+               val = (bankc0_vram) ? 0x7f : 0xff;
+               break;
+       case 0x05c0:
+               val = (extra_nmi_mask) ? 0xf7 : 0xff;
+               break;
+       case 0x05c2:
+               val = (extra_nmi_val) ? 0xff : 0xf7;
+               break;
+       case 0x05e8:
+               // After Towns1F/2F/1H/2H
+               {
+                       switch(machine_id & 0xff00) {
+                       case 0x0000:
+                       case 0x0100:
+                               val = 0xff;
                                break;
-                       case TOWNS_MEMORY_TYPE_DICTLEARN:
-                               if(d_cmos != NULL) {
-                                       return d_cmos->read_data8((addr & 0x0ffe));
-                               }
+                       case 0x0200:
+                       case 0x0300:
+                       case 0x0400:
+                       case 0x0500:
+                       case 0x0600:
+                       case 0x0700:
+                       case 0x0800:
+                       case 0x0a00:
+                               val = ((extram_size >> 20) & 0x1f);
+                               break;
+                       case 0x0b00:
+                       case 0x0c00:
+                       case 0x0d00:
+                       case 0x0f00:
+                               val = ((extram_size >> 20) & 0x7f);
                                break;
-                       case TOWNS_MEMORY_TYPE_FORBID:
                        default:
-                               return 0xff;
+                               val = 0xff; // ???
                                break;
                        }
-                       return 0xff;
-               } else {
-                       return 0xff;
                }
                break;
-       case 0x0d:
-       case 0x0e:
-               // ??
-               return 0xff;
+          
+       case 0x05ec:
+               if(machine_id >= 0x0500) { // Towns2 CX : Is this hidden register after Towns 1F/2F/1H/2H?
+                  val = 0x00 | ((mem_wait_val > 0) ? 0x01 : 0x00); 
+               }
+               break;
+       default:
                break;
-       case 0x0f:
-               // ROM, maybe unable to write.
-               if(addr < 0xfffc0000) {
-                       return 0xff;
+       }
+       return val;
+}
+
+void TOWNS_MEMORY::write_io8(uint32_t addr, uint32_t data)
+{
+
+       switch(addr & 0xffff) {
+       case 0x0020: // Software reset ETC.
+               // reset cause register
+               if((data & 0x80) != 0) {
+                       nmi_vector_protect = true;
+               } else {
+                       nmi_vector_protect = false;
+               }
+               if((data & 0x01) != 0) {
+                       software_reset = true;
                } else {
-                       pp = system_rom;
-                       addr_low = addr - 0xfffc0000;
-                       return (uint32_t)pp[addr_low];
+                       software_reset = false;
+               }
+               if((data & 0x40) != 0) {
+                       d_cpu->set_shutdown_flag(1);
+                       emu->power_off();
+               }
+               if(software_reset) {
+                       d_cpu->reset();
+               }
+               break;
+       case 0x0022:
+               if((data & 0x40) != 0) {
+                       d_cpu->set_shutdown_flag(1);
+                       emu->power_off();
+               }
+               // Power register
+               break;
+       case 0x0032:
+               {
+                       d_serialrom->write_data8(SIG_SERIALROM_CS, ~data, 0x20);
+                       d_serialrom->write_data8(SIG_SERIALROM_CLK, data, 0x40);
+                       d_serialrom->write_data8(SIG_SERIALROM_RESET, data, 0x80);
+               }
+               break;
+       case 0x006c: // Wait register.
+               if(machine_id >= 0x0300) { // After UX*/10F/20F/40H/80H
+                       if(event_wait_1us != -1) cancel_event(this, event_wait_1us);
+                       register_event(this, EVENT_1US_WAIT, 1.0, false, &event_wait_1us);
+                       d_cpu->write_signal(SIG_CPU_BUSREQ, 1, 1);
                }
                break;
+       case 0x0404: // System Status Reg.
+               bankc0_vram = ((data & 0x80) != 0);
+               break;
+       case 0x05c0:
+               extra_nmi_mask = ((data & 0x08) == 0);
+               break;
+       case 0x05ec:
+               if(machine_id >= 0x0500) { // Towns2 CX : Is this hidden register after Towns 1F/2F/1H/2H?
+                       vram_wait_val = ((data & 0x01) != 0) ? 3 : 6;
+                       mem_wait_val = ((data & 0x01) != 0) ? 0 : 3;
+                       this->write_signal(SIG_FMTOWNS_SET_VRAMWAIT, vram_wait_val, 0xff);
+                       this->write_signal(SIG_FMTOWNS_SET_MEMWAIT, mem_wait_val, 0xff);
+               }
+               break;
+       default:
+               break;
        }
-       return 0xff;
+       return;
 }
 
-uint32_t TOWNS_MEMORY::read_data16w(uint32_t addr, int *wait)
+void TOWNS_MEMORY::event_callback(int id, int err)
 {
-       uint32_t addr_head = (addr & 0xf0000000) >> 28;
-       uint32_t addr_mid;
-       uint32_t addr_low;
-       uint32_t ui;
-       uint16_t *pp;
-
+       switch(id) {
+       case EVENT_1US_WAIT:
+               cvent_wait_1us = -1;
+               if(machine_id >= 0x0300) { // After UX*/10F/20F/40H/80H
+                       d_cpu->write_signal(SIG_CPU_BUSREQ, 0, 1);
+               }
+               break;
+       default:
+               break;
+       }
        
-       if(wait != NULL) *wait = mem_wait_val;
-       switch(addr_head) {
+}
+
+uint32_t TOWNS_MEMORY::read_mmio(uint32_t addr, int *wait, bool *hit)
+{
+       if(hit != NULL) *hit = false;
+       if(wait != NULL) *wait = 0; // OK?
+       if(addr >= 0x000d0000) return 0xffffffff;
+       if(addr <  0x000cff80) return 0xffffffff;
+       uint32_t val = 0xff;
+       bool found = false;
+       switch(addr & 0x7f) {
        case 0x00:
+               if(d_vram != NULL) {
+                       val = d_vram->read_io8(FMTOWNS_VRAM_IO_CURSOR);
+                       found = true;
+               }
+               break;
        case 0x01:
+               if(d_vram != NULL) {
+                       val = d_vram->read_io8(FMTOWNS_VRAM_IO_FMR_RAMSELECT);
+                       found = true;
+               }
+               break;
        case 0x02:
+               if(d_vram != NULL) {
+                       val = d_vram->read_io8(FMTOWNS_VRAM_IO_FMR_DISPMODE);
+                       found = true;
+               }
+               break;
        case 0x03:
-               if(addr < 0x00100000) {
-                       return read_page0_16(addr, wait);
-               } else {
-                       ui = (((addr - 0x00100000) & 0x3ff00000) >> 20);
-                       pp = (uint16_t *)extram_adrs[ui];
-                       if(pp != NULL) {
-#ifdef __LITTLE_ENDIAN__
-                               addr_low = (addr & 0x000fffff) >> 1;
-                               return pp[addr_low];
-#else
-                               pair_t d;
-                               uint8 *p8 = (uint8 *)pp;
-                               addr_low = addr & 0x000ffffe;
-                               d.read_2bytes_le_from(&(p8[addr_low]));
-                               return d.d;
-#endif
-                       }
+               if(d_vram != NULL) {
+                       val = d_vram->read_io8(FMTOWNS_VRAM_IO_FMR_PAGESEL);
+                       found = true;
                }
-               return 0xffffffff;
                break;
        case 0x04:
-       case 0x05:
-       case 0x06:
-       case 0x07:
-               if(extio != NULL) return extio->read_data16(addr);
+               val = 0x7f; // Reserve.FIRQ
+               found = true;
                break;
-       case 0x08:
+       case 0x06:
                if(d_vram != NULL) {
-                       if(wait != NULL) *wait = vram_wait_val;
-                       return d_vram->read_data16(addr);
+                       val = d_vram->read_io8(FMTOWNS_VRAM_IO_SYNC_STATUS);
+                       found = true;
                }
                break;
-       case 0x09:
-       case 0x0a:
-       case 0x0b:
-               return 0xffffffff;
-               // ??
+       //case 0x14:
+       //case 0x15:
+       case 0x16:
+       case 0x17:
+               if(d_vram != NULL) {
+                       val = d_vram->read_io8(FMTOWNS_VRAM_KANJICG + (addr & 3));
+                       found = true;
+               }
                break;
-       case 0x0c:
-               addr_mid = (addr & 0x03fff000) >> 12 ;
-               pp = (uint16_t *)read_bank_adrs_cx[addr_mid];
-               if(pp != NULL) {
-#ifdef __LITTLE_ENDIAN__
-                               addr_low = (addr & 0x00000fff) >> 1;
-                               return pp[addr_low];
-#else
-                               pair_t d;
-                               uint8 *p8 = (uint8 *)pp;
-                               addr_low = addr & 0x00000ffe;
-                               d.read_2bytes_le_from(&(p8[addr_low]));
-                               return d.d;
-#endif
-               } else if(device_type_adrs_cx[addr_mid] != 0) {
-                       switch(device_type_adrs_cx[addr_mid]) {
-                       case TOWNS_MEMORY_TYPE_WAVERAM:
-                               if(d_pcm != NULL) {
-                                       return d_pcm->read_data8((addr & 0x0ffe));
-                               }
-                               break;
-                       case TOWNS_MEMORY_TYPE_DICTLEARN:
-                               if(d_cmos != NULL) {
-                                       return d_cmos->read_data8((addr & 0x0ffe));
-                               }
-                               break;
-                       case TOWNS_MEMORY_TYPE_FORBID:
-                       default:
-                               return 0xffff;
-                               break;
-                       }
-                       return 0xffff;
-               } else {
-                       return 0xffff;
+       case 0x18:
+               if(d_beep != NULL) {
+                       d_beep->write_signal(SIG_BEEP_ON, 1, 1);
+                       found = true;
                }
                break;
-       case 0x0d:
-       case 0x0e:
-               // ??
-               return 0xffff;
+       case 0x19:
+               val = val & ((ankcg_enabled) ? 0x00 : 0x01);
+               found = true;
                break;
-       case 0x0f:
-               // ROM, maybe unable to write.
-               if(addr < 0xfffc0000) {
-                       return 0xffff;
-               } else {
-#ifdef __LITTLE_ENDIAN__
-                       pp = (uint16_t *)system_rom;
-                       addr_low = (addr - 0xfffc0000) >> 1;
-                       return (uint32_t)pp[addr_low];
-#else
-                       pair_t d;
-                       uint8_t *p8;
-                       addr_low = (addr - 0xfffc0000) & 0x3fffe;
-                       p8 = &(system_rom[addr_low]);
-                       d.read_2bytes_le_from(p8);
-                       return d.d;
-#endif
-               }
+       case 0x20:
+               val = 0xff;
+               val = val & 0x7f;
+               found = true;
+               break;
+       default:
                break;
        }
-       return 0xffff;
+       if(hit != NULL) *hit = found;
+       return (uint32_t)val;
 }
 
-uint32_t TOWNS_MEMORY::read_data32w(uint32_t addr, int *wait)
+void TOWNS_MEMORY::write_mmio(uint32_t addr, uint32_t data, int *wait, bool *hit)
 {
-       uint32_t addr_head = (addr & 0xf0000000) >> 28;
-       uint32_t addr_mid;
-       uint32_t addr_low;
-       uint32_t ui;
-       uint32_t *pp;
-
-       if(wait != NULL) *wait = mem_wait_val;
-       switch(addr_head) {
+       if(hit != NULL) *hit = false;
+       if(wait != NULL) *wait = 0; // OK?
+       if(addr >= 0x000d0000) return;
+       if(addr <  0x000cff80) return;
+       bool found = false;
+       switch(addr & 0x7f) {
        case 0x00:
+               if(d_vram != NULL) {
+                       d_vram->write_io8(FMTOWNS_VRAM_IO_CURSOR, data);
+                       found = true;
+               }
+               break;
        case 0x01:
+               if(d_vram != NULL) {
+                       d_vram->write_io8(FMTOWNS_VRAM_IO_FMR_RAMSELECT, data);
+                       found = true;
+               }
+               break;
        case 0x02:
+               if(d_vram != NULL) {
+                       d_vram->write_io8(FMTOWNS_VRAM_IO_FMR_DISPMODE, data);
+                       found = true;
+               }
+               break;
        case 0x03:
-               if(addr < 0x00100000) {
-                       return read_page0_32(addr);
-               } else {
-                       ui = (((addr - 0x00100000) & 0x3ff00000) >> 20);
-                       pp = (uint32_t *)extram_adrs[ui];
-                       if(pp != NULL) {
-#ifdef __LITTLE_ENDIAN__
-                               addr_low = (addr & 0x000fffff) >> 2;
-                               return pp[addr_low];
-#else
-                               pair_t d;
-                               uint8 *p8 = (uint8 *)pp;
-                               addr_low = addr & 0x000ffffc;
-                               d.read_4bytes_le_from(&(p8[addr_low]));
-                               return d.d;
-#endif
-                       }
+               if(d_vram != NULL) {
+                       d_vram->write_io8(FMTOWNS_VRAM_IO_FMR_PAGESEL, data);
+                       found = true;
                }
-               return 0xffffffff;
                break;
        case 0x04:
-       case 0x05:
+               found = true;
+               break;
        case 0x06:
-       case 0x07:
-               if(extio != NULL) return extio->read_data32(addr);
+               found = true;
                break;
-       case 0x08:
+       case 0x14:
+       case 0x15:
+       case 0x16:
+       case 0x17:
                if(d_vram != NULL) {
-                       if(wait != NULL) *wait = vram_wait_val;
-                       return d_vram->read_data32(addr);
+                       d_vram->write_io8(FMTOWNS_VRAM_KANJICG + (addr & 3), data);
+                       found = true;
                }
                break;
-       case 0x09:
-       case 0x0a:
-       case 0x0b:
-               return 0xffffffff;
-               // ??
-               break;
-       case 0x0c:
-               addr_mid = (addr & 0x03fff000) >> 12 ;
-               pp = (uint32_t *)read_bank_adrs_cx[addr_mid];
-               if(pp != NULL) {
-#ifdef __LITTLE_ENDIAN__
-                               addr_low = (addr & 0x00000fff) >> 2;
-                               return pp[addr_low];
-#else
-                               pair_t d;
-                               uint8 *p8 = (uint8 *)pp;
-                               addr_low = addr & 0x00000ffc;
-                               d.read_4bytes_le_from(&(p8[addr_low]));
-                               return d.d;
-#endif
-               } else if(device_type_adrs_cx[addr_mid] != 0) {
-                       switch(device_type_adrs_cx[addr_mid]) {
-                       case TOWNS_MEMORY_TYPE_WAVERAM:
-                               if(d_pcm != NULL) {
-                                       return d_pcm->read_data8((addr & 0x0ffc));
-                               }
-                               break;
-                       case TOWNS_MEMORY_TYPE_DICTLEARN:
-                               if(d_cmos != NULL) {
-                                       return d_cmos->read_data8((addr & 0x0ffc));
-                               }
-                               break;
-                       case TOWNS_MEMORY_TYPE_FORBID:
-                       default:
-                               return 0xffffffff;
-                               break;
-                       }
-                       return 0xffffffff;
-               } else {
-                       return 0xffffffff;
+       case 0x18:
+               if(d_beep != NULL) {
+                       d_beep->write_signal(SIG_BEEP_ON, 0, 1);
+                       found = true;
                }
                break;
-       case 0x0d:
-       case 0x0e:
-               // ??
-               return 0xffffffff;
+       case 0x19:
+           ankcg_enabled = ((data & 1) == 0);
+               found = true;
                break;
-       case 0x0f:
-               // ROM, maybe unable to write.
-               if(addr < 0xfffc0000) {
-                       return 0xffffffff;
-               } else {
-#ifdef __LITTLE_ENDIAN__
-                       pp = (uint32_t *)system_rom;
-                       addr_low = (addr - 0xfffc0000) >> 2;
-                       return pp[addr_low];
-#else
-                       pair_t d;
-                       uint8_t *p8;
-                       addr_low = (addr - 0xfffc0000) & 0x3fffc;
-                       p8 = &(system_rom[addr_low]);
-                       d.read_4bytes_le_from(p8);
-                       return d.d;
-#endif
-               }
+       case 0x20:
+               found = true;
+               break;
+       default:
                break;
        }
-       return 0xffffffff;
+       if(hit != NULL) *hit = found;
+       return;
+}
+
+void TOWNS_MEMORY::initialize_tables(void)
+{
+       // Address Cx000000
+       memset(write_bank_adrs_cx, 0x00, sizeof(write_bank_adrs_cx));
+       memset(read_bank_adrs_cx, 0x00, sizeof(read_bank_adrs_cx));
+       memset(device_bank_adrs_cx, 0x00, sizeof(device_bank_adrs_cx));
+       memset(type_bank_adrs_cx, 0x00, sizeof(type_bank_adrs_cx));
+
+       // PAGE0
+       for(uint32_t ui = 0x00000; ui < 0x000c0; ui++) {  // $00000000 - $000bffff
+               read_bank_adrs_cx[ui] = &(ram_page0[ui << 12]);
+               write_bank_adrs_cx[ui] = &(ram_page0[ui << 12]);
+       }
+       
+       for(uint32_t ui = 0x000c0; ui < 0x000c8; ui++) { // $000c0000 - $000effff
+                       type_bank_adrs_cx[ui] = (TOWNS_MEMORY_FMR_VRAM << 24) | ((ui - 0xc0) << 12);    
+       }
+       for(uint32_t ui = 0x000c8; ui < 0x000c9; ui++) { // $000c0000 - $000effff
+                       type_bank_adrs_cx[ui] = (TOWNS_MEMORY_FMR_TEXT << 24) | ((ui - 0xc8) << 12);    
+       }
+       for(uint32_t ui = 0x000c9; ui < 0x000ca; ui++) { // $000c0000 - $000effff
+                       type_bank_adrs_cx[ui] = (TOWNS_MEMORY_FMR_VRAM_RESERVE << 24) | ((ui - 0xc8) << 12);    
+       }
+       for(uint32_t ui = 0x000ca; ui < 0x000cb; ui++) { // $000c0000 - $000effff
+                       type_bank_adrs_cx[ui] = (TOWNS_MEMORY_SPRITE_ANKCG1 << 24) | ((ui - 0xca) << 12);       
+       }
+       for(uint32_t ui = 0x000cb; ui < 0x000cc; ui++) { // $000c0000 - $000effff
+                       type_bank_adrs_cx[ui] = (TOWNS_MEMORY_ANKCG2 << 24) | ((ui - 0xcb) << 12);      
+       }
+       for(uint32_t ui = 0x000cc; ui < 0x000d0; ui++) { // $000c0000 - $000effff
+                       type_bank_adrs_cx[ui] = (TOWNS_MEMORY_MMIO_0CC << 24) | ((ui - 0xcc) << 12);    
+       }
+       for(uint32_t ui = 0x000d0; ui < 0x000f0; ui++) { // $000c0000 - $000effff
+               device_bank_adrs_cx[ui] = d_dictionary;
+       }
+       for(uint32_t ui = 0x000f0; ui < 0x00100; ui++) { // $000f0000 - $000fffff
+               device_bank_adrs_cx[ui] = d_sysrom;
+       }
+       // Extra RAM
+       for(uint32_t ui = 0x00100; ui < (0x00100 + (extram_size >> 12)); ui++) {
+               read_bank_adrs_cx[ui] = &(extram[(ui - 0x100)  << 12]);
+               write_bank_adrs_cx[ui] = &(extram[(ui - 0x100) << 12]);
+       }
+       // ToDo: EXTRA IO(0x40000000 - 0x80000000)
+       
+       // VRAM
+       /*
+       for(uint32_t ui = 0x000c0; ui < 0x000ca; ui++) {
+               device_bank_adrs_cx[ui] = d_vram;
+       }
+       for(uint32_t ui = 0x000ca; ui < 0x000cb; ui++) {
+               device_bank_adrs_cx[ui] = d_sprite;
+       }
+       */
+       for(uint32_t ui = 0x80000; ui < (0x80000 + (vram_size >> 12)); ui++) {
+               device_bank_adrs_cx[ui] = d_vram;
+       }
+       for(uint32_t ui = 0x80100; ui < (0x80100 + (vram_size >> 12)); ui++) {
+               device_bank_adrs_cx[ui] = d_vram;
+       }
+       for(uint32_t ui = 0x81000; ui < 0x81020; ui++) {
+               device_bank_adrs_cx[ui] = d_sprite;
+       }
+
+       // ROM CARD
+       for(uint32_t ui = 0xc0000; ui < 0xc1000; ui++) {
+               device_bank_adrs_cx[ui] = d_romcard[0];
+       }
+       // ROM CARD2
+       for(uint32_t ui = 0xc1000; ui < 0xc2000; ui++) {
+               device_bank_adrs_cx[ui] = d_romcard[1];
+       }
+       for(uint32_t ui = 0xc2140; ui < 0xc2142; ui++) { 
+               device_bank_adrs_cx[ui] = d_dictionary;
+       }
+       for(uint32_t ui = 0xc2200; ui < 0xc2201; ui++) { 
+               device_bank_adrs_cx[ui] = d_pcm;
+       }
+       // ROMs
+       for(uint32_t ui = 0xc2000; ui < 0xc2080; ui++) {
+               device_bank_adrs_cx[ui] = d_msdos;
+       }
+       for(uint32_t ui = 0xc2080; ui < 0xc2100; ui++) {
+               device_bank_adrs_cx[ui] = d_dictionary;
+       }
+       for(uint32_t ui = 0xc2100; ui < 0xc2140; ui++) {
+               device_bank_adrs_cx[ui] = d_fonts;
+       }
+       for(uint32_t ui = 0xc2180; ui < 0xc2200; ui++) { // 20pixs fonts.
+               device_bank_adrs_cx[ui] = d_fonts;
+       }
+
+       // SYSTEM CODE ROM
+       for(uint32_t ui = 0xfffc0; ui < 0x100000; ui++) { 
+               device_bank_adrs_cx[ui] = d_sysrom;
+       }
+}
+
+
+uint32_t TOWNS_MEMORY::read_data8(uint32_t addr)
+{
+       int wait;
+       return read_data8w(addr, &wait);
+}
+
+uint32_t TOWNS_MEMORY::read_data16(uint32_t addr)
+{
+       int wait;
+       return read_data16w(addr, &wait);
+}
+
+uint32_t TOWNS_MEMORY::read_data32(uint32_t addr)
+{
+       int wait;
+       return read_data32w(addr, &wait);
 }
 
 void TOWNS_MEMORY::write_dma_data8(uint32_t addr, uint32_t data)
@@ -1032,284 +995,109 @@ uint32_t TOWNS_MEMORY::read_dma_data16(uint32_t addr)
        return read_data16w(addr & dma_addr_mask, &wait);
 }
 
-void TOWNS_MEMORY::write_io8(uint32_t addr, uint32_t data)
-{
-       switch(addr & 0xffff) {
-       case 0x20:
-               // protect and reset
-               protect = data;
-               update_bank();
-               if(data & 0x40) {
-                       // power off
-                       emu->power_off();
-               }
-               if(data & 1) {
-                       // software reset
-                       rst |= 1;
-                       d_cpu->reset();
-               }
-               // protect mode
-               if(data & 0x80) {
-                       // NMI Vector protect
-               }
-               break;
-       case 0x22:
-               // Power off
-               if(data & 0x40) {
-                       // power off
-                       emu->power_off();
-               }
-               break;
-       case 0x400:
-               // video output control
-               break;
-       case 0x402:
-               // update register
-               wplane = data & 0xf;
-               break;
-       case 0x404:
-               // read out register
-               mainmem = data & 0x80;
-               rplane = data & 3;
-               update_bank();
-               break;
-       case 0x408:
-               // palette code register
-               apalsel = data & 0xf;
-               break;
-       case 0x40a:
-               // blue level register
-               apal[apalsel][0] = data & 0xf0;
-               palette_cg[apalsel] = RGB_COLOR(apal[apalsel][1], apal[apalsel][2], apal[apalsel][0]);
-               break;
-       case 0x40c:
-               // red level register
-               apal[apalsel][1] = data & 0xf0;
-               palette_cg[apalsel] = RGB_COLOR(apal[apalsel][1], apal[apalsel][2], apal[apalsel][0]);
-               break;
-       case 0x40e:
-               // green level register
-               apal[apalsel][2] = data & 0xf0;
-               palette_cg[apalsel] = RGB_COLOR(apal[apalsel][1], apal[apalsel][2], apal[apalsel][0]);
-               break;
-       case 0x480:
-               bankf8_ram = false;
-               if((data & 0x02) != 0) {
-                       bankf8_ram = true;
-               }
-               bankf8_dic = false;
-               if((data & 0x01) != 0) {
-                       bankf8_dic = true;
-               }
-               break;
-       case 0x484:
-               dict_bank = data & 0x0f;
-               break;
-       case 0xfd98:
-       case 0xfd99:
-       case 0xfd9a:
-       case 0xfd9b:
-       case 0xfd9c:
-       case 0xfd9d:
-       case 0xfd9e:
-       case 0xfd9f:
-               // digital palette
-               dpal[addr & 7] = data;
-               if(data & 8) {
-                       palette_cg[addr & 7] = RGB_COLOR(data & 2 ? 255 : 0, data & 4 ? 255 : 0, data & 1 ? 255 : 0);
-               } else {
-                       palette_cg[addr & 7] = RGB_COLOR(data & 2 ? 127 : 0, data & 4 ? 127 : 0, data & 1 ? 127 : 0);
-               }
-               break;
-       case 0xfda0:
-               // video output control
-               outctrl = data;
-               break;
-       }
-}
-
-uint32_t TOWNS_MEMORY::read_io8(uint32_t addr)
-{
-       uint32_t val = 0xff;
-       
-       switch(addr & 0xffff) {
-       case 0x20:
-               // reset cause register
-               val = rst | (d_cpu->get_shutdown_flag() << 1);
-               rst = 0;
-               d_cpu->set_shutdown_flag(0);
-               return val | 0x7c;
-       case 0x21:
-//             return 0x1f;
-               return 0xdf;
-       case 0x24:
-               return dma_wrap_reg;
-       case 0x30:
-               // machine & cpu id
-               return machine_id;
-       case 0x400:
-               // system status register
-#ifdef _FMR60
-               return 0xff;
-#else
-               return 0xfe;
-//             return 0xf6;
-#endif
-       case 0x402:
-               // update register
-               return wplane | 0xf0;
-       case 0x404:
-               // read out register
-               return mainmem | rplane | 0x7c;
-       case 0x40a:
-               // blue level register
-               return apal[apalsel][0];
-       case 0x40c:
-               // red level register
-               return apal[apalsel][1];
-       case 0x40e:
-               // green level register
-               return apal[apalsel][2];
-               // Towns
-       case 0x480:
-               return (bankf8_ram ? 0x02 : 0x00) | (bankf8_dic ? 0x01 : 0x00);
-               break;
-       case 0x484:
-               return dict_bank & 0x0f;
-               break;
-       case 0xfd98:
-       case 0xfd99:
-       case 0xfd9a:
-       case 0xfd9b:
-       case 0xfd9c:
-       case 0xfd9d:
-       case 0xfd9e:
-       case 0xfd9f:
-               // digital palette
-               return dpal[addr & 7] | 0xf0;
-       case 0xfda0:
-               // status register
-               return (disp ? 2 : 0) | (vsync ? 1 : 0) | 0xfc;
-       }
-       return 0xff;
-}
 
-void TOWNS_MEMORY::write_signal(int id, uint32_t data, uint32_t mask)
+void TOWNS_MEMORY::write_signal(int ch, uint32_t data, uint32_t mask)
 {
-       if(id == SIG_MEMORY_DISP) {
-               disp = ((data & mask) != 0);
-       } else if(id == SIG_MEMORY_VSYNC) {
-               vsync = ((data & mask) != 0);
+       if(ch == SIG_MEMORY_EXTNMI) {
+               extra_nmi_val = ((data & mask) != 0);
+       } else if(ch == SIG_CPU_NMI) {
+               // Check protect
+               d_cpu->write_signal(SIG_CPU_NMI, data, mask);
+       } else if(ch == SIG_CPU_IRQ) {
+               d_cpu->write_signal(SIG_CPU_IRQ, data, mask);
+       } else if(ch == SIG_CPU_BUSREQ) {
+               d_cpu->write_signal(SIG_CPU_BUSREQ, data, mask);
+       } else if(ch == SIG_I386_A20) {
+               d_cpu->write_signal(SIG_I386_A20, data, mask);
+       } else if(ch == SIG_FMTOWNS_SET_MEMWAIT) {
+               mem_wait_val = (int)data;
+               d_sysrom->write_signal(SIG_FMTOWNS_SET_MEMWAIT, data, mask);
+               d_dictionary->write_signal(SIG_FMTOWNS_SET_MEMWAIT, data, mask);
+               d_msdos->write_signal(SIG_FMTOWNS_SET_MEMWAIT, data, mask);
+               d_fonts->write_signal(SIG_FMTOWNS_SET_MEMWAIT, data, mask);
+       } else if(ch == SIG_FMTOWNS_SET_VRAMWAIT) {
+               vram_wait_val = (int)data;
+               d_vram->write_signal(SIG_FMTOWNS_SET_MEMWAIT, data, mask);
        }
 }
 
-void TOWNS_MEMORY::update_dma_addr_mask()
+uint32_t TOWNS_MEMORY::read_signal(int ch)
 {
-       switch(dma_addr_reg & 3) {
-       case 0:
-               dma_addr_mask = d_cpu->get_address_mask();
-               break;
-       case 1:
-               if(!(dma_wrap_reg & 1) && d_cpu->get_address_mask() == 0x000fffff) {
-                       dma_addr_mask = 0x000fffff;
-               } else {
-                       dma_addr_mask = 0x00ffffff;
-               }
-               break;
-       default:
-               if(!(dma_wrap_reg & 1) && d_cpu->get_address_mask() == 0x000fffff) {
-                       dma_addr_mask = 0x000fffff;
-               } else {
-                       dma_addr_mask = 0xffffffff;
-               }
-               break;
-       }
+       if(ch == SIG_FMTOWNS_MACHINE_ID) {
+               uint16_t d = (machine_id & 0xfff8) | ((uint16_t)(cpu_id & 0x07));
+               return (uint32_t)d;
+       } else if(ch == SIG_FMTOWNS_SET_MEMWAIT) {
+               return (uint32_t)mem_wait_val;
+       } else if(ch == SIG_FMTOWNS_SET_VRAMWAIT) {
+               return (uint32_t)vram_wait_val;
+       } 
+       return 0;
 }
+// ToDo: DMA
 
 #define STATE_VERSION  1
 
-void TOWNS_MEMORY::save_state(FILEIO* state_fio)
+bool TOWNS_MEMORY::process_state(FILEIO* state_fio, bool loading)
 {
-       state_fio->FputUint32(STATE_VERSION);
-       state_fio->FputInt32(this_device_id);
+       if(!state_fio->StateCheckUint32(STATE_VERSION)) {
+               return false;
+       }
+       if(!state_fio->StateCheckInt32(this_device_id)) {
+               return false;
+       }
+       state_fio->StateValue(bankc0_vram);
+       state_fio->StateValue(ankcg_enabled);
+       state_fio->StateValue(machine_id);
+       state_fio->StateValue(cpu_id);
 
-       state_fio->FputBool(bank8_ram);
-       state_fio->FputBool(bankd0_dict);
-       state_fio->FputUint8(dict_bank);
-       state_fio->FputUint32_LE(extram_pages);
-
-       state_fio->FputInt8((int8_t)vram_wait_val);
-       state_fio->FputInt8((int8_t)mem_wait_val);
-       state_fio->FputInt8((int8_t)extio_wait_val);
-       
-       // Save rom?
-       state_fio->Fwrite(page0, sizeof(page0));
-       state_fio->Fwrite(ram_0d0, sizeof(ram_0d0));
-       state_fio->Fwrite(ram_0f0, sizeof(ram_0f0));
-       state_fio->Fwrite(ram_0f8, sizeof(ram_0f8));
+       state_fio->StateValue(dma_addr_mask);
+       //state_fio->StateValue(dma_addr_reg);
+       //state_fio->StateValue(dma_wrap_reg);
        
-       // ROM?
-       state_fio->Fwrite(msdos_rom, sizeof(msdos_rom));
-       state_fio->Fwrite(dict_rom, sizeof(dict_rom));
-       state_fio->Fwrite(font_rom, sizeof(font_rom));
-       //state_fio->Fwrite(font_20_rom, sizeof(font_20_rom));
-       state_fio->Fwrite(system_rom, sizeof(system_rom));
+       state_fio->StateArray(ram_page0, sizeof(ram_page0), 1);
+       state_fio->StateArray(ram_0c0, sizeof(ram_0c0), 1);
+       state_fio->StateArray(ram_0c8, sizeof(ram_0c8), 1);
+       state_fio->StateArray(ram_0ca, sizeof(ram_0ca), 1);
+       state_fio->StateArray(ram_0cb, sizeof(ram_0cb), 1);
+       state_fio->StateArray(ram_0cc, sizeof(ram_0cc), 1);
        
-       state_fio->Fwrite(extram_base, extram_pages * 0x100000);
-       
-// ToDo
-       state_fio->FputUint8(protect);
-       state_fio->FputUint8(rst);
-}
 
-bool TOWNS_MEMORY::load_state(FILEIO* state_fio)
-{
-       if(state_fio->FgetUint32() != STATE_VERSION) {
-               return false;
-       }
-       if(state_fio->FgetInt32() != this_device_id) {
-               return false;
+       if(loading) {
+               uint32_t length_tmp = state_fio->FgetUint32_LE();
+               if(extram != NULL) {
+                       free(extram);
+                       extram = NULL;
+               }
+               length_tmp = length_tmp & 0x3ff00000;
+               extram_size = length_tmp;
+               if(length_tmp > 0) {
+                       extram = (uint8_t*)malloc(length_tmp);
+               }
+               if(extram == NULL) {
+                       extram_size = 0;
+                       return false;
+               } else {
+                       state_fio->Fread(extram, extram_size, 1);
+               }
+       } else {
+               if(extram == NULL) {
+                       state_fio->FputUint32_LE(0);
+               } else {
+                       state_fio->FputUint32_LE(extram_size & 0x3ff00000);
+                       state_fio->Fwrite(extram, extram_size, 1);
+               }
        }
+                       
+       state_fio->StateValue(vram_wait_val);
+       state_fio->StateValue(mem_wait_val);
+       state_fio->StateValue(vram_size);
 
-       bank8_tam = state_fio->FgetBool();
-       bank0_dict = state_fio->FgetBool();
-       dict_bank = state_fio->FgetUint8();
-       extram_pages = state_fio->FgetUint32_LE();
-       
-       vram_wait_val = (int)state_fio->FgetInt8();
-       mem_wait_val  = (int)state_fio->FgetInt8();
-       extio_wait_val  = (int)state_fio->FgetInt8();
+       // ToDo: Do save ROMs?
 
-       // Save rom?
-       state_fio->Fread(page0, sizeof(page0));
-       state_fio->Fread(ram_0d0, sizeof(ram_0d0));
-       state_fio->Fread(ram_0f0, sizeof(ram_0f0));
-       state_fio->Fread(ram_0f8, sizeof(ram_0f8));
-       
-       // ROM?
-       state_fio->Fread(msdos_rom, sizeof(msdos_rom));
-       state_fio->Fread(dict_rom, sizeof(dict_rom));
-       state_fio->Fread(font_rom, sizeof(font_rom));
-       //state_fio->Fwrite(font_20_rom, sizeof(font_20_rom));
-       state_fio->Fread(system_rom, sizeof(system_rom));
-       
-       uint8_t *pp;
-       pp = malloc(extram_pages * 0x100000);
-       if(pp == NULL) {
-               return false;
-       } else {
-               state_fio->Fread(pp, extram_pages * 0x100000);
+       if(loading) {
+               initialize_tables();
        }
-       //ToDo
-       protect = state_fio->FgetUint8();
-       rst = state_fio->FgetUint8();
-       
-       
-       // post process
-       //update_bank();
-       extram_base = pp;
-       initialize_tables();
-       
        return true;
 }
 
+}