FPGA: - Split up MB registers that control daughterboard specific settings so that daughterboards 0 and 1 could have different setings, in preparation for future devices that require different settings. This requires a compat number bump to 8.0. - Add registers for additional RFDC information, including the block/tile mapping of the individual channels, and information about resampling capabilities - Identify sections of code that would be specific to X410/ZBX and move them to their own headers, so it's trivial to add device-specific sections of code instead for other devices in the future. - This includes constraints for clocks and I/O pins. - Remove ability to do timed ctrlport transactions to the MB CPLD, this was unused and possibly broken. - Move daughterboard-specific code into its own code location (dboards/zbx) - Move X410-specific register documentation to its own location (doc/X410) - Refactor Makefiles to split out X410/ZBX specific components and allow switching between device types - Add 512-bit AXI interconnects - Make number of timekeepers configurable (X410 keeps the single timekeeper) MPM: - Required compat is bumped to 8.0 - Now supports new registers for detecting DSP capabilities and multi-rate settings for the daughterboards - Adds MMCM controls (currently unused) Co-authored-by: Wade Fife <wade.fife@ni.com> Co-authored-by: Ryan Marlow <ryan@lmarlow.com> Co-authored-by: Martin Braun <martin.braun@ettus.com> Co-authored-by: Humberto Jimenez <humberto.jimenez@ni.com> Original-commit: c1d268917ea65dd9c5a42366014cb96d3c025223
427 lines
13 KiB
Systemverilog
427 lines
13 KiB
Systemverilog
//
|
|
// Copyright 2021 Ettus Research, A National Instruments Brand
|
|
//
|
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
//
|
|
// Module: x4xx_mgt_io_core
|
|
//
|
|
// Description:
|
|
//
|
|
// Encapsulates the PCS/PMA, the MAC layer and the control interface
|
|
// for 10GbE, and 100Gbe.
|
|
//
|
|
// Parameters:
|
|
//
|
|
// PROTOCOL : Indicates the protocol to use for each of the 4 QSFP lanes.
|
|
// See x4xx_mgt_types.vh for possible values.
|
|
// REG_BASE : Base address for internal registers
|
|
// REG_DWIDTH : Register data width
|
|
// REG_AWIDTH : Register address width
|
|
// PORTNUM : Port number, to distinguish between multiple QSFP ports
|
|
// LANENUM : Lane number
|
|
//
|
|
|
|
`include "./x4xx_mgt_types.vh"
|
|
|
|
|
|
module x4xx_mgt_io_core #(
|
|
parameter PROTOCOL = `MGT_100GbE,
|
|
parameter [13:0] REG_BASE = 14'h0,
|
|
parameter REG_DWIDTH = 32,
|
|
parameter REG_AWIDTH = 14,
|
|
parameter [ 7:0] PORTNUM = 8'd0,
|
|
parameter LANENUM = 0
|
|
) (
|
|
// Resets
|
|
input logic areset,
|
|
input logic bus_rst,
|
|
|
|
output logic mgt_rst,
|
|
|
|
// Clocks
|
|
input logic clk100,
|
|
input logic bus_clk,
|
|
input logic refclk_p,
|
|
input logic refclk_n,
|
|
|
|
output logic mgt_clk,
|
|
|
|
// QSFP high-speed IO
|
|
output logic [3:0] tx_p,
|
|
output logic [3:0] tx_n,
|
|
input logic [3:0] rx_p,
|
|
input logic [3:0] rx_n,
|
|
|
|
// Common signals for single lane 10 GbE
|
|
output logic [0:0] qpll0_reset,
|
|
input logic [0:0] qpll0_lock,
|
|
input logic [0:0] qpll0_clk,
|
|
input logic [0:0] qpll0_refclk,
|
|
output logic [0:0] qpll1_reset,
|
|
input logic [0:0] qpll1_lock,
|
|
input logic [0:0] qpll1_clk,
|
|
input logic [0:0] qpll1_refclk,
|
|
|
|
// AXI-Lite
|
|
AxiLiteIf.slave m_axi_mac,
|
|
|
|
// Data port
|
|
// Interface clocks on mgt_tx and mgt_rx are NOT used (logic uses mgt_clk).
|
|
AxiStreamIf.slave mgt_tx,
|
|
AxiStreamIf.master mgt_rx,
|
|
input logic mgt_pause_req,
|
|
|
|
// Register port
|
|
input logic reg_wr_req,
|
|
input logic [REG_AWIDTH-1:0] reg_wr_addr,
|
|
input logic [REG_DWIDTH-1:0] reg_wr_data,
|
|
input logic reg_rd_req,
|
|
input logic [REG_AWIDTH-1:0] reg_rd_addr,
|
|
output logic reg_rd_resp,
|
|
output logic [REG_DWIDTH-1:0] reg_rd_data,
|
|
|
|
// Misc.
|
|
output logic rx_rec_clk_out,
|
|
output logic [31:0] port_info,
|
|
output logic link_up,
|
|
output logic activity
|
|
);
|
|
|
|
import PkgAxiLite::*;
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Registers
|
|
//---------------------------------------------------------------------------
|
|
|
|
localparam [7:0] COMPAT_NUM = 8'd2;
|
|
|
|
// Common registers
|
|
localparam REG_PORT_INFO = REG_BASE + 'h0;
|
|
localparam REG_MAC_CTRL_STATUS = REG_BASE + 'h4;
|
|
localparam REG_PHY_CTRL_STATUS = REG_BASE + 'h8;
|
|
localparam REG_MAC_LED_CTL = REG_BASE + 'hC;
|
|
|
|
// Ethernet specific
|
|
localparam REG_ETH_MDIO_BASE = REG_BASE + 'h10;
|
|
|
|
// Aurora specific
|
|
localparam REG_AURORA_OVERRUNS = REG_BASE + 'h20;
|
|
localparam REG_CHECKSUM_ERRORS = REG_BASE + 'h24;
|
|
localparam REG_BIST_CHECKER_SAMPS = REG_BASE + 'h28;
|
|
localparam REG_BIST_CHECKER_ERRORS = REG_BASE + 'h2C;
|
|
|
|
localparam [ 1:0] MAC_LED_CTRL_RST_VAL = 2'h0;
|
|
localparam [ 7:0] MGT_PROTOCOL = PROTOCOL;
|
|
localparam [31:0] MAC_CTRL_RST_VAL =
|
|
PROTOCOL == `MGT_100GbE ? {31'h0, 1'b1} : // Auto-connect enabled by default
|
|
PROTOCOL == `MGT_WhiteRabbit ? 32'h0 :
|
|
PROTOCOL == `MGT_Aurora ? 32'h0 :
|
|
PROTOCOL == `MGT_10GbE ? {31'h0, 1'b1} : // Tx enabled by default
|
|
PROTOCOL == `MGT_1GbE ? {31'h0, 1'b1} : // Tx enabled by default
|
|
32'h0;
|
|
localparam [31:0] PHY_CTRL_RST_VAL =
|
|
PROTOCOL == `MGT_100GbE ? 32'h0 : // Unused
|
|
PROTOCOL == `MGT_WhiteRabbit ? 32'h0 : // Unused
|
|
PROTOCOL == `MGT_Aurora ? 32'h0 :
|
|
PROTOCOL == `MGT_10GbE ? 32'h0 : // Unused
|
|
PROTOCOL == `MGT_1GbE ? 32'h0 :
|
|
32'h0;
|
|
// Writable registers
|
|
logic [31:0] mac_ctrl = MAC_CTRL_RST_VAL;
|
|
logic [31:0] phy_ctrl = PHY_CTRL_RST_VAL;
|
|
logic [ 1:0] mac_led_ctl = MAC_LED_CTRL_RST_VAL;
|
|
|
|
always @(posedge bus_clk) begin
|
|
if (bus_rst) begin
|
|
mac_ctrl <= MAC_CTRL_RST_VAL;
|
|
phy_ctrl <= PHY_CTRL_RST_VAL;
|
|
mac_led_ctl <= MAC_LED_CTRL_RST_VAL;
|
|
end else if (reg_wr_req) begin
|
|
case(reg_wr_addr)
|
|
REG_MAC_CTRL_STATUS:
|
|
mac_ctrl <= reg_wr_data;
|
|
REG_PHY_CTRL_STATUS:
|
|
phy_ctrl <= reg_wr_data;
|
|
REG_MAC_LED_CTL:
|
|
mac_led_ctl <= reg_wr_data[1:0];
|
|
endcase
|
|
end
|
|
end
|
|
|
|
// Readable registers
|
|
logic [31:0] overruns;
|
|
logic [31:0] checksum_errors;
|
|
logic [47:0] bist_checker_samps;
|
|
logic [47:0] bist_checker_errors;
|
|
logic [31:0] mac_status, phy_status;
|
|
logic [31:0] mac_status_bclk, phy_status_bclk;
|
|
logic activity_bclk, link_up_bclk;
|
|
logic [31:0] port_info_bclk;
|
|
|
|
// readback on m_axi.clk outside this core
|
|
assign port_info = {COMPAT_NUM, 6'h0, activity, link_up, MGT_PROTOCOL, PORTNUM};
|
|
assign port_info_bclk = {COMPAT_NUM, 6'h0, activity_bclk, link_up_bclk, MGT_PROTOCOL, PORTNUM};
|
|
|
|
always @(posedge bus_clk) begin
|
|
// No reset handling needed for readback
|
|
if (reg_rd_req) begin
|
|
reg_rd_resp <= 1'b1;
|
|
case(reg_rd_addr)
|
|
REG_PORT_INFO:
|
|
reg_rd_data <= port_info_bclk;
|
|
REG_MAC_CTRL_STATUS:
|
|
reg_rd_data <= mac_status_bclk;
|
|
REG_PHY_CTRL_STATUS:
|
|
reg_rd_data <= phy_status_bclk;
|
|
REG_MAC_LED_CTL:
|
|
reg_rd_data <= {30'd0, mac_led_ctl};
|
|
REG_AURORA_OVERRUNS:
|
|
reg_rd_data <= overruns;
|
|
REG_CHECKSUM_ERRORS:
|
|
reg_rd_data <= checksum_errors;
|
|
REG_BIST_CHECKER_SAMPS:
|
|
reg_rd_data <= bist_checker_samps[47:16]; // Scale num samples by 2^16
|
|
REG_BIST_CHECKER_ERRORS:
|
|
reg_rd_data <= bist_checker_errors[31:0]; // Don't scale errors
|
|
default:
|
|
begin
|
|
reg_rd_data <= 32'd0;
|
|
reg_rd_resp <= 1'b0;
|
|
end
|
|
endcase
|
|
end if (reg_rd_resp) begin
|
|
reg_rd_resp <= 1'b0;
|
|
end
|
|
end
|
|
|
|
synchronizer #(
|
|
.STAGES(2), .WIDTH(32), .INITIAL_VAL(32'h0)
|
|
) synchronizer_mac_status (
|
|
.clk(bus_clk), .rst(1'b0), .in(mac_status), .out(mac_status_bclk)
|
|
);
|
|
|
|
synchronizer #(
|
|
.STAGES(2), .WIDTH(32), .INITIAL_VAL(32'h0)
|
|
) synchronizer_phy_status (
|
|
.clk(bus_clk), .rst(1'b0), .in(phy_status), .out(phy_status_bclk)
|
|
);
|
|
|
|
logic link_up_mgtclk;
|
|
logic wr_activity = 0;
|
|
|
|
if (PROTOCOL == `MGT_10GbE) begin : core_10g
|
|
|
|
//-------------------------------------------------------------------------
|
|
// 10 GbE Interface
|
|
//-------------------------------------------------------------------------
|
|
|
|
eth_10g eth_10g_i (
|
|
.areset (areset),
|
|
// Free-running 100 MHz clock used for InitClk and AxiLite to MAC
|
|
.clk100 (clk100),
|
|
// Quad Info
|
|
.qpll0_refclk (qpll0_refclk),
|
|
.qpll0_clk (qpll0_clk),
|
|
.qpll0_lock (qpll0_lock),
|
|
.qpll0_reset (qpll0_reset),
|
|
.qpll1_refclk (qpll1_refclk),
|
|
.qpll1_clk (qpll1_clk),
|
|
.qpll1_lock (qpll1_lock),
|
|
.qpll1_reset (qpll1_reset),
|
|
// Recovered clock for export
|
|
.rx_rec_clk_out (rx_rec_clk_out),
|
|
// MGT TX/RX differential signals
|
|
.tx_p (tx_p[LANENUM]),
|
|
.tx_n (tx_n[LANENUM]),
|
|
.rx_p (rx_p[LANENUM]),
|
|
.rx_n (rx_n[LANENUM]),
|
|
// 156.25 MHz clock
|
|
.mgt_clk (mgt_clk),
|
|
.mgt_rst (mgt_rst),
|
|
// AXI Stream TX Interface
|
|
.mgt_tx (mgt_tx),
|
|
// AXI Stream RX Interface
|
|
// There is no RX TREADY signal support in the IP. Received data has to
|
|
// be read immediately or it is lost. TUSER indicates an error on
|
|
// received packet.
|
|
.mgt_rx (mgt_rx),
|
|
// AXI-Lite bus for tie off
|
|
.mgt_axil (m_axi_mac),
|
|
// LEDs of QSFP28 port
|
|
.phy_status (phy_status),
|
|
.mac_ctrl (mac_ctrl),
|
|
.mac_status (mac_status),
|
|
.phy_reset (),
|
|
.link_up (link_up_mgtclk)
|
|
);
|
|
|
|
always_comb begin : eth_10g_tieoff
|
|
overruns = 0;
|
|
checksum_errors = 0;
|
|
bist_checker_samps = 0;
|
|
bist_checker_errors = 0;
|
|
end : eth_10g_tieoff
|
|
|
|
end else if (PROTOCOL == `MGT_100GbE) begin : core_100g
|
|
|
|
//-------------------------------------------------------------------------
|
|
// 100 GbE Interface
|
|
//-------------------------------------------------------------------------
|
|
|
|
eth_100g eth_100g_i (
|
|
.areset (areset),
|
|
// Free-running 100 MHz clock used for InitClk and AxiLite to MAC
|
|
.clk100 (clk100),
|
|
// MGT Reference Clock 100/125/156.25/161.1328125 MHz
|
|
.refclk_p (refclk_p),
|
|
.refclk_n (refclk_n),
|
|
// Recovered clock for export
|
|
.rx_rec_clk_out (rx_rec_clk_out),
|
|
// MGT TX/RX differential signals
|
|
.tx_p (tx_p),
|
|
.tx_n (tx_n),
|
|
.rx_p (rx_p),
|
|
.rx_n (rx_n),
|
|
// 322.26666 MHz clock generated by 100G PHY from RefClock
|
|
.mgt_clk (mgt_clk),
|
|
.mgt_rst (mgt_rst),
|
|
.mgt_pause_req (mgt_pause_req),
|
|
// AXI Stream TX Interface
|
|
.mgt_tx (mgt_tx),
|
|
// AXI Stream RX Interface
|
|
// There is no RX TREADY signal support in the IP. Received data has to
|
|
// be read immediately or it is lost. TUSER indicates an error on
|
|
// received packet.
|
|
.mgt_rx (mgt_rx),
|
|
.mgt_axil (m_axi_mac),
|
|
// LEDs of QSFP28 port
|
|
.phy_status (phy_status),
|
|
.mac_status (mac_status),
|
|
.mac_ctrl (mac_ctrl),
|
|
.phy_reset (),
|
|
.link_up (link_up_mgtclk)
|
|
);
|
|
|
|
always_comb begin : eth_100g_tieoff
|
|
overruns = 0;
|
|
checksum_errors = 0;
|
|
bist_checker_samps = 0;
|
|
bist_checker_errors = 0;
|
|
|
|
qpll0_reset = 0;
|
|
qpll1_reset = 0;
|
|
end : eth_100g_tieoff
|
|
|
|
end else if (PROTOCOL == `MGT_Aurora) begin : core_aurora
|
|
|
|
Aurora_not_yet_supported();
|
|
|
|
always_comb begin : aurrora_tieoff
|
|
m_axi_mac.drive_read_resp(.resp(SLVERR),.data(0));
|
|
m_axi_mac.drive_write_resp(.resp(SLVERR));
|
|
m_axi_mac.arready = 1'b1;
|
|
m_axi_mac.awready = 1'b1;
|
|
m_axi_mac.wready = 1'b1;
|
|
|
|
phy_status = 'h0;
|
|
mac_status = 'h0;
|
|
link_up_mgtclk = 1'b0;
|
|
|
|
overruns = 0;
|
|
checksum_errors = 0;
|
|
bist_checker_samps = 0;
|
|
bist_checker_errors = 0;
|
|
rx_rec_clk_out = 0;
|
|
|
|
qpll0_reset = 0;
|
|
qpll1_reset = 0;
|
|
end : aurrora_tieoff
|
|
|
|
end else begin : core_disabled
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Port Disabled
|
|
//-------------------------------------------------------------------------
|
|
|
|
assign mgt_clk = bus_clk;
|
|
assign mgt_rst = bus_rst;
|
|
|
|
always_comb begin : disabled_tieoff
|
|
m_axi_mac.drive_read_resp(.resp(SLVERR),.data(0));
|
|
m_axi_mac.drive_write_resp(.resp(SLVERR));
|
|
m_axi_mac.arready = 1'b1;
|
|
m_axi_mac.awready = 1'b1;
|
|
m_axi_mac.wready = 1'b1;
|
|
|
|
phy_status = 'h0;
|
|
mac_status = 'h0;
|
|
link_up_mgtclk = 1'b0;
|
|
|
|
mgt_tx.tready = 1'b1;
|
|
mgt_rx.tdata = 64'h0;
|
|
mgt_rx.tuser = 4'h0;
|
|
mgt_rx.tlast = 1'b0;
|
|
mgt_rx.tvalid = 1'b0;
|
|
mgt_rx.tkeep = 'b0;
|
|
|
|
overruns = 0;
|
|
checksum_errors = 0;
|
|
bist_checker_samps = 0;
|
|
bist_checker_errors = 0;
|
|
rx_rec_clk_out = 0;
|
|
|
|
tx_p = 0;
|
|
tx_n = 0;
|
|
|
|
qpll0_reset = 0;
|
|
qpll1_reset = 0;
|
|
end : disabled_tieoff
|
|
|
|
end
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Activity Detector
|
|
//---------------------------------------------------------------------------
|
|
|
|
logic identify_enable,identify_value;
|
|
logic activity_mgtclk, activity_int;
|
|
always_comb begin
|
|
identify_enable = mac_led_ctl[0];
|
|
identify_value = mac_led_ctl[1];
|
|
end
|
|
|
|
pulse_stretch pulse_stretch_activity_i (
|
|
.clk (mgt_clk),
|
|
.rst (mgt_rst | ~link_up_mgtclk),
|
|
.pulse ((mgt_tx.tvalid & mgt_tx.tready) | (mgt_rx.tvalid & mgt_rx.tready)),
|
|
.pulse_stretched (activity_mgtclk)
|
|
);
|
|
|
|
synchronizer #(
|
|
.WIDTH (2),
|
|
.STAGES (1)
|
|
) synchronizer_lnk_act_bclk (
|
|
.clk (bus_clk),
|
|
.rst (bus_rst),
|
|
.in ({link_up_mgtclk, activity_mgtclk}),
|
|
.out ({link_up_bclk, activity_int})
|
|
);
|
|
|
|
always @ (posedge bus_clk) begin
|
|
activity_bclk <= identify_enable ? identify_value : activity_int;
|
|
end
|
|
|
|
synchronizer #(
|
|
.WIDTH (2),
|
|
.STAGES (1)
|
|
) synchronizer_lnk_act_aclk (
|
|
.clk (m_axi_mac.clk),
|
|
.rst (m_axi_mac.rst),
|
|
.in ({link_up_bclk, activity_bclk}),
|
|
.out ({link_up, activity})
|
|
);
|
|
|
|
endmodule
|