pcs: Add false_carrier signal
This adds an explicit false carrier signal. Trying to determine this condition the MDIO signals is tricky because BAD_SSD can last over several cycles of CE. To make things easier, add a signal which is high only once per event. Signed-off-by: Sean Anderson <seanga2@gmail.com>
This commit is contained in:
parent
ece7d6c619
commit
02069bceee
|
@ -90,8 +90,7 @@ module mdio_regs (
|
||||||
localparam VCR_LTEST = 14;
|
localparam VCR_LTEST = 14;
|
||||||
|
|
||||||
integer i;
|
integer i;
|
||||||
reg duplex, false_carrier_last, false_carrier_event;
|
reg duplex, link_status_latched, link_status_latched_next, link_status_last, disconnect;
|
||||||
reg link_status_latched, link_status_latched_next, link_status_last, disconnect;
|
|
||||||
reg loopback_next, pdown_next, isolate_next, duplex_next, coltest_next;
|
reg loopback_next, pdown_next, isolate_next, duplex_next, coltest_next;
|
||||||
reg descrambler_test_next, link_monitor_test_next;
|
reg descrambler_test_next, link_monitor_test_next;
|
||||||
reg [15:0] data_read_next;
|
reg [15:0] data_read_next;
|
||||||
|
@ -126,7 +125,6 @@ module mdio_regs (
|
||||||
coltest_next = coltest;
|
coltest_next = coltest;
|
||||||
link_status_latched_next = link_status_latched && link_status;
|
link_status_latched_next = link_status_latched && link_status;
|
||||||
disconnect = link_status_last && !link_status;
|
disconnect = link_status_last && !link_status;
|
||||||
false_carrier_event = false_carrier && !false_carrier_last;
|
|
||||||
descrambler_test_next = descrambler_test;
|
descrambler_test_next = descrambler_test;
|
||||||
link_monitor_test_next = link_monitor_test;
|
link_monitor_test_next = link_monitor_test;
|
||||||
|
|
||||||
|
@ -140,7 +138,7 @@ module mdio_regs (
|
||||||
if (!(&nwc)) nwc_next = nwc + negative_wraparound;
|
if (!(&nwc)) nwc_next = nwc + negative_wraparound;
|
||||||
if (!(&pwc)) pwc_next = pwc + positive_wraparound;
|
if (!(&pwc)) pwc_next = pwc + positive_wraparound;
|
||||||
if (!(&dc)) dc_next = dc + disconnect;
|
if (!(&dc)) dc_next = dc + disconnect;
|
||||||
if (!(&fcc)) fcc_next = fcc + false_carrier_event;
|
if (!(&fcc)) fcc_next = fcc + false_carrier;
|
||||||
if (!(&sec)) sec_next = sec + symbol_error;
|
if (!(&sec)) sec_next = sec + symbol_error;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -174,7 +172,7 @@ module mdio_regs (
|
||||||
nwc_next = negative_wraparound;
|
nwc_next = negative_wraparound;
|
||||||
pwc_next = positive_wraparound;
|
pwc_next = positive_wraparound;
|
||||||
dc_next = disconnect;
|
dc_next = disconnect;
|
||||||
fcc_next = false_carrier_event;
|
fcc_next = false_carrier;
|
||||||
sec_next = symbol_error;
|
sec_next = symbol_error;
|
||||||
end
|
end
|
||||||
descrambler_test_next = 0;
|
descrambler_test_next = 0;
|
||||||
|
@ -223,7 +221,7 @@ module mdio_regs (
|
||||||
data_read_next = fcc;
|
data_read_next = fcc;
|
||||||
|
|
||||||
if (cyc && stb)
|
if (cyc && stb)
|
||||||
fcc_next = we ? data_write : false_carrier_event;
|
fcc_next = we ? data_write : false_carrier;
|
||||||
end
|
end
|
||||||
SECR: if (ENABLE_COUNTERS) begin
|
SECR: if (ENABLE_COUNTERS) begin
|
||||||
data_read_next = sec;
|
data_read_next = sec;
|
||||||
|
@ -260,7 +258,6 @@ module mdio_regs (
|
||||||
coltest <= coltest_next;
|
coltest <= coltest_next;
|
||||||
link_status_latched <= link_status_latched_next;
|
link_status_latched <= link_status_latched_next;
|
||||||
link_status_last <= link_status;
|
link_status_last <= link_status;
|
||||||
false_carrier_last <= false_carrier;
|
|
||||||
data_read <= data_read_next;
|
data_read <= data_read_next;
|
||||||
if (ENABLE_COUNTERS) begin
|
if (ENABLE_COUNTERS) begin
|
||||||
nwc <= nwc_next;
|
nwc <= nwc_next;
|
||||||
|
|
15
rtl/pcs_rx.v
15
rtl/pcs_rx.v
|
@ -190,7 +190,8 @@ module pcs_rx (
|
||||||
input link_status,
|
input link_status,
|
||||||
|
|
||||||
/* Internal */
|
/* Internal */
|
||||||
output reg rx
|
output reg rx,
|
||||||
|
output reg false_carrier
|
||||||
);
|
);
|
||||||
|
|
||||||
localparam IDLE = 0;
|
localparam IDLE = 0;
|
||||||
|
@ -210,7 +211,7 @@ module pcs_rx (
|
||||||
reg [2:0] state, state_next;
|
reg [2:0] state, state_next;
|
||||||
initial state = IDLE;
|
initial state = IDLE;
|
||||||
/* Whether we are aligned and receiving */
|
/* Whether we are aligned and receiving */
|
||||||
reg rx_next;
|
reg rx_next, false_carrier_next;
|
||||||
|
|
||||||
pcs_rx_bits rx_bits (
|
pcs_rx_bits rx_bits (
|
||||||
.clk(clk),
|
.clk(clk),
|
||||||
|
@ -261,6 +262,7 @@ module pcs_rx (
|
||||||
state_next = state;
|
state_next = state;
|
||||||
valid_next = valid;
|
valid_next = valid;
|
||||||
err_next = 0;
|
err_next = 0;
|
||||||
|
false_carrier_next = 0;
|
||||||
|
|
||||||
`define BAD_SSD begin \
|
`define BAD_SSD begin \
|
||||||
state_next = BAD_SSD; \
|
state_next = BAD_SSD; \
|
||||||
|
@ -279,8 +281,10 @@ end
|
||||||
ce_next = 0;
|
ce_next = 0;
|
||||||
if (unaligned == { `CODE_I, `CODE_J })
|
if (unaligned == { `CODE_I, `CODE_J })
|
||||||
state_next = START_J;
|
state_next = START_J;
|
||||||
else
|
else begin
|
||||||
`BAD_SSD;
|
`BAD_SSD;
|
||||||
|
false_carrier_next = 1;
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
BAD_SSD: begin
|
BAD_SSD: begin
|
||||||
|
@ -293,8 +297,10 @@ end
|
||||||
if (aligned[4:0] == `CODE_K) begin
|
if (aligned[4:0] == `CODE_K) begin
|
||||||
state_next = START_K;
|
state_next = START_K;
|
||||||
valid_next = 1;
|
valid_next = 1;
|
||||||
end else
|
end else begin
|
||||||
`BAD_SSD;
|
`BAD_SSD;
|
||||||
|
false_carrier_next = indicate;
|
||||||
|
end
|
||||||
|
|
||||||
if (!indicate)
|
if (!indicate)
|
||||||
state_next = START_J;
|
state_next = START_J;
|
||||||
|
@ -371,6 +377,7 @@ end
|
||||||
rx <= rx_next;
|
rx <= rx_next;
|
||||||
state <= state_next;
|
state <= state_next;
|
||||||
ce <= ce_next;
|
ce <= ce_next;
|
||||||
|
false_carrier <= false_carrier_next;
|
||||||
if (ce_next) begin
|
if (ce_next) begin
|
||||||
data <= data_next;
|
data <= data_next;
|
||||||
valid <= valid_next;
|
valid <= valid_next;
|
||||||
|
|
|
@ -128,7 +128,7 @@ async def test_mdio(regs):
|
||||||
await counter_test(PWCR, regs.positive_wraparound)
|
await counter_test(PWCR, regs.positive_wraparound)
|
||||||
await xfer(DCR) # Clear DCR from the BMSR testing
|
await xfer(DCR) # Clear DCR from the BMSR testing
|
||||||
await counter_test(DCR, regs.link_status, True, False)
|
await counter_test(DCR, regs.link_status, True, False)
|
||||||
await counter_test(FCCR, regs.false_carrier, True)
|
await counter_test(FCCR, regs.false_carrier)
|
||||||
await counter_test(SECR, regs.symbol_error)
|
await counter_test(SECR, regs.symbol_error)
|
||||||
|
|
||||||
await reg_toggle(VCR, VCR_DTEST, regs.descrambler_test)
|
await reg_toggle(VCR, VCR_DTEST, regs.descrambler_test)
|
||||||
|
|
25
tb/pcs_rx.py
25
tb/pcs_rx.py
|
@ -22,20 +22,28 @@ def frame(data):
|
||||||
return itertools.chain(
|
return itertools.chain(
|
||||||
(Code('J'), Code('K')),
|
(Code('J'), Code('K')),
|
||||||
# Chop off the SSD
|
# Chop off the SSD
|
||||||
as_codes(data[2:]),
|
as_codes(itertools.islice(data, 2, None)),
|
||||||
(Code('T'), Code('R')),
|
(Code('T'), Code('R')),
|
||||||
)
|
)
|
||||||
|
|
||||||
async def mii_recv_packet(pcs):
|
async def mii_recv_packet(pcs, signals=None):
|
||||||
while not (pcs.ce.value and pcs.valid.value):
|
if signals is None:
|
||||||
|
signals = {
|
||||||
|
'ce': pcs.ce,
|
||||||
|
'err': pcs.err,
|
||||||
|
'data': pcs.data,
|
||||||
|
'valid': pcs.valid,
|
||||||
|
}
|
||||||
|
|
||||||
|
while not (signals['ce'].value and signals['valid'].value):
|
||||||
await RisingEdge(pcs.clk)
|
await RisingEdge(pcs.clk)
|
||||||
|
|
||||||
while pcs.valid.value:
|
while signals['valid'].value:
|
||||||
if pcs.ce.value:
|
if signals['ce'].value:
|
||||||
if pcs.err.value:
|
if signals['err'].value:
|
||||||
yield None
|
yield None
|
||||||
else:
|
else:
|
||||||
yield pcs.data.value
|
yield signals['data'].value
|
||||||
await RisingEdge(pcs.clk)
|
await RisingEdge(pcs.clk)
|
||||||
|
|
||||||
async def pcs_send_codes(pcs, codes, valids):
|
async def pcs_send_codes(pcs, codes, valids):
|
||||||
|
@ -68,11 +76,14 @@ async def test_rx(pcs, valids):
|
||||||
|
|
||||||
assert packet == await alist(mii_recv_packet(pcs))
|
assert packet == await alist(mii_recv_packet(pcs))
|
||||||
|
|
||||||
|
false_carriers = 0
|
||||||
for _ in range(3):
|
for _ in range(3):
|
||||||
while not (pcs.rx.value and pcs.err.value and pcs.ce.value):
|
while not (pcs.rx.value and pcs.err.value and pcs.ce.value):
|
||||||
await RisingEdge(pcs.clk)
|
await RisingEdge(pcs.clk)
|
||||||
|
false_carriers += pcs.false_carrier.value
|
||||||
assert pcs.data.value == 0xE
|
assert pcs.data.value == 0xE
|
||||||
await FallingEdge(pcs.rx)
|
await FallingEdge(pcs.rx)
|
||||||
|
assert false_carriers == 3
|
||||||
|
|
||||||
assert [0x5, 0x5, None] == await alist(mii_recv_packet(pcs))
|
assert [0x5, 0x5, None] == await alist(mii_recv_packet(pcs))
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue