// license:BSD-3-Clause // copyright-holders:smf /* * am53cf96.c * * AMD/NCR/Symbios 53CF96 SCSI-2 controller. * Qlogic FAS-236 and Emulex ESP-236 are equivalents * * References: * AMD Am53CF96 manual * */ #include "emu.h" #include "am53cf96.h" #include "bus/scsi/scsihle.h" READ8_MEMBER( am53cf96_device::read ) { int rv; static constexpr int states[] = { 0, 0, 1, 1, 2, 3, 4, 5, 6, 7, 0 }; if (offset == REG_STATUS) { scsi_regs[REG_STATUS] &= ~0x7; scsi_regs[REG_STATUS] |= states[xfer_state]; if (xfer_state < 10) { xfer_state++; } } rv = scsi_regs[offset]; if (offset == REG_FIFO) { // logerror("53cf96: read FIFO %s\n", machine().describe_context()); return 0; } // logerror("53cf96: read reg %d = %x %s\n", reg, rv>>shift, machine().describe_context()); if (offset == REG_IRQSTATE) { scsi_regs[REG_STATUS] &= ~0x80; // clear IRQ flag } return rv; } void am53cf96_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) { scsi_regs[REG_IRQSTATE] = 8; // indicate success scsi_regs[REG_STATUS] |= 0x80; // indicate IRQ m_irq_handler(1); } WRITE8_MEMBER( am53cf96_device::write ) { // logerror("53cf96: w %x to reg %d %s\n", data, offset, machine().describe_context()); // if writing to the target ID, cache it off for later if (offset == REG_STATUS) { last_id = data; } if (offset == REG_XFERCNTLOW || offset == REG_XFERCNTMID || offset == REG_XFERCNTHI) { scsi_regs[REG_STATUS] &= ~0x10; // clear CTZ bit } // FIFO if (offset == REG_FIFO) { // osd_printf_debug("%02x to FIFO @ %02d\n", data, fptr); fifo[fptr++] = data; if (fptr > 15) { fptr = 15; } } // command if (offset == REG_COMMAND) { //dma = (data & 0x80) ? 1 : 0; fptr = 0; switch (data & 0x7f) { case 0: // NOP scsi_regs[REG_IRQSTATE] = 8; // indicate success xfer_state = 0; break; case 2: // reset am53cf96 scsi_regs[REG_IRQSTATE] = 8; // indicate success logerror("53cf96: reset target ID = %d %s\n", last_id, machine().describe_context()); xfer_state = 0; break; case 3: // reset SCSI bus scsi_regs[REG_INTSTATE] = 4; // command sent OK reset_bus(); xfer_state = 0; m_transfer_timer->adjust( attotime::from_hz( 16384 ) ); break; case 0x42: // select with ATN steps m_transfer_timer->adjust( attotime::from_hz( 16384 ) ); if ((fifo[1] == 0) || (fifo[1] == 0x48) || (fifo[1] == 0x4b)) { scsi_regs[REG_INTSTATE] = 6; } else { scsi_regs[REG_INTSTATE] = 4; } logerror("53cf96: command %x exec. target ID = %d %s\n", fifo[1], last_id, machine().describe_context()); select(last_id); send_command(&fifo[1], 12); xfer_state = 0; break; case 0x44: // enable selection/reselection xfer_state = 0; break; case 0x10: // information transfer (must not change xfer_state) case 0x11: // second phase of information transfer case 0x12: // message accepted m_transfer_timer->adjust( attotime::from_hz( 16384 ) ); scsi_regs[REG_INTSTATE] = 6; // command sent OK break; default: printf( "unsupported command %02x\n", data ); break; } } // only update the register mirror if it's not a write-only reg if (offset != REG_STATUS && offset != REG_INTSTATE && offset != REG_IRQSTATE && offset != REG_FIFOSTATE) { scsi_regs[offset] = data; } } am53cf96_device::am53cf96_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : legacy_scsi_host_adapter(mconfig, AM53CF96, tag, owner, clock), m_irq_handler(*this) { } void am53cf96_device::device_start() { legacy_scsi_host_adapter::device_start(); m_irq_handler.resolve_safe(); memset(scsi_regs, 0, sizeof(scsi_regs)); fptr = 0; xfer_state = 0; last_id = -1; save_item( NAME( scsi_regs ) ); save_item( NAME( fifo ) ); save_item( NAME( fptr ) ); save_item( NAME( xfer_state ) ); save_item( NAME( last_id ) ); m_transfer_timer = timer_alloc( TIMER_TRANSFER ); } // retrieve data from the SCSI controller void am53cf96_device::dma_read_data(int bytes, uint8_t *pData) { scsi_regs[REG_STATUS] |= 0x10; // indicate DMA finished read_data(pData, bytes); } // write data to the SCSI controller void am53cf96_device::dma_write_data(int bytes, uint8_t *pData) { // int i; scsi_regs[REG_STATUS] |= 0x10; // indicate DMA finished write_data(pData, bytes); } DEFINE_DEVICE_TYPE(AM53CF96, am53cf96_device, "am53cf96", "AMD 53CF96 SCSI")