在verilog中,实现边缘触发清零计数器时。综合的时候会有很多限制:
1、在多个always语句中,不能对同一个变量进行赋值。
2、如果在一个always条件加上两个边缘触发条件时,写法又似乎有一定的要求。
必须使用异步复位的方法清零,否则使用同步复位会因为赋值的延时带来一个时钟周期的延时。
反复试验得到一个勉强可以使用的代码如下:
- module counter(clk,rst,cnt_out,reset);
-
input clk,rst;
-
output cnt_out;
-
output reset;
-
reg rst_last/*synthesis noprune*/;
-
reg [7:0] cnt;
-
reg cnt_out;
-
reg reset;
-
wire mclk;
-
-
pll p0(clk,mclk);
-
-
initial
-
begin
-
cnt=255;
-
cnt_out=1;
-
end
-
-
always@(posedge mclk)
-
begin
-
rst_last=rst;
-
end
-
-
always@(posedge mclk or negedge rst)
-
begin
-
if(!rst)
-
begin
-
if(rst_last)
-
reset=0;
-
else
-
reset=1;
-
end
-
end
-
-
always@(posedge mclk or negedge reset)
-
begin
-
if(!reset)
-
cnt=0;
-
else if(cnt!=255)
-
cnt=cnt+1;
-
end
-
-
always@(cnt)
-
begin
-
if(cnt==255)
-
cnt_out=1;
-
else
-
cnt_out=0;
-
end
-
-
endmodule
在上述代码中rst为输入信号,下降沿时计数器清零。
此外设置了reset变量,reset在rst下降沿时置0,并保持一个周期。
计数器变量则捕捉reset的下降沿,并且在reset为0时清零。
最终达到rst下降沿时计数器立即清零的效果,signaltap得到的图如下:
从图中可以看到,rst下降时,cnt立即置0。但cnt的计数周期会增加一个时钟周期。
因为reset=1的赋值有一定的延时,而同时cnt取reset的值进行判断此时reset仍为0。硬件中的这种延时感觉真让人蛋疼...
阅读(5262) | 评论(0) | 转发(0) |