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