精华内容
下载资源
问答
  • 本人学习过程中整理的各项UVM相关资料,包括:UVM primer, UVM实战及笔记,UVM Cookbook,SV_UVM_Debug,UVM初级开发指南,UVM快速学习教程等。
  • UVM 在 VCS 中的详细教程,但是对于初学者就是一 道屏障,我探索了几天,下文将一步一步的举例子说明 UVM+VCS+Verdi 的 liunx 平台搭建过 程(假设你已经安装好 VCS 和 verdi )、和 Questa sim+UVM 的 window 平台...
  • uvm教程链接汇总

    2021-04-16 17:27:52
  • UVM Connect - SV-SystemC interoperability 464 UvmConnect 464 UvmConnect/Connections 466 UvmConnect/Conversion 468 UvmConnect/CommandAPI 472 UVM Express - step by step improvement 476 UvmExpress 476 ...
  • UVM极简教程

    万次阅读 多人点赞 2019-06-21 17:05:38
    UVM(universal verification method)作为通用验证方法学,解决了什么问题? 验证平台的规范化 验证环境包括激励输入和输出数据的比对。UVM将激励、比对、reference model分别实现为不同的类。在子IP验证环境中使用...

    UVM(universal verification method)作为通用验证方法学,解决了什么问题?

    • 验证平台的规范化

    验证环境包括激励输入和输出数据的比对。UVM将激励、比对、reference model分别实现为不同的类。在子IP验证环境中使用的组件,可以在IP验证环境中复用。

    • 对System Verilog的封装

    System Verilog引入了类似C++,java的语法,可以实现为类。类给我们带来的好处就是封装、继承、多态。

    https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1561024690522&di=38ecd78c14567e7c2e4c9ad0a6225b8f&imgtype=0&src=http%3A%2F%2Fimage.mamicode.com%2Finfo%2F201605%2F20180110193019695430.png

    展开说一下,

    • UVM环境

    UVM的整体环境封装在uvm_env中,这可以看作是与真正实例化module的tb同级的环境。

    • UVM Sequence

    UVM Sequence是负责发送transaction包的激励来源。

    比如axi总线的一个transaction,在真正的verilog中,是按照clock的一拍一拍的数据和地址,在UVM中,可以定义一个uvm_sequence_item,将这一整包的数据和地址封装为成员为int address, int data[]的类;sequence就是负责产生各种各样的transaction。

    注意:

    1)并不是验证环境中只有一个sequence,而是可能会存在多个sequence。

    比如存在以下三种sequence:

            专门发送长包的sequence

            专门发送短包的sequence

            发送存在错包的sequence

    将这三种sequence包装为一个virtual sequence,即可复用其他的验证环境,发送随机间隔的长包、短包、错包sequence。

    2)sequence和transaction都是uvm_sequencet_item类型,都是object,而非component。

    • UVM Sequencer

    UVM Sequencer主要负责将Sequence产生的transaction,转发给driver。

    在case中可以通过设置*sequence.start(*sequencer)指明特定sequence是运行在哪个sequencer上的。

    在sequence中包括m_sequencer成员,在调用sequence的start方法时,会调用set_item_context方法,而这个方法又进一步调用了set_sequencer方法,将uvm_sequence_item中的m_sequencer成员指定了sequencer。

     

    通过m_sequencer这个方式,sequence可以明确当前运行在哪个sequencer上,获取sequencer的信息(需要将m_sequencer通过cast转换为扩展类sequencer类型)。

    • UVM Driver

    UVM Driver的作用:

    1. 将transaction类分解为具体的时序信号,传递到interface接口上;
    2. 完成与sequencer的握手,即来自sequencer的request,driver将会返回response;

     

    张强的《UVM实战》上打了比分:sequence好比是弹夹,driver好比是手枪,这个比喻

    比较形象,sequence里面装满了一颗一颗的子弹,子弹的上膛,发射都是driver作用的,driver如果通用性实现的比较好,是可以发送不同类型的子弹的,这也体现了验证平台的复用。

     

           需要注意的是,driver一般可以实现成forever的,持续的发送transaction,直到结束。这也可以理解成一个只要有子弹,就一直发射的手枪。

    • UVM Reference Model

    UVM Reference Model一般是用C/C++完成的,用于与DUT进行比对的算法,在平台中的作用:

    1. 接收设计DUT的输入transaction,根据算法计算,产生期望比对transaction
    2. 将transaction传出给scoreboard
    • UVM Monitor

    UVM Monitor用于检测interface接口上的数据,其作用:

    1. 将输入DUT interface接口上的数据接收,打包,传递给UVM Reference Model,作为其输入;
    2. 将输出DUT interface接口上的数据接收,打包,传递给UVM Scoreboard,作为其输入
    3. 可以进行protocol的检查;是否interface不满足protocol协议。
    • UVM Scoreboard

    UVM Scoreboard用于将uvm reference model的期望输出与monitor接收到的dut实际输出进行比对。

    • UVM Agent

    UVM Agent负责封装sequencer、driver、monitor;之所以封装这三者,存在以下原因:

    1. 由于在DUT的输入端存在sequencer、driver、monitor;DUT输出端存在monitor;封装为agent后,在env环境中封装两个agent,其中一个为active的agent,其成员为sequencer、driver、monitor;非active的agent仅包括monitor。
    2. 考虑nic的情况,在验证nic时,如果存在多路输入输出,每一路都需要driver、sequencer,如果实例化多套driver,sequencer,monior那么会十分繁琐;在封装后,只需要实例化多套agent即可。

    • Interface

    UVM 环境是基于SystemVerilog类的,设计代码在tb中是使用verilog的方式例化的,如何将设计代码的接口与driver连接呢?通过interface。

    在tb_top中例化interface,与dut的接口连接;

    在driver 类中例化virtual interface;使用uvm_config_db的方式即可将driver中的接口与dut的接口连接。

    此外,介绍一些UVM中比较关键的概念,UVM借鉴了设计模式中的工厂模式,代理模式,单例模式等,使得UVM更加便于使用。本质上这些模式也是基于继承、多态;通过指针或者引用的形式,使基类指针可以指向各式各样的继承类。

    1.Factory 工厂

    在声明继承类型,如uvm_driver的子类my_driver,可以通过uvm_component_utils的形式,来对通过工厂进行注册。在创建类时,也是通过my_driver::type_id::create()进行创建,type_id本质上是uvm_object_registry的别名,通过registry,在单例factory中,对该类进行了创建。

    利用工厂的一个关键好处在于可以使用重载。比如,目前使用的是my_driver,如果想批量的替换成your_driver,可以调用set_override_by_type的方法,将my_driver直接重载掉。

    2.uvm_config_db方法

    uvm_config_db方法可以实现在不同的component之间传递信息,即set、get。

    即比如之前介绍的sequence,如果负责产生axi_transaction,而具体是怎么类型的transaction,burst的大小,地址的大小,是可以通过配置sequence而改变的。那么如何配置sequence呢?testcase是class,sequence也是class,这些component通过什么进行信息交互呢?

    就是uvm_config_db,可以在使用uvm_config_db#(**)::set(*,*,*)来配置,那么uvm_config_db是如何具体工作的呢?

    uvm_config_db继承自uvm_resource_db,在其内部存在静态的uvm_pool类型的关联数组m_rsc。m_rsc的索引为component,值为对应component需要set的uvm_pool。

    uvm_pool的索引为loopup = {inst_name,”_M_UVM_”,filed_name},其值为uvm_resource类型的r。

    如果是set:

    通过r.write(value,cntxt)对r赋值,通过r.set_overide(),向全局静态的uvm_resource_pool写入这个r。

    如果是get:

    通过uvm_resource_pool::get()获得uvm_resouce_pool类型的rp,通过rp.lookup_regex_names获得uvm_reource_types::rsrc_q_t类型的rq,在rq中存放包括优先级的resource 队列,获取优先级最高的uvm_resource,即为返回值。

     

    说了好多,总之,uvm_config_db的set,get是通过静态的uvm_resource_pool进行信息传递的。

    uvm_resource_pool理解可以参考源码:./src/base/uvm_resource.svh

     

    3.::type_id::create::

    UVM约定俗成的要求在class中使用`uvm_component_utils(****_driver)进行注册,在创建时使用my_driver = ***_driver::type_id::create(“my_driver”, );进行创建。

    这背后的机制是什么呢?

    `uvm_component_utils(T)使用宏定义,其进一步调用了`m_uvm_component_regsitery_internal(T,T),在这个宏中,定义了uvm_component_registry #(T,`“S`”)类型的type_id,在uvm_component_registry中实现了create()函数。Create()函数是创建的重头戏:

               Create()函数首先调用uvm_factory::get()方法,得到全局的uvm_factory类型的f,通过obj=f.create_component_by_type(get(),contxt,name,parent())创建这个obj。

                                                                

     

    4.Phase机制

    Phase机制理解起来比较简单,如果把验证平台中的不同的component理解成一个班级里上课的同学,那么虽然不同的同学每节课写作业有快有慢,但是他们都是整齐划一的按照上课的时间,下课的时间,共享一个作息表。

                                                                                   

                                                                                                                               

                                                                                                                              ————欢迎关注我的公众号《处理器与AI芯片》 

    展开全文
  • UVM快速学习教程

    2018-06-02 00:46:12
    uvm验证方法学介绍,源代码分享,结合system Verilog验证,
  • UVM的基本教程

    千次阅读 2020-12-01 14:02:31
    文章目录一、基本介绍二、在实践中学习1.接口interface2.待测设计DUT3.传输数据包transaction4.序列sequence5.序列器sequencer6.驱动器driver7....通用验证方法学UVM(Universal Verification Met.


    一、基本介绍

    通用验证方法学UVM(Universal Verification Methodology)已经成为集成电路设计的验证标准。UVM类构建的库促进了测试用例的搭建,UVM测试用例的每一个元素都是从现有的UVM类派生出来的。
    每个类都有仿真阶段,这些仿真阶段作为类的方法,按照一定的顺序执行。其中较为常用的几个UVM阶段如下:

    • build_phase负责测试用例结构的创建和配置,构建组件的层次结构。
    • connect_phase用于连接类中的不同子组件。
    • run_phase是主要阶段,在其中执行仿真。
    • report_phase可用于显示仿真的结果

    为了在类和变量中实现一些重要的方法,UVM提供了UVM宏。最常见的UVM宏如下:

    • uvm_component_utils: 当类从uvm_component类派生时,注册一个新的类的类型。
    • uvm_object_utils: 类似于uvm_component_utils,但类是从类uvm_object派生的类。
    • uvm_field_int: 在UVM工厂注册一个变量。这个宏提供了像copy()、compare()和print()这样的函数.
    • uvm_info:在环境中仿真期间打印消息。
    • uvm_error:这个宏发送带有错误日志的消息。
    • uvm_fatal: 仿真发生致命错误时,这个宏可以强制结束仿真并打印消息。

    为了解释一个UVM环境的结构,在测试用例中,将使用一个简单的加法器作为测试设计(DUT)。UVM测试平台如图所示。DUT是与测试台交互以验证其功能的硬件实现。
    图1 UVM 测试平台
    为了实现DUT的仿真, sequencer产生一系列数据送入DUT。由于sequencer发送高抽象级别的数据包,并且DUT只接受来自接口的数据,所以,driver用来将来自sequencer的数据包,转换成信号送入DUT。
    经过接口的数据需要被捕获,以便后续的仿真验证。由于driver只能实现数据包到信号的转换,所以,另外还需要一个模块实现与driver相反的功能,将信号转换成数据包。monitor就是这样的一个模块,收集driver与DUT之间通信的接口信号,并将其转换成数据包,最后送入参考模型中去进行比较。
    一个agent通常包含三个组件:一个sequencer序列发生器,一个driver驱动,一个monitor监控。有两种类型的agent:Active Agent包含上述三个组件;Passive Agent只包含上述的monitor监控和driver驱动。agent包含build phase函数,用于去创建层次结果,以及connect phase用于连接模块。
    参考模型(refmod)是在RTL实现之前,早期阶段构思的理想的模型。在抽象的高级别上模拟DUT。
    comparator类主要用于比较参考模型和DUT之间的数据。参考模型和比较器组成了记分牌,用于检查DUT产生的传输是否正确。一个或者多个agent加上记分牌构成了env类。测试类负责执行测试,创建环境,并将序列连接到序列发生器上。最后,top中实现DUT和testbench的例化。

    二、在实践中学习

    下面通过对一个加法器验证环境的搭建,来进一步理解UVM中的各个组件。加法器模块的功能验证平台分为以下的模块和类。

    1.接口interface

    接口的构造是专门为封装块之间的通信信号而创建的,modport为模块端口提供方向信息,并控制特定模块内任务和功能的使用。

    interface input_if(input clk, rst);
        logic [31:0] A, B;
        logic valid, ready;
        
        modport port(input clk, rst, A, B, valid, output ready);
    endinterface
    
    
    interface output_if(input clk, rst);
        logic [31:0] data;
        logic valid, ready;
        
        modport port(input clk, rst, output valid, data, ready);
    endinterface
    
    

    2.待测设计DUT

    待测设计DUT(design under test)是需要被验证的设计代码。

    module adder(input_if.port inter, output_if.port out_inter, output state);
        enum logic [1:0] {INITIAL,WAIT,SEND} state;
        
        always_ff @(posedge inter.clk)
            if(inter.rst) begin
                inter.ready <= 0;
                out_inter.data <= 'x;
                out_inter.valid <= 0;
                state <= INITIAL;
            end
            else case(state)
                    INITIAL: begin
                        inter.ready <= 1;
                        state <= WAIT;
                    end
                    
                    WAIT: begin
                        if(inter.valid) begin
                            inter.ready <= 0;
                            out_inter.data <= inter.A + inter.B;
                            out_inter.valid <= 1;
                            state <= SEND;
                        end
                    end
                    
                    SEND: begin
                        if(out_inter.ready) begin
                            out_inter.valid <= 0;
                            inter.ready <= 1;
                            state <= WAIT;
                        end
                    end
            endcase
    endmodule: adder
    

    3.传输数据包transaction

    传输数据包的构造是专门为封装块之间通信的数据而创建的,其中的field机制能够将数据包中的数据注册到UVM工厂中,为数据提供copy()、compare()、print()、colne()等函数。

    class packet_in extends uvm_sequence_item;
        rand integer A;
        rand integer B;
    
        `uvm_object_utils_begin(packet_in)
            `uvm_field_int(A, UVM_ALL_ON|UVM_HEX)
            `uvm_field_int(B, UVM_ALL_ON|UVM_HEX)
        `uvm_object_utils_end
    
        function new(string name="packet_in");
            super.new(name);
        endfunction: new
    endclass: packet_in
    
    
    class packet_out extends uvm_sequence_item;
        integer data;
    
        `uvm_object_utils_begin(packet_out)
            `uvm_field_int(data, UVM_ALL_ON|UVM_HEX)
        `uvm_object_utils_end
    
        function new(string name="packet_out");
            super.new(name);
        endfunction: new
    endclass: packet_out
    

    4.序列sequence

    UVM序列是一个对象,它用于生成仿真的行为。UVM序列不是组件层次结构的一部分。每个UVM序列最终被绑定到一个UVM序列器。多个UVM序列实例可以绑定到同一个UVM序列器。

    class sequence_in extends uvm_sequence #(packet_in);
        `uvm_object_utils(sequence_in)
    
        function new(string name="sequence_in");
            super.new(name);
        endfunction: new
    
        task body;
            packet_in tx;
    
            forever begin
                tx = packet_in::type_id::create("tx");
                start_item(tx);
                assert(tx.randomize());
                finish_item(tx);
            end
        endtask: body
    endclass: sequence_in
    

    5.序列器sequencer

    UVM序列器作为仲裁器,用于控制来自多个仿真序列的事务流。更具体地说,UVM序列器控制,由一个或多个UVM序列生成的事务流。

    class sequencer extends uvm_sequencer #(packet_in);
        `uvm_component_utils(sequencer)
    
        function new (string name = "sequencer", uvm_component parent = null);
            super.new(name, parent);
        endfunction
    endclass: sequencer
    
    

    6.驱动器driver

    驱动器(driver)从序列器(sequencer),接收序列(sequence)产生的传输数据包(transaction),并在DUT接口上应用(驱动)它。因此,驱动器driver将传输级别的数据包仿真,转换成管脚信号级别的仿真。它还有一个TLM接口,用于接收来自序列器sequencer的传输数据包transaction,去驱动DUT上的接口信号。

    typedef virtual input_if input_vif;
    
    class driver extends uvm_driver #(packet_in);
        `uvm_component_utils(driver)
        input_vif vif;
        event begin_record, end_record;
    
        function new(string name = "driver", uvm_component parent = null);
            super.new(name, parent);
        endfunction
    
        virtual function void build_phase(uvm_phase phase);
            super.build_phase(phase);
            assert(uvm_config_db#(input_vif)::get(this, "", "vif", vif));
        endfunction
    
        virtual task run_phase(uvm_phase phase);
            super.run_phase(phase);
            fork
                reset_signals();
                get_and_drive(phase);
                record_tr();
            join
        endtask
    
        virtual protected task reset_signals();
            wait (vif.rst === 1);
            forever begin
                vif.valid <= '0;
                vif.A <= 'x;
                vif.B <= 'x;
                @(posedge vif.rst);
            end
        endtask
    
        virtual protected task get_and_drive(uvm_phase phase);
            wait(vif.rst === 1);
            @(negedge vif.rst);
            @(posedge vif.clk);
            
            forever begin
                seq_item_port.get(req);
                -> begin_record;
                drive_transfer(req);
            end
        endtask
    
        virtual protected task drive_transfer(packet_in tr);
            vif.A = tr.A;
            vif.B = tr.B;
            vif.valid = 1;
    
            @(posedge vif.clk)
            
            while(!vif.ready)
                @(posedge vif.clk);
            
            -> end_record;
            @(posedge vif.clk); //hold time
            vif.valid = 0;
            @(posedge vif.clk);
        endtask
    
        virtual task record_tr();
            forever begin
                @(begin_record);
                begin_tr(req, "driver");
                @(end_record);
                end_tr(req);
            end
        endtask
    endclass
    
    
    typedef virtual output_if output_vif;
    
    class driver_out extends uvm_driver #(packet_out);
        `uvm_component_utils(driver_out)
        output_vif vif;
    
        function new(string name = "driver_out", uvm_component parent = null);
            super.new(name, parent);
        endfunction
    
        virtual function void build_phase(uvm_phase phase);
            super.build_phase(phase);
            assert(uvm_config_db#(output_vif)::get(this, "", "vif", vif));
        endfunction
    
        virtual task run_phase(uvm_phase phase);
            super.run_phase(phase);
            fork
                reset_signals();
                drive(phase);
            join
        endtask
    
        virtual protected task reset_signals();
            wait (vif.rst === 1);
            forever begin
                vif.ready <= '0;
                @(posedge vif.rst);
            end
        endtask
    
        virtual protected task drive(uvm_phase phase);
            wait(vif.rst === 1);
            @(negedge vif.rst);
            forever begin
              @(posedge vif.clk);
              vif.ready <= 1;
            end
        endtask
    endclass
    

    7.监视器monitor

    监视器(monitor)对DUT接口进行采样,并捕获事务中的信息,构成传输数据包(transaction),这些传输数据包被发送到UVM测试台以进行进一步分析。因此,与驱动器(driver)类似,但过程相反,它实现的是将管脚信号上的信号收集转换成传输数据包。
    UVM监视器可以在内部对所产生的事务执行一些处理(例如覆盖率收集、检查、日志记录、记录等等)。

    class monitor extends uvm_monitor;
        input_vif  vif;
        event begin_record, end_record;
        packet_in tr;
        uvm_analysis_port #(packet_in) item_collected_port;
        `uvm_component_utils(monitor)
       
        function new(string name, uvm_component parent);
            super.new(name, parent);
            item_collected_port = new ("item_collected_port", this);
        endfunction
    
        virtual function void build_phase(uvm_phase phase);
            super.build_phase(phase);
            assert(uvm_config_db#(input_vif)::get(this, "", "vif", vif));
            tr = packet_in::type_id::create("tr", this);
        endfunction
    
        virtual task run_phase(uvm_phase phase);
            super.run_phase(phase);
            fork
                collect_transactions(phase);
                record_tr();
            join
        endtask
    
        virtual task collect_transactions(uvm_phase phase);
            wait(vif.rst === 1);
            @(negedge vif.rst);
            
            forever begin
                do begin
                    @(posedge vif.clk);
                end while (vif.valid === 0 || vif.ready === 0);
                -> begin_record;
                
                tr.A = vif.A;
                tr.B = vif.B;
                item_collected_port.write(tr);
    
                @(posedge vif.clk);
                -> end_record;
            end
        endtask
    
        virtual task record_tr();
            forever begin
                @(begin_record);
                begin_tr(tr, "monitor");
                @(end_record);
                end_tr(tr);
            end
        endtask
    endclass
    
    
    class monitor_out extends uvm_monitor;
        `uvm_component_utils(monitor_out)
        output_vif  vif;
        event begin_record, end_record;
        packet_out tr;
        uvm_analysis_port #(packet_out) item_collected_port;
       
        function new(string name, uvm_component parent);
            super.new(name, parent);
            item_collected_port = new ("item_collected_port", this);
        endfunction
    
        virtual function void build_phase(uvm_phase phase);
            super.build_phase(phase);
            assert(uvm_config_db#(output_vif)::get(this, "", "vif", vif));
            tr = packet_out::type_id::create("tr", this);
        endfunction
    
        virtual task run_phase(uvm_phase phase);
            super.run_phase(phase);
            fork
                collect_transactions(phase);
                record_tr();
            join
        endtask
    
        virtual task collect_transactions(uvm_phase phase);
            wait(vif.rst === 1);
            @(negedge vif.rst);
            
            forever begin
                do begin
                    @(posedge vif.clk);
                end while (vif.valid === 0 || vif.ready === 0);
                -> begin_record;
                
                tr.data = vif.data;
                item_collected_port.write(tr);
    
                @(posedge vif.clk);
                -> end_record;
            end
        endtask
    
        virtual task record_tr();
            forever begin
                @(begin_record);
                begin_tr(tr, "monitor_out");
                @(end_record);
                end_tr(tr);
            end
        endtask
    endclass
    

    8.代理agent

    代理(agent)是一个分层组件,它将处理特定DUT接口的其他验证组件组合在一起。一个典型的代理包括:一个sequencer,用于管理仿真流的UVM序列器;一个driver,用于在DUT接口上驱动仿真的驱动器;一个monitor,用于监视DUT的接口。代理可能包括其他组件,如覆盖率收集器、协议检查器、TLM模型等。
    在这里插入图片描述

    class agent extends uvm_agent;
        sequencer sqr;
        driver    drv;
        monitor   mon;
    
        uvm_analysis_port #(packet_in) item_collected_port;
    
        `uvm_component_utils(agent)
    
        function new(string name = "agent", uvm_component parent = null);
            super.new(name, parent);
            item_collected_port = new("item_collected_port", this);
        endfunction
    
        virtual function void build_phase(uvm_phase phase);
            super.build_phase(phase);
            mon = monitor::type_id::create("mon", this);
            sqr = sequencer::type_id::create("sqr", this);
            drv = driver::type_id::create("drv", this);
        endfunction
    
        virtual function void connect_phase(uvm_phase phase);
            super.connect_phase(phase);
            mon.item_collected_port.connect(item_collected_port);
            drv.seq_item_port.connect(sqr.seq_item_export);
        endfunction
    endclass: agent
    
    
    class agent_out extends uvm_agent;
        driver_out    drv;
        monitor_out   mon;
    
        uvm_analysis_port #(packet_out) item_collected_port;
    
        `uvm_component_utils(agent_out)
    
        function new(string name = "agent_out", uvm_component parent = null);
            super.new(name, parent);
            item_collected_port = new("item_collected_port", this);
        endfunction
    
        virtual function void build_phase(uvm_phase phase);
            super.build_phase(phase);
            mon = monitor_out::type_id::create("mon_out", this);
            drv = driver_out::type_id::create("drv_out", this);
        endfunction
    
        virtual function void connect_phase(uvm_phase phase);
            super.connect_phase(phase);
            mon.item_collected_port.connect(item_collected_port);
        endfunction
    endclass: agent_out
    

    9.记分板scoreboard

    记分板(scoreboard)的主要功能是检查DUT的行为是否正确。记分板接收的实际数据包,来自代理(agent)送入DUT的输入输出,接收的期望数据包,来自参考模型,最后在记分板中比较实际的数据包和期望的数据包。

    class comparator #(type T = packet_out) extends uvm_scoreboard;
      typedef comparator #(T) this_type;
      `uvm_component_param_utils(this_type)
    
      const static string type_name = "comparator #(T)";
    
      uvm_put_imp #(T, this_type) from_refmod;
      uvm_analysis_imp #(T, this_type) from_dut;
    
      typedef uvm_built_in_converter #( T ) convert; 
    
      int m_matches, m_mismatches;
      T exp;
      bit free;
      event compared, end_of_simulation;
    
      function new(string name, uvm_component parent);
        super.new(name, parent);
        from_refmod = new("from_refmod", this);
        from_dut = new("from_dut", this);
        m_matches = 0;
        m_mismatches = 0;
        exp = new("exp");
        free = 1;
      endfunction
    
      virtual function string get_type_name();
        return type_name;
      endfunction
    
      task run_phase(uvm_phase phase);
        phase.raise_objection(this);
        @(end_of_simulation);
        phase.drop_objection(this);
      endtask
    
      virtual task put(T t);
        if(!free) @compared;
        exp.copy(t);
        free = 0;
        
        @compared;
        free = 1;
      endtask
    
      virtual function bit try_put(T t);
        if(free) begin
          exp.copy(t);
          free = 0;
          return 1;
        end
        else return 0;
      endfunction
    
      virtual function bit can_put();
        return free;
      endfunction
    
      virtual function void write(T rec);
        if (free)
          uvm_report_fatal("No expect transaction to compare with", "");
        
        if(!(exp.compare(rec))) begin
          uvm_report_warning("Comparator Mismatch", "");
          m_mismatches++;
        end
        else begin
          uvm_report_info("Comparator Match", "");
          m_matches++;
        end
        
        if(m_matches+m_mismatches > 100)
          -> end_of_simulation;
        
        -> compared;
      endfunction
    endclass
    

    10.仿真环境env

    仿真环境env是一个分层组件,它将其他相互关联的验证组件组合在一起。通常在仿真环境env中实例化的典型组件有代理(agent)、记分牌(scoreboard),甚至其他仿真环境。
    顶层仿真环境封装了所有针对DUT的验证组件。

    class env extends uvm_env;
        agent       mst;
        refmod      rfm;
        agent_out   slv;
        comparator #(packet_out) comp;  
        uvm_tlm_analysis_fifo #(packet_in) to_refmod;
    
        `uvm_component_utils(env)
    
        function new(string name, uvm_component parent = null);
            super.new(name, parent);
            to_refmod = new("to_refmod", this); 
        endfunction
    
        virtual function void build_phase(uvm_phase phase);
            super.build_phase(phase);
            mst = agent::type_id::create("mst", this);
            slv = agent_out::type_id::create("slv", this);
            rfm = refmod::type_id::create("rfm", this);
            comp = comparator#(packet_out)::type_id::create("comp", this);
        endfunction
    
        virtual function void connect_phase(uvm_phase phase);
            super.connect_phase(phase);
            // Connect MST to FIFO
            mst.item_collected_port.connect(to_refmod.analysis_export);
            
            // Connect FIFO to REFMOD
            rfm.in.connect(to_refmod.get_export);
            
            //Connect scoreboard
            rfm.out.connect(comp.from_refmod);
            slv.item_collected_port.connect(comp.from_dut);
        endfunction
    
        virtual function void end_of_elaboration_phase(uvm_phase phase);
            super.end_of_elaboration_phase(phase);
        endfunction
      
        virtual function void report_phase(uvm_phase phase);
            super.report_phase(phase);
            `uvm_info(get_type_name(), $sformatf("Reporting matched %0d", comp.m_matches), UVM_NONE)
            if (comp.m_mismatches) begin
                `uvm_error(get_type_name(), $sformatf("Saw %0d mismatched samples", comp.m_mismatches))
            end
        endfunction
    endclass
    
    
    

    11.测试用例test

    测试用例是测试台中最顶层的组件。测试用例通常执行三个主要功能:实例化顶层环境、配置环境(通过工厂覆盖或配置数据库),以及通过在环境中调用序列来进行仿真。
    通常,有一个带有UVM环境实例化和其他公共项的基本UVM测试。然后,其他单独的测试将扩展这个基本测试,并以不同的方式配置环境或选择不同的序列运行。
    测试用例是在运行时动态实例化的,允许UVM测试台只编译一次,并与许多不同的测试一起运行。

    class simple_test extends uvm_test;
      env env_h;
      sequence_in seq;
    
      `uvm_component_utils(simple_test)
    
      function new(string name, uvm_component parent = null);
        super.new(name, parent);
      endfunction
    
      virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        env_h = env::type_id::create("env_h", this);
        seq = sequence_in::type_id::create("seq", this);
      endfunction
     
      task run_phase(uvm_phase phase);
        seq.start(env_h.mst.sqr);
      endtask: run_phase
    
    endclass
    

    12.顶层top

    顶层主要实例化DUT模块和测试类,并配置它们之间的连接。

    import uvm_pkg::*;
    `include "uvm_macros.svh"
    `include "./input_if.sv"
    `include "./output_if.sv"
    `include "./adder.sv"
    `include "./packet_in.sv"
    `include "./packet_out.sv"
    `include "./sequence_in.sv"
    `include "./sequencer.sv"
    `include "./driver.sv"
    `include "./driver_out.sv"
    `include "./monitor.sv"
    `include "./monitor_out.sv"
    `include "./agent.sv"
    `include "./agent_out.sv"
    `include "./refmod.sv"
    `include "./comparator.sv"
    `include "./env.sv"
    `include "./simple_test.sv"
    
    //Top
    module top;
      logic clk;
      logic rst;
      
      initial begin
        clk = 0;
        rst = 1;
        #22 rst = 0;
        
      end
      
      always #5 clk = !clk;
      
      logic [1:0] state;
      
      input_if in(clk, rst);
      output_if out(clk, rst);
      
      adder sum(in, out, state);
    
      initial begin
        `ifdef INCA
           $recordvars();
        `endif
        `ifdef VCS
            //$vcdpluson;
            $fsdbDumpfile("test.fsdb");
        	$fsdbDumpSVA();
        	$fsdbDumpvars();
            $fsdbDumpMDA();
        `endif
        `ifdef QUESTA
           $wlfdumpvars();
           set_config_int("*", "recording_detail", 1);
        `endif
        
        uvm_config_db#(input_vif)::set(uvm_root::get(), "*.env_h.mst.*", "vif", in);
        uvm_config_db#(output_vif)::set(uvm_root::get(), "*.env_h.slv.*",  "vif", out);
        
        run_test("simple_test");
      end
    endmodule
    

    13.参考模型reference mode和直接编程接口(DPI)

    SystemVerilog直接编程接口(DPI)是SystemVerilog调用外部语言(如C、c++等)函数的接口。DPI由两个层组成:SystemVerilog层和外语层,它们彼此隔离。下面给出了refmod的代码,以说明DPI的用法。sum()函数在文件external.cpp中定义,一旦在refmod中调用它,就应该在sum()函数的定义之前添加关键字“external C”

    #include <stdio.h>
    #include <math.h>
    
    extern "C" int sum(int a, int b){
      return a+b;
    }
    
    
    import "DPI-C" context function int sum(int a, int b);
    
    class refmod extends uvm_component;
        `uvm_component_utils(refmod)
        
        packet_in tr_in;
        packet_out tr_out;
        integer a, b;
        uvm_get_port #(packet_in) in;
        uvm_put_port #(packet_out) out;
        
        function new(string name = "refmod", uvm_component parent);
            super.new(name, parent);
            in = new("in", this);
            out = new("out", this);
        endfunction
        
        virtual function void build_phase(uvm_phase phase);
            super.build_phase(phase);
            tr_out = packet_out::type_id::create("tr_out", this);
        endfunction: build_phase
        
        virtual task run_phase(uvm_phase phase);
            super.run_phase(phase);
            
            forever begin
                in.get(tr_in);
                tr_out.data = sum(tr_in.A, tr_in.B);
                out.put(tr_out);
            end
        endtask: run_phase
    endclass: refmod
    
    

    14.简单的makefile

    comp: clean
    	g++ -c external.cpp -o external.o
    	vcs -full64  -sverilog top.sv -dpi -ntb_opts uvm -debug_pp -timescale=1ns/10ps  external.o -debug_access+cbk -lca -cm tgl+line+fsm+cond+branch
    
    sim:
    	./simv +UVM_TR_RECORD +UVM_VERBOSITY=HIGH +UVM_TESTNAME=simple_test -lca -cm tgl+line+fsm+cond+branch
    
    all: comp sim
    
    dbg: clean
    	g++ -c external.cpp -o external.o
    	vcs -full64  -sverilog top.sv -dpi -ntb_opts uvm -debug_pp -timescale=1ns/10ps  external.o -debug_access+cbk -debug_access+all -kdb -lca
    	$ ./simv +UVM_TR_RECORD +UVM_VERBOSITY=HIGH +UVM_TESTNAME=simple_test -gui=verdi
    
    clean:
    	rm -rf DVEfiles csrc simv simv.daidir ucli.key .vlogansetup.args .vlogansetup.env .vcs_lib_lock simv.vdb AN.DB vc_hdrs.h *.diag *.vpd *tar.gz external.o inter.fsdb novas.conf novas_dump.log novas.rc test.fsdb verdiLog
    
    view_waves:
    	dve &
    
    verdi:
    	verdi -sverilog -ntb_opts uvm-1.2 -timescale=1ns/10ps top.sv -f filelist.f +incdir+./ -ssf ./test.fsdb &
    
    urg_gui:
    	urg -dir *.vdb -format both -report urgReportALL; \
    firefox urgReportALL/tests.html &
    
    

    comp函数先通过g++编译C程序,再通过VCS进行编译,其中-debug_access+cbk选项对静态网络、寄存器和变量启用基于PLI的回调。-cm tgl+line+fsm+cond+branch选项开启代码翻转覆盖率、行覆盖率、状态机覆盖率、条件覆盖率、分支覆盖率。
    sim函数执行VCS仿真。
    dbg函数用于VCS和verdi联调,编译里边加入了-debug_access+all -kdb –lca选项,仿真里边加入了-gui=verdi选项。
    verdi函数用于启动verdi查看波形。
    urg_gui函数用于查看代码覆盖率。


    代码附件

    上述完整代码下载链接如下:
    https://github.com/AFEI1100/easyUVM-master.git

    展开全文
  • 验证结构 03学前指导 04【V3选学】VCS仿真器操作指导 04配套软件安装教程 05【V3选修】Vim编辑器操作及插件使用 06【验证通识2】验证环境的结构和组件 07【SV精通2】接口采样驱动_测试结束开始_调试方法 08【SV练习...

    视频、代码、课件、理论、实践、答疑(5个,设计和验证,资料总共168G)

     

    01【芯片验证V2系列课程介绍】

    02 V2Pro学习路径规划

    02【验证通识1】开发概述_验证前景_任务目标周期

    03【SV精通1】数据类型_过程方法_设计连接_验证结构

    03学前指导

    04【V3选学】VCS仿真器操作指导

    04配套软件安装教程

    05【V3选修】Vim编辑器操作及插件使用

    06【验证通识2】验证环境的结构和组件

    07【SV精通2】接口采样驱动_测试结束开始_调试方法

    08【SV练习选修】练习一指导

    08【验证通识3】验证计划和进程评估

    09【SV精通3】类的方法和继承_动态对象_包的使用

    10【验证通识4】验证的管理

    11【SV精通4】随机约束分布_约束块控制_数组约束_随机控制

    12【SV精通4】实验3代码讲解

    13【验证通识5】验证方法_UVM简介

    14【SV精通5】线程的控制和同步

    15【SV精通5】实验4代码讲解

    15【SV练习选修】练习二指导

    16【SV精通6】验证的量化和功能覆盖率

    17【SV精通7】高级话题

    18【V2Pro增量-1】DVTEclipse集成开发环境

    19【V2Pro增量-1】DVT工具项目运用

    20【V2 Pro增量-2】CDV覆盖率驱动验证-Tcl基础

    21【V2 Pro增量-2】CDV覆盖率驱动验证-验证管理

    22【V2 Pro增量-2】覆盖率驱动验证-Questasim常用命令

    23【UVM入门进阶1】方法学_类库_工厂

    24【UVM入门进阶2】核心基类_阶段_配置_消息机制

    25【UVM入门进阶3】组件家族

    26【UVM入门进阶4】结构_顶层方案_环境元素

    27【UVM入门进阶5】TLM通信_单向双向多向_通信管道

    28【UVM入门进阶6】TLM2通信_同步通信

    29【UVM入门进阶7】Item_Sequence_Sequencer_Driver

    30【UVM入门进阶8】Sequencer仲裁_Sequence层次化

    31【UVM入门进阶9】寄存器模型概览_集成

    32【UVM入门进阶10】寄存器模型方法_应用

    37【V3选学】SVTAPB商业VIP使用说明

    40【V2 Pro增量-3】自动化流程辅助实现-RA寄存器自动化

    40【虚拟项目-3】拨云见日

    41【V2 Pro增量-3】自动化流程辅助实现-RA寄存器自动化

    41【虚拟项目-4】峰峦叠嶂

    42【V2 Pro增量-4】验证回归管理-Questa VRM工具介绍及演示

    43【UVM项目实战1】MCDF更新_AMBA接口_验证环境更新

    43【V2 Pro增量-4】验证回归管理-回归数据文件RMDB及执行管理

    44【UVM项目实战2】验证IP模板_VIP开发流程

    45【UVM项目实战3】Assertion介绍_Sequence定义

    45【虚拟项目-1】丛林迷雾

    46【UVM项目实战4】Property使用_Assertion检查及覆盖率应用

    46【虚拟项目-2】强渡湍流

    47【UVM项目实战5】寄存器信息标准化和寄存器模型自动生成

    48【UVM项目实战6】组件更新和环境序列复用

    49【UVM项目实战7】DPI接口_虚拟处理器_UVM的C测试环境

    50【UVM项目实战8】寄存器应用_寄存器覆盖率_总线解析_性能分析

    V2.2 UVM实验答疑集锦-1

    第51课【微芯答疑:Tony555170】

    第52课【简历优化、模拟面试】

    展开全文
  • UVM经典教程.7z

    2020-07-13 20:17:00
    经典UVM教程,很好的学习资料,高清,有标签,内涵经典代码,非常适合初学者及多年工作经验的人,很好的资料
  • 视频版: ...课程前准备 建议准备仿真软件,熟悉VCS的同学可以直接使用VCS,不熟悉的同学建议直接再win平台的Questa就行了。 使用Questa前期不用打开GUI,不需要看波形,questa的图形界面还是有点... import uvm_pkg::...
  • UVM 快速学习教程

    2012-07-10 14:18:54
    The UVM (Universal Verification Methodology) Class Library provides the building blocks needed to quickly develop well-constructed and reusable verification components and test environments in ...
  • 推荐使用gitbash,使用makefile之前要安装makefile,教程在这里->https://www.eemaker.com/git-bash-make.html 本节代码下载链接:链接:https://pan.baidu.com/s/1JOJDUyBLSkXA67OsaDCLFg 提取码:c8n4 ...
  • 推荐使用gitbash,使用makefile之前要安装makefile,教程在这里->https://www.eemaker.com/git-bash-make.html 本节代码下载链接:链接:https://pan.baidu.com/s/1GBhvpGaoG_BNvRZqh-4kPA 提取码:4rcr ...
  • 当我们在Agent中创建jelly_bean_driver时,我们编写了build_phase函数和run_phase任务,但是实际调用它们的人是谁?答案是uvm_phase类。...这些phase类是从uvm_topdown_phase,uvm_bottomup_phase或uvm_task...
  • uvm+vcs+verdi基本平台搭建,也许平台不是很难,但是网上没有 UVM 在 VCS 中的详细教程,但是对于初学者就是一道屏障,我探索了几天,下文将一步一步的举例子说明 UVM+VCS+Verdi 的 liunx 平台搭建过程
  • UVM_GetStart教程

    2015-08-07 10:39:21
    uvm经典教程,从入门到精通,很实用,亲测。
  • 这篇文章揭示了糖果爱好者系列UVM教程的预期成果。使用创建的验证组件并写出测试用例,然后实际软件仿真运行。Test这个特殊的例子将告诉你如何开发一系列各种无糖的jelly_beans。测试类如下所述。class jelly_bean_...
  • 最近工作稍微没那么忙,就又开始找点书看,于是就看起《芯片验证漫游指南》,觉得有很多新鲜的知识,以前从来没用到,比如通过DPI的方式,以c为桥梁,搭建UVM与其他仿真软件的桥梁,再比如利用python处理UVM生成的...
  • do_record函数是由记录对象属性的uvm_object记录函数调用的用户可定义的钩子。定义do_record定义do_record不是很困难。我们来定义jelly_bean_transaction的do_record。我记录了与我在do_print中打印的属性相同的...
  • UVM糖果爱好者教程 - 1.概述

    千次阅读 2018-03-16 14:52:57
    Accellera最近发布的UVM可能会改变验证的未来,因为验证方法似乎在这个UVM中得到巩固。本专栏将提供关于这种新的验证方法的简单教程。本教程不是关注AXI,OCP或其他系统总线,而是基于jelly-bean生成器(DUT)的假设...
  • uvm-1.2.rar

    2020-11-12 00:13:00
    1小时玩转数字电路.rar AHB-SRAMC和FIFO的设计与验证.rar clock skew.rar IC攻城狮求职宝典.rar ...uvm-1.2.rar VCS_labs.rar Verdi 基础教程.rar Verilog RTL 编码实践.rar [Cadence.IC设计.全资料教
  • 我的第一批UVM教程(#1至#6)已于三年前发布。 从那以后,UVM(以及我的知识)已经发展,我一直想更新我的文章和代码。 但这并不容易,因为我的文章和代码紧密结合,读者的一些评论甚至提到了特定的代码行。UVM ...
  • UVM验证方法学

    热门讨论 2013-09-04 16:35:05
    UVM验证方法学,讲的非常细。个人认为很好!按照各种实例教你如何使用UVM搭建Testbenchf The Test Bench Module
  • 我们的 jelly-bean 业务表现良好,因此我们同时开始接受多份 jelly-bean 订单。有些客户也要求加急运输。...# KERNEL: UVM_INFO @ 255: uvm_test_top.jb_env.jb_agent.jb_drvr [jb_drvr] priority_...
  • UVM具有丰富的报告功能。 本文介绍如何使用冗长阈值来过滤消息。预定义的冗余度级别UVM预先定义了六个详细程度; UVM_NONE到UVM_DEBUG。 这些级别只不过是整数枚举值(图中的括号显示值)。 带有UVM_NONE级别的消息...
  • 当时写这个文档的目的是给后面做UVM验证的师弟师妹留个教程。后面经过导师同意将该文档分享出来,让更多学习UVM验证的同志受益。 文档中以张强的《UVM1.1应用指南及源代码分析》中的第一章的示例作为参考,简单讲述...
  • UVM糖果爱好者教程 - 32.定义do_print

    千次阅读 2018-06-28 14:48:21
    为方便起见,UVM预先定义了三个打印策略(uvm_default_table_printer,uvm_default_tree_printer和uvm_default_line_printer;第5至7行)。如果您未指定打印策略,则会使用默认设置为uvm_default_table_printer的uvm_...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 477
精华内容 190
关键字:

uvm教程