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  * run time execution routines - assigns, strength and gate evaluation
30  */
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <errno.h>
36 
37 #include <sys/types.h>
38 #include <unistd.h>
39 
40 #ifdef __DBMALLOC__
41 #include "../malloc.h"
42 #endif
43 
44 #include "v.h"
45 #include "cvmacros.h"
46 
47 /* sytem stuff */
48 extern int32 errno;
49 
50 /* local prototypes */
51 static void set_from_mpp_unopts(struct mod_t *, struct mod_pin_t *, int32);
52 static void set_from_hconn_unopts(struct mod_t *, struct inst_t *, int32,
53  struct expr_t *, struct mod_pin_t *, int32);
54 static void dbg_unopt_msg(struct mod_t *, struct mod_pin_t *, int32, char *);
55 static void dbg_unopt2_msg(struct mod_t *, struct inst_t *, int32,
56  struct mod_pin_t *, int32, char *);
57 static void std_downtomdport(register struct expr_t *,
58  register struct expr_t *, struct itree_t *);
59 static void prt_assignedto_val(struct expr_t *, char *);
60 static void multfi_acc_downtomdport( register struct expr_t *,
61  struct expr_t *, struct itree_t *);
62 static void stacc_downtomdport(register struct expr_t *,
63  register struct expr_t *, struct itree_t *);
64 static void stbsel_acc_downtomdport(register struct expr_t *,
65  register struct expr_t *, struct itree_t *);
66 static void acc_downtomdport(register struct expr_t *,
67  register struct expr_t *, struct itree_t *);
68 static void bsel_acc_downtomdport(register struct expr_t *,
69  register struct expr_t *, struct itree_t *);
70 static void std_uptoiconn(register struct expr_t *, register struct expr_t *,
71  struct itree_t *);
72 static void multfi_acc_uptoiconn(register struct expr_t *, struct expr_t *,
73  struct itree_t *);
74 static void stacc_uptoiconn(register struct expr_t *, register struct expr_t *,
75  struct itree_t *);
76 static void stbsel_acc_uptoiconn(register struct expr_t *,
77  register struct expr_t *, struct itree_t *);
78 static void acc_uptoiconn(register struct expr_t *, register struct expr_t *,
79  struct itree_t *);
80 static void bsel_acc_uptoiconn(register struct expr_t *,
81  register struct expr_t *, struct itree_t *);
82 static void ldcomb_driver(struct xstk_t *, struct net_t *,
83  register struct net_pin_t *);
84 static word32 widegate_ld_bit(word32 *, int32, int32);
85 static void ldcomb_stdriver(register byte *, struct net_t *,
86  register struct net_pin_t *);
87 static struct xstk_t *init_stwire_accum(struct net_t *);
88 static struct xstk_t *ld_stgate_driver(struct net_pin_t *);
89 static struct xstk_t *ld_stconta_driver(struct net_pin_t *);
90 static struct xstk_t *ld_stvpiputv_driver(struct net_pin_t *);
91 static struct xstk_t *ld_sticonn_up_driver(register struct net_pin_t *);
92 static struct xstk_t *ld_pb_sticonn_up_driver(register struct net_pin_t *);
93 static struct xstk_t *ld_stmodport_down_driver(register struct net_pin_t *);
94 static struct xstk_t *ld_pb_stmodport_down_driver(
95 register struct net_pin_t *);
96 static struct xstk_t *ld_stpull_driver(struct net_pin_t *);
97 static void ndst_eval2_xpr(register byte *, register struct expr_t *);
98 static void access_stpsel(register byte *, register struct expr_t *);
99 static void rhs_stconcat(register byte *, struct expr_t *);
100 static void eval_stwire(word32, register byte *, int32, int32,
101  register byte *);
102 static void adds_evgate_ins(word32 *, word32 *, int32);
103 static void show2_allvars(struct itree_t *);
104 static void emit1_driver(struct net_t *, struct net_pin_t *, int32);
105 static char *drive_tostr(char *, word32 *, word32 *, struct net_pin_t *,
106  int32, int32);
107 static char *stdrive_tostr(char *, byte *, struct net_pin_t *, int32, int32);
108 static char *bld_wire_telltale(char *, struct net_t *);
109 static void emit1_load(struct net_t *, struct net_pin_t *);
110 static struct mdvmast_t *alloc_mdvmast(void);
111 static void setup_all_dvars(void);
112 static void setup_1argdvars(struct mdvmast_t *);
113 static void setup_1subtree_allvars(struct itree_t *, int32);
114 static void setup_1installvars(struct mod_t *, struct itree_t *);
115 static void turnon_1net_dmpv(struct net_t *, struct itree_t *,
116  struct task_t *, struct mod_t *, int32);
117 static char *to_dvcode(register char *, register int32);
118 static void wr_1argdvhdr(struct mdvmast_t *);
119 static void wr_1subtree_allvars(struct itree_t *, int32);
120 static void wr_1inst_dvhdrs(struct itree_t *);
121 static void wr_tasks_dvhdrs(struct itree_t *, register struct symtab_t *);
122 static char *to_dvtsktyp(char *, word32);
123 static void wr_fromtop_iscopeto(struct itree_t *);
124 static void wr_totop_iscopeback(struct itree_t *);
125 static void wr_tskscopeto(struct symtab_t *);
126 static void wr_tskscopeback(struct symtab_t *);
127 static void wr_1vectored_dvdef(struct net_t *, char *, struct itree_t *);
128 static void dump_allvars_vals(void);
129 static void dmp_insts_ofwire(struct mod_t *, struct net_t *);
130 static void bld1_scal_dvval(struct net_t *, char *, struct itree_t *);
131 static void bld1_vec_dvval(struct net_t *, char *, struct itree_t *);
132 static void bld1_xdvval(register struct net_t *, char *);
133 static void dv_wr(int32);
134 static char *to_dvtimstr(char *, register word64);
135 static void access_stbsel(register byte *, register struct expr_t *);
136 
137 /* extern prototypes (maybe defined in this module) */
138 extern void __set_mpp_assign_routines(void);
139 extern void __set_pb_mpp_assign_routines(void);
140 extern void __set_mpp_aoff_routines(void);
141 extern void __vpi_set_downtomdport_proc(struct mod_pin_t *, struct net_t *);
142 extern void __vpi_set_upiconnport_proc(struct mod_pin_t *);
143 extern void __init_instdownport_contas(struct itree_t *, struct itree_t *);
144 extern void __init_instupport_contas(struct itree_t *);
145 extern void __mdr_assign_or_sched(register struct expr_t *);
146 extern void __assign_1mdrwire(register struct net_t *);
147 extern void __sched_1mdrwire(register struct net_t *);
148 extern struct xstk_t *__load_mdrwire(register struct net_t *);
149 extern int32 __move_to_npprefloc(struct net_pin_t *);
150 extern struct xstk_t *__ld_wire_driver(register struct net_pin_t *);
151 extern struct xstk_t *__ld_tfrwarg_driver(struct net_pin_t *);
152 extern struct xstk_t *__ld_conta_driver(struct net_pin_t *);
153 extern struct xstk_t *__ld_vpiputv_driver(struct net_pin_t *);
154 extern struct xstk_t *__ld_gate_driver(struct net_pin_t *);
155 extern struct xstk_t *__ld_iconn_up_driver(register struct net_pin_t *);
156 extern struct xstk_t *__ld_pb_iconn_up_driver(register struct net_pin_t *);
157 extern struct xstk_t *__ld_modport_down_driver(register struct net_pin_t *);
158 extern struct xstk_t *__ld_pb_modport_down_driver(register struct net_pin_t *);
159 
160 
161 extern word32 __ld_gate_out(register struct gate_t *, int32 *);
162 extern void __eval_wire(word32 *, word32 *, struct net_t *,
163  struct net_pin_t *);
164 extern void __eval_wide_wire(word32 *, word32 *, word32 *, word32 *, int32,
165  word32);
166 extern void __eval_1w_nonstren(register word32 *, register word32 *,
167  register word32, register word32, word32);
168 extern struct xstk_t *__stload_mdrwire(struct net_t *);
169 extern struct xstk_t *__ld_stwire_driver(register struct net_pin_t *);
170 extern struct xstk_t *__ld_sttfrwarg_driver(struct net_pin_t *);
171 extern struct xstk_t *__ndst_eval_xpr(struct expr_t *);
172 extern int32 __get_const_bselndx(register struct expr_t *);
173 extern void __st_standval(register byte *, register struct xstk_t *, byte);
174 extern word32 __comb_1bitsts(word32, register word32, register word32);
175 extern char *__gstate_tostr(char *, struct gate_t *, int32);
176 extern void __show_allvars(void);
177 extern void __emit_1showvar(struct net_t *, struct gref_t *);
178 extern char *__bld_valofsched(char *, struct tev_t *);
179 extern char *__bld_showvars_prefix(char *, struct net_t *, struct gref_t *);
180 extern void __exec_dumpvars(struct expr_t *);
181 extern void __setup_dmpvars(void);
182 extern void __do_dmpvars_baseline(char *);
183 extern void __do_dmpvars_chg(void);
184 extern int32 __cnt_dcelstels(register struct dcevnt_t *);
185 
186 extern char *__to_ptnam(char *, word32);
187 extern char *__to_mpnam(char *, char *);
188 extern char *__bld_lineloc(char *, word32, int32);
189 extern void __strenwiden_sizchg(struct xstk_t *, int32);
190 extern struct xstk_t *__eval2_xpr(register struct expr_t *);
191 extern void __sizchgxs(register struct xstk_t *, int32);
192 extern void __sgn_xtnd_widen(struct xstk_t *, int32);
193 extern void __sizchg_widen(register struct xstk_t *, int32);
194 extern void __narrow_sizchg(register struct xstk_t *, int32);
195 extern void __fix_widened_toxs(register struct xstk_t *, int32);
196 extern void __stren_exec_ca_concat(struct expr_t *, byte *, int32);
197 extern void __exec_conta_assign(struct expr_t *, register word32 *,
198  register word32 *, int32);
199 extern void __exec_ca_concat(struct expr_t *, register word32 *,
200  register word32 *, int32);
201 extern char *__msgexpr_tostr(char *, struct expr_t *);
202 extern char *__to_gassign_str(char *, struct expr_t *);
203 extern void __ld_perinst_val(register word32 *, register word32 *,
204  union pck_u, int32);
205 extern void __grow_xstk(void);
206 extern void __chg_xstk_width(struct xstk_t *, int32);
207 extern void __lhsbsel(register word32 *, register int32, word32);
208 extern void __my_free(char *, int32);
209 extern char *__my_malloc(int32);
210 extern char *__to_vvstnam(char *, word32);
211 extern char *__to_vvnam(char *, word32);
212 extern char *__to_timstr(char *, word64 *);
213 extern int32 __correct_forced_newwireval(struct net_t *, word32 *, word32 *);
214 extern void __chg_st_val(struct net_t *, register word32 *, register word32 *);
215 extern void __ld_wire_val(register word32 *, register word32 *,
216  struct net_t *);
217 extern int32 __comp_ndx(register struct net_t *, register struct expr_t *);
218 extern void __ld_bit(register word32 *, register word32 *,
219  register struct net_t *, int32);
220 extern int32 __forced_inhibit_bitassign(struct net_t *, struct expr_t *,
221  struct expr_t *);
222 extern void __assign_to_bit(struct net_t *, struct expr_t *, struct expr_t *,
223  register word32 *, register word32 *);
224 extern void __xmrpush_refgrp_to_targ(struct gref_t *);
225 extern int32 __has_vpi_driver(struct net_t *np, struct net_pin_t *npp);
226 extern int32 __update_tran_harddrvs(struct net_t *);
227 extern void __eval_tran_bits(register struct net_t *);
228 extern void __ld_addr(word32 **, word32 **, register struct net_t *);
229 extern void __st_val(struct net_t *, register word32 *, register word32 *);
230 extern char *__st_regab_tostr(char *, byte *, int32);
231 extern char *__regab_tostr(char *, word32 *, word32 *, int32, int32, int32);
232 extern void __pth_stren_schd_allofwire(struct net_t *, register byte *, int32);
233 extern void __wdel_stren_schd_allofwire(struct net_t *, register byte *,
234  int32);
235 extern void __pth_schd_allofwire(struct net_t *, register word32 *,
236  register word32 *, int32);
237 extern void __wdel_schd_allofwire(struct net_t *, register word32 *,
238  register word32 *, int32);
239 extern void __rhspsel(register word32 *, register word32 *, register int32,
240  register int32);
241 extern void __lhspsel(register word32 *, register int32, register word32 *,
242  register int32);
243 extern char *__to_wtnam(char *, struct net_t *);
244 extern char *__to_wtnam2(char *, word32);
245 extern void __adds(char *);
246 extern void __chg_xprline_size(int32);
247 extern void __disp_itree_path(register struct itree_t *, struct task_t *);
248 extern void __ld_gate_wide_val(word32 *, word32 *, word32 *, int32);
249 extern void __trunc_cstr(char *, int32, int32);
250 extern char *__msg2_blditree(char *, struct itree_t *);
251 extern int32 __get_arrwide(struct net_t *);
252 extern char *__var_tostr(char *, struct net_t *, int32, int32, int32);
253 extern void __disp_var(struct net_t *, int32, int32, int32, char);
254 extern int32 __unnormalize_ndx(struct net_t *, int32);
255 extern void __get_cor_range(register int32, union intptr_u, register int32 *,
256  register int32 *);
257 extern void __getarr_range(struct net_t *, int32 *, int32 *, int32 *);
258 extern void __getwir_range(struct net_t *, int32 *, int32 *);
259 extern int32 __unmap_ndx(int32, int32, int32);
260 extern char *__schop(char *, char *);
261 extern char *__get_tfcellnam(struct tfrec_t *);
262 extern int32 __vval_isallzs(word32 *, word32 *, int32);
263 extern int32 __st_vval_isallzs(byte *, int32);
264 extern char *__to_wrange(char *, struct net_t *);
265 extern char *__to_arr_range(char *, struct net_t *);
266 extern char *__to1_stren_nam(char *, int32, int32);
267 extern int32 __fr_cap_size(int32);
268 extern void __bld_forcedbits_mask(word32 *, struct net_t *);
269 extern int32 __wide_vval_is0(register word32 *, int32);
270 extern int32 __match_push_targ_to_ref(word32, struct gref_t *);
271 extern char *__to_tcnam(char *, word32);
272 extern int32 __get_eval_word(struct expr_t *, word32 *);
273 extern int32 __ip_indsrch(char *);
274 extern char *__to_timunitnam(char *, word32);
275 extern char *__msg_blditree(char *, struct itree_t *, struct task_t *);
276 extern void __sdispb(register word32 *, register word32 *, int32, int32);
277 extern int32 __trim1_0val(word32 *, int32);
278 extern void __declcnv_tostr(char *, word32 *, int32, int32);
279 extern struct task_t *__getcur_scope_tsk(void);
280 extern void __add_nchglst_el(register struct net_t *);
281 extern void __add_dmpv_chglst_el(struct net_t *);
282 extern void __wakeup_delay_ctrls(register struct net_t *, register int32,
283  register int32);
284 extern char *__to_npptyp(char *, struct net_pin_t *);
285 
286 extern void __cv_msg(char *, ...);
287 extern void __cvsim_msg(char *, ...);
288 extern void __tr_msg(char *, ...);
289 extern void __sgfwarn(int32, char *, ...);
290 extern void __pv_warn(int32, char *, ...);
291 extern void __sgferr(int32, char *, ...);
292 extern void __dbg_msg(char *, ...);
293 extern void __sgfinform(int32, char *, ...);
294 extern void __arg_terr(char *, int32);
295 extern void __case_terr(char *, int32);
296 extern void __misc_terr(char *, int32);
297 
298 extern word32 __masktab[];
299 extern byte __stren_map_tab[];
300 extern word32 __cap_to_stren[];
301 
302 /*
303  * ROUTINES TO SET PORT ASSIGN
304  */
305 
306 /*
307  * set module port assign routines (type of acceleration)
308  */
__set_mpp_assign_routines(void)309 extern void __set_mpp_assign_routines(void)
310 {
311  register int32 pi, ii;
312  register struct mod_pin_t *mpp;
313  int32 pnum;
314  struct mod_t *mdp, *imdp;
315  struct inst_t *ip;
316  struct expr_t *xp;
317 
318  /* step 1: set the - down from iconn to mod port from module ports */
319  for (mdp = __modhdr; mdp != NULL; mdp = mdp->mnxt)
320   {
321    if ((pnum = mdp->mpnum) == 0) continue;
322 
323    /* SJM - PORT REMOVE */
324    /* for top module set assign routine to nil - will force early core dump */
325    /* if error */
326    if (mdp->minstnum == 0)
327     {
328      /* leave port assign routines as nil for top level */
329      for (pi = 0; pi < mdp->mpnum; pi++)
330       { mpp = &(mdp->mpins[pi]); mpp->assgnfunc_set = TRUE; }
331      continue;
332     }
333 
334    for (pi = 0; pi < mdp->mpnum; pi++)
335     {
336      mpp = &(mdp->mpins[pi]);
337 
338      /* never have NP ICONN or NP MDPRT for inout */
339      if (mpp->mptyp == IO_BID) { mpp->assgnfunc_set = TRUE; continue; }
340 
341      /* need iconn lhs info for setting output assign routines */
342      if (mpp->mptyp == IO_OUT) continue;
343 
344 
345      set_from_mpp_unopts(mdp, mpp, -1);
346     }
347   }
348  /* step 2: look at all up instance connections to see if can optimize */
349  /* can only be down after all low conn mod ports processed in step 1 */
350  for (mdp = __modhdr; mdp != NULL; mdp = mdp->mnxt)
351   {
352    /* first process all instances in module */
353    for (ii = 0; ii < mdp->minum; ii++)
354     {
355      ip = &(mdp->minsts[ii]);
356      imdp = ip->imsym->el.emdp;
357      if ((pnum = imdp->mpnum) == 0) continue;
358 
359      for (pi = 0; pi < pnum; pi++)
360       {
361        mpp = &(imdp->mpins[pi]);
362        if (mpp->assgnfunc_set)
363         {
364          /* if assgn func set turned on, must not try to optimize more */
365          continue;
366         }
367 
368        /* port (either in or out) down must be simple ID for any accelerate */
369        if (mpp->mpref->optyp != ID)
370         {
371          if (__debug_flg)
372           dbg_unopt2_msg(imdp, ip, pi, mpp, -1, "port is expression");
373          if (mpp->mptyp == IO_IN)
374           mpp->mpaf.mpp_downassgnfunc = std_downtomdport;
375          else mpp->mpaf.mpp_upassgnfunc = std_uptoiconn;
376          mpp->assgnfunc_set = TRUE;
377          continue;
378         }
379 
380        /* if assign not know, down must be simple wire */
381        xp = ip->ipins[pi];
382 
383        /* set the best possible optimization routine from highconn */
384        set_from_hconn_unopts(imdp, ip, pi, xp, mpp, -1);
385       }
386     }
387   }
388 }
389 
390 /*
391  * set decomposed from hconn concat per bit mod port assign routines
392  * i.e. set type of acceleration for interpreter
393  *
394  * -O does much better job of optimizing these
395  */
__set_pb_mpp_assign_routines(void)396 extern void __set_pb_mpp_assign_routines(void)
397 {
398  register int32 pi, ii, pbi;
399  register struct mod_pin_t *mpp;
400  int32 pnum;
401  struct mod_pin_t *mast_mpp;
402  struct mod_t *mdp, *imdp;
403  struct inst_t *ip;
404  struct expr_t *xp;
405 
406  /* step 1: set the - down from iconn to mod port from module ports */
407  for (mdp = __modhdr; mdp != NULL; mdp = mdp->mnxt)
408   {
409    if ((pnum = mdp->mpnum) == 0) continue;
410 
411    /* no top level ports do not have any highconn - so never decomposed */
412    if (mdp->minstnum == 0) continue;
413 
414    for (pi = 0; pi < mdp->mpnum; pi++)
415     {
416      mast_mpp = &(mdp->mpins[pi]);
417      if (!mast_mpp->has_scalar_mpps) continue;
418 
419      for (pbi = 0; pbi < mast_mpp->mpwide; pbi++)
420       {
421        mpp = &(mast_mpp->pbmpps[pbi]);
422 
423        /* need iconn lhs info for setting output assign routines */
424        if (mpp->mptyp == IO_OUT) continue;
425        set_from_mpp_unopts(mdp, mpp, pbi);
426       }
427     }
428   }
429  /* step 2: look at all up instance connections to see if can optimize */
430  /* can only be down after all low conn mod ports processed in step 1 */
431  for (mdp = __modhdr; mdp != NULL; mdp = mdp->mnxt)
432   {
433    /* first process all instances in module */
434    for (ii = 0; ii < mdp->minum; ii++)
435     {
436      ip = &(mdp->minsts[ii]);
437      imdp = ip->imsym->el.emdp;
438      if ((pnum = imdp->mpnum) == 0) continue;
439 
440      for (pi = 0; pi < pnum; pi++)
441       {
442        mast_mpp = &(imdp->mpins[pi]);
443        /* if low conn of this high conn not dcomposed into per bit, done */
444        if (!mast_mpp->has_scalar_mpps) continue;
445 
446        /* if this one's up iconn not separable - ignore for setting accel */
447        if (ip->pb_ipins_tab == NULL || ip->pb_ipins_tab[pi] == NULL)
448         continue;
449 
450        for (pbi = 0; pbi < mast_mpp->mpwide; pbi++)
451         {
452          mpp = &(mast_mpp->pbmpps[pbi]);
453          if (mpp->assgnfunc_set) continue;
454 
455          /* LOOKATME ??? - down will almost always be bsel for these */
456          /* port (in or out) down must be simple ID for any accelerate */
457          if (mpp->mpref->optyp != ID)
458           {
459            if (__debug_flg)
460             dbg_unopt2_msg(imdp, ip, pi, mpp, pbi,
461              "per bit port is expression");
462 
463            if (mpp->mptyp == IO_IN)
464             mpp->mpaf.mpp_downassgnfunc = std_downtomdport;
465            else mpp->mpaf.mpp_upassgnfunc = std_uptoiconn;
466            mpp->assgnfunc_set = TRUE;
467 
468            continue;
469           }
470 
471          /* if assign not know, down must be simple wire */
472          xp = ip->pb_ipins_tab[pi][pbi];
473          /* set the best possible optimization routine from highconn */
474          set_from_hconn_unopts(imdp, ip, pi, xp, mpp, pbi);
475         }
476       }
477     }
478   }
479 }
480 
481 /*
482  * set ports that can't be optimized determinable only from down mpp
483  * also sets input port fi>1 down assign since independent of iconn
484  *
485  * if pbi not -1 then this is bit of per bit decomposed input port
486  */
set_from_mpp_unopts(struct mod_t * mdp,struct mod_pin_t * mpp,int32 pbi)487 static void set_from_mpp_unopts(struct mod_t *mdp, struct mod_pin_t *mpp,
488  int32 pbi)
489 {
490  struct net_t *down_np;
491 
492  if (mpp->mpref->optyp != ID)
493   {
494    if (__debug_flg) dbg_unopt_msg(mdp, mpp, pbi, "port is expression");
495    mpp->mpaf.mpp_downassgnfunc = std_downtomdport;
496    mpp->assgnfunc_set = TRUE;
497    return;
498   }
499  down_np = mpp->mpref->lu.sy->el.enp;
500  /* path destinations are stored as delay wires */
501  if (down_np->ntraux != NULL || down_np->nrngrep == NX_DWIR)
502   {
503    if (__debug_flg)
504     dbg_unopt_msg(mdp, mpp, pbi, "port in tran chan., delay or path dest.");
505    mpp->mpaf.mpp_downassgnfunc = std_downtomdport;
506    mpp->assgnfunc_set = TRUE;
507    return;
508   }
509  /* if port wire multfi - all will be so now know fits fi>1 acc case */
510  if (down_np->n_multfi)
511   {
512    if (__debug_flg) dbg_unopt_msg(mdp, mpp, pbi,
513     "port fi>1 - optimized some");
514    mpp->mpaf.mpp_downassgnfunc = multfi_acc_downtomdport;
515    mpp->assgnfunc_set = TRUE;
516   }
517 }
518 
519 /*
520  * set optimized routines from high conn iconn info
521  *
522  * uses up iconn expr info and optimize info set in step 1 mpp processing
523  * know down is simple ID or not called
524  *
525  * works for both normal ports and per bit decomposed input ports
526  * from concat high conns where pbi is bit, and xp/mpp are per bit decomposed
527  */
set_from_hconn_unopts(struct mod_t * imdp,struct inst_t * ip,int32 pi,struct expr_t * xp,struct mod_pin_t * mpp,int32 pbi)528 static void set_from_hconn_unopts(struct mod_t *imdp, struct inst_t *ip,
529  int32 pi, struct expr_t *xp, struct mod_pin_t *mpp, int32 pbi)
530 {
531  struct net_t *up_np, *down_np;
532 
533  down_np = mpp->mpref->lu.sy->el.enp;
534  /* always non acc if not same width */
535  if (mpp->mpref->szu.xclen != xp->szu.xclen)
536   {
537    if (__debug_flg) dbg_unopt2_msg(imdp, ip, pi, mpp, pbi, "widths differ");
538 set_unoptim:
539    if (mpp->mptyp == IO_IN) mpp->mpaf.mpp_downassgnfunc = std_downtomdport;
540    else mpp->mpaf.mpp_upassgnfunc = std_uptoiconn;
541    mpp->assgnfunc_set = TRUE;
542    return;
543   }
544  if (mpp->mptyp == IO_IN)
545   {
546    /* down input port assign, know port lhs is optimizable */
547    /* make sure rhs up iconn optimizable */
548    if (xp->optyp == ID)
549     {
550      up_np = xp->lu.sy->el.enp;
551      /* both up and down must be have or not have stren */
552      if ((up_np->n_stren && !down_np->n_stren)
553       || (!up_np->n_stren && down_np->n_stren))
554       {
555        if (__debug_flg) dbg_unopt2_msg(imdp, ip, pi, mpp, pbi,
556         "strength needed differs");
557        goto set_unoptim;
558       }
559      if (down_np->n_stren)
560       {
561        if (xp->szu.xclen == 1)
562         mpp->mpaf.mpp_downassgnfunc = stbsel_acc_downtomdport;
563        else mpp->mpaf.mpp_downassgnfunc = stacc_downtomdport;
564        return;
565       }
566      /* non strength ID case */
567      if (xp->szu.xclen == 1)
568       mpp->mpaf.mpp_downassgnfunc = bsel_acc_downtomdport;
569      else mpp->mpaf.mpp_downassgnfunc = acc_downtomdport;
570      return;
571     }
572    /* bit select for this up iconn case */
573    /* SJM 07/24/03 - bit select from XMR high conn must not be optimized */
574    if (xp->optyp != LSB || xp->lu.x->optyp != ID
575     || mpp->mpref->szu.xclen != 1)
576     {
577      if (__debug_flg)
578       dbg_unopt2_msg(imdp, ip, pi, mpp, pbi,
579        "vector port but not bit select from ID highconn");
580      goto set_unoptim;
581     }
582    /* maybe up bit select or scalar - must be constant index */
583    if (xp->ru.x->optyp != NUMBER)
584     {
585      if (__debug_flg)
586       dbg_unopt2_msg(imdp, ip, pi, mpp, pbi, "bit select highconn expr.");
587      goto set_unoptim;
588     }
589    up_np = xp->lu.x->lu.sy->el.enp;
590    /* both must be same strength */
591    if ((up_np->n_stren && !down_np->n_stren)
592     || (!up_np->n_stren && down_np->n_stren))
593     {
594      if (__debug_flg)
595       dbg_unopt2_msg(imdp, ip, pi, mpp, pbi, "bsel strength needed differs");
596      goto set_unoptim;
597     }
598    /* may reduce optimlzation level to bsel form */
599    if (down_np->n_stren)
600     mpp->mpaf.mpp_downassgnfunc = stbsel_acc_downtomdport;
601    else mpp->mpaf.mpp_downassgnfunc = bsel_acc_downtomdport;
602    return;
603   }
604 
605  /* hard output port case - assign to varying up iconns */
606  /* know mod port is ID and widths same or will not get here */
607  if (xp->optyp == ID) up_np = xp->lu.sy->el.enp;
608  else if (xp->optyp == LSB) up_np = xp->lu.x->lu.sy->el.enp;
609  /* no debug message needed here because assign never happens */
610  else if (xp->optyp == OPEMPTY) goto set_unoptim;
611  else
612   {
613    if (__debug_flg)
614     dbg_unopt2_msg(imdp, ip, pi, mpp, pbi, "iconn not bsel or wire");
615    goto set_unoptim;
616   }
617 
618  /* cannot have delay (also path dest.) or be in tran channel */
619  if (up_np->nrngrep == NX_DWIR || up_np->ntraux != NULL)
620   {
621    if (__debug_flg)
622     dbg_unopt2_msg(imdp, ip, pi, mpp, pbi,
623     "iconn in tran chan or delay/path dest.");
624    goto set_unoptim;
625   }
626  if (up_np->n_multfi)
627   {
628    if (mpp->mpaf.mpp_upassgnfunc == NULL)
629     { mpp->mpaf.mpp_upassgnfunc = multfi_acc_uptoiconn; return; }
630    /* if some instance connections, fi>1 and other not, not acc */
631    if (mpp->mpaf.mpp_upassgnfunc != multfi_acc_uptoiconn)
632     goto mixed_multfi;
633    return;
634   }
635  if (mpp->mpaf.mpp_upassgnfunc == multfi_acc_uptoiconn)
636   {
637 mixed_multfi:
638    if (__debug_flg)
639     dbg_unopt2_msg(imdp, ip, pi, mpp, pbi,
640      "mixed fi>1 and non fi>1 highconns");
641    goto set_unoptim;
642   }
643 
644  /* both strengths must be same */
645  if ((up_np->n_stren && !down_np->n_stren)
646   || (!up_np->n_stren && down_np->n_stren)) goto set_unoptim;
647  if (xp->optyp == ID)
648   {
649    if (up_np->n_stren)
650     {
651      /* must be acc. bsel */
652      if (xp->szu.xclen == 1) mpp->mpaf.mpp_upassgnfunc = stbsel_acc_uptoiconn;
653      else mpp->mpaf.mpp_upassgnfunc = stacc_uptoiconn;
654      return;
655     }
656    if (xp->szu.xclen == 1) mpp->mpaf.mpp_upassgnfunc = bsel_acc_uptoiconn;
657    else mpp->mpaf.mpp_upassgnfunc = acc_uptoiconn;
658    return;
659   }
660  /* bit select case */
661  if (down_np->n_stren) mpp->mpaf.mpp_upassgnfunc = stbsel_acc_uptoiconn;
662  else mpp->mpaf.mpp_upassgnfunc = bsel_acc_uptoiconn;
663 }
664 
665 /*
666  * assign std port assign routines if accelerate (port assign optimize off)
667  */
__set_mpp_aoff_routines(void)668 extern void __set_mpp_aoff_routines(void)
669 {
670  register int32 pi, pbi;
671  register struct mod_t *mdp;
672  register struct mod_pin_t *mpp, *mpp2;
673 
674  for (mdp = __modhdr; mdp != NULL; mdp = mdp->mnxt)
675   {
676    if (mdp->minstnum == 0)
677     {
678      for (pi = 0; pi < mdp->mpnum; pi++)
679       {
680        mpp = &(mdp->mpins[pi]);
681        mpp->assgnfunc_set = TRUE;
682       }
683      continue;
684     }
685 
686    for (pi = 0; pi < mdp->mpnum; pi++)
687     {
688      mpp = &(mdp->mpins[pi]);
689      mpp->assgnfunc_set = TRUE;
690 
691      /* lhs destination from port type determines routine */
692      if (mpp->mptyp == IO_OUT) mpp->mpaf.mpp_upassgnfunc = std_uptoiconn;
693      else if (mpp->mptyp == IO_IN)
694       mpp->mpaf.mpp_downassgnfunc = std_downtomdport;
695      else continue;
696 
697      /* SJM 09/18/06 - if not simulated as decomposed bits, avoid this code */
698      if (!mpp->has_scalar_mpps) continue;
699 
700      for (pbi = 0; pbi < mpp->mpwide; pbi++)
701       {
702        mpp2 = &(mpp->pbmpps[pbi]);
703        /* only per bit for input ports */
704        mpp2->mpaf.mpp_downassgnfunc = std_downtomdport;
705        mpp2->assgnfunc_set = TRUE;
706       }
707     }
708   }
709 }
710 
711 /*
712  * set new routine when mod port wire has added vpi put value driver added
713  *
714  * SJM 09/20/02 - this may be separated per bit mod port
715  */
__vpi_set_downtomdport_proc(struct mod_pin_t * mpp,struct net_t * np)716 extern void __vpi_set_downtomdport_proc(struct mod_pin_t *mpp,
717  struct net_t *np)
718 {
719  /* if not accelerated when fi==1, then cannot be when fi>1 */
720  if (mpp->mpaf.mpp_downassgnfunc == std_downtomdport) return;
721 
722  /* driver of wire np in module is module port from up inst. */
723  if (mpp->mpref->optyp == ID && np->ntraux == NULL && np->nrngrep != NX_DWIR)
724    mpp->mpaf.mpp_downassgnfunc = multfi_acc_downtomdport;
725  else mpp->mpaf.mpp_downassgnfunc = std_downtomdport;
726 }
727 
728 /*
729  * for up to iconn that is now multfi, cannot optimize
730  * because do not know other instances
731  */
__vpi_set_upiconnport_proc(struct mod_pin_t * mpp)732 extern void __vpi_set_upiconnport_proc(struct mod_pin_t *mpp)
733 {
734  mpp->mpaf.mpp_upassgnfunc = std_uptoiconn;
735 }
736 
737 /*
738  * write a debug reason message for why port not optimized
739  * this is port side message for input ports
740  */
dbg_unopt_msg(struct mod_t * mdp,struct mod_pin_t * mpp,int32 pbi,char * reason)741 static void dbg_unopt_msg(struct mod_t *mdp, struct mod_pin_t *mpp, int32 pbi,
742  char *reason)
743 {
744  char s1[RECLEN], s2[RECLEN], s3[RECLEN];
745 
746  if (pbi == -1) __to_mpnam(s2, mpp->mpsnam);
747  else sprintf(s2, "%s bit %d", __to_mpnam(s3, mpp->mpsnam), pbi);
748  __dbg_msg("module %s %s port %s unoptimized: %s\n", mdp->msym->synam,
749   __to_ptnam(s1, mpp->mptyp), s2, reason);
750 }
751 
752 /*
753  * write a debug reason message for why port not optimized
754  * this is inst conn. side message for output ports
755  */
dbg_unopt2_msg(struct mod_t * mdp,struct inst_t * ip,int32 pi,struct mod_pin_t * mpp,int32 pbi,char * reason)756 static void dbg_unopt2_msg(struct mod_t *mdp, struct inst_t *ip, int32 pi,
757  struct mod_pin_t *mpp, int32 pbi, char *reason)
758 {
759  char s1[RECLEN], s2[RECLEN], s3[RECLEN], s4[RECLEN];
760 
761  if (pbi == -1) __to_mpnam(s3, mpp->mpsnam);
762  else sprintf(s3, "%s bit %d", __to_mpnam(s4, mpp->mpsnam), pbi);
763 
764  __dbg_msg("inst. %s(%s) at %s %s port %s (pos. %d) unoptimized: %s\n",
765   ip->isym->synam, mdp->msym->synam, __bld_lineloc(s1, ip->isym->syfnam_ind,
766   ip->isym->sylin_cnt), __to_ptnam(s2, mpp->mptyp), s3, pi, reason);
767 }
768 
769 /*
770  * PORT UP AND DOWN ASSIGN ROUTINES
771  */
772 
773 /*
774  * assign all input ports downward into lower itree instance
775  * called from up_itp where itp (down) is under itree place
776  *
777  * assumes called with nothing pushed on itree stack
778  * never called for inout in tran channel - initialized elsewhere
779  */
__init_instdownport_contas(struct itree_t * up_itp,struct itree_t * down_itp)780 extern void __init_instdownport_contas(struct itree_t *up_itp,
781  struct itree_t *down_itp)
782 {
783  register int32 pi;
784  register struct mod_pin_t *mpp;
785  struct expr_t *xp;
786  struct inst_t *ip;
787  struct mod_t *down_mdp;
788  int32 pnum;
789 
790  ip = down_itp->itip;
791  down_mdp = ip->imsym->el.emdp;
792  if ((pnum = down_mdp->mpnum) == 0) return;
793 
794  /* this must work from up itree loc */
795  __push_itstk(up_itp);
796  for (pi = 0; pi < pnum; pi++)
797   {
798    xp = ip->ipins[pi];
799    mpp = &(down_mdp->mpins[pi]);
800    if (mpp->mptyp != IO_IN) continue;
801 
802    __immed_assigns++;
803    /* must be call with current itree location up (rhs) but passed down */
804    /* exec inst. input expr. downward to port changed assign */
805    /* notice down always take only 4 args, down do not have first mpp */
806    (*mpp->mpaf.mpp_downassgnfunc)(mpp->mpref, xp, down_itp);
807   }
808  __pop_itstk();
809 }
810 
811 /*
812  * initialize cross module out instance ports continuous assigns
813  *
814  * can get to up itree loc. but following up ptr
815  * never called for inout in tran channel - initialized elsewhere
816  */
__init_instupport_contas(struct itree_t * down_itp)817 extern void __init_instupport_contas(struct itree_t *down_itp)
818 {
819  register int32 pi;
820  register struct mod_pin_t *mpp;
821  struct expr_t *xp;
822  struct inst_t *ip;
823  struct mod_t *down_mdp;
824  struct itree_t *up_itp;
825  int32 pnum;
826 
827  ip = down_itp->itip;
828  down_mdp = ip->imsym->el.emdp;
829  if ((pnum = down_mdp->mpnum) == 0) return;
830 
831  /* cannot assume current itree location - need down starting */
832  __push_itstk(down_itp);
833  for (pi = 0; pi < pnum; pi++)
834   {
835    xp = ip->ipins[pi];
836    mpp = &(down_mdp->mpins[pi]);
837 
838    if (mpp->mptyp != IO_OUT) continue;
839 
840    __immed_assigns++;
841    /* called from down module itree location */
842    /* SJM - PORT REMOVE - no assign if top level module - ports remain */
843    if ((up_itp = __inst_ptr->up_it) == NULL) continue;
844 
845    /* assign from rhs down mpp ref. to up lhs iconn */
846    /* notice up always take only 3 args, down have extra 1st arg mpp */
847    (*mpp->mpaf.mpp_upassgnfunc)(xp, mpp->mpref, up_itp);
848   }
849  __pop_itstk();
850 }
851 
852 /*
853  * ROUTINES FOR VARIOUS CASES OF DOWN INPUT PORT FROM ICONN TO MDPRT ASSIGN
854  */
855 
856 /*
857  * down from iconn to port assign - for all non special cases
858  *
859  * called from up iconn rhs itree loc.
860  * this is standard (general) function that must handle all cases
861  *
862  * if any inst. size change, in tran channel, lhs has delay, some but not
863  * all fi>1, any iconn is xmr, any iconn is concat, down port is expr.,
864  * up is not wire or reg expr, this routine used - must be some more reasons?
865  * called from up rhs iconn itree loc.
866  */
std_downtomdport(register struct expr_t * lhsx,register struct expr_t * rhsx,struct itree_t * down_itp)867 static void std_downtomdport(register struct expr_t *lhsx,
868  register struct expr_t *rhsx, struct itree_t *down_itp)
869 {
870  register struct xstk_t *xsp;
871  int32 schd_wire, orhslen;
872 
873  if (lhsx->x_multfi)
874   {
875    /* always must evaluate drivers with itstk of lhs (i.e. down) */
876    __push_itstk(down_itp);
877    /* all lhs expr. containging tran chan wire mult fi and handled here */
878    __mdr_assign_or_sched(lhsx);
879 
880    /* assigned to down (destination) wire loads of this new assigned to */
881    /* wire will be added to net chg list */
882    /* DBG remove ---
883    if (__debug_flg && __ev_tracing)
884     prt_assignedto_val(lhsx, "fi>1 down port assign");
885    --- */
886    __pop_itstk();
887    return;
888   }
889 
890  /* if inst. input expr. is empty, nothing to do */
891  if (rhsx->optyp == OPEMPTY) return;
892  if (lhsx->x_stren)
893   {
894    /* handle lhs stren assign - pass strength through */
895    /* other side always marked strength and if rhs reg, will add in strong */
896    xsp = __ndst_eval_xpr(rhsx);
897    /* widen to lhs width with z's - if too narrow, high part just unused */
898    /* SJM 05/10/04 - no sign extension because widening to z'x */
899    /* AIV 03/15/07 - strength for xsp->xslen was wrong for same reaston */
900    /* as one fixed on 11/21/06 */
901    /* SJM 11/21/06 - for stren's xsp is 4 times width for byte per bit */
902    /* problem is xslen for stren is not the expr bit width */
903    if (rhsx->szu.xclen < lhsx->szu.xclen)
904     __strenwiden_sizchg(xsp, lhsx->szu.xclen);
905   }
906  else
907   {
908    xsp = __eval_xpr(rhsx);
909    if (lhsx->szu.xclen != xsp->xslen)
910     {
911      orhslen = xsp->xslen;
912 
913      /* SJM 09/29/03 - change to handle sign extension and separate types */
914      if (xsp->xslen > lhsx->szu.xclen)
915       __narrow_sizchg(xsp, lhsx->szu.xclen);
916      else if (xsp->xslen < lhsx->szu.xclen)
917       {
918        if (rhsx->has_sign) __sgn_xtnd_widen(xsp, lhsx->szu.xclen);
919        else __sizchg_widen(xsp, lhsx->szu.xclen);
920       }
921 
922      /* widened, set bits higher than orhslen to z */
923      /* LOOKATME - only strength continuous assignments widen to z */
924      /* all others widen to 0 */
925      /* ??? if (orhslen < xsp->xslen) __fix_widened_tozs(xsp, orhslen); */
926      /* SJM 05/10/04 - widening to x's eliminates need for sign difference */
927      if (__wire_init) __fix_widened_toxs(xsp, orhslen);
928     }
929   }
930  /* eval. in up itree side but assign on to lhs in down */
931  __push_itstk(down_itp);
932  if (lhsx->lhsx_ndel && !__wire_init) schd_wire = TRUE;
933  else schd_wire = FALSE;
934  if (lhsx->x_stren)
935   {
936    /* port conta just assigns strengths */
937    if (lhsx->optyp == LCB)
938     __stren_exec_ca_concat(lhsx, (byte *) xsp->ap, schd_wire);
939    else __exec_conta_assign(lhsx, xsp->ap, xsp->bp, schd_wire);
940   }
941  else
942   {
943    if (lhsx->optyp == LCB)
944     __exec_ca_concat(lhsx, xsp->ap, xsp->bp, schd_wire);
945    else __exec_conta_assign(lhsx, xsp->ap, xsp->bp, schd_wire);
946   }
947  __pop_xstk();
948  /* DBG remove --
949  if (__debug_flg && __ev_tracing)
950   prt_assignedto_val(lhsx, "port down assign");
951  --- */
952  /* notice cannot pop until here since lhs is down */
953  __pop_itstk();
954 }
955 
956 /*
957  * print value of assign to output wire
958  * only called when debug flag and some kind of tracing on
959  */
prt_assignedto_val(struct expr_t * xp,char * nppnam)960 static void prt_assignedto_val(struct expr_t *xp, char *nppnam)
961 {
962  char s1[RECLEN], s2[RECLEN];
963 
964  if (xp->x_stren) strcpy(s2, "strength "); else strcpy(s2, "");
965  __tr_msg("== %s lvalue %swire %s set or scheduled to %s\n", nppnam, s2,
966   __msgexpr_tostr(__xs, xp), __to_gassign_str(s1, xp));
967 }
968 
969 /*
970  * mulfi lhs upward instance port assign from down module port assign
971  * for output port
972  *
973  * only for down port multi-fi wire (could handle selects but rare)
974  * since port expressions rare
975  * since down lhs is module port all will be same
976  * if port expr. or inout in tran channel, cannot use this routine
977  * can be either strength or non strength
978  * called from up rhs iconn itree location
979  */
multfi_acc_downtomdport(register struct expr_t * lhsx,struct expr_t * rhsx,struct itree_t * down_itp)980 static void multfi_acc_downtomdport(register struct expr_t *lhsx,
981  struct expr_t *rhsx, struct itree_t *down_itp)
982 {
983  /* for mdport fi>1, eval all drivers */
984  /* must evaluate drivers with itstk of lhs (i.e. down here) */
985  __push_itstk(down_itp);
986  __assign_1mdrwire(lhsx->lu.sy->el.enp);
987  /* DBG remove ---
988  if (__debug_flg && __ev_tracing)
989   prt_assignedto_val(lhsx, "fi>1 down port assign");
990  --- */
991  __pop_itstk();
992 }
993 
994 /*
995  * stren both wire/reg up iconn down to mod port assign special case routine
996  * only called if all instances both same width IDs
997  * never for scalar - use bit select version for that
998  *
999  * called from up rhs iconn itree location
1000  */
stacc_downtomdport(register struct expr_t * lhsx,register struct expr_t * rhsx,struct itree_t * down_itp)1001 static void stacc_downtomdport(register struct expr_t *lhsx,
1002  register struct expr_t *rhsx, struct itree_t *down_itp)
1003 {
1004  byte *bp, *sbp;
1005  struct net_t *lhsnp;
1006  struct xstk_t *xsp;
1007 
1008  push_xstk_(xsp, 4*rhsx->szu.xclen);
1009  sbp = (byte *) xsp->ap;
1010  get_stwire_addr_(bp, rhsx->lu.sy->el.enp);
1011  memcpy(sbp, bp, rhsx->szu.xclen);
1012 
1013  /* assign in down */
1014  __push_itstk(down_itp);
1015  lhsnp = lhsx->lu.sy->el.enp;
1016  /* this adds the changed wire to nchglst if needed */
1017  /* return F if all of wire forced, nothing to do */
1018  if (lhsnp->frc_assgn_allocated)
1019   {
1020    if (!__correct_forced_newwireval(lhsnp, (word32 *) sbp, (word32 *) NULL))
1021     { __pop_itstk(); __pop_xstk(); return; }
1022   }
1023  __chg_st_val(lhsnp, (word32 *) sbp, (word32 *) NULL);
1024  __pop_xstk();
1025  /* DBG remove ---
1026  if (__debug_flg && __ev_tracing)
1027   prt_assignedto_val(lhsx, "strength mod. port down assign");
1028  --- */
1029  __pop_itstk();
1030 }
1031 
1032 /*
1033  * stren both wire/reg up iconn down to mod port assign special case routine
1034  * this is also called for all scalars on up inst.
1035  *
1036  * only called if all instances both scalar IDs or up bsel and down
1037  * and nothing special such as delay wire
1038  * only strength scalars handled here
1039  */
stbsel_acc_downtomdport(register struct expr_t * lhsx,register struct expr_t * rhsx,struct itree_t * down_itp)1040 static void stbsel_acc_downtomdport(register struct expr_t *lhsx,
1041  register struct expr_t *rhsx, struct itree_t *down_itp)
1042 {
1043  struct net_t *lhsnp;
1044  byte sb2, *bp, *sbp;
1045 
1046  /* eval rhs up iconn in current itree up loc. */
1047  if (rhsx->optyp == LSB) access_stbsel(&sb2, rhsx);
1048  else { get_stwire_addr_(bp, rhsx->lu.sy->el.enp); sb2 = bp[0]; }
1049 
1050  /* assign in down */
1051  __push_itstk(down_itp);
1052  lhsnp = lhsx->lu.sy->el.enp;
1053  /* this is needed so for endian differences - cast of ptr does nothing */
1054  sbp = &sb2;
1055  /* this adds the changed wire to nchglst if needed */
1056  /* return F if all of wire forced, nothing to do */
1057  if (lhsnp->frc_assgn_allocated)
1058   {
1059    if (!__correct_forced_newwireval(lhsnp, (word32 *) sbp, (word32 *) NULL))
1060     { __pop_itstk(); return; }
1061   }
1062  __chg_st_val(lhsnp, (word32 *) sbp, (word32 *) NULL);
1063  /* DBG remove ---
1064  if (__debug_flg && __ev_tracing)
1065   prt_assignedto_val(lhsx, "strength scalar mod. port assign");
1066  --- */
1067  __pop_itstk();
1068 }
1069 
1070 /*
1071  * non stren both wire upward to instance port assign special case routine
1072  * only called if all instances both same width IDs
1073  * acc bsel routine called for scalars
1074  */
acc_downtomdport(register struct expr_t * lhsx,register struct expr_t * rhsx,struct itree_t * down_itp)1075 static void acc_downtomdport(register struct expr_t *lhsx,
1076  register struct expr_t *rhsx, struct itree_t *down_itp)
1077 {
1078  register struct xstk_t *xsp;
1079  struct net_t *lhsnp;
1080 
1081  /* up rhs always wire/reg or not fast routine */
1082  /* eval rhs up iconn in current itree up loc. */
1083  push_xstk_(xsp, rhsx->szu.xclen);
1084  __ld_wire_val(xsp->ap, xsp->bp, rhsx->lu.sy->el.enp);
1085 
1086  /* assign in down */
1087  __push_itstk(down_itp);
1088  lhsnp = lhsx->lu.sy->el.enp;
1089  /* this adds the changed wire to nchglst if needed */
1090  /* return F if all of wire forced, nothing to do */
1091  if (lhsnp->frc_assgn_allocated)
1092   {
1093    if (!__correct_forced_newwireval(lhsnp, xsp->ap, xsp->bp))
1094     { __pop_itstk(); __pop_xstk(); return; }
1095   }
1096  __chg_st_val(lhsnp, xsp->ap, xsp->bp);
1097  __pop_xstk();
1098  /* DBG remove ---
1099  if (__debug_flg && __ev_tracing)
1100   prt_assignedto_val(lhsx, "mod. port assign");
1101  --- */
1102  __pop_itstk();
1103 }
1104 
1105 /*
1106  * up wire bsel to instance port scalar assign special case routine
1107  *
1108  * only called if up rhs is scalar or bit select and down port
1109  * is scalar wire - all insts must also be simple and not in tran channel
1110  * this is only for scalars and at least one bsel
1111  */
bsel_acc_downtomdport(register struct expr_t * lhsx,register struct expr_t * rhsx,struct itree_t * down_itp)1112 static void bsel_acc_downtomdport(register struct expr_t *lhsx,
1113  register struct expr_t *rhsx, struct itree_t *down_itp)
1114 {
1115  int32 biti;
1116  word32 av, bv;
1117  struct net_t *lhsnp, *rhsnp;
1118 
1119  /* down rhs always wire/reg or not accelerated routine */
1120  if (rhsx->optyp == LSB)
1121   {
1122    rhsnp = rhsx->lu.x->lu.sy->el.enp;
1123    /* know biti never -1 since only fixed non -1 for this routine */
1124    biti = __comp_ndx(rhsnp, rhsx->ru.x);
1125    __ld_bit(&av, &bv, rhsnp, biti);
1126   }
1127  else __ld_wire_val(&av, &bv, rhsx->lu.sy->el.enp);
1128 
1129  /* assign in down - never an expr. */
1130  __push_itstk(down_itp);
1131  lhsnp = lhsx->lu.sy->el.enp;
1132  /* this adds the changed wire to nchglst if needed */
1133  /* return F if all of wire forced, nothing to do */
1134  if (lhsnp->frc_assgn_allocated)
1135   {
1136    if (!__correct_forced_newwireval(lhsnp, &av, &bv))
1137     { __pop_itstk(); return; }
1138   }
1139  __chg_st_val(lhsnp, &av, &bv);
1140  /* DBG remove ---
1141  if (__debug_flg && __ev_tracing)
1142   prt_assignedto_val(lhsx, "mod. port scalar assign");
1143  --- */
1144  __pop_itstk();
1145 }
1146 
1147 /*
1148  * ROUTINES FOR THE VARIOUS CASES OF FROM DOWN MDPRT TO UP ICONN ASSIGN
1149  */
1150 
1151 /*
1152  * upward to instance port assign - for all non special cases
1153  * this is standard (general) function that must handle all cases
1154  *
1155  * if any inst. size change, in tran channel, lhs has delay, some but not
1156  * all fi>1, any iconn is xmr, any iconn is concat, down port is expr.,
1157  * up is not wire or reg expr, this routine used - must be some more reasons?
1158  */
std_uptoiconn(register struct expr_t * lhsx,register struct expr_t * rhsx,struct itree_t * up_itp)1159 static void std_uptoiconn(register struct expr_t *lhsx,
1160  register struct expr_t *rhsx, struct itree_t *up_itp)
1161 {
1162  register struct xstk_t *xsp;
1163  int32 schd_wire, orhslen;
1164 
1165  /* if destination driven by module output is empty, nothing to do */
1166  if (lhsx->optyp == OPEMPTY) return;
1167 
1168  /* for iconn part of fi>1, eval all drivers code */
1169  if (lhsx->x_multfi)
1170   {
1171    /* always must evaluate drivers with itstk of lhs (i.e. up here) */
1172    __push_itstk(up_itp);
1173    __mdr_assign_or_sched(lhsx);
1174 
1175    /* DBG remove ---
1176    if (__debug_flg && __ev_tracing)
1177     prt_assignedto_val(lhsx, "fi>1 upto highconn assign");
1178    --- */
1179    __pop_itstk();
1180    return;
1181   }
1182  /* load rhs according to lhs expr. type and make size equal to lhs */
1183  /* if port has no connections - LOOKATME maybe illegal, nothing to do */
1184  if (rhsx->optyp == OPEMPTY) return;
1185 
1186  /* eval rhs on current itree down loc. */
1187  if (lhsx->x_stren)
1188   {
1189    /* handle lhs stren assign - pass strength through */
1190    /* if reg, will add strong strength */
1191    xsp = __ndst_eval_xpr(rhsx);
1192    /* widen to lhs width with z's - if too narrow, high part just unused */
1193    /* SJM 05/10/04 - no sign extension because widening to z'x */
1194    /* SJM 11/21/06 - for stren's xsp is 4 times width for byte per bit */
1195    /* problem is xslen for stren is not the expr bit width */
1196    if (rhsx->szu.xclen < lhsx->szu.xclen)
1197     __strenwiden_sizchg(xsp, lhsx->szu.xclen);
1198   }
1199  else
1200   {
1201    xsp = __eval_xpr(rhsx);
1202    if (lhsx->szu.xclen != xsp->xslen)
1203     {
1204      orhslen = xsp->xslen;
1205 
1206      /* SJM 09/29/03 - change to handle sign extension and separate types */
1207      if (xsp->xslen > lhsx->szu.xclen)
1208       __narrow_sizchg(xsp, lhsx->szu.xclen);
1209      else if (xsp->xslen < lhsx->szu.xclen)
1210       {
1211        if (rhsx->has_sign) __sgn_xtnd_widen(xsp, lhsx->szu.xclen);
1212        else __sizchg_widen(xsp, lhsx->szu.xclen);
1213       }
1214 
1215      /* widened, set bits higher than orhslen to z */
1216      /* LOOKATME - only strength continuous assignments widen to z */
1217      /* all others widen to 0 except x during initialization */
1218      /* ??? if (orhslen < xsp->xslen) __fix_widened_tozs(xsp, orhslen); */
1219      /* SJM 05/10/04 - widening to x's eliminates need for sign difference */
1220      if (__wire_init) __fix_widened_toxs(xsp, orhslen);
1221     }
1222   }
1223  /* but assign on lhs up iconn itree location */
1224  __push_itstk(up_itp);
1225  if (lhsx->lhsx_ndel && !__wire_init) schd_wire = TRUE;
1226  else schd_wire = FALSE;
1227  /* notice here is lhs is gref, assign handles finding right itree loc. */
1228  if (lhsx->x_stren)
1229   {
1230    /* port conta just assigns strengths */
1231    if (lhsx->optyp == LCB)
1232     __stren_exec_ca_concat(lhsx, (byte *) xsp->ap, schd_wire);
1233    else __exec_conta_assign(lhsx, xsp->ap, xsp->bp, schd_wire);
1234   }
1235  else
1236   {
1237    if (lhsx->optyp == LCB)
1238     __exec_ca_concat(lhsx, xsp->ap, xsp->bp, schd_wire);
1239    else __exec_conta_assign(lhsx, xsp->ap, xsp->bp, schd_wire);
1240   }
1241  __pop_xstk();
1242  /* DBG remove ---
1243  if (__debug_flg && __ev_tracing)
1244   prt_assignedto_val(lhsx, "inst. conn. up assign");
1245  --- */
1246  __pop_itstk();
1247 }
1248 
1249 /*
1250  * mulfi lhs upward instance port assign from down module port assign
1251  *
1252  * only for down wire and up any multi-fi non concat simple and non tran
1253  * if one multfi and any other not, std all cases routine must be used
1254  * can be either strength or non strength
1255  */
multfi_acc_uptoiconn(register struct expr_t * lhsx,struct expr_t * rhsx,struct itree_t * up_itp)1256 static void multfi_acc_uptoiconn(register struct expr_t *lhsx,
1257  struct expr_t *rhsx, struct itree_t *up_itp)
1258 {
1259  /* for iconn part of fi>1, eval all drivers code */
1260  /* must evaluate drivers with itstk of lhs (i.e. up here) */
1261  __push_itstk(up_itp);
1262  if (lhsx->optyp == ID) __assign_1mdrwire(lhsx->lu.sy->el.enp);
1263  else __assign_1mdrwire(lhsx->lu.x->lu.sy->el.enp);
1264  /* DBG remove ---
1265  if (__debug_flg && __ev_tracing)
1266   prt_assignedto_val(lhsx, "fi>1 up to highconn assign");
1267  --- */
1268  __pop_itstk();
1269 }
1270 
1271 /*
1272  * stren both wire upward to instance port assign special case routine
1273  * only called if all instances both same width IDs
1274  */
stacc_uptoiconn(register struct expr_t * lhsx,register struct expr_t * rhsx,struct itree_t * up_itp)1275 static void stacc_uptoiconn(register struct expr_t *lhsx,
1276  register struct expr_t *rhsx, struct itree_t *up_itp)
1277 {
1278  byte *bp, *sbp;
1279  struct net_t *lhsnp;
1280  struct xstk_t *xsp;
1281 
1282  /* eval rhs mod port in current itree down loc. */
1283  /* for accelerated know down port rhs is not an expression */
1284  push_xstk_(xsp, 4*rhsx->szu.xclen);
1285  sbp = (byte *) xsp->ap;
1286  get_stwire_addr_(bp, rhsx->lu.sy->el.enp);
1287  memcpy(sbp, bp, rhsx->szu.xclen);
1288 
1289  /* assign in up */
1290  __push_itstk(up_itp);
1291  lhsnp = lhsx->lu.sy->el.enp;
1292  /* this adds the changed wire to nchglst if needed */
1293  /* return F if all of wire forced, nothing to do */
1294  if (lhsnp->frc_assgn_allocated)
1295   {
1296    if (!__correct_forced_newwireval(lhsnp, (word32 *) sbp, (word32 *) NULL))
1297     { __pop_itstk(); __pop_xstk(); return; }
1298   }
1299  __chg_st_val(lhsnp, (word32 *) sbp, (word32 *) NULL);
1300  __pop_xstk();
1301  /* DBG remove ---
1302  if (__debug_flg && __ev_tracing)
1303   prt_assignedto_val(lhsx, "strength inst. conn. up assign");
1304  --- */
1305  __pop_itstk();
1306 }
1307 
1308 /*
1309  * stren up wire bsel to instance port scalar assign special case routine
1310  *
1311  * only called if up lhs is strength bit select or scalar and down
1312  * is scalar wire, all insts must also be simple and not in tran channel
1313  */
stbsel_acc_uptoiconn(register struct expr_t * lhsx,register struct expr_t * rhsx,struct itree_t * up_itp)1314 static void stbsel_acc_uptoiconn(register struct expr_t *lhsx,
1315  register struct expr_t *rhsx, struct itree_t *up_itp)
1316 {
1317  byte *bp, sb2, *sbp;
1318  struct net_t *lhsnp;
1319  struct expr_t *idndp, *ndx1;
1320 
1321  /* eval rhs mod port in current itree down loc. */
1322  /* for accelerated know down port rhs is not an expression */
1323  get_stwire_addr_(bp, rhsx->lu.sy->el.enp);
1324  sb2 = bp[0];
1325  sbp = &sb2;
1326 
1327  __push_itstk(up_itp);
1328  /* here can be either stren scalar or bit select */
1329  if (lhsx->optyp == ID)
1330   {
1331    lhsnp = lhsx->lu.sy->el.enp;
1332    if (lhsnp->frc_assgn_allocated)
1333     {
1334      if (!__correct_forced_newwireval(lhsnp, (word32 *) sbp, (word32 *) NULL))
1335       { __pop_itstk(); return; }
1336     }
1337    __chg_st_val(lhsnp, (word32 *) sbp, (word32 *) NULL);
1338   }
1339  else
1340   {
1341    idndp = lhsx->lu.x;
1342    ndx1 = lhsx->ru.x;
1343    lhsnp = idndp->lu.sy->el.enp;
1344    /* the 1 bit is forced nothing to do else normal assign */
1345    if (lhsnp->frc_assgn_allocated
1346     && __forced_inhibit_bitassign(lhsnp, idndp, ndx1))
1347     { __pop_itstk(); return; }
1348    __assign_to_bit(lhsnp, idndp, ndx1, (word32 *) sbp, (word32 *) NULL);
1349   }
1350  /* DBG remove --
1351  if (__debug_flg && __ev_tracing)
1352   prt_assignedto_val(lhsx, "strength scalar inst. conn. up assign");
1353  --- */
1354  __pop_itstk();
1355 }
1356 
1357 /*
1358  * non stren both wire upward to instance port assign special case routine
1359  * only called if all instances both same width IDs
1360  */
acc_uptoiconn(register struct expr_t * lhsx,register struct expr_t * rhsx,struct itree_t * up_itp)1361 static void acc_uptoiconn(register struct expr_t *lhsx,
1362  register struct expr_t *rhsx, struct itree_t *up_itp)
1363 {
1364  register struct xstk_t *xsp;
1365  struct net_t *lhsnp;
1366 
1367  /* down rhs always wire/reg or not accerated routine */
1368  push_xstk_(xsp, rhsx->szu.xclen);
1369  __ld_wire_val(xsp->ap, xsp->bp, rhsx->lu.sy->el.enp);
1370 
1371  /* assign in up */
1372  __push_itstk(up_itp);
1373  lhsnp = lhsx->lu.sy->el.enp;
1374  /* this adds the changed wire to nchglst if needed */
1375  /* return F if all of wire forced, nothing to do */
1376  if (lhsnp->frc_assgn_allocated)
1377   {
1378    if (!__correct_forced_newwireval(lhsnp, xsp->ap, xsp->bp))
1379     { __pop_itstk(); __pop_xstk(); return; }
1380   }
1381  __chg_st_val(lhsnp, xsp->ap, xsp->bp);
1382  __pop_xstk();
1383  /* DBG remove ---
1384  if (__debug_flg && __ev_tracing)
1385   prt_assignedto_val(lhsx, "inst. conn. up assign");
1386  --- */
1387  __pop_itstk();
1388 }
1389 
1390 /*
1391  * up wire bsel to instance port scalar assign special case routine
1392  *
1393  * only called if up lhs is strength bit select and down is scalar wire
1394  * all insts must also be simple and not in tran channel
1395  */
bsel_acc_uptoiconn(register struct expr_t * lhsx,register struct expr_t * rhsx,struct itree_t * up_itp)1396 static void bsel_acc_uptoiconn(register struct expr_t *lhsx,
1397  register struct expr_t *rhsx, struct itree_t *up_itp)
1398 {
1399  word32 av, bv;
1400  struct net_t *lhsnp;
1401  struct expr_t *idndp, *ndx1;
1402 
1403  /* down rhs always wire/reg or not accerated routine */
1404  __ld_wire_val(&av, &bv, rhsx->lu.sy->el.enp);
1405 
1406  /* assign in up */
1407  __push_itstk(up_itp);
1408  /* here can be either stren scalar or bit select */
1409  if (lhsx->optyp == ID)
1410   {
1411    lhsnp = lhsx->lu.sy->el.enp;
1412    if (lhsnp->frc_assgn_allocated)
1413     {
1414      if (!__correct_forced_newwireval(lhsnp, &av, &bv))
1415       { __pop_itstk(); return; }
1416     }
1417    __chg_st_val(lhsnp, &av, &bv);
1418   }
1419  else if (lhsx->optyp == LSB)
1420   {
1421    idndp = lhsx->lu.x;
1422    ndx1 = lhsx->ru.x;
1423    lhsnp = idndp->lu.sy->el.enp;
1424    /* the 1 bit is forced nothing to do else normal assign */
1425    if (lhsnp->frc_assgn_allocated
1426     && __forced_inhibit_bitassign(lhsnp, idndp, ndx1))
1427     { __pop_itstk(); return; }
1428    __assign_to_bit(lhsnp, idndp, ndx1, &av, &bv);
1429   }
1430  /* DBG remove (also above bsel if) -- */
1431  else __case_terr(__FILE__, __LINE__);
1432  /* --- */
1433 
1434  /* DBG remove ---
1435  if (__debug_flg && __ev_tracing)
1436   prt_assignedto_val(lhsx, "strength scalar inst. conn. up assign");
1437  --- */
1438  __pop_itstk();
1439 }
1440 
1441 /*
1442  * MULTI FAN IN NON STRENGTH WIRE ASSIGN ROUTINES
1443  * ASSIGN BY EVALUATING ALL DRIVERS
1444  */
1445 
1446 /*
1447  * continuous assign for multi-fi and stren (even if fi=1) wires
1448  * conta, mod and inst. ports
1449  *
1450  * this is called from itree loc. of lhsx, each driver eval may need
1451  * to move to driving itree loc. load driver routine handles moving
1452  *
1453  * notice even if only a few bits are changed - must reevaluate all bits
1454  * idea is that strengths are almost always scalars and multi-fi
1455  */
__mdr_assign_or_sched(register struct expr_t * lhsx)1456 extern void __mdr_assign_or_sched(register struct expr_t *lhsx)
1457 {
1458  register struct net_t *np;
1459  int32 nd_itpop;
1460  struct expr_t *idndp, *catndp;
1461  struct gref_t *grp;
1462 
1463  nd_itpop = FALSE;
1464  switch ((byte) lhsx->optyp) {
1465   case GLBREF:
1466    idndp = lhsx;
1467 mdr_glb:
1468    grp = idndp->ru.grp;
1469    /* move from xmr ref. itree location to wire definition location */
1470    __xmrpush_refgrp_to_targ(grp);
1471    nd_itpop = TRUE;
1472    goto mdr_id;
1473   case ID:
1474    idndp = lhsx;
1475 mdr_id:
1476    np = idndp->lu.sy->el.enp;
1477    /* handle fi>1 eval and store of bits not in any tran channel */
1478    if (np->ntraux != NULL)
1479     {
1480      /* if hard drivers of np do not change, channel cannot change */
1481      /* SJM 12/18/00 - for tran/tranif switch channels may just add to list */
1482      if (__update_tran_harddrvs(np))
1483       {
1484        /* can't eval (relax) tran channels until all hard drivers known */
1485        /* so first relax can be done */
1486        __eval_tran_bits(np);
1487       }
1488      break;
1489     }
1490    if (np->nrngrep == NX_DWIR) __sched_1mdrwire(np);
1491    else __assign_1mdrwire(np);
1492    break;
1493   case LSB:
1494   case PARTSEL:
1495    idndp = lhsx->lu.x;
1496    if (idndp->optyp == GLBREF) goto mdr_glb; else goto mdr_id;
1497   case LCB:
1498    /* must treat all wires in lhs multi-fan-in concat as special */
1499    /* this means every lhs element needs re-eval of rhs */
1500    for (catndp = lhsx->ru.x; catndp != NULL; catndp = catndp->ru.x)
1501     __mdr_assign_or_sched(catndp->lu.x);
1502    break;
1503   default: __case_terr(__FILE__, __LINE__);
1504  }
1505  if (nd_itpop) __pop_itstk();
1506 }
1507 
1508 /*
1509  * assign to one entire wire with multiple fan-in
1510  *
1511  * it can have strength (or not) but delayed wire handled elsewhere
1512  * cannot be either inout iconn or inout port wire
1513  * called in lhs itree loc. of np (wire definition)
1514  */
__assign_1mdrwire(register struct net_t * np)1515 extern void __assign_1mdrwire(register struct net_t *np)
1516 {
1517  register struct xstk_t *xsp;
1518  register byte *sbp;
1519  int32 sbi;
1520  byte *abp;
1521  word32 *app, *bpp;
1522 
1523  /* separate routines for rare multi-fi wires with delay */
1524  /* here since schedule lhs changed always off */
1525  sbp = NULL;
1526  /* first most common strength case since know muliple drive */
1527  if (np->n_stren)
1528   {
1529    /* get new value of wire from combination of all drivers */
1530    xsp = __stload_mdrwire(np);
1531    sbp = (byte *) xsp->ap;
1532 
1533    /* notice any force overrides even tri reg */
1534    if (np->frc_assgn_allocated
1535     && !__correct_forced_newwireval(np, xsp->ap, xsp->bp))
1536     { __pop_xstk(); return; }
1537    /* short circuit chg store into strength wire */
1538    get_stwire_addr_(abp, np);
1539 
1540    /* no delay form trireg wire, correct for same value cap. strength */
1541    if (np->ntyp == N_TRIREG)
1542     {
1543      for (sbi = 0; sbi < np->nwid; sbi++)
1544       {
1545        if (sbp[sbi] == ST_HIZ)
1546         sbp[sbi] = (byte) ((abp[sbi] & 3) | __cap_to_stren[np->n_capsiz]);
1547       }
1548     }
1549    if (memcmp(abp, sbp, np->nwid) != 0)
1550     {
1551      memcpy(abp, sbp, np->nwid);
1552      __lhs_changed = TRUE;
1553     }
1554   }
1555  else
1556   {
1557    /* multiple driver non strength no delay case */
1558    /* xsp is new wire value */
1559    /* load address and store value use current (np lhs) itree place */
1560    xsp = __load_mdrwire(np);
1561 
1562    if (np->frc_assgn_allocated
1563     && !__correct_forced_newwireval(np, xsp->ap, xsp->bp))
1564     { __pop_xstk(); return; }
1565 
1566    /* notice this address because of packing cannot be stored into */
1567    __ld_addr(&app, &bpp, np);
1568    if (np->nwid <= WBITS)
1569     { if (app[0] == xsp->ap[0] && bpp[0] == xsp->bp[0]) goto done; }
1570    else
1571     {
1572      if (cmp_vval_(app, xsp->ap, np->nwid) == 0
1573       && cmp_vval_(bpp, xsp->bp, np->nwid) == 0) goto done;
1574     }
1575    __st_val(np, xsp->ap, xsp->bp);
1576    __lhs_changed = TRUE;
1577   }
1578 
1579 done:
1580  if (__ev_tracing)
1581   {
1582    char s1[RECLEN];
1583 
1584    if (np->n_stren) strcpy(s1, " strength"); else strcpy(s1, "");
1585    __tr_msg(" drivers of%s wire %s combined", s1, np->nsym->synam);
1586    if (__lhs_changed)
1587     {
1588      if (np->n_stren) __st_regab_tostr(__xs, sbp, np->nwid);
1589      else __regab_tostr(__xs, xsp->ap, xsp->bp, xsp->xslen, BHEX, FALSE);
1590      __tr_msg(" and assigned value %s\n", __xs);
1591     }
1592    else __tr_msg(" value unchanged\n");
1593   }
1594  if (__lhs_changed) record_nchg_(np);
1595  __pop_xstk();
1596 }
1597 
1598 /*
1599  * sched assign for one entire wire with multiple fan-in
1600  * that has delay and be strength (or not)
1601  * but cannot be either inout iconn or inout port wire
1602  *
1603  * if forced, still must schedule because by assign force may be off later
1604  */
__sched_1mdrwire(register struct net_t * np)1605 extern void __sched_1mdrwire(register struct net_t *np)
1606 {
1607  register struct xstk_t *xsp;
1608  register byte *sbp;
1609 
1610  /* separate routines for rare multi-fi wires with delay */
1611  /* here since schedule lhs changed always off */
1612  sbp = NULL;
1613  if (np->n_stren)
1614   {
1615    /* this must run in location of ref. not dest. target */
1616    xsp = __stload_mdrwire(np);
1617    sbp = (byte *) xsp->ap;
1618    /* but rest for xmr must store into dest. target */
1619    /* if np is trireg this will handle (decays known from sbp z's) */
1620    if (np->nu.rngdwir->n_delrep == DT_PTHDST)
1621     __pth_stren_schd_allofwire(np, sbp, np->nwid);
1622    else __wdel_stren_schd_allofwire(np, sbp, np->nwid);
1623   }
1624  else
1625   {
1626    xsp = __load_mdrwire(np);
1627    if (np->nu.rngdwir->n_delrep == DT_PTHDST)
1628     __pth_schd_allofwire(np, xsp->ap, xsp->bp, np->nwid);
1629    else __wdel_schd_allofwire(np, xsp->ap, xsp->bp, np->nwid);
1630   }
1631  if (__ev_tracing)
1632   {
1633    char s1[RECLEN];
1634 
1635    if (np->n_stren) strcpy(s1, " strength"); else strcpy(s1, "");
1636    __tr_msg(" drivers of%s wire %s combined", s1,
1637     np->nsym->synam);
1638    if (np->n_stren) __st_regab_tostr(__xs, sbp, np->nwid);
1639    else __regab_tostr(__xs, xsp->ap, xsp->bp, xsp->xslen, BHEX, FALSE);
1640    __tr_msg(" and scheduled to value %s\n", __xs);
1641   }
1642  __pop_xstk();
1643 }
1644 
1645 /*
1646  * ROUTINES TO LOAD AND COMBINE NON STRENGTH MULTI DRIVER WIRE
1647  */
1648 
1649 /*
1650  * load entire wire with at least some bits of multiple fan-in
1651  * onto stack - leaves value on top of stack that caller must pop
1652  *
1653  * this is for non strength case
1654  * for xmr the drivers are drivers for wire target wire
1655  * loads only hard drivers - tran channel code handles tran components
1656  */
__load_mdrwire(register struct net_t * np)1657 extern struct xstk_t *__load_mdrwire(register struct net_t *np)
1658 {
1659  register struct net_pin_t *npp;
1660  register struct xstk_t *xsp;
1661 
1662  /* allocate accumulator with undriven bits set to z */
1663  push_xstk_(xsp, np->nwid);
1664  /* initialize to high z - only possibility in non strength case */
1665  zero_allbits_(xsp->ap, np->nwid);
1666  one_allbits_(xsp->bp, np->nwid);
1667 
1668  /* must reevaluate every driver since no algorithm for undoing */
1669  /* 1 driver to add new one even if could store old value somewhere */
1670  for (npp = np->ndrvs; npp != NULL; npp = npp->npnxt)
1671   {
1672    /* filter new rooted and up. rel col. forms */
1673    if (npp->npproctyp == NP_PROC_FILT
1674     && npp->npaux->npu.filtitp != __inst_ptr) continue;
1675    ldcomb_driver(xsp, np, npp);
1676   }
1677  return(xsp);
1678 }
1679 
1680 /*
1681  * load and combine in to passed z initial acumulator one npp driver
1682  *
1683  * filters for downward relative xmrs if npp does not match this inst.
1684  * know definition itree loc on itstk
1685  */
ldcomb_driver(struct xstk_t * acc_xsp,struct net_t * np,register struct net_pin_t * npp)1686 static void ldcomb_driver(struct xstk_t *acc_xsp, struct net_t *np,
1687  register struct net_pin_t *npp)
1688 {
1689  register struct xstk_t *xsp, *tmpxsp;
1690  int32 lhswid, nd_itpop;
1691  struct npaux_t *npauxp;
1692 
1693  /* --- DBG remove
1694  if (__debug_flg && __ev_tracing)
1695   {
1696    __tr_msg("## loading %s driver of wire %s\n",
1697     __to_npptyp(__xs, npp), np->nsym->synam);
1698   }
1699  --- */
1700  if (npp->npproctyp != NP_PROC_INMOD)
1701   {
1702    /* SJM 04/17/03 - if XMR does not match - do not combine in */
1703    if (!__move_to_npprefloc(npp)) return;
1704    nd_itpop = TRUE;
1705   }
1706  else nd_itpop = FALSE;
1707 
1708  /* this puts the driving value (normal rhs with rhs width) on stack */
1709  /* notice tran strength only so error if appears here */
1710  switch ((byte) npp->npntyp) {
1711   case NP_CONTA: xsp = __ld_conta_driver(npp); break;
1712   case NP_TFRWARG: xsp = __ld_tfrwarg_driver(npp); break;
1713   case NP_VPIPUTV: xsp = __ld_vpiputv_driver(npp); break;
1714   case NP_GATE: xsp = __ld_gate_driver(npp); break;
1715   /* these are up to highconn output port drivers */
1716   case NP_ICONN: xsp = __ld_iconn_up_driver(npp); break;
1717   case NP_PB_ICONN: xsp = __ld_pb_iconn_up_driver(npp); break;
1718   /* these are down to lowconn input port drivers */
1719   case NP_MDPRT: xsp = __ld_modport_down_driver(npp); break;
1720   case NP_PB_MDPRT: xsp = __ld_pb_modport_down_driver(npp); break;
1721   default: __case_terr(__FILE__, __LINE__); xsp = NULL;
1722  }
1723  if (nd_itpop) __pop_itstk();
1724 
1725  /* if lhs of concatenate, must select section out of rhs value */
1726  if ((npauxp = npp->npaux) != NULL && npauxp->lcbi1 != -1)
1727   {
1728    /* loaded value always matches lhs width exactly with z extension */
1729    /* if too wide just will not rhs psel from section */
1730    lhswid = npauxp->lcbi1 - npauxp->lcbi2 + 1;
1731    push_xstk_(tmpxsp, lhswid);
1732    __rhspsel(tmpxsp->ap, xsp->ap, npauxp->lcbi2, lhswid);
1733    __rhspsel(tmpxsp->bp, xsp->bp, npauxp->lcbi2, lhswid);
1734 
1735    __eval_wire(acc_xsp->ap, tmpxsp->ap, np, npp);
1736    __pop_xstk();
1737   }
1738  else __eval_wire(acc_xsp->ap, xsp->ap, np, npp);
1739  __pop_xstk();
1740 }
1741 
1742 /*
1743  * routine to move from xmr definition location of wire npp driver
1744  * or load net on back to reference location so can get gate/conta
1745  * driving or conducting value
1746  *
1747  * push onto itstk and leave on
1748  */
__move_to_npprefloc(struct net_pin_t * npp)1749 extern int32 __move_to_npprefloc(struct net_pin_t *npp)
1750 {
1751  if (npp->npproctyp == NP_PROC_GREF)
1752   {
1753    if (!__match_push_targ_to_ref(npp->np_xmrtyp, npp->npaux->npu.npgrp))
1754     return(FALSE);
1755   }
1756  /* all rooted xmrs here */
1757  else __push_itstk(npp->npaux->npdownitp);
1758  return(TRUE);
1759 }
1760 
1761 /*
1762  * load a wire driver for use by count drivers
1763  * puts the driving value (normal rhs with rhs width) on stack
1764  *
1765  * this is not normal routine - for case where just need one with fi>1 comb.
1766  * must set returned NULL to all z's
1767  */
__ld_wire_driver(register struct net_pin_t * npp)1768 extern struct xstk_t *__ld_wire_driver(register struct net_pin_t *npp)
1769 {
1770  register struct xstk_t *xsp;
1771  int32 nd_itpop;
1772 
1773  /* for new col or xmr npp forms that need to match inst */
1774  /* instance filter already done */
1775  if (npp->npproctyp != NP_PROC_INMOD)
1776   {
1777    /* SJM 04/17/03 - if XMR does not match - do not combine in */
1778    if (!__move_to_npprefloc(npp)) return(NULL);
1779    nd_itpop = TRUE;
1780   }
1781  else nd_itpop = FALSE;
1782 
1783  /* iconn and mod port may return xsp of nil - caller does not pop */
1784  switch ((byte) npp->npntyp) {
1785   case NP_CONTA: xsp = __ld_conta_driver(npp); break;
1786   case NP_TFRWARG: xsp = __ld_tfrwarg_driver(npp); break;
1787   case NP_VPIPUTV: xsp = __ld_vpiputv_driver(npp); break;
1788   case NP_GATE: xsp = __ld_gate_driver(npp); break;
1789   /* these are up to highconn output port drivers */
1790   case NP_ICONN: xsp = __ld_iconn_up_driver(npp); break;
1791   case NP_PB_ICONN: xsp = __ld_pb_modport_down_driver(npp); break;
1792   /* these are down to lowconn input port drivers */
1793   case NP_MDPRT: xsp = __ld_modport_down_driver(npp); break;
1794   case NP_PB_MDPRT: xsp = __ld_pb_modport_down_driver(npp); break;
1795   /* tran strength only */
1796   default: __case_terr(__FILE__, __LINE__); return(NULL);
1797  }
1798  if (nd_itpop) __pop_itstk();
1799  return(xsp);
1800 }
1801 
1802 /*
1803  * load a continuous assignment driver npp
1804  * caller must have moved to right itree loc. for xmr form
1805  *
1806  * if rhs conta concat causes sep into bits, this is PB conta
1807  */
__ld_conta_driver(struct net_pin_t * npp)1808 extern struct xstk_t *__ld_conta_driver(struct net_pin_t *npp)
1809 {
1810  register struct xstk_t *xsp;
1811  register int32 blen;
1812  register struct conta_t *cap;
1813  int32 orhslen;
1814 
1815  /* SJM 09/18/02 - no separate per bit NP type, check for pb sim on */
1816  cap = npp->elnpp.ecap;
1817  if (cap->ca_pb_sim)
1818   {
1819    cap = &(cap->pbcau.pbcaps[npp->pbi]);
1820   }
1821 
1822  blen = cap->lhsx->szu.xclen;
1823  /* case 1: fi=1 - for showvars driver is wire section [nbi1:nbi2] itself */
1824  /* for fi == 1 and no delay need this for wire display */
1825  /* will never get here normally since just assign */
1826  /* accessing rhs for consistency check but lhs should always be same */
1827  if (cap->ca_drv_wp.wp == NULL)
1828   {
1829    xsp = __eval2_xpr(cap->rhsx);
1830    if (blen != xsp->xslen)
1831     {
1832      orhslen = xsp->xslen;
1833 
1834      /* SJM 09/29/03 - change to handle sign extension and separate types */
1835      if (xsp->xslen > blen) __narrow_sizchg(xsp, blen);
1836      else if (xsp->xslen < blen)
1837       {
1838        if (cap->rhsx->has_sign) __sgn_xtnd_widen(xsp, blen);
1839        else __sizchg_widen(xsp, blen);
1840       }
1841 
1842      /* LOOKATME - only strength continuous assignments widen to z */
1843      /* all others widen to 0 unless during initialization when x */
1844      /* ??? if (orhslen < xsp->xslen) __fix_widened_tozs(xsp, orhslen); */
1845      /* SJM 05/10/04 - widening to x's eliminates need for sign difference */
1846      if (__wire_init) __fix_widened_toxs(xsp, orhslen);
1847     }
1848    return(xsp);
1849   }
1850  /* case 2: multi-fi or delay - know driver rhs exists */
1851  /* but if delay 0 no scheduled (since same) */
1852  push_xstk_(xsp, blen);
1853  /* know this is exactly lhs width */
1854  __ld_perinst_val(xsp->ap, xsp->bp, cap->ca_drv_wp, blen);
1855  return(xsp);
1856 }
1857 
1858 /*
1859  * load a tf_ task/func argument rw parameter driver
1860  *
1861  * caller must have moved to right itree loc. for xmr form
1862  * never strength
1863  */
__ld_tfrwarg_driver(struct net_pin_t * npp)1864 extern struct xstk_t *__ld_tfrwarg_driver(struct net_pin_t *npp)
1865 {
1866  register struct xstk_t *xsp;
1867  register int32 blen;
1868  register struct tfrec_t *tfrp;
1869  struct tfarg_t *tfap;
1870  struct expr_t *xp;
1871 
1872  tfrp = npp->elnpp.etfrp;
1873  tfap = &(tfrp->tfargs[npp->obnum]);
1874  xp = tfap->arg.axp;
1875  blen = xp->szu.xclen;
1876  if (tfap->tfdrv_wp.wp == NULL)
1877   {
1878    xsp = __eval2_xpr(xp);
1879    /* here because lhs is width self determing should never differ */
1880    /* DBG remove */
1881    if (blen != xsp->xslen) __misc_terr(__FILE__, __LINE__);
1882    /* -- */
1883    return(xsp);
1884   }
1885  /* case 2: multi-fi */
1886  push_xstk_(xsp, blen);
1887  /* know this is exactly lhs r/w arg width */
1888  __ld_perinst_val(xsp->ap, xsp->bp, tfap->tfdrv_wp, blen);
1889  return(xsp);
1890 }
1891 
1892 /*
1893  * load a vpi put value wire driver (non strength case)
1894  *
1895  * always entire wire stored (bits with no drivers will be z)
1896  * obnum is index into possibly multiple drivers
1897  *
1898  * for the net bit case must load entire (allowing sharing of driver storage
1899  * for per bit) then select out the needed bit which is later combined in
1900  *
1901  * if any bits unused z's will never be seen
1902  */
__ld_vpiputv_driver(struct net_pin_t * npp)1903 extern struct xstk_t *__ld_vpiputv_driver(struct net_pin_t *npp)
1904 {
1905  register struct net_t *np;
1906  register struct xstk_t *xsp;
1907  register struct vpi_drv_t *drvp;
1908  int32 bi;
1909 
1910  np = npp->elnpp.enp;
1911  drvp = np->vpi_ndrvs[npp->obnum];
1912  push_xstk_(xsp, np->nwid);
1913  __ld_perinst_val(xsp->ap, xsp->bp, drvp->vpi_drvwp, np->nwid);
1914  if (npp->npaux != NULL && (bi = npp->npaux->nbi1) != -1)
1915   {
1916    word32 av, bv;
1917 
1918    av = rhsbsel_(xsp->ap, bi);
1919    bv = rhsbsel_(xsp->bp, bi);
1920    __pop_xstk();
1921    push_xstk_(xsp, 1);
1922    xsp->ap[0] = av;
1923    xsp->bp[0] = bv;
1924   }
1925  return(xsp);
1926 }
1927 
1928 /*
1929  * load a gate driver npp - also for strength case
1930  * caller must have moved to right itree loc. for xmr form
1931  */
__ld_gate_driver(struct net_pin_t * npp)1932 extern struct xstk_t *__ld_gate_driver(struct net_pin_t *npp)
1933 {
1934  register struct xstk_t *xsp;
1935  register word32 uwrd;
1936  int32 has_stren;
1937 
1938  /* load output port - must remove strengths since wire is non strength */
1939  push_xstk_(xsp, 1);
1940  uwrd = __ld_gate_out(npp->elnpp.egp, &has_stren);
1941  /* this must load value and remove strength since drives constant */
1942  /* notice this is non stren case - stren passing gates not proc. here */
1943  xsp->ap[0] = uwrd & 1L;
1944  xsp->bp[0] = (uwrd >> 1) & 1L;
1945  return(xsp);
1946 }
1947 
1948 /*
1949  * load a gate or udp output - value determined from gate type
1950  * and set has_stren and return stren byte value if gate drives st.
1951  * some gates always drive varying stren or some have constant non
1952  * (st0,st1) strength
1953  *
1954  * this is passed net pin since need pin number for trans
1955  */
__ld_gate_out(register struct gate_t * gp,int32 * has_stren)1956 extern word32 __ld_gate_out(register struct gate_t *gp, int32 *has_stren)
1957 {
1958  register word32 wrd, uwrd;
1959  register int32 nins;
1960  struct udp_t *udpp;
1961 
1962  /* here just using a part of stack */
1963  *has_stren = FALSE;
1964  nins = gp->gpnum - 1;
1965  switch ((byte) gp->g_class) {
1966   case GC_UDP:
1967    udpp = gp->gmsym->el.eudpp;
1968    if (!udpp->u_wide)
1969     wrd = (((word32) (gp->gstate.hwp[__inum])) >> (2*nins)) & 3L;
1970    else wrd = (gp->gstate.wp[2*__inum] >> (2*nins)) & 3L;
1971    /* must or in driving strength - if (st0,st1) already removed */
1972    /* key here is that know wire driven is n_stren */
1973    /* state here does not have strength */
1974 adjust_stren:
1975    if (gp->g_hasst)
1976     {
1977      /* z value does not have strength */
1978      if (wrd != 2) wrd |= (gp->g_stval << 2L);
1979      wrd = (word32) __stren_map_tab[wrd];
1980      *has_stren = TRUE;
1981     }
1982    break;
1983   case GC_LOGIC:
1984    if (nins > 15) wrd = widegate_ld_bit(gp->gstate.wp, nins + 1, nins);
1985    else
1986     {
1987      wrd = get_packintowrd_(gp->gstate, __inum, nins + 1);
1988      wrd = ((wrd >> nins) & 1L) | (((wrd >> (2*nins + 1)) & 1L) << 1);
1989     }
1990    if (gp->g_hasst) goto adjust_stren;
1991    break;
1992   case GC_BUFIF:
1993    uwrd = (word32) gp->gstate.hwp[__inum];
1994    wrd = (uwrd >> 4) & 0xff;
1995    *has_stren = TRUE;
1996   break;
1997   case GC_MOS:
1998    /* state here has strength */
1999    wrd = (gp->gstate.wp[__inum] >> 16) & 0xffL;
2000    *has_stren = TRUE;
2001    break;
2002   case GC_CMOS:
2003    wrd = (gp->gstate.wp[__inum] >> 24) & 0xffL;
2004    *has_stren = TRUE;
2005    break;
2006   default: __case_terr(__FILE__, __LINE__); wrd = 0;
2007  }
2008  return(wrd);
2009 }
2010 
2011 /*
2012  * load a gate or udp input - value determined from gate type
2013  * and set has_stren and return stren byte value if input has strength
2014  *
2015  * pin number pi starts from 1 for first input since output is 0
2016  */
__ld_gate_in(struct gate_t * gp,int32 pi,int32 * has_stren)2017 extern word32 __ld_gate_in(struct gate_t *gp, int32 pi, int32 *has_stren)
2018 {
2019  register word32 wrd, uwrd, tmp;
2020  register int32 nins;
2021  struct udp_t *udpp;
2022 
2023  /* here just using a part of stack */
2024  *has_stren = FALSE;
2025  nins = gp->gpnum - 1;
2026  wrd = 0;
2027  switch ((byte) gp->g_class) {
2028   case GC_UDP:
2029    udpp = gp->gmsym->el.eudpp;
2030    if (!udpp->u_wide) uwrd = (word32) (gp->gstate.hwp[__inum]);
2031    else uwrd = gp->gstate.wp[2*__inum];
2032    wrd = (uwrd >> (pi - 1)) & 1;
2033    tmp = (uwrd >> (nins + pi - 1)) & 1;
2034    wrd |= (tmp << 1);
2035    break;
2036   case GC_LOGIC:
2037    if (nins > 15) wrd = widegate_ld_bit(gp->gstate.wp, nins + 1, pi - 1);
2038    else
2039     {
2040      wrd = get_packintowrd_(gp->gstate, __inum, nins + 1);
2041      wrd = ((wrd >> (pi - 1)) & 1L) | (((wrd >> (nins + pi - 1)) & 1L) << 1);
2042     }
2043    break;
2044   case GC_BUFIF:
2045    uwrd = (word32) gp->gstate.hwp[__inum];
2046    if (pi == 1) wrd = (uwrd & 3);
2047    else if (pi == 2) wrd = (uwrd >> 2) & 3;
2048    else __case_terr(__FILE__, __LINE__);
2049    break;
2050   case GC_MOS:
2051    /* state here has strength */
2052    uwrd = gp->gstate.wp[__inum];
2053    if (pi == 1) { *has_stren = TRUE; wrd = (uwrd & 0xff); }
2054    else if (pi == 2) wrd = ((uwrd >> 8) & 3);
2055    else __case_terr(__FILE__, __LINE__);
2056    break;
2057   case GC_CMOS:
2058    /* this has one stren data input and 2 control inputs */
2059    uwrd = gp->gstate.wp[__inum];
2060    if (pi == 1) { *has_stren = TRUE; wrd = uwrd & 0xff; }
2061    else if (pi == 2) wrd = (wrd >> 8) & 3;
2062    else if (pi == 3) wrd = (wrd >> 16) & 3;
2063    else __case_terr(__FILE__, __LINE__);
2064    break;
2065   default: __case_terr(__FILE__, __LINE__); wrd = 0;
2066  }
2067  return(wrd);
2068 }
2069 
2070 /*
2071  * load the output bit for wide gate
2072  * format for wide gate is a part in one word32 group, b in other
2073  * bit 0 is 0 (inputs [0:nins - 1]), output is bit nins
2074  */
widegate_ld_bit(word32 * gsp,int32 gwid,int32 biti)2075 static word32 widegate_ld_bit(word32 *gsp, int32 gwid, int32 biti)
2076 {
2077  int32 wlen;
2078  register word32 av, bv, *rap;
2079 
2080  /* rap is start of instance coded vector a b groups */
2081  wlen = wlen_(gwid);
2082  rap = &(gsp[2*wlen*__inum]);
2083  av = rhsbsel_(rap, biti);
2084  bv = rhsbsel_(&(rap[wlen]), biti);
2085  return(av | (bv << 1));
2086 }
2087 
2088 /*
2089  * load a iconn (down module port rhs to up iconn lhs) driver npp
2090  * caller must have moved to right itree loc. for xmr form
2091  *
2092  * driver is down module output port (inout handled in switch channel)
2093  * called from up iconn itree location
2094  */
__ld_iconn_up_driver(register struct net_pin_t * npp)2095 extern struct xstk_t *__ld_iconn_up_driver(register struct net_pin_t *npp)
2096 {
2097  register struct mod_pin_t *mpp;
2098  register struct expr_t *xlhs;
2099  register struct itree_t *itp;
2100  int32 orhslen;
2101  struct xstk_t *xsp;
2102  struct mod_t *downmdp;
2103 
2104  itp = &(__inst_ptr->in_its[npp->elnpp.eii]);
2105  downmdp = itp->itip->imsym->el.emdp;
2106  mpp = &(downmdp->mpins[npp->obnum]);
2107  /* notice this can never be xmr */
2108  __push_itstk(itp);
2109  xsp = __eval2_xpr(mpp->mpref);
2110 
2111  /* lvalue is iconn pos. port number */
2112  xlhs = itp->itip->ipins[npp->obnum];
2113  /* needed iconn connection width may differ from port width */
2114  if (xlhs->szu.xclen != xsp->xslen)
2115   {
2116    orhslen = xsp->xslen;
2117 
2118    /* SJM 09/29/03 - change to handle sign extension and separate types */
2119    if (xsp->xslen > xlhs->szu.xclen)
2120     __narrow_sizchg(xsp, xlhs->szu.xclen);
2121    else if (xsp->xslen < xlhs->szu.xclen)
2122     {
2123      if (mpp->mpref->has_sign) __sgn_xtnd_widen(xsp, xlhs->szu.xclen);
2124      else __sizchg_widen(xsp, xlhs->szu.xclen);
2125     }
2126 
2127    /* LOOKATME - only strength continuous assignments widen to z */
2128    /* all others widen to 0 */
2129    /* ??? if (orhslen < xlhs->szu.xclen) __fix_widened_tozs(xsp, orhslen); */
2130    /* SJM 05/10/04 - widening to x's eliminates need for sign difference */
2131    if (__wire_init) __fix_widened_toxs(xsp, orhslen);
2132   }
2133  __pop_itstk();
2134  return(xsp);
2135 }
2136 
2137 /*
2138  * load per bit iconn (down module port rhs to up iconn lhs) driver npp
2139  * caller must have moved to right itree loc. if xmr form
2140  *
2141  * driver is down module output port (inouts handled in tran channels)
2142  * called from up iconn itree location
2143  */
__ld_pb_iconn_up_driver(register struct net_pin_t * npp)2144 extern struct xstk_t *__ld_pb_iconn_up_driver(register struct net_pin_t *npp)
2145 {
2146  register struct mod_pin_t *mpp;
2147  register struct itree_t *itp;
2148  struct xstk_t *xsp;
2149  struct mod_t *downmdp;
2150 
2151  itp = &(__inst_ptr->in_its[npp->elnpp.eii]);
2152  downmdp = itp->itip->imsym->el.emdp;
2153  mpp = &(downmdp->mpins[npp->obnum]);
2154  mpp = &(mpp->pbmpps[npp->pbi]);
2155  /* notice this can never be xmr */
2156  __push_itstk(itp);
2157  xsp = __eval2_xpr(mpp->mpref);
2158  __pop_itstk();
2159 
2160  /* lvalue is iconn pos. port number */
2161  /* since per bit, never need size convert */
2162  /* DBG remove --
2163  {
2164   struct expr_t *xlhs;
2165 
2166   xlhs = itp->itip->pb_ipins_tab[npp->obnum][npp->pbi];
2167   if (mpp->mpref->szu.xclen != xsp->xslen) __misc_terr(__FILE__, __LINE__);
2168  }
2169  --- */
2170 
2171  return(xsp);
2172 }
2173 
2174 /*
2175  * load a mod. port (up iconn rhs to down mod port lhs) driver npp
2176  *
2177  * xmr form impossible here
2178  * driver is up iconn rhs connection for input port
2179  * called from down module itree location
2180  */
__ld_modport_down_driver(register struct net_pin_t * npp)2181 extern struct xstk_t *__ld_modport_down_driver(register struct net_pin_t *npp)
2182 {
2183  register struct xstk_t *xsp;
2184  register struct mod_pin_t *mpp;
2185  int32 orhslen;
2186  struct itree_t *itp;
2187  struct mod_t *downmdp;
2188  struct expr_t *xlhs, *up_rhsx;
2189 
2190  itp = __inst_ptr;
2191  /* --- DBG remove
2192  if (itp->up_it == NULL) __misc_terr(__FILE__, __LINE__);
2193  --- */
2194  downmdp = itp->itip->imsym->el.emdp;
2195 
2196  /* instance of lhs has module type that provides port lhs expr. */
2197  up_rhsx = itp->itip->ipins[npp->obnum];
2198  /* but variables in ndp come from inside up instance's module */
2199  __push_itstk(itp->up_it);
2200  /* this may access from different itree place if iconn xmr */
2201  xsp = __eval2_xpr(up_rhsx);
2202 
2203  /* up iconn width may differ from port width */
2204  mpp = &(downmdp->mpins[npp->obnum]);
2205  xlhs = mpp->mpref;
2206  if (xlhs->szu.xclen != xsp->xslen)
2207   {
2208    orhslen = xsp->xslen;
2209    /* SJM 09/29/03 - change to handle sign extension and separate types */
2210    if (xsp->xslen > xlhs->szu.xclen)
2211     __narrow_sizchg(xsp, xlhs->szu.xclen);
2212    else if (xsp->xslen < xlhs->szu.xclen)
2213     {
2214      if (up_rhsx->has_sign) __sgn_xtnd_widen(xsp, xlhs->szu.xclen);
2215      else __sizchg_widen(xsp, xlhs->szu.xclen);
2216     }
2217 
2218    /* LOOKATME - only strength continuous assignments widen to z */
2219    /* all others widen to 0 */
2220    /* ?? if (orhslen < xlhs->szu.xclen) __fix_widened_tozs(xsp, orhslen); */
2221    /* SJM 05/10/04 - widening to x's eliminates need for sign difference */
2222    if (__wire_init) __fix_widened_toxs(xsp, orhslen);
2223   }
2224  __pop_itstk();
2225  return(xsp);
2226 }
2227 
2228 /*
2229  * load per bit mod. port (up iconn rhs to down mod port lhs) driver npp
2230  * for input ports where high conn is concat
2231  *
2232  * xmr form impossible here
2233  * driver of this down iput port is up highconn iconn rhs expr
2234  * called from down module itree location
2235  */
__ld_pb_modport_down_driver(register struct net_pin_t * npp)2236 extern struct xstk_t *__ld_pb_modport_down_driver(
2237  register struct net_pin_t *npp)
2238 {
2239  register struct xstk_t *xsp;
2240  register struct itree_t *itp;
2241  struct expr_t *up_rhsx;
2242 
2243  itp = __inst_ptr;
2244  /* --- DBG remove
2245  if (itp->up_it == NULL) __misc_terr(__FILE__, __LINE__);
2246  --- */
2247 
2248  /* instance of lhs has module type that provides port lhs expr. */
2249  up_rhsx = itp->itip->pb_ipins_tab[npp->obnum][npp->pbi];
2250  /* but variables in ndp come from inside up instance's module */
2251 
2252  __push_itstk(itp->up_it);
2253  /* this may access from different itree place if iconn xmr */
2254  /* FIXME ??? - since up rhs decomposes into 1 bit, this can be faster */
2255  xsp = __eval2_xpr(up_rhsx);
2256  __pop_itstk();
2257 
2258  /* since per bit, never need size convert */
2259  /* DBG remove --
2260  {
2261   struct mod_pin_t *mpp;
2262   struct mod_t *downmdp;
2263 
2264   downmdp = itp->itip->imsym->el.emdp;
2265   mpp = &(downmdp->mpins[npp->obnum]);
2266   mpp = &(mpp->pbmpps[npp->pbi]);
2267   if (mpp->mpref->szu.xclen != xsp->xslen) __misc_terr(__FILE__, __LINE__);
2268  }
2269  --- */
2270 
2271  return(xsp);
2272 }
2273 
2274 /*
2275  * ROUTINES TO COMBINE DRIVERS USING NON-STRENGTH RULES
2276  */
2277 
2278 /*
2279  * apply values from npp npcxsp to a/b accumulator for net pin npp
2280  *
2281  * this is for non strength case
2282  * wire here is used for type - does not need itree place
2283  * can pass entire wire since section evaled determined by passed npp
2284  *
2285  * SJM 11/13/02 - not handling IS -2 per inst param range select right
2286  * SJM 11/15/02 - need to pass the a/b word32 ptr so can call from compiled
2287  *
2288  * FIXME - think this can never happen
2289  */
__eval_wire(word32 * acc_wp,word32 * drv_wp,struct net_t * np,struct net_pin_t * npp)2290 extern void __eval_wire(word32 *acc_wp, word32 *drv_wp, struct net_t *np,
2291  struct net_pin_t *npp)
2292 {
2293  register struct npaux_t *npauxp;
2294  word32 resa, resb, *wp;
2295  int32 wlen, pselwid, i1, i2;
2296  struct xstk_t *tmpxsp;
2297 
2298  wlen = wlen_(np->nwid);
2299  /* entire wire */
2300  if ((npauxp = npp->npaux) == NULL || npauxp->nbi1 == -1)
2301   {
2302    if (np->nwid > WBITS)
2303     {
2304      __eval_wide_wire(acc_wp, &(acc_wp[wlen]), drv_wp, &(drv_wp[wlen]),
2305       np->nwid, np->ntyp);
2306     }
2307    else __eval_1w_nonstren(acc_wp, &(acc_wp[1]), drv_wp[0], drv_wp[1],
2308     np->ntyp);
2309    return;
2310   }
2311 
2312  /* know that driver is section of lhs wire - i.e. lhs select decl assign */
2313  /* know npaux field exists */
2314  if (npauxp->nbi1 == -2)
2315   {
2316    /* SJM 10/12/04 - because contab realloced, must be ndx base of IS */
2317    wp = &(__contab[npauxp->nbi2.xvi]);
2318    wp = &(wp[2*__inum]);
2319    i1 = i2 = (int32) wp[0];
2320   }
2321  else { i1 = npauxp->nbi1; i2 = npauxp->nbi2.i; }
2322  if (i1 == i2)
2323   {
2324    resa = rhsbsel_(acc_wp, i1);
2325    resb = rhsbsel_(&(acc_wp[wlen]), i1);
2326    /* know thing driving wire is 1 bit - will eval. to 1 bit */
2327    __eval_1w_nonstren(&resa, &resb, drv_wp[0], drv_wp[1], np->ntyp);
2328    /* assign back to bit */
2329    __lhsbsel(acc_wp, i1, resa);
2330    __lhsbsel(&(acc_wp[wlen]), i1, resb);
2331    return;
2332   }
2333 
2334  /* part select inefficient but think still better than if done bit by bit */
2335  /* part select - net pin range is normalized */
2336  pselwid = i1 - i2 + 1;
2337  /* load accumulator region into tmp xsp */
2338  push_xstk_(tmpxsp, pselwid);
2339  __rhspsel(tmpxsp->ap, acc_wp, i2, pselwid);
2340  __rhspsel(tmpxsp->bp, &(acc_wp[wlen]), i2, pselwid);
2341 
2342  /* eval. - notice if fits in 1 word32 do not need width */
2343  if (pselwid > WBITS)
2344   __eval_wide_wire(tmpxsp->ap, tmpxsp->bp, drv_wp, &(drv_wp[wlen_(pselwid)]),
2345    pselwid, np->ntyp);
2346  /*11/21/2002 AIV was nwid for the last arg should be type*/
2347  else __eval_1w_nonstren(tmpxsp->ap, tmpxsp->bp, drv_wp[0], drv_wp[1],
2348   np->ntyp);
2349 
2350  /* store back into accumulator */
2351  __lhspsel(acc_wp, i2, tmpxsp->ap, pselwid);
2352  __lhspsel(&(acc_wp[wlen]), i2, tmpxsp->bp, pselwid);
2353  __pop_xstk();
2354 }
2355 
2356 /*
2357  * evaluate stack elements into depending on wire type
2358  * any selection handled above here rxsp and xsp1 can be same
2359  * since all have same width here, no need to remove unused bits
2360  *
2361  * SJM 11/15/02 - change so pass a/b word32 ptrs so compiled code can call
2362  */
__eval_wide_wire(word32 * acc_ap,word32 * acc_bp,word32 * drv_ap,word32 * drv_bp,int32 opbits,word32 wtyp)2363 extern void __eval_wide_wire(word32 *acc_ap, word32 *acc_bp,
2364  word32 *drv_ap, word32 *drv_bp, int32 opbits, word32 wtyp)
2365 {
2366  register int32 wi;
2367 
2368  /* DBG remove - only these can have multi-fi and no strength */
2369  /* tri0, tri1 and trireg always strength --
2370  switch ((byte) wtyp) {
2371   case N_WIRE: case N_TRI: case N_TRIAND: case N_WA: case N_TRIOR: case N_WO:
2372    break;
2373   default: __case_terr(__FILE__, __LINE__);
2374  }
2375  --- */
2376  for (wi = 0; wi < wlen_(opbits); wi++)
2377   {
2378    __eval_1w_nonstren(&(acc_ap[wi]), &(acc_bp[wi]), drv_ap[wi],
2379     drv_bp[wi], wtyp);
2380   }
2381 }
2382 
2383 /*
2384  * evaluate a 1 word32 normal tri wire
2385  * notice res and op can be same object since op by value
2386  * for non strength case if one z, use other, if both z leave as z
2387  * since fits in one bit do not need width - high bits will just be 0
2388  *
2389  * eval is word32 by word32 then after stren competition, used section
2390  * extracted with select if needed
2391  *
2392  * LOOKATME - think this can never happen
2393  */
__eval_1w_nonstren(register word32 * resa,register word32 * resb,register word32 op2a,register word32 op2b,word32 wtyp)2394 extern void __eval_1w_nonstren(register word32 *resa, register word32 *resb,
2395  register word32 op2a, register word32 op2b, word32 wtyp)
2396 {
2397  register word32 zmask, donemask;
2398  register word32 op1a, op1b;
2399 
2400  op1a = resa[0];
2401  op1b = resb[0];
2402  /* first all bits that are the same - common case */
2403  /* notice wand and wor same bits always same */
2404  /* unused bits handled here - since will both be 0 */
2405  /* mask has 1 if same else 0 */
2406  zmask = ~((op1a ^ op2a) | (op1b ^ op2b));
2407  resa[0] = op1a & zmask;
2408  resb[0] = op1b & zmask;
2409  donemask = zmask;
2410  if (donemask == __masktab[0]) goto done;
2411 
2412  /* next op1 z bits, use op2 bits */
2413  zmask = (op1a ^ op1b) & op1b;
2414  /* if z in op1, value is op2 */
2415  resa[0] |= (op2a & zmask);
2416  resb[0] |= (op2b & zmask);
2417  donemask |= zmask;
2418  if (donemask == __masktab[0]) goto done;
2419 
2420  /* next op2 zbits, use op1 bits */
2421  zmask = (op2a ^ op2b) & op2b;
2422  /* if z in op2, value is op2 */
2423  resa[0] |= op1a & zmask;
2424  resb[0] |= op1b & zmask;
2425  donemask |= zmask;
2426  if (donemask == __masktab[0]) goto done;
2427 
2428  zmask = ~donemask;
2429  /* finally net type determines algorithm - know b bit 0 for these bits */
2430  switch ((byte) wtyp) {
2431   case N_WIRE: case N_TRI:
2432    /* know remaining bits must be x, neither and not the same */
2433    resa[0] |= zmask; resb[0] |= zmask;
2434    break;
2435   case N_TRIAND: case N_WA:
2436    /* if either 0, result 0, else x, since 1 1 done */
2437    resa[0] |= ((op1a | op1b) & (op2a | op2b)) & zmask;
2438    resb[0] |= (resa[0] & (op1b | op2b)) & zmask;
2439    break;
2440   case N_TRIOR: case N_WO:
2441    resb[0]
2442     |= ((op2b ^ op1b ^ ((op1a | op1b) & (op2b | (op2a & op1b)))) & zmask);
2443    resa[0] |= ((resb[0] | op2a | op1a) & zmask);
2444    break;
2445   default: __case_terr(__FILE__, __LINE__);
2446  }
2447 done:
2448  /* DBG --- */
2449  if (__debug_flg && __ev_tracing)
2450   {
2451    char s1[RECLEN];
2452 
2453    __tr_msg(
2454     "+> fi>1 nonstren: %s op1a=%lx,op1b=%lx,op2a=%lx,op2b=%lx,resa=%lx,resb=%lx,zmask=%lx\n",
2455     __to_wtnam2(s1, wtyp), op1a, op1b, op2a, op2b, resa[0], resb[0], zmask);
2456   }
2457  /* --- */
2458 }
2459 
2460 /*
2461  * MULTI FAN IN STRENGTH WIRE ASSIGN ROUTINES
2462  * ALL STRENGTH ASSIGN THROUGH HERE
2463  */
2464 
2465 /*
2466  * load an entire strength wire value onto top of stack
2467  * by evaluating all drivers
2468  *
2469  * for normal wire itstk must be lhs wire place - for mod. in this is down
2470  * (rhs up) and for inst. output this is up (rhs down)
2471  * for xmr wire current itree place is target (define) inst of wire
2472  *
2473  * the driver evaluation may change to xmr itree place but always restores
2474  *
2475  * loads only hard drivers - tran channel code handles tran components
2476  */
__stload_mdrwire(struct net_t * np)2477 extern struct xstk_t *__stload_mdrwire(struct net_t *np)
2478 {
2479  register struct net_pin_t *npp;
2480  register struct xstk_t *xsp;
2481  register byte *sbp;
2482 
2483  /* allocate accumulator - initialize all bits to z in case not driven */
2484  /* notice built in 8 bits per byte but also no b part so need half size */
2485  xsp = init_stwire_accum(np);
2486  sbp = (byte *) xsp->ap;
2487 
2488  /* evaluation of every net and channel driver against current accum. value */
2489  for (npp = np->ndrvs; npp != NULL; npp = npp->npnxt)
2490   {
2491    /* filter new rooted and up. rel col. forms */
2492    if (npp->npproctyp == NP_PROC_FILT && npp->npaux->npu.filtitp != __inst_ptr)
2493     continue;
2494 
2495    ldcomb_stdriver(sbp, np, npp);
2496   }
2497  return(xsp);
2498 }
2499 
2500 /*
2501  * load and combine in to passed z initial acumulator the driver for 1 val
2502  * may not add if npp does not apply to this inst. or driver off
2503  */
ldcomb_stdriver(register byte * acc_sbp,struct net_t * np,register struct net_pin_t * npp)2504 static void ldcomb_stdriver(register byte *acc_sbp, struct net_t *np,
2505  register struct net_pin_t *npp)
2506 {
2507  register byte *sbp2;
2508  register int32 i1;
2509  register struct xstk_t *xsp;
2510  int32 nd_itpop;
2511  word32 *wp;
2512  byte *sbp;
2513  struct npaux_t *npauxp;
2514 
2515  /* DBG remove ---
2516  if (__debug_flg && __ev_tracing)
2517   {
2518    __tr_msg("## loading %s strength driver of wire %s\n",
2519     __to_npptyp(__xs, npp), np->nsym->synam);
2520   }
2521  --- */
2522 
2523  /* trace from target (definition location) back to ref. inst. itree loc */
2524  if (npp->npproctyp != NP_PROC_INMOD)
2525   {
2526    /* SJM 04/17/03 - if XMR does not match - do not combine in */
2527    if (!__move_to_npprefloc(npp)) return;
2528    nd_itpop = TRUE;
2529   }
2530  else nd_itpop = FALSE;
2531 
2532  /* load driver onto new top of stack (this always pushes) */
2533  /* know rhs driver width will be changed to match lhs width exactly */
2534 
2535  switch ((byte) npp->npntyp) {
2536   case NP_CONTA: xsp = ld_stconta_driver(npp); break;
2537   case NP_TFRWARG: xsp = __ld_sttfrwarg_driver(npp); break;
2538   case NP_VPIPUTV: xsp = ld_stvpiputv_driver(npp); break;
2539   case NP_GATE: xsp = ld_stgate_driver(npp); break;
2540   /* these are up to highconn strength output port drivers */
2541   case NP_ICONN: xsp = ld_sticonn_up_driver(npp); break;
2542   case NP_PB_ICONN: xsp = ld_pb_sticonn_up_driver(npp); break;
2543   /* these are down to lowconn strength input port drivers */
2544   case NP_MDPRT: xsp = ld_stmodport_down_driver(npp); break;
2545   case NP_PB_MDPRT: xsp = ld_pb_stmodport_down_driver(npp); break;
2546   case NP_PULL: xsp = ld_stpull_driver(npp); break;
2547   /* TRAN impossible here */
2548   default: __case_terr(__FILE__, __LINE__); xsp = NULL;
2549  }
2550  if (nd_itpop) __pop_itstk();
2551 
2552  /* SJM 07/08/00 - need high z's if gate driver or narrow conta */
2553  /* need at least when stren gate output drives vector */
2554  /* SJM 11/11/02 - slightly wrong - works because only needed for gate */
2555  /* wich never has lhs concat sink */
2556 
2557  /* SJM 05/10/04 - no sign extension because widening to z'x */
2558  if (xsp->xslen/4 < np->nwid) __strenwiden_sizchg(xsp, np->nwid);
2559 
2560  sbp = (byte *) xsp->ap;
2561 
2562  /* first if this is lhs concat, must isolate relevant from rhs (sbp2) */
2563  /* all indices normalized here to h:0 */
2564  if ((npauxp = npp->npaux) != NULL && npauxp->lcbi1 != -1)
2565   sbp2 = &(sbp[npauxp->lcbi2]);
2566  else sbp2 = sbp;
2567  /* first entire wire case */
2568  if (npauxp == NULL || npauxp->nbi1 == -1)
2569   {
2570    eval_stwire(np->ntyp, acc_sbp, np->nwid - 1, 0, sbp2);
2571    goto done;
2572   }
2573  /* IS bit select cases */
2574  if (npauxp->nbi1 == -2)
2575   {
2576    /* SJM 10/12/04 - because contab realloced, must be ndx base of IS */
2577    wp = &(__contab[npauxp->nbi2.xvi]);
2578    wp = &(wp[2*__inum]);
2579    i1 = (int32) wp[0];
2580    /* here strength competition of sbp2[0] against sbp[i1] accum. */
2581    eval_stwire(np->ntyp, acc_sbp, i1, i1, sbp2);
2582    goto done;
2583   }
2584  /* --- DBG
2585  if (__debug_flg) __st_regab_tostr(s1, acc_sbp, np->nwid);
2586  --- */
2587 
2588  /* finally competition of accum sbp[nbi1:nbi2] to low of sbp2 */
2589  eval_stwire(np->ntyp, acc_sbp, npauxp->nbi1, npauxp->nbi2.i, sbp2);
2590 
2591  /* --- DBG
2592  if (__debug_flg)
2593   {
2594    int32 ti1, ti2, lci1, lci2;
2595    char s2[RECLEN], s3[RECLEN];
2596 
2597    if ((npauxp = npp->npaux) != NULL)
2598     {
2599      ti1 = npauxp->nbi1;
2600      ti2 = npauxp->nbi2.i;
2601      lci1 = npauxp->lcbi1;
2602      lci2 = npauxp->lcbi2;
2603     }
2604    else ti1 = ti2 = lci1 = lci2 = -1;
2605 
2606    __dbg_msg(
2607     "## stren driver before %s, after %s,\n  value %s, rhs [%d:%d] lhs [%d:%d]\n",
2608     s1, __st_regab_tostr(s2, acc_sbp, np->nwid), __st_regab_tostr(s3, sbp2,
2609     ti1 - ti2 + 1), lci1, lci2, ti1, ti2);
2610   }
2611  --- */
2612 done:
2613  __pop_xstk();
2614 }
2615 
2616 /*
2617  * initialize a wire for multi-fi combination (depends on wire type)
2618  * this push value on to expr. stack
2619  */
init_stwire_accum(struct net_t * np)2620 static struct xstk_t *init_stwire_accum(struct net_t *np)
2621 {
2622  register byte *sbp;
2623  struct xstk_t *xsp;
2624  byte stval;
2625 
2626  push_xstk_(xsp, 4*np->nwid);
2627  sbp = (byte *) xsp->ap;
2628 
2629  /* 0,0,2 is high z */
2630  /* initialize in case unc., */
2631  switch ((byte) np->ntyp) {
2632   case N_TRI0: stval = ST_PULL0; goto set_stren;
2633   case N_TRI1: stval = ST_PULL1; goto set_stren;
2634   case N_SUPPLY0:
2635    set_byteval_(sbp, np->nwid, ST_SUPPLY0);
2636    return(xsp);
2637   case N_SUPPLY1:
2638    set_byteval_(sbp, np->nwid, ST_SUPPLY1);
2639    return(xsp);
2640   default:
2641    stval = ST_HIZ;
2642 set_stren:
2643   set_byteval_(sbp, np->nwid, stval);
2644  }
2645  return(xsp);
2646 }
2647 
2648 /*
2649  * load a wire's driven value (maybe not driven z) on to top of stack
2650  * routines called from here must do stack pushing themselves
2651  *
2652  * this is only called by count drivers
2653  */
__ld_stwire_driver(register struct net_pin_t * npp)2654 extern struct xstk_t *__ld_stwire_driver(register struct net_pin_t *npp)
2655 {
2656  register struct xstk_t *xsp;
2657  int32 nd_itpop;
2658 
2659  /* move from target back to itree loc of ref. */
2660  if (npp->npproctyp != NP_PROC_INMOD)
2661   {
2662    /* SJM 04/17/03 - if XMR does not match - do not combine in */
2663    if (!__move_to_npprefloc(npp)) return(NULL);
2664    nd_itpop = TRUE;
2665   }
2666  else nd_itpop = FALSE;
2667 
2668  /* this puts the driving value (normal rhs with rhs width) on stack */
2669  /* notice md port or tran or iconn may return nil, caller does not pop */
2670  switch ((byte) npp->npntyp) {
2671   case NP_CONTA: xsp = ld_stconta_driver(npp); break;
2672   case NP_TFRWARG: xsp = __ld_sttfrwarg_driver(npp); break;
2673   case NP_VPIPUTV: xsp = ld_stvpiputv_driver(npp); break;
2674   case NP_GATE: xsp = ld_stgate_driver(npp); break;
2675   /* these are up to highconn strength output port drivers */
2676   case NP_ICONN: xsp = ld_sticonn_up_driver(npp); break;
2677   case NP_PB_ICONN: xsp = ld_pb_sticonn_up_driver(npp); break;
2678   /* these are down to lowconn strength input port drivers */
2679   case NP_MDPRT: xsp = ld_stmodport_down_driver(npp); break;
2680   case NP_PB_MDPRT: xsp = ld_pb_stmodport_down_driver(npp); break;
2681   default: __case_terr(__FILE__, __LINE__); return(NULL);
2682  }
2683  if (nd_itpop) __pop_itstk();
2684  return(xsp);
2685 }
2686 
2687 /*
2688  * load a strength gate driver npp
2689  * caller must have moved to right itree loc. for xmr form
2690  */
ld_stgate_driver(struct net_pin_t * npp)2691 static struct xstk_t *ld_stgate_driver(struct net_pin_t *npp)
2692 {
2693  register struct xstk_t *xsp;
2694  register byte *sbp;
2695  int32 has_stren;
2696 
2697  /* here must add (st0,st0) if no strength */
2698  push_xstk_(xsp, 4);
2699  sbp = (byte *) xsp->ap;
2700  sbp[0] = (byte) __ld_gate_out(npp->elnpp.egp, &has_stren);
2701  if (!has_stren && sbp[0] != 2) sbp[0] |= (ST_STRVAL << 2);
2702  return(xsp);
2703 }
2704 
2705 /*
2706  * load a strength continuous assignment (not port conta) driver npp
2707  * caller must have moved to right itree loc. for xmr form
2708  *
2709  * for rhs concat separated into per bit, this is PB conta el
2710  */
ld_stconta_driver(struct net_pin_t * npp)2711 static struct xstk_t *ld_stconta_driver(struct net_pin_t *npp)
2712 {
2713  register struct xstk_t *xsp;
2714  register int32 blen;
2715  register struct conta_t *cap;
2716  int32 orhslen;
2717  byte *sbp;
2718  struct xstk_t *xsp2;
2719 
2720  /* case 1: fi of 1 - driver if npp range of net itself */
2721  /* fi == 1 subcase only for driver (show vars) display */
2722  /* SJM 09/18/02 - no separate per bit NP type, checkfor pb sim on */
2723  cap = npp->elnpp.ecap;
2724  if (cap->ca_pb_sim) cap = &(cap->pbcau.pbcaps[npp->pbi]);
2725 
2726  blen = cap->lhsx->szu.xclen;
2727  /* if fi == 1 and no delay, no driver field driver is size changed rhs */
2728  /* could access lhs since should be same but this is consistency check */
2729  /* notice display whole wire with range value printed if cat */
2730  push_xstk_(xsp, 4*blen);
2731  sbp = (byte *) xsp->ap;
2732  if (cap->ca_drv_wp.wp == NULL)
2733   {
2734    xsp2 = __eval2_xpr(cap->rhsx);
2735    if (blen != xsp2->xslen)
2736     {
2737      orhslen = xsp2->xslen;
2738 
2739      /* SJM 09/29/03 - change to handle sign extension and separate types */
2740      /* SJM 06/20/05 - rare case but needs signed widen (stren maybe added?) */
2741      if (xsp2->xslen > blen) __narrow_sizchg(xsp2, blen);
2742      else if (xsp2->xslen < blen)
2743       {
2744        if (cap->rhsx->has_sign) __sgn_xtnd_widen(xsp2, blen);
2745        else __sizchg_widen(xsp2, blen);
2746       }
2747 
2748      if (__wire_init) __fix_widened_toxs(xsp2, orhslen);
2749     }
2750   }
2751  else
2752   {
2753    /* complicated has delay or multi-fi case, driver is saved value */
2754    /* know width will always be correct lhs */
2755    /* for multi-fi, must save driver else rhs may re-eval too many times */
2756    push_xstk_(xsp2, blen);
2757    __ld_perinst_val(xsp2->ap, xsp2->bp, cap->ca_drv_wp, blen);
2758   }
2759  /* add strength */
2760  __st_standval(sbp, xsp2, cap->ca_stval);
2761  __pop_xstk();
2762  return(xsp);
2763 }
2764 
2765 /*
2766  * load a tf_ task/func argument rw parameter strength driver
2767  * caller must have moved to right itree loc. for xmr form
2768  */
__ld_sttfrwarg_driver(struct net_pin_t * npp)2769 extern struct xstk_t *__ld_sttfrwarg_driver(struct net_pin_t *npp)
2770 {
2771  register struct xstk_t *xsp;
2772  register int32 blen;
2773  register struct tfrec_t *tfrp;
2774  byte *sbp, *sbp2;
2775  struct tfarg_t *tfap;
2776  struct expr_t *xp;
2777 
2778  tfrp = npp->elnpp.etfrp;
2779  tfap = &(tfrp->tfargs[npp->obnum]);
2780  xp = tfap->arg.axp;
2781  blen = xp->szu.xclen;
2782  /* tf arg fi == 1 case */
2783  if (tfap->tfdrv_wp.wp == NULL)
2784   {
2785    xsp = __ndst_eval_xpr(xp);
2786    /* know this is lhs so width loaded must be arg width */
2787    /* DBG remove */
2788    if (blen != xsp->xslen/4) __misc_terr(__FILE__, __LINE__);
2789    /* --- */
2790   }
2791  else
2792   {
2793    /* tf arg r/w lhs wire has multiple drivers */
2794    push_xstk_(xsp, 4*blen);
2795    sbp = (byte *) xsp->ap;
2796    sbp2 = &(tfap->tfdrv_wp.bp[__inum*blen]);
2797    memcpy(sbp, sbp2, blen);
2798   }
2799  return(xsp);
2800 }
2801 
2802 /*
2803  * load a putv added terminal strength driver
2804  *
2805  * inst. or bit may not have added driver if so will just load z's
2806  * z's do not hurt and faster to load entire wire
2807  */
ld_stvpiputv_driver(struct net_pin_t * npp)2808 static struct xstk_t *ld_stvpiputv_driver(struct net_pin_t *npp)
2809 {
2810  register struct net_t *np;
2811  register struct xstk_t *xsp;
2812  register struct vpi_drv_t *drvp;
2813  register byte *sbp, *sbp2;
2814  int32 bi;
2815 
2816  np = npp->elnpp.enp;
2817  drvp = np->vpi_ndrvs[npp->obnum];
2818  if (npp->npaux != NULL && (bi = npp->npaux->nbi1) != -1)
2819   {
2820    push_xstk_(xsp, 4);
2821    sbp = (byte *) xsp->ap;
2822    sbp[0] = drvp->vpi_drvwp.bp[np->nwid*__inum + bi];
2823    return(xsp);
2824   }
2825  /* SJM 08/11/00 - was wrongly not 4 times width so widen over-wrote hiz */
2826  push_xstk_(xsp, 4*np->nwid);
2827  sbp = (byte *) xsp->ap;
2828  sbp2 = &(drvp->vpi_drvwp.bp[np->nwid*__inum]);
2829  memcpy(sbp, sbp2, np->nwid);
2830  return(xsp);
2831 }
2832 
2833 /*
2834  * load a strength iconn (down module port rhs to up iconn lhs) driver npp
2835  * caller must have moved to right itree loc. for xmr form
2836  *
2837  * called from up iconn itree location
2838  */
ld_sticonn_up_driver(register struct net_pin_t * npp)2839 static struct xstk_t *ld_sticonn_up_driver(register struct net_pin_t *npp)
2840 {
2841  register struct xstk_t *xsp;
2842  register struct mod_pin_t *mpp;
2843  register struct expr_t *xlhs;
2844  struct itree_t *itp;
2845  struct mod_t *downmdp;
2846 
2847  /* assign from down module port rhs into up iconn lhs expr. */
2848  /* driver is down module port - called with itree location of up */
2849  itp = &(__inst_ptr->in_its[npp->elnpp.eii]);
2850  downmdp = itp->itip->imsym->el.emdp;
2851  mpp = &(downmdp->mpins[npp->obnum]);
2852  xlhs = itp->itip->ipins[npp->obnum];
2853 
2854  /* this must load preserving strengths - here know mod. port has stren */
2855  /* inout port output half driver is always port value */
2856  __push_itstk(itp);
2857  /* if down rhsx is reg, will add stron strength */
2858  xsp = __ndst_eval_xpr(mpp->mpref);
2859 
2860  /* only if rhs too narrow, need to add in HIZ and maybe widen alloc area */
2861  /* if too wide just ignores high bytes */
2862  if (xlhs->szu.xclen > mpp->mpref->szu.xclen)
2863   {
2864    /* SJM 05/10/04 - no sign extension because widening to z'x */
2865    __strenwiden_sizchg(xsp, xlhs->szu.xclen);
2866   }
2867  __pop_itstk();
2868  return(xsp);
2869 }
2870 
2871 /*
2872  * load per bit stren iconn (down module port rhs to up iconn lhs) driver
2873  *
2874  * driver is down module output port
2875  * called from up iconn itree location
2876  * caller must have moved to right itree loc. for xmr form
2877  */
ld_pb_sticonn_up_driver(register struct net_pin_t * npp)2878 static struct xstk_t *ld_pb_sticonn_up_driver(register struct net_pin_t *npp)
2879 {
2880  register struct xstk_t *xsp;
2881  register struct mod_pin_t *mpp;
2882  struct itree_t *itp;
2883  struct mod_t *downmdp;
2884 
2885  /* assign from down module port rhs into up iconn lhs expr. */
2886  /* driver is down module port - called with itree location of up */
2887  itp = &(__inst_ptr->in_its[npp->elnpp.eii]);
2888  downmdp = itp->itip->imsym->el.emdp;
2889  mpp = &(downmdp->mpins[npp->obnum]);
2890  mpp = &(mpp->pbmpps[npp->pbi]);
2891 
2892  /* this must load preserving strengths - here know mod. port has stren */
2893  /* inout port output half driver is always port value */
2894  __push_itstk(itp);
2895  /* if down rhsx is reg, will add stron strength */
2896  xsp = __ndst_eval_xpr(mpp->mpref);
2897  __pop_itstk();
2898 
2899  /* since per bit, never need size convert */
2900  /* DBG remove --
2901  {
2902   struct expr_t *lhsx;
2903 
2904   lhsx = itp->itip->pb_ipins_tab[npp->obnum][npp->pbi];
2905   if (lhsx->szu.xclen != xsp->xslen) __misc_terr(__FILE__, __LINE__);
2906  }
2907  --- */
2908  return(xsp);
2909 }
2910 
2911 /*
2912  * load a mod. port (up iconn rhs to down mod port lhs) driver npp
2913  *
2914  * xmr form impossible here
2915  * driver is down module input or inout port (strength model)
2916  * called from down module itree location
2917  */
ld_stmodport_down_driver(register struct net_pin_t * npp)2918 static struct xstk_t *ld_stmodport_down_driver(register struct net_pin_t *npp)
2919 {
2920  register struct mod_pin_t *mpp;
2921  register struct itree_t *itp;
2922  register struct xstk_t *xsp;
2923  struct mod_t *downmdp;
2924  struct expr_t *xlhs, *up_rhsx;
2925 
2926  itp = __inst_ptr;
2927  /* --- DBG remove
2928  if (itp->up_it == NULL) __misc_terr(__FILE__, __LINE__);
2929  --- */
2930 
2931  up_rhsx = itp->itip->ipins[npp->obnum];
2932  downmdp = itp->itip->imsym->el.emdp;
2933  mpp = &(downmdp->mpins[npp->obnum]);
2934  xlhs = mpp->mpref;
2935  __push_itstk(itp->up_it);
2936  /* if down rhsx is reg, will add strong */
2937  xsp = __ndst_eval_xpr(up_rhsx);
2938  /* only if rhs too narrow, need to add in HIZ and maybe widen alloc area */
2939  /* if too wide just ignores high bytes */
2940  /* SJM 05/10/04 - no sign extension because widening to z'x */
2941  if (xlhs->szu.xclen > up_rhsx->szu.xclen)
2942   __strenwiden_sizchg(xsp, xlhs->szu.xclen);
2943  __pop_itstk();
2944  return(xsp);
2945 }
2946 
2947 /*
2948  * load a mod. port (up iconn rhs to down mod port lhs) driver npp
2949  *
2950  * xmr form impossible here
2951  * driver is down module input or inout port (strength model)
2952  * called from down module itree location
2953  */
ld_pb_stmodport_down_driver(register struct net_pin_t * npp)2954 static struct xstk_t *ld_pb_stmodport_down_driver(
2955  register struct net_pin_t *npp)
2956 {
2957  register struct xstk_t *xsp;
2958  register struct itree_t *itp;
2959  struct expr_t *up_rhsx;
2960 
2961  itp = __inst_ptr;
2962  /* --- DBG remove
2963  if (itp->up_it == NULL) __misc_terr(__FILE__, __LINE__);
2964  --- */
2965 
2966  __push_itstk(itp->up_it);
2967  up_rhsx = itp->itip->pb_ipins_tab[npp->obnum][npp->pbi];
2968  /* if down rhsx is reg, will add strong */
2969  xsp = __ndst_eval_xpr(up_rhsx);
2970 
2971  /* since per bit never need size change */
2972  /* DBG remove --
2973  {
2974   struct mod_pin_t *mpp;
2975   struct mod_t *downmdp;
2976 
2977   downmdp = itp->itip->imsym->el.emdp;
2978   mpp = &(downmdp->mpins[npp->obnum]);
2979   mpp = &(mpp->pbmpps[npp->pbi]);
2980   if (mpp->mpref->szu.xclen > up_rhsx->szu.xclen)
2981    __misc_terr(__FILE__, __LINE__);
2982  }
2983  --- */
2984 
2985  __pop_itstk();
2986  return(xsp);
2987 }
2988 
2989 /*
2990  * load a strength pull driver (only strength possible)
2991  */
ld_stpull_driver(struct net_pin_t * npp)2992 static struct xstk_t *ld_stpull_driver(struct net_pin_t *npp)
2993 {
2994  register struct xstk_t *xsp;
2995  byte *sbp;
2996  struct gate_t *gp;
2997  struct expr_t *ndp;
2998 
2999  /* get pull out lhs wire or select */
3000  gp = npp->elnpp.egp;
3001  ndp = gp->gpins[npp->obnum];
3002  push_xstk_(xsp, 4*ndp->szu.xclen);
3003  sbp = (byte *) xsp->ap;
3004  set_byteval_(sbp, ndp->szu.xclen, (byte) ((gp->g_stval << 2) | npp->pullval));
3005  return(xsp);
3006 }
3007 
3008 /*
3009  * STRENGTH EXPRESSION EVALUATION ROUTINES
3010  */
3011 
3012 /*
3013  * evaluate a rhs expression producing a strength format result
3014  * even if needs to add (st0,st1) for non strength expr.
3015  * this is equivalent of __eval_xpr when strength required
3016  *
3017  * pushes and pops temps and leaves result on top of reg stack
3018  * caller must pop value from stack
3019  * no stack checks underflow checks - maybe would help debugging
3020  */
__ndst_eval_xpr(struct expr_t * ndp)3021 extern struct xstk_t *__ndst_eval_xpr(struct expr_t *ndp)
3022 {
3023  byte *sbp;
3024  struct xstk_t *stxsp;
3025 
3026  /* strength uses only a part of stack register */
3027  push_xstk_(stxsp, 4*ndp->szu.xclen);
3028  sbp = (byte *) stxsp->ap;
3029  ndst_eval2_xpr(sbp, ndp);
3030  return(stxsp);
3031 }
3032 
3033 /*
3034  * in place evaluate at least top node strength expression
3035  * this is for port feed thru assignments that pass strength thru
3036  * this does not leave value on top of stack
3037  */
ndst_eval2_xpr(register byte * sbp,register struct expr_t * ndp)3038 static void ndst_eval2_xpr(register byte *sbp, register struct expr_t *ndp)
3039 {
3040  register byte *bp;
3041  int32 nd_itpop;
3042  struct net_t *np;
3043  struct expr_t *idndp;
3044  struct gref_t *grp;
3045  struct xstk_t *xsp;
3046 
3047  /* possible for this to be non stength reg. where strong added */
3048  if (!ndp->x_stren)
3049   {
3050    xsp = __eval2_xpr(ndp);
3051    __st_standval(sbp, xsp, ST_STRVAL);
3052    __pop_xstk();
3053    return;
3054   }
3055 
3056  /* in this case, must put value on tos */
3057  nd_itpop = FALSE;
3058  switch ((byte) ndp->optyp) {
3059   case UNCONNPULL:
3060    /* connection is unconnected but directives causes unc. to be pulled */
3061    /* know width here always exactly port width and stren */
3062    set_byteval_(sbp, ndp->szu.xclen, (ndp->unc_pull == UNCPULL0) ? ST_PULL0
3063     : ST_PULL1);
3064    return;
3065   case GLBREF:
3066    grp = ndp->ru.grp;
3067    __xmrpush_refgrp_to_targ(grp);
3068    nd_itpop = TRUE;
3069    /*FALLTHRU */
3070   case ID:
3071    np = ndp->lu.sy->el.enp;
3072    /* RELEASE remove ---
3073    if (!np->n_stren) __misc_terr(__FILE__, __LINE__);
3074    --- */
3075    /* get strength wire address */
3076    get_stwire_addr_(bp, np);
3077    memcpy(sbp, bp, ndp->szu.xclen);
3078    break;
3079   case LSB:
3080    /* can never be array */
3081    idndp = ndp->lu.x;
3082    np = idndp->lu.sy->el.enp;
3083    /* SJM - 03/26/00 - was setting grp to bsel node not lhs id */
3084    if (idndp->optyp == GLBREF)
3085     { grp = idndp->ru.grp; __xmrpush_refgrp_to_targ(grp); nd_itpop = TRUE; }
3086    access_stbsel(sbp, ndp);
3087    break;
3088   case PARTSEL:
3089    idndp = ndp->lu.x;
3090    np = idndp->lu.sy->el.enp;
3091    /* SJM - 03/26/00 - was setting grp to bsel node not lhs id */
3092    if (idndp->optyp == GLBREF)
3093     { grp = idndp->ru.grp; __xmrpush_refgrp_to_targ(grp); nd_itpop = TRUE; }
3094    access_stpsel(sbp, ndp);
3095    break;
3096   case LCB: rhs_stconcat(sbp, ndp); break;
3097   default: __case_terr(__FILE__, __LINE__);
3098  }
3099  if (nd_itpop) __pop_itstk();
3100 }
3101 
3102 /*
3103  * access a selected bit to sbp (width 1 for bit)
3104  *
3105  * this if for cases where accessing strength and know it is needed and
3106  * know value has strength
3107  */
access_stbsel(register byte * sbp,register struct expr_t * ndp)3108 static void access_stbsel(register byte *sbp, register struct expr_t *ndp)
3109 {
3110  register int32 biti;
3111  register byte *bp;
3112  register struct net_t *np;
3113 
3114  np = ndp->lu.x->lu.sy->el.enp;
3115  biti = __get_const_bselndx(ndp);
3116  /* unknown index is strong x - cannot emit warning happens too often */
3117  /* strong x 6,6,3 - 11011011 */
3118  if (biti == -1) { *sbp = 0xdb; return; }
3119  /* get strength wire address */
3120  get_stwire_addr_(bp, np);
3121  *sbp = bp[biti];
3122 }
3123 
3124 /*
3125  * get a bit select index from an expr. node
3126  * need to be in correct current itree loc.
3127  * only for constant index cases
3128  */
__get_const_bselndx(register struct expr_t * ndp)3129 extern int32 __get_const_bselndx(register struct expr_t *ndp)
3130 {
3131  register int32 biti;
3132  register word32 *wp;
3133 
3134  /* know will either be constant or expr. here */
3135  if (ndp->ru.x->optyp == NUMBER)
3136   {
3137    wp = &(__contab[ndp->ru.x->ru.xvi]);
3138    if (wp[1] != 0) biti = -1; else biti = (int32) wp[0];
3139   }
3140  else if (ndp->ru.x->optyp == ISNUMBER)
3141   {
3142    wp = &(__contab[ndp->ru.x->ru.xvi]);
3143    wp = &(wp[2*__inum]);
3144    if (wp[1] != 0) biti = -1; else biti = (int32) wp[0];
3145   }
3146  else { __case_terr(__FILE__, __LINE__); biti = -1; }
3147  return(biti);
3148 }
3149 
3150 /*
3151  * push (access) a selected range into sbp
3152  * one bit ok but cannot part select from scalar
3153  */
access_stpsel(register byte * sbp,register struct expr_t * ndp)3154 static void access_stpsel(register byte *sbp, register struct expr_t *ndp)
3155 {
3156  register int32 bi2;
3157  register byte *abp;
3158  struct expr_t *idndp, *ndx2;
3159  struct net_t *np;
3160 
3161  /* know these are both constant nodes, in range, and are h:0 normalized */
3162  /* and non IS form */
3163  idndp = ndp->lu.x;
3164  np = idndp->lu.sy->el.enp;
3165  /* notice 2nd range is low */
3166  ndx2 = ndp->ru.x->ru.x;
3167 
3168  /* bi2 cannot be -1 (out of range) or will not get here */
3169  bi2 = (int32) __contab[ndx2->ru.xvi];
3170 
3171  /* get strength wire address */
3172  get_stwire_addr_(abp, np);
3173 
3174  memcpy(sbp, &(abp[bi2]), ndp->szu.xclen);
3175 }
3176 
3177 /*
3178  * evaluate a known strength expr node rhs concatenate
3179  * key is that { op. node width is same as starting high bit of value
3180  *
3181  * notice that subexpressions of strength concat can be non strength
3182  * strength stored low bit (0) to high bit (n)
3183  */
rhs_stconcat(register byte * sbp,struct expr_t * lcbndp)3184 static void rhs_stconcat(register byte *sbp, struct expr_t *lcbndp)
3185 {
3186  register struct expr_t *ndp;
3187  register byte *sbp2;
3188  register int32 i;
3189  register int32 bi2;
3190  struct expr_t *catndp;
3191 
3192  for (ndp = lcbndp->ru.x; ndp != NULL; ndp = ndp->ru.x)
3193   {
3194    catndp = ndp->lu.x;
3195 
3196    /* bi2 is low bit, LCB node xclen start high bit, catndp is id/num width */
3197    bi2 = ndp->szu.xclen - catndp->szu.xclen;
3198    sbp2 = &(sbp[bi2]);
3199    /* here know cat width must match rhs width */
3200    ndst_eval2_xpr(sbp2, catndp);
3201   }
3202  if (__debug_flg && __ev_tracing)
3203   {
3204    __cur_sofs = 0;
3205    for (i = lcbndp->szu.xclen - 1; i >= 0; i--)
3206     {
3207      __adds(__to_vvstnam(__xs, (word32) sbp[i]));
3208      addch_('|');
3209      __exprline[__cur_sofs] = '\0';
3210     }
3211    __tr_msg("++ strength concatenate result: %s\n", __exprline);
3212    __cur_sofs = 0;
3213   }
3214 }
3215 
3216 /*
3217  * store a/b value into strength byte array - set value or in new stregth
3218  * byte order for strength bytes [h:l] just like word32 bits
3219  * notice this needs to be called with blen less that actual stacked blen
3220  * also must and off possibly unused parts
3221  *
3222  * notice z must not have strong added for non strength case
3223  * and need to map to right 0 val/1 val strengths
3224  */
__st_standval(register byte * sbp,register struct xstk_t * xsp,byte new_st)3225 extern void __st_standval(register byte *sbp, register struct xstk_t *xsp,
3226  byte new_st)
3227 {
3228  register int32 bi, aw, bw;
3229 
3230  /* short circuit for 1 bit case */
3231  if (xsp->xslen == 1)
3232   {
3233    aw = (xsp->ap[0] & 1L) | ((xsp->bp[0] << 1) & 2L);
3234    /* if z, no strength */
3235    if (aw == 2) sbp[0] = (byte) aw;
3236    else
3237      {
3238       /* SJM 08/07/01 - need to use stren map table so val 0 has 0 stren etc */
3239       aw |= (new_st << 2);
3240       sbp[0] = __stren_map_tab[aw];
3241      }
3242    return;
3243   }
3244 
3245  for (bi = 0; bi < xsp->xslen; bi++)
3246   {
3247    aw = rhsbsel_(xsp->ap, bi);
3248    bw = rhsbsel_(xsp->bp, bi);
3249    aw |= (bw << 1);
3250    /* if z no strength */
3251    if (aw == 2) sbp[bi] = (byte) aw;
3252    else
3253     {
3254      /* SJM 08/07/01 - need to use stren map table so val 0 has 0 stren etc */
3255      aw |= (new_st << 2);
3256      /* SJM 08/15/01 - this is vector - from typo was only set 0 */
3257      sbp[bi] = __stren_map_tab[aw];
3258     }
3259   }
3260 }
3261 
3262 /*
3263  * pairwise combine driving value into section (or all) of wire
3264  * know abi1 (high) and abi2 (low) already corrected for h:0 form
3265  */
eval_stwire(word32 wtyp,register byte * accsbp,int32 abi1,int32 abi2,register byte * sbp)3266 static void eval_stwire(word32 wtyp, register byte *accsbp,
3267  int32 abi1, int32 abi2, register byte *sbp)
3268 {
3269  register int32 bi, bi2;
3270 
3271  for (bi = abi2, bi2 = 0; bi <= abi1; bi++, bi2++)
3272   accsbp[bi] = (byte) __comb_1bitsts(wtyp, (word32) accsbp[bi], (word32) sbp[bi2]);
3273 }
3274 
3275 /*
3276  * combine into first 2nd 1 bit (byte form) strength value that is not
3277  * wired logic
3278  *
3279  * format [s000,s111,vv] - 3 high bits st 0, 3 middle bits st 1, 2 low val
3280  * convention for non x/z value s0 is highest and s1 is lowest
3281  *
3282  * routine works for everything except trireg - need special "array" for it
3283  * because for tri0/tri1 initialized to state if no drivers
3284  * supply0 nets cannot be effected by driver so just init and return above
3285  *
3286  * notice storing H and L as x value with 1 or other strength 0 - since
3287  * no different from real way where strengths same but value z (2)
3288  *
3289  * LOOKATME - myabe this should use word32 variables
3290  */
__comb_1bitsts(word32 wtyp,register word32 acc,register word32 op)3291 extern word32 __comb_1bitsts(word32 wtyp, register word32 acc, register word32 op)
3292 {
3293  word32 str0acc, str1acc, vacc, str0op, str1op, vop;
3294  word32 s0hop, s0lop, s1hop, s1lop, s0hacc, s0lacc, s1hacc, s1lacc;
3295  word32 s0h, s0l, s1h, s1l, s0, s1;
3296 
3297  /* eliminate either HiZ because HiZ loses to anything */
3298  /* notice H and L cannot be eliminated here */
3299  if (acc == 2)
3300   {
3301    /* DBG remove -- */
3302    if (__debug_flg && __ev_tracing) { vop = op; goto do_outmsg; }
3303    /* --- */
3304    return(op);
3305   }
3306  if (op == 2)
3307   {
3308    /* DBG remove - */
3309    if (__debug_flg && __ev_tracing) { vop = acc; goto do_outmsg; }
3310    /* --- */
3311    return(acc);
3312   }
3313 
3314  /* extract values, */
3315  vacc = acc & 3;
3316  vop = op & 3;
3317  str0acc = (acc >> 5) & 7;
3318  str1acc = (acc >> 2) & 7;
3319  str0op = (op >> 5) & 7;
3320  str1op = (op >> 2) & 7;
3321 
3322  /* handle special cases that are independent of wired logic type */
3323  /* both 1 or both 0 - strength always largest */
3324  if ((vacc == 1 && vop == 1) || (vacc == 0 && vop == 0))
3325   {
3326    /* in case of both strength in 0 or 1 region, 0 st higher than 1 st */
3327    s0 = (str0acc >= str0op) ? str0acc : str0op;
3328    s1 = (str1acc >= str1op) ? str1acc : str1op;
3329    goto done;
3330   }
3331  /* both have fixed strength (<s:s>=? and <t:t>=?) */
3332  /* notice for H and L, strength never same */
3333  if (str0acc == str1acc && str0op == str1op)
3334   {
3335    /* case 1: strengths same - may need wired logic compare */
3336    s0 = s1 = str0acc;
3337    if (str0acc == str0op)
3338     {
3339      switch ((byte) wtyp) {
3340       /* since know differ and know stren same, non wired must be x */
3341       case N_TRI: case N_WIRE: case N_TRI0: case N_TRIREG: case N_TRI1:
3342       /* SJM 11/16/00 - supplies possible here, but how */
3343       case N_SUPPLY0: case N_SUPPLY1:
3344        vacc = 3;
3345        break;
3346       case N_WA: case N_TRIAND:
3347        /* if either 0, result 0, else result X */
3348        if (vacc == 0 || vop == 0) vacc = 0; else vacc = 3;
3349        break;
3350       case N_WO: case N_TRIOR:
3351        /* if either 1, result 1, else result X */
3352        if (vacc == 1 || vop == 1) vacc = 1; else vacc = 3;
3353        break;
3354       default: __case_terr(__FILE__, __LINE__);
3355      }
3356      goto done;
3357     }
3358    /* case 1: strengths differ - value of stronger stren wins */
3359    if (str0acc <= str0op) { s0 = s1 = str0op; vacc = vop; }
3360    goto done;
3361   }
3362 
3363  /* separate into low-high for both 0 and 1 for both operands */
3364  s0hacc = s0lacc = s1hacc = s1lacc = 0;
3365  switch ((byte) vacc) {
3366   case 0: s0hacc = str0acc; s0lacc = str1acc; break;
3367   case 1: s1hacc = str0acc; s1lacc = str1acc; break;
3368   case 3: s0hacc = str0acc; s1hacc = str1acc; break;
3369   default: __case_terr(__FILE__, __LINE__);
3370  }
3371  s0hop = s0lop = s1hop = s1lop = 0;
3372  switch ((byte) vop) {
3373   case 0: s0hop = str0op; s0lop = str1op; break;
3374   case 1: s1hop = str0op; s1lop = str1op; break;
3375   case 3: s0hop = str0op; s1hop = str1op; break;
3376   default: __case_terr(__FILE__, __LINE__);
3377  }
3378  /* tournament 1 - op and acc 0 strengths and 1 strengths */
3379  s0h = (s0hacc >= s0hop) ? s0hacc : s0hop;
3380  s0l = (s0lacc >= s0lop) ? s0lacc : s0lop;
3381  s1h = (s1hacc >= s1hop) ? s1hacc : s1hop;
3382  s1l = (s1lacc >= s1lop) ? s1lacc : s1lop;
3383 
3384  /* tournament 2 - 0 and 1 strengths */
3385  /* if lowest 0 higher than highest 1, remove 1 strengths */
3386  if (s0l > s1h) { s0 = s0h; s1 = s0l; vacc = 0; }
3387  /* if lowest 1 higher than highest 0, remove 0 strengths */
3388  else if (s1l > s0h) { s0 = s1h; s1 = s1l; vacc = 1; }
3389  /* x - strengths in both regions (fill in smaller gap) */
3390  else { s0 = s0h; s1 = s1h; vacc = 3; }
3391 
3392  /* ? believe that for wired logic, if 1 strength range */
3393  /* then value is outer range x - no wired logic here - is it true */
3394 
3395 done:
3396  /* --- DBG remove */
3397  if (__debug_flg && __ev_tracing)
3398   {
3399    char vs1[10], vs2[10], vs3[10];
3400 
3401    vop = (s0 << 5) | (s1 << 2) | vacc;
3402 do_outmsg:
3403    __tr_msg("+> fi>1 strength: %s acc=%s,op=%s,res=%s\n",
3404     __to_wtnam2(__xs, (word32) wtyp), __to_vvstnam(vs1, (word32) acc),
3405     __to_vvstnam(vs2, (word32) op), __to_vvstnam(vs3, (word32) vop));
3406    return(vop);
3407   }
3408 /* --- */
3409  return((s0 << 5) | (s1 << 2) | vacc);
3410 }
3411 
3412 /*
3413  * EXECUTION OUTPUT ROUTINES INCLUDING SHOWVARS (NEEDS EXEC VALUES)
3414  */
3415 
3416 /*
3417  * build the state of a gate into string
3418  * can only be called during exec when current inst. on itstk
3419  * caller must do any needed truncating
3420  *
3421  * handles strengths and bufif and mos style gates
3422  * all values extracted from gate state
3423  */
__gstate_tostr(char * s,struct gate_t * gp,int32 fullpath)3424 extern char *__gstate_tostr(char *s, struct gate_t *gp, int32 fullpath)
3425 {
3426  int32 srep, pi, nins, sav_sofs, conducting;
3427  word32 tmp, tmp2, uwrd, av, bv;
3428  i_tev_ndx tevpi;
3429  struct xstk_t *xsp;
3430  struct udp_t *udpp;
3431  char s1[RECLEN], s2[10], s3[10], s4[10];
3432 
3433  sav_sofs = __cur_sofs;
3434  __adds(gp->gmsym->synam);
3435 
3436  addch_(' ');
3437  if (fullpath)
3438   {
3439    __disp_itree_path(__inst_ptr, (struct task_t *) NULL);
3440    addch_('.');
3441   }
3442  __adds(gp->gsym->synam);
3443  addch_('(');
3444 
3445  nins = gp->gpnum - 1;
3446  switch ((byte) gp->g_class) {
3447   case GC_LOGIC:
3448    if (gp->gpnum > 16) srep = SR_VEC; else srep = SR_PVEC;
3449    push_xstk_(xsp, nins + 1);
3450    if (srep == SR_VEC)
3451     {
3452      __ld_gate_wide_val(xsp->ap, xsp->bp, gp->gstate.wp, nins + 1);
3453      /* SJM 11/26/00 - need to select from multi-word32 xsp if wider than 16 */
3454      /* put output value in tmp - since low bit is 0 right index is nins **/
3455      tmp = rhsbsel_(xsp->ap, nins);
3456      tmp2 = rhsbsel_(xsp->bp, nins);
3457      tmp |= (tmp2 << 1);
3458      __adds(__to_vvnam(s1, tmp));
3459      adds_evgate_ins(xsp->ap, xsp->bp, nins);
3460     }
3461    else
3462     {
3463      /* extract current output value */
3464      uwrd = get_packintowrd_(gp->gstate, __inum, nins + 1);
3465      tmp = ((uwrd >> nins) & 1L) | ((uwrd >> (2*nins)) & 2L);
3466      __adds(__to_vvnam(s1, tmp));
3467      av = uwrd & __masktab[nins + 1];
3468      bv = uwrd >> (nins + 1);
3469      adds_evgate_ins(&av, &bv, nins);
3470     }
3471    addch_(')');
3472    __pop_xstk();
3473    break;
3474   case GC_UDP:
3475    udpp = gp->gmsym->el.eudpp;
3476    nins = udpp->numins;
3477    if (udpp->u_wide) uwrd = gp->gstate.wp[2*__inum];
3478    else uwrd = (word32) gp->gstate.hwp[__inum];
3479    tmp = (uwrd >> (2*nins)) & 3L;
3480    /* DBG remove ---
3481    if (tmp == 2) __misc_terr(__FILE__, __LINE__);
3482    --- */
3483    __adds(__to_vvnam(s1, tmp));
3484    for (pi = 0; pi < nins; pi++)
3485     {
3486      __adds(", ");
3487      tmp = (uwrd >> (2*pi)) & 3L;
3488      /* DBG remove ---
3489      if (tmp == 2) __misc_terr(__FILE__, __LINE__);
3490      --- */
3491      __adds( __to_vvnam(s1, tmp));
3492     }
3493    addch_(')');
3494    /* --- RELEASE REMOVE ---
3495    if (udpp->u_wide)
3496     {
3497      tmp = gp->gstate.wp[2*__inum + 1];
3498      sprintf(s1, "<%lu>", tmp);
3499      __adds(s1);
3500     }
3501    --- */
3502    break;
3503   case GC_BUFIF:
3504    uwrd = (word32) gp->gstate.hwp[__inum];
3505    __adds(__to_vvstnam(s1, (uwrd >> 4) & 0xffL));
3506    __adds(", ");
3507    __adds(__to_vvnam(s2, (uwrd & 0x3L)));
3508    __adds(", ");
3509    __adds(__to_vvnam(s3, (uwrd >> 2) & 3L));
3510    addch_(')');
3511    break;
3512   case GC_MOS:
3513    /* notice packing bit ranges for mos and bufif different */
3514    uwrd = gp->gstate.wp[__inum];
3515    __adds(__to_vvstnam(s1, ((uwrd >> 16) & 0xffL)));
3516    __adds(", ");
3517    __adds(__to_vvstnam(s2, (uwrd & 0xffL)));
3518    __adds(", ");
3519    __adds(__to_vvnam(s3, ((uwrd >> 8) & 0x3L)));
3520    addch_(')');
3521    break;
3522   case GC_CMOS:
3523    uwrd = gp->gstate.wp[__inum];
3524    __adds(__to_vvstnam(s1, ((uwrd >> 24) & 0xffL)));
3525    __adds(", ");
3526    __adds(__to_vvstnam(s2, (uwrd & 0xffL)));
3527    __adds(", ");
3528    __adds(__to_vvnam(s3, ((uwrd >> 8) & 0x3L)));
3529    __adds(", ");
3530    __adds(__to_vvnam(s4, ((uwrd >> 16) & 0x3L)));
3531    addch_(')');
3532    break;
3533   case GC_TRANIF:
3534    /* only called for tranif input gate */
3535    conducting = get_tranif_onoff_(gp);
3536    if (conducting == 1) __adds("**ON**)");
3537    else if (conducting == 0) __adds("**OFF**)");
3538    else __adds("**UNKNOWN**)");
3539    break;
3540   default: __case_terr(__FILE__, __LINE__);
3541  }
3542  /* if pending event, write it */
3543  if (gp->schd_tevs != NULL
3544   && (tevpi = gp->schd_tevs[__inum]) != -1)
3545   { __bld_valofsched(s1, &(__tevtab[tevpi])); __adds(s1); }
3546  __exprline[__cur_sofs] = '\0';
3547 
3548  /* finally truncate suffix */
3549  __trunc_cstr(&(__exprline[sav_sofs]), MSGTRUNCLEN, FALSE);
3550  strcpy(s, &(__exprline[sav_sofs]));
3551  __cur_sofs = sav_sofs;
3552  __exprline[__cur_sofs] = '\0';
3553  return(s);
3554 }
3555 
3556 /*
3557  * write gate inputs - only for normal logic gates
3558  * notice ports are numbered 0 (output) to gpnum (rightmost input)
3559  * but storage is inputs bit 0 to gpnum and output in gpnum (sep. a and b)
3560  */
adds_evgate_ins(word32 * gatap,word32 * gatbp,int32 nins)3561 static void adds_evgate_ins(word32 *gatap, word32 *gatbp, int32 nins)
3562 {
3563  register int32 bi;
3564  word32 tmp, tmp2;
3565  char s1[RECLEN];
3566 
3567  for (bi = 0; bi < nins; bi++)
3568   {
3569    tmp = rhsbsel_(gatap, bi);
3570    tmp2 = rhsbsel_(gatbp, bi);
3571    tmp |= (tmp2 << 1);
3572    __adds(", ");
3573    __adds(__to_vvnam(s1, tmp));
3574   }
3575 }
3576 
3577 /*
3578  * SIMULATION TIME DUMP (SHOWVARS) ROUTINES
3579  */
3580 
3581 /*
3582  * dump all variables in a design
3583  * this can only be called after prep done
3584  */
__show_allvars(void)3585 extern void __show_allvars(void)
3586 {
3587  register int32 ii;
3588  struct itree_t *itp;
3589 
3590  for (ii = 0; ii < __numtopm; ii++)
3591   { itp = __it_roots[ii]; show2_allvars(itp); }
3592  __cvsim_msg("\n");
3593 }
3594 
3595 /*
3596  * convert global for module whose type corresponds to itree itp
3597  */
show2_allvars(struct itree_t * itp)3598 static void show2_allvars(struct itree_t *itp)
3599 {
3600  register int32 ii;
3601  register struct net_t *np;
3602  struct mod_t *imdp;
3603  struct itree_t *itp2;
3604 
3605  imdp = itp->itip->imsym->el.emdp;
3606  __cvsim_msg("==> showing all variables in %s type %s.\n",
3607   __msg2_blditree(__xs, itp), imdp->msym->synam);
3608 
3609  /* notice using ii as ni here */
3610  if (imdp->mnnum != 0)
3611   {
3612    for (ii = 0, np = &(imdp->mnets[0]); ii < imdp->mnnum; ii++, np++)
3613     { __push_itstk(itp); __emit_1showvar(np, NULL); __pop_itstk(); }
3614   }
3615  for (ii = 0; ii < imdp->minum; ii++)
3616   { itp2 = &(itp->in_its[ii]); show2_allvars(itp2); }
3617 }
3618 
3619 /*
3620  * show variable prefix from current itp instance
3621  * assumes scope location already emitted
3622  *
3623  * expects __stlevel to be set to 0 here
3624  * this must happen after all processing within one time unit
3625  * itree must be on top of stack to call this
3626  */
__emit_1showvar(struct net_t * np,struct gref_t * grp)3627 extern void __emit_1showvar(struct net_t *np, struct gref_t *grp)
3628 {
3629  register int32 i, bi;
3630  register struct net_pin_t *npp;
3631  int32 arrwid, obwid;
3632  i_tev_ndx tevpi, *teviarr;
3633  char s1[RECLEN], s2[RECLEN];
3634 
3635  /* for parameters (still in symb. table but replace) no showvars */
3636  if (np->n_isaparam) return;
3637 
3638  __cur_sofs = 0;
3639  /* emit the variable information prefix */
3640  __bld_showvars_prefix(s1, np, grp);
3641 
3642  if (np->ntyp == N_EVENT)
3643   { __cvsim_msg("%s **event**\n", s1); goto disp_drvs; }
3644 
3645  /* emit the current value of entire variable */
3646  /* for array print the first 4 */
3647  if (np->n_isarr)
3648   {
3649    __adds(" [");
3650    arrwid = __get_arrwide(np);
3651    /* this should be setable in the debugger by the user */
3652    if (arrwid > 4) obwid = 4; else obwid = arrwid;
3653    for (i = 0; i < obwid; i++)
3654     {
3655      if (i != 0) __adds(", ");
3656      __var_tostr(s2, np, i, i, BBIN);
3657      __adds(s2);
3658     }
3659    if (arrwid > obwid)
3660     { sprintf(__xs, ", ... <%d more>", arrwid - obwid); __adds(__xs); }
3661    __adds("]");
3662   }
3663  /* emit variable current value - also handles strength variables */
3664  /* LOOKATME - this should use base from net or at least give base */
3665  else __disp_var(np, -1, -1, BHEX, '?');
3666  __cvsim_msg("%s = %s\n", s1, __exprline);
3667  __cur_sofs = 0;
3668 
3669  /* if wire has delay or path dest., there may be a scheduled value */
3670  if (np->nrngrep == NX_DWIR)
3671   {
3672    /* access per bit array of possibly scheduled values for wire */
3673    /* pointer to array element that is first bit of current inst. */
3674    teviarr = &(np->nu.rngdwir->wschd_pbtevs[np->nwid*__inum]);
3675    if (np->n_isavec)
3676     {
3677      __cvsim_msg("   Per bit wire with delay scheduled values:\n");
3678      for (bi = np->nwid - 1; bi >= 0; bi--)
3679       {
3680        if ((tevpi = teviarr[bi]) != -1)
3681         {
3682          /* form: [i] (schedule %s at %s) */
3683          __cvsim_msg("    [%d] %s\n", __unnormalize_ndx(np, bi),
3684           __bld_valofsched(s1, &(__tevtab[tevpi])));
3685         }
3686       }
3687     }
3688    else if ((tevpi = teviarr[0]) != -1)
3689     {
3690     __cvsim_msg("scalar wire scheduled %s\n",
3691       __bld_valofsched(s1, &(__tevtab[tevpi])));
3692     }
3693   }
3694 
3695  /* emit drivers - regs never have drivers but can have loads */
3696 disp_drvs:
3697  /* here no filter for rooted xmr since one inst is driver */
3698  for (npp = np->ndrvs; npp != NULL; npp = npp->npnxt)
3699   emit1_driver(np, npp, FALSE);
3700  /* emit loads - no inst. filter for rooted xmr npp */
3701  for (npp = np->nlds; npp != NULL; npp = npp->npnxt) emit1_load(np, npp);
3702  __cur_sofs = 0;
3703 }
3704 
3705 /*
3706  * emit a driver string - if nonz_only only emit non floating drivers
3707  *
3708  * only for use at end of time unit
3709  * when called itree location is wire from which npp driver connected to
3710  * notice np tchg can never be a driver
3711  */
emit1_driver(struct net_t * np,struct net_pin_t * npp,int32 nonz_only)3712 static void emit1_driver(struct net_t *np, struct net_pin_t *npp,
3713  int32 nonz_only)
3714 {
3715  int32 i1, i2, obwid, ri1, ri2, nd_itpop;
3716  i_tev_ndx tevpi;
3717  word32 wrd;
3718  byte *sbp;
3719  struct gate_t *gp;
3720  struct conta_t *cap, *cap2;
3721  struct xstk_t *xsp;
3722  struct itree_t *dritp;
3723  struct inst_t *ip;
3724  struct mod_t *mdp;
3725  struct mod_pin_t *mpp;
3726  struct npaux_t *npauxp;
3727  struct tfrec_t *tfrp;
3728  struct tfarg_t *tfap;
3729  char ndxs[RECLEN], s1[RECLEN], s2[RECLEN], s3[RECLEN];
3730 
3731  /* think sbp and xsp always set here - lint warning from  if separation */
3732  sbp = NULL;
3733  xsp = NULL;
3734  ri1 = ri2 = -1;
3735  /* this is needed to get this instances pattern for IS form */
3736 
3737  if ((npauxp = npp->npaux) == NULL) i1 = i2 = -1;
3738  else __get_cor_range(npauxp->nbi1, npauxp->nbi2, &i1, &i2);
3739  /* also need to print lhs select range but leave rhs width as is */
3740  /* assignment will widen or truncate if needed but driver is rhs */
3741  if (i1 != -1)
3742   {
3743    /* need range of array for umapping index for message */
3744    if (np->n_isarr) __getarr_range(np, &ri1, &ri2, &obwid);
3745    else if (np->n_isavec) __getwir_range(np, &ri1, &ri2);
3746    else __arg_terr(__FILE__, __LINE__);
3747    if (i1 == i2) sprintf(ndxs, " [%d]", __unmap_ndx(i1, ri1, ri2));
3748    else sprintf(ndxs, " [%d:%d]", __unmap_ndx(i1, ri1, ri2),
3749    __unmap_ndx(i2, ri1, ri2));
3750   }
3751  else strcpy(ndxs, "");
3752 
3753  /* this traces from target (where var. is) back to ref. itree loc. */
3754  if (npp->npproctyp != NP_PROC_INMOD)
3755   {
3756    /* SJM 04/17/03 - if XMR does not match - do not combine in */
3757    if (!__move_to_npprefloc(npp)) return;
3758    nd_itpop = TRUE;
3759   }
3760  else nd_itpop = FALSE;
3761 
3762  /* special handling for getpattern on rhs */
3763  if (npp->npntyp == NP_CONTA)
3764   {
3765    cap = npp->elnpp.ecap;
3766    if (cap->lhsx->getpatlhs)
3767     {
3768      __cvsim_msg("%s   driver: continuous assign of $getpattern to %s\n",
3769       ndxs, __msgexpr_tostr(__xs, cap->lhsx));
3770      if (nd_itpop) __pop_itstk();
3771      return;
3772     }
3773   }
3774 
3775  /* here for inouts (up iconn and down mdprt) and trans need driver value */
3776  /* notice this insure that returned xsp never nil */
3777  switch ((byte) npp->npntyp) {
3778   case NP_GATE:
3779    /* current value of gate is state output - next value is event state */
3780    /* if driver (gate output) wide just accesses low bit here */
3781    gp = npp->elnpp.egp;
3782    /* get driving value */
3783    if (np->n_stren)
3784     {
3785      xsp = ld_stgate_driver(npp);
3786      sbp = (byte *) xsp->ap;
3787      /* high impedance z will always have z value and 0 strengths */
3788      if (nonz_only && sbp[0] == 2) break;
3789      __to_vvstnam(s1, (word32) sbp[0]);
3790     }
3791    else
3792     {
3793      xsp = __ld_gate_driver(npp);
3794      wrd = xsp->ap[0] | (xsp->bp[0] << 1);
3795      if (nonz_only && wrd == 2L) break;
3796      __to_vvnam(s1, wrd);
3797     }
3798    if (gp->g_class == GC_UDP)
3799     sprintf(s2, "%s udp %s", __schop(__xs, gp->gmsym->synam),
3800     __schop(__xs2, gp->gsym->synam));
3801    else
3802     {
3803      if (gp->gmsym->el.eprimp->gateid == G_ASSIGN)
3804       strcpy(s2,  "1 bit continuous assign");
3805      else sprintf(s2, "%s gate %s", __schop(__xs, gp->gmsym->synam),
3806       __schop(__xs2, gp->gsym->synam));
3807     }
3808    if (gp->schd_tevs != NULL &&
3809     (tevpi = gp->schd_tevs[__inum]) != -1)
3810     __bld_valofsched(s3, &(__tevtab[tevpi]));
3811    else strcpy(s3, "");
3812 
3813    __cvsim_msg("%s   driver: %s (port %d) at %s = %s%s\n", ndxs, s2,
3814     npp->obnum + 1, __bld_lineloc(__xs, gp->gsym->syfnam_ind,
3815     gp->gsym->sylin_cnt), s1, s3);
3816    break;
3817   case NP_CONTA:
3818    /* value for driver that is cont. assign is: 1) ca driver wp per inst if */
3819    /* set, 2) ca_rhsval if for 0 delay case, else evaled lhs if fi == 1 */
3820    cap = npp->elnpp.ecap;
3821    if (cap->ca_pb_sim) cap2 = &(cap->pbcau.pbcaps[npp->pbi]);
3822    else cap2 = cap;
3823    if (np->n_stren)
3824     {
3825      xsp = ld_stconta_driver(npp);
3826      sbp = (byte *) xsp->ap;
3827      /* this returns NULL on all drivers z if nonz only on */
3828      /* SJM 11/13/00 - must use lhs width here in rhs wider truncated */
3829      if (stdrive_tostr(s1, sbp, npp, cap2->lhsx->szu.xclen, nonz_only)
3830       == NULL) break;
3831     }
3832    else
3833     {
3834      xsp = __ld_conta_driver(npp);
3835      if (drive_tostr(s1, xsp->ap, xsp->bp, npp, cap2->rhsx->szu.xclen,
3836       nonz_only) == NULL) break;
3837     }
3838    if (cap2->caschd_tevs != NULL && (tevpi = cap2->caschd_tevs[__inum]) != -1)
3839      __bld_valofsched(s2, &(__tevtab[tevpi]));
3840    else strcpy(s2, "");
3841 
3842    if (cap->ca_pb_sim)
3843     {
3844      __cvsim_msg("%s   driver: continuous assign to %s per bit %d at %s = %s%s\n",
3845       ndxs, __msgexpr_tostr(__xs, cap2->lhsx), npp->pbi,
3846       __bld_lineloc(__xs2, cap->casym->syfnam_ind, cap->casym->sylin_cnt),
3847       s1, s2);
3848     }
3849    else
3850     {
3851      __cvsim_msg("%s   driver: continuous assign to %s at %s = %s%s\n",
3852       ndxs, __msgexpr_tostr(__xs, cap->lhsx),
3853       __bld_lineloc(__xs2, cap->casym->syfnam_ind, cap->casym->sylin_cnt),
3854       s1, s2);
3855     }
3856    break;
3857   case NP_TFRWARG:
3858    tfrp = npp->elnpp.etfrp;
3859    tfap = &(tfrp->tfargs[npp->obnum]);
3860    if (np->n_stren)
3861     {
3862      xsp = __ld_sttfrwarg_driver(npp);
3863      sbp = (byte *) xsp->ap;
3864      /* this returns NULL on all drivers z if nonz only on */
3865      if (stdrive_tostr(s1, sbp, npp, tfap->arg.axp->szu.xclen, nonz_only)
3866       == NULL) break;
3867     }
3868    else
3869     {
3870      xsp = __ld_tfrwarg_driver(npp);
3871      if (drive_tostr(s1, xsp->ap, xsp->bp, npp, tfap->arg.axp->szu.xclen,
3872       nonz_only) == NULL) break;
3873     }
3874    __cvsim_msg("%s   driver: tf_ call of %s arg %s (pos. %d) at %s = %s\n",
3875     ndxs, __get_tfcellnam(tfrp), __msgexpr_tostr(__xs, tfap->arg.axp), npp->obnum,
3876     __bld_lineloc(__xs2, tfrp->tffnam_ind, tfrp->tflin_cnt), s1);
3877    break;
3878   case NP_VPIPUTV:
3879    /* DBG remove -- */
3880    if (npp->elnpp.enp != np) __arg_terr(__FILE__, __LINE__);
3881    /* --- */
3882    /* if this instance does not have driver, do not emit */
3883    if (!__has_vpi_driver(np, npp))
3884     {
3885      if (nd_itpop) __pop_itstk();
3886      return;
3887     }
3888 
3889    if (np->n_stren)
3890     {
3891      xsp = ld_stvpiputv_driver(npp);
3892      sbp = (byte *) xsp->ap;
3893      /* this returns NULL on all drivers z if nonz only on */
3894      if (stdrive_tostr(s1, sbp, npp, np->nwid, nonz_only) == NULL) break;
3895     }
3896    else
3897     {
3898      xsp = __ld_vpiputv_driver(npp);
3899      if (drive_tostr(s1, xsp->ap, xsp->bp, npp, np->nwid, nonz_only) == NULL)
3900       break;
3901     }
3902    __cvsim_msg("%s   driver: vpi_put_value driving %s %s = %s\n", ndxs,
3903     np->nsym->synam, __to_wtnam(__xs2, np), s1);
3904    break;
3905   case NP_ICONN:
3906    /* called from up itree loc. */
3907    dritp = &(__inst_ptr->in_its[npp->elnpp.eii]);
3908    ip = dritp->itip;
3909    /* need to make sure driver is loaded - no concept of changing one here */
3910    if (np->n_stren)
3911     {
3912      xsp = ld_sticonn_up_driver(npp);
3913      sbp = (byte *) xsp->ap;
3914      /* this returns NULL on all drivers z if nonz only on */
3915      if (stdrive_tostr(s1, sbp, npp, xsp->xslen/4, nonz_only) == NULL) break;
3916     }
3917    else
3918     {
3919      xsp = __ld_iconn_up_driver(npp);
3920      if (drive_tostr(s1, xsp->ap, xsp->bp, npp, xsp->xslen, nonz_only)
3921       == NULL) break;
3922     }
3923    __cvsim_msg("%s   driver: instance %s port %s at %s = %s\n",
3924     ndxs, ip->isym->synam, np->nsym->synam, __bld_lineloc(__xs,
3925     ip->isym->syfnam_ind, ip->isym->sylin_cnt), s1);
3926    break;
3927   case NP_PB_ICONN:
3928    /* called from up itree loc. */
3929    dritp = &(__inst_ptr->in_its[npp->elnpp.eii]);
3930    ip = dritp->itip;
3931    /* need to make sure driver is loaded - no concept of changing one here */
3932    if (np->n_stren)
3933     {
3934      xsp = ld_pb_sticonn_up_driver(npp);
3935      sbp = (byte *) xsp->ap;
3936      /* this returns NULL on all drivers z if nonz only on */
3937      if (stdrive_tostr(s1, sbp, npp, xsp->xslen/4, nonz_only) == NULL) break;
3938     }
3939    else
3940     {
3941      xsp = __ld_pb_iconn_up_driver(npp);
3942      if (drive_tostr(s1, xsp->ap, xsp->bp, npp, xsp->xslen, nonz_only)
3943       == NULL) break;
3944     }
3945    __cvsim_msg("%s   driver: instance %s port %s bit %d at %s = %s\n",
3946     ndxs, ip->isym->synam, np->nsym->synam, npp->pbi, __bld_lineloc(__xs,
3947     ip->isym->syfnam_ind, ip->isym->sylin_cnt), s1);
3948    break;
3949   case NP_MDPRT:
3950    /* called from down mod port itree loc. */
3951    mdp = npp->elnpp.emdp;
3952    mpp = &(mdp->mpins[npp->obnum]);
3953    if (np->n_stren)
3954     {
3955      xsp = ld_stmodport_down_driver(npp);
3956      sbp = (byte *) xsp->ap;
3957      /* this returns NULL on all drivers z if nonz only on */
3958      if (stdrive_tostr(s1, sbp, npp, xsp->xslen/4, nonz_only) == NULL)
3959       break;
3960     }
3961    else
3962     {
3963      xsp = __ld_modport_down_driver(npp);
3964      if (drive_tostr(s1, xsp->ap, xsp->bp, npp, xsp->xslen, nonz_only)
3965       == NULL) break;
3966     }
3967    __cvsim_msg("%s   driver: module %s port %s at %s = %s\n",
3968     ndxs, mdp->msym->synam, np->nsym->synam, __bld_lineloc(__xs,
3969     mpp->mpfnam_ind, mpp->mplin_cnt), s1);
3970    break;
3971   case NP_PB_MDPRT:
3972    /* called from down mod port itree loc. */
3973    mdp = npp->elnpp.emdp;
3974    mpp = &(mdp->mpins[npp->obnum]);
3975    mpp = &(mpp->pbmpps[npp->pbi]);
3976    if (np->n_stren)
3977     {
3978      xsp = ld_pb_stmodport_down_driver(npp);
3979      sbp = (byte *) xsp->ap;
3980      /* this returns NULL on all drivers z if nonz only on */
3981      if (stdrive_tostr(s1, sbp, npp, xsp->xslen/4, nonz_only) == NULL)
3982       break;
3983     }
3984    else
3985     {
3986      xsp = __ld_pb_modport_down_driver(npp);
3987      if (drive_tostr(s1, xsp->ap, xsp->bp, npp, xsp->xslen, nonz_only)
3988       == NULL) break;
3989     }
3990    __cvsim_msg("%s   driver: module %s port %s bit %d at %s = %s\n",
3991     ndxs, mdp->msym->synam, np->nsym->synam, npp->pbi, __bld_lineloc(__xs,
3992     mpp->mpfnam_ind, mpp->mplin_cnt), s1);
3993    break;
3994   case NP_PULL:
3995    /* notice do not need to call ld_pull stren - fixed so get from gstate */
3996    gp = npp->elnpp.egp;
3997    __cvsim_msg("%s   driver: pull to %s at %s of %s\n",
3998     ndxs, __to_vvstnam(s1, (word32) ((gp->g_stval << 2) | npp->pullval)),
3999     __bld_lineloc(__xs, gp->gsym->syfnam_ind, gp->gsym->sylin_cnt),
4000     __msgexpr_tostr(__xs2, gp->gpins[npp->obnum]));
4001    if (nd_itpop) __pop_itstk();
4002    return;
4003   default: __case_terr(__FILE__, __LINE__); return;
4004  }
4005  __pop_xstk();
4006  if (nd_itpop) __pop_itstk();
4007 }
4008 
4009 /*
4010  * convert driver to string with non z only processing
4011  * ap and bp rhs conta expr.
4012  * rhs is driver of entire conta which is right unless lhs is
4013  * concat, if so lcb i1 used to select part driving this net
4014  *
4015  * notice truncating this then truncating entire drive message
4016  */
drive_tostr(char * s,word32 * ap,word32 * bp,struct net_pin_t * npp,int32 rhswid,int32 nonz_only)4017 static char *drive_tostr(char *s, word32 *ap, word32 *bp, struct net_pin_t *npp,
4018  int32 rhswid, int32 nonz_only)
4019 {
4020  int32 nd_xpop;
4021  int32 wlen, ubits;
4022  struct xstk_t *tmpxsp;
4023  struct npaux_t *npauxp;
4024 
4025  nd_xpop = FALSE;
4026  /* if lhs is concatenate, must isolate part dirving this npp wire section */
4027  if ((npauxp = npp->npaux) != NULL && npauxp->lcbi1 != -1)
4028   {
4029    rhswid = npauxp->lcbi1 - npauxp->lcbi2 + 1;
4030    if (npauxp->lcbi2 != 0)
4031     {
4032      push_xstk_(tmpxsp, rhswid);
4033      __rhspsel(tmpxsp->ap, ap, npauxp->lcbi2, rhswid);
4034      __rhspsel(tmpxsp->bp, bp, npauxp->lcbi2, rhswid);
4035      nd_xpop = TRUE;
4036      ap = tmpxsp->ap;
4037      bp = tmpxsp->bp;
4038     }
4039    else
4040     {
4041      /* conta lhs concatenate section starts at low bit */
4042      wlen = wlen_(rhswid);
4043      if ((ubits = ubits_(rhswid)) != 0)
4044       { ap[wlen - 1] &= __masktab[ubits]; bp[wlen - 1] &= __masktab[ubits]; }
4045     }
4046   }
4047  /* notice all z test after selection of actual bits that drive this net */
4048  if (nonz_only && !__vval_isallzs(ap, bp, rhswid)) return(FALSE);
4049 
4050  __regab_tostr(s, ap, bp, rhswid, BBIN, FALSE);
4051  if (nd_xpop) __pop_xstk();
4052  return(s);
4053 }
4054 
4055 /*
4056  * copy a strength driving expr. value to a string with select if lhs concat
4057  */
stdrive_tostr(char * s,byte * sbp,struct net_pin_t * npp,int32 rhswid,int32 nonz_only)4058 static char *stdrive_tostr(char *s, byte *sbp, struct net_pin_t *npp,
4059  int32 rhswid, int32 nonz_only)
4060 {
4061  struct npaux_t *npauxp;
4062 
4063  /* if conta has lhs concat, only emit bits that drive this wire */
4064  /* know form here always internal h:l */
4065  if ((npauxp = npp->npaux) != NULL && npauxp->lcbi1 != -1)
4066   {
4067    sbp = &(sbp[npauxp->lcbi2]);
4068    rhswid = npauxp->lcbi1 - npauxp->lcbi2 + 1;
4069   }
4070  /* notice all z test after selection of actual bits that drive this net */
4071  if (nonz_only && !__st_vval_isallzs(sbp, rhswid)) return(NULL);
4072  __st_regab_tostr(s, sbp, rhswid);
4073  return(s);
4074 }
4075 
4076 /*
4077  * for message build event value and time in passed string
4078  *
4079  * notice cannot use __xs strings here since caller will pass as s
4080  * this must only be called if there is a scheduled value
4081  */
__bld_valofsched(char * s,struct tev_t * tevp)4082 extern char *__bld_valofsched(char *s, struct tev_t *tevp)
4083 {
4084  word32 outv;
4085  int32 blen;
4086  byte *sbp;
4087  struct gate_t *gp;
4088  struct conta_t *cap;
4089  struct tenp_t *tenp;
4090  struct xstk_t *xsp, *xsp2;
4091  char s1[RECLEN], s2[RECLEN];
4092 
4093  switch ((byte) tevp->tetyp) {
4094   case TE_G:
4095    gp = tevp->tu.tegp;
4096    outv = tevp->outv;
4097    /* only input TRANIF separate gate can have delay */
4098    if (gp->g_class == GC_TRANIF)
4099     {
4100      if (gp->gpnum != 1) __case_terr(__FILE__, __LINE__);
4101      if (tevp->outv == 0) strcpy(s1, "**OFF**");
4102      else if (tevp->outv == 1) strcpy(s1, "**ON**");
4103      else strcpy(s1, "**UNKNOWN**");
4104      break;
4105     }
4106    if (gp->g_hasst) __to_vvstnam(s1, outv);
4107    else __to_vvnam(s1, outv);
4108    break;
4109   case TE_CA:
4110    /* SJM 09/28/02 - this is passed the per bit conta indexed above */
4111    cap = tevp->tu.tecap;
4112    /* first access the rhs value - that is thing scheduled to change to */
4113    /* if rhs changed, previous scheduled replaced with new */
4114    /* if delay and multi-fi know schedule will exist */
4115    blen = cap->lhsx->szu.xclen;
4116    push_xstk_(xsp, blen);
4117    /* FIXME - think this should not be called from lhs itree loc. for xmr */
4118    __ld_perinst_val(xsp->ap, xsp->bp, cap->schd_drv_wp, blen);
4119    if (cap->ca_hasst)
4120     {
4121      push_xstk_(xsp2, 4*blen);
4122      sbp = (byte *) xsp2->ap;
4123      /* since rhs eval or saved, never stored with strength - must add here */
4124      /* conta may drive strength but any input strengths removed */
4125      __st_standval(sbp, xsp, cap->ca_stval);
4126      __st_regab_tostr(s1, sbp, blen);
4127      __pop_xstk();
4128     }
4129    else __regab_tostr(s1, xsp->ap, xsp->bp, blen, BBIN, FALSE);
4130    __pop_xstk();
4131    break;
4132   case TE_WIRE: case TE_BIDPATH:
4133    tenp = tevp->tu.tenp;
4134    outv = tevp->outv;
4135    if (tenp->tenu.np->n_stren) __to_vvstnam(s1, outv);
4136    else __to_vvnam(s1, outv);
4137    break;
4138   case TE_MIPD_NCHG:
4139    strcpy(s1, "*NONE*");
4140    break;
4141   default: __case_terr(__FILE__, __LINE__);
4142  }
4143  sprintf(s, "(scheduled %s at %s)", s1, __to_timstr(s2, &(tevp->etime)));
4144  return(s);
4145 }
4146 
4147 /*
4148  * emit the showvars variable information prefix
4149  */
__bld_showvars_prefix(char * s,struct net_t * np,struct gref_t * grp)4150 extern char *__bld_showvars_prefix(char *s, struct net_t *np,
4151  struct gref_t *grp)
4152 {
4153  char s1[RECLEN], s2[RECLEN], s3[RECLEN], s4[RECLEN], s5[RECLEN];
4154 
4155  /* always emit prefix info */
4156  if (np->iotyp != NON_IO) sprintf(s1, " %s", __to_ptnam(s3, np->iotyp));
4157  else strcpy(s1, "");
4158  if (np->n_isavec && np->ntyp != N_INT && np->ntyp != N_TIME
4159   && np->ntyp != N_REAL) sprintf(s2, " %s", __to_wrange(s3, np));
4160  else strcpy(s2, "");
4161  if (np->n_isarr) sprintf(s4, __to_arr_range(s3, np)); else strcpy(s4, "");
4162 
4163  /* if xmr form must emit path given as arg */
4164  if (grp == NULL) __schop(s3, np->nsym->synam); else __schop(s3, grp->gnam);
4165  sprintf(s, "%s%s %s%s %s", s1, s2, s3, s4, bld_wire_telltale(s5, np));
4166  return(s);
4167 }
4168 
4169 /*
4170  * build special flag tell-tale
4171  * know NX_CT gone after prep before this called
4172  */
bld_wire_telltale(char * s,struct net_t * np)4173 static char *bld_wire_telltale(char *s, struct net_t *np)
4174 {
4175  char s1[RECLEN], s2[RECLEN];
4176  struct xstk_t *xsp;
4177 
4178  sprintf(s, "<%s", __to_wtnam(s1, np));
4179  if (np->n_signed) strcat(s, " signed");
4180  if (np->n_isavec && !np->vec_scalared) strcat(s, " vectored");
4181  if (np->nrngrep == NX_DWIR)
4182   {
4183    if (np->nu.rngdwir->n_delrep == DT_PTHDST) strcat(s, " path dest.");
4184    else strcat(s, " delay");
4185   }
4186  if (np->n_isapthsrc) strcat(s, " path src.");
4187  if (np->n_stren) strcat(s, " strength");
4188  if (np->n_capsiz != CAP_NONE)
4189   {
4190    sprintf(s1, " %s capacitor", __to1_stren_nam(s2,
4191     __fr_cap_size((int32) np->n_capsiz), 0));
4192    strcat(s, s1);
4193   }
4194  if (np->n_multfi) strcat(s, " multi-fi");
4195  if (np->ntraux != NULL) strcat(s, " in tran channel");
4196  if (np->nlds != NULL) strcat(s, " fo");
4197  if (np->n_hasdvars) strcat(s, " dumpvar");
4198  /* SJM 07/19/02 - if all off no events */
4199  if (np->dcelst != NULL && __cnt_dcelstels(np->dcelst) > 0)
4200   strcat(s, " evnts");
4201  if (np->n_gone) strcat(s, " disconnected");
4202  if (np->frc_assgn_allocated)
4203   {
4204    if (np->ntyp >= NONWIRE_ST)
4205     {
4206      if (np->nu2.qcval[2*__inum].qc_active) strcat(s, " forced");
4207      else if (np->nu2.qcval[2*__inum + 1].qc_active) strcat(s, " assigned");
4208     }
4209    else
4210     {
4211      push_xstk_(xsp, np->nwid);
4212      __bld_forcedbits_mask(xsp->ap, np);
4213      if (!vval_is0_(xsp->ap, np->nwid)) strcat(s, " forced");
4214      __pop_xstk();
4215     }
4216   }
4217  strcat(s, ">");
4218  return(s);
4219 }
4220 
4221 /*
4222  * emit a load string - static information - should be emitted only once
4223  * load on xmr target
4224  */
emit1_load(struct net_t * np,struct net_pin_t * npp)4225 static void emit1_load(struct net_t *np, struct net_pin_t *npp)
4226 {
4227  int32 i1, i2, nd_itpop, obwid, ri1, ri2;
4228  struct inst_t *ip;
4229  struct itree_t *dritp;
4230  struct mod_t *mdp;
4231  struct mod_pin_t *mpp;
4232  struct gate_t *gp;
4233  struct conta_t *cap, *cap2;
4234  struct tchk_t *tcp;
4235  struct spcpth_t *pthp;
4236  struct npaux_t *npauxp;
4237  char ndxs[RECLEN];
4238 
4239  /* SJM 06/03/02 - only call get cor range if npaux exists */
4240  if ((npauxp = npp->npaux) == NULL) i1 = i2 = -1;
4241  else __get_cor_range(npauxp->nbi1, npauxp->nbi2, &i1, &i2);
4242  if (i1 != -1)
4243   {
4244    if (np->n_isarr) __getarr_range(np, &ri1, &ri2, &obwid);
4245    else if (np->n_isavec) __getwir_range(np, &ri1, &ri2);
4246    else { __arg_terr(__FILE__, __LINE__); ri1 = ri2 = 0; }
4247 
4248    if (i1 == i2) sprintf(ndxs, " [%d]", __unmap_ndx(i1, ri1, ri2));
4249    else sprintf(ndxs, " [%d:%d]", __unmap_ndx(i1, ri1, ri2),
4250    __unmap_ndx(i2, ri1, ri2));
4251   }
4252  else strcpy(ndxs, "");
4253 
4254  nd_itpop = TRUE;
4255  switch ((byte) npp->npproctyp) {
4256   case NP_PROC_INMOD: nd_itpop = FALSE; break;
4257   case NP_PROC_GREF:
4258    /* SJM 04/17/03 - if not end instance of matching downrel path do not */
4259    /* print */
4260    if (!__match_push_targ_to_ref(npp->np_xmrtyp, npp->npaux->npu.npgrp))
4261     return;
4262    break;
4263   case NP_PROC_FILT:
4264    /* all rooted xmrs here */
4265    __push_itstk(npp->npaux->npdownitp);
4266    break;
4267   default: __case_terr(__FILE__, __LINE__);
4268  }
4269 
4270  switch ((byte) npp->npntyp) {
4271   case NP_ICONN:
4272    dritp = &(__inst_ptr->in_its[npp->elnpp.eii]);
4273    ip = dritp->itip;
4274    mdp = ip->imsym->el.emdp;
4275    mpp = &(mdp->mpins[npp->obnum]);
4276    __cvsim_msg("%s   load: instance %s port %s at %s\n",
4277     ndxs, ip->imsym->el.emdp->msym->synam, __to_mpnam(__xs2, mpp->mpsnam),
4278     __bld_lineloc(__xs, ip->isym->syfnam_ind, ip->isym->sylin_cnt));
4279    break;
4280   case NP_PB_ICONN:
4281    /* per bit load same except know scalar/bsel */
4282    dritp = &(__inst_ptr->in_its[npp->elnpp.eii]);
4283    ip = dritp->itip;
4284    mdp = ip->imsym->el.emdp;
4285    /* notic since not emitting decomposed per bit exprs, need master port */
4286    mpp = &(mdp->mpins[npp->obnum]);
4287    __cvsim_msg("%s   load: instance %s port %s bit %d at %s\n",
4288     ndxs, ip->imsym->el.emdp->msym->synam, __to_mpnam(__xs2, mpp->mpsnam),
4289     npp->pbi, __bld_lineloc(__xs, ip->isym->syfnam_ind, ip->isym->sylin_cnt));
4290    break;
4291   case NP_GATE:
4292    /* current value of gate is state output - next value is event state */
4293    gp = npp->elnpp.egp;
4294    if (gp->g_class == GC_UDP) strcpy(__xs2, "udp");
4295    else strcpy(__xs2, "gate");
4296    __cvsim_msg("%s   load: %s %s %s (port %d) at %s\n" , ndxs, __xs2,
4297     gp->gmsym->synam, gp->gsym->synam, npp->obnum + 1, __bld_lineloc(__xs,
4298     gp->gsym->syfnam_ind, gp->gsym->sylin_cnt));
4299    break;
4300   case NP_TRANIF:
4301    /* this is only for third port of tranif */
4302    gp = npp->elnpp.egp;
4303    __cvsim_msg("%s   load: %s %s (port %d - enable) at %s\n" , ndxs,
4304     gp->gmsym->synam, gp->gsym->synam, npp->obnum + 1, __bld_lineloc(__xs,
4305     gp->gsym->syfnam_ind, gp->gsym->sylin_cnt));
4306    break;
4307   case NP_CONTA:
4308    cap = npp->elnpp.ecap;
4309    if (cap->ca_pb_sim)
4310     {
4311      cap2 = &(cap->pbcau.pbcaps[npp->pbi]);
4312      __cvsim_msg("%s   load: continuous assign to %s per bit %d at %s\n",
4313       ndxs, __msgexpr_tostr(__xs, cap2->lhsx), npp->pbi,
4314       __bld_lineloc(__xs2, cap->casym->syfnam_ind, cap->casym->sylin_cnt));
4315     }
4316    else
4317     {
4318      __cvsim_msg("%s   load: continuous assign to %s at %s\n", ndxs,
4319       __msgexpr_tostr(__xs, cap->lhsx),
4320       __bld_lineloc(__xs2, cap->casym->syfnam_ind, cap->casym->sylin_cnt));
4321     }
4322    break;
4323   case NP_MDPRT:
4324    /* notice mipd module port is only driver not load */
4325    mdp = npp->elnpp.emdp;
4326    mpp = &(mdp->mpins[npp->obnum]);
4327    __cvsim_msg("%s   load: module %s port %s at %s\n", ndxs,
4328     mdp->msym->synam, __to_mpnam(__xs2, mpp->mpsnam),
4329     __bld_lineloc(__xs, mpp->mpfnam_ind, mpp->mplin_cnt));
4330    break;
4331   case NP_PB_MDPRT:
4332    /* notice mipd module port is only driver not load */
4333    mdp = npp->elnpp.emdp;
4334    mpp = &(mdp->mpins[npp->obnum]);
4335    mpp = &(mpp->pbmpps[npp->pbi]);
4336    /* here since not emitting exprs, need master mod port */
4337    __cvsim_msg("%s   load: module %s port %s bit %d at %s\n", ndxs,
4338     mdp->msym->synam, __to_mpnam(__xs2, mpp->mpsnam), npp->pbi,
4339     __bld_lineloc(__xs, mpp->mpfnam_ind, mpp->mplin_cnt));
4340    break;
4341   case NP_TCHG:
4342    switch ((byte) npp->chgsubtyp) {
4343     case NPCHG_TCSTART:
4344      tcp = npp->elnpp.etchgp->chgu.chgtcp;
4345      __cvsim_msg(
4346      "%s   change: %s timing check line %s reference change event\n",
4347       ndxs, __to_tcnam(__xs, tcp->tchktyp), __bld_lineloc(__xs2,
4348       tcp->tcsym->syfnam_ind, tcp->tcsym->sylin_cnt));
4349      break;
4350     case NPCHG_TCCHK:
4351      tcp = npp->elnpp.echktchgp->startchgp->chgu.chgtcp;
4352      __cvsim_msg("%s   change: %s timing check line %s data check event\n",
4353       ndxs, __to_tcnam(__xs, tcp->tchktyp),__bld_lineloc(__xs2,
4354       tcp->tcsym->syfnam_ind, tcp->tcsym->sylin_cnt));
4355      break;
4356     case NPCHG_PTHSRC:
4357      pthp = npp->elnpp.etchgp->chgu.chgpthp;
4358      __cvsim_msg("%s   change: path source and %s source port bit change\n",
4359       ndxs, __bld_lineloc(__xs, pthp->pthsym->syfnam_ind,
4360       pthp->pthsym->sylin_cnt));
4361      break;
4362     default: __case_terr(__FILE__, __LINE__);
4363    }
4364    break;
4365   case NP_MIPD_NCHG:
4366    /* LOOKATME - should maybe add more details to data structure */
4367    __cvsim_msg("%s   load: MIPD delay device\n", ndxs);
4368    break;
4369   /* pull or tfrw arg can only be driver */
4370   default: __case_terr(__FILE__, __LINE__);
4371  }
4372  if (nd_itpop) __pop_itstk();
4373 }
4374 
4375 /*
4376  * ROUTINES TO IMPLEMENT $DUMPVARS SYSTEM TASK
4377  */
4378 
4379 /*
4380  * ROUTINES TO COLLECT DUMPVARS INFO DURING ONE TIME
4381  */
4382 
4383 /*
4384  * execute a dumpvars system task - just collect information - written
4385  * at end of this time unit __dv_calltime triggers end of slot dump var
4386  * file output - if off must still always write header
4387  *
4388  * this must be called with nil if none or func. call. operator (hd of list)
4389  */
__exec_dumpvars(struct expr_t * argx)4390 extern void __exec_dumpvars(struct expr_t *argx)
4391 {
4392  register struct mdvmast_t *mdvp;
4393  int32 dpth, anum, ii;
4394  word32 tmp;
4395  struct mdvmast_t *mdvp2;
4396  struct itree_t *itp;
4397  struct gref_t *grp;
4398  struct sy_t *syp;
4399 
4400  /* multiple dumpvars legal during first time where dumpvars seen */
4401  /* dv seen means previous dumpvars call failed */
4402  if (__dv_seen)
4403   {
4404    __sgferr(729,
4405     "all $dumpvars calls must be at same time - previously called at %s",
4406     __to_timstr(__xs, &__dv_calltime));
4407    return;
4408   }
4409  __dv_calltime = __simtime;
4410 
4411  if (argx == NULL)
4412   {
4413    if (__dv_hdr != NULL)
4414     {
4415      __sgfwarn(516,
4416       "$dumpvars no argument form replaces previous $dumpvars call");
4417      /* free master records - wire records will be reused if present */
4418      for (mdvp = __dv_hdr; mdvp->mdvnxt != NULL;)
4419       {
4420        mdvp2 = mdvp->mdvnxt;
4421        __my_free((char *) mdvp, sizeof(struct mdvmast_t));
4422        mdvp = mdvp2;
4423       }
4424      __dv_hdr = __dv_end = NULL;
4425     }
4426    /* mdv_iprt NULL means entire design - common case */
4427    mdvp = alloc_mdvmast();
4428    __dv_hdr = __dv_end = mdvp;
4429    __dv_isall_form = TRUE;
4430    goto done;
4431   }
4432  /* argument list form, know first is level */
4433  if (!__get_eval_word(argx->lu.x, &tmp))
4434   {
4435    __sgferr(715,
4436     "$dumpvar depth argument illegal numeric expression %s - 1 used",
4437     __msgexpr_tostr(__xs, argx->lu.x));
4438    tmp = 1;
4439   }
4440  dpth = (int32) tmp;
4441  argx = argx->ru.x;
4442  for (anum = 0; argx != NULL; argx = argx->ru.x, anum++)
4443   {
4444    if (__dv_isall_form)
4445     {
4446      __sgfwarn(500,
4447       "$dumpvars argument %s (number %d) ignored - follows all of design form",
4448       __msgexpr_tostr(__xs, argx->lu.x), anum);
4449      continue;
4450     }
4451 
4452    /* do not need checking since checked at fixup time */
4453    if (argx->lu.x->optyp == GLBREF)
4454     {
4455      grp = argx->lu.x->ru.grp;
4456      syp =  grp->targsyp;
4457      mdvp = alloc_mdvmast();
4458      /* xmr wire */
4459      switch ((byte) syp->sytyp) {
4460       case SYM_N:
4461        __xmrpush_refgrp_to_targ(grp);
4462        mdvp->mdv_itprt = __inst_ptr;
4463        __pop_itstk();
4464        mdvp->mdv_tskp = grp->targtskp;
4465        mdvp->mdv_np = syp->el.enp;
4466        break;
4467       case SYM_I:
4468        __xmrpush_refgrp_to_targ(grp);
4469        itp = __inst_ptr;
4470        __pop_itstk();
4471        goto inst_form;
4472       case SYM_M:
4473        if ((ii = __ip_indsrch(syp->synam)) == -1)
4474         __case_terr(__FILE__, __LINE__);
4475        itp = __it_roots[ii];
4476 inst_form:
4477        mdvp->mdv_itprt = itp;
4478        mdvp->mdv_levels = dpth;
4479        break;
4480       default: __case_terr(__FILE__, __LINE__);
4481      }
4482     }
4483    /* know this is local wire form */
4484    else
4485     {
4486      mdvp = alloc_mdvmast();
4487      mdvp->mdv_itprt = __inst_ptr;
4488      mdvp->mdv_np = argx->lu.x->lu.sy->el.enp;
4489      if (__cur_thd == NULL) __misc_terr(__FILE__, __LINE__);
4490 
4491      /* SJM 02/29/00 - need to also get var's containing func task */
4492      /* LOOKATME - shoudl $dumpvars work in functions - think yes? */
4493      /* SJM 07/05/01 - if var form dumpvars called not task no no task cntxt */
4494      if (__cur_thd->assoc_tsk != NULL) mdvp->mdv_tskp = __getcur_scope_tsk();
4495      syp = mdvp->mdv_np->nsym;
4496     }
4497    if (__dv_end == NULL) __dv_hdr = mdvp; else __dv_end->mdvnxt = mdvp;
4498    __dv_end = mdvp;
4499   }
4500 done:
4501  __slotend_action |= SE_DUMPVARS;
4502  __dv_seen = FALSE;
4503 }
4504 
4505 /*
4506  * allocate a new dumpvars argument master record
4507  * notice these can never be freed - needed for dumping all vars
4508  */
alloc_mdvmast(void)4509 static struct mdvmast_t *alloc_mdvmast(void)
4510 {
4511  struct mdvmast_t *mdvp;
4512 
4513  mdvp = (struct mdvmast_t *) __my_malloc(sizeof(struct mdvmast_t));
4514  mdvp->mdv_levels = 0;
4515  mdvp->mdv_itprt = NULL;
4516  mdvp->mdv_tskp = NULL;
4517  mdvp->mdv_np = NULL;
4518  mdvp->mdvnxt = NULL;
4519  return(mdvp);
4520 }
4521 
4522 /*
4523  * ROUTINES TO SETUP DMPV EVENTS AND DUMP DUMPVARS HEADER AT SETUP SLOT END
4524  */
4525 
4526 /*
4527  * setup the dumpvars header
4528  * called at end of time when first $dumpvars executed
4529  */
__setup_dmpvars()4530 extern void __setup_dmpvars()
4531 {
4532  register struct mdvmast_t *mdvp;
4533 
4534  /* SJM 04/20/00 - in case of reset, must not reallocate */
4535  /* but possible for after reset to invoke dumpvars but not original */
4536  if (__dv_buffer == NULL) __dv_buffer = __my_malloc(DVBUFSIZ);
4537  __dv_nxti = 0;
4538  /* case 1 - all form - know only one mdv master */
4539  if (__dv_isall_form)
4540   {
4541    if (__dv_hdr == NULL || __dv_hdr->mdvnxt != NULL
4542     || __dv_hdr->mdv_itprt != NULL) __misc_terr(__FILE__, __LINE__);
4543 
4544    setup_all_dvars();
4545   }
4546  else
4547   {
4548    for (mdvp = __dv_hdr; mdvp != NULL; mdvp = mdvp->mdvnxt)
4549     setup_1argdvars(mdvp);
4550   }
4551  sprintf(__xs2, "$date\n    %s\n$end\n", __pv_timestamp);
4552  __adds(__xs2);
4553  dv_wr(FALSE);
4554 
4555  sprintf(__xs2, "$version\n    %s%s of %s\n$end\n", __vers, __vers2, __ofdt);
4556  __adds(__xs2);
4557  dv_wr(FALSE);
4558 
4559  /* need to use actual time scale - is default right */
4560  sprintf(__xs2, "$timescale\n    %s\n$end\n", __to_timunitnam(__xs,
4561   __des_timeprec));
4562  __adds(__xs2);
4563  dv_wr(FALSE);
4564 
4565  /* first write the header info for variables form */
4566  for (mdvp = __dv_hdr; mdvp != NULL; mdvp = mdvp->mdvnxt)
4567   wr_1argdvhdr(mdvp);
4568  sprintf(__xs2, "$enddefinitions $end\n");
4569  __adds(__xs2);
4570  dv_wr(FALSE);
4571 }
4572 
4573 /*
4574  * set up dumpvars for all instances of all variables of all modules
4575  * called at end of time slot, $dumpvars called in
4576  */
setup_all_dvars(void)4577 static void setup_all_dvars(void)
4578 {
4579  register int32 ni;
4580  register struct net_t *np;
4581  register struct mod_t *mdp;
4582  register struct task_t *tskp;
4583 
4584  /* each module */
4585  for (mdp = __modhdr; mdp != NULL; mdp = mdp->mnxt)
4586   {
4587    /* add to each variable */
4588    if (mdp->mnnum != 0)
4589     {
4590      for (ni = 0, np = &(mdp->mnets[0]); ni < mdp->mnnum; ni++, np++)
4591       {
4592        if (np->n_isarr) continue;
4593        turnon_1net_dmpv(np, (struct itree_t *) NULL, (struct task_t *) NULL,
4594         mdp, FALSE);
4595       }
4596     }
4597    for (tskp = mdp->mtasks; tskp != NULL; tskp = tskp->tsknxt)
4598     {
4599 
4600      if (tskp->trnum != 0)
4601       {
4602        for (ni = 0, np = &(tskp->tsk_regs[0]); ni < tskp->trnum; ni++, np++)
4603         {
4604          if (np->n_isarr) continue;
4605          turnon_1net_dmpv(np, (struct itree_t *) NULL, tskp, mdp, FALSE);
4606         }
4607       }
4608     }
4609   }
4610 }
4611 
4612 /*
4613  * setup the dumpvar delays controls for 1 master dumpvars arg record
4614  *
4615  * separate routine writes the headers
4616  * know if dump entire design will not get here
4617  */
setup_1argdvars(struct mdvmast_t * mdvp)4618 static void setup_1argdvars(struct mdvmast_t *mdvp)
4619 {
4620  struct net_t *np;
4621  struct mod_t *mdp;
4622  struct itree_t *itp;
4623 
4624  /* case 1 simple variable */
4625  if ((np = mdvp->mdv_np) != NULL)
4626   {
4627    /* think flatinum not needed here since 1 itree loc. place */
4628    if (np->n_isarr) return;
4629 
4630 
4631    itp = mdvp->mdv_itprt;
4632    mdp = itp->itip->imsym->el.emdp;
4633    turnon_1net_dmpv(np, itp, mdvp->mdv_tskp, mdp, FALSE);
4634   }
4635  else
4636   {
4637    /* case 2 subtree */
4638    /* descend number of levels - 0 is all, 1 is just current */
4639    setup_1subtree_allvars(mdvp->mdv_itprt, mdvp->mdv_levels);
4640   }
4641 }
4642 
4643 /*
4644  * set all varaibles in an instance and under for dumping
4645  */
setup_1subtree_allvars(struct itree_t * itp,int32 level)4646 static void setup_1subtree_allvars(struct itree_t *itp, int32 level)
4647 {
4648  register int32 ii;
4649  struct mod_t *mdp;
4650  struct itree_t *down_itp;
4651 
4652  /* must always try to do current */
4653  mdp = itp->itip->imsym->el.emdp;
4654  /* notice cannot stop if one mod dv setup since level may have been less */
4655  /* than current level (i.e. this ones descends more) */
4656  setup_1installvars(mdp, itp);
4657  mdp->mod_hasdvars = TRUE;
4658 
4659  if (level == 1) return;
4660  for (ii = 0; ii < mdp->minum; ii++)
4661   {
4662    down_itp = &(itp->in_its[ii]);
4663    setup_1subtree_allvars(down_itp, (level != 0) ? level - 1 : 0);
4664   }
4665 }
4666 
4667 /*
4668  * set up dumpvars for all variables of module at one itree location
4669  */
setup_1installvars(struct mod_t * mdp,struct itree_t * itp)4670 static void setup_1installvars(struct mod_t *mdp, struct itree_t *itp)
4671 {
4672  register int32 ni;
4673  register struct net_t *np;
4674  struct task_t *tskp;
4675 
4676  /* add to each variable */
4677  if (mdp->mnnum != 0)
4678   {
4679    for (ni = 0, np = &(mdp->mnets[0]); ni < mdp->mnnum; ni++, np++)
4680     {
4681      if (np->n_isarr) continue;
4682      turnon_1net_dmpv(np, itp, NULL, mdp, FALSE);
4683     }
4684   }
4685  for (tskp = mdp->mtasks; tskp != NULL; tskp = tskp->tsknxt)
4686   {
4687 
4688    if (tskp->trnum != 0)
4689     {
4690      for (ni = 0, np = &(tskp->tsk_regs[0]); ni < tskp->trnum; ni++, np++)
4691       {
4692        if (np->n_isarr) continue;
4693 
4694        turnon_1net_dmpv(np, itp, tskp, mdp, FALSE);
4695       }
4696     }
4697   }
4698 }
4699 
4700 /*
4701  * turn on dumpvars for one net - called only at end of time slot
4702  *
4703  * if already turned on for for other instance, just set bit
4704  * if itp nil, set all bits
4705  *
4706  * only get here if at least one net in mod
4707  */
turnon_1net_dmpv(struct net_t * np,struct itree_t * itp,struct task_t * tskp,struct mod_t * mdp,int32 repeat_ok)4708 static void turnon_1net_dmpv(struct net_t *np, struct itree_t *itp,
4709  struct task_t *tskp, struct mod_t *mdp, int32 repeat_ok)
4710 {
4711  register int32 ni, ii, jj;
4712  char s1[RECLEN];
4713 
4714  mdp->mod_hasdvars = TRUE;
4715 
4716  /* assign dump vars id numbers for every inst. even if only some used */
4717  /* LOOKATME - could eliminate bad (hard to read) codes, but for now no */
4718  /* reason to bother - also problem with continuous regions */
4719  /* would need to find good contiguous region */
4720  /* __next_dvnum = skip_bad_codes(np, __next_dvnum); */
4721 
4722  /* if this net already has some instance dumpvared do not set up codes */
4723  if (!np->n_hasdvars)
4724   {
4725    np->n_hasdvars = TRUE;
4726    /* if net has any dumpvars must always use change stores */
4727    /* but recording now unrelated to dumpvars */
4728    /* SJM 10/10/06 - if dmpv in src legal to turn */
4729    /* the nchg nd chgstore bit on because needed for dumpvars and starts */
4730    /* using nchg processing from here on when know no dces */
4731    if (!np->nchg_nd_chgstore)
4732     {
4733      /* DBG remove -- */
4734      if (!np->dmpv_in_src) __misc_terr(__FILE__, __LINE__);
4735      /* -- */
4736      np->nchg_nd_chgstore = TRUE;
4737     }
4738 
4739    /* if first time any net of module has dumpvars - alloc table */
4740    /* for all nets in module */
4741    if (mdp->mndvcodtab == NULL)
4742     {
4743      mdp->mndvcodtab = __my_malloc(5*mdp->mtotvarnum*mdp->flatinum);
4744      memset(mdp->mndvcodtab, 0, 5*mdp->mtotvarnum*mdp->flatinum);
4745     }
4746    /* 07/02/00 - SJM - fill module net dvcod table for this net */
4747    /* FIXME - think size should be 8 for alignment */
4748    ni = np - mdp->mnets;
4749    for (ii = 0, jj = 5*ni*mdp->flatinum; ii < mdp->flatinum; ii++, jj += 5)
4750     {
4751      strcpy(&(mdp->mndvcodtab[jj]), to_dvcode(s1, __next_dvnum + ii));
4752     }
4753    /* RELEASE remove ---
4754    if (__debug_flg)
4755     {
4756     __dbg_msg("$$$ setting dvnum base %d for net %s (%d) in %s\n",
4757      __next_dvnum, np->nsym->synam, ni, mdp->msym->synam);
4758     }
4759    --- */
4760    __next_dvnum += mdp->flatinum;
4761   }
4762 
4763  /* set bits in nets nchg action tab for this dumpvared net and maybe inst */
4764  if (itp == NULL)
4765   {
4766    for (ii = 0; ii < mdp->flatinum; ii++)
4767     {
4768      /* LOOKATME - here just turn on fact that dumpvared */
4769      /* otherwide would start too early - before next time step */
4770      /* i.e. mark not changed but set master dmpv copied to now flag */
4771      np->nchgaction[ii] |=
4772       (NCHG_DMPVARED | NCHG_DMPVARNOW | NCHG_DMPVNOTCHGED);
4773     }
4774    return;
4775   }
4776  if (!repeat_ok && ((np->nchgaction[itp->itinum] & NCHG_DMPVARED) != 0))
4777   {
4778    __sgfinform(435, "variable %s in instance %s repeated in $dumpvars list",
4779     np->nsym->synam, __msg_blditree(__xs, itp, tskp));
4780   }
4781  np->nchgaction[itp->itinum]
4782   |= (NCHG_DMPVARED | NCHG_DMPVARNOW | NCHG_DMPVNOTCHGED);
4783 }
4784 
4785 /*
4786  * convert a number to a special character base 93 char number
4787  * this should be moved to v_cnv
4788  * notice requires ascii
4789  * LOOKATME - code ! is possible - is it legal?
4790  */
to_dvcode(register char * s,register int32 vnum)4791 static char *to_dvcode(register char *s, register int32 vnum)
4792 {
4793  s[4] = '\0';
4794  s[3] = '!' + vnum % 93;
4795  if (vnum < 93) return(&(s[3]));
4796  vnum /= 93;
4797  s[2] = '!' + vnum % 93;
4798  if (vnum < 93) return(&(s[2]));
4799  vnum /= 93;
4800  s[1] = '!' + vnum % 93;
4801  if (vnum < 93) return(&(s[1]));
4802  vnum /= 93;
4803  s[0] = '!' + vnum;
4804  return(s);
4805 }
4806 
4807 /*
4808  * routine which skip number that are illegal codes
4809  * for now # (must be illegal) plus one digit and one letter x, z, X, Z
4810  */
4811 /* --
4812 static int32 skip_bad_codes(struct net_t *np, int32 nextcod)
4813 {
4814  register char *cp;
4815  int32 fr, to, bad;
4816  char s1[RECLEN];
4817 
4818  if (nextcod > 93) return(nextcod);
4819 
4820  -- notice this list must be in numerical order --
4821  strcpy(s1, "#0123456789XZxz");
4822  fr = nextcod;
4823  to = nextcod + np->nwid - 1;
4824 
4825  for (cp = s1; *cp != '\0'; cp++)
4826   {
4827    bad = *cp - '!';
4828    if (fr <= bad && bad <= to)
4829     {
4830      if (isdigit(*cp)) nextcod = '9' - '!' + 1;
4831      else nextcod = bad + 1;
4832      fr = nextcod;
4833      to = nextcod + np->nwid - 1;
4834     }
4835   }
4836  return(nextcod);
4837 }
4838 --- */
4839 
4840 /*
4841  * ROUTINES TO WRITE THE DUMPVAR HEADER REFERENCE INFO
4842  */
4843 
4844 /*
4845  * write the header for 1 master dumpvars arg record
4846  * done at end of setup time slot
4847  */
wr_1argdvhdr(struct mdvmast_t * mdvp)4848 static void wr_1argdvhdr(struct mdvmast_t *mdvp)
4849 {
4850  register int32 ii;
4851  int32 ni, jj;
4852  struct itree_t *itp, *itp2;
4853  struct mod_t *mdp;
4854  struct task_t *tskp;
4855  struct net_t *np;
4856  char *dvcodp;
4857 
4858  /* case 0: all of design */
4859  if (mdvp->mdv_itprt == NULL)
4860   {
4861    for (ii = 0; ii < __numtopm; ii++)
4862     {
4863      itp = __it_roots[ii];
4864      sprintf(__xs2, "$scope module %s $end\n", itp->itip->isym->synam);
4865      __adds(__xs2);
4866      dv_wr(FALSE);
4867 
4868      wr_1subtree_allvars(itp, 0);
4869      sprintf(__xs2, "$upscope $end\n");
4870      __adds(__xs2);
4871      dv_wr(FALSE);
4872     }
4873    return;
4874   }
4875 
4876  /* case 1 simple variable */
4877  if ((np = mdvp->mdv_np) != NULL)
4878   {
4879    /* DBG remove --- */
4880    if (np->n_isarr) __misc_terr(__FILE__, __LINE__);
4881    /* --- */
4882 
4883    /* no need to check for array 1 wire form - illegal if array */
4884    wr_fromtop_iscopeto(mdvp->mdv_itprt);
4885    itp2 = mdvp->mdv_itprt;
4886    mdp = itp2->itip->imsym->el.emdp;
4887    if ((tskp = mdvp->mdv_tskp) != NULL)
4888     {
4889      wr_tskscopeto(tskp->tsksymtab);
4890      ni = np - mdp->mnets;
4891      /* 07/02/00 - SJM - find right dvcod table code */
4892      jj = 5*ni*mdp->flatinum + itp2->itinum;
4893      dvcodp = &(mdp->mndvcodtab[jj]);
4894     }
4895    else
4896     {
4897      /* 07/02/00 - SJM - find right dvcod table code */
4898      ni = np - mdp->mnets;
4899      jj = 5*(ni*mdp->flatinum + itp2->itinum);
4900      dvcodp = &(mdp->mndvcodtab[jj]);
4901     }
4902    wr_1vectored_dvdef(np, dvcodp, itp2);
4903    if (tskp != NULL) wr_tskscopeback(mdvp->mdv_tskp->tsksymtab);
4904    wr_totop_iscopeback(mdvp->mdv_itprt);
4905   }
4906  else
4907   {
4908    /* case 2 inst. scope */
4909    /* this handles all its own scope movements */
4910    /* case inst. with some levels underneath */
4911    /* descend number of levels - 0 is all, 1 is just current */
4912    wr_fromtop_iscopeto(mdvp->mdv_itprt);
4913    wr_1subtree_allvars(mdvp->mdv_itprt, mdvp->mdv_levels);
4914    wr_totop_iscopeback(mdvp->mdv_itprt);
4915 
4916    /* AIV 01/28/05 - removed an extra upscope printing */
4917   }
4918 }
4919 
4920 /*
4921  * write the variables for all instances in and under 1 itree module loc.
4922  * descends level numbers 0 - all
4923  * when called expects scope to be moved upon return leaves scope at itp
4924  */
wr_1subtree_allvars(struct itree_t * itp,int32 level)4925 static void wr_1subtree_allvars(struct itree_t *itp, int32 level)
4926 {
4927  register int32 ii;
4928  struct mod_t *imdp;
4929  struct symtab_t *sytp;
4930  struct itree_t *down_itp;
4931 
4932  wr_1inst_dvhdrs(itp);
4933  imdp = itp->itip->imsym->el.emdp;
4934  /* when done scope left at instance same as called */
4935  if ((sytp = imdp->msymtab->sytofs) != NULL) wr_tasks_dvhdrs(itp, sytp);
4936  if (level != 1)
4937   {
4938    for (ii = 0; ii < imdp->minum; ii++)
4939     {
4940      down_itp = &(itp->in_its[ii]);
4941      sprintf(__xs2, "$scope module %s $end\n", down_itp->itip->isym->synam);
4942      __adds(__xs2);
4943      dv_wr(FALSE);
4944 
4945      wr_1subtree_allvars(down_itp, (level != 0) ? level - 1 : 0);
4946      sprintf(__xs2, "$upscope $end\n");
4947      __adds(__xs2);
4948      dv_wr(FALSE);
4949     }
4950   }
4951 }
4952 
4953 /*
4954  * write the dv header variables in one module
4955  * scope set and does not descend or change scope
4956  */
wr_1inst_dvhdrs(struct itree_t * itp)4957 static void wr_1inst_dvhdrs(struct itree_t *itp)
4958 {
4959  register int32 ni;
4960  register struct net_t *np;
4961  int32 jj;
4962  struct mod_t *mdp;
4963  struct itree_t *itp2;
4964  char *dvcodp;
4965 
4966  mdp = itp->itip->imsym->el.emdp;
4967  /* write all wires */
4968  if (mdp->mnnum == 0) return;
4969  for (ni = 0, np = &(mdp->mnets[0]); ni < mdp->mnnum; ni++, np++)
4970   {
4971    if (np->n_isarr) continue;
4972 
4973 
4974    /* SJM - 07/02/00 - now dvcods pre-built as strings */
4975    jj = 5*(ni*mdp->flatinum + itp->itinum);
4976    dvcodp = &(mdp->mndvcodtab[jj]);
4977    itp2 = itp;
4978    wr_1vectored_dvdef(np, dvcodp, itp2);
4979   }
4980 }
4981 
4982 /*
4983  * dump the header info for task and all contained tasks
4984  * handles scoping but assume all dmpvar dces already set up
4985  */
wr_tasks_dvhdrs(struct itree_t * itp,register struct symtab_t * sytp)4986 static void wr_tasks_dvhdrs(struct itree_t *itp,
4987  register struct symtab_t *sytp)
4988 {
4989  register int32 ni, ni2;
4990  register struct net_t *np;
4991  int32 jj;
4992  struct task_t *tskp;
4993  struct mod_t *mdp;
4994  char *dvcodp;
4995 
4996  mdp = itp->itip->imsym->el.emdp;
4997  /* write all contained tasks/funcs/lbs - through symbol table list */
4998  for (; sytp != NULL; sytp = sytp->sytsib)
4999   {
5000    tskp = sytp->sypofsyt->el.etskp;
5001    /* notice must set up scope even if no variables */
5002    /* if (tskp->tsk_regs == NULL) continue; */
5003    sprintf(__xs2, "$scope %s %s $end\n", to_dvtsktyp(__xs, tskp->tsktyp),
5004     tskp->tsksyp->synam);
5005    __adds(__xs2);
5006    dv_wr(FALSE);
5007 
5008    if (tskp->trnum != 0)
5009     {
5010      for (ni = 0, np = &(tskp->tsk_regs[0]); ni < tskp->trnum; ni++, np++)
5011       {
5012        if (np->n_isarr) continue;
5013        /* 04/15/00 - net index for dmpvars is from mod first net */
5014        ni2 = np - mdp->mnets;
5015 
5016        /* 07/02/00 - SJM - dvcod values not pre-built */
5017        jj = 5*(ni2*mdp->flatinum + itp->itinum);
5018        dvcodp = &(mdp->mndvcodtab[jj]);
5019        wr_1vectored_dvdef(np, dvcodp, itp);
5020       }
5021     }
5022    if (sytp->sytofs != NULL) wr_tasks_dvhdrs(itp, sytp->sytofs);
5023    sprintf(__xs2, "$upscope $end\n");
5024    __adds(__xs2);
5025    dv_wr(FALSE);
5026   }
5027 }
5028 
5029 /*
5030  * build string name of task for $dumpvars - all blocks labeled
5031  */
to_dvtsktyp(char * s,word32 tskt)5032 static char *to_dvtsktyp(char *s, word32 tskt)
5033 {
5034  switch ((byte) tskt) {
5035   case Begin: strcpy(s, "begin"); break;
5036   case FORK: strcpy(s, "fork"); break;
5037   case FUNCTION: strcpy(s, "function"); break;
5038   case TASK: strcpy(s, "task"); break;
5039  }
5040  return(s);
5041 }
5042 
5043 /*
5044  * write commands to scope to an itree place
5045  */
wr_fromtop_iscopeto(struct itree_t * itp)5046 static void wr_fromtop_iscopeto(struct itree_t *itp)
5047 {
5048  register int32 i;
5049  register struct itree_t *witp;
5050  int32 frtoplevs;
5051 
5052  for (witp = itp, frtoplevs = 1;; frtoplevs++)
5053   {
5054    __push_itstk(witp);
5055    if ((witp = witp->up_it) == NULL) break;
5056   }
5057  for (i = 1; i <= frtoplevs; i++)
5058   {
5059    sprintf(__xs2, "$scope module %s $end\n", __inst_ptr->itip->isym->synam);
5060    __adds(__xs2);
5061    dv_wr(FALSE);
5062 
5063    __pop_itstk();
5064   }
5065 }
5066 
wr_totop_iscopeback(struct itree_t * itp)5067 static void wr_totop_iscopeback(struct itree_t *itp)
5068 {
5069  register struct itree_t *witp;
5070 
5071  for (witp = itp;;)
5072   {
5073    sprintf(__xs2, "$upscope $end\n");
5074    __adds(__xs2);
5075    dv_wr(FALSE);
5076 
5077    if ((witp = witp->up_it) == NULL) break;
5078   }
5079 }
5080 
5081 /*
5082  * write the scope into the task/lb/func - must pass tasks symbol
5083  */
wr_tskscopeto(struct symtab_t * sytp)5084 static void wr_tskscopeto(struct symtab_t *sytp)
5085 {
5086  struct task_t *tskp;
5087 
5088  if (sytp->sytpar != NULL && sytp->sytpar->sypofsyt->sytyp != SYM_M)
5089   wr_tskscopeto(sytp->sytpar);
5090  tskp = sytp->sypofsyt->el.etskp;
5091  sprintf(__xs2, "$scope %s %s $end\n", to_dvtsktyp(__xs, tskp->tsktyp),
5092   tskp->tsksyp->synam);
5093  __adds(__xs2);
5094  dv_wr(FALSE);
5095 }
5096 
wr_tskscopeback(struct symtab_t * sytp)5097 static void wr_tskscopeback(struct symtab_t *sytp)
5098 {
5099  struct symtab_t *wsytp;
5100 
5101  for (wsytp = sytp->sytpar;;)
5102   {
5103    sprintf(__xs2, "$upscope $end\n");
5104    __adds(__xs2);
5105    dv_wr(FALSE);
5106 
5107    /* keep going until back to containing module scope */
5108    if (wsytp->sypofsyt->sytyp == SYM_M) break;
5109   }
5110 }
5111 
5112 /*
5113  * write dv define for 1 scalar or vectored wire
5114  * never call for array
5115  */
wr_1vectored_dvdef(struct net_t * np,char * dvcod,struct itree_t * itp)5116 static void wr_1vectored_dvdef(struct net_t *np, char *dvcod,
5117  struct itree_t *itp)
5118 {
5119  int32 r1, r2;
5120  char s1[15];
5121 
5122  if ((np->nchgaction[itp->itinum] & NCHG_DMPVARED) == 0) return;
5123 
5124  if (np->n_isavec || np->ntyp == N_REAL)
5125   {
5126    __getwir_range(np, &r1, &r2);
5127    /* this must be wire name */
5128    sprintf(__xs2, "$var %s ", __to_wtnam2(s1, np->ntyp));
5129    __adds(__xs2);
5130    dv_wr(FALSE);
5131 
5132    /* SJM 06/18/01 - no range for dumpvar of reals and width 64 */
5133    if (np->ntyp == N_REAL)
5134     {
5135      sprintf(__xs2, "     64 %-4s %s $end\n", dvcod, np->nsym->synam);
5136     }
5137    else
5138     {
5139      /* SJM 09/13/99 - range but be MSB to LSB - was internal h:0 */
5140      sprintf(__xs2, "%7d %-4s %s [%d:%d] $end\n", np->nwid, dvcod,
5141       np->nsym->synam, r1, r2);
5142     }
5143    __adds(__xs2);
5144    dv_wr(FALSE);
5145   }
5146  else
5147   {
5148    sprintf(__xs2, "$var %s ", __to_wtnam2(s1, np->ntyp));
5149    __adds(__xs2);
5150    dv_wr(FALSE);
5151    sprintf(__xs2, "      1 %-4s %s $end\n", dvcod, np->nsym->synam);
5152    __adds(__xs2);
5153    dv_wr(FALSE);
5154   }
5155 }
5156 
5157 /* 07/02/00 - now only one dvcod for each net - never scalared */
5158 
5159 /*
5160  * ROUTINES TO TURN ON/OFF DUMPVARS RECORDING
5161  */
5162 
5163 /*
5164  * turn off all dumpvars - uses being dumpvared template
5165  */
__turnoff_all_dumpvars(void)5166 extern void __turnoff_all_dumpvars(void)
5167 {
5168  register int32 ii;
5169  register struct net_t *np;
5170  register struct task_t *tskp;
5171  register struct mod_t *mdp;
5172  int32 ni;
5173 
5174  for (mdp = __modhdr; mdp != NULL; mdp = mdp->mnxt)
5175   {
5176    if (!mdp->mod_hasdvars) continue;
5177 
5178    for (ni = 0, np = &(mdp->mnets[0]); ni < mdp->mnnum; ni++, np++)
5179     {
5180      if (!np->n_hasdvars) continue;
5181 
5182      for (ii = 0; ii < mdp->flatinum; ii++)
5183       {
5184        /* if not dumpvared nothing to do */
5185        if ((np->nchgaction[ii] & NCHG_DMPVARED) == 0) continue;
5186 
5187        /* dumpv now off and not changed on (even if changed in slot) */
5188        np->nchgaction[ii] &= ~NCHG_DMPVARNOW;
5189        np->nchgaction[ii] |= NCHG_DMPVNOTCHGED;
5190       }
5191     }
5192    for (tskp = mdp->mtasks; tskp != NULL; tskp = tskp->tsknxt)
5193     {
5194      for (ni = 0, np = &(tskp->tsk_regs[0]); ni < tskp->trnum; ni++, np++)
5195       {
5196        if (!np->n_hasdvars) continue;
5197 
5198        for (ii = 0; ii < mdp->flatinum; ii++)
5199         {
5200          if ((np->nchgaction[ii] & NCHG_DMPVARED) == 0) continue;
5201 
5202          /* dumpv now off and not changed on (even if changed in slot) */
5203          np->nchgaction[ii] &= ~NCHG_DMPVARNOW;
5204          np->nchgaction[ii] |= NCHG_DMPVNOTCHGED;
5205         }
5206       }
5207     }
5208   }
5209 }
5210 
5211 /*
5212  * turn on all dumpvars (from previous turn-off)
5213  */
__turnon_all_dumpvars(void)5214 extern void __turnon_all_dumpvars(void)
5215 {
5216  register int32 ii;
5217  register struct net_t *np;
5218  register struct task_t *tskp;
5219  register struct mod_t *mdp;
5220  int32 ni;
5221 
5222  for (mdp = __modhdr; mdp != NULL; mdp = mdp->mnxt)
5223   {
5224    if (!mdp->mod_hasdvars) continue;
5225 
5226    for (ni = 0, np = &(mdp->mnets[0]); ni < mdp->mnnum; ni++, np++)
5227     {
5228      if (!np->n_hasdvars) continue;
5229 
5230      for (ii = 0; ii < mdp->flatinum; ii++)
5231       {
5232        /* if not dumpvared nothing to do */
5233        if ((np->nchgaction[ii] & NCHG_DMPVARED) == 0) continue;
5234 
5235        /* dumpv now off and not changed on (even if changed in slot) */
5236        np->nchgaction[ii] |= NCHG_DMPVARNOW;
5237        /* not changed bit already on */
5238       }
5239     }
5240    for (tskp = mdp->mtasks; tskp != NULL; tskp = tskp->tsknxt)
5241     {
5242      for (ni = 0, np = &(tskp->tsk_regs[0]); ni < tskp->trnum; ni++, np++)
5243       {
5244        if (!np->n_hasdvars) continue;
5245 
5246        for (ii = 0; ii < mdp->flatinum; ii++)
5247         {
5248          if ((np->nchgaction[ii] & NCHG_DMPVARED) == 0) continue;
5249 
5250          /* dumpv now off and not changed on (even if changed in slot) */
5251          np->nchgaction[ii] |= NCHG_DMPVARNOW;
5252          /* not changed bit already on */
5253         }
5254       }
5255     }
5256   }
5257 }
5258 
5259 /*
5260  * ROUTINES TO ACTUALLY DUMP VARIABLES
5261  */
5262 
5263 /*
5264  * dump all variables for baseline - for start ($dumpvars), dumpon,
5265  * dumpoff (need x's) and dumpall - keywrds determines which
5266  * set flags
5267  */
__do_dmpvars_baseline(char * keyws)5268 extern void __do_dmpvars_baseline(char *keyws)
5269 {
5270  __cur_sofs = 0;
5271  if (__dv_outlinpos != 0)
5272   {
5273    addch_('\n');
5274    __exprline[__cur_sofs] = '\0';
5275    dv_wr(FALSE);
5276   }
5277  if (!__dv_time_emitted)
5278   {
5279    sprintf(__xs2, "#%s\n", to_dvtimstr(__xs, __simtime));
5280    __adds(__xs2);
5281    __dv_time_emitted = TRUE;
5282    dv_wr(FALSE);
5283   }
5284 
5285  __adds(keyws);
5286  dv_wr(TRUE);
5287  __dv_outlinpos = 0;
5288  if (strcmp(keyws, "$dumpoff") == 0) __dv_func = DMPV_DUMPX;
5289  else __dv_func = DMPV_DMPALL;
5290  dump_allvars_vals();
5291  if (__dv_outlinpos != 0) addch_('\n');
5292  __adds("$end\n");
5293  dv_wr(FALSE);
5294  __dv_outlinpos = 0;
5295 }
5296 
5297 /*
5298  * dumpvars convert a 64 bit internal tick time to a decimal string
5299  *
5300  * SJM 11/21/03 - now all systems but OSX support word32 64 printf
5301  */
to_dvtimstr(char * s,register word64 t)5302 static char *to_dvtimstr(char *s, register word64 t)
5303 {
5304 #ifdef __APPLE__
5305  int32 trimblen, widnumlen;
5306  word32 t1a[2];
5307  char *cp;
5308 
5309  t1a[0] = (word32) (t & WORDMASK_ULL);
5310  if (t < WORDMASK_ULL) { sprintf(s, "%lu", t1a[0]); return(s); }
5311 
5312  t1a[1] = (word32) ((t >> 32) & WORDMASK_ULL);
5313  /* notice this case makes use of c require that fields are in order */
5314  trimblen = __trim1_0val(t1a, TIMEBITS);
5315  /* need ceil here */
5316  widnumlen = (int32) (trimblen*LG2_DIV_LG10 + 0.999999);
5317  __declcnv_tostr(s, t1a, trimblen, widnumlen);
5318  /* AIV 11/20/03 need to trim the spaces for #time in vcd files */
5319  if (*s == ' ')
5320   {
5321    for(cp = s; *cp == ' '; cp++);
5322   }
5323  return(cp);
5324 #else
5325  sprintf(s, "%llu", t);
5326  return(s);
5327 #endif
5328 }
5329 
5330 /*
5331  * dump all variables for various types of check pointing
5332  * know when this called positioned at beginning of new line
5333  */
dump_allvars_vals(void)5334 static void dump_allvars_vals(void)
5335 {
5336  register int32 ni;
5337  register struct mod_t *mdp;
5338  register struct net_t *np;
5339  register struct task_t *tskp;
5340 
5341  for (mdp = __modhdr; mdp != NULL; mdp = mdp->mnxt)
5342   {
5343    if (!mdp->mod_hasdvars) continue;
5344    if (mdp->mnnum != 0)
5345     {
5346      for (ni = 0, np = &(mdp->mnets[0]); ni < mdp->mnnum; ni++, np++)
5347       {
5348        /* if using default only dump vals for col. to col will never */
5349        /* have dumpvars so do not need special checking */
5350        /* if dump all even col. from, this is normal code */
5351        if (np->n_hasdvars)
5352         dmp_insts_ofwire(mdp, np);
5353       }
5354     }
5355    for (tskp = mdp->mtasks; tskp != NULL; tskp = tskp->tsknxt)
5356     {
5357 
5358      if (tskp->trnum == 0) continue;
5359      for (ni = 0, np = &(tskp->tsk_regs[0]); ni < tskp->trnum; ni++, np++)
5360       { if (np->n_hasdvars) dmp_insts_ofwire(mdp, np); }
5361     }
5362   }
5363 }
5364 
5365 /*
5366  * for a given net dump all instances of it - do not check change bit
5367  * this is for base lines and any change info left unchanged
5368  *
5369  * loop here could be unwound to make it faster
5370  * must never be called for arrays
5371  *
5372  * bld1 dvval uses global xs strings
5373  */
dmp_insts_ofwire(struct mod_t * mdp,struct net_t * np)5374 static void dmp_insts_ofwire(struct mod_t *mdp, struct net_t *np)
5375 {
5376  register int32 ii;
5377  register struct itree_t *itp;
5378  int32 jj;
5379  char *dvcodp;
5380 
5381  /* dump all dumpvared instances */
5382  /* LOOKATME - this is only step much slower in new approach - problem? */
5383  for (ii = 0; ii < mdp->flatinum; ii++)
5384   {
5385    if ((np->nchgaction[ii] & NCHG_DMPVARED) == 0) continue;
5386 
5387    itp = mdp->moditps[ii];
5388 
5389    /* 07/02/00 - SJM - find right dvcod table code */
5390    jj = 5*((np - mdp->mnets)*mdp->flatinum + itp->itinum);
5391    dvcodp = &(mdp->mndvcodtab[jj]);
5392 
5393    /* here for strength vector pass 0th (first-low) bit of vector */
5394    if (__dv_func == DMPV_DUMPX) bld1_xdvval(np, dvcodp);
5395    else
5396     {
5397      if (np->n_isavec) bld1_vec_dvval(np, dvcodp, itp);
5398      else bld1_scal_dvval(np, dvcodp, itp);
5399     }
5400    dv_wr(TRUE);
5401   }
5402 }
5403 
5404 /*
5405  * do the dumpvars changes
5406  * this routine requires at least one dv change entry
5407  */
__do_dmpvars_chg()5408 extern void __do_dmpvars_chg()
5409 {
5410  register struct dvchgnets_t *dvchgnp;
5411  register struct dvchgnets_t *dvchg_last;
5412  register struct net_t *np;
5413  register struct itree_t *itp;
5414  int32 jj;
5415  struct mod_t *mdp;
5416  char *dvcodp;
5417 
5418  if (__dv_outlinpos != 0)
5419   {
5420    addch_('\n');
5421    __exprline[__cur_sofs] = '\0';
5422    dv_wr(FALSE);
5423   }
5424  if (!__dv_time_emitted)
5425   {
5426    sprintf(__xs2, "#%s\n", to_dvtimstr(__xs, __simtime));
5427    __adds(__xs2);
5428    dv_wr(FALSE);
5429    __dv_time_emitted = TRUE;
5430    /* notice can only check for over limit when emitting new change time */
5431    if (__dv_dumplimit_size != 0)
5432     {
5433      if (__dv_file_size > __dv_dumplimit_size)
5434       {
5435        __dv_outlinpos = 0;
5436        sprintf(__xs2,
5437         "$comment - Note: $dumplimit %d limit exceeded at %s $end\n",
5438         __dv_dumplimit_size, __to_timstr(__xs, &__simtime));
5439        __adds(__xs2);
5440        dv_wr(FALSE);
5441 
5442        __dv_state = DVST_OVERLIMIT;
5443        __turnoff_all_dumpvars();
5444 
5445        __cv_msg(
5446         "  *** Dumping of variables stopped at %s because $dumplimit %d exceeded.\n",
5447         __to_timstr(__xs, &__simtime), __dv_dumplimit_size);
5448 
5449 
5450        /* need to move to end of change list so can free in chunk */
5451        for (dvchg_last = NULL, dvchgnp = __dv_chgnethdr; dvchgnp != NULL;
5452          dvchgnp = dvchgnp->dvchgnxt) dvchg_last = dvchgnp;
5453        goto free_chglist;
5454       }
5455     }
5456   }
5457  __dv_outlinpos = 0;
5458  __dv_func = DMPV_CHGONLY;
5459 
5460  dvchg_last = NULL;
5461  for (dvchgnp = __dv_chgnethdr; dvchgnp != NULL; dvchgnp = dvchgnp->dvchgnxt)
5462   {
5463    /* do the dumpvars for one var instance */
5464    np = dvchgnp->dvchg_np;
5465    itp = dvchgnp->dvchg_itp;
5466    mdp = itp->itip->imsym->el.emdp;
5467 
5468    jj = 5*((np - mdp->mnets)*mdp->flatinum + itp->itinum);
5469    dvcodp = &(mdp->mndvcodtab[jj]);
5470    if (np->n_isavec) bld1_vec_dvval(np, dvcodp, itp);
5471    else bld1_scal_dvval(np, dvcodp, itp);
5472    dv_wr(TRUE);
5473    /* reset this inst. not changed flag - i.e. must be on (not changed) */
5474    /* for next time */
5475    np->nchgaction[itp->itinum] |= NCHG_DMPVNOTCHGED;
5476    dvchg_last = dvchgnp;
5477   }
5478  /* splice list on front of change free list all at once */
5479  /* if last nil, no changes */
5480 free_chglist:
5481  if (dvchg_last != NULL)
5482   {
5483    dvchg_last->dvchgnxt = __dv_netfreelst;
5484    __dv_netfreelst = __dv_chgnethdr;
5485    __dv_chgnethdr = NULL;
5486   }
5487 }
5488 
5489 /*
5490  * special routine to emit time stamp at end of dumpvars file
5491  *
5492  * LOOKATME - does not write if over file size limit but maybe should
5493  */
__wr_dvtimstr(void)5494 extern void __wr_dvtimstr(void)
5495 {
5496  if (__dv_state != DVST_DUMPING) return;
5497  sprintf(__xs2, "#%s\n", to_dvtimstr(__xs, __simtime));
5498  __adds(__xs2);
5499  dv_wr(FALSE);
5500 }
5501 
5502 static char valtoch_tab[] = { '0', '1', 'z', 'x' };
5503 
5504 /*
5505  * build 1 scalar variable's dumpvar value string into exprline
5506  * caller must make sure right inum on top of itstk
5507  * format for vector b[value] [up to 4 char id] - for scale [v][4 char id]
5508  * for non x/z vector h[value] [id] - for real r[value][id]
5509  * called only when change known or need to dump all vals
5510  * notice __exprline can never be in use here
5511  */
bld1_scal_dvval(struct net_t * np,char * dvcodp,struct itree_t * itp)5512 static void bld1_scal_dvval(struct net_t *np, char *dvcodp,
5513  struct itree_t *itp)
5514 {
5515  register word32 v;
5516 
5517  __cur_sofs = 0;
5518  /* when changed written with 1 - never have value 0 and always 1 bit */
5519  /* will only be on changed list if cause during this time slot */
5520  if (np->ntyp == N_EVENT) addch_('1');
5521  else
5522   {
5523    v = (word32) np->nva.bp[itp->itinum];
5524    addch_(valtoch_tab[v & 3]);
5525   }
5526  __adds(dvcodp);
5527 }
5528 
5529 /*
5530  * build 1 vector variable's dumpvar value string into exprline
5531  * caller must make sure right inum on top of itstk
5532  * format for vector b[value] [up to 4 char id] - for scale [v][4 char id]
5533  * for non x/z vector h[value] [id] - for real r[value][id]
5534  * called only when change known or need to dump all vals
5535  * notice __exprline can never be in use here
5536  */
bld1_vec_dvval(struct net_t * np,char * dvcodp,struct itree_t * itp)5537 static void bld1_vec_dvval(struct net_t *np, char *dvcodp, struct itree_t *itp)
5538 {
5539  double d1;
5540  register struct xstk_t *xsp;
5541 
5542  __cur_sofs = 0;
5543  /* normal case */
5544  if (np->ntyp == N_REAL)
5545   {
5546    /* double is always 8 bytes stored using b part as extra 4 bytes */
5547    /* net width is 32 */
5548    memcpy(&d1, &(np->nva.wp[2*itp->itinum]), sizeof(double));
5549    sprintf(__xs2, "r%.16g ", d1);
5550    __adds(__xs2);
5551   }
5552  else
5553   {
5554    __push_itstk(itp);
5555    push_xstk_(xsp, np->nwid);
5556    __ld_wire_val(xsp->ap, xsp->bp, np);
5557    addch_('b');
5558    __sdispb(xsp->ap, xsp->bp, np->nwid, TRUE);
5559    addch_(' ');
5560    __pop_xstk();
5561    __pop_itstk();
5562   }
5563  __adds(dvcodp);
5564 }
5565 
5566 /*
5567  * build 1 variable's dumpvar x value string into exprline
5568  * format is x[up to 4 char id name] for scalar or bx [id] for vector
5569  */
bld1_xdvval(register struct net_t * np,char * dvcodp)5570 static void bld1_xdvval(register struct net_t *np, char *dvcodp)
5571 {
5572  __cur_sofs = 0;
5573  if (!np->n_isavec)
5574   { if (np->ntyp == N_EVENT) addch_('1'); else addch_('x'); }
5575  /* real x is 0.0 */
5576  else if (np->ntyp == N_REAL) __adds("r0.0 ");
5577  else __adds("bx ");
5578  __adds(dvcodp);
5579 }
5580 
5581 /*
5582  * write the built dump var value
5583  * know by here line always has ending new line
5584  */
dv_wr(int32 nd_nl)5585 static void dv_wr(int32 nd_nl)
5586 {
5587  register int32 new_fsiz;
5588 
5589  if (__cur_sofs == 0) return;
5590  if (__dv_dumplimit_size != 0)
5591   {
5592    if (__dv_state == DVST_OVERLIMIT) return;
5593 
5594    /* LOOKATME - +1 right since it points to \0? */
5595    /* SJM 11/13/99 - no adding one makes file too small (now matches 1862) */
5596    new_fsiz = __dv_file_size + __cur_sofs;
5597    __dv_file_size = new_fsiz;
5598   }
5599  /* know __cur_sofs points one past end of buffer */
5600  /* 2 overflow cases current line bigger than buffer or does not fit */
5601  if (__dv_nxti + __cur_sofs >= DVBUFSIZ - 2)
5602   {
5603    /* SJM 03/03/00 - no longer adding nil to end of dv buffer */
5604    if (__dv_nxti > 0)
5605     {
5606      /* DBG remove --
5607      __cv_msg("writing dumpvars buffer of size %d\n", __dv_nxti);
5608      --- */
5609      write(__dv_fd, __dv_buffer, __dv_nxti);
5610     }
5611    __dv_nxti = 0;
5612    /* immediate write if larger than buffer */
5613    if (__cur_sofs >= DVBUFSIZ - 2)
5614     {
5615      if (nd_nl)
5616       {
5617        __exprline[__cur_sofs++] = '\n';
5618        __dv_file_size++;
5619       }
5620      write(__dv_fd, __exprline, __cur_sofs);
5621      /* DBG remove --
5622      __cv_msg("writing dumpvars buffer of size %d\n", __cur_sofs + 1);
5623      --- */
5624      goto done;
5625     }
5626   }
5627  memcpy(&(__dv_buffer[__dv_nxti]), __exprline, __cur_sofs);
5628 
5629  __dv_nxti += __cur_sofs;
5630  if (nd_nl)
5631   {
5632    __dv_file_size++;
5633    __dv_buffer[__dv_nxti++] = '\n';
5634   }
5635 
5636 done:
5637  /* FIXME - what if wrote without new line to add or in string - then wrong? */
5638  __dv_outlinpos = 0;
5639  __cur_sofs = 0;
5640 }
5641 
5642 /*
5643  * flush a dumpvars - empty buffer then do OS flush
5644  */
__my_dv_flush(void)5645 extern void __my_dv_flush(void)
5646 {
5647  if (__dv_nxti > 0) write(__dv_fd, __dv_buffer, __dv_nxti);
5648  __dv_nxti = 0;
5649 
5650  /* SJM 07/02/00 - now avoiding fwrite buffering --
5651  if (fflush(__dv _ s) == EOF)
5652   {
5653    __sgferr(701, "OS failure when flushing $dumpvars file %s: %s",
5654     __dv_fnam, strerror(errno));
5655   }
5656  --- */
5657 }
5658