Checking a really fast PRBS, we again use multiple wide checkers in parallel.
Now on to the receive side. Again we're set up for 4 patterns to match the transmit side. The errors are broken into ones and zeros errors. The code can be easily modified to just generate errors by the reader.
We start with an 8 bit prbs checker
module rx_prbs_8 (
// Outputs
o_error, o_bad,
// Inputs
i_clk, i_reset, i_prbs_data, prbs_select
);
input i_clk;
input i_reset;
input [7:0] i_prbs_data;
input [1:0] prbs_select;
output [2:0] o_error;
output o_bad;
reg o_bad;
reg [2:0] o_error;
reg [31:0] prbs_15, prbs_23, prbs_31, prbs_7,d;
reg [7:0] error_bit;
reg [7:0] i_prbs_data_p3,i_prbs_data_p2,i_prbs_data_p1;
integer i;
always @ (posedge i_clk)
begin
if (i_reset) //for sims only since the reload will put this in a known state
begin
error_bit <= 0;
i_prbs_data_p1 <= 8'h0;
i_prbs_data_p2 <= 8'h0;
i_prbs_data_p3 <= 8'h0;
o_bad <= 1'h0;
o_error <= 3'h0;
prbs_15 <= 32'h0;
prbs_23 <= 32'h0;
prbs_31 <= 32'h0;
prbs_7 <= 32'h0;
end // if (i_reset)
else
begin
//although we only get 8 bits per clock, we need a 32 bit history
i_prbs_data_p1 <= i_prbs_data;
i_prbs_data_p2 <= i_prbs_data_p1;
i_prbs_data_p3 <= i_prbs_data_p2;
/*****************************************
*reload if the errors are excessive
* *****************************************/
if (o_bad)
begin
prbs_15 <= {i_prbs_data_p3,i_prbs_data_p2,i_prbs_data_p1,i_prbs_data};
prbs_23 <= {i_prbs_data_p3,i_prbs_data_p2,i_prbs_data_p1,i_prbs_data};
prbs_31 <= {i_prbs_data_p3,i_prbs_data_p2,i_prbs_data_p1,i_prbs_data};
prbs_7 <= {i_prbs_data_p3,i_prbs_data_p2,i_prbs_data_p1,i_prbs_data};
end // if (o_bad)
else
/*****************************************
*compute next expected data for the prbs
* **************************************/
begin
d = prbs_7;
repeat (8) d = {d,d[6]^d[5]}; //prbs7
prbs_7 <= d;
d = prbs_15;
repeat (8) d = {d,d[14]^d[13]}; //prbs15
prbs_15 <= d;
d = prbs_23;
repeat (8) d = {d,d[22]^d[17]}; //prbs23
prbs_23 <= d;
d = prbs_31;
repeat (8) d = {d,d[30]^d[27]}; //prbs31
prbs_31 <= d;
end // else: !if(o_bad)
/*********************************************
*compare the expected data to the received data
* ************************************************/
case (prbs_select)
0: error_bit <= prbs_7 ^ i_prbs_data_p1;//7
1: error_bit <= prbs_15 ^ i_prbs_data_p1;//15
2: error_bit <= prbs_23 ^ i_prbs_data_p1;//23
3: error_bit <= prbs_31 ^ i_prbs_data_p1;//31
endcase // case(prbs_select)
/*********************************************
* count up the errors
********************************************/
d=0;
for (i=0;i<8;i=i+1)
d = (d + error_bit[i]);
//more than 3 bit results is an error and will be reloaded anyway.
o_error <= (d > 7) ? 7 : d ;//limit to 3 bit result
o_bad <= d > 3;
end // else: !if(i_reset)
end // always @ (posedge i_clk)
endmodule // rx_prbs_8
Again we need to combine 16 of these into one module to check the whole 40Gbs stream. But what about teh deskew channel? This is a special case. We need to go back to teh subsample stuff. Each channel of the SFI5 is a subsample of the full 40Gbs stream. That means that each channel in turn is a PRBS stream with the same pattern. There is no requirement for each channel on the tx side to line up with a particular channel on the rx side. Depending on how the serdes line up likely the channels on the tx side will be split across rx channels. But each channel is a 1/16 sub sample of the full pattern, which means it in turn is the same pattern. That means we can ignore the deskew channel for this special case. More on the deskew channel later. But for now lets look at the 16 PRBS checkers being instantiated.
module sfi5_rx (
// Outputs
o_error, o_bad,
// Inputs
i_clk_in, i_reset, i_ch_0, i_ch_1, i_ch_2, i_ch_3, i_ch_4, i_ch_5,
i_ch_6, i_ch_7, i_ch_8, i_ch_9, i_ch_a, i_ch_b, i_ch_c, i_ch_d,
i_ch_e, i_ch_f, i_ch_deskew, prbs_select
);
input i_clk_in;
input i_reset; //for sims
input [7:0] i_ch_0, i_ch_1, i_ch_2, i_ch_3, i_ch_4, i_ch_5,
i_ch_6, i_ch_7, i_ch_8, i_ch_9, i_ch_a, i_ch_b,
i_ch_c, i_ch_d, i_ch_e, i_ch_f, i_ch_deskew;
output [5:0] o_error;
output o_bad;
input [1:0] prbs_select;
wire [7:0] ch[0:15];
wire [15:0] bad;
reg o_bad;
wire [2:0] error[0:15];
reg [4:0] error_a, error_b, error_c, error_d;
reg [6:0] o_error;
//convert to an array for the inputs.
assign ch['h0] = i_ch_0;
assign ch['h1] = i_ch_1;
assign ch['h2] = i_ch_2;
assign ch['h3] = i_ch_3;
assign ch['h4] = i_ch_4;
assign ch['h5] = i_ch_5;
assign ch['h6] = i_ch_6;
assign ch['h7] = i_ch_7;
assign ch['h8] = i_ch_8;
assign ch['h9] = i_ch_9;
assign ch['ha] = i_ch_a;
assign ch['hb] = i_ch_b;
assign ch['hc] = i_ch_c;
assign ch['hd] = i_ch_d;
assign ch['he] = i_ch_e;
assign ch['hf] = i_ch_f;
/*******************************************
* instantiate the 16 prbs checkers
* *****************************************/
generate
genvar k;
for (k=0;k<16;k=k+1)
begin: rx_prbs_inst
rx_prbs_8 rx_prbs_8_local
(.i_clk(i_clk_in),
.i_reset(i_reset),
.i_prbs_data(ch[k]),
.o_error(error[k]),
.o_bad(bad[k]),
.prbs_select(prbs_select));
end
endgenerate
/*********************************************
* accumulate the error count
* *****************************************/
always @ (posedge i_clk_in)
begin
if (i_reset)
begin
o_bad <= 16'h0;
error_a <= 5'h0;
error_b <= 5'h0;
error_c <= 5'h0;
error_d <= 5'h0;
o_error <= 7'h0;
end // if (reset)
else
begin
o_bad <= | bad;
error_a <= error['h0] + error['h1] + error['h2] + error['h3];
error_b <= error['h4] + error['h5] + error['h6] + error['h7];
error_c <= error['h8] + error['h9] + error['ha] + error['hb];
error_d <= error['hc] + error['hd] + error['he] + error['hf];
o_error <= error_a + error_b + error_c + error_d;
end // else: !if(reset)
end // always @ (posedge i_clk_in)
endmodule // sfi5_rx
So that's a lot to take for granted. Lets run a simulation.
Still have questions?