1///////////////////////////////////////////////////////////////// 2// 3// Copyright 2018 Ettus Research, A National Instruments Company 4// 5// SPDX-License-Identifier: LGPL-3.0-or-later 6// 7///////////////////////////////////////////////////////////////// 8 9 10 11`timescale 1ns/1ps 12`define NS_PER_TICK 1 13`define NUM_TEST_CASES 13 14 15`include "sim_clks_rsts.vh" 16`include "sim_exec_report.vh" 17`include "sim_cvita_lib.svh" 18`include "sim_axi4_lib.svh" 19`include "sim_set_rb_lib.svh" 20 21module aurora_loopback_tb(); 22 `TEST_BENCH_INIT("aurora_loopback_tb",`NUM_TEST_CASES,`NS_PER_TICK) 23 24 // Define all clocks and resets 25 `DEFINE_CLK(XG_CLK_P, 1000/156.25, 50) //156.25MHz GT transceiver clock 26 `DEFINE_CLK(bus_clk, 1000/200, 50) //define 200 MHz bus clk 27 `DEFINE_RESET(GSR, 0, 100) //100ns for GSR to deassert 28 29 wire XG_CLK_N = ~XG_CLK_P; 30 wire SFP_LN0_P, SFP_LN0_N, SFP_LN1_P, SFP_LN1_N; 31 32 localparam PACKET_MODE = 1; 33 34 // Aurora Loopback Topology: 35 // 36 // TB Simulus ====> |------------| |----------------| 37 // | Aurora MAC | <===> | Aurora PCS/PMA | <====>|| 38 // TB Checker <==== |------------| |----------------| || Loopback through 39 // || 40 // 41 // |-------------------------------------| 42 // | n3xx_npio_qsfp_wrapper | 43 // ====> |------------| |----------------| || perfect serial channel 44 // Loopback | | Aurora MAC | <===> | Aurora PCS/PMA | <====>|| 45 // <==== |------------| |----------------| 46 // |-------------------------------------| 47 48 // Initialize DUT 49 wire aurora_refclk, aurora_init_clk; 50 wire aurora_clk156; 51 wire m_user_rst, s_user_rst; 52 wire m_channel_up, s_channel_up; 53 wire m_hard_err, s_hard_err; 54 wire m_soft_err, s_soft_err; 55 wire s_link_up; 56 57(* dont_touch = "true" *) IBUFDS_GTE2 aurora_refclk_ibuf ( 58 .ODIV2(), 59 .CEB (1'b0), 60 .I (XG_CLK_P), 61 .IB(XG_CLK_N), 62 .O (aurora_refclk) 63 ); 64 65 aurora_phy_clk_gen aurora_clk_gen_i ( 66 .refclk_ibuf(aurora_refclk), 67 .clk156(aurora_clk156), 68 .init_clk(aurora_init_clk) 69 ); 70 wire qpllreset, qpllreset_slave; 71 wire qplllock, qplllock_slave; 72 wire qplloutclk, qplloutclk_slave; 73 wire qplloutrefclk, qplloutrefclk_slave; 74 wire qpllrefclklost, qpllrefclklost_slave; 75 wire [7:0] qpll_drpaddr_in_i = 8'h0; 76 wire [15:0] qpll_drpdi_in_i = 16'h0; 77 wire qpll_drpen_in_i = 1'b0; 78 wire qpll_drpwe_in_i = 1'b0; 79 wire [15:0] qpll_drpdo_out_i, qpll_drpdo_out_s_i; 80 wire qpll_drprdy_out_i, qpll_drprdy_out_s_i; 81 82 aurora_64b66b_pcs_pma_gt_common_wrapper gt_common_support ( 83 .gt_qpllclk_quad1_out (qplloutclk), //to sfp 84 .gt_qpllrefclk_quad1_out (qplloutrefclk), // to sfp 85 .GT0_GTREFCLK0_COMMON_IN (aurora_refclk), 86//----------------------- Common Block - QPLL Ports ------------------------ 87 .GT0_QPLLLOCK_OUT (qplllock), //from 1st sfp 88 .GT0_QPLLRESET_IN (qpllreset), //from 1st sfp 89 .GT0_QPLLLOCKDETCLK_IN (aurora_init_clk), 90 .GT0_QPLLREFCLKLOST_OUT (qpllrefclklost), //from 1st sfp 91//---------------------- Common DRP Ports ---------------------- //not really used??? 92 .qpll_drpaddr_in (qpll_drpaddr_in_i), 93 .qpll_drpdi_in (qpll_drpdi_in_i), 94 .qpll_drpclk_in (aurora_init_clk), 95 .qpll_drpdo_out (qpll_drpdo_out_i), 96 .qpll_drprdy_out (qpll_drprdy_out_i), 97 .qpll_drpen_in (qpll_drpen_in_i), 98 .qpll_drpwe_in (qpll_drpwe_in_i) 99 ); 100 101 wire au_master_tx_out_clk, au_slave_tx_out_clk; 102 wire au_master_gt_pll_lock, au_slave_gt_pll_lock; 103 wire au_user_clk, au_sync_clk, au_mmcm_locked; 104 wire au_s_user_clk, au_s_sync_clk, au_s_mmcm_locked; 105 wire au_master_phy_reset; 106 107 aurora_phy_mmcm aurora_phy_mmcm_0 ( 108 .aurora_tx_clk_unbuf(au_master_tx_out_clk), 109 .mmcm_reset(!au_master_gt_pll_lock), 110 .user_clk(au_user_clk), 111 .sync_clk(au_sync_clk), 112 .mmcm_locked(au_mmcm_locked) 113 ); 114 115 wire [63:0] m_i_tdata, m_o_tdata; 116 wire m_i_tvalid, m_i_tready, m_o_tvalid; 117 wire [63:0] s_i_tdata, s_o_tdata; 118 wire s_i_tvalid, s_i_tready, s_o_tvalid; 119 wire [63:0] loop_tdata; 120 wire loop_tlast, loop_tvalid, loop_tready; 121 wire [31:0] m_overruns; 122 reg [31:0] s_overruns; 123 wire [31:0] m_soft_errors, s_soft_errors; 124 reg m_bist_gen, m_bist_check, s_bist_loopback; 125 reg [5:0] m_bist_rate; 126 wire m_bist_locked; 127 wire [47:0] m_bist_samps, m_bist_errors; 128 129 cvita_master m_tx_chdr (.clk(au_user_clk)); 130 cvita_slave m_rx_chdr (.clk(au_user_clk)); 131 132 aurora_phy_x1 #(.SIMULATION(1)) aurora_phy_master_i ( 133 // Resets 134 .areset(GSR), 135 // Clocks 136 .refclk(aurora_refclk), 137 .qpllclk(qplloutclk), 138 .qpllrefclk(qplloutrefclk), 139 .user_clk(au_user_clk), 140 .sync_clk(au_sync_clk), 141 .init_clk(aurora_init_clk), 142 .user_rst(m_user_rst), 143 // GTX Serial I/O 144 .tx_p(SFP_LN0_P), .tx_n(SFP_LN0_N), 145 .rx_p(SFP_LN1_P), .rx_n(SFP_LN1_N), 146 // AXI4-Stream TX Interface 147 .s_axis_tdata(m_i_tdata), .s_axis_tvalid(m_i_tvalid), .s_axis_tready(m_i_tready), 148 // AXI4-Stream RX Interface 149 .m_axis_tdata(m_o_tdata), .m_axis_tvalid(m_o_tvalid), 150 // AXI4-Lite Config Interface 151 .s_axi_awaddr(32'h0), .s_axi_araddr(32'h0), .s_axi_awvalid(1'b0), .s_axi_awready(), 152 .s_axi_wdata(32'h0), .s_axi_wvalid(1'b0), .s_axi_wstrb(1'b0), .s_axi_wready(), 153 .s_axi_bvalid(), .s_axi_bresp(), .s_axi_bready(1'b1), 154 .s_axi_arready(), .s_axi_arvalid(1'b0), 155 .s_axi_rdata(), .s_axi_rvalid(), .s_axi_rresp(), .s_axi_rready(1'b1), 156 // Status and Error Reporting Interface 157 .channel_up(m_channel_up), .hard_err(m_hard_err), .soft_err(m_soft_err), 158 .qplllock(qplllock), 159 .qpllreset(qpllreset), 160 .qpllrefclklost(qpllrefclklost), 161 .tx_out_clk(au_master_tx_out_clk), 162 .gt_pll_lock(au_master_gt_pll_lock), 163 .mmcm_locked(au_mmcm_locked) 164 ); 165 166 aurora_axis_mac #(.PACKET_MODE(PACKET_MODE), .BIST_ENABLED(1)) aurora_mac_master_i ( 167 // Clocks and resets 168 .phy_clk(au_user_clk), .phy_rst(m_user_rst), 169 .sys_clk(au_user_clk), .sys_rst(m_user_rst), 170 .clear(1'b0), 171 // PHY Interface 172 .phy_s_axis_tdata(m_o_tdata), .phy_s_axis_tvalid(m_o_tvalid), 173 .phy_m_axis_tdata(m_i_tdata), .phy_m_axis_tvalid(m_i_tvalid), .phy_m_axis_tready(m_i_tready), 174 // User Interface 175 .s_axis_tdata(m_tx_chdr.axis.tdata), .s_axis_tlast(m_tx_chdr.axis.tlast), 176 .s_axis_tvalid(m_tx_chdr.axis.tvalid), .s_axis_tready(m_tx_chdr.axis.tready), 177 .m_axis_tdata(m_rx_chdr.axis.tdata), .m_axis_tlast(m_rx_chdr.axis.tlast), 178 .m_axis_tvalid(m_rx_chdr.axis.tvalid), .m_axis_tready(m_rx_chdr.axis.tready), 179 // Misc PHY 180 .channel_up(m_channel_up), .hard_err(m_hard_err), .soft_err(m_soft_err), 181 .overruns(m_overruns), .soft_errors(m_soft_errors), 182 //BIST 183 .bist_gen_en(m_bist_gen), .bist_checker_en(m_bist_check), .bist_loopback_en(1'b0), .bist_gen_rate(m_bist_rate), 184 .bist_checker_locked(m_bist_locked), .bist_checker_samps(m_bist_samps), .bist_checker_errors(m_bist_errors) 185 ); 186 187reg reg_wr_req_s; 188reg [13:0] reg_wr_addr_s; 189reg [31:0] reg_wr_data_s; 190reg reg_rd_req_s; 191reg [13:0] reg_rd_addr_s; 192wire reg_rd_resp_s; 193wire [31:0] reg_rd_data_s; 194 195n3xx_npio_qsfp_wrapper #( 196 .LANES(1), // Number of lanes of Aurora to instantiate (Supported = {1,2,3,4}) 197 .REG_BASE(32'h0), // Base register address 198 .PORTNUM_BASE(4), // Base port number for discovery 199 .REG_DWIDTH(32), // Width of regport address bus 200 .REG_AWIDTH(14) // Width of regport data bus 201) qsfp_wrapper_inst ( 202 // Clocks and Resets 203 .areset(GSR), 204 .bus_clk(bus_clk), 205 .misc_clk(aurora_init_clk), 206 .bus_rst(GSR), 207 .gt_refclk(aurora_refclk), 208 .gt_clk156(aurora_clk156), 209 // Serial lanes 210 .txp(SFP_LN1_P), 211 .txn(SFP_LN1_N), 212 .rxp(SFP_LN0_P), 213 .rxn(SFP_LN0_N), 214 // AXIS input interface 215 .s_axis_tdata(loop_tdata), 216 .s_axis_tlast(loop_tlast), 217 .s_axis_tvalid(~s_bist_loopback & loop_tvalid), 218 .s_axis_tready(loop_tready), 219 // AXIS output interface 220 .m_axis_tdata(loop_tdata), 221 .m_axis_tlast(loop_tlast), 222 .m_axis_tvalid(loop_tvalid), 223 .m_axis_tready(~s_bist_loopback & loop_tready), 224 // Register ports 225 .reg_wr_req(reg_wr_req_s), //input reg_wr_req, 226 .reg_wr_addr(reg_wr_addr_s), //input [REG_AWIDTH-1:0] reg_wr_addr, 227 .reg_wr_data(reg_wr_data_s), //input [REG_DWIDTH-1:0] reg_wr_data, 228 .reg_rd_req(reg_rd_req_s), //input reg_rd_req, 229 .reg_rd_addr(reg_rd_addr_s), //input [REG_AWIDTH-1:0] reg_rd_addr, 230 .reg_rd_resp(reg_rd_resp_s), //output reg_rd_resp, 231 .reg_rd_data(reg_rd_data_s), //output [REG_DWIDTH-1:0] reg_rd_data, 232 233 .link_up(s_link_up), 234 .activity() 235); 236 237 //Testbench variables 238 cvita_hdr_t header, header_out; 239 cvita_stats_t stats; 240 logic [63:0] crc_cache; 241 242 //------------------------------------------ 243 //Main thread for testbench execution 244 //------------------------------------------ 245 initial begin : tb_main 246 `TEST_CASE_START("Wait for reset"); 247 while (GSR) @(posedge aurora_refclk); 248 `TEST_CASE_DONE((~GSR)); 249 250 m_bist_gen <= 1'b0; 251 m_bist_rate <= 6'd0; 252 m_bist_check <= 1'b0; 253 s_bist_loopback <= 1'b0; 254 255 m_tx_chdr.push_bubble(); 256 257 `TEST_CASE_START("Wait for master channel to come up"); 258 while (m_channel_up !== 1'b1) @(posedge au_user_clk); 259 `TEST_CASE_DONE(1'b1); 260 261 `TEST_CASE_START("Wait for slave channel to come up. Uses QSFP Wrapper"); 262 while (s_link_up !== 1'b1) @(posedge bus_clk); 263 `TEST_CASE_DONE(1'b1); 264 265 `TEST_CASE_START("Run PRBS BIST"); 266 s_bist_loopback <= PACKET_MODE; 267 $display("Need to interact with regport to set s_bist_loopback."); 268 reg_wr_req_s <= 1; 269 reg_wr_addr_s <= 4; 270 reg_wr_data_s <= 4; 271 @(posedge bus_clk); 272 repeat (3) @(posedge au_user_clk); 273 reg_wr_req_s <= 0; 274 m_bist_rate <= 6'd60; 275 m_bist_gen <= 1'b1; 276 m_bist_check <= 1'b1; 277 @(posedge au_user_clk); 278 while (m_bist_locked !== 1'b1) @(posedge au_user_clk); 279 repeat (512) @(posedge au_user_clk); 280 `ASSERT_ERROR(m_bist_samps>256, "BIST: Num samples incorrect"); 281 `ASSERT_ERROR(m_bist_errors===36'd0, "BIST: Errors!"); 282 @(posedge au_user_clk); 283 m_bist_gen <= 1'b0; 284 repeat (256) @(posedge au_user_clk); 285 m_bist_check <= 1'b0; 286 `TEST_CASE_DONE(1'b1); 287 288 header = '{ 289 pkt_type:DATA, has_time:0, eob:0, seqnum:12'h666, 290 length:0, src_sid:$random, dst_sid:$random, timestamp:64'h0}; 291 292 `TEST_CASE_START("Fill up empty FIFO then drain (short packet)"); 293 m_rx_chdr.axis.tready = 0; 294 m_tx_chdr.push_ramp_pkt(16, 64'd0, 64'h100, header); 295 m_rx_chdr.axis.tready = 1; 296 m_rx_chdr.wait_for_pkt_get_info(header_out, stats); 297 `ASSERT_ERROR(stats.count==16, "Bad packet: Length mismatch"); 298 `ASSERT_ERROR(header.src_sid==header_out.src_sid, "Bad packet: Wrong Src SID"); 299 `ASSERT_ERROR(header.dst_sid==header_out.dst_sid, "Bad packet: Wrong Dst SID"); 300 `TEST_CASE_DONE(1); 301 302 `TEST_CASE_START("Fill up empty FIFO then drain (long packet)"); 303 m_rx_chdr.axis.tready = 0; 304 m_tx_chdr.push_ramp_pkt(256, 64'd0, 64'h100, header); 305 m_rx_chdr.axis.tready = 1; 306 m_rx_chdr.wait_for_pkt_get_info(header_out, stats); 307 `ASSERT_ERROR(stats.count==256, "Bad packet: Length mismatch"); 308 `ASSERT_ERROR(header.src_sid==header_out.src_sid, "Bad packet: Wrong Src SID"); 309 `ASSERT_ERROR(header.dst_sid==header_out.dst_sid, "Bad packet: Wrong Dst SID"); 310 `TEST_CASE_DONE(1); 311 312 header = '{ 313 pkt_type:DATA, has_time:1, eob:0, seqnum:12'h666, 314 length:0, src_sid:$random, dst_sid:$random, timestamp:64'h0}; 315 316 `TEST_CASE_START("Concurrent read and write (single packet)"); 317 repeat (10) @(posedge au_user_clk); //Wait for clear to go low 318 m_rx_chdr.axis.tready = 1; 319 fork 320 begin 321 m_tx_chdr.push_ramp_pkt(200, 64'd0, 64'h100, header); 322 end 323 begin 324 m_rx_chdr.wait_for_pkt_get_info(header_out, stats); 325 end 326 join 327 crc_cache = stats.crc; //Cache CRC for future test cases 328 `ASSERT_ERROR(stats.count==201, "Bad packet: Length mismatch"); 329 `TEST_CASE_DONE(1); 330 331 `TEST_CASE_START("Concurrent read and write (multiple packets)"); 332 m_rx_chdr.axis.tready = 1; 333 fork 334 begin 335 repeat (20) begin 336 m_tx_chdr.push_ramp_pkt(20, 64'd0, 64'h100, header); 337 m_tx_chdr.push_bubble(); 338 end 339 end 340 begin 341 repeat (20) begin 342 m_rx_chdr.wait_for_pkt_get_info(header_out, stats); 343 `ASSERT_ERROR(stats.count==21, "Bad packet: Length mismatch"); 344 `ASSERT_ERROR(crc_cache==stats.crc, "Bad packet: Wrong CRC"); 345 end 346 end 347 join 348 `TEST_CASE_DONE(1); 349 350 `TEST_CASE_START("Validate no drops (master)"); 351 `TEST_CASE_DONE((m_overruns === 32'd0)); 352 353 `TEST_CASE_START("Validate no drops (slave)"); 354 reg_rd_req_s <= 1; 355 reg_rd_addr_s <= 'h20; 356 @(posedge reg_rd_resp_s) 357 reg_rd_req_s <= 0; 358 s_overruns <= reg_rd_data_s; 359 `TEST_CASE_DONE((s_overruns === 32'd0)); 360 361 s_bist_loopback <= 1'b1; 362 363 `TEST_CASE_START("Run PRBS BIST (Loopback Mode)"); 364 @(posedge au_user_clk); 365 m_bist_gen <= 1'b1; 366 m_bist_rate <= 6'd60; 367 m_bist_check <= 1'b1; 368 @(posedge au_user_clk); 369 while (m_bist_locked !== 1'b1) @(posedge au_user_clk); 370 repeat (512) @(posedge au_user_clk); 371 `ASSERT_ERROR(m_bist_samps>256, "BIST: Num samples incorrect"); 372 `ASSERT_ERROR(m_bist_errors===36'd0, "BIST: Errors!"); 373 @(posedge au_user_clk); 374 m_bist_gen <= 1'b0; 375 repeat (256) @(posedge au_user_clk); 376 m_bist_check <= 1'b0; 377 `TEST_CASE_DONE(1'b1); 378 379 s_bist_loopback <= 1'b0; 380 381 `TEST_CASE_START("Validate no drops (master)"); 382 `TEST_CASE_DONE((m_overruns === 32'd0)); 383 384 `TEST_CASE_START("Validate no drops (slave)"); 385 reg_rd_req_s <= 1; 386 reg_rd_addr_s <= 'h20; 387 @(posedge reg_rd_resp_s) 388 reg_rd_req_s <= 0; 389 s_overruns <= reg_rd_data_s; 390 `TEST_CASE_DONE((s_overruns === 32'd0)); 391 392 `TEST_BENCH_DONE; 393 end 394 395endmodule 396