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