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