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