赞
踩
概要:加减乘除是人类使用的最基本的数学运算。现代计算机的发明之前,人们只能通过纸笔进行运算,效率有限;随着计算机的出现,运算速度几何倍增。在现在的编程语言中,我们只需要输入一个“+”,硬件设备会自动进行加法计算。但加法到底是如和通过硬件来实现的,虽然很底层,但我觉得还是有必要了解一下。
本篇博客就加法器的一种实现方式进行简单介绍——行波进位加法器(也可以叫波纹进位加法器,脉动进位加法器)
说到加法器(通常说的加法器应该指的是全加器),就得从半加器说起。半加器的门级原理图及真值表如下图所示:半加器的目的是实现两个一位的二进制数的加法,也就是实现0与1的加法。但其无法进行超过1位二进制数的加法,所以才有全加器的出现。
一、半加器的实现
根据半加器的门级电路图,我们可以使用Verilog语言将其描述出来
- /**********************************************
- * @Module function : 半加器
- * Description : 实现两个一位二进制数的相加
- * @Author : Akeng
- * @Date 2024/01/07 13:10:39
- * @logic { }
- * @repair
- * @version : 1.0.0
- **********************************************/
-
- module half_adder (
- input wire a,
- input wire b,
- output reg c,
- output reg s,
- output wire [1:0] sum
- );
-
- always @( *) begin
- c = a & b;
- s = a ^ b;
- end
-
- assign sum = {c,s};
-
- endmodule //half_adder
二、单bit全加器的实现
全加器由两个半加器构成,如下图所示:
根据全加器的门级电路图,用代码描述如下:(该全加器现在可以进行进位的处理,要实现多bit的全加器可以将多个单bit全加器级联)
- /**********************************************
- * @Module function : 全加器
- * Description : 1bit加法器
- * @Author : Akeng
- * @Date 2024/01/07 22:08:14
- * @logic { }
- * @repair
- * @version : 1.0.0
- **********************************************/
-
- module full_adder (
- input wire a ,
- input wire b ,
- input wire cin ,
- output wire s ,
- output wire cout
- // output wire sum
- );
-
- assign s = a ^ b ^ cin;
- assign cout = ((a ^ b) & cin) | (a & b);
-
- // assign sum = {cout,s};
-
- endmodule //full_adder
三、4-bit全加器的实现
如上图为4-bit的行波进位加法器的结构图,根据结构图,可以得到相应的门级电路图,如下:
在代码实现中,只需将单bit的全加器例化4次,使用中间信号将其连接起来即可:
- module full_adder_4bit (
- input wire [3:0] a ,
- input wire [3:0] b ,
- input wire [0:0] cin ,
- output wire [3:0] s ,
- output wire [0:0] cout ,
- output wire [4:0] sum
- );
-
- wire [3:0] c;
-
- full_adder add_0(
- /* input wire */ .a (a[0] ) ,
- /* input wire */ .b (b[0] ) ,
- /* input wire */ .cin (cin ) ,
- /* output wire */ .s (s[0] ) ,
- /* output wire */ .cout(c[0] )
- // /* output wire */ .sum (sum[0])
- );
-
- full_adder add_1(
- /* input wire */ .a (a[1] ) ,
- /* input wire */ .b (b[1] ) ,
- /* input wire */ .cin (c[0] ) ,
- /* output wire */ .s (s[1] ) ,
- /* output wire */ .cout(c[1] )
- // /* output wire */ .sum (sum[1])
- );
-
- full_adder add_2(
- /* input wire */ .a (a[2] ) ,
- /* input wire */ .b (b[2] ) ,
- /* input wire */ .cin (c[1] ) ,
- /* output wire */ .s (s[2] ) ,
- /* output wire */ .cout(c[2] )
- // /* output wire */ .sum (sum[2])
- );
-
- full_adder add_3(
- /* input wire */ .a (a[3] ) ,
- /* input wire */ .b (b[3] ) ,
- /* input wire */ .cin (c[2] ) ,
- /* output wire */ .s (s[3] ) ,
- /* output wire */ .cout(cout )
- // /* output wire */ .sum (sum[3])
- );
-
- assign sum = {cout, s};
-
- endmodule //full_adder
通过编写仿真测试对其进行功能行检测,testbench代码如下:
- `timescale 1ns/1ns
-
- module tb_full_adder ();
-
- reg [3:0] a ;
- reg [3:0] b ;
- reg cin ;
- wire[3:0] s ;
- wire cout ;
- wire[4:0] sum ;
-
- /* full_adder full_adder(
- .a (a ) ,
- .b (b ) ,
- .cin (cin ) ,
- .s (s ) ,
- .cout(cout) ,
- .sum (sum )
- ); */
-
- full_adder_4bit full_adder_4bit(
- /* input wire [3:0] */ .a (a ) ,
- /* input wire [3:0] */ .b (b ) ,
- /* input wire [0:0] */ .cin (cin ) ,
- /* output wire [3:0] */ .s (s ) ,
- /* output wire [0:0] */ .cout(cout) ,
- /* output wire [4:0] */ .sum (sum )
- );
-
- initial begin
- a = 4'b0000;
- b = 4'b0000;
- cin = 1'b0;
- #100;
- $stop;
- end
-
- always #10 a <= {$random} % 16;
- always #10 b <= {$random} % 16;
- always #8 cin <= {$random} % 2;
-
-
- endmodule //tb_full_adder
通过MdelSim仿真可以看到功能得到实现
四、Vivado分析
使用Vivado进行RTL分析后,可以看到其RTL级视图如下
展开其中一个add模块,可以看到,其门级电路与我们前面分析的完全一样
当然,最后也可以上板玩一下,使用按键与led观察输入输出……
五、总结
以上只是全加器的一种实现方式,使用行波进位的方法来实现,这中方法最大的缺点是延时大,随着两个加数的位宽的增大,其得到最终结果的时间也随之增大,因为下一位的结果依赖前一位的进位输出。为了优化性能,工程师设计了超前进位加法器(以后由兴趣在深入了解吧)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。