OSDN Git Service

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