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 |
|
|
//
|
40 |
|
|
//
|
41 |
|
|
// hmc_packet monitor
|
42 |
|
|
//
|
43 |
|
|
//
|
44 |
|
|
|
45 |
|
|
`ifndef HMC_MONITOR_SV
|
46 |
|
|
`define HMC_MONITOR_SV
|
47 |
|
|
|
48 |
|
|
class hmc_monitor#(parameter NUM_LANES = 16) extends uvm_monitor;
|
49 |
|
|
|
50 |
|
|
virtual hmc_sr_if#(.NUM_LANES(NUM_LANES)) vif;
|
51 |
|
|
|
52 |
|
|
hmc_link_config link_config;
|
53 |
|
|
hmc_local_link_config local_config;
|
54 |
|
|
hmc_status status;
|
55 |
|
|
hmc_link_status link_status;
|
56 |
|
|
hmc_link_status remote_link_status;
|
57 |
|
|
hmc_transaction_mon transaction_mon;
|
58 |
|
|
hmc_cdr #(.NUM_LANES(NUM_LANES)) cdr;
|
59 |
|
|
|
60 |
|
|
uvm_analysis_port #(hmc_packet) item_collected_port;
|
61 |
|
|
uvm_analysis_port #(hmc_packet) return_token_port;
|
62 |
|
|
uvm_analysis_port #(hmc_packet) frp_port;
|
63 |
|
|
uvm_analysis_port #(int) rrp_port;
|
64 |
|
|
|
65 |
|
|
uvm_event start_clear_retry_event;
|
66 |
|
|
event lane_queue_event; //-- triggers after write to any lane queue
|
67 |
|
|
event flit_queue_event; //-- triggers after write to the collected_flits queue
|
68 |
|
|
|
69 |
|
|
// Partial flits from each lane
|
70 |
|
|
typedef bit [14:0] lsfr_t;
|
71 |
|
|
typedef bit [15:0] partial_flit_t;
|
72 |
|
|
typedef bit [127:0] flit_t;
|
73 |
|
|
// Queue of unassembled flits (per lane)
|
74 |
|
|
typedef partial_flit_t partial_flit_queue_t[$];
|
75 |
|
|
partial_flit_queue_t lane_queues[];
|
76 |
|
|
|
77 |
|
|
|
78 |
|
|
|
79 |
|
|
bit [2:0] next_sequence_num;
|
80 |
|
|
bit lane_reversal_set = 0;//-- TODO move to link_status
|
81 |
|
|
|
82 |
|
|
bit bitstream[$];
|
83 |
|
|
bit [127:0] collected_flits[$];
|
84 |
|
|
|
85 |
|
|
|
86 |
|
|
hmc_packet collected_packet;
|
87 |
|
|
|
88 |
|
|
//-- reporting counter
|
89 |
|
|
int lng_error = 0;
|
90 |
|
|
int crc_error = 0;
|
91 |
|
|
int seq_error = 0;
|
92 |
|
|
int poisoned_pkt =0;
|
93 |
|
|
|
94 |
|
|
|
95 |
|
|
typedef enum {
|
96 |
|
|
LENGTH_ERROR,
|
97 |
|
|
CRC_ERROR,
|
98 |
|
|
SEQ_ERROR,
|
99 |
|
|
POISON,
|
100 |
|
|
INVALID_TS1
|
101 |
|
|
}error_class_e;
|
102 |
|
|
|
103 |
|
|
//-- coverage --//
|
104 |
|
|
int packets_after_Link_up = 0;
|
105 |
|
|
int start_retry_count = 0;
|
106 |
|
|
int clear_error_abort_count = 0;
|
107 |
|
|
error_class_e current_error;
|
108 |
|
|
|
109 |
|
|
int null_flits_after_TS1 = 0;
|
110 |
|
|
int null_flits_between_pkts = 0;
|
111 |
|
|
|
112 |
|
|
|
113 |
|
|
covergroup hmc_pkt_error_cg;
|
114 |
|
|
option.per_instance = 1;
|
115 |
|
|
ERROR_TYPE: coverpoint current_error;
|
116 |
|
|
|
117 |
|
|
HMC_COMMAND: coverpoint collected_packet.command {
|
118 |
|
|
bins flow_types[] = {
|
119 |
|
|
HMC_TRET,
|
120 |
|
|
HMC_PRET,
|
121 |
|
|
HMC_NULL,
|
122 |
|
|
HMC_IRTRY
|
123 |
|
|
};
|
124 |
|
|
bins requests[] = {
|
125 |
|
|
HMC_WRITE_16,
|
126 |
|
|
HMC_WRITE_32,
|
127 |
|
|
HMC_WRITE_48,
|
128 |
|
|
HMC_WRITE_64,
|
129 |
|
|
HMC_WRITE_80,
|
130 |
|
|
HMC_WRITE_96,
|
131 |
|
|
HMC_WRITE_112,
|
132 |
|
|
HMC_WRITE_128,
|
133 |
|
|
|
134 |
|
|
HMC_MODE_WRITE,
|
135 |
|
|
HMC_BIT_WRITE,
|
136 |
|
|
HMC_DUAL_8B_ADDI,
|
137 |
|
|
HMC_SINGLE_16B_ADDI,
|
138 |
|
|
|
139 |
|
|
HMC_POSTED_WRITE_16,
|
140 |
|
|
HMC_POSTED_WRITE_32,
|
141 |
|
|
HMC_POSTED_WRITE_48,
|
142 |
|
|
HMC_POSTED_WRITE_64,
|
143 |
|
|
HMC_POSTED_WRITE_80,
|
144 |
|
|
HMC_POSTED_WRITE_96,
|
145 |
|
|
HMC_POSTED_WRITE_112,
|
146 |
|
|
HMC_POSTED_WRITE_128,
|
147 |
|
|
HMC_POSTED_BIT_WRIT,
|
148 |
|
|
|
149 |
|
|
HMC_POSTED_BIT_WRIT,
|
150 |
|
|
HMC_POSTED_DUAL_8B_ADDI,
|
151 |
|
|
HMC_POSTED_SINGLE_16B_ADDI,
|
152 |
|
|
|
153 |
|
|
HMC_MODE_READ,
|
154 |
|
|
HMC_READ_16,
|
155 |
|
|
HMC_READ_32,
|
156 |
|
|
HMC_READ_48,
|
157 |
|
|
HMC_READ_64,
|
158 |
|
|
HMC_READ_80,
|
159 |
|
|
HMC_READ_96,
|
160 |
|
|
HMC_READ_112,
|
161 |
|
|
HMC_READ_128};
|
162 |
|
|
|
163 |
|
|
bins response[] = {
|
164 |
|
|
HMC_READ_RESPONSE,
|
165 |
|
|
HMC_WRITE_RESPONSE,
|
166 |
|
|
HMC_MODE_READ_RESPONSE,
|
167 |
|
|
HMC_MODE_WRITE_RESPONSE,
|
168 |
|
|
HMC_ERROR_RESPONSE
|
169 |
|
|
};
|
170 |
|
|
illegal_bins n_used = default;
|
171 |
|
|
}
|
172 |
|
|
CROSS_ERROR_TYPPE_COMMAND : cross ERROR_TYPE, HMC_COMMAND {
|
173 |
|
|
ignore_bins SEQ_IGNORE = binsof(ERROR_TYPE) intersect {SEQ_ERROR} && binsof(HMC_COMMAND) intersect {HMC_NULL, HMC_PRET, HMC_IRTRY};
|
174 |
|
|
ignore_bins POISON_IGNORE = binsof(ERROR_TYPE) intersect {POISON} && binsof(HMC_COMMAND) intersect {HMC_NULL};
|
175 |
|
|
}
|
176 |
|
|
endgroup
|
177 |
|
|
|
178 |
|
|
|
179 |
|
|
covergroup null2_cg;
|
180 |
|
|
option.per_instance = 1;
|
181 |
|
|
NULL2_count : coverpoint null_flits_after_TS1+ null_flits_between_pkts{ //-- Link_up is reached after 32 consecutive flits
|
182 |
|
|
illegal_bins ib = {[0:31]};
|
183 |
|
|
bins minimum_amount = {32};
|
184 |
|
|
bins low_amount[] = {[33:50]};
|
185 |
|
|
bins medium_amount[] = {[51:100]};
|
186 |
|
|
bins high_amount = {[101:$]};
|
187 |
|
|
}
|
188 |
|
|
endgroup
|
189 |
|
|
|
190 |
|
|
|
191 |
|
|
covergroup hmc_packets_cg;
|
192 |
|
|
option.per_instance = 1;
|
193 |
|
|
|
194 |
|
|
NULLS_BETWEEN_PACKETS : coverpoint null_flits_between_pkts{
|
195 |
|
|
bins low_amount[] = {[0:20]};
|
196 |
|
|
bins medium_amount[] = {[21:199]};
|
197 |
|
|
bins high_amount ={[200:$]};
|
198 |
|
|
}
|
199 |
|
|
COMMAND : coverpoint collected_packet.command;
|
200 |
|
|
PAYLOAD_LENGTH : coverpoint collected_packet.duplicate_length -1{
|
201 |
|
|
bins no_payload = {0};
|
202 |
|
|
bins payload[] = {[1:8]};
|
203 |
|
|
}
|
204 |
|
|
CROSS_COMMAND_NULLS : cross COMMAND,NULLS_BETWEEN_PACKETS;
|
205 |
|
|
endgroup
|
206 |
|
|
|
207 |
|
|
|
208 |
|
|
covergroup hmc_link_cg;
|
209 |
|
|
option.per_instance = 1;
|
210 |
|
|
LINK_REVERSAL : coverpoint link_status.lane_reversed;
|
211 |
|
|
Link_WIDTH : coverpoint NUM_LANES{
|
212 |
|
|
bins half_width = {8};
|
213 |
|
|
bins full_width = {16};
|
214 |
|
|
}
|
215 |
|
|
CROSS_LANE_LINK_REVERSAL_WIDTH : cross Link_WIDTH, LINK_REVERSAL;
|
216 |
|
|
endgroup
|
217 |
|
|
|
218 |
|
|
|
219 |
|
|
covergroup tokens_cg;
|
220 |
|
|
option.per_instance = 1;
|
221 |
|
|
TOKEN_AVAILABLE : coverpoint link_status.token_count{
|
222 |
|
|
bins no_token_available = {0};
|
223 |
|
|
bins very_low_amount_available[] = {[1:9]};
|
224 |
|
|
bins low_amount_available[] = {[10:30]};
|
225 |
|
|
bins medium_amount_available[] = {[31:100]};
|
226 |
|
|
bins high_amount_available = {[101:$]};
|
227 |
|
|
}
|
228 |
|
|
FPW : coverpoint link_config.fpw {
|
229 |
|
|
bins legal_fpw[] = {2,4,6,8};
|
230 |
|
|
}
|
231 |
|
|
CROSS_FPW_TOKENS : cross FPW, TOKEN_AVAILABLE;
|
232 |
|
|
endgroup
|
233 |
|
|
|
234 |
|
|
`uvm_component_param_utils(hmc_monitor#(.NUM_LANES(NUM_LANES)))
|
235 |
|
|
|
236 |
|
|
|
237 |
|
|
function new ( string name="hmc_monitor", uvm_component parent );
|
238 |
|
|
|
239 |
|
|
super.new(name, parent);
|
240 |
|
|
|
241 |
|
|
lane_queues = new[NUM_LANES] (lane_queues);
|
242 |
|
|
|
243 |
|
|
hmc_pkt_error_cg = new();
|
244 |
|
|
hmc_packets_cg = new();
|
245 |
|
|
hmc_link_cg = new();
|
246 |
|
|
tokens_cg = new();
|
247 |
|
|
null2_cg = new();
|
248 |
|
|
|
249 |
|
|
item_collected_port = new("item_collected_port", this);
|
250 |
|
|
return_token_port = new("return_token_port", this);
|
251 |
|
|
frp_port = new("frp_port", this);
|
252 |
|
|
rrp_port = new("rrp_port", this);
|
253 |
|
|
next_sequence_num = 3'b1;
|
254 |
|
|
|
255 |
|
|
endfunction : new
|
256 |
|
|
|
257 |
|
|
function void build_phase(uvm_phase phase);
|
258 |
|
|
super.build_phase(phase);
|
259 |
|
|
|
260 |
|
|
if(uvm_config_db#(virtual interface hmc_sr_if#(.NUM_LANES(NUM_LANES)))::get(this, "", "vif",vif) ) begin
|
261 |
|
|
this.vif = vif;
|
262 |
|
|
end else begin
|
263 |
|
|
`uvm_fatal(get_type_name(),"vif is not set")
|
264 |
|
|
end
|
265 |
|
|
if(!uvm_config_db#(hmc_link_config)::get(this, "", "link_config",link_config) ) begin
|
266 |
|
|
`uvm_fatal(get_type_name(),"link_config is not set")
|
267 |
|
|
end
|
268 |
|
|
|
269 |
|
|
if(!uvm_config_db#(hmc_local_link_config)::get(this, "", "local_config",local_config) ) begin
|
270 |
|
|
`uvm_fatal(get_type_name(),"local_config is not set")
|
271 |
|
|
end
|
272 |
|
|
|
273 |
|
|
|
274 |
|
|
if(!uvm_config_db#(hmc_status)::get(this, "", "status",status) ) begin
|
275 |
|
|
`uvm_fatal(get_type_name(),"Responder_link_status is not set")
|
276 |
|
|
end
|
277 |
|
|
|
278 |
|
|
if (item_collected_port == null)
|
279 |
|
|
`uvm_fatal(get_type_name(), "uvm_analysis_port not ready")
|
280 |
|
|
|
281 |
|
|
|
282 |
|
|
start_clear_retry_event = new ("start_retry_event");
|
283 |
|
|
link_status = local_config.requester?status.Requester_link_status:status.Responder_link_status;
|
284 |
|
|
remote_link_status = (!local_config.requester)?status.Requester_link_status:status.Responder_link_status;
|
285 |
|
|
|
286 |
|
|
set_config_int("cdr", "link_type", local_config.requester?REQUESTER:RESPONDER);
|
287 |
|
|
|
288 |
|
|
cdr = hmc_cdr#(.NUM_LANES(NUM_LANES))::type_id::create("cdr", this);
|
289 |
|
|
|
290 |
|
|
// This should be a better check for the BFM.
|
291 |
|
|
if (!link_config.responder.active) begin
|
292 |
|
|
status.Responder_link_status.set_relaxed_token_handling(1);
|
293 |
|
|
end
|
294 |
|
|
|
295 |
|
|
|
296 |
|
|
endfunction : build_phase
|
297 |
|
|
|
298 |
|
|
function logic get_bit(input bit Requester, input int lane);
|
299 |
|
|
if (Requester)
|
300 |
|
|
get_bit = vif.RXP[lane];
|
301 |
|
|
else
|
302 |
|
|
get_bit = vif.TXP[lane];
|
303 |
|
|
endfunction : get_bit
|
304 |
|
|
|
305 |
|
|
function bit check_lane_queues_not_empty();
|
306 |
|
|
bit full = 1;
|
307 |
|
|
foreach (lane_queues[i]) begin
|
308 |
|
|
if (lane_queues[i].size()==0)
|
309 |
|
|
full = 0;
|
310 |
|
|
end
|
311 |
|
|
return full;
|
312 |
|
|
endfunction
|
313 |
|
|
|
314 |
|
|
task check_clock();
|
315 |
|
|
int i;
|
316 |
|
|
int start_time = 0;
|
317 |
|
|
int clock_period = 0;
|
318 |
|
|
int expected_period = 0;
|
319 |
|
|
|
320 |
|
|
`uvm_info(get_type_name(),$psprintf("started clock check %0d", $time), UVM_HIGH)
|
321 |
|
|
forever begin
|
322 |
|
|
|
323 |
|
|
if (vif.P_RST_N !== 1) // Reset
|
324 |
|
|
begin
|
325 |
|
|
@(posedge vif.P_RST_N);
|
326 |
|
|
|
327 |
|
|
// Sample REFCLK_BOOT pins
|
328 |
|
|
case (vif.REFCLK_BOOT)
|
329 |
|
|
2'b00: expected_period = 8ns; // 125 MHz
|
330 |
|
|
2'b01: expected_period = 6.4ns; // 156.25 MHz
|
331 |
|
|
2'b10: expected_period = 6ns; // 166.66 MHz
|
332 |
|
|
2'b11: `uvm_fatal(get_type_name(),$psprintf("REFCLK_BOOT setting %0d invalid!", vif.REFCLK_BOOT))
|
333 |
|
|
endcase
|
334 |
|
|
|
335 |
|
|
// Sample REFCLKP
|
336 |
|
|
@(posedge vif.REFCLKP);
|
337 |
|
|
start_time = $time;
|
338 |
|
|
|
339 |
|
|
for (i=0;i<100;i++)
|
340 |
|
|
@(posedge vif.REFCLKP);
|
341 |
|
|
clock_period = ($time-start_time)/100;
|
342 |
|
|
|
343 |
|
|
`uvm_info(get_type_name(),$psprintf("clock_period = %0d expected = %0d", clock_period, expected_period), UVM_HIGH)
|
344 |
|
|
|
345 |
|
|
if (clock_period != expected_period)
|
346 |
|
|
`uvm_fatal(get_type_name(),$psprintf("clock_period %0d (p) != expected %0d!", clock_period, expected_period));
|
347 |
|
|
|
348 |
|
|
// Sample REFCLKN
|
349 |
|
|
@(posedge vif.REFCLKN);
|
350 |
|
|
start_time = $time;
|
351 |
|
|
|
352 |
|
|
for (i=0;i<100;i++)
|
353 |
|
|
@(posedge vif.REFCLKN);
|
354 |
|
|
clock_period = ($time-start_time)/100;
|
355 |
|
|
|
356 |
|
|
if (clock_period != expected_period)
|
357 |
|
|
`uvm_fatal(get_type_name(),$psprintf("clock_period (n) %0d != expected %0d!", clock_period, expected_period));
|
358 |
|
|
|
359 |
|
|
end
|
360 |
|
|
@(negedge vif.P_RST_N);
|
361 |
|
|
end
|
362 |
|
|
endtask : check_clock
|
363 |
|
|
|
364 |
|
|
task monitor_power_pins();
|
365 |
|
|
if (local_config.requester) begin
|
366 |
|
|
link_status.signal_power_state(vif.RXPS);
|
367 |
|
|
forever begin
|
368 |
|
|
@(vif.RXPS)
|
369 |
|
|
if (vif.RXPS == 1'b0)
|
370 |
|
|
CHK_IDLE_BEFORE_REQUESTER_POWERDOWN: assert (idle_check()) //-- check if Link is IDLE
|
371 |
|
|
else begin
|
372 |
|
|
`uvm_fatal(get_type_name(),$psprintf("link is not IDLE"))
|
373 |
|
|
end
|
374 |
|
|
link_status.signal_power_state(vif.RXPS);
|
375 |
|
|
end
|
376 |
|
|
end else begin
|
377 |
|
|
link_status.signal_power_state(vif.TXPS);
|
378 |
|
|
forever begin
|
379 |
|
|
@(vif.TXPS)
|
380 |
|
|
if (vif.TXPS == 1'b0)
|
381 |
|
|
CHK_IDLE_BEFORE_RESPONDER_POWERDOWN: assert (idle_check()) //-- check if Link is IDLE
|
382 |
|
|
else begin
|
383 |
|
|
`uvm_fatal(get_type_name(),$psprintf("link is not IDLE"))
|
384 |
|
|
end
|
385 |
|
|
link_status.signal_power_state(vif.TXPS);
|
386 |
|
|
end
|
387 |
|
|
end
|
388 |
|
|
endtask : monitor_power_pins
|
389 |
|
|
|
390 |
|
|
task descramble(input int lane);
|
391 |
|
|
partial_flit_t partial_flit;
|
392 |
|
|
lsfr_t lfsr;
|
393 |
|
|
lsfr_t calculated_lfsr;
|
394 |
|
|
bit last_bit;
|
395 |
|
|
bit alligned = 0;
|
396 |
|
|
int run_length_count = 0;
|
397 |
|
|
|
398 |
|
|
`uvm_info(get_type_name(),$psprintf("%s lane %0d descrambler started", local_config.requester?"Requester":"Responder", lane), UVM_HIGH)
|
399 |
|
|
forever begin
|
400 |
|
|
if (link_status.current_state == RESET || link_status.current_state == POWER_DOWN) /*RESET*/
|
401 |
|
|
begin
|
402 |
|
|
logic test;
|
403 |
|
|
@(link_status.current_state);
|
404 |
|
|
`uvm_info(get_type_name(), "Waiting for valid bit", UVM_HIGH)
|
405 |
|
|
test = local_config.requester?vif.RXP[lane]:vif.TXP[lane];
|
406 |
|
|
while (test === 1'bz)begin
|
407 |
|
|
@(cdr.int_clk)
|
408 |
|
|
test = local_config.requester?vif.RXP[lane]:vif.TXP[lane];
|
409 |
|
|
end
|
410 |
|
|
end
|
411 |
|
|
|
412 |
|
|
else if (!link_status.get_locked(lane)) /*LOCK SCRAMBLER*/
|
413 |
|
|
begin
|
414 |
|
|
|
415 |
|
|
lfsr = calculated_lfsr;
|
416 |
|
|
//-- Guess that the top bit is 0 to lock when scrambling is turned off
|
417 |
|
|
calculated_lfsr[14] = (link_config.scramblers_enabled? 1'b1 : 1'b0);
|
418 |
|
|
for (int i=0; i<14; i++)
|
419 |
|
|
begin
|
420 |
|
|
calculated_lfsr[i] = get_bit(local_config.requester,lane) ^ last_bit;
|
421 |
|
|
last_bit = get_bit(local_config.requester,lane);
|
422 |
|
|
|
423 |
|
|
@(cdr.int_clk);
|
424 |
|
|
lfsr = {lfsr[1]^lfsr[0], lfsr[14:1]}; // step the LFSR
|
425 |
|
|
end
|
426 |
|
|
if (lane == 0)
|
427 |
|
|
`uvm_info(get_type_name(),$psprintf("%s lane 0 calculated_lfsr=%0x lfsr=%0x", local_config.requester?"Requester":"Responder", calculated_lfsr, lfsr), UVM_HIGH)
|
428 |
|
|
if (lfsr == calculated_lfsr) begin
|
429 |
|
|
/*Inversion check*/
|
430 |
|
|
if (get_bit(local_config.requester,lane) ^ lfsr[0]) begin
|
431 |
|
|
link_status.set_inverted(lane);
|
432 |
|
|
`uvm_info(get_type_name(),$psprintf("%s lane %0d is inverted", local_config.requester?"Requester":"Responder", lane),UVM_LOW)
|
433 |
|
|
end
|
434 |
|
|
Requester_locks_before_Responder : assert (local_config.requester || status.Requester_link_status.get_all_lanes_locked());
|
435 |
|
|
link_status.set_locked(lane);
|
436 |
|
|
end
|
437 |
|
|
end
|
438 |
|
|
else if (!link_status.get_nonzero(lane)) /*WAIT FOR POSSIBLE TS1 (non-zero)*/
|
439 |
|
|
begin
|
440 |
|
|
`uvm_info(get_type_name(),$psprintf("locked on %s lane %0d inverted = %0x lfsr=%0x", local_config.requester?"Requester":"Responder", lane,link_status.get_inverted(lane), lfsr), UVM_HIGH)
|
441 |
|
|
while (get_bit(local_config.requester,lane) ^ lfsr[0] ^ link_status.get_inverted(lane) == 0)
|
442 |
|
|
begin
|
443 |
|
|
lfsr = {lfsr[1]^lfsr[0], lfsr[14:1]}; //-- Every clock after lock, step the LFSR
|
444 |
|
|
@(cdr.int_clk);
|
445 |
|
|
end
|
446 |
|
|
link_status.set_nonzero(lane);
|
447 |
|
|
end
|
448 |
|
|
else if (!link_status.get_aligned(lane)) /*ALIGN WITH TS1*/
|
449 |
|
|
begin
|
450 |
|
|
|
451 |
|
|
`uvm_info(get_type_name(),$psprintf("looking for TS1 on %s lane %0d", local_config.requester?"Requester":"Responder", lane), UVM_HIGH)
|
452 |
|
|
partial_flit[7:0] = 8'hff;
|
453 |
|
|
while (!link_status.get_aligned(lane)) begin
|
454 |
|
|
//-- shift until a possible TS1 sequence is detected
|
455 |
|
|
|
456 |
|
|
partial_flit = partial_flit >> 1;
|
457 |
|
|
partial_flit[7] = get_bit(local_config.requester,lane) ^ lfsr[0] ^ link_status.get_inverted(lane);
|
458 |
|
|
lfsr = {lfsr[1]^lfsr[0], lfsr[14:1]}; //-- Every clock after lock, step the LFSR
|
459 |
|
|
@(cdr.int_clk);
|
460 |
|
|
|
461 |
|
|
if (partial_flit[7:0] == 8'hf0) begin //-- found potential TS1 sequence
|
462 |
|
|
//-- check next partial flits
|
463 |
|
|
alligned = 1;
|
464 |
|
|
for (int i = 0; i
|
465 |
|
|
//-- read next partial flit
|
466 |
|
|
for (int i=0; i<16; i++) begin
|
467 |
|
|
partial_flit[i] = get_bit(local_config.requester,lane) ^ lfsr[0] ^ link_status.get_inverted(lane);
|
468 |
|
|
lfsr = {lfsr[1]^lfsr[0], lfsr[14:1]}; // Every clock after lock, step the LFSR
|
469 |
|
|
@(cdr.int_clk);
|
470 |
|
|
end
|
471 |
|
|
`uvm_info(get_type_name(),$psprintf("partial_flit=%0x", partial_flit), UVM_HIGH)
|
472 |
|
|
if (partial_flit[15:8] != 8'hf0)begin
|
473 |
|
|
`uvm_info(get_type_name(),$psprintf("Alignment Error, retry"), UVM_NONE)
|
474 |
|
|
alligned = 0;
|
475 |
|
|
continue;//-- retry
|
476 |
|
|
end
|
477 |
|
|
if (alligned) begin
|
478 |
|
|
link_status.set_aligned(lane);
|
479 |
|
|
|
480 |
|
|
`uvm_info(get_type_name(),$psprintf("%s lane %0x aligned", local_config.requester?"Requester":"Responder", lane), UVM_HIGH)
|
481 |
|
|
end
|
482 |
|
|
end
|
483 |
|
|
end
|
484 |
|
|
end
|
485 |
|
|
run_length_count = 0;
|
486 |
|
|
end
|
487 |
|
|
else /*NORMAL OPERATION*/
|
488 |
|
|
begin
|
489 |
|
|
for (int i=0; i<16; i++)
|
490 |
|
|
begin
|
491 |
|
|
// Check Run current_packet_length limit
|
492 |
|
|
if (last_bit == get_bit(local_config.requester,lane))
|
493 |
|
|
begin
|
494 |
|
|
run_length_count = run_length_count + 1;
|
495 |
|
|
|
496 |
|
|
if ((run_length_count >= local_config.run_length_limit) && link_config.scramblers_enabled)
|
497 |
|
|
`uvm_fatal(get_type_name(),$psprintf("last_bit=%0x repeated %0d times on %s lane %0d"
|
498 |
|
|
, last_bit, run_length_count, local_config.requester?"Requester":"Responder", lane));
|
499 |
|
|
end else begin
|
500 |
|
|
run_length_count = 0;
|
501 |
|
|
last_bit = !last_bit;
|
502 |
|
|
end
|
503 |
|
|
partial_flit[i] = get_bit(local_config.requester,lane) ^ lfsr[0] ^ link_status.get_inverted(lane);
|
504 |
|
|
lfsr = {lfsr[1]^lfsr[0], lfsr[14:1]}; // Every clock after lock, step the LFSR
|
505 |
|
|
|
506 |
|
|
@(cdr.int_clk);
|
507 |
|
|
end
|
508 |
|
|
lane_queues[lane].push_back(partial_flit);
|
509 |
|
|
//-- lane_queue_event only after all partial flits present
|
510 |
|
|
if(check_lane_queues_not_empty())
|
511 |
|
|
-> lane_queue_event;
|
512 |
|
|
end
|
513 |
|
|
end
|
514 |
|
|
endtask : descramble
|
515 |
|
|
|
516 |
|
|
function void reset_link();
|
517 |
|
|
lane_reversal_set = 0;
|
518 |
|
|
link_status.lane_reversed = 0;
|
519 |
|
|
link_status.num_lanes = NUM_LANES;
|
520 |
|
|
|
521 |
|
|
link_status.reset();
|
522 |
|
|
|
523 |
|
|
bitstream = {};
|
524 |
|
|
collected_flits = {};
|
525 |
|
|
for (int i=0; i < NUM_LANES; i++) begin
|
526 |
|
|
lane_queues[i] = {};
|
527 |
|
|
end
|
528 |
|
|
endfunction :reset_link
|
529 |
|
|
|
530 |
|
|
task collect_flits();
|
531 |
|
|
|
532 |
|
|
flit_t current_flit;
|
533 |
|
|
partial_flit_t lane_flit;
|
534 |
|
|
|
535 |
|
|
`uvm_info(get_type_name(),$psprintf("starting collect_flits %s", local_config.requester? "Requester" : "Responder"), UVM_HIGH)
|
536 |
|
|
forever begin
|
537 |
|
|
if (link_status.current_state == RESET ) // Reset
|
538 |
|
|
reset_link();
|
539 |
|
|
//-- check if partial flits available
|
540 |
|
|
if (!flit_available())begin
|
541 |
|
|
@(lane_queue_event);//-- wait for any change at the lane queues and recheck flit available before reading the lane queues
|
542 |
|
|
end
|
543 |
|
|
|
544 |
|
|
//-- check TS1 sequences
|
545 |
|
|
if (link_status.current_state == TS1) begin
|
546 |
|
|
foreach (lane_queues[i]) begin
|
547 |
|
|
lane_flit = lane_queues[i].pop_front();
|
548 |
|
|
if (lane_flit != 16'b0) begin //-- while TS1 Sequence
|
549 |
|
|
case (i)
|
550 |
|
|
0: begin
|
551 |
|
|
case (lane_flit[7:4])
|
552 |
|
|
4'h3 : link_status.lane_reversed = 0;
|
553 |
|
|
4'hc : link_status.lane_reversed = 1;
|
554 |
|
|
default : if (local_config.lane_errors_enabled) begin
|
555 |
|
|
`uvm_info(get_type_name(), $psprintf("Detected invalid TS1 sequence on Lane %0d %s", i, local_config.requester?"requester":"responder"), UVM_HIGH)
|
556 |
|
|
//-- cover invalid TS1 sequence error
|
557 |
|
|
current_error = INVALID_TS1;
|
558 |
|
|
collected_packet = new();
|
559 |
|
|
void'(collected_packet.randomize() with{command == HMC_NULL;});
|
560 |
|
|
hmc_pkt_error_cg.sample();
|
561 |
|
|
end else begin
|
562 |
|
|
`uvm_fatal(get_type_name(), $psprintf("Detected invalid TS1 sequence on Lane %0d %s", i, local_config.requester?"requester":"responder"))
|
563 |
|
|
end
|
564 |
|
|
endcase
|
565 |
|
|
if (!lane_reversal_set) begin
|
566 |
|
|
`uvm_info(get_type_name(), $psprintf("%s Link is %s"
|
567 |
|
|
, local_config.requester?"Requester":"Responder"
|
568 |
|
|
, link_status.lane_reversed?"reversed":"not reversed"
|
569 |
|
|
), UVM_NONE)
|
570 |
|
|
end
|
571 |
|
|
lane_reversal_set = 1;
|
572 |
|
|
end
|
573 |
|
|
NUM_LANES-1: begin
|
574 |
|
|
case (lane_flit[7:4])
|
575 |
|
|
4'h3 : link_status.lane_reversed = 1;
|
576 |
|
|
4'hc : link_status.lane_reversed = 0;
|
577 |
|
|
default : if (local_config.lane_errors_enabled) begin
|
578 |
|
|
`uvm_info(get_type_name(), $psprintf("Detected invalid TS1 sequence on Lane %0d %s", i, local_config.requester?"requester":"responder"), UVM_HIGH)
|
579 |
|
|
end else begin
|
580 |
|
|
`uvm_fatal(get_type_name(), $psprintf("Detected invalid TS1 sequence on Lane %0d %s", i, local_config.requester?"requester":"responder"))
|
581 |
|
|
end
|
582 |
|
|
endcase
|
583 |
|
|
end
|
584 |
|
|
default: begin
|
585 |
|
|
if (local_config.lane_errors_enabled) begin
|
586 |
|
|
if (lane_flit[7:4] != 4'h5)
|
587 |
|
|
`uvm_info(get_type_name(), $psprintf("Detected invalid TS1 sequence on Lane %0d %s", i, local_config.requester?"requester":"responder"), UVM_HIGH)
|
588 |
|
|
end else begin
|
589 |
|
|
if (local_config.lane_errors_enabled) begin
|
590 |
|
|
if (lane_flit[7:4] != 4'h5)
|
591 |
|
|
`uvm_info(get_type_name(), $psprintf("Detected invalid TS1 sequence on Lane %0d %s", i, local_config.requester?"requester":"responder"), UVM_HIGH)
|
592 |
|
|
end
|
593 |
|
|
else begin
|
594 |
|
|
CHK_TS1_ID: assert (lane_flit[7:4] == 4'h5);
|
595 |
|
|
end
|
596 |
|
|
end
|
597 |
|
|
end
|
598 |
|
|
endcase
|
599 |
|
|
if (local_config.lane_errors_enabled) begin
|
600 |
|
|
if (lane_flit[15:8] != 8'hf0)
|
601 |
|
|
`uvm_info(get_type_name(), $psprintf("Detected invalid TS1 sequence on Lane %0d %s", i, local_config.requester?"requester":"responder"), UVM_HIGH)
|
602 |
|
|
end
|
603 |
|
|
else begin
|
604 |
|
|
CHK_UPPER_TS1: assert (lane_flit[15:8] == 8'hf0);
|
605 |
|
|
end
|
606 |
|
|
end
|
607 |
|
|
|
608 |
|
|
else begin
|
609 |
|
|
hmc_link_cg.sample();
|
610 |
|
|
link_status.first_null_detected = 1;
|
611 |
|
|
null_flits_after_TS1= NUM_LANES/8; //-- add 1 or 2 NULL2 Flits depending on NUM_LANES
|
612 |
|
|
end
|
613 |
|
|
end
|
614 |
|
|
end
|
615 |
|
|
else begin
|
616 |
|
|
|
617 |
|
|
for (int j = 0; j < 16; j++) begin //for each bit position in partial flit
|
618 |
|
|
for (int lane = 0; lane < NUM_LANES; lane++) begin //-- for each lane
|
619 |
|
|
bitstream.push_back(lane_queues[link_status.lane_reversed?NUM_LANES-lane-1:lane][0][j]);
|
620 |
|
|
end
|
621 |
|
|
end
|
622 |
|
|
for (int j = 0; j < 16; j++) begin
|
623 |
|
|
void'(lane_queues[j].pop_front());
|
624 |
|
|
end
|
625 |
|
|
|
626 |
|
|
while(bitstream.size()>=128) begin //-- at least 1 flit in bitstream
|
627 |
|
|
for (int k = 0; k <128; k++)
|
628 |
|
|
current_flit[k]= bitstream.pop_front();
|
629 |
|
|
|
630 |
|
|
if (link_status.current_state == NULL_FLITS_2)
|
631 |
|
|
begin
|
632 |
|
|
link_status.null_after_ts1_seen = 0;
|
633 |
|
|
if (current_flit == 128'h0)
|
634 |
|
|
begin
|
635 |
|
|
null_flits_after_TS1++;
|
636 |
|
|
if(null_flits_after_TS1 >= 32) begin
|
637 |
|
|
link_status.set_null_after_ts1();
|
638 |
|
|
end
|
639 |
|
|
`uvm_info(get_type_name(),$psprintf("null flit #%0d on %s Link",null_flits_after_TS1, local_config.requester?"Requester":"Responder"), UVM_HIGH)
|
640 |
|
|
end
|
641 |
|
|
else begin
|
642 |
|
|
if(null_flits_after_TS1 != 0)
|
643 |
|
|
if(local_config.lane_errors_enabled) begin
|
644 |
|
|
`uvm_info(get_type_name(), $psprintf("received only %d consecutive NULL Flits after TS1 sequences, got %h",null_flits_after_TS1,current_flit ), UVM_NONE)
|
645 |
|
|
null_flits_after_TS1++;
|
646 |
|
|
end
|
647 |
|
|
else begin
|
648 |
|
|
`uvm_fatal(get_type_name(), $psprintf("received only %d consecutive NULL Flits after TS1 sequences, got %h",null_flits_after_TS1,current_flit ))
|
649 |
|
|
end
|
650 |
|
|
end
|
651 |
|
|
end
|
652 |
|
|
else if (link_status.current_state == LINK_UP)
|
653 |
|
|
begin
|
654 |
|
|
collected_flits.push_back(current_flit);
|
655 |
|
|
-> flit_queue_event;
|
656 |
|
|
end
|
657 |
|
|
end
|
658 |
|
|
end
|
659 |
|
|
end
|
660 |
|
|
endtask : collect_flits
|
661 |
|
|
|
662 |
|
|
function bit check_seq_number(hmc_packet packet);
|
663 |
|
|
check_seq_number = 0;
|
664 |
|
|
if (packet.command != HMC_PRET && packet.command != HMC_IRTRY) // No sequence numbers to check in PRET
|
665 |
|
|
begin
|
666 |
|
|
if (packet.sequence_number != next_sequence_num) // Sequence error
|
667 |
|
|
begin
|
668 |
|
|
`uvm_info(get_type_name(),
|
669 |
|
|
$psprintf("%s: expected sequence number %0d, got %0d! in packet with cmd %0s, frp %0d and rrp %0d",
|
670 |
|
|
local_config.requester?"Requester":"Responder",next_sequence_num, packet.sequence_number,
|
671 |
|
|
packet.command.name(),packet.forward_retry_pointer, packet.return_retry_pointer),
|
672 |
|
|
UVM_LOW)
|
673 |
|
|
seq_error++;
|
674 |
|
|
current_error = SEQ_ERROR;
|
675 |
|
|
hmc_pkt_error_cg.sample();
|
676 |
|
|
link_status.set_error_abort_mode();
|
677 |
|
|
link_status.clear_irtry_packet_counts();
|
678 |
|
|
check_seq_number = 1;
|
679 |
|
|
end else begin
|
680 |
|
|
`uvm_info(get_type_name(), $psprintf("CMD %s with current seq_nr: %d",packet.command.name(),packet.sequence_number), UVM_HIGH)
|
681 |
|
|
next_sequence_num = packet.sequence_number + 1;
|
682 |
|
|
end
|
683 |
|
|
end
|
684 |
|
|
else // PRET & IRTRY
|
685 |
|
|
if (packet.sequence_number != 0) begin
|
686 |
|
|
`uvm_info(get_type_name(),$psprintf("%s: expected sequence number 0, got %0d! in packet with cmd %0s, frp %0d and rrp %0d",
|
687 |
|
|
local_config.requester?"Requester":"Responder",packet.sequence_number,packet.command.name(),
|
688 |
|
|
packet.forward_retry_pointer, packet.return_retry_pointer),
|
689 |
|
|
UVM_LOW)
|
690 |
|
|
|
691 |
|
|
seq_error++;
|
692 |
|
|
current_error = SEQ_ERROR;
|
693 |
|
|
hmc_pkt_error_cg.sample();
|
694 |
|
|
link_status.set_error_abort_mode();
|
695 |
|
|
link_status.clear_irtry_packet_counts();
|
696 |
|
|
check_seq_number = 1;
|
697 |
|
|
end
|
698 |
|
|
|
699 |
|
|
endfunction : check_seq_number
|
700 |
|
|
|
701 |
|
|
|
702 |
|
|
function void token_handling(hmc_packet packet);
|
703 |
|
|
|
704 |
|
|
if (!remote_link_status.relaxed_token_handling) begin
|
705 |
|
|
remote_link_status.token_count += packet.return_token_count; //-- add available token to the remote link
|
706 |
|
|
return_token_port.write(collected_packet);
|
707 |
|
|
if (local_config.requester && packet.return_token_count >0)
|
708 |
|
|
`uvm_info(get_type_name(), $psprintf("Command %s adds %0d tokens to remote, new token count = %0d",
|
709 |
|
|
packet.command.name(), packet.return_token_count,remote_link_status.token_count ),
|
710 |
|
|
UVM_HIGH)
|
711 |
|
|
|
712 |
|
|
end
|
713 |
|
|
if (!link_status.relaxed_token_handling) begin
|
714 |
|
|
if (packet.get_command_type() != HMC_FLOW_TYPE)// && !packet.poisoned) // Flow packets do not use tokens.
|
715 |
|
|
begin
|
716 |
|
|
if (!local_config.requester)
|
717 |
|
|
`uvm_info(get_type_name(), $psprintf("Tokens available: %d, used tokens: %d, new token count: %d",link_status.token_count,packet.packet_length, link_status.token_count - packet.packet_length), UVM_HIGH)
|
718 |
|
|
|
719 |
|
|
if (link_status.token_count < packet.packet_length) //--token underflow must not occur due to the token based flow control
|
720 |
|
|
`uvm_fatal(get_type_name(), $psprintf("send_to_validate: no room to push %s token_count = %0d!", packet.command.name(), link_status.token_count))
|
721 |
|
|
|
722 |
|
|
`uvm_info(get_type_name(), $psprintf("send_to_validate: push %s (length %0d) frp %0d token_count %0d new token count %0d.",
|
723 |
|
|
packet.command.name(), packet.packet_length, packet.forward_retry_pointer, link_status.token_count,
|
724 |
|
|
link_status.token_count - packet.packet_length ),
|
725 |
|
|
UVM_HIGH)
|
726 |
|
|
|
727 |
|
|
link_status.token_count -= packet.packet_length;
|
728 |
|
|
tokens_cg.sample();
|
729 |
|
|
end
|
730 |
|
|
end
|
731 |
|
|
endfunction : token_handling
|
732 |
|
|
|
733 |
|
|
function void handle_start_retry(hmc_packet packet);
|
734 |
|
|
if (packet.command == HMC_IRTRY && packet.start_retry) begin
|
735 |
|
|
|
736 |
|
|
`uvm_info(get_type_name(),$psprintf("received %d start retry IRTRYs for FRP %d",
|
737 |
|
|
link_status.get_StartRetry_packet_count(), packet.return_retry_pointer), UVM_HIGH)
|
738 |
|
|
|
739 |
|
|
if(link_status.increment_StartRetry_packet_count() >= local_config.irtry_flit_count_received_threshold) begin
|
740 |
|
|
UNEXPECTED_RETRY : assert (remote_link_status.error_abort_mode);
|
741 |
|
|
|
742 |
|
|
`uvm_info(get_type_name(),$psprintf("Start Retry Threshold Reached for RRP %d", packet.return_retry_pointer),UVM_NONE)
|
743 |
|
|
|
744 |
|
|
if (link_status.get_error_abort_mode()
|
745 |
|
|
&& link_status.irtry_StartRetry_packet_count == local_config.irtry_flit_count_received_threshold)
|
746 |
|
|
begin
|
747 |
|
|
if(remote_link_status.last_successfull_frp != packet.return_retry_pointer)begin
|
748 |
|
|
`uvm_fatal(get_type_name(), $psprintf("expecting RRP %0d, got %0d",
|
749 |
|
|
remote_link_status.last_successfull_frp, packet.return_retry_pointer))
|
750 |
|
|
end
|
751 |
|
|
rrp_port.write(packet.return_retry_pointer);
|
752 |
|
|
end
|
753 |
|
|
start_clear_retry_event.trigger();
|
754 |
|
|
end
|
755 |
|
|
end
|
756 |
|
|
else begin //-- clear start_retry counter
|
757 |
|
|
if (link_status.irtry_StartRetry_packet_count >0) begin
|
758 |
|
|
|
759 |
|
|
`uvm_info(get_type_name(),$psprintf("clearing Start Retry Counter due to a CMD %s after %0d consecutive StartRetry IRTRYs",
|
760 |
|
|
packet.command.name(), link_status.get_StartRetry_packet_count()),UVM_HIGH)
|
761 |
|
|
|
762 |
|
|
link_status.irtry_StartRetry_packet_count = 0;
|
763 |
|
|
end
|
764 |
|
|
end
|
765 |
|
|
endfunction : handle_start_retry
|
766 |
|
|
|
767 |
|
|
function void handle_error_abort_mode(hmc_packet packet);
|
768 |
|
|
|
769 |
|
|
if ((packet.clear_error_abort)) begin
|
770 |
|
|
`uvm_info(get_type_name(), $psprintf("Clear Error Abort Mode: %0d",link_status.irtry_ClearErrorAbort_packet_count ), UVM_HIGH)
|
771 |
|
|
if (link_status.increment_ClearErrorAbort_packet_count() == local_config.irtry_flit_count_received_threshold) begin
|
772 |
|
|
link_status.error_abort_mode = 0;
|
773 |
|
|
|
774 |
|
|
`uvm_info(get_type_name(), $psprintf("Clearing Error Abort Mode" ), UVM_NONE)
|
775 |
|
|
rrp_port.write(packet.return_retry_pointer); //--commit last valid RRP
|
776 |
|
|
end
|
777 |
|
|
|
778 |
|
|
end else begin
|
779 |
|
|
if(!packet.start_retry) begin
|
780 |
|
|
`uvm_info(get_type_name(),$psprintf("clearing Start Retry and Error Abort Counter due to a CMD %s", packet.command.name()),UVM_HIGH)
|
781 |
|
|
link_status.clear_irtry_packet_counts(); //-- reset counter
|
782 |
|
|
end
|
783 |
|
|
end
|
784 |
|
|
|
785 |
|
|
endfunction : handle_error_abort_mode
|
786 |
|
|
|
787 |
|
|
|
788 |
|
|
task collect_packets();
|
789 |
|
|
bit bitstream[];
|
790 |
|
|
flit_t current_flit;
|
791 |
|
|
flit_t header_flit;
|
792 |
|
|
bit [31:0] packet_crc;
|
793 |
|
|
bit [31:0] calculated_crc;
|
794 |
|
|
int unsigned current_packet_length;
|
795 |
|
|
int unsigned last_packet_length;
|
796 |
|
|
|
797 |
|
|
|
798 |
|
|
`uvm_info(get_type_name(),$psprintf("starting collect_packets "), UVM_HIGH)
|
799 |
|
|
forever begin
|
800 |
|
|
if (link_status.current_state == RESET) //-- reset handling
|
801 |
|
|
begin
|
802 |
|
|
next_sequence_num = 3'b1; //-- reset sequence number
|
803 |
|
|
packets_after_Link_up = 0;//-- reset packet counter
|
804 |
|
|
@(link_status.current_state);
|
805 |
|
|
end else
|
806 |
|
|
begin
|
807 |
|
|
if (collected_flits.size() == 0) begin //-- wait until at least one flit is available
|
808 |
|
|
@(flit_queue_event);
|
809 |
|
|
end
|
810 |
|
|
current_flit = collected_flits.pop_front(); //-- header flit
|
811 |
|
|
|
812 |
|
|
if (current_flit[5:0] == HMC_NULL) begin //-- do not forward null packets
|
813 |
|
|
null_flits_between_pkts ++;
|
814 |
|
|
if (link_status.irtry_StartRetry_packet_count >0) begin
|
815 |
|
|
`uvm_info(get_type_name(),$psprintf("clearing Start Retry Counter due to a NULL Packet after %0d consecutive StartRetry IRTRYs", link_status.get_StartRetry_packet_count()),UVM_HIGH)
|
816 |
|
|
link_status.irtry_StartRetry_packet_count = 0;
|
817 |
|
|
end
|
818 |
|
|
continue;
|
819 |
|
|
end
|
820 |
|
|
else begin
|
821 |
|
|
//-- if first packet after NULL2
|
822 |
|
|
if (packets_after_Link_up ==0)begin
|
823 |
|
|
null2_cg.sample();
|
824 |
|
|
end
|
825 |
|
|
packets_after_Link_up++;
|
826 |
|
|
end
|
827 |
|
|
|
828 |
|
|
//-- check length miss-match
|
829 |
|
|
//-- TODO: include CMD in length check
|
830 |
|
|
if (current_flit[14:11] != current_flit[10:7] || current_flit[14:11] == 0) // Length mismatch or invalid current_packet_length
|
831 |
|
|
begin
|
832 |
|
|
|
833 |
|
|
`uvm_info(get_type_name(),$psprintf("%s: current_packet_length mismatch %0x len=%0d, dln = %0d", local_config.requester?"Requester":"Responder", current_flit, current_flit[10:7], current_flit[14:11]),UVM_NONE)
|
834 |
|
|
lng_error ++;
|
835 |
|
|
current_error = LENGTH_ERROR;
|
836 |
|
|
|
837 |
|
|
collected_packet = new();
|
838 |
|
|
|
839 |
|
|
if (local_config.lane_errors_enabled)begin
|
840 |
|
|
void'(collected_packet.randomize() with{
|
841 |
|
|
command == HMC_NULL;
|
842 |
|
|
});
|
843 |
|
|
end else begin
|
844 |
|
|
void'(collected_packet.randomize() with{
|
845 |
|
|
command == hmc_command_encoding'(current_flit[5:0]);
|
846 |
|
|
});
|
847 |
|
|
end
|
848 |
|
|
hmc_pkt_error_cg.sample();
|
849 |
|
|
|
850 |
|
|
link_status.set_error_abort_mode();
|
851 |
|
|
link_status.irtry_ClearErrorAbort_packet_count = 0; //-- reset clear error abort count
|
852 |
|
|
//-- ignore packet fragments until first IRTRY
|
853 |
|
|
while ( (hmc_command_encoding'(current_flit[5:0]) != HMC_IRTRY)
|
854 |
|
|
|| (current_flit[10:7] != current_flit[14:11])
|
855 |
|
|
|| (current_flit[10:7] !=1)
|
856 |
|
|
) begin
|
857 |
|
|
if (collected_flits.size() ==0)
|
858 |
|
|
@(flit_queue_event);
|
859 |
|
|
current_flit = collected_flits.pop_front();
|
860 |
|
|
end
|
861 |
|
|
end
|
862 |
|
|
|
863 |
|
|
current_packet_length = current_flit[10:7];
|
864 |
|
|
|
865 |
|
|
`uvm_info(get_type_name(),$psprintf("%s: current_flit=%0x current_packet_length=%0d", local_config.requester?"Requester":"Responder", current_flit,current_packet_length), UVM_HIGH)
|
866 |
|
|
|
867 |
|
|
bitstream = new[current_packet_length*128];
|
868 |
|
|
|
869 |
|
|
// pack first flit
|
870 |
|
|
header_flit = current_flit;
|
871 |
|
|
for (int i=0; i<128; i=i+1)
|
872 |
|
|
bitstream[i] = current_flit[i];
|
873 |
|
|
|
874 |
|
|
// get and pack the remaining flits
|
875 |
|
|
for (int j=1; j
|
876 |
|
|
begin
|
877 |
|
|
if (collected_flits.size() == 0)
|
878 |
|
|
@(collected_flits.size());
|
879 |
|
|
|
880 |
|
|
current_flit = collected_flits.pop_front();
|
881 |
|
|
|
882 |
|
|
for (int i=0; i<128; i=i+1)
|
883 |
|
|
bitstream[j*128+i] = current_flit[i];
|
884 |
|
|
end
|
885 |
|
|
|
886 |
|
|
for (int i = 0; i <32; i++)begin
|
887 |
|
|
packet_crc[i] = bitstream[bitstream.size()-32 +i];
|
888 |
|
|
end
|
889 |
|
|
calculated_crc = collected_packet.calc_crc(bitstream);
|
890 |
|
|
|
891 |
|
|
|
892 |
|
|
if ( calculated_crc!= packet_crc && !(packet_crc == ~calculated_crc)) begin //-- check CRC
|
893 |
|
|
`uvm_info(get_type_name(), $psprintf("got a CRC error in hmc_packet %x", header_flit), UVM_NONE)
|
894 |
|
|
crc_error ++;
|
895 |
|
|
current_error = CRC_ERROR;
|
896 |
|
|
collected_packet = hmc_packet::type_id::create("collected_packet", this);
|
897 |
|
|
|
898 |
|
|
if (local_config.lane_errors_enabled)begin
|
899 |
|
|
void'(collected_packet.randomize() with{
|
900 |
|
|
command == HMC_NULL;
|
901 |
|
|
});
|
902 |
|
|
end else begin
|
903 |
|
|
void'(collected_packet.unpack(bitstream));
|
904 |
|
|
end
|
905 |
|
|
hmc_pkt_error_cg.sample();
|
906 |
|
|
|
907 |
|
|
link_status.set_error_abort_mode();
|
908 |
|
|
link_status.irtry_ClearErrorAbort_packet_count = 0; //-- reset clear error abort count
|
909 |
|
|
continue;
|
910 |
|
|
|
911 |
|
|
end
|
912 |
|
|
|
913 |
|
|
|
914 |
|
|
collected_packet = hmc_packet::type_id::create("collected_packet", this);
|
915 |
|
|
void'(collected_packet.unpack(bitstream));
|
916 |
|
|
if(collected_packet.command != HMC_IRTRY)
|
917 |
|
|
`uvm_info(get_type_name(), $psprintf("collected_packet CMD: %s FRP: %d",
|
918 |
|
|
collected_packet.command.name(), collected_packet.forward_retry_pointer), UVM_HIGH)
|
919 |
|
|
handle_start_retry(collected_packet);
|
920 |
|
|
|
921 |
|
|
if (link_status.get_error_abort_mode) begin
|
922 |
|
|
if (collected_packet.command == HMC_IRTRY)
|
923 |
|
|
void'(check_seq_number(collected_packet));
|
924 |
|
|
handle_error_abort_mode(collected_packet);
|
925 |
|
|
|
926 |
|
|
end else begin
|
927 |
|
|
|
928 |
|
|
//--check the sequence number
|
929 |
|
|
if(check_seq_number(collected_packet))
|
930 |
|
|
continue;
|
931 |
|
|
|
932 |
|
|
//-- at this point each packet should be clean
|
933 |
|
|
|
934 |
|
|
token_handling(collected_packet);
|
935 |
|
|
|
936 |
|
|
//-- commit the collected packet
|
937 |
|
|
hmc_packets_cg.sample();
|
938 |
|
|
null_flits_between_pkts = 0;
|
939 |
|
|
|
940 |
|
|
if (!link_status.get_error_abort_mode()) begin
|
941 |
|
|
rrp_port.write(collected_packet.return_retry_pointer);
|
942 |
|
|
|
943 |
|
|
end
|
944 |
|
|
|
945 |
|
|
if (collected_packet.command != HMC_PRET) begin
|
946 |
|
|
|
947 |
|
|
if (collected_packet.command != HMC_IRTRY) begin
|
948 |
|
|
frp_port.write(collected_packet);
|
949 |
|
|
link_status.last_successfull_frp = collected_packet.forward_retry_pointer;
|
950 |
|
|
|
951 |
|
|
if (collected_packet.poisoned) begin
|
952 |
|
|
|
953 |
|
|
`uvm_info(get_type_name(),$psprintf("received a poisoned %s", collected_packet.command.name()), UVM_NONE)
|
954 |
|
|
poisoned_pkt++;
|
955 |
|
|
current_error = POISON;
|
956 |
|
|
hmc_pkt_error_cg.sample();
|
957 |
|
|
|
958 |
|
|
continue;
|
959 |
|
|
end
|
960 |
|
|
|
961 |
|
|
if (collected_packet.command != HMC_TRET
|
962 |
|
|
&& !collected_packet.poisoned
|
963 |
|
|
&& collected_packet.command != HMC_IRTRY
|
964 |
|
|
) //-- send only Transaction packets
|
965 |
|
|
item_collected_port.write(collected_packet);
|
966 |
|
|
end
|
967 |
|
|
end
|
968 |
|
|
end
|
969 |
|
|
end
|
970 |
|
|
end
|
971 |
|
|
endtask : collect_packets
|
972 |
|
|
|
973 |
|
|
task link_states();
|
974 |
|
|
forever begin
|
975 |
|
|
@({vif.P_RST_N
|
976 |
|
|
,link_status.power_state
|
977 |
|
|
,link_status.all_lanes_locked
|
978 |
|
|
,link_status.all_lanes_alligned
|
979 |
|
|
,link_status.first_null_detected
|
980 |
|
|
,link_status.null_after_ts1_seen}
|
981 |
|
|
);
|
982 |
|
|
|
983 |
|
|
casex ({vif.P_RST_N
|
984 |
|
|
,link_status.power_state
|
985 |
|
|
,link_status.all_lanes_locked
|
986 |
|
|
,link_status.all_lanes_alligned
|
987 |
|
|
,link_status.first_null_detected
|
988 |
|
|
,link_status.null_after_ts1_seen})
|
989 |
|
|
6'b0xxxxx : link_status.current_state = RESET;
|
990 |
|
|
6'b10xxxx : link_status.current_state = POWER_DOWN; //-- sleep mode
|
991 |
|
|
6'b110xxx : link_status.current_state = PRBS; //-- scrambler waits for null flits
|
992 |
|
|
6'b1110xx : link_status.current_state = NULL_FLITS; //-- scrambler has detected a null flit
|
993 |
|
|
6'b11110x : link_status.current_state = TS1; //-- scrambler has detected a TS1 sequence and is in flit sync
|
994 |
|
|
6'b111110 : link_status.current_state = NULL_FLITS_2;//-- detected first NULL flits after TS1
|
995 |
|
|
6'b111111 : link_status.current_state = LINK_UP; //-- Link is UP
|
996 |
|
|
endcase
|
997 |
|
|
`uvm_info(get_type_name(),$psprintf("%s Link current State: %s \t vector: %b",
|
998 |
|
|
local_config.requester?"Requester":"Responder", link_status.current_state.name(),
|
999 |
|
|
{ vif.P_RST_N,
|
1000 |
|
|
link_status.power_state,
|
1001 |
|
|
link_status.all_lanes_locked,
|
1002 |
|
|
link_status.all_lanes_alligned,
|
1003 |
|
|
link_status.first_null_detected,
|
1004 |
|
|
link_status.null_after_ts1_seen
|
1005 |
|
|
}),UVM_LOW)
|
1006 |
|
|
if (link_status.current_state == POWER_DOWN || RESET)
|
1007 |
|
|
reset_link();
|
1008 |
|
|
end
|
1009 |
|
|
endtask : link_states
|
1010 |
|
|
|
1011 |
|
|
task run();
|
1012 |
|
|
#1;
|
1013 |
|
|
for (int i=0; i
|
1014 |
|
|
begin
|
1015 |
|
|
automatic int lane = i;
|
1016 |
|
|
fork
|
1017 |
|
|
`uvm_info(get_type_name(),$psprintf("starting descrambler for Requester lane %0d", lane), UVM_HIGH)
|
1018 |
|
|
descramble(lane);
|
1019 |
|
|
join_none
|
1020 |
|
|
end
|
1021 |
|
|
fork
|
1022 |
|
|
check_clock();
|
1023 |
|
|
monitor_power_pins();
|
1024 |
|
|
collect_flits();
|
1025 |
|
|
collect_packets();
|
1026 |
|
|
link_states();
|
1027 |
|
|
join_none
|
1028 |
|
|
|
1029 |
|
|
wait fork;
|
1030 |
|
|
endtask : run
|
1031 |
|
|
|
1032 |
|
|
|
1033 |
|
|
function bit flit_available();
|
1034 |
|
|
bit rval = 1'b1;
|
1035 |
|
|
// There is only a flit available if all lane_queues are ready
|
1036 |
|
|
|
1037 |
|
|
for (int i=0; i < NUM_LANES; i++)
|
1038 |
|
|
rval = rval && lane_queues[i].size()>0;
|
1039 |
|
|
|
1040 |
|
|
return rval;
|
1041 |
|
|
endfunction : flit_available
|
1042 |
|
|
|
1043 |
|
|
function bit idle_check();
|
1044 |
|
|
return transaction_mon.idle_check()
|
1045 |
|
|
&& (link_status.token_count == local_config.requester?link_config.rx_tokens:link_config.hmc_tokens);
|
1046 |
|
|
endfunction : idle_check
|
1047 |
|
|
|
1048 |
|
|
function void report_phase(uvm_phase phase);
|
1049 |
|
|
`uvm_info(get_type_name(),$psprintf("LNG error count %0d", lng_error), UVM_NONE)
|
1050 |
|
|
`uvm_info(get_type_name(),$psprintf("CRC error count %0d", crc_error), UVM_NONE)
|
1051 |
|
|
`uvm_info(get_type_name(),$psprintf("SEQ error count %0d", seq_error), UVM_NONE)
|
1052 |
|
|
`uvm_info(get_type_name(),$psprintf("poisoned packets %0d", poisoned_pkt), UVM_NONE)
|
1053 |
|
|
endfunction : report_phase
|
1054 |
|
|
|
1055 |
|
|
function void check_phase(uvm_phase phase);
|
1056 |
|
|
if (!idle_check())//-- TODO check that all transactions are closed
|
1057 |
|
|
`uvm_fatal(get_type_name(),$psprintf("Link is not IDLE"))
|
1058 |
|
|
endfunction : check_phase
|
1059 |
|
|
|
1060 |
|
|
endclass : hmc_monitor
|
1061 |
|
|
|
1062 |
|
|
`endif // HMC_MONITOR_SV
|