計數器是verilog編程中非常常用的一種技巧,但是我們如果是C等語言的編程思維則極有可能錯誤地使用計數器。下面舉個例子:
module delay (
input clk_sys, //系統時鐘
input rst_n,
output reg [31:0] time_cnt
);
parameter DELAY_TIME = 32'd50; //計數總時鐘個數
reg [31:0] time_cnt_r;
//組合電路,實現計數器自增1
always @(*) begin
if(time_cnt == DELAY_TIME)
time_cnt_r = 32'h1;
else
time_cnt_r = time_cnt_r + 1;
end
//時序電路,實現同步輸出到端口
always @(posedge clk_sys or negedge rst_n) begin
if(!rst_n)
time_cnt <= 32'h0;
else
time_cnt <= time_cnt_r;
end
endmodule
該模塊實現對系統時鐘的計數,計數到50個時鐘個數則清零重新開始計數。代碼中time_cnt_r = time_cnt_r + 1;
這條語句大家並不陌生,在C語言裏,典型的計數方式。
我們使用quartus編譯綜合得出的電路:
是不是感覺有點複雜。我們把代碼稍微變一下,把上面那條計數器自增1代碼改成:
time_cnt_r = time_cnt + 1;
再次編譯綜合,得到的RTL電路如下:
電路竟然變得如此簡潔,更重要的是節省了很多很多的buf資源:
仔細對比兩條計數器自增1代碼,發現區別在於:前面一個是計數器+1後賦值給自己,而後面一個是計數器+1後賦值給另外一個臨時計數器。
一個小小的改動,結果相差這麼大,值得深思。