OSDN Git Service

[VM][WIP] Use namespace to devices per VMs.
[csp-qt/common_source_project-fm7.git] / source / src / vm / x1 / display.cpp
index 20bf6ea..6b4cb32 100644 (file)
        SHARP X1 Emulator 'eX1'
        SHARP X1twin Emulator 'eX1twin'
        SHARP X1turbo Emulator 'eX1turbo'
+       SHARP X1turboZ Emulator 'eX1turboZ'
 
        Origin : X1EMU by KM (kanji rom)
-                X-millenium by Yui (ank16 patch)
+                X-millenium by Yui (ank16 patch)
        Author : Takeda.Toshiya
        Date   : 2009.03.14-
 
-       [ display ]
+  [ display ]
 */
 
 #include "display.h"
-#ifdef _X1TURBO_FEATURE
 #include "../hd46505.h"
-#endif
 #include "../i8255.h"
 
+#ifdef _X1TURBO_FEATURE
+#define EVENT_AFTER_BLANK      0
+#endif
+
+namespace X1 {
+
 #ifdef _X1TURBOZ
 #define AEN    ((zmode1 & 0x80) != 0)
+#define C64    ((zmode1 & 0x10) != 0)
 #define APEN   ((zmode2 & 0x80) != 0)
 #define APRD   ((zmode2 & 0x08) != 0)
 #endif
 
-// from X-millenium
-
-static const uint16 ANKFONT7f_af[0x21 * 8] = {
-       0x0000, 0x3000, 0x247f, 0x6c24, 0x484c, 0xce4b, 0x0000, 0x0000,
-
-       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff,
-       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff,
-       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff,
-       0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff,
-       0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
-       0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
-       0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
-       0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
-       0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080,
-       0xc0c0, 0xc0c0, 0xc0c0, 0xc0c0, 0xc0c0, 0xc0c0, 0xc0c0, 0xc0c0,
-       0xe0e0, 0xe0e0, 0xe0e0, 0xe0e0, 0xe0e0, 0xe0e0, 0xe0e0, 0xe0e0,
-       0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0,
-       0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8,
-       0xfcfc, 0xfcfc, 0xfcfc, 0xfcfc, 0xfcfc, 0xfcfc, 0xfcfc, 0xfcfc,
-       0xfefe, 0xfefe, 0xfefe, 0xfefe, 0xfefe, 0xfefe, 0xfefe, 0xfefe,
-       0x0101, 0x0202, 0x0404, 0x0808, 0x1010, 0x2020, 0x4040, 0x8080,
-
-       0x0000, 0x0000, 0x0000, 0x0000, 0x00ff, 0x0000, 0x0000, 0x0000,
-       0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010,
-       0x1010, 0x1010, 0x1010, 0x1010, 0x00ff, 0x0000, 0x0000, 0x0000,
-       0x0000, 0x0000, 0x0000, 0x0000, 0x10ff, 0x1010, 0x1010, 0x1010,
-       0x1010, 0x1010, 0x1010, 0x1010, 0x10f0, 0x1010, 0x1010, 0x1010,
-       0x1010, 0x1010, 0x1010, 0x1010, 0x101f, 0x1010, 0x1010, 0x1010,
-       0x1010, 0x1010, 0x1010, 0x1010, 0x10ff, 0x1010, 0x1010, 0x1010,
-       0x0000, 0x0000, 0x0000, 0x0000, 0x10f0, 0x1010, 0x1010, 0x1010,
-       0x1010, 0x1010, 0x1010, 0x1010, 0x00f0, 0x0000, 0x0000, 0x0000,
-       0x1010, 0x1010, 0x1010, 0x1010, 0x001f, 0x0000, 0x0000, 0x0000,
-       0x0000, 0x0000, 0x0000, 0x0000, 0x101f, 0x1010, 0x1010, 0x1010,
-       0x0000, 0x0000, 0x0000, 0x0000, 0x4080, 0x2020, 0x1010, 0x1010,
-       0x1010, 0x1010, 0x0810, 0x0408, 0x0003, 0x0000, 0x0000, 0x0000,
-       0x1010, 0x1010, 0x2010, 0x4020, 0x0080, 0x0000, 0x0000, 0x0000,
-       0x0000, 0x0000, 0x0000, 0x0000, 0x0403, 0x0808, 0x1010, 0x1010,
-       0x8080, 0x4040, 0x2020, 0x1010, 0x0808, 0x0404, 0x0202, 0x0101
-};
-
-static const uint16 ANKFONTe0_ff[0x20 * 8] = {
-       0x0000, 0x7e3c, 0xffff, 0xdbdb, 0xffff, 0xe7db, 0x7eff, 0x003c,
-       0x0000, 0x423c, 0x8181, 0xa5a5, 0x8181, 0x99a5, 0x4281, 0x003c,
-       0x0000, 0x3810, 0x7c7c, 0xfefe, 0xfefe, 0x106c, 0x7c38, 0x0000,
-       0x0000, 0x6c00, 0xfefe, 0xfefe, 0xfefe, 0x7c7c, 0x1038, 0x0000,
-       0x0000, 0x1010, 0x3838, 0x7c7c, 0x7cfe, 0x387c, 0x1038, 0x0010,
-       0x0000, 0x3810, 0x7c7c, 0x5438, 0xfefe, 0x6cfe, 0x7c10, 0x0000,
-       0x0101, 0x0303, 0x0707, 0x0f0f, 0x1f1f, 0x3f3f, 0x7f7f, 0xffff,
-       0x8080, 0xc0c0, 0xe0e0, 0xf0f0, 0xf8f8, 0xfcfc, 0xfefe, 0xffff,
-       0x8181, 0x4242, 0x2424, 0x1818, 0x1818, 0x2424, 0x4242, 0x8181,
-       0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0x0000, 0x0000, 0x0000, 0x0000,
-       0x0000, 0x0000, 0x0000, 0x0000, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0,
-       0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0000, 0x0000, 0x0000, 0x0000,
-       0x0000, 0x0000, 0x0000, 0x0000, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f,
-       0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0,
-       0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f,
-       0x81ff, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0x8181, 0xff81,
-
-       0x55aa, 0x55aa, 0x55aa, 0x55aa, 0x55aa, 0x55aa, 0x55aa, 0x55aa,
-       0x1000, 0x1010, 0xf01e, 0x1010, 0x1010, 0x1010, 0x7e10, 0x00c0,
-       0x1000, 0x2418, 0x7c42, 0x1090, 0x781c, 0x5410, 0xfe54, 0x0000,
-       0x1000, 0x1010, 0xfe10, 0x1010, 0x3030, 0x565c, 0x9090, 0x0010,
-       0x1000, 0x1210, 0xf412, 0x3034, 0x5030, 0x9654, 0x1090, 0x0000,
-       0x0800, 0x8808, 0x5292, 0x1454, 0x2020, 0x5020, 0x465c, 0x0040,
-       0x0000, 0xe23c, 0x8282, 0x82fa, 0x7a82, 0x4242, 0x0044, 0x0000,
-       0x0000, 0x443c, 0x8242, 0xf282, 0x8282, 0x8282, 0x3844, 0x0000,
-       0x0800, 0x5e18, 0xa468, 0xe4be, 0xbea4, 0xb2a2, 0x0a5a, 0x0002,
-       0x0000, 0x2628, 0x4042, 0xe23c, 0x2222, 0x4222, 0x4442, 0x0004,
-       0x0800, 0x0808, 0xda7a, 0x5454, 0x46e4, 0xe442, 0x08c4, 0x0000,
-       0x0000, 0x7e40, 0x8848, 0x28be, 0x2828, 0x3e28, 0x08e8, 0x0008,
-       0x0000, 0x723c, 0x9252, 0x9292, 0x8292, 0x84fc, 0x8484, 0x0000,
-       0x0000, 0x1010, 0x2010, 0x2020, 0x6040, 0x8c50, 0x8286, 0x0000,
-       0x0000, 0x4040, 0x784e, 0x88c0, 0x388e, 0x0848, 0x7e08, 0x0000,
-       0x0000, 0x7c00, 0x0000, 0x0000, 0x10fe, 0x1010, 0x1010, 0x0010
-};
-
 void DISPLAY::initialize()
 {
        // load rom images
        FILEIO* fio = new FILEIO();
        
        // ank8 (8x8)
-       if(fio->Fopen(emu->bios_path(_T("ANK8.ROM")), FILEIO_READ_BINARY)) {
+       if(fio->Fopen(create_local_path(_T("ANK8.ROM")), FILEIO_READ_BINARY)) {
                fio->Fread(font, sizeof(font), 1);
                fio->Fclose();
-       } else if(fio->Fopen(emu->bios_path(_T("FNT0808.X1")), FILEIO_READ_BINARY)) {
+       } else if(fio->Fopen(create_local_path(_T("FNT0808.X1")), FILEIO_READ_BINARY)) {
                // xmillenium rom
                fio->Fread(font, sizeof(font), 1);
                fio->Fclose();
        }
        
        // ank16 (8x16)
-       if(fio->Fopen(emu->bios_path(_T("ANK16.ROM")), FILEIO_READ_BINARY)) {
+       if(fio->Fopen(create_local_path(_T("ANK16.ROM")), FILEIO_READ_BINARY)) {
                fio->Fread(kanji, 0x1000, 1);
                fio->Fclose();
-       } else if(fio->Fopen(emu->bios_path(_T("FNT0816.X1")), FILEIO_READ_BINARY)) {
+       } else if(fio->Fopen(create_local_path(_T("FNT0816.X1")), FILEIO_READ_BINARY)) {
                // xmillenium rom
                fio->Fread(kanji, 0x1000, 1);
                fio->Fclose();
        }
-       memcpy(kanji + 0x7f * 16, ANKFONT7f_af, sizeof(ANKFONT7f_af));
+       memcpy(kanji + 0x7f * 16, ANKFONT7f_9f, sizeof(ANKFONT7f_9f));
        memcpy(kanji + 0xe0 * 16, ANKFONTe0_ff, sizeof(ANKFONTe0_ff));
        
        // kanji (16x16)
-       if(fio->Fopen(emu->bios_path(_T("KANJI.ROM")), FILEIO_READ_BINARY)) {
+       if(fio->Fopen(create_local_path(_T("KANJI.ROM")), FILEIO_READ_BINARY)) {
                fio->Fread(kanji + 0x1000, 0x4ac00, 1);
                fio->Fclose();
-       } else if(fio->Fopen(emu->bios_path(_T("FNT1616.X1")), FILEIO_READ_BINARY)) {
+       } else if(fio->Fopen(create_local_path(_T("FNT1616.X1")), FILEIO_READ_BINARY)) {
                // xmillenium rom
                fio->Fread(kanji + 0x1000, 0x4ac00, 1);
                fio->Fclose();
        }
        for(int ofs = 0x1000; ofs < 0x4bc00; ofs += 32) {
                // LRLR.. -> LL..RR..
-               uint8 buf[32];
+               uint8_t buf[32];
                for(int i = 0; i < 16; i++) {
                        buf[i     ] = kanji[ofs + i * 2    ];
                        buf[i + 16] = kanji[ofs + i * 2 + 1];
@@ -151,6 +81,24 @@ void DISPLAY::initialize()
                palette_pc[i    ] = RGB_COLOR((i & 2) ? 255 : 0, (i & 4) ? 255 : 0, (i & 1) ? 255 : 0); // text
                palette_pc[i + 8] = RGB_COLOR((i & 2) ? 255 : 0, (i & 4) ? 255 : 0, (i & 1) ? 255 : 0); // cg
        }
+#ifdef _X1TURBOZ
+       for(int i = 0; i < 8; i++) {
+               ztpal[i] = ((i & 1) ? 0x03 : 0) | ((i & 2) ? 0x0c : 0) | ((i & 4) ? 0x30 : 0);
+               zpalette_pc[i    ] = RGB_COLOR((i & 2) ? 255 : 0, (i & 4) ? 255 : 0, (i & 1) ? 255 : 0);        // text
+               zpalette_pc[i + 8] = RGB_COLOR((i & 2) ? 255 : 0, (i & 4) ? 255 : 0, (i & 1) ? 255 : 0);        // digital
+       }
+       for(int g = 0; g < 16; g++) {
+               for(int r = 0; r < 16; r++) {
+                       for(int b = 0; b < 16; b++) {
+                               int num = b + r * 16 + g * 256;
+                               zpal[num].b = b;
+                               zpal[num].r = r;
+                               zpal[num].g = g;
+                               zpalette_pc[num + 16] = RGB_COLOR((r * 255) / 15, (g * 255) / 15, (b * 255) / 15);
+                       }
+               }
+       }
+#endif
        
        // initialize regs
        pal[0] = 0xaa;
@@ -177,6 +125,27 @@ void DISPLAY::initialize()
        // register event
        register_frame_event(this);
        register_vline_event(this);
+
+       // Copy images to draw buffers.
+       my_memcpy(dr_text, text, sizeof(dr_text));
+       my_memcpy(dr_cg, cg, sizeof(dr_cg));
+       my_memcpy(dr_pri_line, pri_line, sizeof(dr_pri_line));
+       my_memcpy(dr_palette_pc, palette_pc, sizeof(dr_palette_pc));
+       dr_priority = priority;
+#ifdef _X1TURBOZ
+       dr_zpriority = zpriority;
+       my_memcpy(dr_zcg, zcg, sizeof(dr_zcg));
+       my_memcpy(dr_aen_line, aen_line, sizeof(dr_aen_line));
+       my_memcpy(dr_zpalette_pc, zpalette_pc, sizeof(zpalette_pc));
+       zpalette_pc[8 + 0] = zpalette_pc[16 + 0x000];
+       zpalette_pc[8 + 1] = zpalette_pc[16 + 0x00f];
+       zpalette_pc[8 + 2] = zpalette_pc[16 + 0x0f0];
+       zpalette_pc[8 + 3] = zpalette_pc[16 + 0x0ff];
+       zpalette_pc[8 + 4] = zpalette_pc[16 + 0xf00];
+       zpalette_pc[8 + 5] = zpalette_pc[16 + 0xf0f];
+       zpalette_pc[8 + 6] = zpalette_pc[16 + 0xff0];
+       zpalette_pc[8 + 7] = zpalette_pc[16 + 0xfff];
+#endif 
 }
 
 void DISPLAY::reset()
@@ -187,33 +156,46 @@ void DISPLAY::reset()
        hireso = true;
 #endif
 #ifdef _X1TURBOZ
-       for(int i = 0; i < 8; i++) {
-               palette_pc[i    ] = RGB_COLOR((i & 2) ? 255 : 0, (i & 4) ? 255 : 0, (i & 1) ? 255 : 0); // text
-               ztpal[i] = ((i & 1) ? 0x03 : 0) | ((i & 2) ? 3 : 0x0c) | ((i & 4) ? 0x30 : 0);
-       }
-       for(int g = 0; g < 16; g++) {
-               for(int r = 0; r < 16; r++) {
-                       for(int b = 0; b < 16; b++) {
-                               int num = b + r * 16 + g * 256;
-                               zpal[num].b = b;
-                               zpal[num].r = r;
-                               zpal[num].g = g;
-                               palette_pc[num + 16] = RGB_COLOR((r * 255) / 15, (g * 255) / 15, (b * 255) / 15);
-                       }
-               }
-       }
-       zmode1 = zpriority = zscroll = zmode2 = 0;
+       zmode1 = 0;
+       zpriority = 0;
+       zadjust = 0;
+       zmosaic = 0;
+       zchromakey = 0;
+       zscroll = 0;
+       zmode2 = 0;
        zpal_num = 0;
 #endif
        cur_line = cur_code = 0;
        vblank_clock = 0;
+       cur_vline = 0;
+       cur_blank = true;
        
        kaddr = kofs = kflag = 0;
        kanji_ptr = &kanji[0];
-}
 
+       // Copy images to draw buffers.
+       my_memcpy(dr_text, text, sizeof(dr_text));
+       my_memcpy(dr_cg, cg, sizeof(dr_cg));
+       my_memcpy(dr_pri_line, pri_line, sizeof(dr_pri_line));
+       my_memcpy(dr_palette_pc, palette_pc, sizeof(dr_palette_pc));
+       dr_priority = priority;
+#ifdef _X1TURBOZ
+       dr_zpriority = zpriority;
+       my_memcpy(dr_zcg, zcg, sizeof(dr_zcg));
+       my_memcpy(dr_aen_line, aen_line, sizeof(dr_aen_line));
+       my_memcpy(dr_zpalette_pc, zpalette_pc, sizeof(zpalette_pc));
+       zpalette_pc[8 + 0] = zpalette_pc[16 + 0x000];
+       zpalette_pc[8 + 1] = zpalette_pc[16 + 0x00f];
+       zpalette_pc[8 + 2] = zpalette_pc[16 + 0x0f0];
+       zpalette_pc[8 + 3] = zpalette_pc[16 + 0x0ff];
+       zpalette_pc[8 + 4] = zpalette_pc[16 + 0xf00];
+       zpalette_pc[8 + 5] = zpalette_pc[16 + 0xf0f];
+       zpalette_pc[8 + 6] = zpalette_pc[16 + 0xff0];
+       zpalette_pc[8 + 7] = zpalette_pc[16 + 0xfff];
+#endif 
+}
 
-void DISPLAY::write_io8(uint32 addr, uint32 data)
+void DISPLAY::write_io8(uint32_t addr, uint32_t data)
 {
        switch(addr & 0xff00) {
        case 0x0e00:
@@ -221,51 +203,66 @@ void DISPLAY::write_io8(uint32 addr, uint32 data)
                break;
        case 0x1000:
 #ifdef _X1TURBOZ
-               if(AEN && APEN && !APRD) {
-                       int num = ((data >> 4) & 0x0f) | ((addr << 4) & 0xff0);
-                       zpal[num].b = data & 0x0f;
-                       palette_pc[num + 16] = RGB_COLOR((zpal[num].r * 255) / 15, (zpal[num].g * 255) / 15, (zpal[num].b * 255) / 15);
-               } else if(AEN && APEN && APRD) {
-                       zpal_num = ((data >> 4) & 0x0f) | ((addr << 4) & 0xff0);
-               } else if(!AEN) {
+               if(AEN) {
+                       if(APEN && !APRD) {
+                               if(!cur_blank) {
+                                       // wait next blank
+                                       d_cpu->write_signal(SIG_CPU_BUSREQ, 1, 1);
+                               }
+                               int num = get_zpal_num(addr, data);
+                               zpal[num].b = data & 0x0f;
+                               zpalette_pc[num + 16] = RGB_COLOR((zpal[num].r * 255) / 15, (zpal[num].g * 255) / 15, (zpal[num].b * 255) / 15);
+                       } else if(APEN && APRD) {
+                               zpal_num = get_zpal_num(addr, data);
+                       }
+               } else
 #endif
+               {
                        pal[0] = data;
                        update_pal();
-#ifdef _X1TURBOZ
                }
-#endif
                break;
        case 0x1100:
 #ifdef _X1TURBOZ
-               if(AEN && APEN && !APRD) {
-                       int num = ((data >> 4) & 0x0f) | ((addr << 4) & 0xff0);
-                       zpal[num].r = data & 0x0f;
-                       palette_pc[num + 16] = RGB_COLOR((zpal[num].r * 255) / 15, (zpal[num].g * 255) / 15, (zpal[num].b * 255) / 15);
-//             } else if(AEN && APEN && APRD) {
-//                     zpal_num = ((data >> 4) & 0x0f) | ((addr << 4) & 0xff0);
-               } else if(!AEN) {
+               if(AEN) {
+                       if(APEN && !APRD) {
+                               if(!cur_blank) {
+                                       // wait next blank
+                                       d_cpu->write_signal(SIG_CPU_BUSREQ, 1, 1);
+                               }
+                               int num = get_zpal_num(addr, data);
+                               zpal[num].r = data & 0x0f;
+                               zpalette_pc[num + 16] = RGB_COLOR((zpal[num].r * 255) / 15, (zpal[num].g * 255) / 15, (zpal[num].b * 255) / 15);
+                       } else if(APEN && APRD) {
+//                             zpal_num = get_zpal_num(addr, data);
+                       }
+               } else
 #endif
+               {
                        pal[1] = data;
                        update_pal();
-#ifdef _X1TURBOZ
                }
-#endif
                break;
        case 0x1200:
 #ifdef _X1TURBOZ
-               if(AEN && APEN && !APRD) {
-                       int num = ((data >> 4) & 0x0f) | ((addr << 4) & 0xff0);
-                       zpal[num].g = data & 0x0f;
-                       palette_pc[num + 16] = RGB_COLOR((zpal[num].r * 255) / 15, (zpal[num].g * 255) / 15, (zpal[num].b * 255) / 15);
-//             } else if(AEN && APEN && APRD) {
-//                     zpal_num = ((data >> 4) & 0x0f) | ((addr << 4) & 0xff0);
-               } else if(!AEN) {
+               if(AEN) {
+                       if(APEN && !APRD) {
+                               if(!cur_blank) {
+                                       // wait next blank
+                                       d_cpu->write_signal(SIG_CPU_BUSREQ, 1, 1);
+                               }
+                               int num = get_zpal_num(addr, data);
+                               zpal[num].g = data & 0x0f;
+                               zpalette_pc[num + 16] = RGB_COLOR((zpal[num].r * 255) / 15, (zpal[num].g * 255) / 15, (zpal[num].b * 255) / 15);
+                       } else if(APEN && APRD) {
+//                             zpal_num = get_zpal_num(addr, data);
+                       }
+               } else
 #endif
+               {
                        pal[2] = data;
                        update_pal();
-#ifdef _X1TURBOZ
                }
-#endif
                break;
        case 0x1300:
                priority = data;
@@ -299,31 +296,53 @@ void DISPLAY::write_io8(uint32 addr, uint32 data)
                case 0x1fb0:
                        zmode1 = data;
                        break;
-               case 0x1fb1:
-               case 0x1fb2:
-               case 0x1fb3:
-               case 0x1fb4:
-               case 0x1fb5:
-               case 0x1fb6:
-               case 0x1fb7:
-                       ztpal[addr & 7] = data;
-                       palette_pc[addr & 7] = RGB_COLOR((((data >> 2) & 3) * 255) / 3, (((data >> 4) & 3) * 255) / 3, (((data >> 0) & 3) * 255) / 3);
+//             case 0x1fb8:
+               case 0x1fb9:
+               case 0x1fba:
+               case 0x1fbb:
+               case 0x1fbc:
+               case 0x1fbd:
+               case 0x1fbe:
+               case 0x1fbf:
+                       if(AEN) {
+                               ztpal[addr & 7] = data;
+                               zpalette_pc[addr & 7] = RGB_COLOR((((data >> 2) & 3) * 255) / 3, (((data >> 4) & 3) * 255) / 3, (((data >> 0) & 3) * 255) / 3);
+                       }
                        break;
                case 0x1fc0:
-                       zpriority = data;
+                       if(AEN) {
+                               zpriority = data;
+                       }
+                       break;
+               case 0x1fc1:
+                       if(AEN) {
+                               zadjust = data;
+                       }
+                       break;
+               case 0x1fc2:
+                       if(AEN) {
+                               zmosaic = data;
+                       }
+                       break;
+               case 0x1fc3:
+                       if(AEN) {
+                               zchromakey = data;
+                       }
                        break;
                case 0x1fc4:
-                       zscroll = data;
+                       if(AEN) {
+                               zscroll = data;
+                       }
                        break;
                case 0x1fc5:
-                       zmode2 = data;
+                       if(AEN) {
+                               zmode2 = data;
+                       }
                        break;
 #endif
                case 0x1fd0:
-//                     if((mode1 & 1) != (data & 1)) {
-                               d_crtc->set_horiz_freq((data & 1) ? 24860 : 15980);
-//                     }
                        mode1 = data;
+                       update_crtc();
 //                     hireso = !((mode1 & 3) == 0 || (mode1 & 3) == 2);
                        break;
                case 0x1fe0:
@@ -380,7 +399,7 @@ void DISPLAY::write_io8(uint32 addr, uint32 data)
        }
 }
 
-uint32 DISPLAY::read_io8(uint32 addr)
+uint32_t DISPLAY::read_io8(uint32_t addr)
 {
        switch(addr & 0xff00) {
        case 0x0e00:
@@ -420,20 +439,48 @@ uint32 DISPLAY::read_io8(uint32 addr)
                switch(addr) {
                case 0x1fb0:
                        return zmode1;
-               case 0x1fb1:
-               case 0x1fb2:
-               case 0x1fb3:
-               case 0x1fb4:
-               case 0x1fb5:
-               case 0x1fb6:
-               case 0x1fb7:
-                       return ztpal[addr & 7];
+//             case 0x1fb8:
+               case 0x1fb9:
+               case 0x1fba:
+               case 0x1fbb:
+               case 0x1fbc:
+               case 0x1fbd:
+               case 0x1fbe:
+               case 0x1fbf:
+                       if(AEN) {
+                               return ztpal[addr & 7];
+                       }
+                       break;
                case 0x1fc0:
-                       return zpriority;
+                       if(AEN) {
+                               return zpriority;
+                       }
+                       break;
+               case 0x1fc1:
+                       if(AEN) {
+                               return zadjust;
+                       }
+                       break;
+               case 0x1fc2:
+                       if(AEN) {
+                               return zmosaic;
+                       }
+                       break;
+               case 0x1fc3:
+                       if(AEN) {
+                               return zchromakey;
+                       }
+                       break;
                case 0x1fc4:
-                       return zscroll;
+                       if(AEN) {
+                               return zscroll;
+                       }
+                       break;
                case 0x1fc5:
-                       return zmode2;
+                       if(AEN) {
+                               return zmode2;
+                       }
+                       break;
                case 0x1fd0:
                        return mode1;
                case 0x1fe0:
@@ -485,18 +532,41 @@ uint32 DISPLAY::read_io8(uint32 addr)
        return 0xff;
 }
 
-void DISPLAY::write_signal(int id, uint32 data, uint32 mask)
+void DISPLAY::write_signal(int id, uint32_t data, uint32_t mask)
 {
        if(id == SIG_DISPLAY_VBLANK) {
                if(!(data & mask)) {
                        // enter vblank
-                       vblank_clock = current_clock();
+                       vblank_clock = get_current_clock();
                }
        } else if(id == SIG_DISPLAY_COLUMN40) {
                column40 = ((data & mask) != 0);
+               update_crtc();
        } else if(id == SIG_DISPLAY_DETECT_VBLANK) {
                // hack: cpu detects vblank
-               vblank_clock = current_clock();
+               vblank_clock = get_current_clock();
+       } else if(id == SIG_DISPLAY_DISP) {
+               bool prev = cur_blank;
+               cur_blank = ((data & mask) == 0); // blank = not disp
+               if(!prev && cur_blank) {
+                       // draw line at start of hblank
+#ifdef _X1TURBO_FEATURE
+                       if(hireso) {
+                               if(cur_vline < 400) {
+                                       draw_line(cur_vline);
+                               }
+                       } else {
+#endif
+                               if(cur_vline < 200) {
+                                       draw_line(cur_vline);
+                               }
+#ifdef _X1TURBO_FEATURE
+                       }
+                       // restart cpu after pcg/cgrom/zpal is accessed
+//                     d_cpu->write_signal(SIG_CPU_BUSREQ, 0, 0);
+                       register_event_by_clock(this, EVENT_AFTER_BLANK, 24, false, NULL);
+#endif
+               }
        }
 }
 
@@ -515,32 +585,126 @@ void DISPLAY::event_frame()
        int vt_total = ((regs[4] & 0x7f) + 1) * ch_height + (regs[5] & 0x1f);
        hireso = (vt_total > 400);
 #endif
+       int vlen;
+#ifdef _X1TURBO_FEATURE
+       vlen = (hireso) ? 400 : 200;
+#else
+       vlen = 200;
+#endif
+       if(vlen > 0) {
+               // Copy images to draw buffers.
+               my_memcpy(dr_text, text, sizeof(uint8_t) * vlen * (640 + 8));
+               my_memcpy(dr_cg, cg, sizeof(uint8_t) * vlen * 640);
+               my_memcpy(dr_pri_line, pri_line, sizeof(uint8_t) * vlen * 8 * 8);
+       }
+       my_memcpy(dr_palette_pc, palette_pc, sizeof(dr_palette_pc));
+       dr_priority = priority;
+       // initialize draw screen
+       memset(text, 0, sizeof(text));
+       memset(cg, 0, sizeof(cg));
+       memset(pri_line, 0, sizeof(pri_line));
+#ifdef _X1TURBOZ
+       if(vlen > 0) {
+       // Copy images to draw buffers.
+               my_memcpy(&(dr_zcg[0][0][0]), &(zcg[0][0][0]), sizeof(uint8_t) * vlen * 640);
+               //my_memcpy(dr_aen_line, aen_line, sizeof(bool) * vlen);
+       }
+       my_memcpy(dr_aen_line, aen_line, sizeof(aen_line));
+       dr_zpriority = zpriority;
+       my_memcpy(dr_zpalette_pc, zpalette_pc, sizeof(zpalette_pc));
+       zpalette_pc[8 + 0] = zpalette_pc[16 + 0x000];
+       zpalette_pc[8 + 1] = zpalette_pc[16 + 0x00f];
+       zpalette_pc[8 + 2] = zpalette_pc[16 + 0x0f0];
+       zpalette_pc[8 + 3] = zpalette_pc[16 + 0x0ff];
+       zpalette_pc[8 + 4] = zpalette_pc[16 + 0xf00];
+       zpalette_pc[8 + 5] = zpalette_pc[16 + 0xf0f];
+       zpalette_pc[8 + 6] = zpalette_pc[16 + 0xff0];
+       zpalette_pc[8 + 7] = zpalette_pc[16 + 0xfff];
+       
+       memset(zcg, 0, sizeof(zcg));
+       memset(aen_line, 0, sizeof(aen_line));
+#endif
+       prev_vert_double = false;
+       raster = 0;
 }
 
 void DISPLAY::event_vline(int v, int clock)
 {
+       cur_vline = v;
+
+#if 0
+       // Copy images to draw buffers.
+       int vlimit;
 #ifdef _X1TURBO_FEATURE
-       if(hireso) {
-               if(v < 400) {
-                       draw_line(v);
-               }
-       } else {
+       vlimit = (hireso) ? 400 : 200;
+#else
+       vlimit = 200;
 #endif
-               if(v < 200) {
-                       draw_line(v);
-               }
+       if((v > vlimit) || (v < 0)) return;
+       
+       if(v == vlimit) {
+               my_memcpy(dr_palette_pc, palette_pc, sizeof(palette_pc));
+#ifdef _X1TURBOZ
+               my_memcpy(dr_zpalette_pc, zpalette_pc, sizeof(zpalette_pc));
+#endif
+               // Copy images to draw buffers.
+               //my_memcpy(&(dr_text[v][0]), &(text[v][0]), sizeof(uint8_t) * (640 + 8));
+               //my_memcpy(&(dr_cg[v][0]), &(cg[v][0]), sizeof(uint8_t) * 640);
+               //my_memcpy(&(dr_pri_line[v][0][0]), &(pri_line[v][0][0]), sizeof(uint8_t) * 8 * 8);
+#ifdef _X1TURBOZ
+               //my_memcpy(&(dr_zcg[0][v][0]), &(zcg[0][v][0]), sizeof(uint8_t) * 640);
+               //my_memcpy(&(dr_zcg[1][v][0]), &(zcg[1][v][0]), sizeof(uint8_t) * 640);
+               //dr_aen_line[v] = aen_line[v];
+#endif
+       } else if(v == 0) {
+               return;
+       }
+       // Copy images to draw buffers.
+       my_memcpy(&(dr_text[v - 1][0]), &(text[v - 1][0]), sizeof(uint8_t) * (640 + 8));
+       my_memcpy(&(dr_cg[v - 1][0]), &(cg[v -1 ][0]), sizeof(uint8_t) * 640);
+       my_memcpy(&(dr_pri_line[v - 1][0][0]), &(pri_line[v - 1][0][0]), sizeof(uint8_t) * 8 * 8);
+       dr_priority = priority;
+#ifdef _X1TURBOZ
+       my_memcpy(&(dr_zcg[0][v - 1 ][0]), &(zcg[0][v - 1][0]), sizeof(uint8_t) * 640);
+       my_memcpy(&(dr_zcg[1][v - 1][0]), &(zcg[1][v - 1][0]), sizeof(uint8_t) * 640);
+       dr_zpriority = zpriority;
+       dr_aen_line[v - 1] = aen_line[v - 1];
+#endif
+#endif
+}
+
 #ifdef _X1TURBO_FEATURE
+void DISPLAY::event_callback(int event_id, int err)
+{
+       if(event_id == EVENT_AFTER_BLANK) {
+               // restart cpu after pcg/cgrom/zpal is accessed
+               d_cpu->write_signal(SIG_CPU_BUSREQ, 0, 0);
+       }
+}
+#endif
+
+void DISPLAY::update_crtc()
+{
+#ifdef _X1TURBO_FEATURE
+       if (column40) {
+               d_crtc->set_char_clock((mode1 & 1) ? VDP_CLOCK * 1.5 / 32.0 : VDP_CLOCK / 32.0);
+       } else {
+               d_crtc->set_char_clock((mode1 & 1) ? VDP_CLOCK * 1.5 / 16.0 : VDP_CLOCK / 16.0);
+       }
+#else
+       if (column40) {
+               d_crtc->set_char_clock(VDP_CLOCK / 32.0);
+       } else {
+               d_crtc->set_char_clock(VDP_CLOCK / 16.0);
        }
-       // restart cpu after pcg/cgrom is accessed
-       d_cpu->write_signal(SIG_CPU_BUSREQ, 0, 0);
 #endif
 }
 
 void DISPLAY::update_pal()
 {
-       uint8 pal2[8];
+       uint8_t pal2[8];
        for(int i = 0; i < 8; i++) {
-               uint8 bit = 1 << i;
+               uint8_t bit = 1 << i;
                pal2[i] = ((pal[0] & bit) ? 1 : 0) | ((pal[1] & bit) ? 2 : 0) | ((pal[2] & bit) ? 4 : 0) | 8;
        }
 #ifdef _X1TURBO_FEATURE
@@ -564,15 +728,15 @@ void DISPLAY::update_pal()
        }
 }
 
-uint8 DISPLAY::get_cur_font(uint32 addr)
+uint8_t DISPLAY::get_cur_font(uint32_t addr)
 {
 #ifdef _X1TURBO_FEATURE
        if(mode1 & 0x20) {
-               // wait next raster
+               // wait next blank
                d_cpu->write_signal(SIG_CPU_BUSREQ, 1, 1);
                
                // from X1EMU
-               uint16 vaddr;
+               uint16_t vaddr;
                if(!(vram_a[0x7ff] & 0x20)) {
                        vaddr = 0x7ff;
                } else if(!(vram_a[0x3ff] & 0x20)) {
@@ -584,11 +748,11 @@ uint8 DISPLAY::get_cur_font(uint32 addr)
                } else {
                        vaddr = 0x3ff;
                }
-               uint16 ank = vram_t[vaddr];
-               uint16 knj = vram_k[vaddr];
+               uint16_t ank = vram_t[vaddr];
+               uint16_t knj = vram_k[vaddr];
                
                if(knj & 0x80) {
-                       uint32 ofs = adr2knj_x1t((knj << 8) | ank);
+                       uint32_t ofs = adr2knj_x1t((knj << 8) | ank);
                        if(knj & 0x40) {
                                ofs += 16; // right
                        }
@@ -604,15 +768,15 @@ uint8 DISPLAY::get_cur_font(uint32 addr)
        return font[(cur_code << 3) | (cur_line & 7)];
 }
 
-void DISPLAY::get_cur_pcg(uint32 addr)
+void DISPLAY::get_cur_pcg(uint32_t addr)
 {
 #ifdef _X1TURBO_FEATURE
        if(mode1 & 0x20) {
-               // wait next raster
+               // wait next blank
                d_cpu->write_signal(SIG_CPU_BUSREQ, 1, 1);
                
                // from X1EMU
-               uint16 vaddr;
+               uint16_t vaddr;
                if(vram_a[0x7ff] & 0x20) {
                        vaddr = 0x7ff;
                } else if(vram_a[0x3ff] & 0x20) {
@@ -633,7 +797,7 @@ void DISPLAY::get_cur_pcg(uint32 addr)
                }
        } else
 #endif
-       get_cur_code_line();
+               get_cur_code_line();
 }
 
 void DISPLAY::get_cur_code_line()
@@ -641,9 +805,9 @@ void DISPLAY::get_cur_code_line()
 //#ifdef _X1TURBO_FEATURE
 //     int ht_clock = hireso ? 161 : 250;
 //#else
-       #define ht_clock 250
+#define ht_clock 250
 //#endif
-       int clock = passed_clock(vblank_clock);
+       int clock = get_passed_clock(vblank_clock);
        int vt_line = vt_disp * ch_height + (int)(clock / ht_clock);
        
        int addr = (hz_total * (clock % ht_clock)) / ht_clock;
@@ -659,123 +823,226 @@ void DISPLAY::get_cur_code_line()
 
 void DISPLAY::draw_line(int v)
 {
-       if(v == 0) {
-               memset(text, 0, sizeof(text));
-               memset(cg, 0, sizeof(cg));
-               prev_vert_double = false;
-               raster = 0;
-       }
        if((regs[8] & 0x30) != 0x30) {
                if((v % ch_height) == 0) {
                        draw_text(v / ch_height);
                }
-               draw_cg(v);
+#ifdef _X1TURBOZ
+               if(AEN && !hireso && column40) {
+                       draw_cg(v, 1);
+               }
+#endif
+               draw_cg(v, 0);
                memcpy(&pri_line[v][0][0], &pri[0][0], sizeof(pri));
-       } else {
-               memset(&pri_line[v][0][0], 0, sizeof(pri));
+//     } else {
+//             memset(&pri_line[v][0][0], 0, sizeof(pri));
        }
+#ifdef _X1TURBOZ
+       aen_line[v] = AEN;
+#endif
 }
 
 void DISPLAY::draw_screen()
 {
        // copy to real screen
+#ifdef _X1TURBOZ
+       dr_zpalette_pc[8 + 0] = dr_zpalette_pc[16 + 0x000];
+       dr_zpalette_pc[8 + 1] = dr_zpalette_pc[16 + 0x00f];
+       dr_zpalette_pc[8 + 2] = dr_zpalette_pc[16 + 0x0f0];
+       dr_zpalette_pc[8 + 3] = dr_zpalette_pc[16 + 0x0ff];
+       dr_zpalette_pc[8 + 4] = dr_zpalette_pc[16 + 0xf00];
+       dr_zpalette_pc[8 + 5] = dr_zpalette_pc[16 + 0xf0f];
+       dr_zpalette_pc[8 + 6] = dr_zpalette_pc[16 + 0xff0];
+       dr_zpalette_pc[8 + 7] = dr_zpalette_pc[16 + 0xfff];
+#endif
 #ifdef _X1TURBO_FEATURE
        if(hireso) {
                // 400 lines
+               emu->set_vm_screen_lines(400);
                if(column40) {
                        // 40 columns
                        for(int y = 0; y < 400; y++) {
-                               scrntype* dest = emu->screen_buffer(y);
-                               uint8* src_text = text[y];
-                               uint8* src_cg = cg[y];
-                               
-                               for(int x = 0, x2 = 0; x < 320; x++, x2 += 2) {
-                                       dest[x2] = dest[x2 + 1] = palette_pc[pri_line[y][src_cg[x]][src_text[x]]];
+                               scrntype_t* dest = emu->get_screen_buffer(y);
+                               uint8_t* src_text = dr_text[y];
+#ifdef _X1TURBOZ
+                               if(dr_aen_line[y]) {
+                                       uint16_t* src_cg0 = dr_zcg[0][y];
+                                       
+                                       for(int x = 0, x2 = 0; x < 320; x++, x2 += 2) {
+                                               uint16_t cg00 = src_cg0[x] | (src_cg0[x] >> 2);
+                                               
+                                               dest[x2] = dest[x2 + 1] = get_zpriority(src_text[x], cg00, cg00);
+                                       }
+                               } else {
+#endif
+                                       uint8_t* src_cg = dr_cg[y];
+                                       
+                                       for(int x = 0, x2 = 0; x < 320; x++, x2 += 2) {
+#ifdef _X1TURBOZ
+                                               dest[x2] = dest[x2 + 1] = dr_zpalette_pc[dr_pri_line[y][src_cg[x]][src_text[x]]];
+#else
+                                               dest[x2] = dest[x2 + 1] =  dr_palette_pc[dr_pri_line[y][src_cg[x]][src_text[x]]];
+#endif
+                                       }
+#ifdef _X1TURBOZ
                                }
+#endif
                        }
                } else {
                        // 80 columns
                        for(int y = 0; y < 400; y++) {
-                               scrntype* dest = emu->screen_buffer(y);
-                               uint8* src_text = text[y];
-                               uint8* src_cg = cg[y];
-                               
-                               for(int x = 0; x < 640; x++) {
-                                       dest[x] = palette_pc[pri_line[y][src_cg[x]][src_text[x]]];
+                               scrntype_t* dest = emu->get_screen_buffer(y);
+                               uint8_t* src_text = dr_text[y];
+#ifdef _X1TURBOZ
+                               if(dr_aen_line[y]) {
+                                       uint16_t* src_cg0 = dr_zcg[0][y];
+                                       
+                                       for(int x = 0; x < 640; x++) {
+                                               uint16_t cg00 = src_cg0[x] | (src_cg0[x] >> 2);
+                                               
+                                               dest[x] = get_zpriority(src_text[x], cg00, cg00);
+                                       }
+                               } else {
+#endif
+                                       uint8_t* src_cg = dr_cg[y];
+                                       
+                                       for(int x = 0; x < 640; x++) {
+#ifdef _X1TURBOZ
+                                               dest[x] = dr_zpalette_pc[dr_pri_line[y][src_cg[x]][src_text[x]]];
+#else
+                                               dest[x] =  dr_palette_pc[dr_pri_line[y][src_cg[x]][src_text[x]]];
+#endif
+                                       }
+#ifdef _X1TURBOZ
                                }
+#endif
                        }
                }
-               emu->screen_skip_line = false;
+               emu->screen_skip_line(false);
        } else {
 #endif
+               emu->set_vm_screen_lines(200);
                // 200 lines
+               emu->set_vm_screen_lines(200);
+               
                if(column40) {
                        // 40 columns
                        for(int y = 0; y < 200; y++) {
-                               scrntype* dest0 = emu->screen_buffer(y * 2 + 0);
-                               scrntype* dest1 = emu->screen_buffer(y * 2 + 1);
-                               uint8* src_text = text[y];
-                               uint8* src_cg = cg[y];
+                               scrntype_t* dest0 = emu->get_screen_buffer(y * 2 + 0);
+                               scrntype_t* dest1 = emu->get_screen_buffer(y * 2 + 1);
+                               uint8_t* src_text = dr_text[y];
+#ifdef _X1TURBOZ
+                               if(dr_aen_line[y]) {
+                                       uint16_t* src_cg0 = dr_zcg[0][y];
+                                       uint16_t* src_cg1 = dr_zcg[1][y];
+                                       
+                                       if(C64) {
+                                               for(int x = 0, x2 = 0; x < 320; x++, x2 += 2) {
+                                                       uint16_t cg00 = src_cg0[x] | (src_cg0[x] >> 2);
+                                                       uint16_t cg11 = src_cg1[x] | (src_cg1[x] >> 2);
+                                                       
+                                                       dest0[x2] = dest0[x2 + 1] = get_zpriority(src_text[x], cg00, cg11);
+                                               }
+                                       } else {
+                                               for(int x = 0, x2 = 0; x < 320; x++, x2 += 2) {
+                                                       uint16_t cg01 = src_cg0[x] | (src_cg1[x] >> 2);
+                                                       
+                                                       dest0[x2] = dest0[x2 + 1] = get_zpriority(src_text[x], cg01, cg01);
+                                               }
+                                       }
+                               } else {
+#endif
+                                       scrntype_t* dest = emu->get_screen_buffer(y);
+                                       uint8_t* src_cg = dr_cg[y];
                                
-                               for(int x = 0, x2 = 0; x < 320; x++, x2 += 2) {
-                                       dest0[x2] = dest0[x2 + 1] = palette_pc[pri_line[y][src_cg[x]][src_text[x]]];
+                                       for(int x = 0, x2 = 0; x < 320; x++, x2 += 2) {
+#ifdef _X1TURBOZ
+                                               dest0[x2] = dest0[x2 + 1] = dr_zpalette_pc[dr_pri_line[y][src_cg[x]][src_text[x]]];
+#else
+                                               dest0[x2] = dest0[x2 + 1] =  dr_palette_pc[dr_pri_line[y][src_cg[x]][src_text[x]]];
+#endif
+                                       }
+#ifdef _X1TURBOZ
                                }
+#endif
                                if(!config.scan_line) {
-                                       memcpy(dest1, dest0, 640 * sizeof(scrntype));
+                                       my_memcpy(dest1, dest0, 640 * sizeof(scrntype_t));
                                } else {
-                                       memset(dest1, 0, 640 * sizeof(scrntype));
+                                       memset(dest1, 0, 640 * sizeof(scrntype_t));
                                }
                        }
                } else {
                        // 80 columns
                        for(int y = 0; y < 200; y++) {
-                               scrntype* dest0 = emu->screen_buffer(y * 2 + 0);
-                               scrntype* dest1 = emu->screen_buffer(y * 2 + 1);
-                               uint8* src_text = text[y];
-                               uint8* src_cg = cg[y];
-                               
-                               for(int x = 0; x < 640; x++) {
-                                       dest0[x] = palette_pc[pri_line[y][src_cg[x]][src_text[x]]];
+                               scrntype_t* dest0 = emu->get_screen_buffer(y * 2 + 0);
+                               scrntype_t* dest1 = emu->get_screen_buffer(y * 2 + 1);
+                               uint8_t* src_text = dr_text[y];
+#ifdef _X1TURBOZ
+                               if(aen_line[y]) {
+                                       uint16_t* src_cg0 = dr_zcg[0][y];
+                                       
+                                       for(int x = 0; x < 640; x++) {
+                                               uint16_t cg00 = src_cg0[x] | (src_cg0[x] >> 2);
+                                               
+                                               dest0[x] = get_zpriority(src_text[x], cg00, cg00);
+                                       }
+                               } else {
+#endif
+                                       uint8_t* src_cg = dr_cg[y];
+                                       
+                                       for(int x = 0; x < 640; x++) {
+#ifdef _X1TURBOZ
+                                               dest0[x] = dr_zpalette_pc[dr_pri_line[y][src_cg[x]][src_text[x]]];
+#else
+                                               dest0[x] =  dr_palette_pc[dr_pri_line[y][src_cg[x]][src_text[x]]];
+#endif
+                                       }
+#ifdef _X1TURBOZ
                                }
+#endif
                                if(!config.scan_line) {
-                                       memcpy(dest1, dest0, 640 * sizeof(scrntype));
+                                       my_memcpy(dest1, dest0, 640 * sizeof(scrntype_t));
                                } else {
-                                       memset(dest1, 0, 640 * sizeof(scrntype));
+                                       memset(dest1, 0, 640 * sizeof(scrntype_t));
                                }
                        }
                }
-               emu->screen_skip_line = true;
+               emu->screen_skip_line(true);
 #ifdef _X1TURBO_FEATURE
        }
 #endif
+
 }
 
 void DISPLAY::draw_text(int y)
 {
        int width = column40 ? 40 : 80;
-       uint16 src = st_addr + hz_disp * y;
+       uint16_t src = st_addr + hz_disp * y;
        
        bool cur_vert_double = true;
-       uint8 prev_attr = 0, prev_pattern_b[32], prev_pattern_r[32], prev_pattern_g[32];
+       uint8_t prev_attr = 0, prev_pattern_b[32], prev_pattern_r[32], prev_pattern_g[32];
        
        for(int x = 0; x < hz_disp && x < width; x++) {
                src &= 0x7ff;
-               uint8 code = vram_t[src];
+               uint8_t code = vram_t[src];
 #ifdef _X1TURBO_FEATURE
-               uint8 knj = vram_k[src];
+               uint8_t knj = vram_k[src];
 #endif
-               uint8 attr = vram_a[src];
+               uint8_t attr = vram_a[src];
                src++;
                
-               uint8 col = attr & 7;
+               uint8_t col = attr & 7;
                bool reverse = ((attr & 8) != 0);
                bool blink = ((attr & 0x10) && (cblink & 0x20));
                reverse = (reverse != blink);
                
                // select pcg or ank
-               const uint8 *pattern_b, *pattern_r, *pattern_g;
+               const uint8_t *pattern_b, *pattern_r, *pattern_g;
 #ifdef _X1TURBO_FEATURE
                int shift = 0;
+               int max_line = 8;
+#else
+#define max_line 8
 #endif
                if(attr & 0x20) {
                        // pcg
@@ -784,6 +1051,7 @@ void DISPLAY::draw_text(int y)
                                pattern_b = gaiji_b[code >> 1];
                                pattern_r = gaiji_r[code >> 1];
                                pattern_g = gaiji_g[code >> 1];
+                               max_line = 16;
                        } else {
 #endif
                                pattern_b = pcg_b[code];
@@ -795,16 +1063,18 @@ void DISPLAY::draw_text(int y)
 #endif
 #ifdef _X1TURBO_FEATURE
                } else if(knj & 0x80) {
-                       uint32 ofs = adr2knj_x1t((knj << 8) | code);
+                       uint32_t ofs = adr2knj_x1t((knj << 8) | code);
                        if(knj & 0x40) {
                                ofs += 16; // right
                        }
                        pattern_b = pattern_r = pattern_g = &kanji[ofs];
                        shift = hireso ? ((ch_height >= 32) ? 1 : 0) : ((ch_height >= 16) ? 0 : -1);
+                       max_line = 16;
                } else if(hireso || (mode1 & 4)) {
                        // ank 8x16 or kanji
                        pattern_b = pattern_r = pattern_g = &kanji[code << 4];
                        shift = hireso ? ((ch_height >= 32) ? 1 : 0) : ((ch_height >= 16) ? 0 : -1);
+                       max_line = 16;
 #endif
                } else {
                        // ank 8x8
@@ -818,6 +1088,7 @@ void DISPLAY::draw_text(int y)
                
                // render character
                for(int l = 0; l < ch_height; l++) {
+                       uint8_t b, r, g;
                        int line = cur_vert_double ? raster + (l >> 1) : l;
 #ifdef _X1TURBO_FEATURE
                        if(shift == 1) {
@@ -829,11 +1100,14 @@ void DISPLAY::draw_text(int y)
                                }
                        }
 #endif
-                       uint8 b, r, g;
                        if((x & 1) && (prev_attr & 0x80)) {
                                b = prev_pattern_b[line] << 4;
                                r = prev_pattern_r[line] << 4;
                                g = prev_pattern_g[line] << 4;
+                       } else if(line >= max_line) {
+                               b = prev_pattern_b[line] = 0;
+                               r = prev_pattern_r[line] = 0;
+                               g = prev_pattern_g[line] = 0;
                        } else {
                                b = prev_pattern_b[line] = pattern_b[line];
                                r = prev_pattern_r[line] = pattern_r[line];
@@ -857,8 +1131,8 @@ void DISPLAY::draw_text(int y)
 #endif
                                break;
                        }
-                       uint8* d = &text[yy][x << 3];
-                       
+                       uint8_t* d = &text[yy][x << 3];
+               
                        if(attr & 0x80) {
                                // horizontal doubled char
                                d[ 0] = d[ 1] = ((b & 0x80) >> 7) | ((r & 0x80) >> 6) | ((g & 0x80) >> 5);
@@ -875,8 +1149,8 @@ void DISPLAY::draw_text(int y)
                                d[6] = ((b & 0x02) >> 1) | ((r & 0x02) >> 0) | ((g & 0x02) << 1);
                                d[7] = ((b & 0x01) >> 0) | ((r & 0x01) << 1) | ((g & 0x01) << 2);
                        }
+                       prev_attr = attr;
                }
-               prev_attr = attr;
        }
        if(cur_vert_double && !prev_vert_double) {
                prev_vert_double = true;
@@ -887,7 +1161,7 @@ void DISPLAY::draw_text(int y)
        }
 }
 
-void DISPLAY::draw_cg(int line)
+void DISPLAY::draw_cg(int line, int plane)
 {
        int width = column40 ? 40 : 80;
        
@@ -902,38 +1176,169 @@ void DISPLAY::draw_cg(int line)
        int ll = hireso ? (l >> 1) : l;
        
        if(mode1 & 4) {
-               ofs = (0x400 * (ll & 15)) + (page ? 0xc000 : 0);
+               ofs = (0x400 * (ll & 15));// + (page ? 0xc000 : 0);
        } else {
-               ofs = (0x800 * (ll & 7)) + (page ? 0xc000 : 0);
+               ofs = (0x800 * (ll &  7));// + (page ? 0xc000 : 0);
        }
 #else
        ofs = 0x800 * (l & 7);
 #endif
-       int ofs_b = ofs + 0x0000;
-       int ofs_r = ofs + 0x4000;
-       int ofs_g = ofs + 0x8000;
-       
-       for(int x = 0; x < hz_disp && x < width; x++) {
-               src &= 0x7ff;
-               uint8 b = vram_ptr[ofs_b | src];
-               uint8 r = vram_ptr[ofs_r | src];
-               uint8 g = vram_ptr[ofs_g | src++];
-               uint8* d = &cg[line][x << 3];
+#ifdef _X1TURBOZ
+       if(AEN) {
+/*
+  HIRESO=0, WIDTH=40, C64=0: 320x200, 4096     PAGE0:(ADDR 000h-3FFh) + PAGE0:(ADDR 400h-7FFh) + PAGE1:(ADDR 000h-3FFh) + PAGE1:(ADDR 400h-7FFh)
+  HIRESO=0, WIDTH=40, C64=1: 320x200, 64x2     PAGE0:(ADDR 000h-3FFh) + PAGE0:(ADDR 400h-7FFh) / PAGE1:(ADDR 000h-3FFh) + PAGE1:(ADDR 400h-7FFh)
+  HIRESO=1, WIDTH=40, C64=*: 320x200, 64               PAGE*:(ADDR 000h-3FFh) + PAGE*:(ADDR 400h-7FFh)
+  HIRESO=0, WIDTH=80, C64=*: 640x200, 64               PAGE0:(ADDR 000h-7FFh) + PAGE1:(ADDR 000h-7FFh)
+  HIRESO=1, WIDTH=80, C64=*: 640x200, 8                PAGE0:(ADDR 000h-7FFh) + PAGE0:(ADDR 000h-7FFh)
+
+  HIRESO=0, WIDTH=40, C64=1: 320x200, 64x2
+  mode1        zpriority       
+  SCREEN 0     00      00              PAGE0
+  SCREEM 2     18      08              PAGE1
+  SCREEN 4     00      10              PAGE0 > PAGE1
+  SCREEN 6     18      18              PAGE0 < PAGE1
+*/
+               if(!hireso) {
+                       if(column40) {
+                               if(C64 && !(zpriority & 0x10)) {
+                                       if(plane) {
+                                               my_memcpy(zcg[plane][1], zcg[plane][0], sizeof(uint16_t) * 640);
+                                               return;
+                                       }
+                               } else {
+                                       page = plane;
+                               }
+                       } else {
+                               page = 0;
+                       }
+               }
+               if(page) {
+                       ofs += 0xc000;
+               }
+               int ofs_b0 = ofs + 0x0000;
+               int ofs_r0 = ofs + 0x4000;
+               int ofs_g0 = ofs + 0x8000;
+               int ofs_b1 = column40 ? (ofs_b0 ^ 0x400) : hireso ? ofs_b0 : (ofs_b0 + 0xc000);
+               int ofs_r1 = column40 ? (ofs_r0 ^ 0x400) : hireso ? ofs_r0 : (ofs_r0 + 0xc000);
+               int ofs_g1 = column40 ? (ofs_g0 ^ 0x400) : hireso ? ofs_g0 : (ofs_g0 + 0xc000);
+               
+               for(int x = 0; x < hz_disp && x < width; x++) {
+                       src &= column40 ? 0x3ff : 0x7ff;
+                       uint16_t b0 = vram_ptr[ofs_b0 | src];
+                       uint16_t r0 = vram_ptr[ofs_r0 | src];
+                       uint16_t g0 = vram_ptr[ofs_g0 | src];
+                       uint16_t b1 = vram_ptr[ofs_b1 | src];
+                       uint16_t r1 = vram_ptr[ofs_r1 | src];
+                       uint16_t g1 = vram_ptr[ofs_g1 | src++];
+                       uint16_t* d = &zcg[plane][line][x << 3];
+                       
+                       // MSB <- G0,G1,0,0, R0,R1,0,0, B0,B1,0,0 -> LSB
+                       d[0] = ((b0 & 0x80) >> 4) | ((b1 & 0x80) >> 5) | ((r0 & 0x80) >> 0) | ((r1 & 0x80) >> 1) | ((g0 & 0x80) <<  4) | ((g1 & 0x80) <<  3);
+                       d[1] = ((b0 & 0x40) >> 3) | ((b1 & 0x40) >> 4) | ((r0 & 0x40) << 1) | ((r1 & 0x40) >> 0) | ((g0 & 0x40) <<  5) | ((g1 & 0x40) <<  4);
+                       d[2] = ((b0 & 0x20) >> 2) | ((b1 & 0x20) >> 3) | ((r0 & 0x20) << 2) | ((r1 & 0x20) << 1) | ((g0 & 0x20) <<  6) | ((g1 & 0x20) <<  5);
+                       d[3] = ((b0 & 0x10) >> 1) | ((b1 & 0x10) >> 2) | ((r0 & 0x10) << 3) | ((r1 & 0x10) << 2) | ((g0 & 0x10) <<  7) | ((g1 & 0x10) <<  6);
+                       d[4] = ((b0 & 0x08) >> 0) | ((b1 & 0x08) >> 1) | ((r0 & 0x08) << 4) | ((r1 & 0x08) << 3) | ((g0 & 0x08) <<  8) | ((g1 & 0x08) <<  7);
+                       d[5] = ((b0 & 0x04) << 1) | ((b1 & 0x04) >> 0) | ((r0 & 0x04) << 5) | ((r1 & 0x04) << 4) | ((g0 & 0x04) <<  9) | ((g1 & 0x04) <<  8);
+                       d[6] = ((b0 & 0x02) << 2) | ((b1 & 0x02) << 1) | ((r0 & 0x02) << 6) | ((r1 & 0x02) << 5) | ((g0 & 0x02) << 10) | ((g1 & 0x02) <<  9);
+                       d[7] = ((b0 & 0x01) << 3) | ((b1 & 0x01) << 2) | ((r0 & 0x01) << 7) | ((r1 & 0x01) << 6) | ((g0 & 0x01) << 11) | ((g1 & 0x01) << 10);
+               }
+       } else
+#endif
+       {
+#ifdef _X1TURBO_FEATURE
+               if(page) {
+                       ofs += 0xc000;
+               }
+#endif
+               int ofs_b = ofs + 0x0000;
+               int ofs_r = ofs + 0x4000;
+               int ofs_g = ofs + 0x8000;
                
-               d[0] = ((b & 0x80) >> 7) | ((r & 0x80) >> 6) | ((g & 0x80) >> 5);
-               d[1] = ((b & 0x40) >> 6) | ((r & 0x40) >> 5) | ((g & 0x40) >> 4);
-               d[2] = ((b & 0x20) >> 5) | ((r & 0x20) >> 4) | ((g & 0x20) >> 3);
-               d[3] = ((b & 0x10) >> 4) | ((r & 0x10) >> 3) | ((g & 0x10) >> 2);
-               d[4] = ((b & 0x08) >> 3) | ((r & 0x08) >> 2) | ((g & 0x08) >> 1);
-               d[5] = ((b & 0x04) >> 2) | ((r & 0x04) >> 1) | ((g & 0x04) >> 0);
-               d[6] = ((b & 0x02) >> 1) | ((r & 0x02) >> 0) | ((g & 0x02) << 1);
-               d[7] = ((b & 0x01) >> 0) | ((r & 0x01) << 1) | ((g & 0x01) << 2);
+               for(int x = 0; x < hz_disp && x < width; x++) {
+                       src &= 0x7ff;
+                       uint8_t b = vram_ptr[ofs_b | src];
+                       uint8_t r = vram_ptr[ofs_r | src];
+                       uint8_t g = vram_ptr[ofs_g | src++];
+                       uint8_t* d = &cg[line][x << 3];
+                       
+                       d[0] = ((b & 0x80) >> 7) | ((r & 0x80) >> 6) | ((g & 0x80) >> 5);
+                       d[1] = ((b & 0x40) >> 6) | ((r & 0x40) >> 5) | ((g & 0x40) >> 4);
+                       d[2] = ((b & 0x20) >> 5) | ((r & 0x20) >> 4) | ((g & 0x20) >> 3);
+                       d[3] = ((b & 0x10) >> 4) | ((r & 0x10) >> 3) | ((g & 0x10) >> 2);
+                       d[4] = ((b & 0x08) >> 3) | ((r & 0x08) >> 2) | ((g & 0x08) >> 1);
+                       d[5] = ((b & 0x04) >> 2) | ((r & 0x04) >> 1) | ((g & 0x04) >> 0);
+                       d[6] = ((b & 0x02) >> 1) | ((r & 0x02) >> 0) | ((g & 0x02) << 1);
+                       d[7] = ((b & 0x01) >> 0) | ((r & 0x01) << 1) | ((g & 0x01) << 2);
+               }
+       }
+}
+
+#ifdef _X1TURBOZ
+int DISPLAY::get_zpal_num(uint32_t addr, uint32_t data)
+{
+       int num = ((data >> 4) & 0x0f) | ((addr << 4) & 0xff0);
+       
+       if(hireso && !column40) {
+               // 8 colors
+               num &= 0x888;
+               num |= num >> 1;
+               num |= num >> 2;
+       } else if(!(!hireso && column40 && !C64)) {
+               // 64 colors
+               num &= 0xccc;
+               num |= num >> 2;
+       }
+       return num;
+}
+
+scrntype_t DISPLAY::get_zpriority(uint8_t text, uint16_t cg0, uint16_t cg1)
+{
+       if((mode2 & 8) && (text == (mode2 & 7))) {
+               int digital = ((cg0 >> 9) & 4) | ((cg0 >> 6) & 2) | ((cg0 >> 3) & 1);
+               if(!(dr_priority & (1 << digital))) {
+                       return 0;
+               }
        }
+       uint16_t fore = ((dr_zpriority & 0x18) != 0x18) ? cg0 : cg1;
+       uint16_t back = ((dr_zpriority & 0x18) != 0x18) ? cg1 : cg0;
+       uint16_t disp;
+       
+       switch(dr_zpriority & 0x13) {
+       case 0x00:
+       case 0x02:
+               disp = text ? text : (fore + 16);
+               break;
+       case 0x01:
+       case 0x03:
+               disp = fore ? (fore + 16) : text;
+               break;
+       case 0x10:
+               disp = text ? text : fore ? (fore + 16) : (back + 16);
+               break;
+       case 0x11:
+               disp = fore ? (fore + 16) : back ? (back + 16) : text;
+               break;
+       case 0x12:
+               disp = fore ? (fore + 16) : text ? text : (back + 16);
+               break;
+       default: // undefined case :-(
+               disp = text ? text : fore ? (fore + 16) : (back + 16);
+               break;
+       }
+//     if((mode2 & 0x10) && disp == (0x000 + 16)) {
+//             return 0;
+//     }
+//     if((mode2 & 0x20) && disp == (0x00f + 16)) {
+//             return 0;
+//     }
+       return dr_zpalette_pc[disp];
 }
+#endif
 
 // kanji rom (from X1EMU by KM)
 
-void DISPLAY::write_kanji(uint32 addr, uint32 data)
+void DISPLAY::write_kanji(uint32_t addr, uint32_t data)
 {
        switch(addr) {
        case 0xe80:
@@ -949,12 +1354,12 @@ void DISPLAY::write_kanji(uint32 addr, uint32 data)
        }
 }
 
-uint32 DISPLAY::read_kanji(uint32 addr)
+uint32_t DISPLAY::read_kanji(uint32_t addr)
 {
        switch(addr) {
        case 0xe80:
                if(kaddr & 0xff00) {
-                       uint32 val = kanji_ptr[kofs];
+                       uint32_t val = kanji_ptr[kofs];
                        kflag |= 1;
                        if(kflag == 3) {
                                kofs = (kofs + 1) & 15;
@@ -965,7 +1370,7 @@ uint32 DISPLAY::read_kanji(uint32 addr)
                return jis2adr_x1(kaddr << 8) >> 8;
        case 0xe81:
                if(kaddr & 0xff00) {
-                       uint32 val = kanji_ptr[kofs + 16];
+                       uint32_t val = kanji_ptr[kofs + 16];
                        kflag |= 2;
                        if(kflag == 3) {
                                kofs = (kofs + 1) & 15;
@@ -978,9 +1383,9 @@ uint32 DISPLAY::read_kanji(uint32 addr)
        return 0xff;
 }
 
-uint16 DISPLAY::jis2adr_x1(uint16 jis)
+uint16_t DISPLAY::jis2adr_x1(uint16_t jis)
 {
-       uint16 jh, jl, adr;
+       uint16_t jh, jl, adr;
        
        jh = jis >> 8;
        jl = jis & 0xff;
@@ -995,9 +1400,9 @@ uint16 DISPLAY::jis2adr_x1(uint16 jis)
        return adr;
 }
 
-uint32 DISPLAY::adr2knj_x1(uint16 adr)
+uint32_t DISPLAY::adr2knj_x1(uint16_t adr)
 {
-       uint16 jh, jl, jis;
+       uint16_t jh, jl, jis;
        
        if(adr < 0x4000) {
                jh = adr - 0x0100;
@@ -1021,11 +1426,11 @@ uint32 DISPLAY::adr2knj_x1(uint16 adr)
 }
 
 #ifdef _X1TURBO_FEATURE
-uint32 DISPLAY::adr2knj_x1t(uint16 adr)
+uint32_t DISPLAY::adr2knj_x1t(uint16_t adr)
 {
-       uint16 j1, j2;
-       uint16 rl, rh;
-       uint16 jis;
+       uint16_t j1, j2;
+       uint16_t rl, rh;
+       uint16_t jis;
        
        rh = adr >> 8;
        rl = adr & 0xff;
@@ -1066,9 +1471,9 @@ uint32 DISPLAY::adr2knj_x1t(uint16 adr)
 }
 #endif
 
-uint32 DISPLAY::jis2knj(uint16 jis)
+uint32_t DISPLAY::jis2knj(uint16_t jis)
 {
-       uint32 sjis = jis2sjis(jis);
+       uint32_t sjis = jis2sjis(jis);
        
        if(sjis < 0x100) {
                return sjis * 16;
@@ -1083,9 +1488,9 @@ uint32 DISPLAY::jis2knj(uint16 jis)
        }
 }
 
-uint16 DISPLAY::jis2sjis(uint16 jis)
+uint16_t DISPLAY::jis2sjis(uint16_t jis)
 {
-       uint16 c1, c2;
+       uint16_t c1, c2;
        
        if(!jis) {
                return 0;
@@ -1108,117 +1513,135 @@ uint16 DISPLAY::jis2sjis(uint16 jis)
        return (c1 << 8) | c2;
 }
 
-#define STATE_VERSION  2
+#define STATE_VERSION  4
 
-void DISPLAY::save_state(FILEIO* state_fio)
+bool DISPLAY::process_state(FILEIO* state_fio, bool loading)
 {
-       state_fio->FputUint32(STATE_VERSION);
-       state_fio->FputInt32(this_device_id);
-       
-       state_fio->Fwrite(vram_t, sizeof(vram_t), 1);
-       state_fio->Fwrite(vram_a, sizeof(vram_a), 1);
+       if(!state_fio->StateCheckUint32(STATE_VERSION)) {
+               return false;
+       }
+       if(!state_fio->StateCheckInt32(this_device_id)) {
+               return false;
+       }
+       state_fio->StateBuffer(vram_t, sizeof(vram_t), 1);
+       state_fio->StateBuffer(vram_a, sizeof(vram_a), 1);
 #ifdef _X1TURBO_FEATURE
-       state_fio->Fwrite(vram_k, sizeof(vram_k), 1);
+       state_fio->StateBuffer(vram_k, sizeof(vram_k), 1);
 #endif
-       state_fio->Fwrite(pcg_b, sizeof(pcg_b), 1);
-       state_fio->Fwrite(pcg_r, sizeof(pcg_r), 1);
-       state_fio->Fwrite(pcg_g, sizeof(pcg_g), 1);
+       state_fio->StateBuffer(pcg_b, sizeof(pcg_b), 1);
+       state_fio->StateBuffer(pcg_r, sizeof(pcg_r), 1);
+       state_fio->StateBuffer(pcg_g, sizeof(pcg_g), 1);
 #ifdef _X1TURBO_FEATURE
-       state_fio->Fwrite(gaiji_b, sizeof(gaiji_b), 1);
-       state_fio->Fwrite(gaiji_r, sizeof(gaiji_r), 1);
-       state_fio->Fwrite(gaiji_g, sizeof(gaiji_g), 1);
-#endif
-       state_fio->FputUint8(cur_code);
-       state_fio->FputUint8(cur_line);
-       state_fio->FputInt32(kaddr);
-       state_fio->FputInt32(kofs);
-       state_fio->FputInt32(kflag);
-       state_fio->FputInt32((int)(kanji_ptr - &kanji[0]));
-       state_fio->Fwrite(pal, sizeof(pal), 1);
-       state_fio->FputUint8(priority);
-       state_fio->Fwrite(pri, sizeof(pri), 1);
-       state_fio->FputBool(column40);
+       state_fio->StateBuffer(gaiji_b, sizeof(gaiji_b), 1);
+       state_fio->StateBuffer(gaiji_r, sizeof(gaiji_r), 1);
+       state_fio->StateBuffer(gaiji_g, sizeof(gaiji_g), 1);
+#endif
+       state_fio->StateUint8(cur_code);
+       state_fio->StateUint8(cur_line);
+       state_fio->StateInt32(kaddr);
+       state_fio->StateInt32(kofs);
+       state_fio->StateInt32(kflag);
+       if(loading) {
+               kanji_ptr = &kanji[0] + state_fio->FgetInt32_LE();
+       } else {
+               state_fio->FputInt32_LE((int)(kanji_ptr - &kanji[0]));
+       }
+       state_fio->StateBuffer(pal, sizeof(pal), 1);
+       state_fio->StateUint8(priority);
+       state_fio->StateBuffer(pri, sizeof(pri), 1);
+       state_fio->StateBool(column40);
 #ifdef _X1TURBO_FEATURE
-       state_fio->FputUint8(mode1);
-       state_fio->FputUint8(mode2);
-       state_fio->FputBool(hireso);
+       state_fio->StateUint8(mode1);
+       state_fio->StateUint8(mode2);
+       state_fio->StateBool(hireso);
 #endif
 #ifdef _X1TURBOZ
-       state_fio->FputUint8(zmode1);
-       state_fio->FputUint8(zpriority);
-       state_fio->FputUint8(zscroll);
-       state_fio->FputUint8(zmode2);
-       state_fio->Fwrite(ztpal, sizeof(ztpal), 1);
-       state_fio->Fwrite(zpal, sizeof(zpal), 1);
-       state_fio->FputInt32(zpal_num);
-       state_fio->Fwrite(palette_pc, sizeof(palette_pc), 1);
-#endif
-       state_fio->FputBool(prev_vert_double);
-       state_fio->FputInt32(raster);
-       state_fio->FputInt32(cblink);
-       state_fio->FputInt32(ch_height);
-       state_fio->FputInt32(hz_total);
-       state_fio->FputInt32(hz_disp);
-       state_fio->FputInt32(vt_disp);
-       state_fio->FputInt32(st_addr);
-       state_fio->FputUint32(vblank_clock);
-}
-
-bool DISPLAY::load_state(FILEIO* state_fio)
-{
-       if(state_fio->FgetUint32() != STATE_VERSION) {
-               return false;
-       }
-       if(state_fio->FgetInt32() != this_device_id) {
-               return false;
+       state_fio->StateUint8(zmode1);
+       state_fio->StateUint8(zpriority);
+       state_fio->StateUint8(zadjust);
+       state_fio->StateUint8(zmosaic);
+       state_fio->StateUint8(zchromakey);
+       state_fio->StateUint8(zscroll);
+       state_fio->StateUint8(zmode2);
+       state_fio->StateBuffer(ztpal, sizeof(ztpal), 1);
+       //state_fio->StateBuffer(zpal, sizeof(zpal), 1);
+       for(int i = 0; i < 4096; i++) {
+               state_fio->StateUint8(zpal[i].b);
+               state_fio->StateUint8(zpal[i].r);
+               state_fio->StateUint8(zpal[i].g);
+       }                                                         
+       state_fio->StateInt32(zpal_num);
+       //state_fio->StateBuffer(zpalette_pc, sizeof(zpalette_pc), 1);
+       if(loading) {
+               for(int i = 0; i < (sizeof(zpalette_pc) / sizeof(scrntype_t)); i++) {
+                       uint8_t r, g, b;
+                       r = state_fio->FgetUint8();
+                       g = state_fio->FgetUint8();
+                       b = state_fio->FgetUint8();
+                       zpalette_pc[i] = RGB_COLOR(r, g, b);
+               }
+       } else {
+               for(int i = 0; i < (sizeof(zpalette_pc) / sizeof(scrntype_t)); i++) {
+                       uint8_t r, g, b;
+                       r = R_OF_COLOR(zpalette_pc[i]);
+                       g = G_OF_COLOR(zpalette_pc[i]);
+                       b = B_OF_COLOR(zpalette_pc[i]);
+                       state_fio->FputUint8(r);
+                       state_fio->FputUint8(g);
+                       state_fio->FputUint8(b);
+               }
        }
-       state_fio->Fread(vram_t, sizeof(vram_t), 1);
-       state_fio->Fread(vram_a, sizeof(vram_a), 1);
-#ifdef _X1TURBO_FEATURE
-       state_fio->Fread(vram_k, sizeof(vram_k), 1);
+
 #endif
-       state_fio->Fread(pcg_b, sizeof(pcg_b), 1);
-       state_fio->Fread(pcg_r, sizeof(pcg_r), 1);
-       state_fio->Fread(pcg_g, sizeof(pcg_g), 1);
-#ifdef _X1TURBO_FEATURE
-       state_fio->Fread(gaiji_b, sizeof(gaiji_b), 1);
-       state_fio->Fread(gaiji_r, sizeof(gaiji_r), 1);
-       state_fio->Fread(gaiji_g, sizeof(gaiji_g), 1);
-#endif
-       cur_code = state_fio->FgetUint8();
-       cur_line = state_fio->FgetUint8();
-       kaddr = state_fio->FgetInt32();
-       kofs = state_fio->FgetInt32();
-       kflag = state_fio->FgetInt32();
-       kanji_ptr = &kanji[0] + state_fio->FgetInt32();
-       state_fio->Fread(pal, sizeof(pal), 1);
-       priority = state_fio->FgetUint8();
-       state_fio->Fread(pri, sizeof(pri), 1);
-       column40 = state_fio->FgetBool();
+       state_fio->StateBool(prev_vert_double);
+       state_fio->StateInt32(raster);
+       state_fio->StateInt32(cblink);
+       state_fio->StateInt32(ch_height);
+       state_fio->StateInt32(hz_total);
+       state_fio->StateInt32(hz_disp);
+       state_fio->StateInt32(vt_disp);
+       state_fio->StateInt32(st_addr);
+       state_fio->StateUint32(vblank_clock);
+       state_fio->StateBool(cur_blank);
+       
+       // post process
+       if(loading) {
+               for(int i = 0; i < 8; i++) {
+                       palette_pc[i    ] = RGB_COLOR((i & 2) ? 255 : 0, (i & 4) ? 255 : 0, (i & 1) ? 255 : 0); // text
+                       palette_pc[i + 8] = RGB_COLOR((i & 2) ? 255 : 0, (i & 4) ? 255 : 0, (i & 1) ? 255 : 0); // cg
+               }
+               // Copy images to draw buffers.
+               my_memcpy(dr_text, text, sizeof(dr_text));
+               my_memcpy(dr_cg, cg, sizeof(dr_cg));
 #ifdef _X1TURBO_FEATURE
-       mode1 = state_fio->FgetUint8();
-       mode2 = state_fio->FgetUint8();
-       hireso = state_fio->FgetBool();
+               for(int v = 0; v < 400; v++) {
+                       memcpy(&pri_line[v][0][0], &pri[0][0], sizeof(pri));
+               }
+#else
+               for(int v = 0; v < 200; v++) {
+                       memcpy(&pri_line[v][0][0], &pri[0][0], sizeof(pri));
+               }
 #endif
+               my_memcpy(dr_pri_line, pri_line, sizeof(dr_pri_line));
+               my_memcpy(dr_palette_pc, palette_pc, sizeof(dr_palette_pc));
+               dr_priority = priority;
 #ifdef _X1TURBOZ
-       zmode1 = state_fio->FgetUint8();
-       zpriority = state_fio->FgetUint8();
-       zscroll = state_fio->FgetUint8();
-       zmode2 = state_fio->FgetUint8();
-       state_fio->Fread(ztpal, sizeof(ztpal), 1);
-       state_fio->Fread(zpal, sizeof(zpal), 1);
-       zpal_num = state_fio->FgetInt32();
-       state_fio->Fread(palette_pc, sizeof(palette_pc), 1);
-#endif
-       prev_vert_double = state_fio->FgetBool();
-       raster = state_fio->FgetInt32();
-       cblink = state_fio->FgetInt32();
-       ch_height = state_fio->FgetInt32();
-       hz_total = state_fio->FgetInt32();
-       hz_disp = state_fio->FgetInt32();
-       vt_disp = state_fio->FgetInt32();
-       st_addr = state_fio->FgetInt32();
-       vblank_clock = state_fio->FgetUint32();
-       return true;
+               dr_zpriority = zpriority;
+               my_memcpy(dr_zcg, zcg, sizeof(dr_zcg));
+               my_memcpy(dr_aen_line, aen_line, sizeof(dr_aen_line));
+               my_memcpy(dr_zpalette_pc, zpalette_pc, sizeof(zpalette_pc));
+               zpalette_pc[8 + 0] = zpalette_pc[16 + 0x000];
+               zpalette_pc[8 + 1] = zpalette_pc[16 + 0x00f];
+               zpalette_pc[8 + 2] = zpalette_pc[16 + 0x0f0];
+               zpalette_pc[8 + 3] = zpalette_pc[16 + 0x0ff];
+               zpalette_pc[8 + 4] = zpalette_pc[16 + 0xf00];
+               zpalette_pc[8 + 5] = zpalette_pc[16 + 0xf0f];
+               zpalette_pc[8 + 6] = zpalette_pc[16 + 0xff0];
+               zpalette_pc[8 + 7] = zpalette_pc[16 + 0xfff];
+#endif 
+               update_crtc(); // force update timing
+       }
+       return true;
 }
 
+}