1 /****************************************************************************
2     Copyright (C) 1987-2015 by Jeffery P. Hansen
3 
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License along
15     with this program; if not, write to the Free Software Foundation, Inc.,
16     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 
18     Last edit by hansen on Sun Feb  8 19:30:29 2009
19 ****************************************************************************/
20 #include "thyme.h"
21 
22 /*****************************************************************************
23  *
24  * When warning_mode is 2, we want to display warnings only if there were
25  * errors.  This means we need to defer display of warnings until we see an
26  * error.  The following structure is used for this purpose.
27  *
28  *****************************************************************************/
29 typedef struct DeferedWarning_str DeferedWarning;
30 struct DeferedWarning_str {
31   char			*dw_msg;
32   DeferedWarning	*dw_next;
33 };
34 DeferedWarning *wdefer_head = 0;
35 DeferedWarning *wdefer_tail = 0;
36 
37 extern Place curPlace;
38 static placemode_t placeMode = (placemode_t)(PM_FILE|PM_LINE|PM_PRETTY);
39 char *current_script = 0;
40 int warning_mode = 3;
41 
42 /*****************************************************************************
43  *
44  * Table of error messages.
45  *
46  * Each error message has a tag, and a text message associated with it.  When
47  * thyme is running in interactive mode, the tags are used, and when running
48  * in stand alone mode, the full messages are used.  The tags are used in interactive
49  * mode to allow translation through a tkgate messages file.  The English message
50  * table in messages format can be generated by running the simulator with the -e switch.
51  *
52  *****************************************************************************/
53 static ErrorDescriptor errorTable[] = {
54   {ERR_OK,		0,	"OK",		"Don't worry, be happy."},
55   {WRN_INPORT,		0,	"INPORT",	"Port size mismatch on input port '%s'."},
56   {WRN_OUTPORT,		0,	"OUTPORT",	"Port size mismatch on output port '%s'."},
57   {WRN_FLOATNET,	0,	"FLOATNET",	"Net '%s' has no drivers (floating net)."},
58   {WRN_DIRECTCONN,	0,	"DIRECTCONN",	"Direct connect operator '=>' unsupported.  Treated as '*>'."},
59   {ERR_MEMADDR,		1,	"MEMADDR",	"Attempt to write to memory %s with unknown address."},
60   {ERR_MEMBITS,		1,	"MEMBITS",	"Attempt to write to memory %s with unknown bitrange."},
61   {ERR_BADARRAYUSG,	1,	"BADARRAYUSG",	"Array '%s' used in expression without index."},
62   {ERR_BADARRAYLHS,	1,	"BADARRAYLHS",	"Array '%s' used without index on left-hand-side."},
63   {ERR_BADCLOSE,	1,	"BADCLOSE",	"Attempt to close non-open descriptor in task '%s'."},
64   {ERR_BADAUTORNG,	1,	"BADAUTORNG",	"Auto range [*] is only valid with 'wire' declaration."},
65   {ERR_BADGATERNG,	1,	"BADGATERNG",	"Bad gate instance range expression."},
66   {ERR_DIVZERO,		1,	"DIVZERO",	"Divide by zero."},
67   {ERR_BADEDGEEVENT,	1,	"BADEDGEEVENT",	"Event on multi-bit net '%s' can not have posedge/negedge."},
68   {ERR_NEEDEDGE,	1,	"NEEDEDGE",	"Must specify posedge or negedge on event for %s."},
69   {ERR_ASGNEVENT,	1,	"ASGNEVENT",	"Event wait on assign is illegal."},
70   {ERR_PROTTASK,	1,	"PROTTASK",	"Execution of protected system task '%s' blocked."},
71   {ERR_NEEDIDENT,	1,	"NEEDIDENT",	"Expecting identifier for argument %s of task '%s'."},
72   {ERR_BADOP,		1,	"BADOP",	"Expression operator error in '%s'."},
73   {ERR_NOREAD,		1,	"NOREAD",	"Failed to load source file '%s'."},
74   {ERR_MEMFILE,		1,	"MEMFILE",	"Failed to open memory file '%s'."},
75   {ERR_WRONGMOD,	1,	"WRONGMOD",	"Found module '%s' when expecting '%s'."},
76   {ERR_NOTPARM,		1,	"NOTPARM",	"Identifier '%s' in constant expression is not a parameter."},
77   {ERR_BADADDR,		1,	"BADADDR",	"Illegal address range on port '%s'."},
78   {ERR_BADADDRSPEC,	1,	"BADADDRSPEC",	"Illegal address range specification '%s'."},
79   {ERR_BADCHAR,		1,	"BADCHAR",	"Illegal character (%s) '%s'."},
80   {ERR_BADEVENT,	1,	"BADEVENT",	"Illegal event control expression."},
81   {ERR_BADCONSTOP,	1,	"BADCONSTOP",	"Illegal operator in constant expression."},
82   {ERR_BADXOP,		1,	"BADXOP",	"Illegal operator in expression."},
83   {ERR_NETREDEF,	1,	"NETREDEF",	"Illegal redefinition of net '%s'."},
84   {ERR_BADINOUT,	1,	"BADINOUT",	"Inout connections must be net-to-net on port '%s'."},
85   {ERR_MODUNDEF,	1,	"MODUNDEF",	"Instance of undefined module '%s'."},
86   {ERR_BADASGNLHS,	1,	"BADASGNLHS",	"Invalid left-hand-side in 'assign'."},
87   {ERR_LHSNOTREG,	1,	"LHSNOTREG",	"Illegal use of '%s' in left-hand-side of assignment."},
88   {ERR_BADLHS,		1,	"BADLHS",	"Invalid left-hand-side in assignment."},
89   {ERR_BADOUT,		1,	"BADOUT",	"Invalid output assignment."},
90   {ERR_NOTREG,		1,	"NOTREG",	"Memories must be declared as register."},
91   {ERR_PORTMIX,		1,	"PORTMIX",	"Mixed named and unnamed ports on interface '%s' of '%s'."},
92   {ERR_REPCASE,		1,	"REPCASE",	"More than one default: in case statement."},
93   {ERR_NOMEM,		1,	"NOMEM",	"No current memory in memory file read."},
94   {ERR_BADCMD,		1,	"BADCMD",	"No such command '%s'."},
95   {ERR_CMDNOTNET,	1,	"CMDNOTNET",	"No such net '%s' in '%s' command."},
96   {ERR_MEMNONBLK,	1,	"MEMNONBLK",	"Non-blocking assignments to memories not implemented."},
97   {ERR_NOTPPORT,	1,	"NOTPPORT",	"Parameter '%s' is not declared as a port."},
98   {ERR_REDEFP,		1,	"REDEFP",	"Parameter redefines identifier '%s'."},
99   {ERR_PORTNOTDEF,	1,	"PORTNOTDEF",	"Port '%s' on interface '%s' is not defined in module '%s'."},
100   {ERR_NOCONN,		1,	"NOCONN",	"Port '%s' has no connections on interface '%s' of '%s'."},
101   {ERR_MULTCONN,	1,	"MULTCONN",	"Port '%s' has multiple connections on interface '%s' of '%s'."},
102   {ERR_PORTCOUNT,	1,	"PORTCOUNT",	"Port count does not match definition on interface '%s' of '%s'."},
103   {ERR_BADPRTRANGE,	1,	"BADPRTRANGE",	"Range on port '%s' is not numeric."},
104   {ERR_BADARRAYRNG,	1,	"BADARRAYRNG",	"Range specification not allowed for memory reference of '%s'."},
105   {ERR_CMDMODREDEF,	1,	"CMDMODREDEF",	"Redefinition of dynamic module '%s'."},
106   {ERR_REDEF,		1,	"REDEF",	"Redefinition of identifier '%s'."},
107   {ERR_PROTTASKSTOP,	1,	"PROTTASKSTOP",	"Simulation stopped on attempted execution of protected system task '%s'."},
108   {ERR_NOTMEM,		1,	"NOTMEM",	"Specified net '%s' is not a memory."},
109   {ERR_CMDNOTMEM,	1,	"CMDNOTMEM",	"Specified net '%s' is not a memory in '%s' command."},
110   {ERR_SYNTAX,		1,	"SYNTAX",	"Syntax error."},
111   {ERR_BADHIER,		1,	"BADHIER",	"Hierarchical variable '%s' referenced in illegal context."},
112   {ERR_TOOFEWPP,	1,	"TOOFEWPP",	"Too few parameter ports on instance %s."},
113   {ERR_OPENTOOMANY,	1,	"OPENTOOMANY",	"Too many files open in task '%s'."},
114   {ERR_TOOMANYPP,	1,	"TOOMANYPP",	"Too many parameter ports on instance %s."},
115   {ERR_NOTOP,		1,	"NOTOP",	"Top-module '%s' not defined."},
116   {ERR_BADOPEN,		1,	"BADOPEN",	"Unable to open output file '%s' in task '%s'."},
117   {ERR_CMDNOMOD,	1,	"CMDNOMOD",	"Undefined dynamic module '%s' in '%s' command."},
118   {ERR_BADEVENTNET,	1,	"BADEVENTNET",	"Undefined net '%s' in event control expression."},
119   {ERR_NOTASK,		1,	"NOTASK",	"Undefined task '%s'."},
120   {ERR_NOTDEF,		1,	"NOTDEF",	"Undefined variable '%s'."},
121   {ERR_BADRANGE,	1,	"BADRANGE",	"Unsupported bit range [%s] on net %s (must be of form [n:0])."},
122   {ERR_GATEUNIMP,	1,	"GATEUNIMP",	"Unimplemented primitive component type on instance '%s'."},
123   {ERR_USAGE,		1,	"USAGE",	"Usage: verga [options][files...]"},
124   {ERR_CLSDWRITE,	1,	"CLSDWRITE",	"Write to closed descriptor."},
125   {ERR_PRIMPTCOUNT,	1,	"PRIMPTCOUNT",	"Wrong number of ports on primitive gate instance '%s'."},
126   {ERR_CMDARGS,		1,	"CMDARGS",	"Wrong number of arguments in '%s' command."},
127   {ERR_YYERROR,		1,	"YYERROR",	"YYError - %s."},
128   {ERR_TASKARGS,	1,	"TASKARGS",	"Task '%s' called with wrong number of arguments."},
129   {ERR_BADSTART,	1,	"BADSTART",	"Illegal start value in task '%s'."},
130   {ERR_BADSTOP,		1,	"BADSTOP",	"Illegal stop value in $readmemb."},
131   {ERR_SPECTASKUSG,	1,	"SPECTASKUSG",	"Task %s must be used in a specify block."},
132   {ERR_BADSPECTASK,	1,	"BADSPECTASK",	"Task %s can not be used in a specify block."},
133   {ERR_TIMING,		1,	"TIMING",	"Timing violation in %s[%s] %s."},
134   {ERR_NOIFDEF,		1,	"NOIFDEF",	"No matching `ifdef/`ifndef for %s declaration."},
135   {ERR_BADSPECLVAL,	1,	"BADSPECLVAL",	"Bit-ranges on path delay specifiers unsupported."},
136   {ERR_PATHDMEM,	1,	"PATHDMEM",	"Illegal declaration of memory '%s' in path-delay module - unsupported."},
137   {ERR_PATHDINOUT,	1,	"PATHDINOUT",	"Use of 'inout' in module with path-delay specification is unsupported."},
138   {ERR_PATHDLOOP,	1,	"PATHDLOOP",	"Loops in path-delay modules are unsupported."},
139   {ERR_PATHDREASSGN,	1,	"PATHDREASSGN",	"Multiple assignment of net '%s' in path-delay module is unsupported."},
140   {ERR_PATHDNOTIN,	1,	"PATHDNOTIN",	"Net '%s' has no driver and is not an input in path-delay module."},
141   {ERR_PATHDCOND,	1,	"PATHDCOND",	"Delay and trigger expressions not allowed in path-delay modules."},
142   {ERR_TASKREDEF,	1,	"TASKREDEF",	"Redefinition of task or function '%s' in module '%s'."},
143   {ERR_TASKASFUNC,	1,	"TASKASFUNC",	"Task '%s' used as function."},
144   {ERR_FUNCASTASK,	1,	"FUNCASTASK",	"Function '%s' used as task."},
145   {ERR_TASKBADTYPE,	1,	"TASKBADTYPE",	"Non-register type used in task or function."},
146   {ERR_TASKBADPORT,	1,	"TASKBADPORT",	"Only input ports are allowed on functions."},
147   {ERR_TIMESCALEU,	1,	"TIMESCALEU",	"Invalid units '%s' in `timescale declaration."},
148   {ERR_TIMESCALEN,	1,	"TIMESCALEN",	"Invalid scale '%s' in `timescale declaration (must be 1, 10 or 100)."},
149   {ERR_TIMESCALES,	1,	"TIMESCALES",	"Invalid syntax in `timescale declartion."},
150   {ERR_TIMESCALEX,	1,	"TIMESCALEX",	"Units must be larger than precision in `timescale declartion."},
151   {ERR_TIMESCALEAN,	1,	"TIMESCALEAN",	"Design contains some modules with `timescale and some without."},
152   {ERR_PARAMMIX,	1,	"PARAMMIX",	"Mixed named and unnamed parameters on interface '%s' of '%s'."},
153   {ERR_BADPORTTYPE,	1,	"BADPORTTYPE",	"Invalid type declaration used on port '%s'."},
154   {ERR_BADVALUE,	1,	"BADVALUE",	"Bad numeric value '%s'."},
155   {ERR_NONEXPCTL,	1,	"NONEXPCTL",	"Event control @(*) applied to non-expression."},
156   {ERR_NONSTATCTL,	1,	"NONSTATCTL",	"Event control @(*) applied to non-statement."},
157 
158   {ERR_MODREDEF,	1,	"MODREDEF",	"Redefinition of module '%s'."},
159   {ERR_IE_TASK,		1,	"IE_TASK",	"Task definition '%s' found outside module - internal error."},
160   {ERR_IE_NONET,	1,	"IE_NONET",	"Failed to find net '%s' - internal error."},
161   {ERR_IE_NOOP,		1,	"IE_NOOP",	"Can not find operator description -- internal error."},
162   {ERR_IE_BADEXP,	1,	"IE_BADEXP",	"Unexpected expression type %s - internal error."},
163   {ERR_IE_BADVAR,	1,	"IE_BADVAR",	"Undefined variable or unknown net - internal error."},
164   {ERR_IE_BADSTATE,	1,	"IE_BADSTATE",	"Unexpected internal state at %s  - internal error."},
165   {ERR_IE_RETURN,	1,	"IE_RETURN",	"Executed BCReturn bytecode with empty return stack - internal error."},
166   {ERR_IE_UNIMP,	1,	"IE_UNIMP",	"Unimplemented feature."},
167 };
168 static int errorTableLen = sizeof(errorTable)/sizeof(errorTable[0]);
169 
170 static ErrorDescriptor unknownError = {
171   ERR_UNKNOWN,		1,	"UNKNOWN",	"Unknown error message."
172 };
173 
174 #define EL_SCRIPTERR 2
175 static char *errLevelText[] = {"warning", "error", "scripterror"};
176 static char *errLevelTextCap[] = {"Warning", "Error", "ScriptError"};
177 
178 /*****************************************************************************
179  *
180  * Array for used to temporarily store arguments for an error message.  The
181  * array is initialized by initErrorMessages() and has a length equal to the
182  * maximum number of arguments in any error message in the error message table.
183  *
184  *****************************************************************************/
185 static char **errArgs;
186 
187 /*****************************************************************************
188  *
189  * Initialize the error table by counting the number of arguments to each message.
190  *
191  *****************************************************************************/
initErrorMessages()192 void initErrorMessages()
193 {
194   int i;
195   int maxCount = 0;
196 
197   for (i = 0;i < errorTableLen;i++) {
198     ErrorDescriptor *ed = &errorTable[i];
199     char *p;
200     int count = 0;
201 
202 
203     for (p = ed->ed_text;*p;p++) {
204       if (*p == '%') {
205 	if (p[1] == '%')
206 	  p++;
207 	else
208 	  count++;
209       }
210     }
211 
212     if (count > maxCount) maxCount = count;
213 
214     ed->ed_numArgs = count;
215   }
216 
217   errArgs = (char**)malloc(sizeof(char*)*maxCount);
218 }
219 
flushDefered()220 void flushDefered()
221 {
222   while (wdefer_head) {
223     DeferedWarning *dw = wdefer_head;
224     wdefer_head = wdefer_head->dw_next;
225     free(dw->dw_msg);
226     free(dw);
227   }
228 
229   wdefer_head = 0;
230   wdefer_tail = 0;
231 }
232 
flushErrors()233 void flushErrors()
234 {
235   extern int errCount;
236   extern int warnCount;
237 
238   errCount = 0;
239   warnCount = 0;
240   flushDefered();
241 }
242 
deferWarning(const char * msg)243 void deferWarning(const char *msg)
244 {
245   DeferedWarning *dw = (DeferedWarning*) malloc(sizeof(DeferedWarning));
246 
247   dw->dw_msg = strdup(msg);
248   dw->dw_next = 0;
249 
250   if (wdefer_tail) {
251     wdefer_tail->dw_next = dw;
252     wdefer_tail = dw;
253   } else {
254     wdefer_head = wdefer_tail = dw;
255   }
256 }
257 
reportDeferedWarnings()258 void reportDeferedWarnings()
259 {
260   DeferedWarning *dw;
261 
262   for (dw = wdefer_head;dw;dw = dw->dw_next)
263     vgio_printf("%s\n",dw->dw_msg);
264   flushDefered();
265 }
266 
267 /*****************************************************************************
268  *
269  * Dump the list of error messages in tkgate messages format.
270  *
271  *****************************************************************************/
dumpErrorMessages()272 void dumpErrorMessages()
273 {
274   int i;
275 
276   for (i = 0;i < errorTableLen;i++) {
277     ErrorDescriptor *ed = &errorTable[i];
278     int l = strlen(ed->ed_tag) + 10;
279 
280     printf("verga.err.%s",ed->ed_tag);
281 
282     l = l/8 + 1;
283 
284     for (;l < 4;l++)
285       printf("\t");
286 
287     printf("\t%s\n",ed->ed_text);
288   }
289 }
290 
291 /*****************************************************************************
292  *
293  * Find the error message descriptor for the error with the given code.
294  *
295  * Parameters:
296  *      ecode		Code number of message to find.
297  *
298  * Returns:		Error descriptor corresponding to the given error code.
299  *			Returns a special "unknown" error descriptor if the
300  *			specified code is not found.
301  *
302  *****************************************************************************/
findError(errorcode_t ecode)303 static ErrorDescriptor *findError(errorcode_t ecode)
304 {
305   int i;
306 
307   for (i = 0;i < errorTableLen;i++)
308     if (errorTable[i].ed_code == ecode)
309       return &errorTable[i];
310 
311   return &unknownError;
312 }
313 
314 /*****************************************************************************
315  *
316  * Initialize the a place to the beginning of a file.
317  *
318  * Parameters:
319  *      p			Place to be initialized
320  *      fileName		Name of file.
321  *
322  *****************************************************************************/
Place_init(Place * p,const char * fileName)323 void Place_init(Place *p, const char *fileName)
324 {
325   p->p_fileName = fileName ? strdup(fileName) : 0;
326   p->p_moduleName = 0;
327   p->p_mitem = 0;
328   p->p_lineNo = 1;
329   p->p_modLineNo = 0;
330   p->p_mtag = 0;
331 }
332 
333 /*****************************************************************************
334  *
335  * Copy a place.
336  *
337  * Parameters:
338  *      dstP			Destination place
339  *      srcP			Source place
340  *
341  *****************************************************************************/
Place_copy(Place * dstP,Place * srcP)342 void Place_copy(Place *dstP, Place *srcP)
343 {
344   *dstP = *srcP;
345 }
346 
347 /*****************************************************************************
348  *
349  * Increment the line number of a place
350  *
351  * Parameters:
352  *      p			Place to be updated
353  *      delta			Number of lines to add to place.
354  *
355  *****************************************************************************/
Place_incLineno(Place * p,int delta)356 void Place_incLineno(Place *p, int delta)
357 {
358   p->p_lineNo += delta;
359   p->p_modLineNo += delta;
360 }
361 
362 /*****************************************************************************
363  *
364  * Indicate current place is in a module
365  *
366  * Parameters:
367  *      p			Place to be updated
368  *      modName			Name of module
369  *
370  *****************************************************************************/
Place_startModule(Place * p,const char * modName)371 void Place_startModule(Place *p, const char *modName)
372 {
373   if (!p->p_mtag) {
374     p->p_moduleName = modName ? strdup(modName) : 0;
375     p->p_modLineNo = 1;
376   }
377 }
378 
379 /*****************************************************************************
380  *
381  * Indicate current place is outside a module
382  *
383  * Parameters:
384  *      p			Place to be updated
385  *
386  *****************************************************************************/
Place_endModule(Place * p)387 void Place_endModule(Place *p)
388 {
389   if (!p->p_mtag) {
390     p->p_moduleName = 0;
391     p->p_modLineNo = 1;
392   }
393 }
394 
395 /*****************************************************************************
396  *
397  * Indicate current place is inside a tag defined module
398  *
399  * Parameters:
400  *      p			Place to be updated
401  *
402  *****************************************************************************/
Place_startMTag(Place * p,const char * modName)403 void Place_startMTag(Place *p, const char *modName)
404 {
405   p->p_moduleName = modName ? strdup(modName) : 0;
406   p->p_modLineNo = 1;
407   p->p_mtag = 1;
408 }
409 
410 /*****************************************************************************
411  *
412  * Indicate current place is outside a tag defined module
413  *
414  * Parameters:
415  *      p			Place to be updated
416  *
417  *****************************************************************************/
Place_endMTag(Place * p)418 void Place_endMTag(Place *p)
419 {
420   p->p_moduleName = 0;
421   p->p_modLineNo = 1;
422   p->p_mtag = 0;
423 }
424 
425 /*****************************************************************************
426  *
427  * Generate string encoding a "place".
428  *
429  * Parameters:
430  *     p		Place to encode
431  *     etype		Error message type
432  *     s		Buffer to write encoding to.
433  *
434  * Returns:		Pointer to end of encoded string in buffer.
435  *
436  *
437  *****************************************************************************/
Place_report(Place * p,const char * etype,const char * netName,char * s)438 char *Place_report(Place *p, const char *etype, const char *netName,char *s)
439 {
440   int did_first = 0;
441 
442   if ((placeMode & PM_PRETTY)) {
443     if (strcmp(etype,"warning") == 0)
444       s += sprintf(s,"Warning: ");
445 
446     *s++ = '<';
447     if ((placeMode & PM_FILE)) {
448       s += sprintf(s, "\"%s\"",p->p_fileName);
449       did_first = 1;
450     }
451     if ((placeMode & PM_LINE)) {
452       if (did_first) s += sprintf(s, ", ");
453       s += sprintf(s, "%d",p->p_lineNo);
454       did_first = 1;
455     }
456     if ((placeMode & PM_MODULE)) {
457       if (did_first) s += sprintf(s, ", ");
458       s += sprintf(s, "[%s]",(p->p_moduleName ? p->p_moduleName : "-"));
459     }
460     if ((placeMode & PM_MODLINE))
461       s += sprintf(s, "+%d",p->p_modLineNo);
462 
463     *s++ = '>';
464     *s++ = ' ';
465   } else {
466     s += sprintf(s,"%s file",etype);
467     if ((placeMode & PM_FILE))
468       s += sprintf(s, " %s",p->p_fileName);
469     if ((placeMode & PM_LINE))
470       s += sprintf(s, " %d",p->p_lineNo);
471     if ((placeMode & PM_MODULE))
472       s += sprintf(s, " %s",(p->p_moduleName ? p->p_moduleName : "-"));
473     if ((placeMode & PM_MODLINE))
474       s += sprintf(s, " %d",p->p_modLineNo);
475     if (p->p_mitem && ModuleItem_getType(p->p_mitem) == IC_INSTANCE && !(placeMode & PM_PRETTY))
476       s += sprintf(s," %s",p->p_mitem->mi_inst.mii_instName);
477     else
478       s += sprintf(s," -");
479 
480     if (netName)
481       s += sprintf(s," %s",netName);
482     else
483       s += sprintf(s," -");
484 
485     s += sprintf(s," : ");
486   }
487 
488   *s = 0;
489   return s;
490 }
491 
492 /*****************************************************************************
493  *
494  * Set the mode for place display
495  *
496  * Parameters:
497  *      pm		Place display mode.
498  *
499  *****************************************************************************/
Place_setMode(placemode_t pm)500 void Place_setMode(placemode_t pm)
501 {
502   placeMode = pm;
503 }
504 
505 /*****************************************************************************
506  *
507  * Reset the module line number
508  *
509  * Parameters:
510  *      p		Place to update
511  *
512  *****************************************************************************/
Place_resetModLine(Place * p)513 void Place_resetModLine(Place *p)
514 {
515   p->p_modLineNo = 0;
516 }
517 
518 
519 /*****************************************************************************
520  *
521  * Set the "current" place.
522  *
523  * Parameters:
524  *      p		Place to use as current place
525  *
526  *****************************************************************************/
Place_setCurrent(Place * p)527 void Place_setCurrent(Place *p)
528 {
529   curPlace = *p;
530 }
531 
532 /*****************************************************************************
533  *
534  * Get the "current" place.
535  *
536  *****************************************************************************/
Place_getCurrent()537 Place *Place_getCurrent()
538 {
539   return &curPlace;
540 }
541 
542 /*****************************************************************************
543  *
544  * Report built-in parser errors
545  *
546  * Parameters:
547  *      err		Text of error message
548  *
549  * This function must be supported by programs using yacc.  It is only called
550  * from within built-in yacc code.  The most common message is "syntax error"
551  * and if we see this message, we translate it to ERR_SYNTAX to allow localization
552  * if necessary.
553  *
554  *****************************************************************************/
yyerror(char * err)555 int yyerror(char *err)
556 {
557   if (strncmp(err,"syntax",6) == 0)
558     errorFile(Place_getCurrent(),ERR_SYNTAX);
559   else
560     errorFile(Place_getCurrent(),ERR_YYERROR,err);
561 
562   return 0;
563 }
564 
565 /*****************************************************************************
566  *
567  * Marshal a string so that it can be read as a tcl string.
568  *
569  * Parameters:
570  *      p		Marshaled string
571  *      s		String to be marshaled
572  *
573  *****************************************************************************/
marshalString(char * p,char * s)574 static int marshalString(char *p,char *s)
575 {
576   char *start = p;		// Remeber start of marshaled string
577 
578   /* Leading quote */
579   *p++ = '"';
580 
581   for (;*s;s++) {
582     if (strchr("\\\"",*s))
583       *p++ = '\\';
584     *p++ = *s;
585   }
586 
587   /* Trailing quote */
588   *p++ = '"';
589   return p-start;
590 }
591 
592 /*****************************************************************************
593  *
594  * Format an error message
595  *
596  *****************************************************************************/
formatErrorMsg(char * p,ErrorDescriptor * ed,va_list ap)597 static int formatErrorMsg(char *p,ErrorDescriptor *ed,va_list ap)
598 {
599   if (vgsim.vg_interactive) {
600     int i;
601     char *q = p;
602 
603     p += sprintf(p,"`%s",ed->ed_tag);
604     for (i = 0;i < ed->ed_numArgs;i++) {
605       p += sprintf(p," ");
606       p += marshalString(p,va_arg(ap,char*));
607     }
608     *p = 0;
609     return p-q;
610   } else {
611     return vsprintf(p,ed->ed_text,ap);
612   }
613 
614   return 0;
615 }
616 
617 /*****************************************************************************
618  *
619  * Handle the output of error (or warning) message text.
620  *
621  * Parameters:
622  *      ed			Error type descriptor
623  *      msg			Text of the error message.
624  *
625  *****************************************************************************/
doErrorOutput(ErrorDescriptor * ed,const char * msg)626 static void doErrorOutput(ErrorDescriptor *ed,const char *msg)
627 {
628   extern int errCount;
629   extern int warnCount;
630 
631   if (ed->ed_level > 0) {
632     errCount++;
633     reportDeferedWarnings();		/* Report any defered warnings */
634     vgio_printf("%s\n",msg);
635   } else {
636     if (warning_mode > 1) {
637       warnCount++;
638       if (warning_mode == 2 && errCount == 0)
639 	deferWarning(msg);
640       else
641 	vgio_printf("%s\n",msg);
642     }
643   }
644 
645 }
646 
647 /*****************************************************************************
648  *
649  * Generate a command error
650  *
651  * Parameters:
652  *      ecode			Error code value
653  *      ...			Error-specific arguments
654  *
655  *****************************************************************************/
errorCmd(errorcode_t ecode,...)656 void errorCmd(errorcode_t ecode,...)
657 {
658   ErrorDescriptor *ed = findError(ecode);
659   char buf[STRMAX],*p;
660   va_list ap;
661   extern int errCount;
662 
663   p = buf;
664   if (vgsim.vg_interactive)
665     p += sprintf(p,"%s command ",errLevelText[ed->ed_level]);
666   else
667     p += sprintf(p,"Command %s: ",errLevelTextCap[ed->ed_level]);
668 
669   va_start(ap,ecode);
670   p += formatErrorMsg(p,ed,ap);
671   va_end(ap);
672 
673   doErrorOutput(ed,buf);
674 
675   errCount++;
676 }
677 
678 /*****************************************************************************
679  *
680  * Generate a runtime error
681  *
682  * Parameters:
683  *      ecode			Error code value
684  *      ...			Error-specific arguments
685  *
686  *****************************************************************************/
errorRun(errorcode_t ecode,...)687 void errorRun(errorcode_t ecode,...)
688 {
689   ErrorDescriptor *ed = findError(ecode);
690   char buf[STRMAX],*p;
691   va_list ap;
692   EvQueue *Q = Circuit_getQueue(&vgsim.vg_circuit);
693   simtime_t curTime = EvQueue_getCurTime(Q);
694 
695   p = buf;
696   if (vgsim.vg_interactive)
697     p += sprintf(p,"%s run %llu : ",errLevelText[ed->ed_level],curTime);
698   else
699     p += sprintf(p,"Runtime %s at %llu: ",errLevelTextCap[ed->ed_level],curTime);
700 
701   va_start(ap,ecode);
702   p += formatErrorMsg(p,ed,ap);
703   va_end(ap);
704 
705   doErrorOutput(ed,buf);
706 }
707 
708 /*****************************************************************************
709  *
710  * Generate a file error
711  *
712  * Parameters:
713  *      place			Place identifier for location of the error.
714  *      ecode			Error code value
715  *      ...			Error-specific arguments
716  *
717  *****************************************************************************/
errorFile(Place * place,errorcode_t ecode,...)718 void errorFile(Place *place,errorcode_t ecode,...)
719 {
720   ErrorDescriptor *ed = findError(ecode);
721   char message[STRMAX],*p;
722   va_list ap;
723   extern int errCount;
724   extern int warnCount;
725 
726   p = message;
727 
728   if (current_script)
729     p += sprintf(p,"scripterror %s %s %d : ",current_script,place->p_fileName,place->p_lineNo+1);
730   else
731     p = Place_report(place,errLevelText[ed->ed_level],0,message);
732 
733   va_start(ap,ecode);
734   p += formatErrorMsg(p,ed,ap);
735   va_end(ap);
736   doErrorOutput(ed,message);
737 
738 #if 0
739   if (!script_error_reporting) {
740     p = Place_report(place,errLevelText[ed->ed_level],0,message);
741     va_start(ap,ecode);
742     p += formatErrorMsg(p,ed,ap);
743     va_end(ap);
744     doErrorOutput(ed,message);
745   } else {
746     if (ed->ed_level > 0)
747       errCount++;
748     else
749       warnCount++;
750   }
751 #endif
752 }
753 
754 /*****************************************************************************
755  *
756  * Generate a module error
757  *
758  * Parameters:
759  *      m			Module in which error occured.
760  *      place			Place identifier for location of the error.
761  *      ecode			Error code value
762  *      ...			Error-specific arguments
763  *
764  *****************************************************************************/
errorModule(ModuleDecl * m,Place * place,errorcode_t ecode,...)765 void errorModule(ModuleDecl *m,Place *place,errorcode_t ecode,...)
766 {
767   ErrorDescriptor *ed = findError(ecode);
768   char buf[STRMAX],*p;
769   va_list ap;
770 
771   if (m->m_errorsDone) return;
772 
773   p = Place_report(place,errLevelText[ed->ed_level],0,buf);
774 
775   va_start(ap,ecode);
776   p += formatErrorMsg(p,ed,ap);
777   va_end(ap);
778 
779   doErrorOutput(ed,buf);
780 }
781 
782 /*****************************************************************************
783  *
784  * Generate a net error
785  *
786  * Parameters:
787  *      m			Module in which error occured.
788  *      place			Place identifier for location of the error.
789  *      ecode			Error code value
790  *      ...			Error-specific arguments
791  *
792  *****************************************************************************/
errorNet(ModuleDecl * m,const char * net,Place * place,errorcode_t ecode,...)793 void errorNet(ModuleDecl *m,const char *net,Place *place,errorcode_t ecode,...)
794 {
795   ErrorDescriptor *ed = findError(ecode);
796   char buf[STRMAX],*p;
797   va_list ap;
798 
799   if (m->m_errorsDone) return;
800 
801   p = Place_report(place,errLevelText[ed->ed_level],net,buf);
802 
803   va_start(ap,ecode);
804   p += formatErrorMsg(p,ed,ap);
805   va_end(ap);
806 
807   doErrorOutput(ed,buf);
808 }
809