1 // license:BSD-3-Clause 2 // copyright-holders:Aaron Giles 3 /************************************************************************* 4 5 SMC91C9X ethernet controller implementation 6 7 by Aaron Giles, Ted Green 8 9 **************************************************************************/ 10 11 #ifndef MAME_MACHINE_SMC91C9X_H 12 #define MAME_MACHINE_SMC91C9X_H 13 14 #pragma once 15 16 /*************************************************************************** 17 TYPE DEFINITIONS 18 ***************************************************************************/ 19 20 class smc91c9x_device : public device_t,public device_network_interface 21 { 22 public: irq_handler()23 auto irq_handler() { return m_irq_handler.bind(); } 24 25 u16 read(offs_t offset, u16 mem_mask = ~0); 26 void write(offs_t offset, u16 data, u16 mem_mask = ~0); 27 set_link_connected(bool connected)28 void set_link_connected(bool connected) { m_link_unconnected = !connected; }; 29 30 protected: 31 enum class dev_type { 32 SMC91C94, 33 SMC91C96 34 }; 35 36 smc91c9x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, dev_type device_type); 37 38 // device-level overrides 39 virtual void device_start() override; 40 virtual void device_reset() override; 41 42 // device_network_interface overrides 43 virtual void send_complete_cb(int result) override; 44 virtual int recv_start_cb(u8 *buf, int length) override; 45 virtual void recv_complete_cb(int result) override; 46 47 void dump_bytes(u8 *buf, int length); 48 int address_filter(u8 *buf); 49 int receive(u8 *buf, int length); 50 51 TIMER_CALLBACK_MEMBER(tx_poll); 52 53 const dev_type m_device_type; 54 unsigned m_num_ebuf; 55 56 private: 57 // Ethernet registers - bank 0 58 enum bank0_addr : u8 { 59 B0_TCR = (0 * 8 + 0), 60 B0_EPH_STATUS = (0 * 8 + 1), 61 B0_RCR = (0 * 8 + 2), 62 B0_COUNTER = (0 * 8 + 3), 63 B0_MIR = (0 * 8 + 4), 64 B0_MCR = (0 * 8 + 5), 65 B0_BANK = (0 * 8 + 7) 66 }; 67 68 // Ethernet registers - bank 1 69 enum bank1_addr : u8 { 70 B1_CONFIG = (1 * 8 + 0), 71 B1_BASE = (1 * 8 + 1), 72 B1_IA0_1 = (1 * 8 + 2), 73 B1_IA2_3 = (1 * 8 + 3), 74 B1_IA4_5 = (1 * 8 + 4), 75 B1_GENERAL_PURP = (1 * 8 + 5), 76 B1_CONTROL = (1 * 8 + 6) 77 }; 78 79 // Ethernet registers - bank 2 80 enum bank2_addr : u8 { 81 B2_MMU_COMMAND = (2 * 8 + 0), 82 B2_PNR_ARR = (2 * 8 + 1), 83 B2_FIFO_PORTS = (2 * 8 + 2), 84 B2_POINTER = (2 * 8 + 3), 85 B2_DATA_0 = (2 * 8 + 4), 86 B2_DATA_1 = (2 * 8 + 5), 87 B2_INTERRUPT = (2 * 8 + 6) 88 }; 89 90 // Ethernet registers - bank 3 91 enum bank3_addr : u8 { 92 B3_MT0_1 = (3 * 8 + 0), 93 B3_MT2_3 = (3 * 8 + 1), 94 B3_MT4_5 = (3 * 8 + 2), 95 B3_MT6_7 = (3 * 8 + 3), 96 B3_MGMT = (3 * 8 + 4), 97 B3_REVISION = (3 * 8 + 5), 98 B3_ERCV = (3 * 8 + 6) 99 }; 100 101 // Ethernet MMU commands 102 enum mmu_cmd : u8 { 103 ECMD_NOP = 0, 104 ECMD_ALLOCATE = 2, 105 ECMD_RESET_MMU = 4, 106 ECMD_REMOVE_TOPFRAME_RX = 6, 107 ECMD_REMOVE_TOPFRAME_TX = 7, 108 ECMD_REMOVE_RELEASE_TOPFRAME_RX = 8, 109 ECMD_RELEASE_PACKET = 10, 110 ECMD_ENQUEUE_PACKET = 12, 111 ECMD_RESET_FIFOS = 14 112 }; 113 114 // Ethernet interrupt bits 115 enum eint_def : u8 { 116 EINT_RCV = 0x01, 117 EINT_TX = 0x02, 118 EINT_TX_EMPTY = 0x04, 119 EINT_ALLOC = 0x08, 120 EINT_RX_OVRN = 0x10, 121 EINT_EPH = 0x20, 122 EINT_ERCV = 0x40, // 91c92 only 123 EINT_TX_IDLE = 0x80 // 91c94 only 124 }; 125 126 // Address filter return codes 127 enum addr_filter_def : int { 128 ADDR_NOMATCH = 0, 129 ADDR_UNICAST = 1, 130 ADDR_BROADCAST = 2, 131 ADDR_MULTICAST = 3 132 }; 133 134 // Rx/Tx control bits 135 enum control_mask : u8 { 136 EBUF_RX_ALWAYS = 0x40, // Always set on receive buffer control byte 137 EBUF_ODD = 0x20, // Odd number of data payload bytes 138 EBUF_CRC = 0x10 // Tx add CRC 139 }; 140 141 // Receive buffer status 142 enum rx_status_mask : u16 { 143 ALGNERR = 0x8000, 144 BRODCAST = 0x4000, 145 BADCRC = 0x2000, 146 ODDFRM = 0x1000, 147 TOOLNG = 0x0800, // Received fram is longer than 1518 bytes on cable 148 TOOSHORT = 0x0400, // Received fram is shorter than 64 bytes on cable 149 HASHVALUE = 0x007e, 150 MULTCAST = 0x0001 151 }; 152 153 // EPH Status bits 154 enum eph_mask : u16 { 155 LINK_OK = 0x4000, // State of link integrity test 156 CTR_ROL = 0x1000, // Counter roll Over 157 EXC_DEF = 0x0800, // Excessive deferral 158 LOST_CARR = 0x0400, // Lost carrier sense 159 LATCOL = 0x0200, // Late collisions detected 160 WAKEUP = 0x0100, // Magic packet received 161 TX_DEFER = 0x0080, // Transmit deferred 162 LTX_BRD = 0x0040, // Last transmit frame was a broadcast 163 SQET = 0x0020, // Signal Quality Error Test 164 E16COL = 0x0010, // 16 collisions reached 165 LTX_MULT = 0x0008, // Last transmit frame was a multicast 166 MULCOL = 0x0004, // Multiple collisions detected 167 SNGLCOL = 0x0002, // Single collision detected 168 TX_SUC = 0x0001 // Last transmit frame was successful 169 }; 170 171 // CTR register bits 172 enum ctr_mask : u16 { 173 RCV_BAD = 0x4000, // Receive bad CRC packets 174 PWRDN = 0x2000, // Power down ethernet 175 WAKEUP_EN = 0x1000, // Enable magic packet wakeup 176 AUTO_RELEASE = 0x0800, // Release transmit packets on good transmission 177 LE_ENABLE = 0x0080, // Link Error enable 178 CR_ENABLE = 0x0040, // Counter Roll over enable 179 TE_ENABLE = 0x0020, // Transmit Error enable 180 EEPROM_SEL = 0x0004, // EEPROM address 181 RELOAD = 0x0002, // Reload config from EEPROM 182 STORE = 0x0001 // Store config to EEPROM 183 }; 184 185 // Transmit Control Register bits 186 enum tcr_mask : u16 { 187 FDSE = 0x8000, 188 EPH_LOOP = 0x2000, 189 STP_SQET = 0x1000, 190 FDUPLX = 0x0800, 191 MON_CSN = 0x0400, 192 NOCRC = 0x0100, 193 PAD_EN = 0x0080, 194 FORCOL = 0x0004, 195 LOOP = 0x0002, 196 TXENA = 0x0001 197 }; 198 199 // Receive Control Register bits 200 enum rcr_mask : u16 { 201 SOFT_RST = 0x8000, 202 FILT_CAR = 0x4000, 203 STRIP_CRC = 0x0200, 204 RXEN = 0x0100, 205 ALMUL = 0x0004, 206 PRMS = 0x0002, 207 RX_ABORT = 0x0001 208 }; 209 210 // Pointer Register bits 211 enum pointer_mask : u16 { 212 RCV = 0x8000, 213 AUTO_INCR = 0x4000, 214 READ = 0x2000, 215 PTR = 0x07ff 216 }; 217 218 static constexpr unsigned ETHER_BUFFER_SIZE = 256 * 6; 219 static const u8 ETH_BROADCAST[]; 220 static const u8 WMS_OUI[]; 221 222 // mmu 223 224 // The bits in these vectors indicate a packet has been allocated 225 u32 m_alloc_rx, m_alloc_tx; 226 227 // Requests a packet allocation and returns true 228 // and sets the packet number if successful 229 bool alloc_req(const int tx, int &packet_num); 230 // Releases an allocation 231 void alloc_release(const int packet_num); 232 // Resets the MMU 233 void mmu_reset(); 234 235 // internal state 236 devcb_write_line m_irq_handler; 237 238 // link unconnected 239 bool m_link_unconnected; 240 241 /* raw register data and masks */ 242 uint16_t m_reg[64]; 243 uint16_t m_regmask[64]; 244 245 /* IRQ information */ 246 uint8_t m_irq_state; 247 248 // Main memory 249 std::unique_ptr<u8[]> m_buffer; 250 251 /* counters */ 252 uint32_t m_sent; 253 uint32_t m_recd; 254 255 emu_timer* m_tx_poll; 256 257 int m_tx_active; 258 int m_rx_active; 259 int m_tx_retry_count; 260 u8 m_rx_hash; 261 u8 m_loopback_result; 262 263 void update_ethernet_irq(); 264 void update_stats(); 265 266 void process_command(uint16_t data); 267 void reset_tx_fifos(); 268 269 // TODO: Make circular fifo a separate device 270 // Simple circular FIFO, power of 2 size, no over/under run checking 271 static constexpr unsigned FIFO_SIZE = 1 << 5; 272 273 // FIFO for allocated (queued) transmit packets 274 u8 m_queued_tx[FIFO_SIZE]; 275 int m_queued_tx_h, m_queued_tx_t; reset_queued_tx()276 void reset_queued_tx() { m_queued_tx_t = m_queued_tx_h = 0; }; push_queued_tx(const u8 & data)277 void push_queued_tx(const u8 &data) { m_queued_tx[m_queued_tx_h++] = data; m_queued_tx_h &= FIFO_SIZE - 1; }; pop_queued_tx()278 u8 pop_queued_tx() { u8 val = m_queued_tx[m_queued_tx_t++]; m_queued_tx_t &= FIFO_SIZE - 1; return val; }; empty_queued_tx()279 bool empty_queued_tx() const { return m_queued_tx_h == m_queued_tx_t; }; curr_queued_tx()280 u8 curr_queued_tx() const { return m_queued_tx[m_queued_tx_t]; }; 281 282 // FIFO for completed transmit packets 283 u8 m_completed_tx[FIFO_SIZE]; 284 int m_completed_tx_h, m_completed_tx_t; reset_completed_tx()285 void reset_completed_tx() { m_completed_tx_t = m_completed_tx_h = 0; }; push_completed_tx(const u8 & data)286 void push_completed_tx(const u8 &data) { m_completed_tx[m_completed_tx_h++] = data; m_completed_tx_h &= FIFO_SIZE - 1; }; pop_completed_tx()287 u8 pop_completed_tx() { u8 val = m_completed_tx[m_completed_tx_t++]; m_completed_tx_t &= FIFO_SIZE - 1; return val; }; empty_completed_tx()288 bool empty_completed_tx() const { return m_completed_tx_h == m_completed_tx_t; }; curr_completed_tx()289 u8 curr_completed_tx() const { return m_completed_tx[m_completed_tx_t]; }; 290 291 // FIFO for completed receive packets 292 u8 m_completed_rx[FIFO_SIZE]; 293 int m_completed_rx_h, m_completed_rx_t; reset_completed_rx()294 void reset_completed_rx() { m_completed_rx_t = m_completed_rx_h = 0; }; push_completed_rx(const u8 & data)295 void push_completed_rx(const u8 &data) { m_completed_rx[m_completed_rx_h++] = data; m_completed_rx_h &= FIFO_SIZE - 1; }; pop_completed_rx()296 u8 pop_completed_rx() { u8 val = m_completed_rx[m_completed_rx_t++]; m_completed_rx_t &= FIFO_SIZE - 1; return val; }; empty_completed_rx()297 bool empty_completed_rx() const { return m_completed_rx_h == m_completed_rx_t; }; curr_completed_rx()298 u8 curr_completed_rx() const { return m_completed_rx[m_completed_rx_t]; }; 299 300 }; 301 302 303 class smc91c94_device : public smc91c9x_device 304 { 305 public: 306 smc91c94_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); 307 }; 308 309 class smc91c96_device : public smc91c9x_device 310 { 311 public: 312 smc91c96_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); 313 }; 314 315 316 DECLARE_DEVICE_TYPE(SMC91C94, smc91c94_device) 317 DECLARE_DEVICE_TYPE(SMC91C96, smc91c96_device) 318 319 320 /*************************************************************************** 321 DEVICE CONFIGURATION MACROS 322 ***************************************************************************/ 323 324 #endif // MAME_MACHINE_SMC91C9X_H 325