1 |
4 |
vladimirar |
//----------------------------------------------------------------------
|
2 |
|
|
// Copyright 2014-2015 SyoSil ApS
|
3 |
|
|
// All Rights Reserved Worldwide
|
4 |
|
|
//
|
5 |
|
|
// Licensed under the Apache License, Version 2.0 (the
|
6 |
|
|
// "License"); you may not use this file except in
|
7 |
|
|
// compliance with the License. You may obtain a copy of
|
8 |
|
|
// the License at
|
9 |
|
|
//
|
10 |
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
11 |
|
|
//
|
12 |
|
|
// Unless required by applicable law or agreed to in
|
13 |
|
|
// writing, software distributed under the License is
|
14 |
|
|
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
15 |
|
|
// CONDITIONS OF ANY KIND, either express or implied. See
|
16 |
|
|
// the License for the specific language governing
|
17 |
|
|
// permissions and limitations under the License.
|
18 |
|
|
//----------------------------------------------------------------------
|
19 |
|
|
/// Top level class implementing the root of the SyoSil UVM scoreboard
|
20 |
|
|
class cl_syoscb extends uvm_scoreboard;
|
21 |
|
|
//-------------------------------------
|
22 |
|
|
// Non randomizable variables
|
23 |
|
|
//-------------------------------------
|
24 |
|
|
/// Handle to the global UVM scoreboard configuration
|
25 |
|
|
local cl_syoscb_cfg cfg;
|
26 |
|
|
|
27 |
|
|
/// Array holding handles to all queues
|
28 |
|
|
local cl_syoscb_queue queues[];
|
29 |
|
|
|
30 |
|
|
// Handle to the compare strategy
|
31 |
|
|
local cl_syoscb_compare compare_strategy;
|
32 |
|
|
|
33 |
|
|
// Assoc array holding each uvm_subscriber
|
34 |
|
|
local cl_syoscb_subscriber subscribers[string];
|
35 |
|
|
|
36 |
|
|
//-------------------------------------
|
37 |
|
|
// UVM Macros
|
38 |
|
|
//-------------------------------------
|
39 |
|
|
`uvm_component_utils_begin(cl_syoscb)
|
40 |
|
|
`uvm_field_object(cfg, UVM_DEFAULT)
|
41 |
|
|
`uvm_field_array_object(queues, UVM_DEFAULT)
|
42 |
|
|
`uvm_field_object(compare_strategy, UVM_DEFAULT)
|
43 |
|
|
`uvm_field_aa_object_string(subscribers, UVM_DEFAULT)
|
44 |
|
|
`uvm_component_utils_end
|
45 |
|
|
|
46 |
|
|
//-------------------------------------
|
47 |
|
|
// Constructor
|
48 |
|
|
//-------------------------------------
|
49 |
|
|
extern function new(string name = "cl_syoscb", uvm_component parent = null);
|
50 |
|
|
|
51 |
|
|
//-------------------------------------
|
52 |
|
|
// UVM Phase methods
|
53 |
|
|
//-------------------------------------
|
54 |
|
|
extern function void build_phase(uvm_phase phase);
|
55 |
|
|
|
56 |
|
|
//-------------------------------------
|
57 |
|
|
// Function based API
|
58 |
|
|
//-------------------------------------
|
59 |
|
|
extern function void add_item(string queue_name, string producer, uvm_sequence_item item);
|
60 |
|
|
extern function void compare();
|
61 |
|
|
|
62 |
|
|
//-------------------------------------
|
63 |
|
|
// Transaction based API
|
64 |
|
|
//-------------------------------------
|
65 |
|
|
extern function cl_syoscb_subscriber get_subscriber(string queue_name, string producer);
|
66 |
|
|
endclass: cl_syoscb
|
67 |
|
|
|
68 |
|
|
function cl_syoscb::new(string name = "cl_syoscb", uvm_component parent = null);
|
69 |
|
|
super.new(name, parent);
|
70 |
|
|
endfunction : new
|
71 |
|
|
|
72 |
|
|
/// The build_phase gets the scoreboard configuration and forwards it to the child components (cl_syoscb_queue
|
73 |
|
|
/// and cl_syoscb_compare). Additionally, it creates all of the queues defined in the configuration object. Finally,
|
74 |
|
|
/// it also creates the compare strategy via a factory create call.
|
75 |
|
|
function void cl_syoscb::build_phase(uvm_phase phase);
|
76 |
|
|
if (!uvm_config_db #(cl_syoscb_cfg)::get(this, "", "cfg", this.cfg)) begin
|
77 |
|
|
// *NOTE*: If no cfg object is given then no scb name is available
|
78 |
|
|
// Thus, no scb name is printed here
|
79 |
|
|
`uvm_fatal("CFG_ERROR", "Configuration object not passed.")
|
80 |
|
|
end
|
81 |
|
|
|
82 |
|
|
// Set the default SCB name if not specified explicitly
|
83 |
|
|
if(this.cfg.get_scb_name() == "") begin
|
84 |
|
|
this.cfg.set_scb_name(this.get_name());
|
85 |
|
|
end
|
86 |
|
|
|
87 |
|
|
// Create list of queues
|
88 |
|
|
this.queues = new[this.cfg.size_queues()];
|
89 |
|
|
|
90 |
|
|
// Create the queues as defined in the configuration
|
91 |
|
|
begin
|
92 |
|
|
string queue_names[];
|
93 |
|
|
|
94 |
|
|
// Get teh list of queue names
|
95 |
|
|
this.cfg.get_queues(queue_names);
|
96 |
|
|
|
97 |
|
|
foreach(queue_names[i]) begin
|
98 |
|
|
this.queues[i] = cl_syoscb_queue::type_id::create(queue_names[i], this);
|
99 |
|
|
this.cfg.set_queue(queue_names[i], this.queues[i]);
|
100 |
|
|
|
101 |
|
|
// Forward the configuration to the queue
|
102 |
|
|
uvm_config_db #(cl_syoscb_cfg)::set(this, queue_names[i], "cfg", this.cfg);
|
103 |
|
|
end
|
104 |
|
|
end
|
105 |
|
|
|
106 |
|
|
// Forward the configuration to the compare_strategy
|
107 |
|
|
uvm_config_db #(cl_syoscb_cfg)::set(this, "compare_strategy", "cfg", this.cfg);
|
108 |
|
|
|
109 |
|
|
// Create the compare strategy
|
110 |
|
|
this.compare_strategy = cl_syoscb_compare::type_id::create(.name("compare_strategy"), .parent(this));
|
111 |
|
|
|
112 |
|
|
begin
|
113 |
|
|
cl_syoscb_report_catcher catcher = new();
|
114 |
|
|
uvm_report_cb::add(null, catcher);
|
115 |
|
|
end
|
116 |
|
|
|
117 |
|
|
begin
|
118 |
|
|
string producers[];
|
119 |
|
|
|
120 |
|
|
this.cfg.get_producers(producers);
|
121 |
|
|
|
122 |
|
|
foreach(producers[i]) begin
|
123 |
|
|
cl_syoscb_cfg_pl pl = this.cfg.get_producer(producers[i]);
|
124 |
|
|
|
125 |
|
|
foreach(pl.list[j]) begin
|
126 |
|
|
cl_syoscb_subscriber subscriber;
|
127 |
|
|
|
128 |
|
|
subscriber = cl_syoscb_subscriber::type_id::create({producers[i], "_", pl.list[j], "_subscr"}, this);
|
129 |
|
|
subscriber.set_queue_name(pl.list[j]);
|
130 |
|
|
subscriber.set_producer(producers[i]);
|
131 |
|
|
this.subscribers[{pl.list[j], producers[i]}] = subscriber;
|
132 |
|
|
end
|
133 |
|
|
end
|
134 |
|
|
end
|
135 |
|
|
endfunction: build_phase
|
136 |
|
|
|
137 |
|
|
/// Method for adding a uvm_sequence_item to a given queue for a given producer.
|
138 |
|
|
/// The method will check if the queue and producer exists before adding it to the queue.
|
139 |
|
|
///
|
140 |
|
|
/// The uvm_sequence_item will be wrapped by a cl_syoscb_item along with some META data
|
141 |
|
|
/// Thus, it is the cl_syoscb_item which will be added to the queue and not the uvm_sequence_item
|
142 |
|
|
/// directly.
|
143 |
|
|
///
|
144 |
|
|
/// This ensures that the scoreboard can easily be added to an existing testbench with already defined
|
145 |
|
|
/// sequence items etc.
|
146 |
|
|
function void cl_syoscb::add_item(string queue_name, string producer, uvm_sequence_item item);
|
147 |
|
|
uvm_sequence_item item_clone;
|
148 |
|
|
|
149 |
|
|
// Check queue
|
150 |
|
|
if(!this.cfg.exist_queue(queue_name)) begin
|
151 |
|
|
`uvm_fatal("CFG_ERROR", $sformatf("[%s]: Queue: %0s is not found", this.cfg.get_scb_name(), queue_name));
|
152 |
|
|
end
|
153 |
|
|
|
154 |
|
|
// Check producer
|
155 |
|
|
if(!this.cfg.exist_producer(producer)) begin
|
156 |
|
|
`uvm_fatal("CFG_ERROR", $sformatf("[%s]: Producer: %0s is not found", this.cfg.get_scb_name(), producer));
|
157 |
|
|
end
|
158 |
|
|
|
159 |
|
|
// Clone the item if not disabled
|
160 |
|
|
// Clone the item in order to isolate the UVM scb from the rest of the TB
|
161 |
|
|
if(this.cfg.get_disable_clone() == 1'b0) begin
|
162 |
|
|
if(!$cast(item_clone, item.clone())) begin
|
163 |
|
|
`uvm_fatal("QUEUE_ERROR", $sformatf("[%s]: Unable to cast cloned item to uvm_sequence_item", this.cfg.get_scb_name()));
|
164 |
|
|
end
|
165 |
|
|
end else begin
|
166 |
|
|
item_clone = item;
|
167 |
|
|
end
|
168 |
|
|
|
169 |
|
|
// Add the uvm_sequence_item to the queue for the given producer
|
170 |
|
|
begin
|
171 |
|
|
cl_syoscb_queue queue;
|
172 |
|
|
|
173 |
|
|
queue = this.cfg.get_queue(queue_name);
|
174 |
|
|
|
175 |
|
|
if(queue == null) begin
|
176 |
|
|
`uvm_fatal("QUEUE_ERROR", $sformatf("[%s]: Queue: %s not found by add_item method", this.cfg.get_scb_name(), queue_name));
|
177 |
|
|
end
|
178 |
|
|
|
179 |
|
|
if(!queue.add_item(producer, item_clone)) begin
|
180 |
|
|
`uvm_fatal("QUEUE_ERROR", $sformatf("[%s]: Unable to add item to queue: %s", this.cfg.get_scb_name(), queue_name));
|
181 |
|
|
end
|
182 |
|
|
end
|
183 |
|
|
|
184 |
|
|
`uvm_info("DEBUG", $sformatf("[%s]: Trigger compare by queue: %s, producer: %s", this.cfg.get_scb_name(), queue_name, producer), UVM_FULL);
|
185 |
|
|
|
186 |
|
|
// Invoke the compare algorithm
|
187 |
|
|
void'(this.compare());
|
188 |
|
|
endfunction: add_item
|
189 |
|
|
|
190 |
|
|
/// Invokes the compare strategy
|
191 |
|
|
function void cl_syoscb::compare();
|
192 |
|
|
this.compare_strategy.compare();
|
193 |
|
|
endfunction: compare
|
194 |
|
|
|
195 |
|
|
/// Returns a UVM subscriber for a given combination of queue and producer
|
196 |
|
|
/// The returned UVM subscriber can then be connected to a UVM monitor or similar
|
197 |
|
|
/// which produces transactions which should be scoreboarded.
|
198 |
|
|
function cl_syoscb_subscriber cl_syoscb::get_subscriber(string queue_name, string producer);
|
199 |
|
|
if(this.subscribers.exists({queue_name, producer})) begin
|
200 |
|
|
return(this.subscribers[{queue_name, producer}]);
|
201 |
|
|
end else begin
|
202 |
|
|
`uvm_fatal("SUBSCRIBER_ERROR", $sformatf("[%s]: Unable to get subscriber for queue: %s and producer: %s", this.cfg.get_scb_name(), queue_name, producer));
|
203 |
|
|
return(null);
|
204 |
|
|
end
|
205 |
|
|
endfunction: get_subscriber
|