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  * input/output conversion and bit part selection mechanism routines
30  */
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <math.h>
36 #include <errno.h>
37 #include <ctype.h>
38 
39 #ifdef __DBMALLOC__
40 #include "../malloc.h"
41 #endif
42 #include "v.h"
43 #include "cvmacros.h"
44 
45 /* local prototypes */
46 static void disp_toexprline(register struct expr_t *, int32);
47 static char *sep_real_fmt(char *, char *, int32);
48 static void sdisph(word32 *, word32 *, int32, int32);
49 static char bitsto_char(word32, word32, int32);
50 static void sdispd(word32 *, word32 *, int32, int32, int32);
51 static char get_decxz(word32 *, word32 *, int32);
52 static int32 bld_tfmt_val(char *, struct expr_t *, word32 *, word32 *, int32,
53  int32, int32);
54 static void sdispo(word32 *, word32 *, int32, int32);
55 static void vstr_to_cstr(char *, int32, int32, int32, int32);
56 static void disp_ufmt_binval(word32 *, word32 *, int32);
57 static void disp_zfmt_binval(word32 *, word32 *, int32);
58 static void numexpr_disp(struct expr_t *, int32);
59 static void st_regab_disp(byte *, int32);
60 static void disp_stvar(struct net_t *, int32, int32);
61 static int32 get_ovrsign(struct net_t *, char);
62 static void dmp_arr_insts(struct net_t *, int32, int32);
63 static void dmp_arr(struct net_t *, int32, int32, int32);
64 static void dmp1n_nplst(struct mod_t *, struct net_t *, int32);
65 static int32 cnt_nplstels(register struct net_pin_t *);
66 static word32 get_dce_edgeval(struct mod_t *, struct dcevnt_t *);
67 static int32 bin_trim_abval(word32 *, word32 *, int32);
68 static int32 trim_abval(word32 *, word32 *, int32);
69 static int32 bithi_is0(word32, int32);
70 static int32 trim1_1val(word32 *, int32);
71 static int32 vval_isall_xs(word32 *, word32 *, int32);
72 static int32 vval_hasx(word32 *, word32 *, int32);
73 static long my_strtol(char *, char **, int32, int32 *);
74 static void dmp_dig_attr_list(FILE *, struct attr_t *, int32);
75 static void dmp_modports(FILE *, struct mod_t *);
76 static void dmp_mod_lofp_hdr(FILE *, struct mod_t *);
77 static void dmp_decls(FILE *, struct mod_t *);
78 static void dmp_1portdecl(FILE *, struct expr_t *);
79 static void dmp_1netdecl(FILE *, struct net_t *);
80 static int32 nd_iowirdecl(struct net_t *);
81 static void dmp_paramdecls(FILE *, struct net_t *, int32, char *);
82 static void dmp_defparams(FILE *, struct mod_t *);
83 static void dmp_mdtasks(FILE *, struct mod_t *);
84 static void dmp_insts(FILE *, struct mod_t *);
85 /* DBG */ static void dbg_dmp_insts(FILE *, struct mod_t *);
86 static void dmp_1inst(FILE *, struct inst_t *, struct giarr_t *);
87 /* DBG */ static void dbg_dmp_1inst(FILE *f, struct inst_t *ip, char *inam);
88 static void dmp_pnd_params(FILE *, struct inst_t *, struct mod_t *);
89 static int32 impl_pndparams(struct inst_t *, struct mod_t *);
90 static void dmp_iports(FILE *, struct inst_t *, struct expr_t **);
91 static void dmp_1gate(FILE *, struct gate_t *, struct giarr_t *);
92 /* DBG */ static void dbg_dmp_1gate(FILE *f, struct gate_t *gp, char *gnam);
93 static void dmp_1conta(FILE *, struct conta_t *);
94 static void dmp_1bitconta(FILE *, struct gate_t *);
95 static void dmp_ialst(FILE *, struct mod_t *);
96 static void dmp_case(FILE *, struct st_t *);
97 static void dmp_case_dflt(FILE *, struct csitem_t *);
98 static void dmp_fj_stlst(FILE *, struct st_t *);
99 static void dmp_task(FILE *, struct task_t *);
100 static void dmp_func_decl(FILE *, struct task_t *);
101 static void dmp_nblock(FILE *, struct task_t *, char *);
102 static void dmp_tfdecls(FILE *, struct task_t *);
103 static void dmp_tf_lofp_hdr(FILE *, struct task_t *);
104 static void dmp_mdspfy(FILE *, struct mod_t *);
105 static void dmp_specpths(FILE *, register struct spcpth_t *);
106 static void dmp_pthlst(FILE *, struct spcpth_t *, int32);
107 static void dmp_pthel(FILE *, struct pathel_t *);
108 static void dmp_tchks(FILE *, register struct tchk_t *);
109 static void dmp_tchk_selector(FILE *, word32, struct expr_t *,
110  struct expr_t *);
111 static void dmp_mod_grefs(FILE *, struct mod_t *);
112 static char *to_glbinfo(char *, struct gref_t *);
113 static void dmp_casesel(FILE *, struct st_t *);
114 static void dmp_delay(FILE *, union del_u, word32, char *);
115 static void dmp_dellst(FILE *, register struct paramlst_t *);
116 static void dmp_lstofsts(FILE *, struct st_t *);
117 static void tox_wrange(FILE *, struct expr_t *, struct expr_t *);
118 static void dmp_expr(FILE *, struct expr_t *);
119 static int32 is_simplex(struct expr_t *);
120 static void dmp_catexpr(FILE *, struct expr_t *);
121 static void dmp_catel(FILE *, struct expr_t *);
122 static void dmp_fcallx(FILE *, struct expr_t *);
123 static void dmp_evor_chain(FILE *, struct expr_t *);
124 static void sdisp_st(struct expr_t *);
125 static int32 find_deepest_level(struct optlst_t *);
126 static int32 cnt_beg_to_endmark(struct optlst_t *, int32);
127 static int32 cnt_level0(struct optlst_t *);
128 static void dump_vpi_argv(int32, char **);
129 static void dump_nest_vpi_argv(int32, char **);
130 static void dmp1_optlst(struct optlst_t *, char *);
131 
132 
133 /* extern prototypes defined elsewhere */
134 extern char *__my_realloc(char *, int32, int32);
135 extern char *__my_malloc(int32);
136 extern char *__mytf_malloc(int32);
137 extern char *__pv_stralloc(char *);
138 extern char *__msgexpr_tostr(char *, struct expr_t *);
139 extern char *__msgtox_wrange(char *, struct expr_t *, struct expr_t *);
140 extern char *__to_wtnam(char *, struct net_t *);
141 extern char *__to_wtnam2(char *, word32);
142 extern char *__to_ptnam(char *, word32);
143 extern char *__to_wrange(char *, struct net_t *);
144 extern char *__to_stren_nam(char *, int32, int32);
145 extern char *__to_stval_nam(char *, word32);
146 extern char *__to_opname(word32);
147 extern char *__to_vvstnam(char *, word32);
148 extern char *__to_sytyp(char *, word32);
149 extern char *__to_tcnam(char *, word32);
150 extern char *__to_edgenam(char *, word32);
151 extern char *__to_timunitnam(char *, word32);
152 extern char *__msg_blditree(char *, struct itree_t *, struct task_t *);
153 extern char *__msg2_blditree(char *, struct itree_t *);
154 extern char *__regab_tostr(char *, word32 *, word32 *, int32, int32, int32);
155 extern char *__xregab_tostr(char *, word32 *, word32 *, int32, struct expr_t *);
156 extern char *__strab_tostr(char *, word32 *, int32, int32, int32);
157 extern char *__vval_to_vstr(word32 *, int32, int32 *);
158 extern char *__to_arr_range(char *, struct net_t *);
159 extern char *__to_mpnam(char *, char *);
160 extern struct xstk_t *__eval2_xpr(struct expr_t *);
161 extern struct xstk_t *__ndst_eval_xpr(struct expr_t *);
162 extern char *__to_timstr(char *, word64 *);
163 extern char *__to_vvnam(char *, word32);
164 extern char *__bld_lineloc(char *, word32, int32);
165 extern struct task_t *__find_thrdtsk(struct thread_t *);
166 extern char *__alloc_vval_to_cstr(word32 *, int32, int32, int32);
167 extern char *__to_sttyp(char *, word32);
168 
169 extern struct expr_t *__disp_1fmt_to_exprline(char *, struct expr_t *);
170 extern struct task_t *__getcur_scope_tsk(void);
171 extern void __wrap_puts(char *, FILE *);
172 extern void __wrap_putc(int32, FILE *);
173 extern void __nl_wrap_puts(char *, FILE *);
174 extern void __chg_xprline_size(int32);
175 extern void __disp_itree_path(register struct itree_t *, struct task_t *);
176 extern void __declcnv_tostr(char *, word32 *, int32, int32);
177 extern void __adds(char *);
178 extern void __sdispb(register word32 *, register word32 *, int32, int32);
179 extern int32 __trim1_0val(word32 *, int32);
180 extern void __xline_vval_to_cstr(word32 *, int32, int32, int32, int32);
181 extern void __my_free(char *, int32);
182 extern void __regab_disp(word32 *, word32 *, int32, int32, int32, int32);
183 extern void __trunc_cstr(char *, int32, int32);
184 extern int32 __vval_isallzs(word32 *, word32 *, int32);
185 extern void __grow_xstk(void);
186 extern void __chg_xstk_width(struct xstk_t *, int32);
187 extern void __by16_ldivmod(word32 *, word32 *, word32 *, word32, int32);
188 extern int32 __wide_vval_is0(register word32 *, int32);
189 extern int32 __v64_to_real(double *, word64 *);
190 extern void __cnv_stk_fromreal_toreg32(struct xstk_t *);
191 extern void __cnv_stk_fromreg_toreal(struct xstk_t *, int32);
192 extern void __rhspsel(register word32 *, register word32 *, register int32,
193  register int32);
194 extern void __disp_var(struct net_t *, int32, int32, int32, char);
195 extern int32 __cnt_dcelstels(register struct dcevnt_t *);
196 extern int32 __get_arrwide(struct net_t *);
197 extern void __ld_arr_val(register word32 *, register word32 *, union pck_u,
198  int32, int32, int32);
199 extern void __ld_wire_val(register word32 *, register word32 *, struct net_t *);
200 extern void __ld_bit(register word32 *, register word32 *, register struct net_t *,
201  int32);
202 extern void __ld_psel(register word32 *, register word32 *,
203  register struct net_t *, int32, int32);
204 extern void __getarr_range(struct net_t *, int32 *, int32 *, int32 *);
205 extern void __dmp1_nplstel(struct mod_t *, struct net_t *, struct net_pin_t *);
206 extern void __dmp1_dcelstel(struct mod_t *, struct dcevnt_t *);
207 extern int32 __get_dcewid(struct dcevnt_t *, struct net_t *);
208 extern void __ld_perinst_val(register word32 *, register word32 *, union pck_u,
209  int32);
210 extern int32 __vval_is1(register word32 *, int32);
211 extern void __sizchgxs(struct xstk_t *, int32);
212 extern int32 __fr_cap_size(int32);
213 extern int32 __get_netwide(struct net_t *);
214 extern void __dmp_proc_assgn(FILE *, struct st_t *, struct delctrl_t *, int32);
215 extern void __dmp_stmt(FILE *, struct st_t *, int32);
216 
217 extern void __dmp_nbproc_assgn(FILE *, struct st_t *, struct delctrl_t *);
218 extern void __dmp_forhdr(FILE *, struct for_t *);
219 extern void __dmp_dctrl(FILE *, struct delctrl_t *);
220 extern void __dmp_tskcall(FILE *, struct st_t *);
221 extern void __map_16v_to_12vform(word64 *, word64 *);
222 extern void __try_reduce_16vtab(word64 *, int32 *);
223 extern void __dmp_dcxpr(FILE *, union del_u, word32);
224 extern int32 __isleaf(struct expr_t *);
225 extern void __getwir_range(struct net_t *, int32 *, int32 *);
226 extern int32 __unnormalize_ndx(struct net_t *, int32);
227 extern int32 __get_giarr_wide(struct giarr_t *);
228 extern char *__get_vkeynam(char *, int32);
229 extern void __push_wrkitstk(struct mod_t *, int32);
230 extern void __pop_wrkitstk(void);
231 extern int32 __is_lnegative(word32 *, int32);
232 extern word32 __cp_lnegate(word32 *, register word32 *, int32);
233 
234 extern void __cvsim_msg(char *, ...);
235 extern void __dbg_msg(char *, ...);
236 extern void __pv_err(int32, char *, ...);
237 extern void __pv_warn(int32, char *,...);
238 extern void __sgfwarn(int32, char *, ...);
239 extern void __sgfinform(int32, char *, ...);
240 extern void __sgferr(int32, char *, ...);
241 extern void __gfterr(int32, word32, int32, char *, ...);
242 extern void __pv_terr(int32, char *, ...);
243 extern void __arg_terr(char *, int32);
244 extern void __case_terr(char *, int32);
245 extern void __misc_terr(char *, int32);
246 
247 extern word32 __masktab[];
248 extern int32 errno;
249 extern double __dbl_toticks_tab[];
250 
251 /* LOOKATME - on mach ten and sunos fmod is drem - but maybe not same */
252 /* think ok since only used for know positive and arg1>arg2 case */
253 #if defined(__SVR4) || defined(__hpux)
254 #define drem fmod
255 #endif
256 
257 /*
258  * VERILOG EXACT DISPLAY ROUTINES - NO LINE HERE
259  */
260 
261 /*
262  * write $fdisplay output to all files selected by multi-channel desc.
263  * or
264  *
265  * important to call write only once per file here
266  * for now this shares line wrap line output code so must save and restore
267  *
268  * axp must be function call comma operator even if only 1 argument
269  */
__fio_do_disp(register struct expr_t * axp,int32 dflt_fmt,int32 nd_nl,char * namstsk)270 extern void __fio_do_disp(register struct expr_t *axp, int32 dflt_fmt, int32 nd_nl,
271  char *namstsk)
272 {
273  register int32 i;
274  word32 mcd;
275  struct xstk_t *xsp;
276  char s1[RECLEN];
277 
278  xsp = __eval_xpr(axp->lu.x);
279  if (xsp->bp[0] != 0L)
280   {
281    __sgfwarn(611,
282     "%s file or multi-channel descriptor %s not 32 bit non x/z value - no action",
283     namstsk, __regab_tostr(s1, xsp->ap, xsp->bp, xsp->xslen, BHEX, FALSE));
284    __pop_xstk();
285    return;
286   }
287  mcd = xsp->ap[0];
288  __pop_xstk();
289 
290  axp = axp->ru.x;
291 
292  __cur_sofs = 0;
293  disp_toexprline(axp, dflt_fmt);
294 
295  /* SJM 09/09/03 - fd case easy because only one stream to write to */
296  if ((mcd & FIO_MSB) == FIO_MSB)
297   {
298    int32 fd;
299 
300    fd = (int32) (mcd & ~FIO_MSB);
301    /* if fd does not correspond to open file, just set error indicator */
302    /* AIV 06/27/05 - fd cannot be greater than max file size */
303    if (fd >= MY_FOPEN_MAX || __fio_fdtab[fd] == NULL)
304     {
305      errno = EBADF;
306      __cur_sofs = 0;
307      return;
308     }
309    fputs(__exprline, __fio_fdtab[fd]->fd_s);
310    if (nd_nl) fputc('\n', __fio_fdtab[fd]->fd_s);
311    __cur_sofs = 0;
312    return;
313   }
314 
315  /* SJM 03/26/00 - mcd 1 now both stdout and std log and vendor 1 must */
316  /* go through call back so can be intercepted */
317  /* bit 0 - mcd 1 is both stdout and stdlog */
318  if ((mcd & 1) != 0)
319   {
320    __cvsim_msg("%s", __exprline);
321    if (nd_nl) __cvsim_msg("\n");
322   }
323 
324  for (i = 1; i < 31; i++)
325   {
326    if (((mcd >> i) & 1L) != 0L)
327     {
328      if (__mulchan_tab[i].mc_s == NULL)
329       {
330        __sgfwarn(583,
331         "%s multi-channel descriptor bit %d on, but file not open",
332         namstsk, i);
333       }
334      else
335       {
336        /* FIXME - how are these handled? */
337        fputs(__exprline, __mulchan_tab[i].mc_s);
338        if (nd_nl) fputc('\n', __mulchan_tab[i].mc_s);
339       }
340     }
341   }
342  if (((mcd >> 31) & 1) != 0)
343   {
344    __sgfwarn(583,
345     "%s multi-channel descriptor bit 31 on but file not open - unusable because reserved for new Verilog 2000 file I/O",
346      namstsk);
347   }
348  __cur_sofs = 0;
349 }
350 
351 /*
352  * $swrite[hdob] version of formatted write into strings
353  * this writes into __exprline - caller handles assign verilog reg
354  *
355  * notice this is write not display so no new line at end
356  */
__str_do_disp(struct expr_t * axp,int32 dflt_fmt)357 extern void __str_do_disp(struct expr_t *axp, int32 dflt_fmt)
358 {
359  __cur_sofs = 0;
360  disp_toexprline(axp, dflt_fmt);
361 }
362 
363 /*
364  * write $display output to file f (must be stream)
365  *
366  * for now this shares line wrap line output code so must save and restore
367  * axp must be function call comma operator even if only 1 argument
368  */
__do_disp(register struct expr_t * axp,int32 dflt_fmt)369 extern void __do_disp(register struct expr_t *axp, int32 dflt_fmt)
370 {
371  __cur_sofs = 0;
372  disp_toexprline(axp, dflt_fmt);
373  __cvsim_msg("%s", __exprline);
374  __cur_sofs = 0;
375 }
376 
377 /*
378  * routine to implement $display type displaying into a expr line string
379  * macros will grow string if needed
380  * starts at place called set __cur_sofs to
381  *
382  * notice this run time routine and any called routines should
383  * not emit messages - exception is round to time if has bits 52-64 on
384  */
disp_toexprline(register struct expr_t * axp,int32 dflt_fmt)385 static void disp_toexprline(register struct expr_t *axp, int32 dflt_fmt)
386 {
387  register char *chp;
388  int32 base, chlen;
389  char *start_fp;
390  struct expr_t *xp;
391  struct xstk_t *xsp;
392 
393  for (;axp != NULL;)
394   {
395    xp = axp->lu.x;
396    /* empty parameter adds 1 space */
397    if (xp->optyp == OPEMPTY) { addch_(' '); axp = axp->ru.x; continue; }
398 
399    /* literal format string (i.e 1st byte is 1st char of string not \0 */
400    /* cannot be defparam since rhs literal string removed */
401    if (xp->is_string)
402     {
403      /* since just encoding literal, know no leading 0's */
404      chp = __vval_to_vstr(&(__contab[xp->ru.xvi]), xp->szu.xclen, &chlen);
405 
406      /* notice since must be literal source text string escapes removed */
407      /* also this string can contain embedded 0's that are printed */
408      /* know literal string has no bval */
409      start_fp = chp;
410 
411      /* assuming 8 bit bytes */
412      axp = __disp_1fmt_to_exprline(chp, axp);
413      if (axp != NULL) xp = axp->lu.x; else xp = NULL;
414 
415      /* already pointing one past last format string used */
416      __my_free(start_fp, chlen);
417      continue;
418     }
419    /* handle argument that is just printed using default format */
420    /* notice if literal string will not get here and if string var */
421    /* here printed as number - need format */
422    /* here default is base, but display real as real */
423    xsp = __eval_xpr(xp);
424    base = (xp->is_real) ? BDBLE : dflt_fmt;
425    /* always trim here */
426    __regab_disp(xsp->ap, xsp->bp, xsp->xslen, base, FALSE,
427     (xp->has_sign == 1));
428    __pop_xstk();
429    axp = axp->ru.x;
430   }
431  __exprline[__cur_sofs] = '\0';
432 }
433 
434 /*
435  * print into string according to specifications in one format string
436  *
437  * this is called multiple times $swrite and exactly onece for $sformat
438  * chp points to value converted to string
439  */
__disp_1fmt_to_exprline(char * chp,struct expr_t * axp)440 extern struct expr_t *__disp_1fmt_to_exprline(char *chp, struct expr_t *axp)
441 {
442  int32 trim, fmt_pos, fmt_non_real, blen;
443  word32 *ap, *bp;
444  double d1;
445  char *new_chp;
446  struct expr_t *xp;
447  struct xstk_t *xsp;
448  struct task_t *tskp;
449  struct mod_t *mdp;
450  char rfmtstr[RECLEN], s1[RECLEN], s2[RECLEN];
451 
452  /* point to 1st format value argument */
453  axp = axp->ru.x;
454  if (axp == NULL) xp = NULL; else xp = axp->lu.x;
455 
456  fmt_pos = 0;
457  for (; *chp != '\0'; chp++)
458   {
459    /* notice is escaped by user char in format gets echoed as is */
460    if (*chp != '%') { addch_(*chp); continue; }
461    chp++;
462    fmt_pos++;
463    /* if non format character just continue */
464    /* needed since xp may be for %[non format] form */
465    trim = FALSE;
466 try_fmt_again:
467    fmt_non_real = TRUE;
468    switch (*chp) {
469     case '%':
470      /* interesting but since output always goes through printf */
471      /* this no longer goes through printf so only one needed */
472      addch_('%');
473      continue;
474     case '0':
475      chp++;
476      if (trim) goto c_style_case;
477      trim = TRUE;
478      goto try_fmt_again;
479     case 'm': case 'M':
480      /* if no thread, know in interactive and have scope */
481      if (__cur_thd == NULL) tskp = __scope_tskp;
482      /* %m defined as "scope" which may be task/func/block/inst */
483      else tskp = __getcur_scope_tsk();
484      __disp_itree_path(__inst_ptr, tskp);
485      /* must not consume an argument */
486      continue;
487     case 'l': case 'L':
488      /* SJM 05/17/04 - FIXME ??? ### need ptr from mod to cfg lib rec def in */
489      mdp = __inst_ptr->itip->imsym->el.emdp;
490      if (mdp->mod_cfglbp != NULL)
491       {
492        sprintf(s1, "%s.%s", mdp->mod_cfglbp->lbname, mdp->msym->synam);
493       }
494      else
495       {
496        sprintf(s1, "[NO-CONFIG].%s", mdp->msym->synam);
497       }
498      __adds(s1);
499      continue;
500 
501     case 'h': case 'H': case 'x': case 'X': case 'd': case 'D':
502     case 'o': case 'O': case 'b': case 'B': case 'c': case 'C':
503     case 's': case 'S': case 'v': case 'V':
504     /* SJM 05/17/04 - binary formats added for P1364 2001 */
505     case 'u': case 'U': case 'z': case 'Z':
506      break;
507 
508     case 't': case 'T':
509      fmt_non_real = FALSE;
510      break;
511     case 'e': case 'E': case 'f': case 'F': case 'g': case 'G':
512      fmt_non_real = FALSE;
513      /* F not in C standard and indentical to 'f' */
514      if (*chp == 'F') *chp = 'f';
515      /* trim ignored here and any c style %10.3g (z.b.) example */
516      strcpy(rfmtstr, "");
517      break;
518     /* for %f/%g only need to parse C style format */
519     /* notice for 0. enter normally, for c legal 00 get here from '0' */
520     case '1': case '2': case '3': case '4': case '5':
521     case '6': case '7': case '8': case '9': case '.': case '-':
522     case '+': case '#': case ' ':
523 c_style_case:
524      /* one of these after percent probably real format */
525      /* if new_chp not 0 points to end format char on return */
526      if ((new_chp = sep_real_fmt(rfmtstr, chp, trim)) == NULL)
527       {
528        addch_('%');
529        if (trim) { addch_('0'); chp--; } else addch_(*chp);
530        continue;
531       }
532      /* got real format */
533      chp = new_chp;
534      fmt_non_real = FALSE;
535      break;
536     default:
537      /* copy %[non format char] case */
538      addch_('%');
539      addch_(*chp);
540      /* notice for loop has chp++ inc */
541      continue;
542    }
543 
544   /* format needs expr. - check it */
545   /* if nil, treat as ,, */
546   if (xp == NULL)
547    {
548     addch_(' ');
549     continue;
550    }
551 
552   if (xp->optyp == OPEMPTY) { addch_(' '); goto nxt_arg; }
553   /* ok for literal string to be printed as value */
554   /* need special evaluation for with strength formats */
555   if (*chp == 'v' || *chp == 'V') { sdisp_st(xp); goto nxt_arg; }
556 
557   /* eval. here uses type of expression to get real or non real val */
558   xsp = __eval_xpr(xp);
559   if (xp->is_real && fmt_non_real) __cnv_stk_fromreal_toreg32(xsp);
560   ap = xsp->ap;
561   bp = xsp->bp;
562   switch (*chp) {
563    case 'h': case 'H': case 'x': case'X':
564     /* for variable accesses correct one */
565     sdisph(ap, bp, xsp->xslen, trim);
566     break;
567    case 'd': case 'D':
568 do_dec:
569     sdispd(ap, bp, xp->szu.xclen, trim, (xp->has_sign == 1));
570     break;
571    case 't': case 'T':
572     {
573      char tfmtstr[IDLEN];
574 
575      if (!bld_tfmt_val(tfmtstr, xp, ap, bp, xsp->xslen, trim, fmt_pos))
576       goto do_dec;
577      __adds(tfmtstr);
578     }
579     break;
580    case 'o': case 'O':
581     sdispo(ap, bp, xsp->xslen, trim);
582     break;
583    case 'b': case 'B':
584     __sdispb(ap, bp, xsp->xslen, trim);
585     break;
586    case 's': case 'S':
587     /* %s ignores b part and if non literal str leading 0's trimmed */
588     /* do not need %0s to cause leading (high) 0's to not print */
589     blen = __trim1_0val(ap, xsp->xslen);
590     __xline_vval_to_cstr(ap, blen, FALSE, FALSE, FALSE);
591     break;
592    case 'c': case 'C':
593     /* OVIsim only prints if printable */
594     /* SJM 09/19/03 - must also print new line and tab - isprint does */
595     /* not include new line and tab etc. */
596     if (isprint(ap[0] & 0xff) || (ap[0] & 0xff) == '\n'
597      || (ap[0] & 0xff) == '\r' || (ap[0] & 0xff) == '\t')
598      addch_((char) (ap[0] & 0xff));
599     else addch_(' ');
600     break;
601    case 'u': case 'U':
602     disp_ufmt_binval(ap, bp, xsp->xslen);
603     break;
604    case 'z': case 'Z':
605     disp_zfmt_binval(ap, bp, xsp->xslen);
606     break;
607 
608    /* this can only be bit select or scalar */
609    /* notice this reevaluates expression since needs to access st too */
610    case 'e': case 'E': case 'f': case 'F': case 'g': case 'G':
611     /* tricky case of real that needs c printf - fmt str in rfmtstr */
612     if (!xp->is_real)
613      {
614       /* this may produce warning if does not fit */
615       __cnv_stk_fromreg_toreal(xsp, (xp->has_sign == 1));
616       ap = xsp->ap;
617       bp = xsp->bp;
618      }
619     /* first build the format string */
620     if (*chp == 'F') *chp = 'f';
621     sprintf(s1, "%%%s%c", rfmtstr, *chp);
622     memcpy(&d1, ap, sizeof(double));
623 
624     /* know max size of real cannot be more than 30 or so */
625     sprintf(s2, s1, d1);
626     __adds(s2);
627     /* LOOKATME - fall thru under what conditions? */
628    }
629    __pop_xstk();
630 nxt_arg:
631    /* know 1 format arguemnt used up, so must move to next */
632    axp = axp->ru.x;
633    if (axp == NULL) xp = NULL; else xp = axp->lu.x;
634   }
635  return(axp);
636 }
637 
638 /*
639  * get the task from the current execing scope
640  * return NULL if none
641  */
__getcur_scope_tsk(void)642 extern struct task_t *__getcur_scope_tsk(void)
643 {
644  struct task_t *tskp;
645 
646  if (__fcspi >= 0) tskp = __fcstk[__fcspi];
647  else if (__cur_thd->th_fj) tskp = __find_thrdtsk(__cur_thd);
648  else tskp = __cur_thd->assoc_tsk;
649  return(tskp);
650 }
651 
652 /*
653  * routine to check a display format system task (called from v_fx)
654  *
655  * this is version of display routine above with all output and evaluation
656  * turned off
657  */
__chk_fmt(register struct expr_t * axp,byte * argnonvtab)658 extern void __chk_fmt(register struct expr_t *axp, byte *argnonvtab)
659 {
660  register char *chp;
661  int32 trim, fmt_pos, fmt_non_real, chlen, argi;
662  char *new_chp, *start_fp;
663  struct expr_t *xp;
664  char rfmtstr[RECLEN], s1[RECLEN];
665 
666  for (fmt_pos = 0, argi = 0; axp != NULL;)
667   {
668    xp = axp->lu.x;
669    /* empty parameter, skip */
670    if (xp->optyp == OPEMPTY) { axp = axp->ru.x; argi++; continue; }
671 
672    /* literal format string (i.e 1st byte is 1st char of string no \0 */
673    /* cannot be defparam */
674    if (xp->is_string)
675     {
676      /* since just en-ecoding literal, know no leading 0's */
677      chp = __vval_to_vstr(&(__contab[xp->ru.xvi]), xp->szu.xclen, &chlen);
678      start_fp = chp;
679      /* know literal string has no bval */
680      /* point to 1st format value argument */
681      axp = axp->ru.x;
682      if (axp == NULL) xp = NULL; else { xp = axp->lu.x; argi++; }
683 
684      /* notice since must be liternal source text string escapes removed */
685      /* also this string can contain embedded 0's that are printed */
686      for (; *chp != '\0'; chp++)
687       {
688        if (*chp != '%')
689         {
690          if (isprint(*chp) || *chp == '\n' || *chp == '\r' || *chp == '\t'
691           || *chp == '\f') continue;
692          __sgfwarn(561,
693           "format contains non printable character \\%o (%d) (next pos. %d)",
694           *chp, *chp, fmt_pos + 1);
695         }
696        chp++;
697        fmt_pos++;
698        /* if non format character just continue */
699        /* needed since xp can be %[non format] form */
700        trim = FALSE;
701 try_fmt_again:
702        fmt_non_real = TRUE;
703        switch (*chp) {
704         case '%': continue;
705         case '0':
706          chp++;
707          if (trim) goto c_style_case;
708          trim = TRUE;
709          goto try_fmt_again;
710         case 'm': case 'M': continue;
711         case 'l': case 'L': continue;
712 
713         case 'v': case 'V':
714          if (argnonvtab != NULL) argnonvtab[argi] = 1;
715          break;
716         case 'h': case 'H': case 'x': case 'X': case 'd': case 'D':
717         case 'o': case 'O': case 'b': case 'B': case 'c': case 'C':
718         case 's': case 'S': case 'u': case 'U': case 'z': case 'Z':
719          break;
720         case 't': case 'T':
721          fmt_non_real = FALSE;
722          break;
723         case 'e': case 'E': case 'f': case 'F': case 'g': case 'G':
724          fmt_non_real = FALSE;
725          /* F not in C standard and indentical to 'f' */
726          if (*chp == 'F') *chp = 'f';
727          /* trim ignored here and any c style %10.3g (z.b.) example */
728          break;
729         /* for %f/%g only need to parse C style format */
730         /* notice for 0. enter normally, for c legal 00 get here from '0' */
731         case '1': case '2': case '3': case '4': case '5':
732         case '6': case '7': case '8': case '9': case '.': case '-':
733         case '+': case '#': case ' ':
734 c_style_case:
735          /* one of these after percent probably real format */
736          /* if new_chp not 0 points to end format char on return */
737          if ((new_chp = sep_real_fmt(rfmtstr, chp, trim)) == NULL)
738           { if (trim) chp--; continue; }
739          /* got real format */
740          chp = new_chp;
741          fmt_non_real = FALSE;
742          break;
743         default: continue;
744          /* notice for loop has chp++ inc */
745        }
746 
747        /* format needs expr. - check it */
748        if (xp == NULL)
749         {
750          __sgferr(719, "argument list exhausted for %%%c format (pos. %d).",
751           *chp, fmt_pos);
752          continue;
753         }
754        if (xp->optyp == OPEMPTY)
755         {
756          __sgfwarn(549,
757           "argument list ,, value - format %%%c (pos. %d) - value is space",
758           *chp, fmt_pos);
759          goto nxt_arg;
760         }
761        if (xp->is_string && *chp != 's' && *chp != 'S')
762         {
763          __sgfwarn(554,
764           "string constant probably incompatible with %%%c format (pos. %d)",
765           *chp, fmt_pos);
766          goto nxt_arg;
767         }
768        /* strengths can be any 1 bit in OVIsim but anything in Cver */
769 
770        /* eval. here uses type of expression to get real or non real val */
771        if (xp->is_real && fmt_non_real)
772         {
773          __sgfwarn(552,
774           "%c format but value expression (pos. %d) type real - converted to 32 bit reg",
775           *chp, fmt_pos);
776         }
777        /* only look at things that need checking */
778        switch (*chp) {
779         case 't': case 'T':
780          if (xp->szu.xclen > TIMEBITS)
781           {
782            if (fmt_pos == -1) strcpy(s1, "");
783            else sprintf(s1, " (pos. %d)", fmt_pos);
784            __sgfwarn(520,
785             "%%t or $timeformat%s expression wider than %d bits - high ignored",
786             s1, TIMEBITS);
787           }
788          break;
789 
790         /* this can only be bit select or scalar */
791         /* notice this reevaluates expression since needs to access st too */
792         case 'e': case 'E': case 'f': case 'F': case 'g': case 'G':
793         /* tricky case of real that needs c printf - fmt str in rfmtstr */
794         if (!xp->is_real)
795          {
796           __sgfinform(480,
797             "non real value output with %c format (pos. %d) - conversion needed",
798            *chp, fmt_pos);
799          }
800         }
801 nxt_arg:
802        /* know 1 format arguemnt used up, so must move to next */
803        axp = axp->ru.x;
804        if (axp == NULL) xp = NULL; else { argi++; xp = axp->lu.x; }
805       }
806      /* already pointing one past last format string used */
807      __my_free(start_fp, chlen);
808      continue;
809     }
810    axp = axp->ru.x;
811    argi++;
812   }
813 }
814 
815 /*
816  * search currently executing task and up to top of nested created
817  * subthreads for a thread that is a task
818  *
819  * must search up since fork-join threads do not have tasks but
820  * thread that fork-join is subthread of may
821  * this is needed by %m
822  */
__find_thrdtsk(struct thread_t * cur_thp)823 extern struct task_t *__find_thrdtsk(struct thread_t *cur_thp)
824 {
825  struct thread_t *thdp;
826 
827  for (thdp = cur_thp; thdp != NULL; thdp = thdp->thpar)
828   {
829    if (thdp->assoc_tsk != NULL) return(thdp->assoc_tsk);
830   }
831  return(NULL);
832 }
833 
834 /*
835  * version os message build itree when know there is no task
836  */
__msg2_blditree(char * s,struct itree_t * itp)837 extern char *__msg2_blditree(char *s, struct itree_t *itp)
838 {
839  return(__msg_blditree(s, itp, (struct task_t *) NULL));
840 }
841 
842 /*
843  * version of instance name that builds work string
844  * does start at cur spos over-write anything ?
845  */
__msg_blditree(char * s,struct itree_t * itp,struct task_t * tskp)846 extern char *__msg_blditree(char *s, struct itree_t *itp, struct task_t *tskp)
847 {
848  int32 sav_sofs = __cur_sofs;
849 
850  __disp_itree_path(itp, tskp);
851  __trunc_cstr(&(__exprline[sav_sofs]), MSGTRUNCLEN, FALSE);
852  strcpy(s, &(__exprline[sav_sofs]));
853  __cur_sofs = sav_sofs;
854  __exprline[__cur_sofs] = '\0';
855  return(s);
856 }
857 
858 /*
859  * add itree path to __exprline - gets path from value of cur. itp
860  * use glbsycmp work array as work stack
861  * this just writes scope part - if need object name caller must write
862  * allow any length path here
863  */
__disp_itree_path(register struct itree_t * itp,struct task_t * tskp)864 extern void __disp_itree_path(register struct itree_t *itp, struct task_t *tskp)
865 {
866  register int32 gi;
867  struct symtab_t *sytp;
868  char *chp;
869 
870  /* if in task (probably nested block), build from bottom */
871  if (tskp != NULL)
872   {
873    for (sytp = tskp->tsksymtab, gi = 0;;)
874     {
875      /* notice do not need glb x cmps here since symbol is right inst */
876      __glbsycmps[gi] = sytp->sypofsyt;
877      sytp = sytp->sytpar;
878      if (sytp == NULL || sytp->sypofsyt->sytyp == SYM_M) break;
879      if (++gi >= MAXGLBCOMPS)
880       __pv_terr(310,
881        "cannot print instance path name with too many components (%d)",
882        MAXGLBCOMPS);
883     }
884    gi++;
885   }
886  else gi = 0;
887 
888  /* fill from front to end - know at least one component */
889  for (;;)
890   {
891    __glbsycmps[gi] = itp->itip->isym;
892    /* virtual tops modules have no up entry */
893    itp = itp->up_it;
894    if (itp == NULL) break;
895    if (++gi >= MAXGLBCOMPS)
896     __pv_terr(310,
897      "cannot print instance path name with too many components (%d)",
898      MAXGLBCOMPS);
899   }
900  /* then fill top end to front - know string nil terminated by last __adds */
901  for (; gi >= 0; gi--)
902   { chp = __glbsycmps[gi]->synam; __adds(chp); if (gi > 0) addch_('.'); }
903 }
904 
905 /*
906  * check for legal c printf style real format string
907  * this is format preprocessing routine
908  * think ascii standard says '-' can go anywhere
909  */
sep_real_fmt(char * fmtstr,char * chp,int32 trim)910 static char *sep_real_fmt(char *fmtstr, char *chp, int32 trim)
911 {
912  int32 i;
913  char *fchp;
914 
915  /* first see if can find real format end char within reasonable distance */
916  /* this eliminates literal % followed by real fonmat pun case */
917  for (fchp = chp, i = 1; ; fchp++, i++)
918   {
919    switch (*fchp) {
920     case 'e': case 'E': case 'f': case 'F': case 'g': case 'G':
921      /* -0dd.ddf is max but allowing 2 extra 0s */
922      if (i > 10) return(NULL);
923      goto got_fmt;
924     case '\0': return(NULL);
925    }
926   }
927  /* know format end fence in string to get here */
928 got_fmt:
929  fchp = fmtstr;
930  for (;;)
931   {
932    switch (*chp) {
933     case '-': case '+': case ' ': case '#': break;
934     /* 0 from trim followed by prefix 0 illegal */
935     case '0': if (trim) return(NULL); break;
936     default: goto col_digs;
937    }
938    *fchp++ = *chp++;
939   }
940 
941 col_digs:
942  /* collect possible digit string */
943  for (;;) { if (!isdigit(*chp)) break; *fchp++ = *chp++; }
944  if (*chp == '.')
945   {
946    *fchp++ = *chp++;
947    for (;;) { if (!isdigit(*chp)) break; *fchp++ = *chp++; }
948   }
949  switch (*chp) {
950   case 'e': case 'E': case 'g': case 'G': case 'f': case 'F': break;
951   default: return(NULL);
952  }
953  *fchp = '\0';
954  /* must return pointer to format char */
955  return(chp);
956 }
957 
958 /*
959  * convert a Verilog value to a printable hex string
960  * if trim false must pad with leading spaces
961  */
sdisph(word32 * ap,word32 * bp,int32 blen,int32 trim)962 static void sdisph(word32 *ap, word32 *bp, int32 blen, int32 trim)
963 {
964  register int32 bi, wi;
965  int32 swlen, bi2, trimmed_blen, highused;
966  word32 tmpa, tmpb;
967  char ch;
968 
969  /* short circuit common 1 bit case */
970  if (blen == 1)
971   {
972    tmpa = ap[0] | (bp[0] << 1);
973    if (tmpa < 2) ch = '0' + ((char) tmpa);
974    else if (tmpa == 2) ch = 'z';
975    else ch = 'x';
976    addch_(ch);
977    goto done;
978   }
979  if (trim)
980   {
981    trimmed_blen = trim_abval(ap, bp, blen);
982    if (trimmed_blen == 0) { addch_('0'); goto done; }
983    if (vval_isall_xs(ap, bp, blen)) { addch_('x'); goto done; }
984    if (__vval_isallzs(ap, bp, blen)) { addch_('z'); goto done; }
985   }
986  else trimmed_blen = blen;
987 
988  /* think high bits non zero (but same as new high bit will select right) */
989  /* may need to adjust so have 1 entire hex digit */
990  swlen = wlen_(trimmed_blen);
991  bi2 = trimmed_blen & 0x1fL;
992  if (bi2 == 0) bi = WBITS;
993  else bi = WRDBYTES*((bi2 + WRDBYTES - 1)/WRDBYTES);
994  bi -= 4;
995  if ((highused = (bi2 % 4)) == 0) highused = 4;
996  for (wi = swlen - 1; wi >= 0; wi--)
997   {
998    tmpa = ap[wi]; tmpb = bp[wi];
999    for (;bi > 0; bi -= 4)
1000     {
1001      tmpa = (ap[wi] >> bi) & 0xfL;
1002      tmpb = (bp[wi] >> bi) & 0xfL;
1003      addch_(bitsto_char(tmpa, tmpb, highused));
1004      highused = 4;
1005     }
1006    /* notice bi will always == 0 here */
1007    addch_(bitsto_char((ap[wi] & 0xfL), (bp[wi] & 0xfL), highused));
1008    bi = WBITS - 4;
1009   }
1010  /* need explicit terminator */
1011 done:
1012  __exprline[__cur_sofs] = '\0';
1013 }
1014 
1015 /*
1016  * convert hex/oct/bin bit pattern to ascii character
1017  * all bits z = lower case else upper case (same for x)
1018  */
bitsto_char(word32 a,word32 b,int32 bwid)1019 static char bitsto_char(word32 a, word32 b, int32 bwid)
1020 {
1021  char ch;
1022  word32 mask;
1023 
1024  if (!b) { ch = (char) valtoch_(a); return(ch); }
1025  mask = __masktab[bwid];
1026  if ((b & mask) == mask)
1027   {
1028    /* know all control bits on */
1029    if (a == 0L) return('z');
1030    else if ((a & mask) == mask) return('x');
1031    else return('X');
1032   }
1033  /* some control bits on - if no x's Z else X */
1034  if ((a & b) == 0L) return('Z');
1035  return('X');
1036 }
1037 
1038 /*
1039  * convert a Verilog value to a printable decimal string using c printf
1040  * starts fill __exprline at sofs and update sofs
1041  * dsigned false for signed value - like %u in c
1042  * if caller added [size]'d will never be signed
1043  */
sdispd(word32 * ap,word32 * bp,int32 blen,int32 trim,int32 dsigned)1044 static void sdispd(word32 *ap, word32 *bp, int32 blen, int32 trim, int32 dsigned)
1045 {
1046  register int32 i;
1047  int32 ochnum, trimblen, widnumlen;
1048  sword32 sval;
1049  struct xstk_t *xsp;
1050  char ch, *chp, *chp2, s1[RECLEN];
1051 
1052  if (!trim)
1053   {
1054    /* need ceil here */
1055    ochnum = (int32) (blen*LG2_DIV_LG10 + 0.999999);
1056    if (dsigned) ochnum++;
1057   }
1058  else ochnum = 0;
1059 
1060  /* handle various x/z forms */
1061  if ((ch = get_decxz(ap, bp, blen)) != ' ')
1062   {
1063    /* ? PORTABILITY sprintf(s1, "%*c", ochnum, ch); */
1064    for (i = 0; i < ochnum - 1; i++) addch_(' ');
1065    addch_(ch);
1066    __exprline[__cur_sofs] = '\0';
1067    return;
1068   }
1069  if (blen <= WBITS)
1070   {
1071    /* for decimal leading untrimmed must be spaces */
1072    if (dsigned)
1073     {
1074      if (blen == WBITS) sprintf(s1, "%ld", (sword32) ap[0]);
1075      else
1076       {
1077        if ((ap[0] & (1 << (blen - 1))) != 0)
1078         {
1079          /* SJM 10/20/03 - 1 bit width vars can't be signed so works */
1080          if (blen == 1)
1081           {
1082            /* AIV 09/15/04 - LOOKATME - should this be -1? */
1083            strcpy(s1, "0");
1084           }
1085          else
1086           {
1087            sval = ~((int32) ap[0]);
1088            sval++;
1089            sval &= __masktab[blen - 1];
1090            /* AIV 09/15/04 - was wrongly printing - 0 for most negative */
1091            if (sval == 0) sprintf(s1, "-%ld", ap[0]);
1092            else sprintf(s1, "-%ld", sval);
1093           }
1094         }
1095        else sprintf(s1, "%lu", ap[0]);
1096       }
1097     }
1098    else sprintf(s1, "%lu", ap[0]);
1099    for (i = 0; i < ochnum - (int32) strlen(s1); i++) addch_(' ');
1100    __adds(s1);
1101    return;
1102   }
1103  /* SJM 05/27/04 - for negative can't trim until negated */
1104  if (dsigned && __is_lnegative(ap, blen))
1105   {
1106    /* compute number of chars required by converted number */
1107    /* need ceil here */
1108    /* SJM 10/20/03 - since wide can now be signed must use 2's complement */
1109    /* this works because know x/z case removed above */
1110 
1111    /* number is negative - compute bit wise not then add 1 */
1112    push_xstk_(xsp, blen);
1113    __cp_lnegate(xsp->ap, ap, blen);
1114 
1115    trimblen = __trim1_0val(xsp->ap, blen);
1116    widnumlen = trimblen*LG2_DIV_LG10 + 0.999999;
1117    chp = (char *) __my_malloc(widnumlen + 2);
1118    __declcnv_tostr(chp, xsp->ap, trimblen, widnumlen);
1119    widnumlen++;
1120    for (i = 0; i < ochnum - widnumlen; i++) addch_(' ');
1121    addch_('-');
1122 
1123    /* SJM 05/28/04 - widnumlen estimate can be 1 too large must trim front */
1124    /* can't just inc chp since must free beginning of area */
1125    chp2 = chp;
1126    while (*chp2 == ' ') chp2++;
1127    __adds(chp2);
1128 
1129    __my_free(chp, widnumlen + 2);
1130    __pop_xstk();
1131    return;
1132   }
1133  /* case 2: either not signed or positive */
1134  trimblen = __trim1_0val(ap, blen);
1135  /* handle wide 0 as special case - these need trim on to happen */
1136  if (trimblen == 0)
1137   {
1138    for (i = 0; i < ochnum - 1; i++) addch_(' ');
1139    addch_('0');
1140    __exprline[__cur_sofs] = '\0';
1141    return;
1142   }
1143  /* next wide that trims to 1 word32 */
1144  if (trimblen <= WBITS)
1145   {
1146    sprintf(s1, "%lu", ap[0]);
1147    for (i = 0; i < ochnum - (int32) strlen(s1); i++) addch_(' ');
1148    __adds(s1);
1149    return;
1150   }
1151  widnumlen = trimblen*LG2_DIV_LG10 + 0.999999;
1152  chp = (char *) __my_malloc(widnumlen + 2);
1153  __declcnv_tostr(chp, ap, trimblen, widnumlen);
1154  for (i = 0; i < ochnum - widnumlen; i++) addch_(' ');
1155  __adds(chp);
1156  __my_free(chp, widnumlen + 2);
1157 }
1158 
1159 /*
1160  * convert an array of words (word32 contiguous Verilog multiword value)
1161  * into a string s known to be wide enough
1162  * know blen > WBITS for will not be called
1163  * this does not use exprline or a part
1164  */
__declcnv_tostr(char * s,word32 * wp,int32 trimblen,int32 widnumlen)1165 extern void __declcnv_tostr(char *s, word32 *wp, int32 trimblen, int32 widnumlen)
1166 {
1167  register int32 chi;
1168  word32 *quot, *u, r0;
1169  int32 wlen;
1170  struct xstk_t *xsp;
1171 
1172  wlen = wlen_(trimblen);
1173  push_xstk_(xsp, wlen*WBITS/2);
1174  quot = xsp->ap;
1175  memset(quot, 0, wlen*WRDBYTES);
1176  push_xstk_(xsp, wlen*WBITS/2);
1177  u = xsp->ap;
1178  cp_walign_(u, wp, trimblen);
1179  s[widnumlen] = '\0';
1180  /* repeatedly divide by 10 filling from end to front */
1181  for (chi = widnumlen - 1;;)
1182   {
1183    __by16_ldivmod(quot, &r0, u, (word32) 10, trimblen);
1184    s[chi--] = (char) (r0 + '0');
1185    if (vval_is0_(quot, trimblen)) break;
1186    if (chi < 0) __case_terr(__FILE__, __LINE__);
1187    /* know value shorter so retrim */
1188    trimblen = __trim1_0val(quot, trimblen);
1189    cp_walign_(u, quot, trimblen);
1190    memset(quot, 0, wlen_(trimblen)*WRDBYTES);
1191   }
1192  for (; chi >= 0; chi--) s[chi] = ' ';
1193  __pop_xstk();
1194  __pop_xstk();
1195 }
1196 
1197 /*
1198  * convert a 64 bit time to a decimal string
1199  * t must be ticks scaled to value for module if needed
1200  */
__to_timstr(char * s,word64 * t)1201 extern char *__to_timstr(char *s, word64 *t)
1202 {
1203  /* UNUSED - int32 trimblen, widnumlen; */
1204  word64 t1;
1205 
1206  /* hard absolute unit case */
1207  if (__nd_timstr_suf && __timstr_mult != 1) t1 = (*t)*__timstr_mult;
1208  else t1 = *t;
1209  /* LOOKATME - is this portable? */
1210  /* LOOKATME - what is sparc and hp format letters for these? */
1211  sprintf(s, "%llu", t1);
1212 
1213  /* LOOKATME - can this be eliminated ---
1214  if ((t1 >> 32) == 0ULL) sprintf(s, "%lu", (word32) (t1 & WORDMASK_ULL));
1215  else
1216   {
1217    word32 t1a[2];
1218 
1219    -* low at 0th address and high at next *-
1220    t1a[0] = (word32) (t1 & WORDMASK_ULL);
1221    t1a[1] = (word32) ((t1 >> 32) & WORDMASK_ULL);
1222    -* notice this case makes use of c require that fields are in order *-
1223    trimblen = __trim1_0val(t1a, TIMEBITS);
1224    -* need ceil here *-
1225    widnumlen = (int32) (trimblen*LG2_DIV_LG10 + 0.999999);
1226    __declcnv_tostr(s, t1a, trimblen, widnumlen);
1227   }
1228  --- */
1229  if (__nd_timstr_suf) strcat(s, __timstr_unitsuf);
1230  return(s);
1231 }
1232 
1233 /*
1234  * return decimal x/z/X/Z char ' ' for non x/z
1235  * could write routine that does not call routines but eliminates
1236  */
get_decxz(word32 * ap,word32 * bp,int32 blen)1237 static char get_decxz(word32 *ap, word32 *bp, int32 blen)
1238 {
1239  if (vval_is0_(bp, blen)) return(' ');
1240  if (vval_isall_xs(ap, bp, blen)) return('x');
1241  if (__vval_isallzs(ap, bp, blen)) return('z');
1242  /* finally find if any z's and any x's */
1243  if (vval_hasx(ap, bp, blen)) return('X');
1244  return('Z');
1245 }
1246 
1247 /*
1248  * build the time format (real) from $timeformat string
1249  * passed expr. is in scaled (mult. by min. units power of 10)
1250  * computation here use double so only 53 (52 ieee) bits of accuracy
1251  * (ieee) may cause loss of values
1252  *
1253  * notice value passed here is scaled to units of current module
1254  * i.e. must come from $time (or $stime or $realtime (already double))
1255  *
1256  * could do some case in exact 64 bit unsigned?
1257  * this string never wider than RECLEN and does not use expr line
1258  */
bld_tfmt_val(char * s,struct expr_t * xp,word32 * ap,word32 * bp,int32 blen,int32 trim,int32 fmt_pos)1259 static int32 bld_tfmt_val(char *s, struct expr_t *xp, word32 *ap, word32 *bp,
1260  int32 blen, int32 trim, int32 fmt_pos)
1261 {
1262  int32 unit;
1263  word64 usertim;
1264  double d1;
1265  struct mod_t *mdp;
1266  char s1[RECLEN];
1267 
1268  if (fmt_pos == -1) strcpy(s1, ""); else sprintf(s1, " (pos. %d)", fmt_pos);
1269  /* fill time from expr. - value is already scaled - may unscale */
1270  if (xp->is_real) memcpy(&d1, ap, sizeof(double));
1271  else
1272   {
1273    if (blen <= WBITS)
1274     { if (bp[0] != 0L) return(FALSE); d1 = (double) ap[0]; }
1275    else
1276     {
1277      /* this causes decimal style x with no suffix string to be emitted */
1278      if (bp[1] != 0L || bp[0] != 0L) return(FALSE);
1279      /* SJM 02/03/00 - works because ap[0] word32 */
1280      usertim = ((word64) ap[0]) | (((word64) ap[1]) << 32);
1281      if (!__v64_to_real(&d1, &usertim))
1282       __sgfwarn(572,
1283        "%%t or $timeformat%s conversion to real lost precision",
1284       s1);
1285     }
1286   }
1287  /* know d1 is this module's time unit time */
1288  /* if time format units same as modules d1 has ticks */
1289  mdp = __inst_mod;
1290  if (mdp->mtime_units != __tfmt_units)
1291   {
1292    if (mdp->mtime_units > __tfmt_units)
1293     {
1294      /* here d1 module ticks higher exponent (more precision) - divide */
1295      unit = mdp->mtime_units - __tfmt_units;
1296      d1 /= __dbl_toticks_tab[unit];
1297     }
1298    else
1299     {
1300      /* here d1 module ticks lower (less precision) - multiply */
1301      unit = __tfmt_units - mdp->mtime_units;
1302      d1 *= __dbl_toticks_tab[unit];
1303     }
1304   }
1305  /* unscaled time (can have frac. part) in d1 */
1306  /* uses the sprintf rounding */
1307  /* this can never fail */
1308  if (!trim)
1309   {
1310    sprintf(s, "%*.*f%s", (int32) (__tfmt_minfwid - strlen(__tfmt_suf)),
1311     (int32) __tfmt_precunits, d1, __tfmt_suf);
1312   }
1313  else sprintf(s, "%.*f%s", (int32) __tfmt_precunits, d1, __tfmt_suf);
1314  return(TRUE);
1315 }
1316 
1317 /*
1318  * for tf_ strgetp routines, build value of expr. in number
1319  *
1320  * return string (nil on error)
1321  * this is in convert because calls display formatting routines
1322  * added %v and %g/%f that are not part of standard
1323  * conversions to/from real are 32 bit following LRM $display
1324  *
1325  * tf_ routines malloc memory that user frees when done
1326  * know correct itree loc. set here
1327  */
__alloc_getasfmt(struct expr_t * xp,struct tfrec_t * tfrp,int32 fmtchar)1328 extern char *__alloc_getasfmt(struct expr_t *xp, struct tfrec_t *tfrp,
1329  int32 fmtchar)
1330 {
1331  int32 sav_sofs, slen, vsigned, valreal;
1332  word32 *wp;
1333  double d1;
1334  struct xstk_t *xsp;
1335  char *chp, s1[RECLEN];
1336 
1337  sav_sofs = __cur_sofs;
1338  /* handle argument 0 only for function as special case */
1339  if (tfrp != NULL)
1340   {
1341    if (fmtchar == 'v' || fmtchar == 'V') return(NULL);
1342    push_xstk_(xsp, tfrp->fretsiz);
1343    wp = (word32 *) tfrp->tfargs[0].arg.awp;
1344    /* SJM 12/12/01 - this was wrong was copying over stk ptr */
1345    memcpy(xsp->ap, wp, 2*wlen_(tfrp->fretsiz)*WRDBYTES);
1346 
1347    if (tfrp->fretreal) valreal = TRUE; else valreal = FALSE;
1348    vsigned = FALSE;
1349    goto xl_disp;
1350   }
1351 
1352  /* return 32 bit int32 as pointer to string */
1353  /* if really literal string format letter ignored */
1354  if (xp->optyp == NUMBER && xp->is_string)
1355   {
1356    /* notice even though in cnv uses tf malloc routine */
1357    chp = __alloc_vval_to_cstr(&(__contab[xp->ru.xvi]), xp->szu.xclen,
1358     FALSE, FALSE);
1359    /* notice no xstk push to get here */
1360    return(chp);
1361   }
1362 
1363  /* now fill exprline (on end saving prefix) */
1364  /* for strength allow vector but here display routine evals expr */
1365  /* if xp is real this will use bit pattern not converted value */
1366  if (fmtchar == 'v' || fmtchar == 'V') { sdisp_st(xp); goto xl_done; }
1367 
1368  xsp = __eval_xpr(xp);
1369  if (xp->is_real) valreal = TRUE; else valreal = FALSE;
1370  if (xp->has_sign) vsigned = TRUE; else vsigned = FALSE;
1371 
1372 xl_disp:
1373  d1 = 0.0;
1374  /* do any to/from real conversion if needed */
1375  switch ((byte) fmtchar) {
1376   case 'g': case 'G': case 'f': case 'F':
1377    if (!valreal) __cnv_stk_fromreg_toreal(xsp, vsigned);
1378    memcpy(&d1, xsp->ap, sizeof(double));
1379    break;
1380   default:
1381    if (valreal) __cnv_stk_fromreal_toreg32(xsp);
1382  }
1383 
1384  /* SJM 08/03/04 - this code was wrongly trimmming leading 0s */
1385  /* LRM  requires keeping leading 0s */
1386  switch ((byte) fmtchar) {
1387   case 'h': case 'H': case 'x': case'X':
1388    sdisph(xsp->ap, xsp->bp, xsp->xslen, FALSE);
1389    break;
1390   case 'd': case 'D':
1391    sdispd(xsp->ap, xsp->bp, xsp->xslen, FALSE, vsigned);
1392    break;
1393   case 'o': case 'O':
1394    sdispo(xsp->ap, xsp->bp, xsp->xslen, FALSE);
1395    break;
1396   case 'b': case 'B':
1397    __sdispb(xsp->ap, xsp->bp, xsp->xslen, FALSE);
1398    break;
1399   case 'g': case 'G': case 'f': case 'F':
1400    sprintf(s1, "%g", d1);
1401    break;
1402   default: __pop_xstk(); return(NULL);
1403  }
1404  __pop_xstk();
1405 
1406 xl_done:
1407  slen = __cur_sofs - sav_sofs;
1408  chp = __mytf_malloc(slen + 1);
1409  strcpy(chp, &(__exprline[sav_sofs]));
1410  __cur_sofs = sav_sofs;
1411  __exprline[__cur_sofs] = 0;
1412  return(chp);
1413 }
1414 
1415 /*
1416  * convert a Verilog value to a printable oct string
1417  */
sdispo(word32 * ap,word32 * bp,int32 blen,int32 trim)1418 static void sdispo(word32 *ap, word32 *bp, int32 blen, int32 trim)
1419 {
1420  register int32 bi;
1421  word32 psaval, psbval;
1422  int32 digs, trimmed_blen, highused, tmp;
1423  char ch;
1424 
1425  /* short circuit common 1 bit case */
1426  if (blen == 1)
1427   {
1428    tmp = (int32) (ap[0] | (bp[0] << 1));
1429    if (tmp < 2) ch = '0' + ((char) tmp);
1430    else if (tmp == 2) ch = 'z';
1431    else ch = 'x';
1432    addch_(ch);
1433    goto done;
1434   }
1435  if (trim)
1436   {
1437    trimmed_blen = trim_abval(ap, bp, blen);
1438    if (trimmed_blen == 0) { addch_('0'); goto done; }
1439    if (vval_isall_xs(ap, bp, blen)) { addch_('x'); goto done; }
1440    if (__vval_isallzs(ap, bp, blen)) { addch_('z'); goto done; }
1441   }
1442  else trimmed_blen = blen;
1443 
1444  /* notice -1 correction start at right part of 3 bit field */
1445  digs = ((trimmed_blen + 2)/3) - 1;
1446 
1447  /* notice selects required here because bits overlap word32 boundaries */
1448  if ((highused = (trimmed_blen % 3)) == 0) highused = 3;
1449  for (bi = 3*digs; bi >= 0; bi -= 3)
1450   {
1451    /* need part select here since word32 overlap */
1452    __rhspsel(&psaval, ap, bi, highused);
1453    __rhspsel(&psbval, bp, bi, highused);
1454    addch_(bitsto_char(psaval, psbval, highused));
1455    highused = 3;
1456   }
1457 done:
1458  __exprline[__cur_sofs] = '\0';
1459 }
1460 
1461 /*
1462  * convert a Verilog value to a printable binary string
1463  * if any prefix that must be preserved - sofs points to 1st usable pos.
1464  * notice this must be efficient since used for value change dump
1465  */
__sdispb(register word32 * ap,register word32 * bp,int32 blen,int32 trim)1466 extern void __sdispb(register word32 *ap, register word32 *bp, int32 blen, int32 trim)
1467 {
1468  register int32 wi, bi;
1469  register word32 tmpa, tmpb;
1470  int32 swlen, trimmed_blen;
1471  char ch;
1472 
1473  /* short circuit common 1 bit case */
1474  if (blen == 1)
1475   {
1476    tmpa = ap[0] | (bp[0] << 1);
1477    if (tmpa < 2) ch = '0' + ((char) tmpa);
1478    else if (tmpa == 2) ch = 'z';
1479    else ch = 'x';
1480    addch_(ch);
1481    __exprline[__cur_sofs] = '\0';
1482    return;
1483   }
1484 
1485  if (trim)
1486   {
1487    trimmed_blen = bin_trim_abval(ap, bp, blen);
1488    if (trimmed_blen == 0) { addch_('0'); goto done; }
1489    if (vval_isall_xs(ap, bp, blen)) { addch_('x'); goto done; }
1490    else if (__vval_isallzs(ap, bp, blen)) { addch_('z'); goto done; }
1491   }
1492  else trimmed_blen = blen;
1493 
1494  swlen = wlen_(trimmed_blen);
1495  bi = trimmed_blen & 0x1f;
1496  if (bi == 0) bi = WBITS - 1; else bi--;
1497  for (wi = swlen - 1; wi >= 0; wi--)
1498   {
1499    tmpa = ap[wi]; tmpb = bp[wi];
1500    for (;bi > 0; bi--)
1501     {
1502      tmpa = (ap[wi] >> bi) & 1L;
1503      tmpb = (bp[wi] >> bi) & 1L;
1504      if (tmpb != 0L) { if (tmpa != 0L) ch = 'x'; else ch = 'z'; }
1505      else ch = '0' + ((char) tmpa);
1506      addch_(ch);
1507     }
1508    /* notice bi always exactly 0 here */
1509    tmpa = ap[wi] & 1L;
1510    tmpb = bp[wi] & 1L;
1511    if (tmpb != 0L) { if (tmpa != 0L) ch = 'x'; else ch = 'z'; }
1512    else ch = '0' + ((char) tmpa);
1513    addch_(ch);
1514    bi = WBITS - 1;
1515   }
1516  /* need \0 but next char. must over write it */
1517 done:
1518  __exprline[__cur_sofs] = '\0';
1519 }
1520 
1521 /*
1522  * convert a value as Verilog string to printable string
1523  * truncating version
1524  */
__strab_tostr(char * s,word32 * ap,int32 blen,int32 nd_quotes,int32 space_0)1525 extern char *__strab_tostr(char *s, word32 *ap, int32 blen, int32 nd_quotes,
1526  int32 space_0)
1527 {
1528  int32 sav_sofs = __cur_sofs;
1529 
1530  __xline_vval_to_cstr(ap, blen, nd_quotes, space_0, FALSE);
1531  /* here keeps low part if trunc needed */
1532  __trunc_cstr(&(__exprline[sav_sofs]), MSGTRUNCLEN, TRUE);
1533  strcpy(s, &(__exprline[sav_sofs]));
1534  __cur_sofs = sav_sofs;
1535  __exprline[sav_sofs] = '\0';
1536  return(s);
1537 }
1538 
1539 /*
1540  * convert a value as Verilog string to printable string
1541  * non truncating version
1542  *
1543  * caller must insure big enough
1544  */
__strab2_tostr(char * s,word32 * ap,int32 blen,int32 nd_quotes,int32 space_0)1545 extern char *__strab2_tostr(char *s, word32 *ap, int32 blen, int32 nd_quotes,
1546  int32 space_0)
1547 {
1548  int32 sav_sofs = __cur_sofs;
1549 
1550  __xline_vval_to_cstr(ap, blen, nd_quotes, space_0, FALSE);
1551  /* here keeps low part if trunc needed */
1552  strcpy(s, &(__exprline[sav_sofs]));
1553  __cur_sofs = sav_sofs;
1554  __exprline[sav_sofs] = '\0';
1555  return(s);
1556 }
1557 
1558 /*
1559  * construct a Verilog string into line starting at __cur_sofs
1560  *
1561  * for values that are being printed in some type of display
1562  * dmp_expr uses this to add string to accumulating line
1563  */
__xline_vval_to_cstr(word32 * ap,int32 blen,int32 nd_quotes,int32 space_0,int32 esc_esc)1564 extern void __xline_vval_to_cstr(word32 *ap, int32 blen, int32 nd_quotes,
1565  int32 space_0, int32 esc_esc)
1566 {
1567  int32 chlen;
1568  char *chp;
1569 
1570  /* convert to pascal (no ending 0) string  - malloc storage */
1571  chp = __vval_to_vstr(ap, blen, &chlen);
1572  /* converts to c string with non printable expansion into __exprline */
1573  vstr_to_cstr(chp, blen, space_0, nd_quotes, esc_esc);
1574  /* free the version in malloced storage */
1575  __my_free(chp, chlen);
1576 }
1577 
1578 /*
1579  * convert a verilog string to a cstring - substitutes chars and adds \0
1580  * and put result in __exprline starting at current place
1581  */
vstr_to_cstr(char * vstr,int32 blen,int32 space_0,int32 nd_quotes,int32 esc_esc)1582 static void vstr_to_cstr(char *vstr, int32 blen, int32 space_0, int32 nd_quotes,
1583  int32 esc_esc)
1584 {
1585  register int32 i;
1586  register char *chp;
1587  int32 chlen;
1588  char s1[RECLEN];
1589 
1590  /* this will never extend higher than high word32, could have inform if */
1591  /* not even 8 bits but no way to locate for user */
1592  chlen = (blen + 7)/8;
1593  /* DBG remove --- */
1594  if (vstr[chlen] != '\0') __arg_terr(__FILE__, __LINE__);
1595  /* --- */
1596  if (nd_quotes) addch_('"');
1597  for (chp = vstr, i = 0; i < chlen; i++, chp++)
1598   {
1599    switch (*chp) {
1600     case '"': case '\\': addch_('\\'); addch_(*chp); break;
1601     case '\n':
1602      /* for source output must escape c escape so string contains embedded */
1603      if (esc_esc) { addch_('\\'); addch_('n'); } else addch_(*chp);
1604      break;
1605     case '\t':
1606      if (esc_esc) { addch_('\\'); addch_('t'); } else addch_(*chp);
1607      break;
1608     default:
1609      if (!isprint(*chp))
1610       {
1611        if (space_0 && *chp == '\0') { addch_(' '); break; }
1612        sprintf(s1, "%03o", *chp);
1613        addch_('\\');
1614        __adds(s1);
1615        break;
1616       }
1617      addch_(*chp);
1618    }
1619   }
1620  if (nd_quotes) addch_('"');
1621  __exprline[__cur_sofs] = '\0';
1622 }
1623 
1624 /* ---
1625 INVERSE:
1626 
1627 #if (BYTE_ORDER == BIG_ENDIAN)
1628    wrd = (b1 & 0xff) | ((b2 & 0xff) << 8) | ((b3 & 0xff) << 16)
1629     | ((b4 & 0xff) << 24);
1630 #else
1631    wrd = (b4 & 0xff) | ((b3 & 0xff) << 8) | ((b2 & 0xff) << 16)
1632     | ((b1 & 0xff) << 24);
1633 --- */
1634 /*
1635  * write 'u' format binary 0/1 one word32 using machine's endianness
1636  * into __exprline
1637  *
1638  * for u format output is a words only but if b bit set value is 0
1639  */
disp_ufmt_binval(word32 * ap,word32 * bp,int32 blen)1640 static void disp_ufmt_binval(word32 *ap, word32 *bp, int32 blen)
1641 {
1642  register int32 j;
1643  register word32 wrd;
1644  byte bval;
1645  int32 wi;
1646 
1647  for (wi = 0; wi < wlen_(blen); wi++)
1648   {
1649    wrd = ap[wi] & (bp[wi] ^ 0xffffffff);
1650 
1651 #if (BYTE_ORDER != BIG_ENDIAN)
1652    for (j = 24; j >= 0; j -= 8)
1653     {
1654      bval = (wrd >> j) & 0xff;
1655      addch_(bval);
1656     }
1657 #else
1658    for (j = 0; j <= 24; j += 8)
1659     {
1660      bval = (wrd >> j) & 0xff;
1661      addch_(bval);
1662     }
1663 #endif
1664   }
1665 }
1666 
1667 /*
1668  * write 'z' format binary 0/1 two words using machine's endianness
1669  * into __exprline
1670  *
1671  * for z format output is a and b words interleaved
1672  */
disp_zfmt_binval(word32 * ap,word32 * bp,int32 blen)1673 static void disp_zfmt_binval(word32 *ap, word32 *bp, int32 blen)
1674 {
1675  register int32 j;
1676  int32 wi;
1677  byte bval;
1678 
1679  for (wi = 0; wi < wlen_(blen); wi++)
1680   {
1681 #if (BYTE_ORDER != BIG_ENDIAN)
1682    for (j = 24; j >= 0; j -= 8)
1683     {
1684      bval = (ap[wi] >> j) & 0xff;
1685      addch_(bval);
1686      bval = (bp[wi] >> j) & 0xff;
1687      addch_(bval);
1688     }
1689 #else
1690    for (j = 0; j <= 24; j += 8)
1691     {
1692      bval = (ap[wi] >> j) & 0xff;
1693      addch_(bval);
1694      bval = (bp[wi] >> j) & 0xff;
1695      addch_(bval);
1696     }
1697 #endif
1698   }
1699 }
1700 
1701 /*
1702  * get a string and allocate with malloc
1703  *
1704  * not for disp routines where string in Verilog must be literal
1705  * this will always build some kind of string
1706  * this must be called with actual string or number object
1707  */
__get_eval_cstr(struct expr_t * xp,int32 * chlen)1708 extern char *__get_eval_cstr(struct expr_t *xp, int32 *chlen)
1709 {
1710  register int32 i;
1711  register char *chp;
1712  int32 sav_sofs, slen;
1713  struct xstk_t *xsp;
1714 
1715  xsp = __eval_xpr(xp);
1716 
1717  /* entire string could be \ddd form and 1 char per 8 bits */
1718  /* notice here every char can become \ddd where digits are octal */
1719  /* puts result in expr line */
1720  sav_sofs = __cur_sofs;
1721  __xline_vval_to_cstr(xsp->ap, xsp->xslen, FALSE, FALSE, FALSE);
1722  __pop_xstk();
1723 
1724  /* final step is trim all leading \000 chars */
1725  /* notice if any non \000, must stop */
1726  slen = __cur_sofs;
1727  for (chp = __exprline; *chp != '\0'; chp += 4)
1728   { if (strncmp(chp, "\\000", 4) != 0) break; }
1729  /* remove leading 0's if needed */
1730  if (chp != __exprline)
1731   {
1732    slen -= (chp - __exprline);
1733    /* tricky in place copy - strcpy not portable - also copy ending 0 */
1734    for (i = 0; i <= slen; i++) __exprline[i] = chp[i];
1735   }
1736  slen = strlen(&(__exprline[sav_sofs]));
1737  chp = __my_malloc(slen + 1);
1738  strcpy(chp, &(__exprline[sav_sofs]));
1739  __cur_sofs = sav_sofs;
1740  __exprline[__cur_sofs] = '\0';
1741  *chlen = slen;
1742  return(chp);
1743 }
1744 
1745 /*
1746  * convert constant string stored as Verilog value to Verilog style string
1747  * know b val always 0 and still must convert to C style string for print
1748  * copy little endian chars in words, bit endian word32 reg to big endian
1749  *
1750  * always puts a \0 at end of string in case needed (usually not)
1751  * also not Verilog value in sense that high chars are not zeroed
1752  *
1753  * cannot use to replace value
1754  * all this stuff is not 8 bit clean
1755  * loop probably better than the inlining here
1756  * notice assuming 8 bit byte
1757  * this routines is 32 bit word32 dependent
1758  */
__vval_to_vstr(word32 * ap,int32 blen,int32 * slen)1759 extern char *__vval_to_vstr(word32 *ap, int32 blen, int32 *slen)
1760 {
1761  register int32 si, wi;
1762  char *s;
1763  int32 wlen, nchs;
1764 
1765  /* make sure one extra character at end, if need to convert to */
1766  /* binary style c string for sreadmem */
1767  nchs = (blen + 7)/8;
1768  wlen = wlen_(8*nchs);
1769  /* make this up to 7 bytes larger than strictly needed */
1770  *slen = WRDBYTES*(wlen + 1);
1771  s = __my_malloc(*slen);
1772 
1773  for (si = nchs - 1, wi = 0; wi < wlen - 1; si -= 4, wi++)
1774   {
1775    s[si] = (char) (ap[wi] & 0xffL);
1776    s[si - 1] = (char) ((ap[wi] >> 8) & 0xffL);
1777    s[si - 2] = (char) ((ap[wi] >> 16) & 0xffL);
1778    s[si - 3] = (char) ((ap[wi] >> 24) & 0xffL);
1779   }
1780  if (si < 0) goto done;
1781  s[si--] = (char) (ap[wi] & 0xffL);
1782  if (si < 0) goto done;
1783  s[si--] = (char) ((ap[wi] >> 8) & 0xffL);
1784  if (si < 0) goto done;
1785  s[si--] = (char) ((ap[wi] >> 16) & 0xffL);
1786  if (si < 0) goto done;
1787  s[si--] = (char) ((ap[wi] >> 24) & 0xffL);
1788  /* format of verilog value string wrong */
1789  if (si != -1) __misc_terr(__FILE__, __LINE__);
1790 done:
1791  /* after filled form high end to low put in high ending \0 */
1792  s[nchs] = '\0';
1793  return(s);
1794 }
1795 
1796 /*
1797  * convert strength wire expr. (maybe range) to string
1798  */
__strenexpr_tostr(char * s,struct expr_t * xp)1799 extern char *__strenexpr_tostr(char *s, struct expr_t *xp)
1800 {
1801  int32 sav_sofs = __cur_sofs;
1802 
1803  sdisp_st(xp);
1804  /* here keeps low part if trunc needed */
1805  __trunc_cstr(&(__exprline[sav_sofs]), MSGTRUNCLEN, TRUE);
1806  strcpy(s, &(__exprline[sav_sofs]));
1807  __cur_sofs = sav_sofs;
1808  __exprline[__cur_sofs] = '\0';
1809  return(s);
1810 }
1811 
1812 /*
1813  * display one strength value - can only be scalar or bit select
1814  * checks for required simple expr.
1815  * this must not leave anything on stack
1816  * also fills exprline from current place
1817  *
1818  * notice for non strength this will add strong
1819  * also notice this has standard extension to allow printing vectors
1820  */
sdisp_st(struct expr_t * xp)1821 static void sdisp_st(struct expr_t *xp)
1822 {
1823  register int32 bi;
1824  int32 first_time;
1825  byte *sbp;
1826  struct xstk_t *xsp;
1827  char s1[10];
1828 
1829  /* eval. the expression - if non strength strong added */
1830  xsp = __ndst_eval_xpr(xp);
1831  sbp = (byte *) xsp->ap;
1832  for (first_time = TRUE, bi = xsp->xslen/4 - 1; bi >= 0; bi--)
1833   {
1834    if (first_time) first_time = FALSE; else addch_(' ');
1835    __adds(__to_vvstnam(s1, (word32) sbp[bi]));
1836   }
1837  __pop_xstk();
1838 }
1839 
1840 /*
1841  * NUMERIC EXPRESSION DISPLAY WORK ROUTINES - EXPR DETERMINES FMT
1842  * INTERNAL INTERFACE TO SAME MECHANISM AS DO_DISP
1843  */
1844 
1845 /*
1846  * truncated string form of num expr to value
1847  * this uses high env
1848  */
__msgnumexpr_tostr(char * s,struct expr_t * ndp,int32 inum)1849 extern char *__msgnumexpr_tostr(char *s, struct expr_t *ndp, int32 inum)
1850 {
1851  int32 sav_sofs = __cur_sofs;
1852 
1853  numexpr_disp(ndp, inum);
1854  __trunc_cstr(&(__exprline[sav_sofs]), MSGTRUNCLEN, FALSE);
1855  strcpy(s, &(__exprline[sav_sofs]));
1856  __cur_sofs = sav_sofs;
1857  __exprline[__cur_sofs] = '\0';
1858  return(s);
1859 }
1860 
1861 /*
1862  * build a numeric expr. value in exprline - grows if needed
1863  * use ndp node info to attempt to reconstruct input string
1864  *
1865  * does not set cur_sofs - can add into middle, but caller must set it
1866  * also if inum not known and IS form - must pass 0
1867  */
numexpr_disp(struct expr_t * ndp,int32 inum)1868 static void numexpr_disp(struct expr_t *ndp, int32 inum)
1869 {
1870  word32 *ap, *bp, *wp;
1871  int32 wlen, base;
1872  double *dp, d1;
1873  char s1[RECLEN];
1874 
1875  if (ndp == NULL)
1876   {
1877    __pv_warn(515, "INTERNAL - trying to print NULL expr.");
1878    __adds("NULL expr.");
1879    return;
1880   }
1881  wlen = wlen_(ndp->szu.xclen);
1882  switch ((byte) ndp->optyp) {
1883   case ISNUMBER:
1884    wp = &(__contab[ndp->ru.xvi]);
1885    ap = &(wp[2*wlen*inum]);
1886    break;
1887   case NUMBER:
1888    ap = &(__contab[ndp->ru.xvi]);
1889    break;
1890   case ISREALNUM:
1891    /* SJM 05/05/05 - must multiply inum by 2 since real cons now use a/bs */
1892    dp = (double *) &(__contab[ndp->ru.xvi + 2*inum]);
1893    d1 = *dp;
1894 disp_real:
1895    sprintf(s1, "%g", d1);
1896    __adds(s1);
1897    return;
1898  case REALNUM:
1899    dp = (double *) &(__contab[ndp->ru.xvi]);
1900    d1 = *dp;
1901    goto disp_real;
1902   default: __case_terr(__FILE__, __LINE__); return;
1903  }
1904  if (ndp->is_string)
1905   {
1906    /* if is string on, know will not contain x/z bits, input as ".." */
1907    /* know cur sofs saved and restored by caller */
1908    __xline_vval_to_cstr(ap, ndp->szu.xclen, TRUE, TRUE, TRUE);
1909    return;
1910   }
1911  bp = &(ap[wlen]);
1912  if (__force_base == BNONE) base = ndp->ibase; else base = __force_base;
1913  switch ((byte) base) {
1914   case BDEC:
1915    if ((ndp->unsiznum || ndp->szu.xclen == WBITS)
1916     && vval_is0_(bp, ndp->szu.xclen))
1917     {
1918      /* unsized (no 'd) decimal always signed */
1919      sdispd(ap, bp, ndp->szu.xclen, TRUE, TRUE);
1920      break;
1921     }
1922    if (ndp->sizdflt) __adds("'d");
1923    else { sprintf(s1, "%d'd", ndp->szu.xclen); __adds(s1); }
1924    /* if no. even decimal has 'd, always word32 and trimmed */
1925    sdispd(ap, bp, ndp->szu.xclen, TRUE, FALSE);
1926    break;
1927   case BHEX:
1928    /* know rest all word32 */
1929    /* [size]'h prefixed number always trimmed */
1930    if (ndp->sizdflt) __adds("'h");
1931    else { sprintf(s1, "%d'h", ndp->szu.xclen); __adds(s1); }
1932    sdisph(ap, bp, ndp->szu.xclen, TRUE);
1933    break;
1934   case BOCT:
1935    if (ndp->sizdflt) __adds("'o");
1936    else { sprintf(s1, "%d'o", ndp->szu.xclen); __adds(s1); }
1937    sdispo(ap, bp, ndp->szu.xclen, TRUE);
1938    break;
1939   case BBIN:
1940    if (ndp->sizdflt) __adds("'b");
1941    else { sprintf(s1, "%d'b", ndp->szu.xclen); __adds(s1); }
1942    __sdispb(ap, bp, ndp->szu.xclen, TRUE);
1943    break;
1944   default:
1945    __case_terr(__FILE__, __LINE__);
1946    return;
1947  }
1948 }
1949 
1950 /*
1951  * truncate __exprline to newsize - __cur_sofs points to end
1952  * know truncation must be less than RECLEN (512)
1953  */
__trunc_exprline(int32 newsize,int32 from_front)1954 extern void __trunc_exprline(int32 newsize, int32 from_front)
1955 {
1956  if (__cur_sofs < newsize) return;
1957 
1958  if (from_front)
1959   {
1960    char s1[RECLEN];
1961 
1962    strcpy(s1, "...");
1963    strcat(s1, &(__exprline[__cur_sofs - newsize - 3]));
1964    strcpy(__exprline, s1);
1965    __cur_sofs = newsize;
1966   }
1967  else
1968   {
1969    __cur_sofs = newsize;
1970    __exprline[__cur_sofs] = '\0';
1971    __exprline[__cur_sofs - 3] = '.';
1972    __exprline[__cur_sofs - 2] = '.';
1973    __exprline[__cur_sofs - 1] = '.';
1974   }
1975 }
1976 
1977 /*
1978  * truncate a cstring know new size inside allocated size of string
1979  * this removes prefix when truncation needed
1980  * know truncation must be less than RECLEN (512)
1981  */
__trunc_cstr(char * s,int32 newsize,int32 from_front)1982 extern void __trunc_cstr(char *s, int32 newsize, int32 from_front)
1983 {
1984  int32 slen;
1985 
1986  if ((slen = strlen(s)) < newsize) return;
1987 
1988  if (from_front)
1989   {
1990    char s1[RECLEN];
1991 
1992    strcpy(s1, "...");
1993    /* since string starts at 0 to start at pos. k index is k - 1 */
1994    strcat(s1, &(s[slen - newsize - 3 - 1]));
1995    strcpy(s, s1);
1996   }
1997  else
1998   {
1999    s[slen - 3] = '.';
2000    s[slen - 2] = '.';
2001    s[slen - 1] = '.';
2002    s[slen] = '\0';
2003   }
2004 }
2005 
2006 /*
2007  * PRINTING COPY INTO STRING INTERFACE ROUTINES TO NORMAL PRINT
2008  */
2009 
2010 /*
2011  * version of regab to string that gets format from expression
2012  * this handles string constants in both forms
2013  * LOOKATME - how does this routine differ from num expr disp
2014  */
__xregab_tostr(char * s,word32 * ap,word32 * bp,int32 blen,struct expr_t * xp)2015 extern char *__xregab_tostr(char *s, word32 *ap, word32 *bp, int32 blen,
2016  struct expr_t *xp)
2017 {
2018  int32 signv, base;
2019 
2020  /* if expr. is string, write as unquoted string */
2021  if (xp->is_string)
2022   {
2023    __strab_tostr(s, ap, xp->szu.xclen, FALSE, TRUE);
2024    return(s);
2025   }
2026  base = BHEX;
2027  signv = FALSE;
2028  if (xp->is_real) { base = BDBLE; signv = TRUE; }
2029  else
2030   {
2031    /* can com close to constant number format duplication */
2032    if  (xp->optyp == NUMBER || xp->optyp == ISNUMBER)
2033     {
2034      if (xp->unsiznum) { base = BDEC; signv = TRUE; }
2035      else base = xp->ibase;
2036     }
2037    /* notice if simple varible signed, has sign on */
2038    if (xp->has_sign) { base = BDEC; signv = TRUE; }
2039   }
2040  __regab_tostr(s, ap, bp, blen, base, signv);
2041  return(s);
2042 }
2043 
2044 /*
2045  * version of regab to string that gets format from parameter ncomp record
2046  * this handles string constants in both forms
2047  */
__pregab_tostr(char * s,word32 * ap,word32 * bp,struct net_t * np)2048 extern char *__pregab_tostr(char *s, word32 *ap, word32 *bp, struct net_t *np)
2049 {
2050  int32 signv, base;
2051 
2052  /* DBG remove --- */
2053  if (np->nrngrep != NX_CT || !np->n_isaparam)
2054   __misc_terr(__FILE__, __LINE__);
2055  /* --- */
2056 
2057  /* if original param rhs string, write as unquoted string */
2058  if (np->nu.ct->pstring)
2059   {
2060    __strab_tostr(s, ap, np->nwid, FALSE, TRUE);
2061    return(s);
2062   }
2063  base = BHEX;
2064  signv = FALSE;
2065  if (np->ntyp == N_REAL) { base = BDBLE; signv = TRUE; }
2066  else
2067   {
2068    base = np->nu.ct->pbase;
2069    if (np->n_signed) signv = TRUE; else signv = FALSE;
2070   }
2071  __regab_tostr(s, ap, bp, np->nwid, base, signv);
2072  return(s);
2073 }
2074 
2075 /*
2076  * convert reg. ab style value to string - always trim
2077  * can always print value by loading to stk and calling this
2078  *
2079  * notice this prints passed string not chp of next pos.
2080  * string passed must be at least RECLEN
2081  */
__regab_tostr(char * s,word32 * ap,word32 * bp,int32 blen,int32 base,int32 hassign)2082 extern char *__regab_tostr(char *s, word32 *ap, word32 *bp, int32 blen, int32 base,
2083  int32 hassign)
2084 {
2085  int32 sav_sofs = __cur_sofs;
2086 
2087  __regab_disp(ap, bp, blen, base, TRUE, hassign);
2088  /* here keeps low part if trunc needed */
2089  __trunc_cstr(&(__exprline[sav_sofs]), MSGTRUNCLEN, TRUE);
2090  strcpy(s, &(__exprline[sav_sofs]));
2091  __cur_sofs = sav_sofs;
2092  __exprline[__cur_sofs] = '\0';
2093  return(s);
2094 }
2095 
2096 /*
2097  * version of regab to string that allows turning trim off
2098  */
__regab2_tostr(char * s,word32 * ap,word32 * bp,int32 blen,int32 base,int32 hassign,int32 trim)2099 extern char *__regab2_tostr(char *s, word32 *ap, word32 *bp, int32 blen, int32 base,
2100  int32 hassign, int32 trim)
2101 {
2102  int32 sav_sofs = __cur_sofs;
2103 
2104  __regab_disp(ap, bp, blen, base, trim, hassign);
2105  __trunc_cstr(&(__exprline[sav_sofs]), MSGTRUNCLEN, TRUE);
2106  strcpy(s, &(__exprline[sav_sofs]));
2107  __cur_sofs = sav_sofs;
2108  __exprline[__cur_sofs] = '\0';
2109  return(s);
2110 }
2111 
2112 /*
2113  * special display routine that takes base as argrument
2114  * but does not output sizes
2115  * to print value subrange caller must adjust passed ap and bp and blen
2116  *
2117  * notice if can be using exprline caller must save
2118  */
__regab_disp(word32 * ap,word32 * bp,int32 blen,int32 base,int32 trim,int32 hassign)2119 extern void __regab_disp(word32 *ap, word32 *bp, int32 blen, int32 base, int32 trim,
2120  int32 hassign)
2121 {
2122  char s1[RECLEN];
2123 
2124  switch ((byte) base) {
2125   case BBIN: __sdispb(ap, bp, blen, trim); break;
2126   case BOCT: sdispo(ap, bp, blen, trim); break;
2127   case BDEC: sdispd(ap, bp, blen, trim, hassign); break;
2128   case BHEX: sdisph(ap, bp, blen, trim); break;
2129   case BDBLE:
2130    {
2131     double d1;
2132 
2133     memcpy(&d1, ap, sizeof(double));
2134     /* here always try to trim to match OVIsim */
2135     sprintf(s1, "%g", d1);
2136     __adds(s1);
2137    }
2138    break;
2139   default:
2140    __pv_err(768, "numeric display format illegal (value %d)", base);
2141  }
2142 }
2143 
2144 /*
2145  * convert strength style value to string
2146  * can always print value by loading to stk and calling this
2147  * s must be at least RECLEN wide
2148  */
__st_regab_tostr(char * s,byte * sbp,int32 blen)2149 extern char *__st_regab_tostr(char *s, byte *sbp, int32 blen)
2150 {
2151  int32 sav_sofs = __cur_sofs;
2152 
2153  st_regab_disp(sbp, blen);
2154  /* truncate from front if needed - keep low bits */
2155  __trunc_cstr(&(__exprline[sav_sofs]), MSGTRUNCLEN, TRUE);
2156  strcpy(s, &(__exprline[sav_sofs]));
2157  __cur_sofs = sav_sofs;
2158  __exprline[__cur_sofs] = '\0';
2159  return(s);
2160 }
2161 
2162 /*
2163  * display a strength value into expr line
2164  */
st_regab_disp(byte * sbp,int32 blen)2165 static void st_regab_disp(byte *sbp, int32 blen)
2166 {
2167  register int32 i;
2168  char s1[RECLEN];
2169 
2170  /* maybe need some kind of separator here */
2171  for (i = blen - 1;; i--)
2172   {
2173    __adds(__to_vvstnam(s1, (word32) sbp[i]));
2174    if (i <= 0) break;
2175    addch_(' ');
2176   }
2177  __exprline[__cur_sofs] = '\0';
2178 }
2179 
2180 /*
2181  * to an expression wire range - x1 must be != NULL
2182  * uses end of expr line in case in use
2183  */
__msgtox_wrange(char * s,struct expr_t * x1,struct expr_t * x2)2184 extern char *__msgtox_wrange(char *s, struct expr_t *x1, struct expr_t *x2)
2185 {
2186  int32 sav_sofs = __cur_sofs;
2187 
2188  tox_wrange((FILE *) NULL, x1, x2);
2189  __trunc_cstr(&(__exprline[sav_sofs]), MSGTRUNCLEN, FALSE);
2190  strcpy(s, &(__exprline[sav_sofs]));
2191  __cur_sofs = sav_sofs;
2192  __exprline[__cur_sofs] = '\0';
2193  return(s);
2194 }
2195 
2196 /*
2197  * version of expr to string that truncates for messages
2198  * this dumps unevaluated expression not value
2199  */
__msgexpr_tostr(char * s,struct expr_t * ndp)2200 extern char *__msgexpr_tostr(char *s, struct expr_t *ndp)
2201 {
2202  int32 sav_sofs = __cur_sofs;
2203 
2204  dmp_expr((FILE *) NULL, ndp);
2205  __trunc_cstr(&(__exprline[sav_sofs]), MSGTRUNCLEN, FALSE);
2206  strcpy(s, &(__exprline[sav_sofs]));
2207  __cur_sofs = sav_sofs;
2208  __exprline[__cur_sofs] = '\0';
2209  return(s);
2210 }
2211 
2212 /*
2213  * FOR DEBUGGING VARIABLE DUMP ROUTINES
2214  */
2215 
2216 /*
2217  * load a value
2218  */
2219 
2220 /*
2221  * convert a variable to a string
2222  */
__var_tostr(char * s,struct net_t * np,int32 i1,int32 i2,int32 base)2223 extern char *__var_tostr(char *s, struct net_t *np, int32 i1, int32 i2, int32 base)
2224 {
2225  int32 sav_sofs = __cur_sofs;
2226 
2227  /* use sign from var. */
2228  __disp_var(np, i1, i2, base, '?');
2229  /* truncate from front if needed - keep low bits */
2230  __trunc_cstr(&(__exprline[sav_sofs]), MSGTRUNCLEN, TRUE);
2231  strcpy(s, &(__exprline[sav_sofs]));
2232  __cur_sofs = sav_sofs;
2233  __exprline[__cur_sofs] = '\0';
2234  return(s);
2235 }
2236 
2237 /*
2238  * display variable (possibly part or bit select range out of [i1,i2]) with
2239  * base base and force signed '-' or word32 ' ' or use variable sign
2240  * in other case
2241  *
2242  * for array - may need to be called multiple times but will index one
2243  * entire array if i1==i2 and in range
2244  *
2245  * expects __cur_sofs to be set and builds in expr line
2246  */
__disp_var(struct net_t * np,int32 i1,int32 i2,int32 base,char vsign_ovride)2247 extern void __disp_var(struct net_t *np, int32 i1, int32 i2, int32 base,
2248  char vsign_ovride)
2249 {
2250  int32 arrwid, hassign, netwid;
2251  double d1;
2252  struct xstk_t *xsp;
2253  char s1[RECLEN];
2254 
2255  /* need var. for net wid since may change width for printing below */
2256  netwid = np->nwid;
2257  /* case 1: strength */
2258  if (np->n_stren) { disp_stvar(np, i1, i2); return; }
2259 
2260  /* case 2: real variable (no arrays of reals) */
2261  if (np->ntyp == N_REAL)
2262   {
2263    memcpy(&d1, &(np->nva.wp[2*__inum]), sizeof(double));
2264    sprintf(s1, "%g", d1);
2265    __adds(s1);
2266    return;
2267   }
2268  hassign = FALSE;
2269  /* case 3: array - must be 1 index */
2270  if (np->n_isarr)
2271   {
2272    /* must have exactly one index */
2273    arrwid = __get_arrwide(np);
2274    if (i1 == i2 && i1 == -1)
2275     {
2276      strcpy(s1, "[first of entire array]: ");
2277      __adds(s1);
2278      i1 = 0;
2279     }
2280    else
2281     {
2282      if (i1 < 0 || i1 != i2 || i1 >= arrwid) __arg_terr(__FILE__, __LINE__);
2283     }
2284    push_xstk_(xsp, netwid);
2285    __ld_arr_val(xsp->ap, xsp->bp, np->nva, arrwid, netwid, i1);
2286    if (netwid > WBITS) goto do_print;
2287    hassign = get_ovrsign(np, vsign_ovride);
2288    goto do_print;
2289   }
2290  /* case 4: scalar or all of vector */
2291  /* case 4a: all of variable */
2292  if (i1 == -1)
2293   {
2294    push_xstk_(xsp, netwid);
2295    __ld_wire_val(xsp->ap, xsp->bp, np);
2296    if (netwid > WBITS) goto do_print;
2297    hassign = get_ovrsign(np, vsign_ovride);
2298    goto do_print;
2299   }
2300  /* 4b part of var. - must be vector do select */
2301  else
2302   {
2303    if (!np->n_isavec) __case_terr(__FILE__, __LINE__);
2304    /* case 4b-a: bit select */
2305    if (i1 == i2)
2306     {
2307      if (i1 < 0 || i1 >= netwid) __case_terr(__FILE__, __LINE__);
2308      push_xstk_(xsp, 1);
2309      __ld_bit(xsp->ap, xsp->bp, np, i1);
2310      netwid = 1;
2311      goto do_print;
2312     }
2313    /* case 4b-b: part select */
2314    if (i1 < 0 || i2 < 0 || i1 < i2 || i1 >= netwid)
2315     __case_terr(__FILE__, __LINE__);
2316    push_xstk_(xsp, netwid);
2317    /* notice here nwid must be width of net */
2318    __ld_psel(xsp->ap, xsp->bp, np, i1, i2);
2319    /* but display nwid as width of part select */
2320    netwid = i1 - i2 + 1;
2321   }
2322 do_print:
2323  __regab_disp(xsp->ap, xsp->bp, netwid, base, TRUE, hassign);
2324  __pop_xstk();
2325 }
2326 
2327 /*
2328  * display a possible section of a strength variable (from the wire)
2329  */
disp_stvar(struct net_t * np,int32 i1,int32 i2)2330 static void disp_stvar(struct net_t *np, int32 i1, int32 i2)
2331 {
2332  register int32 i;
2333  char s1[RECLEN];
2334 
2335  if (i1 == -1) { i1 = np->nwid - 1; i2 = 0; }
2336  /* maybe need some kind of separator here */
2337  for (i = i1; i >= i2; i--)
2338   {
2339    __adds(__to_vvstnam(s1, (word32) np->nva.bp[i]));
2340    if (i > i2) addch_(' ');
2341   }
2342  __exprline[__cur_sofs] = '\0';
2343 }
2344 
2345 /*
2346  * return sign by testing over-ride variable - if not use wire sign
2347  */
get_ovrsign(struct net_t * np,char ovride)2348 static int32 get_ovrsign(struct net_t *np, char ovride)
2349 {
2350  if (ovride == '-') return(TRUE);
2351  else if (ovride == ' ') return(FALSE);
2352  return(np->n_signed == 1);
2353 }
2354 
2355 /*
2356  * dump all of a array for inst ifr to ito
2357  * only called if debug on and inst ptr set
2358  *
2359  */
__dmp_arr_all(struct net_t * np,int32 ifr,int32 ito)2360 extern void __dmp_arr_all(struct net_t *np, int32 ifr, int32 ito)
2361 {
2362  if (!np->n_isarr) __arg_terr(__FILE__, __LINE__);
2363  dmp_arr_insts(np, ifr, ito);
2364 }
2365 
2366 /*
2367  * dmp instance ifr to ito of arr var. np from mfr to mto
2368  * mfr and mto assume normalized h:0 form not actual range
2369  */
dmp_arr_insts(struct net_t * np,int32 ifr,int32 ito)2370 static void dmp_arr_insts(struct net_t *np, int32 ifr, int32 ito)
2371 {
2372  register int32 i;
2373  int32 ri1, ri2, arrwid;
2374 
2375  if (!np->n_isarr) __arg_terr(__FILE__, __LINE__);
2376  __getarr_range(np, &ri1, &ri2, &arrwid);
2377  for (i = ifr; i <= ito; i++) dmp_arr(np, ri1, ri2, i);
2378 }
2379 
2380 /*
2381  * dump an array from index mifr to mito for instance inum
2382  */
dmp_arr(struct net_t * np,int32 mifr,int32 mito,int32 inum)2383 static void dmp_arr(struct net_t *np, int32 mifr, int32 mito, int32 inum)
2384 {
2385  register int32 mi;
2386  int32 arrwid, ri1, ri2, h0_arri;
2387  struct xstk_t *xsp;
2388 
2389  if (!np->n_isarr) __arg_terr(__FILE__, __LINE__);
2390  __getarr_range(np, &ri1, &ri2, &arrwid);
2391 
2392  __push_wrkitstk(__inst_mod, inum);
2393  push_xstk_(xsp, np->nwid);
2394  for (mi = mifr; mi <= mito; mi++)
2395   {
2396    /* FIXME - think this is wrong should unnormalize? */
2397    h0_arri = normalize_ndx_(mi, ri1, ri2);
2398    __ld_arr_val(xsp->ap, xsp->bp, np->nva, arrwid, np->nwid, h0_arri);
2399    __dbg_msg("array %s inst %d width %d index %d = %s\n", np->nsym->synam,
2400     inum, np->nwid, mi, __regab_tostr(__xs, xsp->ap, xsp->bp, np->nwid,
2401     BHEX, FALSE));
2402   }
2403  __pop_xstk();
2404  __pop_wrkitstk();
2405 }
2406 
2407 /*
2408  * FOR DEBUGGING ROUTINES TO DUMP NET PIN LISTS
2409  */
2410 
2411 /*
2412  * dump the np and dce lists for one module
2413  * only called if debug flag on
2414  */
__dmpmod_nplst(struct mod_t * mdp,int32 dces_only)2415 extern void __dmpmod_nplst(struct mod_t *mdp, int32 dces_only)
2416 {
2417  register int32 ni;
2418  register struct net_t *np;
2419  register struct task_t *tskp;
2420 
2421  /* DBG remove ---
2422  --   int32 ii;
2423  if (__debug_flg)
2424   {
2425    for (ii = 0; ii < __numtopm; ii++) __dmp_itree(__it_roots[ii]);
2426   }
2427  --- */
2428 
2429  if (dces_only)
2430   __dbg_msg("++> module %s event list\n", mdp->msym->synam);
2431  else __dbg_msg("++> module %s net pin and event lists\n", mdp->msym->synam);
2432 
2433  if (mdp->mnnum != 0)
2434   {
2435    for (ni = 0, np = &(mdp->mnets[0]); ni < mdp->mnnum; ni++, np++)
2436     dmp1n_nplst(mdp, np, dces_only);
2437   }
2438  for (tskp = mdp->mtasks; tskp != NULL; tskp = tskp->tsknxt)
2439   {
2440    __dbg_msg("**> task %s net pin list\n", tskp->tsksyp->synam);
2441    if (tskp->trnum != 0)
2442     {
2443      for (ni = 0, np = &(tskp->tsk_regs[0]); ni < tskp->trnum; ni++, np++)
2444       dmp1n_nplst(mdp, np, dces_only);
2445     }
2446   }
2447 }
2448 
2449 /*
2450  * dump the net pin list elements for 1 net
2451  */
dmp1n_nplst(struct mod_t * mdp,struct net_t * np,int32 dces_only)2452 static void dmp1n_nplst(struct mod_t *mdp, struct net_t *np, int32 dces_only)
2453 {
2454  register struct net_pin_t *npp;
2455  register struct dcevnt_t *dcep;
2456  int32 first_time;
2457  char s1[RECLEN];
2458 
2459  if (np->ntyp == N_EVENT)
2460   {
2461    __dbg_msg("==> event %s - no net loads and no drivers\n",
2462     np->nsym->synam);
2463    __dbg_msg("==> %s %s size %d with %d event ctrls:\n",
2464     __to_wtnam(s1, np), np->nsym->synam, np->nwid,
2465     __cnt_dcelstels(np->dcelst));
2466    goto try_dces;
2467   }
2468 
2469  __dbg_msg("==> %s %s size %d with %d drivers, %d loads and %d event ctrls:\n",
2470   __to_wtnam(s1, np), np->nsym->synam, np->nwid,
2471   cnt_nplstels(np->ndrvs), cnt_nplstels(np->nlds),
2472   __cnt_dcelstels(np->dcelst));
2473 
2474  if (dces_only) goto try_dces;
2475 
2476  first_time = TRUE;
2477  for (npp = np->ndrvs; npp != NULL; npp = npp->npnxt)
2478   {
2479    if (first_time) { __dbg_msg("  ++drivers ->\n"); first_time = FALSE; }
2480    __dmp1_nplstel(mdp, np, npp);
2481   }
2482  first_time = TRUE;
2483  for (npp = np->nlds; npp != NULL; npp = npp->npnxt)
2484   {
2485    if (first_time) { __dbg_msg("  ++loads ->\n"); first_time = FALSE; }
2486    __dmp1_nplstel(mdp, np, npp);
2487   }
2488 
2489 try_dces:
2490  first_time = TRUE;
2491  /* notice #<num> delays are just scheduled no triggering */
2492  for (dcep = np->dcelst; dcep != NULL; dcep = dcep->dcenxt)
2493   {
2494    if (dcep->dce_off) continue;
2495 
2496    if (first_time)
2497     { __dbg_msg("  ++event controls ->\n"); first_time = FALSE; }
2498    __dmp1_dcelstel(mdp, dcep);
2499   }
2500 }
2501 
2502 /*
2503  * count drivers or loads (inst. specific counted for each inst.)
2504  * SJM 07/25/01 - although MIPD is a load, it is not counted
2505  */
cnt_nplstels(register struct net_pin_t * npp)2506 static int32 cnt_nplstels(register struct net_pin_t *npp)
2507 {
2508  int32 i;
2509 
2510  for (i = 0; npp != NULL; npp = npp->npnxt)
2511   {
2512    if (npp->npntyp != NP_MIPD_NCHG) i++;
2513   }
2514  return(i);
2515 }
2516 
2517 /*
2518  * count delay control/dump vars events
2519  */
__cnt_dcelstels(register struct dcevnt_t * dcep)2520 extern int32 __cnt_dcelstels(register struct dcevnt_t *dcep)
2521 {
2522  int32 i;
2523 
2524  for (i = 0; dcep != NULL; dcep = dcep->dcenxt)
2525   {
2526    if (dcep->dce_off) continue;
2527    i++;
2528   }
2529  return(i);
2530 }
2531 
2532 /*
2533  * dump 1 net pin list element
2534  *
2535  * includes the removed after tran chan build removed npps
2536  * mdp only need for mod port or instance conns npps
2537  */
__dmp1_nplstel(struct mod_t * mdp,struct net_t * np,struct net_pin_t * npp)2538 extern void __dmp1_nplstel(struct mod_t *mdp, struct net_t *np,
2539  struct net_pin_t *npp)
2540 {
2541  word32 stval;
2542  struct inst_t *ip;
2543  struct gate_t *gp;
2544  struct mod_t *imdp, *tmp_mdp;
2545  struct conta_t *cap;
2546  struct tfrec_t *tfrp;
2547  struct tchk_t *tcp;
2548  struct spcpth_t *pthp;
2549  struct npaux_t *npauxp;
2550  struct itree_t *itp;
2551  char s1[RECLEN], s2[RECLEN], s3[RECLEN], s4[RECLEN];
2552 
2553  if ((npauxp = npp->npaux) != NULL && npauxp->nbi1 != -1)
2554   {
2555    if (npauxp->lcbi1 == -1)
2556     __dbg_msg("    [%d:%d]: ", npauxp->nbi1, npauxp->nbi2.i);
2557    else __dbg_msg("    [%d:%d] (lhs cat rhs [%d:%d]): ",
2558     npauxp->nbi1, npauxp->nbi2.i, npauxp->lcbi1, npauxp->lcbi2);
2559   }
2560  else __dbg_msg("    ");
2561 
2562  /* handle proc type - need a module (can by any) */
2563  switch ((byte) npp->npproctyp) {
2564   case NP_PROC_INMOD:
2565    tmp_mdp = mdp;
2566    sprintf(s3, "(IN=%s)", tmp_mdp->msym->synam); break;
2567   case NP_PROC_GREF:
2568    tmp_mdp = npauxp->npu.npgrp->gin_mdp;
2569    sprintf(s3, "(XMR %s mod=%s)", npauxp->npu.npgrp->gnam,
2570     tmp_mdp->msym->synam);
2571    break;
2572   case NP_PROC_FILT:
2573    itp = npauxp->npdownitp;
2574    tmp_mdp = itp->itip->imsym->el.emdp;
2575    sprintf(s3, "(INST-LOC=%s(%s))", __msg2_blditree(__xs, itp),
2576     tmp_mdp->msym->synam);
2577    break;
2578   default: __case_terr(__FILE__, __LINE__); return;
2579  }
2580  switch ((byte) npp->np_xmrtyp) {
2581   case XNP_LOC: strcpy(s4, "-LOCAL-"); break;
2582   case XNP_DOWNXMR: strcpy(s4, "-DOWNXMR-"); break;
2583   case XNP_RTXMR: strcpy(s4, "-RTXMR-"); break;
2584   case XNP_UPXMR: strcpy(s4, "-UPXMR-"); break;
2585   default: __case_terr(__FILE__, __LINE__); return;
2586  }
2587  switch ((byte) npp->npntyp) {
2588   case NP_ICONN: case NP_BIDICONN:
2589    /* current mod is target but need ref module (of first inst?) */
2590    /* DBG remove -- */
2591    if (npp->elnpp.eii >= tmp_mdp->minum || tmp_mdp->minum == 0)
2592     __arg_terr(__FILE__, __LINE__);
2593    /* --- */
2594    /* notice normally actual instance relative to itree place */
2595    ip = &(tmp_mdp->minsts[npp->elnpp.eii]);
2596    __dbg_msg("inst. %s type %s %s %s port %d at %s\n", ip->isym->synam,
2597     ip->imsym->synam, s3, s4, npp->obnum + 1,
2598     __bld_lineloc(__xs, ip->isym->syfnam_ind, ip->isym->sylin_cnt));
2599    break;
2600   case NP_PB_ICONN:
2601    ip = &(tmp_mdp->minsts[npp->elnpp.eii]);
2602    __dbg_msg("inst. %s type %s %s %s port %d bit %d at %s\n",
2603     ip->isym->synam, ip->imsym->synam, s3, s4, npp->obnum + 1,
2604     npp->pbi, __bld_lineloc(__xs, ip->isym->syfnam_ind, ip->isym->sylin_cnt));
2605    break;
2606   case NP_GATE: case NP_TRANIF: case NP_TRAN:
2607    gp = npp->elnpp.egp;
2608    __dbg_msg("gate %s type %s %s %s port %d at %s\n", gp->gsym->synam,
2609     gp->gmsym->synam, s3, s4, npp->obnum + 1, __bld_lineloc(__xs,
2610     gp->gsym->syfnam_ind, gp->gsym->sylin_cnt));
2611    break;
2612   case NP_CONTA:
2613    cap = npp->elnpp.ecap;
2614    if (cap->ca_pb_sim)
2615     {
2616      __dbg_msg("per bit continuous assign bit %d at %s %s %s\n", npp->pbi,
2617       __bld_lineloc(__xs, cap->casym->syfnam_ind, cap->casym->sylin_cnt),
2618       s3, s4);
2619     }
2620    else
2621     {
2622      __dbg_msg("continuous assign at %s %s %s\n", __bld_lineloc(__xs,
2623       cap->casym->syfnam_ind, cap->casym->sylin_cnt), s3, s4);
2624     }
2625    break;
2626   case NP_TFRWARG:
2627    tfrp = npp->elnpp.etfrp;
2628    if (tfrp->tf_func) strcpy(s1, "function"); else strcpy(s1, "task");
2629    __dbg_msg("tf_ %s %s read/write argument (pos. %d) at %s\n", s3, s4,
2630     npp->obnum, __bld_lineloc(__xs, tfrp->tffnam_ind, tfrp->tflin_cnt));
2631    break;
2632   case NP_VPIPUTV:
2633    if (npp->npaux == NULL || npp->npaux->nbi1 == -1)
2634     strcpy(__xs, "vpiWireDriver");
2635    else strcpy(__xs, "vpiWireBitDriver");
2636    __dbg_msg("vpi_ added %s for net %s %s %s\n", __xs, np->nsym->synam, s3,
2637     s4);
2638    break;
2639   case NP_MDPRT: case NP_BIDMDPRT:
2640    imdp = npp->elnpp.emdp;
2641    __dbg_msg("module %s %s %s %s port %s (pos. %d) at %s\n", imdp->msym->synam,
2642     s3, s4, __to_ptnam(s1, np->iotyp),
2643     __to_mpnam(s2, imdp->mpins[npp->obnum].mpsnam), npp->obnum + 1,
2644     __bld_lineloc(__xs, mdp->msym->syfnam_ind, mdp->msym->sylin_cnt));
2645    break;
2646   case NP_PB_MDPRT:
2647    imdp = npp->elnpp.emdp;
2648    __dbg_msg("module %s %s %s %s port %s (pos. %d) bit %d at %s\n",
2649     imdp->msym->synam, s3, s4, __to_ptnam(s1, np->iotyp),
2650     __to_mpnam(s2, imdp->mpins[npp->obnum].mpsnam), npp->obnum + 1,
2651     npp->pbi, __bld_lineloc(__xs, mdp->msym->syfnam_ind,
2652     mdp->msym->sylin_cnt));
2653    break;
2654   case NP_MIPD_NCHG:
2655    __dbg_msg("MIPD delay device in module %s for %s %s\n",
2656     mdp->msym->synam, __to_ptnam(s1, np->iotyp), np->nsym->synam);
2657    break;
2658   case NP_PULL:
2659    gp = npp->elnpp.egp;
2660    stval = gp->g_stval << 2;
2661    if (npp->pullval == 1) stval |= 1;
2662    __dbg_msg("%s to %s on %s at %s\n",
2663     gp->gmsym->synam, __to_vvstnam(s1, (word32) stval),
2664     __msgexpr_tostr(__xs, gp->gpins[npp->obnum]), __bld_lineloc(__xs2,
2665     gp->gsym->syfnam_ind, gp->gsym->sylin_cnt));
2666    break;
2667   case NP_TCHG:
2668    switch ((byte) npp->chgsubtyp) {
2669     case NPCHG_TCSTART:
2670      tcp = npp->elnpp.etchgp->chgu.chgtcp;
2671      __dbg_msg("%s timing check first (reference) change line %s\n",
2672       __to_tcnam(__xs, tcp->tchktyp), __bld_lineloc(__xs2,
2673       tcp->tcsym->syfnam_ind, tcp->tcsym->sylin_cnt));
2674      break;
2675     case NPCHG_TCCHK:
2676      tcp = npp->elnpp.echktchgp->startchgp->chgu.chgtcp;
2677      __dbg_msg("%s timing check 2nd (check) change line %s\n",
2678       __to_tcnam(__xs, tcp->tchktyp), __bld_lineloc(__xs2,
2679       tcp->tcsym->syfnam_ind, tcp->tcsym->sylin_cnt));
2680      break;
2681     case NPCHG_PTHSRC:
2682      pthp = npp->elnpp.etchgp->chgu.chgpthp;
2683      __dbg_msg("delay path source change line %s\n",
2684       __bld_lineloc(__xs, pthp->pthsym->syfnam_ind,
2685       pthp->pthsym->sylin_cnt));
2686      break;
2687     default: __case_terr(__FILE__, __LINE__);
2688    }
2689    break;
2690   default:
2691    __gfterr(302, np->nsym->syfnam_ind, np->nsym->sylin_cnt,
2692     "unknown net pin value %d", npp->npntyp);
2693  }
2694 }
2695 
2696 /*
2697  * dump 1 net pin list element
2698  *
2699  * this does not dump base dvcodes because caller does not know if net
2700  * in task or module
2701  */
__dmp1_dcelstel(struct mod_t * mdp,struct dcevnt_t * dcep)2702 extern void __dmp1_dcelstel(struct mod_t *mdp, struct dcevnt_t *dcep)
2703 {
2704  struct st_t *stp;
2705  struct delctrl_t *dctp;
2706  char s1[RECLEN], s2[RECLEN], s3[RECLEN];
2707 
2708  if (dcep->dce_edge)
2709   {
2710    /* access value */
2711    sprintf(s1, " %s (first instance old value %s)",
2712     __to_edgenam(s2, dcep->dce_edgval), __to_vvnam(s3,
2713     get_dce_edgeval(mdp, dcep)));
2714   }
2715  else strcpy(s1, "");
2716  if (dcep->dce_off) __dbg_msg("*OFF*");
2717  switch ((byte) dcep->dce_typ) {
2718   case DCE_RNG_INST: case DCE_INST:
2719    __dbg_msg("    [%d:%d]: event control net %s trigger: %s",
2720     dcep->dci1, dcep->dci2.i, dcep->dce_np->nsym->synam, s1);
2721    dctp = dcep->st_dctrl;
2722    /* DBG remove --- */
2723    if (dctp->dctyp < DC_EVENT || dctp->dctyp > DC_WAITEVENT)
2724     __misc_terr(__FILE__, __LINE__);
2725    /* --- */
2726    stp = dcep->st_dctrl->actionst;
2727    if (stp == NULL) __dbg_msg("\n");
2728    else __dbg_msg(" at %s\n", __bld_lineloc(s2, stp->stfnam_ind,
2729     stp->stlin_cnt));
2730    break;
2731   case DCE_RNG_MONIT:
2732   case DCE_MONIT:
2733    /* maybe need more info here */
2734    __dbg_msg("    [%d:%d]: monitor net %s trigger\n", dcep->dci1,
2735     dcep->dci2.i, dcep->dce_np->nsym->synam);
2736    /* FIXME - only defined for monitor - should also dump for rng form */
2737    /* LOOKATME - can this happen since no more col. */
2738    if (dcep->dce_1inst)
2739     {
2740      __dbg_msg("   (xmr match: target %s - down src: %s)\n",
2741       __msg2_blditree(s1, dcep->dce_matchitp), __msg2_blditree(s2,
2742       dcep->dce_refitp));
2743     }
2744    break;
2745   case DCE_RNG_QCAF: case DCE_QCAF:
2746    __dbg_msg("    [%d:%d]: quasi-continuous assign or force load net %s\n",
2747     dcep->dci1, dcep->dci2.i, dcep->dce_np->nsym->synam);
2748    break;
2749   case DCE_RNG_PVC: case DCE_PVC:
2750    __dbg_msg("    [%d:%d]: tf_ parameter value change load net %s\n",
2751     dcep->dci1, dcep->dci2.i, dcep->dce_np->nsym->synam);
2752    break;
2753   default: __case_terr(__FILE__, __LINE__);
2754  }
2755 }
2756 
2757 /*
2758  * load a dce edge value with strength removed if attached to stren wire
2759  * know 1 bit and does not use itree loc. - gets from 1st instance
2760  */
get_dce_edgeval(struct mod_t * mdp,struct dcevnt_t * dcep)2761 static word32 get_dce_edgeval(struct mod_t *mdp, struct dcevnt_t *dcep)
2762 {
2763  struct net_t *np;
2764  int32 dcewid;
2765  byte *sbp;
2766  word32 val, aw, bw;
2767  struct xstk_t *xsp;
2768 
2769  /* here edge always 1 bit */
2770  if (dcep->dce_expr != NULL)
2771   {
2772    __push_wrkitstk(mdp, 0);
2773    ld_scalval_(&aw, &bw, dcep->dce_expr->bp);
2774    val = (aw & 1L) | ((bw << 1) & 2L);
2775    __pop_wrkitstk();
2776   }
2777  else
2778   {
2779    np = dcep->dce_np;
2780    /* this is low bit of 1st inst. */
2781    if (np->n_stren) { sbp = dcep->prevval.bp; val = (word32) (sbp[0] & 3); }
2782    else
2783     {
2784      /* since edge, know low bit used for range */
2785      dcewid = __get_dcewid(dcep, np);
2786 
2787      __push_wrkitstk(mdp, 0);
2788      /* special case load of perinst value */
2789      push_xstk_(xsp, dcewid);
2790      __ld_perinst_val(xsp->ap, xsp->bp, dcep->prevval, dcewid);
2791      val = (xsp->ap[0] & 1L) | ((xsp->bp[0] << 1) & 2L);
2792      __pop_xstk();
2793      __pop_wrkitstk();
2794     }
2795   }
2796  return(val);
2797 }
2798 
2799 /*
2800  * MISC. VALUE CONVERSION ROUTINES TOO COMPLICATED TO BE MACROS
2801  * USED FOR VALUE CONVERSION EVERYWHERE
2802  */
2803 
2804 /*
2805  * trim binary value by changing length (for binary only)
2806  * so if all left bits 0, x, or z compute new length
2807  *
2808  * if all highs 0, trim to highest non 0, if 0 make 1
2809  * if all high x or z trim so include 1 high x or z bit
2810  * return new trimmed length
2811  *
2812  * this maybe would be better converting to blen and using that
2813  */
bin_trim_abval(word32 * ap,word32 * bp,int32 blen)2814 static int32 bin_trim_abval(word32 *ap, word32 *bp, int32 blen)
2815 {
2816  int32 ahigh0, bhigh0;
2817  int32 wlen, ubits, trimalen, trimblen, nblen;
2818 
2819  /* this adjusts 0 to WBITS */
2820  wlen = wlen_(blen);
2821  ubits = ubits_(blen);
2822  if (ubits == 0) ubits = WBITS;
2823  /* notice range for bits is [32:1] */
2824  if (bithi_is0(ap[wlen - 1], ubits)) ahigh0 = TRUE; else ahigh0 = FALSE;
2825  if (bithi_is0(bp[wlen - 1], ubits)) bhigh0 = TRUE; else bhigh0 = FALSE;
2826  /* if high bit 1, cannot trim */
2827  if (bhigh0 && !ahigh0) return(blen);
2828 
2829  /* if high bit 0 - len is width where non 0 high a and non 0 highb */
2830  /* if high bit z - len is width where non 0 high a and non 1 highb */
2831  /* if high bit x - len is width where non 1 high a and non 1 highb */
2832  if (ahigh0) trimalen = __trim1_0val(ap, blen);
2833  else trimalen = trim1_1val(ap, blen);
2834  if (bhigh0) trimblen = __trim1_0val(bp, blen);
2835  else trimblen = trim1_1val(bp, blen);
2836  nblen = (trimalen >= trimblen) ? trimalen : trimblen;
2837 
2838  /* if all 0s, x's, or z's, make 1 bit */
2839  if (nblen == 0) return(1);
2840 
2841  /* if trimmed x or z always need high x or z */
2842  /* AIV 01/18/06 - if the high bit was one x or z was returning an extra bit */
2843  if (!bhigh0)
2844   {
2845    if (blen == nblen) return(nblen);
2846    return(nblen + 1);
2847   }
2848 
2849  /* trimmed 0's to something */
2850  /* if trim 0's to x or z - need the to inc for one extra high 0 */
2851  wlen = wlen_(nblen);
2852  ubits = ubits_(nblen);
2853  if (ubits == 0) ubits = WBITS;
2854  /* notice range for bits is [32:1] */
2855  /* if trimmed 0's to 1, do not need extra high 1 */
2856  if (!bithi_is0(bp[wlen - 1], ubits)) return(nblen + 1);
2857 
2858  /* if trimmed 0's to 1, then no extra high 0 */
2859  return(nblen);
2860 }
2861 
2862 /*
2863  * trim a value by changing length so if all left bits 0, x, or z compute
2864  * if all highs 0, trim to highest non 0, if 0 make 1
2865  * if all high x or z trim so include 1 high x or z bit
2866  * return new trimmed length
2867  *
2868  * this maybe would be better converting to blen and using that
2869  */
trim_abval(word32 * ap,word32 * bp,int32 blen)2870 static int32 trim_abval(word32 *ap, word32 *bp, int32 blen)
2871 {
2872  int32 ahigh0, bhigh0;
2873  int32 wlen, ubits, trimalen, trimblen, nblen;
2874 
2875  /* this adjusts 0 to WBITS */
2876  wlen = wlen_(blen);
2877  ubits = ubits_(blen);
2878  if (ubits == 0) ubits = WBITS;
2879  /* notice range for bits is [32:1] */
2880  if (bithi_is0(ap[wlen - 1], ubits)) ahigh0 = TRUE; else ahigh0 = FALSE;
2881  if (bithi_is0(bp[wlen - 1], ubits)) bhigh0 = TRUE; else bhigh0 = FALSE;
2882  /* if high bit 1, cannot trim */
2883  if (bhigh0 && !ahigh0) return(blen);
2884 
2885  if (ahigh0) trimalen = __trim1_0val(ap, blen);
2886  else trimalen = trim1_1val(ap, blen);
2887  if (bhigh0) trimblen = __trim1_0val(bp, blen);
2888  else trimblen = trim1_1val(bp, blen);
2889  nblen = (trimalen >= trimblen) ? trimalen : trimblen;
2890  /* if all 0s, make 1 bit */
2891  if (nblen == 0) return(1);
2892 
2893  /* if x or z extension, need 1 extra bit */
2894  /* AIV 01/18/06 - if the high bit was one x or z was returning an extra bit */
2895  if (!ahigh0 || !bhigh0)
2896   {
2897    if (blen == nblen) return(nblen);
2898    return(nblen + 1);
2899   }
2900  return(nblen);
2901 }
2902 
2903 /*
2904  * return T if bit i is 0 (32 >= i >= 1)
2905  */
bithi_is0(word32 val,int32 ubits)2906 static int32 bithi_is0(word32 val, int32 ubits)
2907 {
2908  word32 mask;
2909 
2910  mask = 1L << (ubits - 1);
2911  if ((mask & val) == 0L) return(TRUE);
2912  return(FALSE);
2913 }
2914 
2915 /* table used by count leading zeros macro */
2916 static byte clz_tab[] =
2917 {
2918  0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
2919  6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,
2920  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
2921  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
2922  8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
2923  8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
2924  8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
2925  8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
2926 };
2927 
2928 /* notice this routine in 32 bit word32 dependent */
__count_leading_zeros(register word32 xr)2929 extern int32 __count_leading_zeros(register word32 xr)
2930 {
2931  register word32 a;
2932  register int32 count;
2933 
2934  a = xr < (1L << 16) ? (xr < (1L << 8) ? 0 : 8) : (xr < (1L << 24) ? 16: 24);
2935  count = 32 - (clz_tab[xr >> a] + a);
2936  return(count);
2937 }
2938 
2939 /*
2940  * trim a 0 value - returns new length that is 0 if all 0's
2941  * else new trimmed length - know all high unsued bits 0
2942  *
2943  * this works on either a or b part but not both at once - caller must
2944  * combine
2945  */
__trim1_0val(word32 * wp,int32 blen)2946 extern int32 __trim1_0val(word32 *wp, int32 blen)
2947 {
2948  register int32 swi;
2949  int32 hbits, wlen;
2950 
2951  /* adjust so blen value as if all bits in high word32 used */
2952  wlen = wlen_(blen);
2953  /* notice this works from high word32 toward low */
2954  for (swi = wlen - 1; swi >= 0; swi--)
2955   {
2956    if (wp[swi] != 0L)
2957     {
2958      hbits = __count_leading_zeros(wp[swi]);
2959      return(WBITS*(swi + 1) - hbits);
2960     }
2961   }
2962  return(0);
2963 }
2964 
2965 /*
2966  * trim a 1 value - returns new length that is 0 if all 1's
2967  * know all high unsued bits 1 in value with new length
2968  */
trim1_1val(word32 * wp,int32 blen)2969 static int32 trim1_1val(word32 *wp, int32 blen)
2970 {
2971  register int32 swi;
2972  word32 tmp;
2973  int32 wlen, hbits, ubits;
2974 
2975  wlen = wlen_(blen);
2976  ubits = ubits_(blen);
2977  /* if some bits unused, use mask when inverting for zero count */
2978  if (ubits != 0)
2979   {
2980    wlen--;
2981    tmp = ~wp[wlen] & __masktab[ubits];
2982    if (tmp != 0L)
2983     { hbits = __count_leading_zeros(tmp); return(WBITS*(wlen + 1) - hbits); }
2984   }
2985  /* notice this works from high word32 toward low */
2986  for (swi = wlen - 1; swi >= 0; swi--)
2987   {
2988    if ((tmp = ~wp[swi]) != 0L)
2989     {
2990      hbits = __count_leading_zeros(tmp);
2991      return(WBITS*(swi + 1) - hbits);
2992     }
2993   }
2994  return(0);
2995 }
2996 
2997 /*
2998  * return T if value is all z's
2999  */
__vval_isallzs(word32 * ap,word32 * bp,int32 blen)3000 extern int32 __vval_isallzs(word32 *ap, word32 *bp, int32 blen)
3001 {
3002  int32 v1, v2;
3003 
3004  /* v1, v2 here for debugging only */
3005  v1 = vval_is0_(ap, blen);
3006  if (!v1) return(FALSE);
3007  v2 = __vval_is1(bp, blen);
3008  return(v2);
3009 }
3010 
3011 /*
3012  * return T for strength value that is all z's
3013  * <0:0=z (i.e. 00000010) is only z value
3014  */
__st_vval_isallzs(byte * sbp,int32 blen)3015 extern int32 __st_vval_isallzs(byte *sbp, int32 blen)
3016 {
3017  register int32 i;
3018 
3019  for (i = 0; i < blen; i++) if (*sbp != 3) return(FALSE);
3020  return(TRUE);
3021 }
3022 
3023 /*
3024  * return T if value is all x's
3025  */
vval_isall_xs(word32 * ap,word32 * bp,int32 blen)3026 static int32 vval_isall_xs(word32 *ap, word32 *bp, int32 blen)
3027 {
3028  if (!__vval_is1(ap, blen)) return(FALSE);
3029  if (!__vval_is1(bp, blen)) return(FALSE);
3030  return(TRUE);
3031 }
3032 
3033 /*
3034  * return T is has any x's, even 1 x implies X, else Z
3035  * notice half word32 here ok
3036  */
vval_hasx(word32 * ap,word32 * bp,int32 blen)3037 static int32 vval_hasx(word32 *ap, word32 *bp, int32 blen)
3038 {
3039  register int32 wi;
3040 
3041  for (wi = 0; wi < wlen_(blen); wi++)
3042   {
3043    if ((ap[wi] & bp[wi]) != 0L) return(TRUE);
3044   }
3045  return(FALSE);
3046 }
3047 
3048 /*
3049  * return T if value is all 1's (processes either a or b value not both)
3050  * notice half word32 blen here ok
3051  */
__vval_is1(register word32 * wp,int32 blen)3052 extern int32 __vval_is1(register word32 *wp, int32 blen)
3053 {
3054  register int32 i;
3055  register word32 mask;
3056  int32 wlen;
3057 
3058  wlen = wlen_(blen);
3059  for (i = 0; i < wlen - 1; i++) if (wp[i] != ALL1W) return(FALSE);
3060  mask = __masktab[ubits_(blen)];
3061  if ((wp[wlen - 1] & mask) != mask) return(FALSE);
3062  return(TRUE);
3063 }
3064 
3065 /*
3066  * return T if value is all 0's (processes either a or b value)
3067  * passed with 2 word32 length for both a and b values
3068  * only for values wider than WBITS
3069  * notice must be word32 since 2 word32 length possible
3070  *
3071  * this is invoked from a macro
3072  */
__wide_vval_is0(register word32 * wp,int32 blen)3073 extern int32 __wide_vval_is0(register word32 *wp, int32 blen)
3074 {
3075  register int32 i;
3076 
3077  for (i = 0; i < wlen_(blen); i++) if (*wp++ != 0L) return(FALSE);
3078  return(TRUE);
3079 }
3080 
3081 /*
3082  * REAL CONVERSION ROUTINES
3083  */
3084 
3085 /*
3086  * convert a 64 bit ver. word32  to a ieee double real value
3087  * return F on error - caller can emit warning - d1 as good as possible
3088  *
3089  * FIXME - since tim now word32 64, maybe can just assign
3090  * PORTABLE - assumes IEEE floating point
3091  */
__v64_to_real(double * d1,word64 * tim)3092 extern int32 __v64_to_real(double *d1, word64 *tim)
3093 {
3094  int32 good;
3095  register word32 w0, w1, mask;
3096  double dbase;
3097 
3098  /* easy case, fit in 32 bits */
3099  w0 = (word32) ((*tim) & WORDMASK_ULL);
3100  w1 = (word32) (((*tim) >> 32) & WORDMASK_ULL);
3101  if (w1 == 0L) { *d1 = (double) w0; return(TRUE); }
3102 
3103  good = TRUE;
3104  /* must fit in mantissa or will lose precision */
3105  mask = __masktab[WBITS - (_DEXPLEN + 1)];
3106  if ((w1 & ~mask) != 0L) good = FALSE;
3107  dbase = ((double) (0xffffffff)) + 1.0;
3108  /* cannot use base 2**32 because conversion to double assumes int32 */
3109  /* even if value is word32 */
3110  /* conversion from double to word32 works if double is positive */
3111  *d1 = (double) w0 + dbase*((double) w1);
3112  return(good);
3113 }
3114 
3115 /*
3116  * convert a stack value to a real and
3117  *
3118  * 09/30/06 SJM - thanks to Bryan Catanzaro from Tabula for find this
3119  *
3120  * there is a slight bug here because this must also change stack
3121  * width to WBITS - needed because the stack value is used later
3122  * and changing the xslen field is always good - see narrow sizchg
3123  */
__cnvt_stk_to_real(struct xstk_t * xsp,int32 is_signed)3124 extern double __cnvt_stk_to_real(struct xstk_t *xsp, int32 is_signed)
3125 {
3126  int32 i, blen;
3127  word32 mask_val;
3128  word32 u;
3129  word64 tim;
3130  double d1;
3131 
3132  if (!vval_is0_(xsp->bp, xsp->xslen))
3133   {
3134 not_real:
3135    __sgfwarn(618,
3136     "expression value %s cannot be represented as real - 0.0 used",
3137     __regab_tostr(__xs, xsp->ap, xsp->bp, xsp->xslen, BHEX, is_signed));
3138    return(0.0);
3139   }
3140  if (xsp->xslen > WBITS)
3141   {
3142    if (xsp->xslen > WBITS && !vval_is0_(&(xsp->ap[2]), xsp->xslen - 64))
3143     goto not_real;
3144    tim = ((word64) xsp->ap[0]) | (((word64) xsp->ap[1]) << 32);
3145    __v64_to_real(&d1, &tim);
3146   }
3147  else
3148   {
3149    /* AIV 09/29/06 - if sign bit on and < WBITS need mask prior to cast */
3150    if (is_signed)
3151     {
3152      blen = xsp->xslen;
3153      mask_val = xsp->ap[0];
3154      if (xsp->xslen != WBITS)
3155       {
3156        if ((mask_val & (1 << (blen - 1))) != 0)
3157         {
3158          mask_val |= ~(__masktab[blen]);
3159         }
3160        }
3161      i = (int32) mask_val;
3162      d1 = (double) i;
3163     }
3164    else { u = (word32) xsp->ap[0]; d1 = (double) u; }
3165   }
3166  /* SJM 09/30/06 - can resue the strength arg */
3167  xsp->xslen = WBITS;
3168  return(d1);
3169 }
3170 
3171 /*
3172  * routine to unscale from ticks to user time as double
3173  * this routine changes value of real
3174  * only called if know need to scale
3175  */
__unscale_realticks(word64 * ticksval,struct mod_t * mdp)3176 extern double __unscale_realticks(word64 *ticksval, struct mod_t *mdp)
3177 {
3178  word32 unit;
3179  double d1;
3180 
3181  if (!__v64_to_real(&d1, ticksval))
3182   {
3183    __sgfwarn(575,
3184     "conversion from internal time %s to time as real lost precision",
3185     __to_timstr(__xs, ticksval));
3186   }
3187 
3188  if (!mdp->mno_unitcnv)
3189   {
3190    unit = __des_timeprec - mdp->mtime_units;
3191    d1 /= __dbl_toticks_tab[unit];
3192   }
3193  return(d1);
3194 }
3195 
3196 /*
3197  * return result of scale function
3198  * this must return a double value
3199  * even though this does not return xstk, must leave on expr. stack
3200  */
__exec_scale(struct expr_t * fax)3201 extern void __exec_scale(struct expr_t *fax)
3202 {
3203  int32 unit;
3204  double d1;
3205  word64 tval;
3206  struct xstk_t *xsp;
3207  struct mod_t *from_mdp, *to_mdp;
3208 
3209  xsp = __eval_xpr(fax);
3210  if (xsp->xslen != TIMEBITS) __sizchgxs(xsp, TIMEBITS);
3211  if (xsp->bp[0] != 0L || xsp->bp[1] != 0)
3212   {
3213    __sgfwarn(629, "$scale time argument bits x or z - scaled to 0.0");
3214    d1 = 0.0;
3215    goto done;
3216   }
3217  tval = ((word64) xsp->ap[0]) | (((word64) xsp->ap[1]) << 32);
3218  if (!__v64_to_real(&d1, &tval))
3219   {
3220    __sgfwarn(575,
3221     "conversion from $scale time %s to time as real lost precision",
3222     __to_timstr(__xs, &tval));
3223   }
3224  to_mdp = __inst_mod;
3225  from_mdp = fax->ru.grp->targmdp;
3226  if (from_mdp->mtime_units != to_mdp->mtime_units)
3227   {
3228    if (from_mdp->mtime_units > to_mdp->mtime_units)
3229     {
3230      /* here from module more precise (high exponent) - divide */
3231      unit = from_mdp->mtime_units - to_mdp->mtime_units;
3232      d1 /= __dbl_toticks_tab[unit];
3233     }
3234    else
3235     {
3236      /* here from module less precise (low exponent) - multiply */
3237      unit = to_mdp->mtime_units - from_mdp->mtime_units;
3238      d1 *= __dbl_toticks_tab[unit];
3239     }
3240   }
3241 done:
3242  memcpy(xsp->ap, &d1, sizeof(double));
3243 }
3244 
3245 /*
3246  * wrapper for cnv stk from real to reg32 when reading source
3247  * purpose to set up right source line
3248  */
__src_rd_cnv_stk_fromreal_toreg32(struct xstk_t * xsp)3249 extern void __src_rd_cnv_stk_fromreal_toreg32(struct xstk_t *xsp)
3250 {
3251  int32 sav_slin_cnt, sav_sfnam_ind;
3252 
3253  /* can assign specparam value immediately */
3254  /* SJM 06/17/99 - needs to run in run/fixup mode - statement loc set */
3255  sav_slin_cnt = __slin_cnt;
3256  sav_sfnam_ind = __sfnam_ind;
3257  __sfnam_ind = __cur_fnam_ind;
3258  __slin_cnt = __lin_cnt;
3259 
3260  __cnv_stk_fromreal_toreg32(xsp);
3261 
3262  /* must put back in case reading iact source */
3263  __slin_cnt = sav_slin_cnt;
3264  __sfnam_ind = sav_sfnam_ind;
3265 }
3266 
3267 /*
3268  * convert an evaluated tos value from real to reg 32 (maybe signed)
3269  * know real will always be WBITS with b part part of real
3270  * this routine is 32 bit dependent
3271  *
3272  * algorith converts real to int32 (32 bit) then move bit pattern to reg32
3273  * notice output can be signed
3274  */
__cnv_stk_fromreal_toreg32(struct xstk_t * xsp)3275 extern void __cnv_stk_fromreal_toreg32(struct xstk_t *xsp)
3276 {
3277  double d1;
3278  int32 i;
3279 
3280  memcpy(&d1, xsp->ap, sizeof(double));
3281  i = ver_rint_(d1);
3282  xsp->ap[0] = (word32) i;
3283  xsp->bp[0] = 0L;
3284 }
3285 
3286 /*
3287  * wrapper for cnv stk from reg to realwhen reading source
3288  * purpose to set up right source line
3289  */
__src_rd_cnv_stk_fromreg_toreal(struct xstk_t * xsp,int32 src_signed)3290 extern void __src_rd_cnv_stk_fromreg_toreal(struct xstk_t *xsp, int32 src_signed)
3291 {
3292  int32 sav_slin_cnt, sav_sfnam_ind;
3293 
3294  /* can assign specparam value immediately */
3295  /* SJM 06/17/99 - needs to run in run/fixup mode - statement loc set */
3296  sav_slin_cnt = __slin_cnt;
3297  sav_sfnam_ind = __sfnam_ind;
3298  __sfnam_ind = __cur_fnam_ind;
3299  __slin_cnt = __lin_cnt;
3300 
3301  __cnv_stk_fromreg_toreal(xsp, src_signed);
3302 
3303  /* must put back in case reading iact source */
3304  __slin_cnt = sav_slin_cnt;
3305  __sfnam_ind = sav_sfnam_ind;
3306 }
3307 
3308 /*
3309  * convert a tos evaluated value from reg to real
3310  * need run time warning if does not fit - since if high bits 0 ok
3311  * this is real width and word32 width dependent
3312  */
__cnv_stk_fromreg_toreal(struct xstk_t * xsp,int32 src_signed)3313 extern void __cnv_stk_fromreg_toreal(struct xstk_t *xsp, int32 src_signed)
3314 {
3315  int32 i;
3316  word32 w;
3317  double d1;
3318 
3319  if ((xsp->xslen > WBITS && !vval_is0_(&(xsp->ap[1]), xsp->xslen - WBITS))
3320   || !vval_is0_(xsp->bp, xsp->xslen))
3321   {
3322    __sgfwarn(518,
3323     "conversion of %s to real width %d too wide or x/z - converted to 0.0",
3324     __regab_tostr(__xs, xsp->ap, xsp->bp, xsp->xslen, BHEX, FALSE),
3325     xsp->xslen);
3326    d1 = 0.0;
3327    goto done;
3328   }
3329  if (src_signed) { i = (int32) xsp->ap[0]; d1 = (double) i;  }
3330  else { w = xsp->ap[0]; d1 = (double) w; }
3331 
3332  /* next must adjust stack - know will have enough room */
3333 done:
3334  xsp->bp = &(xsp->ap[1]);
3335  xsp->xslen = WBITS;
3336  memcpy(xsp->ap, &d1, sizeof(double));
3337 }
3338 
3339 /*
3340  * ROUTINES TO IMPLEMENT VERILOG SPECIFIC OR UNPORTABLE MATH LIB
3341  */
3342 
3343 #define MY_MAXDOUBLE 1.797693134862315708e+308
3344 /* #define MY_MAXDOUBLE 1.79e+308 */
3345 #define MY_MINDOUBLE 4.9406564584124654e-324
3346 #define MY_LONG_MAX 0x7fffffff
3347 #define MY_LONG_MIN 0x80000000
3348 
3349 /*
3350  * convert nptr to a double - modified verision of lib. strtod
3351  * If endptr is not nil, endptr contains addr of 1 afer end
3352  * notice here error EINVAL set even no digits - standard just sets to 0
3353  */
__my_strtod(char * nptr,char ** endptr,int32 * errnum)3354 extern double __my_strtod(char *nptr, char **endptr, int32 *errnum)
3355 {
3356  register char *s;
3357  short int sign;
3358  long int tmpexp;
3359  int32 got_dot, got_digit, save;
3360  long int exponent;
3361  double num;
3362  char *end;
3363 
3364  if (nptr == NULL) goto noconv;
3365  s = nptr;
3366  if (*s == '\0') goto noconv;
3367 
3368  /* skip - know *s is a char from system getc type routinm */
3369  while (isspace(*s)) s++;
3370  /* get sign */
3371  sign = *s == '-' ? -1 : 1;
3372  if (*s == '-' || *s == '+') s++;
3373 
3374  num = 0.0;
3375  got_dot = 0;
3376  got_digit = 0;
3377  exponent = 0;
3378  for (;; s++)
3379   {
3380    if (isdigit(*s))
3381     {
3382      got_digit = 1;
3383      /* if too many digits for double rep., ignore but need for for exp */
3384      if (num > MY_MAXDOUBLE * 0.1) exponent++;
3385       else num = 10.0*num + (*s - '0');
3386      /* count digits after exponent */
3387      if (got_dot) exponent--;
3388     }
3389    /* indicate dot seen */
3390    else if (!got_dot && *s == '.') got_dot = 1;
3391    else break;
3392   }
3393  /* must be at least 1 digit */
3394  if (!got_digit) goto noconv;
3395  /* get the exp. */
3396  *errnum = 0;
3397  if (*s == 'e' || *s == 'E')
3398   {
3399    save = *errnum;
3400    s++;
3401    tmpexp = my_strtol(s, &end, TRUE, errnum);
3402    if (*errnum == ERANGE)
3403     {
3404      /* overflow certainly means double exp. limit also exceeded */
3405      if (endptr != NULL) *endptr = end;
3406      if (tmpexp < 0) goto underflow; else goto overflow;
3407     }
3408    /* no exponent (e was end of number) */
3409    else if (end == s) end = (char *) s - 1;
3410    errno = save;
3411    s = end;
3412    exponent += tmpexp;
3413   }
3414  if (endptr != NULL) *endptr = s;
3415  if (num == 0.0) return(0.0);
3416 
3417  /* multiply int32 part by 10 to exponent as power */
3418  if (exponent < 0)
3419   { if (num < MY_MINDOUBLE * pow(10.0, (double) -exponent)) goto underflow; }
3420  else if (exponent > 0)
3421   { if (num > MY_MAXDOUBLE * pow(10.0, (double) -exponent)) goto overflow; }
3422  num *= pow(10.0, (double) exponent);
3423  return(sign*num);
3424 
3425 overflow:
3426  *errnum = ERANGE;
3427  return(sign*MY_MAXDOUBLE);
3428 
3429 underflow:
3430  if (endptr != NULL) *endptr = nptr;
3431  *errnum = ERANGE;
3432  return(0.0);
3433 
3434 noconv:
3435  if (endptr != NULL) *endptr = nptr;
3436  *errnum = EINVAL;
3437  return(0.0);
3438 }
3439 
3440 /*
3441  * convert string to word32 long
3442  */
__my_strtoul(char * nptr,char ** endptr,int * errnum)3443 extern word32 __my_strtoul(char *nptr, char **endptr, int *errnum)
3444 {
3445  word32 ul;
3446 
3447  ul = (word32) my_strtol(nptr, endptr, FALSE, errnum);
3448  return(ul);
3449 }
3450 
3451 /*
3452  * convert string at nptr to long int and point endptr to 1 past end
3453  * notice here error EINVAL set even no digits - standard just sets to 0
3454  */
my_strtol(char * nptr,char ** endptr,int32 sign,int32 * errnum)3455 static long my_strtol(char *nptr, char **endptr, int32 sign, int32 *errnum)
3456 {
3457  register char *s;
3458  register unsigned char c;
3459  register word32 i;
3460  int32 negative;
3461  word32 cutoff;
3462  word32 cutlim;
3463  char *save;
3464  int32 overflow;
3465 
3466  s = nptr;
3467  /* skip white space */
3468  while (isspace(*s)) ++s;
3469  if (*s == '\0') goto noconv;
3470 
3471  /* check for a sign */
3472  if (*s == '-')
3473   {
3474    /* word32 can not have sign prefix - maybe should allow and convert */
3475    if (!sign) goto noconv;
3476    negative = 1;
3477    s++;
3478   }
3479  else if (*s == '+') { negative = 0; s++; }
3480  else negative = 0;
3481 
3482  /* save pointer to test for no digits */
3483  save = s;
3484  /* this is word32 max */
3485  cutoff = ALL1W / (word32) 10;
3486  cutlim = ALL1W % (word32) 10;
3487  for (overflow = 0, i = 0, c = *s; c != '\0'; c = *++s)
3488   {
3489    if (isdigit(c)) c -= '0'; else break;
3490    /* check for overflow */
3491    if (i > cutoff || (i == cutoff && c > cutlim)) overflow = 1;
3492    else { i *= 10; i += c; }
3493   }
3494  /* if no progress, error */
3495  if (s == save) goto noconv;
3496  /* store endptr if user passed non nil */
3497  if (endptr != NULL) *endptr = (char *) s;
3498 
3499  /* check for in word32 but outside long int */
3500  /* FIXME - what is this supposed to do? */
3501  if (sign)
3502   {
3503    if (i > (negative ? - (word32) MY_LONG_MIN
3504     : (unsigned long int) MY_LONG_MAX)) overflow = 1;
3505    if (overflow)
3506     { *errnum = ERANGE; return(negative ? MY_LONG_MIN : MY_LONG_MAX); }
3507   }
3508  *errnum = 0;
3509  return (negative ? - i : i);
3510 
3511 noconv:
3512  *errnum = EINVAL;
3513  if (endptr != NULL) *endptr = (char *) nptr;
3514  return(0L);
3515 }
3516 
3517 /*
3518  * ASCII RECONSTRUCTED SOURCE DUMP ROUTINES
3519  */
3520 
3521 /*
3522  * not dumping cap charges
3523  * f must not be nil
3524  * this requires a current instance (call be in loop for all)
3525  */
__dmp_mod(FILE * f,struct mod_t * mdp)3526 extern void __dmp_mod(FILE *f, struct mod_t *mdp)
3527 {
3528  char s1[RECLEN];
3529 
3530  if (f == NULL) __arg_terr(__FILE__, __LINE__);
3531  /* if precision changed dump new */
3532  if (__cur_units != mdp->mtime_units || __cur_prec != mdp->mtime_prec)
3533   {
3534    /* replace with new current and write */
3535    __cur_units = mdp->mtime_units;
3536    __cur_prec = mdp->mtime_prec;
3537 
3538    sprintf(s1, "\n`timescale %s / %s", __to_timunitnam(__xs, __cur_units),
3539     __to_timunitnam(__xs2, __cur_units + __cur_prec));
3540    __nl_wrap_puts(s1, f);
3541   }
3542 
3543  __push_wrkitstk(mdp, 0);
3544 
3545  __pv_stlevel = 0;
3546  __outlinpos = 0;
3547  __cur_sofs = 0;
3548  __wrap_putc('\n', f);
3549  /* 04/01/00 SJM - for Verilog 2000 need to dmp digital attributes */
3550  if (mdp->mattrs != NULL) { dmp_dig_attr_list(f, mdp->mattrs, TRUE); }
3551  __wrap_puts("module ", f);
3552  __wrap_puts(mdp->msym->synam, f);
3553 
3554  if (mdp->mod_lofp_decl) dmp_mod_lofp_hdr(f, mdp);
3555  else dmp_modports(f, mdp);
3556 
3557  /* know I/O port decls will come first */
3558  dmp_decls(f, mdp);
3559 
3560  dmp_paramdecls(f, mdp->mprms, mdp->mprmnum, "parameter");
3561  if (mdp->mprms != NULL) { __wrap_putc('\n', f); __outlinpos = 0; }
3562 
3563  /* AIV 09/27/06 - must dump local param declarations too */
3564  dmp_paramdecls(f, mdp->mlocprms, mdp->mlocprmnum, "localparam");
3565  if (mdp->mlocprms != NULL) { __wrap_putc('\n', f); __outlinpos = 0; }
3566 
3567  dmp_defparams(f, mdp);
3568 
3569  dmp_mdtasks(f, mdp);
3570 
3571  if (mdp->mtasks != NULL) { __wrap_putc('\n', f); __outlinpos = 0; }
3572  dbg_dmp_insts(f, mdp);
3573 
3574  if (mdp->mcells != NULL && __outlinpos != 0)
3575   { __wrap_putc('\n', f); __outlinpos = 0; }
3576  dmp_ialst(f, mdp);
3577  if (mdp->ialst != NULL) { __wrap_putc('\n', f); __outlinpos = 0; }
3578 
3579 
3580  if (mdp->mspfy != NULL)
3581   {
3582    dmp_mdspfy(f, mdp);
3583    if (__outlinpos != 0) { __wrap_putc('\n', f); __outlinpos = 0; }
3584   }
3585  __nl_wrap_puts("endmodule", f);
3586 
3587  __pv_stlevel = 0;
3588  if (__debug_flg)
3589   {
3590    /* if regression dumping first symbol tables and global tables */
3591    dmp_mod_grefs(f, mdp);
3592   }
3593  __cur_sofs = 0;
3594  __pop_wrkitstk();
3595 }
3596 
3597 /*
3598  * routine to dump an attribute_instance
3599  */
dmp_dig_attr_list(FILE * f,struct attr_t * attr_hd,int32 nd_nl)3600 static void dmp_dig_attr_list(FILE *f, struct attr_t *attr_hd, int32 nd_nl)
3601 {
3602  register struct attr_t *attrp;
3603  int32 first_time = TRUE;
3604 
3605  if (nd_nl && __outlinpos != 0) __nl_wrap_puts("", f);
3606  __wrap_puts("(* ", f);
3607  for (attrp = attr_hd; attrp != NULL; attrp = attrp->attrnxt)
3608   {
3609    if (first_time) first_time = FALSE; else __wrap_puts(", ", f);
3610    __wrap_puts(attrp->attrnam, f);
3611    if (attrp->attr_xp != NULL)
3612     {
3613      __wrap_puts(" = ", f);
3614      dmp_expr(f, attrp->attr_xp);
3615     }
3616   }
3617  __wrap_puts(" *)", f);
3618  if (nd_nl && __outlinpos != 0) __nl_wrap_puts("", f);
3619  else __wrap_puts(" ", f);
3620 }
3621 
3622 /*
3623  * dump module ports
3624  */
dmp_modports(FILE * f,struct mod_t * mdp)3625 static void dmp_modports(FILE *f, struct mod_t *mdp)
3626 {
3627  register int32 pi;
3628  register struct mod_pin_t *mpp;
3629  int32 first_time, pnum;
3630 
3631  first_time = TRUE;
3632  __pv_stlevel++;
3633  if ((pnum = mdp->mpnum) != 0)
3634   {
3635    for (pi = 0, mpp = &(mdp->mpins[0]); pi < pnum; pi++, mpp++)
3636     {
3637      if (first_time) { __wrap_putc('(', f); first_time = FALSE; }
3638      else __wrap_puts(", ", f);
3639      if (mpp->mp_explicit)
3640       {
3641        /* un-named but explicit module port stored wrong */
3642        /* DBG remove ---
3643        if (mpp->mpsnam == NULL)
3644         __misc_gfterr( __FILE__, __LINE__, mdp->msym->syfnam_ind,
3645          mdp->msym->sylin_cnt);
3646        --- */
3647        __wrap_putc('.', f);
3648        __wrap_puts(mpp->mpsnam, f);
3649        __wrap_putc('(', f);
3650        dmp_expr(f, mpp->mpref);
3651        /* this makes sure (..) always on 1 line */
3652       __wrap_putc(')', f);
3653       }
3654      else dmp_expr(f, mpp->mpref);
3655     }
3656   }
3657  if (!first_time) __wrap_putc(')', f);
3658  __nl_wrap_puts(";", f);
3659  __pv_stlevel--;
3660 }
3661 
3662 /*
3663  * dump new list of ports module ports header
3664  */
dmp_mod_lofp_hdr(FILE * f,struct mod_t * mdp)3665 static void dmp_mod_lofp_hdr(FILE *f, struct mod_t *mdp)
3666 {
3667  register int32 pi;
3668  register struct mod_pin_t *mpp;
3669  int32 first_time, pnum;
3670  struct net_t *np;
3671  char s1[RECLEN];
3672 
3673  first_time = TRUE;
3674  __pv_stlevel++;
3675  if ((pnum = mdp->mpnum) == 0)
3676   {
3677    if (!first_time) __wrap_putc(')', f);
3678    __nl_wrap_puts(";", f);
3679    __pv_stlevel--;
3680   }
3681 
3682  for (pi = 0, mpp = &(mdp->mpins[0]); pi < pnum; pi++, mpp++)
3683   {
3684    if (first_time) { __wrap_putc('(', f); first_time = FALSE; }
3685    else __wrap_puts(", ", f);
3686 
3687    /* DBG remove -- */
3688    if (mpp->mpref->optyp != ID) __misc_terr(__FILE__, __LINE__);
3689    /* --- */
3690 
3691    np = mpp->mpref->lu.sy->el.enp;
3692 
3693    if (np->nattrs != NULL) dmp_dig_attr_list(f, np->nattrs, FALSE);
3694 
3695    __wrap_puts(__to_ptnam(s1, np->iotyp), f);
3696 
3697    if (np->ntyp != N_WIRE)
3698     {
3699      __wrap_putc(' ', f);
3700      __wrap_puts(__to_wtnam(s1, np), f);
3701     }
3702 
3703    if (np->n_signed && (np->ntyp != N_INT && np->ntyp != N_REAL
3704     && np->ntyp != N_TIME))
3705     {
3706      __wrap_puts(" signed", f);
3707     }
3708 
3709    /* for special types no range but will have internal range */
3710    if (!np->n_isavec || np->ntyp == N_INT || np->ntyp == N_TIME
3711     || np->ntyp == N_REAL) strcpy(s1, "");
3712    else { __to_wrange(s1, np); __wrap_putc(' ', f); __wrap_puts(s1, f); }
3713 
3714    __wrap_putc(' ', f);
3715    __wrap_puts(np->nsym->synam, f);
3716   }
3717  if (!first_time) __wrap_putc(')', f);
3718  __nl_wrap_puts(";", f);
3719  __pv_stlevel--;
3720 }
3721 
3722 /*
3723  * dump all i/o and wire declarations for module
3724  */
dmp_decls(FILE * f,struct mod_t * mdp)3725 static void dmp_decls(FILE *f, struct mod_t *mdp)
3726 {
3727  register struct net_t *np;
3728  register int32 i;
3729  int32 pnum;
3730  struct mod_pin_t *mpp;
3731 
3732  __pv_stlevel++;
3733  /* first mark all wires not emitted */
3734  if (mdp->mnnum != 0)
3735   {
3736    for (i = 0, np = &(mdp->mnets[0]); i < mdp->mnnum; np++, i++)
3737     np->n_mark = FALSE;
3738   }
3739 
3740  if ((pnum = mdp->mpnum) != 0 && !mdp->mod_lofp_decl)
3741   {
3742    for (i = 0, mpp = &(mdp->mpins[0]); i < pnum; i++, mpp++)
3743     dmp_1portdecl(f, mpp->mpref);
3744   }
3745  if (mdp->mnnum != 0)
3746   {
3747    /* if use ptr must be sure at least one */
3748    /* do not emit decl. for any added nets */
3749    for (i = 0, np = &(mdp->mnets[0]); i < mdp->mnnum; i++, np++)
3750     dmp_1netdecl(f, np);
3751   }
3752  __outlinpos = 0;
3753  __pv_stlevel--;
3754 }
3755 
3756 /*
3757  * dump the required I/O direction declaration for one port net
3758  * must declare every wire in expr. as I/O port
3759  */
dmp_1portdecl(FILE * f,struct expr_t * ndp)3760 static void dmp_1portdecl(FILE *f, struct expr_t *ndp)
3761 {
3762  register struct expr_t *catndp;
3763  struct net_t *np;
3764  char s1[RECLEN];
3765 
3766  switch ((byte) ndp->optyp) {
3767   case ID:
3768    np = ndp->lu.sy->el.enp;
3769 emit_decl:
3770    /* just a mark here */
3771 
3772    if (!np->n_mark)
3773     {
3774      __wrap_puts(__to_ptnam(s1, np->iotyp), f);
3775      __wrap_putc(' ', f);
3776      __wrap_puts(np->nsym->synam, f);
3777      __nl_wrap_puts(";", f);
3778     }
3779    np->n_mark = TRUE;
3780    break;
3781   case LSB:
3782   case PARTSEL:
3783    np = ndp->lu.x->lu.sy->el.enp;
3784    goto emit_decl;
3785   case LCB:
3786    {
3787     for (catndp = ndp->ru.x; catndp != NULL; catndp = catndp->ru.x)
3788      dmp_1portdecl(f, catndp->lu.x);
3789    }
3790    break;
3791   default: __case_terr(__FILE__, __LINE__);
3792  }
3793 }
3794 
3795 /*
3796  * dump 1 net's declarations - may need I/O and wire
3797  */
dmp_1netdecl(FILE * f,struct net_t * np)3798 static void dmp_1netdecl(FILE *f, struct net_t *np)
3799 {
3800  char wnam[RECLEN], s1[IDLEN], s2[RECLEN];
3801 
3802  __outlinpos = 0;
3803  strcpy(wnam, "");
3804  /* if I/O port is normal wire, do not need wire declaration */
3805  if (np->iotyp != NON_IO)
3806   {
3807    if (__inst_mod->mod_lofp_decl) return;
3808    if (!nd_iowirdecl(np)) return;
3809   }
3810 
3811  /* 04/01/00 SJM - for Verilog 2000 need to dmp digital attributes */
3812  if (np->nattrs != NULL) dmp_dig_attr_list(f, np->nattrs, FALSE);
3813 
3814  __wrap_puts(__to_wtnam(wnam, np), f);
3815  /* know wire type will be trireg for cap. strength here */
3816  if (np->n_capsiz != CAP_NONE)
3817   {
3818    __wrap_putc(' ', f);
3819    __wrap_puts(__to_stren_nam(s1, __fr_cap_size((int32) np->n_capsiz),
3820     ST_STRONG), f);
3821   }
3822  /* never emit scalared/vectored for reg */
3823  if (np->n_isavec && np->ntyp < NONWIRE_ST)
3824   {
3825    if (np->nrngrep == NX_CT)
3826     {
3827      if (np->nu.ct->n_spltstate == SPLT_SCAL) __wrap_puts(" scalared", f);
3828      else if (np->nu.ct->n_spltstate == SPLT_VECT)
3829       __wrap_puts(" vectored", f);
3830     }
3831    else { if (!np->vec_scalared) __wrap_puts(" vectored", f); }
3832   }
3833 
3834  /* SJM 10/06/03 - signed if present after vec/scalar */
3835  if (np->n_signed && (np->ntyp != N_INT && np->ntyp != N_REAL
3836   && np->ntyp != N_TIME))
3837   {
3838    __wrap_puts(" signed", f);
3839   }
3840 
3841  /* for special types no range but will have internal range */
3842  if (!np->n_isavec || np->ntyp == N_INT || np->ntyp == N_TIME
3843   || np->ntyp == N_REAL) strcpy(s1, "");
3844  else { __to_wrange(s1, np); __wrap_putc(' ', f); __wrap_puts(s1, f); }
3845 
3846  /* these only write something if delay present */
3847  if (np->nrngrep == NX_CT) dmp_delay(f, np->nu.ct->n_dels_u,
3848   (word32) DT_CMPLST, "#");
3849  else if (np->nrngrep == NX_DWIR)
3850   dmp_delay(f, np->nu.rngdwir->n_du, np->nu.rngdwir->n_delrep, "#");
3851 
3852  __wrap_putc(' ', f);
3853  __wrap_puts(np->nsym->synam, f);
3854  if (np->n_isarr) __wrap_puts(__to_arr_range(s2, np), f);
3855  __nl_wrap_puts(";", f);
3856 
3857 }
3858 
3859 /*
3860  * return T if need wire decl. for I/O port
3861  * know wire only trireg wire type can have strength and need decl.
3862  *
3863  * default wire type in Verilog already handled because undeclared wires
3864  * will be assigned default wire type
3865  */
nd_iowirdecl(struct net_t * np)3866 static int32 nd_iowirdecl(struct net_t *np)
3867 {
3868  if (np->n_isavec || np->n_isarr || np->nattrs != NULL) return(TRUE);
3869 
3870  /* SJM 10/06/03 - if signed but not integer/real/time, need signed decl */
3871  if (np->n_signed && (np->ntyp != N_INT && np->ntyp != N_REAL
3872   && np->ntyp != N_TIME)) return(TRUE);
3873 
3874  if (np->nrngrep == NX_CT)
3875   {
3876    /* scalared is the default and impossible for regs */
3877    if (np->nu.ct->n_spltstate == SPLT_VECT) return(TRUE);
3878    if (np->nu.ct->n_dels_u.pdels != NULL) return(TRUE);
3879   }
3880  else
3881   {
3882    if (!np->vec_scalared) return(TRUE);
3883    if (np->nrngrep == NX_DWIR && np->nu.rngdwir->n_delrep != DT_PTHDST)
3884     return(TRUE);
3885   }
3886  if (np->ntyp != N_WIRE) return(TRUE);
3887  return(FALSE);
3888 }
3889 
3890 /*
3891  * dump locally declared param declarations
3892  * this does not work if f == NULL - does nothing
3893  */
dmp_paramdecls(FILE * f,struct net_t * parm_nptab,int32 pnum,char * pclassnam)3894 static void dmp_paramdecls(FILE *f, struct net_t *parm_nptab, int32 pnum,
3895  char *pclassnam)
3896 {
3897  register int32 pi;
3898  int32 varwid, base;
3899  struct net_t *parm_np;
3900  struct xstk_t *xsp;
3901  char s1[RECLEN], s2[RECLEN];
3902 
3903  __pv_stlevel++;
3904  for (pi = 0; pi < pnum; pi++)
3905   {
3906    parm_np = &(parm_nptab[pi]);
3907 
3908    __wrap_puts(pclassnam, f);
3909    /* FIXME - should emit according to exact source */
3910    if (parm_np->nu.ct->ptypdecl || parm_np->nu.ct->prngdecl)
3911     {
3912      /* always emit vector declaration even if not in source */
3913      if (parm_np->nu.ct->ptypdecl)
3914       {
3915        /* SJM 10/06/03 - know signed keyword can't have been used for these */
3916        if (parm_np->ntyp == N_REAL) strcpy(s1, " real");
3917        else if (parm_np->ntyp == N_INT) strcpy(s1, " integer");
3918        else if (parm_np->ntyp == N_TIME) strcpy(s1, " time");
3919        else __case_terr(__FILE__, __LINE__);
3920        __wrap_puts(s1, f);
3921       }
3922      else if (parm_np->nu.ct->prngdecl)
3923       {
3924        /* SJM 10/06/03 - signed and range can be declared together */
3925        if (parm_np->nu.ct->psigndecl) __wrap_puts(" signed", f);
3926        if (parm_np->n_isavec)
3927         {
3928          __wrap_putc(' ', f);
3929          __to_wrange(s1, parm_np);
3930          __wrap_puts(s1, f);
3931         }
3932       }
3933     }
3934    /* SJM 10/06/03 - signed without range possible - rhs range used */
3935    else if (parm_np->nu.ct->psigndecl) __wrap_puts(" signed", f);
3936 
3937    __wrap_putc(' ', f);
3938    __wrap_puts(parm_np->nsym->synam, f);
3939    /* for specify never array and only array if decled */
3940    if (parm_np->n_isarr)
3941     {
3942      __wrap_puts(__to_arr_range(s2, parm_np), f);
3943      __wrap_puts(" = ", f);
3944      dmp_expr(f, parm_np->nu.ct->n_dels_u.d1x);
3945      __nl_wrap_puts(";", f);
3946      continue;
3947     }
3948 
3949    __wrap_puts(" = ", f);
3950    /* should probably dump wire range here */
3951    varwid = __get_netwide(parm_np);
3952    push_xstk_(xsp, varwid);
3953    __ld_wire_val(xsp->ap, xsp->bp, parm_np);
3954 
3955    /* since need to parse this if x/z, need [size]'b form */
3956    if (parm_np->nu.ct->pstring)
3957     {
3958      __xline_vval_to_cstr(xsp->ap, xsp->xslen, TRUE, TRUE, FALSE);
3959     }
3960    else
3961     {
3962      base = parm_np->nu.ct->pbase;
3963      __regab_disp(xsp->ap, xsp->bp, xsp->xslen, base, TRUE,
3964       (parm_np->n_signed == 1));
3965     }
3966    __pop_xstk();
3967    __wrap_puts(__exprline, f);
3968 
3969    __nl_wrap_puts(";", f);
3970    /* know f not nil or will not get here */
3971    __cur_sofs = 0;
3972   }
3973  __pv_stlevel--;
3974 }
3975 
3976 
3977 /*
3978  * dump defparam statements (module items)
3979  * if output time becomes a problem could build index since in order
3980  */
dmp_defparams(FILE * f,struct mod_t * mdp)3981 static void dmp_defparams(FILE *f, struct mod_t *mdp)
3982 {
3983  register int32 i;
3984  struct dfparam_t *dfpp;
3985  struct itree_t *itp;
3986 
3987  __pv_stlevel++;
3988  for (dfpp = __dfphdr; dfpp != NULL; dfpp = dfpp->dfpnxt)
3989   {
3990    if (dfpp->in_mdp != mdp) continue;
3991    __wrap_puts("defparam ", f);
3992    if (dfpp->dfp_local) __wrap_puts(dfpp->gdfpnam, f);
3993    else
3994     {
3995      /* this prints the after splitting form */
3996      /* always printed rooted but source may have been downward */
3997      itp = __it_roots[dfpp->dfpiis[0]];
3998      for (i = 0;;)
3999       {
4000        if (i > 0) __wrap_putc('.', f);
4001        /* must be on one line no matter how long */
4002        __wrap_puts(itp->itip->isym->synam, f);
4003        if (++i > dfpp->last_dfpi) break;
4004        itp = &(itp->in_its[dfpp->dfpiis[i]]);
4005       }
4006      if (i > 0) __wrap_putc('.', f);
4007      __wrap_puts(dfpp->targsyp->synam, f);
4008      /* must be on one line no matter how long */
4009     }
4010    __wrap_puts(" = ", f);
4011    dmp_expr(f, dfpp->dfpxrhs);
4012    __nl_wrap_puts(";", f);
4013   }
4014  __pv_stlevel--;
4015 }
4016 
4017 /*
4018  * dump tasks and functions - named blocks dumped inline
4019  */
dmp_mdtasks(FILE * f,struct mod_t * mdp)4020 static void dmp_mdtasks(FILE *f, struct mod_t *mdp)
4021 {
4022  register struct task_t *tskp;
4023 
4024  for (tskp = mdp->mtasks; tskp != NULL; tskp = tskp->tsknxt)
4025   {
4026    if (tskp->tsktyp == FUNCTION || tskp->tsktyp == TASK) dmp_task(f, tskp);
4027   }
4028 }
4029 
4030 /*
4031  * dump module instances and gates
4032  * notice by here cells gone and split into insts and gates
4033  *
4034  * normal version that dumps g/i arrays as vectors
4035  */
dmp_insts(FILE * f,struct mod_t * mdp)4036 static void dmp_insts(FILE *f, struct mod_t *mdp)
4037 {
4038  register int32 ii, gi, cai;
4039  register struct giarr_t *giap;
4040  struct gate_t *gp;
4041  register struct conta_t *cap;
4042  struct inst_t *ip;
4043 
4044  __outlinpos = 0;
4045  __pv_stlevel++;
4046  for (ii = 0; ii < mdp->minum;)
4047   {
4048    if (mdp->miarr != NULL && (giap = mdp->miarr[ii]) != NULL)
4049     {
4050      ip = &(mdp->minsts[ii]);
4051      dmp_1inst(f, ip, giap);
4052      ii += __get_giarr_wide(giap);
4053     }
4054    else
4055     {
4056      dmp_1inst(f, &(mdp->minsts[ii]), NULL);
4057      ii++;
4058     }
4059   }
4060  for (gi = 0; gi < mdp->mgnum;)
4061   {
4062    if (mdp->mgarr != NULL && (giap = mdp->mgarr[gi]) != NULL)
4063     {
4064      gp = &(mdp->mgates[gi]);
4065      dmp_1gate(f, gp, giap);
4066      gi += __get_giarr_wide(giap);
4067     }
4068    else
4069     {
4070      dmp_1gate(f, &(mdp->mgates[gi]), NULL);
4071      gi++;
4072     }
4073   }
4074  for (cap = &(mdp->mcas[0]), cai = 0; cai < mdp->mcanum; cai++, cap++)
4075   dmp_1conta(f, cap);
4076  __pv_stlevel--;
4077 }
4078 
4079 
4080 /*
4081  * dump 1 module instance
4082  */
dmp_1inst(FILE * f,struct inst_t * ip,struct giarr_t * giap)4083 static void dmp_1inst(FILE *f, struct inst_t *ip, struct giarr_t *giap)
4084 {
4085  struct mod_t *imdp;
4086  char s1[RECLEN];
4087 
4088  __wrap_puts(ip->imsym->synam, f);
4089  /* this writes nothing if no # style passed set defparams */
4090  imdp = ip->imsym->el.emdp;
4091  if (ip->ipxprtab != NULL) dmp_pnd_params(f, ip, imdp);
4092 
4093  /* know modules always named */
4094  __wrap_putc(' ', f);
4095  __wrap_puts(ip->isym->synam, f);
4096 
4097  /* if giap non nil - emit range */
4098  if (giap != NULL)
4099   {
4100    if (__debug_flg)
4101     {
4102      sprintf(s1, " [%d:%d]", giap->gia1, giap->gia2);
4103      __wrap_puts(s1, f);
4104     }
4105    else
4106     {
4107      __wrap_puts(" [", f);
4108      dmp_expr(f, giap->giax1);
4109      __wrap_putc(':', f);
4110      dmp_expr(f, giap->giax2);
4111      __wrap_putc(']', f);
4112     }
4113    dmp_iports(f, ip, giap->giapins);
4114   }
4115  else dmp_iports(f, ip, ip->ipins);
4116 }
4117 
4118 /*
4119  * dump instance pound params
4120  */
dmp_pnd_params(FILE * f,struct inst_t * ip,struct mod_t * imdp)4121 static void dmp_pnd_params(FILE *f, struct inst_t *ip, struct mod_t *imdp)
4122 {
4123  register int32 pi;
4124  int32 first_time;
4125  struct expr_t *pxp;
4126  struct net_t *modnp;
4127 
4128  __force_base = BDEC;
4129  __wrap_puts(" #(", f);
4130  if (impl_pndparams(ip, imdp))
4131   {
4132    for (first_time = TRUE, pi = 0; pi < imdp->mprmnum; pi++)
4133     {
4134      pxp = ip->ipxprtab[pi];
4135      /* this handles missing tail params */
4136      if (pxp == NULL) break;
4137      modnp = &(imdp->mprms[pi]);
4138 
4139      if (first_time) first_time = FALSE; else __wrap_puts(", ", f);
4140      if (__debug_flg)
4141       {
4142        int32 wid, base;
4143        struct xstk_t *xsp;
4144        char s1[RECLEN];
4145 
4146        wid = __get_netwide(modnp);
4147        push_xstk_(xsp, wid);
4148        __ld_wire_val(xsp->ap, xsp->bp, modnp);
4149 
4150        /* since need to parse this if x/z, need [size]'b form */
4151        if (modnp->nu.ct->pstring)
4152         {
4153          __xline_vval_to_cstr(xsp->ap, xsp->xslen, TRUE, TRUE, FALSE);
4154         }
4155        else
4156         {
4157          base = modnp->nu.ct->pbase;
4158          if (base == BHEX)
4159           { sprintf(s1, "%d'h", xsp->xslen); __wrap_puts(s1, f); }
4160          __regab_disp(xsp->ap, xsp->bp, xsp->xslen, base, TRUE,
4161           (modnp->n_signed == 1));
4162         }
4163        __pop_xstk();
4164        __wrap_puts(__exprline, f);
4165        /* know f not nil or will not get here */
4166        __cur_sofs = 0;
4167       }
4168      else dmp_expr(f, pxp);
4169     }
4170   }
4171  else
4172   {
4173    for (first_time = TRUE, pi = 0; pi < imdp->mprmnum; pi++)
4174     {
4175      pxp = ip->ipxprtab[pi];
4176      /* this handles missing embedded or tail */
4177      if (pxp == NULL) continue;
4178      modnp = &(imdp->mprms[pi]);
4179 
4180      if (first_time) first_time = FALSE; else __wrap_puts(", ", f);
4181      __wrap_putc('.', f);
4182      __wrap_puts(modnp->nsym->synam, f);
4183      __wrap_putc('(', f);
4184      if (__debug_flg)
4185       {
4186        int32 wid, base;
4187        struct xstk_t *xsp;
4188        char s1[RECLEN];
4189 
4190        wid = __get_netwide(modnp);
4191        push_xstk_(xsp, wid);
4192        __ld_wire_val(xsp->ap, xsp->bp, modnp);
4193 
4194        /* since need to parse this if x/z, need [size]'b form */
4195        if (modnp->nu.ct->pstring)
4196         {
4197          __xline_vval_to_cstr(xsp->ap, xsp->xslen, TRUE, TRUE, FALSE);
4198         }
4199        else
4200         {
4201          base = modnp->nu.ct->pbase;
4202          if (base == BHEX)
4203           { sprintf(s1, "%d'h", xsp->xslen); __wrap_puts(s1, f); }
4204          __regab_disp(xsp->ap, xsp->bp, xsp->xslen, base, TRUE,
4205           (modnp->n_signed == 1));
4206         }
4207        __pop_xstk();
4208        __wrap_puts(__exprline, f);
4209        /* know f not nil or will not get here */
4210        __cur_sofs = 0;
4211       }
4212      else dmp_expr(f, pxp);
4213      __wrap_putc(')', f);
4214     }
4215   }
4216  __wrap_putc(')', f);
4217  __force_base = BNONE;
4218 }
4219 
4220 /*
4221  * return T if can use implicit form for instance pound params
4222  *
4223  * only called if at least 1 pound param
4224  * either all present in ip expr table or only tail missing
4225  */
impl_pndparams(struct inst_t * ip,struct mod_t * imdp)4226 static int32 impl_pndparams(struct inst_t *ip, struct mod_t *imdp)
4227 {
4228  register int32 pi, pi2;
4229  struct expr_t *pxp;
4230 
4231  imdp = ip->imsym->el.emdp;
4232  for (pi2 = imdp->mprmnum - 1; pi2 >= 0; pi2--)
4233   {
4234    pxp = ip->ipxprtab[pi2];
4235    if (pxp != NULL) break;
4236   }
4237  /* DBG remove --- */
4238  if (pi2 < 0) __misc_terr(__FILE__, __LINE__);
4239  /* --- */
4240  for (pi = 0; pi < pi2; pi++)
4241   {
4242    pxp = ip->ipxprtab[pi];
4243    /* once missing tail sequence eliminated, if any missing need explicit */
4244    if (pxp == NULL) return(FALSE);
4245   }
4246  return(TRUE);
4247 }
4248 
4249 /*
4250  * dump module instances and gates
4251  * unused DBG version that dump each bit
4252  */
4253 /* DBG --- */
dbg_dmp_insts(FILE * f,struct mod_t * mdp)4254 static void dbg_dmp_insts(FILE *f, struct mod_t *mdp)
4255 {
4256  register int32 ii, gi, cai;
4257  register struct conta_t *cap;
4258  int32 slen;
4259  struct gate_t *gp;
4260  struct inst_t *ip;
4261  char *chp, s1[IDLEN];
4262 
4263  __outlinpos = 0;
4264  __pv_stlevel++;
4265  for (ii = 0; ii < mdp->minum; ii++)
4266   {
4267    ip = &(mdp->minsts[ii]);
4268    /* 04/01/00 SJM - for Verilog 2000 need to dmp digital attributes */
4269    if (ip->iattrs != NULL) dmp_dig_attr_list(f, ip->iattrs, FALSE);
4270    if (mdp->miarr != NULL && mdp->miarr[ii] != NULL)
4271     {
4272      strcpy(s1, ip->isym->synam);
4273      if ((chp = strrchr(s1, '[')) == NULL) __arg_terr(__FILE__, __LINE__);
4274      *chp = '$';
4275      slen = strlen(s1);
4276      s1[slen - 1] = '$';
4277     }
4278    else strcpy(s1, ip->isym->synam);
4279    dbg_dmp_1inst(f, ip, s1);
4280   }
4281  for (gi = 0; gi < mdp->mgnum; gi++)
4282   {
4283    gp = &(mdp->mgates[gi]);
4284    /* 04/01/00 SJM - for Verilog 2000 need to dmp digital attributes */
4285    if (gp->gattrs != NULL) dmp_dig_attr_list(f, gp->gattrs, FALSE);
4286 
4287    if (mdp->mgarr != NULL && mdp->mgarr[gi] != NULL)
4288     {
4289      strcpy(s1, gp->gsym->synam);
4290      if ((chp = strrchr(s1, '[')) == NULL) __arg_terr(__FILE__, __LINE__);
4291      *chp = '$';
4292      slen = strlen(s1);
4293      s1[slen - 1] = '$';
4294     }
4295    else strcpy(s1, gp->gsym->synam);
4296 
4297    dbg_dmp_1gate(f, gp, s1);
4298   }
4299  for (cap = &(mdp->mcas[0]), cai = 0; cai < mdp->mcanum; cai++, cap++)
4300   dmp_1conta(f, cap);
4301  __pv_stlevel--;
4302 }
4303 
4304 /* --- */
4305 
4306 /*
4307  * dump 1 module instance
4308  */
4309 /* DBG --- */
dbg_dmp_1inst(FILE * f,struct inst_t * ip,char * inam)4310 static void dbg_dmp_1inst(FILE *f, struct inst_t *ip, char *inam)
4311 {
4312  struct mod_t *imdp;
4313 
4314  __wrap_puts(ip->imsym->synam, f);
4315  imdp = ip->imsym->el.emdp;
4316  if (ip->ipxprtab != NULL) dmp_pnd_params(f, ip, imdp);
4317 
4318  __wrap_putc(' ', f);
4319  __wrap_puts(inam, f);
4320  dmp_iports(f, ip, ip->ipins);
4321 }
4322 /* --- */
4323 
4324 /*
4325  * dump an instance port connection list
4326  */
dmp_iports(FILE * f,struct inst_t * ip,struct expr_t ** iptab)4327 static void dmp_iports(FILE *f, struct inst_t *ip, struct expr_t **iptab)
4328 {
4329  register int32 pi;
4330  register struct mod_pin_t *mpp;
4331  int32 first_time, pnum;
4332  struct expr_t *cxp;
4333  struct mod_t *mdp;
4334 
4335  __wrap_putc('(', f);
4336  first_time = TRUE;
4337  mdp = ip->imsym->el.emdp;
4338  if ((pnum = mdp->mpnum) == 0) { __nl_wrap_puts(");", f); return; }
4339 
4340  mpp = &(mdp->mpins[0]);
4341  if (ip->ip_explicit)
4342   {
4343    for (pi = 0; pi < pnum; pi++, mpp++)
4344     {
4345      if (first_time) first_time = FALSE; else __wrap_puts(", ", f);
4346      /* even if explicit, if error and no info make implicit */
4347      cxp = iptab[pi];
4348      if (mpp->mpsnam != NULL)
4349       {
4350        __wrap_putc('.', f);
4351        __wrap_puts(mpp->mpsnam, f);
4352        __wrap_putc('(', f);
4353        dmp_expr(f, cxp);
4354        __wrap_putc(')', f);
4355       }
4356      else dmp_expr(f, cxp);
4357     }
4358   }
4359  else
4360   {
4361    for (pi = 0; pi < pnum; pi++)
4362     {
4363      if (first_time) first_time = FALSE; else __wrap_puts(", ", f);
4364      /* even if explicit, if error and no info make implicit */
4365      cxp = iptab[pi];
4366      dmp_expr(f, cxp);
4367     }
4368   }
4369  __nl_wrap_puts(");", f);
4370 }
4371 
4372 /*
4373  * dump 1 gate - source dumping after output net/bit setting in v_fx
4374  */
dmp_1gate(FILE * f,struct gate_t * gp,struct giarr_t * giap)4375 static void dmp_1gate(FILE *f, struct gate_t *gp, struct giarr_t *giap)
4376 {
4377  register int32 pi;
4378  int32 gid, first_time;
4379  char s1[RECLEN];
4380 
4381  /* 1 bit continous assign simulated as gate must be dumped as ca */
4382  if (gp->g_class == GC_LOGIC)
4383   {
4384    gid = gp->gmsym->el.eprimp->gateid;
4385    if (gid == G_ASSIGN) { dmp_1bitconta(f, gp); return; }
4386   }
4387 
4388  /* normal primitive */
4389  __wrap_puts(gp->gmsym->synam, f);
4390  /* know by here if strength on mod. inst. will have emitted error */
4391  if (gp->g_hasst)
4392   {
4393    __wrap_putc(' ', f);
4394    __wrap_puts(__to_stval_nam(s1, gp->g_stval), f);
4395   }
4396  dmp_delay(f, gp->g_du, gp->g_delrep, "#");
4397 
4398  /* if unnamed (system generated name) do not emit inst. name */
4399  if (!gp->g_unam)
4400   {
4401    __wrap_putc(' ', f);
4402    __wrap_puts(gp->gsym->synam, f);
4403   }
4404 
4405  if (giap != NULL)
4406   {
4407    if (__debug_flg)
4408     {
4409      sprintf(s1, " [%d:%d]", giap->gia1, giap->gia2);
4410      __wrap_puts(s1, f);
4411     }
4412    else
4413     {
4414      __wrap_puts(" [", f);
4415      dmp_expr(f, giap->giax1);
4416      __wrap_putc(':', f);
4417      dmp_expr(f, giap->giax2);
4418      __wrap_putc(']', f);
4419     }
4420   }
4421  __wrap_putc('(', f);
4422  for (first_time = TRUE, pi = 0; pi < (int32) gp->gpnum; pi++)
4423   {
4424    if (first_time) first_time = FALSE; else __wrap_puts(", ", f);
4425    if (giap != NULL) dmp_expr(f, giap->giapins[pi]);
4426    else dmp_expr(f, gp->gpins[pi]);
4427   }
4428  __nl_wrap_puts(");", f);
4429 }
4430 
4431 /*
4432  * dbg dump 1 gate - source dumping after output net/bit setting in v_fx
4433  */
4434 /* DBG --- */
dbg_dmp_1gate(FILE * f,struct gate_t * gp,char * gnam)4435 static void dbg_dmp_1gate(FILE *f, struct gate_t *gp, char *gnam)
4436 {
4437  register int32 pi;
4438  int32 gid, first_time;
4439  char s1[RECLEN];
4440 
4441  if (gp->g_class == GC_LOGIC)
4442   {
4443    gid = gp->gmsym->el.eprimp->gateid;
4444    if (gid == G_ASSIGN) { dmp_1bitconta(f, gp); return; }
4445   }
4446 
4447  __wrap_puts(gp->gmsym->synam, f);
4448  if (gp->g_hasst)
4449   {
4450    __wrap_putc(' ', f);
4451    __wrap_puts(__to_stval_nam(s1, gp->g_stval), f);
4452   }
4453  dmp_delay(f, gp->g_du, gp->g_delrep, "#");
4454 
4455  if (!gp->g_unam)
4456   {
4457    __wrap_putc(' ', f);
4458    __wrap_puts(gnam, f);
4459   }
4460  __wrap_putc('(', f);
4461  for (first_time = TRUE, pi = 0; pi < (int32) gp->gpnum; pi++)
4462   {
4463    if (first_time) first_time = FALSE; else __wrap_puts(", ", f);
4464    /* this dumps post expanded pins */
4465    dmp_expr(f, gp->gpins[pi]);
4466   }
4467  __nl_wrap_puts(");", f);
4468 }
4469 /* --- */
4470 
4471 /*
4472  * dump 1 cont. assign
4473  */
dmp_1conta(FILE * f,struct conta_t * cap)4474 static void dmp_1conta(FILE *f, struct conta_t *cap)
4475 {
4476  char s1[RECLEN];
4477 
4478  /* continous assign:  assign #(delay) lhs = rhs; */
4479  __wrap_puts("assign", f);
4480  if (cap->ca_hasst)
4481   {
4482    __wrap_putc(' ', f);
4483    __wrap_puts(__to_stval_nam(s1, cap->ca_stval), f);
4484   }
4485  dmp_delay(f, cap->ca_du, cap->ca_delrep, "#");
4486  __wrap_putc(' ', f);
4487 
4488  dmp_expr(f, cap->lhsx);
4489  __wrap_puts(" = ", f);
4490  dmp_expr(f, cap->rhsx);
4491  __nl_wrap_puts(";", f);
4492 }
4493 
4494 /*
4495  * dump a 1 bit continuous assign strored as a gate
4496  */
dmp_1bitconta(FILE * f,struct gate_t * gp)4497 static void dmp_1bitconta(FILE *f, struct gate_t *gp)
4498 {
4499  char s1[RECLEN];
4500 
4501  /* continous assign:  assign #(delay) lhs = rhs; */
4502  __wrap_puts("assign", f);
4503  if (gp->g_hasst)
4504   { __wrap_putc(' ', f); __wrap_puts(__to_stval_nam(s1, gp->g_stval), f); }
4505  dmp_delay(f, gp->g_du, gp->g_delrep, "#");
4506  __wrap_putc(' ', f);
4507  dmp_expr(f, gp->gpins[0]);
4508  __wrap_puts(" = ", f);
4509  dmp_expr(f, gp->gpins[1]);
4510  __nl_wrap_puts(";", f);
4511 }
4512 
4513 /*
4514  * routine to dump all initial and always statements
4515  */
dmp_ialst(FILE * f,struct mod_t * mdp)4516 static void dmp_ialst(FILE *f, struct mod_t *mdp)
4517 {
4518  struct ialst_t *ialp;
4519 
4520  for (ialp = mdp->ialst; ialp != NULL; ialp = ialp->ialnxt)
4521   {
4522    if (__outlinpos != 0) __nl_wrap_puts("", f);
4523    __pv_stlevel++;
4524    if (ialp->iatyp == ALWAYS) __wrap_puts("always ", f);
4525    else __wrap_puts("initial ", f);
4526    dmp_lstofsts(f, ialp->iastp);
4527    __pv_stlevel--;
4528   }
4529 }
4530 
4531 /*
4532  * routine to reconstruct and write one statement
4533  * this routine can take nill to build entire statement in string
4534  *
4535  * notice this cannot be called with f== nil
4536  */
__dmp_stmt(FILE * f,struct st_t * stp,int32 nd_nl)4537 extern void __dmp_stmt(FILE *f, struct st_t *stp, int32 nd_nl)
4538 {
4539  struct st_t *stp2;
4540  struct for_t *frs;
4541  struct task_t *tskp;
4542  struct st_t *gtstp;
4543 
4544  if (f == NULL) __arg_terr(__FILE__, __LINE__);
4545  if (nd_nl == NL && __outlinpos != 0) __nl_wrap_puts("", f);
4546  switch ((byte) stp->stmttyp) {
4547   case S_NULL:
4548    __wrap_putc(';', f);
4549    if (__debug_flg) __wrap_puts("** S_NULL **", f);
4550    break;
4551   case S_STNONE:
4552    /* none is place holder for empty block, emit nothing */
4553    if (__debug_flg) __wrap_puts("** S_STNONE **", f);
4554    break;
4555   case S_PROCA: case S_FORASSGN: case S_RHSDEPROCA:
4556    __dmp_proc_assgn(f, stp, (struct delctrl_t *) NULL, FALSE);
4557    break;
4558   case S_NBPROCA:
4559    __dmp_nbproc_assgn(f, stp, (struct delctrl_t *) NULL);
4560    break;
4561   case S_IF:
4562    __wrap_puts("if (", f);
4563    dmp_expr(f, stp->st.sif.condx);
4564    __wrap_puts(") ", f);
4565    dmp_lstofsts(f, stp->st.sif.thenst);
4566    if (stp->st.sif.elsest != NULL)
4567     {
4568      if (f != NULL && __outlinpos != 0) __nl_wrap_puts("", f);
4569      __wrap_puts("else ", f);
4570      dmp_lstofsts(f, stp->st.sif.elsest);
4571     }
4572    break;
4573   case S_CASE:
4574    dmp_case(f, stp);
4575    break;
4576   case S_FOREVER:
4577    __wrap_puts("forever ", f);
4578    dmp_lstofsts(f, stp->st.swh.lpst);
4579    break;
4580   case S_REPEAT:
4581    __wrap_puts("repeat (", f);
4582    dmp_expr(f, stp->st.srpt.repx);
4583    __wrap_puts(") ", f);
4584    dmp_lstofsts(f, stp->st.srpt.repst);
4585    break;
4586   case S_WHILE:
4587    __wrap_puts("while (", f);
4588    dmp_expr(f, stp->st.swh.lpx);
4589    __wrap_puts(") ", f);
4590    dmp_lstofsts(f, stp->st.swh.lpst);
4591    break;
4592   case S_WAIT:
4593    __wrap_puts("wait (", f);
4594    dmp_expr(f, stp->st.swait.lpx);
4595    __wrap_puts(") ", f);
4596    dmp_lstofsts(f, stp->st.swait.lpst);
4597    break;
4598   case S_FOR:
4599    frs = stp->st.sfor;
4600    __dmp_forhdr(f, frs);
4601    dmp_lstofsts(f, frs->forbody);
4602    break;
4603   case S_DELCTRL:
4604    __dmp_dctrl(f, stp->st.sdc);
4605    break;
4606   case S_NAMBLK:
4607    /* indent block and statements within */
4608    __pv_stlevel++;
4609    tskp = stp->st.snbtsk;
4610    dmp_task(f, tskp);
4611    __pv_stlevel--;
4612    break;
4613   case S_UNBLK:
4614    if (f != NULL && nd_nl == NONL && __outlinpos != 0) __nl_wrap_puts("", f);
4615    __pv_stlevel++;
4616    if (f != NULL) __nl_wrap_puts("begin", f);
4617    __pv_stlevel++;
4618    for (stp2 = stp->st.sbsts; stp2 != NULL; stp2 = stp2->stnxt)
4619     __dmp_stmt(f, stp2, NL);
4620    __pv_stlevel--;
4621    if (f != NULL && __outlinpos != 0) __nl_wrap_puts("", f);
4622    __nl_wrap_puts("end", f);
4623    __pv_stlevel--;
4624    break;
4625   case S_UNFJ:
4626    /* only place unnamed blocks (not statements lists) is fork-join */
4627    if (f != NULL && nd_nl == NONL && __outlinpos != 0) __nl_wrap_puts("", f);
4628    __pv_stlevel++;
4629    if (f != NULL) __nl_wrap_puts("fork", f);
4630    __pv_stlevel++;
4631    dmp_fj_stlst(f, stp);
4632    __pv_stlevel--;
4633    if (f != NULL && __outlinpos != 0) __nl_wrap_puts("", f);
4634    __nl_wrap_puts("join", f);
4635    __pv_stlevel--;
4636    break;
4637   case S_TSKCALL:
4638    __dmp_tskcall(f, stp);
4639    break;
4640   case S_QCONTA:
4641    if (stp->st.sqca->qcatyp == ASSIGN) __wrap_puts("assign ", f);
4642    else __wrap_puts("force ", f);
4643    dmp_expr(f, stp->st.sqca->qclhsx);
4644    __wrap_puts(" = ", f);
4645    dmp_expr(f, stp->st.sqca->qcrhsx);
4646    __wrap_putc(';', f);
4647    break;
4648   case S_QCONTDEA:
4649    if (stp->st.sqcdea.qcdatyp == DEASSIGN) __wrap_puts("deassign ", f);
4650    else __wrap_puts("release ", f);
4651    dmp_expr(f, stp->st.sqcdea.qcdalhs);
4652    __wrap_putc(';', f);
4653    break;
4654   case S_CAUSE:
4655    __wrap_puts("->", f);
4656    /* this will print global ref. if needed */
4657    dmp_expr(f, stp->st.scausx);
4658    __wrap_putc(';', f);
4659    break;
4660   case S_DSABLE:
4661    __wrap_puts("disable ", f);
4662    dmp_expr(f, stp->st.sdsable.dsablx);
4663    __wrap_putc(';', f);
4664    break;
4665   case S_REPSETUP:
4666    if (__debug_flg) __wrap_puts("**added setup for repeat**", f);
4667    break;
4668   case S_REPDCSETUP:
4669    if (__debug_flg) __wrap_puts("**added repeat event control setup**", f);
4670    break;
4671   case S_GOTO:
4672    if (__debug_flg)
4673     {
4674      char s1[RECLEN], s2[RECLEN], s3[RECLEN], s4[RECLEN];
4675 
4676      gtstp = stp->st.sgoto;
4677      /* DBG remove -- */
4678      if (gtstp == NULL) __misc_terr(__FILE__, __LINE__);
4679      /* --- */
4680      sprintf(s1,
4681       "** add goto at %s [lpend=%0d,dc=%0d,lstend=%0d,dst=%0d] targ %s at %s [lpend=%0d,dc=%0d,lstend=%0d,dst=%0d]",
4682       __bld_lineloc(s2, stp->stfnam_ind, stp->stlin_cnt),
4683       stp->lpend_goto, stp->dctrl_goto, stp->lstend_goto, stp->lpend_goto_dest,
4684       __to_sttyp(s3, gtstp->stmttyp),
4685       __bld_lineloc(s4, gtstp->stfnam_ind, gtstp->stlin_cnt),
4686       gtstp->lpend_goto, gtstp->dctrl_goto, gtstp->lstend_goto,
4687       gtstp->lpend_goto_dest);
4688      __wrap_puts(s1, f);
4689     }
4690    break;
4691   default: __case_terr(__FILE__, __LINE__);
4692   }
4693 }
4694 
4695 /*
4696  * dump a case statement
4697  * notice that now only place for expr lst is case selector lists
4698  * notice this routine cannot take f == nil, not need and tricky formatting
4699  */
dmp_case(FILE * f,struct st_t * stp)4700 static void dmp_case(FILE *f, struct st_t *stp)
4701 {
4702  register struct csitem_t *csip;
4703  register struct exprlst_t *xplp;
4704  int32 first_time;
4705  struct csitem_t *dflt_csip;
4706 
4707  /* dump the case selector */
4708  dmp_casesel(f, stp);
4709  dflt_csip = stp->st.scs.csitems;
4710  csip = dflt_csip->csinxt;
4711  __pv_stlevel++;
4712  for (; csip != NULL; csip = csip->csinxt)
4713   {
4714    if (__outlinpos != 0) { __wrap_putc('\n', f); __outlinpos = 0; }
4715    first_time = TRUE;
4716    for (xplp = csip->csixlst; xplp != NULL; xplp = xplp->xpnxt)
4717     {
4718      if (first_time) first_time = FALSE; else __wrap_puts(", ", f);
4719      dmp_expr(f, xplp->xp);
4720     }
4721    __wrap_putc(':', f);
4722    dmp_lstofsts(f, csip->csist);
4723   }
4724  if (__outlinpos != 0) { __wrap_putc('\n', f); __outlinpos = 0; }
4725  if (dflt_csip->csist != NULL) dmp_case_dflt(f, dflt_csip);
4726  __pv_stlevel--;
4727  if (__outlinpos != 0) __nl_wrap_puts("", f);
4728  __nl_wrap_puts("endcase", f);
4729 }
4730 
4731 /*
4732  * dump default
4733  */
dmp_case_dflt(FILE * f,struct csitem_t * dflt_csip)4734 static void dmp_case_dflt(FILE *f, struct csitem_t *dflt_csip)
4735 {
4736  __outlinpos = 0;
4737  __wrap_puts("default:", f);
4738  if (dflt_csip->csist != NULL) dmp_lstofsts(f, dflt_csip->csist);
4739 }
4740 
4741 /*
4742  * dump a fj statement list - enclosing stuff done elsewhere
4743  */
dmp_fj_stlst(FILE * f,struct st_t * stp)4744 static void dmp_fj_stlst(FILE *f, struct st_t *stp)
4745 {
4746  register int32 fji;
4747  register struct st_t *fjstp;
4748 
4749  for (fji = 0;; fji++)
4750   {
4751    if ((fjstp = stp->st.fj.fjstps[fji]) == NULL) break;
4752 
4753    /* SJM 09/24/01 - can have 2 stmt if for assign and other inserted */
4754    if (fjstp->rl_stmttyp == S_REPSETUP || fjstp->rl_stmttyp == S_FORASSGN
4755     || fjstp->rl_stmttyp == S_REPDCSETUP) fjstp = fjstp->stnxt;
4756 
4757    __dmp_stmt(f, fjstp, NL);
4758   }
4759 }
4760 
4761 /*
4762  * dump a task or function declartion
4763  */
dmp_task(FILE * f,struct task_t * tskp)4764 static void dmp_task(FILE *f, struct task_t *tskp)
4765 {
4766  struct sy_t *syp;
4767 
4768  syp = tskp->tsksyp;
4769  switch ((byte) tskp->tsktyp) {
4770   case TASK:
4771    if (__outlinpos != 0) __nl_wrap_puts("", f);
4772    __nl_wrap_puts("", f);
4773    __wrap_puts("task ", f);
4774    __wrap_puts(syp->synam, f);
4775 
4776    if (tskp->tf_lofp_decl) dmp_tf_lofp_hdr(f, tskp);
4777    __wrap_putc(';', f);
4778 
4779    dmp_tfdecls(f, tskp);
4780    dmp_paramdecls(f, tskp->tsk_prms, tskp->tprmnum, "parameter");
4781    dmp_lstofsts(f, tskp->tskst);
4782    if (__outlinpos != 0) __nl_wrap_puts("", f);
4783    __nl_wrap_puts("endtask", f);
4784    break;
4785   case FUNCTION:
4786    dmp_func_decl(f, tskp);
4787    break;
4788   /* named task */
4789   case Begin:
4790   case FORK:
4791    dmp_nblock(f, tskp, syp->synam);
4792    break;
4793   default: __case_terr(__FILE__, __LINE__);
4794  }
4795 }
4796 
4797 /*
4798  * dump a function declaration
4799  */
dmp_func_decl(FILE * f,struct task_t * tskp)4800 static void dmp_func_decl(FILE *f, struct task_t *tskp)
4801 {
4802  struct net_t *np;
4803  char ftyp[RECLEN], s1[RECLEN];
4804 
4805  if (__outlinpos != 0) __nl_wrap_puts("", f);
4806  __nl_wrap_puts("", f);
4807  np = tskp->tskpins->tpsy->el.enp;
4808  /* set function type */
4809  if (np->ntyp == N_REAL) strcpy(ftyp, "real");
4810  else if (np->ntyp == N_INT) strcpy(ftyp, "integer");
4811  else if (np->ntyp == N_TIME) strcpy(ftyp, "time");
4812  else __to_wrange(ftyp, np);
4813  sprintf(s1, "function %s ", ftyp);
4814  __wrap_puts(s1, f);
4815  __wrap_puts(tskp->tsksyp->synam, f);
4816 
4817  /* for new Ver 2001, if function args declared in header, emit in hdr */
4818  if (tskp->tf_lofp_decl) dmp_tf_lofp_hdr(f, tskp);
4819 
4820  __nl_wrap_puts(";", f);
4821 
4822  dmp_tfdecls(f, tskp);
4823  dmp_paramdecls(f, tskp->tsk_prms, tskp->tprmnum, "parameter");
4824  dmp_lstofsts(f, tskp->tskst);
4825  if (__outlinpos != 0) __nl_wrap_puts("", f);
4826  __nl_wrap_puts("endfunction", f);
4827 }
4828 
4829 /*
4830  * for named block either begin : [n] - end or fork-join blocks
4831  * even if one statement need begin-join block
4832  */
dmp_nblock(FILE * f,struct task_t * tskp,char * bnam)4833 static void dmp_nblock(FILE *f, struct task_t *tskp, char *bnam)
4834 {
4835  struct st_t *stp2;
4836 
4837  __pv_stlevel++;
4838  if (tskp->tsktyp == FORK) __wrap_puts("fork : ", f);
4839  else __wrap_puts("begin : ", f);
4840  __wrap_puts(bnam, f);
4841  __nl_wrap_puts("", f);
4842  dmp_tfdecls(f, tskp);
4843  dmp_paramdecls(f, tskp->tsk_prms, tskp->tprmnum, "parameter");
4844  __pv_stlevel++;
4845  if (tskp->tsktyp == FORK) dmp_fj_stlst(f, tskp->tskst);
4846  else
4847   {
4848    for (stp2 = tskp->tskst; stp2 != NULL; stp2 = stp2->stnxt)
4849     __dmp_stmt(f, stp2, NL);
4850   }
4851  __pv_stlevel--;
4852  if (__outlinpos != 0) __nl_wrap_puts("", f);
4853  if (tskp->tsktyp == FORK) __nl_wrap_puts("join", f);
4854  else __nl_wrap_puts("end", f);
4855  __pv_stlevel--;
4856 }
4857 
4858 /*
4859  * dump tf declares
4860  */
dmp_tfdecls(FILE * f,struct task_t * tskp)4861 static void dmp_tfdecls(FILE *f, struct task_t *tskp)
4862 {
4863  register int32 i;
4864  register struct task_pin_t *tpp;
4865  register struct net_t *regp;
4866  struct sy_t *syp;
4867  char s1[RECLEN], s2[RECLEN], s3[RECLEN];
4868 
4869  if (__outlinpos != 0) __nl_wrap_puts("", f);
4870  if (!tskp->tf_lofp_decl)
4871   {
4872    /* SJM 05/26/04 - only dump tf port if they were not declared in hdr */
4873    for (tpp = tskp->tskpins; tpp != NULL; tpp = tpp->tpnxt)
4874     {
4875      /* 1st parameter for function is required return value */
4876      if (tskp->tsktyp == FUNCTION && tpp == tskp->tskpins) continue;
4877 
4878      syp = tpp->tpsy;
4879      regp = syp->el.enp;
4880      if (!regp->n_isavec || regp->ntyp == N_TIME || regp->ntyp == N_INT
4881       || regp->ntyp == N_REAL) strcpy(s1, "");
4882      else __to_wrange(s1, regp);
4883 
4884      /* notice __to_wrange truncated to max of RECLEN - ok since only no.s */
4885      sprintf(s3, " %s%s ", __to_ptnam(s2, tpp->trtyp), s1);
4886      __wrap_puts(s3, f);
4887      __wrap_puts(syp->synam, f);
4888      __nl_wrap_puts(";", f);
4889     }
4890   }
4891 
4892  if (tskp->trnum == 0) return;
4893  for (i = 0, regp = &(tskp->tsk_regs[0]); i < tskp->trnum; i++, regp++)
4894   {
4895    if (regp->ntyp == N_REG && regp->iotyp != NON_IO) continue;
4896 
4897    if (!regp->n_isavec || regp->ntyp == N_TIME || regp->ntyp == N_INT
4898     || regp->ntyp == N_REAL) strcpy(s1, "");
4899    else __to_wrange(s1, regp);
4900 
4901    sprintf(s3, " %s%s ", __to_wtnam(s2, regp), s1);
4902    __wrap_puts(s3, f);
4903    __wrap_puts(regp->nsym->synam, f);
4904    __nl_wrap_puts(";", f);
4905   }
4906 }
4907 
4908 /*
4909  * dump tf list of ports header task port decls
4910  */
dmp_tf_lofp_hdr(FILE * f,struct task_t * tskp)4911 static void dmp_tf_lofp_hdr(FILE *f, struct task_t *tskp)
4912 {
4913  register struct task_pin_t *tpp;
4914  int32 first_time;
4915  struct sy_t *syp;
4916  struct net_t *regp;
4917  char s1[RECLEN], s2[RECLEN], s3[RECLEN];
4918 
4919  __wrap_putc('(', f);
4920  first_time = TRUE;
4921  for (tpp = tskp->tskpins; tpp != NULL; tpp = tpp->tpnxt)
4922   {
4923    /* 1st parameter for function is required return value */
4924    if (tskp->tsktyp == FUNCTION && tpp == tskp->tskpins) continue;
4925 
4926    if (!first_time) __wrap_puts(", ", f); else first_time = FALSE;
4927 
4928    syp = tpp->tpsy;
4929    regp = syp->el.enp;
4930    if (!regp->n_isavec || regp->ntyp == N_TIME || regp->ntyp == N_INT
4931     || regp->ntyp == N_REAL) strcpy(s1, "");
4932    else __to_wrange(s1, regp);
4933 
4934    /* notice __to_wrange truncated to max of RECLEN - ok since only no.s */
4935    sprintf(s3, "%s%s ", __to_ptnam(s2, tpp->trtyp), s1);
4936    __wrap_puts(s3, f);
4937    __wrap_puts(syp->synam, f);
4938   }
4939  __wrap_putc(')', f);
4940 }
4941 
4942 /*
4943  * SPECIFY SECTION SOURCE DUMP ROUTINES
4944  * NULL FILE ILLEGAL FOR FILL STRING ILLEGAL
4945  */
4946 
4947 /*
4948  * dump module specify section - will not be called if not persent
4949  */
dmp_mdspfy(FILE * f,struct mod_t * mdp)4950 static void dmp_mdspfy(FILE *f, struct mod_t *mdp)
4951 {
4952  struct spfy_t *spfp;
4953 
4954  __pv_stlevel = 1;
4955  if (__outlinpos != 0) __nl_wrap_puts("", f);
4956  __nl_wrap_puts("", f);
4957  __outlinpos = 0;
4958  __nl_wrap_puts("specify", f);
4959 
4960  spfp = mdp->mspfy;
4961  /* parameters - this indents by 1 level */
4962  dmp_paramdecls(f, spfp->msprms, spfp->sprmnum, "specparam");
4963 
4964  __pv_stlevel = 2;
4965  /* delay paths */
4966  dmp_specpths(f, spfp->spcpths);
4967  /* timing checks */
4968  dmp_tchks(f, spfp->tchks);
4969  __pv_stlevel = 1;
4970  __nl_wrap_puts("endspecify", f);
4971  __pv_stlevel = 0;
4972 }
4973 
4974 /*
4975  * dump specify section paths
4976  * (<pth lst> [=*]> <pth lst>) = (<delay list>);
4977  * edge dependent paths will parse but not stored, simulated or dmped
4978  */
dmp_specpths(FILE * f,register struct spcpth_t * pthp)4979 static void dmp_specpths(FILE *f, register struct spcpth_t *pthp)
4980 {
4981  char s1[RECLEN];
4982 
4983  for (; pthp != NULL; pthp = pthp->spcpthnxt)
4984   {
4985    if (pthp->pth_gone) continue;
4986 
4987    /* dump sdpd (state dependent path desc.) if present */
4988    if (pthp->pthcondx != NULL)
4989     {
4990      __wrap_puts("if (", f);
4991      dmp_expr(f, pthp->pthcondx);
4992      __wrap_puts(") ", f);
4993     }
4994    else if (pthp->pth_ifnone) __wrap_puts("ifnone ", f);
4995    if (pthp->datasrcx == NULL)
4996     {
4997      __wrap_putc('(', f);
4998      dmp_pthlst(f, pthp, TRUE);
4999      __wrap_putc(' ', f);
5000      if (pthp->pthpolar != POLAR_NONE)
5001       {
5002       if (pthp->pthpolar == POLAR_PLUS) __wrap_putc('+', f);
5003        else __wrap_putc('-', f);
5004       }
5005      if (pthp->pthtyp == PTH_FULL) __wrap_puts("*> ", f);
5006      else __wrap_puts("=> ", f);
5007      dmp_pthlst(f, pthp, FALSE);
5008     }
5009    else
5010     {
5011      __wrap_putc('(', f);
5012      if (pthp->pthedge != NOEDGE)
5013       {
5014        __wrap_puts(__to_edgenam(s1, pthp->pthedge), f);
5015        __wrap_putc(' ', f);
5016       }
5017      dmp_pthlst(f, pthp, TRUE);
5018      __wrap_putc(' ', f);
5019      if (pthp->pthpolar != POLAR_NONE)
5020       {
5021        if (pthp->pthpolar == POLAR_PLUS) __wrap_putc('+', f);
5022        else __wrap_putc('-', f);
5023       }
5024      if (pthp->pthtyp == PTH_FULL) __wrap_puts("*> ", f);
5025      else __wrap_puts("=> ", f);
5026      /* edge sensitive path output form */
5027      __wrap_putc('(', f);
5028      dmp_pthlst(f, pthp, FALSE);
5029      __wrap_putc(' ', f);
5030      if (pthp->dsrc_polar != POLAR_NONE)
5031       {
5032        if (pthp->dsrc_polar == POLAR_PLUS) __wrap_putc('+', f);
5033        else __wrap_putc('-', f);
5034       }
5035      __wrap_puts(": ", f);
5036      /* this can be fcall comma form, does it work by itself ? */
5037      dmp_expr(f, pthp->datasrcx);
5038      __wrap_putc(')', f);
5039     }
5040    __wrap_puts(") = ", f);
5041    /* notice delay always start with ' ' and if only 1 value no parens */
5042    dmp_delay(f, pthp->pth_du, pthp->pth_delrep, "");
5043    __nl_wrap_puts(";", f);
5044   }
5045 }
5046 
5047 /*
5048  * dump a path list
5049  */
dmp_pthlst(FILE * f,struct spcpth_t * pthp,int32 is_pein)5050 static void dmp_pthlst(FILE *f, struct spcpth_t *pthp, int32 is_pein)
5051 {
5052  register int32 pthi;
5053 
5054  if (is_pein)
5055   {
5056    for (pthi = 0; pthi <= pthp->last_pein; pthi++)
5057     {
5058      if (pthi != 0) __wrap_puts(", ", f);
5059      dmp_pthel(f, &(pthp->peins[pthi]));
5060     }
5061   }
5062  else
5063   {
5064    for (pthi = 0; pthi <= pthp->last_peout; pthi++)
5065     {
5066      if (pthi != 0) __wrap_puts(", ", f);
5067      dmp_pthel(f, &(pthp->peouts[pthi]));
5068     }
5069   }
5070 }
5071 
5072 /*
5073  * dump a preped path element form
5074  */
dmp_pthel(FILE * f,struct pathel_t * pelp)5075 static void dmp_pthel(FILE *f, struct pathel_t *pelp)
5076 {
5077  char s1[RECLEN];
5078 
5079  __wrap_puts(pelp->penp->nsym->synam, f);
5080  if (pelp->pthi1 == -1) return;
5081 
5082  if (pelp->pthi1 == pelp->pthi2) sprintf(s1, "[%d]", pelp->pthi1);
5083  else sprintf(s1, "[%d:%d]", pelp->pthi1, pelp->pthi2);
5084  __wrap_puts(s1, f);
5085 }
5086 
5087 /*
5088  * dump specify section timing checks
5089  * $setup(<data event>, <reference event>, limit, <opt. notifier>)
5090  */
dmp_tchks(FILE * f,register struct tchk_t * tcp)5091 static void dmp_tchks(FILE *f, register struct tchk_t *tcp)
5092 {
5093  char s1[RECLEN];
5094 
5095  for (; tcp != NULL; tcp = tcp->tchknxt)
5096   {
5097    /* when dumping only emit hold (same conn. order half with right name) */
5098    if (tcp->tc_gone || tcp->tc_supofsuphld || tcp->tc_recofrecrem) continue;
5099 
5100    __wrap_puts(__to_tcnam(s1, tcp->tchktyp), f);
5101    __wrap_putc('(', f);
5102    /* dump an event */
5103    dmp_tchk_selector(f, tcp->startedge, tcp->startxp, tcp->startcondx);
5104    if (tcp->tchktyp != TCHK_PERIOD && tcp->tchktyp != TCHK_WIDTH)
5105     {
5106      __wrap_puts(", ", f);
5107      dmp_tchk_selector(f, tcp->chkedge, tcp->chkxp, tcp->chkcondx);
5108     }
5109    /* dump a delay - know will never be list form */
5110    __wrap_puts(", ", f);
5111    dmp_delay(f, tcp->tclim_du, tcp->tc_delrep, "");
5112    if (tcp->tc_haslim2)
5113     {
5114      __wrap_puts(", ", f);
5115      dmp_delay(f, tcp->tclim2_du, tcp->tc_delrep2, "");
5116     }
5117    /* need , place holder if no limit 2 but notifier */
5118    if (tcp->ntfy_np != NULL)
5119     {
5120      __wrap_puts(", ", f);
5121      __wrap_puts(tcp->ntfy_np->nsym->synam, f);
5122     }
5123    __nl_wrap_puts(");", f);
5124   }
5125 }
5126 
5127 /*
5128  * dump a timing check selector expression form
5129  */
dmp_tchk_selector(FILE * f,word32 edgval,struct expr_t * xp,struct expr_t * condx)5130 static void dmp_tchk_selector(FILE *f, word32 edgval, struct expr_t *xp,
5131  struct expr_t *condx)
5132 {
5133  char s1[RECLEN];
5134 
5135  if (edgval != NOEDGE)
5136   { __wrap_puts(__to_edgenam(s1, edgval), f); __wrap_putc(' ', f); }
5137  dmp_expr(f, xp);
5138  if (condx != NULL) { __wrap_puts(" &&& ", f); dmp_expr(f, condx); }
5139 }
5140 
5141 /*
5142  * dump one gref entry
5143  */
dmp_mod_grefs(FILE * f,struct mod_t * mdp)5144 static void dmp_mod_grefs(FILE *f, struct mod_t *mdp)
5145 {
5146  register int32 gri;
5147  register struct gref_t *grp;
5148  char s1[RECLEN];
5149 
5150  if (mdp->mgrnum == 0) return;
5151 
5152  __pv_stlevel = 0;
5153  if (__outlinpos != 0) __nl_wrap_puts("", f);
5154  __wrap_puts("/* ==> hierarchical path occurring in ", f);
5155  __wrap_puts(mdp->msym->synam, f);
5156  __nl_wrap_puts(":", f);
5157  for (gri = 0, grp = &(mdp->mgrtab[0]); gri < mdp->mgrnum; gri++, grp++)
5158   {
5159    if (grp->gr_gone) continue;
5160 
5161    __wrap_puts(grp->gnam, f);
5162    __wrap_puts(to_glbinfo(s1, grp), f);
5163    __nl_wrap_puts("", f);
5164    /* -- could dump target symbol contents */
5165    /* -- could dump expr. containing gref */
5166   }
5167  __nl_wrap_puts("=== end of globals. */", f);
5168 }
5169 
5170 /*
5171  * convert global reference entry to info line
5172  */
to_glbinfo(char * s,struct gref_t * grp)5173 static char *to_glbinfo(char *s, struct gref_t *grp)
5174 {
5175  struct sy_t *syp;
5176  char s1[RECLEN], s2[RECLEN];
5177 
5178  sprintf(s, "<target %s", grp->targmdp->msym->synam);
5179  /* this is symbol corresponding to symbol table target in */
5180  if (grp->targtskp != NULL)
5181   {
5182    syp = grp->targtskp->tsksyp;
5183    sprintf(s1, " in %s %s", __to_sytyp(s2, syp->sytyp), syp->synam);
5184    strcat(s, s1);
5185   }
5186  sprintf(s1, " %s)", __bld_lineloc(s2, grp->grfnam_ind, grp->grflin_cnt));
5187  strcat(s, s1);
5188  strcat(s, ">");
5189  return(s);
5190 }
5191 
5192 /*
5193  * ROUTINES THAT CAN BE CALLED WITH NULL F TO GO IN EXPRLINE
5194  */
5195 
5196 /*
5197  * dump the case selector
5198  */
dmp_casesel(FILE * f,struct st_t * stp)5199 static void dmp_casesel(FILE *f, struct st_t *stp)
5200 {
5201  char s1[RECLEN];
5202 
5203  if (stp->st.scs.castyp == CASEZ) strcpy(s1, "casez");
5204  else if (stp->st.scs.castyp == CASEX) strcpy(s1, "casex");
5205  else strcpy(s1, "case");
5206  __wrap_puts(s1, f);
5207  __wrap_puts(" (", f);
5208  dmp_expr(f, stp->st.scs.csx);
5209  __wrap_putc(')', f);
5210 }
5211 
5212 /*
5213  * for delays already converted to scaled sim. form
5214  * know by this representation if number will not be x/z
5215  *
5216  * handles no delay case (its a union) and if writes insert leading space
5217  * notice dumping delays always just emits the 1st
5218  */
dmp_delay(FILE * f,union del_u du,word32 drep,char * sharps)5219 static void dmp_delay(FILE *f, union del_u du, word32 drep, char *sharps)
5220 {
5221  register int32 i;
5222  int32 ndels;
5223  word32 t1a[2], t1b[2];
5224  word64 tarr[16], tlist[16], *timp;
5225  char s1[RECLEN];
5226 
5227  /* think ,, form will work right here for timing checks */
5228  if (drep == DT_PTHDST || drep == DT_NONE || (drep == DT_CMPLST
5229   && du.pdels == NULL)) goto done;
5230 
5231  if (strcmp(sharps, "") != 0)
5232   { __wrap_putc(' ', f); __wrap_puts(sharps, f); }
5233  t1b[0] = t1b[1] = 0L;
5234 
5235  switch ((byte) drep) {
5236   case DT_1V:
5237    /* 1 v is a ptr to an 8 byte rec., is1v is ptr to array but use 1st */
5238    t1a[0] = (word32) ((*du.d1v) & WORDMASK_ULL);
5239    t1a[1] = (word32) (((*du.d1v) >> 32) & WORDMASK_ULL);
5240    __regab_disp(t1a, t1b, TIMEBITS, BDEC, TRUE, FALSE);
5241    if (f != NULL) { __wrap_puts(__exprline, f); __cur_sofs = 0; }
5242    break;
5243   case DT_IS1V:
5244    /* 1 v is a ptr to an 8 byte rec., is1v is ptr to array but use 1st */
5245    t1a[0] = (word32) (du.dis1v[0] & WORDMASK_ULL);
5246    t1a[1] = (word32) ((du.dis1v[0] >> 32) & WORDMASK_ULL);
5247    __regab_disp(t1a, t1b, TIMEBITS, BDEC, TRUE, FALSE);
5248    if (f != NULL) { __wrap_puts(__exprline, f); __cur_sofs = 0; }
5249    break;
5250   case DT_IS1V1:
5251    sprintf(s1, "%lu", (word32) du.dis1v1[0]);
5252    __wrap_puts(s1, f);
5253    break;
5254   case DT_IS1V2:
5255    sprintf(s1, "%lu", (word32) du.dis1v2[0]);
5256    __wrap_puts(s1, f);
5257    break;
5258   case DT_4V: timp = du.d4v; goto do4;
5259   case DT_IS4V:
5260    timp = du.dis4v;
5261 do4:
5262    /* for IS 4 v linear array of groups of 4 so just use first */
5263    __wrap_putc('(', f);
5264    t1a[0] = (word32) (timp[1] & WORDMASK_ULL);
5265    t1a[1] = (word32) ((timp[1] >> 32) & WORDMASK_ULL);
5266 
5267    __regab_disp(t1a, t1b, TIMEBITS, BDEC, TRUE, FALSE);
5268    if (f != NULL) { __wrap_puts(__exprline, f); __cur_sofs = 0; }
5269    __wrap_puts(", ", f);
5270    t1a[0] = (word32) (timp[0] & WORDMASK_ULL);
5271    t1a[1] = (word32) ((timp[0] >> 32) & WORDMASK_ULL);
5272    __regab_disp(t1a, t1b, TIMEBITS, BDEC, TRUE, FALSE);
5273    if (f != NULL) { __wrap_puts(__exprline, f); __cur_sofs = 0; }
5274    __wrap_puts(", ", f);
5275    t1a[0] = (word32) (timp[2] & WORDMASK_ULL);
5276    t1a[1] = (word32) ((timp[2] >> 32) & WORDMASK_ULL);
5277    __regab_disp(t1a, t1b, TIMEBITS, BDEC, TRUE, FALSE);
5278    if (f != NULL) { __wrap_puts(__exprline, f); __cur_sofs = 0; }
5279    __wrap_putc(')', f);
5280    break;
5281   case DT_IS4V1:
5282    /* for IS 4 v linear array of groups of 4 so just use first */
5283    sprintf(s1, "(%lu, %lu, %lu)", (word32) du.dis4v1[1],
5284     (word32) du.dis4v1[0], (word32) du.dis4v1[2]);
5285    __wrap_puts(s1, f);
5286    break;
5287   case DT_IS4V2:
5288    /* for IS 4 v linear array of groups of 4 so just use first */
5289    sprintf(s1, "(%lu, %lu, %lu)", (word32) du.dis4v2[1],
5290     (word32) du.dis4v2[0], (word32) du.dis4v2[2]);
5291    __wrap_puts(s1, f);
5292    break;
5293   /* notice all the 6 forms are really size 16 tables */
5294   case DT_16V: timp = du.d16v; goto do16;
5295   case DT_IS16V:
5296    timp = du.dis16v;
5297 do16:
5298    for (i = 0; i < 16; i++) tarr[i] = timp[i];
5299 try_reduce:
5300    /* first step, reorder internal 16 table to 12 values */
5301    __map_16v_to_12vform(tlist, tarr);
5302    __try_reduce_16vtab(tlist, &ndels);
5303    __wrap_putc('(', f);
5304    for (i = 0; i < ndels; i++)
5305     {
5306      if (i != 0) __wrap_puts(", ", f);
5307      t1a[0] = (word32) (tlist[i] & WORDMASK_ULL);
5308      t1a[1] = (word32) ((tlist[i] >> 32) & WORDMASK_ULL);
5309      __regab_disp(t1a, t1b, TIMEBITS, BDEC, TRUE, FALSE);
5310      if (f != NULL) { __wrap_puts(__exprline, f); __cur_sofs = 0; }
5311     }
5312    __wrap_putc(')', f);
5313    break;
5314   case DT_IS16V1:
5315    for (i = 0; i < 16; i++) { tarr[i] = (word64) du.dis16v1[i]; }
5316    goto try_reduce;
5317   case DT_IS16V2:
5318    for (i = 0; i < 16; i++) { tarr[i] = (word64) du.dis16v2[i]; }
5319    goto try_reduce;
5320   case DT_1X:
5321    __wrap_putc('(', f);
5322    dmp_expr(f, du.d1x);
5323    __wrap_putc(')', f);
5324    break;
5325   case DT_4X:
5326    __wrap_putc('(', f);
5327    dmp_expr(f, du.d4x[1]);
5328    __wrap_puts(", ", f);
5329    dmp_expr(f, du.d4x[0]);
5330    if (du.d4x[2] != NULL) { __wrap_puts(", ", f); dmp_expr(f, du.d4x[2]); }
5331    __wrap_putc(')', f);
5332    break;
5333   case DT_CMPLST:
5334    dmp_dellst(f, du.pdels);
5335    break;
5336   default: __case_terr(__FILE__, __LINE__);
5337  }
5338 done:
5339  if (f != NULL) __cur_sofs = 0; else __exprline[__cur_sofs] = '\0';
5340 }
5341 
5342 /*
5343  * dump a delay or module instance parameter list
5344  * this must handle no delay case
5345  */
dmp_dellst(FILE * f,register struct paramlst_t * pmp)5346 static void dmp_dellst(FILE *f, register struct paramlst_t *pmp)
5347 {
5348  int32 first_time;
5349  struct expr_t *xp;
5350 
5351  __force_base = BDEC;
5352  if (pmp->pmlnxt == NULL)
5353   {
5354    xp = pmp->plxndp;
5355    switch ((byte) xp->optyp) {
5356     case NUMBER: case REALNUM: case ISNUMBER: case ISREALNUM: case ID:
5357      dmp_expr(f, pmp->plxndp);
5358      __force_base = BNONE;
5359      return;
5360     }
5361   }
5362  /* for even 1 expr. need parentheses - also for global here */
5363  __wrap_putc('(', f);
5364  for (first_time = TRUE; pmp != NULL; pmp = pmp->pmlnxt)
5365   {
5366    if (first_time) first_time = FALSE; else __wrap_puts(", ", f);
5367    dmp_expr(f, pmp->plxndp);
5368   }
5369  __wrap_putc(')', f);
5370  __force_base = BNONE;
5371 }
5372 
5373 /*
5374  * dump the for header part
5375  */
__dmp_forhdr(FILE * f,struct for_t * frs)5376 extern void __dmp_forhdr(FILE *f, struct for_t *frs)
5377 {
5378  int32 sav_debug_flg;
5379 
5380  sav_debug_flg = __debug_flg;
5381  __debug_flg = TRUE;
5382  __wrap_puts("for (", f);
5383  /* ending ; will be written */
5384  __dmp_proc_assgn(f, frs->forassgn, (struct delctrl_t *) NULL, TRUE);
5385  __wrap_putc(' ', f);
5386  dmp_expr(f, frs->fortermx);
5387  __wrap_puts("; ", f);
5388  /* cannot use dmp procedural assign because of trailing ; */
5389  dmp_expr(f, frs->forinc->st.spra.lhsx);
5390  __wrap_puts(" = ", f);
5391  dmp_expr(f, frs->forinc->st.spra.rhsx);
5392  __wrap_puts(") ", f);
5393  __debug_flg = sav_debug_flg;
5394 }
5395 
5396 /*
5397  * dump a procedural assignment statement
5398  * for rhs delay control statement is dctrl action statement
5399  */
__dmp_proc_assgn(FILE * f,struct st_t * stp,struct delctrl_t * dctp,int32 force_for)5400 extern void __dmp_proc_assgn(FILE *f, struct st_t *stp, struct delctrl_t *dctp,
5401  int32 force_for)
5402 {
5403  /* for assign moved to before for, but must not emit */
5404  if (!force_for && stp->stmttyp == S_FORASSGN && stp->stnxt != NULL
5405   && stp == stp->stnxt->st.sfor->forassgn) return;
5406 
5407  dmp_expr(f, stp->st.spra.lhsx);
5408  __wrap_puts(" = ", f);
5409 
5410  if (dctp != NULL)
5411   {
5412    if (dctp->repcntx != NULL)
5413     {
5414      __wrap_puts("repeat (", f);
5415      dmp_expr(f, dctp->repcntx);
5416      __wrap_puts(") ", f);
5417     }
5418    __dmp_dctrl(f, dctp);
5419   }
5420  dmp_expr(f, stp->st.spra.rhsx);
5421  __wrap_puts(";", f);
5422  /* here may have added goto for rhs form */
5423  if (dctp != NULL && dctp->actionst != NULL)
5424   __dmp_stmt(f, dctp->actionst, FALSE);
5425 }
5426 
5427 /*
5428  * dump a non blocking procedural assignment statement
5429  * for rhs delay control statement is dctrl action statement
5430  */
__dmp_nbproc_assgn(FILE * f,struct st_t * stp,struct delctrl_t * dctp)5431 extern void __dmp_nbproc_assgn(FILE *f, struct st_t *stp,
5432  struct delctrl_t *dctp)
5433 {
5434  dmp_expr(f, stp->st.spra.lhsx);
5435  __wrap_puts(" <= ", f);
5436  /* know this dctrl will not have action statement */
5437  if (dctp != NULL)
5438   {
5439    if (dctp->repcntx != NULL)
5440     {
5441      __wrap_puts("repeat (", f);
5442      dmp_expr(f, dctp->repcntx);
5443      __wrap_puts(") ", f);
5444     }
5445    __dmp_dctrl(f, dctp);
5446   }
5447  dmp_expr(f, stp->st.spra.rhsx);
5448  __wrap_puts(";", f);
5449 }
5450 
5451 /*
5452  * dump a delay control
5453  */
__dmp_dctrl(FILE * f,struct delctrl_t * dctp)5454 extern void __dmp_dctrl(FILE *f, struct delctrl_t *dctp)
5455 {
5456  struct delctrl_t tmpdctp;
5457 
5458  switch ((byte) dctp->dctyp) {
5459   case DC_EVENT:
5460    __wrap_putc('@', f);
5461 non_rhs:
5462    /* continue on same line */
5463    __dmp_dcxpr(f, dctp->dc_du, dctp->dc_delrep);
5464    /* this can be list because of added goto if debug flag on */
5465    if (dctp->actionst != NULL) dmp_lstofsts(f, dctp->actionst);
5466    break;
5467   case DC_DELAY:
5468    __wrap_putc('#', f);
5469    goto non_rhs;
5470   case DC_RHSEVENT:
5471   case DC_RHSDELAY:
5472    if (dctp->dctyp == DC_RHSEVENT) tmpdctp.dctyp = DC_EVENT;
5473    else tmpdctp.dctyp = DC_DELAY;
5474    tmpdctp.actionst = NULL;
5475    /* notice since this is read only just sharing previous expr */
5476    tmpdctp.dc_delrep = dctp->dc_delrep;
5477    tmpdctp.dc_du = dctp->dc_du;
5478    tmpdctp.repcntx = dctp->repcntx;
5479 
5480    if (dctp->actionst->stmttyp == S_NBPROCA)
5481     __dmp_nbproc_assgn(f, dctp->actionst, &tmpdctp);
5482    else if (dctp->actionst->stmttyp == S_RHSDEPROCA)
5483     __dmp_proc_assgn(f, dctp->actionst, &tmpdctp, FALSE);
5484    else __case_terr(__FILE__, __LINE__);
5485    /* if dumping source - maybe goto as actionst next */
5486    if (__run_state != SS_SIM && dctp->actionst->stnxt != NULL)
5487     {
5488      /* notice set off during wire init and no statemnt exec there */
5489      if (dctp->actionst->stnxt->stmttyp != S_GOTO)
5490       __misc_terr(__FILE__, __LINE__);
5491      __dmp_stmt(f, dctp->actionst->stnxt, NONL);
5492     }
5493    break;
5494   default: __case_terr(__FILE__, __LINE__);
5495  }
5496  if (f == NULL) __exprline[__cur_sofs] = '\0';
5497 }
5498 
5499 /*
5500  * dump the actual delay
5501  * can be used during compilation or after prep. where ticks (scaled) dumped
5502  */
__dmp_dcxpr(FILE * f,union del_u du,word32 drep)5503 extern void __dmp_dcxpr(FILE *f, union del_u du, word32 drep)
5504 {
5505  int32 leaf;
5506  struct expr_t *dxp;
5507 
5508  __force_base = BDEC;
5509  if (drep != DT_CMPLST)
5510   {
5511    dmp_delay(f, du, drep, "");
5512    __wrap_putc(' ', f);
5513   }
5514  else
5515   {
5516    dxp = du.pdels->plxndp;
5517    leaf = __isleaf(dxp);
5518    if (!leaf) __wrap_putc('(', f);
5519    dmp_expr(f, dxp);
5520    if (!leaf) __wrap_putc(')', f);
5521    /* needed to make sure exprline for f nil terminated */
5522    __wrap_putc(' ', f);
5523   }
5524  if (f == NULL) __exprline[__cur_sofs] = '\0';
5525  __force_base = BNONE;
5526 }
5527 
5528 /*
5529  * dump a task call
5530  * should dump task call global name
5531  */
__dmp_tskcall(FILE * f,struct st_t * stp)5532 extern void __dmp_tskcall(FILE *f, struct st_t *stp)
5533 {
5534  register struct expr_t *xp;
5535  int32 first_time;
5536 
5537  dmp_expr(f, stp->st.stkc.tsksyx);
5538  first_time = TRUE;
5539  for (xp = stp->st.stkc.targs; xp != NULL; xp = xp->ru.x)
5540   {
5541    if (first_time) { __wrap_putc('(', f); first_time = FALSE; }
5542    else __wrap_puts(", ", f);
5543    dmp_expr(f, xp->lu.x);
5544   }
5545  if (!first_time) __wrap_putc(')', f);
5546  /* need null terminated string */
5547  __wrap_puts(";", f);
5548 }
5549 
5550 /*
5551  * dump a statement list
5552  */
dmp_lstofsts(FILE * f,struct st_t * hdstp)5553 static void dmp_lstofsts(FILE *f, struct st_t *hdstp)
5554 {
5555  register struct st_t *stp;
5556 
5557  if (hdstp->st_unbhead)
5558   {
5559    if (__outlinpos != 0) __nl_wrap_puts("", f);
5560    __pv_stlevel++;
5561    __wrap_puts("begin", f);
5562    __pv_stlevel++;
5563    for (stp = hdstp; stp != NULL; stp = stp->stnxt)
5564     __dmp_stmt(f, stp, NL);
5565    if (__outlinpos != 0) __nl_wrap_puts("", f);
5566    __pv_stlevel--;
5567    __nl_wrap_puts("end", f);
5568    __pv_stlevel--;
5569    return;
5570   }
5571  /* added control statements if being printed go on same line */
5572  for (stp = hdstp; stp != NULL; stp = stp->stnxt)
5573   __dmp_stmt(f, stp, NONL);
5574 }
5575 
5576 /*
5577  * build an array range expression from a net
5578  * assume comp. time representation
5579  *
5580  * notice this uses expr line so cannot be called from expr_tostr
5581  * but does call it
5582  */
__to_arr_range(char * s,struct net_t * np)5583 extern char *__to_arr_range(char *s, struct net_t *np)
5584 {
5585  int32 r1, r2, awid;
5586 
5587  if (np->n_isarr)
5588   {
5589    if (np->nrngrep == NX_CT)
5590     __msgtox_wrange(s, np->nu.ct->ax1, np->nu.ct->ax2);
5591    else
5592     {
5593      __getarr_range(np, &r1, &r2, &awid);
5594      sprintf(s, "[%d:%d]", r1, r2);
5595     }
5596   }
5597  else strcpy(s, "");
5598  return(s);
5599 }
5600 
5601 /*
5602  * build a wire range expression from a net
5603  * silently trucates if > RECLEN
5604  *
5605  * this is for ranges in messages - ok since will be numbers, if expr.
5606  * will use other routine
5607  */
__to_wrange(char * s,struct net_t * np)5608 extern char *__to_wrange(char *s, struct net_t *np)
5609 {
5610  int32 r1, r2;
5611 
5612  if (np->n_isavec)
5613   {
5614    if (np->nrngrep == NX_CT)
5615     __msgtox_wrange(s, np->nu.ct->nx1, np->nu.ct->nx2);
5616    else
5617     {
5618 
5619      /* if this is a vector and not compile time rep, know will be range */
5620      __getwir_range(np, &r1, &r2);
5621      sprintf(s, "[%d:%d]", r1, r2);
5622     }
5623   }
5624  else strcpy(s, "");
5625  return(s);
5626 }
5627 
5628 /*
5629  * build a range expression in expr line
5630  * must terminate string in exprline if nil
5631  * this can be nil
5632  */
tox_wrange(FILE * f,struct expr_t * x1,struct expr_t * x2)5633 static void tox_wrange(FILE *f, struct expr_t *x1, struct expr_t *x2)
5634 {
5635  __force_base = BDEC;
5636  if (x1 == NULL) return;
5637  __wrap_putc('[', f);
5638  dmp_expr(f, x1);
5639  __wrap_putc(':', f);
5640  dmp_expr(f, x2);
5641  __wrap_putc(']', f);
5642  if (f == NULL) __exprline[__cur_sofs] = '\0';
5643  __force_base = BNONE;
5644 }
5645 
5646 
5647 /*
5648  * ROUTINES TO DUMP VERILOG EXPRESSIONS TO SOURCE FORMAT
5649  */
5650 
5651 /*
5652  * either write a string through dmp puts path (wraps lines) if f not nil
5653  * or else collect in __exprline starting at __cur_sofs (make big enough)
5654  *
5655  * must write immediately for dumping source to get line wrapping right
5656  * note this requires current itree place - will crash otherwise
5657  * if f is not nil, __cur_sofs must be set to 0 since used as work area
5658  */
dmp_expr(FILE * f,struct expr_t * ndp)5659 static void dmp_expr(FILE *f, struct expr_t *ndp)
5660 {
5661  int32 indv, ind1, ind2, nd_par, sav_spos;
5662  word32 *wp;
5663  struct net_t *np;
5664  char *chp;
5665  char s1[RECLEN];
5666 
5667  /* expr. pointer while converting to string bad */
5668  if (ndp == NULL || ndp->optyp == 0 || ndp->optyp == UNDEF)
5669   __misc_terr(__FILE__, __LINE__);
5670 
5671  switch ((byte) ndp->optyp) {
5672   case ID:
5673    /* if empty symbol - emit empty string here - for wire ranges */
5674    if (ndp->lu.sy == NULL) return;
5675    if (ndp->locqualnam) chp = ndp->ru.qnchp; else chp = ndp->lu.sy->synam;
5676    __wrap_puts(chp, f);
5677    return;
5678   case GLBREF:
5679    /* know gref always have name - first expr. image during parsing */
5680    /* then image with instance array selectors folded to numbers */
5681    /* once parsing complete xmrs convert to gnam so if global */
5682    /* select is xmr that expr will resolved to gnam before here */
5683    chp = ndp->ru.grp->gnam;
5684    __wrap_puts(chp, f);
5685    return;
5686   case XMRID:
5687    /* special case during global resolution xmr name - no symbol */
5688    chp = ndp->ru.qnchp;
5689    __wrap_puts(chp, f);
5690    return;
5691   case NUMBER: case ISNUMBER: case REALNUM: case ISREALNUM:
5692    /* if empty do not emit anything, else fill with constant value  */
5693    /* this knows about all number forms but IS is 0th only */
5694    if (f == NULL) numexpr_disp(ndp, 0);
5695    else
5696     {
5697      sav_spos = __cur_sofs;
5698      numexpr_disp(ndp, 0);
5699      __wrap_puts(&(__exprline[sav_spos]), f);
5700      __cur_sofs = sav_spos;
5701      __exprline[__cur_sofs] = '\0';
5702     }
5703    return;
5704   case LSB:
5705    if (ndp->lu.x->optyp == XMRID) dmp_expr(f, ndp->lu.x);
5706    else if (ndp->lu.x->lu.sy != NULL) dmp_expr(f, ndp->lu.x);
5707    __wrap_putc('[', f);
5708    /* convert to original value (not h:0 new adjusted) if needed */
5709    if (ndp->ru.x->ind_noth0 && ndp->lu.x->lu.sy != NULL)
5710     {
5711      /* notice for dumping - convention is to use IS 0th */
5712      wp = &(__contab[ndp->ru.x->ru.xvi]);
5713      indv = __unnormalize_ndx(ndp->lu.x->lu.sy->el.enp, (int32) wp[0]);
5714      sprintf(s1, "%d", indv);
5715      __wrap_puts(s1, f);
5716      __wrap_putc(']', f);
5717     }
5718    else { dmp_expr(f, ndp->ru.x); __wrap_putc(']', f); }
5719    if (f == NULL) __exprline[__cur_sofs] = '\0';
5720    return;
5721   case PARTSEL:
5722    if (ndp->lu.x->lu.sy != NULL) dmp_expr(f, ndp->lu.x);
5723    __wrap_putc('[', f);
5724    /* convert to original value (not h:0 new adjusted) if needed */
5725    if (ndp->ru.x->lu.x->ind_noth0 && ndp->lu.x->lu.sy != NULL)
5726     {
5727      np = ndp->lu.x->lu.sy->el.enp;
5728      /* know part select range never IS form */
5729      wp = &(__contab[ndp->ru.x->lu.x->ru.xvi]);
5730      ind1 = __unnormalize_ndx(np, (int32) wp[0]);
5731      wp = &(__contab[ndp->ru.x->ru.x->ru.xvi]);
5732      ind2 = __unnormalize_ndx(np, (int32) wp[0]);
5733      sprintf(s1, "%d:%d]", ind1, ind2);
5734      __wrap_puts(s1, f);
5735     }
5736    else
5737     {
5738      dmp_expr(f, ndp->ru.x->lu.x);
5739      __wrap_putc(':', f);
5740      dmp_expr(f, ndp->ru.x->ru.x);
5741      __wrap_putc(']', f);
5742      if (f == NULL) __exprline[__cur_sofs] = '\0';
5743     }
5744    return;
5745   case QUEST:
5746    /* for now need parentheses around these or cannot parse */
5747    __wrap_putc('(', f);
5748    dmp_expr(f, ndp->lu.x);
5749    __wrap_putc(')', f);
5750    __wrap_puts(" ? ", f);
5751    dmp_expr(f, ndp->ru.x->lu.x);
5752    __wrap_puts(" : ", f);
5753    dmp_expr(f, ndp->ru.x->ru.x);
5754    return;
5755   case LCB:
5756    /* l of expr. node empty */
5757    dmp_catexpr(f, ndp);
5758    return;
5759   case FCALL:
5760    dmp_fcallx(f, ndp);
5761    return;
5762   /* dumping empty is write nothing */
5763   case OPEMPTY:
5764    return;
5765   /* event or cannot be parenthesisized or nested */
5766   case OPEVOR: case OPEVCOMMAOR:
5767    /* SJM 06/01/04 - current scheme is 2 ops that print different but same */
5768    dmp_evor_chain(f, ndp);
5769    return;
5770   /* FALLTHRU */
5771  }
5772  /* know this is operator - unary has right subtree nil */
5773  if (ndp->ru.x == NULL)
5774   {
5775    __wrap_puts(__to_opname(ndp->optyp), f);
5776    if (!is_simplex(ndp->lu.x) && ndp->lu.x->ru.x != NULL) nd_par = TRUE;
5777    else nd_par = FALSE;
5778    if (nd_par) __wrap_putc('(', f);
5779 
5780    dmp_expr(f, ndp->lu.x);
5781    if (nd_par) __wrap_putc(')', f);
5782    if (f == NULL) __exprline[__cur_sofs] = '\0';
5783    return;
5784   }
5785  /* DBG remove --- */
5786  if (ndp->lu.x == NULL) __misc_terr(__FILE__, __LINE__);
5787  /* --- */
5788  /* know this is binary */
5789  if (!is_simplex(ndp->lu.x)) nd_par = TRUE; else nd_par = FALSE;
5790  if (nd_par) __wrap_putc('(', f);
5791  dmp_expr(f, ndp->lu.x);
5792  if (nd_par) __wrap_putc(')', f);
5793  __wrap_putc(' ', f);
5794  __wrap_puts(__to_opname(ndp->optyp), f);
5795  __wrap_putc(' ', f);
5796  if (!is_simplex(ndp->ru.x)) nd_par = TRUE; else nd_par = FALSE;
5797  if (nd_par) __wrap_putc('(', f);
5798  dmp_expr(f, ndp->ru.x);
5799  if (nd_par) __wrap_putc(')', f);
5800  if (f == NULL) __exprline[__cur_sofs] = '\0';
5801 }
5802 
5803 /*
5804  * return T if is simple object expr. leaf, concat, or fcall
5805  * that does not need parenthesis
5806  */
is_simplex(struct expr_t * xp)5807 static int32 is_simplex(struct expr_t *xp)
5808 {
5809  if (__isleaf(xp)) return(TRUE);
5810  switch (xp->optyp) {
5811   case LSB: case PARTSEL: case LCB: case FCALL: return(TRUE);
5812  }
5813  return(FALSE);
5814 }
5815 
5816 /*
5817  * dump a concatenate
5818  * this really needs to have new lines and indentation added
5819  */
dmp_catexpr(FILE * f,struct expr_t * ndp)5820 static void dmp_catexpr(FILE *f, struct expr_t *ndp)
5821 {
5822  int32 first_time;
5823 
5824  __wrap_putc('{', f);
5825  /* know { operator left always unused */
5826  for (first_time = TRUE, ndp = ndp->ru.x; ndp != NULL; ndp = ndp->ru.x)
5827   {
5828    if (!first_time) __wrap_puts(", ", f); else first_time = FALSE;
5829    dmp_catel(f, ndp->lu.x);
5830   }
5831  __wrap_putc('}', f);
5832  if (f == NULL) __exprline[__cur_sofs] = '\0';
5833 }
5834 
5835 /*
5836  * dump a concatenate element
5837  */
dmp_catel(FILE * f,struct expr_t * ndp)5838 static void dmp_catel(FILE *f, struct expr_t *ndp)
5839 {
5840  if (ndp->optyp == CATREP)
5841   {
5842    __wrap_putc('(', f);
5843    dmp_expr(f, ndp->lu.x);
5844    __wrap_putc(')', f);
5845    dmp_catexpr(f, ndp->ru.x);
5846   }
5847  else dmp_expr(f, ndp);
5848 }
5849 
5850 /*
5851  * dump a function call
5852  */
dmp_fcallx(FILE * f,struct expr_t * ndp)5853 static void dmp_fcallx(FILE *f, struct expr_t *ndp)
5854 {
5855  int32 first_time;
5856  char paren;
5857 
5858  dmp_expr(f, ndp->lu.x);
5859  if (ndp->ru.x == NULL) return;
5860 
5861  paren = '(';
5862 
5863  __wrap_putc(paren, f);
5864  if (ndp->ru.x == NULL) return;
5865  /* know fcall operator left always unused */
5866  for (first_time = TRUE, ndp = ndp->ru.x; ndp != NULL; ndp = ndp->ru.x)
5867   {
5868    if (!first_time) __wrap_puts(", ", f); else first_time = FALSE;
5869    dmp_expr(f, ndp->lu.x);
5870   }
5871  if (paren == '<') __wrap_putc('>', f); else __wrap_putc(')', f);
5872  if (f == NULL) __exprline[__cur_sofs] = '\0';
5873 }
5874 
5875 /*
5876  * dump an event evor expression
5877  * syntax allow ([edge] [expr] or ([normal expression]) and
5878  * ([event expr] or [event expr] or [] ) - stylized chain only
5879  *
5880  * LOOKATME:
5881  * but associating to left for some reason - works since just list that
5882  * each of which gets added to dcelst as dcevnt
5883  * maybe needed because rhs section can be complicated expr. not just chain
5884  * as in concat case
5885  */
dmp_evor_chain(FILE * f,struct expr_t * ndp)5886 static void dmp_evor_chain(FILE *f, struct expr_t *ndp)
5887 {
5888  if (ndp->lu.x->optyp == OPEVOR || ndp->lu.x->optyp == OPEVCOMMAOR)
5889   {
5890    dmp_evor_chain(f, ndp->lu.x);
5891   }
5892  else dmp_expr(f, ndp->lu.x);
5893 
5894  if (ndp->lu.x->optyp == OPEVOR) __wrap_puts(" or ", f);
5895  else __wrap_puts(", ", f);
5896 
5897  dmp_expr(f, ndp->ru.x);
5898 }
5899 
5900 /*
5901  * put a string for source statement dumping handles line wrap and
5902  * statement level indenting
5903  */
__wrap_puts(char * s,FILE * f)5904 extern void __wrap_puts(char *s, FILE *f)
5905 {
5906  int32 ll;
5907 
5908  ll = strlen(s);
5909  if (f == NULL)
5910   {
5911    if (__cur_sofs + ll >= __exprlinelen - 1) __chg_xprline_size(ll + 1);
5912    strcpy(&(__exprline[__cur_sofs]), s);
5913    __cur_sofs += ll;
5914    return;
5915   }
5916 
5917  /* case 1: at beginning of line, just need statement indent */
5918  if (__outlinpos == 0)
5919   {
5920    if (__pv_stlevel > 0)
5921     {
5922      __blnkline[__pv_stlevel] = '\0';
5923      __cvsim_msg(__blnkline);
5924      __blnkline[__pv_stlevel] = ' ';
5925     }
5926    /* always print s no matter how wide - cannot break inside objs */
5927    __outlinpos = __pv_stlevel + ll;
5928 
5929    __cvsim_msg("%s", s);
5930    return;
5931   }
5932 
5933  /* case 2: try continuation on current line */
5934  /* if string <= 2 make this line slightly too long (for ,[space]) */
5935  if ((__outlinpos += ll) > OUTLINLEN)
5936   {
5937    /* various ending punctuation (short fields) should go on same line */
5938    if ((ll > 3 || (!ispunct(s[0]) && s[0] != ' '))
5939     || __outlinpos > OUTLINLEN + 6)
5940     {
5941      __cvsim_msg("\n");
5942 
5943      __blnkline[__pv_stlevel + 1] = '\0';
5944      __cvsim_msg("%s", __blnkline);
5945      __blnkline[__pv_stlevel + 1] = ' ';
5946      __outlinpos = __pv_stlevel + ll + 1;
5947     }
5948   }
5949  /* cannot use printf here since must emit format with % as is */
5950  __cvsim_msg("%s", s);
5951 }
5952 
5953 /*
5954  * source statement put char analog of put string above
5955  */
__wrap_putc(int32 c,FILE * f)5956 extern void __wrap_putc(int32 c, FILE *f)
5957 {
5958  if (f == NULL) { addch_(c); return; }
5959 
5960  if (__outlinpos == 0)
5961   {
5962    if (__pv_stlevel > 0)
5963     {
5964      __blnkline[__pv_stlevel] = '\0';
5965      __cvsim_msg("%s", __blnkline);
5966      __blnkline[__pv_stlevel] = ' ';
5967     }
5968    __outlinpos = __pv_stlevel + 1;
5969    __cvsim_msg("%c", c);
5970    return;
5971   }
5972 
5973  /* if string <= 2 make this line slightly too long (for ,[space]) */
5974  if (++__outlinpos > OUTLINLEN)
5975   {
5976    /* various ending punctuation (short fields) should go on same line */
5977    if ((!ispunct(c) && c != ' ') || __outlinpos > OUTLINLEN + 6)
5978     {
5979      __cvsim_msg("\n");
5980 
5981      __blnkline[__pv_stlevel + 1] = '\0';
5982      __cvsim_msg("%s", __blnkline);
5983      __blnkline[__pv_stlevel + 1] = ' ';
5984      __outlinpos = __pv_stlevel + 2;
5985     }
5986   }
5987  __cvsim_msg("%c", c);
5988 }
5989 
5990 /*
5991  * wrap form of puts that adds new line
5992  * notice macro does nothing if called with f == nil
5993  */
__nl_wrap_puts(char * s,FILE * f)5994 extern void __nl_wrap_puts(char *s, FILE *f)
5995 {
5996  if (f != NULL)
5997   {
5998    if (*s != '\0') __wrap_puts(s, f);
5999    __wrap_putc('\n', f);
6000    __outlinpos = 0;
6001   }
6002  else __cur_sofs = 0;
6003 }
6004 
6005 /*
6006  * add string to current place in __exprline
6007  * notice this always leaves line null terminated but addch_ macros does not
6008  */
__adds(char * s)6009 extern void __adds(char *s)
6010 {
6011  int32 slen;
6012 
6013  slen = strlen(s);
6014  if (__cur_sofs + slen >= __exprlinelen - 1) __chg_xprline_size(slen + 1);
6015  strcpy(&(__exprline[__cur_sofs]), s);
6016  __cur_sofs += slen;
6017 }
6018 
6019 /*
6020  * change the length of a partially filled expr string line
6021  * if need to increase increase by needed amount plus large (1024) piece
6022  * requires that __exprline always be \0 terminated before calling this
6023  */
__chg_xprline_size(int32 slen)6024 extern void __chg_xprline_size(int32 slen)
6025 {
6026  int32 newlen;
6027 
6028  newlen = slen + ((__exprlinelen < 4*IDLEN) ? __exprlinelen + IDLEN
6029   : __exprlinelen + BIG_ALLOC_SIZE);
6030  __exprline = __my_realloc(__exprline, __exprlinelen, newlen);
6031  __exprlinelen = newlen;
6032 }
6033 
6034 /*
6035  * ROUTINES TO BUILD VPI_ ARGV ARRAY
6036  */
6037 
6038 /*
6039  * convert opthdr from to vpi_ recursive argv
6040  *
6041  * only called once first time needed (vpi argv nil)
6042  * LOOKATME - this always copies and reallocates but maybe not needed
6043  */
__bld_vpi_argv(void)6044 extern void __bld_vpi_argv(void)
6045 {
6046  register int32 lev, i;
6047  register struct optlst_t *olp;
6048  int32 maxlev, argnum, nbytes;
6049  struct optlst_t *bmark_olp;
6050  char **down_argv;
6051 
6052  maxlev = find_deepest_level(__opt_hdr);
6053  /* process bottom up replacing BMARK to EMARK with sub argv ** */
6054  for (lev = maxlev; lev >= 1; lev--)
6055   {
6056    for (olp = __opt_hdr; olp != NULL; olp = olp->optlnxt)
6057     {
6058      if (olp->argv_done) continue;
6059      if (olp->optlev != lev || !olp->is_bmark) continue;
6060 
6061      /* found right level BMARK */
6062      argnum = cnt_beg_to_endmark(olp, olp->optlev);
6063      down_argv = (char **) __my_malloc(argnum*sizeof(char *));
6064      down_argv[0] = __pv_stralloc(__in_fils[olp->optfnam_ind]);
6065      /* starting one after bmark */
6066      bmark_olp = olp;
6067      for (olp = olp->optlnxt, i = 1;; olp = olp->optlnxt)
6068       {
6069        if (olp->argv_done) continue;
6070        if (olp->optlev != lev) __misc_terr(__FILE__, __LINE__);
6071        /* case 1: insert in down argv (first -f) */
6072        if (olp->is_argv)
6073         {
6074          if (!olp->is_bmark) __misc_terr(__FILE__, __LINE__);
6075          down_argv[i++] = __pv_stralloc("-f");
6076          down_argv[i++] = (char *) olp->dargv;
6077          olp->dargv = NULL;
6078          olp->is_argv = FALSE;
6079          olp->argv_done = TRUE;
6080          continue;
6081         }
6082        /* case 2: end mark - add nil terminator and done */
6083        if (olp->is_emark)
6084         {
6085          olp->argv_done = TRUE;
6086          down_argv[i++] = NULL;
6087          break;
6088         }
6089        /* case 3: normal option (must remove -f by itself) */
6090        if (strcmp(olp->opt, "-f") != 0)
6091         {
6092          down_argv[i++] = __pv_stralloc(olp->opt);
6093         }
6094        olp->argv_done = TRUE;
6095       }
6096      bmark_olp->dargv = down_argv;
6097      bmark_olp->is_argv = TRUE;
6098      bmark_olp->optlev--;
6099     }
6100   }
6101  /* top level is special case because of normal OS argc */
6102  /* special count that counts anything - no bmark-emark needed */
6103  argnum = cnt_level0(__opt_hdr);
6104  /* need 0th that is invoking Cver file name */
6105  __vpi_argc = argnum + 1;
6106  nbytes = __vpi_argc*(sizeof(char **));
6107  __vpi_argv = (char **) __my_malloc(nbytes);
6108  /* need to set simulator name from OS argv[0] */
6109  __vpi_argv[0] = __vpi_argv0;
6110  /* notice top uses argc - no ending nil */
6111  for (i = 1, olp = __opt_hdr; olp != NULL; olp = olp->optlnxt)
6112   {
6113    if (olp->argv_done) continue;
6114    /* case 1: down argv - need to add -f */
6115    if (olp->is_argv)
6116     {
6117      if (!olp->is_bmark) __misc_terr(__FILE__, __LINE__);
6118      __vpi_argv[i++] = __pv_stralloc("-f");
6119      __vpi_argv[i++] = (char *) olp->dargv;
6120      continue;
6121     }
6122    /* case 2: normal option (must reomve -f not followed by openable file) */
6123    if (strcmp(olp->opt, "-f") != 0)
6124     {
6125      __vpi_argv[i++] = __pv_stralloc(olp->opt);
6126     }
6127   }
6128  /* DBG remove ---
6129  dump_vpi_argv(__vpi_argc, __vpi_argv);
6130  --- */
6131 }
6132 
6133 /*
6134  * find highest (deepest level) because convert bottom up to PLI **argv tabs
6135  */
find_deepest_level(struct optlst_t * olphd)6136 static int32 find_deepest_level(struct optlst_t *olphd)
6137 {
6138  register struct optlst_t *olp;
6139  int32 level;
6140 
6141  for (level = 0, olp = olphd; olp != NULL; olp = olp->optlnxt)
6142   { if (olp->optlev > level) level = olp->optlev; }
6143  return(level);
6144 }
6145 
6146 /*
6147  * count number of options from begin to end know olp points to beg
6148  * and ignores any argv_done elements
6149  *
6150  * level passed for checking - all counted must be at level lev or internal err
6151  * BMARK counted for file name and EMARK counted for ending NULL
6152  */
cnt_beg_to_endmark(struct optlst_t * olp,int32 lev)6153 static int32 cnt_beg_to_endmark(struct optlst_t *olp, int32 lev)
6154 {
6155  int32 onum;
6156 
6157  if (!olp->is_bmark) __arg_terr(__FILE__, __LINE__);
6158  olp = olp->optlnxt;
6159  for (onum = 1; olp != NULL; olp = olp->optlnxt)
6160   {
6161    if (olp->argv_done) continue;
6162    /* empty file will have count of 0 */
6163    if (olp->is_emark) return(onum + 1);
6164    if (olp->optlev != lev) __arg_terr(__FILE__, __LINE__);
6165 
6166    if (olp->is_argv) onum += 2;
6167    else
6168     {
6169      /* must not count -f not followed by openable file */
6170      if (strcmp(olp->opt, "-f") != 0) onum++;
6171     }
6172   }
6173  /* must always see EMARK */
6174  __arg_terr(__FILE__, __LINE__);
6175  return(-1);
6176 }
6177 
6178 /*
6179  * count top level (0) non argv done olps
6180  */
cnt_level0(struct optlst_t * olp)6181 static int32 cnt_level0(struct optlst_t *olp)
6182 {
6183  int32 onum;
6184 
6185  for (onum = 0; olp != NULL; olp = olp->optlnxt)
6186   {
6187    if (olp->argv_done) continue;
6188    /* only remaining must be level 0 */
6189    if (olp->optlev != 0) __arg_terr(__FILE__, __LINE__);
6190    if (olp->is_argv) onum += 2;
6191    else
6192     {
6193      /* must not count -f not followed by openable file */
6194      if (strcmp(olp->opt, "-f") != 0) onum++;
6195     }
6196   }
6197  return(onum);
6198 }
6199 
6200 /*
6201  * dump a vpi argv/argc d.s.
6202  */
dump_vpi_argv(int32 argc,char ** argv)6203 static void dump_vpi_argv(int32 argc, char **argv)
6204 {
6205  register int32 i;
6206 
6207  __dbg_msg("TOP ARGC: %d\n", argc);
6208  for (i = 0; i < argc; i++)
6209   {
6210    /* know if see -f, will be followed by sub argv */
6211    if (strcmp(argv[i], "-f") == 0)
6212     {
6213      __dbg_msg("LEVEL 0: arg %d: -f\n", i);
6214      __dbg_msg("LEVEL 0: arg %d: NESTED ARGV\n", i + 1);
6215      dump_nest_vpi_argv(1, (char **) argv[i + 1]);
6216      i++;
6217     }
6218    else __dbg_msg("LEVEL 0: arg %d: %s\n", i, argv[i]);
6219   }
6220 }
6221 
6222 /*
6223  * dump a contained nested file
6224  */
dump_nest_vpi_argv(int32 lev,char ** argv)6225 static void dump_nest_vpi_argv(int32 lev, char **argv)
6226 {
6227  register int32 i;
6228 
6229  __dbg_msg("LEVEL %d: arg 0: file %s\n", lev, argv[0]);
6230  for (i = 1;; i++)
6231   {
6232    if (argv[i] == NULL) break;
6233    /* know if see -f, will be followed by sub argv */
6234    if (strcmp(argv[i], "-f") == 0)
6235     {
6236      __dbg_msg("LEVEL %d: arg %d: -f\n", lev, i);
6237      __dbg_msg("LEVEL %d: arg %d: NESTED ARGV\n", lev, i + 1);
6238      dump_nest_vpi_argv(lev + 1, (char **) argv[i + 1]);
6239      i++;
6240     }
6241    else __dbg_msg("LEVEL %d: arg %d: %s\n", lev, i, argv[i]);
6242   }
6243  __dbg_msg("LEVEL %d: **NULL**\n", lev);
6244 }
6245 
6246 /*
6247  * dump one oplst_t record
6248  */
dmp1_optlst(struct optlst_t * olp,char * emsg)6249 static void dmp1_optlst(struct optlst_t *olp, char *emsg)
6250 {
6251  char s1[RECLEN];
6252 
6253  if (olp->is_bmark && olp->is_emark) __misc_terr(__FILE__, __LINE__);
6254  if (olp->is_bmark) strcpy(s1, "BMARK");
6255  else if (olp->is_emark) strcpy(s1, "EMARK");
6256  else strcpy(s1, "NONE");
6257  __dbg_msg("**%s: file %s line %d: mark %s optnum %d optlev %d opt %s\n",
6258   emsg, __in_fils[olp->optfnam_ind], olp->optlin_cnt, s1, olp->optnum,
6259   olp->optlev, olp->opt);
6260 }
6261