计数器是Verilog中最基本的时序电路,在计数器的基础上可以设计时钟分频器
module counter10(clk,clr,load,en,data,q,count_flag);
input clk;
input clr;
input load;
input en;
input[3:0] data;
output reg[3:0] q;
output reg count_flag;
always@(posedge clk)
if(clr)
q <= 0;
else if(load == 1'b1)
q <= data;
else if(en == 1'b1) begin
if(q == 9 )
q <= 0;
else
q <= q + 1;
end
always@(q) begin //该电路将时序逻辑部分和组合逻辑部分分开设计,是一种很正规的写法
if(q == 9) // 第一个always块中是时序逻辑,在第二个always块中是组合逻辑,
count_flag <= 1; //这样的写法有利于综合
else
count_flag <= 0;
end
endmodule
以下内容为testbench内容:
`timescale 1ns/1ns
module count10_tb;
reg clk;
reg clr;
reg load;
reg en;
reg[3:0] data;
wire[3:0] q;
wire count_flag;
counter10 count(clk,clr,load,en,data,q,count_flag);
initial clk = 0 ;
always #5 clk = ~clk;
initial begin
clr = 0;
load = 1;
en = 1;
data = 4'b0101;
end
initial #100 load = 0;
initial #20 load = 1; // 这里的initial各条语句是并发执行的,基准的时间点是0;
initial #20 load = 0;
initial #40 clr = 1;
initial #80 clr = 0;
endmodule
modelsim6.5 b 中的仿真波形:
在设计中会想到将两个always模块进行合并写到一个always模块中,程序代码如下:
module counter10_2(clk,clr,load,en,data,q,count);
input clk;
input clr;
input load;
input en;
input[3:0] data;
output reg[3:0] q;
output reg count;
always@(posedge clk) begin
if(clr)
q <= 0 ;
else if(load)
q <= data;
else if(en) begin
if(q == 9) begin
q <= 0;
count <= 1;
end
else begin
q <= q + 1;
count <= 0;
end
end
end
endmodule
程序代码看上去没有问题,当q ==9 时,q 再次变为0 ,count_flag变为1,然而在仿真中出现的问题一目了然:
这里count_flag会延迟一个时钟得到
但在循时序电路内,就有两个要考虑:
1.使用的是non-blocking,所以q <= 0和cout_flag <= 1一起执行。
2.因为是循序电路,所以q <= 0和 cout <_flag= 1并不会马上有结果,必须等到下一个clock才出现。
所以在ModelSim的模拟,我们看到{q等于0和cout_flag等于1}同时在下一个clock时出现,所以若要cout_flag马上等于1,就不能用循序电路,而要改用组合电路,这样就会马上等于1,所以用另外一个always block来表示这个组合电路的结果才正确。 |