我在 SystemVerilog 中實作了一個 8 位串行輸入并行輸出暫存器,我正在嘗試對其進行測驗。我正在使用Icarus Verilog作為模擬器。
在測驗臺上,我發送 8 位并等待信號的上升沿,然后檢查獲得的并行緩沖區。問題是,在等待上升沿之后,并行緩沖區沒有預期值。但是,如果我#0在斷言中添加延遲,它確實有效。
我正在等待上升沿的信號以及應包含預期值的緩沖區分配為:
assign rdy = (i == 7) & was_enabled;
assign out_data = {8{rdy}} & buff;
我知道包含正確的值,那么,在,buff的上升沿如何有效但仍然是?rdyrdy1out_data0
波浪轉儲

注意:看看什么時候rdy變高out_data是0xaa。
代碼
串入并出暫存器
module sipo_reg(
input wire in_data,
output wire [7:0] out_data,
output wire rdy,
input wire en,
input wire rst,
input wire clk
);
reg [7:0] buff;
reg [2:0] i;
reg was_enabled;
wire _clk;
always @(posedge _clk, posedge rst) begin
if (rst) begin
buff <= 0;
i <= 7;
was_enabled <= 0;
end else begin
was_enabled <= 1;
buff[i] <= in_data;
i <= i == 0 ? 7 : (i - 1);
end
end
assign _clk = en | clk; // I know this is a very bad practice, I'm on it...
assign rdy = (i == 7) & was_enabled;
assign out_data = {8{rdy}} & buff;
endmodule
試驗臺:
module utils_sipo_reg_tb;
reg clk = 1'b1;
wire _clk;
always #2 clk = ~clk;
assign _clk = clk | en;
reg in_data = 1'b0, rst = 1'b0, en = 1'b0;
wire [7:0] out_data;
wire rdy;
sipo_reg dut(in_data, out_data, rdy, en, rst, clk);
integer i = 0;
initial begin
$dumpfile(`VCD);
$dumpvars(1, utils_sipo_reg_tb);
en = 1;
#4 rst = 1;
#4 rst = 0;
assert(out_data === 8'b0);
assert(rdy === 1'b0);
//
// read 8 bits works
//
#4 en = 0;
for (i = 0; i < 8; i = i 1) begin
@(negedge _clk) in_data = ~in_data;
end
en = 1;
@(posedge rdy);
assert(rdy === 1'b1);
assert(out_data === 8'haa); // <-- This fails, but works if I add a '#0' delay.
#20;
$finish;
end
endmodule
我試圖替換這些行
assign rdy = (i == 7) & was_enabled;
assign out_data = {8{rdy}} & buff;
通過這些
assign rdy = (i == 7) & was_enabled;
assign out_data = {8{((i == 7) & was_enabled)}} & buff;
因為我懷疑模擬器在“計算”out_data之后rdy因為前者取決于后者。但是,它們仍然是具有 0 延遲的連續分配,我希望它們能夠在完全相同的時間獲得它們的值(除非添加延遲)。
在每次之后添加幾皮秒的延遲@(posedge signal)以確保模擬器解決所有問題是一個好的設計實踐嗎?
uj5u.com熱心網友回復:
您的測驗臺中有一個競爭條件,因為您試圖在信號發生變化的時候對其進行采樣。所有數字系統都有固有的競爭條件,處理它們的方法是僅在您知道信號穩定時才對信號進行采樣。
在您的情況下,您可以按照您的建議使用一個小的數字延遲。但是,由于您有一個時鐘信號,如果您知道信號的變化只發生在時鐘的 posedge 上,您可以在 negedge 處對信號進行采樣:
@(posedge rdy);
@(negedge clk);
assert(rdy === 1'b1);
assert(out_data === 8'haa);
這是一種比使用數字延遲更穩健的方法,因為它可以更好地擴展(無需擔心選擇最佳數字延遲值)。
uj5u.com熱心網友回復:
這是一個同步設計,您的斷言也應該同步。這意味著只使用一個邊沿,即(正)時鐘邊沿。一旦開始使用其他信號邊緣,就會在等待信號更改的陳述句之間遇到競爭條件,其中包括@(posedge rdy)程序延遲和assign out_data = {8{rdy}} & buff;連續分配。
有兩種方法可以在您的測驗平臺中解決此問題:
不要@(posedge rdy)在您的程式代碼中使用。利用
@(posedge clk iff (rdy === 1'b1));
assert(out_data === 8'haa);
由于i和was_enabled都使用非阻塞賦值進行更新,因此使用其舊值以及隨后的斷言rdy進行采樣。out_data
另一種選擇是使用任何程式代碼之外的并發斷言
assert property (@(posedge clk) $rose(rdy) |-> out_data === 8'haa);
這寫著“當rdy上升時,這意味著out_data必須在同一個周期內8'haa”
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/493233.html
