1// 2// Copyright 2016 Ettus Research, A National Instruments Company 3// 4// SPDX-License-Identifier: LGPL-3.0-or-later 5// 6// Module: cat_io_lvds_tb 7// 8// Description: Testbench for cat_io_lvds. 9// 10 11`timescale 1ns/1ps 12 13module cat_io_lvds_tb(); 14 15 localparam CLK_PERIOD = 10; 16 localparam CLK200_PERIOD = 2.5; 17 18 localparam FRAME_SAMPLE = 0; 19 20 localparam USE_CLOCK_IDELAY = 1; 21 localparam USE_DATA_IDELAY = 1; 22 localparam DATA_IDELAY_MODE = "VAR_LOAD"; 23 localparam CLOCK_IDELAY_MODE = "VAR_LOAD"; 24 localparam INPUT_CLOCK_DELAY = 0; 25 localparam INPUT_DATA_DELAY = 0; 26 localparam USE_CLOCK_ODELAY = 1; 27 localparam USE_DATA_ODELAY = 1; 28 localparam DATA_ODELAY_MODE = "VAR_LOAD"; 29 localparam CLOCK_ODELAY_MODE = "VAR_LOAD"; 30 localparam OUTPUT_CLOCK_DELAY = 0; 31 localparam OUTPUT_DATA_DELAY = 0; 32 33 reg [8*19:0] test_status; 34 35 reg clk = 0; 36 reg rx_clk = 0; 37 reg clk200 = 0; 38 39 reg reset; 40 reg mimo; 41 reg [5:0] rx_d; 42 reg rx_frame; 43 reg [7:0] count; 44 45// initial $dumpfile("catcap_ddr_lvds_tb.vcd"); 46// initial $dumpvars(0,catcap_ddr_lvds_tb); 47 48 wire [11:0] i0 = {4'hA,count}; 49 wire [11:0] q0 = {4'hB,count}; 50 wire [11:0] i1 = {4'hC,count}; 51 wire [11:0] q1 = {4'hD,count}; 52 53 wire radio_clk; 54 55 reg [11:0] tx_i0; 56 reg [11:0] tx_q0; 57 reg [11:0] tx_i1; 58 reg [11:0] tx_q1; 59 60 wire [11:0] rx_i0; 61 wire [11:0] rx_q0; 62 wire [11:0] rx_i1; 63 wire [11:0] rx_q1; 64 65 wire rx_aligned; 66 67 wire tx_clk_p, tx_clk_n; 68 wire tx_frame_p, tx_frame_n; 69 wire [5:0] tx_d_p, tx_d_n; 70 71 reg [4:0] ctrl_in_data_delay; 72 reg [4:0] ctrl_in_clk_delay; 73 reg ctrl_ld_in_data_delay; 74 reg ctrl_ld_in_clk_delay; 75 76 reg [4:0] ctrl_out_data_delay; 77 reg [4:0] ctrl_out_clk_delay; 78 reg ctrl_ld_out_data_delay; 79 reg ctrl_ld_out_clk_delay; 80 81 82 //--------------------------------------------------------------------------- 83 // Clock Generation 84 //--------------------------------------------------------------------------- 85 86 // IODELAYCTRL reference clock 87 always #(CLK200_PERIOD) clk200 = ~clk200; 88 89 // Create an internal clock we'll use to drive the data 90 always #(CLK_PERIOD) clk = ~clk; 91 92 // RF interface clock. Half the rate of clk and out of phase 93 always @(negedge clk) rx_clk <= ~rx_clk; 94 95 96 //--------------------------------------------------------------------------- 97 // Tasks 98 //--------------------------------------------------------------------------- 99 100 task BURST; 101 input [31:0] len; 102 input do_mimo; 103 begin 104 count <= 0; 105 repeat(len) 106 begin 107 mimo <= do_mimo; 108 109 // Channel 0 sample 110 @(posedge clk); 111 rx_d <= i0[11:6]; 112 rx_frame <= 1; 113 @(posedge clk); 114 rx_d <= q0[11:6]; 115 rx_frame <= 1; 116 @(posedge clk); 117 rx_d <= i0[5:0]; 118 rx_frame <= ~FRAME_SAMPLE; 119 @(posedge clk); 120 rx_d <= q0[5:0]; 121 rx_frame <= ~FRAME_SAMPLE; 122 123 if (do_mimo) begin 124 // Channel 1 sample 125 @(posedge clk); 126 rx_d <= i1[11:6]; 127 rx_frame <= FRAME_SAMPLE; 128 @(posedge clk); 129 rx_d <= q1[11:6]; 130 rx_frame <= FRAME_SAMPLE; 131 @(posedge clk); 132 rx_d <= i1[5:0]; 133 rx_frame <= 0; 134 @(posedge clk); 135 rx_d <= q1[5:0]; 136 rx_frame <= 0; 137 end else begin 138 if (!FRAME_SAMPLE) begin 139 // When we frame every two samples (one from each channel), in 140 // MIMO mode, we should only grab channel 0. So input garbage on 141 // channel 1 to make sure the data doesn't get used. 142 @(posedge clk); 143 rx_d <= 6'bXXXXXX; 144 rx_frame <= FRAME_SAMPLE; 145 @(posedge clk); 146 rx_d <= 6'bXXXXXX; 147 rx_frame <= FRAME_SAMPLE; 148 @(posedge clk); 149 rx_d <= 6'bXXXXXX; 150 rx_frame <= 0; 151 @(posedge clk); 152 rx_d <= 6'bXXXXXX; 153 rx_frame <= 0; 154 end else begin 155 // When every sample is framed, we might sync align to either 156 // channel (no way to tell them apart), so input the channel 1 157 // data, but we should only see one channel's data duplicated on 158 // both outputs. 159 @(posedge clk); 160 rx_d <= i1[11:6]; 161 rx_frame <= FRAME_SAMPLE; 162 @(posedge clk); 163 rx_d <= q1[11:6]; 164 rx_frame <= FRAME_SAMPLE; 165 @(posedge clk); 166 rx_d <= i1[5:0]; 167 rx_frame <= 0; 168 @(posedge clk); 169 rx_d <= q1[5:0]; 170 rx_frame <= 0; 171 end 172 end 173 174 count <= count + 1; 175 end 176 end 177 endtask // BURST 178 179 180 //--------------------------------------------------------------------------- 181 // Test Procedure 182 //--------------------------------------------------------------------------- 183 184 initial 185 begin 186 // Initial values 187 test_status <= "Reset"; 188 reset = 1; 189 mimo = 1; 190 ctrl_in_data_delay = 5'd0; 191 ctrl_in_clk_delay = 5'd8; 192 ctrl_ld_in_data_delay = 1'b0; 193 ctrl_ld_in_clk_delay = 1'b0; 194 ctrl_out_data_delay = 5'd0; 195 ctrl_out_clk_delay = 5'd16; 196 ctrl_ld_out_data_delay = 1'b0; 197 ctrl_ld_out_clk_delay = 1'b0; 198 repeat(10) @(negedge rx_clk); 199 reset = 0; 200 @(negedge rx_clk); 201 202 // Load new input delay values 203 test_status <= "Load input delays"; 204 ctrl_ld_in_data_delay = 1'b1; 205 ctrl_ld_in_clk_delay = 1'b1; 206 @(negedge rx_clk); 207 ctrl_ld_in_data_delay = 1'b0; 208 ctrl_ld_in_clk_delay = 1'b0; 209 210 // Load new output delay values 211 test_status <= "Load output delays"; 212 ctrl_ld_out_data_delay = 1'b1; 213 ctrl_ld_out_clk_delay = 1'b1; 214 @(negedge rx_clk); 215 ctrl_ld_out_data_delay = 1'b0; 216 ctrl_ld_out_clk_delay = 1'b0; 217 218 // Input data until the Rx circuit aligns 219 test_status <= "Wait align"; 220 while (!rx_aligned) begin 221 BURST(1,1); 222 end 223 224 // Input some new samples 225 test_status <= "Burst 1 (MIMO)"; 226 BURST(30, 1); 227 228 // Reset and do another burst 229 test_status <= "Reset 2"; 230 reset = 1; 231 repeat(20) @(negedge rx_clk); 232 reset = 0; 233 repeat(2) @(negedge rx_clk); 234 235 // Input data until the Rx circuit aligns 236 test_status <= "Wait align 2"; 237 while (!rx_aligned) begin 238 BURST(1,1); 239 end 240 241 // Input some new samples 242 test_status <= "Burst 2 (MIMO)"; 243 BURST(30, 1); 244 245 // Reset and do another burst 246 test_status <= "Reset 3"; 247 reset = 1; 248 repeat(20) @(negedge rx_clk); 249 reset = 0; 250 repeat(2) @(negedge rx_clk); 251 252 // Input data until the Rx circuit aligns in SISO mode 253 test_status <= "Wait align 3"; 254 while (!rx_aligned) begin 255 BURST(1,0); 256 end 257 258 // Switch to SISO mode 259 test_status <= "Burst 3 (SISO)"; 260 BURST(25,0); 261 262 repeat(50) @(negedge rx_clk); 263 264 265 $finish; 266 end 267 268 269 //--------------------------------------------------------------------------- 270 // DUT 271 //--------------------------------------------------------------------------- 272 273 // Loop the Rx interface of cat_io_lvds back to its Tx interface 274 always @(posedge radio_clk) begin 275 tx_i0 = rx_i0; 276 tx_q0 = rx_q0; 277 tx_i1 = rx_i1; 278 tx_q1 = rx_q1; 279 end 280 281 cat_io_lvds #( 282 .INVERT_FRAME_RX (0), 283 .INVERT_DATA_RX (6'b00_0000), 284 .INVERT_FRAME_TX (0), 285 .INVERT_DATA_TX (6'b00_0000), 286 .USE_CLOCK_IDELAY (USE_CLOCK_IDELAY ), 287 .USE_DATA_IDELAY (USE_DATA_IDELAY ), 288 .DATA_IDELAY_MODE (DATA_IDELAY_MODE ), 289 .CLOCK_IDELAY_MODE (CLOCK_IDELAY_MODE ), 290 .INPUT_CLOCK_DELAY (INPUT_CLOCK_DELAY ), 291 .INPUT_DATA_DELAY (INPUT_DATA_DELAY ), 292 .USE_CLOCK_ODELAY (USE_CLOCK_ODELAY ), 293 .USE_DATA_ODELAY (USE_DATA_ODELAY ), 294 .DATA_ODELAY_MODE (DATA_ODELAY_MODE ), 295 .CLOCK_ODELAY_MODE (CLOCK_ODELAY_MODE ), 296 .OUTPUT_CLOCK_DELAY (OUTPUT_CLOCK_DELAY), 297 .OUTPUT_DATA_DELAY (OUTPUT_DATA_DELAY ) 298 ) cat_io_lvds_i0 ( 299 .rst (reset), 300 .clk200 (clk200), 301 302 // Data and frame timing 303 .mimo (mimo), 304 .frame_sample (FRAME_SAMPLE[0]), 305 306 // Delay control interface 307 .ctrl_clk (rx_clk), 308 // 309 .ctrl_in_data_delay (ctrl_in_data_delay), 310 .ctrl_in_clk_delay (ctrl_in_clk_delay), 311 .ctrl_ld_in_data_delay (ctrl_ld_in_data_delay), 312 .ctrl_ld_in_clk_delay (ctrl_ld_in_clk_delay), 313 // 314 .ctrl_out_data_delay (ctrl_out_data_delay), 315 .ctrl_out_clk_delay (ctrl_out_clk_delay), 316 .ctrl_ld_out_data_delay (ctrl_ld_out_data_delay), 317 .ctrl_ld_out_clk_delay (ctrl_ld_out_clk_delay), 318 319 // Baseband sample interface 320 .radio_clk (radio_clk), 321 .radio_clk_2x (), 322 .rx_aligned (rx_aligned), 323 // 324 .rx_i0 (rx_i0), 325 .rx_q0 (rx_q0), 326 .rx_i1 (rx_i1), 327 .rx_q1 (rx_q1), 328 // 329 .tx_i0 (tx_i0), 330 .tx_q0 (tx_q0), 331 .tx_i1 (tx_i1), 332 .tx_q1 (tx_q1), 333 334 // Catalina interface 335 .rx_clk_p (rx_clk), 336 .rx_clk_n (~rx_clk), 337 .rx_frame_p (rx_frame), 338 .rx_frame_n (~rx_frame), 339 .rx_d_p (rx_d), 340 .rx_d_n (~rx_d), 341 // 342 .tx_clk_p (tx_clk_p), 343 .tx_clk_n (tx_clk_n), 344 .tx_frame_p (tx_frame_p), 345 .tx_frame_n (tx_frame_n), 346 .tx_d_p (tx_d_p), 347 .tx_d_n (tx_d_n) 348 ); 349 350endmodule // cat_io_lvds_tb 351