系列文章目录:FPGA原理与结构(0)——目录与传送门

目录

一、移位寄存器概述

1、基本概念     

2、LUT实现移位寄存器

3、移位寄存器的应用

4、移位寄存器的功能

5、移位寄存器结构

6、移位寄存器级连

二、移位寄存器数据流

1、动态读操作(移位长度不固定)

2、静态读操作(移位长度固定)

三、移位寄存器例化

1、原语例化

2、vivado推断

2.1采用命令

2.2推断

一、移位寄存器概述

1、基本概念     

        在数字电路中,用于存放二进制数据或代码的电路称为寄存器。寄存器是由具有存储功能的触发器组合起来构成的。一个触发器可以存储一位二进制数据,N个触发器构成的寄存器就可以存放N位二进制数据。根据寄存器的功能,可以分成:基本寄存器和移位寄存器。

        移位寄存器中的数据可以在移位脉冲(时钟信号)作用下依次逐位右移或左移,数据既可以并行输入、并行输出,也可以串行输入、串行输出,还可以并行输入、串行输出,串行输入、并行输出,十分灵活,用途也很广,通常用于数据存储、数据移动和数据操作等。

2、LUT实现移位寄存器

        FPGA实现逻辑功能的重要元素是CLB,一个CLB中有2个SLICE,SLICE根据功能和结构的不同,可以分成SLICEM和SLICEL,SLICEM因为其可读可写的特性,可以实现DRAM或移位寄存器。

        SLICEM可以在不使用触发器的情况下就实现32位的移位寄存器。在这种情况下,每个LUT可以将串行的数据延时1-32个时钟周期。移位输入D(LUT DI1引脚)和移位输出Q31(LUT MC31引脚)可以进行级联,以形成更大的移位寄存器。一个SLICEM的4个LUT6级联可以实现128个时钟周期的延时。多个SLICEM也可以进行组合。但SLICEM之间没有直接连接来构成更长的移位寄存器,在LUT B/C/D处的MC31输出也没有。由此产生的可编程延迟可用于平衡数据pipeline的时间。

3、移位寄存器的应用

        (1)延迟或延迟补偿

        (2)同步FIFO和内容可寻址内存(CAM)

4、移位寄存器的功能

        (1)写操作:带有写使能(WE)的,与时钟(CLK)同步的同步写

        (2)通过Q31的固定的读操作

        (3)动态读取访问

                通过A[4:0]5位地址总线访问

                通过改变地址,任何32位都可以异步读出(在O6 LUT输出处,对应在原语上的Q)    

                此功能对于创建较小的移位寄存器(小于32位)非常有用。

                可以使用一个存储元件或触发器来实现同步读

        (4)移位寄存器不支持复位/置位

5、移位寄存器结构

        下图是一个由LUT构成的32位移位寄存器的结构

        其内部结构如下

        这就是通过LUT实现的移位寄存器的一种形式SRLC32E ,还有一种SRL16E这里不做展开,感兴趣的可以自行查阅《ug953-vivado-7series-libraries》。

        对于SRLC32E这个移位寄存器来说,输入A4、A3、A2、A1和A0决定了移位寄存器的深度,这个深度可以是固定的,也可以是动态可调的。计算公式如下:Depth = (16 x A4) + (8 x A3) + (4 x A2) + (2 x A1) + A0 + 1。主要需要注意最后需要加1。

        端口介绍:

官方给出的verilog原语描述:

// SRLC32E: 32-bit variable length cascadable shift register LUT (Mapped to a SliceM LUT6)
// with clock enable
// 7 Series
// Xilinx HDL Language Template, version 2019.1
SRLC32E #(
 .INIT(32'h00000000) // Initial Value of Shift Register
) SRLC32E_inst (
 .Q(Q), // SRL data output
 .Q31(Q31), // SRL cascade output pin
 .A(A), // 5-bit shift depth select input
 .CE(CE), // Clock enable input
 .CLK(CLK), // Clock input
 .D(D) // SRL data input
);
// End of SRLC32E_inst instantiation

6、移位寄存器级连

        如前所述,MC31输出和移位寄存器之间的专用连接允许将一个移位寄存器的最后一位连接到下一个寄存器的第一位,而不使用LUT O6输出。移位寄存器链和F7AMUX、F7BMUX和F8MUX多路复用器允许一个128位移位寄存器的可寻址访问实现。

        (1)64位移位寄存器实现:

        (2) 96位移位寄存器实现

        (3)128位移位寄存器实现:

         理论上我们当然可以使用多个slice来实现一个大于128深度的移位寄存器,但是在slice之间没有直接的连接来帮助我们实现这样的功能。

二、移位寄存器数据流

1、动态读操作(移位长度不固定)

        (1)输出Q由5位地址决定

        (2)每当一个新地址到达时,在经过访问LUT的时间延迟后,输出Q变化

        (3)读操作是异步的,独立于时钟和时钟使能信号

2、静态读操作(移位长度固定)

        (1)当5位地址固定时(地址固定意味着移位长度固定),输出Q使用相同的比特位

        (2)该模式在一个LUT中实现了从1到32位的任何移位寄存器长度

        (3)移位寄存器长度为(N + 1),其中N为输入地址(0-31)

        (4)输出Q与每一次的移位操作是同步的

        (5)前一位被移到下一个位置,并出现在Q输出上

三、移位寄存器例化

1、原语例化

        之前的内容中已经给出了原语的案例,这里就不进一步展开了,一般在编写HDL代码的时候,除了极个别的特殊情况,我们不推荐使用原语编写。

2、vivado推断

        这里首先要注意的是,移位寄存器是不支持复位和置位的,所以我们的设计中要尽量避免复位和置位,防止vivado推断出现错误。

2.1采用命令

        这里我们可以采用的方式有使用命令 

        (srl_style = “ ”)
        可选择的属性有:
                (1)register:用FF生成SRL
                (2)srl:用LUT生成SRL
                (3)srl_reg:用LUT和FF生成SRL,最后一级深度用FF
                (4)reg_srl:第一级深度用FF,其他用LUT
                (5)reg_srl_reg:第一和最后级深度用FF,其他用LUT
                (6)block:用BRAM生成SRL

        也可以使用命令

        ( shreg_extract = “ ”) 

        可选的属性有:

                (1)yes:使用上述的移位寄存器结构

                (2)no:不使用上述移位寄存器结构

        注意:srl_style命令只能用于静态读取操作!当两者同时出现时,shreg_extract的优先级更高。

//使用寄存器实现移位寄存器
(* srl_style = "register" *) reg [16:0] my_srl;

//使用SRL实现移位寄存器
(* srl_style = "srl" *) reg [16:0] my_srl;

//使用寄存器实现移位寄存器
(* shreg_extract = "no" *) reg [16:0] my_srl;

//使用SRL实现移位寄存器
(* shreg_extract = "yes" *) reg [16:0] my_srl;

2.2推断

        通过设计符合规范的HDL代码,由EDA自行完成推断,综合使用移位寄存器

        这里给出xilinx提供的代码示例:

        (1)32位移位寄存器verilog代码:

// 8-bit Shift Register
// Rising edge clock
// Active high clock enable
// Concatenation-based template
//
// File: HDL_Coding_Techniques/shift_registers/shift_registers-0.v
module v_shift_registers_0 (clk, clken, SI, SO);
    parameter WIDTH = 32; 

    input clk, clken, SI; 

    output SO;

    reg[WIDTH-1:0] shreg;

    always @(posedge clk)begin
        if (clken)
            shreg = {shreg[WIDTH-2:0], SI};
    end
    
    assign SO = shreg[WIDTH-1];
endmodule

        (2)32位动态移位寄存器verilog代码:

// 32-bit dynamic shift register.
// Download: 
// File: HDL_Coding_Techniques/dynamic_shift_registers/dynamic_shift_registers_1.v
module dynamic_shift_register (CLK, CE, SEL, SI, DO);
    parameter SELWIDTH = 5;

    input CLK, CE, SI;
    input[SELWIDTH-1:0] SEL;

    output DO;

    localparam DATAWIDTH = 2**SELWIDTH;

    reg [DATAWIDTH-1:0] data;

    assign DO = data[SEL];
    
    always @(posedge CLK)begin
        if (CE == 1'b1)
            data <= {data[DATAWIDTH-2:0], SI};
    end 
endmodule
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐