Links:

Home

Contact us

Samples

CORES

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?