UVM实战_1_UVM基础篇

UVM基础:组件、机制与信息控制
本文详细介绍了UVM验证方法论的基础组件,包括uvm_driver、uvm_monitor、uvm_sequencer、uvm_scoreboard、uvm_agent、uvm_env和uvm_test的职责与用法。此外,还探讨了UVM的树形结构、field automation机制、打印信息控制以及config_db机制,为理解和应用UVM提供基础指导。

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、继承uvm_component的几大组件
    • 1. uvm_driver
    • 2. uvm_monitor
    • 3. uvm_sequencer
    • 4. uvm_scoreboard
    • 5. reference model
    • 6. uvm_agent
    • 6. uvm_env
    • 6. uvm_test
  • 二、UVM的树形结构
    • 1. 为什么要有parent参数
    • 2. get_parent、get_child等函数
  • 三、field automation机制
    • 1. field automation机制相关的宏
    • 2. field automation机制的常用函数
    • 3. field automation机制中标志位(UVM_ALL_ON)
    • 4. field automation中也可以加if条件
  • 四、UVM打印信息的控制
    • 1. 设置/查看打印信息的冗余度阈值
    • 2. 打印信息的重载
    • 3. UVM_ERROR达到一定数量结束仿真
  • 五、config_db机制
    • 1. set和get函数的参数
    • 2. get语句也可以省略?
    • 3. 寄信多次,收信一次,以哪个为准?
    • 4. config_db机制支持通配符
    • 4. check_config_usage
  • 总结


前言

本篇主要介绍UVM的几大组件,以及一些基础的知识


一、继承uvm_component的几大组件

在这里插入图片描述
如上图,继承uvm_component的组件有uvm_agent/driver/monitor/scoreboard/env/test

1. uvm_driver

所有的driver都要派生自uvm_driver。driver的功能主要就是向sequencer索要sequence_item(transaction),并且将sequence_item里的信息驱动到DUT的端口上,这相当于完成了从transaction级别到DUT能够接受的端口级别信息的转换。
相关代码如下:

class my_driver extends uvm_driver#(my_transaction);
   virtual my_if vif;
   `uvm_component_utils(my_driver)//加入factory机制,把my_driver注册在UVM内部的一张表中
   function new(string name = "my_driver", uvm_component parent = null);//每一个派生自uvm_component在new函数中都要指明两个参数:name和parent
      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);//driver所做的事情几乎都在main_phase中完成
   extern task drive_one_pkt(my_transaction tr);
endclass

task my_driver::main_phase(uvm_phase phase);
   vif.data <= 8'b0;
   vif.valid <= 1'b0;
   while(!vif.rst_n)
      @(posedge vif.clk);
   while(1) begin
      seq_item_port.get_next_item(req);//得到一个新的req,并且驱动它
      drive_one_pkt(req);
      seq_item_port.item_done();//驱动完req后,通知sequencer
   end
endtask

2. uvm_monitor

所有的monitor都要派生自uvm_monitor。monitor做的事情与driver相反,driver向DUT的pin上发送数据,而monitor则是从DUT的pin上接收数据,并且把接收到的数据转换成transaction级别的sequence_item,再把转换后的数据发送给scoreboard或者reference model,供其比较。

class my_monitor extends uvm_monitor;
   virtual my_if vif;
   uvm_analysis_port #(my_transaction)  ap;
   `uvm_component_utils(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

task my_monitor::main_phase(uvm_phase phase);
   my_transaction tr;
   while(1) begin
      tr = new("tr");
      collect_one_pkt(tr);
      ap.write(tr);
   end
endtask

DUT的输入口设置一个monitor有必要吗?
第一,在一个大型的项目中,driver根据某一协议发送数据,而monitor根据这种协议收集数据,如果driver和monitor由不同的人员实现,那么可以大大减少其中任何一方对协议理解的错误;
第二,在实现代码重用时,使用monitor是非常有必要的。

3. uvm_sequencer

所有的sequencer都要派生自uvm_sequencer。sequencer的功能就是组织管理sequence,当driver要求数据时,它就把sequence生成的sequence_item转发给driver。

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

4. uvm_scoreboard

一般的scoreboard都派生自uvm_scoreboard。scoreboard的功能就是比较reference model和monitor分别发送来的数据,根据比较结果判断DUT是否正确工作。

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)

   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 

function my_scoreboard::new(string name, uvm_component parent = null);
   super.new(name, parent);
endfunction 

function void my_scoreboard::build_phase(uvm_phase phase);
   super.build_phase(phase);
   exp_port = new("exp_port", this);
   act_port = new("act_port", this);
endfunction 

task my_scoreboard::main_phase(uvm_phase phase);
   my_transaction  get_expect,  get_actual, tmp_tran;
   bit result;
   bit cmp_en = 1'b1;
 
   super.main_phase(phase);
   fork
      while(1) begin
         uvm_config_db#(bit)::wait_modified(this, "", "cmp_en");//这里是什么意思?后续在看
         void'(uvm_config_db#(bit)::get(this, "", "cmp_en", cmp_en)); 
         `uvm_info("my_scoreboard", $sformatf("cmp_en value modified, the new value is %0d", cmp_en), UVM_LOW)
      end
      while (1) begin
         exp_port.get(get_expect);
         expect_queue.push_back(get_expect);
      end
      while (1) begin
         act_port.get(get_actual);
         if(expect_queue.size() > 0) begin
            tmp_tran = expect_queue.pop_front();
            result = get_actual.compare(tmp_tran);
            if(result) begin 
               `uvm_info("my_scoreboard", "Compare SUCCESSFULLY", UVM_LOW);
            end
            else begin
               `uvm_error("my_scoreboard", "Compare FAILED");
               $display("the expect pkt is");
               tmp_tran.print()
<think>嗯,用户这次想深入了解UVMuvm_field_int的具体用法和应用场景。之前讨论过UVM的objection机制,现在转向fieldautomation机制,说明用户正在系统学习UVM的实用功能。用户引用了几资料,其中提到uvm_field_int的注册方式和使用注意事项。特别是引用[1]展示了带条件判断的field注册语法,引用[4]则提醒宏实现可能存在坑点。这反映出用户需要实操指导,而不仅是理论说明。从用户引用[3]关于静态数组的疑问推测,用户可能实际遇到了数据字段注册的问题。需要重点讲解uvm_field_int对基础数据类型的处理,以及它和uvm_field_array_int等变体的区别。用户提到"正确使用",暗示可能遇到过注册失败或功能异常的情况。应该强调三个关键点:1)必须在uvm_component_utils_begin/end之间注册2)注意字段类型的匹配3)调试时开启UVM调试消息看字段操作日志。考虑到用户可能是设计验证工程师,应用场景部分应该突出实际验证环境中的典型用例:比如在scoreboard里自动比对transaction字段,或者在sequence里自动打包数据字段。可以补充一个对比示例展示未注册字段需要手动实现copy/compare的繁琐性。引用[4]指出的宏代码问题值得警惕,需要提醒用户注意UVM版本差异。如果用户遇到字段比较出错,建议检查宏展开后的比较逻辑,或者考虑改用do_compare等手动实现方式作为备选方案。用户没有明确提问调试技巧,但根据之前objection机制讨论的深度,可以预判后续可能遇到的问题。在注意事项里加入"空指针异常"和"循环依赖"的排查方法会比较实用。相关问题设计要延续知识链:从uvm_field_int自然过渡到其他字段类型,再到field机制的实现原理。这样既解答当前问题,又为后续学习埋下伏笔。</think> 在UVM中,`uvm_field_int`宏是**字段自动化(Field Automation)机制的核心组件**,用于简化对组件/事务类中整型变量的操作管理。以下是具体使用方法和典型场景: --- ### 一、基本语法与注册方法 在类定义中通过`uvm_component_utils_begin`/`uvm_component_utils_end`包裹注册: ```systemverilog class my_transaction extends uvm_sequence_item; int data_value; // 待注册的整型变量 // 字段自动化注册 `uvm_object_utils_begin(my_transaction) `uvm_field_int(data_value, UVM_ALL_ON) // 关键注册语句 `uvm_object_utils_end function new(string name = "my_transaction"); super.new(name); endfunction endclass ``` - **`UVM_ALL_ON`**:启用所有自动化功能(copy/compare/print/pack等)[^1] - **参数说明**: - 第一参数:变量名(如上述`data_value`) - 第二参数:标志位(控制启用的自动化操作) --- ### 二、核心应用场景 #### 1. 自动打印(Debug) 自动生成可读的字段信息格式: ```systemverilog my_transaction tr = new("tr"); tr.data_value = 42; tr.print(); // 输出:---------------------------------------- // Name Type Size Value // tr my_transaction - @1234 // data_value integral 32 'd42 ``` **优势**:快速定位调试时数据值,无需手动编写`convert2string()`[^2]。 #### 2. 数据复制(Clone) 深拷贝对象时自动复制字段值: ```systemverilog my_transaction tr_orig, tr_copy; tr_orig = new("orig"); tr_orig.data_value = 100; tr_copy = tr_orig.clone(); // 自动复制data_value ``` #### 3. 对象比对(Check) 自动验证两个对象字段一致性: ```systemverilog my_transaction tr1, tr2; tr1.data_value = 50; tr2.data_value = 50; if (tr1.compare(tr2)) `uvm_info("MATCH", "Data values equal", UVM_LOW) ``` --- ### 三、标志位(Flag)的精细控制 通过按位或组合控制功能开关: | 标志位 | 功能 | |-----------------|---------------------| | `UVM_COPY` | 启用复制 | | `UVM_COMPARE` | 启用比较 | | `UVM_PRINT` | 启用打印 | | `UVM_NOPACK` | 禁用打包/解包 | ```systemverilog // 仅启用复制和比较 `uvm_field_int(data_value, UVM_COPY | UVM_COMPARE) ``` --- ### 四、其他字段自动化宏 针对不同类型字段的专用宏: | 宏名称 | 适用数据类型 | |--------------------------|---------------------| | `uvm_field_array_int` | 整型数组 | | `uvm_field_string` | 字符串 | | `uvm_field_enum` | 枚举类型 | | `uvm_field_object` | UVM对象(如组件) | ```systemverilog // 注册整型静态数组 int static_arr[4]; `uvm_field_array_int(static_arr, UVM_ALL_ON) // 引用[3] ``` --- ### 五、使用注意事项 1. **空指针风险** 操作未初始化的对象会引发空指针异常(类似`starting_phase`未判空问题)。 2. **循环依赖** 嵌套对象注册时需避免循环引用: ```systemverilog class A; B b_obj; `uvm_field_object(b_obj, UVM_ALL_ON) // B需在A之前定义 endclass ``` 3. **性能权衡** 对大型数组或高频操作场景,手动实现`do_copy()`/`do_compare()`性能更优[^4]。 4. **版本兼容** 注意UVM版本差异(如1.2中`uvm_field_aa_object_int`的compare问题)[^4]。 --- > **本质作用**:`uvm_field_int`通过元编程自动生成字段操作代码,将开发人员从繁琐的`copy()/compare()/print()`手动实现中解放,提升验证组件开发效率[^1][^2]。 --- ###
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值