OSDN Git Service

[VM][FMTOWNS][TOWNS_MEMORY] Make addressing more correctness.
[csp-qt/common_source_project-fm7.git] / source / src / vm / fmtowns / towns_memory.cpp
index 858fd96..5b957cd 100644 (file)
 
 #include "../../fileio.h"
 #include "./towns_memory.h"
-#include "./towns_vram.h"
-#include "../i386.h"
+#include "./dmac.h"
+#include "./vram.h"
+#include "./planevram.h"
+#include "./sprite.h"
+#include "./fontroms.h"
+#include "./serialrom.h"
+#include "./crtc.h"
+#include "./timer.h"
+
+#include "../i386_np21.h"
+//#include "../i386.h"
+
+#include <math.h>
 
 namespace FMTOWNS {
-       
+
 void TOWNS_MEMORY::initialize()
 {
-       MEMORY::initialize();
-       
+       if(initialized) return;
+       //MEMORY::initialize();
+
+       update_machine_features();
        extra_nmi_mask = true;
        extra_nmi_val = false;
-       
+       poff_status = false;
+       reset_happened = false;
+
        vram_wait_val = 6;
        mem_wait_val = 3;
+//     if((cpu_id == 0x01) || (cpu_id == 0x03)) {
+//             wait_register_older = vram_wait_val;
+//             wait_register_vram = vram_wait_val;
+//             wait_register_ram = mem_wait_val;
+//     } else {
+               wait_register_older  = 3;
+               wait_register_vram = 0x06;
+               wait_register_ram  = 0x03;
+//     }
+       //cpu_clock_val = 16 * 1000 * 1000;
+       //cpu_clock_val = get_cpu_clocks(d_cpu);
+       set_cpu_clock_by_wait();
+       extram_size = extram_size & 0x3ff00000;
+       set_extra_ram_size(extram_size >> 20); // Check extra ram size.
 
-       set_memory_rw(0x00000000, 0x000bffff, ram_page0);
-       set_memory_mapped_io_rw(0x000c0000, 0x000c7fff, d_vram); // PLANE ACCESSED VRAM(EMULATED)
-       set_memory_mapped_io_rw(0x000c8000, 0x000c8fff, d_vram); // TEXT VRAM (EMULATED)
-       set_memory_mapped_io_rw(0x000c9000, 0x000c9fff, d_vram); // VRAM RESERVED
-       set_memory_mapped_io_rw(0x000ca000, 0x000cafff, d_vram); // ANKCG1 / IO / RAM
-       set_memory_mapped_io_rw(0x000cb000, 0x000cbfff, d_cgrom);   // ANKCG1 / IO / RAM
-       set_memory_mapped_io_rw(0x000cc000, 0x000cffff, d_vram); // MMIO / RAM
-       set_memory_mapped_io_rw(0x000d0000, 0x000d7fff, d_dictionary); // DICTIONARY (BANKED)
-       set_memory_mapped_io_rw(0x000d8000, 0x000d9fff, d_sram); // SRAM (LEARN/GAIJI)
-       unset_memory_rw(0x000da000, 0x000effff); // RESERVED
-
-       set_memory_rw(0x000f0000, 0x000f7fff, ram_pagef);
-       set_memory_mapped_io_rw(0x000f8000, 0x000fffff, d_sysrom);    // SYSROM / RAM
-
-       unset_memory_rw(0x00100000, 0x3fffffff);
-       extra_ram_size = extra_ram_size & 0x3ff00000;
-       if(extra_ram_size >= 0x00100000) {
-               extra_ram = malloc(extra_ram_size);
-               if(extra_ram != NULL) {
-                       set_memory_rw(0x00100000, (extra_ram_size + 0x00100000) - 1, extra_ram);
-                       memset(extra_ram, 0x00, extra_ram_size);
-               }
-       }               
-       memset(ram_page0, 0x00, sizeof(ram_page0));
-       memset(ram_pagef, 0x00, sizeof(ram_pagef));
+       unset_range_rw(0x00000000, 0xffffffff);
 
-       unset_memory_rw(0x40000000, 0x7fffffff);  // EXTRA SLOT
-       set_memory_mapped_io_rw(0x80000000, 0x8007ffff, d_display); // VRAM
-       unset_memory_rw(0x80080000, 0x800fffff); // RESERVED VRAM
-       set_memory_mapped_io_rw(0x80100000, 0x8017ffff, d_display); // VRAM
-       unset_memory_rw(0x80180000, 0x801fffff); // RESERVED VRAM
-       unset_memory_rw(0x80200000, 0x80ffffff); // RESERVED VRAM
-       set_memory_mapped_io_rw(0x81000000, 0x8101ffff, d_sprite); // SPRITE PATTERN
+       reset_wait_values();
 
-       unset_memory_rw(0xc0000000, 0xc1ffffff); // Reserved
-       if(d_romcard[0] != NULL) {
-               set_memory_mapped_io_rw(0xc0000000, 0xc0ffffff, d_romcard[0]); // DICTIONARY ROM
+       __UNLIKELY_IF(extra_ram == NULL) {
+               extra_ram = (uint8_t*)malloc(extram_size + 0x00100000);
+               __LIKELY_IF(extra_ram != NULL) {
+                       set_region_memory_rw(0x00000000, (extram_size + 0x00100000) - 1, extra_ram, 0);
+                       memset(extra_ram, 0x00, extram_size + 0x00100000);
+               }
        }
-#if 0
-       if(d_romcard[1] != NULL) {
-               set_memory_mapped_io_rw(0xc1000000, 0xc1ffffff, d_romcard[1]); // DICTIONARY ROM
+
+
+       initialized = true;
+
+       // Lower 100000h
+
+       config_page0c_0e(true, false, true);
+       config_page0f(true, true);
+
+       set_region_device_rw(0x80000000, 0x8007ffff, d_vram, NOT_NEED_TO_OFFSET);
+       set_region_device_rw(0x80100000, 0x8017ffff, d_vram, NOT_NEED_TO_OFFSET);
+
+       set_region_device_rw(0x81000000, 0x8101ffff, d_sprite, 0);
+       set_region_device_rw(0xc0000000, 0xc0ffffff, d_iccard[0], 0);
+       set_region_device_rw(0xc1000000, 0xc1ffffff, d_iccard[1], 0);
+//     set_wait_rw(0x00000000, 0xffffffff,  vram_wait_val);
+
+       set_region_device_r (0xc2000000, 0xc207ffff, d_msdos, 0);
+       set_region_device_r (0xc2080000, 0xc20fffff, d_dictionary, NOT_NEED_TO_OFFSET);
+       set_region_device_r (0xc2100000, 0xc213ffff, d_font, NOT_NEED_TO_OFFSET);
+       // REAL IS C2140000h - C2141FFFh, but grain may be 8000h bytes.
+       set_region_device_rw(0xc2140000, 0xc2147fff, d_cmos, 0);
+       if(d_font_20pix != NULL) {
+               set_region_device_r (0xc2180000, 0xc21fffff, d_font_20pix, 0);
        }
-#endif
-       set_memory_mapped_io_rw(0xc2000000, 0xc207ffff, d_msdos); // MSDOS
-       set_memory_mapped_io_rw(0xc2080000, 0xc20fffff, d_dictionary); // DICTIONARY ROM
-       set_memory_mapped_io_rw(0xc2100000, 0xc213ffff, d_font); // FONT ROM
-       set_memory_mapped_io_rw(0xc2140000, 0xc2141fff, d_sram); // LEARN RAM
-       unset_memory_rw(0xc2142000, 0xc21ffffff); // Reserved
-       
-       set_memory_mapped_io_rw(0xc2200000, 0xc2200fff, d_pcm);      // PCM RAM (ToDo:)
-
-       unset_memory_rw(0xc2201000, 0xfffbffff); // Reserved
-       set_memory_mapped_io_rw(0xfffc0000, 0xffffffff, d_sysrom);
-       
+       // REAL IS C2200000h - C2200FFFh, but grain may be 8000h bytes.
+       set_region_device_rw(0xc2200000, 0xc2200000 + memory_map_grain() - 1, d_pcm, 0);
+       set_region_device_r (0xfffc0000, 0xffffffff, d_sysrom, 0);
+       // Another devices are blank
+
        // load rom image
        // ToDo: More smart.
        vram_size = 0x80000; // OK?
-       
-       //dma_addr_reg = dma_wrap_reg = 0;
-       dma_addr_mask = 0x00ffffff; // ToDo
-       
-       initialize_tables();
+}
+
+void TOWNS_MEMORY::reset_wait_values()
+{
+       set_mmio_wait_rw(0x00000000, 0x7fffffff, WAITVAL_RAM);
+       set_dma_wait_rw (0x00000000, 0x7fffffff, WAITVAL_RAM);
+       set_mmio_wait_rw(0x80000000, 0x803fffff, WAITVAL_VRAM); // Default Value
+       set_dma_wait_rw (0x80000000, 0x803fffff, WAITVAL_VRAM); // Default Value
+       set_mmio_wait_rw(0x80400000, 0xffffffff, WAITVAL_RAM);
+       set_dma_wait_rw (0x80400000, 0xffffffff, WAITVAL_RAM);
+}
+
+void TOWNS_MEMORY::config_page0c_0e(const bool vrambank, const bool dictbank, const bool force)
+{
+       const bool is_vram_bak = dma_is_vram;
+       const bool is_dict_bak = select_d0_dict;
+       //__UNLIKELY_IF((vrambank != is_vram_bak) || (force)){
+               if(vrambank) { // VRAM AND around TEXT
+                       set_region_device_rw(0x000c0000, 0x000c7fff, d_planevram, NOT_NEED_TO_OFFSET);
+                       set_region_device_rw(0x000c8000, 0x000cffff, this, NOT_NEED_TO_OFFSET);
+
+                       unset_range_rw(0x000e0000, 0x000effff); // OK?
+
+                       set_mmio_wait_rw(0x000c0000, 0x000cffff, WAITVAL_VRAM); // Default Value
+                       set_dma_wait_rw (0x000c0000, 0x000cffff, WAITVAL_VRAM); // Default Value
+               } else {
+                       __LIKELY_IF(extra_ram != NULL) {
+                               set_region_memory_rw(0x000c0000, 0x000cffff, extra_ram, 0x000c0000);
+                               set_region_memory_rw(0x000e0000, 0x000effff, extra_ram, 0x000e0000);
+                       } else {
+                               unset_range_rw(0x000c0000, 0x000cffff);
+                               unset_range_rw(0x000e0000, 0x000effff);
+                       }
+                       set_mmio_wait_rw(0x000c0000, 0x000cffff, WAITVAL_RAM); // Default Value
+                       set_dma_wait_rw (0x000c0000, 0x000cffff, WAITVAL_VRAM); // Default Value
+               }
+       //}
+       //__UNLIKELY_IF((vrambank != is_vram_bak) || (dictbank != is_dict_bak) || (force)){
+               if(vrambank) { // VRAM AND around TEXT
+                       if(dictbank) {
+                               set_region_device_r(0x000d0000, 0x000d7fff, d_dictionary, NOT_NEED_TO_OFFSET);
+                               unset_range_w(0x000d0000, 0x000d7fff);
+                               // REAL IS 0000D8000h - 000D9FFFh, but grain may be 8000h bytes.
+                               set_region_device_rw(0x000d8000, 0x000dffff, d_cmos, 0);
+                       } else {
+                               unset_range_rw(0x000d0000, 0x000dffff);
+                       }
+               } else {
+                       __LIKELY_IF(extra_ram != NULL) {
+                               set_region_memory_rw(0x000d0000, 0x000dffff, extra_ram, 0x000d0000);
+                       } else {
+                               unset_range_rw(0x000d0000, 0x000dffff);
+                       }
+               }
+       //}
+       dma_is_vram = vrambank;
+       select_d0_dict = dictbank;
+}
+void TOWNS_MEMORY::config_page0f(const bool sysrombank, const bool force)
+{
+       bool sysrom_bak = select_d0_rom;
+       //__LIKELY_IF(extra_ram != NULL) {
+       //      set_region_memory_rw(0x000f0000, 0x000f7fff, extra_ram, 0x000f0000);
+       //}
+       //__UNLIKELY_IF((sysrombank != sysrom_bak) || (force)) {
+               if(sysrombank) {
+                       unset_range_w(0x000f8000, 0x000fffff);
+                       set_region_device_r (0x000f8000, 0x000fffff, d_sysrom, 0x38000);
+               } else {
+                       __LIKELY_IF(extra_ram != NULL) {
+                               set_region_memory_rw(0x000f8000, 0x000fffff, extra_ram, 0x000f8000);
+                       } else {
+                               unset_range_rw(0x000f8000, 0x000fffff);
+                       }
+               }
+       //}
+       select_d0_rom = sysrombank;
+}
+
+void TOWNS_MEMORY::set_memory_devices_map_values(uint32_t start, uint32_t end, memory_device_map_t* dataptr, uint8_t* baseptr, DEVICE* device, uint32_t base_offset)
+{
+       uint64_t _start = (uint64_t)start;
+       uint64_t _end =   (end == 0xffffffff) ? 0x100000000 : (uint64_t)(end + 1);
+       __UNLIKELY_IF(dataptr == NULL) return;
+
+       _start &= ~(memory_map_mask());
+       _end &= ~(memory_map_mask());
+
+       uint64_t mapptr = (uint32_t)(_start >> memory_map_shift());
+       const uint64_t _incval = memory_map_grain();
+       uint32_t realoffset = (base_offset == UINT32_MAX) ? 0 : base_offset;
+
+       for(uint64_t addr = _start; addr < _end; addr += _incval) {
+               __UNLIKELY_IF(mapptr >= memory_map_size()) break; // Safety
+               if(baseptr == NULL) {
+                       dataptr[mapptr].mem_ptr = NULL;
+                       dataptr[mapptr].device_ptr = device;
+               } else {
+                       dataptr[mapptr].mem_ptr = baseptr;
+                       dataptr[mapptr].device_ptr = NULL;
+               }
+               if(base_offset == UINT32_MAX) {
+                       dataptr[mapptr].base_offset = UINT32_MAX;
+               } else {
+                       dataptr[mapptr].base_offset = realoffset;
+               }
+               realoffset += _incval;
+               mapptr++;
+       }
+}
+
+void TOWNS_MEMORY::set_memory_devices_map_wait(uint32_t start, uint32_t end, memory_device_map_t* dataptr, int wait)
+{
+       uint64_t _start = (uint64_t)start;
+       uint64_t _end =   (end == 0xffffffff) ? 0x100000000 : (uint64_t)(end + 1);
+       __UNLIKELY_IF(dataptr == NULL) return;
+
+       _start &= ~(memory_map_mask());
+       _end &= ~(memory_map_mask());
+
+       uint64_t mapptr = (uint32_t)(_start >> memory_map_shift());
+       const uint64_t _incval = memory_map_grain();
+
+       for(uint64_t addr = _start; addr < _end; addr += _incval) {
+               __UNLIKELY_IF(mapptr >= memory_map_size()) break; // Safety
+               dataptr[mapptr].waitval = wait;
+               mapptr++;
+       }
+}
+
+void TOWNS_MEMORY::unset_memory_devices_map(uint32_t start, uint32_t end, memory_device_map_t* dataptr, int wait)
+{
+       uint64_t _start = (uint64_t)start;
+       uint64_t _end =   (end == 0xffffffff) ? 0x100000000 : (uint64_t)(end + 1);
+       __UNLIKELY_IF(dataptr == NULL) return;
+
+       _start &= ~(memory_map_mask());
+       _end &= ~(memory_map_mask());
+
+       uint64_t mapptr = (uint32_t)(_start >> memory_map_shift());
+       const uint64_t _incval = memory_map_grain();
+       for(uint64_t addr = _start; addr < _end; addr += _incval) {
+               __UNLIKELY_IF(mapptr >= memory_map_size()) break; // Safety
+               dataptr[mapptr].mem_ptr = NULL;
+               dataptr[mapptr].device_ptr = NULL;
+               dataptr[mapptr].waitval = wait;
+               dataptr[mapptr].base_offset = UINT32_MAX;
+               mapptr++;
+       }
+
+}
+
+void TOWNS_MEMORY::set_mmio_memory_r(uint32_t start, uint32_t end, uint8_t* baseptr, uint32_t base_offset)
+{
+       set_memory_devices_map_values(start, end, &(membus_read_map[0]), baseptr, NULL, base_offset);
+}
+
+void TOWNS_MEMORY::set_mmio_memory_w(uint32_t start, uint32_t end, uint8_t* baseptr, uint32_t base_offset)
+{
+       set_memory_devices_map_values(start, end, &(membus_write_map[0]), baseptr, NULL, base_offset);
+}
+
+void  __FASTCALL TOWNS_MEMORY::set_mmio_device_r(uint32_t start, uint32_t end, DEVICE* ptr, uint32_t baseaddress)
+{
+       set_memory_devices_map_values(start, end, &(membus_read_map[0]), NULL, ptr, baseaddress);
+}
+
+void  __FASTCALL TOWNS_MEMORY::set_mmio_device_w(uint32_t start, uint32_t end, DEVICE* ptr, uint32_t baseaddress)
+{
+       set_memory_devices_map_values(start, end, &(membus_write_map[0]), NULL, ptr, baseaddress);
+}
+
+void  __FASTCALL TOWNS_MEMORY::set_mmio_wait_r(uint32_t start, uint32_t end, int wait)
+{
+       set_memory_devices_map_wait(start, end, &(membus_read_map[0]), wait);
+}
+
+void  __FASTCALL TOWNS_MEMORY::set_mmio_wait_w(uint32_t start, uint32_t end, int wait)
+{
+       set_memory_devices_map_wait(start, end, &(membus_write_map[0]), wait);
+}
+
+void TOWNS_MEMORY::unset_mmio_r(uint32_t start, uint32_t end, int wait)
+{
+       unset_memory_devices_map(start, end, &(membus_read_map[0]), wait);
+}
+
+void TOWNS_MEMORY::unset_mmio_w(uint32_t start, uint32_t end, int wait)
+{
+       unset_memory_devices_map(start, end, &(membus_write_map[0]), wait);
+}
+
+void TOWNS_MEMORY::unset_dma_r(uint32_t start, uint32_t end, int wait)
+{
+       unset_memory_devices_map(start, end, &(dma_read_map[0]), wait);
+}
+
+void TOWNS_MEMORY::unset_dma_w(uint32_t start, uint32_t end, int wait)
+{
+       unset_memory_devices_map(start, end, &(dma_write_map[0]), wait);
+}
+
+void TOWNS_MEMORY::set_dma_memory_r(uint32_t start, uint32_t end, uint8_t* baseptr, uint32_t base_offset)
+{
+       set_memory_devices_map_values(start, end, &(dma_read_map[0]), baseptr, NULL, base_offset);
+}
+
+void TOWNS_MEMORY::set_dma_memory_w(uint32_t start, uint32_t end, uint8_t* baseptr, uint32_t base_offset)
+{
+       set_memory_devices_map_values(start, end, &(dma_write_map[0]), baseptr, NULL, base_offset);
+}
+
+void  __FASTCALL TOWNS_MEMORY::set_dma_device_r(uint32_t start, uint32_t end, DEVICE* ptr, uint32_t baseaddress)
+{
+       set_memory_devices_map_values(start, end, &(dma_read_map[0]), NULL, ptr, baseaddress);
+}
+
+void  __FASTCALL TOWNS_MEMORY::set_dma_device_w(uint32_t start, uint32_t end, DEVICE* ptr, uint32_t baseaddress)
+{
+       set_memory_devices_map_values(start, end, &(dma_write_map[0]), NULL, ptr, baseaddress);
+}
+
+void  __FASTCALL TOWNS_MEMORY::set_dma_wait_r(uint32_t start, uint32_t end, int wait)
+{
+       set_memory_devices_map_wait(start, end, &(dma_read_map[0]), wait);
+}
+
+void  __FASTCALL TOWNS_MEMORY::set_dma_wait_w(uint32_t start, uint32_t end, int wait)
+{
+       set_memory_devices_map_wait(start, end, &(dma_write_map[0]), wait);
+}
+
+
+bool TOWNS_MEMORY::set_cpu_clock_by_wait()
+{
+       uint32_t cpu_bak = cpu_clock_val;
+       cpu_clock_val = (is_faster_wait()) ?
+               get_cpu_clocks(d_cpu) : (16 * 1000 * 1000);
+       return ((cpu_clock_val != cpu_bak) ? true : false);
+}
+void TOWNS_MEMORY::set_wait_values()
+{
+       uint32_t waitfactor = 0;
+       if(cpu_clock_val < get_cpu_clocks(d_cpu)) {
+               waitfactor = (uint32_t)(((double)get_cpu_clocks(d_cpu) / (double)cpu_clock_val) * 65536.0);
+       }
+       d_cpu->write_signal(SIG_CPU_WAIT_FACTOR, waitfactor, 0xffffffff);
 }
 
 void TOWNS_MEMORY::release()
 {
+//     if(rd_table != NULL) free(rd_table);
+//     if(rd_dummy != NULL) free(rd_dummy);
+//     if(wr_table != NULL) free(wr_table);
+//     if(wr_dummy != NULL) free(wr_dummy);
+
        if(extra_ram != NULL) {
                free(extra_ram);
                extra_ram = NULL;
        }
+
 }
 void TOWNS_MEMORY::reset()
 {
        // reset memory
-       protect = rst = 0;
        // ToDo
-       dma_addr_reg = dma_wrap_reg = 0;
-       dma_addr_mask = 0x00ffffff;
-       d_cpu->set_address_mask(0xffffffff);
+       update_machine_features(); // Update MISC3, MISC4 by MACHINE ID.
+       is_compatible = true;
+       reset_happened = false;
+
+       nmi_vector_protect = false;
+       ankcg_enabled = false;
+       nmi_mask = false;
+       //config_page0c_0e(false, false, true); // VRAM, DICT, FORCE
+       reset_wait_values();
+       config_page0c_0e(false, false, true); // VRAM, DICT, FORCE
+       config_page0f(true,  true); // SYSROM, FORCE
+
+
+       set_cpu_clock_by_wait();
+       set_wait_values();
+#if 1
+       __LIKELY_IF(d_cpu != NULL) {
+               d_cpu->set_address_mask(0xffffffff);
+       }
+       if(d_dmac != NULL) {
+               uint8_t wrap_val = 0xff; // WRAP ON
+               d_dmac->write_signal(SIG_TOWNS_DMAC_WRAP, wrap_val, 0xff);
+       }
+#endif
 }
-       
-// 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)
+
+void TOWNS_MEMORY::update_machine_features()
 {
-       uint32_t val = 0xff;
+       // 0024h: MISC3
+       reg_misc3 = 0xff;
+       if(machine_id >= 0x0b00) { // After MA/MX/ME
+               reg_misc3 &= ~0x04; // DMACMD
+       }
+       if(machine_id >= 0x0700) { // After HR/HG
+               reg_misc3 &= ~0x08; // POFFEN
+       }
+       if(machine_id >= 0x0700) { // After HR/HG
+               reg_misc3 &= ~0x10; // Free run counter
+       }
+       if(machine_id >= 0x0700) { // After HR/HG
+               reg_misc3 &= ~0x20; // CRTPOWOFF (0022h)
+       }
+       if(machine_id >= 0x0700) { // After HR/HG
+               reg_misc3 &= ~0x40; // RCREN
+       }
+       if(machine_id >= 0x0700) { // After HR/HG
+               reg_misc3 &= ~0x80; // ENPOFF
+       }
+       // 0025h: NMICNT
+       if(machine_id >= 0x0500) { // After CX
+               reg_misc4 = 0x7f;
+       } else {
+               reg_misc4 = 0xff;
+       }
+}
+
+uint8_t TOWNS_MEMORY::read_fmr_ports8(uint32_t addr)
+{
+       uint8_t val = 0xff;
+       __UNLIKELY_IF((addr < 0xcff80) || (addr > 0xcffbb)) {
+               return val;
+       }
+       __LIKELY_IF(addr < 0xcff88) {
+               __LIKELY_IF(d_planevram != NULL) {
+                       val = d_planevram->read_memory_mapped_io8(addr & 0xffff);
+               }
+               return val;
+       }
+       if((machine_id >= 0x0600) && !(is_compatible)) { // After UG
+               switch(addr) {
+               case 0xcff88:
+                       __LIKELY_IF(d_crtc != NULL) {
+                               val = d_crtc->read_signal(SIG_TOWNS_CRTC_MMIO_CFF82H);
+                       }
+                       return val;
+                       break;
+               case 0xcff99:
+                       return (ankcg_enabled) ? 0x01 : 0x00;
+                       break;
+               case 0xcff9c:
+               case 0xcff9d:
+               case 0xcff9e:
+                       __LIKELY_IF(d_font != NULL) {
+                               val = d_font->read_io8(addr & 0xffff);
+                       }
+                       return val;
+                       break;
+               default:
+                       break;
+               }
+       }
+       switch(addr) {
+       case 0xcff94:
+       case 0xcff95:
+       case 0xcff96:
+       case 0xcff97:
+               __LIKELY_IF(d_font != NULL) {
+                       val = d_font->read_io8(addr & 0xffff);
+               }
+               break;
+       case 0xcff98:
+               __LIKELY_IF(d_timer != NULL) {
+                       d_timer->write_signal(SIG_TIMER_BEEP_ON, 1, 1);
+               }
+               break;
+       case 0xcff99:
+               __LIKELY_IF(d_planevram != NULL) {
+                       val = d_planevram->read_memory_mapped_io8(addr);
+               }
+               break;
+       default:
+               break;
+       }
+       return val;
+}
+uint8_t TOWNS_MEMORY::read_sys_ports8(uint32_t addr)
+{
+    uint8_t val;
+       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);
+               val = ((software_reset) ? 1 : 0) | ((reset_happened) ? 2 : 0);
+               reset_happened = false;
                software_reset = false;
-               d_cpu->set_shutdown_flag(0);
-               val =  val | 0x7c;
+               __UNLIKELY_IF(d_cpu != NULL) {
+                       d_cpu->set_shutdown_flag(0);
+               }
+               if((machine_id >= 0x0300) && ((machine_id & 0xff00) != 0x0400)) { // After UX
+                       val = val | ((poff_status) ? 0x04 : 0x00);
+               }
                break;
        case 0x0022:
-               // Power register
-               val = 0xff;
+//             val.b.l = 0xff;
+//             if(d_dmac != NULL) {
+//                     val = d_dmac->read_signal(SIG_TOWNS_DMAC_ADDR_REG);
+//             }
+               break;
+               // 0024, 0025 : MISC3 + MISC4
+       case 0x0024:
+               val = reg_misc3;
+               break;
+       case 0x0025:
+               val = reg_misc4;
+               break;
+       case 0x0028:
+               // NMI MASK
+               if(machine_id >= 0x0500) { // After CX
+                       val = (nmi_mask) ? 0x01 : 0x00;
+               }
                break;
        case 0x0030:
-               val = (((machine_id & 0x1f) << 3) | (cpu_id & 7));
-               // SPEED: bit0/Write
+               // 20210227 K.O
+               // From FMTowns::MachineID()  of TSUGARU,
+               // git 83d4ec2309ac9fcbb8c01f26061ff0d49c5321e4.
+//             if((config.dipswitch & TOWNS_DIPSW_PRETEND_I386) != 0) {
+//                     val = ((machine_id & 0xf8) | 1);
+//             } else {
+                       val = ((machine_id & 0xf8) | (cpu_id & 7));
+//             }
                break;
        case 0x0031:
-               val = ((machine_id >> 5) & 0xff);
+               val = ((machine_id >> 8) & 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);
+                       //bool __cs = (d_serialrom->read_signal(SIG_SERIALROM_CS) == 0);
+                       bool __clk = (d_serialrom->read_signal(SIG_SERIALROM_CLK) != 0);
+                       bool __reset = (d_serialrom->read_signal(SIG_SERIALROM_RESET) != 0);
+                       bool __dat = (d_serialrom->read_signal(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;
+       case 0x00c0: // Cache
+               val = 0x00;
+               if((cpu_id == 0x02) || (cpu_id >= 0x04)) { // i486 SX/DX or After Pentium.
+                       // ToDo: Implement around cache.
+                       // Modified by this register and (05ECh:bit0 / Wait register).
+                       // Now, cache is always disabled.
+                       // RPNH = 0 (Disabled) : Bit1
+                       // CMEN = 0 (Disabled) : Bit0
+                       val = 0x00;
+               }
+               break;
+       case 0x00c2: // Cache Diagnostic
+               val = 0x00;
+               if((cpu_id == 0x02) || (cpu_id >= 0x04)) { // i486 SX/DX or After Pentium.
+                       // ToDo: Implement cache disgnostic.
+                       // SDMOD (Not diagnostic) : Bit3
+                       val = 0x00;
                }
                break;
        case 0x0400: // Resolution:
                val = 0xfe;
                break;
        case 0x0404: // System Status Reg.
-               val = (bankc0_vram) ? 0x7f : 0xff;
+               val = (dma_is_vram) ? 0x7f : 0xff;
+//             val = (dma_is_vram) ? 0x00 : 0x80;
+               break;
+       case 0x0480:
+               val  =  (select_d0_dict) ? 0x01 : 0x00;
+               val |=  ((select_d0_rom) ? 0x00 : 0x02);
+               val |= 0xfc;
                break;
        case 0x05c0:
-               val = (extra_nmi_mask) ? 0xf7 : 0xff;
+//             val = (extra_nmi_mask) ? 0xf7 : 0xff;
+               val = (extra_nmi_mask) ? 0x00 : 0x08;
                break;
        case 0x05c2:
-               val = (extra_nmi_val) ? 0xff : 0xf7;
+//             val = (extra_nmi_val) ? 0xff : 0xf7;
+               val = (extra_nmi_val) ? 0x08 : 0x00;
+               break;
+       case 0x05e0:
+               if(machine_id < 0x0200) { // Towns 1/2
+                       val =  wait_register_older;
+               }
+               break;
+       case 0x05e2:
+               if(machine_id >= 0x0200) { // i386
+                       val = wait_register_ram;
+               }
+               break;
+       case 0x05e6:
+               if(machine_id >= 0x0200) { // i386
+                       val = wait_register_vram;
+               }
                break;
        case 0x05e8:
                // After Towns1F/2F/1H/2H
                {
-                       switch(machine_id & 0xff00) {
-                       case 0x0000:
-                       case 0x0100:
+                       uint16_t nid = machine_id & 0xff00;
+                       val = extram_size >> 20;
+                       switch(nid >> 8) {
+                       case 0x00:
+                       case 0x01: // Towns 1/2 : Not Supported.
                                val = 0xff;
                                break;
-                       case 0x0200:
-                       case 0x0300:
-                       case 0x0400:
-                       case 0x0500:
-                       case 0x0600:
-                       case 0x0700:
-                       case 0x0800:
-                       case 0x0a00:
-                               val = ((extram_size >> 20) & 0x1f);
+                       case 0x03: // Towns II UX
+                       case 0x06: // Towns II U6
+                               val = val & 0x0f;
+                               if(val >= 9) val = 9;
+                               break;
+                       case 0x02: // Towns 1F/2F/1H/2H.
+                       case 0x04: // Towns 10F/20F/40H/80H.
+                               val = val & 0x07;
+                               break;
+                       case 0x05: // Towns II CX
+                               val = val & 0x0f;
+                               break;
+                       case 0x08: // Towns II HG : OK?
+                               val = val & 0x0f;
                                break;
-                       case 0x0b00:
-                       case 0x0c00:
-                       case 0x0d00:
-                       case 0x0f00:
-                               val = ((extram_size >> 20) & 0x7f);
+                       case 0x07: // Towns II HR
+                       case 0x09: // Towns II UR
+                               val = val & 0x1f;
                                break;
-                       default:
-                               val = 0xff; // ???
+                       default:   // After MA/MX/ME/MF, Fresh
+                               val = val & 0x7f;
                                break;
                        }
                }
                break;
-          
        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); 
+               // 05ec, 05ed
+               if(machine_id >= 0x0200) { // 05ec
+                       val = ((is_faster_wait()) ? 0x01 : 0x00);
+               }
+               break;
+       case 0x05ed:
+               if(machine_id >= 0x0700) { // 05ed
+                       uint32_t clk = get_cpu_clocks(d_cpu);
+                       clk = clk / (1000 * 1000);
+                       __UNLIKELY_IF(clk < 16) clk = 16;
+                       __UNLIKELY_IF(clk > 127) clk = 127; // ToDo
+                       val = 0x00 | clk;
+               }
+               break;
+       case 0xfda4:
+               if(machine_id >= 0x0700) { // After HR/HG
+                       val = (is_compatible) ? 0x00 : 0x01;
+               } else {
+                       val = 0x00;
                }
                break;
        default:
@@ -201,10 +652,79 @@ uint32_t TOWNS_MEMORY::read_io8(uint32_t addr)
        }
        return val;
 }
+// Address (TOWNS BASIC):
+// 0x0020 - 0x0022, 0x0030-0x0031,
+// 0x0400 - 0x0404,
+// 0x0480 - 0x0484
+// 0x05c0 - 0x05c2
+// 0x05ec (Wait register)
+// 0x05ed (CPU SPEED REGISTER)
+// Is set extra NMI (0x05c0 - 0x05c2)?
+uint32_t TOWNS_MEMORY::read_io8(uint32_t addr)
+{
+//     uint32_t val = 0x00;  // MAY NOT FILL to "1" for unused bit 20200129 K.O
+       __LIKELY_IF((addr & 0xffff) >= 0xff80) {
+               return read_fmr_ports8((addr & 0xffff) | 0x000c0000);
+       }
+       return read_sys_ports8(addr);
+}
 
-void TOWNS_MEMORY::write_io8(uint32_t addr, uint32_t data)
+void TOWNS_MEMORY::write_fmr_ports8(uint32_t addr, uint32_t data)
 {
+       __UNLIKELY_IF((addr < 0xcff80) || (addr > 0xcffbb)) {
+               return;
+       }
+
+       __LIKELY_IF(addr < 0xcff88) {
+               __LIKELY_IF(d_planevram != NULL) {
+                       d_planevram->write_io8(addr & 0xffff, data);
+               }
+               return;
+       }
 
+       if((machine_id >= 0x0600) && !(is_compatible)) { // After UG
+               switch(addr) {
+               case 0xcff9e:
+                       __LIKELY_IF(d_font != NULL) {
+                               d_font->write_io8(addr & 0xffff, data);
+                       }
+                       return;
+               default:
+                       break;
+               }
+       }
+       switch(addr) {
+       case 0xcff94:
+       case 0xcff95:
+               __LIKELY_IF(d_font != NULL) {
+                       d_font->write_io8(addr & 0xffff, data);
+               }
+               break;
+       case 0xcff96:
+       case 0xcff97:
+               break;
+       case 0xcff98:
+               __LIKELY_IF(d_timer != NULL) {
+                       d_timer->write_signal(SIG_TIMER_BEEP_ON, 0, 1);
+               }
+               break;
+       case 0xcff99:
+               {
+                       bool _b = ankcg_enabled;
+                       ankcg_enabled = ((data & 1) != 0) ? true : false;
+               }
+               break;
+       case 0xcffa0:
+               __LIKELY_IF(d_planevram != NULL) {
+                       d_planevram->write_io8(addr & 0xffff, data);
+               }
+               break;
+       default:
+               break;
+       }
+}
+void TOWNS_MEMORY::write_sys_ports8(uint32_t addr, uint32_t data)
+{
        switch(addr & 0xffff) {
        case 0x0020: // Software reset ETC.
                // reset cause register
@@ -218,232 +738,659 @@ void TOWNS_MEMORY::write_io8(uint32_t addr, uint32_t data)
                } else {
                        software_reset = false;
                }
+
                if((data & 0x40) != 0) {
-                       d_cpu->set_shutdown_flag(1);
-                       emu->power_off();
+                       poff_status = true;
+//                     __LIKELY_IF(d_cpu != NULL) {
+//                             d_cpu->set_shutdown_flag(1);
+//                     }
+                       // Todo: Implement true power off.
+//                     emu->notify_power_off();
+//                     emu->power_off();
+//                     break;
+               } else {
+                       poff_status = false;
+//                     __LIKELY_IF(d_cpu != NULL) {
+//                             d_cpu->set_shutdown_flag(0);
+//                     }
                }
-               if(software_reset) {
-                       d_cpu->reset();
+
+               if((software_reset) || (poff_status)){
+//                     __LIKELY_IF(d_cpu != NULL) {
+//                             d_cpu->reset();
+//                     }
+                       uint8_t wrap_val = 0xff; // WRAP ON
+                       __LIKELY_IF(d_dmac != NULL) {
+                               d_dmac->write_signal(SIG_TOWNS_DMAC_WRAP, wrap_val, 0xff);
+                       }
+                       if(poff_status) {
+                               __LIKELY_IF(d_cpu != NULL) {
+                                       d_cpu->set_shutdown_flag(1);
+                               }
+                               // Todo: Implement true power off.
+                                emu->notify_power_off();
+                               // emu->power_off();
+                       }
+                       vm->reset();
                }
+               // Towns SEEMS to not set addreess mask (a.k.a A20 mask). 20200131 K.O
                break;
        case 0x0022:
                if((data & 0x40) != 0) {
-                       d_cpu->set_shutdown_flag(1);
-                       emu->power_off();
+                       __LIKELY_IF(d_cpu != NULL) {
+                               d_cpu->set_shutdown_flag(1);
+                       }
+                       // Todo: Implement true power off.
+                       poff_status = true;
+                       emu->notify_power_off();
+//                     emu->power_off();
+                       vm->reset();
                }
                // Power register
                break;
+       case 0x0024:
+               //if((d_dmac != NULL) && (machine_id >= 0x0b00)) { // After MA/MX/ME
+               //      d_dmac->write_signal(SIG_TOWNS_DMAC_WRAP, data, 0xff);
+               //}
+               break;
        case 0x0032:
+               d_serialrom->write_signal(SIG_SERIALROM_CS, ~data, 0x20);
+               d_serialrom->write_signal(SIG_SERIALROM_CLK, data, 0x40);
+               d_serialrom->write_signal(SIG_SERIALROM_RESET, data, 0x80);
+               break;
+       case 0x0404: // System Status Reg.
                {
-                       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);
+                       config_page0c_0e(((data & 0x80) == 0) ? true : false, select_d0_dict, false); // VRAM, DICT, FORCE
                }
                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);
+       case 0x0480:
+               {
+                       bool is_dict, is_sysrom;
+                       is_dict = ((data & 0x01) != 0) ? true : false;
+                       is_sysrom = ((data & 0x02) == 0) ? true : false;
+                       config_page0c_0e(dma_is_vram, is_dict, false);
+                       config_page0f(is_sysrom, false);
                }
                break;
-       case 0x0404: // System Status Reg.
-               bankc0_vram = ((data & 0x80) != 0);
-               break;
        case 0x05c0:
                extra_nmi_mask = ((data & 0x08) == 0);
                break;
+       case 0x05e0:
+               // From AB.COM
+               if(machine_id < 0x0200) { // Towns 1/2
+                       uint8_t nval_bak = wait_register_older & 0x07;
+                       uint8_t nval = data & 0x07;
+                       if(nval < 1) nval = 1;
+                       mem_wait_val = nval;
+                       vram_wait_val = nval + 3; // OK?
+                       if(vram_wait_val > 6) {
+                               vram_wait_val = 6;
+                       }
+                       wait_register_older = (data & 0xf8) | nval;
+                       cpu_clock_val = 16 * 1000 * 1000;
+                       if(nval_bak != nval) {
+                               set_cpu_clock_by_wait();
+                               set_wait_values();
+                       }
+               }
+               break;
+       case 0x05e2:
+               if(machine_id >= 0x0200) { // After Towns 1H/2F. Hidden wait register.
+                       uint8_t vram_bak = vram_wait_val;
+                       uint8_t mem_bak = mem_wait_val;
+                       if(data != 0x83) {
+                               uint8_t nval = data & 7;
+                               if(machine_id <= 0x0200) { // Towns 1H/2F.
+                                       if(nval < 1) nval = 1;
+                               }
+                               if(nval > 6) nval = 6;
+                               mem_wait_val = nval;
+                               wait_register_ram = (data & 0xf8) | nval;
+                       } else {
+                               mem_wait_val = 3;
+                               vram_wait_val = 6;
+                               wait_register_ram = data;
+                       }
+                       if((vram_bak != vram_wait_val) || (mem_bak != mem_wait_val)) {
+                               set_cpu_clock_by_wait();
+                               set_wait_values();
+                       }
+               }
+               break;
+       case 0x05e6:
+               if(machine_id >= 0x0200) { // After Towns 1H/2F. Hidden wait register.
+                       uint8_t mem_bak = mem_wait_val;
+                       uint8_t vram_bak = vram_wait_val;
+                       if(data != 0x83) {
+                               uint8_t nval = data & 7;
+                               if(machine_id <= 0x0200) { // Towns 1H/2F.
+                                       if(nval < 1) nval = 1;
+                               }
+                               if(nval > 6) nval = 6;
+                               vram_wait_val = nval;
+                               wait_register_vram = (data & 0xf8) | nval;
+                       } else {
+                               mem_wait_val = 3;
+                               vram_wait_val = 3;
+                               wait_register_vram = data;
+                       }
+                       if((vram_bak != vram_wait_val) || (mem_bak != mem_wait_val)) {
+                               set_cpu_clock_by_wait();
+                               set_wait_values();
+                       }
+               }
+               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);
+               // ToDo: 0x05ed
+               if(machine_id >= 0x0500) { // Towns2 CX :
+                       uint8_t mem_bak = mem_wait_val;
+                       uint8_t vram_bak = vram_wait_val;
+                       vram_wait_val = ((data & 0x01) != 0) ? 0 : 6;
+                       mem_wait_val = ((data & 0x01) != 0) ? 0 : 6;
+                       wait_register_ram = mem_wait_val;
+                       wait_register_vram = vram_wait_val;
+                       if((mem_bak != mem_wait_val) || (vram_bak != vram_wait_val)) {
+                               set_cpu_clock_by_wait();
+                               set_wait_values();
+                       }
+               }
+               break;
+
+       case 0xfda4:
+               if(machine_id >= 0x0700) { // After HR/HG
+                       is_compatible = ((data & 0x01) == 0x00) ? true : false;
+                       __LIKELY_IF(d_crtc != NULL) {
+                               d_crtc->write_signal(SIG_TOWNS_CRTC_COMPATIBLE_MMIO, (is_compatible) ? 0xffffffff : 0x00000000, 0xffffffff);
+                       }
                }
                break;
        default:
                break;
        }
-       return;
+}
+void TOWNS_MEMORY::write_io8(uint32_t addr, uint32_t data)
+{
+       __LIKELY_IF((addr & 0xffff) >= 0xff80) {
+               write_fmr_ports8((addr & 0xffff) | 0x000c0000, data);
+               return;
+       }
+       write_sys_ports8(addr, data);
+}
+
+
+uint32_t TOWNS_MEMORY::read_data8w(uint32_t addr, int* wait)
+{
+       uint32_t mapptr = (uint32_t)(((uint64_t)addr) >> memory_map_shift());
+       uint32_t offset = addr & memory_map_mask();
+       return read_8bit_data(membus_read_map, mapptr, addr, offset, false, wait);
+}
+
+uint32_t TOWNS_MEMORY::read_data16w(uint32_t addr, int* wait)
+{
+       uint16_t val;
+       uint32_t mapptr = (uint32_t)(((uint64_t)addr) >> memory_map_shift());
+       uint32_t offset = addr & memory_map_mask();
+       __UNLIKELY_IF(check_device_boundary(membus_read_map, mapptr, offset, 2)) {
+               val = read_beyond_boundary_data16(membus_read_map, addr, offset, mapptr, false, wait);
+       } else {
+               val = read_16bit_data(membus_read_map, mapptr, addr, offset, false, wait);
+       }
+       return val;
+}
+
+uint32_t TOWNS_MEMORY::read_data32w(uint32_t addr, int* wait)
+{
+       uint32_t val;
+       uint32_t mapptr = (uint32_t)(((uint64_t)addr) >> memory_map_shift());
+       uint32_t offset = addr & memory_map_mask();
+       __UNLIKELY_IF(check_device_boundary(membus_read_map, mapptr, offset, 4)) {
+               val =  read_beyond_boundary_data32(membus_read_map, addr, offset, mapptr,false,  wait);
+       } else {
+               val = read_32bit_data(membus_read_map, mapptr, addr, offset, false, wait);
+
+       }
+       return val;
+}
+
+uint32_t TOWNS_MEMORY::read_dma_data8w(uint32_t addr, int* wait)
+{
+       uint32_t mapptr = (uint32_t)(((uint64_t)addr) >> memory_map_shift());
+       uint32_t offset = addr & memory_map_mask();
+       uint8_t val;
+       int waitval;
+       val = read_8bit_data(dma_read_map, mapptr, addr, offset, true, &waitval);
+       //val = read_8bit_data(dma_read_map, mapptr, addr, offset, false, &waitval);
+       __LIKELY_IF(wait != NULL) {
+               *wait = 0; // Discard wait value for DMA.
+       }
+       return val;
+}
+
+uint32_t TOWNS_MEMORY::read_dma_data16w(uint32_t addr, int* wait)
+{
+       uint32_t mapptr = (uint32_t)(((uint64_t)addr) >> memory_map_shift());
+       uint32_t offset = addr & memory_map_mask();
+       uint16_t val;
+       int waitval;
+       __UNLIKELY_IF(check_device_boundary(dma_read_map, mapptr, offset, 2)) {
+               val = read_beyond_boundary_data16(dma_read_map, addr, offset, mapptr, true, &waitval);
+       } else {
+               val = read_16bit_data(dma_read_map, mapptr, addr, offset, true, &waitval);
+               //val = read_16bit_data(dma_read_map, mapptr, addr, offset, false, &waitval);
+       }
+       __LIKELY_IF(wait != NULL) {
+               *wait = 0; // Discard wait value for DMA.
+       }
+       return val;
+
 }
 
-void TOWNS_MEMORY::event_callback(int id, int err)
+uint32_t TOWNS_MEMORY::read_dma_data32w(uint32_t addr, int* wait)
 {
-       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);
+       uint32_t val;
+       int waitval;
+       uint32_t mapptr = (uint32_t)(((uint64_t)addr) >> memory_map_shift());
+       uint32_t offset = addr & memory_map_mask();
+       __UNLIKELY_IF(check_device_boundary(dma_read_map, mapptr, offset, 4)) {
+               val =  read_beyond_boundary_data32(dma_read_map, addr, offset, mapptr, true, &waitval);
+       } else {
+               val = read_32bit_data(dma_read_map, mapptr, addr, offset, true, &waitval);
+               //val = read_32bit_data(dma_read_map, mapptr, addr, offset, false, &waitval);
+       }
+       __LIKELY_IF(wait != NULL) {
+               *wait = 0; // Discard wait value for DMA.
+       }
+       return val;
+}
+
+
+void TOWNS_MEMORY::write_data8w(uint32_t addr, uint32_t data, int* wait)
+{
+       uint32_t mapptr = (uint32_t)(((uint64_t)addr) >> memory_map_shift());
+       uint32_t offset = addr & memory_map_mask();
+       write_8bit_data(membus_write_map, mapptr, addr, offset, false, data, wait);
+}
+
+
+void TOWNS_MEMORY::write_data16w(uint32_t addr, uint32_t data, int* wait)
+{
+       uint32_t mapptr = (uint32_t)(((uint64_t)addr) >> memory_map_shift());
+       uint32_t offset = addr & memory_map_mask();
+       __UNLIKELY_IF(check_device_boundary(membus_write_map, mapptr, offset, 2)) {
+               write_beyond_boundary_data16(membus_write_map, addr, offset, mapptr, false, data, wait);
+       } else {
+               write_16bit_data(membus_write_map, mapptr, addr, offset, false, data, wait);
+       }
+}
+
+
+void TOWNS_MEMORY::write_data32w(uint32_t addr, uint32_t data, int* wait)
+{
+       uint32_t mapptr = (uint32_t)(((uint64_t)addr) >> memory_map_shift());
+       uint32_t offset = addr & memory_map_mask();
+       __UNLIKELY_IF(check_device_boundary(membus_write_map, mapptr, offset, 4)) {
+               write_beyond_boundary_data32(membus_write_map, addr, offset, mapptr, false, data, wait);
+       } else {
+               write_32bit_data(membus_write_map, mapptr, addr, offset, false, data, wait);
+       }
+}
+
+void TOWNS_MEMORY::write_dma_data8w(uint32_t addr, uint32_t data, int* wait)
+{
+       uint32_t mapptr = (uint32_t)(((uint64_t)addr) >> memory_map_shift());
+       uint32_t offset = addr & memory_map_mask();
+       int waitval;
+       write_8bit_data(dma_write_map, mapptr, addr, offset, true, data, &waitval);
+       //write_8bit_data(dma_write_map, mapptr, addr, offset, false, data, &waitval);
+       __LIKELY_IF(wait != NULL) {
+               *wait = 0; // Discard wait value for DMA.
+       }
+}
+
+void TOWNS_MEMORY::write_dma_data16w(uint32_t addr, uint32_t data, int* wait)
+{
+       uint32_t mapptr = (uint32_t)(((uint64_t)addr) >> memory_map_shift());
+       uint32_t offset = addr & memory_map_mask();
+       int waitval;
+       __UNLIKELY_IF(check_device_boundary(dma_write_map, mapptr, offset, 2)) {
+               write_beyond_boundary_data16(dma_write_map, addr, offset, mapptr, true, data, &waitval);
+       } else {
+               write_16bit_data(dma_write_map, mapptr, addr, offset, true, data, &waitval);
+               //write_16bit_data(dma_write_map, mapptr, addr, offset, false, data, &waitval);
+       }
+       __LIKELY_IF(wait != NULL) {
+               *wait = 0; // Discard wait value for DMA.
+       }
+}
+
+
+void TOWNS_MEMORY::write_dma_data32w(uint32_t addr, uint32_t data, int* wait)
+{
+       uint32_t mapptr = (uint32_t)(((uint64_t)addr) >> memory_map_shift());
+       uint32_t offset = addr & memory_map_mask();
+       int waitval;
+       __UNLIKELY_IF(check_device_boundary(dma_write_map, mapptr, offset, 4)) {
+               write_beyond_boundary_data32(dma_write_map, addr, offset, mapptr, true, data, &waitval);
+       } else {
+               write_32bit_data(dma_write_map, mapptr, addr, offset, true, data, &waitval);
+               //write_32bit_data(dma_write_map, mapptr, addr, offset, false, data, &waitval);
+       }
+       __LIKELY_IF(wait != NULL) {
+               *wait = 0; // Discard wait value for DMA.
+       }
+}
+
+uint32_t TOWNS_MEMORY::read_memory_mapped_io8w(uint32_t addr, int* wait)
+{
+       // This should be for VRAM MODE, with ROMs (000C8000h - 000CFFFFh)
+       __LIKELY_IF(wait != NULL) {
+               *wait = 0; // ToDo
+       }
+       __UNLIKELY_IF((addr >= 0x000d0000) || (addr < 0x000c8000)) {
+               // Out of bounds;
+               return 0xff;
+       }
+       __LIKELY_IF(addr < 0x000c9000) { // TEXT VRAM (ANK)
+               __LIKELY_IF(d_sprite != NULL) {
+                       return d_sprite->read_memory_mapped_io8w(addr - 0xc8000, wait);
+               }
+               return 0xff;
+       }
+       __LIKELY_IF(addr >= 0x000cc000) {
+               // RAM: OK?
+               __UNLIKELY_IF(addr >= 0x000cff80) { // I/O
+                       return read_fmr_ports8(addr);
+               } else {
+                       __LIKELY_IF(extra_ram != NULL) {
+                               return extra_ram[addr];
+                       }
+                       return 0xff;
                }
-               break;
-       default:
-               break;
        }
-       
+       // ROMs?
+       if(ankcg_enabled) {
+               if(addr >= 0xca000) {
+                       __LIKELY_IF(d_font != NULL) {
+                               return d_font->read_memory_mapped_io8(addr);
+                       }
+               }
+       } else {
+               if(addr < 0xcb000) {
+                       __LIKELY_IF(d_sprite != NULL) {
+                               return d_sprite->read_memory_mapped_io8w(addr - 0xc8000, wait);
+                       }
+               }
+       }
+       return 0xff;
 }
 
-uint32_t TOWNS_MEMORY::read_mmio(uint32_t addr, int *wait, bool *hit)
+uint32_t TOWNS_MEMORY::read_memory_mapped_io16w(uint32_t addr, int* wait)
 {
-       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;
+       __LIKELY_IF(wait != NULL) {
+               *wait = 0; // ToDo
+       }
+       // This should be for VRAM MODE, with ROMs (000C8000h - 000CFFFFh)
+       __UNLIKELY_IF((addr >= 0x000d0000) || (addr < 0x000c8000)) {
+               // out of bounds
+               return 0xffff;
+       }
+       if(addr < 0x000c9000) { // TEXT VRAM (ANK)
+               __LIKELY_IF(d_sprite != NULL) {
+                       return d_sprite->read_memory_mapped_io16w(addr - 0xc8000, wait);
                }
-               break;
-       case 0x01:
-               if(d_vram != NULL) {
-                       val = d_vram->read_io8(FMTOWNS_VRAM_IO_FMR_RAMSELECT);
-                       found = true;
+               return 0xffff;
+       }
+       __LIKELY_IF(addr >= 0x000cc000) {
+               // RAM: OK?
+               pair16_t w;
+               __UNLIKELY_IF((addr >= 0x000cff80) && (addr < 0x000cffff)) { // I/O
+                       w.b.l = read_fmr_ports8(addr);
+                       w.b.h = read_fmr_ports8(addr + 1);
+               } else {
+                       __LIKELY_IF(extra_ram != NULL) {
+                               w.read_2bytes_le_from(&(extra_ram[addr]));
+                       } else {
+                               w.w = 0xffff;
+                       }
                }
-               break;
-       case 0x02:
-               if(d_vram != NULL) {
-                       val = d_vram->read_io8(FMTOWNS_VRAM_IO_FMR_DISPMODE);
-                       found = true;
+               return w.w;
+       }
+       // ROMs?
+       if(ankcg_enabled) {
+               if(addr >= 0xca000) {
+                       __LIKELY_IF(d_font != NULL) {
+                               return d_font->read_memory_mapped_io16(addr);
+                       }
                }
-               break;
-       case 0x03:
-               if(d_vram != NULL) {
-                       val = d_vram->read_io8(FMTOWNS_VRAM_IO_FMR_PAGESEL);
-                       found = true;
+       } else {
+               if(addr < 0xcb000) {
+                       __LIKELY_IF(d_sprite != NULL) {
+                               return d_sprite->read_memory_mapped_io16w(addr - 0xc8000, wait);
+                       }
                }
-               break;
-       case 0x04:
-               val = 0x7f; // Reserve.FIRQ
-               found = true;
-               break;
-       case 0x06:
-               if(d_vram != NULL) {
-                       val = d_vram->read_io8(FMTOWNS_VRAM_IO_SYNC_STATUS);
-                       found = true;
+       }
+       return 0xffff;
+}
+
+uint32_t TOWNS_MEMORY::read_memory_mapped_io32w(uint32_t addr, int* wait)
+{
+       __LIKELY_IF(wait != NULL) {
+               *wait = 0; // ToDo
+       }
+       // This should be for VRAM MODE, with ROMs (000C8000h - 000CFFFFh)
+       __UNLIKELY_IF((addr > 0x000cffff) || (addr < 0x000c8000)) {
+               // out of bounds
+               return 0xffffffff;
+       }
+       if(addr < 0x000c9000) { //SPRITE
+               __LIKELY_IF(d_sprite != NULL) {
+                       return d_sprite->read_memory_mapped_io32w(addr - 0xc8000, wait);
                }
-               break;
-       //case 0x14:
-       //case 0x15:
-       case 0x16:
-       case 0x17:
-               if(d_vram != NULL) {
-                       val = d_vram->read_io8(FMTOWNS_VRAM_KANJICG + (addr & 3));
-                       found = true;
+               return 0xffffffff;
+       }
+       __LIKELY_IF(addr >= 0x000cc000) {
+               // RAM: OK?
+               pair32_t d;
+               __UNLIKELY_IF((addr >= 0x000cff80) && (addr < 0x000cfffd)) { // I/O
+                       d.b.l  = read_fmr_ports8(addr);
+                       d.b.h  = read_fmr_ports8(addr + 1);
+                       d.b.h2 = read_fmr_ports8(addr + 2);
+                       d.b.h3 = read_fmr_ports8(addr + 3);
+               } else {
+                       __LIKELY_IF(extra_ram != NULL) {
+                               d.read_4bytes_le_from(&(extra_ram[addr]));
+                       } else {
+                               d.d = 0xffffffff;
+                       }
                }
-               break;
-       case 0x18:
-               if(d_beep != NULL) {
-                       d_beep->write_signal(SIG_BEEP_ON, 1, 1);
-                       found = true;
+               return d.d;
+       }
+       // ROMs?
+       if(ankcg_enabled) {
+               if(addr >= 0xca000) {
+                       __LIKELY_IF(d_font != NULL) {
+                               return d_font->read_memory_mapped_io32(addr);
+                       }
+               }
+       } else {
+               if(addr < 0xcb000) {
+                       __LIKELY_IF(d_sprite != NULL) {
+                               return d_sprite->read_memory_mapped_io32w(addr - 0xc8000, wait);
+                       }
                }
-               break;
-       case 0x19:
-               val = val & ((ankcg_enabled) ? 0x00 : 0x01);
-               found = true;
-               break;
-       case 0x20:
-               val = 0xff;
-               val = val & 0x7f;
-               found = true;
-               break;
-       default:
-               break;
        }
-       if(hit != NULL) *hit = found;
-       return (uint32_t)val;
+       return 0xffffffff;
 }
 
-void TOWNS_MEMORY::write_mmio(uint32_t addr, uint32_t data, int *wait, bool *hit)
+
+void TOWNS_MEMORY::write_memory_mapped_io8w(uint32_t addr, uint32_t data, int* wait)
 {
-       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;
+       // This should be for VRAM MODE, with ROMs (000C8000h - 000CFFFFh)
+       __LIKELY_IF(wait != NULL) {
+               *wait = 0; // ToDo
+       }
+       __UNLIKELY_IF((addr >= 0x000d0000) || (addr < 0x000c8000)) {
+               // Out of bounds
+               return;
+       }
+       __LIKELY_IF(addr < 0xcb000) { // From Tsugaru.
+               __LIKELY_IF(d_sprite != NULL) {
+                       d_sprite->write_memory_mapped_io8w(addr - 0xc8000, data, wait);
+                       d_sprite->write_signal(SIG_TOWNS_SPRITE_TVRAM_ENABLED, 0xffffffff, 0xffffffff);
                }
-               break;
-       case 0x01:
-               if(d_vram != NULL) {
-                       d_vram->write_io8(FMTOWNS_VRAM_IO_FMR_RAMSELECT, data);
-                       found = true;
+               return;
+       }
+       __LIKELY_IF(addr >= 0x000cc000) {
+               // RAM: OK?
+               __UNLIKELY_IF(addr >= 0x000cff80) { // I/O
+                       write_fmr_ports8(addr, data);
+                       return;
                }
-               break;
-       case 0x02:
-               if(d_vram != NULL) {
-                       d_vram->write_io8(FMTOWNS_VRAM_IO_FMR_DISPMODE, data);
-                       found = true;
+               __LIKELY_IF(extra_ram != NULL) {
+                       extra_ram[addr] = data;
                }
-               break;
-       case 0x03:
-               if(d_vram != NULL) {
-                       d_vram->write_io8(FMTOWNS_VRAM_IO_FMR_PAGESEL, data);
-                       found = true;
+               return;
+       }
+       // ROMs?
+       return;
+}
+
+void TOWNS_MEMORY::write_memory_mapped_io16w(uint32_t addr, uint32_t data, int* wait)
+{
+       // This should be for VRAM MODE, with ROMs (000C8000h - 000CFFFFh)
+       __LIKELY_IF(wait != NULL) {
+               *wait = 0; // ToDo
+       }
+       __UNLIKELY_IF((addr > 0x000cffff) || (addr < 0x000c8000)) {
+               // Out of bounds
+               return;
+       }
+       __LIKELY_IF(addr < 0xcb000) { // From Tsugaru.
+               __LIKELY_IF(d_sprite != NULL) {
+                       d_sprite->write_memory_mapped_io16w(addr - 0xc8000, data, wait);
+                       d_sprite->write_signal(SIG_TOWNS_SPRITE_TVRAM_ENABLED, 0xffffffff, 0xffffffff);
                }
-               break;
-       case 0x04:
-               found = true;
-               break;
-       case 0x06:
-               found = true;
-               break;
-       case 0x14:
-       case 0x15:
-       case 0x16:
-       case 0x17:
-               if(d_vram != NULL) {
-                       d_vram->write_io8(FMTOWNS_VRAM_KANJICG + (addr & 3), data);
-                       found = true;
+               return;
+       }
+       __LIKELY_IF(addr >= 0x000cc000) {
+               // RAM: OK?
+               pair16_t w;
+               w.w = data;
+               __UNLIKELY_IF((addr >= 0x000cff80) && (addr < 0x000cffff)) { // I/O
+                       write_fmr_ports8(addr    , w.b.l);
+                       write_fmr_ports8(addr + 1, w.b.h);
+                       return;
                }
-               break;
-       case 0x18:
-               if(d_beep != NULL) {
-                       d_beep->write_signal(SIG_BEEP_ON, 0, 1);
-                       found = true;
+               __LIKELY_IF(extra_ram != NULL) {
+                       w.write_2bytes_le_to(&(extra_ram[addr]));
                }
-               break;
-       case 0x19:
-           ankcg_enabled = ((data & 1) == 0);
-               found = true;
-               break;
-       case 0x20:
-               found = true;
-               break;
-       default:
-               break;
+               return;
+       }
+       // ROMs?
+       return;
+}
+
+void TOWNS_MEMORY::write_memory_mapped_io32w(uint32_t addr, uint32_t data, int* wait)
+{
+       // This should be for VRAM MODE, with ROMs (000C8000h - 000CFFFFh)
+       __LIKELY_IF(wait != NULL) {
+               *wait = 0; // ToDo
+       }
+       __UNLIKELY_IF((addr >= 0x000d0000) || (addr < 0x000c8000)) {
+               return;
        }
-       if(hit != NULL) *hit = found;
+       __LIKELY_IF(addr < 0xcb000) { // From Tsugaru.
+               __LIKELY_IF(d_sprite != NULL) {
+                       d_sprite->write_memory_mapped_io32w(addr - 0xc8000, data, wait);
+                       d_sprite->write_signal(SIG_TOWNS_SPRITE_TVRAM_ENABLED, 0xffffffff, 0xffffffff);
+               }
+               return;
+       }
+       __LIKELY_IF(addr >= 0x000cc000) {
+               // RAM: OK?
+               pair32_t d;
+               d.d = data;
+               __UNLIKELY_IF((addr >= 0x000cff80) && (addr < 0x000cfffd)) { // I/O
+                       write_fmr_ports8(addr    , d.b.l);
+                       write_fmr_ports8(addr + 1, d.b.h);
+                       write_fmr_ports8(addr + 2, d.b.h2);
+                       write_fmr_ports8(addr + 3, d.b.h3);
+                       return;
+               }
+               __LIKELY_IF(extra_ram != NULL) {
+                       d.write_4bytes_le_to(&(extra_ram[addr]));
+               }
+               return;
+       }
+       // ROMs?
        return;
 }
+
+
+
 void TOWNS_MEMORY::write_signal(int ch, uint32_t data, uint32_t mask)
 {
        if(ch == SIG_MEMORY_EXTNMI) {
                extra_nmi_val = ((data & mask) != 0);
+               if(!(extra_nmi_mask)) {
+                       // Not MASK
+                       __LIKELY_IF(d_cpu != NULL) {
+                               d_cpu->write_signal(SIG_CPU_NMI, data, mask);
+                       }
+               }
        } else if(ch == SIG_CPU_NMI) {
                // Check protect
-               d_cpu->write_signal(SIG_CPU_NMI, data, mask);
+               if(!(nmi_mask)) {
+                       __LIKELY_IF(d_cpu != NULL) {
+                               d_cpu->write_signal(SIG_CPU_NMI, data, mask);
+                       }
+               }
        } else if(ch == SIG_CPU_IRQ) {
-               d_cpu->write_signal(SIG_CPU_IRQ, data, mask);
+               __LIKELY_IF(d_cpu != NULL) {
+                       d_cpu->write_signal(SIG_CPU_IRQ, data, mask);
+               }
        } else if(ch == SIG_CPU_BUSREQ) {
-               d_cpu->write_signal(SIG_CPU_BUSREQ, data, mask);
+               __LIKELY_IF(d_cpu != NULL) {
+                       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) {
+               __LIKELY_IF(d_cpu != NULL) {
+                       d_cpu->write_signal(SIG_I386_A20, data, mask);
+               }
+       } else if(ch == SIG_FMTOWNS_NOTIFY_RESET) {
+               out_debug_log("RESET FROM CPU!!!\n");
+               reset_happened = true;
+
+               nmi_vector_protect = false;
+               ankcg_enabled = false;
+               nmi_mask = false;
+               config_page0c_0e(true, false, true);
+               config_page0f(true, true);
+               reset_wait_values();
+               set_wait_values();
+
+               __LIKELY_IF(d_cpu != NULL) {
+                       d_cpu->set_address_mask(0xffffffff);
+               }
+               __LIKELY_IF(d_dmac != NULL) {
+                       uint8_t wrap_val = 0xff; // WRAP ON
+                       d_dmac->write_signal(SIG_TOWNS_DMAC_WRAP, wrap_val, 0xff);
+               }
+       } else if(ch == SIG_FMTOWNS_RAM_WAIT) {
+               uint8_t _bak = mem_wait_val;
                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) {
+               if(_bak != mem_wait_val) {
+                       set_wait_values();
+               }
+       } else if(ch == SIG_FMTOWNS_ROM_WAIT) {
+//             mem_wait_val = (int)data;
+               set_wait_values();
+       } else if(ch == SIG_FMTOWNS_VRAM_WAIT) {
+               uint8_t _bak = vram_wait_val;
                vram_wait_val = (int)data;
-               d_vram->write_signal(SIG_FMTOWNS_SET_MEMWAIT, data, mask);
+               if(_bak != vram_wait_val) {
+                       set_wait_values();
+               }
        }
 }
 
@@ -452,74 +1399,105 @@ uint32_t TOWNS_MEMORY::read_signal(int ch)
        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) {
+       } else if(ch == SIG_FMTOWNS_RAM_WAIT) {
                return (uint32_t)mem_wait_val;
-       } else if(ch == SIG_FMTOWNS_SET_VRAMWAIT) {
+       } else if(ch == SIG_FMTOWNS_ROM_WAIT) {
+               return 6; // OK?
+       } else if(ch == SIG_FMTOWNS_VRAM_WAIT) {
                return (uint32_t)vram_wait_val;
-       } 
+       }
        return 0;
 }
+
+void TOWNS_MEMORY::set_intr_line(bool line, bool pending, uint32_t bit)
+{
+       __LIKELY_IF(d_cpu != NULL) {
+               d_cpu->set_intr_line(line, pending, bit);
+       }
+}
+
 // ToDo: DMA
 
-#define STATE_VERSION  1
+#define STATE_VERSION  8
 
 bool TOWNS_MEMORY::process_state(FILEIO* state_fio, bool loading)
 {
        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->StateValue(is_compatible);
+
+       state_fio->StateValue(mem_wait_val);
+       state_fio->StateValue(vram_wait_val);
+       state_fio->StateValue(wait_register_older);
+       state_fio->StateValue(wait_register_ram);
+       state_fio->StateValue(wait_register_vram);
+
+       state_fio->StateValue(dma_is_vram);
+       state_fio->StateValue(nmi_vector_protect);
+       state_fio->StateValue(software_reset);
+       state_fio->StateValue(poff_status);
+       state_fio->StateValue(reset_happened);
+
+       state_fio->StateValue(extra_nmi_val);
+       state_fio->StateValue(extra_nmi_mask);
+       state_fio->StateValue(nmi_mask);
+
+
+       state_fio->StateValue(select_d0_rom);
+       state_fio->StateValue(select_d0_dict);
+       state_fio->StateValue(ankcg_enabled);
+
+       state_fio->StateValue(vram_wait_val);
+       state_fio->StateValue(mem_wait_val);
+       state_fio->StateValue(vram_size);
+       state_fio->StateValue(cpu_clock_val);
 
-       state_fio->StateValue(dma_addr_mask);
-       //state_fio->StateValue(dma_addr_reg);
-       //state_fio->StateValue(dma_wrap_reg);
-       
-       state_fio->StateArray(ram_page0, sizeof(ram_page0), 1);
-       state_fio->StateArray(ram_pagef, sizeof(ram_pagef), 1);
        if(loading) {
+               update_machine_features(); // Update MISC3, MISC4 by MACHINE ID.
+
                uint32_t length_tmp = state_fio->FgetUint32_LE();
+               unset_range_rw(0x00100000, 0x3fffffff);
                if(extra_ram != NULL) {
                        free(extra_ram);
                        extra_ram = NULL;
                }
                length_tmp = length_tmp & 0x3ff00000;
-               extra_ram_size = length_tmp;
-               if(length_tmp > 0) {
-                       extra_ram = (uint8_t*)malloc(length_tmp);
+               extram_size = length_tmp;
+               extra_ram = (uint8_t*)malloc(length_tmp + 0x00100000);
+               __LIKELY_IF(extra_ram != NULL) {
+                       set_region_memory_rw(0x00000000, (extram_size + 0x00100000) - 1, extra_ram, 0);
+                       memset(extra_ram, 0x00, extram_size + 0x00100000);
                }
-               unset_memory_rw(0x00100000, 0x3fffffff);
+
                if(extra_ram == NULL) {
-                       extra_ram_size = 0;
+                       extram_size = 0;
                        return false;
                } else {
-                       state_fio->Fread(extra_ram, extra_ram_size, 1);
-                       set_memory_rw(0x00100000, (extra_ram_size + 0x00100000) - 1, extra_ram);
+                       state_fio->Fread(extra_ram, extram_size + 0x00100000, 1);
+                       //set_memory_rw(0x00100000, (extram_size + 0x00100000) - 1, extra_ram);
                }
-               
+               config_page0c_0e(dma_is_vram, select_d0_dict, true);
+               config_page0f(select_d0_rom, true);
+               set_wait_values();
+               //config_page00();
        } else {
+               // At saving
                if(extra_ram == NULL) {
                        state_fio->FputUint32_LE(0);
                } else {
-                       state_fio->FputUint32_LE(extra_ram_size & 0x3ff00000);
-                       state_fio->Fwrite(extra_ram, extra_ram_size, 1);
+                       state_fio->FputUint32_LE(extram_size & 0x3ff00000);
+                       state_fio->Fwrite(extra_ram, extram_size + 0x00100000, 1);
                }
        }
-                       
-       state_fio->StateValue(vram_wait_val);
-       state_fio->StateValue(mem_wait_val);
-       state_fio->StateValue(vram_size);
 
        // ToDo: Do save ROMs?
-
-       if(loading) {
-               initialize_tables();
-       }
        return true;
 }