我为一个简单的D触发器制作了一个SystemVerilog测试平台。
设计规范:
module dff (dff_if vif);
always@(posedge vif.clk)
begin
if(vif.rst == 1'b1)
vif.dout <= 1'b0;
else
vif.dout <= vif.din;
end
endmodule
在testbench中,即使仿真已经达到$finished,监视器类也将永远运行。
Testbench代码:
interface dff_if;
logic clk;
logic rst;
logic din;
logic dout;
endinterface
/////////////////////////////////////////////////////////////////////////tran
class transaction;
randc bit in;
bit out;
function transaction copy();
copy=new();
copy.in=this.in;
copy.out=this.out;
endfunction
function void display(string tag);
$display("[%s] datain:%d dataout=%d",tag,in,out);
endfunction
endclass
/////////////////////////////////////////////////////////////////////////gen
class generator;
transaction t;
mailbox gtd;
mailbox gts;
event drvnext; //delete after test
event done;
function new(mailbox gtd,mailbox gts);
t=new();
this.gtd=gtd;
this.gts=gts;
endfunction
task run();
repeat(10) begin
$display("______________________________________________________________________");
assert(t.randomize) else $error("[GEN] : RANDOMIZATION FAILED");
gtd.put(t.copy());
gts.put(t.copy());
t.display("GEN");
@(drvnext);
end
->done;
$display("DONE");
endtask
endclass
///////////////////////////////////////////////////////////////////////////drv
class driver;
virtual dff_if vif;
transaction t;
mailbox gtd;
//event drvnext;
function new(mailbox gtd);
t=new();
this.gtd=gtd;
endfunction
task run();
forever begin
@(posedge vif.clk);
@(posedge vif.clk);
gtd.get(t);
vif.din=t.in;
t.display("DRV");
end
endtask
endclass
//////////////////////////////////////////////////////////////////////////mon
class monitor;
virtual dff_if vif;
transaction tr;
mailbox mts;
event drvnext;
function new(mailbox mts);
tr=new();
this.mts=mts;
endfunction
task run();
forever begin
@(posedge vif.clk);
@(posedge vif.clk);
tr.out=vif.dout;
mts.put(tr);
tr.display("MON");
->drvnext;
end
endtask
endclass
//////////////////////////////////////////////////////////////////////////////////
module tb;
generator g;
driver drv;
monitor mn;
dff_if vif();
dff dut(vif);
mailbox gtd;
mailbox gts;
mailbox mts;
event drvnext;
event done;
initial begin
gtd=new();
gts=new();
mts=new();
g=new(gtd,gts);
drv=new(gtd);
mn=new(mts);
g.drvnext=drvnext;
mn.drvnext=drvnext;
g.done=done;
drv.vif=vif;
mn.vif=vif;
fork
g.run();
drv.run();
mn.run();
join_any
@(done);
$finish;
end
initial
vif.clk=0;
always #5 vif.clk=~vif.clk;
endmodule
模拟输出(一些最后的事务):
# KERNEL: [GEN] datain:0 dataout=0
# KERNEL: [DRV] datain:0 dataout=0
# KERNEL: [MON] datain:0 dataout=1
# KERNEL: _______________________________________________________________________________________
# KERNEL: [GEN] datain:1 dataout=0
# KERNEL: [DRV] datain:1 dataout=0
# KERNEL: [MON] datain:0 dataout=0
# KERNEL: _______________________________________________________________________________________
# KERNEL: [GEN] datain:0 dataout=0
# KERNEL: [DRV] datain:0 dataout=0
# KERNEL: [MON] datain:0 dataout=1
# KERNEL: DONE
# KERNEL: [MON] datain:0 dataout=0
# KERNEL: [MON] datain:0 dataout=0
# KERNEL: [MON] datain:0 dataout=0
# KERNEL: [MON] datain:0 dataout=0
# KERNEL: [MON] datain:0 dataout=0
# KERNEL: [MON] datain:0 dataout=0
# KERNEL: [MON] datain:0 dataout=0
# KERNEL: [MON] datain:0 dataout=0
# KERNEL: [MON] datain:0 dataout=0
有人能告诉我我在这里做错了什么吗?
发布于 2022-10-31 19:37:31
这是对event
的误用。该事件是在您开始使用@(done)
语句等待它之前触发的。可以使用wait
/ triggered
组合检测以前的事件。
更改:
@(done);
至:
wait(done.triggered);
参见IEEE Std 1807-2017节9.4.4级敏感序列控制.
模拟输出:
...
______________________________________________________________________
[GEN] datain:1 dataout=0
[DRV] datain:1 dataout=0
[MON] datain:0 dataout=0
______________________________________________________________________
[GEN] datain:0 dataout=0
[DRV] datain:0 dataout=0
[MON] datain:0 dataout=1
DONE
发布于 2022-10-31 19:37:08
您的问题是在@done
之前有$finish
,但是在执行该语句之前触发done
。事件触发器语句必须在等待触发器的语句之前执行。当监视器完成其event done
循环时,您将不需要fork/join_any
。
我强烈反对使用另一个答案中提到的triggered
方法。随着代码变得更加复杂,它很容易中断。想出一种不使用事件的方法(在本例中,您甚至不需要使用它),或者确保代码在@done
之前执行->done
。您可以使用fork/join_none
或使用->>done
代替->
。
https://stackoverflow.com/questions/74268156
复制相似问题