基于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:一组同一个管理机构进行管理,对外呈现统一选路策略的路由器的集合。 自治系统编号: …...
eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...
Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...
Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...
3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...
使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度
文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...
