1 |
15 |
juko |
/*
|
2 |
|
|
* .--------------. .----------------. .------------.
|
3 |
|
|
* | .------------. | .--------------. | .----------. |
|
4 |
|
|
* | | ____ ____ | | | ____ ____ | | | ______ | |
|
5 |
|
|
* | ||_ || _|| | ||_ \ / _|| | | .' ___ || |
|
6 |
|
|
* ___ _ __ ___ _ __ | | | |__| | | | | | \/ | | | |/ .' \_|| |
|
7 |
|
|
* / _ \| '_ \ / _ \ '_ \ | | | __ | | | | | |\ /| | | | || | | |
|
8 |
|
|
* (_) | |_) | __/ | | || | _| | | |_ | | | _| |_\/_| |_ | | |\ `.___.'\| |
|
9 |
|
|
* \___/| .__/ \___|_| |_|| ||____||____|| | ||_____||_____|| | | `._____.'| |
|
10 |
|
|
* | | | | | | | | | | | |
|
11 |
|
|
* |_| | '------------' | '--------------' | '----------' |
|
12 |
|
|
* '--------------' '----------------' '------------'
|
13 |
|
|
*
|
14 |
|
|
* openHMC - An Open Source Hybrid Memory Cube Controller
|
15 |
|
|
* (C) Copyright 2014 Computer Architecture Group - University of Heidelberg
|
16 |
|
|
* www.ziti.uni-heidelberg.de
|
17 |
|
|
* B6, 26
|
18 |
|
|
* 68159 Mannheim
|
19 |
|
|
* Germany
|
20 |
|
|
*
|
21 |
|
|
* Contact: openhmc@ziti.uni-heidelberg.de
|
22 |
|
|
* http://ra.ziti.uni-heidelberg.de/openhmc
|
23 |
|
|
*
|
24 |
|
|
* This source file is free software: you can redistribute it and/or modify
|
25 |
|
|
* it under the terms of the GNU Lesser General Public License as published by
|
26 |
|
|
* the Free Software Foundation, either version 3 of the License, or
|
27 |
|
|
* (at your option) any later version.
|
28 |
|
|
*
|
29 |
|
|
* This source file is distributed in the hope that it will be useful,
|
30 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
31 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
32 |
|
|
* GNU Lesser General Public License for more details.
|
33 |
|
|
*
|
34 |
|
|
* You should have received a copy of the GNU Lesser General Public License
|
35 |
|
|
* along with this source file. If not, see .
|
36 |
|
|
*
|
37 |
|
|
*
|
38 |
|
|
*/
|
39 |
|
|
`ifndef HMC_DRIVER_BASE_SV
|
40 |
|
|
`define HMC_DRIVER_BASE_SV
|
41 |
|
|
|
42 |
|
|
class hmc_driver_base#(parameter NUM_LANES = 16) extends uvm_driver #(hmc_packet);
|
43 |
|
|
|
44 |
|
|
|
45 |
|
|
`uvm_analysis_imp_decl(_hmc_frp)
|
46 |
|
|
uvm_analysis_imp_hmc_frp #(hmc_packet, hmc_driver_base#(.NUM_LANES(NUM_LANES))) hmc_frp_port;
|
47 |
|
|
|
48 |
|
|
init_state_t next_state = RESET;
|
49 |
|
|
init_state_t state = RESET;
|
50 |
|
|
init_state_t last_state = LINK_UP;
|
51 |
|
|
|
52 |
|
|
virtual interface hmc_sr_if #(.NUM_LANES(NUM_LANES)) vif;
|
53 |
|
|
|
54 |
|
|
hmc_token_handler token_handler;
|
55 |
|
|
hmc_retry_buffer retry_buffer;
|
56 |
|
|
hmc_link_status remote_status;
|
57 |
|
|
|
58 |
|
|
//-- The parameters for this link
|
59 |
|
|
hmc_link_config link_config;
|
60 |
|
|
|
61 |
|
|
//-- The parameters for this driver
|
62 |
|
|
hmc_local_link_config local_config;
|
63 |
|
|
|
64 |
|
|
//-- Packets to send
|
65 |
|
|
hmc_packet packet_queue[$];
|
66 |
|
|
|
67 |
|
|
typedef bit lane_queue [$];
|
68 |
|
|
lane_queue lane_queues [NUM_LANES];
|
69 |
|
|
|
70 |
|
|
event driver_clk;
|
71 |
|
|
|
72 |
|
|
uvm_event start_clear_retry_event;
|
73 |
|
|
|
74 |
|
|
// Timestamps for debugging
|
75 |
|
|
int reset_timestamp = 0;
|
76 |
|
|
int prbs_timestamp = 0;
|
77 |
|
|
int null_timestamp = 0;
|
78 |
|
|
int req_ts1_timestamp = 0;
|
79 |
|
|
int ts1_timestamp = 0;
|
80 |
|
|
|
81 |
|
|
// Timestamps for controlling packet flow
|
82 |
|
|
int last_packet_timestamp = 0;
|
83 |
|
|
int start_retry_timestamp = 0;
|
84 |
|
|
//-- error propability
|
85 |
|
|
int next_poisoned = 0;
|
86 |
|
|
int lng_error_prob = 0;
|
87 |
|
|
int seq_error_prob = 0;
|
88 |
|
|
int crc_error_prob = 0;
|
89 |
|
|
|
90 |
|
|
bit recover_from_power_down = 0;
|
91 |
|
|
|
92 |
|
|
// Count retry attempts signalled by the responder (from here)
|
93 |
|
|
int retry_attempts = 0;
|
94 |
|
|
|
95 |
|
|
// Count retry attempts from the requester
|
96 |
|
|
int remote_retries_signalled = 0;
|
97 |
|
|
int remote_retries_cleared = 0;
|
98 |
|
|
int local_retries_signalled = 0;
|
99 |
|
|
int local_retries_cleared = 0;
|
100 |
|
|
|
101 |
|
|
// Internal state for scramblers
|
102 |
|
|
bit [14:0] lfsr[NUM_LANES-1:0];
|
103 |
|
|
|
104 |
|
|
// Internal state for packets
|
105 |
|
|
bit [2:0] seq_num = 1;
|
106 |
|
|
|
107 |
|
|
// State for tokens and frp
|
108 |
|
|
bit [7:0] frp_queue [$];
|
109 |
|
|
bit [7:0] last_frp = 0;
|
110 |
|
|
bit [7:0] last_rrp;
|
111 |
|
|
|
112 |
|
|
int tokens_to_send = 0;
|
113 |
|
|
|
114 |
|
|
int used_tokens = 0;
|
115 |
|
|
int sent_tokens = 0;
|
116 |
|
|
|
117 |
|
|
bit [14:0] lfsr_seed[0:15] = {
|
118 |
|
|
15'h4D56,
|
119 |
|
|
15'h47FF,
|
120 |
|
|
15'h75B8,
|
121 |
|
|
15'h1E18,
|
122 |
|
|
15'h2E10,
|
123 |
|
|
15'h3EB2,
|
124 |
|
|
15'h4302,
|
125 |
|
|
15'h1380,
|
126 |
|
|
15'h3EB3,
|
127 |
|
|
15'h2769,
|
128 |
|
|
15'h4580,
|
129 |
|
|
15'h5665,
|
130 |
|
|
15'h6318,
|
131 |
|
|
15'h6014,
|
132 |
|
|
15'h077B,
|
133 |
|
|
15'h261F
|
134 |
|
|
};
|
135 |
|
|
|
136 |
|
|
bit [15:8] ts1_high = 8'hF0;
|
137 |
|
|
bit [7:4] ts1_top_lane = 4'hC;
|
138 |
|
|
bit [7:4] ts1_bottom_lane = 4'h3;
|
139 |
|
|
bit [7:4] ts1_middle_lane = 4'h5;
|
140 |
|
|
|
141 |
|
|
// Configuration parameters
|
142 |
|
|
bit init_continue;
|
143 |
|
|
bit can_continue;
|
144 |
|
|
|
145 |
|
|
`uvm_component_param_utils(hmc_driver_base #(.NUM_LANES(NUM_LANES)))
|
146 |
|
|
|
147 |
|
|
function new(string name="hmc_driver_base", uvm_component parent);
|
148 |
|
|
super.new(name,parent);
|
149 |
|
|
endfunction : new
|
150 |
|
|
|
151 |
|
|
function void build_phase(uvm_phase phase);
|
152 |
|
|
super.build_phase(phase);
|
153 |
|
|
|
154 |
|
|
vif_found : assert (uvm_config_db#(virtual interface hmc_sr_if#(.NUM_LANES(NUM_LANES)))::get(this, "", "vif",this.vif));
|
155 |
|
|
config_found : assert (uvm_config_db#(hmc_link_config)::get(this, "", "link_config",link_config));
|
156 |
|
|
endfunction : build_phase
|
157 |
|
|
|
158 |
|
|
virtual task run_phase(uvm_phase phase);
|
159 |
|
|
super.run_phase(phase);
|
160 |
|
|
endtask : run_phase
|
161 |
|
|
|
162 |
|
|
task reset();
|
163 |
|
|
|
164 |
|
|
vif.TXP = {$size(vif.TXP) {1'bz}};
|
165 |
|
|
vif.TXN = {$size(vif.TXN) {1'bz}};
|
166 |
|
|
vif.TXPS = 1'bz;
|
167 |
|
|
|
168 |
|
|
seq_num = 1;
|
169 |
|
|
last_rrp = 0;
|
170 |
|
|
init_continue = 0;
|
171 |
|
|
can_continue = 0;
|
172 |
|
|
retry_buffer.reset();
|
173 |
|
|
|
174 |
|
|
//-- wait for reset signal
|
175 |
|
|
@(posedge vif.P_RST_N);
|
176 |
|
|
reset_timestamp = $time;
|
177 |
|
|
|
178 |
|
|
next_state = INIT;
|
179 |
|
|
endtask : reset
|
180 |
|
|
|
181 |
|
|
task clk_gen();
|
182 |
|
|
@(posedge vif.REFCLKP);
|
183 |
|
|
forever begin
|
184 |
|
|
#link_config.bit_time -> driver_clk;
|
185 |
|
|
end
|
186 |
|
|
endtask : clk_gen
|
187 |
|
|
|
188 |
|
|
task send_ts1(int ts1_fits);
|
189 |
|
|
bit [4:0] ts1_seq_num;
|
190 |
|
|
bit [NUM_LANES-1:0] fit_val;
|
191 |
|
|
bit [15:0] ts1_values [NUM_LANES-1:0];
|
192 |
|
|
|
193 |
|
|
ts1_values[0] = {ts1_high, ts1_bottom_lane, 4'h0};
|
194 |
|
|
for (int lane=1; lane < local_config.width-1; lane++)
|
195 |
|
|
ts1_values[lane] = {ts1_high, ts1_middle_lane, 4'h0};
|
196 |
|
|
ts1_values[local_config.width-1] = {ts1_high, ts1_top_lane, 4'h0};
|
197 |
|
|
|
198 |
|
|
//Send some (possibly incomplete) TS1 flits
|
199 |
|
|
while (ts1_fits > 0) begin
|
200 |
|
|
// Cycle through all the sequence numbers
|
201 |
|
|
for (ts1_seq_num=0; ts1_seq_num < 16 && ts1_fits > 0; ts1_seq_num++) begin
|
202 |
|
|
// Add the sequence number to the ts1_values
|
203 |
|
|
for (int i=0; i < local_config.width; i++) begin
|
204 |
|
|
ts1_values[i][3:0] = ts1_seq_num;
|
205 |
|
|
end
|
206 |
|
|
// Send the fits of the ts1 values
|
207 |
|
|
for (int fit=0; fit < 16; fit++) begin
|
208 |
|
|
for (int lane=0; lane < local_config.width; lane++) begin
|
209 |
|
|
fit_val[lane] = ts1_values[lane][fit];
|
210 |
|
|
end
|
211 |
|
|
if (ts1_fits > 0) begin
|
212 |
|
|
drive_fit(fit_val);
|
213 |
|
|
end else begin
|
214 |
|
|
drive_fit({NUM_LANES{1'b0}});
|
215 |
|
|
end
|
216 |
|
|
ts1_fits = ts1_fits - 1;
|
217 |
|
|
end
|
218 |
|
|
end
|
219 |
|
|
end
|
220 |
|
|
endtask : send_ts1
|
221 |
|
|
|
222 |
|
|
task initial_trets();
|
223 |
|
|
hmc_packet tret = new();
|
224 |
|
|
//send TRET FLITs
|
225 |
|
|
while (tokens_to_send > 0) begin
|
226 |
|
|
init_tret_randomization : assert (tret.randomize() with {
|
227 |
|
|
command == HMC_TRET;
|
228 |
|
|
poisoned == 0;
|
229 |
|
|
crc_error == 0;
|
230 |
|
|
packet_length == 1;
|
231 |
|
|
duplicate_length == 1;
|
232 |
|
|
return_token_count <= tokens_to_send && return_token_count > 0;
|
233 |
|
|
});
|
234 |
|
|
send_packet(tret);
|
235 |
|
|
tokens_to_send = tokens_to_send - tret.return_token_count;
|
236 |
|
|
end
|
237 |
|
|
next_state = LINK_UP;
|
238 |
|
|
endtask : initial_trets
|
239 |
|
|
|
240 |
|
|
task link_up();
|
241 |
|
|
hmc_packet packet;
|
242 |
|
|
|
243 |
|
|
get_packets();
|
244 |
|
|
|
245 |
|
|
if (packet_queue.size() > 0 && token_handler.tokens_available(packet_queue[0].packet_length) && (250- retry_buffer.get_buffer_used()) > packet_queue[0].packet_length ) begin
|
246 |
|
|
packet = packet_queue.pop_front(); //-- send the first packet in the queue
|
247 |
|
|
if ((next_poisoned < local_config.poisoned_probability))
|
248 |
|
|
send_poisoned(packet);
|
249 |
|
|
else
|
250 |
|
|
send_packet(packet);
|
251 |
|
|
|
252 |
|
|
poisoned_propability_randomisation : assert (std::randomize(next_poisoned) with {next_poisoned > 0 && next_poisoned < 1000;});
|
253 |
|
|
|
254 |
|
|
end else if ($time-last_packet_timestamp > local_config.send_pret_time && frp_queue.size() > 0) begin
|
255 |
|
|
`uvm_info(get_type_name(),$psprintf("sending pret, frp_queue size = %0d", frp_queue.size()), UVM_HIGH)
|
256 |
|
|
send_pret();
|
257 |
|
|
end else if ($time-last_packet_timestamp > local_config.send_tret_time && (used_tokens - sent_tokens) > 0 &&(250- retry_buffer.get_buffer_used()) >1) begin
|
258 |
|
|
`uvm_info(get_type_name(),$psprintf("sending tret, (<%0d)", used_tokens-sent_tokens), UVM_HIGH)
|
259 |
|
|
send_tret();
|
260 |
|
|
end else begin
|
261 |
|
|
drive_flit(128'h0);
|
262 |
|
|
end
|
263 |
|
|
|
264 |
|
|
// From here on, there are no packets being driven. This is just logic to decide the next state.
|
265 |
|
|
|
266 |
|
|
//-- Handle error_abort_mode on remote link
|
267 |
|
|
if (remote_status.get_error_abort_mode() && $time() - start_retry_timestamp > link_config.retry_timeout_period ) begin
|
268 |
|
|
next_state = START_RETRY_INIT;
|
269 |
|
|
end
|
270 |
|
|
endtask : link_up
|
271 |
|
|
|
272 |
|
|
task start_retry_init(); //-- send start retry IRTRYs
|
273 |
|
|
|
274 |
|
|
start_retry_timestamp = $time;
|
275 |
|
|
local_retries_signalled = local_retries_signalled + 1;
|
276 |
|
|
`uvm_info(get_type_name(),$psprintf("sending start retry packets"), UVM_MEDIUM)
|
277 |
|
|
|
278 |
|
|
//send IRTRY FLITs
|
279 |
|
|
for (int i=0; i < local_config.irtry_flit_count_to_send; i++)
|
280 |
|
|
send_irtry_start();
|
281 |
|
|
|
282 |
|
|
next_state = LINK_UP;
|
283 |
|
|
endtask : start_retry_init
|
284 |
|
|
|
285 |
|
|
task clear_retry(); //-- send clear error abort mode IRTRYs
|
286 |
|
|
|
287 |
|
|
local_retries_cleared = local_retries_cleared + 1;
|
288 |
|
|
//send IRTRY FLITs
|
289 |
|
|
for (int i=0; i < local_config.irtry_flit_count_to_send; i++)
|
290 |
|
|
send_irtry_clear();
|
291 |
|
|
next_state = SEND_RETRY_PACKETS;
|
292 |
|
|
endtask : clear_retry
|
293 |
|
|
|
294 |
|
|
task send_retry_packets();
|
295 |
|
|
hmc_packet packet;
|
296 |
|
|
int spacer_flits;
|
297 |
|
|
|
298 |
|
|
packet = retry_buffer.get_retry_packet();
|
299 |
|
|
while (packet != null) begin
|
300 |
|
|
spacer_flits_randomization_succeeds : assert (std::randomize(spacer_flits) with {spacer_flits >= 0 && spacer_flits < 10;});
|
301 |
|
|
for (int i=0; i
|
302 |
|
|
drive_flit(128'h0);
|
303 |
|
|
end
|
304 |
|
|
retry_send_packet(packet);
|
305 |
|
|
packet = retry_buffer.get_retry_packet();
|
306 |
|
|
end
|
307 |
|
|
next_state = LINK_UP;
|
308 |
|
|
endtask : send_retry_packets
|
309 |
|
|
|
310 |
|
|
task get_packets();
|
311 |
|
|
hmc_packet packet;
|
312 |
|
|
|
313 |
|
|
if( seq_item_port.has_do_available() ) begin
|
314 |
|
|
if( packet_queue.size() == 0) begin
|
315 |
|
|
seq_item_port.get_next_item(packet);
|
316 |
|
|
packet_queue.push_back(packet);
|
317 |
|
|
seq_item_port.item_done();
|
318 |
|
|
end
|
319 |
|
|
end
|
320 |
|
|
endtask : get_packets
|
321 |
|
|
|
322 |
|
|
task send_irtry_start();
|
323 |
|
|
send_irtry(1,0);
|
324 |
|
|
endtask : send_irtry_start
|
325 |
|
|
|
326 |
|
|
task send_irtry_clear();
|
327 |
|
|
send_irtry(0,1);
|
328 |
|
|
endtask : send_irtry_clear
|
329 |
|
|
|
330 |
|
|
task send_irtry(input bit start, input bit clear);
|
331 |
|
|
hmc_packet irtry = new();
|
332 |
|
|
|
333 |
|
|
irtry_randomization: assert (irtry.randomize() with {
|
334 |
|
|
command == HMC_IRTRY;
|
335 |
|
|
packet_length == 1;
|
336 |
|
|
duplicate_length == 1;
|
337 |
|
|
start_retry == start;
|
338 |
|
|
clear_error_abort == clear;
|
339 |
|
|
});
|
340 |
|
|
|
341 |
|
|
send_packet(irtry);
|
342 |
|
|
endtask : send_irtry
|
343 |
|
|
|
344 |
|
|
task send_tret();
|
345 |
|
|
|
346 |
|
|
hmc_packet tret = new();
|
347 |
|
|
|
348 |
|
|
tret_randomization: assert (tret.randomize() with {
|
349 |
|
|
command == HMC_TRET;
|
350 |
|
|
packet_length == 1;
|
351 |
|
|
duplicate_length == 1;
|
352 |
|
|
});
|
353 |
|
|
|
354 |
|
|
send_packet(tret);
|
355 |
|
|
|
356 |
|
|
endtask : send_tret
|
357 |
|
|
|
358 |
|
|
task send_pret();
|
359 |
|
|
|
360 |
|
|
hmc_packet pret = new();
|
361 |
|
|
|
362 |
|
|
pret_randomization: assert (pret.randomize() with {
|
363 |
|
|
command == HMC_PRET;
|
364 |
|
|
packet_length == 1;
|
365 |
|
|
duplicate_length == 1;
|
366 |
|
|
});
|
367 |
|
|
|
368 |
|
|
send_packet(pret);
|
369 |
|
|
|
370 |
|
|
endtask : send_pret
|
371 |
|
|
|
372 |
|
|
task send_poisoned(input hmc_packet pkt);
|
373 |
|
|
hmc_packet poisoned = new pkt; //-- copy the pkt into a new one
|
374 |
|
|
|
375 |
|
|
`uvm_info(get_type_name(),$psprintf("Poisoning Packet with command %s and tag %d", poisoned.command.name(), poisoned.tag),UVM_NONE)
|
376 |
|
|
|
377 |
|
|
poisoned.poisoned = 1;
|
378 |
|
|
send_packet(poisoned);
|
379 |
|
|
|
380 |
|
|
packet_queue.push_back(pkt);//-- resent the packet later
|
381 |
|
|
|
382 |
|
|
endtask : send_poisoned
|
383 |
|
|
|
384 |
|
|
task send_packet(input hmc_packet pkt);
|
385 |
|
|
int packet_frp;
|
386 |
|
|
bit [31:0] crc;
|
387 |
|
|
int bit_pos;
|
388 |
|
|
int tok_cnt;
|
389 |
|
|
// Save packet in Retry buffer if not IRTRY, NULL, or PRET
|
390 |
|
|
// Tokens and Sequence numbers are saved in the retry buffer.
|
391 |
|
|
|
392 |
|
|
if (pkt.command == HMC_IRTRY ||
|
393 |
|
|
pkt.command == HMC_NULL ||
|
394 |
|
|
pkt.command == HMC_PRET) begin
|
395 |
|
|
packet_frp = 0;
|
396 |
|
|
pkt.sequence_number = 0;
|
397 |
|
|
retry_send_packet(pkt);
|
398 |
|
|
end else begin
|
399 |
|
|
pkt.sequence_number = seq_num;
|
400 |
|
|
if (state != INITIAL_TRETS) begin
|
401 |
|
|
if (used_tokens - sent_tokens > 0) begin
|
402 |
|
|
// Always send tokens with TRETs
|
403 |
|
|
if (pkt.command == HMC_TRET)
|
404 |
|
|
tok_cnd_tret_randomization : assert (std::randomize(tok_cnt) with {(pkt.command == HMC_TRET && tok_cnt > 0) && tok_cnt < 32 && tok_cnt <= (used_tokens - sent_tokens);});
|
405 |
|
|
else
|
406 |
|
|
tok_cnt_randomization_succeeds : assert (std::randomize(tok_cnt) with {(tok_cnt >= 0) && tok_cnt < 32 && tok_cnt <= (used_tokens - sent_tokens);});
|
407 |
|
|
pkt.return_token_count = tok_cnt;
|
408 |
|
|
end else begin
|
409 |
|
|
pkt.return_token_count = 0;
|
410 |
|
|
end
|
411 |
|
|
end
|
412 |
|
|
packet_frp = retry_buffer.add_packet(pkt);
|
413 |
|
|
if(packet_frp != -1)begin
|
414 |
|
|
seq_num++;
|
415 |
|
|
if (state != INITIAL_TRETS) begin
|
416 |
|
|
sent_tokens += pkt.return_token_count;
|
417 |
|
|
end
|
418 |
|
|
// From now on, it's equivalent to retry
|
419 |
|
|
`uvm_info(get_type_name(), $psprintf("Sending CDM %s with TRETS %d", pkt.command.name(), pkt.return_token_count), UVM_HIGH)
|
420 |
|
|
retry_send_packet(pkt);
|
421 |
|
|
end
|
422 |
|
|
end
|
423 |
|
|
endtask : send_packet
|
424 |
|
|
|
425 |
|
|
task retry_send_packet(input hmc_packet pkt);
|
426 |
|
|
bit [31:0] crc;
|
427 |
|
|
int bit_pos;
|
428 |
|
|
int bit_error;
|
429 |
|
|
int error_type;
|
430 |
|
|
int rrp_to_send;
|
431 |
|
|
|
432 |
|
|
|
433 |
|
|
int pkt_lng;
|
434 |
|
|
bit [2:0]seq_number;
|
435 |
|
|
|
436 |
|
|
|
437 |
|
|
// Don't change the stored packet (except to clear the CRC error flag)
|
438 |
|
|
hmc_packet copy = new pkt;
|
439 |
|
|
|
440 |
|
|
// Return retry pointers are not saved.
|
441 |
|
|
// Skip some retry pointers
|
442 |
|
|
rrp_to_send_randomization_succeeds : assert (std::randomize(rrp_to_send) with {rrp_to_send >= 0 && rrp_to_send <= frp_queue.size();});
|
443 |
|
|
if (rrp_to_send == 0) begin
|
444 |
|
|
copy.return_retry_pointer = last_rrp;
|
445 |
|
|
end else begin
|
446 |
|
|
for (int i=0;i
|
447 |
|
|
copy.return_retry_pointer = frp_queue.pop_front();
|
448 |
|
|
`uvm_info(get_type_name(),$psprintf("popped %0d for frp in %s", copy.return_retry_pointer, copy.command.name()),UVM_HIGH)
|
449 |
|
|
end
|
450 |
|
|
end
|
451 |
|
|
last_rrp = copy.return_retry_pointer;
|
452 |
|
|
|
453 |
|
|
//-- ERROR INJECTION
|
454 |
|
|
|
455 |
|
|
//-- adding sequence error
|
456 |
|
|
error_type_seq_error_randomization : assert (std::randomize(seq_error_prob) with {seq_error_prob > 0 && seq_error_prob < 1000;});
|
457 |
|
|
if (seq_error_prob < local_config.seq_error_probability) begin
|
458 |
|
|
randcase
|
459 |
|
|
1: copy.sequence_number = copy.sequence_number + 1;
|
460 |
|
|
1: copy.sequence_number = copy.sequence_number - 1;
|
461 |
|
|
1: begin
|
462 |
|
|
random_SEQ_succeeds : assert(
|
463 |
|
|
std::randomize(seq_number) with { seq_number !=copy.sequence_number;});
|
464 |
|
|
copy.sequence_number = seq_number;
|
465 |
|
|
end
|
466 |
|
|
endcase
|
467 |
|
|
`uvm_info(get_type_name(),$psprintf("injecting SEQ error in CMD %s and FRP %d",copy.command.name(), copy.forward_retry_pointer), UVM_NONE)
|
468 |
|
|
end
|
469 |
|
|
|
470 |
|
|
|
471 |
|
|
//-- inserting Length Error
|
472 |
|
|
error_type_lng_error_randomization : assert (std::randomize(lng_error_prob) with {lng_error_prob > 0 && lng_error_prob < 1000;});
|
473 |
|
|
if (lng_error_prob < local_config.lng_error_probability) begin
|
474 |
|
|
randcase
|
475 |
|
|
1: copy.packet_length = copy.packet_length + 1;
|
476 |
|
|
1: copy.packet_length = copy.packet_length - 1;
|
477 |
|
|
1: copy.duplicate_length = copy.duplicate_length + 1;
|
478 |
|
|
1: copy.duplicate_length = copy.duplicate_length - 1;
|
479 |
|
|
1: begin random_LNG_succeeds : assert(
|
480 |
|
|
std::randomize(pkt_lng) with {pkt_lng >= 0 && pkt_lng < 16 && pkt_lng !=copy.packet_length;});
|
481 |
|
|
copy.packet_length = pkt_lng;
|
482 |
|
|
end
|
483 |
|
|
1: begin random_DLN_succeeds : assert(
|
484 |
|
|
std::randomize(pkt_lng) with {pkt_lng >= 0 && pkt_lng < 16 && pkt_lng !=copy.duplicate_length;});
|
485 |
|
|
copy.duplicate_length = pkt_lng;
|
486 |
|
|
end
|
487 |
|
|
endcase
|
488 |
|
|
end
|
489 |
|
|
|
490 |
|
|
crc = copy.calculate_crc(); //-- calculate crc for packet with valid tail
|
491 |
|
|
|
492 |
|
|
|
493 |
|
|
//-- poisoning packets
|
494 |
|
|
if (copy.poisoned) begin
|
495 |
|
|
`uvm_info(get_type_name(),$psprintf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX poisoning packet with CRC %0x and CMD %s and TAG %d", ~crc, copy.command.name(), copy.tag),UVM_LOW)
|
496 |
|
|
crc = ~crc;
|
497 |
|
|
end
|
498 |
|
|
|
499 |
|
|
|
500 |
|
|
//-- inserting CRC error
|
501 |
|
|
error_type_crc_error_randomization : assert (std::randomize(crc_error_prob) with {crc_error_prob > 0 && crc_error_prob < 1000;});
|
502 |
|
|
if (crc_error_prob < local_config.crc_error_probability * copy.packet_length) begin //-- increase the crc error probability for longer packets
|
503 |
|
|
int clear_crc_error;
|
504 |
|
|
crc_bit_error_randomization_succeeds : assert (std::randomize(bit_pos) with {bit_pos >= 0 && bit_pos < 32;});
|
505 |
|
|
`uvm_info(get_type_name(),$psprintf("inserting crc error at %0x", bit_pos),UVM_LOW)
|
506 |
|
|
crc[bit_pos] = !crc[bit_pos];
|
507 |
|
|
clear_crc_error_randomization_succeeds : assert (std::randomize(clear_crc_error) with {clear_crc_error >= 0 && clear_crc_error < 3;});
|
508 |
|
|
if (clear_crc_error == 1)
|
509 |
|
|
pkt.crc_error = 0;
|
510 |
|
|
end
|
511 |
|
|
copy.packet_crc = crc;
|
512 |
|
|
drive_tx_packet(copy);
|
513 |
|
|
|
514 |
|
|
endtask : retry_send_packet
|
515 |
|
|
|
516 |
|
|
task drive_fit(input bit[NUM_LANES-1:0] new_value);
|
517 |
|
|
if (link_config.scramblers_enabled) begin
|
518 |
|
|
drive_lanes(get_scrambler_value()^new_value);
|
519 |
|
|
end else begin
|
520 |
|
|
drive_lanes(new_value);
|
521 |
|
|
end
|
522 |
|
|
@driver_clk;
|
523 |
|
|
step_scramblers();
|
524 |
|
|
endtask : drive_fit
|
525 |
|
|
|
526 |
|
|
task drive_flit(input bit [127:0] flit);
|
527 |
|
|
int i;
|
528 |
|
|
bit [15:0] fits [16];
|
529 |
|
|
|
530 |
|
|
for (int i=0; i<128; i++)
|
531 |
|
|
fits[i/local_config.width][i%local_config.width] = flit[i];
|
532 |
|
|
|
533 |
|
|
for (int i=0; i<128/local_config.width;i++) begin
|
534 |
|
|
drive_fit(fits[i]);
|
535 |
|
|
end
|
536 |
|
|
|
537 |
|
|
endtask : drive_flit
|
538 |
|
|
|
539 |
|
|
task drive_tx_packet(input hmc_packet pkt);
|
540 |
|
|
bit bitstream[];
|
541 |
|
|
bit [127:0] flits [9]; // Max packet size is 9 flits
|
542 |
|
|
bit [127:0] curr_flit;
|
543 |
|
|
int i;
|
544 |
|
|
int bitcount;
|
545 |
|
|
bitcount = pkt.pack(bitstream);
|
546 |
|
|
|
547 |
|
|
for (int i=0; i
|
548 |
|
|
flits[i/128][i%128] = bitstream[i];
|
549 |
|
|
for (int i=0; i
|
550 |
|
|
drive_flit(flits[i]);
|
551 |
|
|
end
|
552 |
|
|
|
553 |
|
|
last_packet_timestamp = $time;
|
554 |
|
|
|
555 |
|
|
endtask : drive_tx_packet
|
556 |
|
|
|
557 |
|
|
virtual function void drive_lanes(input bit[NUM_LANES-1:0] new_value);
|
558 |
|
|
`uvm_info(get_type_name(),$psprintf("called virtual function drive_lanes!"), UVM_HIGH)
|
559 |
|
|
endfunction : drive_lanes
|
560 |
|
|
|
561 |
|
|
function void reset_lfsr();
|
562 |
|
|
int i;
|
563 |
|
|
|
564 |
|
|
for (i = 0; i < NUM_LANES; i= i+1) begin
|
565 |
|
|
if (local_config.reverse_lanes == 1)
|
566 |
|
|
lfsr[i] = lfsr_seed[NUM_LANES-1-i];
|
567 |
|
|
else
|
568 |
|
|
lfsr[i] = lfsr_seed[i];
|
569 |
|
|
end
|
570 |
|
|
endfunction : reset_lfsr
|
571 |
|
|
|
572 |
|
|
function void step_scramblers();
|
573 |
|
|
int i;
|
574 |
|
|
|
575 |
|
|
if (link_config.scramblers_enabled) begin
|
576 |
|
|
for (i = 0; i < NUM_LANES; i= i+1) begin
|
577 |
|
|
lfsr[i] = {lfsr[i][1]^lfsr[i][0], lfsr[i][14:1]};
|
578 |
|
|
end
|
579 |
|
|
end
|
580 |
|
|
endfunction : step_scramblers
|
581 |
|
|
|
582 |
|
|
function bit[NUM_LANES-1:0] get_scrambler_value();
|
583 |
|
|
int i;
|
584 |
|
|
|
585 |
|
|
if (link_config.scramblers_enabled) begin
|
586 |
|
|
for (i = 0; i < NUM_LANES; i= i+1) begin
|
587 |
|
|
get_scrambler_value[i] = lfsr[i][0];
|
588 |
|
|
end
|
589 |
|
|
end else begin
|
590 |
|
|
for (i = 0; i < NUM_LANES; i= i+1) begin
|
591 |
|
|
get_scrambler_value = {NUM_LANES {1'b0}};
|
592 |
|
|
end
|
593 |
|
|
end
|
594 |
|
|
endfunction : get_scrambler_value
|
595 |
|
|
|
596 |
|
|
// I2C or JTAG would configure the HMC during reset
|
597 |
|
|
function void set_init_continue();
|
598 |
|
|
tb_respects_tINIT : assert (can_continue);
|
599 |
|
|
init_continue = 1;
|
600 |
|
|
endfunction : set_init_continue
|
601 |
|
|
|
602 |
|
|
virtual function void write_hmc_frp(input hmc_packet pkt);
|
603 |
|
|
|
604 |
|
|
bit [7:0] frp;
|
605 |
|
|
int random_wait;
|
606 |
|
|
|
607 |
|
|
`uvm_info(get_type_name(),$psprintf("hmc_frp: %s with FRP %0d & size %0d",pkt.command.name(), pkt.forward_retry_pointer, pkt.packet_length),UVM_HIGH)
|
608 |
|
|
|
609 |
|
|
// IRTRY and PRET do not have valid frp fields
|
610 |
|
|
if (pkt.command != HMC_IRTRY && pkt.command != HMC_PRET) begin
|
611 |
|
|
frp = pkt.forward_retry_pointer;
|
612 |
|
|
if (frp != last_frp) begin
|
613 |
|
|
frp_queue.push_back(frp);
|
614 |
|
|
last_frp = frp;
|
615 |
|
|
end
|
616 |
|
|
end
|
617 |
|
|
|
618 |
|
|
if (pkt.get_command_type != HMC_FLOW_TYPE && !pkt.poisoned ) begin
|
619 |
|
|
used_tokens_does_not_overflow : assert ( used_tokens < used_tokens + pkt.packet_length);
|
620 |
|
|
used_tokens = used_tokens + pkt.packet_length;
|
621 |
|
|
end
|
622 |
|
|
|
623 |
|
|
endfunction : write_hmc_frp
|
624 |
|
|
|
625 |
|
|
endclass : hmc_driver_base
|
626 |
|
|
|
627 |
|
|
`endif // HMC_DRIVER_BASE_SV
|
628 |
|
|
|