mirror of
https://github.com/holub/mame
synced 2025-10-06 09:00:04 +03:00
smc91c9x: Refactor code. WIP. (nw)
This commit is contained in:
parent
4f38e6cc54
commit
bd8d63a3a3
File diff suppressed because it is too large
Load Diff
@ -4,13 +4,15 @@
|
|||||||
|
|
||||||
SMC91C9X ethernet controller implementation
|
SMC91C9X ethernet controller implementation
|
||||||
|
|
||||||
by Aaron Giles, Jean-François DEL NERO
|
by Aaron Giles, Ted Green
|
||||||
|
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
#ifndef MAME_MACHINE_SMC91C9X_H
|
#ifndef MAME_MACHINE_SMC91C9X_H
|
||||||
#define MAME_MACHINE_SMC91C9X_H
|
#define MAME_MACHINE_SMC91C9X_H
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
TYPE DEFINITIONS
|
TYPE DEFINITIONS
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
@ -22,39 +24,205 @@ public:
|
|||||||
|
|
||||||
DECLARE_READ16_MEMBER( read );
|
DECLARE_READ16_MEMBER( read );
|
||||||
DECLARE_WRITE16_MEMBER( write );
|
DECLARE_WRITE16_MEMBER( write );
|
||||||
TIMER_CALLBACK_MEMBER(send_frame);
|
|
||||||
|
|
||||||
virtual void recv_cb(uint8_t *data, int length) override;
|
|
||||||
void set_link_connected(bool connected) { m_link_unconnected = !connected; };
|
void set_link_connected(bool connected) { m_link_unconnected = !connected; };
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
smc91c9x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
enum class dev_type {
|
||||||
|
SMC91C94,
|
||||||
|
SMC91C96
|
||||||
|
};
|
||||||
|
|
||||||
|
smc91c9x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, dev_type device_type);
|
||||||
|
|
||||||
// device-level overrides
|
// device-level overrides
|
||||||
virtual void device_start() override;
|
virtual void device_start() override;
|
||||||
virtual void device_reset() override;
|
virtual void device_reset() override;
|
||||||
|
|
||||||
virtual void device_pre_save(void) override;
|
// device_network_interface overrides
|
||||||
virtual void device_post_load(void) override;
|
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;
|
||||||
|
|
||||||
|
void dump_bytes(u8 *buf, int length);
|
||||||
|
int address_filter(u8 *buf);
|
||||||
|
int receive(u8 *buf, int length);
|
||||||
|
|
||||||
|
TIMER_CALLBACK_MEMBER(tx_poll);
|
||||||
|
|
||||||
|
const dev_type m_device_type;
|
||||||
|
unsigned m_num_ebuf;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr unsigned ETHER_BUFFER_SIZE = 2048;
|
// Ethernet registers - bank 0
|
||||||
// TODO: 96 device is larger
|
enum bank0_addr : u8 {
|
||||||
static constexpr unsigned ETHER_BUFFERS = 16;
|
B0_TCR = (0 * 8 + 0),
|
||||||
static constexpr unsigned ETHERNET_ADDR_SIZE = 6;
|
B0_EPH_STATUS = (0 * 8 + 1),
|
||||||
|
B0_RCR = (0 * 8 + 2),
|
||||||
|
B0_COUNTER = (0 * 8 + 3),
|
||||||
|
B0_MIR = (0 * 8 + 4),
|
||||||
|
B0_MCR = (0 * 8 + 5),
|
||||||
|
B0_BANK = (0 * 8 + 7)
|
||||||
|
};
|
||||||
|
|
||||||
// external network is present
|
// Ethernet registers - bank 1
|
||||||
bool m_network_available;
|
enum bank1_addr : u8 {
|
||||||
|
B1_CONFIG = (1 * 8 + 0),
|
||||||
|
B1_BASE = (1 * 8 + 1),
|
||||||
|
B1_IA0_1 = (1 * 8 + 2),
|
||||||
|
B1_IA2_3 = (1 * 8 + 3),
|
||||||
|
B1_IA4_5 = (1 * 8 + 4),
|
||||||
|
B1_GENERAL_PURP = (1 * 8 + 5),
|
||||||
|
B1_CONTROL = (1 * 8 + 6)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Ethernet registers - bank 2
|
||||||
|
enum bank2_addr : u8 {
|
||||||
|
B2_MMU_COMMAND = (2 * 8 + 0),
|
||||||
|
B2_PNR_ARR = (2 * 8 + 1),
|
||||||
|
B2_FIFO_PORTS = (2 * 8 + 2),
|
||||||
|
B2_POINTER = (2 * 8 + 3),
|
||||||
|
B2_DATA_0 = (2 * 8 + 4),
|
||||||
|
B2_DATA_1 = (2 * 8 + 5),
|
||||||
|
B2_INTERRUPT = (2 * 8 + 6)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Ethernet registers - bank 3
|
||||||
|
enum bank3_addr : u8 {
|
||||||
|
B3_MT0_1 = (3 * 8 + 0),
|
||||||
|
B3_MT2_3 = (3 * 8 + 1),
|
||||||
|
B3_MT4_5 = (3 * 8 + 2),
|
||||||
|
B3_MT6_7 = (3 * 8 + 3),
|
||||||
|
B3_MGMT = (3 * 8 + 4),
|
||||||
|
B3_REVISION = (3 * 8 + 5),
|
||||||
|
B3_ERCV = (3 * 8 + 6)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Ethernet MMU commands
|
||||||
|
enum mmu_cmd : u8 {
|
||||||
|
ECMD_NOP = 0,
|
||||||
|
ECMD_ALLOCATE = 2,
|
||||||
|
ECMD_RESET_MMU = 4,
|
||||||
|
ECMD_REMOVE_TOPFRAME_RX = 6,
|
||||||
|
ECMD_REMOVE_TOPFRAME_TX = 7,
|
||||||
|
ECMD_REMOVE_RELEASE_TOPFRAME_RX = 8,
|
||||||
|
ECMD_RELEASE_PACKET = 10,
|
||||||
|
ECMD_ENQUEUE_PACKET = 12,
|
||||||
|
ECMD_RESET_FIFOS = 14
|
||||||
|
};
|
||||||
|
|
||||||
|
// Ethernet interrupt bits
|
||||||
|
enum eint_def : u8 {
|
||||||
|
EINT_RCV = 0x01,
|
||||||
|
EINT_TX = 0x02,
|
||||||
|
EINT_TX_EMPTY = 0x04,
|
||||||
|
EINT_ALLOC = 0x08,
|
||||||
|
EINT_RX_OVRN = 0x10,
|
||||||
|
EINT_EPH = 0x20,
|
||||||
|
EINT_ERCV = 0x40, // 91c92 only
|
||||||
|
EINT_TX_IDLE = 0x80 // 91c94 only
|
||||||
|
};
|
||||||
|
|
||||||
|
// Address filter return codes
|
||||||
|
enum addr_filter_def : int {
|
||||||
|
ADDR_NOMATCH = 0,
|
||||||
|
ADDR_UNICAST = 1,
|
||||||
|
ADDR_BROADCAST = 2,
|
||||||
|
ADDR_MULTICAST = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
// Rx/Tx control bits
|
||||||
|
enum control_mask : u8 {
|
||||||
|
EBUF_RX_ALWAYS = 0x40, // Always set on receive buffer control byte
|
||||||
|
EBUF_ODD = 0x20, // Odd number of data payload bytes
|
||||||
|
EBUF_CRC = 0x10 // Tx add CRC
|
||||||
|
};
|
||||||
|
|
||||||
|
// Receive buffer status
|
||||||
|
enum rx_status_mask : u16 {
|
||||||
|
ALGNERR = 0x8000,
|
||||||
|
BRODCAST = 0x4000,
|
||||||
|
BADCRC = 0x2000,
|
||||||
|
ODDFRM = 0x1000,
|
||||||
|
TOOLNG = 0x0800, // Received fram is longer than 1518 bytes on cable
|
||||||
|
TOOSHORT = 0x0400, // Received fram is shorter than 64 bytes on cable
|
||||||
|
HASHVALUE = 0x007e,
|
||||||
|
MULTCAST = 0x0001
|
||||||
|
};
|
||||||
|
|
||||||
|
// EPH Status bits
|
||||||
|
enum eph_mask : u16 {
|
||||||
|
LINK_OK = 0x4000, // State of link integrity test
|
||||||
|
CTR_ROL = 0x1000, // Counter roll Over
|
||||||
|
EXC_DEF = 0x0800, // Excessive deferral
|
||||||
|
LOST_CARR = 0x0400, // Lost carrier sense
|
||||||
|
LATCOL = 0x0200, // Late collisions detected
|
||||||
|
WAKEUP = 0x0100, // Magic packet received
|
||||||
|
TX_DEFER = 0x0080, // Transmit deferred
|
||||||
|
LTX_BRD = 0x0040, // Last transmit frame was a broadcast
|
||||||
|
SQET = 0x0020, // Signal Quality Error Test
|
||||||
|
E16COL = 0x0010, // 16 collisions reached
|
||||||
|
LTX_MULT = 0x0008, // Last transmit frame was a multicast
|
||||||
|
MULCOL = 0x0004, // Multiple collisions detected
|
||||||
|
SNGLCOL = 0x0002, // Single collision detected
|
||||||
|
TX_SUC = 0x0001 // Last transmit frame was successful
|
||||||
|
};
|
||||||
|
|
||||||
|
// CTR register bits
|
||||||
|
enum ctr_mask : u16 {
|
||||||
|
RCV_BAD = 0x4000, // Receive bad CRC packets
|
||||||
|
PWRDN = 0x2000, // Power down ethernet
|
||||||
|
WAKEUP_EN = 0x1000, // Enable magic packet wakeup
|
||||||
|
AUTO_RELEASE = 0x0800, // Release transmit packets on good transmission
|
||||||
|
LE_ENABLE = 0x0080, // Link Error enable
|
||||||
|
CR_ENABLE = 0x0040, // Counter Roll over enable
|
||||||
|
TE_ENABLE = 0x0020, // Transmit Error enable
|
||||||
|
EEPROM_SEL = 0x0004, // EEPROM address
|
||||||
|
RELOAD = 0x0002, // Reload config from EEPROM
|
||||||
|
STORE = 0x0001 // Store config to EEPROM
|
||||||
|
};
|
||||||
|
|
||||||
|
// Transmit Control Register bits
|
||||||
|
enum tcr_mask : u16 {
|
||||||
|
FDSE = 0x8000,
|
||||||
|
EPH_LOOP = 0x2000,
|
||||||
|
STP_SQET = 0x1000,
|
||||||
|
FDUPLX = 0x0800,
|
||||||
|
MON_CSN = 0x0400,
|
||||||
|
NOCRC = 0x0100,
|
||||||
|
PAD_EN = 0x0080,
|
||||||
|
FORCOL = 0x0004,
|
||||||
|
LOOP = 0x0002,
|
||||||
|
TXENA = 0x0001
|
||||||
|
};
|
||||||
|
|
||||||
|
// Receive Control Register bits
|
||||||
|
enum rcr_mask : u16 {
|
||||||
|
SOFT_RST = 0x8000,
|
||||||
|
FILT_CAR = 0x4000,
|
||||||
|
STRIP_CRC = 0x0200,
|
||||||
|
RXEN = 0x0100,
|
||||||
|
ALMUL = 0x0004,
|
||||||
|
PRMS = 0x0002,
|
||||||
|
RX_ABORT = 0x0001
|
||||||
|
};
|
||||||
|
|
||||||
|
// Pointer Register bits
|
||||||
|
enum pointer_mask : u16 {
|
||||||
|
RCV = 0x8000,
|
||||||
|
AUTO_INCR = 0x4000,
|
||||||
|
READ = 0x2000,
|
||||||
|
PTR = 0x07ff
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr unsigned ETHER_BUFFER_SIZE = 256 * 6;
|
||||||
|
static const u8 ETH_BROADCAST[];
|
||||||
|
|
||||||
// mmu
|
// mmu
|
||||||
|
|
||||||
// The bits in these vectors indicate a packet has been allocated
|
// The bits in these vectors indicate a packet has been allocated
|
||||||
u32 m_alloc_rx, m_alloc_tx;
|
u32 m_alloc_rx, m_alloc_tx;
|
||||||
std::vector<u32> m_comp_tx, m_comp_rx;
|
|
||||||
// Fifo for allocated (queued) transmit packets
|
|
||||||
std::vector<u32> m_trans_tx;
|
|
||||||
// Save vector data and sizes for proper save state restoration
|
|
||||||
u32 m_comp_tx_data[ETHER_BUFFERS], m_comp_rx_data[ETHER_BUFFERS], m_trans_tx_data[ETHER_BUFFERS];
|
|
||||||
u32 m_comp_tx_size, m_comp_rx_size, m_trans_tx_size;
|
|
||||||
// Requests a packet allocation and returns true
|
// Requests a packet allocation and returns true
|
||||||
// and sets the packet number if successful
|
// and sets the packet number if successful
|
||||||
bool alloc_req(const int tx, int &packet_num);
|
bool alloc_req(const int tx, int &packet_num);
|
||||||
@ -77,23 +245,56 @@ private:
|
|||||||
uint8_t m_irq_state;
|
uint8_t m_irq_state;
|
||||||
|
|
||||||
// Main memory
|
// Main memory
|
||||||
uint8_t m_buffer[ETHER_BUFFER_SIZE * ETHER_BUFFERS];
|
std::unique_ptr<u8[]> m_buffer;
|
||||||
|
|
||||||
/* counters */
|
/* counters */
|
||||||
uint32_t m_sent;
|
uint32_t m_sent;
|
||||||
uint32_t m_recd;
|
uint32_t m_recd;
|
||||||
|
|
||||||
emu_timer* m_tx_timer;
|
emu_timer* m_tx_poll;
|
||||||
|
|
||||||
int ethernet_packet_is_for_me(const uint8_t *mac_address);
|
int m_tx_active;
|
||||||
int is_broadcast(const uint8_t *mac_address);
|
int m_rx_active;
|
||||||
|
int m_tx_retry_count;
|
||||||
|
u8 m_rx_hash;
|
||||||
|
u8 m_loopback_result;
|
||||||
|
|
||||||
void update_ethernet_irq();
|
void update_ethernet_irq();
|
||||||
void update_stats();
|
void update_stats();
|
||||||
|
|
||||||
void process_command(uint16_t data);
|
void process_command(uint16_t data);
|
||||||
void clear_tx_fifo();
|
void reset_tx_fifos();
|
||||||
void clear_rx_fifo();
|
|
||||||
|
// TODO: Make circular fifo a separate device
|
||||||
|
// Simple circular FIFO, power of 2 size, no over/under run checking
|
||||||
|
static constexpr unsigned FIFO_SIZE = 1 << 5;
|
||||||
|
|
||||||
|
// FIFO for allocated (queued) transmit packets
|
||||||
|
u8 m_queued_tx[FIFO_SIZE];
|
||||||
|
int m_queued_tx_h, m_queued_tx_t;
|
||||||
|
void reset_queued_tx() { m_queued_tx_t = m_queued_tx_h = 0; };
|
||||||
|
void push_queued_tx(const u8 &data) { m_queued_tx[m_queued_tx_h++] = data; m_queued_tx_h &= FIFO_SIZE - 1; };
|
||||||
|
u8 pop_queued_tx() { u8 val = m_queued_tx[m_queued_tx_t++]; m_queued_tx_t &= FIFO_SIZE - 1; return val; };
|
||||||
|
bool empty_queued_tx() { return m_queued_tx_h == m_queued_tx_t; };
|
||||||
|
u8 curr_queued_tx() { return m_queued_tx[m_queued_tx_t]; };
|
||||||
|
|
||||||
|
// FIFO for completed transmit packets
|
||||||
|
u8 m_completed_tx[FIFO_SIZE];
|
||||||
|
int m_completed_tx_h, m_completed_tx_t;
|
||||||
|
void reset_completed_tx() { m_completed_tx_t = m_completed_tx_h = 0; };
|
||||||
|
void push_completed_tx(const u8 &data) { m_completed_tx[m_completed_tx_h++] = data; m_completed_tx_h &= FIFO_SIZE - 1; };
|
||||||
|
u8 pop_completed_tx() { u8 val = m_completed_tx[m_completed_tx_t++]; m_completed_tx_t &= FIFO_SIZE - 1; return val; };
|
||||||
|
bool empty_completed_tx() { return m_completed_tx_h == m_completed_tx_t; };
|
||||||
|
u8 curr_completed_tx() { return m_completed_tx[m_completed_tx_t]; };
|
||||||
|
|
||||||
|
// FIFO for completed receive packets
|
||||||
|
u8 m_completed_rx[FIFO_SIZE];
|
||||||
|
int m_completed_rx_h, m_completed_rx_t;
|
||||||
|
void reset_completed_rx() { m_completed_rx_t = m_completed_rx_h = 0; };
|
||||||
|
void push_completed_rx(const u8 &data) { m_completed_rx[m_completed_rx_h++] = data; m_completed_rx_h &= FIFO_SIZE - 1; };
|
||||||
|
u8 pop_completed_rx() { u8 val = m_completed_rx[m_completed_rx_t++]; m_completed_rx_t &= FIFO_SIZE - 1; return val; };
|
||||||
|
bool empty_completed_rx() { return m_completed_rx_h == m_completed_rx_t; };
|
||||||
|
u8 curr_completed_rx() { return m_completed_rx[m_completed_rx_t]; };
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user