mdio_regs: Add support for counters
This adds support for counters for interesting conditions (disconnects, PMD phase wraparounds, errors, etc). All the counters are 15 bits instead of 16, because 16-bit counters have an fmax of 110MHz or so. All the counters live behind a condition because they ~double the number of resources used. Signed-off-by: Sean Anderson <seanga2@gmail.com>
This commit is contained in:
parent
ec08287853
commit
7d35e07401
109
rtl/mdio_regs.v
109
rtl/mdio_regs.v
|
@ -16,6 +16,10 @@ module mdio_regs (
|
||||||
|
|
||||||
/* Control signals */
|
/* Control signals */
|
||||||
input link_status,
|
input link_status,
|
||||||
|
input positive_wraparound,
|
||||||
|
input negative_wraparound,
|
||||||
|
input false_carrier,
|
||||||
|
input symbol_error,
|
||||||
output reg loopback,
|
output reg loopback,
|
||||||
output reg pdown,
|
output reg pdown,
|
||||||
output reg isolate,
|
output reg isolate,
|
||||||
|
@ -28,19 +32,39 @@ module mdio_regs (
|
||||||
parameter [3:0] REVISION = 0;
|
parameter [3:0] REVISION = 0;
|
||||||
/*
|
/*
|
||||||
* Normally, this module will assert err when read/writing to an
|
* Normally, this module will assert err when read/writing to an
|
||||||
* unknown register. The master will detect this and won't drive MDIO
|
* unknown register. The master will detect this and won't drive the
|
||||||
* line. However, this might be undesirable if there is no external
|
* MDIO line. However, this might be undesirable if there is no
|
||||||
* MDIO bus. Setting this parameter to 0 will cause it to ack all
|
* external MDIO bus. Setting this parameter to 0 will cause it to ack
|
||||||
* transactions. Writes to unknown registers will be ignored, and
|
* all transactions. Writes to unknown registers will be ignored, and
|
||||||
* reads from unknown registers will yield 16'hffff, emulating
|
* reads from unknown registers will yield 16'hffff, emulating
|
||||||
* a pull-up on MDIO.
|
* a pull-up on MDIO.
|
||||||
*/
|
*/
|
||||||
parameter EMULATE_PULLUP = 0;
|
parameter EMULATE_PULLUP = 0;
|
||||||
|
/* Enable counter registers */
|
||||||
|
parameter ENABLE_COUNTERS = 1;
|
||||||
|
/*
|
||||||
|
* Number of bits in counters; we can't meet timing with 16 bits, so
|
||||||
|
* use a smaller default.
|
||||||
|
*/
|
||||||
|
parameter COUNTER_WIDTH = 15;
|
||||||
|
|
||||||
|
/* c22 Basic Mode Control Register */
|
||||||
localparam BMCR = 0;
|
localparam BMCR = 0;
|
||||||
|
/* c22 Basic Mode Status Register */
|
||||||
localparam BMSR = 1;
|
localparam BMSR = 1;
|
||||||
|
/* c22 Phy Identifier */
|
||||||
localparam ID1 = 2;
|
localparam ID1 = 2;
|
||||||
localparam ID2 = 3;
|
localparam ID2 = 3;
|
||||||
|
/* Negative Wraparound Counter Register */
|
||||||
|
localparam NWCR = 16;
|
||||||
|
/* Positive Wraparound Counter Register */
|
||||||
|
localparam PWCR = 17;
|
||||||
|
/* Disconnect Counter Register */
|
||||||
|
localparam DCR = 18;
|
||||||
|
/* False Carrier Counter Register */
|
||||||
|
localparam FCCR = 19;
|
||||||
|
/* Symbol Error Counter Register */
|
||||||
|
localparam SECR = 21;
|
||||||
|
|
||||||
localparam BMCR_RESET = 15;
|
localparam BMCR_RESET = 15;
|
||||||
localparam BMCR_LOOPBACK = 14;
|
localparam BMCR_LOOPBACK = 14;
|
||||||
|
@ -57,10 +81,13 @@ module mdio_regs (
|
||||||
localparam BMSR_EXTCAP = 0;
|
localparam BMSR_EXTCAP = 0;
|
||||||
|
|
||||||
integer i;
|
integer i;
|
||||||
reg duplex, link_status_latched;
|
reg duplex, false_carrier_last, false_carrier_event;
|
||||||
|
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 link_status_latched_next;
|
|
||||||
reg [15:0] data_read_next;
|
reg [15:0] data_read_next;
|
||||||
|
/* Can't meet timing at 16 bits wide */
|
||||||
|
reg [COUNTER_WIDTH-1:0] nwc, pwc, dc, fcc, sec;
|
||||||
|
reg [COUNTER_WIDTH-1:0] nwc_next, pwc_next, dc_next, fcc_next, sec_next;
|
||||||
|
|
||||||
initial begin
|
initial begin
|
||||||
loopback = 0;
|
loopback = 0;
|
||||||
|
@ -69,6 +96,14 @@ module mdio_regs (
|
||||||
duplex = 0;
|
duplex = 0;
|
||||||
coltest = 0;
|
coltest = 0;
|
||||||
link_status_latched = 0;
|
link_status_latched = 0;
|
||||||
|
link_status_last = 0;
|
||||||
|
if (ENABLE_COUNTERS) begin
|
||||||
|
nwc = 0;
|
||||||
|
pwc = 0;
|
||||||
|
dc = 0;
|
||||||
|
fcc = 0;
|
||||||
|
sec = 0;
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
always @(*) begin
|
always @(*) begin
|
||||||
|
@ -78,6 +113,22 @@ module mdio_regs (
|
||||||
duplex_next = duplex;
|
duplex_next = duplex;
|
||||||
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;
|
||||||
|
false_carrier_event = false_carrier && !false_carrier_last;
|
||||||
|
|
||||||
|
if (ENABLE_COUNTERS) begin
|
||||||
|
nwc_next = nwc;
|
||||||
|
pwc_next = pwc;
|
||||||
|
dc_next = dc;
|
||||||
|
fcc_next = fcc;
|
||||||
|
sec_next = sec;
|
||||||
|
|
||||||
|
if (!(&nwc)) nwc_next = nwc + negative_wraparound;
|
||||||
|
if (!(&pwc)) pwc_next = pwc + positive_wraparound;
|
||||||
|
if (!(&dc)) dc_next = dc + disconnect;
|
||||||
|
if (!(&fcc)) fcc_next = fcc + false_carrier_event;
|
||||||
|
if (!(&sec)) sec_next = sec + symbol_error;
|
||||||
|
end
|
||||||
|
|
||||||
data_read_next = 0;
|
data_read_next = 0;
|
||||||
ack = cyc && stb;
|
ack = cyc && stb;
|
||||||
|
@ -105,6 +156,13 @@ module mdio_regs (
|
||||||
duplex_next = 0;
|
duplex_next = 0;
|
||||||
coltest_next = 0;
|
coltest_next = 0;
|
||||||
link_status_latched_next = link_status;
|
link_status_latched_next = link_status;
|
||||||
|
if (ENABLE_COUNTERS) begin
|
||||||
|
nwc_next = negative_wraparound;
|
||||||
|
pwc_next = positive_wraparound;
|
||||||
|
dc_next = disconnect;
|
||||||
|
fcc_next = false_carrier_event;
|
||||||
|
sec_next = symbol_error;
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -127,6 +185,36 @@ module mdio_regs (
|
||||||
for (i = 0; i < 6; i = i + 1)
|
for (i = 0; i < 6; i = i + 1)
|
||||||
data_read_next[i + 4] = OUI[23 - i];
|
data_read_next[i + 4] = OUI[23 - i];
|
||||||
end
|
end
|
||||||
|
NWCR: if (ENABLE_COUNTERS) begin
|
||||||
|
data_read_next = nwc;
|
||||||
|
|
||||||
|
if (cyc && stb)
|
||||||
|
nwc_next = we ? data_write : negative_wraparound;
|
||||||
|
end
|
||||||
|
PWCR: if (ENABLE_COUNTERS) begin
|
||||||
|
data_read_next = pwc;
|
||||||
|
|
||||||
|
if (cyc && stb)
|
||||||
|
pwc_next = we ? data_write : positive_wraparound;
|
||||||
|
end
|
||||||
|
DCR: if (ENABLE_COUNTERS) begin
|
||||||
|
data_read_next = dc;
|
||||||
|
|
||||||
|
if (cyc && stb)
|
||||||
|
dc_next = we ? data_write : disconnect;
|
||||||
|
end
|
||||||
|
FCCR: if (ENABLE_COUNTERS) begin
|
||||||
|
data_read_next = fcc;
|
||||||
|
|
||||||
|
if (cyc && stb)
|
||||||
|
fcc_next = we ? data_write : false_carrier_event;
|
||||||
|
end
|
||||||
|
SECR: if (ENABLE_COUNTERS) begin
|
||||||
|
data_read_next = sec;
|
||||||
|
|
||||||
|
if (cyc && stb)
|
||||||
|
sec_next = we ? data_write : symbol_error;
|
||||||
|
end
|
||||||
default: begin
|
default: begin
|
||||||
if (EMULATE_PULLUP) begin
|
if (EMULATE_PULLUP) begin
|
||||||
data_read_next = 16'hFFFF;
|
data_read_next = 16'hFFFF;
|
||||||
|
@ -146,7 +234,16 @@ module mdio_regs (
|
||||||
duplex <= duplex_next;
|
duplex <= duplex_next;
|
||||||
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;
|
||||||
|
false_carrier_last <= false_carrier;
|
||||||
data_read <= data_read_next;
|
data_read <= data_read_next;
|
||||||
|
if (ENABLE_COUNTERS) begin
|
||||||
|
nwc <= nwc_next;
|
||||||
|
pwc <= pwc_next;
|
||||||
|
dc <= dc_next;
|
||||||
|
fcc <= fcc_next;
|
||||||
|
sec <= sec_next;
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
@ -14,6 +14,11 @@ BMSR = 1
|
||||||
PHYID1 = 2
|
PHYID1 = 2
|
||||||
PHYID2 = 3
|
PHYID2 = 3
|
||||||
EXTSTATUS = 15
|
EXTSTATUS = 15
|
||||||
|
NWCR = 16
|
||||||
|
PWCR = 17
|
||||||
|
DCR = 18
|
||||||
|
FCCR = 19
|
||||||
|
SECR = 21
|
||||||
|
|
||||||
BMCR_RESET = BIT(15)
|
BMCR_RESET = BIT(15)
|
||||||
BMCR_LOOPBACK = BIT(14)
|
BMCR_LOOPBACK = BIT(14)
|
||||||
|
@ -34,6 +39,10 @@ async def test_mdio(regs):
|
||||||
regs.cyc.value = 1
|
regs.cyc.value = 1
|
||||||
regs.stb.value = 0
|
regs.stb.value = 0
|
||||||
regs.link_status.value = 1
|
regs.link_status.value = 1
|
||||||
|
regs.positive_wraparound.value = 0
|
||||||
|
regs.negative_wraparound.value = 0
|
||||||
|
regs.false_carrier.value = 0
|
||||||
|
regs.symbol_error.value = 0
|
||||||
await Timer(1)
|
await Timer(1)
|
||||||
await cocotb.start(Clock(regs.clk, 8, units='ns').start())
|
await cocotb.start(Clock(regs.clk, 8, units='ns').start())
|
||||||
|
|
||||||
|
@ -93,3 +102,24 @@ async def test_mdio(regs):
|
||||||
# I'm pretty sure this register will never be implemented
|
# I'm pretty sure this register will never be implemented
|
||||||
assert await xfer(EXTSTATUS) is None
|
assert await xfer(EXTSTATUS) is None
|
||||||
assert await xfer(EXTSTATUS, 0) is None
|
assert await xfer(EXTSTATUS, 0) is None
|
||||||
|
|
||||||
|
async def counter_test(reg, signal, edge_triggered=False, active_high=True):
|
||||||
|
signal.value = 1 if active_high else 0
|
||||||
|
assert await xfer(reg) == 1
|
||||||
|
await xfer(reg, 0xfffe)
|
||||||
|
if edge_triggered:
|
||||||
|
signal.value = 0 if active_high else 1
|
||||||
|
await FallingEdge(regs.clk)
|
||||||
|
if edge_triggered:
|
||||||
|
signal.value = 1 if active_high else 0
|
||||||
|
await FallingEdge(regs.clk)
|
||||||
|
signal.value = 0 if active_high else 1
|
||||||
|
assert await xfer(reg) == 0x7fff
|
||||||
|
assert await xfer(reg) == 0
|
||||||
|
|
||||||
|
await counter_test(NWCR, regs.negative_wraparound)
|
||||||
|
await counter_test(PWCR, regs.positive_wraparound)
|
||||||
|
await xfer(DCR) # Clear DCR from the BMSR testing
|
||||||
|
await counter_test(DCR, regs.link_status, True, False)
|
||||||
|
await counter_test(FCCR, regs.false_carrier, True)
|
||||||
|
await counter_test(SECR, regs.symbol_error)
|
||||||
|
|
Loading…
Reference in New Issue