diff options
Diffstat (limited to 'src/devices/machine/mb89352.cpp')
-rw-r--r-- | src/devices/machine/mb89352.cpp | 671 |
1 files changed, 0 insertions, 671 deletions
diff --git a/src/devices/machine/mb89352.cpp b/src/devices/machine/mb89352.cpp deleted file mode 100644 index 62b9adb78bb..00000000000 --- a/src/devices/machine/mb89352.cpp +++ /dev/null @@ -1,671 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Barry Rodewald -/* - * Fujitsu MB89352A SCSI Protocol Controller - * - * Should be compatible with the MB87030/31, and MB89351 - * - * Used on the Sharp X68000 Super, X68000 XVI and X68030 (internal), and on SCSI expansion cards for any X680x0 (external) - * Also used in Sega's Soreike Kokology 1/2 (drives CD-ROM) - * - * Registers (based on datasheet): - * - * 0: BDID (Bus Device ID) - * bit = device ID (ie: bit 2 = device 2) (read) - * bit 0 = ID1, bit 1 = ID2, bit 2 = ID4 (write) - * - * 1: SCTL (SPC Control) - * (all read/write) - * bit 0 = INT Enable - * bit 1 = Reselect Enable - * bit 2 = Select Enable - * bit 3 = Parity Enable - * bit 4 = Arbitration Phase Enable - * bit 5 = Diag Mode - * bit 6 = Control Reset - * bit 7 = Reset and Disable - * - * 2: SCMD (Command) - * bits 0-2 = Transfer Modifier (read) - * bit 0 = Term Mode (write) - * bit 2 = PRG Xfer (write) - * bit 3 = Intercept Xfer (read/write) - * bit 4 = RST Out (read/write) - * bits 5-7 = Command code (read/write) (would have been nice if these codes were mentioned in the datasheet...) - * 000 = Bus release - * 001 = Selection - * 010 = Reset ATN - * 011 = Set ATN - * 100 = Transfer - * 101 = Transfer Pause - * 110 = Reset ACK/REQ - * 111 = Set ACK/REQ - * - * 3: Unused - * - * 4: INTS (Interrupt Sense) - * on write, clear interrupt - * on read: - * bit 0 = Reset Condition - * bit 1 = SPC Hard Error - * bit 2 = Timeout - * bit 3 = Service Required - * bit 4 = Command Complete - * bit 5 = Disconnect - * bit 6 = Reselected - * bit 7 = Selected - * - * 5: PSNS (Phase Sense) (read-only) - * b7 b0 - * | REQ | ACK | ATN | SEL | BSY | MSG | C/D | I/O | - * SDGC (SPC Diag. Control) (write-only) - * bit 5 = Xfer Enable - * bit 4 = Unused - * all other bits are Diag. of the matching inputs above. - * - * 6: SSTS (SPC Status) (read-only) - * bit 0 = DREG Empty - * bit 1 = DREG Full - * bit 2 = TC=0 - * bit 3 = SCSI RST - * bit 4 = Xfer in progress - * bit 5 = SPC BSY - * bit 6 = Connected to Target - * bit 7 = Connected to Initiator - * - * 7: SERR (SCSI Error Status) (read-only) - * bit 1 = Short Transfer Period - * bit 3 = TC Parity Error - * bit 5 = Xfer Out (related to SDGC bit 5) - * bits 6,7 = Data error (10 = undefined, 00 = no error, 01 and 11 = parity error) - * - * 8: PCTL (Phase Control) - * (read/write) - * bits 0-2 = transfer phase ( | MSG | C/D | I/O | ) - * bits 7 = Bus Free interrupt enable - * other bits read 0 - * - * 9: MBC (Modified Byte Counter) - * (read-only) - * bits 0-3 = MBC bits 0-3 - * other bits read 0 - * - * A: DREG (Data Register) - * 8-bit FIFO - * - * B: TEMP (Temporary Register) - * on read, from SCSI - * on write, to SCSI - * - * C, D, E: TCH, TCM, TCL (Transfer Counter High, Mid, Low) - * 24-bit transfer counter - * - */ - -#include "emu.h" -#include "mb89352.h" - -// SCSI lines readable via PSNS register (reg 5) -#define MB89352_LINE_REQ 0x80 -#define MB89352_LINE_ACK 0x40 -#define MB89352_LINE_ATN 0x20 -#define MB89352_LINE_SEL 0x10 -#define MB89352_LINE_BSY 0x08 -#define MB89352_LINE_MSG 0x04 -#define MB89352_LINE_CD 0x02 -#define MB89352_LINE_IO 0x01 - -// INTS bits -#define INTS_RESET 0x01 -#define INTS_HARD_ERROR 0x02 -#define INTS_TIMEOUT 0x04 -#define INTS_SERVICE_REQUIRED 0x08 -#define INTS_COMMAND_COMPLETE 0x10 -#define INTS_DISCONNECTED 0x20 -#define INTS_RESELECTION 0x40 -#define INTS_SELECTION 0x80 - -// SSTS status bits -#define SSTS_DREG_EMPTY 0x01 -#define SSTS_DREG_FULL 0x02 -#define SSTS_TC_ZERO 0x04 -#define SSTS_SCSI_RST 0x08 -#define SSTS_XFER_IN_PROGRESS 0x10 -#define SSTS_SPC_BSY 0x20 -#define SSTS_TARG_CONNECTED 0x40 -#define SSTS_INIT_CONNECTED 0x80 - -// SERR error status bits -#define SERR_OFFSET 0x01 -#define SERR_SHORT_XFR 0x02 -#define SERR_PHASE_ERR 0x04 -#define SERR_TC_PAR 0x08 -#define SERR_SPC_PAR 0x40 -#define SERR_SCSI_PAR 0x80 - - -/* - * Device config - */ - -DEFINE_DEVICE_TYPE(MB89352A, mb89352_device, "mb89352", "Fujitsu MB89352A") - - -/* - * Device - */ - -mb89352_device::mb89352_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : - legacy_scsi_host_adapter(mconfig, MB89352A, tag, owner, clock), - m_irq_cb(*this), - m_drq_cb(*this) -{ -} - -void mb89352_device::device_start() -{ - legacy_scsi_host_adapter::device_start(); - - m_phase = SCSI_PHASE_BUS_FREE; - m_target = 0; - m_command_index = 0; - m_line_status = 0x00; - m_spc_status = 0x01; // presumably the data reg is empty to start with - m_error_status = 0x00; - m_transfer_count = 0; - if(m_transfer_count == 0) - m_spc_status |= SSTS_TC_ZERO; - m_ints = 0x00; - - m_irq_cb.resolve_safe(); - m_drq_cb.resolve_safe(); - - // allocate read timer - m_transfer_timer = timer_alloc(TIMER_TRANSFER); -} - -void mb89352_device::device_reset() -{ - m_phase = SCSI_PHASE_BUS_FREE; - m_target = 0; - m_command_index = 0; - m_line_status = 0x00; - m_error_status = 0x00; - m_transfer_count = 0; - m_spc_status = 0x05; // presumably the data reg is empty to start with - m_busfree_int_enable = 0; -} - -void mb89352_device::device_stop() -{ -} - -// get the length of a SCSI command based on it's command byte type -int mb89352_device::get_scsi_cmd_len(uint8_t cbyte) -{ - int group; - - group = (cbyte>>5) & 7; - - if (group == 0) return 6; - if (group == 1 || group == 2) return 10; - if (group == 5) return 12; - - fatalerror("MB89352: Unknown SCSI command group %d\n", group); - - // never executed - //return 6; -} - -void mb89352_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - switch(id) - { - case TIMER_TRANSFER: - // TODO: check interrupts are actually enabled - { - m_drq_cb(1); - } - break; - } -} - -void mb89352_device::set_phase(int phase) -{ - m_phase = phase; - switch(phase) - { - case SCSI_PHASE_BUS_FREE: - m_line_status = 0; - m_spc_status &= ~SSTS_XFER_IN_PROGRESS; - break; - case SCSI_PHASE_COMMAND: - m_line_status |= MB89352_LINE_REQ; - m_line_status &= ~MB89352_LINE_ACK; - m_line_status &= ~MB89352_LINE_MSG; - m_line_status |= MB89352_LINE_CD; - m_line_status &= ~MB89352_LINE_IO; - break; - case SCSI_PHASE_STATUS: -// m_line_status |= MB89352_LINE_REQ; -// m_line_status &= ~MB89352_LINE_ACK; - m_line_status &= ~MB89352_LINE_MSG; - m_line_status |= MB89352_LINE_CD; - m_line_status |= MB89352_LINE_IO; - break; - case SCSI_PHASE_DATAIN: -// m_line_status |= MB89352_LINE_REQ; -// m_line_status &= ~MB89352_LINE_ACK; - m_line_status &= ~MB89352_LINE_MSG; - m_line_status &= ~MB89352_LINE_CD; - m_line_status |= MB89352_LINE_IO; - break; - case SCSI_PHASE_DATAOUT: -// m_line_status |= MB89352_LINE_REQ; -// m_line_status &= ~MB89352_LINE_ACK; - m_line_status &= ~MB89352_LINE_MSG; - m_line_status &= ~MB89352_LINE_CD; - m_line_status &= ~MB89352_LINE_IO; - break; - case SCSI_PHASE_MESSAGE_IN: -// m_line_status |= MB89352_LINE_REQ; -// m_line_status &= ~MB89352_LINE_ACK; - m_line_status |= MB89352_LINE_MSG; - m_line_status |= MB89352_LINE_CD; - m_line_status |= MB89352_LINE_IO; - break; - case SCSI_PHASE_MESSAGE_OUT: -// m_line_status |= MB89352_LINE_REQ; -// m_line_status &= ~MB89352_LINE_ACK; - m_line_status |= MB89352_LINE_MSG; - m_line_status |= MB89352_LINE_CD; - m_line_status &= ~MB89352_LINE_IO; - break; - } - logerror("MB89352: phase set to %i\n",m_phase); -} - -uint8_t mb89352_device::mb89352_r(offs_t offset) -{ - uint8_t ret; - switch(offset & 0x0f) - { - case 0x00: // BDID - Bus Device ID - return (1 << m_bdid); - case 0x01: // SCTL - SPC Control - ret = 0x00; - if(m_arbit_enable) - ret |= 0x10; - if(m_parity_enable) - ret |= 0x08; - if(m_sel_enable) - ret |= 0x04; - if(m_resel_enable) - ret |= 0x02; - if(m_int_enable) - ret |= 0x01; - return ret; - case 0x02: // SCMD - Command - return m_scmd; - case 0x03: // Unused - return 0xff; - case 0x04: // INTS - Interrupt Sense - return m_ints; - case 0x05: // PSNS - Phase Sense - return m_line_status; // active low -- but Human68k expects it to be zero? - case 0x06: // SSTS - SPC Status - return m_spc_status; - case 0x07: // SERR - SPC Error Status - /* #define SERR_SCSI_PAR 0x80 - #define SERR_SPC_PAR 0x40 - #define SERR_TC_PAR 0x08 - #define SERR_PHASE_ERR 0x04 - #define SERR_SHORT_XFR 0x02 - #define SERR_OFFSET 0x01*/ - return 0; - case 0x08: // PCTL - Phase Control - return ((m_busfree_int_enable) ? (m_line_status & 0x07) | 0x80 : (m_line_status & 0x07)); - case 0x0a: // DREG - Data register (for data transfers) - if(m_spc_status & SSTS_XFER_IN_PROGRESS) - { - m_data = m_buffer[m_transfer_index % 512]; - m_transfer_index++; - m_transfer_count--; - if(m_transfer_index % 512 == 0) - read_data(m_buffer, 512); - if(m_transfer_count == 0) - { - // End of transfer - m_spc_status &= ~SSTS_XFER_IN_PROGRESS; - m_spc_status |= SSTS_DREG_EMPTY; - m_ints |= INTS_COMMAND_COMPLETE; - if(m_int_enable != 0) - m_irq_cb(1); - if(m_phase == SCSI_PHASE_MESSAGE_IN) - set_phase(SCSI_PHASE_BUS_FREE); - else if(m_phase == SCSI_PHASE_DATAIN) - set_phase(SCSI_PHASE_STATUS); - } - } - return m_data; - case 0x0b: // TEMP - Temporary - logerror("mb89352: read temporary register.\n"); - return m_temp; - case 0x0c: // TCH - Transfer Counter High - return (m_transfer_count & 0x00ff0000) >> 16; - case 0x0d: // TCM - Transfer Counter Mid - return (m_transfer_count & 0x0000ff00) >> 8; - case 0x0e: // TCL - Transfer Counter Low - return (m_transfer_count & 0x000000ff); - default: - logerror("mb89352: read from register %02x\n",offset & 0x0f); - } - return 0xff; -} - -void mb89352_device::mb89352_w(offs_t offset, uint8_t data) -{ - switch(offset & 0x0f) - { - case 0x00: // BDID - Bus Device ID - m_bdid = data; - m_spc_status &= ~SSTS_TARG_CONNECTED; - m_spc_status |= SSTS_INIT_CONNECTED; - logerror("mb89352: BDID set to %i\n",data); - break; - case 0x01: // SCTL - SPC Control - if(data & 0x80) // reset and disable - { - device_reset(); - logerror("mb89352: SCTL: Reset and disable.\n"); - } - if(data & 0x10) - { - m_arbit_enable = 1; - logerror("mb89352: SCTL: Arbitration enabled.\n"); - } - else - m_arbit_enable = 0; - if(data & 0x08) - { - m_parity_enable = 1; - logerror("mb89352: SCTL: Parity enabled.\n"); - } - else - m_parity_enable = 0; - if(data & 0x04) - { - m_sel_enable = 1; - logerror("mb89352: SCTL: Selection enabled.\n"); - } - else - m_sel_enable = 0; - if(data & 0x02) - { - m_resel_enable = 1; - logerror("mb89352: SCTL: Reselection enabled.\n"); - } - else - m_resel_enable = 0; - if(data & 0x01) - { - m_int_enable = 1; - logerror("mb89352: SCTL: Interrupts enabled.\n"); - } - else - { - m_int_enable = 0; - logerror("mb89352: SCTL: Interrupts disabled.\n"); - } - break; - case 0x02: // SCMD - Command - /* From NetBSD/x68k source - #define SCMD_BUS_REL 0x00 - #define SCMD_SELECT 0x20 - #define SCMD_RST_ATN 0x40 - #define SCMD_SET_ATN 0x60 - #define SCMD_XFR 0x80 - #define SCMD_XFR_PAUSE 0xa0 - #define SCMD_RST_ACK 0xc0 - #define SCMD_SET_ACK 0xe0 - */ - m_scmd = data; - switch((data & 0xe0) >> 5) - { - case 0x00: - // Bus Free - m_line_status = 0; - m_spc_status &= ~SSTS_TARG_CONNECTED; - m_spc_status &= ~SSTS_INIT_CONNECTED; - m_spc_status &= ~SSTS_XFER_IN_PROGRESS; - set_phase(SCSI_PHASE_BUS_FREE); - if(m_busfree_int_enable) - { - if(m_int_enable != 0) - m_irq_cb(1); - } - logerror("mb89352: SCMD: Bus free\n"); - break; - case 0x01: - // Selection - m_target = m_temp; - m_target &= ~(1 << m_bdid); // mask off the bit relating to initiator - switch(m_target) - { - case 0x01: m_target = 0; break; - case 0x02: m_target = 1; break; - case 0x04: m_target = 2; break; - case 0x08: m_target = 3; break; - case 0x10: m_target = 4; break; - case 0x20: m_target = 5; break; - case 0x40: m_target = 6; break; - case 0x80: m_target = 7; break; - } - if(m_sel_enable != 0) - { - //m_ints |= INTS_SELECTION; - } - select(m_target); - set_phase(SCSI_PHASE_COMMAND); // straight to command phase, may need a delay between selection and command phases - m_line_status |= MB89352_LINE_SEL; - m_line_status |= MB89352_LINE_BSY; - m_spc_status &= ~SSTS_TARG_CONNECTED; - m_spc_status |= SSTS_INIT_CONNECTED; - m_spc_status |= SSTS_SPC_BSY; - m_ints |= INTS_COMMAND_COMPLETE; - if(m_int_enable != 0) - m_irq_cb(1); - logerror("mb89352: SCMD: Selection (SCSI ID%i)\n",m_target); - break; - case 0x02: // Reset ATN - m_line_status &= ~MB89352_LINE_ATN; - logerror("mb89352: SCMD: Reset ATN\n"); - break; - case 0x03: // Set ATN - m_line_status |= MB89352_LINE_ATN; - logerror("mb89352: SCMD: Set ATN\n"); - break; - case 0x04: // Transfer - m_transfer_index = 0; - m_spc_status |= SSTS_XFER_IN_PROGRESS; - if(m_phase == SCSI_PHASE_DATAIN) // if we are reading data... - { - m_spc_status &= ~SSTS_DREG_EMPTY; // DREG is no longer empty - logerror("data-in\n"); - read_data(m_buffer, 512); - } - if(m_phase == SCSI_PHASE_MESSAGE_IN) - { - m_spc_status &= ~SSTS_DREG_EMPTY; // DREG is no longer empty - m_data = 0; - m_temp = 0x00; - set_phase(SCSI_PHASE_BUS_FREE); - logerror("message-in\n"); - m_spc_status &= ~SSTS_XFER_IN_PROGRESS; - m_command_index = 0; - } - if(m_phase == SCSI_PHASE_COMMAND) - { - logerror("command-in\n"); - m_spc_status |= SSTS_SPC_BSY; - } - logerror("mb89352: SCMD: Start Transfer %02x\n",m_phase); - break; - case 0x05: // Transfer pause - logerror("mb89352: SCMD: Pause Transfer\n"); - break; - case 0x06: // reset REQ/ACK - m_line_status &= ~MB89352_LINE_ACK; - if(m_phase != SCSI_PHASE_BUS_FREE) - { - m_line_status |= MB89352_LINE_REQ; - } - else - { - m_spc_status &= ~SSTS_INIT_CONNECTED; - m_spc_status &= ~SSTS_TARG_CONNECTED; - m_spc_status &= ~SSTS_SPC_BSY; - } - logerror("mb89352: SCMD: Reset REQ/ACK\n"); - break; - case 0x07: // set REQ/ACK - m_line_status &= ~MB89352_LINE_REQ; - m_line_status |= MB89352_LINE_ACK; - logerror("mb89352: SCMD: Set REQ/ACK\n"); - if(m_phase == SCSI_PHASE_COMMAND) - { - m_command[m_command_index++] = m_temp; // temp register puts data onto the SCSI bus - if(m_command_index >= get_scsi_cmd_len(m_command[0])) - { - int x; - int phase; - // execute SCSI command - send_command(m_command, m_command_index); - phase = get_phase(); - if(m_command[0] == 1) // Rezero Unit - not implemented in SCSI code - set_phase(SCSI_PHASE_STATUS); - else - set_phase(phase); - logerror("Command executed: "); - //m_spc_status &= ~SSTS_SPC_BSY; - //m_ints |= INTS_COMMAND_COMPLETE; - - for(x=0;x<m_command_index;x++) - logerror(" %02x",m_command[x]); - logerror("\n"); - } - return; - } - if(m_phase == SCSI_PHASE_STATUS) - { - m_temp = get_status(); - set_phase(SCSI_PHASE_MESSAGE_IN); - return; - } - if(m_phase == SCSI_PHASE_MESSAGE_IN) - { - m_temp = 0x00; - set_phase(SCSI_PHASE_BUS_FREE); - m_command_index = 0; - return; - } - break; - default: - logerror("mb89352: SCMD: Unimplemented command %02x\n",(data & 0xe0) >> 5); - break; - } - break; - case 0x04: // INTS - Interrupt Sense - m_ints &= ~data; // resets relevant status bits to zero - m_irq_cb(0); // clear IRQ - logerror("mb89352: Reset INTS status bits %02x\n",data); - break; - case 0x08: // PCTL - Phase control - if((data & 0x80) == 0 && (m_phase == SCSI_PHASE_SELECT)) // if writing 0 to bit 7, selection phase is reset - { - m_ints &= ~INTS_SELECTION; - m_target = 0; - logerror("mb89352: PCTL selection cancelled\n"); - } - // writing to the low 3 bits sets the phase - if((m_phase & 0x07) != (data & 0x07)) - set_phase(data & 0x07); - m_busfree_int_enable = data & 0x80; - logerror("mb89352: PCTL write %02x\n",data); - break; - case 0x0a: // DREG - Data register - if(m_phase == SCSI_PHASE_COMMAND) - { - m_command[m_command_index++] = data; - if(m_command_index >= get_scsi_cmd_len(m_command[0])) - { - int x; - int phase; - // execute SCSI command - send_command(m_command, m_command_index); - phase = get_phase(); - if(m_command[0] == 1) // Rezero Unit - not implemented in SCSI code - set_phase(SCSI_PHASE_STATUS); - else - set_phase(phase); - logerror("Command executed: "); - //m_ints |= INTS_COMMAND_COMPLETE; - - for(x=0;x<m_command_index;x++) - logerror(" %02x",m_command[x]); - logerror("\n"); - } - return; - } - if(m_spc_status & SSTS_XFER_IN_PROGRESS) - { - m_buffer[m_transfer_index % 512] = data; - m_spc_status |= SSTS_DREG_EMPTY; // DREG is empty once sent - m_transfer_index++; - m_transfer_count--; - if(m_transfer_index % 512 == 0) - write_data(m_buffer, 512); - if(m_transfer_count == 0) - { - // End of transfer - m_spc_status &= ~SSTS_XFER_IN_PROGRESS; - m_spc_status |= SSTS_DREG_EMPTY; - m_ints |= INTS_COMMAND_COMPLETE; - if(m_int_enable != 0) - m_irq_cb(1); - set_phase(SCSI_PHASE_STATUS); - } - } - break; - case 0x0b: // TEMP - Temporary - m_temp = data; - logerror("mb89352: Write %02x to temporary register\n",data); - break; - case 0x0c: // TCH - Transfer Counter High - m_transfer_count = (m_transfer_count & 0x0000ffff) | (data << 16); - if(m_transfer_count == 0) - m_spc_status |= SSTS_TC_ZERO; - else - m_spc_status &= ~SSTS_TC_ZERO; - logerror("mb89352: TCH: Write %02x [%06x]\n",data,m_transfer_count); - break; - case 0x0d: // TCM - Transfer Counter Mid - m_transfer_count = (m_transfer_count & 0x00ff00ff) | (data << 8); - if(m_transfer_count == 0) - m_spc_status |= SSTS_TC_ZERO; - else - m_spc_status &= ~SSTS_TC_ZERO; - logerror("mb89352: TCM: Write %02x [%06x]\n",data,m_transfer_count); - break; - case 0x0e: // TCL - Transfer Counter Low - m_transfer_count = (m_transfer_count & 0x00ffff00) | data; - if(m_transfer_count == 0) - m_spc_status |= SSTS_TC_ZERO; - else - m_spc_status &= ~SSTS_TC_ZERO; - logerror("mb89352: TCL: Write %02x [%06x]\n",data,m_transfer_count); - break; - default: - logerror("mb89352: write %02x to register %02x\n",data,offset & 0x0f); - } -} |