天天看點

Verilog設計執行個體(1)線性回報移位寄存器(LFSR)

博文目錄

  • 寫在前面
  • 正文
    • 原理
    • Verilog實作
    • 仿真測試
    • 代碼提示
  • 參考資料
  • 交個朋友

相關博文

部落格首頁

注:學習交流使用!

線性回報移位寄存器(LFSR)的英文全稱為:Linear Feedback Shift Register。

賽靈思公司的高速序列槽IP核示例程式經常以LFSR為例,例如Aurora IP的例子程式:

//______________________________ Transmit Data  __________________________________   
    //Transmit data when TX_DST_RDY_N is asserted.
    //Random data is generated using XNOR feedback LFSR
    //TX_SRC_RDY_N is asserted on every cycle with data
    always @(posedge USER_CLK)
        if(reset_c)
        begin
            data_lfsr_r          <=  `DLY    16'hABCD;  //random seed value
            TX_SRC_RDY_N    <=  `DLY    1'b1;   
        end
        else if(!TX_DST_RDY_N)
        begin
            data_lfsr_r          <=  `DLY    {!{data_lfsr_r[3]^data_lfsr_r[12]^data_lfsr_r[14]^data_lfsr_r[15]},
                                data_lfsr_r[0:14]};
            TX_SRC_RDY_N    <=  `DLY    1'b0;
        end
   
    //Connect TX_D to the DATA LFSR register
    assign  TX_D    =   {1{data_lfsr_r}};

      

相關部落格連結

LFSR代表線性回報移位寄存器,它是一種在FPGA内部有用的設計。 LFSR易于合成,這意味着它們占用的資源相對較少,并且可以在FPGA内部以很高的時鐘速率運作。 使用LFSR可以使許多應用受益,包括:

  • 計數器(Counters)
  • 測試碼型發生器(Test Pattern Generators)
  • 資料加擾(Data Scrambling)
  • 密碼學(Cryptography)

線性回報移位寄存器實作為FPGA内部的一系列觸發器,這些觸發器連接配接在一起作為移位寄存器。 移位寄存器鍊的多個抽頭用作XOR或XNOR門的輸入。 然後,此門的輸出用作對移位寄存器鍊開始的回報,是以用作LFSR中的回報。

例如5bit的LFSR的一種形式:

Verilog設計執行個體(1)線性回報移位寄存器(LFSR)

運作LFSR時,由各個觸發器生成的模式是僞随機的,這意味着它接近随機。 它不是完全随機的,因為從LFSR模式的任何狀态,您都可以預測下一個狀态。 有一些重要的移位寄存器屬性需要注意:

  • LFSR模式是僞随機的。
  • 輸出模式是确定性的。 您可以通過了解XOR門的位置以及目前模式來确定下一個狀态。

    當抽頭使用XOR門時,全0的模式不會出現。 由于0與0異或将始終産生0,是以LFSR将停止運作。

  • 當抽頭使用XNOR門時,全1的模式将不會出現。 由于将1與1進行異或運算将始終産生1,是以LFSR将停止運作。
  • 任何LFSR的最大可能疊代次數= 2^Bits-1

更長的LFSR将花費更長的時間來運作所有疊代。 N位LFSR的最大可能疊代次數為2^N-1。

如果您考慮一下,所有N位長的東西的所有可能模式都是2^N。 是以,隻有一種模式無法使用LFSR表示。 當使用XOR門時,該模式全為0,而使用XNOR門作為您的回報門時全為1。

VHDL和Verilog代碼建立所需的任何N位寬的LFSR。 它使用多項式(這是LFSR背後的數學方法)為每個位寬建立最大可能的LFSR長度。

是以,對于3位,需要2^3-1 = 7個時鐘來運作所有可能的組合;

對于4位:2^4-1 = 15;

對于5位:2^5-1 = 31,依此類推。

我基于XNOR實作 以允許FPGA在LFSR上以全零狀态啟動。 這是Xilinx釋出的所有LFSR模式的完整表。

下面給出Verilog實作代碼:

`timescale 1ns / 1ps
//
// Company: 
// Engineer: Reborn Lee
// Create Date: 2020/06/01 12:50:38
// Design Name: 
// Module Name: lfsr
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module lfsr #(parameter NUM_BITS = 3)(
   input i_Clk,
   input i_Enable,
 
   // data valid
   input i_Seed_DV,

   // Optional Seed Value
   input [NUM_BITS-1:0] i_Seed_Data,
 
   output [NUM_BITS-1:0] o_LFSR_Data,
   output o_LFSR_Done

    );

  // internal variables
  reg [NUM_BITS:1] r_LFSR = 0;
  reg              r_XNOR;
 
 
  // Purpose: Load up LFSR with Seed if Data Valid (DV) pulse is detected.
  // Othewise just run LFSR when enabled.
    always @(posedge i_Clk)
    begin
      if (i_Enable == 1'b1)
      begin
          if (i_Seed_DV == 1'b1)
            r_LFSR <= i_Seed_Data;
          else
            r_LFSR <= {r_LFSR[NUM_BITS-1:1],r_XNOR}; //left right
      end
    end

// Create Feedback Polynomials.  Based on Application Note:
  // http://www.xilinx.com/support/documentation/application_notes/xapp052.pdf
    always @(*)
    begin
      case (NUM_BITS)
        3: begin
          r_XNOR = r_LFSR[3] ^~ r_LFSR[2];
        end
        4: begin
          r_XNOR = r_LFSR[4] ^~ r_LFSR[3];
        end
        5: begin
          r_XNOR = r_LFSR[5] ^~ r_LFSR[3];
        end
        6: begin
          r_XNOR = r_LFSR[6] ^~ r_LFSR[5];
        end
        7: begin
          r_XNOR = r_LFSR[7] ^~ r_LFSR[6];
        end
        8: begin
          r_XNOR = r_LFSR[8] ^~ r_LFSR[6] ^~ r_LFSR[5] ^~ r_LFSR[4];
        end
        9: begin
          r_XNOR = r_LFSR[9] ^~ r_LFSR[5];
        end
        10: begin
          r_XNOR = r_LFSR[10] ^~ r_LFSR[7];
        end
        11: begin
          r_XNOR = r_LFSR[11] ^~ r_LFSR[9];
        end
        12: begin
          r_XNOR = r_LFSR[12] ^~ r_LFSR[6] ^~ r_LFSR[4] ^~ r_LFSR[1];
        end
        13: begin
          r_XNOR = r_LFSR[13] ^~ r_LFSR[4] ^~ r_LFSR[3] ^~ r_LFSR[1];
        end
        14: begin
          r_XNOR = r_LFSR[14] ^~ r_LFSR[5] ^~ r_LFSR[3] ^~ r_LFSR[1];
        end
        15: begin
          r_XNOR = r_LFSR[15] ^~ r_LFSR[14];
        end
        16: begin
          r_XNOR = r_LFSR[16] ^~ r_LFSR[15] ^~ r_LFSR[13] ^~ r_LFSR[4];
          end
        17: begin
          r_XNOR = r_LFSR[17] ^~ r_LFSR[14];
        end
        18: begin
          r_XNOR = r_LFSR[18] ^~ r_LFSR[11];
        end
        19: begin
          r_XNOR = r_LFSR[19] ^~ r_LFSR[6] ^~ r_LFSR[2] ^~ r_LFSR[1];
        end
        20: begin
          r_XNOR = r_LFSR[20] ^~ r_LFSR[17];
        end
        21: begin
          r_XNOR = r_LFSR[21] ^~ r_LFSR[19];
        end
        22: begin
          r_XNOR = r_LFSR[22] ^~ r_LFSR[21];
        end
        23: begin
          r_XNOR = r_LFSR[23] ^~ r_LFSR[18];
        end
        24: begin
          r_XNOR = r_LFSR[24] ^~ r_LFSR[23] ^~ r_LFSR[22] ^~ r_LFSR[17];
        end
        25: begin
          r_XNOR = r_LFSR[25] ^~ r_LFSR[22];
        end
        26: begin
          r_XNOR = r_LFSR[26] ^~ r_LFSR[6] ^~ r_LFSR[2] ^~ r_LFSR[1];
        end
        27: begin
          r_XNOR = r_LFSR[27] ^~ r_LFSR[5] ^~ r_LFSR[2] ^~ r_LFSR[1];
        end
        28: begin
          r_XNOR = r_LFSR[28] ^~ r_LFSR[25];
        end
        29: begin
          r_XNOR = r_LFSR[29] ^~ r_LFSR[27];
        end
        30: begin
          r_XNOR = r_LFSR[30] ^~ r_LFSR[6] ^~ r_LFSR[4] ^~ r_LFSR[1];
        end
        31: begin
          r_XNOR = r_LFSR[31] ^~ r_LFSR[28];
        end
        32: begin
          r_XNOR = r_LFSR[32] ^~ r_LFSR[22] ^~ r_LFSR[2] ^~ r_LFSR[1];
        end
 
      endcase // case (NUM_BITS)
    end // always @ (*)

    assign o_LFSR_Data = r_LFSR[NUM_BITS:1];
 
 	// Conditional Assignment (?)
 	assign o_LFSR_Done = (r_LFSR[NUM_BITS:1] == i_Seed_Data) ? 1'b1 : 1'b0;


endmodule

      

給出一個簡單的仿真測試:

`timescale 1ns / 1ps
module lfsr_tb ();
 
  parameter c_NUM_BITS = 4;
   
  reg r_Clk = 1'b0;
   
  wire [c_NUM_BITS-1:0] w_LFSR_Data;
  wire w_LFSR_Done;
   
  lfsr #(.NUM_BITS(c_NUM_BITS)) LFSR_inst
         (.i_Clk(r_Clk),
          .i_Enable(1'b1),
          .i_Seed_DV(1'b0),
          .i_Seed_Data({c_NUM_BITS{1'b0}}), // Replication
          .o_LFSR_Data(w_LFSR_Data),
          .o_LFSR_Done(w_LFSR_Done)
          );
  
  always @(*)
    #10 r_Clk <= ~r_Clk; 
   
endmodule // LFSR_TB
      

仿真結果:

Verilog設計執行個體(1)線性回報移位寄存器(LFSR)

值得注意的是r_LFSR的定義,内部位從1到NUM_BITS,而非0到NUM_BITS -1;

reg [NUM_BITS:1] r_LFSR = 0;
      

這就意味着移位代碼這樣寫:

r_LFSR <= {r_LFSR[NUM_BITS-1:1],r_XNOR}; //left right
      

也就是低位往高位移,也即左移。

這是根據這張圖來的:

Verilog設計執行個體(1)線性回報移位寄存器(LFSR)

至于仿真檔案中對仿真輸入設計的也十分簡單,就是單純讓種子為0,也即初始值為0,之後進行回報移位操作。

lfsr #(.NUM_BITS(c_NUM_BITS)) LFSR_inst
         (.i_Clk(r_Clk),
          .i_Enable(1'b1),
          .i_Seed_DV(1'b0),
          .i_Seed_Data({c_NUM_BITS{1'b0}}), // Replication
          .o_LFSR_Data(w_LFSR_Data),
          .o_LFSR_Done(w_LFSR_Done)
          );
      

在設計檔案内部,r_LFSR初始值就是為0,是以,不給種子也可以,反正i_Seed_DV本身在測試檔案中就無效。

關于回報多項式是如何确定的呢?

正是上面提供的文檔:

抽頭确定

Verilog設計執行個體(1)線性回報移位寄存器(LFSR)

此表列出了最大長度為168位的LFSR計數器的相應抽頭。前40位的基本描述和表最初在XCELL中釋出,并在1993年和1994年Xilinx資料手冊的第9-24頁上重印。

  • n位LFSR計數器的最大序列長度可以是2^n-1。在這種情況下,它會經曆所有可能的代碼排列,除了一個鎖定狀态。
  • 最大長度的n位LFSR計數器由一個n位移位寄存器組成,該移位寄存器在從最後輸出Qn到第一輸入D1的回報路徑中具有XNOR。XNOR将鎖定狀态設為all-one狀态,也就是說如果種子為全1,則LFSR将鎖定,其最終移位結果永遠為1;XOR将鎖定狀态設為all-zeros狀态。
  • 對于普通的Xilinx應用程式,全1的觸發器都更容易避免,因為“預設情況下”觸發器在全零狀态下喚醒。
  • Table3描述了必須用作XNOR輸入的輸出。LFSR輸出通常标記為1到n,1是移位寄存器的第一級,n是最後一級。這與二進制計數器的傳統0到(n-1)表示法不同。多輸入XNOR也稱為均勻奇偶校驗電路。
  • 請注意,此表中描述的連接配接不一定唯一;某些其他連接配接也可能導緻最大長度序列。