用RTL实现对DDR的BERT测试

作者:Jacky Gao,AMD开发者;来源:AMD开发者社区

本文通过用RTL实现Fibonacci LSFR,对DDR实现误码率测试。并在RTL中实现注入错误码元的功能,模拟误码的情况。此功能可以推广至GT等高速数据总线的BERT测试。

简介

线性反馈移位寄存器(Linear feedback shift register,LFSR)是指给定前一状态的输出,将该输出的线性函数再用作输入的移位寄存器。最常见的运算是异或,即对寄存器的某些位进行异或操作后作为输入,然后进行整体移位。

线性反馈移位寄存器的运算是确定性的,所生成的数据流完全决定于寄存器当时或者之前的状态。其输出的状态是有限的,最终一定会循环。然而,通过本原多项式,线性反馈移位寄存器可以生成看起来是随机的且循环周期非常长的序列。

Fibonacci LFSRs

首先介绍三个重要的概念,

  • LFSR,线性反馈移位寄存器,通过移位操作用来在生成数据流。

  • Tap,即抽头,一般指定进行逻辑运算的寄存器数据位。

  • Seed,即种子,指的是在进行生成PRBS码时的初始值。

LFSR最右端的比特为输出比特。抽头依次与输出比特进行异或运算,然后反馈回最左端的位。最右端位置所生成的序列被称为输出流,赋给寄存器的初始值叫做“种子 “,影响下一个状态的比特位叫做抽头。

例如在下图中,抽头序列为[9,5],分别在第9,5个比特位,则相应的特征多项式为抽头序列1.png

抽头序列2.png


BERT

误码率测试仪(Bit Error Rate Tester,BERT),常用于高速数字通信链路的仿真和测试,用来模拟真实的数据流。

RTL实现

下面我们用RTL实现PRBS和BERT,并在PRBS中加入注入error的功能,模拟传输过程中误码的的情景。

prbs的实现

除了实现LFSR序列,我们还在端口中加入errror信号 ,在有效时我们会在发生序列中加入一位误码。实现的代码如下:

if (ENA_i === 1'b 1 && READY_i === 1'b 1)
        begin
        shift_data = shift_reg;
        for (i = 0; i <= DW - 1; i = i + 1)
          begin
          feedback = shift_data[LENGTH - 1];
          for (j = 0; j <= LENGTH - 2; j = j + 1)
            begin
            if (TAPS[j] === 1'b 1)
              feedback = feedback ^ shift_data[j];
            end
          shift_data = {shift_data[30:0], feedback};
          if (i === 0 & error === 1'b 1)
            begin
            DATA_o[DW - 1 - i] <= ~shift_data[LENGTH - 1];
            error <= 1'b 0;   
            end
          else
            DATA_o[DW - 1 - i] <= shift_data[LENGTH - 1];
          end
        shift_reg <= shift_data;
        end


bert的实现

BERT模块以当前的输入数据作为种子,通过抽头计算LSFR序列,并与后面的数据按位比较。

我们通过ERROR_COUNT和WORD_COUNT分别输出检测到的误码和总共的码元数,这样顶层的模块可以计算出实际的误码率。

if(VALID_i === 1'b 1)
        begin
          shift_data = shift_reg;
          errors = 6'b 0;
          for (i = 0; i <= DW - 1; i = i + 1)
            begin
              feedback = shift_data[LENGTH-1];
              for (j = 0; j <= LENGTH - 2; j = j + 1)
                if (TAPS[j] == 1'b 1)
                  feedback = feedback ^ shift_data[j];
              shift_data = {shift_data[30:0], feedback};
              if (data_reg[DW-1-i] != shift_data[LENGTH-1])
                errors = errors + 1;
            end
          shift_reg    <= shift_data;
          if (error_count[32] == 1'b 0)
            begin
            error_count   <= error_count + errors;
            ERROR_COUNT_o <= error_count[31:0];
            end
          else
            ERROR_COUNT_o <= {32{1'b 1}};
          if (word_count[32] == 1'b 0)
            begin
              word_count   <= word_count + 1;
              WORD_COUNT_o <= word_count[31:0];
            end
          else
            WORD_COUNT_o <= {32{1'b 1}};
        end


测试结果

我们以MIG为例,在Vivado中创建MIG的参考工程,然后修改顶层example_top模块,添加prbs和bert的实例,并在固定的时间注入误码。

通过下面的仿真结果可以看到,bert正确检测到了两次注入的误码,并把误码累加器递增。

完整的测试工程请参考附件。所有的代码都是可以综合的,可以实际上板测试。

测试.png