aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/top/x400/sim/x4xx_qsfp_wrapper
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp3/top/x400/sim/x4xx_qsfp_wrapper')
-rw-r--r--fpga/usrp3/top/x400/sim/x4xx_qsfp_wrapper/Makefile134
-rw-r--r--fpga/usrp3/top/x400/sim/x4xx_qsfp_wrapper/x4xx_qsfp_wrapper_all_tb.sv77
-rw-r--r--fpga/usrp3/top/x400/sim/x4xx_qsfp_wrapper/x4xx_qsfp_wrapper_tb.sv1641
3 files changed, 1852 insertions, 0 deletions
diff --git a/fpga/usrp3/top/x400/sim/x4xx_qsfp_wrapper/Makefile b/fpga/usrp3/top/x400/sim/x4xx_qsfp_wrapper/Makefile
new file mode 100644
index 000000000..0e669b6e5
--- /dev/null
+++ b/fpga/usrp3/top/x400/sim/x4xx_qsfp_wrapper/Makefile
@@ -0,0 +1,134 @@
+#
+# Copyright 2021 Ettus Research, a National Instruments Brand
+#
+# SPDX-License-Identifier: LGPL-3.0-or-later
+#
+
+#-------------------------------------------------
+# Top-of-Makefile
+#-------------------------------------------------
+# Define BASE_DIR to point to the "top" dir
+BASE_DIR = $(abspath ../../../../top)
+IP_DIR = $(BASE_DIR)/x400/ip
+
+
+# Include viv_sim_preamble after defining BASE_DIR
+include $(BASE_DIR)/../tools/make/viv_sim_preamble.mak
+IP_BUILD_DIR = $(BASE_DIR)/x400/build-ip/xczu28drffvg1517-1e
+
+#-------------------------------------------------
+# Design Specific
+#-------------------------------------------------
+# Define part using PART_ID (<device>/<package>/<speedgrade>)
+ARCH = zynquplusRFSOC
+PART_ID = xczu28dr/ffvg1517/-1/e
+
+# Include makefiles and sources for the DUT and its dependencies
+include $(BASE_DIR)/../lib/control/Makefile.srcs
+include $(BASE_DIR)/../lib/axi/Makefile.srcs
+include $(BASE_DIR)/../lib/axi4_sv/Makefile.srcs
+include $(BASE_DIR)/../lib/axi4s_sv/Makefile.srcs
+include $(BASE_DIR)/../lib/axi4lite_sv/Makefile.srcs
+include $(BASE_DIR)/../lib/packet_proc/Makefile.srcs
+include $(BASE_DIR)/../lib/xge_interface/Makefile.srcs
+include $(BASE_DIR)/../lib/xge/Makefile.srcs
+include $(BASE_DIR)/../lib/wb_spi/Makefile.srcs
+include $(BASE_DIR)/../lib/fifo/Makefile.srcs
+include $(BASE_DIR)/../lib/rfnoc/utils/Makefile.srcs
+include $(BASE_DIR)/../lib/rfnoc/xport/Makefile.srcs
+include $(BASE_DIR)/../lib/rfnoc/xport_sv/Makefile.srcs
+include $(BASE_DIR)/../lib/rfnoc/crossbar/Makefile.srcs
+include $(BASE_DIR)/../lib/rfnoc/core/Makefile.srcs
+include $(BASE_DIR)/../lib/xge/Makefile.srcs
+include $(IP_DIR)/Makefile.inc
+
+
+IP_AXI_ETH_DMA_BD_HDL_SIM_SRCS = $(wildcard $(addprefix $(IP_BUILD_DIR)/axi_eth_dma_bd/axi_eth_dma_bd/, \
+sim/axi_eth_dma_bd.v\
+ip/*/sim/*.h\
+ip/*/sim/*.v\
+ip/*/sim/*.vhd\
+ip/*/bd_0/hdl/*.v\
+ip/*/bd_0/sim/*.v\
+ip/*/bd_0/ip/ip_*/sim/*.v\
+ip/*/bd_0/ip/ip_*/sim/*.sv\
+ip/*/bd_0/ip/ip_*/sim/*.vhd\
+ipshared/*/hdl/*.sv\
+ipshared/*/hdl/*.v\
+ipshared/*/simulation/*.v\
+ipshared/*/hdl/verilog/*.v\
+ipshared/*/hdl/verilog/*.svh\
+ipshared/*/hdl/verilog/*.vh\
+))
+
+IP_AXI_INTERCONNECT_DMA_BD_HDL_SIM_SRCS = $(wildcard $(addprefix $(IP_BUILD_DIR)/axi_interconnect_dma_bd/axi_interconnect_dma_bd/, \
+ip/*/sim/*.v\
+))
+
+TOP_SRC = \
+$(abspath $(BASE_DIR)/x400/x4xx_qsfp_wrapper.sv) \
+$(abspath $(BASE_DIR)/x400/x4xx_qsfp_wrapper_temp.sv) \
+$(abspath $(BASE_DIR)/x400/x4xx_mgt_io_core.sv) \
+$(abspath $(BASE_DIR)/x400/x4xx.v)
+
+# Xilinx IP wants lots of libraries
+MODELSIM_LIBS += secureip unimacro_ver unisims_ver xilinx_vip xpm
+# Needed for the HACK_SRC, speeds up the alignment phase (still long!)
+VLOG_ARGS = +define+SIM_SPEED_UP
+SVLOG_ARGS = -lint +define+BUILD_100G=1
+# Xilinx IP wants a second file loaded
+MODELSIM_ARGS = glbl -t 1fs
+
+DESIGN_SRCS = $(abspath \
+$(AXI4_SV_SRCS) \
+$(AXI4S_SV_SRCS) \
+$(AXI4LITE_SV_SRCS) \
+$(FIFO_SRCS) \
+$(CONTROL_LIB_SRCS) \
+$(AXI_SRCS) \
+$(XGE_INTERFACE_SRCS) \
+$(PACKET_PROC_SRCS) \
+$(RFNOC_UTIL_SRCS) \
+$(RFNOC_XPORT_SRCS) \
+$(RFNOC_XPORT_SV_SRCS) \
+$(RFNOC_XBAR_SRCS) \
+$(RFNOC_CORE_SRCS) \
+$(WISHBONE_SRCS) \
+$(XGE_SRCS) \
+$(XGE_INTERFACE_SRCS) \
+$(XGE_PCS_PMA_SRCS) \
+$(IP_AXI_ETH_DMA_BD_HDL_SIM_SRCS) \
+$(IP_AXI_INTERCONNECT_DMA_BD_HDL_SIM_SRCS) \
+$(IP_AXI_INTERCONNECT_ETH_HDL_SRCS) \
+$(IP_AXI_INTERCONNECT_DMA_HDL_SRCS) \
+$(IP_AXI_ETH_DMA_BD_HDL_SRCS) \
+$(IP_100G_HDL_SRCS) \
+$(AURORA_PHY_SRCS) \
+$(IP_HDL_SIM_SRCS) \
+$(TOP_SRC) \
+)
+
+#-------------------------------------------------
+# Testbench Specific
+#-------------------------------------------------
+# Define only one toplevel module
+TB_TOP_MODULE ?= x4xx_qsfp_wrapper_all_tb
+
+SIM_TOP = $(TB_TOP_MODULE)
+
+SIM_SRCS = \
+$(abspath x4xx_qsfp_wrapper_tb.sv) \
+$(abspath $(TB_TOP_MODULE).sv)
+
+# Suppressing the following worthless reminder.
+#* Warning: M:/usrp4-hw/oss-repo/fpga/usrp3/lib/axi4s_sv/axi4s_remove_bytes.sv(228): (vlog-2583) [SVCHK] -
+# Extra checking for conflicts with always_comb and always_latch variables is done at vopt time
+SVLOG_ARGS = -suppress 2583
+
+#-------------------------------------------------
+# Bottom-of-Makefile
+#-------------------------------------------------
+# Include all simulator specific makefiles here
+# Each should define a unique target to simulate
+# e.g. xsim, vsim, etc and a common "clean" target
+include $(BASE_DIR)/../tools/make/viv_simulator.mak
diff --git a/fpga/usrp3/top/x400/sim/x4xx_qsfp_wrapper/x4xx_qsfp_wrapper_all_tb.sv b/fpga/usrp3/top/x400/sim/x4xx_qsfp_wrapper/x4xx_qsfp_wrapper_all_tb.sv
new file mode 100644
index 000000000..2357d7c9c
--- /dev/null
+++ b/fpga/usrp3/top/x400/sim/x4xx_qsfp_wrapper/x4xx_qsfp_wrapper_all_tb.sv
@@ -0,0 +1,77 @@
+//
+// Copyright 2021 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: x4xx_qsfp_wrapper_all_tb
+//
+// Description:
+//
+// Testbench for the QSFP wrapper to allow testing all protocols.
+//
+
+`include "./x4xx_mgt_types.vh"
+
+module x4xx_qsfp_wrapper_all_tb;
+
+ x4xx_qsfp_wrapper_tb #(
+ .TEST_NAME ("100GbE_F"),
+ .PROTOCOL0 (`MGT_100GbE),
+ .CHDR_W (512),
+ .USE_MAC (0)
+ ) ETH_100Gb_fast ();
+
+ x4xx_qsfp_wrapper_tb #(
+ .TEST_NAME ("10GbE_F"),
+ .PROTOCOL0 (`MGT_10GbE),
+ .CHDR_W (64),
+ .USE_MAC (0)
+ ) ETH_10Gb_fast ();
+
+ x4xx_qsfp_wrapper_tb #(
+ .TEST_NAME ("10GbE_x4_F"),
+ .PROTOCOL0 (`MGT_10GbE),
+ .PROTOCOL1 (`MGT_10GbE),
+ .PROTOCOL2 (`MGT_10GbE),
+ .PROTOCOL3 (`MGT_10GbE),
+ .CHDR_W (64),
+ .USE_MAC (0)
+ ) ETH_10Gb_x4_fast ();
+
+ x4xx_qsfp_wrapper_tb #(
+ .TEST_NAME ("100GbE_512S"),
+ .PROTOCOL0 (`MGT_100GbE),
+ .CHDR_W (512),
+ .USE_MAC (1)
+ ) ETH_100Gb_512serial ();
+
+ x4xx_qsfp_wrapper_tb #(
+ .TEST_NAME ("100GbE_128S"),
+ .PROTOCOL0 (`MGT_100GbE),
+ .CHDR_W (128),
+ .USE_MAC (1)
+ ) ETH_100Gb_128serial ();
+
+ x4xx_qsfp_wrapper_tb #(
+ .TEST_NAME ("10GbE_S"),
+ .PROTOCOL0 (`MGT_10GbE),
+ .CHDR_W (64),
+ .USE_MAC (1)
+ ) ETH_10Gb_serial ();
+
+ bit clk,rst;
+
+ sim_clock_gen #(100.0) clk_gen (clk, rst);
+
+ // Wait for all done
+ always_ff@(posedge clk) begin
+ if (ETH_100Gb_fast.test.done &&
+ ETH_10Gb_fast.test.done &&
+ ETH_10Gb_x4_fast.test.done &&
+ ETH_100Gb_512serial.test.done &&
+ ETH_100Gb_128serial.test.done &&
+ ETH_10Gb_serial.test.done
+ ) $finish(1);
+ end
+
+endmodule
diff --git a/fpga/usrp3/top/x400/sim/x4xx_qsfp_wrapper/x4xx_qsfp_wrapper_tb.sv b/fpga/usrp3/top/x400/sim/x4xx_qsfp_wrapper/x4xx_qsfp_wrapper_tb.sv
new file mode 100644
index 000000000..2d8172de9
--- /dev/null
+++ b/fpga/usrp3/top/x400/sim/x4xx_qsfp_wrapper/x4xx_qsfp_wrapper_tb.sv
@@ -0,0 +1,1641 @@
+//
+// Copyright 2021 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: x4xx_qsfp_wrapper_tb
+//
+// Description:
+//
+// Testbench for x4xx_qsfp_wrapper.
+//
+// Parameters:
+//
+// TEST_NAME : String added to test output
+// PROTOCOL : Must be {100Gbe, 10GbE, 1GbE, Aurora, Disabled}
+// USE_MAC : When set simulate through MAC and PHY. When false, cut before
+// the MAC.
+//
+
+`include "./x4xx_mgt_types.vh"
+
+
+module x4xx_qsfp_wrapper_tb #(
+ parameter TEST_NAME = "x4xx_qsfp_wrapper_tb",
+ parameter PROTOCOL0 = `MGT_10GbE,
+ parameter PROTOCOL1 = `MGT_Disabled,
+ parameter PROTOCOL2 = `MGT_Disabled,
+ parameter PROTOCOL3 = `MGT_Disabled,
+ parameter CHDR_W = 64,
+ parameter logic USE_MAC = 1
+) (
+ /* no IO */
+);
+ // Include macros and time declarations for use with PkgTestExec
+ `define TEST_EXEC_OBJ test
+ `include "test_exec.svh"
+ import PkgAxiStreamBfm::*;
+ import PkgAxiLiteBfm::*;
+ import PkgTestExec::*;
+ import PkgChdrUtils::*;
+ import PkgChdrBfm::*;
+ import PkgEthernet::*;
+
+ //---------------------------------------------------------------------------
+ // Local Parameters
+ //---------------------------------------------------------------------------
+
+ localparam int CPU_W = 64;
+
+ localparam int ENET_W = PROTOCOL0 == `MGT_100GbE?512:64;
+ // 10gbe Mac AUTOEXPANDS small packets > 64 bit
+ localparam AUTOEXPAND_TO_64 = PROTOCOL0 == `MGT_100GbE?0:USE_MAC;
+
+ localparam [7:0] PORTNUM = 0;
+ localparam MDIO_EN = 0;
+ localparam [4:0] MDIO_PHYADDR = 0;
+ localparam [15:0] RFNOC_PROTOVER = {8'd1, 8'd0};
+
+ localparam ENET_USER_W = $clog2(ENET_W/8)+1;
+ localparam CPU_USER_W = $clog2(CPU_W/8)+1;
+ localparam CHDR_USER_W = $clog2(CHDR_W/8)+1;
+ // allows the DUT to push full words and tb does not check tuser/tkeep of packets it's transmitting
+ localparam IGNORE_EXTRA_DATA = 0;
+
+ localparam PREAMBLE_BYTES = (PROTOCOL0 == `MGT_100GbE) ? 0 : 0;
+ localparam USER_CLK_PERIOD = (PROTOCOL0 == `MGT_100GbE) ? 3.1 : 6.4;
+ localparam SV_ETH_IFC = 1;
+
+ localparam logic[3:0] DISABLED = {PROTOCOL3 == `MGT_Disabled,
+ PROTOCOL2 == `MGT_Disabled,
+ PROTOCOL1 == `MGT_Disabled,
+ PROTOCOL0 == `MGT_Disabled};
+ localparam logic[3:0] IS10GBE = {PROTOCOL3 == `MGT_10GbE,
+ PROTOCOL2 == `MGT_10GbE,
+ PROTOCOL1 == `MGT_10GbE,
+ PROTOCOL0 == `MGT_10GbE};
+
+ //---------------------------------------------------------------------------
+ // Clocks and resets
+ //---------------------------------------------------------------------------
+
+ bit clk200,clk100,clk40,clk156p25,userclk,sim_userclk;
+ bit clk200_rst,clk100_rst,clk40_rst,clk40_rstn,refclk_rst,userclk_rst,sim_userclk_rst;
+ logic refclk_p,refclk_n;
+ logic done = 0;
+
+
+ // 322.2666 MHz ref - clock generated by 100G core.
+ // 156.25 MHz ref - clock generated by 10G core.
+ // If we simulate the actual xilinx core, don't use this clock
+ sim_clock_gen #(.PERIOD(USER_CLK_PERIOD), .AUTOSTART(1))
+ userclk_gen (.clk(sim_userclk), .rst(sim_userclk_rst));
+ //156.25 MHz ref
+ sim_clock_gen #(.PERIOD(6.4), .AUTOSTART(1))
+ refclk_gen (.clk(clk156p25), .rst(refclk_rst));
+ always_comb begin
+ refclk_p = clk156p25; //156.25
+ refclk_n = !clk156p25;
+ end
+
+ sim_clock_gen #(.PERIOD(5.0), .AUTOSTART(1))
+ clk200_gen (.clk(clk200), .rst(clk200_rst));
+ sim_clock_gen #(.PERIOD(10.0), .AUTOSTART(1))
+ clk100_gen (.clk(clk100), .rst(clk100_rst));
+ sim_clock_gen #(.PERIOD(25.0), .AUTOSTART(1))
+ clk40_gen (.clk(clk40), .rst(clk40_rst));
+ always_comb clk40_rstn = !clk40_rst;
+
+ //---------------------------------------------------------------------------
+ // Bus Functional Models
+ //---------------------------------------------------------------------------
+ TestExec test = new();
+
+ AxiStreamIf #(.DATA_WIDTH(ENET_W),.USER_WIDTH(ENET_USER_W))
+ eth_tx [3:0] (userclk, userclk_rst);
+ AxiStreamIf #(.DATA_WIDTH(ENET_W),.USER_WIDTH(ENET_USER_W))
+ eth_rx [3:0] (userclk, userclk_rst);
+
+ AxiStreamIf #(.DATA_WIDTH(CHDR_W),.USER_WIDTH(CHDR_USER_W),.TKEEP(0),.TUSER(0))
+ v2e [3:0] (clk200, clk200_rst);
+ AxiStreamIf #(.DATA_WIDTH(CHDR_W),.USER_WIDTH(CHDR_USER_W),.TKEEP(0),.TUSER(0))
+ e2v [3:0] (clk200, clk200_rst);
+
+ AxiStreamIf #(.DATA_WIDTH(CPU_W),.USER_WIDTH(CPU_USER_W),.TUSER(0))
+ c2e [3:0] (clk40, clk40_rst);
+ AxiStreamIf #(.DATA_WIDTH(CPU_W),.USER_WIDTH(CPU_USER_W),.TUSER(0))
+ e2c [3:0] (clk40, clk40_rst);
+
+ AxiLiteIf #(.DATA_WIDTH(32),.ADDR_WIDTH(40))
+ s_axi (clk40, clk40_rst);
+
+ // Bus functional model for a axi_stream controller
+ AxiStreamBfm #(.DATA_WIDTH(ENET_W),.USER_WIDTH(ENET_USER_W)) eth [];
+ AxiStreamBfm #(.DATA_WIDTH(CHDR_W),.USER_WIDTH(CHDR_USER_W),.TKEEP(0),.TUSER(0)) v [];
+ AxiStreamBfm #(.DATA_WIDTH(CPU_W),.USER_WIDTH(CPU_USER_W),.TUSER(0)) cpu [];
+ AxiLiteBfm #(.DATA_WIDTH(32),.ADDR_WIDTH(40)) axi = new(.master(s_axi));
+
+ //---------------------------------------------------------------------------
+ // Instantiate DUT
+ //---------------------------------------------------------------------------
+
+ logic [3:0] tx_p,tx_n,rx_p,rx_n;
+ logic [3:0] [31:0] port_info;
+ logic [15:0] device_id;
+ logic [3:0] link_up, activity;
+ logic QSFP_MODPRS_n =1'b0;
+
+ logic [3:0] eth_rx_irq;
+ logic [3:0] eth_tx_irq;
+
+ // ETH DMA AXI To CPU
+ AxiIf_v #(.DATA_WIDTH(128),.ADDR_WIDTH(49))
+ axi_hp_v (clk40, clk40_rst);
+
+ AxiLiteIf_v #(.DATA_WIDTH(32),.ADDR_WIDTH(40))
+ s_axi_v (clk40, clk40_rst);
+ `include "../../../../../../lib/axi4lite_sv/axi_lite.vh"
+ `include "../../../../../../lib/axi4_sv/axi.vh"
+ always_comb begin
+ `AXI4LITE_ASSIGN(s_axi_v,s_axi)
+ axi_hp_v.arready = 1'b1;
+ axi_hp_v.awready = 1'b1;
+ axi_hp_v.wready = 1'b1;
+ axi_hp_v.rdata = '0;
+ axi_hp_v.rresp[1:0] = 2'b0;
+ axi_hp_v.rlast = 1'b0;
+ axi_hp_v.rvalid = 1'b0;
+ axi_hp_v.bresp[1:0] = 2'b0;
+ axi_hp_v.bvalid = 1'b0;
+ end
+
+ `define MGT_IO0 dut.x4xx_qsfp_wrapper_i.mgt_lanes.lane_loop[0].x4xx_mgt_io_core_i
+ `define MGT_IO1 dut.x4xx_qsfp_wrapper_i.mgt_lanes.lane_loop[1].x4xx_mgt_io_core_i
+ `define MGT_IO2 dut.x4xx_qsfp_wrapper_i.mgt_lanes.lane_loop[2].x4xx_mgt_io_core_i
+ `define MGT_IO3 dut.x4xx_qsfp_wrapper_i.mgt_lanes.lane_loop[3].x4xx_mgt_io_core_i
+ `define QSFP_W dut.x4xx_qsfp_wrapper_i
+
+ x4xx_qsfp_wrapper_temp #(
+ .PROTOCOL0 (PROTOCOL0),
+ .PROTOCOL1 (PROTOCOL1),
+ .PROTOCOL2 (PROTOCOL2),
+ .PROTOCOL3 (PROTOCOL3),
+
+ .CPU_W (CPU_W),
+ .CHDR_W (CHDR_W),
+ .PORTNUM (0)
+ ) dut (
+ .areset (refclk_rst),
+ .refclk_p (refclk_p),
+ .refclk_n (refclk_n),
+ .bus_rst (clk200_rst),
+ .clk40_rst (clk40_rst),
+ .clk100 (clk100),
+ .bus_clk (clk200),
+ .clk40 (clk40),
+ `AXI4_PORT_ASSIGN_NR(axi_hp,axi_hp_v)
+ `AXI4LITE_PORT_ASSIGN_NR(s_axi,s_axi_v)
+ .tx_p (tx_p),
+ .tx_n (tx_n),
+ .rx_p (rx_p),
+ .rx_n (rx_n),
+
+ .e2v_tdata ({e2v[3].tdata, e2v[2].tdata, e2v[1].tdata, e2v[0].tdata}),
+ .e2v_tlast ({e2v[3].tlast, e2v[2].tlast, e2v[1].tlast, e2v[0].tlast}),
+ .e2v_tvalid ({e2v[3].tvalid, e2v[2].tvalid, e2v[1].tvalid, e2v[0].tvalid}),
+ .e2v_tready ({e2v[3].tready, e2v[2].tready, e2v[1].tready, e2v[0].tready}),
+ .v2e_tdata ({v2e[3].tdata, v2e[2].tdata, v2e[1].tdata, v2e[0].tdata}),
+ .v2e_tlast ({v2e[3].tlast, v2e[2].tlast, v2e[1].tlast, v2e[0].tlast}),
+ .v2e_tvalid ({v2e[3].tvalid, v2e[2].tvalid, v2e[1].tvalid, v2e[0].tvalid}),
+ .v2e_tready ({v2e[3].tready, v2e[2].tready, v2e[1].tready, v2e[0].tready}),
+
+ .eth_tx_irq (eth_tx_irq),
+ .eth_rx_irq (eth_rx_irq),
+
+ .rx_rec_clk_out (),
+ .device_id (device_id),
+
+ .port_info_0 (port_info[0]),
+ .port_info_1 (port_info[1]),
+ .port_info_2 (port_info[2]),
+ .port_info_3 (port_info[3]),
+
+ .link_up (link_up),
+ .activity (activity)
+ );
+
+
+ //---------------------------------------------------------------------------
+ // Connect to e2c c2e
+ //---------------------------------------------------------------------------
+ // Ideally simulation would update to test Xilinx DMA block, but as a quick
+ // fix we are simulating just to the AXI stream bus.
+ if (PROTOCOL0 == `MGT_100GbE || PROTOCOL0 == `MGT_10GbE) begin
+ always_comb begin
+ e2c[0].tdata = `QSFP_W.mgt_lanes.lane_loop[0].eth_port.e2c.tdata;
+ e2c[0].tuser = `QSFP_W.mgt_lanes.lane_loop[0].eth_port.e2c.tuser;
+ e2c[0].tkeep = `QSFP_W.mgt_lanes.lane_loop[0].eth_port.e2c.tkeep;
+ e2c[0].tlast = `QSFP_W.mgt_lanes.lane_loop[0].eth_port.e2c.tlast;
+ e2c[0].tvalid = `QSFP_W.mgt_lanes.lane_loop[0].eth_port.e2c.tvalid;
+ force `QSFP_W.mgt_lanes.lane_loop[0].eth_port.e2c.tready = e2c[0].tready;
+
+ force `QSFP_W.mgt_lanes.lane_loop[0].eth_port.c2e.tdata = c2e[0].tdata;
+ force `QSFP_W.mgt_lanes.lane_loop[0].eth_port.c2e.tuser = c2e[0].tuser;
+ force `QSFP_W.mgt_lanes.lane_loop[0].eth_port.c2e.tkeep = c2e[0].tkeep;
+ force `QSFP_W.mgt_lanes.lane_loop[0].eth_port.c2e.tlast = c2e[0].tlast;
+ force `QSFP_W.mgt_lanes.lane_loop[0].eth_port.c2e.tvalid = c2e[0].tvalid;
+ c2e[0].tready = `QSFP_W.mgt_lanes.lane_loop[0].eth_port.c2e.tready;
+ end
+ end
+ if (PROTOCOL1 == `MGT_10GbE) begin
+ always_comb begin
+ e2c[1].tdata = `QSFP_W.mgt_lanes.lane_loop[1].eth_port.e2c.tdata;
+ e2c[1].tuser = `QSFP_W.mgt_lanes.lane_loop[1].eth_port.e2c.tuser;
+ e2c[1].tkeep = `QSFP_W.mgt_lanes.lane_loop[1].eth_port.e2c.tkeep;
+ e2c[1].tlast = `QSFP_W.mgt_lanes.lane_loop[1].eth_port.e2c.tlast;
+ e2c[1].tvalid = `QSFP_W.mgt_lanes.lane_loop[1].eth_port.e2c.tvalid;
+ force `QSFP_W.mgt_lanes.lane_loop[1].eth_port.e2c.tready = e2c[1].tready;
+
+ force `QSFP_W.mgt_lanes.lane_loop[1].eth_port.c2e.tdata = c2e[1].tdata;
+ force `QSFP_W.mgt_lanes.lane_loop[1].eth_port.c2e.tuser = c2e[1].tuser;
+ force `QSFP_W.mgt_lanes.lane_loop[1].eth_port.c2e.tkeep = c2e[1].tkeep;
+ force `QSFP_W.mgt_lanes.lane_loop[1].eth_port.c2e.tlast = c2e[1].tlast;
+ force `QSFP_W.mgt_lanes.lane_loop[1].eth_port.c2e.tvalid = c2e[1].tvalid;
+ c2e[1].tready = `QSFP_W.mgt_lanes.lane_loop[1].eth_port.c2e.tready;
+ end
+ end
+ if (PROTOCOL2 == `MGT_10GbE) begin
+ always_comb begin
+ e2c[2].tdata = `QSFP_W.mgt_lanes.lane_loop[2].eth_port.e2c.tdata;
+ e2c[2].tuser = `QSFP_W.mgt_lanes.lane_loop[2].eth_port.e2c.tuser;
+ e2c[2].tkeep = `QSFP_W.mgt_lanes.lane_loop[2].eth_port.e2c.tkeep;
+ e2c[2].tlast = `QSFP_W.mgt_lanes.lane_loop[2].eth_port.e2c.tlast;
+ e2c[2].tvalid = `QSFP_W.mgt_lanes.lane_loop[2].eth_port.e2c.tvalid;
+ force `QSFP_W.mgt_lanes.lane_loop[2].eth_port.e2c.tready = e2c[2].tready;
+
+ force `QSFP_W.mgt_lanes.lane_loop[2].eth_port.c2e.tdata = c2e[2].tdata;
+ force `QSFP_W.mgt_lanes.lane_loop[2].eth_port.c2e.tuser = c2e[2].tuser;
+ force `QSFP_W.mgt_lanes.lane_loop[2].eth_port.c2e.tkeep = c2e[2].tkeep;
+ force `QSFP_W.mgt_lanes.lane_loop[2].eth_port.c2e.tlast = c2e[2].tlast;
+ force `QSFP_W.mgt_lanes.lane_loop[2].eth_port.c2e.tvalid = c2e[2].tvalid;
+ c2e[2].tready = `QSFP_W.mgt_lanes.lane_loop[2].eth_port.c2e.tready;
+ end
+ end
+ if (PROTOCOL3 == `MGT_10GbE) begin
+ always_comb begin
+ e2c[3].tdata = `QSFP_W.mgt_lanes.lane_loop[3].eth_port.e2c.tdata;
+ e2c[3].tuser = `QSFP_W.mgt_lanes.lane_loop[3].eth_port.e2c.tuser;
+ e2c[3].tkeep = `QSFP_W.mgt_lanes.lane_loop[3].eth_port.e2c.tkeep;
+ e2c[3].tlast = `QSFP_W.mgt_lanes.lane_loop[3].eth_port.e2c.tlast;
+ e2c[3].tvalid = `QSFP_W.mgt_lanes.lane_loop[3].eth_port.e2c.tvalid;
+ force `QSFP_W.mgt_lanes.lane_loop[3].eth_port.e2c.tready = e2c[3].tready;
+
+ force `QSFP_W.mgt_lanes.lane_loop[3].eth_port.c2e.tdata = c2e[3].tdata;
+ force `QSFP_W.mgt_lanes.lane_loop[3].eth_port.c2e.tuser = c2e[3].tuser;
+ force `QSFP_W.mgt_lanes.lane_loop[3].eth_port.c2e.tkeep = c2e[3].tkeep;
+ force `QSFP_W.mgt_lanes.lane_loop[3].eth_port.c2e.tlast = c2e[3].tlast;
+ force `QSFP_W.mgt_lanes.lane_loop[3].eth_port.c2e.tvalid = c2e[3].tvalid;
+ c2e[3].tready = `QSFP_W.mgt_lanes.lane_loop[3].eth_port.c2e.tready;
+ end
+ end
+
+ //---------------------------------------------------------------------------
+ // Connect to Internal Bus
+ //---------------------------------------------------------------------------
+
+ logic [3:0] model_link_up;
+ if (USE_MAC) begin : use_mac
+ if (PROTOCOL0 == `MGT_100GbE) begin : use_mac_100
+ model_100gbe model_100gbe_i (
+ .areset (refclk_rst),
+ .ref_clk (refclk_p),
+ .tx_p (rx_p),
+ .tx_n (rx_n),
+ .rx_p (tx_p),
+ .rx_n (tx_n),
+ .mgt_clk (userclk),
+ .mgt_rst (userclk_rst),
+ .link_up (model_link_up[0]),
+ .mgt_tx (eth_rx[0]),
+ .mgt_rx (eth_tx[0])
+ );
+ end else begin : use_mac_single_lane
+ if (IS10GBE[0]) begin : use_mac0_10
+ logic mgt_clk, mgt_rst;
+ model_10gbe #(.PORTNUM(0)) model_10gbe_0(
+ .areset (refclk_rst),
+ .ref_clk (refclk_p),
+ .tx_p (rx_p[0]),
+ .tx_n (rx_n[0]),
+ .rx_p (tx_p[0]),
+ .rx_n (tx_n[0]),
+ .mgt_clk (userclk),
+ .mgt_rst (userclk_rst),
+ .link_up (model_link_up[0]),
+ .mgt_tx (eth_rx[0]),
+ .mgt_rx (eth_tx[0])
+ );
+ end
+ if (IS10GBE[1]) begin : use_mac1_10
+ logic mgt_clk, mgt_rst;
+ model_10gbe #(.PORTNUM(1)) model_10gbe_1(
+ .areset (refclk_rst),
+ .ref_clk (refclk_p),
+ .tx_p (rx_p[1]),
+ .tx_n (rx_n[1]),
+ .rx_p (tx_p[1]),
+ .rx_n (tx_n[1]),
+ .mgt_clk (userclk),
+ .mgt_rst (userclk_rst),
+ .link_up (model_link_up[1]),
+ .mgt_tx (eth_rx[1]),
+ .mgt_rx (eth_tx[1])
+ );
+ end
+ if (IS10GBE[2]) begin : use_mac2_10
+ logic mgt_clk, mgt_rst;
+ model_10gbe #(.PORTNUM(2)) model_10gbe_2(
+ .areset (refclk_rst),
+ .ref_clk (refclk_p),
+ .tx_p (rx_p[2]),
+ .tx_n (rx_n[2]),
+ .rx_p (tx_p[2]),
+ .rx_n (tx_n[2]),
+ .mgt_clk (userclk),
+ .mgt_rst (userclk_rst),
+ .link_up (model_link_up[2]),
+ .mgt_tx (eth_rx[2]),
+ .mgt_rx (eth_tx[2])
+ );
+ end
+ if (IS10GBE[3]) begin : use_mac3_10
+ logic mgt_clk, mgt_rst;
+ model_10gbe #(.PORTNUM(3)) model_10gbe_3(
+ .areset (refclk_rst),
+ .ref_clk (refclk_p),
+ .tx_p (rx_p[3]),
+ .tx_n (rx_n[3]),
+ .rx_p (tx_p[3]),
+ .rx_n (tx_n[3]),
+ .mgt_clk (userclk),
+ .mgt_rst (userclk_rst),
+ .link_up (model_link_up[3]),
+ .mgt_tx (eth_rx[3]),
+ .mgt_rx (eth_tx[3])
+ );
+ end
+ end : use_mac_single_lane
+ end else begin : skip_mac
+ assign model_link_up = 1;
+ always_comb begin
+ userclk = sim_userclk;
+ userclk_rst = sim_userclk_rst;
+ end
+ if (PROTOCOL0 == `MGT_100GbE) begin : skip_mac_100
+ always_comb begin
+ force `MGT_IO0.core_100g.eth_100g_i.eth_100g_bd_i.gt_txusrclk2 = userclk;
+ force `MGT_IO0.core_100g.eth_100g_i.link_up = !userclk_rst;
+
+ eth_tx[0].tdata = `MGT_IO0.core_100g.eth_100g_i.eth100g_tx.tdata;
+ eth_tx[0].tkeep = `MGT_IO0.core_100g.eth_100g_i.eth100g_tx.tkeep;
+ eth_tx[0].tuser = eth_tx[0].keep2trailing(eth_tx[0].tkeep);
+ eth_tx[0].tlast = `MGT_IO0.core_100g.eth_100g_i.eth100g_tx.tlast;
+ eth_tx[0].tvalid = `MGT_IO0.core_100g.eth_100g_i.eth100g_tx.tvalid;
+ force `MGT_IO0.core_100g.eth_100g_i.eth100g_tx.tready = eth_tx[0].tready;
+ force `MGT_IO0.core_100g.eth_100g_i.lbus_tx[0] = 0;
+ force `MGT_IO0.core_100g.eth_100g_i.lbus_tx[1] = 0;
+ force `MGT_IO0.core_100g.eth_100g_i.lbus_tx[2] = 0;
+ force `MGT_IO0.core_100g.eth_100g_i.lbus_tx[3] = 0;
+
+ force `MGT_IO0.core_100g.eth_100g_i.eth100g_rx.tdata = eth_rx[0].tdata;
+ force `MGT_IO0.core_100g.eth_100g_i.eth100g_rx.tuser = eth_rx[0].tuser;
+ force `MGT_IO0.core_100g.eth_100g_i.eth100g_rx.tkeep = eth_rx[0].tkeep;
+ force `MGT_IO0.core_100g.eth_100g_i.eth100g_rx.tlast = eth_rx[0].tlast;
+ force `MGT_IO0.core_100g.eth_100g_i.eth100g_rx.tvalid = eth_rx[0].tvalid;
+ eth_rx[0].tready = 1;
+ end
+ end else begin : skip_mac_single_lane
+ if (IS10GBE[0]) begin : skip_mac0_10
+ always_comb begin
+ force `MGT_IO0.mgt_clk = userclk;
+ force `MGT_IO0.mgt_rst = userclk_rst;
+ eth_tx[0].tdata = `MGT_IO0.core_10g.eth_10g_i.mgt_tx.tdata;
+ eth_tx[0].tuser = `MGT_IO0.core_10g.eth_10g_i.mgt_tx.tuser;
+ eth_tx[0].tkeep = `MGT_IO0.core_10g.eth_10g_i.mgt_tx.tkeep;
+ eth_tx[0].tlast = `MGT_IO0.core_10g.eth_10g_i.mgt_tx.tlast;
+ eth_tx[0].tvalid = `MGT_IO0.core_10g.eth_10g_i.mgt_tx.tvalid;
+ force `MGT_IO0.core_10g.eth_10g_i.mgt_tx.tready = eth_tx[0].tready;
+
+ force `MGT_IO0.core_10g.eth_10g_i.mgt_rx.tdata = eth_rx[0].tdata;
+ force `MGT_IO0.core_10g.eth_10g_i.mgt_rx.tuser = eth_rx[0].tuser;
+ force `MGT_IO0.core_10g.eth_10g_i.mgt_rx.tlast = eth_rx[0].tlast;
+ force `MGT_IO0.core_10g.eth_10g_i.mgt_rx.tvalid = eth_rx[0].tvalid;
+ eth_rx[0].tready = 1;
+ end
+ end : skip_mac0_10
+ if (IS10GBE[1]) begin : skip_mac1_10
+ always_comb begin
+ force `MGT_IO1.mgt_clk = userclk;
+ force `MGT_IO1.mgt_rst = userclk_rst;
+ eth_tx[1].tdata = `MGT_IO1.core_10g.eth_10g_i.mgt_tx.tdata;
+ eth_tx[1].tuser = `MGT_IO1.core_10g.eth_10g_i.mgt_tx.tuser;
+ eth_tx[1].tkeep = `MGT_IO1.core_10g.eth_10g_i.mgt_tx.tkeep;
+ eth_tx[1].tlast = `MGT_IO1.core_10g.eth_10g_i.mgt_tx.tlast;
+ eth_tx[1].tvalid = `MGT_IO1.core_10g.eth_10g_i.mgt_tx.tvalid;
+ force `MGT_IO1.core_10g.eth_10g_i.mgt_tx.tready = eth_tx[1].tready;
+
+ force `MGT_IO1.core_10g.eth_10g_i.mgt_rx.tdata = eth_rx[1].tdata;
+ force `MGT_IO1.core_10g.eth_10g_i.mgt_rx.tuser = eth_rx[1].tuser;
+ force `MGT_IO1.core_10g.eth_10g_i.mgt_rx.tlast = eth_rx[1].tlast;
+ force `MGT_IO1.core_10g.eth_10g_i.mgt_rx.tvalid = eth_rx[1].tvalid;
+ eth_rx[1].tready = 1;
+ end
+ end : skip_mac1_10
+ if (IS10GBE[2]) begin : skip_mac2_10
+ always_comb begin
+ force `MGT_IO2.mgt_clk = userclk;
+ force `MGT_IO2.mgt_rst = userclk_rst;
+ eth_tx[2].tdata = `MGT_IO2.core_10g.eth_10g_i.mgt_tx.tdata;
+ eth_tx[2].tuser = `MGT_IO2.core_10g.eth_10g_i.mgt_tx.tuser;
+ eth_tx[2].tkeep = `MGT_IO2.core_10g.eth_10g_i.mgt_tx.tkeep;
+ eth_tx[2].tlast = `MGT_IO2.core_10g.eth_10g_i.mgt_tx.tlast;
+ eth_tx[2].tvalid = `MGT_IO2.core_10g.eth_10g_i.mgt_tx.tvalid;
+ force `MGT_IO2.core_10g.eth_10g_i.mgt_tx.tready = eth_tx[2].tready;
+
+ force `MGT_IO2.core_10g.eth_10g_i.mgt_rx.tdata = eth_rx[2].tdata;
+ force `MGT_IO2.core_10g.eth_10g_i.mgt_rx.tuser = eth_rx[2].tuser;
+ force `MGT_IO2.core_10g.eth_10g_i.mgt_rx.tlast = eth_rx[2].tlast;
+ force `MGT_IO2.core_10g.eth_10g_i.mgt_rx.tvalid = eth_rx[2].tvalid;
+ eth_rx[2].tready = 1;
+ end
+ end : skip_mac2_10
+ if (IS10GBE[3]) begin : skip_mac3_10
+ always_comb begin
+ force `MGT_IO3.mgt_clk = userclk;
+ force `MGT_IO3.mgt_rst = userclk_rst;
+ eth_tx[3].tdata = `MGT_IO3.core_10g.eth_10g_i.mgt_tx.tdata;
+ eth_tx[3].tuser = `MGT_IO3.core_10g.eth_10g_i.mgt_tx.tuser;
+ eth_tx[3].tkeep = `MGT_IO3.core_10g.eth_10g_i.mgt_tx.tkeep;
+ eth_tx[3].tlast = `MGT_IO3.core_10g.eth_10g_i.mgt_tx.tlast;
+ eth_tx[3].tvalid = `MGT_IO3.core_10g.eth_10g_i.mgt_tx.tvalid;
+ force `MGT_IO3.core_10g.eth_10g_i.mgt_tx.tready = eth_tx[3].tready;
+
+ force `MGT_IO3.core_10g.eth_10g_i.mgt_rx.tdata = eth_rx[3].tdata;
+ force `MGT_IO3.core_10g.eth_10g_i.mgt_rx.tuser = eth_rx[3].tuser;
+ force `MGT_IO3.core_10g.eth_10g_i.mgt_rx.tlast = eth_rx[3].tlast;
+ force `MGT_IO3.core_10g.eth_10g_i.mgt_rx.tvalid = eth_rx[3].tvalid;
+ eth_rx[3].tready = 1;
+ end
+ end : skip_mac3_10
+ end : skip_mac_single_lane
+ end
+
+ //---------------------------------------------------------------------------
+ // Reset
+ //---------------------------------------------------------------------------
+
+ task test_reset();
+ wait(!clk200_rst && !clk100_rst && !clk40_rst);
+ repeat (10) @(posedge clk40);
+ endtask : test_reset
+
+ //---------------------------------------------------------------------------
+ // Test Registers
+ //---------------------------------------------------------------------------
+
+ // register offset for DMA controller
+ localparam REG_DMA = 'h0;
+ localparam MM2S_DMACR = REG_DMA + 'h0;
+
+ // register offsets from x4xx_mgt_io_core
+ // MGT_IO Registers (NI_XGE registers)
+ localparam REG_BASE_SFP_IO = 32'h8000;
+ localparam REG_PORT_INFO = REG_BASE_SFP_IO + 'h0;
+ localparam REG_MAC_CTRL_STATUS = REG_BASE_SFP_IO + 'h4;
+ localparam REG_PHY_CTRL_STATUS = REG_BASE_SFP_IO + 'h8;
+ localparam REG_MAC_LED_CTL = REG_BASE_SFP_IO + 'hC;
+
+ // Ethernet specific
+ localparam REG_ETH_MDIO_BASE = REG_BASE_SFP_IO + 'h10;
+
+ // Aurora specific
+ localparam REG_AURORA_OVERRUNS = REG_BASE_SFP_IO + 'h20;
+ localparam REG_CHECKSUM_ERRORS = REG_BASE_SFP_IO + 'h24;
+ localparam REG_BIST_CHECKER_SAMPS = REG_BASE_SFP_IO + 'h28;
+ localparam REG_BIST_CHECKER_ERRORS = REG_BASE_SFP_IO + 'h2C;
+
+ // At 0x9000 The OpenCores XGE MAC registers exist.
+
+ // Set BASE for UIO - The package file defines the registers at +0x1000.
+ // NOTE that 0x9000/0x9004 has a local copy of the MAC REGISTER.
+ localparam BASE = 32'h9000;
+ localparam REG_AWIDTH = 16;
+ `include "../../../../lib/rfnoc/xport_sv/eth_regs.vh"
+
+ // 100gbe Registers
+ localparam CMAC_BASE = 32'hC000;
+ localparam REG_CONFIGURATION_TX_FLOW_CONTROL_QUANTA_REG1 = CMAC_BASE+ 32'h0048;
+ localparam REG_CONFIGURATION_TX_FLOW_CONTROL_REFRESH_REG1 = CMAC_BASE+ 32'h0034;
+
+ task test_registers(int lane);
+ localparam [7:0] COMPAT_NUM = 8'd2;
+ logic [7:0] MGT_PROTOCOL;
+
+ automatic resp_t resp;
+ automatic logic activity = 0;
+ automatic logic reg_link_up = 0;
+ automatic logic [31:0] port_info;
+ automatic int data = 0;
+ automatic int LANE_BASE = 32'h10000 * lane;
+ string lane_str;
+ lane_str.itoa(lane);
+
+ test.start_test({TEST_NAME," ",lane_str," Test/Setup Registers"}, 30us);
+
+ case (lane)
+ 0 : MGT_PROTOCOL = PROTOCOL0;
+ 1 : MGT_PROTOCOL = PROTOCOL1;
+ 2 : MGT_PROTOCOL = PROTOCOL2;
+ 3 : MGT_PROTOCOL = PROTOCOL3;
+ endcase
+
+ // testing AxiLite Model
+ repeat (4) begin
+ axi.wr(LANE_BASE+REG_MAC_LSB,++data);
+ axi.rd(LANE_BASE+REG_MAC_LSB,data);
+ axi.wr(LANE_BASE+REG_MAC_MSB,++data);
+ axi.rd(LANE_BASE+REG_MAC_MSB,data);
+ end
+
+ // try with different idle states
+ axi.ready_idle_state = 1;
+ repeat (16) begin
+ axi.wr(LANE_BASE+REG_MAC_LSB,++data);
+ end
+ repeat (4) axi.rd(LANE_BASE+REG_MAC_LSB,data);
+ axi.ready_idle_state = 0;
+ repeat (16) begin
+ axi.wr(LANE_BASE+REG_MAC_LSB,++data);
+ end
+ repeat (4) axi.rd(LANE_BASE+REG_MAC_LSB,data);
+
+ if (MGT_PROTOCOL == `MGT_100GbE && !USE_MAC) begin
+ reg_link_up = 1;
+ end
+
+ port_info = {COMPAT_NUM, 6'h0, activity, reg_link_up, MGT_PROTOCOL, PORTNUM};
+ axi.rd(LANE_BASE+REG_PORT_INFO,port_info);
+ // status/ctrl isn't used yet
+ if (MGT_PROTOCOL == `MGT_100GbE) axi.rd(LANE_BASE+REG_MAC_CTRL_STATUS,0);
+ else if (MGT_PROTOCOL == `MGT_10GbE)
+ if (USE_MAC) axi.rd(LANE_BASE+REG_MAC_CTRL_STATUS,32'h0000_0000);
+ else axi.rd(LANE_BASE+REG_MAC_CTRL_STATUS,32'h0000_0080);
+ else assert(1);
+
+ axi.rd(LANE_BASE+REG_PHY_CTRL_STATUS,0);
+ // en 0 / value 1
+ axi.rd(LANE_BASE+REG_MAC_LED_CTL,0);
+ // enabled with value 0
+ axi.wr(LANE_BASE+REG_MAC_LED_CTL,1);
+ axi.rd(LANE_BASE+REG_MAC_LED_CTL,1);
+ activity = 0;
+ port_info = {COMPAT_NUM, 6'h0, activity, reg_link_up, MGT_PROTOCOL, PORTNUM};
+ axi.rd(LANE_BASE+REG_PORT_INFO,port_info);
+
+ // enabled with value 1
+ axi.wr(LANE_BASE+REG_MAC_LED_CTL,3);
+ axi.rd(LANE_BASE+REG_MAC_LED_CTL,3);
+ activity = 1;
+ port_info = {COMPAT_NUM, 6'h0, activity, reg_link_up, MGT_PROTOCOL, PORTNUM};
+ axi.rd(LANE_BASE+REG_PORT_INFO,port_info);
+
+ // enet controls led
+ axi.wr(LANE_BASE+REG_MAC_LED_CTL,0);
+ // unused registers with 100g
+ axi.rd(LANE_BASE+REG_AURORA_OVERRUNS,32'h0);
+ axi.rd(LANE_BASE+REG_CHECKSUM_ERRORS,32'h0);
+ axi.rd(LANE_BASE+REG_BIST_CHECKER_SAMPS,32'h0);
+ axi.rd(LANE_BASE+REG_BIST_CHECKER_ERRORS,32'h0);
+
+ // DEF_DEST_MAC/IP/UDP are defined in the
+ // sim_ethernet_lib.svh, as the destination
+ // addresses. Using the defaults means
+ // if I don't change the dest address on
+ // a packet it will go to the CHDR
+ axi.wr(LANE_BASE+REG_MAC_LSB,DEF_DEST_MAC_ADDR[31:0]);
+ axi.wr(LANE_BASE+REG_MAC_MSB,DEF_DEST_MAC_ADDR[47:32]);
+ axi.wr(LANE_BASE+REG_IP,DEF_DEST_IP_ADDR);
+ axi.wr(LANE_BASE+REG_UDP,DEF_DEST_UDP_PORT);
+ axi.wr(LANE_BASE+REG_BRIDGE_ENABLE,1);
+ axi.wr(LANE_BASE+REG_BRIDGE_MAC_LSB,DEF_BRIDGE_MAC_ADDR[31:0]);
+ axi.wr(LANE_BASE+REG_BRIDGE_MAC_MSB,DEF_BRIDGE_MAC_ADDR[47:32]);
+ axi.wr(LANE_BASE+REG_BRIDGE_IP,DEF_BRIDGE_IP_ADDR);
+ axi.wr(LANE_BASE+REG_BRIDGE_UDP,DEF_BRIDGE_UDP_PORT);
+ axi.wr(LANE_BASE+REG_BRIDGE_ENABLE,0);
+
+ // Readback the values
+ axi.rd(LANE_BASE+REG_MAC_LSB,DEF_DEST_MAC_ADDR[31:0]);
+ axi.rd(LANE_BASE+REG_MAC_MSB,DEF_DEST_MAC_ADDR[47:32]);
+ axi.rd(LANE_BASE+REG_IP,DEF_DEST_IP_ADDR);
+ axi.rd(LANE_BASE+REG_UDP,DEF_DEST_UDP_PORT);
+ axi.rd(LANE_BASE+REG_BRIDGE_ENABLE,0);
+ axi.rd(LANE_BASE+REG_BRIDGE_MAC_LSB,DEF_BRIDGE_MAC_ADDR[31:0]);
+ axi.rd(LANE_BASE+REG_BRIDGE_MAC_MSB,DEF_BRIDGE_MAC_ADDR[47:32]);
+ axi.rd(LANE_BASE+REG_BRIDGE_IP,DEF_BRIDGE_IP_ADDR);
+ axi.rd(LANE_BASE+REG_BRIDGE_UDP,DEF_BRIDGE_UDP_PORT);
+
+ // check the DMA controller
+ axi.rd(LANE_BASE+MM2S_DMACR, 32'h00010002);
+ // Hit reset bit, and poll for completion
+ axi.wr(LANE_BASE+MM2S_DMACR, 32'h4);
+ // Make sure reset asserts
+ axi.rd(LANE_BASE+MM2S_DMACR, 32'h00010006);
+ for (int i = 7; i >= 0; i--) begin
+ logic [31:0] readback;
+ logic [1:0] resp;
+ axi.rd_block(LANE_BASE+MM2S_DMACR, readback, resp);
+ if((readback & 32'h4) == 0) begin
+ // Reset bit cleared
+ break;
+ end
+ // Give up if it hasn't cleared after several tries
+ `ASSERT_ERROR(i != 0, "DMA controller reset failed to deassert.");
+ end
+
+ axi.block();
+ test.end_test();
+ endtask : test_registers
+
+ //---------------------------------------------------------------------------
+ // Ethernet to CPU test
+ //---------------------------------------------------------------------------
+ typedef ChdrData #(CHDR_W)::chdr_word_t chdr_word_t;
+ typedef chdr_word_t word_queue_t[$];
+
+ typedef XportStreamPacket #(ENET_W) EthXportPacket_t;
+ typedef AxiStreamPacket #(ENET_W,ENET_USER_W) EthAxisPacket_t;
+
+ typedef XportStreamPacket #(CPU_W) CpuXportPacket_t;
+ typedef AxiStreamPacket #(CPU_W,CPU_USER_W) CpuAxisPacket_t;
+
+ typedef XportStreamPacket #(CHDR_W) ChdrXportPacket_t;
+ typedef AxiStreamPacket #(CHDR_W,CHDR_USER_W) ChdrAxisPacket_t;
+ typedef ChdrPacket #(CHDR_W,CHDR_USER_W) ChdrPacket_t;
+
+ task automatic test_ethcpu(int num_samples[$], int ERROR_PROB=2, int EXPECT_DROPS=0);
+ fork
+ if (!DISABLED[0]) test_ethcpu_lane(0,num_samples,ERROR_PROB,EXPECT_DROPS);
+ if (!DISABLED[1]) test_ethcpu_lane(1,num_samples,ERROR_PROB,EXPECT_DROPS);
+ if (!DISABLED[2]) test_ethcpu_lane(2,num_samples,ERROR_PROB,EXPECT_DROPS);
+ if (!DISABLED[3]) test_ethcpu_lane(3,num_samples,ERROR_PROB,EXPECT_DROPS);
+ join
+ endtask : test_ethcpu
+
+ task automatic test_ethcpu_lane(int lane, int num_samples[$], int ERROR_PROB=2, int EXPECT_DROPS=0);
+ TestExec test_e2c = new();
+ automatic EthXportPacket_t send[$];
+ automatic CpuXportPacket_t expected[$];
+ automatic int sample_sum = 0;
+ string lane_str;
+ lane_str.itoa(lane);
+
+ test_e2c.start_test({TEST_NAME," ",lane_str," Ethernet to CPU"}, 60us*5);
+ // This path is
+ // eth_rx -> s_mac(eth_adapter) -> s_mac(eth_dispatch) ->
+ //// in_reg(AXI_FIFO)(SIZE=1)
+ // (eth_dispatch) in -> STATMACHINE (Dispatch) + cpu ->
+ //// out_reg_cpu(AXI_FIFO)(SIZE=1)
+ // (eth_dispatch) o_cpu ->
+ //// cpu_out_gate(AXI_GATE)(SIZE=11)
+ // (eth_dispatch) m_cpu -> (eth_adapter) e2c_chdr -> e2c_fifo
+ //// cpu_fifo(AXI_FIFO)(SIZE=CPU_FIFO_SIZE)
+ // (eth_adapater) m_cpu -> e2c
+
+ foreach (num_samples[i]) begin
+ automatic eth_hdr_t eth_hdr;
+ automatic ipv4_hdr_t ipv4_hdr;
+ automatic udp_hdr_t udp_hdr;
+ automatic raw_pkt_t pay,udp_raw;
+ automatic int PREAMBLE;
+
+ PREAMBLE = NO_PREAMBLE;
+
+ expected[i] = new;
+ send[i] = new;
+
+ udp_hdr.dest_port = 0; //change dest port from default so it goes to cpu
+ get_ramp_raw_pkt(.num_samps(num_samples[i]),.ramp_start((sample_sum)%256),
+ .ramp_inc(1),.pkt(pay),.SWIDTH(8));
+ sample_sum += num_samples[i];
+ udp_raw = build_udp_pkt(eth_hdr,ipv4_hdr,udp_hdr,pay,
+ .preamble(PREAMBLE));
+ send[i].push_bytes(udp_raw);
+ send[i].tkeep_to_tuser(.ERROR_PROB(ERROR_PROB));
+
+ // rebuild the expected packet for comparison without the preamble
+ udp_raw = build_udp_pkt(eth_hdr,ipv4_hdr,udp_hdr,pay,
+ .preamble(NO_PREAMBLE));
+ expected[i].push_bytes(udp_raw);
+ expected[i].tkeep_to_tuser();
+
+ end
+
+ // iterate in descending order so deleting doesn't shift down
+ // the packets in future loop iterations.
+ for (int i= num_samples.size()-1 ; i >= 0; i--) begin
+ // original only checks for errors in last word.
+ if (!SV_ETH_IFC && send[i].has_error()) send[i].set_error();
+
+ // If a packet has an error it shouldn't make it through
+ if (send[i].has_error()) expected.delete(i); // MAC ERROR
+
+ end
+
+ fork
+ begin // tx_thread
+ foreach(send[i])begin
+ #1 eth[lane].put(send[i]); // delay causes CPU/CHDR traffic on input to be interleaved.
+ end
+ end
+ begin //rx_thread
+ if (EXPECT_DROPS > 0) begin
+ automatic int pkt_num = 0;
+ automatic logic [31:0] data;
+ automatic resp_t resp;
+ automatic int drop_count = 0;
+ automatic int rcvd_count = 0;
+ automatic int drop_count_reg = 0;
+ while (expected.size() > 0) begin
+ automatic CpuAxisPacket_t actual_a;
+ automatic CpuXportPacket_t actual = new();
+ while (!cpu[lane].try_get(actual_a)) begin
+ axi.rd_block(REG_CPU_DROPPED,data,resp);
+ assert (resp==OKAY);
+ drop_count_reg += data;
+ // to account for case where we drop the last packet,
+ // stop looking if we have received or dropped all the packets
+ if (drop_count_reg+rcvd_count >= num_samples.size() && cpu[lane].slave_idle) begin
+ $display("Last packet dropped skipping to the end");
+ expected.delete();
+ drop_count = drop_count_reg;
+ // last packet may still be pending
+ #1us; // wait
+ void'(cpu[lane].try_get(actual_a));
+ break;
+ end
+ end
+ if (expected.size() > 0) begin
+ actual.import_axis(actual_a);
+ actual.tkeep_to_tuser();
+
+ while (expected.size > 0 && actual.compare_no_user(expected[0],.PRINT_LVL(0))) begin
+ void'(expected.pop_front());
+ ++drop_count;
+ ++pkt_num;
+ $display("Dropped packet %d",pkt_num);
+ `ASSERT_ERROR(drop_count < EXPECT_DROPS,"Exceeded anticipated number of dropped packets e2c");
+ end
+ end
+ // expected size could of changed in while loop above
+ if (expected.size() > 0) begin
+ ++pkt_num;
+ ++rcvd_count;
+ $display("Rcvd packet %d",pkt_num);
+ void'(expected.pop_front());
+ end
+ end
+ axi.rd_block(REG_CPU_DROPPED,data,resp);
+ assert (resp==OKAY);
+ drop_count_reg += data;
+ if (SV_ETH_IFC) begin
+ $display("Verify drop count is %d",drop_count_reg);
+ assert(drop_count_reg == drop_count) else $error("Drop count mismatch");
+ end
+ end else begin
+ foreach(expected[i]) begin
+ automatic CpuAxisPacket_t actual_a;
+ automatic CpuXportPacket_t actual = new();
+ cpu[lane].get(actual_a);
+ actual.import_axis(actual_a);
+ actual.tkeep_to_tuser();
+
+ `ASSERT_ERROR(!actual.compare_no_user(expected[i]),"failed to send packet to e2c");
+ end
+ end
+ end
+ join
+
+ test_e2c.end_test();
+ endtask : test_ethcpu_lane
+
+ task automatic wait_for_udp_packets(int lane, int udp_dest_port);
+ automatic EthAxisPacket_t actual_a;
+ automatic EthXportPacket_t actual = new();
+ automatic raw_pkt_t rcv_raw,rcv_pay;
+ automatic udp_hdr_t rcv_udp;
+ automatic eth_hdr_t rcv_eth;
+ automatic ipv4_hdr_t rcv_ip;
+ automatic int try_count = 0;
+ automatic int PREAMBLE;
+
+ PREAMBLE = NO_PREAMBLE;
+
+ do begin
+ ++try_count;
+ // check if packet is for our port
+ #100;
+ eth[lane].peek(actual_a);
+ actual.import_axis(actual_a);
+ actual.tuser_to_tkeep();
+ rcv_raw = actual.dump_bytes();
+ if (PREAMBLE == ZERO_PREAMBLE) begin
+ repeat(6) rcv_raw.delete(0); // strip preamble
+ end
+ decode_udp_pkt(rcv_raw,rcv_eth,rcv_ip,rcv_udp,rcv_pay);
+ `ASSERT_ERROR(try_count != 100,"unclaimed packet on c2e");
+ end while (rcv_udp.dest_port != udp_dest_port);
+
+ endtask : wait_for_udp_packets
+
+ task automatic test_cpueth(int num_samples[$]);
+ fork
+ if (!DISABLED[0]) test_cpueth_lane(0,num_samples);
+ if (!DISABLED[1]) test_cpueth_lane(1,num_samples);
+ if (!DISABLED[2]) test_cpueth_lane(2,num_samples);
+ if (!DISABLED[3]) test_cpueth_lane(3,num_samples);
+ join
+ endtask : test_cpueth
+
+ task automatic test_cpueth_lane(int lane, int num_samples[$]);
+ TestExec test_c2e = new();
+ automatic CpuXportPacket_t send[$];
+ automatic EthXportPacket_t expected[$];
+ automatic int sample_sum = 0;
+ string lane_str;
+ lane_str.itoa(lane);
+
+ test_c2e.start_test({TEST_NAME," ",lane_str," CPU to Ethernet"}, 60us*5);
+ // This path is
+ // c2e -> (eth_adapter) s_cpu ->
+ //// (ARM_DEFRAMER)(IF ARM)
+ // (eth_adapater) c2e ->
+ //// (ETH_MUX)(SIZE=2)
+ // (eth_adapater) m_mac -> eth_tx
+
+ foreach (num_samples[i]) begin
+ automatic eth_hdr_t eth_hdr;
+ automatic ipv4_hdr_t ipv4_hdr;
+ automatic udp_hdr_t udp_hdr;
+ automatic raw_pkt_t pay,udp_raw;
+ automatic int PREAMBLE;
+ PREAMBLE = NO_PREAMBLE;
+
+ expected[i] = new;
+ send[i] = new;
+
+ get_ramp_raw_pkt(.num_samps(num_samples[i]),.ramp_start((sample_sum)%256),
+ .ramp_inc(1),.pkt(pay),.SWIDTH(8));
+ sample_sum += num_samples[i];
+ udp_raw = build_udp_pkt(eth_hdr,ipv4_hdr,udp_hdr,pay,
+ .preamble(NO_PREAMBLE));
+ send[i].push_bytes(udp_raw);
+ send[i].tkeep_to_tuser();
+
+ // rebuild the expected packet for comparison with a zero preamble
+ udp_raw = build_udp_pkt(eth_hdr,ipv4_hdr,udp_hdr,pay,
+ .preamble(PREAMBLE));
+ //eth ifc expands pre CRC packets to 64 bytes on the C2E path
+ if (SV_ETH_IFC) begin
+ while (udp_raw.size < 64) begin
+ udp_raw.push_back(0);
+ end
+ end;
+
+ expected[i].push_bytes(udp_raw);
+ expected[i].tkeep_to_tuser();
+ end
+
+ fork
+ begin // tx_thread
+ foreach(send[i])begin
+ cpu[lane].put(send[i]);
+ end
+ end
+ begin //rx_thread
+ foreach(expected[i]) begin
+ automatic EthAxisPacket_t actual_a;
+ automatic EthXportPacket_t actual = new();
+ automatic raw_pkt_t rcv_raw,rcv_pay;
+ automatic udp_hdr_t rcv_udp;
+ automatic eth_hdr_t rcv_eth;
+ automatic ipv4_hdr_t rcv_ip;
+ automatic int try_count = 0;
+
+ wait_for_udp_packets(lane,DEF_DEST_UDP_PORT);
+ eth[lane].get(actual_a);
+ actual.import_axis(actual_a);
+ if (!SV_ETH_IFC) begin
+ actual.tuser_to_tkeep();
+ end
+ `ASSERT_ERROR(!actual.compare_w_pad(expected[i],!SV_ETH_IFC),"failed to send packet to c2e");
+ end
+ end
+ join
+ test_c2e.end_test();
+
+ endtask : test_cpueth_lane
+
+ //---------------------------------------------------------------------------
+ // Ethernet to CHDR test
+ //---------------------------------------------------------------------------
+
+ function automatic word_queue_t bytes_to_words(raw_pkt_t pay);
+ automatic ChdrXportPacket_t axis_pkt = new();
+
+ axis_pkt.push_bytes(pay);
+ return axis_pkt.data;
+
+ endfunction : bytes_to_words;
+
+ function automatic raw_pkt_t flatten_chdr(ChdrPacket_t chdr_pkt);
+ automatic ChdrAxisPacket_t axis_chdr;
+ automatic ChdrXportPacket_t xport_chdr = new();
+ axis_chdr = chdr_pkt.chdr_to_axis();
+ foreach (axis_chdr.data[i]) begin
+ axis_chdr.keep[i] = '1;
+ axis_chdr.user[i] = '0;
+ end
+ xport_chdr.import_axis(axis_chdr);
+ return xport_chdr.dump_bytes();
+ endfunction : flatten_chdr
+
+ function automatic ChdrPacket_t unflatten_chdr(raw_pkt_t chdr_raw);
+ automatic ChdrXportPacket_t xport_chdr = new();
+ automatic ChdrPacket_t chdr_pkt = new();
+ xport_chdr.push_bytes(chdr_raw);
+ foreach (xport_chdr.data[i]) begin
+ xport_chdr.keep[i] = '1;
+ xport_chdr.user[i] = '0;
+ end
+ chdr_pkt.axis_to_chdr(xport_chdr);
+ return chdr_pkt;
+ endfunction : unflatten_chdr
+
+ task automatic test_ethchdr(int num_samples[$], int ERROR_PROB=2, int EXPECT_DROPS=0);
+ fork
+ if (!DISABLED[0]) test_ethchdr_lane(0,num_samples,ERROR_PROB,EXPECT_DROPS);
+ if (!DISABLED[1]) test_ethchdr_lane(1,num_samples,ERROR_PROB,EXPECT_DROPS);
+ if (!DISABLED[2]) test_ethchdr_lane(2,num_samples,ERROR_PROB,EXPECT_DROPS);
+ if (!DISABLED[3]) test_ethchdr_lane(3,num_samples,ERROR_PROB,EXPECT_DROPS);
+ join
+ endtask : test_ethchdr;
+
+ task automatic test_ethchdr_lane(int lane, int num_samples[$], int ERROR_PROB=2, int EXPECT_DROPS=0);
+ TestExec test_e2v = new();
+ automatic EthXportPacket_t send[$];
+ automatic ChdrXportPacket_t expected[$];
+ automatic int sample_sum = 0;
+ string lane_str;
+ lane_str.itoa(lane);
+
+ test_e2v.start_test({TEST_NAME," ",lane_str," Ethernet to CHDR"}, 60us);
+ // This path is
+ // eth_rx -> s_mac(eth_adapter) -> s_mac(eth_dispatch) ->
+ //// in_reg(AXI_FIFO)(SIZE=1)
+ // (eth_dispatch) in -> STATMACHINE (Dispatch) + chdr ->
+ //// chdr_user_fifo(AXI_FIFO)(SIZE=8) (capture eth header)
+ //// chdr_out_gate(AXI_GATE)(SIZE=11)
+ // (eth_dispatch) o_chdr ->
+ //// chdr_trim(CHDR_TRIM_PAYLOAD)
+ // (eth_dispatch) m_chdr -> (eth_adapater) e2x_chdr -> (xport_adapter_gen) s_axis_xport
+ //// xport_in_swap (AXIS_DATA_SWAP)
+ // (xport_adapter_gen) i_xport ->
+ //// mgmt_ep(CHDR_MGMT_PKT_HANDLER)
+ // (xport_adapter_gen) x2d ->
+ //// rtn_demux(AXI_SWITCH) x2x(loopback) or m_axis_rfnoc
+ // (xport_adapter_gen) m_axis_rfnoc -> (eth_adapter) e2x_fifo
+ //// chdr_fifo(AXI_FIFO)(SIZE=MTU)
+ // (eth_adapater) m_chdr -> e2v
+
+ foreach (num_samples[i]) begin
+ automatic eth_hdr_t eth_hdr;
+ automatic ipv4_hdr_t ipv4_hdr;
+ automatic udp_hdr_t udp_hdr;
+ automatic raw_pkt_t pay,udp_raw,chdr_raw;
+
+ automatic ChdrPacket_t chdr_pkt = new();
+ automatic chdr_header_t chdr_hdr;
+ automatic chdr_word_t chdr_ts;
+ automatic chdr_word_t chdr_mdata[$];
+ automatic chdr_word_t chdr_data[$];
+
+ automatic int PREAMBLE;
+ PREAMBLE = NO_PREAMBLE;
+
+ expected[i] = new;
+ send[i] = new;
+
+ // build a payload
+ get_ramp_raw_pkt(.num_samps(num_samples[i]),.ramp_start((sample_sum)%256),
+ .ramp_inc(1),.pkt(pay),.SWIDTH(8));
+ sample_sum += num_samples[i];
+ // Fill data in the chdr packet
+ chdr_hdr = '{
+ vc : 0,
+ dst_epid : 0,
+ seq_num : 0,
+ pkt_type : CHDR_DATA_NO_TS,
+ num_mdata : 0,
+ default : 0
+ };
+ chdr_ts = 0; // no timestamp
+ chdr_mdata.delete(); // not adding meta data
+ chdr_data = bytes_to_words(pay);
+
+ chdr_pkt.write_raw(chdr_hdr, chdr_data, chdr_mdata, chdr_ts);
+ chdr_raw = flatten_chdr(chdr_pkt);
+
+ //build a udp packet
+ udp_raw = build_udp_pkt(eth_hdr,ipv4_hdr,udp_hdr,chdr_raw,
+ .preamble(PREAMBLE));
+ send[i].push_bytes(udp_raw);
+ send[i].tkeep_to_tuser(.ERROR_PROB(ERROR_PROB));
+
+ // expect just the chdr packet (UDP stripped)
+ expected[i].push_bytes(chdr_raw);
+ expected[i].tkeep_to_tuser();
+
+ end
+
+ // iterate in descending order so deleting doesn't shift down
+ // the packets in future loop iterations.
+ for (int i= num_samples.size()-1 ; i >= 0; i--) begin
+ // original only checks for errors in last word.
+ if (!SV_ETH_IFC && send[i].has_error()) send[i].set_error();
+ // If a packet has an error it shouldn't make it through
+ if (send[i].has_error()) expected.delete(i);//MAC ERROR
+ end
+
+ fork
+ begin // tx_thread
+ foreach(send[i])begin
+ #1 eth[lane].put(send[i]); // delay causes CPU/CHDR traffic on input to be interleaved.
+ end
+ end
+ begin //rx_thread
+ if (EXPECT_DROPS > 0) begin
+ automatic int pkt_num = 0;
+ automatic int drop_count = 0;
+ while (expected.size() > 0) begin
+ automatic ChdrAxisPacket_t actual_a;
+ automatic ChdrXportPacket_t actual = new();
+ v[lane].get(actual_a);
+ actual.import_axis(actual_a);
+ actual.tuser_to_tkeep();
+ while (expected.size > 0 && actual.compare_no_user(expected[0],.PRINT_LVL(0))) begin
+ void'(expected.pop_front());
+ ++drop_count;
+ ++pkt_num;
+ $display("Dropped packet %d",pkt_num);
+ `ASSERT_ERROR(drop_count < EXPECT_DROPS,"Exceeded anticipated number of dropped packets e2v");
+ end
+ if (expected.size() > 0) begin
+ ++pkt_num;
+ $display("Rcvd packet %d",pkt_num);
+ void'(expected.pop_front());
+ end
+ end
+ if (SV_ETH_IFC) begin
+ $display("Verify drop count is %d",drop_count);
+ axi.rd(REG_CHDR_DROPPED,drop_count);
+ end
+ end else begin
+ foreach(expected[i]) begin
+ automatic ChdrAxisPacket_t actual_a;
+ automatic ChdrXportPacket_t actual = new();
+ v[lane].get(actual_a);
+ actual.import_axis(actual_a);
+ actual.tuser_to_tkeep();
+ `ASSERT_ERROR(!actual.compare_no_user(expected[i]),"failed to send packet e2v");
+ end
+ end
+ end
+ join
+ test_e2v.end_test();
+
+ endtask : test_ethchdr_lane;
+
+
+ task automatic test_chdreth(int num_samples[$]);
+ fork
+ if (!DISABLED[0]) test_chdreth_lane(0,num_samples);
+ if (!DISABLED[1]) test_chdreth_lane(1,num_samples);
+ if (!DISABLED[2]) test_chdreth_lane(2,num_samples);
+ if (!DISABLED[3]) test_chdreth_lane(3,num_samples);
+ join
+ endtask : test_chdreth
+
+ task automatic test_chdreth_lane(int lane, int num_samples[$]);
+ TestExec test_v2e = new();
+ automatic ChdrXportPacket_t send[$];
+ automatic EthXportPacket_t expected[$];
+ automatic int sample_sum = 0;
+ string lane_str;
+ lane_str.itoa(lane);
+
+ test_v2e.start_test({TEST_NAME," ",lane_str," CHDR to Ethernet"}, 60us);
+ // This path is
+ // v2e -> s_chdr(eth_adapter) -> s_axis_rfnoc (xport_adapter_gen) ->
+ //// axi_demux_mgmt_filter (AXI_DEMUX) (IF ALLOW_DISC) (discards discovery packets)
+ // (xport_adapter_gen) f2m ->
+ //// rtn_mux(AXI_MUX) between x2x and f2m
+ // (xport_adapter_gen) m2x ->
+ //// data_fifo/lookup_fifo (AXI_FIFO_SHORT)
+ //// LOOKUP LOGIC (lookup_fifo,data_fifo,results)
+ // (xport_adapter_gen) o_xport ->
+ //// xport_out_swap (AXIS_DATA_SWAP)
+ // (xport_adapter_gen) m_axis_xport -> (eth_adapater) x2e_chdr ->
+ //// ENET_HDR_LOGIC (frame_state)
+ // (eth_adapater) frame -> (eth_adapater) x2e_framed
+ //// (ETH_MUX)(SIZE=2)
+ // (eth_adapater) m_mac -> eth_tx
+
+ foreach (num_samples[i]) begin
+ automatic eth_hdr_t eth_hdr;
+ automatic ipv4_hdr_t ipv4_hdr;
+ automatic udp_hdr_t udp_hdr;
+ automatic raw_pkt_t pay,udp_raw,chdr_raw;
+
+ automatic ChdrPacket_t chdr_pkt = new();
+ automatic chdr_header_t chdr_hdr;
+ automatic chdr_word_t chdr_ts;
+ automatic chdr_word_t chdr_mdata[$];
+ automatic chdr_word_t chdr_data[$];
+
+ automatic int PREAMBLE;
+ if (PROTOCOL0 == `MGT_100GbE) PREAMBLE = NO_PREAMBLE;
+ else PREAMBLE = NO_PREAMBLE;
+
+ // ModelSim should initialize the fields of ipv4_hdr to their default
+ // values, but for some reason it doesn't in this case. We add an
+ // initialization here to work around the bug for now.
+ ipv4_hdr = '{
+ header_length : 4'd5,
+ version : 4'd4,
+ dscp : 6'b0000_00,
+ ecn : 2'b00,
+ length : 16'hXXXX,
+ identification: 16'h462E,
+ rsv_zero : 1'b0,
+ dont_frag : 1'b1,
+ more_frag : 1'b0,
+ frag_offset : 16'd0,
+ time_to_live : 16'd64,
+ protocol : UDP,
+ checksum : 16'hXXXX,
+ src_ip : DEF_SRC_IP_ADDR,
+ dest_ip : DEF_DEST_IP_ADDR
+ };
+
+ expected[i] = new;
+ send[i] = new;
+
+ // build a payload
+ get_ramp_raw_pkt(.num_samps(num_samples[i]),.ramp_start((sample_sum)%256),
+ .ramp_inc(1),.pkt(pay),.SWIDTH(8));
+ sample_sum += num_samples[i];
+
+ // Fill data in the chdr packet
+ chdr_hdr = '{
+ vc : 0,
+ dst_epid : 0,
+ seq_num : 0,
+ pkt_type : CHDR_DATA_NO_TS,
+ num_mdata : 0,
+ default : 0
+ };
+ chdr_ts = 0; // no timestamp
+ chdr_mdata.delete(); // not adding meta data
+ chdr_data = bytes_to_words(pay);
+
+ chdr_pkt.write_raw(chdr_hdr, chdr_data, chdr_mdata, chdr_ts);
+ chdr_raw = flatten_chdr(chdr_pkt);
+
+ // send the raw chedar packet
+ send[i].push_bytes(chdr_raw);
+ send[i].tkeep_to_tuser();
+
+ //build a udp packet
+ // modify as the EthInterface does
+ udp_hdr.src_port = DEF_DEST_UDP_PORT;
+ udp_hdr.dest_port = 0; // Extract from router lookup results (Default)
+ udp_hdr.checksum = 0; // Checksum not calculated at this point
+ ipv4_hdr.src_ip = DEF_DEST_IP_ADDR;
+ ipv4_hdr.dest_ip = 0; // Extract from router lookup results (Default)
+ ipv4_hdr.dscp = 0; // hardcoded
+ ipv4_hdr.dont_frag = 1; // hardcoded
+ ipv4_hdr.identification = 0; // hardcoded
+ ipv4_hdr.time_to_live = 8'h10; //hardcoded
+ eth_hdr.src_mac = DEF_DEST_MAC_ADDR;
+ eth_hdr.dest_mac = 0; // Extract from router lookup results (Default)
+
+ udp_raw = build_udp_pkt(eth_hdr,ipv4_hdr,udp_hdr,chdr_raw,
+ .preamble(PREAMBLE));
+
+ // XGE mac autoexpands all packet to size 60 (pre CRC) to meet 64 byte min packet
+ if (AUTOEXPAND_TO_64) begin
+ while (udp_raw.size < 60) begin
+ udp_raw.push_back(0);
+ end
+ end;
+
+ // expect udp wrapped chdr
+ expected[i].push_bytes(udp_raw);
+ if (IGNORE_EXTRA_DATA) begin
+ expected[i].clear_user(); // expect all full words!
+ expected[i].tuser_to_tkeep();
+ end else begin
+ expected[i].tkeep_to_tuser();
+ end
+ end
+
+ fork
+ begin // tx_thread
+ foreach(send[i])begin
+ v[lane].put(send[i]);
+ end
+ end
+ begin //rx_thread
+ foreach(expected[i]) begin
+ automatic EthAxisPacket_t actual_a;
+ automatic EthXportPacket_t actual = new();
+ automatic eth_hdr_t eth_hdr;
+ automatic ipv4_hdr_t ipv4_hdr;
+ automatic udp_hdr_t udp_hdr;
+ automatic raw_pkt_t chdr_raw,actual_raw;
+ automatic ChdrPacket_t chdr_pkt;
+ automatic integer chdr_len;
+ automatic logic [7:0] trash;
+ localparam UDP_LEN = 8/*udp*/+20/*ipv4*/+14/*eth-no vlan*/;
+
+ wait_for_udp_packets(.lane(lane),.udp_dest_port(0));
+ eth[lane].get(actual_a);
+ actual.import_axis(actual_a);
+ // to get chdr_len
+ actual_raw = actual.dump_bytes();
+
+ repeat(PREAMBLE_BYTES) trash = actual_raw.pop_front();
+ decode_udp_pkt(actual_raw,eth_hdr,ipv4_hdr,udp_hdr,chdr_raw);
+ //chdr_pkt = unflatten_chdr(chdr_raw);
+ if (IGNORE_EXTRA_DATA) begin
+ for (int w=chdr_pkt.header.length+UDP_LEN;w <actual_raw.size();w++) begin
+ actual_raw[w] = '0;
+ end
+ repeat(PREAMBLE_BYTES) actual_raw.push_front(0);
+ actual.empty();
+ actual.push_bytes(actual_raw);
+ end
+ `ASSERT_ERROR(!actual.compare_w_error(expected[i]),"failed to send packet v2e");
+ end
+ end
+ join
+ test_v2e.end_test();
+
+ endtask : test_chdreth_lane
+
+
+ //----------------------------------------------------
+ //----------------------------------------------------
+ //----------------------------------------------------
+ // Main test loop
+ //----------------------------------------------------
+ //----------------------------------------------------
+ //----------------------------------------------------
+ initial begin : tb_main
+ automatic int num_samples[$];
+ automatic int cpu_num_samples[$];
+ automatic int ERROR_PROB;
+ localparam QUICK = 1;
+ localparam CHECK_PAUSE = 0;
+
+ // With QUANTA100/REFRESH200 I expected 50% slow down over
+ // 1024 ns 200*5.12 ns (a Quanta is 512 bit times, bit time=10 ps)
+ localparam PAUSE_QUANTA = 100;
+ localparam PAUSE_REFRESH = 200;
+
+ //allocate BFM's
+ eth = new[4];
+ v = new[4];
+ cpu = new[4];
+
+ //associate with virtual interfaces
+ eth[0] = new(.master(eth_rx[0]), .slave(eth_tx[0]));
+ eth[1] = new(.master(eth_rx[1]), .slave(eth_tx[1]));
+ eth[2] = new(.master(eth_rx[2]), .slave(eth_tx[2]));
+ eth[3] = new(.master(eth_rx[3]), .slave(eth_tx[3]));
+ v[0] = new(.master(v2e[0]), .slave(e2v[0]));
+ v[1] = new(.master(v2e[1]), .slave(e2v[1]));
+ v[2] = new(.master(v2e[2]), .slave(e2v[2]));
+ v[3] = new(.master(v2e[3]), .slave(e2v[3]));
+ cpu[0] = new(.master(c2e[0]), .slave(e2c[0]));
+ cpu[1] = new(.master(c2e[1]), .slave(e2c[1]));
+ cpu[2] = new(.master(c2e[2]), .slave(e2c[2]));
+ cpu[3] = new(.master(c2e[3]), .slave(e2c[3]));
+
+ test.start_test({TEST_NAME,"::Wait for Reset"}, 10us);
+
+ clk40_gen.reset();
+ clk100_gen.reset();
+ clk200_gen.reset();
+ if (!USE_MAC) userclk_gen.reset();
+ refclk_gen.reset();
+ // start tready high - MAC doesn't have a tready so we need model
+ // to always keep it's tready high
+ foreach(eth[lane])begin
+ if (!DISABLED[lane]) begin
+ eth[lane].slave_tready_init = 1;
+ eth[lane].run();
+ cpu[lane].run();
+ v[lane].run();
+ end
+ end
+ axi.run();
+ test_reset();
+
+ test.end_test();
+
+ foreach(eth[lane])begin
+ if (!DISABLED[lane]) begin
+ test_registers(lane);
+ end
+ end
+
+ if (USE_MAC) begin
+ automatic logic [31:0] data;
+ automatic resp_t resp;
+
+ // don't overflow/underflow the mac model
+ foreach(eth[lane])begin
+ if (!DISABLED[lane]) begin
+ eth[lane].set_master_stall_prob(0);
+ eth[lane].set_slave_stall_prob(0);
+ end
+ end
+ // bit errors need to be generated in a different
+ // way on the serial link. (Not Yet Implemented)
+ ERROR_PROB = 0;
+
+ // 10GBE INIT
+ foreach(eth[lane])begin
+ if (IS10GBE[lane]) begin
+ automatic int LANE_BASE = 32'h10000 * lane;
+
+ test.start_test({TEST_NAME,"::Wait for 10gbe MAC link_up"}, 150us);
+ axi.wr(LANE_BASE+REG_MAC_CTRL_STATUS,1); // turn on tx_enable
+ do begin
+ axi.rd_block(LANE_BASE+REG_PORT_INFO,data,resp);
+ assert (resp==OKAY);
+ end while (data[16] !== 1); //link_up
+ test.end_test();
+ test.start_test({TEST_NAME,"::Wait for 10gbe MODEL link_up"}, 150us);
+ // check that model link is up
+ do begin
+ @(posedge clk40);
+ end while (model_link_up[lane] !== 1);
+ test.end_test();
+ end
+ end
+
+ // 100GBE_INIT
+ if (PROTOCOL0 == `MGT_100GbE) begin
+ test.start_test({TEST_NAME,"::Wait for 100gbe phy_reset"}, 20us);
+ // check that the DUT phy is out of reset.
+ do begin
+ axi.rd_block(REG_PHY_CTRL_STATUS,data,resp);
+ assert (resp==OKAY);
+ end while (data[1:0] !== 0); //usr_tx_reset and usr_rx_reset
+
+ test.end_test();
+ test.start_test({TEST_NAME,"::Wait for 100gbe MODEL link_up"}, 150us);
+ // check that model link is up
+ do begin
+ @(posedge clk40);
+ end while (model_link_up[0] !== 1);
+ test.end_test();
+ test.start_test({TEST_NAME,"::Wait for 100gbe MAC link_up"}, 150us);
+ // Added Autoconnect which is on by default. uncomment to run manually
+ //Pkg100gbMac::init_mac(32'h4000,axi);
+ do begin
+ axi.rd_block(REG_PORT_INFO,data,resp);
+ assert (resp==OKAY);
+ end while (data[16] !== 1); //link_up
+
+ test.end_test();
+ test.start_test({TEST_NAME,"::Wait for auto config to complete"}, 10us);
+
+ // check that the MAC auto config completed.
+ do begin
+ axi.rd_block(REG_MAC_CTRL_STATUS,data,resp);
+ assert (resp==OKAY);
+ end while (data[4] !== 1); //auto config complete
+
+ data[0] = 1; // Autoconfig enable
+ data[24:16] = 9'h100; // pause mask (use global pause)
+ axi.wr(REG_MAC_CTRL_STATUS,data); // turn on tx_enable
+
+ data[15:0] = PAUSE_QUANTA;
+ data[31:16] = PAUSE_QUANTA;
+ axi.wr(REG_CONFIGURATION_TX_FLOW_CONTROL_QUANTA_REG1+0*4,data);
+ axi.wr(REG_CONFIGURATION_TX_FLOW_CONTROL_QUANTA_REG1+1*4,data);
+ axi.wr(REG_CONFIGURATION_TX_FLOW_CONTROL_QUANTA_REG1+2*4,data);
+ axi.wr(REG_CONFIGURATION_TX_FLOW_CONTROL_QUANTA_REG1+3*4,data);
+ data[15:0] = PAUSE_QUANTA;
+ data[31:16] = 0;
+ axi.wr(REG_CONFIGURATION_TX_FLOW_CONTROL_QUANTA_REG1+4*4,data);
+
+ data[15:0] = PAUSE_REFRESH;
+ data[31:16] = PAUSE_REFRESH;
+ axi.wr(REG_CONFIGURATION_TX_FLOW_CONTROL_REFRESH_REG1+0*4,data);
+ axi.wr(REG_CONFIGURATION_TX_FLOW_CONTROL_REFRESH_REG1+1*4,data);
+ axi.wr(REG_CONFIGURATION_TX_FLOW_CONTROL_REFRESH_REG1+2*4,data);
+ axi.wr(REG_CONFIGURATION_TX_FLOW_CONTROL_REFRESH_REG1+3*4,data);
+ data[15:0] = PAUSE_REFRESH;
+ data[31:16] = 0;
+ axi.wr(REG_CONFIGURATION_TX_FLOW_CONTROL_REFRESH_REG1+4*4,data);
+ data[15:0] = 64; // 64=4KBytes pause set
+ data[31:16] = 32; // 32=2KBytes pause clear
+ axi.wr(REG_PAUSE,data);
+ axi.block();
+
+ test.end_test();
+
+ end
+ end else begin
+ ERROR_PROB = 2;
+ end
+
+ //Checks that pausing is working.
+ if (CHECK_PAUSE) begin
+
+ // This test will take an excessive time when USE_MAC is true.
+
+ foreach(eth[lane])begin
+ if (!DISABLED[lane]) begin
+ eth[lane].set_master_stall_prob(0);
+ eth[lane].set_slave_stall_prob(0);
+ cpu[lane].set_master_stall_prob(0);
+ cpu[lane].set_slave_stall_prob(0);
+ v[lane].set_master_stall_prob(0);
+ v[lane].set_slave_stall_prob(0);
+ end
+ end
+ num_samples = {7936,7936,7936,7936,7936,320,
+ 7936,7936,320,320,320,320,
+ // 280 512 byte packets (to help back things up)
+ 512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,
+ 512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,
+ 512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,
+ 512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,
+ 512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,
+ 512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,
+ 512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,
+ 512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,
+ 512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,
+ 512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,
+ 7936,7936
+ };
+
+
+ test_ethchdr(num_samples,.EXPECT_DROPS(0),.ERROR_PROB(0));
+ // NOTE : The test ethcpu doesn't finish because the final packet doesn't
+ // make it through, and the algorithm doesn't time out.
+ num_samples = {7936,7936,7936,7936,7936,320,
+ 7936,7936,320,320,320,320};
+ test_ethcpu(num_samples,.EXPECT_DROPS(9),.ERROR_PROB(0));
+
+ end
+
+ foreach(eth[lane])begin
+ if (!DISABLED[lane]) begin
+ if (USE_MAC) begin
+ eth[lane].set_master_stall_prob(0);
+ eth[lane].set_slave_stall_prob(0);
+ cpu[lane].set_master_stall_prob(0);
+ cpu[lane].set_slave_stall_prob(0);
+ v[lane].set_master_stall_prob(0);
+ v[lane].set_slave_stall_prob(0);
+ end else begin
+ eth[lane].set_master_stall_prob(38);
+ eth[lane].set_slave_stall_prob(38);
+ cpu[lane].set_master_stall_prob(38);
+ cpu[lane].set_slave_stall_prob(38);
+ v[lane].set_master_stall_prob(38);
+ v[lane].set_slave_stall_prob(38);
+ end
+ end
+ end
+
+ num_samples = {1,2,3,4,5,6,7,8,
+ ENET_W/8-1,ENET_W/8,ENET_W/8+1,
+ 2*ENET_W/8-1,2*ENET_W/8,2*ENET_W/8+1,
+ CPU_W/8-1,CPU_W/8,CPU_W/8+1,
+ 2*CPU_W/8-1,2*CPU_W/8,2*CPU_W/8+1,
+ CHDR_W/8-1,CHDR_W/8,CHDR_W/8+1,
+ 2*CHDR_W/8-1,2*CHDR_W/8,2*CHDR_W/8+1
+ };
+ //Option to add some extra samples for CPU packets to try to get
+ //above the min packet size of 64. (just the headers makes up 42 bytes)
+ //Packets less than 64 bytes should be padded to 64
+ foreach (num_samples[i]) cpu_num_samples[i] = num_samples[i]+20;
+ test.start_test({TEST_NAME,"::PacketW Combos NO Errors"}, 10us*5);
+ fork // run in parallel
+ // ethrx
+ test_ethcpu(cpu_num_samples,.ERROR_PROB(0));
+ test_ethchdr(num_samples,.ERROR_PROB(0));
+ // ethtx
+ test_chdreth(num_samples);
+ test_cpueth(num_samples);
+ join
+ test.end_test();
+
+ if (!QUICK) begin
+
+ test.start_test({TEST_NAME,"::PacketW Combos Errors"}, 10us*5);
+ fork // run in parallel
+ // ethrx
+ test_ethcpu(cpu_num_samples,.ERROR_PROB(ERROR_PROB));
+ test_ethchdr(num_samples,.ERROR_PROB(ERROR_PROB));
+ // ethtx
+ test_chdreth(num_samples);
+ test_cpueth(num_samples);
+ join
+ test.end_test();
+
+ if (USE_MAC) begin
+ // don't do huge packets with real MAC to save time
+ num_samples = {16,32,64,128,256,512,1024,1500};
+ end else begin
+ num_samples = {16,32,64,128,256,512,1024,1500,1522,9000};
+ end
+ test.start_test({TEST_NAME,"::Pwr2 NoErrors"}, 60us*5);
+ fork // run in parallel
+ // ethrx
+ test_ethcpu(cpu_num_samples,.ERROR_PROB(0));
+ test_ethchdr(num_samples,.ERROR_PROB(0));
+ // ethtx
+ test_chdreth(num_samples);
+ test_cpueth(num_samples);
+ join
+ test.end_test();
+ end
+
+ num_samples = {1,2,3,4,5,6,7,8,
+ ENET_W/8-1,ENET_W/8,ENET_W/8+1,
+ 2*ENET_W/8-1,2*ENET_W/8,2*ENET_W/8+1,
+ CPU_W/8-1,CPU_W/8,CPU_W/8+1,
+ 2*CPU_W/8-1,2*CPU_W/8,2*CPU_W/8+1,
+ CHDR_W/8-1,CHDR_W/8,CHDR_W/8+1,
+ 2*CHDR_W/8-1,2*CHDR_W/8,2*CHDR_W/8+1
+ };
+ test.start_test({TEST_NAME,"::Pktw NoStall+Error"}, 10us*5);
+ fork // run in parallel
+ // ethrx
+ test_ethcpu(cpu_num_samples,.ERROR_PROB(ERROR_PROB));
+ test_ethchdr(num_samples,.ERROR_PROB(ERROR_PROB));
+ // ethtx
+ test_chdreth(num_samples);
+ test_cpueth(num_samples);
+ join
+ test.end_test();
+
+ // repeat with back to back cpu/chdr packets
+ test.start_test({TEST_NAME,"::Serial Pktw NoStall+Error"}, 10us*5);
+ fork // run in parallel
+ // ethrx
+ begin
+ test_ethcpu(cpu_num_samples,.ERROR_PROB(ERROR_PROB));
+ test_ethchdr(num_samples,.ERROR_PROB(ERROR_PROB));
+ end
+ // ethtx
+ begin
+ test_chdreth(num_samples);
+ test_cpueth(num_samples);
+ end
+ join
+ test.end_test();
+
+ // End the TB, but don't $finish, since we don't want to kill other
+ // instances of this testbench that may be running.
+ test.end_tb(0);
+
+ // Kill the clocks to end this instance of the testbench
+ clk40_gen.kill();
+ clk100_gen.kill();
+ clk200_gen.kill();
+ if (!USE_MAC) userclk_gen.kill();
+ refclk_gen.kill();
+ done = 1;
+
+ end // initial begin
+
+endmodule