【芯片前端】auto_testbench的大版本升级——加入简单预期与自动比对

news/2024/5/19 17:36:32 标签: IC, 芯片, verilog, systemverilog, UVM

前言

前文提要:

芯片前端】一键生成简易版本定向RTL验证环境的脚本——auto_verification_rtl脚本_尼德兰的喵的博客-CSDN博客

芯片前端】可能是定向验证的巅峰之作——auto_testbench_autotestbench_尼德兰的喵的博客-CSDN博客

工具路径:

auto_testbench: 用于自动生成verilog rtl的定向用例仿真平台的脚本

在上次完成自诩为“定向验证的巅峰之作”之后,我觉得这个工具应该是写到头了,不过最近的实践中我发现,对于auto_testbench的主要应用场景——CBB与UT的验证而言,如果能不依赖于方法学进行一些简单预期和比对,还是可以大幅收敛debug时间的。

本次升级针对握手接口(因为好久没写其他类型接口了),脚本的功能概述为:

  1. 对于握手接口单输出的模块,会进行符合协议的输入随机,会自动生成采样与比对task,而根据输入生成预期的task需要手动填充;
  2. 对于不满足单输出的其他握手接口模块,会进行符合协议的输入随机,此时如果想要进行比对需要对环境进行比较大的改动;
  3. 对于其他接口模块,会生成整套验证环境,对接口进行初始化和随机驱动;
  4. 如果不进行仿真只想编译模块,在tb.f中注释掉testbench.sv路径然后在sim路径执行make cmp;

其他优化包括:

  1. 优化了生成的tb.f文件;
  2. 修正了模块中有注释是可能误读的问题;
  3. 美化和对齐了一下生成文件;

效果亲测

作为一个负责人的工具发布者,发布前我先亲自验证了一下这个工具的正确性,于是翻出来了去年写的一个cbb bypass_fifo进行了下验证,然后发现这个cbb有BUG!不过放心,我相信这个cbb是没有在工程中使用的。

bypass_fifo的功能是这样,对于输入的data,如果power为1则正常输出,如果为0则丢弃。这个cbb听起来很奇怪不过其实他是另外一个cbb的一部分(一对多的场景,每个数据可能有不同的通道需要)。那么看下出错的log:

对着log找到波形的错误处:

然后分析下问题不是出现在'h57eadcc1这个数身上,而是出现在前一个数'hb985d7ad,RTL出口没有就把valid和数变了!奇怪的是对于类似的场景,其他的数据在出口时序就很正确:

那么这个问题如果通过波形是否能发现呢?不是太容易:

因此,这个工具的新功能我初步认为是有效的。

使用说明

就以bypass_fifo的验证环境生成为例,看一下如何使用。

第一步还是切换到bypass_fifo的路径,执行:

auto_testbench -f bypass_fifo.v
#如果没有设置全局路径,请完整输入auto_testbench的脚本路径

打印信息为:

##====================================================================##
Gen over! please cd ./bypass_fifo_verification/sim
You need modify ./bypass_fifo_verification/top/testbench.sv
    like cp ./bypass_fifo_verification_bak/top/testbench.sv ./bypass_fifo_verification/top/
You need modify ./bypass_fifo_verification/cfg/tb.f
    like cp ./bypass_fifo_verification_bak/cfg/tb.f ./bypass_fifo_verification/cfg/
##====================================================================##

这里说明一下,我的本意是如果已经有bypass_fifo_verification目录了,就把bypass_fifo_verification重命名为bypass_fifo_verification_bak,不过吧脚本写的好像是有点问题导致这个功能时灵时不灵。

第二步,切换到bypass_fifo_verification/cfg路径,打开tb.f文件,并按照需求修改:

+libext+.v
-y /home/ICer/gitee_path/auto_testbench/src/

../ver/bypass_fifo_pkg.sv
/home/ICer/gitee_path/auto_testbench/src/bypass_fifo.v
../top/testbench.sv

第三步,切换到bypass_fifo_verification/ver路径,检查bypass_fifo_pkg.sv是否符合预期:

package bypass_fifo_pkg;

    parameter ERROR_DEBUG_CNT = 5;
    parameter DEPTH = 8;
    parameter WIDTH = 128;

    int error_cnt = 0;
    bit check_en  = 0;

    typedef struct{
        bit [WIDTH -1:0] data_in;
        bit  data_in_power;
    } data_in_valid_struct;
    data_in_valid_struct data_in_valid_bus_q[$];

    typedef struct{
        bit [WIDTH -1:0] data_out;
    } data_out_valid_struct;
    data_out_valid_struct rm_q[$];
    data_out_valid_struct data_out_valid_bus_q[$];

endpackage

重点说bypass_fifo_pkg文件,在这个文档中脚本根据每个valid信号的名字“推测”其它信号是否为该valid“管辖”的信号,并将结果按valid分组为struct结构。然后顺便把每个数据结构的队列进行声明,如果是输出的valid,那么同时声明reference model的预期队列。因此如果有多路valid输出握手的话,这里的rm声明会重复,需要手动修改。

ERROR_DEBUG_CNT表示发生错误的次数,check_en表示是否进行自动比对默认为0,需要进行比对时手动将这个值改为1。

第四步,切换到bypass_fifo_verification/top路径,打开testbench.sv文件,还是如此的赏心悦目:

其他部分之前都讲过,只需说明下新增的auto_verification部分即可。展开这部分可以看到如下代码:

task in_queue_gain();
  while(1)begin
    @(negedge clk);
    if(data_in_valid && data_in_ready)begin
      data_in_valid_struct data_in_valid_dat;
      data_in_valid_dat.data_in = data_in;
      data_in_valid_dat.data_in_power = data_in_power;
      data_in_valid_bus_q.push_back(data_in_valid_dat);
    end//if-end 
  end//while-end 
endtask: in_queue_gain

对输入进行采样,如果有多路输入,会在这个task里均进行采样;

task out_queue_gain();
  while(1)begin
    @(negedge clk);
    if(data_out_valid && data_out_ready)begin
      data_out_valid_struct data_out_valid_dat;
      data_out_valid_dat.data_out = data_out;
      data_out_valid_bus_q.push_back(data_out_valid_dat);
    end//if-end 
  end//while-end 
endtask: out_queue_gain

对输出进行采样,如果有多路输出,会在这个task里均进行采样;

task rm_queue_gain();
  data_in_valid_struct data_in_valid_dat;
  data_out_valid_struct data_out_valid_dat;
  //while(1)begin
    //wait(data_in_valid_bus_q.size > 0);
    //data_in_valid_dat = data_in_valid_bus_q.pop_front();
    //rm_q.push_back(data_out_valid_dat);
  //end
endtask: rm_queue_gain

rm_queue_gain是一个空壳task,用于产生预期,里面预置了数据类型和队列操作方法;

task queue_check();
  while(1)begin
    data_out_valid_struct rm_data;
    data_out_valid_struct dual_data;
    wait(data_out_valid_bus_q.size() > 0);
    dual_data = data_out_valid_bus_q.pop_front();
    if(rm_q.size() == 0) begin
      $display("dual_data = %0p, rm_queue.size = 0", dual_data);
      error_cnt += 1;
    end
    else begin
      rm_data = rm_q.pop_front();
      if(dual_data != rm_data)begin
        error_cnt += 1;
        $display("dual_data(%0p) != rm_data(%0p) at %t", dual_data, rm_data, $realtime);
      end
      else begin
        //$display("dual_data(%0p) == rm_data(%0p) at %t", dual_data, rm_data, $realtime);
      end
    end
    if(error_cnt >= ERROR_DEBUG_CNT) begin
      $display("Check Error!!!");
      $finish;
    end
  end
endtask: queue_check

对rm_q[$]和RTL输出接口queue[$]进行自动比对,同样需要注意,如果有多路进行输出,这里只会比对其中一路;

代码的最后是固定的initial函数:

initial begin
  fork
    in_queue_gain();
    out_queue_gain();
    rm_queue_gain();
    if(check_en == 1) queue_check();
  join_none
end

然后是关键点,根据bypass_fifo的功能对rm_queue_gain task进行改写,完成简单的功能预期:

task rm_queue_gain();
  data_in_valid_struct data_in_valid_dat;
  data_out_valid_struct data_out_valid_dat;
  while(1)begin
    wait(data_in_valid_bus_q.size > 0);
    data_in_valid_dat = data_in_valid_bus_q.pop_front();
    if(data_in_valid_dat.data_in_power == 1)begin
        data_out_valid_dat.data_out = data_in_valid_dat.data_in;
        rm_q.push_back(data_out_valid_dat);
    end
  end
endtask: rm_queue_gain

至此CBB的简单验证环境就完成了。

切换到auto_verification/sim目录,执行:

make run wave=on

之后根据仿真结果和波形进行debug。


http://www.niftyadmin.cn/n/4946809.html

相关文章

爱校对:塑造无瑕公文的强大工具

在公文处理的世界中,每个字、每个标点都需要细心打磨,确保无一瑕疵。如何能达到这种精确无误的程度呢?让我们一起来看看强大的爱校对软件如何帮助我们塑造无瑕的公文。 首先,爱校对软件采用先进的自然语言处理和深度学习技术&…

树结构转List

使用LinkedList效率更高 1、单个顶级节点 public static List<CmsStudentOutline> getTreeList(CmsStudentOutline root) {List<CmsStudentOutline> list new ArrayList<>();Queue<CmsStudentOutline> queue new LinkedList<>();if (root nu…

第六章Tomcat部署以及优化

Tomcat&#xff1a; 开放源代码web应用服务器。&#xff08;基于Java代码开发的&#xff09;&#xff0c;主要是处理动态请求和基于java代码进行页面开发。可以在html当中写入Java代码&#xff0c;Tomcat可以解析html页面当中的Java&#xff0c;执行动态请求&#xff0c;动态页…

keepalived 高可用集群简单搭建

1.keepalived概念 keepalived是一款高可用集群软件&#xff0c;keepalived功能&#xff1a;心跳检测和故障切换。 心跳检测&#xff1a;master主机会向从节点广播心跳信息&#xff0c;当从节点收不到master节点的心跳信息时&#xff0c;会进行vip的漂移。 故障切换&#xff1a;…

C语言:每日一练(选择+编程)

目录 选择题&#xff1a; 题一&#xff1a; 题二&#xff1a; 题三&#xff1a; 题四&#xff1a; 题五&#xff1a; 编程题&#xff1a; 题一&#xff1a;打印1到最大的n位数 示例1 思路一&#xff1a; 题二&#xff1a;计算日期到天数转换 示例1 思路一&#xf…

Unity自定义脚本的 初始模版

参考博主&#xff1a;Unity修改创建的脚本模板&#xff0c;Unity脚本模板路径_unity hub 怎么改脚本模板_先生沉默先的博客-CSDN博客 【100个 Unity实用技能】 ☀️ | Unity自定义脚本的初始模版_unity 模板脚本_呆呆敲代码的小Y的博客-CSDN博客 一&#xff0c;将脚本放到Ed…

每天一道leetcode:1218. 最长定差子序列(动态规划中等)

今日份题目&#xff1a; 给你一个整数数组 arr 和一个整数 difference&#xff0c;请你找出并返回 arr 中最长等差子序列的长度&#xff0c;该子序列中相邻元素之间的差等于 difference 。 子序列 是指在不改变其余元素顺序的情况下&#xff0c;通过删除一些元素或不删除任何…

【【典型电路设计之片内存储器的设计之RAM的Verilog HDL描述一】】

典型电路设计之片内存储器的设计之RAM的Verilog HDL描述一 RAM是随机存储器&#xff0c;存储单元的内容可按需随意取出或存入。这种存储器在断电后将丢失所有数据&#xff0c;一般用来存储一些短时间内使用的程序和数据。 其内部结构如下图所示&#xff1a; 例&#xff1a;用…