用Verilog语言描述32位全加器。使用数据级先描述4位全加器,之后通过模块的实例化实现32位全加器!

在Verilog语言中,使用数据流级描述32位全加器。

设计思路

首先,使用数据流级描述4位全加器,把本次设计的代码与之前设计的4位全加器的门级描述进行对比。观察结果!
之后,通过实例化4位全加器的数据流级描述,最终实现32位全加器。

数据流级语言的简单介绍

定义:数据流级是根据数据在寄存器之间的流动和处理过程对电路进行描述。(标准的定义)
我对概念的理解:首先比数据流级低一个级别的描述方法是门级建模,这种方式虽然可以明确知道电路的组成,但是对于设计者来说,如果设计一个稍微复杂的电路,将会大大提高工作难度和错误率。这完全无法体现HDL(hardware description language)的优越性,所以有必要出现一种比门级建模更适合设计者使用的设计方法。数据流级建模的好处是只需要思考数据在每个部分的流动是什么样子的就可以了,不需要考虑其内部结构。
注:每个级别的建模方式各有优缺点,“适合”的建模方式就是最合适的。

4位全加器的数据流建模

在数据流级编写代码时,要用到一个语句,这个语句被称为连续赋值语句(assign)。语句格式如下:
assign 线网信号 = 运算表达式;
这里的线网信号要注意必须是wire型。这个语句表达式的直观理解就是把运算表达式的结果赋给线网信号。一旦等号右边的信号发生变化,等号左边的信号便会立刻发生变化。这种特点在数字电路中就是组合逻辑电路。

4位全加器数据流建模代码

module add_4_s (a,b,cin,cout,sum);
input	[3:0]	a,b;
input		cin;
output		cout;
output	[3:0]	sum;

assign	{
    
    cout,sum}=a+b+cin;
endmodule

此模块测试代码

在测试模块编写中,有两种赋值方法。一种是这次使用的单个值手动输入特定的值,一种是之后的随机数赋值。如果随机数赋值不太懂的,也可以使用手动输入的方法。各取所需即可。

module add_4_s_tb;
reg	[3:0]	a,b;
reg		cin;
wire		cout;
wire	[3:0]	sum;
add_4_s t1 (a,b,cin,cout,sum);
initial
begin
	a=0;b=0;cin=0;
#10	a=0;b=0;cin=1;
#10	a=0;b=1;cin=0;
#10	a=0;b=1;cin=1;
#10	a=1;b=0;cin=0;
#10	a=1;b=0;cin=1;
#10	a=1;b=1;cin=0;
#10	a=1;b=1;cin=1;
#10	a=10;b=0;cin=1;
#10	a=0;b=14;cin=1;
#10	a=5;b=1;cin=1;
#10	a=15;b=0;cin=0;
#10	a=14;b=13;cin=1;
#10	a=15;b=15;cin=1;
#10	a=12;b=1;cin=1;
#10	$stop;
end

initial	$monitor($realtime,"\ta=%d\tb=%d\tcin=%d\t\t\tcout=%d\tsum=%d",a[3:0],b[3:0],cin,cout,sum[3:0]);
endmodule

结果

波形图波形图
Transcript窗口结果
在这里插入图片描述
相比之下,至少是这次的比较。采用Transcript窗口显示结果是比较直观的。当然,并不是所有的结果都可以采用这种方式显示结果。这点以后会涉及到。

4位全加器门级建模和数据流建模仿真结果比较

代码:

只提供仿真代码(设计思路、设计代码见上一篇博客)
仿真代码采用随机赋值的方式赋值;端口连接方式是顺序端口连接。这种连接方式必须与模块的端口一一对应,常见于简单的设计。

module add_4_tb;
//module add_4_m (a,b,cin,cout,sum);
//module add_4_s (a,b,cin,cout,sum);
reg	[3:0]	a,b;
reg		cin;
wire		cout1,cout2;
wire	[3:0]	sum1,sum2;
add_4_m t1 (a,b,cin,cout1,sum1);
add_4_s t2 (a,b,cin,cout2,sum2);
integer seed1,seed2,seed3;
initial
begin
	seed1=1;seed2=2;seed3=3;
	a=0;b=0;cin=0;
	repeat(10)
		begin
		#10	a=($random(seed1)/16);b=($random(seed2)/16);cin=($random(seed3)/2);
		end
	#10	$stop;
end

initial	$monitor($realtime,"\ta=%d\tb=%d\tcin=%d\t\t\tcout1=%d\tcout2=%d\tsum1=%d\tsum2=%d",a[3:0],b[3:0],cin,cout1,cout2,sum1[3:0],sum2[3:0]);
endmodule

结果

在这里插入图片描述
比较两个加法器结果一样,说明设计没有什么问题。

8位全加器的数据流建模

设计思路:通过调用2个4位全加器的数据流建模,实现8位数据流设计。
模块实例化(模块调用):模块实例化的语法结构如下 模块名称 实例名称(端口连接);
端口连接有两种方式,一种是顺序端口连接,另一种是命名端口连接。具体使用方法见之后的例子。

8位全加器设计代码:

模块实例化的方式采用命定端口连接,实例化两个4位全加器,把输入和输出分为低位和高位,低位的cout是高位的cin。至于命名端口连接的优点是不需要考虑端口的摆放顺序,而且一旦实例化的模块比较多,这样不至于混淆到底哪一个端口和哪一个端口相连的问题。命名端口使得端口连接更加清晰明了。

module add_8_s (a,b,cin,cout,sum);
input	[7:0]	a,b;
input		cin;
output	[7:0]	sum;
output		cout;
wire		c;
add_4_s u1 (.a(a[3:0]),.b(b[3:0]),.cin(cin),.cout(c),.sum(sum[3:0]));
add_4_s u2 (.a(a[7:4]),.b(b[7:4]),.cin(c),.cout(cout),.sum(sum[7:4]));
endmodule

此模块仿真代码:

module add_8_tb;
reg	[7:0]	a,b;
reg		cin;
wire		cout1;
wire	[7:0]	sum1;
add_8_s t1 (a,b,cin,cout1,sum1);
integer seed1,seed2,seed3;
initial
begin
	seed1=1;seed2=2;seed3=3;
	a=0;b=0;cin=0;
	repeat(10)
		begin
		#10	a=($random(seed1)/256);b=($random(seed2)/256);cin=($random(seed3)/2);
		end
	#10	$stop;
end

initial	$monitor($realtime,"\ta=%d\tb=%d\tcin=%d\t\t\tcout1=%d\tsum1=%d",a[7:0],b[7:0],cin,cout1,sum1[7:0]);
endmodule

结果

在这里插入图片描述

32位全加器设计

设计思路:直接把8位全加器实例化4次构成32位全加器。思路和把4位全加器连接成8位全加器的思路是一致的。

扫描二维码关注公众号,回复: 11650965 查看本文章

32位全加器设计代码:

module add_32_s (a,b,cin,cout,sum);
input	[31:0]	a,b;
input		cin;
output	[31:0]	sum;
output		cout;
wire	[2:0]	c;
add_8_s u1 (.a(a[7:0]),.b(b[7:0]),.cin(cin),.cout(c[0]),.sum(sum[7:0]));
add_8_s u2 (.a(a[15:8]),.b(b[15:8]),.cin(c[0]),.cout(c[1]),.sum(sum[15:8]));
add_8_s u3 (.a(a[23:16]),.b(b[23:16]),.cin(c[1]),.cout(c[2]),.sum(sum[23:16]));
add_8_s u4 (.a(a[31:24]),.b(b[31:24]),.cin(c[2]),.cout(cout),.sum(sum[31:24]));
endmodule

此模块仿真代码:

module add_32_tb;
reg	[31:0]	a,b;
reg		cin;
wire		cout1;
wire	[31:0]	sum1;
add_32_s t1 (a,b,cin,cout1,sum1);
integer seed1,seed2,seed3;
initial
begin
	seed1=1;seed2=2;seed3=3;
	a=0;b=0;cin=0;
	repeat(10)
		begin
		#10	a=($random(seed1)/4294967295);b=($random(seed2)/4294967295);cin=($random(seed3)/2);
		end
	#10	$stop;
end

initial	$monitor($realtime,"\ta=%d\tb=%d\tcin=%d\t\t\tcout1=%d\tsum1=%d",a[31:0],b[31:0],cin,cout1,sum1[31:0]);
endmodule

结果

在这里插入图片描述

总结

到此为止,32位全加器的设计就暂且告一段落。这篇博客的主要内容就是介绍为什么要使用数据流设计电路,这样做的好处是什么;数据流建模的风格;模块实例化的方法。有关随机赋值的内容,这个本来是属于测试总结时候想写的,可是想到这个以后用的比较多,就一会附加一旦内容吧。

预告

既然门级建模和数据流建模都编写了代码,这样下一篇博客介绍一下行为级建模。

附加

有关随机数赋值的内容。语句random,具体使用方法见实际例子。
在这里插入图片描述
第7行:定义三个随机变量种子,每个种子用于一个数的赋值,这里需要给三个数赋值,所以定义三个随机数。
第10行:给种子赋值,必须要赋不一样的值。
第12行-第15行:采用循环,把循环内的语句执行10次;这个就是random的使用方法,16代表0-15。
在这里插入图片描述第14行:里面的256代表0-255;2代表0和1。
以此类推,目前这些也够理解这个测试代码。

感想

继续加油,自我鼓励!

猜你喜欢

转载自blog.csdn.net/yixiaoyaobd/article/details/107803879