OSDN Git Service

[VM][General] Merge upstream 2016-03-01. (Pahse 1).
[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 APEN    ((zmode2 & 0x80) != 0)
21 #define APRD    ((zmode2 & 0x08) != 0)
22 #endif
23
24 void DISPLAY::initialize()
25 {
26         // load rom images
27         FILEIO* fio = new FILEIO();
28         
29         // ank8 (8x8)
30         if(fio->Fopen(create_local_path(_T("ANK8.ROM")), FILEIO_READ_BINARY)) {
31                 fio->Fread(font, sizeof(font), 1);
32                 fio->Fclose();
33         } else if(fio->Fopen(create_local_path(_T("FNT0808.X1")), FILEIO_READ_BINARY)) {
34                 // xmillenium rom
35                 fio->Fread(font, sizeof(font), 1);
36                 fio->Fclose();
37         }
38         
39         // ank16 (8x16)
40         if(fio->Fopen(create_local_path(_T("ANK16.ROM")), FILEIO_READ_BINARY)) {
41                 fio->Fread(kanji, 0x1000, 1);
42                 fio->Fclose();
43         } else if(fio->Fopen(create_local_path(_T("FNT0816.X1")), FILEIO_READ_BINARY)) {
44                 // xmillenium rom
45                 fio->Fread(kanji, 0x1000, 1);
46                 fio->Fclose();
47         }
48         memcpy(kanji + 0x7f * 16, ANKFONT7f_9f, sizeof(ANKFONT7f_9f));
49         memcpy(kanji + 0xe0 * 16, ANKFONTe0_ff, sizeof(ANKFONTe0_ff));
50         
51         // kanji (16x16)
52         if(fio->Fopen(create_local_path(_T("KANJI.ROM")), FILEIO_READ_BINARY)) {
53                 fio->Fread(kanji + 0x1000, 0x4ac00, 1);
54                 fio->Fclose();
55         } else if(fio->Fopen(create_local_path(_T("FNT1616.X1")), FILEIO_READ_BINARY)) {
56                 // xmillenium rom
57                 fio->Fread(kanji + 0x1000, 0x4ac00, 1);
58                 fio->Fclose();
59         }
60         for(int ofs = 0x1000; ofs < 0x4bc00; ofs += 32) {
61                 // LRLR.. -> LL..RR..
62                 uint8_t buf[32];
63                 for(int i = 0; i < 16; i++) {
64                         buf[i     ] = kanji[ofs + i * 2    ];
65                         buf[i + 16] = kanji[ofs + i * 2 + 1];
66                 }
67                 memcpy(kanji + ofs, buf, 32);
68         }
69         delete fio;
70         
71         // create pc palette
72         for(int i = 0; i < 8; i++) {
73                 palette_pc[i    ] = RGB_COLOR((i & 2) ? 255 : 0, (i & 4) ? 255 : 0, (i & 1) ? 255 : 0); // text
74                 palette_pc[i + 8] = RGB_COLOR((i & 2) ? 255 : 0, (i & 4) ? 255 : 0, (i & 1) ? 255 : 0); // cg
75         }
76         
77         // initialize regs
78         pal[0] = 0xaa;
79         pal[1] = 0xcc;
80         pal[2] = 0xf0;
81         priority = 0;
82         update_pal();
83         column40 = true;
84         
85         memset(vram_t, 0, sizeof(vram_t));
86         memset(vram_a, 0, sizeof(vram_a));
87 #ifdef _X1TURBO_FEATURE
88         memset(vram_k, 0, sizeof(vram_k));
89 #endif
90         memset(pcg_b, 0, sizeof(pcg_b));
91         memset(pcg_r, 0, sizeof(pcg_r));
92         memset(pcg_g, 0, sizeof(pcg_g));
93 #ifdef _X1TURBO_FEATURE
94         memset(gaiji_b, 0, sizeof(gaiji_b));
95         memset(gaiji_r, 0, sizeof(gaiji_r));
96         memset(gaiji_g, 0, sizeof(gaiji_g));
97 #endif
98         memset((void *)text_bak, 0x00, sizeof(text_bak)); 
99         memset((void *)cg_bak,   0x00, sizeof(cg_bak)); 
100         
101         // register event
102         register_frame_event(this);
103         register_vline_event(this);
104 }
105
106 void DISPLAY::reset()
107 {
108 #ifdef _X1TURBO_FEATURE
109         mode1 = 0;//3;
110         mode2 = 0;
111         hireso = true;
112 #endif
113 #ifdef _X1TURBOZ
114         for(int i = 0; i < 8; i++) {
115                 palette_pc[i    ] = RGB_COLOR((i & 2) ? 255 : 0, (i & 4) ? 255 : 0, (i & 1) ? 255 : 0); // text
116                 ztpal[i] = ((i & 1) ? 0x03 : 0) | ((i & 2) ? 3 : 0x0c) | ((i & 4) ? 0x30 : 0);
117         }
118         for(int g = 0; g < 16; g++) {
119                 for(int r = 0; r < 16; r++) {
120                         for(int b = 0; b < 16; b++) {
121                                 int num = b + r * 16 + g * 256;
122                                 zpal[num].b = b;
123                                 zpal[num].r = r;
124                                 zpal[num].g = g;
125                                 palette_pc[num + 16] = RGB_COLOR((r * 255) / 15, (g * 255) / 15, (b * 255) / 15);
126                         }
127                 }
128         }
129         zmode1 = zpriority = zscroll = zmode2 = 0;
130         zpal_num = 0;
131 #endif
132         cur_line = cur_code = 0;
133         vblank_clock = 0;
134         
135         kaddr = kofs = kflag = 0;
136         kanji_ptr = &kanji[0];
137 }
138
139
140 void DISPLAY::write_io8(uint32_t addr, uint32_t data)
141 {
142         switch(addr & 0xff00) {
143         case 0x0e00:
144                 write_kanji(addr, data);
145                 break;
146         case 0x1000:
147 #ifdef _X1TURBOZ
148                 if(AEN && APEN && !APRD) {
149                         int num = ((data >> 4) & 0x0f) | ((addr << 4) & 0xff0);
150                         zpal[num].b = data & 0x0f;
151                         palette_pc[num + 16] = RGB_COLOR((zpal[num].r * 255) / 15, (zpal[num].g * 255) / 15, (zpal[num].b * 255) / 15);
152                 } else if(AEN && APEN && APRD) {
153                         zpal_num = ((data >> 4) & 0x0f) | ((addr << 4) & 0xff0);
154                 } else if(!AEN) {
155 #endif
156                         pal[0] = data;
157                         update_pal();
158 #ifdef _X1TURBOZ
159                 }
160 #endif
161                 break;
162         case 0x1100:
163 #ifdef _X1TURBOZ
164                 if(AEN && APEN && !APRD) {
165                         int num = ((data >> 4) & 0x0f) | ((addr << 4) & 0xff0);
166                         zpal[num].r = data & 0x0f;
167                         palette_pc[num + 16] = RGB_COLOR((zpal[num].r * 255) / 15, (zpal[num].g * 255) / 15, (zpal[num].b * 255) / 15);
168 //              } else if(AEN && APEN && APRD) {
169 //                      zpal_num = ((data >> 4) & 0x0f) | ((addr << 4) & 0xff0);
170                 } else if(!AEN) {
171 #endif
172                         pal[1] = data;
173                         update_pal();
174 #ifdef _X1TURBOZ
175                 }
176 #endif
177                 break;
178         case 0x1200:
179 #ifdef _X1TURBOZ
180                 if(AEN && APEN && !APRD) {
181                         int num = ((data >> 4) & 0x0f) | ((addr << 4) & 0xff0);
182                         zpal[num].g = data & 0x0f;
183                         palette_pc[num + 16] = RGB_COLOR((zpal[num].r * 255) / 15, (zpal[num].g * 255) / 15, (zpal[num].b * 255) / 15);
184 //              } else if(AEN && APEN && APRD) {
185 //                      zpal_num = ((data >> 4) & 0x0f) | ((addr << 4) & 0xff0);
186                 } else if(!AEN) {
187 #endif
188                         pal[2] = data;
189                         update_pal();
190 #ifdef _X1TURBOZ
191                 }
192 #endif
193                 break;
194         case 0x1300:
195                 priority = data;
196                 update_pal();
197                 break;
198         case 0x1500:
199                 get_cur_pcg(addr);
200                 pcg_b[cur_code][cur_line] = data;
201 #ifdef _X1TURBO_FEATURE
202                 gaiji_b[cur_code >> 1][(cur_line << 1) | (cur_code & 1)] = data;
203 #endif
204                 break;
205         case 0x1600:
206                 get_cur_pcg(addr);
207                 pcg_r[cur_code][cur_line] = data;
208 #ifdef _X1TURBO_FEATURE
209                 gaiji_r[cur_code >> 1][(cur_line << 1) | (cur_code & 1)] = data;
210 #endif
211                 break;
212         case 0x1700:
213                 get_cur_pcg(addr);
214                 pcg_g[cur_code][cur_line] = data;
215 #ifdef _X1TURBO_FEATURE
216                 gaiji_g[cur_code >> 1][(cur_line << 1) | (cur_code & 1)] = data;
217 #endif
218                 break;
219 #ifdef _X1TURBO_FEATURE
220         case 0x1f00:
221                 switch(addr) {
222 #ifdef _X1TURBOZ
223                 case 0x1fb0:
224                         zmode1 = data;
225                         break;
226                 case 0x1fb1:
227                 case 0x1fb2:
228                 case 0x1fb3:
229                 case 0x1fb4:
230                 case 0x1fb5:
231                 case 0x1fb6:
232                 case 0x1fb7:
233                         ztpal[addr & 7] = data;
234                         palette_pc[addr & 7] = RGB_COLOR((((data >> 2) & 3) * 255) / 3, (((data >> 4) & 3) * 255) / 3, (((data >> 0) & 3) * 255) / 3);
235                         break;
236                 case 0x1fc0:
237                         zpriority = data;
238                         break;
239                 case 0x1fc4:
240                         zscroll = data;
241                         break;
242                 case 0x1fc5:
243                         zmode2 = data;
244                         break;
245 #endif
246                 case 0x1fd0:
247                         mode1 = data;
248                         update_crtc();
249 //                      hireso = !((mode1 & 3) == 0 || (mode1 & 3) == 2);
250                         break;
251                 case 0x1fe0:
252                         mode2 = data;
253                         update_pal();
254                         break;
255                 }
256                 break;
257 #endif
258         case 0x2000:
259         case 0x2100:
260         case 0x2200:
261         case 0x2300:
262         case 0x2400:
263         case 0x2500:
264         case 0x2600:
265         case 0x2700:
266                 vram_a[addr & 0x7ff] = data;
267                 break;
268         case 0x2800:
269         case 0x2900:
270         case 0x2a00:
271         case 0x2b00:
272         case 0x2c00:
273         case 0x2d00:
274         case 0x2e00:
275         case 0x2f00:
276                 vram_a[addr & 0x7ff] = data; // mirror
277                 break;
278         case 0x3000:
279         case 0x3100:
280         case 0x3200:
281         case 0x3300:
282         case 0x3400:
283         case 0x3500:
284         case 0x3600:
285         case 0x3700:
286                 vram_t[addr & 0x7ff] = data;
287                 break;
288         case 0x3800:
289         case 0x3900:
290         case 0x3a00:
291         case 0x3b00:
292         case 0x3c00:
293         case 0x3d00:
294         case 0x3e00:
295         case 0x3f00:
296 #ifdef _X1TURBO_FEATURE
297                 vram_k[addr & 0x7ff] = data;
298 #else
299                 vram_t[addr & 0x7ff] = data; // mirror
300 #endif
301                 break;
302         }
303 }
304
305 uint32_t DISPLAY::read_io8(uint32_t addr)
306 {
307         switch(addr & 0xff00) {
308         case 0x0e00:
309                 return read_kanji(addr);
310 #ifdef _X1TURBOZ
311         case 0x1000:
312                 if(AEN && APEN && APRD) {
313                         return zpal[zpal_num].b;
314                 }
315                 break;
316         case 0x1100:
317                 if(AEN && APEN && APRD) {
318                         return zpal[zpal_num].r;
319                 }
320                 break;
321         case 0x1200:
322                 if(AEN && APEN && APRD) {
323                         return zpal[zpal_num].g;
324                 }
325                 break;
326 #endif
327 //      case 0x1300:
328 //              return priority;
329         case 0x1400:
330                 return get_cur_font(addr);
331         case 0x1500:
332                 get_cur_pcg(addr);
333                 return pcg_b[cur_code][cur_line];
334         case 0x1600:
335                 get_cur_pcg(addr);
336                 return pcg_r[cur_code][cur_line];
337         case 0x1700:
338                 get_cur_pcg(addr);
339                 return pcg_g[cur_code][cur_line];
340 #ifdef _X1TURBOZ
341         case 0x1f00:
342                 switch(addr) {
343                 case 0x1fb0:
344                         return zmode1;
345                 case 0x1fb1:
346                 case 0x1fb2:
347                 case 0x1fb3:
348                 case 0x1fb4:
349                 case 0x1fb5:
350                 case 0x1fb6:
351                 case 0x1fb7:
352                         return ztpal[addr & 7];
353                 case 0x1fc0:
354                         return zpriority;
355                 case 0x1fc4:
356                         return zscroll;
357                 case 0x1fc5:
358                         return zmode2;
359                 case 0x1fd0:
360                         return mode1;
361                 case 0x1fe0:
362                         return mode2;
363                 }
364                 break;
365 #endif
366         case 0x2000:
367         case 0x2100:
368         case 0x2200:
369         case 0x2300:
370         case 0x2400:
371         case 0x2500:
372         case 0x2600:
373         case 0x2700:
374                 return vram_a[addr & 0x7ff];
375         case 0x2800:
376         case 0x2900:
377         case 0x2a00:
378         case 0x2b00:
379         case 0x2c00:
380         case 0x2d00:
381         case 0x2e00:
382         case 0x2f00:
383                 return vram_a[addr & 0x7ff]; // mirror
384         case 0x3000:
385         case 0x3100:
386         case 0x3200:
387         case 0x3300:
388         case 0x3400:
389         case 0x3500:
390         case 0x3600:
391         case 0x3700:
392                 return vram_t[addr & 0x7ff];
393         case 0x3800:
394         case 0x3900:
395         case 0x3a00:
396         case 0x3b00:
397         case 0x3c00:
398         case 0x3d00:
399         case 0x3e00:
400         case 0x3f00:
401 #ifdef _X1TURBO_FEATURE
402                 return vram_k[addr & 0x7ff];
403 #else
404                 return vram_t[addr & 0x7ff]; // mirror
405 #endif
406         }
407         return 0xff;
408 }
409
410 void DISPLAY::write_signal(int id, uint32_t data, uint32_t mask)
411 {
412         if(id == SIG_DISPLAY_VBLANK) {
413                 if(!(data & mask)) {
414                         // enter vblank
415                         vblank_clock = get_current_clock();
416                 }
417         } else if(id == SIG_DISPLAY_COLUMN40) {
418                 column40 = ((data & mask) != 0);
419                 update_crtc();
420         } else if(id == SIG_DISPLAY_DETECT_VBLANK) {
421                 // hack: cpu detects vblank
422                 vblank_clock = get_current_clock();
423         }
424 }
425
426 void DISPLAY::event_frame()
427 {
428         cblink = (cblink + 1) & 0x3f;
429         
430         // update crtc parameters
431         ch_height = (regs[9] & 0x1f) + 1;
432         hz_total = regs[0] + 1;
433         hz_disp = regs[1];
434         vt_disp = regs[6] & 0x7f;
435         st_addr = (regs[12] << 8) | regs[13];
436         
437 #ifdef _X1TURBO_FEATURE
438         int vt_total = ((regs[4] & 0x7f) + 1) * ch_height + (regs[5] & 0x1f);
439         hireso = (vt_total > 400);
440 #endif
441 }
442
443 void DISPLAY::event_vline(int v, int clock)
444 {
445 #ifdef _X1TURBO_FEATURE
446         if(hireso) {
447                 if(v < 400) {
448                         draw_line(v);
449                 }
450         } else {
451 #endif
452                 if(v < 200) {
453                         draw_line(v);
454                 }
455 #ifdef _X1TURBO_FEATURE
456         }
457         // restart cpu after pcg/cgrom is accessed
458         d_cpu->write_signal(SIG_CPU_BUSREQ, 0, 0);
459 #endif
460 #ifdef _X1TURBO_FEATURE
461         if(hireso) {
462                 if(v == 400) {
463                         memcpy((void *)text_bak, (void *)text, sizeof(text)); 
464                         memcpy((void *)cg_bak,   (void *)cg, sizeof(cg)); 
465                 }
466         } else {
467 #endif
468                 if(v == 200) {
469                         memcpy((void *)text_bak, (void *)text, sizeof(text)); 
470                         memcpy((void *)cg_bak,   (void *)cg, sizeof(cg)); 
471                 }
472 #ifdef _X1TURBO_FEATURE
473         }
474 #endif
475         
476 }
477
478 void DISPLAY::update_crtc()
479 {
480 #ifdef _X1TURBO_FEATURE
481         if (column40) {
482                 d_crtc->set_char_clock((mode1 & 1) ? VDP_CLOCK * 1.5 / 32.0 : VDP_CLOCK / 32.0);
483         } else {
484                 d_crtc->set_char_clock((mode1 & 1) ? VDP_CLOCK * 1.5 / 16.0 : VDP_CLOCK / 16.0);
485         }
486 #else
487         if (column40) {
488                 d_crtc->set_char_clock(VDP_CLOCK / 32.0);
489         } else {
490                 d_crtc->set_char_clock(VDP_CLOCK / 16.0);
491         }
492 #endif
493 }
494
495 void DISPLAY::update_pal()
496 {
497         uint8_t pal2[8];
498         for(int i = 0; i < 8; i++) {
499                 uint8_t bit = 1 << i;
500                 pal2[i] = ((pal[0] & bit) ? 1 : 0) | ((pal[1] & bit) ? 2 : 0) | ((pal[2] & bit) ? 4 : 0) | 8;
501         }
502 #ifdef _X1TURBO_FEATURE
503         if(mode2 & 0x10) pal2[0] = 8;
504         if(mode2 & 0x20) pal2[1] = 8;
505 #endif
506         for(int c = 0; c < 8; c++) {
507                 for(int t = 0; t < 8; t++) {
508                         if(priority & (1 << c)) {
509                                 pri[c][t] = pal2[c];
510                         } else if(t) {
511 #ifdef _X1TURBO_FEATURE
512                                 pri[c][t] = ((mode2 & 8) && (mode2 & 7) == t) ? 0 : t;
513 #else
514                                 pri[c][t] = t;
515 #endif
516                         } else {
517                                 pri[c][t] = pal2[c];
518                         }
519                 }
520         }
521 }
522
523 uint8_t DISPLAY::get_cur_font(uint32_t addr)
524 {
525 #ifdef _X1TURBO_FEATURE
526         if(mode1 & 0x20) {
527                 // wait next raster
528                 d_cpu->write_signal(SIG_CPU_BUSREQ, 1, 1);
529                 
530                 // from X1EMU
531                 uint16_t vaddr;
532                 if(!(vram_a[0x7ff] & 0x20)) {
533                         vaddr = 0x7ff;
534                 } else if(!(vram_a[0x3ff] & 0x20)) {
535                         vaddr = 0x3ff;
536                 } else if(!(vram_a[0x5ff] & 0x20)) {
537                         vaddr = 0x5ff;
538                 } else if(!(vram_a[0x1ff] & 0x20)) {
539                         vaddr = 0x1ff;
540                 } else {
541                         vaddr = 0x3ff;
542                 }
543                 uint16_t ank = vram_t[vaddr];
544                 uint16_t knj = vram_k[vaddr];
545                 
546                 if(knj & 0x80) {
547                         uint32_t ofs = adr2knj_x1t((knj << 8) | ank);
548                         if(knj & 0x40) {
549                                 ofs += 16; // right
550                         }
551                         return kanji[ofs | (addr & 15)];
552                 } else if(mode1 & 0x40) {
553                         return kanji[(ank << 4) | (addr & 15)];
554                 } else {
555                         return font[(ank << 3) | ((addr >> 1) & 7)];
556                 }
557         }
558 #endif
559         get_cur_code_line();
560         return font[(cur_code << 3) | (cur_line & 7)];
561 }
562
563 void DISPLAY::get_cur_pcg(uint32_t addr)
564 {
565 #ifdef _X1TURBO_FEATURE
566         if(mode1 & 0x20) {
567                 // wait next raster
568                 d_cpu->write_signal(SIG_CPU_BUSREQ, 1, 1);
569                 
570                 // from X1EMU
571                 uint16_t vaddr;
572                 if(vram_a[0x7ff] & 0x20) {
573                         vaddr = 0x7ff;
574                 } else if(vram_a[0x3ff] & 0x20) {
575                         vaddr = 0x3ff;
576                 } else if(vram_a[0x5ff] & 0x20) {
577                         vaddr = 0x5ff;
578                 } else if(vram_a[0x1ff] & 0x20) {
579                         vaddr = 0x1ff;
580                 } else {
581                         vaddr = 0x3ff;
582                 }
583                 cur_code = vram_t[vaddr];
584                 cur_line = (addr >> 1) & 7;
585                 
586                 if(vram_k[vaddr] & 0x90) {
587                         cur_code &= 0xfe;
588                         cur_code += addr & 1;
589                 }
590         } else
591 #endif
592         get_cur_code_line();
593 }
594
595 void DISPLAY::get_cur_code_line()
596 {
597 //#ifdef _X1TURBO_FEATURE
598 //      int ht_clock = hireso ? 161 : 250;
599 //#else
600         #define ht_clock 250
601 //#endif
602         int clock = get_passed_clock(vblank_clock);
603         int vt_line = vt_disp * ch_height + (int)(clock / ht_clock);
604         
605         int addr = (hz_total * (clock % ht_clock)) / ht_clock;
606         addr += hz_disp * (int)(vt_line / ch_height);
607         if(addr > 0x7ff) {
608                 addr = 0x7ff;
609         }
610         addr += st_addr;
611         
612         cur_code = vram_t[addr & 0x7ff];
613         cur_line = (vt_line % ch_height) & 7;
614 }
615
616 void DISPLAY::draw_line(int v)
617 {
618         if(v == 0) {
619                 memset(text, 0, sizeof(text));
620                 memset(cg, 0, sizeof(cg));
621                 prev_vert_double = false;
622                 raster = 0;
623         }
624         if((regs[8] & 0x30) != 0x30) {
625                 if((v % ch_height) == 0) {
626                         draw_text(v / ch_height);
627                 }
628                 draw_cg(v);
629                 memcpy(&pri_line[v][0][0], &pri[0][0], sizeof(pri));
630         } else {
631                 memset(&pri_line[v][0][0], 0, sizeof(pri));
632         }
633 }
634
635 void DISPLAY::draw_screen()
636 {
637         // copy to real screen
638 #ifdef _X1TURBO_FEATURE
639         if(hireso) {
640                 // 400 lines
641                 if(column40) {
642                         // 40 columns
643                         for(int y = 0; y < 400; y++) {
644                                 scrntype* dest = emu->get_screen_buffer(y);
645                                 uint8* src_text = text_bak[y];
646                                 uint8* src_cg = cg_bak[y];
647                                 
648                                 for(int x = 0, x2 = 0; x < 320; x++, x2 += 2) {
649                                         dest[x2] = dest[x2 + 1] = palette_pc[pri_line[y][src_cg[x]][src_text[x]]];
650                                 }
651                         }
652                 } else {
653                         // 80 columns
654                         for(int y = 0; y < 400; y++) {
655                                 scrntype* dest = emu->get_screen_buffer(y);
656                                 uint8* src_text = text_bak[y];
657                                 uint8* src_cg = cg_bak[y];
658                                 
659                                 for(int x = 0; x < 640; x++) {
660                                         dest[x] = palette_pc[pri_line[y][src_cg[x]][src_text[x]]];
661                                 }
662                         }
663                 }
664                 emu->screen_skip_line(false);
665         } else {
666 #endif
667                 // 200 lines
668                 if(column40) {
669                         // 40 columns
670                         for(int y = 0; y < 200; y++) {
671                                 scrntype* dest0 = emu->get_screen_buffer(y * 2 + 0);
672                                 scrntype* dest1 = emu->get_screen_buffer(y * 2 + 1);
673                                 uint8* src_text = text_bak[y];
674                                 uint8* src_cg = cg_bak[y];
675                                 
676                                 for(int x = 0, x2 = 0; x < 320; x++, x2 += 2) {
677                                         dest0[x2] = dest0[x2 + 1] = palette_pc[pri_line[y][src_cg[x]][src_text[x]]];
678                                 }
679                                 if(!config.scan_line) {
680                                         memcpy(dest1, dest0, 640 * sizeof(scrntype));
681                                 } else {
682                                         memset(dest1, 0, 640 * sizeof(scrntype));
683                                 }
684                         }
685                 } else {
686                         // 80 columns
687                         for(int y = 0; y < 200; y++) {
688                                 scrntype* dest0 = emu->get_screen_buffer(y * 2 + 0);
689                                 scrntype* dest1 = emu->get_screen_buffer(y * 2 + 1);
690                                 uint8* src_text = text_bak[y];
691                                 uint8* src_cg = cg_bak[y];
692                                 
693                                 for(int x = 0; x < 640; x++) {
694                                         dest0[x] = palette_pc[pri_line[y][src_cg[x]][src_text[x]]];
695                                 }
696                                 if(!config.scan_line) {
697                                         memcpy(dest1, dest0, 640 * sizeof(scrntype));
698                                 } else {
699                                         memset(dest1, 0, 640 * sizeof(scrntype));
700                                 }
701                         }
702                 }
703                 emu->screen_skip_line(true);
704 #ifdef _X1TURBO_FEATURE
705         }
706 #endif
707 }
708
709 void DISPLAY::draw_text(int y)
710 {
711         int width = column40 ? 40 : 80;
712         uint16_t src = st_addr + hz_disp * y;
713         
714         bool cur_vert_double = true;
715         uint8_t prev_attr = 0, prev_pattern_b[32], prev_pattern_r[32], prev_pattern_g[32];
716         
717         for(int x = 0; x < hz_disp && x < width; x++) {
718                 src &= 0x7ff;
719                 uint8_t code = vram_t[src];
720 #ifdef _X1TURBO_FEATURE
721                 uint8_t knj = vram_k[src];
722 #endif
723                 uint8_t attr = vram_a[src];
724                 src++;
725                 
726                 uint8_t col = attr & 7;
727                 bool reverse = ((attr & 8) != 0);
728                 bool blink = ((attr & 0x10) && (cblink & 0x20));
729                 reverse = (reverse != blink);
730                 
731                 // select pcg or ank
732                 const uint8_t *pattern_b, *pattern_r, *pattern_g;
733 #ifdef _X1TURBO_FEATURE
734                 int shift = 0;
735                 int max_line = 8;
736 #else
737                 #define max_line 8
738 #endif
739                 if(attr & 0x20) {
740                         // pcg
741 #ifdef _X1TURBO_FEATURE
742                         if(knj & 0x90) {
743                                 pattern_b = gaiji_b[code >> 1];
744                                 pattern_r = gaiji_r[code >> 1];
745                                 pattern_g = gaiji_g[code >> 1];
746                                 max_line = 16;
747                         } else {
748 #endif
749                                 pattern_b = pcg_b[code];
750                                 pattern_r = pcg_r[code];
751                                 pattern_g = pcg_g[code];
752 #ifdef _X1TURBO_FEATURE
753                                 shift = hireso ? 1 : 0;
754                         }
755 #endif
756 #ifdef _X1TURBO_FEATURE
757                 } else if(knj & 0x80) {
758                         uint32_t ofs = adr2knj_x1t((knj << 8) | code);
759                         if(knj & 0x40) {
760                                 ofs += 16; // right
761                         }
762                         pattern_b = pattern_r = pattern_g = &kanji[ofs];
763                         shift = hireso ? ((ch_height >= 32) ? 1 : 0) : ((ch_height >= 16) ? 0 : -1);
764                         max_line = 16;
765                 } else if(hireso || (mode1 & 4)) {
766                         // ank 8x16 or kanji
767                         pattern_b = pattern_r = pattern_g = &kanji[code << 4];
768                         shift = hireso ? ((ch_height >= 32) ? 1 : 0) : ((ch_height >= 16) ? 0 : -1);
769                         max_line = 16;
770 #endif
771                 } else {
772                         // ank 8x8
773                         pattern_b = pattern_r = pattern_g = &font[code << 3];
774                 }
775                 
776                 // check vertical doubled char
777                 if(!(attr & 0x40)) {
778                         cur_vert_double = false;
779                 }
780                 
781                 // render character
782                 for(int l = 0; l < ch_height; l++) {
783                         uint8_t b, r, g;
784                         int line = cur_vert_double ? raster + (l >> 1) : l;
785 #ifdef _X1TURBO_FEATURE
786                         if(shift == 1) {
787                                 line >>= 1;
788                         } else if(shift == -1) {
789                                 line <<= 1;
790                                 if(cur_vert_double) {
791                                         line |= l & 1;
792                                 }
793                         }
794 #endif
795                         if((x & 1) && (prev_attr & 0x80)) {
796                                 b = prev_pattern_b[line] << 4;
797                                 r = prev_pattern_r[line] << 4;
798                                 g = prev_pattern_g[line] << 4;
799                         } else if(line >= max_line) {
800                                 b = prev_pattern_b[line] = 0;
801                                 r = prev_pattern_r[line] = 0;
802                                 g = prev_pattern_g[line] = 0;
803                         } else {
804                                 b = prev_pattern_b[line] = pattern_b[line];
805                                 r = prev_pattern_r[line] = pattern_r[line];
806                                 g = prev_pattern_g[line] = pattern_g[line];
807                         }
808                         if(reverse) {
809                                 b = (!(col & 1)) ? 0xff : ~b;
810                                 r = (!(col & 2)) ? 0xff : ~r;
811                                 g = (!(col & 4)) ? 0xff : ~g;
812                         } else {
813                                 b = (!(col & 1)) ? 0 : b;
814                                 r = (!(col & 2)) ? 0 : r;
815                                 g = (!(col & 4)) ? 0 : g;
816                         }
817                         
818                         int yy = y * ch_height + l;
819 #ifdef _X1TURBO_FEATURE
820                         if(yy >= 400) {
821 #else
822                         if(yy >= 200) {
823 #endif
824                                 break;
825                         }
826                         uint8_t* d = &text[yy][x << 3];
827                         
828                         if(attr & 0x80) {
829                                 // horizontal doubled char
830                                 d[ 0] = d[ 1] = ((b & 0x80) >> 7) | ((r & 0x80) >> 6) | ((g & 0x80) >> 5);
831                                 d[ 2] = d[ 3] = ((b & 0x40) >> 6) | ((r & 0x40) >> 5) | ((g & 0x40) >> 4);
832                                 d[ 4] = d[ 5] = ((b & 0x20) >> 5) | ((r & 0x20) >> 4) | ((g & 0x20) >> 3);
833                                 d[ 6] = d[ 7] = ((b & 0x10) >> 4) | ((r & 0x10) >> 3) | ((g & 0x10) >> 2);
834                         } else {
835                                 d[0] = ((b & 0x80) >> 7) | ((r & 0x80) >> 6) | ((g & 0x80) >> 5);
836                                 d[1] = ((b & 0x40) >> 6) | ((r & 0x40) >> 5) | ((g & 0x40) >> 4);
837                                 d[2] = ((b & 0x20) >> 5) | ((r & 0x20) >> 4) | ((g & 0x20) >> 3);
838                                 d[3] = ((b & 0x10) >> 4) | ((r & 0x10) >> 3) | ((g & 0x10) >> 2);
839                                 d[4] = ((b & 0x08) >> 3) | ((r & 0x08) >> 2) | ((g & 0x08) >> 1);
840                                 d[5] = ((b & 0x04) >> 2) | ((r & 0x04) >> 1) | ((g & 0x04) >> 0);
841                                 d[6] = ((b & 0x02) >> 1) | ((r & 0x02) >> 0) | ((g & 0x02) << 1);
842                                 d[7] = ((b & 0x01) >> 0) | ((r & 0x01) << 1) | ((g & 0x01) << 2);
843                         }
844                 }
845                 prev_attr = attr;
846         }
847         if(cur_vert_double && !prev_vert_double) {
848                 prev_vert_double = true;
849                 raster = ch_height >> 1;
850         } else {
851                 prev_vert_double = false;
852                 raster = 0;
853         }
854 }
855
856 void DISPLAY::draw_cg(int line)
857 {
858         int width = column40 ? 40 : 80;
859         
860         int y = line / ch_height;
861         int l = line % ch_height;
862         if(y >= vt_disp) {
863                 return;
864         }
865         int ofs, src = st_addr + hz_disp * y;
866 #ifdef _X1TURBO_FEATURE
867         int page = (hireso && !(mode1 & 2)) ? (l & 1) : (mode1 & 8);
868         int ll = hireso ? (l >> 1) : l;
869         
870         if(mode1 & 4) {
871                 ofs = (0x400 * (ll & 15)) + (page ? 0xc000 : 0);
872         } else {
873                 ofs = (0x800 * (ll & 7)) + (page ? 0xc000 : 0);
874         }
875 #else
876         ofs = 0x800 * (l & 7);
877 #endif
878         int ofs_b = ofs + 0x0000;
879         int ofs_r = ofs + 0x4000;
880         int ofs_g = ofs + 0x8000;
881         
882         for(int x = 0; x < hz_disp && x < width; x++) {
883                 src &= 0x7ff;
884                 uint8_t b = vram_ptr[ofs_b | src];
885                 uint8_t r = vram_ptr[ofs_r | src];
886                 uint8_t g = vram_ptr[ofs_g | src++];
887                 uint8_t* d = &cg[line][x << 3];
888                 
889                 d[0] = ((b & 0x80) >> 7) | ((r & 0x80) >> 6) | ((g & 0x80) >> 5);
890                 d[1] = ((b & 0x40) >> 6) | ((r & 0x40) >> 5) | ((g & 0x40) >> 4);
891                 d[2] = ((b & 0x20) >> 5) | ((r & 0x20) >> 4) | ((g & 0x20) >> 3);
892                 d[3] = ((b & 0x10) >> 4) | ((r & 0x10) >> 3) | ((g & 0x10) >> 2);
893                 d[4] = ((b & 0x08) >> 3) | ((r & 0x08) >> 2) | ((g & 0x08) >> 1);
894                 d[5] = ((b & 0x04) >> 2) | ((r & 0x04) >> 1) | ((g & 0x04) >> 0);
895                 d[6] = ((b & 0x02) >> 1) | ((r & 0x02) >> 0) | ((g & 0x02) << 1);
896                 d[7] = ((b & 0x01) >> 0) | ((r & 0x01) << 1) | ((g & 0x01) << 2);
897         }
898 }
899
900 // kanji rom (from X1EMU by KM)
901
902 void DISPLAY::write_kanji(uint32_t addr, uint32_t data)
903 {
904         switch(addr) {
905         case 0xe80:
906                 kaddr = (kaddr & 0xff00) | data;
907                 break;
908         case 0xe81:
909                 kaddr = (kaddr & 0xff) | (data << 8);
910                 break;
911         case 0xe82:
912                 // TODO: bit0 L->H: Latch
913                 kanji_ptr = &kanji[adr2knj_x1(kaddr & 0xfff0)];
914                 break;
915         }
916 }
917
918 uint32_t DISPLAY::read_kanji(uint32_t addr)
919 {
920         switch(addr) {
921         case 0xe80:
922                 if(kaddr & 0xff00) {
923                         uint32_t val = kanji_ptr[kofs];
924                         kflag |= 1;
925                         if(kflag == 3) {
926                                 kofs = (kofs + 1) & 15;
927                                 kflag = 0;
928                         }
929                         return val;
930                 }
931                 return jis2adr_x1(kaddr << 8) >> 8;
932         case 0xe81:
933                 if(kaddr & 0xff00) {
934                         uint32_t val = kanji_ptr[kofs + 16];
935                         kflag |= 2;
936                         if(kflag == 3) {
937                                 kofs = (kofs + 1) & 15;
938                                 kflag = 0;
939                         }
940                         return val;
941                 }
942                 return 0;
943         }
944         return 0xff;
945 }
946
947 uint16_t DISPLAY::jis2adr_x1(uint16_t jis)
948 {
949         uint16_t jh, jl, adr;
950         
951         jh = jis >> 8;
952         jl = jis & 0xff;
953         if(jh > 0x28) {
954                 adr = 0x4000 + (jh - 0x30) * 0x600;
955         } else {
956                 adr = 0x0100 + (jh - 0x21) * 0x600;
957         }
958         if(jl >= 0x20) {
959                 adr += (jl - 0x20) * 0x10;
960         }
961         return adr;
962 }
963
964 uint32_t DISPLAY::adr2knj_x1(uint16_t adr)
965 {
966         uint16_t jh, jl, jis;
967         
968         if(adr < 0x4000) {
969                 jh = adr - 0x0100;
970                 jh = 0x21 + jh / 0x600;
971         } else {
972                 jh = adr - 0x4000;
973                 jh = 0x30 + jh / 0x600;
974         }
975         if(jh > 0x28) {
976                 adr -= 0x4000 + (jh - 0x30) * 0x600;
977         } else {
978                 adr -= 0x0100 + (jh - 0x21) * 0x600;
979         }
980         jl = 0x20;
981         if(adr) {
982                 jl += adr / 0x10;
983         }
984         
985         jis = (jh << 8) | jl;
986         return jis2knj(jis);
987 }
988
989 #ifdef _X1TURBO_FEATURE
990 uint32_t DISPLAY::adr2knj_x1t(uint16_t adr)
991 {
992         uint16_t j1, j2;
993         uint16_t rl, rh;
994         uint16_t jis;
995         
996         rh = adr >> 8;
997         rl = adr & 0xff;
998         
999         rh &= 0x1f;
1000         if(!rl && !rh) {
1001                 return jis2knj(0);
1002         }
1003         j2 = rl & 0x1f;         // rl4,3,2,1,0
1004         j1 = (rl / 0x20) & 7;   // rl7,6,5
1005         
1006         if(rh < 0x04) {
1007                 // 2121-277e
1008                 j1 |= 0x20;
1009                 switch(rh & 3) {
1010                 case 0: j2 |= 0x20; break;
1011                 case 1: j2 |= 0x60; break;
1012                 case 2: j2 |= 0x40; break;
1013                 default: j1 = j2 = 0; break;
1014                 }
1015         } else if(rh > 0x1c) {
1016                 // 7021-777e
1017                 j1 |= 0x70;
1018                 switch(rh & 3) {
1019                 case 0: j2 |= 0x20; break;
1020                 case 1: j2 |= 0x60; break;
1021                 case 2: j2 |= 0x40; break;
1022                 default: j1 = j2 = 0; break;
1023                 }
1024         } else {
1025                 j1 |= (((rh >> 1) + 7) / 3) * 0x10;
1026                 j1 |= (rh & 1) * 8;
1027                 j2 |= ((((rh >> 1) + 1) % 3) + 1) * 0x20;
1028         }
1029         
1030         jis = (j1 << 8) | j2;
1031         return jis2knj(jis);
1032 }
1033 #endif
1034
1035 uint32_t DISPLAY::jis2knj(uint16_t jis)
1036 {
1037         uint32_t sjis = jis2sjis(jis);
1038         
1039         if(sjis < 0x100) {
1040                 return sjis * 16;
1041         } else if(sjis >= 0x8140 && sjis < 0x84c0) {
1042                 return 0x01000 + (sjis - 0x8140) * 32;
1043         } else if(sjis >= 0x8890 && sjis < 0xa000) {
1044                 return 0x08000 + (sjis - 0x8890) * 32;
1045         } else if(sjis >= 0xe040 && sjis < 0xeab0) {
1046                 return 0x36e00 + (sjis - 0xe040) * 32;
1047         } else {
1048                 return 0;
1049         }
1050 }
1051
1052 uint16_t DISPLAY::jis2sjis(uint16_t jis)
1053 {
1054         uint16_t c1, c2;
1055         
1056         if(!jis) {
1057                 return 0;
1058         }
1059         c1 = jis >> 8;
1060         c2 = jis & 0xff;
1061         
1062         if(c1 & 1) {
1063                 c2 += 0x1f;
1064                 if(c2 >= 0x7f) {
1065                         c2++;
1066                 }
1067         } else {
1068                 c2 += 0x7e;
1069         }
1070         c1 = (c1 - 0x20 - 1) / 2 + 0x81;
1071         if(c1 >= 0xa0) {
1072                 c1 += 0x40;
1073         }
1074         return (c1 << 8) | c2;
1075 }
1076
1077 #define STATE_VERSION   2
1078
1079 void DISPLAY::save_state(FILEIO* state_fio)
1080 {
1081         state_fio->FputUint32(STATE_VERSION);
1082         state_fio->FputInt32(this_device_id);
1083         
1084         state_fio->Fwrite(vram_t, sizeof(vram_t), 1);
1085         state_fio->Fwrite(vram_a, sizeof(vram_a), 1);
1086 #ifdef _X1TURBO_FEATURE
1087         state_fio->Fwrite(vram_k, sizeof(vram_k), 1);
1088 #endif
1089         state_fio->Fwrite(pcg_b, sizeof(pcg_b), 1);
1090         state_fio->Fwrite(pcg_r, sizeof(pcg_r), 1);
1091         state_fio->Fwrite(pcg_g, sizeof(pcg_g), 1);
1092 #ifdef _X1TURBO_FEATURE
1093         state_fio->Fwrite(gaiji_b, sizeof(gaiji_b), 1);
1094         state_fio->Fwrite(gaiji_r, sizeof(gaiji_r), 1);
1095         state_fio->Fwrite(gaiji_g, sizeof(gaiji_g), 1);
1096 #endif
1097         state_fio->FputUint8(cur_code);
1098         state_fio->FputUint8(cur_line);
1099         state_fio->FputInt32(kaddr);
1100         state_fio->FputInt32(kofs);
1101         state_fio->FputInt32(kflag);
1102         state_fio->FputInt32((int)(kanji_ptr - &kanji[0]));
1103         state_fio->Fwrite(pal, sizeof(pal), 1);
1104         state_fio->FputUint8(priority);
1105         state_fio->Fwrite(pri, sizeof(pri), 1);
1106         state_fio->FputBool(column40);
1107 #ifdef _X1TURBO_FEATURE
1108         state_fio->FputUint8(mode1);
1109         state_fio->FputUint8(mode2);
1110         state_fio->FputBool(hireso);
1111 #endif
1112 #ifdef _X1TURBOZ
1113         state_fio->FputUint8(zmode1);
1114         state_fio->FputUint8(zpriority);
1115         state_fio->FputUint8(zscroll);
1116         state_fio->FputUint8(zmode2);
1117         state_fio->Fwrite(ztpal, sizeof(ztpal), 1);
1118         state_fio->Fwrite(zpal, sizeof(zpal), 1);
1119         state_fio->FputInt32(zpal_num);
1120         state_fio->Fwrite(palette_pc, sizeof(palette_pc), 1);
1121 #endif
1122         state_fio->FputBool(prev_vert_double);
1123         state_fio->FputInt32(raster);
1124         state_fio->FputInt32(cblink);
1125         state_fio->FputInt32(ch_height);
1126         state_fio->FputInt32(hz_total);
1127         state_fio->FputInt32(hz_disp);
1128         state_fio->FputInt32(vt_disp);
1129         state_fio->FputInt32(st_addr);
1130         state_fio->FputUint32(vblank_clock);
1131 }
1132
1133 bool DISPLAY::load_state(FILEIO* state_fio)
1134 {
1135         if(state_fio->FgetUint32() != STATE_VERSION) {
1136                 return false;
1137         }
1138         if(state_fio->FgetInt32() != this_device_id) {
1139                 return false;
1140         }
1141         state_fio->Fread(vram_t, sizeof(vram_t), 1);
1142         state_fio->Fread(vram_a, sizeof(vram_a), 1);
1143 #ifdef _X1TURBO_FEATURE
1144         state_fio->Fread(vram_k, sizeof(vram_k), 1);
1145 #endif
1146         state_fio->Fread(pcg_b, sizeof(pcg_b), 1);
1147         state_fio->Fread(pcg_r, sizeof(pcg_r), 1);
1148         state_fio->Fread(pcg_g, sizeof(pcg_g), 1);
1149 #ifdef _X1TURBO_FEATURE
1150         state_fio->Fread(gaiji_b, sizeof(gaiji_b), 1);
1151         state_fio->Fread(gaiji_r, sizeof(gaiji_r), 1);
1152         state_fio->Fread(gaiji_g, sizeof(gaiji_g), 1);
1153 #endif
1154         cur_code = state_fio->FgetUint8();
1155         cur_line = state_fio->FgetUint8();
1156         kaddr = state_fio->FgetInt32();
1157         kofs = state_fio->FgetInt32();
1158         kflag = state_fio->FgetInt32();
1159         kanji_ptr = &kanji[0] + state_fio->FgetInt32();
1160         state_fio->Fread(pal, sizeof(pal), 1);
1161         priority = state_fio->FgetUint8();
1162         state_fio->Fread(pri, sizeof(pri), 1);
1163         column40 = state_fio->FgetBool();
1164 #ifdef _X1TURBO_FEATURE
1165         mode1 = state_fio->FgetUint8();
1166         mode2 = state_fio->FgetUint8();
1167         hireso = state_fio->FgetBool();
1168 #endif
1169 #ifdef _X1TURBOZ
1170         zmode1 = state_fio->FgetUint8();
1171         zpriority = state_fio->FgetUint8();
1172         zscroll = state_fio->FgetUint8();
1173         zmode2 = state_fio->FgetUint8();
1174         state_fio->Fread(ztpal, sizeof(ztpal), 1);
1175         state_fio->Fread(zpal, sizeof(zpal), 1);
1176         zpal_num = state_fio->FgetInt32();
1177         state_fio->Fread(palette_pc, sizeof(palette_pc), 1);
1178 #endif
1179         prev_vert_double = state_fio->FgetBool();
1180         raster = state_fio->FgetInt32();
1181         cblink = state_fio->FgetInt32();
1182         ch_height = state_fio->FgetInt32();
1183         hz_total = state_fio->FgetInt32();
1184         hz_disp = state_fio->FgetInt32();
1185         vt_disp = state_fio->FgetInt32();
1186         st_addr = state_fio->FgetInt32();
1187         vblank_clock = state_fio->FgetUint32();
1188         return true;
1189 }
1190