UVM常用类及树形结构

目录

三、UVM常用类 

1.1uvm_component和uvm_object

1.2常用的uvm_object类

1.3常用的uvm_component类

1.4UVM树形结构


三、UVM常用类 

1.1uvm_component和uvm_object

图1 UVM常用类的继承关系

        UVM中两大基本概念就是component和object,uvm_object是UVM中最基本的类,几乎所有的类都继承于uvm_object,其中包括uvm_component。因此uvm_component拥有uvm_object的基本特性,但又有自己独特的特性:

1.uvm_component通过在new时指定parent参数来形成一种树形组织结构,这是uvm_object所没有的,因此只有uvm_component及其派生类可以成为树形结构的结点;

2.uvm_component拥有phase自动执行的特点,整个树形结构按照phase机制自动执行结点的各个phase;

1.2常用的uvm_object类

        uvm_sequence_item:所有的transaction要从uvm_sequence_item派生,事实上uvm_sequence_item派生自uvm_transaction,但其增加了很多实用的成员变量和方法,因此transaction从uvm_sequence_item派生,可以直接使用这些新增加的变量和方法;

//transaction派生自uvm_sequence_item
class my_transaction extends uvm_sequence_item;
//定义数据包
    typedef enum{WR,RD} opt_e;
    rand bit[7:0] data;
    rand opt_e opt;
//注册factory
    `uvm_object_utils_begin(my_transaction)
//加入field_automatic
        `uvm_field_int(data,UVM_ALL_ON)
        `uvm_field_enum(opt_e,opt,UVM_ALL_ON)
    `uvm_object_utils_end
//new函数
    function new(string name="my_transaction");
        super.new(name);
    endfunction
    function my_transaction my_copy(my_transaction tr);
        this.data=tr.data;
        this.opt=tr.opt;
    endfunction
    function void my_print(my_transaction tr);
        $write("data=%0d",tr.data);
        $write("opt=%s",tr.opt.name());
    endfunction
//重写pre_randomize和post_randomize函数
    extern function void pre_randomize();
    extern function void post_randomize();
endclass
    

        uvm_sequence:所有sequence要从uvm_sequence派生,sequence就是sequence_item的组合,在task body中通过`uvm_do(my_trans)自动创建transaction的实例my_trans并将其随机化,最终发送给sequencer;

//sequence派生自uvm_sequencer
class my_sequence extends uvm_sequence #(my_transaction);
//声明transaction句柄    
    my_transaction tr;
//new函数
    function new(string name="my_sequence");
        super.new(name);
    endfunction
//在task body中产生随机transaction
    virtual task body();
//使用starting_phase提起和撤销objection
        if(starting_phase!=null) 
            starting_phase.raise_objection(this);
        repeat(10) begin
            `uvm_do(tr)
        end
        #100;
        if(starting_phase!=null)
            starting_phase.drop_objection(this);
    endtask
//注册factory
    `uvm_object_utils(my_sequence)
endclass

        config:config一般直接从uvm_object派生,它的作用是将所有的参数放在一个object(对象)中,然后通过config_db的方式设置给所有需要这些参数的component;

        uvm_reg_item:派生自uvm_sequence_item,用于register model当中;

        uvm_phase:派生自uvm_object,用于控制component的行为方式,使component按照规范执行各个不同的phase;

1.3常用的uvm_component类

        uvm_driver:所有的driver都要派生自uvm_driver。driver的功能主要是向sequencer索要sequence_item(transaction),通过seq_item_port.get_next_item(req)向sequencer索要transaction,并驱动到DUT端口,完成从事务级到端口级的转换。

//driver派生自uvm_driver
class my_driver extends uvm_driver #(my_transaction);
//声明virtual interface
    virtual my_if vif;
//new函数
    function new(string name="my_driver",uvm_component parent=null);
        super.new(name,parent);
    endfunction
//加入factory
    `uvm_component_param_utils(my_driver)
//build_phase中进行接口连接和创建实例
    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        uvm_config_db#(virtual my_if)::get(this,"","vif",vif);//接口连接
    endfunction
//task main_phase中向sequencer请求transaction并驱动到DUT
    task main_phase(uvm_phase phase);
        super.main_phase(phase);
        vif.data<='b0;
        vif.winc<=1'b0;
        while(!vif.wrst_n)
            @(posedge vif.wclk);
        while(1) begin//使用while(1)循环,只要有transaction即驱动
            seq_item_port.get_next_item(req);//try_next_item为非阻塞
            drive_one_pkt(req);
            seq_item_port.item_done();
        end
    endtask
//驱动方式需要满足总线协议
    extern virtual task drive_one_pkt(my_transaction tr);
endclass

        uvm_monitor:所有monitor都要派生自uvm_monitor。monitor主要功能是从DUT端口接收数据,并将接收到的数据转换为transaction级的sequence_item,最终发送给scoreboard进行比较;

//monitor继承自uvm_monitor
class my_monitor extends uvm_monitor;
//声明虚接口
    virtual my_if vif;
//声明发信端口将采样的数据发送给scoreboard
    uvm_analysis_port#(my_transaction) ap;
//注册工厂
    `uvm_component_utils(my_monitor)
//new函数
    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);
        ap=new("ap",this);//例化通信端口
        uvm_config_db#(virtual my_if)::get(this,"","vif",vif);//接口连接
    endfunction
//main_phase中实现DUT数据采样
    task main_phase(uvm_phase phase);
        super.main_phase(phase);
        my_transaction tr;
        while(1) begin
            tr=new("tr");
            collect_one_pkt(tr);
            ap.write(tr);//通过端口发送至scoreboard
        end
    endtask
//采样方式满足总线协议
    extern virtual task collect_one_pkt(my_transaction tr);
endclass

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

//sequencer继承自uvm_sequencer
class my_sequencer extends uvm_sequencer #(my_transaction);
//注册工厂
    `uvm_component_utils(my_sequencer)
//new函数
    function new(string name="my_sequencer",uvm_component parent=null);
        super.new(name,parent);
    endfunction
endclass

        uvm_scoreboard:一般scoreboard派生自uvm_scoreboard。scoreboard的功能是接收reference model和monitor发送来的数据,并进行比较,根据比较结果判断DUT功能是否正常;

//scoreboard继承自uvm_scoreboard
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)
//new函数
    function new(string name="my_scoreboard",uvm_component parent=null);
        super.new(name,parent);
    endfunction
//build_phase中创建实例
    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        exp_port=new("exp_port",this);
        act_port=new("act_port",this);
    endfunction
//mian_phase中实现期望和实际结果的比较,并产生比较结果
    task main_phase(uvm_phase phase);
        super.main_phase(phase);
        my_transaction expect,actual,tmp;//定义期望、实际、中转事务
        bit result;//定义对比结果
        fork//期望结果存储与对比同时进行
            while(1) begin
                exp_port.get(expect);//接收reference model产生的期望结果
                expect_queue.push_back(expect);//存放期望结果
            end
            while(1) begin
                act_port.get(actual);//从monitor接收DUT输出结果
                if(expect_queue.size()>0) begin
                    tmp=expect_queue.pop_front();//取出期望数据
                    result=actual.compare(tmp);//比较期望和实际结果
                    if(result) begin
                        `uvm_info("my_scoreboard","compare successful",UVM_LOW)
                    end
                    else begin
                        `uvm_error("my_scoreboard","compare failed")
                        $display("the expect pkt is");
                        tmp.my_print();
                        $display("this actual pkt is");
                        actual.my_print();
                    end
                end
                else begin
                    `uvm_error("my_scoreboard","received from DUT,while expect_queue is empty")
                end
            end
        join
    endtask
endclass

        reference model:reference_model一般直接派生自uvm_component。通过高级语言如SV实现和DUT相同的功能,并发送输出结果供scoreboard进行比较。也通过DPI接口进行调用C或其他高级语言model;

//reference model继承自uvm_component
class my_model extends uvm_component;
//声明通信端口句柄
    uvm_blocking_get_port #(my_transaction) port;
    uvm_analysis_port #(my_transaction) ap;
//注册工厂
    `uvm_component_utils(my_model)
//new函数
    function new(string name="my_model",uvm_component parent=null);
        super.new(name,parent);
    endfunction
//创建实例
    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        port=new("port",this);
        ap=new("ap",this);
    endfunction
//main_phase接收DUT输入数据并实现DUT功能,产生期望结果发送给scoreboard
    virtual task main_phase(uvm_phase phase);
        super.main_phase(phase);
        my_transaction tr;
        my_transaction tr_new;
        while(1) begin
            port.get(tr);
            tr_new=new("tr_new");
            tr_new.my_copy(tr);
            tr_new.my_print();
            ap.write(tr_new);
        end
    endtask
endclass

        uvm_agent:所有的agent派生自uvm_agent。它的作用是将driver和monitor封装在一起,其引入了枚举变量is_active,用于控制实际例化的对象;

//agent继承自uvm_agent
class my_agent extends uvm_agent;
//声明driver、monitor、sequencer句柄
    my_driver    drv;
    my_monitor   mon;
    my_sequencer sqr;
//声明通信端口
    uvm_analysis_port #(my_transaction) ap;
//注册工厂
    `uvm_component_utils(my_agent)
//new函数
    function new(string name="my_agent",uvm_component parent=null);
        super.new(name,parent);
    endfunction
//build_phase中创建实例,agent中内置成员变量is_active
    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        if(is_active==UVM_ACTIVE) begin
            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 connect_phase(uvm_phase phase);
        super.connect_phase(phase);
        if(is_active==UVM_ACTIVE) begin
            drv.seq_item_port.connect(sqr.seq_item_export);//driver与sequencer通信端口连接
        end
        ap=mon.ap;//agent发信端口指向monitor发信端口
    endfunction
endclass

        uvm_env:所有的env都派生自uvm_env。env作用是将验证平台固定不变的component封装在一起,提高验证平台的复用性。当要运行不同测试用例时,只需例化env即可生成相同的验证组件;

//env继承自uvm_env
class my_env extends uvm_env;
//声明in/out agent、reference model及scoreboard句柄
    my_agent i_agt,o_agt;
    my_model mdl;
    my_scoreboard scb;
//fifo用于缓存发向reference model的输入采样数据
    uvm_tlm_analysis_fifo #(my_transaction) agt_mdl_fifo;
//注册工厂
    `uvm_component_utils(my_env)
//new函数
    function new(string name="my_env",uvm_component parent=null);
        super.new(name,parent);
    endfunction
//build_phase创建实例并指定agent.is_active值
    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        i_agt=my_agent::type_id::create("i_agt",this);
        o_agt=my_agent::type_id::create("o_agt",this);
        mdl  =my_model::type_id::create("mdl",this);
        scb  =my_scoreboard::type_id::create("scb",this);
        i_agt.is_active=UVM_ACTIVE;
        o_agt.is_active=UVM_PASSIVE;
    endfunction
//connect_phase中进行component的通信端口连接
    function void connect_phase(uvm_phase phase);
        super.connect_phase(phase);
//model通过fifo接收来自monitor的输入采样数据
        i_agt.ap.connect(agt_mdl_fifo.analysis_export);
        mdl.port.connect(agt_mdl_fifo.blocking_get_export);
//mdl产生的期望结果发送给scoreboard的exp_port
        mdl.ap.connect(scb.exp_port);
//monitor采样的输出数据发送给scoreboard的act_port
        o_agt.ap.connect(scb.act_port);
    endfunction
enclass
        
    

        uvm_test:所有的testcase都要派生自uvm_test或其派生类。通常会从uvm_test派生出base_test,例化env并设置sequencer的default_sequence,并进行验证平台的基础设置或参数设置,实际的test_case派生自base_test,然后根据测试点进行针对性修改。可以通过命令行参数+UVM_TESTNAME=<case_name>指定运行的case;

//base_test继承自uvm_test
class base_test extends uvm_test;
//声明env句柄
    my_env env;
//new函数
    function new(string name="base_test",uvm_component parent=null);
        super.new(name,parent);
    endfunction
//build_phase中创建实例并启动sequence
    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        env=my_env::type_id::create("env",this);
//启动default_sequence
        uvm_config_db#(uvm_object_wrapper)::set(this,
                                                "env.i_agt.sqr.main_phase",
                                                "default_sequence",
                                                my_sequence::type_id::get());
    endfunction
//report_phase进行仿真后报告
    function void report_phase(uvm_phase);
        super.report_phase(phase);
        uvm_report_server server;
        int err_num;
        server=get_report_server();
        err_num=server.get_severity_count(UVM_ERROR);//获取UVM_ERROR数量
        if(err_num!=0) begin
            $display("TEST CASE IS ERROR");
        end
        else begin
            $diaplay("TEST CASE IS PASSED");
        end
    endfunction
endclass
    

        top_tb:验证的顶层模块,进行接口发信、DUT例化以及case运行;

`timescale 1ns/1ps
`include "uvm_macros.svh"
import uvm_pkg::*;
`include "dut.v"
`include "my_if.sv"
import tb.pkg::*;
//tb顶层模块
module top_tb;
//定义公共信号clk、rst_n等
    reg clk,rst_n;
//声明接口
    my_if.INPUT  input_if;
    my_if.OUTPUT output_if;
    my_if vif(clk,rst_n);
//driver、monitor的接口发信
    initial begin
        uvm_config_db#(virtual my_if)::set(null,"uvm_test_top.i_agt.drv","vif",input_if);
        uvm_config_db#(virtual my_if)::set(null,"uvm_test_top.i_agt.mon","vif",input_if);
        uvm_config_db#(virtual my_if)::set(null,"uvm_test_top.o_agt.mon","vif",outpur_if);
    end
//clk
    initial begin
        clk=0;
        forever #10 clk=~clk;
    end
//rst_n
    initial begin
        rst_n=1'b0;
        #100;
        rst_n=1'b1;
    end
//运行case
    initial begin
        run_test();
    end
//例化DUT
    dut inst_dut(vif);
endmodule
1.4UVM树形结构

        UVM采样树形的组织结构管理验证平台的各个component。所有的component类如sequencer、driver、monitor、agent、model、scoreboard、env、case都是树的一个结点。它们在new时都需要指定一个uvm_component类型的变量parent,及它们的上一层级(父结点),通常都在component的上一层级创建实例,因此parent参数为this。

图2 UVM树形结构

        如果component例化时指定其父结点parent为null,那么这个component的parent将会被系统设置为系统中唯一的uvm_root的实例uvm_top。uvm_root的存在确保了整个验证平台只有一颗UVM树,所有的结点都是uvm_top的子结点。使用uvm_top.print_topology()函数可以打印整个UVM树的拓扑结构。通过comp.get_full_name()可以返回任意结点的路径索引。

uvm_top.print_topology();//打印拓扑结构
`uvm_info("drv_full_name",get_full_name(),UVM_LOW)//打印路径uvm_test_top.env.i_agt.drv

        使用comp.get_parent()返回component的parent类,使用comp.get_child(string name)返回指定的child类,comp.get_num_children()函数用于返回当前component所有child的数量。

//UVM源代码
extern virtual function uvm_component get_parent();
extern function uvm_component get_child(string name);
extern function int get_num_children();

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值