赞
踩
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 )
- );
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。