前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【UVM COOKBOOK】配置test环境

【UVM COOKBOOK】配置test环境

作者头像
空白的贝塔
发布2021-09-08 11:48:26
6130
发布2021-09-08 11:48:26
举报
文章被收录于专栏:摸鱼范式摸鱼范式

不想错过我的推送,记得右上角-查看公众号-设为星标,摘下星星送给我

欢迎大家加入2022届数字IC交流群,QQ群号 1060380138

PDF获取

后台回复COOKBOOK,即可获取PDF笔记以及原版COOKBOOK

后台回复即可获取

配置test环境

Testbench配置

概述

介绍

设计可重用testbench的关键原则之一是使其尽可能可配。这就意味着testbench及其组成部分可以很容易地重用和快速修改(即重新配置)。在testbench中,有任意数量的值通常可以写成文本值,如for循环次数、字符串名称、随机权重、其他约束表达式值和coverage bin值。这些值可以用SystemVerilog变量表示,可以在运行时设置(和更改),也可以用SystemVerilog参数表示,但必须在elaboration时设置。由于它们提供的灵活性,应始终在可能的情况下构建存放这些属性的配置对象并使用 uvm_config_db API 访问。

另一方面,像总线宽度这样的,必须在细化时确定,因此就不能通过动态配置对象实现。有许多关于在UVM中处理静态参数的文章:

  • 参数化test文章说明如何对UVM工厂使用参数化测试。
  • Parameters Package一文展示了如何集中在HDL/DUT和HVL/TB域之间共享的参数。
  • 参数和重用一文展示了如何通过uvm_component层次结构向下传递大量参数。
配置对象

配置对象是组织配置变量的一种有效的、可重用的方法。在一个典型的testbench中,通常会有几个配置对象,每个对象都绑定到一个组件。配置对象被创建为uvm_object的子类,以封装testbench层次结构的给定分支的所有相关配置变量。也可能有一个单独的、附加的配置对象来保存全局配置变量。配置对象中的每个配置变量都可以声明为rand,因此配置对象可以被随机化。

UVM配置数据库可以有效地处理用户定义的配置对象的范围和存储。下面是典型agent配置对象的代码。它具有指向driver和monitor与agent关联的BFM接口的虚接口,以及描述和控制这些BFM的许多变量。

代码语言:javascript
复制
// configuration class 
class wb_config extends uvm_object; 
 `uvm_object_utils( wb_config ); 
// Configuration Parameters 
 virtual wb_m_bus_driver_bfm wb_drv_bfm; // virtual driver BFM
 virtual wb bus monitor bfm  wb mon bfm; // virtual monitor BFM 

 int m_wb_id;                 // Wishbone bus ID 
 int m wb master id;          // Wishbone bus master id for wishone agent
 int m mac id;                // id of MAC WB master

 int unsigned m_mac_wb_base_addr;  // Wishbone base address of MAC 
    bit [47:0]  m_mac_eth_addr;       // Ethernet address of MAC 
    bit [47:0]  m_tb_eth_addr;        // Ethernet address of testbench for sends/receives

 int m mem slave size;       // Size of slave memory in bytes
 int unsigned m_s_mem_wb_base_addr; // base address of wb memory for MAC frame buffers 
 int m_mem_slave_wb_id;  // Wishbone ID of slave memory
 int m_wb_verbosity;  // verbosity level for wishbone messages 
    
 function new( string name = "" ); 
  super.new( name ); 
 endfunction 
endclass
使用配置对象

任何使用配置对象的组件都应该执行以下步骤:

  • 如果配置对象句柄为空(即尚未在外部设置),则检索其配置。
  • 创建其内部结构并基于配置定义其行为
  • 配置其子组件

test组件作为顶层组件,从test参数package或UVM配置数据库(例如虚接口句柄)获取配置值。然后为环境中的组件设置特定于test的配置变量。

代码语言:javascript
复制
class test_mac_simple_duplex extends uvm_test; 
 ... 
 wb_config wb_config_0; // config object for WISHBONE BUS
 function void set_wishbone_config_params(); 
// set configuration info 
// NOTE  The MAC is WISHBONE slave 0, mem_slave_0 is WISHBONE slave 1 
// MAC is WISHBONE master 0, wb_master is WISHBONE master 1 
  wb_config_0 = new(); 
        if (!uvm_config_db #(virtual wb_m_bus_driver_bfm)::get(this, "", "WB_DRV_BFM", wb_config_0.wb_drv_bfm)) 
   `uvm_fatal(...) 
  if (!uvm_config_db #(virtual wb_bus_monitor_bfm)::get(this, "", "WB_MON_BFM", wb_config_0.wb_mon_bfm))
   `uvm_fatal(...) 
  wb_config_0.m_wb_id = 0; // WISHBONE 0
  wb_config_0.m_mac_id = 0;  // the ID of the MAC master
  wb_config_0.m_mac_eth_addr = 48'h000BC0D0EF00; 
  wb_config_0.m_mac_wb_base_addr = 32'h00100000; 
  wb_config_0.m_wb_master_id = 1; // the ID of the wb master
  wb_config_0.m_tb_eth_addr = 48'h000203040506; 
  wb_config_0.m_s_mem_wb_base_addr = 32'h00000000; 
  wb_config_0.m_mem_slave_size = 32'h00100000; // 1 Mbyte
  wb_config_0.m_mem_slave_wb_id = 0; // the ID of slave mem
  wb_config_0.m_wb_verbosity = 350; 
  uvm_config_db #(wb_config)::set(this, "*", "wb_config", wb_config_0); 
 endfunction 
 ... 
 function void build_phase(uvm_phase); 
  set_wishbone_config_params(); 
  ... 
 endfunction 
 ... 
endclass

注意,如果在UVM配置数据库中没有找到虚接口,则使用`uvm_fatal()。这将立即停止test,并将给定的消息传递给`uvm_fatal()调用。可以选择将这些`uvm_fatal()消息转换为`uvm_error()消息,以便在停止之前使testbench运行更久。

要么直接将配置对象传递给使用配置对象的组件,要么使用uvm_config_db::get获取配置对象。在本例中,driver从配置对象获取虚接口句柄、ID和详细信息。注意BFM不是uvm_components。因此,driver和/或monitor代理可能还需要通过函数调用将相关的配置数据传递给BFM。一次函数调用通常足以一次传递所有数据,从而最小化调用开销。

代码语言:javascript
复制
class wb_m_bus_driver extends uvm_driver #(wb_txn, wb_txn); 
 ... 
 local virtual wb_m_bus_driver_bfm m_bfm; // Virtual Interface
 wb_config m_cfg; 
 function void build_phase( uvm_phase phase ); 
  if (m_config == null) 
   if( !uvm_config_db #( wb_config )::get( this , "" , "wb_config" , m_cfg ) )    begin 
    `uvm_fatal(...) 
   end 
  m_bfm = m_cfg.wb_drv_bfm; // set local virtual if property
  ... 
 endfunction 
 function void connect_phase( uvm_phase phase ); 
  super.connect_phase( phase ); 
  m_bfm.set_m_id(m_config.m_wb_master_id); //Set config value in BFM
 endfunction 
 function void end_of_elaboration(); 
  set_report_verbosity_level_hier(m_config.m_wb_wb_verbosity); 
 endfunction 
 ... 
endclass 
配置sequence

下文有关于配置sequence的单独章节。

配置DUT连接

建立HDL-to-Testbench连接始终是一种必需的配置活动。SystemVerilog模块(通常是HDL端顶层模块,有时是更精细的模块封装级别)必须将虚接口添加到配置空间中。在HVL Testbench端,test组件从UVM配置数据库中检索相关的虚接口句柄,并将它们应用到适当的配置对象中:

代码语言:javascript
复制
class test_mac_simple_duplex extends uvm_test; 
 ... 
 function void set_wishbone_config_params(); 
  wb_config_0 = new(); 
// Get the virtual interface handle that was set in the top module or protocol module 
  if (!uvm_config_db #(virtual wb_m_bus_driver_bfm)::get(this, "", "WB_DRV_BFM", wb_config_0.wb_drv_bfm)) 
   `uvm_fatal(...) 
  if (!uvm_config_db #(virtual wb_bus_monitor_bfm)::get(this, "", "WB_MON_BFM", wb_config_0.wb_mon_bfm)) 
   `uvm_fatal(...) 
  ... 
  uvm_config_db #( wb_config )::set(this , "*", "wb_config", wb_config_0, 0); // put in config
 endfunction 
 ... 
endclass

配置sequence

一个可配置的sequence

配置sequence最通用的方法是默认使用其完整的层次名称,但允许根据需要设置任何其他名称:

代码语言:javascript
复制
class my_bus_seq extends uvm_sequence #( my_bus_sequence_item ); 
 string scope_name = ""; 
 task body(); 
  my_bus_config m_config; 
  if( scope_name == "" ) begin 
  scope_name = get_full_name(); // this is {sequencer.get_full_name() , get_name() } 
  end 
  if( !uvm_config_db #( my_bus_config )::get( null , scope_name , "my_bus_config" , m_config ) ) begin 
   `uvm_error(...) 
  end 
 endtask 
endclass

考虑一个名为“initialization_sequence”的sequence运行在sequencer“uvm_test_top.env.sub_env.agent1.sequencer”上。上面代码中的scope_name默认设置为"uvm_test_top.env.sub_env.agent1.sequencer.initialization_sequence"。

sequence配置最常见的用例是为agent及其组成组件(sequencer、driver、monitor……)获取agent的配置对象集。

代码语言:javascript
复制
class sub_env extends uvm_env; 
 ... 
 function void build_phase( uvm_phase phase ); 
  ... 
  my_bus_config agent1_config; 
  ... 
  uvm_config_db #( my_bus_config )::set( this , "agent1*" , "my_bus_config" , agent1_config ); 
  ... 
 endfunction 
 task main_phase( uvm_phase phase ); 
  my_bus_sequence seq = my_bus_sequence::type_id::create("my_bus_sequence"); 
  seq.start( agent1.sequencer ); 
 endtask 
 ... 
endclass 

使用sub_env作为context,可配置sequence中的set()调用和默认get()调用将匹配并致使sequence能够访问agent的配置对象。

每个sequence配置

上面可配置sequence类的缺省完整层次作用域名称可以用来唯一地标识多个sequence实例,从而使它们服从不同的单独配置,而所需要的只是sequence的给定实例名不同。

例如,环境类可能像这样:

代码语言:javascript
复制
class sub_env extends uvm_env; 
 ... 
 function void build_phase( uvm_phase phase ); 
  ... 
  my_bus_config agent1_config, agent1_error_config; 
  ... 
  agent1_config.enable_error_injection = 0; 
  agent1_error_config.enable_error_injection = 10; 
// most sequences do not enable error injection 
  uvm_config_db #( my_bus_config )::set( this , "agent1*" , "my_bus_config" , agent1_config ); 
// sequences with "error" in their name will enable error injection 
  uvm_config_db #( my_bus_config )::set( this , "agent1.sequencer.error*" , "my_bus_config" , agent1_error_config ); 
  ... 
 endfunction 
 task main_phase( uvm_phase phase ); 
  my_bus_sequence normal_seq = my_bus_sequence::type_id::create("normal_seq"); 
  my_bus_sequence error_seq = my_bus_sequence::type_id::create("error_seq"); 
  normal_seq.start( agent1.sequencer ); 
        error_seq.start( agent1.sequencer ); 
 endtask 
 ... 
endclass 

由于可配置sequence类使用给定的sequence名执行config_db get()调用,正常sequence将选择禁用错误注入的配置对象,而error_sequence将选择error配置对象。

完全忽略组件层次结构

也可以完全忽略sequence配置的组件层次结构。这样做的好处是,实际上可以定义仅用于配置sequence的行为作用域,并使这些行为作用域与组件层次结构完全分离。上面描述的可配置sequence在这个场景中也可以使用。

例如,在virtual sequence 中:

代码语言:javascript
复制
class my_virtual_sequence extends uvm_sequence #( uvm_sequence_item_base ); 
 ... 
 task body(); 
  my_bus_sequence normal_seq = my_bus_sequence::type_id::create("normal_seq"); 
  my_bus_sequence error_seq = my_bus_sequence::type_id::create("error_seq"); 
  normal_seq.scope_name = "sequences::my_bus_config.no_error_injection"; 
  error_seq.scope_name = "sequences::my_bus_config.enable_error_injection"; 
  normal_seq.start( agent1.sequencer ); 
  error_seq.start( agent1.sequencer ); 
 endtask 
 ... 
endclass 

这种增加灵活性的使用模型缺点是,testbench上的每个sequence和组件必须就命名方案达成一致,或者至少能够处理这种任意命名方案。由于不再保证作用域名称的唯一性,当从模块级转换到集成级testbench时,可能会面临一些重用挑战。

使用Parameter Package

当参数化DUT或接口时,参数值几乎总是在testbench上使用。由于这个原因,我们不应该用实例声明的直接文本值特定化这些公共参数。而是在一个Package中定义相应的命名参数和相关的值,由环境的HDL/DUT端和testbench端共享。这极大地帮助我们避免了这样的错误,即参数值在一边发生了改变,而在另一边却没有发生改变,或者test配置参数是DUT参数的某个函数,而在进行改变时可能会导致计算错误。

请注意,此“共享package”不必是放置所有test参数的地方。不适用和被DUT使用的test参数可以直接在test中特定化。共享参数package应仅包含在 HDL/DUT 和 HVL/TB 域之间共享的参数。

参数package的使用示例

下面的WISHBONE示例涉及两个WISHBONE总线设备、从机存储器和一个以太网MAC(媒体访问控制器)。参数被放在一个包test_params_pkg中,并在实例化HDL顶层模块中的WISHBONE设备和testbench端的test类中使用。

代码语言:javascript
复制
// MAC WISHBONE parameters 
 parameter mac m wb id = 0;        // WISHBONE bus master id of MAC
 parameter mac_slave_wb_id = 1;    // WISHBONE bus slave id of MAC

endpackage

下面展示了在HDL top模块中使用参数mem_slave_size和mem_slave_wb_id实例化WISHBONE总线从机内存模块。注意,在top_mac_hdl模块中导入了test_params_pkg:

代码语言:javascript
复制
module hdl_top_mac; 
 ... 
 import test_params_pkg::*; 
// WISHBONE interface instance 
// Supports up to 8 masters and up to 8 slaves 
 wishbone_master_bfm  wb_mstr_bfm(wb_bus_if); 
 wishbone_bus_syscon_if wb_bus_if(); 
//----------------------------------- 
// WISHBONE 0, slave 0: 000000 - 0fffff 
// this is 1 Mbytes of memory 
wb_slave_mem #(mem_slave_size) wb_s_0 ( 
// inputs 
.clk ( wb_bus_if.clk ), 
.rst ( wb_bus_if.rst ), 
.adr ( wb_bus_if.s_addr ), 
.din ( wb_bus_if.s_wdata ), 
.cyc ( wb_bus_if.s_cyc ), 
.stb ( wb_bus_if.s_stb[mem_slave_wb_id]  ), 
.sel ( wb_bus_if.s_sel[3:0] ), 
.we ( wb_bus_if.s_we ), 
// outputs 
.dout( wb_bus_if.s_rdata[mem_slave_wb_id] ), 
.ack ( wb_bus_if.s_ack[mem_slave_wb_id]  ), 
.err ( wb_bus_if.s_err[mem_slave_wb_id]  ), 
.rty ( wb_bus_if.s_rty[mem_slave_wb_id]  ) 
); 
 ... 
endmodule 

testbench的test类中用于设置WISHBONE总线从机内存配置对象值的参数使用如下所示。注意,不是使用数字字面值32'h00100000,而是使用包含命名DUT参数mem_slave_size的表达式来赋值地址值。

代码语言:javascript
复制
package tests_pkg; 
 ...
 import test_params_pkg::*; 
 ... 
 `include "test_mac_simple_duplex.svh" 
endpackage 
//----------------------------------------------------------------- 
class test_mac_simple_duplex extends uvm_test; 
 ... 
 wb_config wb_config_0; // config object for WISHBONE BUS
 ... 
 function void set_wishbone_config_params(); 
//set configuration info 
 wb_config_0 = new(); 
 wb_config_0.m_s_mem_wb_base_addr = mem_slave_wb_id * slave_addr_space_sz; // base address of slave mem
 wb_config_0.m_mem_slave_size = 2**(mem_slave_size+2); // defaultis 1 Mbyte 
 wb_config_0.m_mem_slave_wb_id = mem_slave_wb_id; // WISHBONE bus slave id of slave mem 
 ... 
 endfunction 
 ... 
endclass 

多个实例

在参数集有多个实例的情况下,可以使用基于实例助记符的命名约定来区分实例,或者使用基于参数化类的方法来通过参数特定化区分参数集。

注意,现在存在两个Wishbone从机mem实例。每个都有自己的特定化参数。这是通过指定参数及其默认值的参数化类来处理的。然后,通过使用typedef创建特定化的参数化类,为每个实例设置实际的参数值。

代码语言:javascript
复制
package test_params_pkg; 
 import uvm_pkg::*; 
// WISHBONE general slave parameters 
 parameter slave_addr_space_sz = 32'h00100000; 
// WISHBONE slave memory parameters 
 class WISHBONE_SLAVE #(int mem_slave_size = 18, int mem_slave_wb_id = 0); 
 endclass 
// Specializations for each slave memory instance 
 typedef WISHBONE_SLAVE #(18, 0) WISHBONE_SLAVE_0; 
 typedef WISHBONE SLAVE #(18, 1) WISHBONE SLAVE 1;
// MAC WISHBONE parameters
 parameter mac m wb id = 0;     // WISHBONE bus master id of MAC
 parameter mac_slave_wb_id = 2; // WISHBONE bus slave id of MAC
endpackage

要在上述代码中使用特定化 WISHBONE_SLAVE_0 或 WISHBONE_SLAVE_1 的参数 mem_slave_size 和 mem_slave_wb_id,请使用以下语法:name_of_specialization::parameter_name,如下图所示。

代码语言:javascript
复制
module hdl_top_mac; 
 ... 
 import test_params_pkg::*; 
// WISHBONE interface instance 
// Supports up to 8 masters and up to 8 slaves 
 wishbone_master_bfm wb_mstr_bfm(wb_bus_if); 
 wishbone_bus_syscon_if wb_bus_if(); 
//----------------------------------- 
// WISHBONE 0, slave 0: 000000 - 0fffff 
// this is 1 Mbytes of memory 
wb_slave_mem #(WISHBONE_SLAVE_0::mem_slave_size) wb_s_0 ( 
// inputs 
.clk ( wb_bus_if.clk ), 
.rst ( wb_bus_if.rst ), 
.adr ( wb_bus_if.s_addr ), 
.din ( wb_bus_if.s_wdata ), 
.cyc ( wb_bus_if.s_cyc ), 
.stb ( wb_bus_if.s_stb [WISHBONE_SLAVE_0::mem_slave_wb_id] ), 
.sel ( wb_bus_if.s_sel[3:0] ), 
.we ( wb_bus_if.s_we ), 
// outputs 
.dout( wb_bus_if.s_rdata[WISHBONE_SLAVE_0::mem_slave_wb_id] ), 
.ack ( wb_bus_if.s_ack [WISHBONE_SLAVE_0::mem_slave_wb_id] ), 
.err ( wb_bus_if.s_err [WISHBONE_SLAVE_0::mem_slave_wb_id] ), 
.rty ( wb_bus_if.s_rty [WISHBONE_SLAVE_0::mem_slave_wb_id] ) 
); 
 ... 
endmodule 

从sequence中访问配置资源

sequence通常需要访问testbench资源,如寄存器模型或配置对象。这最好使用uvm_config_db来检索资源,作为被其他sequence扩展的sequence基类的body()方法的第一个操作。

uvm_config_db可以通过几种方式访问资源:

  • 使用m_sequencer句柄访问资源
代码语言:javascript
复制
// Resource access using m_sequencer: 
spi_env_config m_cfg; 
task body(); 
 if(!uvm_config_db #(spi_env_config)::get(m_sequencer, "", "spi_env_config", m_cfg))  begin 
  `uvm_error("BODY", "spi_env_config config_db lookup failed") 
 end 
endtask: body 
  • 使用sequence的get_full_name()调用访问资源
代码语言:javascript
复制
// Resource access using get_full_name(): 
spi_env_config m_cfg; 
task body(); 
 if(!uvm_config_db #(spi_env_config)::get(null, get_full_name(), "spi_env_config", m_cfg)) begin 
  `uvm_error("BODY", "spi_env_config config_db lookup failed") 
 end 
endtask: body 
  • 当资源未绑定到组件层次结构时,使用作用域字符串访问资源
代码语言:javascript
复制
// Resource access using pre-assigned lookup: 
spi_env_config m_cfg; 
task body(); 
 if(!uvm_config_db #(spi_env_config)::get(null, "SPI_ENV::", "spi_env_config", m_cfg)) 
    begin 
 `uvm_error("BODY", "spi_env_config config_db lookup failed") 
 end 
endtask: body

前两个方法基本上是等价的,因为它们都是基于testbench层次结构中的m_sequencer位置或testbench层次结构中的sequence "伪"位置创建作用域字符串。这两种方法之间的细微差别如下。对于第一个方法,m_sequencer.get_full_name()在m_sequencer作为参数传递给get()调用时被调用,生成testbench层次结构中该sequencer的路径。一个例子是“uvm_test_top.env.my_agent.sequencer”。对于第二个方法,get_full_name()是在sequence上调用的,而不是在sequencer上。如果sequence是在sequencer上启动的(即 m_sequencer 句柄不为空),则此 get_full_name() 调用返回sequencer的路径,并附加sequence名称。这方面的一个例子可能是“uvm_test_top.env.my_agent.sequencer.my_seq”。这对于针对在特定sequencer上运行的特定sequence的特定配置信息很有用。

第三种方法依赖于用户商定的不同配置域的命名约定,该约定可以在特定的项目或工作组中很好地工作,但可能由于名称冲突而导致重用问题。

base sequence实现的完整示例如下所示。派生sequence必须调用base sequence body()方法,以确保在启动激励程序之前设置了资源句柄。

代码语言:javascript
复制
// 
// Sequence that needs to access a testbench resource via the configuration space 
// 
// Note that this is a base class; any class extending it must call super.body() 
// at the start of its body task to get set up 
// 
class register_base_seq extends uvm_sequence #(bus_seq_item); 
 `uvm_object_utils(register_base_seq) 
// Handle for the actual sequencer to be used: 
    bus_sequencer BUS; 
// Handle for the environment configuration object: 
 bus_env_config env_cfg; 
// Handle for the register model 
 dut_reg_model RM; 
 function new(string name = "register_base_seq"); 
  super.new(name); 
 endfunction 
 task body; 
// Get the env configuration object - using get_full_name() 
  if(!uvm_config_db #(bus_env_config)::get(null, get_full_name(), "bus_config", env_cfg)) begin 
   `uvm_error("BODY", "Failed to find bus_env_config in the config_db")
  end 
// Assign a pointer to the register model which is inside the env config object: 
  RM = env_cfg.register_model; 
 endtask: body 
endclass: register_base_seq 
// 
// A derived sequence: 
// 
class initialization_seq extends register_base_seq; 
 `uvm_object_utils(initialization_seq) 
 task body; 
  super.body(); // assign the resource handles
  ... // Sequence body code 
    endtask: body 
endclass: initialization_seq 

使用此技术的另一个示例是访问配置对象中的虚接口以等待硬件事件。

宏 成本-效益 分析

宏在减少小的类似模式的代码段的重复键入、隐藏来自不同供应商的仿真器之间的实现差异或限制、或使关键代码段更不容易出错以便重用等方面都很有用。UVM中的许多宏满足这些条件,但并非全部。虽然宏的好处通常是显而易见且直接的,但与其使用相关的成本通常是不透明的,并且在以后的代码更改变得越来越突发性时可能会出现问题。

在DVCon 2011的一篇题为OVM-UVM Macros-Costs vs Benefits的论文中,对宏的使用进行了详细的探讨。

  • 它会检查一些宏导致的隐藏成本,包括代码膨胀、低性能和调试困难。
  • 它确定哪些宏提供了良好的成本效益权衡,哪些没有。
  • 它展示了如何用简单的SystemVerilog代码替换高成本的宏。

这些建议摘要如下:

关于这篇论文的更多内容可以参考 https://verificationacademy.com/resource/6646

END

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-08-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 摸鱼范式 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • PDF获取
  • 配置test环境
    • Testbench配置
      • 概述
    • 配置sequence
      • 一个可配置的sequence
      • 每个sequence配置
      • 完全忽略组件层次结构
    • 使用Parameter Package
      • 参数package的使用示例
      • 多个实例
      • 从sequence中访问配置资源
      • 宏 成本-效益 分析
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档