【UVM基础】2、组件家族

本文详细介绍了UVM验证方法论中的关键组件,包括transaction、driver、monitor、sequence、sequencer、scoreboard和agent。transaction是数据交换的基本单位,driver负责驱动DUT,monitor用于监测接口数据,sequence是生成和调度transaction的机制,sequencer是协调sequence和driver的桥梁,scoreboard则进行数据比较。此外,还讨论了uvm_test、referencemodel以及如何使用virtual interface提高平台的可移植性。

组件家族

 

uvm_transaction

transaction是一个抽象的概念,一般来说物理协议中的数据交换都是以帧后者包为单位的,在一帧或者一个包中定义好各项参数,一个transaction就是一个包。

class my_transaction extends uvm_sequence_item;

   rand bit[47:0] dmac;
   rand bit[47:0] smac;
   rand bit[15:0] ether_type;
   rand byte      pload[];
   rand bit[31:0] crc;

   constraint pload_cons{
      pload.size >= 46;
      pload.size <= 1500;
   }

   function bit[31:0] calc_crc();
      return 32'h0;
   endfunction

   function void post_randomize();
      crc = calc_crc;
   endfunction

   `uvm_object_utils(my_transaction)

   function new(string name = "my_transaction");
      super.new();
   endfunction
endclass

 transaction和driver之间还是有差别的,整个仿真期间driver都是存在的,而transaction不同,因为transaction有自己的生命周期,在仿真的某一段时间产生,经过driver驱动,reference model处理,他的生命周期也就结束了。

uvm_driver

从uvm_sequencer中获取事务,经过转换对DUT进行时序激励,该类是参数化的类,因此在定义的时候需要声明参数的类型,uvm_driver类的定义:

class uvm_driver # (type REQ=uvm_sequence_item , type RSP=REQ) entends uvm_component; 

在定义新的driver类的时候,应当声明该类所需要获得的事务参数REQ类型,默认情况下,RSP应当和REQ保持相同类型。uvm_driver 在uvm_component的基础上没有扩展新的函数,而是知识扩展了一些通信端口和变量

uvm_driver 示例

 

 uvm_monitor

uvm_monitor类的目的是检测接口数据,任何需要数据监测的monitor都应当继承于这个类,虽然uvm_monitor与它的父类相比,并没有增添新的成员和方法, 但将新定义的monitor类继承于uvm_monitor类会有助于实现父类  uvm monitor的方法和特性.uvm_monitor执行的功能包括:

● 观测DUT的interface,并且收集总线信息

●永远保持PASSIVE模式,即永远不会驱动DUT

●在总线协议或者内部信号协议观察时,可以做一些功能和时序的检查 。

●对干更加复杂的检查要求,它们可以将数据发送至其它验证组件,例如scoreboard  reference model或者coverage collector。

uvm_sequence机制

uvm_sequence

sequence不属于验证平台的任何一个地方,但是与sequencer之间有着密切的联系,sequence比喻成一个弹夹,transaction就是弹夹里面的子弹,sequencer就是一个手枪。需要注意的是sequence是一个uvm_object,而sequencer是一个uvm_component。

class my_sequence extends uvm_sequence #(my_transaction);
   my_transaction m_trans;

   function new(string name= "my_sequence");
      super.new(name);
   endfunction

   virtual task body();
      repeat (10) begin
         `uvm_do(m_trans)
      end
      #1000;
   endtask

   `uvm_object_utils(my_sequence)
endclass

uvm_sequencer

uvm_sequencer就如同一个管道, 从这个管道中会产生连续的激励事务,并最终通过TLM端口送至driver—测。如果需要的话,uvm_Sequencer也可从uvm_driver那里获取随后的RSP对 象来得知数据通信是否正常(通过握手)。 uvm_sequencer类的定义来看,它同uvm_driver—样是个参数类,需要 在定义Sequencer时声明REQ的类型。

class my_sequencer extends uvm_sequencer #(my_transaction);
   
   function new(string name, uvm_component parent);
      super.new(name, parent);
   endfunction 
   
   `uvm_component_utils(my_sequencer)
endclass

 uvm_agent

uvm_agemt 的存在是为了验证环 UVM Agent 境的复用。按照总线的传输方向划分可以分为master和slaveo 。Master agent是用来向DUT 发起transaction; Slave agent是用来响应 DUT  的event。

uvm_agent是一个标准的验证环境“单位”,这样的一个标准单位通常包含一个driver、一个monitor以及一个Sequencer 。同时为了复用,有的时候uvm_agent中只需要包含一个momitor,而不需要driver和sequencer,这就需要通过一个变量来进行有条件的例化。

uvm_active_passive_enum is_active = UVM_ACTIVE;

is_active可以理解为agent的一个成员,缺省值是UVM_ACTIVE,表示在active模式的agent需要例化driver、monitor和sequencer,而如果is_active的值是UVM_PASSIVE,这表示agent是passive模式,只可以例化monitor。 active模式的agent既有激励功能也有监测功能,passive模式的agent只具有监测功能。
通过is_active变量,agent需要在build_phase和connect_phase等函数中通过选择语句来对driver和sequencer进行有条件的例化和连接

 uvm_scoreboard

uvm_scoreboard担任着同SV中checker一样的功能进行数据比对和报告。  uvm_scoreboard本身没有添加额外的成员变量和方法,uvm_scoreboard会接收来自于多个monitor的监测据,从而进行比较。

uvm_scoreboard自带的两个用于数据比较的类:

uvm_in_order_comparator #(type T);
uvm_algorithm_comparator #(type BEFORE,type AFTER ,type TRANSFORMER);

第一个:输入输出是一个类型,直接比较。第二个:输入输出不同,因此需要一个类型转换,转变成相同的。在scoreboard中通常会声明TLM端口以供monitor传输数据。

uvm_env

从环境层次结构而言 , uvm_env可能包含多个  uvm_agent和其它 component,这些不同组件共同构成一个完整的验证环境,而这个环境在将来复用中可以作为子环境被进一步集成到更高的环境中。uvm env的角色就是一个结构化的容器,它可以容纳其它组件 ,同时它也可以作为子环境在更高层的集成中被嵌入。

 uvm_test

uvm_test类本身没有什么新成员,但是作为测试用例的代言人,它不但决定着环境的结构和连接关系,也决定着使用哪一个测试序列。 uvm_test是验证环境建立的唯一入口,只有通过它才能正常运转UVM的phase机制。在uvm_test中只例化一个顶层uvm_env,这便于提供一个唯一环境节点以形成树状的拓扑结构,而这种树状环境结朴也会对应着—种树状配置结构。

reference model

reference model和DUT完成相同的功能,reference model 的输出被scoreboard接收,用于和DUT进行比较。DUT简单,reference model就会简单,DUT复杂,reference model就会复杂

class my_model extends uvm_component;
   
   uvm_blocking_get_port #(my_transaction)  port;
   uvm_analysis_port #(my_transaction)  ap;

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

   `uvm_component_utils(my_model)
endclass 

function my_model::new(string name, uvm_component parent);
   super.new(name, parent);
endfunction 

function void my_model::build_phase(uvm_phase phase);
   super.build_phase(phase);
   port = new("port", this);
   ap = new("ap", this);
endfunction

task my_model::main_phase(uvm_phase phase);
   my_transaction tr;
   my_transaction new_tr;
   super.main_phase(phase);
   while(1) begin
      port.get(tr);
      new_tr = new("new_tr");
      new_tr.my_copy(tr);
      `uvm_info("my_model", "get one transaction, copy and print it:", UVM_LOW)
      new_tr.my_print();
      ap.write(new_tr);
   end
endtask

virtual interface

加入 virtual interface 的目的是为了增强验证平台的可移植性。

使用宏来避免绝对路径:

task my_driver::main_phase(uvm_phase phase);
   top_tb.rxd <= 8'b0; 
   top_tb.rx_dv <= 1'b0;
   while(!top_tb.rst_n)
      @(posedge top_tb.clk);
   for(int i = 0; i < 256; i++)begin
      @(posedge top_tb.clk);
      top_tb.rxd <= $urandom_range(0, 255);
      top_tb.rx_dv <= 1'b1;
      `uvm_info("my_driver", "data is drived", UVM_LOW)
   end
   @(posedge top_tb.clk);
   top_tb.rx_dv <= 1'b0;
endtask

使用interface来避免绝对路径:在类中使用的是virtual interface

task my_driver::main_phase(uvm_phase phase);
   phase.raise_objection(this);
   `uvm_info("my_driver", "main_phase is called", UVM_LOW);
   vif.data <= 8'b0; 
   vif.valid <= 1'b0;
   while(!vif.rst_n)
      @(posedge vif.clk);
   for(int i = 0; i < 256; i++)begin
      @(posedge vif.clk);
      vif.data <= $urandom_range(0, 255);
      vif.valid <= 1'b1;
      `uvm_info("my_driver", "data is drived", UVM_LOW);
   end
   @(posedge vif.clk);
   vif.valid <= 1'b0;
   phase.drop_objection(this);
endtask

### UVM常用组件列表及功能介绍 #### 1. **uvm_driver** `uvm_driver` 是负责驱动激励到设计中的组件。它通过事务级接口接收数据并将其转换为信号级操作,从而控制DUT(Design Under Test)。通常情况下,`uvm_driver` 需要实现 `run_phase` 方法来完成这一过程[^2]。 ```python class my_driver extends uvm_driver #(my_transaction); function new(string name, uvm_component parent); super.new(name, parent); endfunction task run_phase(uvm_phase phase); forever begin seq_item_port.get_next_item(req); // 获取下一个事务项 drive(req); // 将事务项转化为信号活动 seq_item_port.item_done(); // 完成当前事务处理 end endtask endclass ``` --- #### 2. **uvm_monitor** `uvm_monitor` 的主要职责是从 DUT 中采集数据,并将这些数据封装为事务对象以便后续分析或比较。它可以用于观察总线上的流量或其他感兴趣的事件[^4]。 ```python class my_monitor extends uvm_monitor; virtual interface my_if vif; function new(string name, uvm_component parent); super.new(name, parent); endfunction task run_phase(uvm_phase phase); forever begin @(vif.cb); // 等待回调触发 trans_collected = new(); collect_data(trans_collected); // 收集数据并存储到事务对象中 analyze(trans_collected); // 可选:进一步分析收集的数据 end endtask endclass ``` --- #### 3. **uvm_sequencer** 作为序列器 (`uvm_sequencer`),它是连接测试序列和驱动程序之间的桥梁。它的核心作用是管理序列并将它们传递给相应的驱动程序实例[^1]。 ```python class my_sequencer extends uvm_sequencer #(my_transaction); function new(string name, uvm_component parent); super.new(name, parent); endfunction endclass ``` --- #### 4. **uvm_agent** `uvm_agent` 组件是一个容器型结构,用来集成 driver、monitor 和 sequencer 这些子部件。根据配置的不同,可以设置 agent 工作模式为主动 (active) 或被动 (passive)[^3]。 - 主动模式下会包含所有的三个部分; - 被动模式则仅保留 monitor 功能而不涉及任何刺激生成逻辑。 ```python class my_agent extends uvm_agent; my_driver m_drvr; my_monitor m_montr; my_sequencer m_seqr; function new(string name, uvm_component parent); super.new(name, parent); endfunction function void build_phase(uvm_phase phase); if(get_is_active() == UVM_ACTIVE) begin m_seqr = my_sequencer::type_id::create("m_seqr", this); m_drvr = my_driver::type_id::create("m_drvr", this); end m_montr = my_monitor::type_id::create("m_montr", this); endfunction function void connect_phase(uvm_phase phase); if(m_drvr != null && m_seqr != null) m_drvr.seq_item_port.connect(m_seqr.seq_item_export); endfunction endclass ``` --- #### 5. **uvm_scoreboard** 该组件被定义为验证环境中的一种检查机制,主要用于对比实际输出与预期结果的一致性。scoreboards 往往依赖于 monitors 提供的信息来进行判断。 ```python class my_scoreboard extends uvm_scoreboard; uvm_analysis_imp#(my_transaction, my_scoreboard) item_collected_export; function new(string name, uvm_component parent); super.new(name, parent); endfunction function void write(my_transaction t); check_response(t); // 对接收到的每一笔交易执行校验算法 endfunction endclass ``` --- #### 6. **uvm_env** 环境(`uvm_env`)代表整个验证场景的核心框架,其中包含了多个 agents、scoreboards 等其他必要的构建模块。开发者可以通过扩展此基类来自定义特定应用场合下的验证需求。 ```python class my_env extends uvm_env; my_agent m_agnt; my_scoreboard sbdbrd; function new(string name, uvm_component parent); super.new(name, parent); endfunction function void build_phase(uvm_phase phase); m_agnt = my_agent::type_id::create("m_agnt", this); sbdbrd = my_scoreboard::type_id::create("sbdbrd", this); endfunction endclass ``` --- #### 7. **uvm_test** 最后提到的是顶层测试文件——即 test 类。在这里面指定运行哪些具体的 testsuite 并初始化全局参数设定等事项。 ```python class base_test extends uvm_test; my_env env_inst; function new(string name, uvm_component parent); super.new(name, parent); endfunction function void build_phase(uvm_phase phase); env_inst = my_env::type_id::create("env_inst", this); endfunction endclass ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值