OSDN Git Service

[VM][WIP] Merging upstream 2022-09-09.Still be imcompleted.
[csp-qt/common_source_project-fm7.git] / source / src / vm / fmtowns / towns_memory.cpp
1 /*
2         FUJITSU FM Towns Emulator 'eFMTowns'
3
4         Author : Kyuma.Ohta <whatisthis.sowhat _at_ gmail.com>
5         Date   : 2017.01.01 -
6
7         [memory]
8 */
9
10 #include "../../fileio.h"
11 #include "./towns_memory.h"
12 #include "./dmac.h"
13 #include "./vram.h"
14 #include "./planevram.h"
15 #include "./sprite.h"
16 #include "./fontroms.h"
17 #include "./serialrom.h"
18 #include "./crtc.h"
19 #include "./timer.h"
20
21 #include "../i386_np21.h"
22 //#include "../i386.h"
23
24 #include <math.h>
25
26 namespace FMTOWNS {
27
28 #define ADDR_MASK (addr_max - 1)
29 #define BANK_MASK (bank_size - 1)
30
31 void TOWNS_MEMORY::config_page_c0()
32 {
33         if(dma_is_vram) {
34                  // OK? From TSUGARU
35                 set_memory_mapped_io_rw(0x000c0000, 0x000c7fff, d_planevram);
36                 set_memory_mapped_io_rw(0x000c8000, 0x000c9fff, d_sprite);
37                 if(ankcg_enabled) {
38                         set_memory_mapped_io_r(0x000ca000, 0x000cbfff, d_font);
39 //                      set_memory_mapped_io_r(0x000ca000, 0x000ca7ff, d_font);
40 //                      set_memory_r          (0x000ca800, 0x000cafff, rd_dummy);
41 //                      set_memory_mapped_io_r(0x000cb000, 0x000cbfff, d_font);
42                         set_memory_w          (0x000ca000, 0x000cbfff, wr_dummy); // OK?
43                         //set_memory_mapped_io_w(0x000ca000, 0x000cbfff, d_sprite); // OK?
44                 } else {
45                         set_memory_mapped_io_rw(0x000ca000, 0x000cbfff, d_sprite);
46                 }
47 //              set_memory_rw          (0x000cc000, 0x000cfbff, &(ram_pagec[0xc000]));
48                 set_memory_mapped_io_rw(0x000cc000, 0x000cffff, this); // MMIO and higher RAM.
49                 // ToDo: Correctness wait value.
50                 set_wait_rw(0x000c0000, 0x000cffff, vram_wait_val);
51         } else {
52                 set_memory_rw          (0x000c0000, 0x000cffff, ram_pagec);
53                 // ToDo: Correctness wait value.
54                 set_wait_rw(0x000c0000, 0x000cffff, mem_wait_val);
55         }
56 }
57
58 void TOWNS_MEMORY::config_page_d0_e0()
59 {
60         // Change as of
61         // TownsPhysicalMemory::UpdateSysROMDicROMMappingFlag(bool , bool )
62         // at src/towns/memory/pysmem.cpp, TSUGARU.
63         // -- 20220125 K.O
64         if(!(dma_is_vram)) {
65                 set_memory_rw          (0x000d0000, 0x000effff, ram_paged);
66         } else {
67                 if(select_d0_dict) {
68                         set_memory_mapped_io_rw(0x000d0000, 0x000d9fff, d_dictionary);
69                         set_memory_r           (0x000da000, 0x000effff, rd_dummy);
70                         set_memory_w           (0x000da000, 0x000effff, wr_dummy);
71                 } else {
72                         //set_memory_rw          (0x000d0000, 0x000dffff, ram_paged);
73                         set_memory_r           (0x000d0000, 0x000effff, rd_dummy);
74                         set_memory_w           (0x000d0000, 0x000effff, wr_dummy);
75                 }
76         }
77 }
78
79 void TOWNS_MEMORY::config_page_f8_rom()
80 {
81         set_memory_mapped_io_rw (0x000f8000, 0x000fffff, this);
82 //
83 //      if(select_d0_rom) {
84 //              set_memory_mapped_io_r (0x000f8000, 0x000fffff, d_sysrom);
85 //              set_memory_w           (0x000f8000, 0x000fffff, wr_dummy);
86 //      } else {
87 //              set_memory_rw          (0x000f8000, 0x000fffff, &(ram_pagef[0x8000]));
88 //      }
89 }
90
91 void TOWNS_MEMORY::config_page00()
92 {
93         config_page_c0();
94         config_page_d0_e0();
95         config_page_f8_rom();
96 }
97
98 void TOWNS_MEMORY::initialize()
99 {
100 //      if(initialized) return;
101         MEMORY::initialize();
102 //      DEVICE::initialize();
103
104         extra_nmi_mask = true;
105         extra_nmi_val = false;
106         poff_status = false;
107         reset_happened = false;
108
109         vram_wait_val = 6;
110         mem_wait_val = 3;
111         if((cpu_id == 0x01) || (cpu_id == 0x03)) {
112                 wait_register = 0x03;
113         } else {
114                 wait_register = 0x83;
115         }
116         cpu_clock_val = 16000 * 1000;
117
118         // Initialize R/W table
119         _MEMORY_DISABLE_DMA_MMIO = osd->check_feature(_T("MEMORY_DISABLE_DMA_MMIO"));
120         if(!(addr_max_was_set) && osd->check_feature(_T("MEMORY_ADDR_MAX"))) {
121                 addr_max = osd->get_feature_uint64_value(_T("MEMORY_ADDR_MAX"));
122         }
123         if(!(bank_size_was_set) && osd->check_feature(_T("MEMORY_BANK_SIZE"))) {
124                 bank_size = osd->get_feature_uint64_value(_T("MEMORY_BANK_SIZE"));
125         }
126
127         bank_mask = BANK_MASK;
128         addr_mask = ADDR_MASK;
129
130         initialized = true;
131         extram_size = extram_size & 0x3ff00000;
132         set_extra_ram_size(extram_size >> 20); // Check extra ram size.
133
134         if(extram_size >= 0x00100000) {
135                 extra_ram = (uint8_t*)malloc(extram_size);
136                 __LIKELY_IF(extra_ram != NULL) {
137                         set_memory_rw(0x00100000, (extram_size + 0x00100000) - 1, extra_ram);
138                         memset(extra_ram, 0x00, extram_size);
139                 }
140         }
141         memset(ram_page0, 0x00, sizeof(ram_page0));
142         memset(ram_pagec, 0x00, sizeof(ram_pagec));
143         memset(ram_paged, 0x00, sizeof(ram_paged));
144         memset(ram_pagef, 0x00, sizeof(ram_pagef));
145
146         select_d0_dict = false;
147         select_d0_rom = true;
148
149         dma_is_vram = true;
150         // Lower 100000h
151         set_memory_rw          (0x00000000, 0x000bffff, ram_page0);
152         set_memory_rw          (0x000f0000, 0x000f7fff, ram_pagef);
153         config_page00();
154
155         set_memory_mapped_io_rw(0x80000000, 0x8007ffff, d_vram);
156         set_memory_mapped_io_rw(0x80100000, 0x8017ffff, d_vram);
157         set_memory_mapped_io_rw(0x81000000, 0x8101ffff, d_sprite);
158
159 //      set_memory_mapped_io_rw(0xc0000000, 0xc0ffffff, d_iccard[0]);
160 //      set_memory_mapped_io_rw(0xc1000000, 0xc1ffffff, d_iccard[1]);
161         set_wait_rw(0x00000000, 0xffffffff,  vram_wait_val);
162
163         set_memory_mapped_io_rw(0xc0000000, 0xc0ffffff, d_iccard[0]);
164         set_memory_mapped_io_rw(0xc1000000, 0xc1ffffff, d_iccard[1]);
165
166         set_memory_mapped_io_r (0xc2000000, 0xc207ffff, d_msdos);
167         set_memory_mapped_io_r (0xc2080000, 0xc20fffff, d_dictionary);
168         set_memory_mapped_io_r (0xc2100000, 0xc213ffff, d_font);
169         set_memory_mapped_io_rw(0xc2140000, 0xc2141fff, d_dictionary);
170         if(d_font_20pix != NULL) {
171                 set_memory_mapped_io_r (0xc2180000, 0xc21fffff, d_font_20pix);
172         }
173         set_memory_mapped_io_rw(0xc2200000, 0xc2200fff, d_pcm);
174         set_memory_mapped_io_r (0xfffc0000, 0xffffffff, d_sysrom);
175
176         set_wait_values();
177         // Another devices are blank
178
179         // load rom image
180         // ToDo: More smart.
181         vram_size = 0x80000; // OK?
182 }
183
184
185 void TOWNS_MEMORY::set_wait_values()
186 {
187         uint32_t waitfactor = 0;
188         if(cpu_clock_val < get_cpu_clocks(d_cpu)) {
189                 waitfactor = (uint32_t)(((double)get_cpu_clocks(d_cpu) / (double)cpu_clock_val) * 65536.0);
190         }
191         d_cpu->write_signal(SIG_CPU_WAIT_FACTOR, waitfactor, 0xffffffff);
192
193         set_wait_rw(0x00000000, 0x000bffff, mem_wait_val);
194         set_wait_rw(0x000d0000, 0x000fffff, mem_wait_val);
195         if(dma_is_vram) {
196                 set_wait_rw(0x000c0000, 0x000cffff, vram_wait_val);
197         } else {
198                 set_wait_rw(0x000c0000, 0x000cffff, mem_wait_val);
199         }
200         set_wait_rw(0x00100000, 0x00100000 + (extram_size & 0x3ff00000) - 1, mem_wait_val);
201
202         // ToDo: Extend I/O Slots
203         set_wait_rw(0x80000000, 0x800fffff, vram_wait_val);
204         set_wait_rw(0x80100000, 0x801fffff, vram_wait_val);
205         set_wait_rw(0x81000000, 0x8101ffff, vram_wait_val);
206         // ToDo: ROM CARDS
207         if(d_iccard[0] != NULL) {
208                 set_wait_rw(0xc0000000, 0xc0ffffff, mem_wait_val); // OK?
209         }
210         if(d_iccard[0] != NULL) {
211                 set_wait_rw(0xc1000000, 0xc1ffffff, mem_wait_val); // OK?
212         }
213         set_wait_rw(0xc2000000, 0xc2141fff, mem_wait_val);
214         set_wait_rw(0xc2200000, 0xc2200fff, mem_wait_val);
215         set_wait_rw(0xfffc0000, 0xffffffff, mem_wait_val);
216 }
217
218 void TOWNS_MEMORY::release()
219 {
220         if(rd_table != NULL) free(rd_table);
221         if(rd_dummy != NULL) free(rd_dummy);
222         if(wr_table != NULL) free(wr_table);
223         if(wr_dummy != NULL) free(wr_dummy);
224
225         if(extra_ram != NULL) {
226                 free(extra_ram);
227                 extra_ram = NULL;
228         }
229 }
230 void TOWNS_MEMORY::reset()
231 {
232         // reset memory
233         // ToDo
234         is_compatible = true;
235         reset_happened = false;
236         dma_is_vram = true;
237         nmi_vector_protect = false;
238         ankcg_enabled = false;
239         nmi_mask = false;
240         select_d0_dict = false;
241         select_d0_rom = true;
242         config_page00();
243
244         set_wait_values();
245 #if 1
246         __LIKELY_IF(d_cpu != NULL) {
247                 d_cpu->set_address_mask(0xffffffff);
248         }
249         if(d_dmac != NULL) {
250                 d_dmac->write_signal(SIG_TOWNS_DMAC_ADDR_MASK, 0xffffffff, 0xffffffff);
251                 uint8_t wrap_val = 0xff; // WRAP OFF
252                 if(machine_id >= 0x0b00) { // After MA/MX/ME
253                         wrap_val = 0x00;
254                 }
255                 d_dmac->write_signal(SIG_TOWNS_DMAC_WRAP_REG, wrap_val, 0xff);
256         }
257 #endif
258 }
259
260 void TOWNS_MEMORY::update_machine_features()
261 {
262         // 0024h: MISC3
263         reg_misc3 = 0xff;
264         if(machine_id >= 0x0b00) { // After MA/MX/ME
265                 reg_misc3 &= ~0x04; // DMACMD
266         }
267         if(machine_id >= 0x0700) { // After HR/HG
268                 reg_misc3 &= ~0x08; // POFFEN
269         }
270         if(machine_id >= 0x0700) { // After HR/HG
271                 reg_misc3 &= ~0x10; // Free run counter
272         }
273         if(machine_id >= 0x0700) { // After HR/HG
274                 reg_misc3 &= ~0x20; // CRTPOWOFF (0022h)
275         }
276         if(machine_id >= 0x0700) { // After HR/HG
277                 reg_misc3 &= ~0x40; // RCREN
278         }
279         if(machine_id >= 0x0700) { // After HR/HG
280                 reg_misc3 &= ~0x80; // ENPOFF
281         }
282         // 0025h: NMICNT
283         if(machine_id >= 0x0500) { // After CX
284                 reg_misc4 = 0x7f;
285         } else {
286                 reg_misc4 = 0xff;
287         }
288 }
289
290 // Address (TOWNS BASIC):
291 // 0x0020 - 0x0022, 0x0030-0x0031,
292 // 0x0400 - 0x0404,
293 // 0x0480 - 0x0484
294 // 0x05c0 - 0x05c2
295 // 0x05ec (Wait register)
296 // 0x05ed (CPU SPEED REGISTER)
297 // Is set extra NMI (0x05c0 - 0x05c2)?
298 uint32_t TOWNS_MEMORY::read_io8(uint32_t addr)
299 {
300 //      uint32_t val = 0x00;  // MAY NOT FILL to "1" for unused bit 20200129 K.O
301         uint32_t val = 0xff;  //
302         switch(addr & 0xffff) {
303         case 0x0020: // Software reset ETC.
304                 // reset cause register
305                 val = ((software_reset) ? 1 : 0) | ((reset_happened) ? 2 : 0);
306                 reset_happened = false;
307                 software_reset = false;
308                 __UNLIKELY_IF(d_cpu != NULL) {
309                         d_cpu->set_shutdown_flag(0);
310                 }
311                 if((machine_id >= 0x0300) && ((machine_id & 0xff00) != 0x0400)) { // After UX
312                         val = val | ((poff_status) ? 0x04 : 0x00);
313                 }
314                 break;
315         case 0x0022:
316 //              val = 0xff;
317 //              if(d_dmac != NULL) {
318 //                      val = d_dmac->read_signal(SIG_TOWNS_DMAC_ADDR_REG);
319 //              }
320                 break;
321         case 0x0024:
322                 // CPU MISC3
323                 return reg_misc3;
324                 break;
325         case 0x0025:
326                 // CPU MISC4
327                 return reg_misc4;
328                 break;
329         case 0x0028:
330                 // NMI MASK
331                 if(machine_id >= 0x0500) { // After CX
332                         val = (nmi_mask) ? 0x01 : 0x00;
333                 }
334                 break;
335         case 0x0030:
336                 // 20210227 K.O
337                 // From FMTowns::MachineID()  of TSUGARU,
338                 // git 83d4ec2309ac9fcbb8c01f26061ff0d49c5321e4.
339 //              if((config.dipswitch & TOWNS_DIPSW_PRETEND_I386) != 0) {
340 //                      val = ((machine_id & 0xf8) | 1);
341 //              } else {
342                         val = ((machine_id & 0xf8) | (cpu_id & 7));
343 //              }
344                 break;
345         case 0x0031:
346                 val = ((machine_id >> 8) & 0xff);
347                 break;
348         case 0x0032:
349                 {
350                         //bool __cs = (d_serialrom->read_signal(SIG_SERIALROM_CS) == 0);
351                         bool __clk = (d_serialrom->read_signal(SIG_SERIALROM_CLK) != 0);
352                         bool __reset = (d_serialrom->read_signal(SIG_SERIALROM_RESET) != 0);
353                         bool __dat = (d_serialrom->read_signal(SIG_SERIALROM_DATA) != 0);
354                         val = ((__reset) ? 0x80 : 0x00) | ((__clk) ? 0x40 : 0x00) | /*0x3e |*/ ((__dat) ? 0x01 : 0x00);
355                 }
356                 break;
357         case 0x00c0: // Cache
358                 val = 0x00;
359                 if((cpu_id == 0x02) || (cpu_id >= 0x04)) { // i486 SX/DX or After Pentium.
360                         // ToDo: Implement around cache.
361                         // Modified by this register and (05ECh:bit0 / Wait register).
362                         // Now, cache is always disabled.
363                         // RPNH = 0 (Disabled) : Bit1
364                         // CMEN = 0 (Disabled) : Bit0
365                         val = 0x00;
366                 }
367                 break;
368         case 0x00c2: // Cache Diagnostic
369                 val = 0x00;
370                 if((cpu_id == 0x02) || (cpu_id >= 0x04)) { // i486 SX/DX or After Pentium.
371                         // ToDo: Implement cache disgnostic.
372                         // SDMOD (Not diagnostic) : Bit3
373                         val = 0x00;
374                 }
375                 break;
376         case 0x0400: // Resolution:
377                 val = 0xfe;
378 //              val = 0x00;
379                 break;
380         case 0x0404: // System Status Reg.
381 //              val = (dma_is_vram) ? 0x7f : 0xff;
382                 val = (dma_is_vram) ? 0x00 : 0x80;
383                 break;
384         case 0x0480:
385                 val  =  (select_d0_dict) ? 0x01 : 0x00;
386                 val |= ((select_d0_rom) ? 0x00 : 0x02);
387                 break;
388         case 0x05c0:
389 //              val = (extra_nmi_mask) ? 0xf7 : 0xff;
390                 val = (extra_nmi_mask) ? 0x00 : 0x08;
391                 break;
392         case 0x05c2:
393 //              val = (extra_nmi_val) ? 0xff : 0xf7;
394                 val = (extra_nmi_val) ? 0x08 : 0x00;
395                 break;
396         case 0x05e0:
397                 if(machine_id < 0x0200) { // Towns 1/2
398                         return wait_register;
399                 }
400                 break;
401         case 0x05e2:
402                 if(machine_id >= 0x0200) { // i386
403                         return wait_register;
404                 }
405                 break;
406         case 0x05e8:
407                 // After Towns1F/2F/1H/2H
408                 {
409                         uint16_t nid = machine_id & 0xff00;
410                         if(nid >= 0x1000) {
411                                 val = (extram_size >> 20) & 0x7f; // MAX 128MB
412                         } else if(nid >= 0x0900) { // UR,MA,MX,ME,MF
413                                 val = (extram_size >> 20) & 0x1f; // MAX 32MB
414                         } else if(nid == 0x0800) { // HG
415                                 val = (extram_size >> 20) & 0x0f; // MAX 15MB
416                         } else if(nid == 0x0700) { // HR
417                                 val = (extram_size >> 20) & 0x1f; // MAX 32MB
418                         } else if(nid >= 0x0200) { // 2nd GEN,3rd Gen, UX/UG, CX
419                                 val = (extram_size >> 20) & 0x0f; // MAX 15MB
420                         } else {
421                                 val = 0xff; // NOT SUPPORTED
422                         }
423                 }
424                 break;
425
426         case 0x05ec:
427                 if(machine_id >= 0x0200) { // Towns2H/2F : Is this hidden register after Towns 1F/2F/1H/2H? -> Yes
428                         val = 0x00;
429                         if(mem_wait_val < 1) val |= 0x01;
430                 } else {
431                         val = 0xff;
432                 }
433                 break;
434         case 0x05ed:
435                 if(machine_id >= 0x0700) { // After HR/HG
436                         uint32_t clk = get_cpu_clocks(d_cpu);
437                         clk = clk / (1000 * 1000);
438                         __UNLIKELY_IF(clk < 16) clk = 16;
439                         __UNLIKELY_IF(clk > 127) clk = 127; // ToDo
440                         val = 0x00 | clk;
441                 } else {
442                         val = 0xff;
443                 }
444                 break;
445         case 0xfda4:
446                 if(machine_id >= 0x0700) { // After HR/HG
447                         return (is_compatible) ? 0x00 : 0x01;
448                 } else {
449                         return 0x00;
450                 }
451                 break;
452         case 0xff88:
453                 if((machine_id >= 0x0600) && !(is_compatible)) { // After UG
454                         __LIKELY_IF(d_crtc != NULL) {
455                                 val = d_crtc->read_signal(SIG_TOWNS_CRTC_MMIO_CFF82H);
456                         }
457                 } else  __LIKELY_IF(d_planevram != NULL) {
458                         val = d_planevram->read_io8(addr);
459                 }
460                 break;
461         case 0xff94:
462                 return 0x80;
463                 break;
464         case 0xff95:
465                 break;
466         case 0xff96:
467                 __LIKELY_IF(d_font != NULL) {
468                         return d_font->read_signal(SIG_TOWNS_FONT_KANJI_DATA_LOW);
469                 }
470                 break;
471         case 0xff97:
472                 __LIKELY_IF(d_font != NULL) {
473                         return d_font->read_signal(SIG_TOWNS_FONT_KANJI_DATA_HIGH);
474                 }
475                 break;
476         case 0xff98:
477                 __LIKELY_IF(d_timer != NULL) {
478                         d_timer->write_signal(SIG_TIMER_BEEP_ON, 1, 1);
479                 }
480                 break;
481         case 0xff99:
482                 if((machine_id >= 0x0600) && !(is_compatible)) { // After UG
483                         val = (ankcg_enabled) ? 0x01 : 0x00;
484                 } else __LIKELY_IF(d_planevram != NULL) {
485                         val = d_planevram->read_memory_mapped_io8(addr);
486                 }
487                 break;
488         case 0xff9c:
489                 if((machine_id >= 0x0600) && !(is_compatible)) { // After UG
490                         __LIKELY_IF(d_font != NULL) {
491                                 val = d_font->read_signal(SIG_TOWNS_FONT_KANJI_HIGH);
492                         }
493                 } else __LIKELY_IF(d_planevram != NULL) {
494                         val = d_planevram->read_io8(addr);
495                 }
496                 break;
497         case 0xff9d:
498                 if((machine_id >= 0x0600) && !(is_compatible)) { // After UG
499                         __LIKELY_IF(d_font != NULL) {
500                                 val = d_font->read_signal(SIG_TOWNS_FONT_KANJI_LOW);
501                         }
502                 } else __LIKELY_IF(d_planevram != NULL) {
503                         val = d_planevram->read_io8(addr);
504                 }
505                 break;
506         case 0xff9e:
507                 if((machine_id >= 0x0600) && !(is_compatible)) { // After UG
508                         __LIKELY_IF(d_font != NULL) {
509                                 val = d_font->read_signal(SIG_TOWNS_FONT_KANJI_ROW);
510                         }
511                 } else __LIKELY_IF(d_planevram != NULL) {
512                         val = d_planevram->read_io8(addr);
513                 }
514                 break;
515         default:
516                 __LIKELY_IF(d_planevram != NULL) {
517                         val = d_planevram->read_io8(addr);
518                 }
519                 break;
520         }
521         return val;
522 }
523
524 uint32_t TOWNS_MEMORY::read_io16(uint32_t addr)
525 {
526         {
527                 // OK?
528                 pair16_t n;
529                 n.b.l = read_io8((addr & 0xfffe) + 0);
530                 n.b.h = read_io8((addr & 0xfffe) + 1);
531                 return n.w;
532         }
533         return 0xffff;
534 }
535
536 void TOWNS_MEMORY::write_io8(uint32_t addr, uint32_t data)
537 {
538
539         switch(addr & 0xffff) {
540         case 0x0020: // Software reset ETC.
541                 // reset cause register
542                 if((data & 0x80) != 0) {
543                         nmi_vector_protect = true;
544                 } else {
545                         nmi_vector_protect = false;
546                 }
547                 if((data & 0x01) != 0) {
548                         software_reset = true;
549                 } else {
550                         software_reset = false;
551                 }
552
553                 if((data & 0x40) != 0) {
554                         poff_status = true;
555                         __LIKELY_IF(d_cpu != NULL) {
556                                 d_cpu->set_shutdown_flag(1);
557                         }
558                         // Todo: Implement true power off.
559                         emu->notify_power_off();
560 //                      emu->power_off();
561                 } else {
562                         poff_status = false;
563                         __LIKELY_IF(d_cpu != NULL) {
564                                 d_cpu->set_shutdown_flag(0);
565                         }
566                 }
567
568                 if(software_reset) {
569                         __LIKELY_IF(d_cpu != NULL) {
570                                 d_cpu->reset();
571                         }
572                         uint8_t wrap_val = 0xff; // WRAP OFF
573                         if(machine_id >= 0x0b00) { // After MA/MX/ME
574                                 wrap_val = 0x00;
575                         }
576                         __LIKELY_IF(d_dmac != NULL) {
577                                 d_dmac->write_signal(SIG_TOWNS_DMAC_WRAP_REG, wrap_val, 0xff);
578                         }
579                 }
580                 // Towns SEEMS to not set addreess mask (a.k.a A20 mask). 20200131 K.O
581                 break;
582         case 0x0022:
583                 if((data & 0x40) != 0) {
584                         __LIKELY_IF(d_cpu != NULL) {
585                                 d_cpu->set_shutdown_flag(1);
586                         }
587                         // Todo: Implement true power off.
588 //                      emu->power_off();
589                 }
590                 // Power register
591                 break;
592         case 0x0024:
593 //              if(d_dmac != NULL) {
594 //                      d_dmac->write_signal(SIG_TOWNS_DMAC_WRAP_REG, data, 0xff);
595 //              }
596                 break;
597         case 0x0032:
598                 {
599                         d_serialrom->write_signal(SIG_SERIALROM_CS, ~data, 0x20);
600                         d_serialrom->write_signal(SIG_SERIALROM_CLK, data, 0x40);
601                         d_serialrom->write_signal(SIG_SERIALROM_RESET, data, 0x80);
602                 }
603                 break;
604         case 0x0404: // System Status Reg.
605                 {
606                         bool _b = dma_is_vram;
607                         dma_is_vram = ((data & 0x80) == 0);
608                         if((_b != dma_is_vram)/* || (dma_is_vram)*/) {
609                                 config_page_c0();
610                                 config_page_d0_e0();
611                         }
612                 }
613                 break;
614         case 0x0480:
615                 {
616                         bool _dict = select_d0_dict;
617                         //      bool _rom = select_d0_rom;
618                         select_d0_dict = ((data & 0x01) != 0) ? true : false;
619                         select_d0_rom = ((data & 0x02) == 0) ? true : false;
620                         //if(_rom != select_d0_rom) {
621                         //      config_page_f8_rom();
622                         //}
623                         if(_dict != select_d0_dict) {
624                                 config_page_d0_e0();
625                         }
626                 }
627                 break;
628         case 0x05c0:
629                 extra_nmi_mask = ((data & 0x08) == 0);
630                 break;
631         case 0x05e0:
632                 // From AB.COM
633                 if(machine_id < 0x0200) { // Towns 1/2
634                         uint8_t nval = data & 7;
635                         uint8_t val_bak = mem_wait_val;
636                         if(nval < 1) nval = 1;
637                         if(nval > 5) nval = 5;
638                         mem_wait_val = nval + 1;
639                         vram_wait_val = nval + 3 + 1;
640                         wait_register = nval;
641                         if(val_bak != mem_wait_val) {
642                                 set_wait_values();
643                         }
644                 }
645                 break;
646         case 0x05e2:
647                 if(machine_id >= 0x0200) { // After Towns 1H/2F. Hidden wait register.
648                         uint8_t val_bak = mem_wait_val;
649                         if(data != 0x83) {
650                                 uint8_t nval = data & 7;
651                                 if(machine_id <= 0x0200) { // Towns 1H/2F.
652                                         if(nval < 1) nval = 1;
653                                 }
654                                 if(nval > 5) nval = 5;
655                                 mem_wait_val = nval;
656                                 vram_wait_val = nval + 3;
657                                 wait_register = nval;
658                         } else {
659                                 mem_wait_val = 3;
660                                 vram_wait_val = 6;
661                                 wait_register = data;
662                         }
663                         if(val_bak != mem_wait_val) {
664                                 set_wait_values();
665                         }
666                 }
667                 break;
668         case 0x05ec:
669                 if(machine_id >= 0x0500) { // Towns2 CX :
670                         uint8_t val_bak = mem_wait_val;
671                         uint32_t clk_bak = cpu_clock_val;
672                         vram_wait_val = ((data & 0x01) != 0) ? 3 : 6;
673                         mem_wait_val = ((data & 0x01) != 0) ? 0 : 3;
674                         cpu_clock_val = ((data & 0x01) != 0) ? (get_cpu_clocks(d_cpu)) : (16 * 1000 * 1000);
675                         if((val_bak != mem_wait_val) || (cpu_clock_val != clk_bak)) {
676                                 set_wait_values();
677                         }
678                 }
679                 break;
680         case 0xfda4:
681                 if(machine_id >= 0x0700) { // After HR/HG
682                         is_compatible = ((data & 0x01) == 0x00) ? true : false;
683                         __LIKELY_IF(d_crtc != NULL) {
684                                 d_crtc->write_signal(SIG_TOWNS_CRTC_COMPATIBLE_MMIO, (is_compatible) ? 0xffffffff : 0x00000000, 0xffffffff);
685                         }
686                 }
687                 break;
688         case 0xff94:
689                 __LIKELY_IF(d_font != NULL) {
690                         d_font->write_signal(SIG_TOWNS_FONT_KANJI_HIGH, data, 0xff);
691                 }
692                 break;
693         case 0xff95:
694                 __LIKELY_IF(d_font != NULL) {
695                         d_font->write_signal(SIG_TOWNS_FONT_KANJI_LOW, data, 0xff);
696                 }
697                 break;
698         case 0xff96:
699                 break;
700         case 0xff97:
701                 break;
702         case 0xff98:
703                 __LIKELY_IF(d_timer != NULL) {
704                         d_timer->write_signal(SIG_TIMER_BEEP_ON, 0, 1);
705                 }
706                 break;
707         case 0xff99:
708                 {
709                         bool _b = ankcg_enabled;
710                         ankcg_enabled = ((data & 1) != 0) ? true : false;
711                         if((_b != ankcg_enabled) && (dma_is_vram)) {
712                                 config_page_c0();
713                         }
714                 }
715                 break;
716         case 0xff9e:
717                 if((machine_id >= 0x0600) && !(is_compatible)) { // After UG
718                         __LIKELY_IF(d_font != NULL) {
719                                 d_font->write_signal(SIG_TOWNS_FONT_KANJI_ROW, data, 0xff);
720                         }
721                 } else __LIKELY_IF(d_planevram != NULL) {
722                         d_planevram->write_io8(addr , data);
723                 }
724                 break;
725         default:
726                 __LIKELY_IF(d_planevram != NULL) {
727                         d_planevram->write_io8(addr , data);
728                 }
729                 break;
730         }
731         return;
732 }
733 /*
734 // At page 000C0000h - 000CFFFFh : Maybe return real memory for word/dword access.
735 uint32_t TOWNS_MEMORY::read_memory_mapped_io16(uint32_t addr)
736 {
737         if((addr >= 0xc0000) && (addr <= 0xcffff)) {
738                 pair32_t n;
739                 n.d = 0;
740                 n.b.l = ram_pagec[(addr & 0xffff) + 0];
741                 n.b.h = ram_pagec[(addr & 0xffff) + 1];
742                 return n.d;
743         }
744         return 0xffff;
745 }
746
747 uint32_t TOWNS_MEMORY::read_memory_mapped_io32(uint32_t addr)
748 {
749         if((addr >= 0xc0000) && (addr <= 0xcffff)) {
750                 pair32_t n;
751                 n.d = 0;
752                 n.b.l  = ram_pagec[(addr & 0xffff) + 0];
753                 n.b.h  = ram_pagec[(addr & 0xffff) + 1];
754                 n.b.h2 = ram_pagec[(addr & 0xffff) + 2];
755                 n.b.h3 = ram_pagec[(addr & 0xffff) + 3];
756                 return n.d;
757         }
758         return 0xffffffff;
759 }
760 */
761 uint32_t TOWNS_MEMORY::read_memory_mapped_io8(uint32_t addr)
762 {
763         uint32_t val = 0xff;
764         __LIKELY_IF(addr < 0xcff80) {
765                 return ram_pagec[addr & 0xffff];
766         }
767         __LIKELY_IF((addr >= 0x000f8000) && (addr < 0x00100000)) {
768                 __LIKELY_IF(!(select_d0_rom)) {
769                         return ram_pagef[addr & 0xffff];
770                 } else {
771                         __LIKELY_IF(d_sysrom != nullptr) {
772                                 return d_sysrom->read_memory_mapped_io8(addr);
773                         }
774                 }
775         }
776         __UNLIKELY_IF(addr >= 0xd0000) {
777                 return 0xff;
778         }
779         switch(addr) {
780         case 0xcff88:
781         case 0xcff94:
782         case 0xcff96:
783         case 0xcff97:
784         case 0xcff98:
785         case 0xcff99:
786         case 0xcff9c:
787         case 0xcff9d:
788         case 0xcff9e:
789                 val = read_io8(addr & 0xffff);
790                 break;
791         default:
792                 __LIKELY_IF(d_planevram != NULL) {
793                         val = d_planevram->read_io8(addr & 0xffff);
794                 }
795                 break;
796         }
797         return (uint32_t)val;
798 }
799 /*
800 void TOWNS_MEMORY::write_memory_mapped_io16(uint32_t addr, uint32_t data)
801 {
802         if((addr >= 0xc0000) && (addr <= 0xcffff)) {
803                 pair16_t n;
804                 n.w = data;
805                 ram_pagec[(addr & 0xffff) + 0] = n.b.l;
806                 ram_pagec[(addr & 0xffff) + 1] = n.b.h;
807         }
808 }
809
810 void TOWNS_MEMORY::write_memory_mapped_io32(uint32_t addr, uint32_t data)
811 {
812         if((addr >= 0xc0000) && (addr <= 0xcffff)) {
813                 pair32_t n;
814                 n.d = data;
815                 ram_pagec[(addr & 0xffff) + 0] = n.b.l;
816                 ram_pagec[(addr & 0xffff) + 1] = n.b.h;
817                 ram_pagec[(addr & 0xffff) + 2] = n.b.h2;
818                 ram_pagec[(addr & 0xffff) + 3] = n.b.h3;
819         }
820 }
821 */
822
823 void TOWNS_MEMORY::write_memory_mapped_io8(uint32_t addr, uint32_t data)
824 {
825         __LIKELY_IF(addr < 0xcff80) {
826                 ram_pagec[addr & 0xffff] = data;
827                 return;
828         }
829         __LIKELY_IF((addr >= 0x000f8000) && (addr < 0x00100000)) {
830                 __LIKELY_IF(!(select_d0_rom)) {
831                         ram_pagef[addr & 0xffff] = data;
832                 }
833                 return;
834         }
835         __UNLIKELY_IF(addr >= 0xd0000) {
836                 return;
837         }
838         switch(addr) {
839         case 0xcff94:
840         case 0xcff95:
841         case 0xcff98:
842         case 0xcff99:
843         case 0xcff9e:
844                 write_io8(addr & 0xffff, data);
845                 break;
846         default:
847                 __LIKELY_IF(d_planevram != NULL) {
848                         d_planevram->write_io8(addr & 0xffff, data);
849                 }
850                 break;
851         }
852         return;
853 }
854
855 void TOWNS_MEMORY::write_data16w(uint32_t addr, uint32_t data, int* wait)
856 {
857         int bank = (addr & addr_mask) >> addr_shift;
858         int dummy;
859         MEMORY::write_data16w(addr, data, &dummy);
860         // Note: WAIT valus may be same as 1 bytes r/w.
861         __LIKELY_IF(wait != NULL) {
862                 *wait = wr_table[bank].wait;
863         }
864 }
865
866 void TOWNS_MEMORY::write_data32w(uint32_t addr, uint32_t data, int* wait)
867 {
868         int bank = (addr & addr_mask) >> addr_shift;
869         int dummy;
870         MEMORY::write_data32w(addr, data, &dummy);
871         // Note: WAIT valus may be same as 1 bytes r/w.
872         __LIKELY_IF(wait != NULL) {
873                 *wait = wr_table[bank].wait;
874         }
875 }
876
877
878 uint32_t TOWNS_MEMORY::read_data16w(uint32_t addr, int* wait)
879 {
880         int bank = (addr & addr_mask) >> addr_shift;
881         int dummy;
882         uint32_t val = MEMORY::read_data16w(addr, &dummy);
883         // Note: WAIT valus may be same as 1 bytes r/w.
884         __LIKELY_IF(wait != NULL) {
885                 *wait = wr_table[bank].wait;
886         }
887         return val;
888 }
889
890 uint32_t TOWNS_MEMORY::read_data32w(uint32_t addr, int* wait)
891 {
892         int bank = (addr & addr_mask) >> addr_shift;
893         // Note: WAIT valus may be same as 1 bytes r/w.
894         int dummy;
895         uint32_t val = MEMORY::read_data32w(addr, &dummy);
896         __LIKELY_IF(wait != NULL) {
897                 *wait = wr_table[bank].wait;
898         }
899         return val;
900
901 }
902
903 uint32_t TOWNS_MEMORY::read_dma_data8(uint32_t addr)
904 {
905         int bank = (addr & addr_mask) >> addr_shift;
906
907         __UNLIKELY_IF(rd_table[bank].device != NULL) {
908                 return rd_table[bank].device->read_memory_mapped_io8(addr);
909         } else {
910                 return rd_table[bank].memory[addr & bank_mask];
911         }
912 }
913
914 uint32_t TOWNS_MEMORY::read_dma_data16(uint32_t addr)
915 {
916         int bank = (addr & addr_mask) >> addr_shift;
917
918         __UNLIKELY_IF(rd_table[bank].device != NULL) {
919                 return rd_table[bank].device->read_memory_mapped_io16(addr);
920         } else {
921                 uint32_t naddr = addr & bank_mask;
922                 pair32_t n;
923                 n.d = 0;
924
925                 __UNLIKELY_IF((naddr + 1) > bank_mask) {
926                         n.b.l = rd_table[bank].memory[naddr];
927                         n.b.h = read_dma_data8(addr + 1);
928                 } else {
929                         n.b.l = rd_table[bank].memory[naddr + 0];
930                         n.b.h = rd_table[bank].memory[naddr + 1];
931                 }
932                 return n.d;
933         }
934 }
935
936 uint32_t TOWNS_MEMORY::read_dma_data32(uint32_t addr)
937 {
938         int bank = (addr & addr_mask) >> addr_shift;
939
940         __UNLIKELY_IF(rd_table[bank].device != NULL) {
941                 return rd_table[bank].device->read_memory_mapped_io32(addr);
942         } else {
943                 uint32_t naddr = addr & bank_mask;
944                 pair32_t n;
945                 n.d = 0;
946
947                 __UNLIKELY_IF((naddr + 3) > bank_mask) {
948                         n.b.l  = rd_table[bank].memory[naddr];
949                         n.b.h  = read_dma_data8(addr + 1);
950                         n.b.h2 = read_dma_data8(addr + 2);
951                         n.b.h3 = read_dma_data8(addr + 3);
952                 } else {
953                         n.b.l  = rd_table[bank].memory[naddr + 0];
954                         n.b.h  = rd_table[bank].memory[naddr + 1];
955                         n.b.h2 = rd_table[bank].memory[naddr + 2];
956                         n.b.h3 = rd_table[bank].memory[naddr + 3];
957                 }
958                 return n.d;
959         }
960 }
961
962 void TOWNS_MEMORY::write_dma_data8(uint32_t addr, uint32_t data)
963 {
964         int bank = (addr & addr_mask) >> addr_shift;
965
966         __UNLIKELY_IF(wr_table[bank].device != NULL) {
967                 wr_table[bank].device->write_memory_mapped_io8(addr, data);
968         } else {
969                 wr_table[bank].memory[addr & bank_mask] = data;
970         }
971 }
972
973 void TOWNS_MEMORY::write_dma_data16(uint32_t addr, uint32_t data)
974 {
975         int bank = (addr & addr_mask) >> addr_shift;
976
977         __UNLIKELY_IF(wr_table[bank].device != NULL) {
978                 wr_table[bank].device->write_memory_mapped_io16(addr, data);
979         } else {
980                 uint32_t naddr = addr & bank_mask;
981                 pair32_t n;
982                 n.d = data;
983
984                 __UNLIKELY_IF((naddr + 1) > bank_mask) {
985                         wr_table[bank].memory[naddr] = n.b.l;
986                         write_dma_data8(addr + 1, n.b.h);
987                 } else {
988                         wr_table[bank].memory[naddr + 0] = n.b.l;
989                         wr_table[bank].memory[naddr + 1] = n.b.h;
990                 }
991         }
992 }
993
994 void TOWNS_MEMORY::write_dma_data32(uint32_t addr, uint32_t data)
995 {
996         int bank = (addr & addr_mask) >> addr_shift;
997
998         __UNLIKELY_IF(wr_table[bank].device != NULL) {
999                 wr_table[bank].device->write_memory_mapped_io32(addr, data);
1000         } else {
1001                 uint32_t naddr = addr & bank_mask;
1002                 pair32_t n;
1003                 n.d = data;
1004
1005                 __UNLIKELY_IF((naddr + 3) > bank_mask) {
1006                         wr_table[bank].memory[naddr] = n.b.l;
1007                         write_dma_data8(addr + 1, n.b.h);
1008                         write_dma_data8(addr + 2, n.b.h2);
1009                         write_dma_data8(addr + 3, n.b.h3);
1010                 } else {
1011                         wr_table[bank].memory[naddr + 0] = n.b.l;
1012                         wr_table[bank].memory[naddr + 1] = n.b.h;
1013                         wr_table[bank].memory[naddr + 2] = n.b.h2;
1014                         wr_table[bank].memory[naddr + 3] = n.b.h3;
1015                 }
1016         }
1017 }
1018
1019 uint32_t TOWNS_MEMORY::read_dma_data8w(uint32_t addr, int* wait)
1020 {
1021         uint32_t val = read_dma_data8(addr);
1022
1023         __LIKELY_IF(wait != NULL) {
1024                 int bank = (addr & addr_mask) >> addr_shift;
1025                 *wait = wr_table[bank].wait;
1026         }
1027         return val;
1028 }
1029
1030 uint32_t TOWNS_MEMORY::read_dma_data16w(uint32_t addr, int* wait)
1031 {
1032         uint32_t val = read_dma_data16(addr);
1033
1034         __LIKELY_IF(wait != NULL) {
1035                 int bank = (addr & addr_mask) >> addr_shift;
1036                 *wait = wr_table[bank].wait;
1037         }
1038         return val;
1039 }
1040
1041 uint32_t TOWNS_MEMORY::read_dma_data32w(uint32_t addr, int* wait)
1042 {
1043         uint32_t val = read_dma_data32(addr);
1044
1045         __LIKELY_IF(wait != NULL) {
1046                 int bank = (addr & addr_mask) >> addr_shift;
1047                 *wait = wr_table[bank].wait;
1048         }
1049         return val;
1050 }
1051
1052 void TOWNS_MEMORY::write_dma_data8w(uint32_t addr, uint32_t data, int* wait)
1053 {
1054         write_dma_data8(addr, data);
1055
1056         __LIKELY_IF(wait != NULL) {
1057                 int bank = (addr & addr_mask) >> addr_shift;
1058                 *wait = wr_table[bank].wait;
1059         }
1060
1061 }
1062
1063 void TOWNS_MEMORY::write_dma_data16w(uint32_t addr, uint32_t data, int* wait)
1064 {
1065         write_dma_data16(addr, data);
1066
1067         __LIKELY_IF(wait != NULL) {
1068                 int bank = (addr & addr_mask) >> addr_shift;
1069                 *wait = wr_table[bank].wait;
1070         }
1071
1072 }
1073
1074 void TOWNS_MEMORY::write_dma_data32w(uint32_t addr, uint32_t data, int* wait)
1075 {
1076         write_dma_data32(addr, data);
1077
1078         __LIKELY_IF(wait != NULL) {
1079                 int bank = (addr & addr_mask) >> addr_shift;
1080                 *wait = wr_table[bank].wait;
1081         }
1082
1083 }
1084
1085 void TOWNS_MEMORY::write_signal(int ch, uint32_t data, uint32_t mask)
1086 {
1087         if(ch == SIG_MEMORY_EXTNMI) {
1088                 extra_nmi_val = ((data & mask) != 0);
1089                 if(!(extra_nmi_mask)) {
1090                         // Not MASK
1091                         __LIKELY_IF(d_cpu != NULL) {
1092                                 d_cpu->write_signal(SIG_CPU_NMI, data, mask);
1093                         }
1094                 }
1095         } else if(ch == SIG_CPU_NMI) {
1096                 // Check protect
1097                 if(!(nmi_mask)) {
1098                         __LIKELY_IF(d_cpu != NULL) {
1099                                 d_cpu->write_signal(SIG_CPU_NMI, data, mask);
1100                         }
1101                 }
1102         } else if(ch == SIG_CPU_IRQ) {
1103                 __LIKELY_IF(d_cpu != NULL) {
1104                         d_cpu->write_signal(SIG_CPU_IRQ, data, mask);
1105                 }
1106         } else if(ch == SIG_CPU_BUSREQ) {
1107                 __LIKELY_IF(d_cpu != NULL) {
1108                         d_cpu->write_signal(SIG_CPU_BUSREQ, data, mask);
1109                 }
1110         } else if(ch == SIG_I386_A20) {
1111                 __LIKELY_IF(d_cpu != NULL) {
1112                         d_cpu->write_signal(SIG_I386_A20, data, mask);
1113                 }
1114         } else if(ch == SIG_FMTOWNS_NOTIFY_RESET) {
1115                 out_debug_log("RESET FROM CPU!!!\n");
1116                 reset_happened = true;
1117                 dma_is_vram = true;
1118                 nmi_vector_protect = false;
1119                 ankcg_enabled = false;
1120                 nmi_mask = false;
1121                 select_d0_dict = false;
1122                 select_d0_rom = true;
1123                 config_page00();
1124                 set_wait_values();
1125
1126                 __LIKELY_IF(d_cpu != NULL) {
1127                         d_cpu->set_address_mask(0xffffffff);
1128                 }
1129                 __LIKELY_IF(d_dmac != NULL) {
1130                         d_dmac->write_signal(SIG_TOWNS_DMAC_ADDR_MASK, 0xffffffff, 0xffffffff);
1131                         uint8_t wrap_val = 0xff; // WRAP OFF
1132                         if(machine_id >= 0x0b00) { // After MA/MX/ME
1133                                 wrap_val = 0x00;
1134                         }
1135                         d_dmac->write_signal(SIG_TOWNS_DMAC_WRAP_REG, wrap_val, 0xff);
1136                 }
1137         } else if(ch == SIG_FMTOWNS_RAM_WAIT) {
1138                 uint8_t _bak = mem_wait_val;
1139                 mem_wait_val = (int)data;
1140                 if(_bak != mem_wait_val) {
1141                         set_wait_values();
1142                 }
1143         } else if(ch == SIG_FMTOWNS_ROM_WAIT) {
1144 //              mem_wait_val = (int)data;
1145                 set_wait_values();
1146         } else if(ch == SIG_FMTOWNS_VRAM_WAIT) {
1147                 uint8_t _bak = vram_wait_val;
1148                 vram_wait_val = (int)data;
1149                 if(_bak != vram_wait_val) {
1150                         set_wait_values();
1151                 }
1152         }
1153 }
1154
1155 uint32_t TOWNS_MEMORY::read_signal(int ch)
1156 {
1157         if(ch == SIG_FMTOWNS_MACHINE_ID) {
1158                 uint16_t d = (machine_id & 0xfff8) | ((uint16_t)(cpu_id & 0x07));
1159                 return (uint32_t)d;
1160         } else if(ch == SIG_FMTOWNS_RAM_WAIT) {
1161                 return (uint32_t)mem_wait_val;
1162         } else if(ch == SIG_FMTOWNS_ROM_WAIT) {
1163                 return 6; // OK?
1164         } else if(ch == SIG_FMTOWNS_VRAM_WAIT) {
1165                 return (uint32_t)vram_wait_val;
1166         }
1167         return 0;
1168 }
1169
1170 void TOWNS_MEMORY::set_intr_line(bool line, bool pending, uint32_t bit)
1171 {
1172         __LIKELY_IF(d_cpu != NULL) {
1173                 d_cpu->set_intr_line(line, pending, bit);
1174         }
1175 }
1176
1177 // ToDo: DMA
1178
1179 #define STATE_VERSION   5
1180
1181 bool TOWNS_MEMORY::process_state(FILEIO* state_fio, bool loading)
1182 {
1183         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
1184                 return false;
1185         }
1186
1187         if(!state_fio->StateCheckInt32(this_device_id)) {
1188                 return false;
1189         }
1190         state_fio->StateValue(machine_id);
1191         state_fio->StateValue(cpu_id);
1192         state_fio->StateValue(is_compatible);
1193
1194         state_fio->StateValue(mem_wait_val);
1195         state_fio->StateValue(vram_wait_val);
1196         state_fio->StateValue(wait_register);
1197
1198         state_fio->StateValue(dma_is_vram);
1199         state_fio->StateValue(nmi_vector_protect);
1200         state_fio->StateValue(software_reset);
1201         state_fio->StateValue(poff_status);
1202         state_fio->StateValue(reset_happened);
1203
1204         state_fio->StateValue(extra_nmi_val);
1205         state_fio->StateValue(extra_nmi_mask);
1206         state_fio->StateValue(nmi_mask);
1207
1208         state_fio->StateArray(ram_page0,  sizeof(ram_page0), 1);
1209         state_fio->StateArray(ram_pagec,  sizeof(ram_pagec), 1);
1210         state_fio->StateArray(ram_paged,  sizeof(ram_paged), 1);
1211         state_fio->StateArray(ram_pagef,  sizeof(ram_pagef), 1);
1212
1213         state_fio->StateValue(select_d0_rom);
1214         state_fio->StateValue(select_d0_dict);
1215         state_fio->StateValue(ankcg_enabled);
1216
1217         state_fio->StateValue(vram_wait_val);
1218         state_fio->StateValue(mem_wait_val);
1219         state_fio->StateValue(vram_size);
1220         state_fio->StateValue(cpu_clock_val);
1221
1222         if(loading) {
1223                 update_machine_features(); // Update MISC3, MISC4 by MACHINE ID.
1224
1225                 uint32_t length_tmp = state_fio->FgetUint32_LE();
1226                 if(extra_ram != NULL) {
1227                         free(extra_ram);
1228                         extra_ram = NULL;
1229                 }
1230                 length_tmp = length_tmp & 0x3ff00000;
1231                 extram_size = length_tmp;
1232                 if(length_tmp > 0) {
1233                         extra_ram = (uint8_t*)malloc(length_tmp);
1234                 }
1235                 unset_memory_rw(0x00100000, 0x3fffffff);
1236                 if(extra_ram == NULL) {
1237                         extram_size = 0;
1238                         return false;
1239                 } else {
1240                         state_fio->Fread(extra_ram, extram_size, 1);
1241                         set_memory_rw(0x00100000, (extram_size + 0x00100000) - 1, extra_ram);
1242                 }
1243                 set_wait_values();
1244                 config_page00();
1245         } else {
1246                 // At saving
1247                 if(extra_ram == NULL) {
1248                         state_fio->FputUint32_LE(0);
1249                 } else {
1250                         state_fio->FputUint32_LE(extram_size & 0x3ff00000);
1251                         state_fio->Fwrite(extra_ram, extram_size, 1);
1252                 }
1253         }
1254
1255         // ToDo: Do save ROMs?
1256         return true;
1257 }
1258
1259 }