OSDN Git Service

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