尧图精选

UVM环境自动生成工具:从手写三小时到脚本三分钟

🕒 发布时间:2026/9/26 21:35:56 📁 来源:尧图网络
简介这是一款面向芯片验证工程师与IC设计学习者的UVM验证环境自动生成工具旨在解决手动搭建SystemVerilog验证平台耗时且易出错的问题。工具提供图形界面与Excel配置两种方式用户无需编写大量代码即可设定验证环境参数对非编程背景或初学UVM的团队成员尤为友好。资源包共78个文件以58张jpg界面截图、14个sv源码文件、4个xlsx配置表格为主另含1份pdf说明与1个py主程序压缩包约5.74MB目录结构清晰便于按模块查阅。已有1030人学习下载。通过该工具可自动生成验证组件、代理、驱动、监视器、计分板与激励序列等核心模块并完成组件连接与验证流程定义同时支持自定义验证规则与约束帮助读者快速理解UVM环境搭建思路将精力集中于验证逻辑设计与覆盖率提升。1. 芯片验证 UVM 环境自动生成工具从手写三小时到脚本三分钟如果你做过芯片验证大概率经历过这样的场景DUT 接口一变UVM 环境里的 driver、monitor、agent、scoreboard、env、test 全得跟着改手写一遍少说两三个小时改完还得反复核对uvm_config_db的路径有没有写错。这个 UVM 环境自动生成工具解决的正是这件事——它读取一份描述文件通常是 YAML 或 JSON自动吐出完整的 UVM 验证环境骨架代码包括 interface、transaction、sequence、driver、monitor、agent、env、test 以及对应的 compile 脚本。适合谁用一是刚接触 UVM、对 phase 机制和 TLM 端口连接还不太熟的验证新人二是需要快速搭原型环境、不想在重复劳动上耗时间的老手。它不替代验证思路但能把机械劳动压缩到几分钟。2. 工具怎么跑起来从描述文件到可编译环境2.1 环境依赖与安装这个工具本身是一个代码生成器常见实现是 Python 脚本或带 GUI 的桌面程序。我拿到的版本是 Python 写的命令行工具依赖比较干净Python 3.8 以上就能跑。先确认本机环境python3 --version pip3 --version如果版本没问题直接安装依赖。工具本身通常不发布到 PyPI而是以源码包形式提供解压后进入目录安装cd uvm_gen_tool pip3 install -r requirements.txtrequirements.txt里一般只有jinja2和pyyaml两个核心库。jinja2负责模板渲染pyyaml负责解析描述文件。装完后可以用python3 uvm_gen.py --help验证是否可用。如果报ModuleNotFoundError八成是 pip 装到了另一个 Python 版本下用python3 -m pip install重装一遍即可。2.2 描述文件怎么写工具的核心输入是一份 YAML 描述文件我一般叫它dut_spec.yaml。它定义了 DUT 的接口信号、事务字段和组件结构。下面是一个 APB 接口的示例dut_name: apb_slave interface: name: apb_if signals: - {name: pclk, dir: input, width: 1} - {name: presetn, dir: input, width: 1} - {name: paddr, dir: input, width: 32} - {name: psel, dir: input, width: 1} - {name: penable, dir: input, width: 1} - {name: pwrite, dir: input, width: 1} - {name: pwdata, dir: input, width: 32} - {name: prdata, dir: output, width: 32} - {name: pready, dir: output, width: 1} transaction: name: apb_trans fields: - {name: addr, width: 32, rand: true} - {name: data, width: 32, rand: true} - {name: write, width: 1, rand: true} agents: - name: apb_agent interface: apb_if transaction: apb_trans active: true这份描述里interface段决定apb_if.sv里信号怎么声明transaction段决定apb_trans.sv里有哪些 rand 字段agents段决定生成几个 agent、每个 agent 是 active 还是 passive。active: true会同时生成 driver 和 monitorfalse则只生成 monitor。字段的rand属性直接映射到 SystemVerilog 的rand修饰符省得你手动加。2.3 生成命令与输出结构描述文件写好后一条命令就能出全套代码python3 uvm_gen.py -i dut_spec.yaml -o ./uvm_env -t apb参数说明-i指定输入描述文件-o指定输出目录-t指定顶层 test 名称。执行完后uvm_env目录下会生成这样的结构uvm_env/ ├── apb_if.sv ├── apb_trans.sv ├── apb_sequence.sv ├── apb_driver.sv ├── apb_monitor.sv ├── apb_agent.sv ├── apb_env.sv ├── apb_test.sv └── filelist.ffilelist.f是给仿真器用的编译列表里面按依赖顺序列好了所有文件。我一般会先跑一遍编译确认没有语法错误vcs -full64 -sverilog -f filelist.f -top apb_test如果编译报uvm_config_db相关错误多半是 env 里 virtual interface 的配置路径和 test 里 set 的路径对不上这个后面避坑章节会细说。2.4 生成代码里 UVM 机制怎么落地的生成的apb_driver.sv里build_phase会从 config_db 拿 virtual interfacerun_phase里用seq_item_port.get_next_item取事务。这里涉及 UVM 的 phase 机制——build_phase自顶向下执行connect_phase自底向上工具生成的代码严格遵循这个顺序不会出现 connect 在 build 之前执行的玄学问题。apb_agent.sv里会根据active标志决定是否例化 drivermonitor 则始终存在。monitor 的 analysis port 在connect_phase里连到 scoreboard。这里用的是uvm_tlm_analysis_fifo还是普通uvm_tlm_fifo取决于 scoreboard 的消费方式analysis fifo 带无限深度的 analysis export适合 monitor 单向广播普通 fifo 有阻塞语义适合需要背压的场景。工具默认生成 analysis fifo因为验证环境里 monitor 到 scoreboard 绝大多数是单向数据流。apb_env.sv里会把 agent 和 scoreboard 例化并连接。如果你在描述文件里加了多个 agentenv 里会按顺序生成多个 agent 实例名字就是 YAML 里的name字段。apb_test.sv里会 set virtual interface 到 config_db路径是uvm_test_top.env.apb_agent.*这个路径必须和 agent 里 get 的路径完全一致差一个字符就是编译过、仿真挂。3. 参数怎么调让生成的环境贴合真实 DUT3.1 多 agent 与主动被动混合真实 DUT 往往不止一个接口。比如一个带 APB 配置口和 AXI 数据口的模块描述文件里可以写两个 agentagents: - name: apb_agent interface: apb_if transaction: apb_trans active: true - name: axi_agent interface: axi_if transaction: axi_trans active: falseactive: false的 agent 只生成 monitor用来观测 AXI 总线上的流量不驱动。这种主动被动混合的拓扑在 SoC 验证里很常见。工具会在 env 里生成两个 agent 实例scoreboard 的 analysis export 会同时连两个 monitor 的 analysis port。注意如果两个 agent 的 transaction 类型不同scoreboard 里需要写两个write函数分别处理工具生成的 scoreboard 骨架会预留这两个入口。3.2 寄存器模型镜像值的处理热词里提到的uvm寄存器模型镜像值在这个工具里也有对应支持。如果描述文件里加了reg_model段工具会生成寄存器模型骨架包括uvm_reg和uvm_reg_block的子类。镜像值的更新依赖predict和mirror调用生成的 adapter 里会实现reg2bus和bus2reg两个函数。我一般会在 scoreboard 里加一句reg_model.default_map.get_reg_by_offset(addr).mirror(status, UVM_CHECK)来校验镜像值和 DUT 实际值是否一致。工具生成的 adapter 默认按 APB 协议做转换如果你用的是 AXI需要手动改reg2bus里的字段映射。3.3 模块间参数传递的配置uvm_config_db是 UVM 里模块间参数传递的标准手段。工具生成的代码里test 层负责 setagent 和 env 层负责 get。常见的做法是在 test 的build_phase里uvm_config_db#(virtual apb_if)::set(this, env.apb_agent*, vif, apb_vif); uvm_config_db#(int)::set(this, env.apb_agent.driver, pre_num, 3);第一行把 virtual interface 传给 agent 下所有组件第二行把驱动前延时传给 driver。工具生成的 driver 里会有对应的uvm_config_db#(int)::get调用。如果你在 YAML 里加了params段工具会自动生成这些 set/get 的模板代码你只需要填默认值。这里有个细节set 的第二个参数是路径通配符env.apb_agent*里的星号会匹配 agent 下所有子组件但不会匹配 agent 本身所以 agent 自己要用get(this, , vif, vif)来拿。4. 避坑与排查生成代码跑不通时先看这几处4.1 编译报错找不到 uvm_macros.svh现象编译时提示cannot find file uvm_macros.svh。原因仿真器没带 UVM 库路径或者filelist.f里没有 include UVM 的incdir。解决在编译命令里显式加incdir$UVM_HOME/src和$UVM_HOME/src/uvm_pkg.sv或者用仿真器自带的-ntb_opts uvm-1.2选项。我一般会在filelist.f第一行写incdir$UVM_HOME/src这样换仿真器也不用改命令。4.2 仿真挂起在 build_phase 不动现象仿真跑起来后卡在build_phase日志停在uvm_config_db的 get 调用上。原因test 里 set 的路径和 agent 里 get 的路径不匹配get 拿不到值后续$cast失败导致 phase 卡住。解决在 test 的build_phase里加uvm_config_db#(virtual apb_if)::dump()打印当前 config_db 里所有条目对比 agent 里 get 的路径。常见错误是 test 里写env.apb_agentagent 里写this但 agent 的this在 config_db 里展开后是uvm_test_top.env.apb_agent少一层都不行。4.3 sequence 发出去但 driver 收不到现象sequence 里start了driver 的get_next_item一直阻塞。原因sequencer 和 driver 的seq_item_port没连上或者 sequence 启动时用的 sequencer 句柄不对。解决检查 agent 的connect_phase里有没有driver.seq_item_port.connect(sequencer.seq_item_export)。工具生成的代码默认会连但如果你手动改过 agent 结构可能把这句删了。另外sequence 启动时用uvm_seq.start(sequencer)里的 sequencer 必须是 agent 里那个实例不能是null。4.4 寄存器模型 mirror 值始终为 0现象调了mirror但读回来的镜像值一直是 0。原因adapter 的bus2reg函数没把总线上的prdata映射到uvm_reg_bus_op的data字段或者reg2bus里地址偏移算错了。解决在 adapter 里加uvm_info打印每次转换的 addr 和 data对比 DUT 实际读写地址。常见错误是bus2reg里忘了给rw字段赋值导致 UVM 不知道这次是读还是写镜像值自然不更新。4.5 多 agent 场景下 scoreboard 只收到一路数据现象两个 agent 的 monitor 都在跑但 scoreboard 只打印了一路 transaction。原因两个 monitor 的 analysis port 连到了同一个 analysis fifo 的同一个 export 上后连的覆盖了先连的。解决scoreboard 里为每个 agent 建独立的 analysis fifo或者用uvm_tlm_analysis_fifo的多个实例分别连。工具生成的 scoreboard 默认按 agent 数量生成对应个数的 fifo但如果你在 YAML 里改了 agent 名字没重新生成就可能出现端口名对不上的情况。5. 进阶用法把生成器接进 CI 和回归流程生成器最大的价值不是省一次手写时间而是让环境骨架可以随 DUT 接口变更自动更新。我现在的做法是把dut_spec.yaml纳入版本管理每次 DUT 接口有改动先改 YAML再跑一遍生成命令然后git diff看生成了哪些文件变化。如果 diff 里只有 interface 和 transaction 的字段增减说明改动是可控的如果 env 或 test 的结构变了就得人工 review 一下连接关系有没有断。更进一步可以把生成命令写进 Makefile和编译、仿真串起来gen: python3 uvm_gen.py -i dut_spec.yaml -o ./uvm_env -t apb compile: gen vcs -full64 -sverilog -f uvm_env/filelist.f -top apb_test run: compile ./simv UVM_TESTNAMEapb_test UVM_VERBOSITYUVM_LOW这样每次make run都会先根据最新 YAML 重新生成环境再编译。CI 里跑回归时如果 DUT 接口变了但 YAML 没更新编译阶段就会报错相当于用编译错误倒逼描述文件同步。这个习惯帮我省掉了好几次“环境代码和 DUT 对不上”的翻车。验证生成结果是否正确我一般会跑一个最小 smoke test只发一笔读写看 scoreboard 有没有报 mismatch寄存器模型 mirror 值有没有更新。如果 smoke test 过了再跑全量回归。另外生成器输出的filelist.f里文件顺序是按依赖排的但如果你手动加了额外的 package 或 interface记得插在正确位置——package 要在 import 它的模块之前interface 要在使用它的模块之前。我一般会在filelist.f末尾加一个incdir./custom指向自己写的扩展文件这样重新生成时不会覆盖自定义内容。从那以后我每次改完 YAML 都强制走一遍make gen make compile确认生成的环境能编译过再动仿真。希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联 返回资讯列表 →