Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / verif / env / tcu / vera / classes / cluster_hdr_chkr.vr
CommitLineData
86530b38
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: cluster_hdr_chkr.vr
4// Copyright (C) 1995-2007 Sun Microsystems, Inc. All Rights Reserved
5// 4150 Network Circle, Santa Clara, California 95054, U.S.A.
6//
7// * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
8//
9// This program is free software; you can redistribute it and/or modify
10// it under the terms of the GNU General Public License as published by
11// the Free Software Foundation; version 2 of the License.
12//
13// This program is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16// GNU General Public License for more details.
17//
18// You should have received a copy of the GNU General Public License
19// along with this program; if not, write to the Free Software
20// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21//
22// For the avoidance of doubt, and except that if any non-GPL license
23// choice is available it will apply instead, Sun elects to use only
24// the General Public License version 2 (GPLv2) at this time for any
25// software where a choice of GPL license versions is made
26// available with the language indicating that GPLv2 or any later version
27// may be used, or where a choice of which version of the GPL is applied is
28// otherwise unspecified.
29//
30// Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
31// CA 95054 USA or visit www.sun.com if you need additional information or
32// have any questions.
33//
34// ========== Copyright Header End ============================================
35#include <vera_defines.vrh>
36#include "std_display_class.vrh"
37#include "ccu_top.vri"
38#include "cluster_hdr_top.vri"
39#include "ccu_clk_packet.vrh"
40#include "ccu_clks_states.vrh"
41
42class CLUSTER_hdr_chkr {
43 local string name; // name of the cluster header
44 local string dispScope; // standard display: display scope
45 local integer verbose; // 0: disable verbose mode; otherwise, enable
46
47 //---ports and classes---
48 local CLKGEN_port clkgen_port; // port of this cluster header
49 local CLKGEN_port clkgen_dr_port; // DR cluster hdr for checking DR sync locations
50 local CLKGEN_port clkgen_io_port; // IO cluster hdr for checking IO sync locations
51 local CLKGEN_port clkgen_io2x_port; // IO2X cluster hdr for checking IO2X sync locations
52 local CCU_clk_port ccu_clk_port;
53 local StandardDisplay dbg; // Standard display for printing
54 local CCU_clks_states ccu_states; // keep track CCU states
55
56 //--- vars for start/stop checker/checking----
57 local integer running; // 0: not running; otherwise, running
58 local event stop_checker_e; // triggered by stop_checker() to terminate start_checker()
59 local event stop_checking_e; // triggered by stop_checking() to terminate start_checking()
60 local event clkstop_e; // triggered when tcu_clk_stop detected
61
62 //---vars for error reporting---
63 local integer error_cnt; // Global error count. Init to 0. WARN: negative if exeed max integer
64 local integer max_error_printed; // stop print out error if num errors exceed this value
65 local integer max_debug_printed; // stop print out debug msg if debug cnt exceeds this value
66 local integer dr_sync_loc_err_cnt, dr_sync_loc_debug_cnt;
67
68 //---vars for cluster parameters---
69 local cluster_hdr_type_e hdr_type; // cluster type
70 local CCU_clk_packet clk_pkt; // clock-related paramters
71 local integer l2clk_per_nom, l2clk_per_min, l2clk_per_max; // l2clk period: nominal, min, max
72 local integer gclk_per_nom, gclk_per_min, gclk_per_max; // gclk period: nominal, min, max
73 local integer pw_dev; // deviation of l2clk pulse width (in %)
74 local integer cmpslow_sync_is_io2x; // cmp_slow_sync_en is actually io2x_sync_en (MIO block does this)
75
76 //---vars for enable/disable checking sync pulses----
77 local integer chk_cmpslow_sync, chk_slowcmp_sync; // 0: not check; otherwise, check
78 local integer chk_dr_sync, chk_io2x_sync; // 0: not check; otherwise, check
79 local integer chk_iosync_loc, chk_io2xsync_loc, chk_drsync_loc; // 0: not check; otherwise, check
80
81 //--public tasks---
82 task new(string name, StandardDisplay dbg,
83 CCU_clks_states ccu_states, cluster_hdr_type_e hdr_type,
84 CLKGEN_port clkgen_port, CLKGEN_port clkgen_dr_port,
85 CLKGEN_port clkgen_io_port, CLKGEN_port clkgen_io2x_port,
86 integer chk_cmpslow_sync,
87 integer chk_slowcmp_sync, integer chk_dr_sync,
88 integer chk_io2x_sync,
89 integer cmpslow_sync_is_io2x=0, integer start_it=1);
90 task start_checker();
91 task stop_checker();
92
93 //--control tasks---
94 local task start_checking();
95 local task stop_checking();
96 local task check_l2clk_and_sync_pulses();
97
98 //---tasks do the checks---
99 local task check_gclk_toggle();
100 local task check_gclk_freq_dutycycle();
101
102 local task check_l2clk_toggle();
103 local task check_l2clk_freq_dutycyc();
104
105 local task check_iox_sync(string sync_name);
106
107 local task check_dr_sync();
108
109 local task check_cmp_io_sync_loc(integer nchecks=5);
110 local task check_io_cmp_sync_loc(integer nchecks=5);
111 local task check_io2x_sync_loc(integer nchecks=5);
112 local task check_dr_sync_loc(integer nchecks=20);
113 local task check_next_dr_sync_loc();
114
115 //---- supporting subroutines ----
116 local task compute_expected_params();
117 local task print_error_msg(integer err_cnt, string error_msg);
118 local task print_debug_msg(integer debug_cnt, string debug_msg);
119 local function integer is_outside_min_max(integer min_val, integer value, integer max_val);
120 local function integer compute_abs(integer n);
121 local task wait_1st_posedge(string sig_name, integer timeout_val);
122}
123
124//################################################################
125//######### implementation of subroutines ###########
126//################################################################
127
128task CLUSTER_hdr_chkr::new(string name, StandardDisplay dbg,
129 CCU_clks_states ccu_states, cluster_hdr_type_e hdr_type,
130 CLKGEN_port clkgen_port, CLKGEN_port clkgen_dr_port,
131 CLKGEN_port clkgen_io_port, CLKGEN_port clkgen_io2x_port,
132 integer chk_cmpslow_sync,
133 integer chk_slowcmp_sync, integer chk_dr_sync,
134 integer chk_io2x_sync,
135 integer cmpslow_sync_is_io2x=0, integer start_it=1) {
136
137 //---from arg list---
138 this.name = name;
139 this.dbg = dbg;
140 this.ccu_states = ccu_states;
141 this.hdr_type = hdr_type;
142 this.clkgen_port = clkgen_port;
143 this.clkgen_dr_port = clkgen_dr_port;
144 this.clkgen_io_port = clkgen_io_port;
145 this.clkgen_io2x_port = clkgen_io2x_port;
146 this.chk_cmpslow_sync = chk_cmpslow_sync;
147 this.chk_slowcmp_sync = chk_slowcmp_sync;
148 this.chk_dr_sync = chk_dr_sync;
149 this.chk_io2x_sync = chk_io2x_sync;
150 this.cmpslow_sync_is_io2x = cmpslow_sync_is_io2x;
151
152 //---the rest---
153 this.dispScope = this.name;
154 this.verbose = 0; //default is disabling verbose mode
155 this.ccu_clk_port = ccu_clk_bind;
156 this.running = 0;
157 this.error_cnt = 0;
158 this.max_error_printed = 20;
159 this.max_debug_printed = 20;
160 this.dr_sync_loc_err_cnt = 0; // reset error counter
161 this.dr_sync_loc_debug_cnt = 0; // reset debug counter
162 this.clk_pkt = null; // init to illegal value
163 this.l2clk_per_nom = -1; // init to illegal value
164 this.l2clk_per_min = -1; // init to illegal value
165 this.l2clk_per_max = -1; // init to illegal value
166 this.gclk_per_nom = -1; // init to illegal value
167 this.gclk_per_min = -1; // init to illegal value
168 this.gclk_per_max = -1; // init to illegal value
169 this.pw_dev = -1; // init to illegal value
170
171 //--checking sync pulse locations---
172 this.chk_iosync_loc = 1; // by default: checkin sync locations
173 this.chk_io2xsync_loc = 1;
174 this.chk_drsync_loc = 1;
175
176 //---override if runtime options specified---
177 if (get_plus_arg(CHECK, "clstrHdrChkr_maxError=n"))
178 this.max_error_printed = get_plus_arg(NUM, "clstrHdrChkr_maxError=n");
179 if (get_plus_arg(CHECK, "clstrHdrChkr_noSyncLocChk")) {
180 this.chk_iosync_loc = 0;
181 this.chk_io2xsync_loc = 0;
182 this.chk_drsync_loc = 0;
183 }
184 if (get_plus_arg(CHECK, "clstrHdrChkr_verbose"))
185 this.verbose = 1;
186
187 //---start background threads---
188 if (start_it)
189 this.start_checker();
190}
191
192//=============================================================
193// WHAT: start the checker
194//=============================================================
195task CLUSTER_hdr_chkr::start_checker() {
196 reg bit_value;
197
198 if (this.running)
199 return; // it's already running
200 dbg.dispmon(this.dispScope, MON_INFO, "starts ...");
201 this.running = 1;
202 fork {
203 fork {
204 while (1) {
205 bit_value = ccu_clk_port.$ccu_rst_sync_stable;
206 if (bit_value !== 1'b1)
207 @(posedge ccu_clk_port.$ccu_rst_sync_stable); // Sync is stable, so start checking
208 delay(3); // avoid race condition with ccu_states.get_clk_pkt()
209 this.clk_pkt = ccu_states.get_exp_clk_pkt();
210 compute_expected_params();
211 start_checking();
212 @(negedge ccu_clk_port.$rst_ccu_pll_); // reset PLL
213 stop_checking();
214 }
215 }
216 join none
217 sync(ALL, this.stop_checker_e); // stop_checker() triggers this event
218 terminate;
219 dbg.dispmon(this.dispScope, MON_INFO, "stopped");
220 this.running = 0; // checker is not running
221 } join none
222}
223
224//=============================================================
225// WHAT: stop the checker
226//=============================================================
227task CLUSTER_hdr_chkr::stop_checker() {
228 if (this.running)
229 trigger(this.stop_checker_e); // this event terminates start_checker()
230}
231
232//=============================================================
233// Start to check
234//=============================================================
235task CLUSTER_hdr_chkr::start_checking() {
236 dbg.dispmon(this.dispScope, MON_INFO, "start checking ...");
237 fork {
238 fork
239 {
240 check_gclk_toggle();
241 }
242 {
243 check_gclk_freq_dutycycle();
244 }
245 {
246 check_l2clk_and_sync_pulses();
247 }
248 join none
249 sync(ALL, this.stop_checking_e); // stop_checking() triggers this event
250 terminate;
251 dbg.dispmon(this.dispScope, MON_INFO, "checking stopped");
252 } join none
253}
254
255//=============================================================
256// WHAT: stop checking by terminating start_checking()
257//=============================================================
258task CLUSTER_hdr_chkr::stop_checking() {
259 trigger(this.stop_checking_e); // this event terminates start_checking()
260}
261
262//=============================================================
263// WHAT: control task for start/stop checking l2clk and sync pulses
264//=============================================================
265task CLUSTER_hdr_chkr::check_l2clk_and_sync_pulses() {
266 event stop_check_l2clk_sync;
267
268 while (1) {
269 //----not checking during clock stop or cluster_arst_l----
270 while (1) {
271 if ((clkgen_port.$tcu_clk_stop__gclk == 1'b0)
272 && (clkgen_port.$cluster_arst_l__gclk == 1'b1))
273 break;
274 @(posedge clkgen_port.$gclk);
275 }
276 //----check l2clk----
277 fork { check_l2clk_toggle(); } join none
278 fork { check_l2clk_freq_dutycyc(); } join none
279 //--- check sync pulse ---
280 if (this.chk_cmpslow_sync) {
281 fork { check_iox_sync("cmp_slow_sync_en"); } join none
282 if (this.chk_iosync_loc) {
283 if (this.cmpslow_sync_is_io2x)
284 fork { check_io2x_sync_loc(); } join none
285 else
286 fork { check_cmp_io_sync_loc(); } join none
287 }
288 }
289 if (this.chk_slowcmp_sync) {
290 fork { check_iox_sync("slow_cmp_sync_en"); } join none
291 if (this.chk_iosync_loc)
292 fork { check_io_cmp_sync_loc(); } join none
293 }
294 if (this.chk_io2x_sync) {
295 fork { check_iox_sync("io2x_sync_en"); } join none
296 if (this.chk_io2xsync_loc)
297 fork { check_io2x_sync_loc(); } join none
298 }
299 if (this.chk_dr_sync) {
300 fork { check_dr_sync(); } join none
301 if (this.chk_drsync_loc)
302 fork { check_dr_sync_loc(); } join none
303 }
304 //--- stop checking when tcu_clk_stop or scan_en asserted---
305 fork {
306 @(posedge clkgen_port.$tcu_clk_stop__gclk or negedge clkgen_port.$cluster_arst_l__gclk);
307 trigger(stop_check_l2clk_sync);
308 } join none
309 sync(ALL, stop_check_l2clk_sync);
310 terminate;
311 }
312}
313
314//=============================================================
315// Compute expected values for this checker
316//=============================================================
317task CLUSTER_hdr_chkr::compute_expected_params() {
318
319 //---compute l2clk period---
320 case (this.hdr_type) {
321 CLUSTER_HDR_CMP, CLUSTER_HDR_CMP1 : {
322 this.l2clk_per_nom = clk_pkt.cmp_clk_per_nom;
323 this.l2clk_per_min = clk_pkt.cmp_clk_per_min;
324 this.l2clk_per_max = clk_pkt.cmp_clk_per_max;
325 }
326 CLUSTER_HDR_DR : {
327 this.l2clk_per_nom = clk_pkt.dr_clk_per_nom;
328 this.l2clk_per_min = clk_pkt.dr_clk_per_min;
329 this.l2clk_per_max = clk_pkt.dr_clk_per_max;
330 }
331 CLUSTER_HDR_IO : {
332 this.l2clk_per_nom = clk_pkt.io_out_per_nom;
333 this.l2clk_per_min = clk_pkt.io_out_per_min;
334 this.l2clk_per_max = clk_pkt.io_out_per_max;
335 }
336 CLUSTER_HDR_IO2X : {
337 this.l2clk_per_nom = clk_pkt.io2x_out_per_nom;
338 this.l2clk_per_min = clk_pkt.io2x_out_per_min;
339 this.l2clk_per_max = clk_pkt.io2x_out_per_max;
340 }
341 default:
342 dbg.dispmon(this.dispScope, MON_ERR, psprintf("%0d is illegal value for hdr type", hdr_type));
343 }
344 //---compute gclk period and pw_dev---
345 if (hdr_type == CLUSTER_HDR_DR) {
346 this.gclk_per_nom = clk_pkt.dr_clk_per_nom;
347 this.gclk_per_min = clk_pkt.dr_clk_per_min;
348 this.gclk_per_max = clk_pkt.dr_clk_per_max;
349 this.pw_dev = clk_pkt.dr_pw_dev;
350 }
351 else { // cmp/io/io2x header
352 this.gclk_per_nom = clk_pkt.cmp_clk_per_nom;
353 this.gclk_per_min = clk_pkt.cmp_clk_per_min;
354 this.gclk_per_max = clk_pkt.cmp_clk_per_max;
355 this.pw_dev = clk_pkt.cmp_pw_dev;
356 }
357}
358
359//=============================================================
360// WHAT: check gclk is toggles in every 1.5 ccu.dr_pll_clk (for DR
361// cluster hdr) or ccu.cmp_pll_clk (for other cluster hdrs)
362// ASSUMPTION: ccu.cmp_pll_clk and ccu.dr_pll_clk clocks toggle.
363// NOTE: ccu generates sync_stable from gclk, so gclk must toggle
364//=============================================================
365task CLUSTER_hdr_chkr::check_gclk_toggle() {
366 integer old_cyc, new_cyc, ncycs; // gclk cycle counts
367 string ref_clk_name;
368 integer err_cnt=0, debug_cnt=0; // error count
369
370 dbg.dispmon(this.dispScope, MON_INFO, "monitor: gclk toggles");
371 case (this.hdr_type) {
372 CLUSTER_HDR_DR: {
373 ref_clk_name = "ccu.dr_pll_clk";
374 @(posedge ccu_clk_port.$dr_pll_clk);
375 }
376 default: {
377 ref_clk_name = "ccu.cmp_pll_clk";
378 @(posedge ccu_clk_port.$cmp_pll_clk);
379 }
380 }
381 old_cyc = get_cycle(clkgen_port.$gclk);
382 while (1) {
383 case (this.hdr_type) {
384 CLUSTER_HDR_DR: repeat (3) @(ccu_clk_port.$dr_pll_clk); // 1.5 clk cycles
385 default: repeat (3) @(ccu_clk_port.$cmp_pll_clk); // 1.5 clk cycles
386 }
387 new_cyc = get_cycle(clkgen_port.$gclk);
388 ncycs = new_cyc - old_cyc;
389 if (is_outside_min_max(1, ncycs, 2))
390 print_error_msg(err_cnt++, psprintf("check_gclk_toggle: num gclk clks in 1.5 %s clk cycles: %0d. Expect: 1 or 2", ref_clk_name, ncycs));
391 old_cyc = new_cyc;
392 }
393}
394
395//=============================================================
396// WHAT: check gclk period and duty cycle.
397// NOTE: gclk should be stable when ccu_rst_sync_stable asserted.
398//=============================================================
399task CLUSTER_hdr_chkr::check_gclk_freq_dutycycle() {
400 integer per; // gclk period
401 integer pw_hi, pw_lo, pw_min, pw_nom, pw_max; // gclk pulse width.
402 integer pos_edge, neg_edge; // clk posedge and negedge
403 integer per_err_cnt = 0, pw_err_cnt=0; // error counts
404 integer debug_cnt=0; // debug msg counts
405
406 dbg.dispmon(this.dispScope, MON_INFO, psprintf("monitor: gclk period (min=%0d, max=%0d) and duty cycle", this.gclk_per_min, this.gclk_per_max));
407 @(posedge clkgen_port.$gclk);
408 pos_edge = get_time(LO);
409 while (1) {
410 @(negedge clkgen_port.$gclk);
411 neg_edge = get_time(LO);
412 pw_hi = neg_edge - pos_edge;
413 @(posedge clkgen_port.$gclk);
414 pos_edge = get_time(LO);
415 pw_lo = pos_edge - neg_edge;
416 per = pw_hi + pw_lo;
417 pw_nom = per / 2; // nominal is 50% duty cycle
418 pw_min = (pw_nom - 1) - (((this.gclk_per_nom / 100) + 1) * this.pw_dev); // rounding down
419 pw_max = (pw_nom + 1) + (((this.gclk_per_nom / 100) + 1) * this.pw_dev); // rounding up
420 if (is_outside_min_max(this.gclk_per_min, per, this.gclk_per_max))
421 print_error_msg(per_err_cnt++, psprintf("check_gclk_freq_pw: gclk: period=%0d, expect: min=%0d, max=%0d", per, this.gclk_per_min, this.gclk_per_max));
422 if (is_outside_min_max(pw_min, pw_lo, pw_max) || is_outside_min_max(pw_min, pw_hi, pw_max))
423 print_error_msg(pw_err_cnt++, psprintf("check_gclk_freq_pw: gclk: pw_hi=%0d, pw_lo=%0d. expect: pw_min=%0d, pw_max=%0d",
424 pw_hi, pw_lo, pw_min, pw_max));
425 if (this.verbose)
426 print_debug_msg(debug_cnt++, psprintf("check_gclk_freq_pw: gclk: per=%0d, pw_hi=%0d, pw_lo=%0d. expect: per_min=%0d, per_max=%0d, pw_min=%0d, pw_max=%0d",
427 per, pw_hi, pw_lo, this.gclk_per_min, this.gclk_per_max, pw_min, pw_max));
428 }
429}
430
431//=============================================================
432// WHAT: check l2clk toggles in each gclk (for cmp and dr headers),
433// every clk_pkt.cmp2io_ratio gclk (for IO header) or every
434// clk_pkt.cmp2io2x_ratio gclk (for IO2X header)
435//=============================================================
436task CLUSTER_hdr_chkr::check_l2clk_toggle() {
437 integer gclk_ncycs; // number of gclk cycles that l2clk toggles once
438 integer old_cyc, new_cyc, ncycs; // cycle count of l2clk
439 integer err_cnt=0, debug_cnt=0;
440
441 case (this.hdr_type) { // note: +1 is needed in case clk edges are perfectly aligned.
442 CLUSTER_HDR_IO: gclk_ncycs = clk_pkt.cmp2io_ratio + 1; // gclk is cmp clk and l2clk is IO clk
443 CLUSTER_HDR_IO2X: gclk_ncycs = clk_pkt.cmp2io2x_ratio + 1; // gclk is cmp clk and l2clk is IO2X clk
444 default: gclk_ncycs = 1 + 1; // gclk is cmp clk or dr clk
445 }
446 dbg.dispmon(this.dispScope, MON_INFO, psprintf("monitor: l2clk toggles at least once for every %0d gclk cycles", gclk_ncycs));
447
448 //---wait for first l2clk---
449 wait_1st_posedge("l2clk", 10 * gclk_ncycs); // timeout in gclk cycs
450
451 //--- checking ---
452 @(posedge clkgen_port.$gclk);
453 old_cyc = get_cycle(clkgen_port.$l2clk);
454 while (1) {
455 repeat (gclk_ncycs) @(posedge clkgen_port.$gclk);
456 new_cyc = get_cycle(clkgen_port.$l2clk);
457 ncycs = new_cyc - old_cyc;
458 if (is_outside_min_max(1, ncycs, 2))
459 print_error_msg(err_cnt++, psprintf("check_l2clk_toggle: num l2clk clk in %0d gclk: %0d. Expect: 1 or 2", gclk_ncycs, ncycs));
460 else if (this.verbose)
461 print_debug_msg(debug_cnt++, psprintf("check_l2clk_toggle: num l2clk clk in %0d gclk: %0d. Expect: 1 or 2", gclk_ncycs, ncycs));
462 old_cyc = new_cyc;
463 }
464}
465
466//=============================================================
467// WHAT: check freq and duty cycle of l2clk.
468//=============================================================
469task CLUSTER_hdr_chkr::check_l2clk_freq_dutycyc() {
470 integer clk_posedge, clk_negedge, period; // l2clk
471 integer pw_hi, pw_lo, pw_nom, pw_min, pw_max; // pw: pulse width
472 integer per_err_cnt=0, pw_err_cnt=0; // error counts in period or pulse width
473 integer debug_cnt=0;
474
475 dbg.dispmon(this.dispScope, MON_INFO, psprintf("monitor: l2clk period (min=%0d, max=%0d) and duty cycle", this.l2clk_per_min, this.l2clk_per_max));
476 @(posedge clkgen_port.$l2clk); // wait for first l2clk
477 clk_posedge = get_time(LO);
478 while (1) {
479 @(negedge clkgen_port.$l2clk);
480 clk_negedge = get_time(LO);
481 pw_hi = clk_negedge - clk_posedge;
482
483 @(posedge clkgen_port.$l2clk);
484 clk_posedge = get_time(LO);
485 pw_lo = clk_posedge - clk_negedge;
486 period = pw_hi + pw_lo;
487
488 pw_nom = period / 2; // nominal is 50% duty cycle
489 pw_min = (pw_nom - 1) - (((this.l2clk_per_nom / 100) + 1) * this.pw_dev); // rounding down
490 pw_max = (pw_nom + 1) + (((this.l2clk_per_nom / 100) + 1) * this.pw_dev); // rounding down
491
492 if (is_outside_min_max(this.l2clk_per_min, period, this.l2clk_per_max))
493 print_error_msg(per_err_cnt++, psprintf("check_l2clk_freq_pw: l2clk: period=%0d, expected: min=%0d, max=%0d", period, this.l2clk_per_min, this.l2clk_per_max));
494 if (is_outside_min_max(pw_min, pw_hi, pw_max) || is_outside_min_max(pw_min, pw_lo, pw_max))
495 print_error_msg(pw_err_cnt++, psprintf("check_l2clk_freq_pw: l2clk duty cycle: pw_hi=%0d, pw_lo=%0d, expected: min=%0d, max=%0d (per=%0d)",
496 pw_hi, pw_lo, pw_min, pw_max, period));
497 if (this.verbose)
498 print_debug_msg(debug_cnt++, psprintf("check_l2clk_freq_pw: l2clk: per: %0d. Expect: min=%0d, max=%0d. pw_hi=%0d, pw_lo=%0d. Expect: min=%0d, max=%0d",
499 period, this.l2clk_per_min, this.l2clk_per_max, pw_hi, pw_lo, pw_min, pw_max));
500 }
501}
502
503//=============================================================
504// WHAT: check IO and IO2x sync pulse
505// -there is one sync pulse in each IO/IO2X clk cycle
506// -sync pulse is one cmp clk
507// -next sync pulse is separated from prev sync pulse by one IO/IO2X clk cycle.
508// ARGs: sync_name must be "cmp_slow_sync_en", "slow_cmp_sync_en" or "io2x_sync_en"
509// WARNING: this task does NOT check sync pulse locations
510//=============================================================
511task CLUSTER_hdr_chkr::check_iox_sync(string sync_name) {
512 integer cmp2slowclk_ratio; // cmp-to-io or cmp-to-io2x clk ratio
513 integer ncycs_no_sync; // number of l2clk cycs that sync is low
514 integer err_cnt = 0, debug_cnt = 0, i;
515 bit sync_val;
516 string special_note = ((sync_name == "cmp_slow_sync_en") && (this.cmpslow_sync_is_io2x))? "(actually is IO2X sync)" : "";
517
518 case (sync_name) {
519 "cmp_slow_sync_en": {
520 if (this.cmpslow_sync_is_io2x) cmp2slowclk_ratio = clk_pkt.cmp2io2x_ratio; // cmp_slow_sync_en is io2x sync
521 else cmp2slowclk_ratio = clk_pkt.cmp2io_ratio;
522 }
523 "slow_cmp_sync_en": cmp2slowclk_ratio = clk_pkt.cmp2io_ratio;
524 "io2x_sync_en": cmp2slowclk_ratio = clk_pkt.cmp2io2x_ratio;
525 default: {
526 dbg.dispmon(this.dispScope, MON_ERR, psprintf("CLUSTER_hdr_chkr::check_iox_sync(sync_name=%s) <= bad arg", sync_name));
527 this.error_cnt++;
528 return; // ignore
529 }
530 }
531 ncycs_no_sync = cmp2slowclk_ratio - 1;
532 dbg.dispmon(this.dispScope, MON_INFO, psprintf("monitor: %s %s: 1 sync pulse in %0d l2clk cycs", sync_name, special_note, cmp2slowclk_ratio));
533
534 //--wait for first sync pulse---
535 wait_1st_posedge(sync_name, 10 * cmp2slowclk_ratio ); // timeout in gclks
536 dbg.dispmon(this.dispScope, MON_INFO, psprintf("check_iox_sync: first %s <= WARNING: not checking", sync_name));
537 wait_1st_posedge(sync_name, 2 * cmp2slowclk_ratio ); // timeout in gclks
538 dbg.dispmon(this.dispScope, MON_INFO, psprintf("check_iox_sync: this %s pulse is used as reference data point", sync_name));
539 //--check sync pulse----
540 while (1) {
541 for (i = 0; i < ncycs_no_sync; i++) {
542 @(posedge clkgen_port.$l2clk);
543 case (sync_name) {
544 "cmp_slow_sync_en": sync_val = clkgen_port.$cmp_slow_sync_en__l2clk;
545 "slow_cmp_sync_en": sync_val = clkgen_port.$slow_cmp_sync_en__l2clk;
546 "io2x_sync_en": sync_val = clkgen_port.$io2x_sync_en__l2clk;
547 }
548 if (sync_val !== 1'b0)
549 print_error_msg(err_cnt++, psprintf("check_iox_sync: %s %s is %b. Expect: low", sync_name, special_note, sync_val));
550 }
551 @(posedge clkgen_port.$l2clk);
552 case (sync_name) {
553 "cmp_slow_sync_en": sync_val = clkgen_port.$cmp_slow_sync_en__l2clk;
554 "slow_cmp_sync_en": sync_val = clkgen_port.$slow_cmp_sync_en__l2clk;
555 "io2x_sync_en": sync_val = clkgen_port.$io2x_sync_en__l2clk;
556 }
557 if (sync_val !== 1'b1)
558 print_error_msg(err_cnt++, psprintf("check_iox_sync: %s %s is %b. Expect: high", sync_name, special_note, sync_val));
559 else if (this.verbose)
560 print_debug_msg(debug_cnt++, psprintf("check_iox_sync: %s %s is %b. Expect: high", sync_name, special_note, sync_val));
561 }
562}
563
564//=============================================================
565// WHAT: check dr_sync_en
566// -DR sync pulse width is one cmp clk cycle
567// -Number of DR sync pulses in 1.5 DR clk cycles is 1 or 2
568// WARN: this task does NOT check DR sync locations.
569//=============================================================
570task CLUSTER_hdr_chkr::check_dr_sync() {
571 integer err_cnt=0, debug_cnt=0;
572 integer old_sync_cnt, new_sync_cnt, temp_sync_cnt, num_sync; // counts of number of sync pulses
573 integer sync_cnt;
574
575 wait_1st_posedge("dr_sync_en", 30); // timeout after 30 gclks
576 @(posedge clkgen_port.$dr_sync_en__l2clk); // skip the 1st sync since sync_en can be during clk stop (ie. WMR)
577 dbg.dispmon(this.dispScope, MON_INFO, "check_dr_sync: first dr_sync_en used as reference data point");
578 //--- check dr_sync_en width is one cmp clk ---
579 fork {
580 while (1) {
581 @(posedge clkgen_port.$l2clk);
582 if (clkgen_port.$dr_sync_en__l2clk != 1'b0)
583 print_error_msg(err_cnt++, "check_dr_sync: dr_sync_en is high for more than one cmp cycle");
584 @(posedge clkgen_port.$dr_sync_en__l2clk); // cmp posedge at which dr_sync is high
585 }
586 } join none
587 //--- increment counter for every dr_sync pulse---
588 sync_cnt = 1; // first sync pulse counted
589 fork {
590 while (1) {
591 @(posedge clkgen_port.$dr_sync_en__l2clk);
592 sync_cnt++;
593 }
594 } join none
595 //--- check number of dr_sync pulses in 1 dr clk + 0.5 cmp clk---
596 @(posedge clkgen_dr_port.$l2clk);
597 old_sync_cnt = sync_cnt;
598 while (1) {
599 @(posedge clkgen_dr_port.$l2clk);
600 temp_sync_cnt = sync_cnt;
601 repeat (2) @(clkgen_port.$l2clk); // repeat (1): not work for div2_eff is 9
602 new_sync_cnt = sync_cnt;
603 num_sync = new_sync_cnt - old_sync_cnt;
604 if (is_outside_min_max(1, num_sync, 2))
605 print_error_msg(err_cnt++, psprintf("check_dr_sync: number of dr_sync_en pulses in 1 DR clk + 1 cmp clk: %0d. Expect: 1 or 2", num_sync));
606 else if (this.verbose)
607 print_debug_msg(debug_cnt++, psprintf("check_dr_sync: number of dr_sync_en pulses in 1 DR clk + 1 cmp clk: %0d. Expect: 1 or 2", num_sync));
608 old_sync_cnt = temp_sync_cnt;
609 }
610}
611
612//############################################################################
613//############################################################################
614//#### tasks to check sync pulse locations ####################
615//############################################################################
616//############################################################################
617
618//=============================================================
619// WHAT: check locations of cmp_io_sync_en
620// WARNING: do NOT use this task for MIO cmp hdrs since cmp_slow_sync_en is IO2X sync.
621// Use check_io2x_sync_loc() instead.
622//=============================================================
623task CLUSTER_hdr_chkr::check_cmp_io_sync_loc(integer nchecks=10) {
624 integer err_cnt=0, debug_cnt=0;
625 reg sync_value;
626 integer i;
627 integer sync_time=0, clk_edge, old_clk_edge=0, clk_mid;
628 integer sync_loc_dev; // deviation in sync pulse location
629
630 if (this.cmpslow_sync_is_io2x) // call wrong task
631 check_io2x_sync_loc(nchecks); // do a favor here
632
633 //---wait for first IO sync, cmp clk and IO clk---
634 fork {
635 @(clkgen_port.$cmp_slow_sync_en__l2clk); // wait for first IO sync pulse
636 }
637 {
638 @(posedge clkgen_port.$l2clk); // wait for first cmp clk
639 }
640 {
641 @(posedge clkgen_io_port.$l2clk); // wait for first IO l2clk
642 } join
643 dbg.dispmon(this.dispScope, MON_INFO, psprintf("checking sync pulse locations of cmp_slow_sync_en ..."));
644 //----check sync location for DTM mode -----
645 if (this.clk_pkt.mode == CCU_DTM_MODE) {
646 sync_loc_dev = this.clk_pkt.cmp_clk_per_nom;
647 fork {
648 while (1) {
649 @(posedge clkgen_port.$cmp_slow_sync_en__l2clk);
650 @(posedge clkgen_port.$l2clk);
651 sync_time = get_time(LO); // at flop header
652 }
653 } join none
654 @(posedge clkgen_io_port.$l2clk);
655 old_clk_edge = get_time(LO);
656 for (i = 0; i < nchecks; i++) {
657 @(posedge clkgen_io_port.$l2clk);
658 clk_edge = get_time(LO);
659 clk_mid = (clk_edge + old_clk_edge) / 2;
660 if (compute_abs(sync_time - clk_mid) > sync_loc_dev)
661 print_error_msg(err_cnt++, psprintf("sync location check: middle of IO l2clk: %0d, cmp_slow sync pulse at flop input: %0d <= more than %0d", clk_mid, sync_time, sync_loc_dev));
662 else if (this.verbose)
663 print_debug_msg(debug_cnt++, psprintf("sync location check: middle of IO l2clk: %0d, cmp_slow sync pulse at flop input: %0d", clk_mid, sync_time));
664 old_clk_edge = clk_edge;
665 }
666 }
667 else {
668 //---check io sync locations---
669 for (i = 0; i < nchecks; i++) {
670 @(negedge clkgen_io_port.$l2clk); // falling edge of iol2clk
671 repeat (2) @(negedge clkgen_port.$l2clk); // skip 2 cmp clk falling edges
672 @(posedge clkgen_port.$l2clk); // cmp clk rising edge
673 sync_value = clkgen_port.$cmp_slow_sync_en__l2clk;
674 if (sync_value !== 1'b1)
675 print_error_msg(err_cnt++, psprintf("sync location check: cmp_slow_sync_en is %b. Expect: high", sync_value));
676 else if (this.verbose)
677 print_debug_msg(debug_cnt++, psprintf("sync location check: cmp_slow_sync_en is %b. Expect: high", sync_value));
678 }
679 }
680}
681
682//=============================================================
683// WHAT: check locations of io_cmp_sync_en
684//=============================================================
685task CLUSTER_hdr_chkr::check_io_cmp_sync_loc(integer nchecks=10) {
686 integer err_cnt=0, debug_cnt=0;
687 reg sync_value;
688 integer i;
689 integer sync_time=0, clk_edge, old_clk_edge=0, clk_mid;
690 integer sync_loc_dev; // deviation in sync pulse location
691 integer sync_at_phase; // phase at which sync pulse is high
692
693 //---wait for first IO sync, cmp clk and IO clk---
694 fork {
695 @(clkgen_port.$slow_cmp_sync_en__l2clk); // wait for first IO sync pulse
696 }
697 {
698 @(posedge clkgen_port.$l2clk); // wait for first cmp clk
699 }
700 {
701 @(posedge clkgen_io_port.$l2clk); // wait for first IO l2clk
702 } join
703 dbg.dispmon(this.dispScope, MON_INFO, psprintf("checking sync pulse locations of slow_cmp_sync_en ..."));
704 //----check sync location for DTM mode -----
705
706//if (this.clk_pkt.mode == CCU_DTM_MODE) { //!!!! WARNING: this is OLD when cmp_slow/slow_cmp sync are at same locations
707// sync_loc_dev = this.clk_pkt.cmp_clk_per_nom;
708// fork {
709// while (1) {
710// @(posedge clkgen_port.$slow_cmp_sync_en__l2clk);
711// @(posedge clkgen_port.$l2clk);
712// sync_time = get_time(LO); // at flop header
713// }
714// } join none
715// @(posedge clkgen_io_port.$l2clk);
716// old_clk_edge = get_time(LO);
717// for (i = 0; i < nchecks; i++) {
718// @(posedge clkgen_io_port.$l2clk);
719// clk_edge = get_time(LO);
720// clk_mid = (clk_edge + old_clk_edge) / 2;
721// if (compute_abs(sync_time - clk_mid) > sync_loc_dev) {
722// print_error_msg(err_cnt++, psprintf("sync location check: middle of IO l2clk: %0d, slow_cmp sync pulse at flop input: %0d <= more than %0d",
723// clk_mid, sync_time, sync_loc_dev));
724// }
725// old_clk_edge = clk_edge;
726// }
727//}
728 if (this.clk_pkt.mode == CCU_DTM_MODE) {
729 sync_at_phase = this.clk_pkt.cmp2io_ratio - 2; // at flop input: sync is high 1 clk before next IO clk posedge
730 for (i = 0; i < nchecks; i++) { // so, atclkgen output, sync is high 2 clks before next IO clk posedge
731 @(posedge clkgen_io_port.$l2clk);
732 @(negedge clkgen_port.$l2clk);
733 repeat (sync_at_phase) @(posedge clkgen_port.$l2clk);
734 sync_value = clkgen_port.$slow_cmp_sync_en__l2clk;
735 if (sync_value !== 1'b1)
736 print_error_msg(err_cnt++, psprintf("sync location check: slow_cmp sync pulse is %b, expect: high", sync_value));
737 else if (this.verbose)
738 print_debug_msg(debug_cnt++, psprintf("sync location check: slow_cmp sync pulse is %b, expect: high", sync_value));
739 }
740 }
741 else {
742 //---check io sync locations----
743 for (i = 0; i < nchecks; i++) {
744 @(posedge clkgen_io_port.$l2clk);
745 repeat (2) @(negedge clkgen_port.$l2clk); // skip 2 cmp clk falling edges
746 @(posedge clkgen_port.$l2clk); // cmp clk rising edge
747 sync_value = clkgen_port.$slow_cmp_sync_en__l2clk;
748 if (sync_value !== 1'b1)
749 print_error_msg(err_cnt++, psprintf("sync location check: slow_cmp_sync_en is %b. Expect: high", sync_value));
750 else if (this.verbose)
751 print_debug_msg(debug_cnt++, psprintf("sync location check: slow_cmp_sync_en is %b. Expect: high", sync_value));
752 }
753 }
754}
755
756//=============================================================
757// WHAT: check locations of IO2X sync pulse
758// WARNING: cmp_slow_sync_en of MIO cmp clusters is IO2X sync en
759//=============================================================
760task CLUSTER_hdr_chkr::check_io2x_sync_loc(integer nchecks=10) {
761 integer err_cnt=0, debug_cnt=0;
762 reg sync_value;
763 integer i;
764 string special_note = (this.cmpslow_sync_is_io2x)? "(actually is IO2X sync)" : "";
765 string sync_name = (this.cmpslow_sync_is_io2x)? "cmp_slow_sync_en" : "io2x_sync_en";
766 integer sync_time=0, clk_edge, old_clk_edge=0, clk_mid;
767 integer sync_loc_dev; // deviation in sync pulse location
768
769 //---wait for first IO2X sync, cmp clk and IO2X clk---
770 fork {
771 if (this.cmpslow_sync_is_io2x)
772 @(posedge clkgen_port.$cmp_slow_sync_en__l2clk);
773 else
774 @(posedge clkgen_port.$io2x_sync_en__l2clk); // wait for first IO2X sync pulse
775 }
776 {
777 @(posedge clkgen_port.$l2clk); // wait for first cmp clk
778 }
779 {
780 @(posedge clkgen_io2x_port.$l2clk); // wait for first IO2X l2clk
781 } join
782 dbg.dispmon(this.dispScope, MON_INFO, psprintf("checking sync pulse locations of %s %s...", sync_name, special_note));
783 //----check sync location for DTM mode -----
784 if (this.clk_pkt.mode == CCU_DTM_MODE) {
785 sync_loc_dev = this.clk_pkt.cmp_clk_per_nom;
786 fork {
787 while (1) {
788 if (this.cmpslow_sync_is_io2x)
789 @(posedge clkgen_port.$cmp_slow_sync_en__l2clk);
790 else
791 @(posedge clkgen_port.$io2x_sync_en__l2clk);
792 @(posedge clkgen_port.$l2clk);
793 sync_time = get_time(LO); // at flop header
794 }
795 } join none
796 @(posedge clkgen_io2x_port.$l2clk);
797 old_clk_edge = get_time(LO);
798 for (i = 0; i < nchecks; i++) {
799 @(posedge clkgen_io2x_port.$l2clk);
800 clk_edge = get_time(LO);
801 clk_mid = (clk_edge + old_clk_edge) / 2;
802 if (compute_abs(sync_time - clk_mid) > sync_loc_dev)
803 print_error_msg(err_cnt++, psprintf("sync location check: middle of IO2X l2clk: %0d, io2x sync pulse at flop input: %0d <= more than %0d", clk_mid, sync_time, sync_loc_dev));
804 else if (this.verbose)
805 print_debug_msg(debug_cnt++, psprintf("sync location check: middle of IO2X l2clk: %0d, io2x sync pulse at flop input: %0d", clk_mid, sync_time));
806 old_clk_edge = clk_edge;
807 }
808 }
809 else {
810 //--- check io2x_sync_en location---
811 for (i = 0; i < nchecks; i++) {
812 @(negedge clkgen_io2x_port.$l2clk); // falling edge of io2x l2clk
813 @(negedge clkgen_port.$l2clk); // falling edge of cmp clk
814 @(posedge clkgen_port.$l2clk); // rising edge of cmp clk. Sync pulse should be high
815 if (this.cmpslow_sync_is_io2x)
816 sync_value = clkgen_port.$cmp_slow_sync_en__l2clk;
817 else
818 sync_value = clkgen_port.$io2x_sync_en__l2clk;
819 if (sync_value !== 1'b1)
820 print_error_msg(err_cnt++, psprintf("sync location check: %s %s is %b. Expect: high", sync_name, special_note, sync_value));
821 else if (this.verbose)
822 print_debug_msg(debug_cnt++, psprintf("sync location check: %s %s is %b. Expect: high", sync_name, special_note, sync_value));
823 }
824 }
825}
826
827//=============================================================
828// WHAT: check expected DR sync location at the flop input. DR sync
829// is flopped once after clkgen output.
830// HOW: the expected location of dr sync pulse is the cmp clk posedge
831// that is closet to the mid point of dr clk cycle (ie. delta). Since
832// the dr and cmp clk edges can shift a little, so testbench needs to
833// check the actual delta vs. (delta_min plus 1/3 of cmp clk cycle).
834//=============================================================
835task CLUSTER_hdr_chkr::check_dr_sync_loc(integer nchecks=20) {
836 integer i, err_cnt=0, debug_cnt=0;
837 integer sync_time=0, clk_edge, old_clk_edge=0, clk_mid;
838 integer sync_loc_dev; // deviation in sync pulse location
839
840 this.dr_sync_loc_err_cnt = 0; // reset error counter
841 this.dr_sync_loc_debug_cnt = 0; // reset debug counter
842 //---wait for first DR sync, cmp clk and DR clk---
843 fork {
844 @(posedge clkgen_port.$dr_sync_en__l2clk); // wait for first dr sync pulse
845 dbg.dispmon(this.dispScope, MON_INFO, "first dr sync pulse");
846 }
847 {
848 @(posedge clkgen_port.$l2clk); // wait for first cmp clk
849 }
850 {
851 @(posedge clkgen_dr_port.$l2clk); // wait for first dr clk
852 } join
853 dbg.dispmon(this.dispScope, MON_INFO, "monitor: checking dr sync locations");
854 //----check sync location for DTM mode -----
855 if (this.clk_pkt.mode == CCU_DTM_MODE) {
856 sync_loc_dev = this.clk_pkt.cmp_clk_per_nom;
857 fork {
858 while (1) {
859 @(posedge clkgen_port.$dr_sync_en__l2clk);
860 @(posedge clkgen_port.$l2clk);
861 sync_time = get_time(LO); // at flop header
862 }
863 } join none
864 @(posedge clkgen_dr_port.$l2clk);
865 old_clk_edge = get_time(LO);
866 for (i = 0; i < nchecks; i++) {
867 @(posedge clkgen_dr_port.$l2clk);
868 clk_edge = get_time(LO);
869 clk_mid = (clk_edge + old_clk_edge) / 2;
870 if (compute_abs(sync_time - clk_mid) > sync_loc_dev) {
871 print_error_msg(err_cnt++, psprintf("sync location check: middle of DR l2clk: %0d, dr sync pulse at flop input: %0d <= more than %0d", clk_mid, sync_time, sync_loc_dev));
872 }
873 else if (this.verbose)
874 print_debug_msg(debug_cnt++, psprintf("sync location check: middle of DR l2clk: %0d, dr sync pulse at flop input: %0d", clk_mid, sync_time));
875
876 old_clk_edge = clk_edge;
877 }
878 }
879 else {
880 //---check DR sync locations---
881 for (i = 0; i < nchecks; i++) {
882 @(posedge clkgen_port.$dr_sync_en__l2clk); // dr sync is high at clkgen output
883 fork { check_next_dr_sync_loc(); } join none
884 }
885 }
886}
887
888//=============================================================
889// WHAT: check expected DR sync location at the flop input. DR sync
890// is flopped once after clkgen output.
891// HOW: the expected location of dr sync pulse is the cmp clk posedge
892// that is closet to the mid point of dr clk cycle (ie. delta). Since
893// the dr and cmp clk edges can shift a little, so testbench needs to
894// check the actual delta vs. (delta_min plus 1/3 of cmp clk cycle).
895//=============================================================
896task CLUSTER_hdr_chkr::check_next_dr_sync_loc() {
897 integer prev_dr_posedge, next_dr_posedge, at_end_dr_cyc=0, dr_clk_midpoint;
898 integer sync_at_clkgen, sync_at_flop; // sync pulse
899 integer cmp_edges[40], n = 0, i; // high ratio is in DTM mode 15:1 ratio
900 integer delta, min_delta, actual_delta; // time difference between cmp edge and dr clk midpoint
901 integer clks_shift_limit;
902
903 // when this task is called, DR sync is high at clkgen output
904 at_end_dr_cyc = 0;
905 n = 0;
906 fork
907 { // find next sync pulse (at flop input)
908 @(posedge clkgen_port.$dr_sync_en__l2clk); // sync is high at clkgen output
909 sync_at_clkgen = get_time(LO);
910 @(posedge clkgen_port.$l2clk); // sync is high at flop input
911 sync_at_flop = get_time(LO);
912 }
913 { // find next DR clk rising edges
914 @(negedge clkgen_port.$l2clk); // when dr_sync is at phase0 (ie. DR clk edge), avoid this dr clk edge
915 @(posedge clkgen_dr_port.$l2clk);
916 prev_dr_posedge = get_time(LO);
917 @(posedge clkgen_dr_port.$l2clk);
918 next_dr_posedge = get_time(LO);
919 at_end_dr_cyc = 1;
920 }
921 { // record timestamps of all cmp edges
922 while (1) {
923 @(posedge clkgen_port.$l2clk);
924 if (n >= 40) {
925 dbg.dispmon(this.dispScope, MON_ERR, psprintf("CLUSTER_hdrchkr::check_next_dr_sync_loc(n=%0d) <= programming error", n));
926 break;
927 }
928 cmp_edges[n] = get_time(LO);
929 n++;
930 if (at_end_dr_cyc) break; // reach the end of DR clk cycle
931 }
932 } join
933 //---find cmp posedge that is nearest to the DR clk mid point
934 dr_clk_midpoint = (prev_dr_posedge + next_dr_posedge) / 2; // rounding error is 1 tick
935 min_delta = compute_abs(cmp_edges[0] - dr_clk_midpoint);
936 for (i = 1; i < n ; i++) {
937 delta = compute_abs(cmp_edges[i] - dr_clk_midpoint);
938 if (delta < min_delta) // closer to the mid point
939 min_delta = delta;
940 }
941 //---check location of DR sync pulse---
942 actual_delta = compute_abs(sync_at_flop - dr_clk_midpoint);
943 clks_shift_limit = this.clk_pkt.cmp_clk_per_nom / 3; // 1/3 of nominal value of cmp clk cycle
944 if (actual_delta > (min_delta + clks_shift_limit)) {
945 this.dr_sync_loc_err_cnt++;
946 if (this.dr_sync_loc_err_cnt <= this.max_error_printed)
947 dbg.dispmon(this.dispScope, MON_ERR, psprintf(
948 "sync location check: dr sync @flop=%0d. dr clk: edges=%0d and %0d, midpoint=%0d. delta2midpoint=%0d <= exceed min_delta=%0d + %0d",
949 sync_at_flop, prev_dr_posedge, next_dr_posedge, dr_clk_midpoint, actual_delta, min_delta, clks_shift_limit));
950 }
951 else if (this.dr_sync_loc_debug_cnt <= this.max_error_printed) {
952 dbg.dispmon(this.dispScope, MON_INFO, psprintf(
953 "sync location check: dr sync @flop=%0d. dr clk: edges=%0d and %0d, midpoint=%0d, delta2midpoint=%0d, min_delta=%0d, tolerance=%0d",
954 sync_at_flop, prev_dr_posedge, next_dr_posedge, dr_clk_midpoint, actual_delta, min_delta, clks_shift_limit));
955 this.dr_sync_loc_debug_cnt++;
956 }
957}
958
959//############################################################################
960//############################################################################
961//######### supporting subroutines #########################################
962//############################################################################
963//############################################################################
964
965//=============================================================
966// WHAT: print error message
967// NOTE:
968// err_cnt is local error count of a particular error type.
969// this.error_cnt is global error count of this vera class.
970//=============================================================
971task CLUSTER_hdr_chkr::print_error_msg(integer err_cnt, string error_msg) {
972 if (err_cnt <= max_error_printed)
973 dbg.dispmon(this.dispScope, MON_ERR, error_msg);
974 this.error_cnt++; // increment global error count
975}
976
977//=============================================================
978// WHAT: print messages for debug
979//=============================================================
980task CLUSTER_hdr_chkr::print_debug_msg(integer debug_cnt, string debug_msg) {
981 if (debug_cnt <= max_debug_printed)
982 dbg.dispmon(this.dispScope, MON_ALWAYS, debug_msg);
983}
984
985//=============================================================
986// Return 1 if value is outside min and max; otherwise, return 0.
987//=============================================================
988function integer CLUSTER_hdr_chkr::is_outside_min_max(integer min_val, integer value, integer max_val) {
989 is_outside_min_max = ((value < min_val) || (value > max_val))? 1 : 0;
990}
991
992//=============================================================
993// WHAT: compute absolute value
994//=============================================================
995function integer CLUSTER_hdr_chkr::compute_abs(integer n) {
996 compute_abs = (n >= 0)? n : n * -1;
997}
998
999//=============================================================
1000// WHAT: timeout if not seen posedge of 'sig_name' in 'timeout_val' gclk cycles.
1001// ARGs: sig_name must be "l2clk", "cmp_slow_sync_en", "slow_cmp_sync_en",
1002// "io2x_sync_en" or "dr_sync_en"
1003//=============================================================
1004task CLUSTER_hdr_chkr::wait_1st_posedge(string sig_name, integer timeout_val) {
1005 integer got_1st_posedge=0;
1006
1007 if (timeout_val <= 0)
1008 return;
1009 fork {
1010 repeat (timeout_val) @(posedge clkgen_port.$gclk);
1011 if (got_1st_posedge == 0)
1012 dbg.dispmon(this.dispScope, MON_ERR, psprintf("not seen %s posedge in %0d gclks", sig_name, timeout_val));
1013 } join none
1014 case (sig_name) {
1015 "l2clk": @(posedge clkgen_port.$l2clk);
1016 "cmp_slow_sync_en": @(posedge clkgen_port.$cmp_slow_sync_en__l2clk);
1017 "slow_cmp_sync_en": @(posedge clkgen_port.$slow_cmp_sync_en__l2clk);
1018 "io2x_sync_en": @(posedge clkgen_port.$io2x_sync_en__l2clk);
1019 "dr_sync_en": @(posedge clkgen_port.$dr_sync_en__l2clk);
1020 default: {
1021 dbg.dispmon(this.dispScope, MON_ERR, psprintf("wait_1st_posedge(sig_name=%s) <= bad arg", sig_name));
1022 this.error_cnt++;
1023 }
1024 }
1025 got_1st_posedge = 1;
1026 terminate;
1027}
1028