1 /* Copyright (c) 1991-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  * third source module reads tasks/functions, udps and specify section
30  */
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include <errno.h>
38 
39 #if defined(__CYGWIN32__) || defined(__SVR4)
40 #include <sys/stat.h>
41 #endif
42 
43 #if defined(__CYGWIN32__) || defined(__SVR4) || defined(__hpux) || defined(__FreeBSD__)
44 #include <dirent.h>
45 #else
46 #include <sys/dir.h>
47 #endif
48 
49 #ifdef __DBMALLOC__
50 #include "../malloc.h"
51 #endif
52 
53 /* REMOVEME - no longer supporting SunOS - maybe needed for hpux? */
54 #if defined(__sparc) && !defined(__SVR4) && !defined(__FreeBSD__)
55 extern int32 tolower(int32);
56 #endif
57 
58 #include "v.h"
59 #include "cvmacros.h"
60 
61 /* local prototypes */
62 static struct udp_t *alloc_udp(struct sy_t *);
63 static int32 rd_udp_hdr(struct udp_t *);
64 static int32 rd_udp_decls(void);
65 static int32 rd_udp_init(struct udp_t *);
66 static int32 chkcnt_uports(struct udp_t *);
67 static int32 rd_udp_table(struct udp_t *);
68 static void str_tolower(char *, char *);
69 static int32 cvrt_udpedges(char *, char *);
70 static int32 to_udp_levsym(char);
71 static int32 chk_comb_udpline(char *, struct udp_t *, int32 *);
72 static int32 chk_sequdpline(char *, struct udp_t *, int32 *);
73 static char to_edgech(int32);
74 static int32 is_edgesym(char);
75 static char *to_codedge_line(char *, char *);
76 static void extra_chk_edgeudp(struct udp_t *);
77 static char *to_udp_prtnam(struct udp_t *, int32);
78 static void dmp_udp_lines(FILE *, struct udp_t *);
79 static struct spfy_t *alloc_spfy(void);
80 static int32 rd_specparamdecl(void);
81 static void assign_1specparam(struct net_t *, struct expr_t *, int32, int32);
82 static int32 rd_delay_pth(void);
83 static struct exprlst_t *rd_pthtermlst(void);
84 static int32 col_pthexpr(void);
85 static int32 rd_pathdelaylist(struct paramlst_t **);
86 static void init_spcpth(struct spcpth_t *);
87 static int32 rd_setup_or_hold_tchk(word32);
88 static int32 rd_tchk_part(word32, struct tchk_t *, struct expr_t **);
89 static int32 rd_setuphold_tchk(void);
90 static int32 rd_recrem_tchk(void);
91 static int32 rd_width_tchk(void);
92 static int32 rd_period_tchk(void);
93 static int32 rd_skew_recov_rem_tchk(word32);
94 static int32 rd_nochg_tchk(void);
95 static int32 rd_tchk_selector(int32 *, struct expr_t **, struct expr_t **);
96 static int32 rd_edges(int32 *);
97 static struct sy_t *rd_notifier(void);
98 static struct attr_t *chk_dup_attrs(struct attr_t *);
99 static void rd1_cfg_file(FILE *);
100 static void rd_cfg_library(FILE *);
101 static struct libel_t *rd_cfg_fspec_list(FILE *, int32);
102 static void rd_cfg_cfg(FILE *);
103 static int32 chk_libid(char *);
104 static int32 chk_escid(char *);
105 static void init_rule(struct cfgrule_t *);
106 static int32 extract_design_nam(char *, char *, char *);
107 static int32 bld_inst_xmr_comptab(char *);
108 static void grow_bind_comps(void);
109 static int32 extract_libcell_nam(char *, char *, char *);
110 static int32 rd_use_clause(FILE *, char *, char *, int32 *);
111 static int32 extract_use_nam(char *, char *, int32 *, char *);
112 static struct cfgnamlst_t *rd_liblist(FILE *);
113 
114 static void init_cfglib(struct cfglib_t *);
115 static void init_cfg(struct cfg_t *);
116 static int32 cfg_skipto_semi(int32, FILE *);
117 static int32 cfg_skipto_comma_semi(int32, FILE *);
118 static int32 cfg_skipto_semi_endconfig(int32, FILE *);
119 static int32 cfg_skipto_eof(int32, FILE *);
120 
121 static void expand_dir_pats(struct cfglib_t *, struct libel_t *, char *);
122 static void expand_hier_files(struct cfglib_t *, struct libel_t *,
123  struct xpndfile_t *);
124 static void match_dir_pats(struct libel_t *, struct xpndfile_t *, char *,
125  char *, int32, int32);
126 static void movedir_match_dir_pats(struct libel_t *, struct xpndfile_t *);
127 static void find_hier(struct libel_t *, struct xpndfile_t *, char *, char *);
128 static int32 match_hier_name(struct xpndfile_t *, char *);
129 static int32 match_wildcard_str(char *, struct xpndfile_t *);
130 static void expand_libel(struct libel_t *, char *);
131 static int32 expand_single_hier(struct cfglib_t *, struct libel_t *, char *);
132 static int32 has_wildcard(char *);
133 static void prep_cfg_vflist(void);
134 static void dump_config_info(void);
135 static void dump_lib_expand(void);
136 static int32 bind_cfg_design(struct cfg_t *, int32);
137 static struct cfglib_t *find_cfglib(char *);
138 static void free_undef_list(void);
139 static void bind_cells_in1mod(struct cfg_t *, struct cfglib_t *,
140  struct mod_t *);
141 static int32 try_match_rule(struct cfglib_t *, struct cell_t *,
142  struct cfgrule_t *);
143 static void build_rule_error(struct cfg_t *, struct cfglib_t *,
144 struct cfgrule_t *);
145 static int32 bind_liblist_rule(struct cfg_t *, struct cell_t *,
146  struct cfgrule_t *);
147 static int32 bind_use_rule(struct cfg_t *, struct cfglib_t *, struct cell_t *,
148  struct cfgrule_t *);
149 static struct cfg_t *fnd_cfg_by_name(char *);
150 static void bind_cells_inside(struct cfg_t *, struct cell_t *,
151  struct mod_t *, struct cfglib_t *);
152 static struct mod_t *find_cell_in_cfglib(char *, struct cfglib_t *);
153 static int32 open_cfg_lbfil(char *);
154 static void rd_cfg_srcfil(struct libel_t *);
155 static int32 init_chk_cfg_sytab(struct libel_t *, char *);
156 static void free_unused_cfgmods(void);
157 static void partially_free_mod(struct mod_t *);
158 static void add_cfg_libsyms(struct cfglib_t *);
159 static void add_cfgsym(char *, struct tnode_t *);
160 
161 /* extern prototypes (maybe defined in this module) */
162 extern char *__pv_stralloc(char *);
163 extern char *__my_malloc(int32);
164 extern char *__my_realloc(char *, int32 , int32);
165 extern void __my_free(char *, int32);
166 extern char *__prt_vtok(void);
167 extern char *__prt_kywrd_vtok(void);
168 extern char *__to_uvvnam(char *, word32);
169 extern char *__to_tcnam(char *, word32);
170 extern char *__to_sytyp(char *, word32);
171 extern struct sy_t *__get_sym(char *, struct symtab_t *);
172 extern struct sy_t *__decl_sym(char *, struct symtab_t *);
173 extern struct sy_t *__bld_loc_symbol(int32, struct symtab_t *, char *, char *);
174 extern struct exprlst_t *__alloc_xprlst(void);
175 extern struct tnode_t *__vtfind(char *, struct symtab_t *);
176 extern struct symtab_t *__alloc_symtab(int32);
177 extern struct expr_t *__alloc_newxnd(void);
178 extern struct mod_pin_t *__alloc_modpin(void);
179 extern struct paramlst_t *__alloc_pval(void);
180 extern struct expr_t *__bld_rng_numxpr(word32, word32, int32);
181 extern int32 __vskipto_modend(int32);
182 extern void __add_sym(char *, struct tnode_t *);
183 extern int32 __chk_redef_err(char *, struct sy_t *, char *, word32);
184 extern void __remove_undef_mod(struct sy_t *);
185 extern void __get_vtok(void);
186 extern void __unget_vtok(void);
187 extern void __dmp_udp(FILE *, struct udp_t *);
188 extern int32 __udp_vskipto_any(int32);
189 extern int32 __udp_vskipto2_any(int32, int32);
190 extern int32 __udp_vskipto3_any(int32, int32, int32);
191 extern int32 __wide_vval_is0(register word32 *, int32);
192 extern void __wrap_puts(char *, FILE *);
193 extern void __wrap_putc(int32, FILE *);
194 extern void __nl_wrap_puts(char *, FILE *);
195 extern int32 __fr_tcnam(char *);
196 extern int32 __spec_vskipto_any(int32);
197 extern int32 __spec_vskipto2_any(int32, int32);
198 extern int32 __spec_vskipto3_any(int32, int32, int32);
199 extern int32 __rd_opt_param_vec_rng(struct expr_t **, struct expr_t **, int32);
200 extern int32 __col_paramrhsexpr(void);
201 extern int32 __col_connexpr(int32);
202 extern int32 __col_comsemi(int32);
203 extern void __bld_xtree(int32);
204 extern int32 __src_rd_chk_paramexpr(struct expr_t *, int32);
205 extern void __set_numval(struct expr_t *, word32, word32, int32);
206 extern struct net_t *__add_param(char *, struct expr_t *, struct expr_t *,
207  int32);
208 extern int32 __col_parenexpr(int32);
209 extern int32 __bld_expnode(void);
210 extern void __set_xtab_errval(void);
211 extern int32 __col_delexpr(void);
212 extern int32 __vskipto3_modend(int32, int32, int32);
213 extern void __init_tchk(struct tchk_t *, word32);
214 extern void __set_0tab_errval(void);
215 extern void __free_xtree(struct expr_t *);
216 extern void __free2_xtree(struct expr_t *);
217 extern void __skipover_line(void);
218 extern int32 __my_getlin(register char *);
219 extern int32 __pop_vifstk(void);
220 extern int32 __open_sfil(void);
221 extern void __do_include(void);
222 extern void __do_foreign_lang(void);
223 extern void __exec_vpi_langlinecbs(char *, char *, int32);
224 extern int32 __notokenize_skiplines(char *);
225 extern char *__bld_lineloc(char *, word32, int32);
226 extern char *__match_cdir(char *, char *);
227 extern int32 __exec_rdinserted_src(char *);
228 extern void __push_vinfil(void);
229 extern void __rd_ver_mod(void);
230 extern int32 __expr_has_glb(struct expr_t *);
231 extern struct xstk_t *__eval2_xpr(struct expr_t *);
232 extern void __sizchgxs(struct xstk_t *, int32);
233 extern char *__msgexpr_tostr(char *, struct expr_t *);
234 extern void __cnv_stk_fromreal_toreg32(struct xstk_t *);
235 extern void __eval_param_rhs_tonum(struct expr_t *);
236 extern int32 __cmp_xpr(struct expr_t *, struct expr_t *);
237 extern FILE *__tilde_fopen(char *, char *);
238 extern int32 __get_cfgtok(FILE *);
239 extern int32 __vskipto_modend(int32);
240 extern void __grow_infils(int32);
241 extern int32 __rd_cfg(void);
242 extern char *__to_cfgtoknam(char *, int32);
243 extern void __my_fclose(FILE *);
244 extern void __expand_lib_wildcards(void);
245 extern void __process_cdir(void);
246 extern int32 __rd_moddef(struct symtab_t *, int32);
247 extern int32 __vskipto2_modend(int32, int32);
248 extern char *__cfg_lineloc(char *s, char *, int32);
249 extern char *__schop(char *, char *);
250 extern void __sym_addprims(void);
251 
252 extern void __cv_msg(char *s, ...);
253 extern void __finform(int32, char *, ...);
254 extern void __pv_ferr(int32, char *, ...);
255 extern void __pv_fwarn(int32, char *, ...);
256 extern void __gfinform(int32, word32, int32, char *, ...);
257 extern void __gfwarn(int32, word32, int32, char *, ...);
258 extern void __gferr(int32, word32, int32, char *, ...);
259 extern void __ia_err(int32, char *, ...);
260 extern void __dbg_msg(char *, ...);
261 extern void __pv_terr(int32, char *, ...);
262 extern void __arg_terr(char *, int32);
263 extern void __case_terr(char *, int32);
264 extern void __fterr(int32, char *, ...);
265 extern void __misc_terr(char *, int32);
266 extern void __misc_fterr(char *, int32);
267 extern void __pv_err(int32, char *, ...);
268 extern void __pv_warn(int32, char *, ...);
269 
270 /*
271  * UDP PROCESSING ROUTINES
272  */
273 
274 /*
275  * process a udp definition
276  * added to end of list of udps with header __udphead
277  * name of udp has already been read
278  * notice there is a separate design wide list of udps
279  *
280  * primitive keyword read and reads endprimitive
281  */
__rd_udpdef(struct symtab_t * cfg_sytab)282 extern int32 __rd_udpdef(struct symtab_t *cfg_sytab)
283 {
284  int32 retval, initlcnt, initsfnind;
285  struct udp_t *udpp;
286  struct tnode_t *tnp;
287  struct sy_t *syp;
288  char *cp;
289 
290  initlcnt = 0;
291  initsfnind = 0;
292  /* notice that Verilog keywords are reserved words */
293  retval = TRUE;
294  /* for now must be able to declare to continue syntax checking */
295  if (__toktyp != ID)
296   {
297    __pv_ferr(1155, "udp name expected - %s read", __prt_kywrd_vtok());
298 skip_end:
299    retval = __vskipto_modend(ENDPRIMITIVE);
300    return(retval);
301   }
302  cp = __token;
303 
304  if (cfg_sytab != NULL)
305   {
306    tnp = __vtfind(__token, cfg_sytab);
307    /* dups already checked for */
308    /* DBG remove -- */
309    if (!__sym_is_new) __misc_terr(__FILE__, __LINE__);
310    /* --- */
311    __add_sym(__token, tnp);
312    (cfg_sytab->numsyms)++;
313    syp = tnp->ndp;
314   }
315  else
316   {
317    tnp = __vtfind(cp, __modsyms);
318    if (__sym_is_new)
319     {
320      __add_sym(__token, tnp);
321      (__modsyms->numsyms)++;
322      syp = tnp->ndp;
323     }
324    else
325     {
326      syp = tnp->ndp;
327      /* if previously guessed as module, will just change */
328      if (!__chk_redef_err(__token, syp, "udp", SYM_UDP)) goto skip_end;
329      /* chk fail means never in module undef list */
330      __remove_undef_mod(syp);
331     }
332   }
333  syp->sytyp = SYM_UDP;
334  udpp = alloc_udp(syp);
335  syp->el.eudpp = udpp;
336  syp->sydecl = TRUE;
337  /* need place where udp declared */
338  syp->syfnam_ind = __cur_fnam_ind;
339  syp->sylin_cnt = __lin_cnt;
340 
341  /* must also allocate the new symbol table */
342  /* udps have no internal structure, sym table discarded when done */
343  udpp->usymtab = __alloc_symtab(FALSE);
344  __cur_udp = udpp;
345  /* link symbol table back to module symbol */
346  udpp->usymtab->sypofsyt = syp;
347 
348  /* do not need to build type until entire module read */
349  /* any return here means skipped to endprimitive or next file level */
350  if (!rd_udp_hdr(udpp)) return(FALSE);
351  if (!rd_udp_decls()) return(FALSE);
352  if (__toktyp == INITial)
353   {
354    initlcnt = __lin_cnt;
355    initsfnind = __cur_fnam_ind;
356    if (!rd_udp_init(udpp)) return(FALSE);
357    __get_vtok();
358    if (__toktyp != TABLE)
359     {
360      __pv_ferr(1156, "udp table section missing - %s read", __prt_vtok());
361      goto skip_end;
362     }
363   }
364  /* sets type to U_LEVEL if not combinatorial - edge type detected later */
365  if (!chkcnt_uports(udpp)) retval = FALSE;
366  if ((int32) udpp->numstates >= __ualtrepipnum) udpp->u_wide = TRUE;
367  else udpp->u_wide = FALSE;
368 
369  /* this reads the endprimitive */
370  if (!rd_udp_table(udpp)) return(FALSE);
371  if (udpp->utyp == U_COMB && udpp->ival != NO_VAL)
372   {
373    __gferr(1157, initsfnind, initlcnt,
374     "combinatorial udp %s cannot have initial value", syp->synam);
375    udpp->ival = NO_VAL;
376   }
377 
378  __get_vtok();
379  if (__toktyp != ENDPRIMITIVE)
380   {
381    __pv_ferr(1158,
382     "udp endprimitive keyword expected - %s read", __prt_vtok());
383    goto skip_end;
384   }
385  if (!retval) return(TRUE);
386 
387  /* catch common extra ; error here */
388  __get_vtok();
389  if (__toktyp == SEMI)
390   __pv_ferr(1152, "semicolon following endprimitive illegal");
391  else __unget_vtok();
392 
393  extra_chk_edgeudp(udpp);
394 
395  /* notice if error before here not added to list */
396  if (__udp_last == NULL) __udphead = udpp; else __udp_last->udpnxt = udpp;
397  __udp_last = udpp;
398  if (__debug_flg) __dmp_udp(stdout, udpp);
399  return(TRUE);
400 }
401 
402 /*
403  * allocate a udp
404  */
alloc_udp(struct sy_t * syp)405 static struct udp_t *alloc_udp(struct sy_t *syp)
406 {
407  struct udp_t *udpp;
408 
409  udpp = (struct udp_t *) __my_malloc(sizeof(struct udp_t));
410  udpp->usym = syp;
411  udpp->usymtab = NULL;
412  udpp->upins = NULL;
413  udpp->utyp = U_COMB;
414  udpp->numins = 0;
415  udpp->numstates = 0;
416  udpp->u_used = FALSE;
417  udpp->u_wide = FALSE;
418  /* initial value - assume none that becomes 1'bx for level */
419  udpp->ival = NO_VAL;
420  udpp->utlines = NULL;
421  udpp->udpnxt = NULL;
422  udpp->utab = NULL;
423  udpp->uidnum = 0;
424  return(udpp);
425 }
426 
427 /*
428  * read the udp header
429  * only simple variable names allowed in this header
430  * reads ending ;
431  * handles skipping -
432  */
rd_udp_hdr(struct udp_t * udpp)433 static int32 rd_udp_hdr(struct udp_t *udpp)
434 {
435  struct mod_pin_t *upp, *last_upp;
436  struct sy_t *syp;
437 
438  /* empty I/O list illegal */
439  __get_vtok();
440  if (__toktyp == SEMI)
441   {
442    __pv_ferr(1162, "required udp header list of ports missing");
443    return(TRUE);
444   }
445 
446  if (__toktyp != LPAR)
447   {
448    __pv_ferr(1164,
449     "udp header list of ports initial left parenthesis expected - %s read",
450     __prt_vtok());
451    if (__udp_vskipto2_any(RPAR, SEMI))
452     {
453      if (__toktyp == RPAR) __get_vtok();
454      /* if not semi, assume semi left out - if bad, next rout. will catch */
455      if (__toktyp != SEMI) __unget_vtok();
456      return(TRUE);
457     }
458 ret_end:
459    if (__syncto_class == SYNC_FLEVEL) return(FALSE);
460    else return(TRUE);
461   }
462  __get_vtok();
463  if (__toktyp == RPAR)
464   {
465    __pv_ferr(1165, "empty udp header list of ports () form illegal");
466 do_end:
467    __get_vtok();
468    if (__toktyp == SEMI) return(TRUE);
469    __pv_ferr(980,
470     "module header list of ports end semicolon expected - %s read",
471     __prt_vtok());
472    __unget_vtok();
473    return(TRUE);
474   }
475  for (last_upp = NULL;;)
476   {
477    /* this declares the symbols in the header */
478    if (__toktyp != ID)
479     {
480      __pv_ferr(1166, "udp port variable name expected - %s read",
481       __prt_kywrd_vtok());
482 do_resync:
483      if (__udp_vskipto3_any(COMMA, SEMI, RPAR))
484       {
485        /* port effectively not seen - error emitted already */
486        if (__toktyp == COMMA) goto nxt_port;
487        if (__toktyp == RPAR) goto do_end;
488        return(TRUE);
489       }
490      goto ret_end;
491     }
492    syp = __decl_sym(__token, __cur_udp->usymtab);
493    /* must fill in connection to port still */
494    if (__sym_is_new) syp->sytyp = SYM_N;
495    else
496     {
497      __pv_ferr(1167,
498       "udp port %s repeated in header list of ports", syp->synam);
499      goto nxt_port;
500     }
501    upp = __alloc_modpin();
502    upp->mptyp = IO_UNKN;
503    upp->mpsnam = syp->synam;
504    upp->mpref = NULL;
505    syp->el.empp = upp;
506 
507    if (last_upp == NULL) udpp->upins = upp; else last_upp->mpnxt = upp;
508    last_upp = upp;
509 
510 nxt_port:
511    __get_vtok();
512    if (__toktyp == RPAR)
513     {
514      __get_vtok();
515      if (__toktyp == SEMI) break;
516      __pv_ferr(1168,
517       "udp header list of ports ending semicolon expected - %s read",
518       __prt_vtok());
519      goto do_end;
520     }
521    if (__toktyp != COMMA)
522     {
523      __pv_ferr(1169,
524       "udp header comma or semicolon separator expected - %s read",
525       __prt_vtok());
526      goto do_resync;
527     }
528    __get_vtok();
529   }
530  return(TRUE);
531 }
532 
533 /*
534  * read the udp declarations
535  * must read first port type and reads following initial or table
536  * eliminates illegal vector ports by not parsing
537  */
rd_udp_decls(void)538 static int32 rd_udp_decls(void)
539 {
540  struct mod_pin_t *mpp;
541  struct sy_t *syp;
542  int32 outdecl_seen, regdecl_seen;
543 
544  regdecl_seen = outdecl_seen = FALSE;
545  for (;;)
546   {
547 again:
548    __get_vtok();
549    if (__toktyp == INITial || __toktyp == TABLE) break;
550    switch ((byte) __toktyp) {
551     case INPUT:
552      for (;;)
553       {
554        __get_vtok();
555        if (__toktyp != ID)
556         {
557          __pv_ferr(1170, "udp input port name expected - %s read",
558           __prt_kywrd_vtok());
559 sync_in:
560          if (__udp_vskipto2_any(COMMA, SEMI))
561           {
562            /* port effectively not seen - error emitted already */
563            if (__toktyp == COMMA) continue;
564            goto again;
565           }
566          if (__syncto_class == SYNC_FLEVEL) return(FALSE);
567          else goto again;
568         }
569        if ((syp = __get_sym(__token, __cur_udp->usymtab)) == NULL)
570         {
571 not_in_port:
572           __pv_ferr(1173,
573            "udp input declaration of \"%s\" - non header input port", __token);
574          goto nxt_port;
575         }
576        if (syp->sytyp != SYM_N)
577         {
578 bad_sytab:
579          /* udp symbol table inconsistent */
580          __misc_fterr(__FILE__, __LINE__);
581         }
582        mpp = syp->el.empp;
583        if (syp->sydecl || mpp->mptyp != IO_UNKN) goto not_in_port;
584        mpp->mptyp = IO_IN;
585        syp->sydecl = TRUE;
586 
587 nxt_port:
588        __get_vtok();
589        if (__toktyp == SEMI) break;
590        if (__toktyp == COMMA) continue;
591        __pv_ferr(1174,
592         "udp port declaration comma or semicolon separator expected - %s read",
593         __prt_vtok());
594        goto sync_in;
595       }
596      break;
597     case OUTPUT:
598      if (outdecl_seen)
599       {
600        __pv_ferr(1178, "only one udp output port declaration permitted");
601        __get_vtok();
602        goto end_out_port;
603       }
604      outdecl_seen = TRUE;
605 
606       __get_vtok();
607      if (__toktyp != ID)
608       {
609        __pv_ferr(1179, "udp output port name expected - %s read",
610         __prt_kywrd_vtok());
611 sync_out:
612        if (__udp_vskipto_any(SEMI)) return(TRUE);
613        if (__syncto_class == SYNC_FLEVEL) return(FALSE);
614        else goto again;
615       }
616      if ((syp = __get_sym(__token, __cur_udp->usymtab)) == NULL)
617       {
618 not_out_port:
619        __pv_ferr(1180,
620         "udp output port declaration of \"%s\" that is not in header port list",
621         __token);
622        goto end_out_port;
623       }
624      if (syp->sytyp != SYM_N) goto bad_sytab;
625      mpp = syp->el.empp;
626      /* NON_IO means already declared as reg so nothing to do */
627      if (mpp->mptyp != NON_IO)
628       {
629        if (syp->sydecl || mpp->mptyp != IO_UNKN) goto not_out_port;
630        mpp->mptyp = IO_OUT;
631        syp->sydecl = TRUE;
632       }
633 end_out_port:
634      __get_vtok();
635      if (__toktyp != SEMI)
636       {
637        __pv_ferr(1181,
638         "udp output declaration not followed by semicolon - %s read",
639         __prt_vtok());
640        goto sync_out;
641       }
642      break;
643     case REG:
644      if (regdecl_seen)
645       {
646        __pv_ferr(1182, "only one udp reg declaration permitted");
647        __get_vtok();
648        goto end_reg;
649       }
650      regdecl_seen = TRUE;
651      __get_vtok();
652      if (__toktyp != ID)
653       {
654        __pv_ferr(1183,
655         "udp reg declaration output port name expected - %s read",
656         __prt_kywrd_vtok());
657 sync_reg:
658        if (__udp_vskipto_any(SEMI)) return(TRUE);
659        if (__syncto_class == SYNC_FLEVEL) return(FALSE);
660        else goto again;
661       }
662      if ((syp = __get_sym(__token, __cur_udp->usymtab)) == NULL)
663       {
664 not_reg_port:
665        __pv_ferr(1184,
666         "udp reg declaration of \"%s\" that is not in header port list",
667         __token);
668        goto end_reg;
669       }
670      if (syp->sytyp != SYM_N) goto bad_sytab;
671      mpp = syp->el.empp;
672      if (mpp->mptyp == IO_OUT) mpp->mptyp = NON_IO;
673      else
674       {
675        /* if not output must be undeclared */
676        if (syp->sydecl || mpp->mptyp != IO_UNKN) goto not_reg_port;
677        mpp->mptyp = NON_IO;
678       }
679 end_reg:
680      __get_vtok();
681      if (__toktyp != SEMI)
682       {
683        __pv_ferr(1187,
684         "udp output reg declaration ending semicolon expected - %s read",
685         __prt_vtok());
686        goto sync_reg;
687       }
688      break;
689     default:
690      __pv_ferr(1188,
691       "udp declaration I/O declaration keyword expected - %s read",
692       __prt_vtok());
693     return(FALSE);
694    }
695   }
696  return(TRUE);
697 }
698 
699 /*
700  * read the one optional initial statement for the one udp output
701  * know initial read - format is intial [output term] = [1 bit const]
702  * complicated because no mechanism for conversion from 32 1 bit vals
703  */
rd_udp_init(struct udp_t * udpp)704 static int32 rd_udp_init(struct udp_t *udpp)
705 {
706  int32 blen;
707 
708  __get_vtok();
709  if (__toktyp != ID) goto bad_init;
710  __get_vtok();
711  if (__toktyp != EQ) goto bad_init;
712  __get_vtok();
713  if (__toktyp != NUMBER) goto bad_init;
714  __get_vtok();
715  if (__toktyp != SEMI) goto bad_init;
716  if (__itoklen > WBITS)
717   {
718    blen = __itoklen - WBITS;
719    if (!vval_is0_(&(__acwrk[1]), blen)) goto bad_val;
720    if (!vval_is0_(&(__bcwrk[1]), blen)) goto bad_val;
721   }
722  /* this must be a 1 bit value but wider with all zero's ok */
723  if (__acwrk[0] == 0L && __bcwrk[0] == 0L) udpp->ival = 0;
724  else if (__acwrk[0] == 1L && __bcwrk[0] == 0L)
725   udpp->ival = 1;
726  else if (__acwrk[0] == 0L && __bcwrk[0] == 1L)
727   {
728    __pv_fwarn(576, "udp initial value 1'bz illegal - changed to 1'bx");
729    udpp->ival = 3;
730   }
731  else if (__acwrk[0] == 1L && __bcwrk[0] == 1L) udpp->ival = 3;
732  else
733   {
734 bad_val:
735    __pv_ferr(1191, "udp initial value must be one of: 0, 1, 1'bx - %s read",
736     __prt_vtok());
737    udpp->ival = NO_VAL;
738   }
739  return(TRUE);
740 
741 bad_init:
742  __pv_ferr(1192, "udp initial statement syntax error");
743  if (__udp_vskipto_any(SEMI)) return(TRUE);
744  if (__syncto_class == SYNC_FLEVEL) return(FALSE);
745  return(TRUE);
746 }
747 
748 /*
749  * check and count number of ports and set to default sequential if needed
750  * number of ports in number of inputs (+ 1 if level or edge)
751  * udp type number udp inputs and type set here
752  * error if header port not declared
753  * return FALSE on error
754  */
chkcnt_uports(struct udp_t * udpp)755 static int32 chkcnt_uports(struct udp_t *udpp)
756 {
757  register struct mod_pin_t *mpp;
758  int32 retval;
759  int32 unumins, unumstates;
760 
761  mpp = udpp->upins;
762  retval = TRUE;
763  if (mpp->mptyp == IO_IN)
764   {
765    __gferr(1193, udpp->usym->syfnam_ind, udpp->usym->sylin_cnt,
766     "first udp header port %s not the output", mpp->mpsnam);
767    retval = FALSE;
768   }
769  unumins = unumstates = 0;
770  if (mpp->mptyp == NON_IO) { udpp->utyp = U_LEVEL; unumstates++; }
771 
772  mpp = mpp->mpnxt;
773  for (; mpp != NULL; mpp = mpp->mpnxt)
774   {
775    if (mpp->mptyp != IO_IN)
776     {
777      __gferr(1194, udpp->usym->syfnam_ind, udpp->usym->sylin_cnt,
778       "after first udp port %s must be an input", mpp->mpsnam);
779      retval = FALSE;
780     }
781    unumins++;
782   }
783  udpp->numins = unumins;
784  udpp->numstates = unumins + unumstates;
785  if (udpp->numins > MAXUPRTS)
786   {
787    __gferr(1195, udpp->usym->syfnam_ind, udpp->usym->sylin_cnt,
788     "udp definition has %d ports - maximum allowed is %d",
789     udpp->numins, MAXUPRTS);
790    retval = FALSE;
791   }
792  return(retval);
793 }
794 
795 /*
796  * read the udp table
797  * know table keyword read and reads endtable
798  * when done udp lines are array of chars of length numins + 1 (for out)
799  * numins includes state for non combinatorial
800  *
801  * if edge, 1 allowed edge, char in line is 2nd plus uledinum index of edge
802  * and ultabsel is 1st (maybe wildcard) - need to convert back to r/f abbrev.
803  */
rd_udp_table(struct udp_t * udpp)804 static int32 rd_udp_table(struct udp_t *udpp)
805 {
806  int32 ulcnt, has_wcard, ulfnam_ind;
807  struct utline_t *utlp, *last_utlp;
808  char uline[RECLEN], coduline[RECLEN], s1[RECLEN];
809 
810  __letendnum_state = TRUE;
811  /* initialized for malformed ; only line - error caught later */
812  ulfnam_ind = __cur_fnam_ind;
813  ulcnt = __lin_cnt;
814 
815  for (last_utlp = NULL;;)
816   {
817    __get_vtok();
818    if (__toktyp == ENDTABLE) break;
819    strcpy(uline, "");
820    for (;;)
821     {
822      if (__toktyp == SEMI) goto end_line;
823 
824      /* need beginning of udp entry line no. */
825      ulfnam_ind = __cur_fnam_ind;
826      ulcnt = __lin_cnt;
827      switch ((byte) __toktyp) {
828       case LPAR: strcat(uline, "("); break;
829       case RPAR: strcat(uline, ")"); break;
830       case QUEST: strcat(uline, "?"); break;
831       case MINUS: strcat(uline, "-"); break;
832       case TIMES: strcat(uline, "*"); break;
833       case COLON: strcat(uline, ":"); break;
834       /* this requires that even non sized numbers stored in token */
835       /* works because ' not legal in udp table line */
836       case ID: strcat(uline, __token); break;
837       /* SJM 03/20/00 - must assemble from num token for numbers */
838       case NUMBER: strcat(uline, __numtoken); break;
839       default:
840        __pv_ferr(1198, "invalid udp table line symbol %s", __prt_vtok());
841        if (__udp_vskipto_any(SEMI)) continue;
842        if (__toktyp == ENDTABLE) goto done;
843        if (__syncto_class == SYNC_FLEVEL) goto bad_end;
844        __vskipto_modend(ENDPRIMITIVE);
845 bad_end:
846        __letendnum_state = FALSE;
847        return(FALSE);
848      }
849      __get_vtok();
850     }
851 end_line:
852    /* at this point line collected and contains only 1 char values and punct */
853    /* utyp only U_COMB if does not have reg declaration */
854    if (udpp->utyp == U_COMB)
855     {
856      __cur_utabsel = NO_VAL;
857      __cur_ueipnum = NO_VAL;
858      str_tolower(coduline, uline);
859      if (!chk_comb_udpline(coduline, udpp, &has_wcard)) goto bad_end;
860     }
861    else
862     {
863      str_tolower(s1, uline);
864      /* edge temporarily converted to 0x80 form */
865      if (!cvrt_udpedges(coduline, s1)) return(FALSE);
866      /* edge converted to 1st char __cur_utabsel plus 2nd char here in uline */
867      __cur_utabsel = NO_VAL;
868      if (!chk_sequdpline(coduline, udpp, &has_wcard)) continue;
869     }
870    utlp = (struct utline_t *) __my_malloc(sizeof(struct utline_t));
871    utlp->tline = __pv_stralloc(coduline);
872    utlp->ullen = (word32) strlen(coduline);
873    utlp->ulhas_wcard = (has_wcard) ? TRUE : FALSE;
874    utlp->uledinum = __cur_ueipnum;
875    utlp->utabsel = __cur_utabsel;
876    utlp->utlfnam_ind = ulfnam_ind;
877    utlp->utlin_cnt = ulcnt;
878    utlp->utlnxt = NULL;
879    if (last_utlp == NULL) udpp->utlines = utlp; else last_utlp->utlnxt = utlp;
880    last_utlp = utlp;
881   }
882 done:
883  __letendnum_state = FALSE;
884  return(TRUE);
885 }
886 
str_tolower(char * to,char * from)887 static void str_tolower(char *to, char *from)
888 {
889  while (*from)
890   {
891    if (isupper(*from)) *to++ = (char) tolower(*from); else *to++ = *from;
892    from++;
893   }
894  *to = '\0';
895 }
896 
897 /*
898  * convert (..) form edges to one coded char - real edge processing
899  * in check seqential udp line routine
900  * edge has high bit on and then bits 5-3 is e1 and 2-0 is e2
901  *
902  * know all legal upper case edges converted to lower case before called
903  * first step in udp table line checking - edge abbreviation not seen here
904  */
cvrt_udpedges(char * culine,char * uline)905 static int32 cvrt_udpedges(char *culine, char *uline)
906 {
907  register char *culp, *ulp;
908  char *chp, ech1, ech2;
909  int32 ie1, ie2, no_err;
910  char s1[RECLEN];
911 
912  no_err = FALSE;
913  for (no_err = TRUE, ulp = uline, culp = culine;;)
914   {
915    switch (*ulp) {
916     case '\0': *culp = '\0'; goto done;
917     case '(':
918      ech1 = *(++ulp);
919      if ((ie1 = to_udp_levsym(ech1)) == -1)
920       {
921        __pv_ferr(1202,
922         "udp table line edge first symbol '%c' not a level symbol", ech1);
923 edge_err:
924        no_err = FALSE;
925        /* making error into (? ?) edge */
926        *culp++ = (char) (0x80 + (UV_Q << 3) + UV_Q);
927        if ((chp = strchr(ulp, ')')) == NULL) { *culp = '\0'; return(no_err); }
928        ulp = ++chp;
929        continue;
930       }
931      ech2 = *(++ulp);
932      if ((ie2 = to_udp_levsym(ech2)) == -1)
933       {
934        __pv_ferr(1203,
935         "udp table line edge second symbol '%c' not a level symbol", ech2);
936        goto edge_err;
937       }
938      if (*(++ulp) != ')')
939       {
940        __pv_ferr(1204,
941         "udp table line edge symbol closing ')' expected - %c read", *ulp);
942        goto edge_err;
943       }
944      /* edge has high bit on and bits 5-3 is e1 and 2-0 is e2 */
945      *culp++ = (char) (0x80 | (ie1 << 3) | ie2);
946      ulp++;
947      break;
948     default:
949      *culp++ = *ulp++;
950     }
951   }
952 done:
953  if (__debug_flg)
954   __dbg_msg("&&& converted from %s to %s\n", uline, to_codedge_line(s1,
955    culine));
956  return(no_err);
957 }
958 
959 /*
960  * return value of level symbol (-1 if not level symbol)
961  */
to_udp_levsym(char ch)962 static int32 to_udp_levsym(char ch)
963 {
964  switch (ch) {
965   case '0': return(UV_0);
966   case '1': return(UV_1);
967   case 'x': return(UV_X);
968   case '?': return(UV_Q);
969   case 'b': return(UV_B);
970  }
971  return(-1);
972 }
973 
974 /*
975  * check coded combinatorial udp uline
976  */
chk_comb_udpline(char * uline,struct udp_t * udpp,int32 * has_wcard)977 static int32 chk_comb_udpline(char *uline, struct udp_t *udpp,
978  int32 *has_wcard)
979 {
980  register char *chp;
981  int32 ins;
982  char ch;
983 
984  *has_wcard = FALSE;
985  /* separate off ending :[output] */
986  if ((chp = strrchr(uline, ':')) == NULL)
987   {
988    __pv_ferr(1205,
989     "combinatorial udp line expected ':' output separator missing");
990    return(FALSE);
991   }
992  *chp++ = '\0';
993  ch = *chp++;
994  if (ch == '-')
995   {
996    __pv_ferr(1206,
997     "combinatorial udp line '-' output symbol illegal - has no state");
998    return(FALSE);
999   }
1000  if (ch != '0' && ch != '1' && ch != 'x')
1001   {
1002    __pv_ferr(1207,
1003     "combinatorial udp line output symbol (%x) '%c' illegal", ch, ch);
1004    return(FALSE);
1005   }
1006  if (*chp != '\0')
1007   {
1008    __pv_ferr(1208,
1009     "combinatorial udp line has second output symbol '%c' - only one allowed",
1010     *chp);
1011    return(FALSE);
1012   }
1013  /* check inputs - up to rightmost : */
1014  for (chp = uline, ins = 0; *chp != '\0'; chp++, ins++)
1015   {
1016    switch (*chp) {
1017     case '(': case 'r': case 'f': case 'p': case 'n': case '*':
1018      __pv_ferr(1209, "edge symbol %c illegal in combinatorial udp line", *chp);
1019      return(FALSE);
1020    }
1021    if (to_udp_levsym(*chp) == -1)
1022     {
1023      __pv_ferr(1213,
1024       "combinatorial udp line input symbol '%c' (position %d) not a level symbol",
1025       *chp, ins + 1);
1026      return(FALSE);
1027     }
1028    if (ins >= 254)
1029     {
1030      __pv_ferr(1214,
1031       "udp has so many inputs (%d) - it cannot be checked", 254);
1032      return(FALSE);
1033     }
1034    if (*chp == 'b' || *chp == '?') *has_wcard = TRUE;
1035   }
1036  if (ins != udpp->numins)
1037   {
1038    __pv_ferr(1215,
1039     "combinatorial udp line wrong number of input symbols (%d) - should be %d",
1040     ins, udpp->numins);
1041    return(FALSE);
1042   }
1043  /* finally add output as last symbol */
1044  *chp++ = ch;
1045  *chp = '\0';
1046  return(TRUE);
1047 }
1048 
1049 /*
1050  * check coded sequential upd uline
1051  * know all (..) edge convert to 1 char by here (0x80 on)
1052  * if no edge __cur_ueipnum has value NO_VAL
1053  * old 0x80 bit on form edge converted to 1st as __cur_utabsel, 2nd as char
1054  * unless edge wildcard (i.e. r,f,n, etc.) in which case has edge wildcard
1055  */
chk_sequdpline(char * uline,struct udp_t * udpp,int32 * has_wcard)1056 static int32 chk_sequdpline(char *uline, struct udp_t *udpp,
1057  int32 *has_wcard)
1058 {
1059  register char *chp;
1060  char ch1, ch2;
1061  int32 ins, t1;
1062 
1063  *has_wcard = FALSE;
1064  /* separate off : before previous state :[prev. state]:[output] */
1065  if ((chp = strchr(uline, ':')) == NULL)
1066   {
1067    __pv_ferr(1216,
1068     "sequential udp line expected colon before old state symbol missing");
1069    return(FALSE);
1070   }
1071  /* end uline */
1072  *chp = '\0';
1073  chp++;
1074  /* ch1 is state symbol and -1 means not 1 of legasl 0,1,x,?,b */
1075  ch1 = *chp++;
1076  if (to_udp_levsym(ch1) == -1)
1077   {
1078    __pv_ferr(1218,
1079     "sequential udp line state level symbol '%c' illegal", ch1);
1080    return(FALSE);
1081   }
1082  /* state can be wildcard but not edge */
1083  if (ch1 == 'b' || ch1 == '?') *has_wcard = TRUE;
1084  if (*chp++ != ':')
1085   {
1086    __pv_ferr(1219,
1087     "sequential udp line expected colon before output symbol missing");
1088    return(FALSE);
1089   }
1090  /* ch2 is output symbol */
1091  ch2 = *chp++;
1092  if (ch2 != '0' && ch2 != '1' && ch2 != 'x' && ch2 != '-')
1093   {
1094    __pv_ferr(1221, "sequential udp line output symbol '%c' illegal", ch2);
1095    return(FALSE);
1096   }
1097  if (*chp != '\0')
1098   {
1099    __pv_ferr(1222,
1100     "sequential udp line has extra output symbol '%c' - only one allowed",
1101     *chp);
1102    return(FALSE);
1103   }
1104  /* previous state and output done, finally check inputs */
1105  __cur_utabsel = NO_VAL;
1106  __cur_ueipnum = NO_VAL;
1107  for (chp = uline, ins = 0; *chp != '\0'; chp++, ins++)
1108   {
1109    /* know if edge, already checked - wild card only for level sensitive */
1110    if (is_edgesym(*chp))
1111     {
1112      if (__cur_ueipnum != NO_VAL)
1113       {
1114        __pv_ferr(1223,
1115        "sequential udp line has more than one edge symbol (second input %d)",
1116         ins + 1);
1117        return(FALSE);
1118       }
1119      __cur_ueipnum = ins;
1120      if ((*chp & 0x80) != 0)
1121       {
1122        /* know if (..) edge then both letters are edge symbols */
1123        /* edge has high bit on and then bits 5-3 is ie1 and 2-0 is ie2 */
1124        t1 = *chp & 0x7f;
1125        *chp = to_edgech(t1 & 0x7);
1126        __cur_utabsel = to_edgech((t1 >> 3) & 0x7);
1127        if ((__cur_utabsel == '0' && *chp == '0')
1128         || (__cur_utabsel == '1' && *chp == '1')
1129         || (__cur_utabsel == 'x' && *chp == 'x'))
1130         {
1131          __pv_ferr(1224,
1132           "sequential udp line edge (%c%c) (input %d) illegal - no transition",
1133           __cur_utabsel, *chp, __cur_ueipnum + 1);
1134          return(FALSE);
1135         }
1136       }
1137      else if (*chp == 'r') { __cur_utabsel = '0'; *chp = '1'; }
1138      else if (*chp == 'f') { __cur_utabsel = '1'; *chp = '0'; }
1139      /* if special edge abbrev. but not r or f make both edges have abbrev. */
1140      else __cur_utabsel = *chp;
1141      continue;
1142     }
1143    if (to_udp_levsym(*chp) == -1)
1144     {
1145      __pv_ferr(1225,
1146       "sequential udp line symbol '%c' (input %d) not edge or level", *chp,
1147       ins + 1);
1148      return(FALSE);
1149     }
1150    if (*chp == 'b' || *chp == '?') *has_wcard = TRUE;
1151   }
1152  if (ins != udpp->numstates - 1 || ins != udpp->numins)
1153   {
1154    __pv_ferr(1226,
1155     "sequential udp line wrong number of input symbols (%d) - should be %d",
1156     ins, udpp->numins - 1);
1157    return(FALSE);
1158   }
1159  /* finally add previous state input and next state output as last 2 */
1160  *chp++ = ch1;
1161  *chp++ = ch2;
1162  *chp = '\0';
1163  if (__cur_ueipnum != NO_VAL) udpp->utyp = U_EDGE;
1164  return(TRUE);
1165 }
1166 
1167 /*
1168  * convert edge 4 bit encoding to normal level edge symbol
1169  */
to_edgech(int32 encodee)1170 static char to_edgech(int32 encodee)
1171 {
1172  switch ((byte) encodee) {
1173   case UV_0: return('0');
1174   case UV_1: return('1');
1175   case UV_X: break;
1176   case UV_Q: return('?');
1177   case UV_B: return('b');
1178   default: __case_terr(__FILE__, __LINE__);
1179  }
1180  return('x');
1181 }
1182 
1183 /*
1184  * return T if symbol is an edge symbol (code 0x80 or edge letter)
1185  */
is_edgesym(char ch)1186 static int32 is_edgesym(char ch)
1187 {
1188  if ((ch & 0x80) != 0) return(TRUE);
1189  switch (ch) {
1190   case 'r': case 'f': case 'p': case 'n': case '*': return(TRUE);
1191  }
1192  return(FALSE);
1193 }
1194 
1195 /*
1196  * convert a coded edge line to a string
1197  * in form during input before converted to line separate edge char and
1198  * edge destination in line char position
1199  */
to_codedge_line(char * s,char * culine)1200 static char *to_codedge_line(char *s, char *culine)
1201 {
1202  register char *cpi, *cpo;
1203  int32 uch;
1204 
1205  for (cpi = culine, cpo = s; *cpi != '\0'; cpi++)
1206   {
1207    if ((*cpi & 0x80) != 0)
1208     {
1209      *cpo++ = '(';
1210      /* notice 5-3 are e1 and 2-0 are e2 */
1211      uch = (int32) *cpi;
1212      *cpo++ = to_edgech((uch >> 3) & 0x7);
1213      *cpo++ = to_edgech(uch & 0x7);
1214      *cpo++ = ')';
1215     }
1216    else *cpo++ = *cpi;
1217   }
1218  *cpo = '\0';
1219  return(s);
1220 }
1221 
1222 /*
1223  * perform some consistency checks on edge udps
1224  * - input column probably needs edge in some row
1225  * - output column probably needs - somewhere
1226  */
extra_chk_edgeudp(struct udp_t * udpp)1227 static void extra_chk_edgeudp(struct udp_t *udpp)
1228 {
1229  register int32 i;
1230  int32 out_hasbar;
1231  struct utline_t *utlp;
1232 
1233  for (i = 0; i < (int32) udpp->numins; i++)
1234   {
1235    for (utlp = udpp->utlines; utlp != NULL; utlp = utlp->utlnxt)
1236     {
1237      if (utlp->uledinum == i) goto next;
1238     }
1239    __gfinform(421, udpp->usym->syfnam_ind, udpp->usym->sylin_cnt,
1240     "sequential udp \"%s\" column for input %s lacks any edge(s)",
1241      udpp->usym->synam, to_udp_prtnam(udpp, i + 1));
1242 next:;
1243   }
1244  /* inputs are 0 to num ins - 1 then previous state, then next state */
1245  i = udpp->numins + 1;
1246  out_hasbar = FALSE;
1247  for (utlp = udpp->utlines; utlp != NULL; utlp = utlp->utlnxt)
1248   {
1249    if (utlp->tline[i] == '-') out_hasbar = TRUE;
1250   }
1251  if (!out_hasbar)
1252   {
1253    __gfinform(422, udpp->usym->syfnam_ind, udpp->usym->sylin_cnt,
1254     "sequential udp %s output column lacks any no change (-) symbols",
1255     udpp->usym->synam);
1256   }
1257 }
1258 
1259 /*
1260  * find input position %d (first is output)
1261  * know position number legal and starts at 1
1262  */
to_udp_prtnam(struct udp_t * udpp,int32 inum)1263 static char *to_udp_prtnam(struct udp_t *udpp, int32 inum)
1264 {
1265  register struct mod_pin_t *mpp;
1266  int32 nins;
1267 
1268  nins = 1;
1269  mpp = udpp->upins->mpnxt;
1270  for (; mpp != NULL; mpp = mpp->mpnxt, nins++)
1271   {
1272    if (nins == inum) goto done;
1273   }
1274  __misc_terr(__FILE__, __LINE__);
1275 done:
1276  return(mpp->mpsnam);
1277 }
1278 
1279 /*
1280  * UDP DUMP ROUTINES - FOR DEBUGGING
1281  */
1282 
1283 /*
1284  * dump a udp for debugging
1285  * f cannot be nil to put in string
1286  */
__dmp_udp(FILE * f,struct udp_t * udpp)1287 extern void __dmp_udp(FILE *f, struct udp_t *udpp)
1288 {
1289  register struct mod_pin_t *mpp;
1290  int32 first_time;
1291  char s1[RECLEN], s2[RECLEN];
1292 
1293  if (f == NULL) __arg_terr(__FILE__, __LINE__);
1294  __cv_msg("\n");
1295  __cur_sofs = 0;
1296  __outlinpos = 0;
1297  __pv_stlevel = 0;
1298 
1299  __wrap_puts("primitive ", f);
1300  __wrap_puts(udpp->usym->synam, f);
1301  first_time = TRUE;
1302  /* notice udp module pin lists continue to use next pointer */
1303  for (mpp = udpp->upins; mpp != NULL; mpp = mpp->mpnxt)
1304   {
1305    if (first_time) { __wrap_putc('(', f); first_time = FALSE; }
1306    else __wrap_puts(", ", f);
1307    /* know udp pins must be named */
1308    __wrap_puts(mpp->mpsnam, f);
1309   }
1310  __nl_wrap_puts(");", f);
1311 
1312  /* notice here mpsnam must exist or earlier syntax error */
1313  __pv_stlevel = 1;
1314  mpp = udpp->upins;
1315  __wrap_puts("output ", f);
1316  __wrap_puts(mpp->mpsnam, f);
1317  __wrap_putc(';', f);
1318  if (udpp->utyp != U_COMB)
1319   {
1320    __wrap_puts("  reg ", f);
1321    __wrap_puts(mpp->mpsnam, f);
1322    __wrap_putc(';', f);
1323   }
1324  __nl_wrap_puts("", f);
1325 
1326  __wrap_puts("input ", f);
1327  first_time = TRUE;
1328  for (mpp = mpp->mpnxt; mpp != NULL; mpp = mpp->mpnxt)
1329   {
1330    if (first_time) first_time = FALSE; else __wrap_puts(", ", f);
1331    __wrap_puts(mpp->mpsnam, f);
1332   }
1333  __nl_wrap_puts(";", f);
1334 
1335  if (udpp->ival != NO_VAL)
1336   {
1337    __wrap_puts("initial ", f);
1338    __wrap_puts(udpp->upins->mpsnam, f);
1339    sprintf(s1, " = 1'b%s", __to_uvvnam(s2, (word32) udpp->ival));
1340    __wrap_puts(s1, f);
1341    __nl_wrap_puts(";", f);
1342   }
1343  __nl_wrap_puts("", f);
1344  __nl_wrap_puts("table", f);
1345  dmp_udp_lines(f, udpp);
1346  __nl_wrap_puts("endtable", f);
1347  __pv_stlevel--;
1348  __nl_wrap_puts("endprimitive", f);
1349 }
1350 
1351 /*
1352  * dump udp lines
1353  * need to also dump initial value
1354  */
dmp_udp_lines(FILE * f,struct udp_t * udpp)1355 static void dmp_udp_lines(FILE *f, struct udp_t *udpp)
1356 {
1357  register int32 i;
1358  register struct utline_t *utlp;
1359  int32 numins, sav_stlevel;
1360  char *chp, s1[RECLEN];
1361 
1362  sav_stlevel = __pv_stlevel;
1363  __pv_stlevel = 4;
1364  __outlinpos = 0;
1365  numins = udpp->numins;
1366  for (utlp = udpp->utlines; utlp != NULL; utlp = utlp->utlnxt)
1367   {
1368    for (chp = utlp->tline, i = 0; i < numins; i++, chp++)
1369     {
1370      /* the one possible edge */
1371      if (utlp->uledinum == i)
1372       {
1373        /* special wild card types edges are kept as original char */
1374        /* 01 and 10 are converted from rise-fall - convert back */
1375        if (utlp->utabsel == '0' && *chp == '1') __wrap_puts("    r", f);
1376        else if (utlp->utabsel == '1' && *chp == '0') __wrap_puts("    f", f);
1377        else if (utlp->utabsel == '*') __wrap_puts("    *", f);
1378        else if (utlp->utabsel == 'p') __wrap_puts("    p", f);
1379        else if (utlp->utabsel == 'n') __wrap_puts("    n", f);
1380        else
1381         {
1382          sprintf(s1, " (%c%c)", (char) utlp->utabsel, *chp);
1383          __wrap_puts(s1, f);
1384         }
1385       }
1386      /* various wild cards and states left as input char */
1387      else { sprintf(s1, "%5c", *chp); __wrap_puts(s1, f); }
1388     }
1389    if (udpp->utyp != U_COMB)
1390     { sprintf(s1, " : %c ", *chp); __wrap_puts(s1, f); chp++; }
1391    sprintf(s1, " : %c ;", *chp);
1392    __nl_wrap_puts(s1, f);
1393   }
1394  __pv_stlevel = sav_stlevel;
1395 }
1396 
1397 /*
1398  * READ SPECIFY SECTION ROUTINES
1399  */
1400 
1401 /*
1402  * read and build d.s for specify section items
1403  * expects specify to have been read and reads endspecify
1404  * current approach concatenates all specify sections in one mod.
1405  */
__rd_spfy(struct mod_t * mdp)1406 extern int32 __rd_spfy(struct mod_t *mdp)
1407 {
1408  int32 tmpi, sav_decl_obj;
1409  word32 tchktyp;
1410  char s1[RECLEN];
1411 
1412  __path_num = __tchk_num = 1;
1413  sav_decl_obj = __cur_declobj;
1414  __cur_declobj = SPECIFY;
1415  /* all specify sections concatenated together */
1416  if (mdp->mspfy == NULL) mdp->mspfy = alloc_spfy();
1417  __cur_spfy = mdp->mspfy;
1418  /* at this point only module symbol tabl on scope stack since specify */
1419  /* is module item */
1420  if (__top_sti != 0) __misc_terr(__FILE__, __LINE__);
1421  /* place special symbol table for specparams on scope stack */
1422  __venviron[++__top_sti] = __cur_spfy->spfsyms;
1423 
1424  for (;;)
1425   {
1426    __get_vtok();
1427    switch ((byte) __toktyp)
1428     {
1429      case SPECPARAM:
1430       if (!rd_specparamdecl())
1431        {
1432         /* notice unless T (found ;) will not sync to normal ( path */
1433 specitem_resync:
1434         switch ((byte) __syncto_class) {
1435          case SYNC_FLEVEL: case SYNC_MODLEVEL: case SYNC_STMT:
1436           __top_sti--;
1437           return(FALSE);
1438          case SYNC_SPECITEM:
1439           break;
1440          /* if sync. to statement assume initial left out */
1441          default: __case_terr(__FILE__, __LINE__);
1442         }
1443        }
1444       continue;
1445      case IF: case LPAR: case IFNONE:
1446       if (!rd_delay_pth()) goto specitem_resync;
1447       break;
1448      case ENDSPECIFY: goto done;
1449      case ID:
1450       /* this must be timing check */
1451       if (*__token == '$')
1452        {
1453         if ((tmpi = __fr_tcnam(__token)) == -1)
1454          {
1455           __pv_ferr(1228,
1456            "system task %s illegal in specify section", __token);
1457           goto err_skip;
1458          }
1459         tchktyp = tmpi;
1460         __get_vtok();
1461         if (__toktyp != LPAR)
1462          {
1463           __pv_ferr(1231,
1464           "timing check %s argument list left parenthesis expected - %s read",
1465           __to_tcnam(s1, tchktyp) , __prt_vtok());
1466           goto err_skip;
1467          }
1468         /* specify system timing check tasks */
1469         /* the routines fill cur tchk */
1470         switch ((byte) tchktyp) {
1471          case TCHK_SETUP: case TCHK_HOLD:
1472           if (!rd_setup_or_hold_tchk(tchktyp)) goto specitem_resync;
1473           break;
1474          case TCHK_SETUPHOLD:
1475           if (!rd_setuphold_tchk()) goto specitem_resync;
1476           break;
1477          case TCHK_WIDTH:
1478           if (!rd_width_tchk()) goto specitem_resync;
1479           break;
1480          case TCHK_PERIOD:
1481           if (!rd_period_tchk()) goto specitem_resync;
1482           break;
1483          case TCHK_SKEW: case TCHK_RECOVERY: case TCHK_REMOVAL:
1484           if (!rd_skew_recov_rem_tchk(tchktyp)) goto specitem_resync;
1485           break;
1486          case TCHK_RECREM:
1487           if (!rd_recrem_tchk()) goto specitem_resync;
1488           break;
1489          case TCHK_NOCHANGE:
1490           if (!rd_nochg_tchk()) goto specitem_resync;
1491           break;
1492          case TCHK_FULLSKEW:
1493          case TCHK_TIMESKEW:
1494           /* SJM 11/21/03 - this and other new 2001 tchks not supported */
1495           /* for now just skip and later add support for this and others */
1496           __pv_fwarn(3124,"%s timing check not yet supported - ignored",
1497            __to_tcnam(__xs, tchktyp));
1498           goto err_skip;
1499          default: __case_terr(__FILE__, __LINE__);
1500         }
1501         /* add to timing check list */
1502         if (__end_tchks == NULL) __cur_spfy->tchks = __cur_tchk;
1503         else __end_tchks->tchknxt = __cur_tchk;
1504         __end_tchks = __cur_tchk;
1505         break;
1506        }
1507       /* fall through to error since ID not specify item */
1508       /*FALLTHRU*/
1509      default:
1510       __pv_ferr(1229, "specify section item expected - %s read",
1511        __prt_vtok());
1512 err_skip:
1513      if (!__spec_vskipto_any(SEMI)) goto specitem_resync;
1514      /* just fall through if seme to next */
1515     }
1516   }
1517 done:
1518  __top_sti = 0;
1519  __cur_declobj = sav_decl_obj;
1520  /* notice freezing at module end for specparam symbol table too */
1521  return(TRUE);
1522 }
1523 
1524 /*
1525  * allocate a specify block - called when first specify block seen
1526  */
alloc_spfy(void)1527 static struct spfy_t *alloc_spfy(void)
1528 {
1529  struct spfy_t *spcp;
1530 
1531  spcp = (struct spfy_t *) __my_malloc(sizeof(struct spfy_t));
1532  /* notice this symbol table links to mod through this special specify */
1533  /* block but otherwise no symbol table links */
1534  spcp->spfsyms = __alloc_symtab(TRUE);
1535  spcp->spcpths = NULL;
1536  spcp->tchks = NULL;
1537  spcp->msprms = NULL;
1538  spcp->sprmnum = 0;
1539  __end_spcpths = NULL;
1540  __end_tchks = NULL;
1541  __end_msprms = NULL;
1542  return(spcp);
1543 }
1544 
1545 /*
1546  * read the specparam declaration statement
1547  * form: specparam [name] = [constant?], ...
1548  * no  # and () around delay is optional in parameter decl.
1549  * reads parameter name through ending ;
1550  *
1551  * here width actual bit width - later converted to int32 or real
1552  * and then usually to 64 bit delay
1553  */
rd_specparamdecl(void)1554 static int32 rd_specparamdecl(void)
1555 {
1556  int32 good, sav_slin_cnt, sav_sfnam_ind, prng_decl, pwid, rwid, r1, r2;
1557  struct net_t *np;
1558  struct expr_t *dx1, *dx2, *x1, *x2;
1559  char paramnam[IDLEN];
1560 
1561  pwid = 0;
1562  dx1 = dx2 = x1 = x2 = NULL;
1563  prng_decl = FALSE;
1564  __get_vtok();
1565  if (__toktyp == LSB)
1566   {
1567    /* also check to make sure ranges are non x/z 32 bit values */
1568    if (!__rd_opt_param_vec_rng(&dx1, &dx2, FALSE)) return(FALSE);
1569    if (dx1 == NULL || dx2 == NULL) goto rd_param_list;
1570 
1571    r1 = (int32) __contab[dx1->ru.xvi];
1572    r2 = (int32) __contab[dx2->ru.xvi];
1573    pwid = (r1 >= r2) ? r1 - r2 + 1 : r2 - r1 + 1;
1574    x1 = dx1; x2 = dx2;
1575    prng_decl = TRUE;
1576    /* know parameter name read */
1577   }
1578 
1579 rd_param_list:
1580  for (;;)
1581   {
1582    if (__toktyp != ID)
1583     {
1584      __pv_ferr(1230, "specparam name expected - %s read", __prt_kywrd_vtok());
1585 bad_end:
1586      /* part of delay expression may have been built */
1587      if (!__spec_vskipto2_any(COMMA, SEMI)) return(FALSE);
1588      if (__toktyp == COMMA) { __get_vtok(); continue; }
1589      return(TRUE);
1590     }
1591    strcpy(paramnam, __token);
1592 
1593    /* notice the initial value is required */
1594    __get_vtok();
1595    if (__toktyp != EQ)
1596     {
1597      __pv_ferr(1232,
1598       "specparam declaration equal expected - %s read", __prt_vtok());
1599      goto bad_end;
1600     }
1601    /* 06/22/00 - SJM - special path pulse form, for now ignore with warn */
1602    if (strncmp(paramnam, "PATHPULSE$", 10) == 0)
1603     {
1604      __pv_fwarn(3102,
1605       "%s special path pulse specparam ignored - use +show_canceled_e option instead",
1606       paramnam);
1607      /* 06/22/00 - SJM - FIXME - need to really parse this */
1608      if (!__spec_vskipto_any(SEMI))
1609       {
1610        __pv_ferr(3408,
1611         "PATHPULSE$ specparam %s right hand side value illegal format",
1612         paramnam);
1613        return(FALSE);
1614       }
1615      goto nxt_sparam;
1616     }
1617 
1618    /* know symbol table env. in specify specparam rhs specparam local */
1619    __get_vtok();
1620    __sav_spsytp = __venviron[0];
1621    __venviron[0] = __venviron[1];
1622    __top_sti = 0;
1623    good = __col_paramrhsexpr();
1624    __venviron[0] = __sav_spsytp;
1625    __top_sti = 1;
1626    /* on error, does not add spec param */
1627    if (!good) goto bad_end;
1628    __bld_xtree(0);
1629 
1630    /* checking rhs does no evaluation (not known yet) but set sizes */
1631    /* and makes sure contains only num and previously defined specparams */
1632    if (__expr_has_glb(__root_ndp)
1633     || !__src_rd_chk_paramexpr(__root_ndp, WBITS))
1634     {
1635      __pv_ferr(1233,
1636       "specparam %s right hand side %s illegal - defined specparams and constants only",
1637       paramnam, __msgexpr_tostr(__xs, __root_ndp));
1638      goto nxt_sparam;
1639     }
1640 
1641    /* SJM 06/17/99 - illegal to assign string literal to specparam */
1642    /* SJM 02/04/00 - must allow since needed for models where PLI used */
1643    /* to read parameter value - and should be this is just wide reg */
1644    /* --- REMOVED ---
1645    if (__root_ndp->is_string)
1646     {
1647      __pv_fwarn(659,
1648       "specparam %s right hand side string not a delay value - converted to 0 delay",
1649       paramnam);
1650      -* need to still add value of x to prevent further errors *-
1651      __free2_xtree(__root_ndp);
1652      __root_ndp->szu.xclen = WBITS;
1653      __set_numval(__root_ndp, 0L, 0L, WBITS);
1654      -* notice x1, x2 range expressions always WBITS-1 to 0 for specparams *-
1655     }
1656    --- */
1657 
1658    /* if range declared that is used, else if non scalar expr, use that */
1659    if (prng_decl)
1660     {
1661      if (pwid == 1) x1 = x2 = NULL;
1662      else
1663       {
1664        /* for specparam - assume int/word32, convert to real if needed */
1665        x1 = __bld_rng_numxpr(pwid - 1L, 0L, WBITS);
1666        x2 = __bld_rng_numxpr(0L, 0L, WBITS);
1667       }
1668     }
1669    else
1670     {
1671      if (__root_ndp->is_real) rwid = REALBITS;
1672      else rwid = __root_ndp->szu.xclen;
1673 
1674      if (rwid == 1) x1 = x2 = NULL;
1675      else
1676       {
1677        /* if expr value unsized, know will be 32 bit width already */
1678        x1 = __bld_rng_numxpr(rwid - 1, 0, WBITS);
1679        x2 = __bld_rng_numxpr(0, 0, WBITS);
1680       }
1681     }
1682 
1683    /* check and links on modules parameter list */
1684    /* when rhs expr. evaluated, if real will change */
1685    /* LOOKATME - problem with all params in list sharing range xprs? */
1686    np = __add_param(paramnam, x1, x2, FALSE);
1687 
1688    /* using ncomp delay union to store original expresssion - set first */
1689    /* need this separate copy even after parameter value assigned */
1690    np->nu.ct->n_dels_u.d1x = __root_ndp;
1691    np->nu.ct->parm_srep = SR_PXPR;
1692 
1693    /* can assign specparam value immediately */
1694    /* SJM 06/17/99 - needs to run in run/fixup mode - statement loc set */
1695    sav_slin_cnt = __slin_cnt;
1696    sav_sfnam_ind = __sfnam_ind;
1697    __sfnam_ind = (int32) np->nsym->syfnam_ind;
1698    __slin_cnt = np->nsym->sylin_cnt;
1699 
1700    assign_1specparam(np, __root_ndp, prng_decl, pwid);
1701 
1702    __slin_cnt = sav_slin_cnt;
1703    __sfnam_ind = sav_sfnam_ind;
1704 
1705    /* specparams can never be strings or IS forms */
1706    __mod_specparams++;
1707 
1708 nxt_sparam:
1709    if (__toktyp == SEMI) break;
1710    if (__toktyp != COMMA)
1711     {
1712      __pv_ferr(1236,
1713       "specparam ; or , separator expected - %s read", __prt_vtok());
1714      if (!__spec_vskipto2_any(COMMA, SEMI)) return(FALSE);
1715      if (__toktyp == SEMI) break;
1716     }
1717    __get_vtok();
1718   }
1719  return(TRUE);
1720 }
1721 
1722 /*
1723  * assign values to specparams - like defparams but can never be IS form
1724  *
1725  * 02/04/00 - SJM change to move toward v2k LRM and match XL better
1726  * type determined from RHS - range allowed and used for width
1727  *
1728  * SJM 10/06/03 - signed keyword illegal and specparams never signed
1729  * unless real
1730  */
assign_1specparam(struct net_t * np,struct expr_t * ndp,int32 prng_decl,int32 pwid)1731 static void assign_1specparam(struct net_t *np, struct expr_t *ndp,
1732  int32 prng_decl, int32 pwid)
1733 {
1734  int32 wlen;
1735  word32 *wp;
1736  struct xstk_t *xsp;
1737 
1738  /* need dummy itree place on itree stack for eval */
1739  xsp = __eval_xpr(ndp);
1740 
1741  /* case 1: range declaration - may need to convert value */
1742  if (prng_decl)
1743   {
1744    /* convert declared param type real rhs to int/reg */
1745    if (ndp->is_real)
1746     {
1747      __cnv_stk_fromreal_toreg32(xsp);
1748      np->nu.ct->pbase = BDEC;
1749      np->nu.ct->prngdecl = TRUE;
1750      np->nwid = xsp->xslen;
1751      np->ntyp = N_REG;
1752      np->n_signed = TRUE;
1753     }
1754    else
1755     {
1756      if (xsp->xslen != pwid) __sizchgxs(xsp, pwid);
1757 
1758      np->nu.ct->prngdecl = TRUE;
1759      np->nwid = xsp->xslen;
1760      np->ntyp = N_REG;
1761      if (np->nwid > 1) { np->n_isavec = TRUE; np->vec_scalared = TRUE; }
1762      np->nu.ct->pbase = ndp->ibase;
1763     }
1764 
1765    wlen = wlen_(np->nwid);
1766    wp = (word32 *) __my_malloc(2*WRDBYTES*wlen);
1767    memcpy(wp, xsp->ap, 2*WRDBYTES*wlen);
1768    __pop_xstk();
1769    np->nva.wp = wp;
1770    np->srep = SR_PNUM;
1771    return;
1772   }
1773 
1774  /* SJM 10/06/03 - since specparams never signed, interpret as word32 */
1775  /* even if rhs signed with sign bit on */
1776 
1777  /* case 2: type determined from constant expr */
1778  /* spec params either reg or real - by here if range decl ndp fixed */
1779  if (ndp->is_real)
1780   {
1781    np->nwid = REALBITS;
1782    np->ntyp = N_REAL;
1783    np->n_signed = TRUE;
1784    np->n_isavec = TRUE;
1785    np->nu.ct->pbase = BDBLE;
1786    wp = (word32 *) __my_malloc(2*WRDBYTES);
1787    memcpy(wp, xsp->ap, 2*WRDBYTES);
1788   }
1789  else
1790   {
1791    np->nwid = xsp->xslen;
1792    np->ntyp = N_REG;
1793    if (np->nwid > 1) { np->n_isavec = TRUE; np->vec_scalared = TRUE; }
1794    if (ndp->is_string) np->nu.ct->pstring = TRUE;
1795 
1796    np->nu.ct->pbase = ndp->ibase;
1797    wlen = wlen_(np->nwid);
1798    wp = (word32 *) __my_malloc(2*WRDBYTES*wlen);
1799    memcpy(wp, xsp->ap, 2*WRDBYTES*wlen);
1800   }
1801  __pop_xstk();
1802  /* build wire value - this is assign to wire so wire flags unchged */
1803  np->nva.wp = wp;
1804  np->srep = SR_PNUM;
1805 }
1806 
1807 /*
1808  * DELAY PATH ROUTINES
1809  */
1810 
1811 /*
1812  * read the ([path desc. list?] [=*]> [path desc. list?]) = [path val.]
1813  * know initial ( read and if conditional present in condx
1814  * notice no path if any error but may still return T
1815  *
1816  * here when collecting expressions both specparams and top module symbol
1817  * table accessible for wires but only local specparams for delay
1818  */
rd_delay_pth(void)1819 static int32 rd_delay_pth(void)
1820 {
1821  int32 good;
1822  int32 pdtyp, pth_edge, pthpolar, datasrcpolar, is_ifnone;
1823  struct sy_t *pthsyp;
1824  struct exprlst_t *ilstx, *olstx;
1825  struct paramlst_t *pmphdr;
1826  struct expr_t *condx, *datsrcx, *lop, *last_dsx;
1827  struct spcpth_t *pthp;
1828 
1829  is_ifnone = FALSE;
1830  condx = datsrcx = NULL;
1831  /* needed since gcc sees as unset - do not think so */
1832  olstx = NULL;
1833  pdtyp = PTH_NONE;
1834  datasrcpolar = POLAR_NONE;
1835  pthpolar = POLAR_NONE;
1836  if (__toktyp == IFNONE)
1837   {
1838    __get_vtok();
1839    if (__toktyp != LPAR)
1840     {
1841      __pv_ferr(1197,
1842       "sdpd ifnone token not followed by path beginning ( - %s read",
1843       __prt_vtok());
1844      /* here skipping to ) will skip path - no start tok - can not correct */
1845      if (!__spec_vskipto_any(SEMI)) return(FALSE);
1846      return(TRUE);
1847     }
1848    is_ifnone = TRUE;
1849    goto no_pthcond;
1850   }
1851  if (__toktyp == LPAR) goto no_pthcond;
1852  /* must be if token to get here, read optional condition expr. 1st */
1853  __get_vtok();
1854  if (__toktyp != LPAR)
1855   {
1856    __pv_ferr(1251,
1857     "sdpd conditional expression if token not followed by ( - %s read",
1858      __prt_vtok());
1859 bad_sdp:
1860    if (!__spec_vskipto2_any(SEMI, RPAR)) return(FALSE);
1861    if (__toktyp == SEMI) return(TRUE);
1862    /* have ) make cond x NULL - this is not delay this is if actual expr */
1863    __set_numval(__exprtab[0], 1L, 1L, 1);
1864    __last_xtk = 0;
1865    goto bad_sdpx;
1866   }
1867  __get_vtok();
1868  if (!__col_parenexpr(-1)) goto bad_sdp;
1869 bad_sdpx:
1870  __bld_xtree(0);
1871  condx = __root_ndp;
1872  if (__expr_has_glb(condx))
1873   {
1874    __pv_ferr(1022,
1875     "global hierarchical reference illegal in state dependent path condition %s",
1876     __msgexpr_tostr(__xs, condx));
1877   }
1878  __get_vtok();
1879  if (__toktyp != LPAR)
1880   {
1881    __pv_ferr(1252,
1882     "sdpd conditional expression not followed by path start ( - %s read",
1883     __prt_vtok());
1884    /* here skipping to ) will skip path */
1885    if (!__spec_vskipto_any(SEMI)) return(FALSE);
1886    return(TRUE);
1887   }
1888 
1889 no_pthcond:
1890  /* for edge sensitive path can have edge before input */
1891  /* but only pos and neg edges */
1892  __get_vtok();
1893  if (__toktyp == NEGEDGE || __toktyp == POSEDGE)
1894   {
1895    pth_edge = (__toktyp == NEGEDGE) ? E_NEGEDGE : E_POSEDGE;
1896    __get_vtok();
1897   }
1898  else pth_edge = NOEDGE;
1899 
1900  /* this requires read 1st token of path */
1901  if ((ilstx = rd_pthtermlst()) == NULL)
1902   {
1903 bad_pth:
1904    if (!__spec_vskipto3_any(SEMI, RPAR, EQ)) return(FALSE);
1905    if (__toktyp == RPAR) goto get_eq;
1906    if (__toktyp == EQ) goto got_eq;
1907    return(TRUE);
1908   }
1909  /* this just attempts to catch some common errors */
1910  if (__toktyp == RPAR || __toktyp == TCHKEVAND)
1911   {
1912    __pv_ferr(1253,
1913     "input path description connector operator or semicolon expected - %s read",
1914     __prt_vtok());
1915    goto bad_pth;
1916   }
1917  /* path polarity is option stored for pli but not used */
1918  if (__toktyp == PLUS || __toktyp == MINUS)
1919   {
1920    pthpolar = (__toktyp == PLUS) ? POLAR_PLUS : POLAR_MINUS;
1921    __get_vtok();
1922   }
1923  else pthpolar = POLAR_NONE;
1924 
1925  /* path type required */
1926  if (__toktyp == FPTHCON) pdtyp = PTH_FULL;
1927  else if (__toktyp == PPTHCON) pdtyp = PTH_PAR;
1928  else
1929   {
1930    __pv_ferr(1258,
1931     "either full => or parallel *> path operator expected - %s read",
1932     __prt_vtok());
1933    goto bad_pth;
1934   }
1935  /* if ( here then form is ([dst. term list] [polarity?]:[data src. expr.]) */
1936  __get_vtok();
1937  if (__toktyp == LPAR)
1938   {
1939    /* this requires read 1st token of path */
1940    __get_vtok();
1941    if ((olstx = rd_pthtermlst()) == NULL) goto bad_end;
1942    /* data source polarity determines delay selection */
1943    if (__toktyp == PLUS || __toktyp == MINUS)
1944     {
1945      datasrcpolar = (__toktyp == PLUS) ? POLAR_PLUS : POLAR_MINUS;
1946      __get_vtok();
1947     }
1948    else datasrcpolar = POLAR_NONE;
1949    if (__toktyp != COLON)
1950     {
1951      __pv_ferr(1254,
1952       "data source path destination colon terminator expected - %s read",
1953       __prt_vtok());
1954      goto bad_pth;
1955     }
1956    __get_vtok();
1957    /* comma separated list allowed here - width must match dest. width */
1958    if (!__col_parenexpr(-1)) goto bad_pth;
1959    __bld_xtree(0);
1960    /* common edge path trigger as 1 expression not list case */
1961    if (__toktyp != COMMA)
1962     { datsrcx = __root_ndp; __get_vtok(); goto chk_endrpar; }
1963 
1964    /* this is complicated data source expression list case */
1965    lop = __alloc_newxnd();
1966    lop->optyp = FCCOM;
1967    lop->ru.x = NULL;
1968    lop->lu.x = __root_ndp;
1969    datsrcx = lop;
1970    for (last_dsx = lop;;)
1971     {
1972      /* if good this reads trailing delimiter */
1973      if (!__col_connexpr(-1)) goto bad_end;
1974      __bld_xtree(0);
1975      lop = __alloc_newxnd();
1976      lop->optyp = FCCOM;
1977      lop->ru.x = NULL;
1978      lop->lu.x = __root_ndp;
1979      last_dsx->ru.x = lop;
1980      if (__toktyp == RPAR) { __get_vtok(); break; }
1981      if (__toktyp != COMMA)
1982       {
1983        __pv_ferr(1255,
1984         "edge sensitive path data source expression list separator expected - %s read",
1985         __prt_vtok());
1986        goto bad_end;
1987       }
1988      __get_vtok();
1989      if (__toktyp == COMMA || __toktyp == RPAR)
1990       {
1991         __pv_ferr(1259,
1992          "edge sensitive path data source expression ,, or ,) forms illegal");
1993         goto bad_end;
1994       }
1995     }
1996   }
1997  else if ((olstx = rd_pthtermlst()) == NULL) goto bad_pth;
1998 
1999 chk_endrpar:
2000  if (__toktyp != RPAR)
2001   {
2002    __pv_ferr(1256,
2003     "path output terminal list right parenthesis expected - %s read",
2004     __prt_vtok());
2005    goto bad_pth;
2006   }
2007 get_eq:
2008  __get_vtok();
2009  if (__toktyp != EQ)
2010   {
2011    __pv_ferr(1257, "path delay equal sign expected - %s read",
2012     __prt_vtok());
2013 bad_end:
2014    if (!__spec_vskipto_any(SEMI)) return(FALSE);
2015    return(TRUE);
2016   }
2017 got_eq:
2018  /* know symbol table env. in specify always specparam local on mod. lev. */
2019  __sav_spsytp = __venviron[0];
2020  __venviron[0] = __venviron[1];
2021  __top_sti = 0;
2022  /* notice = read but not ( - unusual case of no 1st token read before call */
2023  good = rd_pathdelaylist(&pmphdr);
2024  __venviron[0] = __sav_spsytp;
2025  __top_sti++;
2026  if (!good) goto bad_end;
2027 
2028  /* build the path delay element */
2029  pthp = (struct spcpth_t *) __my_malloc(sizeof(struct spcpth_t));
2030  init_spcpth(pthp);
2031  pthp->pthtyp = pdtyp;
2032  pthp->pthpolar = pthpolar;
2033  pthp->peins = (struct pathel_t *) ilstx;
2034  pthp->peouts = (struct pathel_t *) olstx;
2035 
2036  /* add the location identifying symbol */
2037  pthsyp = __bld_loc_symbol(__path_num, __venviron[0], "path", "delay path");
2038  pthsyp->sytyp = SYM_PTH;
2039  pthsyp->syfnam_ind = __cur_fnam_ind;
2040  pthsyp->sylin_cnt = __lin_cnt;
2041  pthp->pthsym = pthsyp;
2042  pthsyp->el.epthp = pthp;
2043  pthsyp->sydecl = TRUE;
2044  __path_num++;
2045 
2046  /* set delay part */
2047  pthp->pth_delrep = DT_CMPLST;
2048  pthp->pth_du.pdels = pmphdr;
2049 
2050  /* set sdpd and conditional path values */
2051  pthp->pthedge = pth_edge;
2052  pthp->dsrc_polar = datasrcpolar;
2053  pthp->datasrcx = datsrcx;
2054  pthp->pth_ifnone = is_ifnone;
2055  pthp->pthcondx = condx;
2056 
2057  if (__end_spcpths == NULL) __cur_spfy->spcpths = pthp;
2058  else __end_spcpths->spcpthnxt = pthp;
2059  __end_spcpths = pthp;
2060  return(TRUE);
2061 }
2062 
2063 /*
2064  * read a path terminal list
2065  * know 1st token read and reads ending )
2066  */
rd_pthtermlst(void)2067 static struct exprlst_t *rd_pthtermlst(void)
2068 {
2069  struct exprlst_t *xpmphdr, *xpmp, *last_xpmp;
2070 
2071  /* build specify terminal list - semantics that requires subset of mod. */
2072  /* I/O port terminals checked later */
2073  /* no ,, and at least one required */
2074  for (xpmphdr = NULL, last_xpmp = NULL;;)
2075   {
2076    /* this will have skipped to end of statement on error */
2077    if (!col_pthexpr()) return(NULL);
2078    __bld_xtree(0);
2079    xpmp = __alloc_xprlst();
2080    xpmp->xp = __root_ndp;
2081    if (last_xpmp == NULL) xpmphdr = xpmp; else last_xpmp->xpnxt = xpmp;
2082    last_xpmp = xpmp;
2083    if (__toktyp == RPAR || __toktyp == FPTHCON || __toktyp == PPTHCON
2084     || __toktyp == PLUS || __toktyp == MINUS || __toktyp == TCHKEVAND
2085     || __toktyp == COLON) break;
2086    __get_vtok();
2087   }
2088  return(xpmphdr);
2089 }
2090 
2091 /*
2092  * collect a delay path terminal expression
2093  * expects 1st token to be read and read ending token
2094  * ends with ) or ',' or => or *> or - or + or : preceding connection op.
2095  * for timing checks can end with TCHKEVAND &&&
2096  * allows full expressions because port bit select can be full const. expr.
2097  *
2098  * notice ending thing not included in expr. but left in token
2099  *
2100  * this collects a specify expr. - caller must eliminate wrong tokens for
2101  * either tchk or path
2102  *
2103  * notice this is lhs element not delay constants
2104  * maybe should be empty on error
2105  */
col_pthexpr(void)2106 static int32 col_pthexpr(void)
2107 {
2108  int32 parlevel, sqblevel;
2109 
2110  for (__last_xtk = -1, parlevel = 0, sqblevel = 0;;)
2111   {
2112    switch ((byte) __toktyp) {
2113     case LPAR: parlevel++; break;
2114     /* any expression (must later be constant) legal in selects */
2115     case LSB: sqblevel++; break;
2116     case RPAR:
2117      if (parlevel <= 0 && sqblevel <= 0) return(TRUE); else parlevel--;
2118      break;
2119    case RSB:
2120     sqblevel--;
2121     break;
2122    case COMMA:
2123     /* illegal here but parse and check later */
2124     if (parlevel <= 0 && sqblevel <= 0) return(TRUE);
2125     break;
2126    case PLUS: case MINUS:
2127     if (parlevel <= 0 && sqblevel <= 0) return(TRUE);
2128     break;
2129    case COLON:
2130     if (parlevel <= 0 && sqblevel <= 0) return(TRUE);
2131     break;
2132    /* notice these are never nested */
2133    case FPTHCON: case PPTHCON: case TCHKEVAND:
2134     return(TRUE);
2135    case TEOF:
2136    case SEMI:
2137     goto bad_end;
2138    }
2139    if (!__bld_expnode()) goto bad_end;
2140    __get_vtok();
2141   }
2142 
2143 bad_end:
2144  __set_xtab_errval();
2145  return(FALSE);
2146 }
2147 
2148 /*
2149  * read delay path list
2150  * almost same as read oparams del but surrounding () always optional
2151  *
2152  * reads and checks for ending ;
2153  * builds a parameter/delay list and returns pointer to header
2154  * returns F on sync error - caller must resync
2155  * but in places with known delimiter attempt to resync to delim
2156  */
rd_pathdelaylist(struct paramlst_t ** pmphdr)2157 static int32 rd_pathdelaylist(struct paramlst_t **pmphdr)
2158 {
2159  int32 rv;
2160  struct paramlst_t *pmp, *last_pmp;
2161 
2162  *pmphdr = NULL;
2163 
2164  /* this is #[number] or #id - not (..) form - min:typ:max requires () */
2165  /* for path delay will never see this form */
2166  __get_vtok();
2167  /* case 1: has optional () surround list */
2168  if (__toktyp == LPAR)
2169   {
2170    for (last_pmp = NULL;;)
2171     {
2172      __get_vtok();
2173      if (!__col_delexpr())
2174       {
2175        /* need to look to skip to any possible end ( may be unmatched */
2176        if (!__vskipto3_modend(COMMA, RPAR, SEMI)) return(FALSE);
2177        if (__toktyp == SEMI) return(FALSE);
2178        if (__toktyp == RPAR) { __get_vtok(); rv = FALSE; goto chk_semi; }
2179        /* if comman do not add but continue checking */
2180        continue;
2181       }
2182      __bld_xtree(0);
2183      pmp = __alloc_pval();
2184      pmp->plxndp = __root_ndp;
2185 
2186      /* link on front */
2187      if (last_pmp == NULL) *pmphdr = pmp; else last_pmp->pmlnxt = pmp;
2188      last_pmp = pmp;
2189 
2190      if (__toktyp == COMMA) continue;
2191      if (__toktyp == RPAR) break;
2192      /* should never happen - sync on err above, if does give up */
2193      __pv_ferr(1050,
2194       "path delay delay list comma or right parenthesis expected - %s read",
2195       __prt_vtok());
2196      return(FALSE);
2197     }
2198    rv = TRUE;
2199    __get_vtok();
2200 chk_semi:
2201    if (__toktyp != SEMI)
2202     {
2203      __pv_ferr(1279, "path delay final ; expected - %s read", __prt_vtok());
2204      return(FALSE);
2205     }
2206    return(rv);
2207   }
2208  /* case 2: optional surrounding omitted */
2209  for (last_pmp = NULL;;)
2210   {
2211    /* this reads the end , or ; */
2212    if (!__col_paramrhsexpr())
2213     {
2214      /* need to look to skip to any possible end ( may be unmatched */
2215      if (!__vskipto3_modend(COMMA, RPAR, SEMI)) return(FALSE);
2216      if (__toktyp == SEMI) return(FALSE);
2217      if (__toktyp == RPAR) { __get_vtok(); rv = FALSE; goto chk_semi; }
2218      __get_vtok();
2219      continue;
2220     }
2221    __bld_xtree(0);
2222    pmp = __alloc_pval();
2223    pmp->plxndp = __root_ndp;
2224    if (last_pmp == NULL) *pmphdr = pmp; else last_pmp->pmlnxt = pmp;
2225    last_pmp = pmp;
2226 
2227    if (__toktyp == COMMA) { __get_vtok(); continue; }
2228    if (__toktyp == SEMI) break;
2229    /* should never happen - sync on err above, if does give up */
2230    __pv_ferr(1050,
2231     "path delay delay list comma or semicolon expected - %s read",
2232      __prt_vtok());
2233    return(FALSE);
2234   }
2235  return(TRUE);
2236 }
2237 
2238 /*
2239  * initialize a specify section delay path
2240  */
init_spcpth(struct spcpth_t * pthp)2241 static void init_spcpth(struct spcpth_t *pthp)
2242 {
2243  pthp->pthtyp = PTH_NONE;
2244  pthp->pth_gone = FALSE;
2245  pthp->pth_as_xprs = TRUE;
2246  pthp->pth_delrep = DT_NONE;
2247  pthp->pthpolar = FALSE;
2248  pthp->pthedge = NOEDGE;
2249  pthp->dsrc_polar = POLAR_NONE;
2250  pthp->pth_ifnone = FALSE;
2251  pthp->pth_0del_rem = FALSE;
2252  pthp->pthsym = NULL;
2253  pthp->last_pein = -1;
2254  pthp->last_peout = -1;
2255  pthp->peins = NULL;
2256  pthp->peouts = NULL;
2257  pthp->pth_du.d1v = NULL;
2258  pthp->datasrcx = NULL;
2259  pthp->pthcondx = NULL;
2260  pthp->spcpthnxt = NULL;
2261 }
2262 
2263 /*
2264  * TIMING CHECK READ ROUTINES
2265  */
2266 
2267 /*
2268  * read setup or hold timing check
2269  * know system task keyword and ( read and reads ending ; if possible
2270  *
2271  * read and parse timing checks as is - during prep changed to needed form
2272  */
rd_setup_or_hold_tchk(word32 ttyp)2273 static int32 rd_setup_or_hold_tchk(word32 ttyp)
2274 {
2275  int32 fnum, lnum;
2276  struct sy_t *syp, *tcsyp;
2277  struct paramlst_t *pmp;
2278  struct tchk_t tmptchk;
2279  struct expr_t *limx;
2280 
2281  __init_tchk(&tmptchk, ttyp);
2282  /* must save location since, need system task line as tchk loc. */
2283  fnum = __cur_fnam_ind;
2284  lnum = __lin_cnt;
2285  if (!rd_tchk_part(ttyp, &tmptchk, &limx)) return(FALSE);
2286  /* notice can only be ID if present */
2287  if (__toktyp == COMMA) { syp = rd_notifier(); __get_vtok(); }
2288  else syp = NULL;
2289  /* even even error end, still add since good */
2290  if (__toktyp != RPAR) goto noparsemi;
2291  __get_vtok();
2292  if (__toktyp != SEMI)
2293   {
2294 noparsemi:
2295    __pv_ferr(1261, "%s timing check does not end with ); - %s read",
2296     __to_tcnam(__xs, ttyp), __prt_vtok());
2297    if (!__spec_vskipto_any(SEMI)) return(FALSE);
2298   }
2299  __cur_tchk = (struct tchk_t *) __my_malloc(sizeof(struct tchk_t));
2300  *__cur_tchk = tmptchk;
2301  /* add the location idnentifying symbol */
2302  tcsyp = __bld_loc_symbol(__tchk_num, __venviron[0], "tchk", "timing check");
2303  tcsyp->sytyp = SYM_TCHK;
2304  tcsyp->syfnam_ind = fnum;
2305  tcsyp->sylin_cnt = lnum;
2306  tcsyp->el.etcp = __cur_tchk;
2307  tcsyp->sydecl = TRUE;
2308  __cur_tchk->tcsym = tcsyp;
2309  tcsyp->el.etcp = __cur_tchk;
2310  __tchk_num++;
2311 
2312  __cur_tchk->ntfy_np = (struct net_t *) syp;
2313  /* setup and hold identical - users changes order of args - ref. event */
2314  /* always first so $setup(data, clk, ...), $hold(clk, data, ...) */
2315  pmp = __alloc_pval(); pmp->plxndp = limx; pmp->pmlnxt = NULL;
2316  __cur_tchk->tclim_du.pdels = pmp;
2317  return(TRUE);
2318 }
2319 
2320 /*
2321  * build timing check symbol
2322  *
2323  * even if already declared, change to delay object
2324  * if used previously, change to delay object - error if previously declared
2325  * if used in previous expr. but later declared, error emitted at declaration
2326  * common case first used in $set[it]delay expr. and added to symbol table
2327  * as wire then here changed to delay object
2328  */
__bld_loc_symbol(int32 num,struct symtab_t * sytp,char * pref,char * emsgnam)2329 extern struct sy_t *__bld_loc_symbol(int32 num, struct symtab_t *sytp,
2330  char *pref, char *emsgnam)
2331 {
2332  char s1[RECLEN];
2333  struct sy_t *syp;
2334 
2335  sprintf(s1, "__%s$$%d", pref, num);
2336  syp = __decl_sym(s1, sytp);
2337  if (!__sym_is_new)
2338   {
2339    if (syp->sydecl)
2340     {
2341      __pv_ferr(1160,
2342       "%s constructed internal name %s conflicts with declared %s",
2343       emsgnam, s1, __to_sytyp(__xs, syp->sytyp));
2344     }
2345    else
2346     {
2347      __pv_ferr(1160, "%s constructed internal name %s conflicts with wire",
2348       emsgnam, s1);
2349     }
2350   }
2351  return(syp);
2352 }
2353 
2354 /*
2355  * read the event and first limit part of all timing checks
2356  * common code for all timing checks, limits differ
2357  * this must read 1st token before reading tchk events
2358  * if returns F, parameters not set
2359  * this syncs to ; or item location and returns F
2360  * on T reads ) or , after first (maybe only) limit
2361  * notice 1 limit always required
2362  */
rd_tchk_part(word32 ttyp,struct tchk_t * tcp,struct expr_t ** limx)2363 static int32 rd_tchk_part(word32 ttyp, struct tchk_t *tcp,
2364  struct expr_t **limx)
2365 {
2366  struct expr_t *xp, *condx;
2367  int32 edgval;
2368 
2369  /* notice ref. always first */
2370  __get_vtok();
2371  if (!rd_tchk_selector(&edgval, &xp, &condx))
2372   {
2373    if (!__spec_vskipto2_any(SEMI, COMMA)) return(FALSE);
2374    if (__toktyp == SEMI)
2375     {
2376 got_semi:
2377      __syncto_class = SYNC_SPECITEM;
2378      return(FALSE);
2379     }
2380   }
2381  tcp->startedge = edgval;
2382  tcp->startxp = xp;
2383  tcp->startcondx = condx;
2384 
2385  /* tcp initialized to empty fields */
2386  if (ttyp != TCHK_WIDTH && ttyp != TCHK_PERIOD)
2387   {
2388    __get_vtok();
2389    if (!rd_tchk_selector(&edgval, &xp, &condx))
2390     {
2391      if (!__spec_vskipto2_any(SEMI, COMMA)) return(FALSE);
2392      if (__toktyp == SEMI) goto got_semi;
2393     }
2394    tcp->chkedge = edgval;
2395    tcp->chkxp = xp;
2396    tcp->chkcondx = condx;
2397   }
2398  __get_vtok();
2399  __sav_spsytp = __venviron[0];
2400  __venviron[0] = __cur_spfy->spfsyms;
2401  /* limit is one number but can be d:d:d form - but know ends with , or ) */
2402  if (!__col_delexpr())
2403   {
2404    if (!__spec_vskipto2_any(SEMI, COMMA))
2405     { __venviron[0] = __sav_spsytp; return(FALSE); }
2406    if (__toktyp == SEMI)
2407     { __venviron[0] = __sav_spsytp; goto got_semi; }
2408    /* set error, if ,, form will not get here */
2409    /* make it look like ,, form */
2410    __set_0tab_errval();
2411   }
2412  __bld_xtree(0);
2413  if (__has_top_mtm)
2414   {
2415    __pv_fwarn(653,
2416     "%s timing check min:typ:max limit expression needs parentheses under 1364 - unportable",
2417     __to_tcnam(__xs, ttyp));
2418   }
2419  *limx = __root_ndp;
2420  __venviron[0] = __sav_spsytp;
2421  return(TRUE);
2422 }
2423 
2424 /*
2425  * initialize a timing check record
2426  */
__init_tchk(struct tchk_t * tcp,word32 ttyp)2427 extern void __init_tchk(struct tchk_t *tcp, word32 ttyp)
2428 {
2429  tcp->tchktyp = ttyp;
2430  /* notice del rep applies to both limits if present */
2431  tcp->tc_delrep = DT_CMPLST;
2432  tcp->tc_delrep2 = DT_CMPLST;
2433  tcp->tc_gone = FALSE;
2434  tcp->tc_supofsuphld = FALSE;
2435  tcp->tc_recofrecrem = FALSE;
2436  tcp->tc_haslim2 = FALSE;
2437  tcp->startedge = NOEDGE;
2438  tcp->startxp = NULL;
2439  tcp->tcsym = NULL;
2440  tcp->startcondx = NULL;
2441  tcp->chkedge = NOEDGE;
2442  tcp->chkxp = NULL;
2443  tcp->chkcondx = NULL;
2444  /* notice this may be nil */
2445  tcp->ntfy_np = NULL;
2446  tcp->tclim_du.pdels = NULL;
2447  tcp->tclim2_du.pdels = NULL;
2448  tcp->tchknxt = NULL;
2449 }
2450 
2451 /*
2452  * read setuphold timing check (both with 2 limits)
2453  * know system task keyword read
2454  */
rd_setuphold_tchk(void)2455 static int32 rd_setuphold_tchk(void)
2456 {
2457  word32 ttyp;
2458  int32 fnum, lnum;
2459  struct tchk_t tmptchk;
2460  struct expr_t *limx, *lim2x;
2461  struct sy_t *syp, *tcsyp;
2462  struct paramlst_t *pmp;
2463 
2464  ttyp = TCHK_SETUPHOLD;
2465  __init_tchk(&tmptchk, ttyp);
2466  fnum = __cur_fnam_ind;
2467  lnum = __lin_cnt;
2468 
2469  if (!rd_tchk_part(ttyp, &tmptchk, &limx)) return(FALSE);
2470  if (__toktyp != COMMA)
2471   {
2472    __pv_ferr(1267,
2473     "$setuphold hold limit expression , terminator expected - %s read",
2474     __prt_vtok());
2475    __spec_vskipto_any(SEMI);
2476    return(FALSE);
2477   }
2478  __get_vtok();
2479  __sav_spsytp = __venviron[0];
2480  __venviron[0] = __cur_spfy->spfsyms;
2481  /* can be ,, or ,) empty but required */
2482  if (!__col_delexpr())
2483   {
2484    if (!__spec_vskipto2_any(SEMI, COMMA))
2485     { __venviron[0] = __sav_spsytp; return(FALSE); }
2486    if (__toktyp == SEMI)
2487     {
2488      __venviron[0] = __sav_spsytp;
2489      __syncto_class = SYNC_SPECITEM;
2490      return(FALSE);
2491     }
2492    /* set rhs error expr. */
2493    __set_0tab_errval();
2494   }
2495  __bld_xtree(0);
2496  if (__has_top_mtm)
2497   {
2498    __pv_fwarn(653,
2499     "%s timing check min:typ:max 2nd limit expression needs parentheses under 1364 - unportable",
2500     __to_tcnam(__xs, ttyp));
2501   }
2502  lim2x = __root_ndp;
2503  __venviron[0] = __sav_spsytp;
2504 
2505  /* notice can only be ID if present */
2506  if (__toktyp == COMMA) { syp = rd_notifier(); __get_vtok(); }
2507  else syp = NULL;
2508  /* even even error end, still add since good */
2509  if (__toktyp != RPAR) goto noparsemi;
2510  __get_vtok();
2511  if (__toktyp != SEMI)
2512   {
2513 noparsemi:
2514    __pv_ferr(1262, "$setuphold timing check does not end with ); - %s read",
2515     __prt_vtok());
2516    if (!__spec_vskipto_any(SEMI)) return(FALSE);
2517   }
2518  __cur_tchk = (struct tchk_t *) __my_malloc(sizeof(struct tchk_t));
2519  *__cur_tchk = tmptchk;
2520 
2521  /* add the location idnentifying symbol */
2522  tcsyp = __bld_loc_symbol(__tchk_num, __venviron[0], "tchk", "timing check");
2523  tcsyp->sytyp = SYM_TCHK;
2524  tcsyp->syfnam_ind = fnum;
2525  tcsyp->sylin_cnt = lnum;
2526  __cur_tchk->tcsym = tcsyp;
2527  tcsyp->el.etcp = __cur_tchk;
2528  __tchk_num++;
2529  __cur_tchk->ntfy_np = (struct net_t *) syp;
2530  pmp = __alloc_pval();
2531  pmp->plxndp = limx;
2532  pmp->pmlnxt = NULL;
2533  __cur_tchk->tclim_du.pdels = pmp;
2534  pmp = __alloc_pval();
2535  pmp->plxndp = lim2x;
2536  pmp->pmlnxt = NULL;
2537  __cur_tchk->tclim2_du.pdels = pmp;
2538  __cur_tchk->tc_haslim2 = TRUE;
2539  return(TRUE);
2540 }
2541 
2542 /*
2543  * read recrem timing check (both with 2 limits)
2544  * know system task keyword read
2545  *
2546  * SJM 01/16/04 - almost same as setup hold but 2001 LRM has extra stuff
2547  * that is not yet added
2548  */
rd_recrem_tchk(void)2549 static int32 rd_recrem_tchk(void)
2550 {
2551  word32 ttyp;
2552  int32 fnum, lnum;
2553  struct tchk_t tmptchk;
2554  struct expr_t *limx, *lim2x;
2555  struct sy_t *syp, *tcsyp;
2556  struct paramlst_t *pmp;
2557  char s1[RECLEN];
2558 
2559  ttyp = TCHK_RECREM;
2560  __init_tchk(&tmptchk, ttyp);
2561  fnum = __cur_fnam_ind;
2562  lnum = __lin_cnt;
2563 
2564  if (!rd_tchk_part(ttyp, &tmptchk, &limx)) return(FALSE);
2565 
2566  /* for recrem both terminals must be edges */
2567  if (tmptchk.startedge == NOEDGE)
2568   {
2569    __pv_ferr(1260,
2570    "%s timing check first recovery reference event missing required edge",
2571    __to_tcnam(s1, ttyp));
2572   }
2573  if (tmptchk.chkedge == NOEDGE)
2574   {
2575    __pv_ferr(1260,
2576     "%s timing 2nd removal reference event missing required edge",
2577    __to_tcnam(s1, ttyp));
2578   }
2579 
2580  if (__toktyp != COMMA)
2581   {
2582    __pv_ferr(1267,
2583     "$recrem removal limit expression , terminator expected - %s read",
2584     __prt_vtok());
2585    __spec_vskipto_any(SEMI);
2586    return(FALSE);
2587   }
2588  __get_vtok();
2589  __sav_spsytp = __venviron[0];
2590  __venviron[0] = __cur_spfy->spfsyms;
2591  /* can be ,, or ,) empty but required */
2592  if (!__col_delexpr())
2593   {
2594    if (!__spec_vskipto2_any(SEMI, COMMA))
2595     { __venviron[0] = __sav_spsytp; return(FALSE); }
2596    if (__toktyp == SEMI)
2597     {
2598      __venviron[0] = __sav_spsytp;
2599      __syncto_class = SYNC_SPECITEM;
2600      return(FALSE);
2601     }
2602    /* set rhs error expr. */
2603    __set_0tab_errval();
2604   }
2605  __bld_xtree(0);
2606  if (__has_top_mtm)
2607   {
2608    __pv_fwarn(653,
2609     "%s timing check min:typ:max 2nd limit expression needs parentheses under 1364 - unportable",
2610     __to_tcnam(__xs, ttyp));
2611   }
2612  lim2x = __root_ndp;
2613  __venviron[0] = __sav_spsytp;
2614 
2615  /* notice can only be ID if present */
2616  if (__toktyp == COMMA) { syp = rd_notifier(); __get_vtok(); }
2617  else syp = NULL;
2618  /* even even error end, still add since good */
2619  if (__toktyp != RPAR) goto noparsemi;
2620  __get_vtok();
2621  if (__toktyp != SEMI)
2622   {
2623 noparsemi:
2624    __pv_ferr(1262, "$setuphold timing check does not end with ); - %s read",
2625     __prt_vtok());
2626    if (!__spec_vskipto_any(SEMI)) return(FALSE);
2627   }
2628  __cur_tchk = (struct tchk_t *) __my_malloc(sizeof(struct tchk_t));
2629  *__cur_tchk = tmptchk;
2630 
2631  /* add the location idnentifying symbol */
2632  tcsyp = __bld_loc_symbol(__tchk_num, __venviron[0], "tchk", "timing check");
2633  tcsyp->sytyp = SYM_TCHK;
2634  tcsyp->syfnam_ind = fnum;
2635  tcsyp->sylin_cnt = lnum;
2636  __cur_tchk->tcsym = tcsyp;
2637  tcsyp->el.etcp = __cur_tchk;
2638  __tchk_num++;
2639  __cur_tchk->ntfy_np = (struct net_t *) syp;
2640  pmp = __alloc_pval();
2641  pmp->plxndp = limx;
2642  pmp->pmlnxt = NULL;
2643  __cur_tchk->tclim_du.pdels = pmp;
2644  pmp = __alloc_pval();
2645  pmp->plxndp = lim2x;
2646  pmp->pmlnxt = NULL;
2647  __cur_tchk->tclim2_du.pdels = pmp;
2648  __cur_tchk->tc_haslim2 = TRUE;
2649  return(TRUE);
2650 }
2651 
2652 /*
2653  * read width timing check
2654  * know system task keyword read
2655  * width has 2 limits (but 2nd can be omitted), period has 1
2656  */
rd_width_tchk(void)2657 static int32 rd_width_tchk(void)
2658 {
2659  word32 ttyp;
2660  int32 fnum, lnum;
2661  struct tchk_t tmptchk;
2662  struct expr_t *limx, *lim2x;
2663  struct sy_t *syp, *tcsyp;
2664  struct paramlst_t *pmp;
2665 
2666  ttyp = TCHK_WIDTH;
2667  __init_tchk(&tmptchk, ttyp);
2668 
2669  fnum = __cur_fnam_ind;
2670  lnum = __lin_cnt;
2671 
2672  if (!rd_tchk_part(ttyp, &tmptchk, &limx)) return(FALSE);
2673  if (tmptchk.startedge != E_NEGEDGE && tmptchk.startedge != E_POSEDGE)
2674   __pv_ferr(1266,
2675    "$width timing check event missing required negedge or posedge");
2676  /* 2nd limit optional and becomes NULL */
2677  if (__toktyp == RPAR) { syp = NULL; lim2x = NULL; goto done; }
2678  if (__toktyp != COMMA)
2679   {
2680    __pv_ferr(1268,
2681     "$width first limit expression , terminator expected - %s read",
2682     __prt_vtok());
2683    __spec_vskipto_any(SEMI);
2684    return(FALSE);
2685   }
2686  __get_vtok();
2687  __sav_spsytp = __venviron[0];
2688  __venviron[0] = __cur_spfy->spfsyms;
2689  /* lrm says no ,, or ,) forms for width */
2690  /* since ignored by sim value of 0 ok place holder and just ignored */
2691  if (!__col_delexpr())
2692   {
2693    if (!__spec_vskipto2_any(SEMI, COMMA))
2694     { __venviron[0] = __sav_spsytp; return(FALSE); }
2695    if (__toktyp == SEMI)
2696     {
2697      __venviron[0] = __sav_spsytp;
2698      __syncto_class = SYNC_SPECITEM;
2699      return(FALSE);
2700     }
2701    /* make it look like ,, form */
2702    __set_0tab_errval();
2703   }
2704  __bld_xtree(0);
2705  lim2x = __root_ndp;
2706  __venviron[0] = __sav_spsytp;
2707 
2708  /* notice can only be ID and may be omited */
2709  if (__toktyp == COMMA) { syp = rd_notifier(); __get_vtok(); }
2710  else syp = NULL;
2711  /* even even error end, still add since good */
2712  if (__toktyp != RPAR) goto noparsemi;
2713 done:
2714  __get_vtok();
2715  if (__toktyp != SEMI)
2716   {
2717 noparsemi:
2718    __pv_ferr(1263, "$width timing check does not end with ); - %s read",
2719     __prt_vtok());
2720    if (!__spec_vskipto_any(SEMI)) return(FALSE);
2721   }
2722 
2723  /* notice no data even here */
2724  __cur_tchk = (struct tchk_t *) __my_malloc(sizeof(struct tchk_t));
2725  *__cur_tchk = tmptchk;
2726 
2727  /* add the location idnentifying symbol */
2728  tcsyp = __bld_loc_symbol(__tchk_num, __venviron[0], "tchk", "timing check");
2729  tcsyp->sytyp = SYM_TCHK;
2730  tcsyp->syfnam_ind = fnum;
2731  tcsyp->sylin_cnt = lnum;
2732  tcsyp->sydecl = TRUE;
2733  __cur_tchk->tcsym = tcsyp;
2734  tcsyp->el.etcp = __cur_tchk;
2735  __tchk_num++;
2736 
2737  __cur_tchk->ntfy_np = (struct net_t *) syp;
2738  pmp = __alloc_pval();
2739  pmp->plxndp = limx;
2740  pmp->pmlnxt = NULL;
2741  __cur_tchk->tclim_du.pdels = pmp;
2742  /* always build 2nd limit as 0 if missing (during fix) so present */
2743  __cur_tchk->tc_haslim2 = TRUE;
2744  /* notice missing 2nd limit ok since only timing verifier threshold */
2745  /* that stops errors if pulse less than threshold */
2746  if (lim2x == NULL) lim2x = __bld_rng_numxpr(0L, 0L, WBITS);
2747  pmp = __alloc_pval();
2748  pmp->plxndp = lim2x;
2749  pmp->pmlnxt = NULL;
2750  __cur_tchk->tclim2_du.pdels = pmp;
2751  return(TRUE);
2752 }
2753 
2754 /*
2755  * read period timing check
2756  * know system task keyword read
2757  * period has 1 limit (required), width has 2
2758  */
rd_period_tchk(void)2759 static int32 rd_period_tchk(void)
2760 {
2761  word32 ttyp;
2762  int32 fnum, lnum;
2763  struct tchk_t tmptchk;
2764  struct expr_t *limx;
2765  struct sy_t *syp, *tcsyp;
2766  struct paramlst_t *pmp;
2767 
2768  ttyp = TCHK_PERIOD;
2769  __init_tchk(&tmptchk, ttyp);
2770 
2771  fnum = __cur_fnam_ind;
2772  lnum = __lin_cnt;
2773 
2774  if (!rd_tchk_part(ttyp, &tmptchk, &limx)) return(FALSE);
2775  if (tmptchk.startedge == NOEDGE)
2776   __pv_ferr(1269, "$period timing check event missing required edge");
2777  /* notice can only be ID if present */
2778  if (__toktyp == COMMA) { syp = rd_notifier(); __get_vtok(); }
2779  else syp = NULL;
2780  /* even even error end, still add since good */
2781  if (__toktyp != RPAR) goto noparsemi;
2782  __get_vtok();
2783  if (__toktyp != SEMI)
2784   {
2785 noparsemi:
2786    __pv_ferr(1264, "$period timing check does not end with ); - %s read",
2787     __prt_vtok());
2788    if (!__spec_vskipto_any(SEMI)) return(FALSE);
2789   }
2790  __cur_tchk = (struct tchk_t *) __my_malloc(sizeof(struct tchk_t));
2791  *__cur_tchk = tmptchk;
2792 
2793  /* add the location idnentifying symbol */
2794  tcsyp = __bld_loc_symbol(__tchk_num, __venviron[0], "tchk", "timing check");
2795  tcsyp->sytyp = SYM_TCHK;
2796  tcsyp->syfnam_ind = fnum;
2797  tcsyp->sylin_cnt = lnum;
2798  tcsyp->sydecl = TRUE;
2799  __cur_tchk->tcsym = tcsyp;
2800  tcsyp->el.etcp = __cur_tchk;
2801  __tchk_num++;
2802 
2803  __cur_tchk->ntfy_np = (struct net_t *) syp;
2804  pmp = __alloc_pval();
2805  pmp->plxndp = limx;
2806  pmp->pmlnxt = NULL;
2807  __cur_tchk->tclim_du.pdels = pmp;
2808  return(TRUE);
2809 }
2810 
2811 /*
2812  * read skew or recovery timing check
2813  * know system task keyword read
2814  * different timing checks have identical arguments
2815  *
2816  * SJM 01/16/04 - added removal first terminal is the ref events that
2817  * needs to be an edge for both
2818  */
rd_skew_recov_rem_tchk(word32 ttyp)2819 static int32 rd_skew_recov_rem_tchk(word32 ttyp)
2820 {
2821  int32 fnum, lnum;
2822  struct tchk_t tmptchk;
2823  struct expr_t *limx;
2824  struct sy_t *syp, *tcsyp;
2825  struct paramlst_t *pmp;
2826  char s1[RECLEN];
2827 
2828  __init_tchk(&tmptchk, ttyp);
2829  /* must save location since, need system task line as tchk loc. */
2830  fnum = __cur_fnam_ind;
2831  lnum = __lin_cnt;
2832  if (!rd_tchk_part(ttyp, &tmptchk, &limx)) return(FALSE);
2833  if (ttyp == TCHK_RECOVERY || ttyp == TCHK_REMOVAL)
2834   {
2835    if (tmptchk.startedge == NOEDGE)
2836     __pv_ferr(1260,
2837      "%s timing check first reference event missing required edge",
2838      __to_tcnam(s1, ttyp));
2839   }
2840 
2841  /* notice can only be ID if present */
2842  if (__toktyp == COMMA) { syp = rd_notifier(); __get_vtok(); }
2843  else syp = NULL;
2844  /* even even error end, still add since good */
2845  if (__toktyp != RPAR) goto noparsemi;
2846  __get_vtok();
2847  if (__toktyp != SEMI)
2848   {
2849 noparsemi:
2850    __pv_ferr(1265, "%s timing check does not end with ); - %s read",
2851     __to_tcnam(s1, ttyp), __prt_vtok());
2852    if (!__spec_vskipto_any(SEMI)) return(FALSE);
2853   }
2854  __cur_tchk = (struct tchk_t *) __my_malloc(sizeof(struct tchk_t));
2855  *__cur_tchk = tmptchk;
2856 
2857  /* add the location identifying symbol */
2858  tcsyp = __bld_loc_symbol(__tchk_num, __venviron[0], "tchk", "timing check");
2859  tcsyp->sytyp = SYM_TCHK;
2860  tcsyp->syfnam_ind = fnum;
2861  tcsyp->sylin_cnt = lnum;
2862  tcsyp->sydecl = TRUE;
2863  __cur_tchk->tcsym = tcsyp;
2864  tcsyp->el.etcp = __cur_tchk;
2865  __tchk_num++;
2866 
2867  __cur_tchk->ntfy_np = (struct net_t *) syp;
2868  pmp = __alloc_pval(); pmp->plxndp = limx; pmp->pmlnxt = NULL;
2869  __cur_tchk->tclim_du.pdels = pmp;
2870  return(TRUE);
2871 }
2872 
2873 /*
2874  * must correctly parse $nochange but ignore with warning
2875  * this does not build and data structure
2876  */
rd_nochg_tchk(void)2877 static int32 rd_nochg_tchk(void)
2878 {
2879  word32 ttyp;
2880  struct tchk_t tmptchk;
2881  struct expr_t *limx;
2882  char s1[RECLEN];
2883 
2884  ttyp = TCHK_NOCHANGE;
2885  __init_tchk(&tmptchk, ttyp);
2886  /* this reads the first limit but not second */
2887  if (!rd_tchk_part(ttyp, &tmptchk, &limx)) return(FALSE);
2888  if (tmptchk.startedge != E_NEGEDGE && tmptchk.startedge != E_POSEDGE)
2889   __pv_ferr(1271,
2890    "$nochange timing check first reference event missing negedge or posedge");
2891  __free_xtree(limx);
2892  __free_xtree(tmptchk.startxp);
2893  __free_xtree(tmptchk.startcondx);
2894  __free_xtree(tmptchk.chkxp);
2895  __free_xtree(tmptchk.chkcondx);
2896 
2897  if (__toktyp != COMMA)
2898   {
2899    __pv_ferr(1272,
2900     "$nochange second event - comma expected - %s read", __prt_vtok());
2901    __spec_vskipto_any(SEMI);
2902    return(FALSE);
2903   }
2904  __get_vtok();
2905  __sav_spsytp = __venviron[0];
2906  __venviron[0] = __cur_spfy->spfsyms;
2907  /* lrm says no ,, or ,) forms for nochange */
2908  if (!__col_delexpr())
2909   {
2910    if (!__spec_vskipto2_any(SEMI, COMMA))
2911     { __venviron[0] = __sav_spsytp; return(FALSE); }
2912    if (__toktyp == SEMI)
2913     {
2914      __venviron[0] = __sav_spsytp;
2915      __syncto_class = SYNC_SPECITEM;
2916      return(FALSE);
2917     }
2918    /* make it look like ,, form */
2919    __set_0tab_errval();
2920   }
2921  /* this is needed for checking */
2922  __bld_xtree(0);
2923  __free_xtree(__root_ndp);
2924  __venviron[0] = __sav_spsytp;
2925  /* even even error end, still add since good */
2926  if (__toktyp != RPAR) goto noparsemi;
2927 
2928  __get_vtok();
2929  if (__toktyp != SEMI)
2930   {
2931 noparsemi:
2932    __pv_ferr(1273, "%s timing check does not end with ); - %s read",
2933     __to_tcnam(s1, ttyp), __prt_vtok());
2934    if (!__spec_vskipto_any(SEMI)) return(FALSE);
2935   }
2936  __pv_fwarn(599, "$nochange timing check has no effect in simulation");
2937  return(TRUE);
2938 }
2939 
2940 /*
2941  * read a timing check event - know always followed by ,
2942  * know 1st token read and reads ending ,
2943  * returns NULL on error, caller must skip to ;
2944  * caller syncs - returns NULL if syntax error (will need syncing)
2945  */
rd_tchk_selector(int32 * edgval,struct expr_t ** xp,struct expr_t ** condx)2946 static int32 rd_tchk_selector(int32 *edgval, struct expr_t **xp,
2947  struct expr_t **condx)
2948 {
2949  *edgval = NOEDGE;
2950  switch ((byte) __toktyp) {
2951   case NEGEDGE: *edgval = E_NEGEDGE; break;
2952   case POSEDGE: *edgval = E_POSEDGE; break;
2953   case EDGE:
2954    __get_vtok();
2955    if (__toktyp != LSB)
2956     {
2957      __pv_ferr(1281, "timing check event edge list [ expected - %s read",
2958       __prt_vtok());
2959 edge_sync:
2960      /* caller must synchronize - except try for enclosing ] */
2961      if (!__spec_vskipto_any(RSB)) return(FALSE);
2962      goto get_pthx;
2963     }
2964    if (!rd_edges(edgval)) goto edge_sync;
2965    break;
2966   default: goto no_edge;
2967  }
2968 
2969 get_pthx:
2970  __get_vtok();
2971 no_edge:
2972  if (!col_pthexpr()) return(FALSE);
2973  __bld_xtree(0);
2974  *xp = __root_ndp;
2975  if (__toktyp != COMMA)
2976   {
2977    if (__toktyp != TCHKEVAND)
2978     {
2979      __pv_ferr(1282,
2980       "timing check data or reference event, comma or &&& expected - %s read",
2981       __prt_vtok());
2982      return(FALSE);
2983     }
2984    /* read &&& expr. */
2985    __get_vtok();
2986    if (!__col_connexpr(-1)) return(FALSE);
2987    if (__toktyp != COMMA)
2988     {
2989      __pv_ferr(1283,
2990       "timing check event &&& expression comma expected - %s read",
2991       __prt_vtok());
2992      return(FALSE);
2993     }
2994    __bld_xtree(0);
2995    *condx = __root_ndp;
2996   }
2997  else *condx = NULL;
2998  return(TRUE);
2999 }
3000 
3001 /*
3002  * read an edge list
3003  * know [ read and reads trailing ]
3004  * if error tries to sync to , ], ), ;
3005  */
rd_edges(int32 * edge)3006 static int32 rd_edges(int32 *edge)
3007 {
3008  char s1[RECLEN];
3009  byte etmp, e1;
3010 
3011  *edge = etmp = NOEDGE;
3012  __letendnum_state = TRUE;
3013  for (;;)
3014   {
3015    strcpy(s1, "");
3016    for (;;)
3017     {
3018      __get_vtok();
3019      switch ((byte) __toktyp) {
3020       case COMMA: case RSB: goto got_pair;
3021       case ID: strcat(s1, __token); break;
3022       case NUMBER: strcat(s1, __numtoken); break;
3023       default:
3024        __pv_ferr(1284, "edge list edge value pair expected - %s read",
3025         __prt_vtok());
3026        __letendnum_state = FALSE;
3027        return(FALSE);
3028       }
3029     }
3030 got_pair:
3031    if (strlen(s1) > 2)
3032     {
3033 bad_edge:
3034      __pv_ferr(1286, "edge list element %s illegal", s1);
3035      continue;
3036     }
3037    switch (s1[0]) {
3038     case '0':
3039      if (s1[1] == '1') e1 = EDGE01;
3040      else if (s1[1] == 'x') e1 = EDGE0X;
3041      else goto bad_edge;
3042      break;
3043     case '1':
3044      if (s1[1] == '0') e1 = EDGE10;
3045      else if (s1[1] == 'x') e1 = EDGE1X;
3046      else goto bad_edge;
3047      break;
3048     case 'x':
3049      if (s1[1] == '0') e1 = EDGEX0;
3050      else if (s1[1] == '1') e1 = EDGEX1;
3051      else goto bad_edge;
3052      break;
3053     default: goto bad_edge;
3054    }
3055    if ((etmp & e1) != 0)
3056     __pv_fwarn(577, "edge %s repeated in edge list", s1);
3057    else etmp |= e1;
3058    /* notice last edge will be vv with __toktyp of ] - must proces last */
3059    if (__toktyp == RSB) break;
3060   }
3061  __letendnum_state = FALSE;
3062  *edge = etmp;
3063  return(TRUE);
3064 }
3065 
3066 /*
3067  * read an notifier
3068  * know leading , read and reads just the notifier reg
3069  */
rd_notifier(void)3070 static struct sy_t *rd_notifier(void)
3071 {
3072  struct sy_t *syp;
3073 
3074  __get_vtok();
3075  if (__toktyp != ID)
3076   {
3077 bad_notfy:
3078    __pv_ferr(1285, "notifier register name expected - %s read",
3079     __prt_kywrd_vtok());
3080    return(NULL);
3081   }
3082  /* this declares thing as a net - fixed later and checked even later */
3083  __last_xtk = -1;
3084  /* FIXME - since can never fail should change to arg terr */
3085  if (!__bld_expnode()) goto bad_notfy;
3086  __bld_xtree(0);
3087  syp = __root_ndp->lu.sy;
3088  /* type will be checked later */
3089  return(syp);
3090 }
3091 
3092 /*
3093  * ROUTINES TO PROCESS `language INCLUDE CONSTRUCT
3094  */
3095 
3096 extern char __pv_ctab[];
3097 
3098 /*
3099  * read lines after language up to `endlanguage
3100  *
3101  * know first token of line read and it is `language
3102  * reads through `endlanguage
3103  *
3104  * both `language and `endlanguage lines passed to call back if registered
3105  */
__do_foreign_lang(void)3106 extern void __do_foreign_lang(void)
3107 {
3108  register char *chp, *chp2;
3109  int32 first_time, done, savfnam_ind, sav_lin_cnt;
3110 
3111  if (!__rding_top_level || __rescanning_lib)
3112   {
3113    if (!__rescanning_lib)
3114     {
3115      __pv_ferr(2657,
3116       "`language compiler directive inside Verilog construct - skipping to `endlanguage");
3117     }
3118    savfnam_ind = __cur_fnam_ind;
3119    sav_lin_cnt = __lin_cnt;
3120    if (__notokenize_skiplines("`endlanguage") == TEOF)
3121     {
3122      __pv_terr(327,
3123       "skipped `language line %s no matching `endlanguage before **EOF**",
3124       __bld_lineloc(__xs, (word32) savfnam_ind, sav_lin_cnt));
3125     }
3126    if (__langstr != NULL) strcpy(__langstr, "");
3127    return;
3128   }
3129  if (__lib_verbose || __verbose)
3130   {
3131    __cv_msg("  Processing `language directive at **%s(%d)\n",
3132     __in_fils[__cur_fnam_ind], __lin_cnt);
3133   }
3134  __total_lang_dirs++;
3135  if (__iact_state)
3136   {
3137    __ia_err(1401,
3138     "`language compiler directive illegal in interactive commands");
3139    __skipover_line();
3140    if (__langstr != NULL) strcpy(__langstr, "");
3141    return;
3142   }
3143  if (__langstr == NULL) __langstr = __my_malloc(IDLEN + 1);
3144 
3145  __doing_langdir = TRUE;
3146  for (first_time = TRUE, done = FALSE;;)
3147   {
3148 rd_again:
3149    chp = __langstr;
3150    /* this does not move line count to next line - code here must */
3151    if (__my_getlin(__langstr) == EOF)
3152     {
3153      /* first try to pop some sort of outer nested thing */
3154      if (__pop_vifstk()) goto rd_again;
3155      /* next try to replace just finished 0th element with new input file */
3156      if (__cur_infi + 1 > __last_inf) goto eof_error;
3157      __cur_infi++;
3158      if (!__open_sfil()) goto eof_error;
3159      /* know first token of file flag now on */
3160      __file_just_op = FALSE;
3161      __first_num_eol = TRUE;
3162      goto rd_again;
3163 
3164 eof_error:
3165      __pv_ferr(2657,
3166       "while processing foreign `language section **EOF** read before `endlanguage");
3167      if (first_time)
3168       {
3169        if (__langstr != NULL) strcpy(__langstr, "");
3170        __doing_langdir = FALSE;
3171        return;
3172       }
3173 
3174      strcpy(__langstr, "`endlanguage");
3175      __langstr[12] = '\n';
3176      __langstr[13] = '\0';
3177      done = TRUE;
3178      goto try_callback;
3179     }
3180    if (first_time)
3181     {
3182      char s1[IDLEN];
3183 
3184      if (strlen(__langstr) + 11 >= IDLEN)
3185       {
3186        __pv_ferr(2679,
3187         "`language section line too long (%d) - truncated", IDLEN - 1);
3188       }
3189      strcpy(s1, __langstr);
3190      strcpy(__langstr, "`language");
3191      if (s1[0] != ' ' && s1[0] != '\t') strcat(__langstr, " ");
3192      strcat(__langstr, s1);
3193      first_time = FALSE;
3194     }
3195    else
3196     {
3197      if ((chp = __match_cdir(__langstr, "`endlanguage")) != NULL)
3198       done = TRUE;
3199      else if ((chp = __match_cdir(__langstr, "`include")) != NULL)
3200       {
3201        chp2 = &(chp[8]);
3202        while (vis_white_(*chp2)) chp2++;
3203        strcpy(__macwrkstr, chp2);
3204        /* correct for right line because line getting moves to next line */
3205        __do_include();
3206        __lin_cnt++;
3207        __total_rd_lines++;
3208        /* no need to set beginning of lne because new file just opened */
3209        goto rd_again;
3210       }
3211      else chp = __langstr;
3212     }
3213 
3214 try_callback:
3215    /* execute call back if any registered - if none just returns */
3216    /* by passing chp, know for `langauge/`endlanguage no leading whie space */
3217    __exec_vpi_langlinecbs(chp, __in_fils[__cur_fnam_ind], __lin_cnt);
3218    __lin_cnt++;
3219    __total_rd_lines++;
3220    /* this set first token on line using 2 step flag needed for push back */
3221    __first_num_eol = TRUE;
3222    if (done)
3223     {
3224      strcpy(__langstr, "");
3225      __doing_langdir = FALSE;
3226      return;
3227     }
3228   }
3229 }
3230 
3231 /*
3232  * routine to skip over lines to keyword (usually `endlanguage)
3233  *
3234  * special routine that can not tokenize since probably non Verilog
3235  * returns last character read on success else EOF on error of EOF
3236  *
3237  * this must read and expand `include files because `endlanguage can be
3238  * in included file
3239  */
__notokenize_skiplines(char * match_prefix)3240 extern int32 __notokenize_skiplines(char *match_prefix)
3241 {
3242  if (__langstr == NULL) __langstr = __my_malloc(IDLEN + 1);
3243  for (;;)
3244   {
3245    if (__my_getlin(__langstr) == EOF)
3246     {
3247      /* first try to pop some sort of outer nested thing */
3248      /* this sets line number to right outer line and no line here */
3249      if (__pop_vifstk()) continue;
3250 
3251      /* next try to replace just finished 0th element with new input file */
3252      if (__cur_infi + 1 > __last_inf) goto eof_error;
3253      __cur_infi++;
3254      if (!__open_sfil()) goto eof_error;
3255      /* know first token of file flag now on */
3256      __file_just_op = FALSE;
3257      /* this set first token on line using 2 step flag needed for push back */
3258      __first_num_eol = TRUE;
3259      continue;
3260 
3261 eof_error:
3262      __pv_ferr(2657,
3263       "while processing foreign `language section **EOF** read before `endlanguage");
3264      return(TEOF);
3265     }
3266 
3267    if (__match_cdir(__langstr, match_prefix) != NULL)
3268     {
3269      __lin_cnt++;
3270      __total_rd_lines++;
3271      /* this set first token on line using 2 step flag needed for push back */
3272      __first_num_eol = TRUE;
3273      break;
3274     }
3275    /* becausing section ifdefed out, just ignore include */
3276    __lin_cnt++;
3277    __total_rd_lines++;
3278    /* this set first token on line using 2 step flag needed for push back */
3279    __first_num_eol = TRUE;
3280   }
3281  return(UNDEF);
3282 }
3283 
3284 /*
3285  * match a directive prefix (may be leading white space)
3286  * returns char ptr to first character of matched if matched
3287  * else returns nil if no match
3288  */
__match_cdir(char * lp,char * match_prefix)3289 extern char *__match_cdir(char *lp, char *match_prefix)
3290 {
3291  register char *chp;
3292  int32 slen;
3293 
3294  /* possible lang str not yet allocated */
3295  if (lp == NULL) return(NULL);
3296  slen = strlen(match_prefix);
3297  for (chp = __langstr;; chp++) { if (!vis_nonnl_white_(*chp)) break; }
3298  if (strncmp(chp, match_prefix, slen) == 0) return(chp);
3299  return(NULL);
3300 }
3301 
3302 /*
3303  * execute vpi_control vpiInsertSource operation
3304  *
3305  * know in `endlanguage line callback or will not get here
3306  *
3307  * BEWARE - this works because no longjmp in source reading
3308  */
__exec_rdinserted_src(char * buf)3309 extern int32 __exec_rdinserted_src(char *buf)
3310 {
3311  register int32 vi;
3312  int32 sav_ecnt, retv, sav_vin_top, sav_lincnt, sav_cur_fnamind, len;
3313  struct vinstk_t **sav_vinstk;
3314 
3315  /* save lin_cnt to restore after buffer parsed */
3316  sav_lincnt = __lin_cnt;
3317  sav_cur_fnamind = __cur_fnam_ind;
3318 
3319  sav_ecnt = __pv_err_cnt;
3320  /* save the nested open file stack */
3321  sav_vinstk = (struct vinstk_t **)
3322   __my_malloc((__vin_top + 1)*sizeof(struct vinstk_t *));
3323  /* this moves the ptrs to be pointed to by same */
3324  for (vi = 0; vi <= __vin_top; vi++)
3325   {
3326    sav_vinstk[vi] = __vinstk[vi];
3327    __vinstk[vi] = NULL;
3328   }
3329  sav_vin_top = __vin_top;
3330  __vin_top = -1;
3331 
3332  /* push string on top (only one now on) of read stack */
3333  __push_vinfil();
3334  __visp = __vinstk[__vin_top];
3335  __visp->vichp = __visp->vichp_beg = buf;
3336  len = strlen(buf);
3337  __visp->vichplen = len;
3338  __in_s = NULL;
3339 
3340  for (;;)
3341   {
3342    __get_vtok();
3343    if (__toktyp == TEOF) break;
3344    __rding_top_level = FALSE;
3345    __rd_ver_mod();
3346    __rding_top_level = TRUE;
3347    if (__toktyp == TEOF) break;
3348   }
3349  /* restore the nested open file stack */
3350  /* first free any allocated vin stk records from includes */
3351  for (vi = 0; vi < MAXFILNEST; vi++)
3352   {
3353    if (__vinstk[vi] != NULL)
3354     {
3355      __my_free((char *) __vinstk[vi], sizeof(struct vinstk_t));
3356      __vinstk[vi] = NULL;
3357     }
3358   }
3359  /* next copy back and restore */
3360  for (vi = 0; vi <= sav_vin_top; vi++) __vinstk[vi] = sav_vinstk[vi];
3361  __lin_cnt = sav_lincnt;
3362  __cur_fnam_ind = sav_cur_fnamind;
3363  __vin_top = sav_vin_top;
3364  __visp = __vinstk[__vin_top];
3365  __in_s = __visp->vi_s;
3366 
3367  /* LOOKATME - why is this needed */
3368  __toktyp = UNDEF;
3369  __lasttoktyp = UNDEF;
3370 
3371  if (__pv_err_cnt > sav_ecnt) retv = FALSE; else retv = TRUE;
3372  return(retv);
3373 }
3374 
3375 /*
3376  * VERILOG 2001 ATTRIBUTE READING ROUTINES
3377  */
3378 
3379 /*
3380  * read, parse and build attribute list from attribute string
3381  * builds list and returns header of list or nil on error
3382  *
3383  * new verilog 2000 feature
3384  * know string between (* and *) stored on entry in attr name field
3385  * trick is to push string onto file stack as if it is no arg macro
3386  *
3387  * expression value converted to constant number here because
3388  * attributes need to be used by tools that do not know pound param vals
3389  * i.e. can be fed, post generate source
3390  */
__rd_parse_attribute(struct attr_t * rd_attrp)3391 extern struct attr_t *__rd_parse_attribute(struct attr_t *rd_attrp)
3392 {
3393  register char *chp;
3394  int32 sav_ecnt, sav_tot_lines, sav_fnam_ind, attllen;
3395  struct attr_t *attrp, *attr_hd, *last_attrp;
3396  char *attlin, attnam[IDLEN];
3397 
3398  attrp = attr_hd = last_attrp = NULL;
3399  attlin = rd_attrp->attrnam;
3400  /* SJM 07/30/01 - need to read chars and parse out of global */
3401  /* needed so can free work attrnam after rec built */
3402  if ((attllen = strlen(attlin)) >= __attrparsestrlen - 1)
3403   {
3404    __attrparsestr = __my_realloc((char *) __attrparsestr, __attrparsestrlen,
3405     attllen + 1);
3406    __attrparsestrlen = attllen + 1;
3407   }
3408  strcpy(__attrparsestr, attlin);
3409 
3410  /* need to save total lines read since counted in attr when collected */
3411  /* parsing here counts lines because new lines not escaped */
3412  sav_tot_lines = __total_rd_lines;
3413  sav_fnam_ind = __cur_fnam_ind;
3414  sav_ecnt = __pv_err_cnt;
3415 
3416  /* if currently reading file, must preserve line count */
3417  if (__visp->vi_s != NULL) __visp->vilin_cnt = __lin_cnt;
3418  /* push string on top of read stack */
3419  __push_vinfil();
3420  __visp->vichp = __visp->vichp_beg = __attrparsestr;
3421 
3422  /* make sure not freeing line even if somehow hit eof - never should */
3423  __visp->vichplen = -1;
3424  __in_s = NULL;
3425  /* DBG remove --- */
3426  if (__debug_flg) __dbg_msg("parsing attribute string %s\n", attlin);
3427  /* --- */
3428 
3429  __cur_fnam_ind = rd_attrp->attr_fnind;
3430  __lin_cnt = rd_attrp->attrlin_cnt;
3431 
3432  __get_vtok();
3433  /* ; added to end of saved attribute string if not there */
3434  if (__toktyp == SEMI)
3435   {
3436    __pv_ferr(3405,
3437     "attribute_instance illegal - at least one attr_spec required");
3438 chk_eol:
3439    for (chp = __visp->vichp; *chp != '\0'; chp++)
3440     {
3441      if (!vis_white_(*chp))
3442       {
3443        __pv_ferr(3407,
3444         "attribute_instance comma separator expected - semicolon read");
3445        /* on error always skip to end of string - need EOF next read */
3446        while (*chp != '\0') chp++;
3447        goto done;
3448       }
3449     }
3450    goto done;
3451   }
3452  for (;;)
3453   {
3454    if (__toktyp != ID)
3455     {
3456      __pv_ferr(3404, "attribute name expected - %s read", __prt_vtok());
3457 err_skip_eol:
3458      /* on error always skip to end of string - need EOF next read */
3459      for (chp = __visp->vichp; *chp != '\0'; chp++) ;
3460      goto done;
3461     }
3462    strcpy(attnam, __token);
3463    __get_vtok();
3464    __root_ndp = NULL;
3465    if (__toktyp == EQ)
3466     {
3467      __get_vtok();
3468      /* LOOKATME - should try to resync on errors */
3469      __last_xtk = -1;
3470      /* on success (T), this reads either , or ; */
3471      if (!__col_comsemi(-1)) goto err_skip_eol;
3472      __bld_xtree(0);
3473      if (__expr_has_glb(__root_ndp) || !__src_rd_chk_paramexpr(__root_ndp, 0))
3474       {
3475        __pv_ferr(3404,
3476         "attr_spec for attribute %s expression error - defined parameters and constants only",
3477         attnam);
3478        /* need to still add value of x to prevent further errors */
3479        __free2_xtree(__root_ndp);
3480        __root_ndp->szu.xclen = WBITS;
3481        /* default value is on 1 (non zero) */
3482        __set_numval(__root_ndp, 1, 0, WBITS);
3483       }
3484      else
3485       {
3486        /* because of previous check, this can not fail */
3487        __eval_param_rhs_tonum(__root_ndp);
3488       }
3489     }
3490    else __root_ndp = NULL;
3491 
3492    /* allocate in link in attribute */
3493    attrp = (struct attr_t *) __my_malloc(sizeof(struct attr_t));
3494    attrp->attr_tok = rd_attrp->attr_tok;
3495    attrp->attrnam = __pv_stralloc(attnam);
3496    /* must eval. after all param setting is done */
3497    attrp->attr_xp = __root_ndp;
3498    /* LOOKATME - think should just use attr inst loc */
3499    attrp->attr_fnind = __cur_fnam_ind;
3500    attrp->attrlin_cnt = __lin_cnt;
3501    attrp->attrnxt = NULL;
3502    if (last_attrp == NULL) attr_hd = attrp; else last_attrp->attrnxt = attrp;
3503    last_attrp = attrp;
3504 
3505    if (__toktyp == SEMI) goto chk_eol;
3506    if (__toktyp != COMMA)
3507     {
3508      __pv_ferr(3406, "attr_spec separator or end \"*)\" expected - %s read",
3509       __prt_vtok());
3510      goto err_skip_eol;
3511     }
3512    __get_vtok();
3513    continue;
3514   }
3515 
3516 done:
3517  /* caller must free attribute string when pased for all instances */
3518 
3519  /* restore total lines read */
3520  __total_rd_lines = sav_tot_lines;
3521  __cur_fnam_ind = sav_fnam_ind;
3522  /* SJM 07/30/01 - was using visp but that was not set or index */
3523  __cur_fnam = __in_fils[__cur_fnam_ind];
3524  /* small memory leak if syntax error */
3525  if (__pv_err_cnt > sav_ecnt) return(NULL);
3526  /* emit warnings if attr duplicated with different value - inform if same */
3527  if (attr_hd != NULL) attr_hd = chk_dup_attrs(attr_hd);
3528  return(attr_hd);
3529 }
3530 
3531 /*
3532  * check attribute list for duplicates
3533  * if duplicate remove - if different value warn if same value inform
3534  *
3535  * LOOKATME - if lots of attributes need to sort and match
3536  */
chk_dup_attrs(struct attr_t * attr_hd)3537 static struct attr_t *chk_dup_attrs(struct attr_t *attr_hd)
3538 {
3539  register struct attr_t *attrp1, *attrp2, *last_attrp1;
3540  struct attr_t *new_attrhd, *attrp3;
3541  char s1[RECLEN], s2[RECLEN];
3542 
3543  new_attrhd = attr_hd;
3544  last_attrp1 = NULL;
3545  for (attrp1 = attr_hd; attrp1 != NULL;)
3546   {
3547    for (attrp2 = attrp1->attrnxt; attrp2 != NULL; attrp2 = attrp2->attrnxt)
3548     {
3549      if (strcmp(attrp1->attrnam, attrp2->attrnam) == 0)
3550       {
3551        /* know both numbers but still use xpr cmp */
3552        if (__cmp_xpr(attrp1->attr_xp, attrp2->attr_xp) == 0)
3553         {
3554          __gfinform(3001, attrp2->attr_fnind, attrp2->attrlin_cnt,
3555           "attribute %s duplicated with same value (first at %s) - first discared",
3556          attrp1->attrnam, __bld_lineloc(s1, attrp1->attr_fnind,
3557          attrp1->attrlin_cnt));
3558         }
3559        else
3560         {
3561          __gfwarn(3101, attrp2->attr_fnind, attrp2->attrlin_cnt,
3562           "attribute %s value %s duplicated with different values - first at %s value %s discarded",
3563          attrp1->attrnam, __msgexpr_tostr(s1, attrp2->attr_xp),
3564          __bld_lineloc(__xs, attrp1->attr_fnind, attrp1->attrlin_cnt),
3565          __msgexpr_tostr(s2, attrp1->attr_xp));
3566         }
3567        /* SJM 10/16/00 - must set next before freeing and splicing */
3568        attrp3 = attrp1->attrnxt;
3569 
3570        /* splice out first - if more duplicates will catch later */
3571        if (last_attrp1 == NULL) new_attrhd = attrp1->attrnxt;
3572        else last_attrp1->attrnxt = attrp1->attrnxt;
3573        __free_xtree(attrp1->attr_xp);
3574 
3575        __my_free((char *) attrp1, sizeof(struct attr_t));
3576        /* must not advance last attr */
3577        attrp1 = attrp3;
3578        goto chk_nxt_attr;
3579       }
3580     }
3581    attrp1 = attrp1->attrnxt;
3582    last_attrp1 = attrp1;
3583 chk_nxt_attr:;
3584   }
3585  return(new_attrhd);
3586 }
3587 
3588 /*
3589  * ROUTINES TO READ CFG LIB.MAP INPUT FILE LIST
3590  */
3591 
3592 /*
3593  * read a cfg file - returns F on error else T
3594  * reads both library mapping file and the config blocks
3595  *
3596  * may have list of config map library files (if none given using map.lib)
3597  *
3598  * if passed the command line, insrc = FALSE, and mapfile is the file name
3599  * otherwise TRUE, NULL if in source
3600  *
3601  * SJM 11/29/03 - contrary to LRM but following NC, cfg can't appear in src
3602  * but allowing list of lib.map files
3603  */
__rd_cfg(void)3604 extern int32 __rd_cfg(void)
3605 {
3606  int32 i, sav_ecnt, sav_lin_cnt;
3607  FILE *fp;
3608  struct mapfiles_t *mapfp;
3609  char *sav_cur_fnam;
3610 
3611  /* DBG remove -- */
3612  if (__map_files_hd == NULL) __misc_terr(__FILE__, __LINE__);
3613  /* --- */
3614 
3615  /* initialize the instance clause rule binding XMR path component glb tab */
3616  __siz_bind_comps = 50;
3617  __bind_inam_comptab = (char **) __my_malloc(__siz_bind_comps*sizeof(char *));
3618  __last_bind_comp_ndx = -1;
3619  for (i = 0; i < __siz_bind_comps; i++) __bind_inam_comptab[i] = NULL;
3620 
3621  /* SJM 01/15/04 - reading cfg does not use in fils buts must save as cntxt */
3622  sav_lin_cnt = __lin_cnt;
3623  sav_cur_fnam = __cur_fnam;
3624 
3625  sav_ecnt = __pv_err_cnt;
3626  for (mapfp = __map_files_hd; mapfp != NULL; mapfp = mapfp->mapfnxt)
3627   {
3628    /* must set cur file and line count for error messages */
3629    __cur_fnam = __pv_stralloc(mapfp->mapfnam);
3630    __lin_cnt = 1;
3631    if ((fp = __tilde_fopen(__cur_fnam, "r")) == NULL)
3632     {
3633      __pv_err(3500, "cannot open config map library file %s - skipped",
3634       __cur_fnam);
3635      continue;
3636     }
3637    if (feof(fp))
3638     {
3639      __pv_warn(3121, "config map library file %s empty", __cur_fnam);
3640      continue;
3641     }
3642    rd1_cfg_file(fp);
3643   }
3644  /* and then put back */
3645  __lin_cnt = sav_lin_cnt;
3646  __cur_fnam = sav_cur_fnam;
3647 
3648  if (__pv_err_cnt != sav_ecnt) return(FALSE);
3649  return(TRUE);
3650 }
3651 
3652 /*
3653  * read contents of one config file
3654  */
rd1_cfg_file(FILE * fp)3655 static void rd1_cfg_file(FILE *fp)
3656 {
3657  register int32 ttyp;
3658  int32 ttyp2, sav_lin_cnt;
3659  FILE *incfp ;
3660  char *sav_cur_fnam;
3661 
3662  for (;;)
3663   {
3664    ttyp = __get_cfgtok(fp);
3665    if (ttyp == CFG_INCLUDE)
3666     {
3667      if ((ttyp2 = __get_cfgtok(fp)) != CFG_ID)
3668       {
3669        __pv_ferr(3501,
3670         "config map library include statement non wildcard file path name expected - %s read",
3671         __to_cfgtoknam(__xs, ttyp2));
3672        if (cfg_skipto_semi(ttyp2, fp) == CFG_EOF) return;
3673        continue;
3674       }
3675      if ((incfp = __tilde_fopen(__token, "r")) == NULL)
3676       {
3677        __pv_ferr(3502,
3678         "cannot open config map library include file %s - skipped",
3679         __token);
3680        if (cfg_skipto_semi(ttyp2, fp) == CFG_EOF) return;
3681        continue;
3682       }
3683      if (feof(incfp))
3684       {
3685        __pv_warn(3121, "config map library file %s empty", __token);
3686        goto skipto_semi;
3687       }
3688 
3689      /* SJM 01/15/04 - save ptr and malloc name for later err msgs */
3690      sav_lin_cnt = __lin_cnt;
3691      sav_cur_fnam = __cur_fnam;
3692      __cur_fnam = __pv_stralloc(__token);
3693      __lin_cnt = 1;
3694 
3695      rd1_cfg_file(incfp);
3696 
3697      __cur_fnam = sav_cur_fnam;
3698      __lin_cnt = sav_lin_cnt;
3699 
3700 skipto_semi:
3701      ttyp = __get_cfgtok(fp);
3702      if (ttyp != CFG_SEMI)
3703       {
3704        if (cfg_skipto_semi(ttyp2, fp) == CFG_EOF) return;
3705       }
3706      continue;
3707     }
3708    if (ttyp == CFG_LIBRARY)
3709     {
3710      rd_cfg_library(fp);
3711      continue;
3712     }
3713    if (ttyp == CFG_CFG)
3714     {
3715      rd_cfg_cfg(fp);
3716      continue;
3717     }
3718    if (ttyp == CFG_EOF) return;
3719   }
3720  /* -- DBG remove ---
3721  dump_mod_info();
3722  --- */
3723 }
3724 
3725 /*
3726  * read a library map file library list
3727  * expects library keyword to have been read and reads ending ; (or CFG_EOF)
3728  *
3729  * if no libraries specified and unresolved references after reading
3730  * source files (either from config or from list of source files)
3731  * elaboration will fail with unresolved lib refs
3732  */
rd_cfg_library(FILE * fp)3733 static void rd_cfg_library(FILE *fp)
3734 {
3735  int32 ttyp;
3736  struct cfglib_t *lbp;
3737  struct libel_t *lbep;
3738 
3739  /* get the library name */
3740  if ((ttyp =__get_cfgtok(fp)) != CFG_ID)
3741   {
3742    __pv_ferr(3503,
3743     "library map file library description library name expected - %s read",
3744     __to_cfgtoknam(__xs, ttyp));
3745    cfg_skipto_semi(ttyp, fp);
3746    return;
3747   }
3748  lbp = (struct cfglib_t *) __my_malloc(sizeof(struct cfglib_t));
3749  init_cfglib(lbp);
3750  /* needed for expand error messages */
3751  lbp->cfglb_fnam = __cur_fnam;
3752  lbp->cfglb_lno = __lin_cnt;
3753  lbp->sym_added = FALSE;
3754 
3755  if (!chk_libid(__token))
3756   {
3757    __pv_ferr(3504, "library name %s illegal simple Verilog identifier",
3758     __token);
3759   }
3760  lbp->lbname = __pv_stralloc(__token);
3761  lbep = rd_cfg_fspec_list(fp, FALSE);
3762  lbp->lbels = lbep;
3763  if (__cfglib_tail == NULL) __cfglib_hd = __cfglib_tail = lbp;
3764  else
3765   {
3766    __cfglib_tail->lbnxt = lbp;
3767    __cfglib_tail = lbp;
3768   }
3769 }
3770 
3771 /*
3772  * read a list of library file spec (wildcard) paths build and return list
3773  * reads first element and reads ending EOF (for --incdir) or semi
3774  *
3775  * SJM 12/11/03 - notice old config dir code was wrong - comma separated list
3776  *
3777  * LOOKATME - maybe should return nil on error
3778  */
rd_cfg_fspec_list(FILE * fp,int32 in_incdir)3779 static struct libel_t *rd_cfg_fspec_list(FILE *fp, int32 in_incdir)
3780 {
3781  int32 ttyp, ttyp2, sav_lin_cnt;
3782  struct libel_t *lbep, *lbep2, *lbep_hd, *last_lbep;
3783  FILE *incfp;
3784  char *sav_cur_fnam;
3785 
3786  for (lbep_hd = last_lbep = NULL;;)
3787   {
3788    ttyp = __get_cfgtok(fp);
3789    if (ttyp == CFG_SEMI || ttyp == CFG_EOF)
3790     {
3791      if (in_incdir)
3792       {
3793        if (ttyp == CFG_SEMI)
3794         {
3795          __pv_ferr(3507,
3796           "config library description file path spec in -incdir ';' illegal");
3797          cfg_skipto_eof(ttyp, fp);
3798         }
3799        break;
3800       }
3801      if (ttyp == CFG_EOF)
3802       {
3803        __pv_ferr(3507,
3804         "config library description file path spec in -incdir ';' illegal");
3805          cfg_skipto_eof(ttyp, fp);
3806        /* even if hit wrong early EOF return list build so far */
3807       }
3808      /* know correct sem read or error emitted */
3809      break;
3810     }
3811 
3812    if (ttyp != CFG_ID)
3813     {
3814      __pv_ferr(3506,
3815       "config library description file path spec expected - %s read",
3816       __to_cfgtoknam(__xs, ttyp));
3817 
3818      if ((ttyp2 = cfg_skipto_comma_semi(ttyp, fp)) == CFG_COMMA) continue;
3819      if (in_incdir && ttyp2 == CFG_SEMI)
3820       {
3821        __pv_ferr(3507,
3822         "config library description file path spec in -incdir ';' illegal");
3823        cfg_skipto_eof(ttyp, fp);
3824       }
3825      return(NULL);
3826     }
3827 
3828    /* -incdir [name of file contains comma separated lib list] */
3829    /* can be nested */
3830    /* case 1: -incdir file containg comma separated list but end with EOF */
3831    if (strcmp(__token, "-incdir") == 0)
3832     {
3833      /* read the config list from a file (comma separated) */
3834      if ((ttyp2 = __get_cfgtok(fp)) != CFG_ID)
3835       {
3836        __pv_ferr(3501,
3837         "config library description -incdir non wildcard file path name expected - %s read",
3838         __to_cfgtoknam(__xs, ttyp2));
3839 inc_err_skip:
3840        if (cfg_skipto_comma_semi(ttyp, fp) == CFG_COMMA) continue;
3841        return(NULL);
3842       }
3843      if ((incfp = __tilde_fopen(__token, "r")) == NULL)
3844       {
3845        __pv_ferr(3502,
3846         "cannot open config library description -incdir file %s - skipped",
3847         __token);
3848        goto inc_err_skip;
3849       }
3850      if (feof(incfp))
3851       {
3852        __pv_fwarn(3121,
3853         "config library description -incdir file %s empty", __token);
3854        goto inc_err_skip;
3855       }
3856 
3857      /* SJM 01/15/04 - save ptr and malloc name for later err msgs */
3858      sav_cur_fnam = __cur_fnam;
3859      sav_lin_cnt = __lin_cnt;
3860      __cur_fnam = __pv_stralloc(__token);
3861      __lin_cnt = 1;
3862 
3863      lbep = rd_cfg_fspec_list(incfp, TRUE);
3864      if (lbep != NULL)
3865       {
3866        /* link onto end and update last to end of new add (maybe long) list */
3867        if (last_lbep == NULL) lbep_hd = lbep;
3868        else last_lbep->lbenxt = lbep;
3869 
3870        /* SJM 12/08/03 - think this is wrong ??? - need a last */
3871        for (lbep2 = lbep; lbep2->lbenxt != NULL; lbep2 = lbep2->lbenxt) ;
3872        last_lbep = lbep2;
3873       }
3874      __my_fclose(incfp);
3875 
3876      __cur_fnam = sav_cur_fnam;
3877      __lin_cnt = sav_lin_cnt;
3878     }
3879    /* case 2: file spec - only other possibility */
3880    lbep = (struct libel_t *) __my_malloc(sizeof(struct libel_t));
3881    lbep->lbelsrc_rd = FALSE;
3882    lbep->lbefnam = __pv_stralloc(__token);
3883    lbep->lbcelndx = NULL;
3884    lbep->lbel_sytab = NULL;
3885    lbep->lbenxt = NULL;
3886    lbep->expanded = FALSE;
3887 
3888    if (last_lbep == NULL) lbep_hd = lbep; else last_lbep->lbenxt = lbep;
3889    last_lbep = lbep;
3890   }
3891  return(lbep_hd);
3892 }
3893 
3894 /*
3895  * read map library config block
3896  * know config keyword read and reads the endconfig keyword
3897  *
3898  * idea is that the library lists are separate from the config blocks
3899  */
rd_cfg_cfg(FILE * fp)3900 static void rd_cfg_cfg(FILE *fp)
3901 {
3902  int32 ttyp, len, cfg_beg_lno, nbytes, expl_config;
3903  struct cfgdes_t *desp, *des_hd, *des_tail;
3904  struct cfg_t *cfgp;
3905  struct cfgrule_t *rulp, *rule_beg, *rule_end;
3906  struct cfgnamlst_t *lblp;
3907  char objnam[IDLEN], libnam[IDLEN], celnam[IDLEN];
3908  char cfgnam[IDLEN], s1[IDLEN], s2[IDLEN];
3909 
3910  cfg_beg_lno = __lin_cnt;
3911  /* get the config name */
3912  if ((ttyp =__get_cfgtok(fp)) != CFG_ID)
3913   {
3914    __pv_ferr(3503, "config declaration config name expected - %s read",
3915     __to_cfgtoknam(__xs, ttyp));
3916    if (cfg_skipto_semi(ttyp, fp) == CFG_EOF) return;
3917    strcpy(cfgnam, "**none**");
3918   }
3919  else
3920   {
3921    strcpy(cfgnam, __token);
3922    ttyp = __get_cfgtok(fp);
3923   }
3924  if (ttyp != CFG_SEMI)
3925   {
3926    __pv_ferr(3531,
3927     "config declaration config name not followed by semicolon - %s read",
3928     __to_cfgtoknam(__xs, ttyp));
3929    if (cfg_skipto_semi(ttyp, fp) == CFG_EOF) return;
3930   }
3931  /* config names may need to match cell type names so can be escaped */
3932  if (!chk_libid(cfgnam))
3933   {
3934    if (chk_escid(cfgnam))
3935     {
3936      /* remove the leading escaping back slash and ending ' ' */
3937      strcpy(s1, &(cfgnam[1]));
3938      len = strlen(s1);
3939      s1[len - 1] = '\0';
3940      strcpy(cfgnam, s1);
3941     }
3942    else
3943     {
3944      __pv_ferr(3534,
3945       "illegal config name %s - must be legal Verlog identifier", cfgnam);
3946     }
3947   }
3948 
3949  cfgp = (struct cfg_t *) __my_malloc(sizeof(struct cfg_t));
3950  init_cfg(cfgp);
3951  cfgp->cfgnam = __pv_stralloc(cfgnam);
3952  /* config location info for tracing and error msgs */
3953  cfgp->cfg_fnam = __pv_stralloc(__cur_fnam);
3954  cfgp->cfg_lno = cfg_beg_lno;
3955 
3956  ttyp = __get_cfgtok(fp);
3957  /* config design statement must come first if used */
3958  if (ttyp == CFG_DESIGN)
3959   {
3960    /* SJM 12/08/03 - as I read LRM, every top module needs separate config */
3961    /* therefore only one design mod allowed - FIXME- text of LRM contradicts */
3962 
3963    des_hd = des_tail = NULL;
3964    for (;;)
3965     {
3966      ttyp =__get_cfgtok(fp);
3967      if (ttyp == CFG_SEMI)
3968       {
3969        if (des_hd == NULL)
3970         {
3971          __pv_ferr(3532,
3972           "config design statement requires at least one [lib name].[cell name]");
3973         }
3974        break;
3975       }
3976      /* get the design specifier [library].[mod name] */
3977      if (ttyp != CFG_ID)
3978       {
3979        __pv_ferr(3533,
3980         "config design statement design specifier expected - %s read",
3981         __to_cfgtoknam(__xs, ttyp));
3982        if (cfg_skipto_semi(ttyp, fp) == CFG_EOF) return;
3983        /* here just leave objnam nil for none */
3984       }
3985      else
3986       {
3987        /* library name required design cell name */
3988        /* notice cell nam can be escaped and if so escapes removed */
3989        if (!extract_design_nam(libnam, celnam, __token))
3990         {
3991          __pv_ferr(3535,
3992           "config design statement [library identifier].[cell identifier] expected - %s illegal",
3993           __to_cfgtoknam(__xs, ttyp));
3994          /* skip on error */
3995          continue;
3996         }
3997       desp = (struct cfgdes_t *) __my_malloc(sizeof(struct cfgdes_t));
3998       desp->deslbnam = __pv_stralloc(libnam);
3999       desp->deslbp = NULL;
4000       desp->topmodnam = __pv_stralloc(celnam);
4001       desp->desnxt = NULL;
4002 
4003       if (des_hd == NULL) des_hd = des_tail = desp;
4004       else
4005        {
4006         des_tail->desnxt = desp;
4007         des_tail = desp;
4008        }
4009      }
4010     }
4011    cfgp->cfgdeslist = des_hd;
4012 
4013    /* know ';' read to get here */
4014    ttyp =__get_cfgtok(fp);
4015   }
4016  rule_beg = rule_end = NULL;
4017  for (;;)
4018   {
4019    /* liblist or use clauses never start a config rule */
4020    switch(ttyp) {
4021     case CFG_DEFAULT:
4022      if (cfgp->cfgdflt != NULL)
4023       {
4024        __pv_ferr(3538, "config %s default clause repeated - new one replaces",
4025        cfgp->cfgnam);
4026       }
4027 
4028      /* format: default liblist [space sep list of library names]; */
4029      /* may return nil */
4030      if ((ttyp = __get_cfgtok(fp)) != CFG_LIBLIST)
4031       {
4032        __pv_ferr(3537,
4033         "config declaration default clause not followed by liblist keyword - %s read",
4034         __to_cfgtoknam(__xs, ttyp));
4035        if (cfg_skipto_semi_endconfig(ttyp, fp) != CFG_SEMI)
4036         return;
4037        continue;
4038       }
4039      if ((lblp = rd_liblist(fp)) != NULL)
4040       {
4041        if (cfgp->cfgdflt != NULL)
4042         {
4043          /* SJM 12/19/03 - LOOKATME - what if repated */
4044          __pv_ferr(3539, "config declaration default clause repeated - 2nd ignord");
4045         }
4046       }
4047      else
4048       {
4049        __pv_fwarn(3127, "config declaration default clause liblist empty");
4050       }
4051      rulp = (struct cfgrule_t *) __my_malloc(sizeof(struct cfgrule_t));
4052      init_rule(rulp);
4053      rulp->rul_libs = lblp;
4054      rulp->rultyp = CFG_DEFAULT;
4055      cfgp->cfgdflt = rulp;
4056      break;
4057     case CFG_ENDCFG:
4058      /* no semi after end config */
4059      goto endcfg_read;
4060     case CFG_INSTANCE:
4061      /* format: instance [inst name] liblist [space sep lib name list]; */
4062      /* format: instance [inst name] use [qualified mod type name]; */
4063 
4064      /* instance name can be XMR but take apart later */
4065      if ((ttyp = __get_cfgtok(fp)) != CFG_ID)
4066       {
4067        __pv_ferr(3540,
4068         "config instance clause instance named expected - %s read",
4069           __to_cfgtoknam(__xs, ttyp));
4070         if (cfg_skipto_semi_endconfig(ttyp, fp) != CFG_SEMI)
4071          return;
4072        continue;
4073       }
4074      /* save the instance name */
4075      strcpy(objnam, __token);
4076      /* check config XMR path and build malloced cfg nam list of components */
4077      /* if return F, table not built */
4078      if (!bld_inst_xmr_comptab(__token))
4079       {
4080        __pv_ferr(3540,
4081         "config instance clause instance name %s illegal Verilog hierarchical name",
4082        __token);
4083        continue;
4084       }
4085 
4086      lblp = NULL;
4087      if ((ttyp = __get_cfgtok(fp)) == CFG_LIBLIST)
4088       {
4089        /* case 1: liblist form - always reads ending ; */
4090        if ((lblp = rd_liblist(fp)) == NULL)
4091         {
4092          __pv_fwarn(3129, "config instance clause liblist empty - ignored");
4093          goto rd_nxt_tok;
4094         }
4095        rulp = (struct cfgrule_t *) __my_malloc(sizeof(struct cfgrule_t));
4096        init_rule(rulp);
4097        rulp->rultyp = CFG_INSTANCE;
4098        /* just set the instance name and lib names are in lblp */
4099        rulp->objnam = __pv_stralloc(objnam);
4100        rulp->rul_libs = lblp;
4101       }
4102      else if (ttyp == CFG_USE)
4103       {
4104        if (rd_use_clause(fp, s1, s2, &expl_config) == CFG_ENDCFG)
4105         return;
4106        /* on error s1 not set */
4107        if (strcmp(s1, "") == 0 && strcmp(s2, "") == 0) goto rd_nxt_tok;
4108 
4109        rulp = (struct cfgrule_t *) __my_malloc(sizeof(struct cfgrule_t));
4110        init_rule(rulp);
4111        rulp->rultyp = CFG_INSTANCE;
4112        /* instance objnam use s1.s2 */
4113        rulp->rul_use_libnam = __pv_stralloc(s1);
4114        rulp->rul_use_celnam = __pv_stralloc(s2);
4115        rulp->objnam = __pv_stralloc(objnam);
4116        rulp->use_rule_cfg = expl_config;
4117        rulp->is_use = TRUE;
4118       }
4119      else
4120       {
4121        __pv_ferr(3548,
4122         "config inst clause not followed by liblist or use clause - %s read",
4123         __to_cfgtoknam(__xs, ttyp));
4124        if (cfg_skipto_semi(ttyp, fp) == CFG_EOF) return;
4125        goto rd_nxt_tok;
4126       }
4127 
4128      /* SJM 01/14/03 - can't bld the inst XMR components tab until here */
4129      nbytes = (__last_bind_comp_ndx + 1)*sizeof(char *);
4130      rulp->inam_comptab = (char **) __my_malloc(nbytes);
4131      memcpy(rulp->inam_comptab, __bind_inam_comptab, nbytes);
4132      rulp->inam_comp_lasti = __last_bind_comp_ndx;
4133      /* head of instance name must match config name a design cell name */
4134      for (desp = cfgp->cfgdeslist; desp != NULL; desp = desp->desnxt)
4135       {
4136        if (strcmp(desp->topmodnam, rulp->inam_comptab[0]) == 0)
4137         goto fnd_match;
4138       }
4139      __pv_ferr(3541,
4140       "config instance clause hierachical path %s head does not match any design statement top level module name",
4141       s1);
4142 
4143 fnd_match:
4144      /* add to end of list since must search in order of appearance */
4145      if (rule_beg == NULL) cfgp->cfgrules = rule_beg = rule_end = rulp;
4146      else
4147       {
4148        rule_end->rulnxt = rulp;
4149        rule_end = rulp;
4150       }
4151 
4152      break;
4153     case CFG_CELL:
4154      /* format: cell [<lib:>cell] liblist [space sep lib name list]; */
4155      /* format: cell [<lib>:cell] use [qualified mod type name]; */
4156      if ((ttyp = __get_cfgtok(fp)) != CFG_ID)
4157       {
4158        __pv_ferr(3551,
4159         "config cell clause [library].cell name expected - %s read",
4160         __to_cfgtoknam(__xs, ttyp));
4161        if (cfg_skipto_semi_endconfig(ttyp, fp) != CFG_SEMI) return;
4162        continue;
4163       }
4164      if (!extract_libcell_nam(libnam, objnam, __token))
4165       {
4166        goto rd_nxt_tok;
4167       }
4168      lblp = NULL;
4169      if ((ttyp = __get_cfgtok(fp)) == CFG_LIBLIST)
4170       {
4171        /* AIV - LRM (pg 217) states lib.cell with liblist is an error */
4172        /* if stmt will work because libnam init in extract_libcell  */
4173        if (libnam[0] != '\0')
4174        {
4175          __pv_ferr(3552,
4176           "config cell clause library.cell (%s.%s) cannot be used with 'liblist' clause", libnam, objnam);
4177         if (cfg_skipto_semi_endconfig(ttyp, fp) != CFG_SEMI) return;
4178         goto rd_nxt_tok;
4179        }
4180 
4181        /* case 1: liblist form - always reads ending ; */
4182        if ((lblp = rd_liblist(fp)) == NULL)
4183         {
4184          __pv_fwarn(3131, "config cell clause liblist empty - ignored");
4185          goto rd_nxt_tok;
4186         }
4187        rulp = (struct cfgrule_t *) __my_malloc(sizeof(struct cfgrule_t));
4188        init_rule(rulp);
4189        rulp->rultyp = CFG_CELL;
4190        /* libnam optional    libnam.objnam */
4191        rulp->libnam = __pv_stralloc(libnam);
4192        rulp->objnam = __pv_stralloc(objnam);
4193        rulp->rul_libs = lblp;
4194       }
4195      else if (ttyp == CFG_USE)
4196       {
4197        if (rd_use_clause(fp, s1, s2, &expl_config) == CFG_ENDCFG) return;
4198        /* on error s1 not set */
4199        if (strcmp(s1, "") == 0 && strcmp(s2, "") == 0) goto rd_nxt_tok;
4200 
4201        rulp = (struct cfgrule_t *) __my_malloc(sizeof(struct cfgrule_t));
4202        init_rule(rulp);
4203        /* cell objnam use s1.s2 */
4204        rulp->rul_use_libnam = __pv_stralloc(s1);
4205        rulp->rul_use_celnam = __pv_stralloc(s2);
4206        rulp->use_rule_cfg = expl_config;
4207        /* objnam is the cell type to match */
4208        rulp->objnam = __pv_stralloc(objnam);
4209        rulp->libnam = __pv_stralloc(libnam);
4210        rulp->rultyp = CFG_CELL;
4211        rulp->is_use = TRUE;
4212       }
4213      else
4214       {
4215        __pv_ferr(3559,
4216         "config cell clause not followed by liblist or use keywords - %s read",
4217         __to_cfgtoknam(__xs, ttyp));
4218        if (cfg_skipto_semi(ttyp, fp) == CFG_EOF) return;
4219        goto rd_nxt_tok;
4220       }
4221 
4222      /* add to end of list since must search in order of appearance */
4223      if (rule_beg == NULL) cfgp->cfgrules = rule_beg = rule_end = rulp;
4224      else
4225       {
4226        rule_end->rulnxt = rulp;
4227        rule_end = rulp;
4228       }
4229      break;
4230     default:
4231      __pv_ferr(3561,
4232       "config declaration rule statement or endconfig expected - %s read",
4233       __to_cfgtoknam(__xs, ttyp));
4234      if (cfg_skipto_semi(ttyp, fp) == CFG_EOF) return;
4235    }
4236 rd_nxt_tok:
4237    ttyp =__get_cfgtok(fp);
4238   }
4239 endcfg_read:
4240    /* AIV add the config to the list */
4241    if (__cfg_hd == NULL) __cfg_hd = __cur_cfg = cfgp;
4242    else { __cur_cfg->cfgnxt = cfgp;  __cur_cfg = cfgp; }
4243  return;
4244 }
4245 
4246 /*
4247  * initialize a rule record
4248  */
init_rule(struct cfgrule_t * rulp)4249 static void init_rule(struct cfgrule_t *rulp)
4250 {
4251  rulp->rultyp = CFG_UNKNOWN;
4252  rulp->use_rule_cfg = FALSE;
4253  rulp->objnam = NULL;
4254  rulp->libnam = NULL;
4255  rulp->rul_use_libnam = NULL;
4256  rulp->rul_use_celnam = NULL;
4257  rulp->inam_comptab = NULL;
4258  rulp->inam_comp_lasti = -1;
4259  rulp->rul_libs = NULL;
4260  rulp->rulnxt = NULL;
4261  /* AIV just set the line to current line  */
4262  rulp->rul_lno =  __lin_cnt;
4263  rulp->matched =  FALSE;
4264  rulp->is_use =  FALSE;
4265 }
4266 
4267 /*
4268  * extract a [lib].[cell] design name - format [lib].[cell]
4269  * lib ID lexical pattern is: [let or _]{let | num | $ | _}
4270  *
4271  * SJM 12/19/03 - LRM wrong since config can't be in Verilog source lib
4272  * and cell names both required
4273  *
4274  * SJM 01/12/04 - library identifiers (names) can't be escaped
4275  */
extract_design_nam(char * libnam,char * celnam,char * desnam)4276 static int32 extract_design_nam(char *libnam, char *celnam, char *desnam)
4277 {
4278  register char *chp;
4279  int32 len;
4280  char s1[IDLEN], s2[IDLEN];
4281 
4282  strcpy(libnam, "");
4283  strcpy(celnam, "");
4284 
4285  if ((chp = strchr(desnam, '.')) == NULL) return(FALSE);
4286  strncpy(s1, desnam, chp - desnam);
4287  s1[chp - desnam] = '\0';
4288  if (!chk_libid(s1)) return(-1);
4289  strcpy(libnam, s1);
4290 
4291  chp++;
4292  strcpy(s2, chp);
4293  if (!chk_libid(s2))
4294   {
4295    if (chk_escid(s2))
4296     {
4297      /* remove the leading escaping back slash and ending ' ' */
4298      strcpy(s1, &(s2[1]));
4299      len = strlen(s1);
4300      s1[len - 1] = '\0';
4301     }
4302    else
4303     {
4304      __pv_ferr(3534,
4305       "illegal cell name %s - must be legal Verlog identifier", s2);
4306     }
4307    strcpy(celnam, s1);
4308    return(TRUE);
4309   }
4310  strcpy(celnam, s2);
4311  return(TRUE);
4312 }
4313 
4314 /*
4315  * check and return T if library name is legal unescaped ID
4316  */
chk_libid(char * lbnam)4317 static int32 chk_libid(char *lbnam)
4318 {
4319  register char *chp;
4320 
4321  chp = lbnam;
4322  if (!isalpha(*chp) && *chp != '_') return(FALSE);
4323  for (++chp; *chp != '\0'; chp++)
4324   {
4325    if (!isalnum(*chp) && *chp!= '$' && *chp != '_') return(FALSE);
4326   }
4327  return(TRUE);
4328 }
4329 
4330 /*
4331  * check and return T if path component or cell type name is legal escaped ID
4332  */
chk_escid(char * nam)4333 static int32 chk_escid(char *nam)
4334 {
4335  int32 len;
4336  char *chp;
4337 
4338  chp = nam;
4339  if (*chp != '\\') return(FALSE);
4340  len = strlen(nam);
4341  if (nam[len - 1] != ' ') return(FALSE);
4342  return(TRUE);
4343 }
4344 
4345 /*
4346  * build table of ptrs to strings in global cfg bind table of instance comps
4347  * return F on error
4348  *
4349  * grows global table - caller will copy to malloced memory
4350  */
bld_inst_xmr_comptab(char * inam)4351 static int32 bld_inst_xmr_comptab(char *inam)
4352 {
4353  register int32 ci;
4354  register char *chp, *chp2;
4355  int32 len;
4356  char s1[IDLEN], s2[IDLEN];
4357 
4358  /* AIV need to reset the global, after it is copied */
4359  __last_bind_comp_ndx = -1;
4360 
4361  for (chp = inam;;)
4362   {
4363    if (*chp == '\\')
4364     {
4365      if ((chp2 = strchr(chp, ' ')) == NULL)
4366       {
4367 bad_end:
4368        for (ci = 0; ci <= __last_bind_comp_ndx; ci++)
4369         {
4370          __my_free(__bind_inam_comptab[ci],
4371           strlen(__bind_inam_comptab[ci]) + 1);
4372          __bind_inam_comptab[ci] = NULL;
4373         }
4374        return(TRUE);
4375       }
4376 
4377      strncpy(s1, chp, chp2 - chp);
4378      s1[chp2 - chp] = '\0';
4379      if (!chk_escid(s1)) goto bad_end;
4380      strcpy(s2, &(s1[1]));
4381      s2[chp2 - chp - 2] = '\0';
4382      chp++;
4383     }
4384    else
4385     {
4386      if ((chp2 = strchr(chp, '.')) == NULL)
4387       {
4388        strcpy(s2, chp);
4389        len = strlen(chp);
4390        chp = &(chp[len]);
4391       }
4392      else
4393       {
4394        /* non escaped and non tail component */
4395        strncpy(s2, chp, chp2 - chp);
4396        s2[chp2 - chp] = '\0';
4397        chp = chp2;
4398       }
4399     }
4400    /* add malloced comp name to table - table copied so do not need to free */
4401    if (++__last_bind_comp_ndx >= __siz_bind_comps) grow_bind_comps();
4402    __bind_inam_comptab[__last_bind_comp_ndx] = __pv_stralloc(s2);
4403 
4404    if (*chp == '\0') break;
4405    if (*chp != '.') goto bad_end;
4406    chp++;
4407   }
4408  return(TRUE);
4409 }
4410 
4411 /*
4412  * routine to grow global bind comp table
4413  */
grow_bind_comps(void)4414 static void grow_bind_comps(void)
4415 {
4416  int32 osize, nsize;
4417 
4418  osize = __siz_bind_comps*sizeof(char *);
4419  /* SJM 01/13/04 - maybe growing too fast */
4420  __siz_bind_comps *= 2;
4421  nsize = __siz_bind_comps*sizeof(char *);
4422  __bind_inam_comptab = (char **) __my_realloc((char *) __bind_inam_comptab,
4423   osize, nsize);
4424 }
4425 
4426 
4427 /*
4428  * extract a <lib>.[cell] name where [lib] optional
4429  *
4430  * almost same as extracting design [lib].[cell] but there lib name required
4431  */
extract_libcell_nam(char * libnam,char * celnam,char * nam)4432 static int32 extract_libcell_nam(char *libnam, char *celnam, char *nam)
4433 {
4434  register char *chp;
4435  char s1[IDLEN], s2[IDLEN];
4436 
4437  strcpy(libnam, "");
4438  strcpy(celnam, "");
4439 
4440  /* case 1: library omitted and escaped cell name */
4441  if (*nam == '\\')
4442   {
4443    strcpy(s2, nam);
4444 
4445 do_cell_tail:
4446    if ((chp = strchr(nam, ' ')) == NULL) return(FALSE);
4447    strncpy(celnam, nam, chp - nam);
4448    celnam[chp - nam] = '\0';
4449    /* checking esc ID but for now will never fail */
4450    if (!chk_escid(s2)) return(FALSE);
4451    strncpy(s1, &(nam[1]), chp - nam - 2);
4452    s1[chp - nam - 2] = '\0';
4453    strcpy(celnam, s1);
4454    chp++;
4455    if (*chp != '\0') return(FALSE);
4456    return(TRUE);
4457   }
4458  /* if lib name before '.' present, check and fill */
4459  if ((chp = strchr(nam, '.')) != NULL)
4460   {
4461    strncpy(s1, nam, chp - nam);
4462    s1[chp - nam] = '\0';
4463    if (!chk_libid(s1)) return(FALSE);
4464    strcpy(libnam, s1);
4465    chp++;
4466    strcpy(s1, chp);
4467   }
4468  else strcpy(s1, nam);
4469 
4470  /* case 3: lib name present and escaped ID */
4471  if (*s1 == '\\') goto do_cell_tail;
4472 
4473  /* case 4: lib name non escaped ID */
4474  if (!chk_libid(s1)) { strcpy(libnam, ""); return(FALSE); }
4475  strcpy(celnam, s1);
4476  return(TRUE);
4477 }
4478 
4479 /*
4480  * read a use clause and ending SEMI
4481  *
4482  * know use keyword read and reads ending SEMI unless error where resync
4483  * on error return F and set libnam and cell name to empty
4484  */
rd_use_clause(FILE * fp,char * libnam,char * celnam,int32 * expl_config)4485 static int32 rd_use_clause(FILE *fp, char *libnam, char *celnam,
4486  int32 *expl_config)
4487 {
4488  int32 ttyp, ttyp2, has_cfg_suffix;
4489 
4490  strcpy(libnam, "");
4491  strcpy(celnam, "");
4492 
4493  if ((ttyp = __get_cfgtok(fp)) != CFG_ID)
4494   {
4495    __pv_ferr(3542,
4496     "config use clause not followed by use specifier - %s read",
4497     __to_cfgtoknam(__xs, ttyp));
4498    ttyp2 = cfg_skipto_semi_endconfig(ttyp, fp);
4499    return(ttyp2);
4500   }
4501  /* this always sets has cfg suffix */
4502  if (!extract_use_nam(libnam, celnam, &has_cfg_suffix, __token))
4503   {
4504    __pv_ferr(3546,
4505     "config use clause %s illegal - [lib].[cell] or [cell]:config allowed - P1364 disallows configs in library source files",
4506     __token);
4507   }
4508  *expl_config = has_cfg_suffix;
4509 
4510  if ((ttyp = __get_cfgtok(fp)) != CFG_SEMI)
4511   {
4512    __pv_ferr(3544,
4513     "config use clause not followed by semicolon - %s read",
4514     __to_cfgtoknam(__xs, ttyp));
4515    ttyp = cfg_skipto_semi_endconfig(ttyp, fp);
4516    return(ttyp);
4517   }
4518  return(SEMI);
4519 }
4520 
4521 /*
4522  * extract a use clause cell identifier
4523  * format: <lib name>[cell type name]<:config>
4524  *
4525  * if lib name is omitted parent (current) cell's lib used
4526  * if :config used, the use config matching [cell type name] for binding
4527  */
extract_use_nam(char * libnam,char * celnam,int32 * has_config,char * use_spec)4528 static int32 extract_use_nam(char *libnam, char *celnam, int32 *has_config,
4529  char *use_spec)
4530 {
4531  register char *chp;
4532  char s1[IDLEN], s2[IDLEN];
4533 
4534  strcpy(libnam, "");
4535  strcpy(celnam, "");
4536  *has_config = FALSE;
4537 
4538  /* case 1: library omitted and escaped cell name */
4539  if (*use_spec == '\\')
4540   {
4541    strcpy(s2, use_spec);
4542 
4543 do_cell_tail:
4544    if ((chp = strchr(use_spec, ' ')) == NULL) return(FALSE);
4545    strncpy(celnam, use_spec, chp - use_spec);
4546    celnam[chp - use_spec] = '\0';
4547    /* checking esc ID but for now will never fail */
4548    if (!chk_escid(s2)) return(FALSE);
4549    strncpy(s1, &(use_spec[1]), chp - use_spec - 2);
4550    s1[chp - use_spec - 2] = '\0';
4551    strcpy(celnam, s1);
4552    chp++;
4553    if (*chp == ':')
4554     {
4555      if (strcmp(chp, ":config") != 0) return(FALSE);
4556      /* SJM 05/18/04 - :config hierarchical config indirection indicator */
4557      /* can't be used with library name since library are for Verilog src */
4558      if (strcmp(libnam, "") != 0) return(FALSE);
4559      *has_config = TRUE;
4560     }
4561    else
4562     {
4563      if (*chp != '\0') return(FALSE);
4564     }
4565    return(TRUE);
4566   }
4567  /* if lib name before '.' present, check and fill */
4568  if ((chp = strchr(use_spec, '.')) != NULL)
4569   {
4570    strncpy(s1, use_spec, chp - use_spec);
4571    s1[chp - use_spec] = '\0';
4572    if (!chk_libid(s1)) return(FALSE);
4573    strcpy(libnam, s1);
4574    chp++;
4575    strcpy(s1, chp);
4576   }
4577  else strcpy(s1, use_spec);
4578 
4579  /* case 3: lib name present and escaped ID */
4580  if (*s1 == '\\') goto do_cell_tail;
4581 
4582  /* case 4: lib name non escaped ID */
4583  if ((chp = strchr(s1, ':')) == NULL)
4584   {
4585    if (!chk_libid(s1)) { strcpy(libnam, ""); return(FALSE); }
4586    strcpy(celnam, s1);
4587    return(TRUE);
4588   }
4589  /* :config suffix present */
4590  if (strcmp(chp, ":config") != 0) return(FALSE);
4591 
4592  strncpy(s2, s1, chp - s1);
4593  s2[chp - s1] = '\0';
4594  if (!chk_libid(s2)) return(FALSE);
4595  strcpy(celnam, s2);
4596 
4597  /* SJM 05/18/04 - :config hierarchical config indirection indicator */
4598  /* can't be used with library name since library are for Verilog src */
4599  if (strcmp(libnam, "") != 0) return(FALSE);
4600 
4601  *has_config = TRUE;
4602  return(TRUE);
4603 }
4604 
4605 /*
4606  * read a liblist non comma separated list of libraries
4607  *
4608  * know liblist keyword read and reads first libr and keeps reading lib
4609  * names (no wildcards) until ending semicolon read (i.e. list ends with ;
4610  * and no commas)
4611  *
4612  * library names are simple IDs
4613  * even if error continues reading to ; or EOF
4614  */
rd_liblist(FILE * fp)4615 static struct cfgnamlst_t *rd_liblist(FILE *fp)
4616 {
4617  int32 ttyp;
4618  struct cfgnamlst_t *lbp, *lbp_hd, *lbp_tail;
4619 
4620  lbp_hd = lbp_tail = NULL;
4621  for (;;)
4622   {
4623    ttyp = __get_cfgtok(fp);
4624    if (ttyp == CFG_SEMI) break;
4625 
4626    if (ttyp != CFG_ID)
4627     {
4628      __pv_ferr(3562, "config liblist library name expected - %s read",
4629       __to_cfgtoknam(__xs, ttyp));
4630      cfg_skipto_semi(ttyp, fp);
4631      return(NULL);
4632     }
4633    if (!chk_libid(__token))
4634     {
4635      __pv_ferr(3563,
4636       "config liblist library name %s illegal - must be simple Verilog ID",
4637       __token);
4638     }
4639    lbp = (struct cfgnamlst_t *) __my_malloc(sizeof(struct cfgnamlst_t));
4640    lbp->nam = __pv_stralloc(__token);
4641    lbp->cnlnxt = NULL;
4642    if (lbp_hd == NULL) lbp_hd = lbp_tail = lbp;
4643    else { lbp_tail->cnlnxt = lbp;  lbp_tail = lbp; }
4644   }
4645  return(lbp_hd);
4646 }
4647 
4648 /*
4649  * LOW LEVEL ROUTINES FOR CFG INITIALIZATION AND ERROR RECOVERY
4650  */
4651 
4652 /*
4653  * initialize a cfg lib record
4654  */
init_cfglib(struct cfglib_t * lbp)4655 static void init_cfglib(struct cfglib_t *lbp)
4656 {
4657  lbp->lbsrc_rd = FALSE;
4658  lbp->lbname = NULL;
4659  lbp->lbels = NULL;
4660  lbp->lbnxt = NULL;
4661 }
4662 
4663 /*
4664  * initialize a cfg block record
4665  */
init_cfg(struct cfg_t * cfgp)4666 static void init_cfg(struct cfg_t *cfgp)
4667 {
4668  cfgp->cfgnam = NULL;
4669  cfgp->cfgdeslist = NULL;
4670  cfgp->cfgrules = NULL;
4671  cfgp->cfgdflt = NULL;
4672  cfgp->cfg_fnam = NULL;
4673  cfgp->cfg_lno = -1;
4674  cfgp->cfgnxt = NULL;
4675 }
4676 
4677 /*
4678  * cfg get token error recovery skip to semi
4679  *
4680  * notice config token number not related to source reading numbers
4681  * but using __token global for names still
4682  */
cfg_skipto_semi(int32 ttyp,FILE * fp)4683 static int32 cfg_skipto_semi(int32 ttyp, FILE *fp)
4684 {
4685  for (;;)
4686   {
4687    if (ttyp == CFG_SEMI || ttyp == CFG_EOF) break;
4688    ttyp = __get_cfgtok(fp);
4689   }
4690  return(ttyp);
4691 }
4692 
4693 /*
4694  * cfg get token error recovery skip to semi or comma
4695  *
4696  * notice config token number not related to source reading numbers
4697  * but using __token global for names still
4698  */
cfg_skipto_comma_semi(int32 ttyp,FILE * fp)4699 static int32 cfg_skipto_comma_semi(int32 ttyp, FILE *fp)
4700 {
4701  for (;;)
4702   {
4703    if (ttyp == CFG_SEMI || ttyp == CFG_EOF) break;
4704    ttyp = __get_cfgtok(fp);
4705   }
4706  return(ttyp);
4707 }
4708 
4709 /*
4710  * cfg get token error recovery skip to semi or endconfig
4711  *
4712  * notice config token number not related to source reading numbers
4713  * but using __token global for names still
4714  */
cfg_skipto_semi_endconfig(int32 ttyp,FILE * fp)4715 static int32 cfg_skipto_semi_endconfig(int32 ttyp, FILE *fp)
4716 {
4717  for (;;)
4718   {
4719    if (ttyp == CFG_SEMI || ttyp == CFG_ENDCFG || ttyp == CFG_EOF) break;
4720    ttyp = __get_cfgtok(fp);
4721   }
4722  return(ttyp);
4723 }
4724 
4725 
4726 /*
4727  * cfg get token error recovery skip
4728  *
4729  * notice config token number not related to source reading numbers
4730  */
cfg_skipto_eof(int32 ttyp,FILE * fp)4731 static int32 cfg_skipto_eof(int32 ttyp, FILE *fp)
4732 {
4733  for (;;)
4734   {
4735    if (ttyp == CFG_EOF) break;
4736    ttyp = __get_cfgtok(fp);
4737   }
4738  return(ttyp);
4739 }
4740 
4741 /*
4742  * ROUTINES TO EXPAND AND REPLACE LIBRARY WILDCARD FILE LISTS
4743  */
4744 
4745 /* names for the special wildcard characters - see LRM */
4746 #define STAR 1
4747 #define QMARK 2
4748 #define HIER 3
4749 
4750 /*
4751  * return TRUE if the string contains a wildcard
4752  * '*', '?', '...', or ending in a / => TRUE
4753  */
has_wildcard(char * cp)4754 static int32 has_wildcard(char *cp)
4755 {
4756  int32 i, slen;
4757 
4758  slen = strlen(cp);
4759  /* if it ends in a slash return TRUE - include all case */
4760  if (cp[slen -1] == '/') return(TRUE);
4761  for (i = 0; i <= slen - 1; i++, cp++)
4762   {
4763    if (*cp == '*') return(TRUE);
4764    if (*cp == '?') return(TRUE);
4765    if (i < slen + 2 && strncmp(cp, "...", 3) == 0) return(TRUE);
4766   }
4767  return(FALSE);
4768 }
4769 
4770 /*
4771  * expand all wild cards in library file name lists
4772  *
4773  * first step in cfg elaboration after all map and cfg files read
4774  */
__expand_lib_wildcards(void)4775 extern void __expand_lib_wildcards(void)
4776 {
4777  register struct cfglib_t *lbp;
4778  register struct libel_t *lbep;
4779  int32 sav_lin_cnt;
4780  char *sav_cur_fnam, *cp;
4781  FILE *fp;
4782 
4783  /* expand for library */
4784  for (lbp = __cfglib_hd; lbp != NULL; lbp = lbp->lbnxt)
4785   {
4786    sav_lin_cnt = __lin_cnt;
4787    sav_cur_fnam = __cur_fnam;
4788    __cur_fnam = lbp->cfglb_fnam;
4789    __lin_cnt = lbp->cfglb_lno;
4790 
4791    /* for each fspec in one library's fspec list, expand any wildcards */
4792    for (lbep = lbp->lbels; lbep != NULL; lbep = lbep->lbenxt)
4793     {
4794      /* AIV mark the expanded so the pattern string is replaced */
4795      lbep->expanded = FALSE;
4796      cp = lbep->lbefnam;
4797      /* if it doesn't contain a wildcard char must be a file so simple open */
4798      if (!has_wildcard(cp))
4799       {
4800        /* if it returns NULL file no such file */
4801        if ((fp = __tilde_fopen(cp, "r")) == NULL)
4802         {
4803          __pv_ferr(3564, "config library %s unable to match pattern %s\n",
4804           lbp->lbname, cp);
4805         }
4806        else
4807         {
4808          /* no need to change the file name, just mark the flag as expanded */
4809          lbep->expanded = TRUE;
4810          /* close the open file */
4811          __my_fclose(fp);
4812         }
4813       }
4814      else if (strcmp(cp, "...") == 0)
4815       {
4816        /* include all files below the current directory */
4817        if (!expand_single_hier(lbp, lbep, NULL))
4818         {
4819          __pv_ferr(3564, "config library %s unable to match pattern %s\n",
4820           lbp->lbname, cp);
4821         }
4822       }
4823      else
4824       {
4825         /* match the pattern case */
4826         expand_dir_pats(lbp, lbep, cp);
4827       }
4828    }
4829    /* put back for further reading */
4830    __lin_cnt = sav_lin_cnt;
4831    __cur_fnam = sav_cur_fnam;
4832   }
4833 }
4834 
4835 /*
4836  * match a hier name with the given pattern name
4837  */
match_hier_name(struct xpndfile_t * xfp_hd,char * name)4838 static int32 match_hier_name(struct xpndfile_t *xfp_hd, char *name)
4839 {
4840  char *cp, *last;
4841  char str[RECLEN];
4842  struct xpndfile_t *xfp;
4843 
4844  /* skip past ./ meaningless */
4845  if (name[0] == '.' && name[1] == '/') name += 2;
4846  last = name;
4847  xfp = xfp_hd;
4848  cp = strchr(name, '/');
4849  if (cp == NULL)
4850   {
4851    /* Special case ../../\*.v  - last pattern and matches wildcard */
4852    if (xfp->xpfnxt == NULL && match_wildcard_str(name, xfp)) return(TRUE);
4853    /* Special case .../\*.v  */
4854    else if (xfp->wildcard == HIER && xfp->xpfnxt->xpfnxt == NULL
4855     && match_wildcard_str(name, xfp->xpfnxt)) return(TRUE);
4856   }
4857  else
4858   {
4859    for (; xfp != NULL && cp != NULL; cp = strchr(cp, '/'))
4860     {
4861      /* check the string to the next '/' to match the pattern */
4862      /* copy /string/ into str to check with pattern */
4863      strncpy(str, last, cp - last);
4864      str[cp-last] ='\0';
4865      /* if doesn't match pattern return */
4866      if (!match_wildcard_str(str, xfp)) return(FALSE);
4867      /* handle special ... case */
4868      if (xfp->wildcard == HIER)
4869       {
4870        /* no more patterns it is a match */
4871        if (xfp->xpfnxt == NULL) return(TRUE);
4872 
4873        /* match all the remaining patterns after .../ */
4874        /* move pattern up one and get the next /string/ */
4875 hier:
4876        xfp = xfp->xpfnxt;
4877        for (; cp != NULL;  )
4878         {
4879          /* special case it is the last one */
4880          if ((cp - last) == 0) strcpy(str, cp);
4881          else
4882           {
4883            strncpy(str, last, cp - last);
4884            str[cp-last] ='\0';
4885           }
4886          /* if matches continue */
4887          if (match_wildcard_str(str, xfp))
4888           {
4889            xfp = xfp->xpfnxt;
4890            if (xfp == NULL) return(TRUE);
4891           }
4892          last = ++cp;
4893          /* last pattern in the string dir/dir2/lastpattern */
4894          if ((cp = strchr(cp, '/')) == NULL)
4895           {
4896            /* if more patterns continue */
4897            if (xfp->xpfnxt != NULL) return(FALSE); strcpy(str, last);
4898            /* match the lastpattern and gets here it is a match */
4899            if (match_wildcard_str(str, xfp)) return(TRUE);
4900           }
4901         }
4902       }
4903      last = ++cp;
4904 
4905      /* include all in the directory and the last in the char name */
4906      if (xfp->incall && strchr(cp, '/') == NULL) return(TRUE);
4907 
4908      /* if the last pattern and didn't match FALSE  */
4909      xfp = xfp->xpfnxt;
4910      if (xfp == NULL)  return(FALSE);
4911      if (xfp->wildcard == HIER && xfp->xpfnxt != NULL) goto hier;
4912      /* try to match the last of the string */
4913      if (*cp != '\0' && strchr(cp, '/') == NULL)
4914       {
4915        if (xfp->xpfnxt == NULL && match_wildcard_str(cp, xfp)) return(TRUE);
4916        else return(FALSE);
4917       }
4918     }
4919   }
4920  return(FALSE);
4921 }
4922 
4923 /*
4924  * match the special hierarchical wildcard in the pattern
4925  * is recursive call which takes the parameters -
4926  *
4927  * xfp_hd - the start of the split pattern to match
4928  * bpath - the beginning part of the path (the non-wildcard start of the path)
4929  * path - the current path
4930  *
4931  * builds the strings to match according to attempt to match to the xfp list
4932  */
find_hier(struct libel_t * lbep,struct xpndfile_t * xfp_hd,char * bpath,char * path)4933 static void find_hier(struct libel_t *lbep, struct xpndfile_t *xfp_hd,
4934  char *bpath, char *path)
4935 {
4936  char str[RECLEN];
4937  char str2[RECLEN];
4938  char dirstr[RECLEN];
4939  char *cp;
4940  DIR *dp;
4941  struct dirent *dir;
4942 #if defined(__CYGWIN32__) || defined(__SVR4)
4943  struct stat sbuf;
4944 #endif
4945 
4946  /* start from the current directory */
4947  if (path == NULL) { strcpy(str, "."); cp = str; }
4948  else cp = path;
4949 
4950  if ((dp = opendir(cp)) == NULL)
4951   {
4952    __pv_ferr(1368, "during config library expansion cannot open dir %s : %s\n",
4953     cp, strerror(errno));
4954   }
4955 
4956  while ((dir = readdir(dp)) != NULL)
4957   {
4958    if (dir->d_ino == 0) continue;
4959    if (strcmp(dir->d_name, ".") == 0) continue;
4960    if (strcmp(dir->d_name, "..") == 0) continue;
4961 #if defined(__CYGWIN32__) || defined(__SVR4)
4962    if (stat(dir->d_name, &sbuf) == -1) continue;
4963    if ((S_IFMT & sbuf.st_mode) == S_IFDIR)
4964 #else
4965    if (dir->d_type == DT_DIR)
4966 #endif
4967     {
4968      /* directory concat name and call recursively */
4969      if (path == NULL) sprintf(dirstr, "./%s", dir->d_name);
4970      else sprintf(dirstr, "%s/%s", path, dir->d_name);
4971      find_hier(lbep, xfp_hd, bpath, dirstr);
4972     }
4973 #if defined(__CYGWIN32__) || defined(__SVR4)
4974    else if ((S_IFMT & sbuf.st_mode) == S_IFREG)
4975 #else
4976    else if (dir->d_type == DT_REG)
4977 #endif
4978     {
4979      str[0] ='\0';
4980      /* concat the file name to the directory */
4981      if (path == NULL) strcpy(str, dir->d_name);
4982      else sprintf(str, "%s/%s", cp, dir->d_name);
4983      /* check if the name matches the xfp list */
4984      if (match_hier_name(xfp_hd, str))
4985       {
4986        if (bpath != NULL)
4987         {
4988          sprintf(str2, "%s/%s", bpath, str);
4989          expand_libel(lbep, str2);
4990         }
4991        else expand_libel(lbep, str);
4992       }
4993     }
4994   }
4995  if (dp != NULL) closedir(dp);
4996 }
4997 
4998 /*
4999  * routine to actually do the hierarchical search
5000  * moves to the first wildcard xfp and does search
5001  */
expand_hier_files(struct cfglib_t * lbp,struct libel_t * lbep,struct xpndfile_t * xfp_hd)5002 static void expand_hier_files(struct cfglib_t *lbp, struct libel_t *lbep,
5003  struct xpndfile_t *xfp_hd)
5004 {
5005  char dirstr[RECLEN];
5006  char bpath[RECLEN];
5007  char tmp[RECLEN];
5008  int32 first;
5009 
5010  /* if the first xfp has a wildcard do the search do search with current xfp */
5011  if (xfp_hd->wildcard)
5012   {
5013    find_hier(lbep, xfp_hd, NULL, NULL);
5014    return;
5015   }
5016  first = TRUE;
5017  /* save current dir */
5018  getcwd(dirstr, RECLEN);
5019  strcpy(bpath, "");
5020  while (!xfp_hd->wildcard && xfp_hd->incall != TRUE)
5021   {
5022    if (chdir(xfp_hd->fpat) < 0)
5023     {
5024      if (first)
5025       {
5026        __pv_ferr(3564, "config library %s no such directory %s\n",
5027        lbp->lbname, xfp_hd->fpat);
5028       }
5029      else
5030       {
5031        __pv_ferr(3564, "config library %s no such directory %s/%s\n",
5032         lbp->lbname, bpath, xfp_hd->fpat);
5033        chdir(dirstr);
5034        return;
5035       }
5036     }
5037    /* move to non-wildcard dir and buld beginning path name */
5038    if (first)
5039     {
5040      strcpy(bpath, xfp_hd->fpat);
5041      first = FALSE;
5042     }
5043    else
5044     {
5045      strcpy(tmp, bpath);
5046      sprintf(bpath, "%s/%s", tmp, xfp_hd->fpat);
5047     }
5048    xfp_hd = xfp_hd->xpfnxt;
5049   }
5050  /* do the search */
5051  find_hier(lbep, xfp_hd, bpath, NULL);
5052  /* go back to the original dir  */
5053  chdir(dirstr);
5054 }
5055 
5056 /*
5057  * routine to break up the original user pattern by '/' - xfp1/xfp2/xfpn
5058  */
expand_dir_pats(struct cfglib_t * lbp,struct libel_t * lbep,char * pat)5059 static void expand_dir_pats(struct cfglib_t *lbp, struct libel_t *lbep,
5060  char *pat)
5061 {
5062  int32 slen, i, ndx, clevel, last_star;
5063  int32  wildcard, hier, cur_hier, last_hier, back_dir;
5064  char str[RECLEN];
5065  char *last, *cp;
5066  struct xpndfile_t *xfp, *xfp2, *xfp_hd, *xfp_tail;
5067 
5068  str[0] = '\0';
5069  clevel = -1;
5070  xfp_hd = xfp_tail = NULL;
5071  slen = strlen(pat);
5072  cp = last = pat;
5073  last_star = last_hier = wildcard = FALSE;
5074  back_dir = cur_hier = hier = FALSE;
5075  /* ndx if current index of the string */
5076  ndx = 0;
5077  for (i = 0; i < slen; i++, ndx++, cp++)
5078   {
5079    /* split add a xfp to the list */
5080    if (*cp == '/')
5081     {
5082      cur_hier = FALSE;
5083      /* special verilog escape char */
5084      if (i + 1 < slen && *(cp+1) == '/')
5085       {
5086        /* LOOKATME FIXME - check if this works */
5087        /* special espcaped char // read until next ' ' or end of str */
5088        i++;
5089        cp++;
5090        for (; i < slen && *cp != ' '; i++, cp++) ;
5091       }
5092      /* skip a /./ since it doesn't do anything */
5093      if (ndx == 1 &&  str[0] == '.') { last = (cp + 1); continue; }
5094      str[ndx] = '\0';
5095      if (ndx == 3 && strcmp(str, "...") == 0)
5096       {
5097        /* if ... and so was the last skip this one */
5098        if (last_hier)
5099         {
5100          __pv_warn(3124, "config can't have .../... - treating as only one\n");
5101          ndx = -1;
5102          continue;
5103         }
5104        cur_hier = hier = TRUE;
5105       }
5106      else if (ndx == 2 && back_dir && strcmp(str, "..") == 0)
5107       {
5108        __pv_warn(3125,
5109         "Back directory '..' can only be used at the beginning of pattern string\n");
5110       }
5111       /* AIV 05/25/04 - on the first non '..' set back_dir to true */
5112       /* there can be multilple ../.. prior to the pattern */
5113      else if(ndx != 2 || strcmp(str, "..") != 0)
5114             back_dir = TRUE;
5115 
5116      xfp = (struct xpndfile_t *) __my_malloc(sizeof(struct xpndfile_t));
5117      xfp->fpat = __pv_stralloc(str);
5118      if (cur_hier)
5119       {
5120        /* set the wildcar to hierarch */
5121        xfp->wildcard = HIER;
5122        last_hier = TRUE;
5123       }
5124      else
5125       {
5126        /* set the wildcar STAR or QMARK */
5127        xfp->wildcard = wildcard;
5128        last_hier = FALSE;
5129       }
5130      xfp->nmatch = 0;
5131      /* special case that ends in '/' inc all the files */
5132      if (i + 1 == slen) xfp->incall = TRUE;
5133      else xfp->incall = FALSE;
5134      xfp->xpfnxt = NULL;
5135 
5136      /* set the current depth level */
5137      xfp->level = ++clevel;
5138      if (xfp_hd == NULL) xfp_hd = xfp_tail = xfp;
5139      else { xfp_tail->xpfnxt = xfp;  xfp_tail = xfp; }
5140 
5141      /* set the last char to one past the / */
5142      if (i < slen) last = (cp + 1);
5143      /* reset wildcard and last_star and string index */
5144      wildcard = FALSE;
5145      last_star = FALSE;
5146      ndx = -1;
5147     }
5148    else if (*cp == '*')
5149     {
5150      /* previous chars was star as well so just set ndx back one to skip */
5151      if (last_star) ndx--;
5152      last_star = TRUE;
5153      wildcard = STAR;
5154      /* AIV 05/18/04 - can never be negative since last_star is a flag */
5155      /* that can only be set when ndx > 0 */
5156      str[ndx] = *cp;
5157     }
5158    else
5159     {
5160      /* star takes wildcard precedence over qmark - needed for pat matching */
5161      if (*cp == '?' && wildcard != STAR) wildcard = QMARK;
5162      last_star = FALSE;
5163      str[ndx] = *cp;
5164     }
5165   }
5166  /* LOOKATME will /a still work */
5167  /* add the last one this has to be a file or file pattern */
5168  cur_hier = FALSE;
5169  if (cp != last)
5170   {
5171    if (ndx == 1 && *(cp - 1) == '.') goto done;
5172    str[ndx] = '\0';
5173    if (strcmp(str, "...") == 0)
5174     {
5175      /* just skip the last ... if there is two in a row */
5176      if (last_hier) goto done; cur_hier = hier = TRUE;
5177     }
5178    xfp = (struct xpndfile_t *) __my_malloc(sizeof(struct xpndfile_t));
5179    xfp->fpat = __pv_stralloc(str);
5180    if (cur_hier) xfp->wildcard = HIER;
5181    else xfp->wildcard = wildcard;
5182    xfp->nmatch = 0;
5183    xfp->xpfnxt = NULL;
5184    xfp->level = ++clevel;
5185    if (xfp_hd == NULL) xfp_hd = xfp_tail = xfp;
5186    else { xfp_tail->xpfnxt = xfp;  xfp_tail = xfp; }
5187   }
5188 
5189  /* DGB REMOVE */
5190  if (xfp_hd == NULL) __misc_terr(__FILE__, __LINE__);
5191 
5192 done:
5193  /* doesn't contain a hieracrh ... */
5194  if (!hier)
5195   {
5196    /* if the first xfp contains a wildcard just call match overwise */
5197    /* move to on wildcard dir and then match */
5198    if (xfp_hd->wildcard) match_dir_pats(lbep, xfp_hd, NULL, NULL, FALSE, 0);
5199    else movedir_match_dir_pats(lbep, xfp_hd);
5200   }
5201  else
5202   {
5203    /* match the hier case */
5204    expand_hier_files(lbp, lbep, xfp_hd);
5205   }
5206  /* free xfp list */
5207  /* SJM 11/05/04 - need 2nd pointer since xpfnxt can't be accessed */
5208  /* after freed */
5209  for (xfp = xfp_hd ; xfp != NULL;)
5210   {
5211    xfp2 = xfp->xpfnxt;
5212    __my_free((char *) xfp, sizeof(struct xpndfile_t ));
5213    xfp = xfp2;
5214   }
5215 }
5216 
5217 /*
5218  * move xfp_hd to the first wildcard to start the search
5219  */
movedir_match_dir_pats(struct libel_t * lbep,struct xpndfile_t * xfp_hd)5220 static void movedir_match_dir_pats(struct libel_t *lbep,
5221  struct xpndfile_t *xfp_hd)
5222 {
5223  int32 level;
5224  char dirstr[RECLEN];
5225  char bpath[RECLEN];
5226 
5227  level = 0;
5228  /* save current directory */
5229  getcwd(dirstr, RECLEN);
5230  while (!xfp_hd->wildcard && xfp_hd->incall != TRUE)
5231   {
5232    if (chdir(xfp_hd->fpat) < 0)
5233     {
5234      /* SJM 05/11/04 - FIXME ### ??? - need way to locate these */
5235      /* AIV 05/18/04 if the currect level print current pattern name */
5236      if (level == 0)
5237       {
5238        __pv_warn(3132, "no such directory %s\n", xfp_hd->fpat);
5239       }
5240      else
5241       {
5242       /* if lower level print all previous path and current pattern name */
5243        __pv_warn(3132, "Error - no such directory path %s/%s\n",
5244         bpath, xfp_hd->fpat);
5245       }
5246      chdir(dirstr);
5247      return;
5248     }
5249    /* goto the next directory and inc the depth level */
5250    if (level == 0) strcpy(bpath, xfp_hd->fpat);
5251    else sprintf(bpath, "%s/%s", bpath, xfp_hd->fpat);
5252    level++;
5253    xfp_hd = xfp_hd->xpfnxt;
5254   }
5255  /* search directories */
5256  match_dir_pats(lbep, xfp_hd, NULL, bpath, FALSE, level);
5257  /* do back to the current directory */
5258  chdir(dirstr);
5259 }
5260 
5261 /*
5262  * match the patterns for each xfp->fpat per directory
5263  *
5264  * xfp_hd - points to the first wildcard name1/
5265  * bpath - start of path not containing a wildcard
5266  * path - points to all current path
5267  * incall - is the flag to include all the files in the dir, end in '/'
5268  */
match_dir_pats(struct libel_t * lbep,struct xpndfile_t * xfp_hd,char * path,char * bpath,int32 incall,int32 level)5269 static void match_dir_pats(struct libel_t *lbep, struct xpndfile_t *xfp_hd,
5270 char *path, char *bpath, int32 incall, int32 level)
5271 {
5272  char dirstr[RECLEN];
5273  char str[RECLEN];
5274  char str2[RECLEN];
5275  char *cp;
5276  struct xpndfile_t *xfp;
5277  struct dirent *dir;
5278  DIR *dp;
5279 #if defined(__CYGWIN32__) || defined(__SVR4)
5280  struct stat sbuf;
5281 #endif
5282 
5283  /* if it's null just add the ./ */
5284  if (path == NULL) { strcpy(str, "./"); cp = str; }
5285  else cp = path;
5286 
5287  xfp = xfp_hd;
5288  dp = NULL;
5289  for (; xfp != NULL; xfp = xfp->xpfnxt)
5290   {
5291    /* if the xfp->level is greater than the current level return */
5292    if (xfp->level > level) return;
5293    if ((dp = opendir(cp)) == NULL)
5294     {
5295      __pv_ferr(3569, "in config libary file %s cannot open dir %s : %s\n",
5296       lbep->lbefnam, cp, strerror(errno));
5297      return;
5298     }
5299    while ((dir = readdir(dp)) != NULL)
5300     {
5301      if (dir->d_ino == 0) continue;
5302      if (strcmp(dir->d_name, ".") == 0) continue;
5303      /* handle directories */
5304 #if defined(__CYGWIN32__) || defined(__SVR4)
5305      if (stat(dir->d_name, &sbuf) == -1) continue;
5306      if ((S_IFMT & sbuf.st_mode) == S_IFDIR)
5307 #else
5308      if (dir->d_type == DT_DIR)
5309 #endif
5310       {
5311        /* if not include all and it matches the wildcard go to next dir */
5312        if (!incall && match_wildcard_str(dir->d_name, xfp))
5313         {
5314          /* path is null copy else concat dir name */
5315          if (path == NULL) sprintf(dirstr, "%s", dir->d_name);
5316          else sprintf(dirstr, "%s/%s", path, dir->d_name);
5317          /* if include all (end's in /) include all files of dir */
5318          if (xfp->incall)
5319           {
5320            match_dir_pats(lbep, xfp, dirstr, bpath, TRUE, level + 1);
5321           }
5322          else
5323           {
5324            match_dir_pats(lbep, xfp->xpfnxt, dirstr, bpath, incall,
5325             level + 1);
5326           }
5327          /* if no wildcard and doesn't end in / return */
5328          if (!xfp->wildcard && !xfp->incall) return;
5329         }
5330       }
5331 #if defined(__CYGWIN32__) || defined(__SVR4)
5332      else if ((S_IFMT & sbuf.st_mode) == S_IFREG)
5333 #else
5334      else if (dir->d_type == DT_REG)
5335 #endif
5336       {
5337        /* handle files */
5338        /* if not include all in current directory */
5339        if (!incall)
5340         {
5341          /* if another pattern to macth or pattern ends in / continue */
5342          if (xfp->xpfnxt != NULL || xfp->incall) continue;
5343 
5344          /* if doesn't match the wildcard continue */
5345          if (!match_wildcard_str(dir->d_name, xfp)) continue;
5346         }
5347        /* if it gets here include the file */
5348        if (path == NULL) sprintf(str, "%s", dir->d_name);
5349        else sprintf(str, "%s/%s", cp, dir->d_name);
5350        if (bpath != NULL)
5351         {
5352          sprintf(str2, "%s/%s", bpath, str);
5353          expand_libel(lbep, str2);
5354         }
5355        else expand_libel(lbep, str);
5356       }
5357     }
5358   }
5359  if (dp != NULL) closedir(dp);
5360 }
5361 
5362 /*
5363  * routine to return T if a wildcard pattern matches a file name
5364  * matches '...', '*', '?'
5365  * or file name with any of the wild chars
5366  */
match_wildcard_str(char * file,struct xpndfile_t * xfp)5367 static int32 match_wildcard_str(char *file, struct xpndfile_t *xfp)
5368 {
5369  int32 fndx, pndx, flen, plen;
5370  int32 ondx, wildcard;
5371  char *opat, *patp, *filep;
5372 
5373  patp = xfp->fpat;
5374  wildcard = xfp->wildcard;
5375  /* if hier include all patterns */
5376  if (wildcard == HIER || strcmp(patp, "*") == 0) return(TRUE);
5377 
5378  /* if string is an exact match return true */
5379  if (strcmp(file, patp) == 0) return(TRUE);
5380  /* if it doesn't have a wildcard return */
5381  if (!xfp->wildcard) return(FALSE);
5382 
5383  flen = strlen(file);
5384  plen = strlen(patp);
5385 
5386  /* special case if it has a star at the end match exact file - start */
5387  if (wildcard == STAR && flen == plen - 1 && xfp->fpat[plen-1] == '*')
5388   {
5389    if (strncmp(file, xfp->fpat, flen) == 0) return(TRUE);
5390   }
5391  filep = file;
5392  fndx = ondx = 0;
5393  /* skip the regular characters */
5394  while (*patp != '?' && *patp != '*')
5395   {
5396    if (*filep != *patp) return(FALSE);
5397    filep++;
5398    patp++;
5399    fndx++;
5400    ondx++;
5401   }
5402 
5403  /* reset used for * can to reset to location of last special char */
5404  opat = patp;
5405 
5406 reset:
5407  patp = opat;
5408  pndx = ondx;
5409  for (; fndx < flen && pndx < plen; fndx++, pndx++, filep++, patp++)
5410   {
5411    /* if strings are equal or '?' goto the next char */
5412    if (*filep == *patp || *patp == '?') continue;
5413    else if (*patp == '*')
5414     {
5415      /* special case the \*\*\?\?  */
5416      if (*(patp + 1) == '?')
5417       {
5418        opat = (patp + 1);
5419        ondx = pndx + 1;
5420        patp++;
5421        pndx++;
5422        while (*patp == '?' && pndx < plen && fndx < flen)
5423         { fndx++, pndx++, filep++, patp++; }
5424        /* matching chars return */
5425        if (pndx == plen) return(TRUE);
5426        goto reset;
5427       }
5428      opat = patp; ondx = pndx;
5429      /* if a star case just move pattern to next char */
5430      while (*patp == '*' && pndx < plen)
5431       {
5432        patp++; pndx++;
5433       }
5434      if (pndx == plen) return(TRUE);
5435 
5436      /* if a qmark just continue and match the next char */
5437      if (*patp == '?') continue;
5438 
5439      /* while not equal move file forward */
5440      while (fndx < flen && *filep != *patp)
5441       { filep++; fndx++; }
5442 
5443      /* reached the end without finding an equal char */
5444      if (fndx == flen &&  *filep != *patp) return(FALSE);
5445      if (*filep != *patp && fndx < flen){filep++; fndx++; goto reset; }
5446     }
5447    /* if not eq, '?', or '*' doesn't match*/
5448    else if (fndx < flen && wildcard == STAR) goto reset;
5449    else return(FALSE);
5450   }
5451  if (fndx < flen && wildcard == STAR) goto reset;
5452  /* if string reaches the end it is a match */
5453  if (flen == fndx)
5454   {
5455    if (pndx == plen) return(TRUE);
5456    /* special case patp ends in the '*' */
5457    else if (pndx == plen - 1 && *patp == '*') return(TRUE);
5458   }
5459  return(FALSE);
5460 }
5461 
5462 /*
5463  * expand the lib element
5464  */
expand_libel(struct libel_t * lbep,char * file)5465 static void expand_libel(struct libel_t *lbep, char *file)
5466 {
5467  struct libel_t *newlbp;
5468 
5469  /* if F replace the pattern name with the expanded file name */
5470  if (!lbep->expanded)
5471   {
5472    /* only rename/free if it isn't the orginal string */
5473    /* there is no wildcard so the same stays the same */
5474    if (lbep->lbefnam != NULL)
5475     {
5476      __my_free(lbep->lbefnam, strlen(lbep->lbefnam) + 1);
5477      lbep->lbefnam = (char *) __pv_stralloc(file);
5478     }
5479    lbep->expanded = TRUE;
5480   }
5481  else
5482   {
5483    /* link on a new expanded file name  */
5484    newlbp = (struct libel_t *) __my_malloc(sizeof(struct libel_t));
5485    memcpy(newlbp, lbep, sizeof(struct libel_t));
5486    newlbp->lbefnam = (char *) __pv_stralloc(file);
5487    lbep->lbenxt = newlbp;
5488    lbep = newlbp;
5489    lbep->expanded = TRUE;
5490   }
5491 }
5492 
5493 /*
5494  * return to expand all patterns underneath hierarchy
5495  *
5496  * if pattern is only '...' return all files below the current path
5497  * recursively calls itself returning all files
5498  */
expand_single_hier(struct cfglib_t * lbp,struct libel_t * lbep,char * path)5499 static int32 expand_single_hier(struct cfglib_t *lbp, struct libel_t *lbep,
5500  char *path)
5501 {
5502  int32 count;
5503  char str[RECLEN];
5504  char dirstr[RECLEN];
5505  char *cp;
5506  DIR *dp;
5507  struct dirent *dir;
5508 #if defined(__CYGWIN32__) || defined(__SVR4)
5509  struct stat sbuf;
5510 #endif
5511 
5512  if (path == NULL) { strcpy(str, "."); cp = str; }
5513  else cp = path;
5514 
5515  count = 0;
5516  if ((dp = opendir(cp)) == NULL)
5517   {
5518    __pv_ferr(3569, "in config libary %s cannot open dir %s : %s\n",
5519     lbp->lbname, cp, strerror(errno));
5520    return(0);
5521   }
5522  while ((dir = readdir(dp)) != NULL)
5523   {
5524    if (dir->d_ino == 0) continue;
5525    if (strcmp(dir->d_name, ".") == 0) continue;
5526    if (strcmp(dir->d_name, "..") == 0) continue;
5527 #if defined(__CYGWIN32__) || defined(__SVR4)
5528    if (stat(dir->d_name, &sbuf) == -1) continue;
5529    if ((S_IFMT & sbuf.st_mode) == S_IFDIR)
5530 #else
5531    if (dir->d_type == DT_DIR)
5532 #endif
5533     {
5534      if (path == NULL) sprintf(dirstr, "./%s", dir->d_name);
5535      else sprintf(dirstr, "%s/%s", path, dir->d_name);
5536      expand_single_hier(lbp, lbep, dirstr);
5537     }
5538 #if defined(__CYGWIN32__) || defined(__SVR4)
5539    else if ((S_IFMT & sbuf.st_mode) == S_IFREG)
5540 #else
5541    else if (dir->d_type == DT_REG)
5542 #endif
5543     {
5544      str[0] ='\0';
5545      if (path == NULL) sprintf(str, "%s", dir->d_name);
5546      else sprintf(str, "%s/%s", cp, dir->d_name);
5547      count++;
5548      expand_libel(lbep, str);
5549     }
5550   }
5551  if (dp != NULL) closedir(dp);
5552  return(count);
5553 }
5554 
5555 /*
5556  * ROUTINES TO READ CFG LIBRARY SPECIFIED VERILOG SOURCE
5557  */
5558 
5559 /*
5560  * read and bind cells as directed by previously read  config block
5561  *
5562  * reads cfg design statement and then read libraries according to cfg rules
5563  * user must not give and .v files on command line
5564  */
__rd_ver_cfg_src(void)5565 extern void __rd_ver_cfg_src(void)
5566 {
5567  register struct cfg_t *cfgp;
5568 
5569  /* SJM 05/18/04 - LOOKATME - why doesn't this test work? */
5570  /* ### if (__last_inf != __cmd_ifi) __misc_terr(__FILE__, __LINE__); */
5571 
5572  prep_cfg_vflist();
5573 
5574  if (__cfg_verbose) dump_config_info();
5575 
5576  for (cfgp = __cfg_hd; cfgp != NULL; cfgp = cfgp->cfgnxt)
5577   {
5578    if (__cfg_verbose)
5579        __cv_msg("BINDING RULES IN CONFIG %s \n",  cfgp->cfgnam);
5580    bind_cfg_design(cfgp, FALSE);
5581   }
5582 
5583  /* AIV 05/24/04 - free and link out of mod list all cfg lib modules */
5584  /* that are in scanned files but never instantiated */
5585  free_unused_cfgmods();
5586 }
5587 
5588 /*
5589  * cfg verbose routine to dump names of expanded library files
5590  */
dump_lib_expand(void)5591 static void dump_lib_expand(void)
5592 {
5593  struct cfglib_t *lbp;
5594  struct libel_t *lbep;
5595 
5596  __cv_msg("  Library expasion file names:\n");
5597  for (lbp = __cfglib_hd; lbp != NULL; lbp = lbp->lbnxt)
5598   {
5599    __cv_msg("  Libname %s\n", lbp->lbname);
5600    for (lbep = lbp->lbels; lbep != NULL; lbep = lbep->lbenxt)
5601     {
5602      __cv_msg("    %s\n", lbep->lbefnam);
5603     }
5604   }
5605 }
5606 
dump_config_info(void)5607 static void dump_config_info(void)
5608 {
5609  char typ[RECLEN];
5610  struct cfg_t *cfgp;
5611  struct cfgdes_t *desp;
5612  struct cfgrule_t *rulp;
5613  struct cfgnamlst_t *cnlp;
5614 
5615  __cv_msg("\n  DUMPING CONFIG INFORMAION:\n");
5616  dump_lib_expand();
5617  for (cfgp = __cfg_hd; cfgp != NULL; cfgp = cfgp->cfgnxt)
5618   {
5619    __cv_msg("    Config %s in %s lineno %d \n", cfgp->cfgnam, cfgp->cfg_fnam,
5620     cfgp->cfg_lno);
5621 
5622    /* dump design info */
5623    for (desp = cfgp->cfgdeslist; desp != NULL; desp = desp->desnxt)
5624     {
5625      __cv_msg("      Design %s \n", desp->deslbnam);
5626     }
5627 
5628    /* dump rule default info */
5629    if (cfgp->cfgdflt != NULL) __cv_msg("    Default rule:\n");
5630    rulp = cfgp->cfgdflt;
5631    for (cnlp = rulp->rul_libs; cnlp != NULL; cnlp = cnlp->cnlnxt)
5632     {
5633      __cv_msg("      %s \n", cnlp->nam);
5634     }
5635 
5636    /* dump rule info */
5637    for (rulp = cfgp->cfgrules; rulp != NULL; rulp = rulp->rulnxt)
5638     {
5639      __cv_msg("    Rule \n");
5640      if (rulp->rultyp == CFG_INSTANCE)
5641         strcpy(typ, "Instance");
5642      else
5643         strcpy(typ, "Cell");
5644      if (rulp->use_rule_cfg)
5645        __cv_msg("      %s %s using hierarchical config : %s\n",
5646          typ, rulp->objnam, rulp->rul_use_celnam);
5647      else if (rulp->is_use)
5648         __cv_msg("      %s %s use %s.%s\n", rulp->objnam,
5649           typ, rulp->rul_use_libnam, rulp->rul_use_celnam);
5650      else
5651       {
5652        __cv_msg("      %s %s liblist:\n", typ, rulp->objnam);
5653        for (cnlp = rulp->rul_libs; cnlp != NULL; cnlp = cnlp->cnlnxt)
5654         {
5655          __cv_msg("       %s \n", cnlp->nam);
5656         }
5657       }
5658     }
5659   }
5660  __cv_msg("  END CONFIG DUMP\n\n");
5661 }
5662 
5663 /*
5664  * prepare the cfg input file stack - never more than one cfg lib file
5665  *
5666  * but macro expansions and `include put on top of stack so still needed
5667  * this puts one open file struct on tos and inits vinstk
5668  */
prep_cfg_vflist(void)5669 static void prep_cfg_vflist(void)
5670 {
5671  register int32 fi;
5672 
5673  __last_lbf = __last_inf;
5674  /* set open file/macro exp./include stack to empty */
5675  for (fi = 0; fi < MAXFILNEST; fi++) __vinstk[fi] = NULL;
5676  __vin_top = -1;
5677  __lasttoktyp = UNDEF;
5678  __last_attr_prefix = FALSE;
5679  /* this builds the empty top of stack entry */
5680  __push_vinfil();
5681  __cur_infi = __last_inf;
5682 }
5683 
5684 /*
5685  * build error message if the module didn't match any in the
5686  * given library
5687  */
build_rule_error(struct cfg_t * cfgp,struct cfglib_t * cntxt_lbp,struct cfgrule_t * rulp)5688 static void build_rule_error(struct cfg_t *cfgp, struct cfglib_t *cntxt_lbp,
5689  struct cfgrule_t *rulp)
5690 {
5691 
5692  /* if this didn't match there is no such instance */
5693  if (rulp->rultyp == CFG_INSTANCE)
5694   {
5695    __pv_err(3576, "config %s at %s: unable to bind rule - no such module %s",
5696     cfgp->cfgnam, __cfg_lineloc(__xs, cfgp->cfg_fnam, rulp->rul_lno),
5697     rulp->objnam);
5698   }
5699  else if (rulp->rultyp == CFG_CELL)
5700   {
5701    if (rulp->libnam != NULL)
5702     {
5703      /* no such library cell */
5704      __pv_err(3576,
5705       "config %s at %s: unable to bind rule - no such cell %s",
5706       cfgp->cfgnam, __cfg_lineloc(__xs, cfgp->cfg_fnam, rulp->rul_lno),
5707       rulp->objnam);
5708     }
5709   }
5710 }
5711 
5712 /*
5713  * read source of and parse all cells in a design
5714  *
5715  * SJM 01/09/04 FIXME ??? - must allow more than one top level design mod
5716  */
bind_cfg_design(struct cfg_t * cfgp,int32 is_hier)5717 static int32 bind_cfg_design(struct cfg_t *cfgp, int32 is_hier)
5718 {
5719  register struct cfgdes_t *desp;
5720  register struct cfgrule_t *rulp;
5721  struct cfglib_t *lbp;
5722  struct mod_t *mdp;
5723 
5724  if (is_hier)
5725   {
5726    if (cfgp->cfgdeslist == NULL || cfgp->cfgdeslist->desnxt != NULL)
5727     {
5728      __pv_err(3571,
5729       "hierarchical config %s at %s - only one design statement allowed",
5730       cfgp->cfgnam, __cfg_lineloc(__xs, cfgp->cfg_fnam, cfgp->cfg_lno));
5731      return(FALSE);
5732     }
5733   }
5734 
5735  for (desp = cfgp->cfgdeslist; desp != NULL; desp = desp->desnxt)
5736   {
5737    if (desp->deslbnam == NULL)
5738     {
5739      /* SJM 01/09/04 - FIXME - need to use default rule */
5740      __pv_err(3571, "config %s at %s: design library name missing",
5741       cfgp->cfgnam, __cfg_lineloc(__xs, cfgp->cfg_fnam, cfgp->cfg_lno));
5742 
5743      /* --- DBG remove -- */
5744      __misc_terr(__FILE__, __LINE__);
5745      /* --- */
5746     }
5747 
5748    if ((lbp = find_cfglib(desp->deslbnam)) == NULL)
5749     {
5750      __pv_err(3572, "config %s at %s: unable to find design library %s",
5751       cfgp->cfgnam, __cfg_lineloc(__xs, cfgp->cfg_fnam, cfgp->cfg_lno),
5752       desp->deslbnam);
5753      continue;
5754     }
5755    desp->deslbp = lbp;
5756 
5757    /* find the top level module in library lbp and parse source of file it */
5758    /* is in - normally will be in file by itself */
5759 
5760    /* SJM 01/13/04 - may not be top mod but from config view work down */
5761    /* design modules can be non top mods (instantiated somewhere) but */
5762    /* that just works because sub tree just gets bound */
5763    /* SJM 01/13/04 - FIXME - but that means inst and type names must be same */
5764    if (desp->topmodnam == NULL)
5765     {
5766      __pv_err(3573,
5767       "config %s at %s: top level design module name missing - for design lib %s",
5768       cfgp->cfgnam, __cfg_lineloc(__xs, cfgp->cfg_fnam, cfgp->cfg_lno),
5769       desp->deslbnam);
5770      continue;
5771     }
5772 
5773    if ((mdp = find_cell_in_cfglib(desp->topmodnam, lbp)) == NULL)
5774     {
5775      __pv_err(3574,
5776       "config %s at %s: unable to find design top level module %s in library %s",
5777       cfgp->cfgnam, __cfg_lineloc(__xs, cfgp->cfg_fnam, cfgp->cfg_lno),
5778       desp->topmodnam, desp->deslbnam);
5779      continue;
5780     }
5781 
5782    /* can't use undef hd list because only undef inst mod types from */
5783    /* the one design top mod added - rest of the mods must be read and */
5784    /* parsed but there cells can't be added to undef list */
5785 
5786    /* free undef list added from reading one config top level module */
5787    free_undef_list();
5788 
5789    __last_bind_comp_ndx = 0;
5790    __bind_inam_comptab[0] = __pv_stralloc(mdp->msym->synam);
5791 
5792    /* SJM 05/18/04 - binding of mdp uses current cfg library */
5793    mdp->mod_cfglbp = lbp;
5794 
5795    /* AIV rare case with instance/cell rules but no undefined mods */
5796    /* that means rules are not matched */
5797    if (mdp->mcells == NULL)
5798     {
5799      for (rulp = cfgp->cfgrules; rulp != NULL; rulp = rulp->rulnxt)
5800       {
5801        /* just warn because no cells need mapping */
5802        /* AIV LOOKATME message can msym be NULL here ?? */
5803        __pv_warn(3122,
5804         "config %s at %s: unable to bind rule - no modules to map in design %s module %s",
5805         cfgp->cfgnam, __cfg_lineloc(__xs, cfgp->cfg_fnam, rulp->rul_lno),
5806         desp->deslbnam, mdp->msym != NULL ? mdp->msym->synam : "undefined");
5807       }
5808     }
5809    else
5810     {
5811      bind_cells_in1mod(cfgp, desp->deslbp, mdp);
5812      /* emit errors for hierarchical paths in rules that do not exist */
5813      for (rulp = cfgp->cfgrules; rulp != NULL; rulp = rulp->rulnxt)
5814       {
5815        if (!rulp->matched)
5816         {
5817          build_rule_error(cfgp, desp->deslbp, rulp);
5818         }
5819       }
5820     }
5821    /* DBG remove -- */
5822    if (__last_bind_comp_ndx > 0) __misc_terr(__FILE__, __LINE__);
5823    /* -- */
5824    __my_free(__bind_inam_comptab[0], strlen(__bind_inam_comptab[0]) + 1);
5825    __last_bind_comp_ndx = -1;
5826   }
5827  return(TRUE);
5828 }
5829 
5830 /*
5831  * build a **<file>(<line. no.) reference for config where in fils not used
5832  * this chops file name so know will fit
5833  * s must be at least RECLEN wide
5834  */
__cfg_lineloc(char * s,char * fnam,int32 fnlcnt)5835 extern char *__cfg_lineloc(char *s, char *fnam, int32 fnlcnt)
5836 {
5837  char s1[RECLEN];
5838 
5839  sprintf(s, "**%s(%d)", __schop(s1, fnam), fnlcnt);
5840  return(s);
5841 }
5842 
5843 /*
5844  * find a library by name
5845  */
find_cfglib(char * lbnam)5846 static struct cfglib_t *find_cfglib(char *lbnam)
5847 {
5848  struct cfglib_t *lbp;
5849 
5850  for (lbp = __cfglib_hd; lbp != NULL; lbp = lbp->lbnxt)
5851   {
5852    if (strcmp(lbp->lbname, lbnam) == 0) return(lbp);
5853   }
5854  return(NULL);
5855 }
5856 
5857 /*
5858  * free (empty) undef list
5859  *
5860  * because config file reading requires parsing all modules in any file
5861  * read, can't use undef hd list - must scan cells and resolve
5862  * from mcells whose mod type symbol is syundefmod
5863  */
free_undef_list(void)5864 static void free_undef_list(void)
5865 {
5866  struct undef_t *undefp, *undefp2;
5867 
5868  /* final step is to free temp undef list */
5869  for (undefp = __undefhd; undefp != NULL;)
5870   {
5871    undefp2 = undefp->undefnxt;
5872    __my_free((char *) undefp, sizeof(struct undef_t));
5873    undefp = undefp2;
5874   }
5875  /* SJM 02/24/05 - must set tail to nil too */
5876  __undefhd = __undeftail = NULL;
5877 }
5878 
5879 /*
5880  * ROUTINES TO BIND CELLS
5881  */
5882 
5883 /*
5884  * bind all cells inside one already bound module
5885  */
bind_cells_in1mod(struct cfg_t * cfgp,struct cfglib_t * cntxt_lbp,struct mod_t * mdp)5886 static void bind_cells_in1mod(struct cfg_t *cfgp, struct cfglib_t *cntxt_lbp,
5887  struct mod_t *mdp)
5888 {
5889  register struct cfgrule_t *rulp;
5890  register struct libel_t *lbep;
5891  int32 cell_matched;
5892  struct cell_t *cp;
5893  struct sy_t *lbsyp;
5894  char *mnp;
5895 
5896  mdp->cfg_scanned = TRUE;
5897  for (cp = mdp->mcells; cp != NULL; cp = cp->cnxt)
5898   {
5899    if (!cp->cmsym->syundefmod) continue;
5900    cell_matched = FALSE;
5901    for (rulp = cfgp->cfgrules; rulp != NULL; rulp = rulp->rulnxt)
5902     {
5903      if (!try_match_rule(cntxt_lbp, cp, rulp)) continue;
5904 
5905      if (__cfg_verbose)
5906       {
5907        __cv_msg("  ** Rule matched for instance: %s (%s:%s) for rule config file: %s at line %d.\n\n",
5908         cp->csym->synam, __in_fils[cp->cmsym->syfnam_ind],
5909         mdp->msym->synam, cfgp->cfg_fnam, rulp->rul_lno);
5910       }
5911 
5912      if (cell_matched)
5913       {
5914        __pv_warn(3123, "config %s at %s: overriding previous defined matching rule(s)",
5915         cfgp->cfgnam, __cfg_lineloc(__xs, cfgp->cfg_fnam, rulp->rul_lno));
5916       }
5917 
5918      /* SJM 05/18/04 - cells inside bound to this lib (for %l) */
5919      mdp->mod_cfglbp = cntxt_lbp;
5920 
5921      cell_matched = TRUE;
5922      /* if it gets here the module exists so mark as TRUE */
5923      rulp->matched = TRUE;
5924      if (!rulp->is_use)
5925       {
5926        if (!bind_liblist_rule(cfgp, cp, rulp))
5927         {
5928          /* AIV 06/01/04 - FIXME should print out the entire liblist */
5929          /* unable to match type of the ins mod in the specified library */
5930          __pv_err(3577,
5931           "config %s at %s: unable to bind instance rule - module type (%s) never found in liblist (line number %d)",
5932           cfgp->cfgnam, __cfg_lineloc(__xs, cfgp->cfg_fnam, rulp->rul_lno),
5933           cp->cmsym->synam, rulp->rul_lno);
5934         }
5935       }
5936      else if (!bind_use_rule(cfgp, cntxt_lbp, cp, rulp))
5937       {
5938        /* Unable to match the use type of the mod in the specified lib */
5939        __pv_err(3578, "config %s at %s: unable to bind use rule - module type (%s) never found in library (%s)",
5940        cfgp->cfgnam, __cfg_lineloc(__xs, cfgp->cfg_fnam, rulp->rul_lno),
5941        cp->cmsym->synam, rulp->objnam);
5942       }
5943       goto nxt_cell;
5944     }
5945 
5946    /* AIV if a file read via a rule, and in the file it contains mod 'foo' */
5947    /* it must also bind the 'foo' in the file without a rule */
5948    /* AIV LOOKATME ### ??? - is there a better way to do this */
5949    /* get the current file name */
5950    if (mdp->mod_last_ifi == - 1) goto nxt_cell;
5951    mnp = __in_fils[mdp->mod_last_ifi];
5952    for (lbep = cntxt_lbp->lbels; lbep != NULL; lbep = lbep->lbenxt)
5953     {
5954      /* match the name of the expanded library file name */
5955      if (strcmp(lbep->lbefnam, mnp) == 0)
5956       {
5957        /* find the symbol to be bound in the library symbol table */
5958        if ((lbsyp = __get_sym(cp->cmsym->synam, lbep->lbel_sytab)) != NULL)
5959         {
5960          /* bind the cell symbols */
5961          cp->cmsym = lbsyp;
5962          cp->cmsym->cfg_needed = TRUE;
5963 
5964          if (__cfg_verbose)
5965           {
5966            __cv_msg("  ++ Bound in config: %s\n      instance: %s (%s:%s) bound to cell: %s in module: %s from file: %s in library: %s (SCANNED).\n\n",
5967             cfgp->cfgnam, cp->csym->synam, __in_fils[cp->csym->syfnam_ind],
5968             cp->cmsym->synam, lbsyp->synam, mdp->msym->synam,
5969             mnp, cntxt_lbp->lbname);
5970            }
5971           /* cells inside bound to this lib (for %l) */
5972           cp->cmsym->el.emdp->mod_cfglbp = cntxt_lbp;
5973 
5974           /* if a module the unconnected module could have mods */
5975           /* that need to be connected as well  */
5976           /* if the connecting cell hasn't been sanned and is mod check it */
5977           if (!cp->cmsym->el.emdp->cfg_scanned && cp->cmsym->sytyp == SYM_M
5978            && mdp->mcells != NULL)
5979            {
5980             if (__cfg_verbose)
5981              {
5982               __cv_msg("Binding cells in module: %s in file: %s.\n",
5983                mdp->msym->synam, mnp);
5984              }
5985             if (++__last_bind_comp_ndx >= __siz_bind_comps) grow_bind_comps();
5986             __bind_inam_comptab[__last_bind_comp_ndx] =
5987             __pv_stralloc(cp->csym->synam);
5988 
5989             /* bind cells in this one passing lib used to bind this one */
5990             bind_cells_in1mod(cfgp, cntxt_lbp, cp->cmsym->el.emdp);
5991 
5992             __my_free(__bind_inam_comptab[__last_bind_comp_ndx],
5993             strlen(__bind_inam_comptab[__last_bind_comp_ndx]) + 1);
5994             __last_bind_comp_ndx--;
5995            }
5996           goto nxt_cell;
5997          }
5998        }
5999      }
6000 
6001    /* must match rules in order */
6002    if ((rulp = cfgp->cfgdflt) != NULL)
6003     {
6004      /* notice default is always liblist form rule - never use form */
6005      if (bind_liblist_rule(cfgp, cp, rulp)) goto nxt_cell;
6006     }
6007    /* error message if cound not bind cell */
6008    __pv_err(3575,
6009     "config %s at %s: unable to bind cell %s (instance %s) (current lib %s in file %s:%d) - no rule matches",
6010     cfgp->cfgnam, __cfg_lineloc(__xs, cfgp->cfg_fnam, cfgp->cfg_lno),
6011     cp->cmsym->synam, cp->csym->synam, cntxt_lbp->lbname,
6012      __in_fils[cp->csym->syfnam_ind], cp->csym->sylin_cnt);
6013 
6014    nxt_cell:;
6015   }
6016 }
6017 
6018 /*
6019  * routine to attempt to match one rule and return T if matches
6020  * does not bind
6021  */
try_match_rule(struct cfglib_t * cntxt_lbp,struct cell_t * cp,struct cfgrule_t * rulp)6022 static int32 try_match_rule(struct cfglib_t *cntxt_lbp, struct cell_t *cp,
6023  struct cfgrule_t *rulp)
6024 {
6025  register int32 ci;
6026 
6027  if (rulp->rultyp == CFG_INSTANCE)
6028   {
6029    /* match inst */
6030    if (!cp->c_named) return(FALSE);
6031 
6032    if (strcmp(cp->csym->synam, rulp->inam_comptab[rulp->inam_comp_lasti])
6033     != 0) return(FALSE);
6034 
6035    /* if instance path length from config design root different */
6036    /* then can't match */
6037    if (__last_bind_comp_ndx + 1 != rulp->inam_comp_lasti) return(FALSE);
6038 
6039    for (ci = __last_bind_comp_ndx; ci >= 0; ci--)
6040     {
6041      if (strcmp(__bind_inam_comptab[ci], rulp->inam_comptab[ci]) != 0)
6042       return(FALSE);
6043     }
6044    return(TRUE);
6045   }
6046  else if (rulp->rultyp == CFG_CELL)
6047   {
6048    if (rulp->libnam != NULL && rulp->libnam[0] != '\0')
6049     {
6050      if (strcmp(rulp->libnam, cntxt_lbp->lbname) != 0) return(FALSE);
6051     }
6052    if (strcmp(cp->cmsym->synam, rulp->objnam) == 0) return(TRUE);
6053   }
6054  return(FALSE);
6055 }
6056 
6057 /*
6058  * bind instance rule with liblist clause - return T if succeeds else F
6059  */
bind_liblist_rule(struct cfg_t * cfgp,struct cell_t * cp,struct cfgrule_t * rulp)6060 static int32 bind_liblist_rule(struct cfg_t *cfgp, struct cell_t *cp,
6061  struct cfgrule_t *rulp)
6062 {
6063  struct cfgnamlst_t *cnlp;
6064  struct cfglib_t *lbp;
6065  struct mod_t *bind_mdp;
6066  char s1[RECLEN];
6067 
6068  /* match every lib in lib list in order until find match or fail */
6069  for (cnlp = rulp->rul_libs; cnlp != NULL; cnlp = cnlp->cnlnxt)
6070   {
6071    /* find the current lib */
6072    if ((lbp = find_cfglib(cnlp->nam)) == NULL)
6073     {
6074      if (rulp->rultyp == CFG_DEFAULT)
6075        strcpy(s1, "default");
6076      else
6077        strcpy(s1, rulp->objnam);
6078 
6079      __pv_err(3571,
6080       "config %s at %s: binding object %s lib list clause library %s not found",
6081       cfgp->cfgnam, __cfg_lineloc(__xs, cfgp->cfg_fnam, cfgp->cfg_lno),
6082       s1, cnlp->nam);
6083      continue;
6084     }
6085 
6086    /* attempt to bind - cp is cell containing */
6087    if ((bind_mdp = find_cell_in_cfglib(cp->cmsym->synam, lbp)) == NULL)
6088     continue;
6089 
6090    /* AIV 05/18/04 - binding of mdp uses current cfg library */
6091    bind_mdp->mod_cfglbp = lbp;
6092 
6093    /* this does the binding */
6094    cp->cmsym = bind_mdp->msym;
6095    cp->cmsym->cfg_needed = TRUE;
6096 
6097    if (__cfg_verbose)
6098     {
6099      if (rulp->rultyp == CFG_DEFAULT)
6100        strcpy(s1, "default");
6101      else
6102        strcpy(s1, rulp->objnam);
6103       __cv_msg("  ++ Bound in config: %s\n      instance: %s (%s:%s) bound to cell: %s in library: %s (%s) (LIBLIST %s).\n\n",
6104          cfgp->cfgnam, cp->csym->synam, __in_fils[cp->cmsym->syfnam_ind],
6105          cp->cmsym->synam, bind_mdp->msym->synam,  lbp->lbname,
6106          __in_fils[bind_mdp->msym->syfnam_ind], s1);
6107     }
6108 
6109    /* bind cells inside */
6110    bind_cells_inside(cfgp, cp, bind_mdp, lbp);
6111    return(TRUE);
6112   }
6113  return(FALSE);
6114 }
6115 
6116 /*
6117  * bind use rule
6118  *
6119  * use clause - easy because [lib].cell explicitly given
6120  * SJM 01/14/03 - WRITEME - handle different cfg (:config)
6121  */
bind_use_rule(struct cfg_t * cfgp,struct cfglib_t * cntxt_lbp,struct cell_t * cp,struct cfgrule_t * rulp)6122 static int32 bind_use_rule(struct cfg_t *cfgp, struct cfglib_t *cntxt_lbp,
6123  struct cell_t *cp, struct cfgrule_t *rulp)
6124 {
6125  struct cfg_t *use_replace_cfgp;
6126  struct cfglib_t *lbp;
6127  struct mod_t *bind_mdp;
6128  struct sy_t *msyp;
6129 
6130  /* if use clause heirarchical config form find the config to use */
6131  if (rulp->use_rule_cfg)
6132   {
6133    if ((use_replace_cfgp = fnd_cfg_by_name(rulp->rul_use_celnam)) == NULL)
6134     {
6135      __pv_err(3579,
6136       "config %s at %s: hierichical use clause config name %s undefined - config not changed",
6137       cfgp->cfgnam, __cfg_lineloc(__xs, cfgp->cfg_fnam, cfgp->cfg_lno),
6138       rulp->rul_use_celnam);
6139     }
6140 
6141    if (bind_cfg_design(use_replace_cfgp, TRUE))
6142     {
6143      /* SJM 05/18/04 - BEWARE - assuming (and must check) only one */
6144      /* design statement for hierarchical sub configs */
6145      if ((msyp = __get_sym(use_replace_cfgp->cfgdeslist->topmodnam,
6146       __modsyms)) != NULL)
6147       cp->cmsym = msyp;
6148      cp->cmsym->cfg_needed = TRUE;
6149      if (__cfg_verbose)
6150       {
6151        __cv_msg("  ++ Bound in config: %s using hierarchical config: %s\n      binding instance: %s (%s:%s) bound to cell: %s (%s) (USE CLAUSE).\n\n",
6152        cfgp->cfgnam, use_replace_cfgp->cfgnam, cp->csym->synam,
6153        __in_fils[cp->cmsym->syfnam_ind], cp->cmsym->synam, msyp->synam,
6154         __in_fils[msyp->syfnam_ind]);
6155       }
6156     }
6157    return(TRUE);
6158   }
6159 
6160  if (rulp->rul_use_libnam == NULL || rulp->rul_use_libnam[0] == '\0')
6161   {
6162    lbp = cntxt_lbp;
6163   }
6164  else
6165   {
6166    if ((lbp = find_cfglib(rulp->rul_use_libnam)) == NULL)
6167     {
6168      __pv_err(3571,
6169       "config %s at %s: object %s use clause %s:%s library %s not found",
6170       cfgp->cfgnam, __cfg_lineloc(__xs, cfgp->cfg_fnam, cfgp->cfg_lno),
6171       rulp->objnam, rulp->rul_use_libnam, rulp->rul_use_celnam,
6172       rulp->rul_use_libnam);
6173      return(FALSE);
6174     }
6175   }
6176 
6177  /* use the rul_use ins name 'use lib.rul_use_celnam' */
6178  if ((bind_mdp = find_cell_in_cfglib(rulp->rul_use_celnam, lbp)) == NULL)
6179   {
6180     __pv_err(3573, "config %s at %s: object %s use clause %s.%s cell %s not found",
6181      cfgp->cfgnam, __cfg_lineloc(__xs, cfgp->cfg_fnam, cfgp->cfg_lno),
6182      rulp->objnam, lbp->lbname, rulp->rul_use_celnam,
6183      rulp->rul_use_celnam);
6184     return(FALSE);
6185    }
6186 
6187  /* bind the library name (%l) */
6188  bind_mdp->mod_cfglbp = lbp;
6189 
6190  /* found cell */
6191  cp->cmsym = bind_mdp->msym;
6192  cp->cmsym->cfg_needed = TRUE;
6193  if (__cfg_verbose)
6194   {
6195    __cv_msg("  ++ Bound in config: %s \n       binding instance: %s (%s:%s) bound to cell: %s in library: %s (%s) (USE CLAUSE).\n\n",
6196    cfgp->cfgnam, cp->csym->synam, __in_fils[cp->cmsym->syfnam_ind],
6197    cp->csym->synam, bind_mdp->msym->synam, lbp->lbname,
6198    __in_fils[bind_mdp->msym->syfnam_ind]);
6199   }
6200 
6201  /* bind cells inside */
6202  bind_cells_inside(cfgp, cp, bind_mdp, lbp);
6203  return(TRUE);
6204 }
6205 
6206 /*
6207  * find a config given a cfg name
6208  */
fnd_cfg_by_name(char * confnam)6209 static struct cfg_t *fnd_cfg_by_name(char *confnam)
6210 {
6211  register struct cfg_t *cfgp;
6212 
6213  for (cfgp = __cfg_hd; cfgp != NULL; cfgp = cfgp->cfgnxt)
6214   {
6215    if (strcmp(cfgp->cfgnam, confnam) == 0)
6216     {
6217      return(cfgp);
6218     }
6219   }
6220  return(NULL);
6221 }
6222 
6223 /*
6224  * after binding one cell bind cells depth first inside it
6225  */
bind_cells_inside(struct cfg_t * cfgp,struct cell_t * cp,struct mod_t * bind_mdp,struct cfglib_t * lbp)6226 static void bind_cells_inside(struct cfg_t *cfgp, struct cell_t *cp,
6227  struct mod_t *bind_mdp, struct cfglib_t *lbp)
6228 {
6229  if (++__last_bind_comp_ndx >= __siz_bind_comps) grow_bind_comps();
6230  __bind_inam_comptab[__last_bind_comp_ndx] = __pv_stralloc(cp->csym->synam);
6231 
6232  /* bind cells in this one passing library used to bind this one */
6233  bind_cells_in1mod(cfgp, lbp, bind_mdp);
6234 
6235  __my_free(__bind_inam_comptab[__last_bind_comp_ndx],
6236    strlen(__bind_inam_comptab[__last_bind_comp_ndx]) + 1);
6237  __last_bind_comp_ndx--;
6238 }
6239 
6240 /*
6241  * ROUTINE TO FIND A CFG CELL IN A LIBRARY AND FIRST PASS READ SRC
6242  */
6243 
6244 /*
6245  * find a cell in a config library list of cells
6246  *
6247  * if config library file compiled, find pre-fixup d.s module (cell)
6248  * else read all source in file and search for cell
6249  *
6250  * keeps reading until finding cell or reaching end of library file list
6251  * if any part of file is read all cells in file are read and put in
6252  * lib el's symbol table with ptr to mod pre-fixup d.s.
6253  */
find_cell_in_cfglib(char * celnam,struct cfglib_t * lbp)6254 static struct mod_t *find_cell_in_cfglib(char *celnam, struct cfglib_t *lbp)
6255 {
6256  register struct libel_t *lbep;
6257  struct sy_t *msyp;
6258 
6259  for (lbep = lbp->lbels; lbep != NULL; lbep = lbep->lbenxt)
6260   {
6261    if (!lbep->lbelsrc_rd)
6262     {
6263      /* move keep adding files read into in fils for error locations */
6264      if (++__last_lbf >= __siz_in_fils) __grow_infils(__last_lbf);
6265      __in_fils[__last_lbf] = __pv_stralloc(lbep->lbefnam);
6266 
6267      /* returns F and emits error if can't open llb file */
6268      if (!open_cfg_lbfil(lbp->lbname)) continue;
6269 
6270      rd_cfg_srcfil(lbep);
6271      lbep->lbelsrc_rd = TRUE;
6272     }
6273 
6274    /* AIV - 05/24/04 - the rare case there is no symbol table */
6275    /* if the source only contains `define, `tiemscale, etc, continue */
6276    if (lbep->lbel_sytab == NULL) continue;
6277    if ((msyp = __get_sym(celnam, lbep->lbel_sytab)) != NULL)
6278    {
6279     return(msyp->el.emdp);
6280    }
6281   }
6282  return(NULL);
6283 }
6284 
6285 /*
6286  * try to open the config library file and repl. top of stack with its info
6287  *
6288  * except for includes and macros size of vinstk will always be 1
6289  * file must be openable and have contents
6290  * return F on fail
6291  * in fils of last lbf must be filled with file name
6292  * since know last_lbf > last_inf - on EOF get_vtok will resturn to caller
6293  */
open_cfg_lbfil(char * lbnam)6294 static int32 open_cfg_lbfil(char *lbnam)
6295 {
6296  char dirstr[RECLEN];
6297 
6298  /* know called with last_lbf index of file to process */
6299  __cur_fnam = __in_fils[__last_lbf];
6300  /* AIV PUTBACK print directory for now - for debugging */
6301  if ((__in_s = __tilde_fopen(__cur_fnam, "r")) == NULL)
6302   {
6303    __pv_err(710, "cannot open config library %s file %s in dir : %s - skipped",
6304     lbnam, __cur_fnam,  getcwd(dirstr, RECLEN));
6305    return(FALSE);
6306   }
6307  if (feof(__in_s))
6308   {
6309    __pv_warn(512, "config library %s file %s empty", lbnam, __cur_fnam);
6310    return(FALSE);
6311   }
6312  /* whenever open new file must discard pushed back */
6313  __lasttoktyp = UNDEF;
6314  __visp->vi_s = __in_s;
6315  __visp->vifnam_ind = __last_lbf;
6316  __cur_fnam_ind = __last_lbf;
6317  __cur_fnam = __in_fils[__cur_fnam_ind];
6318  __lin_cnt = 1;
6319  __file_just_op = TRUE;
6320  if (__cfg_verbose)
6321   {
6322    __cv_msg("  Parsing config library %s file \"%s\".\n", lbnam, __cur_fnam);
6323   }
6324  return(TRUE);
6325 }
6326 
6327 /*
6328  * read cfg source file to find and elaborate current module
6329  *
6330  * read src and to lbel symbol table for every module in library
6331  */
rd_cfg_srcfil(struct libel_t * lbep)6332 static void rd_cfg_srcfil(struct libel_t *lbep)
6333 {
6334  __get_vtok();
6335  if (__toktyp == TEOF)
6336   {
6337    __pv_fwarn(609, "config library file %s contains no tokens",
6338     lbep->lbefnam);
6339    /* since empty, mark so not re-read */
6340    lbep->lbelsrc_rd = TRUE;
6341    return;
6342   }
6343 
6344  for (;;)
6345   {
6346    /* may be a compiler directive */
6347    if (__toktyp >= CDIR_TOKEN_START && __toktyp <= CDIR_TOKEN_END)
6348     {
6349      __process_cdir();
6350      goto nxt_tok;
6351     }
6352    switch ((byte) __toktyp) {
6353     case TEOF: return;
6354     case MACROMODULE:
6355      __get_vtok();
6356      __finform(423,
6357       "macromodules in config library not expanded - %s translated as module",
6358       __token);
6359      goto chk_name;
6360     case MODULE:
6361      __get_vtok();
6362 chk_name:
6363      if (__toktyp != ID)
6364       {
6365        __pv_ferr(707, "config library file module name expected - %s read",
6366         __prt_vtok());
6367        /* since error, just try to resynchronize */
6368        __vskipto_modend(ENDMODULE);
6369        goto nxt_tok;
6370       }
6371      if (!init_chk_cfg_sytab(lbep, "module"))
6372       {
6373        __vskipto_modend(ENDMODULE);
6374        goto nxt_tok;
6375       }
6376 
6377      /* know error here will cause skipping to file level thing */
6378      /* this adds mod name to lbel one file's symbol table */
6379      if (!__rd_moddef(lbep->lbel_sytab, TRUE)) goto nxt_tok;
6380 
6381      /* when reading source this was set only if in cell define region */
6382      /* now turn on (maybe again) if all library modules are cells */
6383      /* dummy itstk empty here but if good module read mark as cell */
6384      if (__lib_are_cells && __last_libmdp != NULL)
6385       {
6386        __last_libmdp->m_iscell = TRUE;
6387        __design_has_cells = TRUE;
6388       }
6389      __last_libmdp = NULL;
6390      /* know to get here 1 more resolved */
6391      break;
6392 
6393     case PRIMITIVE:
6394      __get_vtok();
6395      if (__toktyp != ID)
6396       {
6397        __pv_ferr(708,
6398         "config library file udp primitive name expected - %s read",
6399         __prt_vtok());
6400        /* since err, just try to skip to end primitive */
6401        __vskipto_modend(ENDPRIMITIVE);
6402        goto nxt_tok;
6403       }
6404      if (!init_chk_cfg_sytab(lbep, "udp primitive"))
6405       {
6406        __vskipto_modend(ENDPRIMITIVE);
6407        goto nxt_tok;
6408       }
6409 
6410      if (!__rd_udpdef(lbep->lbel_sytab)) goto nxt_tok;
6411      break;
6412     default:
6413      __pv_ferr(709,
6414      "config library file module, primitive or directive expected - %s read",
6415       __prt_vtok());
6416      /* here just ignores extra semicolons */
6417      if (__toktyp != SEMI) __vskipto2_modend(ENDMODULE, ENDPRIMITIVE);
6418    }
6419 nxt_tok:
6420    /* why checking this twice */
6421    if (__toktyp == TEOF)
6422     {
6423 chk_ifdef:
6424      if (__in_ifdef_level != 0)
6425       {
6426        __pv_err(924, "last `ifdef unterminated in config libary file %s",
6427         __cur_fnam);
6428       }
6429      break;
6430     }
6431    __get_vtok();
6432    if (__toktyp == TEOF) goto chk_ifdef;
6433   }
6434 }
6435 
6436 /*
6437  * check module/udp name and alloc lib el symbol table if needed
6438  * returns F on error
6439  */
init_chk_cfg_sytab(struct libel_t * lbep,char * celtyp)6440 static int32 init_chk_cfg_sytab(struct libel_t *lbep, char *celtyp)
6441 {
6442  struct sy_t *syp;
6443 
6444  /* if first mod in file, build the lbel's symbol table */
6445  if (lbep->lbel_sytab == NULL) lbep->lbel_sytab = __alloc_symtab(FALSE);
6446 
6447  /* check to see if name repeated in this library file */
6448  if ((syp = __get_sym(__token, lbep->lbel_sytab)) != NULL)
6449   {
6450    __pv_ferr(3474,
6451     "%s %s repeated in config library file %s - previous at %s",
6452     celtyp, syp->synam, lbep->lbefnam,
6453     __bld_lineloc(__xs, syp->syfnam_ind, syp->sylin_cnt));
6454    return(FALSE);
6455   }
6456 
6457  if (__lib_verbose)
6458   {
6459    __cv_msg("  Scanning config library %s %s (%s).\n",
6460     lbep->lbefnam, celtyp, __token);
6461   }
6462  return(TRUE);
6463 }
6464 
6465 /*
6466  * ROUTINES TO FREE COMPILED LIBRARY MODULE NEVER INSTANTIATED
6467  */
add_cfgsym(char * libnam,struct tnode_t * tnp)6468 static void add_cfgsym(char *libnam, struct tnode_t *tnp)
6469 {
6470  struct tnode_t *ntnp;
6471  char s1[RECLEN];
6472 
6473   if (tnp == NULL) return;
6474   add_cfgsym(libnam, tnp->lp);
6475 
6476   // AIV FIXME ??? sprintf(s1, "%s.%s", libnam, tnp->ndp->synam);
6477   if (tnp->ndp->cfg_needed)
6478    {
6479     strcpy(s1, tnp->ndp->synam);
6480     ntnp = __vtfind(s1, __modsyms);
6481    //AIV FIXME ###
6482     if (!__sym_is_new)
6483      {
6484       __fterr(305,
6485        "Sorry - config code to rename module with same name from different libraries not implemented yet.");
6486      }
6487     __add_sym(s1, ntnp);
6488     ntnp->ndp = tnp->ndp;
6489     strcpy(ntnp->ndp->synam, s1);
6490     ntnp->ndp->sydecl = TRUE;
6491     (__modsyms->numsyms)++;
6492    }
6493   add_cfgsym(libnam, tnp->rp);
6494 }
6495 
6496 
6497 /*
6498  * add all the used symbols from a config to __modsyms
6499  */
add_cfg_libsyms(struct cfglib_t * cfgp)6500 static void add_cfg_libsyms(struct cfglib_t *cfgp)
6501 {
6502  struct libel_t *lbp;
6503  struct symtab_t *symt;
6504  struct tnode_t *tnp;
6505  char *cp;
6506  int32 i;
6507 
6508 
6509  for (lbp = cfgp->lbels; lbp != NULL; lbp = lbp->lbenxt)
6510   {
6511    if ((symt = lbp->lbel_sytab) == NULL) continue;
6512    if (symt->stsyms != NULL)
6513     {
6514      for (i = 0; i < symt->numsyms; i++)
6515       {
6516        if (!symt->stsyms[i]->cfg_needed) continue;
6517        cp = symt->stsyms[i]->synam;
6518        tnp = __vtfind(cp, __modsyms);
6519       //AIV FIXME ###
6520        if (!__sym_is_new)
6521         {
6522          __fterr(305,
6523           "Sorry - config code to rename module with same name from different libraries not implemented yet.");
6524         }
6525        __add_sym(cp, tnp);
6526        (__modsyms->numsyms)++;
6527        tnp->ndp = symt->stsyms[i];
6528       }
6529     }
6530    else
6531     {
6532        add_cfgsym(cfgp->lbname, symt->n_head);
6533     }
6534   }
6535 }
6536 
6537 
6538 /*
6539  * removes all modules that were scanned in from config libraries
6540  * but are never needed remove from the __modhdr list
6541  */
free_unused_cfgmods(void)6542 static void free_unused_cfgmods(void)
6543 {
6544  struct mod_t *mdp, *mdp2, *last_mdp;
6545  long sav_mem_use;
6546 
6547 //AIV FIXME ### need to free
6548  __modsyms = NULL;
6549  __modsyms = __alloc_symtab(FALSE);
6550  __sym_addprims();
6551  sav_mem_use = __mem_use;
6552  last_mdp = NULL;
6553  for (mdp = __modhdr; mdp != NULL;)
6554   {
6555    mdp2 = mdp->mnxt;
6556 
6557    /* if module is from a config and hasn't been linked to a library rm */
6558    if (mdp->m_inconfig && mdp->mod_cfglbp == NULL)
6559     {
6560      /* SJM 05/28/04 FIXME ### ??? - need to do some freeing of libs */
6561      /* partially_free_mod(mdp); */
6562 
6563      if (last_mdp != NULL) last_mdp->mnxt = mdp2;
6564      mdp = mdp2;
6565      continue;
6566     }
6567    if (!mdp->mod_cfglbp->sym_added)
6568    {
6569      add_cfg_libsyms(mdp->mod_cfglbp);
6570      mdp->mod_cfglbp->sym_added = TRUE;
6571    }
6572    last_mdp = mdp;
6573    mdp = mdp2;
6574   }
6575  /* AIV 05/31/05 - FIXME ### if not freeing no need to print message */
6576  /*
6577  if (__cfg_verbose)
6578   {
6579    __cv_msg(
6580    "  Config freeing most memory in unused library modules - %ld bytes freed\n",
6581     sav_mem_use - __mem_use);
6582   }
6583   */
6584 }
6585 
6586 /*
6587  * partially free a module (just the larger parts such as stmts and cells)
6588  *
6589  * for now freeing most of the inisdes of modules that were parsed during
6590  * config library loading - eventually will moved to precompiled lib scheme
6591  * so this will be removed
6592  *
6593  * not free mdp but now nothing points to it
6594  *
6595  * SJM 05/26/04 - LOOKATME - since only free large d.s. in modules there is
6596  * quite a bit of memory leakage here
6597  */
partially_free_mod(struct mod_t * mdp)6598 static void partially_free_mod(struct mod_t *mdp)
6599 {
6600  register struct cell_t *cp, *cp2;
6601 
6602  for (cp = mdp->mcells; cp != NULL; )
6603   {
6604    cp2 = cp->cnxt;
6605    __my_free((char *) cp, sizeof(struct cell_t));
6606    cp = cp2;
6607   }
6608 
6609  /* SJM 05/26/04 - LOOKATME ??? ### can't free stmt until fixup ---
6610  struct ialst_t *ialp;
6611  struct task_t *tskp;
6612  for (ialp = mdp->ialst; ialp != NULL; ialp = ialp->ialnxt)
6613   {
6614    __free_stlst(ialp->iastp);
6615   }
6616 
6617  for (tskp = mdp->mtasks; tskp != NULL; tskp = tskp->tsknxt)
6618   {
6619    __free_stlst(tskp->tskst);
6620   }
6621  --- */
6622 
6623 }
6624