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           ) 
    );

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hyunnnnn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值