]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
GVP WD33C93 SCSI emulation.
authorToni Wilen <twilen@winuae.net>
Thu, 1 Jan 2015 11:16:34 +0000 (13:16 +0200)
committerToni Wilen <twilen@winuae.net>
Thu, 1 Jan 2015 11:16:34 +0000 (13:16 +0200)
a2091.cpp
include/a2091.h

index 87bca6242b85aef6c02e8c7fcc37354b6a0f1be6..a92575d2dc49375bb78f5d9f520334fb8db85978 100644 (file)
--- a/a2091.cpp
+++ b/a2091.cpp
@@ -3,11 +3,13 @@
 *
 * A590/A2091/A3000/CDTV SCSI expansion (DMAC/SuperDMAC + WD33C93) emulation
 * Includes A590 + XT drive emulation.
+* GVP Series II
 *
 * Copyright 2007-2014 Toni Wilen
 *
 */
 
+#define GVP_DEBUG_IO 0
 #define A2091_DEBUG 0
 #define A2091_DEBUG_IO 0
 #define XT_DEBUG 0
@@ -37,8 +39,9 @@
 #include "cdtv.h"
 #include "savestate.h"
 
-#define ROM_VECTOR 0x2000
-#define ROM_OFFSET 0x2000
+#define CDMAC_ROM_VECTOR 0x2000
+#define CDMAC_ROM_OFFSET 0x2000
+#define GVP_ROM_OFFSET 0x8000
 
 /* SuperDMAC CNTR bits. */
 #define SCNTR_TCEN     (1<<5)
 #define ISTR_FF_FLG    (1<<1)  /* FIFO-Full Flag */
 #define ISTR_FE_FLG    (1<<0)  /* FIFO-Empty Flag */
 
+/* GVP models */
+#define GVP_GFORCE_040         0x20
+#define GVP_GFORCE_040_SCSI    0x30
+#define GVP_A1291_SCSI         0x40
+#define GVP_GFORCE_030         0xa0
+#define GVP_GFORCE_030_SCSI    0xb0
+#define GVP_COMBO_R4           0x60
+#define GVP_COMBO_R4_SCSI      0x70
+#define GVP_COMBO_R3           0xe0
+#define GVP_COMBO_R3_SCSI      0xf0
+#define GVP_SERIESII           0xf8
+#define GVP_A530                       0xc0
+#define GVP_A530_SCSI          0xd0
+
 /* wd register names */
 #define WD_OWN_ID              0x00
 #define WD_CONTROL             0x01
 static struct wd_state wd_a2091;
 static struct wd_state wd_a2091_2;
 static struct wd_state wd_a3000;
+static struct wd_state wd_gvp;
+static struct wd_state wd_gvp_2;
 struct wd_state wd_cdtv;
 
 static struct wd_state *wda2091[] = {
@@ -250,29 +269,44 @@ static struct wd_state *wdscsi[] = {
                NULL
 };
 
-static int isirq (struct wd_state *wd)
+static struct wd_state *gvpscsi[] = {
+       &wd_gvp,
+       &wd_gvp_2,
+};
+
+static bool isirq(struct wd_state *wd)
 {
        if (!wd->enabled)
-               return 0;
-       if (wd->superdmac) {
-               if (wd->auxstatus & ASR_INT)
-                       wd->dmac_istr |= ISTR_INTS;
-               if ((wd->dmac_cntr & SCNTR_INTEN) && (wd->dmac_istr & (ISTR_INTS | ISTR_E_INT)))
-                       return 1;
-       } else {
-               if (wd->xt_irq)
-                       wd->dmac_istr |= ISTR_INTS;
-               if (wd->auxstatus & ASR_INT)
-                       wd->dmac_istr |= ISTR_INTS;
-               if ((wd->dmac_cntr & CNTR_INTEN) && (wd->dmac_istr & (ISTR_INTS | ISTR_E_INT)))
-                       return 1;
+               return false;
+       switch (wd->dmac_type)
+       {
+               case GVP_DMAC:
+               if (wd->wc.auxstatus & ASR_INT)
+                       wd->gdmac.cntr |= 2;
+               if ((wd->gdmac.cntr & (2 | 8)) == 10)
+                       return true;
+               break;
+               case COMMODORE_SDMAC:
+               if (wd->wc.auxstatus & ASR_INT)
+                       wd->cdmac.dmac_istr |= ISTR_INTS;
+               if ((wd->cdmac.dmac_cntr & SCNTR_INTEN) && (wd->cdmac.dmac_istr & (ISTR_INTS | ISTR_E_INT)))
+                       return true;
+               break;
+               case COMMODORE_DMAC:
+               if (wd->cdmac.xt_irq)
+                       wd->cdmac.dmac_istr |= ISTR_INTS;
+               if (wd->wc.auxstatus & ASR_INT)
+                       wd->cdmac.dmac_istr |= ISTR_INTS;
+               if ((wd->cdmac.dmac_cntr & CNTR_INTEN) && (wd->cdmac.dmac_istr & (ISTR_INTS | ISTR_E_INT)))
+                       return true;
+               break;
        }
-       return 0;
+       return false;
 }
 
 void rethink_a2091 (void)
 {
-       if (isirq (&wd_a2091) ||isirq (&wd_a2091_2) || isirq (&wd_a3000)) {
+       if (isirq (&wd_a2091) ||isirq (&wd_a2091_2) || isirq (&wd_a3000) || isirq(&wd_gvp) || isirq(&wd_gvp_2)) {
                uae_int_requested |= 2;
 #if A2091_DEBUG > 2 || A3000_DEBUG > 2
                write_log (_T("Interrupt_RETHINK\n"));
@@ -286,45 +320,45 @@ static void dmac_scsi_int(struct wd_state *wd)
 {
        if (!wd->enabled)
                return;
-       if (!(wd->auxstatus & ASR_INT))
+       if (!(wd->wc.auxstatus & ASR_INT))
                return;
-       if (isirq (wd))
+       if (isirq(wd))
                uae_int_requested |= 2;
 }
 
-static void dmac_xt_int(struct wd_state *wd)
+static void dmac_a2091_xt_int(struct wd_state *wd)
 {
        if (!wd->enabled)
                return;
-       wd->xt_irq = true;
+       wd->cdmac.xt_irq = true;
        if (isirq(wd))
                uae_int_requested |= 2;
 }
 
-void scsi_dmac_start_dma (struct wd_state *wd)
+void scsi_dmac_a2091_start_dma (struct wd_state *wd)
 {
 #if A3000_DEBUG > 0 || A2091_DEBUG > 0
        write_log (_T("DMAC DMA started, ADDR=%08X, LEN=%08X words\n"), wd->dmac_acr, wd->dmac_wtc);
 #endif
-       wd->dmac_dma = 1;
+       wd->cdmac.dmac_dma = 1;
 }
-void scsi_dmac_stop_dma (struct wd_state *wd)
+void scsi_dmac_a2091_stop_dma (struct wd_state *wd)
 {
-       wd->dmac_dma = 0;
-       wd->dmac_istr &= ~ISTR_E_INT;
+       wd->cdmac.dmac_dma = 0;
+       wd->cdmac.dmac_istr &= ~ISTR_E_INT;
 }
 
 static void dmac_reset (struct wd_state *wd)
 {
 #if WD33C93_DEBUG > 0
-       if (wd->superdmac)
+       if (wd->dmac_type == COMMODORE_SDMAC)
                write_log (_T("A3000 %s SCSI reset\n"), WD33C93);
-       else
+       else if (wd->dmac_type == COMMODORE_DMAC)
                write_log (_T("A2091 %s SCSI reset\n"), WD33C93);
 #endif
 }
 
-static void incsasr (struct wd_state *wd, int w)
+static void incsasr (struct wd_chip_state *wd, int w)
 {
        if (wd->sasr == WD_AUXILIARY_STATUS || wd->sasr == WD_DATA || wd->sasr == WD_COMMAND)
                return;
@@ -334,16 +368,16 @@ static void incsasr (struct wd_state *wd, int w)
        wd->sasr &= 0x1f;
 }
 
-static void dmac_cint (struct wd_state *wd)
+static void dmac_a2091_cint (struct wd_state *wd)
 {
-       wd->dmac_istr = 0;
+       wd->cdmac.dmac_istr = 0;
        rethink_a2091 ();
 }
 
-static void doscsistatus (struct wd_state *wd, uae_u8 status)
+static void doscsistatus(struct wd_state *wd, uae_u8 status)
 {
-       wd->wdregs[WD_SCSI_STATUS] = status;
-       wd->auxstatus |= ASR_INT;
+       wd->wc.wdregs[WD_SCSI_STATUS] = status;
+       wd->wc.auxstatus |= ASR_INT;
 #if WD33C93_DEBUG > 1
        write_log (_T("%s STATUS=%02X\n"), WD33C93, status);
 #endif
@@ -359,7 +393,7 @@ static void doscsistatus (struct wd_state *wd, uae_u8 status)
 #endif
 }
 
-static void set_status (struct wd_state *wd, uae_u8 status, int delay)
+static void set_status (struct wd_chip_state *wd, uae_u8 status, int delay)
 {
        wd->queue_index++;
        if (wd->queue_index >= WD_STATUS_QUEUE)
@@ -368,22 +402,22 @@ static void set_status (struct wd_state *wd, uae_u8 status, int delay)
        wd->scsidelay_irq[wd->queue_index] = delay == 0 ? 1 : (delay <= 2 ? 2 : delay);
 }
 
-static void set_status (struct wd_state *wd, uae_u8 status)
+static void set_status (struct wd_chip_state *wd, uae_u8 status)
 {
        set_status (wd, status, 0);
 }
 
-static uae_u32 gettc (struct wd_state *wd)
+static uae_u32 gettc (struct wd_chip_state *wd)
 {
        return wd->wdregs[WD_TRANSFER_COUNT_LSB] | (wd->wdregs[WD_TRANSFER_COUNT] << 8) | (wd->wdregs[WD_TRANSFER_COUNT_MSB] << 16);
 }
-static void settc (struct wd_state *wd, uae_u32 tc)
+static void settc (struct wd_chip_state *wd, uae_u32 tc)
 {
        wd->wdregs[WD_TRANSFER_COUNT_LSB] = tc & 0xff;
        wd->wdregs[WD_TRANSFER_COUNT] = (tc >> 8) & 0xff;
        wd->wdregs[WD_TRANSFER_COUNT_MSB] = (tc >> 16) & 0xff;
 }
-static bool decreasetc (struct wd_state *wd)
+static bool decreasetc(struct wd_chip_state *wd)
 {
        uae_u32 tc = gettc (wd);
        if (!tc)
@@ -393,7 +427,7 @@ static bool decreasetc (struct wd_state *wd)
        return tc == 0;
 }
 
-static bool canwddma (struct wd_state *wd)
+static bool canwddma(struct wd_chip_state *wd)
 {
        uae_u8 mode = wd->wdregs[WD_CONTROL] >> 5;
        if (mode != 0 && mode != 4 && mode != 1) {
@@ -403,7 +437,7 @@ static bool canwddma (struct wd_state *wd)
 }
 
 #if WD33C93_DEBUG > 0
-static TCHAR *scsitostring (struct wd_state *wd)
+static TCHAR *scsitostring (struct wd_chip_state *wd, struct scsi_data *scsi)
 {
        static TCHAR buf[200];
        TCHAR *p;
@@ -411,7 +445,7 @@ static TCHAR *scsitostring (struct wd_state *wd)
 
        p = buf;
        p[0] = 0;
-       for (i = 0; i < wd->scsi->offset && i < sizeof wd->wd_data; i++) {
+       for (i = 0; i < scsi->offset && i < sizeof wd->wd_data; i++) {
                if (i > 0) {
                        _tcscat (p, _T("."));
                        p++;
@@ -423,107 +457,170 @@ static TCHAR *scsitostring (struct wd_state *wd)
 }
 #endif
 
-static void dmacheck (struct wd_state *wd)
+static void setphase(struct wd_chip_state *wd, uae_u8 phase)
 {
-       wd->dmac_acr++;
-       if (wd->old_dmac && (wd->dmac_cntr & CNTR_TCEN)) {
-               if (wd->dmac_wtc == 0)
-                       wd->dmac_istr |= ISTR_E_INT;
-               else
-                       wd->dmac_wtc--;
-       }
+       wd->wdregs[WD_COMMAND_PHASE] = phase;
 }
 
-static void setphase (struct wd_state *wd, uae_u8 phase)
+static void dmacheck_a2091 (struct wd_state *wd)
 {
-       wd->wdregs[WD_COMMAND_PHASE] = phase;
+       wd->cdmac.dmac_acr++;
+       if (wd->cdmac.old_dmac && (wd->cdmac.dmac_cntr & CNTR_TCEN)) {
+               if (wd->cdmac.dmac_wtc == 0)
+                       wd->cdmac.dmac_istr |= ISTR_E_INT;
+               else
+                       wd->cdmac.dmac_wtc--;
+       }
 }
 
-static bool do_dma (struct wd_state *wd)
+static bool do_dma_commodore(struct wd_state *wd, struct scsi_data *scsi)
 {
-       wd->wd_data_avail = 0;
        if (wd->cdtv)
-               cdtv_getdmadata (&wd->dmac_acr);
-       if (wd->scsi->direction == 0) {
-               write_log (_T("%s DMA but no data!?\n"), WD33C93);
-       } else if (wd->scsi->direction < 0) {
+               cdtv_getdmadata(&wd->cdmac.dmac_acr);
+       if (scsi->direction < 0) {
 #if WD33C93_DEBUG > 0
-               uaecptr odmac_acr = wd->dmac_acr;
+               uaecptr odmac_acr = wd->cdmac.dmac_acr;
 #endif
                for (;;) {
                        uae_u8 v;
-                       int status = scsi_receive_data (wd->scsi, &v);
-                       put_byte (wd->dmac_acr, v);
-                       if (wd->wd_dataoffset < sizeof wd->wd_data)
-                               wd->wd_data[wd->wd_dataoffset++] = v;
-                       dmacheck (wd);
-                       if (decreasetc (wd))
+                       int status = scsi_receive_data (scsi, &v);
+                       put_byte(wd->cdmac.dmac_acr, v);
+                       if (wd->wc.wd_dataoffset < sizeof wd->wc.wd_data)
+                               wd->wc.wd_data[wd->wc.wd_dataoffset++] = v;
+                       dmacheck_a2091 (wd);
+                       if (decreasetc (&wd->wc))
                                break;
                        if (status)
                                break;
                }
 #if WD33C93_DEBUG > 0
-               write_log (_T("%s Done DMA from WD, %d/%d %08X\n"), WD33C93, wd->scsi->offset, wd->scsi->data_len, odmac_acr);
+               write_log (_T("%s Done DMA from WD, %d/%d %08X\n"), WD33C93, scsi->offset, scsi->data_len, odmac_acr);
 #endif
                return true;
-       } else if (wd->scsi->direction > 0) {
+       } else if (scsi->direction > 0) {
 #if WD33C93_DEBUG > 0
-               uaecptr odmac_acr = wd->dmac_acr;
+               uaecptr odmac_acr = wd->cdmac.dmac_acr;
 #endif
                for (;;) {
                        int status;
-                       uae_u8 v = get_byte (wd->dmac_acr);
-                       if (wd->wd_dataoffset < sizeof wd->wd_data)
-                               wd->wd_data[wd->wd_dataoffset++] = v;
-                       status = scsi_send_data (wd->scsi, v);
-                       dmacheck (wd);
-                       if (decreasetc (wd))
+                       uae_u8 v = get_byte(wd->cdmac.dmac_acr);
+                       if (wd->wc.wd_dataoffset < sizeof wd->wc.wd_data)
+                               wd->wc.wd_data[wd->wc.wd_dataoffset++] = v;
+                       status = scsi_send_data (scsi, v);
+                       dmacheck_a2091 (wd);
+                       if (decreasetc (&wd->wc))
                                break;
                        if (status)
                                break;
                }
 #if WD33C93_DEBUG > 0
-               write_log (_T("%s Done DMA to WD, %d/%d %08x\n"), WD33C93, wd->scsi->offset, wd->scsi->data_len, odmac_acr);
+               write_log (_T("%s Done DMA to WD, %d/%d %08x\n"), WD33C93, scsi->offset, scsi->data_len, odmac_acr);
 #endif
                return true;
        }
        return false;
 }
 
+static bool do_dma_gvp(struct wd_state *wd, struct scsi_data *scsi)
+{
+       if (!wd->gdmac.dma_on)
+               return false;
+       if (scsi->direction < 0) {
+               if (wd->gdmac.cntr & 0x10) {
+                       write_log(_T("GVP DMA: mismatched direction when reading!\n"));
+                       return false;
+               }
+               for (;;) {
+                       uae_u8 v;
+                       int status = scsi_receive_data (scsi, &v);
+                       put_byte(wd->gdmac.addr, v);
+                       if (wd->wc.wd_dataoffset < sizeof wd->wc.wd_data)
+                               wd->wc.wd_data[wd->wc.wd_dataoffset++] = v;
+                       wd->gdmac.addr++;
+                       if (decreasetc (&wd->wc))
+                               break;
+                       if (status)
+                               break;
+               }
+#if WD33C93_DEBUG > 0
+               write_log (_T("%s Done DMA from WD, %d/%d\n"), WD33C93, scsi->offset, scsi->data_len);
+#endif
+               return true;
+       } else if (scsi->direction > 0) {
+               if (!(wd->gdmac.cntr & 0x10)) {
+                       write_log(_T("GVP DMA: mismatched direction when writing!\n"));
+                       return false;
+               }
+               for (;;) {
+                       int status;
+                       uae_u8 v = get_byte(wd->gdmac.addr);
+                       if (wd->wc.wd_dataoffset < sizeof wd->wc.wd_data)
+                               wd->wc.wd_data[wd->wc.wd_dataoffset++] = v;
+                       status = scsi_send_data (scsi, v);
+                       wd->gdmac.addr++;
+                       if (decreasetc (&wd->wc))
+                               break;
+                       if (status)
+                               break;
+               }
+#if WD33C93_DEBUG > 0
+               write_log (_T("%s Done DMA to WD, %d/%d\n"), WD33C93, scsi->offset, scsi->data_len);
+#endif
+               return true;
+       }
+       return false;
+}
+
+static bool do_dma(struct wd_state *wd)
+{
+       struct scsi_data *scsi = wd->wc.scsi;
+       wd->wc.wd_data_avail = 0;
+       if (scsi->direction == 0)
+               write_log (_T("%s DMA but no data!?\n"), WD33C93);
+       switch (wd->dmac_type)
+       {
+               case COMMODORE_DMAC:
+               case COMMODORE_SDMAC:
+               return do_dma_commodore(wd, scsi);
+               case GVP_DMAC:
+               return do_dma_gvp(wd, scsi);
+       }
+       return false;
+}
 
-static bool wd_do_transfer_out (struct wd_state *wd)
+static bool wd_do_transfer_out (struct wd_chip_state *wd, struct scsi_data *scsi)
 {
 #if WD33C93_DEBUG > 0
-       write_log (_T("%s SCSI O [%02X] %d/%d TC=%d %s\n"), WD33C93, wd->wdregs[WD_COMMAND_PHASE], wd->scsi->offset, wd->scsi->data_len, gettc (wd), scsitostring (wd));
+       write_log (_T("%s SCSI O [%02X] %d/%d TC=%d %s\n"), WD33C93, wd->wdregs[WD_COMMAND_PHASE], scsi->offset, scsi->data_len, gettc (wd), scsitostring (wd, scsi));
 #endif
        if (wd->wdregs[WD_COMMAND_PHASE] < 0x20) {
                int msg = wd->wd_data[0];
                /* message was sent */
                setphase (wd, 0x20);
                wd->wd_phase = CSR_XFER_DONE | PHS_COMMAND;
-               wd->scsi->status = 0;
-               scsi_start_transfer (wd->scsi);
+               scsi->status = 0;
+               scsi_start_transfer (scsi);
 #if WD33C93_DEBUG > 0
                write_log (_T("%s SCSI got MESSAGE %02X\n"), WD33C93, msg);
 #endif
-               wd->scsi->message[0] = msg;
+               scsi->message[0] = msg;
        } else if (wd->wdregs[WD_COMMAND_PHASE] == 0x30) {
 #if WD33C93_DEBUG > 0
                write_log (_T("%s SCSI got COMMAND %02X\n"), WD33C93, wd->wd_data[0]);
 #endif
-               if (wd->scsi->offset < wd->scsi->data_len) {
+               if (scsi->offset < scsi->data_len) {
                        // data missing, ask for more
                        wd->wd_phase = CSR_XFER_DONE | PHS_COMMAND;
-                       setphase (wd, 0x30 + wd->scsi->offset);
+                       setphase (wd, 0x30 + scsi->offset);
                        set_status (wd, wd->wd_phase, 1);
                        return false;
                }
                settc (wd, 0);
-               scsi_start_transfer (wd->scsi);
-               scsi_emulate_analyze (wd->scsi);
-               if (wd->scsi->direction > 0) {
+               scsi_start_transfer (scsi);
+               scsi_emulate_analyze (scsi);
+               if (scsi->direction > 0) {
                        /* if write command, need to wait for data */
-                       if (wd->scsi->data_len <= 0 || wd->scsi->direction == 0) {
+                       if (scsi->data_len <= 0 || scsi->direction == 0) {
                                // Status phase if command didn't return anything and don't want anything
                                wd->wd_phase = CSR_XFER_DONE | PHS_STATUS;
                                setphase (wd, 0x46);
@@ -532,8 +629,8 @@ static bool wd_do_transfer_out (struct wd_state *wd)
                                setphase (wd, 0x45);
                        }
                } else {
-                       scsi_emulate_cmd (wd->scsi);
-                       if (wd->scsi->data_len <= 0 || wd->scsi->direction == 0) {
+                       scsi_emulate_cmd (scsi);
+                       if (wd->scsi->data_len <= 0 || scsi->direction == 0) {
                                // Status phase if command didn't return anything and don't want anything
                                wd->wd_phase = CSR_XFER_DONE | PHS_STATUS;
                                setphase (wd, 0x46);
@@ -543,73 +640,74 @@ static bool wd_do_transfer_out (struct wd_state *wd)
                        }
                }
        } else if (wd->wdregs[WD_COMMAND_PHASE] == 0x46 || wd->wdregs[WD_COMMAND_PHASE] == 0x45) {
-               if (wd->scsi->offset < wd->scsi->data_len) {
+               if (wd->scsi->offset < scsi->data_len) {
                        // data missing, ask for more
-                       wd->wd_phase = CSR_XFER_DONE | (wd->scsi->direction < 0 ? PHS_DATA_IN : PHS_DATA_OUT);
+                       wd->wd_phase = CSR_XFER_DONE | (scsi->direction < 0 ? PHS_DATA_IN : PHS_DATA_OUT);
                        set_status (wd, wd->wd_phase, 10);
                        return false;
                }
                settc (wd, 0);
-               if (wd->scsi->direction > 0) {
+               if (scsi->direction > 0) {
                        /* data was sent */
-                       scsi_emulate_cmd (wd->scsi);
-                       wd->scsi->data_len = 0;
+                       scsi_emulate_cmd (scsi);
+                       scsi->data_len = 0;
                        wd->wd_phase = CSR_XFER_DONE | PHS_STATUS;
                }
-               scsi_start_transfer (wd->scsi);
+               scsi_start_transfer (scsi);
                setphase (wd, 0x47);
        }
        wd->wd_dataoffset = 0;
-       set_status (wd, wd->wd_phase, wd->scsi->direction <= 0 ? 0 : 1);
+       set_status (wd, wd->wd_phase, scsi->direction <= 0 ? 0 : 1);
        wd->wd_busy = 0;
        return true;
 }
 
-static bool wd_do_transfer_in (struct wd_state *wd)
+static bool wd_do_transfer_in (struct wd_chip_state *wd, struct scsi_data *scsi)
 {
 #if WD33C93_DEBUG > 0
-       write_log (_T("%s SCSI I [%02X] %d/%d TC=%d %s\n"), WD33C93, wd->wdregs[WD_COMMAND_PHASE], wd->scsi->offset, wd->scsi->data_len, gettc (wd), scsitostring (wd));
+       write_log (_T("%s SCSI I [%02X] %d/%d TC=%d %s\n"), WD33C93, wd->wdregs[WD_COMMAND_PHASE], scsi->offset, scsi->data_len, gettc (wd), scsitostring (wd, scsi));
 #endif
        wd->wd_dataoffset = 0;
        if (wd->wdregs[WD_COMMAND_PHASE] >= 0x36 && wd->wdregs[WD_COMMAND_PHASE] < 0x46) {
-               if (wd->scsi->offset < wd->scsi->data_len) {
+               if (scsi->offset < scsi->data_len) {
                        // data missing, ask for more
-                       wd->wd_phase = CSR_XFER_DONE | (wd->scsi->direction < 0 ? PHS_DATA_IN : PHS_DATA_OUT);
-                       set_status (wd, wd->wd_phase, 1);
+                       wd->wd_phase = CSR_XFER_DONE | (scsi->direction < 0 ? PHS_DATA_IN : PHS_DATA_OUT);
+                       set_status(wd, wd->wd_phase, 1);
                        return false;
                }
                if (gettc (wd) != 0) {
                        wd->wd_phase = CSR_UNEXP | PHS_STATUS;
-                       setphase (wd, 0x46);
+                       setphase(wd, 0x46);
                } else {
                        wd->wd_phase = CSR_XFER_DONE | PHS_STATUS;
-                       setphase (wd, 0x46);
+                       setphase(wd, 0x46);
                }
-               scsi_start_transfer (wd->scsi);
+               scsi_start_transfer(scsi);
        } else if (wd->wdregs[WD_COMMAND_PHASE] == 0x46 || wd->wdregs[WD_COMMAND_PHASE] == 0x47) {
-               setphase (wd, 0x50);
+               setphase(wd, 0x50);
                wd->wd_phase = CSR_XFER_DONE | PHS_MESS_IN;
-               scsi_start_transfer (wd->scsi);
+               scsi_start_transfer(scsi);
        } else if (wd->wdregs[WD_COMMAND_PHASE] == 0x50) {
-               setphase (wd, 0x60);
+               setphase(wd, 0x60);
                wd->wd_phase = CSR_DISC;
                wd->wd_selected = false;
-               scsi_start_transfer (wd->scsi);
+               scsi_start_transfer(scsi);
        }
-       set_status (wd, wd->wd_phase, 1);
-       wd->scsi->direction = 0;
+       set_status(wd, wd->wd_phase, 1);
+       scsi->direction = 0;
        return true;
 }
 
-static void wd_cmd_sel_xfer (struct wd_state *wd, bool atn)
+static void wd_cmd_sel_xfer (struct wd_chip_state *wd, struct wd_state *wds, bool atn)
 {
        int i, tmp_tc;
        int delay = 0;
+       struct scsi_data *scsi;
 
        wd->wd_data_avail = 0;
        tmp_tc = gettc (wd);
-       wd->scsi = wd->scsis[wd->wdregs[WD_DESTINATION_ID] & 7];
-       if (!wd->scsi) {
+       scsi = wd->scsi = wds->scsis[wd->wdregs[WD_DESTINATION_ID] & 7];
+       if (!scsi) {
                set_status (wd, CSR_TIMEOUT, 0);
                wd->wdregs[WD_COMMAND_PHASE] = 0x00;
 #if WD33C93_DEBUG > 0
@@ -619,38 +717,38 @@ static void wd_cmd_sel_xfer (struct wd_state *wd, bool atn)
                return;
        }
        if (!wd->wd_selected) {
-               wd->scsi->message[0] = 0x80;
+               scsi->message[0] = 0x80;
                wd->wd_selected = true;
                wd->wdregs[WD_COMMAND_PHASE] = 0x10;
        }
 #if WD33C93_DEBUG > 0
        write_log (_T("* %s select and transfer%s, ID=%d PHASE=%02X TC=%d wddma=%d dmac=%d\n"),
-               WD33C93, atn ? _T(" with atn") : _T(""), wd->wdregs[WD_DESTINATION_ID] & 0x7, wd->wdregs[WD_COMMAND_PHASE], tmp_tc, wd->wdregs[WD_CONTROL] >> 5, wd->dmac_dma);
+               WD33C93, atn ? _T(" with atn") : _T(""), wd->wdregs[WD_DESTINATION_ID] & 0x7, wd->wdregs[WD_COMMAND_PHASE], tmp_tc, wd->wdregs[WD_CONTROL] >> 5, wds->cdmac.dmac_dma);
 #endif
        if (wd->wdregs[WD_COMMAND_PHASE] <= 0x30) {
-               wd->scsi->buffer[0] = 0;
-               wd->scsi->status = 0;
-               memcpy (wd->scsi->cmd, &wd->wdregs[3], 16);
-               wd->scsi->data_len = tmp_tc;
-               scsi_emulate_analyze (wd->scsi);
-               settc (wd, wd->scsi->cmd_len);
+               scsi->buffer[0] = 0;
+               scsi->status = 0;
+               memcpy (scsi->cmd, &wd->wdregs[3], 16);
+               scsi->data_len = tmp_tc;
+               scsi_emulate_analyze (scsi);
+               settc (wd, scsi->cmd_len);
                wd->wd_dataoffset = 0;
-               scsi_start_transfer (wd->scsi);
-               wd->scsi->direction = 2;
-               wd->scsi->data_len = wd->scsi->cmd_len;
+               scsi_start_transfer (scsi);
+               scsi->direction = 2;
+               scsi->data_len = scsi->cmd_len;
                for (i = 0; i < gettc (wd); i++) {
-                       uae_u8 b = wd->scsi->cmd[i];
+                       uae_u8 b = scsi->cmd[i];
                        wd->wd_data[i] = b;
-                       scsi_send_data (wd->scsi, b);
+                       scsi_send_data (scsi, b);
                        wd->wd_dataoffset++;
                }
                // 0x30 = command phase has started
-               wd->scsi->data_len = tmp_tc;
-               scsi_emulate_analyze (wd->scsi);
+               scsi->data_len = tmp_tc;
+               scsi_emulate_analyze (scsi);
                wd->wdregs[WD_COMMAND_PHASE] = 0x30 + gettc (wd);
                settc (wd, 0);
 #if WD33C93_DEBUG > 0
-               write_log (_T("%s: Got Command %s, datalen=%d\n"), WD33C93, scsitostring (wd), wd->scsi->data_len);
+               write_log (_T("%s: Got Command %s, datalen=%d\n"), WD33C93, scsitostring (wd, scsi), scsi->data_len);
 #endif
        }
 
@@ -670,10 +768,10 @@ static void wd_cmd_sel_xfer (struct wd_state *wd, bool atn)
 
        // target replied or start/continue data phase (if data available)
        if (wd->wdregs[WD_COMMAND_PHASE] == 0x44) {
-               if (wd->scsi->direction <= 0) {
-                       scsi_emulate_cmd (wd->scsi);
+               if (scsi->direction <= 0) {
+                       scsi_emulate_cmd (scsi);
                }
-               scsi_start_transfer (wd->scsi);
+               scsi_start_transfer (scsi);
                wd->wdregs[WD_COMMAND_PHASE] = 0x45;
        }
                
@@ -683,17 +781,17 @@ static void wd_cmd_sel_xfer (struct wd_state *wd, bool atn)
                setphase (wd, 0x45);
 
                if (gettc (wd) == 0) {
-                       if (wd->scsi->direction != 0) {
+                       if (scsi->direction != 0) {
                                // TC = 0 but we may have data
-                               if (wd->scsi->direction < 0) {
-                                       if (wd->scsi->data_len == 0) {
+                               if (scsi->direction < 0) {
+                                       if (scsi->data_len == 0) {
                                                // no data, continue normally to status phase
                                                setphase (wd, 0x46);
                                                goto end;
                                        }
                                }
                                wd->wd_phase = CSR_UNEXP;
-                               if (wd->scsi->direction < 0)
+                               if (scsi->direction < 0)
                                        wd->wd_phase |= PHS_DATA_IN;
                                else
                                        wd->wd_phase |= PHS_DATA_OUT;
@@ -704,9 +802,9 @@ static void wd_cmd_sel_xfer (struct wd_state *wd, bool atn)
 
                if (wd->scsi->direction) {
                        if (canwddma (wd)) {
-                               if (wd->scsi->direction <= 0) {
-                                       do_dma (wd);
-                                       if (wd->scsi->offset < wd->scsi->data_len) {
+                               if (scsi->direction <= 0) {
+                                       do_dma(wds);
+                                       if (scsi->offset < scsi->data_len) {
                                                // buffer not completely retrieved?
                                                wd->wd_phase = CSR_UNEXP | PHS_DATA_IN;
                                                set_status (wd, wd->wd_phase, 1);
@@ -720,22 +818,22 @@ static void wd_cmd_sel_xfer (struct wd_state *wd, bool atn)
                                        }
                                        setphase (wd, 0x46);
                                } else {
-                                       if (do_dma (wd)) {
+                                       if (do_dma(wds)) {
                                                setphase (wd, 0x46);
-                                               if (wd->scsi->offset < wd->scsi->data_len) {
+                                               if (scsi->offset < scsi->data_len) {
                                                        // not enough data?
                                                        wd->wd_phase = CSR_UNEXP | PHS_DATA_OUT;
                                                        set_status (wd, wd->wd_phase, 1);
                                                        return;
                                                }
                                                // got all data -> execute it
-                                               scsi_emulate_cmd (wd->scsi);
+                                               scsi_emulate_cmd (scsi);
                                        }
                                }
                        } else {
                                // no dma = Service Request
                                wd->wd_phase = CSR_SRV_REQ;
-                               if (wd->scsi->direction < 0)
+                               if (scsi->direction < 0)
                                        wd->wd_phase |= PHS_DATA_IN;
                                else
                                        wd->wd_phase |= PHS_DATA_OUT;
@@ -755,10 +853,10 @@ static void wd_cmd_sel_xfer (struct wd_state *wd, bool atn)
 
        end:
        if (wd->wdregs[WD_COMMAND_PHASE] == 0x46) {
-               wd->scsi->buffer[0] = 0;
+               scsi->buffer[0] = 0;
                wd->wdregs[WD_COMMAND_PHASE] = 0x50;
-               wd->wdregs[WD_TARGET_LUN] = wd->scsi->status;
-               wd->scsi->buffer[0] = wd->scsi->status;
+               wd->wdregs[WD_TARGET_LUN] = scsi->status;
+               scsi->buffer[0] = scsi->status;
        }
 
        // 0x60 = command complete
@@ -779,11 +877,11 @@ static void wd_cmd_sel_xfer (struct wd_state *wd, bool atn)
 }
 
 
-static void wd_cmd_trans_info (struct wd_state *wd)
+static void wd_cmd_trans_info (struct wd_chip_state *wd, struct scsi_data *scsi)
 {
        if (wd->wdregs[WD_COMMAND_PHASE] == 0x20) {
                wd->wdregs[WD_COMMAND_PHASE] = 0x30;
-               wd->scsi->status = 0;
+               scsi->status = 0;
        }
        wd->wd_busy = 1;
        if (wd->wdregs[WD_COMMAND] & 0x80)
@@ -793,21 +891,21 @@ static void wd_cmd_trans_info (struct wd_state *wd)
        wd->wd_dataoffset = 0;
 
        if (wd->wdregs[WD_COMMAND_PHASE] == 0x30) {
-               wd->scsi->direction = 2; // command
-               wd->scsi->cmd_len = wd->scsi->data_len = gettc (wd);
+               scsi->direction = 2; // command
+               scsi->cmd_len = scsi->data_len = gettc (wd);
        } else if (wd->wdregs[WD_COMMAND_PHASE] == 0x10) {
-               wd->scsi->direction = 1; // message
-               wd->scsi->data_len = gettc (wd);
+               scsi->direction = 1; // message
+               scsi->data_len = gettc (wd);
        } else if (wd->wdregs[WD_COMMAND_PHASE] == 0x45) {
-               scsi_emulate_analyze (wd->scsi);
+               scsi_emulate_analyze (scsi);
        } else if (wd->wdregs[WD_COMMAND_PHASE] == 0x46 || wd->wdregs[WD_COMMAND_PHASE] == 0x47) {
-               wd->scsi->buffer[0] = wd->scsi->status;
-               wd->wdregs[WD_TARGET_LUN] = wd->scsi->status;
-               wd->scsi->direction = -1; // status
-               wd->scsi->data_len = 1;
+               scsi->buffer[0] = scsi->status;
+               wd->wdregs[WD_TARGET_LUN] = scsi->status;
+               scsi->direction = -1; // status
+               scsi->data_len = 1;
        } else if (wd->wdregs[WD_COMMAND_PHASE] == 0x50) {
-               wd->scsi->direction = -1;
-               wd->scsi->data_len = gettc (wd);
+               scsi->direction = -1;
+               scsi->data_len = gettc (wd);
        }
 
        if (canwddma (wd)) {
@@ -817,14 +915,14 @@ static void wd_cmd_trans_info (struct wd_state *wd)
        }
 
 #if WD33C93_DEBUG > 0
-       write_log (_T("* %s transfer info phase=%02x TC=%d dir=%d data=%d/%d wddma=%d dmac=%d\n"),
-               WD33C93, wd->wdregs[WD_COMMAND_PHASE], gettc (wd), wd->scsi->direction, wd->scsi->offset, wd->scsi->data_len, wd->wdregs[WD_CONTROL] >> 5, wd->dmac_dma);
+       write_log (_T("* %s transfer info phase=%02x TC=%d dir=%d data=%d/%d wddma=%d\n"),
+               WD33C93, wd->wdregs[WD_COMMAND_PHASE], gettc (wd), scsi->direction, scsi->offset, scsi->data_len, wd->wdregs[WD_CONTROL] >> 5);
 #endif
 
 }
 
 /* Weird stuff, XT driver (which has nothing to do with SCSI or WD33C93) uses this WD33C93 command! */
-static void wd_cmd_trans_addr(struct wd_state *wd)
+static void wd_cmd_trans_addr(struct wd_chip_state *wd, struct wd_state *wds)
 {
        uae_u32 tcyls = (wd->wdregs[WD_T_CYLS_0] << 8) | wd->wdregs[WD_T_CYLS_1];
        uae_u32 theads = wd->wdregs[WD_T_HEADS];
@@ -844,11 +942,13 @@ static void wd_cmd_trans_addr(struct wd_state *wd)
        wd->wdregs[WD_HEAD] = heads;
        wd->wdregs[WD_SECTOR] = sectors;
 
-       // This is cheating, sector value hardwired on MFM drives. This hack allows to mount hardfiles
-       // that are created using incompatible geometry. (XT MFM/RLL drives have real physical geometry)
-       if (wd->xt_sectors != tsectors && wd->scsis[XT_UNIT]) {
-               write_log(_T("XT drive sector value patched from %d to %d\n"), wd->xt_sectors, tsectors);
-               wd->xt_sectors = tsectors;
+       if (wds) {
+               // This is cheating, sector value is hardwired on MFM drives. This hack allows to mount hardfiles
+               // that are created using incompatible geometry. (XT MFM/RLL drives have real physical geometry)
+               if (wds->cdmac.xt_sectors != tsectors && wds->scsis[XT_UNIT]) {
+                       write_log(_T("XT drive sector value patched from %d to %d\n"), wds->cdmac.xt_sectors, tsectors);
+                       wds->cdmac.xt_sectors = tsectors;
+               }
        }
 
        if (cyls >= tcyls)
@@ -857,16 +957,17 @@ static void wd_cmd_trans_addr(struct wd_state *wd)
                set_status(wd, CSR_TRANS_ADDR);
 }
 
-static void wd_cmd_sel (struct wd_state *wd, bool atn)
+static void wd_cmd_sel (struct wd_chip_state *wd, struct wd_state *wds, bool atn)
 {
+       struct scsi_data *scsi;
 #if WD33C93_DEBUG > 0
        write_log (_T("* %s select%s, ID=%d\n"), WD33C93, atn ? _T(" with atn") : _T(""), wd->wdregs[WD_DESTINATION_ID] & 0x7);
 #endif
        wd->wd_phase = 0;
        wd->wdregs[WD_COMMAND_PHASE] = 0;
 
-       wd->scsi = wd->scsis[wd->wdregs[WD_DESTINATION_ID] & 7];
-       if (!wd->scsi || (wd->wdregs[WD_DESTINATION_ID] & 7) == 7) {
+       scsi = wd->scsi = wds->scsis[wd->wdregs[WD_DESTINATION_ID] & 7];
+       if (!scsi || (wd->wdregs[WD_DESTINATION_ID] & 7) == 7) {
 #if WD33C93_DEBUG > 0
                write_log (_T("%s no drive\n"), WD33C93);
 #endif
@@ -875,7 +976,7 @@ static void wd_cmd_sel (struct wd_state *wd, bool atn)
        }
        scsi_start_transfer (wd->scsi);
        wd->wd_selected = true;
-       wd->scsi->message[0] = 0x80;
+       scsi->message[0] = 0x80;
        set_status (wd, CSR_SELECT, 2);
        if (atn) {
                wd->wdregs[WD_COMMAND_PHASE] = 0x10;
@@ -886,7 +987,7 @@ static void wd_cmd_sel (struct wd_state *wd, bool atn)
        } 
 }
 
-static void wd_cmd_reset (struct wd_state *wd, bool irq)
+static void wd_cmd_reset (struct wd_chip_state *wd, bool irq)
 {
        int i;
 
@@ -906,14 +1007,18 @@ static void wd_cmd_reset (struct wd_state *wd, bool irq)
        wd->wd_data_avail = 0;
        if (irq) {
                set_status (wd, (wd->wdregs[0] & 0x08) ? 1 : 0, 50);
-       } else {
-               wd->dmac_dma = 0;
-               wd->dmac_istr = 0;
-               wd->dmac_cntr = 0;
+       }
+}
+static void wd_cmd_reset_a2091(struct wd_state *wd, bool irq)
+{
+       if (!irq) {
+               wd->cdmac.dmac_dma = 0;
+               wd->cdmac.dmac_istr = 0;
+               wd->cdmac.dmac_cntr = 0;
        }
 }
 
-static void wd_cmd_abort (struct wd_state *wd)
+static void wd_cmd_abort (struct wd_chip_state *wd)
 {
 #if WD33C93_DEBUG > 0
        write_log (_T("%s abort\n"), WD33C93);
@@ -922,18 +1027,20 @@ static void wd_cmd_abort (struct wd_state *wd)
 
 static void xt_command_done(struct wd_state *wd);
 
-static void scsi_hsync2 (struct wd_state *wd)
+static void scsi_hsync2_a2091 (struct wd_state *wds)
 {
        bool irq = false;
-       if (!wd->enabled)
+       struct wd_chip_state *wd = &wds->wc;
+
+       if (!wds->enabled)
                return;
-       if (wd->wd_data_avail < 0 && wd->dmac_dma > 0) {
+       if (wd->wd_data_avail < 0 && wds->cdmac.dmac_dma > 0) {
                bool v;
-               do_dma (wd);
+               do_dma(wds);
                if (wd->scsi->direction < 0) {
-                       v = wd_do_transfer_in (wd);
+                       v = wd_do_transfer_in (wd, wd->scsi);
                } else if (wd->scsi->direction > 0) {
-                       v = wd_do_transfer_out (wd);
+                       v = wd_do_transfer_out (wd, wd->scsi);
                } else {
                        write_log (_T("%s data transfer attempt without data!\n"), WD33C93);
                        v = true;
@@ -942,34 +1049,57 @@ static void scsi_hsync2 (struct wd_state *wd)
                        wd->scsi->direction = 0;
                        wd->wd_data_avail = 0;
                } else {
-                       wd->dmac_dma = -1;
+                       wds->cdmac.dmac_dma = -1;
+               }
+       }
+       if (wds->cdmac.dmac_dma > 0 && (wds->cdmac.xt_status & (XT_STAT_INPUT | XT_STAT_REQUEST))) {
+               wd->scsi = wds->scsis[XT_UNIT];
+               if (do_dma(wds)) {
+                       xt_command_done(wds);
                }
        }
-       if (wd->dmac_dma > 0 && (wd->xt_status & (XT_STAT_INPUT | XT_STAT_REQUEST))) {
-               wd->scsi = wd->scsis[XT_UNIT];
-               if (do_dma(wd)) {
-                       xt_command_done(wd);
+
+       if (wd->auxstatus & ASR_INT)
+               return;
+       for (int i = 0; i < WD_STATUS_QUEUE; i++) {
+               if (wd->scsidelay_irq[i] == 1) {
+                       wd->scsidelay_irq[i] = 0;
+                       doscsistatus(wds, wd->scsidelay_status[i]);
+                       wd->wd_busy = 0;
+               } else if (wd->scsidelay_irq[i] > 1) {
+                       wd->scsidelay_irq[i]--;
                }
        }
+}
 
+static void scsi_hsync2_gvp (struct wd_state *wds)
+{
+       bool irq = false;
+       struct wd_chip_state *wd = &wds->wc;
+
+       if (!wds->enabled)
+               return;
        if (wd->auxstatus & ASR_INT)
                return;
        for (int i = 0; i < WD_STATUS_QUEUE; i++) {
                if (wd->scsidelay_irq[i] == 1) {
                        wd->scsidelay_irq[i] = 0;
-                       doscsistatus(wd, wd->scsidelay_status[i]);
+                       doscsistatus(wds, wd->scsidelay_status[i]);
                        wd->wd_busy = 0;
                } else if (wd->scsidelay_irq[i] > 1) {
                        wd->scsidelay_irq[i]--;
                }
        }
 }
+
 void scsi_hsync (void)
 {
-       scsi_hsync2(&wd_a2091);
-       scsi_hsync2(&wd_a2091_2);
-       scsi_hsync2(&wd_a3000);
-       scsi_hsync2(&wd_cdtv);
+       scsi_hsync2_a2091(&wd_a2091);
+       scsi_hsync2_a2091(&wd_a2091_2);
+       scsi_hsync2_a2091(&wd_a3000);
+       scsi_hsync2_a2091(&wd_cdtv);
+       scsi_hsync2_gvp(&wd_gvp);
+       scsi_hsync2_gvp(&wd_gvp_2);
 }
 
 
@@ -990,7 +1120,7 @@ static uae_u32 makecmd (struct scsi_data *s, int msg, uae_u8 cmd)
        return v;
 }
 
-static void writewdreg (struct wd_state *wd, int sasr, uae_u8 val)
+static void writewdreg (struct wd_chip_state *wd, int sasr, uae_u8 val)
 {
        switch (sasr)
        {
@@ -1009,7 +1139,7 @@ static void writewdreg (struct wd_state *wd, int sasr, uae_u8 val)
        wd->wdregs[sasr] = val;
 }
 
-void wdscsi_put (struct wd_state *wd, uae_u8 d)
+void wdscsi_put (struct wd_chip_state *wd, struct wd_state *wds, uae_u8 d)
 {
 #if WD33C93_DEBUG > 1
        if (WD33C93_DEBUG > 3 || sasr != WD_DATA)
@@ -1020,7 +1150,7 @@ void wdscsi_put (struct wd_state *wd, uae_u8 d)
        }
        if (!wd->wd_used) {
                wd->wd_used = 1;
-               write_log (_T("%s %s in use\n"), wd->name, WD33C93);
+               write_log (_T("%s %s in use\n"), wds->name, WD33C93);
        }
        if (wd->sasr == WD_COMMAND_PHASE) {
 #if WD33C93_DEBUG > 1
@@ -1042,27 +1172,27 @@ void wdscsi_put (struct wd_state *wd, uae_u8 d)
                wd->wd_data_avail = 1;
                if (scsi_send_data (wd->scsi, wd->wdregs[wd->sasr]) || gettc (wd) == 0) {
                        wd->wd_data_avail = 0;
-                       write_comm_pipe_u32 (&wd->requests, makecmd (wd->scsi, 2, 0), 1);
+                       write_comm_pipe_u32 (&wds->requests, makecmd (wd->scsi, 2, 0), 1);
                }
        } else if (wd->sasr == WD_COMMAND) {
                wd->wd_busy = true;
-               write_comm_pipe_u32(&wd->requests, makecmd(wd->scsis[wd->wdregs[WD_DESTINATION_ID] & 7], 0, d), 1);
+               write_comm_pipe_u32(&wds->requests, makecmd(wds->scsis[wd->wdregs[WD_DESTINATION_ID] & 7], 0, d), 1);
                if (wd->scsi && wd->scsi->cd_emu_unit >= 0)
                        gui_flicker_led (LED_CD, wd->scsi->id, 1);
        }
        incsasr (wd, 1);
 }
 
-void wdscsi_sasr (struct wd_state *wd, uae_u8 b)
+void wdscsi_sasr (struct wd_chip_state *wd, uae_u8 b)
 {
        wd->sasr = b;
 }
-uae_u8 wdscsi_getauxstatus (struct wd_state *wd)
+uae_u8 wdscsi_getauxstatus (struct wd_chip_state *wd)
 {
        return (wd->auxstatus & ASR_INT) | (wd->wd_busy || wd->wd_data_avail < 0 ? ASR_BSY : 0) | (wd->wd_data_avail != 0 ? ASR_DBR : 0);
 }
 
-uae_u8 wdscsi_get (struct wd_state *wd)
+uae_u8 wdscsi_get (struct wd_chip_state *wd, struct wd_state *wds)
 {
        uae_u8 v;
 #if WD33C93_DEBUG > 1
@@ -1087,14 +1217,14 @@ uae_u8 wdscsi_get (struct wd_state *wd)
                wd->wd_data_avail = 1;
                if (status || gettc (wd) == 0) {
                        wd->wd_data_avail = 0;
-                       write_comm_pipe_u32 (&wd->requests, makecmd (wd->scsi, 1, 0), 1);
+                       write_comm_pipe_u32 (&wds->requests, makecmd (wd->scsi, 1, 0), 1);
                }
        } else if (wd->sasr == WD_SCSI_STATUS) {
                uae_int_requested &= ~2;
                wd->auxstatus &= ~0x80;
-               if (wd->cdtv)
+               if (wds->cdtv)
                        cdtv_scsi_clear_int ();
-               wd->dmac_istr &= ~ISTR_INTS;
+               wds->cdmac.dmac_istr &= ~ISTR_INTS;
 #if 0
                if (wd->wdregs[WD_COMMAND_PHASE] == 0x10) {
                        wd->wdregs[WD_COMMAND_PHASE] = 0x11;
@@ -1115,91 +1245,91 @@ uae_u8 wdscsi_get (struct wd_state *wd)
 
 /* XT */
 
-static void xt_default_geometry(struct wd_state *wd)
+static void xt_default_geometry(struct wd_state *wds)
 {
-       wd->xt_cyls = wd->scsi->hfd->cyls > 1023 ? 1023 : wd->scsi->hfd->cyls;
-       wd->xt_heads = wd->scsi->hfd->heads > 31 ? 31 : wd->scsi->hfd->heads;
+       wds->cdmac.xt_cyls = wds->wc.scsi->hfd->cyls > 1023 ? 1023 : wds->wc.scsi->hfd->cyls;
+       wds->cdmac.xt_heads = wds->wc.scsi->hfd->heads > 31 ? 31 : wds->wc.scsi->hfd->heads;
 }
 
 
-static void xt_set_status(struct wd_state *wd, uae_u8 state)
+static void xt_set_status(struct wd_state *wds, uae_u8 state)
 {
-       wd->xt_status = state;
-       wd->xt_status |= XT_STAT_SELECT;
-       wd->xt_status |= XT_STAT_READY;
+       wds->cdmac.xt_status = state;
+       wds->cdmac.xt_status |= XT_STAT_SELECT;
+       wds->cdmac.xt_status |= XT_STAT_READY;
 }
 
-static void xt_reset(struct wd_state *wd)
+static void xt_reset(struct wd_state *wds)
 {
-       wd->scsi = wd->scsis[XT_UNIT];
-       if (!wd->scsi)
+       wds->wc.scsi = wds->scsis[XT_UNIT];
+       if (!wds->wc.scsi)
                return;
-       wd->xt_control = 0;
-       wd->xt_datalen = 0;
-       wd->xt_status = 0;
-       xt_default_geometry(wd);
+       wds->cdmac.xt_control = 0;
+       wds->cdmac.xt_datalen = 0;
+       wds->cdmac.xt_status = 0;
+       xt_default_geometry(wds);
        write_log(_T("XT reset\n"));
 }
 
-static void xt_command_done(struct wd_state *wd)
+static void xt_command_done(struct wd_state *wds)
 {
-       switch (wd->xt_cmd[0])
+       switch (wds->cdmac.xt_cmd[0])
        {
                case XT_CMD_DTCSETPARAM:
-                       wd->xt_heads = wd->scsi->buffer[2] & 0x1f;
-                       wd->xt_cyls = ((wd->scsi->buffer[0] & 3) << 8) | (wd->scsi->buffer[1]);
-                       wd->xt_sectors = XT_SECTORS;
-                       if (!wd->xt_heads || !wd->xt_cyls)
-                               xt_default_geometry(wd);
-                       write_log(_T("XT SETPARAM: cyls=%d heads=%d\n"), wd->xt_cyls, wd->xt_heads);
+                       wds->cdmac.xt_heads = wds->wc.scsi->buffer[2] & 0x1f;
+                       wds->cdmac.xt_cyls = ((wds->wc.scsi->buffer[0] & 3) << 8) | (wds->wc.scsi->buffer[1]);
+                       wds->cdmac.xt_sectors = XT_SECTORS;
+                       if (!wds->cdmac.xt_heads || !wds->cdmac.xt_cyls)
+                               xt_default_geometry(wds);
+                       write_log(_T("XT SETPARAM: cyls=%d heads=%d\n"), wds->cdmac.xt_cyls, wds->cdmac.xt_heads);
                        break;
                case XT_CMD_WRITE:
-                       scsi_emulate_cmd(wd->scsi);
+                       scsi_emulate_cmd(wds->wc.scsi);
                        break;
 
        }
 
-       xt_set_status(wd, XT_STAT_INTERRUPT);
-       if (wd->xt_control & XT_INT)
-               dmac_xt_int(wd);
-       wd->xt_datalen = 0;
-       wd->xt_statusbyte = 0;
+       xt_set_status(wds, XT_STAT_INTERRUPT);
+       if (wds->cdmac.xt_control & XT_INT)
+               dmac_a2091_xt_int(wds);
+       wds->cdmac.xt_datalen = 0;
+       wds->cdmac.xt_statusbyte = 0;
 #if XT_DEBUG > 0
-       write_log(_T("XT command %02x done\n"), wd->xt_cmd[0]);
+       write_log(_T("XT command %02x done\n"), wds->xt_cmd[0]);
 #endif
 }
 
-static void xt_wait_data(struct wd_state *wd, int len)
+static void xt_wait_data(struct wd_state *wds, int len)
 {
-       xt_set_status(wd, XT_STAT_REQUEST);
-       wd->xt_offset = 0;
-       wd->xt_datalen = len;
+       xt_set_status(wds, XT_STAT_REQUEST);
+       wds->cdmac.xt_offset = 0;
+       wds->cdmac.xt_datalen = len;
 }
 
-static void xt_sense(struct wd_state *wd)
+static void xt_sense(struct wd_state *wds)
 {
-       wd->xt_datalen = 4;
-       wd->xt_offset = 0;
-       memset(wd->scsi->buffer, 0, wd->xt_datalen);
+       wds->cdmac.xt_datalen = 4;
+       wds->cdmac.xt_offset = 0;
+       memset(wds->wc.scsi->buffer, 0, wds->cdmac.xt_datalen);
 }
 
-static void xt_readwrite(struct wd_state *wd, int rw)
+static void xt_readwrite(struct wd_state *wds, int rw)
 {
-       struct scsi_data *scsi = wd->scsis[XT_UNIT];
+       struct scsi_data *scsi = wds->scsis[XT_UNIT];
        int transfer_len;
        uae_u32 lba;
        // 1 = head
        // 2 = bits 6,7: cyl high, bits 0-5: sectors
        // 3 = cyl (low)
        // 4 = transfer count
-       lba = ((wd->xt_cmd[3] | ((wd->xt_cmd[2] << 2) & 0x300))) * (wd->xt_heads * wd->xt_sectors) +
-               (wd->xt_cmd[1] & 0x1f) * wd->xt_sectors +
-               (wd->xt_cmd[2] & 0x3f);
+       lba = ((wds->cdmac.xt_cmd[3] | ((wds->cdmac.xt_cmd[2] << 2) & 0x300))) * (wds->cdmac.xt_heads * wds->cdmac.xt_sectors) +
+               (wds->cdmac.xt_cmd[1] & 0x1f) * wds->cdmac.xt_sectors +
+               (wds->cdmac.xt_cmd[2] & 0x3f);
 
-       wd->scsi = scsi;
-       wd->xt_offset = 0;
-       transfer_len = wd->xt_cmd[4] == 0 ? 256 : wd->xt_cmd[4];
-       wd->xt_datalen = transfer_len * 512;
+       wds->wc.scsi = scsi;
+       wds->cdmac.xt_offset = 0;
+       transfer_len = wds->cdmac.xt_cmd[4] == 0 ? 256 : wds->cdmac.xt_cmd[4];
+       wds->cdmac.xt_datalen = transfer_len * 512;
 
 #if XT_DEBUG > 0
        write_log(_T("XT %s block %d, %d\n"), rw ? _T("WRITE") : _T("READ"), lba, transfer_len);
@@ -1211,92 +1341,92 @@ static void xt_readwrite(struct wd_state *wd, int rw)
        scsi->cmd[3] = lba >> 0;
        scsi->cmd[4] = transfer_len;
        scsi->cmd[5] = 0;
-       scsi_emulate_analyze(wd->scsi);
+       scsi_emulate_analyze(wds->wc.scsi);
        if (rw) {
-               wd->scsi->direction = 1;
-               xt_set_status(wd, XT_STAT_REQUEST);
+               wds->wc.scsi->direction = 1;
+               xt_set_status(wds, XT_STAT_REQUEST);
        } else {
-               wd->scsi->direction = -1;
+               wds->wc.scsi->direction = -1;
                scsi_emulate_cmd(scsi);
-               xt_set_status(wd, XT_STAT_INPUT);
+               xt_set_status(wds, XT_STAT_INPUT);
        }
        scsi_start_transfer(scsi);
-       settc(wd, scsi->data_len);
+       settc(&wds->wc, scsi->data_len);
 
-       if (!(wd->xt_control & XT_DMA_MODE))
-               xt_command_done(wd);
+       if (!(wds->cdmac.xt_control & XT_DMA_MODE))
+               xt_command_done(wds);
 }
 
-static void xt_command(struct wd_state *wd)
+static void xt_command(struct wd_state *wds)
 {
-       wd->scsi = wd->scsis[XT_UNIT];
-       switch(wd->xt_cmd[0])
+       wds->wc.scsi = wds->scsis[XT_UNIT];
+       switch (wds->cdmac.xt_cmd[0])
        {
        case XT_CMD_READ:
-               xt_readwrite(wd, 0);
+               xt_readwrite(wds, 0);
                break;
        case XT_CMD_WRITE:
-               xt_readwrite(wd, 1);
+               xt_readwrite(wds, 1);
                break;
        case XT_CMD_SEEK:
-               xt_command_done(wd);
+               xt_command_done(wds);
                break;
        case XT_CMD_VERIFY:
-               xt_command_done(wd);
+               xt_command_done(wds);
                break;
        case XT_CMD_FORMATBAD:
        case XT_CMD_FORMATTRK:
-               xt_command_done(wd);
+               xt_command_done(wds);
                break;
        case XT_CMD_TESTREADY:
-               xt_command_done(wd);
+               xt_command_done(wds);
                break;
        case XT_CMD_RECALIBRATE:
-               xt_command_done(wd);
+               xt_command_done(wds);
                break;
        case XT_CMD_SENSE:
-               xt_sense(wd);
+               xt_sense(wds);
                break;
        case XT_CMD_DTCSETPARAM:
-               xt_wait_data(wd, 8);
+               xt_wait_data(wds, 8);
                break;
        default:
-               write_log(_T("XT unknown command %02X\n"), wd->xt_cmd[0]);
-               xt_command_done(wd);
-               wd->xt_status |= XT_STAT_INPUT;
-               wd->xt_datalen = 1;
-               wd->xt_statusbyte = XT_CSB_ERROR;
+               write_log(_T("XT unknown command %02X\n"), wds->cdmac.xt_cmd[0]);
+               xt_command_done(wds);
+               wds->cdmac.xt_status |= XT_STAT_INPUT;
+               wds->cdmac.xt_datalen = 1;
+               wds->cdmac.xt_statusbyte = XT_CSB_ERROR;
                break;
        }
 }
 
-static uae_u8 read_xt_reg(struct wd_state *wd, int reg)
+static uae_u8 read_xt_reg(struct wd_state *wds, int reg)
 {
        uae_u8 v = 0xff;
 
-       wd->scsi = wd->scsis[XT_UNIT];
-       if (!wd->scsi)
+       wds->wc.scsi = wds->scsis[XT_UNIT];
+       if (!wds->wc.scsi)
                return v;
 
        switch(reg)
        {
        case XD_DATA:
-               if (wd->xt_status & XT_STAT_INPUT) {
-                       v = wd->scsi->buffer[wd->xt_offset];
-                       wd->xt_offset++;
-                       if (wd->xt_offset >= wd->xt_datalen) {
-                               xt_command_done(wd);
+               if (wds->cdmac.xt_status & XT_STAT_INPUT) {
+                       v = wds->wc.scsi->buffer[wds->cdmac.xt_offset];
+                       wds->cdmac.xt_offset++;
+                       if (wds->cdmac.xt_offset >= wds->cdmac.xt_datalen) {
+                               xt_command_done(wds);
                        }
                } else {
-                       v = wd->xt_statusbyte;
+                       v = wds->cdmac.xt_statusbyte;
                }
                break;
        case XD_STATUS:
-               v = wd->xt_status;
+               v = wds->cdmac.xt_status;
                break;
        case XD_JUMPER:
                // 20M: 0 40M: 2, xt.device checks it.
-               v = wd->scsi->hfd->size >= 41615 * 2 * 512 ? 2 : 0;
+               v = wds->wc.scsi->hfd->size >= 41615 * 2 * 512 ? 2 : 0;
                break;
        case XD_RESERVED:
                break;
@@ -1307,10 +1437,10 @@ static uae_u8 read_xt_reg(struct wd_state *wd, int reg)
        return v;
 }
 
-static void write_xt_reg(struct wd_state *wd, int reg, uae_u8 v)
+static void write_xt_reg(struct wd_state *wds, int reg, uae_u8 v)
 {
-       wd->scsi = wd->scsis[XT_UNIT];
-       if (!wd->scsi)
+       wds->wc.scsi = wds->scsis[XT_UNIT];
+       if (!wds->wc.scsi)
                return;
 
 #if XT_DEBUG > 2
@@ -1323,54 +1453,54 @@ static void write_xt_reg(struct wd_state *wd, int reg, uae_u8 v)
 #if XT_DEBUG > 1
                write_log(_T("XT data write %02X\n"), v);
 #endif
-               if (!(wd->xt_status & XT_STAT_REQUEST)) {
-                       wd->xt_offset = 0;
-                       xt_set_status(wd, XT_STAT_COMMAND | XT_STAT_REQUEST);
+               if (!(wds->cdmac.xt_status & XT_STAT_REQUEST)) {
+                       wds->cdmac.xt_offset = 0;
+                       xt_set_status(wds, XT_STAT_COMMAND | XT_STAT_REQUEST);
                }
-               if (wd->xt_status & XT_STAT_REQUEST) {
-                       if (wd->xt_status & XT_STAT_COMMAND) {
-                               wd->xt_cmd[wd->xt_offset++] = v;
-                               xt_set_status(wd, XT_STAT_COMMAND | XT_STAT_REQUEST);
-                               if (wd->xt_offset == 6) {
-                                       xt_command(wd);
+               if (wds->cdmac.xt_status & XT_STAT_REQUEST) {
+                       if (wds->cdmac.xt_status & XT_STAT_COMMAND) {
+                               wds->cdmac.xt_cmd[wds->cdmac.xt_offset++] = v;
+                               xt_set_status(wds, XT_STAT_COMMAND | XT_STAT_REQUEST);
+                               if (wds->cdmac.xt_offset == 6) {
+                                       xt_command(wds);
                                }
                        } else {
-                               wd->scsi->buffer[wd->xt_offset] = v;
-                               wd->xt_offset++;
-                               if (wd->xt_offset >= wd->xt_datalen) {
-                                       xt_command_done(wd);
+                               wds->wc.scsi->buffer[wds->cdmac.xt_offset] = v;
+                               wds->cdmac.xt_offset++;
+                               if (wds->cdmac.xt_offset >= wds->cdmac.xt_datalen) {
+                                       xt_command_done(wds);
                                }
                        }
                }
                break;
        case XD_RESET:
-               xt_reset(wd);
+               xt_reset(wds);
                break;
        case XD_SELECT:
 #if XT_DEBUG > 1
                write_log(_T("XT select %02X\n"), v);
 #endif
-               xt_set_status(wd, XT_STAT_SELECT);
+               xt_set_status(wds, XT_STAT_SELECT);
                break;
        case XD_CONTROL:
-               wd->xt_control = v;
-               wd->xt_irq = 0;
+               wds->cdmac.xt_control = v;
+               wds->cdmac.xt_irq = 0;
                break;
        }
 }
 
 /* DMAC */
 
-static uae_u32 dmac_read_word (struct wd_state *wd, uaecptr addr)
+static uae_u32 dmac_a2091_read_word (struct wd_state *wd, uaecptr addr)
 {
        uae_u32 v = 0;
 
        if (addr < 0x40)
                return (wd->dmacmemory[addr] << 8) | wd->dmacmemory[addr + 1];
-       if (addr >= ROM_OFFSET) {
+       if (addr >= CDMAC_ROM_OFFSET) {
                if (wd->rom) {
                        int off = addr & wd->rom_mask;
-                       if (wd->rombankswitcher && (addr & 0xffe0) == ROM_OFFSET)
+                       if (wd->rombankswitcher && (addr & 0xffe0) == CDMAC_ROM_OFFSET)
                                wd->rombank = (addr & 0x02) >> 1;
                        off += wd->rombank * wd->rom_size;
                        return (wd->rom[off] << 8) | wd->rom[off + 1];
@@ -1382,27 +1512,27 @@ static uae_u32 dmac_read_word (struct wd_state *wd, uaecptr addr)
        switch (addr)
        {
        case 0x40:
-               v = wd->dmac_istr;
-               if (v && (wd->dmac_cntr & CNTR_INTEN))
+               v = wd->cdmac.dmac_istr;
+               if (v && (wd->cdmac.dmac_cntr & CNTR_INTEN))
                        v |= ISTR_INT_P;
-               wd->dmac_istr &= ~0xf;
+               wd->cdmac.dmac_istr &= ~0xf;
                break;
        case 0x42:
-               v = wd->dmac_cntr;
+               v = wd->cdmac.dmac_cntr;
                break;
        case 0x80:
-               if (wd->old_dmac)
-                       v = (wd->dmac_wtc >> 16) & 0xffff;
+               if (wd->cdmac.old_dmac)
+                       v = (wd->cdmac.dmac_wtc >> 16) & 0xffff;
                break;
        case 0x82:
-               if (wd->old_dmac)
-                       v = wd->dmac_wtc & 0xffff;
+               if (wd->cdmac.old_dmac)
+                       v = wd->cdmac.dmac_wtc & 0xffff;
                break;
        case 0x90:
-               v = wdscsi_getauxstatus(wd);
+               v = wdscsi_getauxstatus(&wd->wc);
                break;
        case 0x92:
-               v = wdscsi_get(wd);
+               v = wdscsi_get(&wd->wc, wd);
                break;
        case 0xc0:
                v = 0xf8 | (1 << 0) | (1 << 1) | (1 << 2); // bits 0-2 = dip-switches
@@ -1413,19 +1543,19 @@ static uae_u32 dmac_read_word (struct wd_state *wd, uaecptr addr)
                v = 0xffff;
                break;
        case 0xe0:
-               if (wd->dmac_dma <= 0)
-                       scsi_dmac_start_dma (wd);
+               if (wd->cdmac.dmac_dma <= 0)
+                       scsi_dmac_a2091_start_dma (wd);
                break;
        case 0xe2:
-               scsi_dmac_stop_dma (wd);
+               scsi_dmac_a2091_stop_dma (wd);
                break;
        case 0xe4:
-               dmac_cint (wd);
+               dmac_a2091_cint (wd);
                break;
        case 0xe8:
                /* FLUSH (new only) */
-               if (!wd->old_dmac && wd->dmac_dma > 0)
-                       wd->dmac_istr |= ISTR_FE_FLG;
+               if (!wd->cdmac.old_dmac && wd->cdmac.dmac_dma > 0)
+                       wd->cdmac.dmac_istr |= ISTR_FE_FLG;
                break;
        }
 #if A2091_DEBUG_IO > 0
@@ -1434,16 +1564,16 @@ static uae_u32 dmac_read_word (struct wd_state *wd, uaecptr addr)
        return v;
 }
 
-static uae_u32 dmac_read_byte (struct wd_state *wd, uaecptr addr)
+static uae_u32 dmac_a2091_read_byte (struct wd_state *wd, uaecptr addr)
 {
        uae_u32 v = 0;
 
        if (addr < 0x40)
                return wd->dmacmemory[addr];
-       if (addr >= ROM_OFFSET) {
+       if (addr >= CDMAC_ROM_OFFSET) {
                if (wd->rom) {
                        int off = addr & wd->rom_mask;
-                       if (wd->rombankswitcher && (addr & 0xffe0) == ROM_OFFSET)
+                       if (wd->rombankswitcher && (addr & 0xffe0) == CDMAC_ROM_OFFSET)
                                wd->rombank = (addr & 0x02) >> 1;
                        off += wd->rombank * wd->rom_size;
                        return wd->rom[off];
@@ -1454,10 +1584,10 @@ static uae_u32 dmac_read_byte (struct wd_state *wd, uaecptr addr)
        switch (addr)
        {
        case 0x91:
-               v = wdscsi_getauxstatus (wd);
+               v = wdscsi_getauxstatus (&wd->wc);
                break;
        case 0x93:
-               v = wdscsi_get (wd);
+               v = wdscsi_get (&wd->wc, wd);
                break;
        case 0xa1:
        case 0xa3:
@@ -1466,7 +1596,7 @@ static uae_u32 dmac_read_byte (struct wd_state *wd, uaecptr addr)
                v = read_xt_reg(wd, (addr - 0xa0) / 2);
                break;
        default:
-               v = dmac_read_word (wd, addr);
+               v = dmac_a2091_read_word (wd, addr);
                if (!(addr & 1))
                        v >>= 8;
                break;
@@ -1477,11 +1607,11 @@ static uae_u32 dmac_read_byte (struct wd_state *wd, uaecptr addr)
        return v;
 }
 
-static void dmac_write_word (struct wd_state *wd, uaecptr addr, uae_u32 b)
+static void dmac_a2091_write_word (struct wd_state *wd, uaecptr addr, uae_u32 b)
 {
        if (addr < 0x40)
                return;
-       if (addr >= ROM_OFFSET)
+       if (addr >= CDMAC_ROM_OFFSET)
                return;
 
 #if A2091_DEBUG_IO > 0
@@ -1492,63 +1622,63 @@ static void dmac_write_word (struct wd_state *wd, uaecptr addr, uae_u32 b)
        switch (addr)
        {
        case 0x42:
-               wd->dmac_cntr = b;
-               if (wd->dmac_cntr & CNTR_PREST)
+               wd->cdmac.dmac_cntr = b;
+               if (wd->cdmac.dmac_cntr & CNTR_PREST)
                        dmac_reset (wd);
                break;
        case 0x80:
-               wd->dmac_wtc &= 0x0000ffff;
-               wd->dmac_wtc |= b << 16;
+               wd->cdmac.dmac_wtc &= 0x0000ffff;
+               wd->cdmac.dmac_wtc |= b << 16;
                break;
        case 0x82:
-               wd->dmac_wtc &= 0xffff0000;
-               wd->dmac_wtc |= b & 0xffff;
+               wd->cdmac.dmac_wtc &= 0xffff0000;
+               wd->cdmac.dmac_wtc |= b & 0xffff;
                break;
        case 0x84:
-               wd->dmac_acr &= 0x0000ffff;
-               wd->dmac_acr |= b << 16;
+               wd->cdmac.dmac_acr &= 0x0000ffff;
+               wd->cdmac.dmac_acr |= b << 16;
                break;
        case 0x86:
-               wd->dmac_acr &= 0xffff0000;
-               wd->dmac_acr |= b & 0xfffe;
-               if (wd->old_dmac)
-                       wd->dmac_acr &= ~3;
+               wd->cdmac.dmac_acr &= 0xffff0000;
+               wd->cdmac.dmac_acr |= b & 0xfffe;
+               if (wd->cdmac.old_dmac)
+                       wd->cdmac.dmac_acr &= ~3;
                break;
        case 0x8e:
-               wd->dmac_dawr = b;
+               wd->cdmac.dmac_dawr = b;
                break;
        case 0x90:
-               wdscsi_sasr (wd, b);
+               wdscsi_sasr (&wd->wc, b);
                break;
        case 0x92:
-               wdscsi_put (wd, b);
+               wdscsi_put (&wd->wc, wd, b);
                break;
        case 0xc2:
        case 0xc4:
        case 0xc6:
                break;
        case 0xe0:
-               if (wd->dmac_dma <= 0)
-                       scsi_dmac_start_dma (wd);
+               if (wd->cdmac.dmac_dma <= 0)
+                       scsi_dmac_a2091_start_dma (wd);
                break;
        case 0xe2:
-               scsi_dmac_stop_dma (wd);
+               scsi_dmac_a2091_stop_dma (wd);
                break;
        case 0xe4:
-               dmac_cint (wd);
+               dmac_a2091_cint (wd);
                break;
        case 0xe8:
                /* FLUSH */
-               wd->dmac_istr |= ISTR_FE_FLG;
+               wd->cdmac.dmac_istr |= ISTR_FE_FLG;
                break;
        }
 }
 
-static void dmac_write_byte (struct wd_state *wd, uaecptr addr, uae_u32 b)
+static void dmac_a2091_write_byte (struct wd_state *wd, uaecptr addr, uae_u32 b)
 {
        if (addr < 0x40)
                return;
-       if (addr >= ROM_OFFSET)
+       if (addr >= CDMAC_ROM_OFFSET)
                return;
 
 #if A2091_DEBUG_IO > 0
@@ -1558,10 +1688,10 @@ static void dmac_write_byte (struct wd_state *wd, uaecptr addr, uae_u32 b)
        switch (addr)
        {
        case 0x91:
-               wdscsi_sasr (wd, b);
+               wdscsi_sasr (&wd->wc, b);
                break;
        case 0x93:
-               wdscsi_put (wd, b);
+               wdscsi_put (&wd->wc, wd, b);
                break;
        case 0xa1:
        case 0xa3:
@@ -1571,69 +1701,69 @@ static void dmac_write_byte (struct wd_state *wd, uaecptr addr, uae_u32 b)
                break;
        default:
                if (addr & 1)
-                       dmac_write_word (wd, addr, b);
+                       dmac_a2091_write_word (wd, addr, b);
                else
-                       dmac_write_word (wd, addr, b << 8);
+                       dmac_a2091_write_word (wd, addr, b << 8);
        }
 }
 
-static uae_u32 REGPARAM2 dmac_lget (struct wd_state *wd, uaecptr addr)
+static uae_u32 REGPARAM2 dmac_a2091_lget (struct wd_state *wd, uaecptr addr)
 {
        uae_u32 v;
 #ifdef JIT
        special_mem |= S_READ;
 #endif
        addr &= 65535;
-       v = dmac_read_word (wd, addr) << 16;
-       v |= dmac_read_word (wd, addr + 2) & 0xffff;
+       v = dmac_a2091_read_word(wd, addr) << 16;
+       v |= dmac_a2091_read_word(wd, addr + 2) & 0xffff;
        return v;
 }
 
-static uae_u32 REGPARAM2 dmac_wget (struct wd_state *wd, uaecptr addr)
+static uae_u32 REGPARAM2 dmac_a2091_wget(struct wd_state *wd, uaecptr addr)
 {
        uae_u32 v;
 #ifdef JIT
        special_mem |= S_READ;
 #endif
        addr &= 65535;
-       v = dmac_read_word (wd, addr);
+       v = dmac_a2091_read_word(wd, addr);
        return v;
 }
 
-static uae_u32 REGPARAM2 dmac_bget (struct wd_state *wd, uaecptr addr)
+static uae_u32 REGPARAM2 dmac_a2091_bget(struct wd_state *wd, uaecptr addr)
 {
        uae_u32 v;
 #ifdef JIT
        special_mem |= S_READ;
 #endif
        addr &= 65535;
-       v = dmac_read_byte (wd, addr);
+       v = dmac_a2091_read_byte(wd, addr);
        return v;
 }
 
-static void REGPARAM2 dmac_lput (struct wd_state *wd, uaecptr addr, uae_u32 l)
+static void REGPARAM2 dmac_a2091_lput(struct wd_state *wd, uaecptr addr, uae_u32 l)
 {
 #ifdef JIT
        special_mem |= S_WRITE;
 #endif
        addr &= 65535;
-       dmac_write_word (wd, addr + 0, l >> 16);
-       dmac_write_word (wd, addr + 2, l);
+       dmac_a2091_write_word(wd, addr + 0, l >> 16);
+       dmac_a2091_write_word(wd, addr + 2, l);
 }
 
-static void REGPARAM2 dmac_wput (struct wd_state *wd, uaecptr addr, uae_u32 w)
+static void REGPARAM2 dmac_a2091_wput(struct wd_state *wd, uaecptr addr, uae_u32 w)
 {
 #ifdef JIT
        special_mem |= S_WRITE;
 #endif
        addr &= 65535;
-       dmac_write_word (wd, addr, w);
+       dmac_a2091_write_word(wd, addr, w);
 }
 
 extern addrbank dmaca2091_bank;
 extern addrbank dmaca2091_2_bank;
 
-static void REGPARAM2 dmac_bput (struct wd_state *wd, uaecptr addr, uae_u32 b)
+static void REGPARAM2 dmac_a2091_bput(struct wd_state *wd, uaecptr addr, uae_u32 b)
 {
 #ifdef JIT
        special_mem |= S_WRITE;
@@ -1656,40 +1786,40 @@ static void REGPARAM2 dmac_bput (struct wd_state *wd, uaecptr addr, uae_u32 b)
                if (!wd->configured)
                        return;
        }
-       dmac_write_byte (wd, addr, b);
+       dmac_a2091_write_byte(wd, addr, b);
 }
 
-static uae_u32 REGPARAM2 dmac_wgeti (struct wd_state *wd, uaecptr addr)
+static uae_u32 REGPARAM2 dmac_a2091_wgeti(struct wd_state *wd, uaecptr addr)
 {
        uae_u32 v = 0xffff;
 #ifdef JIT
        special_mem |= S_READ;
 #endif
        addr &= 65535;
-       if (addr >= ROM_OFFSET)
+       if (addr >= CDMAC_ROM_OFFSET)
                v = (wd->rom[addr & wd->rom_mask] << 8) | wd->rom[(addr + 1) & wd->rom_mask];
        else
                write_log(_T("Invalid DMAC instruction access %08x\n"), addr);
        return v;
 }
-static uae_u32 REGPARAM2 dmac_lgeti (struct wd_state *wd, uaecptr addr)
+static uae_u32 REGPARAM2 dmac_a2091_lgeti(struct wd_state *wd, uaecptr addr)
 {
        uae_u32 v;
 #ifdef JIT
        special_mem |= S_READ;
 #endif
        addr &= 65535;
-       v = dmac_wgeti (wd, addr) << 16;
-       v |= dmac_wgeti (wd, addr + 2);
+       v = dmac_a2091_wgeti(wd, addr) << 16;
+       v |= dmac_a2091_wgeti(wd, addr + 2);
        return v;
 }
 
-static int REGPARAM2 dmac_check (struct wd_state *wd, uaecptr addr, uae_u32 size)
+static int REGPARAM2 dmac_a2091_check(struct wd_state *wd, uaecptr addr, uae_u32 size)
 {
        return 1;
 }
 
-static uae_u8 *REGPARAM2 dmac_xlate (struct wd_state *wd, uaecptr addr)
+static uae_u8 *REGPARAM2 dmac_a2091_xlate(struct wd_state *wd, uaecptr addr)
 {
        addr &= 0xffff;
        addr += wd->rombank * wd->rom_size;
@@ -1700,84 +1830,84 @@ static uae_u8 *REGPARAM2 dmac_xlate (struct wd_state *wd, uaecptr addr)
 
 static uae_u8 *REGPARAM2 dmac_a2091_xlate (uaecptr addr)
 {
-       return dmac_xlate(&wd_a2091, addr);
+       return dmac_a2091_xlate(&wd_a2091, addr);
 }
 static int REGPARAM2 dmac_a2091_check (uaecptr addr, uae_u32 size)
 {
-       return dmac_check(&wd_a2091, addr, size);
+       return dmac_a2091_check(&wd_a2091, addr, size);
 }
 static uae_u32 REGPARAM2 dmac_a2091_lgeti (uaecptr addr)
 {
-       return dmac_lgeti(&wd_a2091, addr);
+       return dmac_a2091_lgeti(&wd_a2091, addr);
 }
 static uae_u32 REGPARAM2 dmac_a2091_wgeti (uaecptr addr)
 {
-       return dmac_wgeti(&wd_a2091, addr);
+       return dmac_a2091_wgeti(&wd_a2091, addr);
 }
 static uae_u32 REGPARAM2 dmac_a2091_bget (uaecptr addr)
 {
-       return dmac_bget(&wd_a2091, addr);
+       return dmac_a2091_bget(&wd_a2091, addr);
 }
 static uae_u32 REGPARAM2 dmac_a2091_wget (uaecptr addr)
 {
-       return dmac_wget(&wd_a2091, addr);
+       return dmac_a2091_wget(&wd_a2091, addr);
 }
 static uae_u32 REGPARAM2 dmac_a2091_lget (uaecptr addr)
 {
-       return dmac_lget(&wd_a2091, addr);
+       return dmac_a2091_lget(&wd_a2091, addr);
 }
 static void REGPARAM2 dmac_a2091_bput (uaecptr addr, uae_u32 b)
 {
-       dmac_bput(&wd_a2091, addr, b);
+       dmac_a2091_bput(&wd_a2091, addr, b);
 }
 static void REGPARAM2 dmac_a2091_wput (uaecptr addr, uae_u32 b)
 {
-       dmac_wput(&wd_a2091, addr, b);
+       dmac_a2091_wput(&wd_a2091, addr, b);
 }
 static void REGPARAM2 dmac_a2091_lput (uaecptr addr, uae_u32 b)
 {
-       dmac_lput(&wd_a2091, addr, b);
+       dmac_a2091_lput(&wd_a2091, addr, b);
 }
 
 static uae_u8 *REGPARAM2 dmac_a20912_xlate (uaecptr addr)
 {
-       return dmac_xlate(&wd_a2091_2, addr);
+       return dmac_a2091_xlate(&wd_a2091_2, addr);
 }
 static int REGPARAM2 dmac_a20912_check (uaecptr addr, uae_u32 size)
 {
-       return dmac_check(&wd_a2091_2, addr, size);
+       return dmac_a2091_check(&wd_a2091_2, addr, size);
 }
 static uae_u32 REGPARAM2 dmac_a20912_lgeti (uaecptr addr)
 {
-       return dmac_lgeti(&wd_a2091_2, addr);
+       return dmac_a2091_lgeti(&wd_a2091_2, addr);
 }
 static uae_u32 REGPARAM2 dmac_a20912_wgeti (uaecptr addr)
 {
-       return dmac_wgeti(&wd_a2091_2, addr);
+       return dmac_a2091_wgeti(&wd_a2091_2, addr);
 }
 static uae_u32 REGPARAM2 dmac_a20912_bget (uaecptr addr)
 {
-       return dmac_bget(&wd_a2091_2, addr);
+       return dmac_a2091_bget(&wd_a2091_2, addr);
 }
 static uae_u32 REGPARAM2 dmac_a20912_wget (uaecptr addr)
 {
-       return dmac_wget(&wd_a2091_2, addr);
+       return dmac_a2091_wget(&wd_a2091_2, addr);
 }
 static uae_u32 REGPARAM2 dmac_a20912_lget (uaecptr addr)
 {
-       return dmac_lget(&wd_a2091_2, addr);
+       return dmac_a2091_lget(&wd_a2091_2, addr);
 }
 static void REGPARAM2 dmac_a20912_bput (uaecptr addr, uae_u32 b)
 {
-       dmac_bput(&wd_a2091_2, addr, b);
+       dmac_a2091_bput(&wd_a2091_2, addr, b);
 }
 static void REGPARAM2 dmac_a20912_wput (uaecptr addr, uae_u32 b)
 {
-       dmac_wput(&wd_a2091_2, addr, b);
+       dmac_a2091_wput(&wd_a2091_2, addr, b);
 }
 static void REGPARAM2 dmac_a20912_lput (uaecptr addr, uae_u32 b)
 {
-       dmac_lput(&wd_a2091_2, addr, b);
+       dmac_a2091_lput(&wd_a2091_2, addr, b);
 }
 
 addrbank dmaca2091_bank = {
@@ -1793,8 +1923,317 @@ addrbank dmaca2091_2_bank = {
        dmac_a20912_lgeti, dmac_a20912_wgeti, ABFLAG_IO | ABFLAG_SAFE
 };
 
+/* GVP Series II */
+
+extern addrbank gvp_bank;
+extern addrbank gvp_2_bank;
+
+static uae_u32 dmac_gvp_read_byte(struct wd_state *wd, uaecptr addr)
+{
+       uae_u32 v = 0;
+
+       addr &= 0xffff;
+       if (addr < 0x40)
+               return wd->dmacmemory[addr];
+       if (addr >= GVP_ROM_OFFSET) {
+               if (wd->rom) {
+                       if (addr & 1)
+                               return wd->gdmac.version;
+                       if (wd->rombankswitcher && (addr & 0xffe0) == GVP_ROM_OFFSET)
+                               wd->rombank = (addr & 0x02) >> 1;
+                       return wd->rom[(addr - GVP_ROM_OFFSET) / 2 + wd->rombank * 16384];
+               }
+               return 0;
+       }
+
+       switch (addr)
+       {
+               case 0x40:
+               v = wd->gdmac.cntr >> 8;
+               wd->gdmac.cntr &= ~2;
+               break;
+               case 0x41:
+               v = wd->gdmac.cntr;
+               wd->gdmac.cntr &= ~2;
+               break;
+               case 0x61: // SASR
+               v = wdscsi_getauxstatus(&wd->wc);
+               break;
+               case 0x63: // SCMD
+               v = wdscsi_get(&wd->wc, wd);
+               break;
+       }
+
+#if GVP_DEBUG_IO > 0
+       write_log(_T("dmac_bget %04X=%04X PC=%08X\n"), addr, v, M68K_GETPC);
+#endif
+
+       return v;
+}
+static uae_u32 dmac_gvp_read_word(struct wd_state *wd, uaecptr addr)
+{
+       uae_u32 v = 0;
+
+       addr &= 0xffff;
+       if (addr < 0x40)
+               return (wd->dmacmemory[addr] << 8) | wd->dmacmemory[addr + 1];
+       if (addr >= GVP_ROM_OFFSET) {
+               if (wd->rom) {
+                       if (wd->rombankswitcher && (addr & 0xffe0) == GVP_ROM_OFFSET)
+                               wd->rombank = (addr & 0x02) >> 1;
+                       return wd->rom[((addr - GVP_ROM_OFFSET) / 2 + wd->rombank * 16384) << 8] | wd->gdmac.version;
+               }
+               return 0;
+       }
+
+       switch (addr)
+       {
+               case 0x40:
+               v = wd->gdmac.cntr;
+               wd->gdmac.cntr &= ~2;
+               break;
+               case 0x68:
+               v = wd->gdmac.bank;
+               break;
+               case 0x70:
+               v = wd->gdmac.addr >> 16;
+               break;
+               case 0x72:
+               v = wd->gdmac.addr;
+               break;
+       }
+
+#if GVP_DEBUG_IO > 0
+       write_log(_T("dmac_wget %04X=%04X PC=%08X\n"), addr, v, M68K_GETPC);
+#endif
+
+       return v;
+}
+
+static void dmac_gvp_write_word(struct wd_state *wd, uaecptr addr, uae_u32 b)
+{
+       addr &= 0xffff;
+#if GVP_DEBUG_IO > 0
+       write_log(_T("dmac_wput %04X=%04X PC=%08X\n"), addr, b & 65535, M68K_GETPC);
+#endif
+       switch (addr)
+       {
+               case 0x40:
+               wd->gdmac.cntr = b;
+               break;
+               case 0x70: // ACR
+               wd->gdmac.addr &= 0x0000ffff;
+               wd->gdmac.addr |= (b & 0xff) << 16;
+               wd->gdmac.addr &= wd->gdmac.addr_mask;
+               break;
+               case 0x72: // ACR
+               wd->gdmac.addr &= 0xffff0000;
+               wd->gdmac.addr |= b;
+               wd->gdmac.addr &= wd->gdmac.addr_mask;
+               break;
+               case 0x76: // START DMA
+               wd->gdmac.dma_on = true;
+               break;
+               case 0x78: // STOP DMA
+               wd->gdmac.dma_on = false;
+               break;
+       }
+}
+
+static void dmac_gvp_write_byte(struct wd_state *wd, uaecptr addr, uae_u32 b)
+{
+       addr &= 0xffff;
+#if GVP_DEBUG_IO > 0
+       write_log(_T("dmac_bput %04X=%02X PC=%08X\n"), addr, b & 255, M68K_GETPC);
+#endif
+       switch (addr)
+       {
+               case 0x40:
+               wd->gdmac.cntr &= 0x00ff;
+               wd->gdmac.cntr |= b << 8;
+               break;
+               case 0x41:
+               wd->gdmac.cntr &= 0xff00;
+               wd->gdmac.cntr |= b << 0;
+               break;
+               case 0x61: // SASR
+               wdscsi_sasr(&wd->wc, b);
+               break;
+               case 0x63: // SCMD
+               wdscsi_put(&wd->wc, wd, b);
+               break;
+       }
+}
+
+static uae_u32 REGPARAM2 dmac_gvp_lget(struct wd_state *wd, uaecptr addr)
+{
+       uae_u32 v;
+#ifdef JIT
+       special_mem |= S_READ;
+#endif
+       addr &= 65535;
+       v = dmac_gvp_read_word(wd, addr) << 16;
+       v |= dmac_gvp_read_word(wd, addr + 2) & 0xffff;
+       return v;
+}
+
+static uae_u32 REGPARAM2 dmac_gvp_wget(struct wd_state *wd, uaecptr addr)
+{
+       uae_u32 v;
+#ifdef JIT
+       special_mem |= S_READ;
+#endif
+       addr &= 65535;
+       v = dmac_gvp_read_word(wd, addr);
+       return v;
+}
 
-/* SUPERDMAC */
+static uae_u32 REGPARAM2 dmac_gvp_bget(struct wd_state *wd, uaecptr addr)
+{
+       uae_u32 v;
+#ifdef JIT
+       special_mem |= S_READ;
+#endif
+       addr &= 65535;
+       v = dmac_gvp_read_byte(wd, addr);
+       return v;
+}
+
+static void REGPARAM2 dmac_gvp_lput(struct wd_state *wd, uaecptr addr, uae_u32 l)
+{
+#ifdef JIT
+       special_mem |= S_WRITE;
+#endif
+       addr &= 65535;
+       dmac_gvp_write_word(wd, addr + 0, l >> 16);
+       dmac_gvp_write_word(wd, addr + 2, l);
+}
+
+static void REGPARAM2 dmac_gvp_wput(struct wd_state *wd, uaecptr addr, uae_u32 w)
+{
+#ifdef JIT
+       special_mem |= S_WRITE;
+#endif
+       addr &= 65535;
+       dmac_gvp_write_word(wd, addr, w);
+}
+static void REGPARAM2 dmac_gvp_bput(struct wd_state *wd, uaecptr addr, uae_u32 b)
+{
+#ifdef JIT
+       special_mem |= S_WRITE;
+#endif
+       b &= 0xff;
+       addr &= 65535;
+       if (wd->autoconfig) {
+               addrbank *ab = wd == &wd_gvp ? &gvp_bank : &gvp_2_bank;
+               if (addr == 0x48 && !wd->configured) {
+                       map_banks_z2(ab, b, 0x10000 >> 16);
+                       wd->configured = 1;
+                       expamem_next(ab, NULL);
+                       return;
+               }
+               if (addr == 0x4c && !wd->configured) {
+                       wd->configured = 1;
+                       expamem_shutup(ab);
+                       return;
+               }
+               if (!wd->configured)
+                       return;
+       }
+       dmac_gvp_write_byte(wd, addr, b);
+}
+
+static uae_u32 REGPARAM2 dmac_gvp_wgeti(struct wd_state *wd, uaecptr addr)
+{
+       uae_u32 v = 0xffff;
+#ifdef JIT
+       special_mem |= S_READ;
+#endif
+       addr &= 65535;
+       if (addr >= GVP_ROM_OFFSET)
+               v = (wd->rom[addr & wd->rom_mask] << 8) | wd->rom[(addr + 1) & wd->rom_mask];
+       else
+               write_log(_T("Invalid GVP instruction access %08x\n"), addr);
+       return v;
+}
+static uae_u32 REGPARAM2 dmac_gvp_lgeti(struct wd_state *wd, uaecptr addr)
+{
+       uae_u32 v;
+#ifdef JIT
+       special_mem |= S_READ;
+#endif
+       addr &= 65535;
+       v = dmac_gvp_wgeti(wd, addr) << 16;
+       v |= dmac_gvp_wgeti(wd, addr + 2);
+       return v;
+}
+
+static int REGPARAM2 dmac_gvp_check(struct wd_state *wd, uaecptr addr, uae_u32 size)
+{
+       return 1;
+}
+
+static uae_u8 *REGPARAM2 dmac_gvp_xlate(struct wd_state *wd, uaecptr addr)
+{
+       addr &= 0xffff;
+       return wd->rom + addr;
+}
+
+static uae_u8 *REGPARAM2 dmac_gvp_xlate(uaecptr addr)
+{
+       return dmac_gvp_xlate(&wd_gvp, addr);
+}
+static int REGPARAM2 dmac_gvp_check(uaecptr addr, uae_u32 size)
+{
+       return dmac_gvp_check(&wd_gvp, addr, size);
+}
+static uae_u32 REGPARAM2 dmac_gvp_lgeti(uaecptr addr)
+{
+       return dmac_gvp_lgeti(&wd_gvp, addr);
+}
+static uae_u32 REGPARAM2 dmac_gvp_wgeti(uaecptr addr)
+{
+       return dmac_gvp_wgeti(&wd_gvp, addr);
+}
+static uae_u32 REGPARAM2 dmac_gvp_bget(uaecptr addr)
+{
+       return dmac_gvp_bget(&wd_gvp, addr);
+}
+static uae_u32 REGPARAM2 dmac_gvp_wget(uaecptr addr)
+{
+       return dmac_gvp_wget(&wd_gvp, addr);
+}
+static uae_u32 REGPARAM2 dmac_gvp_lget(uaecptr addr)
+{
+       return dmac_gvp_lget(&wd_gvp, addr);
+}
+static void REGPARAM2 dmac_gvp_bput(uaecptr addr, uae_u32 b)
+{
+       dmac_gvp_bput(&wd_gvp, addr, b);
+}
+static void REGPARAM2 dmac_gvp_wput(uaecptr addr, uae_u32 b)
+{
+       dmac_gvp_wput(&wd_gvp, addr, b);
+}
+static void REGPARAM2 dmac_gvp_lput(uaecptr addr, uae_u32 b)
+{
+       dmac_gvp_lput(&wd_gvp, addr, b);
+}
+
+addrbank gvp_bank = {
+       dmac_gvp_lget, dmac_gvp_wget, dmac_gvp_bget,
+       dmac_gvp_lput, dmac_gvp_wput, dmac_gvp_bput,
+       dmac_gvp_xlate, dmac_gvp_check, NULL, NULL, _T("GVP"),
+       dmac_gvp_lgeti, dmac_gvp_wgeti, ABFLAG_IO | ABFLAG_SAFE
+};
+addrbank gvp_2_bank = {
+       dmac_gvp_lget, dmac_gvp_wget, dmac_gvp_bget,
+       dmac_gvp_lput, dmac_gvp_wput, dmac_gvp_bput,
+       dmac_gvp_xlate, dmac_gvp_check, NULL, NULL, _T("GVP #2"),
+       dmac_gvp_lgeti, dmac_gvp_wgeti, ABFLAG_IO | ABFLAG_SAFE
+};
+
+/* SUPERDMAC (A3000 mainboard built-in) */
 
 static void mbdmac_write_word (struct wd_state *wd, uae_u32 addr, uae_u32 val)
 {
@@ -1805,56 +2244,56 @@ static void mbdmac_write_word (struct wd_state *wd, uae_u32 addr, uae_u32 val)
        switch (addr)
        {
        case 0x02:
-               wd->dmac_dawr = val;
+               wd->cdmac.dmac_dawr = val;
                break;
        case 0x04:
-               wd->dmac_wtc &= 0x0000ffff;
-               wd->dmac_wtc |= val << 16;
+               wd->cdmac.dmac_wtc &= 0x0000ffff;
+               wd->cdmac.dmac_wtc |= val << 16;
                break;
        case 0x06:
-               wd->dmac_wtc &= 0xffff0000;
-               wd->dmac_wtc |= val & 0xffff;
+               wd->cdmac.dmac_wtc &= 0xffff0000;
+               wd->cdmac.dmac_wtc |= val & 0xffff;
                break;
        case 0x0a:
-               wd->dmac_cntr = val;
-               if (wd->dmac_cntr & SCNTR_PREST)
+               wd->cdmac.dmac_cntr = val;
+               if (wd->cdmac.dmac_cntr & SCNTR_PREST)
                        dmac_reset (wd);
                break;
        case 0x0c:
-               wd->dmac_acr &= 0x0000ffff;
-               wd->dmac_acr |= val << 16;
+               wd->cdmac.dmac_acr &= 0x0000ffff;
+               wd->cdmac.dmac_acr |= val << 16;
                break;
        case 0x0e:
-               wd->dmac_acr &= 0xffff0000;
-               wd->dmac_acr |= val & 0xfffe;
+               wd->cdmac.dmac_acr &= 0xffff0000;
+               wd->cdmac.dmac_acr |= val & 0xfffe;
                break;
        case 0x12:
-               if (wd->dmac_dma <= 0)
-                       scsi_dmac_start_dma (wd);
+               if (wd->cdmac.dmac_dma <= 0)
+                       scsi_dmac_a2091_start_dma (wd);
                break;
        case 0x16:
-               if (wd->dmac_dma) {
+               if (wd->cdmac.dmac_dma) {
                        /* FLUSH */
-                       wd->dmac_istr |= ISTR_FE_FLG;
-                       wd->dmac_dma = 0;
+                       wd->cdmac.dmac_istr |= ISTR_FE_FLG;
+                       wd->cdmac.dmac_dma = 0;
                }
                break;
        case 0x1a:
-               dmac_cint(wd);
+               dmac_a2091_cint(wd);
                break;
        case 0x1e:
                /* ISTR */
                break;
        case 0x3e:
-               scsi_dmac_stop_dma (wd);
+               scsi_dmac_a2091_stop_dma (wd);
                break;
        case 0x40:
        case 0x48:
-               wd->sasr = val;
+               wdscsi_sasr(&wd->wc, val);
                break;
        case 0x42:
        case 0x46:
-               wdscsi_put(wd, val);
+               wdscsi_put(&wd->wc, wd, val);
                break;
        }
 }
@@ -1870,11 +2309,11 @@ static void mbdmac_write_byte (struct wd_state *wd, uae_u32 addr, uae_u32 val)
 
        case 0x41:
        case 0x49:
-               wd->sasr = val;
+               wdscsi_sasr(&wd->wc, val);
                break;
        case 0x43:
        case 0x47:
-               wdscsi_put (wd, val);
+               wdscsi_put (&wd->wc, wd, val);
                break;
        default:
                if (addr & 1)
@@ -1895,52 +2334,52 @@ static uae_u32 mbdmac_read_word (struct wd_state *wd, uae_u32 addr)
        switch (addr)
        {
        case 0x02:
-               v = wd->dmac_dawr;
+               v = wd->cdmac.dmac_dawr;
                break;
        case 0x04:
        case 0x06:
                v = 0xffff;
                break;
        case 0x0a:
-               v = wd->dmac_cntr;
+               v = wd->cdmac.dmac_cntr;
                break;
        case 0x0c:
-               v = wd->dmac_acr >> 16;
+               v = wd->cdmac.dmac_acr >> 16;
                break;
        case 0x0e:
-               v = wd->dmac_acr;
+               v = wd->cdmac.dmac_acr;
                break;
        case 0x12:
-               if (wd->dmac_dma <= 0)
-                       scsi_dmac_start_dma (wd);
+               if (wd->cdmac.dmac_dma <= 0)
+                       scsi_dmac_a2091_start_dma (wd);
                v = 0;
                break;
        case 0x1a:
-               dmac_cint (wd);
+               dmac_a2091_cint (wd);
                v = 0;
                break;;
        case 0x1e:
-               v = wd->dmac_istr;
+               v = wd->cdmac.dmac_istr;
                if (v & ISTR_INTS)
                        v |= ISTR_INT_P;
-               wd->dmac_istr &= ~15;
-               if (!wd->dmac_dma)
+               wd->cdmac.dmac_istr &= ~15;
+               if (!wd->cdmac.dmac_dma)
                        v |= ISTR_FE_FLG;
                break;
        case 0x3e:
-               if (wd->dmac_dma) {
-                       scsi_dmac_stop_dma (wd);
-                       wd->dmac_istr |= ISTR_FE_FLG;
+               if (wd->cdmac.dmac_dma) {
+                       scsi_dmac_a2091_stop_dma (wd);
+                       wd->cdmac.dmac_istr |= ISTR_FE_FLG;
                }
                v = 0;
                break;
        case 0x40:
        case 0x48:
-               v = wdscsi_getauxstatus(wd);
+               v = wdscsi_getauxstatus(&wd->wc);
                break;
        case 0x42:
        case 0x46:
-               v = wdscsi_get(wd);
+               v = wdscsi_get(&wd->wc, wd);
                break;
        }
 #if A3000_DEBUG_IO > 1
@@ -1961,11 +2400,11 @@ static uae_u32 mbdmac_read_byte (struct wd_state *wd, uae_u32 addr)
        {
        case 0x41:
        case 0x49:
-               v = wdscsi_getauxstatus (wd);
+               v = wdscsi_getauxstatus (&wd->wc);
                break;
        case 0x43:
        case 0x47:
-               v = wdscsi_get (wd);
+               v = wdscsi_get (&wd->wc, wd);
                break;
        default:
                v = mbdmac_read_word (wd, addr);
@@ -2062,15 +2501,16 @@ static void ew (struct wd_state *wd, int addr, uae_u32 value)
 
 static void *scsi_thread (void *wdv)
 {
-       struct wd_state *wd = (struct wd_state*)wdv;
+       struct wd_state *wds = (struct wd_state*)wdv;
+       struct wd_chip_state *wd = &wds->wc;
        for (;;) {
-               uae_u32 v = read_comm_pipe_u32_blocking (&wd->requests);
-               if (wd->scsi_thread_running == 0 || v == 0xfffffff)
+               uae_u32 v = read_comm_pipe_u32_blocking (&wds->requests);
+               if (wds->scsi_thread_running == 0 || v == 0xfffffff)
                        break;
                int cmd = v & 0x7f;
                int msg = (v >> 8) & 0xff;
                int unit = (v >> 24) & 0xff;
-               wd->scsi = wd->scsis[unit];
+               wd->scsi = wds->scsis[unit];
                //write_log (_T("scsi_thread got msg=%d cmd=%d\n"), msg, cmd);
                if (msg == 0) {
                        if (WD33C93_DEBUG > 0)
@@ -2078,28 +2518,29 @@ static void *scsi_thread (void *wdv)
                        switch (cmd)
                        {
                        case WD_CMD_RESET:
-                               wd_cmd_reset (wd, true);
+                               wd_cmd_reset(wd, true);
+                               wd_cmd_reset_a2091(wds, true);
                                break;
                        case WD_CMD_ABORT:
                                wd_cmd_abort (wd);
                                break;
                        case WD_CMD_SEL:
-                               wd_cmd_sel (wd, false);
+                               wd_cmd_sel (wd, wds, false);
                                break;
                        case WD_CMD_SEL_ATN:
-                               wd_cmd_sel (wd, true);
+                               wd_cmd_sel (wd, wds, true);
                                break;
                        case WD_CMD_SEL_ATN_XFER:
-                               wd_cmd_sel_xfer (wd, true);
+                               wd_cmd_sel_xfer (wd, wds, true);
                                break;
                        case WD_CMD_SEL_XFER:
-                               wd_cmd_sel_xfer (wd, false);
+                               wd_cmd_sel_xfer (wd, wds, false);
                                break;
                        case WD_CMD_TRANS_INFO:
-                               wd_cmd_trans_info (wd);
+                               wd_cmd_trans_info (wd, wd->scsi);
                                break;
                        case WD_CMD_TRANS_ADDR:
-                               wd_cmd_trans_addr(wd);
+                               wd_cmd_trans_addr(wd, wds);
                                break;
                        default:
                                wd->wd_busy = false;
@@ -2108,12 +2549,12 @@ static void *scsi_thread (void *wdv)
                                break;
                        }
                } else if (msg == 1) {
-                       wd_do_transfer_in (wd);
+                       wd_do_transfer_in (wd, wd->scsi);
                } else if (msg == 2) {
-                       wd_do_transfer_out (wd);
+                       wd_do_transfer_out (wd, wd->scsi);
                }
        }
-       wd->scsi_thread_running = -1;
+       wds->scsi_thread_running = -1;
        return 0;
 }
 
@@ -2121,8 +2562,8 @@ void init_scsi (struct wd_state *wd)
 {
        wd->configured = 0;
        wd->enabled = true;
-       wd->wd_used = 0;
-       wd->wd33c93_ver = 1;
+       wd->wc.wd_used = 0;
+       wd->wc.wd33c93_ver = 1;
        if (wd == &wd_cdtv) {
                wd->cdtv = true;
                wd->name = _T("CDTV");
@@ -2245,9 +2686,10 @@ void a3000scsi_reset (void)
        init_scsi (wd);
        wd->enabled = true;
        wd->configured = -1;
-       wd->superdmac = 1;
+       wd->dmac_type = COMMODORE_SDMAC;
        map_banks (&mbdmac_a3000_bank, 0xDD, 1, 0);
-       wd_cmd_reset (wd, false);
+       wd_cmd_reset (&wd->wc, false);
+       wd_cmd_reset_a2091(wd, false);
        wd->name = _T("A3000");
 }
 
@@ -2276,6 +2718,18 @@ int a2091_add_scsi_unit(int ch, struct uaedev_config_info *ci, int devnum)
                return add_wd_scsi_hd(wd, ch, NULL, ci, 1);
 }
 
+int gvp_add_scsi_unit(int ch, struct uaedev_config_info *ci, int devnum)
+{
+       struct wd_state *wd = gvpscsi[devnum];
+
+       if (ci->type == UAEDEV_CD)
+               return add_wd_scsi_cd(wd, ch, ci->device_emu_unit);
+       else if (ci->type == UAEDEV_TAPE)
+               return add_wd_scsi_tape(wd, ch, ci->rootdir, ci->readonly);
+       else
+               return add_wd_scsi_hd(wd, ch, NULL, ci, 1);
+}
+
 void a2091_free_device (struct wd_state *wd)
 {
        freenativescsi (wd);
@@ -2291,13 +2745,14 @@ void a2091_free (void)
 static void a2091_reset_device(struct wd_state *wd)
 {
        wd->configured = 0;
-       wd->wd_used = 0;
-       wd->superdmac = 0;
-       wd->wd33c93_ver = 1;
-       wd->old_dmac = 0;
+       wd->wc.wd_used = 0;
+       wd->wc.wd33c93_ver = 1;
+       wd->dmac_type = COMMODORE_DMAC;
+       wd->cdmac.old_dmac = 0;
        if (currprefs.scsi == 2)
                addnativescsi (wd);
-       wd_cmd_reset (wd, false);
+       wd_cmd_reset (&wd->wc, false);
+       wd_cmd_reset_a2091(wd, false);
        if (wd == &wd_a2091)
                wd->name = _T("A2091/A590");
        if (wd == &wd_a2091_2)
@@ -2327,13 +2782,13 @@ addrbank *a2091_init (int devnum)
        memset (wd->dmacmemory, 0xff, sizeof wd->dmacmemory);
        ew (wd, 0x00, 0xc0 | 0x01 | 0x10);
        /* A590/A2091 hardware id */
-       ew (wd, 0x04, wd->old_dmac ? 0x02 : 0x03);
+       ew(wd, 0x04, wd->cdmac.old_dmac ? 0x02 : 0x03);
        /* commodore's manufacturer id */
        ew (wd, 0x10, 0x02);
        ew (wd, 0x14, 0x02);
        /* rom vector */
-       ew (wd, 0x28, ROM_VECTOR >> 8);
-       ew (wd, 0x2c, ROM_VECTOR);
+       ew (wd, 0x28, CDMAC_ROM_VECTOR >> 8);
+       ew (wd, 0x2c, CDMAC_ROM_VECTOR);
 
        ew (wd, 0x18, 0x00); /* ser.no. Byte 0 */
        ew (wd, 0x1c, 0x00); /* ser.no. Byte 1 */
@@ -2385,6 +2840,101 @@ addrbank *a2091_init (int devnum)
        return wd == &wd_a2091 ? &dmaca2091_bank : &dmaca2091_2_bank;
 }
 
+void gvp_free_device (struct wd_state *wd)
+{
+       freenativescsi (wd);
+       xfree (wd->rom);
+       wd->rom = NULL;
+}
+void gvp_free (void)
+{
+       gvp_free_device(&wd_gvp);
+       gvp_free_device(&wd_gvp_2);
+}
+
+static void gvp_reset_device(struct wd_state *wd)
+{
+       wd->configured = 0;
+       wd->wc.wd_used = 0;
+       wd->wc.wd33c93_ver = 1;
+       wd->dmac_type = GVP_DMAC;
+       wd->gdmac.version = GVP_SERIESII;
+       if (wd->gdmac.series2)
+               wd->gdmac.version |= 1;
+       wd->gdmac.addr_mask = 0x00ffffff;
+       if (currprefs.scsi == 2)
+               addnativescsi (wd);
+       wd_cmd_reset (&wd->wc, false);
+       if (wd == &wd_gvp)
+               wd->name = _T("GVP");
+       if (wd == &wd_gvp_2)
+               wd->name = _T("GPV #2");
+}
+
+void gvp_reset (void)
+{
+       gvp_reset_device(&wd_gvp);
+       gvp_reset_device(&wd_gvp_2);
+}
+
+static const uae_u8 gvp_scsi_i_autoconfig[16] = { 0xd1, 0x09, 0x00, 0x00, 0x07, 0xe1, 0xee, 0xee, 0xee, 0xee, 0x80, 0x00 };
+static const uae_u8 gvp_scsi_ii_autoconfig[16] = { 0xd1, 0x0b, 0x00, 0x00, 0x07, 0xe1, 0xee, 0xee, 0xee, 0xee, 0x80, 0x00 };
+
+addrbank *gvp_init(int devnum)
+{
+       struct wd_state *wd = gvpscsi[devnum];
+       int roms[6];
+       struct romlist *rl;
+
+       if (devnum > 0 && !wd->enabled)
+               return &expamem_null;
+
+       init_scsi(wd);
+       wd->name = _T("GVP");
+       wd->configured = 0;
+       wd->autoconfig = true;
+       wd->rombankswitcher = 0;
+       memset(wd->dmacmemory, 0xff, sizeof wd->dmacmemory);
+
+       roms[0] = 109;
+       roms[1] = 110;
+       roms[2] = 111;
+       roms[3] = -1;
+
+       wd->rom_size = 32768;
+       wd->rom = xmalloc(uae_u8, wd->rom_size);
+       memset(wd->rom, 0xff, wd->rom_size);
+       wd->rom_mask = wd->rom_size - 1;
+       wd->gdmac.series2 = true;
+       if (1) {
+               const TCHAR *romname = devnum && currprefs.gvprom.roms[1].romfile[0] ? currprefs.gvprom.roms[1].romfile : currprefs.gvprom.roms[0].romfile;
+               struct zfile *z = read_rom_name(romname);
+               if (!z) {
+                       rl = getromlistbyids(roms, romname);
+                       if (rl) {
+                               z = read_rom(rl->rd);
+                       }
+                       if (rl && rl->rd && rl->rd->id == 111)
+                               wd->gdmac.series2 = false;
+               }
+               if (z) {
+                       for (int i = 0; i < 16; i++) {
+                               uae_u8 b = wd->gdmac.series2 ? gvp_scsi_ii_autoconfig[i] : gvp_scsi_i_autoconfig[i];
+                               ew(wd, i * 4, b);
+                       }
+                       write_log(_T("GVP BOOT ROM '%s'\n"), zfile_getname(z));
+                       int size = zfile_fread(wd->rom, 1, wd->rom_size, z);
+                       zfile_fclose(z);
+                       if (size > 16384) {
+                               wd->rombankswitcher = 1;
+                       }
+               } else {
+                       romwarning(roms);
+               }
+       }
+       return wd == &wd_gvp ? &gvp_bank : &gvp_2_bank;
+}
+
 uae_u8 *save_scsi_dmac (int wdtype, int *len, uae_u8 *dstptr)
 {
        struct wd_state *wd = wdscsi[wdtype];
@@ -2400,12 +2950,12 @@ uae_u8 *save_scsi_dmac (int wdtype, int *len, uae_u8 *dstptr)
        // model (0=original,1=rev2,2=superdmac)
        save_u32 (currprefs.cs_mbdmac == 1 ? 2 : 1);
        save_u32 (0); // reserved flags
-       save_u8 (wd->dmac_istr);
-       save_u8 (wd->dmac_cntr);
-       save_u32 (wd->dmac_wtc);
-       save_u32 (wd->dmac_acr);
-       save_u16 (wd->dmac_dawr);
-       save_u32 (wd->dmac_dma ? 1 : 0);
+       save_u8(wd->cdmac.dmac_istr);
+       save_u8(wd->cdmac.dmac_cntr);
+       save_u32(wd->cdmac.dmac_wtc);
+       save_u32(wd->cdmac.dmac_acr);
+       save_u16(wd->cdmac.dmac_dawr);
+       save_u32(wd->cdmac.dmac_dma ? 1 : 0);
        save_u8 (wd->configured);
        *len = dst - dstbak;
        return dstbak;
@@ -2416,11 +2966,11 @@ uae_u8 *restore_scsi_dmac (int wdtype, uae_u8 *src)
        struct wd_state *wd = wdscsi[wdtype];
        restore_u32 ();
        restore_u32 ();
-       wd->dmac_istr = restore_u8 ();
-       wd->dmac_cntr = restore_u8 ();
-       wd->dmac_wtc = restore_u32 ();
-       wd->dmac_acr = restore_u32 ();
-       wd->dmac_dawr = restore_u16 ();
+       wd->cdmac.dmac_istr = restore_u8();
+       wd->cdmac.dmac_cntr = restore_u8();
+       wd->cdmac.dmac_wtc = restore_u32();
+       wd->cdmac.dmac_acr = restore_u32();
+       wd->cdmac.dmac_dawr = restore_u16();
        restore_u32 ();
        wd->configured = restore_u8 ();
        return src;
@@ -2461,11 +3011,11 @@ uae_u8 *save_scsi_device (int wdtype, int num, int *len, uae_u8 *dstptr)
                save_u32 (s->hfd->hfd.ci.bootpri);
                save_u32 (s->hfd->ansi_version);
                if (num == 7) {
-                       save_u16(wd->xt_cyls);
-                       save_u16(wd->xt_heads);
-                       save_u16(wd->xt_sectors);
-                       save_u8(wd->xt_status);
-                       save_u8(wd->xt_control);
+                       save_u16(wd->cdmac.xt_cyls);
+                       save_u16(wd->cdmac.xt_heads);
+                       save_u16(wd->cdmac.xt_sectors);
+                       save_u8(wd->cdmac.xt_status);
+                       save_u8(wd->cdmac.xt_control);
                }
        break;
        case UAEDEV_CD:
@@ -2518,11 +3068,11 @@ uae_u8 *restore_scsi_device (int wdtype, uae_u8 *src)
                s->hfd->ansi_version = restore_u32 ();
                s->hfd->hfd.ci.blocksize = blocksize;
                if (num == 7) {
-                       wd->xt_cyls = restore_u16();
-                       wd->xt_heads = restore_u8();
-                       wd->xt_sectors = restore_u8();
-                       wd->xt_status = restore_u8();
-                       wd->xt_control = restore_u8();
+                       wd->cdmac.xt_cyls = restore_u16();
+                       wd->cdmac.xt_heads = restore_u8();
+                       wd->cdmac.xt_sectors = restore_u8();
+                       wd->cdmac.xt_status = restore_u8();
+                       wd->cdmac.xt_control = restore_u8();
                }
                if (size)
                        add_wd_scsi_hd (wd, num, hfd, NULL, s->hfd->ansi_version);
index 57a4303a4c73b7cc99b034e8079912add1b05ee6..74501733a985040f9c891c155f651d0368f843be 100644 (file)
@@ -6,37 +6,34 @@
 
 #define WD_STATUS_QUEUE 2
 
-struct wd_state {
-       bool enabled;
-       const TCHAR *name;
-       int configured;
-       bool autoconfig;
-       uae_u8 dmacmemory[100];
-       uae_u8 *rom;
-       int rombankswitcher, rombank;
-       int rom_size, rom_mask;
+struct wd_chip_state {
 
-       uae_u32 dmac_istr, dmac_cntr;
-       uae_u32 dmac_dawr;
-       uae_u32 dmac_acr;
-       uae_u32 dmac_wtc;
-       int dmac_dma;
        volatile uae_u8 sasr, scmd, auxstatus;
        volatile int wd_used;
        volatile int wd_phase, wd_next_phase, wd_busy, wd_data_avail;
        volatile bool wd_selected;
        volatile int wd_dataoffset;
        volatile uae_u8 wd_data[32];
-
-       volatile int scsidelay_irq[WD_STATUS_QUEUE];
+       uae_u8 wdregs[32];
        volatile uae_u8 scsidelay_status[WD_STATUS_QUEUE];
        volatile int queue_index;
-       smp_comm_pipe requests;
-       volatile int scsi_thread_running;
+       volatile int scsidelay_irq[WD_STATUS_QUEUE];
+       struct scsi_data *scsi;
+       int wd33c93_ver;// 0 or 1
+};
 
+#define COMMODORE_DMAC 1
+#define COMMODORE_SDMAC 2
+#define GVP_DMAC 3
+
+struct commodore_dmac
+{
+       uae_u32 dmac_istr, dmac_cntr;
+       uae_u32 dmac_dawr;
+       uae_u32 dmac_acr;
+       uae_u32 dmac_wtc;
+       int dmac_dma;
        int old_dmac;
-       int superdmac;
-       int wd33c93_ver;// 0 or 1
 
        uae_u8 xt_control;
        uae_u8 xt_status;
@@ -47,34 +44,66 @@ struct wd_state {
        int xt_datalen;
        uae_u8 xt_cmd[6];
        uae_u8 xt_statusbyte;
+};
+struct gvp_dmac
+{
+       uae_u16 cntr;
+       uae_u32 addr;
+       uae_u16 len;
+       uae_u16 bank;
+       bool dma_on;
+       uae_u8 version;
+       uae_u32 addr_mask;
+       bool series2;
+};
+
+struct wd_state {
+       bool enabled;
+       const TCHAR *name;
+       int configured;
+       bool autoconfig;
+       uae_u8 dmacmemory[100];
+       uae_u8 *rom;
+       int rombankswitcher, rombank;
+       int rom_size, rom_mask;
+
+
+       smp_comm_pipe requests;
+       volatile int scsi_thread_running;
 
        // unit 7 = XT
        struct scsi_data *scsis[8];
-       struct scsi_data *scsi;
-
-       uae_u8 wdregs[32];
 
        bool cdtv;
+
+       int dmac_type;
+       struct wd_chip_state wc;
+       struct commodore_dmac cdmac;
+       struct gvp_dmac gdmac;
 };
 extern wd_state wd_cdtv;
 
 extern void init_scsi (struct wd_state*);
-extern void scsi_dmac_start_dma (struct wd_state*);
-extern void scsi_dmac_stop_dma (struct wd_state*);
+extern void scsi_dmac_a2091_start_dma (struct wd_state*);
+extern void scsi_dmac_a2091_stop_dma (struct wd_state*);
 
 extern addrbank *a2091_init (int devnum);
-extern void a2091_free (void);
+extern void a2091_free(void);
 extern void a2091_reset (void);
 
+extern addrbank *gvp_init(int devnum);
+extern void gvp_free(void);
+extern void gvp_reset (void);
+
 extern void a3000scsi_init (void);
 extern void a3000scsi_free (void);
 extern void a3000scsi_reset (void);
 extern void rethink_a2091 (void);
 
-extern void wdscsi_put (struct wd_state*, uae_u8);
-extern uae_u8 wdscsi_get (struct wd_state*);
-extern uae_u8 wdscsi_getauxstatus (struct wd_state*);
-extern void wdscsi_sasr (struct wd_state*, uae_u8);
+extern void wdscsi_put (struct wd_chip_state*, wd_state*, uae_u8);
+extern uae_u8 wdscsi_get (struct wd_chip_state*, struct wd_state*);
+extern uae_u8 wdscsi_getauxstatus (struct wd_chip_state*);
+extern void wdscsi_sasr (struct wd_chip_state*, uae_u8);
 
 extern void scsi_hsync (void);
 
@@ -82,10 +111,12 @@ extern void scsi_hsync (void);
 #define WDTYPE_A2091_2 1
 #define WDTYPE_A3000 2
 #define WDTYPE_CDTV 3
+#define WDTYPE_GVP 4
 
 #define WD33C93 _T("WD33C93")
 
 extern int a2091_add_scsi_unit(int ch, struct uaedev_config_info *ci, int devnum);
+extern int gvp_add_scsi_unit(int ch, struct uaedev_config_info *ci, int devnum);
 extern int a3000_add_scsi_unit(int ch, struct uaedev_config_info *ci);
 
 extern int add_wd_scsi_hd (struct wd_state *wd, int ch, struct hd_hardfiledata *hfd, struct uaedev_config_info *ci, int scsi_level);