3. UVM -- factory机制与平台组件构建

3. UVM -- factory机制与平台组件构建

3.1. 什么是factory机制

  • UVM工厂机制可以使用户在不更改代码的情况下实现不同对象的替换;
  • 工厂是UVM的一种数据结构。它的作用范围是整个平台空间,它有且仅有一个实例化对象 (即单实例类)。它是一个 多态构造器,可仅仅使用一个函数让用户实例化很多不同类型的对象。
  • 为了使用一个函数而可以返回多种对象,这些对象必须从一个基类扩展而来。

3.2. uvm factory机制的原理及使用

img

3.2.1 factory机制的运作步骤

(1). factory注册:一般使用宏

注册
`uvm object utils() 对 uvm object类 进行注册
`uvm_component_utils() 对 uvm_component类 进行注册
`uvm object param utils() 对 object参数化类 进行注册
`uvm component param utils() 对 component参数化类 进行注册

宏的作用如下:

  • 为注册的类创建一个代理类:type_id

    • 这个类在注册类的内部,起到间接实例化对象的代理作用
    • 创建一个注册类的对象并将该对象向factory注册
    • type_id内建create函数,该函数的任务是根据替换表创建指定类的对象
  • 创建一个静态函数get_type()

  • 创建一个函数get_object_type(),非静态

(2). 实例化对象:要使用 静态方法 class_name:type_id:create() 来代替new实例化对象;

create()会按以下步骤执行:

  • 调用factory的get函数获取factory对象;
  • 以当前所要创建对象的类名为索引,在factory的替换列表中查询该类 该对象是否被替换;
  • 如果替换列表中没有相关条目,则调用当前类的new(0函数;如果有相关条目,则调用替换类的new()函数实例化对象。

(3). 根据具体要求向替换表添加替换条目,override;

(4). 在运行仿真时,UVM会根据这两张表自动的实现factory机制;

3.2.2. 使用factory机制需要注意的几点:

  1. 用户需要向注册表注册。
  2. 用户需要向替换表添加项目。
  3. 被替换对象的类型是替换对象类型的基类。

3.3. UVM field automation机制

3.3.1. 什么是field automation机制?

UVM field automation机制是为了方便用户对事务进行打印、复制、打包、解压、比较、记录等一系列功能而建立的一套服务机制。

简单的来说就是可使用UVM内建的函数对事务进行处理。

3.3.2. uvm_field宏注册

几种常用的宏:

`uvm_object_utils_begin (my transaction)      //对于object类型
//`uvm_component_utils begin (my transaction) //对于component类型
    `uvm_field_int (ARG,FLAG)
    `uvm_field_real (ARG,FLAG)
    `uvm_field_enum (T,ARG,FLAG)
    `uvm field_object (ARG,FLAG)
    `uvm_field_string (ARG,FLAG)
    `uvm_field_array_enum (ARG,FLAG)
    `uvm_field_array_int (ARG,FLAG)
    `uvm_field_array_string (ARG,FLAG)
    `uvm_field_queue_int (ARG,FLAG)
    `uvm_field_queue_string (ARG,FLAG)
    `uvm_field_aa_int_string (ARG,FLAG)
    `uvm_field_aa_string_string (ARG,FLAG)
`uvm_object_utils_end
//`uvm_component_utils_end

3.3.3. uvm_field常用函数方法

方法名 功能
clone 深度复制功能,调用该函数则将会把目标对象完全复制一份给自己,如果对目标对象的成员中包含了其他对象,则会调用该子对象的clone方法进行复制。复制的内容仅限于使用了UVM field automation机制的成员
copy 普通的复制功能,如果目标对象中包含了其他对象,则不会再调用该对象的copy方法,仅仅对子对象的句柄进行复制。复制的内容仅限于使用了UVM field automation.机制的成员
print 可按照给定的格式打印出对象的成员,打印的内容仅限于使用了UVM field automation机制的成员
sprint 与print类似,但返回的是一个字符串
compare 执行深度对比功能,对比的内容仅限于使用了JVM field automation机制的成员
pack 将成员按一定格式打包成一个数据流,打包的内容仅限于使用了UVM field automation机制的成员
unpack 按成员的规格对数据流进行分解,参与分解的成员仅限于使用了UVM field automation机制的成员
pack_bytes 将在域中注册的变量和数组等打包成byte流,输出到一个动态数组中
unpack_bytes 传入一个动态数组,将所有内容根据域中注册的顺序,转换成类中的字段
record 对成员做记录,参与记录的成员仅限于使用了UVM field automation机制的成员

3.4. UVM configuration机制

3.4.1. 什么是UVM configuration机制

UVM的configuration机制是一个强大的属性配置工具

  • 传递值
  • 传递对象
  • 传递interface

3.4.2. configuration机制的特点

  • 半个全局变量,避免全局变量带来的风险
  • 高层组件可以通过configuration机制实现在不改变代码的情况下更改它所包含子组件的变量
  • 在各个层次上都可以使用configuration机制
  • 支持通配符和正则表达式对多个变量进行配置
  • 支持用户自定义的数据类型
  • 可以在仿真运行的过程中进行配置

3.4.3. configuration机制的原理

UVM configuration机制实现由两部分组成:

  • 设置配置资源
  • 获取配置资源

3.4.4. 如何使用configuration机制

img

3.5. override机制

  常用的override函数有两个:

set_type_override_by_type()

set_type_override_by_type(original_class_name::get_type(),target_class_name::get_type());

  

  这个函数的作用是将平台中 所有类型 为“original_.class_name”实例化的对象都被替换成类型为“target_class_name”的对象 -- 全部替换

set_inst_override_by_type()

set_inst_override_by_type("original_inst_path", original_class_name::get_type(), target_class_name:get_type());

  

  这个函数的作用是将平台中 指定路径 的类型为“original_class_name”实例化的对象被替换成类型为“target_class_name”的对象 -- 指定替换,路径越具体,替换越明确

  这两个函数存在于component中,并且一般需要在 build_phase() 中调用。

3.6. demo-- 添加平台组件

  • 平台架构调试,可使用: uvm_top.print_topology;

  • Makefile

    #! all comp sim run clean
    .PHONY: all comp sim run clean
    
    TC       ?=my_base_test
    SEED     ?=1234
    TOP      ?=test_top
    FILELIST ?=../scripts/filelist.f
    
    COMP_OPTS += -sverilog +v2k -full64
    COMP_OPTS += -kdb -lca
    COMP_OPTS += +acc +vpi -debug_access+all
    COMP_OPTS += -timescale=1ns/1ps
    COMP_OPTS += -ntb_opts uvm-1.2
    COMP_OPTS += +libext+.v+.sv+.svh+.incl
    COMP_OPTS += +plusarg_save
    COMP_OPTS += -top $(TOP)
    COMP_OPTS += -F $(FILELIST)
    
    SIM_OPTS += +UVM_TESTNAME=$(TC)
    SIM_OPTS += +UVM_VERBOSITY=UVM_DEBUG##UVM_LOW
    SIM_OPTS += +UVM_DUMP_CMDLINE_ARGS
    SIM_OPTS += +UVM_CONFIG_DB_TRACE
    SIM_OPTS += +UVM_PHASE_TRACE
    SIM_OPTS += +UVM_OBJECTION_TRACE
    SIM_OPTS += +ntb_random_seed=$(SEED)
    SIM_OPTS += +notimingcheck
    SIM_OPTS += +nospecify
    SIM_OPTS += +delay_mode_zero
    
    COV_OPTS += -cm cond+line+fsm
    COV_OPTS += -cm_name $(TC) -cm_dir $(TC).vdb
    
    DUMP_OPTS += +fsdb+autoflush+all=on
    DUMP_OPTS += -ucli -i ../scripts/wave.tcl
    DUMP_OPTS += +fsdbfile+./wave/$(TC)_$(SEED).fsdb
    
    all: comp sim
    
    comp:
    	mkdir -p ./wave ./log & \
    	vcs $(COMP_OPTS) \
    	-l ./log/comp_$(TC)_$(SEED).log
    
    sim:
    	./simv $(SIM_OPTS) \
    	$(DUMP_OPTS) \
    	-l ./log/sim_$(TC)_$(SEED).log
    
    rpt_cg:
    	urg -dir *.vdb -report cg_report
    	@echo "coverage report generated in ./cg_report"
    
    verdi_cg:
    	verdi -cov -covdir *.vdb/ &
    
    verdi_db:
    	verdi -dbdir simv.daidir &
    
    verdi_f:
    	verdi -f filelist.f &
    
    verdi_wave:
    	verdi -ssf ./wave/*.fsdb &
    
    run:
    	vcs -R -sverilog $(TC)
    
    clean:
    	rm -rf *.log *.vdb *simv* *.h *.key cg_report csrc vdCovLog
    
    clean_all:
    	rm -rf *.log *.vdb *simv* *.h *.key cg_report csrc vdCovLog novas* ./log/* ./wave/* verdiLog
    
    
    
  • test_top

    //-----------------------------------------------
    //@ test_top
    //@ Version : V0.1
    //@ Wesley 2022.04.10
    //-----------------------------------------------
    
    module test_top;
        import uvm_pkg::*;
        `include "uvm_macros.svh"
    
        import my_test_pkg::*;
    
        logic clk     = 0;
        logic reset_n = 0;
    
        //interface
        my_intf vif();
    
        // DUT - a 16550 UART:
        dut DUT ( );
    
        // clock/reset
        always #5ns clk = ~clk;
    
        initial begin
            clk     = 0;
            reset_n = 0;
            repeat(10) @(posedge clk);
            reset_n = 1;
    	    `uvm_info (" TEST_TOP ", $sformatf("clk = 0x%h , resetn = 0x%h", clk, reset_n), UVM_MEDIUM)
        end
    
        // UVM virtual interface handling and run_test()
        initial begin
            // run
            run_test();
        end
    endmodule: test_top
    
    
  • my_base_test

    //-----------------------------------------------
    //@ my_base_test
    //@ Version : V0.1
    //@ Wesley 2022.04.10
    //-----------------------------------------------
    `ifndef my_base_test__SV
    `define my_base_test__SV
    
    class my_base_test extends uvm_test;
    
        `uvm_component_utils(my_base_test)
        my_env             m_env;
    
        extern function new(string name = "my_base_test", uvm_component parent = null);
        extern function void build_phase(uvm_phase phase);
        extern function void connect_phase(uvm_phase phase);
        extern function void end_of_elaboration_phase(uvm_phase phase);
        extern virtual task  run_phase(uvm_phase phase);
        extern function void report_phase(uvm_phase phase);
        extern function void final_phase(uvm_phase phase);
    endclass: my_base_test
    
    function my_base_test::new(string name = "my_base_test", uvm_component parent = null);
        super.new(name, parent);
        `uvm_info(get_type_name(), "< 000 > : new ", UVM_DEBUG)
    endfunction: new
    
    function void my_base_test::build_phase(uvm_phase phase);
        super.build_phase(phase);
        `uvm_info(get_type_name(), "< 001 > : build_phase ", UVM_DEBUG)
        m_env = my_env::type_id::create("m_env", this);
    endfunction: build_phase
    
    function void my_base_test::connect_phase(uvm_phase phase);
       super.connect_phase(phase);
    endfunction: connect_phase
    
    function void my_base_test::end_of_elaboration_phase(uvm_phase phase);
        uvm_top.print_topology;
        `uvm_info(get_type_name(), "< 003 > : end_of_elaboration_phase ", UVM_DEBUG)
    endfunction: end_of_elaboration_phase
    
    task my_base_test::run_phase(uvm_phase phase);
        super.run_phase(phase);
        phase.raise_objection(this);
        `uvm_info(get_type_name(), "< 005 > : run_phase ", UVM_DEBUG)
    
        #100ns;
        phase.get_objection().set_drain_time(this, 1000);
        phase.drop_objection(this);
    endtask: run_phase
    
    function void my_base_test::report_phase(uvm_phase phase);
        `uvm_info(get_type_name(), "< 008 > : report_phase ", UVM_DEBUG)
        `uvm_info(get_type_name(), "+-----------------------------------------------+", UVM_DEBUG)
        `uvm_info(get_type_name(), "+-           *** UVM TEST PASSED ***           -+", UVM_DEBUG)
        `uvm_info(get_type_name(), "+-----------------------------------------------+", UVM_DEBUG)
    
        `uvm_info(get_type_name(), "+-----------------------------------------------+", UVM_DEBUG)
        `uvm_info(get_type_name(), "+-           *** UVM TEST FAILED ***           -+", UVM_DEBUG)
        `uvm_info(get_type_name(), "+-----------------------------------------------+", UVM_DEBUG)
    
    endfunction: report_phase
    
    function void my_base_test::final_phase(uvm_phase phase);
        `uvm_info(get_type_name(), "< 009 > : final_phase ", UVM_DEBUG)
    endfunction: final_phase
    
    `endif // my_base_test__SV
    
    
  • env

    //-----------------------------------------------
    //@ my_env
    //@ Version : V0.1
    //@ Wesley 2022.04.10
    //-----------------------------------------------
    `ifndef my_env__SV
    `define my_env__SV
    
    class my_env extends uvm_env;
    
        `uvm_component_utils(my_env)
    
        my0_agent          m0_agent;
        my_scoreboard      m_scb;
        my_reference       m_ref;
    
        extern function new(string name = "my_env", uvm_component parent = null);
        extern function void build_phase(uvm_phase phase);
        extern function void connect_phase(uvm_phase phase);
    endclass: my_env
    
    function my_env::new(string name = "my_env", uvm_component parent = null);
        super.new(name, parent);
        `uvm_info(get_type_name(), "< 000 > : new ", UVM_DEBUG)
    endfunction: new
    
    function void my_env::build_phase(uvm_phase phase);
        super.build_phase(phase);
        `uvm_info(get_type_name(), "< 001 > : build_phase ", UVM_DEBUG)
    
        m0_agent = my0_agent::type_id::create("m0_agent", this);
        m_scb    = my_scoreboard::type_id::create("m_scb", this);
        m_ref    = my_reference::type_id::create("m_ref", this);
    
    endfunction: build_phase
    
    function void my_env::connect_phase(uvm_phase phase);
        `uvm_info(get_type_name(), "< 002 > : connect_phase ", UVM_DEBUG)
    endfunction: connect_phase
    
    `endif // my_env__SV
    
    
  • agent

    //-----------------------------------------------
    //@ my0_agent
    //@ Version : V0.1
    //@ Wesley 2022.04.10
    //-----------------------------------------------
    `ifndef my0_agent__SV
    `define my0_agent__SV
    
    class my0_agent extends uvm_agent;
    
        `uvm_component_utils(my0_agent)
    
        my0_driver        m0_drv;
        my0_monitor       m0_mon;
        my0_sequencer     m0_seqr;
    
        extern function new(string name = "my0_agent", uvm_component parent = null);
        extern function void build_phase(uvm_phase phase);
        extern function void connect_phase(uvm_phase phase);
    endclass: my0_agent
    
    function my0_agent::new(string name = "my0_agent", uvm_component parent = null);
        super.new(name, parent);
        `uvm_info(get_type_name(), "< 000 > : new ", UVM_DEBUG)
    endfunction: new
    
    function void my0_agent::build_phase(uvm_phase phase);
        super.build_phase(phase);
        `uvm_info(get_type_name(), "< 001 > : build_phase ", UVM_DEBUG)
    
        m0_drv  = my0_driver::type_id::create("m0_drv", this);
        m0_seqr = my0_sequencer::type_id::create("m0_seqr", this);
        m0_mon  = my0_monitor::type_id::create("m0_mon", this);
    endfunction: build_phase
    
    function void my0_agent::connect_phase(uvm_phase phase);
        `uvm_info(get_type_name(), "< 002 > : connect_phase ", UVM_DEBUG)
    endfunction: connect_phase
    
    `endif // my0_agent__SV
    
    
  • driver

    //-----------------------------------------------
    //@ my0_driver
    //@ Version : V0.1
    //@ Wesley 2022.04.10
    //-----------------------------------------------
    `ifndef my0_driver__SV
    `define my0_driver__SV
    
    class my0_driver extends uvm_driver#(my0_seq_item);
        `uvm_component_utils(my0_driver)
    
        extern function new(string name = "my0_driver", uvm_component parent = null);
        extern function void build_phase(uvm_phase phase);
        extern function void connect_phase(uvm_phase phase);
        extern task          run_phase(uvm_phase phase);
    
    endclass: my0_driver
    
    function my0_driver::new(string name = "my0_driver", uvm_component parent = null);
        super.new(name, parent);
        `uvm_info(get_type_name(), "< 000 > : new ", UVM_DEBUG)
    endfunction: new
    
    function void my0_driver::build_phase(uvm_phase phase);
        `uvm_info(get_type_name(), "< 001 > : build_phase ", UVM_DEBUG)
    endfunction: build_phase
    
    function void my0_driver::connect_phase(uvm_phase phase);
        `uvm_info(get_type_name(), "< 002 > : connect_phase ", UVM_DEBUG)
    endfunction: connect_phase
    
    task my0_driver::run_phase(uvm_phase phase);
        `uvm_info(get_type_name(), "< 005 > : run_phase ", UVM_DEBUG)
        super.run_phase(phase);
    endtask: run_phase
    
    `endif // my0_driver__SV
    
    
  • monitor

    //-----------------------------------------------
    //@ my0_monitor
    //@ Version : V0.1
    //@ Wesley 2022.04.10
    //-----------------------------------------------
    `ifndef my0_monitor__SV
    `define my0_monitor__SV
    
    class my0_monitor extends uvm_monitor;
    
        `uvm_component_utils(my0_monitor)
    
        extern function new(string name = "my0_monitor", uvm_component parent = null);
        extern function void build_phase(uvm_phase phase);
        extern function void connect_phase(uvm_phase phase);
        extern task          run_phase(uvm_phase phase);
    endclass: my0_monitor
    
    function my0_monitor::new(string name = "my0_monitor", uvm_component parent = null);
        super.new(name, parent);
        `uvm_info(get_type_name(), "< 000 > : new ", UVM_DEBUG)
    endfunction: new
    
    function void my0_monitor::build_phase(uvm_phase phase);
        `uvm_info(get_type_name(), "< 001 > : build_phase ", UVM_DEBUG)
    endfunction: build_phase
    
    function void my0_monitor::connect_phase(uvm_phase phase);
        `uvm_info(get_type_name(), "< 002 > : connect_phase ", UVM_DEBUG)
    endfunction: connect_phase
    
    task my0_monitor::run_phase(uvm_phase phase);
        `uvm_info(get_type_name(), "< 005 > : run_phase ", UVM_DEBUG)
    endtask: run_phase
    
    `endif // my0_monitor__SV
    
    
  • sequencer

    //-----------------------------------------------
    //@ my0_sequencer
    //@ Version : V0.1
    //@ Wesley 2022.04.10
    //-----------------------------------------------
    `ifndef my0_sequencer__SV
    `define my0_sequencer__SV
    
    class my0_sequencer extends uvm_sequencer #(my0_seq_item);
    
        `uvm_component_utils(my0_sequencer)
    
        function new(string name = "my0_sequencer", uvm_component parent = null);
            super.new(name, parent);
            `uvm_info(get_type_name(), "< 000 > : new ", UVM_DEBUG)
        endfunction: new
    
    endclass: my0_sequencer
    
    `endif // my0_sequencer__SV
    
    
    
  • reference

    //-----------------------------------------------
    //@ my_reference
    //@ Version : V0.1
    //@ Wesley 2022.04.10
    //-----------------------------------------------
    `ifndef my_reference__SV
    `define my_reference__SV
    
    // Step1 : Create a new class that extends from uvm_scoreboard
    class my_reference extends uvm_component;
        `uvm_component_utils (my_reference)
    
        // Step2a: Declare and create a TLM Analysis Port to receive data objects from other TB components
        uvm_blocking_get_port #(my0_seq_item) get_port;//exp_port;
        uvm_analysis_port #(my0_seq_item) ap;
        //uvm_analysis_export #(my0_seq_item) analysis_export;
    
    	  function new (string name = "my_reference", uvm_component parent);
    	  	super.new (name, parent);
    	  endfunction
    
    	  // Step2b: Instantiate the analysis port, because afterall, its a class object
    	  function void build_phase (uvm_phase phase);
    		//ap = new ("ap", this);
    		//get_port = new ("get_port", this);
    		//analysis_export = new ("analysis_export", this);
    	  endfunction
    
    	  // Step3: Define other functions and tasks that operate on the data and call them
    	  // Remember, this is the main task that consumes simulation time in UVM
    	  virtual task run_phase (uvm_phase phase);
          my0_seq_item tr;
    	  endtask
    
    	  // Step4: [Optional] Perform any remaining comparisons or checks before end of simulation
    	  virtual function void check_phase (uvm_phase phase);
    	  	//...
    	  endfunction
    endclass
    
    `endif // my_reference__SV
    
    
  • scoreboard

    //-----------------------------------------------
    //@ my_scoreboard
    //@ Version : V0.1
    //@ Wesley 2022.04.10
    //-----------------------------------------------
    `ifndef my_scoreboard__SV
    `define my_scoreboard__SV
    
    class my_scoreboard extends uvm_scoreboard;
    	`uvm_component_utils (my_scoreboard)
    
    	// Step2a: Declare and create a TLM Analysis Port to receive data objects from other TB components
      uvm_blocking_get_port #(my0_seq_item) get_port;
      //uvm_analysis_imp_monitor #(my0_seq_item, my_scoreboard) analysis_imp;
    
    	function new (string name = "my_scoreboard", uvm_component parent);
    		super.new (name, parent);
    	endfunction
    
    	// Step2b: Instantiate the analysis port, because afterall, its a class object
    	function void build_phase (uvm_phase phase);
    		//get_port = new ("get_port", this);
    		//analysis_imp = new ("analysis_imp", this);
    	endfunction
    
    	// Step3: Define other functions and tasks that operate on the data and call them
    	// Remember, this is the main task that consumes simulation time in UVM
    	virtual task run_phase (uvm_phase phase);
            my0_seq_item tr;
    	endtask
    
    	// Step4: [Optional] Perform any remaining comparisons or checks before end of simulation
    	virtual function void check_phase (uvm_phase phase);
    		//...
    	endfunction
    endclass
    
    `endif // my_scoreboard__SV
    
    
posted @ 2022-07-17 17:17  Thisway2014  阅读(1565)  评论(0编辑  收藏  举报