OSDN Git Service

[VM][FMTOWNS][MEMORY] Fix setup around memory banks by I/O 0404h and 0480h.
[csp-qt/common_source_project-fm7.git] / source / src / vm / x1 / display.cpp
1 /*
2         SHARP X1 Emulator 'eX1'
3         SHARP X1twin Emulator 'eX1twin'
4         SHARP X1turbo Emulator 'eX1turbo'
5         SHARP X1turboZ Emulator 'eX1turboZ'
6
7         Origin : X1EMU by KM (kanji rom)
8                  X-millenium by Yui (ank16 patch)
9         Author : Takeda.Toshiya
10         Date   : 2009.03.14-
11
12   [ display ]
13 */
14
15 #include "display.h"
16 #include "../hd46505.h"
17 #include "../i8255.h"
18
19 #ifdef _X1TURBO_FEATURE
20 #define EVENT_AFTER_BLANK       0
21 #endif
22
23 namespace X1 {
24
25 #ifdef _X1TURBOZ
26 #define AEN     ((zmode1 & 0x80) != 0)
27 #define C64     ((zmode1 & 0x10) != 0)
28 #define APEN    ((zmode2 & 0x80) != 0)
29 #define APRD    ((zmode2 & 0x08) != 0)
30 #endif
31
32 void DISPLAY::initialize()
33 {
34         // load rom images
35         FILEIO* fio = new FILEIO();
36
37         // ank8 (8x8)
38         if(fio->Fopen(create_local_path(_T("ANK8.ROM")), FILEIO_READ_BINARY)) {
39                 fio->Fread(font, sizeof(font), 1);
40                 fio->Fclose();
41         } else if(fio->Fopen(create_local_path(_T("FNT0808.X1")), FILEIO_READ_BINARY)) {
42                 // xmillenium rom
43                 fio->Fread(font, sizeof(font), 1);
44                 fio->Fclose();
45         }
46
47         // ank16 (8x16)
48         if(fio->Fopen(create_local_path(_T("ANK16.ROM")), FILEIO_READ_BINARY)) {
49                 fio->Fread(kanji, 0x1000, 1);
50                 fio->Fclose();
51         } else if(fio->Fopen(create_local_path(_T("FNT0816.X1")), FILEIO_READ_BINARY)) {
52                 // xmillenium rom
53                 fio->Fread(kanji, 0x1000, 1);
54                 fio->Fclose();
55         }
56         memcpy(kanji + 0x7f * 16, ANKFONT7f_9f, sizeof(ANKFONT7f_9f));
57         memcpy(kanji + 0xe0 * 16, ANKFONTe0_ff, sizeof(ANKFONTe0_ff));
58
59         // kanji (16x16)
60         if(fio->Fopen(create_local_path(_T("KANJI.ROM")), FILEIO_READ_BINARY)) {
61                 fio->Fread(kanji + 0x1000, 0x4ac00, 1);
62                 fio->Fclose();
63         } else if(fio->Fopen(create_local_path(_T("FNT1616.X1")), FILEIO_READ_BINARY)) {
64                 // xmillenium rom
65                 fio->Fread(kanji + 0x1000, 0x4ac00, 1);
66                 fio->Fclose();
67         }
68         for(int ofs = 0x1000; ofs < 0x4bc00; ofs += 32) {
69                 // LRLR.. -> LL..RR..
70                 uint8_t buf[32];
71                 for(int i = 0; i < 16; i++) {
72                         buf[i     ] = kanji[ofs + i * 2    ];
73                         buf[i + 16] = kanji[ofs + i * 2 + 1];
74                 }
75                 memcpy(kanji + ofs, buf, 32);
76         }
77         delete fio;
78
79         // create pc palette
80         for(int i = 0; i < 8; i++) {
81                 palette_pc[i    ] = RGB_COLOR((i & 2) ? 255 : 0, (i & 4) ? 255 : 0, (i & 1) ? 255 : 0); // text
82                 palette_pc[i + 8] = RGB_COLOR((i & 2) ? 255 : 0, (i & 4) ? 255 : 0, (i & 1) ? 255 : 0); // cg
83         }
84 #ifdef _X1TURBOZ
85         for(int i = 0; i < 8; i++) {
86                 ztpal[i] = ((i & 1) ? 0x03 : 0) | ((i & 2) ? 0x0c : 0) | ((i & 4) ? 0x30 : 0);
87                 zpalette_tmp[i    ] = RGB_COLOR((i & 2) ? 255 : 0, (i & 4) ? 255 : 0, (i & 1) ? 255 : 0);       // text
88                 zpalette_tmp[i + 8] = RGB_COLOR((i & 2) ? 255 : 0, (i & 4) ? 255 : 0, (i & 1) ? 255 : 0);       // digital
89         }
90         for(int g = 0; g < 16; g++) {
91                 for(int r = 0; r < 16; r++) {
92                         for(int b = 0; b < 16; b++) {
93                                 int num = b + r * 16 + g * 256;
94                                 zpal[num].b = b;
95                                 zpal[num].r = r;
96                                 zpal[num].g = g;
97                                 zpalette_tmp[num + 16] = RGB_COLOR((r * 255) / 15, (g * 255) / 15, (b * 255) / 15);
98                         }
99                 }
100         }
101         zpalette_changed = true;
102 #endif
103
104         // initialize regs
105         pal[0] = 0xaa;
106         pal[1] = 0xcc;
107         pal[2] = 0xf0;
108         priority = 0;
109         update_pal();
110         column40 = true;
111
112         memset(vram_t, 0, sizeof(vram_t));
113         memset(vram_a, 0, sizeof(vram_a));
114 #ifdef _X1TURBO_FEATURE
115         memset(vram_k, 0, sizeof(vram_k));
116 #endif
117         memset(pcg_b, 0, sizeof(pcg_b));
118         memset(pcg_r, 0, sizeof(pcg_r));
119         memset(pcg_g, 0, sizeof(pcg_g));
120 #ifdef _X1TURBO_FEATURE
121         memset(gaiji_b, 0, sizeof(gaiji_b));
122         memset(gaiji_r, 0, sizeof(gaiji_r));
123         memset(gaiji_g, 0, sizeof(gaiji_g));
124 #endif
125
126         // register event
127         register_frame_event(this);
128         register_vline_event(this);
129
130         // Copy images to draw buffers.
131         my_memcpy(dr_text, text, sizeof(dr_text));
132         my_memcpy(dr_cg, cg, sizeof(dr_cg));
133         my_memcpy(dr_pri_line, pri_line, sizeof(dr_pri_line));
134         my_memcpy(dr_palette_pc, palette_pc, sizeof(dr_palette_pc));
135         dr_priority = priority;
136 #ifdef _X1TURBOZ
137         dr_zpriority = zpriority;
138         my_memcpy(dr_zcg, zcg, sizeof(dr_zcg));
139         my_memcpy(dr_aen_line, aen_line, sizeof(dr_aen_line));
140         my_memcpy(dr_zpalette_pc, zpalette_pc, sizeof(zpalette_pc));
141         zpalette_pc[8 + 0] = zpalette_pc[16 + 0x000];
142         zpalette_pc[8 + 1] = zpalette_pc[16 + 0x00f];
143         zpalette_pc[8 + 2] = zpalette_pc[16 + 0x0f0];
144         zpalette_pc[8 + 3] = zpalette_pc[16 + 0x0ff];
145         zpalette_pc[8 + 4] = zpalette_pc[16 + 0xf00];
146         zpalette_pc[8 + 5] = zpalette_pc[16 + 0xf0f];
147         zpalette_pc[8 + 6] = zpalette_pc[16 + 0xff0];
148         zpalette_pc[8 + 7] = zpalette_pc[16 + 0xfff];
149 #endif
150
151         PrepareBitTransTableUint16(&bit_trans_table_b0, 0x01, 0x00);
152         PrepareBitTransTableUint16(&bit_trans_table_r0, 0x02, 0x00);
153         PrepareBitTransTableUint16(&bit_trans_table_g0, 0x04, 0x00);
154 }
155
156 void DISPLAY::reset()
157 {
158 #ifdef _X1TURBO_FEATURE
159         mode1 = 0;//3;
160         mode2 = 0;
161         hireso = true;
162         emu->set_vm_screen_lines(400);
163 #else
164         emu->set_vm_screen_lines(200);
165 #endif
166 #ifdef _X1TURBOZ
167         zmode1 = 0;
168         zpriority = 0;
169         zadjust = 0;
170         zmosaic = 0;
171         zchromakey = 0;
172         zscroll = 0;
173         zmode2 = 0;
174         zpal_num = 0;
175 #endif
176         cur_line = cur_code = 0;
177         vblank_clock = 0;
178         cur_vline = 0;
179         cur_blank = true;
180
181         kaddr = kofs = kflag = 0;
182         kanji_ptr = &kanji[0];
183
184         // Copy images to draw buffers.
185         my_memcpy(dr_text, text, sizeof(dr_text));
186         my_memcpy(dr_cg, cg, sizeof(dr_cg));
187         my_memcpy(dr_pri_line, pri_line, sizeof(dr_pri_line));
188         my_memcpy(dr_palette_pc, palette_pc, sizeof(dr_palette_pc));
189         dr_priority = priority;
190 #ifdef _X1TURBOZ
191         dr_zpriority = zpriority;
192         my_memcpy(dr_zcg, zcg, sizeof(dr_zcg));
193         my_memcpy(dr_aen_line, aen_line, sizeof(dr_aen_line));
194         my_memcpy(dr_zpalette_pc, zpalette_pc, sizeof(zpalette_pc));
195         zpalette_pc[8 + 0] = zpalette_pc[16 + 0x000];
196         zpalette_pc[8 + 1] = zpalette_pc[16 + 0x00f];
197         zpalette_pc[8 + 2] = zpalette_pc[16 + 0x0f0];
198         zpalette_pc[8 + 3] = zpalette_pc[16 + 0x0ff];
199         zpalette_pc[8 + 4] = zpalette_pc[16 + 0xf00];
200         zpalette_pc[8 + 5] = zpalette_pc[16 + 0xf0f];
201         zpalette_pc[8 + 6] = zpalette_pc[16 + 0xff0];
202         zpalette_pc[8 + 7] = zpalette_pc[16 + 0xfff];
203 #endif
204 }
205
206 void DISPLAY::write_io8(uint32_t addr, uint32_t data)
207 {
208         switch(addr & 0xff00) {
209         case 0x0e00:
210                 write_kanji(addr, data);
211                 break;
212         case 0x1000:
213 #ifdef _X1TURBOZ
214                 if(AEN) {
215                         if(APEN && !APRD) {
216                                 if(!cur_blank) {
217                                         // wait next blank
218                                         d_cpu->write_signal(SIG_CPU_WAIT, 1, 1);
219                                 }
220                                 int num = get_zpal_num(addr, data);
221                                 if(zpal[num].b != (data & 0x0f)) {
222                                         zpal[num].b = data & 0x0f;
223                                         zpalette_tmp[num + 16] = RGB_COLOR((zpal[num].r * 255) / 15, (zpal[num].g * 255) / 15, (zpal[num].b * 255) / 15);
224                                         zpalette_changed = true;
225                                 }
226                         } else if(APEN && APRD) {
227                                 zpal_num = get_zpal_num(addr, data);
228                         }
229                 } else
230 #endif
231                 {
232                         pal[0] = data;
233                         update_pal();
234                 }
235                 break;
236         case 0x1100:
237 #ifdef _X1TURBOZ
238                 if(AEN) {
239                         if(APEN && !APRD) {
240                                 if(!cur_blank) {
241                                         // wait next blank
242                                         d_cpu->write_signal(SIG_CPU_WAIT, 1, 1);
243                                 }
244                                 int num = get_zpal_num(addr, data);
245                                 if(zpal[num].r != (data & 0x0f)) {
246                                         zpal[num].r = data & 0x0f;
247                                         zpalette_tmp[num + 16] = RGB_COLOR((zpal[num].r * 255) / 15, (zpal[num].g * 255) / 15, (zpal[num].b * 255) / 15);
248                                         zpalette_changed = true;
249                                 }
250                         } else if(APEN && APRD) {
251 //                              zpal_num = get_zpal_num(addr, data);
252                         }
253                 } else
254 #endif
255                 {
256                         pal[1] = data;
257                         update_pal();
258                 }
259                 break;
260         case 0x1200:
261 #ifdef _X1TURBOZ
262                 if(AEN) {
263                         if(APEN && !APRD) {
264                                 if(!cur_blank) {
265                                         // wait next blank
266                                         d_cpu->write_signal(SIG_CPU_WAIT, 1, 1);
267                                 }
268                                 int num = get_zpal_num(addr, data);
269                                 if(zpal[num].g != (data & 0x0f)) {
270                                         zpal[num].g = data & 0x0f;
271                                         zpalette_tmp[num + 16] = RGB_COLOR((zpal[num].r * 255) / 15, (zpal[num].g * 255) / 15, (zpal[num].b * 255) / 15);
272                                         zpalette_changed = true;
273                                 }
274                         } else if(APEN && APRD) {
275 //                              zpal_num = get_zpal_num(addr, data);
276                         }
277                 } else
278 #endif
279                 {
280                         pal[2] = data;
281                         update_pal();
282                 }
283                 break;
284         case 0x1300:
285                 priority = data;
286                 update_pal();
287                 break;
288         case 0x1500:
289                 get_cur_pcg(addr);
290                 pcg_b[cur_code][cur_line] = data;
291 #ifdef _X1TURBO_FEATURE
292                 gaiji_b[cur_code >> 1][(cur_line << 1) | (cur_code & 1)] = data;
293 #endif
294                 break;
295         case 0x1600:
296                 get_cur_pcg(addr);
297                 pcg_r[cur_code][cur_line] = data;
298 #ifdef _X1TURBO_FEATURE
299                 gaiji_r[cur_code >> 1][(cur_line << 1) | (cur_code & 1)] = data;
300 #endif
301                 break;
302         case 0x1700:
303                 get_cur_pcg(addr);
304                 pcg_g[cur_code][cur_line] = data;
305 #ifdef _X1TURBO_FEATURE
306                 gaiji_g[cur_code >> 1][(cur_line << 1) | (cur_code & 1)] = data;
307 #endif
308                 break;
309 #ifdef _X1TURBO_FEATURE
310         case 0x1f00:
311                 switch(addr) {
312 #ifdef _X1TURBOZ
313                 case 0x1fb0:
314                         zmode1 = data;
315                         break;
316 //              case 0x1fb8:
317                 case 0x1fb9:
318                 case 0x1fba:
319                 case 0x1fbb:
320                 case 0x1fbc:
321                 case 0x1fbd:
322                 case 0x1fbe:
323                 case 0x1fbf:
324                         if(AEN) {
325                                 if(ztpal[addr & 7] != data) {
326                                         ztpal[addr & 7] = data;
327                                         zpalette_tmp[addr & 7] = RGB_COLOR((((data >> 2) & 3) * 255) / 3, (((data >> 4) & 3) * 255) / 3, (((data >> 0) & 3) * 255) / 3);
328                                         zpalette_changed = true;
329                                 }
330                         }
331                         break;
332                 case 0x1fc0:
333                         if(AEN) {
334                                 zpriority = data;
335                         }
336                         break;
337                 case 0x1fc1:
338                         if(AEN) {
339                                 zadjust = data;
340                         }
341                         break;
342                 case 0x1fc2:
343                         if(AEN) {
344                                 zmosaic = data;
345                         }
346                         break;
347                 case 0x1fc3:
348                         if(AEN) {
349                                 zchromakey = data;
350                         }
351                         break;
352                 case 0x1fc4:
353                         if(AEN) {
354                                 zscroll = data;
355                         }
356                         break;
357                 case 0x1fc5:
358                         if(AEN) {
359                                 zmode2 = data;
360                         }
361                         break;
362 #endif
363                 case 0x1fd0:
364                         mode1 = data;
365                         update_crtc();
366 //                      hireso = !((mode1 & 3) == 0 || (mode1 & 3) == 2);
367                         break;
368                 case 0x1fe0:
369                         mode2 = data;
370                         update_pal();
371                         break;
372                 }
373                 break;
374 #endif
375         case 0x2000:
376         case 0x2100:
377         case 0x2200:
378         case 0x2300:
379         case 0x2400:
380         case 0x2500:
381         case 0x2600:
382         case 0x2700:
383                 vram_a[addr & 0x7ff] = data;
384                 break;
385         case 0x2800:
386         case 0x2900:
387         case 0x2a00:
388         case 0x2b00:
389         case 0x2c00:
390         case 0x2d00:
391         case 0x2e00:
392         case 0x2f00:
393                 vram_a[addr & 0x7ff] = data; // mirror
394                 break;
395         case 0x3000:
396         case 0x3100:
397         case 0x3200:
398         case 0x3300:
399         case 0x3400:
400         case 0x3500:
401         case 0x3600:
402         case 0x3700:
403                 vram_t[addr & 0x7ff] = data;
404                 break;
405         case 0x3800:
406         case 0x3900:
407         case 0x3a00:
408         case 0x3b00:
409         case 0x3c00:
410         case 0x3d00:
411         case 0x3e00:
412         case 0x3f00:
413 #ifdef _X1TURBO_FEATURE
414                 vram_k[addr & 0x7ff] = data;
415 #else
416                 vram_t[addr & 0x7ff] = data; // mirror
417 #endif
418                 break;
419         }
420 }
421
422 uint32_t DISPLAY::read_io8(uint32_t addr)
423 {
424         switch(addr & 0xff00) {
425         case 0x0e00:
426                 return read_kanji(addr);
427 #ifdef _X1TURBOZ
428         case 0x1000:
429                 if(AEN && APEN && APRD) {
430                         return zpal[zpal_num].b;
431                 }
432                 break;
433         case 0x1100:
434                 if(AEN && APEN && APRD) {
435                         return zpal[zpal_num].r;
436                 }
437                 break;
438         case 0x1200:
439                 if(AEN && APEN && APRD) {
440                         return zpal[zpal_num].g;
441                 }
442                 break;
443 #endif
444 //      case 0x1300:
445 //              return priority;
446         case 0x1400:
447                 return get_cur_font(addr);
448         case 0x1500:
449                 get_cur_pcg(addr);
450                 return pcg_b[cur_code][cur_line];
451         case 0x1600:
452                 get_cur_pcg(addr);
453                 return pcg_r[cur_code][cur_line];
454         case 0x1700:
455                 get_cur_pcg(addr);
456                 return pcg_g[cur_code][cur_line];
457 #ifdef _X1TURBOZ
458         case 0x1f00:
459                 switch(addr) {
460                 case 0x1fb0:
461                         return zmode1;
462 //              case 0x1fb8:
463                 case 0x1fb9:
464                 case 0x1fba:
465                 case 0x1fbb:
466                 case 0x1fbc:
467                 case 0x1fbd:
468                 case 0x1fbe:
469                 case 0x1fbf:
470                         if(AEN) {
471                                 return ztpal[addr & 7];
472                         }
473                         break;
474                 case 0x1fc0:
475                         if(AEN) {
476                                 return zpriority;
477                         }
478                         break;
479                 case 0x1fc1:
480                         if(AEN) {
481                                 return zadjust;
482                         }
483                         break;
484                 case 0x1fc2:
485                         if(AEN) {
486                                 return zmosaic;
487                         }
488                         break;
489                 case 0x1fc3:
490                         if(AEN) {
491                                 return zchromakey;
492                         }
493                         break;
494                 case 0x1fc4:
495                         if(AEN) {
496                                 return zscroll;
497                         }
498                         break;
499                 case 0x1fc5:
500                         if(AEN) {
501                                 return zmode2;
502                         }
503                         break;
504                 case 0x1fd0:
505                         return mode1;
506                 case 0x1fe0:
507                         return mode2;
508                 }
509                 break;
510 #endif
511         case 0x2000:
512         case 0x2100:
513         case 0x2200:
514         case 0x2300:
515         case 0x2400:
516         case 0x2500:
517         case 0x2600:
518         case 0x2700:
519                 return vram_a[addr & 0x7ff];
520         case 0x2800:
521         case 0x2900:
522         case 0x2a00:
523         case 0x2b00:
524         case 0x2c00:
525         case 0x2d00:
526         case 0x2e00:
527         case 0x2f00:
528                 return vram_a[addr & 0x7ff]; // mirror
529         case 0x3000:
530         case 0x3100:
531         case 0x3200:
532         case 0x3300:
533         case 0x3400:
534         case 0x3500:
535         case 0x3600:
536         case 0x3700:
537                 return vram_t[addr & 0x7ff];
538         case 0x3800:
539         case 0x3900:
540         case 0x3a00:
541         case 0x3b00:
542         case 0x3c00:
543         case 0x3d00:
544         case 0x3e00:
545         case 0x3f00:
546 #ifdef _X1TURBO_FEATURE
547                 return vram_k[addr & 0x7ff];
548 #else
549                 return vram_t[addr & 0x7ff]; // mirror
550 #endif
551         }
552         return 0xff;
553 }
554
555 void DISPLAY::write_signal(int id, uint32_t data, uint32_t mask)
556 {
557         if(id == SIG_DISPLAY_VBLANK) {
558                 if(!(data & mask)) {
559                         // enter vblank
560                         vblank_clock = get_current_clock();
561                 }
562         } else if(id == SIG_DISPLAY_COLUMN40) {
563                 column40 = ((data & mask) != 0);
564                 update_crtc();
565         } else if(id == SIG_DISPLAY_DETECT_VBLANK) {
566                 // hack: cpu detects vblank
567                 vblank_clock = get_current_clock();
568         } else if(id == SIG_DISPLAY_DISP) {
569                 bool prev = cur_blank;
570                 cur_blank = ((data & mask) == 0); // blank = not disp
571                 if(!prev && cur_blank) {
572                         // draw line at start of hblank
573 #ifdef _X1TURBO_FEATURE
574                         if(hireso) {
575                                 if(cur_vline < 400) {
576                                         draw_line(cur_vline);
577                                 }
578                         } else {
579 #endif
580                                 if(cur_vline < 200) {
581                                         draw_line(cur_vline);
582                                 }
583 #ifdef _X1TURBO_FEATURE
584                         }
585                         // restart cpu after pcg/cgrom/zpal is accessed
586 //                      d_cpu->write_signal(SIG_CPU_WAIT, 0, 0);
587                         register_event_by_clock(this, EVENT_AFTER_BLANK, 24, false, NULL);
588 #endif
589                 }
590         }
591 }
592
593 void DISPLAY::event_frame()
594 {
595         cblink = (cblink + 1) & 0x3f;
596
597         // update crtc parameters
598         ch_height = (regs[9] & 0x1f) + 1;
599         hz_total = regs[0] + 1;
600         hz_disp = regs[1];
601         vt_disp = regs[6] & 0x7f;
602         vt_ofs = regs[5] & 0x1f;
603         st_addr = (regs[12] << 8) | regs[13];
604 #ifdef _X1TURBO_FEATURE
605         int vt_total = ((regs[4] & 0x7f) + 1) * ch_height + (regs[5] & 0x1f);
606         bool hireso_old = hireso;
607         hireso = (vt_total >= 400);
608         if(!hireso) vt_ofs = max(vt_ofs - 2, 0);
609 #else
610         vt_ofs = max(vt_ofs - 2, 0);
611 #endif
612         int vlen;
613 #ifdef _X1TURBO_FEATURE
614         vlen = (hireso) ? 400 : 200;
615 //      if(hireso_old != hireso) {
616 //              emu->set_vm_screen_lines(vlen);
617 //      }
618 #else
619         vlen = 200;
620 #endif
621         if(vlen > 0) {
622                 // Copy images to draw buffers.
623                 my_memcpy(dr_text, text, sizeof(uint8_t) * vlen * (640 + 8));
624                 my_memcpy(dr_cg, cg, sizeof(uint8_t) * vlen * 640);
625                 my_memcpy(dr_pri_line, pri_line, sizeof(uint8_t) * vlen * 8 * 8);
626         }
627         my_memcpy(dr_palette_pc, palette_pc, sizeof(dr_palette_pc));
628         dr_priority = priority;
629         // initialize draw screen
630         memset(text, 0, sizeof(text));
631         memset(cg, 0, sizeof(cg));
632         memset(pri_line, 0, sizeof(pri_line));
633 #ifdef _X1TURBOZ
634         if(vlen > 0) {
635         // Copy images to draw buffers.
636                 my_memcpy(&(dr_zcg[0][0][0]), &(zcg[0][0][0]), sizeof(uint8_t) * vlen * 640);
637                 //my_memcpy(dr_aen_line, aen_line, sizeof(bool) * vlen);
638         }
639         my_memcpy(dr_aen_line, aen_line, sizeof(aen_line));
640         dr_zpriority = zpriority;
641         my_memcpy(dr_zpalette_pc, zpalette_pc, sizeof(zpalette_pc));
642         zpalette_pc[8 + 0] = zpalette_pc[16 + 0x000];
643         zpalette_pc[8 + 1] = zpalette_pc[16 + 0x00f];
644         zpalette_pc[8 + 2] = zpalette_pc[16 + 0x0f0];
645         zpalette_pc[8 + 3] = zpalette_pc[16 + 0x0ff];
646         zpalette_pc[8 + 4] = zpalette_pc[16 + 0xf00];
647         zpalette_pc[8 + 5] = zpalette_pc[16 + 0xf0f];
648         zpalette_pc[8 + 6] = zpalette_pc[16 + 0xff0];
649         zpalette_pc[8 + 7] = zpalette_pc[16 + 0xfff];
650
651         memset(zcg, 0, sizeof(zcg));
652         memset(aen_line, 0, sizeof(aen_line));
653 #endif
654         prev_vert_double = false;
655         raster = 0;
656 }
657
658 void DISPLAY::event_vline(int v, int clock)
659 {
660 #ifdef _X1TURBOZ
661 //      if(zpalette_changed && v == (hireso ? 400 : 200)) {
662         if(zpalette_changed && v == 0) {
663                 update_zpalette();
664                 zpalette_changed = false;
665         }
666 #endif
667         cur_vline = v;
668
669 #if 0
670         // Copy images to draw buffers.
671         int vlimit;
672 #ifdef _X1TURBO_FEATURE
673         vlimit = (hireso) ? 400 : 200;
674 #else
675         vlimit = 200;
676 #endif
677         if((v > vlimit) || (v < 0)) return;
678
679         if(v == vlimit) {
680                 my_memcpy(dr_palette_pc, palette_pc, sizeof(palette_pc));
681 #ifdef _X1TURBOZ
682                 my_memcpy(dr_zpalette_pc, zpalette_pc, sizeof(zpalette_pc));
683 #endif
684                 // Copy images to draw buffers.
685                 //my_memcpy(&(dr_text[v][0]), &(text[v][0]), sizeof(uint8_t) * (640 + 8));
686                 //my_memcpy(&(dr_cg[v][0]), &(cg[v][0]), sizeof(uint8_t) * 640);
687                 //my_memcpy(&(dr_pri_line[v][0][0]), &(pri_line[v][0][0]), sizeof(uint8_t) * 8 * 8);
688 #ifdef _X1TURBOZ
689                 //my_memcpy(&(dr_zcg[0][v][0]), &(zcg[0][v][0]), sizeof(uint8_t) * 640);
690                 //my_memcpy(&(dr_zcg[1][v][0]), &(zcg[1][v][0]), sizeof(uint8_t) * 640);
691                 //dr_aen_line[v] = aen_line[v];
692 #endif
693         } else if(v == 0) {
694                 return;
695         }
696         // Copy images to draw buffers.
697         my_memcpy(&(dr_text[v - 1][0]), &(text[v - 1][0]), sizeof(uint8_t) * (640 + 8));
698         my_memcpy(&(dr_cg[v - 1][0]), &(cg[v -1 ][0]), sizeof(uint8_t) * 640);
699         my_memcpy(&(dr_pri_line[v - 1][0][0]), &(pri_line[v - 1][0][0]), sizeof(uint8_t) * 8 * 8);
700         dr_priority = priority;
701 #ifdef _X1TURBOZ
702         my_memcpy(&(dr_zcg[0][v - 1 ][0]), &(zcg[0][v - 1][0]), sizeof(uint8_t) * 640);
703         my_memcpy(&(dr_zcg[1][v - 1][0]), &(zcg[1][v - 1][0]), sizeof(uint8_t) * 640);
704         dr_zpriority = zpriority;
705         dr_aen_line[v - 1] = aen_line[v - 1];
706 #endif
707 #endif
708 }
709
710 #ifdef _X1TURBO_FEATURE
711 void DISPLAY::event_callback(int event_id, int err)
712 {
713         if(event_id == EVENT_AFTER_BLANK) {
714                 // restart cpu after pcg/cgrom/zpal is accessed
715                 d_cpu->write_signal(SIG_CPU_WAIT, 0, 0);
716         }
717 }
718 #endif
719
720 void DISPLAY::update_crtc()
721 {
722 #ifdef _X1TURBO_FEATURE
723         if(column40) {
724                 d_crtc->set_char_clock((mode1 & 1) ? VDP_CLOCK * 1.5 / 32.0 : VDP_CLOCK / 32.0);
725         } else {
726                 d_crtc->set_char_clock((mode1 & 1) ? VDP_CLOCK * 1.5 / 16.0 : VDP_CLOCK / 16.0);
727         }
728 #else
729         if(column40) {
730                 d_crtc->set_char_clock(VDP_CLOCK / 32.0);
731         } else {
732                 d_crtc->set_char_clock(VDP_CLOCK / 16.0);
733         }
734 #endif
735 }
736
737 void DISPLAY::update_pal()
738 {
739         uint8_t pal2[8];
740         for(int i = 0; i < 8; i++) {
741                 uint8_t bit = 1 << i;
742                 pal2[i] = ((pal[0] & bit) ? 1 : 0) | ((pal[1] & bit) ? 2 : 0) | ((pal[2] & bit) ? 4 : 0) | 8;
743         }
744 #ifdef _X1TURBO_FEATURE
745         if(mode2 & 0x10) pal2[0] = 8;
746         if(mode2 & 0x20) pal2[1] = 8;
747 #endif
748         for(int c = 0; c < 8; c++) {
749                 for(int t = 0; t < 8; t++) {
750                         if(priority & (1 << c)) {
751                                 pri[c][t] = pal2[c];
752                         } else if(t) {
753 #ifdef _X1TURBO_FEATURE
754                                 pri[c][t] = ((mode2 & 8) && (mode2 & 7) == t) ? 0 : t;
755 #else
756                                 pri[c][t] = t;
757 #endif
758                         } else {
759                                 pri[c][t] = pal2[c];
760                         }
761                 }
762         }
763 }
764
765 uint8_t DISPLAY::get_cur_font(uint32_t addr)
766 {
767 #ifdef _X1TURBO_FEATURE
768         if(mode1 & 0x20) {
769                 // wait next blank
770                 d_cpu->write_signal(SIG_CPU_WAIT, 1, 1);
771
772                 // from X1EMU
773                 uint16_t vaddr;
774                 if(!(vram_a[0x7ff] & 0x20)) {
775                         vaddr = 0x7ff;
776                 } else if(!(vram_a[0x3ff] & 0x20)) {
777                         vaddr = 0x3ff;
778                 } else if(!(vram_a[0x5ff] & 0x20)) {
779                         vaddr = 0x5ff;
780                 } else if(!(vram_a[0x1ff] & 0x20)) {
781                         vaddr = 0x1ff;
782                 } else {
783                         vaddr = 0x3ff;
784                 }
785                 uint16_t ank = vram_t[vaddr];
786                 uint16_t knj = vram_k[vaddr];
787
788                 if(knj & 0x80) {
789                         uint32_t ofs = adr2knj_x1t((knj << 8) | ank);
790                         if(knj & 0x40) {
791                                 ofs += 16; // right
792                         }
793                         return kanji[ofs | (addr & 15)];
794                 } else if(mode1 & 0x40) {
795                         return kanji[(ank << 4) | (addr & 15)];
796                 } else {
797                         return font[(ank << 3) | ((addr >> 1) & 7)];
798                 }
799         }
800 #endif
801         get_cur_code_line();
802         return font[(cur_code << 3) | (cur_line & 7)];
803 }
804
805 void DISPLAY::get_cur_pcg(uint32_t addr)
806 {
807 #ifdef _X1TURBO_FEATURE
808         if(mode1 & 0x20) {
809                 // wait next blank
810                 d_cpu->write_signal(SIG_CPU_WAIT, 1, 1);
811
812                 // from X1EMU
813                 uint16_t vaddr;
814                 if(vram_a[0x7ff] & 0x20) {
815                         vaddr = 0x7ff;
816                 } else if(vram_a[0x3ff] & 0x20) {
817                         vaddr = 0x3ff;
818                 } else if(vram_a[0x5ff] & 0x20) {
819                         vaddr = 0x5ff;
820                 } else if(vram_a[0x1ff] & 0x20) {
821                         vaddr = 0x1ff;
822                 } else {
823                         vaddr = 0x3ff;
824                 }
825                 cur_code = vram_t[vaddr];
826                 cur_line = (addr >> 1) & 7;
827
828                 if(vram_k[vaddr] & 0x90) {
829                         cur_code &= 0xfe;
830                         cur_code += addr & 1;
831                 }
832         } else
833 #endif
834                 get_cur_code_line();
835 }
836
837 void DISPLAY::get_cur_code_line()
838 {
839 //#ifdef _X1TURBO_FEATURE
840 //      int ht_clock = hireso ? 161 : 250;
841 //#else
842 #define ht_clock 250
843 //#endif
844         int clock = get_passed_clock(vblank_clock);
845         int vt_line = vt_disp * ch_height + (int)(clock / ht_clock);
846
847         int addr = (hz_total * (clock % ht_clock)) / ht_clock;
848         addr += hz_disp * (int)(vt_line / ch_height);
849         addr &= 0x7ff; // thanks Mr.YAT
850         addr += st_addr;
851
852         cur_code = vram_t[addr & 0x7ff];
853         cur_line = (vt_line % ch_height) & 7;
854 }
855
856 void DISPLAY::draw_line(int v)
857 {
858         if((regs[8] & 0x30) != 0x30) {
859                 if((v % ch_height) == 0) {
860                         draw_text(v / ch_height);
861                 }
862 #ifdef _X1TURBOZ
863                 if(AEN && !hireso && column40) {
864                         draw_cg(v, 1);
865                 }
866 #endif
867                 draw_cg(v, 0);
868                 memcpy(&pri_line[v][0][0], &pri[0][0], sizeof(pri));
869 //      } else {
870 //              memset(&pri_line[v][0][0], 0, sizeof(pri));
871         }
872 #ifdef _X1TURBOZ
873         aen_line[v] = AEN;
874 #endif
875 }
876
877 void DISPLAY::draw_screen()
878 {
879         if(emu->now_waiting_in_debugger) {
880                 // draw lines
881 #ifdef _X1TURBO_FEATURE
882                 for(int v = 0; v < (hireso ? 400 : 200); v++) {
883 #else
884                 for(int v = 0; v < 200; v++) {
885 #endif
886                         draw_line(v);
887                 }
888 #ifdef _X1TURBOZ
889                 if(zpalette_changed && cur_vline < (hireso ? 400 : 200)) {
890                         update_zpalette();
891                         zpalette_changed = false;
892                 }
893 #endif
894         }
895
896         // total raster_adjust
897 #ifdef _X1TURBO_FEATURE
898         for(int y = 0; y < vt_ofs * (hireso ? 1 : 2); y++) {
899 #else
900         for(int y = 0; y < vt_ofs * 2; y++) {
901 #endif
902                 scrntype_t* dest = emu->get_screen_buffer(y);
903                 memset(dest, 0, 640 * sizeof(scrntype_t));
904         }
905
906         // copy to real screen
907         __DECL_ALIGNED(16) scrntype_t dbuf[640];
908 #ifdef _X1TURBO_FEATURE
909         if(hireso) {
910                 // 400 lines
911 //              emu->set_vm_screen_lines(400);
912                 if(column40) {
913                         // 40 columns
914                         for(int y = 0; (y + vt_ofs) < 400; y++) {
915                                 scrntype_t* dest = emu->get_screen_buffer(y + vt_ofs);
916                                 uint8_t* src_text = dr_text[y];
917 #ifdef _X1TURBOZ
918                                 if(dr_aen_line[y]) {
919                                         uint16_t* src_cg0 = dr_zcg[0][y];
920
921                                         for(int x = 0, x2 = 0; x < 320; x++, x2 += 2) {
922                                                 uint16_t cg00 = src_cg0[x] | (src_cg0[x] >> 2);
923
924                                                 dbuf[x2] = dbuf[x2 + 1] = get_zpriority(src_text[x], cg00, cg00);
925                                         }
926                                 } else {
927 #endif
928                                         uint8_t* src_cg = dr_cg[y];
929
930                                         for(int x = 0, x2 = 0; x < 320; x++, x2 += 2) {
931 #ifdef _X1TURBOZ
932                                                 dbuf[x2] = dbuf[x2 + 1] = dr_zpalette_pc[dr_pri_line[y][src_cg[x]][src_text[x]]];
933 #else
934                                                 dbuf[x2] = dbuf[x2 + 1] =  dr_palette_pc[dr_pri_line[y][src_cg[x]][src_text[x]]];
935 #endif
936                                         }
937 #ifdef _X1TURBOZ
938                                 }
939 #endif
940 __DECL_VECTORIZED_LOOP
941                                 for(int xx = 0; xx < 640; xx++) {
942                                         dest[xx] = dbuf[xx];
943                                 }
944                         }
945                 } else {
946                         // 80 columns
947                         for(int y = 0; (y + vt_ofs) < 400; y++) {
948                                 scrntype_t* dest = emu->get_screen_buffer(y + vt_ofs);
949                                 uint8_t* src_text = dr_text[y];
950 #ifdef _X1TURBOZ
951                                 if(dr_aen_line[y]) {
952                                         uint16_t* src_cg0 = dr_zcg[0][y];
953
954                                         for(int x = 0; x < 640; x++) {
955                                                 uint16_t cg00 = src_cg0[x] | (src_cg0[x] >> 2);
956
957                                                 dbuf[x] = get_zpriority(src_text[x], cg00, cg00);
958                                         }
959                                 } else {
960 #endif
961                                         uint8_t* src_cg = dr_cg[y];
962
963                                         for(int x = 0; x < 640; x++) {
964 #ifdef _X1TURBOZ
965                                                 dbuf[x] = dr_zpalette_pc[dr_pri_line[y][src_cg[x]][src_text[x]]];
966 #else
967                                                 dbuf[x] =  dr_palette_pc[dr_pri_line[y][src_cg[x]][src_text[x]]];
968 #endif
969                                         }
970 #ifdef _X1TURBOZ
971                                 }
972 #endif
973 __DECL_VECTORIZED_LOOP
974                                 for(int xx = 0; xx < 640; xx++) {
975                                         dest[xx] = dbuf[xx];
976                                 }
977                         }
978                 }
979                 emu->screen_skip_line(false);
980         } else {
981 #endif
982 //              emu->set_vm_screen_lines(200);
983                 // 200 lines
984 //              emu->set_vm_screen_lines(200);
985
986                 if(column40) {
987                         // 40 columns
988                         for(int y = 0; (y + vt_ofs) < 200; y++) {
989                                 scrntype_t* dest0 = emu->get_screen_buffer((y + vt_ofs) * 2 + 0);
990                                 scrntype_t* dest1 = emu->get_screen_buffer((y + vt_ofs) * 2 + 1);
991                                 uint8_t* src_text = dr_text[y];
992 #ifdef _X1TURBOZ
993                                 if(dr_aen_line[y]) {
994                                         uint16_t* src_cg0 = dr_zcg[0][y];
995                                         uint16_t* src_cg1 = dr_zcg[1][y];
996
997                                         if(C64) {
998                                                 for(int x = 0, x2 = 0; x < 320; x++, x2 += 2) {
999                                                         uint16_t cg00 = src_cg0[x];// | (src_cg0[x] >> 2);
1000                                                         uint16_t cg11 = src_cg1[x];// | (src_cg1[x] >> 2);
1001
1002                                                         dbuf[x2] = dbuf[x2 + 1] = get_zpriority(src_text[x], cg00, cg11);
1003                                                 }
1004                                         } else {
1005                                                 for(int x = 0, x2 = 0; x < 320; x++, x2 += 2) {
1006                                                         uint16_t cg01 = src_cg0[x] | (src_cg1[x] >> 2);
1007
1008                                                         dbuf[x2] = dbuf[x2 + 1] = get_zpriority(src_text[x], cg01, cg01);
1009                                                 }
1010
1011                                         }
1012                                 } else {
1013 #endif
1014 //                                      scrntype_t* dest = emu->get_screen_buffer(y);
1015                                         uint8_t* src_cg = dr_cg[y];
1016
1017                                         for(int x = 0, x2 = 0; x < 320; x++, x2 += 2) {
1018 #ifdef _X1TURBOZ
1019                                                 dbuf[x2] = dbuf[x2 + 1] = dr_zpalette_pc[dr_pri_line[y][src_cg[x]][src_text[x]]];
1020 #else
1021                                                 dbuf[x2] = dbuf[x2 + 1] =  dr_palette_pc[dr_pri_line[y][src_cg[x]][src_text[x]]];
1022 #endif
1023                                         }
1024 #ifdef _X1TURBOZ
1025                                 }
1026 #endif
1027 __DECL_VECTORIZED_LOOP
1028                                 for(int xx = 0; xx < 640; xx++) {
1029                                         dest0[xx] = dbuf[xx];
1030                                 }
1031                                 if(!config.scan_line) {
1032 __DECL_VECTORIZED_LOOP
1033                                         for(int xx = 0; xx < 640; xx++) {
1034                                                 dest1[xx] = dbuf[xx];
1035                                         }
1036                                 } else {
1037                                         memset(dest1, 0, 640 * sizeof(scrntype_t));
1038                                 }
1039                         }
1040                 } else {
1041                         // 80 columns
1042                         for(int y = 0; (y + vt_ofs) < 200; y++) {
1043                                 scrntype_t* dest0 = emu->get_screen_buffer((y + vt_ofs) * 2 + 0);
1044                                 scrntype_t* dest1 = emu->get_screen_buffer((y + vt_ofs) * 2 + 1);
1045                                 uint8_t* src_text = dr_text[y];
1046 #ifdef _X1TURBOZ
1047                                 if(aen_line[y]) {
1048                                         uint16_t* src_cg0 = dr_zcg[0][y];
1049
1050                                         for(int x = 0; x < 640; x++) {
1051                                                 uint16_t cg00 = src_cg0[x];// | (src_cg0[x] >> 2);
1052
1053                                                 dbuf[x] = get_zpriority(src_text[x], cg00, cg00);
1054                                         }
1055                                 } else {
1056 #endif
1057                                         uint8_t* src_cg = dr_cg[y];
1058 //__DECL_VECTORIZED_LOOP
1059                                         for(int x = 0; x < 640; x++) {
1060 #ifdef _X1TURBOZ
1061                                                 dbuf[x] = dr_zpalette_pc[dr_pri_line[y][src_cg[x]][src_text[x]]];
1062 #else
1063                                                 dbuf[x] =  dr_palette_pc[dr_pri_line[y][src_cg[x]][src_text[x]]];
1064 #endif
1065                                         }
1066 __DECL_VECTORIZED_LOOP
1067                 for(int xx = 0; xx < 640; xx++) {
1068                         dest0[xx] = dbuf[xx];
1069                 }
1070                 if(!config.scan_line) {
1071 __DECL_VECTORIZED_LOOP
1072                         for(int xx = 0; xx < 640; xx++) {
1073                                 dest1[xx] = dbuf[xx];
1074                         }
1075                 } else {
1076                         memset(dest1, 0, 640 * sizeof(scrntype_t));
1077                 }
1078 #ifdef _X1TURBOZ
1079                                 }
1080 #endif
1081                         }
1082                 }
1083                 emu->screen_skip_line(true);
1084 #ifdef _X1TURBO_FEATURE
1085         }
1086 #endif
1087 }
1088
1089 void DISPLAY::draw_text(int y)
1090 {
1091         int width = column40 ? 40 : 80;
1092         uint16_t src = st_addr + hz_disp * y;
1093
1094         bool cur_vert_double = true;
1095         uint8_t prev_attr = 0, prev_pattern_b[32], prev_pattern_r[32], prev_pattern_g[32];
1096
1097         for(int x = 0; x < hz_disp && x < width; x++) {
1098                 src &= 0x7ff;
1099                 uint8_t code = vram_t[src];
1100 #ifdef _X1TURBO_FEATURE
1101                 uint8_t knj = vram_k[src];
1102 #endif
1103                 uint8_t attr = vram_a[src];
1104                 src++;
1105
1106                 uint8_t col = attr & 7;
1107                 bool reverse = ((attr & 8) != 0);
1108                 bool blink = ((attr & 0x10) && (cblink & 0x20));
1109                 reverse = (reverse != blink);
1110
1111                 // select pcg or ank
1112                 const uint8_t *pattern_b, *pattern_r, *pattern_g;
1113 #ifdef _X1TURBO_FEATURE
1114                 int shift = 0;
1115                 int max_line = 8;
1116 #else
1117 #define max_line 8
1118 #endif
1119                 if(attr & 0x20) {
1120                         // pcg
1121 #ifdef _X1TURBO_FEATURE
1122                         if(knj & 0x90) {
1123                                 pattern_b = gaiji_b[code >> 1];
1124                                 pattern_r = gaiji_r[code >> 1];
1125                                 pattern_g = gaiji_g[code >> 1];
1126                                 max_line = 16;
1127                         } else {
1128 #endif
1129                                 pattern_b = pcg_b[code];
1130                                 pattern_r = pcg_r[code];
1131                                 pattern_g = pcg_g[code];
1132 #ifdef _X1TURBO_FEATURE
1133                                 shift = (mode1 & 1) ? 1 : 0;
1134                         }
1135 #endif
1136 #ifdef _X1TURBO_FEATURE
1137                 } else if(knj & 0x80) {
1138                         uint32_t ofs = adr2knj_x1t((knj << 8) | code);
1139                         if(knj & 0x40) {
1140                                 ofs += 16; // right
1141                         }
1142                         pattern_b = pattern_r = pattern_g = &kanji[ofs];
1143                         max_line = 16;
1144                 } else if((mode1 & 5) != 0) {
1145                         // ank 8x16 or kanji
1146                         pattern_b = pattern_r = pattern_g = &kanji[code << 4];
1147                         max_line = 16;
1148 #endif
1149                 } else {
1150                         // ank 8x8
1151                         pattern_b = pattern_r = pattern_g = &font[code << 3];
1152                 }
1153 #ifdef _X1TURBO_FEATURE
1154                 if(max_line == 16) {
1155                         shift = ((mode1 & 5) == 5) ? 1 : ((mode1 & 5) != 0) ? 0 : -1;
1156                 }
1157 #endif
1158
1159                 // check vertical doubled char
1160                 if(!(attr & 0x40)) {
1161                         cur_vert_double = false;
1162                 }
1163
1164                 // render character
1165                 for(int l = 0; l < ch_height; l++) {
1166                         uint8_t b, r, g;
1167                         int line = cur_vert_double ? raster + (l >> 1) : l;
1168 #ifdef _X1TURBO_FEATURE
1169                         if(shift == 1) {
1170                                 line >>= 1;
1171                         } else if(shift == -1) {
1172                                 line <<= 1;
1173                                 if(cur_vert_double) {
1174                                         line |= l & 1;
1175                                 }
1176                         }
1177 #endif
1178                         if((x & 1) && (prev_attr & 0x80)) {
1179                                 b = prev_pattern_b[line] << 4;
1180                                 r = prev_pattern_r[line] << 4;
1181                                 g = prev_pattern_g[line] << 4;
1182                         } else {
1183                                 b = prev_pattern_b[line] = pattern_b[line % max_line];
1184                                 r = prev_pattern_r[line] = pattern_r[line % max_line];
1185                                 g = prev_pattern_g[line] = pattern_g[line % max_line];
1186                         }
1187                         if(reverse) {
1188                                 b = (!(col & 1)) ? 0xff : ~b;
1189                                 r = (!(col & 2)) ? 0xff : ~r;
1190                                 g = (!(col & 4)) ? 0xff : ~g;
1191                         } else {
1192                                 b = (!(col & 1)) ? 0 : b;
1193                                 r = (!(col & 2)) ? 0 : r;
1194                                 g = (!(col & 4)) ? 0 : g;
1195                         }
1196
1197                         int yy = y * ch_height + l;
1198 #ifdef _X1TURBO_FEATURE
1199                         if(yy >= 400) {
1200 #else
1201                         if(yy >= 200) {
1202 #endif
1203                                 break;
1204                         }
1205                         uint8_t* d = &text[yy][x << 3];
1206
1207                         if(attr & 0x80) {
1208                                 // horizontal doubled char
1209 #if 0
1210                                 d[ 0] = d[ 1] = ((b & 0x80) >> 7) | ((r & 0x80) >> 6) | ((g & 0x80) >> 5);
1211                                 d[ 2] = d[ 3] = ((b & 0x40) >> 6) | ((r & 0x40) >> 5) | ((g & 0x40) >> 4);
1212                                 d[ 4] = d[ 5] = ((b & 0x20) >> 5) | ((r & 0x20) >> 4) | ((g & 0x20) >> 3);
1213                                 d[ 6] = d[ 7] = ((b & 0x10) >> 4) | ((r & 0x10) >> 3) | ((g & 0x10) >> 2);
1214 #else
1215                                 ConvertRGBTo8ColorsUint8_Zoom2Left(r, g, b, d, &bit_trans_table_r0, &bit_trans_table_g0, &bit_trans_table_b0, 0);
1216 #endif
1217                         } else {
1218 #if 0
1219                                 d[0] = ((b & 0x80) >> 7) | ((r & 0x80) >> 6) | ((g & 0x80) >> 5);
1220                                 d[1] = ((b & 0x40) >> 6) | ((r & 0x40) >> 5) | ((g & 0x40) >> 4);
1221                                 d[2] = ((b & 0x20) >> 5) | ((r & 0x20) >> 4) | ((g & 0x20) >> 3);
1222                                 d[3] = ((b & 0x10) >> 4) | ((r & 0x10) >> 3) | ((g & 0x10) >> 2);
1223                                 d[4] = ((b & 0x08) >> 3) | ((r & 0x08) >> 2) | ((g & 0x08) >> 1);
1224                                 d[5] = ((b & 0x04) >> 2) | ((r & 0x04) >> 1) | ((g & 0x04) >> 0);
1225                                 d[6] = ((b & 0x02) >> 1) | ((r & 0x02) >> 0) | ((g & 0x02) << 1);
1226                                 d[7] = ((b & 0x01) >> 0) | ((r & 0x01) << 1) | ((g & 0x01) << 2);
1227 #else
1228                                 ConvertRGBTo8ColorsUint8(r, g, b, d, &bit_trans_table_r0, &bit_trans_table_g0, &bit_trans_table_b0, 0);
1229 #endif
1230                         }
1231                         prev_attr = attr;
1232                 }
1233         }
1234         if(cur_vert_double && !prev_vert_double) {
1235                 prev_vert_double = true;
1236                 raster = ch_height >> 1;
1237         } else {
1238                 prev_vert_double = false;
1239                 raster = 0;
1240         }
1241 }
1242
1243 void DISPLAY::draw_cg(int line, int plane)
1244 {
1245         int width = column40 ? 40 : 80;
1246
1247         int y = line / ch_height;
1248         int l = line % ch_height;
1249         if(y >= vt_disp) {
1250                 return;
1251         }
1252         int ofs, src = st_addr + hz_disp * y;
1253 #ifdef _X1TURBO_FEATURE
1254         int page = (hireso && !(mode1 & 2)) ? (l & 1) : (mode1 & 8);
1255         int ll = hireso ? (l >> 1) : l;
1256
1257         if(mode1 & 4) {
1258                 ofs = (0x400 * (ll & 15));// + (page ? 0xc000 : 0);
1259         } else {
1260                 ofs = (0x800 * (ll &  7));// + (page ? 0xc000 : 0);
1261         }
1262 #else
1263         ofs = 0x800 * (l & 7);
1264 #endif
1265 #ifdef _X1TURBOZ
1266         if(AEN) {
1267 /*
1268   HIRESO=0, WIDTH=40, C64=0: 320x200, 4096      PAGE0:(ADDR 000h-3FFh) + PAGE0:(ADDR 400h-7FFh) + PAGE1:(ADDR 000h-3FFh) + PAGE1:(ADDR 400h-7FFh)
1269   HIRESO=0, WIDTH=40, C64=1: 320x200, 64x2      PAGE0:(ADDR 000h-3FFh) + PAGE0:(ADDR 400h-7FFh) / PAGE1:(ADDR 000h-3FFh) + PAGE1:(ADDR 400h-7FFh)
1270   HIRESO=1, WIDTH=40, C64=*: 320x200, 64                PAGE*:(ADDR 000h-3FFh) + PAGE*:(ADDR 400h-7FFh)
1271   HIRESO=0, WIDTH=80, C64=*: 640x200, 64                PAGE0:(ADDR 000h-7FFh) + PAGE1:(ADDR 000h-7FFh)
1272   HIRESO=1, WIDTH=80, C64=*: 640x200, 8         PAGE0:(ADDR 000h-7FFh) + PAGE0:(ADDR 000h-7FFh)
1273
1274   HIRESO=0, WIDTH=40, C64=1: 320x200, 64x2
1275   mode1 zpriority
1276   SCREEN 0      00      00              PAGE0
1277   SCREEM 2      18      08              PAGE1
1278   SCREEN 4      00      10              PAGE0 > PAGE1
1279   SCREEN 6      18      18              PAGE0 < PAGE1
1280 */
1281                 if(!hireso) {
1282                         if(column40) {
1283                                 if(C64 && !(zpriority & 0x10)) {
1284                                         if(plane) {
1285                                                 my_memcpy(zcg[plane][1], zcg[plane][0], sizeof(uint16_t) * 640);
1286                                                 return;
1287                                         }
1288                                 } else {
1289                                         page = plane;
1290                                 }
1291                         } else {
1292                                 page = 0;
1293                         }
1294                 }
1295                 if(page) {
1296                         ofs += 0xc000;
1297                 }
1298                 int ofs_b0 = ofs + 0x0000;
1299                 int ofs_r0 = ofs + 0x4000;
1300                 int ofs_g0 = ofs + 0x8000;
1301                 int ofs_b1 = column40 ? (ofs_b0 ^ 0x400) : hireso ? ofs_b0 : (ofs_b0 + 0xc000);
1302                 int ofs_r1 = column40 ? (ofs_r0 ^ 0x400) : hireso ? ofs_r0 : (ofs_r0 + 0xc000);
1303                 int ofs_g1 = column40 ? (ofs_g0 ^ 0x400) : hireso ? ofs_g0 : (ofs_g0 + 0xc000);
1304
1305                 for(int x = 0; x < hz_disp && x < width; x++) {
1306                         src &= column40 ? 0x3ff : 0x7ff;
1307                         uint16_t b0 = vram_ptr[ofs_b0 | src];
1308                         uint16_t r0 = vram_ptr[ofs_r0 | src];
1309                         uint16_t g0 = vram_ptr[ofs_g0 | src];
1310                         uint16_t b1 = vram_ptr[ofs_b1 | src];
1311                         uint16_t r1 = vram_ptr[ofs_r1 | src];
1312                         uint16_t g1 = vram_ptr[ofs_g1 | src++];
1313                         uint16_t* d = &zcg[plane][line][x << 3];
1314
1315                         // MSB <- G0,G1,0,0, R0,R1,0,0, B0,B1,0,0 -> LSB
1316                         d[0] = ((b0 & 0x80) >> 4) | ((b1 & 0x80) >> 5) | ((r0 & 0x80) >> 0) | ((r1 & 0x80) >> 1) | ((g0 & 0x80) <<  4) | ((g1 & 0x80) <<  3);
1317                         d[1] = ((b0 & 0x40) >> 3) | ((b1 & 0x40) >> 4) | ((r0 & 0x40) << 1) | ((r1 & 0x40) >> 0) | ((g0 & 0x40) <<  5) | ((g1 & 0x40) <<  4);
1318                         d[2] = ((b0 & 0x20) >> 2) | ((b1 & 0x20) >> 3) | ((r0 & 0x20) << 2) | ((r1 & 0x20) << 1) | ((g0 & 0x20) <<  6) | ((g1 & 0x20) <<  5);
1319                         d[3] = ((b0 & 0x10) >> 1) | ((b1 & 0x10) >> 2) | ((r0 & 0x10) << 3) | ((r1 & 0x10) << 2) | ((g0 & 0x10) <<  7) | ((g1 & 0x10) <<  6);
1320                         d[4] = ((b0 & 0x08) >> 0) | ((b1 & 0x08) >> 1) | ((r0 & 0x08) << 4) | ((r1 & 0x08) << 3) | ((g0 & 0x08) <<  8) | ((g1 & 0x08) <<  7);
1321                         d[5] = ((b0 & 0x04) << 1) | ((b1 & 0x04) >> 0) | ((r0 & 0x04) << 5) | ((r1 & 0x04) << 4) | ((g0 & 0x04) <<  9) | ((g1 & 0x04) <<  8);
1322                         d[6] = ((b0 & 0x02) << 2) | ((b1 & 0x02) << 1) | ((r0 & 0x02) << 6) | ((r1 & 0x02) << 5) | ((g0 & 0x02) << 10) | ((g1 & 0x02) <<  9);
1323                         d[7] = ((b0 & 0x01) << 3) | ((b1 & 0x01) << 2) | ((r0 & 0x01) << 7) | ((r1 & 0x01) << 6) | ((g0 & 0x01) << 11) | ((g1 & 0x01) << 10);
1324                 }
1325 #if 1
1326                 // zpriorityで処理すると、プレーンの取得に遅延がでるので
1327                 // ここで2ビット下へ移動してしまおう
1328                 if(!hireso && column40 && C64 && page) {
1329                         for(int x = 0; x < hz_disp && x < width; x++) {
1330                                 uint16_t* d = &zcg[plane][line][x << 3];
1331
1332                                 // MSB <- G0,G1,0,0, R0,R1,0,0, B0,B1,0,0 -> LSB
1333                                 d[0] >>= 2;
1334                                 d[1] >>= 2;
1335                                 d[2] >>= 2;
1336                                 d[3] >>= 2;
1337                                 d[4] >>= 2;
1338                                 d[5] >>= 2;
1339                                 d[6] >>= 2;
1340                                 d[7] >>= 2;
1341                         }
1342                 }
1343 #endif
1344         } else
1345 #endif
1346         {
1347 #ifdef _X1TURBO_FEATURE
1348                 if(page) {
1349                         ofs += 0xc000;
1350                 }
1351 #endif
1352                 int ofs_b = ofs + 0x0000;
1353                 int ofs_r = ofs + 0x4000;
1354                 int ofs_g = ofs + 0x8000;
1355
1356 #if 0
1357                 for(int x = 0; x < hz_disp && x < width; x++) {
1358                         src &= 0x7ff;
1359                         uint8_t b = vram_ptr[ofs_b | src];
1360                         uint8_t r = vram_ptr[ofs_r | src];
1361                         uint8_t g = vram_ptr[ofs_g | src++];
1362                         uint8_t* d = &cg[line][x << 3];
1363
1364                         d[0] = ((b & 0x80) >> 7) | ((r & 0x80) >> 6) | ((g & 0x80) >> 5);
1365                         d[1] = ((b & 0x40) >> 6) | ((r & 0x40) >> 5) | ((g & 0x40) >> 4);
1366                         d[2] = ((b & 0x20) >> 5) | ((r & 0x20) >> 4) | ((g & 0x20) >> 3);
1367                         d[3] = ((b & 0x10) >> 4) | ((r & 0x10) >> 3) | ((g & 0x10) >> 2);
1368                         d[4] = ((b & 0x08) >> 3) | ((r & 0x08) >> 2) | ((g & 0x08) >> 1);
1369                         d[5] = ((b & 0x04) >> 2) | ((r & 0x04) >> 1) | ((g & 0x04) >> 0);
1370                         d[6] = ((b & 0x02) >> 1) | ((r & 0x02) >> 0) | ((g & 0x02) << 1);
1371                         d[7] = ((b & 0x01) >> 0) | ((r & 0x01) << 1) | ((g & 0x01) << 2);
1372                 }
1373 #else
1374                 _render_command_data_t cmd;
1375                 for(int i = 0; i < 3; i++) {
1376                         cmd.data[i] = vram_ptr;
1377                         cmd.baseaddress[i] = 0;
1378                 }
1379                 cmd.voffset[0] = ofs_b;
1380                 cmd.voffset[1] = ofs_r;
1381                 cmd.voffset[2] = ofs_g;
1382                 cmd.bit_trans_table[0] = &bit_trans_table_b0;
1383                 cmd.bit_trans_table[1] = &bit_trans_table_r0;
1384                 cmd.bit_trans_table[2] = &bit_trans_table_g0;
1385                 cmd.addrmask = 0xffffffff;
1386                 cmd.addrmask2 = 0x07ff;
1387                 cmd.begin_pos = src;
1388                 cmd.shift = 0;
1389                 int iwidth = (hz_disp > width) ? width : hz_disp;
1390                 uint8_t* d = &(cg[line][0]);
1391                 cmd.render_width = (iwidth <= 0) ? 0 : (uint32_t)iwidth;
1392
1393                 Convert8ColorsToByte_Line(&cmd, d);
1394 #endif
1395         }
1396 }
1397
1398 #ifdef _X1TURBOZ
1399 int DISPLAY::get_zpal_num(uint32_t addr, uint32_t data)
1400 {
1401         int num = ((data >> 4) & 0x0f) | ((addr << 4) & 0xff0);
1402
1403 #if 1
1404         if(hireso) {
1405                 if(!column40) {
1406                         // 8 colors (use asic palette ram)
1407                         num &= 0x888;
1408                         num |= num >> 1;
1409                         num |= num >> 2;
1410                 } else {
1411                         // 64 colors (single set)
1412                         num &= 0xccc;
1413                         num |= num >> 2;
1414                 }
1415         } else {
1416                 if(!column40 || C64) {
1417                         // 64 colors (dual set)
1418                         num &= 0xccc;  // BANK0 GRAM
1419                         if(C64 && (mode1 & 0x10)) {
1420                                 num >>=2;  // BANK1 GRAM
1421                         }
1422                 }
1423         }
1424 #else
1425         if(hireso && !column40) {
1426                 // 8 colors
1427                 num &= 0x888;
1428                 num |= num >> 1;
1429                 num |= num >> 2;
1430         } else if(!(!hireso && column40 && !C64)) {
1431                 // 64 colors
1432                 num &= 0xccc;
1433                 num |= num >> 2;
1434         }
1435 #endif
1436         return num;
1437 }
1438
1439 void DISPLAY::update_zpalette()
1440 {
1441         memcpy(zpalette_pc, zpalette_tmp, sizeof(zpalette_pc));
1442         zpalette_pc[8 + 0] = zpalette_pc[16 + 0x000];
1443         zpalette_pc[8 + 1] = zpalette_pc[16 + 0x00f];
1444         zpalette_pc[8 + 2] = zpalette_pc[16 + 0x0f0];
1445         zpalette_pc[8 + 3] = zpalette_pc[16 + 0x0ff];
1446         zpalette_pc[8 + 4] = zpalette_pc[16 + 0xf00];
1447         zpalette_pc[8 + 5] = zpalette_pc[16 + 0xf0f];
1448         zpalette_pc[8 + 6] = zpalette_pc[16 + 0xff0];
1449         zpalette_pc[8 + 7] = zpalette_pc[16 + 0xfff];
1450
1451         dr_zpalette_pc[8 + 0] = dr_zpalette_pc[16 + 0x000];
1452         dr_zpalette_pc[8 + 1] = dr_zpalette_pc[16 + 0x00f];
1453         dr_zpalette_pc[8 + 2] = dr_zpalette_pc[16 + 0x0f0];
1454         dr_zpalette_pc[8 + 3] = dr_zpalette_pc[16 + 0x0ff];
1455         dr_zpalette_pc[8 + 4] = dr_zpalette_pc[16 + 0xf00];
1456         dr_zpalette_pc[8 + 5] = dr_zpalette_pc[16 + 0xf0f];
1457         dr_zpalette_pc[8 + 6] = dr_zpalette_pc[16 + 0xff0];
1458         dr_zpalette_pc[8 + 7] = dr_zpalette_pc[16 + 0xfff];
1459
1460 }
1461
1462 scrntype_t DISPLAY::get_zpriority(uint8_t text, uint16_t cg0, uint16_t cg1)
1463 {
1464         if((mode2 & 8) && (text == (mode2 & 7))) {
1465                 int digital = ((cg0 >> 9) & 4) | ((cg0 >> 6) & 2) | ((cg0 >> 3) & 1);
1466                 if(!(dr_priority & (1 << digital))) {
1467                         return 0;
1468                 }
1469         }
1470         uint16_t fore = ((dr_zpriority & 0x18) != 0x18) ? cg0 : cg1;
1471         uint16_t back = ((dr_zpriority & 0x18) != 0x18) ? cg1 : cg0;
1472         uint16_t disp;
1473
1474         switch(dr_zpriority & 0x13) {
1475         case 0x00:
1476         case 0x02:
1477                 disp = text ? text : (fore + 16);
1478                 break;
1479         case 0x01:
1480         case 0x03:
1481                 disp = fore ? (fore + 16) : text;
1482                 break;
1483         case 0x10:
1484                 disp = text ? text : fore ? (fore + 16) : (back + 16);
1485                 break;
1486         case 0x11:
1487                 disp = fore ? (fore + 16) : back ? (back + 16) : text;
1488                 break;
1489         case 0x12:
1490                 disp = fore ? (fore + 16) : text ? text : (back + 16);
1491                 break;
1492         default: // undefined case :-(
1493                 disp = text ? text : fore ? (fore + 16) : (back + 16);
1494                 break;
1495         }
1496 //      if((mode2 & 0x10) && disp == (0x000 + 16)) {
1497 //              return 0;
1498 //      }
1499 //      if((mode2 & 0x20) && disp == (0x00f + 16)) {
1500 //              return 0;
1501 //      }
1502         return dr_zpalette_pc[disp];
1503 }
1504 #endif
1505
1506 // kanji rom (from X1EMU by KM)
1507
1508 void DISPLAY::write_kanji(uint32_t addr, uint32_t data)
1509 {
1510         switch(addr) {
1511         case 0xe80:
1512                 kaddr = (kaddr & 0xff00) | data;
1513                 break;
1514         case 0xe81:
1515                 kaddr = (kaddr & 0xff) | (data << 8);
1516                 break;
1517         case 0xe82:
1518                 // TODO: bit0 L->H: Latch
1519                 kanji_ptr = &kanji[adr2knj_x1(kaddr & 0xfff0)];
1520                 break;
1521         }
1522 }
1523
1524 uint32_t DISPLAY::read_kanji(uint32_t addr)
1525 {
1526         switch(addr) {
1527         case 0xe80:
1528                 if(kaddr & 0xff00) {
1529                         uint32_t val = kanji_ptr[kofs];
1530                         kflag |= 1;
1531                         if(kflag == 3) {
1532                                 kofs = (kofs + 1) & 15;
1533                                 kflag = 0;
1534                         }
1535                         return val;
1536                 }
1537                 return jis2adr_x1(kaddr << 8) >> 8;
1538         case 0xe81:
1539                 if(kaddr & 0xff00) {
1540                         uint32_t val = kanji_ptr[kofs + 16];
1541                         kflag |= 2;
1542                         if(kflag == 3) {
1543                                 kofs = (kofs + 1) & 15;
1544                                 kflag = 0;
1545                         }
1546                         return val;
1547                 }
1548                 return 0;
1549         }
1550         return 0xff;
1551 }
1552
1553 uint16_t DISPLAY::jis2adr_x1(uint16_t jis)
1554 {
1555         uint16_t jh, jl, adr;
1556
1557         jh = jis >> 8;
1558         jl = jis & 0xff;
1559         if(jh > 0x28) {
1560                 adr = 0x4000 + (jh - 0x30) * 0x600;
1561         } else {
1562                 adr = 0x0100 + (jh - 0x21) * 0x600;
1563         }
1564         if(jl >= 0x20) {
1565                 adr += (jl - 0x20) * 0x10;
1566         }
1567         return adr;
1568 }
1569
1570 uint32_t DISPLAY::adr2knj_x1(uint16_t adr)
1571 {
1572         uint16_t jh, jl, jis;
1573
1574         if(adr < 0x4000) {
1575                 jh = adr - 0x0100;
1576                 jh = 0x21 + jh / 0x600;
1577         } else {
1578                 jh = adr - 0x4000;
1579                 jh = 0x30 + jh / 0x600;
1580         }
1581         if(jh > 0x28) {
1582                 adr -= 0x4000 + (jh - 0x30) * 0x600;
1583         } else {
1584                 adr -= 0x0100 + (jh - 0x21) * 0x600;
1585         }
1586         jl = 0x20;
1587         if(adr) {
1588                 jl += adr / 0x10;
1589         }
1590
1591         jis = (jh << 8) | jl;
1592         return jis2knj(jis);
1593 }
1594
1595 #ifdef _X1TURBO_FEATURE
1596 uint32_t DISPLAY::adr2knj_x1t(uint16_t adr)
1597 {
1598         uint16_t j1, j2;
1599         uint16_t rl, rh;
1600         uint16_t jis;
1601
1602         rh = adr >> 8;
1603         rl = adr & 0xff;
1604
1605         rh &= 0x1f;
1606         if(!rl && !rh) {
1607                 return jis2knj(0);
1608         }
1609         j2 = rl & 0x1f;         // rl4,3,2,1,0
1610         j1 = (rl / 0x20) & 7;   // rl7,6,5
1611
1612         if(rh < 0x04) {
1613                 // 2121-277e
1614                 j1 |= 0x20;
1615                 switch(rh & 3) {
1616                 case 0: j2 |= 0x20; break;
1617                 case 1: j2 |= 0x60; break;
1618                 case 2: j2 |= 0x40; break;
1619                 default: j1 = j2 = 0; break;
1620                 }
1621         } else if(rh > 0x1c) {
1622                 // 7021-777e
1623                 j1 |= 0x70;
1624                 switch(rh & 3) {
1625                 case 0: j2 |= 0x20; break;
1626                 case 1: j2 |= 0x60; break;
1627                 case 2: j2 |= 0x40; break;
1628                 default: j1 = j2 = 0; break;
1629                 }
1630         } else {
1631                 j1 |= (((rh >> 1) + 7) / 3) * 0x10;
1632                 j1 |= (rh & 1) * 8;
1633                 j2 |= ((((rh >> 1) + 1) % 3) + 1) * 0x20;
1634         }
1635
1636         jis = (j1 << 8) | j2;
1637         return jis2knj(jis);
1638 }
1639 #endif
1640
1641 uint32_t DISPLAY::jis2knj(uint16_t jis)
1642 {
1643         uint32_t sjis = jis2sjis(jis);
1644
1645         if(sjis < 0x100) {
1646                 return sjis * 16;
1647         } else if(sjis >= 0x8140 && sjis < 0x84c0) {
1648                 return 0x01000 + (sjis - 0x8140) * 32;
1649         } else if(sjis >= 0x8890 && sjis < 0xa000) {
1650                 return 0x08000 + (sjis - 0x8890) * 32;
1651         } else if(sjis >= 0xe040 && sjis < 0xeab0) {
1652                 return 0x36e00 + (sjis - 0xe040) * 32;
1653         } else {
1654                 return 0;
1655         }
1656 }
1657
1658 uint16_t DISPLAY::jis2sjis(uint16_t jis)
1659 {
1660         uint16_t c1, c2;
1661
1662         if(!jis) {
1663                 return 0;
1664         }
1665         c1 = jis >> 8;
1666         c2 = jis & 0xff;
1667
1668         if(c1 & 1) {
1669                 c2 += 0x1f;
1670                 if(c2 >= 0x7f) {
1671                         c2++;
1672                 }
1673         } else {
1674                 c2 += 0x7e;
1675         }
1676         c1 = (c1 - 0x20 - 1) / 2 + 0x81;
1677         if(c1 >= 0xa0) {
1678                 c1 += 0x40;
1679         }
1680         return (c1 << 8) | c2;
1681 }
1682
1683 #define STATE_VERSION   6
1684
1685 bool DISPLAY::process_state(FILEIO* state_fio, bool loading)
1686 {
1687         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
1688                 return false;
1689         }
1690         if(!state_fio->StateCheckInt32(this_device_id)) {
1691                 return false;
1692         }
1693         state_fio->StateArray(vram_t, sizeof(vram_t), 1);
1694         state_fio->StateArray(vram_a, sizeof(vram_a), 1);
1695 #ifdef _X1TURBO_FEATURE
1696         state_fio->StateArray(vram_k, sizeof(vram_k), 1);
1697 #endif
1698         state_fio->StateArray(&pcg_b[0][0], sizeof(pcg_b), 1);
1699         state_fio->StateArray(&pcg_r[0][0], sizeof(pcg_r), 1);
1700         state_fio->StateArray(&pcg_g[0][0], sizeof(pcg_g), 1);
1701 #ifdef _X1TURBO_FEATURE
1702         state_fio->StateArray(&gaiji_b[0][0], sizeof(gaiji_b), 1);
1703         state_fio->StateArray(&gaiji_r[0][0], sizeof(gaiji_r), 1);
1704         state_fio->StateArray(&gaiji_g[0][0], sizeof(gaiji_g), 1);
1705 #endif
1706         state_fio->StateValue(cur_code);
1707         state_fio->StateValue(cur_line);
1708         state_fio->StateValue(kaddr);
1709         state_fio->StateValue(kofs);
1710         state_fio->StateValue(kflag);
1711         if(loading) {
1712                 intptr_t p = (intptr_t)(&kanji[0]);
1713                 kanji_ptr = (uint8_t*)(p + state_fio->FgetInt32_LE());
1714         } else {
1715                 intptr_t p = (intptr_t)(&kanji[0]);
1716                 intptr_t q = (intptr_t)kanji_ptr;
1717                 state_fio->FputInt32_LE((int)(q - p));
1718         }
1719         state_fio->StateArray(pal, sizeof(pal), 1);
1720         state_fio->StateValue(priority);
1721         state_fio->StateArray(&pri[0][0], sizeof(pri), 1);
1722         state_fio->StateValue(column40);
1723 #ifdef _X1TURBO_FEATURE
1724         state_fio->StateValue(mode1);
1725         state_fio->StateValue(mode2);
1726         state_fio->StateValue(hireso);
1727 #endif
1728 #ifdef _X1TURBOZ
1729         state_fio->StateValue(zmode1);
1730         state_fio->StateValue(zpriority);
1731         state_fio->StateValue(zadjust);
1732         state_fio->StateValue(zmosaic);
1733         state_fio->StateValue(zchromakey);
1734         state_fio->StateValue(zscroll);
1735         state_fio->StateValue(zmode2);
1736         state_fio->StateArray(ztpal, sizeof(ztpal), 1);
1737         for(int i = 0; i < array_length(zpal); i++){
1738                 state_fio->StateValue(zpal[i].r);
1739                 state_fio->StateValue(zpal[i].g);
1740                 state_fio->StateValue(zpal[i].b);
1741         }
1742         state_fio->StateValue(zpal_num);
1743         state_fio->StateArrayScrnType_t(zpalette_tmp, sizeof(zpalette_tmp), 1);
1744 #endif
1745         state_fio->StateValue(prev_vert_double);
1746         state_fio->StateValue(raster);
1747         state_fio->StateValue(cblink);
1748         state_fio->StateValue(ch_height);
1749         state_fio->StateValue(hz_total);
1750         state_fio->StateValue(hz_disp);
1751         state_fio->StateValue(vt_disp);
1752         state_fio->StateValue(vt_ofs);
1753         state_fio->StateValue(st_addr);
1754         state_fio->StateValue(vblank_clock);
1755         state_fio->StateValue(cur_blank);
1756
1757         // post process
1758         if(loading) {
1759 #ifdef _X1TURBOZ
1760                 zpalette_changed = true;
1761 #endif
1762                 for(int i = 0; i < 8; i++) {
1763                         palette_pc[i    ] = RGB_COLOR((i & 2) ? 255 : 0, (i & 4) ? 255 : 0, (i & 1) ? 255 : 0); // text
1764                         palette_pc[i + 8] = RGB_COLOR((i & 2) ? 255 : 0, (i & 4) ? 255 : 0, (i & 1) ? 255 : 0); // cg
1765                 }
1766                 // Copy images to draw buffers.
1767                 my_memcpy(dr_text, text, sizeof(dr_text));
1768                 my_memcpy(dr_cg, cg, sizeof(dr_cg));
1769 #ifdef _X1TURBO_FEATURE
1770                 for(int v = 0; v < 400; v++) {
1771                         memcpy(&pri_line[v][0][0], &pri[0][0], sizeof(pri));
1772                 }
1773 #else
1774                 for(int v = 0; v < 200; v++) {
1775                         memcpy(&pri_line[v][0][0], &pri[0][0], sizeof(pri));
1776                 }
1777 #endif
1778                 my_memcpy(dr_pri_line, pri_line, sizeof(dr_pri_line));
1779                 my_memcpy(dr_palette_pc, palette_pc, sizeof(dr_palette_pc));
1780                 dr_priority = priority;
1781 #ifdef _X1TURBOZ
1782                 // ToDo: Chack save/load.
1783                 dr_zpriority = zpriority;
1784                 my_memcpy(dr_zcg, zcg, sizeof(dr_zcg));
1785                 my_memcpy(dr_aen_line, aen_line, sizeof(dr_aen_line));
1786                 my_memcpy(dr_zpalette_pc, zpalette_tmp, sizeof(zpalette_tmp));
1787 #endif
1788                 update_crtc(); // force update timing
1789         }
1790         return true;
1791 }
1792
1793 }