基于FPGA的数字信号处理(20)--半减器和全减器
目录
1、前言
2、半减器
3、全减器
4、减法器
文章总目录点这里:《基于FPGA的数字信号处理》专栏的导航与说明
1、前言
既然有半加器和全加器,那自然也有半减器和全减器了。尽管在电路中减法的实现基本都是 补码 + 加法 的形式,但是正所谓技多不压身,了解一下半减器和全减器还是有一定作用的,至少能扩宽知识面嘛。
2、半减器
最简单的减法器叫做 半减器(Half Subtractor),它将2个1bit的输入数据相减,输出一个1bit的结果即 差Di(Difference),以及向高位的借位Bo(Borrow output)。例如:
-
1 - 1 = 01 -1 = 0,不需要向高位借位,差为0,即Bo = 0,Di = 0
-
1 - 0 = 01 -0 = 1,不需要向高位借位,差为1,即Bo = 0,Di = 1
-
0 - 1 = 10 -1 = 1, 需要向高位借位,差为1,即Bo = 1,Di = 1
-
0 - 0 = 00 -0 = 0,不需要向高位借位,差为0,即Bo = 0,Di = 0
2个1bit数相减,最多只有4种情况(在上面已经例出来了),据此可以写出半减器的真值表:
| 被减数 | 减数 | 差 | 向高位借位 |
|---|---|---|---|
| X | Y | Di | Bo |
| 0 | 0 | 0 | 0 |
| 0 | 1 | 1 | 1 |
| 1 | 0 | 1 | 0 |
| 1 | 1 | 0 | 0 |
从这个真值表,不难推断出输出的逻辑表达式:
-
差Di在2个输入不同时为1,所以它是输入异或的结果,即 Di = a ^ b
-
向高位借位Bo在X = 0 且 Y = 1 时才为1,即 Bo= ~X & Y
有了逻辑表达式后,可以很容易地画出对应的门电路结构:

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

如果你不了解LUT,可以看看这篇文章:从底层结构开始学习FPGA(2)----LUT查找表,或者看看这个专栏:从底层结构开始学习FPGA
IBUF和OBUF是Vivado自动添加的对输入输出管脚的缓冲,尽管上图显示的是2个LUT2(可能这样的显示更清晰一点),但是实际上就是1个LUT6,下面的资源显示情况也证明了这一点:

用verilog实现半减器如下:
//使用逻辑表达式来描述半减器
module half_subtractor(input x, //被减数input y, //减数output di, //差output bo //向高位借位
);
//根据化简结果分别表示:差 与 向高位借位
assign di = x ^ y;
assign bo = ~x & y;endmodule
有了RTL,接下来就该要写个对应的TB来测试电路功能是否正常。由于这个电路足够简单(一共只有4种情况),所以我们可以把所有可能的情况都穷举出来,然后观察输出是否符合预期即可。TB如下:
`timescale 1ns/1ns //时间刻度:单位1ns,精度1ns
module tb_half_subtractor();
//定义变量
reg x;
reg y;
wire di;
wire bo;
//设置初始化条件
initial begin//第1种情况x =1'b0; y =1'b0; #10 //第2种情况x =1'b0; y =1'b1; #10 //第3种情况x =1'b1; y =1'b0;#10 //第4种情况x =1'b1; y =1'b1;#10 $stop(); //结束仿真
end
//例化被测试模块
half_subtractor u_half_subtractor(.x (x),.y (y), .di (di), .bo (bo)
);endmodule
仿真结果如下:

通过和真值表的对比(或者验证逻辑表达式也可以),可以发现,电路的输出是符合预期的。
3、全减器
虽然半减器可以实现2个1bit数的减法,但在实际应用中,更常见的是要实现2个多bits数的减法,那么该如何实现?以2个2bits数的减法为例:
-
先把低位和高位的减法先分开。
-
低位是2个1bit的减法,所以可以用1个HS(半减器)来实现,它产生的差就是最终结果的低位,它产生的向高位借位要被送入到高位参与它们的减法。
-
高位除了要计算减数和被减数的高位外,还有1个来自低位的借位。
好,现在问题是半减器没有设计来自低位的借位,所以它处理不了这种情况。为此,全减器被设计出来了,它在半减器的基础上,增加了来自低位的借位输入。这样多个全减器就可以级联起来实现多bits的减法了。
全减器(Full Subtractor),它处理2个1bit的输入和来自低位的借位Bi(Borrow input)输入共3个数,输出一个差Di和向高位的借位Bi。例如(格式:被减数- 减数 - 来自低位的借位):
-
1 - 1 - 1 = 11 - 1 - 1 = 0,来自低位的借位为1, 需要向高位借位,差为0,即Bi = 1,Bo = 0,Di = 0
-
1 - 1 - 0 = 01 - 1 - 0 = 0,来自低位的借位为0,不需要向高位借位,差为0,即Bi = 0,Bo = 0,Di = 0
-
1 - 0 - 1 = 01 - 0 - 1 = 0,来自低位的借位为1,不需要向高位借位,差为0,即Bi = 1,Bo = 0,Di = 0
-
1 - 0 - 0 = 01 - 0 - 0 = 0,来自低位的借位为0,不需要向高位借位,差为1,即Bi = 0,Bo = 0,Di = 1
-
······
3个输入一共只有8种情况,把所有情况都穷举出来,就可以列出全减器的真值表:
| 被减数 | 减数 | 来自低位的借位 | 差 | 向高位的借位 |
|---|---|---|---|---|
| X | Y | Bi | Di | Bo |
| 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 1 | 1 | 1 |
| 0 | 1 | 0 | 1 | 1 |
| 0 | 1 | 1 | 0 | 1 |
| 1 | 0 | 0 | 1 | 0 |
| 1 | 0 | 1 | 0 | 0 |
| 1 | 1 | 0 | 0 | 0 |
| 1 | 1 | 1 | 1 | 1 |
从这个真值表,不难推断出两个输出的逻辑表达式:
-
Di为1的4种情况,~x&~y&bi + ~x&y&~bi + x&~y&~bi + x&y&bi=~x&(~y&bi+y&~bi)+x&(~y&~bi+y&bi) = ~x&(y^bi) + x&~(y^bi) = x ^ y ^ bi
-
Bo为1的4种情况,~x&~y&bi + ~x&y&~bi + ~x&y&bi + x&y&bi = ~x&(~y&bi+y&~bi) + (~x+x)&y&bi = ~x&(y^bi) + y&bi
有了逻辑表达式后,就很容易画出电路图了(偷了个懒,不是画的,是用vivado生成的):

根据门电路,可以写出全减器的Verilog实现:
//使用逻辑表达式来描述全减器
module full_subtractor(input x, //被减数input y, //减数input bi, //来自低位的借位output di, //差output bo //向高位借位
);
//根据化简结果分别表示:差 与 向高位借位
assign di = x ^ y ^ bi;
assign bo = ~x & (y ^ bi) | y & bi;endmodule
接下来写个TB测试电路,输入一共只有8个,所以依然用穷举法来测试:
`timescale 1ns/1ns //时间刻度:单位1ns,精度1ns
module tb_full_subtractor();
//定义变量
reg x;
reg y;
reg bi;
wire di;
wire bo;
//设置初始化条件
initial begin//第1种情况x =1'b0; y =1'b0; bi =1'b0; #10 //第2种情况x =1'b0; y =1'b1;bi =1'b0; #10 //第3种情况x =1'b1; y =1'b0;bi =1'b0;#10 //第4种情况x =1'b1; y =1'b1;bi =1'b0;#10 //第5种情况x =1'b0; y =1'b0; bi =1'b1;#10 //第6种情况x =1'b0; y =1'b1;bi =1'b1;#10 //第7种情况x =1'b1; y =1'b0;bi =1'b1;#10 //第8种情况x =1'b1; y =1'b1;bi =1'b1; #10 $stop(); //结束仿真
end
//例化被测试模块
full_subtractor u_full_subtractor(.x (x),.y (y), .di (di),.bi (bi),.bo (bo)
);endmodule
![]()
仿真结果如下所示:

通过和真值表的对比(或者验证逻辑表达式也可以),可以发现,电路的输出是符合预期的。
4、减法器
有了全减器后,就可以实现两个多bits数的减法了,这样的电路也被称为减法器。和行波进位加法器的结构类似,我们也可以将多个全减器级联起来搭建减法器,以4bits的减法为例,它的结构如下:

根据结构图,可以很快地写出它对应的Verilog代码:
//使用多个全减器建联构建减法器
module subtractor(input [3:0] x, //被减数input [3:0] y, //减数input bi, //来自低位的借位output [3:0] di, //差output bo //向高位借位
);
wire b1,b2,b3; //借位连接
//例化全减器来构建减法器
full_subtractor u0(.x (x[0]),.y (y[0]), .di (di[0]),.bi (bi),.bo (b1)
);
full_subtractor u1(.x (x[1]),.y (y[1]), .di (di[1]),.bi (b1),.bo (b2)
);
full_subtractor u2(.x (x[2]),.y (y[2]), .di (di[2]),.bi (b2),.bo (b3)
);
full_subtractor u3(.x (x[3]),.y (y[3]), .di (di[3]),.bi (b3),.bo (bo)
);
endmodule
这里记得要把之前的全减器也添加进工程。生成的示意图如下(这个排布不能很好地看出来层次结构,但确实没错):

然后写个TB测试一下这个减法器电路,因为4个bits即16×16=256种情况,加上低位借位的两种情况,也才256×2=512种情况,所以依然用穷举法来测试:
`timescale 1ns/1ns //时间刻度:单位1ns,精度1ns
module tb_full_subtractor();
//定义变量
reg [3:0] x; //被减数
reg [3:0] y; //减数
reg bi; //来自低位的借位
wire [3:0] di; //差
wire bo; //向高位借位
reg [3:0] di_real; //差的真实值,作为对比
reg bo_real; //向高位借位的真实值,作为对比
wire di_flag; //di正确标志信号
wire bo_flag; //bo正确标志信号
assign di_flag = di == di_real; //di结果正确时拉高该信号
assign bo_flag = bo == bo_real; //bo结果正确时拉高该信号
integer z,i,j; //循环变量
//设置初始化条件
initial begin//初始化x =1'b0; y =1'b0; bi =1'b0; //设定低位借位为0//穷举所有情况for(z=0;z<=1;z=z+1)beginbi = z;for(i=0;i<16;i=i+1)beginx = i;for(j=0;j<16;j=j+1)beginy = j;if((i-j-z)<0)begin //减法结果是负数di_real = (i - j - z)+ 5'd16; //加上向高位的借位bo_real = 1; //向高位的借位为1endelse begin //减法结果是正数数di_real = i - j - z; //结果就是减法本身bo_real = 0; //向高位的借位为0end#5; end endend#10 $stop(); //结束仿真
end
//例化被测试模块
subtractor u_subtractor(.x (x),.y (y), .di (di),.bi (bi),.bo (bo)
);endmodule
TB中分别用3个嵌套循环将所有情况穷举出来,即bi=0~1、x=0~15和y=0~15的所有情况。减法运算的预期结果也是很容易就可以找出来的,就是直接写减法就行。接着构建了两个标志向量di_flag和bo_flag作为电路输出与预期结果的对比值,当二者一致时即拉高这两个信号。这样我们只要观察这两个信号,即可知道电路输出是否正确。仿真结果如下:

可以看到,di_flag和bo_flag都是一直拉高的,说明电路输出正确。
相关文章:
基于FPGA的数字信号处理(20)--半减器和全减器
目录 1、前言 2、半减器 3、全减器 4、减法器 文章总目录点这里:《基于FPGA的数字信号处理》专栏的导航与说明 1、前言 既然有半加器和全加器,那自然也有半减器和全减器了。尽管在电路中减法的实现基本都是 补码 加法 的形式,但是正所谓…...
Python:单引号,双引号,三引号的区别
在Python中,单引号()、双引号(")和三引号( 或 """)都可以用来定义字符串,但它们之间有一些区别: 单引号()和双引号…...
电子电气架构 ---SOMEIP/SD初入门
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人,是精神上的节…...
一些数学基础概念
一些数学基础概念 概率密度函数(PDF) 概率密度函数(Probability Density Function,简称 PDF)是描述连续随机变量的概率分布的一种函数。它用来表示随机变量在各个取值区间内的概率密度。 1. 定义 对于一个连续随机变量 ( X ),…...
责任有限公司的一般组织结构
责任有限公司(有限责任公司,LLC)的组织结构通常是为了确保公司运营的有效性和管理的透明度。以下是一般责任有限公司的组织结构及其主要组成部分: 1. 股东(Shareholders) 职责和角色 所有者:…...
Leetcode3227. 字符串元音游戏
Every day a Leetcode 题目来源:3227. 字符串元音游戏 解法1:博弈论 分类讨论: 如果 s 不包含任何元音,小红输。如果 s 包含奇数个元音,小红可以直接把整个 s 移除,小红赢。如果 s 包含正偶数个元音&am…...
网络流量分析在运维管理中的重要性与实施策略
在运维管理工作中,网络流量分析是一项不可或缺的技术手段。通过对网络流量的深入剖析,运维团队能够更全面地了解网络状态,及时发现潜在问题,优化网络性能,从而确保企业网络的稳定与高效运行。本文将详细探讨网络流量分…...
通信原理实验——PCM编译码
PCM编译码 实验目的 理解PCM编译码原理及PCM编译码性能熟悉PCM编译码专用集成芯片的功能和使用方法及各种时钟关系熟悉语音数字化技术的主要指标及测量方法 主要仪器设备及软件 硬件:多功能实验箱、示波器、导线 软件:无 实验原理 1. 抽样信号的量…...
matlab的strel()函数的使用方法(OK)
这个函数 是形态学的结构元素 使用方法如下 SE strel(nhood) SE strel("diamond",r) SE strel("disk",r) SE strel("disk",r,n) SE strel("octagon",r) SE strel("line",len,deg) SE strel("rectangle",…...
Linux:Linux权限解析
一、Linux下的用户分类 在Linux下,有两种用户,一种是超级用户,一种是普通用户 超级用户:可以再linux系统下做任何事情,不受权限限制(制定规则,但不需要遵守规则) 普通用户࿱…...
Spring面试篇章——IOC
IOC概念和原理 IOC概念 IOC就是控制反射,把对象创建和对象之间的调用过程,交给Spring进行管理使用IOC的目的:降低耦合度 IOC底层原理 xml解析、工厂模式、反射 图解: 原始模式 耦合度太高了,即当dao改了…...
适合制造业的项目管理软件都有哪些?
项目管理软件涉及进度、预算成本、资源、开发、流程、质量、风险、工时、知识文档、商务等各个方面,是企业项目管理领域的重要辅助工具,能够帮助组织提高项目管理水平与质量,确保项目顺利进行。 一、 奥博思 PowerProject 项目管理系统 Pow…...
微应用(Micro-Applications)、微前端(Micro Frontend)、Qiankun 框架之间的区别和联系
简简单单 Online zuozuo: 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo :本心、输入输出、结果 简简单单 Online zuozuo :联系我们:VX :tja6288 / EMAIL: 347969164@qq.com 文章目录 微应用(Micro-Applications)、微…...
String的底层构造
1.String类对象的构造(后面有每一个接口的实现) #define _CRT_SECURE_NO_WARNINGS 1 #pragma once #include<iostream> #include<assert.h> using namespace std;namespace bit {class string{public:typedef char* iterator;typedef const…...
Binder机制的原理
Binder机制是Android系统中用于进程间通信(IPC)的核心机制,它基于C/S(客户端-服务端)模型,允许不同进程间进行高效的通信和数据交换。以下是对Binder机制原理的详细解析: 1. Binder架构 Binde…...
JavaScript输出数据的方法?
在JavaScript中,输出数据有以下几种方法: 使用console.log()函数:使用console.log()函数可以将数据输出到浏览器的控制台,例如: console.log("Hello, World!");使用alert()函数:使用alert()函数…...
Redis学习笔记——第19章 事务
第19章 事务 19.1 事务的实现 19.1.1 事务开始 使用multi命令开启一个事务 通过修改客户端的flags字段为REDIS_MULTI 19.1.2 命令入队 当开启事务之后,exec、discard、watch、multi命令立即执行,而其他命令会放入一个队列中,并返回Queue…...
元太电磁膜SUDE-10S19MI-01X驱动适配
屏规格书: dts配置: 首先要确保CONFIG_I2C_HID宏打开,i2c-hid-core.c 文件才能编译进去代码。规格书vendor product 分别为0x2d1f 和0x0165 来区别,不至于影响到整体的hid其他设备。 i2c-hid-dev10 { compatible "hid-…...
C#数据类型 全局变量 类型转换方法(汇总)
1、C#和S7-1200PLC S7.NET通信 C#和S7-1200PLC S7.NET通信-CSDN博客文章浏览阅读98次。一步步建立一个C#项目(连续读取S7-1200PLC数据)_s7协议批量读取-CSDN博客这篇博客作为C#的基础系列,和大家分享如何一步步建立一个C#项目完成对S7-1200PLC数据的连续读取。首先…...
HCIP重修总笔记(中)
第八节 BGP基础 一、BGP产生背景 BGPBorder Gateway Protocol,边界网关协议)是一种用于自治系统间的动态路出协议,是一种外部网关协议。 自治系统AS:一组同一个管理机构进行管理,对外呈现统一选路策略的路由器的集合。 自治系统编号: …...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...
[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:
根据万维钢精英日课6的内容,使用AI(2025)可以参考以下方法: 四个洞见 模型已经比人聪明:以ChatGPT o3为代表的AI非常强大,能运用高级理论解释道理、引用最新学术论文,生成对顶尖科学家都有用的…...
ios苹果系统,js 滑动屏幕、锚定无效
现象:window.addEventListener监听touch无效,划不动屏幕,但是代码逻辑都有执行到。 scrollIntoView也无效。 原因:这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作,从而会影响…...
selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...
