OSDN Git Service

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