OSDN Git Service

[VM][FM7][DISPLAY] Use function table to access memories within display sub-system.
[csp-qt/common_source_project-fm7.git] / source / src / vm / fm7 / display.cpp
1 /*
2  * Common source code project -> FM-7 -> Display
3  * (C) 2015 K.Ohta <whatisthis.sowhat _at_ gmail.com>
4  * History:
5  *  Feb 10, 2015 : Initial.
6  */
7
8 #include "vm.h"
9 #include "emu.h"
10 #include "../../fileio.h"
11 #include "fm7_display.h"
12 #if defined(_FM77AV_VARIANTS)
13 # include "mb61vh010.h"
14 #endif
15
16 DISPLAY::DISPLAY(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu)
17 {
18         p_vm = parent_vm;
19         p_emu = parent_emu;
20         ins_led = NULL;
21         kana_led = NULL;
22         caps_led = NULL;
23 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX)
24         kanjiclass1 = NULL;
25         kanjiclass2 = NULL;
26 #elif defined(_FM77_VARIANTS)
27         kanjiclass1 = NULL;
28 #endif
29 #if defined(_FM77AV_VARIANTS)
30         alu = NULL;
31 #endif
32         mainio = NULL;
33         subcpu = NULL;
34         keyboard = NULL;
35         for(int i = 0; i < 256; i++) {
36                 uint16_t n = (uint16_t)i;
37                 for(int j = 0; j < 8; j++) {
38                         bit_trans_table_0[i][j] = n & 0x80;
39                         bit_trans_table_1[i][j] = ((n & 0x80) != 0) ? 0x40 : 0;
40                         bit_trans_table_2[i][j] = ((n & 0x80) != 0) ? 0x20 : 0;
41                         bit_trans_table_3[i][j] = ((n & 0x80) != 0) ? 0x10 : 0;
42 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX)
43                         bit_trans_table_4[i][j] = ((n & 0x80) != 0) ? 0x08 : 0;
44                         bit_trans_table_5[i][j] = ((n & 0x80) != 0) ? 0x04 : 0;
45 #endif                  
46                         n <<= 1;
47                 }
48         }
49         displine = 0;
50         active_page = 0;
51         set_device_name(_T("DISPLAY SUBSYSTEM"));
52 }
53
54 DISPLAY::~DISPLAY()
55 {
56
57 }
58
59 void DISPLAY::reset_cpuonly()
60 {
61         int i;
62         double usec;
63         keyboard->write_signal(SIG_FM7KEY_SET_INSLED, 0x00, 0x01);
64         mainio->write_signal(SIG_FM7_SUB_HALT, 0x00, 0xff);
65         sub_busy = true;
66         
67         palette_changed = true;
68         multimode_accessmask = 0;
69         multimode_dispmask = 0;
70         firq_mask = false;
71         //cancel_request = false;
72         switch(config.cpu_type){
73                 case 0:
74                         clock_fast = true;
75                         break;
76                 case 1:
77                         clock_fast = false;
78                         break;
79         }
80         enter_display();
81    
82         offset_point = 0;
83         for(i = 0; i < 2; i++) {
84                 offset_changed[i] = true;
85                 tmp_offset_point[i].d = 0;
86         }
87
88         vram_wrote_shadow = true;
89         for(i = 0; i < 411; i++) vram_wrote_table[i] = true;
90         for(i = 0; i < 411; i++) vram_draw_table[i] = true;
91         write_access_page = 0;
92         for(i = 0; i < 411; i++) vram_wrote_pages[i] = write_access_page;
93         displine = 0;
94         active_page = 0;
95         
96 #if defined(_FM77AV_VARIANTS) || defined(_FM77L4)
97         vsync = true;
98         vblank = true;
99         hblank = false;
100         vblank_count = 0;
101         
102         if(hblank_event_id >= 0) cancel_event(this, hblank_event_id);
103         if(hdisp_event_id >= 0) cancel_event(this, hdisp_event_id);
104         if(vsync_event_id >= 0) cancel_event(this, vsync_event_id);
105         if(vstart_event_id >= 0) cancel_event(this, vstart_event_id);
106         hblank_event_id = -1;
107         hdisp_event_id = -1;
108         vsync_event_id = -1;
109         vstart_event_id = -1;
110         if(display_mode == DISPLAY_MODE_8_400L) {
111                 usec = 0.33 * 1000.0; 
112         } else {
113                 usec = 0.51 * 1000.0;
114         }
115         //usec = 16.0;
116         register_event(this, EVENT_FM7SUB_VSTART, usec, false, &vstart_event_id); // NEXT CYCLE_
117         mainio->write_signal(SIG_DISPLAY_DISPLAY, 0x00, 0xff);
118         mainio->write_signal(SIG_DISPLAY_VSYNC, 0xff, 0xff);
119 #endif
120 #if defined(_FM77AV_VARIANTS)
121         offset_77av = false;
122         offset_point_bank1 = 0;
123         display_page = 0;
124         display_page_bak = 0;
125         
126         subcpu_resetreq = false;
127         subrom_bank_using = subrom_bank;
128    
129         nmi_enable = true;
130         use_alu = false;
131
132 # if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX)
133         vram_bank = 0;
134         vram_display_block = 0;
135         vram_active_block = 0;
136         
137 #  if defined(_FM77AV40EX) || defined(_FM77AV40SX)
138         window_low = 0;
139         window_high = 0;
140         window_xbegin = 0;
141         window_xend = 0;
142         window_opened = false;
143 #  endif        
144 # endif
145         
146         alu->reset();
147 # if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX)
148         alu->write_signal(SIG_ALU_X_WIDTH, (mode320 || mode256k) ? 40 : 80, 0xffff);
149         alu->write_signal(SIG_ALU_Y_HEIGHT, (display_mode == DISPLAY_MODE_8_400L) ? 400: 200, 0xffff);
150         alu->write_signal(SIG_ALU_400LINE, (display_mode == DISPLAY_MODE_8_400L) ? 0xffffffff : 0, 0xffffffff);
151 # else
152         alu->write_signal(SIG_ALU_X_WIDTH, (mode320) ? 40 : 80, 0xffff);
153         alu->write_signal(SIG_ALU_Y_HEIGHT, 200, 0xffff);
154         alu->write_signal(SIG_ALU_400LINE, 0, 0xffffffff);
155 # endif
156         alu->write_signal(SIG_ALU_MULTIPAGE, multimode_accessmask, 0x07);
157         alu->write_signal(SIG_ALU_PLANES, 3, 3);
158         
159 #endif
160         for(i = 0; i < 8; i++) set_dpalette(i, i);
161         do_firq(!firq_mask && key_firq_req);
162
163 #if defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
164         kanjisub = false;
165         kanjiaddr.d = 0x00000000;
166 # if defined(_FM77L4)
167         mode400line = false;
168         stat_400linecard = false;
169 # endif 
170 #endif
171         vram_wrote = true;
172         clr_count = 0;
173         frame_skip_count_draw = 3;
174         frame_skip_count_transfer = 3;
175         need_transfer_line = true;
176 }
177
178
179 void DISPLAY::reset()
180 {
181         int i;
182         memset(io_w_latch, 0xff, sizeof(io_w_latch));
183         halt_flag = false;
184         vram_accessflag = true;
185         display_mode = DISPLAY_MODE_8_200L;
186         crt_flag = true;
187         screen_update_flag = true;
188         crt_flag_bak = true;
189         
190         cancel_request = false;
191 #if defined(_FM77AV_VARIANTS)
192         mode320 = false;
193         apalette_index.d = 0;
194         for(i = 0; i < 4096; i++) {
195                 analog_palette_r[i] = i & 0x0f0;
196                 analog_palette_g[i] = (i & 0xf00) >> 4;
197                 analog_palette_b[i] = (i & 0x00f) << 4;
198                 calc_apalette(i);
199         }
200         subrom_bank = 0;
201         cgrom_bank = 0;
202 # if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX)
203         monitor_ram = false;
204         ram_protect = true;
205         
206         mode400line = false;
207         mode256k = false;
208 # endif
209 #elif defined(_FM77L4)
210         mode400line = false;
211 #endif
212         emu->set_vm_screen_size(640, 200, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_WIDTH_ASPECT, WINDOW_HEIGHT_ASPECT);
213         is_cyclesteal = ((config.dipswitch & FM7_DIPSW_CYCLESTEAL) != 0) ? true : false;
214         key_firq_req = false;   //firq_mask = true;
215         firq_mask = false;
216         reset_cpuonly();
217         
218 #if defined(_FM77AV_VARIANTS)
219         power_on_reset = false;
220         for(i = 0; i < 411; i++) vram_wrote_table[i] = false;
221         nmi_enable = true;
222 #else
223 # if defined(_FM8)
224         for(i = 0; i < 8; i++) set_dpalette(i, i);
225         multimode_accessmask = 0x00;
226         multimode_dispmask = 0x00;
227 # endif
228 #endif  
229         //enter_display();
230         
231         if(nmi_event_id >= 0) cancel_event(this, nmi_event_id);
232         register_event(this, EVENT_FM7SUB_DISPLAY_NMI, 20000.0, true, &nmi_event_id); // NEXT CYCLE_
233         subcpu->write_signal(SIG_CPU_BUSREQ, 0, 1);
234         subcpu->reset();
235 }
236
237 void DISPLAY::update_config()
238 {
239         vram_wrote = true;
240 #if !defined(_FM8)
241         is_cyclesteal = ((config.dipswitch & FM7_DIPSW_CYCLESTEAL) != 0) ? true : false;
242 #endif  
243         enter_display();
244 }
245
246 /*
247  * Vram accessing functions moved to vram.cpp .
248  */
249
250 void DISPLAY::do_irq(bool flag)
251 {
252         subcpu->write_signal(SIG_CPU_IRQ, flag ? 1: 0, 1);
253 }
254
255 void DISPLAY::do_firq(bool flag)
256 {
257         subcpu->write_signal(SIG_CPU_FIRQ, flag ? 1: 0, 1);
258 }
259
260 void DISPLAY::do_nmi(bool flag)
261 {
262 #if defined(_FM77AV_VARIANTS)
263         if(!nmi_enable) flag = false;
264 #endif
265         subcpu->write_signal(SIG_CPU_NMI, flag ? 1 : 0, 1);
266 }
267
268 void DISPLAY::set_multimode(uint8_t val)
269 {
270 #if !defined(_FM8)      
271         multimode_accessmask = val & 0x07;
272         multimode_dispmask = (val & 0x70) >> 4;
273         vram_wrote = true;
274 # if defined(_FM77AV_VARIANTS)
275         alu->write_signal(SIG_ALU_MULTIPAGE, multimode_accessmask, 0x07);
276 # endif
277 #endif  
278 }
279
280 uint8_t DISPLAY::get_multimode(void)
281 {
282 #if defined(_FM8)
283         return 0xff;
284 #else
285         uint8_t val;
286         val = multimode_accessmask & 0x07;
287         val |= ((multimode_dispmask << 4) & 0x70);
288         val |= 0x80;
289         return val;
290 #endif  
291 }
292
293 uint8_t DISPLAY::get_cpuaccessmask(void)
294 {
295         return multimode_accessmask & 0x07;
296 }
297
298 void DISPLAY::set_dpalette(uint32_t addr, uint8_t val)
299 {
300         scrntype_t r, g, b;
301         addr &= 7;
302         dpalette_data[addr] = val | 0xf8; //0b11111000;
303         b =  ((val & 0x01) != 0x00)? 255 : 0x00;
304         r =  ((val & 0x02) != 0x00)? 255 : 0x00;
305         g =  ((val & 0x04) != 0x00)? 255 : 0x00;
306         
307         dpalette_pixel[addr] = RGB_COLOR(r, g, b);
308         palette_changed = true;
309 }
310
311 uint8_t DISPLAY::get_dpalette(uint32_t addr)
312 {
313 #if defined(_FM8)
314         return 0xff;
315 #else
316         uint8_t data;
317         addr = addr & 7;
318         
319         data = dpalette_data[addr];
320         return data;
321 #endif
322 }
323
324 void DISPLAY::halt_subcpu(void)
325 {
326         subcpu->write_signal(SIG_CPU_BUSREQ, 0x01, 0x01);
327 }
328
329 void DISPLAY::go_subcpu(void)
330 {
331         subcpu->write_signal(SIG_CPU_BUSREQ, 0x00, 0x01);
332 }
333
334 void DISPLAY::enter_display(void)
335 {
336         uint32_t subclock;
337         if(clock_fast) {
338                 subclock = SUBCLOCK_NORMAL;
339         } else {
340                 subclock = SUBCLOCK_SLOW;
341         }
342         if(!is_cyclesteal && vram_accessflag) {
343                 subclock = subclock / 3;
344         }
345         if(prev_clock != subclock) p_vm->set_cpu_clock(subcpu, subclock);
346         prev_clock = subclock;
347 }
348
349 void DISPLAY::leave_display(void)
350 {
351 }
352
353 void DISPLAY::halt_subsystem(void)
354 {
355         halt_flag = false;
356         halt_subcpu();
357 }
358
359 void DISPLAY::restart_subsystem(void)
360 {
361         halt_flag = false;
362 #if defined(_FM77AV_VARIANTS)
363         if(subcpu_resetreq) {
364                 firq_mask = (mainio->read_signal(FM7_MAINIO_KEYBOARDIRQ_MASK) != 0) ? false : true;
365                 reset_cpuonly();
366                 power_on_reset = true;
367                 subcpu->write_signal(SIG_CPU_BUSREQ, 0, 1);
368                 subcpu->reset();
369                 do_firq(!firq_mask && key_firq_req);
370         }
371 #endif
372         go_subcpu();
373 }
374
375 //SUB:D408:R
376 void DISPLAY::set_crtflag(void)
377 {
378         crt_flag = true;
379         vram_wrote = true;
380 }
381
382 //SUB:D408:W
383 void DISPLAY::reset_crtflag(void)
384 {
385         crt_flag = false;
386         vram_wrote = true;
387 }
388
389 //SUB:D402:R
390 uint8_t DISPLAY::acknowledge_irq(void)
391 {
392         cancel_request = false;
393         do_irq(false);
394         return 0xff;
395 }
396
397 //SUB:D403:R
398 uint8_t DISPLAY::beep(void)
399 {
400         mainio->write_signal(FM7_MAINIO_BEEP, 0x01, 0x01);
401         return 0xff; // True?
402 }
403
404
405 // SUB:D404 : R 
406 uint8_t DISPLAY::attention_irq(void)
407 {
408         mainio->write_signal(FM7_MAINIO_SUB_ATTENTION, 0x01, 0x01);
409         return 0xff;
410 }
411
412 // SUB:D405:W
413 void DISPLAY::set_cyclesteal(uint8_t val)
414 {
415 #if !defined(_FM8)
416 # if defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)       
417         vram_wrote = true;
418         val &= 0x01;
419         if(val == 0) {
420                 is_cyclesteal = true;
421         } else {
422                 is_cyclesteal = false;
423         }
424         enter_display();
425 # endif 
426 #endif
427 }
428
429 //SUB:D409:R
430 uint8_t DISPLAY::set_vramaccess(void)
431 {
432         vram_accessflag = true;
433         return 0xff;
434 }
435
436 //SUB:D409:W
437 void DISPLAY::reset_vramaccess(void)
438 {
439         vram_accessflag = false;
440 }
441
442 //SUB:D40A:R
443 uint8_t DISPLAY::reset_subbusy(void)
444 {
445         sub_busy = false;
446         return 0xff;
447 }
448
449 //SUB:D40A:W
450 void DISPLAY::set_subbusy(void)
451 {
452         sub_busy = true;
453 }
454
455
456 #if defined(_FM77AV_VARIANTS)
457 // D410
458 void DISPLAY::alu_write_cmdreg(uint32_t val)
459 {
460         alu->write_data8(ALU_CMDREG, val);
461         if((val & 0x80) != 0) {
462                 use_alu = true;
463         } else {
464                 use_alu = false;
465         }
466 }
467
468 // D411
469 void DISPLAY::alu_write_logical_color(uint8_t val)
470 {
471         uint32_t data = (uint32_t)val;
472         alu->write_data8(ALU_LOGICAL_COLOR, data);
473 }
474
475 // D412
476 void DISPLAY::alu_write_mask_reg(uint8_t val)
477 {
478         uint32_t data = (uint32_t)val;
479         alu->write_data8(ALU_WRITE_MASKREG, data);
480 }
481
482 // D413 - D41A
483 void DISPLAY::alu_write_cmpdata_reg(int addr, uint8_t val)
484 {
485         uint32_t data = (uint32_t)val;
486         addr = addr & 7;
487         alu->write_data8(ALU_CMPDATA_REG + addr, data);
488 }
489
490 // D41B
491 void DISPLAY::alu_write_disable_reg(uint8_t val)
492 {
493         uint32_t data = (uint32_t)val;
494         alu->write_data8(ALU_BANK_DISABLE, data);
495 }
496
497 // D41C - D41F
498 void DISPLAY::alu_write_tilepaint_data(uint32_t addr, uint8_t val)
499 {
500         uint32_t data = (uint32_t)val;
501         switch(addr & 3) {
502                 case 0: // $D41C
503                         alu->write_data8(ALU_TILEPAINT_B, data);
504                         break;
505                 case 1: // $D41D
506                         alu->write_data8(ALU_TILEPAINT_R, data);
507                         break;
508                 case 2: // $D41E
509                         alu->write_data8(ALU_TILEPAINT_G, data);
510                         break;
511                 case 3: // xxxx
512                         //alu->write_data8(ALU_TILEPAINT_L, 0xff);
513                         break;
514         }
515 }
516
517 // D420
518 void DISPLAY::alu_write_offsetreg_hi(uint8_t val)
519 {
520         alu->write_data8(ALU_OFFSET_REG_HIGH, val & 0x7f);
521 }
522  
523 // D421
524 void DISPLAY::alu_write_offsetreg_lo(uint8_t val)
525 {
526         alu->write_data8(ALU_OFFSET_REG_LO, val);
527 }
528
529 // D422
530 void DISPLAY::alu_write_linepattern_hi(uint8_t val)
531 {
532         alu->write_data8(ALU_LINEPATTERN_REG_HIGH, val);
533 }
534
535 // D423
536 void DISPLAY::alu_write_linepattern_lo(uint8_t val)
537 {
538         alu->write_data8(ALU_LINEPATTERN_REG_LO, val);
539 }
540
541 // D424-D42B
542 void DISPLAY::alu_write_line_position(int addr, uint8_t val)
543 {
544         uint32_t data = (uint32_t)val;
545         switch(addr) {
546                 case 0:  
547                         alu->write_data8(ALU_LINEPOS_START_X_HIGH, data & 0x03); 
548                         break;
549                 case 1:  
550                         alu->write_data8(ALU_LINEPOS_START_X_LOW, data); 
551                         break;
552                 case 2:  
553                         alu->write_data8(ALU_LINEPOS_START_Y_HIGH, data & 0x01); 
554                         break;
555                 case 3:  
556                         alu->write_data8(ALU_LINEPOS_START_Y_LOW, data); 
557                         break;
558                 case 4:  
559                         alu->write_data8(ALU_LINEPOS_END_X_HIGH, data & 0x03); 
560                         break;
561                 case 5:  
562                         alu->write_data8(ALU_LINEPOS_END_X_LOW, data); 
563                         break;
564                 case 6:  
565                         alu->write_data8(ALU_LINEPOS_END_Y_HIGH, data & 0x01); 
566                         break;
567                 case 7:  
568                         alu->write_data8(ALU_LINEPOS_END_Y_LOW, data);
569                         break;
570         }
571 }
572
573 //SUB:D430:R
574 uint8_t DISPLAY::get_miscreg(void)
575 {
576         uint8_t ret;
577
578         ret = 0x6a;
579         if(!hblank) ret |= 0x80;
580         if(vsync) ret |= 0x04;
581         if(alu->read_signal(SIG_ALU_BUSYSTAT) == 0) ret |= 0x10;
582         if(power_on_reset) ret |= 0x01;
583         return ret;
584 }
585
586 //SUB:D430:W
587 void DISPLAY::set_miscreg(uint8_t val)
588 {
589         int old_display_page = display_page;
590
591         nmi_enable = ((val & 0x80) == 0) ? true : false;
592         if(!nmi_enable) do_nmi(false);
593
594         if((val & 0x40) == 0) {
595                 display_page = 0;
596         } else {
597                 display_page = 1;
598         }
599         if(display_page != old_display_page) {
600                         vram_wrote = true;
601         }
602         active_page = ((val & 0x20) == 0) ? 0 : 1;
603         if((val & 0x04) == 0) {
604                 offset_77av = false;
605         } else {
606                 offset_77av = true;
607         }
608         cgrom_bank = val & 0x03;
609 }
610
611 // Main: FD13
612 void DISPLAY::set_monitor_bank(uint8_t var)
613 {
614 # if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX)
615         if((var & 0x04) != 0){
616                 monitor_ram = true;
617         } else {
618                 monitor_ram = false;
619         }
620 # endif
621         subrom_bank = var & 0x03;
622         vram_wrote = true;
623         if(!halt_flag) {
624                 subcpu_resetreq = false;
625                 power_on_reset = true;
626                 firq_mask = (mainio->read_signal(FM7_MAINIO_KEYBOARDIRQ_MASK) != 0) ? false : true;
627                 reset_cpuonly();
628                 subcpu->write_signal(SIG_CPU_BUSREQ, 0, 1);
629                 subcpu->reset();
630                 do_firq(!firq_mask && key_firq_req);
631         } else {
632                 subcpu_resetreq = true;
633         }
634 }
635
636
637 // FD30
638 void DISPLAY::set_apalette_index_hi(uint8_t val)
639 {
640         apalette_index.b.h = val & 0x0f;
641 }
642
643 // FD31
644 void DISPLAY::set_apalette_index_lo(uint8_t val)
645 {
646         apalette_index.b.l = val;
647 }
648
649 void DISPLAY::calc_apalette(uint16_t idx)
650 {
651         uint8_t r, g, b;
652         idx = idx & 4095;
653         g = analog_palette_g[idx];
654         r = analog_palette_r[idx];
655         b = analog_palette_b[idx];
656         if(g != 0) g |= 0x0f; 
657         if(r != 0) r |= 0x0f; 
658         if(b != 0) b |= 0x0f; 
659         analog_palette_pixel[idx] = RGB_COLOR(r, g, b);
660 }
661
662 // FD32
663 void DISPLAY::set_apalette_b(uint8_t val)
664 {
665         uint16_t index;
666         uint8_t tmp;
667         index = apalette_index.w.l;
668         tmp = (val & 0x0f) << 4;
669         if(analog_palette_b[index] != tmp) {
670                 analog_palette_b[index] = tmp;
671                 calc_apalette(index);
672                 palette_changed = true;
673         }
674 }
675
676 // FD33
677 void DISPLAY::set_apalette_r(uint8_t val)
678 {
679         uint16_t index;
680         uint8_t tmp;
681         index = apalette_index.w.l;
682         tmp = (val & 0x0f) << 4;
683         if(analog_palette_r[index] != tmp) {
684                 analog_palette_r[index] = tmp;
685                 calc_apalette(index);
686                 palette_changed = true;
687         }
688 }
689
690 // FD34
691 void DISPLAY::set_apalette_g(uint8_t val)
692 {
693         uint16_t index;
694         uint8_t tmp;
695         index = apalette_index.w.l;
696         tmp = (val & 0x0f) << 4;
697         if(analog_palette_g[index] != tmp) {
698                 analog_palette_g[index] = tmp;
699                 calc_apalette(index);
700                 palette_changed = true;
701         }
702 }
703
704 #endif // _FM77AV_VARIANTS
705
706
707 void DISPLAY::copy_vram_blank_area(void)
708 {
709 }
710
711 void DISPLAY::copy_vram_per_line(void)
712 {
713         uint32_t src_offset;
714         uint32_t yoff_d1;
715         uint32_t yoff_d2;
716         uint32_t yoff_d;
717         uint32_t poff = 0;
718         uint32_t src_base;
719         int pages = 1;
720         uint32_t src_offset_d1;
721         uint32_t src_offset_d2;
722         uint32_t src_offset_d;
723         uint32_t bytes_d1;
724         uint32_t bytes_d2;
725         uint32_t bytes_d;
726
727         uint32_t addr_d1, addr_d2;
728         
729         int i, j, k;
730         //int dline = (int)displine - 1;
731         int dline = (int)displine;
732
733         if(dline < 0) return;
734         if(display_mode == DISPLAY_MODE_8_400L) {
735                 if(dline >= 400) return;
736         } else {
737                 if(dline >= 200) return;
738         }
739 #if defined(_FM77AV_VARIANTS)
740         yoff_d1 = offset_point;
741         yoff_d2 = offset_point_bank1;
742         if(display_mode == DISPLAY_MODE_4096) {
743                 src_offset = dline * 40;
744 #if defined(_FM77AV40EX) || defined(_FM77AV40SX)
745                 pages = 2;
746 #endif
747                 addr_d1 = (src_offset + yoff_d1) & 0x1fff;
748                 addr_d2 = (src_offset + yoff_d2) & 0x1fff;
749                 bytes_d1 = 0x2000 - addr_d1;
750                 bytes_d2 = 0x2000 - addr_d2;
751                 src_base = 0;
752                 for(k = 0; k < pages; k++) {
753                         for(i = 0; i < 3; i++) {
754                                 for(j = 0; j < 2; j++) {
755                                         uint32_t _addr_base = src_base + src_offset + poff;
756                                         if(bytes_d1 < 40) {
757                                                 memcpy(&gvram_shadow[_addr_base],
758                                                            &gvram[addr_d1 + src_base + poff],
759                                                            bytes_d1);
760                                                 memcpy(&gvram_shadow[_addr_base + bytes_d1],
761                                                            &gvram[src_base + poff],
762                                                            40 - bytes_d1);
763                                         } else {
764                                                 memcpy(&gvram_shadow[_addr_base],
765                                                            &gvram[addr_d1 + src_base + poff],
766                                                            40);
767                                         }
768                                         _addr_base += 0xc000;
769                                         if(bytes_d2 < 40) {
770                                                 memcpy(&gvram_shadow[_addr_base],
771                                                            &gvram[addr_d2 + src_base + poff + 0xc000],
772                                                            bytes_d2);
773                                                 memcpy(&gvram_shadow[_addr_base + bytes_d2],
774                                                            &gvram[src_base + poff + 0xc000],
775                                                            40 - bytes_d2);
776                                         } else {
777                                                 memcpy(&gvram_shadow[_addr_base],
778                                                            &gvram[addr_d2 + src_base + poff + 0xc000],
779                                                            40);
780                                         }
781                                         src_base += 0x2000;
782                                 }
783                                 src_base = (i + 1) * 0x4000;
784                         }
785                         poff += 0x18000;
786                 }
787                 vram_draw_table[dline] = true;
788                 vram_wrote_table[dline] = false;
789         }
790 # if defined(_FM77AV40EX) || defined(_FM77AV40SX) || defined(_FM77AV40)
791         else if(display_mode == DISPLAY_MODE_256k) {
792                 src_offset = dline * 40;
793                 
794 #if defined(_FM77AV40EX) || defined(_FM77AV40SX)
795                 pages = 4;
796 #elif defined(_FM77AV40)
797                 pages = 3;
798 #else
799                 pages = 0;
800 #endif
801                 src_offset_d1 = (src_offset + yoff_d1) & 0x1fff;
802                 src_offset_d2 = (src_offset + yoff_d2) & 0x1fff;
803                 bytes_d1 = 0x2000 - ((src_offset + yoff_d1) & 0x1fff);
804                 bytes_d2 = 0x2000 - ((src_offset + yoff_d2) & 0x1fff);
805                 for(k = 0; k < pages; k++) {
806                         for(i = 0; i < 3; i++) {
807                                 for(j = 0; j < 2; j++) {
808                                         if((k & 1) == 0) {
809                                                 src_base = i * 0x4000 + j * 0x2000 + k *  0xc000;
810                                                 src_offset_d = src_offset_d1;
811                                                 bytes_d = bytes_d1;
812                                         } else {
813                                                 src_base = i * 0x4000 + j * 0x2000 + k *  0xc000;
814                                                 src_offset_d = src_offset_d2;
815                                                 bytes_d = bytes_d2;
816                                         }                                               
817                                         if(bytes_d < 40) {
818                                                 memcpy(&gvram_shadow[src_offset + src_base],
819                                                            &gvram[src_offset_d + src_base],
820                                                            bytes_d);
821                                                 memcpy(&gvram_shadow[src_offset + bytes_d + src_base],
822                                                            &gvram[src_base],
823                                                            40 - bytes_d);
824                                         } else {
825                                                 memcpy(&gvram_shadow[src_offset + src_base],
826                                                            &gvram[src_offset_d + src_base],
827                                                            40);
828                                         }
829                                 }
830                         }
831                 }
832                 vram_draw_table[dline] = true;
833                 vram_wrote_table[dline] = false;
834         }
835         else if(display_mode == DISPLAY_MODE_8_400L) {
836                 src_offset = dline * 80;
837 # if defined(_FM77AV40EX) || defined(_FM77AV40SX)
838                 pages = 2;
839 # elif defined(_FM77AV40)
840                 pages = 1;
841 #endif
842                 if(display_page_bak == 1) { // Is this dirty?
843                         yoff_d = yoff_d2;
844                 } else {
845                         yoff_d = yoff_d1;
846                 }
847                 yoff_d = (yoff_d << 1) & 0x7fff;
848                 src_offset_d = (src_offset + yoff_d) & 0x7fff;
849                 bytes_d = 0x8000 - ((src_offset + yoff_d) & 0x7fff);
850                 for(i = 0; i < pages; i++) {
851                         for(j = 0; j < 3; j++) {
852                                 src_base = i * 0x18000 + j * 0x8000;
853                                 if(bytes_d < 80) {
854                                         memcpy(&gvram_shadow[src_offset + src_base],
855                                                    &gvram[src_offset_d + src_base],
856                                                    bytes_d);
857                                         memcpy(&gvram_shadow[src_offset + bytes_d + src_base],
858                                                    &gvram[src_base],
859                                                    80 - bytes_d);
860                                 } else {
861                                         memcpy(&gvram_shadow[src_offset + src_base + poff],
862                                                    &gvram[src_offset_d + src_base],
863                                                    80);
864                                 }
865                         }
866                 }
867                 vram_draw_table[dline] = true;
868                 vram_wrote_table[dline] = false;
869         }
870 #endif  
871         else { // 200line
872                 src_offset = dline * 80;
873 # if defined(_FM77AV40EX) || defined(_FM77AV40SX)
874                 pages = 4;
875 #elif defined(_FM77AV40)
876                 pages = 3;
877 #elif defined(_FM77AV_VARIANTS)
878                 pages = 2;
879 #else
880                 pages = 1;
881 #endif
882                 poff = 0;
883                 src_offset_d1 = (src_offset + yoff_d1) & 0x3fff;
884                 src_offset_d2 = (src_offset + yoff_d2) & 0x3fff;
885                 bytes_d1 = 0x4000 - ((src_offset + yoff_d1) & 0x3fff);
886                 bytes_d2 = 0x4000 - ((src_offset + yoff_d2) & 0x3fff);
887                 for(i = 0; i < pages; i++) {
888                         if((i & 1) == 0) {
889                                 src_offset_d = src_offset_d1;
890                                 bytes_d = bytes_d1;
891                         } else {
892                                 src_offset_d = src_offset_d2;
893                                 bytes_d = bytes_d2;
894                         }
895                         src_base = 0;
896                         for(j = 0; j < 3; j++) {
897                                 if(bytes_d < 80) {
898                                         memcpy(&gvram_shadow[src_offset + src_base + poff],
899                                                    &gvram[src_offset_d + src_base + poff],
900                                                    bytes_d);
901                                         memcpy(&gvram_shadow[src_offset + bytes_d + src_base + poff],
902                                                    &gvram[src_base + poff],
903                                                    80 - bytes_d);
904                                 } else {
905                                         memcpy(&gvram_shadow[src_offset + src_base + poff],
906                                                    &gvram[src_offset_d + src_base + poff],
907                                                    80);
908                                 }
909                                 src_base += 0x4000;
910                         }
911                         poff += 0xc000;
912                 }
913                 vram_draw_table[dline] = true;
914                 vram_wrote_table[dline] = false;
915         }
916 #else // FM-8/7/77
917         { // 200line
918                 src_offset = dline * 80;
919                 pages = 1;
920                 poff = 0;
921                 yoff_d = offset_point;
922                 src_offset_d = (src_offset + yoff_d) & 0x3fff;
923                 bytes_d = 0x4000 - ((src_offset + yoff_d) & 0x3fff);
924                 for(j = 0; j < 3; j++) {
925                         src_base = j * 0x4000;
926                         if(bytes_d < 80) {
927                                 memcpy(&gvram_shadow[src_offset + src_base + poff],
928                                            &gvram[src_offset_d + src_base + poff],
929                                            bytes_d);
930                                 memcpy(&gvram_shadow[src_offset + bytes_d + src_base + poff],
931                                            &gvram[src_base + poff],
932                                            80 - bytes_d);
933                         } else {
934                                 memcpy(&gvram_shadow[src_offset + src_base + poff],
935                                            &gvram[src_offset_d + src_base + poff],
936                                            80);
937                         }
938                 }
939                 vram_draw_table[dline] = true;
940                 vram_wrote_table[dline] = false;
941         }
942
943 #endif
944 }
945
946 void DISPLAY::copy_vram_all()
947 {
948 #if defined(_FM77AV_VARIANTS)   
949         uint32_t yoff_d1 = offset_point;
950         uint32_t yoff_d2 = offset_point_bank1;
951         uint32_t src_offset_1, src_offset_2;
952         uint32_t poff = 0;
953         if(display_mode == DISPLAY_MODE_4096) {
954 #if defined(_FM77AV40EX) || defined(_FM77AV40SX)
955                 int pages = 2;
956 #else
957                 int pages = 1;
958 #endif
959                 uint32_t bytes_d1 = 0x2000 - (yoff_d1 & 0x1fff);
960                 uint32_t bytes_d2 = 0x2000 - (yoff_d2 & 0x1fff);
961                 for(int k = 0; k < pages; k++) {
962                         for(int i = 0; i < 3; i++) {
963                                 for(int j = 0; j < 2; j++) {
964                                         src_offset_1 = i * 0x4000 + j * 0x2000;
965                                         src_offset_2 = src_offset_1 + 0xc000;
966                                         memcpy(&gvram_shadow[src_offset_1 + poff], &gvram[src_offset_1 + (yoff_d1 & 0x1fff) + poff], bytes_d1);
967                                         memcpy(&gvram_shadow[src_offset_1 + bytes_d1 + poff], &gvram[src_offset_1 + poff], 0x2000 - bytes_d1);
968                                         memcpy(&gvram_shadow[src_offset_2 + poff], &gvram[src_offset_2 + (yoff_d2 & 0x1fff) + poff], bytes_d2);
969                                         memcpy(&gvram_shadow[src_offset_2 + bytes_d2 + poff], &gvram[src_offset_2 + poff], 0x2000 - bytes_d2);
970                                 }
971                         }
972                         poff += 0x18000;
973                 }
974         }
975 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX)
976         else if(display_mode == DISPLAY_MODE_256k) {
977                 uint32_t bytes_d1 = 0x2000 - (yoff_d1 & 0x1fff);
978                 uint32_t bytes_d2 = 0x2000 - (yoff_d2 & 0x1fff);
979                 for(int i = 0; i < 3; i++) {
980                         for(int j = 0; j < 2; j++) {
981                                 src_offset_1 = i * 0x4000 + j * 0x2000;
982                                 src_offset_2 = src_offset_1 + 0xc000;
983                                 memcpy(&gvram_shadow[src_offset_1 + poff], &gvram[src_offset_1 + (yoff_d1 & 0x1fff) + poff], bytes_d1);
984                                 memcpy(&gvram_shadow[src_offset_1 + bytes_d1 + poff], &gvram[src_offset_1 + poff], 0x2000 - bytes_d1);
985                                 memcpy(&gvram_shadow[src_offset_2 + poff], &gvram[src_offset_2 + (yoff_d2 & 0x1fff) + poff], bytes_d2);
986                                 memcpy(&gvram_shadow[src_offset_2 + bytes_d2 + poff], &gvram[src_offset_2 + poff], 0x2000 - bytes_d2);
987                         }
988                 }
989                 poff += 0x18000;
990                 for(int i = 0; i < 3; i++) {
991                         for(int j = 0; j < 2; j++) {
992                                 src_offset_1 = i * 0x4000 + j * 0x2000;
993                                 memcpy(&gvram_shadow[src_offset_1 + poff], &gvram[src_offset_1 + (yoff_d1 & 0x1fff) + poff], bytes_d1);
994                                 memcpy(&gvram_shadow[src_offset_1 + bytes_d1 + poff], &gvram[src_offset_1 + poff], 0x2000 - bytes_d1);
995                         }
996                 }
997         } else if(display_mode == DISPLAY_MODE_8_400L) {
998 #if defined(_FM77AV40EX) || defined(_FM77AV40SX)
999                 int pages = 2;
1000 #else
1001                 int pages = 1;
1002 #endif
1003                 uint32_t yoff_d;
1004                 uint32_t bytes_d;
1005                 
1006                 if(display_page_bak == 1) { // Is this dirty?
1007                         yoff_d = yoff_d2;
1008                 } else {
1009                         yoff_d = yoff_d1;
1010                 }
1011                 yoff_d = (yoff_d << 1) & 0x7fff;
1012                 bytes_d = 0x8000 - yoff_d;
1013                 for(int k = 0; k < pages; k++) {
1014                         for(int i = 0; i < 3; i++) {
1015                                 src_offset_1 = i * 0x8000;
1016                                 memcpy(&gvram_shadow[src_offset_1 + poff], &gvram[src_offset_1 + yoff_d + poff], bytes_d);
1017                                 memcpy(&gvram_shadow[src_offset_1 + bytes_d + poff], &gvram[src_offset_1 + poff], 0x8000 - bytes_d);
1018                         }
1019                         poff += 0x18000;
1020                 }
1021         }
1022 #endif  
1023     else { // 200line
1024 #if defined(_FM77AV40EX) || defined(_FM77AV40SX)
1025                 int pages = 4;
1026 #elif defined(_FM77AV40)
1027                 int pages = 3;
1028 #else
1029                 int pages = 2;
1030 #endif
1031                 uint32_t bytes_d1 = 0x4000 - (yoff_d1 & 0x3fff);
1032                 uint32_t bytes_d2 = 0x4000 - (yoff_d2 & 0x3fff);
1033                 uint32_t yoff_d, bytes_d;
1034                 for(int k = 0; k < pages; k++) {
1035                         yoff_d = ((k & 1) == 0) ? (yoff_d1 & 0x3fff) : (yoff_d2 & 0x3fff);
1036                         bytes_d = ((k & 1) == 0) ? bytes_d1 : bytes_d2;
1037                         for(int j = 0; j < 3; j++) {
1038                                 src_offset_1 = k * 0xc000 + j * 0x4000;
1039                                 memcpy(&gvram_shadow[src_offset_1], &gvram[src_offset_1 + yoff_d], bytes_d);
1040                                 memcpy(&gvram_shadow[src_offset_1 + bytes_d], &gvram[src_offset_1], 0x4000 - bytes_d);
1041                         }
1042                 }
1043         }
1044 #else // FM-8/7/77
1045     { // 200line
1046                 uint32_t yoff_d = offset_point & 0x3fff;
1047                 uint32_t bytes_d = 0x4000 - (offset_point & 0x3fff);
1048                 uint32_t src_offset_1;
1049                 for(int j = 0; j < 3; j++) {
1050                         src_offset_1 = j * 0x4000;
1051                         memcpy(&gvram_shadow[src_offset_1], &gvram[src_offset_1 + yoff_d], bytes_d);
1052                         memcpy(&gvram_shadow[src_offset_1 + bytes_d], &gvram[src_offset_1], 0x4000 - bytes_d);
1053                 }
1054         }
1055 #endif
1056 }
1057
1058 // Timing values from XM7 . Thanks Ryu.
1059 void DISPLAY::event_callback(int event_id, int err)
1060 {
1061         double usec;
1062         bool f;
1063         switch(event_id) {
1064                 case EVENT_FM7SUB_DISPLAY_NMI: // per 20.00ms
1065 #if defined(_FM77AV_VARIANTS)
1066                         if(nmi_enable) {
1067                                 do_nmi(true);
1068                         } else {
1069                                 //do_nmi(false);
1070                         }
1071 #else
1072                         do_nmi(true);
1073 #endif
1074                         break;
1075                 case EVENT_FM7SUB_DISPLAY_NMI_OFF: // per 20.00ms
1076                         do_nmi(false);
1077                         break;
1078 #if defined(_FM77AV_VARIANTS) || defined(_FM77L4)
1079                 case EVENT_FM7SUB_HDISP:
1080                         hblank = false;
1081                         f = false;
1082                         mainio->write_signal(SIG_DISPLAY_DISPLAY, 0x02, 0xff);
1083                         if(displine == 0) {
1084                                 if(display_mode == DISPLAY_MODE_8_400L) {
1085                                         register_event(this, EVENT_FM7SUB_HDISP, 30.0 + 11.0, true, &hdisp_event_id);
1086                                         register_event(this, EVENT_FM7SUB_HBLANK, 30.0, false, &hblank_event_id); // NEXT CYCLE_
1087                                 } else {
1088                                         register_event(this, EVENT_FM7SUB_HDISP, 39.5 + 24.0, true, &hdisp_event_id);
1089                                         register_event(this, EVENT_FM7SUB_HBLANK, 39.5, false, &hblank_event_id); // NEXT CYCLE_
1090                                 }
1091                         }
1092                         if(display_mode == DISPLAY_MODE_8_400L) {
1093                                 if(displine < 400) f = true;
1094                         } else {
1095                                 if(displine < 200) f = true;
1096                         }
1097                         if(f) {
1098                                 if((config.dipswitch & FM7_DIPSW_SYNC_TO_HSYNC) != 0) {
1099                                         if((vram_wrote_table[displine] || vram_wrote) && need_transfer_line/*|| vram_wrote */) copy_vram_per_line();
1100                                 }
1101                                 vsync = false;
1102                                 vblank = false;
1103                                 enter_display();
1104                         }
1105                         f = false;
1106                         break;
1107                 case EVENT_FM7SUB_HBLANK:
1108                         hblank = true;
1109                         mainio->write_signal(SIG_DISPLAY_DISPLAY, 0x00, 0xff);
1110                         f = false;
1111                         if(displine == 0) {
1112                                 if(display_mode == DISPLAY_MODE_8_400L) {
1113                                         usec = 30.0 + 11.0;
1114                                 } else {
1115                                         usec = 39.5 + 24.0;
1116                                 }
1117                                 register_event(this, EVENT_FM7SUB_HBLANK, usec, true, &hblank_event_id); // NEXT CYCLE_
1118                         }
1119                         displine++;
1120                         if(display_mode == DISPLAY_MODE_8_400L) {
1121                                 if((displine < 400)) f = true;
1122                         } else {
1123                                 if((displine < 200)) f = true;
1124                         }
1125                         if(!f && (hdisp_event_id >= 0)) {
1126                                 cancel_event(this, hdisp_event_id);
1127                                 cancel_event(this, hblank_event_id);
1128                                 hdisp_event_id = -1;
1129                                 hblank_event_id = -1;
1130                         }
1131                         //displine++;
1132                         break;
1133                 case EVENT_FM7SUB_VSTART: // Call first.
1134                         vblank = true;
1135                         vsync = false;
1136                         hblank = false;
1137                         displine = 0;
1138                         display_page_bak = display_page;
1139                         // Parameter from XM7/VM/display.c , thanks, Ryu.
1140                         mainio->write_signal(SIG_DISPLAY_DISPLAY, 0x00, 0xff);
1141                         mainio->write_signal(SIG_DISPLAY_VSYNC, 0x00, 0xff);
1142                         if(vblank_count != 0) {
1143                                 if(display_mode == DISPLAY_MODE_8_400L) {
1144                                         usec = (0.98 + 16.4) * 1000.0;
1145                                 } else {
1146                                         usec = (1.91 + 12.7) * 1000.0;
1147                                 }
1148                                 register_event(this, EVENT_FM7SUB_VSYNC, usec, false, &vsync_event_id);
1149
1150                                 if(display_mode == DISPLAY_MODE_8_400L) {
1151                                         usec = 930.0; // 939.0
1152                                 } else {
1153                                         usec = 1840.0; // 1846.5
1154                                 }
1155                                 register_event(this, EVENT_FM7SUB_HDISP, usec, false, &hdisp_event_id); // NEXT CYCLE_
1156                                 vblank_count = 0;
1157                                 return;
1158                         } else {
1159                                 if(display_mode == DISPLAY_MODE_8_400L) {
1160                                         usec = 0.34 * 1000.0;
1161                                 } else {
1162                                         usec = 1.52 * 1000.0;
1163                                 }
1164                                 register_event(this, EVENT_FM7SUB_VSTART, usec, false, &vstart_event_id); // NEXT CYCLE_
1165                                 vblank_count++;
1166                                 //break;
1167                         }
1168                         break;
1169         case EVENT_FM7SUB_VSYNC:
1170                 vblank = true;
1171                 hblank = false;
1172                 vsync = true;
1173                 write_access_page = (write_access_page + 1) & 1;
1174                 displine = 0;
1175                 if(display_mode == DISPLAY_MODE_8_400L) {
1176                         usec = 0.33 * 1000.0; 
1177                 } else {
1178                         usec = 0.51 * 1000.0;
1179                 }
1180                 mainio->write_signal(SIG_DISPLAY_VSYNC, 0x01, 0xff);
1181                 mainio->write_signal(SIG_DISPLAY_DISPLAY, 0x00, 0xff);
1182                 register_event(this, EVENT_FM7SUB_VSTART, usec, false, &vstart_event_id); // NEXT CYCLE_
1183                 if((config.dipswitch & FM7_DIPSW_SYNC_TO_HSYNC) == 0) {
1184                                 bool ff = false;
1185                                 if(!vram_wrote) {
1186                                         if(need_transfer_line) {
1187                                                 int lines = 200;
1188                                                 if(display_mode == DISPLAY_MODE_8_400L) lines = 400;
1189                                                 for(int yy = 0; yy < lines; yy++) {
1190                                                         if(vram_wrote_table[yy]) {
1191                                                                 vram_wrote_table[yy] = false;
1192                                                                 ff = true;
1193                                                         }
1194                                                 }
1195                                         }
1196                                 } else {
1197                                         if(need_transfer_line) ff = true;
1198                                 }
1199                                 if(ff) {
1200                                         for(int yy = 0; yy < 400; yy++) vram_draw_table[yy] = true;
1201                                         copy_vram_all();
1202                                         vram_wrote_shadow = true;
1203                                         screen_update_flag = true;
1204                                         vram_wrote = false;
1205                                 }
1206                 } else {
1207                         if(need_transfer_line) {
1208                                 if(vram_wrote) {
1209                                         for(int yy = 0; yy < 400; yy++) {
1210                                                 if(!vram_draw_table[yy]) {
1211                                                         displine = yy;
1212                                                         copy_vram_per_line();
1213                                                 }
1214                                         }
1215                                         displine = 0;
1216                                         vram_wrote = false;
1217                                 }
1218                         }
1219                         for(int yy = 0; yy < 400; yy++) {
1220                                 if(vram_draw_table[yy]) {
1221                                         vram_wrote_shadow = true;
1222                                         screen_update_flag = true;
1223                                         break;
1224                                 }
1225                         }
1226                         //vram_wrote = false;
1227                 }
1228                 frame_skip_count_transfer++;
1229                 {
1230                         uint32_t factor = ((config.dipswitch & FM7_DIPSW_FRAMESKIP) >> 28) & 3;
1231                         if((frame_skip_count_transfer > factor) /* || (vram_wrote) */) {
1232                                 frame_skip_count_transfer = 0;
1233                                 need_transfer_line = true;
1234                         } else {
1235                                 need_transfer_line = false;
1236                         }
1237                 }
1238                 break;
1239 #endif                  
1240         case EVENT_FM7SUB_CLR_BUSY:
1241                 set_subbusy();
1242                 break;
1243         case EVENT_FM7SUB_CLR_CRTFLAG:
1244                 reset_crtflag();
1245                 break;
1246         }
1247 }
1248
1249 void DISPLAY::event_frame()
1250 {
1251 #if !defined(_FM77AV_VARIANTS) && !defined(_FM77L4)
1252         int yy;
1253         bool f = false;
1254         if(need_transfer_line && vram_wrote) {
1255                 for(yy = 0; yy < 400; yy++) {
1256                         if(!vram_draw_table[yy]) {
1257                                 displine = yy;
1258                                 copy_vram_per_line();
1259                         }
1260                 }
1261                 vram_wrote = false;
1262                 displine = 0;
1263         }
1264         {
1265                 for(yy = 0; yy < 400; yy++) {
1266                         if(vram_draw_table[yy]) {
1267                                 f = true;
1268                                 break;
1269                         }
1270                 }
1271                 if(f) {
1272                         screen_update_flag = true;
1273                         vram_wrote_shadow = true;
1274                 }
1275         }
1276         enter_display();
1277         frame_skip_count_transfer++;
1278         {
1279                 uint32_t factor = (config.dipswitch & FM7_DIPSW_FRAMESKIP) >> 28;
1280                 if(frame_skip_count_transfer > factor) {
1281                         frame_skip_count_transfer = 0;
1282                         need_transfer_line = true;
1283                 } else {
1284                         need_transfer_line = false;
1285                         displine = 0;
1286                         //vram_wrote = false;
1287                 }
1288         }
1289         
1290 #endif  
1291 }
1292
1293 void DISPLAY::event_vline(int v, int clock)
1294 {
1295 #if !defined(_FM77AV_VARIANTS) && !defined(_FM77L4)
1296         if(need_transfer_line == false) return;
1297         displine = v;
1298         if(vram_wrote_table[displine] || vram_wrote) {
1299                 copy_vram_per_line();
1300         }               
1301         enter_display();
1302 #endif  
1303 }
1304
1305
1306 uint32_t DISPLAY::read_signal(int id)
1307 {
1308         uint32_t retval = 0;
1309         switch(id) {
1310                 case SIG_FM7_SUB_HALT:
1311                 case SIG_DISPLAY_HALT:
1312                         retval = (halt_flag) ? 0xffffffff : 0;
1313                         break;
1314                 case SIG_DISPLAY_BUSY:
1315                         retval =  (sub_busy) ? 0x80 : 0;
1316                         break;
1317                 case SIG_DISPLAY_MULTIPAGE:
1318                         retval =  multimode_accessmask;
1319                         break;
1320                 case SIG_DISPLAY_PLANES:
1321                         retval = 3;
1322                         break;
1323 #if defined(_FM77AV_VARIANTS)
1324                 case SIG_DISPLAY_VSYNC:
1325                         retval = (vsync) ? 0x01 : 0x00;
1326                         break;
1327                 case SIG_DISPLAY_DISPLAY:
1328                         retval = (!hblank) ? 0x02: 0x00;
1329                         break;
1330                 case SIG_FM7_SUB_BANK: // Main: FD13
1331                         retval = subrom_bank & 0x03;
1332 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX)
1333                         if(monitor_ram) retval |= 0x04;
1334 #endif
1335                         break;
1336 #endif                  
1337 #if defined(_FM77AV_VARIANTS)
1338                 case SIG_DISPLAY_MODE320:
1339                         retval = (mode320) ? 0x40: 0x00;
1340                         break;
1341 #endif
1342                 case SIG_DISPLAY_Y_HEIGHT:
1343 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX)
1344                         retval = (display_mode == DISPLAY_MODE_8_400L) ? 400 : 200;
1345 #else
1346                         retval = 200;
1347 #endif            
1348                         break;
1349                 case SIG_DISPLAY_X_WIDTH:
1350 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX)
1351                         retval = (mode320 || mode256k) ? 320 : 640;
1352 #elif defined(_FM77AV_VARIANTS)
1353                         retval = (mode320) ? 320 : 640;
1354 #else
1355                         retval = 640;
1356 #endif            
1357                         break;
1358                 default:
1359                         break;
1360         }
1361         return retval;
1362 }
1363
1364 void DISPLAY::write_signal(int id, uint32_t data, uint32_t mask)
1365 {
1366         bool flag = ((data & mask) != 0);
1367         int y;
1368         switch(id) {
1369                 case SIG_FM7_SUB_HALT:
1370                         if(flag) {
1371                                 sub_busy = true;
1372                         }
1373                         halt_flag = flag;
1374                         //mainio->write_signal(SIG_FM7_SUB_HALT, data, mask);
1375                         break;
1376                 case SIG_DISPLAY_HALT:
1377                         if(flag) {
1378                                 halt_subsystem();
1379                         } else {
1380                                 restart_subsystem();
1381                         }
1382                         break;
1383                 case SIG_FM7_SUB_CANCEL:
1384                         if(flag) {
1385                                 cancel_request = true;
1386                                 do_irq(true);
1387                         }
1388                         break;
1389                 case SIG_DISPLAY_CLOCK:
1390                         clock_fast = flag;
1391                         enter_display();
1392                         break;
1393 #if defined(_FM77AV_VARIANTS)
1394                 case SIG_FM7_SUB_BANK: // Main: FD13
1395                         set_monitor_bank(data & 0xff);
1396                         break;
1397 #endif                  
1398                 case SIG_DISPLAY_EXTRA_MODE: // FD04 bit 4, 3
1399 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX)
1400                         //printf("Wrote $FD04: %02x\n", data);
1401                         {
1402                                 int oldmode = display_mode;
1403                                 int mode;
1404                                 kanjisub = ((data & 0x20) == 0) ? true : false;
1405                                 mode256k = (((data & 0x10) != 0) && ((data & 0x08) != 0) ) ? true : false;
1406                                 mode400line = ((data & 0x08) == 0) ? true : false;
1407                                 ram_protect = ((data & 0x04) == 0) ? true : false;
1408                                 if(mode400line && !mode320) {
1409                                         display_mode = DISPLAY_MODE_8_400L;
1410                                 } else if(mode256k) {
1411                                         display_mode = DISPLAY_MODE_256k;
1412                                 } else {
1413                                         display_mode = (mode320) ? DISPLAY_MODE_4096 : DISPLAY_MODE_8_200L;
1414                                 }
1415                                 if(oldmode != display_mode) {
1416                                         scrntype_t *pp;
1417                                         if(mode320 || mode256k) {
1418                                                 emu->set_vm_screen_size(320, 200, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_WIDTH_ASPECT, WINDOW_HEIGHT_ASPECT);
1419                                                 for(y = 0; y < 200; y++) {
1420                                                         pp = emu->get_screen_buffer(y);
1421                                                         if(pp != NULL) memset(pp, 0x00, 320 * sizeof(scrntype_t));
1422                                                 }
1423                                         } else if(display_mode == DISPLAY_MODE_8_400L) {
1424                                                 emu->set_vm_screen_size(640, 400, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_WIDTH_ASPECT, WINDOW_HEIGHT_ASPECT);
1425                                                 for(y = 0; y < 400; y++) {
1426                                                         pp = emu->get_screen_buffer(y);
1427                                                         if(pp != NULL) memset(pp, 0x00, 640 * sizeof(scrntype_t));
1428                                                 }
1429                                         } else {
1430                                                 emu->set_vm_screen_size(640, 200, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_WIDTH_ASPECT, WINDOW_HEIGHT_ASPECT);
1431                                                 for(y = 0; y < 200; y++) {
1432                                                         pp = emu->get_screen_buffer(y);
1433                                                         if(pp != NULL) memset(pp, 0x00, 640 * sizeof(scrntype_t));
1434                                                 }
1435                                         }
1436                                         vram_wrote = true;
1437                                         alu->write_signal(SIG_ALU_X_WIDTH, (mode320 || mode256k) ? 40 :  80, 0xffff);
1438                                         alu->write_signal(SIG_ALU_Y_HEIGHT, (display_mode == DISPLAY_MODE_8_400L) ? 400 : 200, 0xffff);
1439                                         alu->write_signal(SIG_ALU_400LINE, (display_mode == DISPLAY_MODE_8_400L) ? 0xff : 0x00, 0xff);
1440                                         frame_skip_count_draw = 3;
1441                                         frame_skip_count_transfer = 3;
1442                                 }
1443                         }
1444 #elif defined(_FM77_VARIANTS)
1445                         {
1446                                 int oldmode = display_mode;
1447                                 kanjisub = ((data & 0x20) == 0) ? true : false;
1448 # if defined(_FM77L4)                           
1449                                 stat_400linecard = ((data & 0x20) != 0) ? true : false;
1450                                 mode400line = ((data & 0x08) != 0) ? false : true;
1451                                 if(mode400line && stat_400linecard) {
1452                                         display_mode = DISPLAY_MODE_8_400L_TEXT;
1453                                 } else if(stat_400linecard) {
1454                                         display_mode = DISPLAY_MODE_8_200L_TEXT;
1455                                 } else {
1456                                         display_mode = DISPLAY_MODE_8_200L;
1457                                 }
1458 # endif                         
1459                         }                       
1460 #endif
1461                         break;
1462 #if defined(_FM77AV_VARIANTS)
1463                 case SIG_DISPLAY_MODE320: // FD12 bit 6
1464 # if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX)
1465                         {
1466                                 //printf("Wrote $FD12: %02x\n", data);
1467                                 int oldmode = display_mode;
1468                                 mode320 = flag;
1469                                 if(!mode320 && !mode256k) {
1470                                         //display_mode = (mode400line) ? DISPLAY_MODE_8_400L : DISPLAY_MODE_8_200L;
1471                                         display_mode = DISPLAY_MODE_8_200L;
1472                                 } else {
1473                                         display_mode = (mode256k) ? DISPLAY_MODE_256k : DISPLAY_MODE_4096;
1474                                 }
1475                                 if(oldmode != display_mode) {
1476                                         scrntype_t *pp;
1477                                         if(mode320 || mode256k) {
1478                                                 emu->set_vm_screen_size(320, 200, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_WIDTH_ASPECT, WINDOW_HEIGHT_ASPECT);
1479                                                 for(y = 0; y < 200; y++) {
1480                                                         pp = emu->get_screen_buffer(y);
1481                                                         if(pp != NULL) memset(pp, 0x00, 320 * sizeof(scrntype_t));
1482                                                 }
1483                                         } else { // 200 lines, 8 colors.
1484                                                 emu->set_vm_screen_size(640, 200, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_WIDTH_ASPECT, WINDOW_HEIGHT_ASPECT);
1485                                                 for(y = 0; y < 200; y++) {
1486                                                         pp = emu->get_screen_buffer(y);
1487                                                         if(pp != NULL) memset(pp, 0x00, 640 * sizeof(scrntype_t));
1488                                                 }
1489                                         }
1490                                         vram_wrote = true;
1491                                         alu->write_signal(SIG_ALU_X_WIDTH, (mode320) ? 40 :  80, 0xffff);
1492                                         alu->write_signal(SIG_ALU_Y_HEIGHT, 200, 0xffff);
1493                                         alu->write_signal(SIG_ALU_400LINE, 0x00, 0xff);
1494                                         //frame_skip_count = 3;
1495                                 }
1496                         }
1497 # else
1498                         mode320 = flag;
1499                         {
1500                 
1501                                 if(mode320) {
1502                                         emu->set_vm_screen_size(320, 200, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_WIDTH_ASPECT, WINDOW_HEIGHT_ASPECT);
1503                                         for(y = 0; y < 200; y++) memset(emu->get_screen_buffer(y), 0x00, 320 * sizeof(scrntype_t));
1504                                 } else {
1505                                         emu->set_vm_screen_size(640, 200, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_WIDTH_ASPECT, WINDOW_HEIGHT_ASPECT);
1506                                         for(y = 0; y < 200; y++) memset(emu->get_screen_buffer(y), 0x00, 640 * sizeof(scrntype_t));
1507                                 }
1508                         }
1509                         display_mode = (mode320 == true) ? DISPLAY_MODE_4096 : DISPLAY_MODE_8_200L;
1510                         alu->write_signal(SIG_ALU_X_WIDTH, (mode320) ? 40 :  80, 0xffff);
1511                         alu->write_signal(SIG_ALU_Y_HEIGHT, 200, 0xffff);
1512                         alu->write_signal(SIG_ALU_400LINE, 0, 0xffffffff);
1513                         vram_wrote = true;
1514 # endif
1515 #endif                  
1516                         break;
1517                 case SIG_DISPLAY_MULTIPAGE:
1518                         set_multimode(data);
1519                         break;
1520                 case SIG_FM7_SUB_KEY_MASK:
1521                         if(firq_mask == flag) {
1522                                 do_firq(!flag && key_firq_req);
1523                         }
1524                         firq_mask = !flag;
1525                         break;
1526                 case SIG_FM7_SUB_KEY_FIRQ:
1527                         do_firq(flag & !(firq_mask));
1528                         key_firq_req = flag;
1529                         break;
1530                 case SIG_FM7_SUB_USE_CLR:
1531                         if(flag) {
1532                                 clr_count = data & 0x03;
1533                         } else {
1534                                 clr_count = 0;
1535                         }
1536                         break;
1537                 default:
1538                         break;
1539         }
1540 }
1541    
1542 /*
1543  * Vram accessing functions moved to vram.cpp .
1544  */
1545
1546 uint32_t DISPLAY::read_mmio(uint32_t addr)
1547 {
1548         uint32_t retval = 0xff;
1549         uint32_t raddr; 
1550         if(addr < 0xd400) return 0xff;
1551         
1552 #if !defined(_FM77AV_VARIANTS)
1553         raddr = (addr - 0xd400) & 0x000f;
1554 #elif !defined(_FM77AV40SX) && !defined(_FM77AV40EX)
1555         raddr = (addr - 0xd400) & 0x003f;
1556 #else // FM77AV40EX || FM77AV40SX
1557         raddr = (addr - 0xd400) & 0x00ff;
1558 #endif
1559         switch(raddr) {
1560                 case 0x00: // Read keyboard
1561                         retval = (keyboard->read_data8(0x00) != 0) ? 0xff : 0x7f;
1562                         break;
1563                 case 0x01: // Read keyboard
1564                         retval = keyboard->read_data8(0x01) & 0xff;
1565                         break;
1566                 case 0x02: // Acknowledge
1567                         acknowledge_irq();
1568                         break;
1569                 case 0x03:
1570                         beep();
1571                         break;
1572                 case 0x04:
1573                         attention_irq();
1574                         break;
1575 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || \
1576      defined(_FM77AV20) || defined(_FM77AV20EX) || defined(_FM77AV20SX) || defined(_FM77_VARIANTS) // _FM77L4
1577                 case 0x06:
1578                         if(!kanjisub) return 0xff;
1579 # if !defined(_FM77_VARIANTS)
1580                         if(kanji_level2) {
1581                                 return (uint8_t)kanjiclass2->read_data8(KANJIROM_DIRECTADDR + ((kanjiaddr.d << 1) & 0x1ffff));
1582                         }
1583 # endif
1584                         if(kanjiclass1 != NULL) retval = kanjiclass1->read_data8(KANJIROM_DIRECTADDR + ((kanjiaddr.d << 1) & 0x1ffff));
1585                         break;
1586                 case 0x07:
1587                         if(!kanjisub) return 0xff;
1588 # if !defined(_FM77_VARIANTS)
1589                         if(kanji_level2) {
1590                                 return (uint8_t)kanjiclass2->read_data8(KANJIROM_DIRECTADDR + ((kanjiaddr.d << 1) & 0x1ffff) + 1);
1591                         }
1592 # endif
1593                         if(kanjiclass1 != NULL) retval = kanjiclass1->read_data8(KANJIROM_DIRECTADDR + ((kanjiaddr.d << 1) & 0x1ffff) + 1);
1594                         break;
1595 #endif
1596                 case 0x08:
1597                         set_crtflag();
1598                         break;
1599                 case 0x09:
1600                         retval = set_vramaccess();
1601                         break;
1602                 case 0x0a:
1603                         reset_subbusy();
1604                         break;
1605                 case 0x0d:
1606                         keyboard->write_signal(SIG_FM7KEY_SET_INSLED, 0x01, 0x01);
1607                         break;
1608 #if defined(_FM77AV_VARIANTS)
1609                 // ALU
1610                 case 0x10:
1611                         retval = alu->read_data8(ALU_CMDREG);
1612                         break;
1613                 case 0x11:
1614                         retval = alu->read_data8(ALU_LOGICAL_COLOR);
1615                         break;
1616                 case 0x12:
1617                         retval = alu->read_data8(ALU_WRITE_MASKREG);
1618                         break;
1619                 case 0x13:
1620                         retval = alu->read_data8(ALU_CMP_STATUS_REG);
1621                         break;
1622                 case 0x1b:
1623                         retval = alu->read_data8(ALU_BANK_DISABLE);
1624                         break;
1625 # if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX)
1626                 case 0x2f: // VRAM BANK
1627                         retval = 0xfc | (vram_bank & 0x03);
1628                         break;
1629 # endif                 
1630                 // MISC
1631                 case 0x30:
1632                         retval = get_miscreg();
1633                         break;
1634                 // KEY ENCODER.
1635                 case 0x31:
1636                         retval = keyboard->read_data8(0x31);
1637                         break;
1638                 case 0x32:
1639                         retval = keyboard->read_data8(0x32);
1640                         break;
1641 #endif                          
1642                 default:
1643                         break;
1644         }
1645         return (uint8_t)retval;
1646 }
1647
1648 uint32_t DISPLAY::read_vram_data8(uint32_t addr)
1649 {
1650         uint32_t offset;
1651         uint32_t page_offset = 0;
1652         uint32_t page_mask = 0x3fff;
1653         uint32_t color = (addr >> 14) & 0x03;
1654         uint32_t pagemod;
1655         
1656 # if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX)
1657         if(display_mode == DISPLAY_MODE_8_400L) {
1658                 color = vram_bank & 0x03;
1659                 if(color > 2) color = 0;
1660         } else {
1661                 color = (addr >> 14) & 0x03;
1662         }
1663 # endif
1664 # if !defined(_FM8)             
1665         if((multimode_accessmask & (1 << color)) != 0) return 0xff;
1666 # endif         
1667 #if defined(_FM77AV_VARIANTS)
1668         if (active_page != 0) {
1669                 offset = offset_point_bank1;
1670         } else {
1671                 offset = offset_point;
1672         }
1673 #else
1674         offset = offset_point;
1675 #endif
1676                 
1677 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX)
1678 # if defined(_FM77AV40EX) || defined(_FM77AV40SX)
1679         if(vram_active_block != 0) page_offset = 0x18000;
1680 # endif         
1681                 if(display_mode == DISPLAY_MODE_8_400L) {
1682                         if(addr >= 0x8000) return 0xff;
1683                         color = vram_bank & 0x03;
1684                         if(color > 2) color = 0;
1685                         offset <<= 1;
1686                         pagemod = 0x8000 * color;
1687                         return gvram[(((addr + offset) & 0x7fff) | pagemod) + page_offset];
1688                 } else {
1689                         if(mode256k) {
1690 #if defined(_FM77AV40)
1691                                 if(vram_bank < 3) {
1692                                         page_offset = 0xc000 * (vram_bank & 0x03);
1693                                 } else {
1694                                         page_offset = 0; // right?
1695                                 }
1696 #else                   
1697                                 page_offset = 0xc000 * (vram_bank & 0x03);
1698 #endif                  
1699                                 page_mask = 0x1fff;
1700                                 pagemod = addr & 0xe000;
1701                         } else {
1702                                 if(mode320) {
1703                                         page_mask = 0x1fff;
1704                                         pagemod = addr & 0xe000;
1705                                 } else {
1706                                         pagemod = addr & 0xc000;
1707                                 }
1708                                 if(active_page != 0) {
1709                                         page_offset += 0xc000;
1710                                 }
1711                         }                               
1712                         return gvram[(((addr + offset) & page_mask) | pagemod) + page_offset];
1713                 }
1714 #elif defined(_FM77AV_VARIANTS)
1715                 {               
1716                         if(active_page != 0) {
1717                                 page_offset += 0xc000;
1718                         }
1719                         if(mode320) {
1720                                 page_mask = 0x1fff;
1721                                 pagemod = addr & 0xe000;
1722                         } else {
1723                                 pagemod = addr & 0xc000;
1724                         }
1725                         return gvram[(((addr + offset) & page_mask) | pagemod) + page_offset];
1726                 }
1727 #elif defined(_FM77L4) //_FM77L4
1728                 {
1729                         if(display_mode == DISPLAY_MODE_8_400L) {
1730                                 return (uint32_t)read_vram_l4_400l(addr, offset);
1731                         } else {
1732                                 pagemod = addr & 0xc000;
1733                                 return gvram[((addr + offset) & 0x3fff) | pagemod];
1734                         }
1735                         return 0xff;
1736                 }
1737 #else // Others (77/7/8)
1738                 pagemod = addr & 0xc000;
1739                 return gvram[((addr + offset) & 0x3fff) | pagemod];
1740 #endif
1741 }
1742
1743 void DISPLAY::write_dma_data8(uint32_t addr, uint32_t data)
1744 {
1745         uint32_t raddr = (addr & 0xffff) >> 7;
1746         if(write_dma_func_table[raddr] != NULL) {
1747                 (this->*write_dma_func_table[raddr])(addr, (uint8_t) data);
1748         }
1749 }
1750
1751 void DISPLAY::write_vram_data8(uint32_t addr, uint8_t data)
1752 {
1753         uint32_t offset;
1754         uint32_t page_offset = 0;
1755         uint32_t page_mask = 0x3fff;
1756         uint32_t color = (addr >> 14) & 0x03;
1757         uint32_t pagemod;
1758         uint8_t tdata;
1759         
1760 #if defined(_FM77AV_VARIANTS)
1761         if (active_page != 0) {
1762                 offset = offset_point_bank1;
1763         } else {
1764                 offset = offset_point;
1765         }
1766 #else
1767         offset = offset_point;
1768 #endif
1769
1770 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX)
1771 # if defined(_FM77AV40EX) || defined(_FM77AV40SX)
1772         if(vram_active_block != 0) page_offset = 0x18000;
1773 # endif         
1774                 if(display_mode == DISPLAY_MODE_8_400L) {
1775                         if(addr >= 0x8000) {
1776                                 return;
1777                         }
1778                         color = vram_bank & 0x03;
1779                         if(color > 2) color = 0;
1780                         offset <<= 1;
1781                         pagemod = 0x8000 * color;
1782                         // Reduce data transfer.
1783                         tdata = gvram[(((addr + offset) & 0x7fff) | pagemod) + page_offset];                    
1784                         if(tdata != data) {
1785                                 gvram[(((addr + offset) & 0x7fff) | pagemod) + page_offset] = data;
1786                                 vram_wrote_table[(addr & 0x7fff) / 80] = true;
1787                         }
1788                 } else  if(display_mode == DISPLAY_MODE_256k) {
1789 #if defined(_FM77AV40)
1790                         if(vram_bank < 3) {
1791                                 page_offset = 0xc000 * (vram_bank & 0x03);
1792                         } else {
1793                                 page_offset = 0; // right?
1794                         }
1795 #else                   
1796                         page_offset = 0xc000 * (vram_bank & 0x03);
1797 #endif                  
1798                         page_mask = 0x1fff;
1799                         pagemod = addr & 0xe000;
1800                         tdata = gvram[(((addr + offset) & page_mask) | pagemod) + page_offset];
1801                         if(tdata != data) {
1802                                 gvram[(((addr + offset) & page_mask) | pagemod) + page_offset] = data;
1803                                 vram_wrote_table[(addr & page_mask) / 40] = true;
1804                         }
1805                         return;
1806                 } else if(display_mode == DISPLAY_MODE_4096) {
1807                         if(active_page != 0) {
1808                                 page_offset += 0xc000;
1809                         }
1810                         page_mask = 0x1fff;
1811                         pagemod = addr & 0xe000;
1812                         tdata = gvram[(((addr + offset) & page_mask) | pagemod) + page_offset];
1813                         if(tdata != data) {
1814                                 gvram[(((addr + offset) & page_mask) | pagemod) + page_offset] = data;
1815                                 vram_wrote_table[(addr & page_mask) / 40] = true;
1816                         }
1817                 } else { // 200line
1818                         if(active_page != 0) {
1819                                 page_offset += 0xc000;
1820                         }
1821                         page_mask = 0x3fff;
1822                         pagemod = addr & 0xc000;
1823                         tdata = gvram[(((addr + offset) & page_mask) | pagemod) + page_offset];
1824                         if(tdata != data) {
1825                                 gvram[(((addr + offset) & page_mask) | pagemod) + page_offset] = data;
1826                                 vram_wrote_table[(addr & page_mask) / 80] = true;
1827                         }
1828                 }                               
1829 #elif defined(_FM77AV_VARIANTS)
1830                 if(display_mode == DISPLAY_MODE_4096) {
1831                         if(active_page != 0) {
1832                                 page_offset = 0xc000;
1833                         }
1834                         page_mask = 0x1fff;
1835                         pagemod = addr & 0xe000;
1836                         tdata = gvram[(((addr + offset) & page_mask) | pagemod) + page_offset];
1837                         if(tdata != data) {
1838                                 gvram[(((addr + offset) & page_mask) | pagemod) + page_offset] = data;
1839                                 vram_wrote_table[(addr & page_mask) / 40] = true;
1840                         }
1841                 } else { // 200line
1842                         if(active_page != 0) {
1843                                 page_offset = 0xc000;
1844                         }
1845                         page_mask = 0x3fff;
1846                         pagemod = addr & 0xc000;
1847                         tdata = gvram[(((addr + offset) & page_mask) | pagemod) + page_offset];
1848                         if(tdata != data) {
1849                                 gvram[(((addr + offset) & page_mask) | pagemod) + page_offset] = data;
1850                                 vram_wrote_table[(addr & page_mask) / 80] = true;
1851                         }
1852                 }
1853 #elif defined(_FM77L4) //_FM77L4
1854                 {
1855                         if(display_mode == DISPLAY_MODE_8_400L) {
1856                                 write_vram_l4_400l(addr, data, offset);
1857                         } else {
1858                                 pagemod = addr & 0xc000;
1859                                 tdata = gvram[((addr + offset) & 0x3fff) | pagemod];
1860                                 if(data != tdata) {
1861                                         gvram[((addr + offset) & 0x3fff) | pagemod] = data;
1862                                         vram_wrote_table[(addr & 0x3fff) / 80] = true;
1863                                 }
1864                         }
1865                 }
1866 #else // Others (77/7/8)
1867                 pagemod = addr & 0xc000;
1868                 tdata = gvram[((addr + offset) & 0x3fff) | pagemod];
1869                 if(tdata != data) {
1870                         gvram[((addr + offset) & 0x3fff) | pagemod] = data;
1871                         vram_wrote_table[(addr & 0x3fff) / 80] = true;
1872                 }
1873 #endif
1874 }
1875
1876 uint32_t DISPLAY::read_cpu_vram_data8(uint32_t addr)
1877 {
1878         uint8_t color;
1879 #if defined(_FM77AV_VARIANTS)
1880         if(use_alu) {
1881                 alu->read_data8(addr + ALU_WRITE_PROXY);
1882         }
1883 #endif
1884         return read_vram_data8(addr);
1885 }
1886
1887 uint32_t DISPLAY::read_dma_vram_data8(uint32_t addr)
1888 {
1889         return read_vram_data8(addr);
1890 }
1891
1892 void DISPLAY::init_read_table(void)
1893 {
1894         uint32_t _at;
1895         for(_at = 0 ; _at < 0xc000; _at += 0x80) {
1896                 read_cpu_func_table[_at >> 7] = &DISPLAY::read_cpu_vram_data8;
1897                 read_dma_func_table[_at >> 7] = &DISPLAY::read_dma_vram_data8;
1898         }
1899         for(_at = 0xc000; _at < 0xd000; _at += 0x80) {
1900                 read_cpu_func_table[_at >> 7] = &DISPLAY::read_console_ram;
1901                 read_dma_func_table[_at >> 7] = &DISPLAY::read_console_ram;
1902         }
1903         for(_at = 0xd000; _at < 0xd380; _at += 0x80) {
1904                 read_cpu_func_table[_at >> 7] = &DISPLAY::read_work_ram;
1905                 read_dma_func_table[_at >> 7] = &DISPLAY::read_work_ram;
1906         }
1907         for(_at = 0xd380; _at < 0xd400; _at += 0x80) {
1908                 read_cpu_func_table[_at >> 7] = &DISPLAY::read_shared_ram;
1909                 read_dma_func_table[_at >> 7] = &DISPLAY::read_shared_ram;
1910         }
1911 #if defined(_FM77AV_VARIANTS)
1912         for(_at = 0xd400; _at < 0xd500; _at += 0x80) {
1913                 read_cpu_func_table[_at >> 7] = &DISPLAY::read_mmio;
1914                 read_dma_func_table[_at >> 7] = &DISPLAY::read_mmio;
1915         }
1916         for(_at = 0xd500; _at < 0xd800; _at += 0x80) {
1917                 read_cpu_func_table[_at >> 7] = &DISPLAY::read_hidden_ram;
1918                 read_dma_func_table[_at >> 7] = &DISPLAY::read_hidden_ram;
1919         }
1920 #else
1921         for(_at = 0xd400; _at < 0xd800; _at += 0x80) {
1922                 read_cpu_func_table[_at >> 7] = &DISPLAY::read_mmio;
1923                 read_dma_func_table[_at >> 7] = &DISPLAY::read_mmio;
1924         }
1925 #endif
1926         for(_at = 0xd800; _at < 0xe000; _at += 0x80) {
1927                 read_cpu_func_table[_at >> 7] = &DISPLAY::read_cgrom;
1928                 read_dma_func_table[_at >> 7] = &DISPLAY::read_cgrom;
1929         }
1930         for(_at = 0xe000; _at < 0x10000; _at += 0x80) {
1931                 read_cpu_func_table[_at >> 7] = &DISPLAY::read_subsys_monitor;
1932                 read_dma_func_table[_at >> 7] = &DISPLAY::read_subsys_monitor;
1933         }
1934 }
1935
1936 uint32_t DISPLAY::read_console_ram(uint32_t addr)
1937 {
1938         uint32_t raddr = addr & 0xfff;
1939 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX)
1940         if(monitor_ram) {
1941                 if(console_ram_bank >= 1) {
1942                         return submem_console_av40[((console_ram_bank - 1) << 12) + raddr];
1943                 }
1944         }
1945 #endif
1946         return console_ram[raddr];
1947 }
1948
1949 uint32_t DISPLAY::read_work_ram(uint32_t addr)
1950 {
1951         addr = addr & 0x3ff;
1952         return work_ram[addr];
1953 }
1954
1955
1956 uint32_t DISPLAY::read_shared_ram(uint32_t addr)
1957 {
1958         addr = addr - 0xd380;
1959         return shared_ram[addr];
1960 }
1961
1962 #if defined(_FM77AV_VARIANTS)
1963 uint32_t DISPLAY::read_hidden_ram(uint32_t addr)
1964 {
1965         if(addr >= 0xd500) {
1966                 return submem_hidden[addr - 0xd500];
1967         }
1968 }
1969 #endif
1970
1971 uint32_t DISPLAY::read_cgrom(uint32_t addr)
1972 {
1973 #if defined(_FM77AV_VARIANTS)
1974 # if defined(_FM77AV40) || defined(_FM77AV40SX) || defined(_FM77AV40EX)
1975         if(monitor_ram) {
1976                 return submem_cgram[cgram_bank * 0x0800 + (addr - 0xd800)]; //FIXME
1977         }
1978 # endif         
1979         return subsys_cg[(addr - 0xd800) + cgrom_bank * 0x800];
1980 #else
1981         return subsys_c[addr - 0xd800];
1982 #endif
1983 }
1984
1985 uint32_t DISPLAY::read_subsys_monitor(uint32_t addr)
1986 {
1987 #if defined(_FM77AV40) || defined(_FM77AV40SX) || defined(_FM77AV40EX)
1988         if(monitor_ram) {
1989                 return subsys_ram[addr - 0xe000];
1990         }
1991 #endif
1992 #if defined(_FM77AV_VARIANTS)
1993         switch(subrom_bank_using & 3) {
1994         case 0: // SUBSYS_C
1995                 return subsys_c[addr - 0xd800];
1996                 break;
1997         case 1:
1998                 return subsys_a[addr - 0xe000];
1999                 break;
2000         case 2:
2001                 return subsys_b[addr - 0xe000];
2002                 break;
2003         default:
2004                 return subsys_cg[addr - 0xe000];
2005                 break;
2006         }
2007 #else
2008         return subsys_c[addr - 0xd800];
2009 #endif
2010 }
2011
2012 uint32_t DISPLAY::read_dma_data8(uint32_t addr)
2013 {
2014         uint32_t raddr = (addr & 0xffff) >> 7;
2015         if(read_dma_func_table[raddr] != NULL) {
2016                 return (this->*read_dma_func_table[raddr])(addr);
2017         }
2018         return 0xff;
2019 }
2020
2021 uint32_t DISPLAY::read_data8(uint32_t addr)
2022 {
2023         uint32_t raddr = addr;
2024         uint32_t offset;
2025         if(addr < 0x10000) {
2026                 raddr = (addr & 0xffff) >> 7;
2027                 if(read_cpu_func_table[raddr] != NULL) {
2028                         return (this->*read_cpu_func_table[raddr])(addr);
2029                 }
2030                 return 0xff;
2031         }
2032 #if !defined(_FM8)      
2033         else if((addr >= FM7_SUBMEM_OFFSET_DPALETTE) && (addr < (FM7_SUBMEM_OFFSET_DPALETTE + 8))) {
2034                 return dpalette_data[addr - FM7_SUBMEM_OFFSET_DPALETTE];
2035         }
2036 #endif  
2037 #if defined(_FM77AV_VARIANTS)
2038         // ACCESS VIA ALU.
2039         else if((addr >= DISPLAY_VRAM_DIRECT_ACCESS) && (addr < (DISPLAY_VRAM_DIRECT_ACCESS + 0x18000))) {
2040                 addr = addr - DISPLAY_VRAM_DIRECT_ACCESS;
2041 # if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX)         
2042                 if(display_mode == DISPLAY_MODE_8_400L) {
2043                         uint32_t page_offset = 0;
2044 # if defined(_FM77AV40EX) || defined(_FM77AV40SX)
2045                         if(vram_active_block != 0) page_offset = 0x18000;
2046 # endif         
2047                         uint32_t color = (addr & 0x0c000) >> 14;
2048                         color = (addr & 0x18000) >> 15;
2049                         if(color > 2) color = 0;
2050                         
2051                         if (active_page != 0) {
2052                                 offset = offset_point_bank1 << 1;
2053                         } else {
2054                                 offset = offset_point << 1;
2055                         }
2056                         if(color > 2) color = 0;
2057                         uint32_t pagemod = 0x8000 * color;
2058                         return gvram[(((addr + offset) & 0x7fff) | pagemod) + page_offset];
2059                 }
2060 # endif         
2061                 return read_vram_data8(addr);
2062         }
2063 #endif
2064         return 0xff;
2065 }       
2066
2067 /*
2068  * Vram accessing functions moved to vram.cpp .
2069  */
2070
2071 void DISPLAY::write_mmio(uint32_t addr, uint8_t data)
2072 {
2073         uint8_t rval = 0;
2074         pair_t tmpvar;
2075         if(addr < 0xd400) return;
2076         
2077 #if !defined(_FM77AV_VARIANTS)
2078         addr = (addr - 0xd400) & 0x000f;
2079 #elif !defined(_FM77AV40SX) && !defined(_FM77AV40EX)
2080         addr = (addr - 0xd400) & 0x003f;
2081 #else // FM77AV40EX || FM77AV40SX
2082         addr = (addr - 0xd400) & 0x00ff;
2083 #endif
2084         io_w_latch[addr] = (uint8_t)data;
2085         switch(addr) {
2086 #if defined(_FM77) || defined(_FM77L2) || defined(_FM77L4)
2087                 // FM77 SPECIFIED
2088                 case 0x05:
2089                         set_cyclesteal((uint8_t)data);
2090                         break;
2091 #endif
2092 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || \
2093      defined(_FM77AV20) || defined(_FM77AV20EX) || defined(_FM77AV20SX) || defined(_FM77_VARIANTS) // _FM77L4
2094                 // KANJI
2095                 case 0x06:
2096                         if(!kanjisub) return;
2097                         kanjiaddr.w.h = 0x0000;
2098                         kanjiaddr.b.h = (uint8_t) data;
2099                         break;
2100                 case 0x07:
2101                         if(!kanjisub) return;
2102                         kanjiaddr.w.h = 0x0000;
2103                         kanjiaddr.b.l = (uint8_t)data;
2104                         break;
2105 #endif                  
2106                 // CRT OFF
2107                 case 0x08:
2108                         reset_crtflag();
2109                         break;
2110                 // VRAM ACCESS
2111                 case 0x09:
2112                         reset_vramaccess();
2113                         break;
2114                 // BUSY
2115                 case 0x0a:
2116                         if(clr_count <= 0) {
2117                                 set_subbusy();
2118                         } else { // Read once when using clr_foo() to set busy flag.
2119                                 double usec;
2120                                 if(clock_fast) {
2121                                         usec = (1000.0 * 1000.0) / 2000000.0;
2122                                 } else {
2123                                         usec = (1000.0 * 1000.0) / 999000.0;
2124                                 }
2125                                 if(!is_cyclesteal && vram_accessflag)  usec = usec * 3.0;
2126                                 usec = (double)clr_count * usec;
2127                                 register_event(this, EVENT_FM7SUB_CLR_BUSY, usec, false, NULL); // NEXT CYCLE_
2128                                 reset_subbusy();
2129                                 clr_count = 0;
2130                         }
2131                         break;
2132                 // LED
2133                 case 0x0d:
2134                         keyboard->write_signal(SIG_FM7KEY_SET_INSLED, 0x00, 0x01);
2135                         break;
2136                 // OFFSET
2137                 case 0x0e:
2138                 case 0x0f:
2139                         rval = (uint8_t)data;
2140                         if(offset_changed[active_page]) {
2141 #if defined(_FM77AV_VARIANTS)
2142                                 if(active_page != 0) {
2143                                         tmp_offset_point[active_page].d = offset_point_bank1;
2144                                 } else {
2145                                         tmp_offset_point[active_page].d = offset_point;
2146                                 }
2147 #else
2148                                 tmp_offset_point[active_page].d = offset_point;
2149 #endif
2150                         }
2151                         tmp_offset_point[active_page].w.h = 0x0000;
2152                         if(addr == 0x0e) {
2153                                 tmp_offset_point[active_page].b.h = rval;
2154                         } else {
2155                                 tmp_offset_point[active_page].b.l = rval;
2156                         }
2157                         offset_changed[active_page] = !offset_changed[active_page];
2158                         if(offset_changed[active_page]) {
2159                                 vram_wrote = true;
2160 #if defined(_FM77AV_VARIANTS)
2161                                 if(active_page != 0) {
2162                                         if(offset_77av) {
2163                                                 offset_point_bank1 = tmp_offset_point[active_page].d & 0x007fff;
2164                                         } else {
2165                                                 offset_point_bank1 = tmp_offset_point[active_page].d & 0x007fe0;
2166                                         }                                  
2167                                 } else {
2168                                         if(offset_77av) {
2169                                                 offset_point = tmp_offset_point[active_page].d & 0x007fff;
2170                                         } else {
2171                                                 offset_point = tmp_offset_point[active_page].d & 0x007fe0;
2172                                         }                                  
2173                                 }
2174 #else
2175                                 offset_point = tmp_offset_point[active_page].d & 0x7fe0;
2176 #endif                             
2177                         }
2178                         break;
2179 #if defined(_FM77AV_VARIANTS)
2180                 // ALU
2181                 case 0x10:
2182                         alu_write_cmdreg(data);
2183                         break;
2184                 case 0x11:
2185                         alu_write_logical_color(data);
2186                         break;
2187                 case 0x12:
2188                         alu_write_mask_reg(data);
2189                         break;
2190                 case 0x1b:
2191                         alu_write_disable_reg(data);
2192                         break;
2193                 case 0x20:
2194                         alu_write_offsetreg_hi(data);
2195                         break;
2196                 case 0x21:
2197                         alu_write_offsetreg_lo(data);
2198                         break;
2199                 case 0x22:
2200                         alu_write_linepattern_hi(data);
2201                         break;
2202                 case 0x23:
2203                         alu_write_linepattern_lo(data);
2204                         break;
2205 # if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX)
2206                 case 0x2e: //
2207                         console_ram_bank = (data & 0x18) >> 3;
2208                         if(console_ram_bank > 2) console_ram_bank = 0;
2209                         cgram_bank = data & 0x07;
2210                         kanji_level2 = ((data & 0x80) == 0) ? false : true;
2211                         break;
2212                 case 0x2f: // VRAM BANK
2213                         vram_bank = data &  0x03;
2214                         if(vram_bank > 2) vram_bank = 0;
2215                         vram_wrote = true;
2216                         break;
2217 # endif                 
2218                 // MISC
2219                 case 0x30:
2220                         set_miscreg(data);
2221                         break;
2222                 // KEYBOARD ENCODER
2223                 case 0x31:
2224                         keyboard->write_data8(0x31, data);
2225                         break;
2226 # if defined(_FM77AV40EX) || defined(_FM77AV40SX)
2227                 case 0x33: //
2228                         vram_active_block = data & 0x01;
2229                         if(vram_display_block != (((data & 0x10) != 0) ? 1 : 0)) vram_wrote = true;
2230                         vram_display_block = ((data & 0x10) != 0) ? 1 : 0;
2231                         break;
2232                         // Window
2233                 case 0x38: //
2234                 case 0x39: //
2235                         tmpvar.d = window_xbegin * 8;
2236                         tmpvar.w.h = 0;
2237                         if(addr == 0x38) {
2238                                 tmpvar.b.h = data & 0x03;
2239                         } else {
2240                                 tmpvar.b.l = data & 0xf8;
2241                         }
2242                         if(mode320 || mode256k) {
2243                            if(tmpvar.d > 320) tmpvar.d = 320;
2244                         } else {
2245                            if(tmpvar.d > 640) tmpvar.d = 640;
2246                         }
2247                         window_xbegin = tmpvar.d / 8;
2248                         vram_wrote = true;
2249                         break;
2250                 case 0x3a: //
2251                 case 0x3b: //
2252                         tmpvar.d = window_xend * 8;
2253                         tmpvar.w.h = 0;
2254                         if(addr == 0x3a) {
2255                                 tmpvar.b.h = data & 0x03;
2256                         } else {
2257                                 tmpvar.b.l = data & 0xf8;
2258                         }
2259                         if(mode320 || mode256k) {
2260                            if(tmpvar.d > 320) tmpvar.d = 320;
2261                         } else {
2262                            if(tmpvar.d > 640) tmpvar.d = 640;
2263                         }
2264                         window_xend = tmpvar.d / 8;
2265                         vram_wrote = true;
2266                         break;
2267                 case 0x3c: //
2268                 case 0x3d: //
2269                         tmpvar.d = window_low;
2270                         tmpvar.w.h = 0;
2271                         if(addr == 0x3c) {
2272                                 tmpvar.b.h = data & 0x03;
2273                         } else {
2274                                 tmpvar.b.l = data & 0xff;
2275                         }
2276                         if(display_mode == DISPLAY_MODE_8_400L) {
2277                                 if(tmpvar.d > 400) tmpvar.d = 400;
2278                         } else {
2279                                 tmpvar.d <<= 1;
2280                                 if(tmpvar.d > 400) tmpvar.d = 400;
2281                         }
2282                         window_low = tmpvar.d;
2283                         vram_wrote = true;
2284                         break;
2285                 case 0x3e: //
2286                 case 0x3f: //
2287                         tmpvar.d = window_high;
2288                         tmpvar.w.h = 0;
2289                         if(addr == 0x3e) {
2290                                 tmpvar.b.h = data & 0x03;
2291                         } else {
2292                                 tmpvar.b.l = data & 0xff;
2293                         }
2294                         if(display_mode == DISPLAY_MODE_8_400L) {
2295                                 if(tmpvar.d > 400) tmpvar.d = 400;
2296                         } else {
2297                                 tmpvar.d <<= 1;
2298                                 if(tmpvar.d > 400) tmpvar.d = 400;
2299                         }
2300                         window_high = tmpvar.d;
2301                         vram_wrote = true;
2302                         break;
2303 # endif
2304 #endif                          
2305                 default:
2306 #if defined(_FM77AV_VARIANTS)
2307                         //ALU
2308                         if((addr >= 0x13) && (addr <= 0x1a)) {
2309                                 alu_write_cmpdata_reg(addr - 0x13, data);
2310                         } else if((addr >= 0x1c) && (addr <= 0x1e)) {
2311                                 alu_write_tilepaint_data(addr, data);
2312                         } else if((addr >= 0x24) && (addr <= 0x2b)) {
2313                                 alu_write_line_position(addr - 0x24, data);
2314                         }
2315 #endif                          
2316                         break;
2317         }
2318 }
2319
2320 void DISPLAY::init_write_table(void)
2321 {
2322         uint32_t _at;
2323         for(_at = 0 ; _at < 0xc000; _at += 0x80) {
2324                 write_cpu_func_table[_at >> 7] = &DISPLAY::write_cpu_vram_data8;
2325                 write_dma_func_table[_at >> 7] = &DISPLAY::write_dma_vram_data8;
2326         }
2327         for(_at = 0xc000; _at < 0xd000; _at += 0x80) {
2328                 write_cpu_func_table[_at >> 7] = &DISPLAY::write_console_ram;
2329                 write_dma_func_table[_at >> 7] = &DISPLAY::write_console_ram;
2330         }
2331         for(_at = 0xd000; _at < 0xd380; _at += 0x80) {
2332                 write_cpu_func_table[_at >> 7] = &DISPLAY::write_work_ram;
2333                 write_dma_func_table[_at >> 7] = &DISPLAY::write_work_ram;
2334         }
2335         for(_at = 0xd380; _at < 0xd400; _at += 0x80) {
2336                 write_cpu_func_table[_at >> 7] = &DISPLAY::write_shared_ram;
2337                 write_dma_func_table[_at >> 7] = &DISPLAY::write_shared_ram;
2338         }
2339 #if defined(_FM77AV_VARIANTS)
2340         for(_at = 0xd400; _at < 0xd500; _at += 0x80) {
2341                 write_cpu_func_table[_at >> 7] = &DISPLAY::write_mmio;
2342                 write_dma_func_table[_at >> 7] = &DISPLAY::write_mmio;
2343         }
2344         for(_at = 0xd500; _at < 0xd800; _at += 0x80) {
2345                 write_cpu_func_table[_at >> 7] = &DISPLAY::write_hidden_ram;
2346                 write_dma_func_table[_at >> 7] = &DISPLAY::write_hidden_ram;
2347         }
2348 #else
2349         for(_at = 0xd400; _at < 0xd800; _at += 0x80) {
2350                 write_cpu_func_table[_at >> 7] = &DISPLAY::write_mmio;
2351                 write_dma_func_table[_at >> 7] = &DISPLAY::write_mmio;
2352         }
2353 #endif
2354 #if defined(_FM77AV40) || defined(_FM77AV40SX) || defined(_FM77AV40EX)
2355         for(_at = 0xd800; _at < 0xe000; _at += 0x80) {
2356                 write_cpu_func_table[_at >> 7] = &DISPLAY::write_subsys_cgram;
2357                 write_dma_func_table[_at >> 7] = &DISPLAY::write_subsys_cgram;
2358         }
2359         for(_at = 0xe000; _at < 0x10000; _at += 0x80) {
2360                 write_cpu_func_table[_at >> 7] = &DISPLAY::write_subsys_ram;
2361                 write_dma_func_table[_at >> 7] = &DISPLAY::write_subsys_ram;
2362         }
2363 #else
2364         for(_at = 0xd800; _at < 0x10000; _at += 0x80) {
2365                 write_cpu_func_table[_at >> 7] = &DISPLAY::write_dummy;
2366                 write_dma_func_table[_at >> 7] = &DISPLAY::write_dummy;
2367         }
2368 #endif
2369 }
2370
2371 void DISPLAY::write_console_ram(uint32_t addr, uint8_t data)
2372 {
2373         uint32_t raddr = addr & 0xfff;
2374 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX)
2375         if(monitor_ram) {
2376                 if(console_ram_bank >= 1) {
2377                         submem_console_av40[((console_ram_bank - 1) << 12) + raddr] = data;
2378                         return;
2379                 }
2380         }
2381 #endif
2382         console_ram[raddr] = data;
2383         return;
2384 }
2385
2386 void DISPLAY::write_work_ram(uint32_t addr, uint8_t data)
2387 {
2388         uint32_t raddr = addr & 0xfff;
2389         work_ram[raddr] = data;
2390         return;
2391 }
2392
2393 void DISPLAY::write_shared_ram(uint32_t addr, uint8_t data)
2394 {
2395         uint32_t raddr = addr & 0x7f;
2396         shared_ram[raddr] = data;
2397         return;
2398 }
2399
2400 #if defined(_FM77AV40) || defined(_FM77AV40SX) || defined(_FM77AV40EX)
2401 void DISPLAY::write_subsys_cgram(uint32_t addr, uint8_t data)
2402 {
2403         uint32_t raddr = addr - 0xd800;
2404         if(ram_protect) return;
2405         if(!monitor_ram) return;
2406         submem_cgram[cgram_bank * 0x0800 + raddr] = data; //FIXME
2407 }
2408
2409 void DISPLAY::write_subsys_ram(uint32_t addr, uint8_t data)
2410 {
2411         if(ram_protect) return;
2412         if(!monitor_ram) return;
2413         subsys_ram[addr - 0xe000] = data; //FIXME
2414 }
2415 #endif
2416
2417 #if defined(_FM77AV_VARIANTS)
2418 void DISPLAY::write_hidden_ram(uint32_t addr, uint8_t data)
2419 {
2420         submem_hidden[addr - 0xd500] = data;
2421         return;
2422 }
2423 #endif
2424
2425 void DISPLAY::write_cpu_vram_data8(uint32_t addr, uint8_t data)
2426 {
2427         uint32_t color = (addr & 0xc000) >> 14;
2428 #if defined(_FM77AV_VARIANTS)
2429         if(use_alu) {
2430                 alu->read_data8(addr + ALU_WRITE_PROXY);
2431                 return;
2432         }
2433 #endif  
2434 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX)
2435         if(display_mode == DISPLAY_MODE_8_400L) {
2436                 color = vram_bank & 0x03;
2437                 if(color > 2) color = 0;
2438         }
2439 #endif
2440 #if !defined(_FM8)
2441         if((multimode_accessmask & (1 << color)) != 0) return;
2442 #endif          
2443         write_vram_data8(addr & 0xffff, data);
2444 }
2445
2446 void DISPLAY::write_dma_vram_data8(uint32_t addr, uint8_t data)
2447 {
2448         uint32_t color = (addr & 0xc000) >> 14;
2449 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX)
2450         if(display_mode == DISPLAY_MODE_8_400L) {
2451                 color = vram_bank & 0x03;
2452                 if(color > 2) color = 0;
2453         }
2454 #endif
2455 #if !defined(_FM8)
2456         if((multimode_accessmask & (1 << color)) != 0) return;
2457 #endif          
2458         write_vram_data8(addr & 0xffff, data);
2459 }
2460
2461 void DISPLAY::write_dummy(uint32_t addr, uint8_t data)
2462 {
2463 }
2464
2465 void DISPLAY::write_data8(uint32_t addr, uint32_t data)
2466 {
2467         uint32_t offset;
2468         uint32_t raddr;
2469         uint32_t page_offset = 0x0000;
2470         uint8_t val8 = data & 0xff;
2471         uint32_t pagemod;
2472         uint32_t color = (addr & 0xc000) >> 14;
2473         uint8_t tdata;
2474
2475         if(addr < 0x10000) {
2476                 void (*_write_func)(uint32_t, uint32_t);
2477                 raddr = (addr & 0xffff) >> 7;
2478                 if(write_cpu_func_table[raddr] != NULL) {
2479                         (this->*write_cpu_func_table[raddr])(addr, (uint8_t)data);
2480                         return;
2481                 }
2482                 return;
2483         }
2484 #if !defined(_FM8)      
2485         else if((addr >= FM7_SUBMEM_OFFSET_DPALETTE) && (addr < (FM7_SUBMEM_OFFSET_DPALETTE + 8))) {
2486                 set_dpalette(addr - FM7_SUBMEM_OFFSET_DPALETTE, val8);
2487                 return;
2488         }
2489 #endif  
2490 #if defined(_FM77AV_VARIANTS)
2491         // ANALOG PALETTE
2492         else if(addr == FM7_SUBMEM_OFFSET_APALETTE_R) {
2493                 set_apalette_r(val8);
2494                 return;
2495         } else if(addr == FM7_SUBMEM_OFFSET_APALETTE_G) {
2496                 set_apalette_g(val8);
2497                 return;
2498         } else if(addr == FM7_SUBMEM_OFFSET_APALETTE_B) {
2499                 set_apalette_b(val8);
2500                 return;
2501         } else if(addr == FM7_SUBMEM_OFFSET_APALETTE_HI) {
2502                 set_apalette_index_hi(val8);
2503                 return;
2504         } else if(addr == FM7_SUBMEM_OFFSET_APALETTE_LO) {
2505                 set_apalette_index_lo(val8);
2506                 return;
2507         }
2508         // ACCESS VIA ALU.
2509         else if((addr >= DISPLAY_VRAM_DIRECT_ACCESS) && (addr < (DISPLAY_VRAM_DIRECT_ACCESS + 0x18000))) {
2510                 addr = addr - DISPLAY_VRAM_DIRECT_ACCESS; 
2511 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX)
2512                 if(display_mode == DISPLAY_MODE_8_400L) {
2513                         color = (addr & 0x18000) >> 15;
2514                         if(color > 2) color = 0;
2515                         page_offset = 0;
2516 # if defined(_FM77AV40EX) || defined(_FM77AV40SX)
2517                         if(vram_active_block != 0) page_offset = 0x18000;
2518 # endif         
2519                         if(color > 2) color = 0;
2520                         if (active_page != 0) {
2521                                 offset = offset_point_bank1 << 1;
2522                         } else {
2523                                 offset = offset_point << 1;
2524                         }
2525                         pagemod = 0x8000 * color;
2526                         tdata = gvram[(((addr + offset) & 0x7fff) | pagemod) + page_offset];
2527                         if(tdata != (uint8_t)data) {
2528                                 gvram[(((addr + offset) & 0x7fff) | pagemod) + page_offset] = data;
2529                                 vram_wrote_table[(addr & 0x7fff) / 80] = true;
2530                         }
2531                         return;
2532                 }
2533                 write_vram_data8(addr, data);
2534 #else
2535                 write_vram_data8(addr, data);
2536 #endif
2537                 //if((config.dipswitch & FM7_DIPSW_SYNC_TO_HSYNC) == 0) vram_wrote = true;
2538         }
2539 #endif
2540         return;
2541 }       
2542
2543
2544 uint32_t DISPLAY::read_bios(const _TCHAR *name, uint8_t *ptr, uint32_t size)
2545 {
2546         FILEIO fio;
2547         uint32_t blocks;
2548         const _TCHAR *s;
2549   
2550         if((name == NULL) || (ptr == NULL))  return 0;
2551         s = create_local_path(name);
2552         if(s == NULL) return 0;
2553   
2554         if(!fio.Fopen(s, FILEIO_READ_BINARY)) return 0;
2555         blocks = fio.Fread(ptr, size, 1);
2556         fio.Fclose();
2557
2558         return blocks * size;
2559 }
2560
2561
2562 void DISPLAY::initialize()
2563 {
2564         int i;
2565
2566         screen_update_flag = true;
2567         memset(gvram, 0x00, sizeof(gvram));
2568         vram_wrote_shadow = false;
2569         memset(gvram_shadow, 0x00, sizeof(gvram_shadow));
2570         for(i = 0; i < 411; i++) vram_wrote_table[i] = false;
2571         for(i = 0; i < 411; i++) vram_draw_table[i] = false;
2572
2573         memset(console_ram, 0x00, sizeof(console_ram));
2574         memset(work_ram, 0x00, sizeof(work_ram));
2575         memset(shared_ram, 0x00, sizeof(shared_ram));
2576         memset(subsys_c, 0xff, sizeof(subsys_c));
2577         need_transfer_line = true;
2578         frame_skip_count_draw = 3;
2579         frame_skip_count_transfer = 3;
2580         
2581         diag_load_subrom_c = false;
2582 #if defined(_FM8)       
2583         if(read_bios(_T("SUBSYS_8.ROM"), subsys_c, 0x2800) >= 0x2800) diag_load_subrom_c = true;
2584         this->out_debug_log(_T("SUBSYSTEM ROM READING : %s"), diag_load_subrom_c ? "OK" : "NG");
2585 #else
2586         if(read_bios(_T("SUBSYS_C.ROM"), subsys_c, 0x2800) >= 0x2800) diag_load_subrom_c = true;
2587         this->out_debug_log(_T("SUBSYSTEM ROM Type C READING : %s"), diag_load_subrom_c ? "OK" : "NG");
2588 #endif
2589 #if defined(_FM77AV_VARIANTS)
2590         memset(subsys_a, 0xff, sizeof(subsys_a));
2591         memset(subsys_b, 0xff, sizeof(subsys_b));
2592         memset(subsys_cg, 0xff, sizeof(subsys_cg));
2593         memset(submem_hidden, 0x00, sizeof(submem_hidden));
2594    
2595         diag_load_subrom_a = false;
2596         if(read_bios(_T("SUBSYS_A.ROM"), subsys_a, 0x2000) >= 0x2000) diag_load_subrom_a = true;
2597         this->out_debug_log(_T("SUBSYSTEM ROM Type A READING : %s"), diag_load_subrom_a ? "OK" : "NG");
2598
2599         diag_load_subrom_b = false;
2600         if(read_bios(_T("SUBSYS_B.ROM"), subsys_b, 0x2000) >= 0x2000) diag_load_subrom_b = true;
2601         this->out_debug_log(_T("SUBSYSTEM ROM Type B READING : %s"), diag_load_subrom_b ? "OK" : "NG");
2602
2603         diag_load_subrom_cg = false;
2604         if(read_bios(_T("SUBSYSCG.ROM"), subsys_cg, 0x2000) >= 0x2000) diag_load_subrom_cg = true;
2605         this->out_debug_log(_T("SUBSYSTEM CG ROM READING : %s"), diag_load_subrom_cg ? "OK" : "NG");
2606 # if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || \
2607     defined(_FM77AV20) || defined(_FM77AV20EX) || defined(_FM77AV20SX)
2608         memset(subsys_ram, 0x00, sizeof(subsys_ram));
2609         memset(submem_cgram, 0x00, sizeof(submem_cgram));
2610         memset(submem_console_av40, 0x00, sizeof(submem_console_av40));
2611         ram_protect = true;
2612 # endif
2613 #endif
2614         init_read_table();
2615         init_write_table();
2616         
2617 #if defined(_FM77AV_VARIANTS)
2618         mode320 = false;
2619         apalette_index.d = 0;
2620         for(i = 0; i < 4096; i++) {
2621                 analog_palette_r[i] = i & 0x0f0;
2622                 analog_palette_g[i] = (i & 0xf00) >> 4;
2623                 analog_palette_b[i] = (i & 0x00f) << 4;
2624                 calc_apalette(i);
2625         }
2626 #endif
2627 #if defined(_FM77AV_VARIANTS)
2628         hblank_event_id = -1;
2629         hdisp_event_id = -1;
2630         vsync_event_id = -1;
2631         vstart_event_id = -1;
2632 #endif
2633 #if defined(_FM8)
2634         clock_fast = false;
2635 #else
2636         clock_fast = true;
2637 #endif
2638 #if defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
2639         is_cyclesteal = true;
2640 #else
2641         is_cyclesteal = false;
2642 #endif  
2643 //      emu->set_vm_screen_size(640, 200, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_WIDTH_ASPECT, WINDOW_HEIGHT_ASPECT);
2644         emu->set_vm_screen_size(640, 200, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_WIDTH_ASPECT, WINDOW_HEIGHT_ASPECT);
2645         enter_display();
2646         nmi_event_id = -1;
2647         firq_mask = false;
2648         key_firq_req = false;   //firq_mask = true;
2649         frame_skip_count_transfer = 3;
2650         frame_skip_count_draw = 3;
2651         emu->set_vm_screen_size(640, 200, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_WIDTH_ASPECT, WINDOW_HEIGHT_ASPECT);
2652         palette_changed = true;
2653 #if !defined(_FM77AV_VARIANTS) && !defined(_FM77L4)
2654         //register_vline_event(this);
2655         //register_frame_event(this);
2656 #endif  
2657 }
2658
2659 void DISPLAY::release()
2660 {
2661 }
2662
2663 #define STATE_VERSION 8
2664 void DISPLAY::save_state(FILEIO *state_fio)
2665 {
2666         state_fio->FputUint32_BE(STATE_VERSION);
2667         state_fio->FputInt32_BE(this_device_id);
2668         this->out_debug_log("Save State: DISPLAY : id=%d ver=%d\n", this_device_id, STATE_VERSION);
2669
2670         {
2671                 int i;
2672                 state_fio->FputInt32_BE(clr_count);
2673                 state_fio->FputBool(halt_flag);
2674                 state_fio->FputInt32_BE(active_page);
2675                 state_fio->FputBool(sub_busy);
2676                 state_fio->FputBool(crt_flag);
2677                 state_fio->FputBool(vram_wrote);
2678                 state_fio->FputBool(is_cyclesteal);
2679                 
2680                 state_fio->FputBool(clock_fast);
2681                 
2682 #if defined(_FM77AV_VARIANTS)
2683                 state_fio->FputBool(subcpu_resetreq);
2684                 state_fio->FputBool(power_on_reset);
2685 #endif  
2686                 state_fio->FputBool(cancel_request);
2687                 state_fio->FputBool(key_firq_req);
2688
2689                 state_fio->FputInt32_BE(display_mode);
2690                 state_fio->FputUint32_BE(prev_clock);
2691
2692 #if !defined(_FM8)      
2693                 state_fio->Fwrite(dpalette_data, sizeof(dpalette_data), 1);
2694                 state_fio->FputUint8(multimode_accessmask);
2695                 state_fio->FputUint8(multimode_dispmask);
2696 #endif          
2697                 state_fio->FputUint32_BE(offset_point);
2698 #if defined(_FM77AV_VARIANTS)
2699                 state_fio->FputUint32_BE(offset_point_bank1);
2700 #endif          
2701                 for(i = 0; i < 2; i++) {
2702                         state_fio->FputUint32_BE(tmp_offset_point[i].d);
2703                         state_fio->FputBool(offset_changed[i]);
2704                 }
2705                 state_fio->FputBool(offset_77av);
2706                 state_fio->FputBool(diag_load_subrom_c);
2707                 
2708         
2709                 state_fio->Fwrite(io_w_latch, sizeof(io_w_latch), 1);
2710                 state_fio->Fwrite(console_ram, sizeof(console_ram), 1);
2711                 state_fio->Fwrite(work_ram, sizeof(work_ram), 1);
2712                 state_fio->Fwrite(shared_ram, sizeof(shared_ram), 1);
2713                 state_fio->Fwrite(subsys_c, sizeof(subsys_c), 1);
2714                 state_fio->Fwrite(gvram, sizeof(gvram), 1);
2715                 state_fio->Fwrite(gvram_shadow, sizeof(gvram_shadow), 1);
2716         
2717 #if defined(_FM77_VARIANTS)
2718                 state_fio->FputBool(kanjisub);
2719                 state_fio->FputUint16_BE(kanjiaddr.w.l);
2720 # if defined(_FM77L4)
2721                 state_fio->FputBool(mode400line);
2722                 state_fio->FputBool(stat_400linecard);
2723 # endif
2724 #elif defined(_FM77AV_VARIANTS)
2725                 state_fio->FputBool(kanjisub);
2726                 state_fio->FputUint16_BE(kanjiaddr.w.l);
2727
2728                 state_fio->FputBool(vblank);
2729                 state_fio->FputBool(vsync);
2730                 state_fio->FputBool(hblank);
2731                 state_fio->FputInt32_BE(vblank_count);
2732                 
2733                 state_fio->FputBool(mode320);
2734                 state_fio->FputInt8(display_page);
2735                 state_fio->FputInt8(display_page_bak);
2736                 state_fio->FputInt32_BE(cgrom_bank);
2737 #if defined(_FM77AV40) || defined(_FM77AV40SX)|| defined(_FM77AV40SX) || \
2738     defined(_FM77AV20) || defined(_FM77AV20EX) || defined(_FM77AV20SX)
2739                 state_fio->FputInt32_BE(vram_bank);
2740 #endif  
2741         
2742                 state_fio->FputUint32_BE(displine);
2743                 state_fio->FputUint8(subrom_bank);
2744                 state_fio->FputUint8(subrom_bank_using);
2745         
2746                 state_fio->FputBool(nmi_enable);
2747                 state_fio->FputBool(use_alu);
2748                 
2749                 state_fio->FputUint8(apalette_index.b.l);
2750                 state_fio->FputUint8(apalette_index.b.h);
2751                 state_fio->Fwrite(analog_palette_r, sizeof(analog_palette_r), 1);
2752                 state_fio->Fwrite(analog_palette_g, sizeof(analog_palette_g), 1);
2753                 state_fio->Fwrite(analog_palette_b, sizeof(analog_palette_b), 1);
2754                 
2755
2756                 state_fio->FputBool(diag_load_subrom_a);
2757                 state_fio->FputBool(diag_load_subrom_b);
2758                 state_fio->FputBool(diag_load_subrom_cg);
2759         
2760                 state_fio->Fwrite(subsys_a, sizeof(subsys_a), 1);
2761                 state_fio->Fwrite(subsys_b, sizeof(subsys_b), 1);
2762                 state_fio->Fwrite(subsys_cg, sizeof(subsys_cg), 1);
2763                 state_fio->Fwrite(submem_hidden, sizeof(submem_hidden), 1);
2764 # if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX)
2765                 state_fio->FputBool(mode400line);
2766                 state_fio->FputBool(mode256k);
2767                 
2768                 state_fio->FputBool(monitor_ram);
2769 #  if defined(_FM77AV40EX) || defined(_FM77AV40SX)
2770                 state_fio->FputUint16_BE(window_low);
2771                 state_fio->FputUint16_BE(window_high);
2772                 state_fio->FputUint16_BE(window_xbegin);
2773                 state_fio->FputUint16_BE(window_xend);
2774                 state_fio->FputBool(window_opened);
2775 #  endif        
2776                 state_fio->FputBool(kanji_level2);
2777
2778                 state_fio->FputUint8(vram_active_block);
2779                 state_fio->FputUint8(vram_display_block);
2780                 state_fio->FputUint8(console_ram_bank);
2781                 state_fio->FputBool(ram_protect);
2782                 
2783                 state_fio->FputUint32_BE(cgram_bank);
2784                 state_fio->Fwrite(subsys_ram, sizeof(subsys_ram), 1);
2785                 state_fio->Fwrite(submem_cgram, sizeof(submem_cgram), 1);
2786                 state_fio->Fwrite(submem_console_av40, sizeof(submem_console_av40), 1);
2787 # endif
2788 #endif
2789         }
2790         // V2
2791         {
2792                 state_fio->FputInt32_BE(nmi_event_id);
2793 #if defined(_FM77AV_VARIANTS)
2794                 state_fio->FputInt32_BE(hblank_event_id);
2795                 state_fio->FputInt32_BE(hdisp_event_id);
2796                 state_fio->FputInt32_BE(vsync_event_id);
2797                 state_fio->FputInt32_BE(vstart_event_id);
2798 #endif
2799                 state_fio->FputBool(firq_mask);
2800                 state_fio->FputBool(vram_accessflag);
2801         }                       
2802 }
2803
2804 bool DISPLAY::load_state(FILEIO *state_fio)
2805 {
2806
2807         uint32_t version = state_fio->FgetUint32_BE();
2808         if(this_device_id != state_fio->FgetInt32_BE()) {
2809                 return false;
2810         }
2811         this->out_debug_log("Load State: DISPLAY : id=%d ver=%d\n", this_device_id, version);
2812    
2813         if(version >= 1) {
2814                 int addr;
2815                 int i;
2816                 clr_count = state_fio->FgetInt32_BE();
2817                 halt_flag = state_fio->FgetBool();
2818                 active_page = state_fio->FgetInt32_BE();
2819                 sub_busy = state_fio->FgetBool();
2820                 crt_flag = state_fio->FgetBool();
2821                 vram_wrote = state_fio->FgetBool();
2822                 crt_flag_bak = true;
2823                 for(i = 0; i < 411; i++) vram_wrote_table[i] = true;
2824                 for(i = 0; i < 411; i++) vram_draw_table[i] = true;
2825                 is_cyclesteal = state_fio->FgetBool();
2826         
2827                 clock_fast = state_fio->FgetBool();
2828
2829 #if defined(_FM77AV_VARIANTS)
2830                 subcpu_resetreq = state_fio->FgetBool();
2831                 power_on_reset = state_fio->FgetBool();
2832 #endif          
2833                 cancel_request = state_fio->FgetBool();
2834                 key_firq_req = state_fio->FgetBool();
2835
2836                 display_mode = state_fio->FgetInt32_BE();
2837                 prev_clock = state_fio->FgetUint32_BE();
2838         
2839 #if defined(_FM8)
2840                 for(addr = 0; addr < 8; addr++) set_dpalette(addr, addr);
2841 #else
2842                 state_fio->Fread(dpalette_data, sizeof(dpalette_data), 1);
2843                 for(addr = 0; addr < 8; addr++) set_dpalette(addr, dpalette_data[addr]);
2844                 multimode_accessmask = state_fio->FgetUint8();
2845                 multimode_dispmask = state_fio->FgetUint8();
2846 #endif
2847                 offset_point = state_fio->FgetUint32_BE();
2848 #if defined(_FM77AV_VARIANTS)
2849                 offset_point_bank1     = state_fio->FgetUint32_BE();
2850 #endif          
2851                 for(i = 0; i < 2; i++) {
2852                         tmp_offset_point[i].d = state_fio->FgetUint32_BE();
2853                         offset_changed[i] = state_fio->FgetBool();
2854                 }
2855                 offset_77av = state_fio->FgetBool();
2856                 diag_load_subrom_c = state_fio->FgetBool();
2857                 
2858                 state_fio->Fread(io_w_latch, sizeof(io_w_latch), 1);
2859                 state_fio->Fread(console_ram, sizeof(console_ram), 1);
2860                 state_fio->Fread(work_ram, sizeof(work_ram), 1);
2861                 state_fio->Fread(shared_ram, sizeof(shared_ram), 1);
2862                 state_fio->Fread(subsys_c, sizeof(subsys_c), 1);
2863                 state_fio->Fread(gvram, sizeof(gvram), 1);
2864                 state_fio->Fread(gvram_shadow, sizeof(gvram_shadow), 1);
2865 #if defined(_FM77_VARIANTS)
2866                 kanjisub = state_fio->FgetBool();
2867                 kanjiaddr.d = 0;
2868                 kanjiaddr.w.l = state_fio->FgetUint16_BE();
2869 # if defined(_FM77L4)           
2870                 mode400line = state_fio->FgetBool();
2871                 stat_400linecard = state_fio->FgetBool();
2872 # endif         
2873 #elif defined(_FM77AV_VARIANTS)
2874                 kanjisub = state_fio->FgetBool();
2875                 kanjiaddr.d = 0;
2876                 kanjiaddr.w.l = state_fio->FgetUint16_BE();
2877                 
2878                 vblank = state_fio->FgetBool();
2879                 vsync = state_fio->FgetBool();
2880                 hblank = state_fio->FgetBool();
2881                 vblank_count = state_fio->FgetInt32_BE();
2882
2883                 mode320 = state_fio->FgetBool();
2884                 display_page = state_fio->FgetInt8();
2885                 display_page_bak = state_fio->FgetInt8();
2886                 cgrom_bank = state_fio->FgetInt32_BE();
2887 #if defined(_FM77AV40) || defined(_FM77AV40SX)|| defined(_FM77AV40SX) || \
2888     defined(_FM77AV20) || defined(_FM77AV20EX) || defined(_FM77AV20SX)
2889                 vram_bank = state_fio->FgetInt32_BE();
2890 #endif          
2891                 screen_update_flag = true;
2892                 displine = state_fio->FgetUint32_BE();
2893                 subrom_bank = state_fio->FgetUint8();
2894                 subrom_bank_using = state_fio->FgetUint8();
2895         
2896                 nmi_enable = state_fio->FgetBool();
2897                 use_alu = state_fio->FgetBool();
2898
2899                 apalette_index.b.l = state_fio->FgetUint8();
2900                 apalette_index.b.h = state_fio->FgetUint8();
2901         
2902                 state_fio->Fread(analog_palette_r, sizeof(analog_palette_r), 1);
2903                 state_fio->Fread(analog_palette_g, sizeof(analog_palette_g), 1);
2904                 state_fio->Fread(analog_palette_b, sizeof(analog_palette_b), 1);
2905                 for(i = 0; i < 4096; i++) calc_apalette(i);
2906                 
2907                 diag_load_subrom_a = state_fio->FgetBool();
2908                 diag_load_subrom_b = state_fio->FgetBool();
2909                 diag_load_subrom_cg = state_fio->FgetBool();
2910         
2911                 state_fio->Fread(subsys_a, sizeof(subsys_a), 1);
2912                 state_fio->Fread(subsys_b, sizeof(subsys_b), 1);
2913                 state_fio->Fread(subsys_cg, sizeof(subsys_cg), 1);
2914                 state_fio->Fread(submem_hidden, sizeof(submem_hidden), 1);
2915            
2916 # if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX)
2917                 mode400line = state_fio->FgetBool();
2918                 mode256k = state_fio->FgetBool();
2919
2920                 monitor_ram = state_fio->FgetBool();
2921 #  if defined(_FM77AV40EX) || defined(_FM77AV40SX)
2922                 window_low = state_fio->FgetUint16_BE();
2923                 window_high = state_fio->FgetUint16_BE();
2924                 window_xbegin = state_fio->FgetUint16_BE();
2925                 window_xend = state_fio->FgetUint16_BE();
2926                 window_opened = state_fio->FgetBool();
2927 # endif 
2928                 kanji_level2 = state_fio->FgetBool();
2929                 
2930                 vram_active_block = state_fio->FgetUint8();
2931                 vram_display_block = state_fio->FgetUint8();
2932                 console_ram_bank = state_fio->FgetUint8();
2933                 ram_protect = state_fio->FgetBool();
2934
2935                 cgram_bank = state_fio->FgetUint32_BE();
2936                 state_fio->Fread(subsys_ram, sizeof(subsys_ram), 1);
2937                 state_fio->Fread(submem_cgram, sizeof(submem_cgram), 1);
2938                 state_fio->Fread(submem_console_av40, sizeof(submem_console_av40), 1);
2939 # endif
2940 #endif
2941                 palette_changed = true;
2942                 vram_wrote_shadow = true; // Force Draw
2943                 this->draw_screen();
2944                 if(version == 1) return true;
2945         }
2946         if(version >= 2) {      //V2
2947                 nmi_event_id = state_fio->FgetInt32_BE();
2948 #if defined(_FM77AV_VARIANTS)
2949                 hblank_event_id = state_fio->FgetInt32_BE();
2950                 hdisp_event_id = state_fio->FgetInt32_BE();
2951                 vsync_event_id = state_fio->FgetInt32_BE();
2952                 vstart_event_id = state_fio->FgetInt32_BE();
2953 #endif
2954                 firq_mask = state_fio->FgetBool();
2955                 vram_accessflag = state_fio->FgetBool();
2956                 frame_skip_count_draw = 3;
2957                 frame_skip_count_transfer = 3;
2958                 need_transfer_line = true;
2959         }                       
2960         if(version == STATE_VERSION) return true;
2961         return false;
2962 }
2963
2964