Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | /* |
2 | * ========== Copyright Header Begin ========================================== | |
3 | * | |
4 | * OpenSPARC T2 Processor File: monitor.c | |
5 | * Copyright (C) 1995-2007 Sun Microsystems, Inc. All Rights Reserved | |
6 | * 4150 Network Circle, Santa Clara, California 95054, U.S.A. | |
7 | * | |
8 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License as published by | |
12 | * the Free Software Foundation; version 2 of the License. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this program; if not, write to the Free Software | |
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
22 | * | |
23 | * For the avoidance of doubt, and except that if any non-GPL license | |
24 | * choice is available it will apply instead, Sun elects to use only | |
25 | * the General Public License version 2 (GPLv2) at this time for any | |
26 | * software where a choice of GPL license versions is made | |
27 | * available with the language indicating that GPLv2 or any later version | |
28 | * may be used, or where a choice of which version of the GPL is applied is | |
29 | * otherwise unspecified. | |
30 | * | |
31 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | |
32 | * CA 95054 USA or visit www.sun.com if you need additional information or | |
33 | * have any questions. | |
34 | * | |
35 | * | |
36 | * ========== Copyright Header End ============================================ | |
37 | */ | |
38 | #include <stdio.h> | |
39 | #include <stdlib.h> | |
40 | #include <string.h> | |
41 | #include <stdarg.h> | |
42 | ||
43 | //#include "public_platform.h" | |
44 | #include "veriuser.h" | |
45 | #include "vcsuser.h" | |
46 | #include "hasher.h" | |
47 | //#include "saverestore.h" | |
48 | #include "monitor.h" | |
49 | ||
50 | #define MAXTAGS 50 | |
51 | ||
52 | #define NO_MON_TYPE (0) | |
53 | #define WARNING_MON_TYPE (1) | |
54 | #define ERROR_MON_TYPE (2) | |
55 | #define NORMAL_MON_TYPE (3) | |
56 | #define INFO_MON_TYPE (4) | |
57 | #define DEBUG_MON_TYPE (5) | |
58 | #define ALWAYS_MON_TYPE (3) | |
59 | ||
60 | int ch_dispmon(char *l_unit_name, int l_tag, int l_value); | |
61 | ||
62 | typedef struct unit_info | |
63 | { | |
64 | char *unit; | |
65 | unsigned int enable[MAXTAGS]; | |
66 | } UnitInfo; | |
67 | ||
68 | typedef struct monitor_state { | |
69 | int global_errors; | |
70 | int global_warnings; | |
71 | int max_warnings; | |
72 | int max_errors; | |
73 | int external_finish; | |
74 | int finish_pending; | |
75 | int finish_type; | |
76 | int newLine; /* 1 if last char written was \n, 0 otherwise */ | |
77 | HASH_TBL *unit_tbl; | |
78 | UnitInfo default_unit; | |
79 | } monitor_state_t; | |
80 | ||
81 | /* All monitor state is kept in this struct to simplify | |
82 | save and restore. The whole struct is saved at once. | |
83 | New state may be added to the struct without needing | |
84 | to modify the save/restore code. | |
85 | */ | |
86 | static monitor_state_t ms = {0,0,1,1,1,0,0,1,NULL, | |
87 | /* default unit: */ | |
88 | {"default", | |
89 | {1,0,0,0,0,0,0,0,0,0, | |
90 | 0,0,0,0,0,0,0,0,0,0, | |
91 | 0,0,0,0,0,0,0,0,0,0, | |
92 | 1,1,1,1,1,1,1,1,1,1, | |
93 | 1,1,1,1,1,1,1,1,1,1}} | |
94 | /* end default unit */ | |
95 | }; | |
96 | ||
97 | static const char *modulename = "monitor.c"; | |
98 | static const char *has_nfld="bBoOdDhHsxX"; | |
99 | static const char *no_nparam="%mt"; | |
100 | ||
101 | /* Tag values are defined as follows: | |
102 | * 1-19 default Disabled, displays: <time>: DBG: <unit>[module]: formatted_data | |
103 | * 20-29 default disabled, displays: <time>:INFO: <unit>[module]: formatted_data | |
104 | * 31-47 default Enabled, displays: <time>: <unit>[<module>]: formatted_data | |
105 | * 48 default enabled,displays: <time>: WARNING: <unit>[<module>]:formatted_data | |
106 | * 49 default enabled, displays: <time>: ERROR: <unit>[<module>]: formatted_data | |
107 | * this is now essentially hardwired | |
108 | * (It used to be configurable by unit but we've eliminated the syntax | |
109 | which does that) | |
110 | */ | |
111 | ||
112 | ||
113 | ||
114 | /*---------------------------------------------------------------------------- | |
115 | * static int | |
116 | * UnitInfo_cmp(const void *p_a, const void *p_b) | |
117 | * comparison function for UnitInfo, qsort friendly | |
118 | * | |
119 | * Return Value -- | |
120 | * -1 if a<b, 0 if a==b, 1 if a>b | |
121 | * | |
122 | * Design -- | |
123 | * compares UnitInfo based solely on the unit name | |
124 | * | |
125 | * Side effects -- | |
126 | * No side effects | |
127 | *---------------------------------------------------------------------------- | |
128 | */ | |
129 | static int | |
130 | UnitInfo_cmp(const void *p_a, const void *p_b) | |
131 | { | |
132 | const UnitInfo *l_ua=(const UnitInfo *)p_a; | |
133 | const UnitInfo *l_ub=(const UnitInfo *)p_b; | |
134 | ||
135 | return strcmp(l_ua->unit, l_ub->unit); | |
136 | } | |
137 | ||
138 | /* int monitor_SAVE_RESTORE(int user_data, int reason) | |
139 | * | |
140 | * This is called during a save or a restore; it causes the monitor | |
141 | * to save itself or restore itself. Arguments and return value | |
142 | * match those of a misctf call, though this is not called from | |
143 | * the simulator, but from saverestore.c | |
144 | */ | |
145 | ||
146 | /* | |
147 | * N2 - Not using this right now. Need saverestore from | |
148 | * vobs/valid-east/simulator/saverestore/ to make this work .. | |
149 | */ | |
150 | ||
151 | // int monitor_SAVE_RESTORE(int user_data, int reason) { | |
152 | // UnitInfo **unit_list; | |
153 | // int num_units; | |
154 | // | |
155 | // if(reason==reason_save) | |
156 | // { | |
157 | // /* save top level monitor_state_t struct */ | |
158 | // PLI_SAVE("monitor", &ms, sizeof(ms)); | |
159 | // | |
160 | // /* obtain a list of unitInfos from the hash table */ | |
161 | // unit_list = ht_sorted_list(ms.unit_tbl, UnitInfo_cmp); | |
162 | // | |
163 | // /* find and store the length of the list */ | |
164 | // for(num_units=0; unit_list[num_units]!=NULL; num_units++) | |
165 | // { } | |
166 | // PLI_SAVE("monitor", &num_units, sizeof(num_units)); | |
167 | // | |
168 | // /* store each unitInfo */ | |
169 | // while(num_units > 0) | |
170 | // { | |
171 | // int len; | |
172 | // | |
173 | // num_units--; | |
174 | // | |
175 | // /* save each unitInfo's struct */ | |
176 | // PLI_SAVE("monitor", unit_list[num_units], sizeof(UnitInfo) ); | |
177 | // | |
178 | // /* save the unit name */ | |
179 | // len = strlen(unit_list[num_units]->unit) + 1; | |
180 | // PLI_SAVE("monitor", &len, sizeof(len)); | |
181 | // PLI_SAVE("monitor", unit_list[num_units]->unit, sizeof(char) * len); | |
182 | // } | |
183 | // | |
184 | // free(unit_list); | |
185 | // } | |
186 | // else if(reason==reason_restart) | |
187 | // { | |
188 | // /* restore top level monitor_state_t struct */ | |
189 | // PLI_RESTORE("monitor", &ms, sizeof(ms)); | |
190 | // | |
191 | // /* allocate a hash table */ | |
192 | // ms.unit_tbl = ht_new(256); | |
193 | // | |
194 | // /* restore the number of unit_infos */ | |
195 | // PLI_RESTORE("monitor", &num_units, sizeof(num_units)); | |
196 | // | |
197 | // while(num_units > 0) | |
198 | // { | |
199 | // int len; | |
200 | // UnitInfo *unit = malloc(sizeof(UnitInfo)); | |
201 | // num_units--; | |
202 | // | |
203 | // /* restore the unitInfo's struct */ | |
204 | // PLI_RESTORE("monitor", unit, sizeof(UnitInfo)); | |
205 | // | |
206 | // /* restore the unit name */ | |
207 | // PLI_RESTORE("monitor", &len, sizeof(len)); | |
208 | // unit->unit = malloc(sizeof(char) * len); | |
209 | // PLI_RESTORE("monitor", unit->unit, sizeof(char) * len); | |
210 | // | |
211 | // /* put it in the hash table */ | |
212 | // ht_put(ms.unit_tbl, unit->unit, unit); | |
213 | // } | |
214 | // } | |
215 | // | |
216 | // return 0; /* not meaningful */ | |
217 | // } | |
218 | ||
219 | ||
220 | ||
221 | ||
222 | /*---------------------------------------------------------------------------- | |
223 | * static UnitInfo * | |
224 | * UnitInfo_new(const char *p_unitname) | |
225 | * Constructor for UnitInfo, which tracks which tags are enabled | |
226 | * | |
227 | * Return Value -- | |
228 | * A UnitInfo structure | |
229 | * | |
230 | * Design -- | |
231 | * It tries to allocate some memory and copies the default info into it | |
232 | * | |
233 | * Side effects -- | |
234 | * No side effects | |
235 | *---------------------------------------------------------------------------- | |
236 | */ | |
237 | static UnitInfo * | |
238 | UnitInfo_new(const char *p_unitname) | |
239 | { | |
240 | UnitInfo *l_r=(UnitInfo*)malloc(sizeof *l_r); | |
241 | if(!l_r) | |
242 | { | |
243 | printf("ERROR(%s):No memory to allocate unit info",modulename); | |
244 | exit(1); | |
245 | } | |
246 | l_r->unit=strdup(p_unitname); | |
247 | memmove(l_r->enable, ms.default_unit.enable, sizeof l_r->enable); | |
248 | return l_r; | |
249 | } | |
250 | ||
251 | /*---------------------------------------------------------------------------- | |
252 | * void scan_n_chdispmon | |
253 | * | |
254 | * Takes a string of the form | |
255 | * +mon+<unit>=<level>=<value>(,<unit>=<level>=<value>)* | |
256 | * and does ch_dispmon for all spcified units .. | |
257 | * | |
258 | *---------------------------------------------------------------------------- | |
259 | */ | |
260 | static void scan_n_chdispmon (char *str) { | |
261 | ||
262 | int level, value; | |
263 | char *argseq, unit [36]; | |
264 | ||
265 | argseq = strtok(str, ","); | |
266 | while (argseq != NULL) { | |
267 | if (3 == sscanf(argseq, "%[a-z_0-9]=%d=%d", unit, &level, &value)) { | |
268 | ch_dispmon(unit, level, value); | |
269 | } else { | |
270 | cDispmon ("disp", MON_WARN, "Format incorrect in monitor spec \"%s\" - ignored", | |
271 | argseq); | |
272 | } | |
273 | argseq = strtok(NULL, ","); | |
274 | } | |
275 | } | |
276 | ||
277 | /*---------------------------------------------------------------------------- | |
278 | * int parse_ch_dispmon | |
279 | * | |
280 | * Entry point for $parse_ch_dispmon | |
281 | *---------------------------------------------------------------------------- | |
282 | */ | |
283 | ||
284 | int parse_ch_dispmon(void) | |
285 | { | |
286 | if (tf_nump() != 1) { | |
287 | printf("ERROR(parse_ch_dispmon): Usage: " | |
288 | "$parse_ch_dispmon(\"<unit>=<level>=<0/1>(,<unit>=<level>=<0/1>)*\"\n"); | |
289 | } else { | |
290 | char *l_string=tf_getcstringp(1); | |
291 | scan_n_chdispmon(l_string); | |
292 | } | |
293 | return 0; | |
294 | } | |
295 | ||
296 | /*---------------------------------------------------------------------------- | |
297 | * static void | |
298 | * parse_dispmon_plusargs() | |
299 | * parse command line plus args for dispmon, +maxerror, +maxwarning | |
300 | * +debug_all +mon+<name>+<level> | |
301 | * | |
302 | * Return Value -- | |
303 | * none | |
304 | * | |
305 | * Design -- | |
306 | * looks at plusargs, sets variable values | |
307 | * | |
308 | * Side effects -- | |
309 | * sets max_errors and max_warnings and updates hash tables | |
310 | *---------------------------------------------------------------------------- | |
311 | */ | |
312 | static void | |
313 | parse_dispmon_plusargs() | |
314 | { | |
315 | char *l_cp; | |
316 | char *m_cp; | |
317 | int n; | |
318 | ||
319 | // Max err/warn check | |
320 | if (!((l_cp=mc_scan_plusargs("maxerror=")) || | |
321 | (l_cp=mc_scan_plusargs("maxerror"))) || | |
322 | !(ms.max_errors=strtoul(l_cp, 0,10))) | |
323 | { | |
324 | cDispmon("disp", MON_NORMAL, "Can't find valid +maxerror arg, setting to 1"); | |
325 | ms.max_errors = 1; | |
326 | } | |
327 | ||
328 | if (!((l_cp=mc_scan_plusargs("maxwarning=")) || | |
329 | (l_cp=mc_scan_plusargs("maxwarning"))) || | |
330 | !(ms.max_warnings=strtoul(l_cp, 0,10))) | |
331 | { | |
332 | cDispmon("disp", MON_NORMAL, "Can't find valid +maxwarning arg, setting to 5"); | |
333 | ms.max_warnings = 5; | |
334 | } | |
335 | ||
336 | // Debug mode for all | |
337 | if (mc_scan_plusargs("debug_all")) { | |
338 | cDispmon("disp", MON_NORMAL, "Detected global debug mode request. Setting all units"); | |
339 | ch_dispmon("all", MON_DEBUG, 1); | |
340 | } | |
341 | ||
342 | // Info mode for all | |
343 | if (mc_scan_plusargs("info_all")) { | |
344 | cDispmon("disp", MON_NORMAL, "Detected global info mode request. Setting all units"); | |
345 | ch_dispmon("all", MON_INFO, 1); | |
346 | } | |
347 | ||
348 | // Parse generic options of the form | |
349 | // +mon+<unit>=<level>=<value>(,<unit>=<level>=<value>)* | |
350 | l_cp = mc_scan_plusargs("mon+"); | |
351 | if (!(l_cp == NULL)) { | |
352 | n = strlen(l_cp); | |
353 | m_cp = (char*)malloc(sizeof(char) * n); | |
354 | strcpy(m_cp,l_cp); | |
355 | cDispmon ("disp", MON_NORMAL, "Scanned Monitors specification: %s", m_cp); | |
356 | scan_n_chdispmon(m_cp); | |
357 | } | |
358 | ||
359 | // Quiet mode - overrides all | |
360 | if (mc_scan_plusargs("quiet") && !mc_scan_plusargs("noquiet")) { | |
361 | cDispmon("disp", MON_NORMAL, "Detected global quiet mode request."); | |
362 | ch_dispmon("all", MON_ERR, 1); | |
363 | ch_dispmon("all", MON_NORMAL, 0); | |
364 | } | |
365 | ||
366 | } | |
367 | ||
368 | /*---------------------------------------------------------------------------- | |
369 | * static void | |
370 | * init_unit_tbl() | |
371 | * initializes the hash table used to hold units | |
372 | * | |
373 | * Return Value -- | |
374 | * none | |
375 | * | |
376 | * Design -- | |
377 | * calls the hash package to get a hash table, puts in default unit | |
378 | * calls parse_dispmon_plusargs | |
379 | * | |
380 | * Side effects -- | |
381 | * sets unit_tbl | |
382 | *---------------------------------------------------------------------------- | |
383 | */ | |
384 | static void | |
385 | init_unit_tbl() | |
386 | { | |
387 | ms.unit_tbl=ht_new(256); | |
388 | ht_put(ms.unit_tbl, "default", &ms.default_unit); | |
389 | parse_dispmon_plusargs(); | |
390 | } | |
391 | ||
392 | /*---------------------------------------------------------------------------- | |
393 | * static int | |
394 | * tag2mon_type(int p_tag) | |
395 | * give a tag, return a tag type | |
396 | * | |
397 | * Return Value -- | |
398 | * tag type | |
399 | * | |
400 | * Design -- | |
401 | * Figures out tag type based on tag number | |
402 | * | |
403 | * Side effects -- | |
404 | * none | |
405 | *---------------------------------------------------------------------------- | |
406 | */ | |
407 | static int | |
408 | tag2mon_type(int p_tag) | |
409 | { | |
410 | return ((p_tag >= MON_NORMAL && p_tag<=MON_WARN)) ? NORMAL_MON_TYPE : | |
411 | (p_tag == MON_ALWAYS) ? ALWAYS_MON_TYPE : | |
412 | (p_tag < MON_INFO) ? DEBUG_MON_TYPE : | |
413 | (p_tag < MON_NORMAL) ? INFO_MON_TYPE : | |
414 | (p_tag == MON_WARN) ? WARNING_MON_TYPE : | |
415 | (p_tag == MON_ERR) ? ERROR_MON_TYPE : | |
416 | NO_MON_TYPE; | |
417 | } | |
418 | ||
419 | /*---------------------------------------------------------------------------- | |
420 | * static void | |
421 | * smart_write_tagged_output(char *p_tag_string, char *p_message, | |
422 | * int p_add_newline) | |
423 | * prints out tag_string if the global newLine variable is set, | |
424 | * then replaces any \n$text in message with \n$tag_string$text | |
425 | * | |
426 | * Return Value -- | |
427 | * none | |
428 | * | |
429 | * Design -- | |
430 | * prints everything up to the newline, if there is a newline, | |
431 | * prints the tag_string, repeat. Then print what's left | |
432 | * | |
433 | * Side effects -- | |
434 | * sets newLine if last char printed is a newline | |
435 | * modifies p_message | |
436 | *---------------------------------------------------------------------------- | |
437 | */ | |
438 | static void | |
439 | smart_write_tagged_output(char *p_tag_string, char *p_message, | |
440 | int p_add_newline) | |
441 | { | |
442 | char *l_pos; | |
443 | char *l_next; | |
444 | size_t l_buflen=strlen(p_message); | |
445 | l_pos = p_message; | |
446 | while ((l_next=strchr(l_pos,'\n'))!=0) | |
447 | { | |
448 | *l_next=0; | |
449 | if (ms.newLine) | |
450 | printf("%s", p_tag_string); | |
451 | printf("%s\n",l_pos); | |
452 | l_pos=l_next+1; | |
453 | ms.newLine=1; | |
454 | fflush(stdout); | |
455 | } | |
456 | ||
457 | // if l_buflen was zero, there was no newline and the while loop | |
458 | // above didn't print anything out | |
459 | if((l_pos < l_buflen+p_message) || (l_buflen == 0)) | |
460 | { | |
461 | if (ms.newLine) | |
462 | printf("%s", p_tag_string); | |
463 | printf("%s",l_pos); | |
464 | ms.newLine=0; | |
465 | fflush(stdout); | |
466 | } | |
467 | ||
468 | if(p_add_newline!=0) | |
469 | { | |
470 | puts(""); | |
471 | ms.newLine=1; | |
472 | fflush(stdout); | |
473 | } | |
474 | } | |
475 | ||
476 | /*---------------------------------------------------------------------------- | |
477 | * int | |
478 | * warningCheck() | |
479 | * checks to see if we've reached max_warnings | |
480 | * | |
481 | * Return Value -- | |
482 | * 1 on warning kill, 0 otherwise | |
483 | * | |
484 | * Design -- | |
485 | * inhibit printing warnings and errors if we've reached max_warnings | |
486 | * either by dying or turning them off | |
487 | * | |
488 | * Side effects -- | |
489 | * possible death, modifies finish_pending and finish_type | |
490 | *---------------------------------------------------------------------------- | |
491 | */ | |
492 | static int | |
493 | warningCheck() | |
494 | { | |
495 | int l_r=0; | |
496 | ||
497 | if (ms.global_warnings >= ms.max_warnings) | |
498 | { | |
499 | if(ms.external_finish!=0) | |
500 | { | |
501 | if(ms.finish_pending==0) | |
502 | { | |
503 | UnitInfo **l_ul=(UnitInfo **)ht_sorted_list(ms.unit_tbl, UnitInfo_cmp); | |
504 | UnitInfo **l_uit=0; | |
505 | //printf("Setting finish pending for verilog, and warn_stop as type.\n"); | |
506 | ms.finish_pending = 1; | |
507 | ms.finish_type = 2; | |
508 | for(l_uit=l_ul; *l_uit; l_uit++) | |
509 | { | |
510 | (*l_uit)->enable[MON_WARN]=0; | |
511 | (*l_uit)->enable[MON_ERR]=0; | |
512 | } | |
513 | l_r=1; | |
514 | free(l_ul); | |
515 | } | |
516 | } else | |
517 | { | |
518 | printf("\nINFO(%s): MAX WARNINGS REACHED - SIMULATION TERMINATED\n", | |
519 | modulename); | |
520 | printf("INFO(%s): TIME %s, ABNORMAL END--" | |
521 | "MONITOR CAUSED END OF SIMULATION\n", modulename, tf_strgettime()); | |
522 | printf("Ending simulation \nSIM_ERR_STATUS:2 \n"); | |
523 | tf_dofinish(); | |
524 | } | |
525 | } | |
526 | return l_r; | |
527 | } | |
528 | ||
529 | /*---------------------------------------------------------------------------- | |
530 | * int | |
531 | * errorCheck() | |
532 | * checks to see if we've reached max_errors | |
533 | * | |
534 | * Return Value -- | |
535 | * 1 on error kill, 0 otherwise | |
536 | * | |
537 | * Design -- | |
538 | * inhibit printing warnings and errors if we've reached max_errors | |
539 | * either by dying or turning them off | |
540 | * | |
541 | * Side effects -- | |
542 | * possible death, modifies finish_pending and finish_type | |
543 | *---------------------------------------------------------------------------- | |
544 | */ | |
545 | static int | |
546 | errorCheck() | |
547 | { | |
548 | int l_r=0; | |
549 | if (ms.global_errors >= ms.max_errors) | |
550 | { | |
551 | if(ms.external_finish!=0) | |
552 | { | |
553 | if (ms.finish_pending==0) | |
554 | { | |
555 | UnitInfo **l_ul=(UnitInfo **)ht_sorted_list(ms.unit_tbl, UnitInfo_cmp); | |
556 | UnitInfo **l_uit=0; | |
557 | //printf("Setting finish pending for verilog, and warn_stop as type.\n"); | |
558 | ms.finish_pending = 1; | |
559 | ms.finish_type = 1; | |
560 | /* termination pending due to max error */ | |
561 | /* disable further warn/errors till external */ | |
562 | /* verilog shuts down simulator. */ | |
563 | for(l_uit=l_ul; *l_uit; l_uit++) | |
564 | { | |
565 | (*l_uit)->enable[MON_WARN]=0; | |
566 | (*l_uit)->enable[MON_ERR]=0; | |
567 | } | |
568 | l_r=1; | |
569 | free(l_ul); | |
570 | } | |
571 | } else | |
572 | { | |
573 | printf("\nINFO(%s): MAX ERRORS REACHED - SIMULATION TERMINATED\n", | |
574 | modulename); | |
575 | printf("INFO(%s): TIME %s, ABNORMAL END--" | |
576 | "MONITOR CAUSED END OF SIMULATION\n", modulename, tf_strgettime()); | |
577 | printf("Ending simulation \nSIM_ERR_STATUS:1 \n"); | |
578 | tf_dofinish(); | |
579 | } | |
580 | } | |
581 | return l_r; | |
582 | } | |
583 | ||
584 | typedef struct rstr | |
585 | { | |
586 | char *str; | |
587 | size_t sz; | |
588 | } RStr; | |
589 | ||
590 | /*---------------------------------------------------------------------------- | |
591 | * static RStr * | |
592 | * RStr_new(size_t p_init_sz) | |
593 | * "constructor" for a resizeable string | |
594 | * | |
595 | * Return Value -- | |
596 | * ptr to a resizeable string | |
597 | * | |
598 | * Design -- | |
599 | * return a pointer and the amount of memory associated with it | |
600 | * | |
601 | * Side effects -- | |
602 | * none | |
603 | *---------------------------------------------------------------------------- | |
604 | */ | |
605 | ||
606 | static RStr * | |
607 | RStr_new(size_t p_init_sz) | |
608 | { | |
609 | RStr *l_r=(RStr*)malloc(sizeof *l_r); | |
610 | ||
611 | if(!l_r) | |
612 | { | |
613 | printf("ERROR(%s):Not enough memory to make resizeable string\n", | |
614 | modulename); | |
615 | exit(1); | |
616 | } | |
617 | ||
618 | l_r->str= p_init_sz ? (char*)malloc(p_init_sz) : 0; | |
619 | if(l_r->str) { | |
620 | l_r->sz = p_init_sz; | |
621 | l_r->str[0] = '\0'; | |
622 | } else | |
623 | l_r->sz = 0; | |
624 | ||
625 | return l_r; | |
626 | } | |
627 | ||
628 | /*---------------------------------------------------------------------------- | |
629 | * static void | |
630 | * RStr_delete(RStr *p_r) | |
631 | * "constructor" for a resizeable string | |
632 | * | |
633 | * Return Value -- | |
634 | * none | |
635 | * | |
636 | * Design -- | |
637 | * free memory | |
638 | * | |
639 | * Side effects -- | |
640 | * none | |
641 | *---------------------------------------------------------------------------- | |
642 | */ | |
643 | ||
644 | static void | |
645 | RStr_delete(RStr *p_r) | |
646 | { | |
647 | if(p_r->str) { | |
648 | free(p_r->str); | |
649 | p_r->str = NULL; | |
650 | } | |
651 | free(p_r); | |
652 | } | |
653 | ||
654 | /*---------------------------------------------------------------------------- | |
655 | * static RStr * | |
656 | * expanding_strcat(RStr *p_r, char *p_s) | |
657 | * concat str in p_r with p_s | |
658 | * | |
659 | * Return Value -- | |
660 | * the RStr * you passed in | |
661 | * | |
662 | * Design -- | |
663 | * realloc more memory if necessary, strcat | |
664 | * | |
665 | * Side effects -- | |
666 | * possible death | |
667 | *---------------------------------------------------------------------------- | |
668 | */ | |
669 | ||
670 | static RStr * | |
671 | expanding_strcat(RStr *p_r, const char *p_s) | |
672 | { | |
673 | size_t l_sl=strlen(p_s); | |
674 | size_t l_rl=strlen(p_r->str); | |
675 | ||
676 | if(l_rl+l_sl>=p_r->sz && 0==(p_r->str=(char*)realloc(p_r->str,l_rl+l_sl+100))) | |
677 | { | |
678 | printf("ERROR(%s): can't expand string\n", modulename); | |
679 | tf_dofinish(); | |
680 | } | |
681 | ||
682 | strcat(p_r->str,p_s); | |
683 | return p_r; | |
684 | } | |
685 | ||
686 | #if 0 /* b/c this is unused, which would make lint complain */ | |
687 | static RStr * | |
688 | expanding_strncat(RStr *p_r, const char *p_s, size_t n) | |
689 | { | |
690 | size_t l_sl=strlen(p_s); | |
691 | size_t l_rl=strlen(p_r->str); | |
692 | if (l_sl > n) | |
693 | l_sl = n; | |
694 | ||
695 | if(((l_rl + l_sl) >= p_r->sz) && | |
696 | ((p_r->str = realloc(p_r->str, l_rl + l_sl + 100)) == NULL)) | |
697 | { | |
698 | printf("ERROR(%s): can't expand string\n", modulename); | |
699 | tf_dofinish(); | |
700 | } | |
701 | ||
702 | strncat(p_r->str, p_s, n); | |
703 | return p_r; | |
704 | } | |
705 | #endif | |
706 | ||
707 | /* failed means we tried to parse the format spec and failed */ | |
708 | typedef struct fmt_info | |
709 | { | |
710 | char cvt_spec; | |
711 | unsigned int strip:1,lalign:1,failed:1; | |
712 | unsigned long long width; | |
713 | char *text; | |
714 | } FmtInfo; | |
715 | ||
716 | /* yes, this is more or less identical to the RStr stuff. A future | |
717 | implementation should think about uniting them if possible. The obvious | |
718 | ways are not typesafe. */ | |
719 | ||
720 | typedef struct fmt_array | |
721 | { | |
722 | FmtInfo **f; | |
723 | size_t used; | |
724 | size_t sz; | |
725 | } FmtArray; | |
726 | ||
727 | static FmtArray *FmtArray_new(size_t init_sz) | |
728 | { | |
729 | FmtArray *r=(FmtArray*)malloc(sizeof *r); | |
730 | ||
731 | if(!r) | |
732 | { | |
733 | printf("ERROR(%s):Not enough memory to parse format string\n", | |
734 | modulename); | |
735 | tf_dofinish(); | |
736 | } | |
737 | ||
738 | r->f= init_sz ? (FmtInfo**)malloc(init_sz*sizeof(FmtInfo *)) : 0; | |
739 | r->sz = r->f ? init_sz : 0; | |
740 | r->used=0; | |
741 | ||
742 | return r; | |
743 | } | |
744 | ||
745 | /* user creates new text which must be freeable! or null */ | |
746 | static FmtInfo *FmtInfo_new(char cvt_spec,int strip,int lalign, | |
747 | unsigned long long width,int failed,char *text) | |
748 | { | |
749 | FmtInfo *f=(FmtInfo*)malloc(sizeof *f); | |
750 | if(!f) | |
751 | { | |
752 | printf("ERROR(monitor.c):Can't generate new FmtInfo\n"); | |
753 | tf_dofinish(); | |
754 | } | |
755 | f->cvt_spec=cvt_spec; | |
756 | f->strip=strip; | |
757 | f->lalign=lalign; | |
758 | f->width=width; | |
759 | f->failed=failed; | |
760 | f->text=text; | |
761 | return f; | |
762 | } | |
763 | ||
764 | static void FmtInfo_delete(FmtInfo *fi) | |
765 | { | |
766 | if(fi->text) | |
767 | { | |
768 | free(fi->text); | |
769 | fi->text = NULL; | |
770 | } | |
771 | free(fi); | |
772 | } | |
773 | ||
774 | static void FmtArray_delete(FmtArray *r) | |
775 | { | |
776 | size_t i; | |
777 | for(i=0;i<r->used; i++) | |
778 | { | |
779 | FmtInfo_delete(r->f[i]); | |
780 | r->f[i] = NULL; | |
781 | } | |
782 | ||
783 | if(r->f) | |
784 | { | |
785 | free(r->f); | |
786 | r->f = NULL; | |
787 | } | |
788 | free(r); | |
789 | } | |
790 | ||
791 | static FmtArray *FmtArray_add(FmtArray *f, FmtInfo *fmt) | |
792 | { | |
793 | if(f->used==f->sz) | |
794 | { | |
795 | f->sz+=10; | |
796 | if(!(f->f=(FmtInfo**)realloc(f->f,f->sz*sizeof *(f->f)))) | |
797 | { | |
798 | printf("ERROR(%s):Not enough memory to expand FmtArray\n",modulename); | |
799 | tf_dofinish(); | |
800 | } | |
801 | } | |
802 | f->f[f->used++]=fmt; | |
803 | return f; | |
804 | } | |
805 | ||
806 | static char *substring(const char *s, const char *e) | |
807 | { | |
808 | size_t textlen; /* =e ? e-s : strlen(s); */ | |
809 | char *text; | |
810 | ||
811 | if(e) | |
812 | { | |
813 | if(e > s) | |
814 | { | |
815 | /* Casts get around lint error involving substracting | |
816 | one ptr from another. Lint doesn't seem to like that, | |
817 | even though we just checked that e > s. */ | |
818 | textlen = (unsigned )e-(unsigned )s; | |
819 | } | |
820 | else | |
821 | { | |
822 | printf("ERROR: Assertion failed, in fn 'substring()', " | |
823 | "in monitor.c\n"); | |
824 | tf_dofinish(); | |
825 | } | |
826 | } | |
827 | else | |
828 | { | |
829 | textlen = strlen(s); | |
830 | } | |
831 | ||
832 | text=(char*)malloc(textlen+1); | |
833 | if(textlen) | |
834 | { | |
835 | if(text==NULL) | |
836 | { | |
837 | printf("ERROR(%s):Not enough memory to copy substring\n",modulename); | |
838 | tf_dofinish(); | |
839 | } | |
840 | /* strlcpy(text,s,textlen+1); NO STRLCPY ! BAD ON SOLARIS 7 ! */ | |
841 | strncpy(text, s, textlen); text[textlen] = 0; | |
842 | } | |
843 | return text; | |
844 | } | |
845 | ||
846 | #if 0 /* b/c this is unused, which would make lint complain */ | |
847 | static FmtArray *add_nfmtstring(FmtArray *f, const char *s,const char *e) | |
848 | { | |
849 | return f; | |
850 | } | |
851 | #endif | |
852 | ||
853 | /* parses and adds format string to FmtArray, increments ptr to end of fmt | |
854 | string. Being able to return multiple values would have been nice */ | |
855 | /* adds string if we can't figure out what we've parsed */ | |
856 | ||
857 | static FmtArray *add_fmt(FmtArray *f, const char *fmt, const char **end_pos) | |
858 | { | |
859 | int lalign=0, strip=0, failed=0; | |
860 | unsigned long long width=0; | |
861 | const char *pos=fmt; | |
862 | ||
863 | if(!fmt) return f; | |
864 | ||
865 | if(*pos=='%') pos++; | |
866 | ||
867 | /* check for cvt_spec with no options */ | |
868 | if (strchr(no_nparam,*pos)) | |
869 | { | |
870 | if(end_pos) *end_pos=pos+1; | |
871 | return FmtArray_add(f,FmtInfo_new(*pos,0,0,0,0,0)); | |
872 | } | |
873 | ||
874 | /* check for flags */ | |
875 | /* in a reverse from printf style, %0x *removes* zeros, not pads them */ | |
876 | for(;*pos&& (*pos=='-' || *pos=='0');pos++) | |
877 | { | |
878 | if(!lalign) lalign=*pos=='-'; | |
879 | if(!strip) strip=*pos=='0'; | |
880 | } | |
881 | ||
882 | width=strtoull(pos,(char **)&pos,10); | |
883 | failed=!strchr(has_nfld, *pos) || !*pos; | |
884 | ||
885 | if(end_pos) *end_pos=pos+1; | |
886 | return FmtArray_add(f,FmtInfo_new(*pos,strip,lalign,width,failed, | |
887 | failed ? substring(fmt,pos+1) : 0)); | |
888 | } | |
889 | ||
890 | /* takes format string, returns resizeable array with info about broken up | |
891 | pieces of the format string */ | |
892 | static FmtArray* parse_fmt(const char *fmt) | |
893 | { | |
894 | FmtArray *f=FmtArray_new(10); | |
895 | ||
896 | const char *i,*k; | |
897 | ||
898 | for(i=fmt; i && *i; i=k) | |
899 | { | |
900 | k=strchr(i,'%'); | |
901 | if(k!=i) | |
902 | f=FmtArray_add(f,FmtInfo_new(0,0,0,0,0,substring(i,k))); | |
903 | if(k) | |
904 | f=add_fmt(f,k,&k); | |
905 | } | |
906 | return f; | |
907 | } | |
908 | ||
909 | static char *format_val(FmtInfo *fi, char *val) | |
910 | { | |
911 | char *ftext; | |
912 | size_t len,width; | |
913 | ||
914 | if(fi->strip && val && *val) | |
915 | while((*val=='0' || *val==' ') && val[1]) | |
916 | val++; | |
917 | len=strlen(val); | |
918 | width=len > fi->width ? len+1 : fi->width+1; | |
919 | ftext=(char*)malloc(width); | |
920 | if(ftext==NULL) | |
921 | { | |
922 | printf("ERROR(%s):Can't get memory to form output!\n",modulename); | |
923 | tf_dofinish(); | |
924 | } | |
925 | if(fi->lalign) | |
926 | { | |
927 | strcpy(ftext,val); | |
928 | memset(ftext+len, ' ',width-len-1); | |
929 | } else | |
930 | { | |
931 | strcpy(ftext+width-len-1,val); | |
932 | memset(ftext, ' ', width-len-1); | |
933 | } | |
934 | ftext[width-1]=0; | |
935 | ||
936 | return ftext; | |
937 | } | |
938 | ||
939 | static int insert_var(RStr *output, FmtInfo *fi, int pn) | |
940 | { | |
941 | switch(fi->cvt_spec) | |
942 | { | |
943 | case 'm': | |
944 | expanding_strcat(output,tf_mipname()); /* calling module */ | |
945 | break; | |
946 | case 't': | |
947 | expanding_strcat(output,tf_strgettime()); /* current simulator time */ | |
948 | break; | |
949 | case '%': | |
950 | expanding_strcat(output,"%"); /* percent sign */ | |
951 | break; | |
952 | default: | |
953 | /* don't need this check if checktf errors */ | |
954 | if(strchr(has_nfld,fi->cvt_spec)) | |
955 | { | |
956 | char *text; | |
957 | /* translate x's to h's for hex; NC segfaults if you don't */ | |
958 | if(fi->cvt_spec=='x') | |
959 | fi->cvt_spec='h'; | |
960 | if(fi->cvt_spec=='X') | |
961 | fi->cvt_spec='H'; | |
962 | text= format_val(fi, | |
963 | fi->cvt_spec=='s' ? tf_getcstringp(pn) : | |
964 | tf_strgetp(pn,fi->cvt_spec)); | |
965 | expanding_strcat(output,text); | |
966 | free(text); | |
967 | pn++; | |
968 | } | |
969 | } | |
970 | return pn; | |
971 | } | |
972 | ||
973 | /* might as well make this public since the assertion stuff seemed be | |
974 | using it anyways */ | |
975 | char *dispmon_parse(const char *fmt, int nump, int start, | |
976 | const char *unit) | |
977 | { | |
978 | FmtArray *f=parse_fmt(fmt); | |
979 | size_t i=0, pno=start; | |
980 | RStr *output=RStr_new(256); | |
981 | char *s; | |
982 | ||
983 | for(i=0; i<f->used && output; i++) | |
984 | { | |
985 | if(f->f[i]->text) | |
986 | expanding_strcat(output,f->f[i]->text); | |
987 | else | |
988 | { | |
989 | /* should not need this check if checktf errors */ | |
990 | if(pno>nump) | |
991 | { | |
992 | //cDispmon(modulename, MON_ERR, | |
993 | // "insufficient parameters for format string \"%s\" in " | |
994 | // "$dispmon/$writemon", fmt); | |
995 | RStr_delete(output); | |
996 | output = NULL; | |
997 | } else | |
998 | pno=insert_var(output,f->f[i],pno); | |
999 | } | |
1000 | } | |
1001 | FmtArray_delete(f); | |
1002 | s = output ? output->str : 0; | |
1003 | free(output); | |
1004 | return s; | |
1005 | } | |
1006 | ||
1007 | /*---------------------------------------------------------------------------- | |
1008 | * static int | |
1009 | * mon_type_for(char *p_unit, int p_tag) | |
1010 | * look up monitor type | |
1011 | * | |
1012 | * Return Value -- | |
1013 | * returns the monitor type to use for display | |
1014 | * | |
1015 | * Design -- | |
1016 | * Gets unit from hash table, do array look up | |
1017 | * defaults to how ever the enables are set for "default" | |
1018 | * Side effects -- | |
1019 | * none | |
1020 | *---------------------------------------------------------------------------- | |
1021 | */ | |
1022 | static int | |
1023 | mon_type_for(const char *p_unit, int p_tag) | |
1024 | { | |
1025 | UnitInfo *l_ui=(UnitInfo*)ht_get(ms.unit_tbl, p_unit); | |
1026 | ||
1027 | if(0==l_ui) | |
1028 | l_ui=(UnitInfo*)ht_get(ms.unit_tbl, "default"); | |
1029 | ||
1030 | if(0==l_ui) | |
1031 | { | |
1032 | printf("ERROR(%s):Unit hash not set up right!\n", modulename); | |
1033 | tf_dofinish(); | |
1034 | } | |
1035 | ||
1036 | return l_ui->enable[p_tag] ? tag2mon_type(p_tag) : NO_MON_TYPE; | |
1037 | } | |
1038 | ||
1039 | /*---------------------------------------------------------------------------- | |
1040 | * static void | |
1041 | * print_tagged_line(char *p_prefix, char *p_unit, char *p_output, | |
1042 | * int p_mon_type, int p_add_newline) | |
1043 | * print out the line with timestamp and unit responsible | |
1044 | * | |
1045 | * Return Value -- | |
1046 | * none | |
1047 | * | |
1048 | * Design -- | |
1049 | * Get timestamp. Go through way too much effort to come up with a module name | |
1050 | * put it together to get a tag, call smart_write_tagged_output | |
1051 | * Side effects -- | |
1052 | * possible death since it calls warningCheck() and errorCheck() | |
1053 | * may modify global_errors or global_warnings | |
1054 | *---------------------------------------------------------------------------- | |
1055 | */ | |
1056 | static void | |
1057 | print_tagged_line(const char *p_prefix, const char *p_unit, char *p_output, | |
1058 | int p_mon_type, int p_add_newline) | |
1059 | { | |
1060 | char *l_instance=tf_mipname(); | |
1061 | char *l_pt1=0; | |
1062 | char *l_modname=0; | |
1063 | char *l_tag_gen[]={"%s%s%s%s", "%s: WARNING: %s[%s%s]: ", | |
1064 | "%s: ERROR: %s[%s%s]: ", "%s: %s[%s%s]: ", | |
1065 | "%s: INFO: %s[%s%s]: ", "%s: DBG: %s[%s%s]: "}; | |
1066 | ||
1067 | /* If l_instance == NULL, then we may be in a callback */ | |
1068 | if (l_instance == NULL) | |
1069 | { | |
1070 | l_instance = "pli callback"; | |
1071 | } | |
1072 | ||
1073 | /* get the module instance name. */ | |
1074 | /* Generally, ch_sys.cheetah_mod.cpu..... */ | |
1075 | /* Display as: (<mod>...<end_path_name>) */ | |
1076 | if (0==(l_pt1 = strchr(l_instance, '.'))) | |
1077 | { | |
1078 | /* No module */ | |
1079 | l_modname=strdup(l_instance); | |
1080 | } | |
1081 | else | |
1082 | { | |
1083 | /* we just want the full instance name from the mod level down. */ | |
1084 | /* that's what we print out, always! If that's too long and your */ | |
1085 | /* printouts end up hard to read, tough! Post process. */ | |
1086 | l_modname=strdup(l_pt1+1); | |
1087 | } | |
1088 | ||
1089 | if(0!=l_modname) | |
1090 | { | |
1091 | char *l_tagbuffer=0; | |
1092 | /* lacking a predictable snprintf or asprintf, we guess at how large | |
1093 | tagbuffer needs to be */ | |
1094 | if(0==(l_tagbuffer=(char*)malloc(strlen(l_tag_gen[p_mon_type])+strlen(p_unit)+ | |
1095 | strlen(p_prefix)+strlen(l_modname)+20))) | |
1096 | { | |
1097 | printf("ERROR(%s): Can not generate tag for output\n",modulename); | |
1098 | tf_dofinish(); | |
1099 | } | |
1100 | sprintf(l_tagbuffer, l_tag_gen[p_mon_type], tf_strgettime(), p_unit, | |
1101 | p_prefix, l_modname); | |
1102 | if(WARNING_MON_TYPE==p_mon_type) | |
1103 | ms.global_warnings++; | |
1104 | if(ERROR_MON_TYPE==p_mon_type) | |
1105 | { | |
1106 | ms.global_errors++; | |
1107 | /* if we do a dispmon (not writemon!) with an error monitor type. | |
1108 | Force the start of a new line. */ | |
1109 | if(p_add_newline && 0==ms.newLine) | |
1110 | { | |
1111 | puts(""); | |
1112 | ms.newLine=1; | |
1113 | } | |
1114 | } | |
1115 | smart_write_tagged_output(l_tagbuffer, p_output, p_add_newline); | |
1116 | free(l_modname); | |
1117 | free(l_tagbuffer); | |
1118 | warningCheck(); | |
1119 | errorCheck(); | |
1120 | } | |
1121 | } | |
1122 | ||
1123 | /*---------------------------------------------------------------------------- | |
1124 | * static void | |
1125 | * do_mon(int p_add_newline) | |
1126 | * error check Verilog side arguments, generate then print line | |
1127 | * | |
1128 | * Return Value -- | |
1129 | * none | |
1130 | * | |
1131 | * Design -- | |
1132 | * | |
1133 | * Side effects --1H | |
1134 | * possible death, modifies global_errors | |
1135 | *---------------------------------------------------------------------------- | |
1136 | */ | |
1137 | static int | |
1138 | do_mon(int p_add_newline) | |
1139 | { | |
1140 | char *unit_name_arg = tf_getcstringp(1); | |
1141 | char *l_unit; | |
1142 | int l_tag = tf_getp(2); | |
1143 | int l_mon_type; | |
1144 | ||
1145 | if(!unit_name_arg) | |
1146 | { | |
1147 | char *mipname = tf_mipname(); | |
1148 | printf("ERROR: failed to read first argument to $dispmon or " | |
1149 | "$writemon, in 'do_mon()'. Hierarchy is '%s'\n", | |
1150 | mipname ? mipname : "NULL"); | |
1151 | return 0; | |
1152 | } | |
1153 | else | |
1154 | { | |
1155 | l_unit = strdup(unit_name_arg); | |
1156 | if(!l_unit) | |
1157 | { | |
1158 | printf("ERROR: strdup failed in 'do_mon()'\n"); | |
1159 | return 0; | |
1160 | } | |
1161 | } | |
1162 | ||
1163 | if(!ms.unit_tbl) | |
1164 | init_unit_tbl(); | |
1165 | ||
1166 | l_mon_type=mon_type_for(l_unit, l_tag); | |
1167 | ||
1168 | if(l_mon_type!=NO_MON_TYPE) | |
1169 | { | |
1170 | int l_input_parms = tf_nump(); | |
1171 | char *l_output=dispmon_parse(tf_getcstringp(3), l_input_parms, 4, | |
1172 | l_unit); | |
1173 | if (0!=l_output) | |
1174 | { | |
1175 | print_tagged_line("", l_unit, l_output, l_mon_type, p_add_newline); | |
1176 | free(l_output); | |
1177 | } | |
1178 | } | |
1179 | free(l_unit); | |
1180 | return 0; | |
1181 | } | |
1182 | ||
1183 | int | |
1184 | do_dispmon_mon(void) | |
1185 | { | |
1186 | return(do_mon(1)); | |
1187 | } | |
1188 | ||
1189 | int | |
1190 | do_writemon_mon(void) | |
1191 | { | |
1192 | return(do_mon(0)); | |
1193 | } | |
1194 | ||
1195 | size_t monitor_nfmtargs(char *fmt) | |
1196 | { | |
1197 | /* validate # of parameters and correct tokens by parsing format */ | |
1198 | FmtArray *f=parse_fmt(fmt); | |
1199 | size_t i=0,nargs=0; | |
1200 | ||
1201 | for(i=0; i<f->used; i++) | |
1202 | { | |
1203 | if(!f->f[i]->text && !strchr(no_nparam, f->f[i]->cvt_spec)) | |
1204 | nargs++; | |
1205 | ||
1206 | if(f->f[i]->failed) | |
1207 | cDispmon("disp", MON_ERR, "invalid format spec: \"%s\" in " | |
1208 | "format string \"%s\"\nin instance %s", | |
1209 | f->f[i]->text, tf_getcstringp(3),tf_mipname()); | |
1210 | } | |
1211 | FmtArray_delete(f); | |
1212 | return nargs; | |
1213 | } | |
1214 | ||
1215 | int monitor_checktf(void) | |
1216 | { | |
1217 | int nump=tf_nump(); | |
1218 | if (nump < 3) | |
1219 | { | |
1220 | cDispmon("disp", MON_ERR, "Usage: $dispmon(\"unit\", tag, " | |
1221 | "\"printf-style-format\", modulename, reg-or-int, " | |
1222 | "reg-or-int);\nin instance %s", tf_mipname()); | |
1223 | } else if (tf_typep(1) != tf_string) | |
1224 | { | |
1225 | cDispmon("disp", MON_ERR,"dispmon unit name is not a string\n" | |
1226 | "in instance %s",tf_mipname()); | |
1227 | } else if (tf_typep(3) != tf_string) | |
1228 | { | |
1229 | cDispmon("disp", MON_ERR, "dispmon format field is not a string\n" | |
1230 | "in instance %s", tf_mipname()); | |
1231 | } else | |
1232 | { | |
1233 | size_t nargs=monitor_nfmtargs(tf_getcstringp(3)); | |
1234 | if(nargs+3!=nump) | |
1235 | { | |
1236 | cDispmon("disp",MON_ERR, | |
1237 | "wrong number of parameters for format string \"%s\"\n" | |
1238 | "in instance %s", tf_getcstringp(3), tf_mipname()); | |
1239 | } | |
1240 | } | |
1241 | return 0; | |
1242 | } | |
1243 | ||
1244 | /*---------------------------------------------------------------------------- | |
1245 | * int | |
1246 | * check_num_dispmon_errors() | |
1247 | * entry point for $check_num_dispmon_errors | |
1248 | * | |
1249 | * Return Value -- | |
1250 | * always 0 | |
1251 | * | |
1252 | * Design -- | |
1253 | * | |
1254 | * Side effects -- | |
1255 | * none | |
1256 | *---------------------------------------------------------------------------- | |
1257 | */ | |
1258 | int | |
1259 | check_num_dispmon_errors() | |
1260 | { | |
1261 | tf_putp(1, ms.global_errors); | |
1262 | return 0; | |
1263 | } | |
1264 | ||
1265 | /*---------------------------------------------------------------------------- | |
1266 | * int | |
1267 | * enable_dispmon_finish() | |
1268 | * entry point for $enable_dispmon_finish | |
1269 | * | |
1270 | * Return Value -- | |
1271 | * always 0 | |
1272 | * | |
1273 | * Design -- | |
1274 | * parameter to syscall is 1=let dispmon finish | |
1275 | * 0=let external prog finish | |
1276 | * This is exactly the opposite of what we're tracking | |
1277 | * Side effects -- | |
1278 | * none | |
1279 | *---------------------------------------------------------------------------- | |
1280 | */ | |
1281 | int | |
1282 | enable_dispmon_finish() | |
1283 | { | |
1284 | ms.external_finish=tf_getp(1); | |
1285 | ms.external_finish=!ms.external_finish; | |
1286 | return 0; | |
1287 | } | |
1288 | ||
1289 | /*---------------------------------------------------------------------------- | |
1290 | * int | |
1291 | * check_mon() | |
1292 | * entry point for $check_mon | |
1293 | * | |
1294 | * Return Value -- | |
1295 | * always 0 | |
1296 | * | |
1297 | * Design -- | |
1298 | * syscall return is whether we should finish | |
1299 | * first param of syscall returns why | |
1300 | * Side effects -- | |
1301 | * none | |
1302 | *---------------------------------------------------------------------------- | |
1303 | */ | |
1304 | int | |
1305 | check_mon() | |
1306 | { | |
1307 | tf_putp(2, ms.finish_pending); | |
1308 | tf_putp(1, ms.finish_type); | |
1309 | return 0; | |
1310 | } | |
1311 | ||
1312 | /*---------------------------------------------------------------------------- | |
1313 | * int | |
1314 | * do_ch_dispmon() | |
1315 | * entry point for $ch_dispmon | |
1316 | * | |
1317 | * int | |
1318 | * ch_dispmon() | |
1319 | * Return Value -- | |
1320 | * always 0 | |
1321 | * | |
1322 | * Design -- | |
1323 | * Error check V-side arguments, modify hash table entries | |
1324 | * - Set all tags >= l_tag on/off | |
1325 | * - Set default if "all" is specified so later initialized units may | |
1326 | * use the 'all' setting too. | |
1327 | * | |
1328 | * Side effects -- | |
1329 | * modifies hash table entries and default ms entries .. | |
1330 | *---------------------------------------------------------------------------- | |
1331 | */ | |
1332 | int | |
1333 | do_ch_dispmon(void) | |
1334 | { | |
1335 | if (tf_nump() < 3) { | |
1336 | printf("ERROR(ch_dispmon): Usage: " | |
1337 | "$ch_dispmon(unit, tag, value(1 = on, 0 = off))\n"); | |
1338 | } else { | |
1339 | char *l_unit_name=tf_getcstringp(1); | |
1340 | int l_tag= tf_getp(2); | |
1341 | int l_value=tf_getp(3); | |
1342 | return(ch_dispmon(l_unit_name, l_tag, l_value)); | |
1343 | } | |
1344 | return 0; | |
1345 | } | |
1346 | ||
1347 | int | |
1348 | ch_dispmon(char *l_unit_name, int l_tag, int l_value) | |
1349 | { | |
1350 | int i; | |
1351 | ||
1352 | if (l_tag < 1 || l_tag > 49) { | |
1353 | printf("ERROR(ch_dispmon): tag should be between 1 and 49\n"); | |
1354 | } else if (l_value < 0 || l_value > 1) { | |
1355 | printf("ERROR(ch_dispmon): Use 0 to turn off the tag display or " | |
1356 | "1 to turn it on (%0d)\n", l_value); | |
1357 | } else if (0==strcmp(l_unit_name, "all")) { | |
1358 | UnitInfo **l_ul; | |
1359 | UnitInfo **l_uit; | |
1360 | if (l_value == 0) { | |
1361 | ms.default_unit.enable[l_tag] = l_value ; | |
1362 | } else { | |
1363 | for (i=1;i<=49;i++) { | |
1364 | ms.default_unit.enable[i] = (i>=l_tag) ? l_value : ms.default_unit.enable[i]; | |
1365 | } | |
1366 | } | |
1367 | if(!ms.unit_tbl) { | |
1368 | init_unit_tbl(); | |
1369 | cDispmon("disp", MON_ALWAYS, "All units added to monitor list"); | |
1370 | } | |
1371 | l_ul=(UnitInfo **)ht_sorted_list(ms.unit_tbl, UnitInfo_cmp); | |
1372 | l_uit=l_ul; | |
1373 | if (l_value == 0) { | |
1374 | (*l_uit)->enable[l_tag] = l_value ; | |
1375 | } else { | |
1376 | for(l_uit=l_ul; 0!=*l_uit; l_uit++) { | |
1377 | for (i=1;i<=49;i++) { | |
1378 | (*l_uit)->enable[i]= (i>=l_tag) ? l_value : ms.default_unit.enable[i]; | |
1379 | } | |
1380 | } | |
1381 | cDispmon("disp", MON_ALWAYS, "All Units, tags >= %d value changed to %d", | |
1382 | l_tag, l_value); | |
1383 | } | |
1384 | free(l_ul); | |
1385 | } else { | |
1386 | UnitInfo *l_ui; | |
1387 | if(!ms.unit_tbl) init_unit_tbl(); | |
1388 | l_ui=(UnitInfo*)ht_get(ms.unit_tbl,l_unit_name); | |
1389 | if(0==l_ui) { | |
1390 | l_ui=UnitInfo_new(l_unit_name); | |
1391 | ht_put(ms.unit_tbl,l_unit_name,l_ui); | |
1392 | } | |
1393 | if (l_value == 0) { | |
1394 | l_ui->enable[l_tag] = l_value ; | |
1395 | } else { | |
1396 | for (i=1;i<=49;i++) { | |
1397 | l_ui->enable[i]= (i>=l_tag) ? l_value : 0 ; | |
1398 | } | |
1399 | } | |
1400 | cDispmon("disp", MON_NORMAL, "Unit \"%s\" tag >= %d value changed to %d", | |
1401 | l_unit_name, l_tag, l_value); | |
1402 | } | |
1403 | return 0; | |
1404 | } | |
1405 | ||
1406 | /*---------------------------------------------------------------------------- | |
1407 | * static void | |
1408 | * cDomon(int p_add_newline, char *p_unitName, int p_tag, char *p_format, | |
1409 | * va_list p_args) | |
1410 | * prints out C side monitor output | |
1411 | * | |
1412 | * Return Value -- | |
1413 | * none | |
1414 | * | |
1415 | * Design -- | |
1416 | * Error check, vsprintf, print_tagged_output_line | |
1417 | * | |
1418 | * Side effects -- | |
1419 | * could die in print_tagged_line | |
1420 | *---------------------------------------------------------------------------- | |
1421 | */ | |
1422 | void | |
1423 | cDomon(int p_add_newline, const char *p_unitName, int p_tag, | |
1424 | const char *p_format, va_list p_args) | |
1425 | { | |
1426 | if(!ms.unit_tbl) | |
1427 | init_unit_tbl(); | |
1428 | ||
1429 | if (p_tag < 0 || p_tag > 49) | |
1430 | { | |
1431 | printf("ERROR(cDispmon): tag should be between 0 and 49\n"); | |
1432 | } | |
1433 | else | |
1434 | { | |
1435 | int l_mon_type=mon_type_for(p_unitName, p_tag); | |
1436 | if(NO_MON_TYPE!=l_mon_type) | |
1437 | { | |
1438 | char *output; | |
1439 | char otemp; | |
1440 | int osize; | |
1441 | osize = vsnprintf(&otemp, 1, p_format, p_args); | |
1442 | output = (char *)malloc(osize + 1); | |
1443 | vsnprintf(output, osize + 1, p_format, p_args); | |
1444 | print_tagged_line("", p_unitName, output, l_mon_type, | |
1445 | p_add_newline); | |
1446 | free(output); | |
1447 | } | |
1448 | } | |
1449 | } | |
1450 | ||
1451 | /*---------------------------------------------------------------------------- | |
1452 | * int | |
1453 | * cDispmon(char *p_unitName, int p_tag, char *p_format,...) | |
1454 | * user entry point for writing with '\n' at end | |
1455 | * | |
1456 | * Return Value -- | |
1457 | * always 0 | |
1458 | * | |
1459 | * Design -- | |
1460 | * | |
1461 | * Side effects -- | |
1462 | * possible death since it calls cDomon() | |
1463 | *---------------------------------------------------------------------------- | |
1464 | */ | |
1465 | int | |
1466 | cDispmon(const char *p_unitName, int p_tag, const char *p_format,...) | |
1467 | { | |
1468 | va_list l_args; | |
1469 | ||
1470 | va_start(l_args, p_format); | |
1471 | cDomon(1, p_unitName, p_tag, p_format, l_args); | |
1472 | va_end(l_args); | |
1473 | return 0; | |
1474 | } | |
1475 | ||
1476 | /*---------------------------------------------------------------------------- | |
1477 | * int | |
1478 | * cWritemon(char *p_unitName, int p_tag, char *p_format,...) | |
1479 | * user entry point for writing without '\n' at end | |
1480 | * | |
1481 | * Return Value -- | |
1482 | * always 0 | |
1483 | * | |
1484 | * Design -- | |
1485 | * | |
1486 | * Side effects -- | |
1487 | * possible death since it calls cDomon() | |
1488 | *---------------------------------------------------------------------------- | |
1489 | */ | |
1490 | int | |
1491 | cWritemon(const char *p_unitName, int p_tag, const char *p_format,...) | |
1492 | { | |
1493 | va_list l_args; | |
1494 | ||
1495 | va_start(l_args, p_format); | |
1496 | cDomon(0, p_unitName, p_tag, p_format, l_args); | |
1497 | va_end(l_args); | |
1498 | return 0; | |
1499 | } |