当前位置:   article > 正文

FPGA基础学习总结(一)——数字系统和FPGA(基本结构、组合时序逻辑、Verilog、避免锁存器生成、可综合与不可综合、流水线结构、查找表、降低FPGA功耗)_锁存器为何会使静态时序分析变得非常复杂

锁存器为何会使静态时序分析变得非常复杂

数字系统和FPGA

1、数字系统的简单介绍

1.1 控制单元和数据通路

如下图所示:

  • 数字系统有两个基本组件:控制单元和数据通路。

控制单元能够为数据通路提供控制信号,同时数据通路能产生status信号,从而被控制块用于定义要执行的操作顺序。


另外控制单元能从外部接收控制输入信号,比如简单的start信号。数据通路也能对外部接收的数据执行操作。这个操作通常分成一步或者几步执行,每一步占用一个时钟周期

在这里插入图片描述

  • 数据通路块的示例包括

内部连接网络—电路线,多路复用器,总线,以及三态缓冲器
功能单元—加法器, 减法器, 移位器, 乘法器, 以及算数逻辑单元(ALU)

1.2 组合电路和时序电路

数据通路和控制单元都是基于两种类型电路:组合电路和时序电路。

组合电路:输出引脚只取决于输入引脚的值,与电路原来的状态无关。(门电路)
.
时序电路:输出信号不仅取决于输入信号的值,也取决于当前存储模块中存储的状态。因此需要一个存储器件能够记住过去时钟下的输入值,这里的存储器件也就是时序电路元件(存储器件:触发器和锁存器)。


如下分别是组合逻辑和时序逻辑的波形图,以 取反操作 为例子。

1.2.1 组合逻辑电路

1、组合逻辑电路图解:
可看出输出只却决于输入。也就是说,只要输入变化,输出就跟着变化
可看到它无存储电路,因此就是单纯门电路的逻辑组合。
在这里插入图片描述
2、用代码和波形来表示:

assign out = ~ in;
  • 1

在这里插入图片描述
3、常见的组合电路

互连电路:如多路复用器,多路输出选择器,编码器,解码器。
逻辑和算术电路:如加法器,减法器,乘法器,移位器,比较器和ALUs (多个算术模块或逻辑模块)。
多路复用器:多路的输入合并为一个输出。
编码器:把多个低电平有效信号或多个高电平有效信号,转换成多位二进制数输出。
解码器:把多位二进制数转换成多个单电平有效信号输出。

1.2.2 时序逻辑电路

1、时序逻辑电路图解:

时序逻辑电路 = 组合逻辑电路 + 存储电路

和组合逻辑不同,输入变化的时候输出不一定变化,只要当时钟沿到来,输出才可根据输入和电路之前状态改变。

在这里插入图片描述
2、代码和波形分析

以时钟上升沿触发:

always @(posedge clk)begin
    out <= ~in;
end
  • 1
  • 2
  • 3

分析波形:
clk上升沿处输出变化,否则输出保持不变。
clk1上升沿处,由于上一时刻为 in =0,因此输出为一个周期的1
clk2上升沿处,由于上一时刻 in =1,则输出为一个周期的0;
……
在这里插入图片描述

锁存器Latch、触发器和寄存器

掌握锁存器和触发器之间的区别。主要在于锁存器是电平触发,而触发器是时钟边沿触发。锁存器受布线延迟影响较大,很难保证输出没有毛刺产生,而DFF则不易产生毛刺。

如下为锁存器的代码:可看出在组合逻辑中,若存在某个信号需要保持不变的时候,就会生成锁存器。因为如下的条件语句省去了else,那么就相当于默认 else Q = Q ; 该信号保持不变,于是生成latch。

always @ (*)
begin
     if(en)
        Q = D ;
end
  • 1
  • 2
  • 3
  • 4
  • 5

寄存器的存储电路是由锁存器或触发器构成的,因为一个锁存器或触发器存储1位二进制数,所以由N个锁存器或触发器可以构成N位的寄存器,它主要用来用来暂时存放参与运算的数据和运算结果。(比如完成数据的串并或者并串转换


下面重点来学习一下锁存器的危害以及如何避免锁存器的生成
我们尽可能的减少锁存器的使用或者锁存器的生成,而是采用触发器,为什么呢?

  • 因为锁存器的存在不利于时序的分析。根据时序分析原理我们需要分析寄存器输出延迟以及组合逻辑延迟等时间,但是因为锁存器Latch是电平触发,而不是时钟的边沿触发,那么它就可能在时钟的有效沿之间被触发,这就导致无法确定其输出什么时候为低,什么时候为高(与时钟不同步)。D触发器分析的时候只需考虑触发器之间的路径即可。——静态时序分析复杂
  • 电平有效的时候才能输出,这就导致如果有效延迟不同那么就容易产生毛刺。组合逻辑中数据不需要锁存,因此也需要避免产生锁存器。——易产生毛刺,无法异步复位,因此上电后为不定状态
  • 对于资源消耗来说:锁存器在FPGA中是没有的,由触发器加逻辑门构成,因此生成锁存器就会比触发器来说使用更多的资源。——消耗资源更多

如何避免锁存器生成?

组合逻辑生成锁存器,使得输出保持不变。
解决方法:
(1)采用时序逻辑,也就是组合逻辑中插入触发器,从而实现寄存;
(2)尽可能避免在组合逻辑中某个信号保持不变,或者说避免组合逻辑存在环路(常见的组合逻辑中存在锁存器的地方:if else语句中丢失else,或者else后描述的还是信号保持不变,另外就是case语句中缺少了defaut语句,这些都会造成锁存器的生成,应该注意。)

补充:仔细检查综合器(quartus)的综合报告,所综合出的latch都会报“warning”,即可根据此进行修改。


带有异步复位,上升沿触发的触发器

异步复位是指无论时钟沿是否到来,只要复位信号有效,即可对系统进行复位操作。

module test(clk,rst,q,d);

	 input           clk    ;
	 input           rst    ;
	 input           d      ;
	 output  reg     q      ;
	 

always @ (posedge clk or posedge rst )
    if(rst)
	     q <= 0;

    else
	     q <= d;
		  
endmodule

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

复位变成低电平的时候,输出直接发生变化,无需等待clk上升沿的到来。
在这里插入图片描述

带有同步复位,上升沿触发的触发器

(复位信号只有在时钟上升沿到来时,才能有效)

module invert(input in, input clk,input rst, output reg out);
    always @(posedge clk )begin
        if(rst)
            out <= 1'b0;
        else
            out <= ~in;
    end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

下图可看到,复位变成高电平的时候,输出不能直接拉低,需要等到上升沿的到来,才能拉低。在这里插入图片描述

带有同步复位和使能,上升沿触发的触发器

(复位和使能信号只有在时钟上升沿到来时,才能有效)

module invert(input in, input clk,input rst,input en, output reg out);
    always @(posedge clk  )begin
        if(rst)
            out <= 1'b0;
        else if(en)
            out <= ~in;
        else
           out <= 1'b0; 
    end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

波形分析同上。
15ps时钟上升沿处:复位低电平,en高电平,in高电平,因此输出一个周期的低电平。
25ps时钟上升沿处:复位低电平,en低电平,因此输出一个周期的低电平。
35ps时钟上升沿处:复位低电平,en高电平,in低电平,因此输出一个周期的高电平。
45ps时钟上升沿处:复位高电平,en高电平,因此输出一个周期的低电平。……
在这里插入图片描述

带有异步复位和同步使能,上升沿触发的触发器

(使能信号只有在时钟上升沿到来时,才能有效)

module invert(input in, input clk,input rst,input en, output reg out);
    always @(posedge clk or posedge rst  )begin
        if(rst)
            out <= 1'b0;
        else if(en)
            out <= ~in;
        else
           out <= 1'b0; 
    end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
锁存器

锁存器为电平触发,当时钟clk为高电平时,其输出q才会随着输入d的变化而更新;当clk为低电平时,锁存器将保持原来高电平时锁存的值。
此处省略的else分支,就会生成锁存器。

module invert(input in, input clk, output reg out);
    always @(*)begin //敏感列表为*表示对always模块中的任意输入信号变化,都会触发模块重新计算。
        if(clk)
            out <= in;  
    end
  • 1
  • 2
  • 3
  • 4
  • 5

高电平输出随着输入变化,低电平保持之前高电平的值
在这里插入图片描述

移位寄存器

移位寄存器是一种在时钟脉冲的作用下,将寄存器中的数据按位移动的逻辑。 一个N位的移位寄存器就包含N个触发器。
它可以实现串并转换,比如输入一串行数据,串行输出,也可以输入串行数据,并行输出,或者数据并行输入,串行输出。

1.3 数字系统中数值的表示

  • 数字系统中,各种数值常用二进制进行表示

  • 如下所示:一个正的二进制的整数B,就可又N位二进制位bi进行表示,其每一位表示一个连续的2次幂。
    在这里插入图片描述
    在这里插入图片描述

  • 在大多数的软件表示方法中,N固定为8,16,32,64,是由软件运行的计算机架构决定的,但是FPGA的话,没必要约束这些宽度,它能根据表示数值的范围进行宽度的调整,从而减少硬件的消耗;

  • 比如说,640*480的图像,就可以分别采用9位和10位整数来进行 图像长宽的表示。


2、实现数字电路设计的几种方法对比

在这里插入图片描述

设计一个电路实现如下逻辑方程:
在这个电路中,输入A,B和输出 f 都是4位宽的数据。

实现数字电路设计采用如下方法:

2.1 用一个7408 TTL 器件(专用集成电路------ASIC解决方案)

其中TTL电路是晶体管-晶体管逻辑电路的英文缩写(Transister-Transister-Logic),是数字集成电路的一大门类。74系列的7408集成电路芯片是一个输入端四与门芯片。因此,一个7408 TTL 器件足以实现4-bits 功能。
针对上面的题目来说,这是一个不错的解决方案,但是缺点:TTL是过时的技术,存在高功耗和占大空间的弊端。 另外一个缺点是万一遇到设计需求的改变或者升级需要重新完整的设计一遍。也就是说 芯片的功能是制造商定义好的(永久的),不能够被改变,只能将旧芯片换成新芯片。

在这里插入图片描述

2.2 微处理器(软件解决方案)

其中微处理器:由一片或少数几片大规模集成电路组成的中央处理器。
微控制器:微控制器,简单来说就是微型或小型控制器。基本是指由单片机为核心的控制单元,及外部电路组成的控制器。
与第一种方法类似,这个微处理器也需要焊接到PCB上,但是在系统功能改进上它比第一种方案要更加灵活。由于解决方案是在"software"层面实施的,任何设计需求的改变可直接修改软件程序,无需修改硬件或PCB。也就是微处理器内部的硬件已经被设计好了,以便执行程序指令,根据不同的设计需求可以写出不同的程序。
在这里插入图片描述
缺点:需要一个专门的C 编译器来提供4-bits 宽的int型。另外要分配输入和输出(A,B,F)到微处理器物理管脚上。考虑到如果是一个标准的C编译器,开发者需要使用scanf 或者getc等输入函数来获取A和B的值,并用printf函数来输出F的值。

2.3 FPGA(介于硬件方案和软件方案之间的一个方案)

跟TTL方案和微处理器方案类似,FPGA器件亦需要焊接到PCB上,所有的输入输出引脚应该连接上。与微处理器方案相比,FPGA方案的最大的不同点是:解决方案并不是在软件中实现。FPGA方案是一个硬件方案,若需要修改,可以在FPGA中建立起一个新的电路,然后生成一个新的FPGA配置即可,且无需修改PCB。电路的描述可以用VHDL或者Verilog语言。


3、FPGA(现场可编程逻辑门阵列)

3.1 什么是可编程硬件?

可编程硬件就是得到一个通用电路,并可针对特殊的应用对该通用电路的功能进行编程实现。

如下是可编程阵列的解释:

左:可编程的与 和 或
中:PAL :可编程的与 和 固定的或
右:PROM /LUT:可编程的或 和 固定的与(每一个 与门 都对应一个输入信号的组合)
在这里插入图片描述
但是一般来说,可编程只读存储器并不是用右边结构来实现的,是将可编程器件用可编程存储单元来代替,如下所示:
在这里插入图片描述

3.2 FPGA的内部结构

  • FPGA芯片结构采用像SRAM或者FLASH存储器一样的"可写"技术。
  • FPGA 器件有3种主要可配置组件:

逻辑块:通常基于查找表结构(前面分析的可编程的或 和 固定的与 阵列组成)
路由单元:为经过路由单元的每个数据帧寻找一条最佳传输路径,并将该数据有效地传送到目的站点
输入输出(I/O)块:将FPGA核心部分以及内部的其他部分与外围器件进行连接。
由此,在任意配置下,可实现各个模块的连接,从而能改变内部逻辑。

如下是FPGA内部结构图:
在这里插入图片描述
如下是对 f(A,B) = A and B 的实现:
在这里插入图片描述

3.3 FPGA内的逻辑器件

3.3.1 逻辑单元

FPGA内逻辑器件的最小单元是逻辑单元,它通常是由一个小的查找表和一个输出端锁存器组成

如下是FPGA的一个逻辑单元的方框图:

在这里插入图片描述

3.3.2 查找表

  • 三输入的LUT为3-LUT;LUT可实现其输入的任意函数;将LUT多层级联(将输出连到下一层的输入),可实现复杂功能。

  • LUT的最佳尺寸是4-6个输入,由此来判断是大LUT还是小LUT;大LUT有更多的数据传输延迟

  • 锁存器用来寄存输出

  • 可将多个逻辑单元连接并合并到一个逻辑功能块,功能块内的所有逻辑单元共享通用控制信号(通用时钟和时钟使能信号),在逻辑功能块中,相同逻辑功能块内的输出信号可直接用作块内其他逻辑单元的输入,通过直接连接的方式,可减少互连布线信号的数量,减少关键路径上的传输延迟。

  • 使用专用复用器,可将相邻的LUT相连,实现复杂功能。

  • 最佳逻辑单元块的大小是4-10个逻辑单元

  • 查找表实现组合逻辑的延迟是固定的

给出一个例子,看一个计算中有几个LUT?

根据下面的全加器真值表可看出,此操作在FPGA上,1个全加器需要2个3-LUT,一个用来产生和,一个用来产生进位。在这里插入图片描述

3.4 FPGA的功耗

3.4.1 动态和静态功耗

动态:信号01或者10切换时的功耗
静态:不进行信号切换时的功耗——仅仅是设备开机的功耗

详细地讲:

峰值损耗一般出现在时钟翻转的瞬间。
CMOS管功耗 = 动态功耗 + 静态功耗
静态功耗:是时钟不工作的状态下所需的功耗
动态损耗:器件工作时所增加的功耗,它由切换信号及容性负载的充放电引起
动态功耗 = 负载功耗 + 内部功耗
负载功耗:指CMOS管在翻转过程中对负载电容进行充放电消耗的功耗。
内部功耗:指CMOS管在翻转过程中,对内部结点电容进行充放电消耗的功耗及短路电流消耗的功耗。

3.4.2 降低功耗的方法

可以用什么方法让功耗变小呢?

通常来说,时钟信号本身的翻转会消耗大部分功率,因此可降低时钟频率或者采用时钟门控设计。
逻辑器件之间互连线长度最小化(最大限度的插入寄存器)
对于需要控制的寄存器来说,我们在一定的情况下关闭寄存器的传输功能,阻止无用的数据进入下一级逻辑,可避免引起一连串不必要的逻辑翻转,达到降低功耗的可能。(加入使能en信号以关闭更多的空闲功能部件)

1、通过寄存器的传输关闭来降低传播及组合逻辑的功耗

如下为加入使能信号,通过回写的方式来实现了寄存器的传输关闭功能:
可看到通过en信号进行控制,如果不需要数据进行后续的传输,那么将en为低电平,就可以让输出保持为data-out而不引起后继部件的翻转
在这里插入图片描述
2、针对上述回写结构的基础上,虽数据传输降低,但时钟仍然在翻转,因为我们要对时钟信号进行控制。这里通过引入寄存器的时钟门控设计来实现。同样的将使能信号en作用于clock上,当对应的空闲功能被关闭的时候,相应的时钟也关闭。

补充:什么门控时钟:它就是通过组合逻辑门来生成时钟,从而可以实现开关性,这样就能在不需要时钟的时候(状态无需改变),将其关掉。

注意1:不是越多的Clock-Gating控制逻辑就越好,我们必须要衡量加入时钟门控带来的损耗与动态损耗之间的大小。(比如连接的寄存器位数较小的时候,若采用了很多的时钟门控功能,那么可能时钟门控产生的损耗比之前的动态损耗还要大)——位宽一般不低于3一8位

注意2:门控时钟涉及了组合逻辑,那么容易出现竞争和冒险问题,从而容易出现毛刺,同时寄存器存储对时钟边沿敏感,因此容易影响时序,尽量更少的使用门控时钟,除非是功耗很大的情况下,我们可以进行合理设计。

注意3:如何生成的门控时钟过窄,形成了毛刺怎么办?这时候可引入锁存器,能对电平进行保持。

在这里插入图片描述
3、如下为级联时钟门控的原理图。在本级和下一级寄存器都添加了时钟门控电路,此时即可降低更多的损耗。
在这里插入图片描述
4、如下是组合逻辑中降低功耗的方式,通过en01信号对每一级寄存器都进行了控制,因此可看到组合逻辑越复杂,加入的控制逻辑电路也越多,因此我们必须要进行控制电路损耗与组合逻辑动态损耗之间的衡量,因此一般在寄存器位宽较大时考虑这么做。
在这里插入图片描述

3.5 FPGA的编程语言

  • 为了让工作人员读懂工程设计,因此要对工程进行编码——也就是用HDL语言进行硬件描述
  • 综合:将硬件描述进行转化,成一个由器件或门电路组成的网表——RTL图,也可定义不同构造块间的互连关系
  • RTL图:可描述FPGA实际创建的逻辑电路

如下是FPGA的设计流程:FPGA上实现算法要同时对软件(算法方面)和硬件(逻辑电路)技巧进行融合在这里插入图片描述

3.6 FPGA的流水线结构

  • 流水线结构是把逻辑分成更小的块,展开为多个时钟周期,以减少每个时钟周期的传播延迟,从而使得设计的时钟速率更快。
  • 如何分成更小的块?在各个计算之间插入寄存器,尽管寄存器也会引入额外的小延迟,但相当于传播延迟来说可忽略
  • 流水线的方式能让吞吐量随着时钟速率的增高而增加。
  • 虽然整个的计算占用多个时钟周期,且第一次运算的总时间不会改变,但是后续每一个时钟周期都会完成一个计算输出

具体可以看这里:FPGA流水线处理
如下为简单流水线的例子:

第一个:一个时钟周期内完成运算
第二个:两级流水线
第三个:四级流水线,将计算分成四个时钟周期来完成

在这里插入图片描述

3.7 FPGA中的可综合和不可综合

可综合

  • 将原理图或者HDL语言,生成网表文件(门级和寄存器传输级(RTL)块)。
  • 综合产生网表文件后,还可以按照用户提供的面积(资源要求)和时间(时序要求)约束为目标来优化网表。

不可综合:

  • 根据HDL语言或者原理图,不能得到想要的硬件元件(触发器、多路选择器等)
  • 另外Verilog中存在一些用于仿真验证的子集,属于仿真验证语言,只在仿真时候使用,不能被综合成电路,因为没有相应的硬件元件与其对应。如$dsiplay()显示函数,以及initial语句等。

3.7.1 关于for循环的综合

1、 循环语句可以减少代码量,使代码更精简,但使用后可以导致语句不可综合。
2、 对于一些简单的信号连接方式变化,用循环语句是可接受的。对于要生成硬件电路结构,也就是门电路的情况下,不建议采用for语句。如下代码,实现多位输入信号到输出信号的位翻转。

module test(
    input clk,
    input [3:0] din,
    output reg[3:0] dout
);

integer i;

always@(posedge clk)

begin
    for(i=0;i<=3;i=i+1)
       dout[3-i] <= din[i];
end
	 
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

根据RTL也可知,其是可综合的。
在这里插入图片描述
3、for语句到底什么时候可综合,什么时候不可综合?

for循环中迭代的次数在仿真前能由编译器确定(即迭代次数是固定的并且与数据无关),这种循环称为静态循环或是数据独立。——可综合的。

如果循环次数是由运算中的某个变量决定,这种循环则与数据相关,就是其循环次数不确定,因此为非静态循环。——不可综合的。

3.8 从Verilog HDL到硬件的映射

Verilog中变量数据类型有两种:reg寄存器型,wire网线数据类型(综合成连线)。

1、连续赋值语句必须以关键词assign开始,且数据类型为wire型。

assign a = ~b;
  • 1

延迟: 如果在连续赋值语句中加入延迟,综合器会选择忽略。

assign #20 a = ~b;
  • 1

2、过程赋值语句只能出现在always块中,变量都定义成reg型(也能出现在初始化语句initial语句中,但initial 语句不可综合)。过程赋值语句包括阻塞和非阻塞两种。

重点:reg型变量并不一定都是会综合成触发器或锁存器,也可能是硬件连线。例如:

//阻塞赋值
module test(
    input       a,
    output  reg b 
);//虽然是reg型,但仅用作一个临时变量,无需映射为寄存器类型
always@(*)
    b = ~a;	 
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

阻塞赋值综合的RTL图如下:
在这里插入图片描述

//非阻塞赋值
module test(
    input clk,
    input a,
    output reg b
);
always@(posedge clk)
    b <= ~a;	 
endmodule

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

非阻塞赋值综合的RTL图如下:
在这里插入图片描述

3.9 FPGA应用领域

图像处理、通信领域、AI算法设计等。
主要用FPGA做计算的加速。
学会如何用Verilog语言编写可综合的并行结构,在规定的时间间隔内完成算法要求的计算工作量,从而实现硬件加速。针对纯软件算法,将其进行转化,变成用软件和硬件配合实现的过程,实现软硬协同,带来更出色的处理效果。

3.10 如何提高FPGA设计电路的工作频率

提高工作频率的本质就是减少寄存器到寄存器的时延。

  • 电路延迟主要包括三个:
    寄存器延迟(时延是由器件物理特性决定)、走线延迟和组合逻辑延迟。

  • 重点分析走线延迟和组合逻辑延迟

  • 走线延迟:
    1、加入时钟约束(一般以加5%裕量较为合适)
    2、将相关的逻辑的布线时尽量靠近,从而减少走线时延。

  • 组合逻辑延迟:
    1、切割组合逻辑,减少LUT级联,当输出判断条件大于四个输入的话,一般采用多LUT级联的方式,那么就会引入更多的延迟,因此我们要尽可能减少输入条件,从而级联LUT也减少。切割组合逻辑常采用流水线技术,通过各级之间插入寄存器来实现,从而各级之间的组合逻辑减少。
    2、将计数器移除FSM。当我们在进行状态机设计的时候,有时也会将计数器作为判断条件,但是输入常为四输入,而计数器数值较大,比如111100,那么就需要LUT级联,所以我们这里将计数器写到状态机外。
    3、当状态机中有几十个状态的时候,也可以切割,在某状态又可跳转到一个新的小状态机。

总结: 提高时钟频率最有效的方法是避免出现大的组合逻辑(尽量去满足四输入的条件,减少LUT级联数量)。
常用技术: 通过加约束、流水线技术、切割状态的方法提高工作频率。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/178986
推荐阅读
相关标签
  

闽ICP备14008679号