UVM_COOKBOOK学习【Testbench Architecture】

本文详细介绍了UVM测试平台的架构,包括事务处理器分区、UVM测试平台的构建和连接过程。强调了双顶层架构,其中HDL顶层处理时控、信号级代码,而HVL/TB顶层包含事务级testbench代码。此外,还涵盖了testbench的构建过程,如从test类开始的构建、工厂覆盖、配置对象的使用和虚接口的赋值等。最后,讨论了不同层次的构建和连接过程,以及如何在不同集成级别上重用testbench组件。
摘要由CSDN通过智能技术生成

关注微信公众号摸鱼范式,后台回复COOKBOOK获取COOKBOOK原本和译本 PDF度盘链接

Testbench Architecture

UVM Testbench Architecture

UVM testbench 是使用SystemVerilog(动态)类对象与SystemVerilog(静态)接口和结构化层次结构中的模块交互构建的。层次结构由功能层组成,testbench 的中心是被测设计(DUT)。

事务处理器和testbench层次通常完全由SystemVerilog类构建。然而,这种构造风格只针对SystemVerilog仿真器,从而限制了可移植性。使用SystemVerilog类和SystemVerilog接口的另一种风格架构,可以提高执行引擎之间的可移植性。利用这两个SystemVerilog构造,可以在事务器层中进行自然的分离,将一端分组的事务级通信与另一端分组的时控、信号级通信分开。

SV作为验证语言,其最大优势就是利用interface将软件世界(仿真环境)和硬件世界(RTL代码)剥离开来。我们可以利用SV中高级语言属性的优势构造环境,又可以利用其全面继承于verilog的属性与硬件世界交互。利用SV的这一特点,来剥离环境中的事务级通信与RTL中的信号级通信,这就是验证方法学思考的事情。

事务器分区

将不同的抽象级别划分为类似的功能,就形成了一个Dual Top分区的testbench体系结构,其中一个顶层包含所谓的HDL域中所有的时控的、信号级代码,而另一个所谓的HVL/TB顶层包含所有的事务级testbench域代码。由于事务处理器通常位于两个域,因此它们也必须被划分为两个部分。这两部分是一个BFM接口和一个代理类。BFM接口处理信号级代码,而代理类处理常规事务器将执行的任何其他操作。BFM和代理之间通过函数和任务调用进行通信。

虽然这种双顶层测试平台架构可移植性好,但它也在一定程度上降低了建模灵活性。这主要是因为信号级代码被放置到SystemVerilog接口而不是类中。SystemVerilog类提供了强大的面向对象功能,包括SystemVerilog接口所忽略的继承和多态性。

关于双顶层测试平台架构的更多内容可以参考 https://verificationacademy.com/patterns-library/implementation-patterns/environment-patterns/dual-domain-hierarchy-pattern

UVM testbench构建和连接过程

关于构建UVM testbench的文章描述了配置和构建双顶层可移植测试台的所有层的过程。本文提供了一些示例来说明如何构建块级testbench,以及如何将多个块级testbench集成到更高级别的testbench中。

构建UVM Testbench

UVM testbench的首个phase是build phase。在此phase,组成testbench层次结构的uvm_component类被实例化为对象。例化过程自顶向下,在下一层之前构造和配置层次结构的每一层(延迟构造)。

当在HVL顶层模块的initial块中调用run_test()方法时,UVM testbench将被激活。这个UVM静态方法有一个字符串参数,该参数根据名称定义要运行的test,并通过UVM工厂构造它。然后,UVM通过调用test类的build方法开始build phase。在执行test的build phase期间,将准备各种testbench组件配置对象,并将这些配置对象中的虚接口分配给相关的testbench接口,然后将配置对象放入UVM配置数据库中。随后,构建下一层次结构。

这里简要提一下,UVM工厂机制的两大属性,一个是override,而另一个就是根据字符串实例化一个类,也就是上面说到的根据输入的test name,run_test去实例化验证环境开始仿真。再重复一点,所谓UVM配置数据库,就是放置所有config_db传递的属性的地方,而config_db的机制在UVM_basics中已经介绍过了。

在层次结构的下一层,将检索上一层准备的相应配置对象,并可能进行进一步的配置。在使用此配置对象来指导下一层次结构的构造和配置之前,可以在当前层次结构中修改它。(这也就是说控制是逐级的,上一层可以修改再往上的层级给以下层级的配置)这样的条件构造就会影响testbench的层次结构。

build phase是自顶向下工作的,因此对testbench层次结构的每个后续级别执行该过程,直到达到最底层级为止。

在build phase完成后,connect phase开始进行所有组件间的连接。与build phase相反,connect phase自底向上工作,从最底层到testbench层次结构的顶部。在connect phase之后,UVM的其余phase将运行到完成(也是自下而上的),在此基础上将控制传递回testbench模块。

注:UVM_basics中我已经提到过,final_phase其实也是自上而下的。

test是构建过程的起点

UVM testbench的构建过程从test类开始,并自顶向下工作。test类构建方法是在build phase第一个被调用的方法,它(即方法实现)决定在UVM testbench上构建什么。其功能是:

  • 设置工厂覆盖,以便根据需要将配置对象或组件对象创建为其派生类型
  • 创建并配置各个子组件所需的配置对象
  • 通过HDL testbench模块给放入配置空间的虚接口句柄赋值
  • 构建封装的env配置对象,并将其包含到配置空间中
  • 在testbench层次结构中构建test的下层组件,通常是顶层env

对于所有test来说,对于给定的验证环境,在build方法中完成的大部分工作都是相同的,因此建议创建一个test base class,每个test case可以由其扩展。

下面显示的是一个模块级验证环境,用来帮助具体解释test的build过程是如何工作的。这是SPI主机接口DUT的环境,包含两个agent,一个用于APB总线接口,另一个用于SPI接口。关于此示例的build和connect phase的详细描述,请参见“Block Level Testbench Example ”。

Factory Overrides

UVM工厂允许在build过程中用另一个派生类替换其基类。这对于专门化(即定制或扩展)组件行为或配置对象非常有用。必须在构造目标对象之前指定Factory Override,因此在build过程开始时进行Override比较方便。

子组件配置对象

每个容器类组件(如agent或env)都应该有一个配置对象来定义其结构和行为。这些配置对象应该在test的build方法中创建并实现以适应test case的需求。如果子组件的配置很复杂或者很可能更改,那么建议添加一个实现基本(或默认)配置处理的虚函数,然后可以通过在base test类扩展的test case中重写该虚函数来更改配置。

// 
// Class Description: 
// 
// 
class spi_test_base extends uvm_test; 
// UVM Factory Registration Macro 
// 
	`uvm_component_utils(spi_test_base) 
//------------------------------------------ 
// Data Members 
//------------------------------------------ 
//------------------------------------------ 
// Component Members 
//------------------------------------------ 
// The environment class 
	spi_env m_env; 
// Configuration objects 
	spi_env_config   m_env_cfg; 
	apb_agent_config m_apb_cfg; 
	spi_agent_config m_spi_cfg; 
//------------------------------------------ 
// Methods 
//------------------------------------------ 
// Standard UVM Methods: 
	extern function new(string name = "spi_test_base", uvm_component parent = null); 
	extern function void build_phase( uvm_phase phase ); 
	extern virtual function void configure_apb_agent(apb_agent_config cfg);
	extern function void set_seqs(spi_vseq_base seq);
        
endclass: spi_test_base 
        
function spi_test_base::new(string name = "spi_test_base", uvm_component parent = null);
  super.new(name, parent); 
endfunction 
// Build the env, create the env configuration 
// including any sub configurations 
function void spi_test_base::build_phase(uvm_phase phase); 
// env configuration 
	m_env_cfg = spi_env_config::type_id::create("m_env_cfg"); 
// APB configuration 
	m_apb_cfg = apb_agent_config::type_id::create("m_apb_cfg"); 
	configure_apb_agent(m_apb_cfg); 
	m_env_cfg.m_apb_agent_cfg = m_apb_cfg; 
// The SPI is not configured as such 
	m_spi_cfg.has_functional_coverage = 0; 
	m_env_cfg.m_spi_agent_cfg = m_spi_cfg; 
	uvm_config_db #(spi_env_config)::set(this, "*", "spi_env_config", m_env_cfg); 
	m_env = spi_env::type_id::create("m_env", this);
endfunction: build_phase
function void spi_test_base::set_seqs(spi_vseq_base seq);
  seq.m_cfg = m_env_cfg; 
  seq.spi = m_env.m_spi_agent.m_sequencer; 
endfunction

从配置空间赋值虚接口

在调用UVM run_test()方法之前,必须通过将 DUT 的顶层 I/O 上的信号连接到 SystemVerilog interface类型的的pin接口上来建立信号的连接。然后pin接口被连接到(driver和monitor)BFM接口,每个BFM接口的句柄由一个虚接口句柄赋值,这个虚接口句柄通过uvm_config_db::set调用传递给test。详细信息请参阅虚接口的文章。

在test的build()方法中,这些虚接口句柄将被分配给相关组件配置对象中的虚接口句柄。然后,各个组件访问其配置对象中的虚接口句柄,通过方法调用来驱动或监视DUT。为了保持组件的模块化和可重用性,driver和monitor不应该直接从配置空间检索它们的虚接口句柄,而只从它们的配置对象中检索。test类中是确保通过配置对象将虚接口赋值给相应验证组件的正确位置。

以下代码显示了在 SPI testbench示例中使用 uvm_config_db::get 方法对 apb_agent 配置对象中的虚拟接口句柄进行赋值:

// The build method from earlier, adding the apb agent virtual interface assignment 
// Build the env, create the env configuration including any sub configurations and 
// assign virtual interfaces 
function void spi_test_base::build_phase( uvm_phase phase ); 
  // Create env configuration object 
	m_env_cfg = spi_env_config::type_id::create("m_env_cfg"); 
  // Call function to configure the env 
	configure_env(m_env_cfg); 
  // Create apb agent configuration object 
	m_apb_cfg = apb_agent_config::type_id::create("m_apb_cfg"); 
  // Call function to configure the apb_agent 
	configure_apb_agent(m_apb_cfg); 
  // Add the APB driver BFM virtual interface 
    if ( !uvm_config_db #(virtual apb_driver_bfm)::get(this, "", "APB_drv_bfm", m_apb_cfg.drv_bfm ) ) `uvm_error(...) 
// Add the APB monitor BFM virtual interface 
	if ( !uvm_config_db #(virtual apb_monitor_bfm)::get(this, "", "APB_mon_bfm", 
	m_apb_cfg.mon_bfm ) ) `uvm_error(...)
    ... 
endfunction: build_phase

嵌入子组件配置对象

配置对象从test通过UVM组件配置空间传递给子组件。它们可以单独传递,使用uvm_config_db::set方法中的path参数来控制哪些组件可以访问这些对象。然而,一个常见的需求是中间组件也需要做一些本地配置。

因此,通过testbench层次结构传递配置对象的一种有效方法是将配置对象以反映层次结构本身的方式嵌入到另一个配置对象中。在testbench上的每个中间级别,该级别的配置对象都被“展开”,以产生它的子配置对象,这些子配置对象被重新配置(如果有必要的话),然后使用uvm_config_db::set传递给相关的子组件。

依据层级嵌套配置对象是一种不错的整合方式,但是笔者觉得逐级传递可以选择直接逐级赋值配置对象句柄的方式,而没有必要调用uvm_config_db::set方法。对于封装好有复用需求的UVC,上文的这种方式无疑是最好的传递方式,所有配置的选择修改都放到test层进行。但是注意:若你的容器类组件并非是复用的最小单元,那么最好不要选用逐级传递的方式来配置以免影响复用。仍然可以依据层级嵌套配置对象,但是均在test层分别set到相应层级,相应层级组件内分别get即可。我觉得这可能是是比较适合复用的方式,灵活性极高。(也可与根据个人需求来在顶层组件中来进行底层组件配置对象的非直线获取)

按照SPI模块级环境示例,每个agent都有一个单独的配置对象。env配置对象有每个agent配置对象的句柄。在测试中,从test case的角度构造和配置所有三个配置对象,并将agent配置对象赋值给env配置对象中的相应agent配置对象句柄。随后,将env配置对象添加到配置空间中,以便在稍后构建env时检索。

对于更复杂的环境,则需要额外的封装级别。

// 
// Configuration object for the spi_env: 
// 
// 
// Class Description: 
// 
// 
class spi_env_config extends uvm_object; 
// UVM Factory Registration Macro 
// 
	`uvm_object_utils(spi_env_config) 
//------------------------------------------ 
// Data Members 
//------------------------------------------ 
// Whether env analysis components are used: 
	bit has_functional_coverage = 0; 
	bit has_spi_functional_coverage = 1; 
	bit has_reg_scoreboard = 0; 
	bit has_spi_scoreboard = 1; 
// Configurations for the sub_components 
	apb_config       m_apb_agent_cfg; 
	spi_agent_config m_spi_agent_cfg; 
//------------------------------------------ 
// Methods 
//------------------------------------------ 
	extern function new(string name = "spi_env_config"); 
endclass: spi_env_config 
        
function spi_env_config::new(string name = "spi_env_config"); 
super.new(name); 
endfunction 
// 
/
  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Table of Contents Articles Introduction 0 Cookbook/Introduction 0 Cookbook/Acknowledgements 1 Testbench Architecture 2 Testbench 2 Testbench/Build 9 Testbench/Blocklevel 19 Testbench/IntegrationLevel 29 Component 39 Agent 42 Phasing 48 Factory 53 UsingFactoryOverrides 56 SystemVerilogPackages 62 Connections to DUT Interfaces 65 Connections 65 SVCreationOrder 71 Connect/SystemVerilogTechniques 73 ParameterizedTests 75 Connect/Virtual Interface 78 Config/VirtInterfaceConfigDb 86 Connect/VirtInterfacePackage 90 Connect/VirtInterfaceConfigPkg 93 Connect/TwoKingdomsFactory 97 DualTop 103 VirtInterfaceFunctionCallChain 106 BusFunctionalModels 108 ProtocolModules 111 Connect/AbstractConcrete 115 Connect/AbstractConcreteConfigDB 118 Configuring a Test Environment 126 Configuration 126 Resources/config db 131 Config/Params Package 134 Config/ConfiguringSequences 139 ResourceAccessForSequences 142 MacroCostBenefit 145 Analysis Components & Techniques 146 Analysis 146 AnalysisPort 149 AnalysisConnections 152 MonitorComponent 158 Predictors 161 Scoreboards 163 MetricAnalyzers 170 PostRunPhases 172 Matlab/Integration 175 End Of Test Mechanisms 183 EndOfTest 183 Objections 185 Sequences 188 Sequences 188 Sequences/Items 193 Transaction/Methods 195 Sequences/API 200 Connect/Sequencer 204 Driver/Sequence API 206 Sequences/Generation 213 Sequences/Overrides 221 Sequences/Virtual 223 Sequences/VirtualSequencer 231 Sequences/Hierarchy 237 Sequences/SequenceLibrary 242 Driver/Use Models 246 Driver/Unidirectional 247 Driver/Bidirectional 250 Driver/Pipelined 255 Sequences/Arbitration 267 Sequences/Priority 276 Sequences/LockGrab 277 Sequences/Slave 284 Stimulus/Signal Wait 290 Stimulus/Interrupts 294 Sequences/Stopping 301 Sequences/Layering 302 Register Abstraction Layer 308 Registers 308 Registers/Specification 315 Registers/Adapter 317 Registers/Integrating 321 Registers/Integration 327 Registers/RegisterModelOverview 332 Registers/ModelStructure 334 Registers/QuirkyRegisters 344 Registers/ModelCoverage 349 Registers/BackdoorAccess 354 Registers/Generation 357 Registers/StimulusAbstraction 358 Registers/MemoryStimulus 370 Registers/SequenceExamples 375 Registers/BuiltInSequences 382 Registers/Configuration 386 Registers/Scoreboarding 389 Registers/FunctionalCoverage 395 Testbench Acceleration through Co-Emulation 401 Emulation 401 Emulation/SeparateTopLevels 404 Emulation/SplitTransactors 410 Emulation/BackPointers 415 Emulation/DefiningAPI 419 Emulation/Example 422 Emulation/Example/APBDriver 430 Emulation/Example/SPIAgent 435 Emulation/Example/TopLevel 441 Debug of SV and UVM 444 BuiltInDebug 444 Reporting/Verbosity 455 UVM/CommandLineProcessor 460 UVM Connect - SV-SystemC interoperability 464 UvmConnect 464 UvmConnect/Connections 466 UvmConnect/Conversion 468 UvmConnect/CommandAPI 472 UVM Express - step by step improvement 476 UvmExpress 476 UvmExpress/DUT 481 UvmExpress/BFM 485 UvmExpress/WritingBfmTests 490 UvmExpress/FunctionalCoverage 498 UvmExpress/ConstrainedRandom 503 Appendix - Deployment 516 OVM2UVM 516 OVM2UVM/DeprecatedCode 527 OVM2UVM/SequenceLibrary 528 OVM2UVM/Phasing 530 OVM2UVM/ConvertPhaseMethods 535 UVC/UvmVerificationComponent 537 Package/Organization 548 Appendix - Coding Guidelines 555 SV/Guidelines 555 UVM/Guidelines 569 Appendix - Glossary of Terms 579 Doc/Glossary 579
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值