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

news2024/10/1 5:34:38

目录

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种情况(在上面已经例出来了),据此可以写出半减器的真值表:

被减数减数向高位借位
XYDiBo
0000
0111
1010
1100

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

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

  • 向高位借位Bo在X = 0 且 Y = 1 时才为1,即 Bo= ~X & Y

        有了逻辑表达式后,可以很容易地画出对应的门电路结构:

image-20240426103255933

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

image-20240426105010530

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

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

image-20240426105038079

        用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

        仿真结果如下:

image-20240426105113676

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

3、全减器

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

  1. 先把低位和高位的减法先分开。

  2. 低位是2个1bit的减法,所以可以用1个HS(半减器)来实现,它产生的差就是最终结果的低位,它产生的向高位借位要被送入到高位参与它们的减法。

  3. 高位除了要计算减数和被减数的高位外,还有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种情况,把所有情况都穷举出来,就可以列出全减器的真值表:

被减数减数来自低位的借位向高位的借位
XYBiDiBo
00000
00111
01011
01101
10010
10100
11000
11111

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

  • 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生成的):

image-20240426112013178

        根据门电路,可以写出全减器的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

        仿真结果如下所示:

image-20240426112114957

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

4、减法器

        有了全减器后,就可以实现两个多bits数的减法了,这样的电路也被称为减法器。和行波进位加法器的结构类似,我们也可以将多个全减器级联起来搭建减法器,以4bits的减法为例,它的结构如下:

image-20240426113045693

        根据结构图,可以很快地写出它对应的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

        这里记得要把之前的全减器也添加进工程。生成的示意图如下(这个排布不能很好地看出来层次结构,但确实没错):

image-20240426121705201

        然后写个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)begin
        bi = z;
        for(i=0;i<16;i=i+1)begin
            x = i;
            for(j=0;j<16;j=j+1)begin
                y = j;
                if((i-j-z)<0)begin                  //减法结果是负数
                    di_real = (i - j - z)+ 5'd16;   //加上向高位的借位
                    bo_real = 1;                    //向高位的借位为1
                end
                else begin                          //减法结果是正数数
                    di_real = i - j - z;            //结果就是减法本身
                    bo_real = 0;                    //向高位的借位为0
                end
                #5;             
            end 
        end
    end
    #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作为电路输出与预期结果的对比值,当二者一致时即拉高这两个信号。这样我们只要观察这两个信号,即可知道电路输出是否正确。仿真结果如下:

image-20240426122614109

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

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

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

相关文章

Hadoop搭建集群

Hadoop搭建集群 前言一、环境配置1.配置JDK2.配置Hadoop环境 二、Hadoop本地运行三、Hadoop集群部署1.准备三台服务器2.节点规划3.环境配置4.无秘登录5.配置核心文件1&#xff09;修改core-site.xml2&#xff09;修改hdfs-site.xml3&#xff09;修改yarn-site.xml4&#xff09;…

【linux】【操作系统】内核之sched.c源码阅读

sched.c提供的代码片段包含了与操作系统内核中的进程调度和管理相关的多个函数。schedule函数首先对所有任务&#xff08;进程&#xff09;进行检测&#xff0c;唤醒任何一个已经得到信号的任务。具体方法是针对任务数组中的每个任务&#xff0c;检查其报警定时值alam。如果任务…

Midjourney咒语之手机壁纸国画艺术

手机壁纸 Mountains, surfaces, mysterious landscapes --ar 9:16 Abstract shapes of billowing flowing colorful gauze fabric, --ar 9:16 国画艺术 Peony is

如何快速看完一个网页上的视频

如何快速看完一个视频 懂的都懂。 Edge浏览器 添加下面两个书签&#xff1a; javascript:document.querySelector("video").dispatchEvent(new Event("ended"))javascript:var vdocument.querySelector("video");if(v){v.mutedtrue;v.playba…

从艺术创作到作物生长,农业AI迎来“GPT“时刻

&#xff08;于景鑫 国家农业信息化工程技术研究中心&#xff09;"GPT"一词早已不再神秘,其在文本、图像生成领域掀起的风暴正以摧枯拉朽之势席卷全球。人们惊叹于ChatGPT对话之智能、思维之敏捷,更对Stable Diffusion、Midjourney创作的艺术画作赞叹不已。而大语言模…

无代码开发AI服务 - 利用向量库Kendra和Llama大模型在亚马逊云科技AWS上创建RAG知识库

简介&#xff1a; 小李哥将继续每天介绍一个基于亚马逊云科技AWS云计算平台的全球前沿AI技术解决方案&#xff0c;帮助大家快速了解国际上最热门的云计算平台亚马逊云科技AWS AI最佳实践&#xff0c;并应用到自己的日常工作里。 上次我们介绍了我们利用ElasticSearch作为向量…

网鼎杯comment二次注入

靶机网址&#xff1a;BUUCTF在线评测 进来就是这个界面&#xff0c;点击发帖后需要进行登录。 从界面可以看出用户是zhangwei&#xff0c;密码是zhangwei***&#xff0c;密码的最后三位需要进行暴力破解。 这里需要用到工具Burp Suite进行抓包。 这就是抓到的包&#xff0c;我…

【大模型从入门到精通8】openAI API 提升机器推理:高级策略2

这里写目录标题 示例定义处理输入的函数链式思考提示示例&#xff1a;结构化系统和用户提示获取并展示模型的回答实现内心独白结论与最佳实践 示例 设置环境 在深入实施之前&#xff0c;设置必要的环境至关重要。这包括加载 OpenAI API 密钥并导入相关的 Python 库。以下代码块…

Chapter 25 面向对象

欢迎大家订阅【Python从入门到精通】专栏&#xff0c;一起探索Python的无限可能&#xff01; 文章目录 前言一、初识对象二、成员方法三、类和对象 前言 面向对象编程&#xff08;OOP&#xff09;是Python编程中的一个核心概念&#xff0c;它能帮助程序员更好地组织和管理代码…

01 计算机系统基础-2

操作系统 进程管理 进程管理是操作系统的核心&#xff0c;但如果设计不当&#xff0c;就会出现死锁的问题。如果一个进程在等待一件不可能发生的事&#xff0c;则进程就死锁了。而如果一个或多个进程产生死锁&#xff0c;就会造成系统死锁。基于死锁产生机制及解决方案&#…

LeetCode Hard|【460. LFU 缓存】

力扣题目链接 LFU全称是最不经常使用算法&#xff08;Least Frequently Used&#xff09;&#xff0c;LFU算法的基本思想和所有的缓存算法一样&#xff0c;一定时期内被访问次数最少的页&#xff0c;在将来被访问到的几率也是最小的。 相较于 LRU 算法&#xff0c;LFU 更加注重…

MATLAB霍夫曼表盘识别系统

MATLAB霍夫曼表盘识别系统 一、介绍 本设计为基于MATLAB的表盘指针识别&#xff0c;算法原理是基于hough变换。可检测压力表&#xff0c;石英手表&#xff0c;电表刻度&#xff0c;气压表等带指针刻度的表盘。通过hough检测直线和圆的关系&#xff0c;得出指针夹角&#xff0…

保形分位数回归(CQR)

目录 简介1 介绍提纲式总结 分位数回归从数据中估计分位数 3 共性预测4 保形分位数回归(CQR)两个定理 6 实验7 结论 简介 保形预测是一种构造在有限样本中获得有效覆盖的预测区间的技术&#xff0c;无需进行分布假设。尽管有这种吸引力&#xff0c;但现有的保形方法可能是不必…

(C题老外游中国)2024年华数杯大学生数学建模竞赛解题思路完整代码论文集合

我是Tina表姐&#xff0c;毕业于中国人民大学&#xff0c;对数学建模的热爱让我在这一领域深耕多年。我的建模思路已经帮助了百余位学习者和参赛者在数学建模的道路上取得了显著的进步和成就。现在&#xff0c;我将这份宝贵的经验和知识凝练成一份全面的解题思路与代码论文集合…

Open3D 三维重建-Delaunay Triangulation (德劳内三角剖分)

目录 一、概述 1.1原理 1.2实现步骤 1.3应用 二、代码实现 2.1关键函数 2.2完整代码 三、实现效果 3.1原始点云 3.2重建后点云 Open3D点云算法汇总及实战案例汇总的目录地址&#xff1a; Open3D点云算法与点云深度学习案例汇总&#xff08;长期更新&#xff09;-CSD…

MySQL--日志管理

前言&#xff1a;本博客仅作记录学习使用&#xff0c;部分图片出自网络&#xff0c;如有侵犯您的权益&#xff0c;请联系删除 一、日志简介 MySQL日志主要分为4类&#xff0c;使用这些日志文件&#xff0c;可以查看MySQL内部发生的事情。这4类日志分别是: 错误日志&#xff1…

程序编译及链接

你好&#xff01;感谢支持孔乙己的新作&#xff0c;本文就程序的编译及链接与大家分析我的思路。 希望能大佬们多多纠正及支持 &#xff01;&#xff01;&#xff01; 个人主页&#xff1a;爱摸鱼的孔乙己-CSDN博客 ​ ​ 1.翻译译环境与运行环境 当我们进行程序设计时&…

Android Graphics 显示系统 - 计算FPS的原理与探秘Present Fence

“ 最近忙着新房子装修的事情&#xff0c;这篇计划内的文章拖了好久一直没有足够的时间来写作&#xff0c;终于挤出些儿时间来继续研究学习了。” 整了四个晚上终于拼凑出一篇文章&#xff0c;虽说是讲FPS计算原理&#xff0c;但该文涉及的知识点还是蛮多的&#xff0c;特别是对…

webpack的loader机制

webpack的loader机制 loader本质上就是导出函数的JavaScript模块。导出的函数&#xff0c;可以用来实现内容的转换。 /* * param{string|Buffer} content 源文件的内容 * param{object} [map] SourceMap数据 * param{any} [meta] meta数据&#xff0c;可以是任何数据 * */ fu…

黑马头条vue2.0项目实战(五)——首页—频道编辑

目录 1. 使用页面弹出层 1.1 页面弹出层简单使用 1.2 创建频道编辑组件 1.3 页面布局 2. 展示我的频道 3. 展示推荐频道列表 3.1 获取所有频道 3.2 处理展示推荐频道 4. 添加频道 5. 编辑频道 5.1 处理编辑状态 5.2 切换频道 5.3 让激活频道高亮 5.4 删除频道 6.…