Verilog一例(同步與異步時序) 問題
頂層模塊有一個50MHz時鐘輸入(使用testbench實現(xiàn)),一個8位信號輸出。
有一個容量為90的8位RAM子模塊,每個時鐘上升沿,RAM根據(jù)8位地址線,輸出對應的數(shù)據(jù)。
頂層模塊在每100個時鐘周期里,前10個時鐘周期信號無效,輸出為0;后面90個時鐘周期,輸出值分別為RAM中地址0~89的數(shù)據(jù)。
代碼實現(xiàn) RAM子模塊
module ram( ? ?input clk, ? ?input [7:0] addr, ? ?output reg [7:0] data);always @(posedge clk) begin ? ?data <= addr;endendmodule頂層模塊
module sync_async();// 50MHz時鐘 testbenchreg clk = 0;always #10 clk = ~clk;// 0~99循環(huán)計數(shù)器reg [7:0] cnt = 0;always @(posedge clk) begin ? ?if(cnt == 99) ? ? ? ?cnt <= 0; ? ?else ? ? ? ?cnt <= cnt + 1;end// 數(shù)據(jù)有效wire valid;assign valid = cnt >= 10;// 地址線wire [7:0] addr;assign addr = cnt - 10;// 調用子模塊,讀取ram數(shù)據(jù)wire [7:0] ramdata;ram ram1(clk, addr, ramdata);// 輸出wire [7:0] out;assign out = valid ? ramdata : 0;endmodule仿真與分析
一眼看上去,好像程序是沒有問題的。
使用軟件進行仿真后的時序圖如下。
從仿真波形就看出問題來了。當cnt=0~9的時候,輸出都是out=0沒有問題。但是當cnt=10的時候,輸出變成了255。之后所有的數(shù)據(jù)都滯后了一個時鐘周期。
原因在于代碼中的同步異步設計不協(xié)調。
代碼中,RAM子模塊是上升沿觸發(fā)并且同步輸出的(這樣也比較符合正常的RAM結構),而不是直接由組合邏輯電路實現(xiàn)。如果直接將assign
addr = cnt - 10作為RAM的地址線,RAM的輸出相對于addr和cnt的值會滯后一個周期。也就是說,當RAM輸出地址為0的數(shù)據(jù)時,實際上addr的值已經(jīng)是1了。
在RAM模塊的always語句中(
always @(posedge clk) data <= addr;),使用同步賦值操作data <= addr在時鐘上升沿時觸發(fā),上升沿結束后data輸出的值,為上升沿前一瞬間addr的值。
而另一方面,valid變量卻使用的是直接異步賦值,相比cnt,不會有滯后。
于是在cnt==10的時候,valid已經(jīng)變成1,而RAM還沒有輸出地址為0的數(shù)據(jù),所以發(fā)生了與設計不相符的問題。
解決方法
一種比較容易想到的方法是,將valid信號的跳變,也設計成和RAM一樣的上升沿同步觸發(fā)。即將
// 數(shù)據(jù)有效wire valid;assign valid = cnt >= 10;
改為
// 數(shù)據(jù)有效reg valid = 0;always @(posedge clk) begin ? ?valid = cnt >= 10;end
修改正確后的仿真波形如下圖,可以看出valid信號和RAM信號相對于cnt,都滯后了一個周期。從而實現(xiàn)了問題中給出的要求。





