Practice
Plant PHY Register
Dunbar Water Works depends on an Ethernet link to watch pumps, filters, and alarms. Its controller reads the PHY chip's status registers through MDIO, a two-wire management port.
The host owns the shared data wire while it sends a request. It must then let go for both turnaround slots, so the PHY can answer.
The shipped reader kept driving through turnaround. It fought the PHY on every read, and the green link lamp stayed dark.
The control room's wall screen lost its remote view of the plant.
Your task: build mdio_reader. Release the wire on time, check the PHY's turnaround response, and trust the data only when that check passes.
Interface
| Port | Direction | Type | Description |
|---|---|---|---|
clk_i | in | 1 bit | System clock |
rst_i | in | 1 bit | Synchronous reset, active high |
start_i | in | 1 bit | Request one register read |
phy_addr_i | in | 5-bit vector | PHY address |
reg_addr_i | in | 5-bit vector | Clause 22 register address |
mdio_in_i | in | 1 bit | MDIO wire as read by the host |
mdc_o | out | 1 bit | Management clock, idle low |
mdio_out_o | out | 1 bit | Host drive value for the MDIO wire |
mdio_oe_o | out | 1 bit | High while the host drives the MDIO wire |
busy_o | out | 1 bit | High while a read is in progress |
data_o | out | 16-bit vector | Last successful register value, held |
valid_o | out | 1 bit | Successful read complete, one-clock pulse |
ta_err_o | out | 1 bit | Invalid turnaround detected, one-clock pulse |
Behavior
- A high
start_iis accepted only while idle phy_addr_iandreg_addr_iare captured at acceptance- Later address changes do not affect the running read
- Any
start_iassertion whilebusy_ois high is ignored busy_ois high while the accepted read is in progress and low while idlemdc_ouses fourclk_icycles per period: two low cycles followed by two high cycles- The host changes
mdio_out_oandmdio_oe_oonly whilemdc_ois low - The PHY samples the wire on each rising
mdc_oedge - The host samples
mdio_in_ion risingmdc_oedges during turnaround checking and data capture - The host first drives 32 preamble bits, all ones
- It then drives start field
01, read opcode10, capturedphy_addr_i, and capturedreg_addr_i - Each address is sent most significant bit first
mdio_oe_ostays high from the first preamble bit through the lastreg_addr_ibit- The host releases the wire for both turnaround slots by setting
mdio_oe_olow mdio_oe_oremains low throughout both turnaround slots and all 16 data bits- A healthy PHY drives the second turnaround slot to zero
- If that sampled bit is not zero,
ta_err_opulses once and the read is discarded - A discarded read never raises
valid_o, never changesdata_o, and returns the unit to idle - After a valid turnaround, the host captures 16 data bits from
mdio_in_i, most significant bit first - One
clk_icycle after the sixteenth data bit is captured,data_oupdates andvalid_opulses valid_oandta_err_oeach stay high for exactly oneclk_icycledata_oholds its last successful value between reads and throughout later reads- While idle,
mdc_ois low,mdio_oe_ois low, and both pulse outputs are low rst_ihigh on any risingclk_iedge cancels all progress and returns the unit to idle- Reset drives every output low, including
data_o, and no cancelled read resumes afterward
What the bench checks
- The testbench checks idle acceptance, captured addresses, and ignored requests while busy
- It checks all 64 frame bits, including preamble, fields, addresses, turnaround, and data
- It checks the two-low, two-high
mdc_opattern and all rising-edge sampling - It checks that
mdio_oe_ofalls before the first turnaround slot and stays low - It checks MSB-first data capture and the one-clock delay before
data_oandvalid_oupdate - It injects bad turnaround values and checks
ta_err_o, unchangeddata_o, and suppressedvalid_o - It checks one-clock pulses and that
data_oholds between successful reads - It asserts reset during different frame phases and checks that every output clears
Constraints
TIMING: everything is synchronous to
clk_i; inputs are sampled on rising edges, and all outputs are registered.
SCOPE: Clause 22 reads are the whole task. Writes, Clause 45, preamble suppression, and the physical bidirectional pin are out of scope. A board wrapper joins
mdio_out_o,mdio_oe_o, andmdio_in_ito the shared pin.
Do not add ports.
Click Run to execute your code. Output will appear here.