基于FPGA的数字信号处理(18)--半加器和全加器

前言

        在数字系统中,加法运算是最常见的算术运算,同时它也是进行各种复杂运算的基础。

半加器

        最简单的加法器叫做 半加器Half Adder),它将2个输入1bit的数据相加,输出一个2bits的和,和的范围为0~2(10进制)。和的高位也被称为进位Carry),和的低位则通常被直接叫Sum)。例如:

  • 1 + 1 = 2 = 10,即进位carry是1,和sum是0

  • 1 + 0 = 1 = 01,即进位carry是0,和sum是1

  • 0 + 1 = 1 = 01,即进位carry是0,和sum是1

  • 0 + 0 = 0 = 00,即进位carry是0,和sum是0

        2个1bit数相加,最多只有4种情况(在上面已经例出来了),据此可以写出半加器的真值表:

加数1加数2结果进位
absumcarry
0000
0110
1010
1101

        从这个真值表,不难推断出两个输出的逻辑表达式:

  • 和sum在2个输入不同时为1,所以它是输入异或的结果,即 sum = a ^ b

  • 进位carry在2个输入都为1时才为1,所以它是输入相与的结果,即 carry = a & b

        有了逻辑表达式后,就很容易画出电路图了:

image-20240423194559926

        顺便提一句,虽然半加器的基本电路是上面这个样子的,但是在FPGA中,因为只有查找表LUT没有具体的门电路,所以如果用FPGA来综合半加器,它的电路应该是这个样子的(因为只有2个输入和2个输出,所以只要1个LUT6就可以覆盖到所有情况):

如果你不了解LUT,可以看看这篇文章:从底层结构开始学习FPGA(2)----LUT查找表

或者看看这个专栏:从底层结构开始学习FPGA

image-20240423202331743

        IBUF和OBUF是Vivado自动添加的对输入输出管脚的缓冲,尽管上图显示的是2个LUT2,但是实际上就是1个LUT6,只是这样的显示会更清晰一点。下面的资源显示情况证明了这一点:

image-20240423202457190

        用verilog实现半加器的方式有两种:

  • 用逻辑表达式来描述输出

  • 直接写加法

        因为电路非常简单,所以这两种方法综合出来的电路都是一样的(上面说了,就是1个LUT6)。第1种方法:

//使用逻辑表达式来描述半加器
module half_adder(input   in1,    //加数1input   in2,    //加数2output  sum,    //和output  cout    //进位
);
//根据化简结果分别表示:和 与 进位
assign sum  = in1 ^ in2;    
assign cout = in1 & in2;endmodule 

        第2种方法:

//直接使用加法(assign语句)进行计算
module half_adder(input       in1,    //加数1input       in2,    //加数2output      sum,    //和output      cout    //进位
);
//使用拼接运算符分别表示:和 与 进位
assign {cout,sum} = in1 + in2; 
​
endmodule 
​
//使用always块
module half_adder(input           in1,    //加数1input           in2,    //加数2output  reg     sum,    //加和output  reg     cout    //进位
);
//使用拼接运算符分别表示:和 与 进位
always@(*)begin{cout,sum} = in1 + in2;
endendmodule

        上面分别用always语句和assign语句来描述半加器加法,但效果上二者是等价的,对于这种比较简单又比较少的语句描述,建议使用assign语句

        有了RTL,接下来就该要写1个对应的TB来测试电路功能是否正常。由于这个电路足够简单(一共只有4种情况),所以我们可以把所有可能的情况都穷举出来,然后观察输出是否符合预期即可。TB如下:

`timescale 1ns/1ns              //时间刻度:单位1ns,精度1ns
​
module tb_half_adder();         
​
//定义变量  
reg in1;
reg in2;
wire cout;
wire sum;
​
//设置初始化条件
initial begin//第1种情况in1 =1'b0;  //初始化为0in2 =1'b0;  //初始化为0#10     //第2种情况in1 =1'b0;  in2 =1'b1;  #10     //第3种情况in1 =1'b1;  in2 =1'b0;#10     //第4种情况in1 =1'b1;  in2 =1'b1;#10 $stop();    //结束仿真  
end
​
//例化被测试模块
half_adder u_half_adder(.in1    (in1),.in2    (in2),  .sum    (sum),  .cout   (cout)
);endmodule

        仿真结果如下:

image-20240423203701013

        通过和真值表的对比(或者验证逻辑表达式也可以),可以发现,电路的输出是符合预期的。

全加器

        虽然半加器可以实现2个1bit数的加法,但在实际应用中,更常见的是要实现多个bit的加法,那么该如何实现?以2个2bits数的加法为例:

先把低位和高位的加法先分开。

低位是2个1bit的加法,所以可以用1个HA(半加器)来实现,它产生的和就是最终结果的低位,它产生的进位要被送入到高位参与它们的加法。

高位除了要计算2个加数的高位外,还有1个来自低位的进位。

        问题是半加器没有设计来自低位的进位,所以它处理不了这种情况。为此,全加器被设计出来了,它在半加器的基础上,增加了来自低级的进位输入。这样多个全加器就可以级联起来实现多bits的加法了。

        全加器Full Adder),它将2个1bit的输入和来自低级的进位输入共3个数相加,输出一个2bits的和,和的范围为0~3(10进制)。和的高位也被称为进位Carry),和的低位则通常被直接叫Sum)。例如:

  • 1 + 1 + 1 = 3 = 11,即进位carry是1,和sum是1

  • 1 + 0 + 1 = 2 = 10,即进位carry是1,和sum是0

  • ·····

  • 0 + 1 + 0 = 1 = 01,即进位carry是0,和sum是1

  • 0 + 0 + 0 = 0 = 00,即进位carry是0,和sum是0

        3个输入一共只有8种情况,把所有情况都穷举出来,就可以列出全加器的真值表:

加数1加数2低位进位结果高位进位
abcinsumcout
00000
01010
10010
11001
00110
01101
10101
11111

        从这个真值表,不难推断出两个输出的逻辑表达式:

  • 和sum为1的4种情况,ab'cin' + a'bcin' +ab'cin + a'bcin = (ab'+ a'b)cin' + (ab'+ a'b)'cin = (a^b)cin' + (a^b)'cin = (a^b)^cin = a ^ b ^ cin

  • 进位cout为1的4种情况,abcin' + a'bcin + ab'cin + abcin = ab(cin + cin') + cin(a'b + ab') = ab + cin(a^b)

        有了逻辑表达式后,就很容易画出电路图了:

image-20240423220322126

        同样的,虽然全加器的基本电路是上面这个样子的,但是在FPGA中,因为只有查找表LUT没有具体的门电路,所以它的电路其实是这个样子的(因为只有3个输入和2个输出,所以只要1个LUT6就可以覆盖到所有情况):

image-20240423214526562

        尽管显示的也是2个LUT2,但实际上就是1个LUT6。同半加器一样,全加器的Verilog实现也可以用2种方式:

  • 用逻辑表达式来描述输出

  • 直接写加法

        因为电路非常简单,所以这两种方法综合出来的电路是一样的。第1种方法:

//根据逻辑表达式来描述输出
module full_adder(input       a,      //加数1input       b,      //加数2input       cin,    //低位向高位的进位output      sum,    //和output      cout    //进位
);
​
assign sum  = a ^ b ^ cin;  
assign cout = (a & b) | cin & (a ^ b);
​
endmodule

        第2种方法:

//直接用加法来描述全加器
module full_adder(input       a,      //加数1input       b,      //加数2input       cin,    //低位向高位的进位output      sum,    //和output      cout    //进位
);
​
assign {cout,sum} = a + b + cin;    //使用位拼接 和 加法运算
​
endmodule

        接下来,也写1个TB来测试电路,因为输入一共只有8个,所以依然用穷举法来测试:

`timescale 1ns/1ns              //时间刻度:单位1ns,精度1ns
​
module tb_full_adder();         
​
//定义变量  
reg     a;
reg     b;
reg     cin;
wire    cout;
wire    sum;
​
//设置初始化条件
initial begin//第1种情况a =1'b0;    b =1'b0;    cin =1'b0;  #10     //第2种情况a =1'b0;    b =1'b1;cin =1'b0;  #10     //第3种情况a =1'b1;    b =1'b0;cin =1'b0;#10     //第4种情况a =1'b1;    b =1'b1;cin =1'b0;#10     //第5种情况a =1'b0;    b =1'b0;    cin =1'b1;#10     //第6种情况a =1'b0;    b =1'b1;cin =1'b1;#10     //第7种情况a =1'b1;    b =1'b0;cin =1'b1;#10     //第8种情况a =1'b1;    b =1'b1;cin =1'b1;  #10 $stop();    //结束仿真  
end
​
//例化被测试模块
full_adder u_full_adder(.a      (a),.b      (b),    .sum    (sum),.cin    (cin),.cout   (cout)
);endmodule

        仿真结果如下所示:

image-20240423215226332

        通过和真值表的对比(或者验证逻辑表达式也可以),可以发现,电路的输出是符合预期的。

用半加器实现全加器

        如果你仔细看半加器和全加器的电路图,就会发现它们有很多重合的地方:

  • 半加器的组成:1个与门 + 1个异或门

  • 全加器的组成:2个与门 + 2个异或门 + 1个或门

        这么看,全加器似乎可以用2个半加器 + 1个或门组成,我们把全加器的电路图重新布局一下:

image-20240423221247345

        可以清晰地看到,全加器确实可以由2个半加器+1个或门组成:

  • 加数a和b作为第1个半加器的输入

  • 第1个半加器的输出sum1 和 进位输入cin作为第2个半加器的输入;第1个半加器的输出carry1作为或门的1个输入

  • 第2个半加器的输出sum2就是全加器的和sum; 第2个半加器的输出carry2作为或门的另1个输入

  • 或门的输出cout就是全加器的进位cout

        用Verilog来描述是这样的:

//2个半加器级联实现全加器
module full_adder(input       a,      //加数1input       b,      //加数2input       cin,    //低位向高位的进位output      sum,    //和output      cout    //进位
);
​
//模块之间的连线,结合模块图理解
wire    hf1_cout;   //第1个半加器的进位输出
wire    hf2_cout;   //第2个半加器的进位输出
wire    hf1_sum;    //第1个半加器的和输出
​
assign  cout = hf1_cout || hf2_cout;    //例化第1个半加器
half_adder u1_half_adder(.a      (a),        .b      (b),        .sum    (hf1_sum),  .cout   (hf1_cout)  
);
​
//例化第2个半加器
half_adder u2_half_adder(.a      (hf1_sum),      .b      (cin),          .sum    (sum),          .cout   (hf2_cout)  
);
​
endmodule
​
module half_adder(input       a,      //加数1input       b,      //加数2output      sum,    //和output      cout    //进位
);
//使用拼接运算符分别表示:和 与 进位
assign {cout,sum} = a + b; 
​
endmodule

        生成的RTL视图如下:

image-20240423222355211

        这与理论上的框图一致:例化了2个半加器和1个或门。仿真的话用上面的同一个TB就行,仿真结果也和之前的结果一致:

image-20240423222613520

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

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

相关文章

航片转GIS数据自动化管线

近年来,计算机视觉领域的进步已显著改善了物体检测和分割任务。一种流行的方法是 YOLO(You Only Look Once)系列模型。YOLOv8 是 YOLO 架构的演进,兼具准确性和效率,是各种应用的绝佳选择,包括分割卫星航拍…

抖音短视频seo矩阵系统源码开发技术分享(二)--SaaS开源

目录 市场背景分析 一、抖音短视频seo矩阵系统开发部署流程 二、 源码开发功能构思 三、 抖音短视频seo源码开发部署注意事项 四、 部分开发代码展示 市场背景分析 抖音短视频seo矩阵系统是通过不同平台不同账号之间建立联系,通过将同一品牌下不同平台不同账号…

currentTarget和target

*.wxml *.js 点击按钮 发现 currentTarget 获取的是事件绑定者的参数 target 获取的是事件触发者的参数

ZYNQ 入门笔记(零):概述

文章目录 引言产品线Zynq™ 7000 SoCZynq UltraScale™ MPSoCZynq UltraScale RFSoCVersal™ Adaptive SoC 开发环境 引言 Xilinx FPGA 产品线从经济型的 Spartan、Artix 系列到高性能的 Kintex、Virtex、Versal 系列,可以说涵盖了 FPGA 的绝大部分应用场景&#x…

【iOS】内存对齐

内存对齐 OC基本数据类型所占字节数对比 注1:BOOL在32位机器被定义为char、在64位机器被定义为bool boolean_t在32位机器被定义为unsigned int、在64位机器被定义为int NSInteger在32位机器被定义为int、在64位机器被定义为long NSUInteger在32位机器被定义为unsig…

公司技术栈用到了RocketMQ,我对此块知识进行了回顾(初始RocketMQ)

前言 作为24届的校招生,不知道大伙儿们是否都已经到了工作岗位上。为了以后更方便的接触到公司的业务,我司为我们安排了将近一个月的实操。虽然不用敲代码,但是… 了解到我司使用到的技术栈,在空闲时间正好对RocketMQ这块技术做个…

服务器配置两个默认网关必须配置路由优先级

背景 对于具备多网口的服务器来说,启用多个网口很正常,正常情况下应该只有一个默认网关,其他网口配置明细路由,如果将服务器做为软路由,并且有两个外网网络,1主1备,则会需要配置网关默认网关&am…

C++笔试强训7

文章目录 一、选择题1-5题6-10题 二、编程题题目一题目二 一、选择题 1-5题 基础知识,函数代码少,频繁调用的时候才适合定义内联函数。 故选C。 在C中,inline关键字是用来向编译器建议将函数体在每个调用点“内联展开”的。这意味着编译器会…

前端表格解析方法

工具类文件 // fileUtils.tsimport { ref } from vue; import * as xlsx from xlsx;interface RowData {[key: string]: any; }export const tableData ref<RowData[]>([]);export async function handleFileSelect(url: string): Promise<void> {try {const res…

《无线互联科技》是什么级别的期刊?是正规期刊吗?能评职称吗?

​问题解答 问&#xff1a;《无线互联科技》是不是核心期刊&#xff1f; 答&#xff1a;不是&#xff0c;是知网收录的正规学术期刊。 问&#xff1a;《无线互联科技》级别&#xff1f; 答&#xff1a;国家级。主管单位&#xff1a;江苏省科学技术厅 主办单位&#xff1a…

浅谈断言之MD5Hex断言

浅谈断言之MD5Hex断言 “MD5Hex断言”是一种特殊类型的断言&#xff0c;主要用于验证返回数据的完整性和一致性。本文将详细介绍MD5Hex断言的用途、配置方法及应用场景。 MD5Hex断言概述 MD5Hex断言基于MD5&#xff08;Message-Digest Algorithm 5&#xff09;算法&#xff…

Nexus3 批量上传 jar 包、pom文件

Nexus3 Maven 私服搭建及各种使用 详见**Maven私服搭建及各种使用汇总2020** Maven 配置 Nexus 私服 在 Maven 项目中配置 Nexus 私服&#xff0c;需要在项目的 pom.xml 或 maven 的 settings.xml 文件中添加 Nexus 仓库的配置。 示例&#xff1a; 以下是一个项目的 pom.xml…

JDK8升级到JDK17,报错Error:java:错误:不支持的发行版本5

1 问题描述&#xff1a; 我原来用到是JDK8,后来重新安装了JDK17后&#xff0c;并更换了JAVA_HOME的配置&#xff0c;在CDM上面查看JAVA版本确认安装无误。 当我打开IDEA运行代码时&#xff0c;就报错java&#xff1a;错误&#xff1a;不支持的发行版本5&#xff0c;至始至终我都…

UM980的天线馈电设计

UM980 不支持内部天线馈电&#xff0c;需要从模块外部给天线馈电&#xff0c;建议尽量选择高耐压、大功率的器件&#xff1b; 还可以在馈电电路上增加气体放电管、压敏电阻、 TVS 管等大功率的防护器件&#xff0c;可有效提高防雷击与防浪涌的能力。 如果 ANT_BIAS 天线馈电和模…

python3.10.4——CentOS7安装步骤

目录 1.CentOS7中默认有python2.7.5 2.安装前置依赖程序 3.在python官网下载linux系统安装包 4.解析、编译安装python3.10.4 5.创建软链接 6.修改yum相关配置 7.重新检查python版本号 1.CentOS7中默认有python2.7.5 2.安装前置依赖程序 yum install wget zlib-devel bz…

NVIDIA Container Toolkit 安装与配置帮助文档(Ubuntu,Docker)

NVIDIA Container Toolkit 安装与配置帮助文档(Ubuntu,Docker) 本文档详细介绍了在 Ubuntu Server 22.04 上使用 Docker 安装和配置 NVIDIA Container Toolkit 的过程。 概述 NVIDIA 容器工具包使用户能够构建和运行 GPU 加速容器。即可以在容器中使用NVIDIA显卡。 架构图如…

Qt开发网络嗅探器03

数据包分析 想要知道如何解析IP数据包&#xff0c;就要知道不同的IP数据包的包头结构&#xff0c;于是我们上⽹查查资料&#xff1a; 以太网数据包 ARP数据包 IPv4 IPv6 TCP UDP ICMP ICMPv6 根据以上数据包头结构&#xff0c;我们就有了我们的protocol.h文件&#xff0c;声明…

【云原生】Kubernetes中的DaemonSet介绍、原理、用法及实战应用案例分析

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

【LeetCode】填充每个节点的下一个右侧节点指针 II

目录 一、题目二、解法完整代码 一、题目 给定一个二叉树&#xff1a; struct Node { int val; Node *left; Node *right; Node *next; } 填充它的每个 next 指针&#xff0c;让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点&#xff0c;则将 next 指针设置为 NUL…

【学习笔记】无人机系统(UAS)的连接、识别和跟踪(十)-无人机A2X服务

引言 3GPP TS 23.256 技术规范&#xff0c;主要定义了3GPP系统对无人机&#xff08;UAV&#xff09;的连接性、身份识别、跟踪及A2X&#xff08;Aircraft-to-Everything&#xff09;服务的支持。 3GPP TS 23.256 技术规范&#xff1a; 【免费】3GPPTS23.256技术报告-无人机系…