UVM Component

2023-11-06
UVM

所有主要的testbench component,如driver/monitor/scoreboard都從uvm_component class衍生出來,並繼承了UVM framework的phasing和reporting機制。

UVM components使用phasing機制以特定的順序執行初始化(initialization)和配置(configuration)。Phase可以讓component建構自己內部的hierarchy、與其他component連結,並且在實際測試前完成其配置(configuration),確保完好的設定和配置。

Alt text

uvm_component定義提供了許多函數和任務,用於尋找、建置、連接和配置子元件。 大致分類為:
Hierarchy: 支援導航組件層次結構(navigating the component hierarchy)
Phase: 控制testbench如何build與run(controlling the phases that govern how a testbench should be built and run)
Factory: 允許testbench的可重用性(allowing reusability of testbench using a factory)

Hierarchy Methods

這邊的範例是先用UVM建構出以下圖案的hierarchy並且在end_of_elaboration_phase階段使用uvm_component的function找到他的所有children。
另外還有用get_parent得到當前component的parent component,用get_num_children得到children數量等等。

Alt text

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import uvm_pkg::*;
`include "uvm_macros.svh"

class apb_monitor extends uvm_component;
`uvm_component_utils(apb_monitor)
string name = "apb_monitor";

function new(string name = "apb_monitor", uvm_component parent);
super.new(name, parent);
endfunction

virtual function void end_of_elaboration_phase(uvm_phase phase);
`uvm_info (name, $sformatf("get_depth = %0d", get_depth()), UVM_LOW)
endfunction
endclass

class apb_agent extends uvm_component;
`uvm_component_utils(apb_agent)

string name = "apb_agent";
apb_monitor apb_monitor_obj;

function new(string name = "apb_agent", uvm_component parent);
super.new(name, parent);
endfunction

function void build_phase(uvm_phase phase);
apb_monitor_obj = apb_monitor::type_id::create("apb_monitor_obj", this);
endfunction

virtual function void end_of_elaboration_phase(uvm_phase phase);
`uvm_info (name, $sformatf("get_depth = %0d", get_depth()), UVM_LOW)
endfunction
endclass

class child_comp extends uvm_component;
`uvm_component_utils(child_comp)

function new(string name = "child_comp", uvm_component parent);
super.new(name, parent);
endfunction
endclass

class top_comp extends uvm_component;
`uvm_component_utils(top_comp)

child_comp child_comp_obj[3];
apb_agent apb_agent_obj;
string name = "top_comp";

function new(string name = "top_comp", uvm_component parent);
super.new(name, parent);
endfunction

function void build_phase(uvm_phase phase);
foreach(child_comp_obj[i])
child_comp_obj[i] = child_comp::type_id::create($sformatf("child_comp_obj_%0d", i), this);

apb_agent_obj = apb_agent::type_id::create("apb_agent_obj", this);
endfunction

virtual function void end_of_elaboration_phase(uvm_phase phase);
//super.end_of_elaboration_phase(phase);
uvm_component temp_comp;
uvm_component temp_comp_queue[$];

temp_comp = get_parent();
`uvm_info(name, $sformatf("get_parent=%s", temp_comp.get_name()), UVM_LOW)

get_children(temp_comp_queue);
foreach (temp_comp_queue[i])
`uvm_info(name, $sformatf("child[%0d] = %s", i, temp_comp_queue[i].get_name()), UVM_LOW)

`uvm_info (name, $sformatf("number of children = %0d", get_num_children()), UVM_LOW)
`uvm_info (name, $sformatf("has_child('123') = %0d", has_child("123")), UVM_LOW)
`uvm_info (name, $sformatf("has_child('apb_agent') = %0d", has_child("apb_agent_obj")), UVM_LOW)
`uvm_info (name, $sformatf("get_depth = %0d", get_depth()), UVM_LOW)

temp_comp = lookup("apb_monitor_obj");
if (temp_comp) // Cannot find child apb_monitor_obj
`uvm_info (name, $sformatf("1Found %s", temp_comp.get_full_name()), UVM_LOW)

temp_comp = lookup("apb_agent_obj.apb_monitor_obj");
if (temp_comp) // Found uvm_test_top.top_comp_obj.apb_agent_obj.apb_monitor_obj
`uvm_info (name, $sformatf("2Found %s", temp_comp.get_full_name()), UVM_LOW)
endfunction
endclass

class base_test extends uvm_test;
`uvm_component_utils(base_test)

top_comp top_comp_obj;
string name = "base_test";

function new(string name = "base_test", uvm_component parent);
super.new(name, parent);
endfunction

function void build_phase(uvm_phase phase);
top_comp_obj = top_comp::type_id::create("top_comp_obj", this);
endfunction

virtual function void end_of_elaboration_phase(uvm_phase phase);
`uvm_info (name, $sformatf("get_depth = %0d", get_depth()), UVM_LOW)
endfunction
endclass

module tb;
initial begin
$display("start");
run_test("base_test");
end
endmodule

Output

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# start
# UVM_INFO @ 0: reporter [RNTST] Running test base_test...
# UVM_INFO .\uvm_component.sv(13) @ 0: uvm_test_top.top_comp_obj.apb_agent_obj.apb_monitor_obj [apb_monitor] get_depth = 4
# UVM_INFO .\uvm_component.sv(32) @ 0: uvm_test_top.top_comp_obj.apb_agent_obj [apb_agent] get_depth = 3
# UVM_INFO .\uvm_component.sv(68) @ 0: uvm_test_top.top_comp_obj [top_comp] get_parent=uvm_test_top
# UVM_INFO .\uvm_component.sv(72) @ 0: uvm_test_top.top_comp_obj [top_comp] child[0] = apb_agent_obj
# UVM_INFO .\uvm_component.sv(72) @ 0: uvm_test_top.top_comp_obj [top_comp] child[1] = child_comp_obj_0
# UVM_INFO .\uvm_component.sv(72) @ 0: uvm_test_top.top_comp_obj [top_comp] child[2] = child_comp_obj_1
# UVM_INFO .\uvm_component.sv(72) @ 0: uvm_test_top.top_comp_obj [top_comp] child[3] = child_comp_obj_2
# UVM_INFO .\uvm_component.sv(74) @ 0: uvm_test_top.top_comp_obj [top_comp] number of children = 4
# UVM_INFO .\uvm_component.sv(75) @ 0: uvm_test_top.top_comp_obj [top_comp] has_child('123') = 0
# UVM_INFO .\uvm_component.sv(76) @ 0: uvm_test_top.top_comp_obj [top_comp] has_child('apb_agent') = 1
# UVM_INFO .\uvm_component.sv(77) @ 0: uvm_test_top.top_comp_obj [top_comp] get_depth = 2
# UVM_WARNING verilog_src/uvm-1.2/src/base/uvm_component.svh(1985) @ 0: uvm_test_top.top_comp_obj [Lookup Error] Cannot find child apb_monitor_obj
# UVM_INFO .\uvm_component.sv(85) @ 0: uvm_test_top.top_comp_obj [top_comp] 2Found uvm_test_top.top_comp_obj.apb_agent_obj.apb_monitor_obj
# UVM_WARNING verilog_src/uvm-1.2/src/base/uvm_component.svh(1985) @ 0: uvm_test_top.top_comp_obj [Lookup Error] Cannot find child top_comp_obj
# UVM_WARNING verilog_src/uvm-1.2/src/base/uvm_component.svh(1985) @ 0: uvm_test_top.top_comp_obj [Lookup Error] Cannot find child uvm_test_top
# UVM_INFO .\uvm_component.sv(114) @ 0: uvm_test_top [base_test] get_depth = 1
# UVM_INFO verilog_src/uvm-1.2/src/base/uvm_report_server.svh(847) @ 0: reporter [UVM/REPORT/SERVER]
# --- UVM Report Summary ---

Phasing Methods

UVM Component提供了virtual method讓child class可以override掉這些virtual function實作自己在該phase要做的邏輯,在build_phase將所有component實例化(instantiate),在connect_phase把不同的component串起來,還有很多不同的phase讓使用者在合適的phase做該做的事情。

Factory Methods

在class要繼承uvm_object的時候,需要用uvm_object_utils相關的macro在factory中註冊,同樣的uvm_component也有uvm_component_utils 可以將component註冊(register)。

1
2
3
4
5
6
7
8
9
10
class comp extends uvm_component;

`uvm_component_utils (comp)

function new(string name = "comp", uvm_component parent = null);
super.new(name, parent);
endfunction

...
endclass