summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/machine/i82586.h
blob: ad02c0bfecefeeab0ca31d58fc91bedda731f0d1 (plain) (tree)
1
2
3
4
5
6
7
8







                                      





                                       






















































                                                                                                   






                                                                                                     











































































                                                                                                                                                                 
                                                                                                                              


                                                                                                                               

                                                      

                                      
                                           

          
                                                                                                                                                                               
 
                                      


                                             
                                                                                                       
                                                                         
 




                                                                






                                      
                                                   







                                                  
                                            
                                             

                                                        











                                                                              
                                                  


                                   
                                                  
                              





                                                                
                           
                     
                                                              










                                                                           

                                                        



















                                                                                                              






                                                                                                       


                                         
          
                                      


                                             












                                                       

                                                             




                                                                                                                                  
        




                                                                                          
                                                                     

  
                                               

       

















                                         


                                                    
                                                                                                                                                            
 
                                      


                                             












                                                       

                                                             




                                                                                                                                                                                                  
        












                                                                                          
 
                                                                       
                                                          

  
                                               

       
                                                                                                            

  
                                               

       

                                                                                                            
 




                                                                                                            
 



                                                                                                            


                                          



                                                    

                               
// license:BSD-3-Clause
// copyright-holders:Patrick Mackinlay

#ifndef MAME_MACHINE_I82586_H
#define MAME_MACHINE_I82586_H

#pragma once

class i82586_base_device :
	public device_t,
	public device_memory_interface,
	public device_network_interface
{
public:
	enum scb_mask
	{
		T       = 0x00000008, // throttle timers loaded
		RUS     = 0x000000f0, // ru status
		CUS     = 0x00000700, // cu status
		RNR     = 0x00001000, // ru left ready state
		CNA     = 0x00002000, // cu left active state
		FR      = 0x00004000, // ru finished receiving a frame
		CX      = 0x00008000, // cu finished executing a command with its interrupt bit set
		RUC     = 0x00700000, // ru command
		RESET   = 0x00800000, // reset chip (same as hardware reset)
		CUC     = 0x07000000, // cu command
		ACK_RNR = 0x10000000, // acknowledge ru became became not ready
		ACK_CNA = 0x20000000, // acknowledge cu became not active
		ACK_FR  = 0x40000000, // acknowledge ru received a frame
		ACK_CX  = 0x80000000  // acknowledge cu completed an action command
	};

	enum scb_cu_command
	{
		CUC_NOP        = 0x00000000, // no operation
		CUC_START      = 0x01000000, // start execution of first command on cbl
		CUC_RESUME     = 0x02000000, // resume execution of cu
		CUC_SUSPEND    = 0x03000000, // suspend execution after current command
		CUC_ABORT      = 0x04000000, // abort current command immediately
		CUC_THROTTLE_D = 0x05000000, // load throttle timers after next terminal count
		CUC_THROTTLE_I = 0x06000000  // load and restart throttle timers immediately
	};
	enum cu_state : u8
	{
		CU_IDLE      = 0x0, // not executing, not associated with command, initial state
		CU_SUSPENDED = 0x1, // not executing, associated with command
		CU_ACTIVE    = 0x2  // executing, associated with command
	};

	enum scb_ru_command
	{
		RUC_NOP     = 0x00000000, // no operation
		RUC_START   = 0x00100000, // start reception of frames
		RUC_RESUME  = 0x00200000, // resume frame reception
		RUC_SUSPEND = 0x00300000, // suspend frame reception
		RUC_ABORT   = 0x00400000  // abort receiver operation immediately
	};
	enum ru_state : u8
	{
		RU_IDLE      = 0x0, // no resources, discarding frames, initial state
		RU_SUSPENDED = 0x1, // has resources, discarding frames
		RU_NR        = 0x2, // no resources, discarding frames, accumulating statistics
		RU_READY     = 0x4, // has resources, storing frames
		RU_NR_RFD    = 0xa, // no receive frame descriptor resources (not 82586 mode)
		RU_NR_RBD    = 0xc  // no receive block descriptor resources (not 82586 mode)
	};

	enum cu_cb_cs_mask
	{
		CB_MAXCOL = 0x0000000f, // number of collisions
		CB_S5     = 0x00000020, // transmission unsuccessful due to maximum collision retries
		CB_S6     = 0x00000040, // heart beat indicator
		CB_S7     = 0x00000080, // transmission deferred due to traffic on link
		CB_S8     = 0x00000100, // transmission unsuccessful due to dma underrun
		CB_S9     = 0x00000200, // transmission unsuccessful due to loss of cts
		CB_S10    = 0x00000400, // no carrier sense during transmission
		CB_A      = 0x00001000, // command aborted
		CB_OK     = 0x00002000, // error free completion
		CB_B      = 0x00004000, // busy executing command
		CB_C      = 0x00008000, // command completed
		CB_CMD    = 0x00070000, // command operation code
		CB_NC     = 0x00100000, // no crc insertion (82596 only)
		CB_SF     = 0x00080000, // simplified mode (82596 only)
		CB_I      = 0x20000000, // interrupt after completion
		CB_S      = 0x40000000, // suspend after completion
		CB_EL     = 0x80000000  // end of command list
	};
	enum cu_cb_command
	{
		CB_NOP       = 0x00000000, // no operation
		CB_IASETUP   = 0x00010000, // individual address setup
		CB_CONFIGURE = 0x00020000, // configure
		CB_MCSETUP   = 0x00030000, // multicast setup
		CB_TRANSMIT  = 0x00040000, // transmit
		CB_TDREFLECT = 0x00050000, // time domain reflectometer
		CB_DUMP      = 0x00060000, // dump
		CB_DIAGNOSE  = 0x00070000  // diagnose
	};
	enum cu_transmit_count_mask
	{
		TB_COUNT = 0x3fff,
		TB_EOF = 0x8000
	};
	enum cu_tdreflect_mask
	{
		TDR_TIME     = 0x07ff, // time until echo
		TDR_ET_SRT   = 0x1000, // short circuit
		TDR_ET_OPN   = 0x2000, // no termination
		TDR_XCVR_PRB = 0x4000, // transceiver problem
		TDR_LNK_OK   = 0x8000  // no link problem
	};

	enum ru_rfd_cs_mask
	{
		RFD_S_COLLISION = 0x00000001, // receive collision
		RFD_S_MULTICAST = 0x00000002, // multicast address
		RFD_S_TRUNCATED = 0x00000020, // frame truncated

		RFD_S_EOP       = 0x00000040, // no eop
		RFD_S_SHORT     = 0x00000080, // frame too short
		RFD_S_OVERRUN   = 0x00000100, // dma overrun
		RFD_S_BUFFER    = 0x00000200, // no buffer
		RFD_S_ALIGN     = 0x00000400, // alignment error
		RFD_S_CRC       = 0x00000800, // crc error
		RFD_S_LENGTH    = 0x00001000, // length error

		RFD_ERROR_82586 = 0x00000fc0, // 82586 error bits
		RFD_ERROR       = 0x00001fe1, // everything except multicast

		RFD_OK          = 0x00002000, // frame received successfully
		RFD_B           = 0x00004000, // busy receiving frame
		RFD_C           = 0x00008000, // frame reception completed
		RFD_SF          = 0x00080000, // simplified/flexible mode
		RFD_S           = 0x40000000, // suspend after receive
		RFD_EL          = 0x80000000  // end of receive frame list
	};
	enum ru_receive_count_mask
	{
		RB_COUNT = 0x3fff, // actual count
		RB_F     = 0x4000, // buffer used
		RB_EOF   = 0x8000  // end of frame
	};
	enum ru_receive_size_mask
	{
		RB_SIZE = 0x3fff, // receive buffer size
		RB_P    = 0x4000, // rbd prefetched (82596 only)
		RB_EL   = 0x8000  // end of rbd list
	};

	static const u32 SCP_ADDRESS = 0x00fffff4; // the default value of the system configuration pointer
	static const u32 TBD_EMPTY   = 0x0000ffff; // FIXME: datasheet says this field should be "all 1's", but InterPro sets only lower 16 bits (in linear mode)
	static const u32 RBD_EMPTY   = 0x0000ffff;
	static const int MAX_FRAME_SIZE = 65536;   // real device effectively has no limit, emulation relies on index wrapping

	static const u32 FCS_RESIDUE = 0xdebb20e3; // the residue after computing the fcs over a complete frame (including fcs)

	// callback configuration
	auto out_irq_cb() { return m_out_irq.bind(); }

	DECLARE_WRITE_LINE_MEMBER(ca);
	DECLARE_WRITE_LINE_MEMBER(reset_w);

protected:
	i82586_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, endianness_t endian, u8 datawidth, u8 addrwidth);

	// standard device_* overrides
	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 space_config_vector memory_space_config() const override;

	// device_network_interface overrides
	virtual void send_complete_cb(int result) override;
	virtual int recv_start_cb(u8 *buf, int length) override;
	virtual void recv_complete_cb(int result) override;

	// setup and scb
	virtual void initialise() = 0;
	virtual void process_scb();
	virtual void update_scb();

	// command unit
	virtual void cu_execute();
	virtual void cu_complete(const u16 status);
	virtual bool cu_iasetup() = 0;
	virtual bool cu_configure() = 0;
	virtual bool cu_mcsetup() = 0;
	virtual bool cu_transmit(u32 command) = 0;
	virtual bool cu_tdreflect() = 0;
	virtual bool cu_dump() = 0;

	// receive unit
	int recv_start(u8 *buf, int length);
	virtual bool address_filter(u8 *mac);
	virtual u16 ru_execute(u8 *buf, int length) = 0;
	virtual void ru_complete(const u16 status) = 0;

	// helpers
	void set_irq(bool irq);
	virtual u32 address(u32 base, int offset, int address) = 0;
	virtual u32 address(u32 base, int offset, int address, u16 empty) = 0;
	static u32 compute_crc(u8 *buf, int length, bool crc32);
	static u64 address_hash(u8 *buf, int length);
	int fetch_bytes(u8 *buf, u32 src, int length);
	int store_bytes(u32 dst, u8 *buf, int length);
	void dump_bytes(u8 *buf, int length);

	// device_* members
	const address_space_config m_space_config;
	address_space *m_space;

	devcb_write_line m_out_irq;
	static const device_timer_id CU_TIMER = 0;
	emu_timer *m_cu_timer;

	// interrupt state
	bool m_cx;          // command executed (with interrupt)
	bool m_fr;          // frame received
	bool m_cna;         // command unit became inactive
	bool m_rnr;         // receive unit became not ready
	bool m_initialised;
	bool m_reset;
	int m_irq_assert;   // configurable interrupt polarity

	// receive/command unit state
	cu_state m_cu_state; // command unit state
	ru_state m_ru_state; // receive unit state
	u32 m_scp_address;   // system configuration pointer
	u32 m_scb_base;      // system control block base (segmented modes)
	u32 m_scb_address;   // system control block address (linear mode)
	u32 m_scb_cs;        // current scb command and status
	u32 m_cba;           // current command block address
	u32 m_rfd;           // current receive frame descriptor address

	u64 m_mac_multi; // multicast address hash table

	// configure parameters
	enum lb_mode
	{
		LOOPBACK_NONE     = 0x00,
		LOOPBACK_INTERNAL = 0x40,
		LOOPBACK_EXTERNAL = 0x80,
		LOOPBACK_BOTH     = 0xc0  // internal loopback for 82586, external loopback for 82596
	};
	virtual u8 cfg_get(int offset) const = 0;
	virtual void cfg_set(int offset, u8 data) = 0;

	bool cfg_save_bad_frames()   const { return BIT(cfg_get(2), 7); }
	u8 cfg_address_length()      const { return (cfg_get(3) & 0x7) % 7; } // "NOTE: 7 is interpreted as 0"
	bool cfg_no_src_add_ins()    const { return BIT(cfg_get(3), 3); }
	lb_mode cfg_loopback_mode()  const { return (lb_mode)(cfg_get(3) & LOOPBACK_BOTH); }
	bool cfg_promiscuous_mode()  const { return BIT(cfg_get(8), 0); }
	bool cfg_broadcast_disable() const { return BIT(cfg_get(8), 1); }
	bool cfg_no_crc_insertion()  const { return BIT(cfg_get(8), 4); }
	bool cfg_crc16()             const { return BIT(cfg_get(8), 5); }
	u8 cfg_min_frame_length()    const { return cfg_get(10); }
};

class i82586_device : public i82586_base_device
{
public:
	i82586_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

	static const int CFG_SIZE = 12;
	static const int DUMP_SIZE = 170;

protected:
	// standard device_* overrides
	virtual void device_start() override;
	virtual void device_reset() override;

	// setup and scb
	virtual void initialise() override;

	// command unit
	virtual bool cu_iasetup() override;
	virtual bool cu_configure() override;
	virtual bool cu_mcsetup() override;
	virtual bool cu_transmit(u32 command) override;
	virtual bool cu_tdreflect() override;
	virtual bool cu_dump() override;

	// receive unit
	virtual bool address_filter(u8 *mac) override;
	virtual u16 ru_execute(u8 *buf, int length) override;
	virtual void ru_complete(const u16 status) override;

	// helpers
	virtual u32 address(u32 base, int offset, int address) override { return m_scb_base + m_space->read_word(base + offset); }
	virtual u32 address(u32 base, int offset, int address, u16 empty) override;

private:
	// configure parameters
	virtual u8 cfg_get(int offset) const override { return m_cfg_bytes[offset]; }
	virtual void cfg_set(int offset, u8 data) override { m_cfg_bytes[offset] = data; }

	u8 m_cfg_bytes[CFG_SIZE];
	u16 m_rbd_offset; // next available receive buffer descriptor
};

class i82596_device : public i82586_base_device
{
public:
	enum sysbus_mask
	{
		SYSBUS_M    = 0x06,
		SYSBUS_TRG  = 0x08,
		SYSBUS_LOCK = 0x10,
		SYSBUS_INT  = 0x20,
		SYSBUS_BE   = 0x80
	};
	enum sysbus_mode
	{
		MODE_82586       = 0x0,
		MODE_32SEGMENTED = 0x2,
		MODE_LINEAR      = 0x4
	};

	static const int CFG_SIZE = 14;
	static const int DUMP_SIZE = 304;

	void port(u32 data); // cpu access interface

protected:
	i82596_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, endianness_t endian, u8 datawidth);

	// standard device_* overrides
	virtual void device_start() override;
	virtual void device_reset() override;

	// setup and scb
	virtual void initialise() override;

	// command unit
	virtual bool cu_iasetup() override;
	virtual bool cu_configure() override;
	virtual bool cu_mcsetup() override;
	virtual bool cu_transmit(u32 command) override;
	virtual bool cu_tdreflect() override;
	virtual bool cu_dump() override;

	// receive unit
	virtual bool address_filter(u8 *mac) override;
	virtual u16 ru_execute(u8 *buf, int length) override;
	virtual void ru_complete(const u16 status) override;

	// helpers
	virtual u32 address(u32 base, int offset, int address) override { return (mode() == MODE_LINEAR) ? m_space->read_dword(base + address) : m_scb_base + m_space->read_word(base + offset); }
	virtual u32 address(u32 base, int offset, int address, u16 empty) override;

private:
	// configure parameters
	virtual u8 cfg_get(int offset) const override { return m_cfg_bytes[offset]; }
	virtual void cfg_set(int offset, u8 data) override { m_cfg_bytes[offset] = data; }

	bool cfg_crc_in_memory() const { return BIT(cfg_get(11), 2); }
	bool cfg_mc_all()        const { return BIT(cfg_get(11), 5); }
	bool cfg_multi_ia()      const { return BIT(cfg_get(13), 6); }

	// initialisation, configuration and sysbus
	inline sysbus_mode mode() const { return (sysbus_mode)(m_sysbus & SYSBUS_M); }

	u8 m_cfg_bytes[CFG_SIZE];
	u8 m_sysbus;

	u32 m_rbd_address;  // next available receive buffer descriptor
	u64 m_mac_multi_ia; // multi-ia address hash table
};

class i82596_le16_device : public i82596_device
{
public:
	i82596_le16_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
};

class i82596_be16_device : public i82596_device
{
public:
	i82596_be16_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
};

class i82596_le32_device : public i82596_device
{
public:
	i82596_le32_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
};

class i82596_be32_device : public i82596_device
{
public:
	i82596_be32_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
};

DECLARE_DEVICE_TYPE(I82586, i82586_device)
DECLARE_DEVICE_TYPE(I82596_LE16, i82596_le16_device)
DECLARE_DEVICE_TYPE(I82596_BE16, i82596_be16_device)
DECLARE_DEVICE_TYPE(I82596_LE32, i82596_le32_device)
DECLARE_DEVICE_TYPE(I82596_BE32, i82596_be32_device)

#endif // MAME_MACHINE_I82586_H