Co-authored-by: Andrew Moch <Andrew.Moch@ni.com> Co-authored-by: Daniel Jepson <daniel.jepson@ni.com> Co-authored-by: Javier Valenzuela <javier.valenzuela@ni.com> Co-authored-by: Joerg Hofrichter <joerg.hofrichter@ni.com> Co-authored-by: Kumaran Subramoniam <kumaran.subramoniam@ni.com> Co-authored-by: Max Köhler <max.koehler@ni.com> Co-authored-by: Michael Auchter <michael.auchter@ni.com> Co-authored-by: Paul Butler <paul.butler@ni.com> Co-authored-by: Wade Fife <wade.fife@ettus.com> Co-authored-by: Hector Rubio <hrubio@ni.com> Original-commit: 6d3765605262016a80f71e36357f749ea35cbe5a
235 lines
6.9 KiB
Systemverilog
235 lines
6.9 KiB
Systemverilog
//
|
|
// Copyright 2021 Ettus Research, A National Instruments Brand
|
|
//
|
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
//
|
|
// Module: model_100gbe
|
|
//
|
|
// Description:
|
|
//
|
|
// A wrapper of the 100gbe core to axistream interface. this model can be
|
|
// used drive packets into the X400 translated to serial Ethernet. This is
|
|
// generally pretty slower than just driving things in at the output of the
|
|
// mac.
|
|
//
|
|
|
|
package Pkg100gbMac;
|
|
import PkgAxiLite::*;
|
|
import PkgAxiLiteBfm::*;
|
|
import PkgTestExec::*;
|
|
|
|
localparam DATA_WIDTH =32;
|
|
localparam ADDR_WIDTH =15;
|
|
|
|
typedef AxiLiteBfm #(DATA_WIDTH, ADDR_WIDTH) MacAxiLiteBfm_t;
|
|
|
|
// defined in https://www.xilinx.com/support/documentation/ip_documentation/cmac_usplus/v2_4/pg203-cmac-usplus.pdf
|
|
// pg 187
|
|
localparam CONFIGURATION_TX_REG1 = 32'h000C;
|
|
localparam ctl_tx_ctl_enable = 0;
|
|
localparam ctl_tx_ctl_tx_send_lfi = 3;
|
|
localparam ctl_tx_ctl_tx_send_rfi = 4;
|
|
localparam ctl_tx_ctl_tx_send_idle = 5;
|
|
localparam ctl_tx_ctl_test_pattern = 16;
|
|
|
|
localparam CONFIGURATION_RX_REG1 = 32'h0014;
|
|
localparam ctl_rx_ctl_enable = 0;
|
|
localparam ctl_rx_ctl_rx_force_resync = 7;
|
|
localparam ctl_rx_ctl_test_pattern = 8;
|
|
|
|
localparam RSFEC_CONFIG_INDICATION_CORRECTION = 32'h1000;
|
|
localparam rs_fec_in_ctl_rx_rsfec_enable_correction = 0;
|
|
localparam rs_fec_in_ctl_rx_rsfec_enable_indication = 1;
|
|
localparam rs_fec_in_ctl_rsfec_ieee_error_indication_mode = 2;
|
|
|
|
localparam RSFEC_CONFIG_ENABLE = 32'h107C;
|
|
localparam rs_fec_in_ctl_rx_rsfec_enable = 0;
|
|
localparam rs_fec_in_ctl_tx_rsfec_enable = 1;
|
|
|
|
localparam STAT_RX_STATUS_REG = 32'h0204;
|
|
localparam stat_rx_status = 0;
|
|
localparam stat_rx_aligned = 1;
|
|
localparam stat_rx_misaligned = 2;
|
|
localparam stat_rx_aligned_err = 3;
|
|
|
|
task automatic init_mac (int offset, MacAxiLiteBfm_t axi);
|
|
automatic logic [31:0] data;
|
|
automatic resp_t resp;
|
|
|
|
// start transmitting alignment pattern
|
|
data = 0;
|
|
data[ctl_tx_ctl_enable] = 0;
|
|
data[ctl_tx_ctl_tx_send_idle] = 0;
|
|
data[ctl_tx_ctl_tx_send_lfi] = 0;
|
|
data[ctl_tx_ctl_tx_send_rfi] = 1;
|
|
data[ctl_tx_ctl_test_pattern] = 0;
|
|
axi.wr(CONFIGURATION_TX_REG1+offset,data);
|
|
|
|
// configure fec
|
|
data = 0;
|
|
data[rs_fec_in_ctl_rx_rsfec_enable_correction] = 1;
|
|
data[rs_fec_in_ctl_rx_rsfec_enable_indication] = 1;
|
|
data[rs_fec_in_ctl_rsfec_ieee_error_indication_mode] = 1;
|
|
axi.wr(RSFEC_CONFIG_INDICATION_CORRECTION+offset,data);
|
|
|
|
data = 0;
|
|
data[rs_fec_in_ctl_rx_rsfec_enable] = 1;
|
|
data[rs_fec_in_ctl_tx_rsfec_enable] = 1;
|
|
axi.wr(RSFEC_CONFIG_ENABLE+offset,data);
|
|
|
|
// turn on RX interface
|
|
data = 0;
|
|
data[ctl_rx_ctl_enable] = 1;
|
|
data[ctl_rx_ctl_rx_force_resync] = 0;
|
|
data[ctl_rx_ctl_test_pattern] = 0;
|
|
axi.wr(CONFIGURATION_RX_REG1+offset,data);
|
|
|
|
do begin
|
|
axi.rd_block(STAT_RX_STATUS_REG+offset,data,resp);
|
|
assert (resp==OKAY);
|
|
end while (data[stat_rx_aligned] !== 1);
|
|
|
|
// stop transmitting alignment pattern
|
|
// and start transmitting data
|
|
data = 0;
|
|
data[ctl_tx_ctl_enable] = 1;
|
|
data[ctl_tx_ctl_tx_send_idle] = 0;
|
|
data[ctl_tx_ctl_tx_send_lfi] = 0;
|
|
data[ctl_tx_ctl_tx_send_rfi] = 0;
|
|
data[ctl_tx_ctl_test_pattern] = 0;
|
|
axi.wr(CONFIGURATION_TX_REG1+offset,data);
|
|
|
|
endtask : init_mac
|
|
|
|
endpackage : Pkg100gbMac
|
|
|
|
module model_100gbe (
|
|
input logic areset,
|
|
// 156.25 Mhz refclk
|
|
input logic ref_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,
|
|
|
|
// CLK and RESET out
|
|
output logic mgt_clk,
|
|
output logic mgt_rst,
|
|
output logic link_up,
|
|
|
|
// Data port
|
|
AxiStreamIf.slave mgt_tx,
|
|
AxiStreamIf.master mgt_rx
|
|
|
|
);
|
|
|
|
// Include macros and time declarations for use with PkgTestExec
|
|
`define TEST_EXEC_OBJ test
|
|
`include "test_exec.svh"
|
|
import PkgAxiLiteBfm::*;
|
|
import PkgTestExec::*;
|
|
|
|
logic refclk_p;
|
|
logic refclk_n;
|
|
|
|
logic clk40,clk40_rst;
|
|
logic clk100,clk100_rst;
|
|
logic phy_reset;
|
|
|
|
assign refclk_p = ref_clk;
|
|
assign refclk_n = ~ref_clk;
|
|
|
|
//interface
|
|
AxiLiteIf #(Pkg100gbMac::DATA_WIDTH,Pkg100gbMac::ADDR_WIDTH)
|
|
mgt_axil (clk40, clk40_rst);
|
|
//bfm
|
|
Pkg100gbMac::MacAxiLiteBfm_t axi = new(.master(mgt_axil));
|
|
TestExec mac_test = new();
|
|
|
|
sim_clock_gen #(.PERIOD(25.0), .AUTOSTART(1))
|
|
clk40_gen (.clk(clk40), .rst(clk40_rst));
|
|
sim_clock_gen #(.PERIOD(100.0), .AUTOSTART(1))
|
|
clk100_gen (.clk(clk100), .rst(clk100_rst));
|
|
|
|
initial begin : init_model
|
|
clk40_gen.reset();
|
|
axi.run();
|
|
wait(!clk40_rst);
|
|
repeat (10) @(posedge clk40);
|
|
|
|
wait(!phy_reset); // both usr_clk's are ok
|
|
|
|
mac_test.start_test("model_100gbe::Wait for MAC link_up", 150us);
|
|
//Added autoconnect - uncomment to test connecting over AXI
|
|
//Pkg100gbMac::init_mac(0,axi);
|
|
mac_test.end_test();
|
|
end
|
|
|
|
|
|
AxiStreamIf #(.DATA_WIDTH(512),.USER_WIDTH(7),.TKEEP(0))
|
|
eth100g_rx(mgt_clk,mgt_rst);
|
|
|
|
always_comb begin
|
|
mgt_rx.tdata = eth100g_rx.tdata;
|
|
mgt_rx.tuser = eth100g_rx.tuser;
|
|
mgt_rx.tkeep = eth100g_rx.trailing2keep(eth100g_rx.tuser);
|
|
mgt_rx.tvalid = eth100g_rx.tvalid;
|
|
mgt_rx.tlast = eth100g_rx.tlast;
|
|
eth100g_rx.tready = mgt_rx.tready;
|
|
// The MAC ignores hold off. Data must be consumed every clock it is valid.
|
|
if (!mgt_rst) begin
|
|
if (!mgt_rx.tready && mgt_rx.tvalid) begin
|
|
$error("Model 100Gbe : can't hold off the MAC");
|
|
end
|
|
end
|
|
end
|
|
|
|
// model does not pause. Users could access this heirarchically to test it
|
|
logic mgt_pause_req;
|
|
assign mgt_pause_req = 1'b0;
|
|
|
|
// hold off link up untill the stat_auto_config writes are complete
|
|
logic link_up_model;
|
|
logic [31:0] mac_status;
|
|
always_comb begin
|
|
link_up = link_up_model && mac_status[4];
|
|
end
|
|
|
|
eth_100g #(.PAUSE_QUANTA(10),.PAUSE_REFRESH(100)) eth_100gx (
|
|
.areset(areset),
|
|
//-- Free running 100 MHz clock used for InitClk and AxiLite to mac
|
|
//-- 3.125 - 161.132812 MHz.
|
|
.clk100(clk100),
|
|
// MGT Reference Clock 100/125/156.25/161.1328125 MHz
|
|
.refclk_p(refclk_p),
|
|
.refclk_n(refclk_n),
|
|
// 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),
|
|
// pause
|
|
.mgt_pause_req(mgt_pause_req),
|
|
//------------------------ AXI Stream TX Interface ------------------------
|
|
.mgt_tx(mgt_tx),
|
|
//---------------------- AXI Stream RX Interface ------------------------
|
|
// There is no RxTReady signal support by the Ethernet100G IP. Received data has to
|
|
// be read immediately or it is lost.
|
|
// tUser indicates an error on rcvd packet
|
|
.mgt_rx(eth100g_rx),
|
|
.mgt_axil(mgt_axil),
|
|
// LEDs of QSFP28 port
|
|
.phy_status(),
|
|
.mac_ctrl(32'h01000001), // autoconfig / pause mask set to global
|
|
.mac_status(mac_status),
|
|
.phy_reset(phy_reset),
|
|
.link_up(link_up_model)
|
|
);
|
|
|
|
endmodule
|