Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | // ========== Copyright Header Begin ========================================== |
2 | // | |
3 | // OpenSPARC T2 Processor File: cMesg.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 | ||
37 | enum Mesg_level = | |
38 | e_mesg_error, | |
39 | e_mesg_warning, | |
40 | e_mesg_info, | |
41 | e_mesg_debug1, | |
42 | e_mesg_debug2, | |
43 | e_mesg_debug3, | |
44 | e_mesg_debug4; | |
45 | ||
46 | class Mesg { | |
47 | local Mesg_level f_debug_level; | |
48 | ||
49 | static local integer f_error_count; | |
50 | static local integer f_warning_count; | |
51 | ||
52 | function Mesg_level get_debug_level (); | |
53 | function integer get_error_count (); | |
54 | function integer get_warning_count (); | |
55 | ||
56 | task new(Mesg_level level = e_mesg_info); | |
57 | task set_debug_level (Mesg_level level); | |
58 | ||
59 | task print(Mesg_level level, | |
60 | string id = "", | |
61 | string src, | |
62 | string fmt, | |
63 | (bit [511:0] fmt_arg0 = 0, | |
64 | bit [511:0] fmt_arg1 = 0, | |
65 | bit [511:0] fmt_arg2 = 0, | |
66 | bit [511:0] fmt_arg3 = 0, | |
67 | bit [511:0] fmt_arg4 = 0, | |
68 | bit [511:0] fmt_arg5 = 0, | |
69 | bit [511:0] fmt_arg6 = 0, | |
70 | bit [511:0] fmt_arg7 = 0, | |
71 | bit [511:0] fmt_arg8 = 0, | |
72 | bit [511:0] fmt_arg9 = 0) | |
73 | ); | |
74 | ||
75 | task print_test_complete(); | |
76 | } | |
77 | ||
78 | task Mesg::new(Mesg_level level = e_mesg_info) { | |
79 | f_error_count = 0; | |
80 | f_warning_count = 0; | |
81 | f_debug_level = e_mesg_info; | |
82 | ||
83 | set_debug_level (level); | |
84 | } | |
85 | ||
86 | /* | |
87 | * error count | |
88 | */ | |
89 | function integer Mesg::get_error_count () { | |
90 | get_error_count = f_error_count; | |
91 | } | |
92 | ||
93 | /* | |
94 | * warning count | |
95 | */ | |
96 | function integer Mesg::get_warning_count () { | |
97 | get_warning_count = f_warning_count; | |
98 | } | |
99 | ||
100 | /* | |
101 | * I wish we could make this callable only ONCE, no ?? | |
102 | */ | |
103 | task Mesg::set_debug_level (Mesg_level level) { | |
104 | string level_str; | |
105 | ||
106 | if (level < e_mesg_warning) | |
107 | print(e_mesg_error, | |
108 | *, | |
109 | "Mesg::set_debug_level", | |
110 | "Can not set debug level < e_mesg_warning"); | |
111 | else { | |
112 | sprintf(level_str, "Set debug level to %s", level); | |
113 | print(e_mesg_info, | |
114 | *, | |
115 | "Mesg::set_debug_level", | |
116 | level_str); | |
117 | } | |
118 | ||
119 | f_debug_level = level; | |
120 | } | |
121 | ||
122 | /* | |
123 | * Return debug level | |
124 | */ | |
125 | function Mesg_level Mesg::get_debug_level () { | |
126 | get_debug_level = f_debug_level; | |
127 | } | |
128 | ||
129 | /* | |
130 | * print(level, id_string, src_string, fmt_string, [int] ...10... [int]); | |
131 | * | |
132 | * Input: | |
133 | * level: | |
134 | * e_mesg_error (increments error count) | |
135 | * e_mesg_warning (increments warning count) | |
136 | * e_mesg_info | |
137 | * e_mesg_debug1 | |
138 | * e_mesg_debug2 | |
139 | * e_mesg_debug3 | |
140 | * | |
141 | * id_string: | |
142 | * eg, "xtr1" | |
143 | * | |
144 | * src_string: | |
145 | * eg, "class::method" | |
146 | * | |
147 | * fmt_string: | |
148 | * Formatted output: string (%s %S) | |
149 | * bin (%b %B) | |
150 | * dec (%d %D), | |
151 | * hex (%h %H %x %X) | |
152 | * oct (%o %O) | |
153 | * Field width specifiers ignored (eg, %2d). | |
154 | * | |
155 | * Up to 10 optional arguments, int or castable to int, or string. | |
156 | * | |
157 | * Output: | |
158 | * Error, warning and info messages cannot be turned off. | |
159 | * | |
160 | * Debug statements output only if mesg_debug_level <= set_debug_level, otherwise | |
161 | * absolutely nothing happens. | |
162 | * | |
163 | * Minimum field widths used. | |
164 | * | |
165 | * Format type letter follows argument, except integers, eg: 20, 110001b, 32fah, 7403o | |
166 | * | |
167 | * Newline automaticly inserted, but additional ones are acceptable. | |
168 | * | |
169 | * e_mesg_error: | |
170 | * *** ERROR [hi_time][lo_time]<id_str><src_str> formatted_message_str | |
171 | * | |
172 | * e_mesg_warning: | |
173 | * WARNING [hi_time][lo_time]<id_str><src_str> formatted_message_str | |
174 | * | |
175 | * e_mesg_info, e_mesg_debug#: | |
176 | * [hi_time][lo_time]<id_str><src_str> formatted_message_str | |
177 | */ | |
178 | task Mesg::print (Mesg_level level, | |
179 | string id_str = "", | |
180 | string src_str, | |
181 | string fmt_str, | |
182 | (bit [511:0] fmt_arg0 = 0, | |
183 | bit [511:0] fmt_arg1 = 0, | |
184 | bit [511:0] fmt_arg2 = 0, | |
185 | bit [511:0] fmt_arg3 = 0, | |
186 | bit [511:0] fmt_arg4 = 0, | |
187 | bit [511:0] fmt_arg5 = 0, | |
188 | bit [511:0] fmt_arg6 = 0, | |
189 | bit [511:0] fmt_arg7 = 0, | |
190 | bit [511:0] fmt_arg8 = 0, | |
191 | bit [511:0] fmt_arg9 = 0) | |
192 | ) { | |
193 | integer time_lo, time_hi; | |
194 | integer i, fmt_char, next_char, fmt_arg_idx = 0, mesg_idx = 0, j, pad_cnt, got_cnt; | |
195 | bit is_x; | |
196 | bit [511:0] fmt_args[10]; | |
197 | string pre_mesg_str, mesg_str, tmp_str; | |
198 | ||
199 | /* | |
200 | * If level is less than the specified debug level, | |
201 | * we want to process this thing, else do absolutely nothing. | |
202 | */ | |
203 | if (level <= f_debug_level) { | |
204 | /* | |
205 | * Put the args in the arg array | |
206 | */ | |
207 | fmt_args[0] = fmt_arg0; | |
208 | fmt_args[1] = fmt_arg1; | |
209 | fmt_args[2] = fmt_arg2; | |
210 | fmt_args[3] = fmt_arg3; | |
211 | fmt_args[4] = fmt_arg4; | |
212 | fmt_args[5] = fmt_arg5; | |
213 | fmt_args[6] = fmt_arg6; | |
214 | fmt_args[7] = fmt_arg7; | |
215 | fmt_args[8] = fmt_arg8; | |
216 | fmt_args[9] = fmt_arg9; | |
217 | ||
218 | /* | |
219 | * Get the verilog time | |
220 | */ | |
221 | time_lo = get_time(LO); | |
222 | time_hi = get_time(HI); | |
223 | ||
224 | /* | |
225 | * Assemble pre_mesg | |
226 | */ | |
227 | ||
228 | // verilog time | |
229 | if (time_hi == 0) | |
230 | sprintf(pre_mesg_str, "%0d ", time_lo); | |
231 | else | |
232 | sprintf(pre_mesg_str, "%0d%0d ", time_hi, time_lo); | |
233 | ||
234 | // message level | |
235 | if (level == e_mesg_error) { | |
236 | tmp_str = "ERROR "; | |
237 | f_error_count++; | |
238 | } | |
239 | else if (level == e_mesg_warning) { | |
240 | tmp_str = "WARNING "; | |
241 | f_warning_count++; | |
242 | } | |
243 | else if (level == e_mesg_info) | |
244 | tmp_str = "INFO "; | |
245 | else if (level == e_mesg_debug1) | |
246 | tmp_str = "DEBUG1 "; | |
247 | else if (level == e_mesg_debug2) | |
248 | tmp_str = "DEBUG2 "; | |
249 | else if (level == e_mesg_debug3) | |
250 | tmp_str = "DEBUG3 "; | |
251 | else if (level == e_mesg_debug4) | |
252 | tmp_str = "DEBUG4 "; | |
253 | ||
254 | // put message level in pre-mesg | |
255 | pre_mesg_str = { pre_mesg_str, tmp_str }; | |
256 | ||
257 | // source | |
258 | if (id_str.len() == 0) | |
259 | sprintf(tmp_str, "%s ", src_str); | |
260 | else | |
261 | sprintf(tmp_str, "%s %s ", id_str, src_str); | |
262 | ||
263 | // put source in pre-mesg | |
264 | pre_mesg_str = { pre_mesg_str, tmp_str }; | |
265 | ||
266 | /* | |
267 | * Now process the format (fmt_str). | |
268 | * Assemble the message (mesg_str). | |
269 | */ | |
270 | for (i = 0; i < fmt_str.len(); i++, mesg_idx++) { | |
271 | next_char = fmt_str.getc(i); | |
272 | ||
273 | // If the char is anything but %, we want to print it to the mesg | |
274 | if (next_char != 37) | |
275 | sprintf(tmp_str, "%c", next_char); | |
276 | ||
277 | // If the char is %, then print the next arg to the mesg | |
278 | else { | |
279 | got_cnt = 0; //tells if a pad count was received -- acts as a Boolean | |
280 | // The next fmt_char may have the format | |
281 | fmt_char = fmt_str.getc(++i); | |
282 | ||
283 | // If the fmt_char is an integer, then this is a case s.a. %2d, so | |
284 | // save the number | |
285 | ||
286 | if ( (fmt_char >= 32'h30) && (fmt_char <= 32'h39) ){ | |
287 | // j = the number of spaces wanted | |
288 | j = fmt_char - 32'h30; | |
289 | // Save this number of spaces and then increment to the next character | |
290 | // which will be the type. | |
291 | fmt_char = fmt_str.getc(++i); | |
292 | got_cnt = 1; | |
293 | } | |
294 | // If the fmt arg has any x's, we must print %b format, so override fmt_arg | |
295 | is_x = ^fmt_args[fmt_arg_idx]; | |
296 | if (is_x === 1'bx) | |
297 | fmt_char = 32'h42; | |
298 | ||
299 | case (fmt_char) { | |
300 | // %b | |
301 | 32'h42, 32'h62:{ | |
302 | sprintf(tmp_str, "%0bb", fmt_args[fmt_arg_idx++]); | |
303 | pad_cnt = ( j + 1 - tmp_str.len() ); | |
304 | } | |
305 | // %c | |
306 | 32'h43, 32'h63:{ | |
307 | sprintf(tmp_str, "%0c", fmt_args[fmt_arg_idx++]); | |
308 | pad_cnt = ( j - tmp_str.len() ); | |
309 | } | |
310 | // %d | |
311 | 32'h44, 32'h64:{ | |
312 | sprintf(tmp_str, "%0d", fmt_args[fmt_arg_idx++]); | |
313 | pad_cnt = ( j - tmp_str.len() ); | |
314 | } | |
315 | // %h, %x | |
316 | 32'h48, 32'h58, 32'h68, 32'h78:{ | |
317 | sprintf(tmp_str, "%0hh", fmt_args[fmt_arg_idx++]); | |
318 | pad_cnt = ( j + 1 - tmp_str.len() ); | |
319 | } | |
320 | // %o | |
321 | 32'h4f, 32'h6f:{ | |
322 | sprintf(tmp_str, "%0oo", fmt_args[fmt_arg_idx++]); | |
323 | pad_cnt = ( j + 1 - tmp_str.len() ); | |
324 | } | |
325 | // %s | |
326 | 32'h53, 32'h73:{ | |
327 | sprintf(tmp_str, "%0s", fmt_args[fmt_arg_idx++]); | |
328 | pad_cnt = ( j - tmp_str.len() ); | |
329 | } | |
330 | // something is wrong | |
331 | default: { | |
332 | sprintf(tmp_str, "NO_FMT"); | |
333 | fmt_arg_idx++; | |
334 | } | |
335 | } | |
336 | ||
337 | // If user requested a field width and the argument didn't take up | |
338 | // the whole field, pad with zeroes for nums, and spaces for strings. | |
339 | if (( got_cnt == 1 ) && ( pad_cnt > 0 )) { | |
340 | if ((fmt_char == 32'h53) || (fmt_char == 32'h73)) | |
341 | tmp_str = { {pad_cnt {" "} }, tmp_str }; | |
342 | else | |
343 | tmp_str = { {pad_cnt {"0"} }, tmp_str }; | |
344 | } | |
345 | } | |
346 | ||
347 | // Concatenate the arg, or the next char in fmt, either way it is in | |
348 | // tmp_str, to the message str | |
349 | mesg_str = { mesg_str, tmp_str }; | |
350 | } | |
351 | ||
352 | // Finally, print the freakin message! | |
353 | printf("%s%s\n", pre_mesg_str, mesg_str); | |
354 | } | |
355 | } | |
356 | ||
357 | /* | |
358 | * Test complete standard format. | |
359 | */ | |
360 | task Mesg::print_test_complete() { | |
361 | // Change the debug level to info in case it is currently < info, in whic | |
362 | // case this TEST COMPLETE message won't be printed. Also, save the current | |
363 | // level and restore it, just in case someone is calling this within a | |
364 | // test for some reason, I can't necessarily assume this will only be called | |
365 | // when the test exits. | |
366 | Mesg_level prev = f_debug_level; | |
367 | f_debug_level = e_mesg_info; | |
368 | printf("\n"); | |
369 | if ( get_error_count() == 0 ) { | |
370 | print(e_mesg_info, | |
371 | " ", | |
372 | " ", | |
373 | "Simulation reach GOOD End\n"); | |
374 | os_command("banner PASS"); | |
375 | } | |
376 | else | |
377 | { | |
378 | print(e_mesg_info, | |
379 | " ", | |
380 | " ", | |
381 | "TEST COMPLETE. TOTAL ERRORS: %d TOTAL WARNINGS: %d\n", | |
382 | get_error_count(), get_warning_count()); | |
383 | os_command("banner FAIL"); | |
384 | } | |
385 | ||
386 | f_debug_level = prev; | |
387 | ||
388 | } |