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