166 lines
3.4 KiB
Verilog
166 lines
3.4 KiB
Verilog
// SPDX-License-Identifier: AGPL-3.0-Only
|
|
/*
|
|
* Copyright (C) 2022 Sean Anderson <seanga2@gmail.com>
|
|
*/
|
|
|
|
`include "common.vh"
|
|
|
|
`timescale 1ns/1ps
|
|
|
|
module phy_core (
|
|
input clk,
|
|
|
|
/* "PMD" */
|
|
output tx_data,
|
|
input [1:0] rx_data,
|
|
input [1:0] rx_data_valid,
|
|
input signal_status,
|
|
|
|
/* "MII" */
|
|
input tx_ce,
|
|
input tx_en,
|
|
input [3:0] txd,
|
|
input tx_er,
|
|
|
|
output rx_ce,
|
|
output rx_dv,
|
|
output [3:0] rxd,
|
|
output rx_er,
|
|
|
|
output reg crs,
|
|
output reg col,
|
|
|
|
/* Control */
|
|
input loopback,
|
|
input coltest,
|
|
input link_monitor_test_mode,
|
|
input descrambler_test_mode,
|
|
output locked,
|
|
output reg link_status
|
|
);
|
|
|
|
wire tx_bits, transmitting;
|
|
|
|
pcs_tx pcs_tx (
|
|
.clk(clk),
|
|
.ce(tx_ce),
|
|
.enable(tx_en),
|
|
.data(txd),
|
|
.err(tx_er),
|
|
.bits(tx_bits),
|
|
.link_status(link_status),
|
|
.tx(transmitting)
|
|
);
|
|
|
|
scramble scrambler (
|
|
.clk(clk),
|
|
.unscrambled(tx_bits),
|
|
.scrambled(tx_data)
|
|
);
|
|
|
|
reg descrambler_enable, loopback_last;
|
|
initial loopback_last = 0;
|
|
wire [1:0] rx_bits, rx_bits_valid;
|
|
|
|
/* Force desynchronization when entering/exiting loopback */
|
|
always @(*) begin
|
|
if (loopback)
|
|
descrambler_enable = loopback_last;
|
|
else
|
|
descrambler_enable = signal_status && !loopback_last;
|
|
end
|
|
|
|
always @(posedge clk)
|
|
loopback_last <= loopback;
|
|
|
|
descramble descrambler (
|
|
.clk(clk),
|
|
.signal_status(descrambler_enable),
|
|
.scrambled(rx_data),
|
|
.scrambled_valid(rx_data_valid),
|
|
.descrambled(rx_bits),
|
|
.descrambled_valid(rx_bits_valid),
|
|
.test_mode(descrambler_test_mode),
|
|
.locked(locked)
|
|
);
|
|
|
|
/*
|
|
* LFSR counter; see descramble.v for details on how these values were
|
|
* generated.
|
|
*
|
|
* 50000 cycles or 400 us at 125MHz
|
|
*/
|
|
localparam STABILIZE_VALUE = 17'h1ac86;
|
|
/* 16 cycles; there's no instability while testing */
|
|
localparam TEST_STABILIZE_VALUE = 17'h11c71;
|
|
|
|
reg link_status_next;
|
|
initial link_status = 0;
|
|
reg [16:0] stabilize_timer, stabilize_timer_next;
|
|
initial stabilize_timer = STABILIZE_VALUE;
|
|
|
|
/*
|
|
* Link monitor process; this is the entirety of the (section 24.3) PMA
|
|
*
|
|
* Section 24.3.4.4 specifies that link_status is to be set to OK when
|
|
* stabilize_timer completes. However, I have also included whether
|
|
* the descrambler is locked. I think this matches the intent of the
|
|
* signal, which indicates whether "the receive channel is intact and
|
|
* enabled for reception."
|
|
*/
|
|
|
|
always @(*) begin
|
|
link_status_next = 0;
|
|
stabilize_timer_next = stabilize_timer;
|
|
|
|
if (signal_status) begin
|
|
if (&stabilize_timer) begin
|
|
link_status_next = locked;
|
|
end else begin
|
|
stabilize_timer_next[0] = stabilize_timer[16] ^ stabilize_timer[13];
|
|
stabilize_timer_next[16:1] = stabilize_timer[15:0];
|
|
end
|
|
end else if (link_monitor_test_mode) begin
|
|
stabilize_timer_next = TEST_STABILIZE_VALUE;
|
|
end else begin
|
|
stabilize_timer_next = STABILIZE_VALUE;
|
|
end
|
|
|
|
if (loopback)
|
|
stabilize_timer_next = 17'h1ffff;
|
|
end
|
|
|
|
always @(posedge clk) begin
|
|
stabilize_timer <= stabilize_timer_next;
|
|
link_status <= link_status_next;
|
|
end
|
|
|
|
wire receiving;
|
|
|
|
pcs_rx pcs_rx (
|
|
.clk(clk),
|
|
.ce(rx_ce),
|
|
.valid(rx_dv),
|
|
.data(rxd),
|
|
.err(rx_er),
|
|
.bits(rx_bits),
|
|
.bits_valid(rx_bits_valid),
|
|
.link_status(link_status),
|
|
.rx(receiving)
|
|
);
|
|
|
|
/*
|
|
* NB: These signals are not required to be in any particular clock
|
|
* domain (not that it matters).
|
|
*/
|
|
always @(*) begin
|
|
crs = transmitting || receiving;
|
|
col = transmitting && receiving;
|
|
if (coltest)
|
|
col = transmitting;
|
|
else if (loopback)
|
|
col = 0;
|
|
end
|
|
|
|
endmodule
|