1 |
16 |
HanySalah |
//
|
2 |
|
|
// -------------------------------------------------------------
|
3 |
|
|
// Copyright 2004-2009 Synopsys, Inc.
|
4 |
|
|
// Copyright 2010-2011 Mentor Graphics Corporation
|
5 |
|
|
// Copyright 2010-2011 Cadence Design Systems, Inc.
|
6 |
|
|
// All Rights Reserved Worldwide
|
7 |
|
|
//
|
8 |
|
|
// Licensed under the Apache License, Version 2.0 (the
|
9 |
|
|
// "License"); you may not use this file except in
|
10 |
|
|
// compliance with the License. You may obtain a copy of
|
11 |
|
|
// the License at
|
12 |
|
|
//
|
13 |
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
14 |
|
|
//
|
15 |
|
|
// Unless required by applicable law or agreed to in
|
16 |
|
|
// writing, software distributed under the License is
|
17 |
|
|
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
18 |
|
|
// CONDITIONS OF ANY KIND, either express or implied. See
|
19 |
|
|
// the License for the specific language governing
|
20 |
|
|
// permissions and limitations under the License.
|
21 |
|
|
// -------------------------------------------------------------
|
22 |
|
|
//
|
23 |
|
|
|
24 |
|
|
|
25 |
|
|
//------------------------------------------------------------------------------
|
26 |
|
|
// TITLE: Explicit Register Predictor
|
27 |
|
|
//------------------------------------------------------------------------------
|
28 |
|
|
//
|
29 |
|
|
// The class defines a predictor component,
|
30 |
|
|
// which is used to update the register model's mirror values
|
31 |
|
|
// based on transactions explicitly observed on a physical bus.
|
32 |
|
|
//------------------------------------------------------------------------------
|
33 |
|
|
|
34 |
|
|
class uvm_predict_s;
|
35 |
|
|
bit addr[uvm_reg_addr_t];
|
36 |
|
|
uvm_reg_item reg_item;
|
37 |
|
|
endclass
|
38 |
|
|
|
39 |
|
|
//------------------------------------------------------------------------------
|
40 |
|
|
//
|
41 |
|
|
// CLASS: uvm_reg_predictor
|
42 |
|
|
//
|
43 |
|
|
// Updates the register model mirror based on observed bus transactions
|
44 |
|
|
//
|
45 |
|
|
// This class converts observed bus transactions of type ~BUSTYPE~ to generic
|
46 |
|
|
// registers transactions, determines the register being accessed based on the
|
47 |
|
|
// bus address, then updates the register's mirror value with the observed bus
|
48 |
|
|
// data, subject to the register's access mode. See for details.
|
49 |
|
|
//
|
50 |
|
|
// Memories can be large, so their accesses are not predicted.
|
51 |
|
|
//
|
52 |
|
|
//------------------------------------------------------------------------------
|
53 |
|
|
|
54 |
|
|
class uvm_reg_predictor #(type BUSTYPE=int) extends uvm_component;
|
55 |
|
|
|
56 |
|
|
`uvm_component_param_utils(uvm_reg_predictor#(BUSTYPE))
|
57 |
|
|
|
58 |
|
|
// Variable: bus_in
|
59 |
|
|
//
|
60 |
|
|
// Observed bus transactions of type ~BUSTYPE~ are received from this
|
61 |
|
|
// port and processed.
|
62 |
|
|
//
|
63 |
|
|
// For each incoming transaction, the predictor will attempt to get the
|
64 |
|
|
// register or memory handle corresponding to the observed bus address.
|
65 |
|
|
//
|
66 |
|
|
// If there is a match, the predictor calls the register or memory's
|
67 |
|
|
// predict method, passing in the observed bus data. The register or
|
68 |
|
|
// memory mirror will be updated with this data, subject to its configured
|
69 |
|
|
// access behavior--RW, RO, WO, etc. The predictor will also convert the
|
70 |
|
|
// bus transaction to a generic and send it out the
|
71 |
|
|
// ~reg_ap~ analysis port.
|
72 |
|
|
//
|
73 |
|
|
// If the register is wider than the bus, the
|
74 |
|
|
// predictor will collect the multiple bus transactions needed to
|
75 |
|
|
// determine the value being read or written.
|
76 |
|
|
//
|
77 |
|
|
uvm_analysis_imp #(BUSTYPE, uvm_reg_predictor #(BUSTYPE)) bus_in;
|
78 |
|
|
|
79 |
|
|
|
80 |
|
|
// Variable: reg_ap
|
81 |
|
|
//
|
82 |
|
|
// Analysis output port that publishes transactions
|
83 |
|
|
// converted from bus transactions received on ~bus_in~.
|
84 |
|
|
uvm_analysis_port #(uvm_reg_item) reg_ap;
|
85 |
|
|
|
86 |
|
|
|
87 |
|
|
// Variable: map
|
88 |
|
|
//
|
89 |
|
|
// The map used to convert a bus address to the corresponding register
|
90 |
|
|
// or memory handle. Must be configured before the run phase.
|
91 |
|
|
//
|
92 |
|
|
uvm_reg_map map;
|
93 |
|
|
|
94 |
|
|
|
95 |
|
|
// Variable: adapter
|
96 |
|
|
//
|
97 |
|
|
// The adapter used to convey the parameters of a bus operation in
|
98 |
|
|
// terms of a canonical datum.
|
99 |
|
|
// The must be configured before the run phase.
|
100 |
|
|
//
|
101 |
|
|
uvm_reg_adapter adapter;
|
102 |
|
|
|
103 |
|
|
|
104 |
|
|
// Function: new
|
105 |
|
|
//
|
106 |
|
|
// Create a new instance of this type, giving it the optional ~name~
|
107 |
|
|
// and ~parent~.
|
108 |
|
|
//
|
109 |
|
|
function new (string name, uvm_component parent);
|
110 |
|
|
super.new(name, parent);
|
111 |
|
|
bus_in = new("bus_in", this);
|
112 |
|
|
reg_ap = new("reg_ap", this);
|
113 |
|
|
endfunction
|
114 |
|
|
|
115 |
|
|
// This method is documented in uvm_object
|
116 |
|
|
static string type_name = "";
|
117 |
|
|
virtual function string get_type_name();
|
118 |
|
|
if (type_name == "") begin
|
119 |
|
|
BUSTYPE t;
|
120 |
|
|
t = BUSTYPE::type_id::create("t");
|
121 |
|
|
type_name = {"uvm_reg_predictor #(", t.get_type_name(), ")"};
|
122 |
|
|
end
|
123 |
|
|
return type_name;
|
124 |
|
|
endfunction
|
125 |
|
|
|
126 |
|
|
// Function: pre_predict
|
127 |
|
|
//
|
128 |
|
|
// Override this method to change the value or re-direct the
|
129 |
|
|
// target register
|
130 |
|
|
//
|
131 |
|
|
virtual function void pre_predict(uvm_reg_item rw);
|
132 |
|
|
endfunction
|
133 |
|
|
|
134 |
|
|
local uvm_predict_s m_pending[uvm_reg];
|
135 |
|
|
|
136 |
|
|
|
137 |
|
|
// Function- write
|
138 |
|
|
//
|
139 |
|
|
// not a user-level method. Do not call directly. See documentation
|
140 |
|
|
// for the ~bus_in~ member.
|
141 |
|
|
//
|
142 |
|
|
virtual function void write(BUSTYPE tr);
|
143 |
|
|
uvm_reg rg;
|
144 |
|
|
uvm_reg_bus_op rw;
|
145 |
|
|
if (adapter == null)
|
146 |
|
|
`uvm_fatal("REG/WRITE/NULL","write: adapter handle is null")
|
147 |
|
|
|
148 |
|
|
// In case they forget to set byte_en
|
149 |
|
|
rw.byte_en = -1;
|
150 |
|
|
adapter.bus2reg(tr,rw);
|
151 |
|
|
rg = map.get_reg_by_offset(rw.addr, (rw.kind == UVM_READ));
|
152 |
|
|
|
153 |
|
|
// ToDo: Add memory look-up and call
|
154 |
|
|
|
155 |
|
|
if (rg != null) begin
|
156 |
|
|
bit found;
|
157 |
|
|
uvm_reg_item reg_item;
|
158 |
|
|
uvm_reg_map local_map;
|
159 |
|
|
uvm_reg_map_info map_info;
|
160 |
|
|
uvm_predict_s predict_info;
|
161 |
|
|
uvm_reg_indirect_data ireg;
|
162 |
|
|
uvm_reg ir;
|
163 |
|
|
|
164 |
|
|
if (!m_pending.exists(rg)) begin
|
165 |
|
|
uvm_reg_item item = new;
|
166 |
|
|
predict_info =new;
|
167 |
|
|
item.element_kind = UVM_REG;
|
168 |
|
|
item.element = rg;
|
169 |
|
|
item.path = UVM_PREDICT;
|
170 |
|
|
item.map = map;
|
171 |
|
|
item.kind = rw.kind;
|
172 |
|
|
predict_info.reg_item = item;
|
173 |
|
|
m_pending[rg] = predict_info;
|
174 |
|
|
end
|
175 |
|
|
predict_info = m_pending[rg];
|
176 |
|
|
reg_item = predict_info.reg_item;
|
177 |
|
|
|
178 |
|
|
if (predict_info.addr.exists(rw.addr)) begin
|
179 |
|
|
`uvm_error("REG_PREDICT_COLLISION",{"Collision detected for register '",
|
180 |
|
|
rg.get_full_name(),"'"})
|
181 |
|
|
// TODO: what to do with subsequent collisions?
|
182 |
|
|
m_pending.delete(rg);
|
183 |
|
|
end
|
184 |
|
|
|
185 |
|
|
local_map = rg.get_local_map(map,"predictor::write()");
|
186 |
|
|
map_info = local_map.get_reg_map_info(rg);
|
187 |
|
|
ir=($cast(ireg, rg))?ireg.get_indirect_reg():rg;
|
188 |
|
|
|
189 |
|
|
foreach (map_info.addr[i]) begin
|
190 |
|
|
if (rw.addr == map_info.addr[i]) begin
|
191 |
|
|
found = 1;
|
192 |
|
|
reg_item.value[0] |= rw.data << (i * map.get_n_bytes()*8);
|
193 |
|
|
predict_info.addr[rw.addr] = 1;
|
194 |
|
|
if (predict_info.addr.num() == map_info.addr.size()) begin
|
195 |
|
|
// We've captured the entire abstract register transaction.
|
196 |
|
|
uvm_predict_e predict_kind =
|
197 |
|
|
(reg_item.kind == UVM_WRITE) ? UVM_PREDICT_WRITE : UVM_PREDICT_READ;
|
198 |
|
|
|
199 |
|
|
if (reg_item.kind == UVM_READ &&
|
200 |
|
|
local_map.get_check_on_read() &&
|
201 |
|
|
reg_item.status != UVM_NOT_OK) begin
|
202 |
|
|
void'(rg.do_check(ir.get_mirrored_value(), reg_item.value[0], local_map));
|
203 |
|
|
end
|
204 |
|
|
|
205 |
|
|
pre_predict(reg_item);
|
206 |
|
|
|
207 |
|
|
ir.XsampleX(reg_item.value[0], rw.byte_en,
|
208 |
|
|
reg_item.kind == UVM_READ, local_map);
|
209 |
|
|
begin
|
210 |
|
|
uvm_reg_block blk = rg.get_parent();
|
211 |
|
|
blk.XsampleX(map_info.offset,
|
212 |
|
|
reg_item.kind == UVM_READ,
|
213 |
|
|
local_map);
|
214 |
|
|
end
|
215 |
|
|
|
216 |
|
|
rg.do_predict(reg_item, predict_kind, rw.byte_en);
|
217 |
|
|
if(reg_item.kind == UVM_WRITE)
|
218 |
|
|
`uvm_info("REG_PREDICT", {"Observed WRITE transaction to register ",
|
219 |
|
|
ir.get_full_name(), ": value='h",
|
220 |
|
|
$sformatf("%0h",reg_item.value[0]), " : updated value = 'h",
|
221 |
|
|
$sformatf("%0h",ir.get())},UVM_HIGH)
|
222 |
|
|
else
|
223 |
|
|
`uvm_info("REG_PREDICT", {"Observed READ transaction to register ",
|
224 |
|
|
ir.get_full_name(), ": value='h",
|
225 |
|
|
$sformatf("%0h",reg_item.value[0])},UVM_HIGH)
|
226 |
|
|
reg_ap.write(reg_item);
|
227 |
|
|
m_pending.delete(rg);
|
228 |
|
|
end
|
229 |
|
|
break;
|
230 |
|
|
end
|
231 |
|
|
end
|
232 |
|
|
if (!found)
|
233 |
|
|
`uvm_error("REG_PREDICT_INTERNAL",{"Unexpected failed address lookup for register '",
|
234 |
|
|
rg.get_full_name(),"'"})
|
235 |
|
|
end
|
236 |
|
|
else begin
|
237 |
|
|
`uvm_info("REG_PREDICT_NOT_FOR_ME",
|
238 |
|
|
{"Observed transaction does not target a register: ",
|
239 |
|
|
$sformatf("%p",tr)},UVM_FULL)
|
240 |
|
|
end
|
241 |
|
|
endfunction
|
242 |
|
|
|
243 |
|
|
|
244 |
|
|
// Function: check_phase
|
245 |
|
|
//
|
246 |
|
|
// Checks that no pending register transactions are still queued.
|
247 |
|
|
|
248 |
|
|
virtual function void check_phase(uvm_phase phase);
|
249 |
|
|
string q[$];
|
250 |
|
|
super.check_phase(phase);
|
251 |
|
|
|
252 |
|
|
foreach (m_pending[l]) begin
|
253 |
|
|
uvm_reg rg=l;
|
254 |
|
|
q.push_back($sformatf("\n%s",rg.get_full_name()));
|
255 |
|
|
end
|
256 |
|
|
|
257 |
|
|
if (m_pending.num() > 0) begin
|
258 |
|
|
`uvm_error("PENDING REG ITEMS",
|
259 |
|
|
$sformatf("There are %0d incomplete register transactions still pending completion:%s",m_pending.num(),`UVM_STRING_QUEUE_STREAMING_PACK(q)))
|
260 |
|
|
|
261 |
|
|
end
|
262 |
|
|
endfunction
|
263 |
|
|
|
264 |
|
|
endclass
|