UVM新手的踩坑之旅(2)

UVM中while(1)的使用

1.在搭建AHB2APB_BRIDGE的scoreboard时,需要使用while(1)循环来对比采样的数据。

//...... AHB2APB_bridge,apb端的数据采样和比对
while(1) begin
    
    if(vif.pwrite = 1) begin        //pwrite为0时,读操作;为1时,写操作     
        if(vif.penable = 1) begin   //apb协议规定,penable为1时数据有效
            golden_data = golden_data_queue.pop_front();    //把采样的golden data拿出
            if(golden_data == vif.pwdata)                   //两端data比对
                `uvm_info("DATA is OK",$sformatf("HWDATA= %0h",vif.pwdata),UVM_LOW)
            else
                `uvm_error("DARA is DIF",$sformatf("HWDATA= %0h",vif.pwdata))
        end    
    end
    else begin                    //读操作                    
            if(vif.penable == 1)  //penable = 1.数据有效
            apb_write_queue.push_back(vif.prdata);   //放入队列,用于ahb端比对
    end
end

2.编译后没有error,但是在运行时,整个环境却卡住。(scoreboard的写法每个环境相差不多,从来没有遇到过这个情况)

terminal里的打印信息显示,在运行testcase中的reset检测后,这个验证环境便不再运行。

virtual task wait_reset_done();
    @(posedge vif.rst_n);
    `uvm_info("RESET_DONE","posedge of hrst_n!",UVM_LOW)
endtask

思来想去,能使整个环境卡死停止运行的情况有两个:

(1)apb端的vif.penable 或者vif.pwrite没有拉高,导致data没有正确的得到。(大概率不是这种情况......写的testcase和DUT一般不会出现这种低级错误的)

        分析:带着疑问,打开verdi,拉出波形一看便知,所有的信号都正确的显示在波形上,明显不是DUT和testcase的问题,那边便是搭建环境有问题了。

(2)存在与run_phase()中的某个while(1)一直在运行,导致环境卡死。

        分析:首先,需要定位是在run_phase哪一个while(1)卡死。首先,需要分析run_phase()中都使用了几个while(1)。ahb_uvc中ahb_driver的while(1),ahb_monitor的while(1)这些组件是标准的uvc不考虑存在错误。其次就是scoreboard中使用的while(1),这些while(1)的用法与之前UART和SPI模块验证中while(1)的使用方式相同,但是为什么会出问题呢?

于是,为了判断是哪个while(1)陷入死循环,便添加了一些简单的打印信息:

virtual task run_phase(uvm_phase);
    while(1) begin
        reset();
        $display("----------reset finish----------");

        fork
            //进程1:检测reset的下降沿
            begin
                @(negedge vif.rst_n);
            end
            
            //进程2:把ahb写入bridge的data打入uart队列或者spi队列,且把读出的data比对
            while(1) begin
                $display("sample data and compare data at ahb ports");
                ...
            end

            //进程3:把uart slave写入bridge的data打入队列,把得到的data比对
            while(1) begin
                $display("sample data and compare data at uart slave");
                ...
            end


        join_any
        disable fork;
    end

重新运行,如果发现哪个打印任务被重复执行便可以得出这个打印任务所在的while(1)陷入死循环。果然,不出所料,“sample data and compare at uart slave”被重复打印,可以判断出是进程3的while(1)卡死。

思考了很久,跟之前写的scoreboard做了对比,发现了一个小问题。之前搭建的scoreboard收集接口的数据都是由两端的uvm_tlm_analysis_fifo来完成的,但是这次的bridge由于没有数据寄存功能,直接使用virtual interface的端口来得到数据的,使用这种方式与使用fifo的方式的最大不同点就是"数据是否被阻塞"。

uvm_tlm_analysis_fifo 的使用条件是,其两端必须有相应的uvm tlm port来连接。数据流来说,使monitor采样端口(类型先不做考虑)的数据先传输到fifo中,fifo中的数据再流向scoreboard的端口(uvm_get_blocking_port),这个端口简单理解就是,只用我调用了uvm_get_blocking_port的get函数且fifo里面有数据时,fifo里面的数据才会进入scoreboard,其他情况下为阻塞状态。

但是,virtual interface就不一样了。其本质可以理解为一捆没有定义方向的线,只要有数据便会传入scoreboard,使用时不会产生阻塞。这就是导致while(1)陷入死循环的根本原因,接口的信号会被一直判断,进而导致整个环境的卡死。

3.解决办法:想要消除死循环就是要是if前添加一个阻塞语句的同时,还不能影响scoreboard的对data的收集。便想到一个"阻塞+条件判断"的语句"iff":

while(1) begin

    @(posedge vif.clk iff (vif.psel == 1));  //当psel为1时,clk的上升沿才有效,其他情况被阻塞
    if(vif.pwrite == 1) begin
        ...
    end
end

添加了这条特殊的阻塞语句后,只有当iff后的信号为高时,clk的上升沿才有效。数据也可以正确的被采样和对比。

4.总结:while(1)的使用虽然在搭建验证环境中经常被使用,但是一定要注意阻塞语句的使用,防止是整个运行环境陷入死锁。

  • 24
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值