]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
Matrox PCI card emulation. Misc 86box merges.
authorToni Wilen <twilen@winuae.net>
Sun, 2 Feb 2025 11:46:52 +0000 (13:46 +0200)
committerToni Wilen <twilen@winuae.net>
Sun, 2 Feb 2025 11:46:52 +0000 (13:46 +0200)
46 files changed:
gfxboard.cpp
include/gfxboard.h
od-win32/winuae_msvc15/winuae_msvc.vcxproj
od-win32/winuae_msvc15/winuae_msvc.vcxproj.filters
pcem/cpu.cpp
pcem/device.h
pcem/dma.cpp
pcem/dma.h
pcem/ibm.h
pcem/keyboard_at.cpp
pcem/mem.cpp
pcem/model.h
pcem/nvr.cpp
pcem/pcemglue.cpp
pcem/pcemglue.h
pcem/pci.h
pcem/pic.cpp
pcem/sound.h
pcem/sound_cms.cpp
pcem/sound_opl.cpp
pcem/sound_speaker.cpp
pcem/thread.h
pcem/timer.h
pcem/vid_bt482_ramdac.cpp
pcem/vid_cl5429.cpp
pcem/vid_et4000.cpp
pcem/vid_et4000w32.cpp
pcem/vid_inmos.cpp
pcem/vid_mga.cpp [new file with mode: 0644]
pcem/vid_ncr.cpp
pcem/vid_permedia2.cpp
pcem/vid_s3.cpp
pcem/vid_s3_virge.cpp
pcem/vid_sc1502x_ramdac.cpp
pcem/vid_sdac_ramdac.cpp
pcem/vid_svga.cpp
pcem/vid_svga.h
pcem/vid_svga_render.cpp
pcem/vid_tvp3026_ramdac.cpp [new file with mode: 0644]
pcem/vid_voodoo.cpp
pcem/vid_voodoo_banshee.cpp
pcem/vid_voodoo_display.cpp
pcem/vid_voodoo_fifo.cpp
pcem/vid_voodoo_reg.cpp
pcem/video.h
x86.cpp

index 80d832633225cc4eed6e81e8fe4058f4f11678b2..1bafeba395fc9c7ca49604e1729a113c66784778 100644 (file)
@@ -33,6 +33,17 @@ static bool memlogw = true;
 
 #include "options.h"
 #include "uae.h"
+
+#include "pcem/device.h"
+#include "pcem/vid_s3_virge.h"
+#include "pcem/vid_cl5429.h"
+#include "pcem/vid_s3.h"
+#include "pcem/vid_voodoo_banshee.h"
+#include "pcem/vid_ncr.h"
+#include "pcem/vid_permedia2.h"
+#include "pcem/vid_inmos.h"
+#include "pcem/vid_et4000.h"
+
 #include "memory.h"
 #include "debug.h"
 #include "custom.h"
@@ -47,15 +58,6 @@ static bool memlogw = true;
 #include "devices.h"
 #include "gfxfilter.h"
 #include "flashrom.h"
-#include "pcem/device.h"
-#include "pcem/vid_s3_virge.h"
-#include "pcem/vid_cl5429.h"
-#include "pcem/vid_s3.h"
-#include "pcem/vid_voodoo_banshee.h"
-#include "pcem/vid_ncr.h"
-#include "pcem/vid_permedia2.h"
-#include "pcem/vid_inmos.h"
-#include "pcem/vid_et4000.h"
 #include "pci.h"
 #include "pci_hw.h"
 #include "pcem/pcemglue.h"
@@ -63,6 +65,7 @@ static bool memlogw = true;
 #include "qemuvga/vga.h"
 #include "draco.h"
 
+
 extern void put_io_pcem(uaecptr, uae_u32, int);
 extern uae_u32 get_io_pcem(uaecptr, int);
 extern void put_mem_pcem(uaecptr, uae_u32, int);
@@ -128,7 +131,7 @@ struct gfxboard
        uae_u32 romtype;
        uae_u8 er_type;
        struct gfxboard_func *func;
-       device_t *pcemdev;
+       const device_t *pcemdev;
        uae_u8 er_flags;
        int bustype;
 };
@@ -391,6 +394,34 @@ static const struct gfxboard boards[] =
                0x00000000, 0x00200000, 0x00400000, 0x10000000, 0, 0, -1, false, false,
                0, 0, NULL, &s3_trio64_device, 0, GFXBOARD_BUSTYPE_PCI
        },
+       {
+               GFXBOARD_ID_MATROX_MILLENNIUM_PCI,
+               _T("Matrox Millennium [PCI]"), _T("Matrox"), _T("Matrox_Millennium"),
+               0, 0, 0, 0,
+               0x00000000, 0x00200000, 0x00400000, 0x10000000, 0, 0, -1, false, false,
+               0, 0, NULL, &millennium_device, 0, GFXBOARD_BUSTYPE_PCI
+       },
+       {
+               GFXBOARD_ID_MATROX_MILLENNIUM_II_PCI,
+               _T("Matrox Millennium II [PCI]"), _T("Matrox"), _T("Matrox_Millennium_II"),
+               0, 0, 0, 0,
+               0x00000000, 0x00200000, 0x01000000, 0x10000000, 0, 0, -1, false, false,
+               0, 0, NULL, &millennium_ii_device, 0, GFXBOARD_BUSTYPE_PCI
+       },
+       {
+               GFXBOARD_ID_MATROX_MYSTIQUE_PCI,
+               _T("Matrox Mystique [PCI]"), _T("Matrox"), _T("Matrox_Mystique"),
+               0, 0, 0, 0,
+               0x00000000, 0x00200000, 0x00800000, 0x10000000, 0, 0, -1, false, false,
+               0, 0, NULL, &mystique_device, 0, GFXBOARD_BUSTYPE_PCI
+       },
+       {
+               GFXBOARD_ID_MATROX_MYSTIQUE220_PCI,
+               _T("Matrox Mystique 220 [PCI]"), _T("Matrox"), _T("Matrox_Mystique220"),
+               0, 0, 0, 0,
+               0x00000000, 0x00200000, 0x00800000, 0x10000000, 0, 0, -1, false, false,
+               0, 0, NULL, &mystique_220_device, 0, GFXBOARD_BUSTYPE_PCI
+       },
 #if 0
        {
                GFXBOARD_ID_GD5446_PCI,
@@ -509,7 +540,7 @@ struct rtggfxboard
 
        struct gfxboard_func *func;
 
-       device_t *pcemdev;
+       const device_t *pcemdev;
        void *pcemobject; // device_t
        void *pcemobject2; // svga_t
        int pcem_mmio_offset;
@@ -527,6 +558,7 @@ struct rtggfxboard
        int mmiobyteswapmode;
        struct pci_board_state *pcibs;
        bool pcem_direct;
+       int lfbbar;
 
        int width_redraw, height_redraw;
 
@@ -1072,7 +1104,7 @@ static void init_board (struct rtggfxboard *gb)
                extern void initpcemvideo(void*, bool);
                extern void *svga_get_object(void);
                initpcemvideo(gb, gb->board->swap);
-               gb->pcemobject = gb->pcemdev->init();
+               gb->pcemobject = gb->pcemdev->init(gb->pcemdev);
                gb->pcemobject2 = svga_get_object();
        }
        picasso_allocatewritewatch(gb->rbc->rtg_index, gb->rbc->rtgmem_size);
@@ -1164,6 +1196,7 @@ static void gfxboard_free_slot2(struct rtggfxboard *gb)
        }
        if (gb->pcemdev) {
                if (gb->pcemobject) {
+                       pcemfreeaddeddevices();
                        gb->pcemdev->close(gb->pcemobject);
                        gb->pcemobject = NULL;
                }
@@ -1683,6 +1716,7 @@ void gfxboard_vsync_handler(bool full_redraw_required, bool redraw_required)
                                }
                                gb->pcem_vblank = 0;
                                extern int console_logging;
+#if 0
                                if (console_logging) {
                                        fcount++;
                                        if ((fcount % 50) == 0) {
@@ -1696,6 +1730,7 @@ void gfxboard_vsync_handler(bool full_redraw_required, bool redraw_required)
                                                }
                                        }
                                }
+#endif
                                if (!gb->board->hasswitcher && gb->vram) {
                                        bool svga_on(void *p);
                                        bool on = svga_on(gb->pcemobject2);
@@ -3459,6 +3494,7 @@ static void gfxboard_free_board(struct rtggfxboard *gb)
        }
        if (gb->pcemdev) {
                if (gb->pcemobject) {
+                       pcemfreeaddeddevices();
                        gb->pcemdev->close(gb->pcemobject);
                        gb->pcemobject = NULL;
                        gb->pcemobject2 = NULL;
@@ -3912,6 +3948,20 @@ void gfxboard_voodoo_lfb_endianswap(int m)
        }
 }
 
+void gfxboard_matrox_lfb_endianswap(int m)
+{
+       for (int i = 0; i < MAX_RTG_BOARDS; i++) {
+               struct rtggfxboard *gb = &rtggfxboards[i];
+               if (gb->active && gb->board->bustype == GFXBOARD_BUSTYPE_PCI) {
+                       write_log("%d\n", m);
+                       if (m == 1) {
+                               m = 3;
+                       }
+                       gb->lfbbyteswapmode = m;
+               }
+       }
+}
+
 static void pci_change_config(struct pci_board_state *pci)
 {
        struct rtggfxboard *gb = (struct rtggfxboard *)pci->userdata;
@@ -3946,8 +3996,12 @@ static void pci_change_config(struct pci_board_state *pci)
        } else if (gb->rbc->rtgmem_type == GFXBOARD_ID_S3VIRGE_PCI ||
                gb->rbc->rtgmem_type == GFXBOARD_ID_S3TRIO64_PCI ||
                gb->rbc->rtgmem_type == GFXBOARD_ID_PERMEDIA2_PCI ||
-               gb->rbc->rtgmem_type == GFXBOARD_ID_GD5446_PCI) {
-               if (pci->memory_map_active) {
+               gb->rbc->rtgmem_type == GFXBOARD_ID_GD5446_PCI ||
+               gb->rbc->rtgmem_type == GFXBOARD_ID_MATROX_MILLENNIUM_PCI ||
+               gb->rbc->rtgmem_type == GFXBOARD_ID_MATROX_MILLENNIUM_II_PCI ||
+               gb->rbc->rtgmem_type == GFXBOARD_ID_MATROX_MYSTIQUE_PCI ||
+               gb->rbc->rtgmem_type == GFXBOARD_ID_MATROX_MYSTIQUE220_PCI) {
+                       if (pci->memory_map_active) {
                        struct pci_bridge *pcib = pci->bridge;
                        reinit_vram(gb, pci->bar[0] + pcib->memory_start_offset[pcib->windowindex], false);
                }
@@ -4008,7 +4062,7 @@ static void REGPARAM2 voodoo3_mb1_lput(struct pci_board_state *pcibs, uaecptr ad
 {
        struct rtggfxboard *gb = (struct rtggfxboard*)pcibs->userdata;
        int m = gb->lfbbyteswapmode;
-       addr -= pcibs->bar[1];
+       addr -= pcibs->bar[gb->lfbbar];
        addr &= 0x00ffffff;
        switch (m)
        {
@@ -4039,7 +4093,7 @@ static uae_u32 REGPARAM2 voodoo3_mb1_lget(struct pci_board_state* pcibs, uaecptr
        struct rtggfxboard* gb = (struct rtggfxboard*)pcibs->userdata;
        int m = gb->lfbbyteswapmode;
        uae_u32 v = 0;
-       addr -= pcibs->bar[1];
+       addr -= pcibs->bar[gb->lfbbar];
        addr &= 0x00ffffff;
        switch (m)
        {
@@ -4071,7 +4125,7 @@ static void REGPARAM2 voodoo3_mb1_wput(struct pci_board_state *pcibs, uaecptr ad
 {
        struct rtggfxboard *gb = (struct rtggfxboard*)pcibs->userdata;
        int m = gb->lfbbyteswapmode;
-       addr -= pcibs->bar[1];
+       addr -= pcibs->bar[gb->lfbbar];
        addr &= 0x00ffffff;
        switch (m)
        {
@@ -4102,7 +4156,7 @@ static uae_u32 REGPARAM2 voodoo3_mb1_wget(struct pci_board_state* pcibs, uaecptr
        struct rtggfxboard* gb = (struct rtggfxboard*)pcibs->userdata;
        int m = gb->lfbbyteswapmode;
        uae_u32 v = 0;
-       addr -= pcibs->bar[1];
+       addr -= pcibs->bar[gb->lfbbar];
        addr &= 0x00ffffff;
        switch (m)
        {
@@ -4134,7 +4188,7 @@ static void REGPARAM2 voodoo3_mb1_bput(struct pci_board_state *pcibs, uaecptr ad
 {
        struct rtggfxboard *gb = (struct rtggfxboard*)pcibs->userdata;
        int m = gb->lfbbyteswapmode;
-       addr -= pcibs->bar[1];
+       addr -= pcibs->bar[gb->lfbbar];
        addr &= 0x00ffffff;
        switch (m)
        {
@@ -4150,7 +4204,7 @@ static uae_u32 REGPARAM2 voodoo3_mb1_bget(struct pci_board_state *pcibs, uaecptr
 {
        struct rtggfxboard *gb = (struct rtggfxboard*)pcibs->userdata;
        int m = gb->lfbbyteswapmode;
-       addr -= pcibs->bar[1];
+       addr -= pcibs->bar[gb->lfbbar];
        addr &= 0x00ffffff;
        switch (m)
        {
@@ -4441,6 +4495,75 @@ static uae_u32 REGPARAM2 s3virge_io_bget(struct pci_board_state *pcibs, uaecptr
        return v;
 }
 
+static void REGPARAM2 matrox_io_lput(struct pci_board_state *pcibs, uaecptr addr, uae_u32 b)
+{
+       put_mem_pcem(addr, b, 2);
+}
+static void REGPARAM2 matrox_io_wput(struct pci_board_state *pcibs, uaecptr addr, uae_u32 b)
+{
+       put_mem_pcem(addr, b, 1);
+}
+static void REGPARAM2 matrox_io_bput(struct pci_board_state *pcibs, uaecptr addr, uae_u32 b)
+{
+       put_mem_pcem(addr, b, 0);
+}
+static uae_u32 REGPARAM2 matrox_io_lget(struct pci_board_state *pcibs, uaecptr addr)
+{
+       uae_u32 b = get_mem_pcem(addr, 2);
+       return b;
+}
+static uae_u32 REGPARAM2 matrox_io_wget(struct pci_board_state *pcibs, uaecptr addr)
+{
+       uae_u16 b = get_mem_pcem(addr, 1);
+       return b;
+}
+static uae_u32 REGPARAM2 matrox_io_bget(struct pci_board_state *pcibs, uaecptr addr)
+{
+       uae_u32 v = get_mem_pcem(addr, 0);
+       return v;
+}
+
+static const struct pci_config matrox_pci_config =
+{
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 }
+};
+
+static const struct pci_board matrox_pci_board2 =
+{
+       _T("MATROX"),
+       &matrox_pci_config, NULL, NULL, NULL, NULL, NULL,
+       {
+               { voodoo3_mb1_lget, voodoo3_mb1_wget, voodoo3_mb1_bget, voodoo3_mb1_lput, voodoo3_mb1_wput, voodoo3_mb1_bput },
+               { matrox_io_lget, matrox_io_wget, matrox_io_bget, matrox_io_lput, matrox_io_wput, matrox_io_bput },
+               { NULL },
+               { NULL },
+               { NULL },
+               { NULL },
+               { voodoo3_bios_lget, voodoo3_bios_wget, voodoo3_bios_bget, NULL, NULL, NULL },
+               { NULL },
+       },
+       true,
+       get_pci_pcem, put_pci_pcem, pci_change_config
+};
+
+static const struct pci_board matrox_pci_board =
+{
+       _T("MATROX"),
+       &matrox_pci_config, NULL, NULL, NULL, NULL, NULL,
+       {
+               { matrox_io_lget, matrox_io_wget, matrox_io_bget, matrox_io_lput, matrox_io_wput, matrox_io_bput },
+               { voodoo3_mb1_lget, voodoo3_mb1_wget, voodoo3_mb1_bget, voodoo3_mb1_lput, voodoo3_mb1_wput, voodoo3_mb1_bput },
+               { NULL },
+               { NULL },
+               { NULL },
+               { NULL },
+               { voodoo3_bios_lget, voodoo3_bios_wget, voodoo3_bios_bget, NULL, NULL, NULL },
+               { NULL },
+       },
+       true,
+       get_pci_pcem, put_pci_pcem, pci_change_config
+};
+
 static const struct pci_config s3virge_pci_config =
 {
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 }
@@ -4451,7 +4574,7 @@ static const struct pci_board s3virge_pci_board =
        _T("S3VIRGE"),
        &s3virge_pci_config, NULL, NULL, NULL, NULL, NULL,
        {
-               { s3virge_mb0_lget, s3virge_mb0_wget, s3virge_mb0_bget, s3virge_mb0_lput, s3virge_mb0_wput, s3virge_mb0_bput },
+               { voodoo3_mb0_lget, voodoo3_mb0_wget, voodoo3_mb0_bget, voodoo3_mb0_lput, voodoo3_mb0_wput, voodoo3_mb0_bput },
                { NULL },
                { NULL },
                { NULL },
@@ -4947,6 +5070,7 @@ bool gfxboard_init_memory (struct autoconfig_info *aci)
                copyvrambank(&gb->gfxboard_bank_memory, gb->gfxmem_bank, false);
                gb->configured_mem = 1;
                gb->configured_regs = 1;
+               gb->lfbbar = 1;
                struct pci_bridge *b = pci_bridge_get();
                if (b) {
                        if (gb->rbc->rtgmem_type == GFXBOARD_ID_VOODOO3_PCI || gb->rbc->rtgmem_type == GFXBOARD_ID_VOODOO5_PCI) {
@@ -4963,6 +5087,16 @@ bool gfxboard_init_memory (struct autoconfig_info *aci)
                                gb->pcibs = pci_board_add(b, &s3trio_pci_board, -1, -1, aci, gb);
                        } else if (gb->rbc->rtgmem_type == GFXBOARD_ID_S3VIRGE_PCI) {
                                gb->pcibs = pci_board_add(b, &s3virge_pci_board, -1, -1, aci, gb);
+                       } else if (gb->rbc->rtgmem_type == GFXBOARD_ID_MATROX_MILLENNIUM_PCI) {
+                               gb->pcibs = pci_board_add(b, &matrox_pci_board, -1, -1, aci, gb);
+                       } else if (gb->rbc->rtgmem_type == GFXBOARD_ID_MATROX_MILLENNIUM_II_PCI) {
+                               gb->pcibs = pci_board_add(b, &matrox_pci_board2, -1, -1, aci, gb);
+                               gb->lfbbar = 0;
+                       } else if (gb->rbc->rtgmem_type == GFXBOARD_ID_MATROX_MYSTIQUE_PCI) {
+                               gb->pcibs = pci_board_add(b, &matrox_pci_board, -1, -1, aci, gb);
+                       } else if (gb->rbc->rtgmem_type == GFXBOARD_ID_MATROX_MYSTIQUE220_PCI) {
+                               gb->pcibs = pci_board_add(b, &matrox_pci_board2, -1, -1, aci, gb);
+                               gb->lfbbar = 0;
                        }
                }
                gb->gfxboard_intena = 1;
index dff51b1215b3832a0178093fa97196e7b2501b43..9aa8ec7fec48652f1c46c8e8e0dbdf4048e8f548 100644 (file)
@@ -98,8 +98,12 @@ int pcem_getvramsize(void);
 #define GFXBOARD_ID_GRAFFITY_Z2 34
 #define GFXBOARD_ID_GRAFFITY_Z3 35
 #define GFXBOARD_ID_RAINBOWII 36
-#define GFXBOARD_ID_GD5446_PCI 37
-#define GFXBOARD_ID_VOODOO5_PCI 38
+#define GFXBOARD_ID_MATROX_MILLENNIUM_PCI 37
+#define GFXBOARD_ID_MATROX_MILLENNIUM_II_PCI 38
+#define GFXBOARD_ID_MATROX_MYSTIQUE_PCI 39
+#define GFXBOARD_ID_MATROX_MYSTIQUE220_PCI 40
+#define GFXBOARD_ID_GD5446_PCI 41
+#define GFXBOARD_ID_VOODOO5_PCI 42
 
 #define GFXBOARD_BUSTYPE_Z 0
 #define GFXBOARD_BUSTYPE_PCI 1
index fc43f6702bff7fe4ad6afc55eabe6dba5d3562c6..6f94454675af41f67c5c1a7fa74935167dd7f18e 100644 (file)
       <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
       <ForcedIncludeFiles>%(ForcedIncludeFiles)</ForcedIncludeFiles>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
-      <LanguageStandard>stdcpp20</LanguageStandard>
+      <LanguageStandard>stdcpplatest</LanguageStandard>
       <AdditionalOptions>/Zc:strictStrings- %(AdditionalOptions)</AdditionalOptions>
-      <LanguageStandard_C>stdc17</LanguageStandard_C>
+      <LanguageStandard_C>stdclatest</LanguageStandard_C>
       <ConformanceMode>false</ConformanceMode>
       <EnforceTypeConversionRules>
       </EnforceTypeConversionRules>
     <ClCompile Include="..\..\pcem\vid_et4000.cpp" />
     <ClCompile Include="..\..\pcem\vid_et4000w32.cpp" />
     <ClCompile Include="..\..\pcem\vid_inmos.cpp" />
+    <ClCompile Include="..\..\pcem\vid_mga.cpp" />
     <ClCompile Include="..\..\pcem\vid_ncr.cpp" />
     <ClCompile Include="..\..\pcem\vid_permedia2.cpp" />
     <ClCompile Include="..\..\pcem\vid_s3.cpp" />
     <ClCompile Include="..\..\pcem\vid_sdac_ramdac.cpp" />
     <ClCompile Include="..\..\pcem\vid_svga.cpp" />
     <ClCompile Include="..\..\pcem\vid_svga_render.cpp" />
+    <ClCompile Include="..\..\pcem\vid_tvp3026_ramdac.cpp" />
     <ClCompile Include="..\..\pcem\vid_voodoo.cpp" />
     <ClCompile Include="..\..\pcem\vid_voodoo_banshee.cpp" />
     <ClCompile Include="..\..\pcem\vid_voodoo_banshee_blitter.cpp" />
index 839ce97f3a5a66450dbd2b223d7829fa3dbd4173..829f6f01ad7b8374bb15b96c3d045915c8146c2e 100644 (file)
     <ClCompile Include="..\..\mos6502.cpp">
       <Filter>common</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\pcem\vid_mga.cpp">
+      <Filter>pcem</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\pcem\vid_tvp3026_ramdac.cpp">
+      <Filter>pcem</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <None Include="..\resources\35floppy.ico">
index 9d6ac58d8f0e1b4327321c48691093c702056dea..46f648bd6d3dea591f66639d22239b0c769cdb29 100644 (file)
@@ -1,4 +1,6 @@
+
 #include "ibm.h"
+#include "device.h"
 #include "cpu.h"
 #include "model.h"
 #include "io.h"
index e7152b38e172c4c239524e78dee63fd5c43ee274..1f3248e7aac75dc029413f985e58d58375291eae 100644 (file)
@@ -25,19 +25,29 @@ typedef struct device_config_t
 
 typedef struct device_t
 {
-        char name[50];
-        uint32_t flags;
-        void *(*init)();
-        void (*close)(void *p);
-        int  (*available)();
-        void (*speed_changed)(void *p);
-        void (*force_redraw)(void *p);
-        void (*add_status_info)(char *s, int max_len, void *p);
-        device_config_t *config;
+    const char *name;
+    const char *internal_name;
+    uint32_t    flags; /* system flags */
+    uintptr_t   local; /* flags local to device */
+
+    union {
+        void *(*init)(const struct device_t *);
+        void *(*init_ext)(const struct device_t *, void *);
+    };
+    void (*close)(void *priv);
+    void (*reset)(void *priv);
+    union {
+        int (*available)(void);
+        int (*poll)(void *priv);
+    };
+    void (*speed_changed)(void *priv);
+    void (*force_redraw)(void *priv);
+
+    const device_config_t *config;
 } device_t;
 
 void device_init();
-void device_add(device_t *d);
+void *device_add(const device_t *d);
 void device_close_all();
 int device_available(device_t *d);
 void device_speed_changed();
@@ -49,16 +59,43 @@ extern char *current_device_name;
 int device_get_config_int(const char *name);
 char *device_get_config_string(const char *name);
 
-enum
-{
-        DEVICE_NOT_WORKING = 1, /*Device does not currently work correctly and will be disabled in a release build*/
-        DEVICE_AT = 2,          /*Device requires an AT-compatible system*/
-        DEVICE_MCA = 0x20,      /*Device requires an MCA system*/
-        DEVICE_PCI = 0x40,      /*Device requires a PCI system*/
-        DEVICE_PS1 = 0x80       /*Device is only for IBM PS/1 Model 2011*/
+enum {
+    DEVICE_PCJR = 2,          /* requires an IBM PCjr */
+    DEVICE_XTKBC = 4,          /* requires an XT-compatible keyboard controller */
+    DEVICE_AT = 8,          /* requires an AT-compatible system */
+    DEVICE_ATKBC = 0x10,       /* requires an AT-compatible keyboard controller */
+    DEVICE_PS2 = 0x20,       /* requires a PS/1 or PS/2 system */
+    DEVICE_ISA = 0x40,       /* requires the ISA bus */
+    DEVICE_CBUS = 0x80,       /* requires the C-BUS bus */
+    DEVICE_PCMCIA = 0x100,      /* requires the PCMCIA bus */
+    DEVICE_MCA = 0x200,      /* requires the MCA bus */
+    DEVICE_HIL = 0x400,      /* requires the HP HIL bus */
+    DEVICE_EISA = 0x800,      /* requires the EISA bus */
+    DEVICE_AT32 = 0x1000,     /* requires the Mylex AT/32 local bus */
+    DEVICE_OLB = 0x2000,     /* requires the OPTi local bus */
+    DEVICE_VLB = 0x4000,     /* requires the VLB bus */
+    DEVICE_PCI = 0x8000,     /* requires the PCI bus */
+    DEVICE_CARDBUS = 0x10000,    /* requires the CardBus bus */
+    DEVICE_USB = 0x20000,    /* requires the USB bus */
+    DEVICE_AGP = 0x40000,    /* requires the AGP bus */
+    DEVICE_AC97 = 0x80000,    /* requires the AC'97 bus */
+    DEVICE_COM = 0x100000,   /* requires a serial port */
+    DEVICE_LPT = 0x200000,   /* requires a parallel port */
+    DEVICE_KBC = 0x400000,   /* is a keyboard controller */
+    DEVICE_SOFTRESET = 0x800000,   /* requires to be reset on soft reset */
+
+    DEVICE_ONBOARD = 0x40000000, /* is on-board */
+    DEVICE_PIT = 0x80000000, /* device is a PIT */
+
+    DEVICE_ALL = 0xffffffff  /* match all devices */
 };
 
 int model_get_config_int(const char *s);
 char *model_get_config_string(const char *s);
 
+extern const device_t millennium_device;
+extern const device_t millennium_ii_device;
+extern const device_t mystique_device;
+extern const device_t mystique_220_device;
+
 #endif
index e38fb07df828f9efdb2465a515c7503615046e28..9c2cb079e45bfc5bb83bfc22eb458d0a6ff0ea66 100644 (file)
@@ -1,5 +1,6 @@
 #include "ibm.h"
 
+#include "device.h"
 #include "dma.h"
 #include "fdc.h"
 #include "io.h"
index d4b2c71f34cd4b5a9e6be8175059de3bc667ccc9..ebede632cfb1a4de84f89ba73456cc5de3712a96 100644 (file)
@@ -15,3 +15,6 @@ void writedma2(uint8_t temp);
 
 int dma_channel_read(int channel);
 int dma_channel_write(int channel, uint16_t val);
+
+void dma_bm_read(uint32_t PhysAddress, uint8_t *DataRead, uint32_t TotalSize, int TransferSize);
+void dma_bm_write(uint32_t PhysAddress, const uint8_t *DataWrite, uint32_t TotalSize, int TransferSize);
index a4d405e7b6f869c493b98745f5243415743925f4..48397a2aedffb8c143a8a054b60a507f47f0dc9e 100644 (file)
@@ -501,7 +501,7 @@ void speedchanged();
 void saveconfig(char *fn);
 void saveconfig_global_only();
 
-#define UNUSED(x) (void)x
+#define UNUSED(x) x
 
 #define MIN(a, b) ((a) < (b) ? (a) : (b))
 
index 07729ac6b91bf5cb3d299b43b700668df9002dc6..48c9bb76e64816891dcaba41ef0e0aae4268a85a 100644 (file)
@@ -1,6 +1,7 @@
 #include "ibm.h"
 #include "io.h"
 #include "mem.h"
+#include "device.h"
 #include "pic.h"
 #include "pit.h"
 #include "sound.h"
index f2fcbb6c6b3b969b46b7252af8eab8f996d140cf..7f5173f0b74886070543c23dc7fd4fece750a59b 100644 (file)
@@ -11,6 +11,7 @@
 
 #include "config.h"
 #include "mem.h"
+#include "device.h"
 #include "video.h"
 #include "x86.h"
 #include "cpu.h"
index 6834e43934212bf0412a31fdfaa1ec894292a55a..5b1c9846afca9a230e577bc798519409060c1f37 100644 (file)
@@ -30,7 +30,7 @@ typedef struct
         int min_ram, max_ram;
         int ram_granularity;
         void (*init)();
-        struct device_t *device;
+        device_t *device;
 } MODEL;
 
 extern MODEL models[];
@@ -45,6 +45,6 @@ char *model_getname();
 char *model_get_internal_name();
 int model_get_model_from_internal_name(char *s);
 void model_init();
-struct device_t *model_getdevice(int model);
+device_t *model_getdevice(int model);
 int model_has_fixed_gfx(int model);
 int model_has_optional_gfx(int model);
index 7668a80ace82f4dd9a19b0370b7de3617bf8be20..fae178e25ae790cda0dcbf71d712254cfc878305 100644 (file)
@@ -490,7 +490,7 @@ void savenvr()
 }
 #endif
 
-static void *nvr_init()
+static void *nvr_init(const device_t *info)
 {
         nvr_t *nvr = (nvr_t *)malloc(sizeof(nvr_t));
         memset(nvr, 0, sizeof(nvr_t));
@@ -512,13 +512,13 @@ static void nvr_close(void *p)
 
 device_t nvr_device =
 {
-        "Motorola MC146818 RTC",
-        0,
+        "Motorola MC146818 RTC", NULL,
+        0, 0,
         nvr_init,
         nvr_close,
         NULL,
-        nvr_speed_changed,
         NULL,
+        nvr_speed_changed,
         NULL,
         NULL
 };
index e9829cc62cb30ac1587ecdcc855454ebb870c5e3..866c1d9763f3b0010e623c94d1e6f21320b9b863 100644 (file)
@@ -4,6 +4,7 @@
 #include "pit.h"
 #include "pic.h"
 #include "cpu.h"
+#include "device.h"
 #include "model.h"
 #include "x86.h"
 #include "x86_ops.h"
@@ -396,6 +397,7 @@ uint8_t fontdat8x12[256][16];       /* MDSI Genius font */
 uint8_t fontdat12x18[256][36]; /* IM1024 font */
 uint8_t fontdatksc5601[16384][32]; /* Korean KSC-5601 font */
 uint8_t fontdatksc5601_user[192][32]; /* Korean KSC-5601 user defined font */
+uint32_t *video_6to8;
 
 int PCI;
 int readflash;
@@ -412,6 +414,8 @@ uint64_t timer_freq;
 uint8_t edatlookup[4][4];
 uint8_t rotatevga[8][256];
 uint32_t *video_15to32, *video_16to32;
+monitor_t monitors[MONITORS_NUM];
+bitmap_t target_bitmap;
 
 static void *gfxboard_priv;
 
@@ -516,6 +520,19 @@ static void timer_remove_headx(void)
                timer->enabled = 0;
        }
 }
+void timer_advance_u64x(pc_timer_t *timer, uint64_t delay)
+{
+       uint32_t int_delay = delay >> 32;
+       uint32_t frac_delay = delay & 0xffffffff;
+
+       if ((frac_delay + timer->ts_frac) < frac_delay)
+               timer->ts_integer++;
+       timer->ts_frac += frac_delay;
+       timer->ts_integer += int_delay;
+
+       timer_enablex(timer);
+}
+
 
 void pcemglue_hsync(void)
 {
@@ -541,6 +558,23 @@ void pcemvideorbswap(bool swapped)
        }
 }
 
+static int calc_6to8(int c)
+{
+       int    ic;
+       int    i8;
+       double d8;
+
+       ic = c;
+       if (ic == 64)
+               ic = 63;
+       else
+               ic &= 0x3f;
+       d8 = (ic / 63.0) * 255.0;
+       i8 = (int)d8;
+
+       return (i8 & 0xff);
+}
+
 void initpcemvideo(void *p, bool swapped)
 {
        int c, d, e;
@@ -596,12 +630,21 @@ void initpcemvideo(void *p, bool swapped)
                buffer32 = (PCBITMAP *)calloc(sizeof(PCBITMAP) + sizeof(uint8_t *) * 4096, 1);
                buffer32->w = 2048;
                buffer32->h = 4096;
+               target_bitmap.w = buffer32->w;
+               target_bitmap.h = buffer32->h;
                buffer32->dat = xcalloc(uae_u8, buffer32->w * buffer32->h * 4);
+               target_bitmap.dat = (uae_u32*)buffer32->dat;
                for (int i = 0; i < buffer32->h; i++) {
                        buffer32->line[i] = buffer32->dat + buffer32->w * 4 * i;
+                       target_bitmap.line[i] = (uae_u32*)buffer32->line[i];
                }
        }
 
+       video_6to8 = (uint32_t*)malloc(4 * 256);
+       for (uint16_t c = 0; c < 256; c++) {
+               video_6to8[c] = calc_6to8(c);
+       }
+
        pcem_linear_read_b = dummy_bread;
        pcem_linear_read_w = dummy_wread;
        pcem_linear_read_l = dummy_lread;
@@ -611,6 +654,9 @@ void initpcemvideo(void *p, bool swapped)
        pcem_mapping_linear = NULL;
        pcem_mapping_linear_offset = 0;
        timer_head = NULL;
+
+       monitors[0].mon_changeframecount = 2;
+       monitors[0].target_buffer = &target_bitmap;
 }
 
 extern void *svga_get_object(void);
@@ -659,6 +705,11 @@ uae_u8 *getpcembuffer32(int x, int y, int yy)
        return buffer32->line[y + yy] + x * 4;
 }
 
+void video_inform_monitor(int type, const video_timings_t *ptr, int monitor_index)
+{
+}
+
+int monitor_index_global;
 
 void video_wait_for_buffer(void)
 {
@@ -670,6 +721,37 @@ void updatewindowsize(int x, int mx, int y, int my)
        gfxboard_resize(x, y, mx, my, gfxboard_priv);
 }
 
+#define MAX_ADDED_DEVICES 8
+
+struct addeddevice {
+       const device_t *dev;
+       void *priv;
+};
+
+static addeddevice added_devices[MAX_ADDED_DEVICES];
+
+void *device_add(const device_t *d)
+{
+       for (int i = 0; i < MAX_ADDED_DEVICES; i++) {
+               if (!added_devices[i].dev) {
+                       added_devices[i].dev = d;
+                       added_devices[i].priv = d->init(d);
+                       return added_devices[i].priv;
+               }
+       }
+       return NULL;
+}
+
+void pcemfreeaddeddevices(void)
+{
+       for (int i = 0; i < MAX_ADDED_DEVICES; i++) {
+               if (added_devices[i].dev) {
+                       added_devices[i].dev->close(added_devices[i].priv);
+                       added_devices[i].dev = NULL;
+               }
+       }
+}
+
 static void (*pci_card_write)(int func, int addr, uint8_t val, void *priv);
 static uint8_t(*pci_card_read)(int func, int addr, void *priv);
 static void *pci_card_priv;
@@ -689,6 +771,14 @@ uae_u8 get_pci_pcem(uaecptr addr)
        return v;
 }
 
+void pci_add_card(uint8_t add_type, uint8_t(*read)(int func, int addr, void *priv),
+       void (*write)(int func, int addr, uint8_t val, void *priv), void *priv, uint8_t *slot)
+{
+       pci_card_read = read;
+       pci_card_write = write;
+       pci_card_priv = priv;
+}
+
 int pci_add(uint8_t(*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv)
 {
        pci_card_read = read;
@@ -701,12 +791,12 @@ void pci_set_irq_routing(int card, int irq)
 {
        //write_log(_T("pci_set_irq_routing %d %d\n"), card, irq);
 }
-void pci_set_irq(int card, int pci_int)
+void pci_set_irq(int card, int pci_int, uint8_t *state)
 {
        //write_log(_T("pci_set_irq %d %d\n"), card, pci_int);
        gfxboard_intreq(gfxboard_priv, 1, true);
 }
-void pci_clear_irq(int card, int pci_int)
+void pci_clear_irq(int card, int pci_int, uint8_t *state)
 {
        //write_log(_T("pci_clear_irq %d %d\n"), card, pci_int);
        gfxboard_intreq(gfxboard_priv, 0, true);
@@ -737,6 +827,14 @@ event_t *thread_create_event(void)
        uae_sem_init(&sem, 1, 0);
        return sem;
 }
+int thread_wait(thread_t *arg)
+{
+       if (!arg) {
+               return 0;
+       }
+       uae_sem_wait((uae_sem_t*)&arg);
+       return 1;
+}
 void thread_set_event(event_t *event)
 {
        uae_sem_post((uae_sem_t*)&event);
@@ -767,25 +865,47 @@ mutex_t* thread_create_mutex(void)
        return mutex;
 }
 
-void thread_lock_mutex(mutex_t *_mutex)
+int thread_wait_mutex(mutex_t *_mutex)
 {
+       if (!_mutex) {
+               return 0;
+       }
        win_mutex_t *mutex = (win_mutex_t*)_mutex;
        WaitForSingleObject(mutex->handle, INFINITE);
+       return 1;
 }
 
-void thread_unlock_mutex(mutex_t *_mutex)
+int thread_release_mutex(mutex_t *_mutex)
 {
+       if (!_mutex) {
+               return 0;
+       }
        win_mutex_t *mutex = (win_mutex_t*)_mutex;
        ReleaseSemaphore(mutex->handle, 1, NULL);
+       return 1;
 }
 
-void thread_destroy_mutex(mutex_t *_mutex)
+void thread_close_mutex(mutex_t *_mutex)
 {
        win_mutex_t *mutex = (win_mutex_t*)_mutex;
        CloseHandle(mutex->handle);
        xfree(mutex);
 }
 
+int thread_test_mutex(mutex_t *_mutex)
+{
+       if (!_mutex) {
+               return 0;
+       }
+       win_mutex_t *mutex = (win_mutex_t *)_mutex;
+       DWORD ret = WaitForSingleObject(mutex->handle, 0);
+       if (ret == WAIT_OBJECT_0)
+               return 1;
+       return 0;
+}
+
+
+
 static mem_mapping_t *getmm(uaecptr *addrp)
 {
        uaecptr addr = *addrp;
@@ -1105,3 +1225,63 @@ char *model_get_config_string(const char *s)
 void upc_set_mouse(void (*mouse_write)(uint8_t, void*), void *p)
 {
 }
+
+
+/* DMA Bus Master Page Read/Write */
+void
+dma_bm_read(uint32_t PhysAddress, uint8_t *DataRead, uint32_t TotalSize, int TransferSize)
+{
+#if 0
+       uint32_t n;
+       uint32_t n2;
+       uint8_t  bytes[4] = { 0, 0, 0, 0 };
+
+       n = TotalSize & ~(TransferSize - 1);
+       n2 = TotalSize - n;
+
+       /* Do the divisible block, if there is one. */
+       if (n) {
+               for (uint32_t i = 0; i < n; i += TransferSize)
+                       mem_read_phys((void *)&(DataRead[i]), PhysAddress + i, TransferSize);
+       }
+
+       /* Do the non-divisible block, if there is one. */
+       if (n2) {
+               mem_read_phys((void *)bytes, PhysAddress + n, TransferSize);
+               memcpy((void *)&(DataRead[n]), bytes, n2);
+       }
+#endif
+}
+
+void
+dma_bm_write(uint32_t PhysAddress, const uint8_t *DataWrite, uint32_t TotalSize, int TransferSize)
+{
+#if 0
+       uint32_t n;
+       uint32_t n2;
+       uint8_t  bytes[4] = { 0, 0, 0, 0 };
+
+       n = TotalSize & ~(TransferSize - 1);
+       n2 = TotalSize - n;
+
+       /* Do the divisible block, if there is one. */
+       if (n) {
+               for (uint32_t i = 0; i < n; i += TransferSize)
+                       mem_write_phys((void *)&(DataWrite[i]), PhysAddress + i, TransferSize);
+       }
+
+       /* Do the non-divisible block, if there is one. */
+       if (n2) {
+               mem_read_phys((void *)bytes, PhysAddress + n, TransferSize);
+               memcpy(bytes, (void *)&(DataWrite[n]), n2);
+               mem_write_phys((void *)bytes, PhysAddress + n, TransferSize);
+       }
+
+       if (dma_at)
+               mem_invalidate_range(PhysAddress, PhysAddress + TotalSize - 1);
+#endif
+}
+
+void video_force_resize_set_monitor(uint8_t res, int monitor_index)
+{
+}
index 1a8a32b962ef3a6a3192f831dbc0cf002fb60c08..de674a5614419b377028f0b8dfe8806867bab250 100644 (file)
@@ -1,6 +1,7 @@
 
 extern void pcem_close(void);
 extern void pcemglue_hsync(void);
+extern void pcemfreeaddeddevices(void);
 
 uint8_t keyboard_at_read(uint16_t port, void *priv);
 uint8_t mem_read_romext(uint32_t addr, void *priv);
index 6a8778e0fb565ddf22769acb20e4b6dda49d03ce..88463b65199488b70756fbee9c68c61917ec975e 100644 (file)
@@ -1,11 +1,15 @@
 void pci_init(int type);
 void pci_slot(int card);
+
 void pci_add_specific(int card, uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv);
 int pci_add(uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv);
+void pci_add_card(uint8_t add_type, uint8_t(*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv, uint8_t *slot);
+
 void pci_set_irq_routing(int card, int irq);
 void pci_set_card_routing(int card, int pci_int);
-void pci_set_irq(int card, int pci_int);
-void pci_clear_irq(int card, int pci_int);
+void pci_set_irq(int card, int pci_int, uint8_t *state);
+void pci_clear_irq(int card, int pci_int, uint8_t *state);
+
 
 #define PCI_REG_COMMAND 0x04
 
@@ -22,4 +26,26 @@ void pci_clear_irq(int card, int pci_int);
 
 #define PCI_IRQ_DISABLED -1
 
+enum {
+    PCI_ADD_NORTHBRIDGE = 0,
+    PCI_ADD_NORTHBRIDGE_SEC = 1,
+    PCI_ADD_AGPBRIDGE = 2,
+    PCI_ADD_SOUTHBRIDGE = 3,
+    PCI_ADD_SOUTHBRIDGE_IDE = 4,
+    PCI_ADD_SOUTHBRIDGE_PMU = 5,
+    PCI_ADD_SOUTHBRIDGE_USB = 6,
+    PCI_ADD_AGP = 0x0f,
+    PCI_ADD_NORMAL = 0x10,
+    PCI_ADD_VIDEO = 0x11,
+    PCI_ADD_HANGUL = 0x12,
+    PCI_ADD_IDE = 0x13,
+    PCI_ADD_SCSI = 0x14,
+    PCI_ADD_SOUND = 0x15,
+    PCI_ADD_MODEM = 0x16,
+    PCI_ADD_NETWORK = 0x17,
+    PCI_ADD_UART = 0x18,
+    PCI_ADD_USB = 0x19,
+    PCI_ADD_BRIDGE = 0x1a
+};
+
 extern int pci_burst_time, pci_nonburst_time;
index 59a41434f66ae0a552f779310af19964ff3c1a1f..97db7d6e290d619cc47483abd5504fd12dd3e93b 100644 (file)
@@ -1,4 +1,6 @@
+
 #include "ibm.h"
+#include "device.h"
 #include "io.h"
 #include "pic.h"
 #include "pit.h"
index 7c5bc984c631f2785c99c2d6dce8517fe5cda4b2..2178820cad76ed1e2b43ac2b7b104ca3dfa52764 100644 (file)
@@ -6,7 +6,7 @@ extern int sound_card_current;
 
 int sound_card_available(int card);
 char *sound_card_getname(int card);
-struct device_t *sound_card_getdevice(int card);
+device_t *sound_card_getdevice(int card);
 int sound_card_has_config(int card);
 char *sound_card_get_internal_name(int card);
 int sound_card_get_from_internal_name(char *s);
index 470227dcb03f9f8db75b5b5fb0269440a4ca156a..d582906a3179cbd1daa01efcb7189b0111ab74a0 100644 (file)
@@ -174,7 +174,7 @@ uint8_t cms_read(uint16_t addr, void *p)
         return 0xff;
 }
 
-void *cms_init()
+void *cms_init(const device_t *info)
 {
         cms_t *cms = (cms_t*)malloc(sizeof(cms_t));
         memset(cms, 0, sizeof(cms_t));
@@ -194,12 +194,11 @@ void cms_close(void *p)
 
 device_t cms_device =
 {
-        "Creative Music System / Game Blaster",
-        0,
+        "Creative Music System / Game Blaster", NULL,
+        0, 0,
         cms_init,
         cms_close,
         NULL,
         NULL,
-        NULL,
         NULL
 };
index 44c1af7d03d55ac59c118fc51e1904763d475961..d6eb50cc40565bc4bddf76c8f65d398e328a2445 100644 (file)
@@ -1,6 +1,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include "ibm.h"
+#include "device.h"
 #include "io.h"
 #include "sound.h"
 #include "sound_opl.h"
index 3eddc9db48ec30a27e6e1d5f602ebcfb23b9fe0f..73508dd661964fb6ccda244dc0bb7fdcc4059920 100644 (file)
@@ -1,4 +1,6 @@
+
 #include "ibm.h"
+#include "device.h"
 #include "sound.h"
 #include "sound_speaker.h"
 
index c8bcd0b40723d306d22121d7abddc3d6014f8e1c..0e82547fc9d91d447597c3df3c0c28d9b99657bf 100644 (file)
@@ -1,6 +1,7 @@
 typedef void thread_t;
 thread_t *thread_create(void (*thread_rout)(void *param), void *param);
 void thread_kill(thread_t *handle);
+int thread_wait(thread_t *arg);
 
 typedef void event_t;
 event_t *thread_create_event();
@@ -11,8 +12,9 @@ void thread_destroy_event(event_t *_event);
 
 typedef void mutex_t;
 mutex_t *thread_create_mutex(void);
-void thread_lock_mutex(mutex_t *mutex);
-void thread_unlock_mutex(mutex_t *mutex);
-void thread_destroy_mutex(mutex_t *mutex);
+void thread_close_mutex(mutex_t *arg);
+int thread_test_mutex(mutex_t *arg);
+int thread_wait_mutex(mutex_t *arg);
+int thread_release_mutex(mutex_t *mutex);
 
 void thread_sleep(int t);
index d790bbd8a89ca94f02b7172d867b9764cb47cb8a..c2b4cd28918523775da321b3482fec792b0d7611 100644 (file)
@@ -144,6 +144,7 @@ void timer_addx(pc_timer_t* timer, void (*callback)(void* p), void* p, int start
 void timer_enablex(pc_timer_t *timer);
 void timer_disablex(pc_timer_t *timer);
 void timer_set_delay_u64x(pc_timer_t *timer, uint64_t delay);
+void timer_advance_u64x(pc_timer_t *timer, uint64_t delay);
 #endif
 
 
index 3b1eb60a206673f3ba0361285cae96372a5e2edd..9c4d8264170dce5d8ab795b3f6426947d1f2a9b1 100644 (file)
@@ -4,6 +4,7 @@
 #include <memory>
 #include "ibm.h"
 #include "mem.h"
+#include "device.h"
 #include "video.h"
 #include "vid_svga.h"
 #include "vid_sdac_ramdac.h"
@@ -55,7 +56,6 @@ bt482_ramdac_out(uint16_t addr, int rs2, uint8_t val, void *priv, svga_t *svga)
             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;
@@ -72,25 +72,25 @@ bt482_ramdac_out(uint16_t addr, int rs2, uint8_t val, void *priv, svga_t *svga)
                         break;
                     case 3: // cursor
                         ramdac->cursor_r = val;
-                        svga->dac_hwcursor.xsize = 32;
-                        svga->dac_hwcursor.ysize = 32;
+                        svga->dac_hwcursor.cur_xsize = 32;
+                        svga->dac_hwcursor.cur_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;
+                        svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_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;
+                        svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_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;
+                        svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_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;
+                        svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize;
                         break;
                 }
             } else {
@@ -208,9 +208,9 @@ bt482_hwcursor_draw(svga_t *svga, int displine)
 
     /* 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. */
+    pitch = (svga->dac_hwcursor_latch.cur_xsize >> 3); /* Bytes per line. */
     /* A 32x32 cursor has 128 bytes per line */
-    bppl = (pitch * svga->dac_hwcursor_latch.ysize); /* Bytes per plane. */
+    bppl = (pitch * svga->dac_hwcursor_latch.cur_ysize); /* Bytes per plane. */
 
     if (svga->interlace && svga->dac_hwcursor_oddeven)
         svga->dac_hwcursor_latch.addr += pitch;
@@ -218,7 +218,7 @@ bt482_hwcursor_draw(svga_t *svga, int displine)
     cd = (uint8_t *) ramdac->cursor32_data;
     mode = ramdac->cursor_r & 3;
 
-    for (int x = 0; x < svga->dac_hwcursor_latch.xsize; x += 16) {
+    for (int x = 0; x < svga->dac_hwcursor_latch.cur_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];
 
index a76f0e3acbb3ad6efcd55499822ef0619945a832..40d93b6d73e8bc3d5fed16e8a345386e796e6af2 100644 (file)
@@ -169,14 +169,14 @@ static int gd5429_vga_vsync_enabled(gd5429_t *gd5429)
 static void gd5429_update_irqs(gd5429_t *gd5429)
 {
     if (gd5429->vblank_irq > 0 && gd5429_vga_vsync_enabled(gd5429))
-        pci_set_irq(NULL, PCI_INTA);
+        pci_set_irq(NULL, PCI_INTA, NULL);
     else
-        pci_clear_irq(NULL, PCI_INTA);
+        pci_clear_irq(NULL, PCI_INTA, NULL);
 }
 
 static void gd5429_vblank_start(svga_t *svga)
 {
-    gd5429_t *gd5429 = (gd5429_t*)svga->p;
+    gd5429_t *gd5429 = (gd5429_t*)svga->priv;
     if (gd5429->vblank_irq >= 0) {
         gd5429->vblank_irq = 1;
         gd5429_update_irqs(gd5429);
@@ -405,7 +405,7 @@ static void gd5429_vblank_start(svga_t *svga)
 // 5446 overlay
 static void gd5429_overlay_draw(svga_t *svga, int displine)
 {
-    gd5429_t *gd5429 = (gd5429_t*)svga->p;
+    gd5429_t *gd5429 = (gd5429_t*)svga->priv;
     int shift = gd5429->type >= CL_TYPE_GD5446 ? 2 : 0;
     int h_acc = svga->overlay_latch.h_acc;
     int r[8], g[8], b[8];
@@ -477,7 +477,7 @@ static void gd5429_update_overlay(gd5429_t *gd5429)
     svga_t *svga = &gd5429->svga;
     int bpp = svga->bpp;
 
-    svga->overlay.ysize = gd5429->overlay.wve - gd5429->overlay.wvs + 1;
+    svga->overlay.cur_ysize = gd5429->overlay.wve - gd5429->overlay.wvs + 1;
     gd5429->overlay.region1size = 32 * gd5429->overlay.r1sz / bpp + (gd5429->overlay.r1adjust * 8 / bpp);
     gd5429->overlay.region2size = 32 * gd5429->overlay.r2sz / bpp + (gd5429->overlay.r2adjust * 8 / bpp);
 
@@ -539,16 +539,16 @@ void gd5429_out(uint16_t addr, uint8_t val, void *p)
                                 break;
                                 case 0x12:
                                 svga->hwcursor.ena = val & 1;
-                                svga->hwcursor.ysize = (val & 4) ? 64 : 32;
+                                svga->hwcursor.cur_ysize = (val & 4) ? 64 : 32;
                                 svga->hwcursor.yoff = 0;
-                                if (svga->hwcursor.ysize == 64)
+                                if (svga->hwcursor.cur_ysize == 64)
                                         svga->hwcursor.addr = (0x3fc000 + ((svga->seqregs[0x13] & 0x3c) * 256)) & svga->vram_mask;
                                 else
                                         svga->hwcursor.addr = (0x3fc000 + ((svga->seqregs[0x13] & 0x3f) * 256)) & svga->vram_mask;
 //                                pclog("svga->hwcursor.ena = %i\n", svga->hwcursor.ena);
                                 break;                               
                                 case 0x13:
-                                if (svga->hwcursor.ysize == 64)
+                                if (svga->hwcursor.cur_ysize == 64)
                                         svga->hwcursor.addr = (0x3fc000 + ((val & 0x3c) * 256)) & svga->vram_mask;
                                 else
                                         svga->hwcursor.addr = (0x3fc000 + ((val & 0x3f) * 256)) & svga->vram_mask;
@@ -591,7 +591,7 @@ void gd5429_out(uint16_t addr, uint8_t val, void *p)
                 gd5429->dac_3c6_count = 0;
                 // Hidden CLUT entries 256 - 258
                 if (svga->dac_pos == 2 && (svga->seqregs[0x12] & 2)) {
-                    hidden_dac_index = svga->dac_write;
+                    hidden_dac_index = svga->dac_addr;
                     pal_temp0 = svga->pallook[hidden_dac_index];
                     memcpy(&pal_temp1, &svga->vgapal[hidden_dac_index], sizeof(PALETTE));
                 }
@@ -1157,7 +1157,7 @@ void gd5429_recalc_mapping(gd5429_t *gd5429)
         
 void gd5429_recalctimings(svga_t *svga)
 {
-        gd5429_t *gd5429 = (gd5429_t *)svga->p;
+        gd5429_t *gd5429 = (gd5429_t *)svga->priv;
         int clock = (svga->miscout >> 2) & 3;
         int n, d, p;
         double vclk;
@@ -1253,7 +1253,7 @@ void gd5429_recalctimings(svga_t *svga)
 
 static void gd5429_adjust_panning(svga_t *svga)
 {
-    gd5429_t *gd5429 = (gd5429_t *)svga->p;
+    gd5429_t *gd5429 = (gd5429_t *)svga->priv;
     int ar11 = svga->attrregs[0x13] & 7;
     int src = 0, dst = 8;
     switch (svga->bpp)
@@ -1291,7 +1291,7 @@ static void gd5429_adjust_panning(svga_t *svga)
 
 void gd5429_hwcursor_draw(svga_t *svga, int displine)
 {
-        gd5429_t *gd5429 = (gd5429_t *)svga->p;
+        gd5429_t *gd5429 = (gd5429_t *)svga->priv;
         int x;
         uint8_t dat[2];
         int xx;
@@ -2836,7 +2836,7 @@ static void *cl_init(int type, char *fn, int pci_card, uint32_t force_vram_size)
         if (fn)
                 rom_init(&gd5429->bios_rom, fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
         
-        svga_init(&gd5429->svga, gd5429, (vram_size >= 256) ? (vram_size << 10) : (vram_size << 20),
+        svga_init(NULL, &gd5429->svga, gd5429, (vram_size >= 256) ? (vram_size << 10) : (vram_size << 20),
                    gd5429_recalctimings,
                    gd5429_in, gd5429_out,
                    gd5429_hwcursor_draw,
@@ -2903,39 +2903,39 @@ static void *cl_init(int type, char *fn, int pci_card, uint32_t force_vram_size)
 }
 
 
-static void *avga2_init()
+static void *avga2_init(const device_t *info)
 {
         return cl_init(CL_TYPE_AVGA2, "avga2vram.vbi", -1, 0);
 }
-static void *avga2_cbm_sl386sx_init()
+static void *avga2_cbm_sl386sx_init(const device_t *info)
 {
         return cl_init(CL_TYPE_AVGA2, "cbm_sl386sx25/c000.rom", -1, 0);
 }
-static void *gd5426_ps1_init()
+static void *gd5426_ps1_init(const device_t *info)
 {
         return cl_init(CL_TYPE_GD5426, NULL, -1, 1);
 }
-static void *gd5426_init()
+static void *gd5426_init(const device_t *info)
 {
     return cl_init(CL_TYPE_GD5426, "Picasso II", -1, 0);
 }
-static void *gd5426_swapped_init()
+static void *gd5426_swapped_init(const device_t *info)
 {
     gd5429_t *gd5429 = (gd5429_t*)cl_init(CL_TYPE_GD5426, "Picasso II", -1, 0);
     gd5429->svga.swaprb = 1;
     return gd5429;
 }
-static void *gd5428_init()
+static void *gd5428_init(const device_t *info)
 {
     return cl_init(CL_TYPE_GD5428, "Machspeed_VGA_GUI_2100_VLB.vbi", -1, 0);
 }
-static void *gd5428_swapped_init()
+static void *gd5428_swapped_init(const device_t *info)
 {
     gd5429_t *gd5429 = (gd5429_t *)cl_init(CL_TYPE_GD5428, "Picasso II", -1, 0);
     gd5429->svga.swaprb = 1;
     return gd5429;
 }
-static void *ibm_gd5428_init()
+static void *ibm_gd5428_init(const device_t *info)
 {
         gd5429_t *gd5429;
         svga_t *mb_vga = svga_get_pri();
@@ -2956,37 +2956,37 @@ static void *ibm_gd5428_init()
 
         return gd5429;
 }
-static void *gd5429_init()
+static void *gd5429_init(const device_t *info)
 {
         return cl_init(CL_TYPE_GD5429, "5429.vbi", -1, 0);
 }
-static void *gd5430_init()
+static void *gd5430_init(const device_t *info)
 {
         return cl_init(CL_TYPE_GD5430, "gd5430/pci.bin", -1, 0);
 }
-static void *gd5430_pb570_init()
+static void *gd5430_pb570_init(const device_t *info)
 {
         return cl_init(CL_TYPE_GD5430, "pb570/gd5430.bin", 8, 0);
 }
-static void *gd5434_init()
+static void *gd5434_init(const device_t *info)
 {
         return cl_init(CL_TYPE_GD5434, "gd5434.bin", -1, 0);
 }
-static void *gd5434_vlb_swapped_init()
+static void *gd5434_vlb_swapped_init(const device_t *info)
 {
     gd5429_t *gd5429 = (gd5429_t *)cl_init(CL_TYPE_GD5434, "CL", -1, 0);
     has_vlb = 1;
     gd5429->svga.swaprb = 1;
     return gd5429;
 }
-static void *gd5434_vlb_init()
+static void *gd5434_vlb_init(const device_t *info)
 {
     gd5429_t *gd5429 = (gd5429_t *)cl_init(CL_TYPE_GD5434, "CL", -1, 0);
     has_vlb = 1;
     gd5429->svga.swaprb = 0;
     return gd5429;
 }
-static void *gd5446_init()
+static void *gd5446_init(const device_t *info)
 {
     PCI = 1;
     gd5429_t *gd5429 = (gd5429_t *)cl_init(CL_TYPE_GD5446, "gd5446.bin", -1, 0);
@@ -2994,7 +2994,7 @@ static void *gd5446_init()
     return gd5429;
 }
 
-static void *gd5434_pb520r_init()
+static void *gd5434_pb520r_init(const device_t *info)
 {
         return cl_init(CL_TYPE_GD5434, "pb520r/gd5434.bin", 3, 0);
 }
@@ -3136,209 +3136,202 @@ static device_config_t gd5434_config[] =
 
 device_t avga2_device =
 {
-        "AVGA2 / Cirrus Logic GD5402",
-        0,
+        "AVGA2 / Cirrus Logic GD5402", NULL,
+        0, 0,
         avga2_init,
         gd5429_close,
+        NULL,
         avga2_available,
         gd5429_speed_changed,
         gd5429_force_redraw,
-        gd5429_add_status_info,
         avga2_config
 };
 
 device_t avga2_cbm_sl386sx_device =
 {
-        "AVGA2 (Commodore SL386SX-25)",
-        0,
+        "AVGA2 (Commodore SL386SX-25)", NULL,
+        0, 0,
         avga2_cbm_sl386sx_init,
         gd5429_close,
+        NULL,
         gd5430_available,
         gd5429_speed_changed,
         gd5429_force_redraw,
-        gd5429_add_status_info,
         avga2_config
 };
 
 device_t gd5426_ps1_device =
 {
-        "Cirrus Logic GD5426 (IBM PS/1)",
-        0,
+        "Cirrus Logic GD5426 (IBM PS/1)", NULL,
+        0, 0,
         gd5426_ps1_init,
         gd5429_close,
         NULL,
+        NULL,
         gd5429_speed_changed,
         gd5429_force_redraw,
-        gd5429_add_status_info,
         NULL
 };
 
 device_t gd5426_device =
 {
-        "Cirrus Logic GD5426",
-        0,
+        "Cirrus Logic GD5426", NULL,
+        0, 0,
         gd5426_init,
         gd5429_close,
+        NULL,
         gd5428_available,
         gd5429_speed_changed,
         gd5429_force_redraw,
-        gd5429_add_status_info,
         gd5429_config
 };
 
 device_t gd5426_swapped_device =
 {
-    "Cirrus Logic GD5426",
-    0,
+    "Cirrus Logic GD5426", NULL,
+    0, 0,
     gd5426_swapped_init,
     gd5429_close,
+    NULL,
     gd5428_available,
     gd5429_speed_changed,
     gd5429_force_redraw,
-    gd5429_add_status_info,
     gd5429_config
 };
 
 device_t gd5428_device =
 {
-        "Cirrus Logic GD5428",
-        0,
+        "Cirrus Logic GD5428", NULL,
+        0, 0,
         gd5428_init,
         gd5429_close,
+        NULL,
         gd5428_available,
         gd5429_speed_changed,
         gd5429_force_redraw,
-        gd5429_add_status_info,
         gd5429_config
 };
 
 device_t gd5428_swapped_device =
 {
-    "Cirrus Logic GD5428",
-    0,
+    "Cirrus Logic GD5428", NULL,
+    0, 0,
     gd5428_swapped_init,
     gd5429_close,
+        NULL,
     gd5428_available,
     gd5429_speed_changed,
     gd5429_force_redraw,
-    gd5429_add_status_info,
     gd5429_config
 };
 
 
 device_t ibm_gd5428_device =
 {
-        "IBM 1MB SVGA Adapter/A (Cirrus Logic GD5428)",
-        DEVICE_MCA,
+        "IBM 1MB SVGA Adapter/A (Cirrus Logic GD5428)", NULL,
+        DEVICE_MCA, 0,
         ibm_gd5428_init,
         gd5429_close,
+        NULL,
         ibm_gd5428_available,
         gd5429_speed_changed,
         gd5429_force_redraw,
-        gd5429_add_status_info,
         NULL
 };
 
 device_t gd5429_device =
 {
-        "Cirrus Logic GD5429",
-        0,
+        "Cirrus Logic GD5429", NULL,
+        0, 0,
         gd5429_init,
         gd5429_close,
+        NULL,
         gd5429_available,
         gd5429_speed_changed,
         gd5429_force_redraw,
-        gd5429_add_status_info,
         gd5429_config
 };
 
 device_t gd5430_device =
 {
-        "Cirrus Logic GD5430",
-        0,
+        "Cirrus Logic GD5430", NULL,
+        0, 0,
         gd5430_init,
         gd5429_close,
+        NULL,
         gd5430_available,
         gd5429_speed_changed,
-        gd5429_force_redraw,
-        gd5429_add_status_info,
-        gd5429_config
+        gd5429_force_redraw
 };
 
 device_t gd5430_pb570_device =
 {
-        "Cirrus Logic GD5430 (PB570)",
-        0,
+        "Cirrus Logic GD5430 (PB570)", NULL,
+        0, 0,
         gd5430_pb570_init,
         gd5429_close,
+        NULL,
         gd5430_available,
         gd5429_speed_changed,
-        gd5429_force_redraw,
-        gd5429_add_status_info,
-        gd5429_config
+        gd5429_force_redraw
 };
 
 device_t gd5434_device =
 {
-        "Cirrus Logic GD5434",
-        0,
+        "Cirrus Logic GD5434", NULL,
+        0, 0,
         gd5434_init,
         gd5429_close,
+        NULL,
         gd5434_available,
         gd5429_speed_changed,
-        gd5429_force_redraw,
-        gd5429_add_status_info,
-        gd5434_config
+        gd5429_force_redraw
 };
 
 device_t gd5434_vlb_device =
 {
-    "Cirrus Logic GD5434",
-    0,
+    "Cirrus Logic GD5434", NULL,
+    0, 0,
     gd5434_vlb_init,
     gd5429_close,
+    NULL,
     gd5434_available,
     gd5429_speed_changed,
-    gd5429_force_redraw,
-    gd5429_add_status_info,
-    gd5434_config
+    gd5429_force_redraw
 };
 
 device_t gd5434_vlb_swapped_device =
 {
-    "Cirrus Logic GD5434",
-    0,
+    "Cirrus Logic GD5434", NULL,
+    0, 0,
     gd5434_vlb_swapped_init,
     gd5429_close,
+    NULL,
     gd5434_available,
     gd5429_speed_changed,
-    gd5429_force_redraw,
-    gd5429_add_status_info,
-    gd5434_config
+    gd5429_force_redraw
 };
 
 device_t gd5434_pb520r_device =
 {
-        "Cirrus Logic GD5434 (PB520r)",
-        0,
+        "Cirrus Logic GD5434 (PB520r)", NULL,
+        0, 0,
         gd5434_pb520r_init,
         gd5429_close,
+        NULL,
         gd5434_available,
         gd5429_speed_changed,
         gd5429_force_redraw,
-        gd5429_add_status_info,
-        gd5434_config
 };
 
 device_t gd5446_device =
 {
-    "Cirrus Logic GD5446",
-    0,
+    "Cirrus Logic GD5446", NULL,
+    0, 0,
     gd5446_init,
     gd5429_close,
+    NULL,
     gd5434_available,
     gd5429_speed_changed,
-    gd5429_force_redraw,
-    gd5429_add_status_info,
-    gd5434_config
+    gd5429_force_redraw
 };
index 10f1b9f47a495e982039497a009f5ac6f5a1506e..e0c1de707bb7df456cb8e11e131a6fb306dfe146 100644 (file)
@@ -657,7 +657,7 @@ get_et4000_addr(uint32_t addr, void *priv)
 static void
 et4000_recalctimings(svga_t *svga)
 {
-    const et4000_t *dev = (et4000_t *) svga->p;
+    const et4000_t *dev = (et4000_t *) svga->priv;
 
     svga->ma_latch |= (svga->crtc[0x33] & 3) << 16;
 
@@ -820,7 +820,7 @@ et4000_init(const device_t *info)
         case ET4000_TYPE_ISA: /* ISA ET4000AX */
             dev->vram_size = device_get_config_int("memory") << 20;
             //video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_et4000_isa);
-            svga_init(&dev->svga, dev, dev->vram_size,
+            svga_init(info, &dev->svga, dev, dev->vram_size,
                       et4000_recalctimings, et4000_in, et4000_out,
                       NULL, NULL);
             io_sethandlerx(0x03c0, 32,
@@ -1180,7 +1180,7 @@ const device_t et4000_kasan_isa_device = {
 };
 #endif
 
-void *et4000_domino_init()
+void *et4000_domino_init(const device_t *info)
 {
     void *p = et4000_init(NULL);
     et4000_t *et4000 = (et4000_t *)p;
@@ -1191,7 +1191,7 @@ void *et4000_domino_init()
     return p;
 }
 
-void *et4000_omnibus_init()
+void *et4000_omnibus_init(const device_t *info)
 {
     void *p = et4000_init(NULL);
     et4000_t *et4000 = (et4000_t *)p;
@@ -1203,26 +1203,26 @@ void *et4000_omnibus_init()
 }
 device_t et4000_domino_device =
 {
-    "Domino",
-    0,
+    "Domino", NULL,
+    0, 0,
     et4000_domino_init,
     et4000_close,
     NULL,
+    NULL,
     et4000_speed_changed,
     et4000_force_redraw,
-    NULL,
     NULL
 };
 
 device_t et4000_omnibus_device =
 {
-    "oMniBus",
-    0,
+    "oMniBus", NULL,
+    0, 0,
     et4000_omnibus_init,
     et4000_close,
     NULL,
+    NULL,
     et4000_speed_changed,
     et4000_force_redraw,
-    NULL,
     NULL
 };
index d2ecc1ab1acd84976d2df6757e0069cd6024deb3..e0775a322b95a496033446563113bb5aae95e4a1 100644 (file)
@@ -162,14 +162,14 @@ static int et4000_vga_vsync_enabled(et4000w32p_t *et4000)
 static void et4000_update_irqs(et4000w32p_t *et4000)
 {
     if (et4000->vblank_irq > 0 && et4000_vga_vsync_enabled(et4000))
-        pci_set_irq(NULL, PCI_INTA);
+        pci_set_irq(NULL, PCI_INTA, NULL);
     else
-        pci_clear_irq(NULL, PCI_INTA);
+        pci_clear_irq(NULL, PCI_INTA, NULL);
 }
 
 static void et4000_vblank_start(svga_t *svga)
 {
-    et4000w32p_t *et4000 = (et4000w32p_t*)svga->p;
+    et4000w32p_t *et4000 = (et4000w32p_t*)svga->priv;
     if (et4000->vblank_irq >= 0) {
         et4000->vblank_irq = 1;
         et4000_update_irqs(et4000);
@@ -325,15 +325,15 @@ et4000w32p_out(uint16_t addr, uint8_t val, void *priv)
             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;
+            svga->hwcursor.cur_xsize = svga->hwcursor.cur_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;
+                    svga->hwcursor.cur_xsize = svga->hwcursor.cur_ysize = 128;
                 }
             }
 
-            if ((et4000->type == ET4000W32) && (svga->hwcursor.xsize == 128)) {
+            if ((et4000->type == ET4000W32) && (svga->hwcursor.cur_xsize == 128)) {
                 switch (svga->bpp) {
                     case 8:
                         svga->hwcursor.xoff += 32;
@@ -344,7 +344,7 @@ et4000w32p_out(uint16_t addr, uint8_t val, void *priv)
                 }
             }
 
-            if (svga->hwcursor.xsize == 128) {
+            if (svga->hwcursor.cur_xsize == 128) {
                 svga->hwcursor.xoff &= 0x7f;
                 svga->hwcursor.yoff &= 0x7f;
                 if (et4000->type > ET4000W32P_REVC) {
@@ -363,7 +363,7 @@ et4000w32p_out(uint16_t addr, uint8_t val, void *priv)
             }
             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);
+            add2addr = svga->hwcursor.yoff * ((svga->hwcursor.cur_xsize == 128) ? 32 : 16);
             svga->hwcursor.addr += add2addr;
             return;
 
@@ -488,7 +488,7 @@ et4000w32p_in(uint16_t addr, void *priv)
 void
 et4000w32p_recalctimings(svga_t *svga)
 {
-    et4000w32p_t *et4000 = (et4000w32p_t *) svga->p;
+    et4000w32p_t *et4000 = (et4000w32p_t *) svga->priv;
 
     svga->ma_latch |= (svga->crtc[0x33] & 0x7) << 16;
 
@@ -2809,13 +2809,13 @@ et4000w32p_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input, et4000w32
 void
 et4000w32p_hwcursor_draw(svga_t *svga, int displine)
 {
-    const et4000w32p_t *et4000 = (et4000w32p_t *) svga->p;
+    const et4000w32p_t *et4000 = (et4000w32p_t *) svga->priv;
     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                 width       = (svga->hwcursor_latch.cur_xsize - svga->hwcursor_latch.xoff);
+    int                 pitch       = (svga->hwcursor_latch.cur_xsize == 128) ? 32 : 16;
     int                 x_acc       = 4;
     int                 minus_width = 0;
     uint8_t             dat;
@@ -3103,7 +3103,7 @@ et4000w32p_init(const device_t *info)
 
     et4000->type = ET4000W32I;
 
-    svga_init(&et4000->svga, et4000, vram_size << 20,
+    svga_init(info, &et4000->svga, et4000, vram_size << 20,
               et4000w32p_recalctimings,
               et4000w32p_in, et4000w32p_out,
               et4000w32p_hwcursor_draw,
@@ -3572,7 +3572,7 @@ const device_t et4000w32p_pci_device = {
 };
 #endif
 
-void *et4000w32_merlin_z3_init()
+void *et4000w32_merlin_z3_init(const device_t *info)
 {
     void *p = et4000w32p_init(NULL);
     et4000w32p_t *et4000w32p = (et4000w32p_t *)p;
@@ -3584,7 +3584,7 @@ void *et4000w32_merlin_z3_init()
 
     return p;
 }
-void *et4000w32_merlin_z2_init()
+void *et4000w32_merlin_z2_init(const device_t *info)
 {
     void *p = et4000w32p_init(NULL);
     et4000w32p_t *et4000w32p = (et4000w32p_t *)p;
@@ -3596,7 +3596,7 @@ void *et4000w32_merlin_z2_init()
 
     return p;
 }
-void *et4000w32_omnibus_z2_init()
+void *et4000w32_omnibus_z2_init(const device_t *info)
 {
     void *p = et4000w32p_init(NULL);
     et4000w32p_t *et4000w32p = (et4000w32p_t *)p;
@@ -3609,40 +3609,40 @@ void *et4000w32_omnibus_z2_init()
 
 device_t et4000w32_omnibus_device =
 {
-    "oMniBus",
-    0,
+    "oMniBus", NULL,
+    0, 0,
     et4000w32_omnibus_z2_init,
     et4000w32p_close_sc,
     NULL,
+    NULL,
     et4000w32p_speed_changed,
     et4000w32p_force_redraw,
-    NULL,
     NULL
 };
 
 device_t et4000w32_merlin_z2_device =
 {
-    "Merlin Z2",
-    0,
+    "Merlin Z2", NULL,
+    0, 0,
     et4000w32_merlin_z2_init,
     et4000w32p_close_bt,
     NULL,
+    NULL,
     et4000w32p_speed_changed,
     et4000w32p_force_redraw,
-    NULL,
     NULL
 };
 
 device_t et4000w32_merlin_z3_device =
 {
-    "Merlin Z3",
-    0,
+    "Merlin Z3", NULL,
+    0, 0,
     et4000w32_merlin_z3_init,
     et4000w32p_close_bt,
     NULL,
+    NULL,
     et4000w32p_speed_changed,
     et4000w32p_force_redraw,
-    NULL,
     NULL
 };
 
index 6ece01477c89ca00b313a1e41bdca2949b4cea7b..b2d405df9767176df12fa75e4eed6260bac2aaed 100644 (file)
@@ -62,14 +62,14 @@ static void inmos_update_irqs(inmos_t *inmos)
 {
     if (inmos->vblank_irq) {
         inmos->vblank_irq = 0;
-        pci_set_irq(NULL, PCI_INTA);
-        pci_clear_irq(NULL, PCI_INTA);
+        pci_set_irq(NULL, PCI_INTA, NULL);
+        pci_clear_irq(NULL, PCI_INTA, NULL);
     }
 }
 
 static void inmos_vblank_start(svga_t *svga)
 {
-    inmos_t *inmos = (inmos_t*)svga->p;
+    inmos_t *inmos = (inmos_t*)svga->priv;
     uint32_t control = inmos->regs[0x160];
     if (control & 1) {
         inmos->vblank_irq = 1;
@@ -79,7 +79,7 @@ static void inmos_vblank_start(svga_t *svga)
 
 void inmos_hwcursor_draw(svga_t *svga, int displine)
 {
-    inmos_t *inmos = (inmos_t*)svga->p;
+    inmos_t *inmos = (inmos_t*)svga->priv;
     int addr = svga->hwcursor_latch.addr;
     int offset = svga->hwcursor_latch.x;
     int line_offset = 0;
@@ -110,7 +110,7 @@ void inmos_hwcursor_draw(svga_t *svga, int displine)
 
 void inmos_recalctimings(svga_t *svga)
 {
-    inmos_t *inmos = (inmos_t*)svga->p;
+    inmos_t *inmos = (inmos_t*)svga->priv;
 
     if (inmos->chip == INMOS_TYPE_G300) {
 
@@ -377,7 +377,7 @@ static uint32_t inmos_mmio_readl(uint32_t addr, void *p)
 static uint8_t inmos_read_linear(uint32_t addr, void *p)
 {
     svga_t *svga = (svga_t*)p;
-    inmos_t *inmos = (inmos_t*)svga->p;
+    inmos_t *inmos = (inmos_t*)svga->priv;
     uint8_t *fbp = (uint8_t*)(&svga->vram[addr & svga->vram_mask]);
     uint8_t v = *fbp;
     return v;
@@ -385,7 +385,7 @@ static uint8_t inmos_read_linear(uint32_t addr, void *p)
 static uint16_t inmos_readw_linear(uint32_t addr, void *p)
 {
     svga_t *svga = (svga_t*)p;
-    inmos_t *inmos = (inmos_t*)svga->p;
+    inmos_t *inmos = (inmos_t*)svga->priv;
     uint16_t *fbp = (uint16_t*)(&svga->vram[addr & svga->vram_mask]);
     uint16_t v = *fbp;
     return v;
@@ -393,7 +393,7 @@ static uint16_t inmos_readw_linear(uint32_t addr, void *p)
 static uint32_t inmos_readl_linear(uint32_t addr, void *p)
 {
     svga_t *svga = (svga_t*)p;
-    inmos_t *inmos = (inmos_t*)svga->p;
+    inmos_t *inmos = (inmos_t*)svga->priv;
     uint32_t *fbp = (uint32_t*)(&svga->vram[addr & svga->vram_mask]);
     uint32_t v = *fbp;
     return v;
@@ -402,7 +402,7 @@ static uint32_t inmos_readl_linear(uint32_t addr, void *p)
 static void inmos_write_linear(uint32_t addr, uint8_t val, void *p)
 {
     svga_t *svga = (svga_t*)p;
-    inmos_t *inmos = (inmos_t*)svga->p;
+    inmos_t *inmos = (inmos_t*)svga->priv;
     addr &= svga->vram_mask;
     uint8_t *fbp = (uint8_t*)(&svga->vram[addr]);
     *fbp = val;
@@ -411,7 +411,7 @@ static void inmos_write_linear(uint32_t addr, uint8_t val, void *p)
 static void inmos_writew_linear(uint32_t addr, uint16_t val, void *p)
 {
     svga_t *svga = (svga_t*)p;
-    inmos_t *inmos = (inmos_t*)svga->p;
+    inmos_t *inmos = (inmos_t*)svga->priv;
     addr &= svga->vram_mask;
     uint16_t *fbp = (uint16_t*)(&svga->vram[addr]);
     *fbp = val;
@@ -420,7 +420,7 @@ static void inmos_writew_linear(uint32_t addr, uint16_t val, void *p)
 static void inmos_writel_linear(uint32_t addr, uint32_t val, void *p)
 {
     svga_t *svga = (svga_t*)p;
-    inmos_t *inmos = (inmos_t*)svga->p;
+    inmos_t *inmos = (inmos_t*)svga->priv;
     addr &= svga->vram_mask;
     uint32_t *fbp = (uint32_t*)(&svga->vram[addr]);
     *fbp = val;
@@ -463,7 +463,7 @@ void inmos_updatemapping(inmos_t *inmos)
 
 static void inmos_adjust_panning(svga_t *svga)
 {
-    inmos_t *inmos = (inmos_t *)svga->p;
+    inmos_t *inmos = (inmos_t *)svga->priv;
     int src = 0, dst = 8;
 
     dst += 24;
@@ -492,7 +492,7 @@ static void *inmos_init(int chip)
         vram_size = 512 << 10;
     inmos->vram_mask = vram_size - 1;
 
-    svga_init(&inmos->svga, inmos, vram_size,
+    svga_init(NULL, &inmos->svga, inmos, vram_size,
         inmos_recalctimings,
         NULL, NULL,
         inmos_hwcursor_draw,
@@ -528,15 +528,15 @@ static void *inmos_init(int chip)
 
     inmos->chip = chip;
     inmos->addressalign = 2;
-    inmos->svga.hwcursor.xsize = 64;
-    inmos->svga.hwcursor.ysize = 64;
+    inmos->svga.hwcursor.cur_xsize = 64;
+    inmos->svga.hwcursor.cur_ysize = 64;
 
     inmos_updatemapping(inmos);
 
     return inmos;
 }
 
-void *inmos_rainbow3_z3_init()
+void *inmos_rainbow3_z3_init(const device_t *info)
 {
     inmos_t *inmos = (inmos_t*)inmos_init(INMOS_TYPE_G360);
 
@@ -550,7 +550,7 @@ void *inmos_rainbow3_z3_init()
     return inmos;
 }
 
-void *inmos_visiona_z2_init()
+void *inmos_visiona_z2_init(const device_t *info)
 {
     inmos_t *inmos = (inmos_t*)inmos_init(INMOS_TYPE_G300);
 
@@ -564,7 +564,7 @@ void *inmos_visiona_z2_init()
     return inmos;
 }
 
-void *inmos_egs_110_24_init()
+void *inmos_egs_110_24_init(const device_t *info)
 {
     inmos_t *inmos = (inmos_t *)inmos_init(INMOS_TYPE_G364);
 
@@ -616,39 +616,36 @@ void inmos_add_status_info(char *s, int max_len, void *p)
 
 device_t inmos_visiona_z2_device =
 {
-    "Visiona",
-    0,
+    "Visiona", NULL,
+    0, 0,
     inmos_visiona_z2_init,
     inmos_close,
     NULL,
+    NULL,
     inmos_speed_changed,
-    inmos_force_redraw,
-    inmos_add_status_info,
-    NULL
+    inmos_force_redraw
 };
 
 device_t inmos_rainbow3_z3_device =
 {
-    "Rainbow III",
-    0,
+    "Rainbow III", NULL,
+    0, 0,
     inmos_rainbow3_z3_init,
     inmos_close,
     NULL,
+    NULL,
     inmos_speed_changed,
-    inmos_force_redraw,
-    inmos_add_status_info,
-    NULL
+    inmos_force_redraw
 };
 
 device_t inmos_egs_110_24_device =
 {
-    "EGS 110/24",
-    0,
+    "EGS 110/24", NULL,
+    0, 0,
     inmos_egs_110_24_init,
     inmos_close,
     NULL,
+    NULL,
     inmos_speed_changed,
-    inmos_force_redraw,
-    inmos_add_status_info,
-    NULL
+    inmos_force_redraw
 };
diff --git a/pcem/vid_mga.cpp b/pcem/vid_mga.cpp
new file mode 100644 (file)
index 0000000..7c34120
--- /dev/null
@@ -0,0 +1,7120 @@
+/*
+ * 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.
+ *
+ *          Matrox MGA graphics card emulation.
+ *
+ *
+ *
+ * Authors: Sarah Walker, <https://pcem-emulator.co.uk/>
+ *
+ *          Copyright 2008-2020 Sarah Walker.
+ */
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <stdatomic.h>
+#include "ibm.h"
+#include "device.h"
+#include "io.h"
+#include "pci.h"
+#include "mem.h"
+#include "rom.h"
+#include "dma.h"
+#include "thread.h"
+#include "video.h"
+#include "vid_svga.h"
+#include "vid_svga_render.h"
+
+#if 1
+
+extern void activate_debugger(void);
+
+#define ROM_MILLENNIUM    "roms/video/matrox/matrox2064wr2.BIN"
+#define ROM_MILLENNIUM_II "roms/video/matrox/matrox2164wpc.BIN"
+#define ROM_MYSTIQUE      "roms/video/matrox/MYSTIQUE.VBI"
+#define ROM_MYSTIQUE_220  "roms/video/matrox/Myst220_66-99mhz.vbi"
+#define ROM_G100          "roms/video/matrox/productiva8mbsdr.BIN"
+
+#define FIFO_SIZE        65536
+#define FIFO_MASK        (FIFO_SIZE - 1)
+#define FIFO_ENTRY_SIZE  (1 << 31)
+#define FIFO_THRESHOLD   0xe000
+
+#define WAKE_DELAY       (100 * TIMER_USEC) /* 100us */
+
+#define FIFO_ENTRIES     (mystique->fifo_write_idx - mystique->fifo_read_idx)
+#define FIFO_FULL        ((mystique->fifo_write_idx - mystique->fifo_read_idx) >= (FIFO_SIZE - 1))
+#define FIFO_EMPTY       (mystique->fifo_read_idx == mystique->fifo_write_idx)
+
+#define FIFO_TYPE        0xff000000
+#define FIFO_ADDR        0x00ffffff
+
+#define DMA_POLL_TIME_US 100 /*100us*/
+#define DMA_MAX_WORDS    (20 * 14) /*280 quad words per 100us poll*/
+
+/*These registers are also mirrored into 0x1dxx, with the mirrored versions starting
+  the blitter*/
+#define REG_DWGCTL       0x1c00
+#define REG_MACCESS      0x1c04
+#define REG_MCTLWTST     0x1c08
+#define REG_ZORG         0x1c0c
+#define REG_PAT0         0x1c10
+#define REG_PAT1         0x1c14
+#define REG_PLNWT        0x1c1c
+#define REG_BCOL         0x1c20
+#define REG_FCOL         0x1c24
+#define REG_SRC0         0x1c30
+#define REG_SRC1         0x1c34
+#define REG_SRC2         0x1c38
+#define REG_SRC3         0x1c3c
+#define REG_XYSTRT       0x1c40
+#define REG_XYEND        0x1c44
+#define REG_SHIFT        0x1c50
+#define REG_DMAPAD       0x1c54
+#define REG_SGN          0x1c58
+#define REG_LEN          0x1c5c
+#define REG_AR0          0x1c60
+#define REG_AR1          0x1c64
+#define REG_AR2          0x1c68
+#define REG_AR3          0x1c6c
+#define REG_AR4          0x1c70
+#define REG_AR5          0x1c74
+#define REG_AR6          0x1c78
+#define REG_CXBNDRY      0x1c80
+#define REG_FXBNDRY      0x1c84
+#define REG_YDSTLEN      0x1c88
+#define REG_PITCH        0x1c8c
+#define REG_YDST         0x1c90
+#define REG_YDSTORG      0x1c94
+#define REG_YTOP         0x1c98
+#define REG_YBOT         0x1c9c
+#define REG_CXLEFT       0x1ca0
+#define REG_CXRIGHT      0x1ca4
+#define REG_FXLEFT       0x1ca8
+#define REG_FXRIGHT      0x1cac
+#define REG_XDST         0x1cb0
+#define REG_DR0          0x1cc0
+#define REG_DR2          0x1cc8
+#define REG_DR3          0x1ccc
+#define REG_DR4          0x1cd0
+#define REG_DR6          0x1cd8
+#define REG_DR7          0x1cdc
+#define REG_DR8          0x1ce0
+#define REG_DR10         0x1ce8
+#define REG_DR11         0x1cec
+#define REG_DR12         0x1cf0
+#define REG_DR14         0x1cf8
+#define REG_DR15         0x1cfc
+
+#define REG_DR0_Z32LSB      0x2c50
+#define REG_DR0_Z32MSB      0x2c54
+#define REG_DR2_Z32LSB      0x2c60
+#define REG_DR2_Z32MSB      0x2c64
+#define REG_DR3_Z32LSB      0x2c68
+#define REG_DR3_Z32MSB      0x2c6c
+#define REG_TEXFILTER       0x2c58
+
+#define REG_FIFOSTATUS   0x1e10
+#define REG_STATUS       0x1e14
+#define REG_ICLEAR       0x1e18
+#define REG_IEN          0x1e1c
+#define REG_VCOUNT       0x1e20
+#define REG_DMAMAP       0x1e30
+#define REG_RST          0x1e40
+#define REG_OPMODE       0x1e54
+#define REG_PRIMADDRESS  0x1e58
+#define REG_PRIMEND      0x1e5c
+#define REG_DWG_INDIR_WT 0x1e80
+
+#define REG_ATTR_IDX     0x1fc0
+#define REG_ATTR_DATA    0x1fc1
+#define REG_INSTS0       0x1fc2
+#define REG_MISC         0x1fc2
+#define REG_SEQ_IDX      0x1fc4
+#define REG_SEQ_DATA     0x1fc5
+#define REG_MISCREAD     0x1fcc
+#define REG_GCTL_IDX     0x1fce
+#define REG_GCTL_DATA    0x1fcf
+#define REG_CRTC_IDX     0x1fd4
+#define REG_CRTC_DATA    0x1fd5
+#define REG_INSTS1       0x1fda
+#define REG_CRTCEXT_IDX  0x1fde
+#define REG_CRTCEXT_DATA 0x1fdf
+#define REG_CACHEFLUSH   0x1fff
+
+/*Mystique only*/
+#define REG_TMR0       0x2c00
+#define REG_TMR1       0x2c04
+#define REG_TMR2       0x2c08
+#define REG_TMR3       0x2c0c
+#define REG_TMR4       0x2c10
+#define REG_TMR5       0x2c14
+#define REG_TMR6       0x2c18
+#define REG_TMR7       0x2c1c
+#define REG_TMR8       0x2c20
+#define REG_TEXORG     0x2c24
+#define REG_TEXWIDTH   0x2c28
+#define REG_TEXHEIGHT  0x2c2c
+#define REG_TEXCTL     0x2c30
+#define REG_TEXTRANS   0x2c34
+#define REG_SECADDRESS 0x2c40
+#define REG_SECEND     0x2c44
+#define REG_SOFTRAP    0x2c48
+#define REG_ALPHASTART 0x2c70
+#define REG_ALPHACTRL  0x2c7c
+#define REG_ALPHAXINC  0x2c74
+#define REG_ALPHAYINC  0x2c78
+#define REG_FOGSTART   0x1cc4
+#define REG_FOGXINC    0x1cd4
+#define REG_FOGYINC    0x1ce4
+#define REG_FOGCOL     0x1cf4
+
+/*Mystique only*/
+#define REG_PALWTADD                  0x3c00
+#define REG_PALDATA                   0x3c01
+#define REG_PIXRDMSK                  0x3c02
+#define REG_PALRDADD                  0x3c03
+#define REG_X_DATAREG                 0x3c0a
+#define REG_CURPOSX                   0x3c0c
+#define REG_CURPOSY                   0x3c0e
+
+#define REG_STATUS_VSYNCSTS           (1 << 3)
+
+#define CRTCX_R0_STARTADD_MASK        (0xf << 0)
+#define CRTCX_R0_OFFSET_MASK          (3 << 4)
+
+#define CRTCX_R1_HTOTAL8              (1 << 0)
+#define CRTCX_R1_HBLKSTRT8            (1 << 1)
+#define CRTCX_R1_HBLKEND6             (1 << 6)
+
+#define CRTCX_R2_VTOTAL10             (1 << 0)
+#define CRTCX_R2_VTOTAL11             (1 << 1)
+#define CRTCX_R2_VDISPEND10           (1 << 2)
+#define CRTCX_R2_VBLKSTR10            (1 << 3)
+#define CRTCX_R2_VBLKSTR11            (1 << 4)
+#define CRTCX_R2_VSYNCSTR10           (1 << 5)
+#define CRTCX_R2_VSYNCSTR11           (1 << 6)
+#define CRTCX_R2_LINECOMP10           (1 << 7)
+
+#define CRTCX_R3_MGAMODE              (1 << 7)
+
+#define XREG_XCURADDL                 0x04
+#define XREG_XCURADDH                 0x05
+#define XREG_XCURCTRL                 0x06
+
+#define XREG_XCURCOL0R                0x08
+#define XREG_XCURCOL0G                0x09
+#define XREG_XCURCOL0B                0x0a
+
+#define XREG_XCURCOL1R                0x0c
+#define XREG_XCURCOL1G                0x0d
+#define XREG_XCURCOL1B                0x0e
+
+#define XREG_XCURCOL2R                0x10
+#define XREG_XCURCOL2G                0x11
+#define XREG_XCURCOL2B                0x12
+
+#define XREG_XVREFCTRL                0x18
+#define XREG_XMULCTRL                 0x19
+#define XREG_XPIXCLKCTRL              0x1a
+#define XREG_XGENCTRL                 0x1d
+#define XREG_XMISCCTRL                0x1e
+
+#define XREG_XGENIOCTRL               0x2a
+#define XREG_XGENIODATA               0x2b
+
+#define XREG_XSYSPLLM                 0x2c
+#define XREG_XSYSPLLN                 0x2d
+#define XREG_XSYSPLLP                 0x2e
+#define XREG_XSYSPLLSTAT              0x2f
+
+#define XREG_XZOOMCTRL                0x38
+
+#define XREG_XSENSETEST               0x3a
+
+#define XREG_XCRCREML                 0x3c
+#define XREG_XCRCREMH                 0x3d
+#define XREG_XCRCBITSEL               0x3e
+
+#define XREG_XCOLKEYMSKL              0x40
+#define XREG_XCOLKEYMSKH              0x41
+#define XREG_XCOLKEYL                 0x42
+#define XREG_XCOLKEYH                 0x43
+
+#define XREG_XPIXPLLCM                0x4c
+#define XREG_XPIXPLLCN                0x4d
+#define XREG_XPIXPLLCP                0x4e
+#define XREG_XPIXPLLSTAT              0x4f
+
+#define XMISCCTRL_VGA8DAC             (1 << 3)
+#define XMISCCTRL_RAMCS               (1 << 4)
+
+#define XMULCTRL_DEPTH_MASK           (7 << 0)
+#define XMULCTRL_DEPTH_8              (0 << 0)
+#define XMULCTRL_DEPTH_15             (1 << 0)
+#define XMULCTRL_DEPTH_16             (2 << 0)
+#define XMULCTRL_DEPTH_24             (3 << 0)
+#define XMULCTRL_DEPTH_32_OVERLAYED   (4 << 0)
+#define XMULCTRL_DEPTH_2G8V16         (5 << 0)
+#define XMULCTRL_DEPTH_G16V16         (6 << 0)
+#define XMULCTRL_DEPTH_32             (7 << 0)
+
+#define XSYSPLLSTAT_SYSLOCK           (1 << 6)
+
+#define XPIXPLLSTAT_SYSLOCK           (1 << 6)
+
+#define XCURCTRL_CURMODE_MASK         (3 << 0)
+#define XCURCTRL_CURMODE_3COL         (1 << 0)
+#define XCURCTRL_CURMODE_XGA          (2 << 0)
+#define XCURCTRL_CURMODE_XWIN         (3 << 0)
+
+#define DWGCTRL_OPCODE_MASK           (0xf << 0)
+#define DWGCTRL_OPCODE_LINE_OPEN      (0x0 << 0)
+#define DWGCTRL_OPCODE_AUTOLINE_OPEN  (0x1 << 0)
+#define DWGCTRL_OPCODE_LINE_CLOSE     (0x2 << 0)
+#define DWGCTRL_OPCODE_AUTOLINE_CLOSE (0x3 << 0)
+#define DWGCTRL_OPCODE_TRAP           (0x4 << 0)
+#define DWGCTRL_OPCODE_TEXTURE_TRAP   (0x6 << 0)
+#define DWGCTRL_OPCODE_ILOAD_HIGH     (0x7 << 0)
+#define DWGCTRL_OPCODE_BITBLT         (0x8 << 0)
+#define DWGCTRL_OPCODE_ILOAD          (0x9 << 0)
+#define DWGCTRL_OPCODE_IDUMP          (0xa << 0)
+#define DWGCTRL_OPCODE_FBITBLT        (0xc << 0)
+#define DWGCTRL_OPCODE_ILOAD_SCALE    (0xd << 0)
+#define DWGCTRL_OPCODE_ILOAD_HIGHV    (0xe << 0)
+#define DWGCTRL_OPCODE_ILOAD_FILTER   (0xf << 0) /* Not implemented. */
+#define DWGCTRL_ATYPE_MASK            (7 << 4)
+#define DWGCTRL_ATYPE_RPL             (0 << 4)
+#define DWGCTRL_ATYPE_RSTR            (1 << 4)
+#define DWGCTRL_ATYPE_ZI              (3 << 4)
+#define DWGCTRL_ATYPE_BLK             (4 << 4)
+#define DWGCTRL_ATYPE_I               (7 << 4)
+#define DWGCTRL_LINEAR                (1 << 7)
+#define DWGCTRL_ZMODE_MASK            (7 << 8)
+#define DWGCTRL_ZMODE_NOZCMP          (0 << 8)
+#define DWGCTRL_ZMODE_ZE              (2 << 8)
+#define DWGCTRL_ZMODE_ZNE             (3 << 8)
+#define DWGCTRL_ZMODE_ZLT             (4 << 8)
+#define DWGCTRL_ZMODE_ZLTE            (5 << 8)
+#define DWGCTRL_ZMODE_ZGT             (6 << 8)
+#define DWGCTRL_ZMODE_ZGTE            (7 << 8)
+#define DWGCTRL_SOLID                 (1 << 11)
+#define DWGCTRL_ARZERO                (1 << 12)
+#define DWGCTRL_SGNZERO               (1 << 13)
+#define DWGCTRL_SHTZERO               (1 << 14)
+#define DWGCTRL_BOP_MASK              (0xf << 16)
+#define DWGCTRL_TRANS_SHIFT           (20)
+#define DWGCTRL_TRANS_MASK            (0xf << DWGCTRL_TRANS_SHIFT)
+#define DWGCTRL_BLTMOD_MASK           (0xf << 25)
+#define DWGCTRL_BLTMOD_BMONOLEF       (0x0 << 25)
+#define DWGCTRL_BLTMOD_BPLAN          (0x1 << 25)
+#define DWGCTRL_BLTMOD_BFCOL          (0x2 << 25)
+#define DWGCTRL_BLTMOD_BU32BGR        (0x3 << 25)
+#define DWGCTRL_BLTMOD_BMONOWF        (0x4 << 25)
+#define DWGCTRL_BLTMOD_BU32RGB        (0x7 << 25)
+#define DWGCTRL_BLTMOD_BUYUV          (0xe << 25)
+#define DWGCTRL_BLTMOD_BU24RGB        (0xf << 25)
+#define DWGCTRL_PATTERN               (1 << 29)
+#define DWGCTRL_TRANSC                (1 << 30)
+#define BOP(x)                        ((x) << 16)
+
+#define MACCESS_PWIDTH_MASK           (3 << 0)
+#define MACCESS_PWIDTH_8              (0 << 0)
+#define MACCESS_PWIDTH_16             (1 << 0)
+#define MACCESS_PWIDTH_32             (2 << 0)
+#define MACCESS_PWIDTH_24             (3 << 0)
+#define MACCESS_ZWIDTH                (1 << 3)
+#define MACCESS_FOGEN                 (1 << 26)
+#define MACCESS_TLUTLOAD              (1 << 29)
+#define MACCESS_NODITHER              (1 << 30)
+#define MACCESS_DIT555                (1 << 31)
+
+#define PITCH_MASK                    0xfe0
+#define PITCH_YLIN                    (1 << 15)
+
+#define SGN_SDYDXL                    (1 << 0)
+#define SGN_SCANLEFT                  (1 << 0)
+#define SGN_SDXL                      (1 << 1)
+#define SGN_SDY                       (1 << 2)
+#define SGN_SDXR                      (1 << 5)
+
+#define DMA_ADDR_MASK                 0xfffffffc
+#define DMA_MODE_MASK                 3
+
+#define DMA_MODE_REG                  0
+#define DMA_MODE_BLIT                 1
+#define DMA_MODE_VECTOR               2
+
+#define STATUS_SOFTRAPEN              (1 << 0)
+#define STATUS_VSYNCPEN               (1 << 4)
+#define STATUS_VLINEPEN               (1 << 5)
+#define STATUS_DWGENGSTS              (1 << 16)
+#define STATUS_ENDPRDMASTS            (1 << 17)
+
+#define ICLEAR_SOFTRAPICLR            (1 << 0)
+#define ICLEAR_VLINEICLR              (1 << 5)
+
+#define IEN_SOFTRAPEN                 (1 << 0)
+
+#define TEXCTL_TEXFORMAT_MASK         (7 << 0)
+#define TEXCTL_TEXFORMAT_TW4          (0 << 0)
+#define TEXCTL_TEXFORMAT_TW8          (1 << 0)
+#define TEXCTL_TEXFORMAT_TW15         (2 << 0)
+#define TEXCTL_TEXFORMAT_TW16         (3 << 0)
+#define TEXCTL_TEXFORMAT_TW12         (4 << 0)
+#define TEXCTL_PALSEL_MASK            (0xf << 4)
+#define TEXCTL_TPITCH_SHIFT           (16)
+#define TEXCTL_TPITCH_MASK            (7 << TEXCTL_TPITCH_SHIFT)
+#define TEXCTL_TPITCHLIN              (1 << 8)
+#define TEXCTL_TPITCHEXT_MASK         (0x7ff << 9)
+#define TEXCTL_NPCEN                  (1 << 21)
+#define TEXCTL_AZEROEXTEND            (1 << 23)
+#define TEXCTL_DECALCKEY              (1 << 24)
+#define TEXCTL_TAKEY                  (1 << 25)
+#define TEXCTL_TAMASK                 (1 << 26)
+#define TEXCTL_CLAMPV                 (1 << 27)
+#define TEXCTL_CLAMPU                 (1 << 28)
+#define TEXCTL_TMODULATE              (1 << 29)
+#define TEXCTL_STRANS                 (1 << 30)
+#define TEXCTL_ITRANS                 (1 << 31)
+
+#define TEXHEIGHT_TH_MASK             (0x3f << 0)
+#define TEXHEIGHT_THMASK_SHIFT        (18)
+#define TEXHEIGHT_THMASK_MASK         (0x7ff << TEXHEIGHT_THMASK_SHIFT)
+
+#define TEXWIDTH_TW_MASK              (0x3f << 0)
+#define TEXWIDTH_TWMASK_SHIFT         (18)
+#define TEXWIDTH_TWMASK_MASK          (0x7ff << TEXWIDTH_TWMASK_SHIFT)
+
+#define TEXTRANS_TCKEY_MASK           (0xffff)
+#define TEXTRANS_TKMASK_SHIFT         (16)
+#define TEXTRANS_TKMASK_MASK          (0xffff << TEXTRANS_TKMASK_SHIFT)
+
+#define DITHER_565                    0
+#define DITHER_NONE_565               1
+#define DITHER_555                    2
+#define DITHER_NONE_555               3
+
+/*PCI configuration registers*/
+#define OPTION_INTERLEAVE (1 << 12)
+#define OPTION_POWERPC (1 << 31)
+
+enum {
+    MGA_2064W,  /*Millennium*/
+    MGA_1064SG, /*Mystique*/
+    MGA_1164SG, /*Mystique 220*/
+    MGA_2164W, /*Millennium II*/
+    MGA_G100,  /*Productiva G100*/
+};
+
+enum {
+    FIFO_INVALID          = (0x00 << 24),
+    FIFO_WRITE_CTRL_BYTE  = (0x01 << 24),
+    FIFO_WRITE_CTRL_LONG  = (0x02 << 24),
+    FIFO_WRITE_ILOAD_LONG = (0x03 << 24)
+};
+
+enum {
+    DMA_STATE_IDLE = 0,
+    DMA_STATE_PRI,
+    DMA_STATE_SEC
+};
+
+typedef struct
+{
+    uint32_t addr_type;
+    uint32_t val;
+} fifo_entry_t;
+
+typedef struct mystique_t {
+    svga_t svga;
+
+    rom_t bios_rom;
+
+    int type;
+
+    mem_mapping_t lfb_mapping, ctrl_mapping,
+        iload_mapping;
+
+    uint8_t int_line, xcurctrl,
+        xsyspllm, xsysplln, xsyspllp,
+        xgenioctrl, xgeniodata,
+        xmulctrl, xgenctrl,
+        xmiscctrl, xpixclkctrl,
+        xvrefctrl, ien, dmamod,
+        dmadatasiz, dirdatasiz,
+        xcolkeymskl, xcolkeymskh,
+        xcolkeyl, xcolkeyh,
+        xcrcbitsel;
+
+    uint8_t pci_slot, irq_state, pad, pad0;
+
+    uint8_t pci_regs[256], crtcext_regs[6],
+        xreg_regs[256], dmamap[16];
+
+    int vram_size, crtcext_idx, xreg_idx, xzoomctrl;
+
+    atomic_int busy, blitter_submit_refcount,
+        blitter_submit_dma_refcount, blitter_complete_refcount,
+        endprdmasts_pending, softrap_pending,
+        fifo_read_idx, fifo_write_idx;
+
+    uint32_t vram_mask, vram_mask_w, vram_mask_l,
+        lfb_base, ctrl_base, iload_base,
+        ma_latch_old, maccess, mctlwtst, maccess_running,
+        softrap_pending_val;
+
+    atomic_uint status;
+    atomic_bool softrap_status_read;
+
+    uint64_t blitter_time, status_time;
+
+    pc_timer_t softrap_pending_timer, wake_timer;
+
+    fifo_entry_t fifo[FIFO_SIZE];
+
+    thread_t *fifo_thread;
+
+    event_t *wake_fifo_thread, *fifo_not_full_event;
+
+    struct
+    {
+        int m, n, p, s;
+    } xpixpll[3];
+
+    struct
+    {
+        uint8_t funcnt : 7, stylelen,
+            dmamod;
+
+        int16_t fxleft, fxright,
+            xdst;
+
+        uint16_t cxleft, cxright,
+            length;
+
+        int xoff, yoff, selline, ydst,
+            length_cur, iload_rem_count, idump_end_of_line, words,
+            ta_key, ta_mask, lastpix_r, lastpix_g,
+            lastpix_b, highv_line, beta, dither, err, k1, k2;
+
+        bool pattern[8][16];
+
+        uint32_t dwgctrl, dwgctrl_running, bcol, fcol,
+            pitch, plnwt, ybot, ydstorg,
+            ytop, texorg, texwidth, texheight,
+            texctl, textrans, zorg, ydst_lin,
+            src_addr, z_base, iload_rem_data, highv_data,
+            fogcol, fogxinc : 24, fogyinc : 24, fogstart : 24,
+            alphactrl, alphaxinc : 24, alphayinc : 24, alphastart : 24,
+            texfilter;
+
+        uint32_t src[4], ar[7],
+            dr[16], tmr[9];
+
+        uint64_t extended_dr[4];
+
+        struct
+        {
+            int sdydxl, scanleft, sdxl, sdy,
+                sdxr;
+        } sgn;
+    } dwgreg;
+
+    struct
+    {
+        uint8_t r, g, b;
+    } lut[256];
+
+    struct
+    {
+        uint16_t pos_x, pos_y,
+            addr;
+        uint32_t col[3];
+    } cursor;
+
+    struct
+    {
+        int32_t pri_state, sec_state, iload_state, state;
+
+        uint32_t primaddress, primend, secaddress, secend,
+            pri_header, sec_header,
+            iload_header;
+
+        uint32_t words_expected;
+
+        mutex_t *lock;
+    } dma;
+
+    uint8_t thread_run;
+
+    void *i2c, *i2c_ddc, *ddc;
+} mystique_t;
+
+static const uint8_t trans_masks[16][16] = {
+  // clang-format off
+    {
+        1, 1, 1, 1,
+        1, 1, 1, 1,
+        1, 1, 1, 1,
+        1, 1, 1, 1
+    },
+    {
+        1, 0, 1, 0,
+        0, 1, 0, 1,
+        1, 0, 1, 0,
+        0, 1, 0, 1
+    },
+    {
+        0, 1, 0, 1,
+        1, 0, 1, 0,
+        0, 1, 0, 1,
+        1, 0, 1, 0
+    },
+    {
+        1, 0, 1, 0,
+        0, 0, 0, 0,
+        1, 0, 1, 0,
+        0, 0, 0, 0
+    },
+    {
+        0, 1, 0, 1,
+        0, 0, 0, 0,
+        0, 1, 0, 1,
+        0, 0, 0, 0
+    },
+    {
+        0, 0, 0, 0,
+        1, 0, 1, 0,
+        0, 0, 0, 0,
+        1, 0, 1, 0
+    },
+    {
+        0, 0, 0, 0,
+        0, 1, 0, 1,
+        0, 0, 0, 0,
+        0, 1, 0, 1
+    },
+    {
+        1, 0, 0, 0,
+        0, 0, 0, 0,
+        0, 0, 1, 0,
+        0, 0, 0, 0
+    },
+    {
+        0, 0, 0, 0,
+        0, 1, 0, 0,
+        0, 0, 0, 0,
+        0, 0, 0, 1
+    },
+    {
+        0, 0, 0, 1,
+        0, 0, 0, 0,
+        0, 1, 0, 0,
+        0, 0, 0, 0
+    },
+    {
+        0, 0, 0, 0,
+        0, 0, 1, 0,
+        0, 0, 0, 0,
+        1, 0, 0, 0
+    },
+    {
+        0, 0, 0, 0,
+        1, 0, 0, 0,
+        0, 0, 0, 0,
+        0, 0, 1, 0
+    },
+    {
+        0, 1, 0, 0,
+        0, 0, 0, 0,
+        0, 0, 0, 1,
+        0, 0, 0, 0
+    },
+    {
+        0, 0, 0, 0,
+        0, 0, 0, 1,
+        0, 0, 0, 0,
+        0, 1, 0, 0
+    },
+    {
+        0, 0, 1, 0,
+        0, 0, 0, 0,
+        1, 0, 0, 0,
+        0, 0, 0, 0
+    },
+    {
+        0, 0, 0, 0,
+        0, 0, 0, 0,
+        0, 0, 0, 0,
+        0, 0, 0, 0
+    }
+  // clang-format on
+};
+
+static int8_t dither5[256][2][2];
+static int8_t dither6[256][2][2];
+static double bayer_mat[4][4] =
+{
+    { 0.0, 8. / 16., 2. / 16., 10. / 16.},
+    { 12. / 16., 4. / 16., 14. / 16., 6. / 16.},
+    { 3. / 16., 11. / 16., 1. / 16., 9. / 16.},
+    { 15. / 16., 7. / 16., 13. / 16., 5. / 16.},
+};
+
+static video_timings_t timing_matrox_millennium = { .type = VIDEO_PCI, .write_b = 2, .write_w = 2, .write_l = 1, .read_b = 10, .read_w = 10, .read_l = 10 };
+static video_timings_t timing_matrox_mystique   = { .type = VIDEO_PCI, .write_b = 4, .write_w = 4, .write_l = 4, .read_b = 10, .read_w = 10, .read_l = 10 };
+
+static void mystique_start_blit(mystique_t *mystique);
+static void mystique_update_irqs(mystique_t *mystique);
+
+static void wake_fifo_thread(mystique_t *mystique);
+static void wait_fifo_idle(mystique_t *mystique);
+static void mystique_queue(mystique_t *mystique, uint32_t addr, uint32_t val, uint32_t type);
+
+static uint8_t  mystique_readb_linear(uint32_t addr, void *priv);
+static uint16_t mystique_readw_linear(uint32_t addr, void *priv);
+static uint32_t mystique_readl_linear(uint32_t addr, void *priv);
+static void     mystique_writeb_linear(uint32_t addr, uint8_t val, void *priv);
+static void     mystique_writew_linear(uint32_t addr, uint16_t val, void *priv);
+static void     mystique_writel_linear(uint32_t addr, uint32_t val, void *priv);
+
+static void mystique_recalc_mapping(mystique_t *mystique);
+static int  mystique_line_compare(svga_t *svga);
+
+static uint8_t  mystique_iload_read_b(uint32_t addr, void *priv);
+static uint32_t mystique_iload_read_l(uint32_t addr, void *priv);
+static void     mystique_iload_write_b(uint32_t addr, uint8_t val, void *priv);
+static void     mystique_iload_write_l(uint32_t addr, uint32_t val, void *priv);
+
+static uint32_t blit_idump_read(mystique_t *mystique);
+static void     blit_iload_write(mystique_t *mystique, uint32_t data, int size);
+
+static bool powerpc(mystique_t *mystique, uint32_t addr)
+{
+    if (mystique->pci_regs[0x43] & (OPTION_POWERPC >> 24)) {
+        if ((addr & 0x3ffc) >= 0x1c00 && (addr & 0x3ffc) < 0x1f00)
+            return true;
+        if (mystique->type == MGA_1064SG || mystique->type == MGA_1164SG) {
+            if ((addr & 0x3ffc) >= 0x2c00 && (addr & 0x3ffc) < 0x2e00)
+                return true;
+        }
+    }
+    return false;
+}
+
+void
+mystique_out(uint16_t addr, uint8_t val, void *priv)
+{
+    mystique_t *mystique = (mystique_t *) priv;
+    svga_t     *svga     = &mystique->svga;
+    uint8_t     old;
+
+    if ((((addr & 0xFFF0) == 0x3D0 || (addr & 0xFFF0) == 0x3B0) && addr < 0x3de) && !(svga->miscout & 1))
+        addr ^= 0x60;
+
+    switch (addr) {
+        case 0x3c8:
+            mystique->xreg_idx = val;
+            //fallthrough;
+        case 0x3c6:
+        case 0x3c7:
+        case 0x3c9:
+            if (mystique->type == MGA_2064W || mystique->type == MGA_2164W) {
+                tvp3026_ramdac_out(addr, 0, 0, val, svga->ramdac, svga);
+                return;
+            }
+            break;
+
+        case 0x3cf:
+            if ((svga->gdcaddr & 15) == 6 && svga->gdcreg[6] != val) {
+                svga->gdcreg[svga->gdcaddr & 15] = val;
+                mystique_recalc_mapping(mystique);
+                return;
+            }
+            break;
+
+        case 0x3D4:
+            svga->crtcreg = val & 0x3f;
+            return;
+        case 0x3D5:
+            if (((svga->crtcreg & 0x3f) < 7) && (svga->crtc[0x11] & 0x80))
+                return;
+            if (((svga->crtcreg & 0x3f) == 7) && (svga->crtc[0x11] & 0x80))
+                val = (svga->crtc[7] & ~0x10) | (val & 0x10);
+            old                              = svga->crtc[svga->crtcreg & 0x3f];
+            svga->crtc[svga->crtcreg & 0x3f] = val;
+            if (old != val) {
+                if ((svga->crtcreg & 0x3f) < 0xE || (svga->crtcreg & 0x3f) > 0x10) {
+                    if (((svga->crtcreg & 0x3f) == 0xc) || ((svga->crtcreg & 0x3f) == 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 == 0x11) {
+                    if (!(val & 0x10))
+                        mystique->status &= ~STATUS_VSYNCPEN;
+                    mystique_update_irqs(mystique);
+                }
+            }
+            break;
+
+        case 0x3de:
+            mystique->crtcext_idx = val;
+            break;
+        case 0x3df:
+            if (mystique->crtcext_idx == 1)
+                svga->dpms = !!(val & 0x30);
+            old = mystique->crtcext_regs[mystique->crtcext_idx];
+            if (mystique->crtcext_idx < 6)
+                mystique->crtcext_regs[mystique->crtcext_idx] = val;
+
+            if ((mystique->type >= MGA_1064SG) && (mystique->crtcext_idx == 0) &&
+                (mystique->crtcext_regs[3] & CRTCX_R3_MGAMODE)) {
+                svga->rowoffset     = svga->crtc[0x13] |
+                                      ((mystique->crtcext_regs[0] & CRTCX_R0_OFFSET_MASK) << 4);
+
+                if (!(mystique->type >= MGA_2164W))
+                    svga->rowoffset <<= 1;
+
+                svga->ma_latch      = ((mystique->crtcext_regs[0] & CRTCX_R0_STARTADD_MASK) << 16) |
+                                      (svga->crtc[0xc] << 8) | svga->crtc[0xd];
+                if ((mystique->pci_regs[0x41] & (OPTION_INTERLEAVE >> 8))) {
+                    svga->rowoffset <<= 1;
+                    svga->ma_latch <<= 1;
+                }
+
+                if (!(mystique->type >= MGA_2164W))
+                    svga->ma_latch <<= 1;
+
+                if (svga->ma_latch != mystique->ma_latch_old) {
+                    if (svga->interlace && svga->oddeven)
+                        svga->maback = (svga->maback - (mystique->ma_latch_old << 2)) +
+                                       (svga->ma_latch << 2) + (svga->rowoffset << 1);
+                    else
+                        svga->maback = (svga->maback - (mystique->ma_latch_old << 2)) +
+                                       (svga->ma_latch << 2);
+                    mystique->ma_latch_old = svga->ma_latch;
+                }
+            }
+
+            if (mystique->crtcext_idx == 4) {
+                if (svga->gdcreg[6] & 0xc) {
+                    /*64k banks*/
+                    if (mystique->type >= MGA_2164W) {
+                        svga->read_bank  = val << 16;
+                        svga->write_bank = val << 16;
+                    } else {
+                        svga->read_bank  = (val & 0x7f) << 16;
+                        svga->write_bank = (val & 0x7f) << 16;
+                    }
+                } else {
+                    /*128k banks*/
+                    if (mystique->type >= MGA_2164W) {
+                        svga->read_bank  = (val & 0xfe) << 16;
+                        svga->write_bank = (val & 0xfe) << 16;
+                    } else {
+                        svga->read_bank  = (val & 0x7e) << 16;
+                        svga->write_bank = (val & 0x7e) << 16;
+                    }
+                }
+            }
+            if (!((mystique->type >= MGA_1064SG) && (mystique->crtcext_idx == 0) &&
+                (mystique->crtcext_regs[3] & CRTCX_R3_MGAMODE)))
+                svga_recalctimings(svga);
+
+            break;
+
+        default:
+            break;
+    }
+
+    svga_out(addr, val, svga);
+}
+
+uint8_t
+mystique_in(uint16_t addr, void *priv)
+{
+    mystique_t *mystique = (mystique_t *) priv;
+    svga_t     *svga     = &mystique->svga;
+    uint8_t     temp     = 0xff;
+
+    if ((((addr & 0xFFF0) == 0x3D0 || (addr & 0xFFF0) == 0x3B0) && addr < 0x3de) && !(svga->miscout & 1))
+        addr ^= 0x60;
+
+    switch (addr) {
+        case 0x3c1:
+            if (svga->attraddr >= 0x15)
+                temp = 0;
+            else
+                temp = svga->attrregs[svga->attraddr];
+            break;
+
+        case 0x3c6:
+        case 0x3c7:
+        case 0x3c8:
+        case 0x3c9:
+            if (mystique->type == MGA_2064W || mystique->type == MGA_2164W)
+                temp = tvp3026_ramdac_in(addr, 0, 0, svga->ramdac, svga);
+            else
+                temp = svga_in(addr, svga);
+            break;
+
+        case 0x3D4:
+            temp = svga->crtcreg;
+            break;
+        case 0x3D5:
+            if ((svga->crtcreg >= 0x19 && svga->crtcreg <= 0x21) || svga->crtcreg == 0x23 || svga->crtcreg == 0x25 || svga->crtcreg >= 0x27)
+                temp = 0;
+            else
+                temp = svga->crtc[svga->crtcreg & 0x3f];
+            break;
+
+        case 0x3de:
+            temp = mystique->crtcext_idx;
+            break;
+
+        case 0x3df:
+            if (mystique->crtcext_idx < 6)
+                temp = mystique->crtcext_regs[mystique->crtcext_idx];
+            break;
+
+        default:
+            temp = svga_in(addr, svga);
+            break;
+    }
+
+    return temp;
+}
+
+static int
+mystique_line_compare(svga_t *svga)
+{
+    mystique_t *mystique = (mystique_t *) svga->priv;
+
+    mystique->status |= STATUS_VLINEPEN;
+    mystique_update_irqs(mystique);
+
+    return 0;
+}
+
+static void
+mystique_vblank_start(svga_t *svga)
+{
+    mystique_t *mystique = (mystique_t *) svga->priv;
+
+    if (mystique->crtcext_regs[3] & CRTCX_R3_MGAMODE) {
+        svga->ma_latch      = ((mystique->crtcext_regs[0] & CRTCX_R0_STARTADD_MASK) << 16) | (svga->crtc[0xc] << 8) | svga->crtc[0xd];
+        if (mystique->pci_regs[0x41] & (OPTION_INTERLEAVE >> 8))
+            svga->ma_latch <<= 1;
+    }
+}
+
+static void
+mystique_vsync_callback(svga_t *svga)
+{
+    mystique_t *mystique = (mystique_t *) svga->priv;
+
+    if (svga->crtc[0x11] & 0x10) {
+        mystique->status |= STATUS_VSYNCPEN;
+        mystique_update_irqs(mystique);
+    }
+}
+
+static float
+mystique_getclock(int clock, void *priv)
+{
+    const mystique_t *mystique = (mystique_t *) priv;
+
+    if (clock == 0)
+        return 25175000.0;
+    if (clock == 1)
+        return 28322000.0;
+
+    int m  = mystique->xpixpll[2].m;
+    int n  = mystique->xpixpll[2].n;
+    int pl = mystique->xpixpll[2].p;
+
+    float fvco = 14318181.0f * (n + 1) / (m + 1);
+    float fo   = fvco / (pl + 1);
+
+    return fo;
+}
+
+void
+mystique_recalctimings(svga_t *svga)
+{
+    mystique_t *mystique = (mystique_t *) svga->priv;
+    int         clk_sel  = (svga->miscout >> 2) & 3;
+
+    //svga->clock = (cpuclock * (float) (1ULL << 32)) / svga->getclock(clk_sel & 3, svga->clock_gen);
+
+    if (mystique->crtcext_regs[1] & CRTCX_R1_HTOTAL8)
+        svga->htotal |= 0x100;
+
+    svga->hblankstart    = (((mystique->crtcext_regs[1] & 0x02) >> 2) << 8) + svga->crtc[2];
+
+    if (mystique->crtcext_regs[2] & CRTCX_R2_VTOTAL10)
+        svga->vtotal |= 0x400;
+    if (mystique->crtcext_regs[2] & CRTCX_R2_VTOTAL11)
+        svga->vtotal |= 0x800;
+    if (mystique->crtcext_regs[2] & CRTCX_R2_VDISPEND10)
+        svga->dispend |= 0x400;
+    if (mystique->crtcext_regs[2] & CRTCX_R2_VBLKSTR10)
+        svga->vblankstart |= 0x400;
+    if (mystique->crtcext_regs[2] & CRTCX_R2_VBLKSTR11)
+        svga->vblankstart |= 0x800;
+    if (mystique->crtcext_regs[2] & CRTCX_R2_VSYNCSTR10)
+        svga->vsyncstart |= 0x400;
+    if (mystique->crtcext_regs[2] & CRTCX_R2_VSYNCSTR11)
+        svga->vsyncstart |= 0x800;
+    if (mystique->crtcext_regs[2] & CRTCX_R2_LINECOMP10)
+        svga->split |= 0x400;
+
+    if (mystique->type == MGA_2064W || mystique->type == MGA_2164W) {
+        tvp3026_recalctimings(svga->ramdac, svga);
+        svga->interlace |= !!(mystique->crtcext_regs[0] & 0x80);
+    } else
+        svga->interlace = !!(mystique->crtcext_regs[0] & 0x80);
+
+    if (mystique->crtcext_regs[3] & CRTCX_R3_MGAMODE) {
+        svga->lowres        = 0;
+        svga->char_width    = 8;
+        svga->hdisp         = (svga->crtc[1] + 1) << 3;
+        svga->hdisp_time    = svga->hdisp;
+        svga->rowoffset     = svga->crtc[0x13] | ((mystique->crtcext_regs[0] & CRTCX_R0_OFFSET_MASK) << 4);
+
+        svga->dots_per_clock  = 8;
+        svga->hblank_end_val  = (svga->crtc[3] & 0x1f) | (((svga->crtc[5] & 0x80) >> 7) << 5) |
+                                (((mystique->crtcext_regs[1] & 0x40) >> 6) << 6);
+        svga->hblank_end_mask = 0x0000007f;
+
+        if (mystique->type != MGA_2164W && mystique->type != MGA_2064W)
+            svga->lut_map = !!(mystique->xmiscctrl & XMISCCTRL_RAMCS);
+
+        svga->ma_latch = ((mystique->crtcext_regs[0] & CRTCX_R0_STARTADD_MASK) << 16) | (svga->crtc[0xc] << 8) | svga->crtc[0xd];
+
+        if ((mystique->pci_regs[0x41] & (OPTION_INTERLEAVE >> 8))) {
+            svga->rowoffset <<= 1;
+            if (mystique->type >= MGA_1064SG)
+                svga->ma_latch <<= 1;
+        }
+
+        if (mystique->type >= MGA_1064SG) {
+            /*Mystique and later, unlike most SVGA cards, allows display start to take
+              effect mid-screen*/
+            if (!(mystique->type >= MGA_2164W))
+                svga->ma_latch <<= 1;
+            /* Only change maback so the new display start will take effect on the next
+               horizontal retrace. */
+            if (svga->ma_latch != mystique->ma_latch_old) {
+                if (svga->interlace && svga->oddeven)
+                    svga->maback = (svga->maback - (mystique->ma_latch_old << 2)) +
+                                   (svga->ma_latch << 2) + (svga->rowoffset << 1);
+                else
+                    svga->maback = (svga->maback - (mystique->ma_latch_old << 2)) +
+                                   (svga->ma_latch << 2);
+                mystique->ma_latch_old = svga->ma_latch;
+            }
+
+            if (!(mystique->type >= MGA_2164W))
+                svga->rowoffset <<= 1;
+            if (mystique->type != MGA_2164W) {
+                switch (mystique->xmulctrl & XMULCTRL_DEPTH_MASK) {
+                    case XMULCTRL_DEPTH_8:
+                    case XMULCTRL_DEPTH_2G8V16:
+                        svga->render = svga_render_8bpp_highres;
+                        svga->bpp    = 8;
+                        break;
+                    case XMULCTRL_DEPTH_15:
+                    case XMULCTRL_DEPTH_G16V16:
+                        svga->render = svga_render_15bpp_highres;
+                        svga->bpp    = 15;
+                        break;
+                    case XMULCTRL_DEPTH_16:
+                        svga->render = svga_render_16bpp_highres;
+                        svga->bpp    = 16;
+                        break;
+                    case XMULCTRL_DEPTH_24:
+                        svga->render = svga_render_24bpp_highres;
+                        svga->bpp    = 24;
+                        break;
+                    case XMULCTRL_DEPTH_32:
+                    case XMULCTRL_DEPTH_32_OVERLAYED:
+                        svga->render = svga_render_32bpp_highres;
+                        svga->bpp    = 32;
+                        break;
+
+                    default:
+                        break;
+                }
+            } else {
+                switch (svga->bpp) {
+                    case 8:
+                        svga->render = svga_render_8bpp_highres;
+                        break;
+                    case 15:
+                        svga->render = svga_render_15bpp_highres;
+                        break;
+                    case 16:
+                        svga->render = svga_render_16bpp_highres;
+                        break;
+                    case 24:
+                        svga->render = svga_render_24bpp_highres;
+                        break;
+                    case 32:
+                        svga->render = svga_render_32bpp_highres;
+                        break;
+                }
+            }
+        } else {
+            switch (svga->bpp) {
+                case 8:
+                    svga->render = svga_render_8bpp_highres;
+                    break;
+                case 15:
+                    svga->render = svga_render_15bpp_highres;
+                    break;
+                case 16:
+                    svga->render = svga_render_16bpp_highres;
+                    break;
+                case 24:
+                    svga->render = svga_render_24bpp_highres;
+                    break;
+                case 32:
+                    svga->render = svga_render_32bpp_highres;
+                    break;
+            }
+        }
+        svga->packed_chain4 = 1;
+        svga->line_compare = mystique_line_compare;
+        if (mystique->type < MGA_1064SG)
+            svga->vblank_start = mystique_vblank_start;
+    } else {
+        svga->packed_chain4 = 0;
+        svga->line_compare  = NULL;
+        svga->lut_map       = 0;
+        if (mystique->type >= MGA_1064SG)
+            svga->bpp = 8;
+        else
+            svga->vblank_start  = NULL;
+    }
+
+    svga->fb_only       = svga->packed_chain4;
+    svga->disable_blink = (svga->bpp > 4);
+    video_force_resize_set_monitor(1, svga->monitor_index);
+#if 0
+    pclog("PackedChain4=%d, chain4=%x, fast=%x, bit6 attrreg10=%02x, bits 5-6 gdcreg5=%02x, extmode=%02x.\n", svga->packed_chain4, svga->chain4, svga->fast, svga->attrregs[0x10] & 0x40, svga->gdcreg[5] & 0x60, mystique->pci_regs[0x41] & 1, mystique->crtcext_regs[3] & CRTCX_R3_MGAMODE);
+#endif
+}
+
+static void
+mystique_recalc_mapping(mystique_t *mystique)
+{
+    svga_t *svga = &mystique->svga;
+
+    io_removehandlerx(0x03c0, 0x0020, mystique_in, NULL, NULL, mystique_out, NULL, NULL, mystique);
+    if ((mystique->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) && (mystique->pci_regs[0x41] & 1))
+        io_sethandlerx(0x03c0, 0x0020, mystique_in, NULL, NULL, mystique_out, NULL, NULL, mystique);
+
+    if (!(mystique->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) {
+        mem_mapping_disablex(&svga->mapping);
+        mem_mapping_disablex(&mystique->ctrl_mapping);
+        mem_mapping_disablex(&mystique->lfb_mapping);
+        mem_mapping_disablex(&mystique->iload_mapping);
+        return;
+    }
+
+    if (mystique->ctrl_base)
+        mem_mapping_set_addrx(&mystique->ctrl_mapping, mystique->ctrl_base, 0x4000);
+    else
+        mem_mapping_disablex(&mystique->ctrl_mapping);
+
+    if (mystique->lfb_base)
+        mem_mapping_set_addrx(&mystique->lfb_mapping, mystique->lfb_base, (mystique->type >= MGA_2164W) ? 0x1000000 : 0x800000);
+    else
+        mem_mapping_disablex(&mystique->lfb_mapping);
+
+    if (mystique->iload_base)
+        mem_mapping_set_addrx(&mystique->iload_mapping, mystique->iload_base, 0x800000);
+    else
+        mem_mapping_disablex(&mystique->iload_mapping);
+
+    if (mystique->pci_regs[0x41] & 1) {
+        switch (svga->gdcreg[6] & 0x0C) {
+            case 0x0: /*128k at A0000*/
+                mem_mapping_set_addrx(&svga->mapping, 0xa0000, 0x20000);
+                svga->banked_mask = 0xffff;
+                break;
+            case 0x4: /*64k at A0000*/
+                mem_mapping_set_addrx(&svga->mapping, 0xa0000, 0x10000);
+                svga->banked_mask = 0xffff;
+                break;
+            case 0x8: /*32k at B0000*/
+                mem_mapping_set_addrx(&svga->mapping, 0xb0000, 0x08000);
+                svga->banked_mask = 0x7fff;
+                break;
+            case 0xC: /*32k at B8000*/
+                mem_mapping_set_addrx(&svga->mapping, 0xb8000, 0x08000);
+                svga->banked_mask = 0x7fff;
+                break;
+
+            default:
+                break;
+        }
+        if (svga->gdcreg[6] & 0xc) {
+            /*64k banks*/
+            svga->read_bank  = (mystique->crtcext_regs[4] & 0x7f) << 16;
+            svga->write_bank = (mystique->crtcext_regs[4] & 0x7f) << 16;
+        } else {
+            /*128k banks*/
+            svga->read_bank  = (mystique->crtcext_regs[4] & 0x7e) << 16;
+            svga->write_bank = (mystique->crtcext_regs[4] & 0x7e) << 16;
+        }
+    } else
+        mem_mapping_disablex(&svga->mapping);
+}
+
+static void
+mystique_update_irqs(mystique_t *mystique)
+{
+    const svga_t *svga = &mystique->svga;
+    int           irq  = 0;
+
+    if ((mystique->status & mystique->ien) & STATUS_SOFTRAPEN)
+        irq = 1;
+    if ((mystique->status & mystique->ien) & STATUS_VLINEPEN)
+        irq = 1;
+    if ((mystique->status & STATUS_VSYNCPEN) && (svga->crtc[0x11] & 0x30) == 0x10)
+        irq = 1;
+
+    if (irq)
+        pci_set_irq(mystique->pci_slot, PCI_INTA, &mystique->irq_state);
+    else
+        pci_clear_irq(mystique->pci_slot, PCI_INTA, &mystique->irq_state);
+}
+
+#define READ8(addr, var)                \
+    switch ((addr) &3) {                \
+        case 0:                         \
+            ret = (var) &0xff;          \
+            break;                      \
+        case 1:                         \
+            ret = ((var) >> 8) & 0xff;  \
+            break;                      \
+        case 2:                         \
+            ret = ((var) >> 16) & 0xff; \
+            break;                      \
+        case 3:                         \
+            ret = ((var) >> 24) & 0xff; \
+            break;                      \
+    }
+
+#define WRITE8(addr, var, val)                        \
+    switch ((addr) &3) {                              \
+        case 0:                                       \
+            var = (var & 0xffffff00) | (val);         \
+            break;                                    \
+        case 1:                                       \
+            var = (var & 0xffff00ff) | ((val) << 8);  \
+            break;                                    \
+        case 2:                                       \
+            var = (var & 0xff00ffff) | ((val) << 16); \
+            break;                                    \
+        case 3:                                       \
+            var = (var & 0x00ffffff) | ((val) << 24); \
+            break;                                    \
+    }
+
+#define READ8R(addr, var)               \
+    switch ((addr) &3) {                \
+        case 2:                         \
+            ret = (var) &0xff;          \
+            break;                      \
+        case 1:                         \
+            ret = ((var) >> 8) & 0xff;  \
+            break;                      \
+        case 0:                         \
+            ret = ((var) >> 16) & 0xff; \
+            break;                      \
+    }
+
+#define WRITE8R(addr, var, val)                       \
+    switch ((addr) &3) {                              \
+        case 2:                                       \
+            var = (var & 0xffffff00) | (val);         \
+            break;                                    \
+        case 1:                                       \
+            var = (var & 0xffff00ff) | ((val) << 8);  \
+            break;                                    \
+        case 0:                                       \
+            var = (var & 0xff00ffff) | ((val) << 16); \
+            break;                                    \
+    }
+
+
+static uint8_t
+mystique_read_xreg(mystique_t *mystique, int reg)
+{
+    uint8_t ret = 0xff;
+
+    switch (reg) {
+        case XREG_XCURADDL:
+            ret = mystique->cursor.addr & 0xff;
+            break;
+        case XREG_XCURADDH:
+            ret = mystique->cursor.addr >> 8;
+            break;
+        case XREG_XCURCTRL:
+            ret = mystique->xcurctrl;
+            break;
+
+        case XREG_XCURCOL0R:
+        case XREG_XCURCOL0G:
+        case XREG_XCURCOL0B:
+            READ8R(reg, mystique->cursor.col[0]);
+            break;
+        case XREG_XCURCOL1R:
+        case XREG_XCURCOL1G:
+        case XREG_XCURCOL1B:
+            READ8R(reg, mystique->cursor.col[1]);
+            break;
+        case XREG_XCURCOL2R:
+        case XREG_XCURCOL2G:
+        case XREG_XCURCOL2B:
+            READ8R(reg, mystique->cursor.col[2]);
+            break;
+
+        case XREG_XMULCTRL:
+            ret = mystique->xmulctrl;
+            break;
+
+        case XREG_XMISCCTRL:
+            ret = mystique->xmiscctrl;
+            break;
+
+        case XREG_XGENCTRL:
+            ret = mystique->xgenctrl;
+            break;
+
+        case XREG_XVREFCTRL:
+            ret = mystique->xvrefctrl;
+            break;
+
+        case XREG_XGENIOCTRL:
+            ret = mystique->xgenioctrl;
+            break;
+        case XREG_XGENIODATA:
+            ret = mystique->xgeniodata & 0xf0;
+#if 0
+            if (i2c_gpio_get_scl(mystique->i2c_ddc))
+                ret |= 0x08;
+            if (i2c_gpio_get_scl(mystique->i2c))
+                ret |= 0x04;
+            if (i2c_gpio_get_sda(mystique->i2c_ddc))
+                ret |= 0x02;
+            if (i2c_gpio_get_sda(mystique->i2c))
+                ret |= 0x01;
+#endif
+            break;
+
+        case XREG_XSYSPLLM:
+            ret = mystique->xsyspllm;
+            break;
+        case XREG_XSYSPLLN:
+            ret = mystique->xsysplln;
+            break;
+        case XREG_XSYSPLLP:
+            ret = mystique->xsyspllp;
+            break;
+
+        case XREG_XZOOMCTRL:
+            ret = mystique->xzoomctrl;
+            break;
+
+        case XREG_XSENSETEST:
+            ret = 0;
+            if (mystique->svga.vgapal[0].b < 0x80)
+                ret |= 1;
+            if (mystique->svga.vgapal[0].g < 0x80)
+                ret |= 2;
+            if (mystique->svga.vgapal[0].r < 0x80)
+                ret |= 4;
+            break;
+
+        case XREG_XCRCREML: /*CRC not implemented*/
+            ret = 0;
+            break;
+        case XREG_XCRCREMH:
+            ret = 0;
+            break;
+        case XREG_XCRCBITSEL:
+            ret = mystique->xcrcbitsel;
+            break;
+
+        case XREG_XCOLKEYMSKL:
+            ret = mystique->xcolkeymskl;
+            break;
+        case XREG_XCOLKEYMSKH:
+            ret = mystique->xcolkeymskh;
+            break;
+        case XREG_XCOLKEYL:
+            ret = mystique->xcolkeyl;
+            break;
+        case XREG_XCOLKEYH:
+            ret = mystique->xcolkeyh;
+            break;
+
+        case XREG_XPIXCLKCTRL:
+            ret = mystique->xpixclkctrl;
+            break;
+
+        case XREG_XSYSPLLSTAT:
+            ret = XSYSPLLSTAT_SYSLOCK;
+            break;
+
+        case XREG_XPIXPLLSTAT:
+            ret = XPIXPLLSTAT_SYSLOCK;
+            break;
+
+        case XREG_XPIXPLLCM:
+            ret = mystique->xpixpll[2].m;
+            break;
+        case XREG_XPIXPLLCN:
+            ret = mystique->xpixpll[2].n;
+            break;
+        case XREG_XPIXPLLCP:
+            ret = mystique->xpixpll[2].p | (mystique->xpixpll[2].s << 3);
+            break;
+
+        case 0x00:
+        case 0x20:
+        case 0x3f:
+            ret = 0xff;
+            break;
+
+        default:
+            if (reg >= 0x50)
+                ret = 0xff;
+            break;
+    }
+
+    return ret;
+}
+
+static void
+mystique_write_xreg(mystique_t *mystique, int reg, uint8_t val)
+{
+    svga_t *svga = &mystique->svga;
+
+    switch (reg) {
+        case XREG_XCURADDL:
+            mystique->cursor.addr = (mystique->cursor.addr & 0x1f00) | val;
+            svga->hwcursor.addr   = mystique->cursor.addr << 10;
+            break;
+        case XREG_XCURADDH:
+            mystique->cursor.addr = (mystique->cursor.addr & 0x00ff) | ((val & 0x1f) << 8);
+            svga->hwcursor.addr   = mystique->cursor.addr << 10;
+            break;
+
+        case XREG_XCURCTRL:
+            mystique->xcurctrl = val;
+            svga->hwcursor.ena = (val & 3) ? 1 : 0;
+            break;
+
+        case XREG_XCURCOL0R:
+        case XREG_XCURCOL0G:
+        case XREG_XCURCOL0B:
+            WRITE8R(reg, mystique->cursor.col[0], val);
+            break;
+        case XREG_XCURCOL1R:
+        case XREG_XCURCOL1G:
+        case XREG_XCURCOL1B:
+            WRITE8R(reg, mystique->cursor.col[1], val);
+            break;
+        case XREG_XCURCOL2R:
+        case XREG_XCURCOL2G:
+        case XREG_XCURCOL2B:
+            WRITE8R(reg, mystique->cursor.col[2], val);
+            break;
+
+        case XREG_XMULCTRL:
+            mystique->xmulctrl = val;
+            break;
+
+        case XREG_XMISCCTRL:
+            mystique->xmiscctrl = val;
+            svga_set_ramdac_type(svga, (val & XMISCCTRL_VGA8DAC) ? RAMDAC_8BIT : RAMDAC_6BIT);
+            if (mystique->crtcext_regs[3] & CRTCX_R3_MGAMODE)
+                svga->lut_map       = !!(mystique->xmiscctrl & XMISCCTRL_RAMCS);
+            break;
+
+        case XREG_XGENCTRL:
+            mystique->xgenctrl = val;
+            break;
+
+        case XREG_XVREFCTRL:
+            mystique->xvrefctrl = val;
+            break;
+
+        case XREG_XGENIOCTRL:
+            mystique->xgenioctrl = val;
+#if 0
+            i2c_gpio_set(mystique->i2c_ddc, !(mystique->xgenioctrl & 0x08) || (mystique->xgeniodata & 0x08), !(mystique->xgenioctrl & 0x02) || (mystique->xgeniodata & 0x02));
+            i2c_gpio_set(mystique->i2c, !(mystique->xgenioctrl & 0x04) || (mystique->xgeniodata & 0x04), !(mystique->xgenioctrl & 0x01) || (mystique->xgeniodata & 0x01));
+#endif
+            break;
+        case XREG_XGENIODATA:
+            mystique->xgeniodata = val;
+            break;
+
+        case XREG_XSYSPLLM:
+            mystique->xsyspllm = val;
+            break;
+        case XREG_XSYSPLLN:
+            mystique->xsysplln = val;
+            break;
+        case XREG_XSYSPLLP:
+            mystique->xsyspllp = val;
+            break;
+
+        case XREG_XZOOMCTRL:
+            mystique->xzoomctrl = val & 3;
+            break;
+
+        case XREG_XSENSETEST:
+            break;
+
+        case XREG_XCRCREML: /*CRC not implemented*/
+            break;
+        case XREG_XCRCREMH:
+            break;
+        case XREG_XCRCBITSEL:
+            mystique->xcrcbitsel = val & 0x1f;
+            break;
+
+        case XREG_XCOLKEYMSKL:
+            mystique->xcolkeymskl = val;
+            break;
+        case XREG_XCOLKEYMSKH:
+            mystique->xcolkeymskh = val;
+            break;
+        case XREG_XCOLKEYL:
+            mystique->xcolkeyl = val;
+            break;
+        case XREG_XCOLKEYH:
+            mystique->xcolkeyh = val;
+            break;
+
+        case XREG_XSYSPLLSTAT:
+            break;
+
+        case XREG_XPIXPLLSTAT:
+            break;
+
+        case XREG_XPIXCLKCTRL:
+            mystique->xpixclkctrl = val;
+            break;
+
+        case XREG_XPIXPLLCM:
+            mystique->xpixpll[2].m = val;
+            break;
+        case XREG_XPIXPLLCN:
+            mystique->xpixpll[2].n = val;
+            break;
+        case XREG_XPIXPLLCP:
+            mystique->xpixpll[2].p = val & 7;
+            mystique->xpixpll[2].s = (val >> 3) & 3;
+            break;
+
+        case 0x00:
+        case 0x01:
+        case 0x02:
+        case 0x03:
+        case 0x07:
+        case 0x0b:
+        case 0x0f:
+        case 0x13:
+        case 0x14:
+        case 0x15:
+        case 0x16:
+        case 0x17:
+        case 0x1b:
+        case 0x1c:
+        case 0x20:
+        case 0x39:
+        case 0x3b:
+        case 0x3f:
+        case 0x47:
+        case 0x4b:
+            break;
+
+        default:
+            break;
+    }
+}
+
+static uint8_t
+mystique_ctrl_read_bx(uint32_t addr, void *priv)
+{
+    mystique_t *mystique = (mystique_t *) priv;
+    svga_t     *svga     = &mystique->svga;
+    uint8_t     ret      = 0xff;
+    int         fifocount;
+    uint8_t     addr_0x0f = 0;
+    uint16_t    addr_0x03 = 0;
+    int         rs2 = 0;
+    int         rs3 = 0;
+
+    if ((mystique->type == MGA_2064W || mystique->type == MGA_2164W) && (addr & 0x3e00) == 0x3c00) {
+        /*RAMDAC*/
+        addr_0x0f = addr & 0x0f;
+
+        if ((addr_0x0f & 3) == 0)
+            addr_0x03 = 0x3c8;
+        else if ((addr_0x0f & 3) == 1)
+            addr_0x03 = 0x3c9;
+        else if ((addr_0x0f & 3) == 2)
+            addr_0x03 = 0x3c6;
+        else if ((addr_0x0f & 3) == 3)
+            addr_0x03 = 0x3c7;
+
+        if ((addr_0x0f >= 0x04) && (addr_0x0f <= 0x07)) {
+            rs2 = 1;
+            rs3 = 0;
+        } else if ((addr_0x0f >= 0x08) && (addr_0x0f <= 0x0b)) {
+            rs2 = 0;
+            rs3 = 1;
+        } else if ((addr_0x0f >= 0x0c) && (addr_0x0f <= 0x0f)) {
+            rs2 = 1;
+            rs3 = 1;
+        }
+
+        ret = tvp3026_ramdac_in(addr_0x03, rs2, rs3, svga->ramdac, svga);
+    } else
+        switch (addr & 0x3fff) {
+            case REG_FIFOSTATUS:
+                fifocount = FIFO_SIZE - FIFO_ENTRIES;
+                if (fifocount > (mystique->type <= MGA_1064SG ? 32 : 64))
+                    fifocount = (mystique->type <= MGA_1064SG ? 32 : 64);
+                ret = fifocount;
+                break;
+            case REG_FIFOSTATUS + 1:
+                if (FIFO_EMPTY)
+                    ret |= 2;
+                else if (FIFO_ENTRIES >= (mystique->type <= MGA_1064SG ? 32 : 64))
+                    ret |= 1;
+                break;
+            case REG_FIFOSTATUS + 2:
+            case REG_FIFOSTATUS + 3:
+                ret = 0;
+                break;
+
+            case REG_STATUS:
+                ret = mystique->status & 0xff;
+                if (svga->cgastat & 8)
+                    ret |= REG_STATUS_VSYNCSTS;
+                if (ret & 1)
+                    mystique->softrap_status_read = 1;
+                if (mystique->softrap_status_read == 0 && !(ret & 1)) {
+                    mystique->softrap_status_read = 1;
+                    ret |= 1;
+                }
+                break;
+            case REG_STATUS + 1:
+                ret = (mystique->status >> 8) & 0xff;
+                break;
+            case REG_STATUS + 2:
+                ret = (mystique->status >> 16) & 0xff;
+                if (mystique->busy || ((mystique->blitter_submit_refcount + mystique->blitter_submit_dma_refcount) != mystique->blitter_complete_refcount) || !FIFO_EMPTY
+                || mystique->dma.state != DMA_STATE_IDLE || mystique->softrap_pending || mystique->endprdmasts_pending)
+                    ret |= (STATUS_DWGENGSTS >> 16);
+                break;
+            case REG_STATUS + 3:
+                ret = (mystique->status >> 24) & 0xff;
+                break;
+
+            case REG_IEN:
+                ret = mystique->ien & 0x65;
+                break;
+            case REG_IEN + 1:
+            case REG_IEN + 2:
+            case REG_IEN + 3:
+                ret = 0;
+                break;
+
+            case REG_OPMODE:
+                ret = mystique->dmamod << 2;
+                break;
+            case REG_OPMODE + 1:
+                ret = mystique->dmadatasiz;
+                break;
+            case REG_OPMODE + 2:
+                ret = mystique->dirdatasiz;
+                break;
+            case REG_OPMODE + 3:
+                ret = 0;
+                break;
+
+            case REG_PRIMADDRESS:
+            case REG_PRIMADDRESS + 1:
+            case REG_PRIMADDRESS + 2:
+            case REG_PRIMADDRESS + 3:
+                READ8(addr, mystique->dma.primaddress);
+                break;
+            case REG_PRIMEND:
+            case REG_PRIMEND + 1:
+            case REG_PRIMEND + 2:
+            case REG_PRIMEND + 3:
+                READ8(addr, mystique->dma.primend);
+                break;
+
+            case REG_SECADDRESS:
+            case REG_SECADDRESS + 1:
+            case REG_SECADDRESS + 2:
+            case REG_SECADDRESS + 3:
+                READ8(addr, mystique->dma.secaddress);
+                break;
+
+            case REG_VCOUNT:
+            case REG_VCOUNT + 1:
+            case REG_VCOUNT + 2:
+            case REG_VCOUNT + 3:
+                READ8(addr, svga->vc);
+                break;
+
+            case REG_ATTR_IDX:
+                ret = svga_in(0x3c0, svga);
+                break;
+            case REG_ATTR_DATA:
+                ret = svga_in(0x3c1, svga);
+                break;
+
+            case REG_INSTS0:
+                ret = svga_in(0x3c2, svga);
+                break;
+
+            case REG_SEQ_IDX:
+                ret = svga_in(0x3c4, svga);
+                break;
+            case REG_SEQ_DATA:
+                ret = svga_in(0x3c5, svga);
+                break;
+
+            case REG_MISCREAD:
+                ret = svga_in(0x3cc, svga);
+                break;
+
+            case REG_GCTL_IDX:
+                ret = mystique_in(0x3ce, mystique);
+                break;
+            case REG_GCTL_DATA:
+                ret = mystique_in(0x3cf, mystique);
+                break;
+
+            case REG_CRTC_IDX:
+                ret = mystique_in(0x3d4, mystique);
+                break;
+            case REG_CRTC_DATA:
+                ret = mystique_in(0x3d5, mystique);
+                break;
+
+            case REG_INSTS1:
+                ret = mystique_in(0x3da, mystique);
+                break;
+
+            case REG_CRTCEXT_IDX:
+                ret = mystique_in(0x3de, mystique);
+                break;
+            case REG_CRTCEXT_DATA:
+                ret = mystique_in(0x3df, mystique);
+                break;
+
+            case REG_PALWTADD:
+                ret = svga_in(0x3c8, svga);
+                break;
+            case REG_PALDATA:
+                ret = svga_in(0x3c9, svga);
+                break;
+            case REG_PIXRDMSK:
+                ret = svga_in(0x3c6, svga);
+                break;
+            case REG_PALRDADD:
+                ret = svga_in(0x3c7, svga);
+                break;
+
+            case REG_X_DATAREG:
+                ret = mystique_read_xreg(mystique, mystique->xreg_idx);
+                break;
+
+            case 0x1c40:
+            case 0x1c41:
+            case 0x1c42:
+            case 0x1c43:
+            case 0x1d44:
+            case 0x1d45:
+            case 0x1d46:
+            case 0x1d47:
+            case 0x1e50:
+            case 0x1e51:
+            case 0x1e52:
+            case 0x1e53:
+            case REG_ICLEAR:
+            case REG_ICLEAR + 1:
+            case REG_ICLEAR + 2:
+            case REG_ICLEAR + 3:
+            case 0x2c30:
+            case 0x2c31:
+            case 0x2c32:
+            case 0x2c33:
+            case 0x3e08:
+                break;
+
+            case 0x3c08:
+            case 0x3c09:
+            case 0x3c0b:
+                break;
+
+            default:
+                if ((addr & 0x3fff) >= 0x2c00 && (addr & 0x3fff) < 0x2c40)
+                    break;
+                if ((addr & 0x3fff) >= 0x3e00)
+                    break;
+                break;
+        }
+
+    return ret;
+}
+
+static uint8_t
+mystique_ctrl_read_b(uint32_t addr, void *priv)
+{
+    mystique_t *mystique = (mystique_t *)priv;
+
+    if (powerpc(mystique, addr)) {
+        addr ^= 3;
+    }
+       return mystique_ctrl_read_bx(addr, priv);
+}
+
+static void
+mystique_accel_ctrl_write_b(uint32_t addr, uint8_t val, void *priv)
+{
+    mystique_t *mystique   = (mystique_t *) priv;
+    int         start_blit = 0;
+
+    //pclog("B %08x %02x\n", addr, val);
+
+    if ((addr & 0x300) == 0x100) {
+        addr &= ~0x100;
+        start_blit = 1;
+    }
+
+    switch (addr & 0x3fff) {
+        case REG_MACCESS:
+        case REG_MACCESS + 1:
+        case REG_MACCESS + 2:
+        case REG_MACCESS + 3:
+            WRITE8(addr, mystique->maccess, val);
+            mystique->dwgreg.dither = mystique->maccess >> 30;
+            if (mystique->type < MGA_2164W)
+                mystique->maccess &= ~MACCESS_ZWIDTH;
+            else
+                mystique->dwgreg.z_base = mystique->dwgreg.ydstorg * ((mystique->maccess & MACCESS_ZWIDTH) ? 4 : 2) + mystique->dwgreg.zorg;
+            break;
+
+        case REG_MCTLWTST:
+        case REG_MCTLWTST + 1:
+        case REG_MCTLWTST + 2:
+        case REG_MCTLWTST + 3:
+            WRITE8(addr, mystique->mctlwtst, val);
+            break;
+
+        case REG_PAT0:
+        case REG_PAT0 + 1:
+        case REG_PAT0 + 2:
+        case REG_PAT0 + 3:
+        case REG_PAT1:
+        case REG_PAT1 + 1:
+        case REG_PAT1 + 2:
+        case REG_PAT1 + 3:
+            for (uint8_t x = 0; x < 8; x++)
+                mystique->dwgreg.pattern[addr & 7][x] = mystique->dwgreg.pattern[addr & 7][x + 8] = val & (1 << (7 - x));
+            break;
+
+        case REG_XYSTRT:
+        case REG_XYSTRT + 1:
+            WRITE8(addr & 1, mystique->dwgreg.ar[5], val);
+            if (mystique->dwgreg.ar[5] & 0x8000)
+                mystique->dwgreg.ar[5] |= 0xffff8000;
+            else
+                mystique->dwgreg.ar[5] &= ~0xffff8000;
+            WRITE8(addr & 1, mystique->dwgreg.xdst, val);
+            break;
+        case REG_XYSTRT + 2:
+        case REG_XYSTRT + 3:
+            WRITE8(addr & 1, mystique->dwgreg.ar[6], val);
+            if (mystique->dwgreg.ar[6] & 0x8000)
+                mystique->dwgreg.ar[6] |= 0xffff8000;
+            else
+                mystique->dwgreg.ar[6] &= ~0xffff8000;
+            WRITE8(addr & 1, mystique->dwgreg.ydst, val);
+            mystique->dwgreg.ydst_lin = ((int32_t) (int16_t) mystique->dwgreg.ydst * (mystique->dwgreg.pitch & PITCH_MASK)) + mystique->dwgreg.ydstorg;
+            break;
+
+        case REG_XYEND:
+        case REG_XYEND + 1:
+            WRITE8(addr & 1, mystique->dwgreg.ar[0], val);
+            if (mystique->dwgreg.ar[0] & 0x8000)
+                mystique->dwgreg.ar[0] |= 0xffff8000;
+            else
+                mystique->dwgreg.ar[0] &= ~0xffff8000;
+            break;
+        case REG_XYEND + 2:
+        case REG_XYEND + 3:
+            WRITE8(addr & 1, mystique->dwgreg.ar[2], val);
+            if (mystique->dwgreg.ar[2] & 0x8000)
+                mystique->dwgreg.ar[2] |= 0xffff8000;
+            else
+                mystique->dwgreg.ar[2] &= ~0xffff8000;
+            break;
+
+        case REG_SGN:
+            mystique->dwgreg.sgn.sdydxl   = val & SGN_SDYDXL;
+            mystique->dwgreg.sgn.scanleft = val & SGN_SCANLEFT;
+            mystique->dwgreg.sgn.sdxl     = val & SGN_SDXL;
+            mystique->dwgreg.sgn.sdy      = val & SGN_SDY;
+            mystique->dwgreg.sgn.sdxr     = val & SGN_SDXR;
+            break;
+        case REG_SGN + 1:
+        case REG_SGN + 2:
+        case REG_SGN + 3:
+            break;
+
+        case REG_LEN:
+        case REG_LEN + 1:
+            WRITE8(addr, mystique->dwgreg.length, val);
+            break;
+        case REG_LEN + 2:
+            break;
+        case REG_LEN + 3:
+            mystique->dwgreg.beta = val >> 4;
+            if (!mystique->dwgreg.beta)
+                mystique->dwgreg.beta = 16;
+            break;
+
+        case REG_CXBNDRY:
+        case REG_CXBNDRY + 1:
+            WRITE8(addr, mystique->dwgreg.cxleft, val);
+            break;
+        case REG_CXBNDRY + 2:
+        case REG_CXBNDRY + 3:
+            WRITE8(addr & 1, mystique->dwgreg.cxright, val);
+            break;
+        case REG_FXBNDRY:
+        case REG_FXBNDRY + 1:
+            WRITE8(addr, mystique->dwgreg.fxleft, val);
+            break;
+        case REG_FXBNDRY + 2:
+        case REG_FXBNDRY + 3:
+            WRITE8(addr & 1, mystique->dwgreg.fxright, val);
+            break;
+
+        case REG_YDSTLEN:
+        case REG_YDSTLEN + 1:
+            WRITE8(addr, mystique->dwgreg.length, val);
+#if 0
+            pclog("Write YDSTLEN+%i %i\n", addr&1, mystique->dwgreg.length);
+#endif
+            break;
+        case REG_YDSTLEN + 2:
+            mystique->dwgreg.ydst = (mystique->dwgreg.ydst & ~0xff) | val;
+            if (mystique->dwgreg.pitch & PITCH_YLIN)
+                mystique->dwgreg.ydst_lin = (mystique->dwgreg.ydst << 5) + mystique->dwgreg.ydstorg;
+            else {
+                mystique->dwgreg.ydst_lin = ((int32_t) (int16_t) mystique->dwgreg.ydst * (mystique->dwgreg.pitch & PITCH_MASK)) + mystique->dwgreg.ydstorg;
+                mystique->dwgreg.selline  = val & 7;
+            }
+            break;
+        case REG_YDSTLEN + 3:
+            mystique->dwgreg.ydst = (mystique->dwgreg.ydst & 0xff) | (((int32_t) (int8_t) val) << 8);
+            if (mystique->dwgreg.pitch & PITCH_YLIN)
+                mystique->dwgreg.ydst_lin = (mystique->dwgreg.ydst << 5) + mystique->dwgreg.ydstorg;
+            else
+                mystique->dwgreg.ydst_lin = ((int32_t) (int16_t) mystique->dwgreg.ydst * (mystique->dwgreg.pitch & PITCH_MASK)) + mystique->dwgreg.ydstorg;
+            break;
+
+        case REG_XDST:
+        case REG_XDST + 1:
+            WRITE8(addr & 1, mystique->dwgreg.xdst, val);
+            break;
+        case REG_XDST + 2:
+        case REG_XDST + 3:
+            break;
+
+        case REG_YDSTORG:
+        case REG_YDSTORG + 1:
+        case REG_YDSTORG + 2:
+        case REG_YDSTORG + 3:
+            WRITE8(addr, mystique->dwgreg.ydstorg, val);
+            mystique->dwgreg.z_base = mystique->dwgreg.ydstorg * ((mystique->maccess & MACCESS_ZWIDTH) ? 4 : 2) + mystique->dwgreg.zorg;
+            break;
+        case REG_YTOP:
+        case REG_YTOP + 1:
+        case REG_YTOP + 2:
+        case REG_YTOP + 3:
+            WRITE8(addr, mystique->dwgreg.ytop, val);
+            break;
+        case REG_YBOT:
+        case REG_YBOT + 1:
+        case REG_YBOT + 2:
+        case REG_YBOT + 3:
+            WRITE8(addr, mystique->dwgreg.ybot, val);
+            break;
+
+        case REG_CXLEFT:
+        case REG_CXLEFT + 1:
+            WRITE8(addr, mystique->dwgreg.cxleft, val);
+            break;
+        case REG_CXLEFT + 2:
+        case REG_CXLEFT + 3:
+            break;
+        case REG_CXRIGHT:
+        case REG_CXRIGHT + 1:
+            WRITE8(addr, mystique->dwgreg.cxright, val);
+            break;
+        case REG_CXRIGHT + 2:
+        case REG_CXRIGHT + 3:
+            break;
+
+        case REG_FXLEFT:
+        case REG_FXLEFT + 1:
+            WRITE8(addr, mystique->dwgreg.fxleft, val);
+            break;
+        case REG_FXLEFT + 2:
+        case REG_FXLEFT + 3:
+            break;
+        case REG_FXRIGHT:
+        case REG_FXRIGHT + 1:
+            WRITE8(addr, mystique->dwgreg.fxright, val);
+            break;
+        case REG_FXRIGHT + 2:
+        case REG_FXRIGHT + 3:
+            break;
+
+        case REG_SECADDRESS:
+        case REG_SECADDRESS + 1:
+        case REG_SECADDRESS + 2:
+        case REG_SECADDRESS + 3:
+            WRITE8(addr, mystique->dma.secaddress, val);
+            mystique->dma.sec_state = 0;
+            break;
+
+        case REG_TMR0:
+        case REG_TMR0 + 1:
+        case REG_TMR0 + 2:
+        case REG_TMR0 + 3:
+            WRITE8(addr, mystique->dwgreg.tmr[0], val);
+            break;
+        case REG_TMR1:
+        case REG_TMR1 + 1:
+        case REG_TMR1 + 2:
+        case REG_TMR1 + 3:
+            WRITE8(addr, mystique->dwgreg.tmr[1], val);
+            break;
+        case REG_TMR2:
+        case REG_TMR2 + 1:
+        case REG_TMR2 + 2:
+        case REG_TMR2 + 3:
+            WRITE8(addr, mystique->dwgreg.tmr[2], val);
+            break;
+        case REG_TMR3:
+        case REG_TMR3 + 1:
+        case REG_TMR3 + 2:
+        case REG_TMR3 + 3:
+            WRITE8(addr, mystique->dwgreg.tmr[3], val);
+            break;
+        case REG_TMR4:
+        case REG_TMR4 + 1:
+        case REG_TMR4 + 2:
+        case REG_TMR4 + 3:
+            WRITE8(addr, mystique->dwgreg.tmr[4], val);
+            break;
+        case REG_TMR5:
+        case REG_TMR5 + 1:
+        case REG_TMR5 + 2:
+        case REG_TMR5 + 3:
+            WRITE8(addr, mystique->dwgreg.tmr[5], val);
+            break;
+        case REG_TMR6:
+        case REG_TMR6 + 1:
+        case REG_TMR6 + 2:
+        case REG_TMR6 + 3:
+            WRITE8(addr, mystique->dwgreg.tmr[6], val);
+            break;
+        case REG_TMR7:
+        case REG_TMR7 + 1:
+        case REG_TMR7 + 2:
+        case REG_TMR7 + 3:
+            WRITE8(addr, mystique->dwgreg.tmr[7], val);
+            break;
+        case REG_TMR8:
+        case REG_TMR8 + 1:
+        case REG_TMR8 + 2:
+        case REG_TMR8 + 3:
+            WRITE8(addr, mystique->dwgreg.tmr[8], val);
+            break;
+
+        case REG_TEXORG:
+        case REG_TEXORG + 1:
+        case REG_TEXORG + 2:
+        case REG_TEXORG + 3:
+            WRITE8(addr, mystique->dwgreg.texorg, val);
+            break;
+        case REG_TEXWIDTH:
+        case REG_TEXWIDTH + 1:
+        case REG_TEXWIDTH + 2:
+        case REG_TEXWIDTH + 3:
+            WRITE8(addr, mystique->dwgreg.texwidth, val);
+            break;
+        case REG_TEXHEIGHT:
+        case REG_TEXHEIGHT + 1:
+        case REG_TEXHEIGHT + 2:
+        case REG_TEXHEIGHT + 3:
+            WRITE8(addr, mystique->dwgreg.texheight, val);
+            break;
+        case REG_TEXCTL:
+        case REG_TEXCTL + 1:
+        case REG_TEXCTL + 2:
+        case REG_TEXCTL + 3:
+            WRITE8(addr, mystique->dwgreg.texctl, val);
+            mystique->dwgreg.ta_key  = (mystique->dwgreg.texctl & TEXCTL_TAKEY) ? 1 : 0;
+            mystique->dwgreg.ta_mask = (mystique->dwgreg.texctl & TEXCTL_TAMASK) ? 1 : 0;
+            break;
+        case REG_TEXTRANS:
+        case REG_TEXTRANS + 1:
+        case REG_TEXTRANS + 2:
+        case REG_TEXTRANS + 3:
+            WRITE8(addr, mystique->dwgreg.textrans, val);
+            break;
+
+        case 0x1c18:
+        case 0x1c19:
+        case 0x1c1a:
+        case 0x1c1b:
+        case 0x1c28:
+        case 0x1c29:
+        case 0x1c2a:
+        case 0x1c2b:
+        case 0x1c2c:
+        case 0x1c2d:
+        case 0x1c2e:
+        case 0x1c2f:
+        case 0x1cc4:
+        case 0x1cc5:
+        case 0x1cc6:
+        case 0x1cc7:
+        case 0x1cd4:
+        case 0x1cd5:
+        case 0x1cd6:
+        case 0x1cd7:
+        case 0x1ce4:
+        case 0x1ce5:
+        case 0x1ce6:
+        case 0x1ce7:
+        case 0x1cf4:
+        case 0x1cf5:
+        case 0x1cf6:
+        case 0x1cf7:
+            break;
+
+        case REG_OPMODE:
+            mystique->dwgreg.dmamod   = (val >> 2) & 3;
+            mystique->dma.iload_state = 0;
+            break;
+
+        default:
+            if ((addr & 0x3fff) >= 0x2c4c && (addr & 0x3fff) <= 0x2cff)
+                break;
+            break;
+    }
+
+    if (start_blit)
+        mystique_start_blit(mystique);
+}
+
+static void
+mystique_ctrl_write_bx(uint32_t addr, uint8_t val, void *priv)
+{
+    mystique_t *mystique  = (mystique_t *) priv;
+    svga_t     *svga      = &mystique->svga;
+    uint8_t     addr_0x0f = 0;
+    uint16_t    addr_0x03 = 0;
+    int         rs2 = 0;
+    int         rs3 = 0;
+
+    if ((mystique->type == MGA_2064W || mystique->type == MGA_2164W) && (addr & 0x3e00) == 0x3c00) {
+        /*RAMDAC*/
+        addr_0x0f = addr & 0x0f;
+
+        if ((addr & 3) == 0)
+            addr_0x03 = 0x3c8;
+        else if ((addr & 3) == 1)
+            addr_0x03 = 0x3c9;
+        else if ((addr & 3) == 2)
+            addr_0x03 = 0x3c6;
+        else if ((addr & 3) == 3)
+            addr_0x03 = 0x3c7;
+
+        if ((addr_0x0f >= 0x04) && (addr_0x0f <= 0x07)) {
+            rs2 = 1;
+            rs3 = 0;
+        } else if ((addr_0x0f >= 0x08) && (addr_0x0f <= 0x0b)) {
+            rs2 = 0;
+            rs3 = 1;
+        } else if ((addr_0x0f >= 0x0c) && (addr_0x0f <= 0x0f)) {
+            rs2 = 1;
+            rs3 = 1;
+        }
+
+        tvp3026_ramdac_out(addr_0x03, rs2, rs3, val, svga->ramdac, svga);
+        return;
+    }
+
+    if ((addr & 0x3fff) < 0x1c00) {
+        mystique_iload_write_b(addr, val, priv);
+        return;
+    }
+    if ((addr & 0x3e00) == 0x1c00 || (addr & 0x3e00) == 0x2c00) {
+        if ((addr & 0x300) == 0x100)
+            mystique->blitter_submit_refcount++;
+        mystique_queue(mystique, addr & 0x3fff, val, FIFO_WRITE_CTRL_BYTE);
+        return;
+    }
+
+    switch (addr & 0x3fff) {
+        case REG_ICLEAR:
+            if (val & ICLEAR_SOFTRAPICLR) {
+                //pclog("softrapiclr\n");
+                mystique->status &= ~STATUS_SOFTRAPEN;
+                mystique_update_irqs(mystique);
+            }
+            if (val & ICLEAR_VLINEICLR) {
+                mystique->status &= ~STATUS_VLINEPEN;
+                mystique_update_irqs(mystique);
+            }
+            break;
+        case REG_ICLEAR + 1:
+        case REG_ICLEAR + 2:
+        case REG_ICLEAR + 3:
+            break;
+
+        case REG_IEN:
+            mystique->ien = val & 0x65;
+            break;
+        case REG_IEN + 1:
+        case REG_IEN + 2:
+        case REG_IEN + 3:
+            break;
+
+        case REG_OPMODE:
+            thread_wait_mutex(mystique->dma.lock);
+            mystique->dma.state = DMA_STATE_IDLE; /* Interrupt DMA. */
+            thread_release_mutex(mystique->dma.lock);
+            mystique->dmamod = (val >> 2) & 3;
+            mystique_queue(mystique, addr & 0x3fff, val, FIFO_WRITE_CTRL_BYTE);
+            break;
+        case REG_OPMODE + 1:
+            mystique->dmadatasiz = val & 3;
+            break;
+        case REG_OPMODE + 2:
+            mystique->dirdatasiz = val & 3;
+            extern void gfxboard_matrox_lfb_endianswap(int);
+            gfxboard_matrox_lfb_endianswap(val & 3);
+            break;
+        case REG_OPMODE + 3:
+            break;
+
+        case REG_PRIMADDRESS:
+        case REG_PRIMADDRESS + 1:
+        case REG_PRIMADDRESS + 2:
+        case REG_PRIMADDRESS + 3:
+            thread_wait_mutex(mystique->dma.lock);
+            WRITE8(addr, mystique->dma.primaddress, val);
+            mystique->dma.pri_state = 0;
+            if (mystique->dma.state == DMA_STATE_IDLE && !(mystique->softrap_pending || mystique->endprdmasts_pending || !mystique->softrap_status_read)) {
+                mystique->dma.words_expected = 0;
+            }
+            mystique->dma.state = DMA_STATE_IDLE;
+            thread_release_mutex(mystique->dma.lock);
+            break;
+
+        case REG_DMAMAP:
+        case REG_DMAMAP + 0x1:
+        case REG_DMAMAP + 0x2:
+        case REG_DMAMAP + 0x3:
+        case REG_DMAMAP + 0x4:
+        case REG_DMAMAP + 0x5:
+        case REG_DMAMAP + 0x6:
+        case REG_DMAMAP + 0x7:
+        case REG_DMAMAP + 0x8:
+        case REG_DMAMAP + 0x9:
+        case REG_DMAMAP + 0xa:
+        case REG_DMAMAP + 0xb:
+        case REG_DMAMAP + 0xc:
+        case REG_DMAMAP + 0xd:
+        case REG_DMAMAP + 0xe:
+        case REG_DMAMAP + 0xf:
+            mystique->dmamap[addr & 0xf] = val;
+            break;
+
+        case REG_RST:
+        case REG_RST + 1:
+        case REG_RST + 2:
+        case REG_RST + 3:
+            wait_fifo_idle(mystique);
+            mystique->busy                        = 0;
+            mystique->blitter_submit_refcount     = 0;
+            mystique->blitter_submit_dma_refcount = 0;
+            mystique->blitter_complete_refcount   = 0;
+            mystique->dwgreg.iload_rem_count      = 0;
+            mystique->status                      = STATUS_ENDPRDMASTS;
+            thread_wait_mutex(mystique->dma.lock);
+            mystique->dma.pri_state               = 0;
+            mystique->dma.sec_state               = 0;
+            mystique->dma.state                   = DMA_STATE_IDLE;
+            mystique->dma.words_expected          = 0;
+            thread_release_mutex(mystique->dma.lock);
+            break;
+
+        case REG_ATTR_IDX:
+            svga_out(0x3c0, val, svga);
+            break;
+        case REG_ATTR_DATA:
+            svga_out(0x3c1, val, svga);
+            break;
+
+        case REG_MISC:
+            svga_out(0x3c2, val, svga);
+            break;
+
+        case REG_SEQ_IDX:
+            svga_out(0x3c4, val, svga);
+            break;
+        case REG_SEQ_DATA:
+            svga_out(0x3c5, val, svga);
+            break;
+
+        case REG_GCTL_IDX:
+            mystique_out(0x3ce, val, mystique);
+            break;
+        case REG_GCTL_DATA:
+            mystique_out(0x3cf, val, mystique);
+            break;
+
+        case REG_CRTC_IDX:
+            mystique_out(0x3d4, val, mystique);
+            break;
+        case REG_CRTC_DATA:
+            mystique_out(0x3d5, val, mystique);
+            break;
+
+        case REG_CRTCEXT_IDX:
+            mystique_out(0x3de, val, mystique);
+            break;
+        case REG_CRTCEXT_DATA:
+            mystique_out(0x3df, val, mystique);
+            break;
+
+        case REG_CACHEFLUSH:
+            break;
+
+        case REG_PALWTADD:
+            svga_out(0x3c8, val, svga);
+            mystique->xreg_idx = val;
+            break;
+        case REG_PALDATA:
+            svga_out(0x3c9, val, svga);
+            break;
+        case REG_PIXRDMSK:
+            svga_out(0x3c6, val, svga);
+            break;
+        case REG_PALRDADD:
+            svga_out(0x3c7, val, svga);
+            mystique->xreg_idx = val;
+            break;
+
+        case REG_X_DATAREG:
+            mystique_write_xreg(mystique, mystique->xreg_idx, val);
+            break;
+
+        case REG_CURPOSX:
+        case REG_CURPOSX + 1:
+            WRITE8(addr, mystique->cursor.pos_x, val);
+            svga->hwcursor.x = mystique->cursor.pos_x - 64;
+            break;
+        case REG_CURPOSY:
+        case REG_CURPOSY + 1:
+            WRITE8(addr & 1, mystique->cursor.pos_y, val);
+            svga->hwcursor.y = mystique->cursor.pos_y - 64;
+            break;
+
+        case 0x1e50:
+        case 0x1e51:
+        case 0x1e52:
+        case 0x1e53:
+        case 0x3c0b:
+        case 0x3e02:
+        case 0x3e08:
+            break;
+
+        default:
+            if ((addr & 0x3fff) >= 0x2c4c && (addr & 0x3fff) <= 0x2cff)
+                break;
+            if ((addr & 0x3fff) >= 0x3e00)
+                break;
+            break;
+    }
+}
+
+static void
+mystique_ctrl_write_b(uint32_t addr, uint8_t val, void *priv)
+{
+    mystique_t *mystique = (mystique_t *)priv;
+
+    if (powerpc(mystique, addr)) {
+        addr ^= 3;
+    }
+
+    //pclog("B %08x %02x\n", addr, val);
+
+    mystique_ctrl_write_bx(addr, val, priv);
+}
+
+static uint16_t
+mystique_ctrl_read_w(uint32_t addr, void *priv)
+{
+    mystique_t *mystique = (mystique_t *)priv;
+    uint32_t ret;
+
+    if (powerpc(mystique, addr)) {
+        addr ^= 2;
+    }
+
+    ret = mystique_ctrl_read_bx(addr, priv);
+    ret |= mystique_ctrl_read_bx(addr + 1, priv) << 8;
+
+    return ret;
+}
+
+
+static uint32_t
+mystique_ctrl_read_l(uint32_t addr, void *priv)
+{
+    mystique_t *mystique = (mystique_t *)priv;
+    uint32_t ret;
+
+    if ((addr & 0x3fff) < 0x1c00)
+        return mystique_iload_read_l(addr, priv);
+
+    ret = mystique_ctrl_read_bx(addr, priv);
+    ret |= mystique_ctrl_read_bx(addr + 1, priv) << 8;
+    ret |= mystique_ctrl_read_bx(addr + 2, priv) << 16;
+    ret |= mystique_ctrl_read_bx(addr + 3, priv) << 24;
+
+    if (powerpc(mystique, addr)) {
+        ret = _byteswap_ulong(ret);
+    }
+
+    return ret;
+}
+
+static void
+mystique_accel_ctrl_write_l(uint32_t addr, uint32_t val, void *priv)
+{
+    mystique_t *mystique   = (mystique_t *) priv;
+    int         start_blit = 0;
+
+    //pclog("L %08x %08x\n", addr, val);
+
+    if ((addr & 0x300) == 0x100) {
+        addr &= ~0x100;
+        start_blit = 1;
+    }
+
+    switch (addr & 0x3ffc) {
+        case REG_DWGCTL:
+            mystique->dwgreg.dwgctrl = val;
+
+            if (val & DWGCTRL_SOLID) {
+                for (uint8_t y = 0; y < 8; y++) {
+                    for (uint8_t x = 0; x < 16; x++)
+                        mystique->dwgreg.pattern[y][x] = 1;
+                }
+                mystique->dwgreg.src[0] = 0xffffffff;
+                mystique->dwgreg.src[1] = 0xffffffff;
+                mystique->dwgreg.src[2] = 0xffffffff;
+                mystique->dwgreg.src[3] = 0xffffffff;
+            }
+            if (val & DWGCTRL_ARZERO) {
+                mystique->dwgreg.ar[0] = 0;
+                mystique->dwgreg.ar[1] = 0;
+                mystique->dwgreg.ar[2] = 0;
+                mystique->dwgreg.ar[4] = 0;
+                mystique->dwgreg.ar[5] = 0;
+                mystique->dwgreg.ar[6] = 0;
+            }
+            if (val & DWGCTRL_SGNZERO) {
+                mystique->dwgreg.sgn.sdydxl   = 0;
+                mystique->dwgreg.sgn.scanleft = 0;
+                mystique->dwgreg.sgn.sdxl     = 0;
+                mystique->dwgreg.sgn.sdy      = 0;
+                mystique->dwgreg.sgn.sdxr     = 0;
+            }
+            if (val & DWGCTRL_SHTZERO) {
+                mystique->dwgreg.funcnt   = 0;
+                mystique->dwgreg.stylelen = 0;
+                mystique->dwgreg.xoff     = 0;
+                mystique->dwgreg.yoff     = 0;
+            }
+            break;
+
+        case REG_ZORG:
+            mystique->dwgreg.zorg   = val;
+            mystique->dwgreg.z_base = mystique->dwgreg.ydstorg * ((mystique->maccess & MACCESS_ZWIDTH) ? 4 : 2) + mystique->dwgreg.zorg;
+            break;
+
+        case REG_PLNWT:
+            mystique->dwgreg.plnwt = val;
+            break;
+
+        case REG_SHIFT:
+            mystique->dwgreg.funcnt   = val & 0x7f;
+            mystique->dwgreg.xoff     = val & 7;
+            mystique->dwgreg.yoff     = (val >> 4) & 7;
+            mystique->dwgreg.stylelen = (val >> 16) & 0x7f;
+            break;
+
+        case REG_PITCH:
+            mystique->dwgreg.pitch = val & 0xffff;
+            if (mystique->dwgreg.pitch & PITCH_YLIN)
+                mystique->dwgreg.ydst_lin = (mystique->dwgreg.ydst << 5) + mystique->dwgreg.ydstorg;
+            else
+                mystique->dwgreg.ydst_lin = ((int32_t) (int16_t) mystique->dwgreg.ydst * (mystique->dwgreg.pitch & PITCH_MASK)) + mystique->dwgreg.ydstorg;
+            break;
+
+        case REG_YDST:
+            mystique->dwgreg.ydst = val & 0x3fffff;
+            if (mystique->dwgreg.pitch & PITCH_YLIN) {
+                mystique->dwgreg.ydst_lin = (mystique->dwgreg.ydst << 5) + mystique->dwgreg.ydstorg;
+                mystique->dwgreg.selline  = val >> 29;
+            } else {
+                mystique->dwgreg.ydst_lin = ((int32_t) (int16_t) mystique->dwgreg.ydst * (mystique->dwgreg.pitch & PITCH_MASK)) + mystique->dwgreg.ydstorg;
+                mystique->dwgreg.selline  = val & 7;
+            }
+            break;
+        case REG_BCOL:
+            mystique->dwgreg.bcol = val;
+            break;
+        case REG_FCOL:
+            mystique->dwgreg.fcol = val;
+            break;
+
+        case REG_SRC0:
+            {
+                mystique->dwgreg.src[0] = val;
+                for (uint8_t y = 0; y < 2; y++) {
+                    for (uint8_t x = 0; x < 16; x++) {
+                        mystique->dwgreg.pattern[y][x] = val & (1 << (x + (y * 16)));
+                    }
+                }
+#if 0
+                pclog("SRC0 = 0x%08X\n", val);
+#endif
+                if (mystique->busy && (mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) == DWGCTRL_OPCODE_ILOAD)
+                    blit_iload_write(mystique, mystique->dwgreg.src[0], 32);
+            }
+            break;
+        case REG_SRC1:
+            {
+                mystique->dwgreg.src[1] = val;
+                for (uint8_t y = 2; y < 4; y++) {
+                    for (uint8_t x = 0; x < 16; x++) {
+                        mystique->dwgreg.pattern[y][x] = val & (1 << (x + ((y - 2) * 16)));
+                    }
+                }
+#if 0
+                pclog("SRC1 = 0x%08X\n", val);
+#endif
+                if (mystique->busy && (mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) == DWGCTRL_OPCODE_ILOAD)
+                    blit_iload_write(mystique, mystique->dwgreg.src[1], 32);
+            }
+            break;
+        case REG_SRC2:
+            {
+                mystique->dwgreg.src[2] = val;
+                for (uint8_t y = 4; y < 6; y++) {
+                    for (uint8_t x = 0; x < 16; x++) {
+                        mystique->dwgreg.pattern[y][x] = val & (1 << (x + ((y - 4) * 16)));
+                    }
+                }
+#if 0
+                pclog("SRC2 = 0x%08X\n", val);
+#endif
+                if (mystique->busy && (mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) == DWGCTRL_OPCODE_ILOAD)
+                    blit_iload_write(mystique, mystique->dwgreg.src[2], 32);
+                break;
+            }
+        case REG_SRC3:
+            {
+                mystique->dwgreg.src[3] = val;
+                for (uint8_t y = 6; y < 8; y++) {
+                    for (uint8_t x = 0; x < 16; x++) {
+                        mystique->dwgreg.pattern[y][x] = val & (1 << (x + ((y - 6) * 16)));
+                    }
+                }
+#if 0
+                pclog("SRC3 = 0x%08X\n", val);
+#endif
+                if (mystique->busy && (mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) == DWGCTRL_OPCODE_ILOAD)
+                    blit_iload_write(mystique, mystique->dwgreg.src[3], 32);
+                break;
+            }
+
+        case REG_DMAPAD:
+            if (mystique->busy && (mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) == DWGCTRL_OPCODE_ILOAD)
+                blit_iload_write(mystique, val, 32);
+            break;
+
+        case REG_AR0:
+            mystique->dwgreg.ar[0] = val;
+            break;
+        case REG_AR1:
+            mystique->dwgreg.ar[1] = val;
+            break;
+        case REG_AR2:
+            mystique->dwgreg.ar[2] = val;
+            break;
+        case REG_AR3:
+            mystique->dwgreg.ar[3] = val;
+            break;
+        case REG_AR4:
+            mystique->dwgreg.ar[4] = val;
+            break;
+        case REG_AR5:
+            mystique->dwgreg.ar[5] = val;
+            break;
+        case REG_AR6:
+            mystique->dwgreg.ar[6] = val;
+            break;
+
+        case REG_DR0_Z32LSB:
+            mystique->dwgreg.extended_dr[0] = (mystique->dwgreg.extended_dr[0] & ~0xFFFFFFFF) | val;
+            mystique->dwgreg.dr[0] = (mystique->dwgreg.extended_dr[0] >> 16) & 0xFFFFFFFF;
+            break;
+
+        case REG_DR0_Z32MSB:
+            mystique->dwgreg.extended_dr[0] = (mystique->dwgreg.extended_dr[0] & 0xFFFFFFFF) | ((val & 0xFFFFull) << 32ull);
+            mystique->dwgreg.dr[0] = (mystique->dwgreg.extended_dr[0] >> 16) & 0xFFFFFFFF;
+            break;
+
+        case REG_DR2_Z32LSB:
+            mystique->dwgreg.extended_dr[2] = (mystique->dwgreg.extended_dr[2] & ~0xFFFFFFFF) | val;
+            mystique->dwgreg.dr[2] = (mystique->dwgreg.extended_dr[2] >> 16) & 0xFFFFFFFF;
+            break;
+
+        case REG_DR2_Z32MSB:
+            mystique->dwgreg.extended_dr[2] = (mystique->dwgreg.extended_dr[2] & 0xFFFFFFFF) | ((val & 0xFFFFull) << 32ull);
+            mystique->dwgreg.dr[2] = (mystique->dwgreg.extended_dr[2] >> 16) & 0xFFFFFFFF;
+            break;
+
+        case REG_DR3_Z32LSB:
+            mystique->dwgreg.extended_dr[3] = (mystique->dwgreg.extended_dr[3] & ~0xFFFFFFFF) | val;
+            mystique->dwgreg.dr[3] = (mystique->dwgreg.extended_dr[3] >> 16) & 0xFFFFFFFF;
+            break;
+
+        case REG_DR3_Z32MSB:
+            mystique->dwgreg.extended_dr[3] = (mystique->dwgreg.extended_dr[3] & 0xFFFFFFFF) | ((val & 0xFFFFull) << 32ull);
+            mystique->dwgreg.dr[3] = (mystique->dwgreg.extended_dr[3] >> 16) & 0xFFFFFFFF;
+            break;
+
+        case REG_DR0:
+            mystique->dwgreg.dr[0] = val;
+            mystique->dwgreg.extended_dr[0] = (mystique->dwgreg.extended_dr[0] & ~0xFFFFull) | ((uint64_t)val << 16ull);
+            break;
+        case REG_DR2:
+            mystique->dwgreg.dr[2] = val;
+            mystique->dwgreg.extended_dr[2] = (mystique->dwgreg.extended_dr[2] & ~0xFFFFull) | ((uint64_t)val << 16ull);
+            break;
+        case REG_DR3:
+            mystique->dwgreg.dr[3] = val;
+            mystique->dwgreg.extended_dr[3] = (mystique->dwgreg.extended_dr[3] & ~0xFFFFull) | ((uint64_t)val << 16ull);
+            break;
+        case REG_DR4:
+            mystique->dwgreg.dr[4] = val;
+            break;
+        case REG_DR6:
+            mystique->dwgreg.dr[6] = val;
+            break;
+        case REG_DR7:
+            mystique->dwgreg.dr[7] = val;
+            break;
+        case REG_DR8:
+            mystique->dwgreg.dr[8] = val;
+            break;
+        case REG_DR10:
+            mystique->dwgreg.dr[10] = val;
+            break;
+        case REG_DR11:
+            mystique->dwgreg.dr[11] = val;
+            break;
+        case REG_DR12:
+            mystique->dwgreg.dr[12] = val;
+            break;
+        case REG_DR14:
+            mystique->dwgreg.dr[14] = val;
+            break;
+        case REG_DR15:
+            mystique->dwgreg.dr[15] = val;
+            break;
+
+        case REG_SECEND:
+            mystique->dma.secend = val;
+            if (mystique->dma.state != DMA_STATE_SEC && (mystique->dma.secaddress & DMA_ADDR_MASK) != (mystique->dma.secend & DMA_ADDR_MASK))
+                mystique->dma.state = DMA_STATE_SEC;
+            break;
+
+        case REG_SOFTRAP:
+            mystique->dma.state           = DMA_STATE_IDLE;
+            mystique->dma.pri_state       = 0;
+            mystique->dma.words_expected  = 0;
+            mystique->endprdmasts_pending = 1;
+            mystique->softrap_pending_val = val;
+            mystique->softrap_pending     += 1;
+            break;
+
+        case REG_ALPHACTRL:
+            mystique->dwgreg.alphactrl = val;
+            break;
+
+        case REG_ALPHASTART:
+            mystique->dwgreg.alphastart = val;
+            break;
+
+        case REG_ALPHAXINC:
+            mystique->dwgreg.alphaxinc = val;
+            break;
+
+        case REG_ALPHAYINC:
+            mystique->dwgreg.alphayinc = val;
+            break;
+
+        case REG_FOGCOL:
+            mystique->dwgreg.fogcol = val;
+            break;
+
+        case REG_FOGSTART:
+            mystique->dwgreg.fogstart = val;
+            break;
+
+        case REG_FOGXINC:
+            mystique->dwgreg.fogxinc = val;
+            break;
+
+        case REG_FOGYINC:
+            mystique->dwgreg.fogyinc = val;
+            break;
+
+        case REG_TEXFILTER:
+            mystique->dwgreg.texfilter = val;
+            break;
+
+        default:
+            mystique_accel_ctrl_write_b(addr, val & 0xff, priv);
+            mystique_accel_ctrl_write_b(addr + 1, (val >> 8) & 0xff, priv);
+            mystique_accel_ctrl_write_b(addr + 2, (val >> 16) & 0xff, priv);
+            mystique_accel_ctrl_write_b(addr + 3, (val >> 24) & 0xff, priv);
+            break;
+    }
+
+    if (start_blit)
+        mystique_start_blit(mystique);
+}
+
+static void
+mystique_ctrl_write_l(uint32_t addr, uint32_t val, void *priv)
+{
+    mystique_t *mystique = (mystique_t *) priv;
+    uint32_t    reg_addr;
+
+    if ((addr & 0x3fff) < 0x1c00) {
+        mystique_iload_write_l(addr, val, priv);
+        return;
+    }
+
+    if (powerpc(mystique, addr)) {
+        val = _byteswap_ulong(val);
+    }
+
+    //pclog("L %08x %04x\n", addr, val);
+
+    if ((addr & 0x3e00) == 0x1c00 || (addr & 0x3e00) == 0x2c00) {
+        if ((addr & 0x300) == 0x100)
+            mystique->blitter_submit_refcount++;
+        mystique_queue(mystique, addr & 0x3fff, val, FIFO_WRITE_CTRL_LONG);
+        return;
+    }
+
+    switch (addr & 0x3ffc) {
+        case REG_PRIMEND:
+            thread_wait_mutex(mystique->dma.lock);
+            mystique->dma.primend = val;
+            //pclog("PRIMADDRESS = 0x%08X, PRIMEND = 0x%08X\n", mystique->dma.primaddress, mystique->dma.primend);
+            if (mystique->dma.state == DMA_STATE_IDLE && (mystique->dma.primaddress & DMA_ADDR_MASK) != (mystique->dma.primend & DMA_ADDR_MASK)) {
+                mystique->endprdmasts_pending = 0;
+                mystique->status &= ~STATUS_ENDPRDMASTS;
+
+                mystique->dma.state     = DMA_STATE_PRI;
+                //mystique->dma.pri_state = 0;
+                wake_fifo_thread(mystique);
+            }
+            /* HACK: For DirectX 9.0b Direct3D testing on Windows 98 SE.
+
+                The 4.12.013 drivers give an out-of-bounds busmastering range when dxdiag enumerates Direct3D, with exactly 16384 bytes of difference.
+                Don't attempt busmastering in such cases. This isn't ideal, but there are no more crashes faced in this case. */
+            if ((mystique->dma.primend & DMA_ADDR_MASK) < (mystique->dma.primaddress & DMA_ADDR_MASK) && ((mystique->dma.primaddress & DMA_ADDR_MASK) - (mystique->dma.primend & DMA_ADDR_MASK)) == 0x4000)
+            {
+                mystique->dma.primaddress = mystique->dma.primend;
+                mystique->endprdmasts_pending = 1;
+                mystique->dma.state = DMA_STATE_IDLE;
+            }
+            thread_release_mutex(mystique->dma.lock);
+            break;
+
+        case REG_DWG_INDIR_WT:
+        case REG_DWG_INDIR_WT + 0x04:
+        case REG_DWG_INDIR_WT + 0x08:
+        case REG_DWG_INDIR_WT + 0x0c:
+        case REG_DWG_INDIR_WT + 0x10:
+        case REG_DWG_INDIR_WT + 0x14:
+        case REG_DWG_INDIR_WT + 0x18:
+        case REG_DWG_INDIR_WT + 0x1c:
+        case REG_DWG_INDIR_WT + 0x20:
+        case REG_DWG_INDIR_WT + 0x24:
+        case REG_DWG_INDIR_WT + 0x28:
+        case REG_DWG_INDIR_WT + 0x2c:
+        case REG_DWG_INDIR_WT + 0x30:
+        case REG_DWG_INDIR_WT + 0x34:
+        case REG_DWG_INDIR_WT + 0x38:
+        case REG_DWG_INDIR_WT + 0x3c:
+            reg_addr = (mystique->dmamap[(addr >> 2) & 0xf] & 0x7f) << 2;
+            if (mystique->dmamap[(addr >> 2) & 0xf] & 0x80)
+                reg_addr += 0x2c00;
+            else
+                reg_addr += 0x1c00;
+
+            if ((reg_addr & 0x300) == 0x100)
+                mystique->blitter_submit_refcount++;
+
+            mystique_queue(mystique, reg_addr, val, FIFO_WRITE_CTRL_LONG);
+            break;
+
+        default:
+            mystique_ctrl_write_bx(addr, val & 0xff, priv);
+            mystique_ctrl_write_bx(addr + 1, (val >> 8) & 0xff, priv);
+            mystique_ctrl_write_bx(addr + 2, (val >> 16) & 0xff, priv);
+            mystique_ctrl_write_bx(addr + 3, (val >> 24) & 0xff, priv);
+            break;
+    }
+}
+
+static void
+mystique_ctrl_write_w(uint32_t addr, uint16_t val, void *priv)
+{
+    mystique_t *mystique = (mystique_t *)priv;
+    uint32_t    reg_addr;
+
+    if (powerpc(mystique, addr)) {
+        addr ^= 2;
+    }
+
+    //pclog("W %08x %04x\n", addr, val);
+
+    mystique_ctrl_write_bx(addr, val & 0xff, priv);
+    mystique_ctrl_write_bx(addr + 1, (val >> 8) & 0xff, priv);
+}
+
+
+static uint8_t
+mystique_iload_read_b(UNUSED(uint32_t addr), void *priv)
+{
+    mystique_t *mystique = (mystique_t *) priv;
+
+    wait_fifo_idle(mystique);
+
+    if (!mystique->busy)
+        return 0xff;
+
+    return blit_idump_read(mystique);
+}
+
+static uint32_t
+mystique_iload_read_l(UNUSED(uint32_t addr), void *priv)
+{
+    mystique_t *mystique = (mystique_t *) priv;
+
+    wait_fifo_idle(mystique);
+
+    if (!mystique->busy)
+        return 0xffffffff;
+
+    mystique->dwgreg.words++;
+    return blit_idump_read(mystique);
+}
+
+static void
+mystique_iload_write_b(UNUSED(uint32_t addr), UNUSED(uint8_t val), UNUSED(void *priv))
+{
+    //
+}
+
+static void
+mystique_iload_write_l(UNUSED(uint32_t addr), uint32_t val, void *priv)
+{
+    mystique_t *mystique = (mystique_t *) priv;
+
+    mystique_queue(mystique, 0, val, FIFO_WRITE_ILOAD_LONG);
+}
+
+static void
+mystique_accel_iload_write_l(UNUSED(uint32_t addr), uint32_t val, void *priv)
+{
+    mystique_t *mystique = (mystique_t *) priv;
+
+    switch (mystique->dwgreg.dmamod) {
+        case DMA_MODE_REG:
+            if (mystique->dma.iload_state == 0) {
+                mystique->dma.iload_header = val;
+                mystique->dma.iload_state  = 1;
+            } else {
+                uint32_t reg_addr = (mystique->dma.iload_header & 0x7f) << 2;
+                if (mystique->dma.iload_header & 0x80)
+                    reg_addr += 0x2c00;
+                else
+                    reg_addr += 0x1c00;
+
+                if ((reg_addr & 0x300) == 0x100)
+                    mystique->blitter_submit_dma_refcount++;
+                mystique_accel_ctrl_write_l(reg_addr, val, mystique);
+
+                mystique->dma.iload_header >>= 8;
+                mystique->dma.iload_state = (mystique->dma.iload_state == 4) ? 0 : (mystique->dma.iload_state + 1);
+            }
+            break;
+
+        case DMA_MODE_BLIT:
+            if (mystique->busy)
+                blit_iload_write(mystique, val, 32);
+            break;
+
+        default:
+#if 0
+            pclog("ILOAD write DMAMOD %i\n", mystique->dwgreg.dmamod); */
+#endif
+            break;
+    }
+}
+
+static uint8_t
+mystique_readb_linear(uint32_t addr, void *priv)
+{
+    const svga_t *svga = (svga_t *) priv;
+
+    cycles -= svga->monitor->mon_video_timing_read_b;
+
+    if (!svga->fast) {
+        if (svga->chain2_read) {
+            addr &= ~1;
+            addr <<= 2;
+        }
+    }
+
+    addr &= svga->decode_mask;
+    if (addr >= svga->vram_max)
+        return 0xff;
+
+    return svga->vram[addr & svga->vram_mask];
+}
+
+static uint16_t
+mystique_readw_linear(uint32_t addr, void *priv)
+{
+    svga_t *svga = (svga_t *) priv;
+
+    cycles -= svga->monitor->mon_video_timing_read_w;
+
+    addr &= svga->decode_mask;
+    if (addr >= svga->vram_max)
+        return 0xffff;
+
+    return *(uint16_t *) &svga->vram[addr & svga->vram_mask];
+}
+
+static uint32_t
+mystique_readl_linear(uint32_t addr, void *priv)
+{
+    svga_t *svga = (svga_t *) priv;
+
+    cycles -= svga->monitor->mon_video_timing_read_l;
+
+    addr &= svga->decode_mask;
+    if (addr >= svga->vram_max)
+        return 0xffffffff;
+
+    return *(uint32_t *) &svga->vram[addr & svga->vram_mask];
+}
+
+static void
+mystique_writeb_linear(uint32_t addr, uint8_t val, void *priv)
+{
+    svga_t *svga = (svga_t *) priv;
+
+    cycles -= svga->monitor->mon_video_timing_write_b;
+
+    if (!svga->fast) {
+        if (svga->chain2_write) {
+            addr &= ~1;
+            addr <<= 2;
+        }
+    }
+
+    addr &= svga->decode_mask;
+    if (addr >= svga->vram_max)
+        return;
+    addr &= svga->vram_mask;
+    svga->changedvram[addr >> 12] = svga->monitor->mon_changeframecount;
+    svga->vram[addr]              = val;
+}
+
+static void
+mystique_writew_linear(uint32_t addr, uint16_t val, void *priv)
+{
+    svga_t *svga = (svga_t *) priv;
+
+    cycles -= svga->monitor->mon_video_timing_write_w;
+
+    addr &= svga->decode_mask;
+    if (addr >= svga->vram_max)
+        return;
+    addr &= svga->vram_mask;
+    svga->changedvram[addr >> 12]   = svga->monitor->mon_changeframecount;
+    *(uint16_t *) &svga->vram[addr] = val;
+}
+
+static void
+mystique_writel_linear(uint32_t addr, uint32_t val, void *priv)
+{
+    svga_t *svga = (svga_t *) priv;
+
+    cycles -= svga->monitor->mon_video_timing_write_l;
+
+    addr &= svga->decode_mask;
+    if (addr >= svga->vram_max)
+        return;
+    addr &= svga->vram_mask;
+    svga->changedvram[addr >> 12]   = svga->monitor->mon_changeframecount;
+    *(uint32_t *) &svga->vram[addr] = val;
+}
+
+static void
+run_dma(mystique_t *mystique)
+{
+    int words_transferred = 0;
+
+    thread_wait_mutex(mystique->dma.lock);
+
+    if (mystique->softrap_pending || mystique->endprdmasts_pending || !mystique->softrap_status_read)
+    {
+        thread_release_mutex(mystique->dma.lock);
+        return;
+    }
+
+    if (mystique->dma.state == DMA_STATE_IDLE) {
+        if (!(mystique->status & STATUS_ENDPRDMASTS))
+        {
+            /* Force this to appear. */
+            mystique->endprdmasts_pending = 1;
+        }
+        thread_release_mutex(mystique->dma.lock);
+        return;
+    }
+
+    while (words_transferred < DMA_MAX_WORDS && mystique->dma.state != DMA_STATE_IDLE) {
+        switch (mystique->dma.state) {
+            case DMA_STATE_PRI:
+                switch (mystique->dma.primaddress & DMA_MODE_MASK) {
+                    case DMA_MODE_REG:
+                        if ((mystique->dma.primaddress & DMA_ADDR_MASK) == (mystique->dma.primend & DMA_ADDR_MASK)) {
+                            mystique->endprdmasts_pending = 1;
+                            mystique->dma.state           = DMA_STATE_IDLE;
+                            break;
+                        }
+                        if (mystique->dma.pri_state == 0 && !mystique->dma.words_expected) {
+                            dma_bm_read(mystique->dma.primaddress & DMA_ADDR_MASK, (uint8_t *) &mystique->dma.pri_header, 4, 4);
+                            //pclog("DMA header: 0x%08X\n", mystique->dma.pri_header);
+                            mystique->dma.primaddress += 4;
+                            mystique->dma.words_expected = 4;
+                            words_transferred++;
+                        }
+
+                        if ((mystique->dma.primaddress & DMA_ADDR_MASK) == (mystique->dma.primend & DMA_ADDR_MASK)) {
+                            mystique->endprdmasts_pending = 1;
+                            mystique->dma.state           = DMA_STATE_IDLE;
+                            break;
+                        }
+
+                        {
+                            uint32_t val;
+                            uint32_t reg_addr;
+
+                            dma_bm_read(mystique->dma.primaddress & DMA_ADDR_MASK, (uint8_t *) &val, 4, 4);
+                            words_transferred++;
+
+                            reg_addr = (mystique->dma.pri_header & 0x7f) << 2;
+                            if (mystique->dma.pri_header & 0x80)
+                                reg_addr += 0x2c00;
+                            else
+                                reg_addr += 0x1c00;
+
+                            if ((reg_addr & 0x300) == 0x100)
+                                mystique->blitter_submit_dma_refcount++;
+
+                            //pclog("DMA value: 0x%08X to reg 0x%04X\n", val, reg_addr);
+                            mystique_accel_ctrl_write_l(reg_addr, val, mystique);
+                            if (reg_addr == REG_SOFTRAP) {
+                                mystique->dma.primaddress += 4;
+                                break;
+                            }
+                        }
+
+                        if (mystique->dma.words_expected)
+                            mystique->dma.words_expected--;
+                        mystique->dma.primaddress += 4;
+
+                        mystique->dma.pri_header >>= 8;
+                        mystique->dma.pri_state = (mystique->dma.pri_state + 1) & 3;
+
+                        if (mystique->dma.state == DMA_STATE_SEC) {
+                            mystique->dma.sec_state = 0;
+                        }
+                        else if ((mystique->dma.primaddress & DMA_ADDR_MASK) == (mystique->dma.primend & DMA_ADDR_MASK)) {
+                            mystique->endprdmasts_pending = 1;
+                            mystique->dma.state           = DMA_STATE_IDLE;
+                        }
+                        break;
+
+                    default:
+                        fatal("DMA_STATE_PRI: mode %i\n", mystique->dma.primaddress & DMA_MODE_MASK);
+                }
+                break;
+
+            case DMA_STATE_SEC:
+                switch (mystique->dma.secaddress & DMA_MODE_MASK) {
+                    case DMA_MODE_REG:
+                        if ((mystique->dma.secaddress & DMA_ADDR_MASK) >= (mystique->dma.secend & DMA_ADDR_MASK)) {
+                            if ((mystique->dma.primaddress & DMA_ADDR_MASK) == (mystique->dma.primend & DMA_ADDR_MASK)) {
+                                mystique->endprdmasts_pending = 1;
+                                mystique->dma.state           = DMA_STATE_IDLE;
+                                mystique->dma.pri_state       = 0;
+                                mystique->dma.words_expected  = 0;
+                            } else {
+                                mystique->dma.state = DMA_STATE_PRI;
+                                mystique->dma.words_expected = 0;
+                                mystique->dma.pri_state = 0;
+                            }
+                        }
+                        if (mystique->dma.sec_state == 0) {
+                            dma_bm_read(mystique->dma.secaddress & DMA_ADDR_MASK, (uint8_t *) &mystique->dma.sec_header, 4, 4);
+                            mystique->dma.secaddress += 4;
+                            //pclog("DMA header (secondary): 0x%08X\n", mystique->dma.sec_header);
+                            words_transferred++;
+                        }
+
+                        if ((mystique->dma.secaddress & DMA_ADDR_MASK) >= (mystique->dma.secend & DMA_ADDR_MASK)) {
+                            if ((mystique->dma.primaddress & DMA_ADDR_MASK) == (mystique->dma.primend & DMA_ADDR_MASK)) {
+                                mystique->endprdmasts_pending = 1;
+                                mystique->dma.state           = DMA_STATE_IDLE;
+                                mystique->dma.pri_state       = 0;
+                                mystique->dma.words_expected  = 0;
+                            } else {
+                                mystique->dma.state = DMA_STATE_PRI;
+                                mystique->dma.words_expected = 0;
+                                mystique->dma.pri_state = 0;
+                            }
+                        }
+
+                        uint32_t val;
+                        uint32_t reg_addr;
+
+                        dma_bm_read(mystique->dma.secaddress & DMA_ADDR_MASK, (uint8_t *) &val, 4, 4);
+                        mystique->dma.secaddress += 4;
+
+                        reg_addr = (mystique->dma.sec_header & 0x7f) << 2;
+                        if (mystique->dma.sec_header & 0x80)
+                            reg_addr += 0x2c00;
+                        else
+                            reg_addr += 0x1c00;
+
+                        if ((reg_addr & 0x300) == 0x100)
+                            mystique->blitter_submit_dma_refcount++;
+
+                        mystique_accel_ctrl_write_l(reg_addr, val, mystique);
+                        //pclog("DMA value (secondary): 0x%08X\n", val);
+                        mystique->dma.sec_header >>= 8;
+                        mystique->dma.sec_state = (mystique->dma.sec_state + 1) & 3;
+
+                        words_transferred++;
+                        if ((mystique->dma.secaddress & DMA_ADDR_MASK) >= (mystique->dma.secend & DMA_ADDR_MASK)) {
+                            if ((mystique->dma.primaddress & DMA_ADDR_MASK) == (mystique->dma.primend & DMA_ADDR_MASK)) {
+                                mystique->endprdmasts_pending = 1;
+                                mystique->dma.state           = DMA_STATE_IDLE;
+                                mystique->dma.pri_state       = 0;
+                                mystique->dma.words_expected  = 0;
+                            } else {
+                                mystique->dma.state = DMA_STATE_PRI;
+                                mystique->dma.words_expected = 0;
+                                mystique->dma.pri_state = 0;
+                            }
+                        }
+                        break;
+
+                    case DMA_MODE_BLIT:
+                        {
+                            uint32_t val;
+                            if ((mystique->dma.secaddress & DMA_ADDR_MASK) >= (mystique->dma.secend & DMA_ADDR_MASK)) {
+                                if ((mystique->dma.primaddress & DMA_ADDR_MASK) == (mystique->dma.primend & DMA_ADDR_MASK)) {
+                                    mystique->endprdmasts_pending = 1;
+                                    mystique->dma.state           = DMA_STATE_IDLE;
+                                    mystique->dma.words_expected = 0;
+                                    mystique->dma.pri_state = 0;
+                                } else {
+                                    mystique->dma.state = DMA_STATE_PRI;
+                                    mystique->dma.words_expected = 0;
+                                    mystique->dma.pri_state = 0;
+                                }
+                            }
+
+                            dma_bm_read(mystique->dma.secaddress & DMA_ADDR_MASK, (uint8_t *) &val, 4, 4);
+                            mystique->dma.secaddress += 4;
+
+                            if (mystique->busy)
+                                blit_iload_write(mystique, val, 32);
+
+                            words_transferred++;
+                            if ((mystique->dma.secaddress & DMA_ADDR_MASK) >= (mystique->dma.secend & DMA_ADDR_MASK)) {
+                                if ((mystique->dma.primaddress & DMA_ADDR_MASK) == (mystique->dma.primend & DMA_ADDR_MASK)) {
+                                    mystique->endprdmasts_pending = 1;
+                                    mystique->dma.state           = DMA_STATE_IDLE;
+                                    mystique->dma.words_expected = 0;
+                                    mystique->dma.pri_state = 0;
+                                } else {
+                                    mystique->dma.state = DMA_STATE_PRI;
+                                    mystique->dma.words_expected = 0;
+                                    mystique->dma.pri_state = 0;
+                                }
+                            }
+                        }
+                        break;
+
+                    default:
+                        fatal("DMA_STATE_SEC: mode %i\n", mystique->dma.secaddress & DMA_MODE_MASK);
+                }
+                break;
+
+            default:
+                break;
+        }
+    }
+
+    thread_release_mutex(mystique->dma.lock);
+}
+
+static void
+fifo_thread(void *priv)
+{
+    mystique_t *mystique = (mystique_t *) priv;
+
+    while (mystique->thread_run) {
+        thread_set_event(mystique->fifo_not_full_event);
+        thread_wait_event(mystique->wake_fifo_thread, -1);
+        thread_reset_event(mystique->wake_fifo_thread);
+
+        while (!FIFO_EMPTY || mystique->dma.state != DMA_STATE_IDLE) {
+            int words_transferred = 0;
+
+            while (!FIFO_EMPTY && words_transferred < 100) {
+                fifo_entry_t *fifo = &mystique->fifo[mystique->fifo_read_idx & FIFO_MASK];
+
+                switch (fifo->addr_type & FIFO_TYPE) {
+                    case FIFO_WRITE_CTRL_BYTE:
+                        mystique_accel_ctrl_write_b(fifo->addr_type & FIFO_ADDR, fifo->val, mystique);
+                        break;
+                    case FIFO_WRITE_CTRL_LONG:
+                        mystique_accel_ctrl_write_l(fifo->addr_type & FIFO_ADDR, fifo->val, mystique);
+                        break;
+                    case FIFO_WRITE_ILOAD_LONG:
+                        mystique_accel_iload_write_l(fifo->addr_type & FIFO_ADDR, fifo->val, mystique);
+                        break;
+
+                    default:
+                        break;
+                }
+
+                fifo->addr_type = FIFO_INVALID;
+                mystique->fifo_read_idx++;
+
+                if (FIFO_ENTRIES > FIFO_THRESHOLD)
+                    thread_set_event(mystique->fifo_not_full_event);
+
+                words_transferred++;
+            }
+
+            /*Only run DMA once the FIFO is empty. Required by
+              Screamer 2 / Rally which will incorrectly clip an ILOAD
+              if DMA runs ahead*/
+            if (!words_transferred)
+                run_dma(mystique);
+        }
+    }
+}
+
+static void
+wake_fifo_thread(mystique_t *mystique)
+{
+    if (!timer_is_enabled(&mystique->wake_timer)) {
+        /* Don't wake FIFO thread immediately - if we do that it will probably
+           process one word and go back to sleep, requiring it to be woken on
+           almost every write. Instead, wait a short while so that the CPU
+           emulation writes more data so we have more batched-up work. */
+        timer_set_delay_u64x(&mystique->wake_timer, WAKE_DELAY);
+    }
+}
+
+static void
+wake_fifo_thread_now(mystique_t *mystique)
+{
+    thread_set_event(mystique->wake_fifo_thread);
+}
+
+static void
+mystique_wake_timer(void *priv)
+{
+    mystique_t *mystique = (mystique_t *) priv;
+
+    thread_set_event(mystique->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/
+}
+
+static void
+wait_fifo_idle(mystique_t *mystique)
+{
+    while (!FIFO_EMPTY) {
+        wake_fifo_thread_now(mystique);
+        thread_wait_event(mystique->fifo_not_full_event, 1);
+    }
+}
+
+/*IRQ code (PCI & PIC) is not currently thread safe. SOFTRAP IRQ requests must
+  therefore be submitted from the main emulation thread, in this case via a timer
+  callback. End-of-DMA status is also deferred here to prevent races between
+  SOFTRAP IRQs and code reading the status register. Croc will get into an IRQ
+  loop and triple fault if the ENDPRDMASTS flag is seen before the IRQ is taken*/
+static void
+mystique_softrap_pending_timer(void *priv)
+{
+    mystique_t *mystique = (mystique_t *) priv;
+
+    timer_advance_u64x(&mystique->softrap_pending_timer, TIMER_USEC * 100);
+
+    if (mystique->endprdmasts_pending) {
+        mystique->endprdmasts_pending = 0;
+        mystique->status |= STATUS_ENDPRDMASTS;
+    }
+    if (mystique->softrap_pending) {
+        mystique->dma.secaddress = mystique->softrap_pending_val;
+        mystique->status |= STATUS_SOFTRAPEN;
+        mystique->softrap_status_read = 0;
+        //pclog("softrapen\n");
+        mystique_update_irqs(mystique);
+        mystique->softrap_pending--;
+    }
+
+}
+
+static void
+mystique_queue(mystique_t *mystique, uint32_t addr, uint32_t val, uint32_t type)
+{
+    fifo_entry_t *fifo = &mystique->fifo[mystique->fifo_write_idx & FIFO_MASK];
+
+    if (FIFO_FULL) {
+        thread_reset_event(mystique->fifo_not_full_event);
+        if (FIFO_FULL)
+            thread_wait_event(mystique->fifo_not_full_event, -1); /* Wait for room in ringbuffer */
+    }
+
+    fifo->val       = val;
+    fifo->addr_type = (addr & FIFO_ADDR) | type;
+
+    mystique->fifo_write_idx++;
+
+    if (FIFO_ENTRIES > FIFO_THRESHOLD || FIFO_ENTRIES < 8)
+        wake_fifo_thread(mystique);
+}
+
+static uint32_t
+bitop(uint32_t src, uint32_t dst, uint32_t dwgctrl)
+{
+    switch (dwgctrl & DWGCTRL_BOP_MASK) {
+        case BOP(0x0):
+            return 0;
+        case BOP(0x1):
+            return ~(dst | src);
+        case BOP(0x2):
+            return dst & ~src;
+        case BOP(0x3):
+            return ~src;
+        case BOP(0x4):
+            return ~dst & src;
+        case BOP(0x5):
+            return ~dst;
+        case BOP(0x6):
+            return dst ^ src;
+        case BOP(0x7):
+            return ~(dst & src);
+        case BOP(0x8):
+            return dst & src;
+        case BOP(0x9):
+            return ~(dst ^ src);
+        case BOP(0xa):
+            return dst;
+        case BOP(0xb):
+            return dst | ~src;
+        case BOP(0xc):
+            return src;
+        case BOP(0xd):
+            return ~dst | src;
+        case BOP(0xe):
+            return dst | src;
+        case BOP(0xf):
+            return ~0;
+
+        default:
+            break;
+    }
+
+    return 0;
+}
+
+static uint16_t
+dither(mystique_t *mystique, int r, int g, int b, int x, int y)
+{
+    switch (mystique->dwgreg.dither) {
+        case DITHER_NONE_555:
+            return (b >> 3) | ((g >> 3) << 5) | ((r >> 3) << 10);
+
+        case DITHER_NONE_565:
+            return (b >> 3) | ((g >> 2) << 5) | ((r >> 3) << 11);
+
+        case DITHER_555:
+            return dither5[b][y][x] | (dither5[g][y][x] << 5) | (dither5[r][y][x] << 10);
+
+        case DITHER_565:
+        default:
+            return dither5[b][y][x] | (dither6[g][y][x] << 5) | (dither5[r][y][x] << 11);
+    }
+}
+
+static uint32_t
+blit_idump_idump(mystique_t *mystique)
+{
+    svga_t  *svga  = &mystique->svga;
+    uint64_t val64 = 0;
+    uint32_t val   = 0;
+    int      count = 0;
+
+    switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) {
+        case DWGCTRL_ATYPE_RPL:
+            switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) {
+                case DWGCTRL_BLTMOD_BU32RGB:
+                case DWGCTRL_BLTMOD_BFCOL:
+                    switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) {
+                        case MACCESS_PWIDTH_8:
+                            while (count < 32) {
+                                val |= (svga->vram[mystique->dwgreg.src_addr & mystique->vram_mask] << count);
+
+                                if (mystique->dwgreg.src_addr == mystique->dwgreg.ar[0]) {
+                                    mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5];
+                                    mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5];
+                                    mystique->dwgreg.src_addr = mystique->dwgreg.ar[3];
+                                } else
+                                    mystique->dwgreg.src_addr++;
+
+                                if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) {
+                                    mystique->dwgreg.xdst = mystique->dwgreg.fxleft;
+                                    mystique->dwgreg.length_cur--;
+                                    if (!mystique->dwgreg.length_cur) {
+                                        mystique->busy = 0;
+                                        mystique->blitter_complete_refcount++;
+                                        break;
+                                    }
+                                    break;
+                                } else
+                                    mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff;
+
+                                count += 8;
+                            }
+                            break;
+
+                        case MACCESS_PWIDTH_16:
+                            while (count < 32) {
+                                val |= (((uint16_t *) svga->vram)[mystique->dwgreg.src_addr & mystique->vram_mask_w] << count);
+
+                                if (mystique->dwgreg.src_addr == mystique->dwgreg.ar[0]) {
+                                    mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5];
+                                    mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5];
+                                    mystique->dwgreg.src_addr = mystique->dwgreg.ar[3];
+                                } else
+                                    mystique->dwgreg.src_addr++;
+
+                                if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) {
+                                    mystique->dwgreg.xdst = mystique->dwgreg.fxleft;
+                                    mystique->dwgreg.length_cur--;
+                                    if (!mystique->dwgreg.length_cur) {
+                                        mystique->busy = 0;
+                                        mystique->blitter_complete_refcount++;
+                                        break;
+                                    }
+                                    break;
+                                } else
+                                    mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff;
+
+                                count += 16;
+                            }
+                            break;
+
+                        case MACCESS_PWIDTH_24:
+                            if (mystique->dwgreg.idump_end_of_line) {
+                                mystique->dwgreg.idump_end_of_line = 0;
+                                val                                = mystique->dwgreg.iload_rem_data;
+                                mystique->dwgreg.iload_rem_count   = 0;
+                                mystique->dwgreg.iload_rem_data    = 0;
+                                if (!mystique->dwgreg.length_cur) {
+                                    mystique->busy = 0;
+                                    mystique->blitter_complete_refcount++;
+                                }
+                                break;
+                            }
+
+                            count += mystique->dwgreg.iload_rem_count;
+                            val64 = mystique->dwgreg.iload_rem_data;
+
+                            while ((count < 32) && !mystique->dwgreg.idump_end_of_line) {
+                                val64 |= (uint64_t) ((*(uint32_t *) &svga->vram[(mystique->dwgreg.src_addr * 3) & mystique->vram_mask]) & 0xffffff) << count;
+
+                                if (mystique->dwgreg.src_addr == mystique->dwgreg.ar[0]) {
+                                    mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5];
+                                    mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5];
+                                    mystique->dwgreg.src_addr = mystique->dwgreg.ar[3];
+                                } else
+                                    mystique->dwgreg.src_addr++;
+
+                                if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) {
+                                    mystique->dwgreg.xdst = mystique->dwgreg.fxleft;
+                                    mystique->dwgreg.length_cur--;
+                                    if (!mystique->dwgreg.length_cur) {
+                                        if (count > 8)
+                                            mystique->dwgreg.idump_end_of_line = 1;
+                                        else {
+                                            count          = 32;
+                                            mystique->busy = 0;
+                                            mystique->blitter_complete_refcount++;
+                                        }
+                                        break;
+                                    }
+                                    if (!(mystique->dwgreg.dwgctrl_running & DWGCTRL_LINEAR)) {
+                                        if (count > 8)
+                                            mystique->dwgreg.idump_end_of_line = 1;
+                                        else {
+                                            count = 32;
+                                            break;
+                                        }
+                                    }
+                                } else
+                                    mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff;
+
+                                count += 24;
+                            }
+                            if (count > 32)
+                                mystique->dwgreg.iload_rem_count = count - 32;
+                            else
+                                mystique->dwgreg.iload_rem_count = 0;
+                            mystique->dwgreg.iload_rem_data = (uint32_t) (val64 >> 32);
+                            val                             = val64 & 0xffffffff;
+                            break;
+
+                        case MACCESS_PWIDTH_32:
+                            val = (((uint32_t *) svga->vram)[mystique->dwgreg.src_addr & mystique->vram_mask_l] << count);
+
+                            if (mystique->dwgreg.src_addr == mystique->dwgreg.ar[0]) {
+                                mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5];
+                                mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5];
+                                mystique->dwgreg.src_addr = mystique->dwgreg.ar[3];
+                            } else
+                                mystique->dwgreg.src_addr++;
+
+                            if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) {
+                                mystique->dwgreg.xdst = mystique->dwgreg.fxleft;
+                                mystique->dwgreg.length_cur--;
+                                if (!mystique->dwgreg.length_cur) {
+                                    mystique->busy = 0;
+                                    mystique->blitter_complete_refcount++;
+                                    break;
+                                }
+                                break;
+                            } else
+                                mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff;
+                            break;
+
+                        default:
+                            fatal("IDUMP DWGCTRL_BLTMOD_BU32RGB %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->maccess_running);
+                    }
+                    break;
+
+                default:
+                    fatal("IDUMP DWGCTRL_ATYPE_RPL %08x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK, mystique->dwgreg.dwgctrl_running);
+                    break;
+            }
+            break;
+
+        default:
+            fatal("Unknown IDUMP atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running);
+    }
+
+    return val;
+}
+
+static uint32_t
+blit_idump_read(mystique_t *mystique)
+{
+    uint32_t ret = 0xffffffff;
+
+    switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) {
+        case DWGCTRL_OPCODE_IDUMP:
+            ret = blit_idump_idump(mystique);
+            break;
+
+        default:
+            /* pclog("blit_idump_read: bad opcode %08x\n", mystique->dwgreg.dwgctrl_running); */
+            break;
+    }
+
+    return ret;
+}
+
+static void
+blit_fbitblt(mystique_t *mystique)
+{
+    svga_t  *svga = &mystique->svga;
+    uint32_t src_addr;
+    int      x_dir   = mystique->dwgreg.sgn.scanleft ? -1 : 1;
+    int16_t  x_start = mystique->dwgreg.sgn.scanleft ? mystique->dwgreg.fxright : mystique->dwgreg.fxleft;
+    int16_t  x_end   = mystique->dwgreg.sgn.scanleft ? mystique->dwgreg.fxleft : mystique->dwgreg.fxright;
+
+    src_addr = mystique->dwgreg.ar[3];
+
+    for (uint16_t y = 0; y < mystique->dwgreg.length; y++) {
+        int16_t x = x_start;
+        while (1) {
+            if (x >= mystique->dwgreg.cxleft && x <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) {
+                uint32_t src;
+                uint32_t old_dst;
+
+                switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) {
+                    case MACCESS_PWIDTH_8:
+                        src = svga->vram[src_addr & mystique->vram_mask];
+
+                        svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask]                = src;
+                        svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask) >> 12] = changeframecount;
+                        break;
+
+                    case MACCESS_PWIDTH_16:
+                        src = ((uint16_t *) svga->vram)[src_addr & mystique->vram_mask_w];
+
+                        ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = src;
+                        svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w) >> 11] = changeframecount;
+                        break;
+
+                    case MACCESS_PWIDTH_24:
+                        src     = *(uint32_t *) &svga->vram[(src_addr * 3) & mystique->vram_mask];
+                        old_dst = *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask];
+
+                        *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = (src & 0xffffff) | (old_dst & 0xff000000);
+                        svga->changedvram[(((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask) >> 12] = changeframecount;
+                        break;
+
+                    case MACCESS_PWIDTH_32:
+                        src = ((uint32_t *) svga->vram)[src_addr & mystique->vram_mask_l];
+
+                        ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l] = src;
+                        svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l) >> 10] = changeframecount;
+                        break;
+
+                    default:
+                        fatal("BITBLT RPL BFCOL PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running);
+                }
+            }
+
+            if (src_addr == mystique->dwgreg.ar[0]) {
+                mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5];
+                mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5];
+                src_addr = mystique->dwgreg.ar[3];
+                break;
+            } else
+                src_addr += x_dir;
+
+            if (x != x_end)
+                x += x_dir;
+            else
+                break;
+        }
+
+        if (mystique->dwgreg.sgn.sdy)
+            mystique->dwgreg.ydst_lin -= (mystique->dwgreg.pitch & PITCH_MASK);
+        else
+            mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK);
+    }
+
+    mystique->blitter_complete_refcount++;
+}
+
+static uint8_t
+dither_24_to_8(int r, int g, int b)
+{
+    return ((b >> 6) & 3) | (((g >> 5) & 7) << 2) | (((r >> 5) & 7) << 5);
+}
+
+static void
+blit_iload_iload(mystique_t *mystique, uint32_t data, int size)
+{
+    svga_t              *svga = &mystique->svga;
+    uint32_t             src;
+    uint32_t             dst;
+    uint32_t             dst2;
+    uint64_t             data64;
+    int                  min_size = 8;
+    uint32_t             bltckey = mystique->dwgreg.fcol;
+    uint32_t             bltcmsk = mystique->dwgreg.bcol;
+    const int            transc    = mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC;
+    const int            trans_sel = (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANS_MASK) >> DWGCTRL_TRANS_SHIFT;
+    uint8_t const *const trans     = &trans_masks[trans_sel][(mystique->dwgreg.selline & 3) * 4];
+    uint32_t             data_mask = 1;
+
+    switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) {
+        case MACCESS_PWIDTH_8:
+            bltckey &= 0xff;
+            bltcmsk &= 0xff;
+            break;
+        case MACCESS_PWIDTH_16:
+            bltckey &= 0xffff;
+            bltcmsk &= 0xffff;
+            break;
+    }
+
+    mystique->dwgreg.words++;
+    switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) {
+        case DWGCTRL_ATYPE_RPL:
+            if (mystique->maccess_running & MACCESS_TLUTLOAD) {
+                while ((mystique->dwgreg.length_cur > 0) && (size >= 16)) {
+                    uint16_t src = data & 0xffff;
+
+                    mystique->lut[mystique->dwgreg.ydst & 0xff].r = (src >> 11) << 3;
+                    mystique->lut[mystique->dwgreg.ydst & 0xff].g = ((src >> 5) & 0x3f) << 2;
+                    mystique->lut[mystique->dwgreg.ydst & 0xff].b = (src & 0x1f) << 3;
+                    mystique->dwgreg.ydst++;
+                    mystique->dwgreg.length_cur--;
+                    data >>= 16;
+                    size -= 16;
+                }
+
+                if (!mystique->dwgreg.length_cur) {
+                    mystique->busy = 0;
+                    mystique->blitter_complete_refcount++;
+                }
+                break;
+            }
+        case DWGCTRL_ATYPE_RSTR:
+        case DWGCTRL_ATYPE_BLK:
+            switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) {
+                case DWGCTRL_BLTMOD_BFCOL:
+                    size += mystique->dwgreg.iload_rem_count;
+                    data64 = mystique->dwgreg.iload_rem_data | ((uint64_t) data << mystique->dwgreg.iload_rem_count);
+
+                    switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) {
+                        case MACCESS_PWIDTH_8:
+                            min_size = 8;
+                            break;
+                        case MACCESS_PWIDTH_16:
+                            min_size = 16;
+                            break;
+                        case MACCESS_PWIDTH_24:
+                            min_size = 24;
+                            break;
+                        case MACCESS_PWIDTH_32:
+                            min_size = 32;
+                            break;
+
+                        default:
+                            break;
+                    }
+
+                    while (size >= min_size) {
+                        int draw = (!transc || (data & bltcmsk) != bltckey) && trans[mystique->dwgreg.xdst & 3];
+
+                        switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) {
+                            case MACCESS_PWIDTH_8:
+                                if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && draw) {
+                                    dst = svga->vram[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask];
+
+                                    dst                                                                                                  = bitop(data & 0xff, dst, mystique->dwgreg.dwgctrl_running);
+                                    svga->vram[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask]                = dst;
+                                    svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask) >> 12] = changeframecount;
+                                }
+
+                                data >>= 8;
+                                size -= 8;
+                                break;
+
+                            case MACCESS_PWIDTH_16:
+                                if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && draw) {
+                                    dst = ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w];
+
+                                    dst                                                                                                    = bitop(data & 0xffff, dst, mystique->dwgreg.dwgctrl_running);
+                                    ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w] = dst;
+                                    svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w) >> 11] = changeframecount;
+                                }
+
+                                data >>= 16;
+                                size -= 16;
+                                break;
+
+                            case MACCESS_PWIDTH_24:
+                                if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) {
+                                    uint32_t old_dst = *((uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) * 3) & mystique->vram_mask]);
+
+                                    dst                                                                                                          = bitop(data64, old_dst, mystique->dwgreg.dwgctrl_running);
+                                    *((uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) * 3) & mystique->vram_mask]) = (dst & 0xffffff) | (old_dst & 0xff000000);
+                                    svga->changedvram[(((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) * 3) & mystique->vram_mask) >> 12]   = changeframecount;
+                                }
+
+                                data64 >>= 24;
+                                size -= 24;
+                                break;
+
+                            case MACCESS_PWIDTH_32:
+                                if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && draw) {
+                                    dst = ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l];
+
+                                    dst                                                                                                    = bitop(data, dst, mystique->dwgreg.dwgctrl_running);
+                                    ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l] = dst;
+                                    svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l) >> 10] = changeframecount;
+                                }
+
+                                size = 0;
+                                break;
+
+                            default:
+                                fatal("ILOAD RSTR/RPL BFCOL pwidth %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK);
+                        }
+
+                        if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) {
+                            mystique->dwgreg.xdst = mystique->dwgreg.fxleft;
+                            mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK);
+                            mystique->dwgreg.selline = (mystique->dwgreg.selline + 1) & 7;
+                            mystique->dwgreg.length_cur--;
+                            if (!mystique->dwgreg.length_cur) {
+                                mystique->busy = 0;
+                                mystique->blitter_complete_refcount++;
+                                break;
+                            }
+                            data64 = 0;
+                            size   = 0;
+                            break;
+                        } else
+                            mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff;
+                    }
+                    mystique->dwgreg.iload_rem_count = size;
+                    mystique->dwgreg.iload_rem_data  = data64;
+                    break;
+
+                case DWGCTRL_BLTMOD_BMONOWF:
+                    data      = (data >> 24) | ((data & 0x00ff0000) >> 8) | ((data & 0x0000ff00) << 8) | (data << 24);
+                    data_mask = (1 << 31);
+                case DWGCTRL_BLTMOD_BMONOLEF:
+                    while (size) {
+                        if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && ((data & data_mask) || !(mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC)) && trans[mystique->dwgreg.xdst & 3]) {
+                            uint32_t old_dst;
+
+                            src = (data & data_mask) ? mystique->dwgreg.fcol : mystique->dwgreg.bcol;
+                            switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) {
+                                case MACCESS_PWIDTH_8:
+                                    dst = svga->vram[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask];
+
+                                    dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running);
+
+                                    svga->vram[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask]                = dst;
+                                    svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask) >> 12] = changeframecount;
+                                    break;
+
+                                case MACCESS_PWIDTH_16:
+                                    dst = ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w];
+
+                                    dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running);
+
+                                    ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w] = dst;
+                                    svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w) >> 11] = changeframecount;
+                                    break;
+
+                                case MACCESS_PWIDTH_24:
+                                    old_dst = *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) * 3) & mystique->vram_mask];
+
+                                    dst = bitop(src, old_dst, mystique->dwgreg.dwgctrl_running);
+
+                                    *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) * 3) & mystique->vram_mask] = (dst & 0xffffff) | (old_dst & 0xff000000);
+                                    svga->changedvram[(((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) * 3) & mystique->vram_mask) >> 12] = changeframecount;
+                                    break;
+
+                                case MACCESS_PWIDTH_32:
+                                    dst = ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l];
+
+                                    dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running);
+
+                                    ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l] = dst;
+                                    svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l) >> 10] = changeframecount;
+                                    break;
+
+                                default:
+                                    fatal("ILOAD RSTR/RPL BMONOWF pwidth %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK);
+                            }
+                        }
+
+                        if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) {
+                            mystique->dwgreg.xdst = mystique->dwgreg.fxleft;
+                            mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK);
+                            mystique->dwgreg.length_cur--;
+                            if (!mystique->dwgreg.length_cur) {
+                                mystique->busy = 0;
+                                mystique->blitter_complete_refcount++;
+                                break;
+                            }
+                            if (!(mystique->dwgreg.dwgctrl_running & DWGCTRL_LINEAR))
+                                break;
+                        } else
+                            mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff;
+                        if (data_mask == 1)
+                            data >>= 1;
+                        else
+                            data <<= 1;
+                        size--;
+                    }
+                    break;
+
+                case DWGCTRL_BLTMOD_BU24RGB:
+                    size += mystique->dwgreg.iload_rem_count;
+                    data64 = mystique->dwgreg.iload_rem_data | ((uint64_t) data << mystique->dwgreg.iload_rem_count);
+
+                    while (size >= 24) {
+                        if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) {
+                            switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) {
+                                case MACCESS_PWIDTH_16:
+                                {
+                                    dst = ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w];
+
+                                    dst = bitop(dither(mystique, (data64 >> 16) & 0xFF, (data64 >> 8) & 0xFF, data64 & 0xFF, mystique->dwgreg.xdst & 1, mystique->dwgreg.selline & 1), dst, mystique->dwgreg.dwgctrl_running);
+
+                                    ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w] = dst;
+                                    svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w) >> 11] = changeframecount;
+                                    break;
+                                }
+                                case MACCESS_PWIDTH_8:
+                                {
+                                    dst = ((uint8_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask];
+
+                                    dst = bitop(dither_24_to_8((data64 >> 16) & 0xFF, (data64 >> 8) & 0xFF, data64 & 0xFF), dst, mystique->dwgreg.dwgctrl_running);
+
+                                    ((uint8_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask] = dst;
+                                    svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask) >> 12] = changeframecount;
+                                    break;
+                                }
+                                case MACCESS_PWIDTH_32:
+                                    dst = ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l];
+
+                                    dst = bitop(data64 & 0xffffff, dst, mystique->dwgreg.dwgctrl_running);
+
+                                    ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l] = dst;
+                                    svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l) >> 10] = changeframecount;
+                                    break;
+
+                                default:
+                                    fatal("ILOAD RSTR/RPL BU24RGB pwidth %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK);
+                            }
+                        }
+
+                        data64 >>= 24;
+                        size -= 24;
+                        if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) {
+                            mystique->dwgreg.xdst = mystique->dwgreg.fxleft;
+                            mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK);
+                            mystique->dwgreg.length_cur--;
+                            if (!mystique->dwgreg.length_cur) {
+                                mystique->busy = 0;
+                                mystique->blitter_complete_refcount++;
+                                break;
+                            }
+                            data64 = 0;
+                            size   = 0;
+                            break;
+                        } else
+                            mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff;
+                    }
+
+                    mystique->dwgreg.iload_rem_count = size;
+                    mystique->dwgreg.iload_rem_data  = data64;
+                    break;
+
+                case DWGCTRL_BLTMOD_BU32RGB:
+                    size += mystique->dwgreg.iload_rem_count;
+                    data64 = mystique->dwgreg.iload_rem_data | ((uint64_t) data << mystique->dwgreg.iload_rem_count);
+                    while (size >= 32) {
+                        int draw = (!transc || (data & bltcmsk) != bltckey) && trans[mystique->dwgreg.xdst & 3];
+
+                        if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && draw) {
+                            switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) {
+                                case MACCESS_PWIDTH_16:
+                                {
+                                    dst = ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w];
+
+                                    dst = bitop(dither(mystique, (data64 >> 16) & 0xFF, (data64 >> 8) & 0xFF, data64 & 0xFF, mystique->dwgreg.xdst & 1, mystique->dwgreg.selline & 1), dst, mystique->dwgreg.dwgctrl_running);
+
+                                    ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w] = dst;
+                                    svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w) >> 11] = changeframecount;
+                                    break;
+                                }
+                                case MACCESS_PWIDTH_8:
+                                {
+                                    dst = ((uint8_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask];
+
+                                    dst = bitop(dither_24_to_8((data64 >> 16) & 0xFF, (data64 >> 8) & 0xFF, data64 & 0xFF), dst, mystique->dwgreg.dwgctrl_running);
+
+                                    ((uint8_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask] = dst;
+                                    svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask) >> 12] = changeframecount;
+                                    break;
+                                }
+                                default: {
+                                    dst = ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l];
+
+                                    dst                                                                                                    = bitop(data, dst, mystique->dwgreg.dwgctrl_running);
+                                    ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l] = dst;
+                                    svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l) >> 10] = changeframecount;
+                                    break;
+                                }
+                            }
+                        }
+
+                        size = 0;
+
+                        if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) {
+                            mystique->dwgreg.xdst = mystique->dwgreg.fxleft;
+                            mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK);
+                            mystique->dwgreg.selline = (mystique->dwgreg.selline + 1) & 7;
+                            mystique->dwgreg.length_cur--;
+                            if (!mystique->dwgreg.length_cur) {
+                                mystique->busy = 0;
+                                mystique->blitter_complete_refcount++;
+                                break;
+                            }
+                            data64 = 0;
+                            size   = 0;
+                            break;
+                        } else
+                            mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff;
+                    }
+                    mystique->dwgreg.iload_rem_count = size;
+                    mystique->dwgreg.iload_rem_data  = data64;
+                    break;
+
+                case DWGCTRL_BLTMOD_BU32BGR:
+                    size += mystique->dwgreg.iload_rem_count;
+                    while (size >= 32) {
+                        if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) {
+                            switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) {
+                                case MACCESS_PWIDTH_32:
+                                    dst  = ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l];
+                                    dst2 = ((dst >> 16) & 0xff) | (dst & 0xff00) | ((dst & 0xff) << 16); /* BGR to RGB */
+
+                                    dst = bitop(data, dst2, mystique->dwgreg.dwgctrl_running);
+
+                                    ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l] = dst;
+                                    svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l) >> 10] = changeframecount;
+                                    break;
+
+                                default:
+                                    fatal("ILOAD RSTR/RPL BU32RGB pwidth %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK);
+                            }
+                        }
+
+                        size = 0;
+                        if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) {
+                            mystique->dwgreg.xdst = mystique->dwgreg.fxleft;
+                            mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK);
+                            mystique->dwgreg.length_cur--;
+                            if (!mystique->dwgreg.length_cur) {
+                                mystique->busy = 0;
+                                mystique->blitter_complete_refcount++;
+                                break;
+                            }
+                            break;
+                        } else
+                            mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff;
+                    }
+
+                    mystique->dwgreg.iload_rem_count = size;
+                    break;
+
+                default:
+                    fatal("ILOAD DWGCTRL_ATYPE_RPL\n");
+                    break;
+            }
+            break;
+
+        default:
+            fatal("Unknown ILOAD iload atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running);
+    }
+}
+
+#define CLAMP(x)                      \
+    do {                              \
+        if ((x) & ~0xff)              \
+            x = ((x) < 0) ? 0 : 0xff; \
+    } while (0)
+
+static void
+blit_iload_iload_scale(mystique_t *mystique, uint32_t data, int size)
+{
+    svga_t  *svga   = &mystique->svga;
+    uint64_t data64 = 0;
+    int      y0;
+    int      y1;
+    int      u;
+    int      v;
+    int      dR;
+    int      dG;
+    int      dB;
+    int      r0;
+    int      g0;
+    int      b0;
+    int      r1;
+    int      g1;
+    int      b1;
+
+    switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) {
+        case DWGCTRL_BLTMOD_BUYUV:
+            y0 = (298 * ((int) (data & 0xff) - 16)) >> 8;
+            u  = ((data >> 8) & 0xff) - 0x80;
+            y1 = (298 * ((int) ((data >> 16) & 0xff) - 16)) >> 8;
+            v  = ((data >> 24) & 0xff) - 0x80;
+
+            dR = (309 * v) >> 8;
+            dG = (100 * u + 208 * v) >> 8;
+            dB = (516 * u) >> 8;
+
+            r0 = y0 + dR;
+            CLAMP(r0);
+            g0 = y0 - dG;
+            CLAMP(g0);
+            b0 = y0 + dB;
+            CLAMP(b0);
+            r1 = y1 + dR;
+            CLAMP(r1);
+            g1 = y1 - dG;
+            CLAMP(g1);
+            b1 = y1 + dB;
+            CLAMP(b1);
+
+            switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) {
+                case MACCESS_PWIDTH_16:
+                    data = (b0 >> 3) | ((g0 >> 2) << 5) | ((r0 >> 3) << 11);
+                    data |= (((b1 >> 3) | ((g1 >> 2) << 5) | ((r1 >> 3) << 11)) << 16);
+                    size = 32;
+                    break;
+                case MACCESS_PWIDTH_32:
+                    data64 = b0 | (g0 << 8) | (r0 << 16);
+                    data64 |= ((uint64_t) b0 << 32) | ((uint64_t) g0 << 40) | ((uint64_t) r0 << 48);
+                    size = 64;
+                    break;
+
+                default:
+                    fatal("blit_iload_iload_scale BUYUV pwidth %i\n", mystique->maccess_running & MACCESS_PWIDTH_MASK);
+            }
+            break;
+
+        default:
+            fatal("blit_iload_iload_scale bltmod %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK);
+            break;
+    }
+
+    switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) {
+        case MACCESS_PWIDTH_16:
+            while (size >= 16) {
+                if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) {
+                    uint16_t dst                                                                                           = ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w];
+                    dst                                                                                                    = bitop(data & 0xffff, dst, mystique->dwgreg.dwgctrl_running);
+                    ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w] = dst;
+                    svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w) >> 11] = changeframecount;
+                }
+
+                mystique->dwgreg.ar[6] += mystique->dwgreg.ar[2];
+                if ((int32_t) mystique->dwgreg.ar[6] >= 0) {
+                    mystique->dwgreg.ar[6] -= (mystique->dwgreg.fxright - mystique->dwgreg.fxleft);
+                    data >>= 16;
+                    size -= 16;
+                }
+
+                mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff;
+                if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) {
+                    mystique->dwgreg.xdst = mystique->dwgreg.fxleft;
+                    mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK);
+                    mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5];
+                    mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5];
+                    mystique->dwgreg.ar[6] = mystique->dwgreg.ar[2] - (mystique->dwgreg.fxright - mystique->dwgreg.fxleft);
+                    mystique->dwgreg.length_cur--;
+                    if (!mystique->dwgreg.length_cur) {
+                        mystique->busy = 0;
+                        mystique->blitter_complete_refcount++;
+                        break;
+                    }
+                    break;
+                }
+            }
+            break;
+
+        case MACCESS_PWIDTH_32:
+            while (size >= 32) {
+                if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) {
+                    uint32_t dst                                                                                           = ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l];
+                    dst                                                                                                    = bitop(data64, dst, mystique->dwgreg.dwgctrl_running);
+                    ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l] = dst;
+                    svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l) >> 10] = changeframecount;
+                }
+
+                mystique->dwgreg.ar[6] += mystique->dwgreg.ar[2];
+                if ((int32_t) mystique->dwgreg.ar[6] >= 0) {
+                    mystique->dwgreg.ar[6] -= (mystique->dwgreg.fxright - mystique->dwgreg.fxleft);
+                    data64 >>= 32;
+                    size -= 32;
+                }
+
+                mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff;
+                if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) {
+                    mystique->dwgreg.xdst = mystique->dwgreg.fxleft;
+                    mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK);
+                    mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5];
+                    mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5];
+                    mystique->dwgreg.ar[6] = mystique->dwgreg.ar[2] - (mystique->dwgreg.fxright - mystique->dwgreg.fxleft);
+                    mystique->dwgreg.length_cur--;
+                    if (!mystique->dwgreg.length_cur) {
+                        mystique->busy = 0;
+                        mystique->blitter_complete_refcount++;
+                        break;
+                    }
+                    break;
+                }
+            }
+            break;
+
+        default:
+            fatal("ILOAD_SCALE pwidth %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK);
+    }
+}
+
+static void
+blit_iload_iload_high(mystique_t *mystique, uint32_t data, int size)
+{
+    svga_t  *svga = &mystique->svga;
+    uint32_t out_data;
+    int      y0;
+    int      y1;
+    int      u;
+    int      v;
+    int      dR;
+    int      dG;
+    int      dB;
+    int      r = 0;
+    int      g = 0;
+    int      b = 0;
+    int      next_r = 0;
+    int      next_g = 0;
+    int      next_b = 0;
+
+    switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) {
+        case DWGCTRL_BLTMOD_BUYUV:
+            y0 = (298 * ((int) (data & 0xff) - 16)) >> 8;
+            u  = ((data >> 8) & 0xff) - 0x80;
+            y1 = (298 * ((int) ((data >> 16) & 0xff) - 16)) >> 8;
+            v  = ((data >> 24) & 0xff) - 0x80;
+
+            dR = (309 * v) >> 8;
+            dG = (100 * u + 208 * v) >> 8;
+            dB = (516 * u) >> 8;
+
+            r = y0 + dR;
+            CLAMP(r);
+            g = y0 - dG;
+            CLAMP(g);
+            b = y0 + dB;
+            CLAMP(b);
+
+            next_r = y1 + dR;
+            CLAMP(next_r);
+            next_g = y1 - dG;
+            CLAMP(next_g);
+            next_b = y1 + dB;
+            CLAMP(next_b);
+
+            size = 32;
+            break;
+
+        case DWGCTRL_BLTMOD_BU32BGR:
+            r = ((data >> 16) & 0xff);
+            CLAMP(r);
+            g = ((data >> 8) & 0xff);
+            CLAMP(g);
+            b = (data & 0xff);
+            CLAMP(b);
+
+            next_r = r;
+            next_g = g;
+            next_b = b;
+
+            size = 32;
+            break;
+
+        default:
+            fatal("blit_iload_iload_high bltmod %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK);
+            break;
+    }
+
+    while (size >= 16) {
+        if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) {
+            uint32_t dst;
+            int      f1    = (mystique->dwgreg.ar[6] >> 12) & 0xf;
+            int      f0    = 0x10 - f1;
+            int      out_r = ((mystique->dwgreg.lastpix_r * f0) + (r * f1)) >> 4;
+            int      out_g = ((mystique->dwgreg.lastpix_g * f0) + (g * f1)) >> 4;
+            int      out_b = ((mystique->dwgreg.lastpix_b * f0) + (b * f1)) >> 4;
+
+            switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) {
+                case MACCESS_PWIDTH_16:
+                    out_data                                                                                               = (out_b >> 3) | ((out_g >> 2) << 5) | ((out_r >> 3) << 11);
+                    dst                                                                                                    = ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w];
+                    dst                                                                                                    = bitop(out_data, dst, mystique->dwgreg.dwgctrl_running);
+                    ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w] = dst;
+                    svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w) >> 11] = changeframecount;
+                    break;
+                case MACCESS_PWIDTH_32:
+                    out_data                                                                                               = out_b | (out_g << 8) | (out_r << 16);
+                    dst                                                                                                    = ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l];
+                    dst                                                                                                    = bitop(out_data, dst, mystique->dwgreg.dwgctrl_running);
+                    ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l] = dst;
+                    svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l) >> 10] = changeframecount;
+                    break;
+
+                default:
+                    fatal("ILOAD_SCALE_HIGH RSTR/RPL BUYUV pwidth %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK);
+            }
+        }
+
+        mystique->dwgreg.ar[6] += mystique->dwgreg.ar[2];
+        if ((int32_t) mystique->dwgreg.ar[6] >= 0) {
+            mystique->dwgreg.ar[6] -= 65536;
+            size -= 16;
+
+            mystique->dwgreg.lastpix_r = r;
+            mystique->dwgreg.lastpix_g = g;
+            mystique->dwgreg.lastpix_b = b;
+            r                          = next_r;
+            g                          = next_g;
+            b                          = next_b;
+        }
+
+        if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) {
+            mystique->dwgreg.xdst = mystique->dwgreg.fxleft;
+            mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK);
+            mystique->dwgreg.ar[6]     = mystique->dwgreg.ar[2] - (mystique->dwgreg.fxright - mystique->dwgreg.fxleft);
+            mystique->dwgreg.lastpix_r = 0;
+            mystique->dwgreg.lastpix_g = 0;
+            mystique->dwgreg.lastpix_b = 0;
+
+            mystique->dwgreg.length_cur--;
+            if (!mystique->dwgreg.length_cur) {
+                mystique->busy = 0;
+                mystique->blitter_complete_refcount++;
+                break;
+            }
+            break;
+        } else
+            mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff;
+    }
+}
+
+static void
+blit_iload_iload_highv(mystique_t *mystique, uint32_t data, UNUSED(int size))
+{
+    const uint8_t *src0;
+    uint8_t       *src1;
+
+    switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) {
+        case DWGCTRL_BLTMOD_BUYUV:
+            if (!mystique->dwgreg.highv_line) {
+                mystique->dwgreg.highv_data = data;
+                mystique->dwgreg.highv_line = 1;
+                return;
+            }
+            mystique->dwgreg.highv_line = 0;
+
+            src0 = (uint8_t *) &mystique->dwgreg.highv_data;
+            src1 = (uint8_t *) &data;
+
+            src1[0] = ((src0[0] * mystique->dwgreg.beta) + (src1[0] * (16 - mystique->dwgreg.beta))) >> 4;
+            src1[1] = ((src0[1] * mystique->dwgreg.beta) + (src1[1] * (16 - mystique->dwgreg.beta))) >> 4;
+            src1[2] = ((src0[2] * mystique->dwgreg.beta) + (src1[2] * (16 - mystique->dwgreg.beta))) >> 4;
+            src1[3] = ((src0[3] * mystique->dwgreg.beta) + (src1[3] * (16 - mystique->dwgreg.beta))) >> 4;
+            blit_iload_iload_high(mystique, data, 32);
+            break;
+
+        default:
+            fatal("blit_iload_iload_highv bltmod %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK);
+            break;
+    }
+}
+
+static void
+blit_iload_write(mystique_t *mystique, uint32_t data, int size)
+{
+    switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) {
+        case DWGCTRL_OPCODE_ILOAD:
+            blit_iload_iload(mystique, data, size);
+            break;
+
+        case DWGCTRL_OPCODE_ILOAD_SCALE:
+            blit_iload_iload_scale(mystique, data, size);
+            break;
+
+        case DWGCTRL_OPCODE_ILOAD_HIGH:
+            blit_iload_iload_high(mystique, data, size);
+            break;
+
+        case DWGCTRL_OPCODE_ILOAD_HIGHV:
+            blit_iload_iload_highv(mystique, data, size);
+            break;
+
+        default:
+            fatal("blit_iload_write: bad opcode %08x\n", mystique->dwgreg.dwgctrl_running);
+    }
+}
+
+static int
+z_check(uint16_t z, uint16_t old_z, uint32_t z_mode) // mystique->dwgreg.dwgctrl & DWGCTRL_ZMODE_MASK)
+{
+    switch (z_mode) {
+        case DWGCTRL_ZMODE_ZE:
+            return (z == old_z);
+        case DWGCTRL_ZMODE_ZNE:
+            return (z != old_z);
+        case DWGCTRL_ZMODE_ZLT:
+            return (z < old_z);
+        case DWGCTRL_ZMODE_ZLTE:
+            return (z <= old_z);
+        case DWGCTRL_ZMODE_ZGT:
+            return (z > old_z);
+        case DWGCTRL_ZMODE_ZGTE:
+            return (z >= old_z);
+
+        case DWGCTRL_ZMODE_NOZCMP:
+        default:
+            return 1;
+    }
+}
+
+static int
+z_check_32(uint32_t z, uint32_t old_z, uint32_t z_mode) // mystique->dwgreg.dwgctrl & DWGCTRL_ZMODE_MASK)
+{
+    switch (z_mode) {
+        case DWGCTRL_ZMODE_ZE:
+            return (z == old_z);
+        case DWGCTRL_ZMODE_ZNE:
+            return (z != old_z);
+        case DWGCTRL_ZMODE_ZLT:
+            return (z < old_z);
+        case DWGCTRL_ZMODE_ZLTE:
+            return (z <= old_z);
+        case DWGCTRL_ZMODE_ZGT:
+            return (z > old_z);
+        case DWGCTRL_ZMODE_ZGTE:
+            return (z >= old_z);
+
+        case DWGCTRL_ZMODE_NOZCMP:
+        default:
+            return 1;
+    }
+}
+
+static void
+blit_line(mystique_t *mystique, int closed, int autoline)
+{
+    svga_t  *svga = &mystique->svga;
+    uint32_t src = 0;
+    uint32_t dst;
+    uint32_t old_dst;
+    int      x = mystique->dwgreg.xdst;
+    int      z_write;
+    int      pattern_x, pattern_y;
+    bool     transc = !!(mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC);
+
+    switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) {
+        case DWGCTRL_ATYPE_RSTR:
+        case DWGCTRL_ATYPE_RPL:
+            while (mystique->dwgreg.length >= 0) {
+                if (x >= mystique->dwgreg.cxleft && x <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) {
+                    pattern_y = ((mystique->dwgreg.funcnt % (mystique->dwgreg.stylelen + 1)) >> 4) & 0x7;
+                    pattern_x = (mystique->dwgreg.funcnt % (mystique->dwgreg.stylelen + 1)) & 0xf;
+                    if (!transc || (transc && (mystique->dwgreg.pattern[pattern_y][pattern_x])))
+                    switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) {
+                        case MACCESS_PWIDTH_8:
+                            src = mystique->dwgreg.pattern[pattern_y][pattern_x] ? mystique->dwgreg.fcol : mystique->dwgreg.bcol;
+                            dst = svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask];
+
+                            dst                                                                              = bitop(src, dst, mystique->dwgreg.dwgctrl_running);
+                            if (closed) {
+                                svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask]                = dst;
+                                svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask) >> 12] = changeframecount;
+                            } else if (!closed && (mystique->dwgreg.length > 0) && ((mystique->dwgreg.err > 0) || (mystique->dwgreg.err < 0)) && !autoline) {
+                                svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask]                = dst;
+                                svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask) >> 12] = changeframecount;
+                            } else if (!closed && (mystique->dwgreg.length > 0) && autoline) {
+                                svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask]                = dst;
+                                svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask) >> 12] = changeframecount;
+                            }
+                            break;
+
+                        case MACCESS_PWIDTH_16:
+                            src = mystique->dwgreg.pattern[pattern_y][pattern_x] ? mystique->dwgreg.fcol : mystique->dwgreg.bcol;
+                            dst = ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w];
+
+                            dst                                                                                = bitop(src, dst, mystique->dwgreg.dwgctrl_running);
+                            if (closed) {
+                                ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = dst;
+                                svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w) >> 11] = changeframecount;
+                            } else if (!closed && (mystique->dwgreg.length > 0) && ((mystique->dwgreg.err > 0) || (mystique->dwgreg.err < 0)) && !autoline) {
+                                ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = dst;
+                                svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w) >> 11] = changeframecount;
+                            } else if (!closed && (mystique->dwgreg.length > 0) && autoline) {
+                                ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = dst;
+                                svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w) >> 11] = changeframecount;
+                            }
+                            break;
+
+                        case MACCESS_PWIDTH_24:
+                            src = mystique->dwgreg.pattern[pattern_y][pattern_x] ? mystique->dwgreg.fcol : mystique->dwgreg.bcol;
+                            old_dst = *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask];
+
+                            dst                                                                                    = bitop(src, old_dst, mystique->dwgreg.dwgctrl_running);
+                            if (closed) {
+                                *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = (dst & 0xffffff) | (old_dst & 0xff000000);
+                                svga->changedvram[(((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask) >> 12] = changeframecount;
+                            } else if (!closed && (mystique->dwgreg.length > 0) && ((mystique->dwgreg.err > 0) || (mystique->dwgreg.err < 0)) && !autoline) {
+                                *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = (dst & 0xffffff) | (old_dst & 0xff000000);
+                                svga->changedvram[(((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask) >> 12] = changeframecount;
+                            } else if (!closed && (mystique->dwgreg.length > 0) && autoline) {
+                                *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = (dst & 0xffffff) | (old_dst & 0xff000000);
+                                svga->changedvram[(((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask) >> 12] = changeframecount;
+                            }
+                            break;
+
+                        case MACCESS_PWIDTH_32:
+                            src = mystique->dwgreg.pattern[pattern_y][pattern_x] ? mystique->dwgreg.fcol : mystique->dwgreg.bcol;
+                            dst = ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l];
+
+                            dst                                                                                = bitop(src, dst, mystique->dwgreg.dwgctrl_running);
+                            if (closed) {
+                                ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l] = dst;
+                                svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l) >> 10] = changeframecount;
+                            } else if (!closed && (mystique->dwgreg.length > 0) && ((mystique->dwgreg.err > 0) || (mystique->dwgreg.err < 0)) && !autoline) {
+                                ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l] = dst;
+                                svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l) >> 10] = changeframecount;
+                            } else if (!closed && (mystique->dwgreg.length > 0) && autoline) {
+                                ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l] = dst;
+                                svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l) >> 10] = changeframecount;
+                            }
+                            break;
+
+                        default:
+                            fatal("LINE RSTR/RPL PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running);
+                    }
+                }
+
+                if (!mystique->dwgreg.length)
+                    break;
+
+                if (mystique->dwgreg.sgn.sdydxl)
+                    x += (mystique->dwgreg.sgn.sdxl ? -1 : 1);
+                else {
+                    mystique->dwgreg.ydst += (mystique->dwgreg.sgn.sdy ? -1 : 1);
+                    mystique->dwgreg.ydst &= 0x7fffff;
+                    mystique->dwgreg.ydst_lin += (mystique->dwgreg.sgn.sdy ? -(mystique->dwgreg.pitch & PITCH_MASK) : (mystique->dwgreg.pitch & PITCH_MASK));
+                }
+                if (mystique->dwgreg.err >= 0) {
+                    mystique->dwgreg.err += mystique->dwgreg.k2;
+                    if (mystique->dwgreg.sgn.sdydxl) {
+                        mystique->dwgreg.ydst += (mystique->dwgreg.sgn.sdy ? -1 : 1);
+                        mystique->dwgreg.ydst &= 0x7fffff;
+                        mystique->dwgreg.ydst_lin += (mystique->dwgreg.sgn.sdy ? -(mystique->dwgreg.pitch & PITCH_MASK) : (mystique->dwgreg.pitch & PITCH_MASK));
+                    } else
+                        x += (mystique->dwgreg.sgn.sdxl ? -1 : 1);
+                } else
+                    mystique->dwgreg.err += mystique->dwgreg.k1;
+
+                mystique->dwgreg.length--;
+                mystique->dwgreg.funcnt--;
+            }
+            break;
+
+        case DWGCTRL_ATYPE_I:
+        case DWGCTRL_ATYPE_ZI:
+            z_write = ((mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) == DWGCTRL_ATYPE_ZI);
+            while (mystique->dwgreg.length > 0) {
+                if (x >= mystique->dwgreg.cxleft && x <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) {
+                    bool z_check_pass = false;
+                    if (mystique->maccess_running & MACCESS_ZWIDTH) {
+                        uint32_t  z     = (mystique->dwgreg.extended_dr[0] & (1ull << 47ull)) ? 0 : (mystique->dwgreg.extended_dr[0] >> 15ull);
+                        uint32_t *z_p   = (uint32_t *) &svga->vram[(mystique->dwgreg.ydst_lin * 4 + mystique->dwgreg.zorg) & mystique->vram_mask];
+                        uint32_t  old_z = z_p[x];
+                        z_check_pass = z_check_32(z, old_z, mystique->dwgreg.dwgctrl_running & DWGCTRL_ZMODE_MASK);
+                        if (z_write && z_check_pass) {
+                            z_p[x] = z;
+                        }
+                    } else {
+                        uint16_t  z     = ((int32_t) mystique->dwgreg.dr[0] < 0) ? 0 : (mystique->dwgreg.dr[0] >> 15);
+                        uint16_t *z_p   = (uint16_t *) &svga->vram[(mystique->dwgreg.ydst_lin * 2 + mystique->dwgreg.zorg) & mystique->vram_mask];
+                        uint16_t  old_z = z_p[x];
+                        z_check_pass = z_check(z, old_z, mystique->dwgreg.dwgctrl_running & DWGCTRL_ZMODE_MASK);
+                        if (z_write && z_check_pass) {
+                            z_p[x] = z;
+                        }
+                    }
+
+                    if (z_check_pass) {
+                        int r = 0;
+                        int g = 0;
+                        int b = 0;
+
+                        switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) {
+                            case MACCESS_PWIDTH_8:
+                                if (!(mystique->dwgreg.dr[4] & (1 << 23)))
+                                    r = (mystique->dwgreg.dr[4] >> 20) & 0x7;
+                                if (!(mystique->dwgreg.dr[8] & (1 << 23)))
+                                    g = (mystique->dwgreg.dr[8] >> 20) & 0x7;
+                                if (!(mystique->dwgreg.dr[12] & (1 << 23)))
+                                    b = (mystique->dwgreg.dr[12] >> 21) & 0x3;
+                                dst = (r << 5) | (g << 2) | b;
+
+                                ((uint8_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask] = dst;
+                                svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask) >> 12] = changeframecount;
+                                break;
+
+                            case MACCESS_PWIDTH_16:
+                                if (!(mystique->dwgreg.dr[4] & (1 << 23)))
+                                    r = (mystique->dwgreg.dr[4] >> 18) & 0x1f;
+                                if (!(mystique->dwgreg.dr[8] & (1 << 23)))
+                                    g = (mystique->dwgreg.dr[8] >> 17) & 0x3f;
+                                if (!(mystique->dwgreg.dr[12] & (1 << 23)))
+                                    b = (mystique->dwgreg.dr[12] >> 18) & 0x1f;
+                                dst = (r << 11) | (g << 5) | b;
+
+                                ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = dst;
+                                svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w) >> 11] = changeframecount;
+                                break;
+
+                            case MACCESS_PWIDTH_24:
+                                old_dst = *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask];
+                                if (!(mystique->dwgreg.dr[4] & (1 << 23)))
+                                    r = (mystique->dwgreg.dr[4] >> 15) & 0xff;
+                                if (!(mystique->dwgreg.dr[8] & (1 << 23)))
+                                    g = (mystique->dwgreg.dr[8] >> 15) & 0xff;
+                                if (!(mystique->dwgreg.dr[12] & (1 << 23)))
+                                    b = (mystique->dwgreg.dr[12] >> 15) & 0xff;
+                                dst = (r << 16) | (g << 8) | b;
+
+                                ((uint32_t *) svga->vram)[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = dst | (old_dst & 0xFF000000);
+                                svga->changedvram[(((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask) >> 12] = changeframecount;
+                                break;
+
+                            case MACCESS_PWIDTH_32:
+                                if (!(mystique->dwgreg.dr[4] & (1 << 23)))
+                                    r = (mystique->dwgreg.dr[4] >> 15) & 0xff;
+                                if (!(mystique->dwgreg.dr[8] & (1 << 23)))
+                                    g = (mystique->dwgreg.dr[8] >> 15) & 0xff;
+                                if (!(mystique->dwgreg.dr[12] & (1 << 23)))
+                                    b = (mystique->dwgreg.dr[12] >> 15) & 0xff;
+                                dst = (r << 16) | (g << 8) | b;
+
+                                ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l] = dst;
+                                svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l) >> 10] = changeframecount;
+                                break;
+
+                            default:
+                                fatal("LINE I/ZI PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running);
+                        }
+                    }
+                }
+
+                if (mystique->dwgreg.sgn.sdydxl)
+                    x += (mystique->dwgreg.sgn.sdxl ? -1 : 1);
+                else
+                    mystique->dwgreg.ydst_lin += (mystique->dwgreg.sgn.sdy ? -(mystique->dwgreg.pitch & PITCH_MASK) : (mystique->dwgreg.pitch & PITCH_MASK));
+
+                if (mystique->maccess_running & MACCESS_ZWIDTH) {
+                    mystique->dwgreg.extended_dr[0] += mystique->dwgreg.extended_dr[2];
+                    mystique->dwgreg.dr[0] = (mystique->dwgreg.extended_dr[0] >> 16) & 0xFFFFFFFF;
+                } else {
+                    mystique->dwgreg.dr[0] += mystique->dwgreg.dr[2];
+                    mystique->dwgreg.extended_dr[0] = (mystique->dwgreg.extended_dr[0] & ~0xFFFFull) | ((uint64_t)mystique->dwgreg.dr[0] << 16ull);
+                }
+                mystique->dwgreg.dr[4] += mystique->dwgreg.dr[6];
+                mystique->dwgreg.dr[8] += mystique->dwgreg.dr[10];
+                mystique->dwgreg.dr[12] += mystique->dwgreg.dr[14];
+
+                if (mystique->dwgreg.err >= 0) {
+                    mystique->dwgreg.err += mystique->dwgreg.k2;
+
+                    if (mystique->dwgreg.sgn.sdydxl)
+                        mystique->dwgreg.ydst_lin += (mystique->dwgreg.sgn.sdy ? -(mystique->dwgreg.pitch & PITCH_MASK) : (mystique->dwgreg.pitch & PITCH_MASK));
+                    else
+                        x += (mystique->dwgreg.sgn.sdxl ? -1 : 1);
+
+                    if (mystique->maccess_running & MACCESS_ZWIDTH) {
+                        mystique->dwgreg.extended_dr[0] += mystique->dwgreg.extended_dr[3];
+                        mystique->dwgreg.dr[0] = (mystique->dwgreg.extended_dr[0] >> 16) & 0xFFFFFFFF;
+                    } else {
+                        mystique->dwgreg.dr[0] += mystique->dwgreg.dr[3];
+                        mystique->dwgreg.extended_dr[0] = (mystique->dwgreg.extended_dr[0] & ~0xFFFFull) | ((uint64_t)mystique->dwgreg.dr[0] << 16ull);
+                    }
+                    mystique->dwgreg.dr[4] += mystique->dwgreg.dr[7];
+                    mystique->dwgreg.dr[8] += mystique->dwgreg.dr[11];
+                    mystique->dwgreg.dr[12] += mystique->dwgreg.dr[15];
+                } else
+                    mystique->dwgreg.err += mystique->dwgreg.k1;
+
+                mystique->dwgreg.length--;
+            }
+            break;
+
+        default:
+#if 0
+            pclog("Unknown atype %03x %08x LINE\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running);
+#endif
+            break;
+    }
+
+    mystique->blitter_complete_refcount++;
+}
+
+static void
+blit_line_start(mystique_t *mystique, int closed, int autoline)
+{
+    int start_x = (int32_t) mystique->dwgreg.ar[5];
+    int start_y = (int32_t) mystique->dwgreg.ar[6];
+    int end_x   = (int32_t) mystique->dwgreg.ar[0];
+    int end_y   = (int32_t) mystique->dwgreg.ar[2];
+    int dx      = end_x - start_x;
+    int dy      = end_y - start_y;
+
+    if (autoline) {
+        if (ABS(dx) > ABS(dy)) {
+            mystique->dwgreg.sgn.sdydxl = 1;
+            mystique->dwgreg.k1         = 2 * ABS(dy);
+            mystique->dwgreg.err        = 2 * ABS(dy) - ABS(dx) - ((start_y > end_y) ? 1 : 0);
+            mystique->dwgreg.k2         = 2 * ABS(dy) - 2 * ABS(dx);
+            mystique->dwgreg.length     = ABS(end_x - start_x);
+        } else {
+            mystique->dwgreg.sgn.sdydxl = 0;
+            mystique->dwgreg.k1         = 2 * ABS(dx);
+            mystique->dwgreg.err        = 2 * ABS(dx) - ABS(dy) - ((start_y > end_y) ? 1 : 0);
+            mystique->dwgreg.k2         = 2 * ABS(dx) - 2 * ABS(dy);
+            mystique->dwgreg.length     = ABS(end_y - start_y);
+        }
+        mystique->dwgreg.sgn.sdxl = (start_x > end_x) ? 1 : 0;
+        mystique->dwgreg.sgn.sdy  = (start_y > end_y) ? 1 : 0;
+    } else {
+        mystique->dwgreg.k1  = (int32_t) mystique->dwgreg.ar[0];
+        mystique->dwgreg.err = (int32_t) mystique->dwgreg.ar[1];
+        mystique->dwgreg.k2  = (int32_t) mystique->dwgreg.ar[2];
+    }
+
+    blit_line(mystique, closed, autoline);
+
+    if (autoline) {
+        mystique->dwgreg.ar[5]    = end_x;
+        mystique->dwgreg.xdst     = end_x;
+        mystique->dwgreg.ar[6]    = end_y;
+        mystique->dwgreg.ydst     = end_y;
+        mystique->dwgreg.ydst_lin = ((int32_t) (int16_t) mystique->dwgreg.ydst * (mystique->dwgreg.pitch & PITCH_MASK)) + mystique->dwgreg.ydstorg;
+    }
+}
+
+static void
+blit_trap(mystique_t *mystique)
+{
+    svga_t   *svga = &mystique->svga;
+    uint64_t  z_back_32;
+    uint32_t  z_back;
+    uint32_t  r_back;
+    uint32_t  g_back;
+    uint32_t  b_back;
+    int       z_write;
+    int       y;
+    int       err_l = (int32_t)mystique->dwgreg.ar[1];
+    int       err_r = (int32_t)mystique->dwgreg.ar[4];
+    const int trans_sel = (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANS_MASK) >> DWGCTRL_TRANS_SHIFT;
+
+    switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) {
+        case DWGCTRL_ATYPE_BLK:
+        case DWGCTRL_ATYPE_RPL:
+            for (y = 0; y < mystique->dwgreg.length; y++) {
+                uint8_t const *const trans = &trans_masks[trans_sel][(mystique->dwgreg.selline & 3) * 4];
+                int16_t              x_l   = mystique->dwgreg.fxleft & 0xffff;
+                int16_t              x_r   = mystique->dwgreg.fxright & 0xffff;
+                int                  yoff  = (mystique->dwgreg.yoff + mystique->dwgreg.ydst) & 7;
+                int                  len;
+
+                if (x_l > x_r)
+                    len = x_l - x_r;
+                else
+                    len = x_r - x_l;
+
+                while (len > 0) {
+                    if (x_l >= mystique->dwgreg.cxleft && x_l <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && trans[x_l & 3]) {
+                        int      xoff    = (mystique->dwgreg.xoff + (x_l & 7)) & 15;
+                        int      pattern = mystique->dwgreg.pattern[yoff][xoff];
+                        uint32_t dst;
+
+                        switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) {
+                            case MACCESS_PWIDTH_8:
+                                svga->vram[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask]                = (pattern ? mystique->dwgreg.fcol : mystique->dwgreg.bcol) & 0xff;
+                                svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask) >> 12] = changeframecount;
+                                break;
+
+                            case MACCESS_PWIDTH_16:
+                                ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w] = (pattern ? mystique->dwgreg.fcol : mystique->dwgreg.bcol) & 0xffff;
+                                svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w) >> 11] = changeframecount;
+                                break;
+
+                            case MACCESS_PWIDTH_24:
+                                dst                                                                                        = *(uint32_t *) (&svga->vram[((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask]) & 0xff000000;
+                                *(uint32_t *) (&svga->vram[((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask]) = ((pattern ? mystique->dwgreg.fcol : mystique->dwgreg.bcol) & 0xffffff) | dst;
+                                svga->changedvram[(((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask) >> 12]   = changeframecount;
+                                break;
+
+                            case MACCESS_PWIDTH_32:
+                                ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l] = pattern ? mystique->dwgreg.fcol : mystique->dwgreg.bcol;
+                                svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l) >> 10] = changeframecount;
+                                break;
+
+                            default:
+                                fatal("TRAP BLK/RPL PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running);
+                        }
+                    }
+                    len--;
+                    x_l++;
+                }
+
+                while ((err_l < 0) && mystique->dwgreg.ar[0]) {
+                    err_l += mystique->dwgreg.ar[0];
+                    mystique->dwgreg.fxleft += (mystique->dwgreg.sgn.sdxl ? -1 : 1);
+                }
+                err_l += mystique->dwgreg.ar[2];
+
+                while ((err_r < 0) && mystique->dwgreg.ar[6]) {
+                    err_r += mystique->dwgreg.ar[6];
+                    mystique->dwgreg.fxright += (mystique->dwgreg.sgn.sdxr ? -1 : 1);
+                }
+                err_r += mystique->dwgreg.ar[5];
+
+                mystique->dwgreg.ydst++;
+                mystique->dwgreg.ydst &= 0x7fffff;
+                mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK);
+
+                mystique->dwgreg.selline = (mystique->dwgreg.selline + 1) & 7;
+            }
+            break;
+
+        case DWGCTRL_ATYPE_RSTR:
+            for (y = 0; y < mystique->dwgreg.length; y++) {
+                uint8_t const *const trans = &trans_masks[trans_sel][(mystique->dwgreg.selline & 3) * 4];
+                int16_t              x_l   = mystique->dwgreg.fxleft & 0xffff;
+                int16_t              x_r   = mystique->dwgreg.fxright & 0xffff;
+                int                  yoff  = (mystique->dwgreg.yoff + mystique->dwgreg.ydst) & 7;
+                int                  len;
+
+                if (x_l > x_r)
+                    len = x_l - x_r;
+                else
+                    len = x_r - x_l;
+
+                while (len > 0) {
+                    if (x_l >= mystique->dwgreg.cxleft && x_l <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && trans[x_l & 3]) {
+                        int      xoff    = (mystique->dwgreg.xoff + (x_l & 7)) & 15;
+                        int      pattern = mystique->dwgreg.pattern[yoff][xoff];
+                        uint32_t src     = pattern ? mystique->dwgreg.fcol : mystique->dwgreg.bcol;
+                        uint32_t dst;
+                        uint32_t old_dst;
+
+                        switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) {
+                            case MACCESS_PWIDTH_8:
+                                dst = svga->vram[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask];
+
+                                dst                                                                                = bitop(src, dst, mystique->dwgreg.dwgctrl_running);
+                                svga->vram[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask]                = dst;
+                                svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask) >> 12] = changeframecount;
+                                break;
+
+                            case MACCESS_PWIDTH_16:
+                                dst = ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w];
+
+                                dst                                                                                  = bitop(src, dst, mystique->dwgreg.dwgctrl_running);
+                                ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w] = dst;
+                                svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w) >> 11] = changeframecount;
+                                break;
+
+                            case MACCESS_PWIDTH_24:
+                                old_dst = *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask];
+
+                                dst                                                                                      = bitop(src, old_dst, mystique->dwgreg.dwgctrl_running);
+                                *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask] = (dst & 0xffffff) | (old_dst & 0xff000000);
+                                svga->changedvram[(((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask) >> 12] = changeframecount;
+                                break;
+
+                            case MACCESS_PWIDTH_32:
+                                dst = ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l];
+
+                                dst                                                                                  = bitop(src, dst, mystique->dwgreg.dwgctrl_running);
+                                ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l] = dst;
+                                svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l) >> 10] = changeframecount;
+                                break;
+
+                            default:
+                                fatal("TRAP RSTR PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running);
+                        }
+                    }
+                    x_l++;
+                    len--;
+                }
+
+                while ((err_l < 0) && mystique->dwgreg.ar[0]) {
+                    err_l += mystique->dwgreg.ar[0];
+                    mystique->dwgreg.fxleft += (mystique->dwgreg.sgn.sdxl ? -1 : 1);
+                }
+                err_l += mystique->dwgreg.ar[2];
+
+                while ((err_r < 0) && mystique->dwgreg.ar[6]) {
+                    err_r += mystique->dwgreg.ar[6];
+                    mystique->dwgreg.fxright += (mystique->dwgreg.sgn.sdxr ? -1 : 1);
+                }
+                err_r += mystique->dwgreg.ar[5];
+
+                mystique->dwgreg.ydst++;
+                mystique->dwgreg.ydst &= 0x7fffff;
+                mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK);
+
+                mystique->dwgreg.selline = (mystique->dwgreg.selline + 1) & 7;
+            }
+            break;
+
+        case DWGCTRL_ATYPE_I:
+        case DWGCTRL_ATYPE_ZI:
+            z_write = ((mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) == DWGCTRL_ATYPE_ZI);
+
+            for (y = 0; y < mystique->dwgreg.length; y++) {
+                uint8_t const *const trans   = &trans_masks[trans_sel][(mystique->dwgreg.selline & 3) * 4];
+                uint16_t            *z_p     = (uint16_t *) &svga->vram[(mystique->dwgreg.ydst_lin * ((mystique->maccess_running & MACCESS_ZWIDTH) ? 4 : 2) + mystique->dwgreg.zorg) & mystique->vram_mask];
+                int16_t              x_l     = mystique->dwgreg.fxleft & 0xffff;
+                int16_t              x_r     = mystique->dwgreg.fxright & 0xffff;
+                int16_t              old_x_l = x_l;
+                int                  dx;
+
+                z_back_32 = mystique->dwgreg.extended_dr[0];
+
+                z_back = mystique->dwgreg.dr[0];
+                r_back = mystique->dwgreg.dr[4];
+                g_back = mystique->dwgreg.dr[8];
+                b_back = mystique->dwgreg.dr[12];
+
+                while (x_l != x_r) {
+                    if (x_l >= mystique->dwgreg.cxleft && x_l <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && trans[x_l & 3]) {
+                        bool z_check_pass = false;
+                        if (mystique->maccess_running & MACCESS_ZWIDTH) {
+                            uint32_t z     = (mystique->dwgreg.extended_dr[0] & (1ull << 47ull)) ? 0 : (mystique->dwgreg.extended_dr[0] >> 15ull);
+                            uint32_t old_z = *(uint32_t*)&z_p[x_l * 2];
+                            z_check_pass = z_check_32(z, old_z, mystique->dwgreg.dwgctrl_running & DWGCTRL_ZMODE_MASK);
+                        } else {
+                            uint16_t z     = ((int32_t) mystique->dwgreg.dr[0] < 0) ? 0 : (mystique->dwgreg.dr[0] >> 15);
+                            uint16_t old_z = z_p[x_l];
+                            z_check_pass = z_check(z, old_z, mystique->dwgreg.dwgctrl_running & DWGCTRL_ZMODE_MASK);
+                        }
+
+                        if (z_check_pass) {
+                            uint32_t dst = 0;
+                            uint32_t old_dst;
+                            int      r = 0;
+                            int      g = 0;
+                            int      b = 0;
+
+                            if (!(mystique->dwgreg.dr[4] & (1 << 23)))
+                                r = (mystique->dwgreg.dr[4] >> 15) & 0xff;
+                            if (!(mystique->dwgreg.dr[8] & (1 << 23)))
+                                g = (mystique->dwgreg.dr[8] >> 15) & 0xff;
+                            if (!(mystique->dwgreg.dr[12] & (1 << 23)))
+                                b = (mystique->dwgreg.dr[12] >> 15) & 0xff;
+
+                            if (z_write) {
+                                if (mystique->maccess_running & MACCESS_ZWIDTH) {
+                                    *(uint32_t*)(&z_p[x_l * 2]) = (mystique->dwgreg.extended_dr[0] & (1ull << 47ull)) ? 0 : (mystique->dwgreg.extended_dr[0] >> 15ull);
+                                }
+                                else
+                                    z_p[x_l] = ((int32_t) mystique->dwgreg.dr[0] < 0) ? 0 : (mystique->dwgreg.dr[0] >> 15);
+                            }
+
+                            switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) {
+                                case MACCESS_PWIDTH_8:
+                                    svga->vram[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask]                = dst;
+                                    svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask) >> 12] = changeframecount;
+                                    break;
+
+                                case MACCESS_PWIDTH_16:
+                                    dst                                                                                  = dither(mystique, r, g, b, x_l & 1, mystique->dwgreg.selline & 1);
+                                    ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w] = dst;
+                                    svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w) >> 11] = changeframecount;
+                                    break;
+
+                                case MACCESS_PWIDTH_24:
+                                    old_dst                                                                                    = *(uint32_t *) (&svga->vram[((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask]) & 0xff000000;
+                                    *(uint32_t *) (&svga->vram[((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask]) = old_dst | dst;
+                                    svga->changedvram[(((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask) >> 12]   = changeframecount;
+                                    break;
+
+                                case MACCESS_PWIDTH_32:
+                                    ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l] = b | (g << 8) | (r << 16);
+                                    svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l) >> 10] = changeframecount;
+                                    break;
+
+                                default:
+                                    fatal("TRAP BLK/RPL PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running);
+                            }
+                        }
+                    }
+
+                    if (mystique->maccess_running & MACCESS_ZWIDTH) {
+                        mystique->dwgreg.extended_dr[0] += mystique->dwgreg.extended_dr[2];
+                        mystique->dwgreg.dr[0] = (mystique->dwgreg.extended_dr[0] >> 16) & 0xFFFFFFFF;
+                    } else {
+                        mystique->dwgreg.dr[0] += mystique->dwgreg.dr[2];
+                        mystique->dwgreg.extended_dr[0] = (mystique->dwgreg.extended_dr[0] & ~0xFFFFull) | ((uint64_t)mystique->dwgreg.dr[0] << 16ull);
+                    }
+                    mystique->dwgreg.dr[4] += mystique->dwgreg.dr[6];
+                    mystique->dwgreg.dr[8] += mystique->dwgreg.dr[10];
+                    mystique->dwgreg.dr[12] += mystique->dwgreg.dr[14];
+
+                    if (x_l > x_r)
+                        x_l--;
+                    else
+                        x_l++;
+                }
+
+                if (mystique->maccess_running & MACCESS_ZWIDTH) {
+                    mystique->dwgreg.extended_dr[0] = z_back_32 + mystique->dwgreg.extended_dr[3];
+                    mystique->dwgreg.dr[0] = (mystique->dwgreg.extended_dr[0] >> 16) & 0xFFFFFFFF;
+                } else {
+                    mystique->dwgreg.dr[0] = z_back + mystique->dwgreg.dr[3];
+                    mystique->dwgreg.extended_dr[0] = (mystique->dwgreg.extended_dr[0] & ~0xFFFFull) | ((uint64_t)mystique->dwgreg.dr[0] << 16ull);
+                }
+                mystique->dwgreg.dr[4]  = r_back + mystique->dwgreg.dr[7];
+                mystique->dwgreg.dr[8]  = g_back + mystique->dwgreg.dr[11];
+                mystique->dwgreg.dr[12] = b_back + mystique->dwgreg.dr[15];
+
+                while ((int32_t) mystique->dwgreg.ar[1] < 0 && mystique->dwgreg.ar[0]) {
+                    mystique->dwgreg.ar[1] += mystique->dwgreg.ar[0];
+                    mystique->dwgreg.fxleft += (mystique->dwgreg.sgn.sdxl ? -1 : 1);
+                }
+                mystique->dwgreg.ar[1] += mystique->dwgreg.ar[2];
+
+                while ((int32_t) mystique->dwgreg.ar[4] < 0 && mystique->dwgreg.ar[6]) {
+                    mystique->dwgreg.ar[4] += mystique->dwgreg.ar[6];
+                    mystique->dwgreg.fxright += (mystique->dwgreg.sgn.sdxr ? -1 : 1);
+                }
+                mystique->dwgreg.ar[4] += mystique->dwgreg.ar[5];
+
+                dx = (int16_t) ((mystique->dwgreg.fxleft - old_x_l) & 0xffff);
+                if (mystique->maccess_running & MACCESS_ZWIDTH) {
+                    mystique->dwgreg.extended_dr[0] += dx * mystique->dwgreg.extended_dr[2];
+                    mystique->dwgreg.dr[0] = (mystique->dwgreg.extended_dr[0] >> 16) & 0xFFFFFFFF;
+                } else {
+                    mystique->dwgreg.dr[0] += dx * mystique->dwgreg.dr[2];
+                    mystique->dwgreg.extended_dr[0] = (mystique->dwgreg.extended_dr[0] & ~0xFFFFull) | ((uint64_t)mystique->dwgreg.dr[0] << 16ull);
+                }
+                mystique->dwgreg.dr[4] += dx * mystique->dwgreg.dr[6];
+                mystique->dwgreg.dr[8] += dx * mystique->dwgreg.dr[10];
+                mystique->dwgreg.dr[12] += dx * mystique->dwgreg.dr[14];
+
+                mystique->dwgreg.ydst++;
+                mystique->dwgreg.ydst &= 0x7fffff;
+                mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK);
+
+                mystique->dwgreg.selline = (mystique->dwgreg.selline + 1) & 7;
+            }
+            break;
+
+        default:
+#if 0
+            pclog("Unknown atype %03x %08x TRAP\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running);
+#endif
+            break;
+    }
+
+    mystique->blitter_complete_refcount++;
+}
+
+static uint16_t texture_texel_fetch(mystique_t *mystique, int *tex_r, int *tex_g, int *tex_b, int *tex_a, int *atransp, int s, int t, int tex_pitch)
+{
+    const unsigned int w_mask    = (mystique->dwgreg.texwidth & TEXWIDTH_TWMASK_MASK) >> TEXWIDTH_TWMASK_SHIFT;
+    const unsigned int h_mask    = (mystique->dwgreg.texheight & TEXHEIGHT_THMASK_MASK) >> TEXHEIGHT_THMASK_SHIFT;
+    const unsigned int palsel    = mystique->dwgreg.texctl & TEXCTL_PALSEL_MASK;
+    svga_t*            svga      = &mystique->svga;
+    uint16_t           src       = 0x0;
+
+    int atransp_dummy = 0;
+
+    if (!atransp)
+        atransp = &atransp_dummy;
+
+    if (mystique->dwgreg.texctl & TEXCTL_CLAMPU) {
+        if (s < 0)
+            s = 0;
+        else if (s > w_mask)
+            s = w_mask;
+    } else
+        s &= w_mask;
+
+    if (mystique->dwgreg.texctl & TEXCTL_CLAMPV) {
+        if (t < 0)
+            t = 0;
+        else if (t > h_mask)
+            t = h_mask;
+    } else
+        t &= h_mask;
+
+    switch (mystique->dwgreg.texctl & TEXCTL_TEXFORMAT_MASK) {
+        case TEXCTL_TEXFORMAT_TW4:
+            src = svga->vram[(mystique->dwgreg.texorg + (((t * tex_pitch) + s) >> 1)) & mystique->vram_mask];
+            if (s & 1)
+                src >>= 4;
+            else
+                src &= 0xf;
+            *tex_r   = mystique->lut[src | palsel].r;
+            *tex_g   = mystique->lut[src | palsel].g;
+            *tex_b   = mystique->lut[src | palsel].b;
+            *atransp = 0;
+            break;
+        case TEXCTL_TEXFORMAT_TW8:
+            src      = svga->vram[(mystique->dwgreg.texorg + (t * tex_pitch) + s) & mystique->vram_mask];
+            *tex_r   = mystique->lut[src].r;
+            *tex_g   = mystique->lut[src].g;
+            *tex_b   = mystique->lut[src].b;
+            *atransp = 0;
+            break;
+        case TEXCTL_TEXFORMAT_TW15:
+            src    = ((uint16_t *) svga->vram)[((mystique->dwgreg.texorg >> 1) + (t * tex_pitch) + s) & mystique->vram_mask_w];
+            *tex_r = ((src >> 10) & 0x1f) << 3;
+            *tex_g = ((src >> 5) & 0x1f) << 3;
+            *tex_b = (src & 0x1f) << 3;
+            if (((src >> 15) & mystique->dwgreg.ta_mask) == mystique->dwgreg.ta_key)
+                *atransp = 1;
+            else
+                *atransp = 0;
+            break;
+        case TEXCTL_TEXFORMAT_TW12:
+            src    = ((uint16_t *) svga->vram)[((mystique->dwgreg.texorg >> 1) + (t * tex_pitch) + s) & mystique->vram_mask_w];
+            *tex_r = ((src >> 8) & 0xf) << 4;
+            *tex_g = ((src >> 4) & 0xf) << 4;
+            *tex_b = (src & 0xf) << 4;
+            *tex_a = ((src >> 12) & 0xf) << 4;
+            if (mystique->dwgreg.texctl & TEXCTL_AZEROEXTEND) {
+                *atransp = (((src >> 12) & 0xf) & mystique->dwgreg.ta_mask)  == mystique->dwgreg.ta_key;
+            } else {
+                uint8_t ta_mask = mystique->dwgreg.ta_mask ? 0xf : 0x0;
+                uint8_t ta_key = mystique->dwgreg.ta_key ? 0xf : 0x0;
+                *atransp = (((src >> 12) & 0xf) & ta_mask) == ta_key;
+            }
+            break;
+        case TEXCTL_TEXFORMAT_TW16:
+            src      = ((uint16_t *) svga->vram)[((mystique->dwgreg.texorg >> 1) + (t * tex_pitch) + s) & mystique->vram_mask_w];
+            *tex_r   = (src >> 11) << 3;
+            *tex_g   = ((src >> 5) & 0x3f) << 2;
+            *tex_b   = (src & 0x1f) << 3;
+            *atransp = 0;
+            break;
+        default:
+            fatal("Unknown texture format %i\n", mystique->dwgreg.texctl & TEXCTL_TEXFORMAT_MASK);
+            break;
+    }
+    return src;
+}
+
+static double lerp(double v0, double v1, double t) {
+  return (1. - t) * v0 + t * v1;
+}
+
+static int
+texture_read(mystique_t *mystique, int *tex_r, int *tex_g, int *tex_b, int *atransp, int *tex_a)
+{
+    const int          tex_shift = 3 + ((mystique->dwgreg.texctl & TEXCTL_TPITCH_MASK) >> TEXCTL_TPITCH_SHIFT);
+    const uint16_t     tckey     = mystique->dwgreg.textrans & TEXTRANS_TCKEY_MASK;
+    const uint16_t     tkmask    = (mystique->dwgreg.textrans & TEXTRANS_TKMASK_MASK) >> TEXTRANS_TKMASK_SHIFT;
+    const unsigned int w_mask    = (mystique->dwgreg.texwidth & TEXWIDTH_TWMASK_MASK) >> TEXWIDTH_TWMASK_SHIFT;
+    const unsigned int h_mask    = (mystique->dwgreg.texheight & TEXHEIGHT_THMASK_MASK) >> TEXHEIGHT_THMASK_SHIFT;
+    uint16_t           src       = 0;
+    int                s;
+    int                t;
+    int                tex_pitch = 1 << tex_shift;
+    double             s_frac = 0;
+    double             t_frac = 0;
+
+    *tex_a = 255;
+
+    if (mystique->type >= MGA_G100 && (mystique->dwgreg.texctl & TEXCTL_TPITCHLIN))
+    {
+        tex_pitch = (mystique->dwgreg.texctl & TEXCTL_TPITCHEXT_MASK) >> 9;
+        if (tex_pitch == 0)
+            tex_pitch = 2048;
+    }
+
+    if (mystique->dwgreg.texctl & TEXCTL_NPCEN) {
+        const int s_shift = 20 - (mystique->dwgreg.texwidth & TEXWIDTH_TW_MASK);
+        const int t_shift = 20 - (mystique->dwgreg.texheight & TEXHEIGHT_TH_MASK);
+
+        s = (int32_t) mystique->dwgreg.tmr[6] >> s_shift;
+        t = (int32_t) mystique->dwgreg.tmr[7] >> t_shift;
+        s_frac = (((int32_t) mystique->dwgreg.tmr[6]) & ((1 << s_shift) - 1)) / (double)(1 << s_shift);
+        t_frac = (((int32_t) mystique->dwgreg.tmr[7]) & ((1 << t_shift) - 1)) / (double)(1 << t_shift);
+    } else {
+        const int s_shift = (20 + 16) - (mystique->dwgreg.texwidth & TEXWIDTH_TW_MASK);
+        const int t_shift = (20 + 16) - (mystique->dwgreg.texheight & TEXHEIGHT_TH_MASK);
+        int64_t   q       = mystique->dwgreg.tmr[8] ? (0x100000000LL / (int64_t) (int32_t) mystique->dwgreg.tmr[8]) : 0;
+
+        s = ((int64_t) (int32_t) mystique->dwgreg.tmr[6] * q) >> s_shift;
+        t = ((int64_t) (int32_t) mystique->dwgreg.tmr[7] * q) >> t_shift;
+        s_frac = (((int64_t) (int32_t) mystique->dwgreg.tmr[6] * q) & ((1 << s_shift) - 1)) / (double)(1 << s_shift);
+        t_frac = (((int64_t) (int32_t) mystique->dwgreg.tmr[7] * q) & ((1 << t_shift) - 1)) / (double)(1 << t_shift);
+    }
+
+    if (mystique->dwgreg.texctl & TEXCTL_CLAMPU) {
+        if (s < 0)
+            s = 0;
+        else if (s > w_mask)
+            s = w_mask;
+    } else
+        s &= w_mask;
+
+    if (mystique->dwgreg.texctl & TEXCTL_CLAMPV) {
+        if (t < 0)
+            t = 0;
+        else if (t > h_mask)
+            t = h_mask;
+    } else
+        t &= h_mask;
+
+    src = texture_texel_fetch(mystique, tex_r, tex_g, tex_b, tex_a, atransp, s, t, tex_pitch);
+    switch (mystique->dwgreg.texfilter & 3)
+    {
+        case 0:
+            s_frac = t_frac = 0;
+            break;
+        case 1:
+        case 2:
+            break;
+        case 3:
+            s_frac = t_frac = .25;
+            break;
+    }
+    if (s_frac && s != w_mask)
+    {
+        int s_tex_r = 0, s_tex_g = 0, s_tex_b = 0, s_tex_a = 255;
+        texture_texel_fetch(mystique, &s_tex_r, &s_tex_g, &s_tex_b, &s_tex_a, NULL, s + 1, t, tex_pitch);
+        *tex_r = (int)lerp(*tex_r, s_tex_r, s_frac);
+        *tex_g = (int)lerp(*tex_g, s_tex_g, s_frac);
+        *tex_b = (int)lerp(*tex_b, s_tex_b, s_frac);
+        *tex_a = (int)lerp(*tex_a, s_tex_a, s_frac);
+        if (*tex_r > 255) *tex_r = 255;
+        if (*tex_g > 255) *tex_g = 255;
+        if (*tex_b > 255) *tex_b = 255;
+        if (*tex_a > 255) *tex_a = 255;
+    }
+    if (t_frac && t != h_mask)
+    {
+        int t_tex_r = 0, t_tex_g = 0, t_tex_b = 0, t_tex_a = 255;
+        texture_texel_fetch(mystique, &t_tex_r, &t_tex_g, &t_tex_b, &t_tex_a, NULL, s, t + 1, tex_pitch);
+        *tex_r = (int)lerp(*tex_r, t_tex_r, t_frac);
+        *tex_g = (int)lerp(*tex_g, t_tex_g, t_frac);
+        *tex_b = (int)lerp(*tex_b, t_tex_b, t_frac);
+        *tex_a = (int)lerp(*tex_a, t_tex_a, t_frac);
+        if (*tex_r > 255) *tex_r = 255;
+        if (*tex_g > 255) *tex_g = 255;
+        if (*tex_b > 255) *tex_b = 255;
+        if (*tex_a > 255) *tex_a = 255;
+    }
+
+    return ((src & tkmask) == tckey);
+}
+
+static void
+blit_texture_trap(mystique_t *mystique)
+{
+    svga_t   *svga = &mystique->svga;
+    int       y;
+    int       z_write;
+    const int trans_sel = (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANS_MASK) >> DWGCTRL_TRANS_SHIFT;
+    const int dest32    = ((mystique->maccess_running & MACCESS_PWIDTH_MASK) == MACCESS_PWIDTH_32);
+
+    switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) {
+        case DWGCTRL_ATYPE_I:
+        case DWGCTRL_ATYPE_ZI:
+            z_write = ((mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) == DWGCTRL_ATYPE_ZI);
+
+            for (y = 0; y < mystique->dwgreg.length; y++) {
+                uint8_t const *const trans   = &trans_masks[trans_sel][(mystique->dwgreg.selline & 3) * 4];
+                uint16_t            *z_p     = (uint16_t *) &svga->vram[(mystique->dwgreg.ydst_lin * ((mystique->maccess_running & MACCESS_ZWIDTH) ? 4 : 2) + mystique->dwgreg.zorg) & mystique->vram_mask];
+                int16_t              x_l     = mystique->dwgreg.fxleft & 0xffff;
+                int16_t              x_r     = mystique->dwgreg.fxright & 0xffff;
+                int16_t              old_x_l = x_l;
+                int                  dx;
+
+                uint64_t z_back_32 = mystique->dwgreg.extended_dr[0];
+
+                uint32_t z_back = mystique->dwgreg.dr[0];
+                uint32_t r_back = mystique->dwgreg.dr[4];
+                uint32_t g_back = mystique->dwgreg.dr[8];
+                uint32_t b_back = mystique->dwgreg.dr[12];
+                uint32_t s_back = mystique->dwgreg.tmr[6];
+                uint32_t t_back = mystique->dwgreg.tmr[7];
+                uint32_t q_back = mystique->dwgreg.tmr[8];
+                uint32_t a_back = mystique->dwgreg.alphastart;
+                uint32_t fog_back = mystique->dwgreg.fogstart;
+
+                while (x_l != x_r) {
+                    if (x_l >= mystique->dwgreg.cxleft && x_l <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && trans[x_l & 3]) {
+                        bool z_check_pass = false;
+                        if (mystique->maccess_running & MACCESS_ZWIDTH) {
+                            uint32_t z     = (mystique->dwgreg.extended_dr[0] & (1ull << 47ull)) ? 0 : (mystique->dwgreg.extended_dr[0] >> 15ull);
+                            uint32_t old_z = *(uint32_t*)&z_p[x_l * 2];
+                            z_check_pass = z_check_32(z, old_z, mystique->dwgreg.dwgctrl_running & DWGCTRL_ZMODE_MASK);
+                        } else {
+                            uint16_t z     = ((int32_t) mystique->dwgreg.dr[0] < 0) ? 0 : (mystique->dwgreg.dr[0] >> 15);
+                            uint16_t old_z = z_p[x_l];
+                            z_check_pass = z_check(z, old_z, mystique->dwgreg.dwgctrl_running & DWGCTRL_ZMODE_MASK);
+                        }
+
+                        if (z_check_pass) {
+                            int tex_r = 0;
+                            int tex_g = 0;
+                            int tex_b = 0;
+                            int tex_a = 255;
+                            int ctransp;
+                            int atransp = 0;
+                            int i_r = 0;
+                            int i_g = 0;
+                            int i_b = 0;
+                            int i_a = 255;
+                            int i_fog = 0;
+                            uint8_t final_a = 255;
+
+                            if (!(mystique->dwgreg.dr[4] & (1 << 23)))
+                                i_r = (mystique->dwgreg.dr[4] >> 15) & 0xff;
+                            if (!(mystique->dwgreg.dr[8] & (1 << 23)))
+                                i_g = (mystique->dwgreg.dr[8] >> 15) & 0xff;
+                            if (!(mystique->dwgreg.dr[12] & (1 << 23)))
+                                i_b = (mystique->dwgreg.dr[12] >> 15) & 0xff;
+
+                            if (mystique->type >= MGA_G100)
+                            {
+                                if (!(mystique->dwgreg.alphastart & (1 << 23)))
+                                    i_a = (mystique->dwgreg.alphastart >> 15) & 0xff;
+                                else
+                                    i_a = 0;
+
+                                if (!(mystique->dwgreg.fogstart & (1 << 23)))
+                                    i_fog = (mystique->dwgreg.fogstart >> 15) & 0xff;
+                                else
+                                    i_fog = 0;
+                            }
+
+                            ctransp = texture_read(mystique, &tex_r, &tex_g, &tex_b, &atransp, &tex_a);
+
+                            if (mystique->type >= MGA_G100)
+                            {
+                                uint8_t alpha_sel = (mystique->dwgreg.alphactrl >> 24) & 3;
+
+                                switch (alpha_sel)
+                                {
+                                    case 0x0: /* alpha from texture */
+                                        final_a = tex_a;
+                                        break;
+                                    default:
+                                    case 0x1: /* interpolated alpha */
+                                        if ((mystique->dwgreg.alphactrl & (1 << 11)))
+                                            final_a = i_a;
+                                        break;
+                                    case 0x2: /* modulated alpha */
+                                        if (!(mystique->dwgreg.alphactrl & (1 << 11)))
+                                            final_a = tex_a;
+                                        else
+                                            final_a = ((i_a * tex_a) >> 8) & 0xFF;
+                                        break;
+                                }
+                            }
+
+                            switch (mystique->dwgreg.texctl & (TEXCTL_TMODULATE | TEXCTL_STRANS | TEXCTL_ITRANS | TEXCTL_DECALCKEY)) {
+                                case 0:
+                                    if (ctransp)
+                                        goto skip_pixel;
+                                    if (atransp) {
+                                        tex_r = i_r;
+                                        tex_g = i_g;
+                                        tex_b = i_b;
+                                    }
+                                    break;
+
+                                case TEXCTL_DECALCKEY:
+                                    if (ctransp) {
+                                        tex_r = i_r;
+                                        tex_g = i_g;
+                                        tex_b = i_b;
+                                    }
+                                    break;
+
+                                case (TEXCTL_STRANS | TEXCTL_DECALCKEY):
+                                    if (ctransp)
+                                        goto skip_pixel;
+                                    break;
+
+                                case TEXCTL_TMODULATE:
+                                    if (ctransp)
+                                        goto skip_pixel;
+                                    if (mystique->dwgreg.texctl & TEXCTL_TMODULATE) {
+                                        tex_r = (tex_r * i_r) >> 8;
+                                        tex_g = (tex_g * i_g) >> 8;
+                                        tex_b = (tex_b * i_b) >> 8;
+                                    }
+                                    break;
+
+                                case (TEXCTL_TMODULATE | TEXCTL_STRANS):
+                                    if (ctransp || atransp)
+                                        goto skip_pixel;
+                                    if (mystique->dwgreg.texctl & TEXCTL_TMODULATE) {
+                                        tex_r = (tex_r * i_r) >> 8;
+                                        tex_g = (tex_g * i_g) >> 8;
+                                        tex_b = (tex_b * i_b) >> 8;
+                                    }
+                                    break;
+
+                                case (TEXCTL_STRANS | TEXCTL_ITRANS | TEXCTL_DECALCKEY):
+                                    if (!ctransp)
+                                        goto skip_pixel;
+
+                                    tex_r = i_r;
+                                    tex_g = i_g;
+                                    tex_b = i_b;
+                                    break;
+
+                                default:
+                                    fatal("Bad TEXCTL %08x %08x\n", mystique->dwgreg.texctl, mystique->dwgreg.texctl & (TEXCTL_TMODULATE | TEXCTL_STRANS | TEXCTL_ITRANS | TEXCTL_DECALCKEY));
+                            }
+
+                            if (mystique->type >= MGA_G100 && (mystique->maccess_running & MACCESS_FOGEN))
+                            {
+                                tex_r = (tex_r * ((i_fog) / 255.)) + (mystique->dwgreg.fogcol >> 16) * ((255 - i_fog) / 255.);
+                                tex_g = (tex_g * ((i_fog) / 255.)) + ((mystique->dwgreg.fogcol >> 8) & 0xFF) * ((255 - i_fog) / 255.);
+                                tex_b = (tex_b * ((i_fog) / 255.)) + ((mystique->dwgreg.fogcol) & 0xFF) * ((255 - i_fog) / 255.);
+                            }
+
+                            if (final_a != 255)
+                            {
+                                {
+                                    double threshold = bayer_mat[mystique->dwgreg.selline & 3][x_l & 3];
+                                    double final_a_frac = (final_a) / 255.;
+                                    if (final_a_frac >= threshold) {
+                                        final_a = 255;
+                                    } else {
+                                        goto skip_pixel;
+                                    }
+                                }
+                            }
+
+                            if (dest32) {
+                                ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l] = tex_b | (tex_g << 8) | (tex_r << 16);
+                                svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l) >> 10] = changeframecount;
+                            } else {
+                                ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w] = dither(mystique, tex_r, tex_g, tex_b, x_l & 1, mystique->dwgreg.selline & 1);
+                                svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w) >> 11] = changeframecount;
+                            }
+                            if (z_write) {
+                                if (mystique->maccess_running & MACCESS_ZWIDTH) {
+                                    *(uint32_t*)(&z_p[x_l * 2]) = (mystique->dwgreg.extended_dr[0] & (1ull << 47ull)) ? 0 : (mystique->dwgreg.extended_dr[0] >> 15ull);
+                                }
+                                else
+                                    z_p[x_l] = ((int32_t) mystique->dwgreg.dr[0] < 0) ? 0 : (mystique->dwgreg.dr[0] >> 15);
+                            }
+                        }
+                    }
+skip_pixel:
+                    if (x_l > x_r)
+                        x_l--;
+                    else
+                        x_l++;
+
+                    if (mystique->maccess_running & MACCESS_ZWIDTH) {
+                        mystique->dwgreg.extended_dr[0] += mystique->dwgreg.extended_dr[2];
+                        mystique->dwgreg.dr[0] = (mystique->dwgreg.extended_dr[0] >> 16) & 0xFFFFFFFF;
+                    } else {
+                        mystique->dwgreg.dr[0] += mystique->dwgreg.dr[2];
+                        mystique->dwgreg.extended_dr[0] = (mystique->dwgreg.extended_dr[0] & ~0xFFFFull) | ((uint64_t)mystique->dwgreg.dr[0] << 16ull);
+                    }
+                    mystique->dwgreg.dr[4] += mystique->dwgreg.dr[6];
+                    mystique->dwgreg.dr[8] += mystique->dwgreg.dr[10];
+                    mystique->dwgreg.dr[12] += mystique->dwgreg.dr[14];
+                    mystique->dwgreg.tmr[6] += mystique->dwgreg.tmr[0];
+                    mystique->dwgreg.tmr[7] += mystique->dwgreg.tmr[2];
+                    mystique->dwgreg.tmr[8] += mystique->dwgreg.tmr[4];
+                    mystique->dwgreg.fogstart += mystique->dwgreg.fogxinc;
+                    mystique->dwgreg.alphastart += mystique->dwgreg.alphaxinc;
+                    mystique->dwgreg.fogstart &= 0xFFFFFF;
+                    mystique->dwgreg.alphastart &= 0xFFFFFF;
+                }
+
+                if (mystique->maccess_running & MACCESS_ZWIDTH) {
+                    mystique->dwgreg.extended_dr[0] = z_back_32 + mystique->dwgreg.extended_dr[3];
+                    mystique->dwgreg.dr[0] = (mystique->dwgreg.extended_dr[0] >> 16) & 0xFFFFFFFF;
+                } else {
+                    mystique->dwgreg.dr[0] = z_back + mystique->dwgreg.dr[3];
+                    mystique->dwgreg.extended_dr[0] = (mystique->dwgreg.extended_dr[0] & ~0xFFFFull) | ((uint64_t)mystique->dwgreg.dr[0] << 16ull);
+                }
+                mystique->dwgreg.dr[4]      = r_back + mystique->dwgreg.dr[7];
+                mystique->dwgreg.dr[8]      = g_back + mystique->dwgreg.dr[11];
+                mystique->dwgreg.dr[12]     = b_back + mystique->dwgreg.dr[15];
+                mystique->dwgreg.tmr[6]     = s_back + mystique->dwgreg.tmr[1];
+                mystique->dwgreg.tmr[7]     = t_back + mystique->dwgreg.tmr[3];
+                mystique->dwgreg.tmr[8]     = q_back + mystique->dwgreg.tmr[5];
+                mystique->dwgreg.fogstart   = fog_back + mystique->dwgreg.fogyinc;
+                mystique->dwgreg.alphastart = a_back + mystique->dwgreg.alphayinc;
+                mystique->dwgreg.fogstart &= 0xFFFFFF;
+                mystique->dwgreg.alphastart &= 0xFFFFFF;
+
+                while ((int32_t) mystique->dwgreg.ar[1] < 0 && mystique->dwgreg.ar[0]) {
+                    mystique->dwgreg.ar[1] += mystique->dwgreg.ar[0];
+                    mystique->dwgreg.fxleft += (mystique->dwgreg.sgn.sdxl ? -1 : 1);
+                }
+                mystique->dwgreg.ar[1] += mystique->dwgreg.ar[2];
+
+                while ((int32_t) mystique->dwgreg.ar[4] < 0 && mystique->dwgreg.ar[6]) {
+                    mystique->dwgreg.ar[4] += mystique->dwgreg.ar[6];
+                    mystique->dwgreg.fxright += (mystique->dwgreg.sgn.sdxr ? -1 : 1);
+                }
+                mystique->dwgreg.ar[4] += mystique->dwgreg.ar[5];
+
+                dx = (int16_t) ((mystique->dwgreg.fxleft - old_x_l) & 0xffff);
+                if (mystique->maccess_running & MACCESS_ZWIDTH) {
+                    mystique->dwgreg.extended_dr[0] += dx * mystique->dwgreg.extended_dr[2];
+                    mystique->dwgreg.dr[0] = (mystique->dwgreg.extended_dr[0] >> 16) & 0xFFFFFFFF;
+                } else {
+                    mystique->dwgreg.dr[0] += dx * mystique->dwgreg.dr[2];
+                    mystique->dwgreg.extended_dr[0] = (mystique->dwgreg.extended_dr[0] & ~0xFFFFull) | ((uint64_t)mystique->dwgreg.dr[0] << 16ull);
+                }
+                mystique->dwgreg.dr[4] += dx * mystique->dwgreg.dr[6];
+                mystique->dwgreg.dr[8] += dx * mystique->dwgreg.dr[10];
+                mystique->dwgreg.dr[12] += dx * mystique->dwgreg.dr[14];
+                mystique->dwgreg.tmr[6] += dx * mystique->dwgreg.tmr[0];
+                mystique->dwgreg.tmr[7] += dx * mystique->dwgreg.tmr[2];
+                mystique->dwgreg.tmr[8] += dx * mystique->dwgreg.tmr[4];
+                mystique->dwgreg.fogstart += dx * mystique->dwgreg.fogxinc;
+                mystique->dwgreg.alphastart += dx * mystique->dwgreg.alphaxinc;
+                mystique->dwgreg.fogstart &= 0xFFFFFF;
+                mystique->dwgreg.alphastart &= 0xFFFFFF;
+
+                mystique->dwgreg.ydst++;
+                mystique->dwgreg.ydst &= 0x7fffff;
+                mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK);
+
+                mystique->dwgreg.selline = (mystique->dwgreg.selline + 1) & 7;
+            }
+            break;
+
+        default:
+            fatal("Unknown atype %03x %08x TEXTURE_TRAP\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running);
+    }
+
+    mystique->blitter_complete_refcount++;
+}
+
+static void
+blit_bitblt(mystique_t *mystique)
+{
+    svga_t   *svga = &mystique->svga;
+    uint32_t  src_addr;
+    int       y;
+    int       x_dir     = mystique->dwgreg.sgn.scanleft ? -1 : 1;
+    int16_t   x_start   = mystique->dwgreg.sgn.scanleft ? mystique->dwgreg.fxright : mystique->dwgreg.fxleft;
+    int16_t   x_end     = mystique->dwgreg.sgn.scanleft ? mystique->dwgreg.fxleft : mystique->dwgreg.fxright;
+    const int trans_sel = (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANS_MASK) >> DWGCTRL_TRANS_SHIFT;
+    uint32_t  bltckey   = mystique->dwgreg.fcol;
+    uint32_t  bltcmsk   = mystique->dwgreg.bcol;
+
+    switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) {
+        case MACCESS_PWIDTH_8:
+            bltckey &= 0xff;
+            bltcmsk &= 0xff;
+            break;
+        case MACCESS_PWIDTH_16:
+            bltckey &= 0xffff;
+            bltcmsk &= 0xffff;
+            break;
+    }
+
+    switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) {
+        case DWGCTRL_ATYPE_BLK:
+            switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) {
+                case DWGCTRL_BLTMOD_BMONOLEF:
+                case DWGCTRL_BLTMOD_BMONOWF:
+                    src_addr = mystique->dwgreg.ar[3];
+
+                    for (y = 0; y < mystique->dwgreg.length; y++) {
+                        int16_t x = x_start;
+
+                        while (1) {
+                            if (x >= mystique->dwgreg.cxleft && x <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) {
+                                uint32_t byte_addr  = (src_addr >> 3) & mystique->vram_mask;
+                                int      bit_offset = ((mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) == DWGCTRL_BLTMOD_BMONOWF) ? (7 - (src_addr & 7)) : (src_addr & 7);
+                                uint32_t old_dst;
+
+                                switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) {
+                                    case MACCESS_PWIDTH_8:
+                                        if (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC) {
+                                            if (svga->vram[byte_addr] & (1 << bit_offset))
+                                                svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask] = mystique->dwgreg.fcol;
+                                        } else
+                                            svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask] = (svga->vram[byte_addr] & (1 << bit_offset)) ? mystique->dwgreg.fcol : mystique->dwgreg.bcol;
+                                        svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask) >> 12] = changeframecount;
+                                        break;
+
+                                    case MACCESS_PWIDTH_16:
+                                        if (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC) {
+                                            if (svga->vram[byte_addr] & (1 << bit_offset))
+                                                ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = mystique->dwgreg.fcol;
+                                        } else
+                                            ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = (svga->vram[byte_addr] & (1 << bit_offset)) ? mystique->dwgreg.fcol : mystique->dwgreg.bcol;
+                                        svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w) >> 11] = changeframecount;
+                                        break;
+
+                                    case MACCESS_PWIDTH_24:
+                                        old_dst = *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask];
+                                        if (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC) {
+                                            if (svga->vram[byte_addr] & (1 << bit_offset))
+                                                *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = (old_dst & 0xff000000) | (mystique->dwgreg.fcol & 0xffffff);
+                                        } else
+                                            *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = (old_dst & 0xff000000) | (((svga->vram[byte_addr] & (1 << bit_offset)) ? mystique->dwgreg.fcol : mystique->dwgreg.bcol) & 0xffffff);
+                                        svga->changedvram[(((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask) >> 12] = changeframecount;
+                                        break;
+
+                                    case MACCESS_PWIDTH_32:
+                                        if (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC) {
+                                            if (svga->vram[byte_addr] & (1 << bit_offset))
+                                                ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l] = mystique->dwgreg.fcol;
+                                        } else
+                                            ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l] = (svga->vram[byte_addr] & (1 << bit_offset)) ? mystique->dwgreg.fcol : mystique->dwgreg.bcol;
+                                        svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l) >> 11] = changeframecount;
+                                        break;
+
+                                    default:
+                                        fatal("BITBLT DWGCTRL_ATYPE_BLK unknown MACCESS %i\n", mystique->maccess_running & MACCESS_PWIDTH_MASK);
+                                }
+                            }
+
+                            if (src_addr == mystique->dwgreg.ar[0]) {
+                                mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5];
+                                mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5];
+                                src_addr = mystique->dwgreg.ar[3];
+                            } else
+                                src_addr += x_dir;
+
+                            if (x != x_end)  {
+                                if ((x > x_end) && (x_dir == 1))
+                                    x--;
+                                else if ((x < x_end) && (x_dir == -1))
+                                    x++;
+                                else
+                                    x += x_dir;
+                            } else
+                                break;
+                        }
+
+                        if (mystique->dwgreg.sgn.sdy)
+                            mystique->dwgreg.ydst_lin -= (mystique->dwgreg.pitch & PITCH_MASK);
+                        else
+                            mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK);
+                    }
+                    break;
+
+                default:
+                    fatal("BITBLT BLK %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK);
+                    break;
+            }
+            break;
+
+        case DWGCTRL_ATYPE_RPL:
+            if (mystique->maccess_running & MACCESS_TLUTLOAD) {
+                src_addr = mystique->dwgreg.ar[3];
+
+                y = mystique->dwgreg.ydst;
+
+                while (mystique->dwgreg.length) {
+                    uint16_t src = ((uint16_t *) svga->vram)[src_addr & mystique->vram_mask_w];
+
+                    mystique->lut[y & 0xff].r = (src >> 11) << 3;
+                    mystique->lut[y & 0xff].g = ((src >> 5) & 0x3f) << 2;
+                    mystique->lut[y & 0xff].b = (src & 0x1f) << 3;
+                    src_addr++;
+                    y++;
+                    mystique->dwgreg.length--;
+                }
+                break;
+            }
+        case DWGCTRL_ATYPE_RSTR:
+            switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) {
+                /* TODO: This isn't exactly perfect. */
+                case DWGCTRL_BLTMOD_BPLAN:
+                    if (mystique->dwgreg.dwgctrl_running & DWGCTRL_PATTERN)
+                        fatal("BITBLT RPL/RSTR BPLAN with pattern\n");
+
+                    src_addr = mystique->dwgreg.ar[3];
+
+                    for (y = 0; y < mystique->dwgreg.length; y++) {
+                        uint8_t const *const trans = &trans_masks[trans_sel][(mystique->dwgreg.selline & 3) * 4];
+                        int16_t              x     = x_start;
+
+                        while (1) {
+                            uint32_t byte_addr = src_addr & mystique->vram_mask;
+
+                            if (x >= mystique->dwgreg.cxleft && x <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && ((svga->vram[byte_addr] & 1) || !(mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC)) && trans[x & 3]) {
+                                uint32_t src = (svga->vram[byte_addr] & 1) ? mystique->dwgreg.fcol : mystique->dwgreg.bcol;
+                                uint32_t dst;
+                                uint32_t old_dst;
+
+                                switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) {
+                                    case MACCESS_PWIDTH_8:
+                                        dst = svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask];
+
+                                        dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running);
+
+                                        svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask]                = dst;
+                                        svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask) >> 12] = changeframecount;
+                                        break;
+
+                                    case MACCESS_PWIDTH_16:
+                                        dst = ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w];
+
+                                        dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running);
+
+                                        ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = dst;
+                                        svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w) >> 11] = changeframecount;
+                                        break;
+
+                                    case MACCESS_PWIDTH_24:
+                                        old_dst = *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask];
+
+                                        dst = bitop(src, old_dst, mystique->dwgreg.dwgctrl_running); // & DWGCTRL_BOP_MASK
+
+                                        *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = (dst & 0xffffff) | (old_dst & 0xff000000);
+                                        svga->changedvram[(((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask) >> 12] = changeframecount;
+                                        break;
+
+                                    case MACCESS_PWIDTH_32:
+                                        dst = ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l];
+
+                                        dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running);
+
+                                        ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l] = dst;
+                                        svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l) >> 10] = changeframecount;
+                                        break;
+
+                                    default:
+                                        fatal("BITBLT RPL BPLAN PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running);
+                                }
+                            }
+
+                            if (src_addr == mystique->dwgreg.ar[0]) {
+                                mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5];
+                                mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5];
+                                src_addr = mystique->dwgreg.ar[3];
+                            } else
+                                src_addr += x_dir;
+
+                            if (x != x_end)  {
+                                if ((x > x_end) && (x_dir == 1))
+                                    x--;
+                                else if ((x < x_end) && (x_dir == -1))
+                                    x++;
+                                else
+                                    x += x_dir;
+                            } else
+                                break;
+                        }
+
+                        if (mystique->dwgreg.sgn.sdy)
+                            mystique->dwgreg.ydst_lin -= (mystique->dwgreg.pitch & PITCH_MASK);
+                        else
+                            mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK);
+                    }
+                    break;
+                case DWGCTRL_BLTMOD_BMONOLEF:
+                case DWGCTRL_BLTMOD_BMONOWF:
+                    if (mystique->dwgreg.dwgctrl_running & DWGCTRL_PATTERN)
+                        fatal("BITBLT RPL/RSTR BMONOLEF with pattern\n");
+
+                    src_addr = mystique->dwgreg.ar[3];
+
+                    for (y = 0; y < mystique->dwgreg.length; y++) {
+                        uint8_t const *const trans = &trans_masks[trans_sel][(mystique->dwgreg.selline & 3) * 4];
+                        int16_t              x     = x_start;
+
+                        while (1) {
+                            uint32_t byte_addr  = (src_addr >> 3) & mystique->vram_mask;
+                            int      bit_offset = ((mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) == DWGCTRL_BLTMOD_BMONOWF) ? (7 - (src_addr & 7)) : (src_addr & 7);
+
+                            if (x >= mystique->dwgreg.cxleft && x <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && ((svga->vram[byte_addr] & (1 << bit_offset)) || !(mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC)) && trans[x & 3]) {
+                                uint32_t src = (svga->vram[byte_addr] & (1 << bit_offset)) ? mystique->dwgreg.fcol : mystique->dwgreg.bcol;
+                                uint32_t dst;
+                                uint32_t old_dst;
+
+                                switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) {
+                                    case MACCESS_PWIDTH_8:
+                                        dst = svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask];
+
+                                        dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running);
+
+                                        svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask]                = dst;
+                                        svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask) >> 12] = changeframecount;
+                                        break;
+
+                                    case MACCESS_PWIDTH_16:
+                                        dst = ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w];
+
+                                        dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running);
+
+                                        ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = dst;
+                                        svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w) >> 11] = changeframecount;
+                                        break;
+
+                                    case MACCESS_PWIDTH_24:
+                                        old_dst = *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask];
+
+                                        dst = bitop(src, old_dst, mystique->dwgreg.dwgctrl_running); // & DWGCTRL_BOP_MASK
+
+                                        *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = (dst & 0xffffff) | (old_dst & 0xff000000);
+                                        svga->changedvram[(((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask) >> 12] = changeframecount;
+                                        break;
+
+                                    case MACCESS_PWIDTH_32:
+                                        dst = ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l];
+
+                                        dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running);
+
+                                        ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l] = dst;
+                                        svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l) >> 10] = changeframecount;
+                                        break;
+
+                                    default:
+                                        fatal("BITBLT RPL BMONOLEF PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running);
+                                }
+                            }
+
+                            if (src_addr == mystique->dwgreg.ar[0]) {
+                                mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5];
+                                mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5];
+                                src_addr = mystique->dwgreg.ar[3];
+                            } else
+                                src_addr += x_dir;
+
+                            if (x != x_end)  {
+                                if ((x > x_end) && (x_dir == 1))
+                                    x--;
+                                else if ((x < x_end) && (x_dir == -1))
+                                    x++;
+                                else
+                                    x += x_dir;
+                            } else
+                                break;
+                        }
+
+                        if (mystique->dwgreg.sgn.sdy)
+                            mystique->dwgreg.ydst_lin -= (mystique->dwgreg.pitch & PITCH_MASK);
+                        else
+                            mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK);
+                    }
+                    break;
+
+                case DWGCTRL_BLTMOD_BFCOL:
+                case DWGCTRL_BLTMOD_BU32RGB:
+                    src_addr = mystique->dwgreg.ar[3];
+
+                    for (y = 0; y < mystique->dwgreg.length; y++) {
+                        uint8_t const *const trans        = &trans_masks[trans_sel][(mystique->dwgreg.selline & 3) * 4];
+                        uint32_t             old_src_addr = src_addr;
+                        int16_t              x            = x_start;
+
+                        while (1) {
+                            if (x >= mystique->dwgreg.cxleft && x <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && trans[x & 3]) {
+                                uint32_t src;
+                                uint32_t dst;
+                                uint32_t old_dst;
+
+                                switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) {
+                                    case MACCESS_PWIDTH_8:
+                                        src = svga->vram[src_addr & mystique->vram_mask];
+                                        dst = svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask];
+                                        if (!((!(mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC) || (src & bltcmsk) != bltckey)))
+                                            break;
+
+                                        dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running);
+
+                                        svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask]                = dst;
+                                        svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask) >> 12] = changeframecount;
+                                        break;
+
+                                    case MACCESS_PWIDTH_16:
+                                        src = ((uint16_t *) svga->vram)[src_addr & mystique->vram_mask_w];
+                                        dst = ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w];
+                                        if (!((!(mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC) || (src & bltcmsk) != bltckey)))
+                                            break;
+
+                                        dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running);
+
+                                        ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = dst;
+                                        svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w) >> 11] = changeframecount;
+                                        break;
+
+                                    case MACCESS_PWIDTH_24:
+                                        src     = *(uint32_t *) &svga->vram[(src_addr * 3) & mystique->vram_mask];
+                                        old_dst = *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask];
+                                        if (!((!(mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC) || (src & bltcmsk) != bltckey)))
+                                            break;
+
+                                        dst = bitop(src, old_dst, mystique->dwgreg.dwgctrl_running);
+
+                                        *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = (dst & 0xffffff) | (old_dst & 0xff000000);
+                                        svga->changedvram[(((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask) >> 12] = changeframecount;
+                                        break;
+
+                                    case MACCESS_PWIDTH_32:
+                                        src = ((uint32_t *) svga->vram)[src_addr & mystique->vram_mask_l];
+                                        dst = ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l];
+                                        if (!((!(mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC) || (src & bltcmsk) != bltckey)))
+                                            break;
+
+                                        dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running);
+
+                                        ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l] = dst;
+                                        svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l) >> 10] = changeframecount;
+                                        break;
+
+                                    default:
+                                        fatal("BITBLT RPL BFCOL PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running);
+                                }
+                            }
+
+                            if (mystique->dwgreg.dwgctrl_running & DWGCTRL_PATTERN)
+                                src_addr = ((src_addr + x_dir) & 7) | (src_addr & ~7);
+                            else if (src_addr == mystique->dwgreg.ar[0]) {
+                                mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5];
+                                mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5];
+                                src_addr = mystique->dwgreg.ar[3];
+                            } else
+                                src_addr += x_dir;
+
+                            if (x != x_end)  {
+                                if ((x > x_end) && (x_dir == 1))
+                                    x--;
+                                else if ((x < x_end) && (x_dir == -1))
+                                    x++;
+                                else
+                                    x += x_dir;
+                            } else
+                                break;
+                        }
+
+                        if (mystique->dwgreg.dwgctrl_running & DWGCTRL_PATTERN) {
+                            src_addr = old_src_addr;
+                            if (mystique->dwgreg.sgn.sdy)
+                                src_addr = ((src_addr - 32) & 0xe0) | (src_addr & ~0xe0);
+                            else
+                                src_addr = ((src_addr + 32) & 0xe0) | (src_addr & ~0xe0);
+                        }
+
+                        if (mystique->dwgreg.sgn.sdy)
+                            mystique->dwgreg.ydst_lin -= (mystique->dwgreg.pitch & PITCH_MASK);
+                        else
+                            mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK);
+                    }
+                    break;
+
+                default:
+                    fatal("BITBLT DWGCTRL_ATYPE_RPL unknown BLTMOD %08x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK, mystique->dwgreg.dwgctrl_running);
+            }
+            break;
+
+        default:
+#if 0
+            pclog("Unknown BITBLT atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running);
+#endif
+            break;
+    }
+
+    mystique->blitter_complete_refcount++;
+}
+
+static void
+blit_iload(mystique_t *mystique)
+{
+    switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) {
+        case DWGCTRL_ATYPE_RPL:
+        case DWGCTRL_ATYPE_RSTR:
+        case DWGCTRL_ATYPE_BLK:
+#if 0
+            pclog("ILOAD BLTMOD DWGCTRL = %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK);
+#endif
+            switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) {
+                case DWGCTRL_BLTMOD_BFCOL:
+                case DWGCTRL_BLTMOD_BMONOLEF:
+                case DWGCTRL_BLTMOD_BMONOWF:
+                case DWGCTRL_BLTMOD_BU24RGB:
+                case DWGCTRL_BLTMOD_BU32RGB:
+                    mystique->dwgreg.length_cur      = mystique->dwgreg.length;
+                    mystique->dwgreg.xdst            = mystique->dwgreg.fxleft;
+                    mystique->dwgreg.iload_rem_data  = 0;
+                    mystique->dwgreg.iload_rem_count = 0;
+                    mystique->busy = 1;
+#if 0
+                    pclog("ILOAD busy\n");
+#endif
+                    mystique->dwgreg.words = 0;
+                    break;
+
+                default:
+                    fatal("ILOAD DWGCTRL_ATYPE_RPL %08x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK, mystique->dwgreg.dwgctrl_running);
+                    break;
+            }
+            break;
+
+        default:
+            fatal("Unknown ILOAD atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running);
+    }
+}
+
+static void
+blit_idump(mystique_t *mystique)
+{
+    switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) {
+        case DWGCTRL_ATYPE_RPL:
+            mystique->dwgreg.length_cur        = mystique->dwgreg.length;
+            mystique->dwgreg.xdst              = mystique->dwgreg.fxleft;
+            mystique->dwgreg.src_addr          = mystique->dwgreg.ar[3];
+            mystique->dwgreg.words             = 0;
+            mystique->dwgreg.iload_rem_count   = 0;
+            mystique->dwgreg.iload_rem_data    = 0;
+            mystique->dwgreg.idump_end_of_line = 0;
+            mystique->busy                     = 1;
+#if 0
+            pclog("IDUMP ATYPE RPL busy\n");
+#endif
+            break;
+
+        default:
+            fatal("Unknown IDUMP atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running);
+    }
+}
+
+static void
+blit_iload_scale(mystique_t *mystique)
+{
+    switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) {
+        case DWGCTRL_ATYPE_RPL:
+            switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) {
+                case DWGCTRL_BLTMOD_BUYUV:
+                    mystique->dwgreg.length_cur      = mystique->dwgreg.length;
+                    mystique->dwgreg.xdst            = mystique->dwgreg.fxleft;
+                    mystique->dwgreg.iload_rem_data  = 0;
+                    mystique->dwgreg.iload_rem_count = 0;
+                    mystique->busy                   = 1;
+                    mystique->dwgreg.words           = 0;
+                    /* pclog("ILOAD SCALE ATYPE RPL BLTMOD BUYUV busy\n"); */
+                    break;
+
+                default:
+                    fatal("ILOAD_SCALE DWGCTRL_ATYPE_RPL %08x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK, mystique->dwgreg.dwgctrl_running);
+                    break;
+            }
+            break;
+
+        default:
+            fatal("Unknown ILOAD_SCALE atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running);
+    }
+}
+
+static void
+blit_iload_high(mystique_t *mystique)
+{
+    switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) {
+        case DWGCTRL_ATYPE_RPL:
+            switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) {
+                case DWGCTRL_BLTMOD_BUYUV:
+                case DWGCTRL_BLTMOD_BU32BGR:
+                    mystique->dwgreg.length_cur      = mystique->dwgreg.length;
+                    mystique->dwgreg.xdst            = mystique->dwgreg.fxleft;
+                    mystique->dwgreg.iload_rem_data  = 0;
+                    mystique->dwgreg.iload_rem_count = 0;
+                    mystique->busy                   = 1;
+                    mystique->dwgreg.words           = 0;
+                    /* pclog("ILOAD HIGH ATYPE RPL BLTMOD BUYUV busy\n"); */
+                    break;
+
+                default:
+                    fatal("ILOAD_HIGH DWGCTRL_ATYPE_RPL %08x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK, mystique->dwgreg.dwgctrl_running);
+                    break;
+            }
+            break;
+
+        default:
+            fatal("Unknown ILOAD_HIGH atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running);
+    }
+}
+
+static void
+blit_iload_highv(mystique_t *mystique)
+{
+    switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) {
+        case DWGCTRL_ATYPE_RPL:
+            switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) {
+                case DWGCTRL_BLTMOD_BUYUV:
+                    mystique->dwgreg.length_cur      = mystique->dwgreg.length;
+                    mystique->dwgreg.xdst            = mystique->dwgreg.fxleft;
+                    mystique->dwgreg.iload_rem_data  = 0;
+                    mystique->dwgreg.iload_rem_count = 0;
+                    mystique->busy                   = 1;
+                    mystique->dwgreg.words           = 0;
+                    mystique->dwgreg.highv_line      = 0;
+                    mystique->dwgreg.lastpix_r       = 0;
+                    mystique->dwgreg.lastpix_g       = 0;
+                    mystique->dwgreg.lastpix_b       = 0;
+                    /* pclog("ILOAD HIGHV ATYPE RPL BLTMOD BUYUV busy\n"); */
+                    break;
+
+                default:
+                    fatal("ILOAD_HIGHV DWGCTRL_ATYPE_RPL %08x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK, mystique->dwgreg.dwgctrl_running);
+                    break;
+            }
+            break;
+
+        default:
+            fatal("Unknown ILOAD_HIGHV atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running);
+    }
+}
+
+static void
+mystique_start_blit(mystique_t *mystique)
+{
+    svga_t *svga = &mystique->svga;
+    //uint64_t start_time = plat_timer_read();
+    //uint64_t end_time;
+
+    /*Make sure we don't get any artifacts.*/
+    svga->chain2_write = 0;
+    svga->chain2_read = 0;
+
+    mystique->dwgreg.dwgctrl_running = mystique->dwgreg.dwgctrl;
+    mystique->maccess_running        = mystique->maccess;
+
+    switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) {
+        case DWGCTRL_OPCODE_LINE_OPEN:
+            blit_line_start(mystique, 0, 0);
+            break;
+
+        case DWGCTRL_OPCODE_AUTOLINE_OPEN:
+            blit_line_start(mystique, 0, 1);
+            break;
+
+        case DWGCTRL_OPCODE_LINE_CLOSE:
+            blit_line_start(mystique, 1, 0);
+            break;
+
+        case DWGCTRL_OPCODE_AUTOLINE_CLOSE:
+            blit_line_start(mystique, 1, 1);
+            break;
+
+        case DWGCTRL_OPCODE_TRAP:
+            blit_trap(mystique);
+            break;
+
+        case DWGCTRL_OPCODE_TEXTURE_TRAP:
+            blit_texture_trap(mystique);
+            break;
+
+        case DWGCTRL_OPCODE_ILOAD_HIGH:
+            blit_iload_high(mystique);
+            break;
+
+        case DWGCTRL_OPCODE_BITBLT:
+            blit_bitblt(mystique);
+            break;
+
+        case DWGCTRL_OPCODE_FBITBLT:
+            blit_fbitblt(mystique);
+            break;
+
+        case DWGCTRL_OPCODE_ILOAD:
+            blit_iload(mystique);
+            break;
+
+        case DWGCTRL_OPCODE_IDUMP:
+            blit_idump(mystique);
+            break;
+
+        case DWGCTRL_OPCODE_ILOAD_SCALE:
+            blit_iload_scale(mystique);
+            break;
+
+        case DWGCTRL_OPCODE_ILOAD_HIGHV:
+            blit_iload_highv(mystique);
+            break;
+
+        case DWGCTRL_OPCODE_ILOAD_FILTER:
+            /* TODO: Actually implement this. */
+            break;
+
+        default:
+            fatal("mystique_start_blit: unknown blit %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK);
+            break;
+    }
+
+    //end_time = plat_timer_read();
+    //mystique->blitter_time += end_time - start_time;
+}
+
+static void
+mystique_hwcursor_draw(svga_t *svga, int displine)
+{
+    const mystique_t *mystique = (mystique_t *) svga->priv;
+    uint64_t          dat[2];
+    int               offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff;
+
+    if (svga->interlace && svga->hwcursor_oddeven)
+        svga->hwcursor_latch.addr += 16;
+
+    dat[0] = *(uint64_t *) (&svga->vram[svga->hwcursor_latch.addr]);
+    dat[1] = *(uint64_t *) (&svga->vram[svga->hwcursor_latch.addr + 8]);
+    svga->hwcursor_latch.addr += 16;
+    switch (mystique->xcurctrl & XCURCTRL_CURMODE_MASK) {
+
+        case XCURCTRL_CURMODE_3COL:
+            for (uint8_t x = 0; x < 64; x++) {
+                               int c = ((dat[0] & (1ULL << 63)) ? 1 : 0) | ((dat[1] & (1ULL << 63)) ? 2 : 0);
+                if (c) {
+                    svga->monitor->target_buffer->line[displine][(offset + svga->x_add) & 2047] = mystique->cursor.col[c - 1];
+                }
+
+                offset++;
+                dat[0] <<= 1;
+                dat[1] <<= 1;
+            }
+            break;
+
+        case XCURCTRL_CURMODE_XGA:
+            for (uint8_t x = 0; x < 64; x++) {
+                if (!(dat[1] & (1ULL << 63)))
+                    svga->monitor->target_buffer->line[displine][(offset + svga->x_add) & 2047] = (dat[0] & (1ULL << 63)) ? svga_lookup_lut_ram(svga, mystique->cursor.col[1]) : svga_lookup_lut_ram(svga, mystique->cursor.col[0]);
+                else if (dat[0] & (1ULL << 63))
+                    svga->monitor->target_buffer->line[displine][(offset + svga->x_add) & 2047] ^= 0xffffff;
+
+                offset++;
+                dat[0] <<= 1;
+                dat[1] <<= 1;
+            }
+            break;
+
+        case XCURCTRL_CURMODE_XWIN:
+            for (uint8_t x = 0; x < 64; x++) {
+                if ((dat[1] & (1ULL << 63)))
+                    svga->monitor->target_buffer->line[displine][(offset + svga->x_add) & 2047] = (dat[0] & (1ULL << 63)) ? (mystique->cursor.col[1]) : (mystique->cursor.col[0]);
+
+                offset++;
+                dat[0] <<= 1;
+                dat[1] <<= 1;
+            }
+            break;
+
+        default:
+            break;
+    }
+
+    if (svga->interlace && !svga->hwcursor_oddeven)
+        svga->hwcursor_latch.addr += 16;
+}
+
+static uint8_t
+mystique_tvp3026_gpio_read(uint8_t cntl, void *priv)
+{
+    mystique_t *mystique = (mystique_t *) priv;
+
+    uint8_t ret = 0xff;
+#if 0
+    if (!i2c_gpio_get_scl(mystique->i2c_ddc))
+        ret &= ~0x10;
+    if (!i2c_gpio_get_sda(mystique->i2c_ddc))
+        ret &= ~0x04;
+#endif
+    return ret;
+}
+
+static void
+mystique_tvp3026_gpio_write(uint8_t cntl, uint8_t data, void *priv)
+{
+    mystique_t *mystique = (mystique_t *) priv;
+
+#if 0
+    i2c_gpio_set(mystique->i2c_ddc, !(cntl & 0x10) || (data & 0x10), !(cntl & 0x04) || (data & 0x04));
+#endif
+}
+
+static uint8_t
+mystique_pci_read(UNUSED(int func), int addr, void *priv)
+{
+    mystique_t *mystique = (mystique_t *) priv;
+    uint8_t     ret      = 0x00;
+
+    if ((addr >= 0x30) && (addr <= 0x33) && !(mystique->pci_regs[0x43] & 0x40))
+        ret = 0x00;
+    else
+        switch (addr) {
+            case 0x00:
+                ret = 0x2b;
+                break; /*Matrox*/
+            case 0x01:
+                ret = 0x10;
+                break;
+
+            case 0x02:
+                if (mystique->type == MGA_G100)
+                    ret = 0x01;
+                else
+                    ret = (mystique->type == MGA_2164W) ? 0x1b : ((mystique->type == MGA_2064W) ? 0x19 : 0x1a);
+                break; /*MGA*/
+            case 0x03:
+                if (mystique->type == MGA_G100)
+                    ret = 0x10;
+                else
+                    ret = 0x05;
+                break;
+
+            case PCI_REG_COMMAND:
+                ret = mystique->pci_regs[PCI_REG_COMMAND] | 0x80;
+                break; /*Respond to IO and memory accesses*/
+            case 0x05:
+                ret = 0x00;
+                break;
+
+            case 0x06:
+                ret = 0x80;
+                break;
+            case 0x07:
+                ret = mystique->pci_regs[0x07];
+                break; /*Fast DEVSEL timing*/
+
+            case 0x08:
+                ret = (mystique->type == MGA_1164SG) ? 3 : 0;
+                break; /*Revision ID*/
+            case 0x09:
+                ret = 0;
+                break; /*Programming interface*/
+
+            case 0x0a:
+                ret = 0x00;
+                break; /*Supports VGA interface*/
+            case 0x0b:
+                ret = 0x03;
+                break;
+
+            case 0x10:
+                ret = 0x00;
+                break; /*Control aperture for Millennium and Mystique, LFB for Mystique 220 and later*/
+            case 0x11:
+                if (mystique->type >= MGA_1164SG)
+                    ret = 0x00;
+                else
+                    ret = (mystique->ctrl_base >> 8) & 0xc0;
+                break;
+            case 0x12:
+                if (mystique->type >= MGA_1164SG)
+                    ret = (mystique->type >= MGA_2164W) ? 0x00 : ((mystique->lfb_base >> 16) & 0x80);
+                else
+                    ret = mystique->ctrl_base >> 16;
+                break;
+            case 0x13:
+                if (mystique->type >= MGA_1164SG)
+                    ret = mystique->lfb_base >> 24;
+                else
+                    ret = mystique->ctrl_base >> 24;
+                break;
+
+            case 0x14:
+                ret = 0x00;
+                break; /*LFB for Millennium and Mystique, Control aperture for Mystique 220 and later*/
+            case 0x15:
+                if (mystique->type >= MGA_1164SG)
+                    ret = (mystique->ctrl_base >> 8) & 0xc0;
+                else
+                    ret = 0x00;
+                break;
+            case 0x16:
+                if (mystique->type >= MGA_1164SG)
+                    ret = mystique->ctrl_base >> 16;
+                else
+                    ret = (mystique->lfb_base >> 16) & 0x80;
+                break;
+            case 0x17:
+                if (mystique->type >= MGA_1164SG)
+                    ret = mystique->ctrl_base >> 24;
+                else
+                    ret = mystique->lfb_base >> 24;
+                break;
+
+            case 0x18:
+                ret = 0x00;
+                break; /*Pseudo-DMA (ILOAD)*/
+            case 0x1a:
+                ret = (mystique->iload_base >> 16) & 0x80;
+                break;
+            case 0x1b:
+                ret = mystique->iload_base >> 24;
+                break;
+
+            case 0x2c:
+                ret = mystique->pci_regs[0x2c];
+                break;
+            case 0x2d:
+                ret = mystique->pci_regs[0x2d];
+                break;
+            case 0x2e:
+                ret = mystique->pci_regs[0x2e];
+                break;
+            case 0x2f:
+                ret = mystique->pci_regs[0x2f];
+                break;
+
+            case 0x30:
+                ret = mystique->pci_regs[0x30] & 0x01;
+                break; /*BIOS ROM address*/
+            case 0x31:
+                ret = 0x00;
+                break;
+            case 0x32:
+                ret = mystique->pci_regs[0x32];
+                break;
+            case 0x33:
+                ret = mystique->pci_regs[0x33];
+                break;
+
+            case 0x34:
+                ret = (mystique->type == MGA_G100) ? 0xdc : 0x00;
+                break;
+
+            case 0x3c:
+                ret = mystique->int_line;
+                break;
+            case 0x3d:
+                ret = PCI_INTA;
+                break;
+
+            case 0x40:
+                ret = mystique->pci_regs[0x40];
+                break;
+            case 0x41:
+                ret = mystique->pci_regs[0x41];
+                break;
+            case 0x42:
+                ret = mystique->pci_regs[0x42];
+                break;
+            case 0x43:
+                ret = mystique->pci_regs[0x43];
+                break;
+
+            case 0x44:
+                ret = mystique->pci_regs[0x44];
+                break;
+            case 0x45:
+                ret = mystique->pci_regs[0x45];
+                break;
+
+            case 0x48:
+            case 0x49:
+            case 0x4a:
+            case 0x4b:
+                addr = (mystique->pci_regs[0x44] & 0xfc) | ((mystique->pci_regs[0x45] & 0x3f) << 8) | (addr & 3);
+                ret  = mystique_ctrl_read_bx(addr, mystique);
+                break;
+
+            case 0xdc:
+                ret = 0x01;
+                break;
+
+            case 0xdd:
+                ret = 0xf0;
+                break;
+
+            case 0xde:
+                ret = 0x21;
+                break;
+
+            /* No support for turning off the video adapter yet. */
+            case 0xe0:
+                ret = 0x0;
+                break;
+
+            case 0xf0:
+                ret = 0x02;
+                break;
+
+            case 0xf1:
+                ret = 0x00;
+                break;
+
+            case 0xf2:
+                ret = 0x10;
+                break;
+
+            case 0xf4:
+                ret = 0x1;
+                break;
+
+            case 0xf5:
+                ret = 0x2;
+                break;
+
+            case 0xf7:
+                ret = 0x1;
+                break;
+
+            case 0xf8:
+                ret = mystique->pci_regs[0xf8] & 0x7;
+                break;
+
+            case 0xf9:
+                ret = mystique->pci_regs[0xf9] & 0x3;
+                break;
+
+            case 0xfb:
+                ret = mystique->pci_regs[0xfb];
+                break;
+
+            default:
+                break;
+        }
+
+    return ret;
+}
+
+static void
+mystique_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv)
+{
+    mystique_t *mystique = (mystique_t *) priv;
+
+    switch (addr) {
+        case PCI_REG_COMMAND:
+            mystique->pci_regs[PCI_REG_COMMAND] = (val & 0x27) | 0x80;
+            mystique_recalc_mapping(mystique);
+            break;
+
+        case 0x07:
+            mystique->pci_regs[0x07] &= ~(val & 0x38);
+            break;
+
+        case 0x0d:
+            mystique->pci_regs[0x0d] = val;
+            break;
+
+        case 0x11:
+            if (mystique->type >= MGA_1164SG)
+                break;
+            else {
+                mystique->ctrl_base = (mystique->ctrl_base & 0xffff0000) | ((val & 0xc0) << 8);
+                mystique_recalc_mapping(mystique);
+            }
+            break;
+        case 0x12:
+            if (mystique->type >= MGA_1164SG) {
+                if (mystique->type >= MGA_2164W)
+                    break;
+                mystique->lfb_base = (mystique->lfb_base & 0xff000000) | ((val & 0x80) << 16);
+                mystique_recalc_mapping(mystique);
+            } else {
+                mystique->ctrl_base = (mystique->ctrl_base & 0xff00c000) | (val << 16);
+                mystique_recalc_mapping(mystique);
+            }
+            break;
+        case 0x13:
+            if (mystique->type >= MGA_1164SG) {
+                if (mystique->type >= MGA_2164W)
+                    mystique->lfb_base = val << 24;
+                else
+                    mystique->lfb_base = (mystique->lfb_base & 0x00800000) | (val << 24);
+
+                mystique_recalc_mapping(mystique);
+            } else {
+                mystique->ctrl_base = (mystique->ctrl_base & 0x00ffc000) | (val << 24);
+                mystique_recalc_mapping(mystique);
+            }
+            break;
+
+        case 0x15:
+            if (mystique->type >= MGA_1164SG) {
+                mystique->ctrl_base = (mystique->ctrl_base & 0xffff0000) | ((val & 0xc0) << 8);
+                mystique_recalc_mapping(mystique);
+            }
+            break;
+        case 0x16:
+            if (mystique->type >= MGA_1164SG) {
+                mystique->ctrl_base = (mystique->ctrl_base & 0xff00c000) | (val << 16);
+                mystique_recalc_mapping(mystique);
+            } else {
+                mystique->lfb_base = (mystique->lfb_base & 0xff000000) | ((val & 0x80) << 16);
+                mystique_recalc_mapping(mystique);
+            }
+            break;
+        case 0x17:
+            if (mystique->type >= MGA_1164SG) {
+                mystique->ctrl_base = (mystique->ctrl_base & 0x00ffc000) | (val << 24);
+                mystique_recalc_mapping(mystique);
+            } else {
+                mystique->lfb_base = (mystique->lfb_base & 0x00800000) | (val << 24);
+                mystique_recalc_mapping(mystique);
+            }
+            break;
+
+        case 0x1a:
+            mystique->iload_base = (mystique->iload_base & 0xff000000) | ((val & 0x80) << 16);
+            mystique_recalc_mapping(mystique);
+            break;
+        case 0x1b:
+            mystique->iload_base = (mystique->iload_base & 0x00800000) | (val << 24);
+            mystique_recalc_mapping(mystique);
+            break;
+
+        case 0x30:
+        case 0x32:
+        case 0x33:
+            if (!(mystique->pci_regs[0x43] & 0x40))
+                return;
+            mystique->pci_regs[addr] = val;
+            if (addr == 0x30)
+                mystique->pci_regs[addr] &= 1;
+            if (mystique->pci_regs[0x30] & 0x01) {
+                uint32_t biosaddr = (mystique->pci_regs[0x32] << 16) | (mystique->pci_regs[0x33] << 24);
+                mem_mapping_set_addrx(&mystique->bios_rom.mapping, biosaddr, (mystique->type == MGA_G100) ? 0x10000 : 0x8000);
+            } else
+                mem_mapping_disablex(&mystique->bios_rom.mapping);
+            return;
+
+        case 0x3c:
+            mystique->int_line = val;
+            return;
+
+        case 0x40:
+            mystique->pci_regs[addr] = val & 0x3f;
+            break;
+        case 0x41:
+            mystique->pci_regs[addr] = val;
+            break;
+        case 0x42:
+            mystique->pci_regs[addr] = val & 0x1f;
+            break;
+        case 0x43:
+            mystique->pci_regs[addr] = val;
+            //pclog("%08x\n", (mystique->pci_regs[0x40] << 0) | (mystique->pci_regs[0x41] << 8) | (mystique->pci_regs[0x42] << 16) | (mystique->pci_regs[0x43] << 24));
+            if (addr == 0x43) {
+                if (val & 0x40) {
+                    if (mystique->pci_regs[0x30] & 0x01) {
+                        uint32_t biosaddr = (mystique->pci_regs[0x32] << 16) | (mystique->pci_regs[0x33] << 24);
+                        mem_mapping_set_addrx(&mystique->bios_rom.mapping, biosaddr, (mystique->type == MGA_G100) ? 0x10000 : 0x8000);
+                    } else
+                        mem_mapping_disablex(&mystique->bios_rom.mapping);
+                } else
+                    mem_mapping_set_addrx(&mystique->bios_rom.mapping, 0x000c0000, (mystique->type == MGA_G100) ? 0x10000 : 0x8000);
+            }
+            break;
+
+        case 0x4c:
+        case 0x4d:
+        case 0x4e:
+        case 0x4f:
+            mystique->pci_regs[addr - 0x20] = val;
+            break;
+
+        case 0x44:
+            mystique->pci_regs[addr] = val & 0xfc;
+            break;
+        case 0x45:
+            mystique->pci_regs[addr] = val & 0x3f;
+            break;
+
+        case 0x48:
+        case 0x49:
+        case 0x4a:
+        case 0x4b:
+            addr = (mystique->pci_regs[0x44] & 0xfc) | ((mystique->pci_regs[0x45] & 0x3f) << 8) | (addr & 3);
+#if 0
+            pclog("mystique_ctrl_write_bx(%04X, %02X)\n", addr, val);
+#endif
+            mystique_ctrl_write_bx(addr, val, mystique);
+            break;
+
+            case 0xf8:
+                mystique->pci_regs[0xf8] = val & 0x7;
+                break;
+
+            case 0xf9:
+                mystique->pci_regs[0xf9] = val & 0x3;
+                break;
+
+            case 0xfb:
+                mystique->pci_regs[0xfb] = val;
+                break;
+
+        default:
+            break;
+    }
+}
+
+static uint32_t
+mystique_conv_16to32(svga_t* svga, uint16_t color, uint8_t bpp)
+{
+    mystique_t *mystique = (mystique_t*)svga->priv;
+    uint32_t ret = 0x00000000;
+
+    if (svga->lut_map) {
+        if (bpp == 15) {
+            if (mystique->xgenctrl & (1 << 2))
+                color &= 0x7FFF;
+#if 0
+            uint8_t b = getcolr(svga->pallook[(color & 0x1F) | (!!(color & 0x8000) >> 8)]);
+            uint8_t g = getcolg(svga->pallook[((color & 0x3E0) >> 5) | (!!(color & 0x8000) >> 8)]);
+            uint8_t r = getcolb(svga->pallook[((color & 0x7C00) >> 10) | (!!(color & 0x8000) >> 8)]);
+#else
+            uint8_t b = getcolr(svga->pallook[color & 0x1f]);
+            uint8_t g = getcolg(svga->pallook[(color & 0x3e0) >> 5]);
+            uint8_t r = getcolb(svga->pallook[(color & 0x7c00) >> 10]);
+#endif
+            ret = (video_15to32[color] & 0xFF000000) | makecol(r, g, b);
+        } else {
+            uint8_t b = getcolr(svga->pallook[color & 0x1f]);
+            uint8_t g = getcolg(svga->pallook[(color & 0x7e0) >> 5]);
+            uint8_t r = getcolb(svga->pallook[(color & 0xf800) >> 11]);
+            ret = (video_16to32[color] & 0xFF000000) | makecol(r, g, b);
+        }
+    } else
+        ret = (bpp == 15) ? video_15to32[color] : video_16to32[color];
+
+    return ret;
+}
+
+static void *
+mystique_init(const device_t *info)
+{
+    mystique_t *mystique = (mystique_t*)malloc(sizeof(mystique_t));
+    const char *romfn = NULL;
+
+    memset(mystique, 0, sizeof(mystique_t));
+
+    mystique->type = info->local;
+
+    if (mystique->type == MGA_2064W)
+        romfn = ROM_MILLENNIUM;
+    else if (mystique->type == MGA_2164W)
+        romfn = ROM_MILLENNIUM_II;
+    else if (mystique->type == MGA_1064SG)
+        romfn = ROM_MYSTIQUE;
+    else if (mystique->type == MGA_G100)
+        romfn = ROM_G100;
+    else
+        romfn = ROM_MYSTIQUE_220;
+
+    if (mystique->type == MGA_G100)
+        rom_init(&mystique->bios_rom, romfn, 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL);
+    else
+        rom_init(&mystique->bios_rom, romfn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
+    mem_mapping_disablex(&mystique->bios_rom.mapping);
+
+    mystique->vram_size   = device_get_config_int("memory");
+    mystique->vram_mask   = (mystique->vram_size << 20) - 1;
+    mystique->vram_mask_w = mystique->vram_mask >> 1;
+    mystique->vram_mask_l = mystique->vram_mask >> 2;
+
+    video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_matrox_mystique);
+
+    if (mystique->type == MGA_2064W || mystique->type == MGA_2164W) {
+        mystique->svga.dac_hwcursor_draw = tvp3026_hwcursor_draw;
+        mystique->svga.ramdac            = device_add(&tvp3026_ramdac_device);
+        mystique->svga.clock_gen         = mystique->svga.ramdac;
+        mystique->svga.getclock          = tvp3026_getclock;
+        mystique->svga.conv_16to32       = tvp3026_conv_16to32;
+        if (mystique->type == MGA_2164W)
+            mystique->svga.decode_mask = 0xffffff;
+        video_inform(VIDEO_FLAG_TYPE_SPECIAL, (mystique->type == MGA_2164W) ? &timing_matrox_mystique : &timing_matrox_millennium);
+        svga_init(info, &mystique->svga, mystique, mystique->vram_size << 20,
+            mystique_recalctimings,
+            mystique_in, mystique_out,
+            NULL,
+            NULL);
+        tvp3026_gpio(mystique_tvp3026_gpio_read, mystique_tvp3026_gpio_write, mystique, mystique->svga.ramdac);
+    } else {
+        video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_matrox_mystique);
+        mystique->svga.clock_gen = mystique;
+        mystique->svga.getclock  = mystique_getclock;
+        if (mystique->type == MGA_G100)
+            mystique->svga.decode_mask = 0xffffff;
+        svga_init(info, &mystique->svga, mystique, mystique->vram_size << 20,
+            mystique_recalctimings,
+            mystique_in, mystique_out,
+            mystique_hwcursor_draw,
+            NULL);
+    }
+
+    io_sethandler(0x03c0, 0x0020, mystique_in, NULL, NULL, mystique_out, NULL, NULL, mystique);
+    mem_mapping_addx(&mystique->ctrl_mapping, 0, 0,
+                    mystique_ctrl_read_b, mystique_ctrl_read_w, mystique_ctrl_read_l,
+                    mystique_ctrl_write_b, mystique_ctrl_write_w, mystique_ctrl_write_l,
+                    NULL, 0, mystique);
+    mem_mapping_disablex(&mystique->ctrl_mapping);
+
+    mem_mapping_addx(&mystique->lfb_mapping, 0, 0,
+                    mystique_readb_linear, mystique_readw_linear, mystique_readl_linear,
+                    mystique_writeb_linear, mystique_writew_linear, mystique_writel_linear,
+                    NULL, 0, &mystique->svga);
+    mem_mapping_disablex(&mystique->lfb_mapping);
+
+    mem_mapping_addx(&mystique->iload_mapping, 0, 0,
+                    mystique_iload_read_b, NULL, mystique_iload_read_l,
+                    mystique_iload_write_b, NULL, mystique_iload_write_l,
+                    NULL, 0, mystique);
+    mem_mapping_disablex(&mystique->iload_mapping);
+
+    if (romfn == NULL)
+        pci_add_card(PCI_ADD_VIDEO, mystique_pci_read, mystique_pci_write, mystique, &mystique->pci_slot);
+    else
+        pci_add_card((info->flags & DEVICE_AGP) ? PCI_ADD_AGP : PCI_ADD_NORMAL, mystique_pci_read, mystique_pci_write, mystique, &mystique->pci_slot);
+    mystique->pci_regs[0x06] = 0x80;
+    mystique->pci_regs[0x07] = 0 << 1;
+#if 0
+    mystique->pci_regs[0x2c] = mystique->bios_rom.rom[0x7ff8];
+    mystique->pci_regs[0x2d] = mystique->bios_rom.rom[0x7ff9];
+    mystique->pci_regs[0x2e] = mystique->bios_rom.rom[0x7ffa];
+    mystique->pci_regs[0x2f] = mystique->bios_rom.rom[0x7ffb];
+#endif
+    mystique->svga.miscout   = 1;
+    mystique->pci_regs[0x41] = 0x01; /* vgaboot = 1 */
+    mystique->pci_regs[0x43] = 0x40; /* biosen = 1 */
+
+    for (uint16_t c = 0; c < 256; c++) {
+        dither5[c][0][0] = c >> 3;
+        dither5[c][1][1] = (c + 2) >> 3;
+        dither5[c][1][0] = (c + 4) >> 3;
+        dither5[c][0][1] = (c + 6) >> 3;
+
+        if (dither5[c][1][1] > 31)
+            dither5[c][1][1] = 31;
+        if (dither5[c][1][0] > 31)
+            dither5[c][1][0] = 31;
+        if (dither5[c][0][1] > 31)
+            dither5[c][0][1] = 31;
+
+        dither6[c][0][0] = c >> 2;
+        dither6[c][1][1] = (c + 1) >> 2;
+        dither6[c][1][0] = (c + 2) >> 2;
+        dither6[c][0][1] = (c + 3) >> 2;
+
+        if (dither6[c][1][1] > 63)
+            dither6[c][1][1] = 63;
+        if (dither6[c][1][0] > 63)
+            dither6[c][1][0] = 63;
+        if (dither6[c][0][1] > 63)
+            dither6[c][0][1] = 63;
+    }
+
+    mystique->wake_fifo_thread    = thread_create_event();
+    mystique->fifo_not_full_event = thread_create_event();
+    mystique->thread_run          = 1;
+    mystique->fifo_thread         = thread_create(fifo_thread, mystique);
+    mystique->dma.lock            = thread_create_mutex();
+
+    timer_addx(&mystique->wake_timer, mystique_wake_timer, (void *) mystique, 0);
+    timer_addx(&mystique->softrap_pending_timer, mystique_softrap_pending_timer, (void *) mystique, 1);
+
+    mystique->status = STATUS_ENDPRDMASTS;
+
+    mystique->softrap_status_read = 1;
+
+    mystique->svga.vsync_callback = mystique_vsync_callback;
+
+    if (mystique->type != MGA_2064W && mystique->type != MGA_2164W)
+        mystique->svga.conv_16to32    = mystique_conv_16to32;
+
+#if 0
+    mystique->i2c     = i2c_gpio_init("i2c_mga");
+    mystique->i2c_ddc = i2c_gpio_init("ddc_mga");
+    mystique->ddc     = ddc_init(i2c_gpio_get_bus(mystique->i2c_ddc));
+#endif
+    return mystique;
+}
+
+static void
+mystique_close(void *priv)
+{
+    mystique_t *mystique = (mystique_t *) priv;
+
+    mystique->thread_run = 0;
+    thread_set_event(mystique->wake_fifo_thread);
+    thread_wait(mystique->fifo_thread);
+    thread_destroy_event(mystique->wake_fifo_thread);
+    thread_destroy_event(mystique->fifo_not_full_event);
+    thread_close_mutex(mystique->dma.lock);
+
+    svga_close(&mystique->svga);
+
+#if 0
+    ddc_close(mystique->ddc);
+    i2c_gpio_close(mystique->i2c_ddc);
+    i2c_gpio_close(mystique->i2c);
+#endif
+    free(mystique);
+}
+
+static int
+millennium_available(void)
+{
+    return rom_present(ROM_MILLENNIUM);
+}
+
+static int
+mystique_available(void)
+{
+    return rom_present(ROM_MYSTIQUE);
+}
+
+static int
+mystique_220_available(void)
+{
+    return rom_present(ROM_MYSTIQUE_220);
+}
+
+static int
+millennium_ii_available(void)
+{
+    return rom_present(ROM_MILLENNIUM_II);
+}
+
+#ifdef USE_G100
+static int
+matrox_g100_available(void)
+{
+    return rom_present(ROM_G100);
+}
+#endif
+
+static void
+mystique_speed_changed(void *priv)
+{
+    mystique_t *mystique = (mystique_t *) priv;
+
+    svga_recalctimings(&mystique->svga);
+}
+
+static void
+mystique_force_redraw(void *priv)
+{
+    mystique_t *mystique = (mystique_t *) priv;
+
+    mystique->svga.fullchange = changeframecount;
+}
+
+#if 0
+
+static const device_config_t mystique_config[] = {
+  // clang-format off
+    {
+        .name = "memory",
+        .description = "Memory size",
+        .type = CONFIG_SELECTION,
+        .selection = {
+            {
+                .description = "2 MB",
+                .value = 2
+            },
+            {
+                .description = "4 MB",
+                .value = 4
+            },
+            {
+                .description = "8 MB",
+                .value = 8
+            },
+            { .description = "" }
+        },
+        .default_int = 8
+    },
+    { .type = CONFIG_END }
+  // clang-format on
+};
+
+static const device_config_t millennium_ii_config[] = {
+  // clang-format off
+    {
+        .name = "memory",
+        .description = "Memory size",
+        .type = CONFIG_SELECTION,
+        .selection = {
+            {
+                .description = "4 MB",
+                .value = 4
+            },
+            {
+                .description = "8 MB",
+                .value = 8
+            },
+            {
+                .description = "16 MB",
+                .value = 16
+            },
+            { .description = "" }
+        },
+        .default_int = 8
+    },
+    { .type = CONFIG_END }
+  // clang-format on
+};
+#endif
+
+const device_t millennium_device = {
+    .name          = "Matrox Millennium",
+    .internal_name = "millennium",
+    .flags         = DEVICE_PCI,
+    .local         = MGA_2064W,
+    .init          = mystique_init,
+    .close         = mystique_close,
+    .reset         = NULL,
+    .available = millennium_available,
+    .speed_changed = mystique_speed_changed,
+    .force_redraw  = mystique_force_redraw,
+    //.config        = mystique_config
+};
+
+const device_t mystique_device = {
+    .name          = "Matrox Mystique",
+    .internal_name = "mystique",
+    .flags         = DEVICE_PCI,
+    .local         = MGA_1064SG,
+    .init          = mystique_init,
+    .close         = mystique_close,
+    .reset         = NULL,
+    .available = mystique_available,
+    .speed_changed = mystique_speed_changed,
+    .force_redraw  = mystique_force_redraw,
+    //.config        = mystique_config
+};
+
+const device_t mystique_220_device = {
+    .name          = "Matrox Mystique 220",
+    .internal_name = "mystique_220",
+    .flags         = DEVICE_PCI,
+    .local         = MGA_1164SG,
+    .init          = mystique_init,
+    .close         = mystique_close,
+    .reset         = NULL,
+    .available = mystique_220_available,
+    .speed_changed = mystique_speed_changed,
+    .force_redraw  = mystique_force_redraw,
+    //.config        = mystique_config
+};
+
+const device_t millennium_ii_device = {
+    .name          = "Matrox Millennium II",
+    .internal_name = "millennium_ii",
+    .flags         = DEVICE_PCI,
+    .local         = MGA_2164W,
+    .init          = mystique_init,
+    .close         = mystique_close,
+    .reset         = NULL,
+    .available = millennium_ii_available,
+    .speed_changed = mystique_speed_changed,
+    .force_redraw  = mystique_force_redraw,
+    //.config        = millennium_ii_config
+};
+
+#ifdef USE_G100
+const device_t productiva_g100_device = {
+    .name          = "Matrox Productiva G100",
+    .internal_name = "productiva_g100",
+    .flags         = DEVICE_AGP,
+    .local         = MGA_G100,
+    .init          = mystique_init,
+    .close         = mystique_close,
+    .reset         = NULL,
+    .available = matrox_g100_available,
+    .speed_changed = mystique_speed_changed,
+    .force_redraw  = mystique_force_redraw,
+    //.config        = millennium_ii_config
+};
+#endif
+
+#endif
\ No newline at end of file
index 854ef5e91a1170a9e37eeadb38401f6ac2bbf265..32ee860c36319b06f5ac2d8bc15a1446bf6c39e2 100644 (file)
@@ -86,14 +86,14 @@ static int ncr_vga_vsync_enabled(ncr_t *ncr)
 static void ncr_update_irqs(ncr_t *ncr)
 {
     if (ncr->vblank_irq > 0 && ncr_vga_vsync_enabled(ncr))
-        pci_set_irq(NULL, PCI_INTA);
+        pci_set_irq(NULL, PCI_INTA, NULL);
     else
-        pci_clear_irq(NULL, PCI_INTA);
+        pci_clear_irq(NULL, PCI_INTA, NULL);
 }
 
 static void ncr_vblank_start(svga_t *svga)
 {
-    ncr_t *ncr = (ncr_t *)svga->p;
+    ncr_t *ncr = (ncr_t *)svga->priv;
     if (ncr->vblank_irq >= 0) {
         ncr->vblank_irq = 1;
         ncr_update_irqs(ncr);
@@ -103,7 +103,7 @@ static void ncr_vblank_start(svga_t *svga)
 
 void ncr_hwcursor_draw(svga_t *svga, int displine)
 {
-    ncr_t *ncr = (ncr_t*)svga->p;
+    ncr_t *ncr = (ncr_t*)svga->priv;
     int x;
     uint8_t dat[2];
     uint32_t c[2];
@@ -138,7 +138,7 @@ void ncr_hwcursor_draw(svga_t *svga, int displine)
     if ((svga->bpp == 16 || svga->bpp == 15) && svga->hwcursor.h_acc > 0) {
         xdbl = 1 << (svga->hwcursor.h_acc - 1);
     }
-    for (x = 0; x < svga->hwcursor.xsize; x += 8)
+    for (x = 0; x < svga->hwcursor.cur_xsize; x += 8)
     {
             if (x == 32) {
                 addr += (64 / 8);
@@ -146,7 +146,7 @@ void ncr_hwcursor_draw(svga_t *svga, int displine)
             addr--;
             uint32_t addroffset = addr & svga->vram_display_mask;
             dat[0] = svga->vram[addroffset];
-            addroffset = (addr + (svga->hwcursor.xsize / 8)) & svga->vram_display_mask;
+            addroffset = (addr + (svga->hwcursor.cur_xsize / 8)) & svga->vram_display_mask;
             dat[1] = svga->vram[addroffset];
             for (xx = 0; xx < 8; xx++)
             {
@@ -166,7 +166,7 @@ void ncr_hwcursor_draw(svga_t *svga, int displine)
                 dat[1] <<= 1;
             }
     }
-    svga->hwcursor_latch.addr += (svga->hwcursor.xsize / 8) * 2;
+    svga->hwcursor_latch.addr += (svga->hwcursor.cur_xsize / 8) * 2;
 
     if (svga->interlace && !svga->hwcursor_oddeven)
         svga->hwcursor_latch.addr += line_offset;
@@ -213,8 +213,8 @@ void ncr_out(uint16_t addr, uint8_t val, void *p)
                         case 0x0c:
                             svga->hwcursor.ena = val & 1;
                             svga->hwcursor.h_acc = (val >> 5) & 3;
-                            svga->hwcursor.ysize = 16 << ((val >> 1) & 3);
-                            svga->hwcursor.xsize = (val & 0x80) && ncr->chip == NCR_TYPE_32BLT ? 64 : 32;
+                            svga->hwcursor.cur_ysize = 16 << ((val >> 1) & 3);
+                            svga->hwcursor.cur_xsize = (val & 0x80) && ncr->chip == NCR_TYPE_32BLT ? 64 : 32;
                             break;
                         case 0x0d:
                         case 0x0e:
@@ -359,7 +359,7 @@ static const int fontwidths[] =
 
 void ncr_recalctimings(svga_t *svga)
 {
-        ncr_t *ncr = (ncr_t*)svga->p;
+        ncr_t *ncr = (ncr_t*)svga->priv;
         bool ext_end = (svga->crtc[0x30] & 0x20) != 0;
 
         svga->hdisp = svga->crtc[1] - ((svga->crtc[5] & 0x60) >> 5);
@@ -958,19 +958,19 @@ static uint32_t ncr_mmio_readl(uint32_t addr, void *p)
 static void ncr_write_linear(uint32_t addr, uint8_t val, void *p)
 {
     svga_t *svga = (svga_t *)p;
-    ncr_t *ncr = (ncr_t *)svga->p;
+    ncr_t *ncr = (ncr_t *)svga->priv;
     svga_write_linear(addr, val, p);
 }
 static void ncr_writew_linear(uint32_t addr, uint16_t val, void *p)
 {
     svga_t *svga = (svga_t *)p;
-    ncr_t *ncr = (ncr_t *)svga->p;
+    ncr_t *ncr = (ncr_t *)svga->priv;
     svga_writew_linear(addr, val, p);
 }
 static void ncr_writel_linear(uint32_t addr, uint32_t val, void *p)
 {
     svga_t *svga = (svga_t *)p;
-    ncr_t *ncr = (ncr_t *)svga->p;
+    ncr_t *ncr = (ncr_t *)svga->priv;
     if (ncr->blt_fifo_write > 0) {
         blitter_write_fifo(ncr, val);
         return;
@@ -1112,7 +1112,7 @@ static void *ncr_init(char *bios_fn, int chip)
 
         rom_init(&ncr->bios_rom, bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
 
-        svga_init(&ncr->svga, ncr, vram_size,
+        svga_init(NULL, &ncr->svga, ncr, vram_size,
             ncr_recalctimings,
             ncr_in, ncr_out,
             ncr_hwcursor_draw,
@@ -1159,7 +1159,7 @@ static void *ncr_init(char *bios_fn, int chip)
         return ncr;
 }
 
-void *ncr_retina_z2_init()
+void *ncr_retina_z2_init(const device_t *info)
 {
     ncr_t *ncr = (ncr_t *)ncr_init("ncr.bin", NCR_TYPE_22EP);
 
@@ -1173,7 +1173,7 @@ void *ncr_retina_z2_init()
     return ncr;
 }
 
-void *ncr_retina_z3_init()
+void *ncr_retina_z3_init(const device_t *info)
 {
     ncr_t *ncr = (ncr_t *)ncr_init("ncr.bin", NCR_TYPE_32BLT);
 
@@ -1229,26 +1229,24 @@ void ncr_add_status_info(char *s, int max_len, void *p)
 
 device_t ncr_retina_z2_device =
 {
-    "NCR 77C22E+",
-    0,
+    "NCR 77C22E+", NULL,
+    0, 0,
     ncr_retina_z2_init,
     ncr_close,
     NULL,
+    NULL,
     ncr_speed_changed,
     ncr_force_redraw,
-    ncr_add_status_info,
-    NULL
 };
 
 device_t ncr_retina_z3_device =
 {
-    "NCR 77C32BLT",
-    0,
+    "NCR 77C32BLT", NULL,
+    0, 0,
     ncr_retina_z3_init,
     ncr_close,
     NULL,
+    NULL,
     ncr_speed_changed,
     ncr_force_redraw,
-    ncr_add_status_info,
-    NULL
 };
index e693a35b7dc3cb713806ffef642d5f9471e4cd0b..f6b32adc70571007cdf637a4c306de624661fd47 100644 (file)
@@ -192,15 +192,15 @@ static void permedia2_update_irqs(permedia2_t *permedia2)
 {
     if (permedia2->vblank_irq > 0 && permedia2_vsync_enabled(permedia2)) {
         permedia2->intreq |= 0x10;
-        pci_set_irq(NULL, PCI_INTA);
+        pci_set_irq(NULL, PCI_INTA, NULL);
     } else {
-        pci_clear_irq(NULL, PCI_INTA);
+        pci_clear_irq(NULL, PCI_INTA, NULL);
     }
 }
 
 static void permedia2_vblank_start(svga_t *svga)
 {
-    permedia2_t *permedia2 = (permedia2_t *)svga->p;
+    permedia2_t *permedia2 = (permedia2_t *)svga->priv;
     if (permedia2->vblank_irq >= 0) {
         permedia2->vblank_irq = 1;
         permedia2_update_irqs(permedia2);
@@ -318,7 +318,7 @@ uint8_t permedia2_in(uint16_t addr, void *p)
 
 void permedia2_recalctimings(svga_t *svga)
 {
-        permedia2_t *permedia2 = (permedia2_t*)svga->p;
+        permedia2_t *permedia2 = (permedia2_t*)svga->priv;
         bool svga_mode = (svga->seqregs[0x05] & 0x08) != 0;
         int bpp = 8;
 
@@ -421,7 +421,7 @@ void permedia2_recalctimings(svga_t *svga)
 
 static void permedia2_hwcursor_draw(svga_t *svga, int displine)
 {
-    permedia2_t *permedia2 = (permedia2_t*)svga->p;
+    permedia2_t *permedia2 = (permedia2_t*)svga->priv;
     int addr = svga->hwcursor_latch.addr;
     int addradd = 0;
     uint8_t dat[2];
@@ -431,11 +431,11 @@ static void permedia2_hwcursor_draw(svga_t *svga, int displine)
 
     offset <<= svga->horizontal_linedbl;
 
-    if (svga->hwcursor.xsize == 32) {
+    if (svga->hwcursor.cur_xsize == 32) {
         addradd = ((control >> 4) & 3) * (32 * 32 / 8);
     }
 
-    for (int x = 0; x < svga->hwcursor.xsize; x += 8)
+    for (int x = 0; x < svga->hwcursor.cur_xsize; x += 8)
     {
         dat[0] = permedia2->ramdac_cram[addr + addradd];
         dat[1] = permedia2->ramdac_cram[addr + 0x200 + addradd];
@@ -470,7 +470,7 @@ static void permedia2_hwcursor_draw(svga_t *svga, int displine)
         }
         addr++;
     }
-    svga->hwcursor_latch.addr += svga->hwcursor.xsize / 8;
+    svga->hwcursor_latch.addr += svga->hwcursor.cur_xsize / 8;
 
 }
 
@@ -612,7 +612,7 @@ static void permedia2_ramdac_write(int reg, uint8_t v, void *p)
         {
             case 0x06: // cursorcontrol
             svga->hwcursor.ena = (v & 3) != 0;
-            svga->hwcursor.ysize = svga->hwcursor.xsize = (v & 0x40) ? 64 : 32;
+            svga->hwcursor.cur_ysize = svga->hwcursor.cur_xsize = (v & 0x40) ? 64 : 32;
             permedia2->ramdac_cramaddr &= 0x00ff;
             permedia2->ramdac_cramaddr |= ((v >> 2) & 3) << 8;
             break;
@@ -1538,7 +1538,7 @@ static uint8_t permedia2_mmio_read(uint32_t addr, void *p)
 static uint8_t permedia2_read_linear1(uint32_t addr, void *p)
 {
     svga_t *svga = (svga_t*)p;
-    permedia2_t *permedia2 = (permedia2_t*)svga->p;
+    permedia2_t *permedia2 = (permedia2_t*)svga->priv;
 
     uint8_t *fbp = (uint8_t*)(&svga->vram[addr & svga->vram_mask]);
     uint8_t v = *fbp;
@@ -1547,7 +1547,7 @@ static uint8_t permedia2_read_linear1(uint32_t addr, void *p)
 static uint16_t permedia2_readw_linear1(uint32_t addr, void *p)
 {
     svga_t *svga = (svga_t*)p;
-    permedia2_t *permedia2 = (permedia2_t*)svga->p;
+    permedia2_t *permedia2 = (permedia2_t*)svga->priv;
 
     uint16_t *fbp = (uint16_t*)(&svga->vram[addr & svga->vram_mask]);
     uint16_t v = *fbp;
@@ -1561,7 +1561,7 @@ static uint16_t permedia2_readw_linear1(uint32_t addr, void *p)
 static uint32_t permedia2_readl_linear1(uint32_t addr, void *p)
 {
     svga_t *svga = (svga_t*)p;
-    permedia2_t *permedia2 = (permedia2_t*)svga->p;
+    permedia2_t *permedia2 = (permedia2_t*)svga->priv;
 
     uint32_t *fbp = (uint32_t*)(&svga->vram[addr & svga->vram_mask]);
     uint32_t v = *fbp;
@@ -1579,7 +1579,7 @@ static uint32_t permedia2_readl_linear1(uint32_t addr, void *p)
 static uint8_t permedia2_read_linear2(uint32_t addr, void *p)
 {
     svga_t *svga = (svga_t *)p;
-    permedia2_t *permedia2 = (permedia2_t *)svga->p;
+    permedia2_t *permedia2 = (permedia2_t *)svga->priv;
 
     uint8_t *fbp = (uint8_t *)(&svga->vram[addr & svga->vram_mask]);
     uint8_t v = *fbp;
@@ -1588,7 +1588,7 @@ static uint8_t permedia2_read_linear2(uint32_t addr, void *p)
 static uint16_t permedia2_readw_linear2(uint32_t addr, void *p)
 {
     svga_t *svga = (svga_t *)p;
-    permedia2_t *permedia2 = (permedia2_t *)svga->p;
+    permedia2_t *permedia2 = (permedia2_t *)svga->priv;
 
     uint16_t *fbp = (uint16_t *)(&svga->vram[addr & svga->vram_mask]);
     uint16_t v = *fbp;
@@ -1602,7 +1602,7 @@ static uint16_t permedia2_readw_linear2(uint32_t addr, void *p)
 static uint32_t permedia2_readl_linear2(uint32_t addr, void *p)
 {
     svga_t *svga = (svga_t *)p;
-    permedia2_t *permedia2 = (permedia2_t *)svga->p;
+    permedia2_t *permedia2 = (permedia2_t *)svga->priv;
 
     uint32_t *fbp = (uint32_t *)(&svga->vram[addr & svga->vram_mask]);
     uint32_t v = *fbp;
@@ -1620,7 +1620,7 @@ static uint32_t permedia2_readl_linear2(uint32_t addr, void *p)
 static void permedia2_write_linear1(uint32_t addr, uint8_t val, void *p)
 {
     svga_t *svga = (svga_t*)p;
-    permedia2_t *permedia2 = (permedia2_t*)svga->p;
+    permedia2_t *permedia2 = (permedia2_t*)svga->priv;
 
     addr &= svga->vram_mask;
     uint8_t *fbp = (uint8_t*)(&svga->vram[addr]);
@@ -1630,7 +1630,7 @@ static void permedia2_write_linear1(uint32_t addr, uint8_t val, void *p)
 static void permedia2_writew_linear1(uint32_t addr, uint16_t val, void *p)
 {
     svga_t *svga = (svga_t*)p;
-    permedia2_t *permedia2 = (permedia2_t*)svga->p;
+    permedia2_t *permedia2 = (permedia2_t*)svga->priv;
 
     if (permedia2->linear_byte_control[0] == 2) {
         val = (val >> 8) | (val << 8);
@@ -1644,7 +1644,7 @@ static void permedia2_writew_linear1(uint32_t addr, uint16_t val, void *p)
 static void permedia2_writel_linear1(uint32_t addr, uint32_t val, void *p)
 {
     svga_t *svga = (svga_t*)p;
-    permedia2_t *permedia2 = (permedia2_t*)svga->p;
+    permedia2_t *permedia2 = (permedia2_t*)svga->priv;
 
     if (permedia2->linear_byte_control[0] == 2) {
         val = (val >> 16) | (val << 16);
@@ -1662,7 +1662,7 @@ static void permedia2_writel_linear1(uint32_t addr, uint32_t val, void *p)
 static void permedia2_write_linear2(uint32_t addr, uint8_t val, void *p)
 {
     svga_t *svga = (svga_t *)p;
-    permedia2_t *permedia2 = (permedia2_t *)svga->p;
+    permedia2_t *permedia2 = (permedia2_t *)svga->priv;
 
     addr &= svga->vram_mask;
     uint8_t *fbp = (uint8_t *)(&svga->vram[addr]);
@@ -1672,7 +1672,7 @@ static void permedia2_write_linear2(uint32_t addr, uint8_t val, void *p)
 static void permedia2_writew_linear2(uint32_t addr, uint16_t val, void *p)
 {
     svga_t *svga = (svga_t *)p;
-    permedia2_t *permedia2 = (permedia2_t *)svga->p;
+    permedia2_t *permedia2 = (permedia2_t *)svga->priv;
 
     if (permedia2->linear_byte_control[1] == 2) {
         val = (val >> 8) | (val << 8);
@@ -1686,7 +1686,7 @@ static void permedia2_writew_linear2(uint32_t addr, uint16_t val, void *p)
 static void permedia2_writel_linear2(uint32_t addr, uint32_t val, void *p)
 {
     svga_t *svga = (svga_t *)p;
-    permedia2_t *permedia2 = (permedia2_t *)svga->p;
+    permedia2_t *permedia2 = (permedia2_t *)svga->priv;
 
     if (permedia2->linear_byte_control[1] == 2) {
         val = (val >> 16) | (val << 16);
@@ -1910,7 +1910,7 @@ static void *permedia2_init(char *bios_fn, int chip)
 
         rom_init(&permedia2->bios_rom, bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
 
-        svga_init(&permedia2->svga, permedia2, vram_size,
+        svga_init(NULL, &permedia2->svga, permedia2, vram_size,
             permedia2_recalctimings,
             permedia2_in, permedia2_out,
             permedia2_hwcursor_draw,
@@ -1949,7 +1949,7 @@ static void *permedia2_init(char *bios_fn, int chip)
         return permedia2;
 }
 
-void *permedia2_init()
+void *permedia2_init(const device_t *info)
 {
     permedia2_t *permedia2 = (permedia2_t *)permedia2_init("permedia2.bin", 0);
 
@@ -1998,13 +1998,13 @@ void permedia2_add_status_info(char *s, int max_len, void *p)
 
 device_t permedia2_device =
 {
-    "Permedia 2",
-    0,
+    "Permedia 2", NULL,
+    0, 0,
     permedia2_init,
     permedia2_close,
     NULL,
+    NULL,
     permedia2_speed_changed,
     permedia2_force_redraw,
-    permedia2_add_status_info,
     NULL
 };
index f1f04ce12f2b3d104533948bc2f074376e237c65..b47d6c8ac6c583c42aa8a1c7e9b78f047b06bd74 100644 (file)
@@ -190,9 +190,9 @@ static void s3_update_irqs(s3_t *s3)
 {
         int enabled = s3_vga_vsync_enabled(s3);
         if (((s3->subsys_cntl & s3->subsys_stat & INT_MASK) && (s3->svga.crtc[0x32] & 0x10)) || (enabled && (s3->subsys_stat & INT_VSY)))
-                pci_set_irq(s3->card, PCI_INTA);
+                pci_set_irq(s3->card, PCI_INTA, NULL);
         else
-                pci_clear_irq(s3->card, PCI_INTA);
+                pci_clear_irq(s3->card, PCI_INTA, NULL);
 
         if ((s3->subsys_stat & INT_VSY) && !(s3->subsys_cntl & INT_VSY) && !enabled) {
             s3->subsys_stat &= ~INT_VSY;
@@ -202,7 +202,7 @@ static void s3_update_irqs(s3_t *s3)
 static void s3_update_irqs_thread(s3_t* s3, int mask)
 {
     if ((s3->subsys_cntl & s3->subsys_stat & mask) && (s3->svga.crtc[0x32] & 0x10))
-        pci_set_irq(s3->card, PCI_INTA);
+        pci_set_irq(s3->card, PCI_INTA, NULL);
 }
 
 void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_t *s3);
@@ -943,7 +943,7 @@ static void fifo_thread(void *param)
 
 static void s3_vblank_start(svga_t *svga)
 {
-        s3_t *s3 = (s3_t *)svga->p;
+        s3_t *s3 = (s3_t *)svga->priv;
         if (s3->vblank_irq >= 0) {
             s3->vblank_irq = 1;
         }
@@ -1238,7 +1238,7 @@ uint8_t s3_in(uint16_t addr, void *p)
 
 void s3_recalctimings(svga_t *svga)
 {
-        s3_t *s3 = (s3_t *)svga->p;
+        s3_t *s3 = (s3_t *)svga->priv;
         svga->hdisp = svga->hdisp_old;
         int clk_sel = (svga->miscout >> 2) & 3;
 
@@ -2548,7 +2548,7 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat
 
 void s3_hwcursor_draw(svga_t *svga, int displine)
 {
-        s3_t *s3 = (s3_t *)svga->p;
+        s3_t *s3 = (s3_t *)svga->priv;
         int x;
         uint16_t dat[2];
         int xx;
@@ -2810,7 +2810,7 @@ static void *s3_init(char *bios_fn, int chip)
         mem_mapping_addx(&s3->mmio_mapping,   0xa0000, 0x10000, s3_accel_read, NULL, NULL, s3_accel_write, s3_accel_write_w, s3_accel_write_l, NULL, MEM_MAPPING_EXTERNAL, s3);
         mem_mapping_disablex(&s3->mmio_mapping);
 
-        svga_init(&s3->svga, s3, vram_size, /*4mb - 864 supports 8mb but buggy VESA driver reports 0mb*/
+        svga_init(NULL, &s3->svga, s3, vram_size, /*4mb - 864 supports 8mb but buggy VESA driver reports 0mb*/
                    s3_recalctimings,
                    s3_in, s3_out,
                    s3_hwcursor_draw,
@@ -2953,7 +2953,7 @@ int s3_phoenix_trio64_available()
 
 #endif
 
-void *s3_trio64_init()
+void *s3_trio64_init(const device_t *info)
 {
     s3_t *s3 = (s3_t*)s3_init("86c764x1.bin", S3_TRIO64);
 
@@ -2969,7 +2969,7 @@ void *s3_trio64_init()
 }
 
 
-void *s3_cybervision_init()
+void *s3_cybervision_init(const device_t *info)
 {
     s3_t *s3 = (s3_t*)s3_init("86c764x1.bin", S3_TRIO64);
 
@@ -3161,7 +3161,7 @@ static device_config_t s3_phoenix_trio64_config[] =
 device_t s3_bahamas64_device =
 {
         "Paradise Bahamas 64 (S3 Vision864)",
-        0,
+        0, 0,
         s3_bahamas64_init,
         s3_close,
         s3_bahamas64_available,
@@ -3174,7 +3174,7 @@ device_t s3_bahamas64_device =
 device_t s3_9fx_device =
 {
         "Number 9 9FX (S3 Trio64)",
-        0,
+        0, 0,
         s3_9fx_init,
         s3_close,
         s3_9fx_available,
@@ -3187,7 +3187,7 @@ device_t s3_9fx_device =
 device_t s3_phoenix_trio32_device =
 {
         "Phoenix S3 Trio32",
-        0,
+        0, 0,
         s3_phoenix_trio32_init,
         s3_close,
         s3_phoenix_trio32_available,
@@ -3200,7 +3200,7 @@ device_t s3_phoenix_trio32_device =
 device_t s3_phoenix_trio64_device =
 {
         "Phoenix S3 Trio64",
-        0,
+        0, 0,
         s3_phoenix_trio64_init,
         s3_close,
         s3_phoenix_trio64_available,
@@ -3214,27 +3214,27 @@ device_t s3_phoenix_trio64_device =
 
 device_t s3_cybervision_trio64_device =
 {
-    "CyberVision64",
-    0,
+    "CyberVision64", NULL,
+    0, 0,
     s3_cybervision_init,
     s3_close,
     NULL,
+    NULL,
     s3_speed_changed,
     s3_force_redraw,
-    s3_add_status_info,
     NULL
 };
 
 device_t s3_trio64_device =
 {
-    "S3Trio64",
-    0,
+    "S3Trio64", NULL,
+    0, 0,
     s3_trio64_init,
     s3_close,
     NULL,
+    NULL,
     s3_speed_changed,
     s3_force_redraw,
-    s3_add_status_info,
     NULL
 };
 
index e4a498215a63159964ecc701e5a965b0db9b49b4..3de51d3cae7d133ae0a4f6f962c23e7fafdebb84 100644 (file)
@@ -328,15 +328,15 @@ static int virge_vga_vsync_enabled(virge_t *virge)
 static void s3_virge_update_irqs(virge_t *virge)
 {
         if (((virge->subsys_stat & virge->subsys_cntl & INT_MASK) && virge->svga.crtc[0x32] & 0x10) || virge_vga_vsync_enabled(virge))
-                pci_set_irq(virge->card, PCI_INTA);
+                pci_set_irq(virge->card, PCI_INTA, NULL);
         else
-                pci_clear_irq(virge->card, PCI_INTA);
+                pci_clear_irq(virge->card, PCI_INTA, NULL);
 }
 
 static void s3_virge_update_irqs_thread(virge_t* virge, int mask)
 {
     if ((virge->subsys_stat & virge->subsys_cntl & INT_MASK & mask) && virge->svga.crtc[0x32] & 0x10)
-        pci_set_irq(virge->card, PCI_INTA);
+        pci_set_irq(virge->card, PCI_INTA, NULL);
 }
 
 
@@ -593,7 +593,7 @@ static uint8_t s3_virge_in(uint16_t addr, void *p)
 
 static void s3_virge_recalctimings(svga_t *svga)
 {
-        virge_t *virge = (virge_t *)svga->p;
+        virge_t *virge = (virge_t *)svga->priv;
 
         svga->hdisp = svga->crtc[1];
         svga->hdisp++;
@@ -682,7 +682,7 @@ static void s3_virge_recalctimings(svga_t *svga)
                 
                 svga->overlay.x = virge->streams.sec_x - virge->streams.pri_x;
                 svga->overlay.y = virge->streams.sec_y - virge->streams.pri_y;
-                svga->overlay.ysize = virge->streams.sec_h;
+                svga->overlay.cur_ysize = virge->streams.sec_h;
 
                 if (virge->streams.buffer_ctrl & 2)
                         svga->overlay.addr = virge->streams.sec_fb1;
@@ -824,7 +824,7 @@ static void s3_virge_updatemapping(virge_t *virge)
 
 static void s3_virge_vblank_start(svga_t *svga)
 {
-        virge_t *virge = (virge_t *)svga->p;
+        virge_t *virge = (virge_t *)svga->priv;
 
         if (virge->vblank_irq >= 0) {
             virge->vblank_irq = 1;
@@ -3499,7 +3499,7 @@ static void queue_triangle(virge_t *virge)
 
 static void s3_virge_hwcursor_draw(svga_t *svga, int displine)
 {
-        virge_t *virge = (virge_t *)svga->p;
+        virge_t *virge = (virge_t *)svga->priv;
         int x;
         uint16_t dat[2];
         int xx;
@@ -3804,7 +3804,7 @@ static void s3_virge_hwcursor_draw(svga_t *svga, int displine)
 
 static void s3_virge_overlay_draw(svga_t *svga, int displine)
 {
-        virge_t *virge = (virge_t *)svga->p;
+        virge_t *virge = (virge_t *)svga->priv;
         int offset = (virge->streams.sec_x - virge->streams.pri_x) + 1;
         int h_acc = virge->streams.dda_horiz_accumulator;
         int r[8], g[8], b[8];
@@ -3949,7 +3949,7 @@ static void s3_virge_pci_write(int func, int addr, uint8_t val, void *p)
         }
 }
 
-static void *s3_virge_init()
+static void *s3_virge_init(const device_t *info)
 {
         virge_t *virge = (virge_t*)malloc(sizeof(virge_t));
         memset(virge, 0, sizeof(virge_t));
@@ -3958,7 +3958,7 @@ static void *s3_virge_init()
         virge->dithering_enabled = device_get_config_int("dithering");
         virge->memory_size = device_get_config_int("memory");
         
-        svga_init(&virge->svga, virge, virge->memory_size << 20,
+        svga_init(NULL, &virge->svga, virge, virge->memory_size << 20,
                    s3_virge_recalctimings,
                    s3_virge_in, s3_virge_out,
                    s3_virge_hwcursor_draw,
@@ -4057,7 +4057,7 @@ static void *s3_virge_375_init()
         virge->dithering_enabled = device_get_config_int("dithering");
         virge->memory_size = device_get_config_int("memory");
 
-        svga_init(&virge->svga, virge, virge->memory_size << 20,
+        svga_init(NULL, &virge->svga, virge, virge->memory_size << 20,
                    s3_virge_recalctimings,
                    s3_virge_in, s3_virge_out,
                    s3_virge_hwcursor_draw,
@@ -4277,14 +4277,14 @@ static device_config_t s3_virge_config[] =
 
 device_t s3_virge_device =
 {
-        "Diamond Stealth 3D 2000 (S3 ViRGE)",
-        0,
+        "Diamond Stealth 3D 2000 (S3 ViRGE)", NULL,
+        0, 0,
         s3_virge_init,
         s3_virge_close,
+        NULL,
         s3_virge_available,
         s3_virge_speed_changed,
         s3_virge_force_redraw,
-        s3_virge_add_status_info,
 #ifndef UAE
         s3_virge_config
 #endif
@@ -4294,7 +4294,7 @@ device_t s3_virge_device =
 device_t s3_virge_375_device =
 {
         "S3 ViRGE/DX",
-        0,
+        0, 0,
         s3_virge_375_init,
         s3_virge_close,
         s3_virge_375_available,
index 57024c57ea48d52e0aa21aa312baa29db2d4f4c1..cf7ceb70aa773267713992b9a30cb912c2d38f5d 100644 (file)
@@ -21,6 +21,7 @@
 #include <memory>
 #include "ibm.h"
 #include "mem.h"
+#include "device.h"
 #include "video.h"
 #include "vid_svga.h"
 #include "vid_sdac_ramdac.h"
index 08288ac03ecdfd28fd408e8f01284f5e26c44be2..c39fbf535b3b71a00557b4d09bab67e2de803ecd 100644 (file)
@@ -1,6 +1,7 @@
 /*87C716 'SDAC' true colour RAMDAC emulation*/
 #include "ibm.h"
 #include "mem.h"
+#include "device.h"
 #include "video.h"
 #include "vid_svga.h"
 #include "vid_sdac_ramdac.h"
index d6494a356c8c1edd11f35713ce76c6c62d04bff3..478eaa65ad20049a2e313180533c7516cbbc71d0 100644 (file)
@@ -3,6 +3,7 @@
 #include <stdlib.h>
 #include "ibm.h"
 #include "mem.h"
+#include "device.h"
 #include "video.h"
 #include "vid_svga.h"
 #include "vid_svga_render.h"
@@ -57,7 +58,9 @@ void svga_out(uint16_t addr, uint8_t val, void *p)
         svga_t *svga = (svga_t *)p;
         int c;
         uint8_t o;
-//        printf("OUT SVGA %03X %02X %04X:%04X\n",addr,val,CS,pc);
+        uint8_t index;
+
+//      printf("OUT SVGA %03X %02X %04X:%04X\n",addr,val,CS,pc);
         switch (addr)
         {
                 case 0x3C0:
@@ -100,9 +103,9 @@ void svga_out(uint16_t addr, uint8_t val, void *p)
                 case 0x3C2:
                 svga->miscout = val;
                 svga->vidclock = val & 4;// printf("3C2 write %02X\n",val);
-                io_removehandlerx(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->p);
+                io_removehandlerx(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->priv);
                 if (!(val & 1))
-                        io_sethandlerx(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->p);
+                        io_sethandlerx(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->priv);
                 svga_recalctimings(svga);
                 break;
                 case 0x3C4: 
@@ -145,40 +148,42 @@ void svga_out(uint16_t addr, uint8_t val, void *p)
                 svga->dac_mask = val; 
                 break;
                 case 0x3C7: 
-                svga->dac_read = val; 
-                svga->dac_pos = 0; 
-                break;
                 case 0x3C8: 
-                svga->dac_write = val; 
-                svga->dac_read = val - 1; 
-                svga->dac_pos = 0; 
+                svga->dac_pos = 0;
+                svga->dac_status = addr & 0x03;
+                svga->dac_addr = (val + (addr & 0x01)) & 0xff;
                 break;
                 case 0x3C9:
                 svga->dac_status = 0;
-                svga->fullchange = changeframecount;
-                switch (svga->dac_pos)
-                {
-                        case 0: 
+                if (svga->adv_flags & FLAG_RAMDAC_SHIFT)
+                    val <<= 2;
+                svga->fullchange = svga->monitor->mon_changeframecount;
+                switch (svga->dac_pos) {
+                    case 0:
                         svga->dac_r = val;
-                        svga->dac_pos++; 
+                        svga->dac_pos++;
                         break;
-                        case 1: 
+                    case 1:
                         svga->dac_g = val;
-                        svga->dac_pos++; 
+                        svga->dac_pos++;
                         break;
-                        case 2: 
-                        svga->vgapal[svga->dac_write].r = svga->dac_r;
-                        svga->vgapal[svga->dac_write].g = svga->dac_g;
-                        svga->vgapal[svga->dac_write].b = val; 
-                        //pclog("%d: %02x %02x %02x\n", svga->dac_write, svga->dac_r, svga->dac_g, val);
+                    case 2:
+                        index = svga->dac_addr & 0xff;
+                        svga->dac_b = val;
+                        svga->vgapal[index].r = svga->dac_r;
+                        svga->vgapal[index].g = svga->dac_g;
+                        svga->vgapal[index].b = svga->dac_b;
+                        //if (index < 16)
+                        //    pclog("%d: %02x %02x %02x\n", index, svga->dac_r, svga->dac_g, svga->dac_b);
                         if (svga->ramdac_type == RAMDAC_8BIT)
-                                svga->pallook[svga->dac_write] = makecol32(svga->vgapal[svga->dac_write].r, svga->vgapal[svga->dac_write].g, svga->vgapal[svga->dac_write].b);
+                            svga->pallook[index] = makecol32(svga->vgapal[index].r, svga->vgapal[index].g, svga->vgapal[index].b);
                         else
-                                svga->pallook[svga->dac_write] = makecol32((svga->vgapal[svga->dac_write].r & 0x3f) * 4, (svga->vgapal[svga->dac_write].g & 0x3f) * 4, (svga->vgapal[svga->dac_write].b & 0x3f) * 4); 
-                        if (svga->swaprb)
-                            svga->pallook[svga->dac_write] = ((svga->pallook[svga->dac_write] >> 16) & 0xff) | ((svga->pallook[svga->dac_write] & 0xff) << 16) | (svga->pallook[svga->dac_write] & 0x00ff00);
-                        svga->dac_pos = 0; 
-                        svga->dac_write = (svga->dac_write + 1) & 255; 
+                            svga->pallook[index] = makecol32(video_6to8[svga->vgapal[index].r & 0x3f], video_6to8[svga->vgapal[index].g & 0x3f], video_6to8[svga->vgapal[index].b & 0x3f]);
+                        svga->dac_pos = 0;
+                        svga->dac_addr = (svga->dac_addr + 1) & 0xff;
+                        break;
+
+                    default:
                         break;
                 }
                 break;
@@ -237,6 +242,9 @@ uint8_t svga_in(uint16_t addr, void *p)
 {
         svga_t *svga = (svga_t *)p;
         uint8_t temp;
+        uint8_t index;
+        uint8_t ret = 0xff;
+        
 //        if (addr!=0x3da) pclog("Read port %04X\n",addr);
         switch (addr)
         {
@@ -256,28 +264,38 @@ uint8_t svga_in(uint16_t addr, void *p)
                 return svga->seqregs[svga->seqaddr & 0xF];
                 case 0x3c6: return svga->dac_mask;
                 case 0x3c7: return svga->dac_status;
-                case 0x3c8: return svga->dac_write;
+                case 0x3c8: return svga->dac_addr;
                 case 0x3c9:
-                svga->dac_status = 3;
-                switch (svga->dac_pos)
-                {
-                        case 0: 
-                        svga->dac_pos++; 
+                index = (svga->dac_addr - 1) & 0xff;
+                switch (svga->dac_pos) {
+                    case 0:
+                        svga->dac_pos++;
                         if (svga->ramdac_type == RAMDAC_8BIT)
-                                return svga->vgapal[svga->dac_read].r;
-                        return svga->vgapal[svga->dac_read].r & 0x3f;
-                        case 1: 
-                        svga->dac_pos++; 
+                            ret = svga->vgapal[index].r;
+                        else
+                            ret = svga->vgapal[index].r & 0x3f;
+                        break;
+                    case 1:
+                        svga->dac_pos++;
                         if (svga->ramdac_type == RAMDAC_8BIT)
-                                return svga->vgapal[svga->dac_read].g;
-                        return svga->vgapal[svga->dac_read].g & 0x3f;
-                        case 2: 
-                        svga->dac_pos=0; 
-                        svga->dac_read = (svga->dac_read + 1) & 255; 
+                            ret = svga->vgapal[index].g;
+                        else
+                            ret = svga->vgapal[index].g & 0x3f;
+                        break;
+                    case 2:
+                        svga->dac_pos  = 0;
+                        svga->dac_addr = (svga->dac_addr + 1) & 0xff;
                         if (svga->ramdac_type == RAMDAC_8BIT)
-                                return svga->vgapal[(svga->dac_read - 1) & 255].b;
-                        return svga->vgapal[(svga->dac_read - 1) & 255].b & 0x3f;
+                            ret = svga->vgapal[index].b;
+                        else
+                            ret = svga->vgapal[index].b & 0x3f;
+                        break;
+
+                    default:
+                        break;
                 }
+                if (svga->adv_flags & FLAG_RAMDAC_SHIFT)
+                    ret >>= 2;
                 break;
                 case 0x3CC: 
                 return svga->miscout;
@@ -295,7 +313,7 @@ uint8_t svga_in(uint16_t addr, void *p)
                 return svga->cgastat;
         }
 //        printf("Bad EGA read %04X %04X:%04X\n",addr,cs>>4,pc);
-        return 0xFF;
+        return ret;
 }
 
 void svga_set_ramdac_type(svga_t *svga, int type)
@@ -313,7 +331,7 @@ void svga_set_ramdac_type(svga_t *svga, int type)
                         else
                                 svga->pallook[c] = makecol32((svga->vgapal[c].r & 0x3f) * 4, (svga->vgapal[c].g & 0x3f) * 4, (svga->vgapal[c].b & 0x3f) * 4); 
                         if (svga->swaprb)
-                            svga->pallook[svga->dac_write] = ((svga->pallook[svga->dac_write] >> 16) & 0xff) | ((svga->pallook[svga->dac_write] & 0xff) << 16) | (svga->pallook[svga->dac_write] & 0x00ff00);
+                            svga->pallook[svga->dac_addr] = ((svga->pallook[c] >> 16) & 0xff) | ((svga->pallook[c] & 0xff) << 16) | (svga->pallook[c] & 0x00ff00);
                 }
         }
 }
@@ -549,7 +567,7 @@ int svga_poll(void *p)
 //                if (!(vc & 15)) pclog("VC %i %i\n", vc, GetTickCount());
                 if (svga->displine == svga->hwcursor_latch.y && svga->hwcursor_latch.ena)
                 {
-                        svga->hwcursor_on = svga->hwcursor.ysize - svga->hwcursor_latch.yoff;
+                        svga->hwcursor_on = svga->hwcursor.cur_ysize - svga->hwcursor_latch.yoff;
                         if (svga->hwcursor_on < 0)
                                 svga->hwcursor_on = 0;
                         svga->hwcursor_oddeven = 0;
@@ -557,30 +575,30 @@ int svga_poll(void *p)
 
                 if (svga->displine == svga->hwcursor_latch.y+1 && svga->hwcursor_latch.ena && svga->interlace)
                 {
-                        svga->hwcursor_on = svga->hwcursor.ysize - svga->hwcursor_latch.yoff;
+                        svga->hwcursor_on = svga->hwcursor.cur_ysize - svga->hwcursor_latch.yoff;
                         if (svga->hwcursor_on < 0)
                                 svga->hwcursor_on = 0;
                         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_on = svga->dac_hwcursor_latch.cur_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_on = svga->dac_hwcursor_latch.cur_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;
+                        svga->overlay_on = svga->overlay_latch.cur_ysize - svga->overlay_latch.yoff;
                         svga->overlay_oddeven = 0;
                 }
                 if (svga->displine == svga->overlay_latch.y+1 && svga->overlay_latch.ena && svga->interlace)
                 {
-                        svga->overlay_on = svga->overlay_latch.ysize - svga->overlay_latch.yoff;
+                        svga->overlay_on = svga->overlay_latch.cur_ysize - svga->overlay_latch.yoff;
                         svga->overlay_oddeven = 1;
                 }
 #ifndef UAE
@@ -833,6 +851,7 @@ int svga_poll(void *p)
                         }
                         svga->scrollcache_src = 0;
                         svga->scrollcache_dst_reset = svga->scrollcache_dst;
+                        svga->x_add = svga->scrollcache_dst;
 
                         if (svga->adjust_panning) {
                             svga->adjust_panning(svga);
@@ -888,7 +907,7 @@ void svga_setvram(void *p, uint8_t *vram)
     svga->vram = vram;
 }
 
-int svga_init(svga_t *svga, void *p, int memsize, 
+int svga_init(const device_t *info, svga_t *svga, void *priv, int memsize, 
                void (*recalctimings_ex)(struct svga_t *svga),
                uint8_t (*video_in) (uint16_t addr, void *p),
                void    (*video_out)(uint16_t addr, uint8_t val, void *p),
@@ -897,7 +916,9 @@ int svga_init(svga_t *svga, void *p, int memsize,
 {
         int c, d, e;
         
-        svga->p = p;
+        svga->priv = priv;
+        svga->monitor_index = monitor_index_global;
+        svga->monitor = &monitors[svga->monitor_index];
         
         for (c = 0; c < 256; c++)
         {
@@ -910,6 +931,9 @@ int svga_init(svga_t *svga, void *p, int memsize,
         }
         svga->readmode = 0;
 
+        svga->x_add = 8;
+        svga->y_add = 16;
+
         svga->crtcreg_mask = 0x3f;
         svga->crtc[0] = 63;
         svga->crtc[6] = 255;
@@ -932,7 +956,7 @@ int svga_init(svga_t *svga, void *p, int memsize,
         svga->video_out = video_out;
         svga->hwcursor_draw = hwcursor_draw;
         svga->overlay_draw = overlay_draw;
-        svga->hwcursor.ysize = 64;
+        svga->hwcursor.cur_ysize = 64;
         svga->ksc5601_english_font_type = 0;
         svga_recalctimings(svga);
 
index a444a828deadcd09a29a3d6a07641509733d1714..5ca4a6b9ff9938654d15c94b90d3a7e1afc789b9 100644 (file)
 #    define FLAG_S3_911_16BIT 256
 #    define FLAG_512K_MASK    512
 
+struct monitor_t;
+
 typedef struct svga_t
 {
+        void *priv;
+
         mem_mapping_t mapping;
         
         uint8_t crtcreg, crtcreg_mask;
@@ -43,7 +47,7 @@ typedef struct svga_t
         uint8_t la, lb, lc, ld;
         
         uint8_t dac_mask, dac_status;
-        int dac_read, dac_write, dac_pos;
+        int dac_pos;
         int dac_r, dac_g, dac_b;
         int dac_addr;
 
@@ -115,7 +119,7 @@ typedef struct svga_t
                 int ena;
                 int x, y;
                 int xoff, yoff;
-                int xsize, ysize;
+                int cur_xsize, cur_ysize;
                 uint32_t addr;
                 uint32_t pitch;
                 int v_acc, h_acc;
@@ -135,10 +139,14 @@ typedef struct svga_t
         void    (*video_out)(uint16_t addr, uint8_t val, void *p);
         uint8_t (*video_in) (uint16_t addr, void *p);
 
+        float (*getclock)(int clock, void *priv);
+        
         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);
+
+        void (*vblank_start)(struct svga_t *svga);
         
         void (*adjust_panning)(struct svga_t *svga);
 
@@ -153,7 +161,6 @@ typedef struct svga_t
         /*If set then another device is driving the monitor output and the SVGA
           card should not attempt to display anything */
         int override;
-        void *p;
 
         uint8_t ksc5601_sbyte_mask;
         uint8_t ksc5601_udc_area_msb[2];
@@ -170,6 +177,11 @@ typedef struct svga_t
           addresses are shifted to match*/
         int packed_chain4;
 
+        /*Disable 8bpp blink mode - some cards support it, some don't, it's a weird mode
+          If mode 13h appears in a reddish-brown background (0x88) with dark green text (0x8F),
+          you should set this flag when entering that mode*/
+        int disable_blink;
+
         /*Force CRTC to dword mode, regardless of CR14/CR17. Required for S3 enhanced mode*/
         int force_dword_mode;
 
@@ -179,6 +191,7 @@ typedef struct svga_t
         uint32_t  overscan_color;
         int ati_4color;
         void *ramdac;
+        void *clock_gen;
         uint32_t  adv_flags;
         int hblankstart;
         int hblankend;
@@ -193,11 +206,23 @@ typedef struct svga_t
         int x_add;
         int y_add;
         uint8_t ext_overscan;
+        uint8_t dpms;
+        uint8_t lut_map;
+
+        int swaprb;
+
+        /* Return a 32 bpp color from a 15/16 bpp color. */
+        uint32_t(*conv_16to32)(struct svga_t *svga, uint16_t color, uint8_t bpp);
+
+        /* Monitor Index */
+        uint8_t monitor_index;
+
+        /* Pointer to monitor */
+        monitor_t *monitor;
 
-        bool swaprb;
 } svga_t;
 
-extern int svga_init(svga_t *svga, void *p, int memsize, 
+extern int svga_init(const device_t *info, svga_t *svga, void *p, int memsize, 
                void (*recalctimings_ex)(struct svga_t *svga),
                uint8_t (*video_in) (uint16_t addr, void *p),
                void    (*video_out)(uint16_t addr, uint8_t val, void *p),
@@ -232,9 +257,21 @@ void svga_set_override(svga_t *svga, int val);
 
 #define RAMDAC_6BIT 0
 #define RAMDAC_8BIT 1
+
+uint32_t svga_lookup_lut_ram(svga_t *svga, uint32_t val);
+
 void svga_set_ramdac_type(svga_t *svga, int type);
 
 void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga);
 
 extern void    sc1502x_ramdac_out(uint16_t addr, uint8_t val, void *priv, svga_t *svga);
 extern uint8_t sc1502x_ramdac_in(uint16_t addr, void *priv, svga_t *svga);
+
+extern void     tvp3026_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, void *priv, svga_t *svga);
+extern uint8_t  tvp3026_ramdac_in(uint16_t addr, int rs2, int rs3, void *priv, svga_t *svga);
+extern uint32_t tvp3026_conv_16to32(svga_t *svga, uint16_t color, uint8_t bpp);
+extern void     tvp3026_recalctimings(void *priv, svga_t *svga);
+extern void     tvp3026_hwcursor_draw(svga_t *svga, int displine);
+extern float    tvp3026_getclock(int clock, void *priv);
+extern void     tvp3026_gpio(uint8_t(*read)(uint8_t cntl, void *priv), void (*write)(uint8_t cntl, uint8_t data, void *priv), void *cb_priv, void *priv);
+extern const device_t tvp3026_ramdac_device;
index 06d41df00dc8b682275a7b7bcf5c11d5fea4b729..da2c369f8dfa819f2f727412d219feddd379c538 100644 (file)
@@ -1,10 +1,28 @@
+
+#include <stdlib.h>
 #include "ibm.h"
 #include "mem.h"
+#include "device.h"
 #include "video.h"
 #include "vid_svga.h"
 #include "vid_svga_render.h"
 #include "vid_svga_render_remap.h"
 
+
+uint32_t
+svga_lookup_lut_ram(svga_t *svga, uint32_t val)
+{
+    if (!svga->lut_map)
+        return val;
+
+    uint8_t r = getcolr(svga->pallook[getcolr(val)]);
+    uint8_t g = getcolg(svga->pallook[getcolg(val)]);
+    uint8_t b = getcolb(svga->pallook[getcolb(val)]);
+    return makecol32(r, g, b) | (val & 0xFF000000);
+}
+
+#define lookup_lut(val) svga_lookup_lut_ram(svga, val)
+
 void svga_render_null(svga_t *svga)
 {
         if (svga->firstline_draw == 4000)
@@ -1128,7 +1146,7 @@ void svga_render_32bpp_highres_swaprb(svga_t *svga)
                         for (x = 0; x <= svga->hdisp; x++)
                         {
                                 uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + shift + (x << 2)) & svga->vram_display_mask]);
-                                dat = ((dat & 0xff0000) >> 16) | ((dat & 0x0000ff) << 16) | ((dat & 0x00ff00));
+                                dat = _byteswap_ulong(dat);
                                 *p++ = dat & 0xffffff;
                         }
                         svga->ma += x * 4;
@@ -1139,7 +1157,7 @@ void svga_render_32bpp_highres_swaprb(svga_t *svga)
                         {
                                 uint32_t addr = svga->remap_func(svga, svga->ma + shift);
                                 uint32_t dat = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]);
-                                dat = ((dat & 0xff0000) >> 16) | ((dat & 0x0000ff) << 16) | ((dat & 0x00ff00));
+                                dat = _byteswap_ulong(dat);
                                 *p++ = dat & 0xffffff;
                                 svga->ma += 4;
                         }
diff --git a/pcem/vid_tvp3026_ramdac.cpp b/pcem/vid_tvp3026_ramdac.cpp
new file mode 100644 (file)
index 0000000..66113ec
--- /dev/null
@@ -0,0 +1,756 @@
+/*
+ * 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.
+ *
+ *          Emulation of the Texas Instruments TVP3026 true colour RAMDAC
+ *          family.
+ *
+ *
+ * TODO:    Clock and other parts.
+ *
+ * Authors: TheCollector1995,
+ *
+ *          Copyright 2021 TheCollector1995.
+ */
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include "ibm.h"
+#include "device.h"
+#include "mem.h"
+#include "video.h"
+#include "vid_svga.h"
+
+typedef struct tvp3026_ramdac_t {
+    PALETTE  extpal;
+    uint32_t extpallook[256];
+    uint8_t  cursor64_data[1024];
+    int      hwc_y;
+    int      hwc_x;
+    uint8_t  ind_idx;
+    uint8_t  dcc;
+    uint8_t  dc_init;
+    uint8_t  ccr;
+    uint8_t  true_color;
+    uint8_t  latch_cntl;
+    uint8_t  mcr;
+    uint8_t  ppr;
+    uint8_t  general_cntl;
+    uint8_t  mclk;
+    uint8_t  misc;
+    uint8_t  type;
+    uint8_t  mode;
+    uint8_t  pll_addr;
+    uint8_t  clock_sel;
+    struct {
+        uint8_t m;
+        uint8_t n;
+        uint8_t p;
+    } pix, mem, loop;
+    uint8_t   gpio_cntl;
+    uint8_t   gpio_data;
+    uint8_t (*gpio_read)(uint8_t cntl, void *priv);
+    void    (*gpio_write)(uint8_t cntl, uint8_t val, void *priv);
+    void     *gpio_priv;
+} tvp3026_ramdac_t;
+
+static void
+tvp3026_set_bpp(tvp3026_ramdac_t *ramdac, svga_t *svga)
+{
+    svga->swaprb = 0;
+    if (ramdac->true_color & 0x80) {
+        if (ramdac->mcr & 0x08)
+            svga->bpp = 8;
+        else
+            svga->bpp = 4;
+    } else {
+        switch (ramdac->true_color & 0x0f) {
+            case 0x01:
+                svga->bpp = 16;
+                break;
+            case 0x03:
+                svga->bpp = 16;
+                break;
+            case 0x05:
+                svga->bpp = 16;
+                break;
+            case 0x04:
+                svga->bpp = 15;
+                break;
+            case 0x06:
+                if (ramdac->true_color & 0x10)
+                    svga->bpp = 24;
+                else
+                    svga->bpp = 32;
+                break;
+            case 0x07:
+                if (ramdac->true_color & 0x10) {
+                    svga->bpp = 24;
+                    svga->swaprb = 1;
+                } else {
+                    svga->bpp = 32;
+                    svga->swaprb = 1;
+                }
+                break;
+            case 0x0e:
+                svga->bpp = 24;
+                break;
+            case 0x0f:
+                svga->bpp = 24;
+                svga->swaprb = 1;
+                break;
+
+            default:
+                break;
+        }
+    }
+    void pcemvideorbswap(bool swapped);
+       pcemvideorbswap(svga->swaprb);
+    svga_recalctimings(svga);
+}
+
+void
+tvp3026_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, void *priv, svga_t *svga)
+{
+    tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) priv;
+    uint32_t          o32;
+    uint8_t          *cd;
+    uint16_t          index;
+    uint8_t           rs      = (addr & 0x03);
+    uint16_t          da_mask = 0x03ff;
+    rs |= (!!rs2 << 2);
+    rs |= (!!rs3 << 3);
+
+    switch (rs) {
+        case 0x00: /* Palette Write Index Register (RS value = 0000) */
+            ramdac->ind_idx = val;
+            //fallthrough;
+        case 0x04: /* Ext Palette Write Index Register (RS value = 0100) */
+        case 0x03:
+        case 0x07: /* Ext Palette Read Index Register (RS value = 0111) */
+            svga->dac_pos    = 0;
+            svga->dac_status = addr & 0x03;
+            svga->dac_addr   = val;
+            if (svga->dac_status)
+                svga->dac_addr = (svga->dac_addr + 1) & da_mask;
+            break;
+        case 0x01: /* Palette Data Register (RS value = 0001) */
+        case 0x02: /* Pixel Read Mask Register (RS value = 0010) */
+            svga_out(addr, val, svga);
+            break;
+        case 0x05: /* Ext Palette Data Register (RS value = 0101) */
+            svga->dac_status = 0;
+            svga->fullchange = changeframecount;
+            switch (svga->dac_pos) {
+                case 0:
+                    svga->dac_r = val;
+                    svga->dac_pos++;
+                    break;
+                case 1:
+                    svga->dac_g = val;
+                    svga->dac_pos++;
+                    break;
+                case 2:
+                    index                   = svga->dac_addr & 3;
+                    ramdac->extpal[index].r = svga->dac_r;
+                    ramdac->extpal[index].g = svga->dac_g;
+                    ramdac->extpal[index].b = val;
+                    if (svga->ramdac_type == RAMDAC_8BIT)
+                        ramdac->extpallook[index] = makecol32(ramdac->extpal[index].r, ramdac->extpal[index].g, ramdac->extpal[index].b);
+                    else
+                        ramdac->extpallook[index] = makecol32(video_6to8[ramdac->extpal[index].r & 0x3f], video_6to8[ramdac->extpal[index].g & 0x3f], video_6to8[ramdac->extpal[index].b & 0x3f]);
+
+                    if (svga->ext_overscan && !index) {
+                        o32                  = svga->overscan_color;
+                        svga->overscan_color = ramdac->extpallook[0];
+                        if (o32 != svga->overscan_color)
+                            svga_recalctimings(svga);
+                    }
+                    svga->dac_addr = (svga->dac_addr + 1) & 0xff;
+                    svga->dac_pos  = 0;
+                    break;
+
+                default:
+                    break;
+            }
+            break;
+        case 0x09: /* Direct Cursor Control (RS value = 1001) */
+            ramdac->dcc = val;
+            if (ramdac->ccr & 0x80) {
+                svga->dac_hwcursor.cur_xsize = svga->dac_hwcursor.cur_ysize = 64;
+                svga->dac_hwcursor.x                                        = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize;
+                svga->dac_hwcursor.y                                        = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize;
+                svga->dac_hwcursor.ena                                      = !!(val & 0x03);
+                ramdac->mode                                                = val & 0x03;
+            }
+            break;
+        case 0x0a: /* Indexed Data (RS value = 1010) */
+            switch (ramdac->ind_idx) {
+                case 0x06: /* Indirect Cursor Control */
+                    ramdac->ccr = val;
+                    if (!(ramdac->ccr & 0x80)) {
+                        svga->dac_hwcursor.cur_xsize = svga->dac_hwcursor.cur_ysize = 64;
+                        svga->dac_hwcursor.x                                        = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize;
+                        svga->dac_hwcursor.y                                        = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize;
+                        svga->dac_hwcursor.ena                                      = !!(val & 0x03);
+                        ramdac->mode                                                = val & 0x03;
+                    } else {
+                        svga->dac_hwcursor.cur_xsize = svga->dac_hwcursor.cur_ysize = 64;
+                        svga->dac_hwcursor.x                                        = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize;
+                        svga->dac_hwcursor.y                                        = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize;
+                        svga->dac_hwcursor.ena                                      = !!(ramdac->dcc & 0x03);
+                        ramdac->mode                                                = ramdac->dcc & 0x03;
+                    }
+                    break;
+                case 0x0f: /* Latch Control */
+                    ramdac->latch_cntl = val;
+                    break;
+                case 0x18: /* True Color Control */
+                    ramdac->true_color = val;
+                    tvp3026_set_bpp(ramdac, svga);
+                    break;
+                case 0x19: /* Multiplex Control */
+                    ramdac->mcr = val;
+                    tvp3026_set_bpp(ramdac, svga);
+                    break;
+                case 0x1a: /* Clock Selection */
+                    ramdac->clock_sel = val;
+                    break;
+                case 0x1c: /* Palette-Page Register */
+                    ramdac->ppr = val;
+                    break;
+                case 0x1d: /* General Control Register */
+                    ramdac->general_cntl = val;
+                    break;
+                case 0x1e: /* Miscellaneous Control */
+                    ramdac->misc      = val;
+                    svga->ramdac_type = (val & 0x08) ? RAMDAC_8BIT : RAMDAC_6BIT;
+                    break;
+                case 0x2a: /* General-Purpose I/O Control */
+                    ramdac->gpio_cntl = val;
+                    if (ramdac->gpio_write)
+                        ramdac->gpio_write(ramdac->gpio_cntl, ramdac->gpio_data, ramdac->gpio_priv);
+                    break;
+                case 0x2b: /* General-Purpose I/O Data */
+                    ramdac->gpio_data = val;
+                    if (ramdac->gpio_write)
+                        ramdac->gpio_write(ramdac->gpio_cntl, ramdac->gpio_data, ramdac->gpio_priv);
+                    break;
+                case 0x2c: /* PLL Address */
+                    ramdac->pll_addr = val;
+                    break;
+                case 0x2d: /* Pixel clock PLL data */
+                    switch (ramdac->pll_addr & 3) {
+                        case 0:
+                            ramdac->pix.n = val;
+                            break;
+                        case 1:
+                            ramdac->pix.m = val;
+                            break;
+                        case 2:
+                            ramdac->pix.p = val;
+                            break;
+
+                        default:
+                            break;
+                    }
+                    ramdac->pll_addr = ((ramdac->pll_addr + 1) & 3) | (ramdac->pll_addr & 0xfc);
+                    break;
+                case 0x2e: /* Memory Clock PLL Data */
+                    switch ((ramdac->pll_addr >> 2) & 3) {
+                        case 0:
+                            ramdac->mem.n = val;
+                            break;
+                        case 1:
+                            ramdac->mem.m = val;
+                            break;
+                        case 2:
+                            ramdac->mem.p = val;
+                            break;
+
+                        default:
+                            break;
+                    }
+                    ramdac->pll_addr = ((ramdac->pll_addr + 4) & 0x0c) | (ramdac->pll_addr & 0xf3);
+                    break;
+                case 0x2f: /* Loop Clock PLL Data */
+                    switch ((ramdac->pll_addr >> 4) & 3) {
+                        case 0:
+                            ramdac->loop.n = val;
+                            break;
+                        case 1:
+                            ramdac->loop.m = val;
+                            break;
+                        case 2:
+                            ramdac->loop.p = val;
+                            break;
+
+                        default:
+                            break;
+                    }
+                    ramdac->pll_addr = ((ramdac->pll_addr + 0x10) & 0x30) | (ramdac->pll_addr & 0xcf);
+                    break;
+                case 0x39: /* MCLK/Loop Clock Control */
+                    ramdac->mclk = val;
+                    break;
+
+                default:
+                    break;
+            }
+            break;
+        case 0x0b: /* Cursor RAM Data Register (RS value = 1011) */
+            index          = (svga->dac_addr & da_mask) | ((ramdac->ccr & 0x0c) << 6);
+            cd             = (uint8_t *) ramdac->cursor64_data;
+            cd[index]      = val;
+            svga->dac_addr = (svga->dac_addr + 1) & da_mask;
+            break;
+        case 0x0c: /* Cursor X Low Register (RS value = 1100) */
+            ramdac->hwc_x        = (ramdac->hwc_x & 0x0f00) | val;
+            svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize;
+            break;
+        case 0x0d: /* Cursor X High Register (RS value = 1101) */
+            ramdac->hwc_x        = (ramdac->hwc_x & 0x00ff) | ((val & 0x0f) << 8);
+            svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize;
+            break;
+        case 0x0e: /* Cursor Y Low Register (RS value = 1110) */
+            ramdac->hwc_y        = (ramdac->hwc_y & 0x0f00) | val;
+            svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize;
+            break;
+        case 0x0f: /* Cursor Y High Register (RS value = 1111) */
+            ramdac->hwc_y        = (ramdac->hwc_y & 0x00ff) | ((val & 0x0f) << 8);
+            svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize;
+            break;
+
+        default:
+            break;
+    }
+
+    return;
+}
+
+uint8_t
+tvp3026_ramdac_in(uint16_t addr, int rs2, int rs3, void *priv, svga_t *svga)
+{
+    tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) priv;
+    uint8_t           temp   = 0xff;
+    const uint8_t    *cd;
+    uint16_t          index;
+    uint8_t           rs      = (addr & 0x03);
+    uint16_t          da_mask = 0x03ff;
+    rs |= (!!rs2 << 2);
+    rs |= (!!rs3 << 3);
+
+    switch (rs) {
+        case 0x00: /* Palette Write Index Register (RS value = 0000) */
+        case 0x01: /* Palette Data Register (RS value = 0001) */
+        case 0x02: /* Pixel Read Mask Register (RS value = 0010) */
+        case 0x04: /* Ext Palette Write Index Register (RS value = 0100) */
+            temp = svga_in(addr, svga);
+            break;
+        case 0x03: /* Palette Read Index Register (RS value = 0011) */
+        case 0x07: /* Ext Palette Read Index Register (RS value = 0111) */
+            temp = svga->dac_addr & 0xff;
+            break;
+        case 0x05: /* Ext Palette Data Register (RS value = 0101) */
+            index            = (svga->dac_addr - 1) & 3;
+            svga->dac_status = 3;
+            switch (svga->dac_pos) {
+                case 0:
+                    svga->dac_pos++;
+                    if (svga->ramdac_type == RAMDAC_8BIT)
+                        temp = ramdac->extpal[index].r;
+                    else
+                        temp = ramdac->extpal[index].r & 0x3f;
+                    break;
+                case 1:
+                    svga->dac_pos++;
+                    if (svga->ramdac_type == RAMDAC_8BIT)
+                        temp = ramdac->extpal[index].g;
+                    else
+                        temp = ramdac->extpal[index].g & 0x3f;
+                    break;
+                case 2:
+                    svga->dac_pos  = 0;
+                    svga->dac_addr = svga->dac_addr + 1;
+                    if (svga->ramdac_type == RAMDAC_8BIT)
+                        temp = ramdac->extpal[index].b;
+                    else
+                        temp = ramdac->extpal[index].b & 0x3f;
+                    break;
+
+                default:
+                    break;
+            }
+            break;
+        case 0x09: /* Direct Cursor Control (RS value = 1001) */
+            temp = ramdac->dcc;
+            break;
+        case 0x0a: /* Indexed Data (RS value = 1010) */
+            switch (ramdac->ind_idx) {
+                case 0x01: /* Silicon Revision */
+                    temp = 0x00;
+                    break;
+                case 0x06: /* Indirect Cursor Control */
+                    temp = ramdac->ccr;
+                    break;
+                case 0x0f: /* Latch Control */
+                    temp = ramdac->latch_cntl;
+                    break;
+                case 0x18: /* True Color Control */
+                    temp = ramdac->true_color;
+                    break;
+                case 0x19: /* Multiplex Control */
+                    temp = ramdac->mcr;
+                    break;
+                case 0x1a: /* Clock Selection */
+                    temp = ramdac->clock_sel;
+                    break;
+                case 0x1c: /* Palette-Page Register */
+                    temp = ramdac->ppr;
+                    break;
+                case 0x1d: /* General Control Register */
+                    temp = ramdac->general_cntl;
+                    break;
+                case 0x1e: /* Miscellaneous Control */
+                    temp = ramdac->misc;
+                    break;
+                case 0x2a: /* General-Purpose I/O Control */
+                    temp = ramdac->gpio_cntl;
+                    break;
+                case 0x2b: /* General-Purpose I/O Data */
+                    if (ramdac->gpio_read) {
+                        temp = 0xe0 | (ramdac->gpio_cntl & 0x1f); /* keep upper bits untouched */
+                        ramdac->gpio_data = (ramdac->gpio_data & temp) | (ramdac->gpio_read(ramdac->gpio_cntl, ramdac->gpio_priv) & ~temp);
+                    }
+                    temp = ramdac->gpio_data;
+                    break;
+                case 0x2c: /* PLL Address */
+                    temp = ramdac->pll_addr;
+                    break;
+                case 0x2d: /* Pixel clock PLL data */
+                    switch (ramdac->pll_addr & 3) {
+                        case 0:
+                            temp = ramdac->pix.n;
+                            break;
+                        case 1:
+                            temp = ramdac->pix.m;
+                            break;
+                        case 2:
+                            temp = ramdac->pix.p;
+                            break;
+                        case 3:
+                            temp = 0x40; /*PLL locked to frequency*/
+                            break;
+
+                        default:
+                            break;
+                    }
+                    break;
+                case 0x2e: /* Memory Clock PLL Data */
+                    switch ((ramdac->pll_addr >> 2) & 3) {
+                        case 0:
+                            temp = ramdac->mem.n;
+                            break;
+                        case 1:
+                            temp = ramdac->mem.m;
+                            break;
+                        case 2:
+                            temp = ramdac->mem.p;
+                            break;
+                        case 3:
+                            temp = 0x40; /*PLL locked to frequency*/
+                            break;
+
+                        default:
+                            break;
+                    }
+                    break;
+                case 0x2f: /* Loop Clock PLL Data */
+                    switch ((ramdac->pll_addr >> 4) & 3) {
+                        case 0:
+                            temp = ramdac->loop.n;
+                            break;
+                        case 1:
+                            temp = ramdac->loop.m;
+                            break;
+                        case 2:
+                            temp = ramdac->loop.p;
+                            break;
+
+                        default:
+                            break;
+                    }
+                    break;
+                case 0x39: /* MCLK/Loop Clock Control */
+                    temp = ramdac->mclk;
+                    break;
+                case 0x3f: /* ID */
+                    temp = 0x26;
+                    break;
+
+                default:
+                    break;
+            }
+            break;
+        case 0x0b: /* Cursor RAM Data Register (RS value = 1011) */
+            index = ((svga->dac_addr - 1) & da_mask) | ((ramdac->ccr & 0x0c) << 6);
+            cd    = (uint8_t *) ramdac->cursor64_data;
+            temp  = cd[index];
+
+            svga->dac_addr = (svga->dac_addr + 1) & da_mask;
+            break;
+        case 0x0c: /* Cursor X Low Register (RS value = 1100) */
+            temp = ramdac->hwc_x & 0xff;
+            break;
+        case 0x0d: /* Cursor X High Register (RS value = 1101) */
+            temp = (ramdac->hwc_x >> 8) & 0xff;
+            break;
+        case 0x0e: /* Cursor Y Low Register (RS value = 1110) */
+            temp = ramdac->hwc_y & 0xff;
+            break;
+        case 0x0f: /* Cursor Y High Register (RS value = 1111) */
+            temp = (ramdac->hwc_y >> 8) & 0xff;
+            break;
+
+        default:
+            break;
+    }
+
+    return temp;
+}
+
+void
+tvp3026_recalctimings(void *priv, svga_t *svga)
+{
+    const tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) priv;
+
+    svga->interlace = !!(ramdac->ccr & 0x40);
+    /* TODO: Figure out gamma correction for 15/16 bpp color. */
+    svga->lut_map = !!((svga->bpp >= 15 && (svga->bpp != 24)) && (ramdac->true_color & 0xf0) != 0x00);
+
+    if (!(ramdac->clock_sel & 0x70)) {
+        if (ramdac->mcr != 0x98) {
+            svga->hdisp <<= 1;
+            svga->dots_per_clock <<= 1;
+        }
+    }
+}
+
+uint32_t
+tvp3026_conv_16to32(svga_t* svga, uint16_t color, uint8_t bpp)
+{
+    uint32_t ret = 0x00000000;
+
+    if (svga->lut_map) {
+        if (bpp == 15) {
+            uint8_t b = getcolr(svga->pallook[(color & 0x1f) << 3]);
+            uint8_t g = getcolg(svga->pallook[(color & 0x3e0) >> 2]);
+            uint8_t r = getcolb(svga->pallook[(color & 0x7c00) >> 7]);
+            ret = (video_15to32[color] & 0xFF000000) | makecol(r, g, b);
+        } else {
+            uint8_t b = getcolr(svga->pallook[(color & 0x1f) << 3]);
+            uint8_t g = getcolg(svga->pallook[(color & 0x7e0) >> 3]);
+            uint8_t r = getcolb(svga->pallook[(color & 0xf800) >> 8]);
+            ret = (video_16to32[color] & 0xFF000000) | makecol(r, g, b);
+        }
+    } else
+        ret = (bpp == 15) ? video_15to32[color] : video_16to32[color];
+
+    return ret;
+}
+
+void
+tvp3026_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;
+    tvp3026_ramdac_t *ramdac = (tvp3026_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,
+       so a 32x32 cursor has 4 bytes per line, and a 64x64
+       cursor has 8 bytes per line. */
+    pitch = (svga->dac_hwcursor_latch.cur_xsize >> 3); /* Bytes per line. */
+    /* A 32x32 cursor has 128 bytes per line, and a 64x64
+       cursor has 512 bytes per line. */
+    bppl = (pitch * svga->dac_hwcursor_latch.cur_ysize); /* Bytes per plane. */
+    mode = ramdac->mode;
+
+    if (svga->interlace && svga->dac_hwcursor_oddeven)
+        svga->dac_hwcursor_latch.addr += pitch;
+
+    cd = (uint8_t *) ramdac->cursor64_data;
+
+    for (int x = 0; x < svga->dac_hwcursor_latch.cur_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) & 2047;
+            p     = svga->monitor->target_buffer->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: /* XGA */
+                        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;
+}
+
+float
+tvp3026_getclock(int clock, void *priv)
+{
+    const tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) priv;
+    int                     n;
+    int                     m;
+    int                     pl;
+    float                   f_vco;
+    float                   f_pll;
+
+    if (clock == 0)
+        return 25175000.0;
+    if (clock == 1)
+        return 28322000.0;
+
+    /*Fvco = 8 x Fref x (65 - M) / (65 - N)*/
+    /*Fpll = Fvco / 2^P*/
+    n     = ramdac->pix.n & 0x3f;
+    m     = ramdac->pix.m & 0x3f;
+    pl    = ramdac->pix.p & 0x03;
+    f_vco = 8.0f * 14318184 * (float) (65 - m) / (float) (65 - n);
+    f_pll = f_vco / (float) (1 << pl);
+
+    return f_pll;
+}
+
+void
+tvp3026_gpio(uint8_t (*read)(uint8_t cntl, void *priv),
+             void (*write)(uint8_t cntl, uint8_t val, void *priv),
+             void *cb_priv, void *priv)
+{
+    tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) priv;
+
+    ramdac->gpio_read  = read;
+    ramdac->gpio_write = write;
+    ramdac->gpio_priv  = cb_priv;
+}
+
+void *
+tvp3026_ramdac_init(const device_t *info)
+{
+    tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) malloc(sizeof(tvp3026_ramdac_t));
+    memset(ramdac, 0, sizeof(tvp3026_ramdac_t));
+
+    ramdac->type = info->local;
+
+    ramdac->latch_cntl = 0x06;
+    ramdac->true_color = 0x80;
+    ramdac->mcr        = 0x98;
+    ramdac->clock_sel  = 0x07;
+    ramdac->mclk       = 0x18;
+
+    return ramdac;
+}
+
+static void
+tvp3026_ramdac_close(void *priv)
+{
+    tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) priv;
+
+    if (ramdac)
+        free(ramdac);
+}
+
+const device_t tvp3026_ramdac_device = {
+    .name          = "TI TVP3026 RAMDAC",
+    .internal_name = "tvp3026_ramdac",
+    .flags         = 0,
+    .local         = 0,
+    .init          = tvp3026_ramdac_init,
+    .close         = tvp3026_ramdac_close,
+    .reset         = NULL,
+    .available = NULL,
+    .speed_changed = NULL,
+    .force_redraw  = NULL,
+    .config        = NULL
+};
index 3726074141f9a12172924a97580ef37507bfe116..7868bd6ca70a00ebc6625fcca57e34f67b562cf6 100644 (file)
@@ -416,9 +416,9 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p)
                 
                 case SST_swapbufferCMD:
                 voodoo->cmd_written++;
-                thread_lock_mutex(voodoo->swap_mutex);
+                thread_wait_mutex(voodoo->swap_mutex);
                 voodoo->swap_count++;
-                thread_unlock_mutex(voodoo->swap_mutex);
+                thread_release_mutex(voodoo->swap_mutex);
                 if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE)
                         return;
                 voodoo_queue_command(voodoo, addr | FIFO_WRITEL_REG, val);
@@ -499,9 +499,9 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p)
                         if ((voodoo->fbiInit1 & FBIINIT1_VIDEO_RESET) && !(val & FBIINIT1_VIDEO_RESET))
                         {
                                 voodoo->line = 0;
-                                thread_lock_mutex(voodoo->swap_mutex);
+                                thread_wait_mutex(voodoo->swap_mutex);
                                 voodoo->swap_count = 0;
-                                thread_unlock_mutex(voodoo->swap_mutex);
+                                thread_release_mutex(voodoo->swap_mutex);
                                 voodoo->retrace_count = 0;
                         }
                         voodoo->fbiInit1 = (val & ~5) | (voodoo->fbiInit1 & 5);
@@ -1212,7 +1212,7 @@ void *voodoo_2d3d_card_init(int type)
         return voodoo;
 }
 
-void *voodoo_init()
+void *voodoo_init(const device_t *info)
 {
         voodoo_set_t *voodoo_set = (voodoo_set_t*)malloc(sizeof(voodoo_set_t));
         uint32_t tmuConfig = 1;
@@ -1470,13 +1470,12 @@ static device_config_t voodoo_config[] =
 
 device_t voodoo_device =
 {
-        "3DFX Voodoo Graphics",
-        DEVICE_PCI,
+        "3DFX Voodoo Graphics", NULL,
+        DEVICE_PCI, 0,
         voodoo_init,
         voodoo_close,
         NULL,
-        voodoo_speed_changed,
         NULL,
-        voodoo_add_status_info,
-        voodoo_config
+        voodoo_speed_changed,
+        NULL
 };
index 60411f9d8d16f6b9667b5ce4fb34070ac323c6ec..a1f0b04c5f0cd906ae459955774884ff50d1f070 100644 (file)
@@ -222,15 +222,15 @@ static int banshee_vga_vsync_enabled(banshee_t *banshee)
 static void banshee_update_irqs(banshee_t *banshee)
 {
     if (banshee->vblank_irq > 0 && banshee_vga_vsync_enabled(banshee)) {
-        pci_set_irq(NULL, PCI_INTA);
+        pci_set_irq(NULL, PCI_INTA, NULL);
     } else {
-        pci_clear_irq(NULL, PCI_INTA);
+        pci_clear_irq(NULL, PCI_INTA, NULL);
     }
 }
 
 static void banshee_vblank_start(svga_t* svga)
 {
-    banshee_t *banshee = (banshee_t*)svga->p;
+    banshee_t *banshee = (banshee_t*)svga->priv;
     if (banshee->vblank_irq >= 0) {
         banshee->vblank_irq = 1;
         banshee_update_irqs(banshee);
@@ -365,7 +365,7 @@ static void banshee_updatemapping(banshee_t *banshee)
 
 static void banshee_render_16bpp_tiled(svga_t *svga)
 {
-        banshee_t *banshee = (banshee_t *)svga->p;
+        banshee_t *banshee = (banshee_t *)svga->priv;
         int x;
         int offset = 32;
         uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[offset];
@@ -408,7 +408,7 @@ static void banshee_render_16bpp_tiled(svga_t *svga)
 
 static void banshee_recalctimings(svga_t *svga)
 {
-        banshee_t *banshee = (banshee_t *)svga->p;
+        banshee_t *banshee = (banshee_t *)svga->priv;
         voodoo_t *voodoo = banshee->voodoo;
         
 /*7 R/W Horizontal Retrace End bit 5. -
@@ -496,12 +496,12 @@ static void banshee_recalctimings(svga_t *svga)
 
                 svga->overlay.x = voodoo->overlay.start_x;
                 svga->overlay.y = voodoo->overlay.start_y;
-                svga->overlay.xsize = voodoo->overlay.size_x;
-                svga->overlay.ysize = voodoo->overlay.size_y;
+                svga->overlay.cur_xsize = voodoo->overlay.size_x;
+                svga->overlay.cur_ysize = voodoo->overlay.size_y;
                 svga->overlay.pitch = (banshee->vidDesktopOverlayStride & VID_STRIDE_OVERLAY_MASK) >> VID_STRIDE_OVERLAY_SHIFT;
                 if (banshee->vidProcCfg & VIDPROCCFG_OVERLAY_TILE)
                         svga->overlay.pitch *= 128*32;
-                if (svga->overlay.xsize <= 0 || svga->overlay.ysize <= 0)
+                if (svga->overlay.cur_xsize <= 0 || svga->overlay.cur_ysize <= 0)
                         svga->overlay.ena = 0;
                 if (svga->overlay.ena)
                 {
@@ -696,8 +696,8 @@ static void banshee_ext_outl(uint16_t addr, uint32_t val, void *p)
                 else
                         svga->hwcursor.yoff = 0;
                 svga->hwcursor.addr = (banshee->hwCurPatAddr & 0xfffff0) + (svga->hwcursor.yoff * 16);
-                svga->hwcursor.xsize = 64;
-                svga->hwcursor.ysize = 64;
+                svga->hwcursor.cur_xsize = 64;
+                svga->hwcursor.cur_ysize = 64;
 //                pclog("hwCurLoc %08x %i\n", val, svga->hwcursor.y);
                 break;
                 case Video_hwCurC0:
@@ -1380,9 +1380,9 @@ static void banshee_reg_writel(uint32_t addr, uint32_t val, void *p)
                         break;
                         
                         case SST_swapPending:
-                        thread_lock_mutex(voodoo->swap_mutex);
+                        thread_wait_mutex(voodoo->swap_mutex);
                         voodoo->swap_count++;
-                        thread_unlock_mutex(voodoo->swap_mutex);
+                        thread_release_mutex(voodoo->swap_mutex);
 //                        voodoo->cmd_written++;
                         break;
                         
@@ -1710,7 +1710,7 @@ static void banshee_write_linear_l(uint32_t addr, uint32_t val, void *p)
 
 void banshee_hwcursor_draw(svga_t *svga, int displine)
 {
-        banshee_t *banshee = (banshee_t *)svga->p;
+        banshee_t *banshee = (banshee_t *)svga->priv;
         int x, c;
         int x_off;
         uint32_t col0 = banshee->hwCurC0;
@@ -2075,7 +2075,7 @@ void voodoo_generate_vb_filters(voodoo_t *voodoo, int fcr, int fcg)
 
 static void banshee_overlay_draw(svga_t *svga, int displine)
 {
-        banshee_t *banshee = (banshee_t *)svga->p;
+        banshee_t *banshee = (banshee_t *)svga->priv;
         voodoo_t *voodoo = banshee->voodoo;
         uint32_t *p;
         int x;
@@ -2133,7 +2133,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine)
                         OVERLAY_SAMPLE(banshee->overlay_buffer[1]);
                         if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE)
                         {
-                                for (x = 0; x < svga->overlay_latch.xsize; x++)
+                                for (x = 0; x < svga->overlay_latch.cur_xsize; x++)
                                 {
                                         unsigned int x_coeff = (src_x & 0xfffff) >> 4;
                                         unsigned int coeffs[4] = {
@@ -2165,7 +2165,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine)
                         }
                         else
                         {
-                                for (x = 0; x < svga->overlay_latch.xsize; x++)
+                                for (x = 0; x < svga->overlay_latch.cur_xsize; x++)
                                 {
                                         uint32_t samp0 = banshee->overlay_buffer[0][src_x >> 20];
                                         uint32_t samp1 = banshee->overlay_buffer[1][src_x >> 20];
@@ -2191,7 +2191,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine)
 
                                 if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) /* leilei HACK - don't know of real 4x1 hscaled behavior yet, double for now */
                                 {
-                                        for (x=0; x<svga->overlay_latch.xsize;x++)
+                                        for (x=0; x<svga->overlay_latch.cur_xsize;x++)
                                         {
                                                 fil[x*3]       = ((banshee->overlay_buffer[0][src_x >> 20]));
                                                 fil[x*3+1]     = ((banshee->overlay_buffer[0][src_x >> 20] >> 8));
@@ -2204,7 +2204,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine)
                                 }
                                 else
                                 {
-                                        for (x=0; x<svga->overlay_latch.xsize;x++)
+                                        for (x=0; x<svga->overlay_latch.cur_xsize;x++)
                                         {
                                                 fil[x*3]       = ((banshee->overlay_buffer[0][x]));
                                                 fil[x*3+1]     = ((banshee->overlay_buffer[0][x] >> 8));
@@ -2216,7 +2216,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine)
                                 }
                                 if (y % 2 == 0)
                                 {
-                                        for (x=0; x<svga->overlay_latch.xsize;x++)
+                                        for (x=0; x<svga->overlay_latch.cur_xsize;x++)
                                         {
                                                 fil[x*3] = banshee->voodoo->purpleline[fil[x*3+0]][0];
                                                 fil[x*3+1] = banshee->voodoo->purpleline[fil[x*3+1]][1];
@@ -2224,25 +2224,25 @@ static void banshee_overlay_draw(svga_t *svga, int displine)
                                         }
                                 }
 
-                                for (x=1; x<svga->overlay_latch.xsize;x++)
+                                for (x=1; x<svga->overlay_latch.cur_xsize;x++)
                                 {
                                         fil3[(x)*3]   = vb_filter_v1_rb [fil[x*3]]  [fil[(x-1) *3]];
                                         fil3[(x)*3+1] = vb_filter_v1_g  [fil[x*3+1]][fil[(x-1) *3+1]];
                                         fil3[(x)*3+2] = vb_filter_v1_rb [fil[x*3+2]] [fil[(x-1) *3+2]];
                                 }
-                                for (x=1; x<svga->overlay_latch.xsize;x++)
+                                for (x=1; x<svga->overlay_latch.cur_xsize;x++)
                                 {
                                         fil[(x)*3]   = vb_filter_v1_rb [fil[x*3]]  [fil3[(x-1) *3]];
                                         fil[(x)*3+1] = vb_filter_v1_g  [fil[x*3+1]][fil3[(x-1) *3+1]];
                                         fil[(x)*3+2] = vb_filter_v1_rb [fil[x*3+2]] [fil3[(x-1) *3+2]];
                                 }
-                                for (x=1; x<svga->overlay_latch.xsize;x++)
+                                for (x=1; x<svga->overlay_latch.cur_xsize;x++)
                                 {
                                         fil3[(x)*3]   = vb_filter_v1_rb [fil[x*3]]  [fil[(x-1) *3]];
                                         fil3[(x)*3+1] = vb_filter_v1_g  [fil[x*3+1]][fil[(x-1) *3+1]];
                                         fil3[(x)*3+2] = vb_filter_v1_rb [fil[x*3+2]] [fil[(x-1) *3+2]];
                                 }
-                                for (x=0; x<svga->overlay_latch.xsize;x++)
+                                for (x=0; x<svga->overlay_latch.cur_xsize;x++)
                                 {
                                         fil[(x)*3]   = vb_filter_v1_rb [fil[x*3]]  [fil3[(x+1) *3]];
                                         fil[(x)*3+1] = vb_filter_v1_g  [fil[x*3+1]][fil3[(x+1) *3+1]];
@@ -2254,7 +2254,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine)
                         {
                                 if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE)
                                 {
-                                        for (x = 0; x < svga->overlay_latch.xsize; x++)
+                                        for (x = 0; x < svga->overlay_latch.cur_xsize; x++)
                                         {
                                                 p[x] = banshee->overlay_buffer[0][src_x >> 20];
                                                 src_x += voodoo->overlay.vidOverlayDudx;
@@ -2262,7 +2262,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine)
                                 }
                                 else
                                 {
-                                        for (x = 0; x < svga->overlay_latch.xsize; x++)
+                                        for (x = 0; x < svga->overlay_latch.cur_xsize; x++)
                                                 p[x] = banshee->overlay_buffer[0][x];
                                 }
                         }
@@ -2290,7 +2290,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine)
 
                                 src = &svga->vram[src_addr2 & svga->vram_mask];
                                 OVERLAY_SAMPLE(banshee->overlay_buffer[1]);
-                                for (x=0; x<svga->overlay_latch.xsize;x++)
+                                for (x=0; x<svga->overlay_latch.cur_xsize;x++)
                                 {
                                         samp1[x*3]     = ((banshee->overlay_buffer[0][x]));
                                         samp1[x*3+1]   = ((banshee->overlay_buffer[0][x] >> 8));
@@ -2327,7 +2327,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine)
 
                                 if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE)  /* 2x2 on a scaled low res */
                                 {
-                                        for (x=0; x<svga->overlay_latch.xsize;x++)
+                                        for (x=0; x<svga->overlay_latch.cur_xsize;x++)
                                         {
                                                 p[x] = (fil[(src_x >> 20)*3+2] << 16) | (fil[(src_x >> 20)*3+1] << 8) | fil[(src_x >> 20)*3];
                                                 src_x += voodoo->overlay.vidOverlayDudx;
@@ -2335,7 +2335,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine)
                                 }
                                 else
                                 {
-                                        for (x=0; x<svga->overlay_latch.xsize;x++)
+                                        for (x=0; x<svga->overlay_latch.cur_xsize;x++)
                                         {
                                                 p[x] = (fil[x*3+2] << 16) | (fil[x*3+1] << 8) | fil[x*3];
                                         }
@@ -2345,7 +2345,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine)
                         {
                                 if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE)
                                 {
-                                        for (x = 0; x < svga->overlay_latch.xsize; x++)
+                                        for (x = 0; x < svga->overlay_latch.cur_xsize; x++)
                                         {
                                                 p[x] = banshee->overlay_buffer[0][src_x >> 20];
 
@@ -2354,7 +2354,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine)
                                 }
                                 else
                                 {
-                                        for (x = 0; x < svga->overlay_latch.xsize; x++)
+                                        for (x = 0; x < svga->overlay_latch.cur_xsize; x++)
                                                 p[x] = banshee->overlay_buffer[0][x];
                                 }
                        }
@@ -2364,7 +2364,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine)
                         default:
                         if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE)
                         {
-                                for (x = 0; x < svga->overlay_latch.xsize; x++)
+                                for (x = 0; x < svga->overlay_latch.cur_xsize; x++)
                                 {
                                         p[x] = banshee->overlay_buffer[0][src_x >> 20];
 
@@ -2373,7 +2373,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine)
                         }
                         else
                         {
-                                for (x = 0; x < svga->overlay_latch.xsize; x++)
+                                for (x = 0; x < svga->overlay_latch.cur_xsize; x++)
                                         p[x] = banshee->overlay_buffer[0][x];
                         }
                         break;
@@ -2398,17 +2398,17 @@ void banshee_set_overlay_addr(void *p, uint32_t addr)
 
 static void banshee_vsync_callback(svga_t *svga)
 {
-        banshee_t *banshee = (banshee_t *)svga->p;
+        banshee_t *banshee = (banshee_t *)svga->priv;
         voodoo_t *voodoo = banshee->voodoo;
 
         voodoo->retrace_count++;
-        thread_lock_mutex(voodoo->swap_mutex);
+        thread_wait_mutex(voodoo->swap_mutex);
         if (voodoo->swap_pending && (voodoo->retrace_count > voodoo->swap_interval))
         {
                 if (voodoo->swap_count > 0)
                         voodoo->swap_count--;
                 voodoo->swap_pending = 0;
-                thread_unlock_mutex(voodoo->swap_mutex);
+                thread_release_mutex(voodoo->swap_mutex);
 
                 memset(voodoo->dirty_line, 1, sizeof(voodoo->dirty_line));
                 voodoo->retrace_count = 0;
@@ -2417,7 +2417,7 @@ static void banshee_vsync_callback(svga_t *svga)
                 voodoo->frame_count++;
         }
         else
-                thread_unlock_mutex(voodoo->swap_mutex);
+                thread_release_mutex(voodoo->swap_mutex);
 
         voodoo->overlay.src_y = 0;
         banshee->desktop_addr = banshee->vidDesktopStartAddr;
@@ -2747,7 +2747,7 @@ static void *banshee_init_common(char *fn, int has_sgram, int type, int voodoo_t
         else
                 mem_size = 16; /*SDRAM Banshee only supports 16 MB*/
 
-        svga_init(&banshee->svga, banshee, mem_size << 20,
+        svga_init(NULL, &banshee->svga, banshee, mem_size << 20,
                    banshee_recalctimings,
                    banshee_in, banshee_out,
                    banshee_hwcursor_draw,
@@ -2852,19 +2852,19 @@ static void *banshee_init_common(char *fn, int has_sgram, int type, int voodoo_t
         return banshee;
 }
 
-static void *banshee_init()
+static void *banshee_init(const device_t *info)
 {
         return banshee_init_common("pci_sg.rom", 1, TYPE_BANSHEE, VOODOO_BANSHEE);
 }
-static void *creative_banshee_init()
+static void *creative_banshee_init(const device_t *info)
 {
         return banshee_init_common("blasterpci.rom", 0, TYPE_BANSHEE, VOODOO_BANSHEE);
 }
-static void *v3_2000_init()
+static void *v3_2000_init(const device_t *info)
 {
         return banshee_init_common("voodoo3_2000/2k11sd.rom", 0, TYPE_V3_2000, VOODOO_3);
 }
-static void *v3_3000_init()
+static void *v3_3000_init(const device_t *info)
 {
         return banshee_init_common("voodoo3_3000/3k12sd.rom", 0, TYPE_V3_3000, VOODOO_3);
 }
@@ -3002,52 +3002,48 @@ static void banshee_add_status_info(char *s, int max_len, void *p)
 
 device_t voodoo_banshee_device =
 {
-        "Voodoo Banshee PCI (reference)",
-        DEVICE_PCI,
+        "Voodoo Banshee PCI (reference)", NULL,
+        DEVICE_PCI, 0,
         banshee_init,
         banshee_close,
+        NULL,
         banshee_available,
         banshee_speed_changed,
-        banshee_force_redraw,
-        banshee_add_status_info,
-        banshee_sgram_config
+        banshee_force_redraw
 };
 
 device_t creative_voodoo_banshee_device =
 {
-        "Creative Labs 3D Blaster Banshee PCI",
-        DEVICE_PCI,
+        "Creative Labs 3D Blaster Banshee PCI", NULL,
+        DEVICE_PCI, 0,
         creative_banshee_init,
         banshee_close,
+        NULL,
         creative_banshee_available,
         banshee_speed_changed,
-        banshee_force_redraw,
-        banshee_add_status_info,
-        banshee_sdram_config
+        banshee_force_redraw
 };
 
 device_t voodoo_3_2000_device =
 {
-        "Voodoo 3 2000 PCI",
-        DEVICE_PCI,
+        "Voodoo 3 2000 PCI", NULL,
+        DEVICE_PCI, 0,
         v3_2000_init,
         banshee_close,
+        NULL,
         v3_2000_available,
         banshee_speed_changed,
-        banshee_force_redraw,
-        banshee_add_status_info,
-        banshee_sdram_config
+        banshee_force_redraw
 };
 
 device_t voodoo_3_3000_device =
 {
-        "Voodoo 3 3000 PCI",
-        DEVICE_PCI,
+        "Voodoo 3 3000 PCI", NULL,
+        DEVICE_PCI, 0,
         v3_3000_init,
         banshee_close,
+        NULL,
         v3_3000_available,
         banshee_speed_changed,
-        banshee_force_redraw,
-        banshee_add_status_info,
-        banshee_sdram_config
+        banshee_force_redraw
 };
index 34d7e13ce7816b6a226b4cf66ca56b9073677b66..70c289ad687d45c812cfb533b016b56e278df6d9 100644 (file)
@@ -531,7 +531,7 @@ skip_draw:
                         {
                                 voodoo_t *voodoo_1 = voodoo->set->voodoos[1];
 
-                                thread_lock_mutex(voodoo->swap_mutex);
+                                thread_wait_mutex(voodoo->swap_mutex);
                                 /*Only swap if both Voodoos are waiting for buffer swap*/
                                 if (voodoo->swap_pending && (voodoo->retrace_count > voodoo->swap_interval) &&
                                     voodoo_1->swap_pending && (voodoo_1->retrace_count > voodoo_1->swap_interval))
@@ -549,7 +549,7 @@ skip_draw:
                                         if (voodoo_1->swap_count > 0)
                                                 voodoo_1->swap_count--;
                                         voodoo_1->swap_pending = 0;
-                                        thread_unlock_mutex(voodoo->swap_mutex);
+                                        thread_release_mutex(voodoo->swap_mutex);
 
                                         thread_set_event(voodoo->wake_fifo_thread);
                                         thread_set_event(voodoo_1->wake_fifo_thread);
@@ -558,19 +558,19 @@ skip_draw:
                                         voodoo_1->frame_count++;
                                 }
                                 else
-                                        thread_unlock_mutex(voodoo->swap_mutex);
+                                        thread_release_mutex(voodoo->swap_mutex);
                         }
                 }
                 else
                 {
-                        thread_lock_mutex(voodoo->swap_mutex);
+                        thread_wait_mutex(voodoo->swap_mutex);
                         if (voodoo->swap_pending && (voodoo->retrace_count > voodoo->swap_interval))
                         {
                                 voodoo->front_offset = voodoo->swap_offset;
                                 if (voodoo->swap_count > 0)
                                         voodoo->swap_count--;
                                 voodoo->swap_pending = 0;
-                                thread_unlock_mutex(voodoo->swap_mutex);
+                                thread_release_mutex(voodoo->swap_mutex);
 
                                 memset(voodoo->dirty_line, 1, 1024);
                                 voodoo->retrace_count = 0;
@@ -578,7 +578,7 @@ skip_draw:
                                 voodoo->frame_count++;
                         }
                         else
-                                thread_unlock_mutex(voodoo->swap_mutex);
+                                thread_release_mutex(voodoo->swap_mutex);
                 }
                 voodoo->v_retrace = 1;
         }
index 1c87316242c548b90b8d2dba761a306ceb565a3a..5a1c2b03b5f108dbd1f83a97b36c051968a8a55e 100644 (file)
@@ -91,7 +91,7 @@ void voodoo_wait_for_swap_complete(voodoo_t *voodoo)
                 thread_wait_event(voodoo->wake_fifo_thread, -1);
                 thread_reset_event(voodoo->wake_fifo_thread);
 
-                thread_lock_mutex(voodoo->swap_mutex);
+                thread_wait_mutex(voodoo->swap_mutex);
                 if ((voodoo->swap_pending && voodoo->flush) || FIFO_FULL)
                 {
                         /*Main thread is waiting for FIFO to empty, so skip vsync wait and just swap*/
@@ -100,11 +100,11 @@ void voodoo_wait_for_swap_complete(voodoo_t *voodoo)
                         if (voodoo->swap_count > 0)
                                 voodoo->swap_count--;
                         voodoo->swap_pending = 0;
-                        thread_unlock_mutex(voodoo->swap_mutex);
+                        thread_release_mutex(voodoo->swap_mutex);
                         break;
                 }
                 else
-                        thread_unlock_mutex(voodoo->swap_mutex);
+                        thread_release_mutex(voodoo->swap_mutex);
         }
 }
 
index 63e590b56ba4f0f7c3d1ed9b4e88bd4f7aad1801..d443bc9087fcf5447302182c3464747cdef2c3a1 100644 (file)
@@ -56,10 +56,10 @@ void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p)
                         if (!(val & 1))
                         {
                                 banshee_set_overlay_addr(voodoo->p, voodoo->leftOverlayBuf);
-                                thread_lock_mutex(voodoo->swap_mutex);
+                                thread_wait_mutex(voodoo->swap_mutex);
                                 if (voodoo->swap_count > 0)
                                         voodoo->swap_count--;
-                                thread_unlock_mutex(voodoo->swap_mutex);
+                                thread_release_mutex(voodoo->swap_mutex);
                                 voodoo->frame_count++;
                         }
                         else if (TRIPLE_BUFFER)
@@ -104,10 +104,10 @@ void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p)
                 {
                         memset(voodoo->dirty_line, 1, sizeof(voodoo->dirty_line));
                         voodoo->front_offset = voodoo->params.front_offset;
-                        thread_lock_mutex(voodoo->swap_mutex);
+                        thread_wait_mutex(voodoo->swap_mutex);
                         if (voodoo->swap_count > 0)
                                 voodoo->swap_count--;
-                        thread_unlock_mutex(voodoo->swap_mutex);
+                        thread_release_mutex(voodoo->swap_mutex);
                 }
                 else if (TRIPLE_BUFFER)
                 {
index e8a97e50423c007ccd4d11ea597754a1f71d12f0..fd37eeb5beaf2280c039237e2d5bca838e1ff18d 100644 (file)
@@ -1,4 +1,10 @@
 
+#define makecol(r, g, b)   ((b) | ((g) << 8) | ((r) << 16))
+#define makecol32(r, g, b) ((b) | ((g) << 8) | ((r) << 16))
+#define getcolr(color) (((color) >> 16) & 0xFF)
+#define getcolg(color) (((color) >> 8) & 0xFF)
+#define getcolb(color) ((color) & 0xFF)
+
 typedef struct
 {
         int w, h;
@@ -24,7 +30,7 @@ extern PCBITMAP *buffer32;
 
 int video_card_available(int card);
 char *video_card_getname(int card);
-struct device_t *video_card_getdevice(int card, int romset);
+device_t *video_card_getdevice(int card, int romset);
 int video_card_has_config(int card, int romset);
 int video_card_getid(char *s);
 int video_old_to_new(int card);
@@ -58,6 +64,7 @@ extern uint8_t fontdatksc5601[16384][32];
 extern uint8_t fontdatksc5601_user[192][32];
 
 extern uint32_t *video_15to32, *video_16to32;
+extern uint32_t *video_6to8;
 
 extern int xsize,ysize;
 
@@ -104,6 +111,7 @@ void video_init();
 void closevideo();
 
 void video_updatetiming();
+void video_force_resize_set_monitor(uint8_t res, int monitor_index);
 
 void hline(PCBITMAP *b, int x1, int y, int x2, int col);
 
@@ -119,3 +127,86 @@ extern uint32_t cgapal[16];
 #define DISPLAY_WHITE 5
 
 void cgapal_rebuild(int display_type, int contrast);
+
+typedef struct video_timings_t {
+    int type;
+    int write_b;
+    int write_w;
+    int write_l;
+    int read_b;
+    int read_w;
+    int read_l;
+} video_timings_t;
+
+typedef struct bitmap_t {
+    int       w;
+    int       h;
+    uint32_t *dat;
+    uint32_t *line[2112 * 2];
+} bitmap_t;
+
+typedef struct monitor_t {
+    char                     name[512];
+    int                      mon_xsize;
+    int                      mon_ysize;
+    int                      mon_scrnsz_x;
+    int                      mon_scrnsz_y;
+    int                      mon_efscrnsz_y;
+    int                      mon_unscaled_size_x;
+    int                      mon_unscaled_size_y;
+    double                   mon_res_x;
+    double                   mon_res_y;
+    int                      mon_bpp;
+    bitmap_t *target_buffer;
+    int                      mon_video_timing_read_b;
+    int                      mon_video_timing_read_w;
+    int                      mon_video_timing_read_l;
+    int                      mon_video_timing_write_b;
+    int                      mon_video_timing_write_w;
+    int                      mon_video_timing_write_l;
+    int                      mon_overscan_x;
+    int                      mon_overscan_y;
+    int                      mon_force_resize;
+    int                      mon_fullchange;
+    int                      mon_changeframecount;
+    //atomic_int               mon_screenshots;
+    uint32_t *mon_pal_lookup;
+    int *mon_cga_palette;
+    int                      mon_pal_lookup_static;  /* Whether it should not be freed by the API. */
+    int                      mon_cga_palette_static; /* Whether it should not be freed by the API. */
+    const video_timings_t *mon_vid_timings;
+    int                      mon_vid_type;
+    //struct blit_data_struct *mon_blit_data_ptr;
+} monitor_t;
+
+typedef struct monitor_settings_t {
+    int mon_window_x; /* (C) window size and position info. */
+    int mon_window_y;
+    int mon_window_w;
+    int mon_window_h;
+    int mon_window_maximized;
+} monitor_settings_t;
+
+extern int monitor_index_global;
+
+#define MONITORS_NUM 2
+extern monitor_t monitors[MONITORS_NUM];
+
+enum {
+    VIDEO_ISA = 0,
+    VIDEO_MCA,
+    VIDEO_BUS,
+    VIDEO_PCI,
+    VIDEO_AGP
+};
+
+#define VIDEO_FLAG_TYPE_CGA     0
+#define VIDEO_FLAG_TYPE_MDA     1
+#define VIDEO_FLAG_TYPE_SPECIAL 2
+#define VIDEO_FLAG_TYPE_8514    3
+#define VIDEO_FLAG_TYPE_XGA     4
+#define VIDEO_FLAG_TYPE_NONE    5
+#define VIDEO_FLAG_TYPE_MASK    7
+
+void video_inform_monitor(int type, const video_timings_t *ptr, int monitor_index);
+#define video_inform(type, video_timings_ptr) video_inform_monitor(type, video_timings_ptr, monitor_index_global)
diff --git a/x86.cpp b/x86.cpp
index 68cc6ddb9bbfa6c930dbfa1a4898d30d4ba5e127..d92fd77f1fc0e690ed4fb63feb48bd9e1d81284d 100644 (file)
--- a/x86.cpp
+++ b/x86.cpp
@@ -48,6 +48,7 @@
 #include "audio.h"
 
 #include "pcem/ibm.h"
+#include "pcem/device.h"
 #include "pcem/pic.h"
 #include "pcem/pit.h"
 #include "pcem/timer.h"
@@ -3554,7 +3555,7 @@ void *sb_2_init();
 void *sb_pro_v1_init();
 void *sb_pro_v2_init();
 void *sb_16_init();
-void *cms_init();
+void *cms_init(const device_t*);
 
 static int x86_global_settings;
 
@@ -3629,15 +3630,15 @@ static void set_sb_emu(struct x86_bridge *xb)
        switch (model)
        {
        case 0:
-               c = cms_init();
+               c = cms_init(NULL);
                p = sb_1_init();
                break;
        case 1:
-               c = cms_init();
+               c = cms_init(NULL);
                p = sb_15_init();
                break;
        case 2:
-               c = cms_init();
+               c = cms_init(NULL);
                p = sb_2_init();
                break;
        case 3:
@@ -4004,7 +4005,7 @@ bool x86_bridge_init(struct autoconfig_info *aci, uae_u32 romtype, int type)
 
        if (xb->type >= TYPE_2286) {
                AT = 1;
-               nvr_device.init();
+               nvr_device.init(&nvr_device);
                TCHAR path[MAX_DPATH];
                cfgfile_resolve_path_out_load(currprefs.flashfile, path, MAX_DPATH, PATH_ROM);
                xb->cmossize = xb->type == TYPE_2386 ? 192 : 64;