- Fix NODE_INST - Fix RFNOC_PROTOVER - Add option to use SystemVerilog transport adapter for raw UDP Original-commit: 0114e108af63d9ac785649c8099a042299624943
655 lines
23 KiB
Verilog
655 lines
23 KiB
Verilog
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright 2018 Ettus Research, A National Instruments Company
|
|
//
|
|
// SPDX-License-Identifier: LGPL-3.0
|
|
//
|
|
// Module: e320_mgt_io_core
|
|
// Description:
|
|
// Encapsulates the PSC/PMA, the MAC layer and the control interface
|
|
// for 1GbE, 10GbE and Aurora
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
module e320_mgt_io_core #(
|
|
parameter PROTOCOL = "10GbE", // Must be {10GbE, 1GbE, Aurora, Disabled}
|
|
parameter [13:0] REG_BASE = 14'h0,
|
|
parameter REG_DWIDTH = 32,
|
|
parameter REG_AWIDTH = 14,
|
|
parameter [7:0] PORTNUM = 8'd0,
|
|
parameter MDIO_EN = 0,
|
|
parameter [4:0] MDIO_PHYADDR = 5'd0
|
|
)(
|
|
// Resets
|
|
input areset,
|
|
input bus_rst,
|
|
// Clocks
|
|
input gt_refclk,
|
|
input gb_refclk,
|
|
input misc_clk,
|
|
input bus_clk,
|
|
// SFP high-speed IO
|
|
output txp,
|
|
output txn,
|
|
input rxp,
|
|
input rxn,
|
|
// SFP low-speed IO
|
|
input sfpp_rxlos,
|
|
input sfpp_tx_fault,
|
|
output sfpp_tx_disable,
|
|
// Data port: Ethernet TX
|
|
input [63:0] s_axis_tdata,
|
|
input [3:0] s_axis_tuser,
|
|
input s_axis_tlast,
|
|
input s_axis_tvalid,
|
|
output s_axis_tready,
|
|
// Data port: Ethernet RX
|
|
output [63:0] m_axis_tdata,
|
|
output [3:0] m_axis_tuser,
|
|
output m_axis_tlast,
|
|
output m_axis_tvalid,
|
|
input m_axis_tready,
|
|
// Register port
|
|
input reg_wr_req,
|
|
input [REG_AWIDTH-1:0] reg_wr_addr,
|
|
input [REG_DWIDTH-1:0] reg_wr_data,
|
|
input reg_rd_req,
|
|
input [REG_AWIDTH-1:0] reg_rd_addr,
|
|
output reg_rd_resp,
|
|
output [REG_DWIDTH-1:0] reg_rd_data,
|
|
// Misc
|
|
output [31:0] port_info,
|
|
output link_up,
|
|
output reg activity
|
|
);
|
|
|
|
//-----------------------------------------------------------------
|
|
// 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;
|
|
|
|
wire reg_rd_resp_mdio;
|
|
reg reg_rd_resp_glob = 1'b0;
|
|
wire [REG_DWIDTH-1:0] reg_rd_data_mdio;
|
|
reg [REG_DWIDTH-1:0] reg_rd_data_glob = 32'h0;
|
|
|
|
// Protocol specific constants
|
|
wire [7:0] mgt_protocol;
|
|
wire [31:0] mac_ctrl_rst_val, phy_ctrl_rst_val;
|
|
wire [1:0] mac_led_ctl_rst_val = 2'h0;
|
|
|
|
// Flush logic: If the link is not up, we will flush all packets coming from
|
|
// the device. This avoids the MAC backpressuring when the PHY is down.
|
|
// The device will always send discovery packets to the transports during
|
|
// initialization, and they have no way of knowing if it's safe to travel
|
|
// down this route. c2mac == "CHDR to MAC"
|
|
wire [63:0] c2mac_tdata;
|
|
wire [3:0] c2mac_tuser;
|
|
wire c2mac_tlast;
|
|
wire c2mac_tvalid;
|
|
wire c2mac_tready;
|
|
|
|
axis_packet_flush #(
|
|
.WIDTH(64+3), // tdata + tuser
|
|
.TIMEOUT_W(1), // Not using timeout
|
|
.FLUSH_PARTIAL_PKTS(0),
|
|
.PIPELINE("NONE")
|
|
) linkup_flush (
|
|
.clk(bus_clk),
|
|
.reset(bus_rst),
|
|
.enable(~link_up), // enable flushing when link down
|
|
.timeout(1'b0),
|
|
.flushing(/* not required */),
|
|
.done(/* not required */),
|
|
// Input from device/crossbar
|
|
.s_axis_tdata ({s_axis_tuser, s_axis_tdata}),
|
|
.s_axis_tlast (s_axis_tlast),
|
|
.s_axis_tvalid (s_axis_tvalid),
|
|
.s_axis_tready (s_axis_tready),
|
|
// Output to MAC
|
|
.m_axis_tdata ({c2mac_tuser, c2mac_tdata}),
|
|
.m_axis_tlast (c2mac_tlast),
|
|
.m_axis_tvalid (c2mac_tvalid),
|
|
.m_axis_tready (c2mac_tready)
|
|
);
|
|
|
|
generate
|
|
if (PROTOCOL == "Aurora") begin
|
|
assign mgt_protocol = 8'd3;
|
|
assign mac_ctrl_rst_val = 32'h0;
|
|
assign phy_ctrl_rst_val = 32'h0;
|
|
end else if (PROTOCOL == "10GbE") begin
|
|
assign mgt_protocol = 8'd2;
|
|
assign mac_ctrl_rst_val = {31'h0, 1'b1}; // tx_enable on reset
|
|
assign phy_ctrl_rst_val = 32'h0;
|
|
end else if (PROTOCOL == "1GbE") begin
|
|
assign mgt_protocol = 8'd1;
|
|
assign mac_ctrl_rst_val = {31'h0, 1'b1}; // tx_enable on reset
|
|
assign phy_ctrl_rst_val = 32'h0;
|
|
end else begin
|
|
assign mgt_protocol = 8'd0;
|
|
assign mac_ctrl_rst_val = 32'h0;
|
|
assign phy_ctrl_rst_val = 32'h0;
|
|
end
|
|
endgenerate
|
|
|
|
// Writable registers
|
|
reg [31:0] mac_ctrl_reg = 32'h0;
|
|
reg [31:0] phy_ctrl_reg = 32'h0;
|
|
reg [1:0] mac_led_ctl = 2'h0;
|
|
|
|
always @(posedge bus_clk) begin
|
|
if (bus_rst) begin
|
|
mac_ctrl_reg <= mac_ctrl_rst_val;
|
|
phy_ctrl_reg <= phy_ctrl_rst_val;
|
|
mac_led_ctl <= mac_led_ctl_rst_val;
|
|
end else if (reg_wr_req) begin
|
|
case(reg_wr_addr)
|
|
REG_MAC_CTRL_STATUS:
|
|
mac_ctrl_reg <= reg_wr_data;
|
|
REG_PHY_CTRL_STATUS:
|
|
phy_ctrl_reg <= reg_wr_data;
|
|
REG_MAC_LED_CTL:
|
|
mac_led_ctl <= reg_wr_data[1:0];
|
|
endcase
|
|
end
|
|
end
|
|
|
|
// Readable registers
|
|
wire [31:0] overruns;
|
|
wire [31:0] checksum_errors;
|
|
wire [47:0] bist_checker_samps;
|
|
wire [47:0] bist_checker_errors;
|
|
wire [31:0] mac_status, phy_status;
|
|
wire [31:0] mac_status_bclk, phy_status_bclk;
|
|
|
|
assign port_info = {COMPAT_NUM, 6'h0, activity, link_up, mgt_protocol, PORTNUM};
|
|
|
|
always @(posedge bus_clk) begin
|
|
// No reset handling needed for readback
|
|
if (reg_rd_req) begin
|
|
reg_rd_resp_glob <= 1'b1;
|
|
case(reg_rd_addr)
|
|
REG_PORT_INFO:
|
|
reg_rd_data_glob <= port_info;
|
|
REG_MAC_CTRL_STATUS:
|
|
reg_rd_data_glob <= mac_status_bclk;
|
|
REG_PHY_CTRL_STATUS:
|
|
reg_rd_data_glob <= phy_status_bclk;
|
|
REG_MAC_LED_CTL:
|
|
reg_rd_data_glob <= {30'd0, mac_led_ctl};
|
|
REG_AURORA_OVERRUNS:
|
|
reg_rd_data_glob <= overruns;
|
|
REG_CHECKSUM_ERRORS:
|
|
reg_rd_data_glob <= checksum_errors;
|
|
REG_BIST_CHECKER_SAMPS:
|
|
reg_rd_data_glob <= bist_checker_samps[47:16]; //Scale num samples by 2^16
|
|
REG_BIST_CHECKER_ERRORS:
|
|
reg_rd_data_glob <= bist_checker_errors[31:0]; //Don't scale errors
|
|
default:
|
|
reg_rd_resp_glob <= 1'b0;
|
|
endcase
|
|
end if (reg_rd_resp_glob) begin
|
|
reg_rd_resp_glob <= 1'b0;
|
|
end
|
|
end
|
|
|
|
synchronizer #( .STAGES(2), .WIDTH(32), .INITIAL_VAL(32'h0) ) mac_status_sync_i (
|
|
.clk(bus_clk), .rst(1'b0), .in(mac_status), .out(mac_status_bclk)
|
|
);
|
|
|
|
synchronizer #( .STAGES(2), .WIDTH(32), .INITIAL_VAL(32'h0) ) phy_status_sync_i (
|
|
.clk(bus_clk), .rst(1'b0), .in(phy_status), .out(phy_status_bclk)
|
|
);
|
|
|
|
// Regport Mux for response
|
|
regport_resp_mux #(
|
|
.WIDTH (REG_DWIDTH),
|
|
.NUM_SLAVES (2)
|
|
) reg_resp_mux_i (
|
|
.clk(bus_clk), .reset(bus_rst),
|
|
.sla_rd_resp({reg_rd_resp_mdio, reg_rd_resp_glob}),
|
|
.sla_rd_data({reg_rd_data_mdio, reg_rd_data_glob}),
|
|
.mst_rd_resp(reg_rd_resp), .mst_rd_data(reg_rd_data)
|
|
);
|
|
|
|
//-----------------------------------------------------------------
|
|
// Ethernet Specific: MDIO
|
|
//-----------------------------------------------------------------
|
|
|
|
wire mdc, mdio_m2s, mdio_s2m, mdio_s2m_sync;
|
|
generate
|
|
if ((PROTOCOL == "10GbE" || PROTOCOL == "1GbE") && (MDIO_EN == 1)) begin
|
|
mdio_master #(
|
|
.REG_BASE (REG_ETH_MDIO_BASE),
|
|
.REG_AWIDTH (REG_AWIDTH),
|
|
.MDC_DIVIDER (8'd200)
|
|
) mdio_master_i (
|
|
.clk (bus_clk),
|
|
.rst (bus_rst),
|
|
.mdc (mdc),
|
|
.mdio_in (mdio_s2m_sync),
|
|
.mdio_out (mdio_m2s),
|
|
.mdio_tri (),
|
|
.reg_wr_req (reg_wr_req),
|
|
.reg_wr_addr (reg_wr_addr),
|
|
.reg_wr_data (reg_wr_data),
|
|
.reg_rd_req (reg_rd_req),
|
|
.reg_rd_addr (reg_rd_addr),
|
|
.reg_rd_data (reg_rd_data_mdio),
|
|
.reg_rd_resp (reg_rd_resp_mdio)
|
|
);
|
|
|
|
// We can cross mdio_s2m into the bus_clk domain. A synchronizer is safe
|
|
// here because the bit is inherently async
|
|
synchronizer #(.INITIAL_VAL(1'b0)) mdio_s2m_sync_i (
|
|
.clk(bus_clk), .rst(1'b0 /* no reset */), .in(mdio_s2m), .out(mdio_s2m_sync)
|
|
);
|
|
end else begin
|
|
assign mdc = 1'b0;
|
|
assign mdio_m2s = 1'b0;
|
|
assign reg_rd_resp_mdio = 1'b0;
|
|
assign reg_rd_data_mdio = 32'h0;
|
|
end
|
|
endgenerate
|
|
|
|
generate
|
|
if (PROTOCOL == "10GbE") begin
|
|
//-----------------------------------------------------------------
|
|
// 10 Gigabit Ethernet
|
|
//-----------------------------------------------------------------
|
|
wire [63:0] xgmii_txd;
|
|
wire [7:0] xgmii_txc;
|
|
wire [63:0] xgmii_rxd;
|
|
wire [7:0] xgmii_rxc;
|
|
wire xge_phy_resetdone;
|
|
|
|
ten_gige_phy ten_gige_phy_i
|
|
(
|
|
// Clocks and Reset
|
|
.areset(areset | phy_ctrl_reg[0]), // Asynchronous reset for entire core.
|
|
.refclk(gt_refclk), // Transciever reference clock: 156.25MHz
|
|
.clk156(gb_refclk), // Globally buffered core clock: 156.25MHz
|
|
.dclk(misc_clk), // Management/DRP clock: 78.125MHz
|
|
.sim_speedup_control(1'b0),
|
|
// GMII Interface (client MAC <=> PCS)
|
|
.xgmii_txd(xgmii_txd), // Transmit data from client MAC.
|
|
.xgmii_txc(xgmii_txc), // Transmit control signal from client MAC.
|
|
.xgmii_rxd(xgmii_rxd), // Received Data to client MAC.
|
|
.xgmii_rxc(xgmii_rxc), // Received control signal to client MAC.
|
|
// Tranceiver Interface
|
|
.txp(txp), // Differential +ve of serial transmission from PMA to PMD.
|
|
.txn(txn), // Differential -ve of serial transmission from PMA to PMD.
|
|
.rxp(rxp), // Differential +ve for serial reception from PMD to PMA.
|
|
.rxn(rxn), // Differential -ve for serial reception from PMD to PMA.
|
|
// Management: MDIO Interface
|
|
.mdc(mdc), // Management Data Clock
|
|
.mdio_in(mdio_m2s), // Management Data In
|
|
.mdio_out(mdio_s2m), // Management Data Out
|
|
.mdio_tri(), // Management Data Tristate
|
|
.prtad(MDIO_PHYADDR), // MDIO address
|
|
// General IO's
|
|
.core_status(phy_status[7:0]), // Core status
|
|
.resetdone(xge_phy_resetdone),
|
|
.signal_detect(~sfpp_rxlos), // Input from PMD to indicate presence of optical input. (Undocumented, but it seems Xilinx expect this to be inverted.)
|
|
.tx_fault(sfpp_tx_fault),
|
|
.tx_disable(sfpp_tx_disable)
|
|
);
|
|
|
|
xge_mac_wrapper #(
|
|
.PORTNUM(PORTNUM),
|
|
.WISHBONE(0)
|
|
) xge_mac_wrapper_i (
|
|
// XGMII
|
|
.xgmii_clk(gb_refclk),
|
|
.xgmii_txd(xgmii_txd),
|
|
.xgmii_txc(xgmii_txc),
|
|
.xgmii_rxd(xgmii_rxd),
|
|
.xgmii_rxc(xgmii_rxc),
|
|
// Client FIFO Interfaces
|
|
.sys_clk(bus_clk),
|
|
.sys_rst(bus_rst),
|
|
.rx_tdata(m_axis_tdata),
|
|
.rx_tuser(m_axis_tuser),
|
|
.rx_tlast(m_axis_tlast),
|
|
.rx_tvalid(m_axis_tvalid),
|
|
.rx_tready(m_axis_tready),
|
|
.tx_tdata(c2mac_tdata),
|
|
.tx_tuser(c2mac_tuser), // Bit[3] (error) is ignored for now.
|
|
.tx_tlast(c2mac_tlast),
|
|
.tx_tvalid(c2mac_tvalid),
|
|
.tx_tready(c2mac_tready),
|
|
// Other
|
|
.phy_ready(xge_phy_resetdone),
|
|
.ctrl_tx_enable(mac_ctrl_reg[0]),
|
|
.status_crc_error(mac_status[0]),
|
|
.status_fragment_error(mac_status[1]),
|
|
.status_txdfifo_ovflow(mac_status[2]),
|
|
.status_txdfifo_udflow(mac_status[3]),
|
|
.status_rxdfifo_ovflow(mac_status[4]),
|
|
.status_rxdfifo_udflow(mac_status[5]),
|
|
.status_pause_frame_rx(mac_status[6]),
|
|
.status_local_fault(mac_status[7]),
|
|
.status_remote_fault(mac_status[8]),
|
|
.wb_ack_o(),
|
|
.wb_dat_o(),
|
|
.wb_adr_i(1'b0),
|
|
.wb_clk_i(1'b0),
|
|
.wb_cyc_i(1'b0),
|
|
.wb_dat_i(1'b0),
|
|
.wb_rst_i(1'b0),
|
|
.wb_stb_i(1'b0),
|
|
.wb_we_i (1'b0),
|
|
.wb_int_o()
|
|
);
|
|
|
|
assign phy_status[31:8] = 24'h0;
|
|
assign mac_status[31:9] = 23'h0;
|
|
assign link_up = phy_status_bclk[0];
|
|
|
|
end else if (PROTOCOL == "1GbE") begin
|
|
|
|
//-----------------------------------------------------------------
|
|
// 1 Gigabit Ethernet
|
|
//-----------------------------------------------------------------
|
|
wire [7:0] gmii_txd, gmii_rxd;
|
|
wire gmii_tx_en, gmii_tx_er, gmii_rx_dv, gmii_rx_er;
|
|
wire gmii_clk;
|
|
wire gt0_qplloutclk, gt0_qplloutrefclk; //unused in 7-series Zynq
|
|
|
|
assign gt0_qplloutclk = 1'b0;
|
|
assign gt0_qplloutrefclk = 1'b0;
|
|
assign sfpp_tx_disable = 1'b0; // Always on.
|
|
|
|
one_gige_phy one_gige_phy_i
|
|
(
|
|
.reset(areset | phy_ctrl_reg[0]), // Asynchronous reset for entire core.
|
|
.independent_clock(bus_clk),
|
|
// Tranceiver Interface
|
|
.gtrefclk(gt_refclk), // Reference clock for MGT: 125MHz, very high quality.
|
|
.gtrefclk_bufg(gb_refclk), // Reference clock routed through a BUFG
|
|
.txp(txp), // Differential +ve of serial transmission from PMA to PMD.
|
|
.txn(txn), // Differential -ve of serial transmission from PMA to PMD.
|
|
.rxp(rxp), // Differential +ve for serial reception from PMD to PMA.
|
|
.rxn(rxn), // Differential -ve for serial reception from PMD to PMA.
|
|
// GMII Interface (client MAC <=> PCS)
|
|
.gmii_clk(gmii_clk), // Clock to client MAC.
|
|
.gmii_txd(gmii_txd), // Transmit data from client MAC.
|
|
.gmii_tx_en(gmii_tx_en), // Transmit control signal from client MAC.
|
|
.gmii_tx_er(gmii_tx_er), // Transmit control signal from client MAC.
|
|
.gmii_rxd(gmii_rxd), // Received Data to client MAC.
|
|
.gmii_rx_dv(gmii_rx_dv), // Received control signal to client MAC.
|
|
.gmii_rx_er(gmii_rx_er), // Received control signal to client MAC.
|
|
// Management: MDIO Interface
|
|
.mdc(mdc), // Management Data Clock
|
|
.mdio_i(mdio_m2s), // Management Data In
|
|
.mdio_o(mdio_s2m), // Management Data Out
|
|
.mdio_t(), // Management Data Tristate
|
|
.phyaddr(MDIO_PHYADDR), // MDIO address
|
|
.configuration_vector(5'd0), // Alternative to MDIO interface.
|
|
.configuration_valid(1'b1), // Validation signal for Config vector (MUST be 1 for proper functionality...undocumented)
|
|
// General IO's
|
|
.status_vector(phy_status[15:0]), // Core status.
|
|
.signal_detect(1'b1 /*Optical module not supported*/) // Input from PMD to indicate presence of optical input.
|
|
);
|
|
|
|
simple_gemac_wrapper #(.RX_FLOW_CTRL(0), .PORTNUM(PORTNUM)) simple_gemac_wrapper_i
|
|
(
|
|
.clk125(gmii_clk),
|
|
.reset(areset),
|
|
|
|
.GMII_GTX_CLK(),
|
|
.GMII_TX_EN(gmii_tx_en),
|
|
.GMII_TX_ER(gmii_tx_er),
|
|
.GMII_TXD(gmii_txd),
|
|
.GMII_RX_CLK(gmii_clk),
|
|
.GMII_RX_DV(gmii_rx_dv),
|
|
.GMII_RX_ER(gmii_rx_er),
|
|
.GMII_RXD(gmii_rxd),
|
|
|
|
.sys_clk(bus_clk),
|
|
.rx_tdata(m_axis_tdata),
|
|
.rx_tuser(m_axis_tuser),
|
|
.rx_tlast(m_axis_tlast),
|
|
.rx_tvalid(m_axis_tvalid),
|
|
.rx_tready(m_axis_tready),
|
|
.tx_tdata(c2mac_tdata),
|
|
.tx_tuser(c2mac_tuser),
|
|
.tx_tlast(c2mac_tlast),
|
|
.tx_tvalid(c2mac_tvalid),
|
|
.tx_tready(c2mac_tready),
|
|
|
|
.wb_clk_i(1'b0),
|
|
.wb_rst_i(1'b0),
|
|
.wb_adr_i(8'h0),
|
|
.wb_dat_i(32'h0),
|
|
.wb_we_i(1'b0),
|
|
.wb_stb_i(1'b0),
|
|
.wb_cyc_i(1'b0),
|
|
.wb_dat_o(),
|
|
.wb_ack_o(),
|
|
.wb_int_o(),
|
|
.mdc(),
|
|
.mdio_out(1'b0),
|
|
.mdio_tri(),
|
|
.mdio_in(),
|
|
.debug_tx(),
|
|
.debug_rx()
|
|
);
|
|
|
|
assign phy_status[31:16] = 16'h0;
|
|
assign mac_status[31:0] = 32'h0;
|
|
assign link_up = phy_status_bclk[0];
|
|
|
|
assign gt_tx_out_clk_unbuf = 1'b0;
|
|
|
|
end else if (PROTOCOL == "Aurora") begin
|
|
|
|
//-----------------------------------------------------------------
|
|
// Aurora
|
|
//-----------------------------------------------------------------
|
|
wire user_clk, user_rst;
|
|
wire [63:0] m2p_tdata, p2m_tdata;
|
|
wire m2p_tvalid, m2p_tready, p2m_tvalid;
|
|
wire channel_up, hard_err, soft_err, mac_crit_err;
|
|
|
|
wire bist_checker_en = mac_ctrl_reg[0];
|
|
wire bist_gen_en = mac_ctrl_reg[1];
|
|
wire bist_loopback_en = mac_ctrl_reg[2];
|
|
wire [5:0] bist_gen_rate = mac_ctrl_reg[8:3];
|
|
wire phy_areset = mac_ctrl_reg[9];
|
|
wire mac_clear = mac_ctrl_reg[10];
|
|
wire bist_checker_locked;
|
|
|
|
assign sfpp_tx_disable = 1'b0; // Always on.
|
|
|
|
aurora_phy_x1 aurora_phy_i (
|
|
// Resets
|
|
.areset(areset | phy_areset),
|
|
// Clocks
|
|
.refclk(gt_refclk),
|
|
.init_clk(misc_clk),
|
|
.user_clk(user_clk),
|
|
.user_rst(user_rst),
|
|
// GTX Serial I/O
|
|
.tx_p(txp),
|
|
.tx_n(txn),
|
|
.rx_p(rxp),
|
|
.rx_n(rxn),
|
|
// AXI4-Stream TX Interface
|
|
.s_axis_tdata(m2p_tdata),
|
|
.s_axis_tvalid(m2p_tvalid),
|
|
.s_axis_tready(m2p_tready),
|
|
// AXI4-Stream RX Interface
|
|
.m_axis_tdata(p2m_tdata),
|
|
.m_axis_tvalid(p2m_tvalid),
|
|
// AXI4-Lite Config Interface (unused)
|
|
.s_axi_awaddr(32'h0),
|
|
.s_axi_araddr(32'h0),
|
|
.s_axi_awvalid(1'b0),
|
|
.s_axi_awready(),
|
|
.s_axi_wdata(32'h0),
|
|
.s_axi_wvalid(1'b0),
|
|
.s_axi_wstrb(1'b0),
|
|
.s_axi_wready(),
|
|
.s_axi_bvalid(),
|
|
.s_axi_bresp(),
|
|
.s_axi_bready(1'b1),
|
|
.s_axi_arready(),
|
|
.s_axi_arvalid(1'b0),
|
|
.s_axi_rdata(),
|
|
.s_axi_rvalid(),
|
|
.s_axi_rresp(),
|
|
.s_axi_rready(1'b1),
|
|
// Status and Error Reporting Interface
|
|
.channel_up(channel_up),
|
|
.hard_err(hard_err),
|
|
.soft_err(soft_err)
|
|
);
|
|
|
|
aurora_axis_mac #(
|
|
.PHY_ENDIANNESS ("LITTLE"),
|
|
.PACKET_MODE (1),
|
|
.MAX_PACKET_SIZE(1024),
|
|
.BIST_ENABLED (1)
|
|
) aurora_mac_i (
|
|
// Clocks and resets
|
|
.phy_clk(user_clk), .phy_rst(user_rst),
|
|
.sys_clk(bus_clk), .sys_rst(bus_rst),
|
|
.clear(mac_clear),
|
|
// PHY Interface (Synchronous to phy_clk)
|
|
.phy_s_axis_tdata(p2m_tdata),
|
|
.phy_s_axis_tvalid(p2m_tvalid),
|
|
.phy_m_axis_tdata(m2p_tdata),
|
|
.phy_m_axis_tvalid(m2p_tvalid),
|
|
.phy_m_axis_tready(m2p_tready),
|
|
// User Interface (Synchronous to sys_clk)
|
|
.s_axis_tdata(c2mac_tdata),
|
|
.s_axis_tlast(c2mac_tlast),
|
|
.s_axis_tvalid(c2mac_tvalid),
|
|
.s_axis_tready(c2mac_tready),
|
|
.m_axis_tdata(m_axis_tdata),
|
|
.m_axis_tlast(m_axis_tlast),
|
|
.m_axis_tvalid(m_axis_tvalid),
|
|
.m_axis_tready(m_axis_tready),
|
|
// PHY Status Inputs (Synchronous to phy_clk)
|
|
.channel_up(channel_up),
|
|
.hard_err(hard_err),
|
|
.soft_err(soft_err),
|
|
// Status and Error Outputs (Synchronous to sys_clk)
|
|
.overruns(overruns),
|
|
.soft_errors(),
|
|
.checksum_errors(checksum_errors),
|
|
.critical_err(mac_crit_err),
|
|
// BIST Interface (Synchronous to sys_clk)
|
|
.bist_gen_en(bist_gen_en),
|
|
.bist_gen_rate(bist_gen_rate),
|
|
.bist_checker_en(bist_checker_en),
|
|
.bist_loopback_en(bist_loopback_en),
|
|
.bist_checker_locked(bist_checker_locked),
|
|
.bist_checker_samps(bist_checker_samps),
|
|
.bist_checker_errors(bist_checker_errors)
|
|
);
|
|
|
|
assign m_axis_tuser = 4'd0;
|
|
|
|
wire channel_up_bclk, hard_err_bclk, soft_err_bclk, mac_crit_err_bclk;
|
|
synchronizer #(.INITIAL_VAL(1'b0)) channel_up_sync (
|
|
.clk(bus_clk), .rst(1'b0 /* no reset */), .in(channel_up), .out(channel_up_bclk));
|
|
synchronizer #(.INITIAL_VAL(1'b0)) hard_err_sync (
|
|
.clk(bus_clk), .rst(1'b0 /* no reset */), .in(hard_err), .out(hard_err_bclk));
|
|
synchronizer #(.INITIAL_VAL(1'b0)) soft_err_sync (
|
|
.clk(bus_clk), .rst(1'b0 /* no reset */), .in(soft_err), .out(soft_err_bclk));
|
|
synchronizer #(.INITIAL_VAL(1'b0)) mac_crit_err_sync (
|
|
.clk(bus_clk), .rst(1'b0 /* no reset */), .in(mac_crit_err), .out(mac_crit_err_bclk));
|
|
|
|
reg [19:0] bist_lock_latency;
|
|
always @(posedge bus_clk) begin
|
|
if (!bist_checker_en && !bist_checker_locked)
|
|
bist_lock_latency <= 20'd0;
|
|
else if (bist_checker_en && !bist_checker_locked)
|
|
bist_lock_latency <= bist_lock_latency + 20'd1;
|
|
end
|
|
|
|
reg mac_crit_err_latch;
|
|
always @(posedge bus_clk) begin
|
|
if (bus_rst | mac_clear) begin
|
|
mac_crit_err_latch <= 1'b0;
|
|
end else begin
|
|
if (mac_crit_err_bclk)
|
|
mac_crit_err_latch <= 1'b1;
|
|
end
|
|
end
|
|
|
|
assign phy_status = {30'd0, hard_err, channel_up};
|
|
assign mac_status = {
|
|
6'h0, //[31:26]
|
|
mac_crit_err_latch, //[25]
|
|
1'b1, //[24]
|
|
1'b0, //[23]
|
|
1'b0, //[22]
|
|
1'b0, //[21]
|
|
1'b0, //[20]
|
|
bist_lock_latency[19:4], //[19:4]
|
|
bist_checker_locked, //[3]
|
|
soft_err_bclk, //[2]
|
|
hard_err_bclk, //[1]
|
|
channel_up_bclk //[0]
|
|
};
|
|
|
|
assign link_up = channel_up_bclk;
|
|
|
|
end else begin
|
|
|
|
//-----------------------------------------------------------------
|
|
// Disabled
|
|
//-----------------------------------------------------------------
|
|
|
|
assign phy_status = 'h0;
|
|
assign mac_status = 'h0;
|
|
assign link_up = 1'b0;
|
|
|
|
assign sfpp_tx_disable = 1'b0; // Always on.
|
|
|
|
assign c2mac_tready = 1'b1;
|
|
assign m_axis_tdata = 64'h0;
|
|
assign m_axis_tuser = 4'h0;
|
|
assign m_axis_tlast = 1'b0;
|
|
assign m_axis_tvalid = 1'b0;
|
|
|
|
end
|
|
endgenerate
|
|
|
|
wire identify_enable = mac_led_ctl[0];
|
|
wire identify_value = mac_led_ctl[1];
|
|
|
|
//-----------------------------------------------------------------
|
|
// Activity detector
|
|
//-----------------------------------------------------------------
|
|
wire activity_int;
|
|
|
|
pulse_stretch act_pulse_str_i (
|
|
.clk(bus_clk),
|
|
.rst(bus_rst | ~link_up),
|
|
.pulse((s_axis_tvalid & s_axis_tready) | (m_axis_tvalid & m_axis_tready)),
|
|
.pulse_stretched(activity_int)
|
|
);
|
|
|
|
always @ (posedge bus_clk) activity <= identify_enable ? identify_value : activity_int;
|
|
|
|
endmodule
|