1 /* Copyright (c) 1986-2007 Pragmatic C Software Corp. */
2 
3 /*
4    This program is free software; you can redistribute it and/or modify it
5    under the terms of the GNU General Public License as published by the
6    Free Software Foundation; either version 2 of the License, or (at your
7    option) any later version.
8 
9    This program is distributed in the hope that it will be useful, but
10    WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    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    59 Temple Place, Suite 330, Boston, MA, 02111-1307.
17 
18    We are selling our new Verilog compiler that compiles to X86 Linux
19    assembly language.  It is at least two times faster for accurate gate
20    level designs and much faster for procedural designs.  The new
21    commercial compiled Verilog product is called CVC.  For more information
22    on CVC visit our website at www.pragmatic-c.com/cvc.htm or contact
23    Andrew at avanvick@pragmatic-c.com
24 
25  */
26 
27 
28 /*
29  * miscellaneous routines
30  */
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 
36 #include <pwd.h>
37 
38 #include <sys/types.h>
39 #include <sys/timeb.h>
40 #include <sys/fcntl.h>
41 #include <sys/stat.h>
42 #include <unistd.h>
43 
44 #include <time.h>
45 #include <setjmp.h>
46 #include <ctype.h>
47 #include <errno.h>
48 #include <stdarg.h>
49 
50 #ifdef __DBMALLOC__
51 #include "../malloc.h"
52 #endif
53 
54 /* REMOVEME - no longer supporting SunOS - maybe needed for hpux? */
55 #if defined(__sparc) && !defined(__SVR4) && !defined(__FreeBSD__)
56 extern int32 tolower(int32);
57 extern ungetc(int32 c, FILE *);
58 extern long time (long *);
59 #endif
60 
61 #include "v.h"
62 #include "cvmacros.h"
63 
64 /* local prototypes */
65 static char *expand_arg_macro(struct sy_t *, int32 *);
66 static void process_macdef(void);
67 static void dmp_macdef_exptab(char *, struct macexp_t *);
68 static void process_macundef(void);
69 static char *bld_macdef_arglist(int32 *);
70 static char *remchk_macdef_coms(char *);
71 static struct macexp_t *bld_mac_expandtab(char *, char *, int32);
72 static int32 find_mac_formal_arg(char *);
73 static void free_macexplst(register struct macexp_t *);
74 static void do_argmacdefine(char *, struct macexp_t *, int32);
75 static int32 cskip_ifdef_section(FILE *, int32);
76 static int32 my_getc(FILE *);
77 static int32 rd_comment(FILE *);
78 static int32 skipto_attr_end(FILE *);
79 static void rd_attribute(FILE *);
80 static int32 vgetstr(FILE *);
81 static void str_tovval(void);
82 static void unget2_vtok(int32);
83 static int32 rd_num(FILE *, int32);
84 static void rem_lead_0chars(char *);
85 static int32 voverwhite(FILE *, register int32);
86 static int32 chlen_to_bitlen(int32, int32);
87 static void chg_abwrklen(int32);
88 static void to_dec(int32 *);
89 static void wide_strtoverdec(int32);
90 static void to_bin(int32);
91 static void to_oct(int32);
92 static void to_hex(int32);
93 static int32 vnum_toowide(word32 *, int32);
94 static int32 nibblexz(word32, word32, int32);
95 static int32 octdigxz(word32 *, word32 *, int32);
96 static void widen_val(word32 *, int32, int32, word32);
97 static char *prt2_vtok(int32);
98 static int32 get_vkeywrd(register char *);
99 static int32 set_syncto_tokclass(byte);
100 static int32 set_specitem_class(void);
101 static int32 set_udpsyncto(byte);
102 static int32 get_cfgkeywrd(char *);
103 static int32 get_cmdcomment(FILE *);
104 static void one_rot(struct tnode_t *, struct tnode_t *, struct tnode_t *);
105 static void two_rot(struct tnode_t *, struct tnode_t *, struct tnode_t *);
106 static struct tnode_t *alloc_tnode(struct symtab_t *);
107 static char *__to_nppsubtyp(char *, word32);
108 static char *decompnum_to_str(char *, char *, int32, int32);
109 static char *nfbig_alloc(int32);
110 static char *tilde_expand(char *, int32 *);
111 static char *pv_stralloc2(char *);
112 static int32 try_chg_tononesc(void);
113 static int32 ch_tobits(word32 *, word32 *, int32);
114 static int32 ch_toocts(word32 *, word32 *, int32);
115 static int32 ch_tohexs(word32 *, word32 *, int32);
116 
117 /* extern prototypes (maybe defined in this module) */
118 extern void __get_vtok(void);
119 extern int32 __chk_beg_line(int32);
120 extern void __collect_line(void);
121 extern void __skipover_line(void);
122 extern void __do_macdefine(char *, char *);
123 extern int32 __bqline_emptytail(register char *);
124 extern void __do_include(void);
125 extern int32 __rd_ialine(void);
126 extern int32 __get1_vtok(FILE *);
127 extern void __vstr_to_vval(word32 *, char *, int32);
128 extern struct xstk_t *__cstr_to_vval(char *);
129 extern void __unget_vtok(void);
130 extern int32 __to_base(int32);
131 extern int32 __is_vdigit(int32, int32);
132 extern void __to_dhboval(int32, int32);
133 extern char *__prt_vtok(void);
134 extern char *__to_opname(word32);
135 extern char *__get_vkeynam(char *, int32);
136 extern int32 __vskipto_modend(int32);
137 extern int32 __vskipto2_modend(int32, int32);
138 extern int32 __vskipto3_modend(int32, int32, int32);
139 extern int32 __vskipto_any(int32);
140 extern int32 __vskipto2_any(int32, int32);
141 extern int32 __vskipto3_any(int32, int32, int32);
142 extern int32 __vskipto4_any(int32, int32, int32, int32);
143 extern int32 __spec_vskipto_any(int32);
144 extern int32 __spec_vskipto2_any(int32, int32);
145 extern int32 __spec_vskipto3_any(int32, int32, int32);
146 extern int32 __udp_vskipto_any(int32);
147 extern int32 __udp_vskipto2_any(int32, int32);
148 extern int32 __udp_vskipto3_any(int32, int32, int32);
149 extern int32 __get_cmdtok(FILE *);
150 extern struct sy_t *__get_sym_env(char *);
151 extern struct sy_t *__find_sym(char *);
152 extern struct sy_t *__decl_sym(char *, struct symtab_t *);
153 extern void __add_sym(char *, struct tnode_t *);
154 extern struct sy_t *__get_sym(char *, struct symtab_t *);
155 extern struct tnode_t *__vtfind(char *, struct symtab_t *);
156 extern struct sy_t *__zget_sym(char *, struct sy_t **, word32);
157 extern struct symtab_t *__alloc_symtab(int32);
158 extern int32 __ip_indsrch(char *);
159 extern char *__to_idnam(struct expr_t *);
160 extern char *__to_mpnam(char *, char *);
161 extern int32 __fr_wtnam(int32);
162 extern char *__to_wtnam(char *, struct net_t *);
163 extern char *__to_wtnam2(char *, word32);
164 extern char *__to_ptnam(char *, word32);
165 extern char *__to_splt_nam(char *, int32);
166 extern word32 __fr_stren_nam(int32);
167 extern char *__to_stren_nam(char *, int32, int32);
168 extern char *__to_stval_nam(char *, word32);
169 extern char *__to1_stren_nam(char *, int32, int32);
170 extern int32 __is_capstren(int32);
171 extern int32 __fr_cap_size(int32);
172 extern word32 __to_cap_size(int32);
173 extern char *__to_sytyp(char *, word32);
174 extern char *__to_tsktyp(char *, word32);
175 extern char *__to_sttyp(char *, word32);
176 extern char *__to_qctyp(char *, word32);
177 extern char *__to_tetyp(char *, word32);
178 extern char *__to_npptyp(char *, struct net_pin_t *);
179 extern char *__to_deltypnam(char *, word32);
180 extern char *__to_tcnam(char *, word32);
181 extern int32 __fr_tcnam(char *);
182 extern char *__to_gonam(char *, struct gate_t *, word32);
183 extern char *__to_ginam(char *, struct gate_t *, word32, int32);
184 extern char *__to_vnam(char *, word32, word32);
185 extern char *__to_vvstnam(char *, word32);
186 extern char *__to_vvnam(char *, word32);
187 extern char *__to_uvvnam(char *, word32);
188 extern char __to_baselet(int32);
189 extern char *__to_timunitnam(char *, word32);
190 extern char *__to_edgenam(char *, word32);
191 extern char *__to_dcenam(char *, word32);
192 extern char *__pv_stralloc(char *);
193 extern char *__my_malloc(int32);
194 extern void __my_free(char *, int32);
195 extern char *__my_realloc(char *, int32, int32);
196 extern void __my_fclose(FILE *);
197 extern void __my_rewind(FILE *);
198 extern int32 __tilde_open(char *, int32);
199 extern FILE *__tilde_fopen(char *, char *);
200 extern FILE *__my_fopen(char *, char *);
201 extern int32 __tilde_creat(char *);
202 extern int32 __my_creat(char *);
203 extern char *__schop(char *, char *);
204 extern char *__bld_lineloc(char *, word32, int32);
205 extern void __init_sy(struct sy_t *);
206 
207 extern void __crit_msg(char *, ...);
208 extern void __sysfatal_msg(char *, ...);
209 extern void __cv_msg(char *, ...);
210 extern void __cvsim_msg(char *, ...);
211 extern void __dbg_msg(char *, ...);
212 extern void __misc_terr(char *, int32);
213 extern void __misc_fterr(char *, int32);
214 extern void __misc_gfterr(char *, int32, word32, int32);
215 extern void __misc_sgfterr(char *, int32);
216 extern void __case_terr(char *, int32);
217 extern void __arg_terr(char *, int32);
218 extern void __pv_terr(int32, char *, ...);
219 extern void __fterr(int32, char *, ...);
220 extern void __sgfterr(int32, char *, ...);
221 extern void __gfterr(int32, word32, int32, char *, ...);
222 extern void __pv_err(int32, char *, ...);
223 extern void __pv_ferr(int32, char *, ...);
224 extern void __sgferr(int32, char *, ...);
225 extern void __gferr(int32, word32, int32, char *, ...);
226 extern void __ia_err(int32, char *, ...);
227 extern void __via_err(int32, char *, va_list, va_list);
228 extern void __pv_warn(int32, char *, ...);
229 extern void __pv_fwarn(int32, char *, ...);
230 extern void __sgfwarn(int32, char *, ...);
231 extern void __gfwarn(int32, word32, int32, char *, ...);
232 extern void __ia_warn(int32, char *, ...);
233 extern void __via_warn(int32, char *, va_list, va_list);
234 extern void __inform(int32, char *, ...);
235 extern void __finform(int32, char *, ...);
236 extern void __sgfinform(int32, char *, ...);
237 extern void __gfinform(int32, word32, int32, char *, ...);
238 extern int32 __em_suppr(int32);
239 extern void __my_fprintf(FILE *, char *, ...);
240 extern void __my_vfprintf(FILE *, char *, va_list, va_list);
241 extern void __vpi_error_trycall(void);
242 extern void __cberror_fill_einfo(int32, int32, char *, char *, int32);
243 
244 extern int32 __pop_vifstk(void);
245 extern int32 __open_sfil(void);
246 extern void __push_vinfil(void);
247 extern void __grow_infils(int32);
248 extern void __grow_xstk(void);
249 extern void __chg_xstk_width(struct xstk_t *, int32);
250 extern double __my_strtod(char *, char **, int32 *);
251 extern word32 __my_strtoul(char *, char **, int *);
252 extern int32 __trim1_0val(word32 *, int32);
253 extern void __lmult(register word32 *, register word32 *, register word32 *, int32);
254 extern void __ladd(word32 *, word32 *, word32 *, int32);
255 extern void __lhsbsel(register word32 *, register int32, word32);
256 extern void __lhspsel(register word32 *, register int32, register word32 *, register int32);
257 extern void __rhspsel(register word32 *, register word32 *, register int32, register int32);
258 extern void __my_exit(int32, int32);
259 extern char *__to_timstr(char *, word64 *);
260 extern int32 __notokenize_skiplines(char *);
261 extern char *__to_dispst_str(char *, word32);
262 
263 
264 extern struct opinfo_t __opinfo[];
265 extern byte __stren_map_tab[];
266 extern word32 __masktab[];
267 
268 /* system stuff */
269 extern int32 errno;
270 
271 /* jmp buf defined in v_dbg */
272 extern jmp_buf __iact_jmpbuf;
273 extern char __pv_ctab[];
274 
275 /*
276  * ROUTINES THE INTERFACE TO GET TOKEN ROUTINES
277  */
278 
279 /*
280  * get a Verilog token (outer routine for macro handling)
281  *
282  * routine sets globals __toktyp and __token and may set other for numbers
283  * (modified from yylex in "The Unix Programming Environment" p. 337)
284  *
285  * BEWARE - need to be careful here because for efficiency using global
286  * strings ok to use __xs but not call prt2_vtok more than once in error
287  */
__get_vtok(void)288 extern void __get_vtok(void)
289 {
290  int32 ttyp, ifdtyp, len, savlin_cnt;
291  struct sy_t *syp, *tmpsyp;
292  char *chp;
293 
294  /* assume no attribute prefix */
295  __attr_prefix = FALSE;
296  if (__lasttoktyp != UNDEF)
297   {
298    __toktyp = __lasttoktyp;
299    strcpy(__token, __lasttoken);
300    __lasttoktyp = UNDEF;
301    /* SJM 10/16/00 - must save and restore state of pending attr prefix */
302    /* seen when token is pushed back - happens for endmodule then read of */
303    /* module to check for EOF */
304    __attr_prefix = __last_attr_prefix;
305 
306    /* extremely rare number push back case */
307    if (__toktyp == NUMBER)
308     {
309      word32 wlen;
310 
311      __itokbase = __lastitokbase;
312      __itoksized = __lastitoksized;
313      __itoksizdflt = __lastitoksizdflt;
314      __itok_signed = __lastitok_signed;
315      __itoklen = __lastitoklen;
316 
317      /* used malloc to save const value, now need to restore and free */
318      wlen = wlen_(__itoklen);
319      memcpy(__acwrk, __lastacwrk, wlen*WRDBYTES);
320      __my_free((char *) __lastacwrk, wlen*WRDBYTES);
321      memcpy(__bcwrk, __lastbcwrk, wlen*WRDBYTES);
322      __my_free((char *) __lastbcwrk, wlen*WRDBYTES);
323      __lastacwrk = __lastbcwrk = NULL;
324     }
325    else if (__toktyp == REALNUM)
326     {
327      __itokbase = __lastitokbase;
328      __itoksized = __lastitoksized;
329      __itoksizdflt = __lastitoksizdflt;
330      __itok_signed = __lastitok_signed;
331      __itoklen = __lastitoklen;
332      __itok_realval = __lastitok_realval;
333     }
334    return;
335   }
336 
337 vtagain:
338  /* file will be NULL when reading from macro text */
339  switch ((byte) (ttyp = __get1_vtok(__in_s))) {
340   case TEOF:
341    /* first try to pop some sort of outer nested thing */
342    if (__pop_vifstk())
343     {
344      /* SJM 06/22/00 - for 2 stage 2 tok num - ready to read 2nd tok of num */
345      if (__macro_sep_width)
346       {
347        __maybe_2tok_sized_num = TRUE;
348        __macro_sep_width = FALSE;
349       }
350      goto vtagain;
351     }
352    /* next try to replace just finished 0th element with new input file */
353    if (__cur_infi + 1 > __last_inf || __iact_state)
354     { __toktyp = TEOF; return; }
355    __cur_infi++;
356    if (!__open_sfil()) { __toktyp = TEOF; return; }
357    /* know first token of file flag now on */
358    goto vtagain;
359   case CDIR_DEFINE:
360    /* on return - know all of line read */
361    process_macdef();
362    goto vtagain;
363   case CDIR_UNDEF:
364    process_macundef();
365    goto vtagain;
366   case CDIR_INCLUDE:
367    if (__iact_state)
368     {
369 illegal_iact_dir:
370      __ia_err(1401, "%s compiler directive illegal in interactive commands",
371       prt2_vtok(ttyp));
372      __skipover_line();
373      goto vtagain;
374     }
375    /* on return all of line read - trims tail of line for file name */
376    if (!__chk_beg_line(CDIR_INCLUDE)) goto vtagain;
377    /* collect line into mac wr kstrafter first skips white space to token */
378    __collect_line();
379    __do_include();
380    goto vtagain;
381   case CDIR_IFDEF: case CDIR_IFNDEF:
382    if (__iact_state) goto illegal_iact_dir;
383    ifdtyp = ttyp;
384    if (!__chk_beg_line(ifdtyp)) goto vtagain;
385    /* see if token `defined */
386    savlin_cnt = __lin_cnt;
387    if ((ttyp = __get1_vtok(__in_s)) != ID)
388     {
389      /* BEWARE */
390      /* must use get vkeynam for compile directive (know only 2 possible) */
391      /* because prt2_vtok uses fixed storage */
392      __pv_ferr(923, "%s not followed by text macro name - %s read",
393       __get_vkeynam(__xs, ifdtyp), prt2_vtok(ttyp));
394      goto skip_rest;
395     }
396    if (*__token == '`')
397     {
398      __pv_fwarn(570,
399       "%s text macro name %s should not begin with ` - dropped",
400       __get_vkeynam(__xs, ifdtyp), __token);
401      strcpy(__xs, __token);
402      goto skip_rest;
403     }
404    else { strcpy(&(__xs[1]), __token); __xs[0] = '`'; }
405    if (savlin_cnt != __lin_cnt)
406     {
407      __pv_ferr(921, "%s text macro name must be on same line",
408       __get_vkeynam(__xs, ifdtyp));
409      unget2_vtok(ttyp);
410      /* to get here know moved to next line */
411      goto vtagain;
412     }
413    __in_ifdef_level++;
414    /* notice for macro with args. here still just use name */
415    tmpsyp = __get_sym(__xs, __pv_defsyms);
416 
417    /* undeclare when macro undefed because no way to remove from symtab */
418    if (tmpsyp != NULL && !tmpsyp->sydecl) tmpsyp = NULL;
419 
420    /* `ifndef reverses sense of `ifdef - following C preprocessor */
421    if ((ifdtyp == CDIR_IFDEF && tmpsyp == NULL)
422     || (ifdtyp == CDIR_IFNDEF && tmpsyp != NULL))
423     {
424      /* case 1: `ifdef symbol not defined (i.e. if fails) */
425      if (cskip_ifdef_section(__in_s, ifdtyp) == CDIR_ENDIF)
426       {
427        /* if this is `endif just skipped `ifdef (or `ifndef) so continue */
428        /* if else enter look for else state */
429        __in_ifdef_level--;
430       }
431      /* `else or `endif read and processed when get to here */
432      /* know if end with `else, will be ready to include `else lines */
433      /* if this is `endif get an actual token */
434      goto vtagain;
435     }
436    /* case 2: symbol defined - continue getting tokens to `else or endif` */
437 skip_rest:
438    /* must always skip over rest of line */
439    __skipover_line();
440    goto vtagain;
441   case CDIR_ELSE:
442    if (__iact_state) goto illegal_iact_dir;
443    if (!__chk_beg_line(CDIR_ELSE)) goto vtagain;
444    /* know ifdef was true - this is end and need to skip */
445    if (__in_ifdef_level == 0)
446     {
447      __pv_ferr(924, "`else read but no previous matching initial `ifdef");
448      goto skip_rest;
449     }
450    /* if skip to another else, this will emit error and continue */
451    /* know can only return with `endif */
452    cskip_ifdef_section(__in_s, CDIR_ELSE);
453    __in_ifdef_level--;
454    /* this will have consumed `endif line */
455    goto vtagain;
456   case CDIR_ENDIF:
457    if (__iact_state) goto illegal_iact_dir;
458    if (!__chk_beg_line(CDIR_ENDIF)) goto vtagain;
459    __skipover_line();
460    /* think this can never happen */
461    if (__in_ifdef_level == 0)
462     {
463      __pv_ferr(925, "`endif read but no previous matching initial `ifdef");
464      goto vtagain;
465     }
466    __in_ifdef_level--;
467    /* else just up one nested ifdef level */
468    goto vtagain;
469   /* SJM 09/18/99 - these need to be supported inside modules */
470   case CDIR_ENDPROTECT:
471   case CDIR_ENDPROTECTED:
472   case CDIR_PROTECT:
473   case CDIR_PROTECTED:
474    __pv_fwarn(619, "directive %s unimplemented", prt2_vtok(ttyp));
475    __skipover_line();
476    goto vtagain;
477   /* notice time scale can only appear outside modules*/
478   case ID:
479    /* user redefinition of compiler directive overwrites keyword */
480    if (*__token == '$') goto ret_id;
481 
482    if (*__token == '`')
483     {
484      if ((syp = __get_sym(__token, __pv_defsyms)) == NULL || !syp->sydecl)
485       {
486        __pv_fwarn(654,
487         "text macro %s undefined or possibly compiler directive for other tool - ignored",
488         __token);
489        goto vtagain;
490       }
491      if (!syp->sy_argsmac)
492       {
493        chp = syp->el.edfchp;
494        /* `define macros can be empty from +define+ command arg */
495        if (strcmp(chp, "") == 0) goto vtagain;
496        len = -1;
497       }
498      else
499       {
500        int32 sav_first_num_eol;
501 
502        /* save first tok state, if `xx expands to compiler dir. must be 1st */
503        /* 2 stage num eol in get 1 vtok sets first of line */
504        if (__first_linetok) sav_first_num_eol = TRUE;
505        else sav_first_num_eol = FALSE;
506 
507        /* expand into malloced storage setting length to len */
508        /* this may unget TEOF token */
509        chp = expand_arg_macro(syp, &len);
510        __first_num_eol = sav_first_num_eol;
511        if (chp == NULL) goto vtagain;
512       }
513      /* if currently reading file, must preserve line count */
514      if (__visp->vi_s != NULL) __visp->vilin_cnt = __lin_cnt;
515      /* push string on top of read stack */
516      __push_vinfil();
517      __visp->vichp = __visp->vichp_beg = chp;
518      __visp->vichplen = len;
519      __in_s = NULL;
520      /* DBG remove --- */
521      if (__debug_flg)
522       __dbg_msg("macro %s value [%s]\n", syp->synam, chp);
523      /* --- */
524      goto vtagain;
525     }
526 ret_id:
527    __file_just_op = FALSE;
528    __toktyp = ID;
529    break;
530   default:
531    /* if this is not directive, must indicate not at start of file */
532    if (ttyp < CDIR_TOKEN_START || ttyp > CDIR_TOKEN_END)
533     __file_just_op = FALSE;
534    __toktyp = ttyp;
535    break;
536   }
537  /* SJM 06/22/00 - using 2 state 2 token number - finished by here */
538  __maybe_2tok_sized_num = FALSE;
539  /* DBG remove --
540  if (__debug_flg)
541   {
542    if (__toktyp == ID) __dbg_msg("++ returning token %s [%d]\n", __token,
543     __toktyp);
544    else __dbg_msg("++ returning token %s [%d]\n", __prt_vtok(), __toktyp);
545   }
546  --- */
547 }
548 
549 /* macro for adding char and growing mac wrk str */
550 #define addto_macwrkstr_(c) \
551  do { \
552   int32 osize; \
553   if (++len >= __macwrklen - 1) \
554    { \
555     osize = __macwrklen; \
556     __macwrklen += IDLEN; \
557     __macwrkstr = __my_realloc(__macwrkstr, osize, __macwrklen); \
558     chp = &(__macwrkstr[len - 1]); \
559    } \
560   *chp++ = (c); \
561  } while (0)
562 
563 /*
564  * expand a macro with arguments
565  *
566  * collects , (...) list which may have syntax errors into mac work string
567  * list cannot cross macro or include but can contain white space
568  * build array of args that are malloced using __macwrkstr
569  * processing within argument () special char not token scanning
570  * reads ending ) then stops reading
571  *
572  * notice sections of text with unmatched ) or , are illegal since
573  * in Verilog \ escapes an identifier
574  */
expand_arg_macro(struct sy_t * syp,int32 * explen)575 static char *expand_arg_macro(struct sy_t *syp, int32 *explen)
576 {
577  register int32 c;
578  register char *chp, *chp2;
579  int32 ttyp, par_cnt, setb_cnt, setb_err, last_argno, last_i, len;
580  struct amac_t *amacp;
581  struct macexp_t *mxp;
582  struct macarg_t *macap, *macap2, *maca_hdr, *maca_end, **mactab;
583 
584  *explen = -1;
585  if ((ttyp = __get1_vtok(__in_s)) != LPAR)
586   {
587    __pv_ferr(1270, "%s macro argument list ( expected - %s read",
588     syp->synam, prt2_vtok(ttyp));
589    unget2_vtok(ttyp);
590    return(NULL);
591   }
592  /* get each argument first into mac wrk str then alloc */
593  /* argument is string before next non nested , or ) */
594  macap = maca_end = maca_hdr = NULL;
595  for (c = -1, last_argno = 0;; last_argno++)
596   {
597    setb_err = FALSE;
598    par_cnt = setb_cnt = 0;
599    for (chp = __macwrkstr, len = 0;;)
600     {
601      c = my_getc(__in_s);
602      switch (c) {
603       case EOF:
604 eof_err:
605        __pv_ferr(1295,
606         "%s macro argument no. %d **EOF** read before argument ending , or )",
607         syp->synam, last_argno);
608        /* must put back eof */
609        my_ungetc_(c, __in_s);
610        /* allow memory leak on syntax eof error */
611        return(NULL);
612       case '(': par_cnt++; break;
613       case ')':
614        /* if this is extra ) must end - error if in concat */
615        if (par_cnt == 0)
616         {
617          if (setb_cnt > 0)
618           __pv_ferr(1296,
619           "%s macro argument no. %d list ending ) found but concatenate not ended",
620           syp->synam, last_argno);
621          goto arg_end;
622         }
623        par_cnt--;
624        break;
625       case '{': setb_cnt++; break;
626       case '}':
627        if (setb_cnt == 0 && !setb_err)
628         {
629          __pv_ferr(1297,
630           "%s macro argument no. %d list nested concatenate illegal - too many }s",
631           syp->synam, last_argno);
632          setb_err = TRUE;
633         }
634        else setb_cnt--;
635        break;
636       case ',':
637        if (par_cnt == 0 && setb_cnt == 0) goto arg_end;
638        break;
639       /* copy all chars in quoted string - vgetstr used later to scan */
640       case '"':
641        addto_macwrkstr_(c);
642        for (;;)
643         {
644          c = my_getc(__in_s);
645          /* must not end on escaped " */
646          if (c == '\\') { addto_macwrkstr_(c); c = my_getc(__in_s); }
647          else if (c == '"') break;
648 
649          if (c == EOF) goto eof_err;
650          /* here collect embedded new line, error later */
651          if (c == '\n') { __lin_cnt++; __total_rd_lines++; }
652          addto_macwrkstr_(c);
653         }
654        break;
655       /* copy from escape through white space since maybe esc. id */
656       /* no escaping inside escaped ID */
657       case '\\':
658        addto_macwrkstr_(c);
659        for (;;)
660         {
661          c = my_getc(__in_s);
662          if (c == EOF) goto eof_err;
663          if (vis_white_(c)) break;
664          addto_macwrkstr_(c);
665         }
666        break;
667      }
668      if (c == '\n') { __lin_cnt++; __total_rd_lines++; }
669      addto_macwrkstr_(c);
670     }
671 arg_end:
672    *chp = '\0';
673    macap = (struct macarg_t *) __my_malloc(sizeof(struct macarg_t));
674    macap->macargnam = __pv_stralloc(__macwrkstr);
675    macap->macargnxt = NULL;
676    if (maca_end == NULL) maca_hdr = maca_end = macap;
677    else maca_end->macargnxt = macap;
678    maca_end = macap;
679    if (c == ')') break;
680   }
681  /* convert argument list to table for look up from sym mac exp. tab */
682  mactab = (struct macarg_t **)
683   __my_malloc((last_argno + 1)*sizeof(struct macarg_t *));
684  for (last_i = -1, macap = maca_hdr; macap != NULL; macap = macap->macargnxt)
685   mactab[++last_i] = macap;
686  /* DBG remove */
687  if (last_i != last_argno) __misc_terr(__FILE__, __LINE__);
688  /* --- */
689  amacp = syp->el.eamacp;
690  if (last_i + 1 != amacp->num_formal_args)
691   {
692    __pv_ferr(1298,
693     "%s macro requires %d formal arguments - %d present", syp->synam,
694     amacp->num_formal_args, last_i + 1);
695    chp2 = NULL;
696    goto done;
697   }
698  /* do the expansion */
699  chp = __macwrkstr;
700  for (len = 0, mxp = amacp->amxp; mxp != NULL; mxp = mxp->macexpnxt)
701   {
702    /* copy into chp the leading string */
703    for (chp2 = mxp->leading_str; *chp2 != '\0'; chp2++)
704     addto_macwrkstr_(*chp2);
705    /* copy the actual argument, -1 for none (trailing part) */
706    if (mxp->ins_argno != -1)
707     {
708      for (chp2 = mactab[mxp->ins_argno]->macargnam; *chp2 != '\0'; chp2++)
709       addto_macwrkstr_(*chp2);
710     }
711   }
712  *chp = '\0';
713  chp2 = __my_malloc(len + 1);
714  strcpy(chp2, __macwrkstr);
715  *explen = len;
716 
717  /* final step - free actual arg list */
718 done:
719  for (macap = maca_hdr; macap != NULL;)
720   {
721    macap2 = macap->macargnxt;
722    __my_free((char *) macap->macargnam, strlen(macap->macargnam) + 1);
723    __my_free((char *) macap, sizeof(struct macarg_t));
724    macap = macap2;
725   }
726  maca_hdr = NULL;
727  __my_free((char *) mactab, (last_argno + 1)*sizeof(struct macarg_t *));
728  return(chp2);
729 }
730 
731 /*
732  * process one `define macro define
733  * know `define read and consumes entire line
734  * notice macro name must be in symbol table with `
735  */
process_macdef(void)736 static void process_macdef(void)
737 {
738  int32 ttyp, has_err, savlin_cnt, nargs, c, space_before_lpar;
739  char *mactxt_chp, dnam[IDLEN];
740  struct macexp_t *mxp;
741 
742  if (!__chk_beg_line(CDIR_DEFINE)) return;
743  savlin_cnt = __lin_cnt;
744  has_err = FALSE;
745  if ((ttyp = __get1_vtok(__in_s)) != ID)
746   {
747    __pv_ferr(922, "`define not followed by text macro identifier - %s read",
748     prt2_vtok(ttyp));
749    has_err = TRUE;
750   }
751  /* need to use get token that does not know about line breaks */
752  if (__lin_cnt != savlin_cnt)
753   {
754    __pv_ferr(929, "`define text macro identifier name must be on same line");
755    unget2_vtok(ttyp);
756    return;
757   }
758  if (!has_err && __token[0] == '`')
759   {
760    __pv_ferr(1291,
761     "`define text macro identifier name %s cannot begin with `", __token);
762    has_err = TRUE;
763   }
764  if (!has_err) { strcpy(dnam, "`"); strcat(dnam, __token); }
765  /* always collect entire line (with possible escaped nl) into mac wrk str */
766 
767  c = my_getc(__in_s);
768  /* if white space collect will skip anyway - no need to unget */
769  if (vis_nonnl_white_(c)) space_before_lpar = TRUE;
770  else
771   {
772    space_before_lpar = FALSE;
773    my_ungetc_(c, __in_s);
774   }
775  __collect_line();
776 
777  /* if problem with definition but saw `define return after line read */
778  if (has_err) return;
779 
780  if (get_vkeywrd(dnam) != ID)
781   {
782    __pv_ferr(1293,
783     "macro name %s conflicts with predefined directive - redefinition illegal",
784     dnam);
785    return;
786   }
787 
788  /* if has argument build list and return start of body in mac wrk str */
789  /* returns nil if error (it emits the message) */
790  /* SJM - 01/31/00 - now for arg macros ( must be next char (no intervening white space) */
791  /*                  otherwise ( treated as grouping param */
792  if (!space_before_lpar && __macwrkstr[0] == '(')
793   {
794    /* build the global formal argument list and skip over it */
795    if ((mactxt_chp = bld_macdef_arglist(&nargs)) == NULL) return;
796 
797    /* remove all comments macro and replace multiple white space with 1 sp */
798    /* also remove trailing white space */
799    /* this replaces value in mac wrk str - will always be no longer */
800    if ((mactxt_chp = remchk_macdef_coms(mactxt_chp)) == NULL) return;
801 
802    /* if expands to empty (could be some white space) make one space */
803    if ((mxp = bld_mac_expandtab(dnam, mactxt_chp, nargs)) == NULL)
804     { strcpy(__macwrkstr, " "); goto do_nonarg; }
805    do_argmacdefine(dnam, mxp, nargs);
806    if (__debug_flg) dmp_macdef_exptab(dnam, mxp);
807   }
808  else
809   {
810 do_nonarg:
811    /* SJM - 01/31/00 - continue to support old escaped scheme */
812    if (__macwrkstr[0] == '\\' && __macwrkstr[1] == '(')
813     mactxt_chp = &(__macwrkstr[1]);
814    else mactxt_chp = __macwrkstr;
815    if ((mactxt_chp = remchk_macdef_coms(mactxt_chp)) == NULL) return;
816    __do_macdefine(dnam, mactxt_chp);
817    if (__debug_flg)
818     __dbg_msg("+++ text macro %s defined with value [%s]\n", dnam,
819      mactxt_chp);
820   }
821 }
822 
823 /*
824  * dump the arg. macro expansion table for debugging
825  */
dmp_macdef_exptab(char * dnam,struct macexp_t * mxp)826 static void dmp_macdef_exptab(char *dnam, struct macexp_t *mxp)
827 {
828  int32 argno;
829 
830  __dbg_msg("+++ arg text macro %s defined - expands from:\n", dnam);
831  for (argno = 1; mxp != NULL; mxp = mxp->macexpnxt, argno++)
832   {
833    __dbg_msg("    arg. %d: prefix [%s] insert actual %d\n",
834     argno, mxp->leading_str, mxp->ins_argno);
835   }
836  __dbg_msg("+++ end of formal args +++\n");
837 }
838 
839 /*
840  * undefine a macro
841  */
process_macundef(void)842 static void process_macundef(void)
843 {
844  int32 ttyp, has_err, savlin_cnt;
845  struct sy_t *syp;
846  char dnam[IDLEN];
847 
848  if (!__chk_beg_line(CDIR_UNDEF)) return;
849  savlin_cnt = __lin_cnt;
850  has_err = FALSE;
851  if ((ttyp = __get1_vtok(__in_s)) != ID)
852   {
853    __pv_ferr(922, "`undef required text macro identifier missing - %s read",
854     prt2_vtok(ttyp));
855    has_err = TRUE;
856   }
857  /* need to use get token that does not know about line breaks */
858  if (__lin_cnt != savlin_cnt)
859   {
860    __pv_ferr(929, "`undef text macro identifier name must be on same line");
861    unget2_vtok(ttyp);
862    return;
863   }
864  if (!has_err && __token[0] == '`')
865   {
866    __pv_ferr(1291,
867     "`undef text macro identifier name %s cannot begin with `", __token);
868    has_err = TRUE;
869   }
870  if (!has_err) { strcpy(dnam, "`"); strcat(dnam, __token); }
871  __skipover_line();
872  if (has_err) return;
873 
874  if (get_vkeywrd(dnam) != ID)
875   {
876    __pv_ferr(1293,
877     "`undef of macro name %s illegal - cannot `undef predefined directive",
878     dnam);
879    return;
880   }
881 
882  if ((syp = __get_sym(dnam, __pv_defsyms)) == NULL || !syp->sydecl)
883   {
884    __pv_fwarn(655, "`undef of %s does nothing - macro not defined", dnam);
885    return;
886   }
887  if (syp->sy_argsmac)
888   {
889    free_macexplst(syp->el.eamacp->amxp);
890    __my_free((char *) syp->el.eamacp, sizeof(struct amac_t));
891    syp->sy_argsmac = FALSE;
892   }
893  else __my_free(syp->el.edfchp, strlen(syp->el.edfchp) + 1);
894  syp->el.edfchp = __pv_stralloc("");
895  syp->sydecl = FALSE;
896 }
897 
898 /*
899  * return F and emit error if not at beginning of line
900  * tricky case if first token file_just_op - this is really first token
901  * in line but flag will be off - check for case and if found must turn
902  * off file just open - if this check not called will get turned off
903  * normally.
904  *
905  * problem here is caused by Verilog semantics that treat compiler directives
906  * as having \n as token but in normal code not a token
907  */
__chk_beg_line(int32 cdtyp)908 extern int32 __chk_beg_line(int32 cdtyp)
909 {
910  /* ---
911  if (__iact_state)
912   {
913    __ia_err(1401,
914     "compiler directives illegal in interactive commands - %s read",
915     __get_vkeynam(__xs, cdtyp));
916    return(FALSE);
917   }
918  --- */
919  if (!__first_linetok)
920   {
921    if (__file_just_op) { __file_just_op = FALSE; return(TRUE); }
922    else __pv_ferr(928, "compiler directive %s must be first token on line",
923     __get_vkeynam(__xs, cdtyp));
924    return(FALSE);
925   }
926  return(TRUE);
927 }
928 
929 /*
930  * collect a line into mac wrk str first skip over all leading white space
931  * notice white space inside line kept and line can be arbitrarily long
932  * with possible escaped new lines
933  *
934  * this sets length of used part of macro line
935  * this can be arbitrarily long for mulitple line macros
936  */
__collect_line(void)937 extern void __collect_line(void)
938 {
939  register int32 c;
940  register char *chp;
941  int32 len;
942 
943  for (;;) { c = my_getc(__in_s); if (!vis_nonnl_white_(c)) break; }
944  if (c == '\n' || c == EOF)
945   {
946    *__macwrkstr = '\0';
947    my_ungetc_(c, __in_s);
948    return;
949   }
950  for (chp = __macwrkstr, len = 0;;)
951   {
952    /* \\n is line continuation and must become ' ' in macro string line */
953    /* anything else added is part of escaped id */
954    if (c == '\\')
955     {
956      if ((c = my_getc(__in_s)) == '\n') { c = ' '; __lin_cnt++; }
957      else { my_ungetc_(c, __in_s); c = '\\'; }
958     }
959    addto_macwrkstr_(c);
960    c = my_getc(__in_s);
961    if (c == '\n' || c == EOF) { my_ungetc_(c, __in_s); break; }
962   }
963  /* notice trailing new line or eof removed */
964  *chp = '\0';
965  __mac_line_len = len;
966 }
967 
968 /*
969  * skip over characters to a new line (skip ending or error stuff)
970  * know current char never new line
971  * this also skips over \\[newline]
972  *
973  * not counted as part of total source lines since skipped from ` conds
974  */
__skipover_line(void)975 extern void __skipover_line(void)
976 {
977  register int32 c;
978 
979  for (;;)
980   {
981    if ((c = my_getc(__in_s)) == '\n' || c == EOF) break;
982    if (c == '\\')
983     {
984      /* \\n is just white space not end of line but \\EOF is still eof */
985      if ((c = my_getc(__in_s)) == EOF) break;
986      /* not counting continuation lines in total */
987      if (c == '\n') __lin_cnt++;
988     }
989   }
990  if (c != EOF) { my_ungetc_(c, __in_s); };
991 }
992 
993 /*
994  * read a line into passed string
995  */
__my_getlin(register char * lp)996 extern int32 __my_getlin(register char *lp)
997 {
998  register int32 c, len;
999 
1000  for (len = 0;;)
1001   {
1002    c = my_getc(__in_s);
1003    if (++len >= IDLEN)
1004     {
1005      __pv_ferr(2889, "`language section line too long (%d) - truncated",
1006       IDLEN - 1);
1007     }
1008    else *lp++ = c;
1009    if (c == '\n' || c == EOF) break;
1010   }
1011  *lp = '\0';
1012  return(c);
1013 }
1014 
1015 /*
1016  * build the formal arg list and skip over
1017  * passed with mac wrk str pointing to leading (
1018  * returns ptr to one after ending ) or nil if error
1019  *
1020  * FIXME make table larger so can be 8 bit clean
1021  */
bld_macdef_arglist(int32 * nargs)1022 static char *bld_macdef_arglist(int32 *nargs)
1023 {
1024  register char *chp;
1025  char *chp2, *chp3;
1026  int32 argno, arglen, toolong;
1027  struct macarg_t *marp, *macarg_end;
1028  char argnam[IDLEN];
1029 
1030  *nargs = 0;
1031  chp = &(__macwrkstr[1]);
1032  __macarg_hdr = NULL;
1033  macarg_end = NULL;
1034  for (argno = 1;; argno++)
1035   {
1036    toolong = FALSE;
1037    /* skip white space before arg */
1038    while (vis_nonnl_white_(*chp)) chp++;
1039    /* format argument can start with _ but not ` or $ */
1040    /* digit can be in id but not start it */
1041    if (__pv_ctab[(*chp & 0x7f)] != 0 || isdigit(*chp) || *chp == '$')
1042     {
1043      __pv_ferr(1292,
1044       "text macro formal argument %d identifier expected - %c read - if non argument macro, add ' ' before (",
1045       argno, *chp);
1046      /* on error just do not define macro */
1047      return(NULL);
1048     }
1049    arglen = 1;
1050    chp2 = chp++;
1051    chp3 = NULL;
1052    /* collect the chars in the formal name */
1053    while(__pv_ctab[(*chp & 0x7f)] == 0)
1054     {
1055      if (++arglen >= IDLEN - 1)
1056       {
1057        if (!toolong)
1058         {
1059          __pv_ferr(944,
1060           "text macro formal argument has too many characters (%d)",
1061           IDLEN - 1);
1062          toolong = TRUE;
1063          /* end is 1 past end where \0 will go */
1064          chp3 = chp;
1065         }
1066       }
1067      chp++;
1068     }
1069    if (chp3 == NULL) chp3 = chp;
1070    strncpy(argnam, chp2, chp3 - chp2);
1071    argnam[chp3 - chp2] = '\0';
1072    marp = (struct macarg_t *) __my_malloc(sizeof(struct macarg_t));
1073    marp->macargnam = __pv_stralloc(argnam);
1074    marp->macargnxt = NULL;
1075    if (macarg_end == NULL) __macarg_hdr = macarg_end = marp;
1076    else macarg_end->macargnxt = marp;
1077    macarg_end = marp;
1078    /* maybe skip white space */
1079    while (vis_nonnl_white_(*chp)) chp++;
1080    if (*chp == ')') break;
1081    if (*chp == ',') { chp++; continue; }
1082    /* wrong separator */
1083    __pv_ferr(1294,
1084     "text macro formal argument %d not followed by , or ) - char %c read",
1085     argno, *chp);
1086    return(NULL);
1087   }
1088  chp++;
1089  /* notice something like "`define aa(a,b) )()(" is legal, err later */
1090  *nargs = argno;
1091  return(chp);
1092 }
1093 
1094 /*
1095  * remove any comments from macro body copy then build macwrkstr
1096  * error and return F if / * comment or string not completed
1097  *
1098  * only here for macro def. bodies, // \[escaped nl] is removed comment
1099  * / * can span escaped new lines - and always left as escaped in output
1100  * mchp must always point into mac wrk str
1101  *
1102  * this copies into temp and then puts back in macro string
1103  */
remchk_macdef_coms(char * mchp)1104 static char *remchk_macdef_coms(char *mchp)
1105 {
1106  register char *chp, *nchp;
1107  int32 llen, first_time;
1108  char *newwrkstr, *start_mchp;
1109 
1110  /* macro text starts with non white */
1111  while(vis_nonnl_white_(*mchp)) mchp++;
1112  start_mchp = mchp;
1113 
1114  /* region to allocate does not include possible args */
1115  llen = __mac_line_len - (mchp - __macwrkstr);
1116  /* will never be wider but may be same length */
1117  newwrkstr = __my_malloc(llen + 1);
1118 
1119  for (first_time = TRUE, chp = mchp, nchp = newwrkstr; *chp != '\0';)
1120   {
1121    /* replace string of white space with one space */
1122    if (vis_nonnl_white_(*chp))
1123     {
1124      if (!first_time) *nchp++ = ' ';
1125      chp++;
1126      while(vis_nonnl_white_(*chp)) chp++;
1127     }
1128    first_time = FALSE;
1129 
1130    switch (*chp) {
1131     case '/':
1132      /* handle comments - no quoted strings in comments */
1133      chp++;
1134      /* remove // comment - can go to end of area (real nl or esc. nl) */
1135      if (*chp == '/')
1136       {
1137        chp++;
1138        while (*chp != '\0')
1139         {
1140          /* both of these better be removed by collect line */
1141          if (*chp == '\n' || *chp == EOF) __misc_terr(__FILE__, __LINE__);
1142          chp++;
1143         }
1144        /* now skipped to end of // comment */
1145        *nchp = '\0';
1146        goto at_end;
1147       }
1148      /* remove / * comment - error if hit end of string */
1149      if (*chp == '*')
1150       {
1151        chp++;
1152        while (*chp != '*')
1153         {
1154          if (*chp == '\n' || *chp == EOF) __misc_terr(__FILE__, __LINE__);
1155          if (*chp == '\0')
1156           {
1157            __pv_ferr(930,
1158             "*/ in `define macro line without initial /* comment start");
1159            __my_free(newwrkstr, llen + 1);
1160            return(NULL);
1161           }
1162          if (*chp == '/' && chp[1] == '*')
1163           {
1164            __pv_fwarn(622, "nested /* in macro body /* style comment");
1165           }
1166          /* skip any escaped chars - can not end comment */
1167          if (*chp == '\\') { chp++; chp++; }
1168          chp++;
1169         }
1170        chp++;
1171        if (*chp == '/') { *nchp++ = ' '; chp++; continue; }
1172        break;
1173       }
1174      /* simple / so must keep in line */
1175      *nchp++ = '/';
1176      break;
1177     /* must copy any non white space escape and char */
1178     case '\\':
1179      /* escaped nl becomes space */
1180      if (chp[1] == '\n') { chp++; chp++; *nchp++ = ' '; break; }
1181      *nchp++ = *chp++;
1182      if (*chp == '\0')
1183       {
1184        __pv_ferr(931,
1185         "`define macro line ends with \\ - following escaped char required");
1186        return(NULL);
1187       }
1188      /* must copy any escaped char as is - cannot have any meaning */
1189      *nchp++ = *chp++;
1190      break;
1191     case '\0': goto at_end;
1192     case '"':
1193      *nchp++ = *chp++;
1194      while (*chp != '"')
1195       {
1196        if (*chp == '\\') *nchp++ = *chp++;
1197        if (*chp == '\0')
1198         {
1199          __pv_ferr(932,
1200           "`define macro contains unterminated string - not defined");
1201          return(NULL);
1202         }
1203        *nchp++ = *chp++;
1204       }
1205      /* exit and copy " */
1206    }
1207    *nchp++ = *chp++;
1208   }
1209 at_end:
1210  /* remove trailing white space */
1211  for (;;)
1212   {
1213    if (nchp == newwrkstr) break;
1214    nchp--;
1215    if (!vis_white_(*nchp)) { nchp++; break; }
1216   }
1217  *nchp = '\0';
1218 
1219  /* DBG remove --- */
1220  if (nchp - newwrkstr > llen) __misc_terr(__FILE__, __LINE__);
1221  /* --- */
1222  strcpy(mchp, newwrkstr);
1223  __mac_line_len = (mchp - __macwrkstr) + (nchp - newwrkstr);
1224  __my_free(newwrkstr, llen + 1);
1225  return(start_mchp);
1226 }
1227 
1228 /*
1229  * process an argument macro definition
1230  * know mac arg hdr global point to formal argument list
1231  *
1232  * know working out of collected line so new line impossible
1233  * expand arguments anywhere but within strings
1234  * know all comments changed to 1 space and multiple white space to 1 space
1235  * also know all quoted strings completed
1236  * LOOKATME - is it true this cannot fail
1237  */
bld_mac_expandtab(char * dnam,char * dval,int32 nargs)1238 static struct macexp_t *bld_mac_expandtab(char *dnam, char *dval, int32 nargs)
1239 {
1240  register char *chp;
1241  register int32 andx;
1242  register struct macarg_t *marp;
1243  byte *argutab;
1244  struct macexp_t *mxp, *mxp_hdr, *mxp_end;
1245  char *startchp, *startid, idnam[IDLEN];
1246 
1247  argutab = (byte *) __my_malloc(nargs);
1248  memset(argutab, 0, nargs);
1249  mxp_hdr = mxp_end = NULL;
1250  startchp = dval;
1251  for (chp = dval; *chp != '\0';)
1252   {
1253    /* skip leading white space */
1254    while (vis_nonnl_white_(*chp)) chp++;
1255 
1256    /* always skip quoted strings */
1257    if (*chp == '"')
1258     {
1259      chp++;
1260      /* must not match escaped quote */
1261      while (*chp != '"')
1262       {
1263        if (*chp == '\0')
1264         {
1265          __pv_ferr(932,
1266           "macro %s value contains unterminated string - macro undefined",
1267           dnam);
1268          return(NULL);
1269         }
1270        if (*chp == '\\') chp++;
1271        chp++;
1272       }
1273      chp++;
1274      continue;
1275     }
1276    /* if identifier or keyword remove and build record, else just skip */
1277    if (__pv_ctab[(*chp & 0x7f)] == 0 && (!isdigit(*chp) || *chp == '`'))
1278     {
1279      startid = chp;
1280      chp++;
1281      while(__pv_ctab[(*chp & 0x7f)] == 0) chp++;
1282      /* see if this is formal argument */
1283      strncpy(idnam, startid, chp - startid);
1284      idnam[chp - startid] = '\0';
1285      /* if does not match left in literal copy part and at next char */
1286      if ((andx = find_mac_formal_arg(idnam)) == -1) continue;
1287      argutab[andx] = 1;
1288      /* this is formal */
1289      mxp = (struct macexp_t *) __my_malloc(sizeof(struct macexp_t));
1290      mxp->leading_str = __my_malloc(startid - startchp + 1);
1291      strncpy(mxp->leading_str, startchp, startid - startchp);
1292      mxp->leading_str[startid - startchp] = '\0';
1293      mxp->leadlen = startid - startchp;
1294      mxp->ins_argno = andx;
1295      mxp->macexpnxt = NULL;
1296      if (mxp_end == NULL) mxp_hdr = mxp_end = mxp;
1297      else mxp_end->macexpnxt = mxp;
1298      mxp_end = mxp;
1299      /* reset fill to one after ID */
1300      startchp = chp;
1301      continue;
1302     }
1303    chp++;
1304   }
1305  for (andx = 0, marp = __macarg_hdr; andx < nargs; andx++,
1306   marp = marp->macargnxt)
1307   {
1308    if (argutab[andx] == 0)
1309     {
1310      __pv_fwarn(640,
1311       "%s macro definition formal argument %s (no. %d) not used in macro body",
1312       dnam, marp->macargnam, andx);
1313     }
1314   }
1315  __my_free((char *) argutab, nargs);
1316  argutab = NULL;
1317 
1318  /* unless value is empty include trailing chars */
1319  /* if totally empty value, make it one space */
1320  if (chp == startchp && mxp_end == NULL)
1321   {
1322    __pv_fwarn(638, "argument macro %s expands to nothing - use `undef", dnam);
1323    return(NULL);
1324   }
1325  if (chp == startchp) return(mxp_hdr);
1326 
1327  /* add the ending prefix with no argument to expand in */
1328  mxp = (struct macexp_t *) __my_malloc(sizeof(struct macexp_t));
1329  mxp->leading_str = __my_malloc(chp - startchp + 1);
1330  strncpy(mxp->leading_str, startchp, chp - startchp);
1331  mxp->leading_str[chp - startchp] = '\0';
1332  mxp->ins_argno = -1;
1333  mxp->macexpnxt = NULL;
1334  if (mxp_end == NULL) mxp_hdr = mxp_end = mxp;
1335  else mxp_end->macexpnxt = mxp;
1336  return(mxp_hdr);
1337 }
1338 
1339 /*
1340  * search an formal argument list to match a legal ID name
1341  * returns nil if not found
1342  */
find_mac_formal_arg(char * argnam)1343 static int32 find_mac_formal_arg(char *argnam)
1344 {
1345  register int32 anum;
1346  register struct macarg_t *marp;
1347 
1348  anum = 0;
1349  for (marp = __macarg_hdr; marp != NULL; marp = marp->macargnxt, anum++)
1350   { if (strcmp(marp->macargnam, argnam) == 0) return(anum); }
1351  return(-1);
1352 }
1353 
1354 /*
1355  * define a text macro named dnam with value dval
1356  * this looks up in symbol table and stores "" ok and used for `ifdef
1357  * dval here is really rest of line that may be ""
1358  */
__do_macdefine(char * dnam,char * dval)1359 extern void __do_macdefine(char *dnam, char *dval)
1360 {
1361  struct tnode_t *tnp;
1362  struct sy_t *syp;
1363 
1364  tnp = __vtfind(dnam, __pv_defsyms);
1365  /* now add the symbol */
1366  if (__sym_is_new)
1367   {
1368    /* allocate symbol and fill symbol */
1369    __add_sym(dnam, tnp);
1370    __pv_defsyms->numsyms++;
1371    syp = tnp->ndp;
1372    syp->sytyp = SYM_DEF;
1373    syp->sydecl = TRUE;
1374   }
1375  else
1376   {
1377    syp = tnp->ndp;
1378    /* if `define follows undef just define - no message */
1379    if (syp->sydecl)
1380     {
1381      if (syp->sy_argsmac)
1382       {
1383        __finform(415,
1384         "textmacro name %s redefined - previous but not new had args", dnam);
1385         free_macexplst(syp->el.eamacp->amxp);
1386        __my_free((char *) syp->el.eamacp, sizeof(struct amac_t));
1387        syp->sy_argsmac = FALSE;
1388       }
1389      else
1390       {
1391        __finform(415,
1392         "textmacro name %s redefined - neither has arguments", dnam);
1393        __my_free(syp->el.edfchp, strlen(syp->el.edfchp) + 1);
1394       }
1395     }
1396    /* if was undefined now defined */
1397    syp->sydecl = TRUE;
1398   }
1399  syp->el.edfchp = __pv_stralloc(dval);
1400 }
1401 
1402 /*
1403  * free an args macro expand list
1404  */
free_macexplst(register struct macexp_t * mxp)1405 static void free_macexplst(register struct macexp_t *mxp)
1406 {
1407  register struct macexp_t *mxp2;
1408 
1409  for (; mxp != NULL;)
1410   {
1411    mxp2 = mxp->macexpnxt;
1412    __my_free(mxp->leading_str, mxp->leadlen + 1);
1413    __my_free((char *) mxp, sizeof(struct macexp_t));
1414    mxp = mxp2;
1415   }
1416 }
1417 
1418 /*
1419  * define a text macro with arguments named dnam with value dval
1420  * and macro subsitution list macp
1421  *
1422  * this looks up in symbol table and stores "" ok and used for `ifdef
1423  * dval here is really rest of line that may be ""
1424  * illegal conflicts with predefined compiler directives caught before here
1425  */
do_argmacdefine(char * dnam,struct macexp_t * mxp,int32 nformal_args)1426 static void do_argmacdefine(char *dnam, struct macexp_t *mxp, int32 nformal_args)
1427 {
1428  struct tnode_t *tnp;
1429  struct sy_t *syp;
1430 
1431  tnp = __vtfind(dnam, __pv_defsyms);
1432  /* now add the symbol */
1433  if (__sym_is_new)
1434   {
1435    /* allocate symbol and fill symbol */
1436    __add_sym(dnam, tnp);
1437    __pv_defsyms->numsyms++;
1438    syp = tnp->ndp;
1439    syp->sytyp = SYM_DEF;
1440    syp->sy_argsmac = TRUE;
1441    syp->sydecl = TRUE;
1442    syp->el.eamacp = (struct amac_t *) __my_malloc(sizeof(struct amac_t));
1443   }
1444  else
1445   {
1446    syp = tnp->ndp;
1447    if (syp->sydecl)
1448     {
1449      if (syp->sy_argsmac)
1450       {
1451        __finform(415,
1452         "textmacro name %s redefined - previous and new have args",
1453         dnam);
1454        free_macexplst(syp->el.eamacp->amxp);
1455       }
1456      else
1457       {
1458        __finform(415,
1459         "textmacro name %s redefined - only new has args", dnam);
1460        __my_free(syp->el.edfchp, strlen(syp->el.edfchp) + 1);
1461        syp->el.eamacp = (struct amac_t *) __my_malloc(sizeof(struct amac_t));
1462       }
1463     }
1464    syp->sydecl = TRUE;
1465   }
1466  syp->el.eamacp->amxp = mxp;
1467  syp->el.eamacp->num_formal_args = nformal_args;
1468  syp->sy_argsmac = TRUE;
1469 }
1470 
1471 /*
1472  * return F if remainder of line contains anything but comment
1473  * know all white space has been removed before call
1474  * if / * comment but be completed on line
1475  * return T if good
1476  */
__bqline_emptytail(register char * cp)1477 extern int32 __bqline_emptytail(register char *cp)
1478 {
1479  for (; *cp != '\0'; cp++)
1480   {
1481    switch (*cp) {
1482     case '/':
1483      cp++;
1484      if (*cp == '/') return(TRUE);
1485      if (*cp == '*')
1486       {
1487        /* in / *  comment */
1488        for (cp++;; cp++)
1489         {
1490          if (*cp == '\0') return(FALSE);
1491          if (*cp == '*')
1492           {
1493            cp++;
1494            if (*cp == '/') goto nxt_white;
1495            cp--;
1496            continue;
1497           }
1498         }
1499       }
1500      continue;
1501     case '\\': cp++; continue;
1502     default: return(FALSE);
1503    }
1504 nxt_white:;
1505   }
1506  return(TRUE);
1507 }
1508 
1509 /*
1510  * do the new `include directive - entire line consumed
1511  * must be called with file name (starting ") in token
1512  */
__do_include(void)1513 extern void __do_include(void)
1514 {
1515  register int32 idi;
1516  register char *cp;
1517  int32 inflen, plen, space;
1518  FILE *f;
1519  struct incloc_t *ilp;
1520  char *chp, incfnam[RECLEN], incpth[RECLEN];
1521  struct sy_t *syp;
1522 
1523  cp = __macwrkstr;
1524  /* AIV 06/27/05 -  handle the special `include `FILE case */
1525  if (*cp == '`')
1526   {
1527    /* strip the white space at the end of the line */
1528    plen = strlen(cp) - 1;
1529    space = FALSE;
1530    for (idi = plen; idi >= 0; idi--)
1531     {
1532      if (cp[idi] == ' ')
1533       {
1534        space = TRUE;
1535        cp[idi] = '\0';
1536       }
1537      else if (space) break;
1538     }
1539     /* find `define variable to ge the file name */
1540    if ((syp = __get_sym(cp, __pv_defsyms)) == NULL || !syp->sydecl)
1541     {
1542      __pv_fwarn(937,
1543       "`include name - text macro %s undefined or possibly compiler directive for other tool - ignored", cp);
1544      return;
1545     }
1546   /* set the file name pointer */
1547   cp = syp->el.edfchp;
1548  }
1549  chp = cp;
1550  if (*chp != '"')
1551   {
1552 bad_fnam:
1553    __pv_ferr(937,
1554     "`include name not surrounded by double quotation marks");
1555    return;
1556   }
1557  /* fill token to ending " - white space in file names ok */
1558  for (chp++;; chp++)
1559   {
1560    if (*chp == '\0') goto bad_fnam;
1561    if (*chp == '"') break;
1562   }
1563  /* replace ending quotes with \0 */
1564  *chp = '\0';
1565  /* cp now points file name skipping the first char (") */
1566  /* know not longer than 1024 because that is Verilog line length */
1567  strcpy(incfnam, &(cp[1]));
1568 
1569  if ((f = __tilde_fopen(incfnam, "r")) == NULL)
1570   {
1571    /* if file absolute, do not search incdir list */
1572    /* AIV 09/15/04 - ./[name] form is relative not absolute */
1573    if (incfnam[0] == '/' || incfnam[0] == '~') goto nonrel_notfnd;
1574 
1575    if (__last_incdir >= 0)
1576     {
1577      inflen = strlen(incfnam);
1578      for (idi = 0; idi <= __last_incdir; idi++)
1579       {
1580        plen = strlen(__incdirs[idi]) + inflen + 1;
1581        if (plen >= RECLEN)
1582         {
1583          chp = __my_malloc(plen);
1584          strcpy(chp, __incdirs[idi]);
1585          strcat(chp, incfnam);
1586          __pv_fwarn(571,
1587           "`include file +incdir+ path name %s too long (%d) - ignored", chp,
1588            RECLEN);
1589          __my_free(chp, plen);
1590          continue;
1591         }
1592        strcpy(incpth, __incdirs[idi]);
1593        strcat(incpth, incfnam);
1594        /* DBG remove --
1595        __cv_msg("*** attempting to open include path %s\n", chp);
1596        --- */
1597        if ((f = __tilde_fopen(incpth, "r")) != NULL)
1598         { strcpy(incfnam, incpth); goto found_path; }
1599       }
1600      __pv_ferr(933,
1601       "unable to open `include file %s - not found in any +incdir+", incfnam);
1602      return;
1603     }
1604 nonrel_notfnd:
1605    __pv_ferr(933, "unable to open `include file %s", incfnam);
1606    return;
1607   }
1608 
1609 found_path:
1610  /* add include file to file list for error messages */
1611  /* __last_inf still used to find last non lib. input file */
1612  /* this dies if >64k */
1613  /* idea here is that initial build entire list of input then library files */
1614  /* while process arguments - when reading includes put on end of file list */
1615  /* so that contents can be read by debugger */
1616  if (++__last_lbf >= __siz_in_fils) __grow_infils(__last_lbf);
1617  __in_fils[__last_lbf] = __pv_stralloc(incfnam);
1618 
1619  /* have good include file, add to include location list */
1620  ilp = (struct incloc_t *) __my_malloc(sizeof(struct incloc_t));
1621  /* link on end */
1622  if (__inclst_hdr == NULL) __inclst_hdr = __inclst_end = ilp;
1623  else __inclst_end->inclocnxt = ilp;
1624  ilp->inc_fnind = __last_lbf;
1625  ilp->incfrom_fnind = __cur_fnam_ind;
1626  ilp->incfrom_lcnt = __lin_cnt;
1627  ilp->inclocnxt = NULL;
1628 
1629  /* save current __lin_cnt before pushing */
1630  if (__visp->vi_s != NULL) __visp->vilin_cnt = __lin_cnt;
1631  /* push new file on tos */
1632  __push_vinfil();
1633  /* notice push sets __visp */
1634  __visp->vifnam_ind = __last_lbf;
1635  __visp->vi_s = __in_s = f;
1636  __cur_fnam = __in_fils[__visp->vifnam_ind];
1637  __cur_fnam_ind = __visp->vifnam_ind;
1638  __lin_cnt = 1;
1639  if (__lib_verbose || __verbose)
1640   {
1641    if (__doing_langdir)
1642     {
1643      __cv_msg("  Reading `included `language non Verilog file \"%s\"\n",
1644       __cur_fnam);
1645     }
1646    else __cv_msg("  Compiling `included source file \"%s\"\n", __cur_fnam);
1647   }
1648  __file_just_op = TRUE;
1649 }
1650 
1651 /*
1652  * skip to matching level else for `ifdef that is F
1653  * this reads ending `endif or `else and it line
1654  * returns -1 on not found error
1655  *
1656  * fortuntately never need to back up
1657  * this has a bug that needs to be documented - in sections that are
1658  * skipped only looks for match level `else or `endif - once starts skipping
1659  * a down level `ifdef does not catch extra `else's
1660  * notice this routines only uses local variables
1661  *
1662  * FIXME - looks like if `end never found in infinite loop?
1663  */
cskip_ifdef_section(FILE * f,int32 begtok)1664 static int32 cskip_ifdef_section(FILE *f, int32 begtok)
1665 {
1666  int32 level, ttyp2, sav_lin_cnt;
1667  int32 savfnam_ind;
1668 
1669  /* ifdef must be on line by itself - anything treated as comment */
1670  __skipover_line();
1671  /* save the line count */
1672  savfnam_ind = __cur_fnam_ind;
1673  sav_lin_cnt = __lin_cnt;
1674  /* SJM 12/04/00 - need flag when skipping for ifdef section to */
1675  /* not emit rd num warnings since parameter substitution not right */
1676  __ifdef_skipping = TRUE;
1677  /* know reading stars after directive line */
1678  for (level = 0;;)
1679   {
1680    switch ((byte) (ttyp2 = __get1_vtok(f))) {
1681     case TEOF:
1682      /* if finished include or macro expansion just continue reading tokens */
1683      if (__pop_vifstk()) continue;
1684 
1685      /* next try to replace just finished 0th element with new input file */
1686      /* notice these can cross file boundaries - real eof is all files */
1687      /* exhausted */
1688      if (__cur_infi < __last_inf)
1689       {
1690        __cur_infi++;
1691        if (__open_sfil()) continue;
1692       }
1693      /* for interactive can never get here since checking line begin fails */
1694      /* notice control here always ends with fata error */
1695      if (begtok == CDIR_IFDEF || begtok == CDIR_IFNDEF)
1696       {
1697        __pv_terr(313,
1698         "`ifdef/`ifndef line %s - no matching `else or `endif before **EOF**",
1699         __bld_lineloc(__xs, (word32) savfnam_ind, sav_lin_cnt));
1700       }
1701      else
1702       {
1703        __pv_terr(313, "`else line %s - no matching `endif before **EOF**",
1704         __bld_lineloc(__xs, (word32) savfnam_ind, sav_lin_cnt));
1705       }
1706      continue;
1707     case CDIR_IFDEF: case CDIR_IFNDEF:
1708      /* notice will not see if not 1st token of line */
1709      if (__chk_beg_line(ttyp2)) level++;
1710      __skipover_line();
1711      continue;
1712     case CDIR_ENDIF:
1713      if (!__chk_beg_line(CDIR_ENDIF)) break;
1714      __skipover_line();
1715      /* SJM 12/04/00 - when done skipping now need to turn off flag */
1716      /* flag needed because macros now alloed for number width */
1717      if (level == 0)
1718       { __ifdef_skipping = FALSE; return(CDIR_ENDIF); }
1719      level--;
1720      continue;
1721     case CDIR_ELSE:
1722      if (!__chk_beg_line(CDIR_ELSE)) break;
1723      __skipover_line();
1724      if (level == 0)
1725       {
1726        if (begtok == CDIR_ELSE)
1727         {
1728          __pv_ferr(1011,
1729           "`else line %s - followed by same nesting level `else",
1730           __bld_lineloc(__xs, (word32) savfnam_ind, sav_lin_cnt));
1731          /* keep looking for `endif */
1732          continue;
1733         }
1734        __ifdef_skipping = FALSE;
1735        return(CDIR_ELSE);
1736       }
1737      continue;
1738     case CDIR_LANG:
1739      /* here because can not tokenize included foreign language */
1740      savfnam_ind = __cur_fnam_ind;
1741      sav_lin_cnt = __lin_cnt;
1742      if (__notokenize_skiplines("`endlanguage") == TEOF)
1743       {
1744        __pv_terr(328,
1745         "skipped `language at %s in `ifdef/`ifndef no matching `endlanguage before **EOF**",
1746        __bld_lineloc(__xs, (word32) savfnam_ind, sav_lin_cnt));
1747       }
1748      break;
1749     case CDIR_TIMESCALE:
1750      /* SJM 12/02/99 - these require special scanning so can't just skip */
1751      /* must read line and ignore it - know always first on line */
1752      __skipover_line();
1753      continue;
1754    }
1755   }
1756  /*UNREACHABLE*/
1757  __ifdef_skipping = FALSE;
1758  return(-1);
1759 }
1760 
1761 /*
1762  * INTERACTIVE ENVIRONMENT GET TOKEN ROUTINES
1763  */
1764 
1765 /*
1766  * read an interactive line - must handle \[new line] escapes which
1767  * are left in and treated as white space
1768  *
1769  * __iahwrkline grows but must start out at least IDLEN + 1 characters lone
1770  * this returns TEOF on at eof and nothing in line (or error?)
1771  * return TOK_NONE on good
1772  *
1773  * caller must handle key file and parsing tokenization of read line
1774  * (command) and any adding to history list
1775  * ending new line is removed
1776  */
__rd_ialine(void)1777 extern int32 __rd_ialine(void)
1778 {
1779  int32 len, totlen, osize, intr_num;
1780  char *chp;
1781  FILE *f;
1782 
1783 rd_again:
1784  __iahwrkline[0] = '\0';
1785  if (__cmd_s != NULL) { f = __cmd_s; __lin_cnt++; } else f = stdin;
1786  if (feof(f)) return(TEOF);
1787 
1788  for (totlen = 0;;)
1789   {
1790    /* will not return NULL if any chars read */
1791    chp = &(__iahwrkline[totlen]);
1792    /* when iact debugger run from pipe, under FlexLM may be interrupted */
1793    /* and need to restart */
1794    intr_num = 0;
1795 again2:
1796    clearerr(f);
1797    if (fgets(chp, IDLEN + 1, f) == NULL)
1798     {
1799      if (++intr_num >= 512)
1800       {
1801        __ia_err(1450,
1802         "interactive input call interrupted %d consecutive times - assuming EOF",
1803         intr_num);
1804        break;
1805       }
1806      if (!feof(f) && errno == EINTR) goto again2;
1807      if (feof(f) && errno == EINTR)
1808       {
1809        __ia_warn(1603,
1810         "interactive input call interrupted (but EOF also seen?) - trying again");
1811        goto again2;
1812       }
1813      if (ferror(f))
1814       {
1815        __ia_err(1460,
1816         "interactive input call failed because: [%s] - assuming EOF",
1817         strerror(errno));
1818       }
1819      break;
1820     }
1821    if (__pending_enter_iact && __iact_reason == IAER_CTRLC)
1822     {
1823      __pending_enter_iact = FALSE;
1824      __iact_reason = IAER_UNKN;
1825 
1826      if (__cmd_s == NULL) goto rd_again;
1827      /* ^c (interrupt signal) during $input interrupts and closes file */
1828      __ia_err(1457,
1829       "interactive $input file processing terminated by interrupt (^c)");
1830      totlen = 0;
1831      __iahwrkline[0] = '\0';
1832      return(TEOF);
1833     }
1834 
1835    len = strlen(chp);
1836    if (len >= IDLEN)
1837     {
1838      __ia_err(1402, "interactive line too long (%d) - truncated", IDLEN - 1);
1839      chp[IDLEN - 1] = '\0';
1840      break;
1841     }
1842    totlen += len;
1843    /* know last char. always new line for fgets  - see if escaped */
1844    if (chp[len - 2] != '\\') break;
1845    /* if escaped keep reading but first see if need to grow work line */
1846    if (totlen >= __iahwrklen - IDLEN - 4)
1847     {
1848      osize = __iahwrklen;
1849      __iahwrklen += IDLEN + 4;
1850      __iahwrkline = __my_realloc(__iahwrkline, osize, __iahwrklen);
1851     }
1852    /* if (f != NULL) __lin_cnt++; */
1853   }
1854  if (totlen == 0) return(TEOF);
1855  /* FIXME - lot file output only ?? */
1856  if (__echo_iactcmds_tolog && __log_s != NULL)
1857   __my_fprintf(__log_s, "%s", __iahwrkline);
1858 
1859  /* final step change final unescaped new line to blank */
1860  /* if not blank error such as omitted ; previous token not seen */
1861  __iahwrkline[totlen - 1] = ' ';
1862  return(TOK_NONE);
1863 }
1864 
1865 /*
1866  * ACTUAL TOKENIZATION CODE
1867  */
1868 
1869 /*
1870  * ascii character table for processing end of ID tokens
1871  * 0: continue - legal ID char (letter, digit, _, $)
1872  * 1: end and don't back up (white space)
1873  * 2: end and back up (operators plus special back quote)
1874  * 3: inc lin_cnt and end - only new line
1875  * 4: illegal ID char
1876  *
1877  * notice special handling of . - if 1st char after comma or white space,
1878  * then dot part of .[name](port) for else . legal in ID, but can not
1879  * be 1st char of id
1880  * 0x24 is $ and 0x5f is _ both are legal starting and in IDs (value 0)
1881  */
1882 char __pv_ctab[128] = {
1883  4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 3, 4, 1, 1, 4, 4, /* ^i,\n,\f,\r */
1884  4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
1885  /* need to handle " */
1886  1, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* sp,!,%,#,(,),*,',+,-,.,/ */
1887  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, /* digits, :,;,<,=,>,? */
1888  2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @, cap letters */
1889  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, /* letters `,[,\\,],^, */
1890  2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* `, letters */
1891  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2  /* letters, {, |, },~,EOF */
1892 };
1893 
1894 /*
1895  * get a Verilog token
1896  * (modified from yylex in "The Unix Programming Environment" p. 337)
1897  */
__get1_vtok(FILE * f)1898 extern int32 __get1_vtok(FILE *f)
1899 {
1900  register int32 c, ctval;
1901  register char *cp;
1902  int32 c1, len, toolong;
1903  int32 t1typ;
1904 
1905 again:
1906  /* not first line token since always push back new line except number */
1907  /* ending line required scan to make sure not ' */
1908  if (__first_num_eol) { __first_linetok = TRUE; __first_num_eol = FALSE; }
1909  else __first_linetok = FALSE;
1910 
1911 again3:
1912  do { ctval = __pv_ctab[(c = my_getc(f)) & 0x7f]; } while (ctval == 1);
1913  if (c == '\n')
1914   {
1915 again2:
1916    __lin_cnt++;
1917    __total_rd_lines++;
1918    do { ctval = __pv_ctab[(c = my_getc(f)) & 0x7f]; } while (ctval == 1);
1919    if (c == '\n') goto again2;
1920    __first_linetok = TRUE;
1921   }
1922  switch (c) {
1923   case ';': return(SEMI);
1924   case ',': return(COMMA);
1925   case ':': return(COLON);
1926   case '#': return(SHARP);
1927   case '(':
1928    if ((c1 = my_getc(f)) != '*') { my_ungetc_(c1, f); return(LPAR); }
1929 
1930    /* SJM 06/01/04 - for new @(*) form can't be attr - need to check */
1931    /* spaces possible because something like @(`star ) is possible */
1932    if (__canbe_impl_evctrl) { my_ungetc_(c1, f); return(LPAR); }
1933 
1934    /* collect attribute into global string */
1935    rd_attribute(f);
1936    goto again;
1937   case ')': return(RPAR);
1938   case '[': return(LSB);
1939   case ']': return(RSB);
1940   case '{': return(LCB);
1941   case '}': return(RCB);
1942   /* notice dot can not start real number in Verilog - digit or sign only */
1943   case '.': return(DOT);
1944   case '?': return(QUEST);
1945   case '@': return(AT);
1946   case '=':
1947    if ((c1 = my_getc(f)) != '=')
1948     {
1949      if (c1 == '>') return(PPTHCON);
1950      my_ungetc_(c1, f);
1951      return(EQ);
1952     }
1953    if ((c1 = my_getc(f)) != '=') { my_ungetc_(c1, f); return(RELEQ); }
1954    return(RELCEQ);
1955   case '\'':
1956    return(rd_num(f, c));
1957   case '+': return(PLUS);
1958   case '-':
1959    if ((c1 = my_getc(f)) != '>') { my_ungetc_(c1, f); return(MINUS); }
1960    return(CAUSE);
1961 
1962   case '0': case '1': case '2': case '3': case '4': case '5':
1963   case '6': case '7': case '8': case '9':
1964    return(rd_num(f, c));
1965   case '*':
1966    if ((c1 = my_getc(f)) != '>') { my_ungetc_(c1, f); return(TIMES); }
1967    return(FPTHCON);
1968   /* notice no C assignment op operators */
1969   case '/':
1970    if ((t1typ = rd_comment(f)) == UNDEF) goto again;
1971    if (t1typ == TEOF) return(TEOF);
1972    return(DIV);
1973   case '%': return(MOD);
1974   case '~':
1975    /* notice ~& and ~| parse as 2 that must be unaries */
1976    /* a ~| b is meaningless - since ~ is unary only */
1977    /* but ~^ is alternative form of xnor (^~) */
1978    if ((c1 = my_getc(f)) == '^') return(REDXNOR);
1979    my_ungetc_(c1, f);
1980    return(BITNOT);
1981   case '&':
1982    if ((c1 = my_getc(f)) != '&') { my_ungetc_(c1, f); return(BITREDAND); }
1983    if ((c1 = my_getc(f)) != '&') { my_ungetc_(c1, f); return(BOOLAND); }
1984    return(TCHKEVAND);
1985   case '|':
1986    if ((c1 = my_getc(f)) != '|') { my_ungetc_(c1, f); return(BITREDOR); }
1987    return(BOOLOR);
1988   /* also ^~ 2 unaries or bitwise xor of unary bit wise not */
1989   case '^':
1990    /* notice ^~ is not bit wise xor of bit wise negated unary result */
1991    /* but special built in operator */
1992    if ((c1 = my_getc(f)) == '~') return(REDXNOR);
1993    my_ungetc_(c1, f);
1994    return(BITREDXOR);
1995   case '!':
1996    if ((c1 = my_getc(f)) != '=') { my_ungetc_(c1, f); return(NOT); }
1997    if ((c1 = my_getc(f)) != '=') { my_ungetc_(c1, f); return(RELNEQ); }
1998    return(RELCNEQ);
1999   case '>':
2000    if ((c1 = my_getc(f)) == '=') return(RELGE);
2001    else if (c1 == '>')
2002     {
2003      /* SJM 10/01/03 - add >>> arithmetic right shift */
2004      if ((c1 = my_getc(f)) == '>') return(ASHIFTR);
2005      my_ungetc_(c1, f);
2006      return(SHIFTR);
2007     }
2008    my_ungetc_(c1, f);
2009    return(RELGT);
2010   case '<':
2011    if ((c1 = my_getc(f)) == '=') return(RELLE);
2012    else if (c1 == '<')
2013     {
2014      /* SJM 10/01/03 - add <<< arithmetic left shift */
2015      if ((c1 = my_getc(f)) == '<') return(ASHIFTL);
2016      my_ungetc_(c1, f);
2017      return(SHIFTL);
2018     }
2019    my_ungetc_(c1, f);
2020    return(RELLT);
2021   case '\\':
2022    /* escaped new line is white space and inc line counter */
2023    /* removed from macro bodies */
2024    if ((c1 = my_getc(f)) == '\n')
2025     { __lin_cnt++; __total_rd_lines++; goto again3; }
2026    else { my_ungetc_(c1, f); }
2027 
2028    /* handle escaped ID */
2029    for (toolong = FALSE, len = 0, cp = __token;;)
2030     {
2031      /* should never happen since max. line is same as IDLEN */
2032      if (++len >= IDCHARS - 1)
2033       {
2034        if (!toolong)
2035         {
2036          __pv_ferr(942,
2037           "Verilog escaped identifier too many characters (%d)", IDCHARS - 2);
2038           toolong = TRUE;
2039         }
2040       }
2041      else *cp++ = c;
2042 
2043      if ((c = my_getc(f)) == EOF) return(TEOF);
2044      /* 3 is new line, 1 end and don't back up (white space) */
2045      if ((ctval = __pv_ctab[c & 0x7f]) == 3) { my_ungetc_(c, f); break; }
2046      if (ctval == 1) break;
2047     }
2048    /* lrm says trailing white space not part of escaped ID */
2049    /* but must store space at end or name will not be output right */
2050    *cp++ = ' ';
2051    *cp = '\0';
2052    /* according to P1364 must store escaped that is legal as non escaped */
2053    /* but can not escape keyword */
2054    if (!try_chg_tononesc()) return(UNDEF);
2055    return(ID);
2056   case '"': return(vgetstr(f));
2057   case EOF: return(TEOF);
2058  }
2059  /* here know digits eliminated so only letters, $, and _ have ct val 0 */
2060  if (ctval != 0 && c != '`')
2061   {
2062    __pv_ferr(943, "identifier starts with illegal char '%c' (%x)", c & 0xff,
2063     c & 0xff);
2064    goto again;
2065   }
2066  /* try to recognize some kind of id - only */
2067  for (toolong = FALSE, cp = __token, len = 0;;)
2068   {
2069    if (++len >= IDCHARS)
2070     {
2071      if (!toolong)
2072       {
2073        __pv_ferr(944,
2074         "Verilog identifier has too many characters (%d)", IDCHARS - 1);
2075        toolong = TRUE;
2076       }
2077     }
2078    else *cp++ = c;
2079 
2080    c = my_getc(f);
2081    if (__pv_ctab[c & 0x7f] == 0) continue;
2082 
2083    /* must not process \n (3) until next time through */
2084    /* or lin_cnt wrong for errors */
2085    /* punctuation token end - unget it */
2086    /* must always put back char after token since even if white space */
2087    /* a .b .c is not xmr - even though think lrm says it is */
2088    /* unget causes any error to be caught later */
2089    my_ungetc_(c, f);
2090    goto end_id;
2091   }
2092 end_id:
2093  *cp = '\0';
2094  /* only keywords ($ system tasks are not keywords) can be in keyword table */
2095  t1typ = get_vkeywrd(__token);
2096  return(t1typ);
2097 }
2098 
2099 /*
2100  * get character routine that can read from macro
2101  */
my_getc(FILE * f)2102 static int32 my_getc(FILE *f)
2103 {
2104  register int32 c;
2105 
2106 again:
2107  if (f == NULL)
2108   {
2109    c = *__visp->vichp;
2110    /* for get ch from line form, must never move past \0 */
2111    if (c == '\0') return(EOF);
2112    (__visp->vichp)++;
2113   }
2114  else c = getc(f);
2115 
2116  if ((__pv_ctab[c & 0x7f] == 4 || c > 127) && !__rding_comment && c != EOF)
2117   {
2118    __finform(416, "illegal non printable character (%x) ignored", c & 0xff);
2119    goto again;
2120   }
2121  return(c);
2122 }
2123 
2124 /*
2125  * get a comment
2126  */
rd_comment(FILE * f)2127 static int32 rd_comment(FILE *f)
2128 {
2129  register int32 c;
2130  int32 c2;
2131 
2132  /* // to EOL comment */
2133  if ((c2 = my_getc(f)) == '/')
2134   {
2135    __rding_comment = TRUE;
2136    while ((c = my_getc(f)) != '\n') if (c == EOF) return(TEOF);
2137    __rding_comment = FALSE;
2138    my_ungetc_(c, f);
2139    return(UNDEF);
2140   }
2141  /* slash-star comments don't nest */
2142  if (c2 == '*')
2143   {
2144 more_comment:
2145    __rding_comment = TRUE;
2146    while ((c = my_getc(f)) != '*')
2147     {
2148      /* error if / * comments nested */
2149      if (c == '/')
2150       {
2151        if ((c2 = my_getc(f)) == '*')
2152         {
2153          __pv_fwarn(622, "nested /* in /* style comment");
2154          continue;
2155         }
2156        c = c2;
2157       }
2158      if (c == EOF)
2159       {
2160        if (__iact_state)
2161         __pv_ferr(960,
2162         "interactive /* comment cannot extend across multiple lines - */ added");
2163        __rding_comment = FALSE;
2164        return(TEOF);
2165       }
2166      if (c == '\n') { __lin_cnt++; __total_rd_lines++; }
2167     }
2168 got_star:
2169    if ((c = my_getc(f)) == '/')
2170     {
2171      __rding_comment = FALSE;
2172      return(UNDEF);
2173     }
2174    if (c == '*') goto got_star;
2175    if (c == '\n') { __lin_cnt++; __total_rd_lines++; }
2176    goto more_comment;
2177   }
2178  /* not a comment so treat as name token */
2179  /* notice c2 here must be most recent because above if never falls through */
2180  my_ungetc_(c2, f);
2181  return(DIV);
2182 }
2183 
2184 /* macro for adding char and growing attr wrk str */
2185 #define addto_attrwrkstr_(c) \
2186  do { \
2187   int32 osize; \
2188   if (++len >= __attrwrklen - 1) \
2189    { \
2190     osize = __attrwrklen; \
2191     __attrwrklen += IDLEN; \
2192     __attrwrkstr = __my_realloc(__attrwrkstr, osize, __attrwrklen); \
2193     chp = &(__attrwrkstr[len - 1]); \
2194    } \
2195   *chp++ = (c); \
2196  } while (0)
2197 
2198 /*
2199  * read an attribute char by char into a saved line
2200  *
2201  * know (* read and reading ending ) of *)
2202  * collected into attr wrk str - parsed later
2203  *
2204  * error if comments in attribute section
2205  * since parsed in separate parser subroutine `ifdefs must be self contained
2206  *
2207  * LOOKATME - adding ; at end - not clear from grammar if required
2208  *            assuming not for now
2209  */
rd_attribute(FILE * f)2210 static void rd_attribute(FILE *f)
2211 {
2212  register char *chp;
2213  int32 c, c2, len, wrk_fnam_ind, wrk_lin_cnt;
2214 
2215  wrk_fnam_ind = __cur_fnam_ind;
2216  wrk_lin_cnt = __lin_cnt;
2217 
2218  for (chp = __attrwrkstr, len = 0;;)
2219   {
2220    c = my_getc(f);
2221    if (c == EOF)
2222     {
2223 hit_eof:
2224      my_ungetc_(c, f);
2225      __pv_ferr(940, "end of file read inside attribute_instance (* ... *)");
2226      return;
2227     }
2228    switch (c) {
2229     case '\\':
2230      /* escaped can't end or comment */
2231      addto_attrwrkstr_(c);
2232      c = my_getc(__in_s);
2233      if (c == EOF) goto hit_eof;
2234      if (c == '\n') { __lin_cnt++; __total_rd_lines++; }
2235      addto_attrwrkstr_(c);
2236      continue;
2237     case '"':
2238      /* collect string to un-escaped " */
2239      addto_attrwrkstr_(c);
2240      for (;;)
2241       {
2242        if ((c = my_getc(f)) == EOF) goto hit_eof;
2243        if (c == '\\')
2244         {
2245          /* always also both escape and char after */
2246          addto_attrwrkstr_(c);
2247          c = my_getc(__in_s);
2248          if (c == EOF) goto hit_eof;
2249          if (c == '\n') { __lin_cnt++; __total_rd_lines++; }
2250          addto_attrwrkstr_(c);
2251          continue;
2252         }
2253        if (c == '"') { addto_attrwrkstr_(c); break; }
2254        if (c == '\n') { __lin_cnt++; __total_rd_lines++; }
2255        if (c == '\n' || c == '\r')
2256         {
2257          __pv_ferr(945,
2258           "string inside attribute_instance (* .. *) can not cross line boundary - must escape new line");
2259          if ((c = skipto_attr_end(f)) == EOF) goto hit_eof;
2260          return;
2261         }
2262        /* non speical char in string , just collect */
2263        addto_attrwrkstr_(c);
2264       }
2265      continue;
2266     case '/':
2267      addto_attrwrkstr_(c);
2268      c = my_getc(f);
2269      if (c == '/' || c == '*')
2270       {
2271        __pv_ferr(3402,
2272         "/%c comment inside attribute_instance (* ... *) illegal - must be moved outside", c);
2273        if ((c = skipto_attr_end(f)) == EOF) goto hit_eof;
2274        return;
2275       }
2276      my_ungetc_(c, f);
2277      continue;
2278     case '(':
2279      /* know starting (* read before proc called, this is ( inside */
2280      addto_attrwrkstr_(c);
2281      c = my_getc(f);
2282      if (c == '*')
2283       {
2284        __pv_ferr(3403,
2285         "atttribute start sequence (* illegal inside attribute_instance");
2286       }
2287      /* still include it */
2288      my_ungetc_(c, f);
2289      continue;
2290     case '*':
2291      /* do not include leading (* or ending *) */
2292      c2 = my_getc(f);
2293      if (c2 == ')') goto done;
2294      addto_attrwrkstr_(c);
2295      my_ungetc_(c2, f);
2296      continue;
2297     default:
2298      addto_attrwrkstr_(c);
2299    }
2300   }
2301 done:
2302  /* LOOKATME is semi required? */
2303  chp--;
2304  if (*chp != ';')
2305   {
2306    chp++;
2307    addto_attrwrkstr_(';');
2308   }
2309  else chp++;
2310  *chp = '\0';
2311 
2312  /* length does not include added \0 */
2313  __attr_line_len = len;
2314 
2315  if (__attr_prefix)
2316   {
2317    __pv_ferr(3401,
2318     "more than one attribute_instance in row - using last at %s instead of first at %s",
2319     __bld_lineloc(__xs, (word32) wrk_fnam_ind, wrk_lin_cnt),
2320     __bld_lineloc(__xs2, (word32) __attr_fnam_ind, __attr_lin_cnt));
2321   }
2322  __attr_fnam_ind = wrk_fnam_ind;
2323  __attr_lin_cnt = wrk_lin_cnt;
2324  __attr_prefix = TRUE;
2325  /* DBG remove -- */
2326  if (__debug_flg)
2327   {
2328    __dbg_msg("&&& at %s attribute_instance string [%s])\n",
2329     __bld_lineloc(__xs, (word32) __attr_fnam_ind, __attr_lin_cnt),
2330     __attrwrkstr);
2331   }
2332  /* --- */
2333 }
2334 
2335 /*
2336  * skip to attribute ending *)
2337  */
skipto_attr_end(FILE * f)2338 static int32 skipto_attr_end(FILE *f)
2339 {
2340  register int32 c;
2341 
2342  __attr_fnam_ind = 0;
2343  __attr_lin_cnt = 0;
2344  for (;;)
2345   {
2346    if ((c = my_getc(f)) == EOF) return(EOF);
2347    switch (c) {
2348     case '\\':
2349      if ((c = my_getc(f)) == EOF) return(EOF);
2350      continue;
2351     case '"':
2352      for (;;)
2353       {
2354        if ((c = my_getc(f)) == EOF) return(EOF);
2355        if (c == '\\')
2356         {
2357          if ((c = my_getc(f)) == EOF) return(EOF);
2358          continue;
2359         }
2360        if (c == '"') break;
2361       }
2362      continue;
2363     case '*':
2364      c = my_getc(f);
2365      if (c == ')') goto done;
2366    }
2367    /* non special keep reading */
2368   }
2369 done:
2370  return(c);
2371 }
2372 
2373 /*
2374  * read a string token - Verilog string are wide numbers
2375  * notice %% must be left here as 2 characters - processed by display
2376  * also value collected in token is not a 0 terminated c string (no \0)
2377  */
vgetstr(FILE * f)2378 static int32 vgetstr(FILE *f)
2379 {
2380  register char *cp;
2381  int32 c, c1, len, toolong, nsize;
2382 
2383  /* return string - should save length - Ver. strings not \0 terminated */
2384  if ((c = my_getc(f)) == '"')
2385   {
2386    /* "" is special case of 8 bit 0 */
2387    *__strtoken = '\0';
2388    len = 1;
2389    goto done;
2390   }
2391  for (toolong = FALSE, len = 0, cp = __strtoken;;)
2392   {
2393    switch (c) {
2394     case '\n': case '\r':
2395      __pv_ferr(945,
2396       "string cannot cross line boundary (new line must be escaped)");
2397      goto done;
2398     case '\\':
2399      c1 = my_getc(f);
2400      switch (c1) {
2401       case 't': c = '\t'; break;
2402       case 'n': c = '\n'; break;
2403       case '\\': c = '\\'; break;
2404       case '"': c = '"'; break;
2405       case '0': case '1': case '2': case '3': case '4': case '5':
2406       case '6': case '7':
2407        /* c is escaped char value (octal) */
2408        c = c1 - '0';
2409        /* this always reads one past and puts back - read always pushed back */
2410        c1 = my_getc(f);
2411        if (isdigit(c1) && c1 != '8' && c1 != '9')
2412         {
2413          c = (c << 3) + c1 - '0';
2414          c1 = my_getc(f);
2415          if (isdigit(c1) && c1 != '8' && c1 != '9') c = (c << 3) + c1 - '0';
2416          else my_ungetc_(c1, f);
2417         }
2418        else my_ungetc_(c1, f);
2419        break;
2420       default:
2421        /* skip escape and use next char as is */
2422        __pv_fwarn(555, "string \\ escaped character '%c' (%x) same as '%c'",
2423         c1 & 0x7f, c1 & 0x7f, c1 & 0x7f);
2424        c = c1;
2425      }
2426      break;
2427     case '"': goto done;
2428    }
2429    /* should never happen since max. line is same as IDLEN - nd " room */
2430    /* SJM 03/20/00 - now allow up to 1M length strings */
2431    if (++len >= __strtok_wid)
2432     {
2433      if (len >= MAXNUMBITS)
2434       {
2435        if (!toolong)
2436         {
2437          __pv_ferr(946, "string token has too many characters (%d)",
2438    MAXNUMBITS - 1);
2439          toolong = TRUE;
2440        }
2441       }
2442      else
2443       {
2444        /* LOOKATME - SJM 03/20/00 - doubling may be too fast growth */
2445        /* AIV 04/20/06 - was incorrectly using num should be str */
2446        nsize = 2*__strtok_wid;
2447        __strtoken = __my_realloc(__strtoken, __strtok_wid, nsize);
2448        __strtok_wid = nsize;
2449        /* AIV 04/20/06 - need to reset chp pointer due to realloc */
2450        cp = &(__strtoken[len - 1]);
2451        *cp++ = c;
2452       }
2453     }
2454    else *cp++ = c;
2455 
2456    if ((c = my_getc(f)) == EOF)
2457     {
2458      if (__iact_state)
2459       __pv_ferr(947, "interactive string terminator missing");
2460      else __pv_ferr(947, "end of file read inside string");
2461      strcpy(__strtoken, "");
2462      len = 1;
2463      goto done;
2464     }
2465    /* if (__debug_flg) __dbg_msg("&&& vgetstr read %c (%x)\n", c , c); */
2466   }
2467 
2468 done:
2469  /* except for expr. node string bit - this is now normal val. bit pattern */
2470  /* assuming 8 bit bytes - on serious error len can be 0 */
2471  if ((__itoklen = 8*len) == 0) __itoklen = 1;
2472  /* string are actually sized token - must work in concatenates */
2473  __itoksized = TRUE;
2474  /* puts string into ac wrk and bc wrk - may adjust size */
2475  str_tovval();
2476  /* if (__debug_flg) __dbg_msg("&&& vgstrread [%s]\n", __strtoken); */
2477  /* notice even though converted to value - can print input from __token */
2478  return(LITSTR);
2479 }
2480 
2481 /*
2482  * need to convert form escaped ID to normal if escaped (after \\ is legal)
2483  * notice although '$' is a class 0 and can go in IDs, it can not start ID
2484  */
try_chg_tononesc(void)2485 static int32 try_chg_tononesc(void)
2486 {
2487  register char *chp;
2488  register int32 len, ctval;
2489  char s1[IDLEN];
2490 
2491  chp = __token;
2492  /* move past escape */
2493  chp++;
2494  for (len = 0; *chp != '\0'; chp++)
2495   {
2496    if ((ctval = __pv_ctab[*chp & 0x7f]) != 0)
2497     {
2498      if (ctval == 1 || ctval == 3)
2499       {
2500        /* if next is end of ID \0, then found legal non escaped */
2501        if (chp[1] == '\0')
2502         {
2503          if (strcmp(__token, "\\ ") == 0)
2504           {
2505            __pv_ferr(942,
2506      "Verilog escaped identifier empty - at least one non white space character required");
2507            return(FALSE);
2508           }
2509 
2510          strcpy(s1, &(__token[1]));
2511          /* remove the ending white space char */
2512          s1[len] = '\0';
2513          strcpy(__token, s1);
2514          return(TRUE);
2515         }
2516       }
2517      return(TRUE);
2518     }
2519    /* first is one after escape this is present at entry */
2520    /* SJM - 05/26/99 - fixed bug where \222 were getting un-escaped */
2521    if (len == 0)
2522     {
2523      if (*chp == '$' || isdigit(*chp)) return(TRUE);
2524      /* SJM-09/18/00- FIXME must not unescape or - need to handle as keywrd */
2525      if (strcmp(chp, "or ") == 0) return(TRUE);
2526     }
2527    len++;
2528   }
2529  return(TRUE);
2530 }
2531 
2532 /*
2533  * convert ascii user input string into ac wrk and bc wrk
2534  *
2535  * notice __ac wrk and __bc wrk not necessarily contiguous
2536  */
str_tovval(void)2537 static void str_tovval(void)
2538 {
2539  register int32 wlen;
2540 
2541  wlen = wlen_(__itoklen);
2542  if (wlen > __abwrkwlen || (__abwrkwlen > DFLTIOWORDS && wlen <= DFLTIOWORDS))
2543   chg_abwrklen(wlen);
2544  zero_allbits_(__bcwrk, __itoklen);
2545  __vstr_to_vval(__acwrk, __strtoken, __itoklen);
2546 }
2547 
2548 /*
2549  * convert Verilog literal style string to a Verilog numeric value
2550  * notice Verilog has built in 8 bit chars
2551  * know ap wide enough and all bits zeroed before called here
2552  * notice this has built in dependency on 32 bit words
2553  */
__vstr_to_vval(word32 * ap,char * s,int32 bitlen)2554 extern void __vstr_to_vval(word32 *ap, char *s, int32 bitlen)
2555 {
2556  register int32 i;
2557  register int32 bi;
2558  int32 slen;
2559 
2560  slen = bitlen/8;
2561  /* fill val from low char (right str) to high char (const left to right) */
2562  for (i = slen - 1, bi = 0; i >= 0; i--)
2563   {
2564    if (bi == 0) *ap = (word32) s[i];
2565    else *ap |= (((word32) s[i]) << bi);
2566    if (bi == 24) { bi = 0; ap++; } else bi += 8;
2567   }
2568 }
2569 
2570 /*
2571  * convert c style string to Verilog value
2572  * this pushes new v value onto stack
2573  */
__cstr_to_vval(char * s)2574 extern struct xstk_t *__cstr_to_vval(char *s)
2575 {
2576  int32 blen, slen;
2577  struct xstk_t *xsp;
2578 
2579  slen = strlen(s);
2580  blen = 8*slen;
2581  push_xstk_(xsp, blen);
2582  zero_allbits_(xsp->ap, blen);
2583  zero_allbits_(xsp->bp, blen);
2584  __vstr_to_vval(xsp->ap, s, blen);
2585  return(xsp);
2586 }
2587 
2588 /*
2589  * push back for internal use by unget routines where get1_vtok value
2590  * must be pushed back
2591  */
unget2_vtok(int32 ttyp)2592 static void unget2_vtok(int32 ttyp)
2593 {
2594  int32 save_ttyp;
2595 
2596  save_ttyp = __toktyp;
2597  __toktyp = ttyp;
2598  __unget_vtok();
2599  __toktyp = save_ttyp;
2600 }
2601 
2602 /*
2603  * push back an already read token operator or keyword token
2604  */
__unget_vtok(void)2605 extern void __unget_vtok(void)
2606 {
2607  __lasttoktyp = __toktyp;
2608  strcpy(__lasttoken, __token);
2609  /* SJM 10/16/00 - save any pending attribte - because does not really read */
2610  /* token the actual attr string and other vars will be right and preserved */
2611  __last_attr_prefix = __attr_prefix;
2612 
2613  /* extremely rare number push back case */
2614  if (__toktyp == NUMBER)
2615   {
2616    int32 wlen;
2617 
2618    __lastitokbase = __itokbase;
2619    __lastitoksized = __itoksized;
2620    __lastitoksizdflt = __itoksizdflt;
2621    __lastitok_signed = __itok_signed;
2622    __lastitoklen = __itoklen;
2623 
2624    /* must malloc to save in rare pushed back case */
2625    /* SJM 03/20/00 - no unget of num token since already in a/b wrk as val */
2626    wlen = wlen_(__itoklen);
2627    __lastacwrk = (word32 *) __my_malloc(wlen*WRDBYTES);
2628    __lastbcwrk = (word32 *) __my_malloc(wlen*WRDBYTES);
2629    memcpy(__lastacwrk, __acwrk, wlen*WRDBYTES);
2630    memcpy(__lastbcwrk, __bcwrk, wlen*WRDBYTES);
2631    return;
2632   }
2633  if (__toktyp == REALNUM)
2634   {
2635    __lastitokbase = __itokbase;
2636    __lastitoksized = __itoksized;
2637    __lastitoksizdflt = __itoksizdflt;
2638    __lastitok_signed = __itok_signed;
2639    __lastitoklen = __itoklen;
2640    __lastitok_realval = __itok_realval;
2641   }
2642 }
2643 
2644 /*
2645  * read a verilog style number
2646  * know first char digit or ' and reads number end char
2647  * width if present left in nwidtoken and value in token
2648  *
2649  * notice that maximun number can be IDLEN - 1 digits must leave
2650  * since other sizes like max. no. of const. bits set to prevent possibility
2651  * of overflow
2652  *
2653  * notice '_' in number are just ignored and not added to token, is this ok
2654  */
rd_num(FILE * f,int32 c1)2655 static int32 rd_num(FILE *f, int32 c1)
2656 {
2657  register char *chp;
2658  register int32 c;
2659  int32 len, toolong, isreal, errnum, blen, nsize;
2660  word32 v;
2661  double d1;
2662  char *endp;
2663  /* SJM 03/20 - FIXME - for now limiting dec unsized to 16k digits */
2664  char nwidtoken[4*IDLEN];
2665 
2666  __itokbase = BDEC;
2667  __itoksized = FALSE;
2668  __itoksizdflt = FALSE;
2669  __itok_signed = FALSE;
2670  __itoklen = WBITS;
2671  strcpy(nwidtoken, "");
2672 
2673  /* read the possible decimal size value or unsized unbased number */
2674  isreal = FALSE;
2675  len = 0;
2676  if ((c = c1) != '\'')
2677   {
2678    /* 06/22/00 - SJM - only 2 token number case if `[base][num] */
2679    __maybe_2tok_sized_num = FALSE;
2680    /* collect value */
2681    for (toolong = FALSE, chp = nwidtoken, len = 0;;)
2682     {
2683      while (c == '_') c = my_getc(f);
2684      switch (c) {
2685       case '0': case '1': case '2': case '3': case '4': case '5':
2686       case '6': case '7': case '8': case '9': break;
2687       /* - and + here */
2688       case 'e': case 'E': isreal = TRUE; break;
2689       case '.': isreal = TRUE; break;
2690       case '-': case '+':
2691        /* + and minus after exponent legal else end of number */
2692        /* this can never cause a number to be real */
2693        if (*(chp - 1) == 'e' || *(chp - 1) == 'E') break;
2694        goto end_unsiz;
2695       default: goto end_unsiz;
2696      }
2697     if (++len >= 4*IDLEN)
2698      {
2699       if (!toolong)
2700        {
2701         __pv_ferr(948,
2702          "Verilog size prefix or unsized number too many characters (%d)",
2703          4*IDLEN);
2704         toolong = TRUE;
2705        }
2706      }
2707     else *chp++ = c;
2708     c = my_getc(f);
2709    }
2710 end_unsiz:
2711   *chp = '\0';
2712 
2713   /* know c is not a digit - punctuation ok */
2714   if (__pv_ctab[c & 0x7f] == 0)
2715    {
2716     /* numbers can end with letter in udp tables */
2717     if (__letendnum_state) goto ok_letend;
2718     __pv_ferr(949,
2719      "unsized number terminated with illegal char '%c' (%x)", c & 0xff,
2720      c & 0xff);
2721     goto ok_letend;
2722    }
2723   /* this skips across new line */
2724   c = voverwhite(f, c);
2725   if (c == EOF) __macro_sep_width = TRUE;
2726  }
2727 
2728  /* know either c is char after unsized number or quote for Ver number */
2729 ok_letend:
2730  if (c != '\'')
2731   {
2732    /* 06/22/00 - SJM - only 2 token number case if `[base][num] */
2733    __maybe_2tok_sized_num = FALSE;
2734 
2735    /* char after white space starts next token */
2736    /* this is case where next token is special first token on line */
2737    my_ungetc_(c, f);
2738    /* SJM - 03/20/00 - here just increase to size needed */
2739    if (len >= __numtok_wid)
2740     {
2741      /* 06/26/00 - increase size with realloc but unsized not too wide */
2742      __numtoken = __my_realloc(__numtoken, __numtok_wid, __numtok_wid
2743       + RECLEN);
2744      __numtok_wid = len + RECLEN;
2745     }
2746    strcpy(__numtoken, nwidtoken);
2747    strcpy(nwidtoken, "");
2748 
2749    /* remove leading 0's  but if first char is . put 1 back */
2750    if (!__letendnum_state) rem_lead_0chars(__numtoken);
2751    /* allowing any legal c real here - but maybe should not allow dot not */
2752    /* surrounded by digits */
2753    if (isreal)
2754     {
2755      d1 = __my_strtod(__numtoken, &endp, &errnum);
2756      if (errnum != 0 || *endp != '\0')
2757       __pv_ferr(950, "illegal real number %s", __numtoken);
2758      /* notice some compilers crash if doubles not 8 byte aligned ? */
2759      /* therefore need special routine for doubles */
2760      __itok_realval = d1;
2761      __itoklen = REALBITS;
2762      __itokbase = BDBLE;
2763      __macro_sep_width = FALSE;
2764      return(REALNUM);
2765     }
2766    /* SJM 10/02/03 - string of dec digits no '[base] is signed decimal */
2767    __itok_signed = TRUE;
2768    /* handle numbers that fit in 10 chars as special case */
2769    if (strlen(__numtoken) < 10)
2770     {
2771      v = __my_strtoul(__numtoken, &endp, &errnum);
2772      if (errnum != 0 || *endp != '\0') __misc_terr(__FILE__, __LINE__);
2773      __acwrk[0] = v;
2774      __bcwrk[0] = 0L;
2775      if (__macro_sep_width) __macro_sav_nwid = (int32) v;
2776      return(NUMBER);
2777     }
2778    /* for implied WBITS number convert and truncate */
2779    goto do_convert;
2780   }
2781 
2782  /* know c is ' */
2783  /* know token read after this is not first token on line because */
2784  /* number becuase size number ' is on next line */
2785  /* know '[base] form is unsized and word32 but'[Ss][base] is signed */
2786 
2787  /* AIV 07/09/04 - special case to handle:  8'h`DEFINE */
2788  /* if `define macro contains a 'base it is illegal */
2789  if (__macbs_flag)
2790   {
2791    __pv_ferr(3418,
2792     "number with '[base] macro expansion %s contains extra '[base]", __token);
2793    /* AIV 07/12/04 - not sure what happens with error resync here */
2794    return(UNDEF);
2795   }
2796 
2797  /* if this is too wide will be caught later - this sets [size]' size */
2798  if (strcmp(nwidtoken, "") != 0)
2799   {
2800    blen = __my_strtoul(nwidtoken, &endp, &errnum);
2801    if (errnum != 0 || *endp != '\0')
2802     {
2803      __pv_ferr(952, "number size %s format bad", nwidtoken);
2804      __itoklen = WBITS;
2805     }
2806    else __itoklen = blen;
2807 
2808    /* saying 0'[base]... is legal and becomes WBITS */
2809    if (__itoklen == 0)
2810     {
2811      __pv_fwarn(557, "INTERNAL - zero number size changed to %d", WBITS);
2812      __itoklen = WBITS;
2813     }
2814    __itoksized = TRUE;
2815   }
2816  else
2817   {
2818    /* 06/22/00 - SJM - this is 2nd part of sized num */
2819    if (__maybe_2tok_sized_num)
2820     {
2821      /* flags turned off later */
2822      __itoklen = __macro_sav_nwid;
2823      __itoksized = TRUE;
2824     }
2825    else __itoksizdflt = TRUE;
2826   }
2827 
2828  /* '[base][number] is unsized 32 bits */
2829  if (__itoklen > MAXNUMBITS)
2830   {
2831    __pv_ferr(953, "number size too large (%d)", MAXNUMBITS);
2832    __itoklen = WBITS;
2833    __itoksized = FALSE;
2834   }
2835 
2836  /* SJM 10/01/03 - add code that get the optional base signed char */
2837  /* and set signed flag for use when expression token constructed */
2838  c = my_getc(f);
2839  if (c == 's' || c == 'S')
2840   {
2841    __itok_signed = TRUE;
2842    c = my_getc(f);
2843   }
2844 
2845  if ((__itokbase = __to_base(c)) == -1)
2846   {
2847    __pv_ferr(954,
2848     "illegal Verilog number base %c - for compiler directive use back quote(`)", c);
2849    my_ungetc_(c, f);
2850    __macro_sep_width = FALSE;
2851    return(UNDEF);
2852   }
2853  c = my_getc(f);
2854  c = voverwhite(f, c);
2855  /* AIV 07/09/04 - special case to handle:  8'h`DEFINE */
2856  if (c == '`')
2857   {
2858    int32 stok;
2859    my_ungetc_(c, f);
2860    /* save the base */
2861    stok = __itokbase;
2862    /* set the flag to make sure macro doesn't contain a base */
2863    __macbs_flag = TRUE;
2864    /* AIV 07/12/04 - need recursive call but can't read another number */
2865    __get_vtok();
2866    __macbs_flag = FALSE;
2867    __itokbase = stok;
2868    goto do_convert;
2869   }
2870 
2871  /* know c is 1st character of sized number */
2872  toolong = FALSE;
2873  for (chp = __numtoken, len = 0;;)
2874   {
2875    while (c == '_') c = my_getc(f);
2876    c1 = __is_vdigit(c, __itokbase);
2877    if (c1 == -1) break;
2878    if (c1 == -2)
2879     {
2880      __pv_ferr(955, "digit %c illegal for base '%c", c,
2881       __to_baselet(__itokbase));
2882      c = c1 = '0';
2883     }
2884    /* using maximum length of Verilog line as 1024 (really ID len. max) */
2885    if (++len >= __numtok_wid)
2886     {
2887      if (len >= MAXNUMBITS)
2888       {
2889        if (!toolong)
2890         {
2891          __pv_ferr(956,
2892           "Verilog sized number too many characters (%d)", MAXNUMBITS);
2893          toolong = TRUE;
2894         }
2895       }
2896      else
2897       {
2898        /* LOOKATME - SJM 03/20/00 - doubling may be too fast growth */
2899        nsize = 2*__numtok_wid;
2900        __numtoken = __my_realloc(__numtoken, __numtok_wid, nsize);
2901        __numtok_wid = nsize;
2902        /* AIV 04/20/06 - need to reset chp pointer due to realloc */
2903        chp = &(__numtoken[len - 1]);
2904        *chp++ = c1;
2905       }
2906     }
2907    else *chp++ = c1;
2908    c = my_getc(f);
2909   }
2910  *chp = '\0';
2911 
2912  if (strcmp(__numtoken, "") == 0)
2913   {
2914    __pv_ferr(957, "sized number value part empty");
2915    strcpy(__numtoken, "0");
2916   }
2917 
2918  if (__pv_ctab[c & 0x7f] == 0)
2919   __pv_ferr(958, "sized number terminated with illegal char '%c' (%x)",
2920   c % 0xff, c & 0xff);
2921  my_ungetc_(c, f);
2922  /* finally do the conversion - know sizedness set and length in itok len */
2923  /* length never 0 */
2924 
2925  /* notice this can never generate error */
2926  /* wide numbers truncated in here - do all non real numbers here */
2927 do_convert:
2928  /* this sets number bit length and allocates number if needed */
2929  __macro_sep_width = FALSE;
2930  __to_dhboval(__itokbase, TRUE);
2931  return(NUMBER);
2932 }
2933 
2934 /*
2935  * remove leading 0 characters from numer string in token
2936  * this works in place
2937  */
rem_lead_0chars(char * s)2938 static void rem_lead_0chars(char *s)
2939 {
2940  register int32 i, j;
2941  int32 slen;
2942 
2943  /* first set index to first non 0 char */
2944  for (i = 0; ; i++)
2945   {
2946    /* number all zero convert to 1 0 */
2947    if (s[i] == '\0') { s[0] = '0'; s[1] = '\0'; return; }
2948    if (s[i] != '0') break;
2949   }
2950  if (i == 0) return;
2951  /* if leading is . then must add 1 leading 0 - know at least 0. at start */
2952  if (s[i] == '.') i--;
2953 
2954  /* copy to remove all leading 0's */
2955  slen = strlen(s);
2956  for (j = 0; j < slen - i; j++) s[j] = s[i + j];
2957  s[slen - i] = '\0';
2958 }
2959 
2960 /*
2961  * skip over white space and return char just after
2962  * expects current character to be in c - no skip if current not white space
2963  */
voverwhite(FILE * f,register int32 c)2964 static int32 voverwhite(FILE *f, register int32 c)
2965 {
2966  int32 ct;
2967 
2968  for (;; c = my_getc(f))
2969   {
2970    /* notice anthing escaped is not white space */
2971    if ((ct = __pv_ctab[c & 0x7f]) == 1) continue;
2972    if (ct == 3)
2973     { __lin_cnt++; __total_rd_lines++; __first_num_eol = TRUE; continue; }
2974    break;
2975   }
2976  return(c);
2977 }
2978 
2979 /*
2980  * convert a character to a Verilog number base
2981  */
__to_base(int32 c)2982 extern int32 __to_base(int32 c)
2983 {
2984  switch (c) {
2985   case 'b': case 'B': return(BBIN);
2986   case 'o': case 'O': return(BOCT);
2987   case 'd': case 'D': return(BDEC);
2988   case 'h': case 'H': return(BHEX);
2989  }
2990  return(-1);
2991 }
2992 
2993 /*
2994  * return TRUE if character can appear in Verilog number
2995  * return value if digit, -1 for non digit or -2 for out of range digit
2996  * (ends number)
2997  */
__is_vdigit(int32 c,int32 base)2998 extern int32 __is_vdigit(int32 c, int32 base)
2999 {
3000  switch (c) {
3001   case 'x': case 'X': return('x');
3002   case '?': case 'z': case 'Z': return('z');
3003  }
3004  if (!isxdigit(c)) return(-1);
3005  switch (base) {
3006   case BBIN:
3007    if (c != '0' && c != '1') return(-2);
3008    break;
3009   case BOCT:
3010    if (c < '0' || c > '7') return(-2);
3011    break;
3012   case BDEC:
3013    if (!isdigit(c)) return(-2);
3014    break;
3015   case BHEX:
3016    if (c >= 'A' && c <= 'F') return(tolower(c));
3017    break;
3018   default: __case_terr(__FILE__, __LINE__);
3019  }
3020  return(c);
3021 }
3022 
3023 /*
3024  * ROUTINES TO CONVERT TO AB VALUE FROM SCANNED TOKEN
3025  */
3026 
3027 /*
3028  * convert a scanned input number token to a h, b, or o value
3029  * this routines x/z extends from highest used digit if needed
3030  * warning if too many digits and truncates
3031  * this routine fills __ac wrk and __bc wrk, if needed will widen
3032  *
3033  * this is also used by tf_ string to value conversion routines
3034  * sets values in __numtoken, __itoklen, __itok_signed
3035  */
__to_dhboval(int32 base,int32 emit_warn)3036 extern void __to_dhboval(int32 base, int32 emit_warn)
3037 {
3038  register int32 chlen, wlen, srcwlen, ubits;
3039  int32 srcblen;
3040  word32 aival, bival;
3041  char s1[RECLEN];
3042 
3043  chlen = strlen(__numtoken);
3044  /* must allow enough room in work string to convert number */
3045  /* even if much wider than itoklen - just at least wide estimate here */
3046  srcblen = chlen_to_bitlen(chlen, base);
3047  if (srcblen < __itoklen) srcblen = __itoklen;
3048 
3049  /* SJM 10/02/03 now wide decimal or numbers with s/S base part signed */
3050  /* therefore itok is int32 global not accessed here */
3051 
3052  wlen = wlen_(srcblen);
3053  /* if need to widen or wider than default, change allocated length */
3054  /* notice left until maybe changed next time used */
3055  if (wlen > __abwrkwlen || (__abwrkwlen > DFLTIOWORDS && wlen <= DFLTIOWORDS))
3056   chg_abwrklen(wlen);
3057 
3058  /* now know __ac wrk and __bc wrk wide enough */
3059  memset(__acwrk, 0, wlen*WRDBYTES);
3060  memset(__bcwrk, 0, wlen*WRDBYTES);
3061 
3062  /* convert number in token into work constant values */
3063  /* notice previous guess of src blen, made exact here */
3064  switch (base) {
3065   /* notice must trucate/widen after conversion here */
3066   case BDEC: to_dec(&srcblen); strcpy(s1, "decimal"); break;
3067   case BBIN: to_bin(chlen); strcpy(s1, "binary"); srcblen = chlen; break;
3068   case BOCT: to_oct(chlen); strcpy(s1, "octal"); srcblen = 3*chlen; break;
3069   case BHEX: to_hex(chlen); strcpy(s1, "hex"); srcblen = 4*chlen; break;
3070   default: __case_terr(__FILE__, __LINE__);
3071  }
3072 
3073  /* words and occupied bits of number represented by chars */
3074  /* check case of number of character wider - maybe too wide number */
3075  /* __itoklen is number of bits that word32 must be stored in */
3076  /* srcblen is number of bits in source input number */
3077  if (srcblen > __itoklen)
3078   {
3079    srcwlen = wlen_(srcblen);
3080    if (vnum_toowide(__acwrk, srcblen) || vnum_toowide(__bcwrk, srcblen))
3081     {
3082      /* no warning for [3-1]'h[zx] or [2-1]'o[zx] in high position */
3083      /* notice for hex, must be in same word32 to have not too wide nibble */
3084      if (base == BHEX)
3085       {
3086        if (srcblen - __itoklen < 4 && wlen == srcwlen
3087  && nibblexz(__acwrk[wlen - 1], __bcwrk[wlen - 1], srcblen))
3088         goto do_mask;
3089       }
3090      else if (base == BOCT)
3091       {
3092        if (srcblen - __itoklen < 3 && octdigxz(__acwrk, __bcwrk, srcblen))
3093         goto do_mask;
3094       }
3095      /* SJM 12/04/00 - no warn if skipping over ifdef because will not */
3096      /* parse `macro_width_name h [number] right */
3097      if (emit_warn && !__ifdef_skipping)
3098       {
3099        if (__run_state == SS_SIM)
3100         __pv_warn(558, "redundant digit(s) in tf_strput number %s",
3101          decompnum_to_str(s1, __numtoken, base, __itoklen));
3102        else __pv_fwarn(558, "redundant digit(s) in number %s",
3103         decompnum_to_str(s1, __numtoken, base, __itoklen));
3104       }
3105     }
3106    /* if values 0 or vnum not too wide, no warn but still must mask */
3107 
3108    /* must truncate the values to __itoklen */
3109    /* this leave high words as is but since unused - if used will be zeroed */
3110    /* before use */
3111 do_mask:
3112    ubits = ubits_(__itoklen);
3113    __acwrk[wlen - 1] &= __masktab[ubits];
3114    __bcwrk[wlen - 1] &= __masktab[ubits];
3115   }
3116  else if (srcblen < __itoklen)
3117   {
3118    /* case where widening needed */
3119    if (__numtoken[0] == 'z' || __numtoken[0] == 'Z')
3120     { aival = 0L; bival = 1L; }
3121    else if (__numtoken[0] == 'x' || __numtoken[0] == 'X')
3122     { aival = 1L; bival = 1L; }
3123    else { aival = 0L; bival = 0L; }
3124 
3125    widen_val(__acwrk, __itoklen, srcblen, aival);
3126    widen_val(__bcwrk, __itoklen, srcblen, bival);
3127   }
3128 }
3129 
3130 /*
3131  * computer number of bits + 1 needed to store number in base of chlen
3132  * worst case - could contain '_' place holders
3133  */
chlen_to_bitlen(int32 chlen,int32 base)3134 static int32 chlen_to_bitlen(int32 chlen, int32 base)
3135 {
3136  int32 bitlen;
3137  double d1;
3138 
3139  switch (base) {
3140   case BDEC:
3141    /* here must make sure bit enough if rounding error */
3142    /* actual conversion will compute exact bit length */
3143    d1 = ((double) chlen)/LG2_DIV_LG10 + WBITS;
3144    bitlen = (int32) d1;
3145    break;
3146   case BBIN: bitlen = chlen; break;
3147   case BOCT: bitlen = 3*chlen; break;
3148   case BHEX: bitlen = 4*chlen; break;
3149   default: __case_terr(__FILE__, __LINE__); return(0);
3150  }
3151  return(bitlen);
3152 }
3153 
3154 /*
3155  * change __ac wrk (and bc) work area length from blen if needed
3156  * only gets here if either blen (__itoklen) or abwork len wider than default
3157  * notice __ac wrk and __bc wrk not necessary contiguous
3158  */
chg_abwrklen(int32 wlen)3159 static void chg_abwrklen(int32 wlen)
3160 {
3161  int32 olen, nlen;
3162 
3163  olen = WRDBYTES*__abwrkwlen;
3164  if (wlen <= DFLTIOWORDS) __abwrkwlen = DFLTIOWORDS; else __abwrkwlen = wlen;
3165  nlen = WRDBYTES*__abwrkwlen;
3166  __acwrk = (word32 *) __my_realloc((char *) __acwrk, olen, nlen);
3167  __bcwrk = (word32 *) __my_realloc((char *) __bcwrk, olen, nlen);
3168 }
3169 
3170 /*
3171  * convert a number scanned token to a decimal value
3172  * know number initialized to 0 of itoklen width
3173  * LOOKATME - could maybe speed up by using scanf if fits in one word?
3174  */
to_dec(int32 * blen)3175 static void to_dec(int32 *blen)
3176 {
3177  /* know __ac wrk and __bc wrk set to 0 before this is called */
3178  if (strchr(__numtoken, 'z') != NULL)
3179   { one_allbits_(__bcwrk, __itoklen); *blen = __itoklen; return; }
3180  else if (strchr(__numtoken, 'x') != NULL)
3181   {
3182    /* 1 decimal digit will be at least this wide */
3183    one_allbits_(__acwrk, __itoklen);
3184    one_allbits_(__bcwrk, __itoklen);
3185    *blen = __itoklen;
3186    return;
3187   }
3188  /* do the conversion */
3189  wide_strtoverdec(*blen);
3190  /* finally, find real convert decimal number bit width by trimming */
3191  *blen = __trim1_0val(__acwrk, *blen);
3192 }
3193 
3194 /*
3195  * convert a string in __numtoken into a decimal number in acwrk that is known
3196  * to be wide enough (blen width)
3197  * know all digits in token are legal decimal digits
3198  */
wide_strtoverdec(int32 blen)3199 static void wide_strtoverdec(int32 blen)
3200 {
3201  register char *chp;
3202  word32 *reg10, *newdig, *acc;
3203  int32 wlen;
3204  struct xstk_t *xsp;
3205 
3206  wlen = wlen_(blen);
3207  push_xstk_(xsp, blen);
3208  /* build the constant 10 */
3209  reg10 = xsp->ap;
3210  memset(reg10, 0, wlen*WRDBYTES);
3211  reg10[0] = 10;
3212  /* and use b part to hold new digit to add */
3213  newdig = xsp->bp;
3214  memset(newdig, 0, wlen*WRDBYTES);
3215  push_xstk_(xsp, blen);
3216  acc = xsp->ap;
3217  memset(acc, 0, wlen*WRDBYTES);
3218 
3219  chp = __numtoken;
3220  __acwrk[0] = *chp - '0';
3221  /* notice start with high (left) digit */
3222  for (chp++; *chp != '\0'; chp++)
3223   {
3224    /* 10 times current value plus new digit */
3225    __lmult(acc, __acwrk, reg10, blen);
3226    newdig[0] = *chp - '0';
3227    __ladd(acc, acc, newdig, blen);
3228    /* notice the accumulator must be copied into ac wrk since lmult res */
3229    /* must be different value than u and v */
3230    memcpy(__acwrk, acc, wlen*WRDBYTES);
3231   }
3232  /* value now in acwrk */
3233  __pop_xstk();
3234  __pop_xstk();
3235 }
3236 
3237 /*
3238  * convert a number scanned token to binary in work string (acwrk and bcwrk)
3239  * input in token and token length set
3240  * know will fit and correct
3241  * notice caller know to have zerod __ac wrk and __bc wrk
3242  */
to_bin(int32 slen)3243 static void to_bin(int32 slen)
3244 {
3245  register int32 i;
3246  word32 a, b;
3247  int32 bi;
3248 
3249  /* fill val from low char (rght str) to high char (const left to rght) */
3250  for (i = slen - 1, bi = 0; i >= 0; i--, bi++)
3251   {
3252    ch_tobits(&a, &b, __numtoken[i]);
3253    __lhsbsel(__acwrk, bi, a);
3254    __lhsbsel(__bcwrk, bi, b);
3255   }
3256 }
3257 
3258 /*
3259  * convert binary plus z-x character to bit
3260  */
ch_tobits(word32 * ap,word32 * bp,int32 ch)3261 static int32 ch_tobits(word32 *ap, word32 *bp, int32 ch)
3262 {
3263  *ap = *bp = 0L;
3264  switch (ch) {
3265   case 'z': case 'Z': *bp = 1L; break;
3266   case 'x': case 'X': *ap = 1L; *bp = 1L; break;
3267   case '0': break;
3268   case '1': *ap = 1L; break;
3269   default: return(FALSE);
3270  }
3271  return(TRUE);
3272 }
3273 
3274 /*
3275  * convert a number scanned token to octal in work string (acwrk and bcwrk)
3276  * input in token and token length set
3277  * know will fit and __ac wrk and __bc wrk zeroed
3278  */
to_oct(int32 slen)3279 static void to_oct(int32 slen)
3280 {
3281  register int32 i, bi;
3282  word32 a, b;
3283 
3284  /* fill val from low char (rght str) to high char (const left to rght) */
3285  for (i = slen - 1, bi = 0; i >= 0; i--, bi += 3)
3286   {
3287    ch_toocts(&a, &b, __numtoken[i]);
3288    /* cant use literal shifts and mask because some octs split on boundary */
3289    __lhspsel(__acwrk, bi, &a, 3);
3290    __lhspsel(__bcwrk, bi, &b, 3);
3291   }
3292 }
3293 
3294 /*
3295  * convert octal digit plus z-x character to bit
3296  */
ch_toocts(word32 * ap,word32 * bp,int32 ch)3297 static int32 ch_toocts(word32 *ap, word32 *bp, int32 ch)
3298 {
3299  *ap = *bp = 0L;
3300  switch (ch) {
3301   case 'z': case 'Z': *bp = 0x7L; break;
3302   case 'x': case 'X': *ap = 0x7L; *bp = 0x7L; break;
3303   default:
3304    if (ch < '0' || ch > '7') return(FALSE);
3305    *ap = (word32) ((ch - '0') & 0x7L);
3306   }
3307  return(TRUE);
3308 }
3309 
3310 /*
3311  * convert number scanned token to hex in work string (__ac wrk and __bc wrk)
3312  * input in token and itoklen set
3313  * know will fit and know acwrk and bcwrk already zeroed
3314  * sets tokval or tokptr if > WBITS
3315  */
to_hex(int32 slen)3316 static void to_hex(int32 slen)
3317 {
3318  register int32 i, bi;
3319  register word32 *ap, *bp;
3320  word32 a, b;
3321 
3322  /* fill val from low char (right str) to high char (const left to right) */
3323  ap = __acwrk;
3324  bp = __bcwrk;
3325  for (i = slen - 1, bi = 0; i >= 0; i--)
3326   {
3327    /* know already checked for out of range before here */
3328    ch_tohexs(&a, &b, __numtoken[i]);
3329    if (bi == 0) { *ap = a; *bp = b; bi += 4; continue; }
3330    *ap |= a << bi;
3331    *bp |= b << bi;
3332    if (bi == 28) { bi = 0; ap++; bp++; } else bi += 4;
3333   }
3334 }
3335 
3336 /*
3337  * convert hex digit plus x and z to bit pattern
3338  */
ch_tohexs(word32 * ap,word32 * bp,int32 ch)3339 static int32 ch_tohexs(word32 *ap, word32 *bp, int32 ch)
3340 {
3341  *ap = *bp = 0L;
3342  switch (ch) {
3343   case 'z': case 'Z': *bp = 0xfL; break;
3344   case 'x': case 'X': *ap = 0xfL; *bp = 0xfL; break;
3345   default:
3346    if (ch >= '0' && ch <= '9')
3347     {
3348      *ap = (word32) ((ch - '0') & 0xfL);
3349      break;
3350     }
3351    if (isupper(ch)) ch = tolower(ch);
3352    if (ch >= 'a' && ch <= 'f')
3353     {
3354      *ap = (word32) ((10 + ch - 'a') & 0xfL);
3355      break;
3356     }
3357    /* should have already been caught */
3358    /* illegal 'h radix digit */
3359    return(FALSE);
3360   }
3361  return(TRUE);
3362 }
3363 
3364 /*
3365  * return T if source input number at wp of length srcblen wider
3366  * than __itoklen - if all high bits 0 returns F (not too wide)
3367  *
3368  * only called if srcblen > __itoklen
3369  * if too wide only because x or z hex or oct digit returns T here
3370  * but change to not too wide later
3371  */
vnum_toowide(word32 * wp,int32 srcblen)3372 static int32 vnum_toowide(word32 *wp, int32 srcblen)
3373 {
3374  register int32 i;
3375  int32 srcwlen, storwlen, storubits;
3376 
3377  srcwlen = wlen_(srcblen);
3378  storwlen = wlen_(__itoklen);
3379  storubits = ubits_(__itoklen);
3380  /* if high bits of high word32 from storage token length, too wide */
3381  if ((wp[storwlen - 1] & ~__masktab[storubits]) != 0L) return(TRUE);
3382  for (i = storwlen; i < srcwlen; i++) if (wp[i] != 0L) return(TRUE);
3383  return(FALSE);
3384 }
3385 
3386 /*
3387  * return T if high unused bits of high 4 bit nibble x or z
3388  * know shubits is aligned on 4 bit boundary and both in same word
3389  * know if all high bits 0 won't get here
3390  */
nibblexz(word32 aw,word32 bw,int32 srcblen)3391 static int32 nibblexz(word32 aw, word32 bw, int32 srcblen)
3392 {
3393  int32 itokubits;
3394  word32 tmp;
3395 
3396  /* know __itoklen has at least 1 high bit unused or will not get here */
3397  itokubits = ubits_(__itoklen);
3398  bw >>= itokubits;
3399  aw >>= itokubits;
3400  switch (srcblen - __itoklen) {
3401   case 1:
3402    /* notice this will shift so 1 extra bit is in low position not 8 pos. */
3403    if ((bw & 1L) == 0L) return(FALSE);
3404    break;
3405   case 2:
3406    /* if 2, b part bits are not 11 or a part 01 or 10 then not ok nibble */
3407    if ((bw & 3L) != 3L || ((tmp = aw & 3L) == 01L || tmp == 02L))
3408     return(FALSE);
3409    break;
3410   case 3:
3411    /* if 3 extra, b part bits 111 and a part not 000 or 111, not ok nibble */
3412    if ((bw & 7L) != 7L || ((tmp = aw & 7L) != 7L && tmp != 0L))
3413     return(FALSE);
3414    break;
3415   default: __case_terr(__FILE__, __LINE__);
3416  }
3417  return(TRUE);
3418 }
3419 
3420 /*
3421  * return T if high unused bits of high 3 bit nibble x or z
3422  */
octdigxz(word32 * ap,word32 * bp,int32 srcblen)3423 static int32 octdigxz(word32 *ap, word32 *bp, int32 srcblen)
3424 {
3425  word32 tmp, aw, bw;
3426 
3427  /* part select needed to isolate bits, oct can overlap word32 boundary */
3428  __rhspsel(&bw, bp, __itoklen - 1, 3);
3429  switch (srcblen - __itoklen) {
3430   case 1:
3431    if ((bw & 4L) != 0L) return(FALSE); break;
3432   case 2:
3433    if ((bw & 6L) != 6L) return(FALSE);
3434    __rhspsel(&aw, ap, __itoklen - 1, 3);
3435    /* for 2 bits must both be x aw=11? or z aw=00? */
3436    /* not a high x/z if 010 or 100 after masking */
3437    if ((tmp = aw & 6L) == 2L || tmp == 4L) return(FALSE);
3438    break;
3439   default: __case_terr(__FILE__, __LINE__);
3440  }
3441  return(TRUE);
3442 }
3443 
3444 /*
3445  * widen a shorter value into a longer value in place (either a or b)
3446  * highval determines kind of ext. (0 = 0, 1 = 1)
3447  * do not know what is in higher values
3448  * know valwp wide enough
3449  */
widen_val(word32 * vwp,int32 lngblen,int32 shblen,word32 highval)3450 static void widen_val(word32 *vwp, int32 lngblen, int32 shblen, word32 highval)
3451 {
3452  register int32 i;
3453  register word32 *wp;
3454  word32 mask;
3455  int32 shwlen, shubits, lngwlen, lngubits;
3456 
3457  shwlen = wlen_(shblen);
3458  shubits = ubits_(shblen);
3459  lngwlen = wlen_(lngblen);
3460  lngubits = ubits_(lngblen);
3461  /* first extend unused part of old short high word32 */
3462  if (shubits != 0)
3463   {
3464    mask = __masktab[shubits];
3465    vwp[shwlen - 1] &= mask;
3466    if (highval == 1L) vwp[shwlen - 1] |= ~mask;
3467   }
3468  /* done if widen up to max of WBITS or words same length */
3469  if (lngwlen == 1 || lngwlen == shwlen) goto done;
3470 
3471  /* next set all higher words to highval */
3472  if (highval == 0L) memset(&(vwp[shwlen]), 0, WRDBYTES*(lngwlen - shwlen));
3473  else
3474   {
3475    /* notice if incing wp cannot use indexed later */
3476    for (i = shwlen, wp = &(vwp[shwlen]); i < lngwlen; i++) *wp++ = ALL1W;
3477   }
3478 
3479 done:
3480  /* finally zero unused portion of high word32 */
3481  vwp[lngwlen - 1] &= __masktab[lngubits];
3482 }
3483 
3484 /*
3485  * MISC. TOKEN HANDLING ROUTINES
3486  */
3487 
3488 /*
3489  * version of print vtoken where value is not in global _toktyp
3490  * for use inside get token routines
3491  */
prt2_vtok(int32 ttyp)3492 static char *prt2_vtok(int32 ttyp)
3493 {
3494  int32 save_ttyp;
3495  char *chp;
3496 
3497  save_ttyp = __toktyp;
3498  __toktyp = ttyp;
3499  chp = __prt_vtok();
3500  __toktyp = save_ttyp;
3501  return(chp);
3502 }
3503 
3504 /*
3505  * print a token for error messages - indicate token is a keyword for msg
3506  *
3507  */
__prt_kywrd_vtok(void)3508 extern char *__prt_kywrd_vtok(void)
3509 {
3510  char s1[RECLEN];
3511 
3512  if (get_vkeywrd(__token) != ID)
3513   {
3514    /* know pv varnam always has enough room for keyword */
3515    sprintf(s1, "Verilog keyword: %s",  __prt_vtok());
3516    strcpy(__pv_varnam, s1);
3517    return(__pv_varnam);
3518   }
3519  return(__prt_vtok());
3520 }
3521 
3522 /*
3523  * print the value of a token
3524  * only for current token (i.e. moves punct./op. to token)
3525  * i.e. typ cannot be old
3526  */
__prt_vtok(void)3527 extern char *__prt_vtok(void)
3528 {
3529  /* notice this must not change current val. of token */
3530  if (__toktyp >= BKEYS)
3531   { __get_vkeynam(__pv_varnam, __toktyp); return(__pv_varnam); }
3532 
3533  switch ((byte) __toktyp) {
3534   case TEOF:
3535    if (__run_state == SS_SIM && __cmd_s == NULL) strcpy(__token, "**EOL**");
3536    else strcpy(__token, "**EOF**");
3537    break;
3538   case ID: return(__token);
3539   case NUMBER: return(__numtoken);
3540   case REALNUM: sprintf(__token, "%#g",  __itok_realval); break;
3541   case LITSTR: return(__strtoken);
3542   case SEMI: strcpy(__token, ";"); break;
3543   case COMMA: strcpy(__token, ","); break;
3544   case COLON: strcpy(__token, ":"); break;
3545   case SHARP: strcpy(__token, "#"); break;
3546   case LPAR: strcpy(__token, "("); break;
3547   case RPAR: strcpy(__token, ")"); break;
3548   case LSB: strcpy(__token, "["); break;
3549   case RSB: strcpy(__token, "]"); break;
3550   case LCB: strcpy(__token, "{"); break;
3551   case RCB: strcpy(__token, "}"); break;
3552   case DOT: strcpy(__token, "."); break;
3553   case QUEST: strcpy(__token, "?"); break;
3554   case AT: strcpy(__token, "@"); break;
3555   case CAUSE: strcpy(__token, "->"); break;
3556   case PLUS: strcpy(__token, "+"); break;
3557   case MINUS: strcpy(__token, "-"); break;
3558   case TIMES: strcpy(__token, "*"); break;
3559   case DIV: strcpy(__token, "/"); break;
3560   case MOD: strcpy(__token, "%"); break;
3561   case BITNOT: strcpy(__token, "~"); break;
3562   case BITREDAND: strcpy(__token, "&"); break;
3563   case BITREDOR: strcpy(__token, "|"); break;
3564   case BITREDXOR: strcpy(__token, "^"); break;
3565   /* notice ~ ^ are 2 unary operators */
3566   case REDXNOR: strcpy(__token, "^~"); break;
3567   case RELGE: strcpy(__token, ">="); break;
3568   case RELGT: strcpy(__token, ">"); break;
3569   case RELLE: strcpy(__token, "<="); break;
3570   case RELLT: strcpy(__token, "<"); break;
3571   case RELCEQ: strcpy(__token, "==="); break;
3572   case RELEQ: strcpy(__token, "=="); break;
3573   case RELCNEQ: strcpy(__token, "!=="); break;
3574   case RELNEQ: strcpy(__token, "!="); break;
3575   case BOOLAND: strcpy(__token, "&&"); break;
3576   case BOOLOR: strcpy(__token, "||"); break;
3577   case NOT: strcpy(__token, "!"); break;
3578   case SHIFTL: strcpy(__token, "<<"); break;
3579   case ASHIFTL: strcpy(__token, "<<<"); break;
3580   case SHIFTR: strcpy(__token, ">>"); break;
3581   case ASHIFTR: strcpy(__token, ">>>"); break;
3582   case EQ: strcpy(__token, "="); break;
3583   case FPTHCON: strcpy(__token, "*>"); break;
3584   case PPTHCON: strcpy(__token, "=>"); break;
3585   case TCHKEVAND: strcpy(__token, "&&&"); break;
3586   case UNDEF: strcpy(__token, "**NONE**"); break;
3587   default: __case_terr(__FILE__, __LINE__);
3588  }
3589  return(__token);
3590 }
3591 
3592 /*
3593  * convert a punct./operator token to a name
3594  * only for current token (i.e. moves punct./op. to token)
3595  * non expression token removed when tree built but included here
3596  * result
3597  */
__to_opname(word32 otyp)3598 extern char *__to_opname(word32 otyp)
3599 {
3600  /* token number %d illegal in expression */
3601  if (otyp > TEOF) __misc_fterr(__FILE__, __LINE__);
3602  return(__opinfo[otyp].opnam);
3603 }
3604 
3605 /* note! - must be kept in alphabetical order */
3606 /* keyword types (already know token is a name) */
3607 /* making as many things as possible Verilog since they are reserved */
3608 struct vkeywds_t {
3609  char *vknam;
3610  int32 vknum;
3611 };
3612 
3613 static struct vkeywds_t vkeywds[] = {
3614  { "`accelerate", CDIR_ACCEL },
3615  { "`autoexpand_vectornets", CDIR_AEXPVECNETS },
3616  { "`celldefine", CDIR_CELLDEF },
3617  { "`default_decay_time", CDIR_DFLTDECAYTIME },
3618  { "`default_nettype", CDIR_DFLNTYP },
3619  { "`default_trireg_strength", CDIR_DFLTTRIREGSTREN },
3620  { "`define", CDIR_DEFINE },
3621  { "`delay_mode_distributed", CDIR_DELMODEDIST },
3622  { "`delay_mode_path", CDIR_DELMODEPATH },
3623  { "`delay_mode_unit", CDIR_DELMODEUNIT },
3624  { "`delay_mode_zero", CDIR_DELMODEZERO },
3625  { "`else", CDIR_ELSE },
3626  { "`endcelldefine", CDIR_ECELLDEF },
3627  { "`endif", CDIR_ENDIF },
3628  { "`endprotect", CDIR_ENDPROTECT },
3629  { "`endprotected", CDIR_ENDPROTECTED },
3630  { "`expand_vectornets", CDIR_XPNDVNETS },
3631  { "`ifdef", CDIR_IFDEF },
3632  { "`ifndef", CDIR_IFNDEF },
3633  { "`include", CDIR_INCLUDE },
3634  { "`language", CDIR_LANG },
3635  { "`noaccelerate", CDIR_NOACCEL },
3636  { "`noexpand_vectornets", CDIR_NOXPNDVNETS },
3637  { "`noremove_gatenames", CDIR_NOREMGATENAMES },
3638  { "`noremove_netnames", CDIR_NOREMNETNAMES },
3639  { "`nounconnected_drive", CDIR_NOUNCONNDRIVE },
3640  { "`protect", CDIR_PROTECT },
3641  { "`protected", CDIR_PROTECTED },
3642  { "`remove_gatenames", CDIR_REMGATESNAMES },
3643  { "`remove_netnames", CDIR_REMNETNAMES },
3644  { "`resetall", CDIR_RESETALL },
3645  { "`timescale", CDIR_TIMESCALE },
3646  { "`unconnected_drive", CDIR_UNCONNDRIVE },
3647  { "`undef", CDIR_UNDEF },
3648 
3649  { "always", ALWAYS },
3650  { "assign", ASSIGN },
3651  { "begin", Begin },
3652  { "case", CASE },
3653  { "casex", CASEX },
3654  { "casez", CASEZ },
3655  { "deassign", DEASSIGN },
3656  { "default", DEFAULT },
3657  { "defparam", DEFPARAM },
3658  { "disable", DISABLE },
3659  { "edge", EDGE },
3660  { "else", ELSE },
3661  { "end", END },
3662  { "endcase", ENDCASE },
3663  { "endfunction", ENDFUNCTION },
3664  { "endgenerate", ENDGENERATE },
3665  { "endmodule", ENDMODULE },
3666  { "endprimitive", ENDPRIMITIVE },
3667  { "endspecify", ENDSPECIFY },
3668  { "endtable", ENDTABLE },
3669  { "endtask", ENDTASK },
3670  { "event", EVENT },
3671  { "for", FOR },
3672  { "force", FORCE },
3673  { "forever", FOREVER },
3674  { "fork", FORK },
3675  { "function", FUNCTION },
3676  { "generate", GENERATE },
3677  { "highz0", HIGHZ0 },
3678  { "highz1", HIGHZ1 },
3679  { "if", IF },
3680  { "ifnone", IFNONE },
3681  { "initial", INITial },
3682  { "inout", INOUT },
3683  { "input", INPUT },
3684  /* not int32 */
3685  { "integer", INTEGER },
3686  { "join", JOIN },
3687  { "large", LARGE },
3688  { "localparam", LOCALPARAM },
3689  { "macromodule", MACROMODULE },
3690  { "medium", MEDIUM },
3691  { "module", MODULE },
3692  { "negedge", NEGEDGE },
3693  { "output", OUTPUT },
3694  { "parameter", PARAMETER },
3695  { "posedge", POSEDGE },
3696  { "primitive", PRIMITIVE },
3697  { "pull0", PULL0 },
3698  { "pull1", PULL1 },
3699  { "real", REAL },
3700  { "realtime", REALTIME },
3701  { "reg", REG },
3702  { "release", RELEASE },
3703  { "repeat", REPEAT },
3704  { "scalared", SCALARED },
3705  { "signed", SIGNED },
3706  { "small", SMALL },
3707  { "specify", SPECIFY },
3708  { "specparam", SPECPARAM },
3709  { "strength", Strength },
3710  { "strong0", STRONG0 },
3711  { "strong1", STRONG1 },
3712  { "supply0", SUPPLY0 },
3713  { "supply1", SUPPLY1 },
3714  { "table", TABLE },
3715  { "task", TASK },
3716  { "time", TIME },
3717  { "tri", TRI },
3718  { "tri0", TRI0 },
3719  { "tri1", TRI1 },
3720  { "triand", TRIAND },
3721  { "trior", TRIOR },
3722  { "trireg", TRIREG },
3723  { "vectored", VECTORED },
3724  { "wait", WAIT },
3725  { "wand", WAND },
3726  { "weak0", WEAK0 },
3727  { "weak1", WEAK1 },
3728  { "while", WHILE },
3729  { "wire", WIRE },
3730  { "wor", WOR }
3731 };
3732 #define NVKEYWDS (sizeof(vkeywds) / sizeof(struct vkeywds_t))
3733 
3734 /*
3735  * determine type of keyword or ident
3736  * binary search because the table is so big
3737  */
get_vkeywrd(register char * tstr)3738 static int32 get_vkeywrd(register char *tstr)
3739 {
3740  int32 l, h;
3741  register int32 m, cv;
3742 
3743  l = 0; h = NVKEYWDS - 1;
3744  for (;;)
3745   {
3746    m = (l + h)/2;
3747    if ((cv = strcmp(vkeywds[m].vknam, tstr)) == 0) return(vkeywds[m].vknum);
3748    if (cv < 0) l = m + 1; else h = m - 1;
3749    if (h < l) break;
3750   }
3751  return(ID);
3752 }
3753 
3754 /*
3755  * determine keyword name from number
3756  * must use linear search since not sorted
3757  */
__get_vkeynam(char * s,int32 knum)3758 extern char *__get_vkeynam(char *s, int32 knum)
3759 {
3760  register int32 vi;
3761 
3762  for (vi = 0; vi < NVKEYWDS; vi++)
3763   {
3764    if (vkeywds[vi].vknum == knum)
3765    {
3766     strcpy(s, vkeywds[vi].vknam);
3767     return(s);
3768    }
3769   }
3770  strcpy(s, "--none--");
3771  return(s);
3772 }
3773 
3774 /*
3775  * ROUTINES FOR RESYNCING AFTER ERROR
3776  */
3777 
3778 /*
3779  * skip to symbol - if not found only end module/primitive ends
3780  * rest of module not checked
3781  * return T if found targ1 else F
3782  */
__vskipto_modend(int32 targ1)3783 extern int32 __vskipto_modend(int32 targ1)
3784 {
3785  int32 sav_letendnum;
3786 
3787  /* SJM 11/30/04 - save and restore edge illegal num errors when skip mod */
3788  sav_letendnum = __letendnum_state;
3789  __letendnum_state = TRUE;
3790  for (;;)
3791   {
3792    if (__toktyp == targ1)
3793     {
3794      __letendnum_state = sav_letendnum;
3795      return(TRUE);
3796     }
3797    switch ((byte) __toktyp) {
3798     case ENDMODULE: case ENDPRIMITIVE:
3799      goto done;
3800     case PRIMITIVE: case MODULE: case MACROMODULE:
3801      __unget_vtok(); goto done;
3802    }
3803    if (__toktyp == TEOF)
3804     __fterr(315, "unexpected EOF while skipping to %s", prt2_vtok(targ1));
3805    __get_vtok();
3806   }
3807 done:
3808  __letendnum_state = sav_letendnum;
3809  return(FALSE);
3810 }
3811 
3812 /*
3813  * skip to 2 symbols - if not found only end module/primitive ends
3814  * rest of module not checked
3815  * return T if found targ1 else F
3816  */
__vskipto2_modend(int32 targ1,int32 targ2)3817 extern int32 __vskipto2_modend(int32 targ1, int32 targ2)
3818 {
3819  int32 sav_letendnum;
3820 
3821  /* SJM 11/30/04 - save and restore edge illegal num errors when skip mod */
3822  sav_letendnum = __letendnum_state;
3823  __letendnum_state = TRUE;
3824  for (;;)
3825   {
3826    if (__toktyp == targ1 || __toktyp == targ2)
3827     {
3828      __letendnum_state = sav_letendnum;
3829      return(TRUE);
3830     }
3831    switch ((byte) __toktyp) {
3832     case ENDMODULE: case ENDPRIMITIVE:
3833      goto done;
3834     case PRIMITIVE: case MODULE: case MACROMODULE:
3835     __unget_vtok();
3836     goto done;
3837    }
3838    if (__toktyp == TEOF)
3839     __fterr(315, "unexpected EOF while skipping to %s", prt2_vtok(targ1));
3840    __get_vtok();
3841   }
3842 done:
3843  __letendnum_state = sav_letendnum;
3844  return(FALSE);
3845 }
3846 
3847 /*
3848  * skip to 3 symbols - if not found only end module/primitive ends
3849  * est of module not checked
3850  * return T if found targ1 else F
3851  */
__vskipto3_modend(int32 targ1,int32 targ2,int32 targ3)3852 extern int32 __vskipto3_modend(int32 targ1, int32 targ2, int32 targ3)
3853 {
3854  int32 sav_letendnum;
3855 
3856  /* SJM 11/30/04 - save and restore edge illegal num errors when skip mod */
3857  sav_letendnum = __letendnum_state;
3858  __letendnum_state = TRUE;
3859  for (;;)
3860   {
3861    if (__toktyp == targ1 || __toktyp == targ2 || __toktyp == targ3)
3862     {
3863      __letendnum_state = sav_letendnum;
3864      return(TRUE);
3865     }
3866    switch ((byte) __toktyp) {
3867     case ENDMODULE: case ENDPRIMITIVE:
3868      goto done;
3869     case PRIMITIVE: case MODULE: case MACROMODULE:
3870      __unget_vtok();
3871      goto done;
3872    }
3873    if (__toktyp == TEOF)
3874     __fterr(315, "unexpected EOF while skipping to %s", prt2_vtok(targ1));
3875    __get_vtok();
3876   }
3877 done:
3878  __letendnum_state = sav_letendnum;
3879  return(FALSE);
3880 }
3881 
3882 /*
3883  * skip to any start of stmt/item symbol
3884  * general sync algorithm.
3885  *
3886  * if finds specific thing, return T
3887  * else sets syncto_class and return F
3888  *
3889  * possibilities are:
3890  *   SYNC_FLEVEL - file level mod/prim
3891  *   SYNC_MODLEVEL - module level declaration or item
3892  *   SYNC_STMT - start of statement
3893  *   SYNC_TARG - target found and return T
3894  */
__vskipto_any(int32 targ1)3895 extern int32 __vskipto_any(int32 targ1)
3896 {
3897  /* for interactive just give up on any error - but must skip to end of line */
3898  if (__iact_state) longjmp(__iact_jmpbuf, 1);
3899 
3900  for (;;)
3901   {
3902    if (__toktyp == targ1) { __syncto_class = SYNC_TARG; return(TRUE); }
3903    if (set_syncto_tokclass((byte) __toktyp)) break;
3904    if (__toktyp == TEOF)
3905     __fterr(315, "unexpected EOF while skipping to statement token %s",
3906      prt2_vtok(targ1));
3907    __get_vtok();
3908   }
3909  return(FALSE);
3910 }
3911 
__vskipto2_any(int32 targ1,int32 targ2)3912 extern int32 __vskipto2_any(int32 targ1, int32 targ2)
3913 {
3914  if (__iact_state) longjmp(__iact_jmpbuf, 1);
3915  for (;;)
3916   {
3917    if (__toktyp == targ1 || __toktyp == targ2)
3918     { __syncto_class = SYNC_TARG; return(TRUE); }
3919    if (set_syncto_tokclass((byte) __toktyp)) break;
3920    if (__toktyp == TEOF)
3921     __fterr(315, "unexpected EOF while skipping to statement token %s",
3922      prt2_vtok(targ1));
3923    __get_vtok();
3924   }
3925  return(FALSE);
3926 }
3927 
__vskipto3_any(int32 targ1,int32 targ2,int32 targ3)3928 extern int32 __vskipto3_any(int32 targ1, int32 targ2, int32 targ3)
3929 {
3930  if (__iact_state) longjmp(__iact_jmpbuf, 1);
3931  for (;;)
3932   {
3933    if (__toktyp == targ1 || __toktyp == targ2 || __toktyp == targ3)
3934     { __syncto_class = SYNC_TARG; return(TRUE); }
3935    if (set_syncto_tokclass((byte) __toktyp)) break;
3936    if (__toktyp == TEOF)
3937     __fterr(315, "unexpected EOF while skipping to statement token %s",
3938      prt2_vtok(targ1));
3939    __get_vtok();
3940   }
3941  return(FALSE);
3942 }
3943 
__vskipto4_any(int32 targ1,int32 targ2,int32 targ3,int32 targ4)3944 extern int32 __vskipto4_any(int32 targ1, int32 targ2, int32 targ3, int32 targ4)
3945 {
3946  if (__iact_state) longjmp(__iact_jmpbuf, 1);
3947  for (;;)
3948   {
3949    if (__toktyp == targ1 || __toktyp == targ2 || __toktyp == targ3
3950     || __toktyp == targ4)
3951     { __syncto_class = SYNC_TARG; return(TRUE); }
3952    if (set_syncto_tokclass((byte) __toktyp)) break;
3953    if (__toktyp == TEOF)
3954     __fterr(315, "unexpected EOF while skipping to statement token %s",
3955      prt2_vtok(targ1));
3956    __get_vtok();
3957   }
3958  return(FALSE);
3959 }
3960 
3961 /*
3962  * skip to end of list of port port decl element
3963  *
3964  * special case because resyncs at port name keyword ID
3965  * notice can't be used for new list of parameters form
3966  */
__vskipto_lofp_end()3967 extern int32 __vskipto_lofp_end()
3968 {
3969  /* only for list of ports decl so can't be invoked from iact state */
3970  if (__iact_state) __misc_terr(__FILE__, __LINE__);
3971 
3972  for (;;)
3973   {
3974    /* semi can end because end of list ) always followed by ; */
3975    if (__toktyp == INPUT || __toktyp == OUTPUT || __toktyp == INOUT
3976     || __toktyp == RPAR || __toktyp == SEMI)
3977     { __syncto_class = SYNC_TARG; return(TRUE); }
3978    if (set_syncto_tokclass((byte) __toktyp)) break;
3979    if (__toktyp == TEOF)
3980     __fterr(315,
3981      "unexpected EOF while skipping over list of port declaration");
3982    __get_vtok();
3983   }
3984  return(FALSE);
3985 }
3986 
3987 /*
3988  * skip to end of list of port port decl element from inside port name comma
3989  * list
3990  *
3991  * special case because resyncs at port name keyword ID
3992  * notice can't be used for new list of parameters form
3993  */
__vskipto2_lofp_end()3994 extern int32 __vskipto2_lofp_end()
3995 {
3996  /* only for list of ports decl so can't be invoked from iact state */
3997  if (__iact_state) __misc_terr(__FILE__, __LINE__);
3998 
3999  for (;;)
4000   {
4001    /* semi can end because end of list ) always followed by ; */
4002    if (__toktyp == INPUT || __toktyp == OUTPUT || __toktyp == INOUT
4003     || __toktyp == RPAR || __toktyp == SEMI || __toktyp == COMMA)
4004     { __syncto_class = SYNC_TARG; return(TRUE); }
4005 
4006    if (set_syncto_tokclass((byte) __toktyp)) break;
4007 
4008    if (__toktyp == TEOF)
4009     __fterr(315,
4010      "unexpected EOF while skipping over list of port declaration");
4011    __get_vtok();
4012   }
4013  return(FALSE);
4014 }
4015 
4016 /*
4017  * set __token class - return T if not a sync to
4018  */
set_syncto_tokclass(byte ttyp)4019 static int32 set_syncto_tokclass(byte ttyp)
4020 {
4021  switch (ttyp) {
4022   /* file level item */
4023   case ENDMODULE: case ENDPRIMITIVE:
4024    __syncto_class = SYNC_FLEVEL;
4025    break;
4026   case PRIMITIVE: case MODULE: case MACROMODULE:
4027    __unget_vtok();
4028    __syncto_class = SYNC_FLEVEL;
4029    break;
4030   /* module item end - must assume next things is good item */
4031   /* because [id] [type](inst) is common */
4032   case ENDFUNCTION: case ENDTASK: case ENDSPECIFY:
4033    __syncto_class = SYNC_MODLEVEL;
4034    break;
4035   case INITial: case ALWAYS:
4036   case DEFPARAM: case SPECIFY: case TASK: case FUNCTION:
4037   case PARAMETER: case LOCALPARAM: case ASSIGN:
4038   case INPUT: case OUTPUT: case INOUT:
4039   case WIRE: case TRI: case TRI0: case TRI1: case TRIAND:
4040   case TRIOR: case TRIREG: case WAND: case WOR: case SUPPLY0:
4041   case SUPPLY1: case REG: case INTEGER: case TIME: case REAL: case REALTIME:
4042   case EVENT:
4043    __unget_vtok();
4044    __syncto_class = SYNC_MODLEVEL;
4045    break;
4046   /* stmt begin things - sync so next get tok will be stmt start */
4047   /* these are likely module item previous ends and assume so */
4048   /* but could be part of wrong list of stmts */
4049   /* SJM 01/14/1999 - moved else from statement start case to stmt end */
4050   /* LOOKATME - is there a problem with this? */
4051   case END: case JOIN: case ENDCASE: case ELSE:
4052    __syncto_class = SYNC_STMT;
4053    break;
4054   case SHARP: case AT:
4055   case IF: case IFNONE: case CASE: case CASEX: case CASEZ:
4056   case Begin: case FORK: case CAUSE:
4057   case FOREVER: case REPEAT: case WHILE: case FOR: case WAIT:
4058   case DISABLE: case FORCE: case RELEASE:
4059    __unget_vtok();
4060    __syncto_class = SYNC_STMT;
4061    break;
4062   default: return(FALSE);
4063  }
4064  return(TRUE);
4065 }
4066 
4067 /*
4068  * for specify normal skip to any except also specify item level
4069  */
__spec_vskipto_any(int32 targ1)4070 extern int32 __spec_vskipto_any(int32 targ1)
4071 {
4072  for (;;)
4073   {
4074    if (__toktyp == targ1) { __syncto_class = SYNC_TARG; return(TRUE); }
4075    if (set_syncto_tokclass((byte) __toktyp))
4076     {
4077      if (__toktyp == IF) __syncto_class = SYNC_SPECITEM;
4078      break;
4079     }
4080    if (set_specitem_class()) break;
4081    if (__toktyp == TEOF)
4082     __fterr(315, "unexpected EOF while skipping to statement token %s",
4083      prt2_vtok(targ1));
4084    __get_vtok();
4085   }
4086  return(FALSE);
4087 }
4088 
__spec_vskipto2_any(int32 targ1,int32 targ2)4089 extern int32 __spec_vskipto2_any(int32 targ1, int32 targ2)
4090 {
4091  for (;;)
4092   {
4093    if (__toktyp == targ1 || __toktyp == targ2)
4094     { __syncto_class = SYNC_TARG; return(TRUE); }
4095    if (set_syncto_tokclass((byte) __toktyp))
4096     {
4097      if (__toktyp == IF) __syncto_class = SYNC_SPECITEM;
4098      break;
4099     }
4100    if (set_specitem_class()) break;
4101    if (__toktyp == TEOF)
4102     __fterr(315, "unexpected EOF while skipping to statement token %s",
4103      prt2_vtok(targ1));
4104    __get_vtok();
4105   }
4106  return(FALSE);
4107 }
4108 
__spec_vskipto3_any(int32 targ1,int32 targ2,int32 targ3)4109 extern int32 __spec_vskipto3_any(int32 targ1, int32 targ2, int32 targ3)
4110 {
4111  for (;;)
4112   {
4113    if (__toktyp == targ1 || __toktyp == targ2 || __toktyp == targ3)
4114     { __syncto_class = SYNC_TARG; return(TRUE); }
4115    if (set_syncto_tokclass((byte) __toktyp))
4116     {
4117      if (__toktyp == IF) __syncto_class = SYNC_SPECITEM;
4118      break;
4119     }
4120    if (set_specitem_class()) break;
4121    if (__toktyp == TEOF)
4122     __fterr(315, "unexpected EOF while skipping to statement token %s",
4123      prt2_vtok(targ1));
4124    __get_vtok();
4125   }
4126  return(FALSE);
4127 }
4128 
4129 /*
4130  * set specify level for token that can begin specify section
4131  * returns T if found sync to place
4132  * this needs to access global toktyp and token
4133  * notice - cannot sync to most common ( for path start
4134  */
set_specitem_class(void)4135 static int32 set_specitem_class(void)
4136 {
4137  if (__toktyp == ID && *__token == '$')
4138   {
4139    if (__fr_tcnam(__token) != -1)
4140     {
4141      __unget_vtok();
4142      __syncto_class = SYNC_SPECITEM;
4143      return(TRUE);
4144     }
4145   }
4146  return(FALSE);
4147 }
4148 
4149 /*
4150  * skip to udp symbol
4151  */
4152 /*
4153  * skip to udp symbol -
4154  * return T if found targ1 else F
4155  */
__udp_vskipto_any(int32 targ1)4156 extern int32 __udp_vskipto_any(int32 targ1)
4157 {
4158  for (;;)
4159   {
4160    if (__toktyp == targ1) { __syncto_class = SYNC_TARG; return(TRUE); }
4161    if (set_udpsyncto((byte) __toktyp)) break;
4162    if (__toktyp == TEOF)
4163     __fterr(315, "unexpected EOF while skipping to %s", prt2_vtok(targ1));
4164    __get_vtok();
4165   }
4166  return(FALSE);
4167 }
4168 
__udp_vskipto2_any(int32 targ1,int32 targ2)4169 extern int32 __udp_vskipto2_any(int32 targ1, int32 targ2)
4170 {
4171  for (;;)
4172   {
4173    if (__toktyp == targ1 || __toktyp == targ2)
4174     { __syncto_class = SYNC_TARG; return(TRUE); }
4175    if (set_udpsyncto((byte) __toktyp)) break;
4176    if (__toktyp == TEOF)
4177     __fterr(315, "unexpected EOF while skipping to %s", prt2_vtok(targ1));
4178    __get_vtok();
4179   }
4180  return(FALSE);
4181 }
4182 
__udp_vskipto3_any(int32 targ1,int32 targ2,int32 targ3)4183 extern int32 __udp_vskipto3_any(int32 targ1, int32 targ2, int32 targ3)
4184 {
4185  for (;;)
4186   {
4187    if (__toktyp == targ1 || __toktyp == targ2 || __toktyp == targ3)
4188     { __syncto_class = SYNC_TARG; return(TRUE); }
4189    if (set_udpsyncto((byte) __toktyp)) break;
4190    if (__toktyp == TEOF)
4191     __fterr(315, "unexpected EOF while skipping to %s", prt2_vtok(targ1));
4192    __get_vtok();
4193   }
4194  return(FALSE);
4195 }
4196 
4197 /*
4198  * set udp token class - return T if token not a sync to
4199  */
set_udpsyncto(byte ttyp)4200 static int32 set_udpsyncto(byte ttyp)
4201 {
4202  switch (ttyp) {
4203   /* file level item */
4204   case ENDMODULE: case ENDPRIMITIVE:
4205    __syncto_class = SYNC_FLEVEL;
4206    break;
4207   case PRIMITIVE: case MODULE: case MACROMODULE:
4208    __unget_vtok();
4209    __syncto_class = SYNC_FLEVEL;
4210    break;
4211  case INPUT: case OUTPUT: case REG: case TABLE:
4212    __unget_vtok();
4213    __syncto_class = SYNC_UDPLEVEL;
4214    break;
4215   default: return(FALSE);
4216  }
4217  return(TRUE);
4218 }
4219 
4220 /*
4221  *  LIB. INPUT ROUTINES
4222  *  BEWARE - must open file, use all, close file before using other get func.
4223  */
4224 
4225 /*
4226  * ascii character table for processing ID tokens
4227  * 0 - continue, 1 - end and don't back up, 2 - end and back up
4228  * notice here any non white space contiguous chars good since can be path
4229  */
4230 static char __lbctab[128] = {
4231  0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 1, 0, 0,  /* ^i,\n,\f \r */
4232  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4233  1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* sp */
4234  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4235  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4236  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4237  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4238  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2   /* eof */
4239 };
4240 
4241 /*
4242  * get a -f file option token - only white space and semi separation
4243  * (modified from yylex in "The Unix Programming Environment" p. 337)
4244  * notice no push back token here
4245  * also handles normal / * and // comments
4246  */
__get_cmdtok(FILE * f)4247 extern int32 __get_cmdtok(FILE *f)
4248 {
4249  /* the char must be an int32 for machine independence */
4250  register int32 c;
4251  register char *cp;
4252  int32 namlen;
4253 
4254 again:
4255  while ((c = getc(f)) == ' ' || c == '\t' || c == '\f' || c == '\r') ;
4256  /* SJM 12/06/03 - only new line needs line cnt inc and pushed back */
4257  if (c == '\n') { __lin_cnt++; goto again; }
4258 
4259  /* // or / * comments legal */
4260  if (c == '/') if (get_cmdcomment(f)) goto again;
4261 
4262  /* get here by falling through case */
4263  for (cp = __token, namlen = 0;;)
4264   {
4265    if (++namlen >= IDCHARS - 1)
4266     __pv_ferr(919,
4267      "command option token too long (%d) - ignored", IDCHARS - 1);
4268 
4269    *cp++ = c;
4270    if ((c = getc(f)) == EOF) return(TEOF);
4271    switch (__lbctab[c & 0x7f]) {
4272     case 0: continue;         /* normal in ID char */
4273     case 1: goto end_nam;     /* white space token end - swallow it */
4274     /* or lin_cnt wrong for errors */
4275     case 2: ungetc(c, f); goto end_nam; /* non white space end token */
4276    }
4277   }
4278 end_nam:
4279  *cp = '\0';
4280  /* does not need canonical token since not related to output */
4281  /* Verilog world options are case sensitive */
4282  return(ID);
4283 }
4284 
4285 /*
4286  * ascii character table for processing config tokens
4287  * 0 - continue, 1 - end and don't back up, 2 - end and back up
4288  * notice here any non white space contiguous chars good since can be path
4289  */
4290 static char cfgctab[128] = {
4291  0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 1, 0, 0,  /* ^i,\n,\f \r */
4292  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4293  1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,  /* sp, , */
4294  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0,  /* ; */
4295  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4296  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4297  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4298  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2   /* eof */
4299 };
4300 
4301 /*
4302  * get a cfg -L or default map.lib file token
4303  * (modified from yylex in "The Unix Programming Environment" p. 337)
4304  * AIV 10/30/03 - added for new 2001 cfg feature
4305  *
4306  * notice no push back token here and tok typ glb not set
4307  * also handles normal / * and // comments
4308  *
4309  * allowing ' and " quotes and back slash escaping of quotes in quoted
4310  * strings but not allowing embedded new lines in tokens
4311  *
4312  * complicated because need warnings and must handle quoting and
4313  * escaping but only within quoted names
4314  */
__get_cfgtok(FILE * f)4315 extern int32 __get_cfgtok(FILE *f)
4316 {
4317  /* the char must be an int32 for machine independence */
4318  register int32 c;
4319  register char *cp;
4320  int32 namlen, ttyp, qchar;
4321 
4322 again:
4323  while ((c = getc(f)) == ' ' || c == '\t' || c == '\f' || c == '\r') ;
4324  /* SJM 12/06/03 - only new line needs line cnt inc and pushed back */
4325  if (c == '\n') { __lin_cnt++; goto again; }
4326  /* AIV since push back ; if ';' */
4327  if (c == ';') return(CFG_SEMI);
4328  if (c == ',') return(CFG_COMMA);
4329  /* // or / * comments legal */
4330  if (c == '/') if (get_cmdcomment(f)) goto again;
4331 
4332  if (c == '\'' || c == '"')
4333   {
4334    qchar = c;
4335    c = getc(f);
4336    /* get here by falling through case */
4337    for (cp = __token, namlen = 0;;)
4338     {
4339      if (++namlen >= IDCHARS - 1)
4340       {
4341        __pv_ferr(919,
4342         "config file token (path?) too long (%d) - rest discarded",
4343         IDCHARS - 1);
4344        for (;;)
4345         {
4346          if (c == '\\') { c = getc(f); continue; }
4347          if (c == qchar) break;
4348          if (c == EOF) return(CFG_EOF);
4349          c = getc(f);
4350         }
4351        *cp = '\0';
4352        return(CFG_ID);
4353       }
4354      /* escaped chars legal but only in quoted strings */
4355      if (c == '\\')
4356       {
4357        c = getc(f);
4358        if (c == EOF) return(CFG_EOF);
4359        *cp++ = c;
4360       }
4361      else
4362       {
4363        /* ending quote not part of ID and can't be key word32 */
4364        if (c == qchar)
4365         {
4366          if (strcmp(__token, "") == 0)
4367           {
4368            __pv_fwarn(3125, "quoted map library token empty string");
4369           }
4370          break;
4371         }
4372       }
4373      if (c == '\n')
4374       {
4375        if (strcmp(__token, "") == 0)
4376         {
4377          __pv_fwarn(3126,
4378           "quoted map library token contains embedded new line");
4379         }
4380       }
4381      *cp++ = c;
4382      c = getc(f);
4383     }
4384    *cp = '\0';
4385    return(CFG_ID);
4386   }
4387 
4388  /* get here by falling through case */
4389  for (cp = __token, namlen = 0;;)
4390   {
4391    if (++namlen >= IDCHARS - 1)
4392     __pv_ferr(919,
4393      "config file token (path?) too long (%d) - rest discarded", IDCHARS - 1);
4394 
4395    *cp++ = c;
4396    if ((c = getc(f)) == EOF) { __toktyp = CFG_EOF; return(CFG_EOF); }
4397    switch (cfgctab[c & 0x7f]) {
4398     case 0: continue;         /* normal in ID char */
4399     case 1: goto end_nam;     /* white space token end - swallow it */
4400     case 2: ungetc(c, f); goto end_nam; /* non white space end token */
4401    }
4402   }
4403 end_nam:
4404  *cp = '\0';
4405  ttyp = get_cfgkeywrd(__token);
4406  return(ttyp);
4407 }
4408 
4409 /*
4410  * look up a cfg file ID and convert to a keyword NUMBER
4411  *
4412  * notice keyword numbers disjoint32 from and overlap Verilog keywords
4413  * FIXME - should use binary search
4414  */
get_cfgkeywrd(char * tstr)4415 static int32 get_cfgkeywrd(char *tstr)
4416 {
4417  if (strcmp(tstr, "library") == 0) return(CFG_LIBRARY);
4418  if (strcmp(tstr, "config") == 0) return(CFG_CFG);
4419  if (strcmp(tstr, "design") == 0) return(CFG_DESIGN);
4420  if (strcmp(tstr, "liblist") == 0) return(CFG_LIBLIST);
4421  if (strcmp(tstr, "instance") == 0) return(CFG_INSTANCE);
4422  if (strcmp(tstr, "cell") == 0) return(CFG_CELL);
4423  if (strcmp(tstr, "use") == 0) return(CFG_USE);
4424  if (strcmp(tstr, "endconfig") == 0) return(CFG_ENDCFG);
4425  if (strcmp(tstr, "default") == 0) return(CFG_DEFAULT);
4426  return(CFG_ID);
4427 }
4428 
4429 /*
4430  * convert cfg toktyp number to name
4431  */
__to_cfgtoknam(char * s,int32 ttyp)4432 extern char *__to_cfgtoknam(char *s, int32 ttyp)
4433 {
4434  switch (ttyp) {
4435   case CFG_UNKNOWN: strcpy(s, "??CFG-UNKNOWN??"); break;
4436   case CFG_ID: strcpy(s, __token); break;
4437   case CFG_COMMA: strcpy(s, ","); break;
4438   case CFG_SEMI: strcpy(s, ";"); break;
4439   case CFG_EOF: strcpy(s, "**CFG EOF**"); break;
4440   case CFG_LIBRARY: strcpy(s, "library"); break;
4441   case CFG_CFG: strcpy(s, "config"); break;
4442   case CFG_INCLUDE: strcpy(s, "include"); break;
4443   case CFG_DESIGN: strcpy(s, "design"); break;
4444   case CFG_LIBLIST: strcpy(s, "liblist"); break;
4445   case CFG_INSTANCE: strcpy(s, "instance"); break;
4446   case CFG_CELL: strcpy(s, "cell"); break;
4447   case CFG_USE: strcpy(s, "use"); break;
4448   case CFG_ENDCFG: strcpy(s, "endconfig"); break;
4449   case CFG_DEFAULT: strcpy(s, "default"); break;
4450   default: __case_terr(__FILE__, __LINE__);
4451  }
4452  return(s);
4453 }
4454 
4455 /*
4456  * get a comment
4457  */
get_cmdcomment(FILE * f)4458 static int32 get_cmdcomment(FILE *f)
4459 {
4460  register int32 c;
4461  int32 c2;
4462 
4463  /* // to EOL comment */
4464  if ((c2 = getc(f)) == '/')
4465   {
4466    while ((c = getc(f)) != '\n') if (c == EOF) { ungetc(c, f); return(TRUE); }
4467    ungetc(c, f);
4468    return(TRUE);
4469   }
4470  /* slash-star comments don't nest */
4471  if (c2 == '*')
4472   {
4473 more_comment:
4474    while ((c = getc(f)) != '*')
4475     {
4476      if (c == EOF) { ungetc(c, f); return(TRUE); }
4477      if (c == '\n') __lin_cnt++;
4478      if (c == '/')
4479       {
4480        if ((c2 = getc(f)) == '*')
4481         {
4482          __pv_fwarn(622, "nested /* in /* style -f argument file comment");
4483          continue;
4484         }
4485        c = c2;
4486       }
4487     }
4488 
4489 got_star:
4490    if ((c = getc(f)) == '/') return(TRUE);
4491    if (c == '*') goto got_star;
4492    if (c == '\n') __lin_cnt++;
4493    goto more_comment;
4494   }
4495  /* / not followed by / or * so put back and return SLASH token */
4496  ungetc(c2, f);
4497  return(FALSE);
4498 }
4499 
4500 /*
4501  * SYMBOL TABLE ROUTINES
4502  */
4503 
4504 /*
4505  * locate a currently accessible symbol - for non path qualified names
4506  * use __find_sym if needs to be addded when not found
4507  * notice this works for frozen symbol tables since get sym determines type
4508  *
4509  * LOOKATME - could make variable routine if if in this inner loop to slow
4510  */
__get_sym_env(char * nam)4511 extern struct sy_t *__get_sym_env(char *nam)
4512 {
4513  int32 sti;
4514  struct sy_t *syp;
4515  struct symtab_t *sytp;
4516 
4517  /* LOOKATME - special convenience variable symbol table could go here */
4518  if (!__iact_state)
4519   {
4520    for (sti = __top_sti; sti >= 0; sti--)
4521     {
4522      sytp = __venviron[sti];
4523      if ((syp = __get_sym(nam, sytp)) != NULL) return(syp);
4524     }
4525    return(NULL);
4526   }
4527 
4528  if (__scope_tskp == NULL)
4529   __last_iasytp = __scope_ptr->itip->imsym->el.emdp->msymtab;
4530  else __last_iasytp = __scope_tskp->tsksymtab;
4531  /* know parent of task is top level module instance and of module is nil */
4532  for (; __last_iasytp != NULL; __last_iasytp = __last_iasytp->sytpar)
4533   { if ((syp = __get_sym(nam, __last_iasytp)) != NULL) return(syp); }
4534  return(NULL);
4535 }
4536 
4537 /*
4538  * find a symbol (will add SYM_UNKN symbol if needed)
4539  * if needs to be implicit wire decl. caller must add and set net
4540  */
__find_sym(char * nam)4541 extern struct sy_t *__find_sym(char *nam)
4542 {
4543  register int32 sti;
4544  struct sy_t *syp;
4545  struct tnode_t *tnp;
4546  struct symtab_t *sytp;
4547 
4548  /* top module level is lowest in task/function symbol table stack */
4549  for (sti = __top_sti; sti >= 0; sti--)
4550   {
4551    sytp = __venviron[sti];
4552    if ((syp = __get_sym(nam, sytp)) != NULL)
4553     { __sym_is_new = FALSE; return(syp); }
4554   }
4555  sytp = __venviron[__top_sti];
4556  tnp = __vtfind(nam, sytp);
4557  /* know symbol will be new */
4558  /* allocate symbol and fill symbol */
4559  __add_sym(nam, tnp);
4560  (__venviron[__top_sti]->numsyms)++;
4561  syp = tnp->ndp;
4562  return(syp);
4563 }
4564 
4565 /*
4566  * declare a symbol - caller determines where declared
4567  *
4568  * this is used to add sym to symbol table - sydecl not set
4569  * when real source declaration (maybe implicit) sydecl set
4570  */
__decl_sym(char * nam,struct symtab_t * sytp)4571 extern struct sy_t *__decl_sym(char *nam, struct symtab_t *sytp)
4572 {
4573  struct sy_t *syp;
4574  struct tnode_t *tnp;
4575 
4576  if ((syp = __get_sym(nam, sytp)) != NULL)
4577   { __sym_is_new = FALSE; return(syp); }
4578  tnp = __vtfind(nam, sytp);
4579  /* allocate symbol and fill symbol */
4580  __add_sym(nam, tnp);
4581  (sytp->numsyms)++;
4582  return(tnp->ndp);
4583 }
4584 
4585 /*
4586  * add a symbol, caller must fill and set type
4587  * expects symbol tree node to be inserted in avl tree and passed here
4588  * symbol always added to symbol table on top of module/task nesting stack
4589  */
__add_sym(char * snam,struct tnode_t * tnp)4590 extern void __add_sym(char *snam, struct tnode_t *tnp)
4591 {
4592  struct sy_t *syp;
4593 
4594  syp = (struct sy_t *) __my_malloc(sizeof(struct sy_t));
4595  tnp->ndp = syp;
4596  __init_sy(syp);
4597  syp->synam = pv_stralloc2(snam);
4598 }
4599 
4600 /*
4601  * allocate a string from a big block
4602  * this must allocate the 1 char null string for `define as flag
4603  */
pv_stralloc2(char * s)4604 static char *pv_stralloc2(char *s)
4605 {
4606  char *cp;
4607  int32 slen;
4608 
4609  if (*s == '\0') slen = 1; else slen = strlen(s) + 1;
4610  cp = nfbig_alloc(slen);
4611  __memstr_use += slen;
4612  /* this just copies '\0' for "" case */
4613  strcpy(cp, s);
4614  return(cp);
4615 }
4616 
4617 /*
4618  * initialize a symbol
4619  * requires set current file and line number
4620  */
__init_sy(struct sy_t * syp)4621 extern void __init_sy(struct sy_t *syp)
4622 {
4623  syp->synam = NULL;
4624  syp->sytyp = SYM_UNKN;
4625  /* notice all symbols add during input phase */
4626  syp->sydecl = FALSE;
4627  syp->syundefmod = FALSE;
4628  syp->sy_impldecl = FALSE;
4629  syp->sy_argsmac = FALSE;
4630  syp->sy_giabase = FALSE;
4631  syp->el.enp = NULL;
4632  syp->syfnam_ind = __cur_fnam_ind;
4633  syp->sylin_cnt = __lin_cnt;
4634  syp->spltsy = NULL;
4635 }
4636 
4637 /*
4638  * BALANCED TREE ACCESS ROUTINES NETS
4639  * MUST GO HERE BECAUSE GLOBALS USE FIND_NET MECHANISM
4640  */
4641 
4642 /*
4643  * search one symbol table and if found return sym node
4644  * call __vtfind if need to add if not found
4645  */
__get_sym(char * nam,struct symtab_t * sytp)4646 extern struct sy_t *__get_sym(char *nam, struct symtab_t *sytp)
4647 {
4648  struct tnode_t *cur;
4649  int32 cv;
4650 
4651  /* interactive bld node accesses frozen symbol table */
4652  if (sytp->stsyms != NULL)
4653   return(__zget_sym(nam, sytp->stsyms, sytp->numsyms));
4654 
4655  /* FIXME - SJM - 09/16/99 when copied n_head may be non nil for empty tab */
4656  if (sytp->n_head == NULL || sytp->numsyms == 0) return(NULL);
4657  for (cur = sytp->n_head;;)
4658   {
4659    if ((cv = strcmp(nam, cur->ndp->synam)) == 0) return(cur->ndp);
4660    if ((cur = (cv < 0) ? cur->lp : cur->rp) == NULL) break;
4661   }
4662  return(NULL);
4663 }
4664 
4665 /*
4666  * special vpi/sdf version of get sym that fails for g/i array base name
4667  *
4668  * LOOKATME - change this if allowing vpi_ access to arrays of gates/insts
4669  */
__get_nongia_sym(char * nam,struct symtab_t * sytp)4670 extern struct sy_t *__get_nongia_sym(char *nam, struct symtab_t *sytp)
4671 {
4672  struct sy_t *syp;
4673 
4674  if ((syp = __get_sym(nam, sytp)) == NULL) return(NULL);
4675  if (syp->sy_giabase) return(NULL);
4676  return(syp);
4677 }
4678 
4679 /*
4680  * find an entry in symbol node tree and add if needed
4681  * expects caller to connect in sy_t and fill it
4682  */
__vtfind(char * nam,struct symtab_t * sytp)4683 extern struct tnode_t *__vtfind(char *nam, struct symtab_t *sytp)
4684 {
4685  register struct tnode_t *cur, *down;
4686  struct tnode_t *balpt_par, *bal_pt, *vtnew, *bal_down;
4687  int32 cv;
4688 
4689  /* DBG remove --
4690  if (sytp->stsyms != NULL) __misc_terr(__FILE__, __LINE__);
4691   --- */
4692 
4693  vtnew = NULL;
4694  if (sytp->n_head == NULL)
4695   { sytp->n_head = alloc_tnode(sytp); return(sytp->n_head); }
4696  for (balpt_par = NULL, bal_pt = cur = sytp->n_head;;)
4697   {
4698    if ((cv = strcmp(nam, cur->ndp->synam)) == 0)
4699     { __sym_is_new = FALSE; return(cur); }
4700 
4701    if (cv < 0) { cur->via_dir = BLEFT; down = cur->lp; }
4702    else { cur->via_dir = BRIGHT; down = cur->rp; }
4703    if (down == NULL)
4704     {
4705      down = alloc_tnode(sytp);
4706      if (cur->via_dir == BLEFT) cur->lp = down; else cur->rp = down;
4707      vtnew = down;
4708      break;
4709     }
4710    if (down->bal != BEVEN) { balpt_par = cur; bal_pt = down; }
4711    cur = down;
4712   }
4713 
4714  /* bal down is one below balance point */
4715  if (bal_pt->via_dir == BLEFT) bal_down = bal_pt->lp;
4716  else bal_down = bal_pt->rp;
4717  /* know all nodes from bal_pt down to but not including new had balance 0 */
4718  /* adjust up to but not including balance of new */
4719  for (cur = bal_down; cur != vtnew;)
4720   {
4721    cur->bal = cur->via_dir;
4722    if (cur->via_dir == BLEFT) cur = cur->lp; else cur = cur->rp;
4723   }
4724  /* since only unbalanced by 1 put off doing anything */
4725  if (bal_pt->bal == BEVEN) { bal_pt->bal = bal_pt->via_dir; return(vtnew); }
4726 
4727  /* tree got more balanced */
4728  /* check for bal and even dir opposite or both even */
4729  if ((bal_pt->bal == BEVEN && bal_pt->via_dir == BEVEN)
4730   || (bal_pt->bal == BLEFT && bal_pt->via_dir == BRIGHT)
4731   || (bal_pt->bal == BRIGHT && bal_pt->via_dir == BLEFT))
4732   {
4733    bal_pt->bal = BEVEN;
4734    return(vtnew);
4735   }
4736 
4737  __tmp_head = sytp->n_head;
4738  /* these routines may update global __tmp_head */
4739  /* tree more out of balance - needs rebalancing */
4740  if (bal_down->bal == bal_pt->via_dir) one_rot(bal_pt, bal_down, balpt_par);
4741  else two_rot(bal_pt, bal_down, balpt_par);
4742  sytp->n_head = __tmp_head;
4743 
4744  return(vtnew);
4745 }
4746 
4747 /*
4748  * single rotation
4749  */
one_rot(struct tnode_t * bal_pt,struct tnode_t * bal_down,struct tnode_t * balpt_par)4750 static void one_rot(struct tnode_t *bal_pt, struct tnode_t *bal_down,
4751  struct tnode_t *balpt_par)
4752 {
4753  if (bal_pt->via_dir == BLEFT)
4754   {
4755    bal_pt->lp = bal_down->rp;
4756    bal_down->rp = bal_pt;
4757   }
4758  else
4759   {
4760    bal_pt->rp = bal_down->lp;
4761    bal_down->lp = bal_pt;
4762   }
4763  bal_pt->bal = bal_down->bal = BEVEN;
4764 
4765  if (balpt_par == NULL) __tmp_head = bal_down;
4766  else if (balpt_par->via_dir == BLEFT) balpt_par->lp = bal_down;
4767  else balpt_par->rp = bal_down;
4768 }
4769 
4770 /*
4771  * double rotation
4772  */
two_rot(struct tnode_t * bal_pt,struct tnode_t * bal_down,struct tnode_t * balpt_par)4773 static void two_rot(struct tnode_t *bal_pt, struct tnode_t *bal_down,
4774  struct tnode_t *balpt_par)
4775 {
4776  struct tnode_t *tmp;
4777 
4778  if (bal_pt->via_dir == BLEFT)
4779   {
4780    tmp = bal_down->rp;
4781    bal_down->rp = tmp->lp;
4782    tmp->lp = bal_down;
4783    bal_pt->lp = tmp->rp;
4784    tmp->rp = bal_pt;
4785   }
4786  else
4787   {
4788    tmp = bal_down->lp;
4789    bal_down->lp = tmp->rp;
4790    tmp->rp = bal_down;
4791    bal_pt->rp = tmp->lp;
4792    tmp->lp = bal_pt;
4793   }
4794 
4795  /* update the balances */
4796  if (tmp->bal == BEVEN) bal_pt->bal = bal_down->bal = BEVEN;
4797  else if (tmp->bal == bal_pt->via_dir)
4798   {
4799    if (bal_pt->via_dir == BRIGHT) bal_pt->bal = BLEFT;
4800    else if (bal_pt->via_dir == BLEFT) bal_pt->bal = BRIGHT;
4801    else bal_pt->bal = BEVEN;
4802    bal_down->bal = BEVEN;
4803   }
4804  else { bal_pt->bal = BEVEN; bal_down->bal = bal_pt->via_dir; }
4805  tmp->bal = BEVEN;
4806 
4807  /* point node above balance point to new high node */
4808  if (balpt_par == NULL) __tmp_head = tmp;
4809  else if (balpt_par->via_dir == BLEFT) balpt_par->lp = tmp;
4810  else balpt_par->rp = tmp;
4811 }
4812 
4813 /*
4814  * allocate a node
4815  */
alloc_tnode(struct symtab_t * sytp)4816 static struct tnode_t *alloc_tnode(struct symtab_t *sytp)
4817 {
4818  struct tnode_t *tnp;
4819  register struct tnblk_t *tnbp;
4820 
4821  if (!sytp->freezes)
4822   tnp = (struct tnode_t *) __my_malloc(sizeof(struct tnode_t));
4823  else
4824   {
4825    if (__tnblk_nxti == -1)
4826     {
4827      tnbp = (struct tnblk_t *) __my_malloc(sizeof(struct tnblk_t));
4828      tnbp->tnblks = (struct tnode_t *) __my_malloc(BIG_ALLOC_SIZE);
4829      tnbp->tnblknxt = __hdr_tnblks;
4830      __hdr_tnblks = tnbp;
4831      __tnblk_nxti = 0;
4832     }
4833    tnp = (struct tnode_t *) &(__hdr_tnblks->tnblks[__tnblk_nxti]);
4834    if (++__tnblk_nxti > ((BIG_ALLOC_SIZE/sizeof(struct tnode_t)) - 1))
4835      __tnblk_nxti = -1;
4836   }
4837 
4838  tnp->lp = tnp->rp = NULL;
4839  tnp->bal = BEVEN;
4840  tnp->via_dir = BEVEN;
4841  __sym_is_new = TRUE;
4842  tnp->ndp = NULL;
4843  return(tnp);
4844 }
4845 
4846 /*
4847  * find a symbol in the current scope
4848  */
4849 
4850 /*
4851  * get a symbol in frozen table - notice nsyms is num. not last
4852  */
__zget_sym(char * nam,struct sy_t ** syms,word32 nsyms)4853 extern struct sy_t *__zget_sym(char *nam, struct sy_t **syms, word32 nsyms)
4854 {
4855  register int32 l, h;
4856  register int32 m, cv;
4857 
4858  if (nsyms == 0) return(NULL);
4859  l = 0; h = nsyms - 1;
4860  for (;;)
4861   {
4862    m = (l + h)/2;
4863    if ((cv = strcmp(syms[m]->synam, nam)) == 0) return(syms[m]);
4864    if (cv < 0) l = m + 1; else h = m - 1;
4865    if (h < l) break;
4866   }
4867  return(NULL);
4868 }
4869 
4870 /*
4871  * allocate a new empty symbol table
4872  */
__alloc_symtab(int32 freezes)4873 extern struct symtab_t *__alloc_symtab(int32 freezes)
4874 {
4875  struct symtab_t *sytp;
4876 
4877  sytp = (struct symtab_t *) __my_malloc(sizeof(struct symtab_t));
4878  sytp->n_head = NULL;
4879  sytp->stsyms = NULL;
4880  sytp->sytpar = NULL;
4881  sytp->sytsib = NULL;
4882  sytp->sytofs = NULL;
4883  sytp->sypofsyt = NULL;
4884  sytp->numsyms = 0;
4885  sytp->freezes = freezes;
4886  return(sytp);
4887 }
4888 
4889 /*
4890  * MISC. REPRESENTATION CHANGE RROUTINES
4891  */
4892 
4893 /*
4894  * routine to find index in ip table and it roots of top level module
4895  *
4896  * here __top_ipind is sorted array of indexes into top_iptab which
4897  * is || to __it_roots
4898  */
__ip_indsrch(char * nam)4899 extern int32 __ip_indsrch(char *nam)
4900 {
4901  int32 l, h;
4902  register int32 m, cv;
4903 
4904  if (__numtopm == 0) return(-1);
4905  l = 0; h = __numtopm - 1;
4906  for (;;)
4907   {
4908    m = (l + h)/2;
4909    if ((cv = strcmp(__top_itab[__top_ipind[m]]->imsym->synam, nam)) == 0)
4910     return(__top_ipind[m]);
4911    if (cv < 0) l = m + 1; else h = m - 1;
4912    if (h < l) break;
4913   }
4914  return(-1);
4915 }
4916 
4917 /*
4918  * convert an identifier to either global or id name
4919  */
__to_idnam(struct expr_t * xp)4920 extern char *__to_idnam(struct expr_t *xp)
4921 {
4922  char *chp;
4923 
4924  if (xp->optyp == ID)
4925   {
4926    if (xp->locqualnam) return(xp->ru.qnchp); else return(xp->lu.sy->synam);
4927   }
4928  else if (xp->optyp == GLBREF) chp = xp->ru.grp->gnam;
4929  else { chp = NULL;  __case_terr(__FILE__, __LINE__); }
4930  return(chp);
4931 }
4932 
4933 /*
4934  * convert port name to string - maybe unnamed (chp nil)
4935  */
__to_mpnam(char * s,char * chp)4936 extern char *__to_mpnam(char *s, char *chp)
4937 {
4938  if (chp == NULL) strcpy(s, "*unnamed*"); else strcpy(s, chp);
4939  return(s);
4940 }
4941 
4942 
4943 /*
4944  * convert from a wire type token number to its wtyp value (-1 if no match)
4945  */
__fr_wtnam(int32 ttyp)4946 extern int32 __fr_wtnam(int32 ttyp)
4947 {
4948  int32 wtyp;
4949 
4950  switch ((byte) ttyp) {
4951   case WIRE: wtyp = N_WIRE; break;
4952   case TRI: wtyp = N_TRI; break;
4953   case TRI0: wtyp = N_TRI0; break;
4954   case TRI1: wtyp = N_TRI1; break;
4955   case TRIOR: wtyp = N_TRIOR; break;
4956   case TRIAND: wtyp = N_TRIAND; break;
4957   case TRIREG: wtyp = N_TRIREG; break;
4958   case WAND: wtyp = N_WA; break;
4959   case WOR: wtyp = N_WO; break;
4960   /* notice pulls never explicitly declared */
4961   case SUPPLY0: wtyp = N_SUPPLY0; break;
4962   case SUPPLY1: wtyp = N_SUPPLY1; break;
4963   case REG: wtyp = N_REG; break;
4964   case TIME: wtyp = N_TIME; break;
4965   case INTEGER: wtyp = N_INT; break;
4966   case REAL: case REALTIME: wtyp = N_REAL; break;
4967   case EVENT: wtyp = N_EVENT; break;
4968   default: wtyp = -1; break;
4969  }
4970  return(wtyp);
4971 }
4972 
4973 /*
4974  * convert a net to its wire type
4975  */
__to_wtnam(char * s,struct net_t * np)4976 extern char *__to_wtnam(char *s, struct net_t *np)
4977 {
4978  return(__to_wtnam2(s, np->ntyp));
4979 }
4980 
4981 /*
4982  * convert a wire type value into a output name (2nd variant constant wtyp)
4983  * not for I/O port types
4984  */
__to_wtnam2(char * s,word32 typ)4985 extern char *__to_wtnam2(char *s, word32 typ)
4986 {
4987  switch ((byte) typ) {
4988   case N_WIRE: strcpy(s, "wire"); break;
4989   case N_TRI: strcpy(s, "tri"); break;
4990   case N_TRI0: strcpy(s, "tri0"); break;
4991   case N_TRI1: strcpy(s, "tri1"); break;
4992   case N_TRIOR: strcpy(s, "wor"); break;
4993   case N_TRIAND: strcpy(s, "wand"); break;
4994   case N_TRIREG: strcpy(s, "trireg"); break;
4995   case N_WA: strcpy(s, "wand"); break;
4996   case N_WO: strcpy(s, "wor"); break;
4997   case N_SUPPLY0: strcpy(s, "supply0"); break;
4998   case N_SUPPLY1: strcpy(s, "supply1"); break;
4999   /* these need special syntax for declaration */
5000   case N_REG: strcpy(s, "reg"); break;
5001   case N_TIME: strcpy(s, "time"); break;
5002   case N_INT: strcpy(s, "integer"); break;
5003   case N_REAL: strcpy(s, "real"); break;
5004   case N_EVENT: strcpy(s, "event"); break;
5005   default: __case_terr(__FILE__, __LINE__);
5006  }
5007  return(s);
5008 }
5009 
5010 /*
5011  * convert an i/o port type to a name (use lower case for these)
5012  */
__to_ptnam(char * s,word32 ptyp)5013 extern char *__to_ptnam(char *s, word32 ptyp)
5014 {
5015  switch ((byte) ptyp) {
5016   case IO_IN: strcpy(s, "input"); break;
5017   case IO_OUT: strcpy(s, "output"); break;
5018   case IO_BID: strcpy(s, "inout"); break;
5019   case IO_UNKN: strcpy(s, "-unknown-"); break;
5020   case NON_IO: strcpy(s, "-non-io-"); break;
5021   default: __case_terr(__FILE__, __LINE__);
5022  }
5023  return(s);
5024 }
5025 
5026 /*
5027  * convert a wire splitting type to scalared/vectored state
5028  */
__to_splt_nam(char * s,int32 sptyp)5029 extern char *__to_splt_nam(char *s, int32 sptyp)
5030 {
5031  if (sptyp == SPLT_SCAL) strcpy(s, "scalared");
5032  else if (sptyp == SPLT_VECT) strcpy(s, "vectored");
5033  else { __case_terr(__FILE__, __LINE__);  strcpy(s,""); }
5034  return(s);
5035 }
5036 
5037 /*
5038  * convert from a token type number to a strength symbolic constant
5039  * return NO_STREN on not a strength - checking must be elsewhere
5040  */
__fr_stren_nam(int32 ttyp)5041 extern word32 __fr_stren_nam(int32 ttyp)
5042 {
5043  switch ((byte) ttyp) {
5044   case HIGHZ0: case HIGHZ1: return(ST_HIGHZ);
5045   case SMALL: return(ST_SMALL);
5046   case MEDIUM: return(ST_MEDIUM);
5047   case WEAK0: case WEAK1: return(ST_WEAK);
5048   case LARGE: return(ST_LARGE);
5049   case PULL0: case PULL1: return(ST_PULL);
5050   case STRONG0: case STRONG1: return(ST_STRONG);
5051   case SUPPLY0: case SUPPLY1: return(ST_SUPPLY);
5052  }
5053  return(NO_STREN);
5054 }
5055 
5056 /*
5057  * convert a strength pair to a name
5058  * use this to write cap strength
5059  */
__to_stren_nam(char * s,int32 stren1,int32 stren2)5060 extern char *__to_stren_nam(char *s, int32 stren1, int32 stren2)
5061 {
5062  char s1[RECLEN], s2[RECLEN];
5063 
5064  if (__is_capstren(stren1))
5065   sprintf(s, "(%s)", __to1_stren_nam(s1, stren1, 2));
5066  else sprintf(s, "(%s, %s)", __to1_stren_nam(s1, stren1, 0),
5067   __to1_stren_nam(s2, stren2, 1));
5068  return(s);
5069 }
5070 
5071 /*
5072  * convert a stval coded strength name
5073  * not for cap. strength
5074  * and notice value coded in 6 bits (i.e. no value in low 2 bits
5075  */
__to_stval_nam(char * s,word32 stval)5076 extern char *__to_stval_nam(char *s, word32 stval)
5077 {
5078  int32 st0, st1;
5079  char s1[RECLEN], s2[RECLEN];
5080 
5081  st0 = (int32) (stval >> 3) & 7;
5082  st1 = (int32) (stval) & 7;
5083  sprintf(s, "(%s, %s)", __to1_stren_nam(s1, st0, 0),
5084   __to1_stren_nam(s2, st1, 1));
5085  return(s);
5086 }
5087 
5088 /*
5089  * convert from a strength type and 0/1 value to a strength name
5090  * this is source driving strength - not net strength value
5091  */
__to1_stren_nam(char * s,int32 st,int32 st01dir)5092 extern char *__to1_stren_nam(char *s, int32 st, int32 st01dir)
5093 {
5094  switch ((byte) st) {
5095   case ST_HIGHZ: strcpy(s, "highz"); break;
5096   case ST_SMALL: strcpy(s, "small"); return(s);
5097   case ST_MEDIUM: strcpy(s, "medium"); return(s);
5098   case ST_WEAK: strcpy(s, "weak"); break;
5099   case ST_LARGE: strcpy(s, "large"); return(s);
5100   case ST_PULL: strcpy(s, "pull"); break;
5101   case ST_STRONG: strcpy(s, "strong"); break;
5102   case ST_SUPPLY: strcpy(s, "supply"); break;
5103   default: __case_terr(__FILE__, __LINE__);
5104  }
5105  if (st01dir == 0) strcat(s, "0");
5106  else if (st01dir == 1) strcat(s, "1");
5107  return(s);
5108 }
5109 
5110 /*
5111  * return T if strength value is cap. strength
5112  */
__is_capstren(int32 st)5113 extern int32 __is_capstren(int32 st)
5114 {
5115  switch ((byte) st) {
5116   case ST_SMALL: case ST_MEDIUM: case ST_LARGE: return(TRUE);
5117  }
5118  return(FALSE);
5119 }
5120 
5121 /*
5122  * convert from a capacitor size constant to a capacitor strength
5123  */
__fr_cap_size(int32 capsiz)5124 extern int32 __fr_cap_size(int32 capsiz)
5125 {
5126  int32 st;
5127 
5128  switch ((byte) capsiz) {
5129   case CAP_NONE: st = ST_STRONG; break;
5130   case CAP_SMALL: st = ST_SMALL; break;
5131   case CAP_MED: st = ST_MEDIUM; break;
5132   case CAP_LARGE: st = ST_LARGE; break;
5133   default: st = ST_STRONG; __case_terr(__FILE__, __LINE__);
5134  }
5135  return(st);
5136 }
5137 
5138 /*
5139  * convert to a capacitor size constant from a capacitor strength
5140  * must catch non cap size strength input before here
5141  */
__to_cap_size(int32 st)5142 extern word32 __to_cap_size(int32 st)
5143 {
5144  int32 capsiz;
5145 
5146  switch ((byte) st) {
5147   case ST_STRONG: capsiz = CAP_NONE; break;
5148   case ST_SMALL: capsiz = CAP_SMALL; break;
5149   case ST_MEDIUM: capsiz = CAP_MED; break;
5150   case ST_LARGE: capsiz = CAP_LARGE; break;
5151   default: capsiz = CAP_NONE; __case_terr(__FILE__, __LINE__);
5152  }
5153  return(capsiz);
5154 }
5155 
5156 /*
5157  * build a $display style 2 char strength string
5158  */
__to_dispst_str(char * s,word32 st)5159 extern char *__to_dispst_str(char *s, word32 st)
5160 {
5161  switch ((byte) st) {
5162   case ST_HIGHZ: strcpy(s, "Hi"); break;
5163   case ST_SMALL: strcpy(s, "Sm"); break;
5164   case ST_MEDIUM: strcpy(s, "Me"); break;
5165   case ST_WEAK: strcpy(s, "We"); break;
5166   case ST_LARGE: strcpy(s, "La"); break;
5167   case ST_PULL: strcpy(s, "Pu"); break;
5168   case ST_STRONG: strcpy(s, "St"); break;
5169   case ST_SUPPLY: strcpy(s, "Su"); break;
5170   default: __case_terr(__FILE__, __LINE__);
5171  }
5172  return(s);
5173 }
5174 
5175 /*
5176  * build a symbol class name
5177  */
__to_sytyp(char * s,word32 styp)5178 extern char *__to_sytyp(char *s, word32 styp)
5179 {
5180  switch ((byte) styp) {
5181   case SYM_UNKN: strcpy(s, "--unknown--"); break;
5182   case SYM_I: strcpy(s, "instance"); break;
5183   case SYM_M: strcpy(s, "module"); break;
5184   case SYM_PRIM: strcpy(s, "primitive"); break;
5185   case SYM_UDP: strcpy(s, "udp define"); break;
5186   case SYM_N: strcpy(s, "variable"); break;
5187   case SYM_TSK: strcpy(s, "task"); break;
5188   case SYM_STSK: strcpy(s, "systask"); break;
5189   case SYM_LB: strcpy(s, "named block"); break;
5190   case SYM_F: strcpy(s, "function"); break;
5191   case SYM_SF: strcpy(s, "sysfunction"); break;
5192   case SYM_DEF: strcpy(s, "preprocessor `define"); break;
5193   case SYM_CA: strcpy(s, "continuous assign"); break;
5194   case SYM_PTH: strcpy(s, "delay path"); break;
5195   case SYM_TCHK: strcpy(s, "timing check"); break;
5196   default: __case_terr(__FILE__, __LINE__);
5197  }
5198  return(s);
5199 }
5200 
5201 /*
5202  * build a task type name - tskt is token number
5203  */
__to_tsktyp(char * s,word32 tskt)5204 extern char *__to_tsktyp(char *s, word32 tskt)
5205 {
5206  switch ((byte) tskt) {
5207   case Begin: strcpy(s, "named begin"); break;
5208   case FORK: strcpy(s, "named fork"); break;
5209   case FUNCTION: strcpy(s, "function"); break;
5210   case TASK: strcpy(s, "task"); break;
5211  }
5212  return(s);
5213 }
5214 
5215 /*
5216  * build a statement type name
5217  */
__to_sttyp(char * s,word32 sttyp)5218 extern char *__to_sttyp(char *s, word32 sttyp)
5219 {
5220  switch ((byte) sttyp) {
5221   case S_NULL: strcpy(s, "empty"); break;
5222   case S_STNONE: strcpy(s, "empty block"); break;
5223   case S_PROCA: strcpy(s, "proc. assign"); break;
5224   case S_FORASSGN: strcpy(s, "for initial assign"); break;
5225   case S_NBPROCA: strcpy(s, "non-blocking proc. assign"); break;
5226   case S_RHSDEPROCA: strcpy(s, "proc. assign (rhs delay/event)"); break;
5227   case S_IF: strcpy(s, "if"); break;
5228   case S_CASE: strcpy(s, "case/casex/casez"); break;
5229   case S_FOREVER: strcpy(s, "forever"); break;
5230   case S_REPEAT: strcpy(s, "repeat"); break;
5231   case S_WHILE: strcpy(s, "while"); break;
5232   case S_WAIT: strcpy(s, "wait"); break;
5233   case S_FOR : strcpy(s, "for loop"); break;
5234   case S_DELCTRL: strcpy(s, "delay control"); break;
5235   case S_NAMBLK : strcpy(s, "named block"); break;
5236   case S_UNBLK : strcpy(s, "unnamed block"); break;
5237   case S_UNFJ: strcpy(s, "parallel block"); break;
5238   case S_TSKCALL: strcpy(s, "task enable"); break;
5239   case S_QCONTA: strcpy(s, "quasi-continuous assign"); break;
5240   case S_QCONTDEA: strcpy(s, "quasi-continous deassign"); break;
5241   case S_CAUSE: strcpy(s, "cause"); break;
5242   case S_DSABLE: strcpy(s, "disable"); break;
5243   case S_REPSETUP: strcpy(s, "**added loop setup"); break;
5244   case S_REPDCSETUP: strcpy(s, "**added repeat event control setup"); break;
5245   case S_GOTO: strcpy(s, "**added goto"); break;
5246   default: __case_terr(__FILE__, __LINE__);
5247  }
5248  return(s);
5249 }
5250 
5251 /*
5252  * build the quasi-continue statement type name
5253  */
__to_qctyp(char * s,word32 qctyp)5254 extern char *__to_qctyp(char *s, word32 qctyp)
5255 {
5256  switch ((byte) qctyp) {
5257   case FORCE: strcpy(s, "force"); break;
5258   case RELEASE: strcpy(s, "release"); break;
5259   case ASSIGN: strcpy(s, "assign"); break;
5260   case DEASSIGN: strcpy(s, "deassign"); break;
5261   default: __case_terr(__FILE__, __LINE__);
5262  }
5263  return(s);
5264 }
5265 
5266 /*
5267  * build an event type name
5268  */
__to_tetyp(char * s,word32 tetyp)5269 extern char *__to_tetyp(char *s, word32 tetyp)
5270 {
5271  switch ((byte) tetyp) {
5272   case TE_THRD: strcpy(s, "procedural"); break;
5273   case TE_G: strcpy(s, "gate assign"); break;
5274   case TE_CA: strcpy(s, "conta assign"); break;
5275   case TE_WIRE: strcpy(s, "wire delay"); break;
5276   case TE_BIDPATH: strcpy(s, "inout path dest."); break;
5277   case TE_MIPD_NCHG: strcpy(s, "MIPD change"); break;
5278   case TE_NBPA: strcpy(s, "NB assign"); break;
5279   case TE_TFSETDEL: strcpy(s, "tf_ set delay"); break;
5280   case TE_SYNC: strcpy(s, "tf_ #0 synchronize"); break;
5281   case TE_TFPUTPDEL: strcpy(s, "tf_ delayed strputp"); break;
5282   case TE_VPIPUTVDEL: strcpy(s, "vpi_ put value"); break;
5283   case TE_VPIDRVDEL: strcpy(s, "vpi_ add drv. chg."); break;
5284   case TE_VPICBDEL: strcpy(s, "vpi_ delay cb"); break;
5285   case TE_UNKN:
5286    /*FALLTHRU */
5287   default:
5288    strcpy(s, "**UNKNOWN**");
5289    /* __case_terr(__FILE__, __LINE__); */
5290  }
5291  return(s);
5292 }
5293 
5294 /*
5295  * build a net-pin connection/action type
5296  */
__to_npptyp(char * s,struct net_pin_t * npp)5297 extern char *__to_npptyp(char *s, struct net_pin_t *npp)
5298 {
5299  char s1[RECLEN];
5300 
5301  switch ((byte) npp->npntyp) {
5302   case NP_ICONN: strcpy(s, "instance port"); break;
5303   case NP_PB_ICONN: strcpy(s, "instance per bit port"); break;
5304   case NP_MDPRT: strcpy(s, "module port"); break;
5305   case NP_PB_MDPRT: strcpy(s, "module per bit port"); break;
5306   case NP_MIPD_NCHG: strcpy(s, "MIPD input/inout port"); break;
5307   case NP_CONTA:
5308    if (npp->elnpp.ecap->ca_pb_sim) strcpy(s, "per bit cont. assign lvalue");
5309    else strcpy(s, "cont. assign lvalue"); break;
5310    break;
5311   case NP_TFRWARG: strcpy(s, "tf_ PLI rw arg wire driver"); break;
5312   case NP_VPIPUTV: strcpy(s, "vpi_put_value wire driver"); break;
5313   case NP_GATE: strcpy(s, "gate terminal"); break;
5314   case NP_TRANIF: strcpy(s, "tranif enable"); break;
5315   case NP_TCHG:
5316    sprintf(s, "bit change(%s)", __to_nppsubtyp(s1, npp->chgsubtyp));
5317    break;
5318   case NP_PULL: strcpy(s, "pull driver"); break;
5319   default: __case_terr(__FILE__, __LINE__);
5320  }
5321  return(s);
5322 }
5323 
5324 /*
5325  * build the net change subtype name
5326  */
__to_nppsubtyp(char * s,word32 subtyp)5327 static char *__to_nppsubtyp(char *s, word32 subtyp)
5328 {
5329  switch ((byte) subtyp) {
5330   case NPCHG_TCSTART: strcpy(s, "tchk start ref."); break;
5331   case NPCHG_TCCHK: strcpy(s, "tchk data end"); break;
5332   case NPCHG_PTHSRC: strcpy(s, "path source"); break;
5333   default: __case_terr(__FILE__, __LINE__);
5334  }
5335  return(s);
5336 }
5337 
5338 /*
5339  * build a delay type name string
5340  */
__to_deltypnam(char * s,word32 dtyp)5341 extern char *__to_deltypnam(char *s, word32 dtyp)
5342 {
5343  switch ((byte) dtyp) {
5344    case DT_NONE: strcpy(s, "?none?"); break;
5345    case DT_1V: strcpy(s, "one"); break;
5346    case DT_IS1V: case DT_IS1V1: case DT_IS1V2:
5347     strcpy(s, "one instance specific");
5348     break;
5349    case DT_4V: strcpy(s, "(r, f, toz)"); break;
5350    case DT_IS4V: case DT_IS4V1: case DT_IS4V2:
5351     strcpy(s, "(r, f, toz) instance specific");
5352     break;
5353    case DT_16V: strcpy(s, "path 2,3,6,12 value"); break;
5354    case DT_IS16V: case DT_IS16V1: case DT_IS16V2:
5355      strcpy(s, "path 2,3,6,12 value instance specific");
5356      break;
5357    case DT_1X: strcpy(s, "one non constant"); break;
5358    case DT_4X: strcpy(s, "(r, f, toz) non constant"); break;
5359    case DT_PTHDST: strcpy(s, "internal path descriptor non"); break;
5360    case DT_CMPLST: strcpy(s, "translation time expression list"); break;
5361    default: __case_terr(__FILE__, __LINE__);
5362   }
5363  return(s);
5364 }
5365 
5366 /*
5367  * convert timing check type to name
5368  */
__to_tcnam(char * s,word32 tctyp)5369 extern char *__to_tcnam(char *s, word32 tctyp)
5370 {
5371  switch ((byte) tctyp) {
5372   case TCHK_SETUP: strcpy(s, "$setup"); break;
5373   case TCHK_HOLD: strcpy(s, "$hold"); break;
5374   case TCHK_WIDTH: strcpy(s, "$width"); break;
5375   case TCHK_PERIOD: strcpy(s, "$period"); break;
5376   case TCHK_SKEW: strcpy(s, "$skew"); break;
5377   case TCHK_RECOVERY: strcpy(s, "$recovery"); break;
5378   case TCHK_SETUPHOLD: strcpy(s, "$setuphold"); break;
5379   case TCHK_NOCHANGE: strcpy(s, "$nochange"); break;
5380   /* SJM 12/15/03 - new 2001 timing checks - if used not read with warn */
5381   case TCHK_FULLSKEW: strcpy(s, "$fullskew"); break;
5382   case TCHK_REMOVAL: strcpy(s, "$removal"); break;
5383   case TCHK_RECREM: strcpy(s, "$recrem"); break;
5384   case TCHK_TIMESKEW: strcpy(s, "$timeskew"); break;
5385   default: __case_terr(__FILE__, __LINE__);
5386  }
5387  return(s);
5388 }
5389 
5390 /*
5391  * convert timing check name to type number - returns -1 if not found
5392  * expected the leading $
5393  */
__fr_tcnam(char * tcnam)5394 extern int32 __fr_tcnam(char *tcnam)
5395 {
5396  if (*tcnam != '$') return(-1);
5397  switch (tcnam[1]) {
5398   case 'f':
5399    if (strcmp(&(tcnam[2]), "ullskew") == 0) return(TCHK_FULLSKEW);
5400    break;
5401   case 'h': if (strcmp(&(tcnam[2]), "old") == 0) return(TCHK_HOLD); break;
5402   case 'n':
5403    if (strcmp(&(tcnam[2]), "ochange") == 0) return(TCHK_NOCHANGE); break;
5404   case 'p': if (strcmp(&(tcnam[2]), "eriod") == 0) return(TCHK_PERIOD); break;
5405   case 'r':
5406    /* SJM - 11/21/03 - must also recognize recrem */
5407    if (strcmp(&(tcnam[2]), "ecovery") == 0) return(TCHK_RECOVERY);
5408    if (strcmp(&(tcnam[2]), "ecrem") == 0) return(TCHK_RECREM);
5409    if (strcmp(&(tcnam[2]), "emoval") == 0) return(TCHK_REMOVAL);
5410    break;
5411   case 's':
5412    if (tcnam[2] == 'k')
5413     { if (strcmp(&(tcnam[3]), "ew") == 0) return(TCHK_SKEW); break; }
5414    else if (strcmp(&(tcnam[2]), "etuphold") == 0) return(TCHK_SETUPHOLD);
5415    else if (strcmp(&(tcnam[2]), "etup") == 0) return(TCHK_SETUP);
5416    break;
5417   case 't':
5418    if (strcmp(&(tcnam[2]), "imeskew") == 0) return(TCHK_TIMESKEW);
5419    break;
5420   case 'w': if (strcmp(&(tcnam[2]), "idth") == 0) return(TCHK_WIDTH); break;
5421  }
5422  return(-1);
5423 }
5424 
5425 /*
5426  * output a number that is decomposed from input token but not yet converted
5427  * to value for errors during input number processing
5428  */
decompnum_to_str(char * s,char * digs,int32 base,int32 width)5429 static char *decompnum_to_str(char *s, char *digs, int32 base, int32 width)
5430 {
5431  sprintf(s, "%d'%c%s", width, __to_baselet(base), digs);
5432  return(s);
5433 }
5434 
5435 /*
5436  * convert gate output value to printable
5437  * tricky because depending on gate class and stval may or may not need stren
5438  */
__to_gonam(char * s,struct gate_t * gp,word32 v)5439 extern char *__to_gonam(char *s, struct gate_t *gp, word32 v)
5440 {
5441  switch ((byte) gp->g_class) {
5442   case GC_LOGIC: case GC_UDP:
5443    if (gp->g_hasst)
5444     {
5445      if (v != 2) v |= (gp->g_stval << 2);
5446      __to_vvstnam(s, (word32) __stren_map_tab[v]);
5447     }
5448    else __to_vvnam(s, (word32) v);
5449    break;
5450   case GC_TRANIF:
5451    /* here gate "output" is conducting state */
5452    if (v == 0) strcpy(s, "*OFF*");
5453    else if (v == 1) strcpy(s, "*ON*");
5454    else if (v == 3) strcpy(s, "*UNKNOWN*");
5455    else __misc_terr(__FILE__, __LINE__);
5456    break;
5457   case GC_TRAN: case GC_PULL:
5458    __case_terr(__FILE__, __LINE__); strcpy(s, "");
5459   /* mos and bufif outputs always strength */
5460   default: __to_vvstnam(s, (word32) v);
5461  }
5462  return(s);
5463 }
5464 
5465 /*
5466  * convert gate value to printable
5467  * tricky because depending on gate class and stval may or may not need stren
5468  */
__to_ginam(char * s,struct gate_t * gp,word32 v,int32 i)5469 extern char *__to_ginam(char *s, struct gate_t *gp, word32 v, int32 i)
5470 {
5471  switch ((byte) gp->g_class) {
5472   /* bufif inputs non stength even though drives strength */
5473   /* tranif 3rd input non strength and value not just on/off */
5474   case GC_LOGIC: case GC_UDP: case GC_BUFIF: case GC_TRANIF:
5475    __to_vvnam(s, (word32) v);
5476    break;
5477   /* mos input 1 strength (added if needed) but control input non stren */
5478   case GC_MOS: case GC_CMOS:
5479    /* only 1st mos or cmos input has strength not control(s) */
5480    if (i == 1) __to_vvstnam(s, (word32) v); else __to_vvnam(s, (word32) v);
5481    break;
5482   /* tran and pull cannot use this routine */
5483   default: __case_terr(__FILE__, __LINE__);
5484  }
5485  return(s);
5486 }
5487 
5488 /*
5489  * convert net value to printable
5490  */
__to_vnam(char * s,word32 is_stren,word32 v)5491 extern char *__to_vnam(char *s, word32 is_stren, word32 v)
5492 {
5493  if (is_stren) __to_vvstnam(s, (word32) v); else __to_vvnam(s, (word32) v);
5494  return(s);
5495 }
5496 
5497 /*
5498  * convert a strength value to a 3 letter name string
5499  * know always 3 characters
5500  *
5501  * SJM 08/16/01 - BEWARE this routine must not be changed because it is
5502  * only way debug switch determines if mistake in table or algorithm
5503  * has caused one of the illegal 129 stren values to be created
5504  * algorithms do something slightly and undectably wrong if this happens
5505  */
__to_vvstnam(char * s,word32 stval)5506 extern char *__to_vvstnam(char *s, word32 stval)
5507 {
5508  word32 st0, st1;
5509  byte val;
5510  char ch;
5511 
5512  /* decode stren byte */
5513  val = (byte) stval & 3;
5514  st0 = (stval >> 5) & 7;
5515  st1 = (stval >> 2) & 7;
5516 
5517  switch (val) {
5518   case 0: ch = '0'; break;
5519   case 1: ch = '1'; break;
5520   case 2:
5521    /* real HiZ */
5522    if (st0 != 0 || st1 != 0)__misc_terr(__FILE__, __LINE__);
5523    strcpy(s, "HiZ");
5524    return(s);
5525   case 3:
5526    /* this should be Z not X */
5527    if (st0 == 0 && st1 == 0) __misc_terr(__FILE__, __LINE__);
5528 
5529    /* z with hiz 0 strength component is H */
5530    if (st0 == 0) { __to_dispst_str(s, st1); s[2] = 'H'; s[3] = '\0'; }
5531    /* z with hiz 1 strength component is L */
5532    else if (st1 == 0) { __to_dispst_str(s, st0); s[2] = 'L'; s[3] = '\0'; }
5533    else { ch = 'X'; break; }
5534    return(s);
5535   default: __case_terr(__FILE__, __LINE__); return(NULL);
5536  }
5537 
5538  /* finally known case strength is range with value */
5539  /* notice strength letters always 2 chars */
5540  if (st0 == st1)
5541   {
5542    /* DBG remove --- */
5543    /* for normal value strength cannot both be 0 */
5544    if (st0 == 0) __misc_terr(__FILE__, __LINE__);
5545    /* --- */
5546    __to_dispst_str(s, st0);
5547    s[2] = ch;
5548   }
5549  else { s[0] = '0' + st0; s[1] = '0' + st1; s[2] = ch; }
5550  s[3] = '\0';
5551  return(s);
5552 }
5553 
5554 /*
5555  * convert a 2 bit number to its verilog value name
5556  */
__to_vvnam(char * s,word32 v)5557 extern char *__to_vvnam(char *s, word32 v)
5558 {
5559  switch ((byte) v) {
5560   case 0: strcpy(s, "0"); break;
5561   case 1: strcpy(s, "1"); break;
5562   case 2: strcpy(s, "z"); break;
5563   case 3: default: strcpy(s, "x"); break;
5564  }
5565  return(s);
5566 }
5567 
5568 /* same but for udp 3-values */
__to_uvvnam(char * s,word32 v)5569 extern char *__to_uvvnam(char *s, word32 v)
5570 {
5571  switch ((byte) v) {
5572   case 0: strcpy(s, "0"); break;
5573   case 1: strcpy(s, "1"); break;
5574   default: strcpy(s, "x"); break;
5575  }
5576  return(s);
5577 }
5578 
5579 /*
5580  * convert base code to letter
5581  */
__to_baselet(int32 bcod)5582 extern char __to_baselet(int32 bcod)
5583 {
5584  char ch;
5585 
5586  switch ((byte) bcod) {
5587   case BBIN: ch = 'b'; break;
5588   case BHEX: ch = 'h'; break;
5589   case BOCT: ch = 'o'; break;
5590   case BDEC: ch = 'd'; break;
5591   default: ch = '?'; __case_terr(__FILE__, __LINE__);
5592  }
5593  return(ch);
5594 }
5595 
5596 /*
5597  * convert time unit string (0-15) code to time unit name
5598  */
__to_timunitnam(char * s,word32 unit)5599 extern char *__to_timunitnam(char *s, word32 unit)
5600 {
5601  switch ((byte) unit) {
5602   case 0: strcpy(s, "1 s"); break;
5603   case 1: strcpy(s, "100 ms"); break;
5604   case 2: strcpy(s, "10 ms"); break;
5605   case 3: strcpy(s, "1 ms"); break;
5606   case 4: strcpy(s, "100 us"); break;
5607   case 5: strcpy(s, "10 us"); break;
5608   case 6: strcpy(s, "1 us"); break;
5609   case 7: strcpy(s, "100 ns"); break;
5610   case 8: strcpy(s, "10 ns"); break;
5611   case 9: strcpy(s, "1 ns"); break;
5612   case 10: strcpy(s, "100 ps"); break;
5613   case 11: strcpy(s, "10 ps"); break;
5614   case 12: strcpy(s, "1 ps"); break;
5615   case 13: strcpy(s, "100 fs"); break;
5616   case 14: strcpy(s, "10 fs"); break;
5617   case 15: strcpy(s, "1 fs"); break;
5618   default: __case_terr(__FILE__, __LINE__);
5619  }
5620  return(s);
5621 }
5622 
5623 /*
5624  * convert an edge bit byte into an edge name string
5625  * if posedge or negedge use name else use [...] form
5626  */
__to_edgenam(char * s,word32 eval)5627 extern char *__to_edgenam(char *s, word32 eval)
5628 {
5629  int32 first_time;
5630  byte ebyte;
5631 
5632  switch ((ebyte = (byte) eval)) {
5633   case E_POSEDGE: strcpy(s, "posedge"); break;
5634   case E_NEGEDGE: strcpy(s, "negedge"); break;
5635   case NOEDGE: strcpy(s, ""); break;
5636   default:
5637    strcpy(s, "edge[");
5638    first_time = TRUE;
5639    if ((ebyte & EDGE01) != 0)
5640     {
5641      if (first_time) first_time = FALSE; else strcat(s, ", ");
5642      strcat(s, "01");
5643     }
5644    if ((ebyte & EDGE10) != 0)
5645     {
5646      if (first_time) first_time = FALSE; else strcat(s, ", ");
5647      strcat(s, "10");
5648     }
5649    if ((ebyte & EDGE0X) != 0)
5650     {
5651      if (first_time) first_time = FALSE; else strcat(s, ", ");
5652      strcat(s, "0x");
5653     }
5654    if ((ebyte & EDGEX1) != 0)
5655     {
5656      if (first_time) first_time = FALSE; else strcat(s, ", ");
5657      strcat(s, "x1");
5658     }
5659    if ((ebyte & EDGE1X) != 0)
5660     {
5661      if (first_time) first_time = FALSE; else strcat(s, ", ");
5662      strcat(s, "1x");
5663     }
5664    if ((ebyte & EDGEX0) != 0)
5665     {
5666      if (first_time) first_time = FALSE; else strcat(s, ", ");
5667      strcat(s, "x0");
5668     }
5669    strcat(s, "]");
5670   }
5671  return(s);
5672 }
5673 
5674 /*
5675  * convert an delay control type to a name
5676  */
__to_dcenam(char * s,word32 dctyp)5677 extern char *__to_dcenam(char *s, word32 dctyp)
5678 {
5679  switch ((byte) dctyp) {
5680   case DC_NONE: strcpy(s, "**NONE?**"); break;
5681   case DC_EVENT: strcpy(s,"event"); break;
5682   case DC_DELAY: strcpy(s, "delay"); break;
5683   case DC_RHSEVENT:strcpy(s,"rhs event"); break;
5684   case DC_RHSDELAY:strcpy(s, "rhs delay"); break;
5685   case DC_WAITEVENT: strcpy(s,"wait event"); break;
5686   default: __case_terr(__FILE__, __LINE__);
5687  }
5688  return(s);
5689 }
5690 
5691 /*
5692  * SPECIAL MEMORY ALLOCATION ROUTINES
5693  * USES OWN STRUCT AND CONSTANTS BELOW
5694  */
5695 
5696 /*
5697  * allocate a string for use during elaboration - adds the ending \0
5698  * this must allocate the 1 char null string for `define as flag
5699  */
__pv_stralloc(char * s)5700 extern char *__pv_stralloc(char *s)
5701 {
5702  char *cp;
5703  int32 slen;
5704 
5705  if (*s == '\0') slen = 1; else slen = strlen(s) + 1;
5706  cp = __my_malloc(slen);
5707  __memstr_use += slen;
5708  /* this just copies '\0' for "" case */
5709  strcpy(cp, s);
5710  return(cp);
5711 }
5712 
5713 /*
5714  * memory allocator for non freed memory
5715  * and allocate small piece from a large allocated block
5716  * aligns on 4 byte boundaries for VAX and 68000 too
5717  * notice this is 32 bit word32 dependent
5718  *
5719  * could save space in pc by allocating only on bytes but would need always
5720  * at least 4 bytes - no since now using free by size header table
5721  */
nfbig_alloc(int32 size)5722 static char *nfbig_alloc(int32 size)
5723 {
5724  char *cp;
5725  int32 rem, real_size;
5726 
5727  if ((rem = size % 4) != 0) real_size = size + 4 - rem;
5728  else real_size = size;
5729 
5730  if ((__start_sp + real_size + 4) >= __end_sp)
5731   {
5732    __start_sp = __my_malloc(BIG_ALLOC_SIZE);
5733    __end_sp = __start_sp + BIG_ALLOC_SIZE - 16;
5734   }
5735  cp = __start_sp;
5736  __start_sp += real_size;
5737  return(cp);
5738 }
5739 
5740 /*
5741  * call to malloc that dies if no memory available
5742  * these are normal OS memory allocation with error terminaton
5743  */
__my_malloc(int32 size)5744 extern char *__my_malloc(int32 size)
5745 {
5746  char *cp;
5747 
5748  /* DBG remove --- */
5749  if (size <= 0) __arg_terr(__FILE__, __LINE__);
5750  /* --- */
5751 
5752  if ((cp = (char *) malloc((word32) size)) == NULL)
5753   {
5754    __sysfatal_msg(
5755    "**fatal err[1]: No more memory - at file %s line %d allocated %ld bytes\n",
5756     __cur_fnam, __lin_cnt, __mem_use);
5757    __my_exit(4, TRUE);
5758   }
5759  __mem_use += size;
5760  __mem_allocated += size;
5761  /* DBG remove ---
5762  if (__debug_flg) __dbg_msg("my_malloc - allocated %d bytes - use %ld\n",
5763    size, __mem_use);
5764  --- */
5765  return(cp);
5766 }
5767 
5768 /*
5769  * call to free
5770  */
__my_free(char * mp,int32 size)5771 extern void __my_free(char *mp, int32 size)
5772 {
5773  /* DBG remove --- */
5774  if (size <= 0) return;
5775  /* --- */
5776  free(mp);
5777  __mem_use -= size;
5778  __mem_freed += size;
5779  /* DBG remove ---
5780  if (__debug_flg) __dbg_msg("freeing %d bytes - memuse now %ld\n", size,
5781   __mem_use);
5782  --- */
5783 }
5784 
5785 /*
5786  * interface to system realloc()
5787  * can only call with malloced mp or cannot realloc
5788  */
__my_realloc(char * mp,int32 osize,int32 nsize)5789 extern char *__my_realloc(char *mp, int32 osize, int32 nsize)
5790 {
5791  char *cp;
5792 
5793  if ((cp = (char *) realloc(mp, (word32) nsize)) == NULL)
5794   {
5795    __sysfatal_msg(
5796     "**fatal err[1]: realloc failed - allocated %ld bytes\n", __mem_use);
5797    __my_exit(4, TRUE);
5798   }
5799  /* DBG remove ---
5800  if (__debug_flg)
5801   __dbg_msg("realloc: freeing %d byte and allocating %d bytes\n",
5802    osize, nsize);
5803  --- */
5804  __mem_use -= osize;
5805  __mem_use += nsize;
5806  return(cp);
5807 }
5808 
5809 /*
5810  *  INTERFACE TO OS ROUTINES
5811  */
5812 
5813 /*
5814  * version of fclose that ends with fatal error if cannot close
5815  * some unixes do not return anything on fclose failure
5816  */
__my_fclose(FILE * f)5817 extern void __my_fclose(FILE *f)
5818 {
5819  if (f == NULL) __misc_terr(__FILE__, __LINE__);
5820  if (fclose(f) == EOF)
5821   {
5822    __crit_msg("**fatal err[1]: OS fclose failed: %s\n", strerror(errno));
5823    __my_exit(5, TRUE);
5824   }
5825 }
5826 
5827 
5828 /*
5829  * version of fd close that ends with fatal error if cannot close
5830  * some unixes do not return anything on close failure
5831  */
__my_close(int32 fd)5832 extern void __my_close(int32 fd)
5833 {
5834  if (fd == -1) __misc_terr(__FILE__, __LINE__);
5835  if (close(fd) == -1)
5836   {
5837    __crit_msg("**fatal err[1]: OS fclose failed: %s\n", strerror(errno));
5838    __my_exit(5, TRUE);
5839   }
5840 }
5841 
5842 /*
5843  * interface to system rewind routine
5844  */
__my_rewind(FILE * f)5845 extern void __my_rewind(FILE *f)
5846 {
5847  if (fseek(f, 0L, 0) == -1)
5848   {
5849    __crit_msg("**fatal err[1]: OS rewind failed: %s\n", strerror(errno));
5850    __my_exit(5, TRUE);
5851   }
5852 }
5853 
5854 /*
5855  * version of unbuffered open that performs tilde expansion
5856  * FIXME - should allow ~[dir] form and look at some network directory
5857  * and allow ~ anywhere in path name
5858  */
__tilde_open(char * pthnam,int32 opmask)5859 extern int32 __tilde_open(char *pthnam, int32 opmask)
5860 {
5861  int32 newlen;
5862  char *chp;
5863  int32 fd;
5864 
5865  if (*pthnam != '~') return(open(pthnam, opmask));
5866  if ((chp = tilde_expand(pthnam, &newlen)) == NULL) return(-1);
5867  fd = open(chp, opmask);
5868  __my_free(chp, newlen);
5869  return(fd);
5870 }
5871 
5872 /*
5873  * open with expand of leading tilde in file name using home
5874  */
__tilde_fopen(char * pthnam,char * opmod)5875 extern FILE *__tilde_fopen(char *pthnam, char *opmod)
5876 {
5877  int32 newlen;
5878  char *chp;
5879  FILE *f;
5880 
5881  if (*pthnam != '~') return(__my_fopen(pthnam, opmod));
5882  if ((chp = tilde_expand(pthnam, &newlen)) == NULL) return(NULL);
5883  f = __my_fopen(chp, opmod);
5884  __my_free(chp, newlen);
5885  return(f);
5886 }
5887 
5888 /*
5889  * perform prefix tilde expansion
5890  * only called if path starts with tilde
5891  * notice for now silently returns
5892  *
5893  * LOOKATME could allow /~/ component anywhere in path name for net addrs?
5894  */
tilde_expand(char * pthnam,int32 * newlen)5895 static char *tilde_expand(char *pthnam, int32 *newlen)
5896 {
5897  char *chp, *chp2;
5898  int32 hlen, plen;
5899  char usernam[RECLEN];
5900 
5901  /* first ~/ form */
5902  if (pthnam[1] == '/') { chp2 = __pv_homedir; goto bld_expanded; }
5903 
5904  /* ~[user] form - look up if possible */
5905  if ((chp = strchr(pthnam, '/')) == NULL) return(NULL);
5906  strncpy(usernam, &(pthnam[1]), chp - pthnam - 1);
5907  usernam[chp - pthnam - 1] = '\0';
5908  /* pathname now has / prefix but ~[name] removed */
5909  pthnam = chp - 1;
5910 
5911  /* if do not know system, assume vanilla non networked BSD unix */
5912  {
5913   struct passwd *pwp;
5914 
5915   if ((pwp = getpwnam(usernam)) == NULL) return(NULL);
5916   chp2 = pwp->pw_dir;
5917  }
5918  goto bld_expanded;
5919 
5920 bld_expanded:
5921  /* know home dir does not have ending / and . if HOMEDIR not set */
5922  hlen = strlen(chp2);
5923  plen = strlen(pthnam);
5924  *newlen = hlen - 1 + plen + 1;
5925  chp = __my_malloc(*newlen);
5926  strcpy(chp, chp2);
5927  strcpy(&(chp[hlen]), &(pthnam[1]));
5928  return(chp);
5929 }
5930 
5931 /*
5932  * unbuffered creat for writing with expand leading tilde in file name using
5933  */
__tilde_creat(char * pthnam)5934 extern int32 __tilde_creat(char *pthnam)
5935 {
5936  int32 newlen;
5937  char *chp;
5938  int32 fd;
5939 
5940  if (*pthnam != '~') return(__my_creat(pthnam));
5941  if ((chp = tilde_expand(pthnam, &newlen)) == NULL) return(-1);
5942  fd = __my_creat(chp);
5943  __my_free(chp, newlen);
5944  return(fd);
5945 }
5946 
5947 /*
5948  * version of open that returns NULL when directory opened
5949  * unix allows opening directories for reading
5950  */
__my_fopen(char * fnam,char * opmod)5951 extern FILE *__my_fopen(char *fnam, char *opmod)
5952 {
5953  FILE *f;
5954  struct stat sbuf;
5955 
5956  if ((f = fopen(fnam, opmod)) == NULL) return(NULL);
5957  if (fstat(fileno(f), &sbuf) == -1)
5958   {
5959    __crit_msg("**fatal err[1]: OS file stat operation failed: %s\n",
5960     strerror(errno));
5961    __my_exit(5, TRUE);
5962   }
5963  /* anything but directory is ok */
5964  if ((S_IFDIR & sbuf.st_mode) == 0) return(f);
5965 
5966  /* ---
5967  __inform(417, "open failed because %s is directory or special file", fnam);
5968  --- */
5969  __my_fclose(f);
5970  return(NULL);
5971 }
5972 
5973 /*
5974  * version of non buffered creat that returns -1 when directory opened
5975  * unix allows opening directories for reading
5976  */
__my_creat(char * fnam)5977 extern int32 __my_creat(char *fnam)
5978 {
5979  int32 fd;
5980  struct stat sbuf;
5981 
5982  if ((fd = creat(fnam, 0666)) == -1) return(-1);
5983  if (fstat(fd, &sbuf) == -1)
5984   {
5985    __crit_msg("**fatal err[1]: OS file stat operation failed: %s\n",
5986     strerror(errno));
5987    __my_exit(5, TRUE);
5988   }
5989  /* anything but directory is ok */
5990  if ((S_IFDIR & sbuf.st_mode) == 0) return(fd);
5991 
5992  /* ---
5993  __inform(417, "open failed because %s is directory or special file", fnam);
5994  --- */
5995  close(fd);
5996  return(-1);
5997 }
5998 
5999 /*
6000  * routine to truncate (chop) a string for output
6001  * one constant per run value for ID string chopped length
6002  * notice this always copies
6003  */
__schop(char * s1,char * s2)6004 extern char *__schop(char *s1, char *s2)
6005 {
6006  int32 slen, sendi;
6007 
6008  slen = strlen(s2);
6009  if (slen < (sendi = MSGTRUNCLEN - 4)) strcpy(s1, s2);
6010  else { strncpy(s1, s2, sendi); strcpy(&s1[sendi], "..."); }
6011  return(s1);
6012 }
6013 
6014 /*
6015  * build a **<file>(<line. no.) reference
6016  * this chops file name so know will fit
6017  * s must be RECLEN wide
6018  */
__bld_lineloc(char * s,word32 fnind,int32 fnlcnt)6019 extern char *__bld_lineloc(char *s, word32 fnind, int32 fnlcnt)
6020 {
6021  char s1[RECLEN];
6022 
6023  sprintf(s, "**%s(%d)", __schop(s1, __in_fils[fnind]), fnlcnt);
6024  return(s);
6025 }
6026 
6027 /*
6028  * MESSAGE ROUTINES
6029  */
6030 
6031 /*
6032  * intellectual property (IP) message unsuppressable except by special simctrlb
6033  * IP messages suppression also stops log
6034  */
6035 /*VARARGS*/
__ip_msg(char * s,...)6036 extern void __ip_msg(char *s, ...)
6037 {
6038  va_list va, va2;
6039 
6040  /* SJM 10/13/99 - ansii std says varargs not usable after vprintf called */
6041  va_start(va, s);
6042  va_start(va2, s);
6043  vfprintf(stdout, s, va);
6044  if (__log_s != NULL) vfprintf(__log_s, s, va2);
6045  va_end(va);
6046  va_end(va2);
6047 }
6048 
6049 /*
6050  * intellectual property (IP) message
6051  *
6052  * suppressable before customer1 cb if -q flag
6053  * IP messages suppression also stops log
6054  */
6055 /*VARARGS*/
__ip2_msg(char * s,...)6056 extern void __ip2_msg(char *s, ...)
6057 {
6058  va_list va, va2;
6059 
6060  if (__quiet_msgs) return;
6061 
6062  /* SJM 10/13/99 - ansii std says varargs not usable after vprintf called */
6063  va_start(va, s);
6064  va_start(va2, s);
6065  vfprintf(stdout, s, va);
6066  if (__log_s != NULL) vfprintf(__log_s, s, va2);
6067  va_end(va);
6068  va_end(va2);
6069 }
6070 
6071 /*
6072  * critical Copyright, licensing, OS failure, malloc failure etc.
6073  * never suppressed
6074  */
6075 /*VARARGS*/
__crit_msg(char * s,...)6076 extern void __crit_msg(char *s, ...)
6077 {
6078  va_list va, va2;
6079 
6080 
6081  /* SJM 10/13/99 - ansii std says varargs not usable after vprintf called */
6082  va_start(va, s);
6083  va_start(va2, s);
6084  vfprintf(stdout, s, va);
6085  if (__log_s != NULL) vfprintf(__log_s, s, va2);
6086  va_end(va);
6087  va_end(va2);
6088 }
6089 
6090 /*
6091  * never suppressed special OS failure (can't call malloc or os calls)
6092  * vendor 1 must detect -4 (inverse of vpi vpiSystem error level)
6093  * BEWARE - this can't call system or malloc
6094  */
6095 /*VARARGS*/
__sysfatal_msg(char * s,...)6096 extern void __sysfatal_msg(char *s, ...)
6097 {
6098  va_list va, va2;
6099 
6100 
6101  /* SJM 10/13/99 - ansii std says varargs not usable after vprintf called */
6102  va_start(va, s);
6103  va_start(va2, s);
6104  vfprintf(stdout, s, va);
6105  if (__log_s != NULL) vfprintf(__log_s, s, va2);
6106  va_end(va);
6107  va_end(va2);
6108 }
6109 
6110 /*
6111  * all normal (supressable with -q) messages
6112  * Cver progress, -d, status options
6113  */
6114 /*VARARGS*/
__cv_msg(char * s,...)6115 extern void __cv_msg(char *s, ...)
6116 {
6117  va_list va, va2;
6118 
6119  if (__quiet_msgs) return;
6120 
6121  /* SJM 10/13/99 - ansii std says varargs not usable after vprintf called */
6122  va_start(va, s);
6123  va_start(va2, s);
6124  vfprintf(stdout, s, va);
6125  if (__log_s != NULL) vfprintf(__log_s, s, va2);
6126  va_end(va);
6127  va_end(va2);
6128 }
6129 
6130 /*
6131  * cver simulation output messages (from system tasks such as $showvars)
6132  * version 1 to both stdout and log file
6133  *
6134  * also all debugger output since interchangeable with system tasks
6135  * never suppressed
6136  */
6137 /*VARARGS*/
__cvsim_msg(char * s,...)6138 extern void __cvsim_msg(char *s, ...)
6139 {
6140  va_list va, va2;
6141 
6142  /* SJM 10/13/99 - ansii std says varargs not usable after vprintf called */
6143  va_start(va, s);
6144  va_start(va2, s);
6145  vfprintf(stdout, s, va);
6146  if (__log_s != NULL) vfprintf(__log_s, s, va2);
6147  va_end(va);
6148  va_end(va2);
6149 }
6150 
6151 /*
6152  * cver simulation output messages - * version 2 to just stdout
6153  */
6154 /*VARARGS*/
__cvsim2_msg(char * s,...)6155 extern void __cvsim2_msg(char *s, ...)
6156 {
6157  va_list va;
6158 
6159  va_start(va, s);
6160  vfprintf(stdout, s, va);
6161  va_end(va);
6162 }
6163 
6164 /*
6165  * cver simulation output messages
6166  * version 3 only to log file
6167  *
6168  * from system tasks such as $showvars and debugger output
6169  * never suppressed and log file not suppresable
6170  */
6171 /*VARARGS*/
__cvsim3_msg(char * s,...)6172 extern void __cvsim3_msg(char *s, ...)
6173 {
6174  va_list va;
6175 
6176  va_start(va, s);
6177  if (__log_s != NULL) vfprintf(__log_s, s, va);
6178  va_end(va);
6179 }
6180 
6181 /*
6182  * debugger (not debugger output) messages - not callback stopable
6183  * goes to both stdout and log file
6184  */
6185 /*VARARGS*/
__dbg_msg(char * s,...)6186 extern void __dbg_msg(char *s, ...)
6187 {
6188  va_list va;
6189  va_list va2;
6190 
6191  va_start(va, s);
6192  va_start(va2, s);
6193  __my_vfprintf(stdout, s, va, va2);
6194  va_end(va2);
6195  va_end(va);
6196 }
6197 
6198 /*
6199  * trace message printf - to trace file unless stdout (the default)
6200  * LOOATME - maybe should default trace file to verilog.trace
6201  */
6202 /*VARARGS*/
__tr_msg(char * s,...)6203 extern void __tr_msg(char *s, ...)
6204 {
6205  va_list va, va2;
6206 
6207  /* SJM 10/13/99 - ansii std says varargs not usable after vprintf called */
6208  va_start(va, s);
6209  va_start(va2, s);
6210  vfprintf(__tr_s, s, va);
6211  if (__tr_s == stdout && __log_s != NULL) vfprintf(__log_s, s, va2);
6212  va_end(va);
6213  va_end(va2);
6214 }
6215 
6216 /*
6217  * ERROR MESSAGE ROUTINES
6218  */
6219 
6220 /*
6221  * miscellaneous (most) internal fatal errors
6222  */
__misc_terr(char * fnam,int32 lno)6223 extern void __misc_terr(char *fnam, int32 lno)
6224 {
6225  /* SJM DBG REMOVE - malloc_chain_check(1); */
6226  if (lno == -1039)
6227   {
6228    __pv_terr(304,
6229      "cver.lic file or single job lock invalid or removed - run licprobe -lockcheck");
6230   }
6231  __pv_terr(303,
6232   "MISC INTERNAL - source line **%s(%d) - maybe at **%s(%d) or **%s(%d)",
6233   fnam, lno, __cur_fnam, __lin_cnt, __in_fils[__sfnam_ind], __slin_cnt);
6234 }
6235 
6236 /*
6237  * file miscellaneous (most) internal fatal errors (input file place known)
6238  */
__misc_fterr(char * fnam,int32 lno)6239 extern void __misc_fterr(char *fnam, int32 lno)
6240 {
6241  __fterr(303, "MISC INTERNAL - source line **%s(%d)", fnam, lno);
6242 }
6243 
6244 /*
6245  * global analysis phase internal error - object provides line number
6246  */
__misc_gfterr(char * fnam,int32 lno,word32 gfnam_ind,int32 gflin_cnt)6247 extern void __misc_gfterr(char *fnam, int32 lno, word32 gfnam_ind,
6248  int32 gflin_cnt)
6249 {
6250  __gfterr(303, gfnam_ind, gflin_cnt,
6251   "MISC INTERNAL - source line **%s(%d)", fnam, lno);
6252 }
6253 
6254 /*
6255  * non execution statement type error __sfnam_ind contains location
6256  */
__misc_sgfterr(char * fnam,int32 lno)6257 extern void __misc_sgfterr(char *fnam, int32 lno)
6258 {
6259  __gfterr(303, __sfnam_ind, __slin_cnt,
6260   "MISC INTERNAL - source lint **%s(%d)", fnam, lno);
6261 }
6262 
6263 /*
6264  * simple case fatal error - can always find with debugger
6265  */
__case_terr(char * fnam,int32 lno)6266 extern void __case_terr(char *fnam, int32 lno)
6267 {
6268  __pv_terr(324,
6269   "CASE INTERNAL - source line **%s(%d) - maybe at **%s(%d) or **%s(%d)",
6270   fnam, lno, __cur_fnam, __lin_cnt, __in_fils[__sfnam_ind], __slin_cnt);
6271 }
6272 
6273 /*
6274  * simple argument passed to routine internal error
6275  */
__arg_terr(char * fnam,int32 lno)6276 extern void __arg_terr(char *fnam, int32 lno)
6277 {
6278  __pv_terr(322,
6279   "ARG INTERNAL - source line **%s(%d) - maybe at **%s(%d) or **%s(%d)",
6280   fnam, lno, __cur_fnam, __lin_cnt, __in_fils[__sfnam_ind], __slin_cnt);
6281 }
6282 
6283 /*
6284  * error with fatal termination
6285  * arg s is a format specification string for sprintf
6286  *
6287  * notice error messages longer than 4k bytes will cause crash
6288  * caller of error routines must make sure no more than 4 ID called
6289  */
__pv_terr(int32 id_num,char * s,...)6290 extern void __pv_terr(int32 id_num, char *s, ...)
6291 {
6292  va_list va, va2, va3;
6293  int32 slen;
6294  char vpis1[IDLEN], vpis2[4*IDLEN], *vpichp;
6295 
6296  if (__vpierr_cb_active && !__iact_state)
6297   {
6298    /* reset in case user called sim control operation from wrong place */
6299    __errorcb_suppress_msg = FALSE;
6300 
6301    sprintf(vpis1, "**FATAL ERROR** [%d] ", id_num);
6302    va_start(va, s);
6303    vsprintf(vpis2, s, va);
6304    va_end(va);
6305 
6306    slen = strlen(vpis1) + strlen(vpis2) + 1;
6307    vpichp = __my_malloc(slen);
6308    strcpy(vpichp, vpis1);
6309    strcat(vpichp, vpis2);
6310 
6311    __cberror_fill_einfo(FATAL, id_num, vpichp, "[NONE]", 0);
6312    __vpi_error_trycall();
6313 
6314    __my_free(vpichp, slen);
6315    /* if vpi_ontrol used to suppress emsg, used up so turned off here */
6316    if (__errorcb_suppress_msg)
6317     { __errorcb_suppress_msg = FALSE; __my_exit(1, TRUE); }
6318   }
6319  __my_fprintf(stdout, "**FATAL ERROR** [%d] ", id_num);
6320 
6321  /* SJM 10/13/99 - ansii std says varargs not usable after vprintf called */
6322  va_start(va2, s);
6323  va_start(va3, s);
6324  __my_vfprintf(stdout, s, va2, va3);
6325  va_end(va2);
6326  va_end(va3);
6327  my_putc_('\n', stdout);
6328  __my_exit(1, TRUE);
6329 }
6330 
6331 /*
6332  * vpi error with fatal termination and no error cb try call
6333  * arg s is a format specification string for sprintf
6334  *
6335  * notice error messages longer than 4k bytes will cause crash
6336  * caller of error routines must make sure no more than 4 ID called
6337  */
__pv_vpi_terr(int32 id_num,char * s,...)6338 extern void __pv_vpi_terr(int32 id_num, char *s, ...)
6339 {
6340  va_list va, va2, va3;
6341  int32 slen;
6342  char vpis1[IDLEN], vpis2[4*IDLEN], *vpichp;
6343 
6344  if (__vpierr_cb_active && !__iact_state)
6345   {
6346    /* reset in case user called sim control operation from wrong place */
6347    __errorcb_suppress_msg = FALSE;
6348 
6349    sprintf(vpis1, "**FATAL ERROR** [%d] ", id_num);
6350    va_start(va, s);
6351    vsprintf(vpis2, s, va);
6352    va_end(va);
6353 
6354    slen = strlen(vpis1) + strlen(vpis2) + 1;
6355    vpichp = __my_malloc(slen);
6356    strcpy(vpichp, vpis1);
6357    strcat(vpichp, vpis2);
6358 
6359    __my_free(vpichp, slen);
6360    /* if vpi_ontrol used to suppress emsg, used up so turned off here */
6361    if (__errorcb_suppress_msg)
6362     { __errorcb_suppress_msg = FALSE; __my_exit(1, TRUE); }
6363   }
6364  __my_fprintf(stdout, "**FATAL ERROR** [%d] ", id_num);
6365 
6366  /* SJM 10/13/99 - ansii std says varargs not usable after vprintf called */
6367  va_start(va2, s);
6368  va_start(va3, s);
6369  __my_vfprintf(stdout, s, va2, va3);
6370  va_end(va2);
6371  va_end(va3);
6372  my_putc_('\n', stdout);
6373  __my_exit(1, TRUE);
6374 }
6375 
6376 /*
6377  * note ferr forms all take a variable prefix for acc_ and tf_ and debugger
6378  */
6379 
6380 /*VARARGS*/
__fterr(int32 id_num,char * s,...)6381 extern void __fterr(int32 id_num, char *s, ...)
6382 {
6383  va_list va, va2, va3;
6384  int32 slen;
6385  char vpis1[IDLEN], vpis2[4*IDLEN], *vpichp;
6386 
6387  if (__vpierr_cb_active && !__iact_state)
6388   {
6389    /* reset in case user called sim control operation from wrong place */
6390    __errorcb_suppress_msg = FALSE;
6391 
6392    sprintf(vpis1, "**%s(%d) FATAL ERROR** [%d] ", __cur_fnam,
6393     __lin_cnt, id_num);
6394    va_start(va, s);
6395    vsprintf(vpis2, s, va);
6396    va_end(va);
6397 
6398    slen = strlen(vpis1) + strlen(vpis2) + 1;
6399    vpichp = __my_malloc(slen);
6400    strcpy(vpichp, vpis1);
6401    strcat(vpichp, vpis2);
6402 
6403    __cberror_fill_einfo(FATAL, id_num, vpichp, __cur_fnam, __lin_cnt);
6404    __vpi_error_trycall();
6405 
6406    __my_free(vpichp, slen);
6407    /* if vpi_control used to suppress emsg, used up so turned off here */
6408    if (__errorcb_suppress_msg)
6409     { __errorcb_suppress_msg = FALSE; __my_exit(2, TRUE); }
6410   }
6411 
6412  __my_fprintf(stdout, "**%s(%d) FATAL ERROR** [%d] ", __cur_fnam,
6413   __lin_cnt, id_num);
6414 
6415  /* SJM 10/13/99 - ansii std says varargs not usable after vprintf called */
6416  va_start(va2, s);
6417  va_start(va3, s);
6418  __my_vfprintf(stdout, s, va2, va3);
6419  va_end(va2);
6420  va_end(va3);
6421  my_putc_('\n', stdout);
6422  __my_exit(2, TRUE);
6423 }
6424 
6425 /*VARARGS*/
__sgfterr(int32 id_num,char * s,...)6426 extern void __sgfterr(int32 id_num, char *s, ...)
6427 {
6428  va_list va, va2, va3;
6429  int32 slen;
6430  char vpis1[IDLEN], vpis2[4*IDLEN], *vpichp;
6431  char s1[RECLEN], s2[RECLEN];
6432 
6433  if (__run_state == SS_SIM)
6434   sprintf(s1, " now %s", __to_timstr(s2, &__simtime));
6435  else strcpy(s1, "");
6436 
6437  if (__vpierr_cb_active && !__iact_state)
6438   {
6439    /* reset in case user called sim control operation from wrong place */
6440    __errorcb_suppress_msg = FALSE;
6441 
6442    sprintf(vpis1, "**%s(%d) FATAL ERROR**%s [%d] ", __in_fils[__sfnam_ind],
6443     __slin_cnt, s1, id_num);
6444    va_start(va, s);
6445    vsprintf(vpis2, s, va);
6446    va_end(va);
6447 
6448    slen = strlen(vpis1) + strlen(vpis2) + 1;
6449    vpichp = __my_malloc(slen);
6450    strcpy(vpichp, vpis1);
6451    strcat(vpichp, vpis2);
6452 
6453    __cberror_fill_einfo(FATAL, id_num, vpichp, __in_fils[__sfnam_ind],
6454     __slin_cnt);
6455    __vpi_error_trycall();
6456 
6457    __my_free(vpichp, slen);
6458    /* if vpi_control used to suppress emsg, used up so turned off here */
6459    if (__errorcb_suppress_msg)
6460     { __errorcb_suppress_msg = FALSE; __my_exit(2, TRUE); }
6461   }
6462 
6463  __my_fprintf(stdout, "**%s(%d) FATAL ERROR**%s [%d] ",
6464   __in_fils[__sfnam_ind], __slin_cnt, s1, id_num);
6465 
6466  /* SJM 10/13/99 - ansii std says varargs not usable after vprintf called */
6467  va_start(va2, s);
6468  va_start(va3, s);
6469  __my_vfprintf(stdout, s, va2, va3);
6470  va_end(va2);
6471  va_end(va3);
6472  my_putc_('\n', stdout);
6473  __my_exit(2, TRUE);
6474 }
6475 
6476 /*VARARGS*/
__gfterr(int32 id_num,word32 gfnam_ind,int32 gflin_cnt,char * s,...)6477 extern void __gfterr(int32 id_num, word32 gfnam_ind, int32 gflin_cnt,
6478  char *s, ...)
6479 {
6480  va_list va, va2, va3;
6481  int32 slen;
6482  char vpis1[IDLEN], vpis2[4*IDLEN], *vpichp;
6483  char s1[RECLEN], s2[RECLEN];
6484 
6485  if (__run_state == SS_SIM)
6486   sprintf(s1, " now %s", __to_timstr(s2, &__simtime));
6487  else strcpy(s1, "");
6488 
6489  if (__vpierr_cb_active && !__iact_state)
6490   {
6491    /* reset in case user called sim control operation from wrong place */
6492    __errorcb_suppress_msg = FALSE;
6493 
6494    sprintf(vpis1, "**%s(%d) FATAL ERROR**%s [%d] ",
6495     __in_fils[gfnam_ind], gflin_cnt, s1, id_num);
6496    va_start(va, s);
6497    vsprintf(vpis2, s, va);
6498    va_end(va);
6499 
6500    slen = strlen(vpis1) + strlen(vpis2) + 1;
6501    vpichp = __my_malloc(slen);
6502    strcpy(vpichp, vpis1);
6503    strcat(vpichp, vpis2);
6504 
6505    __cberror_fill_einfo(FATAL, id_num, vpichp, __in_fils[gfnam_ind],
6506     gflin_cnt);
6507    __vpi_error_trycall();
6508 
6509    __my_free(vpichp, slen);
6510    /* if vpi_control used to suppress emsg, used up so turned off here */
6511    if (__errorcb_suppress_msg)
6512     { __errorcb_suppress_msg = FALSE; __my_exit(2, TRUE); }
6513   }
6514 
6515  __my_fprintf(stdout, "**%s(%d) FATAL ERROR**%s [%d] ",
6516   __in_fils[gfnam_ind], gflin_cnt, s1, id_num);
6517 
6518  /* SJM 10/13/99 - ansii std says varargs not usable after vprintf called */
6519  va_start(va2, s);
6520  va_start(va3, s);
6521  __my_vfprintf(stdout, s, va2, va3);
6522  va_end(va2);
6523  va_end(va3);
6524  my_putc_('\n', stdout);
6525  __my_exit(2, TRUE);
6526 }
6527 
6528 /*
6529  * serious but non-fatal error
6530  */
6531 /*VARARGS*/
__pv_err(int32 id_num,char * s,...)6532 extern void __pv_err(int32 id_num, char *s, ...)
6533 {
6534  va_list va, va2, va3;
6535  int32 slen;
6536  char vpis1[IDLEN], vpis2[4*IDLEN], *vpichp;
6537 
6538  __pv_err_cnt++;
6539  if (!__no_errs)
6540   {
6541    if (__vpierr_cb_active && !__iact_state)
6542     {
6543      /* reset in case user called sim control operation from wrong place */
6544      __errorcb_suppress_msg = FALSE;
6545 
6546      sprintf(vpis1, "** ERROR** [%d] ", id_num);
6547      va_start(va, s);
6548      vsprintf(vpis2, s, va);
6549      va_end(va);
6550 
6551      slen = strlen(vpis1) + strlen(vpis2) + 1;
6552      vpichp = __my_malloc(slen);
6553      strcpy(vpichp, vpis1);
6554      strcat(vpichp, vpis2);
6555 
6556      __cberror_fill_einfo(ERROR, id_num, vpichp, "[NONE]", 0);
6557      __vpi_error_trycall();
6558 
6559      __my_free(vpichp, slen);
6560      /* if vpi_control used to suppress emsg, used up so turn off here */
6561      if (__errorcb_suppress_msg)
6562       { __errorcb_suppress_msg = FALSE; return; }
6563     }
6564    __my_fprintf(stdout, "** ERROR** [%d] ", id_num);
6565 
6566    /* SJM 10/13/99 - ansii std says varargs not usable after vprintf called */
6567    va_start(va2, s);
6568    va_start(va3, s);
6569    __my_vfprintf(stdout, s, va2, va3);
6570    va_end(va2);
6571    va_end(va3);
6572 
6573    my_putc_('\n', stdout);
6574   }
6575  if (__run_state == SS_SIM)
6576  if ((__run_state == SS_COMP || __run_state == SS_LOAD)
6577   && __max_errors != 0 && __pv_err_cnt > __max_errors)
6578   __pv_terr(id_num, "maximum error count exceeded");
6579 }
6580 
6581 /*VARARGS*/
__pv_ferr(int32 id_num,char * s,...)6582 extern void __pv_ferr(int32 id_num, char *s, ...)
6583 {
6584  va_list va, va2, va3;
6585  int32 slen;
6586  char vpis1[IDLEN], vpis2[4*IDLEN], *vpichp;
6587 
6588  __pv_err_cnt++;
6589  if (__iact_state)
6590   {
6591    /* SJM 10/13/99 - ansii std says varargs not usable after vprintf called */
6592    va_start(va, s);
6593    va_start(va2, s);
6594    __via_err(id_num, s, va, va2);
6595    va_end(va);
6596    va_end(va2);
6597    return;
6598   }
6599 
6600  if (!__no_errs)
6601   {
6602    if (__vpierr_cb_active)
6603     {
6604      /* reset in case user called sim control operation from wrong place */
6605      __errorcb_suppress_msg = FALSE;
6606 
6607      sprintf(vpis1, "**%s(%d) ERROR** [%d] ", __cur_fnam, __lin_cnt, id_num);
6608      va_start(va, s);
6609      vsprintf(vpis2, s, va);
6610      va_end(va);
6611 
6612      slen = strlen(vpis1) + strlen(vpis2) + 1;
6613      vpichp = __my_malloc(slen);
6614      strcpy(vpichp, vpis1);
6615      strcat(vpichp, vpis2);
6616 
6617      __cberror_fill_einfo(ERROR, id_num, vpichp, __cur_fnam, __lin_cnt);
6618      __vpi_error_trycall();
6619 
6620      __my_free(vpichp, slen);
6621      /* if vpi_control used to suppress emsg, used up so turn off here */
6622      if (__errorcb_suppress_msg)
6623       { __errorcb_suppress_msg = FALSE; return; }
6624     }
6625    __my_fprintf(stdout, "**%s(%d) ERROR** [%d] ", __cur_fnam, __lin_cnt,
6626     id_num);
6627 
6628    /* SJM 10/13/99 - ansii std says varargs not usable after vprintf called */
6629    va_start(va2, s);
6630    va_start(va3, s);
6631    __my_vfprintf(stdout, s, va2, va3);
6632    va_end(va2);
6633    va_end(va3);
6634    my_putc_('\n', stdout);
6635   }
6636  if ((__run_state == SS_COMP || __run_state == SS_LOAD)
6637   && __max_errors != 0 && __pv_err_cnt > __max_errors)
6638   __pv_terr(id_num, "maximum error count exceeded");
6639 }
6640 
6641 /*VARARGS*/
__sgferr(int32 id_num,char * s,...)6642 extern void __sgferr(int32 id_num, char *s, ...)
6643 {
6644  va_list va, va2, va3;
6645  int32 slen;
6646  char vpis1[IDLEN], vpis2[4*IDLEN], *vpichp;
6647  char s1[RECLEN], s2[RECLEN];
6648 
6649  __pv_err_cnt++;
6650  if (!__no_errs)
6651   {
6652    if (__run_state == SS_SIM)
6653     sprintf(s1, " now %s", __to_timstr(s2, &__simtime));
6654    else strcpy(s1, "");
6655 
6656    if (__vpierr_cb_active && !__iact_state)
6657     {
6658      /* reset in case user called sim control operation from wrong place */
6659      __errorcb_suppress_msg = FALSE;
6660 
6661      sprintf(vpis1, "**%s(%d) ERROR**%s [%d] ", __in_fils[__sfnam_ind],
6662       __slin_cnt, s1, id_num);
6663      va_start(va, s);
6664      vsprintf(vpis2, s, va);
6665      va_end(va);
6666 
6667      slen = strlen(vpis1) + strlen(vpis2) + 1;
6668      vpichp = __my_malloc(slen);
6669      strcpy(vpichp, vpis1);
6670      strcat(vpichp, vpis2);
6671 
6672      __cberror_fill_einfo(ERROR, id_num, vpichp, __in_fils[__sfnam_ind],
6673       __slin_cnt);
6674      __vpi_error_trycall();
6675 
6676      __my_free(vpichp, slen);
6677      /* if vpi_control used to suppress emsg, used up so turn off here */
6678      if (__errorcb_suppress_msg)
6679       { __errorcb_suppress_msg = FALSE; return; }
6680     }
6681 
6682    __my_fprintf(stdout, "**%s(%d) ERROR**%s [%d] ", __in_fils[__sfnam_ind],
6683     __slin_cnt, s1, id_num);
6684 
6685    /* SJM 10/13/99 - ansii std says varargs not usable after vprintf called */
6686    va_start(va2, s);
6687    va_start(va3, s);
6688    __my_vfprintf(stdout, s, va2, va3);
6689    va_end(va2);
6690    va_end(va3);
6691    my_putc_('\n', stdout);
6692   }
6693  if ((__run_state == SS_COMP || __run_state == SS_LOAD)
6694   && __max_errors != 0 && __pv_err_cnt > __max_errors)
6695   __pv_terr(id_num, "maximum error count exceeded");
6696 }
6697 
6698 /*VARARGS*/
__gferr(int32 id_num,word32 gfnam_ind,int32 gflin_cnt,char * s,...)6699 extern void __gferr(int32 id_num, word32 gfnam_ind, int32 gflin_cnt,
6700  char *s, ...)
6701 {
6702  va_list va, va2, va3;
6703  int32 slen;
6704  char vpis1[IDLEN], vpis2[4*IDLEN], *vpichp;
6705  char s1[RECLEN], s2[RECLEN];
6706 
6707  __pv_err_cnt++;
6708  if (!__no_errs)
6709   {
6710    if (__run_state == SS_SIM)
6711     sprintf(s1, " now %s", __to_timstr(s2, &__simtime));
6712    else strcpy(s1, "");
6713 
6714    if (__vpierr_cb_active && !__iact_state)
6715     {
6716      /* reset in case user called sim control operation from wrong place */
6717      __errorcb_suppress_msg = FALSE;
6718 
6719      sprintf(vpis1, "**%s(%d) ERROR**%s [%d] ", __in_fils[gfnam_ind],
6720       gflin_cnt, s1, id_num);
6721 
6722      va_start(va, s);
6723      vsprintf(vpis2, s, va);
6724      va_end(va);
6725 
6726      slen = strlen(vpis1) + strlen(vpis2) + 1;
6727      vpichp = __my_malloc(slen);
6728      strcpy(vpichp, vpis1);
6729      strcat(vpichp, vpis2);
6730 
6731      __cberror_fill_einfo(ERROR, id_num, vpichp, __in_fils[gfnam_ind],
6732       gflin_cnt);
6733      __vpi_error_trycall();
6734 
6735      __my_free(vpichp, slen);
6736      /* if vpi_control used to suppress emsg, used up so turn off here */
6737      if (__errorcb_suppress_msg)
6738       { __errorcb_suppress_msg = FALSE; return; }
6739     }
6740 
6741    __my_fprintf(stdout, "**%s(%d) ERROR**%s [%d] ", __in_fils[gfnam_ind],
6742     gflin_cnt, s1, id_num);
6743 
6744    /* SJM 10/13/99 - ansii std says varargs not usable after vprintf called */
6745    va_start(va2, s);
6746    va_start(va3, s);
6747    __my_vfprintf(stdout, s, va2, va3);
6748    va_end(va2);
6749    va_end(va3);
6750    my_putc_('\n', stdout);
6751   }
6752  if ((__run_state == SS_COMP || __run_state == SS_LOAD)
6753   && __max_errors != 0 && __pv_err_cnt > __max_errors)
6754   __pv_terr(id_num, "maximum error count exceeded");
6755 }
6756 
6757 /*
6758  * interactive command error
6759  * this output still goes to log file
6760  * notice this routine does not increment err number
6761  */
6762 /*VARARGS*/
__ia_err(int32 id_num,char * s,...)6763 extern void __ia_err(int32 id_num, char *s, ...)
6764 {
6765  va_list va, va2;
6766 
6767  /* can suppress any interactive error */
6768  if (__em_suppr(id_num)) return;
6769 
6770  /* SJM 10/13/99 - ansii std says varargs not usable after vprintf called */
6771  va_start(va, s);
6772  va_start(va2, s);
6773  __via_err(id_num, s, va, va2);
6774  va_end(va);
6775  va_end(va2);
6776 }
6777 
6778 /*VARARGS*/
__via_err(int32 id_num,char * s,va_list args,va_list args2)6779 extern void __via_err(int32 id_num, char *s, va_list args, va_list args2)
6780 {
6781  if (__cmd_s == NULL) __my_fprintf(stdout, "--CMD ERROR** [%d] ", id_num);
6782  else __my_fprintf(stdout, "--%s(%d) CMD ERROR** [%d] ", __cmd_fnam,
6783   __lin_cnt, id_num);
6784  __my_vfprintf(stdout, s, args, args2);
6785  my_putc_('\n', stdout);
6786 }
6787 
6788 /*VARARGS*/
__pv_warn(int32 id_num,char * s,...)6789 extern void __pv_warn(int32 id_num, char *s, ...)
6790 {
6791  va_list va, va2, va3;
6792  int32 slen;
6793  char vpis1[IDLEN], vpis2[4*IDLEN], *vpichp;
6794 
6795  __pv_warn_cnt++;
6796  if (__no_warns || __em_suppr(id_num)) return;
6797 
6798  if (__vpierr_cb_active && !__iact_state)
6799   {
6800    /* reset in case user called sim control operation from wrong place */
6801    __errorcb_suppress_msg = FALSE;
6802 
6803    sprintf(vpis1,"** WARN** [%d] ", id_num);
6804    va_start(va, s);
6805    vsprintf(vpis2, s, va);
6806    va_end(va);
6807 
6808    slen = strlen(vpis1) + strlen(vpis2) + 1;
6809    vpichp = __my_malloc(slen);
6810    strcpy(vpichp, vpis1);
6811    strcat(vpichp, vpis2);
6812 
6813    __cberror_fill_einfo(WARN, id_num, vpichp, "[NONE]", 0);
6814    __vpi_error_trycall();
6815 
6816    __my_free(vpichp, slen);
6817    /* if vpi_control used to suppress emsg, used up so turn off here */
6818    if (__errorcb_suppress_msg)
6819     { __errorcb_suppress_msg = FALSE; return; }
6820   }
6821 
6822  __my_fprintf(stdout,"** WARN** [%d] ", id_num);
6823 
6824  /* SJM 10/13/99 - ansii std says varargs not usable after vprintf called */
6825  va_start(va2, s);
6826  va_start(va3, s);
6827  __my_vfprintf(stdout, s, va2, va3);
6828  va_end(va2);
6829  va_end(va3);
6830  my_putc_('\n', stdout);
6831 }
6832 
6833 /*VARARGS*/
__pv_fwarn(int32 id_num,char * s,...)6834 extern void __pv_fwarn(int32 id_num, char *s, ...)
6835 {
6836  va_list va, va2, va3;
6837  int32 slen;
6838  char vpis1[IDLEN], vpis2[4*IDLEN], *vpichp;
6839 
6840  __pv_warn_cnt++;
6841  if (__no_warns || __em_suppr(id_num)) { va_end(va); return; }
6842 
6843  if (__iact_state)
6844   {
6845    /* SJM 10/13/99 - ansii std says varargs not usable after vprintf called */
6846    va_start(va, s);
6847    va_start(va2, s);
6848    __via_err(id_num, s, va, va2);
6849    va_end(va);
6850    va_end(va2);
6851    return;
6852   }
6853 
6854  if (__vpierr_cb_active)
6855   {
6856    /* reset in case user called sim control operation from wrong place */
6857    __errorcb_suppress_msg = FALSE;
6858 
6859    sprintf(vpis1, "**%s(%d) WARN** [%d] ", __cur_fnam, __lin_cnt, id_num);
6860    va_start(va, s);
6861    vsprintf(vpis2, s, va);
6862    va_end(va);
6863 
6864    slen = strlen(vpis1) + strlen(vpis2) + 1;
6865    vpichp = __my_malloc(slen);
6866    strcpy(vpichp, vpis1);
6867    strcat(vpichp, vpis2);
6868 
6869    __cberror_fill_einfo(WARN, id_num, vpichp, __cur_fnam, __lin_cnt);
6870    __vpi_error_trycall();
6871 
6872    __my_free(vpichp, slen);
6873    /* if vpi_control used to suppress emsg, used up so turn off here */
6874    if (__errorcb_suppress_msg)
6875     { __errorcb_suppress_msg = FALSE; return; }
6876   }
6877 
6878  __my_fprintf(stdout, "**%s(%d) WARN** [%d] ", __cur_fnam, __lin_cnt, id_num);
6879 
6880  /* SJM 10/13/99 - ansii std says varargs not usable after vprintf called */
6881  va_start(va2, s);
6882  va_start(va3, s);
6883  __my_vfprintf(stdout, s, va2, va3);
6884  va_end(va2);
6885  va_end(va3);
6886  my_putc_('\n', stdout);
6887 }
6888 
6889 /*VARARGS*/
__sgfwarn(int32 id_num,char * s,...)6890 extern void __sgfwarn(int32 id_num, char *s, ...)
6891 {
6892  va_list va, va2, va3;
6893  int32 slen;
6894  char vpis1[IDLEN], vpis2[4*IDLEN], *vpichp;
6895  char s1[RECLEN], s2[RECLEN];
6896 
6897  __pv_warn_cnt++;
6898  if (__no_warns || __em_suppr(id_num)) return;
6899 
6900  if (__run_state == SS_SIM)
6901   sprintf(s1, " now %s", __to_timstr(s2, &__simtime));
6902  else strcpy(s1, "");
6903 
6904  if (__vpierr_cb_active && !__iact_state)
6905   {
6906    /* reset in case user called sim control operation from wrong place */
6907    __errorcb_suppress_msg = FALSE;
6908 
6909    sprintf(vpis1, "**%s(%d) WARN**%s [%d] ", __in_fils[__sfnam_ind],
6910     __slin_cnt, s1, id_num);
6911 
6912    va_start(va, s);
6913    vsprintf(vpis2, s, va);
6914    va_end(va);
6915 
6916    slen = strlen(vpis1) + strlen(vpis2) + 1;
6917    vpichp = __my_malloc(slen);
6918    strcpy(vpichp, vpis1);
6919    strcat(vpichp, vpis2);
6920 
6921    __cberror_fill_einfo(WARN, id_num, vpichp, __in_fils[__sfnam_ind],
6922     __slin_cnt);
6923    __vpi_error_trycall();
6924 
6925    __my_free(vpichp, slen);
6926    /* if vpi_control used to suppress emsg, used up so turn off here */
6927    if (__errorcb_suppress_msg)
6928     { __errorcb_suppress_msg = FALSE; return; }
6929   }
6930 
6931  __my_fprintf(stdout, "**%s(%d) WARN**%s [%d] ", __in_fils[__sfnam_ind],
6932   __slin_cnt, s1, id_num);
6933 
6934  /* SJM 10/13/99 - ansii std says varargs not usable after vprintf called */
6935  va_start(va2, s);
6936  va_start(va3, s);
6937  __my_vfprintf(stdout, s, va2, va3);
6938  va_end(va2);
6939  va_end(va3);
6940  my_putc_('\n', stdout);
6941 }
6942 
6943 /*VARARGS*/
__gfwarn(int32 id_num,word32 gfnam_ind,int32 gflin_cnt,char * s,...)6944 extern void __gfwarn(int32 id_num, word32 gfnam_ind, int32 gflin_cnt,
6945  char *s, ...)
6946 {
6947  va_list va, va2, va3;
6948  int32 slen;
6949  char vpis1[IDLEN], vpis2[4*IDLEN], *vpichp;
6950  char s1[RECLEN], s2[RECLEN];
6951 
6952  __pv_warn_cnt++;
6953  if (__no_warns || __em_suppr(id_num)) return;
6954 
6955  if (__run_state == SS_SIM)
6956   sprintf(s1, " now %s", __to_timstr(s2, &__simtime));
6957  else strcpy(s1, "");
6958 
6959  if (__vpierr_cb_active && !__iact_state)
6960   {
6961    /* reset in case user called sim control operation from wrong place */
6962    __errorcb_suppress_msg = FALSE;
6963 
6964    sprintf(vpis1, "**%s(%d) WARN**%s [%d] ", __in_fils[gfnam_ind],
6965     gflin_cnt, s1, id_num);
6966 
6967    va_start(va, s);
6968    vsprintf(vpis2, s, va);
6969    va_end(va);
6970 
6971    slen = strlen(vpis1) + strlen(vpis2) + 1;
6972    vpichp = __my_malloc(slen);
6973    strcpy(vpichp, vpis1);
6974    strcat(vpichp, vpis2);
6975 
6976    __cberror_fill_einfo(WARN, id_num, vpichp, __in_fils[gfnam_ind],
6977     gflin_cnt);
6978    __vpi_error_trycall();
6979 
6980    __my_free(vpichp, slen);
6981    /* if vpi_control used to suppress emsg, used up so turn off here */
6982    if (__errorcb_suppress_msg)
6983     { __errorcb_suppress_msg = FALSE; return; }
6984   }
6985 
6986  __my_fprintf(stdout, "**%s(%d) WARN**%s [%d] ", __in_fils[gfnam_ind],
6987   gflin_cnt, s1, id_num);
6988 
6989  /* SJM 10/13/99 - ansii std says varargs not usable after vprintf called */
6990  va_start(va2, s);
6991  va_start(va3, s);
6992  __my_vfprintf(stdout, s, va2, va3);
6993  va_end(va2);
6994  va_end(va3);
6995  my_putc_('\n', stdout);
6996 }
6997 
6998 /*
6999  * interactive command warning
7000  * this output still goes to log file
7001  * notice this routine does not increment warn number
7002  */
7003 /*VARARGS*/
__ia_warn(int32 id_num,char * s,...)7004 extern void __ia_warn(int32 id_num, char *s, ...)
7005 {
7006  va_list va, va2;
7007 
7008  if (id_num >= 1700) __arg_terr(__FILE__, __LINE__);
7009  /* can suppress any interactive error */
7010  if (__em_suppr(id_num)) return;
7011 
7012  /* SJM 10/13/99 - ansii std says varargs not usable after vprintf called */
7013  va_start(va, s);
7014  va_start(va2, s);
7015  __via_warn(id_num, s, va, va2);
7016  va_end(va);
7017  va_end(va2);
7018 }
7019 
7020 /*VARARGS*/
__via_warn(int32 id_num,char * s,va_list args,va_list args2)7021 extern void __via_warn(int32 id_num, char *s, va_list args, va_list args2)
7022 {
7023  if (__cmd_s == NULL) __my_fprintf(stdout, "--CMD WARN** [%d] ", id_num);
7024  else __my_fprintf(stdout, "--%s(%d) CMD WARN** [%d] ", __cmd_fnam,
7025   __lin_cnt, id_num);
7026  __my_vfprintf(stdout, s, args, args2);
7027  my_putc_('\n', stdout);
7028 }
7029 
7030 /*VARARGS*/
__inform(int32 id_num,char * s,...)7031 extern void __inform(int32 id_num, char *s, ...)
7032 {
7033  va_list va, va2, va3;
7034  int32 slen;
7035  char vpis1[IDLEN], vpis2[4*IDLEN], *vpichp;
7036 
7037  __inform_cnt++;
7038  if (__no_informs || __em_suppr(id_num)) return;
7039 
7040  if (__vpierr_cb_active && !__iact_state)
7041   {
7042    /* reset in case user called sim control operation from wrong place */
7043    __errorcb_suppress_msg = FALSE;
7044 
7045    sprintf(vpis1, "--INFORM: [%d] ", id_num);
7046    va_start(va, s);
7047    vsprintf(vpis2, s, va);
7048    va_end(va);
7049 
7050    slen = strlen(vpis1) + strlen(vpis2) + 1;
7051    vpichp = __my_malloc(slen);
7052    strcpy(vpichp, vpis1);
7053    strcat(vpichp, vpis2);
7054 
7055    __cberror_fill_einfo(INFORM, id_num, vpichp, "[NONE]", 0);
7056    __vpi_error_trycall();
7057 
7058    __my_free(vpichp, slen);
7059    /* if vpi_control used to suppress emsg, used up so turn off here */
7060    if (__errorcb_suppress_msg)
7061     { __errorcb_suppress_msg = FALSE; return; }
7062   }
7063 
7064  __my_fprintf(stdout, "--INFORM: [%d] ", id_num);
7065 
7066  /* SJM 10/13/99 - ansii std says varargs not usable after vprintf called */
7067  va_start(va2, s);
7068  va_start(va3, s);
7069  __my_vfprintf(stdout, s, va2, va3);
7070  va_end(va2);
7071  va_end(va3);
7072  my_putc_('\n', stdout);
7073 }
7074 
7075 /*VARARGS*/
__finform(int32 id_num,char * s,...)7076 extern void __finform(int32 id_num, char *s, ...)
7077 {
7078  va_list va, va2, va3;
7079  int32 slen;
7080  char vpis1[IDLEN], vpis2[4*IDLEN], *vpichp;
7081 
7082  __inform_cnt++;
7083  if (__no_informs || __em_suppr(id_num)) return;
7084 
7085  if (__vpierr_cb_active && !__iact_state)
7086   {
7087    /* reset in case user called sim control operation from wrong place */
7088    __errorcb_suppress_msg = FALSE;
7089 
7090    sprintf(vpis1, "--%s(%d) INFORM-- [%d] ", __cur_fnam, __lin_cnt, id_num);
7091    va_start(va, s);
7092    vsprintf(vpis2, s, va);
7093    va_end(va);
7094 
7095    slen = strlen(vpis1) + strlen(vpis2) + 1;
7096    vpichp = __my_malloc(slen);
7097    strcpy(vpichp, vpis1);
7098    strcat(vpichp, vpis2);
7099 
7100    __cberror_fill_einfo(INFORM, id_num, vpichp, __cur_fnam, __lin_cnt);
7101    __vpi_error_trycall();
7102 
7103    __my_free(vpichp, slen);
7104    /* if vpi_control used to suppress emsg, used up so turn off here */
7105    if (__errorcb_suppress_msg)
7106     { __errorcb_suppress_msg = FALSE; return; }
7107   }
7108 
7109  __my_fprintf(stdout, "--%s(%d) INFORM-- [%d] ", __cur_fnam,
7110   __lin_cnt, id_num);
7111 
7112  /* SJM 10/13/99 - ansii std says varargs not usable after vprintf called */
7113  va_start(va2, s);
7114  va_start(va3, s);
7115  __my_vfprintf(stdout, s, va2, va3);
7116  va_end(va2);
7117  va_end(va3);
7118  my_putc_('\n', stdout);
7119 }
7120 
7121 /*VARARGS*/
__sgfinform(int32 id_num,char * s,...)7122 extern void __sgfinform(int32 id_num, char *s, ...)
7123 {
7124  va_list va, va2, va3;
7125  int32 slen;
7126  char vpis1[IDLEN], vpis2[4*IDLEN], *vpichp;
7127  char s1[RECLEN], s2[RECLEN];
7128 
7129  __inform_cnt++;
7130  if (__no_informs || __em_suppr(id_num)) return;
7131 
7132  if (__run_state == SS_SIM)
7133   sprintf(s1, " now %s", __to_timstr(s2, &__simtime));
7134  else strcpy(s1, "");
7135 
7136  if (__vpierr_cb_active && !__iact_state)
7137   {
7138    /* reset in case user called sim control operation from wrong place */
7139    __errorcb_suppress_msg = FALSE;
7140 
7141    sprintf(vpis1, "--%s(%d) INFORM--%s [%d] ", __in_fils[__sfnam_ind],
7142     __slin_cnt, s1, id_num);
7143    va_start(va, s);
7144    vsprintf(vpis2, s, va);
7145    va_end(va);
7146 
7147    slen = strlen(vpis1) + strlen(vpis2) + 1;
7148    vpichp = __my_malloc(slen);
7149    strcpy(vpichp, vpis1);
7150    strcat(vpichp, vpis2);
7151 
7152    __cberror_fill_einfo(INFORM, id_num, vpichp, __in_fils[__sfnam_ind],
7153     __slin_cnt);
7154    __vpi_error_trycall();
7155 
7156    __my_free(vpichp, slen);
7157    /* if vpi_control used to suppress emsg, used up so turn off here */
7158    if (__errorcb_suppress_msg)
7159     { __errorcb_suppress_msg = FALSE; return; }
7160   }
7161 
7162  __my_fprintf(stdout, "--%s(%d) INFORM--%s [%d] ", __in_fils[__sfnam_ind],
7163   __slin_cnt, s1, id_num);
7164 
7165  /* SJM 10/13/99 - ansii std says varargs not usable after vprintf called */
7166  va_start(va2, s);
7167  va_start(va3, s);
7168  __my_vfprintf(stdout, s, va2, va3);
7169  va_end(va2);
7170  va_end(va3);
7171  my_putc_('\n', stdout);
7172 }
7173 
7174 /*VARARGS*/
__gfinform(int32 id_num,word32 gfnam_ind,int32 gflin_cnt,char * s,...)7175 extern void __gfinform(int32 id_num, word32 gfnam_ind, int32 gflin_cnt,
7176  char *s, ...)
7177 {
7178  va_list va, va2, va3;
7179  int32 slen;
7180  char vpis1[IDLEN], vpis2[4*IDLEN], *vpichp;
7181  char s1[RECLEN], s2[RECLEN];
7182 
7183  __inform_cnt++;
7184  if (__no_informs || __em_suppr(id_num)) return;
7185 
7186  if (__run_state == SS_SIM)
7187   sprintf(s1, " now %s", __to_timstr(s2, &__simtime));
7188  else strcpy(s1, "");
7189 
7190  if (__vpierr_cb_active && !__iact_state)
7191   {
7192    /* reset in case user called sim control operation from wrong place */
7193    __errorcb_suppress_msg = FALSE;
7194 
7195    sprintf(vpis1, "--%s(%d) INFORM--%s [%d] ", __in_fils[gfnam_ind],
7196     gflin_cnt, s1, id_num);
7197    va_start(va, s);
7198    vsprintf(vpis2, s, va);
7199    va_end(va);
7200 
7201    slen = strlen(vpis1) + strlen(vpis2) + 1;
7202    vpichp = __my_malloc(slen);
7203    strcpy(vpichp, vpis1);
7204    strcat(vpichp, vpis2);
7205 
7206    __cberror_fill_einfo(INFORM, id_num, vpichp, __in_fils[gfnam_ind],
7207     gflin_cnt);
7208    __vpi_error_trycall();
7209 
7210    __my_free(vpichp, slen);
7211    /* if vpi_control used to suppress emsg, used up so turn off here */
7212    if (__errorcb_suppress_msg)
7213     { __errorcb_suppress_msg = FALSE; return; }
7214   }
7215 
7216  __my_fprintf(stdout, "--%s(%d) INFORM--%s [%d] ", __in_fils[gfnam_ind],
7217   gflin_cnt, s1, id_num);
7218 
7219  /* SJM 10/13/99 - ansii std says varargs not usable after vprintf called */
7220  va_start(va2, s);
7221  va_start(va3, s);
7222  __my_vfprintf(stdout, s, va2, va3);
7223  va_end(va2);
7224  va_end(va3);
7225  my_putc_('\n', stdout);
7226 }
7227 
7228 /*
7229  * return T if this message marked to be suppressed
7230  * if warnings off all suppressed
7231  */
__em_suppr(int32 id)7232 extern int32 __em_suppr(int32 id)
7233 {
7234  word32 w;
7235  int32 bi, wi;
7236 
7237  bi = id % WBITS;
7238  wi = id / WBITS;
7239  w = __wsupptab[wi];
7240  if ((w & (1L << bi)) != 0) return(TRUE);
7241  return(FALSE);
7242 }
7243 
7244 /*
7245  * my fprintf - normal fprintf except if f is stdout then also to log file
7246  *
7247  * SJM 10/13/99 - ansii std says varargs not usable after vprintf called
7248  */
7249 /*VARARGS*/
__my_fprintf(FILE * f,char * s,...)7250 extern void __my_fprintf(FILE *f, char *s, ...)
7251 {
7252  va_list va, va2;
7253 
7254  va_start(va, s);
7255  va_start(va2, s);
7256  vfprintf(f, s, va);
7257  if (f == stdout && __log_s != NULL) vfprintf(__log_s, s, va2);
7258  va_end(va);
7259  va_end(va2);
7260 }
7261 
7262 /*
7263  * version of my fprintf when caller passed variable arg list
7264  *
7265  * SJM 10/13/99 - ansii std says varargs not usable after vprintf called
7266  */
__my_vfprintf(FILE * f,char * s,va_list args,va_list args2)7267 extern void __my_vfprintf(FILE *f, char *s, va_list args, va_list args2)
7268 {
7269  vfprintf(f, s, args);
7270  if (f == stdout && __log_s != NULL) vfprintf(__log_s, s, args2);
7271 }
7272