/* * UAE - The Un*x Amiga Emulator * * A4000T / A4091 NCR 53C710 SCSI * * (c) 2007-2014 Toni Wilen */ #include "sysconfig.h" #include "sysdeps.h" #ifdef NCR #define NCR_DEBUG 0 #include "options.h" #include "uae.h" #include "memory.h" #include "rommgr.h" #include "custom.h" #include "newcpu.h" #include "ncr_scsi.h" #include "scsi.h" #include "filesys.h" #include "zfile.h" #include "blkdev.h" #include "cpuboard.h" #include "qemuvga/qemuuaeglue.h" #include "qemuvga/queue.h" #include "qemuvga/scsi/scsi.h" #include "autoconf.h" #include "gui.h" #include "devices.h" #define BOARD_SIZE 16777216 #define A4091_ROM_VECTOR 0x0200 #define A4091_ROM_OFFSET 0x0000 #define A4091_ROM_SIZE 65536 #define A4091_IO_OFFSET 0x00800000 #define A4091_IO_ALT 0x00840000 #define A4091_IO_END 0x00880000 #define A4091_DIP_OFFSET 0x008c0003 #define WARP_ENGINE_IO_OFFSET 0x40000 #define WARP_ENGINE_IO_END 0x80000 #define CYBERSTORM_SCSI_RAM_OFFSET 0x1000 #define CYBERSTORM_SCSI_RAM_SIZE 0x2000 #define CYBERSTORM_SCSI_RAM_MASK 0x1fff struct ncr_state { int id; bool newncr; DeviceState devobject; SCSIDevice *scsid[8]; SCSIBus scsibus; uae_u32 board_mask; uae_u8 *rom; int ramsize; uae_u8 acmemory[128]; uae_u32 expamem_hi; uae_u32 expamem_lo; uaecptr baseaddress; int configured; bool enabled; int rom_start, rom_end, rom_offset; int io_start, io_end, io_mask; uae_u8 state[8]; addrbank *bank; bool irq; bool irqlevel; bool z2; void (*irq_func)(int, int); struct romconfig *rc; struct ncr_state **self_ptr; }; #define MAX_NCR_UNITS 10 static struct ncr_state *ncr_units[MAX_NCR_UNITS + 1]; static void freescsi (SCSIDevice *scsi) { if (scsi) { free_scsi((struct scsi_data*)scsi->handle); xfree (scsi); } } static void freencrunit(struct ncr_state *ncr) { if (!ncr) return; for (int i = 0; i < MAX_NCR_UNITS; i++) { if (ncr_units[i] == ncr) { ncr_units[i] = NULL; } } for (int ch = 0; ch < 8; ch++) { freescsi (ncr->scsid[ch]); ncr->scsid[ch] = NULL; } xfree(ncr->rom); if (ncr->self_ptr) *ncr->self_ptr = NULL; xfree(ncr); } static struct ncr_state *allocscsi(struct ncr_state **ncr, struct romconfig *rc, int ch) { struct ncr_state *scsi; if (ch < 0) { freencrunit(*ncr); *ncr = NULL; } if ((*ncr) == NULL) { scsi = xcalloc(struct ncr_state, 1); for (int i = 0; i < MAX_NCR_UNITS; i++) { if (ncr_units[i] == NULL) { ncr_units[i] = scsi; if (rc) rc->unitdata = scsi; scsi->rc = rc; scsi->self_ptr = ncr; *ncr = scsi; return scsi; } } } return *ncr; } static struct ncr_state *getscsi(struct romconfig *rc) { for (int i = 0; i < MAX_NCR_UNITS; i++) { if (ncr_units[i]) { struct ncr_state *ncr = ncr_units[i]; if (ncr->rc == rc) return ncr; } } return NULL; } static struct ncr_state *getscsiboard(uaecptr addr) { for (int i = 0; ncr_units[i]; i++) { if (!ncr_units[i]->baseaddress && !ncr_units[i]->configured) return ncr_units[i]; if ((addr & ~ncr_units[i]->board_mask) == ncr_units[i]->baseaddress) return ncr_units[i]; } return NULL; } static struct ncr_state *ncr_cs; static struct ncr_state *ncr_bppc; static struct ncr_state *ncr_cpuboard; static struct ncr_state *ncr_we; static struct ncr_state *ncr_a4000t; static struct ncr_state *ncra4091[MAX_DUPLICATE_EXPANSION_BOARDS]; static struct ncr_state *ncr_wildfire; static struct ncr_state *ncr_zeus040; static struct ncr_state *ncr_magnum40; static void set_irq2(int id, int level) { if (level) safe_interrupt_set(IRQ_SOURCE_NCR, 0, false); } static void set_irq6(int id, int level) { if (level) safe_interrupt_set(IRQ_SOURCE_NCR, 0, true); } static void ncr_rethink(void) { for (int i = 0; ncr_units[i]; i++) { if (ncr_units[i] != ncr_cs && ncr_units[i]->irq) safe_interrupt_set(IRQ_SOURCE_NCR, i + 1, ncr_units[i]->irqlevel); } if (ncr_cs && ncr_cs->irq) cyberstorm_mk3_ppc_irq_setonly(0, 1); } /* 720+ */ void pci_set_irq(PCIDevice *pci_dev, int level) { struct ncr_state *ncr = (struct ncr_state*)pci_dev; if (!ncr) return; ncr->irq = level != 0; ncr->irq_func(ncr->id, ncr->irq); } void scsi_req_continue(SCSIRequest *req) { struct scsi_data *sd = (struct scsi_data*)req->dev->handle; if (sd->data_len < 0) { lsi_command_complete(req, sd->status, 0); } else if (sd->data_len) { lsi_transfer_data(req, sd->data_len); } else { if (sd->direction > 0) scsi_emulate_cmd(sd); lsi_command_complete(req, sd->status, 0); } } SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun, uint8_t *buf, int len, void *hba_private) { SCSIRequest *req = xcalloc(SCSIRequest, 1); struct scsi_data *sd = (struct scsi_data*)d->handle; struct ncr_state *ncr = (struct ncr_state*)sd->privdata; req->dev = d; req->hba_private = hba_private; req->bus = &ncr->scsibus; req->bus->qbus.parent = &ncr->devobject; memcpy(sd->cmd, buf, len); sd->cmd_len = len; return req; } int32_t scsi_req_enqueue(SCSIRequest *req) { struct scsi_data *sd = (struct scsi_data*)req->dev->handle; sd->data_len = 0; scsi_start_transfer(sd); scsi_emulate_analyze(sd); //write_log (_T("%02x.%02x.%02x.%02x.%02x.%02x\n"), sd->cmd[0], sd->cmd[1], sd->cmd[2], sd->cmd[3], sd->cmd[4], sd->cmd[5]); if (sd->direction <= 0) scsi_emulate_cmd(sd); if (sd->direction == 0) return 1; return -sd->direction; } void scsi_req_unref(SCSIRequest *req) { xfree(req); } uint8_t *scsi_req_get_buf(SCSIRequest *req) { struct scsi_data *sd = (struct scsi_data*)req->dev->handle; sd->data_len = 0; return sd->buffer; } SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int target, int lun) { struct ncr_state *ncr = (struct ncr_state*)bus->privdata; if (lun != 0 || target < 0 || target >= 8) return NULL; return ncr->scsid[target]; } void scsi_req_cancel(SCSIRequest *req) { write_log(_T("scsi_req_cancel\n")); } int pci_dma_rw(PCIDevice *dev, dma_addr_t addr, void *buf, dma_addr_t len, DMADirection dir) { int i = 0; uae_u8 *p = (uae_u8*)buf; while (len > 0) { if (!dir) { *p = dma_get_byte(addr); } else { dma_put_byte(addr, *p); } p++; len--; addr++; } return 0; } /* 710 */ void pci710_set_irq(PCIDevice *pci_dev, int level) { struct ncr_state *ncr = (struct ncr_state*)pci_dev; if (!ncr) return; ncr->irq = level != 0; ncr->irq_func(ncr->id, ncr->irq); } void scsi710_req_continue(SCSIRequest *req) { struct scsi_data *sd = (struct scsi_data*)req->dev->handle; if (sd->data_len < 0) { lsi710_command_complete(req, sd->status, 0); } else if (sd->data_len) { lsi710_transfer_data(req, sd->data_len); } else { if (sd->direction > 0) scsi_emulate_cmd(sd); lsi710_command_complete(req, sd->status, 0); } } SCSIRequest *scsi710_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun, uint8_t *buf, int len, void *hba_private) { SCSIRequest *req = xcalloc(SCSIRequest, 1); struct scsi_data *sd = (struct scsi_data*)d->handle; struct ncr_state *ncr = (struct ncr_state*)sd->privdata; req->dev = d; req->hba_private = hba_private; req->bus = &ncr->scsibus; req->bus->qbus.parent = &ncr->devobject; memcpy (sd->cmd, buf, len); sd->cmd_len = len; return req; } int32_t scsi710_req_enqueue(SCSIRequest *req) { struct scsi_data *sd = (struct scsi_data*)req->dev->handle; sd->data_len = 0; scsi_start_transfer (sd); scsi_emulate_analyze (sd); //write_log (_T("%02x.%02x.%02x.%02x.%02x.%02x\n"), sd->cmd[0], sd->cmd[1], sd->cmd[2], sd->cmd[3], sd->cmd[4], sd->cmd[5]); if (sd->direction <= 0) scsi_emulate_cmd(sd); if (sd->direction == 0) return 1; return -sd->direction; } void scsi710_req_unref(SCSIRequest *req) { xfree (req); } uint8_t *scsi710_req_get_buf(SCSIRequest *req) { struct scsi_data *sd = (struct scsi_data*)req->dev->handle; sd->data_len = 0; return sd->buffer; } SCSIDevice *scsi710_device_find(SCSIBus *bus, int channel, int target, int lun) { struct ncr_state *ncr = (struct ncr_state*)bus->privdata; if (lun != 0 || target < 0 || target >= 8) return NULL; return ncr->scsid[target]; } void scsi710_req_cancel(SCSIRequest *req) { write_log (_T("scsi_req_cancel\n")); } int pci710_dma_rw(PCIDevice *dev, dma_addr_t addr, void *buf, dma_addr_t len, DMADirection dir) { int i = 0; uae_u8 *p = (uae_u8*)buf; while (len > 0) { if (!dir) { *p = dma_get_byte(addr); } else { dma_put_byte(addr, *p); } p++; len--; addr++; } return 0; } static void check_timer(struct ncr_state *ncr) { if (ncr->state[1] & 1) { int v = (ncr->state[5] << 16) | (ncr->state[6] << 8) | (ncr->state[7]); if (v > 0) { v -= 2304; ncr->state[5] = (v >> 16) & 0xff; ncr->state[6] = (v >> 8) & 0xff; ncr->state[7] = (v >> 0) & 0xff; } if (v <= 0) { ncr->state[0] |= 1; ncr->state[5] = ncr->state[2]; ncr->state[6] = ncr->state[3]; ncr->state[7] = ncr->state[4]; } } if (ncr->state[0] & 1) { set_irq2(ncr->id, 1); } } static void ncr_vsync(void) { for (int i = 0; ncr_units[i]; i++) { if (ncr_units[i] == ncr_magnum40) { check_timer(ncr_magnum40); } } } static uae_u8 read_rombyte(struct ncr_state *ncr, uaecptr addr) { uae_u8 v = ncr->rom[addr]; //write_log (_T("%08X = %02X PC=%08X\n"), addr, v, M68K_GETPC); return v; } static uaecptr beswap(uaecptr addr) { return (addr & ~3) | (3 - (addr & 3)); } static void ncr_io_bput(struct ncr_state *ncr, uaecptr addr, uae_u32 val) { if (addr >= CYBERSTORM_SCSI_RAM_OFFSET && ncr->ramsize) { cyberstorm_scsi_ram_put(addr, val); return; } addr &= ncr->io_mask; lsi_mmio_write(ncr->devobject.lsistate, beswap(addr), val, 1); } static void ncr710_io_bput(struct ncr_state *ncr, uaecptr addr, uae_u32 val) { addr &= ncr->io_mask; lsi710_mmio_write(ncr->devobject.lsistate, beswap(addr), val, 1); } void cpuboard_ncr710_io_bput(uaecptr addr, uae_u32 v) { ncr710_io_bput(ncr_cpuboard, addr, v); } void cpuboard_ncr720_io_bput(uaecptr addr, uae_u32 v) { struct ncr_state *ncr = ncr_cpuboard; addr &= ncr->io_mask; lsi_mmio_write(ncr->devobject.lsistate, beswap(addr), v, 1); } static void ncr_bput2 (struct ncr_state *ncr, uaecptr addr, uae_u32 val) { uae_u32 v = val; addr &= ncr->board_mask; if (ncr == ncr_magnum40 && addr >= 0xa000 && addr <= 0xa200) { int reg = (addr >> 4) & 31; switch (reg) { case 0x10: // timer control ncr->state[1] = (uae_u8)v; if (ncr->state[1] & 1) { ncr->state[5] = ncr->state[2]; ncr->state[6] = ncr->state[3]; ncr->state[7] = ncr->state[4]; } break; case 0x13: // timer hi ncr->state[2] = (uae_u8)v; break; case 0x14: // timer med ncr->state[3] = (uae_u8)v; break; case 0x15: // timer lo ncr->state[4] = (uae_u8)v; break; case 0x1a: // timer ZDS if (ncr->state[0] & 1) set_irq2(ncr->id, 0); ncr->state[0] &= ~1; break; } return; } if (ncr->io_end && (addr < ncr->io_start || addr >= ncr->io_end)) { #if NCR_DEBUG > 1 write_log(_T("ncr_bput none %08x %02x %08x\n"), addr, v & 0xff, M68K_GETPC); #endif return; } #if NCR_DEBUG > 1 write_log(_T("ncr_bput %08x %02x %08x\n"), addr, v & 0xff, M68K_GETPC); #endif if (ncr->newncr) ncr_io_bput(ncr, addr, val); else ncr710_io_bput(ncr, addr, val); } static uae_u32 ncr_io_bget(struct ncr_state *ncr, uaecptr addr) { if (addr >= CYBERSTORM_SCSI_RAM_OFFSET && ncr->ramsize) return cyberstorm_scsi_ram_get(addr); addr &= ncr->io_mask; return (uae_u32)lsi_mmio_read(ncr->devobject.lsistate, beswap(addr), 1); } static uae_u32 ncr710_io_bget(struct ncr_state *ncr, uaecptr addr) { addr &= ncr->io_mask; return (uae_u32)lsi710_mmio_read(ncr->devobject.lsistate, beswap(addr), 1); } uae_u32 cpuboard_ncr710_io_bget(uaecptr addr) { return ncr710_io_bget(ncr_cpuboard, addr); } uae_u32 cpuboard_ncr720_io_bget(uaecptr addr) { struct ncr_state *ncr = ncr_cpuboard; addr &= ncr->io_mask; return (uae_u32)lsi_mmio_read(ncr->devobject.lsistate, beswap(addr), 1); } static bool isncrboard(struct ncr_state *ncr, struct ncr_state **ncrb) { return ncr == ncrb[0] || ncr == ncrb[1] || ncr == ncrb[2] || ncr == ncrb[3]; } static uae_u32 ncr_bget2 (struct ncr_state *ncr, uaecptr addr) { uae_u32 v = 0; addr &= ncr->board_mask; if (ncr->rom && addr >= ncr->rom_start && addr < ncr->rom_end) return read_rombyte (ncr, addr - ncr->rom_offset); if (isncrboard(ncr, ncra4091)) { if (addr == A4091_DIP_OFFSET) { uae_u8 v2 = 0; v2 |= ncr->rc->device_id; v2 |= ncr->rc->device_settings << 3; v2 ^= 0xff & ~7; return v2; } } if (ncr == ncr_magnum40 && addr >= 0xa000 && addr <= 0xa200) { int reg = (addr >> 4) & 31; switch(reg) { case 0x0c: // jumpers (68230 port C) if (currprefs.cpuboard_settings & 1) v |= 0x80; return v; case 0x1a: // timer ZDS return ncr->state[0] & 1; } } if (ncr->io_end && (addr < ncr->io_start || addr >= ncr->io_end)) { #if NCR_DEBUG > 1 write_log(_T("ncr_bget none %08x %02x %08x\n"), addr, v, M68K_GETPC); #endif return v; } if (ncr->newncr) v = ncr_io_bget(ncr, addr); else v = ncr710_io_bget(ncr, addr); #if NCR_DEBUG > 1 write_log(_T("ncr_bget %08x %02x %08x\n"), addr, v, M68K_GETPC); #endif return v; } static uae_u32 REGPARAM2 ncr_lget (struct ncr_state *ncr, uaecptr addr) { uae_u32 v = 0; if (ncr) { addr &= ncr->board_mask; v = (ncr_bget2 (ncr, addr + 3) << 0) | (ncr_bget2 (ncr, addr + 2) << 8) | (ncr_bget2 (ncr, addr + 1) << 16) | (ncr_bget2 (ncr, addr + 0) << 24); } return v; } static uae_u32 REGPARAM2 ncr_wget (struct ncr_state *ncr, uaecptr addr) { uae_u32 v = 0; if (ncr) { v = (ncr_bget2 (ncr, addr) << 8) | ncr_bget2 (ncr, addr + 1); } return v; } static uae_u32 REGPARAM2 ncr_bget (struct ncr_state *ncr, uaecptr addr) { uae_u32 v = 0; if (ncr) { addr &= ncr->board_mask; if (!ncr->configured) { addr &= 65535; if (addr >= sizeof ncr->acmemory) return 0; return ncr->acmemory[addr]; } v = ncr_bget2 (ncr, addr); } return v; } static void REGPARAM2 ncr_lput (struct ncr_state *ncr, uaecptr addr, uae_u32 l) { if (!ncr) return; addr &= ncr->board_mask; ncr_bput2 (ncr, addr + 3, l >> 0); ncr_bput2 (ncr, addr + 2, l >> 8); ncr_bput2 (ncr, addr + 1, l >> 16); ncr_bput2 (ncr, addr + 0, l >> 24); } static void REGPARAM2 ncr_wput (struct ncr_state *ncr, uaecptr addr, uae_u32 w) { if (!ncr) return; w &= 0xffff; addr &= ncr->board_mask; if (!ncr->configured) { addr &= 65535; switch (addr) { case 0x44: map_banks_z3(ncr->bank, expamem_board_pointer >> 16, BOARD_SIZE >> 16); ncr->board_mask = 0x00ffffff; ncr->baseaddress = expamem_board_pointer; ncr->configured = 1; expamem_next (ncr->bank, NULL); break; } return; } ncr_bput2(ncr, addr, w >> 8); ncr_bput2 (ncr, addr + 1, w); } static void REGPARAM2 ncr_bput (struct ncr_state *ncr, uaecptr addr, uae_u32 b) { if (!ncr) return; b &= 0xff; addr &= ncr->board_mask; if (!ncr->configured) { addr &= 65535; if (ncr->z2) { switch (addr) { case 0x48: ncr->expamem_hi = b & 0xff; map_banks_z2(ncr->bank, expamem_board_pointer >> 16, expamem_board_size >> 16); ncr->baseaddress = expamem_board_pointer; ncr->configured = 1; expamem_next(ncr->bank, NULL); break; case 0x4c: ncr->configured = 1; expamem_shutup(ncr->bank); break; case 0x4a: ncr->expamem_lo = b & 0xff; break; } } else { switch (addr) { case 0x4c: ncr->configured = 1; expamem_shutup(ncr->bank); break; case 0x48: ncr->expamem_lo = b & 0xff; break; } } return; } ncr_bput2 (ncr, addr, b); } void ncr710_io_bput_a4000t(uaecptr addr, uae_u32 v) { ncr710_io_bput(ncr_a4000t, addr, v); } uae_u32 ncr710_io_bget_a4000t(uaecptr addr) { return ncr710_io_bget(ncr_a4000t, addr); } void ncr815_io_bput_wildfire(uaecptr addr, uae_u32 v) { ncr_io_bput(ncr_wildfire, addr, v); } uae_u32 ncr815_io_bget_wildfire(uaecptr addr) { return ncr_io_bget(ncr_wildfire, addr); } static void REGPARAM2 ncr_generic_bput (uaecptr addr, uae_u32 b) { struct ncr_state *ncr = getscsiboard(addr); if (ncr) ncr_bput(ncr, addr, b); } static void REGPARAM2 ncr_generic_wput (uaecptr addr, uae_u32 b) { struct ncr_state *ncr = getscsiboard(addr); if (ncr) ncr_wput(ncr, addr, b); } static void REGPARAM2 ncr_generic_lput (uaecptr addr, uae_u32 b) { struct ncr_state *ncr = getscsiboard(addr); if (ncr) ncr_lput(ncr, addr, b); } static uae_u32 REGPARAM2 ncr_generic_bget (uaecptr addr) { struct ncr_state *ncr = getscsiboard(addr); if (ncr) return ncr_bget(ncr, addr); return 0; } static uae_u32 REGPARAM2 ncr_generic_wget (uaecptr addr) { struct ncr_state *ncr = getscsiboard(addr); if (ncr) return ncr_wget(ncr, addr); return 0; } static uae_u32 REGPARAM2 ncr_generic_lget (uaecptr addr) { struct ncr_state *ncr = getscsiboard(addr); if (ncr) return ncr_lget(ncr, addr); return 0; } static void REGPARAM2 cs_bput(uaecptr addr, uae_u32 b) { ncr_bput(ncr_cs, addr, b); } static void REGPARAM2 cs_wput(uaecptr addr, uae_u32 b) { ncr_wput(ncr_cs, addr, b); } static void REGPARAM2 cs_lput(uaecptr addr, uae_u32 b) { ncr_lput(ncr_cs, addr, b); } static uae_u32 REGPARAM2 cs_bget(uaecptr addr) { return ncr_bget(ncr_cs, addr); } static uae_u32 REGPARAM2 cs_wget(uaecptr addr) { return ncr_wget(ncr_cs, addr); } static uae_u32 REGPARAM2 cs_lget(uaecptr addr) { return ncr_lget(ncr_cs, addr); } static addrbank ncr_bank_cs_scsi_ram = { cs_lget, cs_wget, cs_bget, cs_lput, cs_wput, cs_bput, cyberstorm_scsi_ram_xlate, cyberstorm_scsi_ram_check, NULL, NULL, _T("CyberStorm SCSI RAM"), cs_lget, cs_wget, ABFLAG_IO | ABFLAG_THREADSAFE, S_READ, S_WRITE }; static addrbank ncr_bank_cs_scsi_io = { cs_lget, cs_wget, cs_bget, cs_lput, cs_wput, cs_bput, default_xlate, default_check, NULL, NULL, _T("CyberStorm SCSI IO"), dummy_lgeti, dummy_wgeti, ABFLAG_IO | ABFLAG_THREADSAFE, S_READ, S_WRITE }; static struct addrbank_sub ncr_sub_bank_cs[] = { { &ncr_bank_cs_scsi_io, 0x0000, 0x0000 }, { &ncr_bank_cs_scsi_ram, 0x1000, 0x0000 }, { &ncr_bank_cs_scsi_ram, 0x3000, 0x2000 }, { &ncr_bank_cs_scsi_ram, 0x5000, 0x4000 }, { &ncr_bank_cs_scsi_ram, 0x7000, 0x6000 }, { &ncr_bank_cs_scsi_ram, 0x9000, 0x8000 }, { &ncr_bank_cs_scsi_ram, 0xb000, 0xa000 }, { &ncr_bank_cs_scsi_ram, 0xd000, 0xc000 }, { &ncr_bank_cs_scsi_ram, 0xf000, 0xe000 }, { NULL } }; addrbank ncr_bank_cyberstorm = { sub_bank_lget, sub_bank_wget, sub_bank_bget, sub_bank_lput, sub_bank_wput, sub_bank_bput, sub_bank_xlate, sub_bank_check, NULL, NULL, _T("CyberStorm SCSI"), sub_bank_lgeti, sub_bank_wgeti, ABFLAG_IO | ABFLAG_THREADSAFE, S_READ, S_WRITE, ncr_sub_bank_cs }; addrbank ncr_bank_generic = { ncr_generic_lget, ncr_generic_wget, ncr_generic_bget, ncr_generic_lput, ncr_generic_wput, ncr_generic_bput, default_xlate, default_check, NULL, NULL, _T("NCR53C700/800"), dummy_lgeti, dummy_wgeti, ABFLAG_IO | ABFLAG_THREADSAFE | ABFLAG_SAFE, S_READ, S_WRITE }; static void ew (struct ncr_state *ncr, int addr, uae_u8 value) { if (addr == 00 || addr == 02 || addr == 0x40 || addr == 0x42) { ncr->acmemory[addr] = (value & 0xf0); ncr->acmemory[addr + 2] = (value & 0x0f) << 4; } else { ncr->acmemory[addr] = ~(value & 0xf0); ncr->acmemory[addr + 2] = ~((value & 0x0f) << 4); } } static void ncr_init_board(struct ncr_state *ncr) { if (!ncr) return; if (!ncr->devobject.lsistate) { if (ncr->newncr) lsi_scsi_init(&ncr->devobject); else lsi710_scsi_init (&ncr->devobject); } if (ncr->newncr) { ncr->io_mask = 0x7f; lsi_scsi_reset(&ncr->devobject, ncr); } else { ncr->io_mask = 0x3f; lsi710_scsi_reset(&ncr->devobject, ncr); } ncr->board_mask = 0xffff; ncr->irq_func = set_irq2; ncr->bank = &ncr_bank_generic; ncr->configured = 0; } static void ncr_free(void) { for (int i = 0; i < MAX_NCR_UNITS; i++) { freencrunit(ncr_units[i]); } } static void ncr_reset_board(struct ncr_state *ncr); void ncr_reset(int hardreset) { for (int i = 0; i < MAX_NCR_UNITS; i++) { ncr_reset_board(ncr_units[i]); } } static void ncr_reset_board (struct ncr_state *ncr) { if (!ncr) return; ncr->irq = false; device_add_rethink(ncr_rethink); device_add_exit(ncr_free, NULL); device_add_vsync_pre(ncr_vsync); device_add_reset(ncr_reset); } // 01010040 // 01020040 = H // 01040040 = J // 01080040 = K static const uae_u8 warpengine_a4000_autoconfig[16] = { 0x90, 0x13, 0x75, 0x00, 0x08, 0x9b, 0x00, 0x19, 0x01, 0x0e, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00 }; #define WARP_ENGINE_ROM_SIZE 32768 bool ncr710_warpengine_autoconfig_init(struct autoconfig_info *aci) { aci->autoconfigp = warpengine_a4000_autoconfig; device_add_reset(ncr_reset); if (!aci->doinit) return true; struct ncr_state *ncr = getscsi(aci->rc); if (!ncr) return false; xfree(ncr->rom); ncr->rom = NULL; ncr->enabled = true; memset (ncr->acmemory, 0xff, sizeof ncr->acmemory); ncr->rom_start = 0x10; ncr->rom_offset = 0; ncr->rom_end = WARP_ENGINE_ROM_SIZE * 4; ncr->io_start = WARP_ENGINE_IO_OFFSET; ncr->io_end = WARP_ENGINE_IO_END; ncr->io_mask = 0x7f; for (int i = 0; i < 16; i++) { uae_u8 b = warpengine_a4000_autoconfig[i]; if (i == 9) { b = currprefs.cpuboard_settings & 7; if (!b) b = 1; else b <<= 1; } ew(ncr, i * 4, b); } ncr->rom = xcalloc (uae_u8, WARP_ENGINE_ROM_SIZE * 4); struct zfile *z = read_device_from_romconfig(aci->rc, ROMTYPE_CB_WENGINE); if (z) { for (int i = 0; i < WARP_ENGINE_ROM_SIZE; i++) { uae_u8 b = 0xff; zfile_fread(&b, 1, 1, z); ncr->rom[i * 4 + 0] = b | 0x0f; ncr->rom[i * 4 + 1] = 0xff; ncr->rom[i * 4 + 2] = (b << 4) | 0x0f; ncr->rom[i * 4 + 3] = 0xff; } zfile_fclose(z); } ncr_reset_board(ncr); aci->addrbank = &ncr_bank_generic; return true; } bool ncr710_a4091_autoconfig_init (struct autoconfig_info *aci) { uae_u8 *rom = NULL; struct zfile *z = read_device_from_romconfig(aci->rc, ROMTYPE_A4091); if (z) { rom = xcalloc(uae_u8, A4091_ROM_SIZE * 4); for (int i = 0; i < A4091_ROM_SIZE; i++) { uae_u8 b = 0xff; if (zfile_fread(&b, 1, 1, z) == 0) { if (i == 32768) { zfile_fseek(z, 0, SEEK_SET); zfile_fread(&b, 1, 1, z); } } rom[i * 4 + 0] = b | 0x0f; rom[i * 4 + 1] = 0xff; rom[i * 4 + 2] = (b << 4) | 0x0f; rom[i * 4 + 3] = 0xff; if (i < 0x20) { aci->autoconfig_raw[i * 4 + 0] = b; } else if (i >= 0x40 && i < 0x60) { aci->autoconfig_raw[(i - 0x40) * 4 + 2] = b; } } zfile_fclose(z); } device_add_reset(ncr_reset); if (!aci->doinit) { xfree(rom); return true; } struct ncr_state *ncr = getscsi(aci->rc); if (!ncr) { xfree(rom); return false; } xfree(ncr->rom); ncr->rom = rom; ncr->enabled = true; memcpy(ncr->acmemory, aci->autoconfig_raw, sizeof ncr->acmemory); ncr->rom_start = 0; ncr->rom_offset = A4091_ROM_OFFSET; ncr->rom_end = A4091_IO_OFFSET; ncr->io_start = A4091_IO_OFFSET; ncr->io_end = A4091_IO_END; ncr->io_mask = 0x3f; ncr_reset_board(ncr); aci->addrbank = &ncr_bank_generic; return true; } static const uae_u8 zeus040_autoconfig[16] = { 0xd1, 0x96, 0x40, 0x00, 0x07, 0xea, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00 }; bool ncr710_zeus040_autoconfig_init(struct autoconfig_info *aci) { aci->autoconfigp = zeus040_autoconfig; device_add_reset(ncr_reset); if (!aci->doinit) return true; struct ncr_state *ncr = getscsi(aci->rc); if (!ncr) return false; xfree(ncr->rom); ncr->rom = NULL; ncr->enabled = true; memset(ncr->acmemory, 0xff, sizeof ncr->acmemory); ncr->rom_start = 0x8000; ncr->rom_offset = 0x8000; ncr->rom_end = 0x10000; ncr->io_start = 0x4000; ncr->io_end = 0x8000; ncr->io_mask = 0x7f; for (int i = 0; i < 16; i++) { uae_u8 b = zeus040_autoconfig[i]; if (i == 0 && (currprefs.cpuboard_settings & 1)) b &= ~0x10; ew(ncr, i * 4, b); } ncr->rom = xcalloc(uae_u8, 32768); load_rom_rc(aci->rc, ROMTYPE_CB_ZEUS040, 16384, 0, ncr->rom, 32768, 0); ncr_reset_board(ncr); aci->addrbank = &ncr_bank_generic; return true; } bool ncr710_magnum40_autoconfig_init(struct autoconfig_info *aci) { device_add_reset(ncr_reset); if (!aci->doinit) { load_rom_rc(aci->rc, ROMTYPE_CB_MAGNUM40, 65536, 0, aci->autoconfig_raw, 128, 0); return true; } struct ncr_state *ncr = getscsi(aci->rc); if (!ncr) return false; xfree(ncr->rom); ncr->rom = NULL; ncr->enabled = true; memset(ncr->acmemory, 0xff, sizeof ncr->acmemory); ncr->rom_start = 0; ncr->rom_offset = 0; ncr->rom_end = 0x8000; ncr->io_start = 0x8000; ncr->io_end = 0x9000; ncr->io_mask = 0x7f; ncr->rom = xcalloc(uae_u8, 32768); load_rom_rc(aci->rc, ROMTYPE_CB_MAGNUM40, 65536, 0, ncr->rom, 32768, 0); memcpy(ncr->acmemory, ncr->rom, sizeof ncr->acmemory); ncr_reset_board(ncr); aci->addrbank = &ncr_bank_generic; return true; } bool ncr710_draco_init(struct autoconfig_info *aci) { device_add_reset(ncr_reset); if (!aci->doinit) { return true; } struct ncr_state *ncr = getscsi(aci->rc); if (!ncr) return false; ncr->enabled = true; ncr->io_start = 0; ncr->io_end = 0xffff; ncr->io_mask = 0x7f; ncr_reset_board(ncr); aci->addrbank = &ncr_bank_generic; return true; } static void allocscsidevice(struct ncr_state *ncr, int ch, struct scsi_data *handle, int uae_unitnum) { handle->privdata = ncr; ncr->scsid[ch] = xcalloc (SCSIDevice, 1); ncr->scsid[ch]->id = ch; ncr->scsid[ch]->handle = handle; handle->uae_unitnum = uae_unitnum; } static void add_ncr_scsi_hd (struct ncr_state *ncr, int ch, struct hd_hardfiledata *hfd, struct uaedev_config_info *ci, int uae_unitnum) { struct scsi_data *handle = NULL; freescsi (ncr->scsid[ch]); ncr->scsid[ch] = NULL; if (!add_scsi_hd(&handle, ch, hfd, ci)) return; allocscsidevice(ncr, ch, handle, uae_unitnum); ncr->enabled = true; } static void add_ncr_scsi_cd (struct ncr_state *ncr, int ch, int unitnum, int uae_unitnum) { struct scsi_data *handle = NULL; freescsi (ncr->scsid[ch]); ncr->scsid[ch] = NULL; if (!add_scsi_cd(&handle, ch, unitnum)) return; allocscsidevice(ncr, ch, handle, uae_unitnum); ncr->enabled = true; } static void add_ncr_scsi_tape (struct ncr_state *ncr, int ch, const TCHAR *tape_directory, bool readonly, int uae_unitnum) { struct scsi_data *handle = NULL; freescsi (ncr->scsid[ch]); ncr->scsid[ch] = NULL; if (!add_scsi_tape(&handle, ch, tape_directory, readonly)) return; allocscsidevice(ncr, ch, handle, uae_unitnum); ncr->enabled = true; } static void ncr_add_scsi_unit(struct ncr_state **ncrp, int ch, struct uaedev_config_info *ci, struct romconfig *rc, bool newncr) { struct ncr_state *ncr = allocscsi(ncrp, rc, ch); if (!ncr) return; ncr->newncr = newncr; ncr_init_board(ncr); if (ch >= 0 && ncr) { if (ci->type == UAEDEV_CD) add_ncr_scsi_cd (ncr, ch, ci->device_emu_unit, ci->uae_unitnum); else if (ci->type == UAEDEV_TAPE) add_ncr_scsi_tape (ncr, ch, ci->rootdir, ci->readonly, ci->uae_unitnum); else if (ci->type == UAEDEV_HDF) add_ncr_scsi_hd (ncr, ch, NULL, ci, ci->uae_unitnum); } } bool a4000t_scsi_init(struct autoconfig_info *aci) { aci->start = 0xdd0000; aci->size = 0x10000; aci->zorro = 0; return true; } bool is_a4000t_scsi(void) { return ncr_a4000t && ncr_a4000t->enabled; } void a4000t_add_scsi_unit (int ch, struct uaedev_config_info *ci, struct romconfig *rc) { ncr_add_scsi_unit(&ncr_a4000t, ch, ci, rc, false); ncr_a4000t->configured = -1; ncr_a4000t->enabled = true; } void warpengine_add_scsi_unit (int ch, struct uaedev_config_info *ci, struct romconfig *rc) { ncr_add_scsi_unit(&ncr_we, ch, ci, rc, false); } void tekmagic_add_scsi_unit (int ch, struct uaedev_config_info *ci, struct romconfig *rc) { ncr_add_scsi_unit(&ncr_cpuboard, ch, ci, rc, false); } void quikpak_add_scsi_unit(int ch, struct uaedev_config_info *ci, struct romconfig *rc) { ncr_add_scsi_unit(&ncr_cpuboard, ch, ci, rc, true); } void a4091_add_scsi_unit (int ch, struct uaedev_config_info *ci, struct romconfig *rc) { ncr_add_scsi_unit(&ncra4091[ci->controller_type_unit], ch, ci, rc, false); } void cyberstorm_add_scsi_unit(int ch, struct uaedev_config_info *ci, struct romconfig *rc) { ncr_add_scsi_unit(&ncr_cs, ch, ci, rc, true); ncr_cs->configured = -1; ncr_cs->enabled = true; ncr_cs->ramsize = CYBERSTORM_SCSI_RAM_SIZE; ncr_cs->irq_func = cyberstorm_mk3_ppc_irq; ncr_cs->bank = &ncr_bank_cyberstorm; ncr_cs->baseaddress = 0xf40000; } void blizzardppc_add_scsi_unit(int ch, struct uaedev_config_info *ci, struct romconfig *rc) { ncr_add_scsi_unit(&ncr_bppc, ch, ci, rc, false); ncr_bppc->configured = -1; ncr_bppc->enabled = true; ncr_bppc->irq_func = blizzardppc_irq; ncr_bppc->bank = &ncr_bank_cyberstorm; ncr_bppc->baseaddress = 0xf40000; } void wildfire_add_scsi_unit(int ch, struct uaedev_config_info *ci, struct romconfig *rc) { ncr_add_scsi_unit(&ncr_wildfire, ch, ci, rc, true); ncr_wildfire->configured = -1; ncr_wildfire->enabled = true; ncr_wildfire->irq_func = wildfire_ncr815_irq; ncr_wildfire->bank = &ncr_bank_generic; } void zeus040_add_scsi_unit(int ch, struct uaedev_config_info *ci, struct romconfig *rc) { ncr_add_scsi_unit(&ncr_zeus040, ch, ci, rc, false); ncr_zeus040->irq_func = set_irq6; ncr_zeus040->irqlevel = true; ncr_zeus040->z2 = true; } void magnum40_add_scsi_unit(int ch, struct uaedev_config_info *ci, struct romconfig *rc) { ncr_add_scsi_unit(&ncr_magnum40, ch, ci, rc, false); ncr_magnum40->irq_func = set_irq6; ncr_magnum40->irqlevel = true; ncr_magnum40->z2 = true; } extern void draco_set_scsi_irq(int, int); void draco_add_scsi_unit(int ch, struct uaedev_config_info *ci, struct romconfig *rc) { ncr_add_scsi_unit(&ncr_cpuboard, ch, ci, rc, false); ncr_cpuboard->irq_func = draco_set_scsi_irq; ncr_cpuboard->irqlevel = true; ncr_cpuboard->bank = &ncr_bank_generic; } #endif