mdio: Support
The 802.3.22.2.4.3 requires that the phy not respond to reads of and ignore writes to unimplemented extended registers. When writing the mdio module, I expected that such read/writes would not be acked by the registers. However, that behavior is not especially nice for wishbone masters which don't expect it. Instead, allow the slave to return an error instead. We need an extra saved_err variable, since we might not be able to set bad immediately (when ce is low). Signed-off-by: Sean Anderson <seanga2@gmail.com>
This commit is contained in:
parent
fb751eb7fb
commit
ebcb8cc056
24
rtl/mdio.v
24
rtl/mdio.v
|
@ -12,7 +12,7 @@ module mdio (
|
|||
output reg mdo,
|
||||
output reg mdo_valid,
|
||||
|
||||
input ack,
|
||||
input ack, err,
|
||||
output cyc,
|
||||
output reg stb, we,
|
||||
output reg [4:0] addr,
|
||||
|
@ -47,7 +47,7 @@ module mdio (
|
|||
reg [4:0] addr_next;
|
||||
reg [15:0] data_next;
|
||||
|
||||
reg bad, bad_next;
|
||||
reg bad, bad_next, saved_err, saved_err_next;
|
||||
reg [2:0] state = IDLE, state_next;
|
||||
reg [4:0] state_counter, state_counter_next;
|
||||
|
||||
|
@ -67,9 +67,13 @@ module mdio (
|
|||
we_next = we;
|
||||
addr_next = addr;
|
||||
data_next = data_write;
|
||||
if (stb && ack) begin
|
||||
saved_err_next = saved_err;
|
||||
if (stb && (ack || err)) begin
|
||||
stb_next = 0;
|
||||
data_next = data_read;
|
||||
if (err)
|
||||
saved_err_next = 1;
|
||||
else
|
||||
data_next = data_read;
|
||||
end
|
||||
|
||||
state_next = state;
|
||||
|
@ -102,6 +106,9 @@ module mdio (
|
|||
OP: begin
|
||||
/* This is a bit of an abuse of we :) */
|
||||
we_next = mdi;
|
||||
/* Accordingly, cancel any outstanding transactions */
|
||||
stb_next = 0;
|
||||
saved_err_next = 0;
|
||||
if (!state_counter) begin
|
||||
case ({ we, mdi })
|
||||
OP_READ: we_next = 0;
|
||||
|
@ -118,9 +125,6 @@ module mdio (
|
|||
bad_next = 1;
|
||||
|
||||
if (!state_counter) begin
|
||||
/* Cancel any outstanding transaction */
|
||||
if (ce)
|
||||
stb_next = 0;
|
||||
state_next = REGAD;
|
||||
state_counter_next = REGAD_BITS - 1;
|
||||
end
|
||||
|
@ -141,9 +145,10 @@ module mdio (
|
|||
if (!we && !bad) begin
|
||||
mdo_next = 0;
|
||||
mdo_valid_next = 1;
|
||||
if (stb) begin
|
||||
if (stb || saved_err) begin
|
||||
/* No response */
|
||||
stb_next = !ce;
|
||||
if (ce)
|
||||
stb_next = 0;
|
||||
bad_next = 1;
|
||||
mdo_valid_next = 0;
|
||||
end
|
||||
|
@ -178,6 +183,7 @@ module mdio (
|
|||
always @(posedge clk) begin
|
||||
stb <= stb_next;
|
||||
data_write <= data_next;
|
||||
saved_err <= saved_err_next;
|
||||
if (ce) begin
|
||||
mdo <= mdo_next;
|
||||
mdo_valid <= mdo_valid_next;
|
||||
|
|
22
tb/mdio.py
22
tb/mdio.py
|
@ -108,6 +108,7 @@ async def wb_write(mdio, addr, data):
|
|||
async def setup(mdio):
|
||||
mdio.mdi.value = 0
|
||||
mdio.ack.value = 0
|
||||
mdio.err.value = 0
|
||||
mdio.data_read.value = LogicArray('X' * 16)
|
||||
await cocotb.start(ClockEnable(mdio.clk, mdio.ce, MDIO_RATIO))
|
||||
await Timer(1)
|
||||
|
@ -160,10 +161,21 @@ async def test_badmdio(mdio):
|
|||
async def test_badwb(mdio):
|
||||
await setup(mdio)
|
||||
|
||||
async def try_mdio():
|
||||
async def bad_resp():
|
||||
# No ack
|
||||
await ClockCycles(mdio.stb, 2, False)
|
||||
# Error response
|
||||
for _ in range(2):
|
||||
while not (mdio.cyc.value and mdio.stb.value):
|
||||
await FallingEdge(mdio.clk)
|
||||
|
||||
mdio.err.value = 1
|
||||
await RisingEdge(mdio.clk)
|
||||
mdio.err.value = 0
|
||||
await FallingEdge(mdio.clk)
|
||||
assert not mdio.stb.value
|
||||
await cocotb.start(bad_resp())
|
||||
|
||||
for _ in range(2):
|
||||
assert await mdio_read(mdio, 0, 0) is None
|
||||
await mdio_write(mdio, 0, 0, 0)
|
||||
assert await mdio_read(mdio, 0, 0) is None
|
||||
await cocotb.start(try_mdio())
|
||||
|
||||
await ClockCycles(mdio.stb, 3, False)
|
||||
|
|
Loading…
Reference in New Issue