转载:从底层结构开始学习FPGA(5)— 移位寄存器SRL

本文转载自CSDN博主「孤独的单刀」的原创文章,原文链接:https://blog.csdn.net/wuzhikaidetb/article/details/124970484

一、移位寄存器SRL

1.1、概述

  移位寄存器内的数据可以在移位脉冲(时钟信号)的作用下依次左移或右移。移位寄存器不仅可以存储数据,还可以用来实现数据的串并转换分频构成序列码发生器序列码检测器,进行数值运算以及数据处理等,它也是数字系统中应用非常广泛的时序逻辑部件之一。

  在FPGA的底层结构 —— 可配置逻辑块CLB中,一个CLB由2个Slice组成,Slice又可以分SliceM和SliceL(其比例大致为1:3),其中M是Memory的首字母,L是Logic的首字母,比较SliceM和SliceL,其区别就是SliceM的查找表具有RAM和ROM的功能,而SliceL的则不具备,所以SliceM比SliceL多的功能就是作存储器和移位。


1.2、概念

  SLICEM中可以在不使用触发器的条件下配置为32位移位寄存器注意:只能左移)。这样,每个LUT6可以将串行数据延迟1到32个时钟周期。移位输入D(LUT DI1脚)和移位输出Q31(LUT MC31脚)可以进行级联,以形成更大的移位寄存器。一个SLICEM的4个LUT6级联可以实现128个时钟周期的延时。

  多个SLICEM也可以进行组合。但SLICEM之间没有直接连接以形成更长的移位寄存器,在LUT B/C/D处的MC31输出也没有。由此产生的可编程延迟可用于平衡数据pipeline的时间。


1.3、应用

  • 延迟或延迟补偿

  • 同步FIFO和内容寻址存储器(CAM)


1.4、结构

  下图是由一个LUT构成的最高支持32位移位的移位寄存器SRLC32E结构。

CLK:时钟
CE:时钟使能,高电平有效
SHIFTIN(D):数据输入
A[4:0]:移位长度配置(支持1~32位),需要+1。如9位移位则A[4:0]需配置成1+8(01000)
SHIFTOUT:32个长度移位后的数据输出,可用来与其他SRLC32E级联,形成更大长度的移位寄存器
OUTPUT(Q) :当移位长度被确定后,数据就会出现在Q端

1.5、级联

  1️⃣ 通过两个32位的移位寄存器SRL32与一个MUX2,即可级联成最高支持64位的移位寄存器。


  2️⃣ 通过三个32位的移位寄存器SRL32与三个MUX2,即可级联成最高支持96位的移位寄存器。

  


  3️⃣ 通过四个32位的移位寄存器SRL32与三个MUX2,即可级联成最高支持128位的移位寄存器。

  而4个移位寄存器由4个LUT组成,刚好一个SLICEM中有4个LUT,这说明一个SLICEM可以实现最多支持128位的移位寄存器。由于4个LUT同在一个SLICE里面,所以布线方便且延迟短,有利于时序收敛。


二、移位操作

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

  • 输入(D)被加载到移位寄存器的第一个位

  • 前一个位被移到下一个位置并出现在Q输出上,最高位移到MC31输出

  • 移位寄存器固定长度为(N + 1),其中N为输入地址(0-31),由地址总线A[4:0]决定

  • 在级联操作中,前一个移位寄存器的SHIFTOUT链接至下一个移位寄存器的SHIFTIN


2.2、动态操作(移位长度可变)

  • 数据的移位输出是异步信号

  • 其他与静态操作一致


2.3、Timing


三、实例化

  在实际的编写RTL过程中,我们可通过以下方式来生成一个移位寄存器。

  • 源语方式

  • 综合工具推断方式


3.1、源语

(1)源语类型

  • SRL16E :最高可实现16个时钟周期的移位功能

  • SRLC32E :最高可实现32个时钟周期的移位功能

  以上均可以实现移位寄存器功能,后文以SRLC32E为例进行讲解。

(2)源语例化

// SRLC32E: 32-bit variable length cascadable shift register LUT (Mapped to a SliceM LUT6)
// with clock enable
 
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

  关于参数与信号在上面已讲解,不赘述。

(3)示例代码

module test
(
    input   clk,
    input   ce,        
    input   shift_in,        // 移位输入
    output  Q,               // 移位输出
    output  shift_out        // 移位输出,可级联
);
 
SRLC32E 
#(
    .INIT(32'h00000000)     // Initial Value of Shift Register
) 
SRLC32E_inst 
(
     .Q(Q),                 // SRL data output
     .Q31(shift_out),       // SRL cascade output pin
     .A(5'b01001),          // 5-bit shift depth select input,移位长度固定为10----01001+1
     .CE(ce),               // Clock enable input
     .CLK(clk),             // Clock input
     .D(shift_in)           // SRL data input
);
 
endmodule

  上面的模块是直接使用SRL32源语例化的一个移位寄存器,移位长度固定为10。 下面是综合出来的结构,可以看到只使用了一个LUT。

(4)Testbench

`timescale 1ns / 1ns

module tb_test();
    
reg  clk;
reg  ce;
reg  shift_in;
wire Q;
wire shift_out;
 
test test_inst
(
    .clk(clk),
    .ce(ce),
    .shift_in(shift_in),
    .Q(Q),
    .shift_out(shift_out)
);
 
initial begin
    clk=0;
    ce=1;
    shift_in = 1;
    #330 $finish;
end
 
always
    #5 clk = ~clk;
 
always
    #10 shift_in <= ~shift_in;
 
endmodule

(5)仿真结果

  在第一个周期输入信号从0跳转到1;移位长度设置为10,在第10个周期Q输出为1,此后输出与shift_in一致;在第32个周期,shift_out开始输出1,然后输出与shift_in一致。仿真结果符合Timing。


3.2、推断方式

  除了直接例化SRL源语外,也可以通过编写常规的RTL代码来实现移位寄存器的功能。但是需要注意的是,要注意编写RTL的风格,有些风格可能导致vivado无法综合出SRL,而是使用多个REG来实现,会造成大量的资源浪费。

(1)错误的推断方式

module test
(
    input  clk,
    input  ce,
    input  shift_in,
    input  rst,
    output Q,
    output shift_out
);
 
reg [31:0] dff;
 
always@(posedge clk) begin
    if(rst)
        dff <= 0;
    else if(ce) begin
        dff[31:0] <= {dff[30:0],shift_in};     // 拼接运算实现向左移位
    end    
end
 
assign shift_out = dff[31];
assign Q = dff[9];
 
endmodule   

  上面代码的综合结果如下,显然不是用的SRL32,而是数个LUT+数个FF。其原因在于RTL中使用了复位信号,而SRL32这个元件是没有复位端口的,因为流水线的结构根本就不需要复位!复位的使用完全是画蛇添足,导致不必要的资源浪费。

(2)正确的推断方式

module test
(
    input  clk,
    input  ce,
    input  shift_in,
    output Q,
    output shift_out
);
 
reg [31:0] dff;
 
always@(posedge clk) begin
    if(ce) begin
        dff[31:0] <= {dff[30:0],shift_in};     // 拼接运算实现向左移位
    end    
end
 
assign shift_out = dff[31];
assign Q = dff[9];
 
endmodule   

  上面的代码是删除复位后的代码,综合结果如下。

  使用的资源:3个FF+2个SRL。因为我们要做的是10位移位,所以结果在第10位被引出。vivado自动帮输入以及输出做了寄存,所以资源消耗得多一些。

(3)仿真结果:

  在第一个周期输入信号从0跳转到1;移位长度设置为10,在第10个周期Q输出为1,此后输出与shift_in一致;在第32个周期,shift_out开始输出1,然后输出与shift_in一致。仿真结果符合Timing


四、应用

4.1、同步移位寄存器

  移位寄存器原语不会使用同一SLICE中可用的寄存器。要实现完全同步的读和写移位寄存器,输出引脚Q必须连接到触发器FF。移位寄存器和触发器共享同一时钟,如图所示。

4.2、固定长度的移位寄存器

  32位移位寄存器可级联实现任何静态长度模式的移位寄存器,而不需要使用专用的多路复用器(F7AMUX, F7BMUX和F8MUX)。下图说明了如何构建72位移位寄存器。只有最后一个SRLC32E原语需要将其地址输入绑定到ob00111。另外,可以将移位寄存器的长度限制为71位(绑定到obo0110的地址),并且可以使用一个触发器作为最后一个寄存器。(在SRLC32E原语中,移位寄存器长度为地址输入+ 1)。


五、总结

  • 一个移位操作需要一个时钟沿

  • 对LUT的Q输出的动态移位长度读操作是异步的

  • 对LUT的Q输出的静态移位长度读取操作是同步的

  • 数据输入具有 setup-to-clock的时序规范

  • 在可级联配置中,Q31输出总是包含最后一位值

  • Q31输出在每次移位操作后同步变化

  • SRL结构不需要使用复位,如果希望使用SRL32减少资源,实现移位,则建议使用源语方式例化

  • 1
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值