2.11 phase - basic
前言
本文以uvm-1.2/examples/simple//phases/basic为例,通过代码了解UVM中机制phases的分类和用法。通过这个例子可以基本了解以下知识点:
- phase的类型和分类
- phase的运行机制
一、基本介绍
UVM中全部的phase如下图所示,按照图中的顺序自上而下自动执行,通过phase来控制仿真的执行顺序。黄色部分是function_phase,这类phase不消耗仿真时间;绿色部分是task_phase,这类phase消耗仿真时间。添加这么多的phase,是为了对仿真更精细化的控制,而且也让环境更加灵活。
build_phase的执行顺序是自上而下,即先执行UVM树状结构根节点的build_phase,再一层一层的往叶子端去执行build_phase。这是因为,在build_phase中主要执行的是实例化工作。例如:driver和monitor都是agent的成员,在agent的build_phase中实例化driver和monitor,但是如果在执行agent的build_phase之前去执行driver的build_phase,就会报错,因为此时driver都还没例化。
除了build_phase之外的其他不消耗仿真时间的function_phase,执行顺序都是自下而上。例如:先执行driver和monitor的connect_phase,再执行agent的connect_phase。
二、代码分析
这个测试用例比较简单,只有一个test.sv文件,创建的UVM树形结构如下所示。
// top
// __________________|_______________
// | |
// a1(AA) a2(AA)
// | | | |
// u1(A) u2(A) u1(A) u2(A)
// | | | | | | | |
// b1(B) d1(D) b1(B) d1(D) b1(B) d1(D) b1(B) d1(D)
2.1 test.sv
module top;
import uvm_pkg::*;
//No run phase
class D extends uvm_component;
function new (string name, uvm_component parent);
super.new(name,parent);
endfunction
function void build_phase(uvm_phase phase);
$display("%0t: %0s: build", $time, get_full_name());
endfunction
function void end_of_elaboration_phase(uvm_phase phase);
$display("%0t: %0s: end_of_elaboration", $time, get_full_name());
endfunction
function void start_of_simulation_phase(uvm_phase phase);
$display("%0t: %0s: start_of_simulation", $time, get_full_name());
endfunction
function void extract_phase(uvm_phase phase);
$display("%0t: %0s: extract", $time, get_full_name());
endfunction
function void check_phase(uvm_phase phase);
$display("%0t: %0s: check", $time, get_full_name());
endfunction
function void report_phase(uvm_phase phase);
$display("%0t: %0s: report", $time, get_full_name());
endfunction
endclass
//Has run phase
class B extends uvm_component;
rand logic [7:0] delay;
function new (string name, uvm_component parent);
super.new(name,parent);
endfunction
function void build_phase(uvm_phase phase);
$display("%0t: %0s: build", $time, get_full_name());
endfunction
function void end_of_elaboration_phase(uvm_phase phase);
$display("%0t: %0s: end_of_elaboration", $time, get_full_name());
endfunction
function void start_of_simulation_phase(uvm_phase phase);
$display("%0t: %0s: start_of_simulation", $time, get_full_name());
endfunction
function void extract_phase(uvm_phase phase);
$display("%0t: %0s: extract", $time, get_full_name());
endfunction
function void check_phase(uvm_phase phase);
$display("%0t: %0s: check", $time, get_full_name());
endfunction
function void report_phase(uvm_phase phase);
$display("%0t: %0s: report", $time, get_full_name());
endfunction
task run_phase(uvm_phase phase);
$display("%0t: %0s: start run phase", $time, get_full_name());
#delay;
$display("%0t: %0s: end run phase", $time, get_full_name());
endtask
endclass
//Has run phase and contains subcomponents
class A extends uvm_component;
rand B b1;
rand D d1;
rand logic [7:0] delay;
function new (string name, uvm_component parent);
super.new(name,parent);
b1 = new("b1", this);
d1 = new("d1", this);
endfunction
function void build_phase(uvm_phase phase);
$display("%0t: %0s: build", $time, get_full_name());
endfunction
function void end_of_elaboration_phase(uvm_phase phase);
$display("%0t: %0s: end_of_elaboration", $time, get_full_name());
endfunction
function void start_of_simulation_phase(uvm_phase phase);
$display("%0t: %0s: start_of_simulation", $time, get_full_name());
endfunction
function void extract_phase(uvm_phase phase);
$display("%0t: %0s: extract", $time, get_full_name());
endfunction
function void check_phase(uvm_phase phase);
$display("%0t: %0s: check", $time, get_full_name());
endfunction
function void report_phase(uvm_phase phase);
$display("%0t: %0s: report", $time, get_full_name());
endfunction
task run_phase(uvm_phase phase);
$display("%0t: %0s: start run phase", $time, get_full_name());
#delay;
$display("%0t: %0s: end run phase", $time, get_full_name());
endtask
endclass
class AA extends uvm_component;
rand A a;
function new (string name, uvm_component parent);
super.new(name,parent);
a = new("a", this);
endfunction
endclass
//Top level contains two A components
class top extends uvm_env;
rand AA a1;
rand AA a2;
function new (string name, uvm_component parent);
super.new(name,parent);
a1 = new("a1", this);
a2 = new("a2", this);
endfunction
function void build_phase(uvm_phase phase);
$display("%0t: %0s: build", $time, get_full_name());
endfunction
function void end_of_elaboration_phase(uvm_phase phase);
$display("%0t: %0s: end_of_elaboration", $time, get_full_name());
endfunction
function void start_of_simulation_phase(uvm_phase phase);
$display("%0t: %0s: start_of_simulation", $time, get_full_name());
endfunction
function void extract_phase(uvm_phase phase);
$display("%0t: %0s: extract", $time, get_full_name());
endfunction
function void check_phase(uvm_phase phase);
$display("%0t: %0s: check", $time, get_full_name());
endfunction
function void report_phase(uvm_phase phase);
$display("%0t: %0s: report", $time, get_full_name());
endfunction
task run_phase(uvm_phase phase);
phase.raise_objection(this);
$display("%0t: %0s: start run phase", $time, get_full_name());
#500;
$display("%0t: %0s: end run phase", $time, get_full_name());
phase.drop_objection(this);
endtask
endclass
top t = new("top", null);
initial begin
//Randomize all of the delays
void'(t.randomize());
run_test();
end
endmodule
2.2 仿真结果
UVM_INFO @ 0: reporter [RNTST] Running test ...
0: top: build
0: top.a1.a: build
0: top.a1.a.b1: build
0: top.a1.a.d1: build
0: top.a2.a: build
0: top.a2.a.b1: build
0: top.a2.a.d1: build
0: top.a1.a.b1: end_of_elaboration
0: top.a1.a.d1: end_of_elaboration
0: top.a1.a: end_of_elaboration
0: top.a2.a.b1: end_of_elaboration
0: top.a2.a.d1: end_of_elaboration
0: top.a2.a: end_of_elaboration
0: top: end_of_elaboration
0: top.a1.a.b1: start_of_simulation
0: top.a1.a.d1: start_of_simulation
0: top.a1.a: start_of_simulation
0: top.a2.a.b1: start_of_simulation
0: top.a2.a.d1: start_of_simulation
0: top.a2.a: start_of_simulation
0: top: start_of_simulation
0: top.a1.a.b1: start run phase
0: top.a1.a: start run phase
0: top.a2.a.b1: start run phase
0: top.a2.a: start run phase
0: top: start run phase
83: top.a2.a: end run phase
124: top.a2.a.b1: end run phase
155: top.a1.a: end run phase
242: top.a1.a.b1: end run phase
500: top: end run phase
UVM_INFO ../../../../src/base/uvm_objection.svh(1270) @ 500: reporter [TEST_DONE] 'run' phase is ready to proceed to the 'extract' phase
500: top.a1.a.b1: extract
500: top.a1.a.d1: extract
500: top.a1.a: extract
500: top.a2.a.b1: extract
500: top.a2.a.d1: extract
500: top.a2.a: extract
500: top: extract
500: top.a1.a.b1: check
500: top.a1.a.d1: check
500: top.a1.a: check
500: top.a2.a.b1: check
500: top.a2.a.d1: check
500: top.a2.a: check
500: top: check
500: top.a1.a.b1: report
500: top.a1.a.d1: report
500: top.a1.a: report
500: top.a2.a.b1: report
500: top.a2.a.d1: report
500: top.a2.a: report
500: top: report
UVM_INFO ../../../../src/base/uvm_report_server.svh(847) @ 500: reporter [UVM/REPORT/SERVER]
--- UVM Report Summary ---
** Report counts by severity
UVM_INFO : 3
UVM_WARNING : 0
UVM_ERROR : 0
UVM_FATAL : 0
** Report counts by id
[RNTST] 1
[TEST_DONE] 1
[UVM/RELNOTES] 1
$finish called from file "../../../../src/base/uvm_root.svh", line 517.
$finish at simulation time 500
V C S S i m u l a t i o n R e p o r t
Time: 500 ns
CPU Time: 2.880 seconds; Data structure size: 0.3Mb
通过仿真结果可以看到:
首先,打印了top的build_phase,build_phase的执行顺序是自顶向下,当所有的build_phase执行完了,才进入下一个phase。
其次,除开build_phase之外,其他的phase的执行顺序都是自底向上,最后打印top的phase。
最后,可以发现,除去run_phase消耗了时间外,其他的phase都不消耗仿真执行的时间。
总结
总的来说,这个例子比较简单,但是通过这个例子,可以比较直观的看到UVM中,phase的类型和执行顺序。