Verilog基本语法学习笔记
两个重要的基本类型
类型 | 说明 |
---|---|
wire | wire就是数字电路中的信号线 |
reg | reg就是数字电路中的D触发器 |
从这个地方就可以明显看出两个类型的区别了,这也是为什么有以下的语句
module a_and_b(
input wire a,
input wire b,
output wire c,
output reg d
);
assign c = a & b;
always @(posedge clk)
d <= a & b;
endmodule
上面的模块中,c作为一根输出的线,说白了,就是 a 和 b 这两根线连到了与门的输入端,然后 c 连到了输出端
而在下面的代码中
always @(posedge clk)
d <= a & b;
d是一个D触发器,clk作为了D触发器的时钟,连接到了d触发器上,a 和 b 连了个与门,然后将与门的输出接到了触发器D的数据输入端上。
从上面,就可以看出,在Verilog中,always中的赋值语句中的被赋值变量(例如 d )只能是reg类型的,因为,它还要接时钟呢(虽然,always也可以综合出组合逻辑,通过一些写法让综合器把触发器给优化掉,但笔者不建议这么写)
激励文件(TestBench)的注意事项
出现这种情况,主要是如何利用Modelsim仿真软件的问题。假设对a_and_b模块进行如下仿真:
module tb_test();
reg clk;
reg rst_n;
reg a,b;
wire cr,dr;
a_and_b ab(
.clk(clk),
.rst_n(rst_n),
.a(a),
.b(b),
.c(cr),
.d(dr)
);
initial begin
clk =0;
rst_n =0;
a ={$random}; // 这一行
b ={$random}; // 还有这一行,是有问题的
#20
rst_n =1;
end
always #5 clk = ~clk;
always #10 a ={$random};
always #15 b ={$random};
endmodule
就会得到这样的结果:
这张图是明显不对的,因为它根本不能反映D触发器的特性,在画红圈的地方,D触发器在时钟上升的时候,应该只能读到这一时刻之前的值,但这张图上,它却跟着组合逻辑一起跳变了
为了让仿真的结果更加正常,可以使用如下方案:
module tb_test();
reg clk;
reg rst_n;
reg a,b;
// 这里的输出,只能是wire
wire cr,dr;
wire[7:0] numr;
a_and_b ab(
.clk(clk),
.rst_n(rst_n),
.a(a),
.b(b),
.num(numr),
.c(cr),
.d(dr)
);
initial begin
clk =0;
rst_n <=0;
a <={$random};
b <={$random};
#20
rst_n <=1;
end
always #5 clk = ~clk;
always #10 a <={$random}; //这儿改成非阻塞赋值
always #15 b <={$random};
endmodule
两个激励文件的唯一区别是,后者的除了时钟信号意外,其他的所有信号都是阻塞式赋值,这样,在仿真的时候,可以将它们的赋值稍慢时钟一点。这个程序得到的结果是: