Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | // ========== Copyright Header Begin ========================================== |
2 | // | |
3 | // OpenSPARC T2 Processor File: report_pli.cc | |
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 | // Test if GNU gcc version is less than 3.x. If so, use pre-standard lib includes | |
36 | #if __GNUC__ < 3 | |
37 | // VSP-modification end | |
38 | ||
39 | //#include <iostream.h> | |
40 | #include <stdio.h> | |
41 | #include <string.h> | |
42 | #include <time.h> | |
43 | #include <limits.h> | |
44 | ||
45 | // VSP-modification begin | |
46 | #else | |
47 | ||
48 | #include <iostream> | |
49 | #include <cstdarg> | |
50 | #include <string> | |
51 | #include <ctime> | |
52 | #include <limits> | |
53 | ||
54 | #endif // else __GNUC__ < 3 | |
55 | // VSP-modification end | |
56 | ||
57 | #include <sys/types.h> | |
58 | #include <sys/times.h> | |
59 | #include <unistd.h> | |
60 | #include <cReport.h> | |
61 | #include <report_info.h> | |
62 | #include <Hash.h> | |
63 | #include <veriuser.h> | |
64 | ||
65 | // utility functions | |
66 | extern void parse_format_string(char*, char*, int); | |
67 | extern int regex_match(const char*, const char*); | |
68 | ||
69 | #ifdef __cplusplus | |
70 | extern "C" { | |
71 | #endif | |
72 | ||
73 | // Global variables | |
74 | HashTable *g_report_hash_table; | |
75 | int g_report_hash_table_initialized = 0; | |
76 | ReportClass g_internal_reports; // for report utility information | |
77 | int g_cycle_count = 0, g_death_cycle_count; | |
78 | int g_exit_on_error = 1; | |
79 | clock_t start_time; | |
80 | struct tms start_tmsbuf; | |
81 | ||
82 | //////////////////////////////////////////////////////////////////////////////// | |
83 | // PLI accessor functions | |
84 | ||
85 | // | |
86 | // ReportClass_report | |
87 | // | |
88 | // PLI accessor for the function ReportClass::report() | |
89 | // | |
90 | // | |
91 | void ReportClass_report() | |
92 | { | |
93 | const HashValueListNode *this_key, *this_value; | |
94 | const char *mip_name = tf_mipname(); // Stash the module pathname in mip_name. | |
95 | ReportType report_type = (ReportType)tf_getp(1); | |
96 | ||
97 | // Create a key and retrieve the correct ReportClass* from the hash. | |
98 | this_key = new HashValueListNode(mip_name, report_type); this_value = g_report_hash_table->lookup(*this_key); | |
99 | if (this_value == NULL) { | |
100 | tf_error("ReportClass (Internal): Couldn't find value for key with mipname %s!\n", | |
101 | mip_name); | |
102 | tf_dofinish(); | |
103 | } | |
104 | delete this_key; | |
105 | ||
106 | { | |
107 | ReportClass this_report = *this_value->report_class; | |
108 | ||
109 | if (this_report.this_will_print(report_type)) { | |
110 | char format_str[REPORT_MAX_LINE_LENGTH]; | |
111 | char time_str[REPORT_MAX_LINE_LENGTH]; | |
112 | char msg_str[REPORT_MAX_LINE_LENGTH]; | |
113 | ||
114 | // Parse the format string and argument list to produce a | |
115 | ||
116 | strncpy(format_str, tf_getcstringp(2), REPORT_MAX_LINE_LENGTH); // make a copy so we can modify it in parse_format_string. | |
117 | format_str[REPORT_MAX_LINE_LENGTH-1] = '\0'; | |
118 | parse_format_string(msg_str, format_str, 3); | |
119 | ||
120 | // Generate the time string. | |
121 | // - tack on simulation time if so desired. | |
122 | if (ReportClass::get_show_simulation_time()) | |
123 | sprintf(time_str, "%d,%d", g_cycle_count, tf_gettime()); | |
124 | else | |
125 | sprintf(time_str, "%d", g_cycle_count); | |
126 | ||
127 | // Generate the location string, shortening the pathname if so desired. | |
128 | if (ReportClass::get_short_pathnames()) { | |
129 | const char * loc_p = strrchr(mip_name, '.'); | |
130 | mip_name = (loc_p == NULL) ? mip_name : ++loc_p; | |
131 | } | |
132 | ||
133 | // Actually make the report. Note that msg_str is always a simple | |
134 | // string at this point, with no format chars. | |
135 | this_report.report(report_type, time_str, mip_name, "%s", msg_str); | |
136 | } else { | |
137 | // no need for strings that won't print. | |
138 | this_report.report(report_type, "", "", "%s", ""); | |
139 | } | |
140 | ||
141 | } | |
142 | } // ReportClass_report | |
143 | ||
144 | ||
145 | // report_verilog_check | |
146 | // | |
147 | // This function is called at the beginning of simulation for each call | |
148 | // made in the design. This allows us to populate an hash table with a | |
149 | // pointer to each {report_type, instance_id} pair. | |
150 | // | |
151 | void report_verilog_check(void) | |
152 | { | |
153 | int nparam; | |
154 | HashValueListNode *key; | |
155 | ||
156 | // first time through | |
157 | if (g_report_hash_table_initialized == 0) { | |
158 | // Instantiate a ReportClass object so we can use it to print and such. | |
159 | //g_internal_reports = new ReportClass(); | |
160 | g_report_hash_table = new HashTable(); | |
161 | g_report_hash_table_initialized++; | |
162 | } | |
163 | ||
164 | // check that we have at least 2 parameters | |
165 | nparam = tf_nump(); | |
166 | if( nparam < 2 ) { | |
167 | tf_error("$report: (%s) line: %d; Too few arguments to ", | |
168 | __FILE__,__LINE__); | |
169 | tf_dofinish(); | |
170 | } | |
171 | ||
172 | // Check that the report's arguments are valid. | |
173 | { | |
174 | const char *index; | |
175 | int nformats = 0; | |
176 | ||
177 | // Check that print format characters belong to the set [hHdDoObBsS] | |
178 | index = tf_getcstringp(2); | |
179 | while( *index ) { | |
180 | if( *index == '%' ) { | |
181 | index++; | |
182 | switch( *index ) { | |
183 | case 'h': case 'H': | |
184 | case 'd': case 'D': | |
185 | case 'o': case 'O': | |
186 | case 'b': case 'B': | |
187 | case 's': case 'S': | |
188 | nformats++; | |
189 | case '%': | |
190 | break; | |
191 | default : { | |
192 | tf_error("$report: (%s) line: %d; Illegal format to : \"%%%c\"", | |
193 | __FILE__,__LINE__, (char)*index); | |
194 | tf_dofinish(); | |
195 | } | |
196 | } // switch() | |
197 | } | |
198 | index++; | |
199 | } | |
200 | ||
201 | ||
202 | // Check that there are at least as many parameters as formats | |
203 | if (nformats > (nparam - 2)) { | |
204 | tf_error("$report: (%s) line: %d: Missing arguments to $report call (%d expected, %d found)", | |
205 | __FILE__,__LINE__, nformats, nparam-2); | |
206 | tf_dofinish(); | |
207 | } | |
208 | } // done checking args | |
209 | ||
210 | { | |
211 | const char *mip_name = tf_mipname(); | |
212 | ReportType report_type = (ReportType)tf_getp(1); | |
213 | ||
214 | if (!is_report_type_valid(report_type)) { | |
215 | tf_error("$report: (%s) line: %d; Invalid report type in %s: %d", | |
216 | __FILE__, __LINE__, mip_name, report_type); | |
217 | } | |
218 | ||
219 | // Build a new hash key for this report and insert it into the table. | |
220 | key = new HashValueListNode(mip_name, report_type); | |
221 | if (key == 0) { | |
222 | tf_error("report_verilog_check:: unable to allocate space for new HashValueListNode"); | |
223 | } | |
224 | ||
225 | // Insert our element into the list | |
226 | if (g_report_hash_table->lookup(*key) == NULL) { | |
227 | key->report_class = new ReportClass(); | |
228 | g_report_hash_table->insert(key); | |
229 | } else { | |
230 | delete key; | |
231 | } | |
232 | } | |
233 | ||
234 | } // report_verilog_check | |
235 | ||
236 | ||
237 | ////////////////////////////////////////////////////////////////// | |
238 | // Wrappers for setting default states. | |
239 | // | |
240 | // Set the *default* print level per type. The change applies to all report | |
241 | // objects for which set_print_level() has not been called previously. | |
242 | void ReportClass_set_default_print_level() { | |
243 | ReportType type = (ReportType) tf_getp(1); | |
244 | PrintLevel pl = (PrintLevel) tf_getp(2); | |
245 | ||
246 | g_internal_reports.set_default_print_level(type, pl); | |
247 | } | |
248 | ||
249 | // Set the *default* error level per type. The change applies to all report | |
250 | // objects for which set_error_level() has not been called previously. | |
251 | void ReportClass_set_default_error_level() { | |
252 | ReportType type = (ReportType) tf_getp(1); | |
253 | ErrorLevel el = (ErrorLevel) tf_getp(2); | |
254 | ||
255 | g_internal_reports.set_default_error_level(type, el); | |
256 | } | |
257 | ||
258 | // Set the *default* table_mode per type. The change applies to all report | |
259 | // objects for which set_table_mode() has not been called previously. | |
260 | void ReportClass_set_default_table_mode() { | |
261 | ReportType type = (ReportType) tf_getp(1); | |
262 | int mode = (int) tf_getp(2); | |
263 | ||
264 | g_internal_reports.set_default_table_mode(type, mode); | |
265 | } | |
266 | ||
267 | ||
268 | //////////////////////////////////////////////////////////////////////////////// | |
269 | // PLI accessors for ReportClass instance variables | |
270 | ||
271 | /* | |
272 | * ReportClass_set_print_level( regexp, report_type, print_level ) | |
273 | * | |
274 | * This function performs the same tasks as "pos_level_control" did for pos_report. | |
275 | * Its arguments are: | |
276 | * | |
277 | * (1) regular expression -- matches the hierarchical paths for which the | |
278 | * print level should be changed | |
279 | * | |
280 | * (2) report type -- the message types which should be changed. Using | |
281 | * ALL_REPORTS as the report type will change the print level for all | |
282 | * messages that match the regexp. | |
283 | * | |
284 | * (3) print level -- the level to which the matching classes should be set | |
285 | * | |
286 | * example: | |
287 | * to suppress all timeout reporting and failures in the "mdu" | |
288 | * instance and all instances beneath it: | |
289 | * | |
290 | * (".*\.mdu\..*", RTYP_TIMEOUT, RPRT_NOP); | |
291 | * | |
292 | * note that because periods are special regular expression characters | |
293 | * they must be escaped. | |
294 | * | |
295 | * If no matches are found for the regex_pattern a warning will be printed. */ | |
296 | void ReportClass_set_print_level() { | |
297 | char *match_pattern = tf_getcstringp(1); | |
298 | ReportType type = (ReportType) tf_getp(2); | |
299 | PrintLevel pl = (PrintLevel) tf_getp(3); | |
300 | int regex_status; | |
301 | int found_match = 0; | |
302 | const HashValueListNode *value = NULL; | |
303 | char prefixed_pattern[REPORT_MAX_FIELD_WIDTH]; | |
304 | ||
305 | // Check that the arguments are valid. | |
306 | if (!is_report_type_valid(type)) | |
307 | tf_error("ReportClass::set_print_level: Invalid report type (%d) to ", type); | |
308 | if (!is_print_level_valid(pl)) | |
309 | tf_error("ReportClass::set_print_level: Invalid print level (%d) to ", pl); | |
310 | ||
311 | ||
312 | strcpy(prefixed_pattern, ReportClass::get_path_prefix()); | |
313 | strncat(prefixed_pattern, match_pattern, REPORT_MAX_FIELD_WIDTH-strlen(prefixed_pattern)); | |
314 | regex_status = regex_match(prefixed_pattern, ""); | |
315 | if (regex_status == 2) { | |
316 | tf_error("ReportClass::set_print_level: Bad regular expression (%s)", prefixed_pattern); | |
317 | tf_dofinish(); | |
318 | } | |
319 | ||
320 | // Walk through the hash, finding entries which match the regexp. | |
321 | g_report_hash_table->start_walk(); | |
322 | while (value = g_report_hash_table->next_element()) { | |
323 | // Attempt to match the stored pathname to the pre-compiled regular expression. | |
324 | regex_status = regex_match(NULL, value->mip_name); | |
325 | ||
326 | // Actually set the print level if we have a match. We have to | |
327 | // construct our own report to tell the user about this, since the | |
328 | // ReportClass itself doesn't know time or location. | |
329 | if (regex_status == 0) { | |
330 | char cycle_str[REPORT_MAX_FIELD_WIDTH]; | |
331 | value->report_class->set_print_level(type, pl, TRUE); // silently -- class doesn't know the path | |
332 | sprintf(cycle_str, "%d", g_cycle_count); | |
333 | g_internal_reports.report(RTYP_REPORT_MSG, | |
334 | cycle_str, value->mip_name, | |
335 | "Setting print level for report type %s to %s", | |
336 | report_type_to_str(value->report_type), | |
337 | print_level_to_str(pl)); | |
338 | found_match = 1; | |
339 | } | |
340 | } | |
341 | ||
342 | if (!found_match) | |
343 | tf_warning("ReportClass (Internal): Could not find match for regular expression \"%s\"\n", prefixed_pattern); | |
344 | ||
345 | } | |
346 | ||
347 | ||
348 | /* | |
349 | * report_set_error_level | |
350 | * | |
351 | * This function sets the error level for a given instance of ReportClass. | |
352 | * It follows the same semantics as "set_print_level" above. | |
353 | */ | |
354 | void ReportClass_set_error_level() | |
355 | { | |
356 | char *match_pattern = tf_getcstringp(1); | |
357 | ReportType type = (ReportType) tf_getp(2); | |
358 | ErrorLevel el = (ErrorLevel) tf_getp(3); | |
359 | int regex_status; | |
360 | int found_match = 0; | |
361 | const HashValueListNode *value = NULL; | |
362 | char prefixed_pattern[REPORT_MAX_FIELD_WIDTH]; | |
363 | ||
364 | // Check that the arguments are valid. | |
365 | if (!is_report_type_valid(type)) | |
366 | tf_error("ReportClass::set_error_level: Invalid report type (%d) to ", type); | |
367 | if (!is_error_level_valid(el)) | |
368 | tf_error("ReportClass::set_error_level: Invalid error level (%d) to ", el); | |
369 | ||
370 | ||
371 | strcpy(prefixed_pattern, ReportClass::get_path_prefix()); | |
372 | strncat(prefixed_pattern, match_pattern, REPORT_MAX_FIELD_WIDTH-strlen(prefixed_pattern)); | |
373 | regex_status = regex_match(match_pattern, ""); | |
374 | if (regex_status == 2) { | |
375 | tf_error("ReportClass::set_error_level): Bad regular expression (%s)", match_pattern); | |
376 | tf_dofinish(); | |
377 | } | |
378 | ||
379 | // Walk through the hash, finding entries which match the regexp. | |
380 | g_report_hash_table->start_walk(); | |
381 | while (value = g_report_hash_table->next_element()) { | |
382 | // Attempt to match the stored pathname to the pre-compiled regular expression. | |
383 | regex_status = regex_match(NULL, value->mip_name); | |
384 | ||
385 | // Actually set table mode for the matching instances. We do this silently. | |
386 | if (regex_status == 0) { | |
387 | char cycle_str[REPORT_MAX_FIELD_WIDTH]; | |
388 | value->report_class->set_error_level(type, el, TRUE); | |
389 | sprintf(cycle_str, "%d", g_cycle_count); | |
390 | g_internal_reports.report(RTYP_REPORT_MSG, | |
391 | cycle_str, value->mip_name, | |
392 | "Setting error level for report type %s to %s", | |
393 | report_type_to_str(value->report_type), | |
394 | error_level_to_str(el)); | |
395 | found_match = 1; | |
396 | } | |
397 | } | |
398 | ||
399 | if (!found_match) | |
400 | tf_warning("ReportClass (Internal): Could not find match for regular expression \"%s\"\n", match_pattern); | |
401 | } | |
402 | ||
403 | ||
404 | /* | |
405 | * ReportClass_set_table_mode | |
406 | * | |
407 | * This function sets the "table mode" parameter for a given instance of ReportClass. | |
408 | * It follows the same semantics as the "set_print_level" function above. | |
409 | * | |
410 | * Placing a particular message type in table mode will: | |
411 | * - remove the prefixes from its output | |
412 | * - remove automatic carriage returns from its output | |
413 | * This might be useful for (duh) printing tables of information, statistics, etc. | |
414 | * | |
415 | */ | |
416 | void ReportClass_set_table_mode() | |
417 | { | |
418 | char *match_pattern = tf_getcstringp(1); | |
419 | ReportType type = (ReportType) tf_getp(2); | |
420 | int table_mode = tf_getp(3); | |
421 | int regex_status; | |
422 | int found_match = 0; | |
423 | const HashValueListNode *value = NULL; | |
424 | char prefixed_pattern[REPORT_MAX_FIELD_WIDTH]; | |
425 | ||
426 | // Check that the arguments are valid. | |
427 | if (!is_report_type_valid(type)) | |
428 | tf_error("ReportClass::set_table_mode: Invalid report type (%d) to ", type); | |
429 | ||
430 | ||
431 | strcpy(prefixed_pattern, ReportClass::get_path_prefix()); | |
432 | strncat(prefixed_pattern, match_pattern, REPORT_MAX_FIELD_WIDTH-strlen(prefixed_pattern)); | |
433 | regex_status = regex_match(match_pattern, ""); | |
434 | if (regex_status == 2) { | |
435 | tf_error("ReportClass::set_table_mode: Bad regular expression (%s)", match_pattern); | |
436 | tf_dofinish(); | |
437 | } | |
438 | ||
439 | // Walk through the hash, finding entries which match the regexp. | |
440 | g_report_hash_table->start_walk(); | |
441 | while (value = g_report_hash_table->next_element()) { | |
442 | // Attempt to match the stored pathname to the pre-compiled regular expression. | |
443 | regex_status = regex_match(NULL, value->mip_name); | |
444 | ||
445 | // Actually set table mode for the matching instances. We do this silently. | |
446 | if (regex_status == 0) { | |
447 | char cycle_str[REPORT_MAX_FIELD_WIDTH]; | |
448 | value->report_class->set_table_mode(type, table_mode, 1); // silently | |
449 | sprintf(cycle_str, "%d", g_cycle_count); | |
450 | g_internal_reports.report(RTYP_REPORT_MSG, | |
451 | cycle_str, value->mip_name, | |
452 | "Setting table mode for report type %s to %s", | |
453 | report_type_to_str(value->report_type), | |
454 | table_mode ? "ON" : "OFF"); | |
455 | found_match = 1; | |
456 | } | |
457 | } | |
458 | ||
459 | if (!found_match) | |
460 | tf_warning("ReportClass (Internal): Could not find match for regular expression \"%s\"\n", match_pattern); | |
461 | } | |
462 | ||
463 | //////////////////////////////////////////////////////////////////////////////// | |
464 | // PLI accessors for ReportClass static variables | |
465 | ||
466 | /* | |
467 | * ReportClass_set_global_print_threshold(int print_level, (int locked_by = REPORT_LOCKED_BY_NO_ONE)) | |
468 | * | |
469 | */ | |
470 | void ReportClass_set_global_print_threshold() | |
471 | { | |
472 | PrintLevel pl = (PrintLevel) tf_getp(1); | |
473 | if (!is_print_level_valid(pl)) | |
474 | tf_error("ReportClass (Internal): Invalid print level %d to ", pl); | |
475 | if (tf_nump() > 1) | |
476 | { | |
477 | // Lock parameter specified -- pass it along to C++. | |
478 | int lock = tf_getp(2); | |
479 | ReportClass::set_global_print_threshold(pl, lock); | |
480 | } | |
481 | else | |
482 | { | |
483 | // No lock specified. | |
484 | ReportClass::set_global_print_threshold(pl); | |
485 | } | |
486 | } | |
487 | ||
488 | /* | |
489 | * ReportClass_get_global_print_threshold | |
490 | * | |
491 | */ | |
492 | void ReportClass_get_global_print_threshold() | |
493 | { | |
494 | tf_putp(0, (int)ReportClass::get_global_print_threshold()); | |
495 | return; | |
496 | } | |
497 | ||
498 | /* | |
499 | * ReportClass_set_max_error_count() | |
500 | * | |
501 | */ | |
502 | void ReportClass_set_max_error_count() | |
503 | { | |
504 | int ec = tf_getp(1); | |
505 | if (ec > 0) | |
506 | ReportClass::set_max_error_count(ec); | |
507 | else | |
508 | tf_error("ReportClass (Internal): Invalid error count (%d) passed to ", ec); | |
509 | } | |
510 | ||
511 | /* | |
512 | * ReportClass_get_max_error_count | |
513 | * | |
514 | */ | |
515 | void ReportClass_get_max_error_count() | |
516 | { | |
517 | tf_putp(0, ReportClass::get_max_error_count()); | |
518 | return; | |
519 | } | |
520 | ||
521 | /* | |
522 | * ReportClass_inc_global_error_count() | |
523 | * | |
524 | */ | |
525 | void ReportClass_inc_global_error_count() | |
526 | { | |
527 | ReportClass::inc_global_error_count(); | |
528 | return; | |
529 | } | |
530 | ||
531 | /* | |
532 | * ReportClass_get_global_error_count | |
533 | */ | |
534 | void ReportClass_get_global_error_count() | |
535 | { | |
536 | tf_putp(0, ReportClass::get_global_error_count()); | |
537 | return; | |
538 | } | |
539 | ||
540 | /* | |
541 | * ReportClass_inc_global_warning_count() | |
542 | */ | |
543 | void ReportClass_inc_global_warning_count() | |
544 | { | |
545 | ReportClass::inc_global_warning_count(); | |
546 | return; | |
547 | } | |
548 | ||
549 | /* | |
550 | * ReportClass_get_global_warning_count() | |
551 | * | |
552 | */ | |
553 | void ReportClass_get_global_warning_count() | |
554 | { | |
555 | tf_putp(0, ReportClass::get_global_warning_count()); | |
556 | return; | |
557 | } | |
558 | ||
559 | /* | |
560 | * ReportClass_set_short_pathnames | |
561 | */ | |
562 | void ReportClass_set_short_pathnames() | |
563 | { | |
564 | ReportClass::set_short_pathnames(tf_getp(1)); | |
565 | return; | |
566 | } | |
567 | ||
568 | /* | |
569 | * ReportClass_get_short_pathnames | |
570 | */ | |
571 | void ReportClass_get_short_pathnames() | |
572 | { | |
573 | tf_putp(0, ReportClass::get_short_pathnames()); | |
574 | return; | |
575 | } | |
576 | ||
577 | /* | |
578 | * ReportClass_set_path_prefix | |
579 | */ | |
580 | void ReportClass_set_path_prefix() | |
581 | { | |
582 | ReportClass::set_path_prefix(tf_getcstringp(1)); | |
583 | return; | |
584 | } | |
585 | ||
586 | /* | |
587 | * ReportClass_get_path_prefix | |
588 | */ | |
589 | void ReportClass_get_path_prefix() | |
590 | { | |
591 | // review: How to return a string value via the PLI? | |
592 | return; | |
593 | } | |
594 | ||
595 | /* | |
596 | * ReportClass_disable_fatal_errors | |
597 | */ | |
598 | void ReportClass_disable_fatal_errors() | |
599 | { | |
600 | ReportClass::disable_fatal_errors(tf_getp(1)); | |
601 | return; | |
602 | } | |
603 | ||
604 | /* | |
605 | * ReportClass_get_num_remaining_nonfatal_cycles | |
606 | */ | |
607 | void ReportClass_get_num_remaining_nonfatal_cycles() | |
608 | { | |
609 | tf_putp(0, ReportClass::get_num_remaining_nonfatal_cycles()); | |
610 | return; | |
611 | } | |
612 | ||
613 | /* | |
614 | * ReportClass_set_show_simulation_time | |
615 | */ | |
616 | void ReportClass_set_show_simulation_time() | |
617 | { | |
618 | ReportClass::set_show_simulation_time(tf_getp(1)); | |
619 | return; | |
620 | } | |
621 | ||
622 | /* | |
623 | * ReportClass_get_show_simulation_time | |
624 | */ | |
625 | void ReportClass_get_show_simulation_time() | |
626 | { | |
627 | tf_putp(0, ReportClass::get_show_simulation_time()); | |
628 | return; | |
629 | } | |
630 | ||
631 | //////////////////////////////////////////////////////////////////////////////// | |
632 | // Other PLI calls | |
633 | ||
634 | /* | |
635 | * report_inc_cycle_count | |
636 | * | |
637 | */ | |
638 | void report_inc_cycle_count() | |
639 | { | |
640 | // Increment the cycle count, which is kept in the PLI as a global. | |
641 | g_cycle_count++; | |
642 | ||
643 | // If the ReportClass has errors disabled, decrement the its number | |
644 | // of remaining nonfatal cycles. | |
645 | if (ReportClass::get_num_remaining_nonfatal_cycles() > 0) { | |
646 | ReportClass::dec_num_remaining_nonfatal_cycles(); | |
647 | } | |
648 | ||
649 | if (g_death_cycle_count && (g_cycle_count >= g_death_cycle_count)) { | |
650 | io_printf("Report:(%0d) [PLI] calling for error which occured at cycle %0d\n", | |
651 | g_cycle_count, g_cycle_count - REPORT_DEATH_CYCLE_DELAY); | |
652 | tf_dofinish(); | |
653 | } | |
654 | } | |
655 | ||
656 | /* | |
657 | * report_set_exit_on_error | |
658 | * | |
659 | */ | |
660 | void report_set_exit_on_error() | |
661 | { | |
662 | int x = tf_getp(1); | |
663 | io_printf("Report:() Setting exit on error to %0d\n", x); | |
664 | g_exit_on_error = x; | |
665 | return; | |
666 | } | |
667 | ||
668 | /* | |
669 | * report_get_exit_on_error | |
670 | * | |
671 | */ | |
672 | void report_get_exit_on_error() | |
673 | { | |
674 | tf_putp(0, g_exit_on_error); | |
675 | return; | |
676 | } | |
677 | ||
678 | //////////////////////////////////////////////////////////////////////////////// | |
679 | // System functions | |
680 | ||
681 | /* | |
682 | * check_number_of_args() | |
683 | * | |
684 | * Called at compile time to ensure that each PLI call is made with | |
685 | * the expected number of arguments. The number of arguments is | |
686 | * specified in the PLI .tab file as a data parameter to this function. | |
687 | * | |
688 | */ | |
689 | void check_number_of_args( long expected_args ) { | |
690 | if( tf_nump() != expected_args ) { | |
691 | tf_error("(%s) line: %d; wrong number of arguments to pli call. expected %d args", | |
692 | __FILE__,__LINE__,expected_args); | |
693 | exit(1); | |
694 | } | |
695 | return; | |
696 | } | |
697 | ||
698 | /* | |
699 | * do_cleanup() | |
700 | * | |
701 | * This function is called at the end of simulation. | |
702 | */ | |
703 | static void do_cleanup(int code) { | |
704 | ||
705 | } | |
706 | ||
707 | /* | |
708 | * set_start_timestamp | |
709 | * | |
710 | * Called at "elaboration time" as a PLI check function for print_cycles_per_second. | |
711 | * Places the wall-clock time into a global variable for calculation the CPS of this sim. | |
712 | * | |
713 | */ | |
714 | void set_start_timestamp() | |
715 | { | |
716 | start_time = times(&start_tmsbuf); | |
717 | } | |
718 | ||
719 | /* | |
720 | * print_cycles_per_second | |
721 | * | |
722 | * Called by report_test_complete() in Vera land to output | |
723 | * the performance in cycles/sec for this simulation. | |
724 | * | |
725 | */ | |
726 | void report_print_cycles_per_second() | |
727 | { | |
728 | clock_t end_time; | |
729 | struct tms end_tmsbuf; | |
730 | double cps_cpu; | |
731 | double elapsed_time_cpu; | |
732 | char *top; | |
733 | ||
734 | end_time = times(&end_tmsbuf); | |
735 | ||
736 | // Total CPU Time is sum of user and system CPU time for calling and child processes | |
737 | elapsed_time_cpu = (double) ((end_tmsbuf.tms_utime - start_tmsbuf.tms_utime) + // Calling Process User Time | |
738 | (end_tmsbuf.tms_stime - start_tmsbuf.tms_stime) + // Calling Process System Time | |
739 | (end_tmsbuf.tms_cutime - start_tmsbuf.tms_cutime) + // Child Processes User Time | |
740 | (end_tmsbuf.tms_cstime - start_tmsbuf.tms_cstime)) // Child Processes System Time | |
741 | / CLK_TCK ; // Divide by clock ticks per second | |
742 | ||
743 | // Avoid division by zero, make sure elapsed time is at least 1/CLK_TCK seconds | |
744 | if (elapsed_time_cpu <= 0) | |
745 | elapsed_time_cpu = 1/CLK_TCK; | |
746 | ||
747 | cps_cpu = g_cycle_count/elapsed_time_cpu; | |
748 | ||
749 | top = (char *)sbrk(0); | |
750 | ||
751 | io_printf("Report:: Total CPU Time (seconds): %0.2f\n", elapsed_time_cpu); | |
752 | io_printf("Report:: Effective cycles per second: %0.2f\n", cps_cpu); | |
753 | io_printf("Report:: Apparent virtual memory size: %d bytes\n", top); | |
754 | io_printf("================================================================================\n\n"); | |
755 | } | |
756 | ||
757 | ||
758 | #ifdef __cplusplus | |
759 | } | |
760 | #endif |