UVM环境的看门狗怎么没看住超时了?

描述

uvm验证环境里一般通过objection机制来控制仿真的结束,不过在机制之外,有时还需要通过看门狗来watchdog避免仿真环境挂死,watchdog配合objection一起来控制仿真的进行与结束。

我一直自诩为对环境watchdog这件事烂熟于心了,不过没想到这天还是被伤害到了。

事故背景

一个中规中矩的watchdog是怎么组织的呢?要明确一下watchdog发挥的作用,就是在objection的基础上进行补充,在环境长时间没有动静的情况下能够使环境报错推出并打印此时阻止仿真结束的罪魁祸首。

基于这个认识,watchdog应该是base_test的run_phase()中进行调用,这样既从时间全程参与又从空间上统揽全局。当然了,因为环境的主要行为集中在main_phase()中,所以把watchdog放在main_phase()中我觉得也是可以的。

task base_test::run_phase(uvm_phase phase):
super.run_phase(phase);
phase.raise_objection(this);

this.watchdog(phase);

phase.drop_objection(this);
endtask: run_phase

watchdog上下的objection还是很有必要的,毕竟你要保证watchdog无论在哪里调用都可以执行起来,别这个phase没有objection就直接略过了。

watchdog内部逻辑就是几个并行的线程,简单来说可以这样写:

task base_test::watchdog(uvm_phase phase):
#1000;
if(this.cfg.watchdog_en == 0) return;
while(1)begin
bit vr_reached;
fork: timeout
begin //normal finish
phase.phase_done.wait_for_total_count(null, 1);
vr_reached = 1;
end
begin //timeout
#this.cfg.watchdog_th;
`uvm_fatal("watchdog", $psprintf("watchdog timeout(%s_phase)::n %s", phase.get_name(), phase.phase_done.convert2string()))
end
#100 @prj_scoreboard::feed_watchdog;
#100 @harness.dut.hand_en;
#100 wait(this.env.num != 0);
join_any
disable timeout;

#10;
if(vr_reached && phase.phase_done.get_objection_tatal == 1)begin
`uvm_info("watchdog", $psprintf("watchdog timeout(%s_phase) normal reached", phase.get_name()), UVM_LOW)
break;
end
end
`uvm_note("watchdog", "watchdog Finished!", UVM_LOW)
endtask

代码的主体就是一个大的while(1)循环,循环内以fork - join_any的形式起多个喂狗线程,根据fork - join_any的机制,只要任何一个线程完成了都会触发喂狗机制。

*线程1:正常结束的线程,因为本身watchdog占着一个raise_objection,所以只要等待wait_for_total_count(null, 1)就可以了,为1说明其他的objection都已经drop了,那么就可以正常结束程序,和uvm本身的objection机制完全一样;

*线程2:超时线程,如果很长的时间里都没有喂狗,那么报fatal推出仿真。注意这里必须是fatal使方正立即结束,报error的话环境还是会挂死状态;

*线程3:所有的scoreboard都可以喂狗,因为scb里比对的一方是可以信任的环境预期,如果比对还在进行那么就说明仿真不应该结束;

*线程N:可以喂狗的其他线程,使用rtl线程需要万分谨慎,很有可能rtl里做错了一致重复出数据导致仿真无法结束;

当喂狗一次后,就可以杀掉timeout这个线程了,然后根据情况看看是否重新回到看门狗循环中。

事故现场

看门狗的核心起始就是,确定仿真在“动”,能动就是还活着不能结束仿真,所以在fork-join_any里除了超时线程以外,其他的都是证明系统还活着的“喂狗”线程。这些线程里如果使用rtl的信号作为系统还活着的参照,一定要万分的小心,万分的小心,万分的小心。

第一点小心是该停止但是停不下来,取材自上个月的bug。场景很简单,#100 @harness.dut.hand_en这个线程里hand_en做错了,进入了无限发包无限握手的死循环,带着环境也一直停不下来看门狗直接失效了。

第二点小心是该仿真但是挺下来了,这个事我以前就没想过能出现。事故现场是这样的还是#100 @harness.dut.hand_en这个线程(就是这么头铁,出过错了还继续用),这次确实是RTL正常的发包握手,但是,性能模式下外部没有反压拍拍握手成功,hand_en起来之后就没见到下降沿!这就导致了什么问题呢,导致@harness.dut.hand_en线程根本就触发不了!这就涉及到@和wait的区别了,@捕捉的是event trigger是信号的跳变,harness.dut.hand_en恒1不跳导致看门狗直接超时了。

简直目瞪口呆,只要每天比别人多碰到3个bug,两年能积累别人五年经验。

事故解决

我把@harness.dut.hand_en改成wait harness.dut.hand_en了

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分