4. UVM波形调试:使用Verdi/DVE与UVM结合,Transaction级波形显示

波形调试,说白了就是芯片验证的「照妖镜」。

我们平时跑仿真,打印一堆log,看到「PASS」就以为万事大吉了。但说实话,很多隐蔽的bug,log根本看不出来。比如某个信号刚好在时钟沿跳变时被采样,或者transaction的时序刚好差了那么一个cycle——这种问题,只有盯着波形才能找到。

我个人习惯,不管log报不报错,每个testcase跑完都会拉一下波形看看。尤其是UVM环境,光看信号级波形太原始了,咱们得看transaction级的波形,那才叫高效。

4.1 为什么需要Transaction级波形?

传统的信号级波形,你看到的是一个个bit在跳。比如一个AXI总线,你看到awaddr、awvalid、awready这些信号在变。但你想过没有,一个完整的写transaction,包含了地址、数据、响应,这些信息是分散在几十个信号里的。

你想想看,如果波形里直接显示「WRITE: addr=0x1000, data=0xDEAD_BEEF, resp=OKAY」,那定位问题得多快?

Transaction级波形的核心价值:

  • 把分散的信号聚合为完整的协议事务
  • 显示transaction的属性字段(地址、数据、状态等)
  • 支持按transaction类型过滤和搜索
  • 一眼看出时序关系,比如两个transaction之间隔了多少cycle

我在项目中遇到过一件事:一个DMA模块,数据一直传错。看信号级波形看了两天,眼睛都快瞎了。后来把transaction级波形打开,发现是地址对齐出了问题——transaction里显示的地址是0x1003,但硬件要求4字节对齐。这种问题,信号级波形根本看不出来,因为地址总线上的值就是0x1003,你没法一眼判断它是不是对齐的。

4.2 UVM与Verdi的Transaction级波形集成

Verdi和DVE都支持UVM的transaction级波形显示。但说实话,不是你把波形dump出来就能自动看到的。你需要做一些配置。

嗯,这里要注意:Verdi支持的是UVM的objection和transaction recording机制。说白了,就是UVM在仿真时把transaction的信息记录下来,Verdi再去读取并显示。

4.2.1 使能Transaction Recording

在UVM环境中,要让transaction出现在波形里,你需要在driver或monitor里调用begin_tr和end_tr。我见过很多新手,写了UVM环境但忘了加这个,结果波形里啥也没有。

class my_driver extends uvm_driver#(my_transaction);
  virtual task run_phase(uvm_phase phase);
    my_transaction tr;
    forever begin
      seq_item_port.get_next_item(tr);
      // 开始记录transaction
      void'(begin_tr(tr, "my_driver"));
      // 驱动信号...
      drive_transaction(tr);
      // 结束记录
      end_tr(tr);
      seq_item_port.item_done();
    end
  endtask
endclass

这里有个坑:begin_tr返回的是一个整数句柄,你可以忽略它,但一定要调用end_tr。我曾经有一次忘了调end_tr,结果波形里transaction一直处于「进行中」状态,根本看不到结束时间。

4.2.2 添加Transaction字段到波形

光有transaction的起止时间还不够,你还需要把transaction里的关键字段显示出来。比如地址、数据、命令类型等。

UVM提供了uvm_record_attribute和uvm_record_field宏,用来把字段添加到波形数据库中。

class my_transaction extends uvm_sequence_item;
  rand bit [31:0] addr;
  rand bit [31:0] data;
  rand cmd_enum   cmd;  // READ, WRITE

  function void do_record(uvm_recorder recorder);
    super.do_record(recorder);
    // 记录字段到波形
    `uvm_record_field("addr", addr)
    `uvm_record_field("data", data)
    `uvm_record_field("cmd", cmd)
  endfunction
endclass

我个人习惯,把关键字段都记录下来。但别什么都记,比如一些中间变量、临时状态,记多了波形会变得很乱。你想想看,一个transaction里显示20个字段,谁看得过来?

我的经验:只记录对调试有帮助的字段。比如地址、数据、状态、错误码。像一些内部计数器、临时标志位,就别记了。保持波形清爽,定位问题才快。

4.3 在Verdi中查看Transaction级波形

好了,仿真跑完,波形dump出来了。怎么在Verdi里看transaction级波形?

首先,打开Verdi,加载波形文件(.fsdb)。然后,在波形窗口里,你会看到信号列表。找到你的UVM组件层次结构,比如uvm_test_top.env.agent.driver。

右键点击driver,选择「Add to Wave」->「Transaction」。Verdi会自动识别出这个driver里记录的transaction。

嗯,这里要注意:如果你在driver里调用了begin_tr和end_tr,Verdi才能看到transaction。否则,你只能看到信号级波形。

4.3.1 使用Transaction过滤和搜索

Verdi的transaction级波形支持按字段值过滤。比如,你只想看地址为0x1000的写transaction,可以这样操作:

  1. 在波形窗口里,点击「Transaction Filter」按钮
  2. 选择字段「addr」,设置值为「0x1000」
  3. 选择字段「cmd」,设置值为「WRITE」
  4. 点击「Apply」

波形里就只显示符合条件的transaction了。这个功能在定位特定场景时特别有用。我记得有一次,一个bug只在地址为0x2000~0x2FFF范围内出现,我就是用这个过滤功能,一秒就锁定了问题transaction。

4.3.2 查看Transaction的详细信息

在波形里,双击某个transaction的条块,Verdi会弹出一个窗口,显示这个transaction的所有字段值。包括你在do_record里记录的那些字段。

这个功能我经常用。比如看到波形里有一个transaction的响应是SLVERR,双击一看,发现地址超出了地址范围。这种问题,如果只看信号级波形,你得一个一个信号去对,累死。

4.4 DVE中的Transaction级波形显示

DVE是Synopsys的波形工具,用法和Verdi类似。但DVE对UVM的支持稍微弱一些,需要额外配置。

在DVE中查看transaction级波形,你需要确保仿真时生成了VCD+或FSDB格式的波形文件。DVE支持读取FSDB,但更推荐使用VCD+。

我个人觉得,DVE的transaction显示不如Verdi直观。Verdi的transaction条块是彩色的,不同颜色代表不同transaction类型。DVE默认是单色的,需要手动设置颜色映射。

避坑指南:我曾经在DVE里折腾了半天,transaction就是显示不出来。后来发现是仿真时忘了加+UVM_TR_RECORD=1这个选项。UVM默认是不记录transaction的,需要显式开启。

仿真命令里加上:+UVM_TR_RECORD=1,或者在testbench里调用uvm_config_int::set(this, "*", "recording_detail", UVM_FULL);

4.5 实战技巧:如何高效使用Transaction级波形

说了这么多,总结几个我实际项目中的经验:

  • 分层记录:在driver、monitor、scoreboard里都加上transaction recording。这样你可以看到从驱动到监测再到比对的完整链路。
  • 命名规范:transaction的name字段要起有意义的名字。比如tr.set_name($sformatf("WR_%0h", addr));,这样波形里一眼就能看出是哪个transaction。
  • 结合信号级波形:别只看transaction级。有时候需要同时看信号级波形,比如检查时序是否满足建立保持时间。Verdi支持同时显示两种视图。
  • 使用书签:找到关键transaction后,加个书签。方便后续回归验证时快速定位。

说实话,transaction级波形是我调试UVM环境时最常用的工具。没有它,很多问题根本无从下手。你想想看,一个复杂的协议,比如AXI、AHB、PCIe,信号成百上千,靠肉眼去对,那不是人干的事。

好了,这一章的内容就到这里。记住:波形调试不是可有可无的步骤,它是验证工程师的必备技能。尤其是transaction级波形,能让你从「看信号」升级到「看事务」,效率提升不止一个量级。

本章核心要点:

  • Transaction级波形把信号聚合为协议事务,大幅提升调试效率
  • 使用begin_tr/end_tr和do_record记录transaction信息
  • Verdi支持按字段过滤和搜索transaction
  • 别忘了加+UVM_TR_RECORD=1选项
  • 只记录关键字段,保持波形清爽
UVM Transaction级波形调试流程 UVM验证环境 Driver/Monitor/Scoreboard Transaction Recording begin_tr / end_tr 字段记录 do_record / uvm_record_field 波形文件 (.fsdb) Verdi加载波形 查看Transaction级波形 按字段过滤/搜索 双击查看详细信息 关键:+UVM_TR_RECORD=1 选项必须开启

可可精品资料库