OSDN Git Service

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