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?