run_test() 验证平台的入口
Run,just run! ——阿甘正传
一个简单的例子:
1 module tb_top; 2 dut u_dut (); 3 4 initial begin 5 run_test(); 6 end 7 8 config_db #()::set(); 9 10 endmoudle
UVM验证平台从仿真器执行时,开始执行initial中的run_test(); 这时首先去uvm_global.svh中查找run_test();
// Title: Globals //------------------------------------------------------------------------------ // // Group: Simulation Control // //------------------------------------------------------------------------------ // Task: run_test // // Convenience function for uvm_top.run_test(). See <uvm_root> for more // information. task run_test (string test_name=""); uvm_root top; uvm_coreservice_t cs; cs = uvm_coreservice_t::get(); top = cs.get_root(); top.run_test(test_name); endtask
全局的run_test() 又调用uvm_root.svh的run_test()
1 //---------------------------------------------------------------------------- 2 // Group: Simulation Control 3 //---------------------------------------------------------------------------- 4 5 6 // Task: run_test 7 // 8 // Phases all components through all registered phases. If the optional 9 // test_name argument is provided, or if a command-line plusarg, 10 // +UVM_TESTNAME=TEST_NAME, is found, then the specified component is created 11 // just prior to phasing. The test may contain new verification components or 12 // the entire testbench, in which case the test and testbench can be chosen from 13 // the command line without forcing recompilation. If the global (package) 14 // variable, finish_on_completion, is set, then $finish is called after 15 // phasing completes. 16 17 extern virtual task run_test (string test_name=""); 18 19 20 // run_test 21 // -------- 22 23 task uvm_root::run_test(string test_name=""); 24 25 uvm_report_server l_rs; 26 uvm_coreservice_t cs = uvm_coreservice_t::get(); 27 uvm_factory factory=cs.get_factory(); 28 bit testname_plusarg; 29 int test_name_count; 30 string test_names[$]; 31 string msg; 32 uvm_component uvm_test_top; 33 34 process phase_runner_proc; // store thread forked below for final cleanup 35 36 testname_plusarg = 0; 37 38 // Set up the process that decouples the thread that drops objections from 39 // the process that processes drop/all_dropped objections. Thus, if the 40 // original calling thread (the "dropper") gets killed, it does not affect 41 // drain-time and propagation of the drop up the hierarchy. 42 // Needs to be done in run_test since it needs to be in an 43 // initial block to fork a process. 44 uvm_objection::m_init_objections(); 45 46 `ifndef UVM_NO_DPI 47 48 // Retrieve the test names provided on the command line. Command line 49 // overrides the argument. 50 test_name_count = clp.get_arg_values("+UVM_TESTNAME=", test_names); 51 52 // If at least one, use first in queue. 53 if (test_name_count > 0) begin 54 test_name = test_names[0]; 55 testname_plusarg = 1; 56 end 57 58 // If multiple, provided the warning giving the number, which one will be 59 // used and the complete list. 60 if (test_name_count > 1) begin 61 string test_list; 62 string sep; 63 for (int i = 0; i < test_names.size(); i++) begin 64 if (i != 0) 65 sep = ", "; 66 test_list = {test_list, sep, test_names[i]}; 67 end 68 uvm_report_warning("MULTTST", 69 $sformatf("Multiple (%0d) +UVM_TESTNAME arguments provided on the command line. '%s' will be used. Provided list: %s.", test_name_count, test_name, test_list), UVM_NONE); 70 end 71 72 `else 73 74 // plusarg overrides argument 75 if ($value$plusargs("UVM_TESTNAME=%s", test_name)) begin 76 `uvm_info("NO_DPI_TSTNAME", "UVM_NO_DPI defined--getting UVM_TESTNAME directly, without DPI", UVM_NONE) 77 testname_plusarg = 1; 78 end 79 80 `endif 81 82 // if test now defined, create it using common factory 83 if (test_name != "") begin 84 uvm_coreservice_t cs = uvm_coreservice_t::get(); 85 uvm_factory factory=cs.get_factory(); 86 87 if(m_children.exists("uvm_test_top")) begin 88 uvm_report_fatal("TTINST", 89 "An uvm_test_top already exists via a previous call to run_test", UVM_NONE); 90 #0; // forces shutdown because $finish is forked 91 end 92 $cast(uvm_test_top, factory.create_component_by_name(test_name, 93 "", "uvm_test_top", null)); 94 95 if (uvm_test_top == null) begin 96 msg = testname_plusarg ? {"command line +UVM_TESTNAME=",test_name} : 97 {"call to run_test(",test_name,")"}; 98 uvm_report_fatal("INVTST", 99 {"Requested test from ",msg, " not found." }, UVM_NONE); 100 end 101 end 102 103 if (m_children.num() == 0) begin 104 uvm_report_fatal("NOCOMP", 105 {"No components instantiated. You must either instantiate", 106 " at least one component before calling run_test or use", 107 " run_test to do so. To run a test using run_test,", 108 " use +UVM_TESTNAME or supply the test name in", 109 " the argument to run_test(). Exiting simulation."}, UVM_NONE); 110 return; 111 end 112 113 begin 114 if(test_name=="") 115 uvm_report_info("RNTST", "Running test ...", UVM_LOW); 116 else if (test_name == uvm_test_top.get_type_name()) 117 uvm_report_info("RNTST", {"Running test ",test_name,"..."}, UVM_LOW); 118 else 119 uvm_report_info("RNTST", {"Running test ",uvm_test_top.get_type_name()," (via factory override for test \"",test_name,"\")..."}, UVM_LOW); 120 end 121 122 // phase runner, isolated from calling process 123 fork begin 124 // spawn the phase runner task 125 phase_runner_proc = process::self(); 126 uvm_phase::m_run_phases(); 127 end 128 join_none 129 #0; // let the phase runner start 130 131 wait (m_phase_all_done == 1); 132 133 // clean up after ourselves 134 phase_runner_proc.kill(); 135 136 l_rs = uvm_report_server::get_server(); 137 l_rs.report_summarize(); 138 139 if (finish_on_completion) 140 $finish; 141 142 endtask
在该run_test 实现中根据有没有DPI调用phase.这样在运行仿真命令时通过simcmd +UVM_TESTNAME=my_case 来执行该case,这样整个系统就被调用了起来。这样做有什么好处?它根据传入的字符串或者从运行参数+UVM_TESTNAME="test_name"读取字符串来生成uvm_test对象, 并运行这个对象的全部phase函数来执行一次测试用例的运行,很方便实现regression。
参考文献:
1 Just Run.https://movie.douban.com/review/5526733/