请帮助理解在使用递归我的任务时遇到的一个问题。 因此,有一项任务应该跟踪2个信号enable和ddr_clk。它们是异步信号,启用可以在ddr_clk posedge之前出现。在这种情况下,任务应该等待启用高,然后@(posedge itf.ddr_clk)发生,以便写入完成。 为了实现这一点,我在任务中使用递归:
task automatic write();
$display ("%t:\tdriver: write function", $time);
if ( itf.enable == 1 ) begin
$display ("%t:\tdriver-write: ->writing in DUT: assiging wdata and waiting for ddr_clk posedge...", $time);
itf.wdata = req.data_wfifo_data; // assign and wait for clk posedge
fork
begin : wait_clock;
@ (posedge itf.ddr_clk)
$display ("%t:\tdriver-write: Got ddr_clk posedge, considering write done", $time);
end
@(itf.enable) // In case when enable goes to low before posedge
begin
$display ("%t:\tdriver-write: enable changed, re-calling write", $time);
disable wait_clock;
write;
end
join_any
end else
begin
$display ("%t:\tdriver-write-enable: waiting for enable...", $time);
@(itf.enable)
write;
end
$display ("%t:\tdriver: END write function", $time);
endtask
这就是模拟结果给出的结果:
65490750.0 ps: driver: write function
65490750.0 ps: driver-write: ->writing in DUT: assiging data_wfifo_data and waiting for ddr_clk posedge...
65490850.0 ps: driver-write: enable changed, re-calling write
65490850.0 ps: driver: write function
65490850.0 ps: driver-write-enable: waiting for enable...
65490850.0 ps: driver-write: enable changed, re-calling write
65490850.0 ps: driver: write function
65490850.0 ps: driver-write-enable: waiting for enable...
65490850.0 ps: driver: END write function
65490850.0 ps: Driver: END Calling write task to write in DUT
在相同的模拟时间,任务被多次调用,然后退出。
请帮助了解行为。 我的印象是“禁用wait_clock”语句在那里不起作用......
答案 0 :(得分:1)
我假设您没有向我们展示活动的完整日志。此任务必须有早期的$ display语句。此外,如果启用是真的,您确定数据是否稳定?
每次使用启用write()
致电true
时都会遇到问题,如果在 @(posedge itf.ddr_clk)
变低之前得到enable
,那么留下悬挂的过程。然后当enable
变低时,它们都会立即被触发。您可以在disable fork
之后加join_any
。
我认为在这里使用递归会使事情变得更复杂。我会用一个循环代替
task write;
fork
forever begin
wait(itf.enable);
itf.wdata = req.data_wfifo_data;
wait(!itf.enable); // @(itf.enable or req.data_wfifo_data) -- if really level sensitive
end
@(posedge itf.ddr_clk iff itf.enable);
join_any
disable fork;
endtask
答案 1 :(得分:0)
在fork和join_any块中,第二个块(its.enable)在65490850.0执行,它禁用wait_clock块并调用write(2)。
这导致两个流程。
在递归中第二次调用write(2)。 第二个任务将等待甚至在稍后完成或进一步递归调用写入。
在write(1)实例中,wait_clock块被禁用,fork join_any现在完成执行。 作为其join_any,禁用块会触发join_any的完成。代码通过跳过else并显示“END write function”并返回到驱动程序中的主调用函数。
然后调用write的主函数将显示“END调用写入任务以写入DUT”。
一种解决方案
添加计数以查看递归调用的次数。它还有助于调试。 它也用于开始等待第一次执行(写入)的触发器。无论何时wait_clock完成,它都会生成触发器。 您可以在首选项结构中实例化触发器。
task automatic write(int count );
$display ("%t:\tdriver: write function , count %d", $time,count);
if ( itf.enable == 1 ) begin
$display ("%t:\tdriver-write: ->writing in DUT: assiging wdata and waiting for ddr_clk posedge... count %d", $time,count);
itf.wdata = req.data_wfifo_data; // assign and wait for clk posedge
fork
begin : wait_clock;
@ (posedge itf.ddr_clk)
$display ("%t:\tdriver-write: Got ddr_clk posedge, considering write done count %d", $time,count);
->itf.done;
//disable wait_enable;
end
//begin : wait_enable
@(itf.enable) // In case when enable goes to low before posedge
begin
$display ("%t:\tdriver-write: enable changed, re-calling write count %d", $time,count);
disable wait_clock;
write(count+1);
end
//end
join_any
end else
begin
$display ("%t:\tdriver-write-enable: waiting for enable...count %d", $time,count);
@(itf.enable)
write(count+1);
end
if ( count == 0 ) wait (itf.done.triggered);
$display ("%t:\tdriver: END write function , count %d", $time,count);
end task
但递归函数很难跟踪和调试。在这种情况下,基于循环的函数MIGHT也同样好。 递归有另一个潜在的问题,因为禁用wait_clock块将导致所有递归函数中的所有wait_clock块被禁用。不确定它是否会引起问题,但需要注意一些问题。
基于协议的有限数据/不足,基于循环的功能如下所示。 代码试图模仿上面的代码,但可以进一步简化甚至修改,以便与协议相关的修复。
task automatic write_non_recursive ();
int done,got_clock,got_enable ;
done = 0 ;
$display ("%t:\tdriver: write function , ", $time);
while ( done == 0 )
begin
if ( itf.enable == 1 ) begin
$display ("%t:\tdriver-write: ->writing in DUT: assiging wdata and waiting for ddr_clk posedge... ", $time);
itf.wdata = req.data_wfifo_data; // assign and wait for clk posedge
end
got_clock = 0 ;
fork
begin //using got clock to check edge
@ (posedge itf.ddr_clk) ; got_clock = 1;
end
@(itf.enable) ;
join_any
//if ( itf.ddr_clk == 1 && itf.enable == 1 ) - if we were looking onyl into clock
if ( got_clock == 1 && itf.enable == 1 )
begin
$display ("%t:\tdriver-write: Got ddr_clk posedge, considering write done ", $time);
done = 1;
end
else if ( itf.enable == 0 ) // en = 0 , clk = 1 or en = 0 , clk = 0 ;
begin
$display ("%t:\tdriver-write: enable changed, re-calling write ", $time);
@(itf.enable) ; // wait for the next edge
end
else // en = 1 , clk = 0 ;
$display ("%t:\tdriver-write-enable: waiting for enable...", $time);
got_clock = 0; //reset and look for edge again
end
$display ("%t:\tdriver: END write function , ", $time);
end task