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?