超前进位加法器原理与递推式超详细推导+verilog实现与测试

2023-05-16

当记忆的线缠绕过往支离破碎,是慌乱占据了心扉。----《寂寞沙洲冷》

超前进位加法器原理

1. 一位二进制的加法

首先考虑两个1位二进制相加 a+b,不考虑上一级的进位,0和1简单相加,即使是三岁小孩理解下面的表格想必也没有什么困难

上一级的进位(Cn-1)AB进位(Cn)
0000
0100
0010
0111

结论显而易见,A&B==1(AB=1)的时候存在进位

2. 考虑存在输入的进位情况下的进位:

上一级的进位(Cn-1)AB进位(Cn)
1000
1011
1101
1111

那么,考虑上一级进位的情况下,A || B==1(A+B=1)时存在进位

3. 卡诺图公式推导

用到一点简单的数电知识,综合以上两个表格,画出卡诺图如下:

一位挂科的学生默默翻开了书复习卡诺图化简

C[n-1]\AB00011110
00010
10111

短暂复习过后,不难看出,存在三个圈,则根据卡诺图写出最简表达式为:

逻辑表达式为:
C[n] = AB + BC[n-1] + AC[n-1]
		= AB + C[n-1](A + B)

使用逻辑运算符书写为:
C[n] = (A[n] & B[n]) || ((A[n] || B[n]) & C[n-1])

即使你没有挂科,如果不会,请去看看数电书。

4.超前进位递推式

既然递推式得到了,那么事情就变得简单了。例如:
设两个八位二进制加数为A、B,则:

C0 = A[0] || B[0] (第一位没有上一级的进位)
C1 = (A[1] & B[1]) || ((A[1] || B[1]) & C[0])
C2 = (A[2] & B[2]) || ((A[2] || B[2]) & C[1])
C3 = (A[3] & B[3]) || ((A[3] || B[3]) & C[2])
C4 = ······

5. 二进制本位加法

两个一位二进制数相加忽略之前的进位,其

ans = A xor B

考虑之前的进位,设进位为C[n-1],二进制数为A、B,则:

C[n-1]ABans[n]
0000
0011
0101
0110
1001
1010
1100
1111

这次,聪明的你想必不需要卡诺图也能直接看出来表达式了,没错,就是:

ans[n] = C[n-1] xor (A[n] xor B[n])

6. 总结

设两加数为A、B,且进位数组为C[n],答案为ans[n],则:

C[0] = A[0] & B[0];
ans[1] = A[0] xor B[0];

C[1] = (A[1] & B[1]) || ((A[1] || B[1]) & C[0]);
ans[2] = C[1] xor (A[2] xor B[2]);

C[2] = (A[2] & B[2]) || ((A[2] || B[2]) & C[1]);
ans[3] = C[2] xor (A[3] xor B[3]);

······

7.代码

根据上述分析,使用verilog写出四位超前进位加法器如下:
(这样写真的很蠢,不要这样写,别的博主有写的更好的,这里贴一篇。他的代码很简单美观。但是注意到他这篇文章的评论有人说他写的不是超前进位,好像确实是这样,因为他那个本质还是递推)
需要注意的是,
超前进位加法器的本质是用电路的复杂程度去换时间。–《数字电子技术基础(第六版)》

module top(
    input [3:0] a,
    input [3:0] b,
    input c,
    output [3:0] ans
);

wire [3:0] C;

assign ans[0] = a[0] ^ b[0];
assign C[0] = a[0] & b[0];

//这些注释掉的都是递推式,你可以先写好递推式再把上面的C[n-1]复制粘贴替换进去就可以
//assign ans[1] = C[0] ^ (a[1] ^ b[1]);
//assign C[1] = ((a[1] | b[1]) & C[0]) | (a[1] & b[1]);

assign ans[1] = (a[0] & b[0]) ^ (a[1] ^ b[1]);
assign C[1] = ((a[1] | b[1]) & (a[0] & b[0])) | (a[1] & b[1]);

// assign ans[2] = C[1] ^ (a[2] ^ b[2]);
// assign C[2] = ((a[2] | b[2]) & C[1]) | (a[2] & b[2]);

assign ans[2] = (((a[1] | b[1]) & (a[0] & b[0])) | (a[1] & b[1])) ^ (a[2] ^ b[2]);
assign C[2] = ((a[2] | b[2]) & (((a[1] | b[1]) & (a[0] & b[0])) | (a[1] & b[1]))) | (a[2] & b[2]);

// assign ans[3] = C[2] ^ (a[3] ^ b[3]);
// assign C[3] = ((a[3] | b[3]) & C[2]) | (a[3] & b[3]);

assign ans[3] = ((a[2] | b[2]) & (((a[1] | b[1]) & (a[0] & b[0])) | (a[1] & b[1]))) | (a[2] & b[2]) ^ (a[3] ^ b[3]);
assign C[3] = ((a[3] | b[3]) & ((a[2] | b[2]) & (((a[1] | b[1]) & (a[0] & b[0])) | (a[1] & b[1]))) | (a[2] & b[2])) | (a[3] & b[3]);


//如果你需要八位的加法器,把下面的注释去掉
// assign ans[4] = C[3] ^ (a[4] ^ b[4]);
// assign C[4] = ((a[4] | b[4]) & C[3]) | (a[4] & b[4]);

// assign ans[5] = C[4] ^ (a[5] ^ b[5]);
// assign C[5] = ((a[5] | b[5]) & C[4]) | (a[5] & b[5]);

// assign ans[6] = C[5] ^ (a[6] ^ b[6]);
// assign C[6] = ((a[6] | b[6]) & C[5]) | (a[6] & b[6]);

// assign ans[7] = C[6] ^ (a[7] ^ b[7]);
// assign C[7] = ((a[7] | b[7]) & C[6]) | (a[7] & b[7]);
endmodule

8. 测试代码

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "verilated_vcd_c.h" //可选,如果要导出vcd则需要加上
#include "Vtop.h"    //.v  ->  .h
#include <iostream>
#include <bitset>


vluint64_t main_time = 0;  //initial 仿真时间


double sc_time_stamp()
{
    return main_time;
}
 
int main(int argc, char **argv)
{
    Verilated::commandArgs(argc, argv); 
    Verilated::traceEverOn(true); //导出vcd波形需要加此语句
    
    VerilatedVcdC* tfp = new VerilatedVcdC; //导出vcd波形需要加此语句
    Vtop *top = new Vtop("top"); //调用VShuang.h里面的IO struct
 
    top->trace(tfp, 0);   
    tfp->open("wave.vcd"); //打开vcd
 
    int a = 1;
    int b = 0;
    int c = 0;

    while (sc_time_stamp() < 7 && !Verilated::gotFinish()) { //控制仿真时间
        top->a = a; //激励控制
        top->b = b;
        top->c = c;
        top->eval(); //计算输出
        std::cout<<a<<"   "<<b<<"   "<<std::bitset<4>(top->ans)<<"    ";
        printf("%d\n", top->ans);
        tfp->dump(main_time); //dump wave
        main_time++; //推动仿真时间
        a++;//向后产生加数,你自己random产生测试数据也行
        b++;
    }
    top->final();
    tfp->close();
    delete top;
 
    return 0;
}

9. 输出

左边两个是加数,中间的是二进制,后面的是十进制表示:

1   0   0001    1
2   1   0011    3
3   2   0101    5
4   3   0111    7
5   4   1001    9
6   5   1011    11
7   6   1101    13

10. 编译命令

文件名为 top.v main.cpp

verilator -Wno-fatal top.v main.cpp --top-module top --cc --trace --exe	#编译.v文件
make -C obj_dir -f ./Vtop.mk Vtop	#编译cpp
./obj_dir/Vtop	#运行
gtkwave wave.vcd	#查看vcd波形

波形图

后记:1.一开始忘了卡诺图每一个相邻项只能变一个值,写成了00 01 10 11,怎么化简也化不出来,后来才发现,真的是,才疏学浅。
2.这玩意还写了半天,真的是很不熟练。
3.本例仅供学习超前进位加法器原理使用,实际编程直接+就完事了,verilog内置的肯定比咱写的垃圾加法器优化要好。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

超前进位加法器原理与递推式超详细推导+verilog实现与测试 的相关文章

随机推荐

  • dockerfile容器的实战安装nginx和mysql服务

    第三章 实验 xff1a docker容器的实战 一 基础环境 安装docker服务 1 xff09 配置网络yum源 root 64 centos01 cd etc yum repos d root 64 centos01 yum rep
  • 使用 Learner Lab 建立 WordPress 网站 (EC2)

    使用 Learner Lab 建立 WordPress 网站 EC2 AWS Academy Learner Lab 是提供一个帐号让学生可以自行使用 AWS 的服务 xff0c 让学生可以在 100 USD的金额下 xff0c 自行练习所
  • LaTex 排版相关记录--1 参考文献排版

    找到latex代码中的 bibligraphystyle xff0c 然后根据下面的各种需求进行替换 bibliographystyle unsrt 样式同plain xff0c 只是按照引用的先后排序 xff0c 参考文献会根据在正文中引
  • 使用rke构建企业生产k8s,安装kubectl客户端

    一 使用rke构建企业生产k8s xff0c 安装kubectl客户端 1 安装kubectl客户端工具 span class token comment wget https storage googleapis com kubernet
  • 保持pppoe不掉线

    对于无极网络的VPS 修改 etc ppp pppoe server options 这个文件里面的两个参数 默认 xff1a lcp echo interval 1 发送间隔秒 lcp echo failure 5 5次未响应断开 因为o
  • Linux环境编程06

    目录 Linux环境编程之进程管理一 进程的基本概念二 创建进程三 进程的正常退出 Linux环境编程之进程管理 一 进程的基本概念 进程与程序 程序是存储在磁盘上的可执行文件 xff0c 程序被加载到内存中开始运行时叫做进程 一个程序可以
  • 区间最大平均值

    题目链接 xff1a https www luogu com cn problem P1404 题目描述 xff1a 给一个长度为 n 的数列 xff0c 我们需要找出该数列的一个子串 xff0c 使得子串平均数最大化 xff0c 并且子串
  • 输出 0~N 内的素数 ( C++ )

    span class token macro property span class token directive hash span span class token directive keyword include span spa
  • 快读模板 ( C++ )

    span class token macro property span class token directive hash span span class token directive keyword include span spa
  • Java正整数分解质因数

    leetcode 2 Java正整数分解质因数 1 题目 xff1a 将一个正整数分解质因数 例如 xff1a 输入 90 打印出 90 61 233 5 2 题目解析 xff1a 先将数m从2开始整除 xff0c 如果能被2整除 xff0
  • you-get使用教程

    you get爬虫 xff0c 依赖于Python3 10 xff0c 可以爬取网页无法下载的视频文件 xff0c 具体步骤如下 xff1a 1 xff0c 下载Python3 10无脑下一步安装 2 xff0c 新建一个空白文件夹 xff
  • Windows如何自定义右键新建菜单栏

    目录 右键新建菜单的实现原理在右键新建菜单中新增项方法一可能出现的问题 方法二编辑右键新建菜单的图标 修改右键新建菜单栏的顺序 右键新建菜单的实现原理 参考文章 修改 win10 右键 新建 菜单 xff08 原理 两种方法及注意事项 xf
  • Centos 8升级至Centos 8 Stream

    文章目录 一 背景 xff1a 二 分析 xff1a 三 升级步骤 xff1a 四 成功安装 openstack 软件仓库参考链接 xff1a 一 背景 xff1a 因使用华为云ecs部署 openstack yoga 版本过程中 xff0
  • Ceph OSD为DOWN时修复

    本文所使用Ceph版本为luminous 不同版本删除OSD基本操作相同 xff09 xff0c 当出现Ceph OSD为down的情况时 xff0c 可以通过以下方法解决 xff08 假设ceph admin节点OSD 1 Down xf
  • 【Anaconda创建虚拟环境】报错及解决办法

    Q1 CondaHTTPError HTTP 000 CONNECTION FAILED for url 错误原因 xff1a 下载网速过慢 xff0c 时间过长 xff0c 自动断开 解决方法 xff1a 在下载命令前加入 conda c
  • 二叉树的绘制

    目录 一 知乎方法 二 动手实践 DOT 语言 无向图 有向图 绘制二叉树 设置属性 如何绘制优美的二叉树 一 知乎方法 知乎上的大佬提供了一系列画图的方法 xff0c 感兴趣的朋友可以自行去看看 用 Graphviz 绘制一棵漂亮的二叉树
  • 修改CPU的调频策略

    cat proc cpuinfo 查看CPU信息 CPU的调频策略修改 xff0c scaling governor xff1a governor 调频 策略 xff0c Linux 内核一共有 5 中调频策略 Performance xf
  • 一文看懂map、odom、base_link、laser之间的tf关系

    这三者之间的关系到底是怎样的 xff1f 尤其是map坐标系到odom坐标系之间的变换 xff0c 到底是有什么意义呢 xff1f 我当时被这个问题也是困扰了很久 现在经过实践终于有机会记录一下拙见 xff0c 如有错误 xff0c 还请指
  • VTK库cmake编译时找不到Qt5UiPlugin_DIR和QT5Sql_DIR

    ubuntu使用cmake gui编译VTK时 xff0c Qt5UiPlugin DIR和QT5Sql DIR是红的 xff0c 怎么办 xff1f 答 xff1a 安装libqt5x11extras5 dev和qt5 default两个
  • 超前进位加法器原理与递推式超详细推导+verilog实现与测试

    当记忆的线缠绕过往支离破碎 xff0c 是慌乱占据了心扉 寂寞沙洲冷 超前进位加法器原理 1 一位二进制的加法 首先考虑两个1位二进制相加 a 43 b xff0c 不考虑上一级的进位 xff0c 0和1简单相加 xff0c 即使是三岁小孩