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

PortDirectionTypeDescription
clkin1 bitSystem clock
rstin1 bitSynchronous reset, active high
startin1 bitRequest one register read
phy_addrin5-bit vectorPHY address
reg_addrin5-bit vectorClause 22 register address
mdio_inin1 bitMDIO wire as read by the host
mdcout1 bitManagement clock, idle low
mdio_outout1 bitHost drive value for the MDIO wire
mdio_oeout1 bitHigh while the host drives the MDIO wire
busyout1 bitHigh while a read is in progress
dataout16-bit vectorLast successful register value, held
validout1 bitSuccessful read complete, one-clock pulse
ta_errout1 bitInvalid turnaround detected, one-clock pulse

Behavior

  • A high start is accepted only while idle
  • phy_addr and reg_addr are captured at acceptance
  • Later address changes do not affect the running read
  • Any start assertion while busy is high is ignored
  • busy is high while the accepted read is in progress and low while idle
  • mdc uses four clk cycles per period: two low cycles followed by two high cycles
  • The host changes mdio_out and mdio_oe only while mdc is low
  • The PHY samples the wire on each rising mdc edge
  • The host samples mdio_in on rising mdc edges during turnaround checking and data capture
  • The host first drives 32 preamble bits, all ones
  • It then drives start field 01, read opcode 10, captured phy_addr, and captured reg_addr
  • Each address is sent most significant bit first
  • mdio_oe stays high from the first preamble bit through the last reg_addr bit
  • The host releases the wire for both turnaround slots by setting mdio_oe low
  • mdio_oe remains 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 pulses once and the read is discarded
  • A discarded read never raises valid, never changes data, and returns the unit to idle
  • After a valid turnaround, the host captures 16 data bits from mdio_in, most significant bit first
  • One clk cycle after the sixteenth data bit is captured, data updates and valid pulses
  • valid and ta_err each stay high for exactly one clk cycle
  • data holds its last successful value between reads and throughout later reads
  • While idle, mdc is low, mdio_oe is low, and both pulse outputs are low
  • rst high on any rising clk edge cancels all progress and returns the unit to idle
  • Reset drives every output low, including data, 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 pattern and all rising-edge sampling
  • It checks that mdio_oe falls before the first turnaround slot and stays low
  • It checks MSB-first data capture and the one-clock delay before data and valid update
  • It injects bad turnaround values and checks ta_err, unchanged data, and suppressed valid
  • It checks one-clock pulses and that data holds between successful reads
  • It asserts reset during different frame phases and checks that every output clears

Constraints

TIMING

everything is synchronous to clk; 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, mdio_oe, and mdio_in to the shared pin.

Do not add ports.

Loading editor...

Click Run to execute your code. Output will appear here.