OSDN Git Service

8afaea53d97ae597c9e3d6e61d54844a6d82105e
[csp-qt/common_source_project-fm7.git] / source / src / vm / mz2800 / crtc.cpp
1 /*
2         SHARP MZ-2800 Emulator 'EmuZ-2800'
3
4         Author : Takeda.Toshiya
5         Date   : 2007.08.13 -
6
7         [ crtc ]
8 */
9
10 #include "crtc.h"
11 #include "../i8255.h"
12 #include "../i8259.h"
13
14 #define EVENT_HSYNC     0
15 #define EVENT_BLINK     256
16
17 #define SCRN_640x400    1
18 #define SCRN_640x200    2
19
20 void CRTC::initialize()
21 {
22         // set 16/4096 palette
23         for(int i = 0; i < 16; i++) {
24                 uint8_t r = ((i & 0x0f) == 8) ? 152 : ((i & 0x0a) == 0x0a) ? 255 : ((i & 0x0a) == 2) ? 127 : 0;
25                 uint8_t g = ((i & 0x0f) == 8) ? 152 : ((i & 0x0c) == 0x0c) ? 255 : ((i & 0x0c) == 4) ? 127 : 0;
26                 uint8_t b = ((i & 0x0f) == 8) ? 152 : ((i & 0x09) == 0x09) ? 255 : ((i & 0x09) == 1) ? 127 : 0;
27                 palette16[i] = RGB_COLOR(r, g, b);
28                 palette4096r[i] = r;
29                 palette4096g[i] = g;
30                 palette4096b[i] = b;
31                 palette4096[i] = RGB_COLOR(r, g, b);
32         }
33         for(int i = 0; i < 8; i++) {
34                 palette16[i + 16] = RGB_COLOR((i & 2) ? 255 : 0, (i & 4) ? 255 : 0, (i & 1) ? 255 : 0);
35         }
36         for(int i = 0; i < 16; i++) {
37                 for(int j = 1; j < 8; j++) {
38                         priority16[i][j] = j + 16;
39                 }
40                 priority16[i][0] = i; // transparent black
41                 priority16[i][8] = 0 + 16; // non transparent black
42         }
43         prev16 = 0xff;
44         update16 = true;
45         
46         // set 65536 palette
47         for(int i = 0; i < 65536; i++) {
48                 // BBBB RRRR GGGG IGRB
49                 uint8_t b = ((i & 0xf000) >> 8) | ((i & 1) << 3) | ((i & 8) >> 1);
50                 uint8_t r = ((i & 0x0f00) >> 4) | ((i & 2) << 2) | ((i & 8) >> 1);
51                 uint8_t g = ((i & 0x00f0) >> 0) | ((i & 4) << 1) | ((i & 8) >> 1);
52                 palette65536[i] = RGB_COLOR(r, g, b);
53         }
54         
55         // extract cg optimize matrix
56         for(int p1 = 0; p1 < 256; p1++) {
57                 for(int p2 = 0; p2 < 256; p2++) {
58                         for(int i = 0; i < 8; i++) {
59                                 cg_matrix0[p1][p2][i] = (p1 & (0x80 >> i) ? 0x01 : 0) | (p2 & (0x80 >> i) ? 0x02 : 0);
60                                 cg_matrix1[p1][p2][i] = (p1 & (0x80 >> i) ? 0x04 : 0) | (p2 & (0x80 >> i) ? 0x08 : 0);
61                                 cg_matrix2[p1][p2][i] = (p1 & (0x80 >> i) ? 0x10 : 0) | (p2 & (0x80 >> i) ? 0x20 : 0);
62                                 cg_matrix3[p1][p2][i] = (p1 & (0x80 >> i) ? 0x40 : 0) | (p2 & (0x80 >> i) ? 0x80 : 0);
63                         }
64                 }
65         }
66         
67         // initialize crtc
68         memset(textreg, 0, sizeof(textreg));
69         memset(rmwreg, 0, sizeof(rmwreg));
70         memset(cgreg, 0, sizeof(cgreg));
71         memset(latch, 0, sizeof(latch));
72         
73         rmwreg_num[0] = rmwreg_num[1] = cgreg_num = 0x80;
74         GDEVS =   0; cgreg[0] = 0x00; cgreg[1] = 0x00;
75         GDEVE = 400; cgreg[2] = 0x90; cgreg[3] = 0x01;
76         GDEHS =   0; cgreg[4] = 0x00;
77         GDEHSC = (int)(CPU_CLOCKS * GDEHS / FRAMES_PER_SEC / LINES_PER_FRAME / CHARS_PER_LINE + 0.5);
78         GDEHE =  80; cgreg[5] = 0x50;
79         GDEHEC = (int)(CPU_CLOCKS * GDEHE / FRAMES_PER_SEC / LINES_PER_FRAME / CHARS_PER_LINE + 0.5);
80         
81         for(int i = 0; i < 16; i++) {
82                 palette_reg[i] = i;
83         }
84         scrn_size = SCRN_640x400;
85         font_size = true;
86         column_size = true;
87         cg_mask = 0x0f;
88         clear_flag = 0;
89         pal_select = false;
90         screen_mask = false;
91         blink = false;
92         blank = hblank = vblank = false;
93         map_init = trans_init = true;
94         
95         // register events
96         register_vline_event(this);
97         register_event(this, EVENT_BLINK, 500000, true, NULL);
98 }
99
100 void CRTC::write_data8(uint32_t addr, uint32_t data)
101 {
102         // read modify write
103         int lh = addr & 1;
104         addr &= 0x1ffff;
105         if((rmwreg[lh][5] & 0xc0) == 0x00) {
106                 // REPLACE
107                 if(rmwreg[lh][5] & 1) {
108                         vram_b[addr] &= ~rmwreg[lh][6];
109                         vram_b[addr] |= (rmwreg[lh][4] & 1) ? (data & rmwreg[lh][0] & rmwreg[lh][6]) : 0;
110                 }
111                 if(rmwreg[lh][5] & 2) {
112                         vram_r[addr] &= ~rmwreg[lh][6];
113                         vram_r[addr] |= (rmwreg[lh][4] & 2) ? (data & rmwreg[lh][1] & rmwreg[lh][6]) : 0;
114                 }
115                 if(rmwreg[lh][5] & 4) {
116                         vram_g[addr] &= ~rmwreg[lh][6];
117                         vram_g[addr] |= (rmwreg[lh][4] & 4) ? (data & rmwreg[lh][2] & rmwreg[lh][6]) : 0;
118                 }
119                 if(rmwreg[lh][5] & 8) {
120                         vram_i[addr] &= ~rmwreg[lh][6];
121                         vram_i[addr] |= (rmwreg[lh][4] & 8) ? (data & rmwreg[lh][3] & rmwreg[lh][6]) : 0;
122                 }
123         } else if((rmwreg[lh][5] & 0xc0) == 0x40) {
124                 // PSET
125                 if(rmwreg[lh][5] & 1) {
126                         vram_b[addr] &= ~data;
127                         vram_b[addr] |= (rmwreg[lh][4] & 1) ? (data & rmwreg[lh][0]) : 0;
128                 }
129                 if(rmwreg[lh][5] & 2) {
130                         vram_r[addr] &= ~data;
131                         vram_r[addr] |= (rmwreg[lh][4] & 2) ? (data & rmwreg[lh][1]) : 0;
132                 }
133                 if(rmwreg[lh][5] & 4) {
134                         vram_g[addr] &= ~data;
135                         vram_g[addr] |= (rmwreg[lh][4] & 4) ? (data & rmwreg[lh][2]) : 0;
136                 }
137                 if(rmwreg[lh][5] & 8) {
138                         vram_i[addr] &= ~data;
139                         vram_i[addr] |= (rmwreg[lh][4] & 8) ? (data & rmwreg[lh][3]) : 0;
140                 }
141         }
142 }
143
144 uint32_t CRTC::read_data8(uint32_t addr)
145 {
146         // read modify write
147         int lh = addr & 1;
148         addr &= 0x1ffff;
149         uint8_t b = latch[lh][0] = vram_b[addr];
150         uint8_t r = latch[lh][1] = vram_r[addr];
151         uint8_t g = latch[lh][2] = vram_g[addr];
152         uint8_t i = latch[lh][3] = vram_i[addr];
153         uint8_t pl = rmwreg[lh][7] & 3;
154         
155         if(rmwreg[lh][7] & 0x10) {
156                 uint8_t compare = rmwreg[lh][7] & 0x0f;
157                 uint8_t val = (compare == (((b & 0x80) >> 7) | ((r & 0x80) >> 6) | ((g & 0x80) >> 5) | ((i & 0x80) >> 4))) ? 0x80 : 0;
158                 val |= (compare == (((b & 0x40) >> 6) | ((r & 0x40) >> 5) | ((g & 0x40) >> 4) | ((i & 0x40) >> 3))) ? 0x40 : 0;
159                 val |= (compare == (((b & 0x20) >> 5) | ((r & 0x20) >> 4) | ((g & 0x20) >> 3) | ((i & 0x20) >> 2))) ? 0x20 : 0;
160                 val |= (compare == (((b & 0x10) >> 4) | ((r & 0x10) >> 3) | ((g & 0x10) >> 2) | ((i & 0x10) >> 1))) ? 0x10 : 0;
161                 val |= (compare == (((b & 0x08) >> 3) | ((r & 0x08) >> 2) | ((g & 0x08) >> 1) | ((i & 0x08)     ))) ? 0x08 : 0;
162                 val |= (compare == (((b & 0x04) >> 2) | ((r & 0x04) >> 1) | ((g & 0x04)     ) | ((i & 0x04) << 1))) ? 0x04 : 0;
163                 val |= (compare == (((b & 0x02) >> 1) | ((r & 0x02)     ) | ((g & 0x02) << 1) | ((i & 0x02) << 2))) ? 0x02 : 0;
164                 val |= (compare == (((b & 0x01)     ) | ((r & 0x01) << 1) | ((g & 0x01) << 2) | ((i & 0x01) << 3))) ? 0x01 : 0;
165                 return val;
166         } else {
167                 return latch[lh][pl];
168         }
169 }
170
171 void CRTC::write_io8(uint32_t addr, uint32_t data)
172 {
173         uint8_t num, r, g, b, prev;
174         int lh = addr & 1;
175         
176         switch(addr & 0x7fff) {
177         case 0x00ae: case 0x01ae: case 0x02ae: case 0x03ae: case 0x04ae: case 0x05ae: case 0x06ae: case 0x07ae:
178         case 0x08ae: case 0x09ae: case 0x0aae: case 0x0bae: case 0x0cae: case 0x0dae: case 0x0eae: case 0x0fae:
179         case 0x10ae: case 0x11ae: case 0x12ae: case 0x13ae: case 0x14ae: case 0x15ae: case 0x16ae: case 0x17ae:
180         case 0x18ae: case 0x19ae: case 0x1aae: case 0x1bae: case 0x1cae: case 0x1dae: case 0x1eae: case 0x1fae:
181                 // 4096 palette reg
182                 num = (addr & 0x1f00) >> 9;
183                 r = palette4096r[num];
184                 g = palette4096g[num];
185                 b = palette4096b[num];
186                 if(addr & 0x100) {
187                         g = (data & 0x0f) << 4;
188                 } else {
189                         r = data & 0xf0;
190                         b = (data & 0x0f) << 4;
191                 }
192                 if(palette4096r[num] != r || palette4096g[num] != g || palette4096b[num] != b) {
193                         palette4096r[num] = r;
194                         palette4096g[num] = g;
195                         palette4096b[num] = b;
196                         palette4096[num] = RGB_COLOR(r, g, b);
197                         update16 = true;
198                 }
199                 // never change palette 0
200                 //palette4096[0] = 0;
201                 break;
202         case 0x170:
203                 // textreg num
204                 textreg_num = data;
205                 break;
206         case 0x172:
207                 // text/palette reg
208                 if(textreg_num < 0x10) {
209                         if(textreg_num == 0) {
210                                 trans_init |= ((textreg[0] & 2) != (uint8_t)(data & 2));
211                         }
212                         textreg[textreg_num] = data;
213                 } else if(0x80 <= textreg_num && textreg_num < 0x90) {
214                         int c = textreg_num & 0x0f;
215                         
216                         prev = palette_reg[c];
217                         palette_reg[c] = data;
218                         
219                         if((prev & 0x0f) != (uint8_t)(data & 0x0f)) {
220                                 update16 = true;
221                         }
222                         if((prev & 0x10) != (uint8_t)(data & 0x10)) {
223                                 int c16 = c << 4;
224                                 int col = data & 0x0f;
225                                 int col16 = col << 4;
226                                 int p = data & 0x10;
227                                 
228                                 // update priority
229                                 for(int i = 1; i < 8; i++) {
230                                         priority16[c][i] = p ? c : (i + 16);
231                                 }
232                                 priority16[c][0] = c; // transparent black
233                                 priority16[c][8] = p ? c : (0 + 16); // non transparent black
234                                 update16 = true;
235                         }
236                 }
237                 break;
238         case 0x174:
239                 // cg mask reg
240                 prev = cg_mask;
241                 cg_mask = (data & 7) | ((data & 1) ? 8 : 0);
242                 update16 |= (prev != cg_mask);
243                 break;
244         case 0x176:
245                 // font size reg
246                 font_size = ((data & 1) != 0);
247                 break;
248         case 0x178:
249         case 0x179:
250                 // rmwreg num
251                 rmwreg_num[lh] = data;
252                 break;
253         case 0x17a:
254         case 0x17b:
255                 // rmwreg
256                 rmwreg[lh][rmwreg_num[lh] & 0x1f] = data;
257                 // clear screen
258                 if((rmwreg_num[lh] & 0x1f) == 5 && (data & 0xc0) == 0x80) {
259                         uint16_t st, sz;
260                         switch(rmwreg[lh][0x0e]) {
261                         case 0x03: case 0x14: case 0x15: case 0x17: case 0x1d:
262                                 // clear 0x0000 - 0x4000
263                                 st = 0x0000;
264                                 sz = 0x4000;
265                                 break;
266                         case 0x94: case 0x95: case 0x97: case 0x9d:
267                                 // clear 0x4000 - 0x7fff
268                                 st = 0x4000;
269                                 sz = 0x4000;
270                                 break;
271                         default:
272                                 // clear 0x0000 - 0x7fff
273                                 st = 0x0000;
274                                 sz = 0x8000;
275                         }
276                         if(rmwreg[lh][5] & 1) {
277                                 memset(vram_b + st, 0, sz);
278                         }
279                         if(rmwreg[lh][5] & 2) {
280                                 memset(vram_r + st, 0, sz);
281                         }
282                         if(rmwreg[lh][5] & 4) {
283                                 memset(vram_g + st, 0, sz);
284                         }
285                         if(rmwreg[lh][5] & 8) {
286                                 memset(vram_i + st, 0, sz);
287                         }
288                         clear_flag = 1;
289                 }
290                 // inc rmwreg num
291                 if(rmwreg_num[lh] & 0x80) {
292                         rmwreg_num[lh] = (rmwreg_num[lh] & 0xfc) | ((rmwreg_num[lh] + 1) & 3);
293                 }
294                 break;
295         case 0x270:
296                 // cgreg num
297                 cgreg_num = data;
298                 break;
299         case 0x272:
300                 // cgreg
301                 prev = cgreg[cgreg_num & 0x1f];;
302                 cgreg[cgreg_num & 0x1f] = data;
303                 
304                 switch(cgreg_num & 0x1f) {
305                 // view range
306                 case 0x00:
307                         cgreg[1] = 0;
308                 case 0x01:
309                         GDEVS = (cgreg[0] | ((cgreg[1] & 1) << 8)); //* ((scrn_size == SCRN_640x400) ? 1 : 2);
310                         break;
311                 case 0x02:
312                         cgreg[3] = 0;
313                 case 0x03:
314                         GDEVE = (cgreg[2] | ((cgreg[3] & 1) << 8)); //* ((scrn_size == SCRN_640x400) ? 1 : 2);
315                         break;
316                 case 0x04:
317                         GDEHS = cgreg[4] & 0x7f;
318                         GDEHSC = (int)(CPU_CLOCKS * GDEHS / FRAMES_PER_SEC / LINES_PER_FRAME / CHARS_PER_LINE + 0.5);
319                         break;
320                 case 0x05:
321                         GDEHE = cgreg[5] & 0x7f;
322                         GDEHEC = (int)(CPU_CLOCKS * GDEHE / FRAMES_PER_SEC / LINES_PER_FRAME / CHARS_PER_LINE + 0.5);
323                         break;
324                 // screen size
325                 case 0x06:
326                         switch(data) {
327                         case 0x17: case 0x1f:
328                                 map_init |= (scrn_size != SCRN_640x200);
329                                 scrn_size = SCRN_640x200;
330                                 break;
331                         case 0x13: case 0x1b:
332                                 map_init |= (scrn_size != SCRN_640x400);
333                                 scrn_size = SCRN_640x400;
334                                 break;
335                         }
336                         break;
337                 // scroll
338                 case 0x07:
339                         map_init |= ((prev & 0x07) != (uint8_t)(data & 0x07));
340                         break;
341                 case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c:
342                         map_init |= (prev != (uint8_t)(data & 0xff));
343                         break;
344                 case 0x0d:
345                         map_init |= ((prev & 0x01) != (uint8_t)(data & 0x01));
346                         break;
347                 }
348                 // inc cgreg num
349                 if(cgreg_num & 0x80) {
350                         cgreg_num = (cgreg_num & 0xfc) | ((cgreg_num + 1) & 3);
351                 }
352                 break;
353         }
354 }
355
356 void CRTC::write_signal(int id, uint32_t data, uint32_t mask)
357 {
358         if(id == SIG_CRTC_COLUMN_SIZE) {
359                 column_size = ((data & mask) != 0);     // from z80pio port a
360         } else if(id == SIG_CRTC_PALLETE) {
361                 pal_select = ((data & mask) == 0);      // from ym2203 port a
362         } else if(id == SIG_CRTC_MASK) {
363                 screen_mask = ((data & mask) != 0);     // from i8255 port c
364         }
365 }
366
367 void CRTC::event_callback(int event_id, int err)
368 {
369         if(event_id & 512) {
370                 blink = !blink;
371         } else {
372                 set_hsync(event_id);
373         }
374 }
375
376 void CRTC::event_vline(int v, int clock)
377 {
378         // vblank
379         bool next = !(GDEVS <= v && v < GDEVE);
380         if(vblank != next) {
381                 // vblank on / off
382 //              d_pic->write_signal(SIG_I8259_CHIP0 | SIG_I8259_IR1, next ? 2 : 0, 2);
383 //              d_pio->write_signal(SIG_I8255_PORT_B, next ? 2 : 0, 2);
384                 vblank = next;
385         }
386 #if 1
387         // force vblank
388         if(v == 0) {
389                 d_pic->write_signal(SIG_I8259_CHIP0 | SIG_I8259_IR1, 0, 2);
390                 d_pio->write_signal(SIG_I8255_PORT_B, 0, 2);
391         } else if(v == 400) {
392                 d_pic->write_signal(SIG_I8259_CHIP0 | SIG_I8259_IR1, 2, 2);
393                 d_pio->write_signal(SIG_I8255_PORT_B, 2, 2);
394         }
395 #endif
396         
397         // complete clear screen
398         if(v == 400) {
399                 clear_flag = 0;
400         }
401         
402         // register hsync events
403         if(!GDEHS) {
404                 set_hsync(0);
405         } else if(GDEHS < CHARS_PER_LINE) {
406                 register_event_by_clock(this, GDEHS, GDEHSC, false, NULL);
407         }
408         if(!GDEHE) {
409                 set_hsync(0);
410         } else if(GDEHE < CHARS_PER_LINE) {
411                 register_event_by_clock(this, GDEHE, GDEHEC, false, NULL);
412         }
413 }
414
415 void CRTC::set_hsync(int h)
416 {
417         hblank = !(GDEHS <= h && h < GDEHE);
418         bool next = (hblank || vblank);
419         if(blank != next) {
420                 d_pio->write_signal(SIG_I8255_PORT_B, next ? 1 : 0, 1);
421                 blank = next;
422         }
423 }
424
425 // ----------------------------------------------------------------------------
426 // draw screen
427 // ----------------------------------------------------------------------------
428
429 void CRTC::draw_screen()
430 {
431         // update 16/4096 palette
432         uint8_t back16 = ((textreg[0x0b] & 4) >> 2) | ((textreg[0x0b] & 0x20) >> 4) | ((textreg[0x0c] & 1) << 2) | ((textreg[0x0b] & 1) << 3);
433         if(back16 != prev16) {
434                 prev16 = back16;
435                 update16 = true;
436         }
437         if(update16) {
438                 scrntype_t palette16tmp[16 + 8], palette4096tmp[16 + 8];
439                 for(int i = 0; i < 16 + 8; i++) {
440                         palette16tmp[i] = palette16[(i & 16) ? i : (palette_reg[i] & 0x0f) ? (palette_reg[i] & cg_mask) : (back16 & cg_mask)];
441                         uint8_t col = (i == 16) ? 0 : (i & 16) ? (i & 0x0f) + 8 : i;
442                         palette4096tmp[i] = palette4096[(palette_reg[col] & 0x0f) ? (palette_reg[col] & cg_mask) : (back16 & cg_mask)];
443                 }
444                 for(int i = 0; i < 16; i++) {
445                         for(int j = 0; j < 9; j++) {
446                                 palette16pri[i][j] = palette16tmp[priority16[i][j]];
447                                 palette4096pri[i][j] = palette4096tmp[priority16[i][j]];
448                         }
449                 }
450                 memcpy(palette16txt, &palette16tmp[16], sizeof(scrntype_t) * 8);
451                 palette16txt[0] = palette16[palette_reg[back16] & 0x0f];
452                 palette16txt[8] = 0;
453                 memcpy(palette4096txt, &palette4096tmp[16], sizeof(scrntype_t) * 8);
454                 palette4096txt[0] = palette4096[palette_reg[back16] & 0x0f];
455                 palette4096txt[8] = 0;
456                 update16 = false;
457         }
458         
459         // draw cg screen
460         memset(cg, 0, sizeof(cg));
461         draw_cg();
462         
463         // draw text screen
464         memset(text, 0, sizeof(text));
465         draw_text();
466         
467         // view port
468         int vs = (GDEVS <= GDEVE) ? GDEVS * (scrn_size == SCRN_640x400 ? 1 : 2) : 0;
469         int ve = (GDEVS <= GDEVE) ? GDEVE * (scrn_size == SCRN_640x400 ? 1 : 2) : 400;
470         int hs = (GDEHS <= GDEHE && GDEHS < 80) ? (GDEHS << 3) : 0;
471         int he = (GDEHS <= GDEHE && GDEHE < 80) ? (GDEHE << 3) : 640;
472         
473         // mix screens
474         if(screen_mask) {
475                 // screen is masked
476                 for(int y = 0; y < 400; y++) {
477                         scrntype_t *dest = emu->get_screen_buffer(y);
478                         memset(dest, 0, sizeof(scrntype_t) * 640);
479                 }
480         } else if(cgreg[6] == 0x1b || cgreg[6] == 0x1f) {
481                 // 65536 colors
482                 for(int y = 0; y < vs && y < 400; y++) {
483                         scrntype_t *dest = emu->get_screen_buffer(y);
484                         uint8_t *src_text = &text[640 * y];
485                         for(int x = 0; x < 640; x++) {
486                                 dest[x] = palette16txt[src_text[x]];
487                         }
488                 }
489                 for(int y = vs; y < ve && y < 400; y++) {
490                         scrntype_t *dest = emu->get_screen_buffer(y);
491                         uint16_t *src_cg = &cg[640 * y];
492                         uint8_t *src_text = &text[640 * y];
493                         for(int x = 0; x < hs && x < 640; x++) {
494                                 dest[x] = palette16txt[src_text[x]];
495                         }
496                         for(int x = hs; x < he && x < 640; x++) {
497                                 dest[x] = src_text[x] ? palette16txt[src_text[x]] : palette65536[src_cg[x]];
498                         }
499                         for(int x = he; x < 640; x++) {
500                                 dest[x] = palette16txt[src_text[x]];
501                         }
502                 }
503                 for(int y = ve; y < 400; y++) {
504                         scrntype_t *dest = emu->get_screen_buffer(y);
505                         uint8_t *src_text = &text[640 * y];
506                         for(int x = 0; x < 640; x++) {
507                                 dest[x] = palette16txt[src_text[x]];
508                         }
509                 }
510         } else if(!pal_select) {
511                 // 16 colors
512                 for(int y = 0; y < vs && y < 400; y++) {
513                         scrntype_t *dest = emu->get_screen_buffer(y);
514                         uint8_t *src_text = &text[640 * y];
515                         for(int x = 0; x < 640; x++) {
516                                 dest[x] = palette16txt[src_text[x]];
517                         }
518                 }
519                 for(int y = vs; y < ve && y < 400; y++) {
520                         scrntype_t *dest = emu->get_screen_buffer(y);
521                         uint16_t *src_cg = &cg[640 * y];
522                         uint8_t *src_text = &text[640 * y];
523                         for(int x = 0; x < hs && x < 640; x++) {
524                                 dest[x] = palette16txt[src_text[x]];
525                         }
526                         for(int x = hs; x < he && x < 640; x++) {
527                                 dest[x] = palette16pri[src_cg[x]][src_text[x]];
528                         }
529                         for(int x = he; x < 640; x++) {
530                                 dest[x] = palette16txt[src_text[x]];
531                         }
532                 }
533                 for(int y = ve; y < 400; y++) {
534                         scrntype_t *dest = emu->get_screen_buffer(y);
535                         uint8_t *src_text = &text[640 * y];
536                         for(int x = 0; x < 640; x++) {
537                                 dest[x] = palette16txt[src_text[x]];
538                         }
539                 }
540         } else {
541                 // 4096 colors
542                 for(int y = 0; y < vs && y < 400; y++) {
543                         scrntype_t *dest = emu->get_screen_buffer(y);
544                         uint8_t *src_text = &text[640 * y];
545                         for(int x = 0; x < 640; x++) {
546                                 dest[x] = palette4096txt[src_text[x]];
547                         }
548                 }
549                 for(int y = vs; y < ve && y < 400; y++) {
550                         scrntype_t *dest = emu->get_screen_buffer(y);
551                         uint16_t *src_cg = &cg[640 * y];
552                         uint8_t *src_text = &text[640 * y];
553                         for(int x = 0; x < hs && x < 640; x++) {
554                                 dest[x] = palette4096txt[src_text[x]];
555                         }
556                         for(int x = hs; x < he && x < 640; x++) {
557                                 dest[x] = palette4096pri[src_cg[x]][src_text[x]];
558                         }
559                         for(int x = he; x < 640; x++) {
560                                 dest[x] = palette4096txt[src_text[x]];
561                         }
562                 }
563                 for(int y = ve; y < 400; y++) {
564                         scrntype_t *dest = emu->get_screen_buffer(y);
565                         uint8_t *src_text = &text[640 * y];
566                         for(int x = 0; x < 640; x++) {
567                                 dest[x] = palette4096txt[src_text[x]];
568                         }
569                 }
570         }
571         emu->screen_skip_line(false);
572 }
573
574 // ----------------------------------------------------------------------------
575 // draw text screen
576 // ----------------------------------------------------------------------------
577
578 void CRTC::draw_text()
579 {
580         // extract text optimize matrix
581         if(trans_init) {
582                 trans_color = (textreg[0] & 2) ? 8 : 0;
583                 for(int pat = 0; pat < 256; pat++) {
584                         for(int col = 0; col < 8; col++) {
585                                 int fore_color = col ? col : 8;
586                                 text_matrix[pat][col][0] = text_matrixw[pat][col][ 0] = text_matrixw[pat][col][ 1] = (pat & 0x80) ? fore_color : trans_color;
587                                 text_matrix[pat][col][1] = text_matrixw[pat][col][ 2] = text_matrixw[pat][col][ 3] = (pat & 0x40) ? fore_color : trans_color;
588                                 text_matrix[pat][col][2] = text_matrixw[pat][col][ 4] = text_matrixw[pat][col][ 5] = (pat & 0x20) ? fore_color : trans_color;
589                                 text_matrix[pat][col][3] = text_matrixw[pat][col][ 6] = text_matrixw[pat][col][ 7] = (pat & 0x10) ? fore_color : trans_color;
590                                 text_matrix[pat][col][4] = text_matrixw[pat][col][ 8] = text_matrixw[pat][col][ 9] = (pat & 0x08) ? fore_color : trans_color;
591                                 text_matrix[pat][col][5] = text_matrixw[pat][col][10] = text_matrixw[pat][col][11] = (pat & 0x04) ? fore_color : trans_color;
592                                 text_matrix[pat][col][6] = text_matrixw[pat][col][12] = text_matrixw[pat][col][13] = (pat & 0x02) ? fore_color : trans_color;
593                                 text_matrix[pat][col][7] = text_matrixw[pat][col][14] = text_matrixw[pat][col][15] = (pat & 0x01) ? fore_color : trans_color;
594                         }
595                 }
596                 trans_init = false;
597         }
598         
599         // draw text
600         if(column_size) {
601                 draw_80column_screen();
602         } else {
603                 draw_40column_screen();
604         }
605         
606         // display period
607         int SL = (textreg[3] - 17) << 1, SC;
608         int EL = (textreg[5] - 17) << 1, EC;
609         if(column_size) {
610                 // 80 colums
611                 SC = (textreg[7] & 0x7f) - 9;
612                 EC = (textreg[8] & 0x7f) - 9;
613         } else {
614                 // 40 column
615                 SC = (textreg[7] & 0x7f) - 8;
616                 EC = (textreg[8] & 0x7f) - 8;
617         }
618         SL = (SL < 0) ? 0 : (SL > 400) ? 400 : SL;
619         EL = (EL < 0) ? 0 : (EL > 400) ? 400 : EL;
620         SC = (SC < 0) ? 0 : (SC > 80) ? 80 : SC;
621         EC = (EC < 0) ? 0 : (EC > 80) ? 80 : EC;
622         
623         if(EL >= SL) {
624                 for(int y = 0; y < SL; y++) {
625                         memset(text + 640 * y, trans_color, 640);
626                 }
627                 for(int y = EL; y < 400; y++) {
628                         memset(text + 640 * y, trans_color, 640);
629                 }
630         } else {
631                 for(int y = EL; y < SL; y++) {
632                         memset(text + 640 * y, trans_color, 640);
633                 }
634         }
635         if(EC >= SC) {
636                 for(int y = 0; y < 400; y++) {
637                         memset(text + 640 * y, trans_color, SC << 3);
638                         memset(text + 640 * y + (EC << 3), trans_color, (80 - EC) << 3);
639                 }
640         } else {
641                 for(int y = 0; y < 400; y++) {
642                         memset(text + 640 * y + (EC << 3), trans_color, (SC - EC) << 3);
643                 }
644         }
645 }
646
647 void CRTC::draw_80column_screen()
648 {
649         uint16_t src = (textreg[1] << 2) | ((textreg[2] & 7) << 10);
650         uint8_t line = (textreg[0] & 0x10) ? 2 : 0;
651         uint8_t height = (textreg[0] & 0x10) ? 20 : 16;
652         uint8_t vd = (textreg[9] & 0x0f) << 1;
653         
654         // 80x20(25)
655         for(int y = line; y < 416; y += height) {
656                 int dest = (y - vd) * 640;
657                 for(int x = 0; x < 80; x++) {
658                         draw_80column_font(src & 0x1fff, dest, y - vd);
659                         src += 4;
660                         dest += 8;
661                 }
662         }
663 }
664
665 void CRTC::draw_40column_screen()
666 {
667         uint16_t src1 = (textreg[1] << 2) | ((textreg[2] & 7) << 10);
668         uint16_t src2 = src1 + 0x1000;
669         uint8_t line = (textreg[0] & 0x10) ? 2 : 0;
670         uint8_t height = (textreg[0] & 0x10) ? 20 : 16;
671         uint8_t vd = (textreg[9] & 0x0f) << 1;
672         
673         switch(textreg[0] & 0x0c) {
674         case 0x00:
675                 // 40x20(25), 64colors
676                 for(int y = line; y < 416; y += height) {
677                         int dest1 = (y - vd) * 640;
678                         int dest2 = (y - vd) * 640 + 640 * 480;
679                         for(int x = 0; x < 40; x++) {
680                                 draw_40column_font(src1 & 0x1fff, dest1, y - vd);
681                                 draw_40column_font(src2 & 0x1fff, dest2, y - vd);
682                                 src1 += 4;
683                                 src2 += 4;
684                                 dest1 += 16;
685                                 dest2 += 16;
686                         }
687                 }
688                 for(int y = 0; y < 400; y++) {
689                         uint32_t src1 = 640 * y;
690                         uint32_t src2 = 640 * y + 640 * 480;
691                         uint32_t dest = 640 * y;
692                         uint8_t col;
693                         for(int x = 0; x < 640; x++) {
694                                 //if((text[src1] & 8) | (text[src2] & 8))
695                                 if((text[src1] & 8) && (text[src2] & 8)) {
696                                         // non transparent black
697                                         col = 8;
698                                 } else {
699                                         col = (((text[src1] & 7) << 3) | (text[src2] & 7)) + 16;
700                                 }
701                                 text[dest++] = col;
702                                 src1++;
703                                 src2++;
704                         }
705                 }
706                 break;
707         case 0x04:
708                 // 40x20(25), No.1 Screen
709                 for(int y = line; y < 416; y += height) {
710                         int dest = (y - vd) * 640;
711                         for(int x = 0; x < 40; x++) {
712                                 draw_40column_font(src1 & 0x1fff, dest, y - vd);
713                                 src1 += 4;
714                                 dest += 16;
715                         }
716                 }
717                 break;
718         case 0x08:
719                 // 40x20(25), No.2 Screen
720                 for(int y = line; y < 416; y += height) {
721                         int dest = (y - vd) * 640;
722                         for(int x = 0; x < 40; x++) {
723                                 draw_40column_font(src2 & 0x1fff, dest, y - vd);
724                                 src2 += 4;
725                                 dest += 16;
726                         }
727                 }
728                 break;
729         case 0x0c:
730                 // 40x20(25), No.1 + No.2 Screens (No.1 > No.2)
731                 for(int y = line; y < 416; y += height) {
732                         int dest = (y - vd) * 640;
733                         for(int x = 0; x < 40; x++) {
734                                 draw_40column_font(src1 & 0x1fff, dest, y - vd);
735                                 src1 += 4;
736                                 dest += 16;
737                         }
738                 }
739                 for(int y = line; y < 416; y += height) {
740                         int dest = (y - vd) * 640 + 640 * 480;
741                         for(int x = 0; x < 40; x++) {
742                                 draw_40column_font(src2 & 0x1fff, dest, y - vd);
743                                 src2 += 4;
744                                 dest += 16;
745                         }
746                 }
747                 for(int y = line; y < 400; y++) {
748                         int dest = (y - vd) * 640;
749                         uint8_t* tsrc1 = &text[dest];
750                         uint8_t* tsrc2 = &text[dest + 640 * 480];
751                         uint8_t* tdest = &text[dest];
752                         for(int x = 0; x < 640; x++) {
753                                 tdest[x] = (tsrc1[x] & 7) ? tsrc1[x] : (tsrc2[x] & 7) ? tsrc2[x] : ((tsrc1[x] & 8) | (tsrc2[x] & 8));
754                         }
755                 }
756                 break;
757         }
758 }
759
760 void CRTC::draw_80column_font(uint16_t src, int dest, int y)
761 {
762         // draw char (80 column)
763         uint8_t* pattern1;
764         uint8_t* pattern2;
765         uint8_t* pattern3;
766         
767         uint32_t code;
768         uint8_t sel, col, pat1, pat2, pat3;
769         uint8_t t1 = tvram[src], t2 = tvram[src + 1], attr = tvram[src + 2];
770         
771         // select char type
772         sel = (t2 & 0xc0) | (attr & 0x38);
773         switch(sel) {
774         case 0x00: case 0x40:
775                 pattern1 = pcg0;
776                 break;
777         case 0x80:
778                 pattern1 = kanji1;
779                 break;
780         case 0xc0:
781                 pattern1 = kanji2;
782                 break;
783         case 0x10: case 0x50: case 0x90: case 0xd0:
784                 pattern1 = pcg1;
785                 break;
786         case 0x20: case 0x60: case 0xa0: case 0xe0:
787                 pattern1 = pcg2;
788                 break;
789         case 0x30: case 0x70: case 0xb0: case 0xf0:
790                 pattern1 = pcg3;
791                 break;
792         default:
793                 pattern1 = pcg1;
794                 pattern2 = pcg2;
795                 pattern3 = pcg3;
796                 break;
797         }
798         if(sel & 8) {
799                 // PCG1 + PCG2 + PCG3 8colors
800                 
801                 // generate addr
802                 code = font_size ? t1 << 3 : (t1 & 0xfe) << 3;
803                 
804                 // draw
805                 if(font_size) {
806                         for(int i = 0; i < 8; i++) {
807                                 // check end line of screen
808                                 if(!(y++ < 480)) {
809                                         break;
810                                 }
811                                 if((attr & 0x80) && blink) {
812                                         // blink
813                                         uint8_t val = (attr & 0x40) ? 7 : trans_color;
814                                         if(dest >= 0) {
815                                                 memset(text + dest, val, 8);
816                                         }
817                                         dest += 640;
818                                         // check end line of screen
819                                         if(!(y++ < 480)) {
820                                                 break;
821                                         }
822                                         if(dest >= 0) {
823                                                 memset(text + dest, val, 8);
824                                         }
825                                         dest += 640;
826                                 } else {
827                                         if(attr & 0x40) {
828                                                 pat1 = ~pattern1[(code + i) << 1];
829                                                 pat2 = ~pattern2[(code + i) << 1];
830                                                 pat3 = ~pattern3[(code + i) << 1];
831                                         } else {
832                                                 pat1 = pattern1[(code + i) << 1];
833                                                 pat2 = pattern2[(code + i) << 1];
834                                                 pat3 = pattern3[(code + i) << 1];
835                                         }
836                                         if(dest >= 0) {
837                                                 uint8_t* tdest = &text[dest];
838                                                 col = ((pat1 & 0x80) >> 7) | ((pat2 & 0x80) >> 6) | ((pat3 & 0x80) >> 5); tdest[0] = col ? col : trans_color;
839                                                 col = ((pat1 & 0x40) >> 6) | ((pat2 & 0x40) >> 5) | ((pat3 & 0x40) >> 4); tdest[1] = col ? col : trans_color;
840                                                 col = ((pat1 & 0x20) >> 5) | ((pat2 & 0x20) >> 4) | ((pat3 & 0x20) >> 3); tdest[2] = col ? col : trans_color;
841                                                 col = ((pat1 & 0x10) >> 4) | ((pat2 & 0x10) >> 3) | ((pat3 & 0x10) >> 2); tdest[3] = col ? col : trans_color;
842                                                 col = ((pat1 & 0x08) >> 3) | ((pat2 & 0x08) >> 2) | ((pat3 & 0x08) >> 1); tdest[4] = col ? col : trans_color;
843                                                 col = ((pat1 & 0x04) >> 2) | ((pat2 & 0x04) >> 1) | ((pat3 & 0x04)     ); tdest[5] = col ? col : trans_color;
844                                                 col = ((pat1 & 0x02) >> 1) | ((pat2 & 0x02)     ) | ((pat3 & 0x02) << 1); tdest[6] = col ? col : trans_color;
845                                                 col = ((pat1 & 0x01)     ) | ((pat2 & 0x01) << 1) | ((pat3 & 0x01) << 2); tdest[7] = col ? col : trans_color;
846                                         }
847                                         dest += 640;
848                                         // check end line of screen
849                                         if(!(y++ < 480)) {
850                                                 break;
851                                         }
852                                         if(dest >= 0) {
853                                                 if(dest >= 640) {
854                                                         memcpy(text + dest, text + dest - 640, 8);
855                                                 } else {
856                                                         uint8_t* tdest = &text[dest];
857                                                         col = ((pat1 & 0x80) >> 7) | ((pat2 & 0x80) >> 6) | ((pat3 & 0x80) >> 5); tdest[0] = col ? col : trans_color;
858                                                         col = ((pat1 & 0x40) >> 6) | ((pat2 & 0x40) >> 5) | ((pat3 & 0x40) >> 4); tdest[1] = col ? col : trans_color;
859                                                         col = ((pat1 & 0x20) >> 5) | ((pat2 & 0x20) >> 4) | ((pat3 & 0x20) >> 3); tdest[2] = col ? col : trans_color;
860                                                         col = ((pat1 & 0x10) >> 4) | ((pat2 & 0x10) >> 3) | ((pat3 & 0x10) >> 2); tdest[3] = col ? col : trans_color;
861                                                         col = ((pat1 & 0x08) >> 3) | ((pat2 & 0x08) >> 2) | ((pat3 & 0x08) >> 1); tdest[4] = col ? col : trans_color;
862                                                         col = ((pat1 & 0x04) >> 2) | ((pat2 & 0x04) >> 1) | ((pat3 & 0x04)     ); tdest[5] = col ? col : trans_color;
863                                                         col = ((pat1 & 0x02) >> 1) | ((pat2 & 0x02)     ) | ((pat3 & 0x02) << 1); tdest[6] = col ? col : trans_color;
864                                                         col = ((pat1 & 0x01)     ) | ((pat2 & 0x01) << 1) | ((pat3 & 0x01) << 2); tdest[7] = col ? col : trans_color;
865                                                 }
866                                         }
867                                         dest += 640;
868                                 }
869                         }
870                 } else {
871                         for(int i = 0; i < 16; i++) {
872                                 // check end line of screen
873                                 if(!(y++ < 480)) {
874                                         break;
875                                 }
876                                 if(dest >= 0) {
877                                         if((attr & 0x80) && blink) {
878                                                 if(attr & 0x40) {
879                                                         memset(text + dest, 7, 8);
880                                                 } else {
881                                                         memset(text + dest, trans_color, 8);
882                                                 }
883                                         } else {
884                                                 if(attr & 0x40) {
885                                                         pat1 = ~pattern1[(code + i) << 1];
886                                                         pat2 = ~pattern2[(code + i) << 1];
887                                                         pat3 = ~pattern3[(code + i) << 1];
888                                                 } else {
889                                                         pat1 = pattern1[(code + i) << 1];
890                                                         pat2 = pattern2[(code + i) << 1];
891                                                         pat3 = pattern3[(code + i) << 1];
892                                                 }
893                                                 uint8_t* tdest = &text[dest];
894                                                 col = ((pat1 & 0x80) >> 7) | ((pat2 & 0x80) >> 6) | ((pat3 & 0x80) >> 5); tdest[0] = col ? col : trans_color;
895                                                 col = ((pat1 & 0x40) >> 6) | ((pat2 & 0x40) >> 5) | ((pat3 & 0x40) >> 4); tdest[1] = col ? col : trans_color;
896                                                 col = ((pat1 & 0x20) >> 5) | ((pat2 & 0x20) >> 4) | ((pat3 & 0x20) >> 3); tdest[2] = col ? col : trans_color;
897                                                 col = ((pat1 & 0x10) >> 4) | ((pat2 & 0x10) >> 3) | ((pat3 & 0x10) >> 2); tdest[3] = col ? col : trans_color;
898                                                 col = ((pat1 & 0x08) >> 3) | ((pat2 & 0x08) >> 2) | ((pat3 & 0x08) >> 1); tdest[4] = col ? col : trans_color;
899                                                 col = ((pat1 & 0x04) >> 2) | ((pat2 & 0x04) >> 1) | ((pat3 & 0x04)     ); tdest[5] = col ? col : trans_color;
900                                                 col = ((pat1 & 0x02) >> 1) | ((pat2 & 0x02)     ) | ((pat3 & 0x02) << 1); tdest[6] = col ? col : trans_color;
901                                                 col = ((pat1 & 0x01)     ) | ((pat2 & 0x01) << 1) | ((pat3 & 0x01) << 2); tdest[7] = col ? col : trans_color;
902                                         }
903                                 }
904                                 dest += 640;
905                         }
906                 }
907         } else {
908                 // monochrome
909                 
910                 // generate addr
911                 if(font_size) {
912                         if(sel == 0x80 || sel == 0xc0) {
913                                 code = ((t2 & 0x3f) << 11) | (t1 << 3);
914                         } else {
915                                 code = t1 << 3;
916                         }
917                 } else {
918                         if(sel == 0x80 || sel == 0xc0) {
919                                 code = ((t2 & 0x3f) << 11) | ((t1 & 0xfe) << 3);
920                         } else {
921                                 code = (t1 & 0xfe) << 3;
922                         }
923                 }
924                 // color
925                 col = attr & 7;
926                 // draw
927                 if(font_size) {
928                         uint32_t dest1 = dest;
929                         uint32_t dest2 = (dest >= 640 * 399) ? dest - 640 * 399 : dest + 640;
930                         for(int i = 0; i < 8; i++) {
931                                 // check end line of screen
932                                 if(!(y++ < 480)) {
933                                         break;
934                                 }
935                                 // reverse, blink
936                                 if(attr & 0x40) {
937                                         pat1 = ((attr & 0x80) && blink) ? 0xff : ~pattern1[(code + i) << 1];
938                                 } else {
939                                         pat1 = ((attr & 0x80) && blink) ? 0x00 : pattern1[(code + i) << 1];
940                                 }
941                                 if(dest >= 0) {
942                                         memcpy(&text[dest], text_matrix[pat1][col], 8);
943                                 }
944                                 dest += 640;
945                                 // check end line of screen
946                                 if(!(y++ < 480)) {
947                                         break;
948                                 }
949                                 if(dest >= 0) {
950                                         memcpy(&text[dest], text_matrix[pat1][col], 8);
951                                 }
952                                 dest += 640;
953                         }
954                 } else {
955                         for(int i = 0; i < 16; i++) {
956                                 // check end line of screen
957                                 if(!(y++ < 480)) {
958                                         break;
959                                 }
960                                 if(dest >= 0) {
961                                         // reverse, blink
962                                         if(attr & 0x40) {
963                                                 pat1 = ((attr & 0x80) && blink) ? 0xff : ~pattern1[(code + i) << 1];
964                                         } else {
965                                                 pat1 = ((attr & 0x80) && blink) ? 0x00 : pattern1[(code + i) << 1];
966                                         }
967                                         memcpy(&text[dest], text_matrix[pat1][col], 8);
968                                 }
969                                 dest += 640;
970                         }
971                 }
972         }
973 }
974
975 void CRTC::draw_40column_font(uint16_t src, int dest, int y)
976 {
977         // draw char (40 column)
978         uint8_t* pattern1;
979         uint8_t* pattern2;
980         uint8_t* pattern3;
981         
982         uint32_t code;
983         uint8_t sel, col, pat1, pat2, pat3;
984         uint8_t t1 = tvram[src], t2 = tvram[src + 1], attr = tvram[src + 2];
985         
986         // select char type
987         sel = (t2 & 0xc0) | (attr & 0x38);
988         switch(sel) {
989         case 0x00: case 0x40:
990                 pattern1 = pcg0;
991                 break;
992         case 0x80:
993                 pattern1 = kanji1;
994                 break;
995         case 0xc0:
996                 pattern1 = kanji2;
997                 break;
998         case 0x10: case 0x50: case 0x90: case 0xd0:
999                 pattern1 = pcg1;
1000                 break;
1001         case 0x20: case 0x60: case 0xa0: case 0xe0:
1002                 pattern1 = pcg2;
1003                 break;
1004         case 0x30: case 0x70: case 0xb0: case 0xf0:
1005                 pattern1 = pcg3;
1006                 break;
1007         default:
1008                 pattern1 = pcg1;
1009                 pattern2 = pcg2;
1010                 pattern3 = pcg3;
1011                 break;
1012         }
1013         if(sel & 8) {
1014                 // PCG1 + PCG2 + PCG3 8colors
1015                 
1016                 // generate addr
1017                 code = font_size ? t1 << 3 : (t1 & 0xfe) << 3;
1018                 // draw
1019                 if(font_size) {
1020                         for(int i = 0; i < 8; i++) {
1021                                 // check end line of screen
1022                                 if(!(y++ < 480)) {
1023                                         break;
1024                                 }
1025                                 if((attr & 0x80) && blink) {
1026                                         // blink
1027                                         uint8_t val = (attr & 0x40) ? 7 : trans_color;
1028                                         if(dest >= 0) {
1029                                                 memset(text + dest, val, 16);
1030                                         }
1031                                         dest += 640;
1032                                         // check end line of screen
1033                                         if(!(y++ < 480)) {
1034                                                 break;
1035                                         }
1036                                         if(dest >= 0) {
1037                                                 memset(text + dest, val, 16);
1038                                         }
1039                                         dest += 640;
1040                                 } else {
1041                                         if(attr & 0x40) {
1042                                                 pat1 = ~pattern1[(code + i) << 1];
1043                                                 pat2 = ~pattern2[(code + i) << 1];
1044                                                 pat3 = ~pattern3[(code + i) << 1];
1045                                         } else {
1046                                                 pat1 = pattern1[(code + i) << 1];
1047                                                 pat2 = pattern2[(code + i) << 1];
1048                                                 pat3 = pattern3[(code + i) << 1];
1049                                         }
1050                                         if(dest >= 0) {
1051                                                 uint8_t* tdest = &text[dest];
1052                                                 col = ((pat1 & 0x80) >> 7) | ((pat2 & 0x80) >> 6) | ((pat3 & 0x80) >> 5); tdest[ 0] = tdest[ 1] = col ? col : trans_color;
1053                                                 col = ((pat1 & 0x40) >> 6) | ((pat2 & 0x40) >> 5) | ((pat3 & 0x40) >> 4); tdest[ 2] = tdest[ 3] = col ? col : trans_color;
1054                                                 col = ((pat1 & 0x20) >> 5) | ((pat2 & 0x20) >> 4) | ((pat3 & 0x20) >> 3); tdest[ 4] = tdest[ 5] = col ? col : trans_color;
1055                                                 col = ((pat1 & 0x10) >> 4) | ((pat2 & 0x10) >> 3) | ((pat3 & 0x10) >> 2); tdest[ 6] = tdest[ 7] = col ? col : trans_color;
1056                                                 col = ((pat1 & 0x08) >> 3) | ((pat2 & 0x08) >> 2) | ((pat3 & 0x08) >> 1); tdest[ 8] = tdest[ 9] = col ? col : trans_color;
1057                                                 col = ((pat1 & 0x04) >> 2) | ((pat2 & 0x04) >> 1) | ((pat3 & 0x04)     ); tdest[10] = tdest[11] = col ? col : trans_color;
1058                                                 col = ((pat1 & 0x02) >> 1) | ((pat2 & 0x02)     ) | ((pat3 & 0x02) << 1); tdest[12] = tdest[13] = col ? col : trans_color;
1059                                                 col = ((pat1 & 0x01)     ) | ((pat2 & 0x01) << 1) | ((pat3 & 0x01) << 2); tdest[14] = tdest[15] = col ? col : trans_color;
1060                                         }
1061                                         dest += 640;
1062                                         // check end line of screen
1063                                         if(!(y++ < 480)) {
1064                                                 break;
1065                                         }
1066                                         if(dest >= 0) {
1067                                                 if(dest >= 640) {
1068                                                         memcpy(text + dest, text + dest - 640, 16);
1069                                                 } else {
1070                                                         uint8_t* tdest = &text[dest];
1071                                                         col = ((pat1 & 0x80) >> 7) | ((pat2 & 0x80) >> 6) | ((pat3 & 0x80) >> 5); tdest[ 0] = tdest[ 1] = col ? col : trans_color;
1072                                                         col = ((pat1 & 0x40) >> 6) | ((pat2 & 0x40) >> 5) | ((pat3 & 0x40) >> 4); tdest[ 2] = tdest[ 3] = col ? col : trans_color;
1073                                                         col = ((pat1 & 0x20) >> 5) | ((pat2 & 0x20) >> 4) | ((pat3 & 0x20) >> 3); tdest[ 4] = tdest[ 5] = col ? col : trans_color;
1074                                                         col = ((pat1 & 0x10) >> 4) | ((pat2 & 0x10) >> 3) | ((pat3 & 0x10) >> 2); tdest[ 6] = tdest[ 7] = col ? col : trans_color;
1075                                                         col = ((pat1 & 0x08) >> 3) | ((pat2 & 0x08) >> 2) | ((pat3 & 0x08) >> 1); tdest[ 8] = tdest[ 9] = col ? col : trans_color;
1076                                                         col = ((pat1 & 0x04) >> 2) | ((pat2 & 0x04) >> 1) | ((pat3 & 0x04)     ); tdest[10] = tdest[11] = col ? col : trans_color;
1077                                                         col = ((pat1 & 0x02) >> 1) | ((pat2 & 0x02)     ) | ((pat3 & 0x02) << 1); tdest[12] = tdest[13] = col ? col : trans_color;
1078                                                         col = ((pat1 & 0x01)     ) | ((pat2 & 0x01) << 1) | ((pat3 & 0x01) << 2); tdest[14] = tdest[15] = col ? col : trans_color;
1079                                                 }
1080                                         }
1081                                         dest += 640;
1082                                 }
1083                         }
1084                 } else {
1085                         for(int i = 0; i < 16; i++) {
1086                                 // check end line of screen
1087                                 if(!(y++ < 480)) {
1088                                         break;
1089                                 }
1090                                 if(dest >= 0) {
1091                                         if((attr & 0x80) && blink) {
1092                                                 if(attr & 0x40) {
1093                                                         memset(text + dest, 7, 16);
1094                                                 } else {
1095                                                         memset(text + dest, trans_color, 16);
1096                                                 }
1097                                         } else {
1098                                                 if(attr & 0x40) {
1099                                                         pat1 = ~pattern1[(code + i) << 1];
1100                                                         pat2 = ~pattern2[(code + i) << 1];
1101                                                         pat3 = ~pattern3[(code + i) << 1];
1102                                                 } else {
1103                                                         pat1 = pattern1[(code + i) << 1];
1104                                                         pat2 = pattern2[(code + i) << 1];
1105                                                         pat3 = pattern3[(code + i) << 1];
1106                                                 }
1107                                                 uint8_t* tdest = &text[dest];
1108                                                 col = ((pat1 & 0x80) >> 7) | ((pat2 & 0x80) >> 6) | ((pat3 & 0x80) >> 5); tdest[ 0] = tdest[ 1] = col ? col : trans_color;
1109                                                 col = ((pat1 & 0x40) >> 6) | ((pat2 & 0x40) >> 5) | ((pat3 & 0x40) >> 4); tdest[ 2] = tdest[ 3] = col ? col : trans_color;
1110                                                 col = ((pat1 & 0x20) >> 5) | ((pat2 & 0x20) >> 4) | ((pat3 & 0x20) >> 3); tdest[ 4] = tdest[ 5] = col ? col : trans_color;
1111                                                 col = ((pat1 & 0x10) >> 4) | ((pat2 & 0x10) >> 3) | ((pat3 & 0x10) >> 2); tdest[ 6] = tdest[ 7] = col ? col : trans_color;
1112                                                 col = ((pat1 & 0x08) >> 3) | ((pat2 & 0x08) >> 2) | ((pat3 & 0x08) >> 1); tdest[ 8] = tdest[ 9] = col ? col : trans_color;
1113                                                 col = ((pat1 & 0x04) >> 2) | ((pat2 & 0x04) >> 1) | ((pat3 & 0x04)     ); tdest[10] = tdest[11] = col ? col : trans_color;
1114                                                 col = ((pat1 & 0x02) >> 1) | ((pat2 & 0x02)     ) | ((pat3 & 0x02) << 1); tdest[12] = tdest[13] = col ? col : trans_color;
1115                                                 col = ((pat1 & 0x01)     ) | ((pat2 & 0x01) << 1) | ((pat3 & 0x01) << 2); tdest[14] = tdest[15] = col ? col : trans_color;
1116                                         }
1117                                 }
1118                                 dest += 640;
1119                         }
1120                 }
1121         } else {
1122                 // monochrome
1123                 
1124                 // generate addr
1125                 if(font_size) {
1126                         if(sel == 0x80 || sel == 0xc0) {
1127                                 code = ((t2 & 0x3f) << 11) | (t1 << 3);
1128                         } else {
1129                                 code = t1 << 3;
1130                         }
1131                 } else {
1132                         if(sel == 0x80 || sel == 0xc0) {
1133                                 code = ((t2 & 0x3f) << 11) | ((t1 & 0xfe) << 3);
1134                         } else {
1135                                 code = (t1 & 0xfe) << 3;
1136                         }
1137                 }
1138                 // color
1139                 col = attr & 7;
1140                 // draw
1141                 if(font_size) {
1142                         for(int i = 0; i < 8; i++) {
1143                                 // check end line of screen
1144                                 if(!(y++ < 480)) {
1145                                         break;
1146                                 }
1147                                 // reverse, blink
1148                                 if(attr & 0x40) {
1149                                         pat1 = ((attr & 0x80) && blink) ? 0xff : ~pattern1[(code + i) << 1];
1150                                 } else {
1151                                         pat1 = ((attr & 0x80) && blink) ? 0x00 : pattern1[(code + i) << 1];
1152                                 }
1153                                 if(dest >= 0) {
1154                                         memcpy(&text[dest], text_matrixw[pat1][col], 16);
1155                                 }
1156                                 dest += 640;
1157                                 // check end line of screen
1158                                 if(!(y++ < 480)) {
1159                                         break;
1160                                 }
1161                                 if(dest >= 0) {
1162                                         memcpy(&text[dest], text_matrixw[pat1][col], 16);
1163                                 }
1164                                 dest += 640;
1165                         }
1166                 } else {
1167                         for(int i = 0; i < 16; i++) {
1168                                 // check end line of screen
1169                                 if(!(y++ < 480)) {
1170                                         break;
1171                                 }
1172                                 if(dest >= 0) {
1173                                         // reverse, blink
1174                                         if(attr & 0x40) {
1175                                                 pat1 = ((attr & 0x80) && blink) ? 0xff : ~pattern1[(code + i) << 1];
1176                                         } else {
1177                                                 pat1 = ((attr & 0x80) && blink) ? 0x00 : pattern1[(code + i) << 1];
1178                                         }
1179                                         memcpy(&text[dest], text_matrixw[pat1][col], 16);
1180                                 }
1181                                 dest += 640;
1182                         }
1183                 }
1184         }
1185 }
1186
1187 // ----------------------------------------------------------------------------
1188 // drive cg screen
1189 // ----------------------------------------------------------------------------
1190
1191 void CRTC::draw_cg()
1192 {
1193         // draw cg screen
1194         int is_400l, is_16col, ymax, ofs;
1195         uint32_t dest = 0;
1196         
1197         switch(cgreg[6]) {
1198         case 0x13: is_400l = 1; is_16col = 1; ymax = 400; ofs = 1; break; // 640x400x16
1199         case 0x17: is_400l = 0; is_16col = 1; ymax = 200; ofs = 1; break; // 640x200x16
1200         case 0x1b: is_400l = 1; is_16col = 0; ymax = 400; ofs = 4; break; // 640x400x65536
1201         case 0x1f: is_400l = 0; is_16col = 0; ymax = 200; ofs = 4; break; // 640x200x65536
1202         default:
1203                 return;
1204         }
1205         
1206         if(map_init) {
1207                 // update vram addr map for the hardware scroll
1208                 uint8_t HDSC = cgreg[0x07] & 7;
1209                 uint32_t SAD0 = (cgreg[0x08] << 1) | (cgreg[0x09] << 9);
1210                 uint32_t SAD1 = (cgreg[0x0a] << 1) | (cgreg[0x0b] << 9);
1211                 uint16_t SLN1 = cgreg[0x0c] | ((cgreg[0x0d] & 1) << 8);
1212                 
1213                 for(int y = 0; y < SLN1 && y < ymax; y++) {
1214                         for(int x = 0; x < 80; x++) {
1215                                 map_hdsc[y][x] = HDSC;
1216                                 map_addr[y][x] = SAD0 & 0x1ffff;
1217                                 SAD0 += ofs;
1218                         }
1219                 }
1220                 for(int y = SLN1; y < ymax; y++) {
1221                         for(int x = 0; x < 80; x++) {
1222                                 map_hdsc[y][x] = 0;
1223                                 map_addr[y][x] = SAD1 & 0x1ffff;
1224                                 SAD1 += ofs;
1225                         }
1226                 }
1227                 map_init = false;
1228         }
1229         if(is_16col) {
1230                 // 16/4096 color mode
1231                 for(int y = 0; y < ymax; y++) {
1232                         for(int x = 0; x < 80; x++) {
1233                                 uint32_t src = map_addr[y][x];
1234                                 uint32_t dest2 = dest + map_hdsc[y][x];
1235                                 dest += 8;
1236                                 
1237                                 uint8_t B = (cgreg[0x10] & 1) ? vram_b[src] : 0;
1238                                 uint8_t R = (cgreg[0x10] & 2) ? vram_r[src] : 0;
1239                                 uint8_t G = (cgreg[0x10] & 4) ? vram_g[src] : 0;
1240                                 uint8_t I = (cgreg[0x10] & 8) ? vram_i[src] : 0;
1241                                 
1242                                 cg[dest2    ] = cg_matrix0[B][R][0] | cg_matrix1[G][I][0];
1243                                 cg[dest2 + 1] = cg_matrix0[B][R][1] | cg_matrix1[G][I][1];
1244                                 cg[dest2 + 2] = cg_matrix0[B][R][2] | cg_matrix1[G][I][2];
1245                                 cg[dest2 + 3] = cg_matrix0[B][R][3] | cg_matrix1[G][I][3];
1246                                 cg[dest2 + 4] = cg_matrix0[B][R][4] | cg_matrix1[G][I][4];
1247                                 cg[dest2 + 5] = cg_matrix0[B][R][5] | cg_matrix1[G][I][5];
1248                                 cg[dest2 + 6] = cg_matrix0[B][R][6] | cg_matrix1[G][I][6];
1249                                 cg[dest2 + 7] = cg_matrix0[B][R][7] | cg_matrix1[G][I][7];
1250                         }
1251                         if(!is_400l) {
1252                                 dest += 640;
1253                         }
1254                 }
1255         } else {
1256                 // 65536 color mode
1257                 uint8_t B0 = 0, R0 = 0, G0 = 0, I0 = 0;
1258                 uint8_t B1 = 0, R1 = 0, G1 = 0, I1 = 0;
1259                 uint8_t B2 = 0, R2 = 0, G2 = 0, I2 = 0;
1260                 uint8_t B3 = 0, R3 = 0, G3 = 0, I3 = 0;
1261                 uint8_t plane_mask = cgreg[0x10] & cg_mask;
1262                 
1263                 for(int y = 0; y < ymax; y++) {
1264                         for(int x = 0; x < 80; x++) {
1265                                 uint32_t src0 = map_addr[y][x];
1266                                 uint32_t src1 = (src0 + 1) & 0x1ffff;
1267                                 uint32_t src2 = (src0 + 2) & 0x1ffff;
1268                                 uint32_t src3 = (src0 + 3) & 0x1ffff;
1269                                 uint32_t dest2 = dest + map_hdsc[y][x];
1270                                 dest += 8;
1271                                 
1272                                 if(plane_mask & 1) {
1273                                         B0 = vram_b[src0];
1274                                         B1 = vram_b[src1];
1275                                         B2 = vram_b[src2];
1276                                         B3 = vram_b[src3];
1277                                 }
1278                                 if(plane_mask & 2) {
1279                                         R0 = vram_r[src0];
1280                                         R1 = vram_r[src1];
1281                                         R2 = vram_r[src2];
1282                                         R3 = vram_r[src3];
1283                                 }
1284                                 if(plane_mask & 4) {
1285                                         G0 = vram_g[src0];
1286                                         G1 = vram_g[src1];
1287                                         G2 = vram_g[src2];
1288                                         G3 = vram_g[src3];
1289                                 }
1290                                 if(plane_mask & 8) {
1291                                         I0 = vram_i[src0];
1292                                         I1 = vram_i[src1];
1293                                         I2 = vram_i[src2];
1294                                         I3 = vram_i[src3];
1295                                 }
1296                                 cg[dest2    ] = ((B0 & 0xf0) <<  8) | ((R0 & 0xf0) << 4) | ((G0 & 0xf0)     ) | ((I0 & 0xf0) >> 4);
1297                                 cg[dest2 + 1] = ((B0 & 0x0f) << 12) | ((R0 & 0x0f) << 8) | ((G0 & 0x0f) << 4) | ((I0 & 0x0f)     );
1298                                 cg[dest2 + 2] = ((B1 & 0xf0) <<  8) | ((R1 & 0xf0) << 4) | ((G1 & 0xf0)     ) | ((I1 & 0xf0) >> 4);
1299                                 cg[dest2 + 3] = ((B1 & 0x0f) << 12) | ((R1 & 0x0f) << 8) | ((G1 & 0x0f) << 4) | ((I1 & 0x0f)     );
1300                                 cg[dest2 + 4] = ((B2 & 0xf0) <<  8) | ((R2 & 0xf0) << 4) | ((G2 & 0xf0)     ) | ((I2 & 0xf0) >> 4);
1301                                 cg[dest2 + 5] = ((B2 & 0x0f) << 12) | ((R2 & 0x0f) << 8) | ((G2 & 0x0f) << 4) | ((I2 & 0x0f)     );
1302                                 cg[dest2 + 6] = ((B3 & 0xf0) <<  8) | ((R3 & 0xf0) << 4) | ((G3 & 0xf0)     ) | ((I3 & 0xf0) >> 4);
1303                                 cg[dest2 + 7] = ((B3 & 0x0f) << 12) | ((R3 & 0x0f) << 8) | ((G3 & 0x0f) << 4) | ((I3 & 0x0f)     );
1304                         }
1305                         if(!is_400l) {
1306                                 dest += 640;
1307                         }
1308                 }
1309         }
1310         // fill scan line
1311         if(!is_400l) {
1312                 for(int y = 0; y < 400; y += 2) {
1313                         memcpy(cg + (y + 1) * 640, cg + y * 640, 1280);
1314                 }
1315         }
1316 }
1317
1318 #define STATE_VERSION   1
1319
1320 bool CRTC::process_state(FILEIO* state_fio, bool loading)
1321 {
1322         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
1323                 return false;
1324         }
1325         if(!state_fio->StateCheckInt32(this_device_id)) {
1326                 return false;
1327         }
1328         state_fio->StateUint8(textreg_num);
1329         state_fio->StateBuffer(textreg, sizeof(textreg), 1);
1330         state_fio->StateBuffer(rmwreg_num, sizeof(rmwreg_num), 1);
1331         state_fio->StateBuffer(rmwreg, sizeof(rmwreg), 1);
1332         state_fio->StateUint8(cgreg_num);
1333         state_fio->StateBuffer(cgreg, sizeof(cgreg), 1);
1334         state_fio->StateUint8(scrn_size);
1335         state_fio->StateUint8(cg_mask);
1336         state_fio->StateBool(font_size);
1337         state_fio->StateBool(column_size);
1338         state_fio->StateBuffer(latch, sizeof(latch), 1);
1339         state_fio->StateUint16(GDEVS);
1340         state_fio->StateUint16(GDEVE);
1341         state_fio->StateUint8(GDEHS);
1342         state_fio->StateUint8(GDEHE);
1343         state_fio->StateInt32(GDEHSC);
1344         state_fio->StateInt32(GDEHEC);
1345         state_fio->StateBool(blank);
1346         state_fio->StateBool(hblank);
1347         state_fio->StateBool(vblank);
1348         state_fio->StateBool(blink);
1349         state_fio->StateUint8(clear_flag);
1350         state_fio->StateBuffer(palette_reg, sizeof(palette_reg), 1);
1351         state_fio->StateBool(pal_select);
1352         state_fio->StateBool(screen_mask);
1353         state_fio->StateBuffer(priority16, sizeof(priority16), 1);
1354         //state_fio->StateBuffer(palette16, sizeof(palette16), 1);
1355         for(int i = 0; i < (sizeof(palette16) / sizeof(scrntype_t)); i++) {
1356                 if(loading) {
1357                         uint8_t r, g, b;
1358                         r = state_fio->FgetUint8();
1359                         g = state_fio->FgetUint8();
1360                         b = state_fio->FgetUint8();
1361                         palette16[i] = RGB_COLOR(r, g, b);
1362                 } else {
1363                         uint8_t r, g, b;
1364                         r = R_OF_COLOR(palette16[i]);
1365                         g = G_OF_COLOR(palette16[i]);
1366                         b = B_OF_COLOR(palette16[i]);
1367                         state_fio->FputUint8(r);
1368                         state_fio->FputUint8(g);
1369                         state_fio->FputUint8(b);
1370                 }
1371         }
1372         //state_fio->StateBuffer(palette4096, sizeof(palette4096), 1);
1373         for(int i = 0; i < (sizeof(palette4096) / sizeof(scrntype_t)); i++) {
1374                 if(loading) {
1375                         uint8_t r, g, b;
1376                         r = state_fio->FgetUint8();
1377                         g = state_fio->FgetUint8();
1378                         b = state_fio->FgetUint8();
1379                         palette4096[i] = RGB_COLOR(r, g, b);
1380                 } else {
1381                         uint8_t r, g, b;
1382                         r = R_OF_COLOR(palette4096[i]);
1383                         g = G_OF_COLOR(palette4096[i]);
1384                         b = B_OF_COLOR(palette4096[i]);
1385                         state_fio->FputUint8(r);
1386                         state_fio->FputUint8(g);
1387                         state_fio->FputUint8(b);
1388                 }
1389         }
1390         state_fio->StateBuffer(palette4096r, sizeof(palette4096r), 1);
1391         state_fio->StateBuffer(palette4096g, sizeof(palette4096g), 1);
1392         state_fio->StateBuffer(palette4096b, sizeof(palette4096b), 1);
1393         //state_fio->StateBuffer(palette16txt, sizeof(palette16txt), 1);
1394         for(int i = 0; i < (sizeof(palette16txt) / sizeof(scrntype_t)); i++) {
1395                 if(loading) {
1396                         uint8_t r, g, b;
1397                         r = state_fio->FgetUint8();
1398                         g = state_fio->FgetUint8();
1399                         b = state_fio->FgetUint8();
1400                         palette16txt[i] = RGB_COLOR(r, g, b);
1401                 } else {
1402                         uint8_t r, g, b;
1403                         r = R_OF_COLOR(palette16txt[i]);
1404                         g = G_OF_COLOR(palette16txt[i]);
1405                         b = B_OF_COLOR(palette16txt[i]);
1406                         state_fio->FputUint8(r);
1407                         state_fio->FputUint8(g);
1408                         state_fio->FputUint8(b);
1409                 }
1410         }
1411         //state_fio->StateBuffer(palette4096txt, sizeof(palette4096txt), 1);
1412         for(int i = 0; i < (sizeof(palette4096txt) / sizeof(scrntype_t)); i++) {
1413                 if(loading) {
1414                         uint8_t r, g, b;
1415                         r = state_fio->FgetUint8();
1416                         g = state_fio->FgetUint8();
1417                         b = state_fio->FgetUint8();
1418                         palette4096txt[i] = RGB_COLOR(r, g, b);
1419                 } else {
1420                         uint8_t r, g, b;
1421                         r = R_OF_COLOR(palette4096txt[i]);
1422                         g = G_OF_COLOR(palette4096txt[i]);
1423                         b = B_OF_COLOR(palette4096txt[i]);
1424                         state_fio->FputUint8(r);
1425                         state_fio->FputUint8(g);
1426                         state_fio->FputUint8(b);
1427                 }
1428         }
1429         //state_fio->StateBuffer(palette16pri, sizeof(palette16pri), 1);
1430         for(int i = 0; i < 16; i++) {
1431                 for(int j = 0; j < 9; j++) {
1432                         if(loading) {
1433                                 uint8_t r, g, b;
1434                                 r = state_fio->FgetUint8();
1435                                 g = state_fio->FgetUint8();
1436                                 b = state_fio->FgetUint8();
1437                                 palette16pri[i][j] = RGB_COLOR(r, g, b);
1438                         } else {
1439                                 uint8_t r, g, b;
1440                                 r = R_OF_COLOR(palette16pri[i][j]);
1441                                 g = G_OF_COLOR(palette16pri[i][j]);
1442                                 b = B_OF_COLOR(palette16pri[i][j]);
1443                                 state_fio->FputUint8(r);
1444                                 state_fio->FputUint8(g);
1445                                 state_fio->FputUint8(b);
1446                         }
1447                 }
1448         }
1449         //state_fio->StateBuffer(palette4096pri, sizeof(palette4096pri), 1);
1450         for(int i = 0; i < 16; i++) {
1451                 for(int j = 0; j < 9; j++) {
1452                         if(loading) {
1453                                 uint8_t r, g, b;
1454                                 r = state_fio->FgetUint8();
1455                                 g = state_fio->FgetUint8();
1456                                 b = state_fio->FgetUint8();
1457                                 palette4096pri[i][j] = RGB_COLOR(r, g, b);
1458                         } else {
1459                                 uint8_t r, g, b;
1460                                 r = R_OF_COLOR(palette4096pri[i][j]);
1461                                 g = G_OF_COLOR(palette4096pri[i][j]);
1462                                 b = B_OF_COLOR(palette4096pri[i][j]);
1463                                 state_fio->FputUint8(r);
1464                                 state_fio->FputUint8(g);
1465                                 state_fio->FputUint8(b);
1466                         }
1467                 }
1468         }
1469         state_fio->StateUint8(prev16);
1470         state_fio->StateBool(update16);
1471         //state_fio->StateBuffer(map_addr, sizeof(map_addr), 1);
1472         for(int i = 0; i < 400; i++) {
1473                 for(int j = 0; j < 80; j++) {
1474                         state_fio->StateUint32(map_addr[i][j]);
1475                 }
1476         }
1477         state_fio->StateBuffer(map_hdsc, sizeof(map_hdsc), 1);
1478         state_fio->StateBuffer(text_matrix, sizeof(text_matrix), 1);
1479         state_fio->StateBuffer(text_matrixw, sizeof(text_matrixw), 1);
1480         state_fio->StateUint8(trans_color);
1481         state_fio->StateBool(map_init);
1482         state_fio->StateBool(trans_init);
1483         return true;
1484 }