一、秒计数器
对于verilog执行顺序的理解(转载自这篇博文)
verilog主要的模块之间都是并行执行的,例如各个always之间 如果你在一个always中要对a赋值,而在另一个always中要使用a的值,这时候就要注意了,两者并行的,处理先后不能确定。 你当前处理的a,是这个时钟被赋值的还是上一时钟被赋值的,意义可能完全不同,这就是并行需要考虑的问题。
而在always内部,一般使用了begin…end。这里面的内容都是顺序执行的,比如b=a; c=b,先执行一条,再执行下一条,那就是c=a了 如果里面有两组if/else,就是先执行前一组,再执行后一组。但是如果是非阻塞,那就要特殊对待,多个非阻塞赋值是在一个块结束时一起执行的,比如b<=a; c<=b,那就跟之前不同了,当执行c<=b 时b还没有变化成a的值,因此 这个赋值的结果是b被赋值前的值,这两条语句其实是独立的、并行的。好处是放得先后顺序没关系,只要在一个块内,随便写。这个不是很好理解,怎么说了begin…end之间是顺序,到了非阻塞就又变成并行执行的呢。 不好理解也没办法, 另外掌握几条原则:组合逻辑用阻塞赋值,时序逻辑用非阻塞赋值,同一个模块中不要既用阻塞又用非阻塞…
掌握一条思路:verilog是硬件,是电路。所以调试的时候不能设置断点 所以所有模块都是并行,毕竟一上电整个板子都有电了,你不能说让它没电就没电,但是你可以在代码中加个控制,让它到了特定时候才干活。
看完上面的就知道为啥run-all会让s_num加1(明明没有到1s,却自增了1)
verilog代码:
//2023/3/29 lzp
//秒计数器 0-9循环, 24M HZ
`timescale 1ns/10ps
module s_counter(clk, res, s_num);
input clk, res;
output[3:0] s_num; //输出的秒\
parameter frequency_clk=24; //24M Hz;
reg[3:0] s_num;
reg[24:0] con_t; //24M可以用25位2机制数来存,秒脉冲分频计数器;
reg s_pulse; //秒脉冲尖;
always@(posedge clk or negedge res) begin
//计数
if(~res) begin
con_t<=0;
s_pulse<=0;
s_num<=0;
end
else begin
if(con_t == frequency_clk*1000000-1) begin
con_t<=0;
end
else begin
con_t<=con_t+1;
end
//脉冲尖
if(con_t==0) begin
s_pulse<=1;
end
else begin
s_pulse<=0;
end
//秒自增
if(s_pulse) begin
if(s_num == 9) begin
s_num<=0;
end
else begin
s_num<=s_num+1;
end
end
end
end
endmodule
//秒计数器,testbench
module s_counter_tb;
reg clk, res;
wire[3:0] s_num;
s_counter s_counter(.clk(clk), .res(res), .s_num(s_num));
initial begin
clk<=0;
res<=0;
#10;
res<=1;
#1000;
$stop;
end
always#(5) clk=~clk;
endmodule