diff --git a/devices/ethernet/bigmac.cpp b/devices/ethernet/bigmac.cpp index dfe91c5..ea15841 100644 --- a/devices/ethernet/bigmac.cpp +++ b/devices/ethernet/bigmac.cpp @@ -30,6 +30,13 @@ BigMac::BigMac(uint8_t id) { supports_types(HWCompType::MMIO_DEV | HWCompType::ETHER_MAC); this->chip_id = id; + this->chip_reset(); +} + +void BigMac::chip_reset() { + this->event_mask = 0xFFFFU; // disable HW events causing on-chip interrupts + this->stat = 0; + this->phy_reset(); this->mii_reset(); this->srom_reset(); @@ -37,12 +44,38 @@ BigMac::BigMac(uint8_t id) { uint16_t BigMac::read(uint16_t reg_offset) { switch (reg_offset) { + case BigMacReg::XIFC: + return this->tx_if_ctrl; case BigMacReg::CHIP_ID: return this->chip_id; case BigMacReg::MIF_CSR: return (this->mif_csr_old & ~Mif_Data_In) | (this->mii_in_bit << 3); + case BigMacReg::GLOB_STAT: { + uint16_t old_stat = this->stat; + this->stat = 0; // clear-on-read + return old_stat; + } + case BigMacReg::EVENT_MASK: + return this->event_mask; case BigMacReg::SROM_CSR: return (this->srom_csr_old & ~Srom_Data_In) | (this->srom_in_bit << 2); + case BigMacReg::TX_SW_RST: + return this->tx_reset; + case BigMacReg::TX_CONFIG: + return this->tx_config; + case BigMacReg::PEAK_ATT: { + uint8_t old_val = this->peak_attempts; + this->peak_attempts = 0; // clear-on-read + return old_val; + } + case BigMacReg::NC_CNT: + return this->norm_coll_cnt; + case BigMacReg::EX_CNT: + return this->excs_coll_cnt; + case BigMacReg::LT_CNT: + return this->late_coll_cnt; + case BigMacReg::RX_CONFIG: + return this->rx_config; default: LOG_F(WARNING, "%s: unimplemented register at 0x%X", this->name.c_str(), reg_offset); @@ -53,6 +86,20 @@ uint16_t BigMac::read(uint16_t reg_offset) { void BigMac::write(uint16_t reg_offset, uint16_t value) { switch (reg_offset) { + case BigMacReg::XIFC: + this->tx_if_ctrl = value; + break; + case BigMacReg::TX_FIFO_CSR: + this->tx_fifo_enable = !!(value & 1); + this->tx_fifo_size = (((value >> 1) & 0xFF) + 1) << 7; + break; + case BigMacReg::TX_FIFO_TH: + this->tx_fifo_tresh = value; + break; + case BigMacReg::RX_FIFO_CSR: + this->rx_fifo_enable = !!(value & 1); + this->rx_fifo_size = (((value >> 1) & 0xFF) + 1) << 7; + break; case BigMacReg::MIF_CSR: if (value & Mif_Data_Out_En) { // send bits one by one on each low-to-high transition of Mif_Clock @@ -64,6 +111,9 @@ void BigMac::write(uint16_t reg_offset, uint16_t value) { } this->mif_csr_old = value; break; + case BigMacReg::EVENT_MASK: + this->event_mask = value; + break; case BigMacReg::SROM_CSR: if (value & Srom_Chip_Select) { // exchange data on each low-to-high transition of Srom_Clock @@ -80,11 +130,58 @@ void BigMac::write(uint16_t reg_offset, uint16_t value) { this->tx_reset = 0; // acknowledge SW reset } break; + case BigMacReg::TX_CONFIG: + this->tx_config = value; + break; + case BigMacReg::NC_CNT: + this->norm_coll_cnt = value; + break; + case BigMacReg::NT_CNT: + this->net_coll_cnt = value; + break; + case BigMacReg::EX_CNT: + this->excs_coll_cnt = value; + break; + case BigMacReg::LT_CNT: + this->late_coll_cnt = value; + break; + case BigMacReg::RNG_SEED: + this->rng_seed = value; + break; case BigMacReg::RX_SW_RST: if (!value) { LOG_F(INFO, "%s: receiver soft reset asserted", this->name.c_str()); } break; + case BigMacReg::RX_CONFIG: + this->rx_config = value; + break; + case BigMacReg::MAC_ADDR_0: + case BigMacReg::MAC_ADDR_1: + case BigMacReg::MAC_ADDR_2: + this->mac_addr_flt[8 - ((reg_offset >> 4) & 0xF)] = value; + break; + case BigMacReg::RX_FRM_CNT: + this->rcv_frame_cnt = value; + break; + case BigMacReg::RX_LE_CNT: + this->len_err_cnt = value; + break; + case BigMacReg::RX_AE_CNT: + this->align_err_cnt = value; + break; + case BigMacReg::RX_FE_CNT: + this->fcs_err_cnt = value; + break; + case BigMacReg::RX_CVE_CNT: + this->cv_err_cnt = value; + break; + case BigMacReg::HASH_TAB_0: + case BigMacReg::HASH_TAB_1: + case BigMacReg::HASH_TAB_2: + case BigMacReg::HASH_TAB_3: + this->hash_table[(reg_offset >> 4) & 3] = value; + break; default: LOG_F(WARNING, "%s: unimplemented register at 0x%X is written with 0x%X", this->name.c_str(), reg_offset, value); diff --git a/devices/ethernet/bigmac.h b/devices/ethernet/bigmac.h index fd83f2b..2ea4dce 100644 --- a/devices/ethernet/bigmac.h +++ b/devices/ethernet/bigmac.h @@ -37,11 +37,37 @@ enum EthernetCellId : uint8_t { /* BigMac HW registers. */ enum BigMacReg : uint16_t { + XIFC = 0x000, // transceiver interface control + TX_FIFO_CSR = 0x100, + TX_FIFO_TH = 0x110, + RX_FIFO_CSR = 0x120, CHIP_ID = 0x170, MIF_CSR = 0x180, + GLOB_STAT = 0x200, // Apple: kSTAT, Sun: Global Status Register + EVENT_MASK = 0x210, // ambiguously called INT_DISABLE in the Apple source SROM_CSR = 0x190, TX_SW_RST = 0x420, + TX_CONFIG = 0x430, + PEAK_ATT = 0x4E0, // Apple: kPAREG, Sun: PeakAttempts Register + NC_CNT = 0x500, // Normal Collision Counter + NT_CNT = 0x510, // Apple: Network Collision Counter + EX_CNT = 0x520, // Excessive Collision Counter + LT_CNT = 0x530, // Late Collision Counter + RNG_SEED = 0x540, RX_SW_RST = 0x620, + RX_CONFIG = 0x630, + MAC_ADDR_2 = 0x660, + MAC_ADDR_1 = 0x670, + MAC_ADDR_0 = 0x680, + RX_FRM_CNT = 0x690, // Receive Frame Counter + RX_LE_CNT = 0x6A0, // Length Error Counter + RX_AE_CNT = 0x6B0, // Alignment Error Counter + RX_FE_CNT = 0x6C0, // FCS Error Counter + RX_CVE_CNT = 0x6E0, // Code Violation Error Counter + HASH_TAB_3 = 0x700, + HASH_TAB_2 = 0x710, + HASH_TAB_1 = 0x720, + HASH_TAB_0 = 0x730, }; /* MIF_CSR bit definitions. */ @@ -107,6 +133,9 @@ public: uint16_t read(uint16_t reg_offset); void write(uint16_t reg_offset, uint16_t value); +protected: + void chip_reset(); + // MII methods bool mii_rcv_value(uint16_t& var, uint8_t num_bits, uint8_t next_bit); void mii_rcv_bit(); @@ -127,7 +156,32 @@ private: uint8_t chip_id; // BigMac Chip ID // BigMac state - uint16_t tx_reset = 0; + uint16_t tx_reset = 0; // self-clearing one-bit register + uint16_t tx_if_ctrl = 0; + uint16_t rng_seed; + uint16_t norm_coll_cnt = 0; + uint16_t net_coll_cnt = 0; + uint16_t excs_coll_cnt = 0; + uint16_t late_coll_cnt = 0; + uint16_t rcv_frame_cnt = 0; + uint8_t len_err_cnt = 0; + uint8_t align_err_cnt = 0; + uint8_t fcs_err_cnt = 0; + uint8_t cv_err_cnt = 0; + uint8_t peak_attempts = 0; + uint8_t tx_fifo_tresh = 0; + bool tx_fifo_enable = false; + bool rx_fifo_enable = false; + uint16_t tx_fifo_size = 0; + uint16_t rx_fifo_size = 0; + uint16_t hash_table[4] = {}; + uint16_t mac_addr_flt[3] = {}; + uint16_t tx_config = 0; + uint16_t rx_config = 0; + + // Interrupt state + uint16_t event_mask = 0xFFFFU; // inverted mask: 0 - enabled, 1 - disabled + uint16_t stat = 0; // MII state uint8_t mif_csr_old = 0;