aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/top/n3xx/sim/aurora_loopback
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp3/top/n3xx/sim/aurora_loopback')
-rw-r--r--fpga/usrp3/top/n3xx/sim/aurora_loopback/Makefile80
-rw-r--r--fpga/usrp3/top/n3xx/sim/aurora_loopback/aurora_loopback_tb.sv395
2 files changed, 475 insertions, 0 deletions
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