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:
Sean Anderson 2022-08-29 21:25:25 -04:00
parent fb751eb7fb
commit ebcb8cc056
2 changed files with 32 additions and 14 deletions

View File

@ -12,7 +12,7 @@ module mdio (
output reg mdo, output reg mdo,
output reg mdo_valid, output reg mdo_valid,
input ack, input ack, err,
output cyc, output cyc,
output reg stb, we, output reg stb, we,
output reg [4:0] addr, output reg [4:0] addr,
@ -47,7 +47,7 @@ module mdio (
reg [4:0] addr_next; reg [4:0] addr_next;
reg [15:0] data_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 [2:0] state = IDLE, state_next;
reg [4:0] state_counter, state_counter_next; reg [4:0] state_counter, state_counter_next;
@ -67,8 +67,12 @@ module mdio (
we_next = we; we_next = we;
addr_next = addr; addr_next = addr;
data_next = data_write; data_next = data_write;
if (stb && ack) begin saved_err_next = saved_err;
if (stb && (ack || err)) begin
stb_next = 0; stb_next = 0;
if (err)
saved_err_next = 1;
else
data_next = data_read; data_next = data_read;
end end
@ -102,6 +106,9 @@ module mdio (
OP: begin OP: begin
/* This is a bit of an abuse of we :) */ /* This is a bit of an abuse of we :) */
we_next = mdi; we_next = mdi;
/* Accordingly, cancel any outstanding transactions */
stb_next = 0;
saved_err_next = 0;
if (!state_counter) begin if (!state_counter) begin
case ({ we, mdi }) case ({ we, mdi })
OP_READ: we_next = 0; OP_READ: we_next = 0;
@ -118,9 +125,6 @@ module mdio (
bad_next = 1; bad_next = 1;
if (!state_counter) begin if (!state_counter) begin
/* Cancel any outstanding transaction */
if (ce)
stb_next = 0;
state_next = REGAD; state_next = REGAD;
state_counter_next = REGAD_BITS - 1; state_counter_next = REGAD_BITS - 1;
end end
@ -141,9 +145,10 @@ module mdio (
if (!we && !bad) begin if (!we && !bad) begin
mdo_next = 0; mdo_next = 0;
mdo_valid_next = 1; mdo_valid_next = 1;
if (stb) begin if (stb || saved_err) begin
/* No response */ /* No response */
stb_next = !ce; if (ce)
stb_next = 0;
bad_next = 1; bad_next = 1;
mdo_valid_next = 0; mdo_valid_next = 0;
end end
@ -178,6 +183,7 @@ module mdio (
always @(posedge clk) begin always @(posedge clk) begin
stb <= stb_next; stb <= stb_next;
data_write <= data_next; data_write <= data_next;
saved_err <= saved_err_next;
if (ce) begin if (ce) begin
mdo <= mdo_next; mdo <= mdo_next;
mdo_valid <= mdo_valid_next; mdo_valid <= mdo_valid_next;

View File

@ -108,6 +108,7 @@ async def wb_write(mdio, addr, data):
async def setup(mdio): async def setup(mdio):
mdio.mdi.value = 0 mdio.mdi.value = 0
mdio.ack.value = 0 mdio.ack.value = 0
mdio.err.value = 0
mdio.data_read.value = LogicArray('X' * 16) mdio.data_read.value = LogicArray('X' * 16)
await cocotb.start(ClockEnable(mdio.clk, mdio.ce, MDIO_RATIO)) await cocotb.start(ClockEnable(mdio.clk, mdio.ce, MDIO_RATIO))
await Timer(1) await Timer(1)
@ -160,10 +161,21 @@ async def test_badmdio(mdio):
async def test_badwb(mdio): async def test_badwb(mdio):
await setup(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 assert await mdio_read(mdio, 0, 0) is None
await mdio_write(mdio, 0, 0, 0) 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)