我是靠谱客的博主 火星上红酒,最近开发中收集的这篇文章主要介绍UVM学习整理——UVM结构(component派生类)二、UVM结构,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

目录

二、UVM结构

2.1UVM组件

2.1.1uvm_driver

2.1.2uvm_monitor

2.1.3uvm_sequencer

2.1.4uvm_agent

2.1.5uvm_scoreboard

2.1.6reference model

2.1.7uvm_env

2.1.8uvm_test

2.1.9uvm_component相关宏

2.2UVM验证平台的树形结构


二、UVM结构

2.1UVM组件

UVM的组件(uvm_component类)继承于UVM的核心基类中一个核心分支,均可构成验证环境,这是因为它们都从uvm_component类继承了phase机制(必须在build_phase中实例化),都会经历各个phase阶段。主要介绍构成环境的常见组件类:uvm_driver、uvm_monitor、uvm_sequencer、uvm_agent、uvm_scoreboard、uvm_env和uvm_test等。

图 5uvm_component类和子类

2.1.1uvm_driver

所有driver派生自uvm_driver。Driver的功能主要就是向sequencer索要sequence_item(transaction),并通过虚拟接口把sequence_item里的信息驱动到DUT的接口上。相当于完成了transaction级别到DUT能够接受的端口级别信息的转变。

drive使用工厂机制注册类通常需要三步:声明,注册,调用new()函数。

class my_driver extends uvm_driver#(my_transaction);     //my_transaction是sequence item类型

   virtual my_if vif; //virtual interface

   `uvm_component_utils(my_driver)    //在factory中注册my_driver
   function new(string name = "my_driver", uvm_component parent = null);
      super.new(name, parent);
   endfunction

   virtual function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      if(!uvm_config_db#(virtual my_if)::get(this, "", "vif", vif))
         `uvm_fatal("my_driver", "virtual interface must be set for vif!!!")
   endfunction

   extern task main_phase(uvm_phase phase);
   extern task drive_one_pkt(my_transaction tr);
endclass

uvm_driver在uvm_component基础上没有扩展新的函数/任务,而只是扩展了一些用来通信的端口seq_item_port和rsp_port。在构建环境组件时,派生uvm_driver和uvm_sequencer的类,可以直接使用这些成员变量。

如果不想使用自带的成员变量,想加入改动,也可以由uvm_component来派生Driver等组件,然后自行定义uvm_seq_item_pull_port #(REQ, RSP)等类型的变量,名字可以不再是seq_item_port等(源码见附录一)

注:uvm_driver和子类都是参数化类,定义新driver类时,应声明获取的事务参数REQ类型(事务参数)。

2.1.2uvm_monitor

monitor通过虚拟接口收集总线信息,并将数据转换成transation级别的sequence_item,再通过端口将数据发送至其他验证组件。收集的数据可用于简单的功能和时序检查。

所有用户自定义数据监测行为的monitor都继承自uvm_monitor,uvm_monitor继承自uvm_component,从源代码来看并没有增添新的成员和方法,但将monitor类都继承于uvm_monitor有助于实现父类monitor的方法和特性。(源码见附录一)

monitor使用工厂机制注册类通常也需要三步:声明uvm_monitor,向工厂注册并调用new()函数。

class my_monitor extends uvm_monitor;

   virtual my_if vif;

   uvm_analysis_port #(my_transaction)  ap;
   
   `uvm_component_utils(my_monitor)    在factory中注册my_monitor
   function new(string name = "my_monitor", uvm_component parent = null);
      super.new(name, parent);
   endfunction

   virtual function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      if(!uvm_config_db#(virtual my_if)::get(this, "", "vif", vif))
         `uvm_fatal("my_monitor", "virtual interface must be set for vif!!!")
      ap = new("ap", this);
   endfunction

   extern task main_phase(uvm_phase phase);
   extern task collect_one_pkt(my_transaction tr);
endclass

2.1.3uvm_sequencer

所有的sequencer都要派生自uvm_sequencer。功能是组织管理sequence,当driver要求数据时,他就把sequence生成sequence_item转发给driver。同时若需要的话,uvm_sequencer也可以从uvm_driver那里获取随后的RSP对象来得知数据通信是否正常(源码见附录一)。

sequencer使用工厂机制注册:

class my_sequencer extends uvm_sequencer #(my_transaction);    //my_transaction为sequence_item类型
   
   function new(string name, uvm_component parent);
      super.new(name, parent);
   endfunction 
   
   `uvm_component_utils(my_sequencer)    //在factory中注册my_sequencer
endclass

一个Sequencer可以挂载多个不同的sequence,sequencer可以通过内置的方法来选择需要发送的sequence,针对不同的测试条件发送不同的transaction。

2.1.4uvm_agent

将driver,monitor,sequencer封装成一个agent模块,方便复用。uvm_agent与uvm_component相比最大的改动在于引入了一个变量is_active,缺省值是UVM_ACTIVE。处在active模式的agent需要例化driver、monitor和sequencer;而如果is_active的值是UVM_PASSIVE,这表示agent是passive模式,只可以例化monitor。

通过is_active变量,agent需要在build_phase()和connect_phase()等函数中通过选择语句来对driver和sequencer进行有条件的例化和连接(源码见附录一)

class my_agent extends uvm_agent ;
   my_sequencer  sqr;
   my_driver     drv;
   my_monitor    mon;
   
   uvm_analysis_port #(my_transaction)  ap;
   
   function new(string name, uvm_component parent);
      super.new(name, parent);
   endfunction 
   
   extern virtual function void build_phase(uvm_phase phase);
   extern virtual function void connect_phase(uvm_phase phase);

   `uvm_component_utils(my_agent)    //在factory中注册my_agent
endclass 

function void my_agent::build_phase(uvm_phase phase);
   super.build_phase(phase);
   if (is_active == UVM_ACTIVE) begin    //通过选择语句来对driver和sequencer进行有条件的例化。
      sqr = my_sequencer::type_id::create("sqr", this);
      drv = my_driver::type_id::create("drv", this);
   end
   mon = my_monitor::type_id::create("mon", this);
endfunction 

function void my_agent::connect_phase(uvm_phase phase);
   super.connect_phase(phase);
   if (is_active == UVM_ACTIVE) begin    //通过选择语句来对driver和sequencer进行有条件的连接。
      drv.seq_item_port.connect(sqr.seq_item_export);
   end
   ap = mon.ap;
endfunction

2.1.5uvm_scoreboard

一般的scoreboard都要派生自uvm_scoreboard。其功能就是比较reference model和monitor分别发送来的数据,根据比较结果判断DUT是否正确。与uvm_component相比uvm_scoreboard也没有额外的成员变量和方法,但UVM建议用户将检查比较类都继承于uvm_scoreboard,这也便于日后的子类可以自动继承于可能被扩充到uvm_scoreboard中的成员(源码见附录一)

在scoreboard中通常会声明TLM端口供monitor传输数据。

class my_scoreboard extends uvm_scoreboard;
   my_transaction  expect_queue[$];
   uvm_blocking_get_port #(my_transaction)  exp_port;
   uvm_blocking_get_port #(my_transaction)  act_port;

   `uvm_component_utils(my_scoreboard)    //在factory中注册my_scoreboard

   extern function new(string name, uvm_component parent = null);
   extern virtual function void build_phase(uvm_phase phase);
   extern virtual task main_phase(uvm_phase phase);
endclass 

2.1.6reference model

reference model是直接派生自uvm_component。其作用就是模仿DUT,完成与DUT相同的功能,可以直接使用systemverilog的特性,或者可以通过DPI等接口调用其它语言来完成与DUT相同功能,将产生的结果输出到scoreboard进行比较。

2.1.7uvm_env

所有env都要派生自uvm_env,属于uvm_component类,相对于uvm_component类没有做过多扩展。env把验证平台固定不变的component(如agent、reference model、scoreboard和底层env等)封装在一起,并配置各个组件间的通信端口。这样在要运行不同case时,只要在case中实例化此env即可(源码见附录一)

class my_env extends uvm_env;

   my_agent   i_agt;
   my_agent   o_agt;
   my_model   mdl;
   my_scoreboard scb;
   
   uvm_tlm_analysis_fifo #(my_transaction) agt_scb_fifo;
   uvm_tlm_analysis_fifo #(my_transaction) agt_mdl_fifo;
   uvm_tlm_analysis_fifo #(my_transaction) mdl_scb_fifo;
   
   function new(string name = "my_env", uvm_component parent);
      super.new(name, parent);
   endfunction

   virtual function void build_phase(uvm_phase phase);    //在build_phase中实例化组件以及通信管道FIFO
      super.build_phase(phase);
      i_agt = my_agent::type_id::create("i_agt", this);
      o_agt = my_agent::type_id::create("o_agt", this);
      i_agt.is_active = UVM_ACTIVE;
      o_agt.is_active = UVM_PASSIVE;
      mdl = my_model::type_id::create("mdl", this);
      scb = my_scoreboard::type_id::create("scb", this);
      agt_scb_fifo = new("agt_scb_fifo", this);
      agt_mdl_fifo = new("agt_mdl_fifo", this);
      mdl_scb_fifo = new("mdl_scb_fifo", this);

   endfunction

   extern virtual function void connect_phase(uvm_phase phase);
   
   `uvm_component_utils(my_env)    //在factory注册my_env
endclass

2.1.8uvm_test

所有的测试用例都要派生自uvm_test或派生类,属于uvm_component类,相对于uvm_component类也没有做过多扩展。不同的case之间差异很大,所以从uvm_test派生出来的类各不同。任何一个派生的case都要实例化env,只有这样才能正常传数(源码见附录一)

class base_test extends uvm_test;

   my_env         env;
   
   function new(string name = "base_test", uvm_component parent = null);
      super.new(name,parent);
   endfunction
   
   extern virtual function void build_phase(uvm_phase phase);
   extern virtual function void report_phase(uvm_phase phase);

   `uvm_component_utils(base_test)    //在factory中注册base_test
endclass

2.1.9uvm_component相关宏

1.`uvm_component_utils:把一个直接或间接派生自uvm_component的类注册到factory中。

2.`uvm_component_param_utils:把一个直接或间接派生自uvm_component的参数化的类注册到factory中。

3.`uvm_component_utils_begin:用于同时需要factory和field_automation机制注册的类,与uvm_object_utils_begin相似。最大的意义在于可以自动使用config_db得到某些变量的值。

4.`uvm_component_param_utils_begin:用于参数化class实现某些变量field_automation机制。

5.`uvm_component_utils_end:总是与uvm_component_*_begin成对出现,作为factory注册结束的标志。

2.2UVM验证平台的树形结构

UVM通过uvm_component实现验证平台的树形结构,uvm_component在new()时,需要指定一个类型为uvm_component、名字是parent的变量。

仿真过程中,会先执行build_phase()。该phase用于构建uvm-tree的结构,注:uvm_component组件类必须在build_phase中实例化,build_phase()的主要用途就是实例化组件类,创建和配置测试平台的结构,构建tree,典型的UVM树如下图:

一般来说,对组件实例化时,会向parent参数传递指定的父类(如this指针),若传递null,此component的父类将被设置成uvm_top;

env = my_env::type_id::create("env", this);

env = my_env::type_id::create("env", null);

uvm_top是一个全局变量,它是uvm_root的一个实例(也是唯一的一个实例),而uvm_root本质上是一个uvm_component派生自uvm_component,它是UVM树的根。uvm_test_top的parent是uvm_top,而uvm_top的parent是null。

uvm_root的存在可以保证整个验证平台中只有一棵树,所有结点都是uvm_top的子结点。在导入uvm_pkg文件包(import uvm_pkg::*;)时,会自动创建一个顶层类uvm_root所例化的对象uvm_top。

UVM提供了一系列的接口函数用于访问UVM树中的结点,主要的包括:

  1. get_parent:用于得到当前实例的parent;
  2. get_num_children:用于返回当前component所拥有的child的数量;
  3. get_child:用于得到当前实例child。此函数需要一个string类型的参数name,表示child实例在实例化时指定的名字(因为component只有一个parent,所以get_parent不需要指定参数;而可能有多个child,所以必须指定name参数);

源码:extern function uvm_component get_child (string name);

  1. get_children:得到当前实例所有的child;

源码:extern function void get_children(ref uvm_component children[$]);

  1. get_first_child和get_next_child的组合依次得到所有的child。

源码:     extern function int get_first_child (ref string name);

                extern function int get_next_child (ref string name);

最后

以上就是火星上红酒为你收集整理的UVM学习整理——UVM结构(component派生类)二、UVM结构的全部内容,希望文章能够帮你解决UVM学习整理——UVM结构(component派生类)二、UVM结构所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(50)

评论列表共有 0 条评论

立即
投稿
返回
顶部