OSDN Git Service

2e2f3e95adaa0ef2f3a9a4fcfe4ee04a852d0678
[csp-qt/common_source_project-fm7.git] / source / src / vm / mz80k / memory.cpp
1 /*
2         SHARP MZ-80K/C Emulator 'EmuZ-80K'
3         SHARP MZ-1200 Emulator 'EmuZ-1200'
4
5         Author : Takeda.Toshiya
6         Date   : 2010.08.18-
7
8         SHARP MZ-80A Emulator 'EmuZ-80A'
9         Modify : Hideki Suga
10         Date   : 2014.12.10 -
11
12         [ memory ]
13 */
14
15 #include "memory.h"
16 #include "../i8253.h"
17 #include "../i8255.h"
18
19 #define EVENT_TEMPO     0
20 #define EVENT_BLINK     1
21 #define EVENT_HBLANK    2
22
23 #define SET_BANK(s, e, w, r) { \
24         int sb = (s) >> 10, eb = (e) >> 10; \
25         for(int i = sb; i <= eb; i++) { \
26                 if((w) == wdmy) { \
27                         wbank[i] = wdmy; \
28                 } else { \
29                         wbank[i] = (w) + 0x400 * (i - sb); \
30                 } \
31                 if((r) == rdmy) { \
32                         rbank[i] = rdmy; \
33                 } else { \
34                         rbank[i] = (r) + 0x400 * (i - sb); \
35                 } \
36         } \
37 }
38
39 void MEMORY::initialize()
40 {
41         // init memory
42         memset(ram, 0, sizeof(ram));
43         memset(vram, 0, sizeof(vram));
44         memset(ipl, 0xff, sizeof(ipl));
45 #if defined(_MZ1200) || defined(_MZ80A)
46         memset(ext, 0xff, sizeof(ext));
47 #endif
48 #if defined(SUPPORT_MZ80AIF) || defined(SUPPORT_MZ80FIO)
49         memset(fdif, 0xff, sizeof(fdif));
50 #endif
51         memset(rdmy, 0xff, sizeof(rdmy));
52         
53         // load rom images
54         FILEIO* fio = new FILEIO();
55         if(fio->Fopen(create_local_path(_T("IPL.ROM")), FILEIO_READ_BINARY)) {
56                 fio->Fread(ipl, sizeof(ipl), 1);
57                 fio->Fclose();
58         }
59 #if defined(_MZ1200) || defined(_MZ80A)
60         if(fio->Fopen(create_local_path(_T("EXT.ROM")), FILEIO_READ_BINARY)) {
61                 fio->Fread(ext, sizeof(ext), 1);
62                 fio->Fclose();
63         }
64 #endif
65 #if defined(SUPPORT_MZ80AIF) || defined(SUPPORT_MZ80FIO)
66         if(fio->Fopen(create_local_path(_T("FDIF.ROM")), FILEIO_READ_BINARY)) {
67                 fio->Fread(fdif, sizeof(fdif), 1);
68                 fio->Fclose();
69         }
70 #endif
71         if(fio->Fopen(create_local_path(_T("FONT.ROM")), FILEIO_READ_BINARY)) {
72                 fio->Fread(font, sizeof(font), 1);
73                 fio->Fclose();
74         }
75         delete fio;
76         
77         // 0000-0FFF    IPL/RAM
78         // 1000-BFFF    RAM
79         // C000-CFFF    RAM/IPL
80         SET_BANK(0x0000, 0x0fff, wdmy, ipl);
81         SET_BANK(0x1000, 0xbfff, ram + 0x1000, ram + 0x1000);
82         SET_BANK(0xc000, 0xcfff, ram + 0xc000, ram + 0xc000);
83 #if defined(_MZ1200) || defined(_MZ80A)
84         SET_BANK(0xd000, 0xd7ff, vram, vram);   // VRAM 2KB
85         SET_BANK(0xd800, 0xdfff, wdmy, rdmy);
86 #else
87         SET_BANK(0xd000, 0xd3ff, vram, vram);   // VRAM 1KB
88         SET_BANK(0xd400, 0xd7ff, vram, vram);
89         SET_BANK(0xd800, 0xdbff, vram, vram);
90         SET_BANK(0xdc00, 0xdfff, vram, vram);
91 #endif
92 #if defined(_MZ1200) || defined(_MZ80A)
93         SET_BANK(0xe000, 0xe7ff, wdmy, rdmy);
94         SET_BANK(0xe800, 0xefff, wdmy, ext);
95 #else
96         SET_BANK(0xe000, 0xefff, wdmy, rdmy);
97 #endif
98 #if defined(SUPPORT_MZ80FIO)
99         SET_BANK(0xf000, 0xf3ff, wdmy, fdif);
100         SET_BANK(0xf400, 0xffff, wdmy, rdmy);
101 #else
102         SET_BANK(0xf000, 0xffff, wdmy, rdmy);
103 #endif
104         
105 #if defined(_MZ80A)
106         // init scroll register
107         e200 = 0x00;    // scroll
108 #endif
109         // init pcg
110         memset(pcg, 0, sizeof(pcg));
111         memcpy(pcg + 0x000, font, 0x400); // copy pattern of 00h-7fh
112 #if defined(_MZ1200)
113         memcpy(pcg + 0x800, font, 0x400);
114 #endif
115         
116         // create pc palette
117         palette_pc[0] = RGB_COLOR(0, 0, 0);
118 #if defined(_MZ1200) || defined(_MZ80A)
119         palette_pc[1] = RGB_COLOR(0, 255, 0);
120 #else
121         if(config.monitor_type) {
122                 palette_pc[1] = RGB_COLOR(0, 255, 0);
123         } else {
124                 palette_pc[1] = RGB_COLOR(255, 255, 255);
125         }
126 #endif
127         
128         // register event
129         register_vline_event(this);
130         register_event_by_clock(this, EVENT_TEMPO, CPU_CLOCKS / 64, true, NULL);        // 32hz * 2
131         register_event_by_clock(this, EVENT_BLINK, CPU_CLOCKS / 3, true, NULL);         // 1.5hz * 2
132 }
133
134 void MEMORY::reset()
135 {
136 #if defined(_MZ1200) || defined(_MZ80A)
137         // reset memory swap
138         memory_swap = false;
139         update_memory_swap();
140 #endif
141 #if defined(SUPPORT_MZ80AIF)
142         // MB8866 IRQ,DRQ
143         fdc_irq = fdc_drq = false;
144         update_fdif_rom_bank();
145 #endif
146         
147         tempo = blink = false;
148         vgate = true;
149 #if defined(_MZ1200) || defined(_MZ80A)
150         hblank = reverse = false;
151 #endif
152         pcg_data = pcg_addr = 0;
153         pcg_ctrl = 0xff;
154         
155         // motor is always rotating...
156         d_pio->write_signal(SIG_I8255_PORT_C, 0xff, 0x10);
157 }
158
159 void MEMORY::event_vline(int v, int clock)
160 {
161         // draw one line
162         if(0 <= v && v < 200) {
163 #if defined(_MZ80A)
164                 int ptr = (v >> 3) * 40 + (int)(e200 << 3);     // scroll
165 #else
166                 int ptr = (v >> 3) * 40;
167 #endif
168                 bool pcg_active = ((config.dipswitch & 1) && !(pcg_ctrl & 8));
169 #if defined(_MZ1200)
170                 uint8_t *pcg_ptr = pcg + ((pcg_ctrl & 4) ? 0x800 : 0);
171 #else
172                 #define pcg_ptr pcg
173 #endif
174                 
175                 for(int x = 0; x < 320; x += 8) {
176                         int code = vram[(ptr++) & 0x7ff] << 3;
177                         uint8_t pat = pcg_active ? pcg_ptr[code | (v & 7)] : font[code | (v & 7)];
178                         
179                         // 8255(PIO) PC0 is /V-GATE 2016.11.21 by Suga
180                         if((d_pio->read_io8(2) & 0x01) == 0x00) {
181                                 pat = 0x00;
182                         }
183 #if defined(_MZ1200) || defined(_MZ80A)
184                         if(reverse) {
185                                 pat = ~pat;
186                         }
187 #endif
188                         uint8_t* dest = &screen[v][x];
189                         
190                         dest[0] = (pat & 0x80) >> 7;
191                         dest[1] = (pat & 0x40) >> 6;
192                         dest[2] = (pat & 0x20) >> 5;
193                         dest[3] = (pat & 0x10) >> 4;
194                         dest[4] = (pat & 0x08) >> 3;
195                         dest[5] = (pat & 0x04) >> 2;
196                         dest[6] = (pat & 0x02) >> 1;
197                         dest[7] = (pat & 0x01) >> 0;
198                 }
199         }
200         
201         // vblank
202         if(v == 0) {
203                 d_pio->write_signal(SIG_I8255_PORT_C, 0xff, 0x80);
204         } else if(v == 200) {
205                 d_pio->write_signal(SIG_I8255_PORT_C, 0, 0x80);
206         }
207         
208 #if defined(_MZ1200) || defined(_MZ80A)
209         // hblank
210         hblank = true;
211         register_event_by_clock(this, EVENT_HBLANK, 92, false, NULL);
212 #endif
213 }
214
215 void MEMORY::event_callback(int event_id, int err)
216 {
217         if(event_id == EVENT_TEMPO) {
218                 // 32khz
219                 tempo = !tempo;
220         } else if(event_id == EVENT_BLINK) {
221                 // 1.5khz
222                 d_pio->write_signal(SIG_I8255_PORT_C, (blink = !blink) ? 0xff : 0, 0x40);
223 #if defined(_MZ1200) || defined(_MZ80A)
224         } else if(event_id == EVENT_HBLANK) {
225                 hblank = false;
226 #endif
227         }
228 }
229
230 void MEMORY::write_data8(uint32_t addr, uint32_t data)
231 {
232         addr &= 0xffff;
233         if(0xe000 <= addr && addr <= 0xe7ff) {
234                 // memory mapped i/o
235                 switch(addr) {
236                 case 0xe000: case 0xe001: case 0xe002: case 0xe003:
237                         d_pio->write_io8(addr & 3, data);
238                         break;
239                 case 0xe004: case 0xe005: case 0xe006: case 0xe007:
240                         d_ctc->write_io8(addr & 3, data);
241                         break;
242                 case 0xe008:
243                         // 8253 gate0
244                         d_ctc->write_signal(SIG_I8253_GATE_0, data, 1);
245                         break;
246                 case 0xe010:
247                         pcg_data = data;
248                         break;
249                 case 0xe011:
250                         pcg_addr = data;
251                         break;
252                 case 0xe012:
253                         if(!(pcg_ctrl & 0x10) && (data & 0x10)) {
254                                 int offset = pcg_addr | ((data & 3) << 8);
255 #if defined(_MZ1200)
256                                 pcg[offset | ((data & 4) ? 0xc00 : 0x400)] = (data & 0x20) ? font[offset | 0x400] : pcg_data;
257 #else
258                                 pcg[offset |                       0x400 ] = (data & 0x20) ? font[offset | 0x400] : pcg_data;
259 #endif
260                         }
261                         pcg_ctrl = data;
262                         break;
263                 }
264                 return;
265         }
266         wbank[addr >> 10][addr & 0x3ff] = data;
267 }
268
269 uint32_t MEMORY::read_data8(uint32_t addr)
270 {
271         addr &= 0xffff;
272         if(0xe000 <= addr && addr <= 0xe7ff) {
273                 // memory mapped i/o
274                 switch(addr) {
275                 case 0xe000: case 0xe001: case 0xe002: case 0xe003:
276                         return d_pio->read_io8(addr & 3);
277                 case 0xe004: case 0xe005: case 0xe006: case 0xe007:
278                         return d_ctc->read_io8(addr & 3);
279                 case 0xe008:
280 #if defined(_MZ1200) || defined(_MZ80A)
281                         return (hblank ? 0x80 : 0) | (tempo ? 1 : 0) | 0x7e;
282 #else
283                         return (tempo ? 1 : 0) | 0xfe;
284 #endif
285 #if defined(_MZ1200) || defined(_MZ80A)
286                 case 0xe00c:
287                         // memory swap
288                         if(!memory_swap) {
289                                 memory_swap = true;
290                                 update_memory_swap();
291                         }
292                         break;
293                 case 0xe010:
294                         // reset memory swap
295                         if(memory_swap) {
296                                 memory_swap = false;
297                                 update_memory_swap();
298                         }
299                         break;
300                 case 0xe014:
301                         // normal display
302                         reverse = false;
303                         break;
304                 case 0xe015:
305                         // reverse display
306                         reverse = true;
307                         break;
308 #endif
309 #if defined(_MZ80A)
310                 default:
311                         if(0xe200 <= addr && addr <= 0xe2ff) {
312                                 e200 = addr & 0xff;     // scroll
313                         }
314                         break;
315 #endif
316                 }
317                 return 0xff;
318         }
319         return rbank[addr >> 10][addr & 0x3ff];
320 }
321
322 #if defined(_MZ1200) || defined(_MZ80A)
323 void MEMORY::update_memory_swap()
324 {
325         if(memory_swap) {
326                 SET_BANK(0x0000, 0x0fff, ram + 0xc000, ram + 0xc000);
327                 SET_BANK(0xc000, 0xcfff, wdmy, ipl);
328         } else {
329                 SET_BANK(0x0000, 0x0fff, wdmy, ipl);
330                 SET_BANK(0xc000, 0xcfff, ram + 0xc000, ram + 0xc000);
331         }
332 }
333 #endif
334
335 #if defined(SUPPORT_MZ80AIF)
336 void MEMORY::update_fdif_rom_bank()
337 {
338         // FD IF ROM BANK switching
339         if(fdc_drq) {
340                 // F000-F7FF    FD IF (MZ-80AIF) ROM  offset 0x400
341                 SET_BANK(0xf000, 0xf3ff, wdmy, fdif + 0x400 );  // FD IF ROM 1KB (2KB / 2)
342                 SET_BANK(0xf400, 0xf7ff, wdmy, fdif + 0x400 );  // FD IF ROM ghost
343         } else {
344                 // F000-F7FF    FD IF (MZ-80AIF) ROM  offset 0
345                 SET_BANK(0xf000, 0xf3ff, wdmy, fdif );          // FD IF ROM 1KB (2KB / 2)
346                 SET_BANK(0xf400, 0xf7ff, wdmy, fdif );          // FD IF ROM ghost
347         }
348 }
349 #endif
350
351 void MEMORY::write_signal(int id, uint32_t data, uint32_t mask)
352 {
353         bool signal = ((data & mask) != 0);
354         
355         if(id == SIG_MEMORY_VGATE) {
356                 vgate = signal;
357 #if defined(SUPPORT_MZ80AIF)
358         } else if(id == SIG_MEMORY_FDC_IRQ) {
359                 if(fdc_irq != signal) {
360                         fdc_irq = signal;
361 //#ifdef _FDC_DEBUG_LOG
362                         if(config.special_debug_fdc) this->out_debug_log(_T("MEM\tfdc_irq=%2x\n"), fdc_irq);
363 //#endif
364 //                      update_fdif_rom_bank();
365                 }
366         } else if(id == SIG_MEMORY_FDC_DRQ) {
367                 if(fdc_drq != signal) {
368                         fdc_drq = signal;
369 //#ifdef _FDC_DEBUG_LOG
370                         if(config.special_debug_fdc) this->out_debug_log(_T("MEM\tfdc_drq=%2x\n"), fdc_drq);
371 //#endif
372                         update_fdif_rom_bank();
373                 }
374 #endif
375         }
376 }
377
378 #if defined(_MZ80K)
379 void MEMORY::update_config()
380 {
381         if(config.monitor_type) {
382                 palette_pc[1] = RGB_COLOR(0, 255, 0);
383         } else {
384                 palette_pc[1] = RGB_COLOR(255, 255, 255);
385         }
386 }
387 #endif
388
389 void MEMORY::draw_screen()
390 {
391         // copy to real screen
392         emu->set_vm_screen_lines(200);
393         
394         if(true || vgate) {
395                 for(int y = 0; y < 200; y++) {
396                         scrntype_t* dest = emu->get_screen_buffer(y);
397                         uint8_t* src = screen[y];
398                         
399                         for(int x = 0; x < 320; x++) {
400                                 dest[x] = palette_pc[src[x] & 1];
401                         }
402                 }
403         } else {
404                 for(int y = 0; y < 200; y++) {
405                         scrntype_t* dest = emu->get_screen_buffer(y);
406                         memset(dest, 0, sizeof(scrntype_t) * 320);
407                 }
408         }
409 }
410
411 #define STATE_VERSION   3
412
413 #include "../../statesub.h"
414
415 void MEMORY::decl_state()
416 {
417         enter_decl_state(STATE_VERSION);
418         
419         DECL_STATE_ENTRY_1D_ARRAY(ram, sizeof(ram));
420         DECL_STATE_ENTRY_1D_ARRAY(vram, sizeof(vram));
421         DECL_STATE_ENTRY_BOOL(tempo);
422         DECL_STATE_ENTRY_BOOL(blink);
423 #if defined(_MZ1200) || defined(_MZ80A)
424         DECL_STATE_ENTRY_BOOL(hblank);
425         DECL_STATE_ENTRY_BOOL(memory_swap);
426 #endif
427 #if defined(SUPPORT_MZ80AIF)
428         DECL_STATE_ENTRY_BOOL(fdc_irq);
429         DECL_STATE_ENTRY_BOOL(fdc_drq);
430 #endif
431         DECL_STATE_ENTRY_BOOL(vgate);
432 #if defined(_MZ1200) || defined(_MZ80A)
433         DECL_STATE_ENTRY_BOOL(reverse);
434 #endif
435 #if defined(_MZ80A)
436         DECL_STATE_ENTRY_UINT32(e200);
437 #endif
438         DECL_STATE_ENTRY_1D_ARRAY(&(pcg[0x400]), 0x400);
439 #if defined(_MZ1200)
440         DECL_STATE_ENTRY_1D_ARRAY(&(pcg[0xc00]), 0x400);
441 #endif
442         DECL_STATE_ENTRY_UINT8(pcg_data);
443         DECL_STATE_ENTRY_UINT8(pcg_addr);
444         DECL_STATE_ENTRY_UINT8(pcg_ctrl);
445         
446         leave_decl_state();
447 }
448
449 void MEMORY::save_state(FILEIO* state_fio)
450 {
451
452         if(state_entry != NULL) {
453                 state_entry->save_state(state_fio);
454         }
455 //      state_fio->FputUint32(STATE_VERSION);
456 //      state_fio->FputInt32(this_device_id);
457         
458 //      state_fio->Fwrite(ram, sizeof(ram), 1);
459 //      state_fio->Fwrite(vram, sizeof(vram), 1);
460 //      state_fio->FputBool(tempo);
461 //      state_fio->FputBool(blink);
462 //#if defined(_MZ1200) || defined(_MZ80A)
463 //      state_fio->FputBool(hblank);
464 //      state_fio->FputBool(memory_swap);
465 //#endif
466 //#if defined(SUPPORT_MZ80AIF)
467 //      state_fio->FputBool(fdc_irq);
468 //      state_fio->FputBool(fdc_drq);
469 //#endif
470 //      vgate = state_fio->FgetBool();
471 //#if defined(_MZ1200) || defined(_MZ80A)
472 //      reverse = state_fio->FgetBool();
473 //#endif
474 //#if defined(_MZ80A)
475 //      state_fio->FputUint32(e200);
476 //#endif
477 //      state_fio->Fwrite(pcg + 0x400, 0x400, 1);
478 //#if defined(_MZ1200)
479 //      state_fio->Fwrite(pcg + 0xc00, 0x400, 1);
480 //#endif
481 //      state_fio->FputUint8(pcg_data);
482 //      state_fio->FputUint8(pcg_addr);
483 //      state_fio->FputUint8(pcg_ctrl);
484 }
485
486 bool MEMORY::load_state(FILEIO* state_fio)
487 {
488         bool mb = false;
489         if(state_entry != NULL) {
490                 mb = state_entry->load_state(state_fio);
491         }
492         if(!mb) {
493                 return false;
494         }
495 //      if(state_fio->FgetUint32() != STATE_VERSION) {
496 //              return false;
497 //      }
498 //      if(state_fio->FgetInt32() != this_device_id) {
499 //              return false;
500 //      }
501 //      state_fio->Fread(ram, sizeof(ram), 1);
502 //      state_fio->Fread(vram, sizeof(vram), 1);
503 //      tempo = state_fio->FgetBool();
504 //      blink = state_fio->FgetBool();
505 //#if defined(_MZ1200) || defined(_MZ80A)
506 //      hblank = state_fio->FgetBool();
507 //      memory_swap = state_fio->FgetBool();
508 //#endif
509 //#if defined(SUPPORT_MZ80AIF)
510 //      fdc_irq = state_fio->FgetBool();
511 //      fdc_drq = state_fio->FgetBool();
512 //#endif
513 //      state_fio->FputBool(vgate);
514 //#if defined(_MZ1200) || defined(_MZ80A)
515 //      state_fio->FputBool(reverse);
516 //#endif
517 //#if defined(_MZ80A)
518 //      e200 = state_fio->FgetUint32();
519 //#endif
520 //      state_fio->Fread(pcg + 0x400, 0x400, 1);
521 //#if defined(_MZ1200)
522 //      state_fio->Fread(pcg + 0xc00, 0x400, 1);
523 //#endif
524 //      pcg_data = state_fio->FgetUint8();
525 //      pcg_addr = state_fio->FgetUint8();
526 //      pcg_ctrl = state_fio->FgetUint8();
527         
528         // post process
529 #if defined(_MZ1200) || defined(_MZ80A)
530         update_memory_swap();
531 #endif
532 #if defined(SUPPORT_MZ80AIF)
533         update_fdif_rom_bank();
534 #endif
535         return true;
536 }
537
538 bool MEMORY::process_state(FILEIO* state_fio, bool loading)
539 {
540         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
541                 return false;
542         }
543         if(!state_fio->StateCheckInt32(this_device_id)) {
544                 return false;
545         }
546         state_fio->StateBuffer(ram, sizeof(ram), 1);
547         state_fio->StateBuffer(vram, sizeof(vram), 1);
548         state_fio->StateBool(tempo);
549         state_fio->StateBool(blink);
550 #if defined(_MZ1200) || defined(_MZ80A)
551         state_fio->StateBool(hblank);
552         state_fio->StateBool(memory_swap);
553 #endif
554 #if defined(SUPPORT_MZ80AIF)
555         state_fio->StateBool(fdc_irq);
556         state_fio->StateBool(fdc_drq);
557 #endif
558         state_fio->StateBool(vgate);
559 #if defined(_MZ1200) || defined(_MZ80A)
560         state_fio->StateBool(reverse);
561 #endif
562 #if defined(_MZ80A)
563         state_fio->StateUint32(e200);
564 #endif
565         state_fio->StateBuffer(pcg + 0x400, 0x400, 1);
566 #if defined(_MZ1200)
567         state_fio->StateBuffer(pcg + 0xc00, 0x400, 1);
568 #endif
569         state_fio->StateUint8(pcg_data);
570         state_fio->StateUint8(pcg_addr);
571         state_fio->StateUint8(pcg_ctrl);
572         
573         // post process
574         if(loading) {
575 #if defined(_MZ1200) || defined(_MZ80A)
576                 update_memory_swap();
577 #endif
578 #if defined(SUPPORT_MZ80AIF)
579                 update_fdif_rom_bank();
580 #endif
581         }
582         return true;
583 }