From 086507005289d4c56bde1a061830594eee07ed08 Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Sun, 11 Jan 2015 14:28:54 +0200 Subject: [PATCH] IDE emulation detached from Gayle. GVP A3001 IDE. --- cpuboard.cpp | 3 + expansion.cpp | 29 +- filesys.cpp | 27 +- gayle.cpp | 1260 +------------------------------------- ide.cpp | 1219 ++++++++++++++++++++++++++++++++++++ idecontrollers.cpp | 487 +++++++++++++++ include/cpuboard.h | 5 +- include/filesys.h | 43 +- include/ide.h | 102 +++ include/idecontrollers.h | 11 + include/savestate.h | 4 +- main.cpp | 2 + rommgr.cpp | 6 +- savestate.cpp | 8 +- 14 files changed, 1942 insertions(+), 1264 deletions(-) create mode 100644 ide.cpp create mode 100644 idecontrollers.cpp create mode 100644 include/ide.h create mode 100644 include/idecontrollers.h diff --git a/cpuboard.cpp b/cpuboard.cpp index e6b59e01..e7fe8d57 100644 --- a/cpuboard.cpp +++ b/cpuboard.cpp @@ -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: diff --git a/expansion.cpp b/expansion.cpp index 9971f525..ca067dd3 100644 --- a/expansion.cpp +++ b/expansion.cpp @@ -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; diff --git a/filesys.cpp b/filesys.cpp index e998da40..e758dfb0 100644 --- a/filesys.cpp +++ b/filesys.cpp @@ -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) { diff --git a/gayle.cpp b/gayle.cpp index 35304fb7..ca4cc436 100644 --- 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 index 00000000..d323d9d0 --- /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 index 00000000..7dfe7c24 --- /dev/null +++ b/idecontrollers.cpp @@ -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; +} + diff --git a/include/cpuboard.h b/include/cpuboard.h index 6779989e..6b547271 100644 --- a/include/cpuboard.h +++ b/include/cpuboard.h @@ -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 diff --git a/include/filesys.h b/include/filesys.h index beead53d..7312dfd9 100644 --- a/include/filesys.h +++ b/include/filesys.h @@ -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 index 00000000..c944bee5 --- /dev/null +++ b/include/ide.h @@ -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 index 00000000..f46e93cb --- /dev/null +++ b/include/idecontrollers.h @@ -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); diff --git a/include/savestate.h b/include/savestate.h index 800c48f8..af628a3a 100644 --- a/include/savestate.h +++ b/include/savestate.h @@ -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); diff --git a/main.cpp b/main.cpp index c5c02568..5be5a089 100644 --- 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 (); diff --git a/rommgr.cpp b/rommgr.cpp index b7750e44..39305333 100644 --- a/rommgr.cpp +++ b/rommgr.cpp @@ -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, diff --git a/savestate.cpp b/savestate.cpp index ede12d61..fe283ce0 100644 --- a/savestate.cpp +++ b/savestate.cpp @@ -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; -- 2.47.3