diff options
Diffstat (limited to 'fpga/usrp3/top/n3xx/sim')
14 files changed, 3790 insertions, 0 deletions
diff --git a/fpga/usrp3/top/n3xx/sim/arm_to_sfp_loopback/Makefile b/fpga/usrp3/top/n3xx/sim/arm_to_sfp_loopback/Makefile new file mode 100644 index 000000000..1e783b2de --- /dev/null +++ b/fpga/usrp3/top/n3xx/sim/arm_to_sfp_loopback/Makefile @@ -0,0 +1,84 @@ +# +# Copyright 2015 Ettus Research LLC +# + +#------------------------------------------------- +# Top-of-Makefile +#------------------------------------------------- +# Define BASE_DIR to point to the "top" dir +BASE_DIR = $(abspath ../../..) +# Include viv_sim_preample after defining BASE_DIR +include $(BASE_DIR)/../tools/make/viv_sim_preamble.mak + +#------------------------------------------------- +# Design Specific +#------------------------------------------------- +# Define part using PART_ID (<device>/<package>/<speedgrade>) +ARCH = zynq +PART_ID = xc7z100/ffg900/-2 + +# Include makefiles and sources for the DUT and its dependencies +include $(BASE_DIR)/../lib/fifo/Makefile.srcs +include $(BASE_DIR)/../lib/axi/Makefile.srcs +include $(BASE_DIR)/../lib/control/Makefile.srcs +include $(BASE_DIR)/../lib/xge_interface/Makefile.srcs +include $(BASE_DIR)/../lib/xge/Makefile.srcs +include $(BASE_DIR)/../lib/packet_proc/Makefile.srcs + +DESIGN_SRCS = $(abspath \ +$(FIFO_SRCS) \ +$(AXI_SRCS) \ +$(CONTROL_LIB_SRCS) \ +) + +#------------------------------------------------- +# IP Specific +#------------------------------------------------- +# If simulation contains IP, define the IP_DIR and point +# it to the base level IP directory +IP_DIR = ../../ip + +# Include makefiles and sources for all IP components +# *after* defining the IP_DIR +include $(IP_DIR)/ten_gig_eth_pcs_pma/Makefile.inc +include $(IP_DIR)/axi64_8k_2clk_fifo/Makefile.inc +include $(IP_DIR)/axi64_4k_2clk_fifo/Makefile.inc + +DESIGN_SRCS += $(abspath \ +$(XGE_SRCS) \ +$(XGE_INTERFACE_SRCS) \ +$(IP_TEN_GIG_ETH_PCS_PMA_SRCS) \ +$(IP_TEN_GIGE_PHY_XCI_SRCS) \ +$(TEN_GIGE_PHY_SRCS) \ +$(IP_AXI64_8K_2CLK_FIFO_SRCS) \ +$(IP_AXI64_4K_2CLK_FIFO_SRCS) \ +$(PACKET_PROC_SRCS) \ +) +#$(IP_FIFO_SHORT_2CLK_SRCS) \ + + +#------------------------------------------------- +# Testbench Specific +#------------------------------------------------- +#include $(BASE_DIR)/../sim/general/Makefile.srcs +#include $(BASE_DIR)/../sim/control/Makefile.srcs +#include $(BASE_DIR)/../sim/axi/Makefile.srcs + +# Define only one toplevel module +SIM_TOP = arm_to_sfp_tb +# Simulation runtime in microseconds +SIM_RUNTIME_US = 30000 + +SIM_SRCS = \ +$(abspath arm_to_sfp_tb.sv) \ +$(SIM_GENERAL_SRCS) \ +$(SIM_CONTROL_SRCS) \ +$(SIM_AXI_SRCS) + +#------------------------------------------------- +# 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/n3xx/sim/arm_to_sfp_loopback/arm_to_sfp_tb.sv b/fpga/usrp3/top/n3xx/sim/arm_to_sfp_loopback/arm_to_sfp_tb.sv new file mode 100644 index 000000000..46005a13a --- /dev/null +++ b/fpga/usrp3/top/n3xx/sim/arm_to_sfp_loopback/arm_to_sfp_tb.sv @@ -0,0 +1,528 @@ +// +// Copyright 2017 Ettus Research +// + + +`timescale 1ns/1ps +`define NS_PER_TICK 1 +`define NUM_TEST_CASES 13 + +`include "sim_clks_rsts.vh" +`include "sim_exec_report.vh" +`include "sim_cvita_lib.svh" +`include "sim_axis_lib.svh" +`include "sim_axi4_lib.svh" +`include "sim_set_rb_lib.svh" + +module arm_to_sfp_tb(); + `TEST_BENCH_INIT("arm_to_sfp_tb",`NUM_TEST_CASES,`NS_PER_TICK) + + // Define all clocks and resets + `DEFINE_CLK(XG_CLK_P, 1000/156.25, 50) //156.25MHz GT transceiver clock + `DEFINE_RESET(GSR, 0, 100) //100ns for GSR to deassert + + wire XG_CLK_N = ~XG_CLK_P; + wire SFP_LN0_P, SFP_LN0_N, SFP_LN1_P, SFP_LN1_N; + + //localparam PACKET_MODE = 0; + localparam PORTNUM = 8'd0; + + // ARM to SFP Loopback Topology: + // + // TB Simulus ====> |------------| |----------------| + // | XgigE MAC | <===> | XgigE PCS/PMA | <====>|| + // TB Checker <==== |------------| |----------------| || Loopback through + // || + // ====> |------------| |----------------| || perfect serial channel + // Loopback | | XgigE MAC | <===> | XgigE PCS/PMA | <====>|| + // <==== |------------| |----------------| + + // Initialize DUT + wire xgige_refclk, xgige_clk156, xgige_dclk; + wire m_user_clk, s_user_clk; + wire m_channel_up, s_channel_up; + + wire [63:0] m_xgmii_txd; + wire [7:0] m_xgmii_txc; + wire [63:0] m_xgmii_rxd; + wire [7:0] m_xgmii_rxc; + wire [63:0] s_xgmii_txd; + wire [7:0] s_xgmii_txc; + wire [63:0] s_xgmii_rxd; + wire [7:0] s_xgmii_rxc; + wire [7:0] m_xgmii_status; + wire [7:0] s_xgmii_status; + wire m_xge_phy_resetdone; + wire s_xge_phy_resetdone; + wire m_mdc, m_mdio_in, m_mdio_out; + wire s_mdc, s_mdio_in, s_mdio_out; + wire sfpp_rxlos,sfpp_tx_fault,sfpp_tx_disable; + + + wire [15:0] m_phy_status; + wire [15:0] s_phy_status; + wire [63:0] loop_tdata; + wire [3:0] loop_tuser; + wire loop_tlast, loop_tvalid, loop_tready; + + wire [7:0] wb_adr_i; + wire wb_cyc_i; + wire [31:0] wb_dat_i; + wire wb_stb_i; + wire wb_we_i; + wire wb_ack_o; + wire [31:0] wb_dat_o; + wire wb_int_o; + wire [63:0] c2e_tdata_int; + wire [3:0] c2e_tuser_int; + wire c2e_tlast_int; + wire c2e_tvalid_int; + wire c2e_tready_int; + wire [63:0] c2e_tdata; + wire [3:0] c2e_tuser; + wire c2e_tlast; + wire c2e_tvalid; + wire c2e_tready; + wire m_axis_tvalid; + wire m_axis_tlast; + wire [63:0] m_axis_tdata; + wire m_axis_tready; + wire [3:0] m_axis_tuser; + + reg independent_clock; + assign m_channel_up = m_phy_status[0]; + assign s_channel_up = s_phy_status[0]; + //assign m_user_clk = xgige_refclk; + //assign s_user_clk = xgige_refclk; + assign m_user_clk = independent_clock; + assign s_user_clk = independent_clock; + + ten_gige_phy_clk_gen xgige_clk_gen_i ( + .areset(GSR), + .refclk_p(XG_CLK_P), + .refclk_n(XG_CLK_N), + .refclk(xgige_refclk), + .clk156(xgige_clk156), + .dclk(xgige_dclk) + ); + + axis_master #(.DWIDTH(34)) m_axis (.clk(m_user_clk)); + axis_slave #(.DWIDTH(68)) s_axis (.clk(s_user_clk)); + + initial + begin + independent_clock <= 1'b0; + forever + begin + independent_clock <= 1'b0; + #2.5; + independent_clock <= 1'b1; + #2.5; + end + end + + assign sfpp_rxlos = 1'b0; + assign sfpp_tx_fault = 1'b0; + + // Instantiate the 10GBASER/KR GT Common block + ten_gig_eth_pcs_pma_gt_common # ( + .WRAPPER_SIM_GTRESET_SPEEDUP("TRUE") ) //Does not affect hardware + ten_gig_eth_pcs_pma_gt_common_block + ( + .refclk(xgige_refclk), + .qpllreset(qpllreset), + .qplllock(qplllock), + .qplloutclk(qplloutclk), + .qplloutrefclk(qplloutrefclk), + .qpllrefclksel(3'b001 /*3'b101*GTSOUTHREFCLK0*/) + ); + + ten_gige_phy ten_gige_phy_master_i + ( + // Clocks and Reset + .areset(GSR), // Asynchronous reset for entire core. + .refclk(xgige_refclk), // Transciever reference clock: 156.25MHz + .clk156(xgige_clk156), // Globally buffered core clock: 156.25MHz + .dclk(xgige_dclk), // Management/DRP clock: 78.125MHz + .sim_speedup_control(~GSR), + // GMII Interface (client MAC <=> PCS) + .xgmii_txd(m_xgmii_txd), // Transmit data from client MAC. + .xgmii_txc(m_xgmii_txc), // Transmit control signal from client MAC. + .xgmii_rxd(m_xgmii_rxd), // Received Data to client MAC. + .xgmii_rxc(m_xgmii_rxc), // Received control signal to client MAC. + // Tranceiver Interface + .txp(SFP_LN0_P), // Differential +ve of serial transmission from PMA to PMD. + .txn(SFP_LN0_N), // Differential -ve of serial transmission from PMA to PMD. + .rxp(SFP_LN1_P), // Differential +ve for serial reception from PMD to PMA. + .rxn(SFP_LN1_N), // Differential -ve for serial reception from PMD to PMA. + // Management: MDIO Interface + .mdc(m_mdc), // Management Data Clock + .mdio_in(m_mdio_in), // Management Data In + .mdio_out(m_mdio_out), // Management Data Out + .mdio_tri(), // Management Data Tristate + .prtad(5'd4), // MDIO address is 4 + // General IO's + .core_status(m_xgmii_status), // Core status + .resetdone(m_xge_phy_resetdone), + .signal_detect(~sfpp_rxlos), //FIXME // Input from PMD to indicate presence of optical input. (Undocumented, but it seems Xilinx expect this to be inverted.) + .tx_fault(sfpp_tx_fault), //FIXME + .tx_disable(/*sfpp_tx_disable*/), //FIXME + .qpllreset(qpllreset1), + .qplllock(qplllock), + .qplloutclk(qplloutclk), + .qplloutrefclk(qplloutrefclk) + + ); + + n310_xge_mac_wrapper #(.PORTNUM(PORTNUM)) xge_mac_wrapper_master_i + ( + // XGMII + .xgmii_clk(xgige_clk156), + .xgmii_txd(m_xgmii_txd), + .xgmii_txc(m_xgmii_txc), + .xgmii_rxd(m_xgmii_rxd), + .xgmii_rxc(m_xgmii_rxc), + // Client FIFO Interfaces + .sys_clk(m_user_clk), + .sys_rst(GSR), + .rx_tdata(s_axis.axis.tdata[63:0]), + .rx_tuser(s_axis.axis.tdata[67:64]), + .rx_tlast(s_axis.axis.tlast), + .rx_tvalid(s_axis.axis.tvalid), + .rx_tready(/*s_axis.axis.tready*/1'b1), + .tx_tdata(c2e_tdata), + .tx_tuser(c2e_tuser), // Bit[3] (error) is ignored for now. + .tx_tlast(c2e_tlast), + .tx_tvalid(c2e_tvalid), + .tx_tready(c2e_tready), + // Other + .phy_ready(m_xge_phy_resetdone), + .ctrl_tx_enable (/*mac_ctrl_reg[0]*/1'b1), //FIXME: Remove hardcoded value + .status_crc_error (), + .status_fragment_error (), + .status_txdfifo_ovflow (), + .status_txdfifo_udflow (), + .status_rxdfifo_ovflow (), + .status_rxdfifo_udflow (), + .status_pause_frame_rx (), + .status_local_fault (), + .status_remote_fault () + ); + + assign m_phy_status = {8'h00, m_xgmii_status}; + + axi_fifo32_to_fifo64 inst_axi_fifo32_to_fifo64 + ( + .clk(m_user_clk), + .reset(GSR), + .i_tdata({m_axis.axis.tdata[31:0]}), // endian swap + .i_tuser(m_axis.axis.tdata[33:32]), + .i_tlast(m_axis.axis.tlast), + .i_tvalid(m_axis.axis.tvalid), + .i_tready(m_axis.axis.tready), + .o_tdata(m_axis_tdata), + .o_tuser(m_axis_tuser), + .o_tlast(m_axis_tlast), + .o_tvalid(m_axis_tvalid), + .o_tready(m_axis_tready) + ); + + arm_framer inst_arm_framer ( + .clk (m_user_clk), + .reset (GSR), + .clear (clear), + .s_axis_tdata (m_axis_tdata), + .s_axis_tuser (m_axis_tuser), + .s_axis_tlast (m_axis_tlast), + .s_axis_tvalid (m_axis_tvalid), + .s_axis_tready (m_axis_tready), + .m_axis_tdata (c2e_tdata_int), + .m_axis_tuser (c2e_tuser_int), + .m_axis_tlast (c2e_tlast_int), + .m_axis_tvalid (c2e_tvalid_int), + .m_axis_tready (c2e_tready_int) + ); + + axi_mux4 #(.PRIO(0), .WIDTH(68)) eth_mux + (.clk(m_user_clk), .reset(GSR), .clear(clear), + .i0_tdata({c2e_tuser_int,c2e_tdata_int}), .i0_tlast(c2e_tlast_int), .i0_tvalid(c2e_tvalid_int), .i0_tready(c2e_tready_int), + .i1_tdata(), .i1_tlast(), .i1_tvalid(), .i1_tready(), + .i2_tdata(), .i2_tlast(), .i2_tvalid(), .i2_tready(), + .i3_tdata(), .i3_tlast(), .i3_tvalid(1'b0), .i3_tready(), + .o_tdata({c2e_tuser,c2e_tdata}), .o_tlast(c2e_tlast), .o_tvalid(c2e_tvalid), .o_tready(c2e_tready)); + + ten_gige_phy ten_gige_phy_slave_i + ( + // Clocks and Reset + .areset(GSR), // Asynchronous reset for entire core. + .refclk(xgige_refclk), // Transciever reference clock: 156.25MHz + .clk156(xgige_clk156), // Globally buffered core clock: 156.25MHz + .dclk(xgige_dclk), // Management/DRP clock: 78.125MHz + .sim_speedup_control(~GSR), + // GMII Interface (client MAC <=> PCS) + .xgmii_txd(s_xgmii_txd), // Transmit data from client MAC. + .xgmii_txc(s_xgmii_txc), // Transmit control signal from client MAC. + .xgmii_rxd(s_xgmii_rxd), // Received Data to client MAC. + .xgmii_rxc(s_xgmii_rxc), // Received control signal to client MAC. + // Tranceiver Interface + .txp(SFP_LN1_P), // Differential +ve of serial transmission from PMA to PMD. + .txn(SFP_LN1_N), // Differential -ve of serial transmission from PMA to PMD. + .rxp(SFP_LN0_P), // Differential +ve for serial reception from PMD to PMA. + .rxn(SFP_LN0_N), // Differential -ve for serial reception from PMD to PMA. + // Management: MDIO Interface + .mdc(s_mdc), // Management Data Clock + .mdio_in(s_mdio_in), // Management Data In + .mdio_out(s_mdio_out), // Management Data Out + .mdio_tri(), // Management Data Tristate + .prtad(5'd4), // MDIO address is 4 + // General IO's + .core_status(s_xgmii_status), // Core status + .resetdone(s_xge_phy_resetdone), + .signal_detect(~sfpp_rxlos), //FIXME // Input from PMD to indicate presence of optical input. (Undocumented, but it seems Xilinx expect this to be inverted.) + .tx_fault(sfpp_tx_fault), //FIXME + .tx_disable(/*sfpp_tx_disable*/), //FIXME + .qpllreset(qpllreset2), + .qplllock(qplllock), + .qplloutclk(qplloutclk), + .qplloutrefclk(qplloutrefclk) + ); + + n310_xge_mac_wrapper #(.PORTNUM(PORTNUM)) xge_mac_wrapper_slave_i + ( + // XGMII + .xgmii_clk(xgige_clk156), + .xgmii_txd(s_xgmii_txd), + .xgmii_txc(s_xgmii_txc), + .xgmii_rxd(s_xgmii_rxd), + .xgmii_rxc(s_xgmii_rxc), + // Client FIFO Interfaces + .sys_clk(s_user_clk), + .sys_rst(GSR), + .rx_tdata(loop_tdata), + .rx_tuser(loop_tuser), + .rx_tlast(loop_tlast), + .rx_tvalid(loop_tvalid), + .rx_tready(loop_tready), + .tx_tdata(loop_tdata), + .tx_tuser(loop_tuser), // Bit[3] (error) is ignored for now. + .tx_tlast(loop_tlast), + .tx_tvalid(loop_tvalid), + .tx_tready(loop_tready), + // Other + .phy_ready(s_xge_phy_resetdone), + .ctrl_tx_enable (/*mac_ctrl_reg[0]*/1'b1), //FIXME: Remove hardcoded value + .status_crc_error (), + .status_fragment_error (), + .status_txdfifo_ovflow (), + .status_txdfifo_udflow (), + .status_rxdfifo_ovflow (), + .status_rxdfifo_udflow (), + .status_pause_frame_rx (), + .status_local_fault (), + .status_remote_fault () + ); + + assign s_phy_status = {8'h00, s_xgmii_status}; + + //Testbench variables + cvita_hdr_t header, header_out; + cvita_stats_t stats; + logic [63:0] crc_cache; + + //------------------------------------------ + //Main thread for testbench execution + //------------------------------------------ + initial begin : tb_main + `TEST_CASE_START("Wait for reset"); + m_axis.reset; + while (GSR) @(posedge XG_CLK_P); + `TEST_CASE_DONE((~GSR)); + + m_axis.push_bubble(); + + `TEST_CASE_START("Wait for master channel to come up"); + while (m_channel_up !== 1'b1) @(posedge m_user_clk); + `TEST_CASE_DONE(1'b1); + + `TEST_CASE_START("Wait for slave channel to come up"); + while (s_channel_up !== 1'b1) @(posedge s_user_clk); + `TEST_CASE_DONE(1'b1); + + repeat(2000) @(posedge m_user_clk); + + //`TEST_CASE_START("Test Ethernet packet"); + // s_axis.axis.tready = 0; + // m_axis.push_word({4'b0, 64'h0000_0000_0000_ffff}, 1'b0); + // s_axis.axis.tready = 1; + // m_axis.push_word({4'b0, 64'hffff_ffff_ce20_ad1b}, 1'b0); + // m_axis.push_word({4'b0, 64'hc57a_0806_0001_0800}, 1'b0); + // m_axis.push_word({4'b0, 64'h0604_0001_ce20_ad1b}, 1'b0); + // m_axis.push_word({4'b0, 64'hc57a_c0a8_0a64_0000}, 1'b0); + // m_axis.push_word({4'b0, 64'h0000_0000_c0a8_0a0a}, 1'b1); + //`TEST_CASE_DONE(1'b1); + //`TEST_CASE_START("Test Ethernet packet"); + // s_axis.axis.tready = 0; + // m_axis.push_word({4'b0, 64'hffff_ffff_ffff_ce20}, 1'b0); + // s_axis.axis.tready = 1; + // m_axis.push_word({4'b0, 64'had1b_c57a_0806_0001}, 1'b0); + // m_axis.push_word({4'b0, 64'h0800_0604_0001_ce20}, 1'b0); + // m_axis.push_word({4'b0, 64'had1b_c57a_c0a8_0a64}, 1'b0); + // m_axis.push_word({4'b0, 64'h0000_0000_0000_c0a8}, 1'b0); + // m_axis.push_word({4'd2, 64'h0a0a_1111_1111_1111}, 1'b1); + //`TEST_CASE_DONE(1'b1); + // repeat(2000) @(posedge m_user_clk); + `TEST_CASE_START("Test Ethernet packet"); + s_axis.axis.tready = 0; + m_axis.push_word({2'b0, 32'hffff_ffff}, 1'b0); + s_axis.axis.tready = 1; + m_axis.push_word({2'b0, 32'hffff_9aa9}, 1'b0); + m_axis.push_word({2'b0, 32'h6400_e341}, 1'b0); + m_axis.push_word({2'b0, 32'h0800_4500}, 1'b0); + m_axis.push_word({2'b0, 32'h0148_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_4011}, 1'b0); + m_axis.push_word({2'b0, 32'h79a6_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_ffff}, 1'b0); + m_axis.push_word({2'b0, 32'hffff_0044}, 1'b0); + m_axis.push_word({2'b0, 32'h0043_0134}, 1'b0); + m_axis.push_word({2'b0, 32'h90be_0101}, 1'b0); + m_axis.push_word({2'b0, 32'h0600_d2ab}, 1'b0); + m_axis.push_word({2'b0, 32'h9f01_0007}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_9aa9}, 1'b0); + m_axis.push_word({2'b0, 32'h6400_e341}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_6382}, 1'b0); + m_axis.push_word({2'b0, 32'h5363_3501}, 1'b0); + m_axis.push_word({2'b0, 32'h013d_0701}, 1'b0); + m_axis.push_word({2'b0, 32'h9aa9_6400}, 1'b0); + m_axis.push_word({2'b0, 32'he341_3902}, 1'b0); + m_axis.push_word({2'b0, 32'h0240_3707}, 1'b0); + m_axis.push_word({2'b0, 32'h0103_060c}, 1'b0); + m_axis.push_word({2'b0, 32'h0f1c_2a3c}, 1'b0); + m_axis.push_word({2'b0, 32'h0c75_6468}, 1'b0); + m_axis.push_word({2'b0, 32'h6370_2031}, 1'b0); + m_axis.push_word({2'b0, 32'h2e32_342e}, 1'b0); + m_axis.push_word({2'b0, 32'h31ff_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'b0, 32'h0000_0000}, 1'b0); + m_axis.push_word({2'd2, 32'h0000_0000}, 1'b1); + + `TEST_CASE_DONE(1'b1); + + repeat(2000) @(posedge m_user_clk); + + `TEST_CASE_START("Test Ethernet packet"); + s_axis.axis.tready = 0; + m_axis.push_word({2'b0, 32'h01005e7f }, 1'b0); + s_axis.axis.tready = 1; + m_axis.push_word({2'b0, 32'hfffa90e2 }, 1'b0); + m_axis.push_word({2'b0, 32'hba3aa7e8 }, 1'b0); + m_axis.push_word({2'b0, 32'h08004500 }, 1'b0); + m_axis.push_word({2'b0, 32'h00c7515e }, 1'b0); + m_axis.push_word({2'b0, 32'h40000111 }, 1'b0); + m_axis.push_word({2'b0, 32'h6d1bc0a8 }, 1'b0); + m_axis.push_word({2'b0, 32'h0a0aefff }, 1'b0); + m_axis.push_word({2'b0, 32'hfffad40f }, 1'b0); + m_axis.push_word({2'b0, 32'h076c00b3 }, 1'b0); + m_axis.push_word({2'b0, 32'hbb714d2d }, 1'b0); + m_axis.push_word({2'b0, 32'h53454152 }, 1'b0); + m_axis.push_word({2'b0, 32'h4348202a }, 1'b0); + m_axis.push_word({2'b0, 32'h20485454 }, 1'b0); + m_axis.push_word({2'b0, 32'h502f312e }, 1'b0); + m_axis.push_word({2'b0, 32'h310d0a48 }, 1'b0); + m_axis.push_word({2'b0, 32'h4f53543a }, 1'b0); + m_axis.push_word({2'b0, 32'h20323339 }, 1'b0); + m_axis.push_word({2'b0, 32'h2e323535 }, 1'b0); + m_axis.push_word({2'b0, 32'h2e323535 }, 1'b0); + m_axis.push_word({2'b0, 32'h2e323530 }, 1'b0); + m_axis.push_word({2'b0, 32'h3a313930 }, 1'b0); + m_axis.push_word({2'b0, 32'h300d0a4d }, 1'b0); + m_axis.push_word({2'b0, 32'h414e3a20 }, 1'b0); + m_axis.push_word({2'b0, 32'h22737364 }, 1'b0); + m_axis.push_word({2'b0, 32'h703a6469 }, 1'b0); + m_axis.push_word({2'b0, 32'h73636f76 }, 1'b0); + m_axis.push_word({2'b0, 32'h6572220d }, 1'b0); + m_axis.push_word({2'b0, 32'h0a4d583a }, 1'b0); + m_axis.push_word({2'b0, 32'h20310d0a }, 1'b0); + m_axis.push_word({2'b0, 32'h53543a20 }, 1'b0); + m_axis.push_word({2'b0, 32'h75726e3a }, 1'b0); + m_axis.push_word({2'b0, 32'h6469616c }, 1'b0); + m_axis.push_word({2'b0, 32'h2d6d756c }, 1'b0); + m_axis.push_word({2'b0, 32'h74697363 }, 1'b0); + m_axis.push_word({2'b0, 32'h7265656e }, 1'b0); + m_axis.push_word({2'b0, 32'h2d6f7267 }, 1'b0); + m_axis.push_word({2'b0, 32'h3a736572 }, 1'b0); + m_axis.push_word({2'b0, 32'h76696365 }, 1'b0); + m_axis.push_word({2'b0, 32'h3a646961 }, 1'b0); + m_axis.push_word({2'b0, 32'h6c3a310d }, 1'b0); + m_axis.push_word({2'b0, 32'h0a555345 }, 1'b0); + m_axis.push_word({2'b0, 32'h522d4147 }, 1'b0); + m_axis.push_word({2'b0, 32'h454e543a }, 1'b0); + m_axis.push_word({2'b0, 32'h20476f6f }, 1'b0); + m_axis.push_word({2'b0, 32'h676c6520 }, 1'b0); + m_axis.push_word({2'b0, 32'h4368726f }, 1'b0); + m_axis.push_word({2'b0, 32'h6d652f35 }, 1'b0); + m_axis.push_word({2'b0, 32'h342e302e }, 1'b0); + m_axis.push_word({2'b0, 32'h32383430 }, 1'b0); + m_axis.push_word({2'b0, 32'h2e353920 }, 1'b0); + m_axis.push_word({2'b0, 32'h4c696e75 }, 1'b0); + m_axis.push_word({2'b1, 32'h78111111 }, 1'b1); + + `TEST_CASE_DONE(1'b1); + end + +endmodule diff --git a/fpga/usrp3/top/n3xx/sim/aurora_loopback/Makefile b/fpga/usrp3/top/n3xx/sim/aurora_loopback/Makefile new file mode 100644 index 000000000..c4cdf38dd --- /dev/null +++ b/fpga/usrp3/top/n3xx/sim/aurora_loopback/Makefile @@ -0,0 +1,80 @@ +# +# Copyright 2015 Ettus Research LLC +# + +#------------------------------------------------- +# Top-of-Makefile +#------------------------------------------------- +# Define BASE_DIR to point to the "top" dir +BASE_DIR = $(abspath ../../..) +# Include viv_sim_preample after defining BASE_DIR +include $(BASE_DIR)/../tools/make/viv_sim_preamble.mak + +#------------------------------------------------- +# Design Specific +#------------------------------------------------- +# Define part using PART_ID (<device>/<package>/<speedgrade>) +ARCH = zynq +PART_ID = xc7z100/ffg900/-2 + +# Include makefiles and sources for the DUT and its dependencies +include $(BASE_DIR)/../lib/fifo/Makefile.srcs +include $(BASE_DIR)/../lib/axi/Makefile.srcs +include $(BASE_DIR)/../lib/control/Makefile.srcs +include $(BASE_DIR)/../lib/rfnoc/Makefile.srcs + +DESIGN_SRCS = $(abspath \ +$(FIFO_SRCS) \ +$(AXI_SRCS) \ +$(CONTROL_LIB_SRCS) \ +$(RFNOC_SRCS) \ +../../n3xx_npio_qsfp_wrapper.v \ +../../n3xx_mgt_io_core.v \ +) + +#------------------------------------------------- +# IP Specific +#------------------------------------------------- +# If simulation contains IP, define the IP_DIR and point +# it to the base level IP directory +IP_DIR = ../../ip + +# Include makefiles and sources for all IP components +# *after* defining the IP_DIR +include $(IP_DIR)/aurora_64b66b_pcs_pma/Makefile.inc +include $(IP_DIR)/fifo_short_2clk/Makefile.inc +include $(IP_DIR)/axi64_4k_2clk_fifo/Makefile.inc + +DESIGN_SRCS += $(abspath \ +$(IP_AURORA_64B66B_PCS_PMA_SRCS) \ +$(IP_AXI64_4K_2CLK_FIFO_SRCS) \ +$(IP_FIFO_SHORT_2CLK_SRCS) \ +$(AURORA_PHY_SRCS) \ +$(AURORA_PHY_1_SRCS) \ +) + +#------------------------------------------------- +# Testbench Specific +#------------------------------------------------- +include $(BASE_DIR)/../sim/general/Makefile.srcs +include $(BASE_DIR)/../sim/control/Makefile.srcs +include $(BASE_DIR)/../sim/axi/Makefile.srcs + +# Define only one toplevel module +SIM_TOP = aurora_loopback_tb +# Simulation runtime in microseconds +SIM_RUNTIME_US = 70 + +SIM_SRCS = \ +$(abspath aurora_loopback_tb.sv) \ +$(SIM_GENERAL_SRCS) \ +$(SIM_CONTROL_SRCS) \ +$(SIM_AXI_SRCS) + +#------------------------------------------------- +# 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/n3xx/sim/aurora_loopback/aurora_loopback_tb.sv b/fpga/usrp3/top/n3xx/sim/aurora_loopback/aurora_loopback_tb.sv new file mode 100644 index 000000000..ed328f153 --- /dev/null +++ b/fpga/usrp3/top/n3xx/sim/aurora_loopback/aurora_loopback_tb.sv @@ -0,0 +1,395 @@ +///////////////////////////////////////////////////////////////// +// +// Copyright 2018 Ettus Research, A National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +///////////////////////////////////////////////////////////////// + + + +`timescale 1ns/1ps +`define NS_PER_TICK 1 +`define NUM_TEST_CASES 13 + +`include "sim_clks_rsts.vh" +`include "sim_exec_report.vh" +`include "sim_cvita_lib.svh" +`include "sim_axi4_lib.svh" +`include "sim_set_rb_lib.svh" + +module aurora_loopback_tb(); + `TEST_BENCH_INIT("aurora_loopback_tb",`NUM_TEST_CASES,`NS_PER_TICK) + + // Define all clocks and resets + `DEFINE_CLK(XG_CLK_P, 1000/156.25, 50) //156.25MHz GT transceiver clock + `DEFINE_CLK(bus_clk, 1000/200, 50) //define 200 MHz bus clk + `DEFINE_RESET(GSR, 0, 100) //100ns for GSR to deassert + + wire XG_CLK_N = ~XG_CLK_P; + wire SFP_LN0_P, SFP_LN0_N, SFP_LN1_P, SFP_LN1_N; + + localparam PACKET_MODE = 1; + + // Aurora Loopback Topology: + // + // TB Simulus ====> |------------| |----------------| + // | Aurora MAC | <===> | Aurora PCS/PMA | <====>|| + // TB Checker <==== |------------| |----------------| || Loopback through + // || + // + // |-------------------------------------| + // | n3xx_npio_qsfp_wrapper | + // ====> |------------| |----------------| || perfect serial channel + // Loopback | | Aurora MAC | <===> | Aurora PCS/PMA | <====>|| + // <==== |------------| |----------------| + // |-------------------------------------| + + // Initialize DUT + wire aurora_refclk, aurora_init_clk; + wire aurora_clk156; + wire m_user_rst, s_user_rst; + wire m_channel_up, s_channel_up; + wire m_hard_err, s_hard_err; + wire m_soft_err, s_soft_err; + wire s_link_up; + +(* dont_touch = "true" *) IBUFDS_GTE2 aurora_refclk_ibuf ( + .ODIV2(), + .CEB (1'b0), + .I (XG_CLK_P), + .IB(XG_CLK_N), + .O (aurora_refclk) + ); + + aurora_phy_clk_gen aurora_clk_gen_i ( + .refclk_ibuf(aurora_refclk), + .clk156(aurora_clk156), + .init_clk(aurora_init_clk) + ); + wire qpllreset, qpllreset_slave; + wire qplllock, qplllock_slave; + wire qplloutclk, qplloutclk_slave; + wire qplloutrefclk, qplloutrefclk_slave; + wire qpllrefclklost, qpllrefclklost_slave; + wire [7:0] qpll_drpaddr_in_i = 8'h0; + wire [15:0] qpll_drpdi_in_i = 16'h0; + wire qpll_drpen_in_i = 1'b0; + wire qpll_drpwe_in_i = 1'b0; + wire [15:0] qpll_drpdo_out_i, qpll_drpdo_out_s_i; + wire qpll_drprdy_out_i, qpll_drprdy_out_s_i; + + aurora_64b66b_pcs_pma_gt_common_wrapper gt_common_support ( + .gt_qpllclk_quad1_out (qplloutclk), //to sfp + .gt_qpllrefclk_quad1_out (qplloutrefclk), // to sfp + .GT0_GTREFCLK0_COMMON_IN (aurora_refclk), +//----------------------- Common Block - QPLL Ports ------------------------ + .GT0_QPLLLOCK_OUT (qplllock), //from 1st sfp + .GT0_QPLLRESET_IN (qpllreset), //from 1st sfp + .GT0_QPLLLOCKDETCLK_IN (aurora_init_clk), + .GT0_QPLLREFCLKLOST_OUT (qpllrefclklost), //from 1st sfp +//---------------------- Common DRP Ports ---------------------- //not really used??? + .qpll_drpaddr_in (qpll_drpaddr_in_i), + .qpll_drpdi_in (qpll_drpdi_in_i), + .qpll_drpclk_in (aurora_init_clk), + .qpll_drpdo_out (qpll_drpdo_out_i), + .qpll_drprdy_out (qpll_drprdy_out_i), + .qpll_drpen_in (qpll_drpen_in_i), + .qpll_drpwe_in (qpll_drpwe_in_i) + ); + + wire au_master_tx_out_clk, au_slave_tx_out_clk; + wire au_master_gt_pll_lock, au_slave_gt_pll_lock; + wire au_user_clk, au_sync_clk, au_mmcm_locked; + wire au_s_user_clk, au_s_sync_clk, au_s_mmcm_locked; + wire au_master_phy_reset; + + aurora_phy_mmcm aurora_phy_mmcm_0 ( + .aurora_tx_clk_unbuf(au_master_tx_out_clk), + .mmcm_reset(!au_master_gt_pll_lock), + .user_clk(au_user_clk), + .sync_clk(au_sync_clk), + .mmcm_locked(au_mmcm_locked) + ); + + wire [63:0] m_i_tdata, m_o_tdata; + wire m_i_tvalid, m_i_tready, m_o_tvalid; + wire [63:0] s_i_tdata, s_o_tdata; + wire s_i_tvalid, s_i_tready, s_o_tvalid; + wire [63:0] loop_tdata; + wire loop_tlast, loop_tvalid, loop_tready; + wire [31:0] m_overruns; + reg [31:0] s_overruns; + wire [31:0] m_soft_errors, s_soft_errors; + reg m_bist_gen, m_bist_check, s_bist_loopback; + reg [5:0] m_bist_rate; + wire m_bist_locked; + wire [47:0] m_bist_samps, m_bist_errors; + + cvita_master m_tx_chdr (.clk(au_user_clk)); + cvita_slave m_rx_chdr (.clk(au_user_clk)); + + aurora_phy_x1 #(.SIMULATION(1)) aurora_phy_master_i ( + // Resets + .areset(GSR), + // Clocks + .refclk(aurora_refclk), + .qpllclk(qplloutclk), + .qpllrefclk(qplloutrefclk), + .user_clk(au_user_clk), + .sync_clk(au_sync_clk), + .init_clk(aurora_init_clk), + .user_rst(m_user_rst), + // GTX Serial I/O + .tx_p(SFP_LN0_P), .tx_n(SFP_LN0_N), + .rx_p(SFP_LN1_P), .rx_n(SFP_LN1_N), + // AXI4-Stream TX Interface + .s_axis_tdata(m_i_tdata), .s_axis_tvalid(m_i_tvalid), .s_axis_tready(m_i_tready), + // AXI4-Stream RX Interface + .m_axis_tdata(m_o_tdata), .m_axis_tvalid(m_o_tvalid), + // AXI4-Lite Config Interface + .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(m_channel_up), .hard_err(m_hard_err), .soft_err(m_soft_err), + .qplllock(qplllock), + .qpllreset(qpllreset), + .qpllrefclklost(qpllrefclklost), + .tx_out_clk(au_master_tx_out_clk), + .gt_pll_lock(au_master_gt_pll_lock), + .mmcm_locked(au_mmcm_locked) + ); + + aurora_axis_mac #(.PACKET_MODE(PACKET_MODE), .BIST_ENABLED(1)) aurora_mac_master_i ( + // Clocks and resets + .phy_clk(au_user_clk), .phy_rst(m_user_rst), + .sys_clk(au_user_clk), .sys_rst(m_user_rst), + .clear(1'b0), + // PHY Interface + .phy_s_axis_tdata(m_o_tdata), .phy_s_axis_tvalid(m_o_tvalid), + .phy_m_axis_tdata(m_i_tdata), .phy_m_axis_tvalid(m_i_tvalid), .phy_m_axis_tready(m_i_tready), + // User Interface + .s_axis_tdata(m_tx_chdr.axis.tdata), .s_axis_tlast(m_tx_chdr.axis.tlast), + .s_axis_tvalid(m_tx_chdr.axis.tvalid), .s_axis_tready(m_tx_chdr.axis.tready), + .m_axis_tdata(m_rx_chdr.axis.tdata), .m_axis_tlast(m_rx_chdr.axis.tlast), + .m_axis_tvalid(m_rx_chdr.axis.tvalid), .m_axis_tready(m_rx_chdr.axis.tready), + // Misc PHY + .channel_up(m_channel_up), .hard_err(m_hard_err), .soft_err(m_soft_err), + .overruns(m_overruns), .soft_errors(m_soft_errors), + //BIST + .bist_gen_en(m_bist_gen), .bist_checker_en(m_bist_check), .bist_loopback_en(1'b0), .bist_gen_rate(m_bist_rate), + .bist_checker_locked(m_bist_locked), .bist_checker_samps(m_bist_samps), .bist_checker_errors(m_bist_errors) + ); + +reg reg_wr_req_s; +reg [13:0] reg_wr_addr_s; +reg [31:0] reg_wr_data_s; +reg reg_rd_req_s; +reg [13:0] reg_rd_addr_s; +wire reg_rd_resp_s; +wire [31:0] reg_rd_data_s; + +n3xx_npio_qsfp_wrapper #( + .LANES(1), // Number of lanes of Aurora to instantiate (Supported = {1,2,3,4}) + .REG_BASE(32'h0), // Base register address + .PORTNUM_BASE(4), // Base port number for discovery + .REG_DWIDTH(32), // Width of regport address bus + .REG_AWIDTH(14) // Width of regport data bus +) qsfp_wrapper_inst ( + // Clocks and Resets + .areset(GSR), + .bus_clk(bus_clk), + .misc_clk(aurora_init_clk), + .bus_rst(GSR), + .gt_refclk(aurora_refclk), + .gt_clk156(aurora_clk156), + // Serial lanes + .txp(SFP_LN1_P), + .txn(SFP_LN1_N), + .rxp(SFP_LN0_P), + .rxn(SFP_LN0_N), + // AXIS input interface + .s_axis_tdata(loop_tdata), + .s_axis_tlast(loop_tlast), + .s_axis_tvalid(~s_bist_loopback & loop_tvalid), + .s_axis_tready(loop_tready), + // AXIS output interface + .m_axis_tdata(loop_tdata), + .m_axis_tlast(loop_tlast), + .m_axis_tvalid(loop_tvalid), + .m_axis_tready(~s_bist_loopback & loop_tready), + // Register ports + .reg_wr_req(reg_wr_req_s), //input reg_wr_req, + .reg_wr_addr(reg_wr_addr_s), //input [REG_AWIDTH-1:0] reg_wr_addr, + .reg_wr_data(reg_wr_data_s), //input [REG_DWIDTH-1:0] reg_wr_data, + .reg_rd_req(reg_rd_req_s), //input reg_rd_req, + .reg_rd_addr(reg_rd_addr_s), //input [REG_AWIDTH-1:0] reg_rd_addr, + .reg_rd_resp(reg_rd_resp_s), //output reg_rd_resp, + .reg_rd_data(reg_rd_data_s), //output [REG_DWIDTH-1:0] reg_rd_data, + + .link_up(s_link_up), + .activity() +); + + //Testbench variables + cvita_hdr_t header, header_out; + cvita_stats_t stats; + logic [63:0] crc_cache; + + //------------------------------------------ + //Main thread for testbench execution + //------------------------------------------ + initial begin : tb_main + `TEST_CASE_START("Wait for reset"); + while (GSR) @(posedge aurora_refclk); + `TEST_CASE_DONE((~GSR)); + + m_bist_gen <= 1'b0; + m_bist_rate <= 6'd0; + m_bist_check <= 1'b0; + s_bist_loopback <= 1'b0; + + m_tx_chdr.push_bubble(); + + `TEST_CASE_START("Wait for master channel to come up"); + while (m_channel_up !== 1'b1) @(posedge au_user_clk); + `TEST_CASE_DONE(1'b1); + + `TEST_CASE_START("Wait for slave channel to come up. Uses QSFP Wrapper"); + while (s_link_up !== 1'b1) @(posedge bus_clk); + `TEST_CASE_DONE(1'b1); + + `TEST_CASE_START("Run PRBS BIST"); + s_bist_loopback <= PACKET_MODE; + $display("Need to interact with regport to set s_bist_loopback."); + reg_wr_req_s <= 1; + reg_wr_addr_s <= 4; + reg_wr_data_s <= 4; + @(posedge bus_clk); + repeat (3) @(posedge au_user_clk); + reg_wr_req_s <= 0; + m_bist_rate <= 6'd60; + m_bist_gen <= 1'b1; + m_bist_check <= 1'b1; + @(posedge au_user_clk); + while (m_bist_locked !== 1'b1) @(posedge au_user_clk); + repeat (512) @(posedge au_user_clk); + `ASSERT_ERROR(m_bist_samps>256, "BIST: Num samples incorrect"); + `ASSERT_ERROR(m_bist_errors===36'd0, "BIST: Errors!"); + @(posedge au_user_clk); + m_bist_gen <= 1'b0; + repeat (256) @(posedge au_user_clk); + m_bist_check <= 1'b0; + `TEST_CASE_DONE(1'b1); + + header = '{ + pkt_type:DATA, has_time:0, eob:0, seqnum:12'h666, + length:0, src_sid:$random, dst_sid:$random, timestamp:64'h0}; + + `TEST_CASE_START("Fill up empty FIFO then drain (short packet)"); + m_rx_chdr.axis.tready = 0; + m_tx_chdr.push_ramp_pkt(16, 64'd0, 64'h100, header); + m_rx_chdr.axis.tready = 1; + m_rx_chdr.wait_for_pkt_get_info(header_out, stats); + `ASSERT_ERROR(stats.count==16, "Bad packet: Length mismatch"); + `ASSERT_ERROR(header.src_sid==header_out.src_sid, "Bad packet: Wrong Src SID"); + `ASSERT_ERROR(header.dst_sid==header_out.dst_sid, "Bad packet: Wrong Dst SID"); + `TEST_CASE_DONE(1); + + `TEST_CASE_START("Fill up empty FIFO then drain (long packet)"); + m_rx_chdr.axis.tready = 0; + m_tx_chdr.push_ramp_pkt(256, 64'd0, 64'h100, header); + m_rx_chdr.axis.tready = 1; + m_rx_chdr.wait_for_pkt_get_info(header_out, stats); + `ASSERT_ERROR(stats.count==256, "Bad packet: Length mismatch"); + `ASSERT_ERROR(header.src_sid==header_out.src_sid, "Bad packet: Wrong Src SID"); + `ASSERT_ERROR(header.dst_sid==header_out.dst_sid, "Bad packet: Wrong Dst SID"); + `TEST_CASE_DONE(1); + + header = '{ + pkt_type:DATA, has_time:1, eob:0, seqnum:12'h666, + length:0, src_sid:$random, dst_sid:$random, timestamp:64'h0}; + + `TEST_CASE_START("Concurrent read and write (single packet)"); + repeat (10) @(posedge au_user_clk); //Wait for clear to go low + m_rx_chdr.axis.tready = 1; + fork + begin + m_tx_chdr.push_ramp_pkt(200, 64'd0, 64'h100, header); + end + begin + m_rx_chdr.wait_for_pkt_get_info(header_out, stats); + end + join + crc_cache = stats.crc; //Cache CRC for future test cases + `ASSERT_ERROR(stats.count==201, "Bad packet: Length mismatch"); + `TEST_CASE_DONE(1); + + `TEST_CASE_START("Concurrent read and write (multiple packets)"); + m_rx_chdr.axis.tready = 1; + fork + begin + repeat (20) begin + m_tx_chdr.push_ramp_pkt(20, 64'd0, 64'h100, header); + m_tx_chdr.push_bubble(); + end + end + begin + repeat (20) begin + m_rx_chdr.wait_for_pkt_get_info(header_out, stats); + `ASSERT_ERROR(stats.count==21, "Bad packet: Length mismatch"); + `ASSERT_ERROR(crc_cache==stats.crc, "Bad packet: Wrong CRC"); + end + end + join + `TEST_CASE_DONE(1); + + `TEST_CASE_START("Validate no drops (master)"); + `TEST_CASE_DONE((m_overruns === 32'd0)); + + `TEST_CASE_START("Validate no drops (slave)"); + reg_rd_req_s <= 1; + reg_rd_addr_s <= 'h20; + @(posedge reg_rd_resp_s) + reg_rd_req_s <= 0; + s_overruns <= reg_rd_data_s; + `TEST_CASE_DONE((s_overruns === 32'd0)); + + s_bist_loopback <= 1'b1; + + `TEST_CASE_START("Run PRBS BIST (Loopback Mode)"); + @(posedge au_user_clk); + m_bist_gen <= 1'b1; + m_bist_rate <= 6'd60; + m_bist_check <= 1'b1; + @(posedge au_user_clk); + while (m_bist_locked !== 1'b1) @(posedge au_user_clk); + repeat (512) @(posedge au_user_clk); + `ASSERT_ERROR(m_bist_samps>256, "BIST: Num samples incorrect"); + `ASSERT_ERROR(m_bist_errors===36'd0, "BIST: Errors!"); + @(posedge au_user_clk); + m_bist_gen <= 1'b0; + repeat (256) @(posedge au_user_clk); + m_bist_check <= 1'b0; + `TEST_CASE_DONE(1'b1); + + s_bist_loopback <= 1'b0; + + `TEST_CASE_START("Validate no drops (master)"); + `TEST_CASE_DONE((m_overruns === 32'd0)); + + `TEST_CASE_START("Validate no drops (slave)"); + reg_rd_req_s <= 1; + reg_rd_addr_s <= 'h20; + @(posedge reg_rd_resp_s) + reg_rd_req_s <= 0; + s_overruns <= reg_rd_data_s; + `TEST_CASE_DONE((s_overruns === 32'd0)); + + `TEST_BENCH_DONE; + end + +endmodule diff --git a/fpga/usrp3/top/n3xx/sim/dram_fifo/Makefile b/fpga/usrp3/top/n3xx/sim/dram_fifo/Makefile new file mode 100644 index 000000000..738cb12dc --- /dev/null +++ b/fpga/usrp3/top/n3xx/sim/dram_fifo/Makefile @@ -0,0 +1,70 @@ +# +# Copyright 2015 Ettus Research LLC +# + +#------------------------------------------------- +# Top-of-Makefile +#------------------------------------------------- +# Define BASE_DIR to point to the "top" dir +BASE_DIR = $(abspath ../../..) +# Include viv_sim_preample after defining BASE_DIR +include $(BASE_DIR)/../tools/make/viv_sim_preamble.mak + +#------------------------------------------------- +# Design Specific +#------------------------------------------------- +# Define part using PART_ID (<device>/<package>/<speedgrade>) +ARCH = zynq +PART_ID = xc7z100/ffg900/-2 + +# Include makefiles and sources for the DUT and its dependencies +include $(BASE_DIR)/../lib/fifo/Makefile.srcs +include $(BASE_DIR)/../lib/axi/Makefile.srcs +include $(BASE_DIR)/../lib/control/Makefile.srcs + +DESIGN_SRCS = $(abspath \ +$(FIFO_SRCS) \ +$(AXI_SRCS) \ +$(CONTROL_LIB_SRCS) \ +) + +#------------------------------------------------- +# IP Specific +#------------------------------------------------- +# If simulation contains IP, define the IP_DIR and point +# it to the base level IP directory +IP_DIR = ../../ip + +# Include makefiles and sources for all IP components +# *after* defining the IP_DIR +include $(IP_DIR)/ddr3_32bit/Makefile.inc +include $(IP_DIR)/axi_intercon_4x64_256_bd/Makefile.inc +include $(IP_DIR)/fifo_short_2clk/Makefile.inc +include $(IP_DIR)/fifo_4k_2clk/Makefile.inc + +DESIGN_SRCS += $(abspath \ +$(IP_DDR3_32BIT_SRCS) \ +$(IP_AXI_INTERCON_4X64_256_SRCS) \ +$(IP_AXI_INTERCON_4X64_256_BD_SRCS) \ +$(IP_FIFO_4K_2CLK_SRCS) \ +$(IP_FIFO_SHORT_2CLK_SRCS) \ +) + +#------------------------------------------------- +# Testbench Specific +#------------------------------------------------- +# Define only one toplevel module +SIM_TOP = dram_fifo_tb + +SIM_SRCS = \ +$(abspath dram_fifo_tb.sv) \ +$(abspath axis_dram_fifo_single.sv) \ +$(IP_DDR3_32BIT_SIM_OUTS) + +#------------------------------------------------- +# 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/n3xx/sim/dram_fifo/axis_dram_fifo_single.sv b/fpga/usrp3/top/n3xx/sim/dram_fifo/axis_dram_fifo_single.sv new file mode 100644 index 000000000..63bea218e --- /dev/null +++ b/fpga/usrp3/top/n3xx/sim/dram_fifo/axis_dram_fifo_single.sv @@ -0,0 +1,493 @@ +// +// Copyright 2015 Ettus Research LLC +// + +`timescale 1ns/1ps + +module axis_dram_fifo_single +#( + parameter DIFF_CLK = 0, + parameter SR_BASE = 0 +) ( + input bus_clk, + input bus_rst, + input sys_clk_p, + input sys_clk_n, + input sys_rst_n, + input dma_engine_clk, + + input [63:0] i_tdata, + input i_tlast, + input i_tvalid, + output i_tready, + + output [63:0] o_tdata, + output o_tlast, + output o_tvalid, + input o_tready, + + input set_stb, + input [7:0] set_addr, + input [31:0] set_data, + output [31:0] rb_data, + + input [63:0] forced_bit_err, + + output init_calib_complete +); + + wire ddr3_axi_clk; // 1/4 DDR external clock rate (250MHz) + wire ddr3_axi_rst; // Synchronized to ddr_sys_clk + reg ddr3_axi_rst_reg_n; // Synchronized to ddr_sys_clk + + // Misc declarations + axi4_rd_t #(.DWIDTH(64), .AWIDTH(32), .IDWIDTH(1)) dma_axi_rd(.clk(dma_engine_clk)); + axi4_wr_t #(.DWIDTH(64), .AWIDTH(32), .IDWIDTH(1)) dma_axi_wr(.clk(dma_engine_clk)); + axi4_rd_t #(.DWIDTH(256), .AWIDTH(32), .IDWIDTH(4)) mig_axi_rd(.clk(ddr3_axi_clk)); + axi4_wr_t #(.DWIDTH(256), .AWIDTH(32), .IDWIDTH(4)) mig_axi_wr(.clk(ddr3_axi_clk)); + + wire [31:0] ddr3_dq; // Data pins. Input for Reads; Output for Writes. + wire [3:0] ddr3_dqs_n; // Data Strobes. Input for Reads; Output for Writes. + wire [3:0] ddr3_dqs_p; + wire [15:0] ddr3_addr; // Address + wire [2:0] ddr3_ba; // Bank Address + wire ddr3_ras_n; // Row Address Strobe. + wire ddr3_cas_n; // Column address select + wire ddr3_we_n; // Write Enable + wire ddr3_reset_n; // SDRAM reset pin. + wire [0:0] ddr3_ck_p; // Differential clock + wire [0:0] ddr3_ck_n; + wire [0:0] ddr3_cke; // Clock Enable + wire [0:0] ddr3_cs_n; // Chip Select + wire [3:0] ddr3_dm; // Data Mask [3] = UDM.U26; [2] = LDM.U26; ... + wire [0:0] ddr3_odt; // On-Die termination enable. + + always @(posedge ddr3_axi_clk) + ddr3_axi_rst_reg_n <= ~ddr3_axi_rst; + + axi_dma_fifo #( + .DEFAULT_BASE(30'h02000000), + .DEFAULT_MASK(30'hFF000000), + .DEFAULT_TIMEOUT(280), + .SR_BASE(SR_BASE), + .EXT_BIST(1), + .SIMULATION(1) + ) axi_dma_fifo_i0 ( + // + // Clocks and reset + .bus_clk (bus_clk), + .bus_reset (bus_rst), + .dram_clk (dma_engine_clk), + .dram_reset (ddr3_axi_rst), + // + // AXI Write address channel + .m_axi_awid (dma_axi_wr.addr.id), + .m_axi_awaddr (dma_axi_wr.addr.addr), + .m_axi_awlen (dma_axi_wr.addr.len), + .m_axi_awsize (dma_axi_wr.addr.size), + .m_axi_awburst (dma_axi_wr.addr.burst), + .m_axi_awlock (dma_axi_wr.addr.lock), + .m_axi_awcache (dma_axi_wr.addr.cache), + .m_axi_awprot (dma_axi_wr.addr.prot), + .m_axi_awqos (dma_axi_wr.addr.qos), + .m_axi_awregion (dma_axi_wr.addr.region), + .m_axi_awuser (dma_axi_wr.addr.user), + .m_axi_awvalid (dma_axi_wr.addr.valid), + .m_axi_awready (dma_axi_wr.addr.ready), + // + // AXI Write data channel. + .m_axi_wdata (dma_axi_wr.data.data), + .m_axi_wstrb (dma_axi_wr.data.strb), + .m_axi_wlast (dma_axi_wr.data.last), + .m_axi_wuser (dma_axi_wr.data.user), + .m_axi_wvalid (dma_axi_wr.data.valid), + .m_axi_wready (dma_axi_wr.data.ready), + // + // AXI Write response channel signals + .m_axi_bid (dma_axi_wr.resp.id), + .m_axi_bresp (dma_axi_wr.resp.resp), + .m_axi_buser (dma_axi_wr.resp.user), + .m_axi_bvalid (dma_axi_wr.resp.valid), + .m_axi_bready (dma_axi_wr.resp.ready), + // + // AXI Read address channel + .m_axi_arid (dma_axi_rd.addr.id), + .m_axi_araddr (dma_axi_rd.addr.addr), + .m_axi_arlen (dma_axi_rd.addr.len), + .m_axi_arsize (dma_axi_rd.addr.size), + .m_axi_arburst (dma_axi_rd.addr.burst), + .m_axi_arlock (dma_axi_rd.addr.lock), + .m_axi_arcache (dma_axi_rd.addr.cache), + .m_axi_arprot (dma_axi_rd.addr.prot), + .m_axi_arqos (dma_axi_rd.addr.qos), + .m_axi_arregion (dma_axi_rd.addr.region), + .m_axi_aruser (dma_axi_rd.addr.user), + .m_axi_arvalid (dma_axi_rd.addr.valid), + .m_axi_arready (dma_axi_rd.addr.ready), + // + // AXI Read data channel + .m_axi_rid (dma_axi_rd.data.id), + .m_axi_rdata (dma_axi_rd.data.data), + .m_axi_rresp (dma_axi_rd.data.resp), + .m_axi_rlast (dma_axi_rd.data.last), + .m_axi_ruser (dma_axi_rd.data.user), + .m_axi_rvalid (dma_axi_rd.data.valid), + .m_axi_rready (dma_axi_rd.data.ready), + // + // CHDR friendly AXI stream input + .i_tdata (i_tdata), + .i_tlast (i_tlast), + .i_tvalid (i_tvalid), + .i_tready (i_tready), + // + // CHDR friendly AXI Stream output + .o_tdata (o_tdata), + .o_tlast (o_tlast), + .o_tvalid (o_tvalid), + .o_tready (o_tready), + // + // Settings + .set_stb (set_stb), + .set_addr (set_addr), + .set_data (set_data), + .rb_data (rb_data), + + .debug() + ); + + //--------------------------------------------------- + // We use an interconnect to connect to FIFOs. + //--------------------------------------------------- + // Attach to third slave just to validate proper ID handling in interconnect + + axi_intercon_4x64_256_bd_wrapper axi_intercon_i ( + // + .S00_AXI_ACLK (dma_engine_clk), // input S01_AXI_ACLK + .S00_AXI_ARESETN (~ddr3_axi_rst), // input S01_AXI_ARESETN + .S00_AXI_AWID (0), // input [0 : 0] S01_AXI_AWID + .S00_AXI_AWADDR (0), // input [31 : 0] S01_AXI_AWADDR + .S00_AXI_AWLEN (0), // input [7 : 0] S01_AXI_AWLEN + .S00_AXI_AWSIZE (0), // input [2 : 0] S01_AXI_AWSIZE + .S00_AXI_AWBURST (0), // input [1 : 0] S01_AXI_AWBURST + .S00_AXI_AWLOCK (0), // input S01_AXI_AWLOCK + .S00_AXI_AWCACHE (0), // input [3 : 0] S01_AXI_AWCACHE + .S00_AXI_AWPROT (0), // input [2 : 0] S01_AXI_AWPROT + .S00_AXI_AWQOS (0), // input [3 : 0] S01_AXI_AWQOS + .S00_AXI_AWVALID (0), // input S01_AXI_AWVALID + .S00_AXI_AWREADY (), // output S01_AXI_AWREADY + .S00_AXI_WDATA (0), // input [63 : 0] S01_AXI_WDATA + .S00_AXI_WSTRB (0), // input [7 : 0] S01_AXI_WSTRB + .S00_AXI_WLAST (0), // input S01_AXI_WLAST + .S00_AXI_WVALID (0), // input S01_AXI_WVALID + .S00_AXI_WREADY (), // output S01_AXI_WREADY + .S00_AXI_BID (), // output [0 : 0] S01_AXI_BID + .S00_AXI_BRESP (), // output [1 : 0] S01_AXI_BRESP + .S00_AXI_BVALID (), // output S01_AXI_BVALID + .S00_AXI_BREADY (1), // input S01_AXI_BREADY + .S00_AXI_ARID (0), // input [0 : 0] S01_AXI_ARID + .S00_AXI_ARADDR (0), // input [31 : 0] S01_AXI_ARADDR + .S00_AXI_ARLEN (0), // input [7 : 0] S01_AXI_ARLEN + .S00_AXI_ARSIZE (0), // input [2 : 0] S01_AXI_ARSIZE + .S00_AXI_ARBURST (0), // input [1 : 0] S01_AXI_ARBURST + .S00_AXI_ARLOCK (0), // input S01_AXI_ARLOCK + .S00_AXI_ARCACHE (0), // input [3 : 0] S01_AXI_ARCACHE + .S00_AXI_ARPROT (0), // input [2 : 0] S01_AXI_ARPROT + .S00_AXI_ARQOS (0), // input [3 : 0] S01_AXI_ARQOS + .S00_AXI_ARVALID (0), // input S01_AXI_ARVALID + .S00_AXI_ARREADY (), // output S01_AXI_ARREADY + .S00_AXI_RID (), // output [0 : 0] S01_AXI_RID + .S00_AXI_RDATA (), // output [63 : 0] S01_AXI_RDATA + .S00_AXI_RRESP (), // output [1 : 0] S01_AXI_RRESP + .S00_AXI_RLAST (), // output S01_AXI_RLAST + .S00_AXI_RVALID (), // output S01_AXI_RVALID + .S00_AXI_RREADY (1), // input S01_AXI_RREADY + // + .S01_AXI_ACLK (dma_engine_clk), // input S01_AXI_ACLK + .S01_AXI_ARESETN (~ddr3_axi_rst), // input S01_AXI_ARESETN + .S01_AXI_AWID (0), // input [0 : 0] S01_AXI_AWID + .S01_AXI_AWADDR (0), // input [31 : 0] S01_AXI_AWADDR + .S01_AXI_AWLEN (0), // input [7 : 0] S01_AXI_AWLEN + .S01_AXI_AWSIZE (0), // input [2 : 0] S01_AXI_AWSIZE + .S01_AXI_AWBURST (0), // input [1 : 0] S01_AXI_AWBURST + .S01_AXI_AWLOCK (0), // input S01_AXI_AWLOCK + .S01_AXI_AWCACHE (0), // input [3 : 0] S01_AXI_AWCACHE + .S01_AXI_AWPROT (0), // input [2 : 0] S01_AXI_AWPROT + .S01_AXI_AWQOS (0), // input [3 : 0] S01_AXI_AWQOS + .S01_AXI_AWVALID (0), // input S01_AXI_AWVALID + .S01_AXI_AWREADY (), // output S01_AXI_AWREADY + .S01_AXI_WDATA (0), // input [63 : 0] S01_AXI_WDATA + .S01_AXI_WSTRB (0), // input [7 : 0] S01_AXI_WSTRB + .S01_AXI_WLAST (0), // input S01_AXI_WLAST + .S01_AXI_WVALID (0), // input S01_AXI_WVALID + .S01_AXI_WREADY (), // output S01_AXI_WREADY + .S01_AXI_BID (), // output [0 : 0] S01_AXI_BID + .S01_AXI_BRESP (), // output [1 : 0] S01_AXI_BRESP + .S01_AXI_BVALID (), // output S01_AXI_BVALID + .S01_AXI_BREADY (1), // input S01_AXI_BREADY + .S01_AXI_ARID (0), // input [0 : 0] S01_AXI_ARID + .S01_AXI_ARADDR (0), // input [31 : 0] S01_AXI_ARADDR + .S01_AXI_ARLEN (0), // input [7 : 0] S01_AXI_ARLEN + .S01_AXI_ARSIZE (0), // input [2 : 0] S01_AXI_ARSIZE + .S01_AXI_ARBURST (0), // input [1 : 0] S01_AXI_ARBURST + .S01_AXI_ARLOCK (0), // input S01_AXI_ARLOCK + .S01_AXI_ARCACHE (0), // input [3 : 0] S01_AXI_ARCACHE + .S01_AXI_ARPROT (0), // input [2 : 0] S01_AXI_ARPROT + .S01_AXI_ARQOS (0), // input [3 : 0] S01_AXI_ARQOS + .S01_AXI_ARVALID (0), // input S01_AXI_ARVALID + .S01_AXI_ARREADY (), // output S01_AXI_ARREADY + .S01_AXI_RID (), // output [0 : 0] S01_AXI_RID + .S01_AXI_RDATA (), // output [63 : 0] S01_AXI_RDATA + .S01_AXI_RRESP (), // output [1 : 0] S01_AXI_RRESP + .S01_AXI_RLAST (), // output S01_AXI_RLAST + .S01_AXI_RVALID (), // output S01_AXI_RVALID + .S01_AXI_RREADY (1), // input S01_AXI_RREADY + // + .S02_AXI_ACLK (dma_engine_clk), // input S01_AXI_ACLK + .S02_AXI_ARESETN (~ddr3_axi_rst), // input S01_AXI_ARESETN + .S02_AXI_AWID (0), // input [0 : 0] S01_AXI_AWID + .S02_AXI_AWADDR (0), // input [31 : 0] S01_AXI_AWADDR + .S02_AXI_AWLEN (0), // input [7 : 0] S01_AXI_AWLEN + .S02_AXI_AWSIZE (0), // input [2 : 0] S01_AXI_AWSIZE + .S02_AXI_AWBURST (0), // input [1 : 0] S01_AXI_AWBURST + .S02_AXI_AWLOCK (0), // input S01_AXI_AWLOCK + .S02_AXI_AWCACHE (0), // input [3 : 0] S01_AXI_AWCACHE + .S02_AXI_AWPROT (0), // input [2 : 0] S01_AXI_AWPROT + .S02_AXI_AWQOS (0), // input [3 : 0] S01_AXI_AWQOS + .S02_AXI_AWVALID (0), // input S01_AXI_AWVALID + .S02_AXI_AWREADY (), // output S01_AXI_AWREADY + .S02_AXI_WDATA (0), // input [63 : 0] S01_AXI_WDATA + .S02_AXI_WSTRB (0), // input [7 : 0] S01_AXI_WSTRB + .S02_AXI_WLAST (0), // input S01_AXI_WLAST + .S02_AXI_WVALID (0), // input S01_AXI_WVALID + .S02_AXI_WREADY (), // output S01_AXI_WREADY + .S02_AXI_BID (), // output [0 : 0] S01_AXI_BID + .S02_AXI_BRESP (), // output [1 : 0] S01_AXI_BRESP + .S02_AXI_BVALID (), // output S01_AXI_BVALID + .S02_AXI_BREADY (1), // input S01_AXI_BREADY + .S02_AXI_ARID (0), // input [0 : 0] S01_AXI_ARID + .S02_AXI_ARADDR (0), // input [31 : 0] S01_AXI_ARADDR + .S02_AXI_ARLEN (0), // input [7 : 0] S01_AXI_ARLEN + .S02_AXI_ARSIZE (0), // input [2 : 0] S01_AXI_ARSIZE + .S02_AXI_ARBURST (0), // input [1 : 0] S01_AXI_ARBURST + .S02_AXI_ARLOCK (0), // input S01_AXI_ARLOCK + .S02_AXI_ARCACHE (0), // input [3 : 0] S01_AXI_ARCACHE + .S02_AXI_ARPROT (0), // input [2 : 0] S01_AXI_ARPROT + .S02_AXI_ARQOS (0), // input [3 : 0] S01_AXI_ARQOS + .S02_AXI_ARVALID (0), // input S01_AXI_ARVALID + .S02_AXI_ARREADY (), // output S01_AXI_ARREADY + .S02_AXI_RID (), // output [0 : 0] S01_AXI_RID + .S02_AXI_RDATA (), // output [63 : 0] S01_AXI_RDATA + .S02_AXI_RRESP (), // output [1 : 0] S01_AXI_RRESP + .S02_AXI_RLAST (), // output S01_AXI_RLAST + .S02_AXI_RVALID (), // output S01_AXI_RVALID + .S02_AXI_RREADY (1), // input S01_AXI_RREADY + // + .S03_AXI_ACLK (dma_engine_clk), // input S00_AXI_ACLK + .S03_AXI_ARESETN (~ddr3_axi_rst), // input S00_AXI_ARESETN + .S03_AXI_AWID (dma_axi_wr.addr.id), // input [0 : 0] S00_AXI_AWID + .S03_AXI_AWADDR (dma_axi_wr.addr.addr), // input [31 : 0] S00_AXI_AWADDR + .S03_AXI_AWLEN (dma_axi_wr.addr.len), // input [7 : 0] S00_AXI_AWLEN + .S03_AXI_AWSIZE (dma_axi_wr.addr.size), // input [2 : 0] S00_AXI_AWSIZE + .S03_AXI_AWBURST (dma_axi_wr.addr.burst), // input [1 : 0] S00_AXI_AWBURST + .S03_AXI_AWLOCK (dma_axi_wr.addr.lock), // input S00_AXI_AWLOCK + .S03_AXI_AWCACHE (dma_axi_wr.addr.cache), // input [3 : 0] S00_AXI_AWCACHE + .S03_AXI_AWPROT (dma_axi_wr.addr.prot), // input [2 : 0] S00_AXI_AWPROT + .S03_AXI_AWQOS (dma_axi_wr.addr.qos), // input [3 : 0] S00_AXI_AWQOS + .S03_AXI_AWVALID (dma_axi_wr.addr.valid), // input S00_AXI_AWVALID + .S03_AXI_AWREADY (dma_axi_wr.addr.ready), // output S00_AXI_AWREADY + .S03_AXI_WDATA (dma_axi_wr.data.data ^ forced_bit_err), // input [63 : 0] S00_AXI_WDATA + .S03_AXI_WSTRB (dma_axi_wr.data.strb), // input [7 : 0] S00_AXI_WSTRB + .S03_AXI_WLAST (dma_axi_wr.data.last), // input S00_AXI_WLAST + .S03_AXI_WVALID (dma_axi_wr.data.valid), // input S00_AXI_WVALID + .S03_AXI_WREADY (dma_axi_wr.data.ready), // output S00_AXI_WREADY + .S03_AXI_BID (dma_axi_wr.resp.id), // output [0 : 0] S00_AXI_BID + .S03_AXI_BRESP (dma_axi_wr.resp.resp), // output [1 : 0] S00_AXI_BRESP + .S03_AXI_BVALID (dma_axi_wr.resp.valid), // output S00_AXI_BVALID + .S03_AXI_BREADY (dma_axi_wr.resp.ready), // input S00_AXI_BREADY + .S03_AXI_ARID (dma_axi_rd.addr.id), // input [0 : 0] S00_AXI_ARID + .S03_AXI_ARADDR (dma_axi_rd.addr.addr), // input [31 : 0] S00_AXI_ARADDR + .S03_AXI_ARLEN (dma_axi_rd.addr.len), // input [7 : 0] S00_AXI_ARLEN + .S03_AXI_ARSIZE (dma_axi_rd.addr.size), // input [2 : 0] S00_AXI_ARSIZE + .S03_AXI_ARBURST (dma_axi_rd.addr.burst), // input [1 : 0] S00_AXI_ARBURST + .S03_AXI_ARLOCK (dma_axi_rd.addr.lock), // input S00_AXI_ARLOCK + .S03_AXI_ARCACHE (dma_axi_rd.addr.cache), // input [3 : 0] S00_AXI_ARCACHE + .S03_AXI_ARPROT (dma_axi_rd.addr.prot), // input [2 : 0] S00_AXI_ARPROT + .S03_AXI_ARQOS (dma_axi_rd.addr.qos), // input [3 : 0] S00_AXI_ARQOS + .S03_AXI_ARVALID (dma_axi_rd.addr.valid), // input S00_AXI_ARVALID + .S03_AXI_ARREADY (dma_axi_rd.addr.ready), // output S00_AXI_ARREADY + .S03_AXI_RID (dma_axi_rd.data.id), // output [0 : 0] S00_AXI_RID + .S03_AXI_RDATA (dma_axi_rd.data.data), // output [63 : 0] S00_AXI_RDATA + .S03_AXI_RRESP (dma_axi_rd.data.resp), // output [1 : 0] S00_AXI_RRESP + .S03_AXI_RLAST (dma_axi_rd.data.last), // output S00_AXI_RLAST + .S03_AXI_RVALID (dma_axi_rd.data.valid), // output S00_AXI_RVALID + .S03_AXI_RREADY (dma_axi_rd.data.ready), // input S00_AXI_RREADY + // + .M00_AXI_ACLK (ddr3_axi_clk), // input M00_AXI_ACLK + .M00_AXI_ARESETN (~ddr3_axi_rst), // input M00_AXI_ARESETN + .M00_AXI_AWID (mig_axi_wr.addr.id), // output [3 : 0] M00_AXI_AWID + .M00_AXI_AWADDR (mig_axi_wr.addr.addr), // output [31 : 0] M00_AXI_AWADDR + .M00_AXI_AWLEN (mig_axi_wr.addr.len), // output [7 : 0] M00_AXI_AWLEN + .M00_AXI_AWSIZE (mig_axi_wr.addr.size), // output [2 : 0] M00_AXI_AWSIZE + .M00_AXI_AWBURST (mig_axi_wr.addr.burst), // output [1 : 0] M00_AXI_AWBURST + .M00_AXI_AWLOCK (mig_axi_wr.addr.lock), // output M00_AXI_AWLOCK + .M00_AXI_AWCACHE (mig_axi_wr.addr.cache), // output [3 : 0] M00_AXI_AWCACHE + .M00_AXI_AWPROT (mig_axi_wr.addr.prot), // output [2 : 0] M00_AXI_AWPROT + .M00_AXI_AWQOS (mig_axi_wr.addr.qos), // output [3 : 0] M00_AXI_AWQOS + .M00_AXI_AWVALID (mig_axi_wr.addr.valid), // output M00_AXI_AWVALID + .M00_AXI_AWREADY (mig_axi_wr.addr.ready), // input M00_AXI_AWREADY + .M00_AXI_WDATA (mig_axi_wr.data.data), // output [127 : 0] M00_AXI_WDATA + .M00_AXI_WSTRB (mig_axi_wr.data.strb), // output [15 : 0] M00_AXI_WSTRB + .M00_AXI_WLAST (mig_axi_wr.data.last), // output M00_AXI_WLAST + .M00_AXI_WVALID (mig_axi_wr.data.valid), // output M00_AXI_WVALID + .M00_AXI_WREADY (mig_axi_wr.data.ready), // input M00_AXI_WREADY + .M00_AXI_BID (mig_axi_wr.resp.id), // input [3 : 0] M00_AXI_BID + .M00_AXI_BRESP (mig_axi_wr.resp.resp), // input [1 : 0] M00_AXI_BRESP + .M00_AXI_BVALID (mig_axi_wr.resp.valid), // input M00_AXI_BVALID + .M00_AXI_BREADY (mig_axi_wr.resp.ready), // output M00_AXI_BREADY + .M00_AXI_ARID (mig_axi_rd.addr.id), // output [3 : 0] M00_AXI_ARID + .M00_AXI_ARADDR (mig_axi_rd.addr.addr), // output [31 : 0] M00_AXI_ARADDR + .M00_AXI_ARLEN (mig_axi_rd.addr.len), // output [7 : 0] M00_AXI_ARLEN + .M00_AXI_ARSIZE (mig_axi_rd.addr.size), // output [2 : 0] M00_AXI_ARSIZE + .M00_AXI_ARBURST (mig_axi_rd.addr.burst), // output [1 : 0] M00_AXI_ARBURST + .M00_AXI_ARLOCK (mig_axi_rd.addr.lock), // output M00_AXI_ARLOCK + .M00_AXI_ARCACHE (mig_axi_rd.addr.cache), // output [3 : 0] M00_AXI_ARCACHE + .M00_AXI_ARPROT (mig_axi_rd.addr.prot), // output [2 : 0] M00_AXI_ARPROT + .M00_AXI_ARQOS (mig_axi_rd.addr.qos), // output [3 : 0] M00_AXI_ARQOS + .M00_AXI_ARVALID (mig_axi_rd.addr.valid), // output M00_AXI_ARVALID + .M00_AXI_ARREADY (mig_axi_rd.addr.ready), // input M00_AXI_ARREADY + .M00_AXI_RID (mig_axi_rd.data.id), // input [3 : 0] M00_AXI_RID + .M00_AXI_RDATA (mig_axi_rd.data.data), // input [127 : 0] M00_AXI_RDATA + .M00_AXI_RRESP (mig_axi_rd.data.resp), // input [1 : 0] M00_AXI_RRESP + .M00_AXI_RLAST (mig_axi_rd.data.last), // input M00_AXI_RLAST + .M00_AXI_RVALID (mig_axi_rd.data.valid), // input M00_AXI_RVALID + .M00_AXI_RREADY (mig_axi_rd.data.ready) // output M00_AXI_RREADY + ); + + //--------------------------------------------------- + // MIG + //--------------------------------------------------- + ddr3_32bit ddr_mig_i ( + // Memory interface ports + .ddr3_addr (ddr3_addr), + .ddr3_ba (ddr3_ba), + .ddr3_cas_n (ddr3_cas_n), + .ddr3_ck_n (ddr3_ck_n), + .ddr3_ck_p (ddr3_ck_p), + .ddr3_cke (ddr3_cke), + .ddr3_ras_n (ddr3_ras_n), + .ddr3_reset_n (ddr3_reset_n), + .ddr3_we_n (ddr3_we_n), + .ddr3_dq (ddr3_dq), + .ddr3_dqs_n (ddr3_dqs_n), + .ddr3_dqs_p (ddr3_dqs_p), + .init_calib_complete (init_calib_complete), + + .ddr3_cs_n (ddr3_cs_n), + .ddr3_dm (ddr3_dm), + .ddr3_odt (ddr3_odt), + // Application interface ports + .ui_clk (ddr3_axi_clk), // 150MHz clock out + .ui_clk_sync_rst (ddr3_axi_rst), // Active high Reset signal synchronised to 150MHz + .aresetn (ddr3_axi_rst_reg_n), + .app_sr_req (1'b0), + .app_sr_active (), + .app_ref_req (1'b0), + .app_ref_ack (), + .app_zq_req (1'b0), + .app_zq_ack (), + + // Slave Interface Write Address Ports + .s_axi_awid (mig_axi_wr.addr.id), + .s_axi_awaddr (mig_axi_wr.addr.addr), + .s_axi_awlen (mig_axi_wr.addr.len), + .s_axi_awsize (mig_axi_wr.addr.size), + .s_axi_awburst (mig_axi_wr.addr.burst), + .s_axi_awlock (mig_axi_wr.addr.lock), + .s_axi_awcache (mig_axi_wr.addr.cache), + .s_axi_awprot (mig_axi_wr.addr.prot), + .s_axi_awqos (mig_axi_wr.addr.qos), + .s_axi_awvalid (mig_axi_wr.addr.valid), + .s_axi_awready (mig_axi_wr.addr.ready), + // Slave Interface Write Data Ports + .s_axi_wdata (mig_axi_wr.data.data), + .s_axi_wstrb (mig_axi_wr.data.strb), + .s_axi_wlast (mig_axi_wr.data.last), + .s_axi_wvalid (mig_axi_wr.data.valid), + .s_axi_wready (mig_axi_wr.data.ready), + // Slave Interface Write Response Ports + .s_axi_bid (mig_axi_wr.resp.id), + .s_axi_bresp (mig_axi_wr.resp.resp), + .s_axi_bvalid (mig_axi_wr.resp.valid), + .s_axi_bready (mig_axi_wr.resp.ready), + // Slave Interface Read Address Ports + .s_axi_arid (mig_axi_rd.addr.id), + .s_axi_araddr (mig_axi_rd.addr.addr), + .s_axi_arlen (mig_axi_rd.addr.len), + .s_axi_arsize (mig_axi_rd.addr.size), + .s_axi_arburst (mig_axi_rd.addr.burst), + .s_axi_arlock (mig_axi_rd.addr.lock), + .s_axi_arcache (mig_axi_rd.addr.cache), + .s_axi_arprot (mig_axi_rd.addr.prot), + .s_axi_arqos (mig_axi_rd.addr.qos), + .s_axi_arvalid (mig_axi_rd.addr.valid), + .s_axi_arready (mig_axi_rd.addr.ready), + // Slave Interface Read Data Ports + .s_axi_rid (mig_axi_rd.data.id), + .s_axi_rdata (mig_axi_rd.data.data), + .s_axi_rresp (mig_axi_rd.data.resp), + .s_axi_rlast (mig_axi_rd.data.last), + .s_axi_rvalid (mig_axi_rd.data.valid), + .s_axi_rready (mig_axi_rd.data.ready), + // System Clock Ports + .sys_clk_p (sys_clk_p), // From external 100MHz source. + .sys_clk_n (sys_clk_n), // From external 100MHz source. + .clk_ref_i (bus_clk), + .sys_rst (sys_rst_n) // IJB. Poorly named active low. Should change RST_ACT_LOW. + ); + + //--------------------------------------------------- + // DDR3 SDRAM Models + //--------------------------------------------------- + ddr3_model #( + .DEBUG(0) //Disable verbose prints + ) sdram_i0 ( + .rst_n (ddr3_reset_n), + .ck (ddr3_ck_p), + .ck_n (ddr3_ck_n), + .cke (ddr3_cke), + .cs_n (ddr3_cs_n), + .ras_n (ddr3_ras_n), + .cas_n (ddr3_cas_n), + .we_n (ddr3_we_n), + .dm_tdqs (ddr3_dm[1:0]), + .ba (ddr3_ba), + .addr (ddr3_addr), + .dq (ddr3_dq[15:0]), + .dqs (ddr3_dqs_p[1:0]), + .dqs_n (ddr3_dqs_n[1:0]), + .tdqs_n (), // Unused on x16 + .odt (ddr3_odt) + ); + + ddr3_model #( + .DEBUG(0) //Disable verbose prints + ) sdram_i1 ( + .rst_n (ddr3_reset_n), + .ck (ddr3_ck_p), + .ck_n (ddr3_ck_n), + .cke (ddr3_cke), + .cs_n (ddr3_cs_n), + .ras_n (ddr3_ras_n), + .cas_n (ddr3_cas_n), + .we_n (ddr3_we_n), + .dm_tdqs (ddr3_dm[3:2]), + .ba (ddr3_ba), + .addr (ddr3_addr), + .dq (ddr3_dq[31:16]), + .dqs (ddr3_dqs_p[3:2]), + .dqs_n (ddr3_dqs_n[3:2]), + .tdqs_n (), // Unused on x16 + .odt (ddr3_odt) + ); + +endmodule diff --git a/fpga/usrp3/top/n3xx/sim/dram_fifo/dram_fifo_tb.sv b/fpga/usrp3/top/n3xx/sim/dram_fifo/dram_fifo_tb.sv new file mode 100644 index 000000000..2979aefb7 --- /dev/null +++ b/fpga/usrp3/top/n3xx/sim/dram_fifo/dram_fifo_tb.sv @@ -0,0 +1,163 @@ +// +// Copyright 2016 Ettus Research +// + + +`timescale 1ns/1ps +`define SIM_TIMEOUT_US 120 +`define NS_PER_TICK 1 +`define NUM_TEST_CASES 7 + +`include "sim_clks_rsts.vh" +`include "sim_exec_report.vh" +`include "sim_cvita_lib.svh" +`include "sim_axi4_lib.svh" +`include "sim_set_rb_lib.svh" + +module dram_fifo_tb(); + `TEST_BENCH_INIT("dram_fifo_tb",`NUM_TEST_CASES,`NS_PER_TICK) + + // Define all clocks and resets + `DEFINE_DIFF_CLK(sys_clk_p, sys_clk_n, 10, 50) //100MHz differential sys_clk to generate DDR3 clocking + `DEFINE_CLK(bus_clk, 1000/200, 50) //200MHz bus_clk + `DEFINE_CLK(dma_engine_clk, 1000.0/305.0, 50) //305MHz dma_engine_clk + `DEFINE_RESET(bus_rst, 0, 100) //100ns for GSR to deassert + `DEFINE_RESET_N(sys_rst_n, 0, 100) //100ns for GSR to deassert + + settings_bus_master #(.SR_AWIDTH(8),.SR_DWIDTH(32)) tst_set (.clk(bus_clk)); + cvita_master chdr_i (.clk(bus_clk)); + cvita_slave chdr_o (.clk(bus_clk)); + + // Initialize DUT + wire calib_complete; + + axis_dram_fifo_single dut_single ( + .bus_clk(bus_clk), + .bus_rst(bus_rst), + .sys_clk_p(sys_clk_p),//use differential clock on N310 + .sys_clk_n(sys_clk_n), + .sys_rst_n(sys_rst_n), + .dma_engine_clk(dma_engine_clk), + + .i_tdata(chdr_i.axis.tdata), + .i_tlast(chdr_i.axis.tlast), + .i_tvalid(chdr_i.axis.tvalid), + .i_tready(chdr_i.axis.tready), + + .o_tdata(chdr_o.axis.tdata), + .o_tlast(chdr_o.axis.tlast), + .o_tvalid(chdr_o.axis.tvalid), + .o_tready(chdr_o.axis.tready), + + .set_stb(tst_set.settings_bus.set_stb), + .set_addr(tst_set.settings_bus.set_addr), + .set_data(tst_set.settings_bus.set_data), + .rb_data(), + + .forced_bit_err(64'h0), + .init_calib_complete(calib_complete) + ); + + //Testbench variables + cvita_hdr_t header; + cvita_pkt_t pkt_out; + integer i; + + //------------------------------------------ + //Main thread for testbench execution + //------------------------------------------ + initial begin : tb_main + string s; + + `TEST_CASE_START("Wait for reset"); + while (bus_rst) @(posedge bus_clk); + while (~sys_rst_n) @(posedge sys_clk_p); + `TEST_CASE_DONE((~bus_rst & sys_rst_n)); + + `TEST_CASE_START("Wait for initial calibration to complete"); + while (calib_complete !== 1'b1) @(posedge bus_clk); + `TEST_CASE_DONE(calib_complete); + + `TEST_CASE_START("Clear FIFO"); + tst_set.write(1, {16'h0, 12'd280, 2'b00, 1'b0, 1'b1}); + repeat (200) @(posedge bus_clk); + tst_set.write(1, {16'h0, 12'd280, 2'b00, 1'b0, 1'b0}); + repeat (200) @(posedge bus_clk); + `TEST_CASE_DONE(1); + + header = '{ + pkt_type:DATA, has_time:0, eob:0, seqnum:12'h666, + length:0, src_sid:$random, dst_sid:$random, timestamp:64'h0}; + + `TEST_CASE_START("Fill up empty FIFO then drain (short packet)"); + chdr_i.push_ramp_pkt(16, 64'd0, 64'h100, header); + chdr_o.pull_pkt(pkt_out); + $sformat(s, "Bad packet: Length mismatch. Expected: %0d, Actual: %0d",16,pkt_out.payload.size()); + `ASSERT_ERROR(pkt_out.payload.size()==16, s); + $sformat(s, "Bad packet: Wrong SID. Expected: %08x, Actual: %08x", + {header.src_sid,header.dst_sid},{pkt_out.hdr.src_sid,pkt_out.hdr.dst_sid}); + `ASSERT_ERROR({header.src_sid,header.dst_sid}=={pkt_out.hdr.src_sid,pkt_out.hdr.dst_sid}, s); + `TEST_CASE_DONE(1); + + `TEST_CASE_START("Fill up empty FIFO then drain (long packet)"); + chdr_i.push_ramp_pkt(1024, 64'd0, 64'h100, header); + chdr_o.pull_pkt(pkt_out); + $sformat(s, "Bad packet: Length mismatch. Expected: %0d, Actual: %0d",1024,pkt_out.payload.size()); + `ASSERT_ERROR(pkt_out.payload.size()==1024, s); + $sformat(s, "Bad packet: Wrong SID. Expected: %08x, Actual: %08x", + {header.src_sid,header.dst_sid},{pkt_out.hdr.src_sid,pkt_out.hdr.dst_sid}); + `ASSERT_ERROR({header.src_sid,header.dst_sid}=={pkt_out.hdr.src_sid,pkt_out.hdr.dst_sid}, s); + `TEST_CASE_DONE(1); + + header = '{ + pkt_type:DATA, has_time:0, eob:0, seqnum:12'h666, + length:0, src_sid:$random, dst_sid:$random, timestamp:64'h0}; + + `TEST_CASE_START("Concurrent read and write (single packet)"); + fork + begin + chdr_i.push_ramp_pkt(20, 64'd0, 64'h100, header); + end + begin + chdr_o.pull_pkt(pkt_out); + end + join + $sformat(s, "Bad packet: Length mismatch. Expected: %0d, Actual: %0d",20,pkt_out.payload.size()); + `ASSERT_ERROR(pkt_out.payload.size()==20, s); + i = 0; + repeat (20) begin + $sformat(s, "Bad packet: Wrong payload. Index: %d, Expected: %08x, Actual: %08x", + i,(i * 64'h100),pkt_out.payload[i]); + `ASSERT_ERROR(pkt_out.payload[i]==(i * 64'h100), s); + end + `TEST_CASE_DONE(1); + + `TEST_CASE_START("Concurrent read and write (multiple packets)"); + fork + begin + repeat (10) begin + chdr_i.push_ramp_pkt(20, 64'd0, 64'h100, header); + repeat (30) @(posedge bus_clk); + end + end + begin + repeat (10) begin + chdr_o.pull_pkt(pkt_out); + $sformat(s, "Bad packet: Length mismatch. Expected: %0d, Actual: %0d",20,pkt_out.payload.size()); + `ASSERT_ERROR(pkt_out.payload.size()==20, s); + i = 0; + repeat (20) begin + $sformat(s, "Bad packet: Wrong payload. Index: %d, Expected: %08x, Actual: %08x", + i,(i * 64'h100),pkt_out.payload[i]); + `ASSERT_ERROR(pkt_out.payload[i]==(i * 64'h100), s); + end + end + end + join + `TEST_CASE_DONE(1); + + `TEST_BENCH_DONE; + + end + +endmodule diff --git a/fpga/usrp3/top/n3xx/sim/dram_fifo_bist/Makefile b/fpga/usrp3/top/n3xx/sim/dram_fifo_bist/Makefile new file mode 100644 index 000000000..49e673dc4 --- /dev/null +++ b/fpga/usrp3/top/n3xx/sim/dram_fifo_bist/Makefile @@ -0,0 +1,70 @@ +# +# Copyright 2015 Ettus Research LLC +# + +#------------------------------------------------- +# Top-of-Makefile +#------------------------------------------------- +# Define BASE_DIR to point to the "top" dir +BASE_DIR = $(abspath ../../..) +# Include viv_sim_preample after defining BASE_DIR +include $(BASE_DIR)/../tools/make/viv_sim_preamble.mak + +#------------------------------------------------- +# Design Specific +#------------------------------------------------- +# Define part using PART_ID (<device>/<package>/<speedgrade>) +ARCH = zynq +PART_ID = xc7z100/ffg900/-2 + +# Include makefiles and sources for the DUT and its dependencies +include $(BASE_DIR)/../lib/fifo/Makefile.srcs +include $(BASE_DIR)/../lib/axi/Makefile.srcs +include $(BASE_DIR)/../lib/control/Makefile.srcs + +DESIGN_SRCS = $(abspath \ +$(FIFO_SRCS) \ +$(AXI_SRCS) \ +$(CONTROL_LIB_SRCS) \ +) + +#------------------------------------------------- +# IP Specific +#------------------------------------------------- +# If simulation contains IP, define the IP_DIR and point +# it to the base level IP directory +IP_DIR = ../../ip + +# Include makefiles and sources for all IP components +# *after* defining the IP_DIR +include $(IP_DIR)/ddr3_32bit/Makefile.inc +include $(IP_DIR)/axi_intercon_4x64_256_bd/Makefile.inc +include $(IP_DIR)/fifo_short_2clk/Makefile.inc +include $(IP_DIR)/fifo_4k_2clk/Makefile.inc + +DESIGN_SRCS += $(abspath \ +$(IP_DDR3_32BIT_SRCS) \ +$(IP_AXI_INTERCON_4X64_256_SRCS) \ +$(IP_AXI_INTERCON_4X64_256_BD_SRCS) \ +$(IP_FIFO_4K_2CLK_SRCS) \ +$(IP_FIFO_SHORT_2CLK_SRCS) \ +) + +#------------------------------------------------- +# Testbench Specific +#------------------------------------------------- +# Define only one toplevel module +SIM_TOP = dram_fifo_bist_tb + +SIM_SRCS = \ +$(abspath dram_fifo_bist_tb.sv) \ +$(abspath ../dram_fifo/axis_dram_fifo_single.sv) \ +$(IP_DDR3_32BIT_SIM_OUTS) + +#------------------------------------------------- +# 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/n3xx/sim/dram_fifo_bist/dram_fifo_bist_tb.sv b/fpga/usrp3/top/n3xx/sim/dram_fifo_bist/dram_fifo_bist_tb.sv new file mode 100644 index 000000000..96a60de6e --- /dev/null +++ b/fpga/usrp3/top/n3xx/sim/dram_fifo_bist/dram_fifo_bist_tb.sv @@ -0,0 +1,348 @@ +// +// Copyright 2015 Ettus Research LLC +// + + +`timescale 1ns/1ps +`define SIM_RUNTIME_US 3000 +`define NS_PER_TICK 1 +`define NUM_TEST_CASES 8 + +`include "sim_clks_rsts.vh" +`include "sim_exec_report.vh" +`include "sim_cvita_lib.svh" +`include "sim_axi4_lib.svh" +`include "sim_set_rb_lib.svh" + +module dram_fifo_bist_tb(); + `TEST_BENCH_INIT("dram_fifo_bist_tb",`NUM_TEST_CASES,`NS_PER_TICK) + + // Define all clocks and resets + `DEFINE_DIFF_CLK(sys_clk_p, sys_clk_n, 10, 50) //100MHz differential sys_clk to generate DDR3 clocking + `DEFINE_CLK(bus_clk, 1000/200, 50) //200MHz bus_clk + `DEFINE_CLK(dma_engine_clk, 1000/300, 50) //300MHz dma_engine_clk + `DEFINE_RESET(bus_rst, 0, 100) //100ns for GSR to deassert + `DEFINE_RESET_N(sys_rst_n, 0, 100) //100ns for GSR to deassert + + localparam EXTENDED_TEST = 0; + + // Initialize DUT + wire calib_complete; + wire running, done; + wire [1:0] error; + wire [31:0] rb_data; + reg [63:0] forced_bit_err; + + settings_bus_master #(.SR_AWIDTH(8),.SR_DWIDTH(32)) tst_set (.clk(bus_clk)); + cvita_master cvita_fifo_in (.clk(bus_clk)); + cvita_slave cvita_fifo_out (.clk(bus_clk)); + + // AXI DRAM FIFO Topology (Inline production BIST for DRAM FIFO): + // + // User Data ====> |---------| |---------------| |-----------| ====> User Data Out + // | AXI MUX | ====> | AXI DRAM FIFO | ====> | AXI DEMUX | + // BIST Data ====> |---------| |---------------| |-----------| ====> BIST Data Out + // || + // |--------------| + // | MIG (D/S)RAM | + // |--------------| + + localparam SR_FIFO_BASE = 0; + localparam SR_BIST_BASE = SR_FIFO_BASE + 4; + + axis_dram_fifo_single dut_single ( + .bus_clk(bus_clk), + .bus_rst(bus_rst), + .sys_clk_p(sys_clk_p),//use differential clock on N310 + .sys_clk_n(sys_clk_n), + .sys_rst_n(sys_rst_n), + .dma_engine_clk(dma_engine_clk), + + .i_tdata(cvita_fifo_in.axis.tdata), + .i_tlast(cvita_fifo_in.axis.tlast), + .i_tvalid(cvita_fifo_in.axis.tvalid), + .i_tready(cvita_fifo_in.axis.tready), + + .o_tdata(cvita_fifo_out.axis.tdata), + .o_tlast(cvita_fifo_out.axis.tlast), + .o_tvalid(cvita_fifo_out.axis.tvalid), + .o_tready(cvita_fifo_out.axis.tready), + + .set_stb(tst_set.settings_bus.set_stb), + .set_addr(tst_set.settings_bus.set_addr), + .set_data(tst_set.settings_bus.set_data), + .rb_data(rb_data), + + .forced_bit_err(forced_bit_err), + .init_calib_complete(calib_complete) + ); + + assign {error, done, running} = rb_data[3:0]; + + //Testbench variables + cvita_hdr_t header; + cvita_pkt_t pkt_out; + integer i; + integer single_run_time; + integer xfer_cnt, cyc_cnt; + + //------------------------------------------ + //Main thread for testbench execution + //------------------------------------------ + initial begin : tb_main + string s; + + `TEST_CASE_START("Wait for reset"); + while (bus_rst) @(posedge bus_clk); + while (~sys_rst_n) @(posedge sys_clk_p); + `TEST_CASE_DONE(~bus_rst & sys_rst_n); + + forced_bit_err <= 64'h0; + repeat (200) @(posedge sys_clk_p); + + `TEST_CASE_START("Wait for initial calibration to complete"); + while (calib_complete !== 1'b1) @(posedge bus_clk); + `TEST_CASE_DONE(calib_complete); + + `TEST_CASE_START("Clear FIFO"); + tst_set.write(SR_FIFO_BASE + 1, {16'h0, 12'd280, 2'b00, 1'b0, 1'b1}); + repeat (200) @(posedge bus_clk); + tst_set.write(SR_FIFO_BASE + 1, {16'h0, 12'd280, 2'b00, 1'b0, 1'b0}); + repeat (200) @(posedge bus_clk); + `TEST_CASE_DONE(1); + + //Select BIST status as the readback output + tst_set.write(SR_FIFO_BASE + 0, 3'd1); + + header = '{ + pkt_type:DATA, has_time:0, eob:0, seqnum:12'h666, + length:0, src_sid:$random, dst_sid:$random, timestamp:64'h0}; + + `TEST_CASE_START("Fill up empty FIFO then drain (long packet)"); + cvita_fifo_in.push_ramp_pkt(100, 64'd0, 64'h100, header); + cvita_fifo_out.pull_pkt(pkt_out); + $sformat(s, "Bad packet: Length mismatch. Expected: %0d, Actual: %0d",100,pkt_out.payload.size()); + `ASSERT_ERROR(pkt_out.payload.size()==100, s); + $sformat(s, "Bad packet: Wrong SID. Expected: %08x, Actual: %08x", + {header.src_sid,header.dst_sid},{pkt_out.hdr.src_sid,pkt_out.hdr.dst_sid}); + `ASSERT_ERROR({header.src_sid,header.dst_sid}=={pkt_out.hdr.src_sid,pkt_out.hdr.dst_sid}, s); + i = 0; + repeat (100) begin + $sformat(s, "Bad packet: Wrong payload. Index: %d, Expected: %08x, Actual: %08x", + i,(i * 64'h100),pkt_out.payload[i]); + `ASSERT_ERROR(pkt_out.payload[i]==(i * 64'h100), s); + end + `TEST_CASE_DONE(1); + + `TEST_CASE_START("Setup BIST: 10 x 40byte packets"); + tst_set.write(SR_BIST_BASE + 0, {2'd0, 2'd0, 1'b0, 1'b0}); + tst_set.write(SR_BIST_BASE + 3, 32'h01234567); + tst_set.write(SR_BIST_BASE + 2, {8'd0, 16'd0}); + tst_set.write(SR_BIST_BASE + 1, {1'b0, 13'd40, 18'd10}); + `TEST_CASE_DONE(~done & ~running); + + `TEST_CASE_START("Run BIST"); + tst_set.write(SR_BIST_BASE + 0, {2'd3, 2'd0, 1'b0, 1'b1}); + while (~done) @(posedge bus_clk); + `ASSERT_ERROR(error==2'b00, "BIST failed!"); + @(posedge bus_clk); + `TEST_CASE_DONE(done & ~running); + + `TEST_CASE_START("Run BIST ... again (should fail)"); + forced_bit_err <= 64'h8000000000000000; + tst_set.write(SR_BIST_BASE + 0, {2'd0, 2'd0, 1'b0, 1'b0}); + tst_set.write(SR_BIST_BASE + 0, {2'd0, 2'd0, 1'b0, 1'b1}); + while (~done) @(posedge bus_clk); + `ASSERT_ERROR(error==2'b01, "BIST passed when it should have failed!"); + forced_bit_err <= 64'h0; + @(posedge bus_clk); + `TEST_CASE_DONE(done & ~running); + + `TEST_CASE_START("Run BIST ... and again (should pass)"); + tst_set.write(SR_BIST_BASE + 0, {2'd0, 2'd0, 1'b0, 1'b0}); + tst_set.write(SR_BIST_BASE + 0, {2'd2, 2'd0, 1'b0, 1'b1}); + while (~done) @(posedge bus_clk); + `ASSERT_ERROR(error==2'b00, "BIST failed!"); + @(posedge bus_clk); + `TEST_CASE_DONE(done & ~running); + + if (EXTENDED_TEST) begin // Extended test mode + `TEST_CASE_START("Setup BIST: 8000 x 40byte ramping packets"); + tst_set.write(SR_BIST_BASE + 0, {2'd0, 2'd0, 1'b0, 1'b0}); + tst_set.write(SR_BIST_BASE + 3, 32'h01234567); + tst_set.write(SR_BIST_BASE + 2, {8'd0, 16'd0}); + tst_set.write(SR_BIST_BASE + 1, {1'b1, 13'd40, 18'd8000}); + `TEST_CASE_DONE(~done & ~running); + + `TEST_CASE_START("Run BIST"); + tst_set.write(SR_BIST_BASE + 0, {2'd3, 2'd0, 1'b0, 1'b1}); + while (~done) @(posedge bus_clk); + `ASSERT_ERROR(error==2'b00, "BIST failed!"); + @(posedge bus_clk); + `TEST_CASE_DONE(done & ~running); + + `TEST_CASE_START("Setup BIST: 256 x 1000byte packets"); + tst_set.write(SR_BIST_BASE + 0, {2'd0, 2'd0, 1'b0, 1'b0}); + tst_set.write(SR_BIST_BASE + 3, 32'h0ABCDEF0); + tst_set.write(SR_BIST_BASE + 2, {8'd4, 16'd256}); + tst_set.write(SR_BIST_BASE + 1, {1'b0, 13'd1000, 18'd256}); + `TEST_CASE_DONE(~done & ~running); + + `TEST_CASE_START("Run BIST"); + tst_set.write(SR_BIST_BASE + 0, {2'd1, 2'd0, 1'b0, 1'b1}); + while (~done) @(negedge bus_clk); + `ASSERT_ERROR(error==2'b00, "BIST failed!"); + @(posedge bus_clk); + `TEST_CASE_DONE(done & ~running); + + `TEST_CASE_START("User Data: Concurrent read and write"); + cvita_fifo_out.axis.tready = 1; + fork + begin + cvita_fifo_in.push_ramp_pkt(20, 64'd0, 64'h100, header); + end + begin + cvita_fifo_out.pull_pkt(pkt_out); + end + join + $sformat(s, "Bad packet: Length mismatch. Expected: %0d, Actual: %0d",20,pkt_out.payload.size()); + `ASSERT_ERROR(pkt_out.payload.size()==20, s); + `TEST_CASE_DONE(1); + + `TEST_CASE_START("Setup BIST: 256 x 600byte ramping packets"); + tst_set.write(SR_BIST_BASE + 0, {2'd0, 2'd0, 1'b0, 1'b0}); + tst_set.write(SR_BIST_BASE + 3, 32'h01234567); + tst_set.write(SR_BIST_BASE + 2, {8'd0, 16'd0}); + tst_set.write(SR_BIST_BASE + 1, {1'b1, 13'd600, 18'd256}); + `TEST_CASE_DONE(~done & ~running); + + `TEST_CASE_START("Run BIST"); + tst_set.write(SR_BIST_BASE + 0, {2'd0, 2'd0, 1'b0, 1'b1}); + while (~done) @(posedge bus_clk); + `ASSERT_ERROR(error==2'b00, "BIST failed!"); + @(posedge bus_clk); + `TEST_CASE_DONE(done & ~running); + + `TEST_CASE_START("Setup BIST: 30 x 8000byte packets"); + tst_set.write(SR_BIST_BASE + 0, {2'd0, 2'd0, 1'b0, 1'b0}); + tst_set.write(SR_BIST_BASE + 3, 32'h0ABCDEF0); + tst_set.write(SR_BIST_BASE + 2, {8'd0, 16'd0}); + tst_set.write(SR_BIST_BASE + 1, {1'b0, 13'd8000, 18'd30}); + `TEST_CASE_DONE(~done & ~running); + + `TEST_CASE_START("Run BIST"); + tst_set.write(SR_BIST_BASE + 0, {2'd1, 2'd0, 1'b0, 1'b1}); + while (~done) @(negedge bus_clk); + `ASSERT_ERROR(error==2'b00, "BIST failed!"); + @(posedge bus_clk); + `TEST_CASE_DONE(done & ~running); + + `TEST_CASE_START("Setup BIST: 100 x 8000byte ramping packets"); + tst_set.write(SR_BIST_BASE + 0, {2'd0, 2'd0, 1'b0, 1'b0}); + tst_set.write(SR_BIST_BASE + 3, 32'h0ABCDEF0); + tst_set.write(SR_BIST_BASE + 2, {8'd0, 16'd0}); + tst_set.write(SR_BIST_BASE + 1, {1'b1, 13'd8000, 18'd100}); + `TEST_CASE_DONE(~done & ~running); + + `TEST_CASE_START("Run BIST"); + tst_set.write(SR_BIST_BASE + 0, {2'd1, 2'd0, 1'b0, 1'b1}); + while (~done) @(negedge bus_clk); + `ASSERT_ERROR(error==2'b00, "BIST failed!"); + @(posedge bus_clk); + `TEST_CASE_DONE(done & ~running); + + `TEST_CASE_START("Validate Throughput"); + tst_set.write(SR_FIFO_BASE + 0, 3'd2); + xfer_cnt = rb_data; + tst_set.write(SR_FIFO_BASE + 0, 3'd3); + cyc_cnt = rb_data; + `ASSERT_ERROR(xfer_cnt>0, "Transfer count was not >0"); + `ASSERT_ERROR(cyc_cnt>0, "Cycle count was not >0"); + $display("Measured Throughput = %0d%% of bus_clk throughput", ((xfer_cnt*100)/cyc_cnt)); + `ASSERT_ERROR(((xfer_cnt*100)/cyc_cnt)>80, "Throughput was less than 80%%"); + tst_set.write(SR_FIFO_BASE + 0, 3'd1); //Restore + `TEST_CASE_DONE(done & ~running); + + `TEST_CASE_START("Setup BIST: 10 x 256byte packets"); + tst_set.write(SR_BIST_BASE + 0, {2'd0, 2'd0, 1'b0, 1'b0}); + tst_set.write(SR_BIST_BASE + 3, 32'hFFFFFFFF); + tst_set.write(SR_BIST_BASE + 2, {8'd0, 16'd0}); + tst_set.write(SR_BIST_BASE + 1, {1'b0, 13'd256, 18'd30}); + `TEST_CASE_DONE(~done & ~running); + + fork + begin + integer curr_time = $time; + `TEST_CASE_START("Run BIST Continuous (Early interrupt)"); + tst_set.write(SR_BIST_BASE + 0, {2'd0, 2'd0, 1'b0, 1'b0}); + tst_set.write(SR_BIST_BASE + 0, {2'd2, 2'd0, 1'b1, 1'b1}); + while (~done) @(negedge bus_clk); + `ASSERT_ERROR(error==2'b00, "BIST failed!"); + @(posedge bus_clk); + single_run_time = $time - curr_time; + `TEST_CASE_DONE(done & ~running); + end + begin + //Wait then clear + #2000; + tst_set.write(SR_BIST_BASE + 0, {2'd0, 2'd0, 1'b0, 1'b0}); + end + join + + fork + begin + `TEST_CASE_START("Run BIST Continuous (Force error)"); + tst_set.write(SR_BIST_BASE + 0, {2'd0, 2'd0, 1'b0, 1'b0}); + tst_set.write(SR_BIST_BASE + 0, {2'd2, 2'd0, 1'b1, 1'b1}); + while (~done) @(negedge bus_clk); + `ASSERT_ERROR(error==2'b01, "BIST passed when it should have failed!"); + @(posedge bus_clk); + `TEST_CASE_DONE(done & ~running); + end + begin + //Wait then force error + #10000; + forced_bit_err <= 64'h1; + end + join + //Recover from failure + forced_bit_err <= 64'h0; + tst_set.write(SR_BIST_BASE + 0, {2'd0, 2'd0, 1'b0, 1'b0}); + repeat (2000) @(posedge bus_clk); + + fork + begin + integer curr_time = $time; + `TEST_CASE_START("Run BIST Continuous"); + tst_set.write(SR_BIST_BASE + 0, {2'd0, 2'd0, 1'b0, 1'b0}); + tst_set.write(SR_BIST_BASE + 0, {2'd2, 2'd0, 1'b1, 1'b1}); + while (~done) @(negedge bus_clk); + `ASSERT_ERROR(error==2'b00, "BIST failed!"); + @(posedge bus_clk); + `ASSERT_ERROR((($time - curr_time) > 2 * single_run_time), "Continuous test most likely stopped early!"); + `TEST_CASE_DONE(done & ~running); + end + begin + //Wait then clear + #100000; + tst_set.write(SR_BIST_BASE + 0, {2'd0, 2'd0, 1'b0, 1'b0}); + end + join + + `TEST_CASE_START("Validate Throughput"); + tst_set.write(SR_FIFO_BASE + 0, 3'd2); + xfer_cnt = rb_data; + tst_set.write(SR_FIFO_BASE + 0, 3'd3); + cyc_cnt = rb_data; + `ASSERT_ERROR(xfer_cnt>0, "Transfer count was not >0"); + `ASSERT_ERROR(cyc_cnt>0, "Cycle count was not >0"); + $display("Measured Throughput = %0d%% of bus_clk throughput", ((xfer_cnt*100)/cyc_cnt)); + `ASSERT_ERROR(((xfer_cnt*100)/cyc_cnt)>80, "Throughput was less than 80%%"); + tst_set.write(SR_FIFO_BASE + 0, 3'd1); //Restore + `TEST_CASE_DONE(done & ~running); + end + + `TEST_BENCH_DONE; + + end +endmodule diff --git a/fpga/usrp3/top/n3xx/sim/one_gig_eth_loopback/Makefile b/fpga/usrp3/top/n3xx/sim/one_gig_eth_loopback/Makefile new file mode 100644 index 000000000..77c7c58c5 --- /dev/null +++ b/fpga/usrp3/top/n3xx/sim/one_gig_eth_loopback/Makefile @@ -0,0 +1,78 @@ +# +# Copyright 2015 Ettus Research LLC +# + +#------------------------------------------------- +# Top-of-Makefile +#------------------------------------------------- +# Define BASE_DIR to point to the "top" dir +BASE_DIR = $(abspath ../../..) +# Include viv_sim_preample after defining BASE_DIR +include $(BASE_DIR)/../tools/make/viv_sim_preamble.mak + +#------------------------------------------------- +# Design Specific +#------------------------------------------------- +# Define part using PART_ID (<device>/<package>/<speedgrade>) +ARCH = zynq +PART_ID = xc7z100/ffg900/-2 + +# Include makefiles and sources for the DUT and its dependencies +include $(BASE_DIR)/../lib/simple_gemac/Makefile.srcs +include $(BASE_DIR)/../lib/fifo/Makefile.srcs +include $(BASE_DIR)/../lib/axi/Makefile.srcs +include $(BASE_DIR)/../lib/control/Makefile.srcs + +DESIGN_SRCS = $(abspath \ +$(FIFO_SRCS) \ +$(AXI_SRCS) \ +$(CONTROL_LIB_SRCS) \ +$(SIMPLE_GEMAC_SRCS) \ +) + +#------------------------------------------------- +# IP Specific +#------------------------------------------------- +# If simulation contains IP, define the IP_DIR and point +# it to the base level IP directory +IP_DIR = ../../ip + +# Include makefiles and sources for all IP components +# *after* defining the IP_DIR +include $(IP_DIR)/one_gig_eth_pcs_pma/Makefile.inc +#include $(IP_DIR)/fifo_short_2clk/Makefile.inc +include $(IP_DIR)/axi64_8k_2clk_fifo/Makefile.inc + +DESIGN_SRCS += $(abspath \ +$(IP_ONE_GIG_ETH_PCS_PMA_SRCS) \ +$(IP_ONE_GIGE_PHY_XCI_SRCS) \ +$(ONE_GIGE_PHY_SRCS) \ +$(IP_AXI64_8K_2CLK_FIFO_SRCS) \ +$(IP_FIFO_SHORT_2CLK_SRCS) \ +) + +#------------------------------------------------- +# Testbench Specific +#------------------------------------------------- +include $(BASE_DIR)/../sim/general/Makefile.srcs +include $(BASE_DIR)/../sim/control/Makefile.srcs +include $(BASE_DIR)/../sim/axi/Makefile.srcs + +# Define only one toplevel module +SIM_TOP = one_gig_eth_loopback_tb +# Simulation runtime in microseconds +SIM_RUNTIME_US = 30000 + +SIM_SRCS = \ +$(abspath one_gig_eth_loopback_tb.sv) \ +$(SIM_GENERAL_SRCS) \ +$(SIM_CONTROL_SRCS) \ +$(SIM_AXI_SRCS) + +#------------------------------------------------- +# 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/n3xx/sim/one_gig_eth_loopback/demo_one_gig_pcs_pma_mdio.v b/fpga/usrp3/top/n3xx/sim/one_gig_eth_loopback/demo_one_gig_pcs_pma_mdio.v new file mode 100644 index 000000000..cd24e14a8 --- /dev/null +++ b/fpga/usrp3/top/n3xx/sim/one_gig_eth_loopback/demo_one_gig_pcs_pma_mdio.v @@ -0,0 +1,489 @@ +//------------------------------------------------------------------------------ +// File : demo_tb.v +// Author : Xilinx Inc. +//------------------------------------------------------------------------------ +// (c) Copyright 2009 Xilinx, Inc. All rights reserved. +// +// This file contains confidential and proprietary information +// of Xilinx, Inc. and is protected under U.S. and +// international copyright and other intellectual property +// laws. +// +// DISCLAIMER +// This disclaimer is not a license and does not grant any +// rights to the materials distributed herewith. Except as +// otherwise provided in a valid license issued to you by +// Xilinx, and to the maximum extent permitted by applicable +// law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND +// WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES +// AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING +// BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- +// INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and +// (2) Xilinx shall not be liable (whether in contract or tort, +// including negligence, or under any other theory of +// liability) for any loss or damage of any kind or nature +// related to, arising under or in connection with these +// materials, including for any direct, or any indirect, +// special, incidental, or consequential loss or damage +// (including loss of data, profits, goodwill, or any type of +// loss or damage suffered as a result of any action brought +// by a third party) even if such damage or loss was +// reasonably foreseeable or Xilinx had been advised of the +// possibility of the same. +// +// CRITICAL APPLICATIONS +// Xilinx products are not designed or intended to be fail- +// safe, or for use in any application requiring fail-safe +// performance, such as life-support or safety devices or +// systems, Class III medical devices, nuclear facilities, +// applications related to the deployment of airbags, or any +// other applications that could lead to death, personal +// injury, or severe property or environmental damage +// (individually and collectively, "Critical +// Applications"). Customer assumes the sole risk and +// liability of any use of Xilinx products in Critical +// Applications, subject only to applicable laws and +// regulations governing limitations on product liability. +// +// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS +// PART OF THIS FILE AT ALL TIMES. +// +// +//------------------------------------------------------------------------------ +// Description: This testbench will exercise the ports of the Ethernet +// 1000BASE-X PCS/PMA core's example design to perform the following +// operations: +// +//---------------- +// Configuration +//---------------- +// The core will be reset, then Auto-Negotiation (if present) will +// be disabled and and the core will be taken out of the Isolate +// state. +// +//---------------- +// Transmitter +//---------------- +// Four frames are generated by the Tx Stimulus and pushed into the +// GMII transmitter. +// +// The PHY side transmitter interface data is captured, 8B10B decoded +// and the Tx Monitor checks that the captured data matches that +// injected. +// +//---------------- +// Receiver +//---------------- +// Four frames are generated by the Rx Stimulus, 8B10B encoded and +// pushed into the PHY side receiver interface. +// +// The GMII side receiver interface data is captured and the +// Rx Monitor checks that the captured data matches that injected. +// +// +//---------------------------------------------------------------------- +// Demonstration Test Fixture | +// | +// | +// -------------------------- | +// | Example Design | | +// | (DUT) | | +// | | | +// | | | +// | | | +// Tx | | 8B10B decode, Tx | +// Generate -------> --------> Monitor | +// Frames | | Frames | +// |GMII PHY | | +// | I/F I/F | | +// | | | +// | | | +// | | | +// Rx | | 8B10B encode, Rx | +// Monitor <-------- <-------- Generate | +// Frames | | Frames | +// | | | +// ------------^------------- | +// | | +// | | +// Stimulate | +// MDIO I/F | +// (if present) | +// | +//---------------------------------------------------------------------- + +`timescale 1 ps/1 ps + + +// To use this testbench copy it over the demo_tb.v in the example testbench +// provided by xilinx + +// This module is a modified version of the demonstration testbench provided +// by Xilinx. It has the mdio_master along with the one_gig dut. +// It uses the configuration vector to control the phy +// Can be used to debug mdio_master +module demo_tb; + + + //---------------------------------------------------------------------------- + // Stimulus - Management Frame data + //---------------------------------------------------------------------------- + // Create management frame + reg [0:63] mdio_data; + + initial + begin + + mdio_data[0:31] = 32'hffffffff; // preamble field + mdio_data[32:33] = 2'h1; // start opcode + mdio_data[34:35] = 2'h1; // write opcode + mdio_data[36:40] = 5'd1; // phyad (write to this device) + mdio_data[41:45] = 5'h0; // regad (write to Configuration Register) + mdio_data[46:47] = 2'h2; // Turn-around cycles + + // DATA FIELD + + mdio_data[48] = 1'b0; // Do not assert Reset + mdio_data[49] = 1'b0; // No loopback + mdio_data[50] = 1'b0; // Speed selection + mdio_data[51] = 1'b0; // Disable Auto-Negotiation + mdio_data[52] = 1'b0; // Disable Power Down + mdio_data[53] = 1'b0; // Disable Isolate GMII + mdio_data[54] = 1'b0; // Disable Auto-Negotiation Restart + mdio_data[55] = 1'b1; // Full Duplex Mode + mdio_data[56] = 1'b0; // Disable Collision Test + mdio_data[57] = 1'b0; // Speed selection + mdio_data[58:63] = 6'h0; // Reserved + + end + + + + //---------------------------------------------------------------------------- + // testbench signals + //---------------------------------------------------------------------------- + + // testbench control semaphores + reg configuration_finished; + wire tx_monitor_finished; + wire rx_monitor_finished; + wire simulation_finished; + + + //---------------------------------------------------------------------------- + // DUT signals + //---------------------------------------------------------------------------- + + // An independent clock source used as the reference clock for an + // IDELAYCTRL (if present) and for the main GT transceiver reset logic. + // This example design assumes that this is of frequency 200MHz. + reg independent_clock; + + // System Reset + reg reset; + + // Transceiver Interface + //---------------------- + reg gtrefclk_p; + reg gtrefclk_n; + wire rxuserclk2; + wire txp; + wire txn; + wire rxp; + wire rxn; + + // GMII Interface + //--------------- + wire gmii_tx_clk; + wire gmii_rx_clk; + wire [7:0] gmii_txd; + wire gmii_tx_en; + wire gmii_tx_er; + wire [7:0] gmii_rxd; + wire gmii_rx_dv; + wire gmii_rx_er; + + // Management: MDIO Interface + //--------------------------- + wire mdc; + wire mdio_i; + wire mdio_o; + wire mdio_t; + reg [4:0] configuration_vector; + reg configuration_valid; + wire signal_detect; + wire [15:0] status_vector; + + parameter [13:0] REG_BASE = 14'h0; + parameter REG_DWIDTH = 32; + parameter REG_AWIDTH = 14; + + reg reg_wr_req; + reg [REG_AWIDTH-1:0] reg_wr_addr; + reg [31:0] reg_wr_data; + reg reg_rd_req; + reg [REG_AWIDTH-1:0] reg_rd_addr; + wire reg_rd_resp; + wire [31:0] reg_rd_data; + + //---------------------------------------------------------------------------- + // Create clock sources + //---------------------------------------------------------------------------- + + // An independent clock source used as the reference clock for an + // IDELAYCTRL (if present) and for the main GT transceiver reset logic. + // This testbench uses the frequency of 200MHz. + initial + begin + independent_clock <= 1'b0; + forever + begin + independent_clock <= 1'b0; + #2500; + independent_clock <= 1'b1; + #2500; + end + end + + + + // Create the transceiver Reference clock (125 MHz) + initial + begin + gtrefclk_p <= 1'b0; + gtrefclk_n <= 1'b1; + forever + begin + gtrefclk_p <= 1'b0; + gtrefclk_n <= 1'b1; + #4000; + gtrefclk_p <= 1'b1; + gtrefclk_n <= 1'b0; + #4000; + end + end + + // MDIO Master + mdio_master #( + .REG_BASE (REG_BASE + 32'h10), + .REG_AWIDTH (REG_AWIDTH), + .MDC_DIVIDER (8'd200) + ) mdio_master_i ( + .clk (independent_clock), + .rst (reset), + .mdc (mdc), + .mdio_in (mdio_o), + .mdio_out (mdio_i), + .mdio_tri (mdio_t), + .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), + .reg_rd_resp(reg_rd_resp) + ); + + //---------------------------------------------------------------------------- + // Wire up Device Under Test + //---------------------------------------------------------------------------- + one_gig_eth_pcs_pma_example_design dut + ( + .independent_clock (independent_clock), + .gtrefclk_p (gtrefclk_p), + .gtrefclk_n (gtrefclk_n), + .rxuserclk2 (rxuserclk2), + .txp (txp), + .txn (txn), + .rxp (rxp), + .rxn (rxn), + .gmii_tx_clk (gmii_tx_clk), + .gmii_rx_clk (gmii_rx_clk), + .gmii_txd (gmii_txd), + .gmii_tx_en (gmii_tx_en), + .gmii_tx_er (gmii_tx_er), + .gmii_rxd (gmii_rxd), + .gmii_rx_dv (gmii_rx_dv), + .gmii_rx_er (gmii_rx_er), + .mdc (mdc), + .mdio_i (mdio_i), + .mdio_o (mdio_o), + .mdio_t (mdio_t), + .configuration_vector (configuration_vector), + .configuration_valid (configuration_valid), + .status_vector (status_vector), + .reset (reset), + .signal_detect (signal_detect) + ); + + + + //---------------------------------------------------------------------------- + // Instantiate a Stimulus module for the core + //---------------------------------------------------------------------------- + stimulus_tb stimulus + ( + .txp (txp), + .txn (txn), + .rxp (rxp), + .rxn (rxn), + + .gmii_tx_clk (gmii_tx_clk), + .gmii_rx_clk (gmii_rx_clk), + .gmii_txd (gmii_txd), + .gmii_tx_en (gmii_tx_en), + .gmii_tx_er (gmii_tx_er), + .gmii_rxd (gmii_rxd), + .gmii_rx_dv (gmii_rx_dv), + .gmii_rx_er (gmii_rx_er), + + .configuration_finished (configuration_finished), + .tx_monitor_finished (tx_monitor_finished), + .rx_monitor_finished (rx_monitor_finished) + ); + + + + //---------------------------------------------------------------------------- + // Simulate that PMD sublayer has detected and optical input. + //---------------------------------------------------------------------------- + assign signal_detect = 1'b1; + + + + + //---------------------------------------------------------------------------- + // Set the PHYAD for the core + //---------------------------------------------------------------------------- + + + //---------------------------------------------------------------------------- + // Configuration process. This process will reset the core, then write + // to configuration register 0 to turn off autonegotiation and take + // the core out of the isolate state. + //---------------------------------------------------------------------------- + + // drives MDC at 2.5 MHz + //initial + //begin + // mdc <= 1'b0; + // forever + // begin + // mdc <= 1'b0; + // #200000; + // mdc <= 1'b1; + // #200000; + // end + //end + + + // Main configuration process + initial + begin : p_configuration + integer MDIO_BIT; // Bit counter within MDIO frame + + $display("** Note: Timing checks are not valid"); + + configuration_finished <= 0; + configuration_vector <= 5'b00000; + // Not doing any MDIO write, so configure the Register 0 using + // Configuration Vector + configuration_valid <= 1'b1; + //mdio_i <= 1'b1; + + // reset the core + $display("Resetting core..."); + reset <= 1'b1; + #1000000 + @(posedge gtrefclk_p) + reset <= 1'b0; + // wait for core to obtain synchronisation + + #2000000000 + #1000000000 + + #250000000 + + // Write to PCS Management configuration register 0. + $display("Writing to Control Register in PCS sublayer...."); + + // Write REG_MDIO_OP to Read MDIO Phy Addr 1, Reg Addr 1 + @(posedge independent_clock) + reg_wr_addr <= 14'h18; + reg_wr_data <= 16'h822; + reg_wr_req <= 1'b1; + @(posedge independent_clock) + reg_wr_req <= 1'b0; + #4000000 + + // Write REG_MDIO_CTRL_STATUS to turn on mdio_running + @(posedge independent_clock) + reg_wr_addr <= 14'h1c; + reg_wr_data <= 32'h1; + reg_wr_req <= 1'b1; + @(posedge independent_clock) + reg_wr_req <= 1'b0; + #4000000 + + // Write REG_MDIO_OP to Read MDIO Phy Addr 1, Reg Addr 0 + @(posedge independent_clock) + reg_wr_addr <= 14'h18; + reg_wr_data <= 32'h820; + reg_wr_req <= 1'b1; + @(posedge independent_clock) + reg_wr_req <= 1'b0; + #4000000 + //@(negedge mdc) // centre MDIO around MDC rising edge + + //MDIO_BIT = 0; + + //// transmit serial management frame + //while(MDIO_BIT !== 64) + //begin + // @(negedge mdc); + // mdio_i <= mdio_data[MDIO_BIT]; + // MDIO_BIT = MDIO_BIT + 1; + //end + + //@(negedge mdc) + //mdio_i <= 1'b1; // simulate tri-state with pullup + #10000000 + // wait for core to obtain synchronisation + wait (status_vector[1] == 1); + #8000000 + + configuration_finished <= 1; + end // p_configuration + + + + //---------------------------------------------------------------------------- + // End the simulation. + //---------------------------------------------------------------------------- + + assign simulation_finished = tx_monitor_finished & rx_monitor_finished; + + + initial + begin : p_end_simulation + fork: sim_in_progress + @(posedge simulation_finished) disable sim_in_progress; + #2000000000 + #2000000000 + #500000000 + disable sim_in_progress; + + join + if (simulation_finished) begin + #1000000 + $display("Test completed successfully"); + $display("Simulation Complete."); + end + else + $display("** Error: Testbench timed out"); + $stop; + end // p_end_simulation + + +endmodule + diff --git a/fpga/usrp3/top/n3xx/sim/one_gig_eth_loopback/one_gig_eth_loopback_tb.sv b/fpga/usrp3/top/n3xx/sim/one_gig_eth_loopback/one_gig_eth_loopback_tb.sv new file mode 100644 index 000000000..759ea2872 --- /dev/null +++ b/fpga/usrp3/top/n3xx/sim/one_gig_eth_loopback/one_gig_eth_loopback_tb.sv @@ -0,0 +1,381 @@ +// +// Copyright 2016 Ettus Research LLC +// + + +`timescale 1ns/1ps +`define NS_PER_TICK 1 +`define NUM_TEST_CASES 13 + +`include "sim_clks_rsts.vh" +`include "sim_exec_report.vh" +`include "sim_cvita_lib.svh" +`include "sim_axi4_lib.svh" +`include "sim_set_rb_lib.svh" + +module one_gig_eth_loopback_tb(); + `TEST_BENCH_INIT("one_gig_eth_loopback_tb",`NUM_TEST_CASES,`NS_PER_TICK) + + // Define all clocks and resets + `DEFINE_CLK(ETH_CLK_P, 1000/125, 50) //125MHz GT transceiver clock + `DEFINE_RESET(GSR, 0, 100) //100ns for GSR to deassert + + wire ETH_CLK_N = ~ETH_CLK_P; + wire SFP_LN0_P, SFP_LN0_N, SFP_LN1_P, SFP_LN1_N; + + //localparam PACKET_MODE = 0; + localparam PORTNUM = 8'd0; + + // One_gigE Loopback Topology: + // + // TB Simulus ====> |------------| |----------------| + // | gigE MAC | <===> | gigE PCS/PMA | <====>|| + // TB Checker <==== |------------| |----------------| || Loopback through + // || + // ====> |------------| |----------------| || perfect serial channel + // Loopback | | gigE MAC | <===> | gigE PCS/PMA | <====>|| + // <==== |------------| |----------------| + + // Initialize DUT + wire gige_refclk, gige_refclk_bufg; + wire m_user_clk, s_user_clk; + wire m_channel_up, s_channel_up; + wire [7:0] m_gmii_txd, m_gmii_rxd; + wire m_gmii_tx_en, m_gmii_tx_er, m_gmii_rx_dv, m_gmii_rx_er; + wire m_gmii_clk; + wire [7:0] s_gmii_txd, s_gmii_rxd; + wire s_gmii_tx_en, s_gmii_tx_er, s_gmii_rx_dv, s_gmii_rx_er; + wire s_gmii_clk; + wire [15:0] m_phy_status; + wire [15:0] s_phy_status; + wire [63:0] loop_tdata; + wire loop_tlast, loop_tvalid, loop_tready; + + + reg independent_clock; + assign m_channel_up = m_phy_status[0]; + assign s_channel_up = s_phy_status[0]; + //assign m_user_clk = gmii_clk; + //assign s_user_clk = gmii_clk; + assign m_user_clk = independent_clock; + assign s_user_clk = independent_clock; + wire gt0_qplloutclk, gt0_qplloutrefclk, pma_reset; + + one_gige_phy_clk_gen gige_clk_gen_i ( + .areset(GSR), + .refclk_p(ETH_CLK_P), + .refclk_n(ETH_CLK_N), + .refclk(gige_refclk), + .refclk_bufg(gige_refclk_bufg) + ); + + cvita_master m_tx_chdr (.clk(m_user_clk)); + cvita_slave s_rx_chdr (.clk(s_user_clk)); + initial + begin + independent_clock <= 1'b0; + forever + begin + independent_clock <= 1'b0; + #0.5; + independent_clock <= 1'b1; + #0.5; + end + end + + //----------------------------------------------------------------- + // MDIO Master + //----------------------------------------------------------------- + wire mdc, mdio_m2s, mdio_s2m; + + mdio_master #( + .MDC_DIVIDER (8'd200) + ) mdio_master_i ( + .clk (m_user_clk), + .rst (GSR), + .mdc (mdc), + .mdio_in (mdio_s2m), + .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*/), + .reg_rd_resp(/*reg_rd_resp*/) + ); + + //GT COMMON + one_gig_eth_pcs_pma_gt_common core_gt_common_i + ( + .GTREFCLK0_IN (gige_refclk) , + .QPLLLOCK_OUT (), + .QPLLLOCKDETCLK_IN (independent_clock), + .QPLLOUTCLK_OUT (gt0_qplloutclk), + .QPLLOUTREFCLK_OUT (gt0_qplloutrefclk), + .QPLLREFCLKLOST_OUT (), + .QPLLRESET_IN (pma_reset) + ); + + one_gige_phy one_gige_phy_master_i + ( + .reset(GSR), // Asynchronous reset for entire core. + .independent_clock(independent_clock), + .pma_reset_out(pma_reset), + .gt0_qplloutclk_in(gt0_qplloutclk), + .gt0_qplloutrefclk_in(gt0_qplloutrefclk), + // Tranceiver Interface + .gtrefclk(gige_refclk), // Reference clock for MGT: 125MHz, very high quality. + .gtrefclk_bufg(gige_refclk_bufg), // Reference clock routed through a BUFG + .txp(SFP_LN1_P), // Differential +ve of serial transmission from PMA to PMD. + .txn(SFP_LN1_N), // Differential -ve of serial transmission from PMA to PMD. + .rxp(SFP_LN0_P), // Differential +ve for serial reception from PMD to PMA. + .rxn(SFP_LN0_N), // Differential -ve for serial reception from PMD to PMA. + // GMII Interface (client MAC <=> PCS) + .gmii_clk(m_gmii_clk), // Clock to client MAC. + .gmii_txd(m_gmii_txd), // Transmit data from client MAC. + .gmii_tx_en(m_gmii_tx_en), // Transmit control signal from client MAC. + .gmii_tx_er(m_gmii_tx_er), // Transmit control signal from client MAC. + .gmii_rxd(m_gmii_rxd), // Received Data to client MAC. + .gmii_rx_dv(m_gmii_rx_dv), // Received control signal to client MAC. + .gmii_rx_er(m_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 + .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(m_phy_status), // 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_master_i + ( + .clk125(m_gmii_clk), + .reset(GSR), + + .GMII_GTX_CLK(), + .GMII_TX_EN(m_gmii_tx_en), + .GMII_TX_ER(m_gmii_tx_er), + .GMII_TXD(m_gmii_txd), + .GMII_RX_CLK(m_gmii_clk), + .GMII_RX_DV(m_gmii_rx_dv), + .GMII_RX_ER(m_gmii_rx_er), + .GMII_RXD(m_gmii_rxd), + + .sys_clk(m_user_clk), + .rx_tdata(s_rx_chdr.axis.tdata), + .rx_tuser(/*s_rx_chdr.axis.tuser*/), + .rx_tlast(s_rx_chdr.axis.tlast), + .rx_tvalid(s_rx_chdr.axis.tvalid), + .rx_tready(s_rx_chdr.axis.tready), + .tx_tdata(m_tx_chdr.axis.tdata), + .tx_tuser(/*m_tx_chdr.axis_tuser*/), + .tx_tlast(m_tx_chdr.axis.tlast), + .tx_tvalid(m_tx_chdr.axis.tvalid), + .tx_tready(m_tx_chdr.axis.tready), + // Debug + .debug_tx(), .debug_rx() + ); + + one_gige_phy one_gige_phy_slave_i + ( + .reset(GSR), // Asynchronous reset for entire core. + .independent_clock(independent_clock), + .pma_reset_out(), + .gt0_qplloutclk_in(gt0_qplloutclk), + .gt0_qplloutrefclk_in(gt0_qplloutrefclk), + // Tranceiver Interface + .gtrefclk(gige_refclk), // Reference clock for MGT: 125MHz, very high quality. + .gtrefclk_bufg(gige_refclk_bufg), // Reference clock routed through a BUFG + .txp(SFP_LN0_P), // Differential +ve of serial transmission from PMA to PMD. + .txn(SFP_LN0_N), // Differential -ve of serial transmission from PMA to PMD. + .rxp(SFP_LN1_P), // Differential +ve for serial reception from PMD to PMA. + .rxn(SFP_LN1_N), // Differential -ve for serial reception from PMD to PMA. + // GMII Interface (client MAC <=> PCS) + .gmii_clk(s_gmii_clk), // Clock to client MAC. + .gmii_txd(s_gmii_txd), // Transmit data from client MAC. + .gmii_tx_en(s_gmii_tx_en), // Transmit control signal from client MAC. + .gmii_tx_er(s_gmii_tx_er), // Transmit control signal from client MAC. + .gmii_rxd(s_gmii_rxd), // Received Data to client MAC. + .gmii_rx_dv(s_gmii_rx_dv), // Received control signal to client MAC. + .gmii_rx_er(s_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 + .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(s_phy_status), // 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_slave_i + ( + .clk125(s_gmii_clk), + .reset(GSR), + + .GMII_GTX_CLK(), + .GMII_TX_EN(s_gmii_tx_en), + .GMII_TX_ER(s_gmii_tx_er), + .GMII_TXD(s_gmii_txd), + .GMII_RX_CLK(s_gmii_clk), + .GMII_RX_DV(s_gmii_rx_dv), + .GMII_RX_ER(s_gmii_rx_er), + .GMII_RXD(s_gmii_rxd), + + .sys_clk(s_user_clk), + .rx_tdata(loop_tdata), + .rx_tuser(), + .rx_tlast(loop_tlast), + .rx_tvalid(loop_tvalid), + .rx_tready(loop_tready), + .tx_tdata(loop_tdata), + .tx_tuser(), + .tx_tlast(loop_tlast), + .tx_tvalid(loop_tvalid), + .tx_tready(loop_tready), + // Debug + .debug_tx(), .debug_rx() + ); + + //Testbench variables + cvita_hdr_t header, header_out; + cvita_stats_t stats; + logic [63:0] crc_cache; + + //------------------------------------------ + //Main thread for testbench execution + //------------------------------------------ + initial begin : tb_main + `TEST_CASE_START("Wait for reset"); + while (GSR) @(posedge ETH_CLK_P); + `TEST_CASE_DONE((~GSR)); + + m_tx_chdr.push_bubble(); + + `TEST_CASE_START("Wait for master channel to come up"); + while (m_channel_up !== 1'b1) @(posedge m_user_clk); + `TEST_CASE_DONE(1'b1); + + `TEST_CASE_START("Wait for slave channel to come up"); + while (s_channel_up !== 1'b1) @(posedge s_user_clk); + `TEST_CASE_DONE(1'b1); + + // `TEST_CASE_START("Run PRBS15 BIST"); + // s_bist_loopback <= PACKET_MODE; + // @(posedge m_user_clk); + // m_bist_gen <= 1'b1; + // m_bist_check <= 1'b1; + // @(posedge m_user_clk); + // while (m_bist_locked !== 1'b1) @(posedge m_user_clk); + // repeat (512) @(posedge m_user_clk); + // `ASSERT_ERROR(m_bist_samps>256, "BIST: Num samples incorrect"); + // `ASSERT_ERROR(m_bist_errors===36'd0, "BIST: Errors!"); + // @(posedge m_user_clk); + // m_bist_gen <= 1'b0; + // repeat (256) @(posedge m_user_clk); + // m_bist_check <= 1'b0; + // `TEST_CASE_DONE(1'b1); + + repeat(1000) @(posedge m_user_clk); + + header = '{ + pkt_type:DATA, has_time:0, eob:0, seqnum:12'h666, + length:0, src_sid:$random, dst_sid:$random, timestamp:64'h0}; + + `TEST_CASE_START("Fill up empty FIFO then drain (short packet)"); + s_rx_chdr.axis.tready = 0; + m_tx_chdr.push_ramp_pkt(16, 64'd0, 64'h100, header); + s_rx_chdr.axis.tready = 1; + s_rx_chdr.wait_for_pkt_get_info(header_out, stats); + `ASSERT_ERROR(stats.count==16, "Bad packet: Length mismatch"); + `ASSERT_ERROR(header.dst_sid==header_out.dst_sid, "Bad packet: Wrong SID"); + `TEST_CASE_DONE(1); + + `TEST_CASE_START("Fill up empty FIFO then drain (long packet)"); + s_rx_chdr.axis.tready = 0; + m_tx_chdr.push_ramp_pkt(256, 64'd0, 64'h100, header); + s_rx_chdr.axis.tready = 1; + s_rx_chdr.wait_for_pkt_get_info(header_out, stats); + `ASSERT_ERROR(stats.count==256, "Bad packet: Length mismatch"); + `ASSERT_ERROR(header.dst_sid==header_out.dst_sid, "Bad packet: Wrong SID"); + `TEST_CASE_DONE(1); + + header = '{ + pkt_type:DATA, has_time:1, eob:0, seqnum:12'h666, + length:0, src_sid:$random, dst_sid:$random, timestamp:64'h0}; + + `TEST_CASE_START("Concurrent read and write (single packet)"); + s_rx_chdr.axis.tready = 1; + fork + begin + m_tx_chdr.push_ramp_pkt(1000, 64'd0, 64'h100, header); + end + begin + s_rx_chdr.wait_for_pkt_get_info(header_out, stats); + end + join + crc_cache = stats.crc; //Cache CRC for future test cases + `ASSERT_ERROR(stats.count==1000, "Bad packet: Length mismatch"); + `TEST_CASE_DONE(1); + + `TEST_CASE_START("Concurrent read and write (multiple packets)"); + s_rx_chdr.axis.tready = 1; + fork + begin + repeat (20) begin + m_tx_chdr.push_ramp_pkt(20, 64'd0, 64'h100, header); + m_tx_chdr.push_bubble(); + end + end + begin + repeat (20) begin + s_rx_chdr.wait_for_pkt_get_info(header_out, stats); + `ASSERT_ERROR(stats.count==20, "Bad packet: Length mismatch"); + `ASSERT_ERROR(crc_cache==stats.crc, "Bad packet: Wrong CRC"); + end + end + join + `TEST_CASE_DONE(1); + + //`TEST_CASE_START("Validate no drops (master)"); + //`TEST_CASE_DONE((m_overruns === 32'd0)); + + //`TEST_CASE_START("Validate no drops (slave)"); + //`TEST_CASE_DONE((s_overruns === 32'd0)); + + //s_bist_loopback <= 1'b1; + + //`TEST_CASE_START("Run PRBS15 BIST (Loopback Mode)"); + //@(posedge m_user_clk); + //m_bist_gen <= 1'b1; + //m_bist_rate <= 5'd4; + //m_bist_check <= 1'b1; + //@(posedge m_user_clk); + //while (m_bist_locked !== 1'b1) @(posedge m_user_clk); + //repeat (512) @(posedge m_user_clk); + //`ASSERT_ERROR(m_bist_samps>256, "BIST: Num samples incorrect"); + //`ASSERT_ERROR(m_bist_errors===36'd0, "BIST: Errors!"); + //@(posedge m_user_clk); + //m_bist_gen <= 1'b0; + //repeat (256) @(posedge m_user_clk); + //m_bist_check <= 1'b0; + //`TEST_CASE_DONE(1'b1); + + //s_bist_loopback <= 1'b0; + + //`TEST_CASE_START("Validate no drops (master)"); + //`TEST_CASE_DONE((m_overruns === 32'd0)); + + //`TEST_CASE_START("Validate no drops (slave)"); + //`TEST_CASE_DONE((s_overruns === 32'd0)); + + end + +endmodule diff --git a/fpga/usrp3/top/n3xx/sim/ten_gig_eth_loopback/Makefile b/fpga/usrp3/top/n3xx/sim/ten_gig_eth_loopback/Makefile new file mode 100644 index 000000000..c1271a40b --- /dev/null +++ b/fpga/usrp3/top/n3xx/sim/ten_gig_eth_loopback/Makefile @@ -0,0 +1,84 @@ +# +# Copyright 2015 Ettus Research LLC +# + +#------------------------------------------------- +# Top-of-Makefile +#------------------------------------------------- +# Define BASE_DIR to point to the "top" dir +BASE_DIR = $(abspath ../../..) +# Include viv_sim_preample after defining BASE_DIR +include $(BASE_DIR)/../tools/make/viv_sim_preamble.mak + +#------------------------------------------------- +# Design Specific +#------------------------------------------------- +# Define part using PART_ID (<device>/<package>/<speedgrade>) +ARCH = zynq +PART_ID = xc7z100/ffg900/-2 + +# Include makefiles and sources for the DUT and its dependencies +include $(BASE_DIR)/../lib/fifo/Makefile.srcs +include $(BASE_DIR)/../lib/axi/Makefile.srcs +include $(BASE_DIR)/../lib/control/Makefile.srcs +include $(BASE_DIR)/../lib/xge_interface/Makefile.srcs +include $(BASE_DIR)/../lib/xge/Makefile.srcs +include $(BASE_DIR)/../lib/packet_proc/Makefile.srcs + +DESIGN_SRCS = $(abspath \ +$(FIFO_SRCS) \ +$(AXI_SRCS) \ +$(CONTROL_LIB_SRCS) \ +) + +#------------------------------------------------- +# IP Specific +#------------------------------------------------- +# If simulation contains IP, define the IP_DIR and point +# it to the base level IP directory +IP_DIR = ../../ip + +# Include makefiles and sources for all IP components +# *after* defining the IP_DIR +include $(IP_DIR)/ten_gig_eth_pcs_pma/Makefile.inc +include $(IP_DIR)/axi64_8k_2clk_fifo/Makefile.inc +include $(IP_DIR)/axi64_4k_2clk_fifo/Makefile.inc + +DESIGN_SRCS += $(abspath \ +$(XGE_SRCS) \ +$(XGE_INTERFACE_SRCS) \ +$(IP_TEN_GIG_ETH_PCS_PMA_SRCS) \ +$(IP_TEN_GIGE_PHY_XCI_SRCS) \ +$(TEN_GIGE_PHY_SRCS) \ +$(IP_AXI64_8K_2CLK_FIFO_SRCS) \ +$(IP_AXI64_4K_2CLK_FIFO_SRCS) \ +$(PACKET_PROC_SRCS) \ +) +#$(IP_FIFO_SHORT_2CLK_SRCS) \ + + +#------------------------------------------------- +# Testbench Specific +#------------------------------------------------- +#include $(BASE_DIR)/../sim/general/Makefile.srcs +#include $(BASE_DIR)/../sim/control/Makefile.srcs +#include $(BASE_DIR)/../sim/axi/Makefile.srcs + +# Define only one toplevel module +SIM_TOP = ten_gig_eth_loopback_tb +# Simulation runtime in microseconds +SIM_RUNTIME_US = 30000 + +SIM_SRCS = \ +$(abspath ten_gig_eth_loopback_tb.sv) \ +$(SIM_GENERAL_SRCS) \ +$(SIM_CONTROL_SRCS) \ +$(SIM_AXI_SRCS) + +#------------------------------------------------- +# 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/n3xx/sim/ten_gig_eth_loopback/ten_gig_eth_loopback_tb.sv b/fpga/usrp3/top/n3xx/sim/ten_gig_eth_loopback/ten_gig_eth_loopback_tb.sv new file mode 100644 index 000000000..b0233a339 --- /dev/null +++ b/fpga/usrp3/top/n3xx/sim/ten_gig_eth_loopback/ten_gig_eth_loopback_tb.sv @@ -0,0 +1,527 @@ +// +// Copyright 2016 Ettus Research LLC +// + + +`timescale 1ns/1ps +`define NS_PER_TICK 1 +`define NUM_TEST_CASES 13 + +`include "sim_clks_rsts.vh" +`include "sim_exec_report.vh" +`include "sim_cvita_lib.svh" +`include "sim_axis_lib.svh" +`include "sim_axi4_lib.svh" +`include "sim_set_rb_lib.svh" + +module ten_gig_eth_loopback_tb(); + `TEST_BENCH_INIT("ten_gig_eth_loopback_tb",`NUM_TEST_CASES,`NS_PER_TICK) + + // Define all clocks and resets + `DEFINE_CLK(XG_CLK_P, 1000/156.25, 50) //156.25MHz GT transceiver clock + `DEFINE_RESET(GSR, 0, 100) //100ns for GSR to deassert + + wire XG_CLK_N = ~XG_CLK_P; + wire SFP_LN0_P, SFP_LN0_N, SFP_LN1_P, SFP_LN1_N; + + //localparam PACKET_MODE = 0; + localparam PORTNUM = 8'd0; + + // Ten_gigE Loopback Topology: + // + // TB Simulus ====> |------------| |----------------| + // | XgigE MAC | <===> | XgigE PCS/PMA | <====>|| + // TB Checker <==== |------------| |----------------| || Loopback through + // || + // ====> |------------| |----------------| || perfect serial channel + // Loopback | | XgigE MAC | <===> | XgigE PCS/PMA | <====>|| + // <==== |------------| |----------------| + + // Initialize DUT + wire xgige_refclk, xgige_clk156, xgige_dclk; + wire m_user_clk, s_user_clk; + wire m_channel_up, s_channel_up; + + wire [63:0] m_xgmii_txd; + wire [7:0] m_xgmii_txc; + wire [63:0] m_xgmii_rxd; + wire [7:0] m_xgmii_rxc; + wire [63:0] s_xgmii_txd; + wire [7:0] s_xgmii_txc; + wire [63:0] s_xgmii_rxd; + wire [7:0] s_xgmii_rxc; + wire [7:0] m_xgmii_status; + wire [7:0] s_xgmii_status; + wire m_xge_phy_resetdone; + wire s_xge_phy_resetdone; + wire m_mdc, m_mdio_in, m_mdio_out; + wire s_mdc, s_mdio_in, s_mdio_out; + wire sfpp_rxlos,sfpp_tx_fault,sfpp_tx_disable; + + + wire [15:0] m_phy_status; + wire [15:0] s_phy_status; + wire [63:0] loop_tdata; + wire [3:0] loop_tuser; + wire loop_tlast, loop_tvalid, loop_tready; + + wire [7:0] wb_adr_i; + wire wb_cyc_i; + wire [31:0] wb_dat_i; + wire wb_stb_i; + wire wb_we_i; + wire wb_ack_o; + wire [31:0] wb_dat_o; + wire wb_int_o; + //`ifdef USE_ARM_FRAMER + //wire [63:0] c2e_tdata_int; + //wire [3:0] c2e_tuser_int; + //wire c2e_tlast_int; + //wire c2e_tvalid_int; + //wire c2e_tready_int; + //wire [63:0] c2e_tdata; + //wire [3:0] c2e_tuser; + //wire c2e_tlast; + //wire c2e_tvalid; + //wire c2e_tready; + //`endif + + reg independent_clock; + assign m_channel_up = m_phy_status[0]; + assign s_channel_up = s_phy_status[0]; + //assign m_user_clk = xgige_refclk; + //assign s_user_clk = xgige_refclk; + assign m_user_clk = independent_clock; + assign s_user_clk = independent_clock; + + ten_gige_phy_clk_gen xgige_clk_gen_i ( + .areset(GSR), + .refclk_p(XG_CLK_P), + .refclk_n(XG_CLK_N), + .refclk(xgige_refclk), + .clk156(xgige_clk156), + .dclk(xgige_dclk) + ); + + cvita_master m_tx_chdr (.clk(m_user_clk)); + cvita_slave s_rx_chdr (.clk(s_user_clk)); + // Use this to send axi-stream with arm_framer + //`ifdef USE_ARM_FRAMER + //axis_master #(.DWIDTH(68)) m_axis (.clk(m_user_clk)); + //axis_slave #(.DWIDTH(68)) s_axis (.clk(s_user_clk)); + //`endif + initial + begin + independent_clock <= 1'b0; + forever + begin + independent_clock <= 1'b0; + #2.5; + independent_clock <= 1'b1; + #2.5; + end + end + + assign sfpp_rxlos = 1'b0; + assign sfpp_tx_fault = 1'b0; + + // Instantiate the 10GBASER/KR GT Common block + ten_gig_eth_pcs_pma_gt_common # ( + .WRAPPER_SIM_GTRESET_SPEEDUP("TRUE") ) //Does not affect hardware + ten_gig_eth_pcs_pma_gt_common_block + ( + .refclk(xgige_refclk), + .qpllreset(qpllreset), + .qplllock(qplllock), + .qplloutclk(qplloutclk), + .qplloutrefclk(qplloutrefclk), + .qpllrefclksel(3'b001 /*3'b101*GTSOUTHREFCLK0*/) + ); + + ten_gige_phy ten_gige_phy_master_i + ( + // Clocks and Reset + .areset(GSR), // Asynchronous reset for entire core. + .refclk(xgige_refclk), // Transciever reference clock: 156.25MHz + .clk156(xgige_clk156), // Globally buffered core clock: 156.25MHz + .dclk(xgige_dclk), // Management/DRP clock: 78.125MHz + .sim_speedup_control(~GSR), + // GMII Interface (client MAC <=> PCS) + .xgmii_txd(m_xgmii_txd), // Transmit data from client MAC. + .xgmii_txc(m_xgmii_txc), // Transmit control signal from client MAC. + .xgmii_rxd(m_xgmii_rxd), // Received Data to client MAC. + .xgmii_rxc(m_xgmii_rxc), // Received control signal to client MAC. + // Tranceiver Interface + .txp(SFP_LN0_P), // Differential +ve of serial transmission from PMA to PMD. + .txn(SFP_LN0_N), // Differential -ve of serial transmission from PMA to PMD. + .rxp(SFP_LN1_P), // Differential +ve for serial reception from PMD to PMA. + .rxn(SFP_LN1_N), // Differential -ve for serial reception from PMD to PMA. + // Management: MDIO Interface + .mdc(m_mdc), // Management Data Clock + .mdio_in(m_mdio_in), // Management Data In + .mdio_out(m_mdio_out), // Management Data Out + .mdio_tri(), // Management Data Tristate + .prtad(5'd4), // MDIO address is 4 + // General IO's + .core_status(m_xgmii_status), // Core status + .resetdone(m_xge_phy_resetdone), + .signal_detect(~sfpp_rxlos), //FIXME // Input from PMD to indicate presence of optical input. (Undocumented, but it seems Xilinx expect this to be inverted.) + .tx_fault(sfpp_tx_fault), //FIXME + .tx_disable(/*sfpp_tx_disable*/), //FIXME + .qpllreset(qpllreset1), + .qplllock(qplllock), + .qplloutclk(qplloutclk), + .qplloutrefclk(qplloutrefclk) + + ); + + n310_xge_mac_wrapper #(.PORTNUM(PORTNUM)) xge_mac_wrapper_master_i + ( + // XGMII + .xgmii_clk(xgige_clk156), + .xgmii_txd(m_xgmii_txd), + .xgmii_txc(m_xgmii_txc), + .xgmii_rxd(m_xgmii_rxd), + .xgmii_rxc(m_xgmii_rxc), + // Client FIFO Interfaces + .sys_clk(m_user_clk), + .sys_rst(GSR), + //`ifdef USE_ARM_FRAMER + //.rx_tdata(s_axis.axis.tdata[63:0]), + //.rx_tuser(s_axis.axis.tdata[67:64]), + //.rx_tlast(s_axis.axis.tlast), + //.rx_tvalid(s_axis.axis.tvalid), + //.rx_tready(/*s_axis.axis.tready*/1'b1), + //.tx_tdata(c2e_tdata), + //.tx_tuser(c2e_tuser), + //.tx_tlast(c2e_tlast), + //.tx_tvalid(c2e_tvalid), + //.tx_tready(c2e_tready), + //`endif + .rx_tdata(s_rx_chdr.axis.tdata), + .rx_tuser(), + .rx_tlast(s_rx_chdr.axis.tlast), + .rx_tvalid(s_rx_chdr.axis.tvalid), + .rx_tready(s_rx_chdr.axis.tready), + .tx_tdata(m_tx_chdr.axis.tdata), + .tx_tuser(4'd4), // Bit[3] (error) is ignored for now. + .tx_tlast(m_tx_chdr.axis.tlast), + .tx_tvalid(m_tx_chdr.axis.tvalid), + .tx_tready(m_tx_chdr.axis.tready), + // Other + .phy_ready(m_xge_phy_resetdone), + .ctrl_tx_enable (/*mac_ctrl_reg[0]*/1'b1), //FIXME: Remove hardcoded value + .status_crc_error (), + .status_fragment_error (), + .status_txdfifo_ovflow (), + .status_txdfifo_udflow (), + .status_rxdfifo_ovflow (), + .status_rxdfifo_udflow (), + .status_pause_frame_rx (), + .status_local_fault (), + .status_remote_fault () + ); + + assign m_phy_status = {8'h00, m_xgmii_status}; + + //`ifdef USE_ARM_FRAMER + // arm_framer inst_arm_framer ( + // .clk (m_user_clk), + // .reset (GSR), + // .clear (clear), + // .s_axis_tdata (m_axis.axis.tdata[63:0]), + // .s_axis_tuser (m_axis.axis.tdata[67:64]), + // .s_axis_tlast (m_axis.axis.tlast), + // .s_axis_tvalid (m_axis.axis.tvalid), + // .s_axis_tready (m_axis.axis.tready), + // .m_axis_tdata (c2e_tdata_int), + // .m_axis_tuser (c2e_tuser_int), + // .m_axis_tlast (c2e_tlast_int), + // .m_axis_tvalid (c2e_tvalid_int), + // .m_axis_tready (c2e_tready_int) + // ); + + // axi_mux4 #(.PRIO(0), .WIDTH(68)) eth_mux + // (.clk(m_user_clk), .reset(GSR), .clear(clear), + // .i0_tdata({c2e_tuser_int,c2e_tdata_int}), .i0_tlast(c2e_tlast_int), .i0_tvalid(c2e_tvalid_int), .i0_tready(c2e_tready_int), + // .i1_tdata(), .i1_tlast(), .i1_tvalid(), .i1_tready(), + // .i2_tdata(), .i2_tlast(), .i2_tvalid(), .i2_tready(), + // .i3_tdata(), .i3_tlast(), .i3_tvalid(1'b0), .i3_tready(), + // .o_tdata({c2e_tuser,c2e_tdata}), .o_tlast(c2e_tlast), .o_tvalid(c2e_tvalid), .o_tready(c2e_tready)); + //`endif + + ten_gige_phy ten_gige_phy_slave_i + ( + // Clocks and Reset + .areset(GSR), // Asynchronous reset for entire core. + .refclk(xgige_refclk), // Transciever reference clock: 156.25MHz + .clk156(xgige_clk156), // Globally buffered core clock: 156.25MHz + .dclk(xgige_dclk), // Management/DRP clock: 78.125MHz + .sim_speedup_control(~GSR), + // GMII Interface (client MAC <=> PCS) + .xgmii_txd(s_xgmii_txd), // Transmit data from client MAC. + .xgmii_txc(s_xgmii_txc), // Transmit control signal from client MAC. + .xgmii_rxd(s_xgmii_rxd), // Received Data to client MAC. + .xgmii_rxc(s_xgmii_rxc), // Received control signal to client MAC. + // Tranceiver Interface + .txp(SFP_LN1_P), // Differential +ve of serial transmission from PMA to PMD. + .txn(SFP_LN1_N), // Differential -ve of serial transmission from PMA to PMD. + .rxp(SFP_LN0_P), // Differential +ve for serial reception from PMD to PMA. + .rxn(SFP_LN0_N), // Differential -ve for serial reception from PMD to PMA. + // Management: MDIO Interface + .mdc(s_mdc), // Management Data Clock + .mdio_in(s_mdio_in), // Management Data In + .mdio_out(s_mdio_out), // Management Data Out + .mdio_tri(), // Management Data Tristate + .prtad(5'd4), // MDIO address is 4 + // General IO's + .core_status(s_xgmii_status), // Core status + .resetdone(s_xge_phy_resetdone), + .signal_detect(~sfpp_rxlos), //FIXME // Input from PMD to indicate presence of optical input. (Undocumented, but it seems Xilinx expect this to be inverted.) + .tx_fault(sfpp_tx_fault), //FIXME + .tx_disable(/*sfpp_tx_disable*/), //FIXME + .qpllreset(qpllreset2), + .qplllock(qplllock), + .qplloutclk(qplloutclk), + .qplloutrefclk(qplloutrefclk) + ); + + n310_xge_mac_wrapper #(.PORTNUM(PORTNUM)) xge_mac_wrapper_slave_i + ( + // XGMII + .xgmii_clk(xgige_clk156), + .xgmii_txd(s_xgmii_txd), + .xgmii_txc(s_xgmii_txc), + .xgmii_rxd(s_xgmii_rxd), + .xgmii_rxc(s_xgmii_rxc), + // Client FIFO Interfaces + .sys_clk(s_user_clk), + .sys_rst(GSR), + .rx_tdata(loop_tdata), + .rx_tuser(loop_tuser), + .rx_tlast(loop_tlast), + .rx_tvalid(loop_tvalid), + .rx_tready(loop_tready), + .tx_tdata(loop_tdata), + .tx_tuser(loop_tuser), // Bit[3] (error) is ignored for now. + .tx_tlast(loop_tlast), + .tx_tvalid(loop_tvalid), + .tx_tready(loop_tready), + // Other + .phy_ready(s_xge_phy_resetdone), + .ctrl_tx_enable (/*mac_ctrl_reg[0]*/1'b1), //FIXME: Remove hardcoded value + .status_crc_error (), + .status_fragment_error (), + .status_txdfifo_ovflow (), + .status_txdfifo_udflow (), + .status_rxdfifo_ovflow (), + .status_rxdfifo_udflow (), + .status_pause_frame_rx (), + .status_local_fault (), + .status_remote_fault () + ); + + assign s_phy_status = {8'h00, s_xgmii_status}; + + //Testbench variables + cvita_hdr_t header, header_out; + cvita_stats_t stats; + logic [63:0] crc_cache; + + //------------------------------------------ + //Main thread for testbench execution + //------------------------------------------ + initial begin : tb_main + `TEST_CASE_START("Wait for reset"); + // `ifdef USE_ARM_FRAMER + // m_axis.reset; + // `endif + while (GSR) @(posedge XG_CLK_P); + `TEST_CASE_DONE((~GSR)); + + m_tx_chdr.push_bubble(); + // `ifdef USE_ARM_FRAMER + //m_axis.push_bubble(); + // `endif + + `TEST_CASE_START("Wait for master channel to come up"); + while (m_channel_up !== 1'b1) @(posedge m_user_clk); + `TEST_CASE_DONE(1'b1); + + `TEST_CASE_START("Wait for slave channel to come up"); + while (s_channel_up !== 1'b1) @(posedge s_user_clk); + `TEST_CASE_DONE(1'b1); + + // `TEST_CASE_START("Run PRBS15 BIST"); + // s_bist_loopback <= PACKET_MODE; + // @(posedge m_user_clk); + // m_bist_gen <= 1'b1; + // m_bist_check <= 1'b1; + // @(posedge m_user_clk); + // while (m_bist_locked !== 1'b1) @(posedge m_user_clk); + // repeat (512) @(posedge m_user_clk); + // `ASSERT_ERROR(m_bist_samps>256, "BIST: Num samples incorrect"); + // `ASSERT_ERROR(m_bist_errors===36'd0, "BIST: Errors!"); + // @(posedge m_user_clk); + // m_bist_gen <= 1'b0; + // repeat (256) @(posedge m_user_clk); + // m_bist_check <= 1'b0; + // `TEST_CASE_DONE(1'b1); + + repeat(2000) @(posedge m_user_clk); + + //`TEST_CASE_START("Test Ethernet packet"); + // s_axis.axis.tready = 0; + // m_axis.push_word({4'b0, 64'h0000_0000_0000_ffff}, 1'b0); + // s_axis.axis.tready = 1; + // m_axis.push_word({4'b0, 64'hffff_ffff_ce20_ad1b}, 1'b0); + // m_axis.push_word({4'b0, 64'hc57a_0806_0001_0800}, 1'b0); + // m_axis.push_word({4'b0, 64'h0604_0001_ce20_ad1b}, 1'b0); + // m_axis.push_word({4'b0, 64'hc57a_c0a8_0a64_0000}, 1'b0); + // m_axis.push_word({4'b0, 64'h0000_0000_c0a8_0a0a}, 1'b1); + //`TEST_CASE_DONE(1'b1); + + // repeat(2000) @(posedge m_user_clk); + //`TEST_CASE_START("Test Ethernet packet"); + // s_axis.axis.tready = 0; + // m_axis.push_word({4'b0, 64'hffff_ffff_ffff_9aa9}, 1'b0); + // s_axis.axis.tready = 1; + // m_axis.push_word({4'b0, 64'h6400_e341_0800_4500}, 1'b0); + // m_axis.push_word({4'b0, 64'h0148_0000_0000_4011}, 1'b0); + // m_axis.push_word({4'b0, 64'h79a6_0000_0000_ffff}, 1'b0); + // m_axis.push_word({4'b0, 64'hffff_0044_0043_0134}, 1'b0); + // m_axis.push_word({4'b0, 64'h90be_0101_0600_d2ab}, 1'b0); + // m_axis.push_word({4'b0, 64'h9f01_0007_0000_0000}, 1'b0); + // m_axis.push_word({4'b0, 64'h0000_0000_0000_0000}, 1'b0); + // m_axis.push_word({4'b0, 64'h0000_0000_0000_9aa9}, 1'b0); + // m_axis.push_word({4'b0, 64'h6400_e341_0000_0000}, 1'b0); + // m_axis.push_word({4'b0, 64'h0000_0000_0000_0000}, 1'b0); + // m_axis.push_word({4'b0, 64'h0000_0000_0000_0000}, 1'b0); + // m_axis.push_word({4'b0, 64'h0000_0000_0000_0000}, 1'b0); + // m_axis.push_word({4'b0, 64'h0000_0000_0000_0000}, 1'b0); + // m_axis.push_word({4'b0, 64'h0000_0000_0000_0000}, 1'b0); + // m_axis.push_word({4'b0, 64'h0000_0000_0000_0000}, 1'b0); + // m_axis.push_word({4'b0, 64'h0000_0000_0000_0000}, 1'b0); + // m_axis.push_word({4'b0, 64'h0000_0000_0000_0000}, 1'b0); + // m_axis.push_word({4'b0, 64'h0000_0000_0000_0000}, 1'b0); + // m_axis.push_word({4'b0, 64'h0000_0000_0000_0000}, 1'b0); + // m_axis.push_word({4'b0, 64'h0000_0000_0000_0000}, 1'b0); + // m_axis.push_word({4'b0, 64'h0000_0000_0000_0000}, 1'b0); + // m_axis.push_word({4'b0, 64'h0000_0000_0000_0000}, 1'b0); + // m_axis.push_word({4'b0, 64'h0000_0000_0000_0000}, 1'b0); + // m_axis.push_word({4'b0, 64'h0000_0000_0000_0000}, 1'b0); + // m_axis.push_word({4'b0, 64'h0000_0000_0000_0000}, 1'b0); + // m_axis.push_word({4'b0, 64'h0000_0000_0000_0000}, 1'b0); + // m_axis.push_word({4'b0, 64'h0000_0000_0000_0000}, 1'b0); + // m_axis.push_word({4'b0, 64'h0000_0000_0000_0000}, 1'b0); + // m_axis.push_word({4'b0, 64'h0000_0000_0000_0000}, 1'b0); + // m_axis.push_word({4'b0, 64'h0000_0000_0000_0000}, 1'b0); + // m_axis.push_word({4'b0, 64'h0000_0000_0000_0000}, 1'b0); + // m_axis.push_word({4'b0, 64'h0000_0000_0000_0000}, 1'b0); + // m_axis.push_word({4'b0, 64'h0000_0000_0000_0000}, 1'b0); + // m_axis.push_word({4'b0, 64'h0000_0000_0000_6382}, 1'b0); + // m_axis.push_word({4'b0, 64'h5363_3501_013d_0701}, 1'b0); + // m_axis.push_word({4'b0, 64'h9aa9_6400_e341_3902}, 1'b0); + // m_axis.push_word({4'b0, 64'h0240_3707_0103_060c}, 1'b0); + // m_axis.push_word({4'b0, 64'h0f1c_2a3c_0c75_6468}, 1'b0); + // m_axis.push_word({4'b0, 64'h6370_2031_2e32_342e}, 1'b0); + // m_axis.push_word({4'b0, 64'h31ff_0000_0000_0000}, 1'b0); + // m_axis.push_word({5'b0, 64'h0000_0000_0000_0000}, 1'b0); + // m_axis.push_word({4'd6, 64'h0000_0000_1234_0000}, 1'b1); + + //`TEST_CASE_DONE(1'b1); + + header = '{ + pkt_type:DATA, has_time:0, eob:0, seqnum:12'h666, + length:0, src_sid:$random, dst_sid:$random, timestamp:64'h0}; + + `TEST_CASE_START("Fill up empty FIFO then drain (short packet)"); + s_rx_chdr.axis.tready = 0; + m_tx_chdr.push_ramp_pkt(16, 64'd0, 64'h100, header); + s_rx_chdr.axis.tready = 1; + s_rx_chdr.wait_for_pkt_get_info(header_out, stats); + `ASSERT_ERROR(stats.count==16, "Bad packet: Length mismatch"); + `ASSERT_ERROR(header.dst_sid==header_out.dst_sid, "Bad packet: Wrong SID"); + `TEST_CASE_DONE(1); + + `TEST_CASE_START("Fill up empty FIFO then drain (long packet)"); + s_rx_chdr.axis.tready = 0; + m_tx_chdr.push_ramp_pkt(256, 64'd0, 64'h100, header); + s_rx_chdr.axis.tready = 1; + s_rx_chdr.wait_for_pkt_get_info(header_out, stats); + `ASSERT_ERROR(stats.count==256, "Bad packet: Length mismatch"); + `ASSERT_ERROR(header.dst_sid==header_out.dst_sid, "Bad packet: Wrong SID"); + `TEST_CASE_DONE(1); + + header = '{ + pkt_type:DATA, has_time:1, eob:0, seqnum:12'h666, + length:0, src_sid:$random, dst_sid:$random, timestamp:64'h0}; + + `TEST_CASE_START("Concurrent read and write (single packet)"); + s_rx_chdr.axis.tready = 1; + fork + begin + m_tx_chdr.push_ramp_pkt(1000, 64'd0, 64'h100, header); + end + begin + s_rx_chdr.wait_for_pkt_get_info(header_out, stats); + end + join + crc_cache = stats.crc; //Cache CRC for future test cases + `ASSERT_ERROR(stats.count==1000, "Bad packet: Length mismatch"); + `TEST_CASE_DONE(1); + + `TEST_CASE_START("Concurrent read and write (multiple packets)"); + s_rx_chdr.axis.tready = 1; + fork + begin + repeat (20) begin + m_tx_chdr.push_ramp_pkt(20, 64'd0, 64'h100, header); + m_tx_chdr.push_bubble(); + end + end + begin + repeat (20) begin + s_rx_chdr.wait_for_pkt_get_info(header_out, stats); + `ASSERT_ERROR(stats.count==20, "Bad packet: Length mismatch"); + `ASSERT_ERROR(crc_cache==stats.crc, "Bad packet: Wrong CRC"); + end + end + join + `TEST_CASE_DONE(1); + + //`TEST_CASE_START("Validate no drops (master)"); + //`TEST_CASE_DONE((m_overruns === 32'd0)); + + //`TEST_CASE_START("Validate no drops (slave)"); + //`TEST_CASE_DONE((s_overruns === 32'd0)); + + //s_bist_loopback <= 1'b1; + + //`TEST_CASE_START("Run PRBS15 BIST (Loopback Mode)"); + //@(posedge m_user_clk); + //m_bist_gen <= 1'b1; + //m_bist_rate <= 5'd4; + //m_bist_check <= 1'b1; + //@(posedge m_user_clk); + //while (m_bist_locked !== 1'b1) @(posedge m_user_clk); + //repeat (512) @(posedge m_user_clk); + //`ASSERT_ERROR(m_bist_samps>256, "BIST: Num samples incorrect"); + //`ASSERT_ERROR(m_bist_errors===36'd0, "BIST: Errors!"); + //@(posedge m_user_clk); + //m_bist_gen <= 1'b0; + //repeat (256) @(posedge m_user_clk); + //m_bist_check <= 1'b0; + //`TEST_CASE_DONE(1'b1); + + //s_bist_loopback <= 1'b0; + + //`TEST_CASE_START("Validate no drops (master)"); + //`TEST_CASE_DONE((m_overruns === 32'd0)); + + //`TEST_CASE_START("Validate no drops (slave)"); + //`TEST_CASE_DONE((s_overruns === 32'd0)); + + end + +endmodule |