1 /* Copyright (c) 1995-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  * first module to implement pli vpi_ routines
30  */
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <ctype.h>
36 #include <stdarg.h>
37 #include <dlfcn.h>
38 
39 #ifdef __DBMALLOC__
40 #include "../malloc.h"
41 #endif
42 
43 #include "v.h"
44 #include "cvmacros.h"
45 
46 #include "vpi_user.h"
47 #include "cv_vpi_user.h"
48 
49 /* local prototypes */
50 static int32 lbnam_so_suffix(char *);
51 static int32 check_systf(p_vpi_systf_data, int32 *);
52 static int32 chk_idnam_systfs(char *);
53 static void exec_vpisysfunc_compiletf(struct vpisystf_t *);
54 static void exec_vpisystask_compiletf(struct vpisystf_t *);
55 static struct sy_t *task_add_vpi_systf(char *, int32);
56 static struct sy_t *func_add_vpi_systf(char *, int32);
57 static vpiHandle valchg_cb_register(p_cb_data);
58 static int32 chk_valchg_cb(p_cb_data, struct h_t *);
59 static vpiHandle bld_cbrec(p_cb_data, word32);
60 static void bld_cbvc_dces(struct expr_t *, struct cbrec_t *);
61 static void linkon_cb_dce(struct net_t *, int32, int32, struct gref_t *,
62  struct cbrec_t *, int32);
63 static vpiHandle gateout_valchg_register(struct h_t *, struct t_cb_data *);
64 static void set_dce_strenchg_on(struct dceauxlst_t *);
65 static vpiHandle rf_cb_register(p_cb_data, int32);
66 static int32 chk_rf_cb(p_cb_data, struct h_t *, char *);
67 static vpiHandle rf_all_register_cb(p_cb_data, int32);
68 static vpiHandle delay_cb_register(register p_cb_data);
69 static int32 chk_delay_cb(p_cb_data, struct h_t *);
70 static void exec_vpi_delaycbs(int32);
71 static void free_cbrec(struct cbrec_t *);
72 static vpiHandle action_cb_register(register p_cb_data);
73 static void linkout_allcb(struct cbrec_t *, int32);
74 static void linkout_gateout_cb(struct cbrec_t *);
75 static void linkout_action_cb(struct cbrec_t *);
76 static char *to_cbtypnam(char *, int32);
77 static vpiHandle get_cursystfcall(struct h_t *);
78 static vpiHandle get_inmod_itp(struct h_t *);
79 static vpiHandle get_obj_index(struct h_t *);
80 static vpiHandle get_obj_range(struct h_t *, int32);
81 static vpiHandle get_obj_parent(struct h_t *);
82 static void exprobj_to_itreeloc(struct itree_t **, struct task_t **,
83  struct expr_t *, struct itree_t *, struct task_t *);
84 static vpiHandle get_obj_side(struct h_t *, int32);
85 static vpiHandle bld_scope_par(struct h_t *, struct task_t *);
86 static vpiHandle getbit_lowconn(struct h_t *);
87 static vpiHandle getexpr_lowconn(struct h_t *);
88 static vpiHandle getbit_highconn(struct h_t *);
89 static struct expr_t *find_catxp_frombit(struct expr_t *, int32, int32 *);
90 static vpiHandle getexpr_highconn(struct h_t *);
91 static void no1_1to1h_err(word32, word32, struct h_t *);
92 static void no_1to1h_err(int32, struct h_t *);
93 static vpiHandle get_tchk_term(word32, struct h_t *);
94 static vpiHandle get_cond(struct h_t *);
95 static vpiHandle bld_1to1_exprclass_handle(struct h_t *);
96 static vpiHandle mk_pthterm_exprclass_handle(struct net_t *, int32, int32,
97  struct itree_t *);
98 static vpiHandle get_obj_scope(struct h_t *);
99 static vpiHandle get_disable_scope(struct h_t *);
100 static vpiHandle get_contained_stmt(struct h_t *);
101 static vpiHandle get_dctrl_stmt(struct h_t *, int32);
102 static vpiHandle get_udpdef_from_inobj(struct h_t *);
103 static vpiHandle get_contained_udp_init(struct h_t *);
104 static vpiHandle get_up_poundparam_expr(struct h_t *);
105 static vpiHandle bld_itree_iterator(struct h_t *);
106 static vpiHandle bld_type_iterator(struct h_t *);
107 static vpiHandle bld_inst_iterator(struct h_t *);
108 static vpiHandle bld_udpdef_iterator(struct h_t *);
109 static void mustbe_inmoditer_err(word32, struct h_t *);
110 static vpiHandle bld_scope_iterator(register struct h_t *);
111 static vpiHandle bld_symtabs_iterator(struct symtab_t *, struct itree_t *);
112 static void fill_scopehandle(struct hrec_t *, struct symtab_t *);
113 static vpiHandle bld_net_iterator(struct h_t *, word32);
114 static vpiHandle bld_listofnets_iter(struct net_t *, int32, struct itree_t *,
115  word32, struct task_t *);
116 static int32 cnt_typnetnum(register struct net_t *, int32, word32);
117 
118 
119 static vpiHandle bld_initalw_iterator(struct h_t *);
120 static vpiHandle bld_conta_iterator(struct h_t *);
121 static vpiHandle bld_gate_iterator(struct h_t *);
122 static vpiHandle bld_modpth_iterator(struct h_t *);
123 static vpiHandle bld_tchk_iterator(struct h_t *);
124 static vpiHandle bld_param_iterator(struct h_t *, int32);
125 static vpiHandle bld_listofparams_iter(struct net_t *, int32, struct net_t *,
126  int32, struct itree_t *, struct task_t *);
127 static vpiHandle bld_specparam_iterator(struct h_t *);
128 static vpiHandle bld_defparam_stmt_iterator(struct h_t *);
129 
130 /* NEED? static void shrink_systfdata_tab(void); */
131 static void exec_vpi_actioncbs(int32);
132 static void exec_vpi_tchkerr(int32, struct tchk_t *, struct itree_t *);
133 
134 /* extern prototypes (maybe defined in this module) */
135 extern void __call_vlog_startup_procs(void);
136 extern void __chkbld_vpi_systf_func(struct expr_t *);
137 extern void __chkbld_vpi_systf_task(struct st_t *);
138 extern void __vpi_sysf_calltf(struct expr_t *);
139 extern void __vpi_syst_calltf(struct st_t *);
140 extern char *__cb_reason_to_nam(char *, int32);
141 extern int32 __expr_is_vpiconst(struct expr_t *);
142 extern void __find_call_force_cbs(struct net_t *, int32);
143 extern void __find_call_rel_cbs(struct net_t *, int32);
144 extern void __cb_all_rfs(struct net_t *, int32, int32);
145 extern void __cbvc_callback(struct dcevnt_t *, struct cbrec_t *, struct h_t *);
146 extern void __delay_callback(i_tev_ndx);
147 extern void __vpi_startreset_trycall(void);
148 extern void __vpi_endreset_trycall(void);
149 extern void __vpi_endcomp_trycall(void);
150 extern void __vpi_startsim_trycall(void);
151 extern void __vpi_endsim_trycall(void);
152 extern void __vpi_enteriact_trycall(void);
153 extern void __vpi_exitiact_trycall(void);
154 extern void __vpi_iactscopechg_trycall(void);
155 extern void __vpi_del_nxtsimtim_trycall(void);
156 extern void __vpi_del_rosync_call(void);
157 extern void __vpi_tchkerr_trycall(struct tchk_t *, struct itree_t *);
158 extern void __vpi_error_trycall(void);
159 extern struct task_t *__find_qualnam_task(char *, struct mod_t *,
160  struct task_t *);
161 extern vpiHandle __mk_exprclass_handle(struct expr_t *, struct itree_t *,
162  struct task_t *);
163 extern vpiHandle __mk_handle(word32, void *, struct itree_t *,
164  struct task_t *);
165 extern vpiHandle __mk_stmt_handle(word32, struct st_t *, struct itree_t *,
166  struct task_t *);
167 extern word32 __to_vpi_tasktyp(word32);
168 extern word32 __gate_to_vpiprimtyp(struct gate_t *);
169 extern void __init_hrec(struct hrec_t *);
170 extern struct thread_t *__alloc_thrd(void);
171 extern vpiHandle __nil_iter_err(word32);
172 extern struct pviter_t *__alloc_iter(int32, vpiHandle *);
173 extern word32 __to_vpi_stmttyp(struct st_t **);
174 extern vpiHandle __bld_port_iterator(struct h_t *);
175 extern vpiHandle __bld_neticonn_iter(struct h_t *);
176 extern vpiHandle __bld_paramassign_stmt_iter(struct h_t *);
177 extern vpiHandle __bld_udpline_iter(struct h_t *);
178 extern vpiHandle __bld_primterm_iterator(struct h_t *);
179 extern vpiHandle __bld_loc_lds_iterator(struct h_t *, int32);
180 extern vpiHandle __bld_lds_iterator(struct h_t *, int32);
181 extern vpiHandle __bld_loc_drvs_iterator(struct h_t *, int32);
182 extern vpiHandle __bld_drvs_iterator(struct h_t *, int32);
183 extern vpiHandle __bld_arrwrd_iterator(struct h_t *);
184 extern vpiHandle __bld_bitof_iterator(struct h_t *);
185 extern vpiHandle __bld_systf_iterator(struct h_t *);
186 extern vpiHandle __bld_tfargexpr_iterator(struct h_t *);
187 extern vpiHandle __bld_pthterm_iterator(struct h_t *, word32);
188 extern vpiHandle __bld_stmt_iterator(struct h_t *);
189 extern vpiHandle __bld_netin_tchkterms(struct h_t *);
190 extern vpiHandle __bld_netin_pthterms(struct h_t *);
191 extern vpiHandle __bld_caseitems_iter(struct h_t *);
192 extern vpiHandle __bld_casi_exprs_iter(struct h_t *);
193 extern vpiHandle __bld_operands_iter(struct h_t *);
194 extern vpiHandle __bld_allcbs_iter(struct h_t *);
195 extern vpiHandle __bld_delay_expr_iter(struct h_t *);
196 extern vpiHandle __bld_dig_attr_iter(struct h_t *);
197 extern vpiHandle __bld_iodecl_stmt_iter(struct h_t *);
198 extern vpiHandle __get_digattr_parent(struct h_t *);
199 extern struct itree_t *__find_dfpbot_itp(struct dfparam_t *);
200 
201 extern char *__my_realloc(char *, int32, int32);
202 extern struct systsk_t *__alloc_systsk(void);
203 extern struct tnode_t *__vtfind(char *, struct symtab_t *);
204 extern void __add_sym(char *, struct tnode_t *);
205 extern struct sysfunc_t *__alloc_sysfunc(void);
206 extern int32 __validate_handle(char *, struct h_t *);
207 extern int32 __validate_nonit_handle(char *, struct h_t *);
208 extern void __chg_xstk_width(struct xstk_t *, int32);
209 extern void __grow_xstk(void);
210 extern int32 __wide_vval_is0(register word32 *, int32);
211 extern void __grow_tevtab(void);
212 extern void __sim_notbegun_err(char *);
213 extern int32 __validate_time_type(char *, int32);
214 extern int32 __validate_value_fmt(char *, int32);
215 extern char *__to_vpiopnam(char *, int32);
216 extern void __xmrpush_refgrp_to_targ(struct gref_t *);
217 extern struct dcevnt_t *__alloc_dcevnt(struct net_t *);
218 extern void __alloc_1intdce_prevval(struct dcevnt_t *);
219 extern void __init_1instdce_prevval(struct dcevnt_t *);
220 extern struct task_t *__getcur_scope_tsk(void);
221 extern void __set_vpi_time(struct t_vpi_time *, word64 *, int32, struct mod_t *);
222 extern struct xstk_t *__eval2_xpr(register struct expr_t *);
223 extern int32 __vpitime_to_ticks(word64 *, p_vpi_time, struct mod_t *);
224 extern void __bad_rosync_err(char *);
225 extern void __insert_event(register i_tev_ndx);
226 extern void __my_free(char *, int32);
227 extern char *__my_malloc(int32);
228 extern char *__pv_stralloc(char *);
229 extern void __free_dceauxlst(struct dceauxlst_t *, int32);
230 extern void __free_xtree(struct expr_t *);
231 extern void __free_hp(struct h_t *);
232 extern void __still_comp_err(char *);
233 extern int32 __validate_accessm(char *, int32, char *);
234 extern int32 __unnormalize_ndx(struct net_t *, int32);
235 extern struct expr_t *__bld_rng_numxpr(word32, word32, int32);
236 extern int32 __exprtype_get(struct expr_t *);
237 extern char *__to_vpionam(char *, word32);
238 extern void __getwir_range(struct net_t *, int32 *, int32 *);
239 extern void __getarr_range(struct net_t *, int32 *, int32 *, int32 *);
240 extern char *__to_mpnam(char *, char *);
241 extern int32 __expr_optype_get(struct expr_t *);
242 extern struct sy_t *__get_sym(char *, struct symtab_t *);
243 extern int32 __is_scope_sym(struct sy_t *);
244 extern struct expr_t *__sim_alloc_newxnd(void);
245 extern int32 __comp_ndx(register struct net_t *, register struct expr_t *);
246 extern word32 __from_vpi_vartyp(word32);
247 extern word32 __ntyp_to_vpivarhtyp(struct net_t *);
248 extern word32 __to_vpinetbithtyp(word32);
249 extern struct expr_t *__glbnam_to_expr(char *);
250 extern struct expr_t *__sim_copy_expr(struct expr_t *);
251 extern char *__to_timstr(char *, word64 *);
252 extern void __logic_acc_off(struct gate_t *);
253 extern char *__msg2_blditree(char *, struct itree_t *);
254 extern void __dce_turn_chg_store_on(struct mod_t *, struct dcevnt_t *, int32);
255 extern void __dcelst_off(struct dceauxlst_t *);
256 extern void __alloc_1instdce_prevval(struct dcevnt_t *);
257 
258 extern void __cv_msg(char *, ...);
259 extern void __tr_msg(char *, ...);
260 extern void __pv_err(int32, char *, ...);
261 extern void __pv_warn(int32, char *, ...);
262 extern void __pv_vpi_terr(int32, char *, ...);
263 extern void __inform(int32, char *, ...);
264 
265 extern void __vpi_err(int32, int32, char *, ...);
266 extern void __vpi_terr(char *, int32);
267 
268 extern word32 __masktab[];
269 
270 /* vpi only storage */
271 extern struct t_vpi_error_info *__last_eip;/* if err, ptr to wrk eifo or nil */
272 
273 /*
274  * ROUTINES TO REGISTER VPI STYLE SYS TASKS AND FUNCTIONS
275  */
276 
277 
278 #ifdef __APPLE__
279 #define SO_SUFFIX ".dylib"
280 #else
281 #define SO_SUFFIX ".so"
282 #endif
283 
284 /*
285  * process either load pli1 or load vpi dynamic load option lists
286  *
287  * same dynamic loading for both since bootstrap routine not called here
288  */
__process_pli_dynamic_libs(struct loadpli_t * ldp_hd)289 extern void __process_pli_dynamic_libs(struct loadpli_t *ldp_hd)
290 {
291  register struct loadpli_t *ldp;
292  register struct dynboot_t *dnbp;
293  int32 slen;
294  void *handle;
295  void *boot_rout;
296  char s1[RECLEN], onam[RECLEN];
297 
298  for (ldp = ldp_hd; ldp != NULL; ldp = ldp->load_plinxt)
299   {
300    /* no dynamic library - assume boot routines in other dyn libs */
301    if (ldp->pli1_option) strcpy(onam, "+loadpli1=");
302    else strcpy(onam, "+loadvpi=");
303 
304    /* dynamic lib must be defined or previous error */
305    /* if name does not have .so suffix - try that first */
306    if (!lbnam_so_suffix(ldp->libnam))
307     {
308      strcpy(s1, ldp->libnam);
309      strcat(s1, SO_SUFFIX);
310      if ((handle = dlopen(s1, RTLD_LAZY | RTLD_GLOBAL)) == NULL)
311       {
312        if ((handle = dlopen(ldp->libnam, RTLD_LAZY | RTLD_GLOBAL)) == NULL)
313         {
314          __pv_err(1803,
315           "unable to load %s dynamic library (also tried adding %s suffix): %s",
316           ldp->libnam, SO_SUFFIX, dlerror());
317          continue;
318         }
319       }
320      else
321       {
322        slen = strlen(ldp->libnam) + 1;
323        __my_free(ldp->libnam, slen);
324        ldp->libnam = __pv_stralloc(s1);
325       }
326     }
327    else
328     {
329      /* SJM 11/25/02 - must be now not lazy */
330      if ((handle = dlopen(ldp->libnam, RTLD_LAZY | RTLD_GLOBAL)) == NULL)
331       {
332        __pv_err(1803, "unable to load %s dynamic library: %s",
333          onam, dlerror());
334        continue;
335       }
336     }
337 
338    /* ok to have no boot routines - if so this does nothing */
339    /* because dynblst empty */
340    for (dnbp = ldp->dynblst; dnbp != NULL; dnbp = dnbp->dynbootnxt)
341     {
342 #if defined(__APPLE_CC__) && (__APPLE_CC__ < 1495)
343      /* for Mach (Mac OSX) need to prepend a '_' - old BSD convention */
344      /* LOOKATME - what happens if name already has '_'? */
345      strcpy(s1, "_");
346      strcat(s1, dnbp->bootrout_nam);
347 #else
348      strcpy(s1, dnbp->bootrout_nam);
349 #endif
350      if ((boot_rout = dlsym(handle, s1)) == NULL)
351       {
352        __pv_err(1803, "unable to find %s bootstrap routine in %s: %s",
353         s1, ldp->libnam, dlerror());
354        continue;
355       }
356      if (ldp->pli1_option) dnbp->dynu.tf_rout = boot_rout;
357      else dnbp->dynu.vpi_rout = boot_rout;
358     }
359   }
360 }
361 
362 /*
363  * return T if name has .so suffix (may differ on some systems)
364  */
lbnam_so_suffix(char * lbnam)365 static int32 lbnam_so_suffix(char *lbnam)
366 {
367  int32 suflen;
368  char *cp;
369 
370  if ((cp = rindex(lbnam, '.')) == NULL) return(FALSE);
371  suflen = strlen(SO_SUFFIX);
372  if (strncmp(cp, SO_SUFFIX, suflen) == 0 && strlen(cp) == suflen)
373   return(TRUE);
374  return(FALSE);
375 }
376 
377 /*
378  * if vpi used, this is called
379  */
__call_vlog_startup_procs(void)380 extern void __call_vlog_startup_procs(void)
381 {
382  register struct loadpli_t *ldp;
383  register struct dynboot_t *dnbp;
384 
385  /* SJM 07/08/02 - unless user needs static PLI, this now always empty */
386  __vpi_vlog_start_done = FALSE;
387 #ifdef __STATIC_PLI__
388  {
389   register int32 i;
390 
391   for (i = 0;; i++)
392    {
393     if (vlog_startup_routines[i] == NULL) break;
394     vlog_startup_routines[i]();
395    }
396  }
397 #else
398  /* SJM 07/08/02 - call each dynamic vpi bootstrap routine */
399  /* although normally static cverobj.o not shipped, run after P1364 vpi_ */
400  /* standardized vlog_startup_routines table */
401  for (ldp = __vpi_dynlib_hd; ldp != NULL; ldp = ldp->load_plinxt)
402  {
403   /* vpi boostrap routines are assume to return void - if not ret ignored */
404   for (dnbp = ldp->dynblst; dnbp != NULL;  dnbp = dnbp->dynbootnxt)
405    {
406     if (dnbp->dynu.vpi_rout != NULL) (dnbp->dynu.vpi_rout)();
407    }
408  }
409 #endif
410  __vpi_vlog_start_done = TRUE;
411  /* shrink_systfdata_tab(); */
412 }
413 
414 /*
415  * register a vpi_ systf style user system task or function
416  * this must be done from vlog start routines only or error
417  *
418  * emitting both normal source error and vpi error - needed for two reasons
419  * 1) experts need vpi error when handler registed, 2) novices will not
420  * be able to get error call back or error check code written when initial
421  * registering happens
422  */
vpi_register_systf(p_vpi_systf_data systf_data_p)423 extern vpiHandle vpi_register_systf(p_vpi_systf_data systf_data_p)
424 {
425  int32 stf_ind, systf_typ;
426  p_vpi_systf_data in_systfdatp;
427  struct systftab_t *stftabp;
428  struct systsk_t *stbp;
429  struct sysfunc_t *sfbp;
430  struct sy_t *syp;
431  struct h_t *hp;
432  struct hrec_t *hrp;
433 
434  __last_eip = NULL;
435  if (__vpi_vlog_start_done)
436   {
437 #ifdef __STATIC_PLI__
438    __pv_err(1802,
439     "vpi_register_systf only callable from vlog_startup_routines at start of elaboration");
440 
441    __vpi_err(1802, vpiError,
442     "vpi_register_systf only callable from vlog_startup_routines at start of elaboration");
443 #else
444    __pv_err(1802,
445     "vpi_register_systf from +loadvpi= option only callable at start of elaboration");
446 
447    __vpi_err(1802, vpiError,
448     "vpi_register_systf from +loadvpi= option only callable at start of elaboration");
449 #endif
450    return(NULL);
451   }
452  if (!check_systf(systf_data_p, &systf_typ)) return(NULL);
453 
454  /* allocate initial registered vpi_ systf table if first time */
455  /* numbering starts just after tf_ table */
456  if (__last_systf == __last_veriusertf)
457   {
458    __systftab = (struct systftab_t *)
459     __my_malloc(SYSTFDATSIZE*sizeof(struct systftab_t));
460    __size_systftab = SYSTFDATSIZE;
461   }
462 
463  __last_systf++;
464  /* grow the vpi_ systf table if at end */
465  if ((__last_systf - __last_veriusertf) >= __size_systftab)
466   {
467    int32 osize;
468 
469    osize = __size_systftab*sizeof(struct systftab_t);
470    __size_systftab = 3*(__size_systftab/2);
471    __systftab = (struct systftab_t *) __my_realloc((char *) __systftab, osize,
472     __size_systftab*sizeof(struct systftab_t));
473   }
474  stf_ind = __last_systf - (__last_veriusertf + 1);
475  stftabp = &(__systftab[stf_ind]);
476  /* must copy so caller can free passed data - never need to free since */
477  /* no vpi remove systf */
478  in_systfdatp = (p_vpi_systf_data) __my_malloc(sizeof(struct t_vpi_systf_data));
479 
480  *(in_systfdatp) = *(systf_data_p);
481  /* only field that needs to be copied (reallocated is name) */
482  in_systfdatp->tfname = __pv_stralloc(systf_data_p->tfname);
483  stftabp->vpi_sytfdat = in_systfdatp;
484 
485  if (systf_data_p->type == vpiSysTask)
486   {
487    syp = task_add_vpi_systf(systf_data_p->tfname, __last_systf);
488    stbp = syp->el.esytbp;
489    stftabp->sfu.stbp = stbp;
490   }
491  else
492   {
493    syp = func_add_vpi_systf(systf_data_p->tfname, __last_systf);
494    sfbp = syp->el.esyftbp;
495    stftabp->sfu.sfbp = sfbp;
496    sfbp->tftyp = systf_typ;
497   }
498  stftabp->systf_chk = FALSE;
499  /* systf handles do not go on list since cannot be freed */
500  hp = (struct h_t *) __my_malloc(sizeof(struct h_t));
501  hrp = (struct hrec_t *) __my_malloc(sizeof(struct hrec_t));
502  __init_hrec(hrp);
503  hrp->htyp = vpiUserSystf;
504  /* handle is 1000 + value that is always correct for indexing stftab table */
505  hrp->hi = __last_systf;
506  hp->hrec = hrp;
507  hp->hin_itp = NULL;
508  return((vpiHandle) hp);
509 }
510 
511 /*
512  * check a user passed systf structure
513  * LOOKATME - also maybe warning for real func that has size_t?
514  *
515  * here error message is not vpi_ error since impossible to se
516  *
517  */
check_systf(p_vpi_systf_data systfp,int32 * stftyp)518 static int32 check_systf(p_vpi_systf_data systfp, int32 *stftyp)
519 {
520  *stftyp = SYSF_VPI;
521  if (!chk_idnam_systfs(systfp->tfname)) return(FALSE);
522 
523  if (systfp->type == vpiSysTask)
524   {
525    if (systfp->sizetf != NULL)
526     {
527      __pv_warn(2001,
528       "vpi_register_systf of task %s systf data record has sizetf function - ignored",
529       systfp->tfname);
530 
531      __vpi_err(2001, vpiWarning,
532       "vpi_register_systf of task %s systf data record has sizetf function - ignored",
533       systfp->tfname);
534      systfp->sizetf = NULL;
535     }
536   }
537  else if (systfp->type == vpiSysFunc)
538   {
539    switch (systfp->sysfunctype) {
540     case vpiIntFunc: case vpiRealFunc: case vpiTimeFunc: case vpiSizedFunc:
541      break;
542     default:
543      __vpi_err(1806, vpiError,
544       "vpi_register_systf function %s sysfunctype %d illegal",
545       systfp->tfname, systfp->sysfunctype);
546      return(FALSE);
547     }
548    /* sizetf required for Func Size */
549    if (systfp->sysfunctype == vpiSizedFunc)
550     {
551      if (systfp->sizetf == NULL)
552       {
553        __pv_warn(2028,
554         "vpi_register_systf of function %s systf data record sizetf function missing - using integer size",
555         systfp->tfname);
556 
557       __vpi_err(2028, vpiWarning,
558        "vpi_register_systf of function %s systf data record sizetf function missing - using integer size",
559        systfp->tfname);
560       }
561     }
562    else
563     {
564      /* but ignored for any other */
565      if (systfp->sizetf != NULL)
566       {
567        __pv_warn(2002,
568         "vpi_register_systf of function %s non vpiSizedFunc has sizetf - ignored",
569         systfp->tfname);
570 
571        __vpi_err(2002, vpiWarning,
572         "vpi_register_systf of function %s non vpiSizedFunc has sizetf - ignored",
573         systfp->tfname);
574        systfp->sizetf = NULL;
575       }
576     }
577   }
578  else
579   {
580    __pv_err(1811,
581     "vpi_register_systf task/function %s type %d illegal",
582     systfp->tfname, systfp->type);
583    return(FALSE);
584   }
585  return(TRUE);
586 }
587 
588 /*
589  * check for legal vpi systf task or function name
590  * version supporting vpi style errors
591  */
chk_idnam_systfs(char * tfnam)592 static int32 chk_idnam_systfs(char *tfnam)
593 {
594  register char *chp;
595  int32 len;
596 
597  chp = tfnam;
598  if (chp == NULL || *chp == '\0' || *chp != '$')
599   {
600    __pv_err(1812,
601     "vpi_register_systf data record task or function name %s must begin with '$'",
602     tfnam);
603 
604    __vpi_err(1812, vpiError,
605     "vpi_register_systf data record task or function name %s must begin with '$'",
606     tfnam);
607    return(FALSE);
608   }
609  chp++;
610  for (len = 1; *chp != '\0'; chp++)
611   {
612    /* notice no escaped names here */
613    if (!isalnum(*chp) && *chp != '_' && *chp != '$')
614     {
615      __pv_err(1813,
616       "vpi_register_systf data record task or function name %s contains illegal char %c",
617       tfnam, *chp);
618 
619      __vpi_err(1813, vpiError,
620       "vpi_register_systf data record task or function name %s contains illegal char %c",
621       tfnam, *chp);
622      return(FALSE);
623     }
624    if (++len >= IDLEN)
625     {
626      /* notice cannot truncate since in user memory */
627      __pv_err(1814,
628       "vpi_register_systf data record task or function name %s too long (%d)",
629       tfnam, IDLEN);
630 
631      __vpi_err(1814, vpiError,
632       "vpi_register_systf data record task or function name %s too long (%d)",
633       tfnam, IDLEN);
634      return(FALSE);
635     }
636   }
637  return(TRUE);
638 }
639 
640 
641 /*
642  * add a vpi_ systf pli system task - handles vpi style errors
643  */
task_add_vpi_systf(char * tnam,int32 tnum)644 static struct sy_t *task_add_vpi_systf(char *tnam, int32 tnum)
645 {
646  struct systsk_t *stbp;
647  struct tnode_t *tnp;
648  struct sy_t *syp;
649 
650  /* allocate a systsk_t entry - needed because splicing pli on and */
651  /* need to be able to compile version without */
652  stbp = __alloc_systsk();
653  /* notice cross linking here is right */
654  stbp->stsknam = tnam;
655  stbp->stsknum = tnum;
656  tnp = __vtfind(tnam, __syssyms);
657  if (!__sym_is_new)
658   {
659    syp = tnp->ndp;
660 
661    __inform(2103,
662     "PLI vpi systf task %s replaces predefined or veriusertf system task or function with same name",
663     syp->synam);
664 
665    __vpi_err(2103, vpiNotice,
666     "PLI vpi systf task %s replaces predefined or veriusertf system task or function with same name",
667     syp->synam);
668   }
669  else
670   {
671    __add_sym(tnam, tnp);
672    (__syssyms->numsyms)++;
673    syp = tnp->ndp;
674   }
675  syp->sytyp = SYM_STSK;
676  syp->sydecl = TRUE;
677  syp->el.esytbp = stbp;
678  return(syp);
679 }
680 
681 /*
682  * add a vpi systf task symbol table for registering new systf task
683  */
func_add_vpi_systf(char * fnam,int32 fnum)684 static struct sy_t *func_add_vpi_systf(char *fnam, int32 fnum)
685 {
686  struct tnode_t *tnp;
687  struct sy_t *syp;
688  struct sysfunc_t *sfbp;
689 
690  sfbp = __alloc_sysfunc();
691  /* notice cross linking right here */
692  sfbp->syfnam = fnam;
693  sfbp->syfnum = fnum;
694  /* caller will set this if different */
695  sfbp->tftyp = SYSF_VPI;
696  tnp = __vtfind(fnam, __syssyms);
697  if (!__sym_is_new)
698   {
699    syp = tnp->ndp;
700    __inform(2104,
701     "PLI vpi systf task %s replaces predefined or veriusertf system task or function with same name",
702     syp->synam);
703 
704    __vpi_err(2104, vpiNotice,
705     "PLI vpi systf task %s replaces predefined or veriusertf system task or function with same name",
706     syp->synam);
707   }
708  else
709   {
710    __add_sym(fnam, tnp);
711    (__syssyms->numsyms)++;
712    syp = tnp->ndp;
713   }
714  syp->sytyp = SYM_SF;
715  syp->sydecl = TRUE;
716  syp->el.esyftbp = sfbp;
717  return(syp);
718 }
719 
720 /*
721  * get vpi registered systf info - either call or registered handle allowed
722  * notice internal name string is used - user must not free or write into
723  */
vpi_get_systf_info(vpiHandle object,p_vpi_systf_data systf_data_p)724 extern void vpi_get_systf_info(vpiHandle object,
725  p_vpi_systf_data systf_data_p)
726 {
727  int32 stf_ind;
728  struct h_t *hp;
729  struct hrec_t *hrp;
730  p_vpi_systf_data tfdatp;
731  struct systftab_t *stftabp;
732 
733  __last_eip = NULL;
734  hp = (struct h_t *) object;
735  if (!__validate_handle("vpi_get_systf_info", hp)) return;
736  hrp = hp->hrec;
737  if (hrp->htyp != vpiUserSystf && hrp->htyp != vpiSysFuncCall
738   && hrp->htyp != vpiSysTaskCall)
739   {
740    __vpi_err(1821, vpiError,
741     "vpi_get_systf_info requires vpiUserSystf or vpiSys[Func|Task]Call handle");
742    return;
743   }
744  stf_ind = hrp->hi - (__last_veriusertf + 1);
745  stftabp = &(__systftab[stf_ind]);
746  tfdatp = (p_vpi_systf_data) stftabp->vpi_sytfdat;
747  *(systf_data_p) = *(tfdatp);
748 }
749 
750 /*
751  * final step shrink table to right size and adjust last values
752  */
753 /* --- LOOKATME - think can not use this
754 static void shrink_systfdata_tab(void)
755 {
756  int32 num_systfs, osize, nsize;
757 
758  -* maybe none *-
759  if (__last_systf == -1) return;
760 
761  num_systfs = __last_systf - __last_veriusertf;
762  if (num_systfs > 0 && __verbose)
763   {
764    __cv_msg(
765     "  %d vpi_register_systf user system tasks and functions registered.\n",
766     num_systfs);
767   }
768  if (num_systfs < __size_systftab)
769   {
770    osize = __size_systftab*sizeof(struct systftab_t);
771    nsize = num_systfs*sizeof(struct systftab_t);
772    __systftab = (struct systftab_t *) __my_realloc((char *) __systftab, osize,
773     nsize);
774   }
775 }
776 --- */
777 
778 /*
779  * ROUTINES TO EXECUTE VPI COMPILETF AND CHECKTF IF FIRST TIME SEEN
780  */
781 
782 /*
783  * check a systfs user function and call sizetf and compiletf if present
784  * only called first time function seen (i.e. once per source location)
785  */
__chkbld_vpi_systf_func(struct expr_t * fcallx)786 extern void __chkbld_vpi_systf_func(struct expr_t *fcallx)
787 {
788  int32 stf_ind;
789  struct sy_t *syp;
790  struct sysfunc_t *syfp;
791  struct systftab_t *stftabp;
792  p_vpi_systf_data stfdp;
793  struct vpisystf_t *vstfp;
794  int32 (*sizetf_func)();
795 
796  syp = fcallx->lu.x->lu.sy;
797  syfp = syp->el.esyftbp;
798  stf_ind = syfp->syfnum - (__last_veriusertf + 1);
799  stftabp = &(__systftab[stf_ind]);
800  stfdp = (p_vpi_systf_data) stftabp->vpi_sytfdat;
801 
802  /* SJM 04/14/04 - following PLI 1.0, can use the sysf lu.x ptr to sy */
803  /* field for the per call in source user data settable/readable fld */
804  fcallx->lu.x->szu.vpi_sysf_datap = NULL;
805 
806  /* if has vpi registered systf compiletf, must put on list so can call */
807  /* just before end of compile (when vpi_ d.s. built) point */
808  if (stfdp->compiletf != NULL)
809   {
810    vstfp = (struct vpisystf_t *) __my_malloc(sizeof(struct vpisystf_t));
811    vstfp->is_sysfunc = TRUE;
812    vstfp->vstffnam_ind = __sfnam_ind;
813    vstfp->vstflin_cnt = __slin_cnt;
814    vstfp->curmdp = __inst_mod;
815    vstfp->curtskp = __cur_tsk;
816    vstfp->vsystfu.sysfcallx = fcallx;
817 
818    /* link onto front */
819    vstfp->vpistfnxt = __vpi_sysf_hdr;
820    __vpi_sysf_hdr = vstfp;
821   }
822 
823  /* do not need to set expr. node width - if called before*/
824  if (stftabp->systf_chk) return;
825 
826  /* must run sizetf with no environment since still compiling */
827  __cur_sysf_expr = NULL;
828  switch (stfdp->sysfunctype) {
829   case vpiIntFunc:
830    syfp->retntyp = N_INT;
831    syfp->retsigned = TRUE;
832    syfp->retwid = WBITS;
833    fcallx->has_sign = TRUE;
834    break;
835   case vpiRealFunc:
836    syfp->retntyp = N_REAL;
837    syfp->retsigned = TRUE;
838    /* special width or real since no x/z */
839    syfp->retwid = WBITS;
840    fcallx->is_real = TRUE;
841    fcallx->has_sign = TRUE;
842    break;
843   case vpiTimeFunc:
844    syfp->retntyp = N_TIME;
845    syfp->retsigned = FALSE;
846    syfp->retwid = TIMEBITS;
847    break;
848   case vpiSizedFunc:
849    syfp->retntyp = N_REG;
850    syfp->retsigned = FALSE;
851 
852    /* if sizetf not set warning was emited and use 32 (WBITS) */
853    if ((sizetf_func = stfdp->sizetf) == NULL) syfp->retwid = WBITS;
854    else syfp->retwid = (*sizetf_func)(stfdp->user_data);
855 
856    break;
857   default: __vpi_terr(__FILE__, __LINE__);
858  }
859  fcallx->szu.xclen = syfp->retwid;
860  stftabp->systf_chk = TRUE;
861 }
862 
863 /*
864  * check a systfs user task and link on to compiletf list if needed
865  * only called first time task seen at each source loc. (not per inst)
866  *
867  * never see sizetf here
868  */
__chkbld_vpi_systf_task(struct st_t * stp)869 extern void __chkbld_vpi_systf_task(struct st_t *stp)
870 {
871  int32 stf_ind;
872  struct systsk_t *stbp;
873  struct systftab_t *stftabp;
874  p_vpi_systf_data stfdp;
875  struct vpisystf_t *vstfp;
876  struct tskcall_t *tkcp;
877 
878  tkcp = &(stp->st.stkc);
879  stbp = tkcp->tsksyx->lu.sy->el.esytbp;
880 
881  stf_ind = stbp->stsknum - (__last_veriusertf + 1);
882  stftabp = &(__systftab[stf_ind]);
883  stfdp = (p_vpi_systf_data) stftabp->vpi_sytfdat;
884 
885  /* SJM 04/14/04 - following PLI 1.0, can use the syst task_t tkcaux ptr */
886  /* field for the per call in source user data settable/readable fld */
887  tkcp->tkcaux.vpi_syst_datap = NULL;
888 
889  /* if has vpi registered systf compiletf, must pu on list so can call */
890  /* just before end of compile (when vpi_ d.s. built) point */
891  if (stfdp->compiletf != NULL)
892   {
893    vstfp = (struct vpisystf_t *) __my_malloc(sizeof(struct vpisystf_t));
894    vstfp->is_sysfunc = FALSE;
895    vstfp->vstffnam_ind = __sfnam_ind;
896    vstfp->vstflin_cnt = __slin_cnt;
897    vstfp->curmdp = __inst_mod;
898    vstfp->curtskp = __cur_tsk;
899    vstfp->vsystfu.syststp = stp;
900    /* link onto front of sys task list */
901    vstfp->vpistfnxt = __vpi_syst_hdr;
902    __vpi_syst_hdr = vstfp;
903   }
904  stftabp->systf_chk = TRUE;
905 }
906 
907 /*
908  * ROUTINES TO EXECUTE VPI SYSTF COMPILETF
909  */
910 
911 /*
912  * execute every vpi registered systf compiletf routine
913  *
914  * notice because of xform for code gen - these can't be used after here
915  * LOOKATME - memory leak because could be freed and only accessible through
916  * header and list
917  */
__exec_all_compiletf_routines(void)918 extern void __exec_all_compiletf_routines(void)
919 {
920  register struct vpisystf_t *vstfp;
921 
922  for (vstfp = __vpi_sysf_hdr; vstfp != NULL; vstfp = vstfp->vpistfnxt)
923   exec_vpisysfunc_compiletf(vstfp);
924 
925  for (vstfp = __vpi_syst_hdr; vstfp != NULL; vstfp = vstfp->vpistfnxt)
926   exec_vpisystask_compiletf(vstfp);
927 }
928 
929 /*
930  * execute the vpi systf system function compiletf routine
931  *
932  * like calltf but does not return anything and must build own context since
933  * nothing executing at this time so need thd and itree (first) env.
934  * also need task on stack if inside task or function
935  *
936  * LOOKATME is there ever a problem calling with first inst?
937  */
exec_vpisysfunc_compiletf(struct vpisystf_t * vstfp)938 static void exec_vpisysfunc_compiletf(struct vpisystf_t *vstfp)
939 {
940  int32 stf_ind;
941  struct sysfunc_t *sfbp;
942  struct systftab_t *stftabp;
943  p_vpi_systf_data stfdp;
944  struct thread_t *thp, *sav_cur_thd;
945  int32 (*vpicomptf_func)();
946 
947  sfbp = vstfp->vsystfu.sysfcallx->lu.x->lu.sy->el.esyftbp;
948  stf_ind = sfbp->syfnum - (__last_veriusertf + 1);
949  stftabp = &(__systftab[stf_ind]);
950  stfdp = (p_vpi_systf_data) stftabp->vpi_sytfdat;
951  __cur_sysf_expr = vstfp->vsystfu.sysfcallx;
952 
953  vpicomptf_func = stfdp->compiletf;
954  __vpifnam_ind = vstfp->vstffnam_ind;
955  __vpilin_cnt = vstfp->vstflin_cnt;
956  __push_itstk(vstfp->curmdp->moditps[0]);
957 
958  /* need dummy thread - still if user tried to use tf_stop think will crash */
959  thp = __alloc_thrd();
960  thp->thenbl_sfnam_ind = 0;
961  thp->thenbl_slin_cnt = 0;
962  thp->thnxtstp = NULL;
963  thp->thpar = NULL;
964  /* think should never have a current thread here */
965  sav_cur_thd = __cur_thd;
966  __cur_thd = thp;
967 
968  if (vstfp->curtskp != NULL)
969   {
970    /* DBG remove --- */
971    if (__fcspi != -1) __vpi_terr(__FILE__, __LINE__);
972    /* --- */
973    __fcstk[++__fcspi] = vstfp->curtskp;
974   }
975 
976  /* notice global __sf location values are rigth for call loc. */
977  (*vpicomptf_func)(stfdp->user_data);
978 
979  if (vstfp->curtskp != NULL) __fcspi--;
980  __cur_thd = sav_cur_thd;
981  __my_free((char *) thp, sizeof(struct thread_t));
982  __pop_itstk();
983  __cur_sysf_expr = NULL;
984  __vpifnam_ind = 0;
985  __vpilin_cnt = 0;
986 }
987 
988 /*
989  * execute the vpi systf system task compiletf routine
990  *
991  * like calltf but does not return anything and must build own context since
992  * nothing executing at this time so need thd and itree (first) env.
993  * also need task on stack if inside task or function
994  *
995  * LOOKATME is there ever a problem calling with first inst?
996  */
exec_vpisystask_compiletf(struct vpisystf_t * vstfp)997 static void exec_vpisystask_compiletf(struct vpisystf_t *vstfp)
998 {
999  int32 stf_ind;
1000  struct systsk_t *stbp;
1001  struct systftab_t *stftabp;
1002  p_vpi_systf_data stfdp;
1003  struct thread_t *thp, *sav_cur_thd;
1004  struct st_t *stp;
1005  int32 (*vpicomptf_tsk)();
1006 
1007  stp = vstfp->vsystfu.syststp;
1008  stbp = stp->st.stkc.tsksyx->lu.sy->el.esytbp;
1009  stf_ind = stbp->stsknum - (__last_veriusertf + 1);
1010  stftabp = &(__systftab[stf_ind]);
1011  stfdp = (p_vpi_systf_data) stftabp->vpi_sytfdat;
1012  __cur_syst_stp = stp;
1013 
1014  vpicomptf_tsk = stfdp->compiletf;
1015  __vpifnam_ind = __sfnam_ind;
1016  __vpilin_cnt = __slin_cnt;
1017 
1018  __push_itstk(vstfp->curmdp->moditps[0]);
1019 
1020  /* need dummy thread - still if user tried to use tf_stop think will crash */
1021  thp = __alloc_thrd();
1022  thp->thenbl_sfnam_ind = 0;
1023  thp->thenbl_slin_cnt = 0;
1024  thp->thnxtstp = NULL;
1025  thp->thpar = NULL;
1026  /* think should never have a current thread here */
1027  sav_cur_thd = __cur_thd;
1028  __cur_thd = thp;
1029 
1030  if (vstfp->curtskp != NULL)
1031   {
1032    /* DBG remove --- */
1033    if (__fcspi != -1) __vpi_terr(__FILE__, __LINE__);
1034    /* --- */
1035    __fcstk[++__fcspi] = vstfp->curtskp;
1036   }
1037 
1038  /* set systf for get handle and nil handle user must call vpi put value */
1039  (*vpicomptf_tsk)(stfdp->user_data);
1040 
1041  if (vstfp->curtskp != NULL) __fcspi--;
1042  __cur_thd = sav_cur_thd;
1043  __my_free((char *) thp, sizeof(struct thread_t));
1044  __pop_itstk();
1045  __cur_syst_stp = NULL;
1046  __vpifnam_ind = 0;
1047  __vpilin_cnt = 0;
1048 }
1049 
1050 /*
1051  * ROUTINES TO EXECUTE VPI SYSTF CALLTF
1052  */
1053 
1054 /*
1055  * execute the vpi systf system function calltf routine
1056  * this pushes return value on top of expr. stack but does not return it
1057  * uses the instance tree loc. called from
1058  *
1059  * notice required replacement of built-in names happens because
1060  * symbol table symbol gets replaced
1061  */
__vpi_sysf_calltf(struct expr_t * fcallx)1062 extern void __vpi_sysf_calltf(struct expr_t *fcallx)
1063 {
1064  int32 stf_ind;
1065  struct sysfunc_t *sfbp;
1066  struct xstk_t *xsp;
1067  struct systftab_t *stftabp;
1068  p_vpi_systf_data stfdp;
1069  int32 (*vpicalltf_func)();
1070 
1071  sfbp = fcallx->lu.x->lu.sy->el.esyftbp;
1072  stf_ind = sfbp->syfnum - (__last_veriusertf + 1);
1073  stftabp = &(__systftab[stf_ind]);
1074  stfdp = (p_vpi_systf_data) stftabp->vpi_sytfdat;
1075  __cur_sysf_expr = fcallx;
1076 
1077  /* set systf for get handle and nil handle user must call vpi_put_value */
1078  push_xstk_(xsp, stftabp->sfu.sfbp->retwid);
1079  one_allbits_(xsp->ap, xsp->xslen);
1080  one_allbits_(xsp->bp, xsp->xslen);
1081  __cur_sysf_xsp = xsp;
1082 
1083  /* LOOKATME - maybe need warning if nil */
1084  if ((vpicalltf_func = stfdp->calltf) == NULL) { return; }
1085  __vpifnam_ind = __sfnam_ind;
1086  __vpilin_cnt = __slin_cnt;
1087 
1088  /* notice global __sf location values are rigth for call loc. */
1089  (*vpicalltf_func)(stfdp->user_data);
1090 
1091  __cur_sysf_xsp = NULL;
1092  __cur_sysf_expr = NULL;
1093  __vpifnam_ind = 0;
1094  __vpilin_cnt = 0;
1095 }
1096 
1097 /*
1098  * call the pli tf system task calltf routine
1099  */
__vpi_syst_calltf(struct st_t * stp)1100 extern void __vpi_syst_calltf(struct st_t *stp)
1101 {
1102  int32 stf_ind;
1103  struct systsk_t *stbp;
1104  struct systftab_t *stftabp;
1105  p_vpi_systf_data stfdp;
1106  int32 (*vpicalltf_tsk)();
1107 
1108  stbp = stp->st.stkc.tsksyx->lu.sy->el.esytbp;
1109  stf_ind = stbp->stsknum - (__last_veriusertf + 1);
1110  stftabp = &(__systftab[stf_ind]);
1111  stfdp = (p_vpi_systf_data) stftabp->vpi_sytfdat;
1112  __cur_syst_stp = stp;
1113 
1114  /* LOOKATME - maybe need warning if nil */
1115  if ((vpicalltf_tsk = stfdp->calltf) == NULL) return;
1116 
1117  __vpifnam_ind = __sfnam_ind;
1118  __vpilin_cnt = __slin_cnt;
1119  /* set systf for get handle and nil handle user must call vpi put value */
1120  (*vpicalltf_tsk)(stfdp->user_data);
1121 
1122  __cur_syst_stp = NULL;
1123  __vpifnam_ind = 0;
1124  __vpilin_cnt = 0;
1125 }
1126 
1127 /*
1128  * ROUTINES TO IMPLEMENT VPI CALLBACKS
1129  */
1130 
1131 /*
1132  * register a callback
1133  *
1134  * this can add non delay or val change call backs before sim begins
1135  */
vpi_register_cb(p_cb_data cb_data_p)1136 extern vpiHandle vpi_register_cb(p_cb_data cb_data_p)
1137 {
1138  __last_eip = NULL;
1139 
1140  if (cb_data_p->cb_rtn == NULL)
1141   {
1142    __vpi_err(1810, vpiError,
1143     "vpi_register_cb no effect - no call back routine (cb_rtn field NULL)");
1144    return(NULL);
1145   }
1146 
1147  /* needs built net list */
1148  /* cannot check handle until call back type */
1149  switch (cb_data_p->reason) {
1150   /* value change cbs */
1151   case cbValueChange:
1152    if (__run_state != SS_SIM)
1153     {
1154 no_sim:
1155       __sim_notbegun_err("vpi_register_cb");
1156       return(NULL);
1157     }
1158    return(valchg_cb_register(cb_data_p));
1159   case cbForce: case cbRelease:
1160    if (__run_state != SS_SIM) goto no_sim;
1161    return(rf_cb_register(cb_data_p, cb_data_p->reason));
1162   /* delayed wake up cbs */
1163   case cbReadWriteSynch: case cbReadOnlySynch:
1164   case cbNextSimTime: case cbAfterDelay:
1165    if (__run_state != SS_SIM) goto no_sim;
1166    /* schedule a delay callback - reason determines how scheduled */
1167    return(delay_cb_register(cb_data_p));
1168   /* fixed routine call cbs - can be register before start of sim */
1169   case cbEndOfCompile: case cbStartOfSimulation: case cbEndOfSimulation:
1170   case cbError: case cbPLIError:
1171   case cbTchkViolation: case cbStartOfReset:
1172   case cbEndOfReset: case cbEnterInteractive: case cbExitInteractive:
1173   case cbInteractiveScopeChange:
1174   case cbLanguageLine:
1175     return(action_cb_register(cb_data_p));
1176   case cbAtStartOfSimTime: return(delay_cb_register(cb_data_p));
1177 
1178   /* currently unimplemented */
1179   case cbStartOfSave: case cbEndOfSave: case cbStartOfRestart:
1180   case cbEndOfRestart: case cbUnresolvedSystf:
1181    __vpi_err(1823, vpiError, "vpi_register_cb reason %s unsupported",
1182     __cb_reason_to_nam(__wrks1, cb_data_p->reason));
1183    return(NULL);
1184   case cbStmt:
1185    /* after move time, execute event from special list */
1186    __vpi_err(1823, vpiError,
1187     "vpi_register_cb reason %s unsupported - not yet implemented",
1188     __cb_reason_to_nam(__wrks1, cb_data_p->reason));
1189    return(NULL);
1190   default:
1191    __vpi_err(1824, vpiError,
1192     "vpi_register_cb illegal reason value %d - no callback registered",
1193      cb_data_p->reason);
1194  }
1195  return(NULL);
1196 }
1197 
1198 /*
1199  * convert a callback reason to a name
1200  */
__cb_reason_to_nam(char * s,int32 reason)1201 extern char *__cb_reason_to_nam(char *s, int32 reason)
1202 {
1203  switch (reason) {
1204   case cbValueChange: strcpy(s, "cbValueChange"); break;
1205   case cbStmt: strcpy(s, "cbStmt"); break;
1206   case cbForce: strcpy(s, "cbForce"); break;
1207   case cbRelease: strcpy(s, "cbRelease"); break;
1208   case cbAtStartOfSimTime: strcpy(s, "cbAtStartOfSimTime"); break;
1209   case cbReadWriteSynch: strcpy(s, "cbReadWriteSynch"); break;
1210   case cbReadOnlySynch: strcpy(s, "cbReadOnlySynch"); break;
1211   case cbNextSimTime: strcpy(s, "cbNextSimTime"); break;
1212   case cbAfterDelay: strcpy(s, "cbAfterDelay"); break;
1213   case cbEndOfCompile: strcpy(s, "cbEndOfCompile"); break;
1214   case cbStartOfSimulation: strcpy(s, "cbStartOfSimulation"); break;
1215   case cbEndOfSimulation: strcpy(s, "cbEndOfSimulation"); break;
1216   case cbError: strcpy(s, "cbError"); break;
1217   case cbPLIError: strcpy(s, "cbPLIError"); break;
1218   case cbTchkViolation: strcpy(s, "cbTchkViolation"); break;
1219   case cbStartOfReset: strcpy(s, "cbStartOfReset"); break;
1220   case cbEndOfReset: strcpy(s, "cbEndOfReset"); break;
1221   case cbEnterInteractive: strcpy(s, "cbEnterInteractive"); break;
1222   case cbExitInteractive: strcpy(s, "cbExitInteractive"); break;
1223   case cbInteractiveScopeChange:
1224    strcpy(s, "cbInteractiveScopeChange");
1225    break;
1226   case cbUnresolvedSystf: strcpy(s, "cbUnresolvedSystf"); break;
1227   case cbStartOfSave: strcpy(s, "cbStartOfSave"); break;
1228   case cbEndOfSave: strcpy(s, "cbEndOfSave"); break;
1229   case cbStartOfRestart: strcpy(s, "cbStartOfRestart"); break;
1230   case cbEndOfRestart: strcpy(s, "cbEndOfRestart"); break;
1231   case cbLanguageLine: strcpy(s, "cbLanguageLine"); break;
1232   default:
1233    /* checking must be elsewhere */
1234    strcpy(s, "**illegal**");
1235  }
1236  return(s);
1237 }
1238 
1239 /*
1240  * setup (register) the value change callback
1241  *
1242  * LOOKATME - think call backs for events not possible
1243  *
1244  * interpreting LRM to only allow value change call backs on members of
1245  * expression class (can come from to <expr. class> or contents of mod/task)
1246  *
1247  * LRM says term but interpreting term as "expr. of term" where must then go
1248  * through loads to find needed term - alternative could actually pass term
1249  * such as prim (gate), tchk, path, and more? but not for now
1250  */
valchg_cb_register(p_cb_data cb_data_p)1251 static vpiHandle valchg_cb_register(p_cb_data cb_data_p)
1252 {
1253  int32 biti;
1254  vpiHandle cbref, ihref;
1255  struct h_t *hp, *hp2;
1256  struct hrec_t *hrp;
1257  struct net_t *np;
1258  struct expr_t *xp;
1259  struct gate_t *gp;
1260 
1261  hp = (struct h_t *) cb_data_p->obj;
1262  if (!chk_valchg_cb(cb_data_p, hp)) return(NULL);
1263  hrp = hp->hrec;
1264  __cbvc_dcehdr = NULL;
1265  __push_itstk(hp->hin_itp);
1266  switch (hrp->htyp) {
1267   case vpiNet: case vpiReg: case vpiIntegerVar: case vpiTimeVar:
1268    np = hrp->hu.hnp;
1269    cbref = bld_cbrec(cb_data_p, CB_VALCHG);
1270    hp2 = (struct h_t *) cbref;
1271    linkon_cb_dce(np, -1, -1, NULL, hp2->hrec->hu.hcbp, DCE_CBVC);
1272    break;
1273   case vpiNamedEvent:
1274    /* FIXME - think need to support change call back on events */
1275    np = hrp->hu.hnp;
1276    /* DBG remove -- */
1277    if (np->ntyp != N_EVENT) __vpi_terr(__FILE__, __LINE__);
1278    /* --- */
1279    /* can not place change call back on event since no value? */
1280    __vpi_err(2024, vpiWarning,
1281     "vpi_register_cb value change form for vpiNamedEvent %s object unsupported",
1282     np->nsym->synam);
1283    goto bad_end;
1284   case vpiNetBit: case vpiRegBit: case vpiVarSelect: case vpiMemoryWord:
1285    /* know parent object is a vector or will not get here */
1286    if (!hrp->bith_ndx) { xp = hrp->hu.hxp; goto bit_expr_form; }
1287 
1288    np = hrp->hu.hnp;
1289    cbref = bld_cbrec(cb_data_p, CB_VALCHG);
1290    hp2 = (struct h_t *) cbref;
1291    /* always need to set this so callback cb_data field has change index */
1292    hp2->hrec->hu.hcbp->cb_ndxobj = TRUE;
1293 
1294    /* for vectored vectors or array - no individual bit/array cell identity */
1295    /* LOOKATME - can callbacks be placed on individual cells of arrays? */
1296    if (!np->vec_scalared || hrp->htyp == vpiMemoryWord) biti = -1;
1297    else biti = hrp->hi;
1298 
1299    /* index stored as normalized h:0 */
1300    /* must filter bit or array index */
1301    linkon_cb_dce(np, biti, biti, NULL, hp2->hrec->hu.hcbp, DCE_CBVC);
1302    break;
1303   case vpiRealVar: case vpiConstant:
1304    /* no call back allowed on real variable or constant */
1305    __vpi_err(1836, vpiError,
1306     "vpi_register_cb real value change object %s illegal",
1307     __to_vpionam(__wrks1, hrp->htyp));
1308 bad_end:
1309    __pop_itstk();
1310    return(NULL);
1311   case vpiPartSelect: case vpiFuncCall: case vpiSysFuncCall:
1312   case vpiOperation:
1313    xp = hrp->hu.hxp;
1314 bit_expr_form:
1315    /* normal rhs expression for which value change monitoring possible */
1316    cbref = bld_cbrec(cb_data_p, CB_VALCHG);
1317    hp2 = (struct h_t *) cbref;
1318    /* LSB for both bit select and array index */
1319    hp2->hrec->hu.hcbp->cb_ndxobj = (xp->optyp == LSB) ? TRUE : FALSE;
1320    bld_cbvc_dces(xp, hp2->hrec->hu.hcbp);
1321    break;
1322   case vpiPrimTerm:
1323    /* SJM 11/22/00 - add ability to put call backs on non tran/pull */
1324    /* gate outputs */
1325    gp = hrp->hu.hgp;
1326    /* for tran/pull put call back on expr - can go on either */
1327    if (gp->g_class == GC_PULL || gp->g_class == GC_TRAN
1328     || gp->g_class == GC_TRANIF)
1329     {
1330      if (gp->g_class == GC_TRANIF && hrp->hi == 2)
1331       {
1332        __vpi_err(1912, vpiError,
1333         "vpi_register_cb of value change for vpiPrimTerm (pos. %d) of %s.%s illegal input - only output or inout allowed",
1334         hrp->hi + 1, __msg2_blditree(__xs, hp->hin_itp), gp->gsym->synam);
1335        goto bad_end;
1336       }
1337      xp = hrp->hu.hgp->gpins[hrp->hi];
1338      /* SJM 11/28/00 - also must change handle to terminal index handle */
1339      ihref = __mk_exprclass_handle(xp, hp->hin_itp, hrp->hin_tskp);
1340      /* LOOKATME - must replace cb object passed by user to make this work */
1341      cb_data_p->obj = ihref;
1342      hp = (struct h_t *) ihref;
1343      hrp = hp->hrec;
1344      goto bit_expr_form;
1345     }
1346    /* if value monitoring used, must be strength - call backs always */
1347    /* monitor strengths for mos/cmos gates and never for others */
1348    if (gp->g_class == GC_LOGIC || gp->g_class == GC_UDP)
1349     {
1350      if (cb_data_p->value != NULL
1351       && cb_data_p->value->format == vpiStrengthVal)
1352       {
1353        __vpi_err(2055, vpiWarning,
1354        "vpi_register_cb primtive output value change form for logic/udp gate %s.%s strength never changes but format value vpiStrengthVal",
1355         __msg2_blditree(__xs, hp->hin_itp), gp->gsym->synam);
1356       }
1357     }
1358    else
1359     {
1360      if (cb_data_p->value != NULL
1361       && cb_data_p->value->format != vpiStrengthVal)
1362       {
1363        __vpi_err(2055, vpiWarning,
1364        "vpi_register_cb primtive output value change form for mos/bufif gate %s.%s always called for strength changes but format value non strength",
1365         __msg2_blditree(__xs, hp->hin_itp), gp->gsym->synam);
1366       }
1367     }
1368    cbref = gateout_valchg_register(hp, cb_data_p);
1369    break;
1370   default:
1371    __vpi_err(1839, vpiError,
1372     "vpi_register_cb object %s illegal for cbValueChange reason",
1373     __to_vpionam(__wrks1, hrp->htyp));
1374    goto bad_end;
1375  }
1376  __pop_itstk();
1377 
1378  /* succeeded link dce's onto list associated with this cb for removing */
1379  hp2 = (struct h_t *) cbref;
1380  /* link on list because may be multiple for different nets from expr */
1381  hp2->hrec->hu.hcbp->cbdcep = __cbvc_dcehdr;
1382  /* SJM - 05/23/00 - if stren format, for each stren net off no mon stren */
1383  if (hp2->hrec->hu.hcbp->cb_retvalfmt == vpiStrengthVal)
1384   {
1385    set_dce_strenchg_on(__cbvc_dcehdr);
1386   }
1387 
1388  __cbvc_dcehdr = NULL;
1389  return(cbref);
1390 }
1391 
1392 /*
1393  * check value change callback passed cb_data record
1394  */
chk_valchg_cb(p_cb_data cb_data_p,struct h_t * hp)1395 static int32 chk_valchg_cb(p_cb_data cb_data_p, struct h_t *hp)
1396 {
1397  if (!__validate_nonit_handle("vpi_register_cb (value change obj)", hp))
1398   return(FALSE);
1399  if (cb_data_p->time == NULL)
1400   {
1401    __vpi_err(1850, vpiError,
1402     "vpi_register_cb cbValueChange p_cb_data record required time field empty");
1403    return(FALSE);
1404   }
1405  if (cb_data_p->value == NULL)
1406   {
1407    __vpi_err(1931, vpiError,
1408     "vpi_register_cb cbValueChange p_cb_data record required value field empty");
1409    return(FALSE);
1410   }
1411 
1412  /* validate time format and value format */
1413  if (!__validate_time_type("vpi_register_cb cbValueChange",
1414   cb_data_p->time->type)) return(FALSE);
1415  if (!__validate_value_fmt("vpi_register_cb cbValueChange",
1416   cb_data_p->value->format)) return(FALSE);
1417  return(TRUE);
1418 }
1419 
1420 /*
1421  * build a call back record and build associated handle
1422  *
1423  * notice need handle for cb remove and dce points to cbrec
1424  * if call back handle is freed, no way to remove call back
1425  *
1426  * know value and time fields point to records or will not get here
1427  */
bld_cbrec(p_cb_data cb_data_p,word32 cbclass)1428 static vpiHandle bld_cbrec(p_cb_data cb_data_p, word32 cbclass)
1429 {
1430  vpiHandle cbref;
1431  struct cbrec_t *cbp;
1432  struct h_t *hp, *hp2;
1433  struct hrec_t *hrp2;
1434  struct gate_t *gp;
1435 
1436  /* no need to init because user always creates and passes */
1437  cbp = (struct cbrec_t *) __my_malloc(sizeof(struct cbrec_t));
1438  cbp->cb_reason = cb_data_p->reason;
1439  cbp->cb_class = cbclass;
1440  cbp->cb_ndxobj = FALSE;
1441  /* SJM 07/24/00 - call backs can be set off by user using sim control */
1442  cbp->cb_user_off = FALSE;
1443  cbp->cb_gateout = FALSE;
1444  /* if object passed must copy handle so user can free or reuse */
1445  if (cb_data_p->obj != NULL)
1446   {
1447    /* user can now free or reuse object */
1448    hp = (struct h_t *) cb_data_p->obj;
1449    /* this is same as copy object */
1450    hp2 = (struct h_t *) __mk_handle(hp->hrec->htyp, NULL, NULL, NULL);
1451    hp2->hin_itp = hp->hin_itp;
1452    hrp2 = hp2->hrec;
1453    *(hrp2) = *(hp->hrec);
1454    /* if copy from iterator, no longer in iterator */
1455    hrp2->in_iter = FALSE;
1456    if (hrp2->free_xpr) hrp2->hu.hxp = __sim_copy_expr(hp->hrec->hu.hxp);
1457    cbp->cb_hp = hp2;
1458   }
1459  else cbp->cb_hp = NULL;
1460 
1461  cbp->cb_rtn = cb_data_p->cb_rtn;
1462  cbp->cb_user_data = cb_data_p->user_data;
1463 
1464  if (cb_data_p->time != NULL)
1465   cbp->cb_rettimtyp = (word32) cb_data_p->time->type;
1466  else cbp->cb_rettimtyp = vpiSuppressTime;
1467 
1468  if (cb_data_p->value != NULL)
1469   cbp->cb_retvalfmt = (word32) cb_data_p->value->format;
1470  else cbp->cb_retvalfmt = vpiSuppressVal;
1471  cbp->cbdcep = NULL;
1472  cbp->cbtevpi = -1;
1473 
1474  /* link on to front design wide list */
1475  if (__vpi_cbrec_hdr == NULL)
1476   { __vpi_cbrec_hdr = cbp; cbp->cbnxt = cbp->cbprev = NULL; }
1477  else
1478   {
1479    cbp->cbnxt = __vpi_cbrec_hdr;
1480    cbp->cbnxt->cbprev = cbp;
1481    cbp->cbprev = NULL;
1482    __vpi_cbrec_hdr = cbp;
1483   }
1484  /* callback handles never have itree loc, but obj might */
1485  cbref = __mk_handle(vpiCallback, (void *) cbp, NULL, NULL);
1486  cbp->cb_cbhp = (struct h_t *) cbref;
1487 
1488  /* 11/28/00 - special processing for gate out term cb */
1489  /* BEWARE - must turn off optimization on fly when gate out */
1490  /* terminal call back is acclerated output of logic gate */
1491  /* only need to turn off for logic gates */
1492  /* problem here is that this is only value change call back */
1493  /* that can't use net scheduling mechanism but must be checked for */
1494  if (cbp->cb_gateout)
1495   {
1496    gp = cbp->cb_hp->hrec->hu.hgp;
1497    if (gp->g_class == GC_LOGIC) __logic_acc_off(gp);
1498   }
1499 
1500  return(cbref);
1501 }
1502 
1503 /*
1504  * build and link on special cb val chg change dce for one callback
1505  * xp is expr. - if simple expr. (reg/wire handle not expr)
1506  *
1507  * here because variable index becomes entire range all indices are
1508  * already normalized h:0 constants
1509  */
bld_cbvc_dces(struct expr_t * xp,struct cbrec_t * cbp)1510 static void bld_cbvc_dces(struct expr_t *xp, struct cbrec_t *cbp)
1511 {
1512  struct net_t *np;
1513  int32 biti, bitj;
1514  word32 *wp;
1515  struct expr_t *idndp, *ndx;
1516  struct expr_t *fax;
1517 
1518  switch ((byte) xp->optyp) {
1519   case GLBREF:
1520    idndp = xp;
1521    biti = bitj = -1;
1522 glb_dce:
1523    np = idndp->lu.sy->el.enp;
1524    linkon_cb_dce(np, biti, bitj, idndp->ru.grp, cbp, DCE_CBVC);
1525    break;
1526   case ID:
1527    idndp = xp;
1528    np = xp->lu.sy->el.enp;
1529    linkon_cb_dce(np, -1, -1, NULL, cbp, DCE_CBVC);
1530    break;
1531   /* SJM 05/18/00 - must do nothing for reals */
1532   case NUMBER: case ISNUMBER: case REALNUM: case ISREALNUM: case OPEMPTY:
1533    return;
1534   case LSB:
1535    idndp = xp->lu.x;
1536    np = idndp->lu.sy->el.enp;
1537    ndx = xp->ru.x;
1538    /* any reg or non scalaraed wire must trigger on any chg */
1539    if (ndx->optyp == NUMBER)
1540     {
1541      wp = &(__contab[ndx->ru.xvi]);
1542      if (wp[1] != 0L) biti = -1; else biti = (int32) wp[0];
1543     }
1544    else if (ndx->optyp == ISNUMBER)
1545     {
1546      /* because cb dces are per instance, for IS form just need to get */
1547      /* right index and use for per. inst. dces - no need for -2 form */
1548      wp = &(__contab[ndx->ru.xvi]);
1549      wp = &(wp[2*__inum]);
1550      /* need length for IS number because can be wider - but get low */
1551      if (wp[1] != 0L) biti = -1; else biti = (int32) wp[0];
1552     }
1553    else
1554     {
1555      /* notice for monitor and dctrl event change, variable here is legal */
1556      /* and implies change for index and trigger on all bits of variable */
1557      bld_cbvc_dces(ndx, cbp);
1558      biti = -1;
1559     }
1560    if (biti != -1 && !np->vec_scalared) biti = -1;
1561    /* know non -1 value already normalized because constant normalized to */
1562    /* h:0 when source read */
1563    if (idndp->optyp == GLBREF) { bitj = biti; goto glb_dce; }
1564    linkon_cb_dce(np, biti, biti, NULL, cbp, DCE_CBVC);
1565    break;
1566   case PARTSEL:
1567    idndp = xp->lu.x;
1568    np = idndp->lu.sy->el.enp;
1569    ndx = xp->ru.x;
1570    /* know part select never IS and normalized during fixup */
1571    biti = (int32) __contab[ndx->lu.x->ru.xvi];
1572    bitj = (int32) __contab[ndx->ru.x->ru.xvi];
1573    if (!np->vec_scalared) biti = bitj = -1;
1574    if (idndp->optyp == GLBREF) goto glb_dce;
1575    linkon_cb_dce(np, biti, bitj, NULL, cbp, DCE_CBVC);
1576    break;
1577   case FCALL:
1578    /* if any arguments of system or user functions change, monitor triggers */
1579    /* notice $time function do not have arguments */
1580    for (fax = xp->ru.x; fax != NULL; fax = fax->ru.x)
1581     bld_cbvc_dces(fax->lu.x, cbp);
1582    break;
1583   case LCB:
1584    for (fax = xp->ru.x; fax != NULL; fax = fax->ru.x)
1585     bld_cbvc_dces(fax->lu.x, cbp);
1586    break;
1587   default:
1588    if (xp->lu.x != NULL) bld_cbvc_dces(xp->lu.x, cbp);
1589    if (xp->ru.x != NULL) bld_cbvc_dces(xp->ru.x, cbp);
1590    break;
1591  }
1592 }
1593 
1594 /*
1595  * link on a special (one per inst) callback valchg dce
1596  *
1597  * -2 IS form impossible any one inst. IS form made constant before here
1598  * need old value for ranges since need exact change processing
1599  *
1600  * passed biti and bitj must be normalized to internal h:0
1601  */
linkon_cb_dce(struct net_t * np,int32 biti,int32 bitj,struct gref_t * grp,struct cbrec_t * cbp,int32 dcetyp)1602 static void linkon_cb_dce(struct net_t *np, int32 biti, int32 bitj,
1603  struct gref_t *grp, struct cbrec_t *cbp, int32 dcetyp)
1604 {
1605  register struct dcevnt_t *dcep;
1606  int32 nd_itpop;
1607  struct itree_t *ref_itp;
1608  struct dceauxlst_t *dclp;
1609 
1610  ref_itp = __inst_ptr;
1611  nd_itpop = FALSE;
1612  if (grp != NULL) { __xmrpush_refgrp_to_targ(grp); nd_itpop = TRUE; }
1613  /* allocate, init, and fill the fields */
1614  dcep = __alloc_dcevnt(np);
1615 
1616  if (biti == -1) dcep->dce_typ = dcetyp;
1617  else
1618   {
1619    if (dcetyp == DCE_CBVC) dcep->dce_typ = DCE_RNG_CBVC;
1620    else if (dcetyp == DCE_CBF) dcep->dce_typ = DCE_RNG_CBF;
1621    else dcep->dce_typ = DCE_RNG_CBR;
1622    dcep->dci1 = biti;
1623    dcep->dci2.i = bitj;
1624   }
1625 
1626  /* since no dce, no loads, and no dmpvars must always turn chg store on */
1627  if (!np->nchg_nd_chgstore)
1628   {
1629    /* this also regen net's decl iops from dce if -O on */
1630    __dce_turn_chg_store_on(__inst_mod, dcep, FALSE);
1631   }
1632  /* SJM 02/06/03 - may have npps but not dces so must turn this on */
1633  /* since nchg nd chgstore on, know nchg action right */
1634 
1635  /* SJM 04/14/04 - if wire also need to turn on when dumpvars execed later */
1636  /* this was wrongly only turning on for regs - also needed for nets */
1637  np->nchg_has_dces = TRUE;
1638 
1639  /* link this on front */
1640  /* notice goes in front of pvc dces? */
1641  dcep->dcenxt = np->dcelst;
1642  np->dcelst = dcep;
1643 
1644  dcep->dce_1inst = TRUE;
1645  /* this is itree dcep put on */
1646  dcep->dce_matchitp = __inst_ptr;
1647  /* this is placed referenced, unless xmr same as match */
1648  dcep->dce_refitp = ref_itp;
1649  /* know in right itree place and need prevous value for selects */
1650  __alloc_1instdce_prevval(dcep);
1651  __init_1instdce_prevval(dcep);
1652  dcep->dceu.dce_cbp = cbp;
1653 
1654  /* then link on cb undo/chg list - need if remove called */
1655  dclp = (struct dceauxlst_t *) __my_malloc(sizeof(struct dceauxlst_t));
1656  dclp->ldcep = dcep;
1657  dclp->dclnxt = __cbvc_dcehdr;
1658  __cbvc_dcehdr = dclp;
1659 
1660  if (nd_itpop) __pop_itstk();
1661 }
1662 
1663 /*
1664  * for val change callback with vpi stren value - turn off no stren mon
1665  * if wire is stren model
1666  *
1667  * need to go through list since one for each net
1668  * only call if vpi_ value change callback stren format is stren change
1669  */
set_dce_strenchg_on(struct dceauxlst_t * dceaux_hd)1670 static void set_dce_strenchg_on(struct dceauxlst_t *dceaux_hd)
1671 {
1672  register struct dceauxlst_t *dceauxlp;
1673 
1674  for (dceauxlp = dceaux_hd; dceauxlp != NULL; dceauxlp = dceauxlp->dclnxt)
1675   {
1676    if (!dceauxlp->ldcep->dce_np->n_stren) continue;
1677 
1678    dceauxlp->ldcep->dce_nomonstren = FALSE;
1679   }
1680 }
1681 
1682 /*
1683  * allocate and add value change call back to gate output per inst list
1684  */
gateout_valchg_register(struct h_t * hp,struct t_cb_data * datp)1685 static vpiHandle gateout_valchg_register(struct h_t *hp,
1686  struct t_cb_data *datp)
1687 {
1688  register int32 i, last_i;
1689  register struct mod_t *mdp;
1690  int32 gi, tevpi;
1691  word64 timval;
1692  struct gate_t *gp;
1693  vpiHandle cbref;
1694  struct cbrec_t *cbp;
1695  struct h_t *hp2;
1696 
1697  gp = hp->hrec->hu.hgp;
1698  mdp = __inst_mod;
1699  /* if first primitive out cb for this module allocate list headers */
1700  if (mdp->mgateout_cbs == NULL)
1701   {
1702    mdp->mgateout_cbs = (i_tev_ndx **)
1703     __my_malloc(mdp->mgnum*sizeof(i_tev_ndx *));
1704    for (i = 0; i < mdp->mgnum; i++) mdp->mgateout_cbs[i] = NULL;
1705   }
1706  gi = gp - mdp->mgates;
1707  if (mdp->mgateout_cbs[gi] == NULL)
1708   {
1709    mdp->mgateout_cbs[gi] = (i_tev_ndx *)
1710     __my_malloc(mdp->flatinum*sizeof(int32));
1711    for (i = 0; i < mdp->flatinum; i++) mdp->mgateout_cbs[gi][i] = -1;
1712   }
1713  __have_vpi_gateout_cbs = TRUE;
1714 
1715  /* need a cbref to hold passsed cb data record */
1716  cbref = bld_cbrec(datp, CB_VALCHG);
1717  hp2 = (struct h_t *) cbref;
1718  cbp = hp2->hrec->hu.hcbp;
1719  cbp->cb_gateout = TRUE;
1720 
1721  /* need an event so cb can be removed */
1722  timval = 0ULL;
1723  alloc_tev_(tevpi, 0, NULL, timval);
1724  __tevtab[tevpi].tu.tehp = hp2;
1725  /* needed for remove because must match event from non delay sched list */
1726  cbp->cbtevpi = tevpi;
1727 
1728  /* using a list of events so can free and reuse while linking out */
1729  /* from all cb list */
1730  /* LOOKATME could store extra field to speed search up but lists short */
1731  /* link on end of list */
1732  if ((i = mdp->mgateout_cbs[gi][__inum]) == -1)
1733   {
1734    mdp->mgateout_cbs[gi][__inum] = tevpi;
1735   }
1736  else
1737   {
1738    last_i = -1;
1739    for (; i != -1; i = __tevtab[i].tenxti) last_i = i;
1740    __tevtab[last_i].tenxti = tevpi;
1741   }
1742  return(cbref);
1743 }
1744 
1745 /*
1746  * setup (register) the force or release callback (specific net/reg form)
1747  *
1748  * scheme: the lhs forced or released wire has a dce placed on that
1749  * is checked for force or release statement (or vpi routine) is execed
1750  * cb remove just unlinks the dce
1751  *
1752  * force and release can only be entire reg (but not real or array)
1753  * or wire or bit select of wire but not non lvalue expression
1754  */
rf_cb_register(p_cb_data cb_data_p,int32 qctyp)1755 static vpiHandle rf_cb_register(p_cb_data cb_data_p, int32 qctyp)
1756 {
1757  int32 rftyp, biti;
1758  vpiHandle cbref;
1759  struct h_t *hp, *hp2;
1760  struct net_t *np;
1761  struct hrec_t *hrp;
1762  struct expr_t *ndx, *xp;
1763  char s1[RECLEN];
1764 
1765  if (qctyp == cbForce) { strcpy(s1, "cbForce"); rftyp = DCE_CBF; }
1766  else { strcpy(s1, "cbRelease"); rftyp = DCE_CBR; }
1767  hp = (struct h_t *) cb_data_p->obj;
1768  if (!chk_rf_cb(cb_data_p, hp, s1)) return(NULL);
1769 
1770  /* handle nil obj (cb for all rel or force separately - no dces needed */
1771  if (cb_data_p->obj == NULL) return(rf_all_register_cb(cb_data_p, qctyp));
1772 
1773  hrp = hp->hrec;
1774  __cbvc_dcehdr = NULL;
1775  __push_itstk(hp->hin_itp);
1776  switch (hrp->htyp) {
1777   case vpiNet: case vpiReg: case vpiIntegerVar: case vpiTimeVar:
1778    np = hrp->hu.hnp;
1779    cbref = bld_cbrec(cb_data_p, CB_VALCHG);
1780    hp2 = (struct h_t *) cbref;
1781    linkon_cb_dce(np, -1, -1, NULL, hp2->hrec->hu.hcbp, rftyp);
1782    break;
1783   case vpiNetBit:
1784    /* this can be either form */
1785    if (!hrp->bith_ndx)
1786     {
1787      /* DBG remove --- */
1788      if (hrp->hu.hxp->optyp != LSB) __vpi_terr(__FILE__, __LINE__);
1789      /* --- */
1790      ndx = hrp->hu.hxp->ru.x;
1791      /* know index is 32 bits */
1792      if (!__expr_is_vpiconst(ndx))
1793       {
1794 bad_bsel:
1795        __vpi_err(1834, vpiError,
1796        "vpi_register_cb %s non constant or 'bx bit select of vpiNetBit illegal",
1797         s1);
1798        __pop_itstk();
1799        return(NULL);
1800       }
1801 
1802      xp = hrp->hu.hxp->lu.x;
1803      np = xp->lu.sy->el.enp;
1804      /* know correct itree loc. on top of stack - this may access IS number */
1805      /* but never variable - and know already normalized to h:0 */
1806      biti = __comp_ndx(np, ndx);
1807      if (biti == -1) goto bad_bsel;
1808     }
1809    /* stored in normalized h:0 range */
1810    else { np = hrp->hu.hnp; biti = hrp->hi; }
1811 
1812    cbref = bld_cbrec(cb_data_p, CB_VALCHG);
1813    hp2 = (struct h_t *) cbref;
1814    /* must filter bit or array index */
1815    linkon_cb_dce(np, biti, biti, NULL, hp2->hrec->hu.hcbp, rftyp);
1816    break;
1817   default:
1818    __vpi_err(1839, vpiError, "vpi_register_cb %s object %s illegal", s1,
1819     __to_vpionam(__wrks1, hrp->htyp));
1820    __pop_itstk();
1821    return(NULL);
1822  }
1823  __pop_itstk();
1824  if (qctyp == cbForce) __num_vpi_force_cbs++; else __num_vpi_rel_cbs++;
1825  return(cbref);
1826 }
1827 
1828 /*
1829  * check force/release callback passed cb_data record
1830  */
chk_rf_cb(p_cb_data cb_data_p,struct h_t * hp,char * rfnam)1831 static int32 chk_rf_cb(p_cb_data cb_data_p, struct h_t *hp, char *rfnam)
1832 {
1833  /* if obj nil, legal means all forces/release form */
1834  if (hp != NULL)
1835   {
1836    if (!__validate_nonit_handle("vpi_register_cb", hp)) return(FALSE);
1837   }
1838  if (cb_data_p->time == NULL)
1839   {
1840    __vpi_err(1932, vpiError,
1841     "vpi_register_cb %s p_cb_data record required time field empty", rfnam);
1842    return(FALSE);
1843   }
1844  if (cb_data_p->value == NULL)
1845   {
1846    __vpi_err(1933, vpiError,
1847     "vpi_register_cb %s p_cb_data record required value field empty", rfnam);
1848    return(FALSE);
1849   }
1850 
1851  /* validate time format and value format */
1852  if (!__validate_time_type("vpi_register_cb", cb_data_p->time->type))
1853   return(FALSE);
1854  if (!__validate_value_fmt("vpi_register_cb", cb_data_p->value->format))
1855   return(FALSE);
1856  return(TRUE);
1857 }
1858 
1859 /*
1860  * return T if expression will be converted to vpiConst
1861  */
__expr_is_vpiconst(struct expr_t * xp)1862 extern int32 __expr_is_vpiconst(struct expr_t *xp)
1863 {
1864  switch ((byte) xp->optyp) {
1865   case NUMBER: case ISNUMBER: case REALNUM: case ISREALNUM: case OPEMPTY:
1866    return(TRUE);
1867  }
1868  return(FALSE);
1869 }
1870 
1871 /*
1872  * setup (register) every force or release callback
1873  *
1874  * caller must make right itree loc.
1875  *
1876  * here on any change check flag and if set go through list of
1877  * all registered all changes cbs (can be many) and exec routine
1878  * before cb, build and sets handle (handle can must be copied by user)
1879  */
rf_all_register_cb(p_cb_data cb_data_p,int32 qctyp)1880 static vpiHandle rf_all_register_cb(p_cb_data cb_data_p, int32 qctyp)
1881 {
1882  vpiHandle cbref;
1883  struct h_t *hp;
1884  struct rfcblst_t *rfp;
1885 
1886  /* build the cbrec and handle */
1887  cbref = bld_cbrec(cb_data_p, CB_VALCHG);
1888  hp = (struct h_t *) cbref;
1889 
1890  rfp = (struct rfcblst_t *) __my_malloc(sizeof(struct rfcblst_t));
1891  rfp->rfcbp = hp->hrec->hu.hcbp;
1892  rfp->rfcbnxt = NULL;
1893 
1894  /* link on to right list and update flags */
1895  if (qctyp == cbForce)
1896   {
1897    if (!__vpi_force_cb_always)
1898     {
1899      __vpi_force_cb_always = TRUE;
1900      __force_allcb_hdr = __force_allcb_end = rfp;
1901     }
1902    else { __force_allcb_end->rfcbnxt = rfp; __force_allcb_end = rfp; }
1903   }
1904  else
1905   {
1906    if (!__vpi_rel_cb_always)
1907     { __vpi_rel_cb_always = TRUE; __rel_allcb_hdr = __rel_allcb_end = rfp; }
1908    else { __rel_allcb_end->rfcbnxt = rfp; __rel_allcb_end = rfp; }
1909   }
1910  return(cbref);
1911 }
1912 
1913 /*
1914  * from force - go thru net dces looking for force cb
1915  */
__find_call_force_cbs(struct net_t * np,int32 i1)1916 extern void __find_call_force_cbs(struct net_t *np, int32 i1)
1917 {
1918  register struct dcevnt_t *dcep;
1919  register struct cbrec_t *cbp;
1920 
1921  for (dcep = np->dcelst; dcep != NULL; dcep = dcep->dcenxt)
1922   {
1923    if (dcep->dce_typ == DCE_RNG_CBF)
1924     {
1925      if (i1 != -1 && (i1 < dcep->dci2.i || i1 > dcep->dci1))
1926       { if (__num_vpi_force_cbs == 1) return; else continue; }
1927      goto try_non_rng;
1928     }
1929    if (dcep->dce_typ != DCE_CBF) continue;
1930 
1931 try_non_rng:
1932    /* SJM 07/24/00 - must turn off PLI 1.0 PV dces from inside self */
1933    /* LOOKATME - on/off of cbs may break use of counter to stop loop */
1934    /* think only does small amount of extra work */
1935    if (dcep->dce_off) continue;
1936 
1937    /* only entire reg/wire or 1 bit of wire allowed here */
1938    if (dcep->dce_matchitp != __inst_ptr) continue;
1939    /* have matching force */
1940    cbp = dcep->dceu.dce_cbp;
1941 
1942    /* SJM 07/24/00 - must run with this callback off in case rf in user code */
1943    dcep->dce_off = TRUE;
1944 
1945    /* SJM 10/06/06  - must run with this cb off - if user did not turn off */
1946    /* or remove call back, cbvc routine turns back on */
1947    __cbvc_callback(dcep, cbp, cbp->cb_hp);
1948 
1949 
1950    /* SJM 10/06/06 - call back routine turns back on if not turned off */
1951    /* by user */
1952 
1953    /* if only one force cb (common case) can stop now */
1954    if (__num_vpi_force_cbs == 1) return;
1955   }
1956 }
1957 
1958 /*
1959  * from release - go thru net dces looking for release cb
1960  */
__find_call_rel_cbs(struct net_t * np,int32 i1)1961 extern void __find_call_rel_cbs(struct net_t *np, int32 i1)
1962 {
1963  register struct dcevnt_t *dcep;
1964  register struct cbrec_t *cbp;
1965 
1966  for (dcep = np->dcelst; dcep != NULL; dcep = dcep->dcenxt)
1967   {
1968    if (dcep->dce_typ == DCE_RNG_CBR)
1969     {
1970      if (i1 != -1 && (i1 < dcep->dci2.i || i1 > dcep->dci1))
1971       { if (__num_vpi_rel_cbs == 1) return; else continue; }
1972      goto try_non_rng;
1973     }
1974    if (dcep->dce_typ != DCE_CBR) continue;
1975 try_non_rng:
1976    /* only entire reg/wire or 1 bit of wire allowed here */
1977    if (dcep->dce_matchitp != __inst_ptr) continue;
1978    /* have matching force */
1979    cbp = dcep->dceu.dce_cbp;
1980 
1981    /* SJM 07/24/00 - must run with this callback off in case rf in user code */
1982    dcep->dce_off = TRUE;
1983 
1984    /* SJM 10/06/06  - must run with this cb off - if user did not turn off */
1985    /* or remove call back, cbvc routine turns back on */
1986    __cbvc_callback(dcep, cbp, cbp->cb_hp);
1987 
1988    /* SJM 10/06/06 - call back routine turns back on if not turned off */
1989    /* by user */
1990 
1991    /* if only one force cb (common case) can stop now */
1992    if (__num_vpi_rel_cbs == 1) return;
1993   }
1994 }
1995 
1996 /*
1997  * call all forces and release form registered call backs
1998  *
1999  * registered routine passed nil
2000  * no dce here - user can register multiple (handle built from changed)
2001  *
2002  * this builds a forced/released (after) changed reg or bit handle
2003  * and does normal vc change call back after that
2004  * fills dat obj field then frees handle and sets to nil upon return
2005  *
2006  * this works for all case because no instance specific filtering
2007  * so just use itree loc for one changed
2008  */
__cb_all_rfs(struct net_t * np,int32 bi,int32 is_force)2009 extern void __cb_all_rfs(struct net_t *np, int32 bi, int32 is_force)
2010 {
2011  register struct rfcblst_t *rfp;
2012  word32 sav_cb_ndxobj;
2013  struct cbrec_t *cbp;
2014  struct h_t *hp;
2015  struct task_t *tskp;
2016 
2017  /* SJM 07/24/00 - if user executes force/release from within all rf */
2018  /* type call back must not see rf callback again */
2019  if ( __allrel_cbs_off) return;
2020 
2021  __vpifnam_ind = __sfnam_ind;
2022  __vpilin_cnt = __slin_cnt;
2023  tskp = __getcur_scope_tsk();
2024  /* SJM 07/24/00 - if user executes force/release from within all rf */
2025  /* type call back must not see rf callback again */
2026  if (is_force)
2027   {
2028    if (__allforce_cbs_off) return;
2029    rfp = __force_allcb_hdr;
2030   }
2031  else
2032   {
2033    if (__allrel_cbs_off) return;
2034    rfp = __rel_allcb_hdr;
2035   }
2036 
2037  for (; rfp != NULL; rfp = rfp->rfcbnxt)
2038   {
2039    cbp = rfp->rfcbp;
2040    sav_cb_ndxobj = cbp->cb_ndxobj;
2041    if (bi == -1)
2042     {
2043      cbp->cb_ndxobj = FALSE;
2044      hp = (struct h_t *) __mk_handle(vpiNet, (void *) np, __inst_ptr, tskp);
2045     }
2046    else
2047     {
2048      cbp->cb_ndxobj = TRUE;
2049      hp = (struct h_t *) __mk_handle(vpiNetBit, (void *) np, __inst_ptr, tskp);
2050      hp->hrec->hi = bi;
2051     }
2052    /* SJM 07/24/00 - all force/release form cbs require no force/release */
2053    /* call backs allows from within user callback routine in case user code */
2054    /* does some forcing and releasing */
2055    if (is_force) __allforce_cbs_off = TRUE; else __allrel_cbs_off = TRUE;
2056 
2057    /* since know cbp dce pointer also nil, will not access dce field */
2058    __cbvc_callback(NULL, cbp, hp);
2059 
2060    if (is_force) __allforce_cbs_off = FALSE; else __allrel_cbs_off = FALSE;
2061 
2062    /* this just frees temp handle allocated for call back */
2063    cbp->cb_ndxobj = sav_cb_ndxobj;
2064    /* free the temp object - because can be indexed need vpi free */
2065    vpi_free_object((vpiHandle) hp);
2066   }
2067  __sfnam_ind = __vpifnam_ind;
2068  __slin_cnt = __vpilin_cnt;
2069 }
2070 
2071 /*
2072  * call the cb value change call back routine (process the change)
2073  * also for force/release - net specific type - only cbrec ptr used
2074  *
2075  * for all form of force/release need to pass hp which is one that
2076  * changed - changes each time called for all (nil) case
2077  *
2078  * dcep's always 1 instance - called for any change of expr.
2079  *
2080  * must allocate new cb_data record and set time and and value fields
2081  * (unless field type suppress) following new LRM rules for val chg cbs
2082  *
2083  * this routine runs with no vpi_ location because event usually changes
2084  * but does have an itree loc.
2085  */
__cbvc_callback(struct dcevnt_t * dcep,struct cbrec_t * cbp,struct h_t * hp)2086 extern void __cbvc_callback(struct dcevnt_t *dcep, struct cbrec_t *cbp,
2087  struct h_t *hp)
2088 {
2089  int32 biti, ndx;
2090  struct t_cb_data wrk_cbdata, *datp;
2091  struct t_vpi_time wrk_time;
2092  struct t_vpi_value wrk_val;
2093  struct xstk_t *xsp;
2094  struct net_t *np;
2095  struct h_t *hp2;
2096  struct hrec_t *hrp2;
2097 
2098  /* suppress call backs during reset */
2099  if (__run_state == SS_RESET) return;
2100 
2101  datp = &wrk_cbdata;
2102  datp->reason = cbp->cb_reason;
2103  datp->cb_rtn = cbp->cb_rtn;
2104  /* value change return call back requires all next 3 fields be present */
2105  /* must be passed for all force/release case - usually just from cbp fld */
2106  datp->obj = (vpiHandle) hp;
2107  datp->time = &wrk_time;
2108  datp->value = &wrk_val;
2109  datp->user_data = cbp->cb_user_data;
2110 
2111  if (cbp->cb_retvalfmt != vpiSuppressVal)
2112   {
2113    datp->value->format = (int32) cbp->cb_retvalfmt;
2114    vpi_get_value(datp->obj, datp->value);
2115   }
2116  else datp->value->format = vpiSuppressVal;
2117  if (cbp->cb_rettimtyp != vpiSuppressTime)
2118   {
2119    datp->time->type = (int32) cbp->cb_rettimtyp;
2120    __set_vpi_time(datp->time, &__simtime, datp->time->type, __inst_mod);
2121   }
2122  else datp->time->type = vpiSuppressTime;
2123 
2124  /* if bit handle or bit select or array word32 select handle set index field */
2125  if (cbp->cb_ndxobj)
2126   {
2127    /* cb object is object not index */
2128    hp2 = (struct h_t *) datp->obj;
2129    hrp2 = hp2->hrec;
2130    /* alt form for expr. handle is index rather than expr. */
2131    if (!hrp2->bith_ndx)
2132     {
2133      /* DBG remove --- */
2134      if (hrp2->htyp != vpiNetBit && hrp2->htyp != vpiRegBit
2135       && hrp2->htyp != vpiVarSelect && hrp2->htyp != vpiMemoryWord)
2136       __vpi_terr(__FILE__, __LINE__);
2137 
2138      if (hrp2->hu.hxp->optyp != LSB) __vpi_terr(__FILE__, __LINE__);
2139      /* --- */
2140 
2141      /* evaluate index expr. even if constant because of IS case */
2142      __push_itstk(hp2->hin_itp);
2143      xsp = __eval_xpr(hrp2->hu.hxp->ru.x);
2144      __pop_itstk();
2145      if (xsp->bp[0] != 0) datp->index = 0;
2146      else
2147       {
2148        ndx = (int32) xsp->ap[0];
2149        /* constants must be unnormalized - non constant not normalized so */
2150        /* no need to unnormalize */
2151        if (__expr_is_vpiconst(hp2->hrec->hu.hxp->ru.x))
2152         {
2153          np = hrp2->hu.hxp->lu.x->lu.sy->el.enp;
2154          biti = __unnormalize_ndx(np, ndx);
2155         }
2156        else biti = ndx;
2157        __pop_xstk();
2158        datp->index = biti;
2159       }
2160     }
2161    /* for non expr bit obj type, stored as internal h:0 need unnormalize */
2162    else datp->index = __unnormalize_ndx(hrp2->hu.hnp, hrp2->hi);
2163   }
2164 
2165  /* DBG remove --
2166  if (__debug_flg && __ev_tracing)
2167   {
2168    -* SJM 08/16/01 - BEWARE - not sure if can call vpi routine in here *-
2169    __tr_msg("<> processing vpi_ %s callback on %s now %s\n",
2170     to_cbtypnam(__xs2, datp->reason), vpi_get_str(vpiFullName, datp->obj),
2171     __to_timstr(__xs, &__simtime));
2172   }
2173  --- */
2174 
2175  /* 10/06/06 - this will be set to nil if user code removes the call back */
2176  /* that is now being processed */
2177  __cbvc_causing_dcep = dcep;
2178 
2179  (*(datp->cb_rtn))(datp);
2180 
2181  /* SJM 07/24/00 - unless user turned off with vpi control turn back on */
2182  /* user may turn off in value change call back routine */
2183 
2184  /* SJM 10/06/06 - also if user removed this call back in value change */
2185  /* routine, must not turn back on since dcep will have been freed */
2186 
2187  /* SJM 10/06/06 - the cbvc causing dcep will be nil if user code */
2188  /* call cb remove for the currently active call back cbp (and dcep) */
2189 
2190  if (__cbvc_causing_dcep != NULL && !dcep->dceu.dce_cbp->cb_user_off)
2191    dcep->dce_off = FALSE;
2192  __cbvc_causing_dcep = NULL;
2193 
2194  /* t_cb_data automatic so no need to free */
2195 }
2196 
2197 /*
2198  * execute a special case primitive output terminal value change call back
2199  *
2200  * these can only be freed by cb remove
2201  */
__exec_vpi_gateoutcbs(register int32 tevpi)2202 extern void __exec_vpi_gateoutcbs(register int32 tevpi)
2203 {
2204  struct cbrec_t *cbp;
2205 
2206  for (; tevpi != -1; tevpi = __tevtab[tevpi].tenxti)
2207   {
2208    /* if already cancelled (i.e. callback removed), nothing to do */
2209    /* LOOKATME - think canceling not possible - will have been removed */
2210    if (__tevtab[tevpi].te_cancel) continue;
2211 
2212    cbp = __tevtab[tevpi].tu.tehp->hrec->hu.hcbp;
2213    /* SJM 07/24/00 - user can turn off/on with sim control */
2214    if (cbp->cb_user_off) continue;
2215 
2216    /* SJM 10/06/06 - this does not need to run with cb off since no assign */
2217    __cbvc_callback(NULL, cbp, cbp->cb_hp);
2218   }
2219  /* nothing to free since cb_data record in automatic storage */
2220 }
2221 
2222 /*
2223  * ROUTINES TO IMPLEMENT DELAY STYLE CALL BACKS
2224  */
2225 
2226 /*
2227  * routine that registers all delay (time) callbacks
2228  * removal when done automatic - can be removed before happen
2229  *
2230  * for: sim start, wr sync, ro sync, next sim time, normal delay
2231  *
2232  * SJM 07/24/00 - delay call backs can't be turned off by user
2233  */
delay_cb_register(register p_cb_data datp)2234 static vpiHandle delay_cb_register(register p_cb_data datp)
2235 {
2236  word64 ticksdel, schtim;
2237  vpiHandle cbref;
2238  i_tev_ndx tevpi;
2239  struct h_t *hp;
2240  struct mod_t *mdp;
2241 
2242  /* need delay value in internal ticks */
2243  ticksdel = 0ULL;
2244  hp = (struct h_t *) datp->obj;
2245  if (!chk_delay_cb(datp, hp)) return(NULL);
2246 
2247  if (datp->reason != cbNextSimTime)
2248   {
2249    /* notice the object does not need to be scope object */
2250    if (hp != NULL && hp->hin_itp != NULL)
2251     mdp = hp->hin_itp->itip->imsym->el.emdp;
2252    else mdp = NULL;
2253    if (!__vpitime_to_ticks(&ticksdel, datp->time, mdp)) return(NULL);
2254   }
2255 
2256  /* #0 cases - add to event queue - at current time */
2257  if (datp->reason == cbNextSimTime || ticksdel == 0ULL)
2258   {
2259    /* can't schedule any #0 in ro sync region */
2260    if (__rosync_slot && datp->reason != cbNextSimTime)
2261     { __bad_rosync_err("vpi_register_cb"); return(NULL); }
2262 
2263    cbref = bld_cbrec(datp, CB_DELAY);
2264    /* notice reusing hp */
2265    hp = (struct h_t *) cbref;
2266    /* alloc as #0 */
2267    alloc_tev_(tevpi, TE_VPICBDEL, __it_roots[0], __simtime);
2268    __tevtab[tevpi].tu.tehp = hp;
2269    /* back link from cbrec to event */
2270    hp->hrec->hu.hcbp->cbtevpi = tevpi;
2271 
2272    switch (datp->reason) {
2273     case cbAtStartOfSimTime:
2274      __vpi_err(1852, vpiError,
2275       "vpi_register_cb cbAtStartOfSimTime #0 delay illegal - already past");
2276 
2277      /* on error free actioncb psuedo event, free cbrec, and free callback */
2278      __tevtab[tevpi].tenxti = __tefreelsti;
2279      __tefreelsti = tevpi;
2280      free_cbrec(hp->hrec->hu.hcbp);
2281      return(NULL);
2282     case cbReadOnlySynch:
2283      /* link on end of rosync list - exec all cbs in register order */
2284      if (__vpicb_tehdri[cbReadOnlySynch] == -1)
2285       __vpicb_tehdri[cbReadOnlySynch] = __vpicb_teendi[cbReadOnlySynch]
2286        = tevpi;
2287      else
2288       {
2289        __tevtab[__vpicb_teendi[cbReadOnlySynch]].tenxti = tevpi;
2290        __vpicb_teendi[cbReadOnlySynch] = tevpi;
2291       }
2292      __slotend_action |= SE_VPIROSYNC;
2293      break;
2294     case cbNextSimTime:
2295      /* link on front of nxtim list */
2296      if (__vpicb_tehdri[cbNextSimTime] == -1)
2297       __vpicb_tehdri[cbNextSimTime] = __vpicb_teendi[cbNextSimTime] = tevpi;
2298      else
2299       {
2300        __tevtab[__vpicb_teendi[cbNextSimTime]].tenxti = tevpi;
2301        __vpicb_teendi[cbNextSimTime] = tevpi;
2302       }
2303      __have_vpi_actions = TRUE;
2304      break;
2305     case cbReadWriteSynch:
2306      /* MAYBE FIXME  - for now same as #0 except future becomes #0 */
2307     case cbAfterDelay:
2308      if (__p0_te_hdri == -1) __p0_te_hdri = __p0_te_endi = tevpi;
2309      else { __tevtab[__p0_te_endi].tenxti = tevpi; __p0_te_endi = tevpi; }
2310      break;
2311     default: __vpi_terr(__FILE__, __LINE__);
2312    }
2313    return(cbref);
2314   }
2315  /* case 2: for later time */
2316  schtim = __simtime + ticksdel;
2317  cbref = bld_cbrec(datp, CB_DELAY);
2318  alloc_tev_(tevpi, TE_VPICBDEL, __it_roots[0], schtim);
2319  hp = (struct h_t *) cbref;
2320  __tevtab[tevpi].tu.tehp = hp;
2321  /* back link from cbrec to event */
2322  hp->hrec->hu.hcbp->cbtevpi = tevpi;
2323 
2324  /* some later slot */
2325  switch (datp->reason) {
2326   case cbAtStartOfSimTime:
2327    /* add to front instead of end of queue */
2328    __tevtab[tevpi].vpi_onfront = TRUE;
2329    __insert_event(tevpi);
2330    break;
2331   case cbReadWriteSynch: case cbReadOnlySynch:
2332    /* schedule ev for future normal event queue, flag frees, alloc, schds #0 */
2333    __tevtab[tevpi].vpi_reschd = TRUE;
2334    __insert_event(tevpi);
2335    break;
2336   case cbAfterDelay:
2337    __insert_event(tevpi);
2338    break;
2339   default: __vpi_terr(__FILE__, __LINE__);
2340  }
2341  return(cbref);
2342 }
2343 
2344 /*
2345  * check force/release callback passed cb_data record
2346  */
chk_delay_cb(p_cb_data datp,struct h_t * hp)2347 static int32 chk_delay_cb(p_cb_data datp, struct h_t *hp)
2348 {
2349  /* if optional obj present, it must be valid and a scope object */
2350  if (hp != NULL)
2351   {
2352    if (!__validate_nonit_handle("delay vpi_register_cb", hp)) return(FALSE);
2353   }
2354  /* unless next sim time, time field required and must not be suppress */
2355  if (datp->reason != cbNextSimTime)
2356   {
2357    if (datp->time == NULL)
2358     {
2359      __vpi_err(1934, vpiError,
2360       "delay vpi_register_cb p_cb_data record required time field missing");
2361      return(FALSE);
2362     }
2363    /* validate time format */
2364    if (!__validate_time_type("delay call back", datp->time->type))
2365     return(FALSE);
2366    if (datp->time->type == vpiSuppressTime)
2367     {
2368      __vpi_err(1935, vpiError,
2369       "delay vpi_register_cb p_cb_data record time field type vpiSuppress field illegal");
2370       return(FALSE);
2371     }
2372   }
2373  /* value field ignored - so may be nil - no need to check */
2374  return(TRUE);
2375 }
2376 
2377 /*
2378  * execute a delay related call back list
2379  *
2380  * only for ro sync and nxt sim time (after move time)
2381  * after event is processed, the cbrec is freed
2382  * tevs freed when done en masse here
2383  * list may be empty if all removed - no way to detect until here
2384  *
2385  * SJM 07/24/00 - delay call backs can't be turned off by user
2386  */
exec_vpi_delaycbs(int32 cbtyp)2387 static void exec_vpi_delaycbs(int32 cbtyp)
2388 {
2389  register i_tev_ndx tevpi;
2390 
2391  /* all may have been cancelled */
2392  if ((tevpi = __vpicb_tehdri[cbtyp]) == -1) return;
2393 
2394  if (cbtyp == cbReadOnlySynch) __rosync_slot = TRUE;
2395  /* if cancelled cbrec will be freed */
2396  for (; tevpi != -1; tevpi = __tevtab[tevpi].tenxti)
2397   {
2398    /* since not scheduled - never can be cancelled */
2399    /* DBG remove ---
2400    if (__tevtab[tevpi].te_cancel) __vpi_terr(__FILE__, __LINE__);
2401    if (__tevtab[tevpi].vpi_reschd) __vpi_terr(__FILE__, __LINE__);
2402    --- */
2403    /* when called from here reschd never on */
2404    __delay_callback(tevpi);
2405   }
2406 
2407  /* slot end action turned off all at once later */
2408  /* add entire list to tev free list - know no guts */
2409  __tevtab[__vpicb_teendi[cbtyp]].tenxti = __tefreelsti;
2410  __tefreelsti = __vpicb_tehdri[cbtyp];
2411  __vpicb_tehdri[cbtyp] = __vpicb_teendi[cbtyp] = -1;
2412  if (cbtyp == cbReadOnlySynch) __rosync_slot = FALSE;
2413 }
2414 
2415 /*
2416  * call the cb delay routine - event exec is calling cb routine
2417  * used for all time related cbs
2418  *
2419  * when processed (not just moved to other part of slot) will never happen
2420  * again and handle is freed
2421  *
2422  * 2 ways through here - 1) move event to other part of slot list, 2) do
2423  * callback and free event since done and can never happen again
2424  *
2425  * if call back cancelled, event cancelled so will never get here
2426  */
__delay_callback(i_tev_ndx tevpi)2427 extern void __delay_callback(i_tev_ndx tevpi)
2428 {
2429  int32 tevp2i;
2430  struct t_cb_data wrk_cbdata, *datp;
2431  struct t_vpi_time wrk_time;
2432  struct cbrec_t *cbp;
2433  struct h_t *cbhp;
2434  struct mod_t *mdp;
2435 
2436  /* DBG remove -- */
2437  if (__debug_flg && __ev_tracing)
2438   {
2439    __tr_msg("-- processing vpi_ delay call back at %s\n",
2440    __to_timstr(__xs, &__simtime));
2441   }
2442  /* --- */
2443 
2444  cbhp = __tevtab[tevpi].tu.tehp;
2445  cbp = cbhp->hrec->hu.hcbp;
2446  /* move to right sync location */
2447  if (__tevtab[tevpi].vpi_reschd)
2448   {
2449    /* SJM 08/07/00 - must schedule new event since carrier event free */
2450    /* enmass with all other regular events in now being processed queue */
2451    alloc_tev_(tevp2i, TE_VPICBDEL, __tevtab[tevpi].teitp, __simtime);
2452    /* move cb hp ptr to new event */
2453    __tevtab[tevp2i].tu.tehp = cbhp;
2454    /* nil field in normal event queue event since it is soon to be freed */
2455    __tevtab[tevpi].tu.tehp = NULL;
2456    __num_proc_tevents--;
2457    /* now all fields same except vpi reschd not on in new - as needed */
2458 
2459    if (cbp->cb_reason == cbReadWriteSynch)
2460     {
2461      if (__p0_te_hdri == -1) __p0_te_hdri = __p0_te_endi = tevp2i;
2462      else { __tevtab[__p0_te_endi].tenxti = tevp2i; __p0_te_endi = tevp2i; }
2463     }
2464    else if (cbp->cb_reason == cbReadOnlySynch)
2465     {
2466      /* link on end of rosync list since exec cbs in register order */
2467      if (__vpicb_tehdri[cbReadOnlySynch] == -1)
2468       __vpicb_tehdri[cbReadOnlySynch] = __vpicb_teendi[cbReadOnlySynch]
2469        = tevp2i;
2470      else
2471       {
2472        __tevtab[__vpicb_teendi[cbReadOnlySynch]].tenxti = tevp2i;
2473        __vpicb_teendi[cbReadOnlySynch] = tevp2i;
2474       }
2475      __slotend_action |= SE_VPIROSYNC;
2476     }
2477    else __vpi_terr(__FILE__, __LINE__);
2478    return;
2479   }
2480 
2481  datp = &wrk_cbdata;
2482  datp->reason = cbp->cb_reason;
2483  datp->cb_rtn = cbp->cb_rtn;
2484  /* if user passed object (for scope) must return else nil */
2485  if (cbp->cb_hp != NULL) datp->obj = (vpiHandle) cbp->cb_hp;
2486  else datp->obj = NULL;
2487 
2488  wrk_time.type = vpiSuppressTime;
2489  datp->time = &wrk_time;
2490  /* value always nil */
2491  datp->value = NULL;
2492  datp->user_data = cbp->cb_user_data;
2493 
2494  /* assign time */
2495  if (cbp->cb_rettimtyp != vpiSuppressTime)
2496   {
2497    datp->time->type = (int32) cbp->cb_rettimtyp;
2498    if (cbp->cb_hp != NULL) mdp = cbp->cb_hp->hin_itp->itip->imsym->el.emdp;
2499    else mdp = NULL;
2500    __set_vpi_time(datp->time, &__simtime, datp->time->type, mdp);
2501   }
2502 
2503  (*(cbp->cb_rtn))(datp);
2504 
2505  /* datp freed since automatic var */
2506  /* remove the call back since can't happen again */
2507  free_cbrec(cbp);
2508  /* event will be collected by normal mechanism or when all of list done */
2509  __tevtab[tevpi].tu.tehp = NULL;
2510 }
2511 
2512 /*
2513  * remove a callback - must unline from global list
2514  * only field to free is cb_hp copied object - cbtevp not freeable from here
2515  */
free_cbrec(struct cbrec_t * cbp)2516 static void free_cbrec(struct cbrec_t *cbp)
2517 {
2518  struct h_t *cbhp;
2519 
2520  /* link out of list */
2521  /* case 1: at front */
2522  if (cbp->cbprev == NULL)
2523   {
2524    __vpi_cbrec_hdr = cbp->cbnxt;
2525    if (cbp->cbnxt != NULL) cbp->cbnxt->cbprev = NULL;
2526   }
2527  /* case 2: at end but not at front */
2528  else if (cbp->cbnxt == NULL) cbp->cbprev->cbnxt = NULL;
2529  /* case 3: inside */
2530  else { cbp->cbprev->cbnxt = cbp->cbnxt; cbp->cbnxt->cbprev = cbp->cbprev; }
2531 
2532  /* free the copied object handle */
2533  if (cbp->cb_hp != NULL)
2534   {
2535    vpi_free_object((vpiHandle) cbp->cb_hp);
2536   }
2537  cbhp = cbp->cb_cbhp;
2538  __free_hp(cbhp);
2539 
2540  __my_free((char *) cbp, sizeof(struct cbrec_t));
2541 }
2542 
2543 /*
2544  * add a call back to a action (or feature) (fixed) reason
2545  *
2546  * cbs remain unless explicitly removed
2547  * value and time fields completely ignored
2548  */
action_cb_register(register p_cb_data datp)2549 static vpiHandle action_cb_register(register p_cb_data datp)
2550 {
2551  word64 timval;
2552  vpiHandle cbref;
2553  struct cbrec_t *cbp;
2554  struct h_t *cbhp;
2555  i_tev_ndx tevpi;
2556 
2557  if (datp->reason == cbCustomer1)
2558   {
2559    if (__vpicb_tehdri[datp->reason] != -1)
2560     {
2561      __vpi_err(1830, vpiError, "cbCustomer1 action callback unsupported");
2562      return(NULL);
2563     }
2564   }
2565 
2566  /* already checked cb_rtn and reason, rest need not be set at all */
2567  /* because they are ignored */
2568 
2569  /* need a cbref to hold passsed cb data record */
2570  cbref = bld_cbrec(datp, CB_ACTION);
2571  cbhp = (struct h_t *) cbref;
2572  cbp = cbhp->hrec->hu.hcbp;
2573  /* need an event so cb can be removed */
2574  timval = 0ULL;
2575  alloc_tev_(tevpi, 0, NULL, timval);
2576  __tevtab[tevpi].tu.tehp = cbhp;
2577  /* needed for remove because must match event from non delay sched list */
2578  cbp->cbtevpi = tevpi;
2579 
2580  /* link on to end of list */
2581  if (__vpicb_tehdri[datp->reason] == -1)
2582   __vpicb_tehdri[datp->reason] = __vpicb_teendi[datp->reason] = tevpi;
2583  else
2584   {
2585    __tevtab[__vpicb_teendi[datp->reason]].tenxti = tevpi;
2586    __vpicb_teendi[datp->reason] = tevpi;
2587   }
2588  /* need special flag for at least one cbError cb active */
2589  if (datp->reason == cbError) __vpierr_cb_active = TRUE;
2590  __have_vpi_actions = TRUE;
2591  return(cbref);
2592 }
2593 
2594 /*
2595  * try to call start of reset routine
2596  *
2597  * wrapper around call since vpi_ include only in vpi_ code
2598  */
__vpi_startreset_trycall(void)2599 extern void __vpi_startreset_trycall(void)
2600 {
2601  if (__vpicb_tehdri[cbStartOfReset] != -1)
2602   exec_vpi_actioncbs(cbStartOfReset);
2603 }
2604 
2605 /*
2606  * execute end of reset callback wrapper
2607  */
__vpi_endreset_trycall(void)2608 extern void __vpi_endreset_trycall(void)
2609 {
2610  if (__vpicb_tehdri[cbEndOfReset] != -1)
2611   exec_vpi_actioncbs(cbEndOfReset);
2612 }
2613 
2614 /*
2615  * execute end of compile callback wrapper
2616  */
__vpi_endcomp_trycall(void)2617 extern void __vpi_endcomp_trycall(void)
2618 {
2619  if (__vpicb_tehdri[cbEndOfCompile] != -1)
2620   exec_vpi_actioncbs(cbEndOfCompile);
2621 }
2622 
2623 /*
2624  * execute start of sim callback wrapper
2625  */
__vpi_startsim_trycall(void)2626 extern void __vpi_startsim_trycall(void)
2627 {
2628  if (__vpicb_tehdri[cbStartOfSimulation] != -1)
2629   exec_vpi_actioncbs(cbStartOfSimulation);
2630 }
2631 
2632 /*
2633  * execute end of sim callback wrapper
2634  */
__vpi_endsim_trycall(void)2635 extern void __vpi_endsim_trycall(void)
2636 {
2637  if (__vpicb_tehdri[cbEndOfSimulation] != -1)
2638   exec_vpi_actioncbs(cbEndOfSimulation);
2639 }
2640 
2641 /*
2642  * try to call enter iact reason wrapper
2643  */
__vpi_enteriact_trycall(void)2644 extern void __vpi_enteriact_trycall(void)
2645 {
2646  __vpifnam_ind = __sfnam_ind;
2647  __vpilin_cnt = __slin_cnt;
2648 
2649  if (__vpicb_tehdri[cbEnterInteractive] != -1)
2650   exec_vpi_actioncbs(cbEnterInteractive);
2651 
2652  __vpifnam_ind = 0;
2653  __vpilin_cnt = 0;
2654 }
2655 
2656 /*
2657  * try to call exit iact reason wrapper
2658  */
__vpi_exitiact_trycall(void)2659 extern void __vpi_exitiact_trycall(void)
2660 {
2661  __vpifnam_ind = __sfnam_ind;
2662  __vpilin_cnt = __slin_cnt;
2663 
2664  if (__vpicb_tehdri[cbExitInteractive] != -1)
2665   exec_vpi_actioncbs(cbExitInteractive);
2666 
2667  __vpifnam_ind = 0;
2668  __vpilin_cnt = 0;
2669 }
2670 
2671 /*
2672  * try to call interactive scope change reason wrapper
2673  * this sets cb data handle using alloced and freed after call handle obj
2674  */
__vpi_iactscopechg_trycall(void)2675 extern void __vpi_iactscopechg_trycall(void)
2676 {
2677  word32 parhtyp;
2678  vpiHandle scopobj;
2679  struct t_cb_data wrk_cbdata, *datp;
2680  struct cbrec_t *cbp;
2681  i_tev_ndx tevpi;
2682  struct mod_t *mdp;
2683  struct task_t *up_tskp;
2684  struct symtab_t *sytp;
2685 
2686  if ((tevpi = __vpicb_tehdri[cbInteractiveScopeChange]) == -1) return;
2687 
2688  __vpifnam_ind = __sfnam_ind;
2689  __vpilin_cnt = __slin_cnt;
2690 
2691  /* interactive scope change call back sets obj field to new scope */
2692  if (__scope_tskp == NULL)
2693   {
2694    mdp = __scope_ptr->itip->imsym->el.emdp;
2695    scopobj = __mk_handle(vpiModule, (void *) mdp, __scope_ptr, NULL);
2696   }
2697  else
2698   {
2699    sytp = __scope_tskp->tsksymtab;
2700    if (sytp->sytpar == NULL || sytp->sytpar->sypofsyt->sytyp == SYM_M)
2701     up_tskp = NULL;
2702    else up_tskp = sytp->sytpar->sypofsyt->el.etskp;
2703 
2704    parhtyp = __to_vpi_tasktyp(__scope_tskp->tsktyp);
2705    scopobj = __mk_handle(parhtyp, (void *) __scope_tskp, __scope_ptr, up_tskp);
2706   }
2707 
2708  datp = &wrk_cbdata;
2709  /* for action callback next 2 must be nil */
2710  datp->time = NULL;
2711  datp->value = NULL;
2712  /* scope object always return as obj - required */
2713  datp->obj = scopobj;
2714 
2715  for (; tevpi != -1; tevpi = __tevtab[tevpi].tenxti)
2716   {
2717    /* DBG remove --- */
2718    if (__tevtab[tevpi].te_cancel) __vpi_terr(__FILE__, __LINE__);
2719    /* --- */
2720 
2721    cbp = __tevtab[tevpi].tu.tehp->hrec->hu.hcbp;
2722 
2723    /* SJM 07/24/00 - user can turn off/on with sim control */
2724    if (cbp->cb_user_off) continue;
2725 
2726    datp->reason = cbp->cb_reason;
2727    datp->cb_rtn = cbp->cb_rtn;
2728    datp->user_data = cbp->cb_user_data;
2729 
2730    (*(datp->cb_rtn))(datp);
2731   }
2732  /* datp automatic so no need to free */
2733  /* must leave callback cbrec until released */
2734 
2735  /* can't free created scope object - because user may save and use */
2736 
2737  __vpifnam_ind = 0;
2738  __vpilin_cnt = 0;
2739 }
2740 
2741 /*
2742  * try to call next sim time (next move time time) reason wrapper
2743  * this is delay cb not action
2744  */
__vpi_del_nxtsimtim_trycall(void)2745 extern void __vpi_del_nxtsimtim_trycall(void)
2746 {
2747  if (__vpicb_tehdri[cbNextSimTime] != -1) exec_vpi_delaycbs(cbNextSimTime);
2748 }
2749 
2750 /*
2751  * call the rosync (know slot bit set)
2752  * this is del cb not action
2753  */
__vpi_del_rosync_call(void)2754 extern void __vpi_del_rosync_call(void)
2755 {
2756  exec_vpi_delaycbs(cbReadOnlySynch);
2757 }
2758 
2759 /*
2760  * try to call tchk violation reason wrapper
2761  */
__vpi_tchkerr_trycall(struct tchk_t * tcp,struct itree_t * itp)2762 extern void __vpi_tchkerr_trycall(struct tchk_t *tcp, struct itree_t *itp)
2763 {
2764  __vpifnam_ind = tcp->tcsym->syfnam_ind;
2765  __vpilin_cnt = tcp->tcsym->sylin_cnt;
2766 
2767  if (__vpicb_tehdri[cbTchkViolation] != -1)
2768   exec_vpi_tchkerr(cbTchkViolation, tcp, itp);
2769 
2770  __vpifnam_ind = 0;
2771  __vpilin_cnt = 0;
2772 }
2773 
2774 /*
2775  * try to call vpi_ PLI error (only for __vpi errors) reason wrapper
2776  *
2777  * here error location maybe set by caller of error
2778  *
2779  * if error call back generated by routine called from error cb
2780  * end with fatal error since serious user code bug (infinite loop)
2781  */
__vpi_plierror_trycall(void)2782 extern void __vpi_plierror_trycall(void)
2783 {
2784  if (__acc_vpi_erroff) return;
2785 
2786  if (__vpicb_tehdri[cbPLIError] != -1)
2787   {
2788    if (__in_vpi_errorcb)
2789     {
2790      __pv_vpi_terr(303,
2791      "cbPLIError callback caused recursive error callback - giving up");
2792     }
2793    __in_vpi_errorcb = TRUE;
2794    exec_vpi_actioncbs(cbPLIError);
2795    __in_vpi_errorcb = FALSE;
2796   }
2797 }
2798 
2799 /*
2800  * try to call vpi_ non PLI error reason wrapper
2801  *
2802  * all Cver errors except interactive try to call these callbacks
2803  * vpi_chk_error used inside these call backs to get Cver einfo
2804  */
__vpi_error_trycall(void)2805 extern void __vpi_error_trycall(void)
2806 {
2807  if (__acc_vpi_erroff) return;
2808 
2809  if (__vpicb_tehdri[cbError] == -1) return;
2810 
2811  if (__in_vpi_errorcb)
2812   {
2813    __pv_vpi_terr(303,
2814     "cbError callback caused recursive error callback - giving up");
2815   }
2816  __in_vpi_errorcb = TRUE;
2817  exec_vpi_actioncbs(cbError);
2818  __in_vpi_errorcb = FALSE;
2819 
2820  /* PLI error status on until next routine, but other Cver errors */
2821  /* only pending in callback - if no callback no error ever pending */
2822  /* and when all callbacks done, always turned off */
2823  /* needed because no obvious place to reset non PLI errors */
2824  __last_eip = NULL;
2825 }
2826 
2827 
2828 /*
2829  * execute a fixed action or feature call back list
2830  *
2831  * these can only be freed by cb remove
2832  */
exec_vpi_actioncbs(int32 cbtyp)2833 static void exec_vpi_actioncbs(int32 cbtyp)
2834 {
2835  register i_tev_ndx tevpi;
2836  struct cbrec_t *cbp;
2837  struct t_cb_data wrk_cbdata, *datp;
2838 
2839  if ((tevpi = __vpicb_tehdri[cbtyp]) == -1) return;
2840 
2841  datp = &wrk_cbdata;
2842  /* for action cbs, next 3 nil */
2843  datp->time = NULL;
2844  datp->value = NULL;
2845  datp->obj = NULL;
2846 
2847  for (; tevpi != -1; tevpi = __tevtab[tevpi].tenxti)
2848   {
2849    /* if already cancelled (i.e. callback removed), nothing to do */
2850    if (__tevtab[tevpi].te_cancel) continue;
2851 
2852    cbp = __tevtab[tevpi].tu.tehp->hrec->hu.hcbp;
2853    /* SJM 07/24/00 - user can turn off/on with sim control */
2854    if (cbp->cb_user_off) continue;
2855 
2856    datp->reason = cbp->cb_reason;
2857    datp->cb_rtn = cbp->cb_rtn;
2858    datp->user_data = cbp->cb_user_data;
2859 
2860    (*(datp->cb_rtn))(datp);
2861   }
2862  /* nothing to free since cb_data record in automatic storage */
2863 }
2864 
2865 /*
2866  * execute a timing check feature call back list
2867  * these can only be freed by cb remove (or reset)
2868  */
exec_vpi_tchkerr(int32 cbtyp,struct tchk_t * tcp,struct itree_t * itp)2869 static void exec_vpi_tchkerr(int32 cbtyp, struct tchk_t *tcp,
2870  struct itree_t *itp)
2871 {
2872  register i_tev_ndx tevpi;
2873  struct cbrec_t *cbp;
2874  struct t_cb_data wrk_cbdata, *datp;
2875 
2876  if ((tevpi = __vpicb_tehdri[cbtyp]) == -1) return;
2877 
2878  datp = &wrk_cbdata;
2879  /* for action cbs, next 2 nil */
2880  datp->time = NULL;
2881  datp->value = NULL;
2882  /* free on return when all call backs done */
2883  datp->obj = __mk_handle(vpiTchk, (void *) tcp, itp, NULL);
2884 
2885  for (; tevpi != -1; tevpi = __tevtab[tevpi].tenxti)
2886   {
2887    /* if cancelled, cbrec will have been freed */
2888    if (__tevtab[tevpi].te_cancel) continue;
2889 
2890    cbp = __tevtab[tevpi].tu.tehp->hrec->hu.hcbp;
2891 
2892    /* SJM 07/24/00 - user can turn off/on with sim control */
2893    if (cbp->cb_user_off) continue;
2894 
2895    datp->reason = cbp->cb_reason;
2896    datp->cb_rtn = cbp->cb_rtn;
2897 
2898    (*(datp->cb_rtn))(datp);
2899   }
2900  /* can't free timing check object - caller may use it */
2901 }
2902 
2903 /*
2904  * execute a Cver extended foreign language line cb
2905  * call back is cbLanguageLine
2906  * these can only be freed by cb remove
2907  *
2908  * this fills value record misc field with ptr to line record
2909  */
__exec_vpi_langlinecbs(char * lp,char * fnam,int32 lno)2910 extern void __exec_vpi_langlinecbs(char *lp, char *fnam, int32 lno)
2911 {
2912  register i_tev_ndx tevpi;
2913  struct t_vpi_value wrk_val;
2914  struct t_vpi_languageline wrk_langlin;
2915  struct cbrec_t *cbp;
2916  struct t_cb_data wrk_cbdata, *datp;
2917 
2918  if ((tevpi = __vpicb_tehdri[cbLanguageLine]) == -1) return;
2919 
2920  datp = &wrk_cbdata;
2921  /* for action cbs, next 3 nil */
2922  datp->time = NULL;
2923  datp->value = &wrk_val;
2924  datp->value->format = vpiStringVal;
2925  datp->value->value.misc = (char *) &wrk_langlin;
2926  wrk_langlin.linep = lp;
2927  wrk_langlin.file = fnam;
2928  wrk_langlin.lineno = lno;
2929  datp->obj = NULL;
2930 
2931  for (; tevpi != -1; tevpi = __tevtab[tevpi].tenxti)
2932   {
2933    /* if already cancelled (i.e. callback removed), nothing to do */
2934    if (__tevtab[tevpi].te_cancel) continue;
2935 
2936    cbp = __tevtab[tevpi].tu.tehp->hrec->hu.hcbp;
2937    datp->reason = cbp->cb_reason;
2938    datp->cb_rtn = cbp->cb_rtn;
2939    datp->user_data = cbp->cb_user_data;
2940 
2941    (*(datp->cb_rtn))(datp);
2942   }
2943  /* nothing to free since cb_data record in automatic storage */
2944 }
2945 
2946 /*
2947  * CALLBACK REMOVAL ROUTINES
2948  */
2949 
2950 /*
2951  * remove a call back - find and free the cbrec
2952  *
2953  * handle is also freed because if used again will cause error
2954  * can access handle from event and cbrec from handle and back link from
2955  * cbrec to event
2956  *
2957  * notice not freeing p_cb_data since user allocated
2958  * if user references after remove cb, error
2959  * BEWARE - action cbs usually do not have any itree loc (hin_itp nil)
2960  *
2961  * SJM 02/08/03 - removed need for module since now just turn off dces
2962  */
vpi_remove_cb(vpiHandle cb_obj)2963 extern PLI_INT32 vpi_remove_cb(vpiHandle cb_obj)
2964 {
2965  i_tev_ndx tevpi;
2966  struct h_t *hp;
2967  struct hrec_t *hrp;
2968  struct cbrec_t *cbp;
2969  struct tev_t *tevp;
2970 
2971  __last_eip = NULL;
2972  hp = (struct h_t *) cb_obj;
2973  if (!__validate_handle("vpi_remove_cb", hp)) return(FALSE);
2974  hrp = hp->hrec;
2975  if (hrp->htyp != vpiCallback)
2976   {
2977    __vpi_err(1832, vpiError,
2978     "vpi_remove_cb requires vpiCallback handle - %s illegal",
2979     __to_vpionam(__wrks1, hrp->htyp));
2980    return(FALSE);
2981   }
2982  cbp = hrp->hu.hcbp;
2983 
2984  switch (cbp->cb_reason) {
2985   /* value change call backs - removal after some occurred */
2986   case cbValueChange:
2987    if (__run_state != SS_SIM)
2988     {
2989 no_sim:
2990       __sim_notbegun_err("vpi_remove_cb");
2991       return(FALSE);
2992     }
2993    /* no event here - once dce records gone, can't occur */
2994    /* this can only run once simulation starts run state is SIM STATE */
2995    if (cbp->cb_gateout) linkout_gateout_cb(cbp);
2996    else
2997     {
2998      /* SJM 10/06/06 - now vpi looks at head of dce list so */
2999      /* can always free */
3000      __free_dceauxlst(cbp->cbdcep, 1);
3001     }
3002    free_cbrec(cbp);
3003    break;
3004   case cbForce:
3005    if (__run_state != SS_SIM) goto no_sim;
3006    if (cbp->cb_hp != NULL)
3007     {
3008      /* SJM 10/06/06 - now vpi looks at head of dce list so */
3009      /* can always free */
3010      __free_dceauxlst(cbp->cbdcep, 1);
3011 
3012      free_cbrec(cbp);
3013      __num_vpi_force_cbs--;
3014      if (__num_vpi_force_cbs < 0) __vpi_terr(__FILE__, __LINE__);
3015     }
3016    else linkout_allcb(cbp, TRUE);
3017    break;
3018   case cbRelease:
3019    if (__run_state != SS_SIM) goto no_sim;
3020    if (cbp->cb_hp != NULL)
3021     {
3022      /* SJM 10/06/06 - now vpi looks at head of dce list so */
3023      /* can always free */
3024      __free_dceauxlst(cbp->cbdcep, 1);
3025 
3026      free_cbrec(cbp);
3027      __num_vpi_rel_cbs--;
3028      if (__num_vpi_rel_cbs < 0) __vpi_terr(__FILE__, __LINE__);
3029     }
3030    else linkout_allcb(cbp, FALSE);
3031    break;
3032 
3033   /* call backs only removed before they happen */
3034   /* case 1: always scheduled - part of all events removed at end of slot */
3035   /* RW sync moves from scheduled with vpi reschd on to #0 list so */
3036   case cbAfterDelay: case cbAtStartOfSimTime: case cbReadWriteSynch:
3037    if (__run_state != SS_SIM) goto no_sim;
3038    /* when cancelled handle zero and removed from iterator list so must */
3039    /* never be seen again */
3040    tevpi = cbp->cbtevpi;
3041    tevp = &(__tevtab[tevpi]);
3042    /* DBG remove --- */
3043    if (tevp->te_cancel) __vpi_terr(__FILE__, __LINE__);
3044    /* --- */
3045    free_cbrec(cbp);
3046    tevp->te_cancel = TRUE;
3047    tevp->tu.tehp = NULL;
3048    break;
3049 
3050   /* if vpi reschd on, scheduled so cancel event */
3051   /* else remove from action list */
3052   case cbReadOnlySynch:
3053    if (__run_state != SS_SIM) goto no_sim;
3054    tevpi = cbp->cbtevpi;
3055    tevp = &(__tevtab[tevpi]);
3056    /* DBG remove --- */
3057    if (tevp->te_cancel) __vpi_terr(__FILE__, __LINE__);
3058    /* --- */
3059    if (!tevp->vpi_reschd) goto in_nonschd_list;
3060 
3061    free_cbrec(cbp);
3062    tevp->te_cancel = TRUE;
3063    tevp->tu.tehp = NULL;
3064    break;
3065   /* this is treated as an action cb for removal - delay when happens */
3066   case cbNextSimTime:
3067    if (__run_state != SS_SIM) goto no_sim;
3068    goto in_nonschd_list;
3069 
3070   /* action cbs */
3071   case cbEndOfCompile: case cbStartOfSimulation: case cbEndOfSimulation:
3072   case cbError: case cbPLIError: case cbTchkViolation:
3073   case cbStartOfReset: case cbEndOfReset:
3074   case cbEnterInteractive: case cbExitInteractive:
3075   case cbInteractiveScopeChange:
3076   case cbLanguageLine:
3077 in_nonschd_list:
3078    /* permanent lists - link out */
3079    linkout_action_cb(cbp);
3080    free_cbrec(cbp);
3081    break;
3082   /* currently unimplemented */
3083   case cbStartOfSave: case cbEndOfSave: case cbStartOfRestart:
3084   case cbEndOfRestart:
3085   case cbUnresolvedSystf:
3086    __vpi_err(1823, vpiError, "vpi_remove_cb reason %s unsupported",
3087     __cb_reason_to_nam(__wrks1, cbp->cb_reason));
3088    return(FALSE);
3089   case cbStmt:
3090    __vpi_err(1823, vpiError,
3091     "vpi_remove_cb reason %s unsupported - statement callbacks not yet implemented",
3092     __cb_reason_to_nam(__wrks1, cbp->cb_reason));
3093    return(FALSE);
3094   default:
3095    __vpi_err(1824, vpiError,
3096     "vpi_remove_cb illegal reason value %d - no callback removed",
3097      cbp->cb_reason);
3098    return(FALSE);
3099  }
3100  return(TRUE);
3101 }
3102 
3103 /*
3104  * find and link out all forces or release handle (cbrec in list)
3105  *
3106  * this also frees cbrec and allocated copy of cb_data record
3107  */
linkout_allcb(struct cbrec_t * cbp,int32 is_force)3108 static void linkout_allcb(struct cbrec_t *cbp, int32 is_force)
3109 {
3110  register struct rfcblst_t *rfp, *last_rfp;
3111 
3112  last_rfp = NULL;
3113  if (is_force)
3114   {
3115    rfp = __force_allcb_hdr;
3116    /* DBG remove --- */
3117    if (__vpi_force_cb_always && rfp == NULL) __vpi_terr(__FILE__, __LINE__);
3118    if (!__vpi_rel_cb_always && rfp != NULL) __vpi_terr(__FILE__, __LINE__);
3119    /* --- */
3120    for (; rfp != NULL; rfp = rfp->rfcbnxt)
3121     { if (rfp->rfcbp == cbp) goto got_force_cbp; last_rfp = rfp; }
3122    __vpi_terr(__FILE__, __LINE__);
3123 got_force_cbp:
3124    /* case 1: removing from front */
3125    if (last_rfp == NULL)
3126     {
3127      /* case 1a: only one */
3128      if (rfp->rfcbnxt == NULL)
3129       {
3130        __vpi_force_cb_always = FALSE;
3131        __force_allcb_hdr = __force_allcb_end = NULL;
3132 rem_done:
3133        free_cbrec(rfp->rfcbp);
3134        __my_free((char *) rfp, sizeof(struct rfcblst_t));
3135        return;
3136      }
3137      /* case 1b: more than one */
3138      __force_allcb_hdr = rfp->rfcbnxt;
3139      goto rem_done;
3140     }
3141    /* case 2: removing from inside */
3142    if (rfp->rfcbnxt == NULL)
3143     {
3144      /* case 2a: removing last */
3145      __force_allcb_end = last_rfp;
3146      last_rfp->rfcbnxt = NULL;
3147      goto rem_done;
3148     }
3149    /* case 2a: removing interior */
3150    last_rfp->rfcbnxt = rfp->rfcbnxt;
3151    goto rem_done;
3152   }
3153  rfp = __rel_allcb_hdr;
3154  /* DBG remove --- */
3155  if (__vpi_rel_cb_always && rfp == NULL) __vpi_terr(__FILE__, __LINE__);
3156  if (!__vpi_rel_cb_always && rfp != NULL) __vpi_terr(__FILE__, __LINE__);
3157  /* --- */
3158  for (; rfp != NULL; rfp = rfp->rfcbnxt)
3159   { if (rfp->rfcbp == cbp) goto got_rel_cbp; last_rfp = rfp;   }
3160  __vpi_terr(__FILE__, __LINE__);
3161 got_rel_cbp:
3162  /* case 1: removing from front */
3163  if (last_rfp == NULL)
3164   {
3165    /* case 1a: only one */
3166    if (rfp->rfcbnxt == NULL)
3167     {
3168      __vpi_rel_cb_always = FALSE;
3169      __rel_allcb_hdr = __rel_allcb_end = NULL;
3170      goto rem_done;
3171     }
3172    /* case 1b: more than one */
3173    __rel_allcb_hdr = rfp->rfcbnxt;
3174    goto rem_done;
3175   }
3176  /* case 2: removing from inside */
3177  if (rfp->rfcbnxt == NULL)
3178   {
3179    /* case 2a: removing last */
3180    __rel_allcb_end = last_rfp;
3181    last_rfp->rfcbnxt = NULL;
3182    goto rem_done;
3183   }
3184  /* case 2a: removing interior */
3185  last_rfp->rfcbnxt = rfp->rfcbnxt;
3186  goto rem_done;
3187 }
3188 
3189 /*
3190  * link out prim output term
3191  *
3192  * although using tev, not part of scheduling mechanism just in list
3193  */
linkout_gateout_cb(struct cbrec_t * cbp)3194 static void linkout_gateout_cb(struct cbrec_t *cbp)
3195 {
3196  register i_tev_ndx tevpi, last_tevpi;
3197  int32 gi, ii;
3198  struct h_t *ghp;
3199  struct gate_t *gp;
3200  struct mod_t *mdp;
3201 
3202  ghp = cbp->cb_hp;
3203  mdp = ghp->hin_itp->itip->imsym->el.emdp;
3204  ii = ghp->hin_itp->itinum;
3205  gp = ghp->hrec->hu.hgp;
3206  gi = gp - mdp->mgates;
3207  if (mdp->mgateout_cbs == NULL || mdp->mgateout_cbs[gi] == NULL
3208   || mdp->mgateout_cbs[gi][ii] == -1)
3209   {
3210    __vpi_err(1826, vpiError,
3211     "vpi_remove_cb of primitive terminal output value change type failed - cb handle already removed?");
3212    return;
3213   }
3214  last_tevpi = -1;
3215  tevpi = mdp->mgateout_cbs[gi][ii];
3216  for (; tevpi != -1; tevpi = __tevtab[tevpi].tenxti)
3217   {
3218    /* find right one to remove and one before it if not front */
3219    if (tevpi != cbp->cbtevpi) { last_tevpi = tevpi; continue; }
3220 
3221    /* one to remove on front */
3222    if (last_tevpi == -1)
3223     {
3224      /* just one to remove */
3225      if (__tevtab[tevpi].tenxti == -1) mdp->mgateout_cbs[gi][ii] = -1;
3226      /* link out first te end remains same */
3227      else mdp->mgateout_cbs[gi][ii] = __tevtab[tevpi].tenxti;
3228     }
3229    else
3230     {
3231      /* at end */
3232      if (__tevtab[tevpi].tenxti == -1) __tevtab[last_tevpi].tenxti = -1;
3233      /* te end remains same */
3234      else __tevtab[last_tevpi].tenxti = __tevtab[tevpi].tenxti;
3235     }
3236    /* link on front of free list - pseudo event so nothing else to do */
3237    __tevtab[tevpi].tenxti = __tefreelsti;
3238    __tefreelsti = tevpi;
3239    return;
3240   }
3241  __vpi_terr(__FILE__, __LINE__);
3242 }
3243 
3244 /*
3245  * link out action call back tevp from an action list
3246  *
3247  * although using tev, not part of scheduling mechanism just in list
3248  */
linkout_action_cb(struct cbrec_t * cbp)3249 static void linkout_action_cb(struct cbrec_t *cbp)
3250 {
3251  register i_tev_ndx tevpi, last_tevpi;
3252 
3253  if ((tevpi = __vpicb_tehdri[cbp->cb_reason]) == -1)
3254   {
3255    __vpi_err(1826, vpiError,
3256     "vpi_remove_cb of action type %s failed - cb handle already removed?",
3257     to_cbtypnam(__wrks1, cbp->cb_reason));
3258    return;
3259   }
3260  last_tevpi = -1;
3261  for (; tevpi != -1; tevpi = __tevtab[tevpi].tenxti)
3262   {
3263    /* find right one to remove and one before it if not front */
3264    if (tevpi != cbp->cbtevpi) { last_tevpi = tevpi; continue; }
3265 
3266    /* one to remove on front */
3267    if (last_tevpi == -1)
3268     {
3269      /* just one to remove */
3270      if (__tevtab[tevpi].tenxti == -1)
3271       {
3272        /* turn off special compile error callback registered flag */
3273        if (__vpicb_tehdri[cbp->cb_reason] == cbError)
3274         __vpierr_cb_active = FALSE;
3275 
3276        /* then remove the action call back */
3277        __vpicb_tehdri[cbp->cb_reason] = __vpicb_teendi[cbp->cb_reason] = -1;
3278       }
3279      /* link out first te end remains same */
3280      else __vpicb_tehdri[cbp->cb_reason] = __tevtab[tevpi].tenxti;
3281     }
3282    else
3283     {
3284      /* at end */
3285      if (__tevtab[tevpi].tenxti == -1)
3286       {
3287        __tevtab[last_tevpi].tenxti = -1;
3288        __vpicb_teendi[cbp->cb_reason] = last_tevpi;
3289       }
3290      /* te end remains same */
3291      else __tevtab[last_tevpi].tenxti = __tevtab[tevpi].tenxti;
3292     }
3293    /* link on front of free list - pseudo event so nothing else to do */
3294    __tevtab[tevpi].tenxti = __tefreelsti;
3295    __tefreelsti = tevpi;
3296    return;
3297   }
3298  __vpi_terr(__FILE__, __LINE__);
3299 }
3300 
3301 /*
3302  * convert a call back value to its name
3303  */
to_cbtypnam(char * s,int32 reason)3304 static char *to_cbtypnam(char *s, int32 reason)
3305 {
3306  switch (reason) {
3307   case cbValueChange: strcpy(s, "cbValueChange"); break;
3308   case cbStmt: strcpy(s, "cbStmt"); break;
3309   case cbForce: strcpy(s, "cbForce"); break;
3310   case cbRelease: strcpy(s, "cbRelease"); break;
3311   case cbAtStartOfSimTime: strcpy(s, "cbAtStartOfSimTime"); break;
3312   case cbReadWriteSynch: strcpy(s, "cbReadWriteSynch"); break;
3313   case cbReadOnlySynch: strcpy(s, "cbReadOnlySynch"); break;
3314   case cbNextSimTime: strcpy(s, "cbNextSimTime"); break;
3315   case cbAfterDelay: strcpy(s, "cbAfterDelay"); break;
3316   case cbEndOfCompile: strcpy(s, "cbEndOfCompile"); break;
3317   case cbStartOfSimulation: strcpy(s, "cbStartOfSimulation"); break;
3318   case cbEndOfSimulation: strcpy(s, "cbEndOfSimulation"); break;
3319   case cbError: strcpy(s, "cbError"); break;
3320   case cbTchkViolation: strcpy(s, "cbTchkViolation"); break;
3321   case cbStartOfSave: strcpy(s, "cbStartOfSave"); break;
3322   case cbEndOfSave: strcpy(s, "cbEndOfSave"); break;
3323   case cbStartOfRestart: strcpy(s, "cbStartOfRestart"); break;
3324   case cbEndOfRestart: strcpy(s, "cbEndOfRestart"); break;
3325   case cbStartOfReset: strcpy(s, "cbStartOfReset"); break;
3326   case cbEndOfReset: strcpy(s, "cbEndOfReset"); break;
3327   case cbEnterInteractive: strcpy(s, "cbEnterInteractive"); break;
3328   case cbExitInteractive: strcpy(s, "cbExitInteractive"); break;
3329   case cbInteractiveScopeChange: strcpy(s, "cbInteractiveScopeChange"); break;
3330   case cbUnresolvedSystf: strcpy(s, "cbUnresolvedSystf"); break;
3331   default: strcpy(s, "**none**");
3332  }
3333  return(s);
3334 }
3335 
3336 /*
3337  * get information about a call back
3338  *
3339  * LOOKATME - standard should return ptr not copy - copy guts for now
3340  */
vpi_get_cb_info(vpiHandle object,p_cb_data cb_data_p)3341 extern void vpi_get_cb_info(vpiHandle object, p_cb_data cb_data_p)
3342 {
3343  struct h_t *hp;
3344  struct hrec_t *hrp;
3345  struct cbrec_t *cbp;
3346 
3347  hp = (struct h_t *) object;
3348  if (!__validate_handle("vpi_get_cb_info", hp)) return;
3349  hrp = hp->hrec;
3350  if (hrp->htyp != vpiCallback)
3351   {
3352    __vpi_err(1825, vpiError,
3353     "vpiget_cb_info requires vpiCallback object argument - %s illegal",
3354     __to_vpionam(__wrks1, hrp->htyp));
3355    return;
3356   }
3357  cbp = hrp->hu.hcbp;
3358  cb_data_p->reason = cbp->cb_reason;
3359  cb_data_p->cb_rtn = cbp->cb_rtn;
3360  cb_data_p->obj = (vpiHandle) cbp->cb_hp;
3361  if (cb_data_p->time != NULL) cb_data_p->time->type = (int32) cbp->cb_rettimtyp;
3362  if (cb_data_p->value != NULL)
3363   cb_data_p->value->format = (int32) cbp->cb_retvalfmt;
3364  cb_data_p->index = 0;
3365  cb_data_p->user_data = cbp->cb_user_data;
3366 }
3367 
3368 /*
3369  * ROUTINES FOR TRAVERSING OBJECTS
3370  */
3371 
3372 /*
3373  * get a 1-to-1 object handle given a reference handle and 1-to-1 access type
3374  *
3375  * for Cver only declarative structure and variables accessible and know
3376  * handle will be of supported object type
3377  *
3378  * ALGORITHM:  use destination property (or tag) as first level index
3379  * then for each destination use reference handle (object) to
3380  * as starting point for which to select the destination property from
3381  */
vpi_handle(PLI_INT32 type,vpiHandle referenceHandle)3382 extern vpiHandle vpi_handle(PLI_INT32 type, vpiHandle referenceHandle)
3383 {
3384  register struct h_t *rhp;
3385  register struct hrec_t *rhrp;
3386  int32 sf_ind;
3387  word32 sttyp, primtyp;
3388  struct sy_t *syp;
3389  struct st_t *stp;
3390  struct expr_t *xp;
3391  struct itree_t *itp;
3392  struct net_t *np;
3393 
3394  /* must reset at start of call to no error */
3395  __last_eip = NULL;
3396  if (__run_state == SS_COMP)
3397   { __still_comp_err("vpi_handle"); return(NULL); }
3398  if (!__validate_accessm("vpi_handle", type, "1-to-1")) return(NULL);
3399  rhp = (struct h_t *) referenceHandle;
3400  /* handle must be nil can not validate */
3401  if (type == vpiSysTfCall) return(get_cursystfcall(rhp));
3402  if (!__validate_handle("vpi_handle", rhp)) return(NULL);
3403  rhrp = rhp->hrec;
3404 
3405  switch (type) {
3406   /* get an object of type module (itree instance) that contains handle */
3407   case vpiModule:
3408    return(get_inmod_itp(rhp));
3409   case vpiIndex: return(get_obj_index(rhp));
3410   case vpiLeftRange: return(get_obj_range(rhp, type));
3411   case vpiRightRange: return(get_obj_range(rhp, type));
3412   /* only selects have parents - vpiScope or vpiModule for containing scope */
3413   case vpiParent: return(get_obj_parent(rhp));
3414   case vpiRhs: return(get_obj_side(rhp, type));
3415   case vpiLhs: return(get_obj_side(rhp, type));
3416   case vpiLowConn:
3417    /* port bit high conn is variable or var bit not expr */
3418    if (rhrp->htyp == vpiPortBit) return(getbit_lowconn(rhp));
3419    /* lowconn of port is module port expression */
3420    if (rhrp->htyp == vpiPort) return(getexpr_lowconn(rhp));
3421    goto bad_args;
3422   case vpiHighConn:
3423    /* port bit high conn is variable or var bit not expr */
3424    if (rhrp->htyp == vpiPortBit) return(getbit_highconn(rhp));
3425    /* highconn of port is expression */
3426    if (rhrp->htyp == vpiPort) return(getexpr_highconn(rhp));
3427    goto bad_args;
3428   case vpiTask:
3429    if (rhrp->htyp != vpiTaskCall) goto bad_args;
3430    syp = rhrp->hu.hstp->st.stkc.tsksyx->lu.x->lu.sy;
3431    /* this is task definition handle - tsk in not set */
3432    /* know task def. at top level */
3433    return(__mk_handle(vpiTask, (void *) syp->el.etskp, rhp->hin_itp, NULL));
3434   case vpiFunction:
3435    if (rhrp->htyp != vpiFuncCall) goto bad_args;
3436    syp = rhrp->hu.hxp->lu.x->lu.sy;
3437    return(__mk_handle(vpiFunction, (void *) syp->el.etskp, rhp->hin_itp,
3438     NULL));
3439   case vpiUserSystf:
3440    if (rhrp->htyp == vpiSysFuncCall)
3441     {
3442      syp = rhrp->hu.hxp->lu.x->lu.sy;
3443 do_usersystf:
3444      sf_ind = syp->el.esyftbp->syfnum;
3445      if (sf_ind <= __last_veriusertf || sf_ind > __last_systf)
3446       {
3447        __vpi_err(1829, vpiError,
3448         "%s (of %s) handle no vpiUserSystf handle - not registered vpi_",
3449         __to_vpionam(__wrks1, rhp->hrec->htyp), syp->synam);
3450        return(NULL);
3451       }
3452      return(__mk_handle(vpiUserSystf, (void *) sf_ind, NULL, NULL));
3453     }
3454    if (rhrp->htyp == vpiSysTaskCall)
3455     {
3456      syp = rhrp->hu.hstp->st.stkc.tsksyx->lu.x->lu.sy;
3457      goto do_usersystf;
3458     }
3459    goto bad_args;
3460   /* notifier returns reg handle, others tchk term */
3461   case vpiTchkRefTerm: case vpiTchkDataTerm: case vpiTchkNotifier:
3462    return(get_tchk_term((word32) type, rhp));
3463   case vpiTchk:
3464    /* LOOKATME - LRM says no connection back from notifier */
3465    if (rhrp->htyp != vpiTchkRefTerm && rhrp->htyp != vpiTchkDataTerm
3466     && rhrp->htyp != vpiTchkNotifier) goto bad_args;
3467    return(__mk_handle(vpiTchk, (void *) rhrp->hu.htcp, rhp->hin_itp, NULL));
3468   case vpiModPath:
3469    if (rhrp->htyp != vpiPathTerm) goto bad_args;
3470    return(__mk_handle(vpiModPath, (void *) rhrp->hu.hpthp, rhp->hin_itp,
3471     NULL));
3472   case vpiPrimitive:
3473    /* handle from primitive term to primitive it is part of */
3474    if (rhrp->htyp != vpiPrimTerm) goto bad_args;
3475    primtyp = __gate_to_vpiprimtyp(rhrp->hu.hgp);
3476    return(__mk_handle(primtyp, (void *) rhrp->hu.hgp, rhp->hin_itp, NULL));
3477   case vpiCondition: return(get_cond(rhp));
3478   case vpiElseStmt:
3479    if (rhrp->htyp != vpiIfElse) goto bad_args;
3480    stp = rhrp->hu.hstp->st.sif.elsest;
3481    if (stp->st_unbhead) sttyp = vpiBegin;
3482    else sttyp = __to_vpi_stmttyp(&stp);
3483    return(__mk_stmt_handle(sttyp, stp, rhp->hin_itp, rhrp->hin_tskp));
3484   case vpiExpr:
3485    return(bld_1to1_exprclass_handle(rhp));
3486   case vpiNamedEvent:
3487    if (rhrp->htyp != vpiEventStmt) goto bad_args;
3488    stp = rhrp->hu.hstp;
3489    xp = stp->st.scausx;
3490    if (xp->optyp == GLBREF)
3491     {
3492      __push_itstk(rhp->hin_itp);
3493      __xmrpush_refgrp_to_targ(xp->ru.grp);
3494      itp = __inst_ptr;
3495      __pop_itstk();
3496      __pop_itstk();
3497     }
3498    else if (xp->optyp == ID) itp = rhp->hin_itp;
3499    else { __vpi_terr(__FILE__, __LINE__); return(NULL); }
3500    np = xp->lu.sy->el.enp;
3501    return(__mk_handle(vpiNamedEvent, (void *) np, itp, rhrp->hin_tskp));
3502   /* scope handle offrom disable statement */
3503   case vpiScope: return(get_obj_scope(rhp));
3504   case vpiStmt: return(get_contained_stmt(rhp));
3505   case vpiDelayControl: case vpiRepeatControl:
3506    return(get_dctrl_stmt(rhp, type));
3507   case vpiEventControl:
3508    /* repeat dctrl form does not have contained stmt only contained ev ctrl */
3509    if (rhrp->htyp == vpiRepeatControl)
3510     {
3511      /* actual h_u object is the S DELCTRL - only difference between */
3512      /* repeat ev cntrl and normal ev cntrl is type */
3513      return(__mk_handle(vpiEventControl, (void *) rhrp->hu.hstp, rhp->hin_itp,
3514       rhrp->hin_tskp));
3515     }
3516    return(get_dctrl_stmt(rhp, type));
3517   case vpiForInitStmt:
3518    if (rhrp->htyp != vpiFor) goto bad_args;
3519    stp = rhrp->hu.hstp->st.sfor->forassgn;
3520    /* this must really return for init part (special prefix now to for) */
3521    /* so cannot call to vpi stmttyp */
3522    /* DBG remove -- */
3523    if (stp->stmttyp != S_FORASSGN) __vpi_terr(__FILE__, __LINE__);
3524    /* --- */
3525    return(__mk_handle(vpiAssignment, (void *) stp, rhp->hin_itp,
3526     rhrp->hin_tskp));
3527   case vpiForIncStmt:
3528    if (rhrp->htyp != vpiFor) goto bad_args;
3529    stp = rhrp->hu.hstp->st.sfor->forinc;
3530    sttyp = __to_vpi_stmttyp(&stp);
3531    return(__mk_stmt_handle(sttyp, stp, rhp->hin_itp, rhrp->hin_tskp));
3532   case vpiUdpDefn:
3533    return(get_udpdef_from_inobj(rhp));
3534   case vpiInitial:
3535    /* udp initial statement - containing is udp define */
3536    if (rhrp->htyp != vpiUdpDefn) goto bad_args;
3537    return(get_contained_udp_init(rhp));
3538   case vpiPoundParam:
3539    return(get_up_poundparam_expr(rhp));
3540   default:
3541 bad_args:
3542    __vpi_err(1827, vpiError,
3543     "there is no 1-to-1 relationships of type %s from reference handle %s",
3544     __to_vpionam(__wrks1, (word32) type), __to_vpionam(__wrks2, rhrp->htyp));
3545  }
3546  return(NULL);
3547 }
3548 
3549 /*
3550  * access handle for multi-dimensional array - mult dim arrays not supported
3551  */
vpi_handle_multi(PLI_INT32 type,vpiHandle refHandle1,vpiHandle refHandle2,...)3552 extern vpiHandle vpi_handle_multi(PLI_INT32 type, vpiHandle refHandle1,
3553  vpiHandle refHandle2, ...)
3554 {
3555  __vpi_err(1801, vpiError, "vpi_handle_multi routine currently unsupported");
3556  return(NULL);
3557 }
3558 
3559 /*
3560  * make a statement handle
3561  *
3562  * handles name block (fj or begin) except where contents is task not stp
3563  */
__mk_stmt_handle(word32 sttyp,struct st_t * stp,struct itree_t * itp,struct task_t * tskp)3564 extern vpiHandle __mk_stmt_handle(word32 sttyp, struct st_t *stp,
3565  struct itree_t *itp, struct task_t *tskp)
3566 {
3567  if (sttyp == vpiNamedBegin || sttyp == vpiNamedFork)
3568   {
3569    return(__mk_handle(sttyp, (void *) stp->st.snbtsk, itp, tskp));
3570   }
3571  return(__mk_handle(sttyp, (void *) stp, itp, tskp));
3572 }
3573 
3574 /*
3575  * get current user systf call handle that can be passed to get systf info
3576  *
3577  * this must be sys tf call with itree and task loc. but LRM unclear
3578  * this can only be called from inside called vpi sys task or func.
3579  */
get_cursystfcall(struct h_t * hp)3580 static vpiHandle get_cursystfcall(struct h_t *hp)
3581 {
3582  vpiHandle ihref;
3583  struct task_t *tskp;
3584 
3585  if (hp != NULL)
3586   {
3587    __vpi_err(1833, vpiError,
3588     "vpi_handle with 1-to-1 vpiSysTfCall NULL handle required - %s illegal",
3589     __to_vpionam(__wrks1, hp->hrec->htyp));
3590    return(NULL);
3591   }
3592  /* DBG remove --- */
3593  if (__cur_sysf_expr == NULL && __cur_syst_stp == NULL)
3594   {
3595    __vpi_err(1840, vpiError,
3596     "vpi_handle with vpiSysTfCall not called from inside vpi_ systf callback");
3597    return(NULL);
3598   }
3599  /* --- */
3600  /* DBG remove --- */
3601  if (__cur_sysf_expr != NULL && __cur_syst_stp != NULL)
3602   __vpi_terr(__FILE__, __LINE__);
3603  /* --- */
3604  tskp = __getcur_scope_tsk();
3605  if (__cur_sysf_expr != NULL)
3606   ihref = __mk_handle(vpiSysFuncCall, (void *) __cur_sysf_expr, __inst_ptr,
3607    tskp);
3608  else ihref = __mk_handle(vpiSysTaskCall, (void *) __cur_syst_stp, __inst_ptr,
3609   tskp);
3610  return(ihref);
3611 }
3612 
3613 /*
3614  * for object in module, get enclosing module (actually itree inst)
3615  *
3616  * non declarative object types will never be handle types
3617  */
get_inmod_itp(struct h_t * hp)3618 static vpiHandle get_inmod_itp(struct h_t *hp)
3619 {
3620  struct itree_t *itp;
3621 
3622  switch (hp->hrec->htyp) {
3623   case vpiModule:
3624    if ((itp = hp->hin_itp->up_it) == NULL) return(NULL);
3625    return(__mk_handle(vpiModule, (void *) itp->itip->imsym->el.emdp, itp,
3626     NULL));
3627    /* even if inner scope (in nested named blocks?), still itree inst. */
3628    /* scope is symbol table so top mod scope goes to itree inst (mod) */
3629    /* SJM 11/13/00 - forgot vpiReg - now added and checked new LRM */
3630   case vpiPort: case vpiNet: case vpiReg: case vpiIntegerVar: case vpiTimeVar:
3631   case vpiRealVar: case vpiMemory: case vpiNamedEvent: case vpiContAssign:
3632   case vpiGate: case vpiSwitch: case vpiUdp: case vpiModPath: case vpiTchk:
3633   case vpiSpecParam: case vpiDefParam:
3634   case vpiIODecl:
3635    break;
3636   case vpiParameter: case vpiParamAssign:
3637    break;
3638 
3639   /* can get containing module (inst) for any of 4 scope objects */
3640   case vpiTask: case vpiFunction: case vpiNamedBegin: case vpiNamedFork:
3641    break;
3642   case vpiInitial: case vpiAlways:
3643    break;
3644   default: no_1to1h_err(vpiModule, hp); return(NULL);
3645  }
3646  /* down handle will always have itree loc. */
3647  return(__mk_handle(vpiModule, (void *) hp->hin_itp->itip->imsym->el.emdp,
3648   hp->hin_itp, NULL));
3649 }
3650 
3651 /*
3652  * build a handle from malloced array - user must handle freeing
3653  * this should probably be macro
3654  */
__mk_handle(word32 typ,void * h_unp,struct itree_t * itp,struct task_t * tskp)3655 extern vpiHandle __mk_handle(word32 typ, void *h_unp, struct itree_t *itp,
3656  struct task_t *tskp)
3657 {
3658  register int32 hi;
3659  register struct h_t *hp, *hparr;
3660  register struct hrec_t *hrp, *hrarr;
3661 
3662  /* if free list empty - add a few thousand */
3663  /* separate malloc calls waste 16 bytes per call for small record */
3664  if (__vpi_hfree_hdr == NULL)
3665   {
3666    hparr = (struct h_t *) __my_malloc(VPI_OBJALLOCNUM*sizeof(struct h_t));
3667    for (hi = 0; hi < VPI_OBJALLOCNUM - 1; hi++)
3668     {
3669      hparr[hi].hin_itp = (struct itree_t *) &(hparr[hi + 1]);
3670     }
3671    hparr[VPI_OBJALLOCNUM - 1].hin_itp = NULL;
3672    __vpi_hfree_hdr = &(hparr[0]);
3673   }
3674  if (__vpi_hrecfree_hdr == NULL)
3675   {
3676    hrarr = (struct hrec_t *)
3677     __my_malloc(VPI_OBJALLOCNUM*sizeof(struct hrec_t));
3678    for (hi = 0; hi < VPI_OBJALLOCNUM - 1; hi++)
3679     {
3680      hrarr[hi].hu.hfreenxt = &(hrarr[hi + 1]);
3681     }
3682    hrarr[VPI_OBJALLOCNUM - 1].hu.hfreenxt = NULL;
3683    __vpi_hrecfree_hdr = &(hrarr[0]);
3684   }
3685 
3686  /* know at least one always on each free list by here */
3687  hrp = __vpi_hrecfree_hdr;
3688  __vpi_hrecfree_hdr = hrp->hu.hfreenxt;
3689 
3690  hp = __vpi_hfree_hdr;
3691  __vpi_hfree_hdr = (struct h_t *) hp->hin_itp;
3692 
3693  __init_hrec(hrp);
3694  hrp->htyp = typ;
3695  hrp->hu.hanyp = h_unp;
3696  hrp->hin_tskp = tskp;
3697 
3698  hp->hin_itp = itp;
3699  hp->hrec = hrp;
3700 
3701  return((vpiHandle) hp);
3702 }
3703 
3704 /*
3705  * initialize a cver internal handle - zeroing handle turns off bits
3706  *
3707  * BEWARE - because zeroing must always define set bits to init to F (0)
3708  */
__init_hrec(struct hrec_t * hrp)3709 extern void __init_hrec(struct hrec_t *hrp)
3710 {
3711  memset(hrp, 0, sizeof(struct hrec_t));
3712  hrp->h_magic = PVH_MAGIC;
3713  hrp->hi = -1;
3714 }
3715 
3716 /*
3717  * build an index expression handle for an object
3718  *
3719  * this always blds vpiConst expr. handle - i.e. evaluates expression
3720  *
3721  * for bith ndx forms (from per bit iterator) must convert to const and norm
3722  */
get_obj_index(struct h_t * hp)3723 static vpiHandle get_obj_index(struct h_t *hp)
3724 {
3725  register word32 av;
3726  register struct hrec_t *hrp;
3727  vpiHandle ihref;
3728  struct h_t *rhp;
3729 
3730  hrp = hp->hrec;
3731  switch (hrp->htyp) {
3732   case vpiMemoryWord: case vpiNetBit: case vpiRegBit: case vpiVarSelect:
3733    /* case 1, alternate form for expr. handle is fixed index */
3734    if (hrp->bith_ndx)
3735     {
3736      /* index hi is fixed index - know in range */
3737      av = (word32) __unnormalize_ndx(hrp->hu.hnp, hrp->hi);
3738      /* this is expr. separate from bsel so must be unnormalized value */
3739      /* because not connected to bsel constant can be unnormalized */
3740 bld_const_obj:
3741      ihref = __mk_handle(vpiConstant, NULL, hp->hin_itp, hrp->hin_tskp);
3742      rhp = (struct h_t *) ihref;
3743      rhp->hrec->hu.hxp = __bld_rng_numxpr(av, 0L, WBITS);
3744      rhp->hrec->free_xpr = TRUE;
3745      break;
3746     }
3747    /* expr form case */
3748    /* DBG remove --- */
3749    if (hrp->hu.hxp->optyp != LSB) __vpi_terr(__FILE__, __LINE__);
3750    /* --- */
3751    ihref = __mk_exprclass_handle(hrp->hu.hxp->ru.x, hp->hin_itp,
3752     hrp->hin_tskp);
3753    break;
3754   case vpiPortBit:
3755    /* no ned to normalize since port bits virtual range always h:0 */
3756    av = (word32) hrp->hi;
3757    goto bld_const_obj;
3758   default: no_1to1h_err(vpiIndex, hp); return(NULL);
3759  }
3760  return(ihref);
3761 }
3762 
3763 /*
3764  * build an index expression handle for an object
3765  */
get_obj_range(struct h_t * hp,int32 lrtyp)3766 static vpiHandle get_obj_range(struct h_t *hp, int32 lrtyp)
3767 {
3768  register struct hrec_t *hrp;
3769  int32 r1, r2, wid;
3770  vpiHandle ihref;
3771  word32 rngv;
3772  struct h_t *rhp;
3773  struct expr_t *xp;
3774  struct task_t *tskp;
3775  struct net_t *np;
3776 
3777  rngv = 0;
3778  hrp = hp->hrec;
3779  switch (hrp->htyp) {
3780   case vpiNet: case vpiReg:
3781    if (!hrp->hu.hnp->n_isavec) return(NULL);
3782    goto get_rng;
3783   case vpiIntegerVar: case vpiTimeVar:
3784 get_rng:
3785    __getwir_range(hrp->hu.hnp, &r1, &r2);
3786    if (lrtyp == vpiLeftRange) rngv = (word32) r1; else rngv = (word32) r2;
3787 set_val:
3788    ihref = __mk_handle(vpiConstant, NULL, hp->hin_itp, hrp->hin_tskp);
3789    rhp = (struct h_t *) ihref;
3790    rhp->hrec->hu.hxp = __bld_rng_numxpr(rngv, 0L, WBITS);
3791    rhp->hrec->free_xpr = TRUE;
3792    break;
3793   case vpiMemoryWord:
3794    if (hrp->bith_ndx) np = hrp->hu.hnp;
3795    else
3796     {
3797      xp = hrp->hu.hxp;
3798      /* DBG remove -- */
3799      if (xp->optyp != LSB) __vpi_terr(__FILE__, __LINE__);
3800      /* --- */
3801      np = xp->lu.x->lu.sy->el.enp;
3802     }
3803    if (!np->n_isavec || np->ntyp == N_REAL) return(NULL);
3804    __getwir_range(np, &r1, &r2);
3805    if (lrtyp == vpiLeftRange) rngv = (word32) r1; else rngv = (word32) r2;
3806    goto set_val;
3807   case vpiFunction:
3808    /* this if function declaration - only reg ret. funcs have range */
3809    tskp = hrp->hu.htskp;
3810    np = tskp->tskpins->tpsy->el.enp;
3811    if (!np->n_isavec) return(NULL);
3812    __getwir_range(np, &r1, &r2);
3813    if (lrtyp == vpiLeftRange) rngv = (word32) r1; else rngv = (word32) r2;
3814    goto set_val;
3815   case vpiMemory:
3816    __getarr_range(hrp->hu.hnp, &r1, &r2, &wid);
3817    if (lrtyp == vpiLeftRange) rngv = (word32) r1; else rngv = (word32) r2;
3818    goto set_val;
3819   /* expr that is part select has ranges */
3820   case vpiPartSelect:
3821    xp = hrp->hu.hxp;
3822    /* know range can never be x or will not get here */
3823 
3824    if (lrtyp == vpiLeftRange) rngv = __contab[xp->ru.x->lu.x->ru.xvi];
3825    else rngv = __contab[xp->ru.x->ru.x->ru.xvi];
3826    goto set_val;
3827   case vpiIODecl:
3828    if (hrp->htyp2 == vpiUdpDefn)
3829     {
3830      /* udp io decls always scalars so no ranges */
3831      return(NULL);
3832     }
3833    np = hrp->hu.hnp;
3834    if (!np->n_isavec) return(NULL);
3835    goto get_rng;
3836   default:
3837    no_1to1h_err(lrtyp, hp);
3838    return(NULL);
3839  }
3840  return(ihref);
3841 }
3842 
3843 /*
3844  * get parent (containing) handle for bit of object
3845  *
3846  * also gets object part select is select of
3847  * here for non index form of these must map to itree loc of variable
3848  * also know never see bith index form for xmr
3849  *
3850  * tricky because for index handles must map to dest. for xmrs
3851  */
get_obj_parent(struct h_t * hp)3852 static vpiHandle get_obj_parent(struct h_t *hp)
3853 {
3854  register struct hrec_t *hrp;
3855  word32 hotyp;
3856  vpiHandle ihref;
3857  struct expr_t *idndp;
3858  struct net_t *np;
3859  struct itree_t *nitp;
3860  struct task_t *ntskp;
3861  struct h_t *hp2;
3862 
3863  ihref = NULL;
3864  hrp = hp->hrec;
3865  switch (hrp->htyp) {
3866   case vpiMemoryWord:
3867    if (hrp->bith_ndx)
3868     {
3869      ihref = __mk_handle(vpiMemory, (void *) hrp->hu.hnp, hp->hin_itp,
3870       hrp->hin_tskp);
3871      break;
3872     }
3873    hotyp = vpiMemory;
3874 bld_par_handle:
3875    idndp = hrp->hu.hxp->lu.x;
3876    /* expr. form - for xmr must map to right itree and task loc. */
3877    exprobj_to_itreeloc(&nitp, &ntskp, idndp, hp->hin_itp, hrp->hin_tskp);
3878    ihref = __mk_handle(hotyp, (void *) idndp->lu.sy->el.enp, nitp, ntskp);
3879    break;
3880   case vpiNetBit:
3881    if (hrp->bith_ndx)
3882     {
3883      ihref = __mk_handle(vpiNet, (void *) hrp->hu.hnp, hp->hin_itp,
3884       hrp->hin_tskp);
3885      break;
3886     }
3887    hotyp = vpiNet;
3888    goto bld_par_handle;
3889   case vpiRegBit: case vpiVarSelect:
3890    if (hrp->bith_ndx)
3891     {
3892      hotyp = __ntyp_to_vpivarhtyp(hrp->hu.hnp);
3893      ihref = __mk_handle(hotyp, (void *) hrp->hu.hnp, hp->hin_itp,
3894       hrp->hin_tskp);
3895      break;
3896     }
3897    hotyp = __ntyp_to_vpivarhtyp(hrp->hu.hxp->lu.x->lu.sy->el.enp);
3898    goto bld_par_handle;
3899   case vpiPortBit:
3900    /* know in_tskp will be nil */
3901    ihref = __mk_handle(vpiPort, (void *) hrp->hu.hpi, hp->hin_itp,
3902     hrp->hin_tskp);
3903    break;
3904   case vpiPartSelect:
3905    np = hrp->hu.hxp->lu.x->lu.sy->el.enp;
3906    hotyp = __ntyp_to_vpivarhtyp(np);
3907    goto bld_par_handle;
3908   case vpiNetDriver:
3909    np = hrp->hu.hnpp->elnpp.enp;
3910    ihref = __mk_handle(vpiNet, (void *) np, hp->hin_itp, hrp->hin_tskp);
3911    break;
3912   case vpiPrimTerm:
3913    /* parent of primitive (gate) terminal is primitive */
3914    hotyp = __gate_to_vpiprimtyp(hrp->hu.hgp);
3915    ihref = __mk_handle(hotyp, (void *) hrp->hu.hgp, hp->hin_itp, NULL);
3916    break;
3917   case vpiNetBitDriver:
3918    np = hrp->hu.hnpp->elnpp.enp;
3919    ihref = __mk_handle(vpiNetBit, (void *) np, hp->hin_itp, hrp->hin_tskp);
3920    hp2 = (struct h_t *) ihref;
3921    /* DBG remove --- */
3922    if (hrp->hu.hnpp->npaux == NULL) __vpi_terr(__FILE__, __LINE__);
3923    /* --- */
3924    /* need internal h:0 bit form here */
3925    hp2->hrec->hi = hrp->hu.hnpp->npaux->nbi1;
3926    break;
3927   case vpiAttribute:
3928    return(__get_digattr_parent(hp));
3929 
3930   default: no_1to1h_err(vpiParent, hp); return(NULL);
3931  }
3932  return(ihref);
3933 }
3934 
3935 /*
3936  * get expr. handle variable itree and task location
3937  *
3938  * for selects passed the left variable expr. node
3939  */
exprobj_to_itreeloc(struct itree_t ** itpp,struct task_t ** tskpp,struct expr_t * idndp,struct itree_t * itp,struct task_t * tskp)3940 static void exprobj_to_itreeloc(struct itree_t **itpp, struct task_t **tskpp,
3941  struct expr_t *idndp, struct itree_t *itp, struct task_t *tskp)
3942 {
3943  struct mod_t *mdp;
3944  struct gref_t *grp;
3945 
3946  mdp = itp->itip->imsym->el.emdp;
3947  if (idndp->optyp == ID)
3948   {
3949    if (idndp->locqualnam)
3950     *tskpp = __find_qualnam_task(idndp->ru.qnchp, mdp, tskp);
3951    else *tskpp = tskp;
3952    *itpp = itp;
3953   }
3954  else if (idndp->optyp == GLBREF)
3955   {
3956    grp = idndp->ru.grp;
3957    __push_itstk(itp);
3958    __xmrpush_refgrp_to_targ(grp);
3959    itp = __inst_ptr;
3960    __pop_itstk();
3961    __pop_itstk();
3962    tskp = grp->targtskp;
3963   }
3964  else __vpi_terr(__FILE__, __LINE__);
3965 }
3966 
3967 /*
3968  * get all 1-to-1 relationships that are on a vpi_ rhs or lhs
3969  */
get_obj_side(struct h_t * rhp,int32 type)3970 static vpiHandle get_obj_side(struct h_t *rhp, int32 type)
3971 {
3972  register struct hrec_t *rhrp;
3973  int32 hotyp;
3974  vpiHandle ihref;
3975  struct expr_t *xp;
3976  struct st_t *stp;
3977  struct task_t *tskp;
3978  struct dfparam_t *dfpp;
3979  struct itree_t *itp;
3980  struct net_t *np;
3981 
3982  tskp = NULL;
3983  rhrp = rhp->hrec;
3984  switch (rhrp->htyp) {
3985   case vpiContAssign:
3986    if (rhrp->htyp2 == vpiGate)
3987     {
3988      if (type == vpiRhs) xp = rhrp->hu.hgp->gpins[1];
3989      else xp = rhrp->hu.hgp->gpins[0];
3990     }
3991    else
3992     {
3993      if (type == vpiRhs) xp = rhrp->hu.hcap->rhsx;
3994      else xp = rhrp->hu.hcap->lhsx;
3995     }
3996    break;
3997   case vpiAssignment:
3998    stp = rhrp->hu.hstp;
3999    /* rhs delay or event control has RHS del/evnt control as stmt */
4000    if (stp->stmttyp == S_DELCTRL) stp = stp->st.sdc->actionst;
4001    if (type == vpiRhs) xp = stp->st.spra.rhsx;
4002    else xp = stp->st.spra.lhsx;
4003    tskp = rhrp->hin_tskp;
4004    break;
4005   /* qc assign or force - do not need to distinguish here */
4006   case vpiAssignStmt: case vpiForce:
4007    stp = rhrp->hu.hstp;
4008    if (type == vpiRhs) xp = stp->st.sqca->qcrhsx;
4009    else xp = stp->st.sqca->qclhsx;
4010    tskp = rhrp->hin_tskp;
4011    break;
4012  case vpiDeassign: case vpiRelease:
4013    stp = rhrp->hu.hstp;
4014    if (type == vpiLhs) xp = stp->st.sqcdea.qcdalhs;
4015    else { no_1to1h_err(type, rhp); return(NULL); }
4016    tskp = rhrp->hin_tskp;
4017    break;
4018   case vpiDefParam:
4019    dfpp = rhrp->hu.hdfp;
4020    /* already converted to rooted in exactly one itree */
4021    if (type == vpiLhs)
4022     {
4023      /* left hand side is parameter (i.e. net) and can be task param */
4024      np = dfpp->targsyp->el.enp;
4025      /* SJM - 05/26/05 - must search for bottom - splitting changes */
4026      itp = __find_dfpbot_itp(dfpp);
4027      ihref = __mk_handle(vpiParameter, (void *) np, itp, dfpp->dfptskp);
4028      return(ihref);
4029     }
4030    /* SJM 01/27/04 - this no longer needs to be const for dependent dfps */
4031    xp = dfpp->dfpxrhs;
4032    /* rhs is constant that must appear in source at module level */
4033    break;
4034   case vpiParamAssign:
4035    /* because know assign (decl.) address - rally same as vpi param object */
4036    np = rhrp->hu.hnp;
4037    if (type == vpiLhs)
4038     {
4039      hotyp = vpiParameter;
4040      /* i.e. same thing except type different */
4041      ihref = __mk_handle(hotyp, (void *) np, rhp->hin_itp, rhrp->hin_tskp);
4042      return(ihref);
4043     }
4044    /* rhs is param expr. - to get value need to get value of lhs */
4045    /* DBG remove -- */
4046    if (np->nrngrep != NX_CT) __vpi_terr(__FILE__, __LINE__);
4047    /* --- */
4048    if (np->nu.ct->parm_srep == SR_PXPR) xp = np->nu.ct->n_dels_u.d1x;
4049    else if (np->nu.ct->parm_srep == SR_PISXPR)
4050     {
4051      /* d4x used but in fact allocated size is number of insts */
4052      xp = np->nu.ct->n_dels_u.d4x[rhp->hin_itp->itinum];
4053     }
4054    else { __vpi_terr(__FILE__, __LINE__); return(NULL); }
4055    ihref = __mk_exprclass_handle(xp, rhp->hin_itp, rhrp->hin_tskp);
4056    return(ihref);
4057   default: no_1to1h_err(type, rhp); return(NULL);
4058  }
4059  ihref = __mk_exprclass_handle(xp, rhp->hin_itp, tskp);
4060  return(ihref);
4061 }
4062 
4063 /*
4064  * build a scope (mod or task) parent handle (up one symbol table)
4065  *
4066  * for named blocks and name fork-join, hu field is statement for
4067  * real tasks (task and function definitions hu field is tskp
4068  * but in head case other handle information right
4069  */
bld_scope_par(struct h_t * hp,struct task_t * tskp)4070 static vpiHandle bld_scope_par(struct h_t *hp, struct task_t *tskp)
4071 {
4072  word32 parhtyp;
4073  vpiHandle ihref;
4074  struct task_t *up_tskp;
4075  struct symtab_t *sytp, *sytp2;
4076 
4077  sytp = tskp->tsksymtab;
4078  if ((sytp2 = sytp->sytpar) == NULL) __vpi_terr(__FILE__, __LINE__);
4079  if (sytp2->sypofsyt->sytyp == SYM_M)
4080   {
4081    ihref = __mk_handle(vpiModule, (void *) sytp->sytpar->sypofsyt->el.emdp,
4082     hp->hin_itp, tskp);
4083    return(ihref);
4084   }
4085  if (sytp2->sytpar == NULL || sytp2->sytpar->sypofsyt->sytyp == SYM_M)
4086   up_tskp = NULL;
4087  else up_tskp = sytp2->sytpar->sypofsyt->el.etskp;
4088 
4089  parhtyp = __to_vpi_tasktyp(tskp->tsktyp);
4090  ihref = __mk_handle(parhtyp, (void *) sytp2->sypofsyt->el.etskp,
4091   hp->hin_itp, up_tskp);
4092  return(ihref);
4093 }
4094 
4095 /*
4096  * convert from v.h task type to handle constant
4097  */
__to_vpi_tasktyp(word32 tsktyp)4098 extern word32 __to_vpi_tasktyp(word32 tsktyp)
4099 {
4100  switch (tsktyp) {
4101   case TASK: return(vpiTask);
4102   case FUNCTION: return(vpiFunction);
4103   case Begin: return(vpiNamedBegin);
4104   case FORK: return(vpiNamedFork);
4105   default: __vpi_terr(__FILE__, __LINE__);
4106  }
4107  return(0);
4108 }
4109 
4110 /*
4111  * build an net/reg bit handle from a port for the low connection (mod port)
4112  *
4113  * this build a reg/net bit (or reg/net if scalar) handle from expression
4114  * use with vpiPort to get entire expression (then can convert if needed)
4115  * this is easy case because no xmrs or qualified names
4116  *
4117  * hp is port bit handle that must be lvalue
4118  *
4119  * here unc. impossible because connections determine width
4120  */
getbit_lowconn(struct h_t * hp)4121 static vpiHandle getbit_lowconn(struct h_t *hp)
4122 {
4123  int32 ndx, new_ndx;
4124  word32 hotyp;
4125  vpiHandle href;
4126  struct mod_t *mdp;
4127  struct mod_pin_t *mpp;
4128  struct expr_t *xp, *idndp;
4129  struct net_t *np;
4130  struct h_t *hp2;
4131  struct hrec_t *hrp;
4132 
4133  href = NULL;
4134  mdp = hp->hin_itp->itip->imsym->el.emdp;
4135  hrp = hp->hrec;
4136  mpp = &(mdp->mpins[hrp->hu.hpi]);
4137  /* this is index of port bit - always h:0 */
4138  ndx = hrp->hi;
4139  xp = mpp->mpref;
4140 catcmp_again:
4141  /* know this is lvalue expr - using cver expressions */
4142  switch (xp->optyp) {
4143   case ID:
4144    idndp = xp;
4145 make_handle:
4146    np = idndp->lu.sy->el.enp;
4147    /* notice need special correction for Net (wire) vector as bit */
4148    if (np->ntyp < NONWIRE_ST)
4149     {
4150      hotyp = (np->n_isavec) ? vpiNetBit : vpiNet;
4151     }
4152    /* reg cnnections never bits */
4153    else
4154     {
4155      if (np->n_isavec) hotyp = __to_vpinetbithtyp(np->ntyp);
4156      else hotyp = __ntyp_to_vpivarhtyp(np);
4157     }
4158    href = __mk_handle(hotyp, (void *) np, hp->hin_itp, NULL);
4159    hp2 = (struct h_t *) href;
4160    /* for scalar will be -1 - ndx is internal h:0 that for ID is same bit */
4161    hp2->hrec->hi = ndx;
4162    if (hotyp == vpiNetBit || hotyp == vpiRegBit || hotyp == vpiVarSelect)
4163     hp2->hrec->bith_ndx = TRUE;
4164    break;
4165   case LSB:
4166    /* if constant, convert to bith_ndx form */
4167    if (__expr_is_vpiconst(xp->ru.x))
4168     {
4169      idndp = xp->lu.x;
4170      /* evaluate index since constant know will be non x but maybe IS form */
4171      __push_itstk(hp->hin_itp);
4172      ndx = __comp_ndx(idndp->lu.sy->el.enp, xp->ru.x);
4173      __pop_itstk();
4174      /* DBG remove --- */
4175      if (ndx == -1) __vpi_terr(__FILE__, __LINE__);
4176      /* --- */
4177      goto make_handle;
4178     }
4179    else
4180     {
4181      /* variable case - this is variable bit or array select */
4182      href = __mk_exprclass_handle(xp, hp->hin_itp, hrp->hin_tskp);
4183     }
4184    break;
4185   case PARTSEL:
4186    idndp = xp->lu.x;
4187    /* because always constant - normalized */
4188    ndx = __contab[xp->ru.x->ru.x->ru.xvi] + ndx;
4189    goto make_handle;
4190   case LCB:
4191    xp = find_catxp_frombit(xp, ndx, &new_ndx);
4192    ndx = new_ndx;
4193    goto catcmp_again;
4194   default: __vpi_terr(__FILE__, __LINE__);
4195  }
4196  return(href);
4197 }
4198 
4199 /*
4200  * build an expr handle from a port for the low connection (mod port)
4201  */
getexpr_lowconn(struct h_t * hp)4202 static vpiHandle getexpr_lowconn(struct h_t *hp)
4203 {
4204  vpiHandle ihref;
4205  struct mod_t *mdp;
4206  struct mod_pin_t *mpp;
4207 
4208  if (hp->hrec->htyp != vpiPort)
4209   { no1_1to1h_err(vpiLowConn, vpiPort, hp); return(NULL); }
4210  mdp = hp->hin_itp->itip->imsym->el.emdp;
4211  mpp = &(mdp->mpins[hp->hrec->hu.hpi]);
4212  ihref = __mk_exprclass_handle(mpp->mpref, hp->hin_itp, NULL);
4213  return(ihref);
4214 }
4215 
4216 /*
4217  * build an variable or var bit handle form vpi Port bit
4218  *
4219  * know handle is vpiPortBit
4220  * for port bit, get iconn expr then take apart to component, then to
4221  * bit in expression, but if vpiOperation returns nil since no handle
4222  *
4223  * this is hard case because converting up iconn expr to net/bit handle
4224  * and can be xmr or in module qualified name
4225  *
4226  * same as acc_, only variables, bit and port selects or concatenates thereof
4227  * are legal (not bits of constants, for example)
4228  *
4229  * hp is vpi port bit
4230  */
getbit_highconn(struct h_t * hp)4231 static vpiHandle getbit_highconn(struct h_t *hp)
4232 {
4233  int32 ndx, new_ndx;
4234  word32 xtyp, otyp, hotyp;
4235  vpiHandle href;
4236  struct inst_t *ip;
4237  struct itree_t *up_itp, *itp;
4238  struct net_t *np;
4239  struct expr_t *xp, *idndp;
4240  struct task_t *tskp;
4241  struct h_t *hp2;
4242  struct hrec_t *hrp;
4243  struct gref_t *grp;
4244  struct mod_t *mdp;
4245 
4246  href = NULL;
4247  hrp = hp->hrec;
4248  ip = hp->hin_itp->itip;
4249  mdp = ip->imsym->el.emdp;
4250  /* no highconn for ports of top level module */
4251  if ((up_itp = hp->hin_itp->up_it) == NULL) return(NULL);
4252  ndx = hrp->hi;
4253  xp = ip->ipins[hrp->hu.hpi];
4254 new_expr:
4255  /* possibly unconnected */
4256  if (ndx >= xp->szu.xclen)
4257  /* possibly unconnected */
4258  /* SJM 08/24/99 - silently return nil if unc. - only way to tell if */
4259  /* unc - no warning because otherwise no way to tell unc. */
4260  if (ndx >= xp->szu.xclen) return(NULL);
4261 
4262  xtyp = (word32) __exprtype_get(xp);
4263  if (xtyp == vpiOperation)
4264   {
4265    /* know concatenates reduced to one level always */
4266    if ((otyp = (word32) __expr_optype_get(xp)) == vpiConcatOp)
4267     {
4268      xp = find_catxp_frombit(xp, ndx, &new_ndx);
4269      ndx = new_ndx;
4270      goto new_expr;
4271     }
4272    __to_vpiopnam(__wrks2, (int32) otyp);
4273 no_iconnbit:
4274    /* xtyp is an object */
4275    __vpi_err(2014, vpiWarning,
4276     "vpi_handle: no vpiHighConn of vpiPortBit for %s expression type %s",
4277     __to_vpionam(__wrks1, xtyp), __wrks2);
4278    return(NULL);
4279   }
4280  if (xtyp == vpiConstant || xtyp == vpiSysFuncCall || xtyp == vpiFuncCall)
4281   {
4282    strcpy(__wrks2, "*none*");
4283    goto no_iconnbit;
4284   }
4285 
4286  switch (xp->optyp) {
4287   case ID:
4288    /* if vector, will be bit handle if scalar will be net/reg handle only */
4289    idndp = xp;
4290 make_var:
4291    if (idndp->locqualnam)
4292     tskp = __find_qualnam_task(idndp->ru.qnchp, mdp, hrp->hin_tskp);
4293    else tskp = NULL;
4294    itp = up_itp;
4295 bld_handle:
4296    /* this always builds either variable or variable bit */
4297    np = idndp->lu.sy->el.enp;
4298    /* notice need special correction for Net (wire) vector as bit */
4299    if (np->ntyp < NONWIRE_ST)
4300     {
4301      hotyp = (np->n_isavec) ? vpiNetBit : vpiNet;
4302     }
4303    else
4304     {
4305      if (np->n_isavec) hotyp = __to_vpinetbithtyp(np->ntyp);
4306      else hotyp = __ntyp_to_vpivarhtyp(np);
4307     }
4308    href = __mk_handle(hotyp, (void *) np, itp, tskp);
4309    hp2 = (struct h_t *) href;
4310    /* for scalar will be 0 */
4311    hp2->hrec->hi = ndx;
4312    hp2->hrec->bith_ndx = TRUE;
4313    break;
4314   case GLBREF:
4315    idndp = xp;
4316 make_grp_var:
4317    grp = idndp->ru.grp;
4318    __push_itstk(up_itp);
4319    __xmrpush_refgrp_to_targ(grp);
4320    itp = __inst_ptr;
4321    __pop_itstk();
4322    __pop_itstk();
4323    tskp = grp->targtskp;
4324    goto bld_handle;
4325   case LSB:
4326    /* here handle becomes index of bit select */
4327    idndp = xp->lu.x;
4328    /* no way in vpi_ routines to represent array bit (undivisable) */
4329    if (idndp->lu.sy->el.enp->n_isarr)
4330     {
4331      __vpi_err(2026, vpiWarning,
4332       "vpi_handle: no vpiHighConn of vpiPortBit for array %s",
4333       idndp->lu.sy->el.enp->nsym->synam);
4334      return(NULL);
4335     }
4336    /* also if var select, no highconn because no fixed bit */
4337    if (xp->ru.x->optyp != NUMBER && xp->ru.x->optyp != ISNUMBER)
4338     { strcpy(__wrks2, "variable vpiVarSelect"); goto no_iconnbit; }
4339 
4340    /* rule for bit conn, is that it must be constant bit select */
4341    /* or error before here - but routine must return vpiNetbit */
4342    /* need to evaluate for constant since may be IS form */
4343    if (__expr_is_vpiconst(xp->ru.x))
4344     {
4345      __push_itstk(up_itp);
4346      /* evaluate index since constant know will be non x */
4347      ndx = __comp_ndx(idndp->lu.sy->el.enp, xp->ru.x);
4348      if (ndx == -1)
4349       { strcpy(__wrks2, "x/z vpiVarSelect"); goto no_iconnbit; }
4350      __pop_itstk();
4351      if (idndp->optyp == GLBREF) goto make_grp_var;
4352      goto make_var;
4353     }
4354    else
4355     {
4356      /* variable case - this is variable bit or array select */
4357      /* up xmr to task if present will be in XMR ref - se just need up */
4358      href = __mk_exprclass_handle(xp, up_itp, NULL);
4359     }
4360    break;
4361   case PARTSEL:
4362    /* this becomes vpiNetBit or vpiRegBit with index correct for part sel */
4363    idndp = xp->lu.x;
4364    ndx = __contab[xp->ru.x->ru.x->ru.xvi] + ndx;
4365    if (idndp->optyp == GLBREF) goto make_grp_var;
4366    goto make_var;
4367   default: __vpi_terr(__FILE__, __LINE__);
4368  }
4369  return(href);
4370 }
4371 
4372 /*
4373  * given a concatenate and a bit index, return the concat component expr
4374  *
4375  * this works on Cver expr_t not handles
4376  * know in range
4377  */
find_catxp_frombit(struct expr_t * catxp,int32 bi,int32 * newbi)4378 static struct expr_t *find_catxp_frombit(struct expr_t *catxp, int32 bi,
4379  int32 *newbi)
4380 {
4381  register struct expr_t *xp;
4382  register int32 catbi;
4383 
4384  xp = catxp->ru.x;
4385  for (catbi = catxp->szu.xclen; xp != NULL; xp = xp->ru.x)
4386   {
4387    catbi -= xp->lu.x->szu.xclen;
4388    if (bi >= catbi) { *newbi = bi - catbi; return(xp->lu.x); }
4389   }
4390  __vpi_terr(__FILE__, __LINE__);
4391  return(NULL);
4392 }
4393 
4394 /*
4395  * find loal qualified name task
4396  *
4397  * because this can only be local qualified (named blocks) name - instance
4398  * selects impossible
4399  *
4400  * never need to store except for vpi since have right symbol
4401  * but for vpi need to know task in
4402  */
__find_qualnam_task(char * qualnam,struct mod_t * mdp,struct task_t * reftskp)4403 extern struct task_t *__find_qualnam_task(char *qualnam, struct mod_t *mdp,
4404  struct task_t *reftskp)
4405 {
4406  register struct expr_t *gcmp_ndp;
4407  struct sy_t *syp;
4408  struct expr_t *qn_ndp;
4409  struct symtab_t *sytp;
4410 
4411  /* know will have at least 2 components including ending variable */
4412  /* this can never fail because processing already check qualified name */
4413  if ((qn_ndp = __glbnam_to_expr(qualnam)) == NULL)
4414   __vpi_terr(__FILE__, __LINE__);
4415  /* handle already in some task - work upward */
4416  gcmp_ndp = qn_ndp->ru.x;
4417  /* DBG remove --- */
4418  if (gcmp_ndp->lu.x->optyp != XMRID) __vpi_terr(__FILE__, __LINE__);
4419  /* --- */
4420  if (reftskp != NULL)
4421   {
4422    for (sytp = reftskp->tsksymtab;;)
4423     {
4424      if ((syp = __get_sym(gcmp_ndp->lu.x->ru.qnchp, sytp)) != NULL)
4425       {
4426        if (!__is_scope_sym(syp)) __vpi_terr(__FILE__, __LINE__);
4427        if (syp->sytyp == SYM_M) sytp = syp->el.emdp->msymtab;
4428        else sytp = syp->el.etskp->tsksymtab;
4429        gcmp_ndp = gcmp_ndp->ru.x;
4430        break;
4431       }
4432      if ((sytp = sytp->sytpar) == NULL) __vpi_terr(__FILE__, __LINE__);
4433     }
4434   }
4435  else { sytp = mdp->msymtab;; }
4436  /* have start of path symbol table - need to stop 1 from tail end */
4437  /* DBG remove --- */
4438  if (gcmp_ndp == NULL) __vpi_terr(__FILE__, __LINE__);
4439  /* -- */
4440  /* know at least one more component by here */
4441  for (;;)
4442   {
4443    /* DBG remove ---*/
4444    if (gcmp_ndp->lu.x->optyp != XMRID) __vpi_terr(__FILE__, __LINE__);
4445    /* ---*/
4446    if ((syp = __get_sym(gcmp_ndp->lu.x->ru.qnchp, sytp)) == NULL
4447     || !__is_scope_sym(syp)) __vpi_terr(__FILE__, __LINE__);
4448    sytp = syp->el.etskp->tsksymtab;
4449    if ((gcmp_ndp = gcmp_ndp->ru.x) == NULL) break;
4450    /* if next is tail wire, also done */
4451    if (gcmp_ndp->ru.x == NULL) break;
4452   }
4453  __free_xtree(qn_ndp);
4454  return(sytp->sypofsyt->el.etskp);
4455 }
4456 
4457 /*
4458  * build an expr handle from a port for the high connection (iconn)
4459  */
getexpr_highconn(struct h_t * hp)4460 static vpiHandle getexpr_highconn(struct h_t *hp)
4461 {
4462  vpiHandle ihref;
4463  struct inst_t *ip;
4464  struct itree_t *up_itp;
4465  struct hrec_t *hrp;
4466 
4467  hrp = hp->hrec;
4468  if (hrp->htyp != vpiPort && hrp->htyp != vpiPortBit)
4469   { no1_1to1h_err(vpiHighConn, vpiPort, hp); return(NULL); }
4470  ip = hp->hin_itp->itip;
4471  if ((up_itp = hp->hin_itp->up_it) == NULL) return(NULL);
4472  /* for port, high conn is iconn expression */
4473  ihref = __mk_exprclass_handle(ip->ipins[hrp->hu.hpi], up_itp, NULL);
4474  return(ihref);
4475 }
4476 
4477 /*
4478  * no 1-to-1 connection error with 1 expected handle
4479  */
no1_1to1h_err(word32 typ1to1,word32 exptyp,struct h_t * hp)4480 static void no1_1to1h_err(word32 typ1to1, word32 exptyp, struct h_t *hp)
4481 {
4482  char s1[RECLEN];
4483 
4484  __vpi_err(1887, vpiError,
4485   "vpi_handle: handle %s (expected %s) does not have a 1-to-1 connection for type %s",
4486   __to_vpionam(__wrks2, hp->hrec->htyp), __to_vpionam(s1, exptyp),
4487   __to_vpionam(__wrks1, typ1to1));
4488 }
4489 
4490 /*
4491  * no 1-to-1 connection error with no one expected handle type
4492  */
no_1to1h_err(int32 typ1to1,struct h_t * hp)4493 static void no_1to1h_err(int32 typ1to1, struct h_t *hp)
4494 {
4495  __vpi_err(1887, vpiError,
4496   "vpi_handle: handle %s does not have a 1-to-1 connection for type %s",
4497   __to_vpionam(__wrks2, hp->hrec->htyp), __to_vpionam(__wrks1,
4498   (word32) typ1to1));
4499 }
4500 
4501 /*
4502  * build an tchk term handle from a tchk - 2 different no iterator
4503  */
get_tchk_term(word32 termtyp,struct h_t * hp)4504 static vpiHandle get_tchk_term(word32 termtyp, struct h_t *hp)
4505 {
4506  vpiHandle ihref;
4507  struct tchk_t *tcp;
4508  struct h_t *hp2;
4509  struct hrec_t *hrp;
4510 
4511  hrp = hp->hrec;
4512  if (hrp->htyp != vpiTchk)
4513   { no1_1to1h_err(termtyp, vpiTchk, hp); return(NULL); }
4514  tcp = hrp->hu.htcp;
4515  if (termtyp == vpiTchkNotifier)
4516   {
4517    if (tcp->ntfy_np == NULL) return(NULL);
4518    ihref = __mk_handle(vpiReg, (void *) tcp->ntfy_np, hp->hin_itp, NULL);
4519   }
4520  else
4521   {
4522    ihref = __mk_handle(vpiTchkTerm, (void *) tcp, hp->hin_itp, NULL);
4523    hp2 = (struct h_t *) ihref;
4524    /* term type determines since each terminal of tchk different */
4525    hp2->hrec->htyp2 = (word32) termtyp;
4526   }
4527  return(ihref);
4528 }
4529 
4530 /*
4531  * get condition 1-to-1 handle from hp
4532  */
get_cond(struct h_t * hp)4533 static vpiHandle get_cond(struct h_t *hp)
4534 {
4535  register struct hrec_t *hrp;
4536  vpiHandle ihref;
4537  struct tchk_t *tcp;
4538  struct spcpth_t *pthp;
4539  struct delctrl_t *dctp;
4540  struct expr_t *xp;
4541 
4542  hrp = hp->hrec;
4543  switch (hrp->htyp) {
4544   case vpiTchkTerm:
4545    tcp = hrp->hu.htcp;
4546    if (hrp->htyp2 == vpiTchkRefTerm)
4547     {
4548      if (tcp->startcondx == NULL) return(NULL);
4549      ihref = __mk_exprclass_handle(tcp->startcondx, hp->hin_itp, NULL);
4550     }
4551    else if (hrp->htyp2 == vpiTchkDataTerm)
4552     {
4553      if (tcp->chkcondx == NULL) return(NULL);
4554      ihref = __mk_exprclass_handle(tcp->chkcondx, hp->hin_itp, NULL);
4555     }
4556    else { __vpi_terr(__FILE__, __LINE__); return(NULL); }
4557    break;
4558   case vpiModPath:
4559    pthp = hrp->hu.hpthp;
4560    if (pthp->pthcondx == NULL) return(NULL);
4561    ihref = __mk_exprclass_handle(pthp->pthcondx, hp->hin_itp, NULL);
4562    break;
4563   /* conditon is if conditon */
4564   case vpiIf: case vpiIfElse:
4565    ihref = __mk_exprclass_handle(hrp->hu.hstp->st.sif.condx,
4566     hp->hin_itp, hrp->hin_tskp);
4567    break;
4568   case vpiCase:
4569    ihref = __mk_exprclass_handle(hrp->hu.hstp->st.scs.csx,
4570     hp->hin_itp, hrp->hin_tskp);
4571    break;
4572   /* notice to get condition for rhs proca event control first */
4573   /* use stmt handle of event control then handle of event control stmt */
4574   /* this is expression that is special - but checking already done */
4575   case vpiEventControl:
4576    dctp = hrp->hu.hstp->st.sdc;
4577    /* DBG remove --- */
4578    if (dctp->dc_delrep != DT_1X) __vpi_terr(__FILE__, __LINE__);
4579    /* --- */
4580    xp = dctp->dc_du.d1x;
4581    ihref = __mk_exprclass_handle(xp, hp->hin_itp, hrp->hin_tskp);
4582    break;
4583   case vpiWhile:
4584    ihref = __mk_exprclass_handle(hrp->hu.hstp->st.swh.lpx, hp->hin_itp,
4585     hrp->hin_tskp);
4586    break;
4587   case vpiRepeat:
4588    ihref = __mk_exprclass_handle(hrp->hu.hstp->st.srpt.repx, hp->hin_itp,
4589     hrp->hin_tskp);
4590    break;
4591   case vpiWait:
4592    ihref = __mk_exprclass_handle(hrp->hu.hstp->st.swait.lpx, hp->hin_itp,
4593     hrp->hin_tskp);
4594    break;
4595   case vpiFor:
4596    ihref = __mk_exprclass_handle(hrp->hu.hstp->st.sfor->fortermx,
4597     hp->hin_itp, hrp->hin_tskp);
4598    break;
4599   default: no_1to1h_err(vpiCondition, hp); return(NULL);
4600  }
4601  return(ihref);
4602 }
4603 
4604 /*
4605  * get expr. (1-to-1) from handle
4606  *
4607  * this traverses to expr_t then converts to <expr object class> handle
4608  * except for disable statement vpi_handle
4609  */
bld_1to1_exprclass_handle(struct h_t * hp)4610 static vpiHandle bld_1to1_exprclass_handle(struct h_t *hp)
4611 {
4612  register int32 pi;
4613  register struct hrec_t *hrp;
4614  word32 hotyp;
4615  struct spcpth_t *pthp;
4616  struct tchk_t *tcp;
4617  struct gate_t *gp;
4618  struct net_t *np;
4619  struct pathel_t *pep;
4620  struct expr_t *xp;
4621  struct delctrl_t *dctp;
4622  vpiHandle ihref;
4623 
4624  ihref = NULL;
4625  hrp = hp->hrec;
4626  switch (hrp->htyp) {
4627   case vpiDisable:
4628    /* even though disable is a statement scope here is expr. disabling scope */
4629    /* odd case because vpiScope 1-to-1 method gets containing scope */
4630    /* not scope to disable - therefore using vpiExpr 1-to-1 method */
4631    return(get_disable_scope(hp));
4632   case vpiTchkTerm:
4633    tcp = hrp->hu.htcp;
4634    /* get tchk term of notifier is expr. already not tchk terminal obj */
4635    if (hrp->htyp2 == vpiTchkRefTerm)
4636     {
4637      if (tcp->startxp == NULL) return(NULL);
4638      ihref = __mk_exprclass_handle(tcp->startxp, hp->hin_itp, NULL);
4639      break;
4640     }
4641    if (hrp->htyp2 == vpiTchkDataTerm)
4642     {
4643      if (tcp->chkxp == NULL) return(NULL);
4644      ihref = __mk_exprclass_handle(tcp->chkxp, hp->hin_itp, NULL);
4645      break;
4646     }
4647    __vpi_terr(__FILE__, __LINE__);
4648    return(NULL);
4649   case vpiPathTerm:
4650    pthp = hrp->hu.hpthp;
4651    if (hrp->htyp2 == vpiModPathIn || hrp->htyp2 == vpiModPathOut)
4652     {
4653      if (hrp->htyp2 == vpiModPathIn) pep = &(pthp->peins[hrp->hi]);
4654      else pep = &(pthp->peouts[hrp->hi]);
4655      ihref = mk_pthterm_exprclass_handle(pep->penp, pep->pthi1, pep->pthi2,
4656       hp->hin_itp);
4657      break;
4658     }
4659    if (hrp->htyp2 != vpiModDataPathIn) __vpi_terr(__FILE__, __LINE__);
4660    if ((xp = pthp->datasrcx) == NULL) return(NULL);
4661 
4662    /* notice indices start at 0 */
4663    if (xp->optyp != FCCOM)
4664     {
4665      if (hrp->hi > 0) __vpi_terr(__FILE__, __LINE__);
4666      ihref = __mk_exprclass_handle(xp, hp->hin_itp, NULL);
4667      break;
4668     }
4669    /* FCCOM list */
4670    for (pi = 0; xp != NULL; xp = xp->ru.x, pi++)
4671     {
4672      if (xp->optyp != FCCOM || pi > hrp->hi) __vpi_terr(__FILE__, __LINE__);
4673      if (pi == hrp->hi)
4674       {
4675        ihref = __mk_exprclass_handle(xp->lu.x, hp->hin_itp, NULL);
4676        break;
4677       }
4678     }
4679    break;
4680   case vpiPrimTerm:
4681    gp = hrp->hu.hgp;
4682    ihref = __mk_exprclass_handle(gp->gpins[hrp->hi], hp->hin_itp, NULL);
4683    break;
4684   case vpiParameter: case vpiSpecParam:
4685    /* parameters stored as nets but this must return expr. not final val. */
4686    np = hrp->hu.hnp;
4687    if (np->nu.ct->parm_srep == SR_PXPR) xp = np->nu.ct->n_dels_u.d1x;
4688    else if (np->nu.ct->parm_srep == SR_PISXPR)
4689     {
4690      /* d4x used but in fact allocated size is number of insts */
4691      xp = np->nu.ct->n_dels_u.d4x[hp->hin_itp->itinum];
4692     }
4693    else { __vpi_terr(__FILE__, __LINE__); return(NULL); }
4694    ihref = __mk_exprclass_handle(xp, hp->hin_itp, hrp->hin_tskp);
4695    break;
4696   case vpiIODecl:
4697    if (hrp->htyp2 == vpiUdpDefn) return(NULL);
4698 
4699    /* since can not be bit of - just get wire or reg type */
4700    hotyp = __ntyp_to_vpivarhtyp(hrp->hu.hnp);
4701    /* since can only be var. do not need expr. class object */
4702    /* can be io decl in task so need task from io decl handle */
4703    ihref = __mk_handle(hotyp, (void *) hrp->hu.hnp, hp->hin_itp,
4704     hrp->hin_tskp);
4705    return(ihref);
4706   case vpiRepeatControl:
4707    /* 10/28/00 SJM - added vpi Expr 1-to-1 access method from repeat ev ctrl */
4708    /* returns the repeat count expr */
4709    dctp = hrp->hu.hstp->st.sdc;
4710    xp = hrp->hu.hstp->st.sdc->repcntx;
4711    ihref = __mk_exprclass_handle(xp, hp->hin_itp, hrp->hin_tskp);
4712    return(ihref);
4713   default: no_1to1h_err(vpiExpr, hp); return(NULL);
4714  }
4715  return(ihref);
4716 }
4717 
4718 /*
4719  * build a path terminal expression class handle
4720  *
4721  * only need to allocate expr_t and waste storage for part select
4722  * never a task for specify section object
4723  *
4724  * builds vpiNetBit index form for bit select
4725  */
mk_pthterm_exprclass_handle(struct net_t * np,int32 i1,int32 i2,struct itree_t * in_itp)4726 static vpiHandle mk_pthterm_exprclass_handle(struct net_t *np,
4727  int32 i1, int32 i2, struct itree_t *in_itp)
4728 {
4729  word32 hotyp;
4730  vpiHandle href;
4731  struct expr_t *xp, *xpcol, *xpid, *xp1, *xp2;
4732  struct h_t *hp;
4733 
4734  if (i1 == -1 && i2 == -1)
4735   {
4736    hotyp = __ntyp_to_vpivarhtyp(np);
4737    href = __mk_handle(hotyp, (void *) np, in_itp, NULL);
4738    return(href);
4739   }
4740 
4741  /* bit select */
4742  if (i1 == i2)
4743   {
4744    /* this can be bit index form because can not be xmr */
4745    href = __mk_handle(vpiNetBit, (void *) np, in_itp, NULL);
4746    hp = (struct h_t *) href;
4747    hp->hrec->bith_ndx = TRUE;
4748    hp->hrec->hi = i1;
4749    return(href);
4750   }
4751  /* part select - allocate new expr and build expr vpiPartSelect handle */
4752  xpid = __sim_alloc_newxnd();
4753  xpid->optyp = ID;
4754  xpid->lu.sy = np->nsym;
4755  xp1 = __bld_rng_numxpr((word32) i1, 0L, WBITS);
4756  xp2 = __bld_rng_numxpr((word32) i2, 0L, WBITS);
4757  /* root of part select */
4758  xp = __sim_alloc_newxnd();
4759  xp->optyp = PARTSEL;
4760  xp->lu.x = xpid;
4761  xpcol = __sim_alloc_newxnd();
4762  xpcol->optyp = COLON;
4763  xp->ru.x = xpcol;
4764  xpcol->lu.x = xp1;
4765  xpcol->ru.x = xp2;
4766  href = __mk_exprclass_handle(xp, in_itp, NULL);
4767  hp = (struct h_t *) href;
4768  hp->hrec->free_xpr = TRUE;
4769  return(href);
4770 }
4771 
4772 /*
4773  * get object containing scope handle
4774  *
4775  * LOOKATME - allowing use of vpiScope for things in module even though
4776  * LRM says handle should be vpiModule
4777  */
get_obj_scope(struct h_t * hp)4778 static vpiHandle get_obj_scope(struct h_t *hp)
4779 {
4780  int32 ttyp;
4781  vpiHandle ihref;
4782  struct mod_t *mdp;
4783  struct symtab_t *sytp;
4784  struct task_t *up_tskp;
4785  struct hrec_t *hrp;
4786 
4787  ihref = NULL;
4788  mdp = hp->hin_itp->itip->imsym->el.emdp;
4789  hrp = hp->hrec;
4790  switch (hrp->htyp) {
4791   /* also process class containing scope (vpiModule) accessible */
4792   /* using vpiModule 1-to-1 method */
4793   case vpiAlways: case vpiInitial:
4794   /* simple cases - parent is module in */
4795   case vpiPort: case vpiContAssign:
4796   case vpiModPath: case vpiTchk: case vpiSpecParam:
4797   case vpiGate: case vpiUdp: case vpiSwitch:
4798    ihref = __mk_handle(vpiModule, (void *) mdp, hp->hin_itp, NULL);
4799    break;
4800    /* this is object in handle - all variables and stmts */
4801   case vpiNet: case vpiReg: case vpiNamedEvent: case vpiMemory:
4802   case vpiIntegerVar: case vpiTimeVar: case vpiRealVar:
4803   case vpiModule:
4804    /* all statements - except those with symbol tables */
4805   case vpiAssignStmt: case vpiAssignment: case vpiBegin:
4806   case vpiCase: case vpiDeassign: case vpiDelayControl:
4807   case vpiEventStmt: case vpiFor: case vpiForce: case vpiForever:
4808   case vpiFork: case vpiFuncCall: case vpiIf: case vpiIfElse:
4809   case vpiNullStmt: case vpiRelease: case vpiRepeat: case vpiSysFuncCall:
4810   case vpiSysTaskCall: case vpiTaskCall: case vpiWait: case vpiWhile:
4811   /* for expression forms - in module is where expr. appears not variable */
4812   case vpiMemoryWord: case vpiNetBit: case vpiRegBit: case vpiVarSelect:
4813   case vpiNetDriver: case vpiNetBitDriver:
4814   /* 10/28/00 - added missing things with scope */
4815   case vpiEventControl: case vpiRepeatControl:
4816    /* if index is expression form, context is where expr appears */
4817    /* to get variable def. loc. need to get parent object */
4818    /* this can either be in module or task */
4819    if (hp->hrec->hin_tskp == NULL)
4820     ihref = __mk_handle(vpiModule, (void *) mdp, hp->hin_itp, NULL);
4821    else
4822     {
4823      sytp = hrp->hin_tskp->tsksymtab;
4824      if (sytp->sytpar == NULL || sytp->sytpar->sypofsyt->sytyp == SYM_M)
4825       up_tskp = NULL;
4826      else up_tskp = sytp->sytpar->sypofsyt->el.etskp;
4827 
4828      ttyp = __to_vpi_tasktyp(hrp->hin_tskp->tsktyp);
4829      ihref = __mk_handle(ttyp, (void *) hrp->hin_tskp, hp->hin_itp, up_tskp);
4830     }
4831    break;
4832   /* these are definitions in */
4833   case vpiTask: case vpiFunction:
4834    return(bld_scope_par(hp, hrp->hu.htskp));
4835   /* LOOKATME - think can reduce to one case for all 4 */
4836   case vpiNamedBegin: case vpiNamedFork:
4837    /* for named block handle is stmt not task so know loc. - can go from */
4838    /* task to enclosing stmt */
4839    return(bld_scope_par(hp, hrp->hu.htskp));
4840   default: no_1to1h_err(vpiScope, hp); return(NULL);
4841  }
4842  return(ihref);
4843 }
4844 
4845 /*
4846  * get scope (task/func/named fork or join) of disable
4847  *
4848  * LOOKATME - since statement vpiScope should be containing
4849  * but LRM says this is exception where it is disable scope
4850  */
get_disable_scope(struct h_t * rhp)4851 static vpiHandle get_disable_scope(struct h_t *rhp)
4852 {
4853  int32 ttyp;
4854  struct st_t *stp;
4855  struct expr_t *xp;
4856  struct itree_t *itp;
4857  struct task_t *tskp;
4858  struct symtab_t *sytp;
4859  struct task_t *up_tskp;
4860 
4861  stp = rhp->hrec->hu.hstp;
4862  xp = stp->st.sdsable.dsablx;
4863 
4864  if (xp->optyp == GLBREF)
4865   {
4866    __push_itstk(rhp->hin_itp);
4867    __xmrpush_refgrp_to_targ(xp->ru.grp);
4868    itp = __inst_ptr;
4869    __pop_itstk();
4870    __pop_itstk();
4871   }
4872  else if (xp->optyp == ID) itp = rhp->hin_itp;
4873  else { __vpi_terr(__FILE__, __LINE__); return(NULL); }
4874 
4875  /* this is scope symbol */
4876  tskp = xp->lu.sy->el.etskp;
4877  sytp = tskp->tsksymtab;
4878  if (sytp->sytpar == NULL || sytp->sytpar->sypofsyt->sytyp == SYM_M)
4879   up_tskp = NULL;
4880  else up_tskp = sytp->sytpar->sypofsyt->el.etskp;
4881 
4882  /* return task-function-named block handle */
4883  ttyp = __to_vpi_tasktyp(tskp->tsktyp);
4884  return(__mk_handle(ttyp, (void *) tskp, itp, up_tskp));
4885 }
4886 
4887 /*
4888  * get a contained in stmt handle
4889  */
get_contained_stmt(struct h_t * rhp)4890 static vpiHandle get_contained_stmt(struct h_t *rhp)
4891 {
4892  register struct hrec_t *rhrp;
4893  word32 sttyp;
4894  vpiHandle ihref;
4895  struct st_t *ifstp, *thenstp, *dcstp, *stp;
4896  struct csitem_t *csip;
4897  struct delctrl_t *dctp;
4898  struct task_t *tskp;
4899 
4900  rhrp = rhp->hrec;
4901  switch (rhrp->htyp) {
4902    case vpiInitial: case vpiAlways:
4903     stp = rhrp->hu.hialstp->iastp;
4904     if (stp->st_unbhead) sttyp = vpiBegin;
4905     else sttyp = __to_vpi_stmttyp(&stp);
4906     ihref = __mk_stmt_handle(sttyp, stp, rhp->hin_itp, NULL);
4907     break;
4908    case vpiTask: case vpiFunction:
4909     /* SJM 07/30/01 - misisng access from function or task object to stmt */
4910     tskp = rhrp->hu.htskp;
4911     stp = tskp->tskst;
4912     if (stp->st_unbhead) sttyp = vpiBegin;
4913     else sttyp = __to_vpi_stmttyp(&stp);
4914     ihref = __mk_stmt_handle(sttyp, tskp->tskst, rhp->hin_itp, tskp);
4915     break;
4916    case vpiIf: case vpiIfElse:
4917     ifstp = rhrp->hu.hstp;
4918     thenstp = ifstp->st.sif.thenst;
4919     if (thenstp->st_unbhead) sttyp = vpiBegin;
4920     else sttyp = __to_vpi_stmttyp(&thenstp);
4921     ihref = __mk_stmt_handle(sttyp, thenstp, rhp->hin_itp, rhrp->hin_tskp);
4922     break;
4923    case vpiCaseItem:
4924     /* for multiple expressions, know points to first (stp non nil) */
4925     csip = rhrp->hu.hcsip;
4926     stp = csip->csist;
4927     if (stp->st_unbhead) sttyp = vpiBegin;
4928     else sttyp = __to_vpi_stmttyp(&stp);
4929     ihref = __mk_stmt_handle(sttyp, stp, rhp->hin_itp, rhrp->hin_tskp);
4930     break;
4931    case vpiDelayControl:
4932     dctp = rhrp->hu.hstp->st.sdc;
4933     /* really assignment with rhs delay control so LRM requires nil */
4934     if (dctp->dctyp == DC_RHSDELAY || dctp->actionst == NULL) return(NULL);
4935     dcstp = dctp->actionst;
4936     if (dcstp->st_unbhead) sttyp = vpiBegin;
4937     else sttyp = __to_vpi_stmttyp(&dcstp);
4938     ihref = __mk_stmt_handle(sttyp, dcstp, rhp->hin_itp, rhrp->hin_tskp);
4939     break;
4940    case vpiEventControl:
4941     dctp = rhrp->hu.hstp->st.sdc;
4942     /* really assignment with rhs delay control so LRM requires nil */
4943     if (dctp->dctyp == DC_RHSEVENT || dctp->actionst == NULL) return(NULL);
4944     dcstp = dctp->actionst;
4945     /* since after prep for some loops need to return one stmt after setup */
4946     if (dcstp->st_unbhead) sttyp = vpiBegin;
4947     else sttyp = __to_vpi_stmttyp(&dcstp);
4948     ihref = __mk_stmt_handle(sttyp, dcstp, rhp->hin_itp, rhrp->hin_tskp);
4949     break;
4950    /* forever condition is nil and never accessed */
4951    case vpiWhile: case vpiForever:
4952     stp = rhrp->hu.hstp->st.swh.lpst;
4953 loop_sthandle:
4954     if (stp->st_unbhead) sttyp = vpiBegin;
4955     else sttyp = __to_vpi_stmttyp(&stp);
4956     ihref = __mk_stmt_handle(sttyp, stp, rhp->hin_itp, rhrp->hin_tskp);
4957     break;
4958    case vpiRepeat: stp = rhrp->hu.hstp->st.srpt.repst; goto loop_sthandle;
4959    case vpiWait: stp = rhrp->hu.hstp->st.swait.lpst; goto loop_sthandle;
4960    case vpiFor: stp = rhrp->hu.hstp->st.sfor->forbody; goto loop_sthandle;
4961 
4962   default: no_1to1h_err(vpiStmt, rhp); return(NULL);
4963  }
4964  return(ihref);
4965 }
4966 
4967 /*
4968  * get a vpi delay control statement from an vpi assignment statement
4969  * this is tricky because for rhs dctrls DELCTRL is stmt not actionst assign
4970  */
get_dctrl_stmt(struct h_t * rhp,int32 dctype)4971 static vpiHandle get_dctrl_stmt(struct h_t *rhp, int32 dctype)
4972 {
4973  struct st_t *stp;
4974  struct delctrl_t *dctp;
4975  struct hrec_t *rhrp;
4976 
4977  rhrp = rhp->hrec;
4978  if (rhrp->htyp != vpiAssignment)
4979   { no_1to1h_err(dctype, rhp); return(NULL); }
4980  stp = rhrp->hu.hstp;
4981  if (stp->stmttyp != S_DELCTRL) return(NULL);
4982  /* same code for both delay control and event control */
4983  dctp = stp->st.sdc;
4984  if (dctp->dctyp != DC_RHSEVENT && dctp->dctyp != DC_RHSDELAY)
4985   __vpi_terr(__FILE__, __LINE__);
4986  if (dctype == vpiDelayControl && dctp->dctyp == DC_RHSDELAY)
4987   {
4988    return(__mk_handle(vpiDelayControl, (void *) stp, rhp->hin_itp,
4989     rhrp->hin_tskp));
4990   }
4991  if (dctype == vpiEventControl && dctp->dctyp == DC_RHSEVENT
4992   && dctp->repcntx == NULL)
4993   {
4994    return(__mk_handle(vpiEventControl, (void *) stp, rhp->hin_itp,
4995     rhrp->hin_tskp));
4996   }
4997  /* 10/26/00 SJM - also access repeat control */
4998  if (dctype == vpiRepeatControl && dctp->dctyp == DC_RHSEVENT
4999   && dctp->repcntx != NULL)
5000   {
5001    return(__mk_handle(vpiRepeatControl, (void *) stp, rhp->hin_itp,
5002     rhrp->hin_tskp));
5003   }
5004  return(NULL);
5005 }
5006 
5007 /*
5008  * get a udp define handle from either a udp primitive
5009  * or object inside udp Def
5010  */
get_udpdef_from_inobj(struct h_t * rhp)5011 static vpiHandle get_udpdef_from_inobj(struct h_t *rhp)
5012 {
5013  vpiHandle href;
5014  struct udp_t *udpp;
5015  struct hrec_t *rhrp;
5016 
5017  rhrp = rhp->hrec;
5018  switch (rhrp->htyp) {
5019   case vpiIODecl:
5020    /* DBG remove --- */
5021    if (rhrp->htyp2 != vpiUdpDefn) __vpi_terr(__FILE__, __LINE__);
5022    /* --- */
5023    udpp = (struct udp_t *) rhp->hin_itp;
5024    break;
5025   case vpiTableEntry: case vpiInitial:
5026    udpp = (struct udp_t *) rhp->hin_itp;
5027    break;
5028   case vpiUdp:
5029    udpp = rhrp->hu.hgp->gmsym->el.eudpp;
5030    break;
5031   default: no_1to1h_err(vpiUdpDefn, rhp); return(NULL);
5032  }
5033  href = __mk_handle(vpiUdpDefn, (void *) udpp, NULL, NULL);
5034  return(href);
5035 }
5036 
5037 /*
5038  * get initial value - handle here is just udp with initial type
5039  */
get_contained_udp_init(struct h_t * rhp)5040 static vpiHandle get_contained_udp_init(struct h_t *rhp)
5041 {
5042  vpiHandle href;
5043  struct udp_t *udpp;
5044  struct h_t *hp;
5045 
5046  udpp = rhp->hrec->hu.hudpp;
5047  if (udpp->ival == NO_VAL)
5048   {
5049    __vpi_err(2111, vpiNotice,
5050     "vpi_handle of vpiInitial for vpiUdpDefn handle failed - no initial value");
5051    return(NULL);
5052   }
5053  href = __mk_handle(vpiInitial, (void *) udpp, NULL, NULL);
5054  hp = (struct h_t *) href;
5055  hp->hrec->htyp2 = vpiUdpDefn;
5056  return(href);
5057 }
5058 
5059 /*
5060  * one to one access method for getting up instance pound param override
5061  * expression
5062  */
get_up_poundparam_expr(struct h_t * rhp)5063 static vpiHandle get_up_poundparam_expr(struct h_t *rhp)
5064 {
5065  int32 pi;
5066  vpiHandle href;
5067  struct inst_t *ip;
5068  struct mod_t *mdp;
5069  struct itree_t *up_itp;
5070  struct expr_t *xp;
5071 
5072  if (rhp->hrec->htyp != vpiParameter)
5073   {
5074    no_1to1h_err(vpiPoundParam, rhp);
5075    return(NULL);
5076   }
5077 
5078  ip = rhp->hin_itp->itip;
5079  if (ip->ipxprtab == NULL) return(NULL);
5080 
5081  mdp = rhp->hin_itp->itip->imsym->el.emdp;
5082  pi = rhp->hrec->hu.hnp - mdp->mprms;
5083  if ((xp = ip->ipxprtab[pi]) == NULL) return(NULL);
5084 
5085  up_itp = rhp->hin_itp->up_it;
5086  /* DBG remove --- */
5087  if (up_itp == NULL) __vpi_terr(__FILE__, __LINE__);
5088  /* --- */
5089 
5090  href = __mk_exprclass_handle(xp, up_itp, NULL);
5091  return(href);
5092 }
5093 
5094 /*
5095  * ROUTINES TO BUILD ITERATOR HANDLES (FIRST GROUP)
5096  */
5097 
5098 /*
5099  * allocate and return an iterator handle
5100  *
5101  * build the entire table of iterators that are returned in order and
5102  * freed by scan
5103  *
5104  * ALGORITHM: use type as first level index that filters which of multiple
5105  *            objects to build into scan table.  Then for given type
5106  *            use handle (object) as object from which to traverse and build
5107  *            type list (i.e. type is target of ->->[type])
5108  *
5109  * a nil reference handle means use all top level modules
5110  * FIXME - what if reference handle is nil for top level modules?
5111  */
vpi_iterate(PLI_INT32 itype,vpiHandle referenceHandle)5112 extern vpiHandle vpi_iterate(PLI_INT32 itype, vpiHandle referenceHandle)
5113 {
5114  register struct h_t *hp;
5115 
5116  __last_eip = NULL;
5117  if (__run_state == SS_COMP)
5118   { __still_comp_err("vpi_iterate"); return(NULL); }
5119  if (!__validate_accessm("vpi_iterate", itype, "1-to-many iterator"))
5120   return(NULL);
5121  hp = (struct h_t *) referenceHandle;
5122  /* some iterators have nil (top level?) and value cases so must check */
5123  /* for validitly of nil in the routine */
5124  if (hp != NULL && !__validate_handle("vpi_iterate", hp)) return(NULL);
5125 
5126  /* separate processing for each 1 to many connection type */
5127  /* given 1 - many conn. type handle determines object to traverse from */
5128  /* type of thing that can appear as multiple list in some handle */
5129  switch (itype) {
5130   case vpiModule:
5131    return(bld_itree_iterator(hp));
5132   case vpiOneOfEachMod:
5133    return(bld_type_iterator(hp));
5134   case vpiUdpDefn:
5135    return(bld_udpdef_iterator(hp));
5136   /* this is 1-to-many acess method selector - inside mod or task */
5137   case vpiInternalScope:
5138    return(bld_scope_iterator(hp));
5139   case vpiPort:
5140    /* for ports in module and net/reg and bit port hiconn connections */
5141    return(__bld_port_iterator(hp));
5142   case vpiPortInst: return(__bld_neticonn_iter(hp));
5143   case vpiNet: case vpiReg: case vpiNamedEvent: case vpiMemory:
5144   case vpiVariables:
5145    /* vpiVariables for all of integer, time, real - not separated */
5146    return(bld_net_iterator(hp, (word32) itype));
5147   case vpiProcess:
5148    /* list of initial - always statements in module - only access from mod */
5149    return(bld_initalw_iterator(hp));
5150   case vpiContAssign:
5151    return(bld_conta_iterator(hp));
5152   /* here primitive is right since it is the access method */
5153   case vpiPrimitive:
5154    /* gate, switch, or udp, handle set to actual type */
5155    return(bld_gate_iterator(hp));
5156   case vpiModPath: return(bld_modpth_iterator(hp));
5157   case vpiTchk: return(bld_tchk_iterator(hp));
5158   case vpiParameter: return(bld_param_iterator(hp, itype));
5159   case vpiSpecParam: return(bld_specparam_iterator(hp));
5160   case vpiDefParam: return(bld_defparam_stmt_iterator(hp));
5161   /* AIV 09/27/06 - this includes localparams too */
5162   case vpiParamAssign: return(__bld_paramassign_stmt_iter(hp));
5163   case vpiIODecl: return(__bld_iodecl_stmt_iter(hp));
5164   case vpiTableEntry: return(__bld_udpline_iter(hp));
5165   case vpiPrimTerm: return(__bld_primterm_iterator(hp));
5166 
5167   case vpiLocalLoad: return(__bld_loc_lds_iterator(hp, itype));
5168   case vpiLoad: return(__bld_lds_iterator(hp, itype));
5169   case vpiLocalDriver: return(__bld_loc_drvs_iterator(hp, itype));
5170   case vpiDriver: return(__bld_drvs_iterator(hp, itype));
5171 
5172   case vpiMemoryWord: return(__bld_arrwrd_iterator(hp));
5173   case vpiBit: return(__bld_bitof_iterator(hp));
5174 
5175   case vpiUserSystf: return(__bld_systf_iterator(hp));
5176   case vpiArgument: return(__bld_tfargexpr_iterator(hp));
5177   case vpiModPathIn: case vpiModPathOut: case vpiModDataPathIn:
5178    return(__bld_pthterm_iterator(hp, (word32) itype));
5179   case vpiStmt: return(__bld_stmt_iterator(hp));
5180   case vpiTchkTerm: return(__bld_netin_tchkterms(hp));
5181   case vpiPathTerm: return(__bld_netin_pthterms(hp));
5182   case vpiCaseItem: return(__bld_caseitems_iter(hp));
5183   case vpiExpr: return(__bld_casi_exprs_iter(hp));
5184   /* notice only concatenate accessible */
5185   case vpiOperand: return(__bld_operands_iter(hp));
5186   /* error if hp non nil - routine checks */
5187   case vpiCallback: return(__bld_allcbs_iter(hp));
5188   case vpiDelay: return(__bld_delay_expr_iter(hp));
5189   case vpiAttribute: return(__bld_dig_attr_iter(hp));
5190   default:
5191    if (hp == NULL) strcpy(__wrks2, "**NULL**");
5192    else __to_vpionam(__wrks2, hp->hrec->htyp);
5193    __vpi_err(1838, vpiError,
5194     "method %s not a 1-to-many (iterator) object for %s handle",
5195     __to_vpionam(__wrks1, (word32) itype), __wrks2);
5196  }
5197  return(NULL);
5198 }
5199 
5200 /*
5201  * build the top level module (itree inst.) iterator
5202  */
bld_itree_iterator(struct h_t * hp)5203 static vpiHandle bld_itree_iterator(struct h_t *hp)
5204 {
5205  register int32 ii;
5206  register struct h_t *hp2;
5207  register struct hrec_t *hrp2;
5208  vpiHandle ihref;
5209  struct itree_t *itp;
5210  struct pviter_t *iterp;
5211 
5212  /* case 1: handle non nil, get instances (vpi Module) inside */
5213  if (hp != NULL) return(bld_inst_iterator(hp));
5214 
5215  /* case 2: nil so get top level modules */
5216  /* LOOKATME - how can there be no top level modules */
5217  if (__numtopm <= 0) return(NULL);
5218 
5219  /* get all of it roots */
5220  iterp = __alloc_iter(__numtopm, &ihref);
5221  for (ii = 0; ii < __numtopm; ii++)
5222   {
5223    hp2 = &(iterp->scanhtab[ii]);
5224    hrp2 = hp2->hrec;
5225    hrp2->htyp = vpiModule;
5226    itp = __it_roots[ii];
5227    hrp2->hu.hmdp = itp->itip->imsym->el.emdp;
5228    hp2->hin_itp = itp;
5229   }
5230  return(ihref);
5231 }
5232 
5233 /*
5234  * build one instance of each type iterator
5235  *
5236  * error if handle non nil
5237  * LOOKATME - for now returning connect modules (even if only used in
5238  * connect or maybe by accident connect from others) - is this right?
5239  */
bld_type_iterator(struct h_t * hp)5240 static vpiHandle bld_type_iterator(struct h_t *hp)
5241 {
5242  register int32 ti;
5243  register struct mod_t *mdp;
5244  register struct h_t *hp2;
5245  register struct hrec_t *hrp2;
5246  int32 numtypes;
5247  vpiHandle ihref;
5248  struct itree_t *itp;
5249  struct pviter_t *iterp;
5250 
5251  /* case 1: handle non nil, get instances (vpi Module) inside */
5252  if (hp != NULL)
5253   {
5254    __vpi_err(1860, vpiError,
5255     "vpiOneOfEachMod 1-to-many iterator 2nd argument must NULL - %s object passed",
5256     __to_vpionam(__wrks1, hp->hrec->htyp));
5257    return(NULL);
5258   }
5259  /* count number of types */
5260  for (mdp = __modhdr, numtypes = 0; mdp != NULL; mdp = mdp->mnxt)
5261   {
5262    numtypes++;
5263   }
5264 
5265  if (numtypes <= 0) return(NULL);
5266  /* get all of it roots */
5267  iterp = __alloc_iter(numtypes, &ihref);
5268  for (ti = 0, mdp = __modhdr; ti < numtypes; ti++, mdp = mdp->mnxt)
5269   {
5270    hp2 = &(iterp->scanhtab[ti]);
5271    hrp2 = hp2->hrec;
5272    hrp2->htyp = vpiModule;
5273    itp = mdp->moditps[0];
5274    hrp2->hu.hmdp = mdp;
5275    hp2->hin_itp = itp;
5276   }
5277  return(ihref);
5278 }
5279 
5280 /*
5281  * allocate an iterator
5282  */
__alloc_iter(int32 nels,vpiHandle * ihrefp)5283 extern struct pviter_t *__alloc_iter(int32 nels, vpiHandle *ihrefp)
5284 {
5285  register int32 iti;
5286  register struct h_t *hp;
5287  register struct hrec_t *hrarr;
5288  struct pviter_t *iterp;
5289 
5290  iterp = (struct pviter_t *) __my_malloc(sizeof(struct pviter_t));
5291  iterp->numhs = nels;
5292  iterp->nxthi = 0;
5293  *ihrefp = __mk_handle(vpiIterator, (void *) iterp,  NULL, NULL);
5294  /* this is table of handle guts not ptrs to handles */
5295  iterp->scanhtab = (struct h_t *) __my_malloc(nels*sizeof(struct h_t));
5296  hrarr = (struct hrec_t *) __my_malloc(nels*sizeof(struct hrec_t));
5297  iterp->ihrectab = hrarr;
5298 
5299  /* do the non type specific initialization */
5300  for (iti = 0; iti < nels; iti++)
5301   {
5302    hp = &(iterp->scanhtab[iti]);
5303    hp->hin_itp = NULL;
5304    hp->hrec = &(hrarr[iti]);
5305    __init_hrec(hp->hrec);
5306    hp->hrec->in_iter = TRUE;
5307   }
5308  return(iterp);
5309 }
5310 
5311 /*
5312  * build the iterator scan table for module instances in handle instance
5313  * 1-to-many Vpi Module to Vpi Module inside
5314  * only called if at least one contained instance (hp not nil)
5315  */
bld_inst_iterator(struct h_t * hp)5316 static vpiHandle bld_inst_iterator(struct h_t *hp)
5317 {
5318  register int32 ii;
5319  register struct hrec_t *hrp2;
5320  register struct h_t *hp2;
5321  struct mod_t *mdp;
5322  struct itree_t *itp, *itp2;
5323  vpiHandle ihref;
5324  struct pviter_t *iterp;
5325 
5326  if (hp->hrec->htyp != vpiModule)
5327   { mustbe_inmoditer_err(vpiModule, hp); return(NULL); }
5328  itp = hp->hin_itp;
5329  mdp = itp->itip->imsym->el.emdp;
5330  if (mdp->minum <= 0) return(NULL);
5331  iterp = __alloc_iter(mdp->minum, &ihref);
5332  for (ii = 0; ii < mdp->minum; ii++)
5333   {
5334    hp2 = &(iterp->scanhtab[ii]);
5335    hrp2 = hp2->hrec;
5336    hrp2->htyp = vpiModule;
5337    itp2 = &(itp->in_its[ii]);
5338    hrp2->hu.hmdp = itp2->itip->imsym->el.emdp;
5339    hp2->hin_itp = itp2;
5340   }
5341  return(ihref);
5342 }
5343 
5344 /*
5345  * error for iterator that only exists in module but handle is other
5346  */
mustbe_inmoditer_err(word32 ityp,struct h_t * hp)5347 static void mustbe_inmoditer_err(word32 ityp, struct h_t *hp)
5348 {
5349  __vpi_err(1841, vpiError,
5350   "%s 1-to-many iterator from object %s illegal - only allowed for vpiModule",
5351   __to_vpionam(__wrks1, ityp), __to_vpionam(__wrks2, hp->hrec->htyp));
5352 }
5353 
5354 /*
5355  * build the iterator for all defined in design iterators
5356  *
5357  * in Cver all non instantiated udps removed
5358  */
bld_udpdef_iterator(struct h_t * rhp)5359 static vpiHandle bld_udpdef_iterator(struct h_t *rhp)
5360 {
5361  register int32 ui;
5362  register struct udp_t *udpp;
5363  register struct hrec_t *hrp;
5364  register struct h_t *hp;
5365  int32 nudps;
5366  vpiHandle ihref;
5367  struct pviter_t *iterp;
5368 
5369  if (rhp != NULL)
5370   {
5371    __vpi_err(1837, vpiError,
5372     "vpi_iterate of vpiUdpDefn handle must be NULL (%s illegal) - udp definitions design wide",
5373     __to_vpionam(__wrks1, rhp->hrec->htyp));
5374    return(NULL);
5375   }
5376  for (udpp = __udphead, nudps = 0; udpp != NULL; udpp = udpp->udpnxt) nudps++;
5377  if (nudps <= 0) return(NULL);
5378 
5379  /* build the design wide iterator of all udps */
5380  iterp = __alloc_iter(nudps, &ihref);
5381  for (ui = 0, udpp = __udphead; ui < nudps; udpp = udpp->udpnxt, ui++)
5382   {
5383    hp = &(iterp->scanhtab[ui]);
5384    hrp = hp->hrec;
5385    hrp->htyp = vpiUdpDefn;
5386    hrp->hu.hudpp = udpp;
5387    /* there is no hin itp for design wide udps */
5388   }
5389  return(ihref);
5390 }
5391 
5392 /*
5393  * given an object handle - build iterator of all scopes in object
5394  *
5395  * nil handle is top level scopes
5396  * scope is class but actual handler is one of module, taskfunc, named begin,
5397  * and named fork
5398  */
bld_scope_iterator(register struct h_t * hp)5399 static vpiHandle bld_scope_iterator(register struct h_t *hp)
5400 {
5401  struct mod_t *mdp;
5402  struct symtab_t *sytp;
5403 
5404  if (hp == NULL) return(__nil_iter_err(vpiInternalScope));
5405  switch (hp->hrec->htyp) {
5406   case vpiModule:
5407    /* scope list in module */
5408    mdp = hp->hin_itp->itip->imsym->el.emdp;
5409    return(bld_symtabs_iterator(mdp->msymtab->sytofs, hp->hin_itp));
5410   case vpiTask: case vpiFunction:
5411    /* real task, hu is task ptr */
5412    sytp = hp->hrec->hu.htskp->tsksymtab;
5413    return(bld_symtabs_iterator(sytp->sytofs, hp->hin_itp));
5414   case vpiNamedBegin: case vpiNamedFork:
5415    /* pseudo task, hu is stmt */
5416    sytp = hp->hrec->hu.htskp->tsksymtab;
5417    return(bld_symtabs_iterator(sytp->sytofs, hp->hin_itp));
5418   default:
5419    __vpi_err(1843, vpiError,
5420     "unable to construct iterator of contained scopes for %s object",
5421    __to_vpionam(__wrks1, hp->hrec->htyp));
5422  }
5423  return(NULL);
5424 }
5425 
5426 /*
5427  * emit error for iterator type that can not be nil
5428  *
5429  * needed because many design lists accessed from nil handle
5430  */
__nil_iter_err(word32 otyp)5431 extern vpiHandle __nil_iter_err(word32 otyp)
5432 {
5433  __vpi_err(1854, vpiError, "vpi_iterate type %s passed illegal NULL handle",
5434   __to_vpionam(__wrks1, otyp));
5435  return(NULL);
5436 }
5437 
5438 /*
5439  * build an iterator for a list of scopes - works from symbol table
5440  * know passed left most symbol table for multiple disjoint32 scopes
5441  */
bld_symtabs_iterator(struct symtab_t * sytp,struct itree_t * itp)5442 static vpiHandle bld_symtabs_iterator(struct symtab_t *sytp,
5443  struct itree_t *itp)
5444 {
5445  register int32 ii;
5446  register struct symtab_t *sytp2;
5447  register struct h_t *hp;
5448  register struct hrec_t *hrp;
5449  int32 numtabs;
5450  vpiHandle ihref;
5451  struct pviter_t *iterp;
5452  struct task_t *up_tskp;
5453 
5454  if (sytp == NULL) return(NULL);
5455  for (numtabs = 0, sytp2 = sytp; sytp2 != NULL; sytp2 = sytp2->sytsib)
5456   numtabs++;
5457  if (numtabs <= 0) return(NULL);
5458  iterp = __alloc_iter(numtabs, &ihref);
5459  for (sytp2 = sytp, ii = 0; ii < numtabs; sytp2 = sytp2->sytsib, ii++)
5460   {
5461    hp = &(iterp->scanhtab[ii]);
5462    hrp = hp->hrec;
5463    fill_scopehandle(hrp, sytp2);
5464    hp->hin_itp = itp;
5465    if (sytp->sytpar == NULL || sytp->sytpar->sypofsyt->sytyp == SYM_M)
5466     up_tskp = NULL;
5467    else up_tskp = sytp->sytpar->sypofsyt->el.etskp;
5468    /* this task handle is maybe in one up task (for nested named blocks) */
5469    hrp->hin_tskp = up_tskp;
5470   }
5471  return(ihref);
5472 }
5473 
5474 /*
5475  * get vpi_ object associated with a symbol table - always a task_t
5476  *
5477  * only one of tskp or mdp set
5478  */
fill_scopehandle(struct hrec_t * hrp,struct symtab_t * sytp)5479 static void fill_scopehandle(struct hrec_t *hrp, struct symtab_t *sytp)
5480 {
5481  struct task_t *tskp;
5482  struct sy_t *syp;
5483 
5484  syp = sytp->sypofsyt;
5485  switch ((byte) syp->sytyp) {
5486   case SYM_M:
5487    hrp->htyp = vpiModule;
5488    hrp->hu.hmdp = syp->el.emdp;
5489    return;
5490   case SYM_TSK: hrp->htyp = vpiTask; break;
5491   case SYM_F: hrp->htyp = vpiFunction; break;
5492   case SYM_LB:
5493    tskp = syp->el.etskp;
5494    if (tskp->tsktyp == Begin) hrp->htyp = vpiNamedBegin;
5495    else if (tskp->tsktyp == FORK) hrp->htyp = vpiNamedFork;
5496    else __vpi_terr(__FILE__, __LINE__);
5497    /* this is tricky part of named block as task code because scope is tskp */
5498    /* but need the enclosing statement (can only be one) */
5499    hrp->hu.htskp = syp->el.etskp->st_namblkin->st.snbtsk;
5500    return;
5501   default:;
5502  }
5503  hrp->hu.htskp = syp->el.etskp;
5504 }
5505 
5506 /*
5507  * given an object containing nets handle - build iterator of all nets
5508  *
5509  * otype is vpi_ type of net
5510  */
bld_net_iterator(struct h_t * hp,word32 otype)5511 static vpiHandle bld_net_iterator(struct h_t *hp, word32 otype)
5512 {
5513  register struct hrec_t *hrp;
5514  struct mod_t *mdp;
5515  struct task_t *tskp;
5516  struct itree_t *itp;
5517  struct net_t *np;
5518  word32 ntyp;
5519 
5520  if (hp == NULL) return(__nil_iter_err(otype));
5521  itp = hp->hin_itp;
5522  hrp = hp->hrec;
5523  switch (hrp->htyp) {
5524   case vpiModule:
5525    mdp = itp->itip->imsym->el.emdp;
5526    if (mdp->mnets == NULL) return(NULL);
5527    np = &(mdp->mnets[0]);
5528    return(bld_listofnets_iter(np, mdp->mnnum, itp, otype, NULL));
5529   case vpiTask: case vpiFunction: case vpiNamedBegin: case vpiNamedFork:
5530    /* variables class does not map to ntyp */
5531    if (otype != vpiVariables)
5532     {
5533      /* cannot be wire type for task */
5534      ntyp = __from_vpi_vartyp(otype);
5535      if (ntyp < NONWIRE_ST)
5536       {
5537        __vpi_err(1845, vpiError,
5538         "unable to construct %s iterator for non module scope %s",
5539         __to_vpionam(__wrks1, otype), __to_vpionam(__wrks2, hrp->htyp));
5540        return(NULL);
5541       }
5542     }
5543    tskp = hrp->hu.htskp;
5544    if (tskp->tsk_regs == NULL) return(NULL);
5545 
5546    np = &(tskp->tsk_regs[0]);
5547    return(bld_listofnets_iter(np, tskp->trnum, itp, otype, tskp));
5548   default:
5549    __vpi_err(1847, vpiError,
5550     "unable to construct iterator of contained %s for %s object",
5551     __to_vpionam(__wrks1, otype), __to_vpionam(__wrks2, hrp->htyp));
5552  }
5553  return(NULL);
5554 }
5555 
5556 /*
5557  * build an iterator for a list of module nets of type type
5558  *
5559  * know at least one net or will not be called but maybe none of type
5560  */
bld_listofnets_iter(struct net_t * np,int32 onnum,struct itree_t * itp,word32 otype,struct task_t * tskp)5561 static vpiHandle bld_listofnets_iter(struct net_t *np, int32 onnum,
5562  struct itree_t *itp, word32 otype, struct task_t *tskp)
5563 {
5564  register int32 ni, ni2;
5565  register struct net_t *np2;
5566  register struct h_t *hp;
5567  register struct hrec_t *hrp;
5568  int32 nnum;
5569  word32 ntyp, vpityp;
5570  vpiHandle ihref;
5571  struct pviter_t *iterp;
5572 
5573  if ((nnum = cnt_typnetnum(np, onnum, otype)) <= 0) return(NULL);
5574  iterp = __alloc_iter(nnum, &ihref);
5575  if (otype == vpiMemory)
5576   {
5577    for (ni = ni2 = 0, np2 = np; ni < onnum; ni++, np2++)
5578     {
5579      if (np2->n_isarr)
5580       {
5581        /* notice number of nets (ni) maybe larger than iterator size ni2 */
5582        hp = &(iterp->scanhtab[ni2++]);
5583        hrp = hp->hrec;
5584        hrp->htyp = vpiMemory;
5585        hrp->hu.hnp = np2;
5586        hp->hin_itp = itp;
5587        hrp->hin_tskp = tskp;
5588       }
5589     }
5590    return(ihref);
5591   }
5592  /* passed vpiNet for all wire types (all non regs) */
5593  if (otype == vpiNet)
5594   {
5595    for (ni = ni2 = 0, np2 = np; ni < onnum; ni++, np2++)
5596     {
5597      if (np2->ntyp < NONWIRE_ST)
5598       {
5599        hp = &(iterp->scanhtab[ni2++]);
5600        hrp = hp->hrec;
5601        hrp->htyp = vpiNet;
5602        hrp->hu.hnp = np2;
5603        hp->hin_itp = itp;
5604        hrp->hin_tskp = tskp;
5605       }
5606     }
5607    return(ihref);
5608   }
5609  /* passed vpiVariables for all reg types (all non wires) */
5610  if (otype == vpiVariables)
5611   {
5612    for (ni = ni2 = 0, np2 = np; ni < onnum; ni++, np2++)
5613     {
5614      if (np2->n_isarr) continue;
5615 
5616      /* 1 to many iterator selector must be variable but handle is separate */
5617      /* variable type */
5618      if (np2->ntyp == N_TIME) vpityp = vpiTimeVar;
5619      else if (np2->ntyp == N_INT) vpityp = vpiIntegerVar;
5620      else if (np2->ntyp == N_REAL) vpityp = vpiRealVar;
5621      else continue;
5622 
5623      hp = &(iterp->scanhtab[ni2++]);
5624      hrp = hp->hrec;
5625      hrp->htyp = vpityp;
5626      hrp->hu.hnp = np2;
5627      hp->hin_itp = itp;
5628      hrp->hin_tskp = tskp;
5629     }
5630    return(ihref);
5631   }
5632  /* this is used to convert for comparing know type already checked */
5633  ntyp = __from_vpi_vartyp(otype);
5634  for (ni2 = ni = 0, np2 = np; ni < onnum; ni++, np2++)
5635   {
5636    if (np2->n_isarr) continue;
5637    if (np2->ntyp == ntyp)
5638     {
5639      hp = &(iterp->scanhtab[ni2++]);
5640      hrp = hp->hrec;
5641      hrp->htyp = otype;
5642      hrp->hu.hnp = np2;
5643      hp->hin_itp = itp;
5644      hrp->hin_tskp = tskp;
5645     }
5646   }
5647  return(ihref);
5648 }
5649 
5650 /*
5651  * count number of nets of object type
5652  * needed because all wires stored in one list in Cver
5653  * possibilities are array, net (and wire) or match N_ internal type
5654  */
cnt_typnetnum(register struct net_t * np,int32 onnum,word32 typ)5655 static int32 cnt_typnetnum(register struct net_t *np, int32 onnum,
5656  word32 typ)
5657 {
5658  register int32 ni;
5659  word32 nnum;
5660  word32 ntyp;
5661 
5662  nnum = 0;
5663  if (typ == vpiMemory)
5664   {
5665    for (ni = 0; ni < onnum; ni++, np++) { if (np->n_isarr) nnum++; }
5666    return(nnum);
5667   }
5668  /* passed vpiNet for all wire types (all non regs) */
5669  if (typ == vpiNet)
5670   {
5671    for (ni = 0; ni < onnum; ni++, np++)
5672     { if (np->ntyp < NONWIRE_ST) nnum++; }
5673    return(nnum);
5674   }
5675  /* vpiVarible for real, integer, and time that are accessed together */
5676  if (typ == vpiVariables)
5677   {
5678    for (ni = 0; ni < onnum; ni++, np++)
5679     {
5680      if (np->n_isarr) continue;
5681      if (np->ntyp == N_REAL || np->ntyp == N_INT || np->ntyp == N_TIME)
5682       nnum++;
5683     }
5684    return(nnum);
5685   }
5686  /* for reg - can not fail */
5687  ntyp = __from_vpi_vartyp(typ);
5688  for (ni = 0; ni < onnum; ni++, np++)
5689   {
5690    if (np->n_isarr) continue;
5691    if (np->ntyp == ntyp) nnum++;
5692   }
5693  return(nnum);
5694 }
5695 
5696 
5697 /*
5698  * build the iterator for initial-always - 1-to-many selector is vpi process
5699  * but handle has type of object itself
5700  *
5701  * the object here is the ialst not the one statement
5702  */
bld_initalw_iterator(struct h_t * hp)5703 static vpiHandle bld_initalw_iterator(struct h_t *hp)
5704 {
5705  register struct ialst_t *ialp;
5706  register int32 iai;
5707  register struct hrec_t *hrp2;
5708  int32 ianum;
5709  vpiHandle ihref;
5710  struct h_t *hp2;
5711  struct mod_t *mdp;
5712  struct itree_t *itp;
5713  struct pviter_t *iterp;
5714 
5715  if (hp == NULL) return(__nil_iter_err(vpiProcess));
5716  if (hp->hrec->htyp != vpiModule)
5717   { mustbe_inmoditer_err(vpiProcess, hp); return(NULL); }
5718  itp = hp->hin_itp;
5719  mdp = itp->itip->imsym->el.emdp;
5720  if (mdp->ialst == NULL) return(NULL);
5721  for (ianum = 0, ialp = mdp->ialst; ialp != NULL; ialp = ialp->ialnxt)
5722   ianum++;
5723  /* DBG remove - checking again to maybe catch corrupted memory */
5724  if (ianum <= 0) return(NULL);
5725 
5726  iterp = __alloc_iter(ianum, &ihref);
5727  for (iai = 0, ialp = mdp->ialst; iai < ianum; iai++, ialp = ialp->ialnxt)
5728   {
5729    hp2 = &(iterp->scanhtab[iai]);
5730    hrp2 = hp2->hrec;
5731    if (ialp->iatyp == ALWAYS) hrp2->htyp = vpiAlways;
5732    else hrp2->htyp = vpiInitial;
5733    hrp2->hu.hialstp = ialp;
5734    hp2->hin_itp = itp;
5735   }
5736  return(ihref);
5737 }
5738 
5739 /*
5740  * build the iterator scan table for module contas
5741  * only called if at least one conta and no other 1-to-many access path
5742  */
bld_conta_iterator(struct h_t * hp)5743 static vpiHandle bld_conta_iterator(struct h_t *hp)
5744 {
5745  register int32 cai, gi;
5746  register struct h_t *hp2;
5747  register struct hrec_t *hrp2;
5748  int32 numcas, num1bcas;
5749  vpiHandle ihref;
5750  struct conta_t *cap;
5751  struct gate_t *gp;
5752  struct mod_t *mdp;
5753  struct itree_t *itp;
5754  struct pviter_t *iterp;
5755 
5756  if (hp == NULL) return(__nil_iter_err(vpiContAssign));
5757  if (hp->hrec->htyp != vpiModule)
5758   { mustbe_inmoditer_err(vpiContAssign, hp); return(NULL); }
5759  mdp = hp->hin_itp->itip->imsym->el.emdp;
5760 
5761  itp = hp->hin_itp;
5762  /* contas in table - does not include 1 bit cas treated as gate */
5763  numcas = mdp->mcanum;
5764  num1bcas = 0;
5765  if (mdp->mod_1bcas)
5766   {
5767    for (gi = 0; gi < mdp->mgnum; gi++)
5768     {
5769      gp = &(mdp->mgates[gi]);
5770      if (gp->gmsym->el.eprimp->gateid == G_ASSIGN) num1bcas++;
5771     }
5772   }
5773  if (numcas + num1bcas <= 0) return(NULL);
5774  iterp = __alloc_iter(numcas + num1bcas, &ihref);
5775  for (cai = 0, cap = &(mdp->mcas[0]); cai < numcas; cai++, cap++)
5776   {
5777    hp2 = &(iterp->scanhtab[cai]);
5778    hrp2 = hp2->hrec;
5779    hrp2->htyp = vpiContAssign;
5780    hrp2->hu.hcap = cap;
5781    hp2->hin_itp = itp;
5782   }
5783  if (mdp->mod_1bcas)
5784   {
5785    for (gi = 0; gi < mdp->mgnum; gi++)
5786     {
5787      gp = &(mdp->mgates[gi]);
5788 
5789      if (gp->gmsym->el.eprimp->gateid != G_ASSIGN) continue;
5790      hp2 = &(iterp->scanhtab[cai]);
5791      hrp2 = hp2->hrec;
5792      hrp2->htyp = vpiContAssign;
5793      hrp2->htyp2 = vpiGate;
5794      hrp2->hu.hgp = gp;
5795      hp2->hin_itp = itp;
5796      cai++;
5797     }
5798   }
5799  return(ihref);
5800 }
5801 
5802 /*
5803  * build the iterator scan table for gates one scan table mixed the 3
5804  * types with htyp giving the type
5805  *
5806  * notice primitives are all gates, switches, and udps
5807  */
bld_gate_iterator(struct h_t * hp)5808 static vpiHandle bld_gate_iterator(struct h_t *hp)
5809 {
5810  register struct gate_t *gp;
5811  register struct h_t *hp2;
5812  register struct hrec_t *hrp2;
5813  int32 numgs, gi, hi;
5814  vpiHandle ihref;
5815  struct pviter_t *iterp;
5816  struct mod_t *mdp;
5817 
5818  if (hp == NULL) return(__nil_iter_err(vpiPrimitive));
5819  if (hp->hrec->htyp != vpiModule)
5820   { mustbe_inmoditer_err(vpiPrimitive, hp); return(NULL); }
5821 
5822  mdp = hp->hin_itp->itip->imsym->el.emdp;
5823  if (mdp->mgnum == 0) return(NULL);
5824  for (numgs = 0, gi = 0; gi < mdp->mgnum; gi++)
5825   {
5826    gp = &(mdp->mgates[gi]);
5827    if (gp->gmsym->el.eprimp->gateid != G_ASSIGN) numgs++;
5828   }
5829  /* DBG remove - checking again to maybe catch corrupted memory */
5830  if (numgs <= 0) return(NULL);
5831  iterp = __alloc_iter(numgs, &ihref);
5832  for (gi = 0, hi = 0; gi < mdp->mgnum; gi++)
5833   {
5834    gp = &(mdp->mgates[gi]);
5835    if (gp->gmsym->el.eprimp->gateid == G_ASSIGN) continue;
5836 
5837    hp2 = &(iterp->scanhtab[hi++]);
5838    hrp2 = hp2->hrec;
5839    hrp2->hu.hgp = gp;
5840    hp2->hin_itp = hp->hin_itp;
5841    hrp2->htyp = __gate_to_vpiprimtyp(gp);
5842   }
5843  return(ihref);
5844 }
5845 
5846 /*
5847  * map from a gate_t to a vpi primitive type (i.e. vpi Switch)
5848  */
__gate_to_vpiprimtyp(struct gate_t * gp)5849 extern word32 __gate_to_vpiprimtyp(struct gate_t *gp)
5850 {
5851  int32 ptyp;
5852 
5853  switch ((byte) gp->g_class) {
5854   /* LOOKATME - is pull possible here (think so) */
5855   case GC_LOGIC: case GC_BUFIF: case GC_MOS: case GC_CMOS: case GC_PULL:
5856    ptyp = vpiGate;
5857    break;
5858   case GC_UDP: ptyp = vpiUdp; break;
5859   case GC_TRAN: case GC_TRANIF: ptyp = vpiSwitch; break;
5860   default: __vpi_terr(__FILE__, __LINE__); return(0);
5861  }
5862  return(ptyp);
5863 }
5864 
5865 /*
5866  * build the iterator scan table for mod paths
5867  * only called if module has at least one path
5868  */
bld_modpth_iterator(struct h_t * hp)5869 static vpiHandle bld_modpth_iterator(struct h_t *hp)
5870 {
5871  register int32 pi;
5872  register struct spcpth_t *pthp;
5873  register struct hrec_t *hrp2;
5874  int32 mpths;
5875  vpiHandle ihref;
5876  struct h_t *hp2;
5877  struct mod_t *mdp;
5878  struct pviter_t *iterp;
5879 
5880  if (hp == NULL) return(__nil_iter_err(vpiModPath));
5881  if (hp->hrec->htyp != vpiModule)
5882   { mustbe_inmoditer_err(vpiModPath, hp); return(NULL); }
5883 
5884  mdp = hp->hin_itp->itip->imsym->el.emdp;
5885  if (mdp->mspfy == NULL || mdp->mspfy->spcpths == NULL) return(NULL);
5886  mpths = 0;
5887  for (pthp = mdp->mspfy->spcpths; pthp != NULL; pthp = pthp->spcpthnxt)
5888   mpths++;
5889  /* DBG remove - checking again to maybe catch corrupted memory */
5890  if (mpths <= 0) return(NULL);
5891 
5892  iterp = __alloc_iter(mpths, &ihref);
5893  for (pi = 0, pthp = mdp->mspfy->spcpths; pi < mpths; pthp = pthp->spcpthnxt,
5894   pi++)
5895   {
5896    hp2 = &(iterp->scanhtab[pi]);
5897    hrp2 = hp2->hrec;
5898    hrp2->htyp = vpiModPath;
5899    hrp2->hu.hpthp = pthp;
5900    hp2->hin_itp = hp->hin_itp;
5901   }
5902  return(ihref);
5903 }
5904 
5905 /*
5906  * build the iterator scan table for tchks
5907  *
5908  * added complication must remove setup with tc setup of setup hold flag on
5909  * hold has pointer to setup value when needed
5910  */
bld_tchk_iterator(struct h_t * hp)5911 static vpiHandle bld_tchk_iterator(struct h_t *hp)
5912 {
5913  register int32 tci;
5914  register struct h_t *hp2;
5915  register struct tchk_t *tcp;
5916  register struct hrec_t *hrp2;
5917  int32 ntchks;
5918  vpiHandle ihref;
5919  struct mod_t *mdp;
5920  struct pviter_t *iterp;
5921 
5922  if (hp == NULL) return(__nil_iter_err(vpiTchk));
5923  if (hp->hrec->htyp != vpiModule)
5924   { mustbe_inmoditer_err(vpiTchk, hp); return(NULL); }
5925  mdp = hp->hin_itp->itip->imsym->el.emdp;
5926  if (mdp->mspfy == NULL || mdp->mspfy->tchks == NULL) return(NULL);
5927  for (ntchks = 0, tcp = mdp->mspfy->tchks; tcp != NULL; tcp = tcp->tchknxt)
5928   {
5929    if (tcp->tchktyp == TCHK_SETUP && tcp->tc_supofsuphld) continue;
5930    if (tcp->tchktyp == TCHK_RECOVERY && tcp->tc_recofrecrem) continue;
5931    ntchks++;
5932   }
5933  /* DBG remove - checking again to maybe catch corrupted memory */
5934  if (ntchks <= 0) return(NULL);
5935 
5936  iterp = __alloc_iter(ntchks, &ihref);
5937  for (tci = 0, tcp = mdp->mspfy->tchks; tcp != NULL; tcp = tcp->tchknxt)
5938   {
5939    /* must remove setup of setuphold since can access from hold side */
5940    if (tcp->tchktyp == TCHK_SETUP && tcp->tc_supofsuphld) continue;
5941    if (tcp->tchktyp == TCHK_RECOVERY && tcp->tc_recofrecrem) continue;
5942 
5943    hp2 = &(iterp->scanhtab[tci++]);
5944    hrp2 = hp2->hrec;
5945    hrp2->htyp = vpiTchk;
5946    hrp2->hu.htcp = tcp;
5947    hp2->hin_itp = hp->hin_itp;
5948   }
5949  return(ihref);
5950 }
5951 
5952 /*
5953  * given an object containing params handle - build iterator of all params
5954  *
5955  * otype is vpi_ type of net
5956  */
bld_param_iterator(struct h_t * hp,int32 otype)5957 static vpiHandle bld_param_iterator(struct h_t *hp, int32 otype)
5958 {
5959  register struct hrec_t *hrp;
5960  struct mod_t *mdp;
5961  struct task_t *tskp;
5962  struct itree_t *itp;
5963 
5964  if (hp == NULL)
5965   {
5966    return(__nil_iter_err(vpiParameter));
5967   }
5968 
5969  itp = hp->hin_itp;
5970  hrp = hp->hrec;
5971  switch (hrp->htyp) {
5972   case vpiModule:
5973    mdp = hp->hin_itp->itip->imsym->el.emdp;
5974    if (mdp->mprms == NULL) return(NULL);
5975    return(bld_listofparams_iter(mdp->mprms, mdp->mprmnum,
5976     mdp->mlocprms, mdp->mlocprmnum, itp, NULL));
5977   case vpiTask: case vpiFunction:
5978    tskp = hrp->hu.htskp;
5979 bld_tskprms:
5980    if (tskp->tsk_prms == NULL) return(NULL);
5981    return(bld_listofparams_iter(tskp->tsk_prms, tskp->tprmnum,
5982     tskp->tsk_locprms, tskp->tlocprmnum, itp, tskp));
5983   case vpiNamedBegin: case vpiNamedFork:
5984    tskp = hrp->hu.htskp;
5985    goto bld_tskprms;
5986   default:
5987    __vpi_err(1851, vpiError,
5988     "unable to construct iterator of contained %s for %s object",
5989     __to_vpionam(__wrks1, (word32) otype), __to_vpionam(__wrks2, hrp->htyp));
5990  }
5991  return(NULL);
5992 }
5993 
5994 /*
5995  * build the iterator scan table for parameters (all nets of mprms)
5996  *
5997  * LOOKATME - why was mprms not freed? - needed for here
5998  * SJM 09/28/06 - simplified since no more param arrays
5999  */
bld_listofparams_iter(struct net_t * nptab,int32 nparams,struct net_t * loc_nptab,int32 loc_nparams,struct itree_t * itp,struct task_t * tskp)6000 static vpiHandle bld_listofparams_iter(struct net_t *nptab, int32 nparams,
6001  struct net_t *loc_nptab, int32 loc_nparams, struct itree_t *itp,
6002  struct task_t *tskp)
6003 {
6004  register int32 pi, iti;
6005  register struct hrec_t *hrp;
6006  int32 tot_nparams;
6007  vpiHandle ihref;
6008  struct h_t *hp;
6009  struct net_t *np;
6010  struct pviter_t *iterp;
6011 
6012  tot_nparams = nparams + loc_nparams;
6013  if (tot_nparams == 0) return(NULL);
6014  /* because iter by array class may have params but 0 iterator size */
6015  if (tot_nparams <= 0) return(NULL);
6016 
6017  iterp = __alloc_iter(tot_nparams, &ihref);
6018  for (pi = 0, iti = -1; pi < nparams; pi++)
6019   {
6020    np = &(nptab[pi]);
6021    hp = &(iterp->scanhtab[++iti]);
6022    hrp = hp->hrec;
6023    hrp->htyp = vpiParameter;
6024    hrp->hu.hnp = &(nptab[pi]);
6025    hp->hin_itp = itp;
6026    hrp->hin_tskp = tskp;
6027   }
6028  /* SJM 09/27/06 - local params go into iterator after normal */
6029  for (pi = 0; pi < loc_nparams; pi++)
6030   {
6031    np = &(loc_nptab[pi]);
6032    hp = &(iterp->scanhtab[++iti]);
6033    hrp = hp->hrec;
6034    hrp->htyp = vpiParameter;
6035    hrp->hu.hnp = &(loc_nptab[pi]);
6036    hp->hin_itp = itp;
6037    hrp->hin_tskp = tskp;
6038   }
6039 
6040  return(ihref);
6041 }
6042 
6043 /*
6044  * build the iterator scan table for specparam (all nets)
6045  *
6046  * only called if module has at least one specparam
6047  * this does not need parent since one in module - can get from itp
6048  */
bld_specparam_iterator(struct h_t * hp)6049 static vpiHandle bld_specparam_iterator(struct h_t *hp)
6050 {
6051  register int32 pi;
6052  register struct h_t *hp2;
6053  register struct hrec_t *hrp2;
6054  int32 nsparams;
6055  vpiHandle ihref;
6056  struct pviter_t *iterp;
6057  struct mod_t *mdp;
6058  struct spfy_t *spfyp;
6059  struct hrec_t *hrp;
6060 
6061  if (hp == NULL) return(__nil_iter_err(vpiSpecParam));
6062  hrp = hp->hrec;
6063  if (hrp->htyp != vpiModule)
6064   { mustbe_inmoditer_err(vpiSpecParam, hp); return(NULL); }
6065 
6066  mdp = hp->hin_itp->itip->imsym->el.emdp;
6067  if ((spfyp = mdp->mspfy) == NULL) return(NULL);
6068  if (spfyp->msprms == NULL) return(NULL);
6069 
6070  nsparams = spfyp->sprmnum;
6071  if (nsparams <= 0) return(NULL);
6072  iterp = __alloc_iter(nsparams, &ihref);
6073  for (pi = 0; pi < spfyp->sprmnum; pi++)
6074   {
6075    hp2 = &(iterp->scanhtab[pi]);
6076    hrp2 = hp2->hrec;
6077    hrp2->htyp = vpiSpecParam;
6078    hrp2->hu.hnp = &(spfyp->msprms[pi]);
6079    hp2->hin_itp = hp->hin_itp;
6080   }
6081  return(ihref);
6082 }
6083 
6084 /*
6085  * build a defparam statement iterator
6086  *
6087  * no one master list - must match itree location of module handle
6088  */
bld_defparam_stmt_iterator(struct h_t * hp)6089 static vpiHandle bld_defparam_stmt_iterator(struct h_t *hp)
6090 {
6091  register int32 dfi;
6092  register struct h_t *hp2;
6093  register struct hrec_t *hrp2;
6094  register struct dfparam_t *dfp;
6095  int32 ndfps;
6096  vpiHandle ihref;
6097  struct pviter_t *iterp;
6098  struct itree_t *itp;
6099 
6100  if (hp == NULL) return(__nil_iter_err(vpiDefParam));
6101  if (hp->hrec->htyp != vpiModule)
6102   { mustbe_inmoditer_err(vpiDefParam, hp); return(NULL); }
6103 
6104  if (__dfphdr == NULL) return(NULL);
6105 
6106  for (ndfps = 0, dfp = __dfphdr; dfp != NULL; dfp = dfp->dfpnxt)
6107   {
6108    itp = __find_dfpbot_itp(dfp);
6109    if (itp == hp->hin_itp) ndfps++;
6110   }
6111  if (ndfps <= 0) return(NULL);
6112  iterp = __alloc_iter(ndfps, &ihref);
6113  for (dfi = 0, dfp = __dfphdr; dfp != NULL; dfp = dfp->dfpnxt)
6114   {
6115    itp = __find_dfpbot_itp(dfp);
6116    if (itp != hp->hin_itp) continue;
6117 
6118    hp2 = &(iterp->scanhtab[dfi]);
6119    hrp2 = hp2->hrec;
6120    hrp2->htyp = vpiDefParam;
6121    hrp2->hu.hdfp = dfp;
6122    hp2->hin_itp = hp->hin_itp;
6123    dfi++;
6124   }
6125  return(ihref);
6126 }
6127