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