3. UVM -- factory机制与平台组件构建
3. UVM -- factory机制与平台组件构建
3.1. 什么是factory机制
- UVM工厂机制可以使用户在不更改代码的情况下实现不同对象的替换;
- 工厂是UVM的一种数据结构。它的作用范围是整个平台空间,它有且仅有一个实例化对象 (即单实例类)。它是一个 多态构造器,可仅仅使用一个函数让用户实例化很多不同类型的对象。
- 为了使用一个函数而可以返回多种对象,这些对象必须从一个基类扩展而来。
3.2. uvm factory机制的原理及使用
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机制需要注意的几点:
- 用户需要向注册表注册。
- 用户需要向替换表添加项目。
- 被替换对象的类型是替换对象类型的基类。
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.机制的成员 |
可按照给定的格式打印出对象的成员,打印的内容仅限于使用了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机制
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
本文来自博客园,作者:Thisway2014,转载请注明原文链接:https://www.cnblogs.com/thisway2014/p/16487814.html