From 482fe3eb80484d10ba3b579fc298431ffe886ffb Mon Sep 17 00:00:00 2001 From: Maxim Poliakovski Date: Sat, 8 Jul 2023 21:32:26 +0200 Subject: [PATCH] bigmac: MAC serial EEPROM emulation. --- devices/ethernet/bigmac.cpp | 77 +++++++++++++++++++++++++++++++++++++ devices/ethernet/bigmac.h | 36 ++++++++++++++++- 2 files changed, 111 insertions(+), 2 deletions(-) diff --git a/devices/ethernet/bigmac.cpp b/devices/ethernet/bigmac.cpp index f312867..c9ecac7 100644 --- a/devices/ethernet/bigmac.cpp +++ b/devices/ethernet/bigmac.cpp @@ -32,6 +32,7 @@ BigMac::BigMac(uint8_t id) { this->chip_id = id; this->phy_reset(); this->mii_reset(); + this->srom_reset(); } uint16_t BigMac::read(uint16_t reg_offset) { @@ -40,6 +41,8 @@ uint16_t BigMac::read(uint16_t reg_offset) { return this->chip_id; case BigMacReg::MIF_CSR: return (this->mif_csr_old & ~Mif_Data_In) | (this->mii_in_bit << 3); + case BigMacReg::SROM_CSR: + return (this->srom_csr_old & ~Srom_Data_In) | (this->srom_in_bit << 2); default: LOG_F(WARNING, "%s: unimplemented register at 0x%X", this->name.c_str(), reg_offset); @@ -61,6 +64,16 @@ void BigMac::write(uint16_t reg_offset, uint16_t value) { } this->mif_csr_old = value; break; + case BigMacReg::SROM_CSR: + if (value & Srom_Chip_Select) { + // exchange data on each low-to-high transition of Srom_Clock + if (((this->srom_csr_old ^ value) & Srom_Clock) && (value & Srom_Clock)) + this->srom_xmit_bit(!!(value & Srom_Data_Out)); + } else { + this->srom_reset(); + } + this->srom_csr_old = value; + break; default: LOG_F(WARNING, "%s: unimplemented register at 0x%X is written with 0x%X", this->name.c_str(), reg_offset, value); @@ -247,6 +260,70 @@ void BigMac::phy_reg_write(uint8_t reg_num, uint16_t value) { } } +// ======================== MAC Serial EEPROM emulation ======================== +void BigMac::srom_reset() { + this->srom_csr_old = 0; + this->srom_bit_counter = 0; + this->srom_opcode = 0; + this->srom_address = 0; + this->srom_state = Srom_Start; +} + +bool BigMac::srom_rcv_value(uint16_t& var, uint8_t num_bits, uint8_t next_bit) { + var = (var << 1) | (next_bit & 1); + this->srom_bit_counter++; + if (this->srom_bit_counter >= num_bits) { + this->srom_bit_counter = 0; + return true; // all bits have been received -> return true + } + return false; // more bits expected +} + +void BigMac::srom_xmit_bit(const uint8_t bit_val) { + switch(this->srom_state) { + case Srom_Start: + if (bit_val) + this->srom_state = Srom_Opcode; + else + this->srom_reset(); + break; + case Srom_Opcode: + if (this->srom_rcv_value(this->srom_opcode, 2, bit_val)) { + switch(this->srom_opcode) { + case 2: // read + this->srom_state = Srom_Address; + break; + default: + LOG_F(ERROR, "%s: unsupported SROM opcode %d", this->name.c_str(), + this->srom_opcode); + this->srom_reset(); + } + } + break; + case Srom_Address: + if (this->srom_rcv_value(this->srom_address, 6, bit_val)) { + LOG_F(9, "SROM address received = 0x%X", this->srom_address); + this->srom_bit_counter = 16; + this->srom_state = Srom_Read_Data; + } + break; + case Srom_Read_Data: + if (this->srom_bit_counter) { + this->srom_bit_counter--; + this->srom_in_bit = (this->srom_data[this->srom_address] >> this->srom_bit_counter) & 1; + if (!this->srom_bit_counter) { + this->srom_address++; + this->srom_bit_counter = 16; + } + } + break; + default: + LOG_F(ERROR, "%s: unhandled state %d in srom_xmit_bit", this->name.c_str(), + this->srom_state); + this->srom_reset(); + } +} + static const DeviceDescription BigMac_Heathrow_Descriptor = { BigMac::create_for_heathrow, {}, {} }; diff --git a/devices/ethernet/bigmac.h b/devices/ethernet/bigmac.h index 9801c41..99b76b9 100644 --- a/devices/ethernet/bigmac.h +++ b/devices/ethernet/bigmac.h @@ -37,8 +37,9 @@ enum EthernetCellId : uint8_t { /* BigMac HW registers. */ enum BigMacReg : uint16_t { - CHIP_ID = 0x170, - MIF_CSR = 0x180, + CHIP_ID = 0x170, + MIF_CSR = 0x180, + SROM_CSR = 0x190, }; /* MIF_CSR bit definitions. */ @@ -49,6 +50,22 @@ enum { Mif_Data_In = 1 << 3 }; +/* SROM_CSR bit definitions. */ +enum { + Srom_Chip_Select = 1 << 0, + Srom_Clock = 1 << 1, + Srom_Data_In = 1 << 2, + Srom_Data_Out = 1 << 3, +}; + +/* Serial EEPROM states (see ST93C46 datasheet). */ +enum { + Srom_Start, + Srom_Opcode, + Srom_Address, + Srom_Read_Data, +}; + /* MII frame states. */ enum MII_FRAME_SM { Preamble, @@ -98,6 +115,11 @@ public: uint16_t phy_reg_read(uint8_t reg_num); void phy_reg_write(uint8_t reg_num, uint16_t value); + // MAC Serial EEPROM methods + void srom_reset(); + bool srom_rcv_value(uint16_t& var, uint8_t num_bits, uint8_t next_bit); + void srom_xmit_bit(const uint8_t bit_val); + private: uint8_t chip_id; // BigMac Chip ID @@ -120,6 +142,16 @@ private: uint8_t phy_rev; uint16_t phy_bmcr; uint16_t phy_anar; + + // MAC SROM state + uint8_t srom_csr_old = 0; + uint8_t srom_bit_counter = 0; + uint16_t srom_opcode = 0; + uint16_t srom_address = 0; + uint8_t srom_in_bit = 0; + uint8_t srom_state = Srom_Start; + uint16_t srom_data[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0xDEAD, 0xBEEF, 0xBABE}; // bogus MAC!!! }; #endif // BIG_MAC_H