Vivado中的加法器电路结构

本文详细介绍了Vivado设计工具中利用SLICE中的LUT和进位链实现加法器的过程,包括全加器结构、SLICE工作原理以及实例测试,展示了如何通过LUT级联来构建加法器功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先给出结论,Vivado中的加法器是利用SLICE中的LUT和进位链实现的。

一、全加器

一位全加器的结构如下:

在这里插入图片描述

其中:

  • A、B为输入的两个加数
  • CI为进位
  • CO为本位对高位的进位
  • S为本位和

输出与输入的逻辑关系为:

S = A ⊕ B ⊕ C i n C o u t = A B + B C i n + A C i n S=A\oplus B\oplus C_{in}\\ C_{out}= AB+BC_{in}+AC_{in} S=ABCinCout=AB+BCin+ACin

二、SLICE如何实现加法器

SLICEM的结构如下:

在这里插入图片描述

CARRY4进位链结构如下:

在这里插入图片描述

介绍图中几个信号的含义:

  • CIN:进位信号
  • DI:数据输入,两个加数或的结果;
  • O:本位和
  • CO:本位对高位的进位
  • S:两个加数异或的结果

参考全加器输出与输入的对应关系

S = A ⊕ B ⊕ C i n C o u t = A B + B C i n + A C i n S=A\oplus B\oplus C_{in}\\ C_{out}= AB+BC_{in}+AC_{in} S=ABCinCout=AB+BCin+ACin

再观察下图中红色框部分,其中,LUT的O6输出(O6 From LUTA)和进位CIN进行异或得到输出AMUX,对比公式可知这个为本位和的输出,,可以选择直接输出也可以选择经过触发器同步输出。

在这里插入图片描述

而本位对高位的进位在图中是如何体现的呢?

首先明确四个信号,在图中已标出:

在这里插入图片描述

当S0为0时,MUX输出左边的DI,若S0为1则输出CIN。

具体分析如下:

  • 若S0为0说明两个加数要么为00,要么为11,此时输出的是DI即两个加数相或的结果

    ①如果为0表明两个加数为00,DI为0,根本不会产生进位,因此CO0输出0;

    ②如果为1表明两个加数为11,DI为1,一定会产生进位,因此CO0输出1;

    两种情况下CO0的输出和DI的值相同。

  • 若S0为1表明两个加数中只有一个1,这时只要CIN为1就有进位,CO0输出1;为0 则没有进位,CO0输出0,CO0的输出与CIN值相同。

那重点是如何实现让S表示两个数异或的结果,让DI表示两数相互或的结果?

这就利用到将1一个六输入LUT当作两个5输入LUT的原理。LUT6的结构如下:

在这里插入图片描述

因此我们需要将上面LUT5的输出对应S,下面的LUT5输出对应DI,如何实现?就是通过填写LUT5的初始值(LUT就像真值表一样,根据输入的情况产生对应的输出)。

三、实例测试

1.直接使用加法器

module full_add(
    input [7:0] a,
    input [7:0] b,
    input c_in,
    output [7:0] sum
    );
assign sum=a+b+c_in;
endmodule

综合后的电路为:

在这里插入图片描述

大部分电路结构和我们上述分析的是一致的,但是我们也会发现有几个不同的地方(仅分析低4bit对应的电路):

(1)b[0]没有和a[0]连入一个查找表,而是b[0]连接到动态进位输入CYINIT,a[0]和c_in构成了查找表的输出S0;

(2)DI连接的不少查找表的O5输出,而是连接的a[3:0]

S = a ⊕ c i n D I = a S=a\oplus c_{in} \\DI=a \\ S=acinDI=a

而原来的情况下:

S = a ⊕ b D I = a + b S=a\oplus b \\DI=a+b \\ S=abDI=a+b

那这样的效果和之前描述的效果一样吗?

首先可以明确的是对于本位和是没有影响的,因为本位和是三者的异或。将b[0]和c_in换位置并不影响。

但是本位对高位的进位就不一定了,因为要经过S控制的MUX,做如下分析:

之前说过S为0选择DI输出,S为1选择低位对本位的进位(对于第一级就是b)输出。

①假设c_in为0

abSDIC[0]
00000
01000
10110
11111

符合要求。

②假设c_in为1

abSDIC[0]
00100
01101
10011
11011

也符合要求。

但是不理解为什么会综合成这个结果…

2.LUT级别

为能够更深入的理解进位链的结构和LUT的关系,给出采用LUT级别实现加法器的例子。

参考LUT6的结构发现其为两个LUT5的组合,因此给出两个5输入LUT真值表如下:

(1)上面LUT5的真值表(两个输入异或,用于输出O6)

I4-I2I0(a)I1(b)O6
0000
0011
0101
0110

(2)下面LUT5的真值表(两个输入相或,用于输出O5)

I4-I2I0(a)I1(b)O6
x000
x011
x101
x111
module ADD_lut(
  input rst,
  input clk,
  input CE,
  input [7:0]a,
  input [7:0]b,
  output [7:0]sum,
  output [7:0]co
);

  wire [7:0]sum;
  wire [7:0]lut_o6;
  wire [7:0]lut_o5;
  

  LUT6_2#(.INIT(64'h66666666EEEEEEEE))LUT6_2_inst0(.O6(lut_o6[0]),.O5(lut_o5[0]),.I0(a[0]),.I1(b[0]),.I2(0),.I3(0),.I4(0),.I5(1));
  LUT6_2#(.INIT(64'h66666666EEEEEEEE))LUT6_2_inst1(.O6(lut_o6[1]),.O5(lut_o5[1]),.I0(a[1]),.I1(b[1]),.I2(0),.I3(0),.I4(0),.I5(1));
  LUT6_2#(.INIT(64'h66666666EEEEEEEE))LUT6_2_inst2(.O6(lut_o6[2]),.O5(lut_o5[2]),.I0(a[2]),.I1(b[2]),.I2(0),.I3(0),.I4(0),.I5(1));
  LUT6_2#(.INIT(64'h66666666EEEEEEEE))LUT6_2_inst3(.O6(lut_o6[3]),.O5(lut_o5[3]),.I0(a[3]),.I1(b[3]),.I2(0),.I3(0),.I4(0),.I5(1));
  LUT6_2#(.INIT(64'h66666666EEEEEEEE))LUT6_2_inst4(.O6(lut_o6[4]),.O5(lut_o5[4]),.I0(a[4]),.I1(b[4]),.I2(0),.I3(0),.I4(0),.I5(1));
  LUT6_2#(.INIT(64'h66666666EEEEEEEE))LUT6_2_inst5(.O6(lut_o6[5]),.O5(lut_o5[5]),.I0(a[5]),.I1(b[5]),.I2(0),.I3(0),.I4(0),.I5(1));
  LUT6_2#(.INIT(64'h66666666EEEEEEEE))LUT6_2_inst6(.O6(lut_o6[6]),.O5(lut_o5[6]),.I0(a[6]),.I1(b[6]),.I2(0),.I3(0),.I4(0),.I5(1));
  LUT6_2#(.INIT(64'h66666666EEEEEEEE))LUT6_2_inst7(.O6(lut_o6[7]),.O5(lut_o5[7]),.I0(a[7]),.I1(b[7]),.I2(0),.I3(0),.I4(0),.I5(1));
  
  CARRY4 CARRY4_inst0(.CO(co[3:0]),.O(sum[3:0]),.CI(1'b1),.CYINIT(1'b0),.DI(lut_o5[3:0]),.S(lut_o6[3:0]));
  CARRY4 CARRY4_inst1(.CO(co[7:4]),.O(sum[7:4]),.CI(co[3]),.CYINIT(1'b0),.DI(lut_o5[7:4]),.S(lut_o6[7:4]));
  
  FDRE FDRE_inst0(.Q(o_sum[0]),.C(clk),.CE(CE),.R(rst),.D(sum[0]));
  FDRE FDRE_inst1(.Q(o_sum[1]),.C(clk),.CE(CE),.R(rst),.D(sum[1]));
  FDRE FDRE_inst2(.Q(o_sum[2]),.C(clk),.CE(CE),.R(rst),.D(sum[2]));
  FDRE FDRE_inst3(.Q(o_sum[3]),.C(clk),.CE(CE),.R(rst),.D(sum[3]));
  FDRE FDRE_inst4(.Q(o_sum[4]),.C(clk),.CE(CE),.R(rst),.D(sum[4]));
  FDRE FDRE_inst5(.Q(o_sum[5]),.C(clk),.CE(CE),.R(rst),.D(sum[5]));
  FDRE FDRE_inst6(.Q(o_sum[6]),.C(clk),.CE(CE),.R(rst),.D(sum[6]));
  FDRE FDRE_inst7(.Q(o_sum[7]),.C(clk),.CE(CE),.R(rst),.D(sum[7]));
  FDRE FDRE_inst8(.Q(o_sum[8]),.C(clk),.CE(CE),.R(rst),.D(co[7]));
  
endmodule

综合出来的电路结构如下:

在这里插入图片描述

这个就和上述介绍的完全一致了。

### Vivado 中定点数补位操作方法 在 Vivado 的设计过程中,处理定点数的补位操作通常涉及 Verilog 或 VHDL 编程以及 IP 核配置。以下是针对定点数补位的具体实现方式: #### 1. 符号扩展与零扩展 对于有符号数,在进行加法或乘法前需对数据进行 **符号扩展**,以防止计算过程中的溢出。这可以通过硬件描述语言(如 Verilog)来完成。 ```verilog // 假设输入信号为 a 和 b,均为 n 位宽度 wire signed [n-1:0] a, b; wire signed [m-1:0] result; assign extended_a = {{(m-n){a[n-1]}}, a}; // 对 a 进行符号扩展到 m 位[^1] assign extended_b = {{(m-n){b[n-1]}}, b}; // 对 b 进行符号扩展到 m 位 always @(*) begin result = extended_a + extended_b; // 执行加法运算 end ``` 对于无符号数,则采用 **零扩展** 来增加位宽。 ```verilog assign zero_extended_a = { {(m-n){1'b0}}, a }; // 零扩展到 m 位 ``` --- #### 2. FPGA 定点小数乘法中的补位 当执行定点小数乘法时,按照引用的内容,可以总结如下步骤: 1. 将负数转换为其绝对值形式(通过补码表示),即将其按位取反后再加一。 ```verilog wire [n-1:0] abs_num; assign abs_num = ~negative_number + 1'b1; // 负数转正数 (补码)[^2] ``` 2. 移除符号位后进行相乘,并根据结果调整位宽至指定大小(例如 10 位)。 ```verilog reg [(2*n)-1:0] product; always @(*) begin product = multiplicand * multiplier; // 正常相乘 end // 截断多余高位并保留低位精度 wire [9:0] truncated_product; assign truncated_product = product[(2*n)-1-(n-1):n]; ``` 3. 添加最终结果的符号位,形成完整的 11 位输出。 ```verilog wire sign_bit; assign sign_bit = multiplicand_sign ^ multiplier_sign; // 取异或得到符号位[^2] wire [10:0] final_result; assign final_result = {sign_bit, truncated_product}; ``` --- #### 3. 使用 Vivado HLS 实现自动补位 Vivado HLS 提供了一种更高级的方式来自动生成这些逻辑。开发者只需定义变量的数据类型及其范围即可让工具自动生成相应的补位逻辑。 例如,声明一个 `ap_fixed` 类型用于定点数运算: ```cpp #include "hls_math.h" typedef ap_fixed<11, 5> fixed_point_t; // 总共 11 位,其中整数部分占 5 位 void multiply(fixed_point_t a, fixed_point_t b, fixed_point_t &result) { result = a * b; // 自动处理补位和截断 } ``` HLS 工具会依据所选的目标器件优化该函数的行为,包括必要的符号扩展、零填充以及其他细节。 --- #### 4. 利用 Xilinx Core Generator 创建专用模块 Xilinx 提供了一些预构建的核心库(CoreGen/IP Catalogue),可以直接生成支持固定点算术的功能模块。比如 AXI DSP48E Slice 即可用来高效地实施复杂的数学算法。 具体流程如下: - 启动 Vivado 并打开项目; - 导航至 “IP Integrator” 页面创建新的 Block Design; - 搜索所需核心组件(如 Multiplier/DSP Blocks)并将其拖放到画布上; - 配置参数选项,设定输入/输出端口的数量及位宽等属性; - 自动生成 HDL 文件并与其余电路集成在一起。 这种方法的优势在于减少了手动编码的工作量,同时也提高了性能表现。 --- ### 结论 无论是借助纯 RTL 描述还是利用高层次综合技术或者预制好的硬核资源,都可以很好地满足不同场景下对定点数值进行适当补充的需求。选择哪种途径取决于实际应用背景和个人偏好等因素。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值