/* * UAE - The Un*x Amiga Emulator * * A590/A2091/A3000/CDTV SCSI expansion (DMAC/SuperDMAC + WD33C93) emulation * Includes A590 + XT drive emulation. * GVP Series I and II * A2090 SCSI and ST-506 * * Copyright 2007-2015 Toni Wilen * */ #define GVP_S1_DEBUG_IO 0 #define GVP_S2_DEBUG_IO 0 #define A2091_DEBUG 0 #define A2091_DEBUG_IO 0 #define XT_DEBUG 0 #define A3000_DEBUG 0 #define A3000_DEBUG_IO 0 #define WD33C93_DEBUG 0 #define WD33C93_DEBUG_PIO 0 #include "sysconfig.h" #include "sysdeps.h" #include "options.h" #include "uae.h" #include "memory.h" #include "rommgr.h" #include "custom.h" #include "newcpu.h" #include "debug.h" #include "scsi.h" #include "threaddep/thread.h" #include "a2091.h" #include "blkdev.h" #include "gui.h" #include "zfile.h" #include "filesys.h" #include "autoconf.h" #include "cdtv.h" #include "savestate.h" #include "cpuboard.h" #define DMAC_8727_ROM_VECTOR 0x8000 #define CDMAC_ROM_VECTOR 0x2000 #define CDMAC_ROM_OFFSET 0x2000 #define GVP_ROM_OFFSET 0x8000 #define GVP_SERIES_I_RAM_OFFSET_1 0x04000 #define GVP_SERIES_I_RAM_OFFSET_2 0x04000 #define GVP_SERIES_I_RAM_OFFSET_3 0x10000 #define GVP_SERIES_I_RAM_MASK_1 (4096 - 1) #define GVP_SERIES_I_RAM_MASK_2 (16384 - 1) #define GVP_SERIES_I_RAM_MASK_3 (16384 - 1) /* SuperDMAC CNTR bits. */ #define SCNTR_TCEN (1<<5) #define SCNTR_PREST (1<<4) #define SCNTR_PDMD (1<<3) #define SCNTR_INTEN (1<<2) #define SCNTR_DDIR (1<<1) #define SCNTR_IO_DX (1<<0) /* DMAC CNTR bits. */ #define CNTR_TCEN (1<<7) #define CNTR_PREST (1<<6) #define CNTR_PDMD (1<<5) #define CNTR_INTEN (1<<4) #define CNTR_DDIR (1<<3) /* ISTR bits. */ #define ISTR_INT_F (1<<7) /* Interrupt Follow */ #define ISTR_INTS (1<<6) /* SCSI or XT Peripheral Interrupt */ #define ISTR_E_INT (1<<5) /* End-Of-Process Interrupt */ #define ISTR_INT_P (1<<4) /* Interrupt Pending */ #define ISTR_UE_INT (1<<3) /* Under-Run FIFO Error Interrupt */ #define ISTR_OE_INT (1<<2) /* Over-Run FIFO Error Interrupt */ #define ISTR_FF_FLG (1<<1) /* FIFO-Full Flag */ #define ISTR_FE_FLG (1<<0) /* FIFO-Empty Flag */ /* GVP models */ #define GVP_GFORCE_040 0x20 #define GVP_GFORCE_040_SCSI 0x30 #define GVP_A1291_SCSI 0x40 #define GVP_GFORCE_030 0xa0 #define GVP_GFORCE_030_SCSI 0xb0 #define GVP_COMBO_R4 0x60 #define GVP_COMBO_R4_SCSI 0x70 #define GVP_COMBO_R3 0xe0 #define GVP_COMBO_R3_SCSI 0xf0 #define GVP_SERIESII 0xf8 #define GVP_A530 0xc0 #define GVP_A530_SCSI 0xd0 /* wd register names */ #define WD_OWN_ID 0x00 #define WD_CONTROL 0x01 #define WD_TIMEOUT_PERIOD 0x02 #define WD_CDB_1 0x03 #define WD_T_SECTORS 0x03 #define WD_CDB_2 0x04 #define WD_T_HEADS 0x04 #define WD_CDB_3 0x05 #define WD_T_CYLS_0 0x05 #define WD_CDB_4 0x06 #define WD_T_CYLS_1 0x06 #define WD_CDB_5 0x07 #define WD_L_ADDR_0 0x07 #define WD_CDB_6 0x08 #define WD_L_ADDR_1 0x08 #define WD_CDB_7 0x09 #define WD_L_ADDR_2 0x09 #define WD_CDB_8 0x0a #define WD_L_ADDR_3 0x0a #define WD_CDB_9 0x0b #define WD_SECTOR 0x0b #define WD_CDB_10 0x0c #define WD_HEAD 0x0c #define WD_CDB_11 0x0d #define WD_CYL_0 0x0d #define WD_CDB_12 0x0e #define WD_CYL_1 0x0e #define WD_TARGET_LUN 0x0f #define WD_COMMAND_PHASE 0x10 #define WD_SYNCHRONOUS_TRANSFER 0x11 #define WD_TRANSFER_COUNT_MSB 0x12 #define WD_TRANSFER_COUNT 0x13 #define WD_TRANSFER_COUNT_LSB 0x14 #define WD_DESTINATION_ID 0x15 #define WD_SOURCE_ID 0x16 #define WD_SCSI_STATUS 0x17 #define WD_COMMAND 0x18 #define WD_DATA 0x19 #define WD_QUEUE_TAG 0x1a #define WD_AUXILIARY_STATUS 0x1f /* WD commands */ #define WD_CMD_RESET 0x00 #define WD_CMD_ABORT 0x01 #define WD_CMD_ASSERT_ATN 0x02 #define WD_CMD_NEGATE_ACK 0x03 #define WD_CMD_DISCONNECT 0x04 #define WD_CMD_RESELECT 0x05 #define WD_CMD_SEL_ATN 0x06 #define WD_CMD_SEL 0x07 #define WD_CMD_SEL_ATN_XFER 0x08 #define WD_CMD_SEL_XFER 0x09 #define WD_CMD_RESEL_RECEIVE 0x0a #define WD_CMD_RESEL_SEND 0x0b #define WD_CMD_WAIT_SEL_RECEIVE 0x0c #define WD_CMD_TRANS_ADDR 0x18 #define WD_CMD_TRANS_INFO 0x20 #define WD_CMD_TRANSFER_PAD 0x21 #define WD_CMD_SBT_MODE 0x80 /* paused or aborted interrupts */ #define CSR_MSGIN 0x20 #define CSR_SDP 0x21 #define CSR_SEL_ABORT 0x22 #define CSR_RESEL_ABORT 0x25 #define CSR_RESEL_ABORT_AM 0x27 #define CSR_ABORT 0x28 /* successful completion interrupts */ #define CSR_RESELECT 0x10 #define CSR_SELECT 0x11 #define CSR_TRANS_ADDR 0x15 #define CSR_SEL_XFER_DONE 0x16 #define CSR_XFER_DONE 0x18 /* terminated interrupts */ #define CSR_INVALID 0x40 #define CSR_UNEXP_DISC 0x41 #define CSR_TIMEOUT 0x42 #define CSR_PARITY 0x43 #define CSR_PARITY_ATN 0x44 #define CSR_BAD_STATUS 0x45 #define CSR_UNEXP 0x48 /* service required interrupts */ #define CSR_RESEL 0x80 #define CSR_RESEL_AM 0x81 #define CSR_DISC 0x85 #define CSR_SRV_REQ 0x88 /* SCSI Bus Phases */ #define PHS_DATA_OUT 0x00 #define PHS_DATA_IN 0x01 #define PHS_COMMAND 0x02 #define PHS_STATUS 0x03 #define PHS_MESS_OUT 0x06 #define PHS_MESS_IN 0x07 /* Auxialiry status */ #define ASR_INT 0x80 /* Interrupt pending */ #define ASR_LCI 0x40 /* Last command ignored */ #define ASR_BSY 0x20 /* Busy, only cmd/data/asr readable */ #define ASR_CIP 0x10 /* Busy, cmd unavail also */ #define ASR_xxx 0x0c #define ASR_PE 0x02 /* Parity error (even) */ #define ASR_DBR 0x01 /* Data Buffer Ready */ /* Status */ #define CSR_CAUSE 0xf0 #define CSR_RESET 0x00 /* chip was reset */ #define CSR_CMD_DONE 0x10 /* cmd completed */ #define CSR_CMD_STOPPED 0x20 /* interrupted or abrted*/ #define CSR_CMD_ERR 0x40 /* end with error */ #define CSR_BUS_SERVICE 0x80 /* REQ pending on the bus */ /* Control */ #define CTL_DMA 0x80 /* Single byte dma */ #define CTL_DBA_DMA 0x40 /* direct buffer access (bus master) */ #define CTL_BURST_DMA 0x20 /* continuous mode (8237) */ #define CTL_NO_DMA 0x00 /* Programmed I/O */ #define CTL_HHP 0x10 /* Halt on host parity error */ #define CTL_EDI 0x08 /* Ending disconnect interrupt */ #define CTL_IDI 0x04 /* Intermediate disconnect interrupt*/ #define CTL_HA 0x02 /* Halt on ATN */ #define CTL_HSP 0x01 /* Halt on SCSI parity error */ /* SCSI Messages */ #define MSG_COMMAND_COMPLETE 0x00 #define MSG_SAVE_DATA_POINTER 0x02 #define MSG_RESTORE_DATA_POINTERS 0x03 #define MSG_NOP 0x08 #define MSG_IDENTIFY 0x80 /* XT hard disk controller registers */ #define XD_DATA 0x00 /* data RW register */ #define XD_RESET 0x01 /* reset WO register */ #define XD_STATUS 0x01 /* status RO register */ #define XD_SELECT 0x02 /* select WO register */ #define XD_JUMPER 0x02 /* jumper RO register */ #define XD_CONTROL 0x03 /* DMAE/INTE WO register */ #define XD_RESERVED 0x03 /* reserved */ /* XT hard disk controller commands (incomplete list) */ #define XT_CMD_TESTREADY 0x00 /* test drive ready */ #define XT_CMD_RECALIBRATE 0x01 /* recalibrate drive */ #define XT_CMD_SENSE 0x03 /* request sense */ #define XT_CMD_FORMATDRV 0x04 /* format drive */ #define XT_CMD_VERIFY 0x05 /* read verify */ #define XT_CMD_FORMATTRK 0x06 /* format track */ #define XT_CMD_FORMATBAD 0x07 /* format bad track */ #define XT_CMD_READ 0x08 /* read */ #define XT_CMD_WRITE 0x0A /* write */ #define XT_CMD_SEEK 0x0B /* seek */ /* Controller specific commands */ #define XT_CMD_DTCSETPARAM 0x0C /* set drive parameters (DTC 5150X & CX only?) */ /* Bits for command status byte */ #define XT_CSB_ERROR 0x02 /* error */ #define XT_CSB_LUN 0x20 /* logical Unit Number */ /* XT hard disk controller status bits */ #define XT_STAT_READY 0x01 /* controller is ready */ #define XT_STAT_INPUT 0x02 /* data flowing from controller to host */ #define XT_STAT_COMMAND 0x04 /* controller in command phase */ #define XT_STAT_SELECT 0x08 /* controller is selected */ #define XT_STAT_REQUEST 0x10 /* controller requesting data */ #define XT_STAT_INTERRUPT 0x20 /* controller requesting interrupt */ /* XT hard disk controller control bits */ #define XT_INT 0x02 /* Interrupt enable */ #define XT_DMA_MODE 0x01 /* DMA enable */ #define XT_UNIT 8 #define XT_SECTORS 17 /* hardwired */ #define XT506_UNIT0 8 #define XT506_UNIT1 9 #define MAX_SCSI_UNITS (8 + 2) static struct wd_state *wd_a2091[MAX_DUPLICATE_EXPANSION_BOARDS]; static struct wd_state *wd_a2090[MAX_DUPLICATE_EXPANSION_BOARDS]; static struct wd_state *wd_a3000; static struct wd_state *wd_gvps1[MAX_DUPLICATE_EXPANSION_BOARDS]; static struct wd_state *wd_gvps2[MAX_DUPLICATE_EXPANSION_BOARDS]; static struct wd_state *wd_gvps2accel; struct wd_state *wd_cdtv; static struct wd_state *scsi_units[MAX_SCSI_UNITS + 1]; static void freencrunit(struct wd_state *wd) { if (!wd) return; for (int i = 0; i < MAX_SCSI_UNITS; i++) { if (scsi_units[i] == wd) { scsi_units[i] = NULL; } } scsi_freenative(wd->scsis, MAX_SCSI_UNITS); xfree (wd->rom); wd->rom = NULL; if (wd->self_ptr) *wd->self_ptr = NULL; xfree(wd); } static struct wd_state *allocscsi(struct wd_state **wd, struct romconfig *rc, int ch) { struct wd_state *scsi; if (ch < 0) { freencrunit(*wd); *wd = NULL; } if ((*wd) == NULL) { scsi = xcalloc(struct wd_state, 1); for (int i = 0; i < MAX_SCSI_UNITS; i++) { if (scsi_units[i] == NULL) { scsi_units[i] = scsi; if (rc) rc->unitdata = scsi; scsi->rc = rc; scsi->self_ptr = wd; *wd = scsi; return scsi; } } } return *wd; } static struct wd_state *getscsi(struct romconfig *rc) { if (rc->unitdata) return (struct wd_state*)rc->unitdata; return NULL; } static struct wd_state *getscsiboard(uaecptr addr) { for (int i = 0; scsi_units[i]; i++) { if (!scsi_units[i]->baseaddress) return scsi_units[i]; if ((addr & ~scsi_units[i]->board_mask) == scsi_units[i]->baseaddress) return scsi_units[i]; } return NULL; } static void reset_dmac(struct wd_state *wd) { switch (wd->dmac_type) { case GVP_DMAC_S1: case GVP_DMAC_S2: wd->gdmac.cntr = 0; wd->gdmac.dma_on = 0; break; case COMMODORE_SDMAC: case COMMODORE_DMAC: case COMMODORE_8727: wd->cdmac.dmac_dma = 0; wd->cdmac.dmac_istr = 0; wd->cdmac.dmac_cntr = 0; break; } } static bool isirq(struct wd_state *wd) { if (!wd->enabled) return false; switch (wd->dmac_type) { case GVP_DMAC_S1: if ((wd->gdmac.cntr & 0x80) && (wd->wc.auxstatus & ASR_INT)) return true; break; case GVP_DMAC_S2: if (wd->wc.auxstatus & ASR_INT) wd->gdmac.cntr |= 2; if ((wd->gdmac.cntr & (2 | 8)) == (2 | 8)) return true; break; case COMMODORE_SDMAC: if (wd->wc.auxstatus & ASR_INT) wd->cdmac.dmac_istr |= ISTR_INTS | ISTR_INT_F; else wd->cdmac.dmac_istr &= ~ISTR_INT_F; if ((wd->cdmac.dmac_cntr & SCNTR_INTEN) && (wd->cdmac.dmac_istr & (ISTR_INTS | ISTR_E_INT))) return true; break; case COMMODORE_DMAC: if (wd->cdmac.xt_irq) wd->cdmac.dmac_istr |= ISTR_INTS | ISTR_INT_F; else if (wd->wc.auxstatus & ASR_INT) wd->cdmac.dmac_istr |= ISTR_INTS | ISTR_INT_F; else wd->cdmac.dmac_istr &= ~ISTR_INT_F; if ((wd->cdmac.dmac_cntr & CNTR_INTEN) && (wd->cdmac.dmac_istr & (ISTR_INTS | ISTR_E_INT))) return true; break; case COMMODORE_8727: if (wd->cdmac.xt_irq) wd->cdmac.dmac_istr |= ISTR_INTS; if (wd->wc.auxstatus & ASR_INT) wd->cdmac.dmac_istr |= ISTR_INTS; if ((wd->cdmac.dmac_cntr & CNTR_INTEN) && (wd->cdmac.dmac_istr & ISTR_INTS)) return true; break; } return false; } static void set_dma_done(struct wd_state *wds) { switch (wds->dmac_type) { case GVP_DMAC_S1: case GVP_DMAC_S2: wds->gdmac.dma_on = -1; break; case COMMODORE_SDMAC: case COMMODORE_DMAC: case COMMODORE_8727: wds->cdmac.dmac_dma = -1; break; } } static bool is_dma_enabled(struct wd_state *wds) { switch (wds->dmac_type) { case GVP_DMAC_S1: return true; case GVP_DMAC_S2: return wds->gdmac.dma_on > 0; case COMMODORE_SDMAC: case COMMODORE_DMAC: case COMMODORE_8727: return wds->cdmac.dmac_dma > 0; } return false; } void rethink_a2091 (void) { for (int i = 0; i < MAX_SCSI_UNITS; i++) { if (scsi_units[i] && isirq(scsi_units[i])) { INTREQ_0(0x8000 | 0x0008); #if A2091_DEBUG > 2 || A3000_DEBUG > 2 write_log (_T("Interrupt_RETHINK\n")); #endif } } } static void dmac_scsi_int(struct wd_state *wd) { if (!wd->enabled) return; if (!(wd->wc.auxstatus & ASR_INT)) return; rethink_a2091(); } static void dmac_a2091_xt_int(struct wd_state *wd) { if (!wd->enabled) return; wd->cdmac.xt_irq = true; rethink_a2091(); } void scsi_dmac_a2091_start_dma (struct wd_state *wd) { #if A3000_DEBUG > 0 || A2091_DEBUG > 0 write_log (_T("DMAC DMA started, ADDR=%08X, LEN=%08X words\n"), wd->cdmac.dmac_acr, wd->cdmac.dmac_wtc); #endif wd->cdmac.dmac_dma = 1; } void scsi_dmac_a2091_stop_dma (struct wd_state *wd) { wd->cdmac.dmac_dma = 0; wd->cdmac.dmac_istr &= ~ISTR_E_INT; } static void dmac_reset (struct wd_state *wd) { #if WD33C93_DEBUG > 0 if (wd->dmac_type == COMMODORE_SDMAC) write_log (_T("A3000 %s SCSI reset\n"), WD33C93); else if (wd->dmac_type == COMMODORE_DMAC) write_log (_T("A2091 %s SCSI reset\n"), WD33C93); #endif } static void incsasr (struct wd_chip_state *wd, int w) { if (wd->sasr == WD_AUXILIARY_STATUS || wd->sasr == WD_DATA || wd->sasr == WD_COMMAND) return; if (w && wd->sasr == WD_SCSI_STATUS) return; wd->sasr++; wd->sasr &= 0x1f; } static void dmac_a2091_cint (struct wd_state *wd) { wd->cdmac.dmac_istr = 0; rethink_a2091 (); } static void doscsistatus(struct wd_state *wd, uae_u8 status) { wd->wc.wdregs[WD_SCSI_STATUS] = status; wd->wc.auxstatus |= ASR_INT; #if WD33C93_DEBUG > 1 write_log (_T("%s STATUS=%02X\n"), WD33C93, status); #endif if (!wd->enabled) return; if (wd->cdtv) { cdtv_scsi_int (); return; } dmac_scsi_int(wd); #if WD33C93_DEBUG > 2 write_log (_T("Interrupt\n")); #endif } static void set_status (struct wd_chip_state *wd, uae_u8 status, int delay) { if (wd->queue_index >= WD_STATUS_QUEUE) return; wd->scsidelay_status[wd->queue_index] = status; wd->scsidelay_irq[wd->queue_index] = delay == 0 ? 1 : (delay <= 2 ? 2 : delay); wd->queue_index++; } static void set_status (struct wd_chip_state *wd, uae_u8 status) { set_status (wd, status, 0); } static uae_u32 gettc (struct wd_chip_state *wd) { return wd->wdregs[WD_TRANSFER_COUNT_LSB] | (wd->wdregs[WD_TRANSFER_COUNT] << 8) | (wd->wdregs[WD_TRANSFER_COUNT_MSB] << 16); } static void settc (struct wd_chip_state *wd, uae_u32 tc) { wd->wdregs[WD_TRANSFER_COUNT_LSB] = tc & 0xff; wd->wdregs[WD_TRANSFER_COUNT] = (tc >> 8) & 0xff; wd->wdregs[WD_TRANSFER_COUNT_MSB] = (tc >> 16) & 0xff; } static bool decreasetc(struct wd_chip_state *wd) { uae_u32 tc = gettc (wd); if (!tc) return true; tc--; settc (wd, tc); return tc == 0; } static bool canwddma(struct wd_state *wds) { struct wd_chip_state *wd = &wds->wc; uae_u8 mode = wd->wdregs[WD_CONTROL] >> 5; switch(wds->dmac_type) { case COMMODORE_8727: if (mode != 0 && mode != 4) { write_log (_T("%s weird DMA mode %d!!\n"), WD33C93, mode); } return mode == 4; case COMMODORE_DMAC: case COMMODORE_SDMAC: case GVP_DMAC_S2: if (mode != 0 && mode != 4 && mode != 1) { write_log (_T("%s weird DMA mode %d!!\n"), WD33C93, mode); } return mode == 4 || mode == 1; case GVP_DMAC_S1: if (mode != 0 && mode != 2) { write_log (_T("%s weird DMA mode %d!!\n"), WD33C93, mode); } return mode == 2; default: return false; } } #if WD33C93_DEBUG > 0 static TCHAR *scsitostring (struct wd_chip_state *wd, struct scsi_data *scsi) { static TCHAR buf[200]; TCHAR *p; int i; p = buf; p[0] = 0; for (i = 0; i < scsi->offset && i < sizeof wd->wd_data; i++) { if (i > 0) { _tcscat (p, _T(".")); p++; } _stprintf (p, _T("%02X"), wd->wd_data[i]); p += _tcslen (p); } return buf; } #endif static void setphase(struct wd_chip_state *wd, uae_u8 phase) { wd->wdregs[WD_COMMAND_PHASE] = phase; } static bool dmacheck_a2091 (struct wd_state *wd) { wd->cdmac.dmac_acr++; if (wd->cdmac.old_dmac && (wd->cdmac.dmac_cntr & CNTR_TCEN)) { if (wd->cdmac.dmac_wtc == 0) { wd->cdmac.dmac_istr |= ISTR_E_INT; return true; } else { if ((wd->cdmac.dmac_acr & 1) == 1) wd->cdmac.dmac_wtc--; } } return false; } static bool dmacheck_a2090 (struct wd_state *wd) { int dir = wd->cdmac.dmac_acr & 0x00800000; wd->cdmac.dmac_acr &= 0x7fffff; wd->cdmac.dmac_acr++; wd->cdmac.dmac_acr &= 0x7fffff; wd->cdmac.dmac_acr |= dir; wd->cdmac.dmac_wtc--; return wd->cdmac.dmac_wtc == 0; } static bool do_dma_commodore_8727(struct wd_state *wd, struct scsi_data *scsi) { int dir = wd->cdmac.dmac_acr & 0x00800000; if (scsi->direction < 0) { if (dir) { write_log(_T("8727 mismatched direction!\n")); return false; } #if WD33C93_DEBUG > 0 uaecptr odmac_acr = wd->cdmac.dmac_acr; #endif for (;;) { uae_u8 v1 = 0, v2 = 0; int status; status = scsi_receive_data (scsi, &v1, true); if (!status) status = scsi_receive_data(scsi, &v2, true); put_word((wd->cdmac.dmac_acr << 1) & 0xffffff, (v1 << 8) | v2); if (wd->wc.wd_dataoffset < sizeof wd->wc.wd_data) { wd->wc.wd_data[wd->wc.wd_dataoffset++] = v1; wd->wc.wd_data[wd->wc.wd_dataoffset++] = v2; } if (decreasetc (&wd->wc)) break; if (decreasetc (&wd->wc)) break; if (status) break; if (dmacheck_a2090 (wd)) break; } #if WD33C93_DEBUG > 0 write_log (_T("%s Done DMA from WD, %d/%d %08X\n"), WD33C93, scsi->offset, scsi->data_len, (odmac_acr << 1) & 0xffffff); #endif return true; } else if (scsi->direction > 0) { if (!dir) { write_log(_T("8727 mismatched direction!\n")); return false; } #if WD33C93_DEBUG > 0 uaecptr odmac_acr = wd->cdmac.dmac_acr; #endif for (;;) { int status; uae_u16 v = get_word((wd->cdmac.dmac_acr << 1) & 0xffffff); if (wd->wc.wd_dataoffset < sizeof wd->wc.wd_data) { wd->wc.wd_data[wd->wc.wd_dataoffset++] = v >> 8; wd->wc.wd_data[wd->wc.wd_dataoffset++] = v; } status = scsi_send_data (scsi, v >> 8); if (!status) status = scsi_send_data (scsi, v); if (decreasetc (&wd->wc)) break; if (decreasetc (&wd->wc)) break; if (status) break; if (dmacheck_a2090 (wd)) break; } #if WD33C93_DEBUG > 0 write_log (_T("%s Done DMA to WD, %d/%d %08x\n"), WD33C93, scsi->offset, scsi->data_len, (odmac_acr << 1) & 0xffffff); #endif return true; } return false; } static bool do_dma_commodore(struct wd_state *wd, struct scsi_data *scsi) { if (wd->cdtv) cdtv_getdmadata(&wd->cdmac.dmac_acr); if (scsi->direction < 0) { #if WD33C93_DEBUG || XT_DEBUG > 0 uaecptr odmac_acr = wd->cdmac.dmac_acr; #endif bool run = true; while (run) { uae_u8 v; int status = scsi_receive_data(scsi, &v, true); put_byte(wd->cdmac.dmac_acr, v); if (wd->wc.wd_dataoffset < sizeof wd->wc.wd_data) wd->wc.wd_data[wd->wc.wd_dataoffset++] = v; if (decreasetc (&wd->wc)) run = false; if (dmacheck_a2091 (wd)) run = false; if (status) run = false; } #if WD33C93_DEBUG || XT_DEBUG > 0 write_log (_T("%s Done DMA from WD, %d/%d %08X\n"), WD33C93, scsi->offset, scsi->data_len, odmac_acr); #endif return true; } else if (scsi->direction > 0) { #if WD33C93_DEBUG || XT_DEBUG > 0 uaecptr odmac_acr = wd->cdmac.dmac_acr; #endif bool run = true; while (run) { int status; uae_u8 v = get_byte(wd->cdmac.dmac_acr); if (wd->wc.wd_dataoffset < sizeof wd->wc.wd_data) wd->wc.wd_data[wd->wc.wd_dataoffset++] = v; status = scsi_send_data (scsi, v); if (decreasetc (&wd->wc)) run = false; if (dmacheck_a2091 (wd)) run = false; if (status) run = false; } #if WD33C93_DEBUG || XT_DEBUG > 0 write_log (_T("%s Done DMA to WD, %d/%d %08x\n"), WD33C93, scsi->offset, scsi->data_len, odmac_acr); #endif return true; } return false; } static bool do_dma_gvp_s1(struct wd_state *wd, struct scsi_data *scsi) { if (scsi->direction < 0) { for (;;) { uae_u8 v; int status = scsi_receive_data(scsi, &v, true); wd->gdmac.buffer[wd->wc.wd_dataoffset++] = v; wd->wc.wd_dataoffset &= wd->gdmac.s1_rammask; if (decreasetc (&wd->wc)) break; if (status) break; } #if WD33C93_DEBUG > 0 write_log (_T("%s Done DMA from WD, %d/%d\n"), WD33C93, scsi->offset, scsi->data_len); #endif return true; } else if (scsi->direction > 0) { for (;;) { int status; uae_u8 v = wd->gdmac.buffer[wd->wc.wd_dataoffset++]; wd->wc.wd_dataoffset &= wd->gdmac.s1_rammask; status = scsi_send_data (scsi, v); wd->gdmac.addr++; if (decreasetc (&wd->wc)) break; if (status) break; } #if WD33C93_DEBUG > 0 write_log (_T("%s Done DMA to WD, %d/%d\n"), WD33C93, scsi->offset, scsi->data_len); #endif return true; } return false; } static bool do_dma_gvp_s2(struct wd_state *wd, struct scsi_data *scsi) { #if WD33C93_DEBUG > 0 uae_u32 dmaptr = wd->gdmac.addr; #endif if (!is_dma_enabled(wd)) return false; if (scsi->direction < 0) { if (wd->gdmac.cntr & 0x10) { write_log(_T("GVP DMA: mismatched direction when reading!\n")); return false; } for (;;) { uae_u8 v; int status = scsi_receive_data(scsi, &v, true); put_byte(wd->gdmac.addr, v); if (wd->wc.wd_dataoffset < sizeof wd->wc.wd_data) wd->wc.wd_data[wd->wc.wd_dataoffset++] = v; wd->gdmac.addr++; if (decreasetc (&wd->wc)) break; if (status) break; } #if WD33C93_DEBUG > 0 write_log (_T("%s Done DMA from WD, %d/%d %08x\n"), WD33C93, scsi->offset, scsi->data_len, dmaptr); #endif return true; } else if (scsi->direction > 0) { if (!(wd->gdmac.cntr & 0x10)) { write_log(_T("GVP DMA: mismatched direction when writing!\n")); return false; } for (;;) { int status; uae_u8 v = get_byte(wd->gdmac.addr); if (wd->wc.wd_dataoffset < sizeof wd->wc.wd_data) wd->wc.wd_data[wd->wc.wd_dataoffset++] = v; status = scsi_send_data (scsi, v); wd->gdmac.addr++; if (decreasetc (&wd->wc)) break; if (status) break; } #if WD33C93_DEBUG > 0 write_log (_T("%s Done DMA to WD, %d/%d %08x\n"), WD33C93, scsi->offset, scsi->data_len, dmaptr); #endif return true; } return false; } static bool do_dma(struct wd_state *wd) { struct scsi_data *scsi = wd->wc.scsi; wd->wc.wd_data_avail = 0; if (scsi->direction == 0) write_log (_T("%s DMA but no data!?\n"), WD33C93); switch (wd->dmac_type) { case COMMODORE_DMAC: case COMMODORE_SDMAC: return do_dma_commodore(wd, scsi); case COMMODORE_8727: return do_dma_commodore_8727(wd, scsi); case GVP_DMAC_S2: return do_dma_gvp_s2(wd, scsi); case GVP_DMAC_S1: return do_dma_gvp_s1(wd, scsi); } return false; } static bool wd_do_transfer_out (struct wd_chip_state *wd, struct scsi_data *scsi) { #if WD33C93_DEBUG > 0 write_log (_T("%s SCSI O [%02X] %d/%d TC=%d %s\n"), WD33C93, wd->wdregs[WD_COMMAND_PHASE], scsi->offset, scsi->data_len, gettc (wd), scsitostring (wd, scsi)); #endif if (wd->wdregs[WD_COMMAND_PHASE] < 0x20) { int msg = wd->wd_data[0]; /* message was sent */ setphase (wd, 0x20); wd->wd_phase = CSR_XFER_DONE | PHS_COMMAND; scsi->status = 0; scsi_start_transfer (scsi); #if WD33C93_DEBUG > 0 write_log (_T("%s SCSI got MESSAGE %02X\n"), WD33C93, msg); #endif scsi->message[0] = msg; } else if (wd->wdregs[WD_COMMAND_PHASE] == 0x30) { #if WD33C93_DEBUG > 0 write_log (_T("%s SCSI got COMMAND %02X\n"), WD33C93, wd->wd_data[0]); #endif if (scsi->offset < scsi->data_len) { // data missing, ask for more wd->wd_phase = CSR_XFER_DONE | PHS_COMMAND; setphase (wd, 0x30 + scsi->offset); set_status (wd, wd->wd_phase, 1); return false; } settc (wd, 0); scsi_start_transfer (scsi); scsi_emulate_analyze (scsi); if (scsi->direction > 0) { /* if write command, need to wait for data */ if (scsi->data_len <= 0 || scsi->direction == 0) { // Status phase if command didn't return anything and don't want anything wd->wd_phase = CSR_XFER_DONE | PHS_STATUS; setphase (wd, 0x46); } else { wd->wd_phase = CSR_XFER_DONE | PHS_DATA_OUT; setphase (wd, 0x45); } } else { scsi_emulate_cmd (scsi); if (wd->scsi->data_len <= 0 || scsi->direction == 0) { // Status phase if command didn't return anything and don't want anything wd->wd_phase = CSR_XFER_DONE | PHS_STATUS; setphase (wd, 0x46); } else { wd->wd_phase = CSR_XFER_DONE | PHS_DATA_IN; setphase (wd, 0x45); // just skip all reselection and message stuff for now.. } } } else if (wd->wdregs[WD_COMMAND_PHASE] == 0x46 || wd->wdregs[WD_COMMAND_PHASE] == 0x45) { if (wd->scsi->offset < scsi->data_len) { // data missing, ask for more wd->wd_phase = CSR_XFER_DONE | (scsi->direction < 0 ? PHS_DATA_IN : PHS_DATA_OUT); set_status (wd, wd->wd_phase, 10); return false; } settc (wd, 0); if (scsi->direction > 0) { /* data was sent */ scsi_emulate_cmd (scsi); scsi->data_len = 0; wd->wd_phase = CSR_XFER_DONE | PHS_STATUS; } scsi_start_transfer (scsi); setphase (wd, 0x47); } wd->wd_dataoffset = 0; set_status (wd, wd->wd_phase, scsi->direction <= 0 ? 0 : 1); wd->wd_busy = 0; return true; } static bool wd_do_transfer_in (struct wd_chip_state *wd, struct scsi_data *scsi, bool message_in_transfer_info) { #if WD33C93_DEBUG > 0 write_log (_T("%s SCSI I [%02X] %d/%d TC=%d %s\n"), WD33C93, wd->wdregs[WD_COMMAND_PHASE], scsi->offset, scsi->data_len, gettc (wd), scsitostring (wd, scsi)); #endif wd->wd_dataoffset = 0; if (wd->wdregs[WD_COMMAND_PHASE] >= 0x36 && wd->wdregs[WD_COMMAND_PHASE] < 0x46) { if (scsi->offset < scsi->data_len) { // data missing, ask for more wd->wd_phase = CSR_XFER_DONE | (scsi->direction < 0 ? PHS_DATA_IN : PHS_DATA_OUT); set_status(wd, wd->wd_phase, 1); return false; } if (gettc (wd) != 0) { wd->wd_phase = CSR_UNEXP | PHS_STATUS; setphase(wd, 0x46); } else { wd->wd_phase = CSR_XFER_DONE | PHS_STATUS; setphase(wd, 0x46); } scsi_start_transfer(scsi); } else if (wd->wdregs[WD_COMMAND_PHASE] == 0x46 || wd->wdregs[WD_COMMAND_PHASE] == 0x47) { setphase(wd, 0x50); wd->wd_phase = CSR_XFER_DONE | PHS_MESS_IN; scsi_start_transfer(scsi); } else if (wd->wdregs[WD_COMMAND_PHASE] == 0x50) { // was TRANSFER INFO with message phase, wait for Negate ACK if (!message_in_transfer_info) { wd->wd_phase = CSR_DISC; wd->wd_selected = false; scsi_start_transfer(scsi); setphase(wd, 0x60); } else { wd->wd_phase = CSR_MSGIN; } } set_status(wd, wd->wd_phase, 1); scsi->direction = 0; return true; } static void wd_cmd_sel_xfer (struct wd_chip_state *wd, struct wd_state *wds, bool atn) { int i, tmp_tc; int delay = 0; struct scsi_data *scsi; wd->wd_data_avail = 0; tmp_tc = gettc (wd); scsi = wd->scsi = wds->scsis[wd->wdregs[WD_DESTINATION_ID] & 7]; if (!scsi) { set_status (wd, CSR_TIMEOUT, 0); wd->wdregs[WD_COMMAND_PHASE] = 0x00; #if WD33C93_DEBUG > 0 write_log (_T("* %s select and transfer%s, ID=%d: No device\n"), WD33C93, atn ? _T(" with atn") : _T(""), wd->wdregs[WD_DESTINATION_ID] & 0x7); #endif return; } if (!wd->wd_selected) { scsi->message[0] = 0x80; wd->wd_selected = true; wd->wdregs[WD_COMMAND_PHASE] = 0x10; } #if WD33C93_DEBUG > 0 write_log (_T("* %s select and transfer%s, ID=%d PHASE=%02X TC=%d wddma=%d dmac=%d\n"), WD33C93, atn ? _T(" with atn") : _T(""), wd->wdregs[WD_DESTINATION_ID] & 0x7, wd->wdregs[WD_COMMAND_PHASE], tmp_tc, wd->wdregs[WD_CONTROL] >> 5, wds->cdmac.dmac_dma); #endif if (wd->wdregs[WD_COMMAND_PHASE] <= 0x30) { scsi->buffer[0] = 0; scsi->status = 0; memcpy (scsi->cmd, &wd->wdregs[3], 16); scsi->data_len = tmp_tc; scsi_emulate_analyze (scsi); settc (wd, scsi->cmd_len); wd->wd_dataoffset = 0; scsi_start_transfer (scsi); scsi->direction = 2; scsi->data_len = scsi->cmd_len; for (i = 0; i < gettc (wd); i++) { uae_u8 b = scsi->cmd[i]; wd->wd_data[i] = b; scsi_send_data (scsi, b); wd->wd_dataoffset++; } // 0x30 = command phase has started scsi->data_len = tmp_tc; #if WD33C93_DEBUG > 0 write_log (_T("%s: Got Command %s, datalen=%d\n"), WD33C93, scsitostring (wd, scsi), scsi->data_len); #endif if (!scsi_emulate_analyze (scsi)) { wd->wdregs[WD_COMMAND_PHASE] = 0x46; goto end; } wd->wdregs[WD_COMMAND_PHASE] = 0x30 + gettc (wd); settc (wd, 0); if (scsi->direction <= 0) { scsi_emulate_cmd (scsi); } scsi_start_transfer (scsi); } if (wd->wdregs[WD_COMMAND_PHASE] <= 0x41) { wd->wdregs[WD_COMMAND_PHASE] = 0x44; #if 0 if (wd->wdregs[WD_CONTROL] & CTL_IDI) { wd->wd_phase = CSR_DISC; set_status (wd, wd->wd_phase, delay); wd->wd_phase = CSR_RESEL; set_status (wd, wd->wd_phase, delay + 10); return; } #endif wd->wdregs[WD_COMMAND_PHASE] = 0x44; } // target replied or start/continue data phase (if data available) if (wd->wdregs[WD_COMMAND_PHASE] == 0x44) { wd->wdregs[WD_COMMAND_PHASE] = 0x45; } if (wd->wdregs[WD_COMMAND_PHASE] == 0x45) { settc (wd, tmp_tc); wd->wd_dataoffset = 0; setphase (wd, 0x45); if (gettc (wd) == 0) { if (scsi->direction != 0) { // TC = 0 but we may have data if (scsi->direction < 0) { if (scsi->data_len == 0 || scsi->offset >= scsi->data_len) { // no data, continue normally to status phase setphase (wd, 0x46); goto end; } } wd->wd_phase = CSR_UNEXP; if (scsi->direction < 0) wd->wd_phase |= PHS_DATA_IN; else wd->wd_phase |= PHS_DATA_OUT; set_status (wd, wd->wd_phase, 1); return; } } if (wd->scsi->direction) { // wanted data but nothing available? if (scsi->direction < 0 && scsi->data_len == 0 && gettc(wd)) { setphase(wd, 0x46); wd->wd_phase = CSR_UNEXP | PHS_STATUS; set_status (wd, wd->wd_phase, 1); return; } if (canwddma (wds)) { if (scsi->direction <= 0) { do_dma(wds); if (scsi->offset < scsi->data_len) { // buffer not completely retrieved? wd->wd_phase = CSR_UNEXP | PHS_DATA_IN; set_status (wd, wd->wd_phase, 1); return; } if (gettc (wd) > 0) { // requested more data than was available. setphase(wd, 0x46); wd->wd_phase = CSR_UNEXP | PHS_STATUS; set_status (wd, wd->wd_phase, 1); return; } setphase (wd, 0x46); } else { if (do_dma(wds)) { setphase (wd, 0x46); if (scsi->offset < scsi->data_len) { // not enough data? wd->wd_phase = CSR_UNEXP | PHS_DATA_OUT; set_status (wd, wd->wd_phase, 1); return; } // got all data -> execute it scsi_emulate_cmd (scsi); } } } else { // no dma = Service Request wd->wd_phase = CSR_SRV_REQ; if (scsi->direction < 0) wd->wd_phase |= PHS_DATA_IN; else wd->wd_phase |= PHS_DATA_OUT; set_status (wd, wd->wd_phase, 1); return; } } else { // TC > 0 but no data to transfer if (gettc (wd)) { wd->wd_phase = CSR_UNEXP | PHS_STATUS; set_status (wd, wd->wd_phase, 1); return; } setphase(wd, 0x46); } } end: if (wd->wdregs[WD_COMMAND_PHASE] == 0x46) { scsi->buffer[0] = 0; wd->wdregs[WD_COMMAND_PHASE] = 0x50; wd->wdregs[WD_TARGET_LUN] = scsi->status; scsi->buffer[0] = scsi->status; } // 0x60 = command complete wd->wdregs[WD_COMMAND_PHASE] = 0x60; if (!(wd->wdregs[WD_CONTROL] & CTL_EDI)) { wd->wd_phase = CSR_SEL_XFER_DONE; delay += 2; set_status (wd, wd->wd_phase, delay); delay += 2; wd->wd_phase = CSR_DISC; set_status (wd, wd->wd_phase, delay); } else { delay += 2; wd->wd_phase = CSR_SEL_XFER_DONE; set_status (wd, wd->wd_phase, delay); } wd->wd_selected = 0; } static void wd_cmd_trans_info (struct wd_state *wds, struct scsi_data *scsi, bool pad) { struct wd_chip_state *wd = &wds->wc; if (wd->wdregs[WD_COMMAND_PHASE] == 0x20) { wd->wdregs[WD_COMMAND_PHASE] = 0x30; scsi->status = 0; } wd->wd_busy = 1; if (wd->wdregs[WD_COMMAND] & 0x80) settc (wd, 1); if (gettc (wd) == 0) settc (wd, 1); wd->wd_dataoffset = 0; if (wd->wdregs[WD_COMMAND_PHASE] == 0x30) { scsi->direction = 2; // command scsi->cmd_len = scsi->data_len = gettc (wd); } else if (wd->wdregs[WD_COMMAND_PHASE] == 0x10) { scsi->direction = 1; // message scsi->data_len = gettc (wd); } else if (wd->wdregs[WD_COMMAND_PHASE] == 0x45) { scsi_emulate_analyze (scsi); } else if (wd->wdregs[WD_COMMAND_PHASE] == 0x46 || wd->wdregs[WD_COMMAND_PHASE] == 0x47) { scsi->buffer[0] = scsi->status; wd->wdregs[WD_TARGET_LUN] = scsi->status; scsi->direction = -1; // status scsi->data_len = 1; } else if (wd->wdregs[WD_COMMAND_PHASE] == 0x50) { scsi->direction = -1; scsi->data_len = gettc (wd); } if (pad) { int v; settc(wd, 0); if (wd->scsi->direction < 0) { v = wd_do_transfer_in (wd, wd->scsi, false); } else if (wd->scsi->direction > 0) { v = wd_do_transfer_out (wd, wd->scsi); } wd->scsi->direction = 0; wd->wd_data_avail = 0; } else { if (canwddma (wds)) { wd->wd_data_avail = -1; } else { wd->wd_data_avail = 1; } } #if WD33C93_DEBUG > 0 write_log (_T("* %s transfer info phase=%02x TC=%d dir=%d data=%d/%d wddma=%d\n"), WD33C93, wd->wdregs[WD_COMMAND_PHASE], gettc (wd), scsi->direction, scsi->offset, scsi->data_len, wd->wdregs[WD_CONTROL] >> 5); #endif } /* Weird stuff, XT driver (which has nothing to do with SCSI or WD33C93) uses this WD33C93 command! */ static void wd_cmd_trans_addr(struct wd_chip_state *wd, struct wd_state *wds) { uae_u32 tcyls = (wd->wdregs[WD_T_CYLS_0] << 8) | wd->wdregs[WD_T_CYLS_1]; uae_u32 theads = wd->wdregs[WD_T_HEADS]; uae_u32 tsectors = wd->wdregs[WD_T_SECTORS]; uae_u32 lba = (wd->wdregs[WD_L_ADDR_0] << 24) | (wd->wdregs[WD_L_ADDR_1] << 16) | (wd->wdregs[WD_L_ADDR_2] << 8) | (wd->wdregs[WD_L_ADDR_3] << 0); uae_u32 cyls, heads, sectors; cyls = lba / (theads * tsectors); heads = (lba - ((cyls * theads * tsectors))) / tsectors; sectors = (lba - ((cyls * theads * tsectors))) % tsectors; write_log(_T("WD TRANS ADDR: LBA=%d TC=%d TH=%d TS=%d -> C=%d H=%d S=%d\n"), lba, tcyls, theads, tsectors, cyls, heads, sectors); wd->wdregs[WD_CYL_0] = cyls >> 8; wd->wdregs[WD_CYL_1] = cyls; wd->wdregs[WD_HEAD] = heads; wd->wdregs[WD_SECTOR] = sectors; if (cyls >= tcyls) set_status(wd, CSR_BAD_STATUS); else set_status(wd, CSR_TRANS_ADDR); } static void wd_cmd_sel (struct wd_chip_state *wd, struct wd_state *wds, bool atn) { struct scsi_data *scsi; #if WD33C93_DEBUG > 0 write_log (_T("* %s select%s, ID=%d\n"), WD33C93, atn ? _T(" with atn") : _T(""), wd->wdregs[WD_DESTINATION_ID] & 0x7); #endif wd->wd_phase = 0; wd->wdregs[WD_COMMAND_PHASE] = 0; scsi = wd->scsi = wds->scsis[wd->wdregs[WD_DESTINATION_ID] & 7]; if (!scsi || (wd->wdregs[WD_DESTINATION_ID] & 7) == 7) { #if WD33C93_DEBUG > 0 write_log (_T("%s no drive\n"), WD33C93); #endif set_status (wd, CSR_TIMEOUT, 1000); return; } scsi_start_transfer (wd->scsi); wd->wd_selected = true; scsi->message[0] = 0x80; set_status (wd, CSR_SELECT, 2); if (atn) { wd->wdregs[WD_COMMAND_PHASE] = 0x10; set_status (wd, CSR_SRV_REQ | PHS_MESS_OUT, 4); } else { wd->wdregs[WD_COMMAND_PHASE] = 0x20; set_status (wd, CSR_SRV_REQ | PHS_COMMAND, 4); } } static void wd_cmd_reset (struct wd_chip_state *wd, bool irq) { int i; #if WD33C93_DEBUG > 0 if (irq) write_log (_T("%s reset\n"), WD33C93); #endif for (i = 1; i < 0x16; i++) wd->wdregs[i] = 0; wd->wdregs[0x18] = 0; wd->sasr = 0; wd->wd_selected = false; wd->scsi = NULL; wd->scsidelay_irq[0] = 0; wd->scsidelay_irq[1] = 0; wd->queue_index = 0; wd->auxstatus = 0; wd->wd_data_avail = 0; if (irq) { set_status (wd, (wd->wdregs[0] & 0x08) ? 1 : 0, 50); } } static void wd_master_reset(struct wd_state *wd, bool irq) { memset(wd->wc.wdregs, 0, sizeof wd->wc.wdregs); wd_cmd_reset(&wd->wc, false); if (irq) doscsistatus(wd, 0); } static void wd_cmd_abort (struct wd_chip_state *wd) { #if WD33C93_DEBUG > 0 write_log (_T("%s abort\n"), WD33C93); #endif } static void xt_command_done(struct wd_state *wd); static void wd_check_interrupt(struct wd_state *wds, bool checkonly) { struct wd_chip_state *wd = &wds->wc; if (wd->auxstatus & ASR_INT) return; if (wd->queue_index == 0) return; if (wd->scsidelay_irq[0] == 1) { wd->scsidelay_irq[0] = 0; doscsistatus(wds, wd->scsidelay_status[0]); wd->wd_busy = 0; if (wd->queue_index == 2) { wd->scsidelay_irq[0] = 1; wd->scsidelay_status[0] = wd->scsidelay_status[1]; wd->queue_index = 1; } else { wd->queue_index = 0; } } else if (!checkonly && wd->scsidelay_irq[0] > 1) { wd->scsidelay_irq[0]--; } } static void scsi_hsync_check_dma(struct wd_state *wds) { struct wd_chip_state *wd = &wds->wc; if (wd->wd_data_avail < 0 && is_dma_enabled(wds)) { bool v; do_dma(wds); if (wd->scsi->direction < 0) { v = wd_do_transfer_in (wd, wd->scsi, false); } else if (wd->scsi->direction > 0) { v = wd_do_transfer_out (wd, wd->scsi); } else { write_log (_T("%s data transfer attempt without data!\n"), WD33C93); v = true; } if (v) { wd->scsi->direction = 0; wd->wd_data_avail = 0; } else { set_dma_done(wds); } } } static void scsi_hsync2_a2091 (struct wd_state *wds) { struct wd_chip_state *wd = &wds->wc; if (!wds || !wds->enabled) return; scsi_hsync_check_dma(wds); if (wds->cdmac.dmac_dma > 0 && (wds->cdmac.xt_control & XT_DMA_MODE) && (wds->cdmac.xt_status & (XT_STAT_INPUT | XT_STAT_REQUEST) && !(wds->cdmac.xt_status & XT_STAT_COMMAND))) { wd->scsi = wds->scsis[XT_UNIT]; if (do_dma(wds)) { xt_command_done(wds); } } wd_check_interrupt(wds, false); } static void scsi_hsync2_gvp (struct wd_state *wds) { if (!wds || !wds->enabled) return; scsi_hsync_check_dma(wds); wd_check_interrupt(wds, false); } void scsi_hsync (void) { for (int i = 0; i < MAX_DUPLICATE_EXPANSION_BOARDS; i++) { scsi_hsync2_a2091(wd_a2091[i]); scsi_hsync2_a2091(wd_a2090[i]); scsi_hsync2_gvp(wd_gvps1[i]); scsi_hsync2_gvp(wd_gvps2[i]); } scsi_hsync2_gvp(wd_gvps2accel); scsi_hsync2_a2091(wd_a3000); scsi_hsync2_a2091(wd_cdtv); } static int writeonlyreg (int reg) { if (reg == WD_SCSI_STATUS) return 1; return 0; } static uae_u32 makecmd (struct scsi_data *s, int msg, uae_u8 cmd) { uae_u32 v = 0; if (s) v |= s->id << 24; v |= msg << 8; v |= cmd; return v; } static void writewdreg (struct wd_chip_state *wd, int sasr, uae_u8 val) { switch (sasr) { case WD_OWN_ID: if (wd->wd33c93_ver == 0) val &= ~(0x20 | 0x08); else if (wd->wd33c93_ver == 1) val &= ~0x20; break; } if (sasr > WD_QUEUE_TAG && sasr < WD_AUXILIARY_STATUS) return; // queue tag is B revision only if (sasr == WD_QUEUE_TAG && wd->wd33c93_ver < 2) return; wd->wdregs[sasr] = val; } void wdscsi_put (struct wd_chip_state *wd, struct wd_state *wds, uae_u8 d) { #if WD33C93_DEBUG > 1 if (WD33C93_DEBUG > 3 || wd->sasr != WD_DATA) write_log (_T("W %s REG %02X = %02X (%d) PC=%08X\n"), WD33C93, wd->sasr, d, d, M68K_GETPC); #endif if (!writeonlyreg (wd->sasr)) { writewdreg (wd, wd->sasr, d); } if (!wd->wd_used) { wd->wd_used = 1; write_log (_T("%s %s in use\n"), wds->bank ? wds->bank->name : _T("built-in"), WD33C93); } if (wd->sasr == WD_COMMAND_PHASE) { #if WD33C93_DEBUG > 1 write_log (_T("%s PHASE=%02X\n"), WD33C93, d); #endif ; } else if (wd->sasr == WD_DATA) { #if WD33C93_DEBUG_PIO write_log (_T("%s WD_DATA WRITE %02x %d/%d\n"), WD33C93, d, wd->scsi->offset, wd->scsi->data_len); #endif if (!wd->wd_data_avail) { write_log (_T("%s WD_DATA WRITE without data request!?\n"), WD33C93); return; } if (wd->wd_dataoffset < sizeof wd->wd_data) wd->wd_data[wd->wd_dataoffset] = wd->wdregs[wd->sasr]; wd->wd_dataoffset++; decreasetc (wd); wd->wd_data_avail = 1; if (scsi_send_data (wd->scsi, wd->wdregs[wd->sasr]) || gettc (wd) == 0) { wd->wd_data_avail = 0; write_comm_pipe_u32 (&wds->requests, makecmd (wd->scsi, 2, 0), 1); } } else if (wd->sasr == WD_COMMAND) { wd->wd_busy = true; write_comm_pipe_u32(&wds->requests, makecmd(wds->scsis[wd->wdregs[WD_DESTINATION_ID] & 7], 0, d), 1); if (wd->scsi && wd->scsi->cd_emu_unit >= 0) gui_flicker_led (LED_CD, wd->scsi->id, 1); } incsasr (wd, 1); } void wdscsi_sasr (struct wd_chip_state *wd, uae_u8 b) { wd->sasr = b; } uae_u8 wdscsi_getauxstatus (struct wd_chip_state *wd) { return (wd->auxstatus & ASR_INT) | (wd->wd_busy || wd->wd_data_avail < 0 ? ASR_BSY : 0) | (wd->wd_data_avail != 0 ? ASR_DBR : 0); } uae_u8 wdscsi_get (struct wd_chip_state *wd, struct wd_state *wds) { uae_u8 v; #if WD33C93_DEBUG > 1 uae_u8 osasr = wd->sasr; #endif v = wd->wdregs[wd->sasr]; if (wd->sasr == WD_DATA) { if (!wd->wd_data_avail) { write_log (_T("%s WD_DATA READ without data request!?\n"), WD33C93); return 0; } int status = scsi_receive_data(wd->scsi, &v, true); #if WD33C93_DEBUG_PIO write_log (_T("%s WD_DATA READ %02x %d/%d\n"), WD33C93, v, wd->scsi->offset, wd->scsi->data_len); #endif if (wd->wd_dataoffset < sizeof wd->wd_data) wd->wd_data[wd->wd_dataoffset] = v; wd->wd_dataoffset++; decreasetc (wd); wd->wdregs[wd->sasr] = v; wd->wd_data_avail = 1; if (status || gettc (wd) == 0) { wd->wd_data_avail = 0; write_comm_pipe_u32 (&wds->requests, makecmd (wd->scsi, 3, 0), 1); } } else if (wd->sasr == WD_SCSI_STATUS) { wd->auxstatus &= ~0x80; if (wds->cdtv) cdtv_scsi_clear_int (); wds->cdmac.dmac_istr &= ~ISTR_INTS; wd_check_interrupt(wds, true); #if 0 if (wd->wdregs[WD_COMMAND_PHASE] == 0x10) { wd->wdregs[WD_COMMAND_PHASE] = 0x11; wd->wd_phase = CSR_SRV_REQ | PHS_MESS_OUT; set_status (wd, wd->wd_phase, 1); } #endif } else if (wd->sasr == WD_AUXILIARY_STATUS) { v = wdscsi_getauxstatus (wd); } incsasr (wd, 0); #if WD33C93_DEBUG > 1 if (WD33C93_DEBUG > 3 || osasr != WD_DATA) write_log (_T("R %s REG %02X = %02X (%d) PC=%08X\n"), WD33C93, osasr, v, v, M68K_GETPC); #endif return v; } /* A590 XT */ static void xt_default_geometry(struct wd_state *wds) { wds->cdmac.xt_cyls = wds->wc.scsi->hfd->cyls > 1023 ? 1023 : wds->wc.scsi->hfd->cyls; wds->cdmac.xt_heads = wds->wc.scsi->hfd->heads > 31 ? 31 : wds->wc.scsi->hfd->heads; wds->cdmac.xt_sectors = wds->wc.scsi->hfd->secspertrack; write_log(_T("XT Default CHS %d %d %d\n"), wds->cdmac.xt_cyls, wds->cdmac.xt_heads, wds->cdmac.xt_sectors); } static void xt_set_status(struct wd_state *wds, uae_u8 state) { wds->cdmac.xt_status = state; wds->cdmac.xt_status |= XT_STAT_SELECT; wds->cdmac.xt_status |= XT_STAT_READY; } static void xt_reset(struct wd_state *wds) { wds->wc.scsi = wds->scsis[XT_UNIT]; if (!wds->wc.scsi) return; wds->cdmac.xt_control = 0; wds->cdmac.xt_datalen = 0; wds->cdmac.xt_status = 0; xt_default_geometry(wds); write_log(_T("XT reset\n")); } static void xt_command_done(struct wd_state *wds) { struct scsi_data *scsi = wds->scsis[XT_UNIT]; if (scsi->direction > 0) { if (scsi->cmd[0] == 0x0c) { xt_default_geometry(wds); int size = wds->cdmac.xt_cyls * wds->cdmac.xt_heads * wds->cdmac.xt_sectors; wds->cdmac.xt_heads = scsi->buffer[2] & 0x1f; wds->cdmac.xt_cyls = (scsi->buffer[0] << 8) | scsi->buffer[1]; wds->cdmac.xt_sectors = size / (wds->cdmac.xt_cyls * wds->cdmac.xt_heads); write_log(_T("XT_SETPARAM: Cyls=%d Heads=%d Sectors=%d\n"), wds->cdmac.xt_cyls, wds->cdmac.xt_heads, wds->cdmac.xt_sectors); for (int i = 0; i < 8; i++) { write_log(_T("%02X "), scsi->buffer[i]); } write_log(_T("\n")); } else { scsi_emulate_cmd(scsi); } } xt_set_status(wds, XT_STAT_INTERRUPT); if (wds->cdmac.xt_control & XT_INT) dmac_a2091_xt_int(wds); wds->cdmac.xt_datalen = 0; wds->cdmac.xt_statusbyte = 0; #if XT_DEBUG > 0 write_log(_T("XT command %02x done\n"), wds->cdmac.xt_cmd[0]); #endif } static void xt_wait_data(struct wd_state *wds, int len) { xt_set_status(wds, XT_STAT_REQUEST); wds->cdmac.xt_offset = 0; wds->cdmac.xt_datalen = len; } static void xt_command(struct wd_state *wds) { wds->wc.scsi = wds->scsis[XT_UNIT]; struct scsi_data *scsi = wds->scsis[XT_UNIT]; #if XT_DEBUG > 0 write_log(_T("XT command %02x. DMA=%d\n"), wds->cdmac.xt_cmd[0], (wds->cdmac.xt_control & XT_DMA_MODE) ? 1 : 0); #endif memcpy(scsi->cmd, wds->cdmac.xt_cmd, 6); scsi->data_len = -1; wds->cdmac.xt_offset = 0; scsi_emulate_analyze(scsi); scsi_start_transfer(scsi); if (scsi->direction > 0) { xt_set_status(wds, XT_STAT_REQUEST); } else if (scsi->direction < 0) { scsi_emulate_cmd(scsi); xt_set_status(wds, XT_STAT_INPUT); } else { xt_command_done(wds); } wds->cdmac.xt_datalen = scsi->data_len; settc(&wds->wc, scsi->data_len); } static uae_u8 read_xt_reg(struct wd_state *wds, int reg) { uae_u8 v = 0xff; wds->wc.scsi = wds->scsis[XT_UNIT]; if (!wds->wc.scsi) return v; switch(reg) { case XD_DATA: if (wds->cdmac.xt_status & XT_STAT_INPUT) { v = wds->wc.scsi->buffer[wds->cdmac.xt_offset]; #if XT_DEBUG > 1 write_log(_T("XT data read %02X (%d/%d)\n"), v, wds->cdmac.xt_offset, wds->cdmac.xt_datalen); #endif wds->cdmac.xt_offset++; if (wds->cdmac.xt_offset >= wds->cdmac.xt_datalen) { xt_command_done(wds); } } else { v = wds->cdmac.xt_statusbyte; #if XT_DEBUG > 1 write_log(_T("XT status byte read %02X\n"), v); #endif } break; case XD_STATUS: v = wds->cdmac.xt_status; break; case XD_JUMPER: // 20M: 2 40M: 0, xt.device checks it. v = wds->wc.scsi->hfd->size >= 41615 * 2 * 512 ? 0 : 2; break; case XD_RESERVED: break; } #if XT_DEBUG > 2 write_log(_T("XT read %d: %02X\n"), reg, v); #endif return v; } static void write_xt_reg(struct wd_state *wds, int reg, uae_u8 v) { wds->wc.scsi = wds->scsis[XT_UNIT]; if (!wds->wc.scsi) return; #if XT_DEBUG > 2 write_log(_T("XT write %d: %02X\n"), reg, v); #endif switch (reg) { case XD_DATA: if (!(wds->cdmac.xt_status & XT_STAT_REQUEST)) { wds->cdmac.xt_offset = 0; xt_set_status(wds, XT_STAT_COMMAND | XT_STAT_REQUEST); } if (wds->cdmac.xt_status & XT_STAT_REQUEST) { if (wds->cdmac.xt_status & XT_STAT_COMMAND) { #if XT_DEBUG > 1 write_log(_T("XT command write %02X (%d/6)\n"), v, wds->cdmac.xt_offset); #endif wds->cdmac.xt_cmd[wds->cdmac.xt_offset++] = v; xt_set_status(wds, XT_STAT_COMMAND | XT_STAT_REQUEST); if (wds->cdmac.xt_offset == 6) { xt_command(wds); } } else { #if XT_DEBUG > 1 write_log(_T("XT data write %02X (%d/6)\n"), v, wds->cdmac.xt_offset, wds->cdmac.xt_datalen); #endif wds->wc.scsi->buffer[wds->cdmac.xt_offset] = v; wds->cdmac.xt_offset++; if (wds->cdmac.xt_offset >= wds->cdmac.xt_datalen) { xt_command_done(wds); } } #if XT_DEBUG > 1 } else { write_log(_T("XT data write without REQUEST %02X\n"), v); #endif } break; case XD_RESET: xt_reset(wds); break; case XD_SELECT: #if XT_DEBUG > 1 write_log(_T("XT select %02X\n"), v); #endif xt_set_status(wds, XT_STAT_SELECT); break; case XD_CONTROL: #if XT_DEBUG > 1 if ((v & XT_DMA_MODE) != (wds->cdmac.xt_control & XT_DMA_MODE)) write_log(_T("XT DMA mode=%d\n"), (v & XT_DMA_MODE) ? 1 : 0); if ((v & XT_INT) != (wds->cdmac.xt_control & XT_INT)) write_log(_T("XT IRQ mode=%d\n"), (v & XT_INT) ? 1 : 0); #endif wds->cdmac.xt_control = v; wds->cdmac.xt_irq = 0; break; } } /* 8727 DMAC */ static uae_u8 dmac8727_read_pcss(struct wd_state *wd) { uae_u8 v; v = wd->cdmac.c8727_pcss; #if A2091_DEBUG_IO > 0 write_log(_T("dmac8727_read_pcss %02x\n"), v); #endif return v; } static void dmac8727_write_pcss(struct wd_state *wd, uae_u8 v) { wd->cdmac.c8727_pcss = v; #if A2091_DEBUG_IO > 0 write_log(_T("dmac8727_write_pcss %02x\n"), v); #endif } static uae_u8 dmac8727_read_pcsd(struct wd_state *wd) { struct commodore_dmac *c = &wd->cdmac; uae_u8 v = 0; if (!(c->c8727_pcss & 8)) { // 0xF7 1111 0111 wd->cdmac.dmac_dma = 1; } if (!(c->c8727_pcss & 0x10)) { // 0xEF 1110 1111 // dma complete, no overflow v = (1 << 7) | (1 << 5); } return v; } static void dmac8727_write_pcsd(struct wd_state *wd, uae_u8 v) { struct commodore_dmac *c = &wd->cdmac; if (!(c->c8727_pcss & 4)) { // 0xFB 1111 1011 c->dmac_acr &= 0xff00ffff; c->dmac_acr |= v << 16; } if (!(c->c8727_pcss & 2)) { // 0xFD 1111 1101 c->dmac_acr &= 0xffff00ff; c->dmac_acr |= v << 8; } if (!(c->c8727_pcss & 1)) { // 0xFE 1111 1110 c->dmac_acr &= 0xffffff00; c->dmac_acr |= v << 0; c->dmac_wtc = 65535; } #if 0 if (!(c->c8727_pcss & 8)) { // 0xF7 1111 0111 } #endif if (!(c->c8727_pcss & 0x80)) { c->dmac_dma = 0; } #if 0 switch (c->c8727_pcss) { case 0x7f: case 0xff: c->dmac_dma = 0; break; } #endif } static void dmac8727_cbp(struct wd_state *wd) { struct commodore_dmac *c = &wd->cdmac; c->c8727_st506_cb >>= 8; c->c8727_st506_cb |= c->c8727_wrcbp << 8; } static void a2090_st506(struct wd_state *wd, uae_u8 b) { uae_u8 cb[16]; if (!b) { wd->cdmac.dmac_istr &= ~(ISTR_INT_F | ISTR_INTS); return; } uaecptr cbp = wd->cdmac.c8727_st506_cb << 9; if (!valid_address(cbp, 16)) { write_log(_T("Invalid ST-506 command block address %08x\n"), cb); return; } for (int i = 0; i < sizeof cb; i++) { cb[i] = get_byte(cbp + i); } int unit = (cb[1] >> 5) & 1; // new command? if (cb[12] != 0xff) return; uaecptr dmaaddr = (cb[6] << 16) | (cb[7] << 8) | cb[8]; memset(cb + 12, 0, 4); struct scsi_data *scsi = wd->scsis[XT506_UNIT0 + unit]; if (scsi) { memcpy(scsi->cmd, cb, 6); // We handle LUN, not SCSI emulation. scsi->cmd[1] &= ~0x20; scsi->cmd_len = 6; scsi_emulate_analyze(scsi); if (scsi->direction < 0) { scsi_emulate_cmd(scsi); for (int i = 0; i < scsi->data_len; i++) { put_byte(dmaaddr + i, scsi->buffer[i]); } } else { for (int i = 0; i < scsi->data_len; i++) { scsi->buffer[i] = get_byte(dmaaddr + i); } scsi_emulate_cmd(scsi); } if (scsi->status && scsi->sense_len) { memcpy(cb + 12, scsi->sense, 4); } } else { cb[12] = 0x04; // Drive not ready cb[13] = cb[1]; cb[14] = cb[2]; cb[15] = cb[3]; } for (int i = 0; i < sizeof cb; i++) { put_byte(cbp + i, cb[i]); } set_dma_done(wd); wd->cdmac.xt_irq = true; } static uae_u32 dmac_a2091_read_word (struct wd_state *wd, uaecptr addr) { uae_u32 v = 0; if (addr < 0x40) return (wd->dmacmemory[addr] << 8) | wd->dmacmemory[addr + 1]; if (wd->dmac_type == COMMODORE_8727) { if (addr >= CDMAC_ROM_OFFSET) { if (wd->rom) { int off = addr & wd->rom_mask; return (wd->rom[off] << 8) | wd->rom[off + 1]; } return 0; } switch (addr) { case 0x40: v = 0; if (wd->cdmac.dmac_istr & ISTR_INTS) v |= (1 << 7) | (1 << 4); break; case 0x42: v = 0; if (wd->cdmac.dmac_cntr & CNTR_INTEN) v |= 1 << 4; v |= wd->cdmac.c8727_ctl & 0x80; break; case 0x60: v = wdscsi_getauxstatus (&wd->wc); break; case 0x62: v = wdscsi_get (&wd->wc, wd); break; case 0x64: v = dmac8727_read_pcss(wd); break; case 0x68: v = dmac8727_read_pcsd(wd); break; } v <<= 8; return v; } else if (wd->dmac_type == COMMODORE_DMAC) { if (addr >= CDMAC_ROM_OFFSET) { if (wd->rom) { int off = addr & wd->rom_mask; if (wd->rombankswitcher && (addr & 0xffe0) == CDMAC_ROM_OFFSET) wd->rombank = (addr & 0x02) >> 1; off += wd->rombank * wd->rom_size; return (wd->rom[off] << 8) | wd->rom[off + 1]; } return 0; } addr &= ~1; switch (addr) { case 0x40: v = wd->cdmac.dmac_istr; if ((v & (ISTR_E_INT | ISTR_INTS)) && (wd->cdmac.dmac_cntr & CNTR_INTEN)) v |= ISTR_INT_P; wd->cdmac.dmac_istr &= ~0xf; break; case 0x42: v = wd->cdmac.dmac_cntr; break; case 0x80: if (wd->cdmac.old_dmac) v = (wd->cdmac.dmac_wtc >> 16) & 0xffff; break; case 0x82: if (wd->cdmac.old_dmac) v = wd->cdmac.dmac_wtc & 0xffff; break; case 0x90: v = wdscsi_getauxstatus(&wd->wc); break; case 0x92: v = wdscsi_get(&wd->wc, wd); break; case 0xc0: v = 0xf8 | (1 << 0) | (1 << 1) | (1 << 2); // bits 0-2 = dip-switches break; case 0xc2: case 0xc4: case 0xc6: v = 0xffff; break; case 0xe0: if (wd->cdmac.dmac_dma <= 0) scsi_dmac_a2091_start_dma (wd); break; case 0xe2: scsi_dmac_a2091_stop_dma (wd); break; case 0xe4: dmac_a2091_cint (wd); break; case 0xe8: /* FLUSH (new only) */ if (!wd->cdmac.old_dmac && wd->cdmac.dmac_dma > 0) wd->cdmac.dmac_istr |= ISTR_FE_FLG; break; } } #if A2091_DEBUG_IO > 0 write_log (_T("dmac_wget %04X=%04X PC=%08X\n"), addr, v, M68K_GETPC); #endif return v; } static uae_u32 dmac_a2091_read_byte (struct wd_state *wd, uaecptr addr) { uae_u32 v = 0; if (addr < 0x40) return wd->dmacmemory[addr]; if (wd->dmac_type == COMMODORE_8727) { if (addr >= DMAC_8727_ROM_VECTOR) { if (wd->rom) { int off = addr & wd->rom_mask; return wd->rom[off]; } return 0; } switch (addr) { case 0x40: v = 0; if (wd->cdmac.dmac_istr & ISTR_INTS) v |= (1 << 7) | (1 << 4); break; case 0x42: v = 0; if (wd->cdmac.dmac_cntr & CNTR_INTEN) v |= 1 << 4; v |= wd->cdmac.c8727_ctl & 0x80; break; case 0x60: v = wdscsi_getauxstatus (&wd->wc); break; case 0x62: v = wdscsi_get (&wd->wc, wd); break; case 0x64: v = dmac8727_read_pcss(wd); break; case 0x68: v = dmac8727_read_pcsd(wd); break; } } else if (wd->dmac_type == COMMODORE_DMAC) { if (addr >= CDMAC_ROM_OFFSET) { if (wd->rom) { int off = addr & wd->rom_mask; if (wd->rombankswitcher && (addr & 0xffe0) == CDMAC_ROM_OFFSET) wd->rombank = (addr & 0x02) >> 1; off += wd->rombank * wd->rom_size; return wd->rom[off]; } return 0; } switch (addr) { case 0x91: v = wdscsi_getauxstatus (&wd->wc); break; case 0x93: v = wdscsi_get (&wd->wc, wd); break; case 0xa1: case 0xa3: case 0xa5: case 0xa7: v = read_xt_reg(wd, (addr - 0xa0) / 2); break; default: v = dmac_a2091_read_word (wd, addr); if (!(addr & 1)) v >>= 8; break; } } #if A2091_DEBUG_IO > 0 write_log (_T("dmac_bget %04X=%02X PC=%08X\n"), addr, v, M68K_GETPC); #endif return v; } static void dmac_a2091_write_word (struct wd_state *wd, uaecptr addr, uae_u32 b) { #if A2091_DEBUG_IO > 0 write_log (_T("dmac_wput %04X=%04X PC=%08X\n"), addr, b & 65535, M68K_GETPC); #endif if (addr < 0x40) return; if (wd->dmac_type == COMMODORE_8727) { if (addr >= DMAC_8727_ROM_VECTOR) return; b >>= 8; switch(addr) { case 0x40: break; case 0x42: wd->cdmac.dmac_cntr &= ~(CNTR_INTEN | CNTR_PDMD); if (b & (1 << 4)) wd->cdmac.dmac_cntr |= CNTR_INTEN; wd->cdmac.c8727_ctl = b; if (b & 0x80) dmac8727_cbp(wd); break; case 0x50: // clear interrupt wd->cdmac.dmac_istr &= ~(ISTR_INT_F | ISTR_INTS); wd->cdmac.xt_irq = false; wd->cdmac.c8727_wrcbp = b; break; case 0x52: a2090_st506(wd, b); break; case 0x60: wdscsi_sasr (&wd->wc, b); break; case 0x62: wdscsi_put (&wd->wc, wd, b); break; case 0x64: dmac8727_write_pcss(wd, b); break; case 0x68: dmac8727_write_pcsd(wd, b); break; } } else if (wd->dmac_type == COMMODORE_DMAC) { if (addr >= CDMAC_ROM_OFFSET) return; addr &= ~1; switch (addr) { case 0x42: wd->cdmac.dmac_cntr = b; if (wd->cdmac.dmac_cntr & CNTR_PREST) dmac_reset (wd); break; case 0x80: wd->cdmac.dmac_wtc &= 0x0000ffff; wd->cdmac.dmac_wtc |= b << 16; break; case 0x82: wd->cdmac.dmac_wtc &= 0xffff0000; wd->cdmac.dmac_wtc |= b & 0xffff; break; case 0x84: wd->cdmac.dmac_acr &= 0x0000ffff; wd->cdmac.dmac_acr |= b << 16; break; case 0x86: wd->cdmac.dmac_acr &= 0xffff0000; wd->cdmac.dmac_acr |= b & 0xfffe; if (wd->cdmac.old_dmac) wd->cdmac.dmac_acr &= ~3; break; case 0x8e: wd->cdmac.dmac_dawr = b; break; case 0x90: wdscsi_sasr (&wd->wc, b); break; case 0x92: wdscsi_put (&wd->wc, wd, b); break; case 0xc2: case 0xc4: case 0xc6: break; case 0xe0: if (wd->cdmac.dmac_dma <= 0) scsi_dmac_a2091_start_dma (wd); break; case 0xe2: scsi_dmac_a2091_stop_dma (wd); break; case 0xe4: dmac_a2091_cint (wd); break; case 0xe8: /* FLUSH */ wd->cdmac.dmac_istr |= ISTR_FE_FLG; break; } } } static void dmac_a2091_write_byte (struct wd_state *wd, uaecptr addr, uae_u32 b) { #if A2091_DEBUG_IO > 0 write_log (_T("dmac_bput %04X=%02X PC=%08X\n"), addr, b & 255, M68K_GETPC); #endif if (addr < 0x40) return; if (wd->dmac_type == COMMODORE_8727) { if (addr >= DMAC_8727_ROM_VECTOR) return; switch(addr) { case 0x40: break; case 0x42: wd->cdmac.dmac_cntr &= ~CNTR_INTEN; if (b & (1 << 4)) wd->cdmac.dmac_cntr |= CNTR_INTEN; wd->cdmac.c8727_ctl = b; if (b & 0x80) dmac8727_cbp(wd); break; case 0x50: // clear interrupt wd->cdmac.dmac_istr &= ~(ISTR_INT_F | ISTR_INTS); wd->cdmac.xt_irq = false; wd->cdmac.c8727_wrcbp = b; break; case 0x52: a2090_st506(wd, b); break; case 0x60: wdscsi_sasr (&wd->wc, b); break; case 0x62: wdscsi_put (&wd->wc, wd, b); break; case 0x64: dmac8727_write_pcss(wd, b); break; case 0x68: dmac8727_write_pcsd(wd, b); break; } } else if (wd->dmac_type == COMMODORE_DMAC) { if (addr >= CDMAC_ROM_OFFSET) return; switch (addr) { case 0x91: wdscsi_sasr (&wd->wc, b); break; case 0x93: wdscsi_put (&wd->wc, wd, b); break; case 0xa1: case 0xa3: case 0xa5: case 0xa7: write_xt_reg(wd, (addr - 0xa0) / 2, b); break; default: if (addr & 1) dmac_a2091_write_word (wd, addr, b); else dmac_a2091_write_word (wd, addr, b << 8); } } } static uae_u32 REGPARAM2 dmac_a2091_lget (struct wd_state *wd, uaecptr addr) { uae_u32 v; #ifdef JIT special_mem |= S_READ; #endif addr &= 65535; v = dmac_a2091_read_word(wd, addr) << 16; v |= dmac_a2091_read_word(wd, addr + 2) & 0xffff; return v; } static uae_u32 REGPARAM2 dmac_a2091_wget(struct wd_state *wd, uaecptr addr) { uae_u32 v; #ifdef JIT special_mem |= S_READ; #endif addr &= 65535; v = dmac_a2091_read_word(wd, addr); return v; } static uae_u32 REGPARAM2 dmac_a2091_bget(struct wd_state *wd, uaecptr addr) { uae_u32 v; #ifdef JIT special_mem |= S_READ; #endif addr &= 65535; v = dmac_a2091_read_byte(wd, addr); return v; } static void REGPARAM2 dmac_a2091_lput(struct wd_state *wd, uaecptr addr, uae_u32 l) { #ifdef JIT special_mem |= S_WRITE; #endif addr &= 65535; dmac_a2091_write_word(wd, addr + 0, l >> 16); dmac_a2091_write_word(wd, addr + 2, l); } static void REGPARAM2 dmac_a2091_wput(struct wd_state *wd, uaecptr addr, uae_u32 w) { #ifdef JIT special_mem |= S_WRITE; #endif addr &= 65535; dmac_a2091_write_word(wd, addr, w); } extern addrbank dmaca2091_bank; static void REGPARAM2 dmac_a2091_bput(struct wd_state *wd, uaecptr addr, uae_u32 b) { #ifdef JIT special_mem |= S_WRITE; #endif b &= 0xff; addr &= 65535; if (wd->autoconfig) { if (addr == 0x48 && !wd->configured) { map_banks_z2 (wd->bank, b, 0x10000 >> 16); wd->baseaddress = b << 16; wd->configured = 1; expamem_next (wd->bank, NULL); return; } if (addr == 0x4c && !wd->configured) { wd->configured = 1; expamem_shutup(wd->bank); return; } if (!wd->configured) return; } dmac_a2091_write_byte(wd, addr, b); } static uae_u32 REGPARAM2 dmac_a2091_wgeti(struct wd_state *wd, uaecptr addr) { uae_u32 v = 0xffff; #ifdef JIT special_mem |= S_READ; #endif addr &= 65535; if (addr >= CDMAC_ROM_OFFSET) v = (wd->rom[addr & wd->rom_mask] << 8) | wd->rom[(addr + 1) & wd->rom_mask]; else write_log(_T("Invalid DMAC instruction access %08x\n"), addr); return v; } static uae_u32 REGPARAM2 dmac_a2091_lgeti(struct wd_state *wd, uaecptr addr) { uae_u32 v; #ifdef JIT special_mem |= S_READ; #endif addr &= 65535; v = dmac_a2091_wgeti(wd, addr) << 16; v |= dmac_a2091_wgeti(wd, addr + 2); return v; } static int REGPARAM2 dmac_a2091_check(struct wd_state *wd, uaecptr addr, uae_u32 size) { return 1; } static uae_u8 *REGPARAM2 dmac_a2091_xlate(struct wd_state *wd, uaecptr addr) { addr &= 0xffff; addr += wd->rombank * wd->rom_size; if (addr >= 0x8000) addr = 0x8000; return wd->rom + addr; } static uae_u8 *REGPARAM2 dmac_a2091_xlate (uaecptr addr) { struct wd_state *wd = getscsiboard(addr); if (wd) return dmac_a2091_xlate(wd, addr); return default_xlate(0); } static int REGPARAM2 dmac_a2091_check (uaecptr addr, uae_u32 size) { struct wd_state *wd = getscsiboard(addr); if (wd) return dmac_a2091_check(wd, addr, size); return 0; } static uae_u32 REGPARAM2 dmac_a2091_lgeti (uaecptr addr) { struct wd_state *wd = getscsiboard(addr); if (wd) return dmac_a2091_lgeti(wd, addr); return 0; } static uae_u32 REGPARAM2 dmac_a2091_wgeti (uaecptr addr) { struct wd_state *wd = getscsiboard(addr); if (wd) return dmac_a2091_wgeti(wd, addr); return 0; } static uae_u32 REGPARAM2 dmac_a2091_bget (uaecptr addr) { struct wd_state *wd = getscsiboard(addr); if (wd) return dmac_a2091_bget(wd, addr); return 0; } static uae_u32 REGPARAM2 dmac_a2091_wget (uaecptr addr) { struct wd_state *wd = getscsiboard(addr); if (wd) return dmac_a2091_wget(wd, addr); return 0; } static uae_u32 REGPARAM2 dmac_a2091_lget (uaecptr addr) { struct wd_state *wd = getscsiboard(addr); if (wd) return dmac_a2091_lget(wd, addr); return 0; } static void REGPARAM2 dmac_a2091_bput (uaecptr addr, uae_u32 b) { struct wd_state *wd = getscsiboard(addr); if (wd) dmac_a2091_bput(wd, addr, b); } static void REGPARAM2 dmac_a2091_wput (uaecptr addr, uae_u32 b) { struct wd_state *wd = getscsiboard(addr); if (wd) dmac_a2091_wput(wd, addr, b); } static void REGPARAM2 dmac_a2091_lput (uaecptr addr, uae_u32 b) { struct wd_state *wd = getscsiboard(addr); if (wd) dmac_a2091_lput(wd, addr, b); } addrbank dmaca2091_bank = { dmac_a2091_lget, dmac_a2091_wget, dmac_a2091_bget, dmac_a2091_lput, dmac_a2091_wput, dmac_a2091_bput, dmac_a2091_xlate, dmac_a2091_check, NULL, NULL, _T("A2090/A2091/A590"), dmac_a2091_lgeti, dmac_a2091_wgeti, ABFLAG_IO | ABFLAG_SAFE }; /* GVP Series I and II */ extern addrbank gvp_bank; static uae_u32 dmac_gvp_read_byte(struct wd_state *wd, uaecptr addr) { uae_u32 v = 0; addr &= wd->board_mask; if (addr < 0x3e) { v = wd->dmacmemory[addr]; } else if ((addr & 0x8000) == GVP_ROM_OFFSET) { addr &= 0xffff; if (wd->gdmac.series2) { if (addr & 1) { v = wd->gdmac.version; } else { if (wd->rom) { if (wd->rombankswitcher && (addr & 0xffe0) == GVP_ROM_OFFSET) wd->rombank = (addr & 0x02) >> 1; v = wd->rom[(addr - GVP_ROM_OFFSET) / 2 + wd->rombank * 16384]; } } } else { if ((addr & 1) && wd->gdmac.use_version) { v = wd->gdmac.version; } else if (wd->rom) { v = wd->rom[addr - GVP_ROM_OFFSET]; } } } else if (addr >= wd->gdmac.s1_ramoffset && !wd->gdmac.series2) { #if GVP_S1_DEBUG_IO > 1 int off = wd->gdmac.bufoffset; #endif v = wd->gdmac.buffer[wd->gdmac.bufoffset++]; wd->gdmac.bufoffset &= wd->gdmac.s1_rammask; #if GVP_S1_DEBUG_IO > 1 write_log(_T("gvp_s1_bget sram %d %04x\n"), off, v); #endif } else if (wd->configured) { if (wd->gdmac.series2) { switch (addr) { case 0x40: v = wd->gdmac.cntr >> 8; break; case 0x41: v = wd->gdmac.cntr; break; case 0x61: // SASR v = wdscsi_getauxstatus(&wd->wc); break; case 0x63: // SCMD v = wdscsi_get(&wd->wc, wd); break; default: write_log(_T("gvp_s2_bget_unk %04X PC=%08X\n"), addr, M68K_GETPC); break; } } else { switch (addr) { case 0x3e: v = (wd->wc.auxstatus & ASR_INT) ? 0x80 : 0x00; break; case 0x60: // SASR v = wdscsi_getauxstatus(&wd->wc); break; case 0x62: // SCMD v = wdscsi_get(&wd->wc, wd); break; case 0x68: v = 0; break; default: write_log(_T("gvp_s1_bget_unk %04X PC=%08X\n"), addr, M68K_GETPC); break; } } } else { v = 0xff; } #if GVP_S2_DEBUG_IO > 0 write_log(_T("gvp_bget %04X=%02X PC=%08X\n"), addr, v, M68K_GETPC); #endif return v; } static uae_u32 dmac_gvp_read_word(struct wd_state *wd, uaecptr addr) { uae_u32 v = 0; addr &= wd->board_mask; if (addr < 0x3e) { v = (wd->dmacmemory[addr] << 8) | wd->dmacmemory[addr + 1]; } else if ((addr & 0x8000) == GVP_ROM_OFFSET) { addr &= 0xffff; if (wd->gdmac.series2) { if (wd->rom) { if (wd->rombankswitcher && (addr & 0xffe0) == GVP_ROM_OFFSET) wd->rombank = (addr & 0x02) >> 1; v = (wd->rom[(addr - GVP_ROM_OFFSET) / 2 + wd->rombank * 16384] << 8) | wd->gdmac.version; } else { v = wd->gdmac.version; } } else { if (wd->rom) { v = (wd->rom[addr - GVP_ROM_OFFSET] << 8) | (wd->rom[addr - GVP_ROM_OFFSET + 1]); } if (wd->gdmac.use_version) { v &= 0xff00; v |= wd->gdmac.version; } } } else if (addr >= wd->gdmac.s1_ramoffset && !wd->gdmac.series2) { #if GVP_S1_DEBUG_IO > 1 int off = wd->gdmac.bufoffset; #endif v = wd->gdmac.buffer[wd->gdmac.bufoffset++] << 8; wd->gdmac.bufoffset &= wd->gdmac.s1_rammask; v |= wd->gdmac.buffer[wd->gdmac.bufoffset++] << 0; wd->gdmac.bufoffset &= wd->gdmac.s1_rammask; #if GVP_S1_DEBUG_IO > 1 write_log(_T("gvp_s1_wget sram %d %04x\n"), off, v); #endif } else if (wd->configured) { if (wd->gdmac.series2) { switch (addr) { case 0x40: v = wd->gdmac.cntr; break; case 0x68: v = wd->gdmac.bank; break; case 0x70: v = wd->gdmac.addr >> 16; break; case 0x72: v = wd->gdmac.addr; break; default: write_log(_T("gvp_s2_wget_unk %04X PC=%08X\n"), addr, M68K_GETPC); break; } #if GVP_S2_DEBUG_IO > 0 write_log(_T("gvp_s2_wget %04X=%04X PC=%08X\n"), addr, v, M68K_GETPC); #endif } else { v = dmac_gvp_read_byte(wd, addr) << 8; v |= dmac_gvp_read_byte(wd, addr + 1); #if GVP_S1_DEBUG_IO > 0 write_log(_T("gvp_s1_wget %04X=%04X PC=%08X\n"), addr, v, M68K_GETPC); #endif } } else { v = 0xffff; } return v; } static void dmac_gvp_write_byte(struct wd_state *wd, uaecptr addr, uae_u32 b) { addr &= wd->board_mask; if (addr >= GVP_ROM_OFFSET) return; if (addr >= wd->gdmac.s1_ramoffset && !wd->gdmac.series2) { #if GVP_S1_DEBUG_IO > 1 int off = wd->gdmac.bufoffset; #endif if (!(addr & GVP_ROM_OFFSET)) { wd->gdmac.buffer[wd->gdmac.bufoffset++] = b; wd->gdmac.bufoffset &= wd->gdmac.s1_rammask; } #if GVP_S1_DEBUG_IO > 1 write_log(_T("gvp_s1_bput sram %d %04x\n"), off, b); #endif return; } if (wd->gdmac.series2) { #if GVP_S2_DEBUG_IO > 0 write_log(_T("gvp_s2_bput %04X=%02X PC=%08X\n"), addr, b & 255, M68K_GETPC); #endif switch (addr) { case 0x40: wd->gdmac.cntr &= 0x00ff; wd->gdmac.cntr |= b << 8; break; case 0x41: b &= ~(1 | 2); wd->gdmac.cntr &= 0xff00; wd->gdmac.cntr |= b << 0; break; case 0x61: // SASR wdscsi_sasr(&wd->wc, b); break; case 0x63: // SCMD wdscsi_put(&wd->wc, wd, b); break; case 0x74: // "secret1" case 0x75: case 0x7a: // "secret2" case 0x7b: case 0x7c: // "secret3" case 0x7d: write_log(_T("gvp_s2_bput_config %04X=%04X PC=%08X\n"), addr, b & 255, M68K_GETPC); break; default: write_log(_T("gvp_s2_bput_unk %04X=%02X PC=%08X\n"), addr, b & 255, M68K_GETPC); break; } } else { #if GVP_S1_DEBUG_IO > 0 write_log(_T("gvp_s1_bput %04X=%02X PC=%08X\n"), addr, b & 255, M68K_GETPC); #endif switch (addr) { case 0x60: // SASR wdscsi_sasr(&wd->wc, b); break; case 0x62: // SCMD wdscsi_put(&wd->wc, wd, b); break; // 68: // 00 CPU SRAM access // ff WD SRAM access // 6c: // 28 0010 startup reset? // b8 1011 before CPU reading from SRAM // a8 1100 before CPU writing to SRAM // e8 1110 before starting WD write DMA // f8 1111 access done/start WD read DMA // 08 = intena? case 0x68: #if GVP_S1_DEBUG_IO > 0 write_log(_T("gvp_s1_bput_s1 %04X=%04X PC=%08X\n"), addr, b & 255, M68K_GETPC); #endif wd->gdmac.bufoffset = 0; break; case 0x6c: #if GVP_S1_DEBUG_IO > 0 write_log(_T("gvp_s1_bput_s1 %04X=%04X PC=%08X\n"), addr, b & 255, M68K_GETPC); #endif if (!(wd->gdmac.cntr & 8) && (b & 8)) wd_master_reset(wd, true); wd->gdmac.cntr = b; break; default: write_log(_T("gvp_s1_bput_unk %04X=%02X PC=%08X\n"), addr, b & 255, M68K_GETPC); break; } } } static void dmac_gvp_write_word(struct wd_state *wd, uaecptr addr, uae_u32 b) { addr &= wd->board_mask; if (addr >= GVP_ROM_OFFSET && addr < 65536) return; if (addr >= wd->gdmac.s1_ramoffset && !wd->gdmac.series2) { #if GVP_S1_DEBUG_IO > 1 int off = wd->gdmac.bufoffset; #endif if (!(addr & GVP_ROM_OFFSET)) { wd->gdmac.buffer[wd->gdmac.bufoffset++] = b >> 8; wd->gdmac.bufoffset &= wd->gdmac.s1_rammask; wd->gdmac.buffer[wd->gdmac.bufoffset++] = b; wd->gdmac.bufoffset &= wd->gdmac.s1_rammask; } #if GVP_S1_DEBUG_IO > 1 write_log(_T("gvp_s1_wput sram %d %04x\n"), off, b); #endif return; } if (wd->gdmac.series2) { #if GVP_S2_DEBUG_IO > 0 write_log(_T("gvp_s2_wput %04X=%04X PC=%08X\n"), addr, b & 65535, M68K_GETPC); #endif switch (addr) { case 0x40: b &= ~(1 | 2); wd->gdmac.cntr = b; break; case 0x68: // bank if (b != 0) write_log(_T("bank %02x\n"), b); break; case 0x70: // ACR wd->gdmac.addr &= 0x0000ffff; wd->gdmac.addr |= (b & 0xff) << 16; wd->gdmac.addr &= wd->gdmac.addr_mask; break; case 0x72: // ACR wd->gdmac.addr &= 0xffff0000; wd->gdmac.addr |= b; wd->gdmac.addr &= wd->gdmac.addr_mask; break; case 0x76: // START DMA wd->gdmac.dma_on = 1; break; case 0x78: // STOP DMA wd->gdmac.dma_on = 0; break; case 0x74: // "secret1" case 0x7a: // "secret2" case 0x7c: // "secret3" write_log(_T("gvp_s2_wput_config %04X=%04X PC=%08X\n"), addr, b & 65535, M68K_GETPC); break; default: write_log(_T("gvp_s2_wput_unk %04X=%04X PC=%08X\n"), addr, b & 65535, M68K_GETPC); break; } } else { dmac_gvp_write_byte(wd, addr, b >> 8); dmac_gvp_write_byte(wd, addr + 1, b); #if GVP_S1_DEBUG_IO > 0 write_log(_T("gvp_s1_wput %04X=%04X PC=%08X\n"), addr, b & 65535, M68K_GETPC); #endif } } static uae_u32 REGPARAM2 dmac_gvp_lget(struct wd_state *wd, uaecptr addr) { uae_u32 v; #ifdef JIT special_mem |= S_READ; #endif addr &= wd->board_mask; v = dmac_gvp_read_word(wd, addr) << 16; v |= dmac_gvp_read_word(wd, addr + 2) & 0xffff; return v; } static uae_u32 REGPARAM2 dmac_gvp_wget(struct wd_state *wd, uaecptr addr) { uae_u32 v; #ifdef JIT special_mem |= S_READ; #endif addr &= wd->board_mask; v = dmac_gvp_read_word(wd, addr); return v; } static uae_u32 REGPARAM2 dmac_gvp_bget(struct wd_state *wd, uaecptr addr) { uae_u32 v; #ifdef JIT special_mem |= S_READ; #endif addr &= wd->board_mask; v = dmac_gvp_read_byte(wd, addr); return v; } static void REGPARAM2 dmac_gvp_lput(struct wd_state *wd, uaecptr addr, uae_u32 l) { #ifdef JIT special_mem |= S_WRITE; #endif addr &= wd->board_mask; dmac_gvp_write_word(wd, addr + 0, l >> 16); dmac_gvp_write_word(wd, addr + 2, l); } static void REGPARAM2 dmac_gvp_wput(struct wd_state *wd, uaecptr addr, uae_u32 w) { #ifdef JIT special_mem |= S_WRITE; #endif addr &= wd->board_mask; dmac_gvp_write_word(wd, addr, w); } static void REGPARAM2 dmac_gvp_bput(struct wd_state *wd, uaecptr addr, uae_u32 b) { #ifdef JIT special_mem |= S_WRITE; #endif b &= 0xff; addr &= wd->board_mask; if (wd->autoconfig) { if (addr == 0x48 && !wd->configured) { map_banks_z2(wd->bank, b, (wd->board_mask + 1) >> 16); wd->baseaddress = b << 16; wd->configured = 1; expamem_next(wd->bank, NULL); return; } if (addr == 0x4c && !wd->configured) { wd->configured = 1; expamem_shutup(wd->bank); return; } if (!wd->configured) return; } dmac_gvp_write_byte(wd, addr, b); } static uae_u32 REGPARAM2 dmac_gvp_wgeti(struct wd_state *wd, uaecptr addr) { uae_u32 v = 0xffff; #ifdef JIT special_mem |= S_READ; #endif addr &= wd->board_mask; if (addr >= GVP_ROM_OFFSET) { addr -= GVP_ROM_OFFSET; v = (wd->rom[addr & wd->rom_mask] << 8) | wd->rom[(addr + 1) & wd->rom_mask]; } else { write_log(_T("Invalid GVP instruction access %08x\n"), addr); } return v; } static uae_u32 REGPARAM2 dmac_gvp_lgeti(struct wd_state *wd, uaecptr addr) { uae_u32 v; #ifdef JIT special_mem |= S_READ; #endif addr &= wd->board_mask; v = dmac_gvp_wgeti(wd, addr) << 16; v |= dmac_gvp_wgeti(wd, addr + 2); return v; } static void REGPARAM2 dmac_gvp_bput (uaecptr addr, uae_u32 b) { struct wd_state *wd = getscsiboard(addr); if (wd) dmac_gvp_bput(wd, addr, b); } static void REGPARAM2 dmac_gvp_wput (uaecptr addr, uae_u32 b) { struct wd_state *wd = getscsiboard(addr); if (wd) dmac_gvp_wput(wd, addr, b); } static void REGPARAM2 dmac_gvp_lput (uaecptr addr, uae_u32 b) { struct wd_state *wd = getscsiboard(addr); if (wd) dmac_gvp_lput(wd, addr, b); } static uae_u32 REGPARAM2 dmac_gvp_bget (uaecptr addr) { struct wd_state *wd = getscsiboard(addr); if (wd) return dmac_gvp_bget(wd, addr); return 0; } static uae_u32 REGPARAM2 dmac_gvp_wget (uaecptr addr) { struct wd_state *wd = getscsiboard(addr); if (wd) return dmac_gvp_wget(wd, addr); return 0; } static uae_u32 REGPARAM2 dmac_gvp_lget (uaecptr addr) { struct wd_state *wd = getscsiboard(addr); if (wd) return dmac_gvp_lget(wd, addr); return 0; } static uae_u32 REGPARAM2 dmac_gvp_wgeti (uaecptr addr) { struct wd_state *wd = getscsiboard(addr); if (wd) return dmac_gvp_wgeti(wd, addr); return 0; } static uae_u32 REGPARAM2 dmac_gvp_lgeti (uaecptr addr) { struct wd_state *wd = getscsiboard(addr); if (wd) return dmac_gvp_lgeti(wd, addr); return 0; } static int REGPARAM2 dmac_gvp_check(uaecptr addr, uae_u32 size) { struct wd_state *wd = getscsiboard(addr); return wd ? 1 : 0; } static uae_u8 *REGPARAM2 dmac_gvp_xlate(uaecptr addr) { struct wd_state *wd = getscsiboard(addr); if (!wd) return default_xlate(0); addr &= 0xffff; return wd->rom + addr; } addrbank gvp_bank = { dmac_gvp_lget, dmac_gvp_wget, dmac_gvp_bget, dmac_gvp_lput, dmac_gvp_wput, dmac_gvp_bput, dmac_gvp_xlate, dmac_gvp_check, NULL, NULL, _T("GVP"), dmac_gvp_lgeti, dmac_gvp_wgeti, ABFLAG_IO | ABFLAG_SAFE }; /* SUPERDMAC (A3000 mainboard built-in) */ static void mbdmac_write_word (struct wd_state *wd, uae_u32 addr, uae_u32 val) { #if A3000_DEBUG_IO > 1 write_log (_T("DMAC_WWRITE %08X=%04X PC=%08X\n"), addr, val & 0xffff, M68K_GETPC); #endif addr &= 0xfffe; switch (addr) { case 0x02: wd->cdmac.dmac_dawr = val; break; case 0x04: wd->cdmac.dmac_wtc &= 0x0000ffff; wd->cdmac.dmac_wtc |= val << 16; break; case 0x06: wd->cdmac.dmac_wtc &= 0xffff0000; wd->cdmac.dmac_wtc |= val & 0xffff; break; case 0x0a: wd->cdmac.dmac_cntr = val; if (wd->cdmac.dmac_cntr & SCNTR_PREST) dmac_reset (wd); break; case 0x0c: wd->cdmac.dmac_acr &= 0x0000ffff; wd->cdmac.dmac_acr |= val << 16; break; case 0x0e: wd->cdmac.dmac_acr &= 0xffff0000; wd->cdmac.dmac_acr |= val & 0xfffe; break; case 0x12: if (wd->cdmac.dmac_dma <= 0) scsi_dmac_a2091_start_dma (wd); break; case 0x16: if (wd->cdmac.dmac_dma) { /* FLUSH */ wd->cdmac.dmac_istr |= ISTR_FE_FLG; wd->cdmac.dmac_dma = 0; } break; case 0x1a: dmac_a2091_cint(wd); break; case 0x1e: /* ISTR */ break; case 0x3e: scsi_dmac_a2091_stop_dma (wd); break; case 0x40: case 0x48: wdscsi_sasr(&wd->wc, val); break; case 0x42: case 0x46: wdscsi_put(&wd->wc, wd, val); break; } } static void mbdmac_write_byte (struct wd_state *wd, uae_u32 addr, uae_u32 val) { #if A3000_DEBUG_IO > 1 write_log (_T("DMAC_BWRITE %08X=%02X PC=%08X\n"), addr, val & 0xff, M68K_GETPC); #endif addr &= 0xffff; switch (addr) { case 0x41: case 0x49: wdscsi_sasr(&wd->wc, val); break; case 0x43: case 0x47: wdscsi_put (&wd->wc, wd, val); break; default: if (addr & 1) mbdmac_write_word (wd, addr, val); else mbdmac_write_word (wd, addr, val << 8); } } static uae_u32 mbdmac_read_word (struct wd_state *wd, uae_u32 addr) { #if A3000_DEBUG_IO > 1 uae_u32 vaddr = addr; #endif uae_u32 v = 0xffffffff; addr &= 0xfffe; switch (addr) { case 0x02: v = wd->cdmac.dmac_dawr; break; case 0x04: case 0x06: v = 0xffff; break; case 0x0a: v = wd->cdmac.dmac_cntr; break; case 0x0c: v = wd->cdmac.dmac_acr >> 16; break; case 0x0e: v = wd->cdmac.dmac_acr; break; case 0x12: if (wd->cdmac.dmac_dma <= 0) scsi_dmac_a2091_start_dma (wd); v = 0; break; case 0x1a: dmac_a2091_cint (wd); v = 0; break;; case 0x1e: v = wd->cdmac.dmac_istr; if (v & ISTR_INTS) v |= ISTR_INT_P; wd->cdmac.dmac_istr &= ~15; if (!wd->cdmac.dmac_dma) v |= ISTR_FE_FLG; break; case 0x3e: if (wd->cdmac.dmac_dma) { scsi_dmac_a2091_stop_dma (wd); wd->cdmac.dmac_istr |= ISTR_FE_FLG; } v = 0; break; case 0x40: case 0x48: v = wdscsi_getauxstatus(&wd->wc); break; case 0x42: case 0x46: v = wdscsi_get(&wd->wc, wd); break; } #if A3000_DEBUG_IO > 1 write_log (_T("DMAC_WREAD %08X=%04X PC=%X\n"), vaddr, v & 0xffff, M68K_GETPC); #endif return v; } static uae_u32 mbdmac_read_byte (struct wd_state *wd, uae_u32 addr) { #if A3000_DEBUG_IO > 1 uae_u32 vaddr = addr; #endif uae_u32 v = 0xffffffff; addr &= 0xffff; switch (addr) { case 0x41: case 0x49: v = wdscsi_getauxstatus (&wd->wc); break; case 0x43: case 0x47: v = wdscsi_get (&wd->wc, wd); break; default: v = mbdmac_read_word (wd, addr); if (!(addr & 1)) v >>= 8; break; } #if A3000_DEBUG_IO > 1 write_log (_T("DMAC_BREAD %08X=%02X PC=%X\n"), vaddr, v & 0xff, M68K_GETPC); #endif return v; } static uae_u32 REGPARAM3 mbdmac_lget (uaecptr) REGPARAM; static uae_u32 REGPARAM3 mbdmac_wget (uaecptr) REGPARAM; static uae_u32 REGPARAM3 mbdmac_bget (uaecptr) REGPARAM; static void REGPARAM3 mbdmac_lput (uaecptr, uae_u32) REGPARAM; static void REGPARAM3 mbdmac_wput (uaecptr, uae_u32) REGPARAM; static void REGPARAM3 mbdmac_bput (uaecptr, uae_u32) REGPARAM; static uae_u32 REGPARAM2 mbdmac_lget (uaecptr addr) { uae_u32 v; #ifdef JIT special_mem |= S_READ; #endif v = mbdmac_read_word (wd_a3000, addr + 0) << 16; v |= mbdmac_read_word (wd_a3000, addr + 2) << 0; return v; } static uae_u32 REGPARAM2 mbdmac_wget (uaecptr addr) { uae_u32 v; #ifdef JIT special_mem |= S_READ; #endif v = mbdmac_read_word (wd_a3000, addr); return v; } static uae_u32 REGPARAM2 mbdmac_bget (uaecptr addr) { #ifdef JIT special_mem |= S_READ; #endif return mbdmac_read_byte (wd_a3000, addr); } static void REGPARAM2 mbdmac_lput (uaecptr addr, uae_u32 l) { #ifdef JIT special_mem |= S_WRITE; #endif if ((addr & 0xffff) == 0x40) { // long write to 0x40 = write byte to SASR mbdmac_write_byte (wd_a3000, 0x41, l); } else { mbdmac_write_word (wd_a3000, addr + 0, l >> 16); mbdmac_write_word (wd_a3000, addr + 2, l >> 0); } } static void REGPARAM2 mbdmac_wput (uaecptr addr, uae_u32 w) { #ifdef JIT special_mem |= S_WRITE; #endif mbdmac_write_word (wd_a3000, addr + 0, w); } static void REGPARAM2 mbdmac_bput (uaecptr addr, uae_u32 b) { #ifdef JIT special_mem |= S_WRITE; #endif mbdmac_write_byte (wd_a3000, addr, b); } addrbank mbdmac_a3000_bank = { mbdmac_lget, mbdmac_wget, mbdmac_bget, mbdmac_lput, mbdmac_wput, mbdmac_bput, default_xlate, default_check, NULL, NULL, _T("A3000 DMAC"), dummy_lgeti, dummy_wgeti, ABFLAG_IO | ABFLAG_SAFE }; static void ew (struct wd_state *wd, int addr, uae_u32 value) { addr &= 0xffff; if (addr == 00 || addr == 02 || addr == 0x40 || addr == 0x42) { wd->dmacmemory[addr] = (value & 0xf0); wd->dmacmemory[addr + 2] = (value & 0x0f) << 4; } else { wd->dmacmemory[addr] = ~(value & 0xf0); wd->dmacmemory[addr + 2] = ~((value & 0x0f) << 4); } } static void *scsi_thread (void *wdv) { struct wd_state *wds = (struct wd_state*)wdv; struct wd_chip_state *wd = &wds->wc; for (;;) { uae_u32 v = read_comm_pipe_u32_blocking (&wds->requests); if (wds->scsi_thread_running == 0 || v == 0xfffffff) break; int cmd = v & 0x7f; int msg = (v >> 8) & 0xff; int unit = (v >> 24) & 0xff; wd->scsi = wds->scsis[unit]; //write_log (_T("scsi_thread got msg=%d cmd=%d\n"), msg, cmd); if (msg == 0) { if (WD33C93_DEBUG > 0) write_log (_T("%s command %02X\n"), WD33C93, cmd); switch (cmd) { case WD_CMD_RESET: wd_cmd_reset(wd, true); break; case WD_CMD_ABORT: wd_cmd_abort (wd); break; case WD_CMD_SEL: wd_cmd_sel (wd, wds, false); break; case WD_CMD_SEL_ATN: wd_cmd_sel (wd, wds, true); break; case WD_CMD_SEL_ATN_XFER: wd_cmd_sel_xfer (wd, wds, true); break; case WD_CMD_SEL_XFER: wd_cmd_sel_xfer (wd, wds, false); break; case WD_CMD_TRANS_INFO: wd_cmd_trans_info (wds, wd->scsi, false); break; case WD_CMD_TRANS_ADDR: wd_cmd_trans_addr(wd, wds); break; case WD_CMD_NEGATE_ACK: if (wd->wd_phase == CSR_MSGIN && wd->wd_selected) wd_do_transfer_in(wd, wd->scsi, false); break; case WD_CMD_TRANSFER_PAD: wd_cmd_trans_info (wds, wd->scsi, true); break; default: wd->wd_busy = false; write_log (_T("%s unimplemented/unknown command %02X\n"), WD33C93, cmd); set_status (wd, CSR_INVALID, 10); break; } } else if (msg == 1) { wd_do_transfer_in (wd, wd->scsi, false); } else if (msg == 2) { wd_do_transfer_out (wd, wd->scsi); } else if (msg == 3) { wd_do_transfer_in (wd, wd->scsi, true); } } wds->scsi_thread_running = -1; return 0; } void init_wd_scsi (struct wd_state *wd) { wd->configured = 0; wd->enabled = true; wd->wc.wd_used = 0; wd->wc.wd33c93_ver = 1; wd->baseaddress = 0; if (wd == wd_cdtv) { wd->cdtv = true; } if (!wd->scsi_thread_running) { wd->scsi_thread_running = 1; init_comm_pipe (&wd->requests, 100, 1); uae_start_thread (_T("scsi"), scsi_thread, wd, NULL); } } void a3000_add_scsi_unit (int ch, struct uaedev_config_info *ci, struct romconfig *rc) { struct wd_state *wd = allocscsi(&wd_a3000, rc, ch); if (!wd || ch < 0) return; add_scsi_device(&wd->scsis[ch], ch, ci, rc); } void a3000scsi_reset (void) { struct wd_state *wd = wd_a3000; if (!wd) return; init_wd_scsi (wd); wd->enabled = true; wd->configured = -1; wd->dmac_type = COMMODORE_SDMAC; map_banks(&mbdmac_a3000_bank, 0xDD, 1, 0); wd_cmd_reset (&wd->wc, false); reset_dmac(wd); } void a3000scsi_free (void) { struct wd_state *wd = wd_a3000; if (!wd) return; freencrunit(wd); if (wd->scsi_thread_running > 0) { wd->scsi_thread_running = 0; write_comm_pipe_u32 (&wd->requests, 0xffffffff, 1); while(wd->scsi_thread_running == 0) sleep_millis (10); wd->scsi_thread_running = 0; } } void a2090_add_scsi_unit(int ch, struct uaedev_config_info *ci, struct romconfig *rc) { struct wd_state *wd = allocscsi(&wd_a2090[ci->controller_type_unit], rc, ch); if (!wd || ch < 0) return; add_scsi_device(&wd->scsis[ch], ch, ci, rc); } void a2091_add_scsi_unit(int ch, struct uaedev_config_info *ci, struct romconfig *rc) { struct wd_state *wd = allocscsi(&wd_a2091[ci->controller_type_unit], rc, ch); if (!wd || ch < 0) return; add_scsi_device(&wd->scsis[ch], ch, ci, rc); } void gvp_s1_add_scsi_unit(int ch, struct uaedev_config_info *ci, struct romconfig *rc) { struct wd_state *wd = allocscsi(&wd_gvps1[ci->controller_type_unit], rc, ch); if (!wd || ch < 0) return; add_scsi_device(&wd->scsis[ch], ch, ci, rc); } void gvp_s2_add_scsi_unit(int ch, struct uaedev_config_info *ci, struct romconfig *rc) { struct wd_state *wd = allocscsi(&wd_gvps2[ci->controller_type_unit], rc, ch); if (!wd || ch < 0) return; add_scsi_device(&wd->scsis[ch], ch, ci, rc); } void gvp_s2_add_accelerator_scsi_unit(int ch, struct uaedev_config_info *ci, struct romconfig *rc) { struct wd_state *wd = allocscsi(&wd_gvps2accel, rc, ch); if (!wd || ch < 0) return; add_scsi_device(&wd->scsis[ch], ch, ci, rc); } static void a2091_free_device (struct wd_state *wd) { freencrunit(wd); } void a2091_free (void) { for (int i = 0; i < MAX_DUPLICATE_EXPANSION_BOARDS; i++) { a2091_free_device(wd_a2091[i]); a2091_free_device(wd_a2090[i]); } } static void a2091_reset_device(struct wd_state *wd) { if (!wd) return; wd->configured = 0; wd->wc.wd_used = 0; wd->wc.wd33c93_ver = 1; wd->dmac_type = COMMODORE_DMAC; wd->cdmac.old_dmac = 0; if (currprefs.scsi == 2) scsi_addnative(wd->scsis); wd_cmd_reset (&wd->wc, false); reset_dmac(wd); xt_reset(wd); } static void a2090_reset_device(struct wd_state *wd) { if (!wd) return; wd->configured = 0; wd->wc.wd_used = 0; wd->wc.wd33c93_ver = 1; wd->dmac_type = COMMODORE_8727; wd->cdmac.old_dmac = 0; wd_cmd_reset (&wd->wc, false); reset_dmac(wd); } void a2091_reset (void) { for (int i = 0; i < MAX_DUPLICATE_EXPANSION_BOARDS; i++) { a2091_reset_device(wd_a2091[i]); a2090_reset_device(wd_a2090[i]); } } addrbank *a2091_init (struct romconfig *rc) { struct wd_state *wd = getscsi(rc); int slotsize; if (!wd) return &expamem_null; init_wd_scsi(wd); wd->cdmac.old_dmac = rc->subtype == 0; wd->configured = 0; wd->autoconfig = true; wd->board_mask = 65535; wd->bank = &dmaca2091_bank; memset (wd->dmacmemory, 0xff, sizeof wd->dmacmemory); ew(wd, 0x00, 0xc0 | 0x01 | 0x10 | (expansion_is_next_board_fastram() ? 0x08 : 0x00)); /* A590/A2091 hardware id */ ew(wd, 0x04, wd->cdmac.old_dmac ? 0x02 : 0x03); /* commodore's manufacturer id */ ew (wd, 0x10, 0x02); ew (wd, 0x14, 0x02); /* rom vector */ ew (wd, 0x28, CDMAC_ROM_VECTOR >> 8); ew (wd, 0x2c, CDMAC_ROM_VECTOR); ew (wd, 0x18, 0x00); /* ser.no. Byte 0 */ ew (wd, 0x1c, 0x00); /* ser.no. Byte 1 */ ew (wd, 0x20, 0x00); /* ser.no. Byte 2 */ ew (wd, 0x24, 0x00); /* ser.no. Byte 3 */ wd->rombankswitcher = 0; wd->rombank = 0; slotsize = 65536; wd->rom = xcalloc (uae_u8, slotsize); memset(wd->rom, 0xff, slotsize); wd->rom_size = 16384; wd->rom_mask = wd->rom_size - 1; if (!rc->autoboot_disabled) { struct zfile *z = read_device_from_romconfig(rc, ROMTYPE_A2091); if (z) { wd->rom_size = zfile_size (z); zfile_fread (wd->rom, wd->rom_size, 1, z); zfile_fclose (z); if (wd->rom_size == 32768) { wd->rombankswitcher = 1; for (int i = wd->rom_size - 1; i >= 0; i--) { wd->rom[i * 2 + 0] = wd->rom[i]; wd->rom[i * 2 + 1] = 0xff; } } else { for (int i = 1; i < slotsize / wd->rom_size; i++) memcpy (wd->rom + i * wd->rom_size, wd->rom, wd->rom_size); } wd->rom_mask = wd->rom_size - 1; } } return wd->bank; } addrbank *a2090_init (struct romconfig *rc) { struct wd_state *wd = getscsi(rc); int slotsize; if (!wd) return &expamem_null; init_wd_scsi(wd); wd->configured = 0; wd->autoconfig = true; wd->board_mask = 65535; wd->bank = &dmaca2091_bank; memset (wd->dmacmemory, 0xff, sizeof wd->dmacmemory); ew (wd, 0x00, 0xc0 | 0x01 | 0x10); /* A590/A2091 hardware id */ ew(wd, 0x04, rc->subtype ? 0x02 : 0x01); /* commodore's manufacturer id */ ew (wd, 0x10, 0x02); ew (wd, 0x14, 0x02); /* rom vector */ ew (wd, 0x28, DMAC_8727_ROM_VECTOR >> 8); ew (wd, 0x2c, DMAC_8727_ROM_VECTOR); ew (wd, 0x18, 0x00); /* ser.no. Byte 0 */ ew (wd, 0x1c, 0x00); /* ser.no. Byte 1 */ ew (wd, 0x20, 0x00); /* ser.no. Byte 2 */ ew (wd, 0x24, 0x00); /* ser.no. Byte 3 */ //ew(wd, 0x30, 0x80); // SCSI only flag wd->rombankswitcher = 0; wd->rombank = 0; slotsize = 65536; wd->rom = xcalloc (uae_u8, slotsize); memset(wd->rom, 0xff, slotsize); wd->rom_size = 16384; wd->rom_mask = wd->rom_size - 1; if (!rc->autoboot_disabled) { struct zfile *z = read_device_from_romconfig(rc, ROMTYPE_A2090); if (z) { wd->rom_size = zfile_size (z); zfile_fread (wd->rom, wd->rom_size, 1, z); zfile_fclose (z); for (int i = 1; i < slotsize / wd->rom_size; i++) { memcpy (wd->rom + i * wd->rom_size, wd->rom, wd->rom_size); } wd->rom_mask = wd->rom_size - 1; } } return wd->bank; } static void gvp_free_device (struct wd_state *wd) { freencrunit(wd); } void gvp_free (void) { for (int i = 0; i < MAX_DUPLICATE_EXPANSION_BOARDS; i++) { gvp_free_device(wd_gvps1[i]); gvp_free_device(wd_gvps2[i]); } gvp_free_device(wd_gvps2accel); } static void gvp_reset_device(struct wd_state *wd) { if (!wd) return; wd->configured = 0; wd->wc.wd_used = 0; wd->wc.wd33c93_ver = 1; wd->dmac_type = wd->gdmac.series2 ? GVP_DMAC_S2 : GVP_DMAC_S1; if (currprefs.scsi == 2) scsi_addnative(wd->scsis); wd_cmd_reset (&wd->wc, false); reset_dmac(wd); } void gvp_reset (void) { for (int i = 0; i < MAX_DUPLICATE_EXPANSION_BOARDS; i++) { gvp_reset_device(wd_gvps1[i]); gvp_reset_device(wd_gvps2[i]); } gvp_reset_device(wd_gvps2accel); } static const uae_u8 gvp_scsi_i_autoconfig_1[16] = { 0xd1, 0x01, 0x00, 0x00, 0x07, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 }; static const uae_u8 gvp_scsi_i_autoconfig_2[16] = { 0xd1, 0x02, 0x00, 0x00, 0x07, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 }; static const uae_u8 gvp_scsi_i_autoconfig_3[16] = { 0xd2, 0x03, 0x00, 0x00, 0x07, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 }; static const uae_u8 gvp_scsi_ii_autoconfig[16] = { 0xd1, 0x0b, 0x00, 0x00, 0x07, 0xe1, 0xee, 0xee, 0xee, 0xee, 0x80, 0x00 }; static bool is_gvp_accelerator(void) { return ISCPUBOARD(BOARD_GVP, -1); } static addrbank *gvp_init(struct romconfig *rc, bool series2, bool accel) { struct wd_state *wd = getscsi(rc); bool isscsi = true; const uae_u8 *ac; int romtype; if (!accel) { romtype = series2 ? ROMTYPE_GVPS2 : ROMTYPE_GVPS1; } else { romtype = ROMTYPE_CPUBOARD; } if (!wd) return &expamem_null; init_wd_scsi(wd); wd->configured = 0; wd->bank = &gvp_bank; wd->autoconfig = true; wd->rombankswitcher = 0; memset(wd->dmacmemory, 0xff, sizeof wd->dmacmemory); wd->gdmac.series2 = series2; wd->gdmac.use_version = series2; wd->board_mask = 65535; wd->rom_size = 32768; wd->rom = xcalloc(uae_u8, 2 * wd->rom_size); memset(wd->rom, 0xff, 2 * wd->rom_size); wd->rom_mask = 32768 - 1; wd->gdmac.s1_subtype = 0; ac = gvp_scsi_ii_autoconfig; ac = gvp_scsi_ii_autoconfig; if (!series2) { ac = gvp_scsi_i_autoconfig_1; wd->gdmac.s1_rammask = GVP_SERIES_I_RAM_MASK_1; wd->gdmac.s1_ramoffset = GVP_SERIES_I_RAM_OFFSET_1; if (rc->subtype == 1) { ac = gvp_scsi_i_autoconfig_2; wd->gdmac.s1_rammask = GVP_SERIES_I_RAM_MASK_2; wd->gdmac.s1_ramoffset = GVP_SERIES_I_RAM_OFFSET_2; } else if (rc->subtype == 2) { ac = gvp_scsi_i_autoconfig_3; wd->gdmac.s1_rammask = GVP_SERIES_I_RAM_MASK_3; wd->gdmac.s1_ramoffset = GVP_SERIES_I_RAM_OFFSET_3; wd->board_mask = 131071; } wd->gdmac.s1_subtype = rc->subtype; } xfree(wd->gdmac.buffer); wd->gdmac.buffer = xcalloc(uae_u8, 16384); if (!rc->autoboot_disabled) { struct zfile *z = read_device_from_romconfig(rc, ROMTYPE_GVPS2); if (z) { int size = zfile_size(z); if (series2) { int total = 0; int seekpos = 0; int size = zfile_size(z); if (size > 16384 + 4096) { zfile_fread(wd->rom, 64, 1, z); zfile_fseek(z, 16384, SEEK_SET); zfile_fread(wd->rom + 64, 64, 1, z); if (!memcmp(wd->rom, wd->rom + 64, 64)) wd->rombankswitcher = true; else seekpos = 16384; } while (total < 32768 - 4096) { int prevtotal = total; zfile_fseek(z, seekpos, SEEK_SET); total += zfile_fread(wd->rom + total, 1, wd->rom_size - total >= wd->rom_size ? wd->rom_size : wd->rom_size - total, z); if (prevtotal == total) break; } } else { int j = 0; bool oddonly = false; for (int i = 0; i < 16384; i++) { uae_u8 b; zfile_fread(&b, 1, 1, z); wd->rom[j + 16384] = b; wd->rom[j++] = b; if (i == 0 && (b & 0xc0) != 0x80) { // was not wordwide oddonly = true; wd->gdmac.use_version = true; } if (oddonly) { wd->rom[j + 16384] = 0xff; wd->rom[j++] = 0xff; } } } zfile_fclose(z); } else { isscsi = false; } } if (series2) { wd->gdmac.version = GVP_SERIESII; wd->gdmac.addr_mask = 0x00ffffff; if (ISCPUBOARD(BOARD_GVP, BOARD_GVP_SUB_A530)) { wd->gdmac.version = isscsi ? GVP_A530_SCSI : GVP_A530; wd->gdmac.addr_mask = 0x01ffffff; } else if (ISCPUBOARD(BOARD_GVP, BOARD_GVP_SUB_GFORCE030)) { wd->gdmac.version = isscsi ? GVP_GFORCE_030_SCSI : GVP_GFORCE_030; wd->gdmac.addr_mask = 0x01ffffff; } } else { wd->gdmac.version = 0x00; } for (int i = 0; i < 16; i++) { uae_u8 b = ac[i]; ew(wd, i * 4, b); } gvp_reset_device(wd); return wd->bank; } addrbank *gvp_init_s1(struct romconfig *rc) { return gvp_init(rc, false, false); } addrbank *gvp_init_s2(struct romconfig *rc) { return gvp_init(rc, true, false); } addrbank *gvp_init_accelerator(struct romconfig *rc) { return gvp_init(rc, true, true); } void cdtv_add_scsi_unit (int ch, struct uaedev_config_info *ci, struct romconfig *rc) { struct wd_state *wd = allocscsi(&wd_cdtv, rc, ch); if (!wd || ch < 0) return; add_scsi_device(&wd_cdtv->scsis[ch], ch, ci, rc); } #if 0 uae_u8 *save_scsi_dmac (int wdtype, int *len, uae_u8 *dstptr) { struct wd_state *wd = wdscsi[wdtype]; uae_u8 *dstbak, *dst; if (!wd->enabled) return NULL; if (dstptr) dstbak = dst = dstptr; else dstbak = dst = xmalloc (uae_u8, 1000); // model (0=original,1=rev2,2=superdmac) save_u32 (currprefs.cs_mbdmac == 1 ? 2 : 1); save_u32 (0); // reserved flags save_u8(wd->cdmac.dmac_istr); save_u8(wd->cdmac.dmac_cntr); save_u32(wd->cdmac.dmac_wtc); save_u32(wd->cdmac.dmac_acr); save_u16(wd->cdmac.dmac_dawr); save_u32(wd->cdmac.dmac_dma ? 1 : 0); save_u8 (wd->configured); *len = dst - dstbak; return dstbak; } uae_u8 *restore_scsi_dmac (int wdtype, uae_u8 *src) { struct wd_state *wd = wdscsi[wdtype]; restore_u32 (); restore_u32 (); wd->cdmac.dmac_istr = restore_u8(); wd->cdmac.dmac_cntr = restore_u8(); wd->cdmac.dmac_wtc = restore_u32(); wd->cdmac.dmac_acr = restore_u32(); wd->cdmac.dmac_dawr = restore_u16(); restore_u32 (); wd->configured = restore_u8 (); return src; } uae_u8 *save_scsi_device (int wdtype, int num, int *len, uae_u8 *dstptr) { uae_u8 *dstbak, *dst; struct scsi_data *s; struct wd_state *wd = wdscsi[wdtype]; if (!wd->enabled) return NULL; s = wd->scsis[num]; if (!s) return NULL; if (dstptr) dstbak = dst = dstptr; else dstbak = dst = xmalloc (uae_u8, 1000); save_u32 (num); save_u32 (s->device_type); // flags switch (s->device_type) { case UAEDEV_HDF: case 0: save_u64 (s->hfd->size); save_string (s->hfd->hfd.ci.rootdir); save_u32 (s->hfd->hfd.ci.blocksize); save_u32 (s->hfd->hfd.ci.readonly); save_u32 (s->hfd->cyls); save_u32 (s->hfd->heads); save_u32 (s->hfd->secspertrack); save_u64 (s->hfd->hfd.virtual_size); save_u32 (s->hfd->hfd.ci.sectors); save_u32 (s->hfd->hfd.ci.surfaces); save_u32 (s->hfd->hfd.ci.reserved); save_u32 (s->hfd->hfd.ci.bootpri); save_u32 (s->hfd->ansi_version); if (num == 7) { save_u16(wd->cdmac.xt_cyls); save_u16(wd->cdmac.xt_heads); save_u16(wd->cdmac.xt_sectors); save_u8(wd->cdmac.xt_status); save_u8(wd->cdmac.xt_control); } break; case UAEDEV_CD: save_u32 (s->cd_emu_unit); break; case UAEDEV_TAPE: save_u32 (s->cd_emu_unit); save_u32 (s->tape->blocksize); save_u32 (s->tape->wp); save_string (s->tape->tape_dir); break; } *len = dst - dstbak; return dstbak; } uae_u8 *restore_scsi_device (int wdtype, uae_u8 *src) { struct wd_state *wd = wdscsi[wdtype]; int num, num2; struct hd_hardfiledata *hfd; struct scsi_data *s; uae_u64 size; uae_u32 flags; int blocksize, readonly; TCHAR *path; num = restore_u32 (); flags = restore_u32 (); switch (flags & 15) { case UAEDEV_HDF: case 0: hfd = xcalloc (struct hd_hardfiledata, 1); s = wd->scsis[num] = scsi_alloc_hd (num, hfd); size = restore_u64 (); path = restore_string (); _tcscpy (s->hfd->hfd.ci.rootdir, path); blocksize = restore_u32 (); readonly = restore_u32 (); s->hfd->cyls = restore_u32 (); s->hfd->heads = restore_u32 (); s->hfd->secspertrack = restore_u32 (); s->hfd->hfd.virtual_size = restore_u64 (); s->hfd->hfd.ci.sectors = restore_u32 (); s->hfd->hfd.ci.surfaces = restore_u32 (); s->hfd->hfd.ci.reserved = restore_u32 (); s->hfd->hfd.ci.bootpri = restore_u32 (); s->hfd->ansi_version = restore_u32 (); s->hfd->hfd.ci.blocksize = blocksize; if (num == 7) { wd->cdmac.xt_cyls = restore_u16(); wd->cdmac.xt_heads = restore_u8(); wd->cdmac.xt_sectors = restore_u8(); wd->cdmac.xt_status = restore_u8(); wd->cdmac.xt_control = restore_u8(); } if (size) add_scsi_hd (&wd->scsis[num], num, hfd, NULL, s->hfd->ansi_version); xfree (path); break; case UAEDEV_CD: num2 = restore_u32 (); add_scsi_cd (wd->scsis, num, num2); break; case UAEDEV_TAPE: num2 = restore_u32 (); blocksize = restore_u32 (); readonly = restore_u32 (); path = restore_string (); add_scsi_tape (&wd->scsis[num], num, path, readonly != 0); xfree (path); break; } return src; } #endif