i82586: functional, ~90% complete (#2498)

* i82586: functional, ~90% complete
* added dumping of 82586 configuration
* i82586: state save
* Changed address handling and filtering.
This commit is contained in:
Patrick Mackinlay 2017-07-21 16:40:55 +07:00 committed by Vas Crabb
parent 3e60ab4a04
commit 754240e3b7
2 changed files with 2198 additions and 34 deletions

File diff suppressed because it is too large Load Diff

View File

@ -15,22 +15,236 @@ class i82586_base_device :
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 = 0x00000007, // number of collisions (82596 only)
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 u32 FCS_RESIDUE = 0xdebb20e3; // the residue after computing the fcs over a complete frame (including fcs)
template <class Object> static devcb_base &static_set_out_irq_callback(device_t &device, Object &&cb) { return downcast<i82586_base_device &>(device).m_out_irq.set_callback(std::forward<Object>(cb)); }
DECLARE_WRITE_LINE_MEMBER(ca);
virtual void recv_cb(u8 *buf, int length) override;
protected:
i82586_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, u8 datawidth, u8 addrwidth);
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;
// setup and scb
virtual void initialise() = 0;
virtual void process_scb();
virtual void update_scb();
// command unit
virtual void cu_execute();
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
virtual bool address_filter(u8 *mac);
virtual void ru_execute(u8 *buf, int length) = 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;
static const device_timer_id RU_TIMER = 1;
emu_timer *m_cu_timer;
emu_timer *m_ru_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_irq_state;
bool m_initialised;
// 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
u8 m_lb_buf[1528]; // storage for loopback frames
int m_lb_length; // length of loopback frame
// 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
@ -38,49 +252,137 @@ 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 void ru_execute(u8 *buf, int length) 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];
};
class i82596_base_device : public i82586_base_device
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_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, u8 datawidth, u8 addrwidth);
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 void ru_execute(u8 *buf, int length) 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_iscp_address;
u64 m_mac_multi_ia; // multi-ia address hash table
};
class i82596sx_device : public i82596_base_device
class i82596_le16_device : public i82596_device
{
public:
i82596sx_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
protected:
private:
i82596_le16_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
};
class i82596dx_device : public i82596_base_device
class i82596_be16_device : public i82596_device
{
public:
i82596dx_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
i82596_be16_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
};
protected:
class i82596_le32_device : public i82596_device
{
public:
i82596_le32_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
};
private:
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(I82596SX, i82596sx_device)
DECLARE_DEVICE_TYPE(I82596DX, i82596dx_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