Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | // ========== Copyright Header Begin ========================================== |
2 | // | |
3 | // OpenSPARC T2 Processor File: cReport.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 "report_info.vrh" | |
37 | #include "report_msg_format.vrh" | |
38 | ||
39 | // Definitions, constants, etc. | |
40 | #define REPORT_DEFAULT_PRINT_THRESHOLD RPRT_INFO | |
41 | #define REPORT_DEFAULT_PRINT_LEVEL RPRT_INFO | |
42 | #define REPORT_DEFAULT_MAX_ERROR_COUNT 1 | |
43 | #define REPORT_VERA_LOCATION_STRING "VERA" | |
44 | #define REPORT_NO_PLUS_ARG_SPECIFIED_STR "NONE" | |
45 | #define DEATH_CYCLE_DELAY 10 | |
46 | ||
47 | // verilog_tasks for communicating w/ the Report PLI | |
48 | extern verilog_task ReportPLI_set_global_print_threshold(integer new_print_threshold, integer locked_by); | |
49 | extern verilog_task ReportPLI_set_max_error_count(integer max_error_count); | |
50 | extern verilog_task ReportPLI_inc_global_error_count(); | |
51 | extern verilog_task ReportPLI_get_global_error_count(var integer ec); | |
52 | extern verilog_task ReportPLI_inc_global_warning_count(); | |
53 | extern verilog_task ReportPLI_get_global_warning_count(var integer wc); | |
54 | extern verilog_task ReportPLI_set_short_pathnames(integer short_names); | |
55 | extern verilog_task ReportPLI_set_path_prefix(bit [(256*8)-1:0] path_prefix); | |
56 | extern verilog_task ReportPLI_disable_fatal_errors(integer num_cycles); | |
57 | extern verilog_task ReportPLI_set_show_simulation_time(integer show_sim_time); | |
58 | extern verilog_task ReportPLI_set_print_level(bit [(256*8)-1:0] regexp, integer report_type, integer print_level); | |
59 | extern verilog_task ReportPLI_set_error_level(bit [(256*8)-1:0] regexp, integer report_type, integer error_level); | |
60 | extern verilog_task ReportPLI_set_table_mode(bit [(256*8)-1:0] regexp, integer report_type, integer table_mode); | |
61 | extern verilog_task ReportPLI_set_exit_on_error(integer exit_on_error); | |
62 | extern verilog_task ReportPLI_get_exit_on_error(var integer exit_on_error); | |
63 | extern verilog_task ReportPLI_print_cycles_per_second(); | |
64 | ||
65 | //////////////////////////////////////////////////////////////////////////////// | |
66 | // The Vera ReportClass header | |
67 | // | |
68 | class ReportClass | |
69 | { | |
70 | /////////////// | |
71 | // Private data | |
72 | ||
73 | // Class Variables (for all reports) | |
74 | // | |
75 | // NOTE: The Vera ReportClass only tracks the error count for Vera errors. | |
76 | // * To obtain the total global error count (Verilog + Vera), | |
77 | // use the method get_total_error_count(). | |
78 | // | |
79 | static protected PrintLevel global_print_threshold = REPORT_DEFAULT_PRINT_THRESHOLD; | |
80 | static protected integer max_error_count = REPORT_DEFAULT_MAX_ERROR_COUNT; | |
81 | static protected integer vera_error_count = 0; | |
82 | static protected integer vera_warning_count = 0; | |
83 | static protected integer use_short_pathnames = 0; | |
84 | static protected string path_prefix = ""; | |
85 | static protected integer num_remaining_nonfatal_cycles = 0; | |
86 | static protected integer show_simulation_time = 0; | |
87 | static protected integer in_death_spiral = 0; | |
88 | ||
89 | // Information about report types from the report_info class | |
90 | static protected integer report_has_been_initialized = 0; | |
91 | static protected ReportTypeInfo report_info; | |
92 | static protected PrintLevel print_level_per_type[]; | |
93 | static protected ErrorLevel error_level_per_type[]; | |
94 | ||
95 | // For command line overriding | |
96 | static protected integer cmd_line_args_parsed = 0; | |
97 | static protected integer global_print_threshold_locked_by; | |
98 | static protected integer print_level_locked_by[]; | |
99 | ||
100 | // This semaphore prevents multiple threads from making PLI calls simultaneously. | |
101 | // Vera can't do this since "HDL tasks aren't reentrant". | |
102 | static protected integer pli_semaphore = alloc(SEMAPHORE, 0, 1, 1); | |
103 | ||
104 | // Instance variables | |
105 | protected integer table_mode; | |
106 | static protected event deadly_event; | |
107 | ||
108 | /////////////// | |
109 | // Public methods | |
110 | ||
111 | virtual task report(ReportType report_type, string msg_string, | |
112 | (bit [511:0] arg1 = "", bit [511:0] arg2 = "", bit [511:0] arg3 = "", | |
113 | bit [511:0] arg4 = "", bit [511:0] arg5 = "", bit [511:0] arg6 = "", | |
114 | bit [511:0] arg7 = "", bit [511:0] arg8 = "", bit [511:0] arg9 = "", | |
115 | bit [511:0] arg10 = "", bit [511:0] arg11 = "", bit [511:0] arg12 = "")); | |
116 | // Just like report() but always error. | |
117 | virtual task report_error(string msg_string, | |
118 | bit [511:0] arg1 = "", bit [511:0] arg2 = "", bit [511:0] arg3 = "", | |
119 | bit [511:0] arg4 = "", bit [511:0] arg5 = "", bit [511:0] arg6 = "", | |
120 | bit [511:0] arg7 = "", bit [511:0] arg8 = "", bit [511:0] arg9 = "", | |
121 | bit [511:0] arg10 = "", bit [511:0] arg11 = "", bit [511:0] arg12 = ""); | |
122 | // Just like report() but expects only one argument (a string) | |
123 | virtual task report_string(ReportType report_type, string msg_string); | |
124 | virtual task report_test_complete(); | |
125 | ||
126 | // Accessors for class variables | |
127 | virtual task set_global_print_threshold(PrintLevel new_print_threshold, (integer locked_by = REPORT_LOCKED_BY_NO_ONE)); | |
128 | virtual function PrintLevel get_global_print_threshold(); | |
129 | virtual task set_max_error_count(integer error_count); | |
130 | virtual function integer get_max_error_count(); | |
131 | virtual function integer get_vera_error_count(); | |
132 | virtual function integer get_vera_warning_count(); | |
133 | virtual task set_short_pathnames(integer use_short); | |
134 | virtual function integer get_short_pathnames(); | |
135 | virtual task set_path_prefix(string prefix); | |
136 | virtual function string get_path_prefix(); | |
137 | virtual task disable_fatal_errors(integer num_cycles); | |
138 | virtual function integer get_num_remaining_nonfatal_cycles(); | |
139 | virtual task set_show_simulation_time(integer show_sim_time); | |
140 | virtual function integer get_show_simulation_time(); | |
141 | virtual task set_exit_on_error(integer exit_on_error); | |
142 | virtual function integer get_exit_on_error(); | |
143 | ||
144 | // Accessors for instance variables | |
145 | virtual task set_print_level(ReportType report_type, PrintLevel new_print_level, (integer locked_by = REPORT_LOCKED_BY_NO_ONE)); | |
146 | virtual function PrintLevel get_print_level(ReportType report_type); | |
147 | virtual task set_error_level(ReportType report_type, ErrorLevel new_error_level); | |
148 | virtual function ErrorLevel get_error_level(ReportType report_type); | |
149 | virtual task set_table_mode(integer table_mode); | |
150 | virtual function integer get_table_mode(); | |
151 | virtual function bit will_this_print(ReportType report_type); | |
152 | ||
153 | // Accessors for Report PLI class variables | |
154 | virtual function integer get_total_error_count(); | |
155 | virtual function integer get_total_warning_count(); | |
156 | ||
157 | // Accessors for Report PLI instance variables | |
158 | virtual task set_verilog_print_level(string regexp, ReportType report_type, PrintLevel print_level); | |
159 | virtual task set_verilog_error_level(string regexp, ReportType report_type, ErrorLevel error_level); | |
160 | virtual task set_verilog_table_mode(string regexp, ReportType report_type, integer table_mode); | |
161 | ||
162 | ////////////// | |
163 | // Protected methods | |
164 | ||
165 | protected virtual task handle_error(); | |
166 | protected virtual function string get_location(); | |
167 | protected virtual task launch_death_spiral(); | |
168 | ||
169 | protected task parse_cmd_line_print_threshold(); | |
170 | protected task parse_cmd_line_print_mask(); | |
171 | ||
172 | task new() | |
173 | { | |
174 | integer tmp_var; | |
175 | integer index; | |
176 | ||
177 | // Turn table mode (a per-instance variable) off by default. | |
178 | this.table_mode = 0; | |
179 | ||
180 | // Do a bunch of things that need to be done only once per test. | |
181 | if (this.report_has_been_initialized == 0) | |
182 | { | |
183 | ReportType type; | |
184 | // Initialize all instance properties. | |
185 | // Populate the print/error level arrays with the correct default values. | |
186 | // | |
187 | // *PERFORMANCE: Only do this once, since the array is populated with | |
188 | // values determined at compile time. | |
189 | // | |
190 | this.report_info = new; | |
191 | for(type = __RTYP_FIRST_TYPE; type < __RTYP_LAST_TYPE; type++) | |
192 | { | |
193 | //ReportType type = index; //report_info.get_type_by_index(index); | |
194 | this.print_level_per_type[type] = report_info.get_default_print_level(type); | |
195 | this.error_level_per_type[type] = report_info.get_default_error_level(type); | |
196 | } | |
197 | ||
198 | // Parse command line print threshold | |
199 | this.global_print_threshold_locked_by = REPORT_LOCKED_BY_NO_ONE; | |
200 | this.parse_cmd_line_print_threshold(); | |
201 | ||
202 | // Parse command line print mask | |
203 | for (index = 0; index < report_info.num_report_types; index++) | |
204 | this.print_level_locked_by[index] = REPORT_LOCKED_BY_NO_ONE; | |
205 | this.parse_cmd_line_print_mask(); | |
206 | ||
207 | // Launch a thread to wait for the "deadly event" triggered by a fatal error. | |
208 | launch_death_spiral(); | |
209 | ||
210 | // No need to do all this again. | |
211 | this.report_has_been_initialized = 1; | |
212 | } | |
213 | } | |
214 | } | |
215 | // | |
216 | //////////////////////////////////////////////////////////////////////////////// | |
217 | ||
218 | //////////////////////////////////////////////////////////////////////////////// | |
219 | // ReportClass method definitions | |
220 | // | |
221 | ||
222 | //////////////////////////////////////////////////////////////////////////////// | |
223 | // Message display | |
224 | ||
225 | /* | |
226 | report | |
227 | ||
228 | Outputs a message with the given report type in a standard format. | |
229 | */ | |
230 | task ReportClass::report(ReportType report_type, string msg_str, | |
231 | (bit [511:0] arg1 = "", bit [511:0] arg2 = "", bit [511:0] arg3 = "", | |
232 | bit [511:0] arg4 = "", bit [511:0] arg5 = "", bit [511:0] arg6 = "", | |
233 | bit [511:0] arg7 = "", bit [511:0] arg8 = "", bit [511:0] arg9 = "", | |
234 | bit [511:0] arg10 = "", bit [511:0] arg11 = "", bit [511:0] arg12 = "")) | |
235 | { | |
236 | string prefix_str, time_str, location_str; | |
237 | PrintLevel my_print_level = this.print_level_per_type[report_type]; | |
238 | ErrorLevel my_error_level = this.error_level_per_type[report_type]; | |
239 | ||
240 | // *PERFORMANCE: Return -immediately- if this report will be a NOP. | |
241 | if (my_print_level < this.global_print_threshold) | |
242 | return; | |
243 | ||
244 | ||
245 | // - if fatal errors are disabled, make errors into warnings. | |
246 | if (this.num_remaining_nonfatal_cycles > 0 && my_error_level == RERR_ERROR) | |
247 | prefix_str = report_info.get_prefix(report_type, RERR_MESSAGE); | |
248 | else | |
249 | prefix_str = report_info.get_prefix(report_type, my_error_level); | |
250 | ||
251 | // Generate the time string. | |
252 | // - tack on simulation time if so desired. | |
253 | if (show_simulation_time) | |
254 | { | |
255 | string cycle_str, tick_hi_str, tick_lo_str; | |
256 | sprintf(cycle_str, "%0d", get_cycle()); | |
257 | sprintf(tick_hi_str, "%0d", get_time(HI)); | |
258 | sprintf(tick_lo_str, "%0d", get_time(LO)); | |
259 | time_str = {cycle_str, ",", tick_hi_str, tick_lo_str}; // e.g. "350,768990" | |
260 | } | |
261 | else | |
262 | { | |
263 | sprintf(time_str, "%0d", get_cycle()); | |
264 | } | |
265 | ||
266 | // Get the location string. | |
267 | location_str = this.get_location(); | |
268 | ||
269 | // Actually do the output, if the print level is appropriate. | |
270 | if (my_print_level >= this.global_print_threshold) | |
271 | { | |
272 | string regexp_pattern, match_str; | |
273 | ||
274 | // review: Support output redirection here!!! | |
275 | ||
276 | // Check for bitfield width specifiers in the message format string. | |
277 | // For example, "%32h" will print only the rightmost 32 bits of a hex number. | |
278 | /* | |
279 | TODO: Figure out how to implement this cleanly. | |
280 | ||
281 | regexp_pattern = "[^%]%([0-9]+)[hHxXoObB]"; | |
282 | match_str = msg_str; | |
283 | while (match_str.match(regexp_pattern) == 1) | |
284 | { | |
285 | string width_str = match_str.backref(0); | |
286 | integer width = width_str.atoi(); | |
287 | printf("*** msg_str contains bitfield width specifier %s, giving width of %0d ***\n", match_str.thismatch(), width); | |
288 | match_str = match_str.postmatch(); | |
289 | } | |
290 | */ | |
291 | ||
292 | ||
293 | if (!this.table_mode) | |
294 | printf(REPORT_MSG_FORMAT_STRING, prefix_str, time_str, location_str); | |
295 | ||
296 | // If fatal error, output the error type. | |
297 | if (my_error_level == RERR_ERROR) | |
298 | printf("%s: ", report_info.report_type_to_str(report_type)); | |
299 | ||
300 | // Print message string | |
301 | printf(msg_str, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); | |
302 | ||
303 | // Print newline (if not in table mode) | |
304 | if (!this.table_mode) printf("\n"); | |
305 | } | |
306 | ||
307 | // If this message was an error/warning, increment the global error/warning count. | |
308 | // Then increment the Vera-specific error/warning count. | |
309 | if (my_error_level == RERR_ERROR) | |
310 | { | |
311 | integer total_errors, exit_on_error; | |
312 | ||
313 | semaphore_get(WAIT, this.pli_semaphore, 1); | |
314 | ||
315 | if (num_remaining_nonfatal_cycles == 0) | |
316 | { | |
317 | // Only do this if fatal errors are not currently disabled! | |
318 | ReportPLI_inc_global_error_count(); | |
319 | vera_error_count++; | |
320 | } | |
321 | ||
322 | ReportPLI_get_global_error_count(total_errors); | |
323 | ||
324 | semaphore_put(this.pli_semaphore, 1); | |
325 | ||
326 | // If this error pushed us over the maximum error count (as recorded by Verilog) | |
327 | // handle the error and kill the simulation if we're supposed to. | |
328 | ||
329 | if (total_errors >= this.max_error_count) | |
330 | { | |
331 | this.handle_error(); | |
332 | ||
333 | trigger(ONE_BLAST, deadly_event); // unblocks launch_death_spiral() | |
334 | } | |
335 | } | |
336 | else if (my_error_level == RERR_WARNING) | |
337 | { | |
338 | semaphore_get(WAIT, this.pli_semaphore, 1); | |
339 | ReportPLI_inc_global_warning_count(); | |
340 | vera_warning_count++; | |
341 | semaphore_put(this.pli_semaphore, 1); | |
342 | } | |
343 | } | |
344 | ||
345 | // Just like report() but always error. | |
346 | task ReportClass::report_error(string msg_string, | |
347 | bit [511:0] arg1 = "", bit [511:0] arg2 = "", bit [511:0] arg3 = "", | |
348 | bit [511:0] arg4 = "", bit [511:0] arg5 = "", bit [511:0] arg6 = "", | |
349 | bit [511:0] arg7 = "", bit [511:0] arg8 = "", bit [511:0] arg9 = "", | |
350 | bit [511:0] arg10 = "", bit [511:0] arg11 = "", bit [511:0] arg12 = "") { | |
351 | this.report(RTYP_VERA_ERROR, msg_string, arg1, arg2, arg3, | |
352 | arg4, arg5, arg6, | |
353 | arg7, arg8, arg9, | |
354 | arg10, arg11, arg12); | |
355 | } // ReportClass.error() | |
356 | ||
357 | ||
358 | /* | |
359 | * report_string | |
360 | */ | |
361 | task ReportClass::report_string(ReportType report_type, string msg_string) | |
362 | { | |
363 | string prefix_str, time_str, location_str; | |
364 | PrintLevel my_print_level = this.print_level_per_type[report_type]; | |
365 | ErrorLevel my_error_level = this.error_level_per_type[report_type]; | |
366 | ||
367 | // *PERFORMANCE: Return -immediately- if this report will be a NOP. | |
368 | if (my_print_level < this.global_print_threshold) | |
369 | return; | |
370 | ||
371 | ||
372 | // - if fatal errors are disabled, make errors into warnings. | |
373 | if (this.num_remaining_nonfatal_cycles > 0 && my_error_level == RERR_ERROR) | |
374 | prefix_str = report_info.get_prefix(report_type, RERR_MESSAGE); | |
375 | else | |
376 | prefix_str = report_info.get_prefix(report_type, my_error_level); | |
377 | ||
378 | // Generate the time string. | |
379 | // - tack on simulation time if so desired. | |
380 | if (show_simulation_time) | |
381 | { | |
382 | string cycle_str, tick_hi_str, tick_lo_str; | |
383 | sprintf(cycle_str, "%0d", get_cycle()); | |
384 | sprintf(tick_hi_str, "%0d", get_time(HI)); | |
385 | sprintf(tick_lo_str, "%0d", get_time(LO)); | |
386 | time_str = {cycle_str, ",", tick_hi_str, tick_lo_str}; // e.g. "350,768990" | |
387 | } | |
388 | else | |
389 | { | |
390 | sprintf(time_str, "%0d", get_cycle()); | |
391 | } | |
392 | ||
393 | // Get the location string. | |
394 | location_str = this.get_location(); | |
395 | ||
396 | // Actually do the output, if the print level is appropriate. | |
397 | if (my_print_level >= this.global_print_threshold) | |
398 | { | |
399 | string regexp_pattern, match_str; | |
400 | ||
401 | ||
402 | if (!this.table_mode) | |
403 | printf(REPORT_MSG_FORMAT_STRING, prefix_str, time_str, location_str); | |
404 | ||
405 | // If fatal error, output the error type. | |
406 | if (my_error_level == RERR_ERROR) | |
407 | printf("%s: ", report_info.report_type_to_str(report_type)); | |
408 | ||
409 | // Print message string | |
410 | printf(msg_string); | |
411 | ||
412 | // Print newline (if not in table mode) | |
413 | if (!this.table_mode) printf("\n"); | |
414 | } | |
415 | ||
416 | // If this message was an error/warning, increment the global error/warning count. | |
417 | // Then increment the Vera-specific error/warning count. | |
418 | if (my_error_level == RERR_ERROR) | |
419 | { | |
420 | integer total_errors, exit_on_error; | |
421 | ||
422 | semaphore_get(WAIT, this.pli_semaphore, 1); | |
423 | ||
424 | if (num_remaining_nonfatal_cycles == 0) | |
425 | { | |
426 | // Only do this if fatal errors are not currently disabled! | |
427 | ReportPLI_inc_global_error_count(); | |
428 | vera_error_count++; | |
429 | } | |
430 | ||
431 | ReportPLI_get_global_error_count(total_errors); | |
432 | ||
433 | semaphore_put(this.pli_semaphore, 1); | |
434 | ||
435 | // If this error pushed us over the maximum error count (as recorded by Verilog) | |
436 | // handle the error and kill the simulation if we're supposed to. | |
437 | ||
438 | if (total_errors >= this.max_error_count) | |
439 | { | |
440 | this.handle_error(); | |
441 | ||
442 | trigger(ONE_BLAST, deadly_event); // unblocks launch_death_spiral() | |
443 | } | |
444 | } | |
445 | else if (my_error_level == RERR_WARNING) | |
446 | { | |
447 | semaphore_get(WAIT, this.pli_semaphore, 1); | |
448 | ReportPLI_inc_global_warning_count(); | |
449 | vera_warning_count++; | |
450 | semaphore_put(this.pli_semaphore, 1); | |
451 | } | |
452 | } | |
453 | ||
454 | ||
455 | /* | |
456 | report_test_complete | |
457 | */ | |
458 | task ReportClass::report_test_complete() | |
459 | { | |
460 | integer total_errors, total_warnings; | |
461 | ||
462 | semaphore_get(WAIT, this.pli_semaphore, 1); | |
463 | ReportPLI_get_global_error_count(total_errors); | |
464 | ReportPLI_get_global_warning_count(total_warnings); | |
465 | semaphore_put(this.pli_semaphore, 1); | |
466 | if (in_death_spiral) { | |
467 | error("Report(%0d) [VERA] Test finished in death spiral!\n", get_cycle()); | |
468 | } | |
469 | printf(REPORT_TEST_DONE_FORMAT_STRING, get_cycle(), total_errors, total_warnings); | |
470 | ReportPLI_print_cycles_per_second(); | |
471 | } | |
472 | ||
473 | /* | |
474 | handle_error | |
475 | */ | |
476 | task ReportClass::handle_error() | |
477 | { | |
478 | // NOTE: By default, the base ReportClass does nothing to handle errors. | |
479 | this.report(RTYP_REPORT_MSG, "Fatal error encountered!!!"); | |
480 | } | |
481 | ||
482 | /* | |
483 | protected virtual function string get_location() | |
484 | ||
485 | Returns the location from which this report is being made. | |
486 | NOTE: This may one day actually be the object+method we're in, | |
487 | but Vera doesn't currently support this. | |
488 | */ | |
489 | function string ReportClass::get_location() | |
490 | { | |
491 | get_location = REPORT_VERA_LOCATION_STRING; | |
492 | } | |
493 | ||
494 | // | |
495 | //////////////////////////////////////////////////////////////////////////////// | |
496 | ||
497 | //////////////////////////////////////////////////////////////////////////////// | |
498 | // Accessors for class variables | |
499 | // | |
500 | // NOTE: Since control changes in Vera override those in Verilog, | |
501 | // these accessors also call the UDF functions to reconfigure the C+ ReportClass. | |
502 | ||
503 | /* | |
504 | set_global_print_threshold | |
505 | ||
506 | This accessor may be called with a "lock" variable to prevent further changes. | |
507 | This can be used to lock in changes from the command line, for example. | |
508 | NOTE! The lock variable can only be set once; further changes are ignored. | |
509 | */ | |
510 | task ReportClass::set_global_print_threshold(PrintLevel new_print_threshold, (integer locked_by = REPORT_LOCKED_BY_NO_ONE)) | |
511 | { | |
512 | integer int_pl = new_print_threshold; | |
513 | if (this.global_print_threshold_locked_by == REPORT_LOCKED_BY_NO_ONE) | |
514 | { | |
515 | if (locked_by != REPORT_LOCKED_BY_NO_ONE) | |
516 | { | |
517 | this.report(RTYP_REPORT_MSG, "Locked global print threshold to %s -- further changes will be ignored", | |
518 | report_info.print_level_to_str(new_print_threshold)); | |
519 | this.global_print_threshold_locked_by = locked_by; | |
520 | } | |
521 | else | |
522 | { | |
523 | // The usual case -- no locks specified or set. | |
524 | // When we call C++, though, lock their print threshold so only we can change it. | |
525 | this.report(RTYP_REPORT_MSG, "Changing global print threshold from %s to %s", | |
526 | report_info.print_level_to_str(this.global_print_threshold), | |
527 | report_info.print_level_to_str(new_print_threshold)); | |
528 | locked_by = REPORT_LOCKED_BY_VERA; | |
529 | } | |
530 | this.global_print_threshold = new_print_threshold; | |
531 | ||
532 | // Pass the good news along to C++. | |
533 | ||
534 | // semaphore_get(WAIT, pli_semaphore, 1); | |
535 | ReportPLI_set_global_print_threshold(int_pl, locked_by); | |
536 | // semaphore_put(pli_semaphore, 1); | |
537 | } | |
538 | else | |
539 | { | |
540 | this.report(RTYP_REPORT_MSG, "Can't change global print threshold to %s -- it's locked!", | |
541 | report_info.print_level_to_str(new_print_threshold)); | |
542 | } | |
543 | } | |
544 | ||
545 | /* | |
546 | get_global_print_threshold | |
547 | */ | |
548 | function PrintLevel ReportClass::get_global_print_threshold() | |
549 | { | |
550 | get_global_print_threshold = this.global_print_threshold; | |
551 | } | |
552 | ||
553 | /* | |
554 | set_max_error_count | |
555 | */ | |
556 | task ReportClass::set_max_error_count(integer error_count) | |
557 | { | |
558 | semaphore_get(WAIT, pli_semaphore, 1); | |
559 | ReportPLI_set_max_error_count(error_count); | |
560 | semaphore_put(pli_semaphore, 1); | |
561 | this.report(RTYP_REPORT_MSG, "Changing maximum error count from %0d to %0d", | |
562 | this.max_error_count, error_count); | |
563 | this.max_error_count = error_count; | |
564 | } | |
565 | ||
566 | /* | |
567 | get_max_error_count | |
568 | */ | |
569 | function integer ReportClass::get_max_error_count() | |
570 | { | |
571 | get_max_error_count = this.max_error_count; | |
572 | } | |
573 | ||
574 | /* | |
575 | get_vera_error_count | |
576 | */ | |
577 | function integer ReportClass::get_vera_error_count() | |
578 | { | |
579 | get_vera_error_count = this.vera_error_count; | |
580 | } | |
581 | ||
582 | /* | |
583 | get_vera_warning_count | |
584 | */ | |
585 | function integer ReportClass::get_vera_warning_count() | |
586 | { | |
587 | get_vera_warning_count = this.vera_warning_count; | |
588 | } | |
589 | ||
590 | /* | |
591 | set_short_pathnames | |
592 | */ | |
593 | task ReportClass::set_short_pathnames(integer use_short) | |
594 | { | |
595 | semaphore_get(WAIT, pli_semaphore, 1); | |
596 | ReportPLI_set_short_pathnames(use_short); | |
597 | semaphore_put(pli_semaphore, 1); | |
598 | if (use_short) | |
599 | this.report(RTYP_REPORT_MSG, "Using short pathnames."); | |
600 | else | |
601 | this.report(RTYP_REPORT_MSG, "Using long pathnames."); | |
602 | ||
603 | this.use_short_pathnames = use_short; | |
604 | } | |
605 | ||
606 | /* | |
607 | get_short_pathnames | |
608 | */ | |
609 | function integer ReportClass::get_short_pathnames() | |
610 | { | |
611 | get_short_pathnames = this.use_short_pathnames; | |
612 | } | |
613 | ||
614 | /* | |
615 | set_path_prefix | |
616 | */ | |
617 | task ReportClass::set_path_prefix(string prefix) | |
618 | { | |
619 | semaphore_get(WAIT, pli_semaphore, 1); | |
620 | ReportPLI_set_path_prefix(prefix); | |
621 | semaphore_put(pli_semaphore, 1); | |
622 | this.report(RTYP_REPORT_MSG, "Setting path prefix to %s", prefix); | |
623 | this.path_prefix = prefix; | |
624 | } | |
625 | ||
626 | /* | |
627 | get_path_prefix | |
628 | */ | |
629 | function string ReportClass::get_path_prefix() | |
630 | { | |
631 | get_path_prefix = this.path_prefix; | |
632 | } | |
633 | ||
634 | /* | |
635 | set_exit_on_error | |
636 | */ | |
637 | task ReportClass::set_exit_on_error(integer exit) | |
638 | { | |
639 | semaphore_get(WAIT, pli_semaphore, 1); | |
640 | ReportPLI_set_exit_on_error(exit); | |
641 | semaphore_put(pli_semaphore, 1); | |
642 | } | |
643 | ||
644 | /* | |
645 | get_exit_on_error | |
646 | */ | |
647 | function integer ReportClass::get_exit_on_error() | |
648 | { | |
649 | integer exit_on_error; | |
650 | semaphore_get(WAIT, pli_semaphore, 1); | |
651 | ReportPLI_get_exit_on_error(exit_on_error); | |
652 | semaphore_put(pli_semaphore, 1); | |
653 | get_exit_on_error = exit_on_error; | |
654 | } | |
655 | ||
656 | /* | |
657 | disable_fatal_errors | |
658 | */ | |
659 | task ReportClass::disable_fatal_errors(integer num_cycles) | |
660 | { | |
661 | semaphore_get(WAIT, pli_semaphore, 1); | |
662 | ReportPLI_disable_fatal_errors(num_cycles); | |
663 | semaphore_put(pli_semaphore, 1); | |
664 | if (num_cycles > 0) | |
665 | { | |
666 | this.report(RTYP_REPORT_MSG, "Disabling fatal errors for %0d cycles.", num_cycles); | |
667 | this.num_remaining_nonfatal_cycles = num_cycles; | |
668 | ||
669 | // Spawn a thread to count down the number of remaining nonfatal cycles. | |
670 | // NOTE: The nonfatal cycle count for C++ is decremented by the PLI code. | |
671 | fork | |
672 | repeat (num_cycles) | |
673 | { | |
674 | this.report(RTYP_REPORT_MSG, "Fatal errors are disabled on this cycle!!!"); | |
675 | this.num_remaining_nonfatal_cycles--; | |
676 | @(posedge CLOCK); // review: Which clock? What if there is more than one? | |
677 | } | |
678 | join none | |
679 | } | |
680 | } | |
681 | ||
682 | /* | |
683 | get_num_remaining_nonfatal_cycles | |
684 | */ | |
685 | function integer ReportClass::get_num_remaining_nonfatal_cycles() | |
686 | { | |
687 | get_num_remaining_nonfatal_cycles = this.num_remaining_nonfatal_cycles; | |
688 | } | |
689 | ||
690 | /* | |
691 | set_show_simulation_time | |
692 | */ | |
693 | task ReportClass::set_show_simulation_time(integer sim_time) | |
694 | { | |
695 | semaphore_get(WAIT, pli_semaphore, 1); | |
696 | ReportPLI_set_show_simulation_time(sim_time); | |
697 | semaphore_put(pli_semaphore, 1); | |
698 | if (!sim_time) | |
699 | report(RTYP_REPORT_MSG, "ReportClass: Not displaying simulation time."); | |
700 | else | |
701 | report(RTYP_REPORT_MSG, "ReportClass: Displaying simulation time."); | |
702 | this.show_simulation_time = sim_time; | |
703 | } | |
704 | ||
705 | /* | |
706 | get_show_simulation_time | |
707 | */ | |
708 | function integer ReportClass::get_show_simulation_time() | |
709 | { | |
710 | get_show_simulation_time = this.show_simulation_time; | |
711 | } | |
712 | ||
713 | //////////////////////////////////////////////////////////////////////////////// | |
714 | // Accessors for instance variables | |
715 | ||
716 | /* | |
717 | set_print_level | |
718 | Changes the print level of this message type only | |
719 | */ | |
720 | task ReportClass::set_print_level(ReportType report_type, PrintLevel new_print_level, (integer locked_by = REPORT_LOCKED_BY_NO_ONE)) | |
721 | { | |
722 | if (this.print_level_locked_by[report_type] == REPORT_LOCKED_BY_NO_ONE) | |
723 | { | |
724 | if (locked_by != REPORT_LOCKED_BY_NO_ONE) | |
725 | { | |
726 | report(RTYP_REPORT_MSG, "ReportClass: Locking print level for report type %s to %s -- further changes will be ignored", | |
727 | report_info.report_type_to_str(report_type), report_info.print_level_to_str(new_print_level)); | |
728 | this.print_level_locked_by[report_type] = locked_by; | |
729 | } | |
730 | else | |
731 | { | |
732 | report(RTYP_REPORT_MSG, "ReportClass: Setting print level for report type %s to %s", | |
733 | report_info.report_type_to_str(report_type), report_info.print_level_to_str(new_print_level)); | |
734 | } | |
735 | ||
736 | // If the type is "ALL_REPORTS", set everything. | |
737 | // Otherwise, just set the desired type. | |
738 | if (report_type == RTYP_ALL_REPORTS) | |
739 | { | |
740 | ReportType type; | |
741 | for (type = __RTYP_FIRST_TYPE; type <= __RTYP_LAST_TYPE; type++) | |
742 | { | |
743 | print_level_per_type[type] = new_print_level; | |
744 | } | |
745 | } | |
746 | else | |
747 | { | |
748 | print_level_per_type[report_type] = new_print_level; | |
749 | } | |
750 | } | |
751 | else | |
752 | { | |
753 | report(RTYP_REPORT_MSG, "Can't change print level for %s to %s -- it's locked!", | |
754 | report_info.report_type_to_str(report_type), report_info.print_level_to_str(new_print_level)); | |
755 | } | |
756 | } | |
757 | ||
758 | /* | |
759 | get_print_level | |
760 | Returns this message type's print level | |
761 | */ | |
762 | ||
763 | function PrintLevel ReportClass::get_print_level(ReportType report_type) | |
764 | { | |
765 | get_print_level = print_level_per_type[report_type]; | |
766 | } | |
767 | ||
768 | /* | |
769 | set_error_level | |
770 | Changes the error level of this message type only | |
771 | */ | |
772 | task ReportClass::set_error_level(ReportType report_type, ErrorLevel new_error_level) | |
773 | { | |
774 | report(RTYP_REPORT_MSG, "ReportClass: Setting error level for report type %s to %s", | |
775 | report_info.report_type_to_str(report_type), report_info.error_level_to_str(new_error_level)); | |
776 | ||
777 | // If the type is "ALL_REPORTS", set everything. | |
778 | // Otherwise, just set the desired type. | |
779 | if (report_type == RTYP_ALL_REPORTS) | |
780 | { | |
781 | ReportType type; | |
782 | for (type = __RTYP_FIRST_TYPE; type <= __RTYP_LAST_TYPE; type++) | |
783 | { | |
784 | error_level_per_type[type] = new_error_level; | |
785 | } | |
786 | } | |
787 | else | |
788 | { | |
789 | error_level_per_type[report_type] = new_error_level; | |
790 | } | |
791 | } | |
792 | ||
793 | /* | |
794 | get_error_level | |
795 | Returns this message type's error level | |
796 | */ | |
797 | ||
798 | function ErrorLevel ReportClass::get_error_level(ReportType report_type) | |
799 | { | |
800 | get_error_level = error_level_per_type[report_type]; | |
801 | } | |
802 | ||
803 | /* | |
804 | set_table_mode | |
805 | */ | |
806 | task ReportClass::set_table_mode(integer table_mode) | |
807 | { | |
808 | /* | |
809 | if (!table_mode) | |
810 | report(RTYP_DEBUG_1, "ReportClass: Disabling table mode."); | |
811 | else | |
812 | report(RTYP_DEBUG_1, "ReportClass: Enabling table mode."); | |
813 | */ | |
814 | ||
815 | this.table_mode = table_mode; | |
816 | } | |
817 | ||
818 | /* | |
819 | get_table_mode | |
820 | */ | |
821 | function integer ReportClass::get_table_mode() | |
822 | { | |
823 | get_table_mode = this.table_mode; | |
824 | } | |
825 | ||
826 | /* | |
827 | * will_this_print | |
828 | * | |
829 | * Returns 1 if report_type's print_level is above the global print threshold, | |
830 | * and 0 if it is not. | |
831 | * | |
832 | */ | |
833 | function bit ReportClass::will_this_print(ReportType report_type) | |
834 | { | |
835 | will_this_print = (print_level_per_type[report_type] >= this.global_print_threshold); | |
836 | } | |
837 | ||
838 | //////////////////////////////////////////////////////////////////////////////// | |
839 | // Accessors for Report PLI class variables | |
840 | function integer ReportClass::get_total_error_count() | |
841 | { | |
842 | integer ec; | |
843 | semaphore_get(WAIT, pli_semaphore, 1); | |
844 | ReportPLI_get_global_error_count(ec); | |
845 | semaphore_put(pli_semaphore, 1); | |
846 | get_total_error_count = ec; | |
847 | } | |
848 | ||
849 | function integer ReportClass::get_total_warning_count() | |
850 | { | |
851 | integer wc; | |
852 | semaphore_get(WAIT, pli_semaphore, 1); | |
853 | ReportPLI_get_global_warning_count(wc); | |
854 | semaphore_put(pli_semaphore, 1); | |
855 | get_total_warning_count = wc; | |
856 | } | |
857 | ||
858 | //////////////////////////////////////////////////////////////////////////////// | |
859 | // Accessors for Report PLI instance variables | |
860 | // | |
861 | task ReportClass::set_verilog_print_level(string regexp, ReportType report_type, PrintLevel print_level) | |
862 | { | |
863 | integer int_type = report_type; | |
864 | integer int_lvl = print_level; | |
865 | semaphore_get(WAIT, pli_semaphore, 1); | |
866 | ReportPLI_set_print_level(regexp, int_type, int_lvl); | |
867 | semaphore_put(pli_semaphore, 1); | |
868 | } | |
869 | ||
870 | task ReportClass::set_verilog_error_level(string regexp, ReportType report_type, ErrorLevel error_level) | |
871 | { | |
872 | integer int_type = report_type; | |
873 | integer int_lvl = error_level; | |
874 | semaphore_get(WAIT, pli_semaphore, 1); | |
875 | ReportPLI_set_error_level(regexp, int_type, int_lvl); | |
876 | semaphore_put(pli_semaphore, 1); | |
877 | } | |
878 | ||
879 | task ReportClass::set_verilog_table_mode(string regexp, ReportType report_type, integer table_mode) | |
880 | { | |
881 | integer int_type = report_type; | |
882 | semaphore_get(WAIT, pli_semaphore, 1); | |
883 | ReportPLI_set_table_mode(regexp, int_type, table_mode); | |
884 | semaphore_put(pli_semaphore, 1); | |
885 | } | |
886 | ||
887 | //////////////////////////////////////////////////////////////////////////////// | |
888 | // Protected methods | |
889 | ||
890 | /* | |
891 | * parse_cmd_line_print_threshold | |
892 | * | |
893 | */ | |
894 | task ReportClass::parse_cmd_line_print_threshold() | |
895 | { | |
896 | // Get print thresholds specified on the command line. | |
897 | bit [511:0] global_print_threshold_bits, vera_print_threshold_bits, verilog_print_threshold_bits; | |
898 | PrintLevel global_print_threshold, vera_print_threshold, verilog_print_threshold; | |
899 | ||
900 | global_print_threshold_bits = get_plus_arg(STR, "report_global_print_threshold="); | |
901 | vera_print_threshold_bits = get_plus_arg(STR, "report_vera_print_threshold="); | |
902 | verilog_print_threshold_bits = get_plus_arg(STR, "report_verilog_print_threshold="); | |
903 | ||
904 | if (!report_info.bit_string_to_print_level(global_print_threshold_bits, global_print_threshold)) | |
905 | { | |
906 | // No global specified -- check for individual Verilog or Vera thresholds. | |
907 | // Set the Verilog threshold, if any... | |
908 | if (report_info.bit_string_to_print_level(verilog_print_threshold_bits, verilog_print_threshold)) | |
909 | { | |
910 | integer int_pl = verilog_print_threshold; | |
911 | if (verilog_print_threshold != this.get_global_print_threshold()) | |
912 | { | |
913 | ||
914 | // semaphore_get(WAIT, pli_semaphore, 1); | |
915 | ReportPLI_set_global_print_threshold(int_pl, REPORT_LOCKED_BY_CMD_LINE); | |
916 | // semaphore_put(pli_semaphore, 1); | |
917 | } | |
918 | } | |
919 | ||
920 | // ...then set the Vera threshold, if any. | |
921 | if (report_info.bit_string_to_print_level(vera_print_threshold_bits, vera_print_threshold)) | |
922 | { | |
923 | if (vera_print_threshold != this.get_global_print_threshold()) | |
924 | this.set_global_print_threshold(vera_print_threshold, REPORT_LOCKED_BY_VERA); // HACK: leave Verilog threshold unchanged by specifying 'Vera' lock | |
925 | } | |
926 | } | |
927 | else | |
928 | { | |
929 | // "global" overrides both of the "vera" and "verilog" individual settings. | |
930 | if (global_print_threshold != this.get_global_print_threshold()) | |
931 | this.set_global_print_threshold(global_print_threshold, REPORT_LOCKED_BY_CMD_LINE); | |
932 | } | |
933 | } | |
934 | ||
935 | /* | |
936 | * parse_cmd_line_print_mask | |
937 | * | |
938 | */ | |
939 | task ReportClass::parse_cmd_line_print_mask() | |
940 | { | |
941 | // Get the Vera print mask specified on the command line, if any. | |
942 | // Pull out individual message types from it by using a regular expression. | |
943 | bit [511:0] vera_print_mask_bits; | |
944 | string vera_print_mask_str; | |
945 | ||
946 | vera_print_mask_bits = get_plus_arg(STR, "report_vera_print_mask="); | |
947 | vera_print_mask_str.bittostr(vera_print_mask_bits); | |
948 | ||
949 | // Get each message type name and lock its print level to NONMASKABLE. | |
950 | while (vera_print_mask_str.match("[a-zA-Z0-9_]+") > 0) | |
951 | { | |
952 | ReportType type; | |
953 | if (report_info.string_to_report_type(vera_print_mask_str.thismatch(), type)) | |
954 | { | |
955 | this.set_print_level(type, RPRT_NONMASKABLE, REPORT_LOCKED_BY_CMD_LINE); | |
956 | } | |
957 | else | |
958 | { | |
959 | this.report(RTYP_REPORT_MSG, "Encountered bad report type %s in command line argument REPORT_VERA_PRINT_MASK", | |
960 | vera_print_mask_str.thismatch()); | |
961 | } | |
962 | vera_print_mask_str = vera_print_mask_str.postmatch(); | |
963 | } | |
964 | } | |
965 | ||
966 | // | |
967 | //////////////////////////////////////////////////////////////////////////////// | |
968 | ||
969 | // task launch_death_spiral | |
970 | // | |
971 | // Description: This class launches the thread which will actually kill the | |
972 | // test on a fatal error. The test is killed by an error() | |
973 | // call triggered DEATH_CYCLE_DELAY cycles after receiving | |
974 | // the 'deadly_event' signal. | |
975 | // | |
976 | ||
977 | task ReportClass::launch_death_spiral() | |
978 | { | |
979 | fork | |
980 | { | |
981 | integer exit_on_error; | |
982 | ||
983 | // Block until the deadly event happens. | |
984 | // NOTE: Only need to do this once, since it will kill the test! | |
985 | sync(ALL, deadly_event); | |
986 | ||
987 | ReportPLI_get_exit_on_error(exit_on_error); | |
988 | ||
989 | if (exit_on_error) | |
990 | { | |
991 | if (!in_death_spiral) | |
992 | { | |
993 | integer death_spiral_count = DEATH_CYCLE_DELAY; | |
994 | ||
995 | in_death_spiral = 1; | |
996 | printf("Report:(%0d) [VERA] Scheduling termination for cycle %0d\n", get_cycle(), get_cycle() + DEATH_CYCLE_DELAY); | |
997 | ||
998 | while(death_spiral_count--) { | |
999 | ||
1000 | printf("Report:(%0d) [VERA] In death spiral. %0d cycles left till termination.\n", | |
1001 | get_cycle(), death_spiral_count); | |
1002 | ||
1003 | @(posedge CLOCK); | |
1004 | } | |
1005 | ||
1006 | printf("Report:(%0d) [VERA] Calling error() for error which occurred on cycle %0d\n", | |
1007 | get_cycle(), get_cycle() - DEATH_CYCLE_DELAY); | |
1008 | error(""); // actually kill the test! | |
1009 | ||
1010 | } | |
1011 | else | |
1012 | { | |
1013 | printf("Report:(%0d) [VERA] termination already scheduled\n"); | |
1014 | } | |
1015 | } | |
1016 | } | |
1017 | join none | |
1018 | } |