关于四位计数器的设计,阻塞式与非阻塞式赋值引发的问题
2015-04-20 16:11
627 查看
1、今天,从教材中学了两种可综合的四位计术器的设计方法,先附上代码吧。
(1)、建模:
方法一:
module counter1(out,cout,data,load,cin,clk);
input [3:0]data;
input load,cin,clk;
output cout;
output [3:0]out;
reg [3:0]out;
always @(posedge clk)
if(load)
out<=data;
else
out<=out+cin;
assign cout=&out&cin;
endmodule
方法二:
module counter2(preout,out,cout,data,load,cin,clk);
input [3:0]data;
input load,cin,clk;
output cout;
output [3:0]out,preout;
reg [3:0]out;
reg cout;
reg [3:0]preout;
//preout起到一种监控作用,是我自己添加的。
always @(posedge clk)
begin
out<=preout;
end
always @(out,data,load,cin)
begin
{cout,preout}=out+cin;
if(load)
preout=data;
end
endmodule
(2)、testbench:
`include "counter2.v"
module counter_stimulus;
reg load,cin,clk;
reg [3:0]data;
wire [3:0] out;
wire cout;
counter2 ct(out,cout,data,load,cin,clk);
initial
begin
clk=1;
forever #5 clk=~clk;
end
initial
begin
data=4'd5;
cin=0;
load=1;
#5 load=0;
#10 cin=1;
end
endmodule
(3)、仿真效果图:
2、下面我来说说,出现的问题,第一次仿真时,仿真结果如下图(1):其中,out和cout的值都是红线,不确定值,于是我在counter2的代码中,添加了preout作为输出变量,仿真便出现了图(2)的仿真效果:
图(1)
图(2)
由图(2)可知,当上升沿到来前,load变成0,preout变成了未知值,除都非,我在仿真模块中把load前10ns的值设置为1,让preout一直为1,才能保证后面时刻仿真正确。
后来分析,发现问题就出现在阻塞和非阻塞的赋值方式上,因为在错误代码中,我对preout使用了非阻塞式赋值,如下图,而在正确代码中,我采取的是阻塞式。具体,阻塞式和非阻塞式的区别,还要在后面的学习中,继续巩固学习。在此,我只明白,问题出在这,但不能说出个所以然来。
3、此部分是后续添加的,在学习过阻塞式及非阻塞式赋值后来解决第二部分所出现的问题。看上面图片的代码,第一个always过程块表示一个时序电路,采用非阻塞式赋值肯定没有问题。但第二个always过程表示一个组合逻辑,不适合采用非阻塞式赋值,这是因为当load值变化为1时,preout置为data,即为0101,这个没错,但当load为0时,就只执行{count,preout}<=out+cin;而这个非阻塞赋值等号右边参与运算的是out的初始值,而out的初始值为未知值x,因此,cout和preout保持为未知值x。采用阻塞式的仿真图如下:值得特别注意的是,当always过程块表示一个时序电路时,过程块中的赋值必须为非阻塞式赋值,而当always过程块表示一个组合逻辑时,过程块中的赋值必须为阻塞式赋值。
(1)、建模:
方法一:
module counter1(out,cout,data,load,cin,clk);
input [3:0]data;
input load,cin,clk;
output cout;
output [3:0]out;
reg [3:0]out;
always @(posedge clk)
if(load)
out<=data;
else
out<=out+cin;
assign cout=&out&cin;
endmodule
方法二:
module counter2(preout,out,cout,data,load,cin,clk);
input [3:0]data;
input load,cin,clk;
output cout;
output [3:0]out,preout;
reg [3:0]out;
reg cout;
reg [3:0]preout;
//preout起到一种监控作用,是我自己添加的。
always @(posedge clk)
begin
out<=preout;
end
always @(out,data,load,cin)
begin
{cout,preout}=out+cin;
if(load)
preout=data;
end
endmodule
(2)、testbench:
`include "counter2.v"
module counter_stimulus;
reg load,cin,clk;
reg [3:0]data;
wire [3:0] out;
wire cout;
counter2 ct(out,cout,data,load,cin,clk);
initial
begin
clk=1;
forever #5 clk=~clk;
end
initial
begin
data=4'd5;
cin=0;
load=1;
#5 load=0;
#10 cin=1;
end
endmodule
(3)、仿真效果图:
2、下面我来说说,出现的问题,第一次仿真时,仿真结果如下图(1):其中,out和cout的值都是红线,不确定值,于是我在counter2的代码中,添加了preout作为输出变量,仿真便出现了图(2)的仿真效果:
图(1)
图(2)
由图(2)可知,当上升沿到来前,load变成0,preout变成了未知值,除都非,我在仿真模块中把load前10ns的值设置为1,让preout一直为1,才能保证后面时刻仿真正确。
后来分析,发现问题就出现在阻塞和非阻塞的赋值方式上,因为在错误代码中,我对preout使用了非阻塞式赋值,如下图,而在正确代码中,我采取的是阻塞式。具体,阻塞式和非阻塞式的区别,还要在后面的学习中,继续巩固学习。在此,我只明白,问题出在这,但不能说出个所以然来。
3、此部分是后续添加的,在学习过阻塞式及非阻塞式赋值后来解决第二部分所出现的问题。看上面图片的代码,第一个always过程块表示一个时序电路,采用非阻塞式赋值肯定没有问题。但第二个always过程表示一个组合逻辑,不适合采用非阻塞式赋值,这是因为当load值变化为1时,preout置为data,即为0101,这个没错,但当load为0时,就只执行{count,preout}<=out+cin;而这个非阻塞赋值等号右边参与运算的是out的初始值,而out的初始值为未知值x,因此,cout和preout保持为未知值x。采用阻塞式的仿真图如下:值得特别注意的是,当always过程块表示一个时序电路时,过程块中的赋值必须为非阻塞式赋值,而当always过程块表示一个组合逻辑时,过程块中的赋值必须为阻塞式赋值。
相关文章推荐
- JavaScript给input的value赋值引发的关于基本类型值和引用类型值问题
- 一个讨论引发关于js中函数声明,函数表达式,形参与变量声明赋值引发的一些事(http://www.cnblogs.com/zhouyongtao/archive/2012/11/22/2783089)
- 关于不同数据类型之间赋值的问题
- 关于修改以太网帧头类型字段引发的问题
- 关于ajax回调无法给全局变量赋值的问题
- 关于为c++类中的变量赋值的问题
- 关于final变量的赋值问题
- 关于提交文件和提交图片时可能引发的安全问题和解决方法
- 关于c语言的赋值和memcpy的问题
- 黑马程序员——java中关于单例设计模式和懒汉式多调用的问题
- 关于网络心跳与磁盘心跳超时多久会引发节点重启的问题
- 一个关于指针间赋值及间接求值的问题
- [全程建模]关于建模技术中界面层开发设计的问题
- 关于使用eventbus引发的NoClassDefFoundError问题解决方案
- 字段类型设计与实际业务不符引发的问题2
- 《关于我们-合作》页面设计问题
- 关于UI设计你需要自问的10 个问题
- 关于java中子父类赋值的问题
- 由一个问题引发的思考——关于数据库的外键约束
- 关于开关电源PCB设计中存在的问题