基于FPGA的数字信号处理(22)--进位保存加法器(Carry Save Adder, CSA)

news2025/1/30 16:27:29

目录

1、拆解多个数的加法

2、进位保存加法器

3、CSA的优点和缺点

4、CSA电路的实现


         文章总目录点这里:《基于FPGA的数字信号处理》专栏的导航与说明


1、拆解多个数的加法

        考虑3个4bits数相加,10 + 4 + 7 = 21 的过程是这样的:

image-20240427191114236

        其中的红色数字是由低位向高位产生的进位,因为进位值是直接在当前位与3个加数相加,所以我们也可以把进位值拆解出来,改写成如下格式:

image-20240427191349219

cout是低位产生的进位。例如,最低位的3个值是0/0/1,所以产生了向高位的进位0;次低位的3个值是1/0/1,所以产生了向高位的进位1。

sum是不考虑进位值时3个数相加的和。例如,最低位的3个值是0/0/1,所以该位的和为1;次低位的3个值是1/0/1,所以该位的和为0。

        这样分别产生了进位cout = 01100,和sum=1001,二者相加后的结果就是最终3个数的和即21。这种方法相当于把3个数的加法转换成了2个数的加法。

2、进位保存加法器

        上面这种将3个数的加法转换成两个数加法形式的电路就叫做 进位保存加法器(Carry Save Adder, CSA)

        当3个数中有2个或3个1时就会向高位产生进位,而和的值则和1的个数相关,奇数个1时和为1,偶数个1时和为0,所以它的真值表如下:

加数1加数2加数3结果进位
abcsumcout
00000
01010
10010
11001
00110
01101
10101
11111

        如果你仔细点观察,就会发现上面的真值表和全加器FA的真值表是一样的,这不就说明CSA就是FA吗?只是FA的进位输入都改成了第3个加数,如下:

image-20240427194749587

        对于3个4bits的加法,就可以用4个CSA来组成:

image-20240427194812026

        可以看到这样结构的加法器的关键路径的延迟是多少呢?一个CSA电路的延迟,也就是一个FA的延迟,如下(3个门电路):

image-20240427194924330

3、CSA的优点和缺点

        上面说了3个数的加法,如果使用CSA电路,那么关键路径的延迟只有3个门电路,而如果使用常规的RCA(行波进位加法器)呢?考虑6个4bits数相加,其一般的电路结构如下:

image-20240427204823137

        如果其中的加法器是RCA,那么该电路的关键路径延迟是3级加法器的延迟。如果采用CSA电路,则其电路结构如下:

image-20240427220537983

        前面说了,CSA电路的延迟也就一个门电路,那么上面电路的关键路径延迟就是 3个门电路 + 最后的加法器 的延迟,假设加法器也是使用的RCA加法器,那么最终的延迟就是 1个RCA的延迟 + 3个门电路 延迟,这显然比3级RCA电路的延迟要小。可以预见的是,随着加数个数的增加,两种电路的延迟差距还会拉大。

        以4比特乘法为例,其竖式计算表示如下:

image-20240430210444307

        ai和bi分别表示A和B的某个bit,aibi表示ai与bi相与,使用与门电路生成,aibi的值只有0和1。S表示AB相乘的结果。每一列使用半加器HA或全加器FA两两相加,其结果表示为Si,每一列每两个数产生的进位将传递至相邻高的一列参与计算。其电路结构如下(其中虚线箭头表示进位传播的路线):

image-20240430210453212

        根据进位传播链,可以看出该电路的关键路径如下:

image-20240430210459616

        红线和紫线是由于累加造成的进位链的最长路径。其中:

  • 红色路径:6个FA + 2个HA

  • 紫色路径:5个FA + 3个HA

        使用进位保留加法器CSA可缩短该进位链的传播延时,其电路结构如下:

image-20240430210508221

        将RCA阵列乘法器的进位连接至斜下角的加法器,CSA结构的阵列乘法器将进位与和分别计算,不必计算该层的进位,省去了行波进位加法器进位链的依赖,只在最后一级通过RCA结构(上图绿色虚框)传递进位合并最后的结果。上图红色是CSA结构的关键路径:3个FA + 3个HA。可见,CSA结构使用相同的资源却有更优的时序性能,当加法个数变多时,这一优势将更大。

        进位保存加法器的优点如下:

  • 进位保存加法器将 3 个数字的加法减少到 2 个数字

  • 由于进位传播级很少,与其他类型的加法器相比,它的功耗较低

  • 该加法器可以一次执行三位加法

  • 无论最终操作完成,下一级都会使用简单的 N 位 RCA。

        进位保存加法器的缺点如下:

  • 在进位保存加法的每一步中,可以立即知道加法结果,但我们不知道加法结果与给定数字相比是更小还是更大。

  • 这种类型的加法器不能解决将 2 个整数相加以生成单个输出的问题。相反,它只是将 3 个整数相加并生成两个整数,因此两个整数的总和等于三个输入的总和。

  • 它对于少数位操作具有高功耗和传播延迟。

4、CSA电路的实现

        接下来,以6个8bits有符号数的加法为例,看如何用CSA的树形结构实现。首先要确定的是,对于单个bit的CSA来说,就是全加器,如下:

image-20240427230436809

        所以它的生成公式是:

s = in1 ^ in2 ^ in3; c = (in1&in2) | (in1&in3) | (in2&in2) ;

        第1级有2个CSA电路,它们实现3个8bits的加法。第1个CSA的输入是3个加数a,b,c,输出是8bit的和csa11_s 跟 进位csa11_c,需要注意的是进位csa11_c在参与下级加法的时候要左移1bit(即乘2),因为它是向高位的进位。代码如下:

//第1级的第1个 CSA
assign csa11_in1 = a;
assign csa11_in2 = b;
assign csa11_in3 = c;
assign csa11_s = csa11_in1 ^ csa11_in2 ^ csa11_in3;
assign csa11_c = (csa11_in1 & csa11_in2) | (csa11_in1 & csa11_in3) | (csa11_in2 & csa11_in3);

        第2个CSA的输入是3个加数d,e,f,输出是8bit的和csa12_s 跟 进位csa12_c,需要注意的是进位csa12_c在参与下级加法的时候要左移1bit(即乘2),因为它是向高位的进位。代码如下:

//第1级的第2个 CSA
assign csa12_in1 = d;
assign csa12_in2 = e;
assign csa12_in3 = f;
assign csa12_s = csa12_in1 ^ csa12_in2 ^ csa12_in3;
assign csa12_c = (csa12_in1 & csa12_in2) | (csa12_in1 & csa12_in3) | (csa12_in2 & csa12_in3);

        第2级只有1个CSA,它的输入是第1级第1个CSA的两个输出和第2个CSA的一个输出,因为输入中有两个数是上级CSA产生的进位,所以需要左移1位,这样原本的8bits加法就变成了9bits加法。输出是9bit的和csa21_s 跟 进位csa21_c,需要注意的是进位csa21_c在参与下级加法的时候要左移1bit(即乘2),因为它是向高位的进位。代码如下:

//第2级的CSA
assign csa21_in1 = {csa11_c,1'b0};          //左移1比特
assign csa21_in2 = {csa11_s[7],csa11_s};    //为了适配csa21_in1,在高位补符号位
assign csa21_in3 = {csa12_s[7],csa12_s};    //为了适配csa21_in1,在高位补符号位
assign csa21_s = csa21_in1 ^ csa21_in2 ^ csa21_in3;
assign csa21_c = (csa21_in1 & csa21_in2) | (csa21_in1 & csa21_in3) | (csa21_in2 & csa21_in3);

        第3级只有1个CSA,它的输入是第2级的CSA的两个输出和第1级的第2个CSA的一个输出,因为输入中有1个数是上级CSA产生的进位,所以需要左移1位,这样原本的9bits加法就变成了10bits加法。输出是10bit的和csa31_s 跟 进位csa31_c,需要注意的是进位csa31_c在参与下级加法的时候要左移1bit(即乘2),因为它是向高位的进位。代码如下:

//第3级的CSA
assign csa31_in1 = {csa21_c,1'b0};                  //左移1比特
assign csa31_in2 = {csa21_s[8],csa21_s};            //为了适配csa31_in1,在高位补符号位
assign csa31_in3 = {csa12_c[7],csa12_c,1'b0};       //左移1bit,在高位补符号位
assign csa31_s = csa31_in1 ^ csa31_in2 ^ csa31_in3;
assign csa31_c = (csa31_in1 & csa31_in2) | (csa31_in1 & csa31_in3) | (csa31_in2 & csa31_in3);

        经过3级CSA产生的 和csa31_s进位csa31_c就是6个数相加的结果,但是它不是一个直接表示的数值,而是拆成了两部分的冗余结果,所以我们还需要设计一个加法,来将这两个数相加,这样得到的结果最是最终的6个数的加法结果。这里仍然要注意,进位需要左移1bit(乘2),如下:

//第4级加法-------------------------------------------------------------------------------------
//把 和 + 进位,得到最终的加法结果。因为进位要左移1位,所以和也要在高位补符号位
assign sum = {csa31_c,1'b0} + {csa31_s[9],csa31_s};

        综上,总体的RTL代码如下:

//CSA的生成公式:
//  s = in1 ^ in2 ^ in3;
//  c = (in1&in2)  | (in1&in3)  | (in2&in3) ;
module csa(
    input   [7 :0]  a,b,c,d,e,f,
    output  [10:0]  sum_1
);
//----------------------------------------------------------
//定义有关wire
wire [7:0]  csa11_in1,csa11_in2,csa11_in3;
wire [7:0]  csa12_in1,csa12_in2,csa12_in3;
wire [7:0]  csa11_s,csa11_c;
wire [7:0]  csa12_s,csa12_c;
​
//第1级的第1个 CSA
assign csa11_in1 = a;
assign csa11_in2 = b;
assign csa11_in3 = c;
assign csa11_s = csa11_in1 ^ csa11_in2 ^ csa11_in3;
assign csa11_c = (csa11_in1 & csa11_in2) | (csa11_in1 & csa11_in3) | (csa11_in2 & csa11_in3);
​
//第1级的第2个 CSA
assign csa12_in1 = d;
assign csa12_in2 = e;
assign csa12_in3 = f;
assign csa12_s = csa12_in1 ^ csa12_in2 ^ csa12_in3;
assign csa12_c = (csa12_in1 & csa12_in2) | (csa12_in1 & csa12_in3) | (csa12_in2 & csa12_in3);
​
//第2级-------------------------------------------------------------------------------------
//定义有关wire,因为上级的进位是往高位进位,所以需要左移1比特,即cout是9bits,
//为了适配,其他输入也要在高位补符号位到9bits
wire [8:0]  csa21_in1,csa21_in2,csa21_in3;
wire [8:0]  csa21_s,csa21_c;
​
//第2级的CSA
assign csa21_in1 = {csa11_c,1'b0};          //左移1比特
assign csa21_in2 = {csa11_s[7],csa11_s};    //为了适配csa21_in1,在高位补符号位
assign csa21_in3 = {csa12_s[7],csa12_s};    //为了适配csa21_in1,在高位补符号位
assign csa21_s = csa21_in1 ^ csa21_in2 ^ csa21_in3;
assign csa21_c = (csa21_in1 & csa21_in2) | (csa21_in1 & csa21_in3) | (csa21_in2 & csa21_in3);
​
//第3级-------------------------------------------------------------------------------------
//定义有关wire,因为上级的进位是往高位进位,所以需要左移1比特,即cout是10bits,
//为了适配,其他输入也要在高位补符号位到10bits
wire [9:0]  csa31_in1,csa31_in2,csa31_in3;
wire [9:0]  csa31_s,csa31_c;
​
//第3级的CSA
assign csa31_in1 = {csa21_c,1'b0};                  //左移1比特
assign csa31_in2 = {csa21_s[8],csa21_s};            //为了适配csa31_in1,在高位补符号位
assign csa31_in3 = {csa12_c[7],csa12_c,1'b0};       //左移1bit,在高位补符号位
assign csa31_s = csa31_in1 ^ csa31_in2 ^ csa31_in3;
assign csa31_c = (csa31_in1 & csa31_in2) | (csa31_in1 & csa31_in3) | (csa31_in2 & csa31_in3);
​
//第4级加法-------------------------------------------------------------------------------------
//把 和 + 进位,得到最终的加法结果。因为进位要左移1位,所以和也要在高位补符号位
assign sum_1 = {csa31_c,1'b0} + {csa31_s[9],csa31_s};
​
endmodule

        接下来写个TB测试一下电路,因为可能的输入太多了,一共有(2^8)^6 = 2^48 = 281,474,976,710,656种情况,显然不可能遍历完,所以我们采用随机测试的方式。通过生成数组随机向量来对电路进行测试:

module tb_test();
 
reg signed  [7 :0]  a,b,c,d,e,f;
wire        [10:0]  sum;
wire                sum_flag;               //结果比对正确时拉高
​
wire signed [10:0] sum_real;
​
assign sum_real = a + b + c + d + e + f;    //预期的正确结果
assign sum_flag = sum == sum_real;          //判断电路输出是否与预期输出一致
​
initial begin
    //赋初值
    a = 0;
    b = 0;
    c = 0;
    d = 0;
    e = 0;
    f = 0;
    #5;
    repeat(1024)begin   //设定向量个数
        //生成随机向量
        a = $random();
        b = $random();
        c = $random();
        d = $random();      
        e = $random();      
        f = $random();      
        #5;
    end
    #10 $stop();    //结束仿真
end
    
//例化被测试模块   
csa u_csa(
    .a      (a      ),
    .b      (b      ),
    .c      (c      ),
    .d      (d      ),
    .e      (e      ),
    .f      (f      ),  
    .sum    (sum    )
);
​
endmodule

        加法运算的预期结果也是很容易就可以找出来的,就是在TB中直接写加法就行。接着构建了向量sum_flag作为电路输出与预期结果的对比值,当二者一致时即拉高这两个信号。这样我们只要观察这个信号,即可知道电路输出是否正确。仿真结果如下:

image-20240430212443654

        可以看到,sum_flag都是一直拉高的,说明电路输出正确。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1977588.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【树莓派】初始化配置(自动连wifi,自动开启SSH)换清华源,远程桌面连接

@TOC 【树莓派】初始化配置(自动连wifi,自动开启SSH)换清华源 一 .烧录系统 二 .自动连wifi,自动开启SSH 三.插电启动派 四.找到树莓派的IP,SSH连接(默认账密 pi:raspberry) 五.更改清华源 注意:按快捷键ctrl+x,会提示是否保存,按Y键确认即可 1.sudo nano /etc/apt/sourc…

java面向对象编程入门

一、前言: 在Java中,面向对象编程(Object-Oriented Programming, OOP)是一种核心的编程范式。Java的设计和开发都是基于面向对象的思想。面向对象编程的主要目的是提高代码的可重用性、灵活性和可维护性。以下是Java面向对象编程…

在windows本地机搭建gitlab

在windows本地机搭建gitlab 1. 解决方案2. docker安装gitlab2.1 下载Docker Desktop2.2 安装gitlab的docker2.3 配置gitlab网页2.3 配置gitlab配置文件 3. frp端口转发4. ssh密钥配置5. 运行 1. 解决方案 注:gitlab只有linux版本,并不存在windows版本&a…

小柴带你学AutoSar系列三、标准和规范篇(2)BSWGeneral

BSWDistributionGuide BSW在AUTOSAR架构中的这里哦 BSW Distribution in Multi-Core Systems BSW Functional Clusters BSW功能集群是一组相关功能的模块 BSW functional clusters are groups of functionally coherent BSW modules. The following types of clusters might…

如何搭建云电脑?让数据更安全。。。。。。

上周,微软Windows系统的蓝屏故障对各行各业造成了严重影响。航空业首当其冲,当天所有航班停飞,人员滞留在机场。 酒店业也未能幸免,同样受到波及。 1. 故障分析及解决措施 本次蓝屏事件的导火索是CrowdStrike公司更新的驱动程序。CrowdStrike提供的解决方案相当复杂,用户需要…

JavaFX布局-ScrollPane

JavaFX布局-ScrollPane 常用属性paddingcontentvbarPolicyhbarPolicyfitToWidthfitToHeight 实现方式Java实现 一个容器组件,用于展示那些可能超出窗口尺寸的内容当内容超过容器的大小时,会自动出现滚动条 常用属性 padding 内边距,可以单独…

【开源分享】PHP在线提交工单源码|工单管理系统源码 (附源码搭建教程)

一、设备报修工作内容 1.工单管理:设备报修系统可以将设备故障统计为工单并对工单进行汇总管理。将工单数据进行归类,将故障分类进行查看、统计、分析等等。 2.设备状态:工单可通过用户上报设备状态数据进行查看,维修工程师在维…

跟李沐学AI:LeNet

LeNet整体由两部分组成:由两个卷积层组成的卷积编码器、由三个全连接层组成的全连接层密集快。 每个卷积块的基本单元是一个卷积层、一个sigmoid激活函数和平均池化层。每个卷积层使用5x5的卷积核和一个sigmoid激活函数。 这些层将输入映射到多个二维特征输出同时输…

保研机试练习:leetcode算法top200(第二弹)

🌮101.对称二叉树(简单) 🍟题目描述 🍟题目反思 对称二叉树,对每个节点来说,就是当前节点相同,且左右镜像相等。这道题目重点也是在于掌握递归检查树上。 🍟代码 /**…

C# 自定义控件无法加载

问题 在做winform开发时自己定义了一个控件,控件在工具箱中显示了,但是拖动到窗体设计器时会提示未能加载工具箱项xxx,将从工具箱中将其删除,如下图所示: 点击确定后,控件会从工具箱中移除。 解决方法 将 生成>…

深信服的云桌面操作简要

看了深信服的云桌面操作手册,讲真,我是没有耐心看的,656页,我是云桌面管理员,为了管理也必须耐着性子去看,但我看了40页就看不下去了,太啰嗦了。 深信服的技术人员安装好服务器后给我实际演示操…

【C++题解】1351. 买公园门票

欢迎关注本专栏《C从零基础到信奥赛入门级(CSP-J)》 问题:1351. 买公园门票 类型:简单穷举 题目描述: 某公园门票价格为:成人票 8 元 / 张,儿童票 3 元 / 张;某旅游团来公园游玩&…

Memcached未授权访问漏洞

Memcached未授权访问漏洞 Memcache能够提供临时数据存储服务,可以提高网站的整体性能,但由于memcache安全设计缺陷,默认开放的端口是11211,导致不需要密码就可以访问,攻击者可以直接连接服务器的11211端口获取数据库中…

GIt最新教程通俗易懂

Git学习笔记 一、Git版本控制分类1.1 本地版本控制1.2 集中版本1.3 分布式版本控制系统1.5 Git和SVN的区别二、Git的历史 三、Gti基础学习3.1 Git的基础学习3.2 启动Git 3.3 Git基本的配置3.3.1 配置文件相关位置 四、Git基本理论(核心)4.1 Git 的工作流…

vue echarts 柱状图和折线图的组合

柱状图和折线图的组合代码如下&#xff1a; <template><div><div id"barLineChart" ref"barLineChartRef" style"width: 100%; height: 450px"></div></div> </template><script> import * as echar…

【收录率高丨最快会后3-4个月EI检索 | 往届均已EI检索】第四届光学与通信技术国际学术会议(ICOCT 2024,8月9-11)

欢迎参加第四届光学与通信技术国际学术会议&#xff08;ICOCT 2024&#xff09;&#xff0c;该会议将于2024年8月9-11日在南京举办。自2021年首次会议以来&#xff0c;ICOCT已经发展成为光学和通信领域较有影响力的国际会议之一&#xff0c;聚焦最前沿的技术进展与未来发展趋势…

C/C++大雪纷飞代码(完整代码)

目录 写在前面 C语言简介 EasyX简介 大雪纷飞 运行结果 写在后面 写在前面 本期博主给大家带来了C/C++实现的大雪纷飞代码,一起来看看吧! 系列推荐 序号目录直达链接1爱心代码C/C++爱心代码(完整代码)_爱心代码编程c++语言-CSDN博客2李峋同款跳动的爱心C/C++李峋同…

详解高性能中间件Iceoryx在ROS2中的使用

文章目录 0. 概述1. 系统架构对比1.1 移除 Master 节点1.2 引入 DDS 系统1.3 跨平台支持 2. DDS 系统的引入2.1 RMW 概述2.2 QoS&#xff08;质量服务策略&#xff09; 3. ROS2安装与配置3.1 一键安装3.2 官网教程 4. [ROS2 底层切换 Iceoryx 官方实现](https://github.com/ros…

安全与效率并重:利用PowerShell脚本实现SQL Server网络配置的自动化监控与日志

目录 脚本概述 步骤实现 注意事项 创建一个PowerShell脚本&#xff0c;用于自动发现并记录SQL Server上所有连接的网络配置细节&#xff0c;包括端口、协议和安全性设置&#xff0c;是一个非常实用的操作&#xff0c;特别是在需要定期审计或新服务器部署时。以下是一个创意性…