OSDN Git Service

[VM][I286] Save cpustate without StateBuffer().
[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 MZ80A_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 MZ80A_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 MZ80A_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 MZ80A_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 MZ80A_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 MZ80A_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 MZ80A_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 MZ80A_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 MZ80A_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 MZ80A_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 MZ80A_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 bool MZ80A_MEMORY::process_state(FILEIO* state_fio, bool loading)
414 {
415         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
416                 return false;
417         }
418         if(!state_fio->StateCheckInt32(this_device_id)) {
419                 return false;
420         }
421         state_fio->StateBuffer(ram, sizeof(ram), 1);
422         state_fio->StateBuffer(vram, sizeof(vram), 1);
423         state_fio->StateBool(tempo);
424         state_fio->StateBool(blink);
425 #if defined(_MZ1200) || defined(_MZ80A)
426         state_fio->StateBool(hblank);
427         state_fio->StateBool(memory_swap);
428 #endif
429 #if defined(SUPPORT_MZ80AIF)
430         state_fio->StateBool(fdc_irq);
431         state_fio->StateBool(fdc_drq);
432 #endif
433         state_fio->StateBool(vgate);
434 #if defined(_MZ1200) || defined(_MZ80A)
435         state_fio->StateBool(reverse);
436 #endif
437 #if defined(_MZ80A)
438         state_fio->StateUint32(e200);
439 #endif
440         state_fio->StateBuffer(pcg + 0x400, 0x400, 1);
441 #if defined(_MZ1200)
442         state_fio->StateBuffer(pcg + 0xc00, 0x400, 1);
443 #endif
444         state_fio->StateUint8(pcg_data);
445         state_fio->StateUint8(pcg_addr);
446         state_fio->StateUint8(pcg_ctrl);
447         
448         // post process
449         if(loading) {
450 #if defined(_MZ1200) || defined(_MZ80A)
451                 update_memory_swap();
452 #endif
453 #if defined(SUPPORT_MZ80AIF)
454                 update_fdif_rom_bank();
455 #endif
456         }
457         return true;
458 }