bigmac: MAC serial EEPROM emulation.

This commit is contained in:
Maxim Poliakovski 2023-07-08 21:32:26 +02:00
parent 4de2afc0c5
commit 482fe3eb80
2 changed files with 111 additions and 2 deletions

View File

@ -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, {}, {}
};

View File

@ -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