FPGA開發中SRL16E的使用

FPGA開發過程中是免不了要用到移位寄存器的,傳統的移位寄存器是通過寄存器(或者叫觸發器FF)實現的,佔用的是FPGA內部的邏輯資源,當要移位的次數過多時,自然會耗費更多FF資源。

但是如果用LUT(look up table)查找表實現的話就很輕鬆了,LUT是通過提前存儲下一張真值表來實現邏輯運算的,所以非常節省邏輯資源。常用的移位寄存器SRL種類很多,這裏以16bit的SRL16E爲例,說一說怎麼使用它。

Xilinx SRL16E的源碼如下,這個代碼在安裝vivado之後,都會默認自帶,我的代碼路徑如下C:\Xilinx\Vivado\2018.3\data\verilog\src\unisims。此處推薦一個全盤快速搜索工具everything,誰用誰知道。

 

///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 1995/2016 Xilinx, Inc.
// All Right Reserved.
///////////////////////////////////////////////////////////////////////////////
//   ____  ____
//  /   /\/   /
// /___/  \  /    Vendor      : Xilinx
// \   \   \/     Version     : 2017.1
//  \   \         Description : Xilinx Unified Simulation Library Component
//  /   /                  16-Bit Shift Register Look-Up-Table with Clock Enable
// /___/   /\     Filename    : SRL16E.v
// \   \  /  \
//  \___\/\___\
//
///////////////////////////////////////////////////////////////////////////////
// Revision
//    03/23/04 - Initial version.
//    03/11/05 - Add LOC paramter;
//    05/07/08 - 468872 - Add negative setup/hold support
//    12/13/11 - 524859 - Added `celldefine and `endcelldefine
//    04/16/13 - 683925 - add invertible pin support.
// End Revision
///////////////////////////////////////////////////////////////////////////////

`timescale 1 ps/1 ps

`celldefine

module SRL16E #(
  `ifdef XIL_TIMING
  parameter LOC = "UNPLACED",
  `endif
  parameter [15:0] INIT = 16'h0000,
  parameter [0:0] IS_CLK_INVERTED = 1'b0
)(
  output Q,
  
  input A0,
  input A1,
  input A2,
  input A3,
  input CE,
  input CLK,
  input D
);

`ifdef XIL_TIMING
  wire CE_dly;
  wire CLK_dly;
  wire D_dly;
`endif

  reg  [15:0] data = INIT;
  reg first_time = 1'b1;

  initial
  begin
    assign  data = INIT;
    first_time <= #100000 1'b0;
`ifdef XIL_TIMING
    while ((((CLK_dly !== 1'b0) && (IS_CLK_INVERTED == 1'b0)) ||
            ((CLK_dly !== 1'b1) && (IS_CLK_INVERTED == 1'b1))) &&
           (first_time == 1'b1)) #1000;
`else
    while ((((CLK !== 1'b0) && (IS_CLK_INVERTED == 1'b0)) ||
            ((CLK !== 1'b1) && (IS_CLK_INVERTED == 1'b1))) &&
           (first_time == 1'b1)) #1000;
`endif
    deassign data;
  end

`ifdef XIL_TIMING
generate
if (IS_CLK_INVERTED == 1'b0) begin : generate_block1
  always @(posedge CLK_dly) begin
    if (CE_dly == 1'b1) begin
      data[15:0] <= {data[14:0], D_dly};
    end
  end
end else begin : generate_block1
  always @(negedge CLK_dly) begin
    if (CE_dly == 1'b1) begin
      data[15:0] <= {data[14:0], D_dly};
    end
  end
end
endgenerate
`else
generate
if (IS_CLK_INVERTED == 1'b0) begin : generate_block1
  always @(posedge CLK) begin
    if (CE == 1'b1) begin
      data[15:0] <= {data[14:0], D};
    end
  end
end else begin : generate_block1
  always @(negedge CLK) begin
    if (CE == 1'b1) begin
      data[15:0] <= {data[14:0], D};
    end
  end
end
endgenerate
`endif

  assign Q = data[{A3, A2, A1, A0}];

`ifdef XIL_TIMING

  reg notifier;

  wire sh_clk_en_p;
  wire sh_clk_en_n;
  wire sh_ce_clk_en_p;
  wire sh_ce_clk_en_n;

  always @(notifier) 
    data[0] = 1'bx;

  assign sh_clk_en_p = ~IS_CLK_INVERTED;
  assign sh_clk_en_n = IS_CLK_INVERTED;
  assign sh_ce_clk_en_p = CE && ~IS_CLK_INVERTED;
  assign sh_ce_clk_en_n = CE && IS_CLK_INVERTED;
`endif

  specify
    (A0 => Q) = (0:0:0, 0:0:0);
    (A1 => Q) = (0:0:0, 0:0:0);
    (A2 => Q) = (0:0:0, 0:0:0);
    (A3 => Q) = (0:0:0, 0:0:0);
    (CLK => Q) = (100:100:100, 100:100:100);
`ifdef XIL_TIMING
    $period (negedge CLK, 0:0:0, notifier);
    $period (posedge CLK, 0:0:0, notifier);
    $setuphold (negedge CLK, negedge CE, 0:0:0, 0:0:0, notifier,sh_clk_en_n,sh_clk_en_n,CLK_dly,CE_dly);
    $setuphold (negedge CLK, negedge D, 0:0:0, 0:0:0, notifier,sh_ce_clk_en_n,sh_ce_clk_en_n,CLK_dly,D_dly);
    $setuphold (negedge CLK, posedge CE, 0:0:0, 0:0:0, notifier,sh_clk_en_n,sh_clk_en_n,CLK_dly,CE_dly);
    $setuphold (negedge CLK, posedge D, 0:0:0, 0:0:0, notifier,sh_ce_clk_en_n,sh_ce_clk_en_n,CLK_dly,D_dly);
    $setuphold (posedge CLK, negedge CE, 0:0:0, 0:0:0, notifier,sh_clk_en_p,sh_clk_en_p,CLK_dly,CE_dly);
    $setuphold (posedge CLK, negedge D, 0:0:0, 0:0:0, notifier,sh_ce_clk_en_p,sh_ce_clk_en_p,CLK_dly,D_dly);
    $setuphold (posedge CLK, posedge CE, 0:0:0, 0:0:0, notifier,sh_clk_en_p,sh_clk_en_p,CLK_dly,CE_dly);
    $setuphold (posedge CLK, posedge D, 0:0:0, 0:0:0, notifier,sh_ce_clk_en_p,sh_ce_clk_en_p,CLK_dly,D_dly);
    $width (negedge CLK, 0:0:0, 0, notifier);
    $width (posedge CLK, 0:0:0, 0, notifier);
`endif
    specparam PATHPULSE$ = 0;
  endspecify

endmodule

`endcelldefine

SRL16E例化原語如下,輸入是時鐘CLK,使能CE,D,和四位輸出位選擇控制地址A3A2A1A0,輸出是Q。首先要給出一個16bit的初始值,後面的移位就是按照時鐘節拍對初始進行操作的,以代碼爲例,輸入是D(0),意味着這16個週期內每個週期給序列最右邊增加一個0,相應的每個週期對應的序列最左邊的值也會被擠走。第0次移位得到0000000000001111,第二位是1,輸出Q就是1,第一次移位得到0000000000011110,第二位是1,輸出Q就是1,第二次移位得到0000000000111100,第二位是0,輸出Q就是0,以此類推,輸出依次是1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,輸出第幾位由A3A2A1A0做地址控制(第二位輸出對應0001).

modelsim仿真示意圖如下:

 

SRL16E #(
    .INIT   (16'h0000       ), // Initial contents of shift register
    .IS_CLK_INVERTED(1'b0   )  // Optional inversion for CLK
        )
u_ca_gain(
    .Q      (o_ca_out       ), // 1-bit output: SRL Data
    .CE     (1'b1           ), // 1-bit input: Clock enable
    .CLK    (i_clk          ), // 1-bit input: Clock
    .D      (i_ca_in        ), // 1-bit input: SRL Data
    // Depth Selection inputs: A0-A3 select SRL depth
    .A0     (1'b1           ),
    .A1     (1'b1           ),
    .A2     (1'b0           ),
    .A3     (1'b1           ) 
    );

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章