]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
Merlin Z2/Z3 boards added. Blitter not yet functional. Some 86box updates.
authorToni Wilen <twilen@winuae.net>
Wed, 27 Mar 2024 19:25:33 +0000 (21:25 +0200)
committerToni Wilen <twilen@winuae.net>
Wed, 27 Mar 2024 19:25:33 +0000 (21:25 +0200)
12 files changed:
gfxboard.cpp
include/gfxboard.h
od-win32/winuae_msvc15/winuae_msvc.vcxproj
od-win32/winuae_msvc15/winuae_msvc.vcxproj.filters
pcem/vid_bt482_ramdac.cpp [new file with mode: 0644]
pcem/vid_et4000.h
pcem/vid_et4000w32.cpp [new file with mode: 0644]
pcem/vid_inmos.cpp
pcem/vid_permedia2.cpp
pcem/vid_sdac_ramdac.h
pcem/vid_svga.cpp
pcem/vid_svga.h

index b3b37fa216583bdf88b5bc848c59b7f93a6dde73..f60cdf48da0c8eba7a175c78baec0253191d1f76 100644 (file)
@@ -2,8 +2,9 @@
 * UAE - The Un*x Amiga Emulator
 *
 * Cirrus Logic based graphics board emulation
+* PCem/86box glue interface + boards.
 *
-* Copyright 2013 Toni Wilen
+* Copyright 2013-2024 Toni Wilen
 *
 */
 
@@ -295,6 +296,20 @@ static const struct gfxboard boards[] =
                0x00000000, 0x00100000, 0x00100000, 0x00100000, 0, 2, 0, false, false,
                0, 0, NULL, &et4000_domino_device
        },
+       {
+               GFXBOARD_ID_MERLIN_Z2,
+               _T("Merlin [Zorro II]"), _T("X-Pert Computer Services"), _T("MerlinZ2"),
+               2117, 3, 4, 0,
+               0x00000000, 0x00200000, 0x00200000, 0x00200000, 0, 2, 0, false, false,
+               0, 0, NULL, &et4000w32_merlin_z2_device
+       },
+       {
+               GFXBOARD_ID_MERLIN_Z3,
+               _T("Merlin [Zorro III]"), _T("X-Pert Computer Services"), _T("MerlinZ3"),
+               2117, 3, 4, 0,
+               0x00000000, 0x00200000, 0x00400000, 0x02000000, 0, 3, 0, false, false,
+               0, 0, NULL, &et4000w32_merlin_z3_device
+       },
        {
                GFXBOARD_ID_HARLEQUIN,
                _T("Harlequin [Zorro II]"), _T("ACS"), _T("Harlequin_PAL"),
@@ -2845,6 +2860,17 @@ static void REGPARAM2 gfxboard_wput_mem_autoconfig (uaecptr addr, uae_u32 b)
                                gb->configured_regs = gb->gfxmem_bank->start >> 16;
                                gb->gfxboard_external_interrupt = true;
 
+                       } else if (boardnum == GFXBOARD_ID_MERLIN_Z3) {
+
+                               map_banks_z3(&gb->gfxboard_bank_vram_pcem, start >> 16, gb->gfxboard_bank_vram_pcem.allocated_size >> 16);
+                               gb->pcem_mmio_offset = 0x1000000;
+                               gb->pcem_vram_mask = 0x3fffff;
+                               gb->pcem_vram_offset = 0x800000;
+                               map_banks_z3(&gb->gfxboard_bank_special_pcem, (start + 0x400000) >> 16, 0xc00000 >> 16);
+                               map_banks_z3(&gb->gfxboard_bank_special_pcem, (start + 0x1000000) >> 16, 0x1000000 >> 16);
+                               gb->pcem_mmio_mask = 0xffff;
+                               gb->configured_regs = gb->gfxmem_bank->start >> 16;
+
                        }
 
                } else {
@@ -6077,6 +6103,17 @@ static void special_pcem_put(uaecptr addr, uae_u32 v, int size)
                        put_io_pcem(addr, v & 0xff, 0);
                }
 
+       } else if (boardnum == GFXBOARD_ID_MERLIN_Z2 || boardnum == GFXBOARD_ID_MERLIN_Z3) {
+
+               addr &= 0xffff;
+
+               if (size) {
+                       put_io_pcem(addr + 0, (v >> 8) & 0xff, 0);
+                       put_io_pcem(addr + 1, (v >> 0) & 0xff, 0);
+               } else if (size == 0) {
+                       put_io_pcem(addr, v & 0xff, 0);
+               }
+
        } else if (boardnum == GFXBOARD_ID_EGS_110_24) {
 
                addr &= 0xffff;
@@ -6406,6 +6443,16 @@ static uae_u32 special_pcem_get(uaecptr addr, int size)
                        v = get_io_pcem(addr, 0);
                }
 
+       } else if (boardnum == GFXBOARD_ID_MERLIN_Z2 || boardnum == GFXBOARD_ID_MERLIN_Z3) {
+
+               addr &= 0xffff;
+               if (size) {
+                       v = get_io_pcem(addr + 0, 0) << 8;
+                       v |= get_io_pcem(addr + 1, 0) << 0;
+               } else if (size == 0) {
+                       v = get_io_pcem(addr, 0);
+               }
+
        } else if (boardnum == GFXBOARD_ID_EGS_110_24) {
 
                addr &= 0xffff;
index 749ebaea9b540c61b95b893d6be1fe6b78680331..489090482d8d17a600f7d1a73a884bb953a00b85 100644 (file)
@@ -90,7 +90,9 @@ int pcem_getvramsize(void);
 #define GFXBOARD_ID_VISIONA 27
 #define GFXBOARD_ID_EGS_110_24 28
 #define GFXBOARD_ID_DOMINO 29
-#define GFXBOARD_ID_VOODOO5_PCI 30
+#define GFXBOARD_ID_MERLIN_Z2 30
+#define GFXBOARD_ID_MERLIN_Z3 31
+#define GFXBOARD_ID_VOODOO5_PCI 32
 
 #define GFXBOARD_BUSTYPE_Z 0
 #define GFXBOARD_BUSTYPE_PCI 1
index 1085d6bba7c8572e03c0971bebe146dc03fcf2a9..1d0b9fc950eebd95f345aab7b3dbe41eec8556bf 100644 (file)
     <ClCompile Include="..\..\pcem\sound_sb_dsp.cpp" />
     <ClCompile Include="..\..\pcem\sound_speaker.cpp" />
     <ClCompile Include="..\..\pcem\timer.cpp" />
+    <ClCompile Include="..\..\pcem\vid_bt482_ramdac.cpp" />
     <ClCompile Include="..\..\pcem\vid_cl5429.cpp" />
     <ClCompile Include="..\..\pcem\vid_et4000.cpp" />
+    <ClCompile Include="..\..\pcem\vid_et4000w32.cpp" />
     <ClCompile Include="..\..\pcem\vid_inmos.cpp" />
     <ClCompile Include="..\..\pcem\vid_ncr.cpp" />
     <ClCompile Include="..\..\pcem\vid_permedia2.cpp" />
index 517f83222a94ab919b14ccc61c40f413bbd807bf..5869048a717b92b246a1108f71b6fce4c0936d26 100644 (file)
     <ClCompile Include="..\..\pcem\vid_sc1502x_ramdac.cpp">
       <Filter>pcem</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\pcem\vid_et4000w32.cpp">
+      <Filter>pcem</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\pcem\vid_bt482_ramdac.cpp">
+      <Filter>pcem</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <None Include="..\resources\35floppy.ico">
diff --git a/pcem/vid_bt482_ramdac.cpp b/pcem/vid_bt482_ramdac.cpp
new file mode 100644 (file)
index 0000000..38066ce
--- /dev/null
@@ -0,0 +1,282 @@
+
+/* BT482 RAMDAC (based on 86box BT484) */
+
+#include <memory>
+#include "ibm.h"
+#include "mem.h"
+#include "video.h"
+#include "vid_svga.h"
+#include "vid_sdac_ramdac.h"
+
+enum {
+    BT481 = 0,
+    BT482,
+};
+
+static void
+bt482_set_bpp(bt482_ramdac_t *ramdac, svga_t *svga)
+{
+    svga->swaprb = 0;
+    switch (ramdac->cmd_r0 >> 4) {
+        case 0x0f:
+            svga->bpp = 24;
+            svga->swaprb = (ramdac->cmd_r0 & 2) == 0;
+            break;
+        case 0x09:
+            svga->bpp = 32;
+            svga->swaprb = (ramdac->cmd_r0 & 2) == 0;
+            break;
+        case 0x0e:
+        case 0x0c:
+            svga->bpp = 16;
+            break;
+        case 0x08:
+        case 0x0a:
+            svga->bpp = 15;
+            break;
+        default:
+            svga->bpp = 8;
+            break;
+    }
+     svga_recalctimings(svga);
+}
+
+void
+bt482_ramdac_out(uint16_t addr, int rs2, uint8_t val, void *priv, svga_t *svga)
+{
+    bt482_ramdac_t *ramdac = (bt482_ramdac_t *) priv;
+    uint8_t         rs      = (addr & 0x03);
+    uint16_t        da_mask = 0x0ff;
+    rs |= (!!rs2 << 2);
+
+    switch (rs) {
+        case 0x00: /* Palette Write Index Register (RS value = 0000) */
+            svga->dac_pos    = 0;
+            svga->dac_status = addr & 0x03;
+            svga->dac_addr   = val;
+            svga->dac_write = val;
+            if (svga->dac_status)
+                svga->dac_addr = (svga->dac_addr + 1) & da_mask;
+            break;
+        case 0x01: /* Palette Data Register (RS value = 0001) */
+            svga_out(addr, val, svga);
+            break;
+        case 0x02:
+            if (ramdac->cmd_r0 & 1) {
+                switch(svga->dac_addr)
+                {
+                    case 2: // command B
+                        svga->ramdac_type = (val & 0x02) ? RAMDAC_8BIT : RAMDAC_6BIT;
+                        break;
+                    case 3: // cursor
+                        ramdac->cursor_r = val;
+                        svga->dac_hwcursor.xsize = 32;
+                        svga->dac_hwcursor.ysize = 32;
+                        svga->dac_hwcursor.ena = (val & 0x03) != 0;
+                        break;
+                    case 4: // cursor x low
+                        ramdac->hwc_x = (ramdac->hwc_x & 0x0f00) | val;
+                        svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.xsize;
+                        break;
+                    case 5: // cursor x high
+                        ramdac->hwc_x = (ramdac->hwc_x & 0x00ff) | ((val & 0x0f) << 8);
+                        svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.xsize;
+                        break;
+                    case 6: // cursor y low
+                        ramdac->hwc_y = (ramdac->hwc_y & 0x0f00) | val;
+                        svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.ysize;
+                        break;
+                    case 7: // cursor y high
+                        ramdac->hwc_y = (ramdac->hwc_y & 0x00ff) | ((val & 0x0f) << 8);
+                        svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.ysize;
+                        break;
+                }
+            } else {
+                // pixel mask
+            }
+            break;
+        case 0x04: // overlay and cursor color write
+            svga->dac_addr = val;
+            svga->dac_pos = 0;
+            break;
+        case 0x05: // overlay/cursor color
+            if (ramdac->cursor_r & (1 << 3)) {
+                ramdac->cursor32_data[svga->dac_addr] = val;
+                svga->dac_addr = (svga->dac_addr + 1) & da_mask;
+            } else {
+                ramdac->rgb[svga->dac_pos] = val;
+                svga->dac_pos++;
+                if (svga->dac_pos == 3) {
+                    ramdac->extpallook[svga->dac_addr & 3] = makecol32(ramdac->rgb[0], ramdac->rgb[1], ramdac->rgb[2]);
+                    svga->dac_addr++;
+                    svga->dac_pos = 0;
+                }
+            }
+            break;
+        case 0x06: /* Command Register A (RS value = 0110) */
+            ramdac->cmd_r0    = val;
+            bt482_set_bpp(ramdac, svga);
+            break;
+    }
+
+    return;
+}
+
+uint8_t
+bt482_ramdac_in(uint16_t addr, int rs2, void *priv, svga_t *svga)
+{
+    bt482_ramdac_t *ramdac = (bt482_ramdac_t *) priv;
+    uint8_t         temp   = 0xff;
+    uint8_t         rs      = (addr & 0x03);
+    uint16_t        da_mask = 0x00ff;
+    rs |= (!!rs2 << 2);
+
+    // TODO
+    switch (rs) {
+        case 0x00: /* Palette Write Index Register (RS value = 0000) */
+            temp = svga_in(addr, svga);
+            break;
+        case 0x03: /* Palette Read Index Register (RS value = 0011) */
+            temp = svga->dac_addr & 0xff;
+            break;
+        case 0x06: /* Command Register 0 (RS value = 0110) */
+            temp = ramdac->cmd_r0;
+            break;
+    }
+
+    return temp;
+}
+
+void
+bt482_recalctimings(void *priv, svga_t *svga)
+{
+    const bt482_ramdac_t *ramdac = (bt482_ramdac_t *) priv;
+}
+
+void
+bt482_hwcursor_draw(svga_t *svga, int displine)
+{
+    int             comb;
+    int             b0;
+    int             b1;
+    uint16_t        dat[2];
+    int             offset = svga->dac_hwcursor_latch.x - svga->dac_hwcursor_latch.xoff;
+    int             pitch;
+    int             bppl;
+    int             mode;
+    int             x_pos;
+    int             y_pos;
+    uint32_t        clr1;
+    uint32_t        clr2;
+    uint32_t        clr3;
+    uint32_t       *p;
+    const uint8_t  *cd;
+    bt482_ramdac_t *ramdac = (bt482_ramdac_t *) svga->ramdac;
+
+    clr1 = ramdac->extpallook[1];
+    clr2 = ramdac->extpallook[2];
+    clr3 = ramdac->extpallook[3];
+
+    /* The planes come in two parts, and each plane is 1bpp,
+       32x32 cursor has 4 bytes per line */
+    pitch = (svga->dac_hwcursor_latch.xsize >> 3); /* Bytes per line. */
+    /* A 32x32 cursor has 128 bytes per line */
+    bppl = (pitch * svga->dac_hwcursor_latch.ysize); /* Bytes per plane. */
+
+    if (svga->interlace && svga->dac_hwcursor_oddeven)
+        svga->dac_hwcursor_latch.addr += pitch;
+
+    cd = (uint8_t *) ramdac->cursor32_data;
+    mode = ramdac->cursor_r & 3;
+
+    for (int x = 0; x < svga->dac_hwcursor_latch.xsize; x += 16) {
+        dat[0] = (cd[svga->dac_hwcursor_latch.addr] << 8) | cd[svga->dac_hwcursor_latch.addr + 1];
+        dat[1] = (cd[svga->dac_hwcursor_latch.addr + bppl] << 8) | cd[svga->dac_hwcursor_latch.addr + bppl + 1];
+
+        for (uint8_t xx = 0; xx < 16; xx++) {
+            b0   = (dat[0] >> (15 - xx)) & 1;
+            b1   = (dat[1] >> (15 - xx)) & 1;
+            comb = (b0 | (b1 << 1));
+
+            y_pos = displine;
+            x_pos = offset + svga->x_add + 32;
+            p     = (uint32_t*)(buffer32->line[y_pos]);
+
+            if (offset >= svga->dac_hwcursor_latch.x) {
+                switch (mode) {
+                    case 1: /* Three Color */
+                        switch (comb) {
+                            case 1:
+                                p[x_pos] = clr1;
+                                break;
+                            case 2:
+                                p[x_pos] = clr2;
+                                break;
+                            case 3:
+                                p[x_pos] = clr3;
+                                break;
+
+                            default:
+                                break;
+                        }
+                        break;
+                    case 2: /* PM/Windows */
+                        switch (comb) {
+                            case 0:
+                                p[x_pos] = clr1;
+                                break;
+                            case 1:
+                                p[x_pos] = clr2;
+                                break;
+                            case 3:
+                                p[x_pos] ^= 0xffffff;
+                                break;
+
+                            default:
+                                break;
+                        }
+                        break;
+                    case 3: /* X-Windows */
+                        switch (comb) {
+                            case 2:
+                                p[x_pos] = clr1;
+                                break;
+                            case 3:
+                                p[x_pos] = clr2;
+                                break;
+
+                            default:
+                                break;
+                        }
+                        break;
+
+                    default:
+                        break;
+                }
+            }
+            offset++;
+        }
+        svga->dac_hwcursor_latch.addr += 2;
+    }
+
+    if (svga->interlace && !svga->dac_hwcursor_oddeven)
+        svga->dac_hwcursor_latch.addr += pitch;
+}
+
+void *
+bt482_ramdac_init(const device_t *info)
+{
+    bt482_ramdac_t *ramdac = (bt482_ramdac_t *) malloc(sizeof(bt482_ramdac_t));
+    memset(ramdac, 0, sizeof(bt482_ramdac_t));
+
+    return ramdac;
+}
+
+void
+bt482_ramdac_close(void *priv)
+{
+    bt482_ramdac_t *ramdac = (bt482_ramdac_t *) priv;
+
+    if (ramdac)
+        free(ramdac);
+}
index b88574de01567951a34fa2b123fd4ec7e3b5074f..4bc9414fc321e06ddfc008034bbdadad5c7f172a 100644 (file)
@@ -1 +1,3 @@
 extern device_t et4000_domino_device;
+extern device_t et4000w32_merlin_z2_device;
+extern device_t et4000w32_merlin_z3_device;
diff --git a/pcem/vid_et4000w32.cpp b/pcem/vid_et4000w32.cpp
new file mode 100644 (file)
index 0000000..f279e34
--- /dev/null
@@ -0,0 +1,3341 @@
+/*
+ * 86Box    A hypervisor and IBM PC system emulator that specializes in
+ *          running old operating systems and software designed for IBM
+ *          PC systems and compatibles from 1981 through fairly recent
+ *          system designs based on the PCI bus.
+ *
+ *          This file is part of the 86Box distribution.
+ *
+ *          ET4000/W32 series emulation.
+ *
+ * Known bugs: Accelerator doesn't work in planar modes
+ *
+ *
+ *
+ * Authors: Sarah Walker, <https://pcem-emulator.co.uk/>
+ *          Miran Grca, <mgrca8@gmail.com>
+ *
+ *          Copyright 2008-2019 Sarah Walker.
+ *          Copyright 2016-2019 Miran Grca.
+ */
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include "ibm.h"
+#include "device.h"
+#include "io.h"
+#include "pci.h"
+#include "mem.h"
+#include "rom.h"
+#include "thread.h"
+#include "video.h"
+#include "vid_svga.h"
+#include "vid_svga_render.h"
+#include "vid_sdac_ramdac.h"
+
+#define BIOS_ROM_PATH_DIAMOND                  "roms/video/et4000w32/et4000w32.bin"
+#define BIOS_ROM_PATH_CARDEX                   "roms/video/et4000w32/cardex.vbi"
+#define BIOS_ROM_PATH_W32                      "roms/video/et4000w32/ET4000W32VLB_bios_MX27C512.BIN"
+#define BIOS_ROM_PATH_W32I_ISA                 "roms/video/et4000w32/ET4KW32I.VBI"
+#define BIOS_ROM_PATH_W32I_VLB                 "roms/video/et4000w32/tseng.u41.bin"
+#define BIOS_ROM_PATH_W32P_VIDEOMAGIC_REVB_VLB "roms/video/et4000w32/VideoMagic-BioS-HXIRTW32PWSRL.BIN"
+#define BIOS_ROM_PATH_W32P                     "roms/video/et4000w32/ET4K_W32.BIN"
+#define BIOS_ROM_PATH_W32P_REVC                "roms/video/et4000w32/et4000w32pcardex.BIN"
+
+#define ACL_WRST                               1
+#define ACL_RDST                               2
+#define ACL_XYST                               4
+#define ACL_SSO                                8
+
+enum {
+    ET4000W32,
+    ET4000W32I,
+    ET4000W32P_REVC,
+    ET4000W32P_VIDEOMAGIC_REVB,
+    ET4000W32P,
+    ET4000W32P_CARDEX,
+    ET4000W32P_DIAMOND
+};
+
+typedef struct et4000w32p_t {
+    mem_mapping_t linear_mapping;
+    mem_mapping_t mmu_mapping;
+
+    void *ramdac;
+
+    rom_t bios_rom;
+
+    svga_t svga;
+
+    uint8_t banking, banking2, adjust_cursor, rev, pci_slot;
+
+    uint8_t regs[256], pci_regs[256];
+
+    int index, vlb, pci, interleaved,
+        bank, type;
+
+    uint32_t linearbase;
+    uint32_t vram_mask;
+
+    /* Accelerator */
+    struct {
+        struct {
+            uint8_t vbus, pixel_depth, xy_dir, pattern_wrap,
+                source_wrap, ctrl_routing, ctrl_reload, rop_fg,
+                rop_bg;
+
+            uint16_t pattern_off, source_off, dest_off, mix_off,
+                count_x, count_y, pos_x, pos_y,
+                error, dmin, dmaj;
+
+            uint32_t pattern_addr, source_addr, dest_addr, mix_addr;
+        } queued, internal;
+
+        uint8_t  suspend_terminate, osr;
+        uint8_t  status;
+        uint16_t x_count, y_count;
+        uint16_t cpu_x_cnt, cpu_x_cnt_back, cpu_y_cnt;
+
+        int pattern_x, source_x, pattern_x_back, source_x_back,
+            pattern_y, source_y, cpu_dat_pos, pix_pos,
+            cpu_input_num, fifo_queue;
+        int mmu_start;
+
+        uint32_t pattern_addr, source_addr, dest_addr, mix_addr,
+            pattern_back, source_back, dest_back, mix_back,
+            cpu_input;
+
+        uint64_t cpu_dat;
+    } acl;
+
+    struct {
+        uint32_t base[3];
+        uint8_t  ctrl;
+    } mmu;
+
+    bool blitter_mmio;
+    uint32_t blitter_mmio_addr;
+
+    volatile int busy;
+} et4000w32p_t;
+
+static int et4000w32_vbus[4] = { 1, 2, 4, 4 };
+
+static int et4000w32_max_x[8]  = { 0, 0, 4, 8, 0x10, 0x20, 0x40, 0x70000000 };
+static int et4000w32_wrap_x[8] = { 0, 0, 3, 7, 0x0f, 0x1f, 0x3f, ~0 };
+static int et4000w32_wrap_y[8] = { 1, 2, 4, 8, ~0, ~0, ~0, ~0 };
+
+//static video_timings_t timing_et4000w32_vlb = { .type = VIDEO_BUS, .write_b = 4, .write_w = 4, .write_l = 4, .read_b = 10, .read_w = 10, .read_l = 10 };
+//static video_timings_t timing_et4000w32_pci = { .type = VIDEO_PCI, .write_b = 4, .write_w = 4, .write_l = 4, .read_b = 10, .read_w = 10, .read_l = 10 };
+//static video_timings_t timing_et4000w32_isa = { .type = VIDEO_ISA, .write_b = 4, .write_w = 4, .write_l = 4, .read_b = 10, .read_w = 10, .read_l = 10 };
+
+void et4000w32p_recalcmapping(et4000w32p_t *et4000);
+
+static uint8_t et4000w32p_mmu_read(uint32_t addr, void *priv);
+static void    et4000w32p_mmu_write(uint32_t addr, uint8_t val, void *priv);
+
+static void et4000w32_blit_start(et4000w32p_t *et4000);
+static void et4000w32p_blit_start(et4000w32p_t *et4000);
+static void et4000w32_blit(int count, int cpu_input, uint32_t src_dat, uint32_t mix_dat, et4000w32p_t *et4000);
+static void et4000w32p_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input, et4000w32p_t *et4000);
+uint8_t     et4000w32p_in(uint16_t addr, void *priv);
+
+#define et4000w32_log pclog
+
+#ifdef ENABLE_ET4000W32_LOG
+int et4000w32_do_log = ENABLE_ET4000W32_LOG;
+
+static void
+et4000w32_log(const char *fmt, ...)
+{
+    va_list ap;
+
+    if (et4000w32_do_log) {
+        va_start(ap, fmt);
+        pclog_ex(fmt, ap);
+        va_end(ap);
+    }
+}
+#else
+//#    define et4000w32_log(fmt, ...)
+#endif
+
+void
+et4000w32p_out(uint16_t addr, uint8_t val, void *priv)
+{
+    et4000w32p_t *et4000 = (et4000w32p_t *) priv;
+    svga_t       *svga   = &et4000->svga;
+    uint8_t       old;
+    uint32_t      add2addr = 0;
+
+    if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1))
+        addr ^= 0x60;
+
+    switch (addr) {
+        case 0x3c2:
+//            if (et4000->type == ET4000W32P_DIAMOND)
+//                icd2061_write(svga->clock_gen, (val >> 2) & 3);
+            break;
+
+#if 0
+        case 0x3c6:
+        case 0x3c7:
+        case 0x3c8:
+        case 0x3c9:
+            if (et4000->type <= ET4000W32P_REVC)
+                sdac_ramdac_out(addr, val, &et4000->ramdac, svga);
+            else
+                stg_ramdac_out(addr, val, svga->ramdac, svga);
+            return;
+#endif
+        case 0x3cb: /* Banking extension */
+            if (!(svga->crtc[0x36] & 0x10) && !(svga->gdcreg[6] & 0x08)) {
+                svga->write_bank = (svga->write_bank & 0xfffff) | ((val & 1) << 20);
+                svga->read_bank  = (svga->read_bank & 0xfffff) | ((val & 0x10) << 16);
+            }
+            et4000->banking2 = val;
+            return;
+        case 0x3cd: /* Banking */
+            if (!(svga->crtc[0x36] & 0x10) && !(svga->gdcreg[6] & 0x08)) {
+                svga->write_bank = (svga->write_bank & 0x100000) | ((val & 0xf) * 65536);
+                svga->read_bank  = (svga->read_bank & 0x100000) | (((val >> 4) & 0xf) * 65536);
+            }
+            et4000->banking = val;
+            return;
+        case 0x3cf:
+            switch (svga->gdcaddr & 15) {
+                case 6:
+                    if (!(svga->crtc[0x36] & 0x10) && !(val & 0x08)) {
+                        svga->write_bank = ((et4000->banking2 & 1) << 20) | ((et4000->banking & 0xf) * 65536);
+                        svga->read_bank  = ((et4000->banking2 & 0x10) << 16) | (((et4000->banking >> 4) & 0xf) * 65536);
+                    } else
+                        svga->write_bank = svga->read_bank = 0;
+
+                    svga->gdcreg[svga->gdcaddr & 15] = val;
+                    et4000w32p_recalcmapping(et4000);
+                    return;
+
+                default:
+                    break;
+            }
+            break;
+        case 0x3d4:
+            svga->crtcreg = val & 0x3f;
+            return;
+        case 0x3d5:
+            if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80))
+                return;
+            if ((svga->crtcreg == 0x35) && (svga->crtc[0x11] & 0x80))
+                return;
+            if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80))
+                val = (svga->crtc[7] & ~0x10) | (val & 0x10);
+            old                       = svga->crtc[svga->crtcreg];
+            svga->crtc[svga->crtcreg] = val;
+            if (svga->crtcreg == 0x36) {
+                if (!(val & 0x10) && !(svga->gdcreg[6] & 0x08)) {
+                    svga->write_bank = ((et4000->banking2 & 1) << 20) | ((et4000->banking & 0xf) * 65536);
+                    svga->read_bank  = ((et4000->banking2 & 0x10) << 16) | (((et4000->banking >> 4) & 0xf) * 65536);
+                } else
+                    svga->write_bank = svga->read_bank = 0;
+            }
+            if (old != val) {
+                if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) {
+                    if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) {
+                        svga->fullchange = 3;
+                        svga->ma_latch   = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5);
+                    } else {
+                        svga->fullchange = changeframecount;
+                        svga_recalctimings(svga);
+                    }
+                }
+            }
+            if (svga->crtcreg == 0x30) {
+                if (et4000->pci && (et4000->rev != 5))
+                    et4000->linearbase = (et4000->linearbase & 0xc0000000) | ((val & 0xfc) << 22);
+                else
+                    et4000->linearbase = val << 22;
+                et4000w32p_recalcmapping(et4000);
+            }
+            if (svga->crtcreg == 0x32 || svga->crtcreg == 0x36)
+                et4000w32p_recalcmapping(et4000);
+            break;
+
+        case 0x210a:
+        case 0x211a:
+        case 0x212a:
+        case 0x213a:
+        case 0x214a:
+        case 0x215a:
+        case 0x216a:
+        case 0x217a:
+            et4000->index = val;
+            return;
+        case 0x210b:
+        case 0x211b:
+        case 0x212b:
+        case 0x213b:
+        case 0x214b:
+        case 0x215b:
+        case 0x216b:
+        case 0x217b:
+            et4000->regs[et4000->index] = val;
+            svga->hwcursor.x                                    = et4000->regs[0xE0] | ((et4000->regs[0xE1] & 7) << 8);
+            svga->hwcursor.y                                    = et4000->regs[0xE4] | ((et4000->regs[0xE5] & 7) << 8);
+            svga->hwcursor.ena                                  = !!(et4000->regs[0xF7] & 0x80);
+            svga->hwcursor.xoff                                 = et4000->regs[0xE2];
+            svga->hwcursor.yoff                                 = et4000->regs[0xE6];
+            svga->hwcursor.xsize = svga->hwcursor.ysize = ((et4000->regs[0xEF] & 4) || ((et4000->type == ET4000W32) && (et4000->regs[0xe2] >= 0x1f) && (et4000->regs[0xe6] >= 0x1f))) ? 128 : 64;
+
+            if (et4000->type == ET4000W32) {
+                if ((svga->bpp == 15) || (svga->bpp == 16)) {
+                    svga->hwcursor.xsize = svga->hwcursor.ysize = 128;
+                }
+            }
+
+            if ((et4000->type == ET4000W32) && (svga->hwcursor.xsize == 128)) {
+                switch (svga->bpp) {
+                    case 8:
+                        svga->hwcursor.xoff += 32;
+                        break;
+
+                    default:
+                        break;
+                }
+            }
+
+            if (svga->hwcursor.xsize == 128) {
+                svga->hwcursor.xoff &= 0x7f;
+                svga->hwcursor.yoff &= 0x7f;
+                if (et4000->type > ET4000W32P_REVC) {
+                    if (svga->bpp == 24) {
+                        et4000->adjust_cursor = 2;
+                    }
+                }
+            } else {
+                if (et4000->type > ET4000W32P_REVC) {
+                    if ((svga->bpp == 24) && et4000->adjust_cursor) {
+                        et4000->adjust_cursor = 0;
+                    }
+                }
+                svga->hwcursor.xoff &= 0x3f;
+                svga->hwcursor.yoff &= 0x3f;
+            }
+            svga->hwcursor.addr = (et4000->regs[0xe8] | (et4000->regs[0xe9] << 8) | ((et4000->regs[0xea] & 7) << 16)) << 2;
+
+            add2addr = svga->hwcursor.yoff * ((svga->hwcursor.xsize == 128) ? 32 : 16);
+            svga->hwcursor.addr += add2addr;
+            return;
+
+        default:
+            break;
+    }
+
+    svga_out(addr, val, svga);
+}
+
+uint8_t
+et4000w32p_in(uint16_t addr, void *priv)
+{
+    et4000w32p_t *et4000 = (et4000w32p_t *) priv;
+    svga_t       *svga   = &et4000->svga;
+
+    if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1))
+        addr ^= 0x60;
+
+    switch (addr) {
+        case 0x3c5:
+            if ((svga->seqaddr & 0xf) == 7)
+                return svga->seqregs[svga->seqaddr & 0xf] | 4;
+            break;
+#if 0
+        case 0x3c6:
+        case 0x3c7:
+        case 0x3c8:
+        case 0x3c9:
+            if (et4000->type <= ET4000W32P_REVC)
+                return sdac_ramdac_in(addr, &et4000->ramdac, svga);
+            else
+                return stg_ramdac_in(addr, svga->ramdac, svga);
+#endif
+        case 0x3cb:
+            return et4000->banking2;
+        case 0x3cd:
+            return et4000->banking;
+        case 0x3d4:
+            return svga->crtcreg;
+        case 0x3d5:
+            if (et4000->type == ET4000W32) {
+                if (svga->crtcreg == 0x37)
+                    return 0x09;
+            }
+            return svga->crtc[svga->crtcreg];
+
+        case 0x3da:
+            svga->attrff = 0;
+
+            /*Bit 1 of the Input Status Register is required by the OS/2 and NT ET4000W32/I drivers to be set otherwise
+              the guest will loop infinitely upon reaching the GUI*/
+            if (svga->cgastat & 0x01)
+                svga->cgastat &= ~0x32;
+            else
+                svga->cgastat ^= 0x32;
+            return svga->cgastat;
+
+        case 0x210a:
+        case 0x211a:
+        case 0x212a:
+        case 0x213a:
+        case 0x214a:
+        case 0x215a:
+        case 0x216a:
+        case 0x217a:
+            return et4000->index;
+        case 0x210B:
+        case 0x211B:
+        case 0x212B:
+        case 0x213B:
+        case 0x214B:
+        case 0x215B:
+        case 0x216B:
+        case 0x217B:
+            if (et4000->index == 0xec) {
+                return (et4000->regs[0xec] & 0xf) | (et4000->rev << 4);
+            }
+            if (et4000->index == 0xee) {
+                if (svga->bpp == 8) {
+                    if ((svga->gdcreg[5] & 0x60) >= 0x40)
+                        return 3;
+                    else if ((svga->gdcreg[5] & 0x60) == 0x20)
+                        return 1;
+                    else
+                        return 2;
+                } else if (svga->bpp == 15 || svga->bpp == 16)
+                    return 4;
+                else
+                    break;
+            }
+            if (et4000->index == 0xef) {
+                if (et4000->pci)
+                    return (et4000->regs[0xef] & 0x0f) | (et4000->rev << 4) | et4000->pci;
+                else
+                    return (et4000->regs[0xef] & 0x8f) | (et4000->rev << 4) | et4000->vlb;
+            }
+            return et4000->regs[et4000->index];
+
+        default:
+            break;
+    }
+
+    return svga_in(addr, svga);
+}
+
+void
+et4000w32p_recalctimings(svga_t *svga)
+{
+    et4000w32p_t *et4000 = (et4000w32p_t *) svga->p;
+
+    svga->ma_latch |= (svga->crtc[0x33] & 0x7) << 16;
+
+    svga->hblankstart    = (((svga->crtc[0x3f] & 0x4) >> 2) << 8) + svga->crtc[2];
+
+    if (svga->crtc[0x35] & 0x01)
+        svga->vblankstart |= 0x400;
+    if (svga->crtc[0x35] & 0x02)
+        svga->vtotal |= 0x400;
+    if (svga->crtc[0x35] & 0x04)
+        svga->dispend |= 0x400;
+    if (svga->crtc[0x35] & 0x08)
+        svga->vsyncstart |= 0x400;
+    if (svga->crtc[0x35] & 0x10)
+        svga->split |= 0x400;
+    if (svga->crtc[0x3F] & 0x80)
+        svga->rowoffset |= 0x100;
+    if (svga->crtc[0x3F] & 0x01)
+        svga->htotal |= 0x100;
+    if (svga->attrregs[0x16] & 0x20) {
+        svga->hdisp <<= 1;
+        svga->dots_per_clock <<= 1;
+    }
+
+    bt482_recalctimings(et4000->ramdac, svga);
+
+    //svga->clock = (cpuclock * (double) (1ULL << 32)) / svga->getclock((svga->miscout >> 2) & 3, svga->clock_gen);
+
+    if (et4000->type != ET4000W32P_DIAMOND) {
+        if ((svga->gdcreg[6] & 1) || (svga->attrregs[0x10] & 1)) {
+            if (svga->gdcreg[5] & 0x40) {
+                switch (svga->bpp) {
+                    case 8:
+                        svga->clock /= 2;
+                        break;
+                    case 15:
+                    case 16:
+                        svga->clock /= 3;
+                        break;
+                    case 24:
+                        svga->clock /= 4;
+                        break;
+
+                    default:
+                        break;
+                }
+            }
+        }
+    }
+
+    if (et4000->type == ET4000W32) {
+        if ((svga->gdcreg[6] & 1) || (svga->attrregs[0x10] & 1)) {
+            if (svga->gdcreg[5] & 0x40) {
+                switch (svga->bpp) {
+                    case 8:
+                        if (svga->hdisp == 640 || svga->hdisp == 800 || svga->hdisp == 1024)
+                            break;
+                        svga->hdisp -= 24;
+                        break;
+
+                    default:
+                        break;
+                }
+            }
+        }
+    }
+
+    et4000->adjust_cursor = 0;
+
+    switch (svga->bpp) {
+        case 15:
+        case 16:
+            if ((svga->gdcreg[6] & 1) || (svga->attrregs[0x10] & 1)) {
+                svga->hdisp >>= 1;
+                svga->dots_per_clock >>= 1;
+            }
+            if (et4000->type <= ET4000W32P_REVC) {
+                if (et4000->type == ET4000W32P_REVC) {
+                    if (svga->hdisp != 1024)
+                        et4000->adjust_cursor = 1;
+                } else
+                    et4000->adjust_cursor = 1;
+            }
+            break;
+        case 24:
+            svga->hdisp /= 3;
+            svga->dots_per_clock /= 3;
+            if (et4000->type <= ET4000W32P_REVC)
+                et4000->adjust_cursor = 2;
+            if ((et4000->type == ET4000W32P_DIAMOND) && ((svga->hdisp == (640 / 2)) || (svga->hdisp == 1232))) {
+                svga->hdisp = 640;
+            }
+            break;
+
+        default:
+            break;
+    }
+
+    svga->render = svga_render_blank;
+    if (!svga->scrblank && svga->attr_palette_enable) {
+        if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /* Text mode */
+            if (svga->seqregs[1] & 8)                                /* 40 column */
+                svga->render = svga_render_text_40;
+            else
+                svga->render = svga_render_text_80;
+        } else {
+            switch (svga->gdcreg[5] & 0x60) {
+                case 0x00:
+                    if (svga->seqregs[1] & 8) /* Low res (320) */
+                        svga->render = svga_render_4bpp_lowres;
+                    else
+                        svga->render = svga_render_4bpp_highres;
+                    break;
+                case 0x20:                    /* 4 colours */
+                    if (svga->seqregs[1] & 8) /*Low res (320)*/
+                        svga->render = svga_render_2bpp_lowres;
+                    else
+                        svga->render = svga_render_2bpp_highres;
+                    break;
+                case 0x40:
+                case 0x60: /* 256+ colours */
+                    if (et4000->type <= ET4000W32P_REVC)
+                        svga->clock /= 2;
+
+                    switch (svga->bpp) {
+                        case 8:
+                            svga->map8 = svga->pallook;
+                            if (svga->lowres)
+                                svga->render = svga_render_8bpp_lowres;
+                            else
+                                svga->render = svga_render_8bpp_highres;
+                            break;
+                        case 15:
+                            if (svga->lowres || (svga->seqregs[1] & 8))
+                                svga->render = svga_render_15bpp_lowres;
+                            else
+                                svga->render = svga_render_15bpp_highres;
+                            break;
+                        case 16:
+                            if (svga->lowres || (svga->seqregs[1] & 8))
+                                svga->render = svga_render_16bpp_lowres;
+                            else
+                                svga->render = svga_render_16bpp_highres;
+                            break;
+#if 0
+                        case 17:
+                            if (svga->lowres || (svga->seqregs[1] & 8))
+                                svga->render = svga_render_15bpp_mix_lowres;
+                            else
+                                svga->render = svga_render_15bpp_mix_highres;
+                            break;
+#endif
+                        case 24:
+                            if (svga->lowres || (svga->seqregs[1] & 8))
+                                svga->render = svga_render_24bpp_lowres;
+                            else
+                                svga->render = svga_render_24bpp_highres;
+                            break;
+                        case 32:
+                            if (svga->lowres || (svga->seqregs[1] & 8))
+                                svga->render = svga_render_32bpp_lowres;
+                            else
+                                svga->render = svga_render_32bpp_highres;
+                            break;
+
+                        default:
+                            break;
+                    }
+                    break;
+
+                default:
+                    break;
+            }
+        }
+    }
+}
+
+void
+et4000w32p_recalcmapping(et4000w32p_t *et4000)
+{
+    svga_t *svga = &et4000->svga;
+    int     map;
+
+    if (et4000->pci && !(et4000->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) {
+        mem_mapping_disablex(&svga->mapping);
+        mem_mapping_disablex(&et4000->linear_mapping);
+        mem_mapping_disablex(&et4000->mmu_mapping);
+        return;
+    }
+
+    if (svga->crtc[0x36] & 0x10) { /* Linear frame buffer */
+        et4000->blitter_mmio = (svga->crtc[0x36] & 0x08) != 0;
+        et4000->blitter_mmio_addr = et4000->linearbase + svga->vram_max - 0x100;
+        mem_mapping_set_addrx(&et4000->linear_mapping, et4000->linearbase, svga->vram_max);
+        mem_mapping_disablex(&svga->mapping);
+        mem_mapping_disablex(&et4000->mmu_mapping);
+    } else {
+        map = (svga->gdcreg[6] & 0xc) >> 2;
+        if (svga->crtc[0x36] & 0x20)
+            map |= 4;
+        if (svga->crtc[0x36] & 0x08)
+            map |= 8;
+        mem_mapping_disablex(&et4000->linear_mapping);
+        switch (map) {
+            case 0x0:
+            case 0x4:
+            case 0x8:
+            case 0xc: /* 128k at A0000 */
+                mem_mapping_set_addrx(&svga->mapping, 0xa0000, 0x20000);
+                mem_mapping_disablex(&et4000->mmu_mapping);
+                svga->banked_mask = 0x1ffff;
+                break;
+            case 0x1: /* 64k at A0000 */
+                mem_mapping_set_addrx(&svga->mapping, 0xa0000, 0x10000);
+                mem_mapping_disablex(&et4000->mmu_mapping);
+                svga->banked_mask = 0xffff;
+                break;
+            case 0x2: /* 32k at B0000 */
+                mem_mapping_set_addrx(&svga->mapping, 0xb0000, 0x08000);
+                mem_mapping_disablex(&et4000->mmu_mapping);
+                svga->banked_mask = 0x7fff;
+                break;
+            case 0x3: /* 32k at B8000 */
+                mem_mapping_set_addrx(&svga->mapping, 0xb8000, 0x08000);
+                mem_mapping_disablex(&et4000->mmu_mapping);
+                svga->banked_mask = 0x7fff;
+                break;
+            case 0x5:
+            case 0x9:
+            case 0xd: /* 64k at A0000, MMU at B8000 */
+                mem_mapping_set_addrx(&svga->mapping, 0xa0000, 0x10000);
+                mem_mapping_set_addrx(&et4000->mmu_mapping, 0xb8000, 0x08000);
+                svga->banked_mask = 0xffff;
+                break;
+            case 0x6:
+            case 0xa:
+            case 0xe: /* 32k at B0000, MMU at A8000 */
+                mem_mapping_set_addrx(&svga->mapping, 0xb0000, 0x08000);
+                mem_mapping_set_addrx(&et4000->mmu_mapping, 0xa8000, 0x08000);
+                svga->banked_mask = 0x7fff;
+                break;
+            case 0x7:
+            case 0xb:
+            case 0xf: /* 32k at B8000, MMU at A8000 */
+                mem_mapping_set_addrx(&svga->mapping, 0xb8000, 0x08000);
+                mem_mapping_set_addrx(&et4000->mmu_mapping, 0xa8000, 0x08000);
+                svga->banked_mask = 0x7fff;
+                break;
+
+            default:
+                break;
+        }
+    }
+
+    if (!et4000->interleaved && (svga->crtc[0x32] & 0x80))
+        mem_mapping_disablex(&svga->mapping);
+}
+
+static void
+et4000w32p_accel_write_fifo(et4000w32p_t *et4000, uint32_t addr, uint8_t val)
+{
+    et4000->acl.fifo_queue++;
+    switch (addr & 0xff) {
+        case 0x80:
+            et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0xffffff00) | val;
+            break;
+        case 0x81:
+            et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0xffff00ff) | (val << 8);
+            break;
+        case 0x82:
+            et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0xff00ffff) | (val << 16);
+            break;
+        case 0x83:
+            et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0x00ffffff) | (val << 24);
+            break;
+        case 0x84:
+            et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0xffffff00) | val;
+            break;
+        case 0x85:
+            et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0xffff00ff) | (val << 8);
+            break;
+        case 0x86:
+            et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0xff00ffff) | (val << 16);
+            break;
+        case 0x87:
+            et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0x00ffffff) | (val << 24);
+            break;
+        case 0x88:
+            et4000->acl.queued.pattern_off = (et4000->acl.queued.pattern_off & 0xff00) | val;
+            break;
+        case 0x89:
+            et4000->acl.queued.pattern_off = (et4000->acl.queued.pattern_off & 0x00ff) | (val << 8);
+            break;
+        case 0x8a:
+            et4000->acl.queued.source_off = (et4000->acl.queued.source_off & 0xff00) | val;
+            break;
+        case 0x8b:
+            et4000->acl.queued.source_off = (et4000->acl.queued.source_off & 0x00ff) | (val << 8);
+            break;
+        case 0x8c:
+            et4000->acl.queued.dest_off = (et4000->acl.queued.dest_off & 0xff00) | val;
+            break;
+        case 0x8d:
+            et4000->acl.queued.dest_off = (et4000->acl.queued.dest_off & 0x00ff) | (val << 8);
+            break;
+        case 0x8e:
+            if (et4000->type >= ET4000W32P_REVC)
+                et4000->acl.queued.pixel_depth = val & 0x30;
+            else
+                et4000->acl.queued.vbus = val & 0x03;
+            break;
+        case 0x8f:
+            if (et4000->type >= ET4000W32P_REVC)
+                et4000->acl.queued.xy_dir = val & 0xb7;
+            else
+                et4000->acl.queued.xy_dir = val & 0x03;
+            break;
+        case 0x90:
+            et4000->acl.queued.pattern_wrap = val & 0x77;
+            break;
+        case 0x92:
+            et4000->acl.queued.source_wrap = val & 0x77;
+            break;
+        case 0x98:
+            et4000->acl.queued.count_x = (et4000->acl.queued.count_x & 0xff00) | val;
+            break;
+        case 0x99:
+            et4000->acl.queued.count_x = (et4000->acl.queued.count_x & 0x00ff) | (val << 8);
+            break;
+        case 0x9a:
+            et4000->acl.queued.count_y = (et4000->acl.queued.count_y & 0xff00) | val;
+            break;
+        case 0x9b:
+            et4000->acl.queued.count_y = (et4000->acl.queued.count_y & 0x00ff) | (val << 8);
+            break;
+        case 0x9c:
+            if (et4000->type >= ET4000W32P_REVC)
+                et4000->acl.queued.ctrl_routing = val & 0xdb;
+            else
+                et4000->acl.queued.ctrl_routing = val & 0xb7;
+            break;
+        case 0x9d:
+            et4000->acl.queued.ctrl_reload = val & 0x03;
+            break;
+        case 0x9e:
+            et4000->acl.queued.rop_bg = val;
+            break;
+        case 0x9f:
+            et4000->acl.queued.rop_fg = val;
+            break;
+        case 0xa0:
+            et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0xffffff00) | val;
+            break;
+        case 0xa1:
+            et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0xffff00ff) | (val << 8);
+            break;
+        case 0xa2:
+            et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0xff00ffff) | (val << 16);
+            break;
+        case 0xa3:
+            et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0x00ffffff) | (val << 24);
+            et4000->acl.internal = et4000->acl.queued;
+            if (et4000->type >= ET4000W32P_REVC) {
+                et4000w32p_blit_start(et4000);
+                et4000w32_log("Destination Address write and start XY Block, xcnt = %i, ycnt = %i\n", et4000->acl.x_count + 1, et4000->acl.y_count + 1);
+                if (!(et4000->acl.queued.ctrl_routing & 0x43)) {
+                    et4000w32p_blit(0xffffff, ~0, 0, 0, et4000);
+                }
+                if ((et4000->acl.queued.ctrl_routing & 0x40) && !(et4000->acl.internal.ctrl_routing & 3)) {
+                    et4000w32p_blit(4, ~0, 0, 0, et4000);
+                }
+            } else {
+                et4000w32_blit_start(et4000);
+                et4000->acl.cpu_input_num = 0;
+                if (!(et4000->acl.queued.ctrl_routing & 0x37)) {
+                    et4000->acl.mmu_start = 1;
+                    et4000w32_blit(-1, 0, 0, 0xffffffff, et4000);
+                } else
+                    et4000->acl.mmu_start = 0;
+            }
+            break;
+        case 0xa4:
+            et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0xFFFFFF00) | val;
+            break;
+        case 0xa5:
+            et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0xFFFF00FF) | (val << 8);
+            break;
+        case 0xa6:
+            et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0xFF00FFFF) | (val << 16);
+            break;
+        case 0xa7:
+            et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0x00FFFFFF) | (val << 24);
+            break;
+        case 0xa8:
+            et4000->acl.queued.mix_off = (et4000->acl.queued.mix_off & 0xFF00) | val;
+            break;
+        case 0xa9:
+            et4000->acl.queued.mix_off = (et4000->acl.queued.mix_off & 0x00FF) | (val << 8);
+            break;
+        case 0xaa:
+            et4000->acl.queued.error = (et4000->acl.queued.error & 0xFF00) | val;
+            break;
+        case 0xab:
+            et4000->acl.queued.error = (et4000->acl.queued.error & 0x00FF) | (val << 8);
+            break;
+        case 0xac:
+            et4000->acl.queued.dmin = (et4000->acl.queued.dmin & 0xFF00) | val;
+            break;
+        case 0xad:
+            et4000->acl.queued.dmin = (et4000->acl.queued.dmin & 0x00FF) | (val << 8);
+            break;
+        case 0xae:
+            et4000->acl.queued.dmaj = (et4000->acl.queued.dmaj & 0xFF00) | val;
+            break;
+        case 0xaf:
+            et4000->acl.queued.dmaj = (et4000->acl.queued.dmaj & 0x00FF) | (val << 8);
+            break;
+
+        default:
+            break;
+    }
+}
+
+static void
+et4000w32p_accel_write_mmu(et4000w32p_t *et4000, uint32_t addr, uint8_t val, uint8_t bank)
+{
+    if (et4000->type >= ET4000W32P_REVC) {
+        if (!(et4000->acl.status & ACL_XYST)) {
+            et4000w32_log("XY MMU block not started\n");
+            return;
+        }
+        if (et4000->acl.internal.ctrl_routing & 3) {
+            et4000->acl.fifo_queue++;
+            if ((et4000->acl.internal.ctrl_routing & 3) == 2) /*CPU data is Mix data*/
+                et4000w32p_blit(8 - (et4000->acl.mix_addr & 7), val >> (et4000->acl.mix_addr & 7), 0, 1, et4000);
+            else if ((et4000->acl.internal.ctrl_routing & 3) == 1) /*CPU data is Source data*/
+                et4000w32p_blit(1, ~0, val, 2, et4000);
+        }
+    } else {
+        if (!(et4000->acl.status & ACL_XYST)) {
+            et4000->acl.fifo_queue++;
+            et4000->acl.queued.dest_addr = ((addr & 0x1fff) + et4000->mmu.base[bank]);
+            et4000->acl.internal         = et4000->acl.queued;
+            et4000w32_blit_start(et4000);
+            et4000w32_log("ET4000W32 Accelerated MMU aperture start XY Block (Implicit): bank = %i, patx = %i, paty = %i, wrap x = %i, wrap y = %i\n", et4000->bank, et4000->acl.pattern_x, et4000->acl.pattern_y, et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7], et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7]);
+            et4000->acl.cpu_input_num = 0;
+            if (!(et4000->acl.queued.ctrl_routing & 0x37)) {
+                et4000->acl.mmu_start = 1;
+                et4000w32_blit(-1, 0, 0, 0xffffffff, et4000);
+            } else {
+                et4000->acl.mmu_start = 0;
+            }
+        }
+
+        if (et4000->acl.internal.ctrl_routing & 7) {
+            et4000->acl.fifo_queue++;
+            et4000->acl.cpu_input = (et4000->acl.cpu_input & ~(0xff << (et4000->acl.cpu_input_num << 3))) | (val << (et4000->acl.cpu_input_num << 3));
+            et4000->acl.cpu_input_num++;
+
+            if (et4000->acl.cpu_input_num == et4000w32_vbus[et4000->acl.internal.vbus]) {
+                if ((et4000->acl.internal.ctrl_routing & 7) == 2) /*CPU data is Mix data*/
+                    et4000w32_blit(et4000->acl.cpu_input_num << 3, 2, 0, et4000->acl.cpu_input, et4000);
+                else if ((et4000->acl.internal.ctrl_routing & 7) == 1) /*CPU data is Source data*/
+                    et4000w32_blit(et4000->acl.cpu_input_num, 1, et4000->acl.cpu_input, 0xffffffff, et4000);
+
+                et4000->acl.cpu_input_num = 0;
+            }
+
+            if (et4000w32_vbus[et4000->acl.internal.vbus] == 1) {
+                if ((et4000->acl.internal.ctrl_routing  & 7) == 4) { /*CPU data is X Count*/
+                    et4000w32_log("ET4000W32 Accelerated MMU aperture routing = %02x: val = %02x, cx = %02x.\n", et4000->acl.internal.ctrl_routing, val, et4000->acl.internal.count_x);
+                    et4000->acl.cpu_x_cnt = val + 1;
+                    et4000->acl.cpu_x_cnt |= ((et4000->acl.queued.count_x >> 8) << 8);
+                    et4000w32_blit(et4000->acl.cpu_x_cnt, 3, 0, 0xffffffff, et4000);
+                } else if ((et4000->acl.internal.ctrl_routing  & 7) == 5) { /*CPU data is Y Count*/
+                    et4000w32_log("ET4000W32 Accelerated MMU aperture routing = %02x: val = %02x, cy = %02x.\n", et4000->acl.internal.ctrl_routing, val, et4000->acl.internal.count_y);
+                    et4000->acl.cpu_y_cnt = val + 1;
+                    et4000->acl.cpu_y_cnt |= ((et4000->acl.queued.count_y >> 8) << 8);
+                    et4000w32_blit(et4000->acl.cpu_y_cnt, 4, 0, 0xffffffff, et4000);
+                }
+            }
+        }
+    }
+}
+
+static void
+et4000w32p_mmu_write(uint32_t addr, uint8_t val, void *priv)
+{
+    et4000w32p_t *et4000 = (et4000w32p_t *) priv;
+    svga_t       *svga   = &et4000->svga;
+
+    switch (addr & 0x6000) {
+        case 0x0000: /* MMU 0 */
+        case 0x2000: /* MMU 1 */
+        case 0x4000: /* MMU 2 */
+            et4000->bank = (addr >> 13) & 3;
+            if (et4000->mmu.ctrl & (1 << et4000->bank)) {
+                et4000w32p_accel_write_mmu(et4000, addr & 0x7fff, val, et4000->bank);
+            } else {
+                if (((addr & 0x1fff) + et4000->mmu.base[et4000->bank]) < svga->vram_max) {
+                    svga->vram[((addr & 0x1fff) + et4000->mmu.base[et4000->bank]) & et4000->vram_mask]                = val;
+                    svga->changedvram[(((addr & 0x1fff) + et4000->mmu.base[et4000->bank]) & et4000->vram_mask) >> 12] = changeframecount;
+                }
+            }
+            break;
+        case 0x6000:
+            if ((addr & 0xff) >= 0x80) {
+                et4000w32p_accel_write_fifo(et4000, addr & 0x7fff, val);
+            } else {
+                switch (addr & 0xff) {
+                    case 0x00:
+                        et4000->mmu.base[0] = (et4000->mmu.base[0] & 0xffffff00) | val;
+                        break;
+                    case 0x01:
+                        et4000->mmu.base[0] = (et4000->mmu.base[0] & 0xffff00ff) | (val << 8);
+                        break;
+                    case 0x02:
+                        et4000->mmu.base[0] = (et4000->mmu.base[0] & 0xff00ffff) | (val << 16);
+                        break;
+                    case 0x03:
+                        et4000->mmu.base[0] = (et4000->mmu.base[0] & 0x00ffffff) | (val << 24);
+                        break;
+                    case 0x04:
+                        et4000->mmu.base[1] = (et4000->mmu.base[1] & 0xffffff00) | val;
+                        break;
+                    case 0x05:
+                        et4000->mmu.base[1] = (et4000->mmu.base[1] & 0xffff00ff) | (val << 8);
+                        break;
+                    case 0x06:
+                        et4000->mmu.base[1] = (et4000->mmu.base[1] & 0xff00ffff) | (val << 16);
+                        break;
+                    case 0x07:
+                        et4000->mmu.base[1] = (et4000->mmu.base[1] & 0x00ffffff) | (val << 24);
+                        break;
+                    case 0x08:
+                        et4000->mmu.base[2] = (et4000->mmu.base[2] & 0xffffff00) | val;
+                        break;
+                    case 0x09:
+                        et4000->mmu.base[2] = (et4000->mmu.base[2] & 0xffff00ff) | (val << 8);
+                        break;
+                    case 0x0a:
+                        et4000->mmu.base[2] = (et4000->mmu.base[2] & 0xff00ffff) | (val << 16);
+                        break;
+                    case 0x0b:
+                        et4000->mmu.base[2] = (et4000->mmu.base[2] & 0x00ffffff) | (val << 24);
+                        break;
+                    case 0x13:
+                        et4000->mmu.ctrl = val;
+                        break;
+                    case 0x30:
+                        et4000->acl.suspend_terminate = val;
+                        break;
+                    case 0x31:
+                        et4000->acl.osr = val;
+                        break;
+
+                    default:
+                        break;
+                }
+            }
+            break;
+
+        default:
+            break;
+    }
+}
+
+static uint8_t
+et4000w32p_mmu_read(uint32_t addr, void *priv)
+{
+    et4000w32p_t *et4000 = (et4000w32p_t *) priv;
+    const svga_t *svga   = &et4000->svga;
+    uint8_t       temp;
+
+    switch (addr & 0x6000) {
+        case 0x0000: /* MMU 0 */
+        case 0x2000: /* MMU 1 */
+        case 0x4000: /* MMU 2 */
+            et4000->bank = (addr >> 13) & 3;
+            if (et4000->mmu.ctrl & (1 << et4000->bank)) {
+                temp = 0xff;
+                if (et4000->acl.cpu_dat_pos) {
+                    et4000->acl.cpu_dat_pos--;
+                    temp = et4000->acl.cpu_dat & 0xff;
+                    et4000->acl.cpu_dat >>= 8;
+                }
+                if ((et4000->acl.queued.ctrl_routing & 0x40) && !et4000->acl.cpu_dat_pos && !(et4000->acl.internal.ctrl_routing & 3))
+                    et4000w32p_blit(4, ~0, 0, 0, et4000);
+
+                /* ???? */
+                return temp;
+            }
+
+            if ((addr & 0x1fff) + et4000->mmu.base[et4000->bank] >= svga->vram_max)
+                return 0xff;
+
+            return svga->vram[(addr & 0x1fff) + et4000->mmu.base[et4000->bank]];
+
+        case 0x6000:
+            switch (addr & 0xff) {
+                case 0x00:
+                    return et4000->mmu.base[0] & 0xff;
+                case 0x01:
+                    return et4000->mmu.base[0] >> 8;
+                case 0x02:
+                    return et4000->mmu.base[0] >> 16;
+                case 0x03:
+                    return et4000->mmu.base[0] >> 24;
+                case 0x04:
+                    return et4000->mmu.base[1] & 0xff;
+                case 0x05:
+                    return et4000->mmu.base[1] >> 8;
+                case 0x06:
+                    return et4000->mmu.base[1] >> 16;
+                case 0x07:
+                    return et4000->mmu.base[1] >> 24;
+                case 0x08:
+                    return et4000->mmu.base[2] & 0xff;
+                case 0x09:
+                    return et4000->mmu.base[2] >> 8;
+                case 0x0a:
+                    return et4000->mmu.base[2] >> 16;
+                case 0x0b:
+                    return et4000->mmu.base[2] >> 24;
+                case 0x13:
+                    return et4000->mmu.ctrl;
+
+                case 0x36:
+                    if (et4000->acl.fifo_queue) {
+                        et4000->acl.status |= ACL_RDST;
+                        et4000->acl.fifo_queue = 0;
+                    } else
+                        et4000->acl.status &= ~ACL_RDST;
+                    return et4000->acl.status;
+
+                case 0x80:
+                    return et4000->acl.internal.pattern_addr & 0xff;
+                case 0x81:
+                    return et4000->acl.internal.pattern_addr >> 8;
+                case 0x82:
+                    return et4000->acl.internal.pattern_addr >> 16;
+                case 0x83:
+                    return et4000->acl.internal.pattern_addr >> 24;
+                case 0x84:
+                    return et4000->acl.internal.source_addr & 0xff;
+                case 0x85:
+                    return et4000->acl.internal.source_addr >> 8;
+                case 0x86:
+                    return et4000->acl.internal.source_addr >> 16;
+                case 0x87:
+                    return et4000->acl.internal.source_addr >> 24;
+                case 0x88:
+                    return et4000->acl.internal.pattern_off & 0xff;
+                case 0x89:
+                    return et4000->acl.internal.pattern_off >> 8;
+                case 0x8a:
+                    return et4000->acl.internal.source_off & 0xff;
+                case 0x8b:
+                    return et4000->acl.internal.source_off >> 8;
+                case 0x8c:
+                    return et4000->acl.internal.dest_off & 0xff;
+                case 0x8d:
+                    return et4000->acl.internal.dest_off >> 8;
+                case 0x8e:
+                    if (et4000->type >= ET4000W32P_REVC)
+                        return et4000->acl.internal.pixel_depth;
+                    return et4000->acl.internal.vbus;
+                case 0x8f:
+                    return et4000->acl.internal.xy_dir;
+                case 0x90:
+                    return et4000->acl.internal.pattern_wrap;
+                case 0x92:
+                    return et4000->acl.internal.source_wrap;
+                case 0x98:
+                    return et4000->acl.internal.count_x & 0xff;
+                case 0x99:
+                    return et4000->acl.internal.count_x >> 8;
+                case 0x9a:
+                    return et4000->acl.internal.count_y & 0xff;
+                case 0x9b:
+                    return et4000->acl.internal.count_y >> 8;
+                case 0x9c:
+                    return et4000->acl.internal.ctrl_routing;
+                case 0x9d:
+                    return et4000->acl.internal.ctrl_reload;
+                case 0x9e:
+                    return et4000->acl.internal.rop_bg;
+                case 0x9f:
+                    return et4000->acl.internal.rop_fg;
+                case 0xa0:
+                    return et4000->acl.internal.dest_addr & 0xff;
+                case 0xa1:
+                    return et4000->acl.internal.dest_addr >> 8;
+                case 0xa2:
+                    return et4000->acl.internal.dest_addr >> 16;
+                case 0xa3:
+                    return et4000->acl.internal.dest_addr >> 24;
+
+                default:
+                    break;
+            }
+
+            return 0xff;
+
+        default:
+            break;
+    }
+
+    return 0xff;
+}
+
+void
+et4000w32_blit_start(et4000w32p_t *et4000)
+{
+    et4000->acl.x_count = et4000->acl.internal.count_x;
+    et4000->acl.y_count = et4000->acl.internal.count_y;
+
+    et4000->acl.pattern_addr = et4000->acl.internal.pattern_addr;
+    et4000->acl.source_addr  = et4000->acl.internal.source_addr;
+    et4000->acl.dest_addr    = et4000->acl.internal.dest_addr;
+    et4000->acl.dest_back    = et4000->acl.dest_addr;
+    et4000->acl.pattern_x = et4000->acl.source_x = et4000->acl.pattern_y = et4000->acl.source_y = 0;
+
+    et4000->acl.status |= ACL_XYST;
+    et4000->acl.status &= ~ACL_SSO;
+
+    if (!(et4000->acl.internal.ctrl_routing & 7) || (et4000->acl.internal.ctrl_routing & 4))
+        et4000->acl.status |= ACL_SSO;
+
+    if (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7]) {
+        et4000->acl.pattern_x = et4000->acl.pattern_addr & et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7];
+        et4000->acl.pattern_addr &= ~et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7];
+    }
+    et4000->acl.pattern_back = et4000->acl.pattern_addr;
+
+    if (!(et4000->acl.internal.pattern_wrap & 0x40)) {
+        if ((et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1) == 0x00) { /*This is to avoid a division by zero crash*/
+            et4000->acl.pattern_y = (et4000->acl.pattern_addr / (0x7f + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1);
+        } else
+            et4000->acl.pattern_y = (et4000->acl.pattern_addr / (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1);
+        et4000->acl.pattern_back &= ~(((et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1) * et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7]) - 1);
+    }
+    et4000->acl.pattern_x_back = et4000->acl.pattern_x;
+
+    if (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7]) {
+        et4000->acl.source_x = et4000->acl.source_addr & et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7];
+        et4000->acl.source_addr &= ~et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7];
+    }
+    et4000->acl.source_back = et4000->acl.source_addr;
+
+    if (!(et4000->acl.internal.source_wrap & 0x40)) {
+        if ((et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1) == 0x00) { /*This is to avoid a division by zero crash*/
+            et4000->acl.source_y = (et4000->acl.source_addr / (0x7f + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1);
+        } else
+            et4000->acl.source_y = (et4000->acl.source_addr / (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1);
+        et4000->acl.source_back &= ~(((et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1) * et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7]) - 1);
+    }
+    et4000->acl.source_x_back = et4000->acl.source_x;
+
+    if ((et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] == 7) && !(et4000->acl.internal.ctrl_routing & 0x37) && (et4000->acl.internal.rop_fg == 0x5a)) {
+        if ((et4000->acl.internal.count_y > 0) && (et4000->acl.pattern_y > 0)) {
+            if (et4000->acl.pattern_addr == et4000->acl.pattern_back)
+                et4000->acl.pattern_y = 0;
+            else {
+                et4000->acl.pattern_y = (et4000->acl.pattern_addr - et4000->acl.pattern_back) & 0x70;
+                et4000->acl.pattern_y >>= 4;
+            }
+        }
+    } else if ((et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] == 15) && !(et4000->acl.internal.ctrl_routing & 0x37) && (et4000->acl.internal.rop_fg == 0x5a)) {
+        if ((et4000->acl.internal.count_y > 0) && (et4000->acl.pattern_y > 0)) {
+            if (et4000->acl.pattern_addr == et4000->acl.pattern_back)
+                et4000->acl.pattern_y = 0;
+            else {
+                et4000->acl.pattern_y = (et4000->acl.pattern_addr - et4000->acl.pattern_back) & 0xf0;
+                et4000->acl.pattern_y >>= 5;
+            }
+        }
+    }
+}
+
+static void
+et4000w32p_blit_start(et4000w32p_t *et4000)
+{
+    et4000->acl.x_count = et4000->acl.internal.count_x;
+    et4000->acl.y_count = et4000->acl.internal.count_y;
+
+    if (!(et4000->acl.queued.xy_dir & 0x20))
+        et4000->acl.internal.error = et4000->acl.internal.dmaj / 2;
+
+    et4000->acl.pattern_addr   = et4000->acl.internal.pattern_addr;
+    et4000->acl.source_addr    = et4000->acl.internal.source_addr;
+    et4000->acl.mix_addr       = et4000->acl.internal.mix_addr;
+    et4000->acl.mix_back       = et4000->acl.mix_addr;
+    et4000->acl.dest_addr      = et4000->acl.internal.dest_addr;
+    et4000->acl.dest_back      = et4000->acl.dest_addr;
+    et4000->acl.internal.pos_x = et4000->acl.internal.pos_y = 0;
+    et4000->acl.pattern_x = et4000->acl.source_x = et4000->acl.pattern_y = et4000->acl.source_y = 0;
+    et4000->acl.status |= ACL_XYST;
+
+    et4000w32_log("ACL status XYST set\n");
+    if ((!(et4000->acl.internal.ctrl_routing & 7) || (et4000->acl.internal.ctrl_routing & 4)) && !(et4000->acl.internal.ctrl_routing & 0x40))
+        et4000->acl.status |= ACL_SSO;
+
+    if (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7]) {
+        et4000->acl.pattern_x = et4000->acl.pattern_addr & et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7];
+        et4000->acl.pattern_addr &= ~et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7];
+    }
+    et4000->acl.pattern_back = et4000->acl.pattern_addr;
+    if (!(et4000->acl.internal.pattern_wrap & 0x40)) {
+        et4000->acl.pattern_y = (et4000->acl.pattern_addr / (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1);
+        et4000->acl.pattern_back &= ~(((et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1) * et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7]) - 1);
+    }
+    et4000->acl.pattern_x_back = et4000->acl.pattern_x;
+
+    if (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7]) {
+        et4000->acl.source_x = et4000->acl.source_addr & et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7];
+        et4000->acl.source_addr &= ~et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7];
+    }
+    et4000->acl.source_back = et4000->acl.source_addr;
+
+    if (!(et4000->acl.internal.source_wrap & 0x40)) {
+        et4000->acl.source_y = (et4000->acl.source_addr / (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1);
+        et4000->acl.source_back &= ~(((et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1) * et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7]) - 1);
+    }
+    et4000->acl.source_x_back = et4000->acl.source_x;
+
+    et4000w32_max_x[2] = (et4000->acl.internal.pixel_depth == 0x20) ? 3 : 4;
+
+    et4000->acl.internal.count_x += (et4000->acl.internal.pixel_depth >> 4) & 3;
+    et4000->acl.cpu_dat_pos = 0;
+    et4000->acl.cpu_dat     = 0;
+
+    et4000->acl.pix_pos = 0;
+}
+
+void
+et4000w32_incx(int c, et4000w32p_t *et4000)
+{
+    et4000->acl.dest_addr += c;
+    et4000->acl.pattern_x += c;
+    et4000->acl.source_x += c;
+    et4000->acl.mix_addr += c;
+    if (et4000->acl.pattern_x >= et4000w32_max_x[et4000->acl.internal.pattern_wrap & 7])
+        et4000->acl.pattern_x -= et4000w32_max_x[et4000->acl.internal.pattern_wrap & 7];
+    if (et4000->acl.source_x >= et4000w32_max_x[et4000->acl.internal.source_wrap & 7])
+        et4000->acl.source_x -= et4000w32_max_x[et4000->acl.internal.source_wrap & 7];
+}
+
+void
+et4000w32_decx(int c, et4000w32p_t *et4000)
+{
+    et4000->acl.dest_addr -= c;
+    et4000->acl.pattern_x -= c;
+    et4000->acl.source_x -= c;
+    et4000->acl.mix_addr -= c;
+    if (et4000->acl.pattern_x < 0)
+        et4000->acl.pattern_x += et4000w32_max_x[et4000->acl.internal.pattern_wrap & 7];
+    if (et4000->acl.source_x < 0)
+        et4000->acl.source_x += et4000w32_max_x[et4000->acl.internal.source_wrap & 7];
+}
+
+void
+et4000w32_incy(et4000w32p_t *et4000)
+{
+    et4000->acl.pattern_addr += et4000->acl.internal.pattern_off + 1;
+    et4000->acl.source_addr += et4000->acl.internal.source_off + 1;
+    et4000->acl.mix_addr += et4000->acl.internal.mix_off + 1;
+    et4000->acl.dest_addr += et4000->acl.internal.dest_off + 1;
+    et4000->acl.pattern_y++;
+    if (et4000->acl.pattern_y == et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7]) {
+        et4000->acl.pattern_y    = 0;
+        et4000->acl.pattern_addr = et4000->acl.pattern_back;
+    }
+    et4000->acl.source_y++;
+    if (et4000->acl.source_y == et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7]) {
+        et4000->acl.source_y    = 0;
+        et4000->acl.source_addr = et4000->acl.source_back;
+    }
+}
+
+void
+et4000w32_decy(et4000w32p_t *et4000)
+{
+    et4000->acl.pattern_addr -= et4000->acl.internal.pattern_off + 1;
+    et4000->acl.source_addr -= et4000->acl.internal.source_off + 1;
+    et4000->acl.mix_addr -= et4000->acl.internal.mix_off + 1;
+    et4000->acl.dest_addr -= et4000->acl.internal.dest_off + 1;
+    et4000->acl.pattern_y--;
+    if ((et4000->acl.pattern_y < 0) && !(et4000->acl.internal.pattern_wrap & 0x40)) {
+        et4000->acl.pattern_y    = et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1;
+        et4000->acl.pattern_addr = et4000->acl.pattern_back + (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] * (et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1));
+    }
+    et4000->acl.source_y--;
+    if ((et4000->acl.source_y < 0) && !(et4000->acl.internal.source_wrap & 0x40)) {
+        et4000->acl.source_y    = et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1;
+        et4000->acl.source_addr = et4000->acl.source_back + (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] * (et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1));
+    }
+}
+
+static uint8_t ROPMIX(uint8_t R, uint8_t D, uint8_t P, uint8_t S)
+{                                
+    uint8_t out;
+        switch (R) {                 
+            case 0x00:               
+                out = 0;             
+                break;               
+            case 0x01:               
+                out = ~(D | (P | S));
+                break;               
+            case 0x02:               
+                out = D & ~(P | S);  
+                break;               
+            case 0x03:               
+                out = ~(P | S);      
+                break;               
+            case 0x04:               
+                out = S & ~(D | P);  
+                break;               
+            case 0x05:               
+                out = ~(D | P);      
+                break;               
+            case 0x06:               
+                out = ~(P | ~(D ^ S));
+                break;               
+            case 0x07:               
+                out = ~(P | (D & S));
+                break;               
+            case 0x08:               
+                out = S & (D & ~P);  
+                break;               
+            case 0x09:               
+                out = ~(P | (D ^ S));
+                break;               
+            case 0x0a:               
+                out = D & ~P;        
+                break;               
+            case 0x0b:               
+                out = ~(P | (S & ~D));
+                break;               
+            case 0x0c:               
+                out = S & ~P;        
+                break;               
+            case 0x0d:               
+                out = ~(P | (D & ~S));
+                break;               
+            case 0x0e:               
+                out = ~(P | ~(D | S));
+                break;               
+            case 0x0f:               
+                out = ~P;            
+                break;               
+            case 0x10:               
+                out = P & ~(D | S);  
+                break;               
+            case 0x11:               
+                out = ~(D | S);      
+                break;               
+            case 0x12:               
+                out = ~(S | ~(D ^ P));
+                break;               
+            case 0x13:               
+                out = ~(S | (D & P));
+                break;               
+            case 0x14:               
+                out = ~(D | ~(P ^ S));
+                break;               
+            case 0x15:               
+                out = ~(D | (P & S));
+                break;               
+            case 0x16:               
+                out = P ^ (S ^ (D & ~(P & S)));
+                break;               
+            case 0x17:               
+                out = ~(S ^ ((S ^ P) & (D ^ S)));
+                break;               
+            case 0x18:               
+                out = (S ^ P) & (P ^ D);
+                break;               
+            case 0x19:               
+                out = ~(S ^ (D & ~(P & S)));
+                break;               
+            case 0x1a:               
+                out = P ^ (D | (S & P));
+                break;               
+            case 0x1b:               
+                out = ~(S ^ (D & (P ^ S)));
+                break;               
+            case 0x1c:               
+                out = P ^ (S | (D & P));
+                break;               
+            case 0x1d:               
+                out = ~(D ^ (S & (P ^ D)));
+                break;               
+            case 0x1e:               
+                out = P ^ (D | S);   
+                break;               
+            case 0x1f:               
+                out = ~(P & (D | S));
+                break;               
+            case 0x20:               
+                out = D & (P & ~S);  
+                break;               
+            case 0x21:               
+                out = ~(S | (D ^ P));
+                break;               
+            case 0x22:               
+                out = D & ~S;        
+                break;               
+            case 0x23:               
+                out = ~(S | (P & ~D));
+                break;               
+            case 0x24:               
+                out = (S ^ P) & (D ^ S);         
+                break;               
+            case 0x25:               
+                out = ~(P ^ (D & ~(S & P)));     
+                break;               
+            case 0x26:               
+                out = S ^ (D | (P & S));         
+                break;               
+            case 0x27:               
+                out = S ^ (D | ~(P ^ S));        
+                break;               
+            case 0x28:               
+                out = D & (P ^ S);   
+                break;               
+            case 0x29:               
+                out = ~(P ^ (S ^ (D | (P & S))));
+                break;               
+            case 0x2a:               
+                out = D & ~(P & S);  
+                break;               
+            case 0x2b:               
+                out = ~(S ^ ((S ^ P) & (P ^ D)));
+                break;               
+            case 0x2c:               
+                out = S ^ (P & (D | S));         
+                break;               
+            case 0x2d:               
+                out = P ^ (S | ~D);  
+                break;               
+            case 0x2e:               
+                out = P ^ (S | (D ^ P));         
+                break;               
+            case 0x2f:               
+                out = ~(P & (S | ~D));
+                break;               
+            case 0x30:               
+                out = P & ~S;        
+                break;               
+            case 0x31:               
+                out = ~(S | (D & ~P));
+                break;               
+            case 0x32:               
+                out = S ^ (D | (P | S));         
+                break;               
+            case 0x33:               
+                out = ~S;            
+                break;               
+            case 0x34:               
+                out = S ^ (P | (D & S));         
+                break;               
+            case 0x35:               
+                out = S ^ (P | ~(D ^ S));        
+                break;               
+            case 0x36:               
+                out = S ^ (D | P);   
+                break;               
+            case 0x37:               
+                out = ~(S & (D | P));
+                break;               
+            case 0x38:               
+                out = P ^ (S & (D | P));         
+                break;               
+            case 0x39:               
+                out = S ^ (P | ~D);  
+                break;               
+            case 0x3a:               
+                out = S ^ (P | (D ^ S));         
+                break;               
+            case 0x3b:               
+                out = ~(S & (P | ~D));
+                break;               
+            case 0x3c:               
+                out = P ^ S;         
+                break;               
+            case 0x3d:               
+                out = S ^ (P | ~(D | S));        
+                break;               
+            case 0x3e:               
+                out = S ^ (P | (D & ~S));        
+                break;               
+            case 0x3f:               
+                out = ~(P & S);      
+                break;               
+            case 0x40:               
+                out = P & (S & ~D);  
+                break;               
+            case 0x41:               
+                out = ~(D | (P ^ S));
+                break;               
+            case 0x42:               
+                out = (S ^ D) & (P ^ D);         
+                break;               
+            case 0x43:               
+                out = ~(S ^ (P & ~(D & S)));     
+                break;               
+            case 0x44:               
+                out = S & ~D;        
+                break;               
+            case 0x45:               
+                out = ~(D | (P & ~S));
+                break;               
+            case 0x46:               
+                out = D ^ (S | (P & D));         
+                break;               
+            case 0x47:               
+                out = ~(P ^ (S & (D ^ P)));      
+                break;               
+            case 0x48:               
+                out = S & (D ^ P);   
+                break;               
+            case 0x49:               
+                out = ~(P ^ (D ^ (S | (P & D))));
+                break;               
+            case 0x4a:               
+                out = D ^ (P & (S | D));         
+                break;               
+            case 0x4b:               
+                out = P ^ (D | ~S);  
+                break;               
+            case 0x4c:               
+                out = S & ~(D & P);  
+                break;               
+            case 0x4d:               
+                out = ~(S ^ ((S ^ P) | (D ^ S)));
+                break;               
+            case 0x4e:               
+                out = P ^ (D | (S ^ P));         
+                break;               
+            case 0x4f:               
+                out = ~(P & (D | ~S));
+                break;               
+            case 0x50:               
+                out = P & ~D;        
+                break;               
+            case 0x51:               
+                out = ~(D | (S & ~P));
+                break;               
+            case 0x52:               
+                out = D ^ (P | (S & D));         
+                break;               
+            case 0x53:               
+                out = ~(S ^ (P & (D ^ S)));      
+                break;               
+            case 0x54:               
+                out = ~(D | ~(P | S));
+                break;               
+            case 0x55:               
+                out = ~D;            
+                break;               
+            case 0x56:               
+                out = D ^ (P | S);   
+                break;               
+            case 0x57:               
+                out = ~(D & (P | S));
+                break;               
+            case 0x58:               
+                out = P ^ (D & (S | P));         
+                break;               
+            case 0x59:               
+                out = D ^ (P | ~S);  
+                break;               
+            case 0x5a:               
+                out = D ^ P;         
+                break;               
+            case 0x5b:               
+                out = D ^ (P | ~(S | D));        
+                break;               
+            case 0x5c:               
+                out = D ^ (P | (S ^ D));         
+                break;               
+            case 0x5d:               
+                out = ~(D & (P | ~S));
+                break;               
+            case 0x5e:               
+                out = D ^ (P | (S & ~D));        
+                break;               
+            case 0x5f:               
+                out = ~(D & P);      
+                break;               
+            case 0x60:               
+                out = P & (D ^ S);   
+                break;               
+            case 0x61:               
+                out = ~(D ^ (S ^ (P | (D & S))));
+                break;               
+            case 0x62:               
+                out = D ^ (S & (P | D));         
+                break;               
+            case 0x63:               
+                out = S ^ (D | ~P);  
+                break;               
+            case 0x64:               
+                out = S ^ (D & (P | S));         
+                break;               
+            case 0x65:               
+                out = D ^ (S | ~P);  
+                break;               
+            case 0x66:               
+                out = D ^ S;         
+                break;               
+            case 0x67:               
+                out = S ^ (D | ~(P | S));        
+                break;               
+            case 0x68:               
+                out = ~(D ^ (S ^ (P | ~(D | S))));
+                break;               
+            case 0x69:               
+                out = ~(P ^ (D ^ S));
+                break;               
+            case 0x6a:               
+                out = D ^ (P & S);   
+                break;               
+            case 0x6b:               
+                out = ~(P ^ (S ^ (D & (P | S))));
+                break;               
+            case 0x6c:               
+                out = S ^ (D & P);   
+                break;               
+            case 0x6d:               
+                out = ~(P ^ (D ^ (S & (P | D))));
+                break;               
+            case 0x6e:               
+                out = S ^ (D & (P | ~S));        
+                break;               
+            case 0x6f:               
+                out = ~(P & ~(D ^ S));
+                break;               
+            case 0x70:               
+                out = P & ~(D & S);  
+                break;               
+            case 0x71:               
+                out = ~(S ^ ((S ^ D) & (P ^ D)));
+                break;               
+            case 0x72:               
+                out = S ^ (D | (P ^ S));         
+                break;               
+            case 0x73:               
+                out = ~(S & (D | ~P));
+                break;               
+            case 0x74:               
+                out = D ^ (S | (P ^ D));         
+                break;               
+            case 0x75:               
+                out = ~(D & (S | ~P));
+                break;               
+            case 0x76:               
+                out = S ^ (D | (P & ~S));        
+                break;               
+            case 0x77:               
+                out = ~(D & S);      
+                break;               
+            case 0x78:               
+                out = P ^ (D & S);   
+                break;               
+            case 0x79:               
+                out = ~(D ^ (S ^ (P & (D | S))));
+                break;               
+            case 0x7a:               
+                out = D ^ (P & (S | ~D));        
+                break;               
+            case 0x7b:               
+                out = ~(S & ~(D ^ P));
+                break;               
+            case 0x7c:               
+                out = S ^ (P & (D | ~S));        
+                break;               
+            case 0x7d:               
+                out = ~(D & ~(P ^ S));
+                break;               
+            case 0x7e:               
+                out = (S ^ P) | (D ^ S);         
+                break;               
+            case 0x7f:               
+                out = ~(D & (P & S));
+                break;               
+            case 0x80:               
+                out = D & (P & S);   
+                break;               
+            case 0x81:               
+                out = ~((S ^ P) | (D ^ S));      
+                break;               
+            case 0x82:               
+                out = D & ~(P ^ S);  
+                break;               
+            case 0x83:               
+                out = ~(S ^ (P & (D | ~S)));     
+                break;               
+            case 0x84:               
+                out = S & ~(D ^ P);  
+                break;               
+            case 0x85:               
+                out = ~(P ^ (D & (S | ~P)));     
+                break;               
+            case 0x86:               
+                out = D ^ (S ^ (P & (D | S)));   
+                break;               
+            case 0x87:               
+                out = ~(P ^ (D & S));
+                break;               
+            case 0x88:               
+                out = D & S;         
+                break;               
+            case 0x89:               
+                out = ~(S ^ (D | (P & ~S)));     
+                break;               
+            case 0x8a:               
+                out = D & (S | ~P);  
+                break;               
+            case 0x8b:               
+                out = ~(D ^ (S | (P ^ D)));      
+                break;               
+            case 0x8c:               
+                out = S & (D | ~P);  
+                break;               
+            case 0x8d:               
+                out = ~(S ^ (D | (P ^ S)));      
+                break;               
+            case 0x8e:               
+                out = S ^ ((S ^ D) & (P ^ D));   
+                break;               
+            case 0x8f:               
+                out = ~(P & ~(D & S));
+                break;               
+            case 0x90:               
+                out = P & ~(D ^ S);  
+                break;               
+            case 0x91:               
+                out = ~(S ^ (D & (P | ~S)));     
+                break;               
+            case 0x92:               
+                out = D ^ (P ^ (S & (D | P)));   
+                break;               
+            case 0x93:               
+                out = ~(S ^ (P & D));
+                break;               
+            case 0x94:               
+                out = P ^ (S ^ (D & (P | S)));   
+                break;               
+            case 0x95:               
+                out = ~(D ^ (P & S));
+                break;               
+            case 0x96:               
+                out = D ^ (P ^ S);   
+                break;               
+            case 0x97:               
+                out = P ^ (S ^ (D | ~(P | S)));  
+                break;               
+            case 0x98:               
+                out = ~(S ^ (D | ~(P | S)));     
+                break;               
+            case 0x99:               
+                out = ~(D ^ S);      
+                break;               
+            case 0x9a:               
+                out = D ^ (P & ~S);  
+                break;               
+            case 0x9b:               
+                out = ~(S ^ (D & (P | S)));      
+                break;               
+            case 0x9c:               
+                out = S ^ (P & ~D);  
+                break;               
+            case 0x9d:               
+                out = ~(D ^ (S & (P | D)));      
+                break;               
+            case 0x9e:               
+                out = D ^ (S ^ (P | (D & S)));   
+                break;               
+            case 0x9f:               
+                out = ~(P & (D ^ S));
+                break;               
+            case 0xa0:               
+                out = D & P;         
+                break;               
+            case 0xa1:               
+                out = ~(P ^ (D | (S & ~P)));     
+                break;               
+            case 0xa2:               
+                out = D & (P | ~S);  
+                break;               
+            case 0xa3:               
+                out = ~(D ^ (P | (S ^ D)));      
+                break;               
+            case 0xa4:               
+                out = ~(P ^ (D | ~(S | P)));     
+                break;               
+            case 0xa5:               
+                out = ~(P ^ D);      
+                break;               
+            case 0xa6:               
+                out = D ^ (S & ~P);  
+                break;               
+            case 0xa7:               
+                out = ~(P ^ (D & (S | P)));      
+                break;               
+            case 0xa8:               
+                out = D & (P | S);   
+                break;               
+            case 0xa9:               
+                out = ~(D ^ (P | S));
+                break;               
+            case 0xaa:               
+                out = D;             
+                break;               
+            case 0xab:               
+                out = D | ~(P | S);  
+                break;               
+            case 0xac:               
+                out = S ^ (P & (D ^ S));         
+                break;               
+            case 0xad:               
+                out = ~(D ^ (P | (S & D)));      
+                break;               
+            case 0xae:               
+                out = D | (S & ~P);  
+                break;               
+            case 0xaf:               
+                out = D | ~P;        
+                break;               
+            case 0xb0:               
+                out = P & (D | ~S);  
+                break;               
+            case 0xb1:               
+                out = ~(P ^ (D | (S ^ P)));      
+                break;               
+            case 0xb2:               
+                out = S ^ ((S ^ P) | (D ^ S));   
+                break;               
+            case 0xb3:               
+                out = ~(S & ~(D & P));
+                break;               
+            case 0xb4:               
+                out = P ^ (S & ~D);  
+                break;               
+            case 0xb5:               
+                out = ~(D ^ (P & (S | D)));      
+                break;               
+            case 0xb6:               
+                out = D ^ (P ^ (S | (D & P)));   
+                break;               
+            case 0xb7:               
+                out = ~(S & (D ^ P));
+                break;               
+            case 0xb8:               
+                out = P ^ (S & (D ^ P));         
+                break;               
+            case 0xb9:               
+                out = ~(D ^ (S | (P & D)));      
+                break;               
+            case 0xba:               
+                out = D | (P & ~S);  
+                break;               
+            case 0xbb:               
+                out = D | ~S;        
+                break;               
+            case 0xbc:               
+                out = S ^ (P & ~(D & S));        
+                break;               
+            case 0xbd:               
+                out = ~((S ^ D) & (P ^ D));      
+                break;               
+            case 0xbe:               
+                out = D | (P ^ S);   
+                break;               
+            case 0xbf:               
+                out = D | ~(P & S);  
+                break;               
+            case 0xc0:               
+                out = P & S;         
+                break;               
+            case 0xc1:               
+                out = ~(S ^ (P | (D & ~S)));     
+                break;               
+            case 0xc2:               
+                out = ~(S ^ (P | ~(D | S)));     
+                break;               
+            case 0xc3:               
+                out = ~(P ^ S);      
+                break;               
+            case 0xc4:               
+                out = S & (P | ~D);  
+                break;               
+            case 0xc5:               
+                out = ~(S ^ (P | (D ^ S)));      
+                break;               
+            case 0xc6:               
+                out = S ^ (D & ~P);  
+                break;               
+            case 0xc7:               
+                out = ~(P ^ (S & (D | P)));      
+                break;               
+            case 0xc8:               
+                out = S & (D | P);   
+                break;               
+            case 0xc9:               
+                out = ~(S ^ (P | D));
+                break;               
+            case 0xca:               
+                out = D ^ (P & (S ^ D));         
+                break;               
+            case 0xcb:               
+                out = ~(S ^ (P | (D & S)));      
+                break;               
+            case 0xcc:               
+                out = S;             
+                break;               
+            case 0xcd:               
+                out = S | ~(D | P);  
+                break;               
+            case 0xce:               
+                out = S | (D & ~P);  
+                break;               
+            case 0xcf:               
+                out = S | ~P;        
+                break;               
+            case 0xd0:               
+                out = P & (S | ~D);  
+                break;               
+            case 0xd1:               
+                out = ~(P ^ (S | (D ^ P)));      
+                break;               
+            case 0xd2:               
+                out = P ^ (D & ~S);  
+                break;               
+            case 0xd3:               
+                out = ~(S ^ (P & (D | S)));      
+                break;               
+            case 0xd4:               
+                out = S ^ ((S ^ P) & (P ^ D));   
+                break;               
+            case 0xd5:               
+                out = ~(D & ~(P & S));
+                break;               
+            case 0xd6:               
+                out = P ^ (S ^ (D | (P & S)));   
+                break;               
+            case 0xd7:               
+                out = ~(D & (P ^ S));
+                break;               
+            case 0xd8:               
+                out = P ^ (D & (S ^ P));         
+                break;               
+            case 0xd9:               
+                out = ~(S ^ (D | (P & S)));      
+                break;               
+            case 0xda:               
+                out = D ^ (P & ~(S & D));        
+                break;               
+            case 0xdb:               
+                out = ~((S ^ P) & (D ^ S));      
+                break;               
+            case 0xdc:               
+                out = S | (P & ~D);  
+                break;               
+            case 0xdd:               
+                out = S | ~D;        
+                break;               
+            case 0xde:               
+                out = S | (D ^ P);   
+                break;               
+            case 0xdf:               
+                out = S | ~(D & P);  
+                break;               
+            case 0xe0:               
+                out = P & (D | S);   
+                break;               
+            case 0xe1:               
+                out = ~(P ^ (D | S));
+                break;               
+            case 0xe2:               
+                out = D ^ (S & (P ^ D));         
+                break;               
+            case 0xe3:               
+                out = ~(P ^ (S | (D & P)));      
+                break;               
+            case 0xe4:               
+                out = S ^ (D & (P ^ S));         
+                break;               
+            case 0xe5:               
+                out = ~(P ^ (D | (S & P)));      
+                break;               
+            case 0xe6:               
+                out = S ^ (D & ~(P & S));        
+                break;               
+            case 0xe7:               
+                out = ~((S ^ P) & (P ^ D));      
+                break;               
+            case 0xe8:               
+                out = S ^ ((S ^ P) & (D ^ S));   
+                break;               
+            case 0xe9:               
+                out = ~(D ^ (S ^ (P & ~(D & S))));
+                break;               
+            case 0xea:               
+                out = D | (P & S);   
+                break;               
+            case 0xeb:               
+                out = D | ~(P ^ S);  
+                break;               
+            case 0xec:               
+                out = S | (D & P);   
+                break;               
+            case 0xed:               
+                out = S | ~(D ^ P);  
+                break;               
+            case 0xee:               
+                out = D | S;         
+                break;               
+            case 0xef:               
+                out = S | (D | ~P);  
+                break;               
+            case 0xf0:               
+                out = P;             
+                break;               
+            case 0xf1:               
+                out = P | ~(D | S);  
+                break;               
+            case 0xf2:               
+                out = P | (D & ~S);  
+                break;               
+            case 0xf3:               
+                out = P | ~S;        
+                break;               
+            case 0xf4:               
+                out = P | (S & ~D);  
+                break;               
+            case 0xf5:               
+                out = P | ~D;        
+                break;               
+            case 0xf6:               
+                out = P | (D ^ S);   
+                break;               
+            case 0xf7:               
+                out = P | ~(D & S);  
+                break;               
+            case 0xf8:               
+                out = P | (D & S);   
+                break;               
+            case 0xf9:               
+                out = P | ~(D ^ S);  
+                break;               
+            case 0xfa:               
+                out = D | P;         
+                break;               
+            case 0xfb:               
+                out = D | (P | ~S);  
+                break;               
+            case 0xfc:               
+                out = P | S;         
+                break;               
+            case 0xfd:               
+                out = P | (S | ~D);  
+                break;               
+            case 0xfe:               
+                out = D | (P | S);   
+                break;               
+            case 0xff:               
+                out = ~0;            
+                break;               
+        }                            
+        return out;
+}
+
+static void
+et4000w32_blit(int count, int cpu_input, uint32_t src_dat, uint32_t mix_dat, et4000w32p_t *et4000)
+{
+    svga_t *svga = &et4000->svga;
+    uint8_t pattern;
+    uint8_t source;
+    uint8_t dest;
+    uint8_t rop;
+    uint8_t out = 0;
+    int     mixmap;
+
+    if (!(et4000->acl.status & ACL_XYST) && !et4000->acl.mmu_start) {
+        et4000w32_log("XY Block not started\n");
+        return;
+    }
+
+    if (cpu_input == 3) {
+        while (1) {
+            pattern = svga->vram[(et4000->acl.pattern_addr + et4000->acl.pattern_x) & et4000->vram_mask];
+            source = svga->vram[(et4000->acl.source_addr + et4000->acl.source_x) & et4000->vram_mask];
+
+            dest   = svga->vram[et4000->acl.dest_addr & et4000->vram_mask];
+            mixmap = mix_dat & 1;
+
+            rop = mixmap ? et4000->acl.internal.rop_fg : et4000->acl.internal.rop_bg;
+            mix_dat >>= 1;
+            mix_dat |= 0x80000000;
+
+            out = ROPMIX(rop, dest, pattern, source);
+
+            /*Write the data*/
+            svga->vram[et4000->acl.dest_addr & et4000->vram_mask]                = out;
+            svga->changedvram[(et4000->acl.dest_addr & et4000->vram_mask) >> 12] = changeframecount;
+
+            if (et4000->acl.internal.xy_dir & 1)
+                et4000w32_decx(1, et4000);
+            else
+                et4000w32_incx(1, et4000);
+
+            count--;
+            if (!count) {
+                count = et4000->acl.cpu_x_cnt;
+
+                if (et4000->acl.internal.xy_dir & 2) {
+                    et4000w32_decy(et4000);
+                    et4000->acl.dest_back = et4000->acl.dest_addr = et4000->acl.dest_back - (et4000->acl.internal.dest_off + 1);
+                } else {
+                    et4000w32_incy(et4000);
+                    et4000->acl.dest_back = et4000->acl.dest_addr = et4000->acl.dest_back + et4000->acl.internal.dest_off + 1;
+                }
+
+                et4000->acl.pattern_x = et4000->acl.pattern_x_back;
+                et4000->acl.source_x  = et4000->acl.source_x_back;
+
+                et4000->acl.y_count--;
+                if (et4000->acl.y_count == 0xffff) {
+                    et4000->acl.status &= ~ACL_XYST;
+                    if (!(et4000->acl.internal.ctrl_routing & 7) || (et4000->acl.internal.ctrl_routing & 4)) {
+                        et4000w32_log("W32i: end blit, xcount = %i\n", et4000->acl.x_count);
+                        et4000->acl.status &= ~ACL_SSO;
+                    }
+                    return;
+                }
+            }
+        }
+    } else if (cpu_input == 4) {
+        while (1) {
+            pattern = svga->vram[(et4000->acl.pattern_addr + et4000->acl.pattern_x) & et4000->vram_mask];
+            source = svga->vram[(et4000->acl.source_addr + et4000->acl.source_x) & et4000->vram_mask];
+
+            dest   = svga->vram[et4000->acl.dest_addr & et4000->vram_mask];
+            mixmap = mix_dat & 1;
+
+            rop = mixmap ? et4000->acl.internal.rop_fg : et4000->acl.internal.rop_bg;
+            mix_dat >>= 1;
+            mix_dat |= 0x80000000;
+
+            out = ROPMIX(rop, dest, pattern, source);
+
+            /*Write the data*/
+            svga->vram[et4000->acl.dest_addr & et4000->vram_mask]                = out;
+            svga->changedvram[(et4000->acl.dest_addr & et4000->vram_mask) >> 12] = changeframecount;
+
+            if (et4000->acl.internal.xy_dir & 1)
+                et4000w32_decx(1, et4000);
+            else
+                et4000w32_incx(1, et4000);
+
+            et4000->acl.x_count--;
+            if (et4000->acl.x_count == 0xffff) {
+                et4000->acl.x_count = et4000->acl.internal.count_x;
+
+                if (et4000->acl.internal.xy_dir & 2) {
+                    et4000w32_decy(et4000);
+                    et4000->acl.dest_back = et4000->acl.dest_addr = et4000->acl.dest_back - (et4000->acl.internal.dest_off + 1);
+                } else {
+                    et4000w32_incy(et4000);
+                    et4000->acl.dest_back = et4000->acl.dest_addr = et4000->acl.dest_back + et4000->acl.internal.dest_off + 1;
+                }
+
+                et4000->acl.pattern_x = et4000->acl.pattern_x_back;
+                et4000->acl.source_x  = et4000->acl.source_x_back;
+
+                count--;
+                if (!count) {
+                    et4000->acl.status &= ~ACL_XYST;
+                    if (!(et4000->acl.internal.ctrl_routing & 7) || (et4000->acl.internal.ctrl_routing & 4)) {
+                        et4000w32_log("W32i: end blit, xcount = %i\n", et4000->acl.x_count);
+                        et4000->acl.status &= ~ACL_SSO;
+                    }
+                    return;
+                }
+            }
+        }
+    } else {
+        while (count-- && (et4000->acl.y_count >= 0)) {
+            pattern = svga->vram[(et4000->acl.pattern_addr + et4000->acl.pattern_x) & et4000->vram_mask];
+
+            if (cpu_input == 1) {
+                source = src_dat & 0xff;
+                src_dat >>= 8;
+            } else /*The source data is from the display memory if the Control Routing register is not set to 1*/
+                source = svga->vram[(et4000->acl.source_addr + et4000->acl.source_x) & et4000->vram_mask];
+
+            dest   = svga->vram[et4000->acl.dest_addr & et4000->vram_mask];
+            mixmap = mix_dat & 1;
+
+            /*Now determine the Raster Operation*/
+            rop = mixmap ? et4000->acl.internal.rop_fg : et4000->acl.internal.rop_bg;
+            mix_dat >>= 1;
+            mix_dat |= 0x80000000;
+
+            out = ROPMIX(rop, dest, pattern, source);
+
+            /*Write the data*/
+            svga->vram[et4000->acl.dest_addr & et4000->vram_mask]                = out;
+            svga->changedvram[(et4000->acl.dest_addr & et4000->vram_mask) >> 12] = changeframecount;
+
+            if (et4000->acl.internal.xy_dir & 1)
+                et4000w32_decx(1, et4000);
+            else
+                et4000w32_incx(1, et4000);
+
+            et4000->acl.x_count--;
+            if (et4000->acl.x_count == 0xffff) {
+                et4000->acl.x_count = et4000->acl.internal.count_x;
+
+                if (et4000->acl.internal.xy_dir & 2) {
+                    et4000w32_decy(et4000);
+                    et4000->acl.dest_back = et4000->acl.dest_addr = et4000->acl.dest_back - (et4000->acl.internal.dest_off + 1);
+                } else {
+                    et4000w32_incy(et4000);
+                    et4000->acl.dest_back = et4000->acl.dest_addr = et4000->acl.dest_back + et4000->acl.internal.dest_off + 1;
+                }
+
+                et4000->acl.pattern_x = et4000->acl.pattern_x_back;
+                et4000->acl.source_x  = et4000->acl.source_x_back;
+
+                et4000->acl.y_count--;
+                if (et4000->acl.y_count == 0xffff) {
+                    et4000->acl.status &= ~ACL_XYST;
+                    if (!(et4000->acl.internal.ctrl_routing & 7) || (et4000->acl.internal.ctrl_routing & 4)) {
+                        et4000w32_log("W32i: end blit, xcount = %i\n", et4000->acl.x_count);
+                        et4000->acl.status &= ~ACL_SSO;
+                    }
+                    et4000->acl.cpu_input_num = 0;
+                    return;
+                }
+
+                if (cpu_input) {
+                    return;
+                }
+            }
+        }
+    }
+}
+
+static void
+et4000w32p_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input, et4000w32p_t *et4000)
+{
+    svga_t *svga = &et4000->svga;
+    uint8_t pattern;
+    uint8_t source;
+    uint8_t dest;
+    uint8_t out;
+    uint8_t rop;
+    int     mixdat;
+
+    if (!(et4000->acl.status & ACL_XYST)) {
+        et4000w32_log("XY Block not started\n");
+        return;
+    }
+
+    if (et4000->acl.internal.xy_dir & 0x80) { /* Line draw */
+        et4000w32_log("Line draw\n");
+        while (count--) {
+            et4000w32_log("%i,%i : ", et4000->acl.internal.pos_x, et4000->acl.internal.pos_y);
+            pattern = svga->vram[(et4000->acl.pattern_addr + et4000->acl.pattern_x) & et4000->vram_mask];
+            source  = svga->vram[(et4000->acl.source_addr + et4000->acl.source_x) & et4000->vram_mask];
+            et4000w32_log("%06X %06X ", (et4000->acl.pattern_addr + et4000->acl.pattern_x) & et4000->vram_mask, (et4000->acl.source_addr + et4000->acl.source_x) & et4000->vram_mask);
+            if (cpu_input == 2) {
+                source = sdat & 0xff;
+                sdat >>= 8;
+            }
+            dest = svga->vram[et4000->acl.dest_addr & et4000->vram_mask];
+            out  = 0;
+            et4000w32_log("%06X   ", et4000->acl.dest_addr);
+            if ((et4000->acl.internal.ctrl_routing & 0xa) == 8) {
+                mixdat = svga->vram[(et4000->acl.mix_addr >> 3) & et4000->vram_mask] & (1 << (et4000->acl.mix_addr & 7));
+                et4000w32_log("%06X %02X  ", et4000->acl.mix_addr, svga->vram[(et4000->acl.mix_addr >> 3) & et4000->vram_mask]);
+            } else {
+                mixdat = mix & 1;
+                mix >>= 1;
+                mix |= 0x80000000;
+            }
+            et4000->acl.mix_addr++;
+            rop = mixdat ? et4000->acl.internal.rop_fg : et4000->acl.internal.rop_bg;
+
+            out = ROPMIX(rop, dest, pattern, source);
+
+            et4000w32_log("%06X = %02X\n", et4000->acl.dest_addr & et4000->vram_mask, out);
+            if (!(et4000->acl.internal.ctrl_routing & 0x40)) {
+                svga->vram[et4000->acl.dest_addr & et4000->vram_mask]                = out;
+                svga->changedvram[(et4000->acl.dest_addr & et4000->vram_mask) >> 12] = changeframecount;
+            } else {
+                et4000->acl.cpu_dat |= ((uint64_t) out << (et4000->acl.cpu_dat_pos * 8));
+                et4000->acl.cpu_dat_pos++;
+            }
+
+            et4000->acl.pix_pos++;
+            et4000->acl.internal.pos_x++;
+            if (et4000->acl.pix_pos <= ((et4000->acl.internal.pixel_depth >> 4) & 3)) {
+                if (et4000->acl.internal.xy_dir & 1)
+                    et4000w32_decx(1, et4000);
+                else
+                    et4000w32_incx(1, et4000);
+            } else {
+                if (et4000->acl.internal.xy_dir & 1)
+                    et4000w32_incx((et4000->acl.internal.pixel_depth >> 4) & 3, et4000);
+                else
+                    et4000w32_decx((et4000->acl.internal.pixel_depth >> 4) & 3, et4000);
+                et4000->acl.pix_pos = 0;
+
+                /*Next pixel*/
+                switch (et4000->acl.internal.xy_dir & 7) {
+                    case 0:
+                    case 1: /* Y+ */
+                        et4000w32_incy(et4000);
+                        et4000->acl.internal.pos_y++;
+                        et4000->acl.internal.pos_x -= ((et4000->acl.internal.pixel_depth >> 4) & 3) + 1;
+                        break;
+                    case 2:
+                    case 3: /* Y- */
+                        et4000w32_decy(et4000);
+                        et4000->acl.internal.pos_y++;
+                        et4000->acl.internal.pos_x -= ((et4000->acl.internal.pixel_depth >> 4) & 3) + 1;
+                        break;
+                    case 4:
+                    case 6: /* X+ */
+                        et4000w32_incx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000);
+                        break;
+                    case 5:
+                    case 7: /* X- */
+                        et4000w32_decx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000);
+                        break;
+
+                    default:
+                        break;
+                }
+                et4000->acl.internal.error += et4000->acl.internal.dmin;
+                if (et4000->acl.internal.error > et4000->acl.internal.dmaj) {
+                    et4000->acl.internal.error -= et4000->acl.internal.dmaj;
+                    switch (et4000->acl.internal.xy_dir & 7) {
+                        case 0:
+                        case 2: /* X+ */
+                            et4000w32_incx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000);
+                            et4000->acl.internal.pos_x++;
+                            break;
+                        case 1:
+                        case 3: /* X- */
+                            et4000w32_decx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000);
+                            et4000->acl.internal.pos_x++;
+                            break;
+                        case 4:
+                        case 5: /* Y+ */
+                            et4000w32_incy(et4000);
+                            et4000->acl.internal.pos_y++;
+                            break;
+                        case 6:
+                        case 7: /* Y- */
+                            et4000w32_decy(et4000);
+                            et4000->acl.internal.pos_y++;
+                            break;
+
+                        default:
+                            break;
+                    }
+                }
+                if ((et4000->acl.internal.pos_x > et4000->acl.internal.count_x) || (et4000->acl.internal.pos_y > et4000->acl.internal.count_y)) {
+                    et4000w32_log("ACL status linedraw 0\n");
+                    et4000->acl.status &= ~(ACL_XYST | ACL_SSO);
+                    return;
+                }
+            }
+        }
+    } else {
+        et4000w32_log("BitBLT: count = %i\n", count);
+        while (count-- && et4000->acl.y_count >= 0) {
+            pattern = svga->vram[(et4000->acl.pattern_addr + et4000->acl.pattern_x) & et4000->vram_mask];
+
+            if (cpu_input == 2) {
+                source = sdat & 0xff;
+                sdat >>= 8;
+            } else
+                source = svga->vram[(et4000->acl.source_addr + et4000->acl.source_x) & et4000->vram_mask];
+
+            dest = svga->vram[et4000->acl.dest_addr & et4000->vram_mask];
+            out  = 0;
+
+            if ((et4000->acl.internal.ctrl_routing & 0xa) == 8) {
+                mixdat = svga->vram[(et4000->acl.mix_addr >> 3) & et4000->vram_mask] & (1 << (et4000->acl.mix_addr & 7));
+            } else {
+                mixdat = mix & 1;
+                mix >>= 1;
+                mix |= 0x80000000;
+            }
+
+            rop = mixdat ? et4000->acl.internal.rop_fg : et4000->acl.internal.rop_bg;
+
+            out = ROPMIX(rop, dest, pattern, source);
+
+            if (!(et4000->acl.internal.ctrl_routing & 0x40)) {
+                svga->vram[et4000->acl.dest_addr & et4000->vram_mask]                = out;
+                svga->changedvram[(et4000->acl.dest_addr & et4000->vram_mask) >> 12] = changeframecount;
+            } else {
+                et4000->acl.cpu_dat |= ((uint64_t) out << (et4000->acl.cpu_dat_pos * 8));
+                et4000->acl.cpu_dat_pos++;
+            }
+
+            if (et4000->acl.internal.xy_dir & 1)
+                et4000w32_decx(1, et4000);
+            else
+                et4000w32_incx(1, et4000);
+
+            et4000->acl.x_count--;
+            if (et4000->acl.x_count == 0xffff) {
+                if (et4000->acl.internal.xy_dir & 2) {
+                    et4000w32_decy(et4000);
+                    et4000->acl.mix_back = et4000->acl.mix_addr = et4000->acl.mix_back - (et4000->acl.internal.mix_off + 1);
+                    et4000->acl.dest_back = et4000->acl.dest_addr = et4000->acl.dest_back - (et4000->acl.internal.dest_off + 1);
+                } else {
+                    et4000w32_incy(et4000);
+                    et4000->acl.mix_back = et4000->acl.mix_addr = et4000->acl.mix_back + et4000->acl.internal.mix_off + 1;
+                    et4000->acl.dest_back = et4000->acl.dest_addr = et4000->acl.dest_back + et4000->acl.internal.dest_off + 1;
+                }
+
+                et4000->acl.pattern_x = et4000->acl.pattern_x_back;
+                et4000->acl.source_x  = et4000->acl.source_x_back;
+
+                et4000->acl.y_count--;
+                et4000->acl.x_count = et4000->acl.internal.count_x;
+                if (et4000->acl.y_count == 0xffff) {
+                    et4000w32_log("BitBLT end\n");
+                    et4000->acl.status &= ~(ACL_XYST | ACL_SSO);
+                    return;
+                }
+
+                if (cpu_input)
+                    return;
+
+                if (et4000->acl.internal.ctrl_routing & 0x40) {
+                    if (et4000->acl.cpu_dat_pos & 3)
+                        et4000->acl.cpu_dat_pos += 4 - (et4000->acl.cpu_dat_pos & 3);
+                    return;
+                }
+            }
+        }
+    }
+}
+
+void
+et4000w32p_hwcursor_draw(svga_t *svga, int displine)
+{
+    const et4000w32p_t *et4000 = (et4000w32p_t *) svga->p;
+    int                 offset;
+    int                 xx;
+    int                 xx2;
+    int                 shift       = (et4000->adjust_cursor + 1);
+    int                 width       = (svga->hwcursor_latch.xsize - svga->hwcursor_latch.xoff);
+    int                 pitch       = (svga->hwcursor_latch.xsize == 128) ? 32 : 16;
+    int                 x_acc       = 4;
+    int                 minus_width = 0;
+    uint8_t             dat;
+
+    offset = svga->hwcursor_latch.xoff;
+
+    if ((et4000->type == ET4000W32) && (pitch == 32)) {
+        switch (svga->bpp) {
+            case 8:
+                minus_width = 0;
+                x_acc       = 2;
+                break;
+            case 15:
+            case 16:
+                minus_width = 64;
+                x_acc       = 2;
+                break;
+
+            default:
+                break;
+        }
+    }
+
+    for (int x = 0; x < (width - minus_width); x += x_acc) {
+        dat = svga->vram[svga->hwcursor_latch.addr + (offset >> 2)];
+
+        xx = svga->hwcursor_latch.x + svga->x_add + x;
+
+        if (!(xx % shift)) {
+            xx2 = xx / shift;
+            if (!(dat & 2))
+                buffer32->line[displine][xx2] = (dat & 1) ? 0xFFFFFF : 0;
+            else if ((dat & 3) == 3)
+                buffer32->line[displine][xx2] ^= 0xFFFFFF;
+        }
+        dat >>= 2;
+        xx++;
+        if (!(xx % shift)) {
+            xx2 = xx / shift;
+            if (!(dat & 2))
+                buffer32->line[displine][xx2] = (dat & 1) ? 0xFFFFFF : 0;
+            else if ((dat & 3) == 3)
+                buffer32->line[displine][xx2] ^= 0xFFFFFF;
+        }
+        dat >>= 2;
+        xx++;
+        if (!(xx % shift)) {
+            xx2 = xx / shift;
+            if (!(dat & 2))
+                buffer32->line[displine][xx2] = (dat & 1) ? 0xFFFFFF : 0;
+            else if ((dat & 3) == 3)
+                buffer32->line[displine][xx2] ^= 0xFFFFFF;
+        }
+        dat >>= 2;
+        xx++;
+        if (!(xx % shift)) {
+            xx2 = xx / shift;
+            if (!(dat & 2))
+                buffer32->line[displine][xx2] = (dat & 1) ? 0xFFFFFF : 0;
+            else if ((dat & 3) == 3)
+                buffer32->line[displine][xx2] ^= 0xFFFFFF;
+        }
+        dat >>= 2;
+
+        offset += 4;
+    }
+
+    svga->hwcursor_latch.addr += pitch;
+}
+
+static void
+et4000w32p_io_remove(et4000w32p_t *et4000)
+{
+    io_removehandlerx(0x03c0, 0x0020, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000);
+
+    io_removehandlerx(0x210a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000);
+    io_removehandlerx(0x211a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000);
+    io_removehandlerx(0x212a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000);
+    io_removehandlerx(0x213a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000);
+    io_removehandlerx(0x214a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000);
+    io_removehandlerx(0x215a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000);
+    io_removehandlerx(0x216a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000);
+    io_removehandlerx(0x217a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000);
+}
+
+static void
+et4000w32p_io_set(et4000w32p_t *et4000)
+{
+    et4000w32p_io_remove(et4000);
+
+    io_sethandlerx(0x03c0, 0x0020, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000);
+
+    io_sethandlerx(0x210a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000);
+    io_sethandlerx(0x211a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000);
+    io_sethandlerx(0x212a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000);
+    io_sethandlerx(0x213a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000);
+    io_sethandlerx(0x214a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000);
+    io_sethandlerx(0x215a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000);
+    io_sethandlerx(0x216a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000);
+    io_sethandlerx(0x217a, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000);
+}
+
+uint8_t
+et4000w32p_pci_read(int func, int addr, void *priv)
+{
+    const et4000w32p_t *et4000 = (et4000w32p_t *) priv;
+
+    if (func > 0)
+        return 0xff;
+
+    addr &= 0xff;
+
+    switch (addr) {
+        case 0x00:
+            return 0x0c; /* Tseng Labs */
+        case 0x01:
+            return 0x10;
+
+        case 0x02:
+            return (et4000->rev);
+        case 0x03:
+            return 0x32;
+
+        case PCI_REG_COMMAND:
+            return et4000->pci_regs[PCI_REG_COMMAND] | 0x80; /* Respond to IO and memory accesses */
+
+        case 0x07:
+            return 1 << 1; /* Medium DEVSEL timing */
+
+        case 0x08:
+            return (et4000->rev); /* Revision ID */
+        case 0x09:
+            return 0; /* Programming interface */
+
+        case 0x0a:
+            return 0x00; /* Supports VGA interface */
+        case 0x0b:
+            return 0x03; /* This has to be done in order to make this card work with the two 486 PCI machines. */
+
+        case 0x10:
+            return 0x00; /* Linear frame buffer address */
+        case 0x11:
+            return 0x00;
+        case 0x12:
+            return 0x00;
+        case 0x13:
+            return (et4000->linearbase >> 24);
+
+        case 0x30:
+            return et4000->pci_regs[0x30] & 0x01; /* BIOS ROM address */
+        case 0x31:
+            return 0x00;
+        case 0x32:
+            return 0x00;
+        case 0x33:
+            return et4000->pci_regs[0x33] & 0xf0;
+
+        default:
+            break;
+    }
+
+    return 0;
+}
+
+void
+et4000w32p_pci_write(int func, int addr, uint8_t val, void *priv)
+{
+    et4000w32p_t *et4000 = (et4000w32p_t *) priv;
+    svga_t       *svga   = &et4000->svga;
+
+    if (func > 0)
+        return;
+
+    addr &= 0xff;
+
+    switch (addr) {
+        case PCI_REG_COMMAND:
+            et4000->pci_regs[PCI_REG_COMMAND] = (val & 0x23) | 0x80;
+            if (val & PCI_COMMAND_IO)
+                et4000w32p_io_set(et4000);
+            else
+                et4000w32p_io_remove(et4000);
+            et4000w32p_recalcmapping(et4000);
+            break;
+
+        case 0x13:
+            et4000->linearbase &= 0x00c00000;
+            et4000->linearbase |= (et4000->pci_regs[0x13] << 24);
+            svga->crtc[0x30] &= 3;
+            svga->crtc[0x30] |= ((et4000->linearbase & 0x3f000000) >> 22);
+            et4000w32p_recalcmapping(et4000);
+            break;
+
+        case 0x30:
+        case 0x31:
+        case 0x32:
+        case 0x33:
+            et4000->pci_regs[addr] = val;
+            et4000->pci_regs[0x30] = 1;
+            et4000->pci_regs[0x31] = 0;
+            et4000->pci_regs[0x32] = 0;
+            et4000->pci_regs[0x33] &= 0xf0;
+            if (et4000->pci_regs[0x30] & 0x01) {
+                uint32_t biosaddr = (et4000->pci_regs[0x33] << 24);
+                if (!biosaddr)
+                    biosaddr = 0xc0000;
+                et4000w32_log("ET4000 bios_rom enabled at %08x\n", biosaddr);
+                mem_mapping_set_addrx(&et4000->bios_rom.mapping, biosaddr, 0x8000);
+            } else {
+                et4000w32_log("ET4000 bios_rom disabled\n");
+                mem_mapping_disablex(&et4000->bios_rom.mapping);
+            }
+            return;
+
+        default:
+            break;
+    }
+}
+
+static uint32_t et4000_readl_linear(uint32_t addr, void *p)
+{
+    svga_t *svga = (svga_t *)p;
+    et4000w32p_t *et4000 = (et4000w32p_t *)svga->p;
+    if (et4000->blitter_mmio && addr >= et4000->blitter_mmio_addr) {
+        uint32_t v = 0;
+        v |= et4000w32p_mmu_read((addr & 0xff) + 0x6000, p) << 0;
+        v |= et4000w32p_mmu_read((addr & 0xff) + 0x6001, p) << 8;
+        v |= et4000w32p_mmu_read((addr & 0xff) + 0x6002, p) << 16;
+        v |= et4000w32p_mmu_read((addr & 0xff) + 0x6003, p) << 24;
+        return v;
+    }
+    return svga_readl_linear(addr, p);
+}
+
+static uint16_t et4000_readw_linear(uint32_t addr, void *p)
+{
+    svga_t *svga = (svga_t *)p;
+    et4000w32p_t *et4000 = (et4000w32p_t *)svga->p;
+    if (et4000->blitter_mmio && addr >= et4000->blitter_mmio_addr) {
+        uint16_t v = 0;
+        v |= et4000w32p_mmu_read((addr & 0xff) + 0x6000, p) << 0;
+        v |= et4000w32p_mmu_read((addr & 0xff) + 0x6001, p) << 8;
+        return v;
+    }
+    return svga_readw_linear(addr, p);
+}
+
+static uint8_t et4000_read_linear(uint32_t addr, void *p)
+{
+    svga_t *svga = (svga_t *)p;
+    et4000w32p_t *et4000 = (et4000w32p_t *)svga->p;
+    if (et4000->blitter_mmio && addr >= et4000->blitter_mmio_addr) {
+        uint8_t v = 0;
+        v |= et4000w32p_mmu_read((addr & 0xff) + 0x6000, p) << 0;
+        return v;
+    }
+    return svga_read_linear(addr, p);
+}
+
+static void et4000_writel_linear(uint32_t addr, uint32_t val, void *p)
+{
+    svga_t *svga = (svga_t*)p;
+    et4000w32p_t *et4000 = (et4000w32p_t*)svga->p;
+    if (et4000->blitter_mmio && addr >= et4000->blitter_mmio_addr) {
+        et4000w32p_mmu_write((addr & 0xff) + 0x6000, val >>  0, et4000);
+        et4000w32p_mmu_write((addr & 0xff) + 0x6001, val >>  8, et4000);
+        et4000w32p_mmu_write((addr & 0xff) + 0x6002, val >> 16, et4000);
+        et4000w32p_mmu_write((addr & 0xff) + 0x6003, val >> 24, et4000);
+        return;
+    }
+    svga_writel_linear(addr, val, p);
+}
+static void et4000_writew_linear(uint32_t addr, uint16_t val, void *p)
+{
+    svga_t *svga = (svga_t *)p;
+    et4000w32p_t *et4000 = (et4000w32p_t *)svga->p;
+    if (et4000->blitter_mmio && addr >= et4000->blitter_mmio_addr) {
+        et4000w32p_mmu_write((addr & 0xff) + 0x6000, val >> 0, et4000);
+        et4000w32p_mmu_write((addr & 0xff) + 0x6001, val >> 8, et4000);
+        return;
+    }
+    svga_writew_linear(addr, val, p);
+}
+static void et4000_write_linear(uint32_t addr, uint8_t val, void *p)
+{
+    svga_t *svga = (svga_t *)p;
+    et4000w32p_t *et4000 = (et4000w32p_t *)svga->p;
+    if (et4000->blitter_mmio && addr >= et4000->blitter_mmio_addr) {
+        et4000w32p_mmu_write((addr & 0xff) + 0x6000, val, et4000);
+        return;
+    }
+    svga_write_linear(addr, val, p);
+}
+
+
+static void bt_out(uint16_t addr, uint8_t val, void *priv)
+{
+    et4000w32p_t *et4000 = (et4000w32p_t *)priv;
+    uint16_t saddr = 0x3c8 + ((addr >> 2) & 3);
+    bt482_ramdac_out(saddr, (addr >> 4) & 1, val, et4000->ramdac, &et4000->svga);
+}
+static uint8_t bt_in(uint16_t addr, void *priv)
+{
+    et4000w32p_t *et4000 = (et4000w32p_t *)priv;
+    uint16_t saddr = 0x3c8 + ((addr >> 2) & 3);
+    uint8_t v = bt482_ramdac_in(saddr, (addr >> 4) & 1, et4000->ramdac, &et4000->svga);
+    return v;
+}
+
+void *
+et4000w32p_init(const device_t *info)
+{
+    int           vram_size;
+    et4000w32p_t *et4000 = (et4000w32p_t*)malloc(sizeof(et4000w32p_t));
+    memset(et4000, 0, sizeof(et4000w32p_t));
+
+//    et4000->pci = (info->flags & DEVICE_PCI) ? 0x80 : 0x00;
+//    et4000->vlb = (info->flags & DEVICE_VLB) ? 0x40 : 0x00;
+
+    /*The ET4000/W32i ISA BIOS seems to not support 2MB of VRAM*/
+//    if ((info->local == ET4000W32) || ((info->local == ET4000W32I) && !(et4000->vlb)))
+//        vram_size = 1;
+//    else
+        vram_size = device_get_config_int("memory");
+
+    /*The interleaved VRAM was introduced by the ET4000/W32i*/
+    //et4000->interleaved = ((vram_size == 2) && (info->local != ET4000W32)) ? 1 : 0;
+
+#if 0
+    if (info->flags & DEVICE_PCI)
+        video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_et4000w32_pci);
+    else if (info->flags & DEVICE_VLB)
+        video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_et4000w32_vlb);
+    else
+        video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_et4000w32_isa);
+#endif
+
+    et4000->type = ET4000W32P_REVC;
+    et4000->ramdac = bt482_ramdac_init(NULL);
+    io_sethandlerx(0x000, 0x0020, bt_in, NULL, NULL, bt_out, NULL, NULL, et4000);
+
+    svga_init(&et4000->svga, et4000, vram_size << 20,
+              et4000w32p_recalctimings,
+              et4000w32p_in, et4000w32p_out,
+              et4000w32p_hwcursor_draw,
+              NULL);
+    et4000->svga.dac_hwcursor_draw = bt482_hwcursor_draw;
+    et4000->svga.ramdac = et4000->ramdac;
+
+    et4000->vram_mask        = (vram_size << 20) - 1;
+    et4000->svga.decode_mask = (vram_size << 20) - 1;
+
+    //et4000->type = info->local;
+
+    switch (et4000->type) {
+        case ET4000W32:
+            /* ET4000/W32 */
+            et4000->rev = 0;
+#if 0
+            rom_init(&et4000->bios_rom, BIOS_ROM_PATH_W32, 0xc0000, 0x8000, 0x7fff, 0,
+                     MEM_MAPPING_EXTERNAL);
+
+            et4000->svga.ramdac    = device_add(&tseng_ics5301_ramdac_device);
+            et4000->svga.clock_gen = et4000->svga.ramdac;
+            et4000->svga.getclock  = sdac_getclock;
+#endif
+            break;
+
+        case ET4000W32I:
+            /* ET4000/W32i rev B */
+            et4000->rev = 3;
+
+#if 0
+            if (et4000->vlb) {
+                rom_init(&et4000->bios_rom, BIOS_ROM_PATH_W32I_VLB, 0xc0000, 0x8000, 0x7fff, 0,
+                         MEM_MAPPING_EXTERNAL);
+            } else {
+                rom_init(&et4000->bios_rom, BIOS_ROM_PATH_W32I_ISA, 0xc0000, 0x8000, 0x7fff, 0,
+                         MEM_MAPPING_EXTERNAL);
+            }
+
+            et4000->svga.ramdac    = device_add(&tseng_ics5301_ramdac_device);
+            et4000->svga.clock_gen = et4000->svga.ramdac;
+            et4000->svga.getclock  = sdac_getclock;
+#endif
+            break;
+
+        case ET4000W32P_VIDEOMAGIC_REVB:
+            /* ET4000/W32p rev B */
+            et4000->rev = 5;
+
+#if 0
+            rom_init(&et4000->bios_rom, BIOS_ROM_PATH_W32P_VIDEOMAGIC_REVB_VLB, 0xc0000, 0x8000, 0x7fff, 0,
+                     MEM_MAPPING_EXTERNAL);
+
+            et4000->svga.ramdac    = device_add(&stg_ramdac_device);
+            et4000->svga.clock_gen = et4000->svga.ramdac;
+            et4000->svga.getclock  = stg_getclock;
+#endif
+            break;
+
+        case ET4000W32P_REVC:
+            /* ET4000/W32p rev C */
+            et4000->rev = 7;
+
+#if 0
+            rom_init(&et4000->bios_rom, BIOS_ROM_PATH_W32P_REVC, 0xc0000, 0x8000, 0x7fff, 0,
+                     MEM_MAPPING_EXTERNAL);
+
+            et4000->svga.ramdac    = device_add(&tseng_ics5341_ramdac_device);
+            et4000->svga.clock_gen = et4000->svga.ramdac;
+            et4000->svga.getclock  = sdac_getclock;
+#endif
+            break;
+
+        case ET4000W32P:
+            /* ET4000/W32p rev D */
+            et4000->rev = 6;
+
+#if 0
+            rom_init(&et4000->bios_rom, BIOS_ROM_PATH_W32P, 0xc0000, 0x8000, 0x7fff, 0,
+                     MEM_MAPPING_EXTERNAL);
+
+            et4000->svga.ramdac    = device_add(&stg_ramdac_device);
+            et4000->svga.clock_gen = et4000->svga.ramdac;
+            et4000->svga.getclock  = stg_getclock;
+#endif
+            break;
+
+        case ET4000W32P_CARDEX:
+            /* ET4000/W32p rev D */
+            et4000->rev = 6;
+
+#if 0
+            rom_init(&et4000->bios_rom, BIOS_ROM_PATH_CARDEX, 0xc0000, 0x8000, 0x7fff, 0,
+                     MEM_MAPPING_EXTERNAL);
+
+            et4000->svga.ramdac    = device_add(&stg_ramdac_device);
+            et4000->svga.clock_gen = et4000->svga.ramdac;
+            et4000->svga.getclock  = stg_getclock;
+#endif
+            break;
+
+        case ET4000W32P_DIAMOND:
+            /* ET4000/W32p rev D */
+            et4000->rev = 6;
+
+#if 0
+            rom_init(&et4000->bios_rom, BIOS_ROM_PATH_DIAMOND, 0xc0000, 0x8000, 0x7fff, 0,
+                     MEM_MAPPING_EXTERNAL);
+
+            et4000->svga.ramdac    = device_add(&stg_ramdac_device);
+            et4000->svga.clock_gen = device_add(&icd2061_device);
+            et4000->svga.getclock  = icd2061_getclock;
+#endif
+            break;
+
+        default:
+            break;
+    }
+
+#if 0
+    if (info->flags & DEVICE_PCI)
+        mem_mapping_disable(&et4000->bios_rom.mapping);
+#endif
+
+    mem_mapping_addx(&et4000->linear_mapping, 0, 0, et4000_read_linear, et4000_readw_linear, et4000_readl_linear, et4000_write_linear, et4000_writew_linear, et4000_writel_linear, NULL, MEM_MAPPING_EXTERNAL, &et4000->svga);
+    mem_mapping_addx(&et4000->mmu_mapping, 0, 0, et4000w32p_mmu_read, NULL, NULL, et4000w32p_mmu_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, et4000);
+
+    et4000w32p_io_set(et4000);
+
+//    if (info->flags & DEVICE_PCI)
+//        pci_add_card(PCI_ADD_NORMAL, et4000w32p_pci_read, et4000w32p_pci_write, et4000, &et4000->pci_slot);
+
+    /* Hardwired bits: 00000000 1xx0x0xx */
+    /* R/W bits:                 xx xxxx */
+    /* PCem bits:                    111 */
+    et4000->pci_regs[0x04] = 0x83;
+
+    et4000->pci_regs[0x10] = 0x00;
+    et4000->pci_regs[0x11] = 0x00;
+    et4000->pci_regs[0x12] = 0xff;
+    et4000->pci_regs[0x13] = 0xff;
+
+    et4000->pci_regs[0x30] = 0x00;
+    et4000->pci_regs[0x31] = 0x00;
+    et4000->pci_regs[0x32] = 0x00;
+    et4000->pci_regs[0x33] = 0xf0;
+
+    et4000->svga.packed_chain4 = 1;
+
+    svga_set_ramdac_type(&et4000->svga, RAMDAC_8BIT);
+
+    return et4000;
+}
+
+int
+et4000w32_available(void)
+{
+    return rom_present(BIOS_ROM_PATH_W32);
+}
+
+int
+et4000w32i_isa_available(void)
+{
+    return rom_present(BIOS_ROM_PATH_W32I_ISA);
+}
+
+int
+et4000w32i_vlb_available(void)
+{
+    return rom_present(BIOS_ROM_PATH_W32I_VLB);
+}
+
+int
+et4000w32p_videomagic_revb_vlb_available(void)
+{
+    return rom_present(BIOS_ROM_PATH_W32P_VIDEOMAGIC_REVB_VLB);
+}
+
+int
+et4000w32p_revc_available(void)
+{
+    return rom_present(BIOS_ROM_PATH_W32P_REVC);
+}
+
+int
+et4000w32p_noncardex_available(void)
+{
+    return rom_present(BIOS_ROM_PATH_W32P);
+}
+
+int
+et4000w32p_available(void)
+{
+    return rom_present(BIOS_ROM_PATH_DIAMOND);
+}
+
+int
+et4000w32p_cardex_available(void)
+{
+    return rom_present(BIOS_ROM_PATH_CARDEX);
+}
+
+void
+et4000w32p_close(void *priv)
+{
+    et4000w32p_t *et4000 = (et4000w32p_t *) priv;
+
+    svga_close(&et4000->svga);
+
+    bt482_ramdac_close(et4000->ramdac);
+
+    free(et4000);
+}
+
+void
+et4000w32p_speed_changed(void *priv)
+{
+    et4000w32p_t *et4000 = (et4000w32p_t *) priv;
+
+    svga_recalctimings(&et4000->svga);
+}
+
+void
+et4000w32p_force_redraw(void *priv)
+{
+    et4000w32p_t *et4000 = (et4000w32p_t *) priv;
+
+    et4000->svga.fullchange = changeframecount;
+}
+
+#if 0
+static const device_config_t et4000w32p_config[] = {
+  // clang-format off
+    {
+        .name = "memory",
+        .description = "Memory size",
+        .type = CONFIG_SELECTION,
+        .default_int = 2,
+        .selection = {
+            {
+                .description = "1 MB",
+                .value = 1
+            },
+            {
+                .description = "2 MB",
+                .value = 2
+            },
+            {
+                .description = ""
+            }
+        }
+    },
+    {
+        .type = CONFIG_END
+    }
+  // clang-format on
+};
+
+const device_t et4000w32_device = {
+    .name          = "Tseng Labs ET4000/w32 ISA",
+    .internal_name = "et4000w32",
+    .flags         = DEVICE_ISA | DEVICE_AT,
+    .local         = ET4000W32,
+    .init          = et4000w32p_init,
+    .close         = et4000w32p_close,
+    .reset         = NULL,
+    { .available = et4000w32_available },
+    .speed_changed = et4000w32p_speed_changed,
+    .force_redraw  = et4000w32p_force_redraw,
+    .config        = NULL
+};
+
+const device_t et4000w32_onboard_device = {
+    .name          = "Tseng Labs ET4000/w32 (ISA) (On-Board)",
+    .internal_name = "et4000w32_onboard",
+    .flags         = DEVICE_ISA | DEVICE_AT,
+    .local         = ET4000W32,
+    .init          = et4000w32p_init,
+    .close         = et4000w32p_close,
+    .reset         = NULL,
+    { .available = et4000w32_available },
+    .speed_changed = et4000w32p_speed_changed,
+    .force_redraw  = et4000w32p_force_redraw,
+    .config        = NULL
+};
+
+const device_t et4000w32i_isa_device = {
+    .name          = "Tseng Labs ET4000/w32i Rev. B ISA",
+    .internal_name = "et4000w32i",
+    .flags         = DEVICE_ISA | DEVICE_AT,
+    .local         = ET4000W32I,
+    .init          = et4000w32p_init,
+    .close         = et4000w32p_close,
+    .reset         = NULL,
+    { .available = et4000w32i_isa_available },
+    .speed_changed = et4000w32p_speed_changed,
+    .force_redraw  = et4000w32p_force_redraw,
+    .config        = NULL
+};
+
+const device_t et4000w32i_vlb_device = {
+    .name          = "Tseng Labs ET4000/w32i Rev. B VLB",
+    .internal_name = "et4000w32i_vlb",
+    .flags         = DEVICE_VLB,
+    .local         = ET4000W32I,
+    .init          = et4000w32p_init,
+    .close         = et4000w32p_close,
+    .reset         = NULL,
+    { .available = et4000w32i_vlb_available },
+    .speed_changed = et4000w32p_speed_changed,
+    .force_redraw  = et4000w32p_force_redraw,
+    .config        = et4000w32p_config
+};
+
+const device_t et4000w32p_videomagic_revb_vlb_device = {
+    .name          = "Tseng Labs ET4000/w32p Rev. B VLB (VideoMagic)",
+    .internal_name = "et4000w32p_videomagic_revb_vlb",
+    .flags         = DEVICE_VLB,
+    .local         = ET4000W32P_VIDEOMAGIC_REVB,
+    .init          = et4000w32p_init,
+    .close         = et4000w32p_close,
+    .reset         = NULL,
+    { .available = et4000w32p_videomagic_revb_vlb_available },
+    .speed_changed = et4000w32p_speed_changed,
+    .force_redraw  = et4000w32p_force_redraw,
+    .config        = et4000w32p_config
+};
+
+const device_t et4000w32p_videomagic_revb_pci_device = {
+    .name          = "Tseng Labs ET4000/w32p Rev. B PCI (VideoMagic)",
+    .internal_name = "et4000w32p_videomagic_revb_pci",
+    .flags         = DEVICE_PCI,
+    .local         = ET4000W32P_VIDEOMAGIC_REVB,
+    .init          = et4000w32p_init,
+    .close         = et4000w32p_close,
+    .reset         = NULL,
+    { .available = et4000w32p_videomagic_revb_vlb_available },
+    .speed_changed = et4000w32p_speed_changed,
+    .force_redraw  = et4000w32p_force_redraw,
+    .config        = et4000w32p_config
+};
+
+const device_t et4000w32p_revc_vlb_device = {
+    .name          = "Tseng Labs ET4000/w32p Rev. C VLB (Cardex)",
+    .internal_name = "et4000w32p_revc_vlb",
+    .flags         = DEVICE_VLB,
+    .local         = ET4000W32P_REVC,
+    .init          = et4000w32p_init,
+    .close         = et4000w32p_close,
+    .reset         = NULL,
+    { .available = et4000w32p_revc_available },
+    .speed_changed = et4000w32p_speed_changed,
+    .force_redraw  = et4000w32p_force_redraw,
+    .config        = et4000w32p_config
+};
+
+const device_t et4000w32p_revc_pci_device = {
+    .name          = "Tseng Labs ET4000/w32p Rev. C PCI (Cardex)",
+    .internal_name = "et4000w32p_revc_pci",
+    .flags         = DEVICE_PCI,
+    .local         = ET4000W32P_REVC,
+    .init          = et4000w32p_init,
+    .close         = et4000w32p_close,
+    .reset         = NULL,
+    { .available = et4000w32p_revc_available },
+    .speed_changed = et4000w32p_speed_changed,
+    .force_redraw  = et4000w32p_force_redraw,
+    .config        = et4000w32p_config
+};
+
+const device_t et4000w32p_noncardex_vlb_device = {
+    .name          = "Tseng Labs ET4000/w32p Rev. D VLB",
+    .internal_name = "et4000w32p_nc_vlb",
+    .flags         = DEVICE_VLB,
+    .local         = ET4000W32P,
+    .init          = et4000w32p_init,
+    .close         = et4000w32p_close,
+    .reset         = NULL,
+    { .available = et4000w32p_noncardex_available },
+    .speed_changed = et4000w32p_speed_changed,
+    .force_redraw  = et4000w32p_force_redraw,
+    .config        = et4000w32p_config
+};
+
+const device_t et4000w32p_noncardex_pci_device = {
+    .name          = "Tseng Labs ET4000/w32p Rev. D PCI",
+    .internal_name = "et4000w32p_nc_pci",
+    .flags         = DEVICE_PCI,
+    .local         = ET4000W32P,
+    .init          = et4000w32p_init,
+    .close         = et4000w32p_close,
+    .reset         = NULL,
+    { .available = et4000w32p_noncardex_available },
+    .speed_changed = et4000w32p_speed_changed,
+    .force_redraw  = et4000w32p_force_redraw,
+    .config        = et4000w32p_config
+};
+
+const device_t et4000w32p_cardex_vlb_device = {
+    .name          = "Tseng Labs ET4000/w32p Rev. D VLB (Cardex)",
+    .internal_name = "et4000w32p_vlb",
+    .flags         = DEVICE_VLB,
+    .local         = ET4000W32P_CARDEX,
+    .init          = et4000w32p_init,
+    .close         = et4000w32p_close,
+    .reset         = NULL,
+    { .available = et4000w32p_cardex_available },
+    .speed_changed = et4000w32p_speed_changed,
+    .force_redraw  = et4000w32p_force_redraw,
+    .config        = et4000w32p_config
+};
+
+const device_t et4000w32p_cardex_pci_device = {
+    .name          = "Tseng Labs ET4000/w32p Rev. D PCI (Cardex)",
+    .internal_name = "et4000w32p_pci",
+    .flags         = DEVICE_PCI,
+    .local         = ET4000W32P_CARDEX,
+    .init          = et4000w32p_init,
+    .close         = et4000w32p_close,
+    .reset         = NULL,
+    { .available = et4000w32p_cardex_available },
+    .speed_changed = et4000w32p_speed_changed,
+    .force_redraw  = et4000w32p_force_redraw,
+    .config        = et4000w32p_config
+};
+
+const device_t et4000w32p_vlb_device = {
+    .name          = "Tseng Labs ET4000/w32p Rev. D VLB (Diamond Stealth32)",
+    .internal_name = "stealth32_vlb",
+    .flags         = DEVICE_VLB,
+    .local         = ET4000W32P_DIAMOND,
+    .init          = et4000w32p_init,
+    .close         = et4000w32p_close,
+    .reset         = NULL,
+    { .available = et4000w32p_available },
+    .speed_changed = et4000w32p_speed_changed,
+    .force_redraw  = et4000w32p_force_redraw,
+    .config        = et4000w32p_config
+};
+
+const device_t et4000w32p_pci_device = {
+    .name          = "Tseng Labs ET4000/w32p Rev. D PCI (Diamond Stealth32)",
+    .internal_name = "stealth32_pci",
+    .flags         = DEVICE_PCI,
+    .local         = ET4000W32P_DIAMOND,
+    .init          = et4000w32p_init,
+    .close         = et4000w32p_close,
+    .reset         = NULL,
+    { .available = et4000w32p_available },
+    .speed_changed = et4000w32p_speed_changed,
+    .force_redraw  = et4000w32p_force_redraw,
+    .config        = et4000w32p_config
+};
+#endif
+
+void *et4000w32_merlin_z3_init()
+{
+    void *p = et4000w32p_init(NULL);
+    et4000w32p_t *et4000w32p = (et4000w32p_t *)p;
+
+    return p;
+}
+void *et4000w32_merlin_z2_init()
+{
+    void *p = et4000w32p_init(NULL);
+    et4000w32p_t *et4000w32p = (et4000w32p_t *)p;
+
+    return p;
+}
+
+device_t et4000w32_merlin_z2_device =
+{
+    "Merlin Z2",
+    0,
+    et4000w32_merlin_z2_init,
+    et4000w32p_close,
+    NULL,
+    et4000w32p_speed_changed,
+    et4000w32p_force_redraw,
+    NULL,
+    NULL
+};
+
+
+device_t et4000w32_merlin_z3_device =
+{
+    "Merlin Z3",
+    0,
+    et4000w32_merlin_z3_init,
+    et4000w32p_close,
+    NULL,
+    et4000w32p_speed_changed,
+    et4000w32p_force_redraw,
+    NULL,
+    NULL
+};
+
index beb16865ad189904a4dcd72be0c08e36275e4aae..6ece01477c89ca00b313a1e41bdca2949b4cea7b 100644 (file)
@@ -127,10 +127,12 @@ void inmos_recalctimings(svga_t *svga)
 
         svga->bpp = 1 << ((control >> 17) & 3);
         int bs = 0;
+        inmos->syncdelay = 0;
         if ((control >> 8) & 1) {
             svga->bpp = 32;
             bs = 2;
             svga->rowoffset <<= 2;
+            inmos->syncdelay = 6;
         }
 
         int meminit = inmos->regs[0x12b];
@@ -215,14 +217,13 @@ void inmos_recalctimings(svga_t *svga)
         svga->rowoffset = 2048 + (svga->htotal << bs) - (len << bs);
 
         uint32_t start = inmos->regs[0x080];
-        pclog("%08x\n", control);
         int row = start / 0x2000;
         int col = start % 0x2000;
         int width = svga->rowoffset / (4 * 4);
 
         svga->ma_latch = start * 2;
         svga->rowoffset >>= 3;
-        inmos->syncdelay = (control >> 15) & 7;
+        inmos->syncdelay = ((control >> 15) & 7) * ((bpp + 7) >> 3);
         svga->vtotal = (inmos->regs[0x02a] + inmos->regs[0x029] * 3 + inmos->regs[0x26]) / 2;
         svga->dispend = inmos->regs[0x02a] / 2;
         svga->split = 99999;
@@ -467,7 +468,7 @@ static void inmos_adjust_panning(svga_t *svga)
 
     dst += 24;
     svga->scrollcache_dst = dst;
-    svga->scrollcache_src = src + inmos->syncdelay * ((svga->bpp + 7) >> 3) * 4;
+    svga->scrollcache_src = src + inmos->syncdelay * 4;
 }
 
 static inline uint32_t dword_remap(uint32_t in_addr)
index 7b8b2db187fa9478bc73cd77260d40f7b629023a..0c53d62deae326fef5b7a5403aeece3fd89c4bfe 100644 (file)
@@ -1930,8 +1930,8 @@ void *permedia2_init()
 
     permedia2->svga.fb_only = -1;
 
-    permedia2->getclock = sdac_getclock;
-    permedia2->getclock_p = &permedia2->ramdac;
+    //permedia2->getclock = sdac_getclock;
+    //permedia2->getclock_p = &permedia2->ramdac;
     permedia2->id_ext_pci = 0x07;
     sdac_init(&permedia2->ramdac);
     svga_set_ramdac_type(&permedia2->svga, RAMDAC_8BIT);
index 48126f7b4f4c63470d1556c0f9764c5c6adf4929..ec3f86fbdaeaf2705971dbeaf04c17f09d8844d3 100644 (file)
@@ -14,3 +14,24 @@ void sdac_ramdac_out(uint16_t addr, uint8_t val, sdac_ramdac_t *ramdac, svga_t *
 uint8_t sdac_ramdac_in(uint16_t addr, sdac_ramdac_t *ramdac, svga_t *svga);
 
 float sdac_getclock(int clock, void *p);
+
+
+typedef struct bt482_ramdac_t {
+    uint32_t extpallook[4];
+    uint8_t rgb[3];
+    uint8_t  cursor32_data[256];
+    int      hwc_y;
+    int      hwc_x;
+    uint8_t  cmd_r0;
+    uint8_t  cmd_r1;
+    uint8_t  cursor_r;
+    uint8_t  status;
+    uint8_t  type;
+} bt482_ramdac_t;
+
+void *bt482_ramdac_init(const device_t *info);
+void bt482_ramdac_close(void *priv);
+void bt482_hwcursor_draw(svga_t *svga, int displine);
+void bt482_recalctimings(void *priv, svga_t *svga);
+uint8_t bt482_ramdac_in(uint16_t addr, int rs2, void *priv, svga_t *svga);
+void bt482_ramdac_out(uint16_t addr, int rs2, uint8_t val, void *priv, svga_t *svga);
index a08eff712c6e4e7e8a9b0b51bc190f1bb1d79b22..f28b8e1ee5b9743602d406cc560bf49092b53c15 100644 (file)
@@ -563,6 +563,16 @@ int svga_poll(void *p)
                         svga->hwcursor_oddeven = 1;
                 }
 
+                if (svga->displine == ((svga->dac_hwcursor_latch.y < 0) ? 0 : svga->dac_hwcursor_latch.y) && svga->dac_hwcursor_latch.ena) {
+                    svga->dac_hwcursor_on = svga->dac_hwcursor_latch.ysize - svga->dac_hwcursor_latch.yoff;
+                    svga->dac_hwcursor_oddeven = 0;
+                }
+
+                if (svga->displine == (((svga->dac_hwcursor_latch.y < 0) ? 0 : svga->dac_hwcursor_latch.y) + 1) && svga->dac_hwcursor_latch.ena && svga->interlace) {
+                    svga->dac_hwcursor_on = svga->dac_hwcursor_latch.ysize - (svga->dac_hwcursor_latch.yoff + 1);
+                    svga->dac_hwcursor_oddeven = 1;
+                }
+
                 if (svga->displine == svga->overlay_latch.y && svga->overlay_latch.ena)
                 {
                         svga->overlay_on = svga->overlay_latch.ysize - svga->overlay_latch.yoff;
@@ -591,7 +601,7 @@ int svga_poll(void *p)
                                 video_wait_for_buffer();
                         }
                         
-                        if (svga->hwcursor_on || svga->overlay_on)
+                        if (svga->hwcursor_on || svga->dac_hwcursor_on || svga->overlay_on)
                                 svga->changedvram[svga->ma >> 12] = svga->changedvram[(svga->ma >> 12) + 1] = svga->interlace ? 3 : 2;
                       
                         if (!svga->override)
@@ -606,7 +616,7 @@ int svga_poll(void *p)
                                         svga->overlay_on--;
                         }
 
-                        if (svga->hwcursor_on)
+                        if (svga->hwcursor_on && svga->hwcursor_draw)
                         {
                                 if (!svga->override)
                                         svga->hwcursor_draw(svga, svga->displine);
@@ -614,6 +624,14 @@ int svga_poll(void *p)
                                 if (svga->hwcursor_on && svga->interlace)
                                         svga->hwcursor_on--;
                         }
+                        if (svga->dac_hwcursor_on && svga->dac_hwcursor_draw)
+                        {
+                            if (!svga->override)
+                                svga->dac_hwcursor_draw(svga, svga->displine);
+                            svga->dac_hwcursor_on--;
+                            if (svga->dac_hwcursor_on && svga->interlace)
+                                svga->dac_hwcursor_on--;
+                        }
 
                         if (svga->lastline < svga->displine) 
                                 svga->lastline = svga->displine;
@@ -818,6 +836,9 @@ int svga_poll(void *p)
                         svga->hwcursor_on = 0;
                         svga->hwcursor_latch = svga->hwcursor;
 
+                        svga->dac_hwcursor_on = 0;
+                        svga->dac_hwcursor_latch = svga->dac_hwcursor;
+
                         svga->overlay_on = 0;
                         svga->overlay_latch = svga->overlay;
 
index 010131d699115ebe3252e1413f951a1174b4a3c3..a444a828deadcd09a29a3d6a07641509733d1714 100644 (file)
@@ -44,8 +44,9 @@ typedef struct svga_t
         
         uint8_t dac_mask, dac_status;
         int dac_read, dac_write, dac_pos;
-        int dac_r, dac_g;
-                
+        int dac_r, dac_g, dac_b;
+        int dac_addr;
+
         uint8_t cgastat;
         
         uint8_t plane_mask;
@@ -118,14 +119,16 @@ typedef struct svga_t
                 uint32_t addr;
                 uint32_t pitch;
                 int v_acc, h_acc;
-        } hwcursor, hwcursor_latch, overlay, overlay_latch;
-        
+        } hwcursor, hwcursor_latch, overlay, overlay_latch, dac_hwcursor, dac_hwcursor_latch;
+
         int hwcursor_on;
         int overlay_on;
+        int dac_hwcursor_on;
         
         int hwcursor_oddeven;
         int overlay_oddeven;
-        
+        uint8_t dac_hwcursor_oddeven;
+
         void (*render)(struct svga_t *svga);
         void (*recalctimings_ex)(struct svga_t *svga);
 
@@ -133,6 +136,7 @@ typedef struct svga_t
         uint8_t (*video_in) (uint16_t addr, void *p);
 
         void (*hwcursor_draw)(struct svga_t *svga, int displine);
+        void (*dac_hwcursor_draw)(struct svga_t *svga, int displine);
 
         void (*overlay_draw)(struct svga_t *svga, int displine);
         
@@ -186,6 +190,9 @@ typedef struct svga_t
         uint8_t fcr;
         uint32_t *map8;
         uint32_t(*translate_address)(uint32_t addr, void *priv);
+        int x_add;
+        int y_add;
+        uint8_t ext_overscan;
 
         bool swaprb;
 } svga_t;