OSDN Git Service

[VM][STATE] Apply new framework to some VMs.
[csp-qt/common_source_project-fm7.git] / source / src / vm / mz3500 / sub.cpp
index 54837be..fd7de6e 100644 (file)
@@ -4,11 +4,11 @@
        Author : Takeda.Toshiya
        Date   : 2010.08.31-
 
-       [ sub ]
+       [ sub pcb ]
 */
 
-#include "sub.h"
-#include "main.h"
+#include "./sub.h"
+#include "./main.h"
 
 #define SET_BANK(s, e, w, r) { \
        int sb = (s) >> 11, eb = (e) >> 11; \
 void SUB::initialize()
 {
        // load rom image
+       memset(kanji, 0xff, sizeof(kanji));
+       
        FILEIO* fio = new FILEIO();
-       if(fio->Fopen(emu->bios_path(_T("FONT.ROM")), FILEIO_READ_BINARY)) {
+       if(fio->Fopen(create_local_path(_T("FONT.ROM")), FILEIO_READ_BINARY)) {
                fio->Fread(font, sizeof(font), 1);
                fio->Fclose();
        }
-       delete fio;
-       
-       // create pc palette
-       for(int i = 0; i < 8; i++) {
-               palette_pc[i] = RGB_COLOR((i & 2) ? 255 : 0, (i & 4) ? 255 : 0, (i & 1) ? 255 : 0);
+       if(fio->Fopen(create_local_path(_T("KANJI.ROM")), FILEIO_READ_BINARY)) {
+               fio->Fread(kanji, sizeof(kanji), 1);
+               fio->Fclose();
+       } else {
+               if(fio->Fopen(create_local_path(_T("MB83256-019.ROM")), FILEIO_READ_BINARY)) {
+                       fio->Fread(kanji + 0x00000, 0x8000, 1);
+                       fio->Fclose();
+               }
+               if(fio->Fopen(create_local_path(_T("MB83256-020.ROM")), FILEIO_READ_BINARY)) {
+                       fio->Fread(kanji + 0x08000, 0x8000, 1);
+                       fio->Fclose();
+               }
+               if(fio->Fopen(create_local_path(_T("MB83256-021.ROM")), FILEIO_READ_BINARY)) {
+                       fio->Fread(kanji + 0x10000, 0x8000, 1);
+                       fio->Fclose();
+               }
+               if(fio->Fopen(create_local_path(_T("MB83256-022.ROM")), FILEIO_READ_BINARY)) {
+                       fio->Fread(kanji + 0x18000, 0x8000, 1);
+                       fio->Fclose();
+               }
        }
+       delete fio;
        
        // init memory
        memset(ram, 0, sizeof(ram));
@@ -52,6 +70,8 @@ void SUB::initialize()
        SET_BANK(0x4000, 0x7fff, ram, ram);
        SET_BANK(0x8000, 0xffff, wdmy, rdmy);
        
+       crt_400line = (config.monitor_type == 0 || config.monitor_type == 1);
+       
        register_frame_event(this);
 }
 
@@ -61,23 +81,23 @@ void SUB::reset()
        cblink = 0;
 }
 
-void SUB::write_data8(uint32 addr, uint32 data)
+void SUB::write_data8(uint32_t addr, uint32_t data)
 {
        addr &= 0xffff;
        wbank[addr >> 11][addr & 0x7ff] = data;
 }
 
-uint32 SUB::read_data8(uint32 addr)
+uint32_t SUB::read_data8(uint32_t addr)
 {
        addr &= 0xffff;
        return rbank[addr >> 11][addr & 0x7ff];
 }
 
-void SUB::write_io8(uint32 addr, uint32 data)
+void SUB::write_io8(uint32_t addr, uint32_t data)
 {
        switch(addr & 0xf0) {
        case 0x00:      // mz3500sm p.18,77
-//             emu->out_debug_log("SUB->MAIN\tINT0=1\n");
+//             this->out_debug_log(_T("SUB->MAIN\tINT0=1\n"));
                d_main->write_signal(SIG_MAIN_INT0, 1, 1);
                break;
        case 0x50:      // mz3500sm p.28
@@ -90,13 +110,9 @@ void SUB::write_io8(uint32 addr, uint32 data)
        }
 }
 
-uint32 SUB::read_io8(uint32 addr)
+uint32_t SUB::read_io8(uint32_t addr)
 {
        switch(addr & 0xf0) {
-       case 0x00:      // mz3500sm p.18,77
-//             emu->out_debug_log("SUB->MAIN\tINT0=1\n");
-               d_main->write_signal(SIG_MAIN_INT0, 1, 1);
-               break;
        case 0x50:      // mz3500sm p.28
                if((addr & 0x0f) == 0x0d) {
                        return disp[5];
@@ -112,13 +128,6 @@ void SUB::event_frame()
        cblink++;
 }
 
-void SUB::write_signal(int id, uint32 data, uint32 mask)
-{
-       if(id == SIG_SUB_PIO_PM) {
-               pm = ((data & mask) != 0);
-       }
-}
-
 // display
 
 void SUB::draw_screen()
@@ -128,27 +137,72 @@ void SUB::draw_screen()
        
        // mz3500sm p.28
        if(disp[0] & 1) {
-               draw_chr();
+               if(crt_400line) {
+                       draw_chr_400line();
+               } else {
+                       draw_chr_200line();
+               }
        }
        if(disp[1] & 7) {
-               draw_gfx();
+               if(crt_400line) {
+                       draw_gfx_400line();
+               } else if(disp[5] & 1) {
+                       draw_gfx_200line_16bit();
+               } else {
+                       draw_gfx_200line_8bit();
+               }
+       }
+       uint8_t back = disp[3] & 7;
+       
+       // create pc palette
+       scrntype_t palette_pc[8];
+       
+       for(int i = 0; i < 8; i++) {
+               if(config.monitor_type == 1 || config.monitor_type == 3) {
+                       // green monitor
+                       palette_pc[i] = RGB_COLOR(0, (i != 0) ? 255 : 0, 0);
+               } else if(!(disp[4] & 1)) {
+                       // monochrome mode
+                       palette_pc[i] = RGB_COLOR((i != 0) ? 255 : 0, (i != 0) ? 255 : 0, (i != 0) ? 255 : 0);
+               } else {
+                       // color mode
+                       palette_pc[i] = RGB_COLOR((i & 2) ? 255 : 0, (i & 4) ? 255 : 0, (i & 1) ? 255 : 0);
+               }
        }
-       uint8 back = disp[3] & 7;
        
        // copy to pc screen
-       for(int y = 0; y <400; y++) {
-               scrntype* dest = emu->screen_buffer(y);
-               uint8* src_chr = screen_chr[y];
-               uint8* src_gfx = screen_gfx[y];
-               
-               for(int x = 0; x < 640; x++) {
-                       dest[x] = palette_pc[(src_chr[x] ? (src_chr[x] & 7) : src_gfx[x] ? (src_gfx[x] & 7) : back)];
+       if(crt_400line) {
+               for(int y = 0; y <400; y++) {
+                       scrntype_t* dest = emu->get_screen_buffer(y);
+                       uint8_t* src_chr = screen_chr[y];
+                       uint8_t* src_gfx = screen_gfx[y];
+                       
+                       for(int x = 0; x < 640; x++) {
+                               dest[x] = palette_pc[(src_chr[x] ? (src_chr[x] & 7) : src_gfx[x] ? (src_gfx[x] & 7) : back)];
+                       }
                }
+               emu->screen_skip_line(false);
+       } else {
+               for(int y = 0; y < 400; y += 2) {
+                       scrntype_t* dest0 = emu->get_screen_buffer(y + 0);
+                       scrntype_t* dest1 = emu->get_screen_buffer(y + 1);
+                       uint8_t* src_chr = screen_chr[y];
+                       uint8_t* src_gfx = screen_gfx[y];
+                       
+                       for(int x = 0; x < 640; x++) {
+                               dest0[x] = palette_pc[(src_chr[x] ? (src_chr[x] & 7) : src_gfx[x] ? (src_gfx[x] & 7) : back)];
+                       }
+                       if(config.scan_line) {
+                               memset(dest1, 0, 640 * sizeof(scrntype_t));
+                       } else {
+                               my_memcpy(dest1, dest0, 640 * sizeof(scrntype_t));
+                       }
+               }
+               emu->screen_skip_line(true);
        }
-       emu->screen_skip_line = false;
 }
 
-void SUB::draw_chr()
+void SUB::draw_chr_400line()
 {
        // mz3500sm p.28
        int width = (disp[5] & 2) ? 1 : 2;      // 80/40 columns
@@ -156,7 +210,7 @@ void SUB::draw_chr()
        int ymax = (disp[7] & 1) ? 20 : 25;     // 20/25 lines
        
        for(int i = 0, ytop = 0; i < 4; i++) {
-               uint32 ra = ra_chr[4 * i];
+               uint32_t ra = ra_chr[4 * i];
                ra |= ra_chr[4 * i + 1] << 8;
                ra |= ra_chr[4 * i + 2] << 16;
                ra |= ra_chr[4 * i + 3] << 24;
@@ -167,33 +221,45 @@ void SUB::draw_chr()
                for(int y = ytop; y < (ytop + len) && y < ymax; y++) {
                        for(int x = 0; x < 80; x += width) {
                                bool cursor = (src == caddr);
-                               uint8 code = vram_chr[(src * 2 + 0) & 0xfff];   // low byte  : code
-                               uint8 attr = vram_chr[(src * 2 + 1) & 0xfff];   // high byte : attr
+                               uint32_t code = vram_chr[(src * 2 + 0) & 0xfff];        // low byte  : code
+                               uint8_t attr = vram_chr[(src * 2 + 1) & 0xfff]; // high byte : attr
+                               uint32_t knji = vram_chr[((src* 2 + 0) & 0xfff) | 0x1000];
                                src++;
+                               uint8_t *pattern;
+                               
+                               if(!(knji & 0x20)) {
+                                       pattern = &kanji[((code << 4) | (knji << 12)) & 0x1ffff];
+                               } else {
+                                       pattern = &font[0x1000 | (code << 4)];
+                               }
                                
                                // mz3500sm p.31
                                // bit3: blink
                                // bit2: reverse or green
-                               // bit1: vertical line or red
-                               // bit0: horizontal line or blue
+                               // bit1: horizontal line or red
+                               // bit0: vertical line or blue
                                
-                               uint8 color;
-                               bool reverse, blink;
+                               uint8_t color;
+                               bool vline, hline, reverse, blink;
                                
                                if(disp[4] & 1) {
-                                       // color
-                                       color = attr & 7;
-                                       reverse = false;
+                                       // color mode
+                                       if(!(knji & 0x20)) {
+                                               color = (~attr & 7) | 8;
+                                       } else {
+                                               color = (attr & 7) | 8;
+                                       }
+                                       vline = hline = reverse = false;
                                } else {
-                                       // monocrhome
+                                       // monocrhome mode
                                        color = 7;
+                                       vline = ((attr & 1) != 0);
+                                       hline = ((attr & 2) != 0);
                                        reverse = ((attr & 4) != 0);
                                }
                                blink = ((attr & 8) != 0 && (cblink & 0x10) != 0);
                                reverse = (reverse != blink);
                                
-                               uint8* pattern = &font[0x1000 | (code << 4)];
-                               
                                // NOTE: need to consider 200 line mode
                                
                                for(int l = 0; l < 16; l++) {
@@ -201,8 +267,8 @@ void SUB::draw_chr()
                                        if(yy >= 400) {
                                                break;
                                        }
-                                       uint8 pat = reverse ? ~pattern[l] : pattern[l];
-                                       uint8 *dest = &screen_chr[yy][x << 3];
+                                       uint8_t pat = reverse ? ~pattern[l] : pattern[l];
+                                       uint8_t *dest = &screen_chr[yy][x << 3];
                                        
                                        if(width == 1) {
                                                // 8dots (80columns)
@@ -226,6 +292,21 @@ void SUB::draw_chr()
                                                dest[14] = dest[15] = (pat & 0x01) ? color : 0;
                                        }
                                }
+                               if(vline) {
+                                       for(int l = 0; l < ((height == 16) ? 16 : 18); l++) {
+                                               int yy = y * height + l;
+                                               if(yy >= 400) {
+                                                       break;
+                                               }
+                                               screen_chr[yy][(x << 3) + (width * 8 - 1)] = color;
+                                       }
+                               }
+                               if(hline) {
+                                       int yy = y * height + ((height == 16) ? 15 : 17);
+                                       if(!(yy >= 400)) {
+                                               memset(&screen_chr[yy][x << 3], color, width * 8);
+                                       }
+                               }
                                if(cursor) {
                                        int top = cs_chr[1] & 0x1f, bottom = cs_chr[2] >> 3;
                                        for(int l = top; l < bottom && l < height; l++) {
@@ -242,39 +323,265 @@ void SUB::draw_chr()
        }
 }
 
-void SUB::draw_gfx()
+void SUB::draw_chr_200line()
+{
+       // mz3500sm p.28
+       int width = (disp[5] & 2) ? 1 : 2;      // 80/40 columns
+       int height = (disp[7] & 1) ? 10 : 8;    // 20/16 dots/ine
+       int ymax = (disp[7] & 1) ? 20 : 25;     // 20/25 lines
+       
+       for(int i = 0, ytop = 0; i < 4; i++) {
+               uint32_t ra = ra_chr[4 * i];
+               ra |= ra_chr[4 * i + 1] << 8;
+               ra |= ra_chr[4 * i + 2] << 16;
+               ra |= ra_chr[4 * i + 3] << 24;
+               int src = ra & 0x1fff;
+               int len = ((ra >> 20) & 0x3ff) / height;
+               int caddr = ((cs_chr[0] & 0x80) && ((cs_chr[1] & 0x20) || !(cblink & 0x10))) ? (*ead_chr & 0x1fff) : -1;
+               
+               for(int y = ytop; y < (ytop + len) && y < ymax; y++) {
+                       for(int x = 0; x < 80; x += width) {
+                               bool cursor = (src == caddr);
+                               uint32_t code = vram_chr[(src * 2 + 0) & 0xfff];        // low byte  : code
+                               uint8_t attr = vram_chr[(src * 2 + 1) & 0xfff]; // high byte : attr
+                               uint32_t knji = vram_chr[((src* 2 + 0) & 0xfff) | 0x1000];
+                               src++;
+                               uint8_t *pattern;
+                               
+                               if(!(knji & 0x20)) {
+                                       pattern = &kanji[((code << 4) | (knji << 12)) & 0x1ffff];
+                               } else {
+                                       pattern = &font[(code << 4) + ((config.dipswitch & 0x100) ? 0 : 8)];
+                               }
+                               
+                               // mz3500sm p.31
+                               // bit3: blink
+                               // bit2: reverse or green
+                               // bit1: horizontal line or red
+                               // bit0: vertical line or blue
+                               
+                               uint8_t color;
+                               bool vline, hline, reverse, blink;
+                               
+                               if(disp[4] & 1) {
+                                       // color mode
+                                       color = (attr & 7) ? (attr & 7) : 7;
+                                       vline = hline = reverse = false;
+                               } else {
+                                       // monocrhome mode
+                                       color = 7;
+                                       vline = ((attr & 1) != 0);
+                                       hline = ((attr & 2) != 0);
+                                       reverse = ((attr & 4) != 0);
+                               }
+                               blink = ((attr & 8) != 0 && (cblink & 0x10) != 0);
+                               reverse = (reverse != blink);
+                               
+                               // NOTE: need to consider 200 line mode
+                               
+                               for(int l = 0; l < 8; l++) {
+                                       int yy = (y * height + l) * 2;
+                                       if(yy >= 400) {
+                                               break;
+                                       }
+                                       uint8_t pat = reverse ? ~pattern[l] : pattern[l];
+                                       uint8_t *dest = &screen_chr[yy][x << 3];
+                                       
+                                       if(width == 1) {
+                                               // 8dots (80columns)
+                                               dest[0] = (pat & 0x80) ? color : 0;
+                                               dest[1] = (pat & 0x40) ? color : 0;
+                                               dest[2] = (pat & 0x20) ? color : 0;
+                                               dest[3] = (pat & 0x10) ? color : 0;
+                                               dest[4] = (pat & 0x08) ? color : 0;
+                                               dest[5] = (pat & 0x04) ? color : 0;
+                                               dest[6] = (pat & 0x02) ? color : 0;
+                                               dest[7] = (pat & 0x01) ? color : 0;
+                                       } else {
+                                               // 16dots (40columns)
+                                               dest[ 0] = dest[ 1] = (pat & 0x80) ? color : 0;
+                                               dest[ 2] = dest[ 3] = (pat & 0x40) ? color : 0;
+                                               dest[ 4] = dest[ 5] = (pat & 0x20) ? color : 0;
+                                               dest[ 6] = dest[ 7] = (pat & 0x10) ? color : 0;
+                                               dest[ 8] = dest[ 9] = (pat & 0x08) ? color : 0;
+                                               dest[10] = dest[11] = (pat & 0x04) ? color : 0;
+                                               dest[12] = dest[13] = (pat & 0x02) ? color : 0;
+                                               dest[14] = dest[15] = (pat & 0x01) ? color : 0;
+                                       }
+                               }
+                               if(vline) {
+                                       for(int l = 0; l < ((height == 8) ? 8 : 9); l++) {
+                                               int yy = (y * height + l) * 2;
+                                               if(yy >= 400) {
+                                                       break;
+                                               }
+                                               screen_chr[yy][(x << 3) + (width * 8 - 1)] = color;
+                                       }
+                               }
+                               if(hline) {
+                                       int yy = (y * height + ((height == 8) ? 7 : 8)) * 2;
+                                       if(!(yy >= 400)) {
+                                               memset(&screen_chr[yy][x << 3], color, width * 8);
+                                       }
+                               }
+                               if(cursor) {
+                                       int top = cs_chr[1] & 0x1f, bottom = cs_chr[2] >> 3;
+                                       for(int l = top; l < bottom && l < height; l++) {
+                                               int yy = (y * height + l) * 2;
+                                               if(yy >= 400) {
+                                                       break;
+                                               }
+                                               memset(&screen_chr[yy][x << 3], 7, width * 8);  // always white ???
+                                       }
+                               }
+                       }
+               }
+               ytop += len;
+       }
+}
+
+void SUB::draw_gfx_400line()
 {
+       for(int i = 0, ytop = 0; i < 4; i++) {
+               uint32_t ra = ra_gfx[4 * i];
+               ra |= ra_gfx[4 * i + 1] << 8;
+               ra |= ra_gfx[4 * i + 2] << 16;
+               ra |= ra_gfx[4 * i + 3] << 24;
+               int src = ra & 0x1fff;
+               int len = (ra >> 20) & 0x3ff;
+               
+               for(int y = ytop; y < (ytop + len) && y < 400; y++) {
+                       if(y >= 400) {
+                               break;
+                       }
+                       for(int x = 0; x < 40; x++) {
+                               uint8_t lo_b = (disp[1] & 1) ? vram_gfx[((src * 2 + 0) & 0x7fff) | 0x00000] : 0;
+                               uint8_t hi_b = (disp[1] & 1) ? vram_gfx[((src * 2 + 1) & 0x7fff) | 0x00000] : 0;
+                               uint8_t lo_r = (disp[1] & 2) ? vram_gfx[((src * 2 + 0) & 0x7fff) | 0x08000] : 0;
+                               uint8_t hi_r = (disp[1] & 2) ? vram_gfx[((src * 2 + 1) & 0x7fff) | 0x08000] : 0;
+                               uint8_t lo_g = (disp[1] & 4) ? vram_gfx[((src * 2 + 0) & 0x7fff) | 0x10000] : 0;
+                               uint8_t hi_g = (disp[1] & 4) ? vram_gfx[((src * 2 + 1) & 0x7fff) | 0x10000] : 0;
+                               src++;
+                               
+                               uint8_t *dest = &screen_gfx[y][x * 16];
+                               dest[ 0] = ((lo_b & 0x01)     ) | ((lo_r & 0x01) << 1) | ((lo_g & 0x01) << 2);
+                               dest[ 1] = ((lo_b & 0x02) >> 1) | ((lo_r & 0x02)     ) | ((lo_g & 0x02) << 1);
+                               dest[ 2] = ((lo_b & 0x04) >> 2) | ((lo_r & 0x04) >> 1) | ((lo_g & 0x04)     );
+                               dest[ 3] = ((lo_b & 0x08) >> 3) | ((lo_r & 0x08) >> 2) | ((lo_g & 0x08) >> 1);
+                               dest[ 4] = ((lo_b & 0x10) >> 4) | ((lo_r & 0x10) >> 3) | ((lo_g & 0x10) >> 2);
+                               dest[ 5] = ((lo_b & 0x20) >> 5) | ((lo_r & 0x20) >> 4) | ((lo_g & 0x20) >> 3);
+                               dest[ 6] = ((lo_b & 0x40) >> 6) | ((lo_r & 0x40) >> 5) | ((lo_g & 0x40) >> 4);
+                               dest[ 7] = ((lo_b & 0x80) >> 7) | ((lo_r & 0x80) >> 6) | ((lo_g & 0x80) >> 5);
+                               dest[ 8] = ((hi_b & 0x01)     ) | ((hi_r & 0x01) << 1) | ((hi_g & 0x01) << 2);
+                               dest[ 9] = ((hi_b & 0x02) >> 1) | ((hi_r & 0x02)     ) | ((hi_g & 0x02) << 1);
+                               dest[10] = ((hi_b & 0x04) >> 2) | ((hi_r & 0x04) >> 1) | ((hi_g & 0x04)     );
+                               dest[11] = ((hi_b & 0x08) >> 3) | ((hi_r & 0x08) >> 2) | ((hi_g & 0x08) >> 1);
+                               dest[12] = ((hi_b & 0x10) >> 4) | ((hi_r & 0x10) >> 3) | ((hi_g & 0x10) >> 2);
+                               dest[13] = ((hi_b & 0x20) >> 5) | ((hi_r & 0x20) >> 4) | ((hi_g & 0x20) >> 3);
+                               dest[14] = ((hi_b & 0x40) >> 6) | ((hi_r & 0x40) >> 5) | ((hi_g & 0x40) >> 4);
+                               dest[15] = ((hi_b & 0x80) >> 7) | ((hi_r & 0x80) >> 6) | ((hi_g & 0x80) >> 5);
+                       }
+               }
+               ytop += len;
+       }
 }
 
-#define STATE_VERSION  1
+void SUB::draw_gfx_200line_16bit()
+{
+       for(int i = 0, ytop = 0; i < 4; i++) {
+               uint32_t ra = ra_gfx[4 * i];
+               ra |= ra_gfx[4 * i + 1] << 8;
+               ra |= ra_gfx[4 * i + 2] << 16;
+               ra |= ra_gfx[4 * i + 3] << 24;
+               int src = ra & 0x1fff;
+               int len = (ra >> 20) & 0x3ff;
+               
+               for(int y = ytop; y < (ytop + len) && y < 200; y++) {
+                       if(y >= 200) {
+                               break;
+                       }
+                       for(int x = 0; x < 40; x++) {
+                               uint8_t lo_b = (disp[1] & 1) ? vram_gfx[((src * 2 + 0) & 0x7fff) | 0x00000] : 0;
+                               uint8_t hi_b = (disp[1] & 1) ? vram_gfx[((src * 2 + 1) & 0x7fff) | 0x00000] : 0;
+                               uint8_t lo_r = (disp[1] & 2) ? vram_gfx[((src * 2 + 0) & 0x7fff) | 0x08000] : 0;
+                               uint8_t hi_r = (disp[1] & 2) ? vram_gfx[((src * 2 + 1) & 0x7fff) | 0x08000] : 0;
+                               uint8_t lo_g = (disp[1] & 4) ? vram_gfx[((src * 2 + 0) & 0x7fff) | 0x10000] : 0;
+                               uint8_t hi_g = (disp[1] & 4) ? vram_gfx[((src * 2 + 1) & 0x7fff) | 0x10000] : 0;
+                               src++;
+                               
+                               uint8_t *dest = &screen_gfx[y * 2][x * 16];
+                               dest[ 0] = ((lo_b & 0x01)     ) | ((lo_r & 0x01) << 1) | ((lo_g & 0x01) << 2);
+                               dest[ 1] = ((lo_b & 0x02) >> 1) | ((lo_r & 0x02)     ) | ((lo_g & 0x02) << 1);
+                               dest[ 2] = ((lo_b & 0x04) >> 2) | ((lo_r & 0x04) >> 1) | ((lo_g & 0x04)     );
+                               dest[ 3] = ((lo_b & 0x08) >> 3) | ((lo_r & 0x08) >> 2) | ((lo_g & 0x08) >> 1);
+                               dest[ 4] = ((lo_b & 0x10) >> 4) | ((lo_r & 0x10) >> 3) | ((lo_g & 0x10) >> 2);
+                               dest[ 5] = ((lo_b & 0x20) >> 5) | ((lo_r & 0x20) >> 4) | ((lo_g & 0x20) >> 3);
+                               dest[ 6] = ((lo_b & 0x40) >> 6) | ((lo_r & 0x40) >> 5) | ((lo_g & 0x40) >> 4);
+                               dest[ 7] = ((lo_b & 0x80) >> 7) | ((lo_r & 0x80) >> 6) | ((lo_g & 0x80) >> 5);
+                               dest[ 8] = ((hi_b & 0x01)     ) | ((hi_r & 0x01) << 1) | ((hi_g & 0x01) << 2);
+                               dest[ 9] = ((hi_b & 0x02) >> 1) | ((hi_r & 0x02)     ) | ((hi_g & 0x02) << 1);
+                               dest[10] = ((hi_b & 0x04) >> 2) | ((hi_r & 0x04) >> 1) | ((hi_g & 0x04)     );
+                               dest[11] = ((hi_b & 0x08) >> 3) | ((hi_r & 0x08) >> 2) | ((hi_g & 0x08) >> 1);
+                               dest[12] = ((hi_b & 0x10) >> 4) | ((hi_r & 0x10) >> 3) | ((hi_g & 0x10) >> 2);
+                               dest[13] = ((hi_b & 0x20) >> 5) | ((hi_r & 0x20) >> 4) | ((hi_g & 0x20) >> 3);
+                               dest[14] = ((hi_b & 0x40) >> 6) | ((hi_r & 0x40) >> 5) | ((hi_g & 0x40) >> 4);
+                               dest[15] = ((hi_b & 0x80) >> 7) | ((hi_r & 0x80) >> 6) | ((hi_g & 0x80) >> 5);
+                       }
+               }
+               ytop += len;
+       }
+}
 
-void SUB::save_state(FILEIO* state_fio)
+void SUB::draw_gfx_200line_8bit()
 {
-       state_fio->FputUint32(STATE_VERSION);
-       state_fio->FputInt32(this_device_id);
-       
-       state_fio->Fwrite(ram, sizeof(ram), 1);
-       state_fio->Fwrite(vram_chr, sizeof(vram_chr), 1);
-       state_fio->Fwrite(vram_gfx, sizeof(vram_gfx), 1);
-       state_fio->Fwrite(disp, sizeof(disp), 1);
-       state_fio->FputBool(pm);
-       state_fio->FputInt32(cblink);
+       for(int i = 0, ytop = 0; i < 4; i++) {
+               uint32_t ra = ra_gfx[4 * i];
+               ra |= ra_gfx[4 * i + 1] << 8;
+               ra |= ra_gfx[4 * i + 2] << 16;
+               ra |= ra_gfx[4 * i + 3] << 24;
+               int src = ra & 0x1fff;
+               int len = (ra >> 20) & 0x3ff;
+               
+               for(int y = ytop; y < (ytop + len) && y < 200; y++) {
+                       if(y >= 200) {
+                               break;
+                       }
+                       for(int x = 0; x < 80; x++) {
+                               uint8_t b = (disp[1] & 1) ? vram_gfx[((src * 2 + 0) & 0x7fff) | 0x00000] : 0;
+                               uint8_t r = (disp[1] & 2) ? vram_gfx[((src * 2 + 1) & 0x7fff) | 0x00000] : 0;
+                               uint8_t g = (disp[1] & 4) ? vram_gfx[((src * 2 + 0) & 0x7fff) | 0x10000] : 0;
+                               src++;
+                               
+                               uint8_t *dest = &screen_gfx[y * 2][x * 8];
+                               dest[0] = ((b & 0x01)     ) | ((r & 0x01) << 1) | ((g & 0x01) << 2);
+                               dest[1] = ((b & 0x02) >> 1) | ((r & 0x02)     ) | ((g & 0x02) << 1);
+                               dest[2] = ((b & 0x04) >> 2) | ((r & 0x04) >> 1) | ((g & 0x04)     );
+                               dest[3] = ((b & 0x08) >> 3) | ((r & 0x08) >> 2) | ((g & 0x08) >> 1);
+                               dest[4] = ((b & 0x10) >> 4) | ((r & 0x10) >> 3) | ((g & 0x10) >> 2);
+                               dest[5] = ((b & 0x20) >> 5) | ((r & 0x20) >> 4) | ((g & 0x20) >> 3);
+                               dest[6] = ((b & 0x40) >> 6) | ((r & 0x40) >> 5) | ((g & 0x40) >> 4);
+                               dest[7] = ((b & 0x80) >> 7) | ((r & 0x80) >> 6) | ((g & 0x80) >> 5);
+                       }
+               }
+               ytop += len;
+       }
 }
 
-bool SUB::load_state(FILEIO* state_fio)
+#define STATE_VERSION  3
+
+bool SUB::process_state(FILEIO* state_fio, bool loading)
 {
-       if(state_fio->FgetUint32() != STATE_VERSION) {
+       if(!state_fio->StateCheckUint32(STATE_VERSION)) {
                return false;
        }
-       if(state_fio->FgetInt32() != this_device_id) {
+       if(!state_fio->StateCheckInt32(this_device_id)) {
                return false;
        }
-       state_fio->Fread(ram, sizeof(ram), 1);
-       state_fio->Fread(vram_chr, sizeof(vram_chr), 1);
-       state_fio->Fread(vram_gfx, sizeof(vram_gfx), 1);
-       state_fio->Fread(disp, sizeof(disp), 1);
-       pm = state_fio->FgetBool();
-       cblink = state_fio->FgetInt32();
+       state_fio->StateBuffer(ram, sizeof(ram), 1);
+       state_fio->StateBuffer(vram_chr, sizeof(vram_chr), 1);
+       state_fio->StateBuffer(vram_gfx, sizeof(vram_gfx), 1);
+       state_fio->StateBuffer(disp, sizeof(disp), 1);
+       state_fio->StateInt32(cblink);
+       state_fio->StateBool(crt_400line);
        return true;
 }
-