OSDN Git Service

[General] Merge Upstream 2018-12-27.
[csp-qt/common_source_project-fm7.git] / source / src / vm / pc8801 / pc88.cpp
index 32e8da6..e78c144 100644 (file)
 #include "../ym2203.h"
 #include "../z80.h"
 
+#ifdef SUPPORT_PC88_CDROM
+#include "../scsi_cdrom.h"
+#include "../scsi_host.h"
+#endif
+
 #define DEVICE_JOYSTICK        0
 #define DEVICE_MOUSE   1
 #define DEVICE_JOYMOUSE        2       // not supported yet
 #define EVENT_CMT_SEND 2
 #define EVENT_CMT_DCD  3
 #define EVENT_BEEP     4
-#define EVENT_CMT_SOUND        5
+#ifdef SUPPORT_PC88_CDROM
+#define EVENT_FADE_IN  5
+#define EVENT_FADE_OUT 6
+#endif
 
 #define IRQ_USART      0
 #define IRQ_VRTC       1
 #define IRQ_TIMER      2
 #define IRQ_SOUND      4
 
+namespace PC88DEV 
+{
+   
 #define Port30_40      !(port[0x30] & 0x01)
 #define Port30_COLOR   !(port[0x30] & 0x02)
 #define Port30_MTON    (port[0x30] & 0x08)
 #define Port31_V1_320x200      (port[0x31] & 0x10)     // PC-8001 (V1)
 #define Port31_V1_MONO         (port[0x31] & 0x04)     // PC-8001 (V1)
 
-#define Port31_COLOR   (port[0x31] & 0x10)     // PC-8001
 #define Port31_320x200 (port[0x31] & 0x04)     // PC-8001
 
 #define Port32_EROMSL  (port[0x32] & 0x03)
 #define Port32_TMODE   (port[0x32] & 0x10)
+#if !defined(_PC8001SR)
 #define Port32_PMODE   (port[0x32] & 0x20)
+#else
+#define Port32_PMODE   false
+#endif
 #define Port32_GVAM    (port[0x32] & 0x40)
 #define Port32_SINTM   (port[0x32] & 0x80)
 
 
 #define Port71_EROM    port[0x71]
 
+#ifdef SUPPORT_PC88_CDROM
+#define Port99_CDREN   (port[0x99] & 0x10)
+#endif
+
 // XM8 version 1.20
 #define PortA8_OPNCH   port[0xa8]
 #define PortAA_S2INTM  (port[0xaa] & 0x80)
 #define PortF0_DICROMSL        (port[0xf0] & 0x1f)
 #define PortF1_DICROM  !(port[0xf1] & 0x01)
 
+#if defined(SUPPORT_PC88_VAB)
+// X88000
+#define PortB4_VAB_DISP        ((port[0xb4] & 0x41) == 0x41)
+#define PortE3_VAB_SEL (((port[0xe3] >> 2) & 3) == PC88_VAB_PAGE)
+#endif
+
 #define SET_BANK(s, e, w, r) { \
        int sb = (s) >> 12, eb = (e) >> 12; \
        for(int i = sb; i <= eb; i++) { \
@@ -156,29 +180,31 @@ static const int key_table[15][8] = {
        { 0x58, 0x59, 0x5a, 0xdb, 0xdc, 0xdd, 0xde, 0xbd },
        { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37 },
        { 0x38, 0x39, 0xba, 0xbb, 0xbc, 0xbe, 0xbf, 0xe2 },
-       { 0x24, 0x26, 0x27, 0x2e, 0x12, 0x15, 0x10, 0x11 },
+//     { 0x24, 0x26, 0x27, 0x2e, 0x12, 0x15, 0x10, 0x11 },
+       { 0x24, 0x26, 0x27, 0x08, 0x12, 0x15, 0x10, 0x11 },
        { 0x13, 0x70, 0x71, 0x72, 0x73, 0x74, 0x20, 0x1b },
        { 0x09, 0x28, 0x25, 0x23, 0x7b, 0x6d, 0x6f, 0x14 },
        { 0x21, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
        { 0x75, 0x76, 0x77, 0x78, 0x79, 0x08, 0x2d, 0x2e },
-       { 0x1c, 0x1d, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00 },
+       { 0x1c, 0x1d, 0x7a, 0x19, 0x00, 0x00, 0x00, 0x00 },
        { 0x0d, 0x00, 0xa0, 0xa1, 0x00, 0x00, 0x00, 0x00 }
 };
 
-static const int key_conv_table[9][3] = {
+static const int key_conv_table[][3] = {
        {0x2d, 0x2e, 1}, // INS -> SHIFT + DEL
        {0x75, 0x70, 1}, // F6  -> SHIFT + F1
        {0x76, 0x71, 1}, // F7  -> SHIFT + F2
        {0x77, 0x72, 1}, // F8  -> SHIFT + F3
        {0x78, 0x73, 1}, // F9  -> SHIFT + F4
        {0x79, 0x74, 1}, // F10 -> SHIFT + F5
-       {0x08, 0x2e, 0}, // BS  -> DEL
+//     {0x08, 0x2e, 0}, // BS  -> DEL
+       {0x2e, 0x08, 0}, // DEL -> BS
        {0x1c, 0x20, 0}, // \95Ï\8a·-> SPACE
        {0x1d, 0x20, 0}, // \8c\88\92è-> SPACE
 };
 
-static const uint8 intr_mask2_table[8] = {
-       ~7, ~3, ~5, ~1, ~6, ~2, ~4, ~0
+static const uint8_t intr_mask2_table[8] = {
+       (uint8_t)~7, (uint8_t)~3, (uint8_t)~5, (uint8_t)~1, (uint8_t)~6, (uint8_t)~2, (uint8_t)~4, (uint8_t)~0
 };
 
 void PC88::initialize()
@@ -204,6 +230,10 @@ void PC88::initialize()
 #ifdef SUPPORT_PC88_DICTIONARY
        memset(dicrom, 0xff, sizeof(dicrom));
 #endif
+#ifdef SUPPORT_PC88_CDROM
+       memset(cdbios, 0xff, sizeof(cdbios));
+       cdbios_loaded = false;
+#endif
        
        // load rom images
        FILEIO* fio = new FILEIO();
@@ -265,12 +295,21 @@ void PC88::initialize()
                fio->Fclose();
        }
 #endif
+#ifdef SUPPORT_PC88_CDROM
+       if(config.boot_mode == MODE_PC88_V2) {
+               if(fio->Fopen(create_local_path(_T("CDBIOS.ROM")), FILEIO_READ_BINARY)) {
+                       fio->Fread(cdbios, 0x10000, 1);
+                       fio->Fclose();
+                       cdbios_loaded = true;
+               }
+       }
+#endif
        delete fio;
        
        // memory pattern
        for(int i = 0, ofs = 0; i < 256; i++) {
                for(int j = 0; j < 16; j++) {
-                       static const uint8 p0[256] = {
+                       static const uint8_t p0[256] = {
                                0,1,0,1,0,1,0,0,0,0,0,0,1,0,1,0, // 0000
                                0,1,0,1,0,1,0,0,0,0,1,0,1,0,1,0, // 1000
                                0,1,0,1,0,0,0,0,0,0,1,0,1,0,1,0, // 2000
@@ -288,7 +327,7 @@ void PC88::initialize()
                                0,1,0,1,0,1,0,0,0,0,1,0,1,0,1,0, // e000
                                0,1,0,1,0,0,0,0,0,0,1,0,1,0,1,0, // f000
                        };
-                       static const uint8 p1[16] = {
+                       static const uint8_t p1[16] = {
                                0x00,0xff,0x00,0xff,0xff,0x00,0xff,0x00,0x00,0xff,0x00,0xff,0xff,0x00,0xff,0x00,
                        };
                        memset(ram + ofs, (p0[i] == 0) ? p1[j] : ~p1[j], 16);
@@ -298,17 +337,26 @@ void PC88::initialize()
        
        // create semi graphics pattern
        for(int i = 0; i < 256; i++) {
-               uint8 *dest = sg_pattern + 8 * i;
+               uint8_t *dest = sg_pattern + 8 * i;
                dest[0] = dest[1] = ((i & 1) ? 0xf0 : 0) | ((i & 0x10) ? 0x0f : 0);
                dest[2] = dest[3] = ((i & 2) ? 0xf0 : 0) | ((i & 0x20) ? 0x0f : 0);
                dest[4] = dest[5] = ((i & 4) ? 0xf0 : 0) | ((i & 0x40) ? 0x0f : 0);
                dest[6] = dest[7] = ((i & 8) ? 0xf0 : 0) | ((i & 0x80) ? 0x0f : 0);
        }
        
-       // initialize text palette
-       for(int i = 0; i < 9; i++) {
-               palette_text_pc[i] = RGBA_COLOR((i & 2) ? 255 : 0, (i & 4) ? 255 : 0, (i & 1) ? 255 : 0, 255); // A is a flag for crt filter
+#ifdef SUPPORT_PC88_VAB
+       // X88000
+       for(uint32_t g = 0; g < 64; g++) {
+               uint32_t gg = (255 * g) / 63;
+               for(uint32_t r = 0; r < 32; r++) {
+                       uint32_t rr = (255 * r) / 31;
+                       for(uint32_t b = 0; b < 32; b++) {
+                               uint32_t bb = (255 * b) / 31;
+                               palette_vab_pc[b | (r << 5) | (g << 10)] = RGB_COLOR(rr, gg, bb);
+                       }
+               }
        }
+#endif
        
 #ifdef SUPPORT_PC88_HIGH_CLOCK
        cpu_clock_low = (config.cpu_type == 1);         // 4MHz
@@ -318,32 +366,27 @@ void PC88::initialize()
 #endif
        
 #ifdef SUPPORT_PC88_JOYSTICK
-       joystick_status = emu->joy_buffer();
-       mouse_status = emu->mouse_buffer();
+       joystick_status = emu->get_joy_buffer();
+       mouse_status = emu->get_mouse_buffer();
        mouse_strobe_clock_lim = (int)((cpu_clock_low ? 720 : 1440) * 1.25);
 #endif
        
        // initialize cmt
        cmt_fio = new FILEIO();
        cmt_play = cmt_rec = false;
-#ifdef DATAREC_SOUND
-       cmt_mix = config.tape_sound;
-#ifdef USE_MULTIPLE_SOUNDCARDS
-       cmt_volume = (config.sound_device_level[0] + 0x8000) >> 2;
-       if(cmt_volume <= 0) cmt_volume = 0;
-       if(cmt_volume >= 0x4000) cmt_volume = 0;
-#else
-       cmt_volume = 0x1000;
-#endif
-       cmt_level_flag = false;
-       cmt_sound_flag = false;
-       cmt_sound_count = 0;
-       cmt_sound_data = 0;
-#endif
+       
        register_frame_event(this);
        register_vline_event(this);
        register_event(this, EVENT_TIMER, 1000000.0 / 600.0, true, NULL);
        register_event(this, EVENT_BEEP, 1000000.0 / 4800.0, true, NULL);
+       
+#if !defined(_PC8001SR)
+       // hack to update config.scan_line at first
+       hireso = !(config.monitor_type == 0);
+#endif
+#ifdef SUPPORT_PC88_CDROM
+       cdda_register_id = -1;
+#endif
 }
 
 void PC88::release()
@@ -357,7 +400,12 @@ void PC88::reset()
 #if defined(_PC8001SR)
        hireso = false;
 #else
-       hireso = (config.monitor_type == 0);
+       bool value = (config.monitor_type == 0);
+       if(hireso != value) {
+               // update config.scan_line when config.monitor_type is changed
+               //hireso = config.scan_line = value;
+               hireso = value; // Revert 20181217 K.O
+       }
 #endif
        
        // memory
@@ -369,7 +417,11 @@ void PC88::reset()
        }
 //     port[0x70] = 0x80;      // XM8 version 1.10
        port[0x71] = port[0xf1] = 0xff;
-       
+#if defined(SUPPORT_PC88_CDROM)
+       if (cdbios_loaded) {
+               port[0x99]  = 0x10;
+       }
+#endif
        memset(alu_reg, 0, sizeof(alu_reg));
        gvram_plane = gvram_sel = 0;
        
@@ -382,8 +434,9 @@ void PC88::reset()
        }
        SET_BANK(0x8000, 0xffff, ram + 0x8000, ram + 0x8000);
 #else
-       SET_BANK(0x0000, 0x7fff, ram, n88rom);
+//     SET_BANK(0x0000, 0x7fff, ram, n88rom);
        SET_BANK(0x8000, 0xefff, ram + 0x8000, ram + 0x8000);
+       update_low_memmap();
        update_tvram_memmap();  // XM8 version 1.10
 #endif
        
@@ -406,7 +459,8 @@ void PC88::reset()
        crtc.reset(hireso);
        update_timing();
        
-       for(int i = 0; i < 9; i++) {
+       memset(palette, 0, sizeof(palette));
+       for(int i = 1; i < 8; i++) {
                palette[i].b = (i & 1) ? 7 : 0;
                palette[i].r = (i & 2) ? 7 : 0;
                palette[i].g = (i & 4) ? 7 : 0;
@@ -415,8 +469,14 @@ void PC88::reset()
        
        // dma
        memset(&dmac, 0, sizeof(dmac));
-       dmac.mem = dmac.ch[2].io = this;
-       dmac.ch[0].io = dmac.ch[1].io = dmac.ch[3].io = vm->dummy;
+       dmac.ch[0].io = dmac.ch[3].io = vm->dummy;
+#ifdef SUPPORT_PC88_CDROM
+       if(cdbios_loaded) {
+               dmac.ch[1].io = d_scsi_host;
+       } else
+#endif
+       dmac.ch[1].io = vm->dummy;;
+       dmac.ch[2].io = dmac.mem = this;
        dmac.ch[0].addr.b.l = 0x56;     // XM8 version 1.10
        dmac.ch[0].addr.b.h = 0x56;
        dmac.ch[1].addr.b.l = 0x7a;
@@ -427,7 +487,7 @@ void PC88::reset()
        
        // mouse
 #ifdef SUPPORT_PC88_JOYSTICK
-       mouse_strobe_clock = current_clock();
+       mouse_strobe_clock = get_current_clock();
        mouse_phase = -1;
        mouse_dx = mouse_dy = mouse_lx = mouse_ly = 0;
 #endif
@@ -458,13 +518,21 @@ void PC88::reset()
        write_io8(2, 0);
        write_io8(3, 0);
 #endif
+#ifdef SUPPORT_PC88_CDROM
+       if(cdda_register_id != -1) {
+               cancel_event(this, cdda_register_id);
+               cdda_register_id = -1;
+       }
+       cdda_volume = 100.0;
+       d_scsi_cdrom->set_volume((int)cdda_volume);
+#endif
 #ifdef NIPPY_PATCH
        // dirty patch for NIPPY
        nippy_patch = false;
 #endif
 }
 
-void PC88::write_data8w(uint32 addr, uint32 data, int* wait)
+void PC88::write_data8w(uint32_t addr, uint32_t data, int* wait)
 {
        addr &= 0xffff;
        *wait = mem_wait_clocks_w;
@@ -537,7 +605,7 @@ void PC88::write_data8w(uint32 addr, uint32 data, int* wait)
        wbank[addr >> 12][addr & 0xfff] = data;
 }
 
-uint32 PC88::read_data8w(uint32 addr, int* wait)
+uint32_t PC88::read_data8w(uint32_t addr, int* wait)
 {
        addr &= 0xffff;
        *wait = mem_wait_clocks_r;
@@ -553,7 +621,7 @@ uint32 PC88::read_data8w(uint32 addr, int* wait)
 #else
        if((addr & 0xc000) == 0x8000) {
 #endif
-               uint8 b, r, g;
+               uint8_t b, r, g;
                switch(gvram_sel) {
                case 1:
                        *wait = gvram_wait_clocks_r;
@@ -590,9 +658,9 @@ uint32 PC88::read_data8w(uint32 addr, int* wait)
        return rbank[addr >> 12][addr & 0xfff];
 }
 
-uint32 PC88::fetch_op(uint32 addr, int *wait)
+uint32_t PC88::fetch_op(uint32_t addr, int *wait)
 {
-       uint32 data = read_data8w(addr, wait);
+       uint32_t data = read_data8w(addr, wait);
        if((addr & 0xf000) == 0xf000) {
                *wait += f000_m1_wait_clocks;
        } else {
@@ -601,11 +669,11 @@ uint32 PC88::fetch_op(uint32 addr, int *wait)
        return data;
 }
 
-void PC88::write_io8(uint32 addr, uint32 data)
+void PC88::write_io8(uint32_t addr, uint32_t data)
 {
        addr &= 0xff;
 #ifdef _IO_DEBUG_LOG
-       emu->out_debug_log(_T("%6x\tOUT8\t%02x,%02x\n"), d_cpu->get_pc(), addr, data);
+       this->out_debug_log(_T("%06x\tOUT8\t%02x,%02x\n"), d_cpu->get_pc(), addr, data);
 #endif
 #ifdef NIPPY_PATCH
        // dirty patch for NIPPY
@@ -614,7 +682,7 @@ void PC88::write_io8(uint32 addr, uint32 data)
        }
        // poke &haa4e, &h39
 #endif
-       uint8 mod = port[addr] ^ data;
+       uint8_t mod = port[addr] ^ data;
        port[addr] = data;
        
        switch(addr) {
@@ -676,7 +744,7 @@ void PC88::write_io8(uint32 addr, uint32 data)
 #endif
                break;
        case 0x10:
-               emu->printer_out(data);
+               d_prn->write_signal(SIG_PRINTER_DATA, data, 0xff);
                d_rtc->write_signal(SIG_UPD1990A_C0, data, 1);
                d_rtc->write_signal(SIG_UPD1990A_C1, data, 2);
                d_rtc->write_signal(SIG_UPD1990A_C2, data, 4);
@@ -754,6 +822,7 @@ void PC88::write_io8(uint32 addr, uint32 data)
                }
                if(mod & 0x08) {
                        update_gvram_wait();
+                       update_palette = true;
                }
                if(mod & 0x11) {
                        update_timing();
@@ -766,7 +835,7 @@ void PC88::write_io8(uint32 addr, uint32 data)
                break;
        case 0x32:
                if(mod & 0x03) {
-                       if(Port71_EROM == 0xfe) {
+                       if(!(Port71_EROM & 1)) {
                                update_low_memmap();
                        }
                }
@@ -793,7 +862,7 @@ void PC88::write_io8(uint32 addr, uint32 data)
                }
                break;
        case 0x40:
-               emu->printer_strobe((data & 1) == 0);
+               d_prn->write_signal(SIG_PRINTER_STROBE, data, 1);
                d_rtc->write_signal(SIG_UPD1990A_STB, ~data, 2);
                d_rtc->write_signal(SIG_UPD1990A_CLK, data, 4);
                // bit3: crtc i/f sync mode
@@ -803,7 +872,7 @@ void PC88::write_io8(uint32 addr, uint32 data)
                beep_on = ((data & 0x20) != 0);
 #ifdef SUPPORT_PC88_JOYSTICK
                if(mod & 0x40) {
-                       if(Port40_JOP1 && (mouse_phase == -1 || passed_clock(mouse_strobe_clock) > mouse_strobe_clock_lim)) {
+                       if(Port40_JOP1 && (mouse_phase == -1 || get_passed_clock(mouse_strobe_clock) > mouse_strobe_clock_lim)) {
                                mouse_phase = 0;//mouse_dx = mouse_dy = 0;
                        } else {
                                mouse_phase = (mouse_phase + 1) & 3;
@@ -814,7 +883,7 @@ void PC88::write_io8(uint32 addr, uint32 data)
                                mouse_ly = -((mouse_dy > 127) ? 127 : (mouse_dy < -127) ? -127 : mouse_dy);
                                mouse_dx = mouse_dy = 0;
                        }
-                       mouse_strobe_clock = current_clock();
+                       mouse_strobe_clock = get_current_clock();
                }
 #endif
                sing_signal = ((data & 0x80) != 0);
@@ -860,7 +929,7 @@ void PC88::write_io8(uint32 addr, uint32 data)
        case 0x5b:
 #if !defined(_PC8001SR)
                if(Port32_PMODE) {
-                       int n = (data & 0x80) ? 8 : (addr - 0x54);
+                       int n = (data & 0x80) ? 9 : (addr - 0x54);
                        if(data & 0x40) {
                                palette[n].g = data & 7;
                        } else {
@@ -933,13 +1002,99 @@ void PC88::write_io8(uint32 addr, uint32 data)
                break;
 #else
        case 0x71:
-               if(mod) {
+               if(mod & 0x01) {
                        update_low_memmap();
                }
                break;
        case 0x78:
                Port70_TEXTWND++;
                break;
+#ifdef SUPPORT_PC88_HMB20
+       case 0x88:
+       case 0x89:
+               d_opm->write_io8(addr, data);
+               break;
+#endif
+#ifdef SUPPORT_PC88_CDROM
+       // M88 cdif
+       case 0x90:
+               if(cdbios_loaded && (mod & 0x01)) {
+                       if(data & 0x01) {
+                               if(port[0x9f] & 0x01) {
+                                       d_scsi_host->write_signal(SIG_SCSI_SEL, 0, 1);
+                                       d_scsi_host->write_signal(SIG_SCSI_SEL, 1, 1);
+                                       d_scsi_host->write_signal(SIG_SCSI_SEL, 0, 1);
+                               }
+                       } else {
+                               d_scsi_host->write_signal(SIG_SCSI_SEL, 0, 1);
+                       }
+//                     d_scsi_host->write_signal(SIG_SCSI_SEL, data, 1);
+               }
+               break;
+       case 0x91:
+               if(cdbios_loaded) {
+                       d_scsi_host->write_dma_io8(0, data);
+               }
+               break;
+       case 0x94:
+               if(cdbios_loaded) {
+                       d_scsi_host->write_signal(SIG_SCSI_RST, data, 0x80);
+               }
+               break;
+       case 0x98:
+               if(cdbios_loaded) {
+                       switch(data & 7) {
+                       case 0:
+                       case 1:
+                               if(cdda_register_id != -1) {
+                                       cancel_event(this, cdda_register_id);
+                               }
+                               d_scsi_cdrom->set_volume((int)(cdda_volume = 100.0));
+                               break;
+                       case 2:
+                       case 3:
+                               if(cdda_register_id != -1) {
+                                       cancel_event(this, cdda_register_id);
+                               }
+                               d_scsi_cdrom->set_volume((int)(cdda_volume = 0.0));
+                               break;
+                       case 4:
+                               if(cdda_register_id != -1) {
+                                       cancel_event(this, cdda_register_id);
+                               }
+                               register_event(this, EVENT_FADE_IN, 100, true, &cdda_register_id); // 100ms
+                               d_scsi_cdrom->set_volume((int)(cdda_volume = 0.0));
+                               break;
+                       case 5:
+                               if(cdda_register_id != -1) {
+                                       cancel_event(this, cdda_register_id);
+                               }
+                               register_event(this, EVENT_FADE_IN, 1500, true, &cdda_register_id); // 1500ms
+                               d_scsi_cdrom->set_volume((int)(cdda_volume = 0.0));
+                               break;
+                       case 6:
+                               if(cdda_register_id != -1) {
+                                       cancel_event(this, cdda_register_id);
+                               }
+                               register_event(this, EVENT_FADE_OUT, 100, true, &cdda_register_id); // 100ms
+                               d_scsi_cdrom->set_volume((int)(cdda_volume = 100.0));
+                               break;
+                       case 7:
+                               if(cdda_register_id != -1) {
+                                       cancel_event(this, cdda_register_id);
+                               }
+                               register_event(this, EVENT_FADE_OUT, 5000, true, &cdda_register_id); // 5000ms
+                               d_scsi_cdrom->set_volume((int)(cdda_volume = 100.0));
+                               break;
+                       }
+               }
+               break;
+       case 0x99:
+               if(cdbios_loaded && (mod & 0x10)) {
+                       update_low_memmap();
+               }
+               break;
+#endif
 #ifdef SUPPORT_PC88_SB2
        case 0xa8:
        case 0xa9:
@@ -969,8 +1124,14 @@ void PC88::write_io8(uint32 addr, uint32 data)
                }
                break;
        case 0xe3:
+#ifdef PC88_IODATA_EXRAM
                if(mod) {
-                       update_low_memmap();
+#else
+               if(mod & 0x0f) {
+#endif
+                       if(PortE2_RDEN || PortE2_WREN) {
+                               update_low_memmap();
+                       }
                }
                break;
 #endif
@@ -1012,18 +1173,18 @@ void PC88::write_io8(uint32 addr, uint32 data)
        }
 }
 
-uint32 PC88::read_io8(uint32 addr)
+uint32_t PC88::read_io8(uint32_t addr)
 #ifdef _IO_DEBUG_LOG
 {
-       uint32 val = read_io8_debug(addr);
-       emu->out_debug_log(_T("%06x\tIN8\t%02x = %02x\n"), d_cpu->get_pc(), addr & 0xff, val);
+       uint32_t val = read_io8_debug(addr);
+       this->out_debug_log(_T("%06x\tIN8\t%02x = %02x\n"), d_cpu->get_pc(), addr & 0xff, val);
        return val;
 }
 
-uint32 PC88::read_io8_debug(uint32 addr)
+uint32_t PC88::read_io8_debug(uint32_t addr)
 #endif
 {
-       uint32 val = 0xff;
+       uint32_t val = 0xff;
        
        addr &= 0xff;
        switch(addr) {
@@ -1074,8 +1235,8 @@ uint32 PC88::read_io8_debug(uint32 addr)
 #endif
        case 0x40:
                // XM8 version 1.10
-               return (crtc.vblank ? 0x20 : 0) | (d_rtc->read_signal(0) ? 0x10 : 0) | (usart_dcd ? 4 : 0) | (hireso ? 0 : 2) | 0xc1;
-//             return (crtc.vblank ? 0x20 : 0) | (d_rtc->read_signal(0) ? 0x10 : 0) | (usart_dcd ? 4 : 0) | (hireso ? 0 : 2) | 0xc0;
+//             return (crtc.vblank ? 0x20 : 0) | (d_rtc->read_signal(0) ? 0x10 : 0) | (usart_dcd ? 4 : 0) | (hireso ? 0 : 2) | 0xc1;
+               return (crtc.vblank ? 0x20 : 0) | (d_rtc->read_signal(0) ? 0x10 : 0) | (usart_dcd ? 4 : 0) | (hireso ? 0 : 2) | (d_prn->read_signal(SIG_PRINTER_BUSY) ? 1 : 0) | 0xc0;
        case 0x44:
                val = d_opn->read_io8(addr);
                if(opn_busy) {
@@ -1089,9 +1250,9 @@ uint32 PC88::read_io8_debug(uint32 addr)
        case 0x45:
                if(Port44_OPNCH == 14) {
 #ifdef SUPPORT_PC88_JOYSTICK
-                       if(config.device_type == DEVICE_JOYSTICK) {
+                       if(config.joystick_type == DEVICE_JOYSTICK) {
                                return (~(joystick_status[0] >> 0) & 0x0f) | 0xf0;
-                       } else if(config.device_type == DEVICE_MOUSE) {
+                       } else if(config.joystick_type == DEVICE_MOUSE) {
                                switch(mouse_phase) {
                                case 0:
                                        return ((mouse_lx >> 4) & 0x0f) | 0xf0;
@@ -1108,9 +1269,9 @@ uint32 PC88::read_io8_debug(uint32 addr)
                        return 0xff;
                } else if(Port44_OPNCH == 15) {
 #ifdef SUPPORT_PC88_JOYSTICK
-                       if(config.device_type == DEVICE_JOYSTICK) {
+                       if(config.joystick_type == DEVICE_JOYSTICK) {
                                return (~(joystick_status[0] >> 4) & 0x03) | 0xfc;
-                       } else if(config.device_type == DEVICE_MOUSE) {
+                       } else if(config.joystick_type == DEVICE_MOUSE) {
                                return (~mouse_status[2] & 0x03) | 0xfc;
                        }
 #endif
@@ -1155,6 +1316,62 @@ uint32 PC88::read_io8_debug(uint32 addr)
 #endif
        case 0x71:
                return port[0x71];
+#ifdef SUPPORT_PC88_HMB20
+//     case 0x88:
+       case 0x89:
+               return d_opm->read_io8(addr);
+#endif
+#ifdef SUPPORT_PC88_CDROM
+       // M88 cdif
+       case 0x90:
+               if(cdbios_loaded) {
+                       val  = d_scsi_host->read_signal(SIG_SCSI_BSY) ? 0x80 : 0;
+                       val |= d_scsi_host->read_signal(SIG_SCSI_REQ) ? 0x40 : 0;
+                       val |= d_scsi_host->read_signal(SIG_SCSI_MSG) ? 0x20 : 0;
+                       val |= d_scsi_host->read_signal(SIG_SCSI_CD ) ? 0x10 : 0;
+                       val |= d_scsi_host->read_signal(SIG_SCSI_IO ) ? 0x08 : 0;
+                       // do not show BSY,MSG,CxD,IxD when SEL=1 (\90M\92·\82Ì\96ì\96\95\90\8f«\95\97\89_\98^)
+                       if(port[0x90] & 0x01) {
+                               val &= ~(0x80 | 0x20 | 0x10 | 0x08);
+                               val |= (port[0x9f] & 0x01); // correct ???
+                       }
+                       #ifdef _SCSI_DEBUG_LOG
+                               this->out_debug_log(_T("[SCSI_PC88] Status = %02X\n"), val);
+                       #endif
+                       return val;
+               }
+               break;
+       case 0x91:
+               if(cdbios_loaded) {
+                       return d_scsi_host->read_dma_io8(0);
+               }
+               break;
+       case 0x92:
+       case 0x93:
+       case 0x96:
+               if(cdbios_loaded) {
+                       return 0x00;
+               }
+               break;
+       case 0x99:
+               if(cdbios_loaded) {
+//                     return 0xcd; // PC-8801MC
+                       return 0x00;
+               }
+               break;
+       case 0x98:
+               if(cdbios_loaded) {
+                       port[0x98] ^= 0x80; // clock ???
+                       return port[0x98];
+               }
+               break;
+       case 0x9b:
+       case 0x9d:
+               if(cdbios_loaded) {
+                       return 60;
+               }
+               break;
+#endif
 #ifdef SUPPORT_PC88_SB2
        case 0xa8:
                if(d_sb2 != NULL) {
@@ -1165,9 +1382,9 @@ uint32 PC88::read_io8_debug(uint32 addr)
                if(d_sb2 != NULL) {
                        if(PortA8_OPNCH == 14) {
 #ifdef SUPPORT_PC88_JOYSTICK
-                               if(config.device_type == DEVICE_JOYSTICK) {
+                               if(config.joystick_type == DEVICE_JOYSTICK) {
                                        return (~(joystick_status[0] >> 0) & 0x0f) | 0xf0;
-                               } else if(config.device_type == DEVICE_MOUSE) {
+                               } else if(config.joystick_type == DEVICE_MOUSE) {
                                        switch(mouse_phase) {
                                        case 0:
                                                return ((mouse_lx >> 4) & 0x0f) | 0xf0;
@@ -1184,9 +1401,9 @@ uint32 PC88::read_io8_debug(uint32 addr)
                                return 0xff;
                        } else if(PortA8_OPNCH == 15) {
 #ifdef SUPPORT_PC88_JOYSTICK
-                               if(config.device_type == DEVICE_JOYSTICK) {
+                               if(config.joystick_type == DEVICE_JOYSTICK) {
                                        return (~(joystick_status[0] >> 4) & 0x03) | 0xfc;
-                               } else if(config.device_type == DEVICE_MOUSE) {
+                               } else if(config.joystick_type == DEVICE_MOUSE) {
                                        return (~mouse_status[2] & 0x03) | 0xfc;
                                }
 #endif
@@ -1206,6 +1423,15 @@ uint32 PC88::read_io8_debug(uint32 addr)
                break;
 #endif
 #endif
+#if defined(SUPPORT_PC88_VAB)
+       // X88000
+       case 0xb4:
+       case 0xb5:
+               if(PortE3_VAB_SEL) {
+                       return port[addr];
+               }
+               break;
+#endif
        case 0xe2:
                return (~port[0xe2]) | 0xee;
        case 0xe3:
@@ -1230,8 +1456,9 @@ uint32 PC88::read_io8_debug(uint32 addr)
        return 0xff;
 }
 
-uint32 PC88::read_dma_data8(uint32 addr)
+uint32_t PC88::read_dma_data8(uint32_t addr)
 {
+       // from ram
 #if defined(_PC8001SR)
        return ram[addr & 0xffff];
 #else
@@ -1243,7 +1470,13 @@ uint32 PC88::read_dma_data8(uint32 addr)
 #endif
 }
 
-void PC88::write_dma_io8(uint32 addr, uint32 data)
+void PC88::write_dma_data8(uint32_t addr, uint32_t data)
+{
+       // to ram
+       ram[addr & 0xffff] = data;
+}
+
+void PC88::write_dma_io8(uint32_t addr, uint32_t data)
 {
        // to crtc
        crtc.write_buffer(data);
@@ -1510,25 +1743,31 @@ void PC88::update_low_memmap()
                        SET_BANK_R(0x0000, 0x7fff, exram + 0x8000 * PortE3_ERAMSL);
                } else {
 #endif
-                       SET_BANK_R(0x0000, 0x7fff, rdmy);
+//                     SET_BANK_R(0x0000, 0x7fff, rdmy);
 #ifdef PC88_EXRAM_BANKS
                }
 #endif
        } else if(Port31_MMODE) {
                // 64K RAM
                SET_BANK_R(0x0000, 0x7fff, ram);
+#ifdef SUPPORT_PC88_CDROM
+       } else if(cdbios_loaded && Port99_CDREN) {
+               if(Port31_RMODE) {
+                       SET_BANK_R(0x0000, 0x7fff, cdbios + 0x8000);
+               } else {
+                       SET_BANK_R(0x0000, 0x7fff, cdbios + 0x0000);
+               }
+#endif
        } else if(Port31_RMODE) {
                // N-BASIC
                SET_BANK_R(0x0000, 0x7fff, n80rom);
        } else {
                // N-88BASIC
                SET_BANK_R(0x0000, 0x5fff, n88rom);
-               if(Port71_EROM == 0xff) {
+               if(Port71_EROM & 1) {
                        SET_BANK_R(0x6000, 0x7fff, n88rom + 0x6000);
-               } else if(Port71_EROM == 0xfe) {
-                       SET_BANK_R(0x6000, 0x7fff, n88exrom + 0x2000 * Port32_EROMSL);
                } else {
-                       SET_BANK_R(0x6000, 0x7fff, rdmy);
+                       SET_BANK_R(0x6000, 0x7fff, n88exrom + 0x2000 * Port32_EROMSL);
                }
        }
        
@@ -1539,7 +1778,8 @@ void PC88::update_low_memmap()
                        SET_BANK_W(0x0000, 0x7fff, exram + 0x8000 * PortE3_ERAMSL);
                } else {
 #endif
-                       SET_BANK_W(0x0000, 0x7fff, wdmy);
+//                     SET_BANK_W(0x0000, 0x7fff, wdmy);
+                       SET_BANK_W(0x0000, 0x7fff, ram);
 #ifdef PC88_EXRAM_BANKS
                }
 #endif
@@ -1559,7 +1799,7 @@ void PC88::update_tvram_memmap()
 }
 #endif
 
-void PC88::write_signal(int id, uint32 data, uint32 mask)
+void PC88::write_signal(int id, uint32_t data, uint32_t mask)
 {
        if(id == SIG_PC88_USART_IRQ) {
                request_intr(IRQ_USART, ((data & mask) != 0));
@@ -1579,6 +1819,17 @@ void PC88::write_signal(int id, uint32 data, uint32 mask)
                        request_intr(IRQ_SOUND, true);
                }
 #endif
+#ifdef SUPPORT_PC88_CDROM
+       } else if(id == SIG_PC88_SCSI_DRQ) {
+               if((data & mask) && cdbios_loaded) {
+                       if(!dmac.ch[1].running) {
+                               dmac.start(1);
+                       }
+                       if(dmac.ch[1].running) {
+                               dmac.run(1, 1);
+                       }
+               }
+#endif
        } else if(id == SIG_PC88_USART_OUT) {
                // recv from sio
                if(Port30_CMT) {
@@ -1594,61 +1845,8 @@ void PC88::write_signal(int id, uint32 data, uint32 mask)
                        // send to rs-232c
                }
        }
-#ifdef DATAREC_SOUND
-       else if(id == SIG_PC88_DATAREC_MIX) {
-               if((data & mask) != 0) {
-                       cmt_mix = true;
-               } else {
-                       cmt_mix = false;
-               }
-       } else if(id == SIG_PC88_DATAREC_VOLUME) {
-               if(data >= 0x4000) {
-                       cmt_volume = 0x4000;
-               } else {
-                       cmt_volume = data;
-               }
-       }
-#endif
 }
 
-void PC88::update_config(void)
-{
-#if defined(DATAREC_SOUND) && defined(USE_MULTIPLE_SOUNDCARDS)
-       int vv;
-       cmt_mix = config.tape_sound;
-       vv = (config.sound_device_level[0] + 0x8000) >> 2;
-       if(vv >= 0x4000) {
-               cmt_volume = 0x4000;
-       } else if(vv <= 0) {
-               cmt_volume = 0;
-       } else {
-               cmt_volume = vv;
-       }
-#endif
-}
-#ifdef DATAREC_SOUND
-void PC88::mix(int32* buffer, int cnt)
-{
-       int vol = 0;
-       if(!cmt_mix) return;
-       if(cmt_play || cmt_rec) {
-               if(cmt_level_flag) {
-                       vol =  cmt_volume;
-               } else {
-                       vol = -cmt_volume;
-               }
-               if(!cmt_sound_flag) vol = 0;  
-       } else {
-               return;
-       }
-       for(int i = 0; i < cnt; i++) {
-               *buffer++ += vol;
-               *buffer++ += vol;
-       }
-}
-#endif
-
 void PC88::event_callback(int event_id, int err)
 {
        switch(event_id) {
@@ -1671,85 +1869,47 @@ void PC88::event_callback(int event_id, int err)
        case EVENT_CMT_DCD:
                // send data to sio
                usart_dcd = false;
-#ifdef DATAREC_SOUND
-               cmt_sound_data = cmt_buffer[cmt_bufptr];
-               cmt_sound_count = 0;
-               cmt_local_count = 0;
-#endif
-#ifdef DATAREC_SOUND
-               register_event(this, EVENT_CMT_SOUND, 1000000.0 / 4800.0, false, NULL);
-#endif
                if(cmt_play && cmt_bufptr < cmt_bufcnt && Port30_MTON) {
                        d_sio->write_signal(SIG_I8251_RECV, cmt_buffer[cmt_bufptr++], 0xff);
                        if(cmt_bufptr < cmt_bufcnt) {
                                register_event(this, EVENT_CMT_SEND, 5000, false, &cmt_register_id);
                                break;
                        }
-               } else {
-#ifdef DATAREC_SOUND
-                 //cmt_level_flag = false;
-                 //cmt_sound_flag = false;
-#endif
                }
                usart_dcd = true; // Jackie Chan no Spartan X
                cmt_register_id = -1;
                break;
-       case EVENT_CMT_SOUND:
-#ifdef DATAREC_SOUND
-               if(cmt_sound_count < 8) {
-                       if((cmt_sound_data & 0x80) != 0) {
-                               cmt_sound_flag = true;
-                               cmt_level_flag = ((cmt_local_count & 0x01) != 0);
-                               if(cmt_local_count & 0x01 != 0) {
-                                       cmt_sound_data <<= 1;
-                                       cmt_sound_count++;
-                                       cmt_local_count = 0;
-                               }
-                       } else {
-                               cmt_sound_flag = true;
-                               cmt_level_flag = ((cmt_local_count & 0x02) != 0);
-                               if((cmt_local_count & 0x03) == 3) {
-                                       cmt_sound_data <<= 1; 
-                                       cmt_sound_count++;
-                                       cmt_local_count = 0;
-                               }
-                       }
-                       cmt_local_count++;
-                       register_event(this, EVENT_CMT_SOUND, 1000000.0 / 4800.0, false, NULL);
-               } else if(cmt_sound_count < 11) {
-                       // STOP BIT = 1.5
-                       cmt_sound_flag = true;
-                       cmt_level_flag = true;
-                       cmt_sound_count++;
-                       register_event(this, EVENT_CMT_SOUND, 1000000.0 / 4800.0, false, NULL);
-                       
-               } else if(cmt_sound_count == 12) {
-                       // Fall down
-                       cmt_sound_flag = true;
-                       cmt_level_flag = false;
-                       cmt_sound_count++;
-                       register_event(this, EVENT_CMT_SOUND, 1000000.0 / 4800.0, false, NULL);
-               } else {
-                       cmt_sound_flag = false;
-                       cmt_level_flag = false;
-                       cmt_sound_count = 0;
-                       cmt_local_count = 0;
-               }
-#endif
-               break;
        case EVENT_BEEP:
                beep_signal = !beep_signal;
                d_pcm->write_signal(SIG_PCM1BIT_SIGNAL, ((beep_on && beep_signal) || sing_signal) ? 1 : 0, 1);
                break;
+#ifdef SUPPORT_PC88_CDROM
+       case EVENT_FADE_IN:
+               if((cdda_volume += 0.1) >= 100.0) {
+                       cancel_event(this, cdda_register_id);
+                       cdda_register_id = -1;
+                       cdda_volume = 100.0;
+               }
+               d_scsi_cdrom->set_volume((int)cdda_volume);
+               break;
+       case EVENT_FADE_OUT:
+               if((cdda_volume -= 0.1) <= 0) {
+                       cancel_event(this, cdda_register_id);
+                       cdda_register_id = -1;
+                       cdda_volume = 0.0;
+               }
+               d_scsi_cdrom->set_volume((int)cdda_volume);
+               break;
+#endif
        }
 }
 
 void PC88::event_frame()
 {
        // update key status
-       memcpy(key_status, emu->key_buffer(), sizeof(key_status));
+       memcpy(key_status, emu->get_key_buffer(), sizeof(key_status));
        
-       for(int i = 0; i < 9; i++) {
+       for(int i = 0; i < array_length(key_conv_table); i++) {
                // INS or F6-F10 -> SHIFT + DEL or F1-F5
                if(key_status[key_conv_table[i][0]]) {
                        key_status[key_conv_table[i][1]] = 1;
@@ -1827,6 +1987,88 @@ void PC88::event_vline(int v, int clock)
                request_intr(IRQ_VRTC, true);
                update_gvram_wait();
        }
+       // update palette
+#if !defined(_PC8001SR)
+       if(v < (disp_line <= 200 ? 200 : 400)) {
+#else
+       if(v < 200) {
+#endif
+               if(update_palette) {
+                       static bool initialized = false;
+                       static palette_t initial[9] = {0};
+                       
+                       if(!initialized) {
+                               for(int i = 1; i < 8; i++) {
+                                       initial[i].b = (i & 1) ? 7 : 0;
+                                       initial[i].r = (i & 2) ? 7 : 0;
+                                       initial[i].g = (i & 4) ? 7 : 0;
+                               }
+                               initialized = true;
+                       }
+                       for(int i = 0; i < 9; i++) {
+                               palette_digital[i] = palette_analog[i] = initial[i];
+                       }
+#if defined(_PC8001SR)
+                       if(config.boot_mode != MODE_PC80_V2) {
+                               if(Port31_V1_320x200) {
+                                       for(int i = 0; i < 3; i++) {
+                                               palette_analog[i].b = (port[0x31] & 4) ? 7 : 0;
+                                               palette_analog[i].r = (i          & 1) ? 7 : 0;
+                                               palette_analog[i].g = (i          & 2) ? 7 : 0;
+                                       }
+                                       palette_analog[3] = palette[8];
+                               } else if(Port31_V1_MONO) {
+//                                     palette_analog[0] = {0, 0, 0};
+                                       palette_analog[1] = palette[8];
+                               } else {
+//                                     for(int i = 1; i < 8; i++) {
+//                                             palette_analog[i].b = (i & 1) ? 7 : 0;
+//                                             palette_analog[i].r = (i & 2) ? 7 : 0;
+//                                             palette_analog[i].g = (i & 4) ? 7 : 0;
+//                                     }
+                                       palette_analog[0] = palette[8];
+                               }
+                               if(Port31_V1_320x200) {
+//                                     palette_digital[0] = {0, 0, 0};
+                               } else {
+                                       palette_digital[0] = palette_analog[0];
+                               }
+                       } else {
+                               for(int i = 0; i < 8; i++) {
+                                       palette_analog[i].b = (port[0x54 + i] & 1) ? 7 : 0;
+                                       palette_analog[i].r = (port[0x54 + i] & 2) ? 7 : 0;
+                                       palette_analog[i].g = (port[0x54 + i] & 4) ? 7 : 0;
+                               }
+                               if(!Port31_HCOLOR) {
+                                       palette_analog[0] = palette[8];
+                               }
+                               palette_digital[0] = palette_analog[0];
+                       }
+#else
+                       for(int i = 0; i < 8; i++) {
+                               palette_analog[i] = palette[i];
+                       }
+                       if(!Port31_HCOLOR) {
+                               if(!Port32_PMODE) {
+                                       palette_analog[0] = palette[8];
+                               } else {
+                                       palette_analog[0] = palette[9];
+                               }
+                       }
+                       palette_digital[0] = palette_analog[0];
+#endif
+               }
+               if(v == 0) {
+                       memset(palette_line_changed, 0, sizeof(palette_line_changed));
+               }
+               if((palette_line_changed[v] = (update_palette || v == 0)) == true) {
+                       for(int i = 0; i < 9; i++) {
+                               palette_line_digital[v][i] = palette_digital[i];
+                               palette_line_analog [v][i] = palette_analog [i];
+                       }
+                       update_palette = false;
+               }
+       }
 }
 
 void PC88::key_down(int code, bool repeat)
@@ -1893,12 +2135,6 @@ void PC88::play_tape(const _TCHAR* file_path)
                        if(cmt_register_id != -1) {
                                cancel_event(this, cmt_register_id);
                        }
-#ifdef DATAREC_SOUND
-                       cmt_sound_count = 0;
-                       cmt_sound_data = 0;
-                       cmt_level_flag = false;
-                       cmt_sound_flag = true;
-#endif            
                        register_event(this, EVENT_CMT_SEND, 5000, false, &cmt_register_id);
                }
        }
@@ -1936,7 +2172,7 @@ void PC88::release_tape()
        cmt_play = cmt_rec = false;
 }
 
-bool PC88::now_skip()
+bool PC88::is_frame_skippable()
 {
        return (cmt_play && cmt_bufptr < cmt_bufcnt && Port30_MTON);
 }
@@ -1975,8 +2211,8 @@ void PC88::draw_screen()
        draw_text();
        
        // render graph screen
-       scrntype *palette_pc = palette_graph_pc;
        bool disp_color_graph = true;
+       bool draw_scanline_black = config.scan_line;
 #if defined(_PC8001SR)
        if(config.boot_mode != MODE_PC80_V2) {
                if(Port31_V1_320x200) {
@@ -1984,161 +2220,214 @@ void PC88::draw_screen()
                } else if(Port31_V1_MONO) {
                        draw_640x200_mono_graph();
                } else {
+                       if(hireso) {
+                               draw_scanline_black = false;
+                       }
                        draw_640x200_attrib_graph();
-                       palette_pc = palette_text_pc;
                }
+               emu->set_vm_screen_lines(200);
        } else {
-               if(Port31_COLOR) {
+               if(Port31_HCOLOR) {
                        if(Port31_320x200) {
                                disp_color_graph = draw_320x200_color_graph();
                        } else {
                                disp_color_graph = draw_640x200_color_graph();
                        }
+                       emu->set_vm_screen_lines(200);
                } else {
                        if(Port31_320x200) {
                                draw_320x200_attrib_graph();
                        } else {
                                draw_640x200_attrib_graph();
                        }
-                       palette_pc = palette_text_pc;
+                       if(hireso) {
+                               draw_scanline_black = false;
+                       }
+                       emu->set_vm_screen_lines(200);
                }
        }
 #else
        if(Port31_HCOLOR) {
                disp_color_graph = draw_640x200_color_graph();
+               emu->set_vm_screen_lines(200);
        } else if(!Port31_400LINE) {
-               draw_640x200_mono_graph();
+               if(hireso) {
+                       draw_scanline_black = false;
+               }
+               draw_640x200_attrib_graph();
+//             draw_640x200_mono_graph();
+               emu->set_vm_screen_lines(200);
        } else {
+               if(hireso) {
+                       draw_scanline_black = false;
+               }
                draw_640x400_attrib_graph();
-               palette_pc = palette_text_pc;
+//             draw_640x400_mono_graph();
+               emu->set_vm_screen_lines(400);
        }
 #endif
        
-       // update palette
-       if(update_palette) {
-               static const int pex[8] = {
-                       0,  36,  73, 109, 146, 182, 219, 255 // from m88
-               };
-               scrntype back_color = 0;
-#if defined(_PC8001SR)
-               if(config.boot_mode != MODE_PC80_V2) {
-                       if(Port31_V1_320x200) {
-                               for(int i = 0; i < 3; i++) {
-                                       uint8 b = (port[0x31] & 4) ? 7 : 0;
-                                       uint8 r = (i          & 1) ? 7 : 0;
-                                       uint8 g = (i          & 2) ? 7 : 0;
-                                       palette_graph_pc[i] = RGB_COLOR(pex[r], pex[g], pex[b]);
-                               }
-                               palette_graph_pc[3] = RGB_COLOR(pex[palette[8].r], pex[palette[8].g], pex[palette[8].b]);
-                       } else if(Port31_V1_MONO) {
-                               palette_graph_pc[0] = 0;
-                               palette_graph_pc[1] = RGB_COLOR(pex[palette[8].r], pex[palette[8].g], pex[palette[8].b]);
-                       } else {
-                               back_color = RGB_COLOR(pex[palette[8].r], pex[palette[8].g], pex[palette[8].b]);
+       // create palette for each scanline
+#if !defined(_PC8001SR)
+       int disp_line = crtc.height * crtc.char_height;
+       int ymax = (disp_line <= 200) ? 200 : 400;
+#else
+       int ymax = 200;
+#endif
+       static const uint32_t pex[8] = {
+               0,  36,  73, 109, 146, 182, 219, 255 // from m88
+       };
+       scrntype_t palette_digital_text_pc [9];
+       scrntype_t palette_analog_text_pc  [9];
+       scrntype_t palette_digital_graph_pc[9];
+       scrntype_t palette_analog_graph_pc [9];
+       
+       scrntype_t palette_line_digital_text_pc [400][9];
+       scrntype_t palette_line_analog_graph_pc [400][9];
+#if !defined(_PC8001SR)
+       scrntype_t palette_line_analog_text_pc  [400][9];
+       scrntype_t palette_line_digital_graph_pc[400][9];
+#endif
+       
+       for(int y = 0; y < ymax; y++) {
+               if(palette_line_changed[y]) {
+                       for(int i = 0; i < 9; i++) {
+                               // A is a flag for crt filter
+                               palette_digital_text_pc [i] = RGBA_COLOR(pex[palette_line_digital[y][i].r], pex[palette_line_digital[y][i].g], pex[palette_line_digital[y][i].b], 255);
+                               palette_analog_text_pc  [i] = RGBA_COLOR(pex[palette_line_analog [y][i].r], pex[palette_line_analog [y][i].g], pex[palette_line_analog [y][i].b], 255);
+                               palette_digital_graph_pc[i] = RGBA_COLOR(pex[palette_line_digital[y][i].r], pex[palette_line_digital[y][i].g], pex[palette_line_digital[y][i].b],   0);
+                               palette_analog_graph_pc [i] = RGBA_COLOR(pex[palette_line_analog [y][i].r], pex[palette_line_analog [y][i].g], pex[palette_line_analog [y][i].b],   0);
                        }
-               } else {
-                       if(Port31_COLOR) {
-                               for(int i = 0; i < 8; i++) {
-                                       uint8 b = (port[0x54 + i] & 1) ? 7 : 0;
-                                       uint8 r = (port[0x54 + i] & 2) ? 7 : 0;
-                                       uint8 g = (port[0x54 + i] & 4) ? 7 : 0;
-                                       palette_graph_pc[i] = RGB_COLOR(pex[r], pex[g], pex[b]);
-                               }
-                               back_color = palette_graph_pc[0];
-                       } else {
-                               back_color = RGB_COLOR(pex[palette[8].r], pex[palette[8].g], pex[palette[8].b]);
+                       // set back color to black if cg screen is off in color mode
+                       if(!disp_color_graph) {
+                               palette_digital_text_pc [0] = 
+                               palette_analog_text_pc  [0] = 
+                               palette_digital_graph_pc[0] = 
+                               palette_analog_graph_pc [0] = 0;
                        }
-               }
-#else
-               if(Port31_HCOLOR) {
-                       for(int i = 0; i < 8; i++) {
-                               palette_graph_pc[i] = RGB_COLOR(pex[palette[i].r], pex[palette[i].g], pex[palette[i].b]);
+                       palette_analog_text_pc [8] = palette_digital_text_pc [0];
+                       palette_analog_graph_pc[8] = palette_digital_graph_pc[0];
+               }
+               if(ymax == 200) {
+                       for(int i = 0; i < 9; i++) {
+                               palette_line_digital_text_pc [2 * y    ][i] = 
+                               palette_line_digital_text_pc [2 * y + 1][i] = palette_digital_text_pc [i];
+                               palette_line_analog_graph_pc [2 * y    ][i] = 
+                               palette_line_analog_graph_pc [2 * y + 1][i] = palette_analog_graph_pc [i];
+#if !defined(_PC8001SR)
+                               palette_line_analog_text_pc  [2 * y    ][i] = 
+                               palette_line_analog_text_pc  [2 * y + 1][i] = palette_analog_text_pc  [i];
+                               palette_line_digital_graph_pc[2 * y    ][i] = 
+                               palette_line_digital_graph_pc[2 * y + 1][i] = palette_digital_graph_pc[i];
+#endif
                        }
-               } else if(!Port31_400LINE) {
-                       palette_graph_pc[0] = RGB_COLOR(pex[palette[8].r], pex[palette[8].g], pex[palette[8].b]);
-                       palette_graph_pc[1] = RGB_COLOR(255, 255, 255);
-               }
-               back_color = RGB_COLOR(pex[palette[8].r], pex[palette[8].g], pex[palette[8].b]);
+               } else {
+                       for(int i = 0; i < 9; i++) {
+                               palette_line_digital_text_pc [y][i] = palette_digital_text_pc [i];
+                               palette_line_analog_graph_pc [y][i] = palette_analog_graph_pc [i];
+#if !defined(_PC8001SR)
+                               palette_line_analog_text_pc  [y][i] = palette_analog_text_pc  [i];
+                               palette_line_digital_graph_pc[y][i] = palette_digital_graph_pc[i];
 #endif
-               // back color for attrib mode
-               palette_text_pc[0] = back_color;
-               update_palette = false;
-       }
-       
-       // set back color to black if cg screen is off in color mode
-       scrntype palette_text_back = palette_text_pc[0];
-       scrntype palette_graph_back = palette_graph_pc[0];
-       
-       if(!disp_color_graph) {
-               palette_text_pc[0] = palette_graph_pc[0] = 0;
+                       }
+               }
        }
        
        // copy to screen buffer
 #if !defined(_PC8001SR)
-       if(!Port31_400LINE) {
-#endif
-               for(int y = 0; y < 200; y++) {
-                       // for Xak2 opening (XM8 version 1.00)
-                       if(crtc.char_height == 0x10) {
-                               if(y >= (crtc.height * crtc.char_height / 2)) {
-                                       while(y < 200) {
-                                               scrntype* dest0 = emu->screen_buffer(y * 2);
-                                               scrntype* dest1 = emu->screen_buffer(y * 2 + 1);
-                                               memset(dest0, 0, sizeof(scrntype) * 640);
-                                               memset(dest1, 0, sizeof(scrntype) * 640);
-                                               y++;
-                                       }
-                                       break;
-                               }
+#if defined(SUPPORT_PC88_VAB)
+       // X88000
+       if(PortB4_VAB_DISP) {
+               uint8_t *src = &exram[(0x8000 * 4) * PC88_VAB_PAGE];
+               
+               for(int y = 0; y < 400; y += 2) {
+                       scrntype_t* dest0 = emu->get_screen_buffer(y);
+                       scrntype_t* dest1 = emu->get_screen_buffer(y + 1);
+                       
+                       for(int x = 0; x < 640; x += 2) {
+                               pair16_t c;
+                               c.b.l = *src++;
+                               c.b.h = *src++;
+                               dest0[x] = dest0[x + 1] = palette_vab_pc[c.w];
                        }
-                       scrntype* dest0 = emu->screen_buffer(y * 2);
-                       scrntype* dest1 = emu->screen_buffer(y * 2 + 1);
-                       uint8* src_t = text[y];
-                       uint8* src_g = graph[y];
+                       if(config.scan_line) {
+                               memset(dest1, 0, sizeof(scrntype_t) * 640);
+                       } else {
+                               memcpy(dest1, dest0, sizeof(scrntype_t) * 640);
+                       }
+               }
+               emu->screen_skip_line(true);
+       } else
+#endif
+       if(!Port31_HCOLOR && Port31_400LINE) {
+               for(int y = 0; y < 400; y++) {
+                       scrntype_t* dest = emu->get_screen_buffer(y);
+                       uint8_t* src_t = text[y >> 1];
+                       uint8_t* src_g = graph[y];
+                       scrntype_t* pal_t;
+                       scrntype_t* pal_g;
                        
+//                     if(Port31_HCOLOR) {
+//                             pal_t = palette_line_digital_text_pc [y];
+//                             pal_g = palette_line_analog_graph_pc [y];
+//                     } else
+                       if(Port32_PMODE) {
+                               pal_t = palette_line_analog_text_pc  [y];
+                               pal_g = palette_line_analog_graph_pc [y];
+                       } else {
+                               pal_t = palette_line_digital_text_pc [y];
+                               pal_g = palette_line_digital_graph_pc[y];
+                       }
+                       for(int x = 0; x < 640; x++) {
+                               uint32_t t = src_t[x];
+                               dest[x] = t ? pal_t[t] : pal_g[src_g[x]];
+                       }
+               }
+               emu->screen_skip_line(false);
+       } else
+#endif
+       {
+               for(int y = 0; y < 400; y++) {
+                       scrntype_t* dest = emu->get_screen_buffer(y);
+                       uint8_t* src_t = text[y >> 1];
+                       uint8_t* src_g = graph[y];
+                       scrntype_t* pal_t;
+                       scrntype_t* pal_g;
 #if defined(_PC8001SR)
+                       pal_t = palette_line_digital_text_pc[y];
+                       pal_g = palette_line_analog_graph_pc[y];
+                       
                        if(port[0x33] & 8) {
                                for(int x = 0; x < 640; x++) {
-                                       uint32 g = src_g[x];
-                                       dest0[x] = g ? palette_pc[g] : palette_text_pc[src_t[x]];
+                                       uint32_t t = src_t[x];
+                                       uint32_t g = src_g[x];
+                                       dest[x] = (!g && t) ? pal_t[t] : ((y & 1) && draw_scanline_black) ? 0 : pal_g[g];
                                }
                        } else {
-#endif
                                for(int x = 0; x < 640; x++) {
-                                       uint32 t = src_t[x];
-                                       dest0[x] = t ? palette_text_pc[t] : palette_pc[src_g[x]];
+                                       uint32_t t = src_t[x];
+                                       dest[x] = t ? pal_t[t] : ((y & 1) && draw_scanline_black) ? 0 : pal_g[src_g[x]];
                                }
-#if defined(_PC8001SR)
                        }
-#endif
-                       if(config.scan_line) {
-                               memset(dest1, 0, 640 * sizeof(scrntype));
+#else
+                       if(Port31_HCOLOR) {
+                               pal_t = palette_line_digital_text_pc [y];
+                               pal_g = palette_line_analog_graph_pc [y];
+                       } else if(Port32_PMODE) {
+                               pal_t = palette_line_analog_text_pc  [y];
+                               pal_g = palette_line_analog_graph_pc [y];
                        } else {
-                               for(int x = 0; x < 640; x++) {
-                                       dest1[x] = dest0[x];
-                               }
+                               pal_t = palette_line_digital_text_pc [y];
+                               pal_g = palette_line_digital_graph_pc[y];
                        }
-               }
-               emu->screen_skip_line(true);
-#if !defined(_PC8001SR)
-       } else {
-               for(int y = 0; y < 400; y++) {
-                       scrntype* dest = emu->screen_buffer(y);
-                       uint8* src_t = text[y >> 1];
-                       uint8* src_g = graph[y];
-                       
                        for(int x = 0; x < 640; x++) {
-                               uint32 t = src_t[x];
-                               dest[x] = t ? palette_text_pc[t] : palette_pc[src_g[x]];
+                               uint32_t t = src_t[x];
+                               dest[x] = t ? pal_t[t] : ((y & 1) && draw_scanline_black) ? 0 : pal_g[src_g[x]];
                        }
+#endif
                }
-               emu->screen_skip_line(false);
+               emu->screen_skip_line(true);
        }
-#endif
-       
-       // restore back color palette
-       palette_text_pc[0] = palette_text_back;
-       palette_graph_pc[0] = palette_graph_back;
 }
 
 /*
@@ -2156,70 +2445,106 @@ void PC88::draw_screen()
 
 void PC88::draw_text()
 {
+       if(crtc.status & 0x88) {
+               // dma underrun
+               crtc.status &= ~0x80;
+               memset(crtc.text.expand, 0, 200 * 80);
+               memset(crtc.attrib.expand, crtc.reverse ? 3 : 2, 200 * 80);
+       }
        // for Advanced Fantasian Opening (20line) (XM8 version 1.00)
        if(!(crtc.status & 0x10) || Port53_TEXTDS) {
 //     if(!(crtc.status & 0x10) || (crtc.status & 8) || Port53_TEXTDS) {
-               memset(text, 0, sizeof(text));
-               return;
+               memset(crtc.text.expand, 0, 200 * 80);
+               for(int y = 0; y < 200; y++) {
+                       for(int x = 0; x < 80; x++) {
+                               crtc.attrib.expand[y][x] &= 0xe0;
+                               crtc.attrib.expand[y][x] |= 0x02;
+                       }
+               }
+//             memset(crtc.attrib.expand, 2, 200 * 80);
        }
        
+       // for Xak2 opening
+       memset(text, 8, sizeof(text));
+       memset(text_color, 7, sizeof(text_color));
+       memset(text_reverse, 0, sizeof(text_reverse));
+       
        int char_height = crtc.char_height;
-       uint8 color_mask = Port30_COLOR ? 0 : 7;
+       uint8_t color_mask = Port30_COLOR ? 0 : 7;
+       uint8_t code_expand, attr_expand;
        
        if(!hireso) {
                char_height <<= 1;
        }
-       if(Port31_400LINE || !crtc.skip_line) {
-               char_height >>= 1;
+//     if(Port31_400LINE || !crtc.skip_line) {
+//             char_height >>= 1;
+//     }
+       if(crtc.skip_line) {
+               char_height <<= 1;
        }
-       for(int cy = 0, ytop = 0; cy < crtc.height && ytop < 200; cy++, ytop += char_height) {
+//     for(int cy = 0, ytop = 0; cy < 64 && ytop < 400; cy++, ytop += char_height) {
+       for(int cy = 0, ytop = 0; cy < crtc.height && ytop < 400; cy++, ytop += char_height) {
                for(int x = 0, cx = 0; cx < crtc.width; x += 8, cx++) {
                        if(Port30_40 && (cx & 1)) {
-                               continue;
+                               // don't update code/attrib
+                       } else {
+                               code_expand = crtc.text.expand[cy][cx];
+                               attr_expand = crtc.attrib.expand[cy][cx];
                        }
-                       uint8 attrib = crtc.attrib.expand[cy][cx];
-                       uint8 color = (attrib & 0xe0) ? ((attrib >> 5) | color_mask) : 8;
+                       uint8_t attrib = attr_expand;//crtc.attrib.expand[cy][cx];
+//                     uint8_t color = !(Port30_COLOR && (attrib & 8)) ? 7 : (attrib & 0xe0) ? (attrib >> 5) : 8;
+                       uint8_t color = (attrib & 0xe0) ? ((attrib >> 5) | color_mask) : 8;
                        bool under_line = ((attrib & 8) != 0);
                        bool upper_line = ((attrib & 4) != 0);
                        bool secret = ((attrib & 2) != 0);
                        bool reverse = ((attrib & 1) != 0);
                        
-                       uint8 code = secret ? 0 : crtc.text.expand[cy][cx];
+                       uint8_t color_tmp = color;
+                       bool reverse_tmp = reverse;
+                       
+                       // from ePC-8801MA\89ü
+                       if(Port31_GRAPH && !Port31_HCOLOR) {
+                               if(reverse) {
+                                       reverse = false;
+                                       color = 8;
+                               }
+                       }
+                       uint8_t code = secret ? 0 : code_expand;//crtc.text.expand[cy][cx];
 #ifdef SUPPORT_PC88_PCG8100
-                       uint8 *pattern = ((attrib & 0x10) ? sg_pattern : pcg_pattern) + code * 8;
+                       uint8_t *pattern = ((attrib & 0x10) ? sg_pattern : pcg_pattern) + code * 8;
 #else
-                       uint8 *pattern = ((attrib & 0x10) ? sg_pattern : kanji1 + 0x1000) + code * 8;
+                       uint8_t *pattern = ((attrib & 0x10) ? sg_pattern : kanji1 + 0x1000) + code * 8;
 #endif
                        
-                       for(int l = 0, y = ytop; l < char_height && y < 200; l++, y++) {
-                               uint8 pat = (l < 8) ? pattern[l] : 0;
+                       for(int l = 0, y = ytop; l < char_height / 2 && y < 400; l++, y += 2) {
+                               uint8_t pat = (l < 8) ? pattern[l] : 0;
+                               
+                               if(Port30_40) {
+                                       // from ePC-8801MA\89ü
+                                       static const uint8_t wct[16] = {
+                                               0x00, 0x03, 0x0c, 0x0f, 0x30, 0x33, 0x3c, 0x3f, 0xc0, 0xc3, 0xcc, 0xcf, 0xf0, 0xf3, 0xfc, 0xff
+                                       };
+                                       pat = wct[(cx & 1) ? (pat & 0x0f) : (pat >> 4)];
+                               }
                                if((upper_line && l == 0) || (under_line && l >= 7)) {
                                        pat = 0xff;
                                }
                                if(reverse) {
-                                       pat = ~pat;
+                                       pat ^= 0xff;
                                }
+                               uint8_t *dest = &text[y >> 1][x];
+                               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;
                                
-                               uint8 *dest = &text[y][x];
-                               if(Port30_40) {
-                                       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;
-                               } else {
-                                       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;
-                               }
+                               // store text attributes for monocolor graph screen
+                               text_color[y >> 1][cx] = color_tmp;
+                               text_reverse[y >> 1][cx] = reverse_tmp;
                        }
                }
        }
@@ -2232,32 +2557,32 @@ bool PC88::draw_320x200_color_graph()
                memset(graph, 0, sizeof(graph));
                return false;
        }
-       uint8 *gvram_b0 = Port53_G0DS ? gvram_null : (gvram + 0x0000);
-       uint8 *gvram_r0 = Port53_G0DS ? gvram_null : (gvram + 0x4000);
-       uint8 *gvram_g0 = Port53_G0DS ? gvram_null : (gvram + 0x8000);
-       uint8 *gvram_b1 = Port53_G1DS ? gvram_null : (gvram + 0x2000);
-       uint8 *gvram_r1 = Port53_G1DS ? gvram_null : (gvram + 0x6000);
-       uint8 *gvram_g1 = Port53_G1DS ? gvram_null : (gvram + 0xa000);
+       uint8_t *gvram_b0 = Port53_G0DS ? gvram_null : (gvram + 0x0000);
+       uint8_t *gvram_r0 = Port53_G0DS ? gvram_null : (gvram + 0x4000);
+       uint8_t *gvram_g0 = Port53_G0DS ? gvram_null : (gvram + 0x8000);
+       uint8_t *gvram_b1 = Port53_G1DS ? gvram_null : (gvram + 0x2000);
+       uint8_t *gvram_r1 = Port53_G1DS ? gvram_null : (gvram + 0x6000);
+       uint8_t *gvram_g1 = Port53_G1DS ? gvram_null : (gvram + 0xa000);
        
        if(port[0x33] & 4) {
                // G1>G0
-               uint8 *tmp;
+               uint8_t *tmp;
                tmp = gvram_b0; gvram_b0 = gvram_b1; gvram_b1 = tmp;
                tmp = gvram_r0; gvram_r0 = gvram_r1; gvram_r1 = tmp;
                tmp = gvram_g0; gvram_g0 = gvram_g1; gvram_g1 = tmp;
        }
        
-       for(int y = 0, addr = 0; y < 200; y++) {
+       for(int y = 0, addr = 0; y < 400; y += 2) {
                for(int x = 0; x < 640; x += 16) {
-                       uint8 b0 = gvram_b0[addr];
-                       uint8 r0 = gvram_r0[addr];
-                       uint8 g0 = gvram_g0[addr];
-                       uint8 b1 = gvram_b1[addr];
-                       uint8 r1 = gvram_r1[addr];
-                       uint8 g1 = gvram_g1[addr];
+                       uint8_t b0 = gvram_b0[addr];
+                       uint8_t r0 = gvram_r0[addr];
+                       uint8_t g0 = gvram_g0[addr];
+                       uint8_t b1 = gvram_b1[addr];
+                       uint8_t r1 = gvram_r1[addr];
+                       uint8_t g1 = gvram_g1[addr];
                        addr++;
-                       uint8 *dest = &graph[y][x];
-                       uint8 brg0, brg1;
+                       uint8_t *dest = &graph[y][x];
+                       uint8_t brg0, brg1;
                        brg0 = ((b0 & 0x80) >> 7) | ((r0 & 0x80) >> 6) | ((g0 & 0x80) >> 5);
                        brg1 = ((b1 & 0x80) >> 7) | ((r1 & 0x80) >> 6) | ((g1 & 0x80) >> 5);
                        dest[ 0] = dest[ 1] = brg0 ? brg0 : brg1;
@@ -2283,6 +2608,11 @@ bool PC88::draw_320x200_color_graph()
                        brg1 = ((b1 & 0x01)     ) | ((r1 & 0x01) << 1) | ((g1 & 0x01) << 2);
                        dest[14] = dest[15] = brg0 ? brg0 : brg1;
                }
+               if(config.scan_line) {
+                       memset(graph[y + 1], 0, 640);
+               } else {
+                       memcpy(graph[y + 1], graph[y], 640);
+               }
        }
        return true;
 }
@@ -2293,20 +2623,25 @@ bool PC88::draw_320x200_4color_graph()
                memset(graph, 0, sizeof(graph));
                return false;
        }
-       uint8 *gvram_b = Port53_G0DS ? gvram_null : (gvram + 0x0000);
-       uint8 *gvram_r = Port53_G1DS ? gvram_null : (gvram + 0x4000);
-       uint8 *gvram_g = Port53_G2DS ? gvram_null : (gvram + 0x8000);
+       uint8_t *gvram_b = Port53_G0DS ? gvram_null : (gvram + 0x0000);
+       uint8_t *gvram_r = Port53_G1DS ? gvram_null : (gvram + 0x4000);
+       uint8_t *gvram_g = Port53_G2DS ? gvram_null : (gvram + 0x8000);
        
-       for(int y = 0, addr = 0; y < 200; y++) {
+       for(int y = 0, addr = 0; y < 400; y += 2) {
                for(int x = 0; x < 640; x += 8) {
-                       uint8 brg = gvram_b[addr] | gvram_r[addr] | gvram_g[addr];
+                       uint8_t brg = gvram_b[addr] | gvram_r[addr] | gvram_g[addr];
                        addr++;
-                       uint8 *dest = &graph[y][x];
+                       uint8_t *dest = &graph[y][x];
                        dest[0] = dest[1] = (brg >> 6) & 3;
                        dest[2] = dest[3] = (brg >> 4) & 3;
                        dest[4] = dest[5] = (brg >> 2) & 3;
                        dest[6] = dest[7] = (brg     ) & 3;
                }
+               if(config.scan_line) {
+                       memset(graph[y + 1], 0, 640);
+               } else {
+                       memcpy(graph[y + 1], graph[y], 640);
+               }
        }
        return true;
 }
@@ -2317,56 +2652,96 @@ void PC88::draw_320x200_attrib_graph()
                memset(graph, 0, sizeof(graph));
                return;
        }
-       uint8 *gvram_b0 = Port53_G0DS ? gvram_null : (gvram + 0x0000);
-       uint8 *gvram_r0 = Port53_G1DS ? gvram_null : (gvram + 0x4000);
-       uint8 *gvram_g0 = Port53_G2DS ? gvram_null : (gvram + 0x8000);
-       uint8 *gvram_b1 = Port53_G3DS ? gvram_null : (gvram + 0x2000);
-       uint8 *gvram_r1 = Port53_G4DS ? gvram_null : (gvram + 0x6000);
-       uint8 *gvram_g1 = Port53_G5DS ? gvram_null : (gvram + 0xa000);
-       
-       int char_height = crtc.char_height ? crtc.char_height : 8;
-       uint8 color_mask = Port30_COLOR ? 0 : 7;
+       uint8_t *gvram_b0 = Port53_G0DS ? gvram_null : (gvram + 0x0000);
+       uint8_t *gvram_r0 = Port53_G1DS ? gvram_null : (gvram + 0x4000);
+       uint8_t *gvram_g0 = Port53_G2DS ? gvram_null : (gvram + 0x8000);
+       uint8_t *gvram_b1 = Port53_G3DS ? gvram_null : (gvram + 0x2000);
+       uint8_t *gvram_r1 = Port53_G4DS ? gvram_null : (gvram + 0x6000);
+       uint8_t *gvram_g1 = Port53_G5DS ? gvram_null : (gvram + 0xa000);
        
        if(Port30_40) {
-               for(int y = 0, addr = 0; y < 200; y++) {
-                       int cy = y / char_height;
+               for(int y = 0, addr = 0; y < 400; y += 2) {
                        for(int x = 0, cx = 0; x < 640; x += 16, cx += 2) {
-                               uint8 attrib = crtc.attrib.expand[cy][cx];
-                               uint8 color = (attrib & 0xe0) ? ((attrib >> 5) | color_mask) : 8;
-                               uint8 brg = gvram_b0[addr] | gvram_r0[addr] | gvram_g0[addr] |
-                                           gvram_b1[addr] | gvram_r1[addr] | gvram_g1[addr];
+                               uint8_t color = text_color[y >> 1][cx];
+                               uint8_t brg0 = gvram_b0[addr] | gvram_r0[addr] | gvram_g0[addr] |
+                                              gvram_b1[addr] | gvram_r1[addr] | gvram_g1[addr];
+                               uint8_t brg1 = 0;
+                               if(text_reverse[y >> 1][cx]) {
+                                       brg0 ^= 0xff;
+                                       brg1 ^= 0xff;
+                               }
                                addr++;
-                               uint8 *dest = &graph[y][x];
-                               dest[ 0] = dest[ 1] = (brg & 0x80) ? color : 0;
-                               dest[ 2] = dest[ 3] = (brg & 0x40) ? color : 0;
-                               dest[ 4] = dest[ 5] = (brg & 0x20) ? color : 0;
-                               dest[ 6] = dest[ 7] = (brg & 0x10) ? color : 0;
-                               dest[ 8] = dest[ 9] = (brg & 0x08) ? color : 0;
-                               dest[10] = dest[11] = (brg & 0x04) ? color : 0;
-                               dest[12] = dest[13] = (brg & 0x02) ? color : 0;
-                               dest[14] = dest[15] = (brg & 0x01) ? color : 0;
+                               uint8_t *dest0 = &graph[y    ][x];
+                               uint8_t *dest1 = &graph[y + 1][x];
+                               dest0[ 0] = dest0[ 1] = (brg0 & 0x80) ? color : 0;
+                               dest0[ 2] = dest0[ 3] = (brg0 & 0x40) ? color : 0;
+                               dest0[ 4] = dest0[ 5] = (brg0 & 0x20) ? color : 0;
+                               dest0[ 6] = dest0[ 7] = (brg0 & 0x10) ? color : 0;
+                               dest0[ 8] = dest0[ 9] = (brg0 & 0x08) ? color : 0;
+                               dest0[10] = dest0[11] = (brg0 & 0x04) ? color : 0;
+                               dest0[12] = dest0[13] = (brg0 & 0x02) ? color : 0;
+                               dest0[14] = dest0[15] = (brg0 & 0x01) ? color : 0;
+                               if(!hireso) continue;
+                               dest1[ 0] = dest1[ 1] = (brg1 & 0x80) ? color : 0;
+                               dest1[ 2] = dest1[ 3] = (brg1 & 0x40) ? color : 0;
+                               dest1[ 4] = dest1[ 5] = (brg1 & 0x20) ? color : 0;
+                               dest1[ 6] = dest1[ 7] = (brg1 & 0x10) ? color : 0;
+                               dest1[ 8] = dest1[ 9] = (brg1 & 0x08) ? color : 0;
+                               dest1[10] = dest1[11] = (brg1 & 0x04) ? color : 0;
+                               dest1[12] = dest1[13] = (brg1 & 0x02) ? color : 0;
+                               dest1[14] = dest1[15] = (brg1 & 0x01) ? color : 0;
+                       }
+                       if(!hireso) {
+                               if(config.scan_line) {
+                                       memset(graph[y + 1], 0, 640);
+                               } else {
+                                       memcpy(graph[y + 1], graph[y], 640);
+                               }
                        }
                }
        } else {
-               for(int y = 0, addr = 0; y < 200; y++) {
-                       int cy = y / char_height;
+               for(int y = 0, addr = 0; y < 400; y += 2) {
                        for(int x = 0, cx = 0; x < 640; x += 16, cx += 2) {
-                               uint8 attrib_l = crtc.attrib.expand[cy][cx];
-                               uint8 color_l = (attrib_l & 0xe0) ? ((attrib_l >> 5) | color_mask) : 8;
-                               uint8 attrib_r = crtc.attrib.expand[cy][cx + 1];
-                               uint8 color_r = (attrib_r & 0xe0) ? ((attrib_r >> 5) | color_mask) : 8;
-                               uint8 brg = gvram_b0[addr] | gvram_r0[addr] | gvram_g0[addr] |
-                                           gvram_b1[addr] | gvram_r1[addr] | gvram_g1[addr];
+                               uint8_t color_l = text_color[y >> 1][cx + 0];
+                               uint8_t color_r = text_color[y >> 1][cx + 1];
+                               uint8_t brg0 = gvram_b0[addr] | gvram_r0[addr] | gvram_g0[addr] |
+                                              gvram_b1[addr] | gvram_r1[addr] | gvram_g1[addr];
+                               uint8_t brg1 = 0;
+                               if(text_reverse[y >> 1][cx + 0]) {
+                                       brg0 ^= 0xf0;
+                                       brg0 ^= 0xf0;
+                               }
+                               if(text_reverse[y >> 1][cx + 1]) {
+                                       brg1 ^= 0x0f;
+                                       brg1 ^= 0x0f;
+                               }
                                addr++;
-                               uint8 *dest = &graph[y][x];
-                               dest[ 0] = dest[ 1] = (brg & 0x80) ? color_l : 0;
-                               dest[ 2] = dest[ 3] = (brg & 0x40) ? color_l : 0;
-                               dest[ 4] = dest[ 5] = (brg & 0x20) ? color_l : 0;
-                               dest[ 6] = dest[ 7] = (brg & 0x10) ? color_l : 0;
-                               dest[ 8] = dest[ 9] = (brg & 0x08) ? color_r : 0;
-                               dest[10] = dest[11] = (brg & 0x04) ? color_r : 0;
-                               dest[12] = dest[13] = (brg & 0x02) ? color_r : 0;
-                               dest[14] = dest[15] = (brg & 0x01) ? color_r : 0;
+                               uint8_t *dest0 = &graph[y    ][x];
+                               uint8_t *dest1 = &graph[y + 1][x];
+                               dest0[ 0] = dest0[ 1] = (brg0 & 0x80) ? color_l : 0;
+                               dest0[ 2] = dest0[ 3] = (brg0 & 0x40) ? color_l : 0;
+                               dest0[ 4] = dest0[ 5] = (brg0 & 0x20) ? color_l : 0;
+                               dest0[ 6] = dest0[ 7] = (brg0 & 0x10) ? color_l : 0;
+                               dest0[ 8] = dest0[ 9] = (brg0 & 0x08) ? color_r : 0;
+                               dest0[10] = dest0[11] = (brg0 & 0x04) ? color_r : 0;
+                               dest0[12] = dest0[13] = (brg0 & 0x02) ? color_r : 0;
+                               dest0[14] = dest0[15] = (brg0 & 0x01) ? color_r : 0;
+                               if(!hireso) continue;
+                               dest1[ 0] = dest1[ 1] = (brg1 & 0x80) ? color_l : 0;
+                               dest1[ 2] = dest1[ 3] = (brg1 & 0x40) ? color_l : 0;
+                               dest1[ 4] = dest1[ 5] = (brg1 & 0x20) ? color_l : 0;
+                               dest1[ 6] = dest1[ 7] = (brg1 & 0x10) ? color_l : 0;
+                               dest1[ 8] = dest1[ 9] = (brg1 & 0x08) ? color_r : 0;
+                               dest1[10] = dest1[11] = (brg1 & 0x04) ? color_r : 0;
+                               dest1[12] = dest1[13] = (brg1 & 0x02) ? color_r : 0;
+                               dest1[14] = dest1[15] = (brg1 & 0x01) ? color_r : 0;
+                       }
+                       if(!hireso) {
+                               if(config.scan_line) {
+                                       memset(graph[y + 1], 0, 640);
+                               } else {
+                                       memcpy(graph[y + 1], graph[y], 640);
+                               }
                        }
                }
        }
@@ -2383,17 +2758,17 @@ bool PC88::draw_640x200_color_graph()
                memset(graph, 0, sizeof(graph));
                return false;
        }
-       uint8 *gvram_b = /*Port53_G0DS ? gvram_null : */(gvram + 0x0000);
-       uint8 *gvram_r = /*Port53_G1DS ? gvram_null : */(gvram + 0x4000);
-       uint8 *gvram_g = /*Port53_G2DS ? gvram_null : */(gvram + 0x8000);
+       uint8_t *gvram_b = /*Port53_G0DS ? gvram_null : */(gvram + 0x0000);
+       uint8_t *gvram_r = /*Port53_G1DS ? gvram_null : */(gvram + 0x4000);
+       uint8_t *gvram_g = /*Port53_G2DS ? gvram_null : */(gvram + 0x8000);
        
-       for(int y = 0, addr = 0; y < 200; y++) {
+       for(int y = 0, addr = 0; y < 400; y += 2) {
                for(int x = 0; x < 640; x += 8) {
-                       uint8 b = gvram_b[addr];
-                       uint8 r = gvram_r[addr];
-                       uint8 g = gvram_g[addr];
+                       uint8_t b = gvram_b[addr];
+                       uint8_t r = gvram_r[addr];
+                       uint8_t g = gvram_g[addr];
                        addr++;
-                       uint8 *dest = &graph[y][x];
+                       uint8_t *dest = &graph[y][x];
                        dest[0] = ((b & 0x80) >> 7) | ((r & 0x80) >> 6) | ((g & 0x80) >> 5);
                        dest[1] = ((b & 0x40) >> 6) | ((r & 0x40) >> 5) | ((g & 0x40) >> 4);
                        dest[2] = ((b & 0x20) >> 5) | ((r & 0x20) >> 4) | ((g & 0x20) >> 3);
@@ -2403,6 +2778,11 @@ bool PC88::draw_640x200_color_graph()
                        dest[6] = ((b & 0x02) >> 1) | ((r & 0x02)     ) | ((g & 0x02) << 1);
                        dest[7] = ((b & 0x01)     ) | ((r & 0x01) << 1) | ((g & 0x01) << 2);
                }
+               if(config.scan_line) {
+                       memset(graph[y + 1], 0, 640);
+               } else {
+                       memcpy(graph[y + 1], graph[y], 640);
+               }
        }
        return true;
 }
@@ -2413,15 +2793,15 @@ void PC88::draw_640x200_mono_graph()
                memset(graph, 0, sizeof(graph));
                return;
        }
-       uint8 *gvram_b = Port53_G0DS ? gvram_null : (gvram + 0x0000);
-       uint8 *gvram_r = Port53_G1DS ? gvram_null : (gvram + 0x4000);
-       uint8 *gvram_g = Port53_G2DS ? gvram_null : (gvram + 0x8000);
+       uint8_t *gvram_b = Port53_G0DS ? gvram_null : (gvram + 0x0000);
+       uint8_t *gvram_r = Port53_G1DS ? gvram_null : (gvram + 0x4000);
+       uint8_t *gvram_g = Port53_G2DS ? gvram_null : (gvram + 0x8000);
        
-       for(int y = 0, addr = 0; y < 200; y++) {
+       for(int y = 0, addr = 0; y < 400; y += 2) {
                for(int x = 0; x < 640; x += 8) {
-                       uint8 brg = gvram_b[addr] | gvram_r[addr] | gvram_g[addr];
+                       uint8_t brg = gvram_b[addr] | gvram_r[addr] | gvram_g[addr];
                        addr++;
-                       uint8 *dest = &graph[y][x];
+                       uint8_t *dest = &graph[y][x];
                        dest[0] = (brg & 0x80) >> 7;
                        dest[1] = (brg & 0x40) >> 6;
                        dest[2] = (brg & 0x20) >> 5;
@@ -2431,73 +2811,124 @@ void PC88::draw_640x200_mono_graph()
                        dest[6] = (brg & 0x02) >> 1;
                        dest[7] = (brg & 0x01)     ;
                }
+               if(config.scan_line) {
+                       memset(graph[y + 1], 0, 640);
+               } else {
+                       memcpy(graph[y + 1], graph[y], 640);
+               }
        }
 }
 
-#if defined(_PC8001SR)
 void PC88::draw_640x200_attrib_graph()
 {
        if(!Port31_GRAPH || (Port53_G0DS && Port53_G1DS && Port53_G2DS)) {
                memset(graph, 0, sizeof(graph));
                return;
        }
-       uint8 *gvram_b = Port53_G0DS ? gvram_null : (gvram + 0x0000);
-       uint8 *gvram_r = Port53_G1DS ? gvram_null : (gvram + 0x4000);
-       uint8 *gvram_g = Port53_G2DS ? gvram_null : (gvram + 0x8000);
+       uint8_t *gvram_b = Port53_G0DS ? gvram_null : (gvram + 0x0000);
+       uint8_t *gvram_r = Port53_G1DS ? gvram_null : (gvram + 0x4000);
+       uint8_t *gvram_g = Port53_G2DS ? gvram_null : (gvram + 0x8000);
        
-       int char_height = crtc.char_height ? crtc.char_height : 8;
-       uint8 color_mask = Port30_COLOR ? 0 : 7, color;
-       
-       for(int y = 0, addr = 0; y < 200; y++) {
-               int cy = y / char_height;
+       for(int y = 0, addr = 0; y < 400; y += 2) {
                for(int x = 0, cx = 0; x < 640; x += 8, cx++) {
-                       if(Port30_40 && (cx & 1)) {
-                               // don't update color
+                       uint8_t color = text_color[y >> 1][cx];
+                       uint8_t brg0 = gvram_b[addr] | gvram_r[addr] | gvram_g[addr];
+                       uint8_t brg1 = 0;
+                       if(text_reverse[y >> 1][cx]) {
+                               brg0 ^= 0xff;
+                               brg1 ^= 0xff;
+                       }
+                       addr++;
+                       uint8_t *dest0 = &graph[y    ][x];
+                       uint8_t *dest1 = &graph[y + 1][x];
+                       dest0[0] = (brg0 & 0x80) ? color : 0;
+                       dest0[1] = (brg0 & 0x40) ? color : 0;
+                       dest0[2] = (brg0 & 0x20) ? color : 0;
+                       dest0[3] = (brg0 & 0x10) ? color : 0;
+                       dest0[4] = (brg0 & 0x08) ? color : 0;
+                       dest0[5] = (brg0 & 0x04) ? color : 0;
+                       dest0[6] = (brg0 & 0x02) ? color : 0;
+                       dest0[7] = (brg0 & 0x01) ? color : 0;
+                       if(!hireso) continue;
+                       dest1[0] = (brg1 & 0x80) ? color : 0;
+                       dest1[1] = (brg1 & 0x40) ? color : 0;
+                       dest1[2] = (brg1 & 0x20) ? color : 0;
+                       dest1[3] = (brg1 & 0x10) ? color : 0;
+                       dest1[4] = (brg1 & 0x08) ? color : 0;
+                       dest1[5] = (brg1 & 0x04) ? color : 0;
+                       dest1[6] = (brg1 & 0x02) ? color : 0;
+                       dest1[7] = (brg1 & 0x01) ? color : 0;
+               }
+               if(!hireso) {
+                       if(config.scan_line) {
+                               memset(graph[y + 1], 0, 640);
                        } else {
-                               uint8 attrib = crtc.attrib.expand[cy][cx];
-                               color = (attrib & 0xe0) ? ((attrib >> 5) | color_mask) : 8;
+                               memcpy(graph[y + 1], graph[y], 640);
                        }
-                       uint8 brg = gvram_b[addr] | gvram_r[addr] | gvram_g[addr];
+               }
+       }
+}
+
+#if !defined(_PC8001SR)
+void PC88::draw_640x400_mono_graph()
+{
+       if(!Port31_GRAPH || (Port53_G0DS && Port53_G1DS)) {
+               memset(graph, 0, sizeof(graph));
+               return;
+       }
+       uint8_t *gvram_b = Port53_G0DS ? gvram_null : (gvram + 0x0000);
+       uint8_t *gvram_r = Port53_G1DS ? gvram_null : (gvram + 0x4000);
+       
+       for(int y = 0, addr = 0; y < 200; y++) {
+               for(int x = 0; x < 640; x += 8) {
+                       uint8_t b = gvram_b[addr];
                        addr++;
-                       uint8 *dest = &graph[y][x];
-                       dest[0] = (brg & 0x80) ? color : 0;
-                       dest[1] = (brg & 0x40) ? color : 0;
-                       dest[2] = (brg & 0x20) ? color : 0;
-                       dest[3] = (brg & 0x10) ? color : 0;
-                       dest[4] = (brg & 0x08) ? color : 0;
-                       dest[5] = (brg & 0x04) ? color : 0;
-                       dest[6] = (brg & 0x02) ? color : 0;
-                       dest[7] = (brg & 0x01) ? color : 0;
+                       uint8_t *dest = &graph[y][x];
+                       dest[0] = (b & 0x80) >> 7;
+                       dest[1] = (b & 0x40) >> 6;
+                       dest[2] = (b & 0x20) >> 5;
+                       dest[3] = (b & 0x10) >> 4;
+                       dest[4] = (b & 0x08) >> 3;
+                       dest[5] = (b & 0x04) >> 2;
+                       dest[6] = (b & 0x02) >> 1;
+                       dest[7] = (b & 0x01)     ;
+               }
+       }
+       for(int y = 200, addr = 0; y < 400; y++) {
+               for(int x = 0; x < 640; x += 8) {
+                       uint8_t r = gvram_r[addr];
+                       addr++;
+                       uint8_t *dest = &graph[y][x];
+                       dest[0] = (r & 0x80) >> 7;
+                       dest[1] = (r & 0x40) >> 6;
+                       dest[2] = (r & 0x20) >> 5;
+                       dest[3] = (r & 0x10) >> 4;
+                       dest[4] = (r & 0x08) >> 3;
+                       dest[5] = (r & 0x04) >> 2;
+                       dest[6] = (r & 0x02) >> 1;
+                       dest[7] = (r & 0x01)     ;
                }
        }
 }
-#else
+
 void PC88::draw_640x400_attrib_graph()
 {
        if(!Port31_GRAPH || (Port53_G0DS && Port53_G1DS)) {
                memset(graph, 0, sizeof(graph));
                return;
        }
-       uint8 *gvram_b = Port53_G0DS ? gvram_null : (gvram + 0x0000);
-       uint8 *gvram_r = Port53_G1DS ? gvram_null : (gvram + 0x4000);
-       
-       int char_height = crtc.char_height ? crtc.char_height : 16;
-       uint8 color_mask = Port30_COLOR ? 0 : 7, color;
+       uint8_t *gvram_b = Port53_G0DS ? gvram_null : (gvram + 0x0000);
+       uint8_t *gvram_r = Port53_G1DS ? gvram_null : (gvram + 0x4000);
        
        for(int y = 0, addr = 0; y < 200; y++) {
-               int cy = y / char_height;
                for(int x = 0, cx = 0; x < 640; x += 8, cx++) {
-                       if(Port30_40 && (cx & 1)) {
-                               // don't update color
-                       } else {
-                               uint8 attrib = crtc.attrib.expand[cy][cx];
-                               // for SORCERIAN music library (XM8 version 1.20)
-                               color = (attrib >> 5) | color_mask;
-//                             color = (attrib & 0xe0) ? ((attrib >> 5) | color_mask) : 8;
+                       uint8_t color = text_color[y >> 1][cx];
+                       uint8_t b = gvram_b[addr];
+                       if(text_reverse[y >> 1][cx]) {
+                               b ^= 0xff;
                        }
-                       uint8 b = gvram_b[addr];
                        addr++;
-                       uint8 *dest = &graph[y][x];
+                       uint8_t *dest = &graph[y][x];
                        dest[0] = (b & 0x80) ? color : 0;
                        dest[1] = (b & 0x40) ? color : 0;
                        dest[2] = (b & 0x20) ? color : 0;
@@ -2509,19 +2940,14 @@ void PC88::draw_640x400_attrib_graph()
                }
        }
        for(int y = 200, addr = 0; y < 400; y++) {
-               int cy = y / char_height;
                for(int x = 0, cx = 0; x < 640; x += 8, cx++) {
-                       if(Port30_40 && (cx & 1)) {
-                               // don't update color
-                       } else {
-                               uint8 attrib = crtc.attrib.expand[cy][cx];
-                               // for SORCERIAN music library (XM8 version 1.20)
-                               color = (attrib >> 5) | color_mask;
-//                             color = (attrib & 0xe0) ? ((attrib >> 5) | color_mask) : 8;
+                       uint8_t color = text_color[y >> 1][cx];
+                       uint8_t r = gvram_r[addr];
+                       if(text_reverse[y >> 1][cx]) {
+                               r ^= 0xff;
                        }
-                       uint8 r = gvram_r[addr];
                        addr++;
-                       uint8 *dest = &graph[y][x];
+                       uint8_t *dest = &graph[y][x];
                        dest[0] = (r & 0x80) ? color : 0;
                        dest[1] = (r & 0x40) ? color : 0;
                        dest[2] = (r & 0x20) ? color : 0;
@@ -2537,7 +2963,7 @@ void PC88::draw_640x400_attrib_graph()
 
 void PC88::request_intr(int level, bool status)
 {
-       uint8 bit = 1 << level;
+       uint8_t bit = 1 << level;
        
        if(status) {
                // for Nobunaga Fuunroku Opening & MID-GARTS Opening (XM8 version 1.00)
@@ -2559,9 +2985,9 @@ void PC88::update_intr()
        d_cpu->set_intr_line(((intr_req & intr_mask1 & intr_mask2) != 0), true, 0);
 }
 
-uint32 PC88::intr_ack()
+uint32_t PC88::get_intr_ack()
 {
-       uint8 ai = intr_req & intr_mask1 & intr_mask2;
+       uint8_t ai = intr_req & intr_mask1 & intr_mask2;
        
        for(int i = 0; i < 8; i++, ai >>= 1) {
                if(ai & 1) {
@@ -2573,7 +2999,7 @@ uint32 PC88::intr_ack()
        return 0;
 }
 
-void PC88::intr_ei()
+void PC88::notify_intr_ei()
 {
        update_intr();
 }
@@ -2588,7 +3014,6 @@ void pc88_crtc_t::reset(bool hireso)
        cursor.type = cursor.mode = -1;
        cursor.x = cursor.y = -1;
        attrib.data = 0xe0;
-       attrib.mask = 0xff;
        attrib.num = 20;
        width = 80;
        height = 25;
@@ -2600,23 +3025,26 @@ void pc88_crtc_t::reset(bool hireso)
        intr_mask = 3;
 }
 
-void pc88_crtc_t::write_cmd(uint8 data)
+void pc88_crtc_t::write_cmd(uint8_t data)
 {
        cmd = (data >> 5) & 7;
        cmd_ptr = 0;
        switch(cmd) {
        case 0: // reset
                status &= ~0x16;
+               status |= 0x80; // fix
                cursor.x = cursor.y = -1;
                break;
        case 1: // start display
                reverse = data & 1;
-               status |= 0x10;
+//             status |= 0x10;
+               status |= 0x90; // fix
                status &= ~8;
                break;
        case 2: // set interrupt mask
                if(!(data & 1)) {
-                       status = 0; // from M88
+//                     status = 0; // from M88
+                       status = 0x80; // fix
                }
                intr_mask = data & 3;
                break;
@@ -2635,7 +3063,7 @@ void pc88_crtc_t::write_cmd(uint8 data)
        }
 }
 
-void pc88_crtc_t::write_param(uint8 data)
+void pc88_crtc_t::write_param(uint8_t data)
 {
        switch(cmd) {
        case 0:
@@ -2680,13 +3108,16 @@ void pc88_crtc_t::write_param(uint8 data)
                        break;
                }
                break;
+       case 6:
+               status = 0;
+               break;
        }
        cmd_ptr++;
 }
 
-uint32 pc88_crtc_t::read_param()
+uint32_t pc88_crtc_t::read_param()
 {
-       uint32 val = 0xff;
+       uint32_t val = 0xff;
        
        switch(cmd) {
        case 3: // read light pen
@@ -2708,7 +3139,7 @@ uint32 pc88_crtc_t::read_param()
        return val;
 }
 
-uint32 pc88_crtc_t::read_status()
+uint32_t pc88_crtc_t::read_status()
 {
        if(status & 8) {
                return status & ~0x10;
@@ -2732,12 +3163,12 @@ void pc88_crtc_t::finish()
        vblank = true;
 }
 
-void pc88_crtc_t::write_buffer(uint8 data)
+void pc88_crtc_t::write_buffer(uint8_t data)
 {
        buffer[(buffer_ptr++) & 0x3fff] = data;
 }
 
-uint8 pc88_crtc_t::read_buffer(int ofs)
+uint8_t pc88_crtc_t::read_buffer(int ofs)
 {
        if(ofs < buffer_ptr) {
                return buffer[ofs];
@@ -2787,7 +3218,7 @@ void pc88_crtc_t::expand_buffer(bool hireso, bool line400)
                for(int cy = 0, ytop = 0, ofs = 0; cy < height && ytop < 200; cy++, ytop += char_height_tmp, ofs += 80 + attrib.num * 2) {
                        for(int cx = 0; cx < width; cx += 2) {
                                set_attrib(read_buffer(ofs + cx + 1));
-                               attrib.expand[cy][cx] = attrib.expand[cy][cx + 1] = attrib.data & attrib.mask;
+                               attrib.expand[cy][cx] = attrib.expand[cy][cx + 1] = attrib.data;
                        }
                        if((status & 8) && exitline == -1) {
                                exitline = cy;
@@ -2800,17 +3231,19 @@ void pc88_crtc_t::expand_buffer(bool hireso, bool line400)
                        memset(attrib.expand, 0xe0, sizeof(attrib.expand));
                } else {
                        for(int cy = 0, ytop = 0, ofs = 0; cy < height && ytop < 200; cy++, ytop += char_height_tmp, ofs += 80 + attrib.num * 2) {
-                               uint8 flags[128];
+                               uint8_t flags[128];
                                memset(flags, 0, sizeof(flags));
                                for(int i = 2 * (attrib.num - 1); i >= 0; i -= 2) {
                                        flags[read_buffer(ofs + i + 80) & 0x7f] = 1;
                                }
+                               attrib.data &= 0xf3; // for PC-8801mkIIFR \95t\91®\83f\83\82
+                               
                                for(int cx = 0, pos = 0; cx < width; cx++) {
                                        if(flags[cx]) {
                                                set_attrib(read_buffer(ofs + pos + 81));
                                                pos += 2;
                                        }
-                                       attrib.expand[cy][cx] = attrib.data & attrib.mask;
+                                       attrib.expand[cy][cx] = attrib.data;
                                }
                                if((status & 8) && exitline == -1) {
                                        exitline = cy;
@@ -2823,7 +3256,7 @@ void pc88_crtc_t::expand_buffer(bool hireso, bool line400)
                if((cursor.type & 1) && blink.cursor) {
                        // no cursor
                } else {
-                       static const uint8 ctype[5] = {0, 8, 8, 1, 1};
+                       static const uint8_t ctype[5] = {0, 8, 8, 1, 1};
                        attrib.expand[cursor.y][cursor.x] ^= ctype[cursor.type + 1];
                }
        }
@@ -2832,29 +3265,32 @@ underrun:
        if(exitline != -1) {
                for(int cy = exitline; cy < 200; cy++) {
                        memset(&text.expand[cy][0], 0, width);
-                       memset(&attrib.expand[cy][0], 0, width);
+#if 1
+                       // SORCERIAN Music Library ver-2.1
+                       memset(&attrib.expand[cy][0], 0xe0, width); // color=7
+#else
+                       // from ePC-8801MA\89ü
+                       memset(&attrib.expand[cy][0], 0x00, width);
+#endif
                }
        }
 }
 
-void pc88_crtc_t::set_attrib(uint8 code)
+void pc88_crtc_t::set_attrib(uint8_t code)
 {
        if(mode & 2) {
                // color
                if(code & 8) {
                        attrib.data = (attrib.data & 0x0f) | (code & 0xf0);
-                       attrib.mask = 0xf3; //for PC-8801mkIIFR \95t\91®\83f\83\82
                } else {
                        attrib.data = (attrib.data & 0xf0) | ((code >> 2) & 0x0d) | ((code << 1) & 2);
                        attrib.data ^= reverse;
                        attrib.data ^= ((code & 2) && !(code & 1)) ? blink.attrib : 0;
-                       attrib.mask = 0xff;
                }
        } else {
                attrib.data = 0xe0 | ((code >> 3) & 0x10) | ((code >> 2) & 0x0d) | ((code << 1) & 2);
                attrib.data ^= reverse;
                attrib.data ^= ((code & 2) && !(code & 1)) ? blink.attrib : 0;
-               attrib.mask = 0xff;
        }
 }
 
@@ -2862,7 +3298,7 @@ void pc88_crtc_t::set_attrib(uint8 code)
        DMAC (uPD8257)
 ---------------------------------------------------------------------------- */
 
-void pc88_dmac_t::write_io8(uint32 addr, uint32 data)
+void pc88_dmac_t::write_io8(uint32_t addr, uint32_t data)
 {
        int c = (addr >> 1) & 3;
        
@@ -2879,8 +3315,10 @@ void pc88_dmac_t::write_io8(uint32 addr, uint32 data)
                } else {
                        if((mode & 0x80) && c == 2) {
                                ch[3].addr.b.h = data;
+                               ch[3].addr.b.h2 = ch[3].addr.b.h3 = 0;
                        }
                        ch[c].addr.b.h = data;
+                       ch[c].addr.b.h2 = ch[c].addr.b.h3 = 0;
                }
                high_low = !high_low;
                break;
@@ -2896,9 +3334,11 @@ void pc88_dmac_t::write_io8(uint32 addr, uint32 data)
                } else {
                        if((mode & 0x80) && c == 2) {
                                ch[3].count.b.h = data & 0x3f;
+                               ch[3].count.b.h2 = ch[3].count.b.h3 = 0;
                                ch[3].mode = data & 0xc0;
                        }
                        ch[c].count.b.h = data & 0x3f;
+                       ch[c].count.b.h2 = ch[c].count.b.h3 = 0;
                        ch[c].mode = data & 0xc0;
                }
                high_low = !high_low;
@@ -2910,9 +3350,9 @@ void pc88_dmac_t::write_io8(uint32 addr, uint32 data)
        }
 }
 
-uint32 pc88_dmac_t::read_io8(uint32 addr)
+uint32_t pc88_dmac_t::read_io8(uint32_t addr)
 {
-       uint32 val = 0xff;
+       uint32_t val = 0xff;
        int c = (addr >> 1) & 3;
        
        switch(addr & 0x0f) {
@@ -2961,15 +3401,20 @@ void pc88_dmac_t::run(int c, int nbytes)
 {
        if(ch[c].running) {
                while(nbytes > 0 && ch[c].count.sd >= 0) {
-//                     if(ch[c].mode == 0x80) {
+                       if(ch[c].mode == 0x80) {
                                ch[c].io->write_dma_io8(0, mem->read_dma_data8(ch[c].addr.w.l));
-//                     } else if(ch[c].mode == 0x40) {
-//                             mem->write_dma_data8(ch[c].addr.w.l, ch[c].io->read_dma_io8(0));
-//                     }
+                       } else if(ch[c].mode == 0x40) {
+                               mem->write_dma_data8(ch[c].addr.w.l, ch[c].io->read_dma_io8(0));
+                       } else if(ch[c].mode == 0x00) {
+                               ch[c].io->read_dma_io8(0); // verify
+                       }
                        ch[c].addr.sd++;
                        ch[c].count.sd--;
                        nbytes--;
                }
+               if(ch[c].count.sd < 0) {
+                       finish(c);
+               }
        }
 }
 
@@ -2977,11 +3422,13 @@ void pc88_dmac_t::finish(int c)
 {
        if(ch[c].running) {
                while(ch[c].count.sd >= 0) {
-//                     if(ch[c].mode == 0x80) {
+                       if(ch[c].mode == 0x80) {
                                ch[c].io->write_dma_io8(0, mem->read_dma_data8(ch[c].addr.w.l));
-//                     } else if(ch[c].mode == 0x40) {
-//                             mem->write_dma_data8(ch[c].addr.w.l, ch[c].io->read_dma_io8(0));
-//                     }
+                       } else if(ch[c].mode == 0x40) {
+                               mem->write_dma_data8(ch[c].addr.w.l, ch[c].io->read_dma_io8(0));
+                       } else if(ch[c].mode == 0x00) {
+                               ch[c].io->read_dma_io8(0); // verify
+                       }
                        ch[c].addr.sd++;
                        ch[c].count.sd--;
                }
@@ -2997,212 +3444,185 @@ void pc88_dmac_t::finish(int c)
        }
 }
 
-#define STATE_VERSION  5
-
-void PC88::save_state(FILEIO* state_fio)
-{
-       state_fio->FputUint32(STATE_VERSION);
-       state_fio->FputInt32(this_device_id);
-       
-       state_fio->Fwrite(ram, sizeof(ram), 1);
-#if defined(PC88_EXRAM_BANKS)
-       state_fio->Fwrite(exram, sizeof(exram), 1);
-#endif
-       state_fio->Fwrite(gvram, sizeof(gvram), 1);
-       state_fio->Fwrite(tvram, sizeof(tvram), 1);
-       state_fio->Fwrite(port, sizeof(port), 1);
-       state_fio->Fwrite(&crtc, sizeof(crtc), 1);
-       state_fio->Fwrite(&dmac, sizeof(dmac), 1);
-       state_fio->Fwrite(alu_reg, sizeof(alu_reg), 1);
-       state_fio->FputUint8(gvram_plane);
-       state_fio->FputUint8(gvram_sel);
-       state_fio->FputBool(cpu_clock_low);
-#if defined(SUPPORT_PC88_HIGH_CLOCK)
-       state_fio->FputBool(cpu_clock_high_fe2);
-#endif
-       state_fio->FputBool(mem_wait_on);
-       state_fio->FputInt32(m1_wait_clocks);
-       state_fio->FputInt32(f000_m1_wait_clocks);
-       state_fio->FputInt32(mem_wait_clocks_r);
-       state_fio->FputInt32(mem_wait_clocks_w);
-       state_fio->FputInt32(tvram_wait_clocks_r);
-       state_fio->FputInt32(tvram_wait_clocks_w);
-       state_fio->FputInt32(gvram_wait_clocks_r);
-       state_fio->FputInt32(gvram_wait_clocks_w);
-       state_fio->FputInt32(busreq_clocks);
-       state_fio->Fwrite(palette, sizeof(palette), 1);
-       state_fio->FputBool(update_palette);
-       state_fio->FputBool(hireso);
-       state_fio->Fwrite(text, sizeof(text), 1);
-       state_fio->Fwrite(graph, sizeof(graph), 1);
-       state_fio->Fwrite(palette_text_pc, sizeof(palette_text_pc), 1);
-       state_fio->Fwrite(palette_graph_pc, sizeof(palette_graph_pc), 1);
-       state_fio->FputBool(usart_dcd);
-       state_fio->FputBool(opn_busy);
-       state_fio->FputUint8(key_caps);
-       state_fio->FputUint8(key_kana);
-#ifdef SUPPORT_PC88_JOYSTICK
-       state_fio->FputUint32(mouse_strobe_clock);
-       state_fio->FputUint32(mouse_strobe_clock_lim);
-       state_fio->FputInt32(mouse_phase);
-       state_fio->FputInt32(mouse_dx);
-       state_fio->FputInt32(mouse_dy);
-       state_fio->FputInt32(mouse_lx);
-       state_fio->FputInt32(mouse_ly);
-#endif
-       state_fio->FputUint8(intr_req);
-       state_fio->FputBool(intr_req_sound);
-#ifdef SUPPORT_PC88_SB2
-       state_fio->FputBool(intr_req_sb2);
-#endif
-       state_fio->FputUint8(intr_mask1);
-       state_fio->FputUint8(intr_mask2);
-       state_fio->FputBool(cmt_play);
-       state_fio->FputBool(cmt_rec);
-       state_fio->Fwrite(rec_file_path, sizeof(rec_file_path), 1);
-       if(cmt_rec && cmt_fio->IsOpened()) {
-               int length_tmp = (int)cmt_fio->Ftell();
-               cmt_fio->Fseek(0, FILEIO_SEEK_SET);
-               state_fio->FputInt32(length_tmp);
-               while(length_tmp != 0) {
-                       uint8 buffer[1024];
-                       int length_rw = min(length_tmp, (int)sizeof(buffer));
-                       cmt_fio->Fread(buffer, length_rw, 1);
-                       state_fio->Fwrite(buffer, length_rw, 1);
-                       length_tmp -= length_rw;
-               }
-       } else {
-               state_fio->FputInt32(0);
-       }
-       state_fio->FputInt32(cmt_bufptr);
-       state_fio->FputInt32(cmt_bufcnt);
-       state_fio->Fwrite(cmt_buffer, sizeof(cmt_buffer), 1);
-       state_fio->Fwrite(cmt_data_carrier, sizeof(cmt_data_carrier), 1);
-       state_fio->FputInt32(cmt_data_carrier_cnt);
-       state_fio->FputInt32(cmt_register_id);
-       state_fio->FputBool(beep_on);
-       state_fio->FputBool(beep_signal);
-       state_fio->FputBool(sing_signal);
-#ifdef SUPPORT_PC88_PCG8100
-       state_fio->FputUint16(pcg_addr);
-       state_fio->FputUint8(pcg_data);
-       state_fio->FputUint8(pcg_ctrl);
-       state_fio->Fwrite(pcg_pattern, sizeof(pcg_pattern), 1);
-#endif
-#ifdef NIPPY_PATCH
-       state_fio->FputBool(nippy_patch);
-#endif
-}
+#define STATE_VERSION  10
 
-bool PC88::load_state(FILEIO* state_fio)
+bool PC88::process_state(FILEIO* state_fio, bool loading)
 {
-       release_tape();
-       
-       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->StateArray(ram, sizeof(ram), 1);
 #if defined(PC88_EXRAM_BANKS)
-       state_fio->Fread(exram, sizeof(exram), 1);
-#endif
-       state_fio->Fread(gvram, sizeof(gvram), 1);
-       state_fio->Fread(tvram, sizeof(tvram), 1);
-       state_fio->Fread(port, sizeof(port), 1);
-       state_fio->Fread(&crtc, sizeof(crtc), 1);
-       state_fio->Fread(&dmac, sizeof(dmac), 1);
-       state_fio->Fread(alu_reg, sizeof(alu_reg), 1);
-       gvram_plane = state_fio->FgetUint8();
-       gvram_sel = state_fio->FgetUint8();
-       cpu_clock_low = state_fio->FgetBool();
+       state_fio->StateArray(exram, sizeof(exram), 1);
+#endif
+       state_fio->StateArray(gvram, sizeof(gvram), 1);
+       state_fio->StateArray(tvram, sizeof(tvram), 1);
+       state_fio->StateArray(port, sizeof(port), 1);
+       state_fio->StateValue(crtc.blink.rate);
+       state_fio->StateValue(crtc.blink.counter);
+       state_fio->StateValue(crtc.blink.cursor);
+       state_fio->StateValue(crtc.blink.attrib);
+       state_fio->StateValue(crtc.cursor.type);
+       state_fio->StateValue(crtc.cursor.mode);
+       state_fio->StateValue(crtc.cursor.x);
+       state_fio->StateValue(crtc.cursor.y);
+       state_fio->StateValue(crtc.attrib.data);
+       state_fio->StateValue(crtc.attrib.num);
+       state_fio->StateArray(&crtc.attrib.expand[0][0], sizeof(crtc.attrib.expand), 1);
+       state_fio->StateArray(&crtc.text.expand[0][0], sizeof(crtc.text.expand), 1);
+       state_fio->StateValue(crtc.width);
+       state_fio->StateValue(crtc.height);
+       state_fio->StateValue(crtc.char_height);
+       state_fio->StateValue(crtc.skip_line);
+       state_fio->StateValue(crtc.vretrace);
+       state_fio->StateValue(crtc.timing_changed);
+       state_fio->StateArray(crtc.buffer, sizeof(crtc.buffer), 1);
+       state_fio->StateValue(crtc.buffer_ptr);
+       state_fio->StateValue(crtc.cmd);
+       state_fio->StateValue(crtc.cmd_ptr);
+       state_fio->StateValue(crtc.mode);
+       state_fio->StateValue(crtc.reverse);
+       state_fio->StateValue(crtc.intr_mask);
+       state_fio->StateValue(crtc.status);
+       state_fio->StateValue(crtc.vblank);
+       for(int i = 0; i < array_length(dmac.ch); i++) {
+               state_fio->StateValue(dmac.ch[i].addr);
+               state_fio->StateValue(dmac.ch[i].count);
+               state_fio->StateValue(dmac.ch[i].mode);
+               state_fio->StateValue(dmac.ch[i].nbytes);
+               state_fio->StateValue(dmac.ch[i].running);
+       }
+       state_fio->StateValue(dmac.mode);
+       state_fio->StateValue(dmac.status);
+       state_fio->StateValue(dmac.high_low);
+       state_fio->StateArray(alu_reg, sizeof(alu_reg), 1);
+       state_fio->StateValue(gvram_plane);
+       state_fio->StateValue(gvram_sel);
+       state_fio->StateValue(cpu_clock_low);
 #if defined(SUPPORT_PC88_HIGH_CLOCK)
-       cpu_clock_high_fe2 = state_fio->FgetBool();
-#endif
-       mem_wait_on = state_fio->FgetBool();
-       m1_wait_clocks = state_fio->FgetInt32();
-       f000_m1_wait_clocks = state_fio->FgetInt32();
-       mem_wait_clocks_r = state_fio->FgetInt32();
-       mem_wait_clocks_w = state_fio->FgetInt32();
-       tvram_wait_clocks_r = state_fio->FgetInt32();
-       tvram_wait_clocks_w = state_fio->FgetInt32();
-       gvram_wait_clocks_r = state_fio->FgetInt32();
-       gvram_wait_clocks_w = state_fio->FgetInt32();
-       busreq_clocks = state_fio->FgetInt32();
-       state_fio->Fread(palette, sizeof(palette), 1);
-       update_palette = state_fio->FgetBool();
-       hireso = state_fio->FgetBool();
-       state_fio->Fread(text, sizeof(text), 1);
-       state_fio->Fread(graph, sizeof(graph), 1);
-       state_fio->Fread(palette_text_pc, sizeof(palette_text_pc), 1);
-       state_fio->Fread(palette_graph_pc, sizeof(palette_graph_pc), 1);
-       usart_dcd = state_fio->FgetBool();
-       opn_busy = state_fio->FgetBool();
-       key_caps = state_fio->FgetUint8();
-       key_kana = state_fio->FgetUint8();
+       state_fio->StateValue(cpu_clock_high_fe2);
+#endif
+       state_fio->StateValue(mem_wait_on);
+       state_fio->StateValue(m1_wait_clocks);
+       state_fio->StateValue(f000_m1_wait_clocks);
+       state_fio->StateValue(mem_wait_clocks_r);
+       state_fio->StateValue(mem_wait_clocks_w);
+       state_fio->StateValue(tvram_wait_clocks_r);
+       state_fio->StateValue(tvram_wait_clocks_w);
+       state_fio->StateValue(gvram_wait_clocks_r);
+       state_fio->StateValue(gvram_wait_clocks_w);
+       state_fio->StateValue(busreq_clocks);
+       for(int i = 0; i < array_length(palette); i++) {
+               state_fio->StateValue(palette[i].r);
+               state_fio->StateValue(palette[i].g);
+               state_fio->StateValue(palette[i].b);
+       }
+//     state_fio->StateValue(update_palette);
+       state_fio->StateValue(hireso);
+       state_fio->StateArray(&text[0][0], sizeof(text), 1);
+       state_fio->StateArray(&graph[0][0], sizeof(graph), 1);
+/*
+       for(int i = 0; i < 9; i++) {
+               state_fio->StateValue(palette_digital[i].b);
+               state_fio->StateValue(palette_digital[i].r);
+               state_fio->StateValue(palette_digital[i].g);
+               state_fio->StateValue(palette_analog [i].b);
+               state_fio->StateValue(palette_analog [i].r);
+               state_fio->StateValue(palette_analog [i].g);
+       }
+*/
+       state_fio->StateValue(usart_dcd);
+       state_fio->StateValue(opn_busy);
+       state_fio->StateValue(key_caps);
+       state_fio->StateValue(key_kana);
 #ifdef SUPPORT_PC88_JOYSTICK
-       mouse_strobe_clock = state_fio->FgetUint32();
-       mouse_strobe_clock_lim = state_fio->FgetUint32();
-       mouse_phase = state_fio->FgetInt32();
-       mouse_dx = state_fio->FgetInt32();
-       mouse_dy = state_fio->FgetInt32();
-       mouse_lx = state_fio->FgetInt32();
-       mouse_ly = state_fio->FgetInt32();
-#endif
-       intr_req = state_fio->FgetUint8();
-       intr_req_sound = state_fio->FgetBool();
+       state_fio->StateValue(mouse_strobe_clock);
+       state_fio->StateValue(mouse_strobe_clock_lim);
+       state_fio->StateValue(mouse_phase);
+       state_fio->StateValue(mouse_dx);
+       state_fio->StateValue(mouse_dy);
+       state_fio->StateValue(mouse_lx);
+       state_fio->StateValue(mouse_ly);
+#endif
+       state_fio->StateValue(intr_req);
+       state_fio->StateValue(intr_req_sound);
 #ifdef SUPPORT_PC88_SB2
-       intr_req_sb2 = state_fio->FgetBool();
-#endif
-       intr_mask1 = state_fio->FgetUint8();
-       intr_mask2 = state_fio->FgetUint8();
-       cmt_play = state_fio->FgetBool();
-       cmt_rec = state_fio->FgetBool();
-       state_fio->Fread(rec_file_path, sizeof(rec_file_path), 1);
-       int length_tmp = state_fio->FgetInt32();
-       if(cmt_rec) {
-               cmt_fio->Fopen(rec_file_path, FILEIO_READ_WRITE_NEW_BINARY);
-               while(length_tmp != 0) {
-                       uint8 buffer[1024];
-                       int length_rw = min(length_tmp, (int)sizeof(buffer));
-                       state_fio->Fread(buffer, length_rw, 1);
-                       if(cmt_fio->IsOpened()) {
-                               cmt_fio->Fwrite(buffer, length_rw, 1);
-                       }
-                       length_tmp -= length_rw;
-               }
-       }
-       cmt_bufptr = state_fio->FgetInt32();
-       cmt_bufcnt = state_fio->FgetInt32();
-       state_fio->Fread(cmt_buffer, sizeof(cmt_buffer), 1);
-       state_fio->Fread(cmt_data_carrier, sizeof(cmt_data_carrier), 1);
-       cmt_data_carrier_cnt = state_fio->FgetInt32();
-       cmt_register_id = state_fio->FgetInt32();
-       beep_on = state_fio->FgetBool();
-       beep_signal = state_fio->FgetBool();
-       sing_signal = state_fio->FgetBool();
+       state_fio->StateValue(intr_req_sb2);
+#endif
+       state_fio->StateValue(intr_mask1);
+       state_fio->StateValue(intr_mask2);
+       state_fio->StateValue(cmt_play);
+       state_fio->StateValue(cmt_rec);
+       state_fio->StateArray(rec_file_path, sizeof(rec_file_path), 1);
+       if(loading) {
+               int length_tmp = state_fio->FgetInt32_LE();
+               if(cmt_rec) {
+                       cmt_fio->Fopen(rec_file_path, FILEIO_READ_WRITE_NEW_BINARY);
+                       while(length_tmp != 0) {
+                               uint8_t buffer[1024];
+                               int length_rw = min(length_tmp, (int)sizeof(buffer));
+                               state_fio->Fread(buffer, length_rw, 1);
+                               if(cmt_fio->IsOpened()) {
+                                       cmt_fio->Fwrite(buffer, length_rw, 1);
+                               }
+                               length_tmp -= length_rw;
+                       }
+               }
+       } else {
+               if(cmt_rec && cmt_fio->IsOpened()) {
+                       int length_tmp = (int)cmt_fio->Ftell();
+                       cmt_fio->Fseek(0, FILEIO_SEEK_SET);
+                       state_fio->FputInt32_LE(length_tmp);
+                       while(length_tmp != 0) {
+                               uint8_t buffer[1024];
+                               int length_rw = min(length_tmp, (int)sizeof(buffer));
+                               cmt_fio->Fread(buffer, length_rw, 1);
+                               state_fio->Fwrite(buffer, length_rw, 1);
+                               length_tmp -= length_rw;
+                       }
+               } else {
+                       state_fio->FputInt32_LE(0);
+               }
+       }
+       state_fio->StateValue(cmt_bufptr);
+       state_fio->StateValue(cmt_bufcnt);
+       state_fio->StateArray(cmt_buffer, sizeof(cmt_buffer), 1);
+       state_fio->StateArray(cmt_data_carrier, sizeof(cmt_data_carrier), 1);
+       state_fio->StateValue(cmt_data_carrier_cnt);
+       state_fio->StateValue(cmt_register_id);
+       state_fio->StateValue(beep_on);
+       state_fio->StateValue(beep_signal);
+       state_fio->StateValue(sing_signal);
 #ifdef SUPPORT_PC88_PCG8100
-       pcg_addr = state_fio->FgetUint16();
-       pcg_data = state_fio->FgetUint8();
-       pcg_ctrl = state_fio->FgetUint8();
-       state_fio->Fread(pcg_pattern, sizeof(pcg_pattern), 1);
+       state_fio->StateValue(pcg_addr);
+       state_fio->StateValue(pcg_data);
+       state_fio->StateValue(pcg_ctrl);
+       state_fio->StateArray(pcg_pattern, sizeof(pcg_pattern), 1);
+#endif
+#ifdef SUPPORT_PC88_CDROM
+       state_fio->StateValue(cdda_register_id);
+       state_fio->StateValue(cdda_volume);
 #endif
 #ifdef NIPPY_PATCH
-       nippy_patch = state_fio->FgetBool();
+       state_fio->StateValue(nippy_patch);
 #endif
        
        // post process
-       dmac.mem = dmac.ch[2].io = this;
-       dmac.ch[0].io = dmac.ch[1].io = dmac.ch[3].io = vm->dummy;
+       if(loading) {
 #if defined(_PC8001SR)
-       update_n80_write();
-       update_n80_read();
+               update_n80_write();
+               update_n80_read();
 #else
-       update_low_memmap();
-       update_tvram_memmap();
+               update_low_memmap();
+               update_tvram_memmap();
 #endif
+               // force update palette when state file is loaded
+               update_palette = true;
+       }
        return true;
 }
-
+}
+