数字IC设计 FPGA——再谈加法器设计(使用Verilog 原语 进行四位加法器设计)
前面介绍了关于xilinx FPGA CLB的基本原理和结构,以及如何使用原语进行设计(在一般的设计中使用不到,本节只是更好理解FPGA内部逻辑块资源的使用),参考这篇博客: 浅谈XILINX FPGA CLB单元 汇总 (CLB、LUT、存储单元、Distributed RAM、移位寄存器、多路复用器、进位逻辑(Carry Logic))
之前写过一篇关于如何使用Verilog 设计半加器,全加器及超前进位加法器的博客:数字电路基础知识(四) 加法器-半加器、全加器与超前进位加法器
在使用FPGA进行设计时,如果能对FPGA中的资源分布及配置能有详细的了解,对于设计高性能的计算硬件具有更好的指导意义。因此我们可以使用原语来设计快速加法器或乘法器等比较常用的电路。
因为一个全加器由输入A,B,及进位信号Cout 三个输入端口,所以利用查找表进行设计,应该选用LUT3以上的查找表,下面针对LUT3 单元进行设计分析 下面的结构是经典的行波进位加法器
全加器 有关基本的加法器的介绍本节会略去。 一位全加器的基本逻辑方程: S = A xor B xor Cin Cout = (A and B) or (A and Cin) or (B and Cin) 下表给出了真值表: 因此输出S的三位查找表的初始值为:8’b1001_0110 (8’h96) 进位输出Cout的三位查找表的初始值为:8’b1110_1000 (8’hE8)
使用Vivado进行一位全加器的设计 代码如下:
module addr_1bit( A,B,Cin,S,Cout ); input A,B; input Cin; output S,Cout; LUT3 #( .INIT(8'h96) // Specify LUT Contents 查找表值 ) LUT3_inst1 ( .O(S), // LUT general output 结果输出端 .I0(Cin), // LUT input .I1(B), // LUT input .I2(A) // LUT input ); LUT3 #( .INIT(8'hE8) // Specify LUT Contents 查找表值 ) LUT3_inst2 ( .O(Cout), // LUT general output 进位输出端 .I0(Cin), // LUT input .I1(B), // LUT input .I2(A) // LUT input ); endmoduleLUT3_inst1和LUT3_inst2分别是S 结果输出端和Cout进位输出端。
仿真结果四位全加器的设计 module addr_4bit( A,B,Ci,S,Co ); input [3:0] A,B; input Ci; output [3:0] S; output Co; wire [4:0] Cin; genvar i; generate assign Ci = Cin[0]; assign Co = Cin[4]; for (i=0;i<4;i=i+1) begin: label // label是实例化之后的名称 addr_1bit u( .A(A[i]), .B(B[i]), .S(S[i]), .Cout(Cin[i+1]), .Cin(Cin[i]) ); end endgenerate endmodule需要注意的是Cin是线网wire类型的变量,位宽为5bit。addr_1bit即为上面的一位全加器的模块。
对于generate语句块,这是Verilog 2001语法中新增的语法,方便了设计者设计电路。 但需要注意generate-for语句: (1) 必须有genvar关键字定义for语句的变量。 (2)for语句的内容必须加begin和end(即使就一句)。 (3)for语句必须有个名字。
上面的generate 的代码片段等效于下面:
/* addr_1bit u1(.A(A[0]),.B(B[0]),.S(S[0]),.Cin(Cin[0]),.Cout(Cin[1])); addr_1bit u2(.A(A[1]),.B(B[1]),.S(S[1]),.Cin(Cin[1]),.Cout(Cin[2])); addr_1bit u3(.A(A[2]),.B(B[2]),.S(S[2]),.Cin(Cin[2]),.Cout(Cin[3])); addr_1bit u4(.A(A[3]),.B(B[3]),.S(S[3]),.Cin(Cin[3]),.Cout(Cin[4])); assign Ci = Cin[0]; assign Cout = Cin[4]; */其RTL电路为: 仿真结果如下: 可以看到有正确的结果输出和进位输出 5. 利用LUT3设计四位加法器的资源利用及延迟情况
我们将S0作为三位查找表的输出,其初始值仍为:8’b1001_0110 (8’h96); 输出S1的五位查找表,初始值为:32’b1001_1001_1001_0110_1001_0110_0110_0110 (32’h9996_9666); 输出Cout的五位查找表,初始值为:32’b1110_1110_1110_1000_1110_1000_1000_1000 (32’hEEE8_E888)
一级对应的全加器代码如下: RTL电路结构: 两级形成四位全加器 module addr_4bit( a0,a1,b0,b1,Ci,s0,s1,Co ); input [1:0] a0,a1,b0,b1; input Ci; output [1:0] s0,s1; output Co; wire [2:0] Cin; addr_2bit u1( .A0(a0[0]), .A1(a0[1]), .B0(b0[0]), .B1(b0[1]), .S0(s0[0]), .S1(s0[1]), .Cin(Cin[0]), .Cout(Cin[1]) ); addr_2bit u2( .A0(a1[0]), .A1(a1[1]), .B0(b1[0]), .B1(b1[1]), .S0(s1[0]), .S1(s1[1]), .Cin(Cin[1]), .Cout(Cin[2]) ); assign Ci = Cin[0]; assign Co = Cin[2]; endmoduleRTL电路结构: 仿真结果: 5. 两级形成四位全加器的资源利用和延迟情况对比 可以看到和之前采用LUT3设计的四位加法器相比,资源利用变少了,关键路径延迟也变小了。
但需要说明一点的是: 如果再不采用原语进行设计的情况下,直接编写加法器Verilog代码,综合工具会根据自己的算法给出一个比较合理的电路,可能会比我们采用后一种方法设计的要更好,这需要依赖EDA综合工具。 但是通过了解CLB的不同的基本配置方式以及内部资源分布,对于更好理解软件综合过程和设计具有更好的指导意义,如果能再关键的位置手动配置硬件资源,可能会改善局部性能,这对于高性能计算硬件有重要意义,尤其是底层的硬件加法等部件。