58 / 63 · 概念
FIFO、記憶體驗證計畫與獨立 scoreboard
編寫不依賴實作指標的 queue scoreboard,將邊界、reset、valid 與未初始化讀取納入驗證計畫。
單元可免費閱讀,註冊課程即可儲存學習進度。
產生答案的模型應不同於 DUT
驗證器將契約所定的預期行為與 DUT 比較。若複製 FIFOFIFO是先進先出的佇列。滿、空,以及是否允許同時讀寫的規則,都是行為契約的一部分。 詳細內容 的 rptr、wptr 計算答案,可能重現同一指標錯誤。獨立 scoreboardScoreboard是驗證環境中的參考狀態,用來依序比對預期資料與實際輸出。應獨立計算,不能直接複製實作的內部狀態。 以 SystemVerilog queue 只保存邏輯順序:接受 push 加尾端,接受 pop 取前端。
驗證計畫列出狀態與請求交叉組合:empty/中間/full 各檢查無請求、只 push、只 pop、同時請求,再加反覆回捲、連續 pop、仍有資料時 reset。記錄各案例是否觀察過,保留亂數 seed 與失敗輸入以重現。
預期接受條件依 queue 舊大小 計算,不依 DUT full 或 occupancy。
先取舊 head 再接新資料,保留 full 同時請求的原頭部。只有預期 時才比較 dout。
完整測試平台
以下是與上一堂 fifo4 一起編譯的完整測試平台,屬於使用延遲與 queue 的驗證程式。輸入在下降緣改變,上升緣 1 ps 後比較 DUT 的 nonblocking非阻塞賦值(nonblocking)在循序 RTL 中以 <= 表示。它先求右側運算式的值,再排程更新,讓同一邊緣的暫存器都能依據先前狀態計算。 詳細內容 更新結果。
module tb_fifo4;
timeunit 1ns;
timeprecision 1ps;
typedef logic [7:0] word_t;
logic clk=0, rst=1, push=0, pop=0;
word_t din=0, dout;
logic dout_valid, full, empty;
logic [2:0] occupancy;
word_t model[$], expected;
bit expect_pop, expect_push;
fifo4 dut (.*);
always #5ns clk = ~clk;
always @(posedge clk) begin
if (rst) begin
model.delete();
expect_pop = 0;
end else begin
expect_pop = pop && (model.size() != 0);
expect_push = push && ((model.size() < 4) || expect_pop);
if (expect_pop) expected = model.pop_front();
if (expect_push) model.push_back(din);
end
#1ps;
assert (dout_valid === expect_pop)
else $fatal(1, "valid mismatch");
if (expect_pop)
assert (dout === expected)
else $fatal(1, "data mismatch");
assert (int'(occupancy) === model.size())
else $fatal(1, "count mismatch");
assert (empty === (model.size() == 0))
else $fatal(1, "empty mismatch");
assert (full === (model.size() == 4))
else $fatal(1, "full mismatch");
end
task automatic step(input bit r, p, o, input word_t d);
@(negedge clk);
rst=r; push=p; pop=o; din=d;
endtask
initial begin
step(0,0,1,0);
step(0,1,1,8'hA0);
for (int i=1; i<4; i++)
step(0,1,0,word_t'(160+i));
step(0,1,0,8'hEE);
step(0,1,1,8'hB0);
repeat (5) step(0,0,1,0);
repeat (3) begin
for (int i=0; i<4; i++) step(0,1,0,word_t'(i));
repeat (4) step(0,0,1,0);
end
step(0,1,0,8'h5A);
step(1,1,1,8'hFF);
step(0,0,1,0);
repeat (100)
step(0,bit'($urandom_range(1,0)),bit'($urandom_range(1,0)),
word_t'($urandom));
repeat (4) step(0,0,1,0);
@(negedge clk);
$display("PASS");
$finish;
end
endmodule第一個上升緣 rst=1,清空 DUT 與模型。=== 連 X 都嚴格比較。Valid=0 時不比較未初始化的 dout,但 valid 本身若為 X 就失敗。最後四次 pop 檢查全部剩餘資料。PASS 是實際執行並通過所有 assertion 的訊息,不表示此處列出的程式已經執行。
加入 B0 前,先將舊 head A0 分離成預期輸出。比較的是資料邏輯順序,不是指標或實體槽位。
- 先前佇列: [A0, A1, A2, A3]
- pop 預期值: 保留原有 head A0
- 套用 push: [A1, A2, A3, B0]
- 比對回應: valid=1 時,dout=A0
用邊界案例核對 scoreboard
Queue=[A0,A1,A2,A3] 時若只有 push,大小為 4,捨棄 EE。接著同時請求,先保留 expected=A0,再把 B0 接尾,形成 [A1,A2,A3,B0]。若 DUT 立即輸出新 B0,資料 assertion 就失敗。Empty 同時請求則 expect_pop=0、expect_push=1,不比輸出,只存一個。Reset 期間忽略兩請求,清 queue 並檢查 valid=0。
記憶體驗證也用同原則:維護位址參考陣列與 initialized 表,read-first 在參考寫更新前取得讀預期。暫存器暫存器儲存多個位元的狀態。本課程中的同步暫存器會在時脈邊緣儲存指定的輸入。 詳細內容檔案 bypass 在碰撞時先選 wr_data,再更新參考陣列。未初始化位址讀取是禁止還是允許未定回應,須列為測試前提,不得任意拿 0 當答案。位址型記憶體需要獨立驗證器。
分別注入 full 同時 pop 卻輸出新值、雙接受時數量增加、empty pop 開 valid 等缺陷,對應檢查應失敗。透過這類審查與各邊界覆蓋找出測試遺漏。RAM 資源配置與時序需另以合成和時序驗證確認。
自己試試看
錯誤 scoreboard 先把 push 加到 queue,再用更新後大小判斷 pop。Empty 同時 push/pop 會如何誤判?Full 同時請求應何時保留預期資料?也評估每次 reset 後檢查 dout=0 的規則。
查看解說
會誤以為可立即 pop 新項目,產生 expect_pop=1。契約依邊緣前大小決定接受,因此只接受 push、輸出 valid=0。Full 時先保留舊 head 為 expected 並移除,再把新資料加到尾端。Reset 不把 dout 清零,只檢查 valid=0、queue 與 occupancy 為空。資料在 expect_pop=1 時比較,但也要獨立比較 DUT valid,才不會漏掉 valid 永遠為 0 的錯誤。