可配置逻辑块(Configurable Logic Block,CLB)是主要的逻辑资源,用于实现时序和组合逻辑电路。
UltraScale 和 UltraScale+架构的 CLB 提供了高性能与低功耗的可编程逻辑,包含真正的 6输入查找表功能(Look Up Table,LUT)、两个LUT5(5输入LUT)功能、分布式存储器和移位寄存器逻辑、用于算术运算的专用高速进位逻辑、实现高效利用的宽多路复用器,以及具有灵活控制信号的可配置为触发器或锁存器的专用存储元件。
一个CLB包含一个切片(Slice),每个切片提供8个6输入的查找表和16个触发器。互联线很容易将切片连接在一起,以创建更大的函数。切片及其CLB在整个器件中按列排序,列的大小和数量随着密度的增加而增加。UltraScale+架构中包含两种类型的切片,即 SLICEL 和SLICEM。下面以Xilinx Kintex UltraScale+系列FPGA中的xcku5p-ffva676-1-i器件为例,说明SLICEL(L是Logic的缩写,表示逻辑)和SLICEM(M是Memory的缩写,表示存储器)的内部结构。
SLICEL 和 SLICEM 的最大区别是,SLICEL 中的 LUT 只能实现组合逻辑功能,而SLICEM中的LUT不但能实现组合逻辑功能,还能实现时序逻辑电路的存储功能。
SLICEL的内部结构如图1.1所示。图中:
图1.1 SLICEL的内部结构
(1)8个6输入的LUT,即SLICEL_A6LUT~SLICEL_H6LUT;
(2)16个锁存/触发器资源,即AFF~HFF和AFF2~HFF2;
(3)一个8位的进位链CARRY8,用于算术运算中的快速进位;
(4) 4 个 F7 类型的多路复用开关,从下到上依次用 MUXF7_AB、MUXF7_CD、MUXF7_EF 和 MUXF7_GH 标记。该类型的多路复用开关用于组合两个相邻 LUT 的输出。当组合两个 6 输入逻辑变量的 LUT 时,就可以实现 7 个逻辑输入变量的函数。因此,这也是MUXF7名字的由来。
(5)两个F8 类型的多路复用开关,从下到上依次用MUXF8_BOT和MUXF8_TOP标记。该类型的多路复用开关用于组合4个LUT的输出,即MUXF7_AB和MUXF7_CD的输出,以及MUXF7_EF和MUXF7_GH的输出。当组合4个6输入逻辑变量的LUT时,就可以实现8个逻辑输入变量的函数。因此,这也是MUXF8名字的由来。
(6)一个 F9 类型的多路复用开关,用 MUXF9 标记。该类型的多路复用开关用于组合8 个 LUT 的输出,即 MUXF8_BOT 和 MUXF8_TOP 的输出。当组合 8 个 6 输入逻辑变量的LUT时,就可以实现9个逻辑输入变量的函数。因此,这也是MUXF9名字的由来。
SLICEM的内部结构如图1.2所示。SLICEM中的LUT不像SLICEL中的LUT只能配置为查找表,其还能配置为查找表、64位的分布式存储器或32位的移位寄存器。
图1.2 SLICEM的内部结构
SLICEL和SLICEM内LUT的符号如图1.3所示,从图中可知,SLICEM比SLICEL的功能复杂。例如,在SLICEM的符号上有CLK输入。
图1.3 SLICEL和SLICEM内LUT的符号
根据图1.3给出的LUT符号可知,LUT提供了两个可能的输出O5和O6。其中,O5表示5个逻辑输入变量5经过单个LUT的输出,而O6表示6个逻辑输入变量经过单个LUT后的输出。
LUT的两种不同配置模式如图1.4所示,即
(1)一个输出的6输入LUT;
(2)两个独立输出的5输入LUT,但是有公共的地址和逻辑输入。
图1.4 LUT的两种不同配置模式
对于一个5输入LUT来说,它可以创建5输入逻辑变量的函数,即
O5= f (A1,A2,A3,A4,A5)
对于一个6输入LUT来说,它可以创建6输入逻辑变量的函数,即
O6= f (A1,A2,A3,A4,A5,A6)
使用Verilog HDL和VHDL调用LUT5和LUT6的寄存器传输级(Register Transfer Level,RTL)描述如代码清单1-1和代码清单1-2所示。在该设计中,使用5输入查找表实现5个逻辑输入变量的逻辑“与”运算和使用 6 输入查找表实现 6 个逻辑输入变量的逻辑“或”运算。注意,代码中的USE_LUTNM属性为ture,表示强制让逻辑函数在一个LUT中。
代码清单1-1 使用Verilog HDL调用LUT5和LUT6的RTL描述例子
注: 读者进入本书提供的\vivado_example\lut_verilog_rtl 资源目录中,用 Vivado 2023.1 打开名字为project1.xprj的工程文件。
代码清单1-2 使用VHDL调用LUT5和LUT6的RTL描述例子
注: 读者进入本书提供的\vivado_example\lut_vhdl_rtl 资源目录中,用 Vivado 2023.1 打开名字为project1.xprj的工程文件。
使用Vivado 2023.1对该设计进行综合后的结果如图1.5所示。
为了进一步理解查找表实现逻辑功能的本质,分别单击图1.5中的LUT5和LUT6,在Cell Properties窗口中,单击Truth Table标签,则会给出输出O与输入IO、I1、I2、I3、I4 之间的关系(见图1.6):
O=10&11&12&13&14
输出O与输入I0、I1、I2、I3、I4、I5之间的关系(见图1.7):
O=10+11+12+13+14+15
图1.5 使用Vivado 2023.1对该设计进行综合后的结果
图1.6 LUT5的内部逻辑关系
图1.7 LUT6的内部逻辑关系
图中的列表本质上就是“真值表”,它真实反映了输入和输出之间的对应关系。在学习数字电路课程的时候,首先会使用“真值表”表示逻辑输入和输出之间的对应关系;然后根据真值表给出的逻辑对应关系,通过卡诺图化简的方法得到使用积之和(Sum Of Product,SOP)或和之积(Product of Sum,POS)形式的最简逻辑表达式;最后使用诸如74LSXX这样的小规模集成电路(Small-Scale Integrated Circuit,SSI)实现逻辑表达式所要表示的逻辑功能。
那么为什么在 FPGA 中使用 LUT 表示逻辑功能,而不使用类似 SSI 的方法表示逻辑功能呢?显然,对于 5 个输入/6 个输入的逻辑变量,当实现的逻辑关系发生变化时,真值表的内容会发生变化,最终得到的SOP/POS最简逻辑表达式也会发生变化,因此使用的SSI的个数和构成形式也会发生变化。根据数字逻辑电路所学到的知识可知,一方面,当逻辑变量通过门电路送到输出端口时,会出现逻辑门的翻转延迟;另一方面,从一个逻辑门的输出到另一个逻辑门的输入会出现连线的传输延迟。显然,当所使用的 SSI 的个数和构成形式发生变化时,从逻辑输入I0~I4/I0~I5到逻辑输出O的延迟时间会有所不同。频率是时间的倒数,则频率也有所不同,频率常常和触发器等存储元件有关。由于频率有所不同,因此触发器的时钟工作频率也有所不同,无法确定触发器的工作速度。如果考虑到SSI之间的连线,则更增加了延迟的不确定性。
但是,如果使用类似真值表的LUT表示逻辑关系,则从逻辑输入I0~I4/I0~I5到逻辑输出O的延迟时间是固定的,因此频率也是固定的。所以,用于触发器的时钟速度也是固定的,不存在类似SSI的延迟不固定的问题。因此,采用LUT表示函数的逻辑关系较好地解决了延迟不确定的问题。
从另一个角度来说明使用LUT表示逻辑功能的好处。前面提到,当使用传统真值表、卡诺图化简、最简表达式到 SSI 实现的方法时,一旦逻辑关系发生变化时,实现逻辑关系的门电路的个数和连接形式也会发生变化。整个逻辑电路的复杂度和两个因素有关。一方面,当输入逻辑变量的个数增加时,可以表示更多的逻辑功能;另一方面,使用的 SSI 的个数越多,所需要使用的连线也就越多,整个逻辑电路的复杂度就会增加。
但是,当使用 LUT 表示逻辑关系时,整个逻辑电路的复杂度只与逻辑输入变量的个数有关。显然,对于6输入变量的LUT,其LUT的深度为2 6 (=64)。
综上所述,采用 LUT 实现组合逻辑的优势在于:解决了传统使用逻辑门的延迟不确定问题;使组合逻辑的复杂度只与LUT的输入变量个数有关。
图1.8 布局布线的结果
进一步讨论LUT的结构,如果将6输入LUT的输入端口I0~I5看作存储器的地址输入,则I0~I5可以寻址存储器的深度范围是0~63,总计 64 个深度。I5~I0 这六个地址组合的变化范围为 000000~111111。将输出 O 所对应一列的值作为每个地址所对应的存储器的内容,事先保存到表中,则可以将LUT看作容量为64×1位的只读存储器(Read Only Memory,ROM),因此LUT也可以作为存储器使用。
那么,存储器的内容是如何保存到这个表中的呢?这是通过 FPGA厂商专用的下载电缆和软件开发工具,将硬件描述语言(Hardware Description Language,HDL)经过综合和实现后的比特流文件下载到FPGA中实现的。
该设计经过Vivado 2023.1实现后的布局布线结果如图1.8所示。
思考与练习1-1: 请读者打开该设计综合后的结果,观察图1.6和图1.7中每个查找表中的内容,以及所实现的功能。
思考与练习1-2: 请读者打开该设计实现后的结果,观察图 1.8 中查找表的输出网络和布局布线结果。
多功能多路复用器将LUT组合在一起,构成7、8或者9个输入的任意函数功能,或者最多55个输入的一些函数功能。每个切片包含7个多路复用器,用于构建更多的函数功能。
MUXF7_AB、MUXF7_CD、MUXF7_EF 和 MUXF7_GH 用于组合两个相邻的 LUT。其中,后缀 AB、CD、EF、GH 表示该类型的多路复用器由 SLICE 外部输入的 AX、BX、EX、GX 控制信号对相应的多路复用器进行控制。其可以实现辅助的 7 输入函数功能或实现一个 8选1多路复用器的功能。
使用Verilog HDL和VHDL调用MUXF7的RTL描述,如代码清单1-3和代码清单1-4所示。
代码清单1-3 使用Verilog HDL调用F7MUX的RTL描述例子
注: 读者进入本书提供的\vivado_example\mux7_verilog资源目录中,用Vivado 2023.1打开名字为project1.xprj的工程文件。
代码清单1-4 使用VHDL调用MUXF7的RTL描述例子
注: 读者进入本书提供的\vivado_example\mux7_vhdl资源目录中,用Vivado 2023.1打开名字为project1.xprj的工程文件。
使用 Vivado 2023.1 对该设计进行综合后的结果如图1.9 所示。从图中可知,两个LUT 分别实现了规约“与”和规约“或”操作,两个 LUT 的输出送到 MUXF7 的输入,sel 信号作为MUXF7的选择端输入信号,MUXF7的输出连接到输出端口z。
显然,两个LUT和MUXF7的组合构成的13位位宽的输入变量和输出之间的函数如下:
z = f (a[5:0],b[5:0],sel)
思考与练习1-3: 请读者打开该设计综合后的结果,观察图1.9中每个查找表的内容。
思考与练习1-4: 请读者打开该设计实现后的结果,观察图 1.9 中 LUT 和 MUXF7 的布局布线结果。
F8MUX_BOT和F8MUX_TOP用于组合两个相邻的多路复用器。其中,后缀BOT和TOP表示该类型的多路复用器由SLICE外部输入的BX、FX控制信号对相应的F8MUX进行控制。其可以实现辅助的8输入函数功能或实现一个16选1多路复用器的功能。
图1.9 综合后的结果
在 UltraScale 和 UltraScale+架构中的原语库中,按如下描述 MUXF7 原语,即该设计元素是一个2选1多路复用器,它与两个LUT6相结合,可以在单个CLB内创建任何7输入逻辑函数,8选1多路复用器或其他高达13位位宽的逻辑函数。LUT6元件的输出连接到MUXF7的I0和I1输入。S输入来自任何网络。当为低时,S选择I0;当为高时,S选择I1。此外,按如下描述F8MUX原语,该设计元素是一个2选1多路复用器,与2个MUXF7和4个LUT6相结合,可以在单个CLB中创建任何8输入逻辑函数、16选1多路复用器或其他高达27位位宽的逻辑函数。MUXF7元件的输出连接到MUXF8的I0和I1输入。S输入来自任何网络。当为低时,S选择I0;当为高时,S选择I1。
下面使用Verilog HDL和VHDL的结构化描述,通过调用MUXF7和MUXF8,实现4选1多路复用器的功能,如代码清单1-5和代码清单1-6所示。
代码清单1-5 用于MUXF7和MUXF8的Verilog HDL结构级描述例子
注: 读者进入本书提供的\vivado_example\mux8_verilog_arch资源目录中,用Vivado 2023.1打开名字为project1.xprj的工程文件。
代码清单1-6 用于MUXF7和MUXF8的VHDL结构级描述例子
注: 读者进入本书提供的\vivado_example\mux8_vhdl_arch 资源目录中,用 Vivado 2023.1打开名字为project1.xprj的工程文件。
使用Vivado 2023.1对该设计进行综合后的结果如图1.10所示。从图中可知,在sel[1:0]信号的控制下,两个 MUXF7 分别对输入 a 和 b,以及 c 和 d 进行组合,这两个多路复用器的输出通过MUXF8的组合,最后送到输出端口。
图1.10 使用Vivado 2023.1对该设计进行综合后的结果(1)
思考与练习1-5: 观察图 1.10,说明该布局布线的原因(提示:输入直接连接到 6 输入 LUT的输出,然后连接到MUX7,这与UltraScale+FPGA元件库中对MUXF7的功能说明相一致)。
前面通过直接调用底层原语MUXF7和MUXF8实现了4选1多路复用器,根据已经学过的 Verilog HDL 和 VHDL 语法可知,4 选 1 多路复用器也可以使用 Verilog HDL 和VHDL 的RTL级描述,如代码清单1-7和代码清单1-8所示。
代码清单1-7 4选1多路复用器的Verilog HDL RTL描述例子
注: 读者进入本书提供的\vivado_example\mux8_verilog_rtl 资源目录中,用 Vivado 2023.1打开名字为project1.xprj的工程文件。
代码清单1-8 4选1多路复用器的VHDL RTL描述例子
注: 读者进入本书提供的\vivado_example\mux8_vhdl_rtl 资源目录中,用 Vivado 2023.1 打开名字为project1.xprj的工程文件。
使用Vivado 2023.1对该设计执行综合后的结果如图1.11所示。为什么在HDL RTL描述了多路选择的功能,但是在综合后的结果中并没有出现使用 FPGA 中的多路复用器呢?显然,从数字电路的角度很好理解,这是因为逻辑输入a、b、c、d和sel与输出z之间存在一个可以用真值表描述的逻辑关系,即
z = f (a,b,c,d,sel)
图1.11 使用Vivado 2023.1对该设计进行综合后的结果(2)
因此,Vivado综合工具将HDL RTL描述的比较关系转换为使用LUT表示的逻辑关系。与前面使用 HDL 的结构级描述相比,在结构级描述中,通过强制调用FPGA 底层MUXF7和MUXF8,使用FPGA 底层的多路复用器原语实现了4选1多路复用器的功能。因此,通过这个例子可知,HDL 的结构级描述最“贴近”FPGA 的底层硬件原语,对 FPGA 底层原语有很好的“掌控”能力,但建立复杂模型的效率较低;而 HDL 的 RTL 描述建立复杂模型的效率较高,但对 FPGA 底层原语的“掌控”能力稍弱。HDL 的行为级、RTL 和结构级描述与 FPGA 底层原语之间的关系如图1.12所示。
图1.12 HDL的行为级、RTL和结构级描述与FPGA底层原语之间的关系
注: FPGA 的底层原语(Primitive)是指存在于 FPGA内部的逻辑设计资源,如 CLB(以及 CLB 内的 LUT 和 FF等)、DSP切片、BRAM等。
MUXF9 用于组合两个 MUXF8,该类型的多路复用器由 SLICE 外部输入的 DX 控制信号进行控制。其可以实现辅助的8输入函数功能或实现一个32选1多路复用器的功能。
在 UltraScale 和 UltraScale+架构中的原语库中,按如下描述 F9MUX,该设计元素是一个两输入多路复用器,它与两个MUXF8、4个MUXF7和8个LUT6元件结合,可以在一个CLB内创建任何9个输入、32选1多路复用器或其他高达55位宽的逻辑函数。MUXF8元件的输出连接到MUXF9的I0和I1。S输入来自任何网络。当为低时,S选择I0;当为高时,S选择I1。
下面通过一个例子将LUT、MUXF7、MUXF8和MUXF9组合在一起,完整地呈现出它们之间的关系,其Verilog HDL和VHDL的RTL与结构级混合描述如代码清单1-9和代码清单1-10所示。
代码清单1-9 组合LUT和MUX的Verilog HDL描述例子
注: 读者进入本书提供的\vivado_example\mux9_verilog资源目录中,用Vivado 2023.1打开名字为project1.xprj的工程文件。
代码清单1-10 组合LUT和MUX的VHDL描述例子
注: 读者进入本书提供的\vivado_example\mux9_verilog资源目录中,用Vivado 2023.1打开名字为project1.xprj的工程文件。
使用 Vivado 2023.1 对该设计进行综合后的结果如图 1.13 所示。从图中可知,该设计中使用了8个6输入LUT、4个MUXF7、2个MUXF8、1个MUXF9。
图1.13 使用Vivado 2023.1对该设计进行综合后的结果
对综合后的结果进行布局布线,如图 1.14 所示。从图中可以看到该设计在一个 CLB 中使用了8个6输入LUT、4个MUXF7、2个MUXF8,以及1个MUXF9。此外,从图中可以很清晰地看到这些原语之间的连接关系。
图1.14 对综合后的结果进行布局布线
CLB 内提供了一个专用的快速超前进位逻辑,用来执行快速的加法和减法运算。多个快速进位逻辑可以级联在一起,实现更宽位数的加法和减法运算。
图1.15给出了UltraScale和UltraScale+架构FPGA中CLB内超前快速进位逻辑CARRY8的结构。
从图中可知,进位链向上运行,并且每个CLB具有8位宽度。进位初始化输入CYINIT用于选择进位链中的第一位。该输入的值为“0”时,用于加法;该输入的值为“1”时,用于减法或 AX 输入(用于动态第一位进位)。进位初始化功能在 CLB 底部进位链的开始处或中点处都可用,用于将进位链分成两个四位进位块。专用连接用于将进位从一个 CLB 的 COUT 引脚级联到上面CLB的CIN引脚。对于每一位,都有一个进位复用器(MUXCY)和一个专门的逻辑“异或”门(XOR),用于将操作数与所选的进位比特相加/相减。专用进位路径和进位多路复用器(MUXCY)也可以用于级联函数生成器,以实现宽的逻辑函数。
为了说明图 1.15 给出的超前进位加法器的结构,下面从一位加法器的结构开始,对于一位的全加器来说,用表1.6所示的真值表表示全加器的逻辑关系。表中的A和B分别表示参与二进制加法的两个一位二进制数,Cin 表示当前的进位输入,Cout 表示进位输出,S 表示二进制加法运算的求和结果。
图1.15 UltraScale和UltraScale+架构FPGA中CLB内超前快速进位逻辑CARRY8的结构
表1.6 全加器的逻辑关系
对表1.6给出的全加器逻辑关系进行重新排列,如表1.7所示。
表1.7 重排后的全加器真值表逻辑关系
观察表1.7,可知下面的规律。
(1)当A=“0”且B=“0”时:
①不论 Cin 是“0”还是“1”,Cout 均为“0”。由于此时 B=“0”。因此,可以用 B 作为输出。
② Cin="1",S="1";Cin="0",S="0".
(2)当A=“0”且B=“1”时:
① Cin="1",Cout="1";Cin="0",Cout="0".
② Cin=“1”,S=“0”;Cin=“0”时,S=“1”。
(3)当A=“1”且B=“0”时:
① Cin="1",Cout="1";Cin="0",Cout="0".
② Cin="1",S="0";Cin="0",S="1".
(4)当A=“1”且B=“1”时:
① Cout均为“1”。由于此时B=“1”。因此,可以用B作为输出。
② Cin="1",S="1";Cin="0",S="0".
根据上面的规律,将表1.7给出的三变量输入真值表简化为两输入真值表,如表1.8所示。
表1.8 简化为两输入变量的全加器真值表
对表1.8使用输入变量的卡诺图化简方法,得到下面的逻辑关系:
令A⊕B=P,B=G,则
对于一个2选1多路复用器,输入端为x和y,选择端为s,输出端为 o,如图 1.16 所示。当 s=“0”时,x 端口的输入送到 o 端口输出;当s=“1”时,y端口的输入送到o端口输出。
图1.16 2选1多路复用器
该2选1多路复用器的逻辑关系如表1.9表示。
表1.9 2选1多路复用器的逻辑关系
对表1.9给出的逻辑关系使用卡诺图化简,得到下面的关系:
因此,式(1.2)为一个 2 选 1 多路复用器的逻辑关系,综合式(1.1)和式(1.2)可得到下面的电路结构,如图1.17所示。
图1.17 一位全加器的电路结构
将图 1.17 给出的电路结构与图 1.15 中虚线方框内的结构相比,显然,图 1.15 中虚线框内的电路结构是图1.17一位全加器电路结构的串联。在图1.17中:
(1)P 分别映射到图 1.15 虚线框中的 S0~S7,称为超前进位逻辑的“传递”信号。S0~S7来自LUT的O6输出。
(2)G 分别映射到图 1.15 虚线框中的 DI0~DI7,称为超前进位逻辑的“生成”信号,来自LUT的O5输出(用于创建乘法器)或者切片的BYPASS输入(AX、BX、CX、DX、EX、FX、GX和HX)(用于创建加法器/累加器)。
(3)S分别映射到图1.15虚线框中的O0~O7,称为加法/减法的和。
(4)Cin 分别对应于图 1.15 虚线框中上一级进位的输出 CIN、CO0、CO1、CO2、CO3、CO4、CO5和CO6。
(5)Cout 分别对应于图 1.15 虚线框中每一级进位的输出 CO0~CO7。CO7 的输出可作为其他切片的Cin,这样可以构成更宽的进位链。
进一步观察图 1.17,两个输入 A 和 B 经过异或非门的逻辑运算关系,可以通过 LUT 实现,并且通过该LUT的O6输出,将B直接通过同一个LUT的O5输出。
下面通过调用 UltraScale+架构 FPGA 底层原语 LUT6_2 和 CARRY8,实现 8 位全加器功能。
LUT6_2 原语的内部结构如图 1.18 所示。在UltraScale 和 UltraScale+架构中的原语库中,按如下描述LUT6_2原语,该设计元件是6输入、2输出的LUT,它可以充当两个异步32位ROM(具有5位寻址),利用共享输入实现任意两个 5 输入逻辑功能,或者利用共享输入和共享逻辑值实现 6 输入逻辑功能和 5 输入逻辑功能。LUT 是基本的逻辑构建块,用于实现设计中的大部分逻辑功能。LUT6_2 将映射到 CLB 中的 8 个查找表中的一个。
图1.18 LUT6_2原语的内部结构
必须指定由64位十六进制值组成的INIT属性来指示 LUT 的逻辑函数。INIT 的值是通过在应用相关输入时将“1”分配给相应的 INIT 位值来计算的。例如,如果 Verilog HDL INIT 值为64'hFFFFFFFFFFFFFFFE(VHDL为X“FFFFFFFFFFFFFFFE”),则O6输出为“1”,除非输入端全为零,O5输出为“1”;或者,除非I[4:0]全为零(5输入或6输入或门)。INIT值的下半部分(31:0)应用于O5输出的逻辑函数。
FPGA LUT原语的INIT参数是赋予LUT逻辑值的参数。默认情况下,该值为零。因此,无论输入值是什么,都会将输出驱动为零。但是,在大多数情况下,必须确定新的INIT值才能指定LUT原语的逻辑函数。至少有两种方法可以确定LUT所需的INIT值。
(1)逻辑表方法:确定 LUT 所需 INIT 值的常用方法是使用逻辑表。要做到这一点,只需创建一个包含所有可能输入的二进制逻辑表,指定输出的所需逻辑值,然后根据这些输出值创建INIT字符串。
(2)表达式方法。确定LUT所需INIT值的另一种方法是为LUT的每个输入定义与其列出的真值相对应的参数或类属,并使用这些参数或类属来构建 FPGA 开发人员想要的逻辑等式。一旦掌握了这个概念,这个方法就更容易理解,并且逻辑表方法更能自己记录。但是,该方法确实需要代码实现指定合适的参数或类属。
LUT6_2逻辑输入和输出之间的关系如表1.10所示。
表1.10 LUT6_2逻辑输入和输出之间的关系
该设计的Verilog HDL和VHDL描述如代码清单1-11和代码清单1-12所示。
代码清单1-11 8位超前进位加法器的Verilog HDL描述例子
注: 读者进入本书提供的\vivado_example\carry_verilog资源目录中,用Vivado 2023.1打开名字为project1.xprj的工程文件。
代码清单1-12 8位超前进位加法器的VHDL描述例子
注: 读者进入本书提供的\vivado_example\carry_vhdl资源目录中,用Vivado 2023.1打开名字为project1.xprj的工程文件。
使用 Vivado 2023.1 对该设计执行综合后的结果如图 1.19 所示。从图中可知,通过调用LUT6_2原语和CARRY8原语,构成了包含超前进位逻辑的8位全加器电路结构。使用Vivado 2023.1对该设计进行布局布线后的结果如图1.20所示。
图1.19 使用Vivado 2023.1对该设计进行综合后的结果
图1.20 使用Vivado 2023.1对该设计进行布局布线后的结果
每个CLB的切片内有16个存储元件,其中每一个存储元件都可以配置为边沿触发的D触发器,或者电平触发的锁存器。在UltraScale/UltraScale+架构FPGA中,将16个存储元件分成上半部分和下半部分,每部分内包含8个存储元件;每个LUT的输入与两个存储元件连接。因此,每两个存储元件构成一对存储元件,分别用FF和FF2表示。
基于上面的结构特点,上半部分存储元件和下半部分存储元件各包含 4 对存储元件,分别用A~D、E~H表示。
在UltraScale/UltraScale+FPGA结构中,为每个CLB提供了两个时钟输入和两个置位/复位(SR)输入。它们分别分配到上半部分和下半部分的存储元件。而对于置位/复位,提供同步或者异步两种方式。如图 1.21 所示为 UltraScale+Kintex 系列 FPGA 中 16 个存储元件的控制信号。
图1.21 UltraScale+Kintex系列FPGA中16个存储元件的控制信号
如图 1.22 所示,在 UltraScale 结构中,每个存储元件的输入 FFMUX,其有 6 个输入源,包括:
图1.22 一对存储元件的D输入
(1)LUT的O6输出(D6)。
(2)LUT的O5输出(D5)。
(3)CLB的输入信号,该信号直接旁路LUT(BYP)。CLB X输入用于Q1,CLB I输入用于Q2(BYP)。
(4)进位的逻辑异或结果(XORIN)。
(5)进位级联输出(CY)。
(6)多路复用器输出的一个(对于底部的LUT A,不可用)(F7F8)。
思考与练习1-6: 在Vivado 2023.1中打开Device视图,仔细查看图1.21给出的与16个存储元件相连的控制信号。并回答下面的问题。
(1)总共有____个时钟信号CLK,它们分别控制_______个存储元件。
(2)总共有____个时钟使能信号CE,它们分别控制_____个存储元件。
(3)总共有_____个置位和复位信号,它们分别控制_____个存储元件。
思考与练习1-7: 在 Vivado 2023.1 中打开 Device 视图,仔细查看图 1.22 给出的 FFMUX与FPGA内其他原语的连线路径。
切片内的两个置位/复位(Set&Reset,SR)信号可通过HDL设置为同步或异步。对于任何单独的存储元件,可以将 SR 编程为置位或复位,但不同时将其编程为置位和复位,这一点要特别注意。
触发器/锁存器的SR的配置选项包括:
(1)无置位和复位。
(2)同步置位(FDSE原语)。
(3)同步复位(FDRE原语)。
(4)异步置位(预置)(FDPE原语)。
(5)异步复位(清除)(FDCE原语)。
对于 4 个触发器的组(与 CE 输入控制的组相同),可以忽略 SR。当一个存储元件使能了SR时,组中的其他3个存储元件也必须使能SR。
可以针对切片中的每个存储元件单独控制置位和复位的选择。同步(SYNC)或异步(ASYNC)置位/复位(SYNC_ATTR)的选择以8个触发器为一组进行控制,分别用于两个单独的SR。
配置后的初始状态由一个单独的 INIT 属性定义,该属性可以指定为“0”或“1”。默认情况下,将 SR 定义为一个置位,定义 INIT=“1”;将 SR 定义为一个复位,定义 INIT=“0”。INIT可以独立于SR功能进行定义。
存储元件同步复位和异步置位的Verilog HDL和VHDL描述如代码清单1-13和代码清单1-14所示。
代码清单1-13 存储元件同步复位和异步置位的Verilog HDL描述例子
注: 读者进入本书提供的\vivado_example\ff_verilog 资源目录中,用 Vivado 2023.1 打开名字为project1.xprj的工程文件。
代码清单1-14 存储元件同步复位和异步置位的VHDL描述例子
注: 读者进入本书提供的\vivado_example\ff_vhdl 资源目录中,用 Vivado 2023.1 打开名字为project1.xprj的工程文件。
使用 Vivado 2023.1 对该设计进行综合后的结果如图 1.23 所示。从图中可知,由于该设计包含了同步复位和异步置位电路,因此在底层调用了同步复位原语 FDRE 和异步置位原语FDPE。使用Vivado 2023.1对该设计进行布局布线后的结果如图1.24所示。
图1.23 使用Vivado 2023.1对该设计进行综合后的结果
图1.24 使用Vivado 2023.1对该设计进行布局布线后的结果
SLICEM内的函数发生器(LUT)可以作为同步RAM资源,也称为分布式RAM。分布式RAM 模块是同步(写)资源。写时钟来自独立于存储元件的两个时钟的专用 SLICEM 输入LCLK。对于写入操作,写入使能(Write Enable,WE)必须设置为“1”(高电平)。默认情况下,读取是异步的。同步读取可用同一SLICEM中的触发器来实现。通过使用该触发器,因为减少了从时钟到输出的延迟,所以提高了分布式RAM的性能,但是,增加了额外的时钟延迟。
在这里说明一下同步写操作和异步读操作的概念。同步写操作是具有激活高写入使能(WE)功能的单时钟沿操作。当 WE 为“1”(高电平)时,输入(D)被加载到地址 A 处的存储器位置。异步读操作是指输出由单端口模式SPO输出的地址A或双端口模式DPO输出的地址 DPRA 确定。每次将新地址用于地址引脚时,在访问 LUT 的时间延迟后,该地址的存储器位置中的数据值在输出上可用。显然,读取操作与时钟信号无关。
SLICEM内的多个LUT可组合构成最多512位的RAM。
包括 32×(1~16)位、64×(1~8)位、128×(1~4)位、256×(1~2)位或 512×1 位。图 1.25给出了64×1位单端口(Single Port,SP)分布式RAM的结构。从图中可知,该结构包含用于同步写入和异步读取的通用地址端口。读取和写入地址共享同一地址总线。单端口分布式RAM由SPRAM32/SPRAM64的LUT配置定义。其中,SPRAM32用于具有5 个地址输入的 32×1 位的 RAM,SPRAM64 用于具有 6 个地址(A[5:0])输入的 64×1 位的RAM。通过连接第六根地址线(逻辑“1”)并独立使用 O5 和 O6 输出,可以将具有公共地址输入的两个SPRAM32组合在同一个LUT中。
图1.25 64×1位单端口分布式RAM的结构
显然,如果一个 SLICEM 中的 8 个 LUT 共享相同的时钟、写使能,以及共享读和写端口地址输入,则8个RAM64×1S原语将占用一个SLICEM。该配置等效于一个64×8位的单端口分布式RAM。
单端口存储器的信号功能如下。
(1)WCLK:该信号用于同步写入。数据和地址输入引脚具有参考 WCLK 引脚的建立时间。时钟信号(WCLK)在切片级具有翻转选项,其可以在时钟的上升沿或下降沿活动而不需要其他逻辑资源。默认值为时钟上升沿。
(2)WE:该信号影响端口的写入功能。无效的 WE 信号会阻止对存储器单元的任何写入操作。有效的WE信号将使数据在时钟边沿写入输入地址所指向的存储器位置。
(3)A[#:0](用于单端口和双端口)、DPRA[#:0](用于双端口)和 ADDRA[#:0]~ADDRH[#:00] (用于 8 端口):该信号用于选择用于读取或写入的存储单元。端口的宽度决定了所需要的地址输入。
(4)D、DIH[#:0]:数据输入。数据输入 D(用于单端口和双端口)和 DIH[#:0](用于 8 端口)提供了写入RAM的新的数据值。
(5)O、SPO、DPO和DOA[#:0]~DOH[#:0]:数据输出。O、SPO (单端口)、DPO(双端口)和 DOA[#:0]~DOH[#:0](8 端口)反映了地址输入所引用的存储单元的内容。在活动的写入时钟沿后,数据输出(O、SPO或DOH[#:0])反映新写入的数据。
包括 32×(1~4)位、64×(1~4)位、128×1 位或者 256×1 位。图 1.26 给出了 64×1 位双端口(Dual Port,DP)分布式RAM的结构。在该结构中,一个端口用于同步写入,另
一个端口用于异步读取。第二个函数发生器具有连接到第二个只读端口地址的地址输入,并且写地址(WA)输入与第一个读/写端口地址共享。4 端口和 8 端口配置添加了额外的函数发生器作为异步读取端口。
只要共享相同的时钟,以及共享读和写端口地址输出,4 个 RAM64×1D 会占用一个SLICEM。该配置相当于一个64×4位的分布式DPRAM。
包括 32×(1~14)位、64×(1~7)位。在简单双端口中,一个端口用于同步写(没有来自写入端口的数据输出/读端口);一个端口用于异步读取。简单的双端口配置可以扩展到一个切片内的64×7位存储器,该存储器具有一个专用写端口和7个读端口,如图1.27所示。
图1.26 64×1位双端口分布式RAM的结构
图1.27 64×7简单双端口分布式RAM的结构
包括32×(1~4)位、64×(1~2)位、128×1位。
包括64×1位。
一个宽度为4位、深度为16的分布式存储器的Verilog HDL和VHDL描述如代码清单1-15和代码清单1-16所示。
代码清单1-15 一个宽度为4位、深度为16的分布式存储器的Verilog HDL描述例子
注: 读者进入本书提供的\vivado_example\ram_verilog 资源目录中,用 Vivado 2023.1 打开名字为project1.xprj的工程文件。
代码清单1-16 一个宽度为4位、深度为16的分布式存储器的VHDL描述例子
注: 读者进入本书提供的\vivado_example\ram_vhdl 资源目录中,用 Vivado 2023.1 打开名字为project1.xprj的工程文件。
使用 Vivado 2023.1 对该设计进行综合后的结果如图 1.28 所示。从图中可知,在该设计中,调用了RAM32×1S原语,该原语为32×1位单端口分布式存储器。RAM32×1S原语的地址线 A4 连接到 GROUND(“0”)。每个 RAM32×1S 原语的地址线实际为 A0~A3,寻址范围为0~15。因此,通过调用4个RAM32×1S原语,构成了16×4位单端口分布式存储器。进一步观察可知,每个RAM32×1S原语端口O的输出连接到了FDRE原语(同步复位)。
图1.28 使用Vivado 2023.1对该设计进行综合后的结果(1)
使用 Vivado 2023.1 对该设计进行布局布线后的结果如图 1.29 所示。从图中可以看出,在一个SLICEM切片中,实际只使用了两个LUT,从这两个LUT的O5和O6端口分别连接到了切片内的4个触发器中。那为什么只使用两个LUT就可以实现16×4位单端口分布式存储器的功能。读者可以在Vivado的Device视图中放大LUT,以进一步观察LUT的细节。
在图 1.29 中,两个 LUT 的 WA5 与 A5 连接在一起,并且连接到了逻辑“1”(VCC),参考表1.10给出的LUT6_2的O5和O6与I5的关系,就理解为什么一个LUT可以实现综合网表中两个分布式RAM的功能。
SLICEM和SLICEL内的每个LUT都可以实现一个64×1位的ROM。提供了4种ROM的配置方式,包括ROM64×1位(1个LUT)、ROM128×1位(2个LUT)、ROM256×1位(4个LUT)和ROM512×1位(8个LUT)。
图1.29 使用Vivado 2023.1对该设计进行布局布线后的结果(1)
一个分布式ROM的Verilog HDL和VHDL描述如代码清单1-17和代码清单1-18所示。
代码清单1-17 一个分布式ROM的Verilog HDL描述例子
注: (1)读者进入本书提供的\vivado_example\rom_verilog 资源目录中,用 Vivado 2023.1打开名字为project1.xprj的工程文件。
(2)data.txt文件在\vivado_example\rom_verilog\project_1.src\sources_1\new目录下。
代码清单1-18 一个分布式ROM的VHDL描述例子
注: (1)读者进入本书提供的\vivado_example\rom_vhdl 资源目录中,用 Vivado 2023.1 打开名字为project1.xprj的工程文件。
(2)data.txt文件在\vivado_example\rom_vhdl\project_1.src\sources_1\new目录下。
使用Vivado 2023.1对该设计进行综合后的结果如图1.30所示。
图1.30 使用Vivado 2023.1对该设计执行综合后的结果(2)
对综合后的网表添加设计约束,如代码清单1-19所示。
代码清单1-19 设计约束条件
注: 读者进入本书提供的\vivado_example\rom_verilog\project_1.srcs\constrs_1\new\资源目录中,打开top.xdc文件。
使用 Vivado 2023.1 对该设计进行布局布线后的结果如图 1.31 所示。从图中可知,当对综合后的网表添加物理布局约束后,在一个切片中,通过占用 4 个 LUT 和 8 个触发器实现了ROM 的内容。类似地,在综合后的网表中我们看到的是 8 个 LUT,而在布局布线后的网表中,通过使用一个LUT的O5和O6输出,将综合后给出的8个LUT压缩到了4个LUT。
图1.31 使用Vivado 2023.1对该设计进行布局布线后的结果
思考与练习1-8: 在布局布线后的 Device 视图中,查看该设计所使用切片内的 LUT 和触发器资源,以及这些资源的连接关系,并对布局布线后的网表结构进行分析。
在不使用触发器的情况下,可以将一个 SLICEM 函数发生器配置为一个 32 位的移位寄存器。当用作移位寄存器时,每个LUT 可以将串行数据延迟1~32 个时钟。当移位输入 D(DI1 LUT 引脚)和移位输出 Q31(MC31 LUT 引脚)连接在一起时,就可以构成更大的移位寄存器。因此,当把一个SLICEM内的8个LUT级联在一起时,可以产生最多256个时钟周期的延迟。在 UltraScale/UltraScale+架构中,可以跨越 SLICEM 将移位寄存器进行组合。因此,最终得到的可编程延迟,用于平衡数据流水线的时序。
移位寄存器的应用包括:时延或者延迟补偿;同步 FIFO 和内容可寻址存储器(Content Addressable Memory,CAM)。
移位寄存器的功能包括:
(1)写操作。通过时钟输入和一个可选的时钟使能进行同步。
(2)到 Q31 的固定读访问,用于级联到下面的 LUT。最下面 LUT A 的 Q31 连接到SLICEM的输出,用于直接使用或者级联到下一个SLICEM。
(3)动态地读访问。通过5位地址线A[4∶0]执行,没有使用LUT地址的LSB,软件工具自动地将其拉高;通过不同的地址,可以异步读出任何32位数据(在O6 LUT输出)。在创建小的(少于 32 位)移位寄存器时,这个功能非常有用。例如,当构建一个 13 位的移位寄存器时,简单地将地址设置为第13位。
图1.32 32位移位寄存器的配置
(4)一个存储元素或者触发器可以用来实现一个同步读操作功能。时钟到触发器的输出决定了整个延迟,并且改善了性能。因此,增加了一个额外的延迟。
(5)不支持移位寄存器的置位或复位。但是,当配置完成后,可以初始化为任意的值。
图 1.32给出了 32位移位寄存器的配置。
占用一个函数发生器的移位寄存器配置的例子如图1.33所示。
图1.33 占用一个函数发生器的移位寄存器配置的例子
一个16位移位寄存器的Verilog HDL和VHDL描述如代码清单1-20和代码清单1-21所示。
代码清单1-20 一个16位移位寄存器的Verilog HDL描述例子
注: 读者进入本书提供的\vivado_example\shifter_verilog 资源目录中,用 Vivado 2023.1 打开名字为project1.xprj的工程文件。
代码清单1-21 一个16位移位寄存器的VHDL描述例子
注: 读者进入本书提供的\vivado_example\shifter_vhdl 资源目录中,用 Vivado 2023.1 打开名字为project1.xprj的工程文件。
使用 Vivado 2023.1 对该设计进行综合后的结果如图 1.34 所示。从图中可知,与使用切片内的存储元件实现16位移位寄存器相比,实现成本显著降低。
注: (1)对于SRL16而言,一个LUT等效于16个触发器;对于SRL32而言,一个LUT等效于32个触发器。
(2)使用SRL唯一的限制就是,不能对寄存器内的每个元素进行单独复位操作。
SRL16E的内部结构如图1.35所示。从该结构可知,它可以实现可变长度的移位寄存器。在图1.34给出的结构中,SRL16E的输入A3A2A1A0为“1101”,则读取从第14个寄存器的输出。
图1.34 使用Vivado 2023.1对该设计进行综合后的结果
图1.35 SRL 16E的内部结构
注: (1)第14个寄存器的索引为“1101”,索引从“0000”开始。
(2)从图1.34可知,SRL16E后的FDRE可以额外增加一个延迟。
思考与练习1-9: 根据图1.34给出的综合结果,分析该移位寄存器的实现原理。
使用 Vivado 2023.1 对该设计进行布局布线后的结果如图 1.36 所示。从图中可知,该设计使用了SLIMEM类型切片内的一个LUT和两个存储元件。
图1.36 使用Vivado 2023.1对该设计进行布局布线后的结果