summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/machine/nscsi_bus.h
blob: 16a69b22444eee2d1ce0b1c59995aaac608a2113 (plain) (tree)
1
2
3
4
5
6
7
8
9

                                     



                                
 
 
                                         

                                           
                                                             
                                                                     
                                                                 





                                        
                                                                                                          
 


                                                                 
 

                                

          


                                                       



                                  

                                         




                      
                            





                                       
                                                                            

       
                                                                                                         


                                   

          
                                             

  
                                                                       




















                                                                      
                                                    

          

                                                                                   
 
          



                                                                                                                        







                                             
                                                  




                                  







                                                        
                                                       


                        
                                                    
              


















































































































                                                        
                                                       



                        




















                                                        
                                                       



                          
                          

          
                                         
 


                                                                                                       




                                    
                                              


                                              
                                               


                                 

                                                                      






























































                                                        



                                                        

              
                    









                                                  
                                         





                                           
                                      




                                    
                                   








                                  
                           


















                                                              
 

                                
                                           




                                       

                                                      
 
                                  
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert
#ifndef MAME_MACHINE_NSCSI_BUS_H
#define MAME_MACHINE_NSCSI_BUS_H

#pragma once


#define MCFG_NSCSI_BUS_ADD(_tag)        \
	MCFG_DEVICE_ADD(_tag, NSCSI_BUS, 0)

#define MCFG_NSCSI_ADD(_tag, _slot_intf, _def_slot, _fixed) \
	MCFG_DEVICE_ADD(_tag, NSCSI_CONNECTOR, 0)                   \
	MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _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_t clock);

	void ctrl_w(int refid, uint32_t lines, uint32_t mask);
	void data_w(int refid, uint32_t lines);
	void ctrl_wait(int refid, uint32_t lines, uint32_t mask);

	uint32_t ctrl_r() const;
	uint32_t data_r() const;

protected:
	virtual void device_start() override;
	virtual void device_reset() override;
	virtual void device_config_complete() override;

private:
	struct dev_t {
		nscsi_device *dev;
		uint32_t ctrl, wait_ctrl;
		uint32_t data;
	};

	dev_t dev[16];
	int devcnt;

	uint32_t 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_t clock);
	virtual ~nscsi_connector();

	nscsi_device *get_device();

protected:
	virtual void device_start() override;
};

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
	};

	void connect_to_bus(nscsi_bus_device *bus, int refid, int default_scsi_id);
	virtual void scsi_ctrl_changed();

protected:
	nscsi_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);

	virtual void device_start() override;

	int scsi_id;
	int scsi_refid;
	nscsi_bus_device *scsi_bus;
};

class nscsi_full_device : public nscsi_device
{
public:
	virtual void scsi_ctrl_changed() override;
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
	static const char *const command_names[256];
	enum {
		SC_TEST_UNIT_READY               = 0x00,
		SC_REZERO                        = 0x01,
		SC_REQUEST_SENSE                 = 0x03,
		SC_FORMAT_UNIT                   = 0x04,
		SC_REASSIGN_BLOCKS               = 0x07,
		SC_READ_6                        = 0x08,
		SC_RECIEVE                       = 0x08,
		SC_WRITE_6                       = 0x0a,
		SC_SEND                          = 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_PREVENT_ALLOW_MEDIUM_REMOVAL  = 0x1e,
		SC_READ_FORMAT_CAPACITIES        = 0x23,
		SC_READ_CAPACITY                 = 0x25,
		SC_READ_10                       = 0x28,
		SC_READ_GENERATION               = 0x29,
		SC_WRITE_10                      = 0x2a,
		SC_SEEK_10                       = 0x2b,
		SC_ERASE_10                      = 0x2c,
		SC_READ_UPDATED_BLOCK_10         = 0x2d,
		SC_WRITE_VERIFY                  = 0x2e,
		SC_VERIFY                        = 0x2f,
		SC_SEARCH_DATA_HIGH_10           = 0x30,
		SC_SEARCH_DATA_EQUAL_10          = 0x31,
		SC_SEARCH_DATA_LOW_10            = 0x32,
		SC_SET_LIMITS_10                 = 0x33,
		SC_PREFETCH                      = 0x34,
		SC_SYNC_CACHE                    = 0x35,
		SC_LOCK_UNLOCK_CACHE             = 0x36,
		SC_READ_DEFECT_DATA              = 0x37,
		SC_MEDIUM_SCAN                   = 0x38,
		SC_COMPARE                       = 0x39,
		SC_COPY_AND_VERIFY               = 0x3a,
		SC_WRITE_BUFFER                  = 0x3b,
		SC_READ_DATA_BUFFER              = 0x3c,
		SC_UPDATE_BLOCK                  = 0x3d,
		SC_READ_LONG                     = 0x3e,
		SC_WRITE_LONG                    = 0x3f,
		SC_CHANGE_DEFINITION             = 0x40,
		SC_WRITE_SAME                    = 0x41,
		SC_READ_SUB_CHANNEL              = 0x42,
		SC_READ_TOC_PMA_ATIP             = 0x43,
		SC_READ_HEADER                   = 0x44,
		SC_PLAY_AUDIO_10                 = 0x45,
		SC_GET_CONFIGURATION             = 0x46,
		SC_PLAY_AUDIO_MSF                = 0x47,
		SC_PLAY_AUDIO_TRACK_INDEX        = 0x48,
		SC_PLAY_RELATIVE_10              = 0x49,
		SC_GET_EVENT_STATUS_NOTIFICATION = 0x4a,
		SC_PAUSE_RESUME                  = 0x4b,
		SC_LOG_SELECT                    = 0x4c,
		SC_LOG_SENSE                     = 0x4d,
		SC_STOP_PLAY_SCAN                = 0x4e,
		SC_XDWRITE                       = 0x50,
		SC_XPWRITE                       = 0x51,
		SC_READ_DISC_INFORMATION         = 0x51,
		SC_READ_TRACK_INFORMATION        = 0x52,
		SC_XDREAD                        = 0x52,
		SC_RESERVE_TRACK                 = 0x53,
		SC_SEND_OPC_INFORMATION          = 0x54,
		SC_MODE_SELECT_10                = 0x55,
		SC_RESERVE_10                    = 0x56,
		SC_RELEASE_10                    = 0x57,
		SC_REPAIR_TRACK                  = 0x58,
		SC_READ_MASTER_CUE               = 0x59,
		SC_MODE_SENSE_10                 = 0x5a,
		SC_CLOSE_TRACK_SESSION           = 0x5b,
		SC_READ_BUFFER_CAPACITY          = 0x5c,
		SC_SEND_CUE_SHEET                = 0x5d,
		SC_PERSISTENT_RESERVE_IN         = 0x5e,
		SC_PERSISTENT_RESERVE_OUT        = 0x5f,
		SC_XDWRITE_EXTENDED              = 0x80,
		SC_REBUILD                       = 0x81,
		SC_REGENERATE                    = 0x82,
		SC_EXTENDED_COPY                 = 0x83,
		SC_RECEIVE_COPY_RESULTS          = 0x84,
		SC_REPORT_LUNS                   = 0xa0,
		SC_BLANK                         = 0xa1,
		SC_SEND_EVENT                    = 0xa2,
		SC_REPORT_DEVICE_IDENTIFIER      = 0xa3,
		SC_SEND_KEY                      = 0xa3,
		SC_REPORT_KEY                    = 0xa4,
		SC_SET_DEVICE_IDENTIFIER         = 0xa4,
		SC_PLAY_AUDIO_12                 = 0xa5,
		SC_LOAD_UNLOAD_MEDIUM            = 0xa6,
		SC_MOVE_MEDIUM_ATTACHED          = 0xa7,
		SC_SET_READ_AHEAD                = 0xa7,
		SC_READ_12                       = 0xa8,
		SC_PLAY_RELATIVE_12              = 0xa9,
		SC_WRITE_12                      = 0xaa,
		SC_ERASE_12                      = 0xac,
		SC_GET_PERFORMANCE               = 0xac,
		SC_READ_DVD_STRUCTURE            = 0xad,
		SC_WRITE_AND_VERIFY_12           = 0xae,
		SC_VERIFY_12                     = 0xaf,
		SC_SEARCH_DATA_HIGH_12           = 0xb0,
		SC_SEARCH_DATA_EQUAL_12          = 0xb1,
		SC_SEARCH_DATA_LOW_12            = 0xb2,
		SC_SET_LIMITS_12                 = 0xb3,
		SC_READ_ELEMENT_STATUS_ATTACHED  = 0xb4,
		SC_SET_STREAMING                 = 0xb6,
		SC_READ_DEFECT_DATA_12           = 0xb7,
		SC_READ_CD_MSF                   = 0xb9,
		SC_SCAN_MMC                      = 0xba,
		SC_SET_CD_SPEED                  = 0xbb,
		SC_PLAY_CD                       = 0xbc,
		SC_MECHANISM_STATUS              = 0xbd,
		SC_READ_CD                       = 0xbe,
		SC_SEND_DVD_STRUCTURE            = 0xbf
	};

	// 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
	};

	using nscsi_device::nscsi_device;

	virtual void device_start() override;
	virtual void device_reset() override;
	virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;

	virtual void scsi_message();
	virtual void scsi_command();

	void scsi_unknown_command();
	void scsi_status_complete(uint8_t st);
	void scsi_data_in(int buf, int size);
	void scsi_data_out(int buf, int size);

	void sense(bool deferred, uint8_t key);
	int get_lun(int def = 0);
	void bad_lun();

	virtual uint8_t scsi_get_data(int buf, int offset);
	virtual void scsi_put_data(int buf, int offset, uint8_t 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();

	uint8_t scsi_cmdbuf[4096], scsi_sense_buffer[8];
	int scsi_cmdsize;
	uint8_t scsi_identify;

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_t val);
	void target_send_buffer_byte();
	bool command_done();
};


DECLARE_DEVICE_TYPE(NSCSI_BUS,       nscsi_bus_device)
DECLARE_DEVICE_TYPE(NSCSI_CONNECTOR, nscsi_connector)

#endif // MAME_MACHINE_NSCSI_BUS_H