#ifndef __NSCSI_BUS_H__ #define __NSCSI_BUS_H__ #include "emu.h" #define MCFG_NSCSI_BUS_ADD(_tag) \ MCFG_DEVICE_ADD(_tag, NSCSI_BUS, 0) #define MCFG_NSCSI_ADD(_tag, _slot_intf, _def_slot, _def_inp, _def_config, _def_clock, _fixed) \ MCFG_DEVICE_ADD(_tag, NSCSI_CONNECTOR, 0) \ MCFG_DEVICE_SLOT_INTERFACE_FULL(_slot_intf, _def_slot, _def_inp, _def_config, _def_clock, _fixed) class nscsi_device; class nscsi_bus_device : public device_t { public: nscsi_bus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); void ctrl_w(int refid, UINT32 lines, UINT32 mask); void data_w(int refid, UINT32 lines); void ctrl_wait(int refid, UINT32 lines, UINT32 mask); UINT32 ctrl_r() const; UINT32 data_r() const; protected: virtual void device_start(); virtual void device_reset(); virtual void device_config_complete(); private: struct dev_t { nscsi_device *dev; UINT32 ctrl, wait_ctrl; UINT32 data; }; dev_t dev[16]; int devcnt; UINT32 data, ctrl; void regen_data(); void regen_ctrl(int refid); }; class nscsi_connector: public device_t, public device_slot_interface { public: nscsi_connector(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); virtual ~nscsi_connector(); nscsi_device *get_device(); protected: virtual void device_start(); }; class nscsi_device : public device_t, public device_slot_card_interface { public: // Here because the biggest users are the devices, not the bus enum { S_INP = 0x0001, S_CTL = 0x0002, S_MSG = 0x0004, S_BSY = 0x0008, S_SEL = 0x0010, S_REQ = 0x0020, S_ACK = 0x0040, S_ATN = 0x0080, S_RST = 0x0100, S_ALL = 0x01ff, S_PHASE_DATA_OUT = 0, S_PHASE_DATA_IN = S_INP, S_PHASE_COMMAND = S_CTL, S_PHASE_STATUS = S_CTL|S_INP, S_PHASE_MSG_OUT = S_MSG|S_CTL, S_PHASE_MSG_IN = S_MSG|S_CTL|S_INP, S_PHASE_MASK = S_MSG|S_CTL|S_INP, }; nscsi_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock); void connect_to_bus(nscsi_bus_device *bus, int refid, int default_scsi_id); virtual void scsi_ctrl_changed(); protected: int scsi_id; int scsi_refid; nscsi_bus_device *scsi_bus; }; class nscsi_full_device : public nscsi_device { public: nscsi_full_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock); virtual void scsi_ctrl_changed(); protected: enum { SCSI_TIMER = 100 }; // SCSI status returns enum { SS_GOOD = 0x00, SS_CHECK_CONDITION = 0x02, SS_CONDITION_MET = 0x04, SS_BUSY = 0x08, SS_INT_GOOD = 0x10, SS_INT_CONDITION_MET = 0x14, SS_RESV_CONFLICT = 0x18, SS_TERMINATED = 0x22, SS_QUEUE_FULL = 0x28, }; // SCSI commands enum { SC_TEST_UNIT_READY = 0x00, SC_REZERO = 0x01, SC_REQUEST_SENSE = 0x03, SC_FORMAT_UNIT = 0x04, SC_REASSIGN_BLOCKS = 0x07, SC_READ = 0x08, SC_WRITE = 0x0a, SC_SEEK = 0x0b, SC_INQUIRY = 0x12, SC_MODE_SELECT_6 = 0x15, SC_RESERVE_6 = 0x16, SC_RELEASE_6 = 0x17, SC_MODE_SENSE_6 = 0x1a, SC_START_STOP_UNIT = 0x1b, SC_RECIEVE_DIAG_RES = 0x1c, SC_SEND_DIAGNOSTICS = 0x1d, SC_READ_CAPACITY = 0x25, SC_READ_EXTENDED = 0x28, SC_WRITE_EXTENDED = 0x2a, SC_SEEK_EXTENDED = 0x2b, SC_WRITE_VERIFY = 0x2e, SC_VERIFY = 0x2f, SC_SYNC_CACHE = 0x35, SC_READ_DEFECT_DATA = 0x37, SC_READ_DATA_BUFFER = 0x3c, SC_READ_LONG = 0x3e, SC_WRITE_LONG = 0x3f, SC_CHANGE_DEFINITION = 0x40, SC_LOG_SELECT = 0x4c, SC_LOG_SENSE = 0x4d, SC_MODE_SELECT_10 = 0x55, SC_RESERVE_10 = 0x56, SC_RELEASE_10 = 0x57, SC_MODE_SENSE_10 = 0x5a, }; // SCSI Messages enum { SM_COMMAND_COMPLETE = 0x00, SM_EXTENDED_MSG = 0x01, SM_SAVE_DATA_PTR = 0x02, SM_RESTORE_PTR = 0x03, SM_DISCONNECT = 0x04, SM_INITIATOR_ERROR = 0x05, SM_ABORT = 0x06, SM_MSG_REJECT = 0x07, SM_NOP = 0x08, SM_MSG_PARITY = 0x09, SM_LCMD_COMPLETE = 0x0a, SM_LCMD_COMPLETE_F = 0x0b, SM_BUS_DEVICE_RESET = 0x0c, SM_ABORT_TAG = 0x0d, SM_CLEAR_QUEUE = 0x0e, SM_INIT_RECOVERY = 0x0f, SM_RELEASE_RECOVERY = 0x10, SM_TERMINATE_IO = 0x11, SM_SIMPLE_QUEUE = 0x20, SM_HEAD_QUEUE = 0x21, SM_ORDERED_QUEUE = 0x22, SM_IGNORE_WIDE_RES = 0x23, }; enum { SBUF_MAIN, SBUF_SENSE, }; UINT8 scsi_cmdbuf[4096], scsi_sense_buffer[8]; int scsi_cmdsize; UINT8 scsi_identify; virtual void device_start(); virtual void device_reset(); virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); virtual void scsi_message(); virtual void scsi_command(); void scsi_unknown_command(); void scsi_status_complete(UINT8 st); void scsi_data_in(int buf, int size); void scsi_data_out(int buf, int size); void sense(bool deferred, UINT8 key); int get_lun(int def = 0); void bad_lun(); virtual UINT8 scsi_get_data(int buf, int offset); virtual void scsi_put_data(int buf, int offset, UINT8 data); // Default delays: // Arbitration delay (2.4us) virtual attotime scsi_arbitation_delay(); // Assertion period (90ns) virtual attotime scsi_assertion_period(); // Bus clear delay (800ns) virtual attotime scsi_bus_clear_delay(); // Bus free delay (800ns) virtual attotime scsi_bus_free_delay(); // Bus set delay (1.8us) virtual attotime scsi_bus_set_delay(); // Bus settle delay (400ns) virtual attotime scsi_bus_settle_delay(); // Cable skew delay (10ns) virtual attotime scsi_cable_skew_delay(); // Data release delay (400ns) virtual attotime scsi_data_release_delay(); // Deskew delay (45ns) virtual attotime scsi_deskew_delay(); // Disconnection delay (200us) virtual attotime scsi_disconnection_delay(); // Hold time (45ns) virtual attotime scsi_hold_time(); // Negation period (90ns) virtual attotime scsi_negation_period(); // Reset hold time (25us) virtual attotime scsi_reset_hold_time(); // Selection abort time (200us) virtual attotime scsi_selection_abort_time(); // Selection timeout delay (250ms) virtual attotime scsi_selection_timeout_delay(); // Fast assertion period (30ns) virtual attotime scsi_fast_assertion_period(); // Fast cable skew delay (5ns) virtual attotime scsi_fast_cable_skew_delay(); // Fast deskew delay (20ns) virtual attotime scsi_fast_deskew_delay(); // Fast hold time (10ns) virtual attotime scsi_fast_hold_time(); // Fast negation period (30ns) virtual attotime scsi_fast_negation_period(); private: enum { IDLE, }; enum { TARGET_SELECT_WAIT_BUS_SETTLE = 1, TARGET_SELECT_WAIT_SEL_0, TARGET_NEXT_CONTROL, TARGET_WAIT_MSG_BYTE, TARGET_WAIT_CMD_BYTE, TARGET_WAIT_DATA_IN_BYTE, TARGET_WAIT_DATA_OUT_BYTE, }; enum { RECV_BYTE_T_WAIT_ACK_0 = 1, RECV_BYTE_T_WAIT_ACK_1, SEND_BYTE_T_WAIT_ACK_0, SEND_BYTE_T_WAIT_ACK_1, }; enum { STATE_MASK = 0x00ff, SUB_SHIFT = 8, SUB_MASK = 0xff00, }; enum { BC_MSG_OR_COMMAND, BC_STATUS, BC_MESSAGE_1, BC_MESSAGE_2, BC_DATA_IN, BC_DATA_OUT, BC_BUS_FREE, }; struct control { int action; int param1, param2; }; emu_timer *scsi_timer; int scsi_state, scsi_substate; int scsi_initiator_id; int data_buffer_id, data_buffer_size, data_buffer_pos; control buf_control[32]; int buf_control_rpos; int buf_control_wpos; control *buf_control_push(); control *buf_control_pop(); void step(bool timeout); void target_recv_byte(); void target_send_byte(UINT8 val); void target_send_buffer_byte(); bool command_done(); }; extern const device_type NSCSI_BUS; extern const device_type NSCSI_CONNECTOR; #endif