]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
IDE emulation detached from Gayle. GVP A3001 IDE.
authorToni Wilen <twilen@winuae.net>
Sun, 11 Jan 2015 12:28:54 +0000 (14:28 +0200)
committerToni Wilen <twilen@winuae.net>
Sun, 11 Jan 2015 12:28:54 +0000 (14:28 +0200)
14 files changed:
cpuboard.cpp
expansion.cpp
filesys.cpp
gayle.cpp
ide.cpp [new file with mode: 0644]
idecontrollers.cpp [new file with mode: 0644]
include/cpuboard.h
include/filesys.h
include/ide.h [new file with mode: 0644]
include/idecontrollers.h [new file with mode: 0644]
include/savestate.h
main.cpp
rommgr.cpp
savestate.cpp

index e6b59e0125230b55415fd0266bb66c92ffac0031..e7fe8d57183707c44723beaf3d4822e4d8656c02 100644 (file)
@@ -1802,6 +1802,9 @@ addrbank *cpuboard_autoconfig_init(void)
                roms[0] = 105;
                roms[1] = 106;
                break;
+       case BOARD_A3001_I:
+       case BOARD_A3001_II:
+               return &expamem_null;
        case BOARD_BLIZZARD_1230_IV_SCSI:
                roms2[0] = 94;
        case BOARD_BLIZZARD_1230_IV:
index 9971f525ef90ca4ff722ba2f1140e86fa8565948..ca067dd3e56072eedcd90c00a881c40f4b53535e 100644 (file)
@@ -32,6 +32,7 @@
 #include "ncr9x_scsi.h"
 #include "debug.h"
 #include "gayle.h"
+#include "idecontrollers.h"
 #include "cpuboard.h"
 #include "sndboard.h"
 #include "uae/ppc.h"
@@ -1094,7 +1095,7 @@ static addrbank *expamem_init_fastcard_2 (int boardnum)
                pid = commodore_a2091_ram;
                mid = commodore;
                serial = 0;
-       } else if (cfgfile_board_enabled(&currprefs.gvprom)) {
+       } else if (cfgfile_board_enabled(&currprefs.gvprom) || currprefs.cpuboard_type == BOARD_A3001_I || currprefs.cpuboard_type == BOARD_A3001_II) {
                pid = 10;
                mid = 2017;
                serial = 0;
@@ -1702,6 +1703,14 @@ static addrbank *expamem_init_oktagon_2(void)
 {
        return ncr_oktagon_autoconfig_init (1);
 }
+static addrbank *expamem_init_a3001_rom(void)
+{
+       return gvp_ide_rom_autoconfig_init();
+}
+static addrbank *expamem_init_a3001_ide(void)
+{
+       return gvp_ide_controller_autoconfig_init();
+}
 static addrbank *expamem_init_warpengine(void)
 {
        return ncr710_warpengine_autoconfig_init();
@@ -1785,7 +1794,25 @@ void expamem_reset (void)
                        map_banks(&fastmem2_bank, (0x00200000 + fastmem_bank.allocated) >> 16, fastmem2_bank.allocated >> 16, 0);
                }
        }
+
        // immediately after Z2Fast so that they can be emulated as A590/A2091 with fast ram.
+
+       if (currprefs.cpuboard_type == BOARD_A3001_I) {
+               card_flags[cardno] = 0;
+               card_name[cardno] = _T("A3001 IDE");
+               card_init[cardno] = expamem_init_a3001_rom;
+               card_map[cardno++] = NULL;
+       } else if (currprefs.cpuboard_type == BOARD_A3001_II) {
+               card_flags[cardno] = 0;
+               card_name[cardno] = _T("A3001 BOOT");
+               card_init[cardno] = expamem_init_a3001_rom;
+               card_map[cardno++] = NULL;
+               card_flags[cardno] = 0;
+               card_name[cardno] = _T("A3001 IDE");
+               card_init[cardno] = expamem_init_a3001_ide;
+               card_map[cardno++] = NULL;
+       }
+
 #ifdef A2091
        if (cfgfile_board_enabled(&currprefs.a2091rom)) {
                card_flags[cardno] = 0;
index e998da401054cf8d43281fd791ea55e400b4ca11..e758dfb0521c00129485cd043f8e9ed5443c6ee2 100644 (file)
@@ -44,6 +44,7 @@
 #include "zarchive.h"
 #include "gui.h"
 #include "gayle.h"
+#include "idecontrollers.h"
 #include "savestate.h"
 #include "a2091.h"
 #include "ncr_scsi.h"
@@ -814,6 +815,21 @@ static bool add_cpuboard_scsi_unit(int unit, struct uaedev_config_info *uci)
        return added;
 }
 
+static bool add_ide_unit(int type, int unit, struct uaedev_config_info *uci)
+{
+       bool added = false;
+       if (type == HD_CONTROLLER_TYPE_IDE_MB) {
+               if (currprefs.cs_ide) {
+                       gayle_add_ide_unit(unit, uci);
+                       added = true;
+               }
+       } else if (type == HD_CONTROLLER_TYPE_IDE_GVP) {
+               gvp_add_ide_unit(unit, uci);
+               added = true;
+       }
+       return added;
+}
+
 static bool add_scsi_unit(int type, int unit, struct uaedev_config_info *uci)
 {
        bool added = false;
@@ -979,9 +995,14 @@ static void initialize_mountinfo (void)
                bool added = false;
                if (type == HD_CONTROLLER_TYPE_UAE) {
                        continue;
-               } else if (type >= HD_CONTROLLER_TYPE_IDE_FIRST && type <= HD_CONTROLLER_TYPE_IDE_LAST) {
-                       gayle_add_ide_unit (unit, uci);
-                       added = true;
+               } else if (type != HD_CONTROLLER_TYPE_IDE_AUTO && type >= HD_CONTROLLER_TYPE_IDE_FIRST && type <= HD_CONTROLLER_TYPE_IDE_LAST) {
+                       added = add_ide_unit(type, unit, uci);
+               } else if (type == HD_CONTROLLER_TYPE_IDE_AUTO) {
+                       for (int st = HD_CONTROLLER_TYPE_IDE_FIRST; st <= HD_CONTROLLER_TYPE_IDE_LAST; st++) {
+                               added = add_ide_unit(st, unit, uci);
+                               if (added)
+                                       break;
+                       }
                } else if (type != HD_CONTROLLER_TYPE_SCSI_AUTO && type >= HD_CONTROLLER_TYPE_SCSI_FIRST && type <= HD_CONTROLLER_TYPE_SCSI_LAST) {
                        added = add_scsi_unit(type, unit, uci);
                } else if (type == HD_CONTROLLER_TYPE_SCSI_AUTO) {
index 35304fb7886fa9206f8b63744e3693c914e5ea13..ca4cc436948f9fb7127fadf05f917f48b74ff6aa 100644 (file)
--- a/gayle.cpp
+++ b/gayle.cpp
@@ -7,7 +7,6 @@
 */
 
 #define GAYLE_LOG 0
-#define IDE_LOG 0
 #define MBRES_LOG 0
 #define PCMCIA_LOG 0
 
@@ -29,6 +28,7 @@
 #include "ncr_scsi.h"
 #include "blkdev.h"
 #include "scsi.h"
+#include "ide.h"
 
 #define PCMCIA_SRAM 1
 #define PCMCIA_IDE 2
@@ -71,44 +71,11 @@ DE0000 to DEFFFF    64 KB Motherboard resources
 #define GAYLE_IO_8BITODD        0xa30000     /* odd 8bit registers */
 
 #define GAYLE_ADDRESS   0xda8000      /* gayle main registers base address */
-#define GAYLE_RESET     0xa40000      /* write 0x00 to start reset,
-read 1 byte to stop reset */
-/* IDE stuff */
+#define GAYLE_RESET     0xa40000      /* write 0x00 to start reset, read 1 byte to stop reset */
 
 /*  Bases of the IDE interfaces */
 #define GAYLE_BASE_4000 0xdd2020    /* A4000/A4000T */
 #define GAYLE_BASE_1200 0xda0000    /* A1200/A600 and E-Matrix 530 */
-/* IDE drive registers */
-#define IDE_DATA       0x00
-#define IDE_ERROR      0x01        /* see err-bits */
-#define IDE_NSECTOR    0x02        /* sector count, nr of sectors to read/write */
-#define IDE_SECTOR     0x03        /* starting sector */
-#define IDE_LCYL       0x04        /* starting cylinder */
-#define IDE_HCYL       0x05        /* high byte of starting cyl */
-#define IDE_SELECT     0x06        /* 101dhhhh , d=drive, hhhh=head */
-#define IDE_STATUS     0x07        /* see status-bits */
-#define IDE_DEVCON     0x0406
-#define IDE_DRVADDR    0x0407
-/* STATUS bits */
-#define IDE_STATUS_ERR 0x01            // 0
-#define IDE_STATUS_IDX 0x02            // 1
-#define IDE_STATUS_DRQ 0x08            // 3
-#define IDE_STATUS_DSC 0x10            // 4
-#define IDE_STATUS_DRDY 0x40   // 6
-#define IDE_STATUS_BSY 0x80            // 7
-#define ATAPI_STATUS_CHK IDE_STATUS_ERR
-/* ERROR bits */
-#define IDE_ERR_UNC 0x40
-#define IDE_ERR_MC 0x20
-#define IDE_ERR_IDNF 0x10
-#define IDE_ERR_MCR 0x08
-#define IDE_ERR_ABRT 0x04
-#define IDE_ERR_NM 0x02
-#define ATAPI_ERR_EOM 0x02
-#define ATAPI_ERR_ILI 0x01
-/* ATAPI interrupt reason (Sector Count) */
-#define ATAPI_IO 0x02
-#define ATAPI_CD 0x01
 
 /*
 *  These are at different offsets from the base
@@ -167,62 +134,11 @@ read 1 byte to stop reset */
 #define GAYLE_CFG_250NS         0x00
 #define GAYLE_CFG_720NS         0x0c
 
-#define IDE_GAYLE 0
-#define IDE_ADIDE 1
-
-
-#define ATAPI_MAX_TRANSFER 32768
-#define MAX_IDE_MULTIPLE_SECTORS 64
-#define SECBUF_SIZE (131072 * 2)
-
-struct ide_registers
-{
-       uae_u8 ide_select, ide_nsector, ide_sector, ide_lcyl, ide_hcyl, ide_devcon, ide_error, ide_feat;
-       uae_u8 ide_nsector2, ide_sector2, ide_lcyl2, ide_hcyl2, ide_feat2;
-       uae_u8 ide_status;
-};
-
-struct ide_hdf
-{
-       struct hd_hardfiledata hdhfd;
-       struct ide_registers regs;
-       struct ide_registers *regs0;
-       struct ide_registers *regs1;
-       struct ide_hdf *pair;
-
-       uae_u8 secbuf[SECBUF_SIZE];
-       int data_offset;
-       int data_size;
-       int data_multi;
-       int direction; // 0 = read, 1 = write
-       bool intdrq;
-       bool lba48;
-       bool lba48cmd;
-       uae_u8 multiple_mode;
-       int irq_delay;
-       int irq;
-       int num;
-       int type;
-       int blocksize;
-       int maxtransferstate;
-       int ide_drv;
-
-       bool atapi;
-       bool atapi_drdy;
-       int cd_unit_num;
-       int packet_state;
-       int packet_data_size;
-       int packet_data_offset;
-       int packet_transfer_size;
-       struct scsi_data *scsi;
-};
-
 #define TOTAL_IDE 3
 #define GAYLE_IDE_ID 0
 #define PCMCIA_IDE_ID 2
 
 static struct ide_hdf *idedrive[TOTAL_IDE * 2];
-static struct ide_registers ideregs[TOTAL_IDE * 2];
 struct hd_hardfiledata *pcmcia_sram;
 
 static int pcmcia_card;
@@ -235,31 +151,7 @@ static int gayle_id_cnt;
 static uae_u8 gayle_irq, gayle_int, gayle_cs, gayle_cs_mask, gayle_cfg;
 static int ide_splitter;
 
-static smp_comm_pipe requests;
-static volatile int gayle_thread_running;
-
-STATIC_INLINE void pw (struct ide_hdf *ide, int offset, uae_u16 w)
-{
-       ide->secbuf[offset * 2 + 0] = (uae_u8)w;
-       ide->secbuf[offset * 2 + 1] = w >> 8;
-}
-static void ps (struct ide_hdf *ide, int offset, const TCHAR *src, int max)
-{
-       int i, len;
-       char *s;
-
-       offset *= 2;
-       s = ua (src);
-       len = strlen (s);
-       for (i = 0; i < max; i++) {
-               char c = ' ';
-               if (i < len)
-                       c = s[i];
-               ide->secbuf[offset ^ 1] = c;
-               offset++;
-       }
-       xfree (s);
-}
+static struct ide_thread_state gayle_its;
 
 static void pcmcia_reset (void)
 {
@@ -273,18 +165,13 @@ static uae_u8 checkpcmciaideirq (void)
 {
        if (!idedrive || pcmcia_type != PCMCIA_IDE || pcmcia_configured < 0)
                return 0;
-       if (ideregs[PCMCIA_IDE_ID].ide_devcon & 2)
+       if (idedrive[PCMCIA_IDE_ID * 2]->regs0->ide_devcon & 2)
                return 0;
        if (idedrive[PCMCIA_IDE_ID * 2]->irq)
                return GAYLE_IRQ_BSY;
        return 0;
 }
 
-static bool isdrive (struct ide_hdf *ide)
-{
-       return ide && (ide->hdhfd.size != 0 || ide->atapi);
-}
-
 static uae_u8 checkgayleideirq (void)
 {
        int i;
@@ -296,9 +183,9 @@ static uae_u8 checkgayleideirq (void)
                if (!(idedrive[i]->regs.ide_devcon & 2) && (idedrive[i]->irq || idedrive[i + 2]->irq))
                        irq = true;
                /* IDE killer feature. Do not eat interrupt to make booting faster. */
-               if (idedrive[i]->irq && !isdrive (idedrive[i]))
+               if (idedrive[i]->irq && !ide_isdrive (idedrive[i]))
                        idedrive[i]->irq = 0;
-               if (idedrive[i + 2]->irq && !isdrive (idedrive[i + 2]))
+               if (idedrive[i + 2]->irq && !ide_isdrive (idedrive[i + 2]))
                        idedrive[i + 2]->irq = 0;
        }
        return irq ? GAYLE_IRQ_IDE : 0;
@@ -437,754 +324,6 @@ static uae_u8 read_gayle_cs (void)
        return v;
 }
 
-static void ide_interrupt (struct ide_hdf *ide)
-{
-       ide->regs.ide_status |= IDE_STATUS_BSY;
-       ide->regs.ide_status &= ~IDE_STATUS_DRQ;
-       ide->irq_delay = 2;
-}
-static void ide_fast_interrupt (struct ide_hdf *ide)
-{
-       ide->regs.ide_status |= IDE_STATUS_BSY;
-       ide->regs.ide_status &= ~IDE_STATUS_DRQ;
-       ide->irq_delay = 1;
-}
-
-#if 0
-uae_u16 isideint(void)
-{
-       if (!(gayle_irq & 0x80))
-               return 0;
-       gayle_irq &= ~0x80;
-       return 0x8000;
-}
-#endif
-
-static void ide_interrupt_do (struct ide_hdf *ide)
-{
-       uae_u8 os = ide->regs.ide_status;
-       ide->regs.ide_status &= ~IDE_STATUS_DRQ;
-       if (ide->intdrq)
-               ide->regs.ide_status |= IDE_STATUS_DRQ;
-       ide->regs.ide_status &= ~IDE_STATUS_BSY;
-       if (IDE_LOG > 1)
-               write_log (_T("IDE INT %02X -> %02X\n"), os, ide->regs.ide_status);
-       ide->intdrq = false;
-       ide->irq_delay = 0;
-       if (ide->regs.ide_devcon & 2)
-               return;
-       ide->irq = 1;
-       rethink_gayle ();
-}
-
-static void ide_fail_err (struct ide_hdf *ide, uae_u8 err)
-{
-       ide->regs.ide_error |= err;
-       if (ide->ide_drv == 1 && !isdrive (ide->pair))
-               idedrive[ide->ide_drv >= 2 ? 2 : 0]->regs.ide_status |= IDE_STATUS_ERR;
-       ide->regs.ide_status |= IDE_STATUS_ERR;
-       ide_interrupt (ide);
-}
-static void ide_fail (struct ide_hdf *ide)
-{
-       ide_fail_err (ide, IDE_ERR_ABRT);
-}
-
-static void ide_data_ready (struct ide_hdf *ide)
-{
-       memset (ide->secbuf, 0, ide->blocksize);
-       ide->data_offset = 0;
-       ide->data_size = ide->blocksize;
-       ide->data_multi = 1;
-       ide->intdrq = true;
-       ide_interrupt (ide);
-}
-
-static void ide_recalibrate (struct ide_hdf *ide)
-{
-       write_log (_T("IDE%d recalibrate\n"), ide->num);
-       ide->regs.ide_sector = 0;
-       ide->regs.ide_lcyl = ide->regs.ide_hcyl = 0;
-       ide_interrupt (ide);
-}
-static void ide_identify_drive (struct ide_hdf *ide)
-{
-       uae_u64 totalsecs;
-       int v;
-       uae_u8 *buf = ide->secbuf;
-       TCHAR tmp[100];
-       bool atapi = ide->atapi;
-
-       if (!isdrive (ide)) {
-               ide_fail (ide);
-               return;
-       }
-       memset (buf, 0, ide->blocksize);
-       if (IDE_LOG > 0)
-               write_log (_T("IDE%d identify drive\n"), ide->num);
-       ide_data_ready (ide);
-       ide->direction = 0;
-       pw (ide, 0, atapi ? 0x85c0 : 1 << 6);
-       pw (ide, 1, ide->hdhfd.cyls_def);
-       pw (ide, 2, 0xc837);
-       pw (ide, 3, ide->hdhfd.heads_def);
-       pw (ide, 4, ide->blocksize * ide->hdhfd.secspertrack_def);
-       pw (ide, 5, ide->blocksize);
-       pw (ide, 6, ide->hdhfd.secspertrack_def);
-       ps (ide, 10, _T("68000"), 20); /* serial */
-       pw (ide, 20, 3);
-       pw (ide, 21, ide->blocksize);
-       pw (ide, 22, 4);
-       ps (ide, 23, _T("0.5"), 8); /* firmware revision */
-       if (ide->atapi)
-               _tcscpy (tmp, _T("UAE-ATAPI"));
-       else
-               _stprintf (tmp, _T("UAE-IDE %s"), ide->hdhfd.hfd.product_id);
-       ps (ide, 27, tmp, 40); /* model */
-       pw (ide, 47, MAX_IDE_MULTIPLE_SECTORS >> (ide->blocksize / 512 - 1)); /* max sectors in multiple mode */
-       pw (ide, 48, 1);
-       pw (ide, 49, (1 << 9) | (1 << 8)); /* LBA and DMA supported */
-       pw (ide, 51, 0x200); /* PIO cycles */
-       pw (ide, 52, 0x200); /* DMA cycles */
-       pw (ide, 53, 1 | 2 | 4);
-       pw (ide, 54, ide->hdhfd.cyls);
-       pw (ide, 55, ide->hdhfd.heads);
-       pw (ide, 56, ide->hdhfd.secspertrack);
-       totalsecs = ide->hdhfd.cyls * ide->hdhfd.heads * ide->hdhfd.secspertrack;
-       pw (ide, 57, (uae_u16)totalsecs);
-       pw (ide, 58, (uae_u16)(totalsecs >> 16));
-       v = idedrive[ide->ide_drv]->multiple_mode;
-       pw (ide, 59, (v > 0 ? 0x100 : 0) | v);
-       totalsecs = ide->blocksize ? ide->hdhfd.size / ide->blocksize : 0;
-       if (totalsecs > 0x0fffffff)
-               totalsecs = 0x0fffffff;
-       pw (ide, 60, (uae_u16)totalsecs);
-       pw (ide, 61, (uae_u16)(totalsecs >> 16));
-       pw (ide, 62, 0x0f);
-       pw (ide, 63, 0x0f);
-       pw (ide, 64, 0x03); /* PIO3 and PIO4 */
-       pw (ide, 65, 120); /* MDMA2 supported */
-       pw (ide, 66, 120);
-       pw (ide, 67, 120);
-       pw (ide, 68, 120);
-       pw (ide, 80, (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6)); /* ATA-1 to ATA-6 */
-       pw (ide, 81, 0x1c); /* ATA revision */
-       pw (ide, 82, (1 << 14) | (atapi ? 0x10 | 4 : 0)); /* NOP, ATAPI: PACKET and Removable media features supported */
-       pw (ide, 83, (1 << 14) | (1 << 13) | (1 << 12) | (ide->lba48 ? (1 << 10) : 0)); /* cache flushes, LBA 48 supported */
-       pw (ide, 84, 1 << 14);
-       pw (ide, 85, 1 << 14);
-       pw (ide, 86, (1 << 14) | (1 << 13) | (1 << 12) | (ide->lba48 ? (1 << 10) : 0)); /* cache flushes, LBA 48 enabled */
-       pw (ide, 87, 1 << 14);
-       pw (ide, 88, (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1) | (1 << 0)); /* UDMA modes */
-       pw (ide, 93, (1 << 14) | (1 << 13) | (1 << 0));
-       if (ide->lba48) {
-               totalsecs = ide->hdhfd.size / ide->blocksize;
-               pw (ide, 100, (uae_u16)(totalsecs >> 0));
-               pw (ide, 101, (uae_u16)(totalsecs >> 16));
-               pw (ide, 102, (uae_u16)(totalsecs >> 32));
-               pw (ide, 103, (uae_u16)(totalsecs >> 48));
-       }
-}
-
-static void set_signature (struct ide_hdf *ide)
-{
-       if (ide->atapi) {
-               ide->regs.ide_sector = 1;
-               ide->regs.ide_nsector = 1;
-               ide->regs.ide_lcyl = 0x14;
-               ide->regs.ide_hcyl = 0xeb;
-               ide->regs.ide_status = 0;
-               ide->atapi_drdy = false;
-       } else {
-               ide->regs.ide_nsector = 1;
-               ide->regs.ide_sector = 1;
-               ide->regs.ide_lcyl = 0;
-               ide->regs.ide_hcyl = 0;
-               ide->regs.ide_status = 0;
-       }
-       ide->regs.ide_error = 0x01; // device ok
-       ide->packet_state = 0;
-}
-
-static void reset_device (struct ide_hdf *ide, bool both)
-{
-       set_signature (ide);
-       if (both)
-               set_signature (ide->pair);
-}
-
-static void ide_execute_drive_diagnostics (struct ide_hdf *ide, bool irq)
-{
-       reset_device (ide, irq);
-       if (irq)
-               ide_interrupt (ide);
-       else
-               ide->regs.ide_status &= ~IDE_STATUS_BSY;
-}
-
-static void ide_initialize_drive_parameters (struct ide_hdf *ide)
-{
-       if (ide->hdhfd.size) {
-               ide->hdhfd.secspertrack = ide->regs.ide_nsector == 0 ? 256 : ide->regs.ide_nsector;
-               ide->hdhfd.heads = (ide->regs.ide_select & 15) + 1;
-               if (ide->hdhfd.hfd.ci.pcyls)
-                       ide->hdhfd.cyls = ide->hdhfd.hfd.ci.pcyls;
-               else
-                       ide->hdhfd.cyls = (ide->hdhfd.size / ide->blocksize) / (ide->hdhfd.secspertrack * ide->hdhfd.heads);
-               if (ide->hdhfd.heads * ide->hdhfd.cyls * ide->hdhfd.secspertrack > 16515072 || ide->lba48) {
-                       if (ide->hdhfd.hfd.ci.pcyls)
-                               ide->hdhfd.cyls = ide->hdhfd.hfd.ci.pcyls;
-                       else
-                               ide->hdhfd.cyls = ide->hdhfd.cyls_def;
-                       ide->hdhfd.heads = ide->hdhfd.heads_def;
-                       ide->hdhfd.secspertrack = ide->hdhfd.secspertrack_def;
-               }
-       } else {
-               ide->regs.ide_error |= IDE_ERR_ABRT;
-               ide->regs.ide_status |= IDE_STATUS_ERR;
-       }
-       write_log (_T("IDE%d initialize drive parameters, CYL=%d,SPT=%d,HEAD=%d\n"),
-               ide->num, ide->hdhfd.cyls, ide->hdhfd.secspertrack, ide->hdhfd.heads);
-       ide_interrupt (ide);
-}
-static void ide_set_multiple_mode (struct ide_hdf *ide)
-{
-       write_log (_T("IDE%d drive multiple mode = %d\n"), ide->num, ide->regs.ide_nsector);
-       ide->multiple_mode = ide->regs.ide_nsector;
-       ide_interrupt (ide);
-}
-static void ide_set_features (struct ide_hdf *ide)
-{
-       int type = ide->regs.ide_nsector >> 3;
-       int mode = ide->regs.ide_nsector & 7;
-
-       write_log (_T("IDE%d set features %02X (%02X)\n"), ide->num, ide->regs.ide_feat, ide->regs.ide_nsector);
-       ide_fail (ide);
-}
-
-static void get_lbachs (struct ide_hdf *ide, uae_u64 *lbap, unsigned int *cyl, unsigned int *head, unsigned int *sec)
-{
-       if (ide->lba48 && ide->lba48cmd && (ide->regs.ide_select & 0x40)) {
-               uae_u64 lba;
-               lba = (ide->regs.ide_hcyl << 16) | (ide->regs.ide_lcyl << 8) | ide->regs.ide_sector;
-               lba |= ((ide->regs.ide_hcyl2 << 16) | (ide->regs.ide_lcyl2 << 8) | ide->regs.ide_sector2) << 24;
-               *lbap = lba;
-       } else {
-               if (ide->regs.ide_select & 0x40) {
-                       *lbap = ((ide->regs.ide_select & 15) << 24) | (ide->regs.ide_hcyl << 16) | (ide->regs.ide_lcyl << 8) | ide->regs.ide_sector;
-               } else {
-                       *cyl = (ide->regs.ide_hcyl << 8) | ide->regs.ide_lcyl;
-                       *head = ide->regs.ide_select & 15;
-                       *sec = ide->regs.ide_sector;
-                       *lbap = (((*cyl) * ide->hdhfd.heads + (*head)) * ide->hdhfd.secspertrack) + (*sec) - 1;
-               }
-       }
-}
-
-static int get_nsec (struct ide_hdf *ide)
-{
-       if (ide->lba48 && ide->lba48cmd)
-               return (ide->regs.ide_nsector == 0 && ide->regs.ide_nsector2 == 0) ? 65536 : (ide->regs.ide_nsector2 * 256 + ide->regs.ide_nsector);
-       else
-               return ide->regs.ide_nsector == 0 ? 256 : ide->regs.ide_nsector;
-}
-static int dec_nsec (struct ide_hdf *ide, int v)
-{
-       if (ide->lba48 && ide->lba48cmd) {
-               uae_u16 nsec;
-               nsec = ide->regs.ide_nsector2 * 256 + ide->regs.ide_nsector;
-               ide->regs.ide_nsector -= v;
-               ide->regs.ide_nsector2 = nsec >> 8;
-               ide->regs.ide_nsector = nsec & 0xff;
-               return (ide->regs.ide_nsector2 << 8) | ide->regs.ide_nsector;
-       } else {
-               ide->regs.ide_nsector -= v;
-               return ide->regs.ide_nsector;
-       }
-}
-
-static void put_lbachs (struct ide_hdf *ide, uae_u64 lba, unsigned int cyl, unsigned int head, unsigned int sec, unsigned int inc)
-{
-       if (ide->lba48 && ide->lba48cmd) {
-               lba += inc;
-               ide->regs.ide_hcyl = (lba >> 16) & 0xff;
-               ide->regs.ide_lcyl = (lba >> 8) & 0xff;
-               ide->regs.ide_sector = lba & 0xff;
-               lba >>= 24;
-               ide->regs.ide_hcyl2 = (lba >> 16) & 0xff;
-               ide->regs.ide_lcyl2 = (lba >> 8) & 0xff;
-               ide->regs.ide_sector2 = lba & 0xff;
-       } else {
-               if (ide->regs.ide_select & 0x40) {
-                       lba += inc;
-                       ide->regs.ide_select &= ~15;
-                       ide->regs.ide_select |= (lba >> 24) & 15;
-                       ide->regs.ide_hcyl = (lba >> 16) & 0xff;
-                       ide->regs.ide_lcyl = (lba >> 8) & 0xff;
-                       ide->regs.ide_sector = lba & 0xff;
-               } else {
-                       sec += inc;
-                       while (sec >= ide->hdhfd.secspertrack) {
-                               sec -= ide->hdhfd.secspertrack;
-                               head++;
-                               if (head >= ide->hdhfd.heads) {
-                                       head -= ide->hdhfd.heads;
-                                       cyl++;
-                               }
-                       }
-                       ide->regs.ide_select &= ~15;
-                       ide->regs.ide_select |= head;
-                       ide->regs.ide_sector = sec;
-                       ide->regs.ide_hcyl = cyl >> 8;
-                       ide->regs.ide_lcyl = (uae_u8)cyl;
-               }
-       }
-}
-
-static void check_maxtransfer (struct ide_hdf *ide, int state)
-{
-       if (state == 1) {
-               // transfer was started
-               if (ide->maxtransferstate < 2 && ide->regs.ide_nsector == 0) {
-                       ide->maxtransferstate = 1;
-               } else if (ide->maxtransferstate == 2) {
-                       // second transfer was started (part of split)
-                       write_log (_T("IDE maxtransfer check detected split >256 block transfer\n"));
-                       ide->maxtransferstate = 0;
-               } else {
-                       ide->maxtransferstate = 0;
-               }
-       } else if (state == 2) {
-               // address was read
-               if (ide->maxtransferstate == 1)
-                       ide->maxtransferstate++;
-               else
-                       ide->maxtransferstate = 0;
-       }
-}
-
-static void setdrq (struct ide_hdf *ide)
-{
-       ide->regs.ide_status |= IDE_STATUS_DRQ;
-       ide->regs.ide_status &= ~IDE_STATUS_BSY;
-}
-static void setbsy (struct ide_hdf *ide)
-{
-       ide->regs.ide_status |= IDE_STATUS_BSY;
-       ide->regs.ide_status &= ~IDE_STATUS_DRQ;
-}
-
-static void process_rw_command (struct ide_hdf *ide)
-{
-       setbsy (ide);
-       write_comm_pipe_u32 (&requests, ide->num, 1);
-}
-static void process_packet_command (struct ide_hdf *ide)
-{
-       setbsy (ide);
-       write_comm_pipe_u32 (&requests, ide->num | 0x80, 1);
-}
-
-static void atapi_data_done (struct ide_hdf *ide)
-{
-       ide->regs.ide_nsector = ATAPI_IO | ATAPI_CD;
-       ide->regs.ide_status = IDE_STATUS_DRDY;
-       ide->data_size = 0;
-       ide->packet_data_offset = 0;
-       ide->data_offset = 0;
-}
-
-static bool atapi_set_size (struct ide_hdf *ide)
-{
-       int size;
-       size = ide->data_size;
-       ide->data_offset = 0;
-       if (!size) {
-               ide->packet_state = 0;
-               ide->packet_transfer_size = 0;
-               return false;
-       }
-       if (ide->packet_state == 2) {
-               if (size > ide->packet_data_size)
-                       size = ide->packet_data_size;
-               if (size > ATAPI_MAX_TRANSFER)
-                       size = ATAPI_MAX_TRANSFER;
-               ide->packet_transfer_size = size & ~1;
-               ide->regs.ide_lcyl = size & 0xff;
-               ide->regs.ide_hcyl = size >> 8;
-       } else {
-               ide->packet_transfer_size = 12;
-       }
-       if (IDE_LOG > 1)
-               write_log (_T("ATAPI data transfer %d/%d bytes\n"), ide->packet_transfer_size, ide->data_size);
-       return true;
-}
-
-static void atapi_packet (struct ide_hdf *ide)
-{
-       ide->packet_data_offset = 0;
-       ide->packet_data_size = (ide->regs.ide_hcyl << 8) | ide->regs.ide_lcyl;
-       if (ide->packet_data_size == 65535)
-               ide->packet_data_size = 65534;
-       ide->data_size = 12;
-       if (IDE_LOG > 0)
-               write_log (_T("ATAPI packet command. Data size = %d\n"), ide->packet_data_size);
-       ide->packet_state = 1;
-       ide->data_multi = 1;
-       ide->data_offset = 0;
-       ide->regs.ide_nsector = ATAPI_CD;
-       ide->regs.ide_error = 0;
-       if (atapi_set_size (ide))
-               setdrq (ide);
-}
-
-static void do_packet_command (struct ide_hdf *ide)
-{
-       memcpy (ide->scsi->cmd, ide->secbuf, 12);
-       ide->scsi->cmd_len = 12;
-       if (IDE_LOG > 0) {
-               uae_u8 *c = ide->scsi->cmd;
-               write_log (_T("ATASCSI %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x\n"),
-                       c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8], c[9], c[10], c[11]);
-       }
-       ide->direction = 0;
-       scsi_emulate_analyze (ide->scsi);
-       if (ide->scsi->direction <= 0) {
-               // data in
-               ide->scsi->data_len = SECBUF_SIZE;
-               scsi_emulate_cmd (ide->scsi);
-               ide->data_size = ide->scsi->data_len;
-               ide->regs.ide_status = 0;
-               if (ide->scsi->status) {
-                       // error
-                       ide->regs.ide_error = (ide->scsi->sense[2] << 4) | 4;
-                       atapi_data_done (ide);
-                       ide->regs.ide_status |= ATAPI_STATUS_CHK;
-                       atapi_set_size (ide);
-                       return;
-               } else if (ide->scsi->data_len) {
-                       // data in
-                       memcpy (ide->secbuf, ide->scsi->buffer, ide->scsi->data_len);
-                       ide->regs.ide_nsector = ATAPI_IO;
-               } else {
-                       // no data
-                       atapi_data_done (ide);
-               }
-       } else {
-               // data out
-               ide->direction = 1;
-               ide->regs.ide_nsector = 0;
-               ide->data_size = ide->scsi->data_len;
-       }
-       ide->packet_state = 2; // data phase
-       if (atapi_set_size (ide))
-               ide->intdrq = true;
-}
-
-static void do_process_packet_command (struct ide_hdf *ide)
-{
-       if (ide->packet_state == 1) {
-               do_packet_command (ide);
-       } else {
-               ide->packet_data_offset += ide->packet_transfer_size;
-               if (!ide->direction) {
-                       // data still remaining, next transfer
-                       if (atapi_set_size (ide))
-                               ide->intdrq = true;
-               } else {
-                       if (atapi_set_size (ide)) {
-                               ide->intdrq = true;
-                       } else {
-                               memcpy (&ide->scsi->buffer, ide->secbuf, ide->data_size);
-                               ide->scsi->data_len = ide->data_size;
-                               scsi_emulate_cmd (ide->scsi);
-                               if (IDE_LOG > 1)
-                                       write_log (_T("IDE%d ATAPI write finished, %d bytes\n"), ide->num, ide->data_size);
-                       }
-               }
-       }
-       ide_fast_interrupt (ide);
-}
-
-static void do_process_rw_command (struct ide_hdf *ide)
-{
-       unsigned int cyl, head, sec, nsec;
-       uae_u64 lba;
-       bool last;
-
-       ide->data_offset = 0;
-       get_lbachs (ide, &lba, &cyl, &head, &sec);
-       nsec = get_nsec (ide);
-       if (IDE_LOG > 1)
-               write_log (_T("IDE%d off=%d, nsec=%d (%d) lba48=%d\n"), ide->num, (uae_u32)lba, nsec, ide->multiple_mode, ide->lba48 + ide->lba48cmd);
-       if (nsec * ide->blocksize > ide->hdhfd.size - lba * ide->blocksize) {
-               nsec = (ide->hdhfd.size - lba * ide->blocksize) / ide->blocksize;
-               if (IDE_LOG > 1)
-                       write_log (_T("IDE%d nsec changed to %d\n"), ide->num, nsec);
-       }
-       if (nsec <= 0) {
-               ide_data_ready (ide);
-               ide_fail_err (ide, IDE_ERR_IDNF);
-               return;
-       }
-       if (nsec > ide->data_multi)
-               nsec = ide->data_multi;
-
-       if (ide->direction) {
-               hdf_write (&ide->hdhfd.hfd, ide->secbuf, lba * ide->blocksize, nsec * ide->blocksize);
-               if (IDE_LOG > 1)
-                       write_log (_T("IDE%d write, %d bytes written\n"), ide->num, nsec * ide->blocksize);
-       } else {
-               hdf_read (&ide->hdhfd.hfd, ide->secbuf, lba * ide->blocksize, nsec * ide->blocksize);
-               if (IDE_LOG > 1)
-                       write_log (_T("IDE%d read, read %d bytes\n"), ide->num, nsec * ide->blocksize);
-       }
-       ide->intdrq = true;
-       last = dec_nsec (ide, nsec) == 0;
-       put_lbachs (ide, lba, cyl, head, sec, last ? nsec - 1 : nsec);
-       if (last && ide->direction) {
-               ide->intdrq = false;
-               if (IDE_LOG > 1)
-                       write_log (_T("IDE%d write finished\n"), ide->num);
-       }
-       ide_fast_interrupt (ide);
-}
-
-static void ide_read_sectors (struct ide_hdf *ide, int flags)
-{
-       unsigned int cyl, head, sec, nsec;
-       uae_u64 lba;
-       int multi = flags & 1;
-
-       ide->lba48cmd = (flags & 2) != 0;
-       if (multi && ide->multiple_mode == 0) {
-               ide_fail (ide);
-               return;
-       }
-       check_maxtransfer (ide, 1);
-       gui_flicker_led (LED_HD, ide->num, 1);
-       nsec = get_nsec (ide);
-       get_lbachs (ide, &lba, &cyl, &head, &sec);
-       if (lba * ide->blocksize >= ide->hdhfd.size) {
-               ide_data_ready (ide);
-               ide_fail_err (ide, IDE_ERR_IDNF);
-               return;
-       }
-       if (IDE_LOG > 0)
-               write_log (_T("IDE%d read off=%d, sec=%d (%d) lba48=%d\n"), ide->num, (uae_u32)lba, nsec, ide->multiple_mode, ide->lba48 + ide->lba48cmd);
-       ide->data_multi = multi ? ide->multiple_mode : 1;
-       ide->data_offset = 0;
-       ide->data_size = nsec * ide->blocksize;
-       ide->direction = 0;
-       // read start: preload sector(s), then trigger interrupt.
-       process_rw_command (ide);
-}
-
-static void ide_write_sectors (struct ide_hdf *ide, int flags)
-{
-       unsigned int cyl, head, sec, nsec;
-       uae_u64 lba;
-       int multi = flags & 1;
-
-       ide->lba48cmd = (flags & 2) != 0;
-       if (multi && ide->multiple_mode == 0) {
-               ide_fail (ide);
-               return;
-       }
-       check_maxtransfer (ide, 1);
-       gui_flicker_led (LED_HD, ide->num, 2);
-       nsec = get_nsec (ide);
-       get_lbachs (ide, &lba, &cyl, &head, &sec);
-       if (lba * ide->blocksize >= ide->hdhfd.size) {
-               ide_data_ready (ide);
-               ide_fail_err (ide, IDE_ERR_IDNF);
-               return;
-       }
-       if (IDE_LOG > 0)
-               write_log (_T("IDE%d write off=%d, sec=%d (%d) lba48=%d\n"), ide->num, (uae_u32)lba, nsec, ide->multiple_mode, ide->lba48 + ide->lba48cmd);
-       if (nsec * ide->blocksize > ide->hdhfd.size - lba * ide->blocksize)
-               nsec = (ide->hdhfd.size - lba * ide->blocksize) / ide->blocksize;
-       if (nsec <= 0) {
-               ide_data_ready (ide);
-               ide_fail_err (ide, IDE_ERR_IDNF);
-               return;
-       }
-       ide->data_multi = multi ? ide->multiple_mode : 1;
-       ide->data_offset = 0;
-       ide->data_size = nsec * ide->blocksize;
-       ide->direction = 1;
-       // write start: set DRQ and clear BSY. No interrupt.
-       ide->regs.ide_status |= IDE_STATUS_DRQ;
-       ide->regs.ide_status &= ~IDE_STATUS_BSY;
-}
-
-static void ide_do_command (struct ide_hdf *ide, uae_u8 cmd)
-{
-       int lba48 = ide->lba48;
-
-       if (IDE_LOG > 1)
-               write_log (_T("**** IDE%d command %02X\n"), ide->num, cmd);
-       ide->regs.ide_status &= ~ (IDE_STATUS_DRDY | IDE_STATUS_DRQ | IDE_STATUS_ERR);
-       ide->regs.ide_error = 0;
-       ide->lba48cmd = false;
-
-       if (ide->atapi) {
-
-               gui_flicker_led (LED_CD, ide->num, 1);
-               ide->atapi_drdy = true;
-               if (cmd == 0x00) { /* nop */
-                       ide_interrupt (ide);
-               } else if (cmd == 0x08) { /* device reset */
-                       ide_execute_drive_diagnostics (ide, true);
-               } else if (cmd == 0xa1) { /* identify packet device */
-                       ide_identify_drive (ide);
-               } else if (cmd == 0xa0) { /* packet */
-                       atapi_packet (ide);
-               } else if (cmd == 0x90) { /* execute drive diagnostics */
-                       ide_execute_drive_diagnostics (ide, true);
-               } else {
-                       ide_execute_drive_diagnostics (ide, false);
-                       ide->atapi_drdy = false;
-                       ide_fail (ide);
-                       write_log (_T("IDE%d: unknown ATAPI command 0x%02x\n"), ide->num, cmd);
-               }
-
-       } else {
-
-               if (cmd == 0x10) { /* recalibrate */
-                       ide_recalibrate (ide);
-               } else if (cmd == 0xec) { /* identify drive */
-                       ide_identify_drive (ide);
-               } else if (cmd == 0x90) { /* execute drive diagnostics */
-                       ide_execute_drive_diagnostics (ide, true);
-               } else if (cmd == 0x91) { /* initialize drive parameters */
-                       ide_initialize_drive_parameters (ide);
-               } else if (cmd == 0xc6) { /* set multiple mode */
-                       ide_set_multiple_mode (ide);
-               } else if (cmd == 0x20 || cmd == 0x21) { /* read sectors */
-                       ide_read_sectors (ide, 0);
-               } else if (cmd == 0x24 && lba48) { /* read sectors ext */
-                       ide_read_sectors (ide, 2);
-               } else if (cmd == 0xc4) { /* read multiple */
-                       ide_read_sectors (ide, 1);
-               } else if (cmd == 0x29 && lba48) { /* read multiple ext */
-                       ide_read_sectors (ide, 1|2);
-               } else if (cmd == 0x30 || cmd == 0x31) { /* write sectors */
-                       ide_write_sectors (ide, 0);
-               } else if (cmd == 0x34 && lba48) { /* write sectors ext */
-                       ide_write_sectors (ide, 2);
-               } else if (cmd == 0xc5) { /* write multiple */
-                       ide_write_sectors (ide, 1);
-               } else if (cmd == 0x39 && lba48) { /* write multiple ext */
-                       ide_write_sectors (ide, 1|2);
-               } else if (cmd == 0x50) { /* format track (nop) */
-                       ide_interrupt (ide);
-               } else if (cmd == 0xef) { /* set features  */
-                       ide_set_features (ide);
-               } else if (cmd == 0x00) { /* nop */
-                       ide_fail (ide);
-               } else if (cmd == 0xe0 || cmd == 0xe1 || cmd == 0xe7 || cmd == 0xea) { /* standby now/idle/flush cache/flush cache ext */
-                       ide_interrupt (ide);
-               } else if (cmd == 0xe5) { /* check power mode */
-                       ide->regs.ide_nsector = 0xff;
-                       ide_interrupt (ide);
-               } else {
-                       ide_fail (ide);
-                       write_log (_T("IDE%d: unknown ATA command 0x%02x\n"), ide->num, cmd);
-               }
-       }
-}
-
-static uae_u16 ide_get_data (struct ide_hdf *ide)
-{
-       bool irq = false;
-       uae_u16 v;
-
-       if (IDE_LOG > 4)
-               write_log (_T("IDE%d DATA read\n"), ide->num);
-       if (ide->data_size == 0) {
-               if (IDE_LOG > 0)
-                       write_log (_T("IDE%d DATA but no data left!? %02X PC=%08X\n"), ide->num, ide->regs.ide_status, m68k_getpc ());
-               if (!isdrive (ide))
-                       return 0xffff;
-               return 0;
-       }
-       if (ide->packet_state) {
-               v = ide->secbuf[ide->packet_data_offset + ide->data_offset + 1] | (ide->secbuf[ide->packet_data_offset + ide->data_offset + 0] << 8);
-               ide->data_offset += 2;
-               if (ide->data_size < 0)
-                       ide->data_size += 2;
-               else
-                       ide->data_size -= 2;
-               if (ide->data_offset == ide->packet_transfer_size) {
-                       if (IDE_LOG > 1)
-                               write_log (_T("IDE%d ATAPI partial read finished, %d bytes remaining\n"), ide->num, ide->data_size);
-                       if (ide->data_size == 0) {
-                               ide->packet_state = 0;
-                               atapi_data_done (ide);
-                               if (IDE_LOG > 1)
-                                       write_log (_T("IDE%d ATAPI read finished, %d bytes\n"), ide->num, ide->packet_data_offset + ide->data_offset);
-                               irq = true;
-                       } else {
-                               process_packet_command (ide);
-                       }
-               }
-       } else {
-               v = ide->secbuf[ide->data_offset + 1] | (ide->secbuf[ide->data_offset + 0] << 8);
-               ide->data_offset += 2;
-               if (ide->data_size < 0) {
-                       ide->data_size += 2;
-               } else {
-                       ide->data_size -= 2;
-                       if (((ide->data_offset % ide->blocksize) == 0) && ((ide->data_offset / ide->blocksize) % ide->data_multi) == 0) {
-                               if (ide->data_size)
-                                       process_rw_command (ide);
-                       }
-               }
-               if (ide->data_size == 0) {
-                       if (!(ide->regs.ide_status & IDE_STATUS_DRQ)) {
-                               write_log (_T("IDE%d read finished but DRQ was not active?\n"), ide->num);
-                       }
-                       ide->regs.ide_status &= ~IDE_STATUS_DRQ;
-                       if (IDE_LOG > 1)
-                               write_log (_T("IDE%d read finished\n"), ide->num);
-               }
-       }
-       if (irq)
-               ide_fast_interrupt (ide);
-       return v;
-}
-
-static void ide_put_data (struct ide_hdf *ide, uae_u16 v)
-{
-       if (IDE_LOG > 4)
-               write_log (_T("IDE%d DATA write %04x %d/%d\n"), ide->num, v, ide->data_offset, ide->data_size);
-       if (ide->data_size == 0) {
-               if (IDE_LOG > 0)
-                       write_log (_T("IDE%d DATA write without request!? %02X PC=%08X\n"), ide->num, ide->regs.ide_status, m68k_getpc ());
-               return;
-       }
-       ide->secbuf[ide->packet_data_offset + ide->data_offset + 1] = v & 0xff;
-       ide->secbuf[ide->packet_data_offset + ide->data_offset + 0] = v >> 8;
-       ide->data_offset += 2;
-       ide->data_size -= 2;
-       if (ide->packet_state) {
-               if (ide->data_offset == ide->packet_transfer_size) {
-                       if (IDE_LOG > 0) {
-                               uae_u16 v = (ide->regs.ide_hcyl << 8) | ide->regs.ide_lcyl;
-                               write_log (_T("Data size after command received = %d (%d)\n"), v, ide->packet_data_size);
-                       }
-                       process_packet_command (ide);
-               }
-       } else {
-               if (ide->data_size == 0) {
-                       process_rw_command (ide);
-               } else if (((ide->data_offset % ide->blocksize) == 0) && ((ide->data_offset / ide->blocksize) % ide->data_multi) == 0) {
-                       process_rw_command (ide);
-               }
-       }
-}
-
 static int get_gayle_ide_reg (uaecptr addr, struct ide_hdf **ide)
 {
        int ide2;
@@ -1195,176 +334,16 @@ static int get_gayle_ide_reg (uaecptr addr, struct ide_hdf **ide)
        addr &= ~0x2020;
        addr >>= 2;
        ide2 = 0;
-       if (addr & 0x400) {
+       if (addr & IDE_SECONDARY) {
                if (ide_splitter) {
                        ide2 = 2;
-                       addr &= ~0x400;
+                       addr &= ~IDE_SECONDARY;
                }
        }
        *ide = idedrive[ide2 + idedrive[ide2]->ide_drv];
        return addr;
 }
 
-static uae_u32 ide_read_reg (struct ide_hdf *ide, int ide_reg)
-{
-       uae_u8 v = 0;
-       bool isdrv = isdrive (ide);
-
-       if (!ide)
-               goto end;
-
-       if (ide->regs.ide_status & IDE_STATUS_BSY)
-               ide_reg = IDE_STATUS;
-       if (!isdrive (ide)) {
-               if (ide_reg == IDE_STATUS && ide->pair->irq)
-                       ide->pair->irq = 0;
-               if (isdrive (ide->pair))
-                       v = 0x00;
-               else
-                       v = 0xff;
-               goto end;
-       }
-
-       switch (ide_reg)
-       {
-       case IDE_DRVADDR:
-               v = ((ide->ide_drv ? 2 : 1) | ((ide->regs.ide_select & 15) << 2)) ^ 0xff;
-               break;
-       case IDE_DATA:
-               break;
-       case IDE_ERROR:
-               v = ide->regs.ide_error;
-               break;
-       case IDE_NSECTOR:
-               if (isdrv) {
-                       if (ide->regs.ide_devcon & 0x80)
-                               v = ide->regs.ide_nsector2;
-                       else
-                               v = ide->regs.ide_nsector;
-               }
-               break;
-       case IDE_SECTOR:
-               if (isdrv) {
-                       if (ide->regs.ide_devcon & 0x80)
-                               v = ide->regs.ide_sector2;
-                       else
-                               v = ide->regs.ide_sector;
-                       check_maxtransfer (ide, 2);
-               }
-               break;
-       case IDE_LCYL:
-               if (isdrv) {
-                       if (ide->regs.ide_devcon & 0x80)
-                               v = ide->regs.ide_lcyl2;
-                       else
-                               v = ide->regs.ide_lcyl;
-               }
-               break;
-       case IDE_HCYL:
-               if (isdrv) {
-                       if (ide->regs.ide_devcon & 0x80)
-                               v = ide->regs.ide_hcyl2;
-                       else
-                               v = ide->regs.ide_hcyl;
-               }
-               break;
-       case IDE_SELECT:
-               v = ide->regs.ide_select;
-               break;
-       case IDE_STATUS:
-               ide->irq = 0;
-               /* fall through */
-       case IDE_DEVCON: /* ALTSTATUS when reading */
-               if (!isdrv) {
-                       v = 0;
-                       if (ide->regs.ide_error)
-                               v |= IDE_STATUS_ERR;
-               } else {
-                       v = ide->regs.ide_status;
-                       if (!ide->atapi || (ide->atapi && ide->atapi_drdy))
-                               v |= IDE_STATUS_DRDY | IDE_STATUS_DSC;
-               }
-               break;
-       }
-end:
-       if (IDE_LOG > 2 && ide_reg > 0 && (1 || ide->num > 0))
-               write_log (_T("IDE%d GET register %d->%02X (%08X)\n"), ide->num, ide_reg, (uae_u32)v & 0xff, m68k_getpc ());
-       return v;
-}
-
-static void ide_write_reg (struct ide_hdf *ide, int ide_reg, uae_u32 val)
-{
-       if (!ide)
-               return;
-       
-       ide->regs1->ide_devcon &= ~0x80; /* clear HOB */
-       ide->regs0->ide_devcon &= ~0x80; /* clear HOB */
-       if (IDE_LOG > 2 && ide_reg > 0 && (1 || ide->num > 0))
-               write_log (_T("IDE%d PUT register %d=%02X (%08X)\n"), ide->num, ide_reg, (uae_u32)val & 0xff, m68k_getpc ());
-
-       switch (ide_reg)
-       {
-       case IDE_DRVADDR:
-               break;
-       case IDE_DEVCON:
-               if ((ide->regs.ide_devcon & 4) == 0 && (val & 4) != 0) {
-                       reset_device (ide, true);
-                       if (IDE_LOG > 1)
-                               write_log (_T("IDE%d: SRST\n"), ide->num);
-               }
-               ide->regs0->ide_devcon = val;
-               ide->regs1->ide_devcon = val;
-               break;
-       case IDE_DATA:
-               break;
-       case IDE_ERROR:
-               ide->regs0->ide_feat2 = ide->regs0->ide_feat;
-               ide->regs0->ide_feat = val;
-               ide->regs1->ide_feat2 = ide->regs1->ide_feat;
-               ide->regs1->ide_feat = val;
-               break;
-       case IDE_NSECTOR:
-               ide->regs0->ide_nsector2 = ide->regs0->ide_nsector;
-               ide->regs0->ide_nsector = val;
-               ide->regs1->ide_nsector2 = ide->regs1->ide_nsector;
-               ide->regs1->ide_nsector = val;
-               break;
-       case IDE_SECTOR:
-               ide->regs0->ide_sector2 = ide->regs0->ide_sector;
-               ide->regs0->ide_sector = val;
-               ide->regs1->ide_sector2 = ide->regs1->ide_sector;
-               ide->regs1->ide_sector = val;
-               break;
-       case IDE_LCYL:
-               ide->regs0->ide_lcyl2 = ide->regs0->ide_lcyl;
-               ide->regs0->ide_lcyl = val;
-               ide->regs1->ide_lcyl2 = ide->regs1->ide_lcyl;
-               ide->regs1->ide_lcyl = val;
-               break;
-       case IDE_HCYL:
-               ide->regs0->ide_hcyl2 = ide->regs0->ide_hcyl;
-               ide->regs0->ide_hcyl = val;
-               ide->regs1->ide_hcyl2 = ide->regs1->ide_hcyl;
-               ide->regs1->ide_hcyl = val;
-               break;
-       case IDE_SELECT:
-               ide->regs0->ide_select = val;
-               ide->regs1->ide_select = val;
-#if IDE_LOG > 2
-               if (ide->ide_drv != (val & 0x10) ? 1 : 0)
-                       write_log (_T("DRIVE=%d\n"), (val & 0x10) ? 1 : 0);
-#endif
-               ide->pair->ide_drv = ide->ide_drv = (val & 0x10) ? 1 : 0;
-               break;
-       case IDE_STATUS:
-               ide->irq = 0;
-               if (isdrive (ide)) {
-                       ide->regs.ide_status |= IDE_STATUS_BSY;
-                       ide_do_command (ide, val);
-               }
-               break;
-       }
-}
 
 static uae_u32 gayle_read2 (uaecptr addr)
 {
@@ -1372,7 +351,7 @@ static uae_u32 gayle_read2 (uaecptr addr)
        int ide_reg;
 
        addr &= 0xffff;
-       if ((IDE_LOG > 3 && (addr != 0x2000 && addr != 0x2001 && addr != 0x3020 && addr != 0x3021 && addr != GAYLE_IRQ_1200)) || IDE_LOG > 5)
+       if ((GAYLE_LOG > 3 && (addr != 0x2000 && addr != 0x2001 && addr != 0x3020 && addr != 0x3021 && addr != GAYLE_IRQ_1200)) || GAYLE_LOG > 5)
                write_log (_T("IDE_READ %08X PC=%X\n"), addr, M68K_GETPC);
        if (currprefs.cs_ide <= 0) {
                if (addr == 0x201c) // AR1200 IDE detection hack
@@ -1398,7 +377,7 @@ static uae_u32 gayle_read2 (uaecptr addr)
        }
        ide_reg = get_gayle_ide_reg (addr, &ide);
        /* Emulated "ide killer". Prevents long KS boot delay if no drives installed */
-       if (!isdrive (idedrive[0]) && !isdrive (idedrive[1]) && !isdrive (idedrive[2]) && !isdrive (idedrive[3])) {
+       if (!ide_isdrive (idedrive[0]) && !ide_isdrive (idedrive[1]) && !ide_isdrive (idedrive[2]) && !ide_isdrive (idedrive[3])) {
                if (ide_reg == IDE_STATUS)
                        return 0x7f;
                return 0xff;
@@ -1411,7 +390,7 @@ static void gayle_write2 (uaecptr addr, uae_u32 val)
        struct ide_hdf *ide = NULL;
        int ide_reg;
 
-       if ((IDE_LOG > 3 && (addr != 0x2000 && addr != 0x2001 && addr != 0x2020 && addr != 0x2021 && addr != GAYLE_IRQ_1200)) || IDE_LOG > 5)
+       if ((GAYLE_LOG > 3 && (addr != 0x2000 && addr != 0x2001 && addr != 0x2020 && addr != 0x2021 && addr != GAYLE_IRQ_1200)) || GAYLE_LOG > 5)
                write_log (_T("IDE_WRITE %08X=%02X PC=%X\n"), addr, (uae_u32)val & 0xff, M68K_GETPC);
        if (currprefs.cs_ide <= 0)
                return;
@@ -1930,83 +909,8 @@ addrbank mbres_bank = {
 
 void gayle_hsync (void)
 {
-       int i;
-
-       for (i = 0; i < TOTAL_IDE * 2; i++) {
-               struct ide_hdf *ide = idedrive[i];
-               if (ide->irq_delay > 0) {
-                       ide->irq_delay--;
-                       if (ide->irq_delay == 0)
-                               ide_interrupt_do (ide);
-               }
-       }
-}
-
-static void alloc_ide_mem (struct ide_hdf **ide, int max)
-{
-       int i;
-
-       for (i = 0; i < max; i++) {
-               if (!ide[i]) {
-                       ide[i] = xcalloc (struct ide_hdf, 1);
-                       ide[i]->cd_unit_num = -1;
-               }
-       }
-}
-
-static void remode_ide_unit(int ch)
-{
-       struct ide_hdf *ide;
-
-       ide = idedrive[ch];
-       if (!ide)
-               return;
-       hdf_hd_close(&ide->hdhfd);
-       scsi_free(ide->scsi);
-       ide->scsi = NULL;
-}
-
-static struct ide_hdf *add_ide_unit (int ch, struct uaedev_config_info *ci)
-{
-       struct ide_hdf *ide;
-
-       alloc_ide_mem (idedrive, TOTAL_IDE * 2);
-       ide = idedrive[ch];
-       if (ci)
-               memcpy (&ide->hdhfd.hfd.ci, ci, sizeof (struct uaedev_config_info));
-       if (ci->type == UAEDEV_CD && ci->device_emu_unit >= 0) {
-               device_func_init (0);
-               ide->scsi = scsi_alloc_cd (ch, ci->device_emu_unit, true);
-               if (!ide->scsi) {
-                       write_log (_T("IDE: CD EMU unit %d failed to open\n"), ide->cd_unit_num);
-                       return NULL;
-               }
-               ide->cd_unit_num = ci->device_emu_unit;
-               ide->atapi = true;
-               ide->blocksize = 512;
-               gui_flicker_led (LED_CD, ch, -1);
-
-               write_log (_T("IDE%d CD %d\n"), ch, ide->cd_unit_num);
-
-       } else if (ci->type == UAEDEV_HDF) {
-               if (!hdf_hd_open (&ide->hdhfd))
-                       return NULL;
-               ide->blocksize = ide->hdhfd.hfd.ci.blocksize;
-               ide->lba48 = ide->hdhfd.size >= 128 * (uae_u64)0x40000000 ? 1 : 0;
-               gui_flicker_led (LED_HD, ch, -1);
-               ide->cd_unit_num = -1;
-
-               write_log (_T("IDE%d HD '%s', LCHS=%d/%d/%d. PCHS=%d/%d/%d %uM. LBA48=%d\n"),
-                       ch, ide->hdhfd.hfd.ci.rootdir,
-                       ide->hdhfd.cyls, ide->hdhfd.heads, ide->hdhfd.secspertrack,
-                       ide->hdhfd.hfd.ci.pcyls, ide->hdhfd.hfd.ci.pheads, ide->hdhfd.hfd.ci.psecs,
-                       (int)(ide->hdhfd.size / (1024 * 1024)), ide->lba48);
-
-       }
-       ide->regs.ide_status = 0;
-       ide->data_offset = 0;
-       ide->data_size = 0;
-       return ide;
+       if (ide_interrupt_check(idedrive, TOTAL_IDE * 2))
+               rethink_gayle ();
 }
 
 static int pcmcia_common_size, pcmcia_attrs_size;
@@ -2361,7 +1265,7 @@ static int freepcmcia (int reset)
                        pcmcia_sram->hfd.drive_empty = 1;
                }
        }
-       remode_ide_unit(PCMCIA_IDE_ID * 2);
+       remove_ide_unit(idedrive, PCMCIA_IDE_ID * 2);
        if (pcmcia_card)
                gayle_cs_change (GAYLE_CS_CCDET, 0);
        
@@ -2428,7 +1332,7 @@ static int initpcmcia (const TCHAR *path, int readonly, int type, int reset, str
        } else if (type == PCMCIA_IDE) {
 
                if (reset && path) {    
-                       add_ide_unit (PCMCIA_IDE_ID * 2, uci);
+                       add_ide_unit (idedrive, TOTAL_IDE * 2, PCMCIA_IDE_ID * 2, uci);
                }
 
                pcmcia_common_size = 0;
@@ -2671,19 +1575,8 @@ void gayle_map_pcmcia (void)
 
 void gayle_free_units (void)
 {
-       int i;
-
-       for (i = 0; i < TOTAL_IDE * 2; i++) {
-               struct ide_hdf *ide = idedrive[i];
-               if (ide) {
-                       if (ide->scsi) {
-                               scsi_free (ide->scsi);
-                       } else {
-                               hdf_hd_close (&ide->hdhfd);
-                       }
-                       memset (ide, 0, sizeof (struct ide_hdf));
-                       ide->cd_unit_num = -1;
-               }
+       for (int i = 0; i < TOTAL_IDE * 2; i++) {
+               remove_ide_unit(idedrive, i);
        }
        freepcmcia (1);
 }
@@ -2714,10 +1607,9 @@ int gayle_add_ide_unit (int ch, struct uaedev_config_info *ci)
 
        if (ch >= 2 * 2)
                return -1;
-       ide = add_ide_unit (ch, ci);
+       ide = add_ide_unit (idedrive, TOTAL_IDE * 2, ch, ci);
        if (ide == NULL)
                return 0;
-       ide->type = IDE_GAYLE;
        //dumphdf (&ide->hdhfd.hfd);
        return 1;
 }
@@ -2748,70 +1640,28 @@ int gayle_modify_pcmcia_ide_unit (struct uaedev_config_info *uci, int insert)
                return freepcmcia (0);
 }
 
-static void *ide_thread (void *null)
-{
-       for (;;) {
-               uae_u32 unit = read_comm_pipe_u32_blocking (&requests);
-               struct ide_hdf *ide;
-               if (gayle_thread_running == 0 || unit == 0xfffffff)
-                       break;
-               ide = idedrive[unit & 0x7f];
-               if (unit & 0x80)
-                       do_process_packet_command (ide);
-               else
-                       do_process_rw_command (ide);
-       }
-       gayle_thread_running = -1;
-       return 0;
-}
-
 static void initide (void)
 {
-       int i;
-
-       if (!gayle_thread_running) {
-               gayle_thread_running = 1;
-               init_comm_pipe (&requests, 100, 1);
-               uae_start_thread (_T("ide"), ide_thread, 0, NULL);
-       }
+       gayle_its.idetable = idedrive;
+       gayle_its.idetotal = TOTAL_IDE * 2;
+       start_ide_thread(&gayle_its);
+       alloc_ide_mem (idedrive, TOTAL_IDE * 2, &gayle_its);
 
-       alloc_ide_mem (idedrive, TOTAL_IDE * 2);
        if (isrestore ())
                return;
-       for (i = 0; i < TOTAL_IDE; i++) {
-               struct ide_hdf *ide;
-
-               ide = idedrive[i * 2 + 0];
-               ide->regs0 = &ide->regs;
-               ide->regs1 = &idedrive[i * 2 + 1]->regs;
-               ide->pair = idedrive[i * 2 + 1];
-
-               ide = idedrive[i * 2 + 1];
-               ide->regs1 = &ide->regs;
-               ide->regs0 = &idedrive[i * 2 + 0]->regs;
-               ide->pair = idedrive[i * 2 + 0];
-
-               reset_device (ide, true);
-       }
+       ide_initialize(idedrive, 0);
+       ide_initialize(idedrive, 1);
        ide_splitter = 0;
-       if (isdrive (idedrive[2]) || isdrive(idedrive[3])) {
+       if (ide_isdrive (idedrive[2]) || ide_isdrive(idedrive[3])) {
                ide_splitter = 1;
                write_log (_T("IDE splitter enabled\n"));
        }
-       for (i = 0; i < TOTAL_IDE * 2; i++)
-               idedrive[i]->num = i;
        gayle_irq = gayle_int = 0;
 }
 
 void gayle_free (void)
 {
-       if (gayle_thread_running > 0) {
-               gayle_thread_running = 0;
-               write_comm_pipe_u32 (&requests, 0xffffffff, 1);
-               while(gayle_thread_running == 0)
-                       sleep_millis (10);
-               gayle_thread_running = 0;
-       }
+       stop_ide_thread(&gayle_its);
 }
 
 void gayle_reset (int hardreset)
@@ -2846,8 +1696,6 @@ uae_u8 *restore_gayle (uae_u8 *src)
        gayle_cs = restore_u8 ();
        gayle_cs_mask = restore_u8 ();
        gayle_cfg = restore_u8 ();
-       ideregs[0].ide_error = 0;
-       ideregs[1].ide_error = 0;
        return src;
 }
 
@@ -2871,7 +1719,7 @@ uae_u8 *save_gayle (int *len, uae_u8 *dstptr)
        return dstbak;
 }
 
-uae_u8 *save_ide (int num, int *len, uae_u8 *dstptr)
+uae_u8 *save_gayle_ide (int num, int *len, uae_u8 *dstptr)
 {
        uae_u8 *dstbak, *dst;
        struct ide_hdf *ide;
@@ -2888,44 +1736,19 @@ uae_u8 *save_ide (int num, int *len, uae_u8 *dstptr)
        else
                dstbak = dst = xmalloc (uae_u8, 1000);
        save_u32 (num);
-       save_u64 (ide->hdhfd.size);
-       save_string (ide->hdhfd.hfd.ci.rootdir);
-       save_u32 (ide->hdhfd.hfd.ci.blocksize);
-       save_u32 (ide->hdhfd.hfd.ci.readonly);
-       save_u8 (ide->multiple_mode);
-       save_u32 (ide->hdhfd.cyls);
-       save_u32 (ide->hdhfd.heads);
-       save_u32 (ide->hdhfd.secspertrack);
-       save_u8 (ide->regs.ide_select);
-       save_u8 (ide->regs.ide_nsector);
-       save_u8 (ide->regs.ide_nsector2);
-       save_u8 (ide->regs.ide_sector);
-       save_u8 (ide->regs.ide_sector2);
-       save_u8 (ide->regs.ide_lcyl);
-       save_u8 (ide->regs.ide_lcyl2);
-       save_u8 (ide->regs.ide_hcyl);
-       save_u8 (ide->regs.ide_hcyl2);
-       save_u8 (ide->regs.ide_feat);
-       save_u8 (ide->regs.ide_feat2);
-       save_u8 (ide->regs.ide_error);
-       save_u8 (ide->regs.ide_devcon);
-       save_u64 (ide->hdhfd.hfd.virtual_size);
-       save_u32 (ide->hdhfd.hfd.ci.sectors);
-       save_u32 (ide->hdhfd.hfd.ci.surfaces);
-       save_u32 (ide->hdhfd.hfd.ci.reserved);
-       save_u32 (ide->hdhfd.hfd.ci.bootpri);
+       dst = ide_save_state(dst, ide);
        *len = dst - dstbak;
        return dstbak;
 }
 
-uae_u8 *restore_ide (uae_u8 *src)
+uae_u8 *restore_gayle_ide (uae_u8 *src)
 {
        int num, readonly, blocksize;
        uae_u64 size;
        TCHAR *path;
        struct ide_hdf *ide;
 
-       alloc_ide_mem (idedrive, TOTAL_IDE * 2);
+       alloc_ide_mem (idedrive, TOTAL_IDE * 2, NULL);
        num = restore_u32 ();
        ide = idedrive[num];
        size = restore_u64 ();
@@ -2933,28 +1756,7 @@ uae_u8 *restore_ide (uae_u8 *src)
        _tcscpy (ide->hdhfd.hfd.ci.rootdir, path);
        blocksize = restore_u32 ();
        readonly = restore_u32 ();
-       ide->multiple_mode = restore_u8 ();
-       ide->hdhfd.cyls = restore_u32 ();
-       ide->hdhfd.heads = restore_u32 ();
-       ide->hdhfd.secspertrack = restore_u32 ();
-       ide->regs.ide_select = restore_u8 ();
-       ide->regs.ide_nsector = restore_u8 ();
-       ide->regs.ide_sector = restore_u8 ();
-       ide->regs.ide_lcyl = restore_u8 ();
-       ide->regs.ide_hcyl = restore_u8 ();
-       ide->regs.ide_feat = restore_u8 ();
-       ide->regs.ide_nsector2 = restore_u8 ();
-       ide->regs.ide_sector2 = restore_u8 ();
-       ide->regs.ide_lcyl2 = restore_u8 ();
-       ide->regs.ide_hcyl2 = restore_u8 ();
-       ide->regs.ide_feat2 = restore_u8 ();
-       ide->regs.ide_error = restore_u8 ();
-       ide->regs.ide_devcon = restore_u8 ();
-       ide->hdhfd.hfd.virtual_size = restore_u64 ();
-       ide->hdhfd.hfd.ci.sectors = restore_u32 ();
-       ide->hdhfd.hfd.ci.surfaces = restore_u32 ();
-       ide->hdhfd.hfd.ci.reserved = restore_u32 ();
-       ide->hdhfd.hfd.ci.bootpri = restore_u32 ();
+       src = ide_restore_state(src, ide);
        if (ide->hdhfd.hfd.virtual_size)
                gayle_add_ide_unit (num, NULL);
        else
diff --git a/ide.cpp b/ide.cpp
new file mode 100644 (file)
index 0000000..d323d9d
--- /dev/null
+++ b/ide.cpp
@@ -0,0 +1,1219 @@
+/*
+* UAE - The Un*x Amiga Emulator
+*
+* IDE HD/ATAPI CD emulation
+*
+* (c) 2006 - 2015 Toni Wilen
+*/
+
+#define IDE_LOG 0
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "options.h"
+#include "blkdev.h"
+#include "filesys.h"
+#include "gui.h"
+#include "uae.h"
+#include "memory.h"
+#include "newcpu.h"
+#include "threaddep/thread.h"
+#include "debug.h"
+#include "savestate.h"
+#include "scsi.h"
+#include "ide.h"
+
+/* STATUS bits */
+#define IDE_STATUS_ERR 0x01            // 0
+#define IDE_STATUS_IDX 0x02            // 1
+#define IDE_STATUS_DRQ 0x08            // 3
+#define IDE_STATUS_DSC 0x10            // 4
+#define IDE_STATUS_DRDY 0x40   // 6
+#define IDE_STATUS_BSY 0x80            // 7
+#define ATAPI_STATUS_CHK IDE_STATUS_ERR
+/* ERROR bits */
+#define IDE_ERR_UNC 0x40
+#define IDE_ERR_MC 0x20
+#define IDE_ERR_IDNF 0x10
+#define IDE_ERR_MCR 0x08
+#define IDE_ERR_ABRT 0x04
+#define IDE_ERR_NM 0x02
+#define ATAPI_ERR_EOM 0x02
+#define ATAPI_ERR_ILI 0x01
+/* ATAPI interrupt reason (Sector Count) */
+#define ATAPI_IO 0x02
+#define ATAPI_CD 0x01
+
+#define ATAPI_MAX_TRANSFER 32768
+#define MAX_IDE_MULTIPLE_SECTORS 64
+
+static void ide_grow_buffer(struct ide_hdf *ide, int newsize)
+{
+       if (ide->secbuf_size >= newsize)
+               return;
+       uae_u8 *oldbuf = ide->secbuf;
+       int oldsize = ide->secbuf_size;
+       ide->secbuf_size = newsize + 16384;
+       if (oldsize)
+               write_log(_T("IDE%d buffer %d -> %d\n"), ide->num, oldsize, ide->secbuf_size);
+       ide->secbuf = xmalloc(uae_u8, ide->secbuf_size);
+       memcpy(ide->secbuf, oldbuf, oldsize);
+       xfree(oldbuf);
+}
+
+static void pw (struct ide_hdf *ide, int offset, uae_u16 w)
+{
+       if (ide->byteswap) {
+               ide->secbuf[offset * 2 + 1] = (uae_u8)w;
+               ide->secbuf[offset * 2 + 0] = w >> 8;
+       } else {
+               ide->secbuf[offset * 2 + 0] = (uae_u8)w;
+               ide->secbuf[offset * 2 + 1] = w >> 8;
+       }
+}
+
+static void ps (struct ide_hdf *ide, int offset, const TCHAR *src, int max)
+{
+       int i, len, swap;
+       char *s;
+
+       swap = ide->byteswap ? 0 : 1;
+       offset *= 2;
+       s = ua (src);
+       len = strlen (s);
+       for (i = 0; i < max; i++) {
+               char c = ' ';
+               if (i < len)
+                       c = s[i];
+               ide->secbuf[offset ^ swap] = c;
+               offset++;
+       }
+       xfree (s);
+}
+
+bool ide_isdrive (struct ide_hdf *ide)
+{
+       return ide && (ide->hdhfd.size != 0 || ide->atapi);
+}
+
+static void ide_interrupt (struct ide_hdf *ide)
+{
+       ide->regs.ide_status |= IDE_STATUS_BSY;
+       ide->regs.ide_status &= ~IDE_STATUS_DRQ;
+       ide->irq_delay = 2;
+}
+
+static void ide_fast_interrupt (struct ide_hdf *ide)
+{
+       ide->regs.ide_status |= IDE_STATUS_BSY;
+       ide->regs.ide_status &= ~IDE_STATUS_DRQ;
+       ide->irq_delay = 1;
+}
+
+static bool ide_interrupt_do (struct ide_hdf *ide)
+{
+       uae_u8 os = ide->regs.ide_status;
+       ide->regs.ide_status &= ~IDE_STATUS_DRQ;
+       if (ide->intdrq)
+               ide->regs.ide_status |= IDE_STATUS_DRQ;
+       ide->regs.ide_status &= ~IDE_STATUS_BSY;
+       if (IDE_LOG > 1)
+               write_log (_T("IDE INT %02X -> %02X\n"), os, ide->regs.ide_status);
+       ide->intdrq = false;
+       ide->irq_delay = 0;
+       if (ide->regs.ide_devcon & 2)
+               return false;
+       ide->irq = 1;
+       return true;
+}
+
+bool ide_interrupt_check(struct ide_hdf **idetable, int num)
+{
+       bool irq = false;
+       for (int i = 0; i < num; i++) {
+               struct ide_hdf *ide = idetable[i];
+               if (ide) {
+                       if (ide->irq_delay > 0) {
+                               ide->irq_delay--;
+                               if (ide->irq_delay == 0) {
+                                       ide_interrupt_do (ide);
+                               }
+                       }
+                       if (ide->irq && !(ide->regs.ide_devcon & 2))
+                               irq = true;
+               }
+       }
+       return irq;
+}
+
+static void ide_fail_err (struct ide_hdf *ide, uae_u8 err)
+{
+       ide->regs.ide_error |= err;
+       if (ide->ide_drv == 1 && !ide_isdrive (ide->pair)) {
+               ide->pair->regs.ide_status |= IDE_STATUS_ERR;
+       }
+       ide->regs.ide_status |= IDE_STATUS_ERR;
+       ide_interrupt (ide);
+}
+
+static void ide_fail (struct ide_hdf *ide)
+{
+       ide_fail_err (ide, IDE_ERR_ABRT);
+}
+
+static void ide_data_ready (struct ide_hdf *ide)
+{
+       memset (ide->secbuf, 0, ide->blocksize);
+       ide->data_offset = 0;
+       ide->data_size = ide->blocksize;
+       ide->data_multi = 1;
+       ide->intdrq = true;
+       ide_interrupt (ide);
+}
+
+static void ide_recalibrate (struct ide_hdf *ide)
+{
+       write_log (_T("IDE%d recalibrate\n"), ide->num);
+       ide->regs.ide_sector = 0;
+       ide->regs.ide_lcyl = ide->regs.ide_hcyl = 0;
+       ide_interrupt (ide);
+}
+
+static void ide_identify_drive (struct ide_hdf *ide)
+{
+       uae_u64 totalsecs;
+       int v;
+       uae_u8 *buf = ide->secbuf;
+       TCHAR tmp[100];
+       bool atapi = ide->atapi;
+
+       if (!ide_isdrive (ide)) {
+               ide_fail (ide);
+               return;
+       }
+       memset (buf, 0, ide->blocksize);
+       if (IDE_LOG > 0)
+               write_log (_T("IDE%d identify drive\n"), ide->num);
+       ide_data_ready (ide);
+       ide->direction = 0;
+       pw (ide, 0, atapi ? 0x85c0 : 1 << 6);
+       pw (ide, 1, ide->hdhfd.cyls_def);
+       pw (ide, 2, 0xc837);
+       pw (ide, 3, ide->hdhfd.heads_def);
+       pw (ide, 4, ide->blocksize * ide->hdhfd.secspertrack_def);
+       pw (ide, 5, ide->blocksize);
+       pw (ide, 6, ide->hdhfd.secspertrack_def);
+       ps (ide, 10, _T("68000"), 20); /* serial */
+       pw (ide, 20, 3);
+       pw (ide, 21, ide->blocksize);
+       pw (ide, 22, 4);
+       ps (ide, 23, _T("0.6"), 8); /* firmware revision */
+       if (ide->atapi)
+               _tcscpy (tmp, _T("UAE-ATAPI"));
+       else
+               _stprintf (tmp, _T("UAE-IDE %s"), ide->hdhfd.hfd.product_id);
+       ps (ide, 27, tmp, 40); /* model */
+       pw (ide, 47, MAX_IDE_MULTIPLE_SECTORS >> (ide->blocksize / 512 - 1)); /* max sectors in multiple mode */
+       pw (ide, 48, 1);
+       pw (ide, 49, (1 << 9) | (1 << 8)); /* LBA and DMA supported */
+       pw (ide, 51, 0x200); /* PIO cycles */
+       pw (ide, 52, 0x200); /* DMA cycles */
+       pw (ide, 53, 1 | 2 | 4);
+       pw (ide, 54, ide->hdhfd.cyls);
+       pw (ide, 55, ide->hdhfd.heads);
+       pw (ide, 56, ide->hdhfd.secspertrack);
+       totalsecs = ide->hdhfd.cyls * ide->hdhfd.heads * ide->hdhfd.secspertrack;
+       pw (ide, 57, (uae_u16)totalsecs);
+       pw (ide, 58, (uae_u16)(totalsecs >> 16));
+       v = ide->multiple_mode;
+       pw (ide, 59, (v > 0 ? 0x100 : 0) | v);
+       totalsecs = ide->blocksize ? ide->hdhfd.size / ide->blocksize : 0;
+       if (totalsecs > 0x0fffffff)
+               totalsecs = 0x0fffffff;
+       pw (ide, 60, (uae_u16)totalsecs);
+       pw (ide, 61, (uae_u16)(totalsecs >> 16));
+       pw (ide, 62, 0x0f);
+       pw (ide, 63, 0x0f);
+       pw (ide, 64, 0x03); /* PIO3 and PIO4 */
+       pw (ide, 65, 120); /* MDMA2 supported */
+       pw (ide, 66, 120);
+       pw (ide, 67, 120);
+       pw (ide, 68, 120);
+       pw (ide, 80, (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6)); /* ATA-1 to ATA-6 */
+       pw (ide, 81, 0x1c); /* ATA revision */
+       pw (ide, 82, (1 << 14) | (atapi ? 0x10 | 4 : 0)); /* NOP, ATAPI: PACKET and Removable media features supported */
+       pw (ide, 83, (1 << 14) | (1 << 13) | (1 << 12) | (ide->lba48 ? (1 << 10) : 0)); /* cache flushes, LBA 48 supported */
+       pw (ide, 84, 1 << 14);
+       pw (ide, 85, 1 << 14);
+       pw (ide, 86, (1 << 14) | (1 << 13) | (1 << 12) | (ide->lba48 ? (1 << 10) : 0)); /* cache flushes, LBA 48 enabled */
+       pw (ide, 87, 1 << 14);
+       pw (ide, 88, (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1) | (1 << 0)); /* UDMA modes */
+       pw (ide, 93, (1 << 14) | (1 << 13) | (1 << 0));
+       if (ide->lba48) {
+               totalsecs = ide->hdhfd.size / ide->blocksize;
+               pw (ide, 100, (uae_u16)(totalsecs >> 0));
+               pw (ide, 101, (uae_u16)(totalsecs >> 16));
+               pw (ide, 102, (uae_u16)(totalsecs >> 32));
+               pw (ide, 103, (uae_u16)(totalsecs >> 48));
+       }
+}
+
+static void set_signature (struct ide_hdf *ide)
+{
+       if (ide->atapi) {
+               ide->regs.ide_sector = 1;
+               ide->regs.ide_nsector = 1;
+               ide->regs.ide_lcyl = 0x14;
+               ide->regs.ide_hcyl = 0xeb;
+               ide->regs.ide_status = 0;
+               ide->atapi_drdy = false;
+       } else {
+               ide->regs.ide_nsector = 1;
+               ide->regs.ide_sector = 1;
+               ide->regs.ide_lcyl = 0;
+               ide->regs.ide_hcyl = 0;
+               ide->regs.ide_status = 0;
+       }
+       ide->regs.ide_error = 0x01; // device ok
+       ide->packet_state = 0;
+}
+
+static void reset_device (struct ide_hdf *ide, bool both)
+{
+       set_signature (ide);
+       if (both)
+               set_signature (ide->pair);
+}
+
+static void ide_execute_drive_diagnostics (struct ide_hdf *ide, bool irq)
+{
+       reset_device (ide, irq);
+       if (irq)
+               ide_interrupt (ide);
+       else
+               ide->regs.ide_status &= ~IDE_STATUS_BSY;
+}
+
+static void ide_initialize_drive_parameters (struct ide_hdf *ide)
+{
+       if (ide->hdhfd.size) {
+               ide->hdhfd.secspertrack = ide->regs.ide_nsector == 0 ? 256 : ide->regs.ide_nsector;
+               ide->hdhfd.heads = (ide->regs.ide_select & 15) + 1;
+               if (ide->hdhfd.hfd.ci.pcyls)
+                       ide->hdhfd.cyls = ide->hdhfd.hfd.ci.pcyls;
+               else
+                       ide->hdhfd.cyls = (ide->hdhfd.size / ide->blocksize) / (ide->hdhfd.secspertrack * ide->hdhfd.heads);
+               if (ide->hdhfd.heads * ide->hdhfd.cyls * ide->hdhfd.secspertrack > 16515072 || ide->lba48) {
+                       if (ide->hdhfd.hfd.ci.pcyls)
+                               ide->hdhfd.cyls = ide->hdhfd.hfd.ci.pcyls;
+                       else
+                               ide->hdhfd.cyls = ide->hdhfd.cyls_def;
+                       ide->hdhfd.heads = ide->hdhfd.heads_def;
+                       ide->hdhfd.secspertrack = ide->hdhfd.secspertrack_def;
+               }
+       } else {
+               ide->regs.ide_error |= IDE_ERR_ABRT;
+               ide->regs.ide_status |= IDE_STATUS_ERR;
+       }
+       write_log (_T("IDE%d initialize drive parameters, CYL=%d,SPT=%d,HEAD=%d\n"),
+               ide->num, ide->hdhfd.cyls, ide->hdhfd.secspertrack, ide->hdhfd.heads);
+       ide_interrupt (ide);
+}
+
+static void ide_set_multiple_mode (struct ide_hdf *ide)
+{
+       write_log (_T("IDE%d drive multiple mode = %d\n"), ide->num, ide->regs.ide_nsector);
+       ide->multiple_mode = ide->regs.ide_nsector;
+       ide_interrupt (ide);
+}
+
+static void ide_set_features (struct ide_hdf *ide)
+{
+       int type = ide->regs.ide_nsector >> 3;
+       int mode = ide->regs.ide_nsector & 7;
+
+       write_log (_T("IDE%d set features %02X (%02X)\n"), ide->num, ide->regs.ide_feat, ide->regs.ide_nsector);
+       ide_fail (ide);
+}
+
+static void get_lbachs (struct ide_hdf *ide, uae_u64 *lbap, unsigned int *cyl, unsigned int *head, unsigned int *sec)
+{
+       if (ide->lba48 && ide->lba48cmd && (ide->regs.ide_select & 0x40)) {
+               uae_u64 lba;
+               lba = (ide->regs.ide_hcyl << 16) | (ide->regs.ide_lcyl << 8) | ide->regs.ide_sector;
+               lba |= ((ide->regs.ide_hcyl2 << 16) | (ide->regs.ide_lcyl2 << 8) | ide->regs.ide_sector2) << 24;
+               *lbap = lba;
+       } else {
+               if (ide->regs.ide_select & 0x40) {
+                       *lbap = ((ide->regs.ide_select & 15) << 24) | (ide->regs.ide_hcyl << 16) | (ide->regs.ide_lcyl << 8) | ide->regs.ide_sector;
+               } else {
+                       *cyl = (ide->regs.ide_hcyl << 8) | ide->regs.ide_lcyl;
+                       *head = ide->regs.ide_select & 15;
+                       *sec = ide->regs.ide_sector;
+                       *lbap = (((*cyl) * ide->hdhfd.heads + (*head)) * ide->hdhfd.secspertrack) + (*sec) - 1;
+               }
+       }
+}
+
+static int get_nsec (struct ide_hdf *ide)
+{
+       if (ide->lba48 && ide->lba48cmd)
+               return (ide->regs.ide_nsector == 0 && ide->regs.ide_nsector2 == 0) ? 65536 : (ide->regs.ide_nsector2 * 256 + ide->regs.ide_nsector);
+       else
+               return ide->regs.ide_nsector == 0 ? 256 : ide->regs.ide_nsector;
+}
+static int dec_nsec (struct ide_hdf *ide, int v)
+{
+       if (ide->lba48 && ide->lba48cmd) {
+               uae_u16 nsec;
+               nsec = ide->regs.ide_nsector2 * 256 + ide->regs.ide_nsector;
+               ide->regs.ide_nsector -= v;
+               ide->regs.ide_nsector2 = nsec >> 8;
+               ide->regs.ide_nsector = nsec & 0xff;
+               return (ide->regs.ide_nsector2 << 8) | ide->regs.ide_nsector;
+       } else {
+               ide->regs.ide_nsector -= v;
+               return ide->regs.ide_nsector;
+       }
+}
+
+static void put_lbachs (struct ide_hdf *ide, uae_u64 lba, unsigned int cyl, unsigned int head, unsigned int sec, unsigned int inc)
+{
+       if (ide->lba48 && ide->lba48cmd) {
+               lba += inc;
+               ide->regs.ide_hcyl = (lba >> 16) & 0xff;
+               ide->regs.ide_lcyl = (lba >> 8) & 0xff;
+               ide->regs.ide_sector = lba & 0xff;
+               lba >>= 24;
+               ide->regs.ide_hcyl2 = (lba >> 16) & 0xff;
+               ide->regs.ide_lcyl2 = (lba >> 8) & 0xff;
+               ide->regs.ide_sector2 = lba & 0xff;
+       } else {
+               if (ide->regs.ide_select & 0x40) {
+                       lba += inc;
+                       ide->regs.ide_select &= ~15;
+                       ide->regs.ide_select |= (lba >> 24) & 15;
+                       ide->regs.ide_hcyl = (lba >> 16) & 0xff;
+                       ide->regs.ide_lcyl = (lba >> 8) & 0xff;
+                       ide->regs.ide_sector = lba & 0xff;
+               } else {
+                       sec += inc;
+                       while (sec >= ide->hdhfd.secspertrack) {
+                               sec -= ide->hdhfd.secspertrack;
+                               head++;
+                               if (head >= ide->hdhfd.heads) {
+                                       head -= ide->hdhfd.heads;
+                                       cyl++;
+                               }
+                       }
+                       ide->regs.ide_select &= ~15;
+                       ide->regs.ide_select |= head;
+                       ide->regs.ide_sector = sec;
+                       ide->regs.ide_hcyl = cyl >> 8;
+                       ide->regs.ide_lcyl = (uae_u8)cyl;
+               }
+       }
+}
+
+static void check_maxtransfer (struct ide_hdf *ide, int state)
+{
+       if (state == 1) {
+               // transfer was started
+               if (ide->maxtransferstate < 2 && ide->regs.ide_nsector == 0) {
+                       ide->maxtransferstate = 1;
+               } else if (ide->maxtransferstate == 2) {
+                       // second transfer was started (part of split)
+                       write_log (_T("IDE maxtransfer check detected split >256 block transfer\n"));
+                       ide->maxtransferstate = 0;
+               } else {
+                       ide->maxtransferstate = 0;
+               }
+       } else if (state == 2) {
+               // address was read
+               if (ide->maxtransferstate == 1)
+                       ide->maxtransferstate++;
+               else
+                       ide->maxtransferstate = 0;
+       }
+}
+
+static void setdrq (struct ide_hdf *ide)
+{
+       ide->regs.ide_status |= IDE_STATUS_DRQ;
+       ide->regs.ide_status &= ~IDE_STATUS_BSY;
+}
+static void setbsy (struct ide_hdf *ide)
+{
+       ide->regs.ide_status |= IDE_STATUS_BSY;
+       ide->regs.ide_status &= ~IDE_STATUS_DRQ;
+}
+
+static void process_rw_command (struct ide_hdf *ide)
+{
+       setbsy (ide);
+       write_comm_pipe_u32 (&ide->its->requests, ide->num, 1);
+}
+static void process_packet_command (struct ide_hdf *ide)
+{
+       setbsy (ide);
+       write_comm_pipe_u32 (&ide->its->requests, ide->num | 0x80, 1);
+}
+
+static void atapi_data_done (struct ide_hdf *ide)
+{
+       ide->regs.ide_nsector = ATAPI_IO | ATAPI_CD;
+       ide->regs.ide_status = IDE_STATUS_DRDY;
+       ide->data_size = 0;
+       ide->packet_data_offset = 0;
+       ide->data_offset = 0;
+}
+
+static bool atapi_set_size (struct ide_hdf *ide)
+{
+       int size;
+       size = ide->data_size;
+       ide->data_offset = 0;
+       if (!size) {
+               ide->packet_state = 0;
+               ide->packet_transfer_size = 0;
+               return false;
+       }
+       if (ide->packet_state == 2) {
+               if (size > ide->packet_data_size)
+                       size = ide->packet_data_size;
+               if (size > ATAPI_MAX_TRANSFER)
+                       size = ATAPI_MAX_TRANSFER;
+               ide->packet_transfer_size = size & ~1;
+               ide->regs.ide_lcyl = size & 0xff;
+               ide->regs.ide_hcyl = size >> 8;
+       } else {
+               ide->packet_transfer_size = 12;
+       }
+       if (IDE_LOG > 1)
+               write_log (_T("ATAPI data transfer %d/%d bytes\n"), ide->packet_transfer_size, ide->data_size);
+       return true;
+}
+
+static void atapi_packet (struct ide_hdf *ide)
+{
+       ide->packet_data_offset = 0;
+       ide->packet_data_size = (ide->regs.ide_hcyl << 8) | ide->regs.ide_lcyl;
+       if (ide->packet_data_size == 65535)
+               ide->packet_data_size = 65534;
+       ide->data_size = 12;
+       if (IDE_LOG > 0)
+               write_log (_T("ATAPI packet command. Data size = %d\n"), ide->packet_data_size);
+       ide->packet_state = 1;
+       ide->data_multi = 1;
+       ide->data_offset = 0;
+       ide->regs.ide_nsector = ATAPI_CD;
+       ide->regs.ide_error = 0;
+       if (atapi_set_size (ide))
+               setdrq (ide);
+}
+
+static void do_packet_command (struct ide_hdf *ide)
+{
+       memcpy (ide->scsi->cmd, ide->secbuf, 12);
+       ide->scsi->cmd_len = 12;
+       if (IDE_LOG > 0) {
+               uae_u8 *c = ide->scsi->cmd;
+               write_log (_T("ATASCSI %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x\n"),
+                       c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8], c[9], c[10], c[11]);
+       }
+       ide->direction = 0;
+       scsi_emulate_analyze (ide->scsi);
+       if (ide->scsi->direction <= 0) {
+               // data in
+               scsi_emulate_cmd (ide->scsi);
+               ide->data_size = ide->scsi->data_len;
+               ide->regs.ide_status = 0;
+               if (ide->scsi->status) {
+                       // error
+                       ide->regs.ide_error = (ide->scsi->sense[2] << 4) | 4;
+                       atapi_data_done (ide);
+                       ide->regs.ide_status |= ATAPI_STATUS_CHK;
+                       atapi_set_size (ide);
+                       return;
+               } else if (ide->scsi->data_len) {
+                       // data in
+                       ide_grow_buffer(ide, ide->scsi->data_len);
+                       memcpy (ide->secbuf, ide->scsi->buffer, ide->scsi->data_len);
+                       ide->regs.ide_nsector = ATAPI_IO;
+               } else {
+                       // no data
+                       atapi_data_done (ide);
+               }
+       } else {
+               // data out
+               ide->direction = 1;
+               ide->regs.ide_nsector = 0;
+               ide->data_size = ide->scsi->data_len;
+       }
+       ide->packet_state = 2; // data phase
+       if (atapi_set_size (ide))
+               ide->intdrq = true;
+}
+
+static void do_process_packet_command (struct ide_hdf *ide)
+{
+       if (ide->packet_state == 1) {
+               do_packet_command (ide);
+       } else {
+               ide->packet_data_offset += ide->packet_transfer_size;
+               if (!ide->direction) {
+                       // data still remaining, next transfer
+                       if (atapi_set_size (ide))
+                               ide->intdrq = true;
+               } else {
+                       if (atapi_set_size (ide)) {
+                               ide->intdrq = true;
+                       } else {
+                               memcpy (&ide->scsi->buffer, ide->secbuf, ide->data_size);
+                               ide->scsi->data_len = ide->data_size;
+                               scsi_emulate_cmd (ide->scsi);
+                               if (IDE_LOG > 1)
+                                       write_log (_T("IDE%d ATAPI write finished, %d bytes\n"), ide->num, ide->data_size);
+                       }
+               }
+       }
+       ide_fast_interrupt (ide);
+}
+
+static void do_process_rw_command (struct ide_hdf *ide)
+{
+       unsigned int cyl, head, sec, nsec;
+       uae_u64 lba;
+       bool last;
+
+       ide->data_offset = 0;
+       get_lbachs (ide, &lba, &cyl, &head, &sec);
+       nsec = get_nsec (ide);
+       if (IDE_LOG > 1)
+               write_log (_T("IDE%d off=%d, nsec=%d (%d) lba48=%d\n"), ide->num, (uae_u32)lba, nsec, ide->multiple_mode, ide->lba48 + ide->lba48cmd);
+       if (nsec * ide->blocksize > ide->hdhfd.size - lba * ide->blocksize) {
+               nsec = (ide->hdhfd.size - lba * ide->blocksize) / ide->blocksize;
+               if (IDE_LOG > 1)
+                       write_log (_T("IDE%d nsec changed to %d\n"), ide->num, nsec);
+       }
+       if (nsec <= 0) {
+               ide_data_ready (ide);
+               ide_fail_err (ide, IDE_ERR_IDNF);
+               return;
+       }
+       if (nsec > ide->data_multi)
+               nsec = ide->data_multi;
+
+       ide_grow_buffer(ide, nsec * ide->blocksize);
+       if (ide->direction) {
+               hdf_write (&ide->hdhfd.hfd, ide->secbuf, lba * ide->blocksize, nsec * ide->blocksize);
+               if (IDE_LOG > 1)
+                       write_log (_T("IDE%d write, %d bytes written\n"), ide->num, nsec * ide->blocksize);
+       } else {
+               hdf_read (&ide->hdhfd.hfd, ide->secbuf, lba * ide->blocksize, nsec * ide->blocksize);
+               if (IDE_LOG > 1)
+                       write_log (_T("IDE%d read, read %d bytes\n"), ide->num, nsec * ide->blocksize);
+       }
+       ide->intdrq = true;
+       last = dec_nsec (ide, nsec) == 0;
+       put_lbachs (ide, lba, cyl, head, sec, last ? nsec - 1 : nsec);
+       if (last && ide->direction) {
+               ide->intdrq = false;
+               if (IDE_LOG > 1)
+                       write_log (_T("IDE%d write finished\n"), ide->num);
+       }
+       ide_fast_interrupt (ide);
+}
+
+static void ide_read_sectors (struct ide_hdf *ide, int flags)
+{
+       unsigned int cyl, head, sec, nsec;
+       uae_u64 lba;
+       int multi = flags & 1;
+
+       ide->lba48cmd = (flags & 2) != 0;
+       if (multi && ide->multiple_mode == 0) {
+               ide_fail (ide);
+               return;
+       }
+       check_maxtransfer (ide, 1);
+       gui_flicker_led (LED_HD, ide->num, 1);
+       nsec = get_nsec (ide);
+       get_lbachs (ide, &lba, &cyl, &head, &sec);
+       if (lba * ide->blocksize >= ide->hdhfd.size) {
+               ide_data_ready (ide);
+               ide_fail_err (ide, IDE_ERR_IDNF);
+               return;
+       }
+       if (IDE_LOG > 0)
+               write_log (_T("IDE%d read off=%d, sec=%d (%d) lba48=%d\n"), ide->num, (uae_u32)lba, nsec, ide->multiple_mode, ide->lba48 + ide->lba48cmd);
+       ide->data_multi = multi ? ide->multiple_mode : 1;
+       ide->data_offset = 0;
+       ide->data_size = nsec * ide->blocksize;
+       ide->direction = 0;
+       // read start: preload sector(s), then trigger interrupt.
+       process_rw_command (ide);
+}
+
+static void ide_write_sectors (struct ide_hdf *ide, int flags)
+{
+       unsigned int cyl, head, sec, nsec;
+       uae_u64 lba;
+       int multi = flags & 1;
+
+       ide->lba48cmd = (flags & 2) != 0;
+       if (multi && ide->multiple_mode == 0) {
+               ide_fail (ide);
+               return;
+       }
+       check_maxtransfer (ide, 1);
+       gui_flicker_led (LED_HD, ide->num, 2);
+       nsec = get_nsec (ide);
+       get_lbachs (ide, &lba, &cyl, &head, &sec);
+       if (lba * ide->blocksize >= ide->hdhfd.size) {
+               ide_data_ready (ide);
+               ide_fail_err (ide, IDE_ERR_IDNF);
+               return;
+       }
+       if (IDE_LOG > 0)
+               write_log (_T("IDE%d write off=%d, sec=%d (%d) lba48=%d\n"), ide->num, (uae_u32)lba, nsec, ide->multiple_mode, ide->lba48 + ide->lba48cmd);
+       if (nsec * ide->blocksize > ide->hdhfd.size - lba * ide->blocksize)
+               nsec = (ide->hdhfd.size - lba * ide->blocksize) / ide->blocksize;
+       if (nsec <= 0) {
+               ide_data_ready (ide);
+               ide_fail_err (ide, IDE_ERR_IDNF);
+               return;
+       }
+       ide->data_multi = multi ? ide->multiple_mode : 1;
+       ide->data_offset = 0;
+       ide->data_size = nsec * ide->blocksize;
+       ide->direction = 1;
+       // write start: set DRQ and clear BSY. No interrupt.
+       ide->regs.ide_status |= IDE_STATUS_DRQ;
+       ide->regs.ide_status &= ~IDE_STATUS_BSY;
+}
+
+static void ide_do_command (struct ide_hdf *ide, uae_u8 cmd)
+{
+       int lba48 = ide->lba48;
+
+       if (IDE_LOG > 1)
+               write_log (_T("**** IDE%d command %02X\n"), ide->num, cmd);
+       ide->regs.ide_status &= ~ (IDE_STATUS_DRDY | IDE_STATUS_DRQ | IDE_STATUS_ERR);
+       ide->regs.ide_error = 0;
+       ide->lba48cmd = false;
+
+       if (ide->atapi) {
+
+               gui_flicker_led (LED_CD, ide->num, 1);
+               ide->atapi_drdy = true;
+               if (cmd == 0x00) { /* nop */
+                       ide_interrupt (ide);
+               } else if (cmd == 0x08) { /* device reset */
+                       ide_execute_drive_diagnostics (ide, true);
+               } else if (cmd == 0xa1) { /* identify packet device */
+                       ide_identify_drive (ide);
+               } else if (cmd == 0xa0) { /* packet */
+                       atapi_packet (ide);
+               } else if (cmd == 0x90) { /* execute drive diagnostics */
+                       ide_execute_drive_diagnostics (ide, true);
+               } else {
+                       ide_execute_drive_diagnostics (ide, false);
+                       ide->atapi_drdy = false;
+                       ide_fail (ide);
+                       write_log (_T("IDE%d: unknown ATAPI command 0x%02x\n"), ide->num, cmd);
+               }
+
+       } else {
+
+               if (cmd == 0x10) { /* recalibrate */
+                       ide_recalibrate (ide);
+               } else if (cmd == 0xec) { /* identify drive */
+                       ide_identify_drive (ide);
+               } else if (cmd == 0x90) { /* execute drive diagnostics */
+                       ide_execute_drive_diagnostics (ide, true);
+               } else if (cmd == 0x91) { /* initialize drive parameters */
+                       ide_initialize_drive_parameters (ide);
+               } else if (cmd == 0xc6) { /* set multiple mode */
+                       ide_set_multiple_mode (ide);
+               } else if (cmd == 0x20 || cmd == 0x21) { /* read sectors */
+                       ide_read_sectors (ide, 0);
+               } else if (cmd == 0x24 && lba48) { /* read sectors ext */
+                       ide_read_sectors (ide, 2);
+               } else if (cmd == 0xc4) { /* read multiple */
+                       ide_read_sectors (ide, 1);
+               } else if (cmd == 0x29 && lba48) { /* read multiple ext */
+                       ide_read_sectors (ide, 1|2);
+               } else if (cmd == 0x30 || cmd == 0x31) { /* write sectors */
+                       ide_write_sectors (ide, 0);
+               } else if (cmd == 0x34 && lba48) { /* write sectors ext */
+                       ide_write_sectors (ide, 2);
+               } else if (cmd == 0xc5) { /* write multiple */
+                       ide_write_sectors (ide, 1);
+               } else if (cmd == 0x39 && lba48) { /* write multiple ext */
+                       ide_write_sectors (ide, 1|2);
+               } else if (cmd == 0x50) { /* format track (nop) */
+                       ide_interrupt (ide);
+               } else if (cmd == 0xef) { /* set features  */
+                       ide_set_features (ide);
+               } else if (cmd == 0x00) { /* nop */
+                       ide_fail (ide);
+               } else if (cmd == 0xe0 || cmd == 0xe1 || cmd == 0xe7 || cmd == 0xea) { /* standby now/idle/flush cache/flush cache ext */
+                       ide_interrupt (ide);
+               } else if (cmd == 0xe5) { /* check power mode */
+                       ide->regs.ide_nsector = 0xff;
+                       ide_interrupt (ide);
+               } else {
+                       ide_fail (ide);
+                       write_log (_T("IDE%d: unknown ATA command 0x%02x\n"), ide->num, cmd);
+               }
+       }
+}
+
+uae_u16 ide_get_data (struct ide_hdf *ide)
+{
+       bool irq = false;
+       uae_u16 v;
+
+       if (IDE_LOG > 4)
+               write_log (_T("IDE%d DATA read\n"), ide->num);
+       if (ide->data_size == 0) {
+               if (IDE_LOG > 0)
+                       write_log (_T("IDE%d DATA but no data left!? %02X PC=%08X\n"), ide->num, ide->regs.ide_status, m68k_getpc ());
+               if (!ide_isdrive (ide))
+                       return 0xffff;
+               return 0;
+       }
+       if (ide->packet_state) {
+               v = ide->secbuf[ide->packet_data_offset + ide->data_offset + 1] | (ide->secbuf[ide->packet_data_offset + ide->data_offset + 0] << 8);
+               ide->data_offset += 2;
+               if (ide->data_size < 0)
+                       ide->data_size += 2;
+               else
+                       ide->data_size -= 2;
+               if (ide->data_offset == ide->packet_transfer_size) {
+                       if (IDE_LOG > 1)
+                               write_log (_T("IDE%d ATAPI partial read finished, %d bytes remaining\n"), ide->num, ide->data_size);
+                       if (ide->data_size == 0) {
+                               ide->packet_state = 0;
+                               atapi_data_done (ide);
+                               if (IDE_LOG > 1)
+                                       write_log (_T("IDE%d ATAPI read finished, %d bytes\n"), ide->num, ide->packet_data_offset + ide->data_offset);
+                               irq = true;
+                       } else {
+                               process_packet_command (ide);
+                       }
+               }
+       } else {
+               v = ide->secbuf[ide->data_offset + 1] | (ide->secbuf[ide->data_offset + 0] << 8);
+               ide->data_offset += 2;
+               if (ide->data_size < 0) {
+                       ide->data_size += 2;
+               } else {
+                       ide->data_size -= 2;
+                       if (((ide->data_offset % ide->blocksize) == 0) && ((ide->data_offset / ide->blocksize) % ide->data_multi) == 0) {
+                               if (ide->data_size)
+                                       process_rw_command (ide);
+                       }
+               }
+               if (ide->data_size == 0) {
+                       if (!(ide->regs.ide_status & IDE_STATUS_DRQ)) {
+                               write_log (_T("IDE%d read finished but DRQ was not active?\n"), ide->num);
+                       }
+                       ide->regs.ide_status &= ~IDE_STATUS_DRQ;
+                       if (IDE_LOG > 1)
+                               write_log (_T("IDE%d read finished\n"), ide->num);
+               }
+       }
+       if (irq)
+               ide_fast_interrupt (ide);
+       return v;
+}
+
+void ide_put_data (struct ide_hdf *ide, uae_u16 v)
+{
+       if (IDE_LOG > 4)
+               write_log (_T("IDE%d DATA write %04x %d/%d\n"), ide->num, v, ide->data_offset, ide->data_size);
+       if (ide->data_size == 0) {
+               if (IDE_LOG > 0)
+                       write_log (_T("IDE%d DATA write without request!? %02X PC=%08X\n"), ide->num, ide->regs.ide_status, m68k_getpc ());
+               return;
+       }
+       ide_grow_buffer(ide, ide->packet_data_offset + ide->data_offset + 2);
+       ide->secbuf[ide->packet_data_offset + ide->data_offset + 1] = v & 0xff;
+       ide->secbuf[ide->packet_data_offset + ide->data_offset + 0] = v >> 8;
+       ide->data_offset += 2;
+       ide->data_size -= 2;
+       if (ide->packet_state) {
+               if (ide->data_offset == ide->packet_transfer_size) {
+                       if (IDE_LOG > 0) {
+                               uae_u16 v = (ide->regs.ide_hcyl << 8) | ide->regs.ide_lcyl;
+                               write_log (_T("Data size after command received = %d (%d)\n"), v, ide->packet_data_size);
+                       }
+                       process_packet_command (ide);
+               }
+       } else {
+               if (ide->data_size == 0) {
+                       process_rw_command (ide);
+               } else if (((ide->data_offset % ide->blocksize) == 0) && ((ide->data_offset / ide->blocksize) % ide->data_multi) == 0) {
+                       process_rw_command (ide);
+               }
+       }
+}
+
+uae_u32 ide_read_reg (struct ide_hdf *ide, int ide_reg)
+{
+       uae_u8 v = 0;
+       bool isdrv = ide_isdrive (ide);
+
+       if (!ide)
+               goto end;
+
+       if (ide->regs.ide_status & IDE_STATUS_BSY)
+               ide_reg = IDE_STATUS;
+       if (!ide_isdrive (ide)) {
+               if (ide_reg == IDE_STATUS && ide->pair->irq)
+                       ide->pair->irq = 0;
+               if (ide_isdrive (ide->pair))
+                       v = 0x00;
+               else
+                       v = 0xff;
+               goto end;
+       }
+
+       switch (ide_reg)
+       {
+       case IDE_SECONDARY:
+       case IDE_SECONDARY + 1:
+       case IDE_SECONDARY + 2:
+       case IDE_SECONDARY + 3:
+       case IDE_SECONDARY + 4:
+       case IDE_SECONDARY + 5:
+               v = 0xff;
+               break;
+       case IDE_DRVADDR:
+               v = ((ide->ide_drv ? 2 : 1) | ((ide->regs.ide_select & 15) << 2)) ^ 0xff;
+               break;
+       case IDE_DATA:
+               break;
+       case IDE_ERROR:
+               v = ide->regs.ide_error;
+               break;
+       case IDE_NSECTOR:
+               if (isdrv) {
+                       if (ide->regs.ide_devcon & 0x80)
+                               v = ide->regs.ide_nsector2;
+                       else
+                               v = ide->regs.ide_nsector;
+               }
+               break;
+       case IDE_SECTOR:
+               if (isdrv) {
+                       if (ide->regs.ide_devcon & 0x80)
+                               v = ide->regs.ide_sector2;
+                       else
+                               v = ide->regs.ide_sector;
+                       check_maxtransfer (ide, 2);
+               }
+               break;
+       case IDE_LCYL:
+               if (isdrv) {
+                       if (ide->regs.ide_devcon & 0x80)
+                               v = ide->regs.ide_lcyl2;
+                       else
+                               v = ide->regs.ide_lcyl;
+               }
+               break;
+       case IDE_HCYL:
+               if (isdrv) {
+                       if (ide->regs.ide_devcon & 0x80)
+                               v = ide->regs.ide_hcyl2;
+                       else
+                               v = ide->regs.ide_hcyl;
+               }
+               break;
+       case IDE_SELECT:
+               v = ide->regs.ide_select;
+               break;
+       case IDE_STATUS:
+               ide->irq = 0;
+               /* fall through */
+       case IDE_DEVCON: /* ALTSTATUS when reading */
+               if (!isdrv) {
+                       v = 0;
+                       if (ide->regs.ide_error)
+                               v |= IDE_STATUS_ERR;
+               } else {
+                       v = ide->regs.ide_status;
+                       if (!ide->atapi || (ide->atapi && ide->atapi_drdy))
+                               v |= IDE_STATUS_DRDY | IDE_STATUS_DSC;
+               }
+               break;
+       }
+end:
+       if (IDE_LOG > 2 && ide_reg > 0 && (1 || ide->num > 0))
+               write_log (_T("IDE%d GET register %d->%02X (%08X)\n"), ide->num, ide_reg, (uae_u32)v & 0xff, m68k_getpc ());
+       return v;
+}
+
+void ide_write_reg (struct ide_hdf *ide, int ide_reg, uae_u32 val)
+{
+       if (!ide)
+               return;
+       
+       ide->regs1->ide_devcon &= ~0x80; /* clear HOB */
+       ide->regs0->ide_devcon &= ~0x80; /* clear HOB */
+       if (IDE_LOG > 2 && ide_reg > 0 && (1 || ide->num > 0))
+               write_log (_T("IDE%d PUT register %d=%02X (%08X)\n"), ide->num, ide_reg, (uae_u32)val & 0xff, m68k_getpc ());
+
+       switch (ide_reg)
+       {
+       case IDE_DRVADDR:
+               break;
+       case IDE_DEVCON:
+               if ((ide->regs.ide_devcon & 4) == 0 && (val & 4) != 0) {
+                       reset_device (ide, true);
+                       if (IDE_LOG > 1)
+                               write_log (_T("IDE%d: SRST\n"), ide->num);
+               }
+               ide->regs0->ide_devcon = val;
+               ide->regs1->ide_devcon = val;
+               break;
+       case IDE_DATA:
+               break;
+       case IDE_ERROR:
+               ide->regs0->ide_feat2 = ide->regs0->ide_feat;
+               ide->regs0->ide_feat = val;
+               ide->regs1->ide_feat2 = ide->regs1->ide_feat;
+               ide->regs1->ide_feat = val;
+               break;
+       case IDE_NSECTOR:
+               ide->regs0->ide_nsector2 = ide->regs0->ide_nsector;
+               ide->regs0->ide_nsector = val;
+               ide->regs1->ide_nsector2 = ide->regs1->ide_nsector;
+               ide->regs1->ide_nsector = val;
+               break;
+       case IDE_SECTOR:
+               ide->regs0->ide_sector2 = ide->regs0->ide_sector;
+               ide->regs0->ide_sector = val;
+               ide->regs1->ide_sector2 = ide->regs1->ide_sector;
+               ide->regs1->ide_sector = val;
+               break;
+       case IDE_LCYL:
+               ide->regs0->ide_lcyl2 = ide->regs0->ide_lcyl;
+               ide->regs0->ide_lcyl = val;
+               ide->regs1->ide_lcyl2 = ide->regs1->ide_lcyl;
+               ide->regs1->ide_lcyl = val;
+               break;
+       case IDE_HCYL:
+               ide->regs0->ide_hcyl2 = ide->regs0->ide_hcyl;
+               ide->regs0->ide_hcyl = val;
+               ide->regs1->ide_hcyl2 = ide->regs1->ide_hcyl;
+               ide->regs1->ide_hcyl = val;
+               break;
+       case IDE_SELECT:
+               ide->regs0->ide_select = val;
+               ide->regs1->ide_select = val;
+#if IDE_LOG > 2
+               if (ide->ide_drv != (val & 0x10) ? 1 : 0)
+                       write_log (_T("DRIVE=%d\n"), (val & 0x10) ? 1 : 0);
+#endif
+               ide->pair->ide_drv = ide->ide_drv = (val & 0x10) ? 1 : 0;
+               break;
+       case IDE_STATUS:
+               ide->irq = 0;
+               if (ide_isdrive (ide)) {
+                       ide->regs.ide_status |= IDE_STATUS_BSY;
+                       ide_do_command (ide, val);
+               }
+               break;
+       }
+}
+
+static void *ide_thread (void *idedata)
+{
+       struct ide_thread_state *its = (struct ide_thread_state*)idedata;
+       for (;;) {
+               uae_u32 unit = read_comm_pipe_u32_blocking (&its->requests);
+               struct ide_hdf *ide;
+               if (its->state == 0 || unit == 0xfffffff)
+                       break;
+               ide = its->idetable[unit & 0x7f];
+               if (unit & 0x80)
+                       do_process_packet_command (ide);
+               else
+                       do_process_rw_command (ide);
+       }
+       its->state = -1;
+       return 0;
+}
+
+void start_ide_thread(struct ide_thread_state *its)
+{
+       if (!its->state) {
+               its->state = 1;
+               init_comm_pipe (&its->requests, 100, 1);
+               uae_start_thread (_T("ide"), ide_thread, its, NULL);
+       }
+}
+
+void stop_ide_thread(struct ide_thread_state *its)
+{
+       if (its->state > 0) {
+               its->state = 0;
+               write_comm_pipe_u32 (&its->requests, 0xffffffff, 1);
+               while(its->state == 0)
+                       sleep_millis (10);
+               its->state = 0;
+       }
+}
+
+void ide_initialize(struct ide_hdf **idetable, int chpair)
+{
+       struct ide_hdf *ide0 = idetable[chpair * 2 + 0];
+       struct ide_hdf *ide1 = idetable[chpair * 2 + 1];
+
+       ide0->regs0 = &ide0->regs;
+       ide0->regs1 = &ide1->regs;
+       ide0->pair = ide1;
+
+       ide1->regs1 = &ide1->regs;
+       ide1->regs0 = &ide0->regs;
+       ide1->pair = ide0;
+
+       ide0->num = chpair * 2 + 0;
+       ide1->num = chpair * 2 + 1;
+
+       reset_device (ide0, true);
+}
+
+void alloc_ide_mem (struct ide_hdf **idetable, int max, struct ide_thread_state *its)
+{
+       for (int i = 0; i < max; i++) {
+               struct ide_hdf *ide;
+               if (!idetable[i]) {
+                       ide = idetable[i] = xcalloc (struct ide_hdf, 1);
+                       ide->cd_unit_num = -1;
+               }
+               ide = idetable[i];
+               ide_grow_buffer(ide, 1024);
+               if (its)
+                       ide->its = its;
+       }
+}
+
+void remove_ide_unit(struct ide_hdf **idetable, int ch)
+{
+       struct ide_hdf *ide;
+       if (!idetable)
+               return;
+       ide = idetable[ch];
+       if (ide) {
+               hdf_hd_close(&ide->hdhfd);
+               scsi_free(ide->scsi);
+               xfree(ide->secbuf);
+               memset(ide, 0, sizeof(struct ide_hdf));
+       }
+}
+
+struct ide_hdf *add_ide_unit (struct ide_hdf **idetable, int max, int ch, struct uaedev_config_info *ci)
+{
+       struct ide_hdf *ide;
+
+       alloc_ide_mem(idetable, max, NULL);
+       ide = idetable[ch];
+       if (ci)
+               memcpy (&ide->hdhfd.hfd.ci, ci, sizeof (struct uaedev_config_info));
+       if (ci->type == UAEDEV_CD && ci->device_emu_unit >= 0) {
+               device_func_init (0);
+               ide->scsi = scsi_alloc_cd (ch, ci->device_emu_unit, true);
+               if (!ide->scsi) {
+                       write_log (_T("IDE: CD EMU unit %d failed to open\n"), ide->cd_unit_num);
+                       return NULL;
+               }
+               ide->cd_unit_num = ci->device_emu_unit;
+               ide->atapi = true;
+               ide->blocksize = 512;
+               gui_flicker_led (LED_CD, ch, -1);
+
+               write_log (_T("IDE%d CD %d\n"), ch, ide->cd_unit_num);
+
+       } else if (ci->type == UAEDEV_HDF) {
+               if (!hdf_hd_open (&ide->hdhfd))
+                       return NULL;
+               ide->blocksize = ide->hdhfd.hfd.ci.blocksize;
+               ide->lba48 = ide->hdhfd.size >= 128 * (uae_u64)0x40000000 ? 1 : 0;
+               gui_flicker_led (LED_HD, ch, -1);
+               ide->cd_unit_num = -1;
+
+               write_log (_T("IDE%d HD '%s', LCHS=%d/%d/%d. PCHS=%d/%d/%d %uM. LBA48=%d\n"),
+                       ch, ide->hdhfd.hfd.ci.rootdir,
+                       ide->hdhfd.cyls, ide->hdhfd.heads, ide->hdhfd.secspertrack,
+                       ide->hdhfd.hfd.ci.pcyls, ide->hdhfd.hfd.ci.pheads, ide->hdhfd.hfd.ci.psecs,
+                       (int)(ide->hdhfd.size / (1024 * 1024)), ide->lba48);
+
+       }
+       ide->regs.ide_status = 0;
+       ide->data_offset = 0;
+       ide->data_size = 0;
+       return ide;
+}
+
+uae_u8 *ide_save_state(uae_u8 *dst, struct ide_hdf *ide)
+{
+       save_u64 (ide->hdhfd.size);
+       save_string (ide->hdhfd.hfd.ci.rootdir);
+       save_u32 (ide->hdhfd.hfd.ci.blocksize);
+       save_u32 (ide->hdhfd.hfd.ci.readonly);
+       save_u8 (ide->multiple_mode);
+       save_u32 (ide->hdhfd.cyls);
+       save_u32 (ide->hdhfd.heads);
+       save_u32 (ide->hdhfd.secspertrack);
+       save_u8 (ide->regs.ide_select);
+       save_u8 (ide->regs.ide_nsector);
+       save_u8 (ide->regs.ide_nsector2);
+       save_u8 (ide->regs.ide_sector);
+       save_u8 (ide->regs.ide_sector2);
+       save_u8 (ide->regs.ide_lcyl);
+       save_u8 (ide->regs.ide_lcyl2);
+       save_u8 (ide->regs.ide_hcyl);
+       save_u8 (ide->regs.ide_hcyl2);
+       save_u8 (ide->regs.ide_feat);
+       save_u8 (ide->regs.ide_feat2);
+       save_u8 (ide->regs.ide_error);
+       save_u8 (ide->regs.ide_devcon);
+       save_u64 (ide->hdhfd.hfd.virtual_size);
+       save_u32 (ide->hdhfd.hfd.ci.sectors);
+       save_u32 (ide->hdhfd.hfd.ci.surfaces);
+       save_u32 (ide->hdhfd.hfd.ci.reserved);
+       save_u32 (ide->hdhfd.hfd.ci.bootpri);
+       return dst;
+}
+
+uae_u8 *ide_restore_state(uae_u8 *src, struct ide_hdf *ide)
+{
+       ide->multiple_mode = restore_u8 ();
+       ide->hdhfd.cyls = restore_u32 ();
+       ide->hdhfd.heads = restore_u32 ();
+       ide->hdhfd.secspertrack = restore_u32 ();
+       ide->regs.ide_select = restore_u8 ();
+       ide->regs.ide_nsector = restore_u8 ();
+       ide->regs.ide_sector = restore_u8 ();
+       ide->regs.ide_lcyl = restore_u8 ();
+       ide->regs.ide_hcyl = restore_u8 ();
+       ide->regs.ide_feat = restore_u8 ();
+       ide->regs.ide_nsector2 = restore_u8 ();
+       ide->regs.ide_sector2 = restore_u8 ();
+       ide->regs.ide_lcyl2 = restore_u8 ();
+       ide->regs.ide_hcyl2 = restore_u8 ();
+       ide->regs.ide_feat2 = restore_u8 ();
+       ide->regs.ide_error = restore_u8 ();
+       ide->regs.ide_devcon = restore_u8 ();
+       ide->hdhfd.hfd.virtual_size = restore_u64 ();
+       ide->hdhfd.hfd.ci.sectors = restore_u32 ();
+       ide->hdhfd.hfd.ci.surfaces = restore_u32 ();
+       ide->hdhfd.hfd.ci.reserved = restore_u32 ();
+       ide->hdhfd.hfd.ci.bootpri = restore_u32 ();
+       return src;
+}
diff --git a/idecontrollers.cpp b/idecontrollers.cpp
new file mode 100644 (file)
index 0000000..7dfe7c2
--- /dev/null
@@ -0,0 +1,487 @@
+/*
+* UAE - The Un*x Amiga Emulator
+*
+* Other IDE controllers
+*
+* (c) 2015 Toni Wilen
+*/
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "options.h"
+
+#include "memory.h"
+#include "newcpu.h"
+#include "uae.h"
+#include "gui.h"
+#include "filesys.h"
+#include "threaddep/thread.h"
+#include "debug.h"
+#include "ide.h"
+#include "idecontrollers.h"
+#include "zfile.h"
+#include "custom.h"
+#include "rommgr.h"
+#include "cpuboard.h"
+
+#define DEBUG_IDE 0
+
+#define GVP_IDE 0 // GVP A3001
+#define TOTAL_IDE 1
+
+#define GVP_IDE_ROM_OFFSET 0x8000
+
+static struct ide_board gvp_ide_rom_board, gvp_ide_controller_board;
+static struct ide_hdf *idecontroller_drive[TOTAL_IDE * 2];
+static struct ide_thread_state idecontroller_its;
+
+static void init_ide(struct ide_board *board, struct ide_hdf **idetable)
+{
+       alloc_ide_mem (idetable, 2, &idecontroller_its);
+       board->ide = idetable[0];
+       idetable[0]->board = board;
+       idetable[1]->board = board;
+       idetable[0]->byteswap = true;
+       idetable[1]->byteswap = true;
+       ide_initialize(idetable, 0);
+       idecontroller_its.idetable = idecontroller_drive;
+       idecontroller_its.idetotal = TOTAL_IDE * 2;
+       start_ide_thread(&idecontroller_its);
+}
+
+static bool ide_irq_check(void)
+{
+       bool irq = ide_interrupt_check(idecontroller_drive, 2);
+       gvp_ide_controller_board.irq = irq;
+       return irq;
+}
+
+void idecontroller_rethink(void)
+{
+       if (!gvp_ide_controller_board.configured)
+               return;
+       if (gvp_ide_controller_board.intena && ide_irq_check() && !(intreq & 0x0008)) {
+               INTREQ_0(0x8000 | 0x0008);
+       }
+}
+
+void idecontroller_hsync(void)
+{
+       if (!gvp_ide_controller_board.configured)
+               return;
+       if (ide_irq_check())
+               idecontroller_rethink();
+}
+
+void idecontroller_free_units(void)
+{
+       for (int i = 0; i < TOTAL_IDE * 2; i++) {
+               remove_ide_unit(idecontroller_drive, i);
+       }
+}
+
+int gvp_add_ide_unit(int ch, struct uaedev_config_info *ci)
+{
+       struct ide_hdf *ide;
+
+       ide = add_ide_unit (idecontroller_drive, 2, ch, ci);
+       if (ide == NULL)
+               return 0;
+       return 1;
+}
+
+
+void idecontroller_free(void)
+{
+       stop_ide_thread(&idecontroller_its);
+}
+
+void idecontroller_reset(void)
+{
+       gvp_ide_controller_board.configured = 0;
+       gvp_ide_controller_board.intena = false;
+}
+
+static bool is_gvp2_intreq(uaecptr addr)
+{
+       if (currprefs.cpuboard_type == BOARD_A3001_II && (addr & 0x440) == 0x440)
+               return true;
+       return false;
+}
+static bool is_gvp1_intreq(uaecptr addr)
+{
+       if (currprefs.cpuboard_type == BOARD_A3001_I && (addr & 0x440) == 0x40)
+               return true;
+       return false;
+}
+
+static int get_gvp_reg(uaecptr addr, struct ide_board *board, struct ide_hdf **idep)
+{
+       struct ide_hdf *ide;
+       int reg = -1;
+
+       if (addr & 0x1000) {
+               reg = IDE_SECONDARY + ((addr >> 8) & 7);
+       } else if (addr & 0x0800) {
+               reg = (addr >> 8) & 7;
+       }
+       if (!(addr & 0x400) && (addr & 0x20)) {
+               if (reg < 0)
+                       reg = 0;
+               int extra = (addr >> 1) & 15;
+               if (extra >= 8)
+                       reg |= IDE_SECONDARY;
+               reg |= extra;
+       }
+       if (reg >= 0)
+               reg &= IDE_SECONDARY | 7;
+
+       ide = board->ide;
+       if (idecontroller_drive[GVP_IDE]->ide_drv)
+               ide = ide->pair;
+       *idep = ide;
+       return reg;
+}
+
+static uae_u32 ide_read_byte(struct ide_board *board, uaecptr addr)
+{
+       uae_u8 v = 0;
+       addr &= 0xffff;
+       if (addr < 0x40)
+               return board->acmemory[addr];
+       if (addr >= GVP_IDE_ROM_OFFSET) {
+               if (board->rom) {
+                       if (addr & 1)
+                               v = 0xe8; // board id
+                       else 
+                               v = board->rom[((addr - GVP_IDE_ROM_OFFSET) / 2) & board->rom_mask];
+                       return v;
+               }
+               v = 0xe8;
+#if DEBUG_IDE
+               write_log(_T("GVP BOOT GET %08x %02x %08x\n"), addr, v, M68K_GETPC);
+#endif
+               return v;
+       }
+       if (board->configured) {
+               if (board == &gvp_ide_rom_board && currprefs.cpuboard_type == BOARD_A3001_II) {
+                       if (addr == 0x42) {
+                               v = 0xff;
+                       }
+#if DEBUG_IDE
+                       write_log(_T("GVP BOOT GET %08x %02x %08x\n"), addr, v, M68K_GETPC);
+#endif
+               } else {
+                       struct ide_hdf *ide;
+                       int regnum = get_gvp_reg(addr, board, &ide);
+#if DEBUG_IDE
+                       write_log(_T("GVP IDE GET %08x %02x %d %08x\n"), addr, v, regnum, M68K_GETPC);
+#endif
+                       if (regnum >= 0) {
+                               v = ide_read_reg(ide, regnum);
+                       } else if (is_gvp2_intreq(addr)) {
+                               v = board->irq ? 0x40 : 0x00;
+#if DEBUG_IDE
+                               write_log(_T("GVP IRQ %02x\n"), v);
+#endif
+                               ide_irq_check();
+                       } else if (is_gvp1_intreq(addr)) {
+                               v = gvp_ide_controller_board.irq ? 0x80 : 0x00;
+#if DEBUG_IDE
+                               write_log(_T("GVP IRQ %02x\n"), v);
+#endif
+                               ide_irq_check();
+                       }
+               }
+       } else {
+               v = 0xff;
+       }
+       return v;
+}
+
+static uae_u32 ide_read_word(struct ide_board *board, uaecptr addr)
+{
+       uae_u32 v = 0xffff;
+
+       addr &= 65535;
+       if (board->configured && (board == &gvp_ide_controller_board || currprefs.cpuboard_type == BOARD_A3001_I)) {
+               if (addr < 0x60) {
+                       if (is_gvp1_intreq(addr))
+                               v = gvp_ide_controller_board.irq ? 0x8000 : 0x0000;
+                       else if (addr == 0x40) {
+                               if (currprefs.cpuboard_type == BOARD_A3001_II)
+                                       v = board->intena ? 8 : 0;
+                       }
+#if DEBUG_IDE
+                       write_log(_T("GVP IO WORD READ %08x %08x\n"), addr, M68K_GETPC);
+#endif
+               } else {
+                       struct ide_hdf *ide;
+                       int regnum = get_gvp_reg(addr, board, &ide);
+                       if (regnum == IDE_DATA) {
+                               v = ide_get_data(ide);
+#if DEBUG_IDE > 2
+                               write_log(_T("IDE WORD READ %04x\n"), v);
+#endif
+                       } else {
+                               v = ide_read_byte(board, addr) << 8;
+                               v |= ide_read_byte(board, addr + 1);
+                       }
+               }
+       }
+       return v;
+}
+
+static void ide_write_byte(struct ide_board *board, uaecptr addr, uae_u8 v)
+{
+       addr &= 65535;
+       if (!board->configured) {
+               addrbank *ab = board->bank;
+               if (addr == 0x48) {
+                       map_banks_z2(ab, v, 0x10000 >> 16);
+                       board->configured = 1;
+                       expamem_next(ab, NULL);
+                       return;
+               }
+               if (addr == 0x4c) {
+                       board->configured = 1;
+                       expamem_shutup(ab);
+                       return;
+               }
+       }
+       if (board->configured) {
+               if (board == &gvp_ide_rom_board && currprefs.cpuboard_type == BOARD_A3001_II) {
+#if DEBUG_IDE
+                       write_log(_T("GVP BOOT PUT %08x %02x %08x\n"), addr, v, M68K_GETPC);
+#endif
+               } else {
+                       struct ide_hdf *ide;
+                       int regnum = get_gvp_reg(addr, board, &ide);
+#if DEBUG_IDE
+                       write_log(_T("GVP IDE PUT %08x %02x %d %08x\n"), addr, v, regnum, M68K_GETPC);
+#endif
+                       if (regnum >= 0)
+                               ide_write_reg(ide, regnum, v);
+               }
+       }
+}
+
+static void ide_write_word(struct ide_board *board, uaecptr addr, uae_u16 v)
+{
+       addr &= 65535;
+       if (board->configured && (board == &gvp_ide_controller_board || currprefs.cpuboard_type == BOARD_A3001_I)) {
+               if (addr < 0x60) {
+#if DEBUG_IDE
+                       write_log(_T("GVP IO WORD WRITE %08x %04x %08x\n"), addr, v, M68K_GETPC);
+#endif
+                       if (addr == 0x40 && currprefs.cpuboard_type == BOARD_A3001_II)
+                               board->intena = (v & 8) != 0;
+               } else {
+                       struct ide_hdf *ide;
+                       int regnum = get_gvp_reg(addr, board, &ide);
+                       if (regnum == IDE_DATA) {
+                               ide_put_data(ide, v);
+#if DEBUG_IDE > 2
+                               write_log(_T("IDE WORD WRITE %04x\n"), v);
+#endif
+                       } else {
+                               ide_write_byte(board, addr, v >> 8);
+                               ide_write_byte(board, addr + 1, v & 0xff);
+                       }
+               }
+       }
+}
+
+static uae_u32 REGPARAM2 ide_controller_gvp_lget (uaecptr addr)
+{
+       uae_u32 v;
+#ifdef JIT
+       special_mem |= S_READ;
+#endif
+       v =  ide_read_word (&gvp_ide_controller_board, addr + 0) << 16;
+       v |= ide_read_word (&gvp_ide_controller_board, addr + 2) << 0;
+       return v;
+}
+static uae_u32 REGPARAM2 ide_controller_gvp_wget (uaecptr addr)
+{
+       uae_u32 v;
+#ifdef JIT
+       special_mem |= S_READ;
+#endif
+       v =  ide_read_word (&gvp_ide_controller_board, addr);
+       return v;
+}
+static uae_u32 REGPARAM2 ide_controller_gvp_bget (uaecptr addr)
+{
+#ifdef JIT
+       special_mem |= S_READ;
+#endif
+       return ide_read_byte (&gvp_ide_controller_board, addr);
+}
+static void REGPARAM2 ide_controller_gvp_lput (uaecptr addr, uae_u32 l)
+{
+#ifdef JIT
+       special_mem |= S_WRITE;
+#endif
+       ide_write_word (&gvp_ide_controller_board, addr + 0, l >> 16);
+       ide_write_word (&gvp_ide_controller_board, addr + 2, l >> 0);
+}
+static void REGPARAM2 ide_controller_gvp_wput (uaecptr addr, uae_u32 w)
+{
+#ifdef JIT
+       special_mem |= S_WRITE;
+#endif
+       ide_write_word (&gvp_ide_controller_board, addr + 0, w);
+}
+static void REGPARAM2 ide_controller_gvp_bput (uaecptr addr, uae_u32 b)
+{
+#ifdef JIT
+       special_mem |= S_WRITE;
+#endif
+       ide_write_byte (&gvp_ide_controller_board, addr, b);
+}
+addrbank gvp_ide_controller_bank = {
+       ide_controller_gvp_lget, ide_controller_gvp_wget, ide_controller_gvp_bget,
+       ide_controller_gvp_lput, ide_controller_gvp_wput, ide_controller_gvp_bput,
+       default_xlate, default_check, NULL, NULL, _T("GVP IDE"),
+       dummy_lgeti, dummy_wgeti, ABFLAG_IO | ABFLAG_SAFE
+};
+
+static uae_u32 REGPARAM2 ide_rom_gvp_lget (uaecptr addr)
+{
+       uae_u32 v;
+#ifdef JIT
+       special_mem |= S_READ;
+#endif
+       v =  ide_read_word (&gvp_ide_rom_board, addr + 0) << 16;
+       v |= ide_read_word (&gvp_ide_rom_board, addr + 2) << 0;
+       return v;
+}
+static uae_u32 REGPARAM2 ide_rom_gvp_wget (uaecptr addr)
+{
+       uae_u32 v;
+#ifdef JIT
+       special_mem |= S_READ;
+#endif
+       v =  ide_read_word (&gvp_ide_rom_board, addr);
+       return v;
+}
+static uae_u32 REGPARAM2 ide_rom_gvp_bget (uaecptr addr)
+{
+#ifdef JIT
+       special_mem |= S_READ;
+#endif
+       return ide_read_byte (&gvp_ide_rom_board, addr);
+}
+static void REGPARAM2 ide_rom_gvp_lput (uaecptr addr, uae_u32 l)
+{
+#ifdef JIT
+       special_mem |= S_WRITE;
+#endif
+       ide_write_word (&gvp_ide_rom_board, addr + 0, l >> 16);
+       ide_write_word (&gvp_ide_rom_board, addr + 2, l >> 0);
+}
+static void REGPARAM2 ide_rom_gvp_wput (uaecptr addr, uae_u32 w)
+{
+#ifdef JIT
+       special_mem |= S_WRITE;
+#endif
+       ide_write_word (&gvp_ide_rom_board, addr + 0, w);
+}
+static void REGPARAM2 ide_rom_gvp_bput (uaecptr addr, uae_u32 b)
+{
+#ifdef JIT
+       special_mem |= S_WRITE;
+#endif
+       ide_write_byte (&gvp_ide_rom_board, addr, b);
+}
+addrbank gvp_ide_rom_bank = {
+       ide_rom_gvp_lget, ide_rom_gvp_wget, ide_rom_gvp_bget,
+       ide_rom_gvp_lput, ide_rom_gvp_wput, ide_rom_gvp_bput,
+       default_xlate, default_check, NULL, NULL, _T("GVP BOOT"),
+       dummy_lgeti, dummy_wgeti, ABFLAG_IO | ABFLAG_SAFE
+};
+
+static void ew(struct ide_board *ide, int addr, uae_u32 value)
+{
+       addr &= 0xffff;
+       if (addr == 00 || addr == 02 || addr == 0x40 || addr == 0x42) {
+               ide->acmemory[addr] = (value & 0xf0);
+               ide->acmemory[addr + 2] = (value & 0x0f) << 4;
+       } else {
+               ide->acmemory[addr] = ~(value & 0xf0);
+               ide->acmemory[addr + 2] = ~((value & 0x0f) << 4);
+       }
+}
+
+static const uae_u8 gvp_ide2_rom_autoconfig[16] = { 0xd1, 0x0d, 0x00, 0x00, 0x07, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 };
+static const uae_u8 gvp_ide2_controller_autoconfig[16] = { 0xc1, 0x0b, 0x00, 0x00, 0x07, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static const uae_u8 gvp_ide1_controller_autoconfig[16] = { 0xd1, 0x08, 0x00, 0x00, 0x07, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 };
+
+addrbank *gvp_ide_rom_autoconfig_init(void)
+{
+       struct ide_board *ide = &gvp_ide_rom_board;
+       int roms[2];
+       struct romlist *rl;
+       const uae_u8 *autoconfig;
+
+       if (currprefs.cpuboard_type == BOARD_A3001_I) {
+               ide->bank = &gvp_ide_rom_bank;
+               autoconfig = gvp_ide1_controller_autoconfig;
+               init_ide(ide, &idecontroller_drive[GVP_IDE]);
+               ide->rom_size = 8192;
+               gvp_ide_controller_board.intena = true;
+               gvp_ide_controller_board.configured = -1;
+               roms[0] = 114;
+               roms[1] = -1;
+       } else {
+               ide->bank = &gvp_ide_rom_bank;
+               autoconfig = gvp_ide2_rom_autoconfig;
+               ide->rom_size = 16384;
+               roms[0] = -1;
+       }
+       ide->configured = 0;
+       memset(ide->acmemory, 0xff, sizeof ide->acmemory);
+
+
+       ide->rom = xcalloc(uae_u8, ide->rom_size);
+       memset(ide->rom, 0xff, ide->rom_size);
+       ide->rom_mask = ide->rom_size - 1;
+       const TCHAR *romname = currprefs.acceleratorromfile;
+       struct zfile *z = read_rom_name(romname);
+       if (!z) {
+               rl = getromlistbyids(roms, romname);
+               if (rl) {
+                       z = read_rom(rl->rd);
+               }
+       }
+       if (z) {
+               for (int i = 0; i < 16; i++) {
+                       uae_u8 b = autoconfig[i];
+                       ew(ide, i * 4, b);
+               }
+               write_log(_T("GVP IDE BOOT ROM '%s'\n"), zfile_getname(z));
+               int size = zfile_fread(ide->rom, 1, ide->rom_size, z);
+               zfile_fclose(z);
+       } else {
+               romwarning(roms);
+       }
+       return ide->bank;
+}
+
+addrbank *gvp_ide_controller_autoconfig_init(void)
+{
+       struct ide_board *ide = &gvp_ide_controller_board;
+
+       init_ide(ide, &idecontroller_drive[GVP_IDE]);
+       ide->configured = 0;
+       ide->bank = &gvp_ide_controller_bank;
+       memset(ide->acmemory, 0xff, sizeof ide->acmemory);
+       for (int i = 0; i < 16; i++) {
+               uae_u8 b = gvp_ide2_controller_autoconfig[i];
+               ew(ide, i * 4, b);
+       }
+       return ide->bank;
+}
+
index 6779989e6d39ae97439fed4432e7f3e853558ae9..6b547271c855c7b7e278f1a8a8b4d3c0ecc56536 100644 (file)
@@ -44,7 +44,6 @@ extern uae_u8 *REGPARAM3 cyberstorm_scsi_ram_xlate(uaecptr addr) REGPARAM;
 #define BOARD_A2630 13
 #define BOARD_DKB1200 14
 #define BOARD_FUSIONFORTY 15
-
-
-
+#define BOARD_A3001_I 16
+#define BOARD_A3001_II 17
 
index beead53df9bdc1267f1ced26132f650d5fc0e0fb..7312dfd9abcd48578760ccb75660071756f8ad5a 100644 (file)
@@ -89,29 +89,30 @@ struct hd_hardfiledata {
 
 #define HD_CONTROLLER_TYPE_UAE 0
 #define HD_CONTROLLER_TYPE_IDE_AUTO 1
-#define HD_CONTROLLER_TYPE_IDE_MB 1
-#define HD_CONTROLLER_TYPE_SCSI_AUTO 2
-#define HD_CONTROLLER_TYPE_SCSI_A2091 3
-#define HD_CONTROLLER_TYPE_SCSI_A2091_2 4
-#define HD_CONTROLLER_TYPE_SCSI_GVP 5
-#define HD_CONTROLLER_TYPE_SCSI_GVP_2 6
-#define HD_CONTROLLER_TYPE_SCSI_A4091 7
-#define HD_CONTROLLER_TYPE_SCSI_A4091_2 8
-#define HD_CONTROLLER_TYPE_SCSI_FASTLANE 9
-#define HD_CONTROLLER_TYPE_SCSI_FASTLANE_2 10
-#define HD_CONTROLLER_TYPE_SCSI_OKTAGON 11
-#define HD_CONTROLLER_TYPE_SCSI_OKTAGON_2 12
-#define HD_CONTROLLER_TYPE_SCSI_A3000 13
-#define HD_CONTROLLER_TYPE_SCSI_A4000T 14
-#define HD_CONTROLLER_TYPE_SCSI_CDTV 15
-#define HD_CONTROLLER_TYPE_SCSI_CPUBOARD 16
-#define HD_CONTROLLER_TYPE_PCMCIA_SRAM 17
-#define HD_CONTROLLER_TYPE_PCMCIA_IDE 18
+#define HD_CONTROLLER_TYPE_IDE_MB 2
+#define HD_CONTROLLER_TYPE_IDE_GVP 3
+#define HD_CONTROLLER_TYPE_SCSI_AUTO 4
+#define HD_CONTROLLER_TYPE_SCSI_A2091 5
+#define HD_CONTROLLER_TYPE_SCSI_A2091_2 6
+#define HD_CONTROLLER_TYPE_SCSI_GVP 7
+#define HD_CONTROLLER_TYPE_SCSI_GVP_2 8
+#define HD_CONTROLLER_TYPE_SCSI_A4091 9
+#define HD_CONTROLLER_TYPE_SCSI_A4091_2 10
+#define HD_CONTROLLER_TYPE_SCSI_FASTLANE 11
+#define HD_CONTROLLER_TYPE_SCSI_FASTLANE_2 12
+#define HD_CONTROLLER_TYPE_SCSI_OKTAGON 13
+#define HD_CONTROLLER_TYPE_SCSI_OKTAGON_2 14
+#define HD_CONTROLLER_TYPE_SCSI_A3000 15
+#define HD_CONTROLLER_TYPE_SCSI_A4000T 16
+#define HD_CONTROLLER_TYPE_SCSI_CDTV 17
+#define HD_CONTROLLER_TYPE_SCSI_CPUBOARD 18
+#define HD_CONTROLLER_TYPE_PCMCIA_SRAM 19
+#define HD_CONTROLLER_TYPE_PCMCIA_IDE 20
 
 #define HD_CONTROLLER_TYPE_IDE_FIRST 1
-#define HD_CONTROLLER_TYPE_IDE_LAST 1
-#define HD_CONTROLLER_TYPE_SCSI_FIRST 2
-#define HD_CONTROLLER_TYPE_SCSI_LAST 16
+#define HD_CONTROLLER_TYPE_IDE_LAST 3
+#define HD_CONTROLLER_TYPE_SCSI_FIRST 4
+#define HD_CONTROLLER_TYPE_SCSI_LAST 18
 
 #define FILESYS_VIRTUAL 0
 #define FILESYS_HARDFILE 1
diff --git a/include/ide.h b/include/ide.h
new file mode 100644 (file)
index 0000000..c944bee
--- /dev/null
@@ -0,0 +1,102 @@
+
+/* IDE drive registers */
+#define IDE_DATA       0x00
+#define IDE_ERROR      0x01        /* see err-bits */
+#define IDE_NSECTOR    0x02        /* sector count, nr of sectors to read/write */
+#define IDE_SECTOR     0x03        /* starting sector */
+#define IDE_LCYL       0x04        /* starting cylinder */
+#define IDE_HCYL       0x05        /* high byte of starting cyl */
+#define IDE_SELECT     0x06        /* 101dhhhh , d=drive, hhhh=head */
+#define IDE_STATUS     0x07        /* see status-bits */
+
+#define IDE_SECONDARY 0x0400
+#define IDE_DEVCON     0x0406
+#define IDE_DRVADDR    0x0407
+
+struct ide_registers
+{
+       uae_u8 ide_select, ide_nsector, ide_sector, ide_lcyl, ide_hcyl, ide_devcon, ide_error, ide_feat;
+       uae_u8 ide_nsector2, ide_sector2, ide_lcyl2, ide_hcyl2, ide_feat2;
+       uae_u8 ide_status;
+};
+
+struct ide_thread_state;
+struct ide_hdf;
+
+struct ide_board
+{
+       uae_u8 *rom;
+       uae_u8 acmemory[128];
+       int rom_size;
+       int rom_mask;
+       int configured;
+       addrbank *bank;
+       struct ide_hdf *ide;
+       bool irq;
+       bool intena;
+};
+
+struct ide_hdf
+{
+       struct hd_hardfiledata hdhfd;
+       struct ide_board *board;
+       struct ide_registers regs;
+       struct ide_registers *regs0;
+       struct ide_registers *regs1;
+       struct ide_hdf *pair; // master<>slave
+       struct ide_thread_state *its;
+       bool byteswap;
+
+       uae_u8 *secbuf;
+       int secbuf_size;
+       int data_offset;
+       int data_size;
+       int data_multi;
+       int direction; // 0 = read, 1 = write
+       bool intdrq;
+       bool lba48;
+       bool lba48cmd;
+       uae_u8 multiple_mode;
+       int irq_delay;
+       int irq;
+       int num;
+       int blocksize;
+       int maxtransferstate;
+       int ide_drv;
+
+       bool atapi;
+       bool atapi_drdy;
+       int cd_unit_num;
+       int packet_state;
+       int packet_data_size;
+       int packet_data_offset;
+       int packet_transfer_size;
+       struct scsi_data *scsi;
+};
+
+struct ide_thread_state
+{
+       struct ide_hdf **idetable;
+       int idetotal;
+       volatile int state;
+       smp_comm_pipe requests; 
+};
+
+uae_u32 ide_read_reg (struct ide_hdf *ide, int ide_reg);
+void ide_write_reg (struct ide_hdf *ide, int ide_reg, uae_u32 val);
+void ide_put_data (struct ide_hdf *ide, uae_u16 v);
+uae_u16 ide_get_data (struct ide_hdf *ide);
+
+bool ide_interrupt_check(struct ide_hdf **ide, int num);
+bool ide_isdrive(struct ide_hdf *ide);
+void ide_initialize(struct ide_hdf **idetable, int chpair);
+struct ide_hdf *add_ide_unit (struct ide_hdf **idetable, int max, int ch, struct uaedev_config_info *ci);
+void remove_ide_unit(struct ide_hdf **idetable, int ch);
+void alloc_ide_mem (struct ide_hdf **ide, int max, struct ide_thread_state *its);
+
+void start_ide_thread(struct ide_thread_state *its);
+void stop_ide_thread(struct ide_thread_state *its);
+
+uae_u8 *ide_save_state(uae_u8 *dst, struct ide_hdf *ide);
+uae_u8 *ide_restore_state(uae_u8 *src, struct ide_hdf *ide);
+
diff --git a/include/idecontrollers.h b/include/idecontrollers.h
new file mode 100644 (file)
index 0000000..f46e93c
--- /dev/null
@@ -0,0 +1,11 @@
+// Other IDE controllers
+
+void idecontroller_free_units(void);
+void idecontroller_free(void);
+void idecontroller_reset(void);
+void idecontroller_rethink(void);
+void idecontroller_hsync(void);
+
+int gvp_add_ide_unit(int ch, struct uaedev_config_info *ci);
+addrbank *gvp_ide_rom_autoconfig_init(void);
+addrbank *gvp_ide_controller_autoconfig_init(void);
index 800c48f8983e69b592e912af710f1e737921e4d0..af628a3a39d4faaaceaa139c721148b7d42656ba 100644 (file)
@@ -152,8 +152,8 @@ extern int save_filesys_cando(void);
 
 extern uae_u8 *restore_gayle(uae_u8 *src);
 extern uae_u8 *save_gayle (int *len, uae_u8*);
-extern uae_u8 *restore_ide (uae_u8 *src);
-extern uae_u8 *save_ide (int num, int *len, uae_u8*);
+extern uae_u8 *restore_gayle_ide (uae_u8 *src);
+extern uae_u8 *save_gayle_ide (int num, int *len, uae_u8*);
 
 extern uae_u8 *save_cd (int num, int *len);
 extern uae_u8 *restore_cd (int, uae_u8 *src);
index c5c02568f1ed4bc7fd68c0f004188cf1afe71230..5be5a0893cc12449accfb7e004904328321f25c7 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -57,6 +57,7 @@
 #include "sampler.h"
 #include "consolehook.h"
 #include "gayle.h"
+#include "idecontrollers.h"
 #include "gfxboard.h"
 #include "luascript.h"
 #include "uaenative.h"
@@ -1044,6 +1045,7 @@ void do_leave_program (void)
        bsdlib_reset ();
 #endif
        gayle_free ();
+       idecontroller_free();
        device_func_reset ();
 #ifdef WITH_LUA
        uae_lua_free ();
index b7750e440002a2968fd89ae6ac3532cc52224b93..39305333a359b7bf76f668fa61b7554fb06a1478 100644 (file)
@@ -93,7 +93,7 @@ struct romdata *getromdatabypath (const TCHAR *path)
        return NULL;
 }
 
-#define NEXT_ROM_ID 114
+#define NEXT_ROM_ID 115
 
 static struct romheader romheaders[] = {
        { _T("Freezer Cartridges"), 1 },
@@ -340,6 +340,10 @@ static struct romdata roms[] = {
        { _T("GVP Series II Guru ROM"), 6, 14, 6, 14, _T("GVPII\0"), 32768, 110, 0, 0, ROMTYPE_GVP, 0, 0, NULL,
        0x756103b1, 0x7f1335ea,0xf5b7ce73,0xc5231173,0x261da5aa,0xe7249645, NULL, NULL },
 
+       { _T("GVP A3001 Series I ROM"), 3, 3, 3, 3, _T("A3001SI\0"), 8192, 114, 0, 0, ROMTYPE_CPUBOARD, 0, 0, NULL,
+       0xaaff7c65, 0x424cf3da,0xcc9da794,0x0ba74446,0x69dd1691,0x44ae87ee, NULL, NULL },
+
+
        { _T("CyberStorm MK I 68040"), 0, 0, 0, 0, _T("CSMKI\0"), 32768, 95, 0, 0, ROMTYPE_CPUBOARD, 0, 0, NULL,
          0, 0, 0, 0, 0, 0, NULL, _T("cyberstormmk1_040.rom") },
        { _T("CyberStorm MK I 68060"), 0, 0, 0, 0, _T("CSMKI\0"), 65536, 101, 0, 0, ROMTYPE_CPUBOARD, 0, 0, NULL,
index ede12d61fb49c09a1046fd917da93e09ed294b09..fe283ce09a0539099d32887bd7cf6adce3e515fc 100644 (file)
@@ -701,7 +701,7 @@ void restore_state (const TCHAR *filename)
                else if (!_tcscmp (name, _T("GAYL")))
                        end = restore_gayle (chunk);
                else if (!_tcscmp (name, _T("IDE ")))
-                       end = restore_ide (chunk);
+                       end = restore_gayle_ide (chunk);
                else if (!_tcsncmp (name, _T("CDU"), 3))
                        end = restore_cd (name[3] - '0', chunk);
 #ifdef A2065
@@ -1032,7 +1032,7 @@ static int save_state_internal (struct zfile *f, const TCHAR *description, int c
                xfree(dst);
        }
        for (i = 0; i < 4; i++) {
-               dst = save_ide (i, &len, NULL);
+               dst = save_gayle_ide (i, &len, NULL);
                if (dst) {
                        save_chunk (f, dst, len, _T("IDE "), 0);
                        xfree (dst);
@@ -1329,7 +1329,7 @@ void savestate_rewind (void)
                p = restore_gayle (p);
        for (i = 0; i < 4; i++) {
                if (restore_u32_func (&p))
-                       p = restore_ide (p);
+                       p = restore_gayle_ide (p);
        }
        p += 4;
        if (p != p2) {
@@ -1703,7 +1703,7 @@ retry2:
                p3 = p;
                save_u32_func (&p, 0);
                tlen += 4;
-               if (save_ide (i, &len, p)) {
+               if (save_gayle_ide (i, &len, p)) {
                        save_u32_func (&p3, 1);
                        tlen += len;
                        p += len;