A test bench that can be used to check the functionality of the wide parallel PRBS generator/checker.
So that's a lot to take for granted. Lets run a simulation. This test bench combines the 16 SFI5 tx channels into one 40 Gbs stream. Checks that stream for correctness for a PRBS. Then adds a variable delay before demuxing the stream back into 16 rx channels. By adding a variable delay we can control how the data is striped across the incoming channels, and more importantly test that the rx side is correct independant of the alignement of the data between the tx and rx side. To test the locking of the checkers, the 'fiber delay' which changes the striping offset gets changed periodically, and the RX side relocks. Then the pattern is also changed through all 4 patterns as well. Each time, the rx side will relock. The reset on the rx side is optional for actual implementation as the relock will take care of putting all of the logic in the correct state. Unfortunately simulation needs some state to start with. Optionally, there is a commnted out direct connect between the tx and rx sides. Useful for simulation debug.
module test_tx_rx ( ); reg [31:0] prbs_40; reg error_40; reg clk; reg [6:0] channel_counter, rx_channel_counter; reg reset; reg [7:0] byte_shifter_f, byte_shifter_e, byte_shifter_d, byte_shifter_c, byte_shifter_b, byte_shifter_a, byte_shifter_9, byte_shifter_8, byte_shifter_7, byte_shifter_6, byte_shifter_5, byte_shifter_4, byte_shifter_3, byte_shifter_2, byte_shifter_1, byte_shifter_0, rx_byte_shifter_f, rx_byte_shifter_e, rx_byte_shifter_d, rx_byte_shifter_c, rx_byte_shifter_b, rx_byte_shifter_a, rx_byte_shifter_9, rx_byte_shifter_8, rx_byte_shifter_7, rx_byte_shifter_6, rx_byte_shifter_5, rx_byte_shifter_4, rx_byte_shifter_3, rx_byte_shifter_2, rx_byte_shifter_1, rx_byte_shifter_0; reg [15:0] bit_shifter, rx_bit_shifter; reg data_out, data_in; reg tx_clk, rx_clk; wire [7:0] tx_prbs_f, tx_prbs_e, tx_prbs_d, tx_prbs_c, tx_prbs_b, tx_prbs_a, tx_prbs_9, tx_prbs_8, tx_prbs_7, tx_prbs_6, tx_prbs_5, tx_prbs_4, tx_prbs_3, tx_prbs_2, tx_prbs_1, tx_prbs_0, tx_deskew; reg [7:0] rx_prbs_f, rx_prbs_e, rx_prbs_d, rx_prbs_c, rx_prbs_b, rx_prbs_a, rx_prbs_9, rx_prbs_8, rx_prbs_7, rx_prbs_6, rx_prbs_5, rx_prbs_4, rx_prbs_3, rx_prbs_2, rx_prbs_1, rx_prbs_0; reg [31:0] fiber,fiber_p1; wire [6:0] error; wire bad; reg [1:0] prbs_select; reg [15:0] fiber_delay; initial begin clk = 0; channel_counter = 0; rx_channel_counter = 5; reset = 0; prbs_select = 0; fiber_delay = 15; #1000 reset = 1; #2000 reset = 0; #10_000 fiber_delay = fiber_delay + 1; #10_000 fiber_delay = fiber_delay + 1; #10_000 fiber_delay = fiber_delay + 1; #10_000 fiber_delay = fiber_delay + 1; #10_000 prbs_select = 1; #10_000 fiber_delay = fiber_delay + 1; #10_000 fiber_delay = fiber_delay + 1; #10_000 fiber_delay = fiber_delay + 1; #10_000 fiber_delay = fiber_delay + 1; #10_000 prbs_select = 2; #10_000 fiber_delay = fiber_delay + 1; #10_000 fiber_delay = fiber_delay + 1; #10_000 fiber_delay = fiber_delay + 1; #10_000 fiber_delay = fiber_delay + 1; #10_000 prbs_select = 3; #10_000 fiber_delay = fiber_delay + 1; #10_000 fiber_delay = fiber_delay + 1; #10_000 fiber_delay = fiber_delay + 1; #10_000 fiber_delay = fiber_delay + 1; #10_000 $stop; end always clk = #0.0125 ~ clk; //the "40G" clk /******************************* * tx mux side * output is data out which connects to "fiber" variable delay * ******************************/ always @ (posedge clk) begin data_out <= bit_shifter[15]; channel_counter <= channel_counter + 1; if (channel_counter[3:0]=='hf) begin bit_shifter <= {byte_shifter_f[7], byte_shifter_e[7], byte_shifter_d[7], byte_shifter_c[7], byte_shifter_b[7], byte_shifter_a[7], byte_shifter_9[7], byte_shifter_8[7], byte_shifter_7[7], byte_shifter_6[7], byte_shifter_5[7], byte_shifter_4[7], byte_shifter_3[7], byte_shifter_2[7], byte_shifter_1[7], byte_shifter_0[7]}; if (channel_counter[6:4] =='h7) begin byte_shifter_f <= tx_prbs_f; byte_shifter_e <= tx_prbs_e; byte_shifter_d <= tx_prbs_d; byte_shifter_c <= tx_prbs_c; byte_shifter_b <= tx_prbs_b; byte_shifter_a <= tx_prbs_a; byte_shifter_9 <= tx_prbs_9; byte_shifter_8 <= tx_prbs_8; byte_shifter_7 <= tx_prbs_7; byte_shifter_6 <= tx_prbs_6; byte_shifter_5 <= tx_prbs_5; byte_shifter_4 <= tx_prbs_4; byte_shifter_3 <= tx_prbs_3; byte_shifter_2 <= tx_prbs_2; byte_shifter_1 <= tx_prbs_1; byte_shifter_0 <= tx_prbs_0; tx_clk <= 1; end else begin byte_shifter_f <= {byte_shifter_f,1'b0}; byte_shifter_e <= {byte_shifter_e,1'b0}; byte_shifter_d <= {byte_shifter_d,1'b0}; byte_shifter_c <= {byte_shifter_c,1'b0}; byte_shifter_b <= {byte_shifter_b,1'b0}; byte_shifter_a <= {byte_shifter_a,1'b0}; byte_shifter_9 <= {byte_shifter_9,1'b0}; byte_shifter_8 <= {byte_shifter_8,1'b0}; byte_shifter_7 <= {byte_shifter_7,1'b0}; byte_shifter_6 <= {byte_shifter_6,1'b0}; byte_shifter_5 <= {byte_shifter_5,1'b0}; byte_shifter_4 <= {byte_shifter_4,1'b0}; byte_shifter_3 <= {byte_shifter_3,1'b0}; byte_shifter_2 <= {byte_shifter_2,1'b0}; byte_shifter_1 <= {byte_shifter_1,1'b0}; byte_shifter_0 <= {byte_shifter_0,1'b0}; tx_clk <= 1'b0; end end // if (channel_counter[3:0]=='hf) else begin bit_shifter <= {bit_shifter,1'b0}; tx_clk <= 0; end // else: !if(channel_counter[3:0]=='hf) end // always @ (posedge clk) //instantiate the tx tx_prbs sfi5_tx_test ( .i_clk(tx_clk), .i_reset(reset), .prbs_select(prbs_select), .o_prbs_data_0(tx_prbs_0), .o_prbs_data_1(tx_prbs_1), .o_prbs_data_2(tx_prbs_2), .o_prbs_data_3(tx_prbs_3), .o_prbs_data_4(tx_prbs_4), .o_prbs_data_5(tx_prbs_5), .o_prbs_data_6(tx_prbs_6), .o_prbs_data_7(tx_prbs_7), .o_prbs_data_8(tx_prbs_8), .o_prbs_data_9(tx_prbs_9), .o_prbs_data_a(tx_prbs_a), .o_prbs_data_b(tx_prbs_b), .o_prbs_data_c(tx_prbs_c), .o_prbs_data_d(tx_prbs_d), .o_prbs_data_e(tx_prbs_e), .o_prbs_data_f(tx_prbs_f) ); /********************************** * here we add the variable delay between the mux and demux * *******************************/ always @ (posedge clk) begin fiber <= {fiber,data_out}; fiber_p1 <= fiber; data_in <= fiber[fiber_delay]; //this is the delay # //for checking the stream as one 40g prbs if (error_40) prbs_40 <= {fiber,data_out}; else case (prbs_select) 0: prbs_40 <= {prbs_40,prbs_40[6]^prbs_40[5]}; 1: prbs_40 <= {prbs_40,prbs_40[14]^prbs_40[13]}; 2: prbs_40 <= {prbs_40,prbs_40[22]^prbs_40[17]}; 3: prbs_40 <= {prbs_40,prbs_40[30]^prbs_40[27]}; endcase // case(prbs_select) if (prbs_40[31:0] == fiber[31:0]) error_40 <= 0; else error_40 <= 1; end /****************************************************** * and the demux on the recieve side * **************************************/ always @ (posedge clk) begin rx_channel_counter <= rx_channel_counter + 1; rx_bit_shifter <= {rx_bit_shifter,data_in}; if (rx_channel_counter[3:0] == 4'hf) begin rx_byte_shifter_f <= {rx_byte_shifter_f,rx_bit_shifter['hf]}; rx_byte_shifter_e <= {rx_byte_shifter_e,rx_bit_shifter['he]}; rx_byte_shifter_d <= {rx_byte_shifter_d,rx_bit_shifter['hd]}; rx_byte_shifter_c <= {rx_byte_shifter_c,rx_bit_shifter['hc]}; rx_byte_shifter_b <= {rx_byte_shifter_b,rx_bit_shifter['hb]}; rx_byte_shifter_a <= {rx_byte_shifter_a,rx_bit_shifter['ha]}; rx_byte_shifter_9 <= {rx_byte_shifter_9,rx_bit_shifter['h9]}; rx_byte_shifter_8 <= {rx_byte_shifter_8,rx_bit_shifter['h8]}; rx_byte_shifter_7 <= {rx_byte_shifter_7,rx_bit_shifter['h7]}; rx_byte_shifter_6 <= {rx_byte_shifter_6,rx_bit_shifter['h6]}; rx_byte_shifter_5 <= {rx_byte_shifter_5,rx_bit_shifter['h5]}; rx_byte_shifter_4 <= {rx_byte_shifter_4,rx_bit_shifter['h4]}; rx_byte_shifter_3 <= {rx_byte_shifter_3,rx_bit_shifter['h3]}; rx_byte_shifter_2 <= {rx_byte_shifter_2,rx_bit_shifter['h2]}; rx_byte_shifter_1 <= {rx_byte_shifter_1,rx_bit_shifter['h1]}; rx_byte_shifter_0 <= {rx_byte_shifter_0,rx_bit_shifter['h0]}; if (rx_channel_counter[6:4] == 3'h7) begin rx_prbs_f <= rx_byte_shifter_f; rx_prbs_e <= rx_byte_shifter_e; rx_prbs_d <= rx_byte_shifter_d; rx_prbs_c <= rx_byte_shifter_c; rx_prbs_b <= rx_byte_shifter_b; rx_prbs_a <= rx_byte_shifter_a; rx_prbs_9 <= rx_byte_shifter_9; rx_prbs_8 <= rx_byte_shifter_8; rx_prbs_7 <= rx_byte_shifter_7; rx_prbs_6 <= rx_byte_shifter_6; rx_prbs_5 <= rx_byte_shifter_5; rx_prbs_4 <= rx_byte_shifter_4; rx_prbs_3 <= rx_byte_shifter_3; rx_prbs_2 <= rx_byte_shifter_2; rx_prbs_1 <= rx_byte_shifter_1; rx_prbs_0 <= rx_byte_shifter_0; rx_clk <= 1; end else rx_clk <= 0; end // if (rx_channel_counter[3:0] == 4'hf) else rx_clk <= 0; end // always @ (posedge clk) /************************************* * and of course instantiate the rx sfi5 * ********************************/ sfi5_rx sfi5_rx_test ( .i_clk_in(rx_clk), .i_reset(reset), .prbs_select(prbs_select), .i_ch_0(rx_prbs_0), .i_ch_1(rx_prbs_1), .i_ch_2(rx_prbs_2), .i_ch_3(rx_prbs_3), .i_ch_4(rx_prbs_4), .i_ch_5(rx_prbs_5), .i_ch_6(rx_prbs_6), .i_ch_7(rx_prbs_7), .i_ch_8(rx_prbs_8), .i_ch_9(rx_prbs_9), .i_ch_a(rx_prbs_a), .i_ch_b(rx_prbs_b), .i_ch_c(rx_prbs_c), .i_ch_d(rx_prbs_d), .i_ch_e(rx_prbs_e), .i_ch_f(rx_prbs_f), /* skip the mux/demux .i_ch_0(tx_prbs_0), .i_ch_1(tx_prbs_1), .i_ch_2(tx_prbs_2), .i_ch_3(tx_prbs_3), .i_ch_4(tx_prbs_4), .i_ch_5(tx_prbs_5), .i_ch_6(tx_prbs_6), .i_ch_7(tx_prbs_7), .i_ch_8(tx_prbs_8), .i_ch_9(tx_prbs_9), .i_ch_a(tx_prbs_a), .i_ch_b(tx_prbs_b), .i_ch_c(tx_prbs_c), .i_ch_d(tx_prbs_d), .i_ch_e(tx_prbs_e), .i_ch_f(tx_prbs_f), */ .i_ch_deskew(8'h0), .o_error(error), .o_bad(bad) ); always @ (error) $display("error is %d",error); endmodule // test_tx
Still have questions?