UVM环境自动生成工具(2)uvmdvgen

介绍

OpenTitan是一个谷歌的开源RISC-V项目,这里借用了项目中的uvm环境生成脚本uvmdvgen来生成环境。

使用流程是通过命令后缀指定环境和agent名称,然后脚本依据路径下的mako模板替换生成环境,脚本基于python实现。

项目链接:
GitHub - lowRISC/opentitan: OpenTitan: Open source silicon root of trust

使用步骤

环境

脚本基于python实现,github目录有环境要求,个人在centos7 python 3.14测试。

脚本在util/路径,-h可以看到帮助说明,-a用于生成agent,-s指示agent主从分开,-e用于生成env,-c从CIP库生成否则从DV库生成,-hr、hi、ha指示包含寄存器模型、中断和alert,-ea指示env中包含的agent,-ao指示agent生成在路径,-ro指示env生成在的路径。

复制代码
$ util/uvmdvgen.py -h
usage: uvmdvgen.py [-h] [-a] [-s] [-e] [-c] [-hr] [-hi] [-ha]
                   [-ea agt1 agt2 [agt1 agt2 ...]] [-ao [hw/dv/sv]]
                   [-eo [hw/ip/<ip>]] [-v VENDOR]
                   [ip/block name]

生成agent

使用脚本生成环境包括2步,首先通过-a生成agent,再通过-e -ea生成集成agent的env。

在端口通过指令生成i2c agent,这里是生成在当前目录,也可以加-ao指定目录。

复制代码
$ util/uvmdvgen.py i2c -a

在i2c/i2c_agent可以看到生成文件。

但实际生成的是纯空文件,或者说替换了名字的空模板,内容还要自己从头写,所以指令agent可以是任何名称,例如i3c、i4c,不一定是DV库中的agent。

在项目的hw/dv/sv路径中有一些uvm agent,包含jtag、uart、spi、i2c等,是有完整内容的,可以直接拷贝到自己的环境。

生成env

在vrf目录生成一个环境,包含axi apb pcie agent,和前相似agent名可以任意。

复制代码
util/uvmdvgen.py vrf -e -ea axi apb pcie

在vrf/dv路径下可以看到生成环境,这个脚本还是比较自动的,首先env中可以看到例化各个agent,传递了配置,连接了scb,连接了top_seqr。不过也有缺点,同名agent只能例化1次否则要手动修改,还有就是没有ref model和对应scb连接。

其他vseq、vseqr不再赘述,tb中例化了agent同名if,并config_db发送到了agent中,基本流程都有实现。

脚本实现

脚本通过python实现,可以看一下实现方法。

uvmdvgen.py

脚本接收了参数,并根据-a还是-e决定执行gen_agent还是gen_env。

复制代码
if args.gen_agent:
	gen_agent.gen_agent(args.name, args.has_separate_host_device_driver, args.agent_outdir, args.vendor)
if args.gen_env:
    gen_env.gen_env(args.name, args.is_cip, args.has_ral, args.has_interrupts, args.has_alerts,args.num_edn, args.env_agents, args.env_outdir, args.vendor)

gen_agent.py

首先将agent内文件定义成包含元组的列表,按照路径、agent名、文件名和后缀形式保存。

复制代码
agent_srcs = [(agent_dir,               name + '_', 'if',            '.sv'),
              (agent_dir,               name + '_', 'item',          '.sv'),
              (agent_dir,               name + '_', 'agent_cfg',     '.sv'),
              (agent_dir,               name + '_', 'agent_cov',     '.sv'),
              (agent_dir,               name + '_', 'monitor',       '.sv'),
              (agent_dir,               name + '_', 'driver',        '.sv'),
              (agent_dir,               name + '_', 'host_driver',   '.sv'),
              (agent_dir,               name + '_', 'device_driver', '.sv'),
              (agent_dir,               name + '_', 'agent_pkg',     '.sv'),
              (agent_dir,               name + '_', 'agent',         '.sv'),
              (agent_dir,               name + '_', 'agent',         '.core'),
              (agent_dir,               "",         'README',        '.md'),
              (agent_dir + "/seq_lib",  name + '_', 'seq_list',      '.sv'),
              (agent_dir + "/seq_lib",  name + '_', 'base_seq',      '.sv')]

然后通过for循环读出,使用mako组件,根据名称找到同路径下预存的.tpl模板,然后在模板文件中替换名称。

复制代码
for tup in agent_srcs:
    path_dir = tup[0]
    src_prefix = tup[1]
    src = tup[2]
    src_suffix = tup[3]

    ftpl = src + src_suffix + '.tpl'
    fname = src_prefix + src + src_suffix

    # read template
    tpl = Template(filename=str(importlib.resources.files('uvmdvgen') / ftpl))
    with open(path_dir + "/" + fname, 'w') as fout:
        fout.write(
            tpl.render(name=name,
                       has_separate_host_device_driver=
                       has_separate_host_device_driver,
                       vendor=vendor))

实际替换过程均在模板中实现,以driver.sv.tpl为例,模板就是空的,所以生成agent也是空文件,如有一些通用需求,可以直接修改.tpl模板。

复制代码
class ${name}_driver extends dv_base_driver #(.ITEM_T(${name}_item),
                                              .CFG_T (${name}_agent_cfg));
  `uvm_component_utils(${name}_driver)

  // the base class provides the following handles for use:
  // ${name}_agent_cfg: cfg

gen_env.py

和gen_agent.py相似,替换过程均在模板中实现,env的模板更复杂一些,所以生成出来的不是空文件,以env.sv.tpl为例,会根据agent列表for循环生成集成的代码。例如有添加ref model的需求,直接修改模板文件即可。

复制代码
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
% for agent in env_agents:
    // create components
    m_${agent}_agent = ${agent}_agent::type_id::create("m_${agent}_agent", this);
    uvm_config_db#(${agent}_agent_cfg)::set(this, "m_${agent}_agent*", "cfg", cfg.m_${agent}_agent_cfg);
    cfg.m_${agent}_agent_cfg.en_cov = cfg.en_cov;
% endfor
  endfunction

总结

脚本定位还是生成模板,不能直接运行,agent也只是壳子,需要再人工完成。不过毕竟不是专门生成环境的工具,实现过程比较清晰,适合写平台脚本参考。

参考
UVM验证环境生成工具-Open Titan UVM Generator - SOC验证工程师 - 博客园

相关推荐
白又白、2 个月前
uvm-tlm-sockets
uvm
-interface7 个月前
25届数字IC验证秋招总结
秋招·uvm·ic验证
啄缘之间7 个月前
17. 示例:用assert property检查FIFO空满标志冲突
学习·fpga开发·verilog·uvm·sv
啄缘之间8 个月前
7. 覆盖率:covergroup/coverpoint/cross
学习·测试用例·verilog·uvm·sv
啄缘之间8 个月前
4. 示例:创建带约束的随机地址生成器(范围0x1000-0xFFFF)
学习·测试用例·verilog·uvm·sv
啄缘之间8 个月前
4.6 学习UVM中的“report_phase“,将其应用到具体案例分为几步?
学习·verilog·uvm·sv
啄缘之间8 个月前
3.9 学习UVM中的uvm_env类分为几步?
学习·verilog·uvm·sv
啄缘之间8 个月前
3.3 学习UVM中的uvm_driver 类分为几步?
学习·测试用例·verilog·uvm
啄缘之间8 个月前
verilog练习:i2c slave 模块设计
学习·fpga开发·verilog·uvm