数字电路设计——加法器

数字电路设计——加法器

半加器

半加器只有两个一位宽的输入 a a a b b b ,输出 a + b a+b a+b 所产生的本位和 s u m sum sum 和进位 c o u t cout cout。组合逻辑为:

S = A ⊕ B , C o u t = A B S = A \oplus B,Cout = AB S=AB,Cout=AB

真值表和原理图符合为:

半加器
SystemVerilog实现代码:

module hadder (input logic a,input logic b,output logic sum,output logic cout
);assign sum = a ^ b;assign cout = a & b;
endmodule

全加器

加法器一般指全加器,半加器只能实现一位加法,而全加器才能真正实现多位加法,相较于半加器,全加器考虑了上一位的进位,因此全加器有三个输入分别是 a , b , c i n a,b,cin a,b,cin ,输出 a + b + c i n a+b+cin a+b+cin 所产生的本位和 s u m sum sum 和进位 c o u t cout cout。组合逻辑为:

S = A ⊕ B ⊕ C i n , C o u t = A B + A C i n + B C i n S = A \oplus B \oplus Cin, Cout = AB + ACin + BCin S=ABCin,Cout=AB+ACin+BCin

真值表和原理图符号为:

全加器
SystemVerilog实现代码:

module fadder (input logic a,input logic b,input logic cin,output logic sum,output logic cout
);assign sum = a ^ b ^ cin;assign cout = a & b | a & cin | b & cin;
endmodule

进位传播加法器

单个全加器只能实现单个位的加法,若想实习多位加法,就必须考虑到位于位直接的进位问题,我们称这类模拟竖式依次进位的加法器为进位传播加法器(carry propagate adder),简称CPA。

其原理图表示为:

进位链加法器

进位链加法器

单个全加器只能实现单个位的加法,当将多个全加器进行进位链式连接的时候,就可以实现多位加法,我们称为进位链加法器(Ripple-Carry Adder),具体的,一个32位宽的进位链加法器可表示为:

进位链加法器

SystemVerilog实现代码:

module rcadder(input logic[31:0] a,input logic[31:0] b,input logic cin,output logic[31:0] sum,output logic cout
);genvar i;
logic[32:0] c;generateassign c[0] = cin;for(i = 0;i < 32;i=i+1) beginfadder adder_inst(.a (a[i]),.b (b[i]),.cin (c[i]),.sum (sum[i]),.cout (c[i + 1]));end
endgenerateassign cout = c[32];endmodule

显然,进位加法器的传播延迟 t r i p p l e t_{ripple} tripple 为:

t r i p p l e = N t F A t_{ripple} = Nt_{FA} tripple=NtFA

其中 N N N 为加法位宽,而 t F A t_{FA} tFA 是单个全加器的传播延迟。

超前进位加法器

进位链加法器的缺点在于进位传播的太慢,以至于进位链成为组合逻辑的关键路径,拖慢了系统时钟速率,通过巧妙的构造,可以加速这个过程,称为超前进位加法器(Carry-Lookahead Adder),简称CLA。

CLA使用生成(generate)G和传播(propagate)P两个信号来描述一个加法器如何控制进位的输入和输出。

具体的,考虑第 i i i 位全加器,我们称其生成进位而与上一位的进位无关,当且仅当 A i A_i Ai B i B_i Bi 都是1,换句话说当 A i A_i Ai B i B_i Bi 都是1的时候,该位一定进位而与上一位是否进位无关。

考虑第 i i i 位全加器,我们称其传播进位,则当上一位进位的时候,该位一定进位,此时 A i A_i Ai B i B_i Bi 有一个至少是1。

两个信号的逻辑表达式为:

G i = A i B i , P i = A i + B i G_i = A_i B_i,P_i = A_i + B_i Gi=AiBi,Pi=Ai+Bi

现在我们再考虑当前进位 C i C_i Ci 和上一位进位的关系 C i − 1 C_{i-1} Ci1 根据G和P的定义,显然有:

C i = G i + P i C i − 1 C_i = G_i + P_iC_{i-1} Ci=Gi+PiCi1

现在来考虑一个进位链加法器,我们将 G i : j G_{i:j} Gi:j 表示为第j个到第i个加法器所组成CPA的G信号,而将 P i : j P_{i:j} Pi:j 表示为第j个到第i个加法器所组成CPA的P信号。

具体的,考虑 G 3 : 0 G_{3:0} G3:0 的表示,若 G 3 : 0 G_{3:0} G3:0 成立,当且仅当 G 3 G_3 G3 成立,或是 P 3 G 2 : 0 P_3G_{2:0} P3G2:0 成立。那么:

G 3 : 0 = G 3 + P 3 G 2 : 0 G_{3:0} = G_3 + P_3G_{2:0} G3:0=G3+P3G2:0

我们发现这是一个递归定义的式子,将递归展开后得到:

G 3 : 0 = G 3 + P 3 ( G 2 + P 2 ( G 1 + P 1 G 0 ) ) G_{3:0} = G_3 + P_3(G_2 + P_2(G_1 + P_1G_0)) G3:0=G3+P3(G2+P2(G1+P1G0))

考虑 P 3 : 0 P_{3:0} P3:0 的表示,其结构类似于串联的开关:

P 3 : 0 = P 3 P 2 P 1 P 0 P_{3:0} = P_3P_2P_1P_0 P3:0=P3P2P1P0

而且下面的式子显然成立:

C i = G i : j + P i : j C j − 1 C_i = G_{i:j} + P_{i:j}C_{j-1} Ci=Gi:j+Pi:jCj1

有了上面的基础,我们就可以描述超前进位加法器的结构:

超前进位加法器
超前进位加法器利用了并行的思想,例如将32位的加法,拆成8个4位的并行加法器,每个4位加法器中仍然使用进位链加法器,不同的是,通过构造G和P,使得并行加法器之间传播进位更快了,解决了传统进位链加法器进位传播慢的特点。具体的,G和P只和当前位有关,而和进位位无关,因此对于G和P的计算结构是并行的。

一旦所有并行加法器的 G i : j G_{i:j} Gi:j P i : j P_{i:j} Pi:j 同时计算好之后, C C C 进位就可以快速的传播,只需要串行传播8次即可,相比于进位链加法器传播32次少了不少。下面是超前进位加法器的时间线:

超前进位加法器时间线
观察可以得到,超前进位加法器的传播延迟为:

t C L A = t p g + t p g b l o c k + ( N k − 1 ) t A N D / O R + k t F A t_{CLA} = t_{pg} + t_{pgblock} + (\frac{N}{k} - 1) t_{AND/OR} + kt_{FA} tCLA=tpg+tpgblock+(kN1)tAND/OR+ktFA

其中 t p g t_{pg} tpg 是计算单个 G i G_i Gi P i P_i Pi 的时间,通常是一个与门或是或门的传播时延。 t p g b l o c k t_{pgblock} tpgblock 是计算单个并行加法器的G和P的时间, N N N 是加法器的位数, k k k 的每个并行加法器的位数, t A N D / O R t_{AND/OR} tAND/OR 是从 C i C_i Ci C i + k C_{i+k} Ci+k 的时延,通常为一个或门加与门的传播时延。 k t F A kt_{FA} ktFA 是一个并行加法器的加法的传播时延。

N > 16 N > 16 N>16 的时候,超前进位加法器的时延将远大于进位链加法器。

SystemVerilog实现代码:

module rcadder4(input logic[3:0] a,input logic[3:0] b,input logic cin,output logic[3:0] sum,output logic cout
);genvar i;
logic[4:0] c;generateassign c[0] = cin;for(i = 0;i < 4;i=i+1) beginfadder adder_inst(.a (a[i]),.b (b[i]),.cin (c[i]),.sum (sum[i]),.cout (c[i + 1]));end
endgenerateassign cout = c[4];
endmodulemodule cladder(input logic[31:0] a,input logic[31:0] b,input logic cin,output logic[31:0] sum,output logic cout
);genvar i;
logic[31:0] g;
logic[31:0] p;
logic[8:0] c;generateassign c[0] = cin;for(i = 0;i < 32;i=i+1) beginassign g[i] = a[i] & b[i];assign p[i] = a[i] | b[i];endfor(i = 0;i < 8;i=i+1) beginlogic g_block;logic p_block;assign g_block = g[i * 4 + 3] | p[i * 4 + 3] & (g[i * 4 + 2] | p[i * 4 + 2] & (g[i * 4 + 1] | p[i * 4 + 1] & g[i * 4]));assign p_block = p[i * 4 + 3] & p[i * 4 + 2] & p[i * 4 + 1] & p[i * 4];assign c[i + 1] = g_block | p_block & c[i];rcadder4 adder4_inst(.a (a[(i + 1) * 4 - 1:i * 4]),.b (b[(i + 1) * 4 - 1:i * 4]),.cin (c[i]),.sum (sum[(i + 1) * 4 - 1:i * 4]),.cout ());end
endgenerateassign cout = c[8];
endmodule

并行前缀和加法器

考虑如何合并两个CLA的G和P信号:

G i : j = G i : k + P i : k G k − 1 : j , P i : j = P i : k P k − 1 : j G_{i:j} = G_{i:k} + P_{i:k}G_{k-1:j},P_{i:j} = P_{i:k}P_{k-1:j} Gi:j=Gi:k+Pi:kGk1:j,Pi:j=Pi:kPk1:j

我们将这样的组合逻辑元件记为:

GP合并
考虑到第 i i i个全加器的进位为 C i C_i Ci 特别的 C 0 = C i n C_0=Cin C0=Cin 。那么:

C i = G i − 1 : 0 + P i − 1 : 0 C i n C_i = G_{i-1:0} + P_{i-1:0}Cin Ci=Gi1:0+Pi1:0Cin

那么 C i C_i Ci 只和 G G G P P P 的前缀和有关系。有很多并行计算前缀和的结构,其中我们介绍Ladner-Fischer(LF)结构如下:

Ladner-Fischer
具体的,LF结构的层数是 log ⁡ 2 N \log_2N log2N 这里 N N N 是加法器的位数,我们将第一个元素下标记为 0 0 0 ,那么第 e e e层(从1开始)第 i i i个元素的值 g [ e ] [ i ] g[e][i] g[e][i] 代表:

g [ e ] [ i ] = G i : i & ∼ ( ( 1 < < e ) − 1 ) g[e][i] = G_{i:i \& \sim((1 << e)-1)} g[e][i]=Gi:i&((1<<e)1)

同理 p [ e ] [ i ] p[e][i] p[e][i] 也成立。

那么本位和就等于:

S [ i ] = A [ i ] ⊕ B [ i ] ⊕ C [ i ] S[i] = A[i] \oplus B[i] \oplus C[i] S[i]=A[i]B[i]C[i]

SystemVerilog代码实现:

module gp(input logic gh,input logic ph,input logic gl,input logic pl,output logic g,output logic p
);assign g = gh | ph & gl;assign p = ph & pl;
endmodulemodule padder(input logic[31:0] a,input logic[31:0] b,input logic cin,output logic[31:0] sum,output logic cout
);  genvar i;genvar j;genvar e;logic[31:0] g[5:0];logic[31:0] p[5:0];generatefor(i=0;i<32;i=i+1) beginassign g[0][i] = a[i] & b[i];assign p[0][i] = a[i] | b[i];endfor(e = 1;e < 6;e=e+1) beginfor(i=0;i< 32 / (1 << (e-1));i=i+1) beginif(i % 2 == 1) beginfor(j=i*(1 << (e-1));j<(i+1)*(1 << (e-1));j++) begingp gp_inst(g[e-1][j],p[e-1][j],g[e-1][i*(1 << (e-1)) - 1],p[e-1][i*(1 << (e-1)) - 1],g[e][j],p[e][j]);endendelse beginfor(j=i*(1 << (e-1));j<(i+1)*(1 << (e-1));j++) beginassign g[e][j] = g[e-1][j];assign p[e][j] = p[e-1][j];endendendendassign sum[0] = a[0] ^ b[0] ^ cin;for(i=1;i<32;i++) beginassign sum[i] = a[i] ^ b[i] ^ (g[5][i-1] | p[5][i-1] & cin);endassign cout = g[5][31] | p[5][31] & cin;endgenerate
endmodule

传播延迟为:

t P A = t p g + log ⁡ 2 N ( t p g p r e f i x ) + t X O R t_{PA} = t_{pg} + \log_2N(t_{pgprefix})+t_{XOR} tPA=tpg+log2N(tpgprefix)+tXOR

其中 t p g t_{pg} tpg 是计算一个 G i , P i G_i,P_i Gi,Pi 的时间, t p g p r e f i x t_{pgprefix} tpgprefix 是合并一个G和P的时间, t X O R t_{XOR} tXOR 是最后计算一个本位和的时间。

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

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

相关文章

经典神经网络(7)DenseNet及其在Fashion-MNIST数据集上的应用

经典神经网络(7)DenseNet及其在Fashion-MNIST数据集上的应用 1 DenseNet的简述 DenseNet不是通过更深或者更宽的结构&#xff0c;而是通过特征重用来提升网络的学习能力。 ResNet 的思想是&#xff1a;创建从“靠近输入的层” 到 “靠近输出的层” 的直连。而DenseNet 做得更…

python环境

卸载旧环境 wini 打开应用卸载 删除python解释器和pycharm 删除配置文件夹JetBrains C:\Users\CJC\AppData\Roaming\JetBrains 安装 安装python解释器 安装pycharm 查看或设置该项目的解释器和安装包 快捷键 全局搜索 双击shift 当前文件中搜索 ctrl f 查看函数…

【Linux】基础开发工具——yum篇

目录 &#x1f4d6;Linux下安装软件的三种方案&#x1f4f0;源代码安装&#x1f4f0;rpm安装&#x1f4f0;yum安装 &#x1f4d6;Linux软件包管理器yum&#x1f4f0;rz、sz&#x1f4f0;查看软件包&#x1f4f0;软件安装&#x1f4f0;软件删除 &#x1f4d6;yum源问题&#x1f…

如何查看 当前安装的vue版本

目录 1 实现 1 实现 要查看当前安装的 Vue 版本&#xff0c;可以使用以下方法&#xff1a; 在终端或命令提示符中运行以下命令&#xff1a; vue --version如果你使用的是 Vue CLI 创建的项目&#xff0c;可以在项目的根目录中找到 package.json 文件。在该文件中&#xff0c…

ChatGPT爆火 但生成式AI并非全新产物

以ChatGPT、Midjourney 为代表的 AIGC 产品横空出世&#xff0c;在全球掀起新一轮的 AI 技术变革新浪潮。近二十年来&#xff0c;我们见证了从「机器学习」算法到「深度学习」&#xff0c;再到「基础模型」的发展。随着数据量大规模膨胀&#xff0c;可扩展的算力&#xff0c;再…

机器学习26:《数据准备和特征工程-IV》数据转换

特征工程 是确定哪些特征可能对训练模型有用&#xff0c;然后通过转换日志文件等数据来源中的原始数据来创建这些特征的过程。在本文中&#xff0c;笔者将重点讨论何时以及如何转换数字和分类数据&#xff0c;以及不同方法的权衡。 目录 1.数据转换的原因 1.1 数据兼容性的强…

PPT文件,使用python删除链接

文章目录 一、需求二、处理方式三、代码实现 一、需求 如下图所示&#xff0c;将PPT文件中的链接进行删除&#xff0c;且不保留链接名。 原始文件&#xff1a; 处理后文件&#xff1a; 二、处理方式 使用python 的pptx模块进行处理&#xff0c;读取文字块&#xff0c;然后…

部署LVS+Keepalived高可用集群

目录 一、keepalived概述 1.1管理LVS负载均衡软件 1.2VRRP(Virtual Router Redundancy Protocol) 原理 二、keepalived服务的重要功能 2.1自动切换&#xff08;failover&#xff09; 2.2健康检查&#xff08;health checking&#xff09; 2.3高可用&#xff08;HA&#x…

决策树分析特征重要性可视化无监督特征筛选

from sklearn.tree import DecisionTreeClassifierdtc DecisionTreeClassifier() # 初始化 dtc.fit(x_train, y_train) # 训练# 获取特征权重值 weights dtc.feature_importances_ print(>>>特征权重值\n, weights)# 索引降序排列 sort_index np.argsort(weights…

idea goland 插件 struct to struct

go-struct-to-struct idea goland 插件。实现自动生成 struct 间 转换代码。 https://plugins.jetbrains.com/plugin/22196-struct-to-struct/ IntelliJ plugin that Automatically generate two struct transformations through function declarations Usage define func …

在当今这个信息时代,互联网中的隐私越来越重要,究竟是隐私换便利还是花钱护隐私呢?

一、互联网生存指南&#xff1a;通过哪些方法来加强个人信息保护&#xff1f; 网上注册内容时不要填写个人私密信息&#xff1a;互联网时代用户数和用户信息量已然和企业的盈利关联了起来&#xff0c;企业希望尽可能多地获取用户信息。但是很多企业在数据保护上所做的工作存在缺…

golang arena

go 1.20新特性 goland设置 Enviroment 定义环境变量 Go tool arguments 就是go build 的参数 Program arguments 启动参数 GOEXPERIMENTarenas -tags goexperiment.arenas //go:build goexperiment.arenaspackage mainimport ("arena""fmt""net/…