第二章 一个简单的UVM验证平台

2.1 验证平台的组成

第二章 一个简单的UVM验证平台_第1张图片

2.2 只有driver的验证平台

2.2.1 最简单的验证平台

class my_driver extends uvm_driver;

    function new(string name = "my_driver", uvm_component parent = null);

        super.new(name, parent);

    endfunction

    extern virtual task main_phase(uvm_phase phase)

endclass

task my driver::main_phase(uvm_phase phase);

    ......

        `uvm_info("my_driver", "data is drived", UVM_LOW)

    ......

endtask


uvm_driver是一个派生字uvm_component的类,每一个派生自uvm_component或其派生类的类在其new函数种要指明两个参数:name 和 parent。

uvm_info宏有三个参数,第一个参数是字符串,把打印的信息归类,第二个参数是具体要打印的信息,第三个参数是冗余级别(UVM_LOW, UVM_MEDIUM, UVM_HIGH)。

get_full_name() 获取路径索引。


2.2.1 加入factory机制

"my_driver.sv"

class my_driver extends uvm_driver;

    `uvm_component_utils(my_driver)

    ......

endclass


"top_tb.sv"

module top_tb;

initial begin

    run_test("my_driver");

end

endmodule


`uvm_component_utils(my_driver) 其功能之一是将my_driver登记在UVM内部的一张表中,这张表是factory功能实现的基础。

一个run_test语句会创建一个my_driver的实例,并会自动调用my_driver的main_phase。只有在类的定义时声明了`uvm_component_utils(my_driver)才能使用这个功能。所有派生自uvm_component及其派生类的类都应该使用宏注册。


2.2.3 加入objection机制

task my_driver::main_phase(uvm_phase phase);

    phase.raise_objection(this);

    ......

    phase.drop_objection(this);

endtask


raise_objection语句必须在main_phase种第一个消耗仿真时间的语句之前,如$display语句可以放在raise_objection之前。


2.2.4 加入virtual interface

"top_tb.sv"

module top_tb;

initial begin

    run_test("my_driver");

end

initial begin

    uvm_config_db#(virtual my_if)::set(null, "uvm_test_top", "vif", input);

end

endmodule


"my_driver.sv"

virtual function void build_phase(uvm_phase phase);

    ......

    if(!uvm_config_db#(virtual my_if)::get(this, " ", "vif", vif)

    ......

endfunction

UVM通过run_test语句实例化了一个脱离了top_tb层次结构的实例,建立了一个新的层次结构。

对于这种脱离了top_tb层次结构,同时又期望在top_tb中对其进行某些操作的实例,UVM引进了config_db机制。

在build_phase中主要通过config_db的 set 和 get 操作来传递一些数据,以及实例化成员变量等。build_phase是一个函数phase,不消耗仿真时间,总是在仿真时间为0时执行,而main_phase是一个任务phase。

config_db的 set 和 get 函数都有四个参数,这两个函数的第三个参数必须完全一致。set函数的第四个参数表示要将哪个interface通过config_db传递给my_driver,get函数的第四个参数表示把得到的interface传递给哪个my_driver的成员变量。set函数的第二个参数表示的是路径索引,无论传递给run_test的参数是什么,创建的实例的名字都为uvm_test_top,因为set操作的目标是my_driver,所以set函数的第二个参数就是uvm_test_top。


2.3 为验证平台加入各个组件

2.3.1 加入transaction

验证平台的组件之间,信息的传递是基于transaction的。


class my_transaction extends uvm_sequence_item;

    rand bit [47:0] dmac;

    ......

    constraint ...{}

    function bit [31:0] calc_crc();

        return 32'h0;

    endfunction

    `uvm_object_utils(my_transaction)

    function new(...);

    ......

endclass

在UVM中,所有transaction都要从uvm_sequence_item派生。

my_transaction有生命周期,这种类都是派生自uvm_object或者uvm_object的派生类,uvm_sequence_item的祖先就是uvm_object,UVM中具有这种特征的类都要使用uvm_object_utils宏来实现。


2.3.2 加入env

run_test只能实例化一个实例。引入一个容器类,在这个容器类中实例化driver, monitor, reference model 和 scoreboard等,在调用run_test时,传递参数是这个容器类,uvm_env。

class my_env extends uvm_env;

    my_driver drv;

    ......

    virtual function void build_phase(uvm_phase phase);

        super.build_phase(phase);

        drv = my_driver::type_id::create("drv", this);

    endfunction

    `uvm_component_utils(my_env)

endclass


factory机制注册过的类的实例化: type_name::type_id::create()。


2.3.3 加入monitor

class my_monitor extends uvm_monitor;

    virtual my_if vif;

    `uvm_component_utils(my_monitor)

    function new(...)

    ......

    virtual function void build_phase(uvm_phase phase);

    ......

endclass


2.3.4 封装成agent

driver和monitor二者处理的是同一种协议,agent将driver和monitor封装在一起,不同agent代表了不同的协议。

class my_agent extends uvm_agent;

    my_driver     drv;

    my_monitor  mon;

    ......

    `uvm_component_utils(my_agent)

endclass

function void my_agent::build_phase(uvm_phase phase);

    super.build_phase(phase);

    if(is.active == UVM_ACTIVE)    begin

        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);

endfunction


is_avtive 是uvm_agent的一个成员变量:

    uvm_active_passive_enum is_active = UVM_ACTIVE;

    typedef enum bit {UVM_PASSIVE=0, UVM_ACTIVE=1} uvm_active_passive_enum;


2.3.5 加入reference model

class my_model extends uvm_component;

    uvm_blocking_get_port     #(my_transaction)     port;

    uvm_analysis_port    #(my_transaction)    ap;

在UVM中,通常使用TLM(Transaction Level Modeling)实现compone之间transaction级别的通信。

数据的一种发送方式:uvm_analysis_port

数据的一种接收方式:uvm_blocking_get_port


my_monitor在main_phase收集完一个transaction,将其写入ap中:

            task my_monitor::main_phase(uvm_phase phase);

                ......

                ap.write(tr);

my_env中使用fifo将 ap 和 port 端口联系在一起:

            uvm_tlm_analysis_fifo    #(my_transaction)    agt_mdl_fifo;

            ......

            agt_mdl_fifo = new("agt_mdl_fifo", this);

my_env在connect_phase中将fifo分别与my_monitor中的analysis_port和my_model中的blocking_get_port相连:

            function void my_env::connect_phase(uvm_phase phase);

                super.connect_phase(phase);

                i_agt.ap.connect(agt_mdl_fifo.analysis_export);

                mdl.port.connect(agt_mdl_fifo.blocking_get_export);

            endfunction

my_agent在connect_phase中:ap = mon.ap。


2.3.6 加入scoreboard

class my_scoreboard extends uvm_scoreboard;


2.3.7 加入field_automation机制

class my_transaction extends uvm_sequence_item;

    rand bit[47:0] dmac;

    rand byte       pload[];

    ......

    `uvm_object_utils_begin(my_transaction)

        `uvm_field_int(dmac, UVM_ALL_ON)

        `uvm_field_array_int(pload, UVM_ALL_ON)

    `uvm_object_utils_end

endclass


使用uvm_object_utils_begin和uvm_object_utils_end来实现my_factory的factory注册,在这两个宏中间,使用uvm_field宏注册所有字段,就可以直接调用copy, compare, print等函数。


data_size = tr.pack_bytes(data_q)/8

            pack_bytes将 tr 中的所有字段变成byte流放入data_q中,字段按照uvm_field系列宏书写的顺序排列。


data_size = tr.unpack_bytes(data_array)/8

            unpack_bytes将data_q中的byte流转换成 tr 中的各个字段,其输入参数必须是一个动态数组。



2.4 UVM的终极大作:Sequence

2.4.1 在验证平台中加入sequencer

在规范化的UVM验证平台中,driver只负责驱动transaction,而不负责产生transaction。

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


class my_driver extends uvm_driver #(my_transaction);


2.4.2 sequence机制

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


当一个sequence启动之后,会自动执行body中的代码。

`uvm_do: (1)创建一个my_transaction的实例m_trans; (2)将其随机化; (3)最终将其送给sequencer。


uvm_driver中有成员变量seq_item_port,uvm_sequencer中有成员变量seq_item_export,这两者之间可以建立一个通道,通道中传递transaction。在my_agent中,使用connect函数将两者联系在一起:

drv.seq_item_port.connect(sqr.seq_item_export);


2.4.3 default_sequence的使用

"my_env.sv"

virtual function void build_phase(uvm_phase phase);

    super.build_phase(phase);

    ......

    uvm_config_db#(uvm_object_wrapper)::set(this, "i_agt.sqr.main_phase", "default_sequence", my_sequence::type_id::get());


2.5 建造测试用例

2.5.1 加入base_test

class base_test extends uvm_test;

    my_env    env;

    function new(...)

    extern virtual function void build_phase(uvm_phase phase);

    extern virtual function void report_phase(uvm_phase phase);

    `uvm_component_utils(base_test)

endclass


2.5.2 UVM中测试用例的启动

class case0_sequence extends uvm_sequence #(my_transaction);

......

endclass

class my_case0 extends base_test

    ......

    uvm_config_db#(uvm_object_wrapper)::set(this, "env.i_agt.sqr.main_phase", "default_sequence", case0_sequence::type_id::get());


class case1_sequence extends uvm_sequence #(my_transaction);

......

endclass

class my_case1 extends base_test

......

endclass


                

你可能感兴趣的:(第二章 一个简单的UVM验证平台)