OSDN Git Service

[VM][General][WIP] Start to merge upstream 2018-10-14.Open branch upstream_20181014 .
[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 namespace MZ80 {
24
25 #define SET_BANK(s, e, w, r) { \
26         int sb = (s) >> 10, eb = (e) >> 10; \
27         for(int i = sb; i <= eb; i++) { \
28                 if((w) == wdmy) { \
29                         wbank[i] = wdmy; \
30                 } else { \
31                         wbank[i] = (w) + 0x400 * (i - sb); \
32                 } \
33                 if((r) == rdmy) { \
34                         rbank[i] = rdmy; \
35                 } else { \
36                         rbank[i] = (r) + 0x400 * (i - sb); \
37                 } \
38         } \
39 }
40
41 void MEMORY::initialize()
42 {
43         // init memory
44         memset(ram, 0, sizeof(ram));
45         memset(vram, 0, sizeof(vram));
46         memset(ipl, 0xff, sizeof(ipl));
47 #if defined(_MZ1200) || defined(_MZ80A)
48         memset(ext, 0xff, sizeof(ext));
49 #endif
50 #if defined(SUPPORT_MZ80AIF) || defined(SUPPORT_MZ80FIO)
51         memset(fdif, 0xff, sizeof(fdif));
52 #endif
53         memset(rdmy, 0xff, sizeof(rdmy));
54         
55         // load rom images
56         FILEIO* fio = new FILEIO();
57         if(fio->Fopen(create_local_path(_T("IPL.ROM")), FILEIO_READ_BINARY)) {
58                 fio->Fread(ipl, sizeof(ipl), 1);
59                 fio->Fclose();
60         }
61 #if defined(_MZ1200) || defined(_MZ80A)
62         if(fio->Fopen(create_local_path(_T("EXT.ROM")), FILEIO_READ_BINARY)) {
63                 fio->Fread(ext, sizeof(ext), 1);
64                 fio->Fclose();
65         }
66 #endif
67 #if defined(SUPPORT_MZ80AIF) || defined(SUPPORT_MZ80FIO)
68         if(fio->Fopen(create_local_path(_T("FDIF.ROM")), FILEIO_READ_BINARY)) {
69                 fio->Fread(fdif, sizeof(fdif), 1);
70                 fio->Fclose();
71         }
72 #endif
73         if(fio->Fopen(create_local_path(_T("FONT.ROM")), FILEIO_READ_BINARY)) {
74                 fio->Fread(font, sizeof(font), 1);
75                 fio->Fclose();
76         }
77         delete fio;
78         
79         // 0000-0FFF    IPL/RAM
80         // 1000-BFFF    RAM
81         // C000-CFFF    RAM/IPL
82         SET_BANK(0x0000, 0x0fff, wdmy, ipl);
83         SET_BANK(0x1000, 0xbfff, ram + 0x1000, ram + 0x1000);
84         SET_BANK(0xc000, 0xcfff, ram + 0xc000, ram + 0xc000);
85 #if defined(_MZ1200) || defined(_MZ80A)
86         SET_BANK(0xd000, 0xd7ff, vram, vram);   // VRAM 2KB
87         SET_BANK(0xd800, 0xdfff, wdmy, rdmy);
88 #else
89         SET_BANK(0xd000, 0xd3ff, vram, vram);   // VRAM 1KB
90         SET_BANK(0xd400, 0xd7ff, vram, vram);
91         SET_BANK(0xd800, 0xdbff, vram, vram);
92         SET_BANK(0xdc00, 0xdfff, vram, vram);
93 #endif
94 #if defined(_MZ1200) || defined(_MZ80A)
95         SET_BANK(0xe000, 0xe7ff, wdmy, rdmy);
96         SET_BANK(0xe800, 0xefff, wdmy, ext);
97 #else
98         SET_BANK(0xe000, 0xefff, wdmy, rdmy);
99 #endif
100 #if defined(SUPPORT_MZ80FIO)
101         SET_BANK(0xf000, 0xf3ff, wdmy, fdif);
102         SET_BANK(0xf400, 0xffff, wdmy, rdmy);
103 #else
104         SET_BANK(0xf000, 0xffff, wdmy, rdmy);
105 #endif
106         
107 #if defined(_MZ80A)
108         // init scroll register
109         e200 = 0x00;    // scroll
110 #endif
111         // init pcg
112         memset(pcg, 0, sizeof(pcg));
113         memcpy(pcg + 0x000, font, 0x400); // copy pattern of 00h-7fh
114 #if defined(_MZ1200)
115         memcpy(pcg + 0x800, font, 0x400);
116 #endif
117         
118         // create pc palette
119         palette_pc[0] = RGB_COLOR(0, 0, 0);
120 #if defined(_MZ1200) || defined(_MZ80A)
121         palette_pc[1] = RGB_COLOR(0, 255, 0);
122 #else
123         if(config.monitor_type) {
124                 palette_pc[1] = RGB_COLOR(0, 255, 0);
125         } else {
126                 palette_pc[1] = RGB_COLOR(255, 255, 255);
127         }
128 #endif
129         
130         // register event
131         register_vline_event(this);
132         register_event_by_clock(this, EVENT_TEMPO, CPU_CLOCKS / 64, true, NULL);        // 32hz * 2
133         register_event_by_clock(this, EVENT_BLINK, CPU_CLOCKS / 3, true, NULL);         // 1.5hz * 2
134 }
135
136 void MEMORY::reset()
137 {
138 #if defined(_MZ1200) || defined(_MZ80A)
139         // reset memory swap
140         memory_swap = false;
141         update_memory_swap();
142 #endif
143 #if defined(SUPPORT_MZ80AIF)
144         // MB8866 IRQ,DRQ
145         fdc_irq = fdc_drq = false;
146         update_fdif_rom_bank();
147 #endif
148         
149         tempo = blink = false;
150         vgate = true;
151 #if defined(_MZ1200) || defined(_MZ80A)
152         hblank = reverse = false;
153 #endif
154         pcg_data = pcg_addr = 0;
155         pcg_ctrl = 0xff;
156         
157         // motor is always rotating...
158         d_pio->write_signal(SIG_I8255_PORT_C, 0xff, 0x10);
159 }
160
161 void MEMORY::event_vline(int v, int clock)
162 {
163         // draw one line
164         if(0 <= v && v < 200) {
165 #if defined(_MZ80A)
166                 int ptr = (v >> 3) * 40 + (int)(e200 << 3);     // scroll
167 #else
168                 int ptr = (v >> 3) * 40;
169 #endif
170                 bool pcg_active = ((config.dipswitch & 1) && !(pcg_ctrl & 8));
171 #if defined(_MZ1200)
172                 uint8_t *pcg_ptr = pcg + ((pcg_ctrl & 4) ? 0x800 : 0);
173 #else
174                 #define pcg_ptr pcg
175 #endif
176                 
177                 for(int x = 0; x < 320; x += 8) {
178                         int code = vram[(ptr++) & 0x7ff] << 3;
179                         uint8_t pat = pcg_active ? pcg_ptr[code | (v & 7)] : font[code | (v & 7)];
180                         
181                         // 8255(PIO) PC0 is /V-GATE 2016.11.21 by Suga
182                         if((d_pio->read_io8(2) & 0x01) == 0x00) {
183                                 pat = 0x00;
184                         }
185 #if defined(_MZ1200) || defined(_MZ80A)
186                         if(reverse) {
187                                 pat = ~pat;
188                         }
189 #endif
190                         uint8_t* dest = &screen[v][x];
191                         
192                         dest[0] = (pat & 0x80) >> 7;
193                         dest[1] = (pat & 0x40) >> 6;
194                         dest[2] = (pat & 0x20) >> 5;
195                         dest[3] = (pat & 0x10) >> 4;
196                         dest[4] = (pat & 0x08) >> 3;
197                         dest[5] = (pat & 0x04) >> 2;
198                         dest[6] = (pat & 0x02) >> 1;
199                         dest[7] = (pat & 0x01) >> 0;
200                 }
201         }
202         
203         // vblank
204         if(v == 0) {
205                 d_pio->write_signal(SIG_I8255_PORT_C, 0xff, 0x80);
206         } else if(v == 200) {
207                 d_pio->write_signal(SIG_I8255_PORT_C, 0, 0x80);
208         }
209         
210 #if defined(_MZ1200) || defined(_MZ80A)
211         // hblank
212         hblank = true;
213         register_event_by_clock(this, EVENT_HBLANK, 92, false, NULL);
214 #endif
215 }
216
217 void MEMORY::event_callback(int event_id, int err)
218 {
219         if(event_id == EVENT_TEMPO) {
220                 // 32khz
221                 tempo = !tempo;
222         } else if(event_id == EVENT_BLINK) {
223                 // 1.5khz
224                 d_pio->write_signal(SIG_I8255_PORT_C, (blink = !blink) ? 0xff : 0, 0x40);
225 #if defined(_MZ1200) || defined(_MZ80A)
226         } else if(event_id == EVENT_HBLANK) {
227                 hblank = false;
228 #endif
229         }
230 }
231
232 void MEMORY::write_data8(uint32_t addr, uint32_t data)
233 {
234         addr &= 0xffff;
235         if(0xe000 <= addr && addr <= 0xe7ff) {
236                 // memory mapped i/o
237                 switch(addr) {
238                 case 0xe000: case 0xe001: case 0xe002: case 0xe003:
239                         d_pio->write_io8(addr & 3, data);
240                         break;
241                 case 0xe004: case 0xe005: case 0xe006: case 0xe007:
242                         d_ctc->write_io8(addr & 3, data);
243                         break;
244                 case 0xe008:
245                         // 8253 gate0
246                         d_ctc->write_signal(SIG_I8253_GATE_0, data, 1);
247                         break;
248                 case 0xe010:
249                         pcg_data = data;
250                         break;
251                 case 0xe011:
252                         pcg_addr = data;
253                         break;
254                 case 0xe012:
255                         if(!(pcg_ctrl & 0x10) && (data & 0x10)) {
256                                 int offset = pcg_addr | ((data & 3) << 8);
257 #if defined(_MZ1200)
258                                 pcg[offset | ((data & 4) ? 0xc00 : 0x400)] = (data & 0x20) ? font[offset | 0x400] : pcg_data;
259 #else
260                                 pcg[offset |                       0x400 ] = (data & 0x20) ? font[offset | 0x400] : pcg_data;
261 #endif
262                         }
263                         pcg_ctrl = data;
264                         break;
265                 }
266                 return;
267         }
268         wbank[addr >> 10][addr & 0x3ff] = data;
269 }
270
271 uint32_t MEMORY::read_data8(uint32_t addr)
272 {
273         addr &= 0xffff;
274         if(0xe000 <= addr && addr <= 0xe7ff) {
275                 // memory mapped i/o
276                 switch(addr) {
277                 case 0xe000: case 0xe001: case 0xe002: case 0xe003:
278                         return d_pio->read_io8(addr & 3);
279                 case 0xe004: case 0xe005: case 0xe006: case 0xe007:
280                         return d_ctc->read_io8(addr & 3);
281                 case 0xe008:
282 #if defined(_MZ1200) || defined(_MZ80A)
283                         return (hblank ? 0x80 : 0) | (tempo ? 1 : 0) | 0x7e;
284 #else
285                         return (tempo ? 1 : 0) | 0xfe;
286 #endif
287 #if defined(_MZ1200) || defined(_MZ80A)
288                 case 0xe00c:
289                         // memory swap
290                         if(!memory_swap) {
291                                 memory_swap = true;
292                                 update_memory_swap();
293                         }
294                         break;
295                 case 0xe010:
296                         // reset memory swap
297                         if(memory_swap) {
298                                 memory_swap = false;
299                                 update_memory_swap();
300                         }
301                         break;
302                 case 0xe014:
303                         // normal display
304                         reverse = false;
305                         break;
306                 case 0xe015:
307                         // reverse display
308                         reverse = true;
309                         break;
310 #endif
311 #if defined(_MZ80A)
312                 default:
313                         if(0xe200 <= addr && addr <= 0xe2ff) {
314                                 e200 = addr & 0xff;     // scroll
315                         }
316                         break;
317 #endif
318                 }
319                 return 0xff;
320         }
321         return rbank[addr >> 10][addr & 0x3ff];
322 }
323
324 #if defined(_MZ1200) || defined(_MZ80A)
325 void MEMORY::update_memory_swap()
326 {
327         if(memory_swap) {
328                 SET_BANK(0x0000, 0x0fff, ram + 0xc000, ram + 0xc000);
329                 SET_BANK(0xc000, 0xcfff, wdmy, ipl);
330         } else {
331                 SET_BANK(0x0000, 0x0fff, wdmy, ipl);
332                 SET_BANK(0xc000, 0xcfff, ram + 0xc000, ram + 0xc000);
333         }
334 }
335 #endif
336
337 #if defined(SUPPORT_MZ80AIF)
338 void MEMORY::update_fdif_rom_bank()
339 {
340         // FD IF ROM BANK switching
341         if(fdc_drq) {
342                 // F000-F7FF    FD IF (MZ-80AIF) ROM  offset 0x400
343                 SET_BANK(0xf000, 0xf3ff, wdmy, fdif + 0x400 );  // FD IF ROM 1KB (2KB / 2)
344                 SET_BANK(0xf400, 0xf7ff, wdmy, fdif + 0x400 );  // FD IF ROM ghost
345         } else {
346                 // F000-F7FF    FD IF (MZ-80AIF) ROM  offset 0
347                 SET_BANK(0xf000, 0xf3ff, wdmy, fdif );          // FD IF ROM 1KB (2KB / 2)
348                 SET_BANK(0xf400, 0xf7ff, wdmy, fdif );          // FD IF ROM ghost
349         }
350 }
351 #endif
352
353 void MEMORY::write_signal(int id, uint32_t data, uint32_t mask)
354 {
355         bool signal = ((data & mask) != 0);
356         
357         if(id == SIG_MEMORY_VGATE) {
358                 vgate = signal;
359 #if defined(SUPPORT_MZ80AIF)
360         } else if(id == SIG_MEMORY_FDC_IRQ) {
361                 if(fdc_irq != signal) {
362                         fdc_irq = signal;
363 //#ifdef _FDC_DEBUG_LOG
364                         if(config.special_debug_fdc) this->out_debug_log(_T("MEM\tfdc_irq=%2x\n"), fdc_irq);
365 //#endif
366 //                      update_fdif_rom_bank();
367                 }
368         } else if(id == SIG_MEMORY_FDC_DRQ) {
369                 if(fdc_drq != signal) {
370                         fdc_drq = signal;
371 //#ifdef _FDC_DEBUG_LOG
372                         if(config.special_debug_fdc) this->out_debug_log(_T("MEM\tfdc_drq=%2x\n"), fdc_drq);
373 //#endif
374                         update_fdif_rom_bank();
375                 }
376 #endif
377         }
378 }
379
380 #if defined(_MZ80K)
381 void MEMORY::update_config()
382 {
383         if(config.monitor_type) {
384                 palette_pc[1] = RGB_COLOR(0, 255, 0);
385         } else {
386                 palette_pc[1] = RGB_COLOR(255, 255, 255);
387         }
388 }
389 #endif
390
391 void MEMORY::draw_screen()
392 {
393         // copy to real screen
394         emu->set_vm_screen_lines(200);
395         
396         if(true || vgate) {
397                 for(int y = 0; y < 200; y++) {
398                         scrntype_t* dest = emu->get_screen_buffer(y);
399                         uint8_t* src = screen[y];
400                         
401                         for(int x = 0; x < 320; x++) {
402                                 dest[x] = palette_pc[src[x] & 1];
403                         }
404                 }
405         } else {
406                 for(int y = 0; y < 200; y++) {
407                         scrntype_t* dest = emu->get_screen_buffer(y);
408                         memset(dest, 0, sizeof(scrntype_t) * 320);
409                 }
410         }
411 }
412
413 #define STATE_VERSION   3
414
415 bool MEMORY::process_state(FILEIO* state_fio, bool loading)
416 {
417         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
418                 return false;
419         }
420         if(!state_fio->StateCheckInt32(this_device_id)) {
421                 return false;
422         }
423         state_fio->StateArray(ram, sizeof(ram), 1);
424         state_fio->StateArray(vram, sizeof(vram), 1);
425         state_fio->StateValue(tempo);
426         state_fio->StateValue(blink);
427 #if defined(_MZ1200) || defined(_MZ80A)
428         state_fio->StateValue(hblank);
429         state_fio->StateValue(memory_swap);
430 #endif
431 #if defined(SUPPORT_MZ80AIF)
432         state_fio->StateValue(fdc_irq);
433         state_fio->StateValue(fdc_drq);
434 #endif
435         state_fio->StateValue(vgate);
436 #if defined(_MZ1200) || defined(_MZ80A)
437         state_fio->StateValue(reverse);
438 #endif
439 #if defined(_MZ80A)
440         state_fio->StateValue(e200);
441 #endif
442         state_fio->StateArray(pcg + 0x400, 0x400, 1);
443 #if defined(_MZ1200)
444         state_fio->StateArray(pcg + 0xc00, 0x400, 1);
445 #endif
446         state_fio->StateValue(pcg_data);
447         state_fio->StateValue(pcg_addr);
448         state_fio->StateValue(pcg_ctrl);
449         
450         // post process
451         if(loading) {
452 #if defined(_MZ1200) || defined(_MZ80A)
453                 update_memory_swap();
454 #endif
455 #if defined(SUPPORT_MZ80AIF)
456                 update_fdif_rom_bank();
457 #endif
458         }
459         return true;
460 }
461
462 }