OSDN Git Service

fd7de6e75bfdc209ce123e4116a7330b4c9ac411
[csp-qt/common_source_project-fm7.git] / source / src / vm / mz3500 / sub.cpp
1 /*
2         SHARP MZ-3500 Emulator 'EmuZ-3500'
3
4         Author : Takeda.Toshiya
5         Date   : 2010.08.31-
6
7         [ sub pcb ]
8 */
9
10 #include "./sub.h"
11 #include "./main.h"
12
13 #define SET_BANK(s, e, w, r) { \
14         int sb = (s) >> 11, eb = (e) >> 11; \
15         for(int i = sb; i <= eb; i++) { \
16                 if((w) == wdmy) { \
17                         wbank[i] = wdmy; \
18                 } else { \
19                         wbank[i] = (w) + 0x800 * (i - sb); \
20                 } \
21                 if((r) == rdmy) { \
22                         rbank[i] = rdmy; \
23                 } else { \
24                         rbank[i] = (r) + 0x800 * (i - sb); \
25                 } \
26         } \
27 }
28
29 void SUB::initialize()
30 {
31         // load rom image
32         memset(kanji, 0xff, sizeof(kanji));
33         
34         FILEIO* fio = new FILEIO();
35         if(fio->Fopen(create_local_path(_T("FONT.ROM")), FILEIO_READ_BINARY)) {
36                 fio->Fread(font, sizeof(font), 1);
37                 fio->Fclose();
38         }
39         if(fio->Fopen(create_local_path(_T("KANJI.ROM")), FILEIO_READ_BINARY)) {
40                 fio->Fread(kanji, sizeof(kanji), 1);
41                 fio->Fclose();
42         } else {
43                 if(fio->Fopen(create_local_path(_T("MB83256-019.ROM")), FILEIO_READ_BINARY)) {
44                         fio->Fread(kanji + 0x00000, 0x8000, 1);
45                         fio->Fclose();
46                 }
47                 if(fio->Fopen(create_local_path(_T("MB83256-020.ROM")), FILEIO_READ_BINARY)) {
48                         fio->Fread(kanji + 0x08000, 0x8000, 1);
49                         fio->Fclose();
50                 }
51                 if(fio->Fopen(create_local_path(_T("MB83256-021.ROM")), FILEIO_READ_BINARY)) {
52                         fio->Fread(kanji + 0x10000, 0x8000, 1);
53                         fio->Fclose();
54                 }
55                 if(fio->Fopen(create_local_path(_T("MB83256-022.ROM")), FILEIO_READ_BINARY)) {
56                         fio->Fread(kanji + 0x18000, 0x8000, 1);
57                         fio->Fclose();
58                 }
59         }
60         delete fio;
61         
62         // init memory
63         memset(ram, 0, sizeof(ram));
64         memset(vram_chr, 0, sizeof(vram_chr));
65         memset(vram_gfx, 0, sizeof(vram_gfx));
66         
67         SET_BANK(0x0000, 0x1fff, wdmy, ipl);
68         SET_BANK(0x2000, 0x27ff, common, common);
69         SET_BANK(0x2800, 0x3fff, wdmy, rdmy);
70         SET_BANK(0x4000, 0x7fff, ram, ram);
71         SET_BANK(0x8000, 0xffff, wdmy, rdmy);
72         
73         crt_400line = (config.monitor_type == 0 || config.monitor_type == 1);
74         
75         register_frame_event(this);
76 }
77
78 void SUB::reset()
79 {
80         memset(disp, 0, sizeof(disp));
81         cblink = 0;
82 }
83
84 void SUB::write_data8(uint32_t addr, uint32_t data)
85 {
86         addr &= 0xffff;
87         wbank[addr >> 11][addr & 0x7ff] = data;
88 }
89
90 uint32_t SUB::read_data8(uint32_t addr)
91 {
92         addr &= 0xffff;
93         return rbank[addr >> 11][addr & 0x7ff];
94 }
95
96 void SUB::write_io8(uint32_t addr, uint32_t data)
97 {
98         switch(addr & 0xf0) {
99         case 0x00:      // mz3500sm p.18,77
100 //              this->out_debug_log(_T("SUB->MAIN\tINT0=1\n"));
101                 d_main->write_signal(SIG_MAIN_INT0, 1, 1);
102                 break;
103         case 0x50:      // mz3500sm p.28
104                 if((addr & 0x0f) == 0x0d) {
105                         disp[5] = data;
106                 } else {
107                         disp[addr & 0x0f] = data;
108                 }
109                 break;
110         }
111 }
112
113 uint32_t SUB::read_io8(uint32_t addr)
114 {
115         switch(addr & 0xf0) {
116         case 0x50:      // mz3500sm p.28
117                 if((addr & 0x0f) == 0x0d) {
118                         return disp[5];
119                 } else {
120                         return disp[addr & 0x0f];
121                 }
122         }
123         return 0xff;
124 }
125
126 void SUB::event_frame()
127 {
128         cblink++;
129 }
130
131 // display
132
133 void SUB::draw_screen()
134 {
135         memset(screen_chr, 0, sizeof(screen_chr));
136         memset(screen_gfx, 0, sizeof(screen_gfx));
137         
138         // mz3500sm p.28
139         if(disp[0] & 1) {
140                 if(crt_400line) {
141                         draw_chr_400line();
142                 } else {
143                         draw_chr_200line();
144                 }
145         }
146         if(disp[1] & 7) {
147                 if(crt_400line) {
148                         draw_gfx_400line();
149                 } else if(disp[5] & 1) {
150                         draw_gfx_200line_16bit();
151                 } else {
152                         draw_gfx_200line_8bit();
153                 }
154         }
155         uint8_t back = disp[3] & 7;
156         
157         // create pc palette
158         scrntype_t palette_pc[8];
159         
160         for(int i = 0; i < 8; i++) {
161                 if(config.monitor_type == 1 || config.monitor_type == 3) {
162                         // green monitor
163                         palette_pc[i] = RGB_COLOR(0, (i != 0) ? 255 : 0, 0);
164                 } else if(!(disp[4] & 1)) {
165                         // monochrome mode
166                         palette_pc[i] = RGB_COLOR((i != 0) ? 255 : 0, (i != 0) ? 255 : 0, (i != 0) ? 255 : 0);
167                 } else {
168                         // color mode
169                         palette_pc[i] = RGB_COLOR((i & 2) ? 255 : 0, (i & 4) ? 255 : 0, (i & 1) ? 255 : 0);
170                 }
171         }
172         
173         // copy to pc screen
174         if(crt_400line) {
175                 for(int y = 0; y <400; y++) {
176                         scrntype_t* dest = emu->get_screen_buffer(y);
177                         uint8_t* src_chr = screen_chr[y];
178                         uint8_t* src_gfx = screen_gfx[y];
179                         
180                         for(int x = 0; x < 640; x++) {
181                                 dest[x] = palette_pc[(src_chr[x] ? (src_chr[x] & 7) : src_gfx[x] ? (src_gfx[x] & 7) : back)];
182                         }
183                 }
184                 emu->screen_skip_line(false);
185         } else {
186                 for(int y = 0; y < 400; y += 2) {
187                         scrntype_t* dest0 = emu->get_screen_buffer(y + 0);
188                         scrntype_t* dest1 = emu->get_screen_buffer(y + 1);
189                         uint8_t* src_chr = screen_chr[y];
190                         uint8_t* src_gfx = screen_gfx[y];
191                         
192                         for(int x = 0; x < 640; x++) {
193                                 dest0[x] = palette_pc[(src_chr[x] ? (src_chr[x] & 7) : src_gfx[x] ? (src_gfx[x] & 7) : back)];
194                         }
195                         if(config.scan_line) {
196                                 memset(dest1, 0, 640 * sizeof(scrntype_t));
197                         } else {
198                                 my_memcpy(dest1, dest0, 640 * sizeof(scrntype_t));
199                         }
200                 }
201                 emu->screen_skip_line(true);
202         }
203 }
204
205 void SUB::draw_chr_400line()
206 {
207         // mz3500sm p.28
208         int width = (disp[5] & 2) ? 1 : 2;      // 80/40 columns
209         int height = (disp[7] & 1) ? 20 : 16;   // 20/16 dots/ine
210         int ymax = (disp[7] & 1) ? 20 : 25;     // 20/25 lines
211         
212         for(int i = 0, ytop = 0; i < 4; i++) {
213                 uint32_t ra = ra_chr[4 * i];
214                 ra |= ra_chr[4 * i + 1] << 8;
215                 ra |= ra_chr[4 * i + 2] << 16;
216                 ra |= ra_chr[4 * i + 3] << 24;
217                 int src = ra & 0x1fff;
218                 int len = ((ra >> 20) & 0x3ff) / height;
219                 int caddr = ((cs_chr[0] & 0x80) && ((cs_chr[1] & 0x20) || !(cblink & 0x10))) ? (*ead_chr & 0x1fff) : -1;
220                 
221                 for(int y = ytop; y < (ytop + len) && y < ymax; y++) {
222                         for(int x = 0; x < 80; x += width) {
223                                 bool cursor = (src == caddr);
224                                 uint32_t code = vram_chr[(src * 2 + 0) & 0xfff];        // low byte  : code
225                                 uint8_t attr = vram_chr[(src * 2 + 1) & 0xfff]; // high byte : attr
226                                 uint32_t knji = vram_chr[((src* 2 + 0) & 0xfff) | 0x1000];
227                                 src++;
228                                 uint8_t *pattern;
229                                 
230                                 if(!(knji & 0x20)) {
231                                         pattern = &kanji[((code << 4) | (knji << 12)) & 0x1ffff];
232                                 } else {
233                                         pattern = &font[0x1000 | (code << 4)];
234                                 }
235                                 
236                                 // mz3500sm p.31
237                                 // bit3: blink
238                                 // bit2: reverse or green
239                                 // bit1: horizontal line or red
240                                 // bit0: vertical line or blue
241                                 
242                                 uint8_t color;
243                                 bool vline, hline, reverse, blink;
244                                 
245                                 if(disp[4] & 1) {
246                                         // color mode
247                                         if(!(knji & 0x20)) {
248                                                 color = (~attr & 7) | 8;
249                                         } else {
250                                                 color = (attr & 7) | 8;
251                                         }
252                                         vline = hline = reverse = false;
253                                 } else {
254                                         // monocrhome mode
255                                         color = 7;
256                                         vline = ((attr & 1) != 0);
257                                         hline = ((attr & 2) != 0);
258                                         reverse = ((attr & 4) != 0);
259                                 }
260                                 blink = ((attr & 8) != 0 && (cblink & 0x10) != 0);
261                                 reverse = (reverse != blink);
262                                 
263                                 // NOTE: need to consider 200 line mode
264                                 
265                                 for(int l = 0; l < 16; l++) {
266                                         int yy = y * height + l;
267                                         if(yy >= 400) {
268                                                 break;
269                                         }
270                                         uint8_t pat = reverse ? ~pattern[l] : pattern[l];
271                                         uint8_t *dest = &screen_chr[yy][x << 3];
272                                         
273                                         if(width == 1) {
274                                                 // 8dots (80columns)
275                                                 dest[0] = (pat & 0x80) ? color : 0;
276                                                 dest[1] = (pat & 0x40) ? color : 0;
277                                                 dest[2] = (pat & 0x20) ? color : 0;
278                                                 dest[3] = (pat & 0x10) ? color : 0;
279                                                 dest[4] = (pat & 0x08) ? color : 0;
280                                                 dest[5] = (pat & 0x04) ? color : 0;
281                                                 dest[6] = (pat & 0x02) ? color : 0;
282                                                 dest[7] = (pat & 0x01) ? color : 0;
283                                         } else {
284                                                 // 16dots (40columns)
285                                                 dest[ 0] = dest[ 1] = (pat & 0x80) ? color : 0;
286                                                 dest[ 2] = dest[ 3] = (pat & 0x40) ? color : 0;
287                                                 dest[ 4] = dest[ 5] = (pat & 0x20) ? color : 0;
288                                                 dest[ 6] = dest[ 7] = (pat & 0x10) ? color : 0;
289                                                 dest[ 8] = dest[ 9] = (pat & 0x08) ? color : 0;
290                                                 dest[10] = dest[11] = (pat & 0x04) ? color : 0;
291                                                 dest[12] = dest[13] = (pat & 0x02) ? color : 0;
292                                                 dest[14] = dest[15] = (pat & 0x01) ? color : 0;
293                                         }
294                                 }
295                                 if(vline) {
296                                         for(int l = 0; l < ((height == 16) ? 16 : 18); l++) {
297                                                 int yy = y * height + l;
298                                                 if(yy >= 400) {
299                                                         break;
300                                                 }
301                                                 screen_chr[yy][(x << 3) + (width * 8 - 1)] = color;
302                                         }
303                                 }
304                                 if(hline) {
305                                         int yy = y * height + ((height == 16) ? 15 : 17);
306                                         if(!(yy >= 400)) {
307                                                 memset(&screen_chr[yy][x << 3], color, width * 8);
308                                         }
309                                 }
310                                 if(cursor) {
311                                         int top = cs_chr[1] & 0x1f, bottom = cs_chr[2] >> 3;
312                                         for(int l = top; l < bottom && l < height; l++) {
313                                                 int yy = y * height + l;
314                                                 if(yy >= 400) {
315                                                         break;
316                                                 }
317                                                 memset(&screen_chr[yy][x << 3], 7, width * 8);  // always white ???
318                                         }
319                                 }
320                         }
321                 }
322                 ytop += len;
323         }
324 }
325
326 void SUB::draw_chr_200line()
327 {
328         // mz3500sm p.28
329         int width = (disp[5] & 2) ? 1 : 2;      // 80/40 columns
330         int height = (disp[7] & 1) ? 10 : 8;    // 20/16 dots/ine
331         int ymax = (disp[7] & 1) ? 20 : 25;     // 20/25 lines
332         
333         for(int i = 0, ytop = 0; i < 4; i++) {
334                 uint32_t ra = ra_chr[4 * i];
335                 ra |= ra_chr[4 * i + 1] << 8;
336                 ra |= ra_chr[4 * i + 2] << 16;
337                 ra |= ra_chr[4 * i + 3] << 24;
338                 int src = ra & 0x1fff;
339                 int len = ((ra >> 20) & 0x3ff) / height;
340                 int caddr = ((cs_chr[0] & 0x80) && ((cs_chr[1] & 0x20) || !(cblink & 0x10))) ? (*ead_chr & 0x1fff) : -1;
341                 
342                 for(int y = ytop; y < (ytop + len) && y < ymax; y++) {
343                         for(int x = 0; x < 80; x += width) {
344                                 bool cursor = (src == caddr);
345                                 uint32_t code = vram_chr[(src * 2 + 0) & 0xfff];        // low byte  : code
346                                 uint8_t attr = vram_chr[(src * 2 + 1) & 0xfff]; // high byte : attr
347                                 uint32_t knji = vram_chr[((src* 2 + 0) & 0xfff) | 0x1000];
348                                 src++;
349                                 uint8_t *pattern;
350                                 
351                                 if(!(knji & 0x20)) {
352                                         pattern = &kanji[((code << 4) | (knji << 12)) & 0x1ffff];
353                                 } else {
354                                         pattern = &font[(code << 4) + ((config.dipswitch & 0x100) ? 0 : 8)];
355                                 }
356                                 
357                                 // mz3500sm p.31
358                                 // bit3: blink
359                                 // bit2: reverse or green
360                                 // bit1: horizontal line or red
361                                 // bit0: vertical line or blue
362                                 
363                                 uint8_t color;
364                                 bool vline, hline, reverse, blink;
365                                 
366                                 if(disp[4] & 1) {
367                                         // color mode
368                                         color = (attr & 7) ? (attr & 7) : 7;
369                                         vline = hline = reverse = false;
370                                 } else {
371                                         // monocrhome mode
372                                         color = 7;
373                                         vline = ((attr & 1) != 0);
374                                         hline = ((attr & 2) != 0);
375                                         reverse = ((attr & 4) != 0);
376                                 }
377                                 blink = ((attr & 8) != 0 && (cblink & 0x10) != 0);
378                                 reverse = (reverse != blink);
379                                 
380                                 // NOTE: need to consider 200 line mode
381                                 
382                                 for(int l = 0; l < 8; l++) {
383                                         int yy = (y * height + l) * 2;
384                                         if(yy >= 400) {
385                                                 break;
386                                         }
387                                         uint8_t pat = reverse ? ~pattern[l] : pattern[l];
388                                         uint8_t *dest = &screen_chr[yy][x << 3];
389                                         
390                                         if(width == 1) {
391                                                 // 8dots (80columns)
392                                                 dest[0] = (pat & 0x80) ? color : 0;
393                                                 dest[1] = (pat & 0x40) ? color : 0;
394                                                 dest[2] = (pat & 0x20) ? color : 0;
395                                                 dest[3] = (pat & 0x10) ? color : 0;
396                                                 dest[4] = (pat & 0x08) ? color : 0;
397                                                 dest[5] = (pat & 0x04) ? color : 0;
398                                                 dest[6] = (pat & 0x02) ? color : 0;
399                                                 dest[7] = (pat & 0x01) ? color : 0;
400                                         } else {
401                                                 // 16dots (40columns)
402                                                 dest[ 0] = dest[ 1] = (pat & 0x80) ? color : 0;
403                                                 dest[ 2] = dest[ 3] = (pat & 0x40) ? color : 0;
404                                                 dest[ 4] = dest[ 5] = (pat & 0x20) ? color : 0;
405                                                 dest[ 6] = dest[ 7] = (pat & 0x10) ? color : 0;
406                                                 dest[ 8] = dest[ 9] = (pat & 0x08) ? color : 0;
407                                                 dest[10] = dest[11] = (pat & 0x04) ? color : 0;
408                                                 dest[12] = dest[13] = (pat & 0x02) ? color : 0;
409                                                 dest[14] = dest[15] = (pat & 0x01) ? color : 0;
410                                         }
411                                 }
412                                 if(vline) {
413                                         for(int l = 0; l < ((height == 8) ? 8 : 9); l++) {
414                                                 int yy = (y * height + l) * 2;
415                                                 if(yy >= 400) {
416                                                         break;
417                                                 }
418                                                 screen_chr[yy][(x << 3) + (width * 8 - 1)] = color;
419                                         }
420                                 }
421                                 if(hline) {
422                                         int yy = (y * height + ((height == 8) ? 7 : 8)) * 2;
423                                         if(!(yy >= 400)) {
424                                                 memset(&screen_chr[yy][x << 3], color, width * 8);
425                                         }
426                                 }
427                                 if(cursor) {
428                                         int top = cs_chr[1] & 0x1f, bottom = cs_chr[2] >> 3;
429                                         for(int l = top; l < bottom && l < height; l++) {
430                                                 int yy = (y * height + l) * 2;
431                                                 if(yy >= 400) {
432                                                         break;
433                                                 }
434                                                 memset(&screen_chr[yy][x << 3], 7, width * 8);  // always white ???
435                                         }
436                                 }
437                         }
438                 }
439                 ytop += len;
440         }
441 }
442
443 void SUB::draw_gfx_400line()
444 {
445         for(int i = 0, ytop = 0; i < 4; i++) {
446                 uint32_t ra = ra_gfx[4 * i];
447                 ra |= ra_gfx[4 * i + 1] << 8;
448                 ra |= ra_gfx[4 * i + 2] << 16;
449                 ra |= ra_gfx[4 * i + 3] << 24;
450                 int src = ra & 0x1fff;
451                 int len = (ra >> 20) & 0x3ff;
452                 
453                 for(int y = ytop; y < (ytop + len) && y < 400; y++) {
454                         if(y >= 400) {
455                                 break;
456                         }
457                         for(int x = 0; x < 40; x++) {
458                                 uint8_t lo_b = (disp[1] & 1) ? vram_gfx[((src * 2 + 0) & 0x7fff) | 0x00000] : 0;
459                                 uint8_t hi_b = (disp[1] & 1) ? vram_gfx[((src * 2 + 1) & 0x7fff) | 0x00000] : 0;
460                                 uint8_t lo_r = (disp[1] & 2) ? vram_gfx[((src * 2 + 0) & 0x7fff) | 0x08000] : 0;
461                                 uint8_t hi_r = (disp[1] & 2) ? vram_gfx[((src * 2 + 1) & 0x7fff) | 0x08000] : 0;
462                                 uint8_t lo_g = (disp[1] & 4) ? vram_gfx[((src * 2 + 0) & 0x7fff) | 0x10000] : 0;
463                                 uint8_t hi_g = (disp[1] & 4) ? vram_gfx[((src * 2 + 1) & 0x7fff) | 0x10000] : 0;
464                                 src++;
465                                 
466                                 uint8_t *dest = &screen_gfx[y][x * 16];
467                                 dest[ 0] = ((lo_b & 0x01)     ) | ((lo_r & 0x01) << 1) | ((lo_g & 0x01) << 2);
468                                 dest[ 1] = ((lo_b & 0x02) >> 1) | ((lo_r & 0x02)     ) | ((lo_g & 0x02) << 1);
469                                 dest[ 2] = ((lo_b & 0x04) >> 2) | ((lo_r & 0x04) >> 1) | ((lo_g & 0x04)     );
470                                 dest[ 3] = ((lo_b & 0x08) >> 3) | ((lo_r & 0x08) >> 2) | ((lo_g & 0x08) >> 1);
471                                 dest[ 4] = ((lo_b & 0x10) >> 4) | ((lo_r & 0x10) >> 3) | ((lo_g & 0x10) >> 2);
472                                 dest[ 5] = ((lo_b & 0x20) >> 5) | ((lo_r & 0x20) >> 4) | ((lo_g & 0x20) >> 3);
473                                 dest[ 6] = ((lo_b & 0x40) >> 6) | ((lo_r & 0x40) >> 5) | ((lo_g & 0x40) >> 4);
474                                 dest[ 7] = ((lo_b & 0x80) >> 7) | ((lo_r & 0x80) >> 6) | ((lo_g & 0x80) >> 5);
475                                 dest[ 8] = ((hi_b & 0x01)     ) | ((hi_r & 0x01) << 1) | ((hi_g & 0x01) << 2);
476                                 dest[ 9] = ((hi_b & 0x02) >> 1) | ((hi_r & 0x02)     ) | ((hi_g & 0x02) << 1);
477                                 dest[10] = ((hi_b & 0x04) >> 2) | ((hi_r & 0x04) >> 1) | ((hi_g & 0x04)     );
478                                 dest[11] = ((hi_b & 0x08) >> 3) | ((hi_r & 0x08) >> 2) | ((hi_g & 0x08) >> 1);
479                                 dest[12] = ((hi_b & 0x10) >> 4) | ((hi_r & 0x10) >> 3) | ((hi_g & 0x10) >> 2);
480                                 dest[13] = ((hi_b & 0x20) >> 5) | ((hi_r & 0x20) >> 4) | ((hi_g & 0x20) >> 3);
481                                 dest[14] = ((hi_b & 0x40) >> 6) | ((hi_r & 0x40) >> 5) | ((hi_g & 0x40) >> 4);
482                                 dest[15] = ((hi_b & 0x80) >> 7) | ((hi_r & 0x80) >> 6) | ((hi_g & 0x80) >> 5);
483                         }
484                 }
485                 ytop += len;
486         }
487 }
488
489 void SUB::draw_gfx_200line_16bit()
490 {
491         for(int i = 0, ytop = 0; i < 4; i++) {
492                 uint32_t ra = ra_gfx[4 * i];
493                 ra |= ra_gfx[4 * i + 1] << 8;
494                 ra |= ra_gfx[4 * i + 2] << 16;
495                 ra |= ra_gfx[4 * i + 3] << 24;
496                 int src = ra & 0x1fff;
497                 int len = (ra >> 20) & 0x3ff;
498                 
499                 for(int y = ytop; y < (ytop + len) && y < 200; y++) {
500                         if(y >= 200) {
501                                 break;
502                         }
503                         for(int x = 0; x < 40; x++) {
504                                 uint8_t lo_b = (disp[1] & 1) ? vram_gfx[((src * 2 + 0) & 0x7fff) | 0x00000] : 0;
505                                 uint8_t hi_b = (disp[1] & 1) ? vram_gfx[((src * 2 + 1) & 0x7fff) | 0x00000] : 0;
506                                 uint8_t lo_r = (disp[1] & 2) ? vram_gfx[((src * 2 + 0) & 0x7fff) | 0x08000] : 0;
507                                 uint8_t hi_r = (disp[1] & 2) ? vram_gfx[((src * 2 + 1) & 0x7fff) | 0x08000] : 0;
508                                 uint8_t lo_g = (disp[1] & 4) ? vram_gfx[((src * 2 + 0) & 0x7fff) | 0x10000] : 0;
509                                 uint8_t hi_g = (disp[1] & 4) ? vram_gfx[((src * 2 + 1) & 0x7fff) | 0x10000] : 0;
510                                 src++;
511                                 
512                                 uint8_t *dest = &screen_gfx[y * 2][x * 16];
513                                 dest[ 0] = ((lo_b & 0x01)     ) | ((lo_r & 0x01) << 1) | ((lo_g & 0x01) << 2);
514                                 dest[ 1] = ((lo_b & 0x02) >> 1) | ((lo_r & 0x02)     ) | ((lo_g & 0x02) << 1);
515                                 dest[ 2] = ((lo_b & 0x04) >> 2) | ((lo_r & 0x04) >> 1) | ((lo_g & 0x04)     );
516                                 dest[ 3] = ((lo_b & 0x08) >> 3) | ((lo_r & 0x08) >> 2) | ((lo_g & 0x08) >> 1);
517                                 dest[ 4] = ((lo_b & 0x10) >> 4) | ((lo_r & 0x10) >> 3) | ((lo_g & 0x10) >> 2);
518                                 dest[ 5] = ((lo_b & 0x20) >> 5) | ((lo_r & 0x20) >> 4) | ((lo_g & 0x20) >> 3);
519                                 dest[ 6] = ((lo_b & 0x40) >> 6) | ((lo_r & 0x40) >> 5) | ((lo_g & 0x40) >> 4);
520                                 dest[ 7] = ((lo_b & 0x80) >> 7) | ((lo_r & 0x80) >> 6) | ((lo_g & 0x80) >> 5);
521                                 dest[ 8] = ((hi_b & 0x01)     ) | ((hi_r & 0x01) << 1) | ((hi_g & 0x01) << 2);
522                                 dest[ 9] = ((hi_b & 0x02) >> 1) | ((hi_r & 0x02)     ) | ((hi_g & 0x02) << 1);
523                                 dest[10] = ((hi_b & 0x04) >> 2) | ((hi_r & 0x04) >> 1) | ((hi_g & 0x04)     );
524                                 dest[11] = ((hi_b & 0x08) >> 3) | ((hi_r & 0x08) >> 2) | ((hi_g & 0x08) >> 1);
525                                 dest[12] = ((hi_b & 0x10) >> 4) | ((hi_r & 0x10) >> 3) | ((hi_g & 0x10) >> 2);
526                                 dest[13] = ((hi_b & 0x20) >> 5) | ((hi_r & 0x20) >> 4) | ((hi_g & 0x20) >> 3);
527                                 dest[14] = ((hi_b & 0x40) >> 6) | ((hi_r & 0x40) >> 5) | ((hi_g & 0x40) >> 4);
528                                 dest[15] = ((hi_b & 0x80) >> 7) | ((hi_r & 0x80) >> 6) | ((hi_g & 0x80) >> 5);
529                         }
530                 }
531                 ytop += len;
532         }
533 }
534
535 void SUB::draw_gfx_200line_8bit()
536 {
537         for(int i = 0, ytop = 0; i < 4; i++) {
538                 uint32_t ra = ra_gfx[4 * i];
539                 ra |= ra_gfx[4 * i + 1] << 8;
540                 ra |= ra_gfx[4 * i + 2] << 16;
541                 ra |= ra_gfx[4 * i + 3] << 24;
542                 int src = ra & 0x1fff;
543                 int len = (ra >> 20) & 0x3ff;
544                 
545                 for(int y = ytop; y < (ytop + len) && y < 200; y++) {
546                         if(y >= 200) {
547                                 break;
548                         }
549                         for(int x = 0; x < 80; x++) {
550                                 uint8_t b = (disp[1] & 1) ? vram_gfx[((src * 2 + 0) & 0x7fff) | 0x00000] : 0;
551                                 uint8_t r = (disp[1] & 2) ? vram_gfx[((src * 2 + 1) & 0x7fff) | 0x00000] : 0;
552                                 uint8_t g = (disp[1] & 4) ? vram_gfx[((src * 2 + 0) & 0x7fff) | 0x10000] : 0;
553                                 src++;
554                                 
555                                 uint8_t *dest = &screen_gfx[y * 2][x * 8];
556                                 dest[0] = ((b & 0x01)     ) | ((r & 0x01) << 1) | ((g & 0x01) << 2);
557                                 dest[1] = ((b & 0x02) >> 1) | ((r & 0x02)     ) | ((g & 0x02) << 1);
558                                 dest[2] = ((b & 0x04) >> 2) | ((r & 0x04) >> 1) | ((g & 0x04)     );
559                                 dest[3] = ((b & 0x08) >> 3) | ((r & 0x08) >> 2) | ((g & 0x08) >> 1);
560                                 dest[4] = ((b & 0x10) >> 4) | ((r & 0x10) >> 3) | ((g & 0x10) >> 2);
561                                 dest[5] = ((b & 0x20) >> 5) | ((r & 0x20) >> 4) | ((g & 0x20) >> 3);
562                                 dest[6] = ((b & 0x40) >> 6) | ((r & 0x40) >> 5) | ((g & 0x40) >> 4);
563                                 dest[7] = ((b & 0x80) >> 7) | ((r & 0x80) >> 6) | ((g & 0x80) >> 5);
564                         }
565                 }
566                 ytop += len;
567         }
568 }
569
570 #define STATE_VERSION   3
571
572 bool SUB::process_state(FILEIO* state_fio, bool loading)
573 {
574         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
575                 return false;
576         }
577         if(!state_fio->StateCheckInt32(this_device_id)) {
578                 return false;
579         }
580         state_fio->StateBuffer(ram, sizeof(ram), 1);
581         state_fio->StateBuffer(vram_chr, sizeof(vram_chr), 1);
582         state_fio->StateBuffer(vram_gfx, sizeof(vram_gfx), 1);
583         state_fio->StateBuffer(disp, sizeof(disp), 1);
584         state_fio->StateInt32(cblink);
585         state_fio->StateBool(crt_400line);
586         return true;
587 }