Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / verif / env / common / pli / monitor / c / src / monitor.c
CommitLineData
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
60int ch_dispmon(char *l_unit_name, int l_tag, int l_value);
61
62typedef struct unit_info
63{
64 char *unit;
65 unsigned int enable[MAXTAGS];
66} UnitInfo;
67
68typedef 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*/
86static 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
97static const char *modulename = "monitor.c";
98static const char *has_nfld="bBoOdDhHsxX";
99static 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*/
129static int
130UnitInfo_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*/
237static UnitInfo *
238UnitInfo_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*/
260static 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
284int 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*/
312static void
313parse_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*/
384static void
385init_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*/
407static int
408tag2mon_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*/
438static void
439smart_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*/
492static int
493warningCheck()
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*/
545static int
546errorCheck()
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
584typedef 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
606static RStr *
607RStr_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
644static void
645RStr_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
670static RStr *
671expanding_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 */
687static RStr *
688expanding_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 */
708typedef 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
720typedef struct fmt_array
721{
722 FmtInfo **f;
723 size_t used;
724 size_t sz;
725} FmtArray;
726
727static 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 */
746static 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
764static 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
774static 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
791static 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
806static 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 */
847static 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
857static 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 */
892static 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
909static 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
939static 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 */
975char *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*/
1022static int
1023mon_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*/
1056static void
1057print_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*/
1137static int
1138do_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
1183int
1184do_dispmon_mon(void)
1185{
1186 return(do_mon(1));
1187}
1188
1189int
1190do_writemon_mon(void)
1191{
1192 return(do_mon(0));
1193}
1194
1195size_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
1215int 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*/
1258int
1259check_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*/
1281int
1282enable_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*/
1304int
1305check_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*/
1332int
1333do_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 }
1344return 0;
1345}
1346
1347int
1348ch_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*/
1422void
1423cDomon(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*/
1465int
1466cDispmon(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*/
1490int
1491cWritemon(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}