1 /* Copyright (c) 1991-2007 Pragmatic C Software Corp. */
2 
3 /*
4    This program is free software; you can redistribute it and/or modify it
5    under the terms of the GNU General Public License as published by the
6    Free Software Foundation; either version 2 of the License, or (at your
7    option) any later version.
8 
9    This program is distributed in the hope that it will be useful, but
10    WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License along
15    with this program; if not, write to the Free Software Foundation, Inc.,
16    59 Temple Place, Suite 330, Boston, MA, 02111-1307.
17 
18    We are selling our new Verilog compiler that compiles to X86 Linux
19    assembly language.  It is at least two times faster for accurate gate
20    level designs and much faster for procedural designs.  The new
21    commercial compiled Verilog product is called CVC.  For more information
22    on CVC visit our website at www.pragmatic-c.com/cvc.htm or contact
23    Andrew at avanvick@pragmatic-c.com
24 
25  */
26 
27 
28 /*
29  * run time execution routines - statements but not expression eval
30  */
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sys/types.h>
36 #include <setjmp.h>
37 #include <math.h>
38 #include <errno.h>
39 #include <ctype.h>
40 
41 #include <signal.h>
42 
43 #ifdef __DBMALLOC__
44 #include "../malloc.h"
45 #endif
46 
47 #include "v.h"
48 #include "cvmacros.h"
49 
50 /* local prototypes */
51 static void tr_resume_msg(void);
52 static void exec_stmts(register struct st_t *);
53 static void thrd_done_cleanup(register struct thread_t *);
54 static void brktr_exec_stmts(register struct st_t *);
55 static void step_exec_stmt(register struct st_t *);
56 static int32 stepped_to_new_loc(struct st_t *);
57 static void eval_tskassign_rhsexpr(register struct xstk_t *, register int32,
58  register int32, register int32, register int32);
59 static void tr_proc_assign(struct st_t *, struct xstk_t *);
60 static void tr_nbproc_assign(struct st_t *, struct xstk_t *);
61 static struct st_t *exec_rep_ectl_setup(struct st_t *stp);
62 static int32 exec_dctrl(struct st_t *);
63 static void sched_proc_delay(struct delctrl_t *, word32 *, int32);
64 static void sched_nbproc_delay(struct delctrl_t *, struct xstk_t *,
65  struct st_t *);
66 static void arm_event_dctrl(struct delctrl_t *, register word32 *, int32);
67 static void arm_nbevent_dctrl(struct delctrl_t *, struct xstk_t *,
68  struct st_t *);
69 static struct st_t *exec_case(struct st_t *);
70 static struct st_t *exec_real_case(struct st_t *);
71 static void tr_case_st(struct xstk_t *, int32);
72 static struct st_t *exec_casex(struct st_t *);
73 static struct st_t *exec_casez(struct st_t *);
74 static int32 exec_wait(register struct st_t *);
75 static int32 for_not_done(struct for_t *);
76 static void exec_namblk(struct st_t *);
77 static struct thread_t *sched_fj_subthread(struct st_t *stp);
78 static void init_thrd(register struct thread_t *);
79 static void tradd_tf_argval(int32, struct net_t *, struct xstk_t *);
80 static void store_tskcall_outs(struct st_t *);
81 static void grow_fcstk(void);
82 static void exec_count_drivers(struct expr_t *);
83 static void exec_testplusargs(struct expr_t *);
84 static void exec_scanplusargs(struct expr_t *);
85 static void exec_valueplusargs(struct expr_t *);
86 static void exec_1arg_transcendental(int32, struct expr_t *);
87 static void exec_transcendental_int(struct expr_t *);
88 static void exec_transcendental_sign(struct expr_t *);
89 static void exec_transcendental_powsign(int32, struct expr_t *);
90 static void exec_transcendental_minmax(int32, struct expr_t *);
91 static void exec_transcendental_atan2(struct expr_t *);
92 static void exec_transcendental_hypot(struct expr_t *);
93 static void exec_cause(struct st_t *);
94 static struct thread_t *find_hgh_sametskthrd(struct thread_t *);
95 static int32 thread_above_cur(struct thread_t *);
96 static void free_thd_stuff(struct thread_t *);
97 static void unlink_tskthd(struct thread_t *);
98 static int32 chk_strobe_infloop(struct st_t *, struct sy_t *);
99 static void mcd_do_fclose(struct expr_t *);
100 static word32 bld_open_mcd(void);
101 static word32 mc_do_fopen(struct expr_t *);
102 static void do_showvars_stask(struct expr_t *);
103 static void do_warn_supp_chg(char *, struct expr_t *, int32);
104 static void do_reset(struct expr_t *);
105 static void do_showscopes(struct expr_t *);
106 static void prt_1m_scopelist(struct itree_t *);
107 static void prt_1tsk_scopelist(struct task_t *, int32);
108 static void prt_1m_nestscopes(struct itree_t *);
109 static void prt_1tsk_nestscopes(struct symtab_t *);
110 static void exec_qfull(struct expr_t *);
111 static void do_q_init(struct expr_t *);
112 static struct q_hdr_t *find_q_from_id(int32);
113 static void init_q(struct q_hdr_t *);
114 static void do_q_add(struct expr_t *);
115 static void do_q_remove(struct expr_t *);
116 static void do_q_examine(struct expr_t *);
117 static void cmp_mean_interarriv_tim(word64 *, struct q_hdr_t *);
118 static void cmp_max_wait(word64 *, struct q_hdr_t *);
119 static void cmp_mean_wait_tim(word64 *, struct q_hdr_t *);
120 static void exec_prttimscale(struct expr_t *);
121 static void exec_timefmt(struct expr_t *);
122 static int32 get_opt_starg(struct expr_t *, int32);
123 static void exec_log_fnamchg(struct expr_t *);
124 static void exec_trace_fnamchg(struct expr_t *);
125 static void exec_expr_schg(struct expr_t *);
126 static void free_thd_subtree(struct thread_t *);
127 static void suspend_curthd(struct st_t *);
128 
129 static word32 fio_do_fopen(struct expr_t *, struct expr_t *);
130 static word32 fio_fopen(char *, char *);
131 static int32 chk_cnvt_fd_modes(char *, char *);
132 static void fio_do_fclose(struct expr_t *);
133 static int32 chk_get_mcd_or_fd(struct expr_t *, int32 *);
134 static void fio_fflush(struct expr_t *);
135 static int32 fio_ungetc(struct expr_t *, struct expr_t *);
136 static int32 chk_get_ver_fd(struct expr_t *);
137 static int32 fio_fgets(struct expr_t *, struct expr_t *);
138 static int32 fio_rewind(struct expr_t *);
139 static int32 fio_fseek(struct expr_t *, struct expr_t *, struct expr_t *);
140 static int32 fio_ferror(struct expr_t *, struct expr_t *);
141 static void fio_swrite(struct expr_t *, int32);
142 static void fio_sformat(struct expr_t *);
143 static int32 fio_fscanf(struct expr_t *);
144 static int32 fio_sscanf(struct expr_t *);
145 static int32 fio_exec_scanf(FILE *, struct expr_t *);
146 static int32 fio_fread(struct expr_t *);
147 static void fread_onto_stk(struct xstk_t *, byte *, int32);
148 static int32 fio_arr_fread(struct expr_t *, int32, struct expr_t *,
149  struct expr_t *);
150 static int32 scanf_getc(FILE *);
151 static void scanf_ungetc(int32, FILE *);
152 static int32 chk_scanf_fmt(char *);
153 static int32 collect_scanf_num(int32 *, FILE *, int32, int32, int32);
154 static int32 collect_scanf_realnum(double *, FILE *, int32, int32, int32);
155 static struct xstk_t *collect_ufmt_binval(FILE *, struct expr_t *, int32);
156 static struct xstk_t *collect_zfmt_binval(FILE *, struct expr_t *, int32 );
157 static int32 cnvt_scanf_stnam_to_val(char *);
158 extern void __str_do_disp(struct expr_t *, int32);
159 extern word32 __inplace_lnegate(register word32 *, int32);
160 
161 /* extern prototypes (maybe defined in this module) */
162 extern int32 __comp_sigint_handler(void);
163 extern char *__my_malloc(int32);
164 extern char *__pv_stralloc(char *);
165 extern char *__my_realloc(char *, int32, int32);
166 extern struct xstk_t *__eval_assign_rhsexpr(register struct expr_t *,
167  register struct expr_t *);
168 extern struct thread_t *__setup_tsk_thread(struct task_t *);
169 extern void __sched_fork(struct st_t *);
170 extern i_tev_ndx __bld_nb_tev(struct st_t *, struct xstk_t *, word64);
171 extern int32 __lhsexpr_var_ndx(register struct expr_t *);
172 extern void __eval_lhsexpr_var_ndxes(register struct expr_t *);
173 extern struct st_t *__brktr_exec_1stmt(struct st_t *);
174 extern struct thread_t *__alloc_thrd(void);
175 extern struct st_t *__exec_tskcall(struct st_t *);
176 extern struct xstk_t *__eval2_xpr(struct expr_t *);
177 extern struct expr_t *__copy_expr(struct expr_t *);
178 extern struct expr_t *__sim_copy_expr(struct expr_t *);
179 extern int32 __comp_ndx(register struct net_t *, register struct expr_t *);
180 extern struct expr_t *__bld_rng_numxpr(word32, word32, int32);
181 extern void __free_xtree(struct expr_t *);
182 extern char *__regab_tostr(char *, word32 *, word32 *, int32, int32, int32);
183 extern char *__xregab_tostr(char *, word32 *, word32 *, int32, struct expr_t *);
184 extern char *__msgexpr_tostr(char *, struct expr_t *);
185 extern char *__to_idnam(struct expr_t *);
186 extern char *__msg_blditree(char *, struct itree_t *, struct task_t *);
187 extern char *__msg2_blditree(char *, struct itree_t *);
188 extern char *__bld_lineloc(char *, word32, int32);
189 extern char *__to_timunitnam(char *, word32);
190 extern char *__to_timstr(char *, word64 *);
191 extern char *__to_tetyp(char *, word32);
192 extern char *__to_tsktyp(char *, word32);
193 extern double __unscale_realticks(word64 *, struct mod_t *);
194 extern FILE *__tilde_fopen(char *, char *);
195 extern struct xstk_t *__ld_wire_driver(register struct net_pin_t *);
196 extern struct xstk_t *__ld_stwire_driver(register struct net_pin_t *);
197 extern int32 __has_vpi_driver(struct net_t *, struct net_pin_t *);
198 extern char *__schop(char *, char *);
199 extern char *__to_dcenam(char *, word32);
200 extern struct xstk_t *__cstr_to_vval(char *);
201 extern struct task_t *__getcur_scope_tsk(void);
202 extern word32 __mc1_fopen(char *, int32, int32);
203 extern word32 __close_mcd(word32, int32);
204 extern void __wrap_puts(char *, FILE *);
205 extern void __wrap_putc(int32, FILE *);
206 extern void __evtr_resume_msg(void);
207 extern void __do_iact_disable(struct hctrl_t *, int32);
208 extern void __dmp_thrd_info(struct thread_t *);
209 extern void __dmp_tskthd(struct task_t *, struct mod_t *);
210 extern void __my_free(char *, int32);
211 extern void __exec2_proc_assign(struct expr_t *, register word32 *,
212  register word32 *);
213 extern int32 __cvt_lngbool(word32 *, word32 *, int32);
214 extern int32 __wide_vval_is0(register word32 *, int32);
215 extern void __exec_qc_assign(struct st_t *, int32);
216 extern void __exec_qc_wireforce(struct st_t *);
217 extern void __exec_qc_deassign(struct st_t *, int32);
218 extern void __exec_qc_wirerelease(struct st_t *);
219 extern int32 __process_brkpt(struct st_t *);
220 extern void __prt_src_lines(int32, int32, int32);
221 extern void __cnv_stk_fromreg_toreal(struct xstk_t *, int32);
222 extern void __cnv_stk_fromreal_toreg32(struct xstk_t *);
223 extern void __sizchgxs(struct xstk_t *, int32);
224 extern void __narrow_to1wrd(register struct xstk_t *);
225 extern void __narrow_sizchg(register struct xstk_t *, int32);
226 extern void __sizchg_widen(register struct xstk_t *, int32);
227 extern void __sgn_xtnd_wrd(register struct xstk_t *, int32);
228 extern void __sgn_xtnd_widen(struct xstk_t *, int32);
229 extern void __dmp_proc_assgn(FILE *, struct st_t *, struct delctrl_t *, int32);
230 extern void __trunc_exprline(int32, int32);
231 extern void __dmp_nbproc_assgn(FILE *, struct st_t *, struct delctrl_t *);
232 extern void __dmp_dctrl(FILE *, struct delctrl_t *);
233 extern void __chg_xprline_size(int32);
234 extern void __dmp_dcxpr(FILE *, union del_u, word32);
235 extern void __get_del(register word64 *, register union del_u, word32);
236 extern void __insert_event(register i_tev_ndx);
237 extern void __dmp_forhdr(FILE *, struct for_t *);
238 extern void __add_ev_to_front(register i_tev_ndx);
239 extern void __dmp_tskcall(FILE *, struct st_t *);
240 extern void __xmrpush_refgrp_to_targ(struct gref_t *);
241 extern void __adds(char *);
242 extern void __chg_st_val(struct net_t *, register word32 *, register word32 *);
243 extern void __st_val(struct net_t *, register word32 *, register word32 *);
244 extern void __grow_xstk(void);
245 extern void __chg_xstk_width(struct xstk_t *, int32);
246 extern void __grow_tevtab(void);
247 extern void __ld_wire_val(register word32 *, register word32 *, struct net_t *);
248 extern void __do_interactive_loop(void);
249 extern void __cnv_ticks_tonum64(word64 *, word64, struct mod_t *);
250 extern void __exec_sfrand(struct expr_t *);
251 extern void __exec_scale(struct expr_t *);
252 extern void __pli_func_calltf(struct expr_t *);
253 extern void __vpi_sysf_calltf(struct expr_t *);
254 extern void __get_bidnpp_sect(struct net_t *, struct net_pin_t *, int32 *,
255  int32 *);
256 extern char *__get_eval_cstr(struct expr_t *, int32 *);
257 extern void __free_1thd(struct thread_t *);
258 extern struct st_t *__exec_stsk(struct st_t *, struct sy_t *,
259  struct tskcall_t *);
260 extern void __free_thd_list(struct thread_t *);
261 extern int32 __exec_disable(struct expr_t *);
262 extern void __do_disp(register struct expr_t *, int32);
263 extern void __fio_do_disp(register struct expr_t *, int32, int32, char *);
264 extern void __start_fmonitor(struct st_t *);
265 extern void __dmpmod_nplst(struct mod_t *, int32);
266 extern void __start_monitor(struct st_t *);
267 extern void __exec_readmem(struct expr_t *, int32);
268 extern void __exec_sreadmem(struct expr_t *, int32);
269 extern void __exec_dumpvars(struct expr_t *);
270 extern int32 __get_eval_word(struct expr_t *, word32 *);
271 extern void __exec_input_fnamchg(struct expr_t *);
272 extern void __exec_history_list(int32);
273 extern void __do_scope_list(void);
274 extern void __exec_sdf_annotate_systsk(struct expr_t *);
275 extern void __call_misctfs_finish(void);
276 extern void __vpi_endsim_trycall(void);
277 extern void __emit_stsk_endmsg(void);
278 extern void __maybe_open_trfile(void);
279 extern void __escape_to_shell(char *);
280 extern void __write_snapshot(int32);
281 extern void __prt2_mod_typetab(int32);
282 extern void __pli_task_calltf(struct st_t *);
283 extern void __vpi_syst_calltf(struct st_t *);
284 extern void __my_fclose(FILE *);
285 extern void __emit_1showvar(struct net_t *, struct gref_t *);
286 extern void __prt_top_mods(void);
287 extern void __disp_itree_path(struct itree_t *, struct task_t *);
288 extern void __set_scopchg_listline(void);
289 extern void __call_misctfs_scope(void);
290 extern void __vpi_iactscopechg_trycall(void);
291 extern void __my_ftime(time_t *, time_t *);
292 extern void __prt_end_msg(void);
293 extern void __exec_dist_uniform(struct expr_t *);
294 extern void __exec_dist_stdnorm(struct expr_t *);
295 extern void __exec_dist_exp(struct expr_t *);
296 extern void __exec_dist_poisson(struct expr_t *);
297 extern void __exec_chi_square(struct expr_t *);
298 extern void __exec_dist_t(struct expr_t *);
299 /* ??? extern void __dmp_event_tab(void); */
300 extern void __my_dv_flush(void);
301 extern void __add_nchglst_el(register struct net_t *);
302 extern void __add_dmpv_chglst_el(struct net_t *);
303 extern void __wakeup_delay_ctrls(register struct net_t *, register int32,
304  register int32);
305 extern void __dmp_all_thrds(void);
306 extern double __cnvt_stk_to_real(struct xstk_t *, int32);
307 extern int32 __enum_is_suppressable(int32);
308 extern int32 __trim1_0val(word32 *, int32);
309 extern char *__vval_to_vstr(word32 *, int32, int32 *);
310 extern void __vstr_to_vval(word32 *, char *, int32);
311 extern int32 __is_vdigit(int32, int32);
312 extern void __to_dhboval(int32, int32);
313 extern double __my_strtod(char *, char **, int32 *);
314 extern void __add_pnd0_nonblk_list(i_tev_ndx);
315 
316 extern struct expr_t *__disp_1fmt_to_exprline(char *, struct expr_t *);
317 extern void __getarr_range(struct net_t *, int32 *, int32 *, int32 *);
318 extern void __st_arr_val(union pck_u, int32, int32, int32, register word32 *,
319  register word32 *);
320 extern void __chg_st_arr_val(union pck_u, int32, int32, int32,
321  register word32 *, register word32 *);
322 extern int32 __fd_do_fclose(int32);
323 extern void __add_select_nchglst_el(register struct net_t *, register int32,
324  register int32);
325 
326 extern void __tr_msg(char *, ...);
327 extern void __cv_msg(char *, ...);
328 extern void __cvsim_msg(char *, ...);
329 extern void __sgfwarn(int32, char *, ...);
330 extern void __sgferr(int32, char *, ...);
331 extern void __dbg_msg(char *, ...);
332 extern void __sgfinform(int32, char *, ...);
333 extern void __arg_terr(char *, int32);
334 extern void __case_terr(char *, int32);
335 extern void __misc_terr(char *, int32);
336 extern void __misc_sgfterr(char *, int32);
337 extern void __my_exit(int32, int32);
338 extern void __my_fprintf(FILE *, char *, ...);
339 
340 /* reset mechanism long jump buffer */
341 extern jmp_buf __reset_jmpbuf;
342 
343 /* system stuff */
344 extern int32 errno;
345 
346 /* some general evaluation tables */
347 word32 __masktab[] = {
348  /* since 0 is the same as all used, mask must be entire word32 */
349  0xffffffffL, 0x00000001L, 0x00000003L, 0x00000007L,
350  0x0000000fL, 0x0000001fL, 0x0000003fL, 0x0000007fL,
351  0x000000ffL, 0x000001ffL, 0x000003ffL, 0x000007ffL,
352  0x00000fffL, 0x00001fffL, 0x00003fffL, 0x00007fffL,
353  0x0000ffffL, 0x0001ffffL, 0x0003ffffL, 0x0007ffffL,
354  0x000fffffL, 0x001fffffL, 0x003fffffL, 0x007fffffL,
355  0x00ffffffL, 0x01ffffffL, 0x03ffffffL, 0x07ffffffL,
356  0x0fffffffL, 0x1fffffffL, 0x3fffffffL, 0x7fffffffL,
357  /* special for places where mask uses length i.e. 32 bits */
358  0xffffffffL
359 };
360 
361 extern double __dbl_toticks_tab[];
362 
363 /*
364  * ROUTINES TO PROCESS PROCEDURAL EVENTS AND EXECUTE BEHAVIORAL STATEMENTS
365  */
366 
367 /*
368  * execute a control thread from one event suspension until next
369  * need to handle rhs delay control and => proc. assignment
370  *
371  * when thread completes just removes and continues with other threads
372  * know if this suspends or hits ctrl-c will always build and schedule new ev
373  * possible for thread next statement to be nil to terminate thread
374  * and here must be left and terminated after suspend
375  */
__process_thrd_ev(register struct tev_t * tevp)376 extern void __process_thrd_ev(register struct tev_t *tevp)
377 {
378  register struct st_t *stp;
379  struct st_t *stp2;
380  struct thread_t *parthp;
381 
382  __proc_thrd_tevents++;
383  __suspended_thd = NULL;
384  __suspended_itp = NULL;
385  /* set current thread and remove connection of thread to event */
386  __cur_thd = tevp->tu.tethrd;
387  __cur_thd->thdtevi = -1;
388 
389  /* if not func. must have change itree to right one for thread */
390  /* NO - this will not be be true if invoked xmr task - inst ptr. diff */
391  /* but will be put back when xmr task done so ok */
392  /* DBG remove --
393  if (__fcspi == -1 && __cur_thd->th_itp != __inst_ptr)
394   __misc_terr(__FILE__, __LINE__);
395  --- */
396  stp = __cur_thd->thnxtstp;
397 
398  /* possible to remove thread even though no more statements to exec */
399  if (stp != NULL && (__st_tracing || __ev_tracing))
400   {
401    __slin_cnt = stp->stlin_cnt;
402    __sfnam_ind = stp->stfnam_ind;
403 
404    if (__st_tracing) tr_resume_msg(); else __evtr_resume_msg();
405    __tr_msg("-- resuming at statement %s\n",
406     __bld_lineloc(__xs, stp->stfnam_ind, stp->stlin_cnt));
407   }
408 
409  /* for each completed thread continue in parent without schd */
410  /* loop because continues until thread tree done or suspend */
411  for (__stmt_suspend = FALSE;;)
412   {
413    /* keep executing behavioral stmts until done or hit timing control */
414    if (stp != NULL)
415     {
416      /* even if single stepping must not see iact threads */
417      /* since this always either hits end of thread or suspends */
418      if (__single_step && __cur_thd->th_hctrl == NULL)
419       {
420        step_exec_stmt(stp);
421       }
422      /* but batch tracing traces */
423      else if (__st_tracing) brktr_exec_stmts(stp);
424      else exec_stmts(stp);
425 
426      /* on suspend event itree location is right for exec */
427      /* if no suspend but current ctrl thread (init/always/task) got to end */
428      /* fall thru and try to immediately exec parent */
429      if (__stmt_suspend) break;
430     }
431 
432    /* DBG remove --- */
433    if (__cur_thd->thdtevi != -1) __misc_terr(__FILE__, __LINE__);
434    /* --- */
435    /* this thread tree done if nil - can only be interactive or init/always */
436    /* this handles all freeing because entire thread tree done */
437    if ((parthp = __cur_thd->thpar) == NULL)
438     {
439      /* if interactive thread - free and set possible history disabled */
440      if (__cur_thd->th_hctrl != NULL)
441       __do_iact_disable(__cur_thd->th_hctrl, FALSE);
442      __stmt_suspend = TRUE;
443      break;
444     }
445 
446    /* know if task has outs will always have parent */
447    /* store parameters if needed */
448    if (__cur_thd->tsk_stouts)
449     {
450      /* DBG remove --- */
451      if (!parthp->th_postamble) __misc_terr(__FILE__, __LINE__);
452      /* --- */
453      /* if disabled do not store parameters, but still adjust nxt stp */
454      /* not parent must be set to continue at tsk call for storing outs */
455      if (!__cur_thd->th_dsable) store_tskcall_outs(parthp->thnxtstp);
456 
457      /* SJM 08/18/02 - must fixup including skip of non loop end gotos */
458      /* now that store of tsk outs finished */
459      stp2 = parthp->thnxtstp;
460      if (stp2 != NULL) stp2 = stp2->stnxt;
461      if (stp2 == NULL) parthp->thnxtstp = NULL;
462      else if (stp2->stmttyp != S_GOTO) parthp->thnxtstp = stp2;
463      else if (stp2->lpend_goto) parthp->thnxtstp = stp2;
464      else
465       {
466        for (;;)
467         {
468          /* know here stp2 is non loop end goto - moves to goto first */
469          if ((stp2 = stp2->st.sgoto) == NULL || stp2->stmttyp != S_GOTO)
470           { parthp->thnxtstp = stp2; break; }
471          if (stp2->lpend_goto) { parthp->thnxtstp = stp2; break; }
472         }
473       }
474      /* ??? REPLACED parthp->thnxtstp = parthp->thnxtstp->stnxt; */
475      parthp->th_postamble = FALSE;
476     }
477 
478    /* DBG remove --- */
479    if (__cur_thd->th_ialw) __misc_terr(__FILE__, __LINE__);
480    if (parthp->thofscnt == 0) __misc_terr(__FILE__, __LINE__);
481    if (__debug_flg)
482     { __dbg_msg("*** thread finished:\n"); __dmp_thrd_info(__cur_thd); }
483    /* --- */
484 
485    /* this thread finished - remove it from control thread d.s. */
486    thrd_done_cleanup(parthp);
487 
488    /* more fork-join subthreads to complete */
489    if (parthp->thofscnt > 0) { __stmt_suspend = TRUE; break; }
490 
491    /* all subthreads finished, continue with parent */
492    /* for enabled task (not named block), know out arg. store phase done */
493    parthp->thofs = NULL;
494    /* continue with parent by executing next statement */
495    /* no suspend here */
496    __cur_thd = parthp;
497    __pop_itstk();
498    __push_itstk(__cur_thd->th_itp);
499    stp = __cur_thd->thnxtstp;
500   }
501  /* DBG remove
502  if (!__stmt_suspend) __misc_terr(__FILE__, __LINE__);
503  --- */
504  /* only have current thread when evaling thread event */
505  __cur_thd = NULL;
506 }
507 
508 
509 /*
510  * routine to clean up linked thread control structure after thread done
511  *
512  * thread finished - clean up and try to continue in parent
513  * this removes various connected stuff but leave thread fields
514  *
515  * when done no current thread caller must set if needed
516  */
thrd_done_cleanup(register struct thread_t * parthp)517 static void thrd_done_cleanup(register struct thread_t *parthp)
518 {
519  free_thd_stuff(__cur_thd);
520 
521  /* move up and continue in parent */
522  parthp->thofscnt -= 1;
523  /* one thread of fork/join done - link it out after redundant cnt dec */
524  if (__cur_thd->thleft != NULL)
525   __cur_thd->thleft->thright = __cur_thd->thright;
526  /* adjust parent's thread ofset if removing first in list */
527  else parthp->thofs = __cur_thd->thright;
528 
529  if (__cur_thd->thright != NULL)
530   __cur_thd->thright->thleft = __cur_thd->thleft;
531  /* free stuff already removed and events canceled so just free */
532  __my_free((char *) __cur_thd, sizeof(struct thread_t));
533  __cur_thd = NULL;
534 
535  /* RELEASE remove ---
536  if (parthp->thofscnt == 1)
537   {
538    if (parthp->thofs->thright != NULL
539     || parthp->thofs->thleft != NULL) __misc_terr(__FILE__, __LINE__);
540   }
541  --- */
542 }
543 
544 /*
545  * print out trace location and time states
546  *
547  * no leading new line may need to have separate trace file if user output
548  * leaves unfinished lines.
549  *
550  * for statement tracing only change file name when module changes
551  * so line number will be in same * file
552  */
tr_resume_msg(void)553 static void tr_resume_msg(void)
554 {
555  char s1[RECLEN], s2[RECLEN];
556 
557  if (__inst_ptr != __last_tritp)
558   {
559    __tr_msg("==> tracing in %s (%s) line %s\n",
560     __msg2_blditree(s1, __inst_ptr), __inst_ptr->itip->imsym->synam,
561     __bld_lineloc(s2, (word32) __sfnam_ind, __slin_cnt));
562    __last_tritp = __inst_ptr;
563   }
564  if (__last_trtime != __simtime)
565   {
566    /* this should go through time format ? */
567    __tr_msg("<<< tracing at time %s\n", __to_timstr(s1, &__simtime));
568    __last_trtime = __simtime;
569   }
570 }
571 
572 /*
573  * execute statement list
574  * called from thrd event processing routine and return when blocked or done
575  * execute until fall off end (thread done) or schedule wake up event
576  */
exec_stmts(register struct st_t * stp)577 static void exec_stmts(register struct st_t *stp)
578 {
579  register word32 val;
580  register struct xstk_t *xsp;
581  int32 tmp, wlen;
582  struct st_t *stp2;
583  struct for_t *forp;
584  struct expr_t *cntx;
585 
586  /* notice one pass through loop executes exactly 1 statement */
587  for (;;)
588   {
589    __slin_cnt = stp->stlin_cnt;
590    __sfnam_ind = stp->stfnam_ind;
591    __num_execstmts++;
592    /* DBG remove --
593    if (__cur_thd == NULL || __cur_thd->th_itp != __inst_ptr)
594     __misc_terr(__FILE__, __LINE__);
595    --- */
596 
597    switch ((byte) stp->stmttyp) {
598     /* SJM - 02/08/02 - should not count empties as exec stmts */
599     case S_NULL: case S_STNONE: __num_execstmts--; break;
600     case S_FORASSGN:
601      __num_addedexec++;
602      /* FALLTHRU */
603     case S_PROCA:
604      xsp = __eval_assign_rhsexpr(stp->st.spra.rhsx, stp->st.spra.lhsx);
605      __exec2_proc_assign(stp->st.spra.lhsx, xsp->ap, xsp->bp);
606      __pop_xstk();
607      break;
608     case S_NBPROCA:
609      /* only non delay form non blocking assign exec here - implied #0 */
610      xsp = __eval_assign_rhsexpr(stp->st.spra.rhsx, stp->st.spra.lhsx);
611      sched_nbproc_delay((struct delctrl_t *) NULL, xsp, stp);
612      __pop_xstk();
613      break;
614     case S_RHSDEPROCA:
615      /* notice this statement never executed directly - delctrl execed */
616      /* then after block - results execed here */
617      wlen = wlen_(stp->st.spra.lhsx->szu.xclen);
618      /* know rhs width here same as lhs width */
619      __exec2_proc_assign(stp->st.spra.lhsx, __cur_thd->th_rhswp,
620       &(__cur_thd->th_rhswp[wlen]));
621      /* must reset and free pending saved rhs over schedule */
622      __my_free((char *) __cur_thd->th_rhswp, 2*wlen*WRDBYTES);
623      __cur_thd->th_rhswp = NULL;
624      __cur_thd->th_rhswlen = -1;
625      __cur_thd->th_rhsform = FALSE;
626      break;
627     case S_IF:
628      xsp = __eval_xpr(stp->st.sif.condx);
629      /* condition T (non zero) only if at least 1, 1 */
630      if (xsp->xslen <= WBITS)
631       {
632        /* SJM 07/20/00 - must convert to real if real */
633        if (stp->st.sif.condx->is_real)
634         {
635          double d1;
636 
637          memcpy(&d1, xsp->ap, sizeof(double));
638          tmp = (d1 != 0.0);
639         }
640        else tmp = ((xsp->ap[0] & ~xsp->bp[0]) != 0L);
641       }
642      else tmp = (__cvt_lngbool(xsp->ap, xsp->bp, wlen_(xsp->xslen)) == 1);
643      __pop_xstk();
644      if (tmp) stp = stp->st.sif.thenst;
645      else if (stp->st.sif.elsest != NULL) stp = stp->st.sif.elsest;
646      else stp = stp->stnxt;
647      goto nxt_stmt;
648     case S_CASE:
649      /* notice Verilog cases cannot fall thru */
650      if ((stp2 = exec_case(stp)) == NULL) break;
651      stp = stp2;
652      goto nxt_stmt;
653     case S_FOREVER: stp = stp->st.swh.lpst; goto nxt_stmt;
654     case S_REPSETUP:
655      /* know repeat stmt follows rep setup */
656      __num_addedexec++;
657      cntx = stp->stnxt->st.srpt.repx;
658      xsp = __eval_xpr(cntx);
659      /* SJM 04/02/02 - real count must be converted to word/int32 */
660      if (cntx->is_real) __cnv_stk_fromreal_toreg32(xsp);
661      /* SJM 12/05/04 - ### ??? FIXME - what if wide and low word good? */
662      if (xsp->xslen > WBITS) __narrow_to1wrd(xsp);
663      if (xsp->ap[1] != 0L)
664       {
665        __sgfwarn(645,
666         "repeat loop in %s count has x/z expression value - loop skipped",
667         __msg_blditree(__xs, __cur_thd->th_itp, __cur_thd->assoc_tsk));
668        val = 0;
669       }
670      else
671       {
672        /* SJM 04/02/02 - if repeat count signed and negative, never exec */
673        if (cntx->has_sign && ((int32) xsp->ap[0]) <= 0) val = 0;
674        else val = xsp->ap[0];
675       }
676      __pop_xstk();
677      /* notice count must be converted to word32 with neg set to 0 */
678      /* set to 0 so after inced here and initial repeat exec dec, */
679      stp->stnxt->st.srpt.reptemp[__inum] = ++val;
680      break;
681     case S_REPEAT:
682      if ((val = --(stp->st.srpt.reptemp[__inum])) == 0L) break;
683      stp = stp->st.srpt.repst;
684      goto nxt_stmt;
685     case S_WHILE:
686      xsp = __eval_xpr(stp->st.swh.lpx);
687      if (xsp->xslen <= WBITS)
688       {
689        /* SJM 07/20/00 - must convert to real if real */
690        if (stp->st.swh.lpx->is_real)
691         {
692          double d1;
693 
694          memcpy(&d1, xsp->ap, sizeof(double));
695          __pop_xstk();
696          /* must not emit informs from val if real */
697          if (d1 != 0.0) { stp = stp->st.swh.lpst; goto nxt_stmt; }
698          break;
699         }
700        val = xsp->bp[0];
701        if ((xsp->ap[0] & ~val) != 0L)
702         {
703          if (val != 0)
704           {
705            __sgfinform(403, "while in %s condition true but some bits x/z",
706             __msg_blditree(__xs, __cur_thd->th_itp, __cur_thd->assoc_tsk));
707           }
708          __pop_xstk();
709          stp = stp->st.swh.lpst;
710          goto nxt_stmt;
711         }
712        /* notice any 1 implies true so will not get here */
713        if (val != 0)
714         {
715          __sgfinform(402,
716           "while loop in %s terminating false condition value has x/z bits",
717           __msg_blditree(__xs, __cur_thd->th_itp, __cur_thd->assoc_tsk));
718         }
719        __pop_xstk();
720        break;
721       }
722      if ((tmp = __cvt_lngbool(xsp->ap, xsp->bp, wlen_(xsp->xslen))) == 1)
723       {
724        if (!vval_is0_(xsp->bp, xsp->xslen))
725         {
726          __sgfinform(403, "while condition in %s true but some bits x/z",
727           __msg_blditree(__xs, __cur_thd->th_itp, __cur_thd->assoc_tsk));
728         }
729        __pop_xstk();
730        stp = stp->st.swh.lpst;
731        goto nxt_stmt;
732       }
733      __pop_xstk();
734      /* notice any 1 implies true so will not get here */
735      if (tmp == 3)
736       {
737        __sgfinform(402,
738         "while loop terminating false condition in %s value has x/z bits",
739         __msg_blditree(__xs, __cur_thd->th_itp, __cur_thd->assoc_tsk));
740      }
741      break;
742     case S_WAIT:
743      /* on true expression, returns true */
744      if (exec_wait(stp)) { stp = stp->st.swait.lpst; goto nxt_stmt; }
745      /* is this unnecessary since action stmt points back to wait */
746      __cur_thd->thnxtstp = stp;
747      __stmt_suspend = TRUE;
748      return;
749     case S_FOR:
750      /* when loop done, for returns NULL as next stmt else 1st body st. */
751      forp = stp->st.sfor;
752      /* F when done */
753      if (!for_not_done(forp))
754       {
755        break;
756       }
757      stp = forp->forbody;
758      goto nxt_stmt;
759     case S_REPDCSETUP:
760      stp = exec_rep_ectl_setup(stp);
761      goto nxt_stmt;
762     case S_DELCTRL:
763      /* this returns F, for suspend, non blocking returns T */
764      /* 10/27/00 SJM - for repeat rhs ectrl count x/z <= 0 assign */
765      /* immediate so also return T */
766      if (exec_dctrl(stp)) { stp = __cur_thd->thnxtstp; goto nxt_stmt; }
767      __stmt_suspend = TRUE;
768      return;
769     case S_NAMBLK:
770      /* for function only, just continue in named block */
771      if (__fcspi >= 0) { stp = stp->st.snbtsk->tskst; goto nxt_stmt; }
772      exec_namblk(stp);
773      stp = __cur_thd->thnxtstp;
774      goto nxt_stmt;
775     case S_UNBLK:
776      stp = stp->st.sbsts;
777      goto nxt_stmt;
778     case S_UNFJ:
779      /* this is unnamed fork-join only */
780      __sched_fork(stp);
781      __cur_thd->thnxtstp = stp->stnxt;
782      __stmt_suspend = TRUE;
783      return;
784     case S_TSKCALL:
785      /* if system task, NULL will suspend, else continue in down thread */
786      if ((stp2 = __exec_tskcall(stp)) == NULL) return;
787      stp = stp2;
788      goto nxt_stmt;
789     case S_QCONTA:
790      if (stp->st.sqca->qcatyp == ASSIGN) __exec_qc_assign(stp, FALSE);
791      else
792       {
793        /* force of reg, is like assign except overrides assign */
794        if (stp->st.sqca->regform) __exec_qc_assign(stp, TRUE);
795        else __exec_qc_wireforce(stp);
796       }
797      break;
798     case S_QCONTDEA:
799      if (stp->st.sqcdea.qcdatyp == DEASSIGN) __exec_qc_deassign(stp, FALSE);
800      else
801       {
802        if (stp->st.sqcdea.regform) __exec_qc_deassign(stp, TRUE);
803        else __exec_qc_wirerelease(stp);
804       }
805      break;
806     case S_CAUSE:
807      exec_cause(stp);
808      break;
809     case S_DSABLE:
810      /* if function, disable means continue with statement after block */
811      /* if disable of func. next statement is nil, so done with func. */
812      if (__fcspi >= 0) { stp = stp->st.sdsable.func_nxtstp; goto nxt_stmt; }
813 
814      if (__exec_disable(stp->st.sdsable.dsablx)) goto thread_done;
815      /* disable elsewhere in control tree means just continue here */
816      break;
817     case S_GOTO:
818      stp = stp->st.sgoto;
819      /* notice goto of nil, ok just means done */
820      __num_addedexec++;
821      goto nxt_stmt;
822     case S_BRKPT:
823      /* returns T on need to break */
824      if (__process_brkpt(stp)) goto nxt_stmt;
825 
826      /* not a break for some reason - restore stmt type and exec 1 stmt */
827      /* if bp halt off 2nd time through after break, this execs */
828      stp->stmttyp = stp->rl_stmttyp;
829      /* execute the broken on stmt */
830      stp2 = __brktr_exec_1stmt(stp);
831      /* put back break pt. and make returned next stp as stp */
832      stp->stmttyp = S_BRKPT;
833      /* if nil will check to see if suspend or end of thread */
834      stp = stp2;
835      goto nxt_stmt;
836     default: __case_terr(__FILE__, __LINE__);
837    }
838    stp = stp->stnxt;
839 nxt_stmt:
840    if (stp == NULL) break;
841    /* entry from exec of interactive command only if ctrl c hit */
842    if (__pending_enter_iact)
843     { __stmt_suspend = TRUE; suspend_curthd(stp); return; }
844   }
845  /* when done with current function just return */
846  if (__stmt_suspend || __fcspi >= 0) return;
847 thread_done:
848  __stmt_suspend = FALSE;
849  __cur_thd->thnxtstp = NULL;
850 }
851 
852 /*
853  * tracing and break point processing version of exec statements
854  * called from thrd event processing routine and return when blocked or done
855  * execute until fall off end (thread done) or schedule wake up event
856  */
brktr_exec_stmts(register struct st_t * stp)857 static void brktr_exec_stmts(register struct st_t *stp)
858 {
859  /* notice one pass through loop executes exactly 1 statement */
860  for (;;)
861   {
862    /* here if nil returned force suspend - exec set thread next statement */
863    stp = __brktr_exec_1stmt(stp);
864    if (stp == NULL) break;
865    /* if done with thread, will detect enter iact flag in higher routine */
866    if (__pending_enter_iact)
867     { __stmt_suspend = TRUE; suspend_curthd(stp); return; }
868   }
869  if (__stmt_suspend) return;
870  __cur_thd->thnxtstp = NULL;
871 }
872 
873 /*
874  * exec statements while stepping
875  * special case if break hit in here
876  * called from thrd event processing routine and return when blocked or done
877  * execute until fall off end (thread done) or schedule wake up event
878  */
step_exec_stmt(register struct st_t * stp)879 static void step_exec_stmt(register struct st_t *stp)
880 {
881  /* notice one pass through loop executes exactly 1 statement */
882  for (;;)
883   {
884    /* if step command when iact entered from iact thread or ^c step to 1st */
885    /* of new thread not one more statement */
886    if (__step_from_thread) stp = __brktr_exec_1stmt(stp);
887    else __step_from_thread = TRUE;
888 
889    /* if hit break point while stepping, disable stepping and return */
890    /* suspend already done */
891    if (__pending_enter_iact && __iact_reason == IAER_BRKPT)
892     {
893      __single_step = FALSE;
894      __step_rep_cnt = 0;
895      __step_match_itp = NULL;
896      __verbose_step = FALSE;
897      /* since rexec stmt, must have current thread */
898      /* DBG remove --- */
899      if (stp == NULL || __cur_thd == NULL) __misc_terr(__FILE__, __LINE__);
900      /* --- */
901      __last_stepitp = __cur_thd->th_itp;
902      __last_steptskp = __cur_thd->assoc_tsk;
903      __last_stepifi = (int32) stp->stfnam_ind;
904      __step_lini = stp->stlin_cnt;
905      __step_ifi = (int32) stp->stfnam_ind;
906      /* must suspend */
907      __stmt_suspend = TRUE;
908      suspend_curthd(stp);
909      return;
910     }
911    /* must exit loop since done with this thread */
912    if (stp == NULL)
913     {
914      if (!__stmt_suspend)
915       { __step_lini = -1; __step_ifi = -1; __cur_thd->thnxtstp = NULL; }
916      return;
917     }
918 
919    /* if istep (within cur. itree inst. only) continue if different */
920    if (__step_match_itp != NULL && __inst_ptr != __step_match_itp)
921     continue;
922    /* in same instance, make sure move to next line - keep exec ing */
923    if (stp->stlin_cnt == __step_lini && (int32) stp->stfnam_ind == __step_ifi)
924     continue;
925    /* hit step point, need to enter iact */
926    break;
927   }
928  /* hit step stop know step non nil, suspend and return */
929  /* set current step line in case in loop - most move to next line */
930  __step_lini = stp->stlin_cnt;
931  __step_ifi = (int32) stp->stfnam_ind;
932  /* stepped to something to stop at */
933  if (stepped_to_new_loc(stp))
934   {
935    __last_stepitp = __inst_ptr;
936    __last_steptskp = __cur_thd->assoc_tsk;
937    __last_stepifi = (int32) stp->stfnam_ind;
938 
939     /* FIXME - is this __tr_s tracing ??? */
940    __cvsim_msg("%s (%s line %d)", __msg_blditree(__xs, __last_stepitp,
941     __last_steptskp), __in_fils[__last_stepifi], stp->stlin_cnt);
942    if (__last_brktime != __simtime)
943     {
944      __cvsim_msg(" time %s\n", __to_timstr(__xs, &__simtime));
945      __last_brktime = __simtime;
946     }
947    else __cvsim_msg("\n");
948   }
949  /* notice only change list location if print */
950  if (__verbose_step)
951   __prt_src_lines((int32) stp->stfnam_ind, stp->stlin_cnt, stp->stlin_cnt);
952  __single_step = FALSE;
953  /* if more stepping, continue using istep itp matching if needed */
954  if (__step_rep_cnt <= 1) __step_match_itp = NULL;
955  __verbose_step = FALSE;
956  suspend_curthd(stp);
957  /* even if interrupt (^c) received, doing again does not hurt */
958  signal(SIGINT, SIG_IGN);
959  /* when execing interactive command, never single stepped */
960  __pending_enter_iact = TRUE;
961  __iact_reason = IAER_STEP;
962 }
963 
964 /*
965  * return T if stepped to new scope or new file
966  */
stepped_to_new_loc(struct st_t * stp)967 static int32 stepped_to_new_loc(struct st_t *stp)
968 {
969  if (__last_stepitp != __inst_ptr
970   || __last_steptskp != __cur_thd->assoc_tsk
971   || __last_stepifi != (int32) stp->stfnam_ind
972   || __last_brktime != __simtime) return(TRUE);
973  return(FALSE);
974 }
975 
976 /*
977  * break point and tracing version of execute one statement
978  * also for executing non delay interactive statements
979  */
__brktr_exec_1stmt(struct st_t * stp)980 extern struct st_t *__brktr_exec_1stmt(struct st_t *stp)
981 {
982  register word32 val;
983  int32 tmp, wlen;
984  struct st_t *stp2;
985  struct xstk_t *xsp;
986  struct for_t *forp;
987  struct if_t *ifinfo;
988  struct expr_t *cntx;
989 
990 again:
991  /* notice must set location here - few cases where more than 1 stmt here */
992  __slin_cnt = stp->stlin_cnt;
993  __sfnam_ind = stp->stfnam_ind;
994  __num_execstmts++;
995  switch ((byte) stp->stmttyp) {
996   case S_NULL: case S_STNONE: break;
997   case S_FORASSGN:
998    xsp = __eval_assign_rhsexpr(stp->st.spra.rhsx, stp->st.spra.lhsx);
999    __exec2_proc_assign(stp->st.spra.lhsx, xsp->ap, xsp->bp);
1000    if (__st_tracing) tr_proc_assign(stp, xsp);
1001    __pop_xstk();
1002    stp = stp->stnxt;
1003    __num_addedexec++;
1004    __num_execstmts++;
1005    goto again;
1006   case S_PROCA:
1007    xsp = __eval_assign_rhsexpr(stp->st.spra.rhsx, stp->st.spra.lhsx);
1008    __exec2_proc_assign(stp->st.spra.lhsx, xsp->ap, xsp->bp);
1009    if (__st_tracing) tr_proc_assign(stp, xsp);
1010    __pop_xstk();
1011    break;
1012   case S_NBPROCA:
1013    /* only non delay form non blocking assign exec here - implied #0 */
1014    xsp = __eval_assign_rhsexpr(stp->st.spra.rhsx, stp->st.spra.lhsx);
1015    if (__st_tracing) tr_nbproc_assign(stp, xsp);
1016    sched_nbproc_delay((struct delctrl_t *) NULL, xsp, stp);
1017    __pop_xstk();
1018    break;
1019   case S_RHSDEPROCA:
1020    /* this is continuation point for rhs form after block */
1021    wlen = wlen_(stp->st.spra.lhsx->szu.xclen);
1022    __exec2_proc_assign(stp->st.spra.lhsx, __cur_thd->th_rhswp,
1023     &(__cur_thd->th_rhswp[wlen]));
1024    if (__st_tracing)
1025     {
1026      /* here delay statement already displayed */
1027      __tr_msg("trace: %-7d %s = [%s] (saved rhs assign)\n", __slin_cnt,
1028       __msgexpr_tostr(__xs, stp->st.spra.lhsx),
1029       __xregab_tostr(__xs2, __cur_thd->th_rhswp, &(__cur_thd->th_rhswp[wlen]),
1030       stp->st.spra.lhsx->szu.xclen, stp->st.spra.rhsx));
1031     }
1032    /* must reset and free pending saved rhs over schedule */
1033    __my_free((char *) __cur_thd->th_rhswp, 2*wlen*WRDBYTES);
1034    __cur_thd->th_rhswp = NULL;
1035    __cur_thd->th_rhswlen = -1;
1036    __cur_thd->th_rhsform = FALSE;
1037    break;
1038   case S_IF:
1039    ifinfo = &(stp->st.sif);
1040    xsp = __eval_xpr(ifinfo->condx);
1041    /* condition T (1) only if at least 1, 1 */
1042    if (xsp->xslen <= WBITS)
1043     {
1044      /* SJM 07/20/00 - must convert to real if real */
1045      if (ifinfo->condx->is_real)
1046       {
1047        double d1;
1048 
1049        memcpy(&d1, xsp->ap, sizeof(double));
1050        tmp = (d1 != 0.0);
1051       }
1052      else tmp = ((xsp->ap[0] & ~xsp->bp[0]) != 0L);
1053     }
1054    else tmp = (__cvt_lngbool(xsp->ap, xsp->bp, wlen_(xsp->xslen)) == 1);
1055    __pop_xstk();
1056    if (__st_tracing)
1057     __tr_msg("trace: %-7d if (%s) [cond %d]\n", __slin_cnt,
1058      __msgexpr_tostr(__xs, ifinfo->condx), tmp);
1059    if (tmp) stp = ifinfo->thenst;
1060    else if (ifinfo->elsest != NULL) stp = ifinfo->elsest;
1061    else stp = stp->stnxt;
1062    return(stp);
1063   case S_CASE:
1064    /* notice Verilog cases cannot fall thru */
1065    if ((stp2 = exec_case(stp)) == NULL) break;
1066    return(stp2);
1067   case S_FOREVER:
1068    if (__st_tracing) __tr_msg("trace: %-7d forever\n", __slin_cnt);
1069    return(stp->st.swh.lpst);
1070   case S_REPSETUP:
1071    /* know repeat stmt follows rep setup */
1072    __num_addedexec++;
1073    cntx = stp->stnxt->st.srpt.repx;
1074    xsp = __eval_xpr(cntx);
1075    /* SJM 04/02/02 - real count must be converted to word/int32 */
1076    if (cntx->is_real) __cnv_stk_fromreal_toreg32(xsp);
1077    if (xsp->xslen > WBITS) __narrow_to1wrd(xsp);
1078 
1079    if (xsp->ap[1] != 0L)
1080     {
1081      __last_stepitp = __cur_thd->th_itp;
1082      __last_steptskp = __cur_thd->assoc_tsk;
1083      __sgfwarn(645,
1084       "repeat loop in %s count has x/z expression value - loop skipped",
1085       __msg_blditree(__xs, __cur_thd->th_itp, __cur_thd->assoc_tsk));
1086      val = 0;
1087     }
1088    else
1089     {
1090      /* SJM 04/02/02 - if repeat count signed and negative, never exec */
1091      if (cntx->has_sign && ((int32) xsp->ap[0]) <= 0) val = 0;
1092      else val = xsp->ap[0];
1093     }
1094    __pop_xstk();
1095    /* notice count must be converted to word32 with neg set to 0 */
1096    stp->stnxt->st.srpt.reptemp[__inum] = ++val;
1097    break;
1098   case S_REPEAT:
1099    val = --(stp->st.srpt.reptemp[__inum]);
1100    if (__st_tracing)
1101     {
1102      __tr_msg("trace: %-7d repeat (%s) [count %u]\n", __slin_cnt,
1103       __msgexpr_tostr(__xs, stp->st.srpt.repx), val);
1104     }
1105    if (val == 0L) break;
1106    return(stp->st.srpt.repst);
1107   case S_WHILE:
1108    xsp = __eval_xpr(stp->st.swh.lpx);
1109    if (xsp->xslen <= WBITS)
1110     {
1111      if (stp->st.swh.lpx->is_real)
1112       {
1113        double d1;
1114 
1115        memcpy(&d1, xsp->ap, sizeof(double));
1116        if (d1 != 0.0) tmp = 1; else tmp = 0;
1117        goto while_end;
1118       }
1119      val = xsp->bp[0];
1120      if ((xsp->ap[0] & ~val) != 0L)
1121       {
1122        if (val != 0)
1123         {
1124          __sgfinform(403, "while in %s condition true but some bits x/z",
1125           __msg_blditree(__xs, __cur_thd->th_itp, __cur_thd->assoc_tsk));
1126         }
1127        tmp = 1;
1128        goto while_end;
1129       }
1130      /* notice any 1 implies true so will not get here */
1131      if (val != 0)
1132       {
1133         __sgfinform(402,
1134         "while loop in %s terminating false condition value has x/z bits",
1135         __msg_blditree(__xs, __cur_thd->th_itp, __cur_thd->assoc_tsk));
1136       }
1137      tmp = 0;
1138      goto while_end;
1139     }
1140    if ((tmp = __cvt_lngbool(xsp->ap, xsp->bp, wlen_(xsp->xslen))) == 1)
1141     {
1142      if (!vval_is0_(xsp->bp, xsp->xslen))
1143       {
1144        __sgfinform(403, "while in %s condition true but some bits x/z",
1145         __msg_blditree(__xs, __cur_thd->th_itp, __cur_thd->assoc_tsk));
1146       }
1147      goto while_end;
1148     }
1149    /* notice any 1 implies true so will not get here */
1150    if (tmp == 3)
1151     {
1152      __sgfinform(402,
1153       "while loop in %s terminating false condition value has x/z bits",
1154       __msg_blditree(__xs, __cur_thd->th_itp, __cur_thd->assoc_tsk));
1155     }
1156 
1157 while_end:
1158    __pop_xstk();
1159    if (__st_tracing)
1160     __tr_msg("trace: %-7d while (%s) [cond: %d]\n", __slin_cnt,
1161      __msgexpr_tostr(__xs, stp->st.swh.lpx), tmp);
1162    if (tmp == 1) return(stp->st.swh.lpst);
1163    return(stp->stnxt);
1164   case S_WAIT:
1165    /* on true expression, returns true */
1166    if (exec_wait(stp)) return(stp->st.swait.lpst);
1167    /* is this unnecessary since action stmt points back to wait */
1168    __cur_thd->thnxtstp = stp;
1169    __stmt_suspend = TRUE;
1170    return(NULL);
1171   case S_FOR:
1172    /* when loop done for returns NULL as next statement else 1st body st. */
1173    forp = stp->st.sfor;
1174    if (!for_not_done(forp))
1175     break;
1176    return(forp->forbody);
1177   case S_REPDCSETUP:
1178    /* 10/27/00 SJM - added repeat form rhs ectl and nb proca ectl setup */
1179    /* next statment is s delctrl or one after if repeat cnt x/z or <= 0 */
1180    return(exec_rep_ectl_setup(stp));
1181   case S_DELCTRL:
1182    /* this returns F, for suspend, non blocking returns T */
1183    /* 10/27/00 SJM - for repeat rhs ectrl count x/z <= 0 assign */
1184    /* immediate so also return T */
1185    if (exec_dctrl(stp)) return(__cur_thd->thnxtstp);
1186    __stmt_suspend = TRUE;
1187    return(NULL);
1188   case S_NAMBLK:
1189    /* for function only, just continue in named block */
1190    if (__fcspi >= 0)
1191     {
1192      if (__st_tracing)
1193       {
1194        __tr_msg("trace: %-7d begin : %s\n", __slin_cnt,
1195         stp->st.snbtsk->tsksyp->synam);
1196       }
1197      return(stp->st.snbtsk->tskst);
1198     }
1199    /* know this is new down thread - know at least 1 statement */
1200    exec_namblk(stp);
1201    return(__cur_thd->thnxtstp);
1202   case S_UNBLK:
1203    if (__st_tracing) __tr_msg("trace: %-7d begin\n", __slin_cnt);
1204    return(stp->st.sbsts);
1205   case S_UNFJ:
1206    /* this is unnamed fork-join only */
1207    if (__st_tracing) __tr_msg("trace: %-7d fork\n", __slin_cnt);
1208    __sched_fork(stp);
1209    __cur_thd->thnxtstp = stp->stnxt;
1210    __stmt_suspend = TRUE;
1211    return(NULL);
1212   case S_TSKCALL:
1213    /* if system task, NULL will suspend, else continue in down thread */
1214    if ((stp2 = __exec_tskcall(stp)) == NULL) return(NULL);
1215    return(stp2);
1216   case S_QCONTA:
1217    if (stp->st.sqca->qcatyp == ASSIGN) __exec_qc_assign(stp, FALSE);
1218    else
1219     {
1220      /* force of reg, is like assign except overrides assign */
1221      if (stp->st.sqca->regform) __exec_qc_assign(stp, TRUE);
1222      else __exec_qc_wireforce(stp);
1223     }
1224    if (__st_tracing)
1225     {
1226      char s1[RECLEN], s2[RECLEN];
1227 
1228      strcpy(s2, "");
1229      if (stp->st.sqca->qcatyp == ASSIGN)
1230       {
1231        strcpy(s1, "assign");
1232        if (__force_active) strcpy(s2, " [active force effect hidden]");
1233       }
1234      else
1235       {
1236        strcpy(s1, "force");
1237        if (__assign_active) strcpy(s2, " [assign value saved]");
1238       }
1239      __tr_msg("trace: %-7d %s %s = %s%s\n", __slin_cnt, s1,
1240       __msgexpr_tostr(__xs, stp->st.sqca->qclhsx),
1241       __msgexpr_tostr(__xs2, stp->st.sqca->qcrhsx), s2);
1242     }
1243    /* --- DBG remove
1244    __dmpmod_nplst(__inst_mod, TRUE);
1245    --- */
1246    __force_active = FALSE;
1247    __assign_active = FALSE;
1248    break;
1249   case S_QCONTDEA:
1250    if (stp->st.sqcdea.qcdatyp == DEASSIGN) __exec_qc_deassign(stp, FALSE);
1251    else
1252     {
1253      if (stp->st.sqcdea.regform) __exec_qc_deassign(stp, TRUE);
1254      else __exec_qc_wirerelease(stp);
1255     }
1256 
1257    if (__st_tracing)
1258     {
1259      char s1[RECLEN], s2[RECLEN];
1260 
1261      strcpy(s2, "");
1262      if (stp->st.sqcdea.qcdatyp == DEASSIGN)
1263       {
1264        strcpy(s1, "deassign");
1265        if (__force_active) strcpy(s2, " [active force effect hidden]");
1266       }
1267      else
1268       {
1269        strcpy(s1, "release");
1270        if (__assign_active) strcpy(s2, " [assign value restored]");
1271       }
1272      __tr_msg("trace: %-7d %s %s%s\n", __slin_cnt, s1,
1273       __msgexpr_tostr(__xs, stp->st.sqcdea.qcdalhs), s2);
1274     }
1275    __force_active = FALSE;
1276    __assign_active = FALSE;
1277    break;
1278   case S_CAUSE:
1279    exec_cause(stp);
1280    break;
1281   case S_DSABLE:
1282    if (__st_tracing)
1283     {
1284      __tr_msg("trace: %-7d disable %s;\n", __slin_cnt,
1285       __msgexpr_tostr(__xs, stp->st.sdsable.dsablx));
1286     }
1287    /* if function, disable means continue with statement after block */
1288    if (__fcspi >= 0) return(stp->st.sdsable.func_nxtstp);
1289 
1290    /* here - done - suspend off so nil will end thread */
1291    /* xmr disable will mark some thread and return F */
1292    if (__exec_disable(stp->st.sdsable.dsablx)) return(NULL);
1293    break;
1294   case S_GOTO:
1295    stp = stp->st.sgoto;
1296    /* debug to nil ok, just end of list */
1297    __num_addedexec++;
1298    if (__st_tracing)
1299     __tr_msg("trace: %-7d --continue %s\n", __slin_cnt,
1300      __bld_lineloc(__xs, stp->stfnam_ind, stp->stlin_cnt));
1301    __num_execstmts++;
1302    return(stp);
1303   /* do not trace break during break - may trace when execed */
1304   case S_BRKPT:
1305    /* returns T on need to break */
1306    if (__process_brkpt(stp)) return(stp);
1307 
1308    /* not a break for some reason - restore stmt type and exec 1 stmt */
1309    /* if bp halt off 2nd time through after break, this execs */
1310    stp->stmttyp = stp->rl_stmttyp;
1311    stp2 = __brktr_exec_1stmt(stp);
1312    stp->stmttyp = S_BRKPT;
1313    return(stp2);
1314   default: __case_terr(__FILE__, __LINE__);
1315  }
1316  return(stp->stnxt);
1317 }
1318 
1319 /*
1320  * evaluate an procedural assign rhs expression and convert to form
1321  * needed for assignment
1322  * handles real conversion and size changes - never z widening
1323  * know returned stack width always exactly matches lhs width
1324  */
__eval_assign_rhsexpr(register struct expr_t * xrhs,register struct expr_t * xlhs)1325 extern struct xstk_t *__eval_assign_rhsexpr(register struct expr_t *xrhs,
1326  register struct expr_t *xlhs)
1327 {
1328  register struct xstk_t *xsp;
1329 
1330  xsp = __eval_xpr(xrhs);
1331  if (xlhs->is_real)
1332   {
1333    /* needed: think passing packed bit does not work on all compilers ? */
1334    if (!xrhs->is_real) __cnv_stk_fromreg_toreal(xsp, (xrhs->has_sign == 1));
1335   }
1336  else
1337   {
1338    /* handle rhs preparation of reals - then assign is just copy for reals */
1339    if (xrhs->is_real) __cnv_stk_fromreal_toreg32(xsp);
1340 
1341    /* SJM 09/29/03 - change to handle sign extension and separate types */
1342    if (xsp->xslen > xlhs->szu.xclen) __narrow_sizchg(xsp, xlhs->szu.xclen);
1343    else if (xsp->xslen < xlhs->szu.xclen)
1344     {
1345      if (xrhs->has_sign) __sgn_xtnd_widen(xsp, xlhs->szu.xclen);
1346      else __sizchg_widen(xsp, xlhs->szu.xclen);
1347     }
1348   }
1349  return(xsp);
1350 }
1351 
1352 /*
1353  * evaulate task assign - only different if form of various flags
1354  */
eval_tskassign_rhsexpr(register struct xstk_t * xsp,register int32 lhsreal,register int32 lhswid,register int32 rhsreal,register int32 rhssign)1355 static void eval_tskassign_rhsexpr(register struct xstk_t *xsp,
1356  register int32 lhsreal, register int32 lhswid, register int32 rhsreal,
1357  register int32 rhssign)
1358 {
1359  if (lhsreal)
1360   {
1361    /* think passing packed bit does not work on all compilers ? */
1362    if (!rhsreal) __cnv_stk_fromreg_toreal(xsp, rhssign);
1363   }
1364  else
1365   {
1366    /* handle rhs preparation of reals - then assign is just copy for reals */
1367    if (rhsreal) __cnv_stk_fromreal_toreg32(xsp);
1368 
1369    if (xsp->xslen > lhswid) __narrow_sizchg(xsp, lhswid);
1370    else if (xsp->xslen < lhswid)
1371     {
1372      if (rhssign) __sgn_xtnd_widen(xsp, lhswid);
1373      else __sizchg_widen(xsp, lhswid);
1374     }
1375   }
1376 }
1377 
1378 /*
1379  * trace an assignment statement
1380  * notice this expects rhs value to be on top of stack (caller pops)
1381  *
1382  * ok to use rgab_tostr here since know __exprline can not be in use before
1383  * statement execution begins
1384  */
tr_proc_assign(struct st_t * stp,struct xstk_t * xsp)1385 static void tr_proc_assign(struct st_t *stp, struct xstk_t *xsp)
1386 {
1387  struct expr_t *xrhs;
1388 
1389  __cur_sofs = 0;
1390  __dmp_proc_assgn((FILE *) NULL, stp, (struct delctrl_t *) NULL, FALSE);
1391  __exprline[__cur_sofs] = 0;
1392  __trunc_exprline(TRTRUNCLEN, FALSE);
1393  __tr_msg("trace: %-7d %s", __slin_cnt, __exprline);
1394  xrhs = stp->st.spra.rhsx;
1395  /* if rhs is number value is obvious, else print value that was assigned */
1396  /* any conversion to lhs already made so expr. info from lhs */
1397  if (xrhs->optyp != NUMBER && xrhs->optyp != REALNUM)
1398   {
1399    __tr_msg(" [%s]\n", __xregab_tostr(__xs, xsp->ap, xsp->bp, xsp->xslen,
1400     stp->st.spra.lhsx));
1401   }
1402  else __tr_msg("\n");
1403  __cur_sofs = 0;
1404 }
1405 
1406 /*
1407  * trace an non blocking assignment statement
1408  * notice this expects rhs value to be on top of stack (caller pops)
1409  *
1410  * ok to use rgab_tostr here since know __exprline can not be in use before
1411  * statement execution begins
1412  */
tr_nbproc_assign(struct st_t * stp,struct xstk_t * xsp)1413 static void tr_nbproc_assign(struct st_t *stp, struct xstk_t *xsp)
1414 {
1415  struct expr_t *xrhs;
1416 
1417  __cur_sofs = 0;
1418  __dmp_nbproc_assgn((FILE *) NULL, stp, (struct delctrl_t *) NULL);
1419  __exprline[__cur_sofs] = 0;
1420  __trunc_exprline(TRTRUNCLEN, FALSE);
1421  __tr_msg("trace: %-7d %s", __slin_cnt, __exprline);
1422  xrhs = stp->st.spra.rhsx;
1423  if (xrhs->optyp != NUMBER && xrhs->optyp != REALNUM)
1424   {
1425    __tr_msg(" [%s]\n", __xregab_tostr(__xs, xsp->ap, xsp->bp,
1426     xsp->xslen, xrhs));
1427   }
1428  else __tr_msg("\n");
1429  __cur_sofs = 0;
1430 }
1431 
1432 /*
1433  * execute repeat event setup (rhs nb ectl proca or rhs ectl delay
1434  * know rhs DEL CTRL stmt with repeat form rhs ev control follows
1435  * only can be rhs ev control or rhs non blocking assign ev ctrl
1436  */
exec_rep_ectl_setup(struct st_t * stp)1437 static struct st_t *exec_rep_ectl_setup(struct st_t *stp)
1438 {
1439  register struct xstk_t *xsp;
1440  register struct st_t *nxtstp, *astp;
1441  struct delctrl_t *rdctp;
1442  word32 val;
1443 
1444  __num_addedexec++;
1445  nxtstp = stp->stnxt;
1446  /* DBG RELEASE remove --- */
1447  if (nxtstp->stmttyp != S_DELCTRL) __misc_terr(__FILE__, __LINE__);
1448  /* --- */
1449  rdctp = nxtstp->st.sdc;
1450  xsp = __eval_xpr(rdctp->repcntx);
1451  /* SJM 04/02/02 - real count must be converted to word/int32 */
1452  if (rdctp->repcntx->is_real) __cnv_stk_fromreal_toreg32(xsp);
1453 
1454  /* FIXME ??? - although know WBITS wide, should use bp here */
1455  if (xsp->ap[1] != 0L)
1456   {
1457    __sgfwarn(645,
1458     "repeat event control in %s count has x/z value - no wait for event",
1459     __msg_blditree(__xs, __cur_thd->th_itp, __cur_thd->assoc_tsk));
1460    __pop_xstk();
1461 
1462 immed_ectl_exec:
1463    astp = nxtstp->st.sdc->actionst;
1464    xsp = __eval_assign_rhsexpr(astp->st.spra.rhsx, astp->st.spra.lhsx);
1465    if (astp->stmttyp == S_NBPROCA)
1466     {
1467      /* case 1: NB assign - becomes no delay NB assign form */
1468      sched_nbproc_delay(NULL, xsp, astp);
1469     }
1470    else
1471     {
1472      /* case 2: rhs repeat event control - treat as simple proca */
1473      __exec2_proc_assign(astp->st.spra.lhsx, xsp->ap, xsp->bp);
1474     }
1475    __pop_xstk();
1476    /* continuation statment is one after S DELCTRL since no ev ctrl */
1477    /* in this case */
1478    return(nxtstp->stnxt);
1479   }
1480  /* if signed and <= 0, or word32 equal to 0, becomes immediate assign */
1481  /* SJM 04/02/02 - need to use word32 counter and convert neg to 0 */
1482  if (rdctp->repcntx->has_sign && (int32) xsp->ap[0] <= 0) val = 0;
1483  else val = xsp->ap[0];
1484  __pop_xstk();
1485  if (val == 0) goto immed_ectl_exec;
1486 
1487  /* val now number of edges (if 1 same as normal rhs ectrl */
1488  /* notice, here never exec unless at least one so do not need inc */
1489  rdctp->dce_repcnts[__inum] = val;
1490  return(nxtstp);
1491 }
1492 
1493 /*
1494  * execute a delay control indicator
1495  * notice this arms or schedules something - caller suspends thread
1496  * this return T if non blocking assign needs to not schedule
1497  */
exec_dctrl(struct st_t * stp)1498 static int32 exec_dctrl(struct st_t *stp)
1499 {
1500  int32 bytes, wlen;
1501  word32 *wp;
1502  struct delctrl_t *dctp;
1503  struct xstk_t *xsp;
1504  struct st_t *astp;
1505 
1506  dctp = stp->st.sdc;
1507  if (__st_tracing)
1508   {
1509    __evtr_resume_msg();
1510    __cur_sofs = 0;
1511    if (dctp->actionst == NULL || dctp->dctyp == DC_RHSEVENT
1512     || dctp->dctyp == DC_RHSDELAY) __dmp_dctrl((FILE *) NULL, dctp);
1513    else
1514     {
1515      if (dctp->dctyp == DC_EVENT) addch_('@'); else addch_('#');
1516      __dmp_dcxpr((FILE *) NULL, dctp->dc_du, dctp->dc_delrep);
1517     }
1518    __trunc_exprline(TRTRUNCLEN, FALSE);
1519    __tr_msg("trace: %-7d %s\n", __slin_cnt, __exprline);
1520    __cur_sofs = 0;
1521   }
1522  /* for all but non blocking assign block - continue with action statement */
1523  if (dctp->actionst == NULL) __cur_thd->thnxtstp = stp->stnxt;
1524  else __cur_thd->thnxtstp = dctp->actionst;
1525 
1526  switch ((byte) dctp->dctyp) {
1527   case DC_DELAY:
1528    sched_proc_delay(dctp, (word32 *) NULL, -1);
1529    break;
1530   case DC_EVENT:
1531    arm_event_dctrl(dctp, (word32 *) NULL, -1);
1532    break;
1533   case DC_RHSDELAY: case DC_RHSEVENT:
1534    /* 10/28/00 SJM - only rhs event either blocking or non blocking */
1535    /* can have repeat form */
1536    astp = dctp->actionst;
1537    /* rhs # delay or event ctrl */
1538    /* -- DBG remove
1539    if (astp == NULL || (astp->stmttyp != S_RHSDEPROCA
1540     && astp->stmttyp != S_NBPROCA)) __arg_terr(__FILE__, __LINE__);
1541    --- */
1542 
1543    /* evaluate rhs and schedule as usual */
1544    /* notice this depends on contiguous xsp a and b parts */
1545    xsp = __eval_assign_rhsexpr(astp->st.spra.rhsx, astp->st.spra.lhsx);
1546 
1547    if (astp->stmttyp == S_NBPROCA)
1548     {
1549      /* for non blocking assign - must not exec assign - event processing */
1550      /* routine does that, must continue after actionst if can else nxt */
1551      if (dctp->actionst != NULL && dctp->actionst->stnxt != NULL)
1552       __cur_thd->thnxtstp = dctp->actionst->stnxt;
1553      else __cur_thd->thnxtstp = stp->stnxt;
1554 
1555      if (dctp->dctyp == DC_RHSDELAY) sched_nbproc_delay(dctp, xsp, astp);
1556      else arm_nbevent_dctrl(dctp, xsp, astp);
1557      __pop_xstk();
1558      return(TRUE);
1559     }
1560    /* continuation point for rhs delay form is action statement if exists */
1561    /* that is same as normal delay control */
1562 
1563    /* if blocking allocate and store - no inertial problems for blocking */
1564    /* SJM - 01/12/00 - wlen_ omitted so here was large memory leak */
1565    /*                  was only freeing 4/32 percent of bytes */
1566    wlen = wlen_(astp->st.spra.lhsx->szu.xclen);
1567    bytes = 2*WRDBYTES*wlen;
1568 
1569    wp = (word32 *) __my_malloc(bytes);
1570    memcpy(wp, xsp->ap, bytes);
1571 
1572    if (dctp->dctyp == DC_RHSDELAY) sched_proc_delay(dctp, wp, wlen);
1573    else arm_event_dctrl(dctp, wp, wlen);
1574    __pop_xstk();
1575    break;
1576   default: __case_terr(__FILE__, __LINE__);
1577  }
1578  return(FALSE);
1579 }
1580 
1581 /*
1582  * schedule procedural delay thread simple prefix timing delay
1583  *
1584  * must continue after wake up with same thread (contents?)
1585  * before call statement set to statement to exec after wake up
1586  * also handles rhs delay form
1587  *
1588  * notice on disable event canceled and any rhs value free but that is
1589  * all that is needed
1590  */
sched_proc_delay(struct delctrl_t * dctp,word32 * wp,int32 wlen)1591 static void sched_proc_delay(struct delctrl_t *dctp, word32 *wp, int32 wlen)
1592 {
1593  register i_tev_ndx tevpi;
1594  register struct tev_t *tevp;
1595  word64 t, schtim;
1596  struct st_t *stp;
1597 
1598  /* this can not be edge delay or syntax error before here */
1599  __get_del(&t, dctp->dc_du, dctp->dc_delrep);
1600  schtim = __simtime + t;
1601  alloc_tev_(tevpi, TE_THRD, __inst_ptr, schtim);
1602  /* set the associate event - after return, __cur_thd will be new */
1603  __cur_thd->thdtevi = tevpi;
1604  /* restart current - will block after here and change threads */
1605  tevp = &(__tevtab[tevpi]);
1606  tevp->tu.tethrd = __cur_thd;
1607  /* if rhs delay form, set values */
1608  if (wp != NULL)
1609   {
1610    __cur_thd->th_rhsform = TRUE;
1611    __cur_thd->th_rhswp = wp;
1612    __cur_thd->th_rhswlen = wlen;
1613   }
1614 
1615  if (__ev_tracing)
1616   {
1617    char s1[RECLEN], vs2[10];
1618 
1619    __evtr_resume_msg();
1620    if (wp == NULL) strcpy(vs2, ""); else strcpy(vs2, "(rhs)");
1621    stp = tevp->tu.tethrd->thnxtstp;
1622    __tr_msg("-- scheduling delay resume%s at %s for time %s\n",
1623     vs2, __bld_lineloc(s1, stp->stfnam_ind, stp->stlin_cnt),
1624     __to_timstr(__xs, &(tevp->etime)));
1625   }
1626  /* notice that procedural #0 (does not need to be rhs assign form) */
1627  /* done after all normal events */
1628  if (t == 0ULL)
1629   {
1630    if (__debug_flg && __ev_tracing)
1631     {
1632      __tr_msg("sched: adding #0 %s event to list end\n",
1633       __to_tetyp(__xs, tevp->tetyp));
1634     }
1635    /* notice pound 0 only added from current time events */
1636    if (__p0_te_hdri == -1) __p0_te_hdri = __p0_te_endi = tevpi;
1637    else { __tevtab[__p0_te_endi].tenxti = tevpi; __p0_te_endi = tevpi; }
1638   }
1639  /* if non blocking procedural assign, insert in normal moved to #0 later */
1640  else __insert_event(tevpi);
1641 }
1642 
1643 /*
1644  * schedule non blocking procedural assign simple prefix timing delay
1645  *
1646  * this is simple because of strange non hardware related semantics
1647  * every time a non blocking delay assigned is executed, just compute
1648  * delay and schedule - can have >1 events per unit or per statement
1649  * but just schedule and forget
1650  */
sched_nbproc_delay(struct delctrl_t * dctp,struct xstk_t * xsp,struct st_t * stp)1651 static void sched_nbproc_delay(struct delctrl_t *dctp, struct xstk_t *xsp,
1652  struct st_t *stp)
1653 {
1654  i_tev_ndx tevpi;
1655  word64 t, schtim;
1656 
1657  /* if no delay form, schedule at end of currnt time #0s */
1658  if (dctp == NULL) t = 0ULL;
1659  /* error before here if edge dependent delay */
1660  else __get_del(&t, dctp->dc_du, dctp->dc_delrep);
1661  schtim = __simtime + t;
1662 
1663  if (__ev_tracing)
1664   {
1665    char s1[RECLEN], s2[RECLEN], s3[RECLEN];
1666 
1667    __evtr_resume_msg();
1668    __tr_msg(
1669     "-- scheduling delay form non blocking assign line %s now %s in %s:\n",
1670     __bld_lineloc(s1, stp->stfnam_ind, stp->stlin_cnt),
1671     __to_timstr(s2, &__simtime), __msg2_blditree(s3, __inst_ptr));
1672    __tr_msg(" NB SCHEDULE TO NEW VALUE %s AT TIME %s\n",
1673     __xregab_tostr(s1, xsp->ap, xsp->bp, stp->st.spra.rhsx->szu.xclen,
1674      stp->st.spra.rhsx), __to_timstr(s2, &schtim));
1675   }
1676 
1677  /* build the disable remove list for possibly multiple active nb forms */
1678  tevpi = __bld_nb_tev(stp, xsp, schtim);
1679  /* final step is inserting event in list */
1680  /* no dleay form becomes #0 schedule for assign event here */
1681  if (t == 0ULL)
1682   {
1683    if (__debug_flg && __ev_tracing)
1684     {
1685      __tr_msg("sched: adding #0 %s event to list end\n",
1686       __to_tetyp(__xs, __tevtab[tevpi].tetyp));
1687     }
1688    /* notice pound 0 only added for current time events */
1689    /* AIV 06/28/05 - if option not set add to the end of the nb #0 list */
1690    if (!__nb_sep_queue)
1691     {
1692      if (__p0_te_hdri == -1) __p0_te_hdri = __p0_te_endi = tevpi;
1693      else { __tevtab[__p0_te_endi].tenxti = tevpi; __p0_te_endi = tevpi; }
1694     }
1695    else
1696     {
1697      /* AIV 07/05/05 - to match XL need nb te list that only processed */
1698      /* when all pnd 0s done */
1699      /* effectively adds another section to current time event queue */
1700      if (__nb_te_hdri == -1) __nb_te_hdri = __nb_te_endi = tevpi;
1701      else { __tevtab[__nb_te_endi].tenxti = tevpi; __nb_te_endi = tevpi; }
1702     }
1703   }
1704  /* if non blocking procedural assign, insert in normal moved to #0 later */
1705  else __insert_event(tevpi);
1706 }
1707 
1708 /*
1709  * build and emit trace message for non blocking schedule or trigger
1710  * notice these are not inertial - just keep scheduling
1711  * never cancel or re-schedule
1712  *
1713  * SJM 08/08/99 - change so if lhs expr (maybe concat) has non constant
1714  * bit selects copy and then evaluate variable indices to numbers
1715  * and change copied expr.
1716  *
1717  * BEWARE - code here and in many places assumes numeric expressions
1718  * folded to number or IS number by here
1719  */
__bld_nb_tev(struct st_t * stp,struct xstk_t * xsp,word64 schtim)1720 extern i_tev_ndx __bld_nb_tev(struct st_t *stp, struct xstk_t *xsp,
1721  word64 schtim)
1722 {
1723  register struct tenbpa_t *nbpap;
1724  register word32 *wp;
1725  i_tev_ndx tevpi;
1726  int32 wlen;
1727  struct expr_t *lhsxp;
1728 
1729  alloc_tev_(tevpi, TE_NBPA, __inst_ptr, schtim);
1730  nbpap = (struct tenbpa_t *) __my_malloc(sizeof(struct tenbpa_t));
1731  __tevtab[tevpi].tu.tenbpa = nbpap;
1732  wlen = wlen_(stp->st.spra.lhsx->szu.xclen);
1733  wp = (word32 *) __my_malloc(2*wlen*WRDBYTES);
1734 
1735  memcpy(wp, xsp->ap, 2*wlen*WRDBYTES);
1736 
1737  nbpap->nbawp = wp;
1738  nbpap->nbastp = stp;
1739 
1740  /* copy expr. if needed */
1741  /* BEWARE - code in many places assumes numeric expressions folded to */
1742  /* number or IS number by here */
1743  if (!__lhsexpr_var_ndx(stp->st.spra.lhsx)) nbpap->nblhsxp = NULL;
1744  else
1745   {
1746    /* notice - know will have same width as stp lhsx */
1747    lhsxp = __sim_copy_expr(stp->st.spra.lhsx);
1748    __eval_lhsexpr_var_ndxes(lhsxp);
1749    nbpap->nblhsxp = lhsxp;
1750   }
1751  /* caller sets dctp if needed */
1752  nbpap->nbdctp = NULL;
1753  return(tevpi);
1754 }
1755 
1756 /*
1757  * return T if expression contains non constant bit select index
1758  *
1759  * this assume only one level concats but maybe should
1760  */
__lhsexpr_var_ndx(register struct expr_t * xp)1761 extern int32 __lhsexpr_var_ndx(register struct expr_t *xp)
1762 {
1763  switch ((byte) xp->optyp) {
1764   case GLBREF: case ID:
1765    break;
1766   case PARTSEL:
1767    /* part select always constant */
1768    break;
1769   case LSB:
1770    if (xp->ru.x->optyp == NUMBER || xp->ru.x->optyp == ISNUMBER) break;
1771    return(TRUE);
1772   case LCB:
1773    {
1774     register struct expr_t *catxp;
1775 
1776     for (catxp = xp->ru.x; catxp != NULL; catxp = catxp->ru.x)
1777      {
1778       /* if var index must copy entire expr. */
1779       if (__lhsexpr_var_ndx(catxp->lu.x)) return(TRUE);
1780      }
1781    }
1782    break;
1783   default: __case_terr(__FILE__, __LINE__);
1784  }
1785  return(FALSE);
1786 }
1787 
1788 /*
1789  * evaluate any variable indices to constants
1790  *
1791  * this is guts of LRM non-blocking assign algorithm - for any variable
1792  * bit index eval and convert to constant
1793  *
1794  * this mangles expr but since copied and free when non blocking assign
1795  * done still works
1796  *
1797  * assumes only one level concats but maybe should
1798  */
__eval_lhsexpr_var_ndxes(register struct expr_t * xp)1799 extern void __eval_lhsexpr_var_ndxes(register struct expr_t *xp)
1800 {
1801  int32 biti;
1802  struct expr_t *idndp;
1803  struct net_t *np;
1804  struct expr_t *ndx;
1805 
1806  switch ((byte) xp->optyp) {
1807   case GLBREF: case ID: break;
1808   case PARTSEL:
1809    /* part select always constant */
1810    break;
1811   case LSB:
1812    if (xp->ru.x->optyp != NUMBER && xp->ru.x->optyp != ISNUMBER)
1813     {
1814      idndp = xp->lu.x;
1815      np = idndp->lu.sy->el.enp;
1816      /* can be either constant or expr. - both handled in comp. */
1817      biti = __comp_ndx(np, xp->ru.x);
1818      /* out of range is x as index */
1819      if (biti == -1) ndx = __bld_rng_numxpr(ALL1W, ALL1W, WBITS);
1820      else ndx = __bld_rng_numxpr((word32) biti, 0, WBITS);
1821      __free_xtree(xp->ru.x);
1822      xp->ru.x = ndx;
1823     }
1824    /* if constant (even IS) index, nothing to do */
1825    break;
1826   case LCB:
1827    {
1828     register struct expr_t *catxp;
1829 
1830     for (catxp = xp->ru.x; catxp != NULL; catxp = catxp->ru.x)
1831      {
1832       /* if var index must copy entire expr. */
1833       __eval_lhsexpr_var_ndxes(catxp->lu.x);
1834      }
1835    }
1836    break;
1837   default: __case_terr(__FILE__, __LINE__);
1838  }
1839 }
1840 
1841 /*
1842  * arm an event delay control - know already set up
1843  * know current thread set to continuation point here
1844  * know current thread will be blocked waiting for this 1 event
1845  *
1846  * notice may be triggered from other thread (init/always) in same inst.
1847  * but continuation is here
1848  * here arming ref. instance even though only change of target wire will
1849  * trigger for xmr or col. case
1850  */
arm_event_dctrl(struct delctrl_t * dctp,register word32 * wp,int32 wlen)1851 static void arm_event_dctrl(struct delctrl_t *dctp, register word32 *wp,
1852  int32 wlen)
1853 {
1854  register i_tev_ndx tevpi;
1855  struct tev_t *tevp;
1856  struct st_t *stp;
1857 
1858  /* build after trigger fires, startup event */
1859  /* notice this event record is not linked onto any event list for now */
1860  alloc_tev_(tevpi, TE_THRD, __inst_ptr, __simtime);
1861  /* link event back to thread */
1862  __cur_thd->thdtevi = tevpi;
1863  tevp = &(__tevtab[tevpi]);
1864  tevp->tu.tethrd = __cur_thd;
1865 
1866  /* if rhs delay form, set values */
1867  if (wp != NULL)
1868   {
1869    __cur_thd->th_rhsform = TRUE;
1870    __cur_thd->th_rhswp = wp;
1871    __cur_thd->th_rhswlen = wlen;
1872   }
1873 
1874  if (__debug_flg && __st_tracing)
1875   {
1876    stp = tevp->tu.tethrd->thnxtstp;
1877    __tr_msg("-- arming event thread %s itree loc. %s statement at %s\n",
1878     __cur_thd->th_itp->itip->isym->synam, __inst_ptr->itip->isym->synam,
1879     __bld_lineloc(__xs, stp->stfnam_ind, stp->stlin_cnt));
1880   }
1881  /* RELEASE remove --
1882  if (__debug_flg)
1883   __dmp_dcemsg(dctp, "setting dce to event");
1884  --- */
1885 
1886  /* if rexecuting task, algorithm is to cancel previous pending */
1887  /* delay control and emit warning */
1888  if (dctp->dceschd_tevs[__inum] != -1)
1889   {
1890    if (__cur_thd->assoc_tsk == NULL)
1891     {
1892      stp = tevp->tu.tethrd->thnxtstp;
1893      __sgfwarn(635,
1894       "INTERNAL BUG? - in %s cancel and rearm of event control to resume at %s",
1895       __msg2_blditree(__xs, __inst_ptr), __bld_lineloc(__xs2, stp->stfnam_ind,
1896       stp->stlin_cnt));
1897     }
1898    else
1899     {
1900      stp = tevp->tu.tethrd->thnxtstp;
1901      __sgfwarn(635,
1902       "when reexecuting task %s cancel and rearm of event control to resume at %s",
1903       __msg_blditree(__xs, __inst_ptr, __cur_thd->assoc_tsk),
1904       __bld_lineloc(__xs2, stp->stfnam_ind, stp->stlin_cnt));
1905     }
1906   }
1907 
1908  /* DBG remove -- */
1909  if (__cur_thd->th_dctp != NULL) __misc_terr(__FILE__, __LINE__);
1910  /* --- */
1911 
1912  /* notice simply linking event on the scheduled list enables the ev ctrl */
1913  dctp->dceschd_tevs[__inum] = tevpi;
1914  __cur_thd->th_dctp = dctp;
1915  /* handle any tracing */
1916  if (__ev_tracing)
1917   {
1918    char vs2[10];
1919 
1920    stp = tevp->tu.tethrd->thnxtstp;
1921    if (wp == NULL) strcpy(vs2, ""); else strcpy(vs2, "(rhs)");
1922    __tr_msg("-- event control suspend%s to resume line %s\n",
1923     vs2, __bld_lineloc(__xs, stp->stfnam_ind, stp->stlin_cnt));
1924   }
1925 }
1926 
1927 /*
1928  * print a dctp message for debugging
1929  */
__dmp_dcemsg(struct delctrl_t * dctp,char * dcemsg)1930 extern void __dmp_dcemsg(struct delctrl_t *dctp, char *dcemsg)
1931 {
1932  char s1[RECLEN];
1933 
1934  if (dctp->actionst != NULL)
1935   __bld_lineloc(s1, dctp->actionst->stfnam_ind, dctp->actionst->stlin_cnt);
1936  else strcpy(s1, "<none>");
1937  __dbg_msg("%s: at %p of type %s instance %d(%s) iact=%d stmt. %s\n", dcemsg,
1938   dctp, __to_dcenam(__xs, dctp->dctyp), __inum,
1939   __msg2_blditree(__xs2, __inst_ptr), dctp->dc_iact, s1);
1940 }
1941 
1942 /*
1943  * arm a non blocking assign delay control
1944  *
1945  * multiple allowed just add each new tev to end
1946  * LOOKATME - notice current scheme requires linear traversal to list end.
1947  */
arm_nbevent_dctrl(struct delctrl_t * dctp,struct xstk_t * xsp,struct st_t * stp)1948 static void arm_nbevent_dctrl(struct delctrl_t *dctp, struct xstk_t *xsp,
1949  struct st_t *stp)
1950 {
1951  register i_tev_ndx tevp2i;
1952  i_tev_ndx tevpi;
1953  struct tev_t *tevp;
1954  char s1[RECLEN], s2[RECLEN], s3[RECLEN];
1955 
1956  /* DBG remove -- */
1957  if (__ev_tracing)
1958   {
1959    __evtr_resume_msg();
1960     __tr_msg(
1961      "-- arming event control non blocking assign line %s now %s in %s:\n",
1962      __bld_lineloc(s1, stp->stfnam_ind, stp->stlin_cnt),
1963      __to_timstr(s3, &__simtime), __msg2_blditree(s2, __inst_ptr));
1964 
1965    __tr_msg("   EVENT TRIGGER ARM NEW VALUE %s\n",
1966     __xregab_tostr(s1, xsp->ap, xsp->bp, stp->st.spra.lhsx->szu.xclen,
1967     stp->st.spra.rhsx));
1968   }
1969  /* --- */
1970  tevpi = __bld_nb_tev(stp, xsp, __simtime);
1971  tevp = &(__tevtab[tevpi]);
1972  tevp->nb_evctrl = TRUE;
1973  /* for event control form need to set dctp field */
1974  tevp->tu.tenbpa->nbdctp = dctp;
1975  if ((tevp2i = dctp->dceschd_tevs[__inum]) != -1)
1976   {
1977    /* could save end pointer if too slow ? */
1978    for (; __tevtab[tevp2i].tenxti != -1; tevp2i = __tevtab[tevp2i].tenxti) ;
1979    __tevtab[tevp2i].tenxti = tevpi;
1980    /* ??? LOOKATME is this needed */
1981    __tevtab[tevpi].tenxti = -1;
1982   }
1983  else dctp->dceschd_tevs[__inum] = tevpi;
1984 }
1985 
1986 /*
1987  * execute a simple (not casex and casez) case statement
1988  */
exec_case(struct st_t * stp)1989 static struct st_t *exec_case(struct st_t *stp)
1990 {
1991  register word32 aw, bw;
1992  register struct xstk_t *itemxsp;
1993  register struct exprlst_t *xplp;
1994  register struct csitem_t *csip;
1995  int32 selxlen, selwlen, i;
1996  struct xstk_t *selxsp;
1997  struct csitem_t *dflt_csip;
1998 
1999  /* SJM 12/12/03 - must treat all 3 case types as special case if any */
2000  /* of select or case item exprs real */
2001  if (stp->st.scs.csx->is_real || stp->st.scs.csx->cnvt_to_real)
2002   {
2003    return(exec_real_case(stp));
2004   }
2005 
2006  if (stp->st.scs.castyp == CASEX) return(exec_casex(stp));
2007  else if (stp->st.scs.castyp == CASEZ) return(exec_casez(stp));
2008 
2009  /* compute the case type - determines operator to use */
2010  selxsp = __eval_xpr(stp->st.scs.csx);
2011 
2012  /* if expression real, convert to 32 bit reg */
2013  if (stp->st.scs.csx->is_real) __cnv_stk_fromreal_toreg32(selxsp);
2014 
2015  /* if result of selector is not as wide as needed widen */
2016  /* case needs w bits width but selector is wire < w */
2017  selxlen = stp->st.scs.maxselwid;
2018  /* DBG remove -- */
2019  if (selxsp->xslen > selxlen) __misc_terr(__FILE__, __LINE__);
2020  /* --- */
2021  /* SJM 09/29/03 - change for new sized but widen only */
2022  if (selxsp->xslen < selxlen)
2023   {
2024    /* SJM 05/10/04 - LOOKATME - algorithm is that if any of the case match */
2025    /* exprs are word32 - case becomes word32 */
2026    if (stp->st.scs.csx->has_sign && !stp->st.scs.csx->unsgn_widen)
2027     __sgn_xtnd_widen(selxsp, selxlen);
2028    else __sizchg_widen(selxsp, selxlen);
2029   }
2030 
2031  selxlen = selxsp->xslen;
2032  if (__st_tracing) tr_case_st(selxsp, (stp->st.scs.csx->has_sign == 1));
2033  dflt_csip = stp->st.scs.csitems;
2034  csip = dflt_csip->csinxt;
2035 
2036  /* case case 1: fits in one word32 */
2037  if (selxlen <= WBITS)
2038   {
2039    aw = selxsp->ap[0];
2040    bw = selxsp->bp[0];
2041    for (; csip != NULL; csip = csip->csinxt)
2042     {
2043      for (xplp = csip->csixlst; xplp != NULL; xplp = xplp->xpnxt)
2044       {
2045        itemxsp = __eval2_xpr(xplp->xp);
2046 
2047        /* SJM 12/12/03 - never can be real here using new all if any code */
2048 
2049        /* no conversion needed becaause know item may be too narrow only */
2050        if (((aw ^ itemxsp->ap[0]) | (bw ^ itemxsp->bp[0])) == 0)
2051         { __pop_xstk(); __pop_xstk(); return(csip->csist); }
2052        __pop_xstk();
2053       }
2054     }
2055    __pop_xstk();
2056    if (dflt_csip->csist != NULL) return(dflt_csip->csist);
2057    return(NULL);
2058   }
2059  /* case case 2: wider than 1 word32 */
2060  selwlen = wlen_(selxlen);
2061  for (; csip != NULL; csip = csip->csinxt)
2062   {
2063    for (xplp = csip->csixlst; xplp != NULL; xplp = xplp->xpnxt)
2064     {
2065      itemxsp = __eval2_xpr(xplp->xp);
2066 
2067      /* SJM 12/12/03 - never can be real here using new all if any code */
2068 
2069      /* SJM 09/29/03 handle sign extension and separate cases */
2070      if (itemxsp->xslen > selxlen) __narrow_sizchg(itemxsp, selxlen);
2071      else if (itemxsp->xslen < selxlen)
2072       {
2073        if (xplp->xp->has_sign && !xplp->xp->unsgn_widen)
2074         __sgn_xtnd_widen(itemxsp, selxlen);
2075        else __sizchg_widen(itemxsp, selxlen);
2076       }
2077 
2078      for (i = 0; i < selwlen; i++)
2079       {
2080        if (((selxsp->ap[i] ^ itemxsp->ap[i])
2081         | (selxsp->bp[i] ^ itemxsp->bp[i])) != 0) goto nxt_x;
2082       }
2083      __pop_xstk();
2084      __pop_xstk();
2085      return(csip->csist);
2086 
2087 nxt_x:
2088      __pop_xstk();
2089     }
2090   }
2091  __pop_xstk();
2092  if (dflt_csip->csist != NULL) return(dflt_csip->csist);
2093  return(NULL);
2094 }
2095 
2096 /*
2097  * special case routine to exec a case where any expr real
2098  *
2099  * SJM 12/12/03 - was converting real to word32 for cases with real but
2100  * think that is wrong (although 2001 LRM does not say exactly) so now
2101  * if any of case select or case item real, all compares real
2102  * (following same rule, if any of select or match expr word32 all)
2103  * (widening word32 - compares are for equal so only widening changes)
2104  */
exec_real_case(struct st_t * stp)2105 static struct st_t *exec_real_case(struct st_t *stp)
2106 {
2107  register struct xstk_t *itemxsp;
2108  register struct exprlst_t *xplp;
2109  register struct csitem_t *csip;
2110  double d1, d2;
2111  struct xstk_t *selxsp;
2112  struct csitem_t *dflt_csip;
2113 
2114  /* warning if casex or casez with real since no effect */
2115  if (stp->st.scs.castyp == CASEX || stp->st.scs.castyp == CASEZ)
2116   {
2117    __sgfwarn(3113,
2118     "select or case item expression real - casex/casez no effect");
2119   }
2120 
2121  /* compute the case type - determines operator to use */
2122  selxsp = __eval_xpr(stp->st.scs.csx);
2123 
2124  /* if select expr not real convert it */
2125  if (stp->st.scs.csx->cnvt_to_real)
2126   __cnv_stk_fromreg_toreal(selxsp, stp->st.scs.csx->has_sign);
2127 
2128  if (__st_tracing) tr_case_st(selxsp, (stp->st.scs.csx->has_sign == 1));
2129 
2130  dflt_csip = stp->st.scs.csitems;
2131  csip = dflt_csip->csinxt;
2132  memcpy(&d1, selxsp->ap, sizeof(double));
2133 
2134  for (; csip != NULL; csip = csip->csinxt)
2135   {
2136    for (xplp = csip->csixlst; xplp != NULL; xplp = xplp->xpnxt)
2137     {
2138      itemxsp = __eval2_xpr(xplp->xp);
2139 
2140      /* if case item expr not real convert it */
2141      if (xplp->xp->cnvt_to_real)
2142       {
2143        __cnv_stk_fromreg_toreal(itemxsp, xplp->xp->has_sign);
2144       }
2145      memcpy(&d2, itemxsp->ap, sizeof(double));
2146 
2147      /* real == (near 0.0) */
2148      if ((d2 - d1) > -EPSILON && (d2 - d1) < EPSILON)
2149       { __pop_xstk(); __pop_xstk(); return(csip->csist); }
2150      __pop_xstk();
2151     }
2152   }
2153  __pop_xstk();
2154  if (dflt_csip->csist != NULL) return(dflt_csip->csist);
2155  return(NULL);
2156 }
2157 
2158 /*
2159  * trace a case (for any of case/casex/casez)
2160  */
tr_case_st(struct xstk_t * selxsp,int32 cas_sign)2161 static void tr_case_st(struct xstk_t *selxsp, int32 cas_sign)
2162 {
2163  __tr_msg("trace: %-7d -- [selector: %d'h%s]\n",
2164   __slin_cnt, selxsp->xslen, __regab_tostr(__xs, selxsp->ap, selxsp->bp,
2165   selxsp->xslen, BHEX, cas_sign));
2166 }
2167 
2168 /*
2169  * execute a casex case statement
2170  */
exec_casex(struct st_t * stp)2171 static struct st_t *exec_casex(struct st_t *stp)
2172 {
2173  register word32 aw, bw;
2174  register struct xstk_t *itemxsp;
2175  register struct csitem_t *csip;
2176  register struct exprlst_t *xplp;
2177  int32 selxlen, selwlen, i;
2178  struct xstk_t *selxsp;
2179  struct csitem_t *dflt_csip;
2180 
2181  /* compute the case type - determines operator to use */
2182  selxsp = __eval_xpr(stp->st.scs.csx);
2183 
2184  /* if expression real, convert to 32 bit reg */
2185  if (stp->st.scs.csx->is_real) __cnv_stk_fromreal_toreg32(selxsp);
2186 
2187  /* if result of selector is not as wide as needed widen */
2188  /* case needs w bits width but selector is wire < w */
2189 
2190  selxlen = stp->st.scs.maxselwid;
2191  /* DBG remove -- */
2192  if (selxsp->xslen > selxlen) __misc_terr(__FILE__, __LINE__);
2193  /* --- */
2194  /* SJM 09/29/03 - change for new sized but widen only */
2195  if (selxsp->xslen < selxlen)
2196   {
2197    if (stp->st.scs.csx->has_sign && !stp->st.scs.csx->unsgn_widen)
2198     __sgn_xtnd_widen(selxsp, selxlen);
2199    else __sizchg_widen(selxsp, selxlen);
2200   }
2201  if (__st_tracing) tr_case_st(selxsp, (stp->st.scs.csx->has_sign == 1));
2202 
2203  dflt_csip = stp->st.scs.csitems;
2204  csip = dflt_csip->csinxt;
2205 
2206  /* case case 1: fits in one word32 */
2207  if (selxlen <= WBITS)
2208   {
2209    aw = selxsp->ap[0];
2210    bw = selxsp->bp[0];
2211    for (; csip != NULL; csip = csip->csinxt)
2212     {
2213      for (xplp = csip->csixlst; xplp != NULL; xplp = xplp->xpnxt)
2214       {
2215        itemxsp = __eval2_xpr(xplp->xp);
2216 
2217        /* SJM 12/12/03 - never can be real here using new all if any code */
2218 
2219        /* no conversion needed becaause know item may be too narrow only */
2220        /* must 0 any don't care bits with either x/z bit 0 mask */
2221        if ((((aw ^ itemxsp->ap[0]) | (bw ^ itemxsp->bp[0]))
2222         & ~(bw | itemxsp->bp[0])) == 0)
2223         { __pop_xstk(); __pop_xstk(); return(csip->csist); }
2224        __pop_xstk();
2225       }
2226     }
2227    __pop_xstk();
2228    if (dflt_csip->csist != NULL) return(dflt_csip->csist);
2229    return(NULL);
2230   }
2231  /* case case 2: wider than 1 word32 */
2232  selwlen = wlen_(selxlen);
2233  for (; csip != NULL; csip = csip->csinxt)
2234   {
2235    for (xplp = csip->csixlst; xplp != NULL; xplp = xplp->xpnxt)
2236     {
2237      itemxsp = __eval2_xpr(xplp->xp);
2238 
2239      /* SJM 12/12/03 - never can be real here using new all if any code */
2240 
2241      /* SJM 09/29/03 handle sign extension and separate cases */
2242      if (itemxsp->xslen > selxlen) __narrow_sizchg(itemxsp, selxlen);
2243      else if (itemxsp->xslen < selxlen)
2244       {
2245        if (xplp->xp->has_sign && !xplp->xp->unsgn_widen)
2246         __sgn_xtnd_widen(itemxsp, selxlen);
2247        else __sizchg_widen(itemxsp, selxlen);
2248       }
2249 
2250      for (i = 0; i < selwlen; i++)
2251       {
2252        /* SJM 01/08/99 - WAS WRONG - for wide if == 0 always matches first */
2253        if ((((selxsp->ap[i] ^ itemxsp->ap[i])
2254         | (selxsp->bp[i] ^ itemxsp->bp[i]))
2255         & ~(selxsp->bp[i] | itemxsp->bp[i])) != 0) goto nxt_x;
2256       }
2257      __pop_xstk();
2258      __pop_xstk();
2259      return(csip->csist);
2260 
2261 nxt_x:
2262      __pop_xstk();
2263     }
2264   }
2265  __pop_xstk();
2266  if (dflt_csip->csist != NULL) return(dflt_csip->csist);
2267  return(NULL);
2268 }
2269 
2270 /*
2271  * execute a casez case statement
2272  */
exec_casez(struct st_t * stp)2273 static struct st_t *exec_casez(struct st_t *stp)
2274 {
2275  register word32 aw, bw;
2276  register struct xstk_t *itemxsp;
2277  register struct csitem_t *csip;
2278  register struct exprlst_t *xplp;
2279  register word32 mask;
2280  int32 selxlen, selwlen, i;
2281  struct xstk_t *selxsp;
2282  struct csitem_t *dflt_csip;
2283 
2284  /* compute the case type - determines operator to use */
2285  selxsp = __eval_xpr(stp->st.scs.csx);
2286 
2287  /* if expression real, convert to 32 bit reg */
2288  if (stp->st.scs.csx->is_real) __cnv_stk_fromreal_toreg32(selxsp);
2289 
2290  /* if result of selector is not as wide as needed widen */
2291  /* case needs w bits width but selector is wire < w */
2292  selxlen = stp->st.scs.maxselwid;
2293  /* DBG remove -- */
2294  if (selxsp->xslen > selxlen) __misc_terr(__FILE__, __LINE__);
2295  /* --- */
2296  /* SJM 09/29/03 - change for new sized but widen only */
2297  if (selxsp->xslen < selxlen)
2298   {
2299    if (stp->st.scs.csx->has_sign && !stp->st.scs.csx->unsgn_widen)
2300     __sgn_xtnd_widen(selxsp, selxlen);
2301    else __sizchg_widen(selxsp, selxlen);
2302   }
2303  if (__st_tracing) tr_case_st(selxsp, (stp->st.scs.csx->has_sign == 1));
2304 
2305  dflt_csip = stp->st.scs.csitems;
2306  csip = dflt_csip->csinxt;
2307 
2308  /* case case 1: fits in one word32 */
2309  if (selxlen <= WBITS)
2310   {
2311    aw = selxsp->ap[0];
2312    bw = selxsp->bp[0];
2313    for (; csip != NULL; csip = csip->csinxt)
2314     {
2315      for (xplp = csip->csixlst; xplp != NULL; xplp = xplp->xpnxt)
2316       {
2317        itemxsp = __eval_xpr(xplp->xp);
2318 
2319        /* SJM 12/12/03 - never can be real here using new all if any code */
2320 
2321        /* no conversion needed becaause know item may be too narrow only */
2322        /* must 0 any don't care bits z bits in either */
2323        mask = (aw | ~bw) & (itemxsp->ap[0] | ~itemxsp->bp[0]);
2324        if ((((aw ^ itemxsp->ap[0]) | (bw ^ itemxsp->bp[0])) & mask) == 0)
2325         { __pop_xstk(); __pop_xstk(); return(csip->csist); }
2326        __pop_xstk();
2327       }
2328     }
2329    __pop_xstk();
2330    if (dflt_csip->csist != NULL) return(dflt_csip->csist);
2331    return(NULL);
2332   }
2333  /* case case 2: wider than 1 word32 */
2334  selwlen = wlen_(selxlen);
2335  for (; csip != NULL; csip = csip->csinxt)
2336   {
2337    for (xplp = csip->csixlst; xplp != NULL; xplp = xplp->xpnxt)
2338     {
2339      itemxsp = __eval_xpr(xplp->xp);
2340 
2341      /* SJM 12/12/03 - never can be real here using new all if any code */
2342 
2343      /* SJM 09/29/03 handle sign extension and separate cases */
2344      if (itemxsp->xslen > selxlen) __narrow_sizchg(itemxsp, selxlen);
2345      else if (itemxsp->xslen < selxlen)
2346       {
2347        if (xplp->xp->has_sign && !xplp->xp->unsgn_widen)
2348         __sgn_xtnd_widen(itemxsp, selxlen);
2349        else __sizchg_widen(itemxsp, selxlen);
2350       }
2351 
2352      for (i = 0; i < selwlen; i++)
2353       {
2354        mask = (selxsp->ap[i] | ~selxsp->bp[i]) & (itemxsp->ap[i]
2355         | ~itemxsp->bp[i]);
2356 /* SJM 01/08/99 - WRONG - for wide if == 0 always matches first */
2357        if ((((selxsp->ap[i] ^ itemxsp->ap[i])
2358         | (selxsp->bp[i] ^ itemxsp->bp[i])) & mask) != 0) goto nxt_x;
2359       }
2360      __pop_xstk();
2361      __pop_xstk();
2362      return(csip->csist);
2363 
2364 nxt_x:
2365      __pop_xstk();
2366     }
2367   }
2368  __pop_xstk();
2369  if (dflt_csip->csist != NULL) return(dflt_csip->csist);
2370  return(NULL);
2371 }
2372 
2373 /*
2374  * execute the wait statement (not really a loop)
2375  *
2376  * if expression T, execute immediately
2377  * else block until change of variable in expr.
2378  * set up special net pin list elements (like events) until change
2379  * evaluate and remove if T
2380  *
2381  */
exec_wait(register struct st_t * stp)2382 static int32 exec_wait(register struct st_t *stp)
2383 {
2384  int32 tmp, rv;
2385  i_tev_ndx tevpi;
2386  struct xstk_t *xsp;
2387  struct delctrl_t *dctp;
2388 
2389  xsp = __eval_xpr(stp->st.swait.lpx);
2390  dctp = stp->st.swait.wait_dctp;
2391  if (xsp->xslen <= WBITS) tmp = ((xsp->ap[0] & ~xsp->bp[0]) != 0L);
2392 
2393  if (xsp->xslen <= WBITS)
2394   {
2395    if (stp->st.swait.lpx->is_real)
2396     {
2397      double d1;
2398 
2399      memcpy(&d1, xsp->ap, sizeof(double));
2400      tmp = (d1 != 0.0);
2401      /* must not emit z bit warning for real */
2402      /* LOOKATME - changing part of stack since really done with it */
2403      xsp->bp[0] = 0;
2404     }
2405    else tmp = ((xsp->ap[0] & ~xsp->bp[0]) != 0L);
2406   }
2407  else tmp = (__cvt_lngbool(xsp->ap, xsp->bp, wlen_(xsp->xslen)) == 1);
2408 
2409  if (tmp == 1)
2410   {
2411    if (!vval_is0_(xsp->bp, xsp->xslen))
2412     __sgfinform(404, "TRUE wait expression contains some x/z bits");
2413    __pop_xstk();
2414 
2415    /* RELEASE remove
2416    if (__debug_flg)
2417     __dmp_dcemsg(dctp, "setting wait dce to nil");
2418    --- */
2419 
2420    /* disarm for this instance - wait now past */
2421    /* first time thru will be nils but faster to just assign */
2422    dctp->dceschd_tevs[__inum] = -1;
2423    __cur_thd->th_dctp = NULL;
2424 
2425    if (__st_tracing)
2426     { strcpy(__xs2, "--continuing"); rv = TRUE; goto tr_done; }
2427    return(TRUE);
2428   }
2429 
2430  __pop_xstk();
2431  /* because of fast tev reclaim scheme - allocate and assign new */
2432  /* tev each time through here */
2433  /* notice this does not link on list */
2434  alloc_tev_(tevpi, TE_THRD, __inst_ptr, __simtime);
2435  __cur_thd->thdtevi = tevpi;
2436  __tevtab[tevpi].tu.tethrd = __cur_thd;
2437  /* if rexecuting task, algorithm is to cancel previous pending */
2438  /* delay control and emit warning */
2439  if (dctp->dceschd_tevs[__inum] != -1)
2440   {
2441    if (__cur_thd->assoc_tsk == NULL)
2442     {
2443      __sgfwarn(635,
2444       "INTERNAL BUG? - when reexecuting in %s cancel and rearm of wait",
2445       __msg2_blditree(__xs, __inst_ptr));
2446     }
2447    else
2448     {
2449      __sgfwarn(635, "when reexecuting task %s cancel and rearm of wait",
2450      __msg_blditree(__xs, __inst_ptr, __cur_thd->assoc_tsk));
2451     }
2452   }
2453  /* RELEASE remove ---
2454  if (__debug_flg)
2455   __dmp_dcemsg(dctp, "setting wait dce to event");
2456  --- */
2457  dctp->dceschd_tevs[__inum] = tevpi;
2458  __cur_thd->th_dctp = dctp;
2459  if (__st_tracing) { strcpy(__xs2, "--suspend"); rv = FALSE; goto tr_done; }
2460  /* this arms this instances delay control in case expr. changes */
2461  return(FALSE);
2462 
2463 tr_done:
2464  if (__st_tracing)
2465   {
2466    __tr_msg("trace: %-7d wait (%s) [cond: %d] %s\n",
2467     __slin_cnt, __msgexpr_tostr(__xs, stp->st.swait.lpx), tmp, __xs2);
2468   }
2469  return(rv);
2470 }
2471 
2472 /*
2473  * execute a for statement header
2474  * for is [init. assign; while (cond. exp) { <stmt>; <inc. assign stmt>; }
2475  * notice unlike C both initial statement and inc. statement must be assigns
2476  *
2477  * know inc. executed before here and never seen
2478  */
for_not_done(struct for_t * frs)2479 static int32 for_not_done(struct for_t *frs)
2480 {
2481  int32 tmp, has_xzs;
2482  word32 val;
2483  double d1;
2484  struct xstk_t *xsp;
2485 
2486  /* must move and execute for inc. at end not beginning of loop */
2487  has_xzs = FALSE;
2488  xsp = __eval_xpr(frs->fortermx);
2489  if (xsp->xslen <= WBITS)
2490   {
2491    /* SJM 07/20/00 - must convert to real if real */
2492    if (frs->fortermx->is_real)
2493     { memcpy(&d1, xsp->ap, sizeof(double)); tmp = (d1 != 0.0); }
2494    else
2495     {
2496      val = xsp->bp[0];
2497      tmp = ((xsp->ap[0] & ~val) != 0L);
2498      if (val != 0) { if (tmp == 0) tmp = 3; else has_xzs = TRUE; }
2499     }
2500   }
2501  else
2502   {
2503    tmp = __cvt_lngbool(xsp->ap, xsp->bp, wlen_(xsp->xslen));
2504    if (tmp == 1) { if (!vval_is0_(xsp->bp, xsp->xslen)) has_xzs = TRUE; }
2505   }
2506 
2507  if (__st_tracing)
2508   {
2509    __cur_sofs = 0;
2510    __dmp_forhdr((FILE *) NULL, frs);
2511    __trunc_exprline(TRTRUNCLEN, FALSE);
2512    __tr_msg("trace: %-7d %s) [cond: %d]\n",
2513     __slin_cnt, __exprline, tmp);
2514    __cur_sofs = 0;
2515   }
2516  __pop_xstk();
2517  if (tmp == 1)
2518   {
2519    if (has_xzs)
2520     {
2521      __sgfinform(405, "for condition true but has some x/z bits");
2522     }
2523    return(TRUE);
2524   }
2525  /* notice any 1 implies true so will not get here */
2526  if (tmp == 3)
2527   {
2528    __sgfinform(406,
2529     "for loop terminated by FALSE expressions containing x/z bits");
2530   }
2531  /* done with loop */
2532  return(FALSE);
2533 }
2534 
2535 /* notice non label begin block optimized away by here */
2536 
2537 /*
2538  * USER TASK/FUNCTION EXECUTION ROUTINES
2539  */
2540 
2541 /*
2542  * build named block thread structure and then execute the block
2543  */
exec_namblk(struct st_t * stp)2544 static void exec_namblk(struct st_t *stp)
2545 {
2546  struct task_t *tskp;
2547  struct thread_t *thp;
2548 
2549  tskp = stp->st.snbtsk;
2550  /* indent block and statements within */
2551  if (__st_tracing)
2552   {
2553    if (tskp->tsktyp == FORK) strcpy(__xs, "fork");
2554    else strcpy(__xs, "begin");
2555    __tr_msg("trace: %-7d %s : %s\n", __slin_cnt, __xs,
2556     tskp->tsksyp->synam);
2557   }
2558  /* use sub thread scheduling routine but just build and exec immediately */
2559  __cur_thd->thofscnt = 1;
2560  __cur_thd->thnxtstp = stp->stnxt;
2561 
2562  /* create normal thread structure but exec immediately - no schedule */
2563  thp = __setup_tsk_thread(tskp);
2564 
2565  thp->thpar = __cur_thd;
2566  __cur_thd->thofs = thp;
2567  /* move down but notice never an xmr instance loc. change */
2568  __cur_thd = thp;
2569  __cur_thd->th_itp = __inst_ptr;
2570  /* DBG remove -- */
2571  if (__cur_thd->thnxtstp == NULL) __misc_terr(__FILE__, __LINE__);
2572  /* __dmp_tskthd(tskp, __inst_mod); */
2573  /* --- */
2574  /* always continue with down 1 thread - need thread only for possible */
2575  /* disable of named block */
2576 }
2577 
2578 /*
2579  * exec a task or named block as subthread of __cur_thd
2580  * stp is place to begin after completion
2581  * returns pointer to new sub thread
2582  *
2583  * not used for fork-join because all fork join sub threads must be scheduled
2584  * caller must set current thread fields
2585  * will never see simple unnamed begin-end blocks here
2586  */
__setup_tsk_thread(struct task_t * tskp)2587 extern struct thread_t *__setup_tsk_thread(struct task_t *tskp)
2588 {
2589  register struct thread_t *thp;
2590  register struct tskthrd_t *ttp;
2591 
2592  /* allocate a new thread */
2593  thp = __alloc_thrd();
2594  thp->thenbl_sfnam_ind = __sfnam_ind;
2595  thp->thenbl_slin_cnt = __slin_cnt;
2596 
2597  /* DBG remove -- */
2598  if (tskp == NULL) __arg_terr(__FILE__, __LINE__);
2599  /* --- */
2600 
2601  /* if task, set next stmt to first of task and link thread on tasks list */
2602  /* for disable, task list of all threads and thread to task link  */
2603  /* schedule of task conflicts with thread task */
2604  /* DBG remove --- */
2605  if (thp->assoc_tsk != NULL && thp->assoc_tsk != tskp)
2606   __misc_sgfterr(__FILE__, __LINE__);
2607  /* --- */
2608 
2609  thp->thnxtstp = tskp->tskst;
2610 
2611  /* put on front of task thread lists */
2612  ttp = (struct tskthrd_t *) __my_malloc(sizeof(struct tskthrd_t));
2613  ttp->tthd_l = NULL;
2614  ttp->tthd_r = tskp->tthrds[__inum];
2615  tskp->tthrds[__inum] = ttp;
2616  if (ttp->tthd_r != NULL) ttp->tthd_r->tthd_l = ttp;
2617  ttp->tthrd = thp;
2618  thp->assoc_tsk = tskp;
2619  /* set the one list element that this thread connects to */
2620  thp->tthlst = ttp;
2621  return(thp);
2622 }
2623 
2624 /*
2625  * allocate threads and schedule execution of a fork-join
2626  * know __cur_thd will be named block thread for label fork join - else
2627  * current thread
2628  *
2629  * no assoc. task since disabling fork-join label block disable 1 up normal
2630  * label block not fork join
2631  */
__sched_fork(register struct st_t * stp)2632 extern void __sched_fork(register struct st_t *stp)
2633 {
2634  register int32 fji;
2635  register struct thread_t *thp;
2636  int32 sav_slin_cnt, sav_sfnam_ind;
2637  struct thread_t *last_thp;
2638  struct st_t *fjstp;
2639 
2640  /* DBG remove */
2641  if (__cur_thd->thofscnt != 0) __misc_terr(__FILE__, __LINE__);
2642  /* --- */
2643  /* convert current thread (one-up) to fork joint32 header */
2644  /* and build (link in) list of per statement threads */
2645  last_thp = NULL;
2646  for (fji = 0;; fji++)
2647   {
2648    if ((fjstp = stp->st.fj.fjstps[fji]) == NULL) break;
2649 
2650    /* SJM 03/07/02 - for optimizer must always schedule 1st stmt of unblk */
2651    /* instead of unnamed blk as now */
2652    if (fjstp->stmttyp == S_UNBLK) fjstp = fjstp->st.sbsts;
2653 
2654    /* using location of fork-join statement as enable loc. not fork loc. */
2655    sav_sfnam_ind = __sfnam_ind;
2656    sav_slin_cnt = __slin_cnt;
2657    __sfnam_ind = fjstp->stfnam_ind;
2658    __slin_cnt = fjstp->stlin_cnt;
2659    /* schedule each subthread after building it */
2660    thp = sched_fj_subthread(fjstp);
2661 
2662    __sfnam_ind = sav_sfnam_ind;
2663    __slin_cnt = sav_slin_cnt;
2664 
2665    __cur_thd->thofscnt += 1;
2666    if (last_thp == NULL) __cur_thd->thofs = thp;
2667    else { thp->thleft = last_thp; last_thp->thright = thp; }
2668    thp->thpar = __cur_thd;
2669    thp->th_itp = __inst_ptr;
2670    /* flag on fork-join component to indicate must look for assoc tsk up */
2671    thp->th_fj = TRUE;
2672    last_thp = thp;
2673   }
2674 }
2675 
2676 /*
2677  * setup and schedule execution of one fork-join subthread of __cur_thd
2678  *
2679  * stp is place to begin when event processed
2680  * returns pointer to thread value in scheduled event
2681  * caller must set current thread fields
2682  */
sched_fj_subthread(struct st_t * stp)2683 static struct thread_t *sched_fj_subthread(struct st_t *stp)
2684 {
2685  register struct thread_t *thp;
2686  i_tev_ndx tevpi;
2687 
2688  /* allocate a new thread */
2689  thp = __alloc_thrd();
2690  thp->thenbl_sfnam_ind = __sfnam_ind;
2691  thp->thenbl_slin_cnt = __slin_cnt;
2692 
2693  /* set the one fj statement (or list) as next stmt of subthread */
2694  thp->thnxtstp = stp;
2695 
2696  /* allocate an event for this fork-join component statement */
2697  /* at end of current time slot */
2698  alloc_tev_(tevpi, TE_THRD, __inst_ptr, __simtime);
2699 
2700  /* link thread back to event */
2701  thp->thdtevi = tevpi;
2702  __tevtab[tevpi].tu.tethrd = thp;
2703 
2704  if (__debug_flg && __st_tracing)
2705   {
2706    __tr_msg("trace: %-7d -- schedule new subthread at %s continue at %s\n",
2707     __slin_cnt, __bld_lineloc(__xs, thp->thenbl_sfnam_ind,
2708     thp->thenbl_slin_cnt), __bld_lineloc(__xs2, stp->stfnam_ind,
2709     stp->stlin_cnt));
2710   }
2711 
2712  /* this must go on front because interactive statement must complete */
2713  __add_ev_to_front(tevpi);
2714  return(thp);
2715 }
2716 
2717 /*
2718  * add an event to front of current queue
2719  * for various procedural control - must go front so interactive completes
2720  * before any other events processed
2721  *
2722  * scheme is to always execute procedural as soon as possible
2723  * but declarative as late as possible
2724  */
__add_ev_to_front(register i_tev_ndx tevpi)2725 extern void __add_ev_to_front(register i_tev_ndx tevpi)
2726 {
2727  if (!__processing_pnd0s)
2728   {
2729    /* adding to front is just after current since now processing current */
2730    if (__cur_tevpi == -1)
2731     {
2732      if (__cur_te_hdri == -1) __cur_te_hdri = __cur_te_endi = tevpi;
2733      else { __tevtab[tevpi].tenxti = __cur_te_hdri; __cur_te_hdri = tevpi; }
2734     }
2735    else
2736     {
2737      if (__cur_tevpi != __cur_te_endi)
2738       __tevtab[tevpi].tenxti = __tevtab[__cur_tevpi].tenxti;
2739      else __cur_te_endi = tevpi;
2740      __tevtab[__cur_tevpi].tenxti = tevpi;
2741     }
2742    __num_twhevents++;
2743    /* need to make sure number of timing wheel events matches cur number */
2744    __twheel[__cur_twi]->num_events += 1;
2745   }
2746  else
2747   {
2748    /* also in pnd 0's front is just after current if set */
2749    if (__cur_tevpi == -1)
2750     {
2751      /* notice during add net chg elements cur tevp nil, so common to add */
2752      /* to end */
2753      if (__p0_te_hdri == -1) __p0_te_hdri = __p0_te_endi = tevpi;
2754      else { __tevtab[tevpi].tenxti = __p0_te_hdri; __p0_te_hdri = tevpi; }
2755     }
2756    else
2757     {
2758      if (__cur_tevpi != __p0_te_endi)
2759       __tevtab[tevpi].tenxti = __tevtab[__cur_tevpi].tenxti;
2760      else __p0_te_endi = tevpi;
2761      __tevtab[__cur_tevpi].tenxti = tevpi;
2762     }
2763    /* this does not go on timing wheel or get counted */
2764   }
2765 }
2766 
2767 /*
2768  * allocate a new thread
2769  */
__alloc_thrd(void)2770 extern struct thread_t *__alloc_thrd(void)
2771 {
2772  register struct thread_t *thp;
2773 
2774  thp = (struct thread_t *) __my_malloc(sizeof(struct thread_t));
2775  init_thrd(thp);
2776  return(thp);
2777 }
2778 
2779 /*
2780  * initialize a new thread
2781  */
init_thrd(register struct thread_t * thp)2782 static void init_thrd(register struct thread_t *thp)
2783 {
2784  thp->tsk_stouts = FALSE;
2785  thp->th_dsable = FALSE;
2786  thp->th_rhsform = FALSE;
2787  thp->th_fj = FALSE;
2788  thp->th_ialw = FALSE;
2789  thp->th_postamble = FALSE;
2790  /* off-spring count is 0 unless incremented when sub thread created */
2791  thp->thofscnt = 0;
2792  thp->thnxtstp = NULL;
2793  thp->thpar = thp->thright = thp->thleft = thp->thofs = NULL;
2794  thp->tthlst = NULL;
2795  thp->assoc_tsk = NULL;
2796  thp->th_dctp = NULL;
2797  thp->thdtevi = -1;
2798  thp->thenbl_sfnam_ind = 0;
2799  thp->thenbl_slin_cnt = 0;
2800  thp->th_rhswp = NULL;
2801  thp->th_rhswlen = -1;
2802  thp->th_itp = NULL;
2803  thp->th_hctrl = NULL;
2804 }
2805 
2806 /*
2807  * execute a task call
2808  *
2809  * thread suspend mechanism set up but works by continuing with first
2810  * stmt in tsk body (can be execed as iop) - thread mechanism fixed
2811  * up so suspend works right including handling of disable and tsk outs
2812  *
2813  * know for user tasks, argument list exactly matches definition list
2814  * can improve this by preprocessing call/return evaluation
2815  */
__exec_tskcall(struct st_t * stp)2816 extern struct st_t *__exec_tskcall(struct st_t *stp)
2817 {
2818  register struct expr_t *xp;
2819  register struct task_pin_t *tpp;
2820  int32 argi;
2821  struct tskcall_t *tkcp;
2822  struct expr_t *tkxp, *rhsxp;
2823  struct sy_t *syp;
2824  struct task_t *tskp;
2825  struct xstk_t *xsp;
2826  struct net_t *np;
2827  struct thread_t *thp;
2828  struct itree_t *tsk_itp;
2829  struct st_t *stp2;
2830 
2831  tkcp = &(stp->st.stkc);
2832  tkxp = tkcp->tsksyx;
2833  syp = tkxp->lu.sy;
2834 
2835  if (syp->sytyp == SYM_STSK)
2836   {
2837    /* no time movement in system tasks */
2838    /* return NULL, to suspend thread - non null to continue as to next st */
2839    /* this does own tracing */
2840    if (__st_tracing)
2841     {
2842      __cur_sofs = 0;
2843      __dmp_tskcall((FILE *) NULL, stp);
2844      __trunc_exprline(TRTRUNCLEN, FALSE);
2845      __tr_msg("trace: %-7d %s\n", __slin_cnt,
2846        __exprline);
2847      __cur_sofs = 0;
2848     }
2849    return(__exec_stsk(stp, syp, tkcp));
2850   }
2851  tskp = syp->el.etskp;
2852  tpp = tskp->tskpins;
2853 
2854  if (tkxp->optyp == GLBREF)
2855   {
2856    /* must get tsk exec itree location but cannot change to yet */
2857    __xmrpush_refgrp_to_targ(tkxp->ru.grp);
2858    tsk_itp = __inst_ptr;
2859    /* notice need to print new location for xmr task */
2860    if (__st_tracing) tr_resume_msg();
2861    __pop_itstk();
2862   }
2863  else tsk_itp = NULL;
2864  if (__st_tracing)
2865   {
2866    __cur_sofs = 0;
2867    __adds("<** enabling task ");
2868    __adds(__to_idnam(tkxp));
2869    addch_('(');
2870   }
2871 
2872  /* must assign to task variables since values persist */
2873  /* user tasks are value-result */
2874  argi = 0;
2875  for (xp = tkcp->targs; xp != NULL; xp = xp->ru.x, tpp = tpp->tpnxt, argi++)
2876   {
2877    if (tpp->trtyp != IO_OUT)
2878     {
2879      /* assign rhs in or inout arg. expr. to task local variable */
2880      np = tpp->tpsy->el.enp;
2881      rhsxp = xp->lu.x;
2882      xsp = __eval_xpr(rhsxp);
2883      eval_tskassign_rhsexpr(xsp, (np->ntyp == N_REAL), np->nwid,
2884       (rhsxp->is_real == 1), (rhsxp->has_sign == 1));
2885      if (__st_tracing) tradd_tf_argval(argi, np, xsp);
2886      /* if xmr call, afer eval in cur. itree loc. must store in xmr dest */
2887      if (tsk_itp != NULL)
2888       {
2889        __push_itstk(tsk_itp);
2890        __chg_st_val(np, xsp->ap, xsp->bp);
2891        __pop_itstk();
2892       }
2893      else __chg_st_val(np, xsp->ap, xsp->bp);
2894      __pop_xstk();
2895     }
2896    else if (__st_tracing)
2897     {
2898      /* for tracing output value on entry, need caller's itree loc. */
2899      np = tpp->tpsy->el.enp;
2900      push_xstk_(xsp, np->nwid);
2901      __ld_wire_val(xsp->ap, xsp->bp, np);
2902      tradd_tf_argval(argi, np, xsp);
2903      __pop_xstk();
2904     }
2905   }
2906  if (__st_tracing)
2907   {
2908    __adds(")");
2909    __trunc_exprline(TRTRUNCLEN, FALSE);
2910    __tr_msg("trace: %-7d %s\n", __slin_cnt, __exprline);
2911    __cur_sofs = 0;
2912   }
2913 
2914  /* use sub thread scheduling routine but just build and exec immediately */
2915  __cur_thd->thofscnt = 1;
2916 
2917  /* if xmr task call replace top of instance stack here - cur_thd has up 1 */
2918  if (tsk_itp != NULL) { __pop_itstk(); __push_itstk(tsk_itp); }
2919 
2920  /* trick here is that must not advance statement since need to store */
2921  thp = __setup_tsk_thread(tskp);
2922 
2923  if (tskp->thas_outs || __st_tracing)
2924   {
2925    thp->tsk_stouts = TRUE;
2926    /* must set thrd nxt stmt to the task call so can find task after */
2927    /* task completed suspend so can find tsk to set out params in */
2928    /* fixup to skip of non loop end gotos after tsk outs stored */
2929    __cur_thd->thnxtstp = stp;
2930    __cur_thd->th_postamble = TRUE;
2931   }
2932  /* SJM 04/05/02 - skip over all non loop end gotos so can exec actual stmt */
2933  else
2934   {
2935    stp2 = stp->stnxt;
2936    if (stp2 == NULL) __cur_thd->thnxtstp = NULL;
2937    else if (stp2->stmttyp != S_GOTO) __cur_thd->thnxtstp = stp2;
2938    else if (stp2->lpend_goto) __cur_thd->thnxtstp = stp2;
2939    else
2940     {
2941      for (;;)
2942       {
2943        /* know on entry stp2 goto */
2944        stp2 = stp2->st.sgoto;
2945        if (stp2 == NULL || stp2->stmttyp != S_GOTO)
2946         { __cur_thd->thnxtstp = stp2; break; }
2947        if (stp2->lpend_goto) { __cur_thd->thnxtstp = stp2; break; }
2948       }
2949     }
2950   }
2951 
2952  thp->thpar = __cur_thd;
2953  __cur_thd->thofs = thp;
2954  /* make task thread current */
2955  __cur_thd = thp;
2956  __cur_thd->th_itp = __inst_ptr;
2957  /* DBG remove ---
2958  __dmp_tskthd(tskp, __inst_mod);
2959  --- */
2960  return(thp->thnxtstp);
2961 }
2962 
2963 /*
2964  * print a task or function argument value
2965  */
tradd_tf_argval(int32 argi,struct net_t * np,struct xstk_t * xsp)2966 static void tradd_tf_argval(int32 argi, struct net_t *np, struct xstk_t *xsp)
2967 {
2968  char s1[RECLEN];
2969  int32 signv, base;
2970 
2971  if (argi != 0) __adds(", ");
2972  if (!vval_is0_(xsp->bp, xsp->xslen) && np->ntyp != N_REAL)
2973   {
2974    sprintf(s1, "%d'h", xsp->xslen);
2975    __adds(s1);
2976    __regab_tostr(s1, xsp->ap, xsp->bp, xsp->xslen, BHEX, FALSE);
2977   }
2978  else
2979   {
2980    signv = FALSE; base = BHEX;
2981    if (np->ntyp == N_REAL) base = BDBLE;
2982    else if (np->n_signed) { base = BDEC; signv = TRUE; }
2983    __regab_tostr(s1, xsp->ap, xsp->bp, xsp->xslen, base, signv);
2984   }
2985  __adds(s1);
2986 }
2987 
2988 /*
2989  * store task return output parameters
2990  *
2991  * if disabled never get here
2992  * tricky because must eval using tos itree loc. but assign to 1 under
2993  * also get here even if no out args but statement tracing on
2994  *
2995  * this is called from task thread and itree loc. but assigns to one up
2996  * thread and itree location
2997  */
store_tskcall_outs(struct st_t * tskcall_stp)2998 static void store_tskcall_outs(struct st_t *tskcall_stp)
2999 {
3000  register struct expr_t *xp;
3001  register struct task_pin_t *tpp;
3002  int32 first_time, base, signv;
3003  struct tskcall_t *tkcp;
3004  struct expr_t *tkxp, *lhsxp;
3005  struct task_t *tskp;
3006  struct xstk_t *xsp;
3007  struct net_t *np;
3008  char s1[RECLEN];
3009 
3010  tkcp = &(tskcall_stp->st.stkc);
3011  tkxp = tkcp->tsksyx;
3012 
3013  tskp = tkxp->lu.sy->el.etskp;
3014  if (__st_tracing)
3015   {
3016    __cur_sofs = 0;
3017    __adds("**> returning from task ");
3018    __adds(__to_idnam(tkxp));
3019    addch_('(');
3020   }
3021  tpp = tskp->tskpins;
3022  first_time = TRUE;
3023  for (xp = tkcp->targs; xp != NULL; xp = xp->ru.x, tpp = tpp->tpnxt)
3024   {
3025    if (tpp->trtyp == IO_IN) continue;
3026 
3027    /* assign task local param var. value to lhs call argument */
3028    /* xp->lu.x is rhs src., np is lhs dest. var. */
3029    np = tpp->tpsy->el.enp;
3030    push_xstk_(xsp, np->nwid);
3031    /* need load value here because, need to decode storage rep */
3032    __ld_wire_val(xsp->ap, xsp->bp, np);
3033    lhsxp = xp->lu.x;
3034    eval_tskassign_rhsexpr(xsp, (lhsxp->is_real == 1), lhsxp->szu.xclen,
3035     (np->ntyp == N_REAL), (np->n_signed == 1));
3036    /* np here is rhs */
3037    if (__st_tracing)
3038     {
3039      if (first_time) first_time = FALSE; else __adds(", ");
3040      if (np->ntyp != N_REAL && !vval_is0_(xsp->bp, xsp->xslen))
3041       {
3042        sprintf(s1, "%d'h", xsp->xslen);
3043        __adds(s1);
3044        __regab_tostr(s1, xsp->ap, xsp->bp, xsp->xslen, BHEX, FALSE);
3045       }
3046      else
3047       {
3048        signv = FALSE; base = BHEX;
3049        if (np->ntyp == N_REAL) base = BDBLE;
3050        else if (np->n_signed) { base = BDEC; signv = TRUE; }
3051        __regab_tostr(s1, xsp->ap, xsp->bp, xsp->xslen, base, signv);
3052       }
3053      __adds(s1);
3054     }
3055    /* notice for xmr task enable, must eval in task itree place */
3056    /* but store top of expr. stack in calling itree place */
3057    if (tkxp->optyp == GLBREF)
3058     {
3059      __push_itstk(__cur_thd->thpar->th_itp);
3060      __exec2_proc_assign(lhsxp, xsp->ap, xsp->bp);
3061      __pop_itstk();
3062     }
3063    else __exec2_proc_assign(lhsxp, xsp->ap, xsp->bp);
3064    __pop_xstk();
3065   }
3066  if (__st_tracing)
3067   {
3068    __adds(")");
3069    __trunc_exprline(TRTRUNCLEN, FALSE);
3070    __tr_msg("trace: %-7d %s\n", __slin_cnt, __exprline);
3071    __cur_sofs = 0;
3072   }
3073 }
3074 
3075 /*
3076  * execute a user function call operator in an expression
3077  * ndp is FCALL expression node - ru is operand list
3078  * user functions only take input args
3079  * notice local variables presist and puts return value on top of expr stk
3080  */
__exec_func(register struct expr_t * ndp)3081 extern void __exec_func(register struct expr_t *ndp)
3082 {
3083  register struct expr_t *argxp;
3084  register struct task_pin_t *tpp;
3085  int32 savslin_cnt, savsfnam_ind, nd_thdfree;
3086  struct sy_t *fsyp;
3087  struct itree_t *func_itp, *xmr_savitp;
3088  struct st_t *stp;
3089  struct task_t *tskp;
3090  struct tev_t *tevp;
3091  int32 argi;
3092  struct gref_t *grp;
3093  struct xstk_t *xsp;
3094  struct net_t *np;
3095  struct expr_t *rhsxp;
3096 
3097  /* SJM 05/22/05 - no reason to pass func symbol - just get from expr node */
3098  fsyp = ndp->lu.x->lu.sy;
3099 
3100  /* for decl. rhs, maybe no thrd - bld for 1st call else take over cur. */
3101  nd_thdfree = FALSE;
3102  if (__cur_thd == NULL)
3103   {
3104    __cur_thd = __alloc_thrd();
3105    __cur_thd->th_itp = __inst_ptr;
3106    nd_thdfree = TRUE;
3107   }
3108  /* DBG remove --- */
3109  else if (__cur_thd->th_itp != __inst_ptr) __misc_terr(__FILE__, __LINE__);
3110  /* --- */
3111 
3112  /* function source will be dump later */
3113  if (__st_tracing)
3114   {
3115    __cur_sofs = 0;
3116    __adds("<** calling function ");
3117    __adds(__to_idnam(ndp->lu.x));
3118    addch_('(');
3119   }
3120 
3121  xmr_savitp = __inst_ptr;
3122  /* function call prep. block */
3123 
3124  argi = 0;
3125  tskp = fsyp->el.etskp;
3126  tpp = tskp->tskpins->tpnxt;
3127  /* if global, local variables accessed from target (defining mod) inst */
3128  if (ndp->lu.x->optyp == GLBREF)
3129   {
3130    grp = ndp->lu.x->ru.grp;
3131    __xmrpush_refgrp_to_targ(grp);
3132    if (__st_tracing) tr_resume_msg();
3133    func_itp = __inst_ptr;
3134    /* cannot change to func xmr place yet */
3135    __pop_itstk();
3136   }
3137  else func_itp = NULL;
3138 
3139  /* evaluate and store input params */
3140  /* 1st tpp is by convention is return value but 1st arg is real arg */
3141  /* know number matches exactly (no ,,) or will not get here */
3142  argi = 0;
3143  for (argxp = ndp->ru.x; argxp != NULL; argxp = argxp->ru.x,
3144   tpp = tpp->tpnxt, argi++)
3145   {
3146    /* if xmr call, must eval. these in current not func. */
3147    /* assign rhs in or inout arg. expr. to task local variable */
3148    np = tpp->tpsy->el.enp;
3149    rhsxp = argxp->lu.x;
3150    xsp = __eval2_xpr(rhsxp);
3151    eval_tskassign_rhsexpr(xsp, (np->ntyp == N_REAL), np->nwid,
3152     (rhsxp->is_real == 1), (rhsxp->has_sign == 1));
3153 
3154    if (__st_tracing) tradd_tf_argval(argi, np, xsp);
3155 
3156    /* notice can cause propagate reg xmr on rhs that is function arg */
3157    /* if xmr need to store in down itree location */
3158    if (func_itp != NULL)
3159     {
3160      __push_itstk(func_itp);
3161      __chg_st_val(np, xsp->ap, xsp->bp);
3162      __pop_itstk();
3163     }
3164    else __chg_st_val(np, xsp->ap, xsp->bp);
3165    __pop_xstk();
3166   }
3167 
3168  if (__st_tracing)
3169   {
3170    __adds(")");
3171    __trunc_exprline(TRTRUNCLEN, FALSE);
3172    __tr_msg("trace: %-7d %s\n", __slin_cnt, __exprline);
3173    __cur_sofs = 0;
3174   }
3175  /* this is dynamic call list */
3176  if (++__fcspi >= __maxfcnest) grow_fcstk();
3177  __fcstk[__fcspi] = tskp;
3178  savslin_cnt = __slin_cnt;
3179  savsfnam_ind = __sfnam_ind;
3180  /* if xmr function call replace top - relative xmr's not though itstk */
3181  if (func_itp != NULL)
3182   { __pop_itstk(); __push_itstk(func_itp); __cur_thd->th_itp = __inst_ptr; }
3183 
3184  /* cannot schedule and resume inside func. so suspend and schedule */
3185  /* then unsuspend and cancel event */
3186  stp = tskp->tskst;
3187  __cur_thd->thnxtstp = stp;
3188  /* if stepping, make sure first execed */
3189  if (__single_step) __step_from_thread = FALSE;
3190 
3191 again:
3192  __stmt_suspend = FALSE;
3193  /* step returns after 1 statement (to new line) or end of func */
3194  if (__single_step && __cur_thd->th_hctrl == NULL) step_exec_stmt(stp);
3195  else if (__st_tracing || __single_step)
3196   {
3197     brktr_exec_stmts(stp);
3198   }
3199  else exec_stmts(stp);
3200 
3201  /* happens if hit break or step or ^c hit - suspend routine just execed */
3202  if (__stmt_suspend)
3203   {
3204    __do_interactive_loop();
3205    /* tricky code for func - restart and cancel scheduled resume event */
3206    /* DBG remove --- */
3207    if (__fsusp_tevpi == -1) __misc_terr(__FILE__, __LINE__);
3208 
3209    tevp = &(__tevtab[__fsusp_tevpi]);
3210    if (__inst_ptr != tevp->teitp || __inst_ptr != __suspended_itp)
3211     __misc_terr(__FILE__, __LINE__);
3212    /* --- */
3213    /* restore from func. suspended event and cancel event */
3214    __cur_thd = tevp->tu.tethrd;
3215    tevp->te_cancel = TRUE;
3216    __fsusp_tevpi = -1L;
3217 
3218    /* undo suspend */
3219    __cur_thd->thdtevi = -1;
3220    __suspended_thd = NULL;
3221    __suspended_itp = NULL;
3222    stp = __cur_thd->thnxtstp;
3223    goto again;
3224   }
3225 
3226  __slin_cnt = savslin_cnt;
3227  __sfnam_ind = savsfnam_ind;
3228  __fcspi--;
3229 
3230  /* SJM 05/12/03 - do not need block here */
3231  /* return block */
3232  /* put assign func return variable (func. name) value on tos */
3233  /* key here is task name local variable has declaration from func hdr */
3234  /* notice ok if not assigned, to will just return x */
3235  np = tskp->tskpins->tpsy->el.enp;
3236  push_xstk_(xsp, np->nwid);
3237  /* caller must intepret type of value on tos */
3238  /* for itp this must be loaded from dest. */
3239  __ld_wire_val(xsp->ap, xsp->bp, np);
3240  /* if xmr replace top with original and put back thread itp */
3241  if (func_itp != NULL)
3242  { __pop_itstk(); __push_itstk(xmr_savitp); __cur_thd->th_itp = __inst_ptr; }
3243 
3244  if (__st_tracing)
3245   {
3246    int32 signv, base;
3247 
3248    if (np->ntyp != N_REAL && !vval_is0_(xsp->bp, xsp->xslen))
3249     {
3250      sprintf(__xs2, "%d'h%s", xsp->xslen, __regab_tostr(__xs, xsp->ap,
3251       xsp->bp, xsp->xslen, BHEX, FALSE));
3252     }
3253    else
3254     {
3255      signv = FALSE; base = BHEX;
3256      if (np->ntyp == N_REAL) base = BDBLE;
3257      else if (np->n_signed) { base = BDEC; signv = TRUE; }
3258      __regab_tostr(__xs2, xsp->ap, xsp->bp, xsp->xslen, base, signv);
3259     }
3260    __tr_msg("trace: %-7d **> [%s] returned by function %s\n",
3261     __slin_cnt, __xs2, __to_idnam(ndp->lu.x));
3262   }
3263 
3264  if (nd_thdfree)
3265   {
3266    __my_free((char *) __cur_thd, sizeof(struct thread_t));
3267    __cur_thd = NULL;
3268   }
3269  return;
3270 }
3271 
3272 
3273 /*
3274  * routine to grow fcstk (function call no display local variables)
3275  */
grow_fcstk(void)3276 static void grow_fcstk(void)
3277 {
3278  register int32 i;
3279  int32 old_maxnest;
3280  int32 osize, nsize;
3281 
3282  old_maxnest = __maxfcnest;
3283  osize = old_maxnest*sizeof(struct task_t *);
3284  /* grow by 50% after certain point */
3285  if (__maxfcnest >= 2000) __maxfcnest += __maxfcnest/2;
3286  else __maxfcnest *= 2;
3287  nsize = __maxfcnest*sizeof(struct task_t *);
3288  __fcstk = (struct task_t **) __my_realloc((char *) __fcstk, osize, nsize);
3289  for (i = old_maxnest; i < __maxfcnest; i++) __fcstk[i] = NULL;
3290  if (__debug_flg)
3291   __dbg_msg("+++ fcall stack grew from %d bytes to %d\n", osize, nsize);
3292 }
3293 
3294 /*
3295  * execute a system function call operator
3296  * ndp is actual FCALL node
3297  * leaves return value on top of expr. stack but does not return it
3298  */
__exec_sysfunc(register struct expr_t * ndp)3299 extern void __exec_sysfunc(register struct expr_t *ndp)
3300 {
3301  register struct xstk_t *xsp, *xsp2;
3302  register struct expr_t *fax;
3303  int32 ival, fd, c;
3304  word32 uval;
3305  word64 timval;
3306  double d1;
3307  struct sy_t *fsyp;
3308  struct sysfunc_t *sfbp;
3309 
3310  /* SJM 05/22/05 - no reason to pass func symbol - just get from expr node */
3311  fsyp = ndp->lu.x->lu.sy;
3312 
3313  sfbp = fsyp->el.esyftbp;
3314  switch (sfbp->syfnum) {
3315   /* functions that take exactly one argument */
3316   case STN_FOPEN:
3317    /* AIV 09/08/03 - changed now can take one or 2 args for OS FILE * */
3318    /* fd = $fopen([filen name]) or fd = $fopen([file name], [I/O mode]) */
3319    fax = ndp->ru.x->lu.x;
3320    /* 2nd arg empty also must be interpreted as MCD open */
3321    if (ndp->ru.x->ru.x != NULL && ndp->ru.x->lu.x->optyp != OPEMPTY)
3322     {
3323      uval = fio_do_fopen(fax, ndp->ru.x->ru.x->lu.x);
3324     }
3325    else uval = mc_do_fopen(fax);
3326 
3327    push_xstk_(xsp, WBITS);
3328    xsp->ap[0] = (word32) uval;
3329    xsp->bp[0] = 0L;
3330    break;
3331   /* AIV 09/08/03 - new fileio system functions */
3332   case STN_FGETC:
3333    /* c = $fgetc([fd expr]) */
3334    /* on error, this sets errno OS state var */
3335    if ((fd = chk_get_ver_fd(ndp->ru.x->lu.x)) == -1) c = -1;
3336    else
3337     {
3338      /* on error, this return EOF (-1) and sets OS err number state var */
3339      c = fgetc(__fio_fdtab[fd]->fd_s);
3340     }
3341    push_xstk_(xsp, WBITS);
3342    /* -1 becomes correct all word32 all 1's until new signed added */
3343    xsp->ap[0] = (word32) c;
3344    xsp->bp[0] = 0L;
3345    break;
3346   case STN_UNGETC:
3347    /* c = $ungetc([put back ch], [fd expr]) */
3348    /* know exactly 2 args or won't get here */
3349    ival = fio_ungetc(ndp->ru.x->lu.x, ndp->ru.x->ru.x->lu.x);
3350    push_xstk_(xsp, WBITS);
3351    /* -1 becomes correct all word32 all 1's until new signed added */
3352    xsp->ap[0] = (word32) ival;
3353    xsp->bp[0] = 0L;
3354    break;
3355   case STN_FGETS:
3356    /* format: cnt = $fgets([lhs proc str expr], [fd expr]) */
3357    /* know exactly 2 args or won't get here - returns 0 or num chs read */
3358    ival= fio_fgets(ndp->ru.x->lu.x, ndp->ru.x->ru.x->lu.x);
3359    push_xstk_(xsp, WBITS);
3360    /* 0 on error esle number of chars read */
3361    xsp->ap[0] = (word32) ival;
3362    xsp->bp[0] = 0L;
3363    break;
3364   case STN_FTELL:
3365    /* format: fpos = $ftell([fd expr]) */
3366    /* on error, this sets errno OS state var */
3367    if ((fd = chk_get_ver_fd(ndp->ru.x->lu.x)) == -1) ival = -1;
3368    else
3369     {
3370      /* on error, this return EOF (-1) and sets OS err number state var */
3371      ival = ftell(__fio_fdtab[fd]->fd_s);
3372     }
3373    push_xstk_(xsp, WBITS);
3374    /* -1 becomes correct all word32 all 1's until new signed added */
3375    xsp->ap[0] = (word32) ival;
3376    xsp->bp[0] = 0L;
3377    break;
3378   case STN_REWIND:
3379    /* format: fpos = $rewind([fd expr]) */
3380    ival = fio_rewind(ndp->ru.x->lu.x);
3381    push_xstk_(xsp, WBITS);
3382    /* -1 becomes correct all word32 all 1's until new signed added */
3383    xsp->ap[0] = (word32) ival;
3384    xsp->bp[0] = 0L;
3385    break;
3386   case STN_FSEEK:
3387    /* format: fpos = $fseek([fd expr], [ofs expr], [whence expr]) */
3388    /* syntax error does not have 3 args caught during check (in v_fx3.c) */
3389    ival = fio_fseek(ndp->ru.x->lu.x, ndp->ru.x->ru.x->lu.x,
3390     ndp->ru.x->ru.x->ru.x->lu.x);
3391    push_xstk_(xsp, WBITS);
3392    /* -1 becomes correct all word32 all 1's until new signed added */
3393    xsp->ap[0] = (word32) ival;
3394    xsp->bp[0] = 0L;
3395    break;
3396   case STN_FERROR:
3397    /* format: errnum = $ferror([fd expr], [lhs proc string]) */
3398    ival = fio_ferror(ndp->ru.x->lu.x, ndp->ru.x->ru.x->lu.x);
3399    push_xstk_(xsp, WBITS);
3400    /* -1 becomes correct all word32 all 1's until new signed added */
3401    xsp->ap[0] = (word32) ival;
3402    xsp->bp[0] = 0L;
3403    break;
3404   case STN_FREAD:
3405    /* [num chars read] = $fread([lhs proc reg expr], [fd expr]) */
3406    /* [num chars read] = $fread([mem name], [fd expr], [{starg}, {count}]) */
3407    ival = fio_fread(ndp->ru.x);
3408    push_xstk_(xsp, WBITS);
3409    /* -1 becomes correct all word32 all 1's until new signed added */
3410    xsp->ap[0] = (word32) ival;
3411    xsp->bp[0] = 0L;
3412    break;
3413   case STN_FSCANF:
3414    /* [num matched flds] = $fscanf([fd], [format], ...) */
3415    ival = fio_fscanf(ndp->ru.x);
3416    push_xstk_(xsp, WBITS);
3417    /* -1 becomes correct all word32 all 1's until new signed added */
3418    xsp->ap[0] = (word32) ival;
3419    xsp->bp[0] = 0L;
3420    break;
3421  case STN_SSCANF:
3422    /* [num matched flds] = $sscanf([string expr], [format], ...) */
3423    ival = fio_sscanf(ndp->ru.x);
3424    push_xstk_(xsp, WBITS);
3425    /* -1 becomes correct all word32 all 1's until new signed added */
3426    xsp->ap[0] = (word32) ival;
3427    xsp->bp[0] = 0;
3428    break;
3429   case STN_STIME:
3430   case STN_TIME:
3431    /* convert ticks to user time (maybe smaller) and return WBIT form */
3432    /* with warn if does not fit */
3433    /* this can be 0 - know conversion to user time always succeeds */
3434    if (!__inst_mod->mno_unitcnv)
3435     __cnv_ticks_tonum64(&timval, __simtime, __inst_mod);
3436    else timval = __simtime;
3437    if (sfbp->syfnum == STN_STIME)
3438     {
3439      push_xstk_(xsp, WBITS);
3440      if (timval > WORDMASK_ULL)
3441       {
3442        __sgfinform(411, "system function %s result does not fit in %d bits",
3443         fsyp->synam, WBITS);
3444       }
3445      xsp->ap[0] = (word32) (timval & WORDMASK_ULL);
3446      xsp->bp[0] = 0L;
3447     }
3448    else
3449     {
3450      push_xstk_(xsp, TIMEBITS);
3451      xsp->ap[0] = (word32) (timval & WORDMASK_ULL);
3452      xsp->ap[1] = (word32) ((timval >> 32) & WORDMASK_ULL);
3453      xsp->bp[0] = xsp->bp[1] = 0L;
3454     }
3455    break;
3456   case STN_REALTIME:
3457    /* for time as user world (unscaled) time, must convert to real first */
3458    d1 =__unscale_realticks(&__simtime, __inst_mod);
3459    push_xstk_(xsp, WBITS);
3460    /* copy from 1st to 2nd */
3461    memcpy(xsp->ap, &d1, sizeof(double));
3462    break;
3463   case STN_STICKSTIME:
3464    push_xstk_(xsp, WBITS);
3465    if (__simtime > WORDMASK_ULL)
3466     {
3467      __sgfinform(411, "system function %s result does not fit in %d bits",
3468       fsyp->synam, WBITS);
3469     }
3470    xsp->ap[0] = (word32) (__simtime & WORDMASK_ULL);
3471    xsp->bp[0] = 0L;
3472    break;
3473   case STN_TICKSTIME:
3474    push_xstk_(xsp, TIMEBITS);
3475    xsp->ap[0] = (word32) (__simtime & WORDMASK_ULL);
3476    xsp->ap[1] = (word32) ((__simtime >> 32) & WORDMASK_ULL);
3477    xsp->bp[0] = xsp->bp[1] = 0L;
3478    break;
3479   case STN_BITSTOREAL:
3480    /* this converts the a parts of a 64 bit reg to a wbit real */
3481    /* know this will be 64 bit or previous error */
3482    fax = ndp->ru.x->lu.x;
3483    xsp = __eval_xpr(fax);
3484    if (xsp->xslen != 64)
3485     {
3486      __sgfwarn(636, "$bitstoreal of %s value not 64 bits - set to 0",
3487       __regab_tostr(__xs, xsp->ap, xsp->bp, xsp->xslen, BHEX, FALSE));
3488 conv_0:
3489      d1 = 0.0;
3490      memcpy(xsp->ap, &d1, sizeof(double));
3491      /* SJM 07/05/03 - need to also adjust b part for real */
3492      xsp->xslen = WBITS;
3493      xsp->bp = &(xsp->ap[1]);
3494      break;
3495     }
3496 
3497    /* notice must silently convert x to 0.0, since port will start at x */
3498    if (!vval_is0_(xsp->bp, xsp->xslen)) goto conv_0;
3499    /* finally, convert to real - assuming bits good - should convert to */
3500    /* something and see what error code is set ? */
3501    /* this is stupid but allow looking at the number in debugger */
3502    memcpy(&d1, xsp->ap, sizeof(double));
3503    /* DBG - LOOKATME - why here
3504    if (finite(d1) == 0) __arg_terr(__FILE__, __LINE__);
3505    -- */
3506    memcpy(xsp->ap, &d1, sizeof(double));
3507 
3508    xsp->bp = &(xsp->ap[1]);
3509    xsp->xslen = WBITS;
3510    break;
3511   case STN_REALTOBITS:
3512    push_xstk_(xsp, 64);
3513    fax = ndp->ru.x->lu.x;
3514    xsp2 = __eval_xpr(fax);
3515    /* notice double stored with b (x/z) part as WBITS really 64 */
3516    xsp->ap[0] = xsp2->ap[0];
3517    xsp->ap[1] = xsp2->bp[0];
3518    xsp->bp[0] = xsp->bp[1] = 0L;
3519    __pop_xstk();
3520    break;
3521   case STN_ITOR:
3522    /* know arg must be 32 or narrower */
3523    fax = ndp->ru.x->lu.x;
3524    xsp = __eval_xpr(fax);
3525    if (xsp->bp[0] != 0L)
3526     {
3527      __sgfwarn(631,
3528       "system function %s argument %s x/z value converted to 0.0",
3529        fsyp->synam, __msgexpr_tostr(__xs, fax));
3530      d1 = 0.0;
3531     }
3532    else
3533     {
3534      if (fax->has_sign) { ival = (int32) xsp->ap[0]; d1 = (double) ival; }
3535      else d1 = (double) xsp->ap[0];
3536     }
3537    /* notice reusing xsp since know size of both is WBITS */
3538    memcpy(xsp->ap, &d1, sizeof(double));
3539    break;
3540   case STN_RTOI:
3541    /* think semantics is to convert keeping sign - number maybe 2's compl */
3542    fax = ndp->ru.x->lu.x;
3543    xsp = __eval_xpr(fax);
3544    memcpy(&d1, xsp->ap, sizeof(double));
3545    /* DBG - LOOKATME - why here
3546    if (finite(d1) == 0) __arg_terr(__FILE__, __LINE__);
3547    -- */
3548    ival = (int32) d1;
3549    /* reuse expr. that know is WBITS */
3550    xsp->bp[0] = 0L;
3551    xsp->ap[0] = (word32) ival;
3552    break;
3553   case STN_SIGNED:
3554    /* this must eval its argument and then return its value */
3555    /* signed is just marking expr - no bit pattern change */
3556    fax = ndp->ru.x->lu.x;
3557    xsp = __eval_xpr(fax);
3558    /* 05/26/04 - may need size change here to mach fcall node size */
3559    if (xsp->xslen != ndp->szu.xclen)
3560     {
3561      if (xsp->xslen < ndp->szu.xclen) __sgn_xtnd_wrd(xsp, ndp->szu.xclen);
3562      else __narrow_sizchg(xsp, ndp->szu.xclen);
3563     }
3564    break;
3565   case STN_UNSIGNED:
3566    /* this must eval its argument and then return its value */
3567    /* word32 is just marking expr - no bit pattern change */
3568    fax = ndp->ru.x->lu.x;
3569    xsp = __eval_xpr(fax);
3570 
3571    /* 05/26/04 - may need size change here to mach fcall node size */
3572    /* but know result always word32 */
3573    if (xsp->xslen != ndp->szu.xclen) __sizchgxs(xsp, ndp->szu.xclen);
3574 
3575    /* because function return value has exactly same width as arg - never */
3576    /* need conversion */
3577    /* DBG remove -- */
3578    if (fax->szu.xclen != xsp->xslen) __misc_terr(__FILE__, __LINE__);
3579    /* --- */
3580    break;
3581   case STN_RANDOM:
3582    __exec_sfrand(ndp);
3583    break;
3584   case STN_COUNT_DRIVERS:
3585    exec_count_drivers(ndp);
3586    break;
3587   case STN_DIST_UNIFORM:
3588    __exec_dist_uniform(ndp);
3589    break;
3590   case STN_DIST_EXPONENTIAL:
3591    __exec_dist_exp(ndp);
3592    break;
3593   case STN_DIST_NORMAL:
3594    __exec_dist_stdnorm(ndp);
3595    break;
3596   case STN_DIST_CHI_SQUARE:
3597    __exec_chi_square(ndp);
3598    break;
3599   case STN_DIST_POISSON:
3600    __exec_dist_poisson(ndp);
3601    break;
3602   case STN_DIST_T:
3603    __exec_dist_t(ndp);
3604    break;
3605 
3606   case STN_DIST_ERLANG:
3607    /* not yet implemented make 32 bit x */
3608    __sgfwarn(550, "system function %s not implemented - returning 32'bx",
3609     fsyp->synam);
3610    push_xstk_(xsp, WBITS);
3611    xsp->ap[0] = ALL1W;
3612    xsp->bp[0] = ALL1W;
3613    break;
3614   case STN_Q_FULL:
3615    exec_qfull(ndp);
3616    break;
3617   case STN_SCALE:
3618    fax = ndp->ru.x->lu.x;
3619    /* DBG remove */
3620    if (fax->optyp != GLBREF) __arg_terr(__FILE__, __LINE__);
3621    /* --- */
3622    /* this puts scale value on top of stack */
3623    __exec_scale(fax);
3624    break;
3625   case STN_TESTPLUSARGS:
3626    exec_testplusargs(ndp);
3627    break;
3628   case STN_SCANPLUSARGS:
3629    exec_scanplusargs(ndp);
3630    break;
3631   case STN_VALUEPLUSARGS:
3632    exec_valueplusargs(ndp);
3633    break;
3634   case STN_RESET_COUNT:
3635    push_xstk_(xsp, WBITS);
3636    xsp->ap[0] = (word32) __reset_count;
3637    xsp->bp[0] = 0L;
3638    break;
3639   case STN_RESET_VALUE:
3640    push_xstk_(xsp, WBITS);
3641    /* value may be int32 (signed) - caller will interpret */
3642    xsp->ap[0] = (word32) __reset_value;
3643    xsp->bp[0] = 0L;
3644    break;
3645   case STN_GETPATTERN:
3646    /* should never see get pattern here */
3647    __arg_terr(__FILE__, __LINE__);
3648    break;
3649   case STN_COS: case STN_SIN: case STN_TAN:
3650   case STN_ACOS: case STN_ASIN: case STN_ATAN:
3651   case STN_COSH: case STN_SINH: case STN_TANH:
3652   case STN_ACOSH: case STN_ASINH: case STN_ATANH:
3653   case STN_LN: case STN_LOG10: case STN_ABS: case STN_SQRT: case STN_EXP:
3654   case STN_HSQRT: case STN_HLOG: case STN_HLOG10: case STN_HDB:
3655    fax = ndp->ru.x->lu.x;
3656    exec_1arg_transcendental(sfbp->syfnum, fax);
3657    break;
3658   case STN_INT:
3659    exec_transcendental_int(ndp);
3660    break;
3661   case STN_SGN:
3662    exec_transcendental_sign(ndp);
3663    break;
3664   case STN_POW: case STN_HPOW: case STN_HPWR: case STN_HSIGN:
3665    exec_transcendental_powsign(sfbp->syfnum, ndp);
3666    break;
3667   case STN_MIN: case STN_MAX:
3668    exec_transcendental_minmax(sfbp->syfnum, ndp);
3669    break;
3670   case STN_ATAN2:
3671    exec_transcendental_atan2(ndp);
3672    break;
3673   case STN_HYPOT:
3674    exec_transcendental_hypot(ndp);
3675    break;
3676   default:
3677    /* DBG remove --- */
3678    if (sfbp->syfnum < BASE_VERIUSERTFS || (int32) sfbp->syfnum > __last_systf)
3679     __case_terr(__FILE__, __LINE__);
3680    /* --- */
3681    /* call pli system function calltf here - leave ret. value on stk */
3682    if (sfbp->syfnum <= __last_veriusertf) __pli_func_calltf(ndp);
3683    /* vpi_ systf after veriusertfs up to last systf */
3684    else __vpi_sysf_calltf(ndp);
3685  }
3686 }
3687 
3688 /*
3689  * execute the count driver system function
3690  * notice these leave return (count) on expr. stack
3691  * change so count forced when force implemented
3692  */
exec_count_drivers(struct expr_t * ndp)3693 static void exec_count_drivers(struct expr_t *ndp)
3694 {
3695  register struct net_pin_t *npp;
3696  register struct expr_t *axp;
3697  register int32 i;
3698  int32 ri1, ri2, nd_itpop, biti, indi, is_forced, numdrvs, drvcnt[4];
3699  word32 val;
3700  byte *sbp;
3701  struct net_t *np;
3702  struct xstk_t *xsp;
3703  struct expr_t *idndp;
3704  struct gref_t *grp;
3705 
3706  nd_itpop = FALSE;
3707  for (i = 0; i < 4; i++) drvcnt[i] = 0;
3708  is_forced = 0;
3709  numdrvs = 0;
3710  biti = -1;
3711  /* first get 1st argument value */
3712  axp = ndp->ru.x->lu.x;
3713  /* know if bit select will be non x or earlier error to stop execution */
3714  if (axp->optyp == LSB)
3715   {
3716    /* must eval. index expr. in ref. not target in case xmr */
3717    xsp = __eval_xpr(axp->ru.x);
3718    biti = xsp->ap[0];
3719    __pop_xstk();
3720    idndp = axp->lu.x;
3721   }
3722  else idndp = axp;
3723 
3724  if (idndp->optyp == GLBREF)
3725   {
3726    grp = idndp->ru.grp;
3727    __xmrpush_refgrp_to_targ(grp);
3728    nd_itpop = TRUE;
3729   }
3730  np = idndp->lu.sy->el.enp;
3731 
3732  if (biti == -1) indi = 0; else indi = biti;
3733  if (np->frc_assgn_allocated)
3734   {
3735    if (np->ntyp >= NONWIRE_ST)
3736     {
3737      if (np->nu2.qcval[2*__inum].qc_active ||
3738       np->nu2.qcval[2*__inum + 1].qc_active) is_forced = TRUE;
3739      }
3740    else
3741     {
3742      if (np->nu2.qcval[np->nwid*__inum + indi].qc_active)
3743       is_forced = TRUE;
3744     }
3745   }
3746 
3747  /* since just evaluating read only must evaluate all drivers in here */
3748  /* inout itp and inout mpp NULL which is needed */
3749  for (npp = np->ndrvs; npp != NULL; npp = npp->npnxt)
3750   {
3751    if (npp->npproctyp == NP_PROC_FILT
3752     && npp->npaux->npu.filtitp != __inst_ptr) continue;
3753 
3754    /* need to handle -2 IS specific bit select */
3755    __get_bidnpp_sect(np, npp, &ri1, &ri2);
3756    if (npp->npaux == NULL || ri1 == -1 || biti == -1) goto got_match;
3757    if (biti > ri1 || biti < ri2) continue;
3758 
3759 got_match:
3760    /* need to make sure driver is loaded - no concept of changing here */
3761    switch (npp->npntyp) {
3762     case NP_VPIPUTV:
3763      /* for added vpi driver - this inst. or bit may not be added */
3764      /* if not added (used), do not count */
3765      if (!__has_vpi_driver(np, npp)) continue;
3766      goto load_driver;
3767 
3768     case NP_GATE: case NP_CONTA: case NP_MDPRT: case NP_PB_MDPRT:
3769     case NP_ICONN: case NP_TFRWARG:
3770 load_driver:
3771      /* load driver leaves value on expr. stack */
3772      if (np->n_stren)
3773       {
3774        if ((xsp = __ld_stwire_driver(npp)) == NULL) break;
3775        sbp = (byte *) xsp->ap;
3776        val = sbp[indi] & 3;
3777        __pop_xstk();
3778       }
3779      else
3780       {
3781        xsp = __ld_wire_driver(npp);
3782        if (biti == -1) val = (xsp->ap[0] & 1L) | ((xsp->bp[0] & 1L) << 1);
3783        else val = (rhsbsel_(xsp->ap, biti)) | (rhsbsel_(xsp->bp, biti) << 1);
3784        __pop_xstk();
3785       }
3786      (drvcnt[val])++;
3787      break;
3788     case NP_PULL: break;
3789     default: __case_terr(__FILE__, __LINE__);
3790    }
3791    /* other drivers such as pull just ingored in determing drivers */
3792   }
3793  if (nd_itpop) __pop_itstk();
3794 
3795  /* finally do the storing */
3796  numdrvs = drvcnt[0] + drvcnt[1] + drvcnt[3];
3797  /* know at least one argument */
3798  push_xstk_(xsp, WBITS);
3799  xsp->ap[0] = 0;
3800  xsp->bp[0] = 0;
3801  if ((axp = ndp->ru.x->ru.x) == NULL) goto just_ret;
3802  for (i = 1; axp != NULL; axp = axp->ru.x, i++)
3803   {
3804    if (axp->lu.x->optyp == OPEMPTY) continue;
3805    switch ((byte) i) {
3806     case 1: xsp->ap[0] = (word32) is_forced; break;
3807     case 2: xsp->ap[0] = (word32) numdrvs; break;
3808     /* next 3 are 0, 1, and x drivers */
3809     case 3: xsp->ap[0] = (word32) drvcnt[0]; break;
3810     case 4: xsp->ap[0] = (word32) drvcnt[1]; break;
3811     case 5: xsp->ap[0] = (word32) drvcnt[3]; break;
3812     default: __case_terr(__FILE__, __LINE__);
3813    }
3814    __exec2_proc_assign(axp->lu.x, xsp->ap, xsp->bp);
3815   }
3816 just_ret:
3817  xsp->ap[0] = (numdrvs > 1) ? 1 : 0;
3818 }
3819 
3820 
3821 /*
3822  * execute the test plus args system function
3823  * argument does not include the plus
3824  */
exec_testplusargs(struct expr_t * ndp)3825 static void exec_testplusargs(struct expr_t *ndp)
3826 {
3827  int32 slen;
3828  register struct optlst_t *olp;
3829  register char *chp, *argchp;
3830  int32 rv;
3831  struct xstk_t *xsp;
3832 
3833  argchp = __get_eval_cstr(ndp->ru.x->lu.x, &slen);
3834  for (rv = 0, olp = __opt_hdr; olp != NULL; olp = olp->optlnxt)
3835   {
3836    /* ignore markers added for building vpi argc/argv */
3837    if (olp->is_bmark || olp->is_emark) continue;
3838 
3839    chp = olp->opt;
3840    if (*chp != '+') continue;
3841    if (strcmp(&(chp[1]), argchp) == 0) { rv = 1; break; }
3842   }
3843  push_xstk_(xsp, WBITS);
3844  xsp->bp[0] = 0L;
3845  xsp->ap[0] = (word32) rv;
3846  __my_free(argchp, slen + 1);
3847 }
3848 
3849 /*
3850  * execute the scan plus args added system function
3851  * same function as mc_scan_plusargs but assigns to 2nd parameter
3852  * almost same code as mc scan plus args pli system task
3853  * argument does not include the '+'
3854  */
exec_scanplusargs(struct expr_t * ndp)3855 static void exec_scanplusargs(struct expr_t *ndp)
3856 {
3857  register struct optlst_t *olp;
3858  register char *chp;
3859  int32 arglen, rv;
3860  struct expr_t *fax;
3861  struct xstk_t *xsp;
3862  char *plusarg;
3863 
3864  fax = ndp->ru.x;
3865  /* this is the passed argment prefix */
3866  plusarg = __get_eval_cstr(fax->lu.x, &arglen);
3867 
3868  /* all options expanded and saved so this is easy */
3869  for (rv = 0, olp = __opt_hdr; olp != NULL; olp = olp->optlnxt)
3870   {
3871    /* ignore markers added for building vpi argc/argv */
3872    if (olp->is_bmark || olp->is_emark) continue;
3873 
3874    chp = olp->opt;
3875    if (*chp != '+') continue;
3876 
3877    /* option length if the length of the command line plus option string */
3878    /* option must be at least as long as passed arg or cannot match */
3879    if (strlen(chp) < arglen) continue;
3880    /* match prefix - arg. is same or narrow that plus command line option */
3881    if (strncmp(&(chp[1]), plusarg, arglen) == 0)
3882     {
3883      rv = 1;
3884      xsp = __cstr_to_vval(&(chp[arglen + 1]));
3885      /* move to next - assign to arg */
3886      fax = fax->ru.x;
3887 
3888      /* SJM 05/10/04 - think this can be signed */
3889      if (xsp->xslen != fax->lu.x->szu.xclen)
3890       {
3891        if (xsp->xslen < fax->lu.x->szu.xclen && fax->lu.x->has_sign)
3892         __sgn_xtnd_wrd(xsp, fax->lu.x->szu.xclen);
3893        else __sizchgxs(xsp, fax->lu.x->szu.xclen);
3894       }
3895 
3896      __exec2_proc_assign(fax->lu.x, xsp->ap, xsp->bp);
3897      __pop_xstk();
3898      break;
3899     }
3900   }
3901  push_xstk_(xsp, WBITS);
3902  xsp->bp[0] = 0L;
3903  xsp->ap[0] = (word32) rv;
3904  __my_free(plusarg, arglen + 1);
3905 }
3906 
3907 /*
3908  * execute the $value$plusargs system function
3909  * takes a string with a single format and places the value into a single
3910  * variable passed as the second argument
3911  *
3912  * works by dividing string from the variable name and the format
3913  * so "TEST=%d", becomes two strings "TEST=" and "%d"
3914  * when it is passed to scanf routine
3915  *
3916  * returns TRUE on success fails returns FALSE
3917  * $value$plusargs("TEST=%d", var)
3918  * takes +TEST=3 off command line and places value (format %) into var
3919  */
exec_valueplusargs(struct expr_t * ndp)3920 static void exec_valueplusargs(struct expr_t *ndp)
3921 {
3922  register struct optlst_t *olp;
3923  register char *chp;
3924  int32 arglen, rv, i, j, namlen, saverrno;
3925  struct expr_t *fax;
3926  struct xstk_t *xsp;
3927  char *plusarg;
3928  char format[RECLEN];
3929 
3930  fax = ndp->ru.x;
3931  /* this is the passed argment prefix */
3932  plusarg = __get_eval_cstr(fax->lu.x, &arglen);
3933 
3934  rv = FALSE;
3935  chp = plusarg;
3936  /* namlen is the name of the +variable minus the format */
3937  namlen = -1;
3938  /* get the +variable without the format */
3939  for (i = 0; i < arglen; i++, chp++)
3940   {
3941    /* first '%' found probably the format */
3942    if (*chp == '%')
3943     {
3944      /* check for escaped '%%' */
3945      if (i+1 < arglen && *(chp+1) == '%')
3946       {
3947        i++; chp++;
3948       }
3949      else break;
3950     }
3951   }
3952 
3953  /* the one format has to have at least '%d' */
3954  if (i > (arglen-2))
3955   {
3956    __sgferr(1300, "$value$plusargs string '%s' doesn't contain a format",
3957     plusarg);
3958    goto done;
3959   }
3960 
3961   /* end of +variable name */
3962   namlen = i;
3963   j = 0;
3964   /* the one format has to have at least '%d' */
3965   format[j++] = *chp++;
3966   /* add the number format */
3967   while (isdigit(*chp))
3968    {
3969     format[j++] = *chp++;
3970    }
3971   /* check to make sure the format is valid */
3972   switch (*chp) {
3973    case 'd':
3974    case 'o':
3975    case 'h':
3976    case 'b':
3977    case 'e':
3978    case 'f':
3979    case 'g':
3980    case 's':
3981     format[j++] = *chp;
3982     /* the fomat has to be the end of the string */
3983     if (i+j == arglen)
3984      {
3985       format[j] = '\0';
3986       break;
3987      }
3988     /* FALLTHRU */
3989    default:
3990     __sgferr(1301, "$value$plusargs string '%s' contains illegal format",
3991      plusarg);
3992     goto done;
3993     break;
3994   }
3995 
3996  /* this part just the same as $scan$plusargs */
3997  for (olp = __opt_hdr; olp != NULL; olp = olp->optlnxt)
3998   {
3999    /* ignore markers added for building vpi argc/argv */
4000    if (olp->is_bmark || olp->is_emark) continue;
4001 
4002    chp = olp->opt;
4003    if (*chp != '+') continue;
4004 
4005    /* option length if the length of the command line plus option string */
4006    /* option must be at least as long as passed arg or cannot match */
4007    if (strlen(chp) < namlen) continue;
4008    /* match prefix - arg. is same or narrow that plus command line option */
4009    if (strncmp(&(chp[1]), plusarg, namlen) == 0)
4010     {
4011      /* set the scanf format string */
4012      /* SJM 09/28/06 - can't pass local var pointed to by global */
4013      __fiofp = __pv_stralloc(format);
4014      /* pass the string value */
4015      __fiolp = &(chp[namlen+1]);
4016      /* move to next - assign to arg */
4017      fax = fax->ru.x;
4018      /* save and restore errno since it isn't an IO operation */
4019      saverrno = errno;
4020      /* get the format */
4021      rv = fio_exec_scanf(NULL, fax);
4022      __my_free(__fiofp, strlen(__fiofp) + 1);
4023      errno = saverrno;
4024      if (rv == -1) rv = FALSE;
4025      else rv = TRUE;
4026      break;
4027     }
4028   }
4029 done:
4030  push_xstk_(xsp, WBITS);
4031  xsp->bp[0] = 0L;
4032  xsp->ap[0] = (word32) rv;
4033  __my_free(plusarg, arglen + 1);
4034 }
4035 
4036 /*
4037  * execute 1 real in returns real transcendental
4038  * places computed real on to expr stack
4039  */
exec_1arg_transcendental(int32 syfnum,struct expr_t * fax)4040 static void exec_1arg_transcendental(int32 syfnum, struct expr_t *fax)
4041 {
4042  double d1, d2;
4043  struct xstk_t *xsp;
4044 
4045  /* this pushes avaluated expressions onto stack - always real and replaced */
4046  xsp = __eval_xpr(fax);
4047  if (!fax->is_real) d1 = __cnvt_stk_to_real(xsp, (fax->has_sign == 1));
4048  else memcpy(&d1, xsp->ap, sizeof(double));
4049 
4050  /* DBG - LOOKATME - why here
4051  if (finite(d1) == 0) __arg_terr(__FILE__, __LINE__);
4052  -- */
4053  switch (syfnum) {
4054   case STN_COS: d2 = cos(d1); break;
4055   case STN_SIN: d2 = sin(d1); break;
4056   case STN_TAN: d2 = tan(d1); break;
4057   case STN_ACOS:
4058    if (d1 < -1.0 || d1 > 1.0)
4059     {
4060      __sgfwarn(631,
4061       "$acos system function argument %s outside -1 to 1 legal range - returning 0.0",
4062        __msgexpr_tostr(__xs, fax));
4063      d2 = 0.0;
4064     }
4065    else d2 = acos(d1);
4066    break;
4067   case STN_ACOSH:
4068    if (d1 < 1.0)
4069     {
4070      __sgfwarn(631,
4071       "$acosh system function argument %s outside 1 to inf legal range - returning 0.0",
4072        __msgexpr_tostr(__xs, fax));
4073      d2 = 0.0;
4074     }
4075    else d2 = acosh(d1);
4076    break;
4077   case STN_ASIN:
4078    if (d1 < -1.0 || d1 > 1.0)
4079     {
4080      __sgfwarn(631,
4081       "$asin system function argument %s outside -1 to 1 legal range - returning 0.0",
4082        __msgexpr_tostr(__xs, fax));
4083      d2 = 0.0;
4084     }
4085    else d2 = asin(d1);
4086    break;
4087   case STN_ASINH: d2 = asinh(d1); break;
4088   case STN_ATAN: d2 = atan(d1); break;
4089   case STN_COSH: d2 = cosh(d1); break;
4090   case STN_SINH: d2 = sinh(d1); break;
4091   case STN_TANH: d2 = tanh(d1); break;
4092   case STN_ATANH:
4093    if (d1 < -1.0 || d1 > 1.0)
4094     {
4095      __sgfwarn(631,
4096       "$atanh system function argument %s outside -1 to 1 legal range - returning 0.0",
4097        __msgexpr_tostr(__xs, fax));
4098      d2 = 0.0;
4099     }
4100    else d2 = atanh(d1);
4101    break;
4102   case STN_LN:
4103    if (d1 <= 0.0)
4104     {
4105      __sgfwarn(631,
4106       "$ln system function argument %s illegal non positive - returning 0.0",
4107        __msgexpr_tostr(__xs, fax));
4108      d2 = 0.0;
4109     }
4110    else d2 = log(d1);
4111    break;
4112   case STN_LOG10:
4113    if (d1 <= 0.0)
4114     {
4115      __sgfwarn(631,
4116       "$log10 system function argument %s illegal non positive - returning 0.0",
4117        __msgexpr_tostr(__xs, fax));
4118      d2 = 0.0;
4119     }
4120    else d2 = log10(d1);
4121    break;
4122   case STN_ABS: d2 = fabs(d1); break;
4123   case STN_SQRT:
4124    if (d1 < 0.0)
4125     {
4126      __sgfwarn(631,
4127       "$sqrt system function argument %s illegal negative - returning 0.0",
4128        __msgexpr_tostr(__xs, fax));
4129      d2 = 0.0;
4130     }
4131    else d2 = sqrt(d1);
4132    break;
4133   case STN_EXP: d2 = exp(d1); break;
4134   case STN_HSQRT:
4135    if (d1 >= 0.0) d2 = sqrt(d1); else d2 = -sqrt(-d1);
4136    break;
4137   case STN_HLOG:
4138    if (d1 > 0.0) d2 = log(d1);
4139    else if (d1 == 0.0) d2 = 0.0;
4140    else d2 = -log(-d1);
4141    break;
4142   case STN_HLOG10:
4143    if (d1 > 0.0) d2 = log10(d1);
4144    else if (d1 == 0.0) d2 = 0.0;
4145    else d2 = -log10(-d1);
4146    break;
4147   case STN_HDB:
4148    if (d1 > 0.0) d2 = log(d1);
4149    else if (d1 == 0.0) d2 = 0.0;
4150    else d2 = -20.0*log(-d1);
4151    break;
4152   default: d2 = 0.0; __case_terr(__FILE__, __LINE__);
4153  }
4154  memcpy(xsp->ap, &d2, sizeof(double));
4155  xsp->bp = &(xsp->ap[1]);
4156  xsp->xslen = WBITS;
4157 }
4158 
4159 /*
4160  * execute transcendental int32 (convert to int32) routine
4161  */
exec_transcendental_int(struct expr_t * ndp)4162 static void exec_transcendental_int(struct expr_t *ndp)
4163 {
4164  int32 ival;
4165  double d1;
4166  struct expr_t *fax;
4167  struct xstk_t *xsp;
4168 
4169  /* this returns 32 bit signed reg aka integer not real */
4170  fax = ndp->ru.x->lu.x;
4171  xsp = __eval_xpr(fax);
4172  if (!fax->is_real)
4173   {
4174    if (xsp->xslen > WBITS) __narrow_to1wrd(xsp);
4175    else
4176     {
4177      /* SJM 05/10/04 - old style convert to int32 - needs sign extension */
4178      if (xsp->xslen < WBITS) __sgn_xtnd_wrd(xsp, fax->szu.xclen);
4179     }
4180 
4181    if (xsp->bp[0] != 0) { xsp->ap[0] = ALL1W; xsp->bp[0] = ALL1W; }
4182    else
4183     {
4184      /* LOOKATME - does this do anything? */
4185      ival = (int32) xsp->ap[0];
4186      xsp->ap[0] = (word32) ival;
4187     }
4188   }
4189  else
4190   {
4191    memcpy(&d1, xsp->ap, sizeof(double));
4192    ival = (int32) d1;
4193    xsp->bp[0] = 0L;
4194    xsp->ap[0] = (word32) ival;
4195   }
4196  /* reuse xstk that know is now WBITS */
4197 }
4198 
4199 /*
4200  * execute transcendental sign routine
4201  */
exec_transcendental_sign(struct expr_t * ndp)4202 static void exec_transcendental_sign(struct expr_t *ndp)
4203 {
4204  int32 ival;
4205  double d1;
4206  struct expr_t *fax;
4207  struct xstk_t *xsp;
4208 
4209  /* this returns 32 bit signed reg aka integer not real */
4210  fax = ndp->ru.x->lu.x;
4211 
4212  xsp = __eval_xpr(fax);
4213  if (!fax->is_real) d1 = __cnvt_stk_to_real(xsp, (fax->has_sign == 1));
4214  else memcpy(&d1, xsp->ap, sizeof(double));
4215  if (d1 < 0) ival = -1; else if (d1 > 0) ival = 1; else ival = 0;
4216  /* reuse xstk that know is WBITS */
4217  xsp->bp[0] = 0L;
4218  xsp->ap[0] = (word32) ival;
4219 }
4220 
4221 /*
4222  * exec transcendental pow - takes 2 args
4223  * also hspice sign with 2 args here
4224  */
exec_transcendental_powsign(int32 sysfnum,struct expr_t * ndp)4225 static void exec_transcendental_powsign(int32 sysfnum, struct expr_t *ndp)
4226 {
4227  int32 ival;
4228  double d1, d2, d3;
4229  struct expr_t *fax, *fax2;
4230  struct xstk_t *xsp;
4231 
4232  ndp = ndp->ru.x;
4233  fax = ndp->lu.x;
4234  xsp = __eval_xpr(fax);
4235  if (!fax->is_real) d1 = __cnvt_stk_to_real(xsp, (fax->has_sign == 1));
4236  else memcpy(&d1, xsp->ap, sizeof(double));
4237  __pop_xstk();
4238 
4239  ndp = ndp->ru.x;
4240  fax2 = ndp->lu.x;
4241  xsp = __eval_xpr(fax2);
4242  if (!fax2->is_real) d2 = __cnvt_stk_to_real(xsp, (fax2->has_sign == 1));
4243  else memcpy(&d2, xsp->ap, sizeof(double));
4244 
4245  d3 = 0.0;
4246  if (sysfnum == STN_POW)
4247   {
4248    if (d1 < 0.0)
4249     {
4250      double d4;
4251 
4252      /* notice this uses hspice not Verilog conversion to int32 - matters not */
4253      ival = (int32) d2;
4254      d4 = ival;
4255      /* != real */
4256      if ((d4 - d2) <= -EPSILON && (d4 - d2) >= EPSILON)
4257       {
4258        __sgfwarn(631,
4259         "$pow system function argument first argument %s negative and second argument %s non integral - returning 0.0",
4260        __msgexpr_tostr(__xs, fax), __msgexpr_tostr(__xs2, fax2));
4261        d2 = 0.0;
4262       }
4263      else d3 = pow(d1, d2);
4264     }
4265    else d3 = pow(d1, d2);
4266   }
4267  else if (sysfnum == STN_HPOW)
4268   {
4269    /* LOOKATME - notice this uses Hspice not Verilog conversion to int32 */
4270    ival = (int32) d2;
4271    d2 = ival;
4272    d3 = pow(d1, d2);
4273   }
4274  else if (sysfnum == STN_HPWR)
4275   {
4276    if (d1 > 0.0) d3 = pow(d1, d2);
4277    else if (d1 == 0.0) d3 = 0.0;
4278    else d3 = -pow(-d1, d2);
4279   }
4280  else if (sysfnum == STN_HSIGN)
4281   {
4282    /* notice $hsign returns double but $sign returns int32 */
4283    if (d2 > 0.0) d3 = fabs(d1);
4284    else if (d2 == 0.0) d3 = 0.0;
4285    else d3 = -fabs(d1);
4286   }
4287  else { d3 = 0.0; __case_terr(__FILE__, __LINE__); }
4288 
4289  memcpy(xsp->ap, &d3, sizeof(double));
4290  xsp->bp = &(xsp->ap[1]);
4291  xsp->xslen = WBITS;
4292 }
4293 
4294 /*
4295  * exec transcendental min/max - takes 2 args
4296  * LOOKATME - since can do with arg macro maybe unneeded
4297  */
exec_transcendental_minmax(int32 syfnum,struct expr_t * ndp)4298 static void exec_transcendental_minmax(int32 syfnum, struct expr_t *ndp)
4299 {
4300  double d1, d2, d3;
4301  struct expr_t *fax;
4302  struct xstk_t *xsp;
4303 
4304  ndp = ndp->ru.x;
4305  fax = ndp->lu.x;
4306  xsp = __eval_xpr(fax);
4307  if (!fax->is_real) d1 = __cnvt_stk_to_real(xsp, (fax->has_sign == 1));
4308  else memcpy(&d1, xsp->ap, sizeof(double));
4309  __pop_xstk();
4310 
4311  ndp = ndp->ru.x;
4312  fax = ndp->lu.x;
4313  xsp = __eval_xpr(fax);
4314  if (!fax->is_real) d2 = __cnvt_stk_to_real(xsp, (fax->has_sign == 1));
4315  else memcpy(&d2, xsp->ap, sizeof(double));
4316 
4317  if (syfnum == STN_MIN) d3 = (d1 < d2) ? d1 : d2;
4318  else d3 = (d1 > d2) ? d1 : d2;
4319 
4320  memcpy(xsp->ap, &d3, sizeof(double));
4321 
4322  xsp->bp = &(xsp->ap[1]);
4323  xsp->xslen = WBITS;
4324 }
4325 
4326 /*
4327  * exec transcendental atan2 - takes 2 args
4328  */
exec_transcendental_atan2(struct expr_t * ndp)4329 static void exec_transcendental_atan2(struct expr_t *ndp)
4330 {
4331  double d1, d2, d3;
4332  struct expr_t *fax;
4333  struct xstk_t *xsp;
4334 
4335  ndp = ndp->ru.x;
4336  fax = ndp->lu.x;
4337  xsp = __eval_xpr(fax);
4338  if (!fax->is_real) d1 = __cnvt_stk_to_real(xsp, (fax->has_sign == 1));
4339  else memcpy(&d1, xsp->ap, sizeof(double));
4340  __pop_xstk();
4341 
4342  ndp = ndp->ru.x;
4343  fax = ndp->lu.x;
4344  xsp = __eval_xpr(fax);
4345  if (!fax->is_real) d2 = __cnvt_stk_to_real(xsp, (fax->has_sign == 1));
4346  else memcpy(&d2, xsp->ap, sizeof(double));
4347 
4348  d3 = atan2(d1, d2);
4349  memcpy(xsp->ap, &d3, sizeof(double));
4350 
4351  xsp->bp = &(xsp->ap[1]);
4352  xsp->xslen = WBITS;
4353 }
4354 
4355 /*
4356  * exec transcendental hypot (dist func) - takes 2 args
4357  */
exec_transcendental_hypot(struct expr_t * ndp)4358 static void exec_transcendental_hypot(struct expr_t *ndp)
4359 {
4360  double d1, d2, d3;
4361  struct expr_t *fax;
4362  struct xstk_t *xsp;
4363 
4364  ndp = ndp->ru.x;
4365  fax = ndp->lu.x;
4366  xsp = __eval_xpr(fax);
4367  if (!fax->is_real) d1 = __cnvt_stk_to_real(xsp, (fax->has_sign == 1));
4368  else memcpy(&d1, xsp->ap, sizeof(double));
4369  __pop_xstk();
4370 
4371  ndp = ndp->ru.x;
4372  fax = ndp->lu.x;
4373  xsp = __eval_xpr(fax);
4374  if (!fax->is_real) d2 = __cnvt_stk_to_real(xsp, (fax->has_sign == 1));
4375  else memcpy(&d2, xsp->ap, sizeof(double));
4376 
4377  d3 = hypot(d1, d2);
4378  memcpy(xsp->ap, &d3, sizeof(double));
4379 
4380  xsp->bp = &(xsp->ap[1]);
4381  xsp->xslen = WBITS;
4382 }
4383 
4384 
4385 /*
4386  * ROUTINES TO EXEC CAUSE
4387  */
4388 
4389 /*
4390  * execute a cause statement
4391  * this is simply an assign to the event variable - gets added to net chg
4392  * as normal var change and during prep has normal dce npp's built
4393  */
exec_cause(struct st_t * stp)4394 static void exec_cause(struct st_t *stp)
4395 {
4396  int32 nd_itpop;
4397  struct expr_t *xp;
4398  struct net_t *np;
4399  struct gref_t *grp;
4400 
4401  if (__st_tracing)
4402   __tr_msg("trace: %-7d -> %s\n", __slin_cnt,
4403    __to_idnam(stp->st.scausx));
4404  xp = stp->st.scausx;
4405  nd_itpop = FALSE;
4406  if (xp->optyp == GLBREF)
4407   {
4408    /* idea for xmr cause is to cause an event in some other part of the */
4409    /* itree - by changine current itree place will match waits only in */
4410    /* target of cause instance */
4411    grp = xp->ru.grp;
4412    __xmrpush_refgrp_to_targ(grp);
4413    nd_itpop = TRUE;
4414   }
4415  else if (xp->optyp != ID) __case_terr(__FILE__, __LINE__);
4416 
4417  /* notice even if global ref. can still get net from symbol */
4418  np = xp->lu.sy->el.enp;
4419  /* notice cause does nothing - just schedules trigger for each waiting */
4420  /* armed ectrl - so any waiting event control blocks will be activated */
4421 
4422  /* record cause event var change as usual, if no pending do not record */
4423  /* must not record or will be worse event ordering dependency */
4424  /* know change see if need to record - also maybe dmpvars */
4425  record_nchg_(np);
4426 
4427  if (nd_itpop) __pop_itstk();
4428 }
4429 
4430 /*
4431  * DISABLE ROUTINES
4432  */
4433 
4434 /*
4435  * ROUTINES TO IMPLEMENT TASK AND THREAD DISABLING
4436  */
4437 
4438 /*
4439  * execute a disable statement - disable tskp
4440  * return T to cause disable of current thread (above on chain)
4441  * and F if this thread continues as usual
4442  *
4443  * this code is not for functions there all disables converted to added gotos
4444  * disable argument is task name not ??
4445  */
__exec_disable(struct expr_t * dsxndp)4446 extern int32 __exec_disable(struct expr_t *dsxndp)
4447 {
4448  register struct tskthrd_t *ttp, *ttp_real_r;
4449  int32 thread_finished, nd_itpop;
4450  struct sy_t *syp;
4451  struct task_t *tskp;
4452  struct thread_t *dsathp, *thp, *thd_1up, *sav_thd;
4453  struct gref_t *grp;
4454  struct st_t *stp;
4455 
4456  /* this pointer to target symbol in some other module */
4457  nd_itpop = FALSE;
4458  syp = dsxndp->lu.sy;
4459  if (dsxndp->optyp == GLBREF)
4460   { grp = dsxndp->ru.grp; __xmrpush_refgrp_to_targ(grp); nd_itpop = TRUE; }
4461 
4462  /* disabling every thread associated with task of given instance required */
4463  /* first disable and free all underneath */
4464  tskp = syp->el.etskp;
4465  /* assume current thread not disabled */
4466  thread_finished = FALSE;
4467  /* task can be enabled from >1 place in inst. but share vars */
4468  ttp = tskp->tthrds[__inum];
4469 
4470  if (ttp == NULL)
4471   {
4472    __sgfinform(469, "disable of %s %s no effect - not active",
4473     __to_tsktyp(__xs2, tskp->tsktyp), __msg_blditree(__xs, __inst_ptr, tskp));
4474    goto done;
4475   }
4476  for (; ttp != NULL;)
4477   {
4478    /* the task thread list that ttp points to will probably be freed */
4479    /* changing the right ptr so must get the next before freeing */
4480    ttp_real_r = ttp->tthd_r;
4481    dsathp = ttp->tthrd;
4482 
4483    /* better point back to self */
4484    /* -- DBG remove */
4485    if (dsathp->assoc_tsk != NULL && dsathp->assoc_tsk != tskp)
4486     __misc_sgfterr(__FILE__, __LINE__);
4487    /* --- */
4488 
4489    /* first if recurive task enables, disable top most */
4490    if ((thp = find_hgh_sametskthrd(dsathp)) != NULL) dsathp = thp;
4491 
4492    /* case 1: disabling current thread */
4493    if (dsathp == __cur_thd)
4494     {
4495      /* cannot unlink here since will be unlinked because thread done */
4496      __cur_thd->th_dsable = TRUE;
4497      thread_finished = TRUE;
4498     }
4499    /* case 2: disabling highest thread above currently active */
4500    /* this is case where above spawns subthread for task/blk/fj */
4501    /* case 1: and 2: mutually exclusive */
4502    else if (thread_above_cur(dsathp))
4503     {
4504      /* free under threads including current */
4505      free_thd_subtree(dsathp);
4506      /* ok to just set current thread since finished and all under gone */
4507      __cur_thd = dsathp;
4508      __cur_thd->th_dsable = TRUE;
4509      thread_finished = TRUE;
4510     }
4511    /* disabling thread with scheduled event elsewhere in thread tree */
4512    else
4513     {
4514      thd_1up = dsathp->thpar;
4515      /* anything (task-named block than can be disabled here parent */
4516      /* DBG remove --- */
4517      if (thd_1up == NULL) __misc_terr(__FILE__, __LINE__);
4518      if (thd_1up->thofscnt > 1 && !dsathp->th_fj)
4519       __misc_terr(__FILE__, __LINE__);
4520      /* --- */
4521      /* disable a thread means remove and unlink from parent */
4522      thd_1up->thofscnt -= 1;
4523      if (dsathp->thleft != NULL) dsathp->thleft->thright = dsathp->thright;
4524      /* if first thread finished, make up thofs list point to its right */
4525      else thd_1up->thofs = dsathp->thright;
4526      if (dsathp->thright != NULL) dsathp->thright->thleft = dsathp->thleft;
4527 
4528      /* free all under and thread itself - mark schd. events canceled */
4529      free_thd_subtree(dsathp);
4530      __free_1thd(dsathp);
4531      dsathp = NULL;
4532      /* if more subthreads, nothing to do since will eval thread events */
4533      /* for other fj subthreads */
4534      if (thd_1up->thofscnt == 0)
4535       {
4536        /* know have parent or cannot get here */
4537        /* previously disable thread scheduled, after remove schedule 1 up */
4538        /* eliminating any waiting delay/event controls */
4539        sav_thd = __cur_thd;
4540        __cur_thd = thd_1up;
4541        /* if this was task with output parameters - do not store and */
4542        /* make sure up thread not in task returning state */
4543        if (thd_1up->th_postamble)
4544         { stp = thd_1up->thnxtstp->stnxt; thd_1up->th_postamble = FALSE; }
4545        else stp = thd_1up->thnxtstp;
4546        /* this will incorrectly turn on stmt suspend */
4547        /* DBG remove --- */
4548        if (__stmt_suspend) __misc_terr(__FILE__, __LINE__);
4549        /* --- */
4550        suspend_curthd(stp);
4551        __stmt_suspend = FALSE;
4552        __cur_thd = sav_thd;
4553       }
4554     }
4555    /* move to next - saved since previous probably freed */
4556    ttp = ttp_real_r;
4557   }
4558 
4559 done:
4560  /* DBG remove ---
4561  __dmp_tskthd(tskp, __inst_mod);
4562  --- */
4563  if (nd_itpop) __pop_itstk();
4564  return(thread_finished);
4565 }
4566 
4567 /*
4568  * find highest thread associated with same task above
4569  * return NULL if thread to disable not above this one
4570  */
find_hgh_sametskthrd(struct thread_t * dsthp)4571 static struct thread_t *find_hgh_sametskthrd(struct thread_t *dsthp)
4572 {
4573  register struct thread_t *thp;
4574  struct thread_t *highthd;
4575 
4576  for (highthd = NULL, thp = __cur_thd; thp != NULL; thp = thp->thpar)
4577   {
4578    if (thp->assoc_tsk != NULL && thp->assoc_tsk == dsthp->assoc_tsk)
4579     highthd = thp;
4580   }
4581  return(highthd);
4582 }
4583 
4584 /*
4585  * return T if thread is above current thread
4586  */
thread_above_cur(struct thread_t * dsthp)4587 static int32 thread_above_cur(struct thread_t *dsthp)
4588 {
4589  register struct thread_t *thp;
4590 
4591  for (thp = __cur_thd; thp != NULL; thp = thp->thpar)
4592   {
4593    if (thp == dsthp) return(TRUE);
4594   }
4595  return(FALSE);
4596 }
4597 
4598 /*
4599  * free a thread subtree below thp (but not including thp)
4600  */
free_thd_subtree(struct thread_t * thp)4601 static void free_thd_subtree(struct thread_t *thp)
4602 {
4603  if (thp->thofs != NULL) __free_thd_list(thp->thofs);
4604  thp->thofscnt = 0;
4605  thp->thofs = NULL;
4606  thp->th_fj = FALSE;
4607 }
4608 
4609 /*
4610  * free a thread list (passed head that is probably thofs)
4611  */
__free_thd_list(struct thread_t * thp)4612 extern void __free_thd_list(struct thread_t *thp)
4613 {
4614  register struct thread_t *thp2, *thp3;
4615 
4616  for (thp2 = thp; thp2 != NULL;)
4617   {
4618    thp3 = thp2->thright;
4619    if (thp2->thofs != NULL) __free_thd_list(thp2->thofs);
4620    __free_1thd(thp2);
4621    thp2 = thp3;
4622   }
4623 }
4624 
4625 /*
4626  * free one thread
4627  * called after any subthreads freed
4628  */
__free_1thd(struct thread_t * thp)4629 extern void __free_1thd(struct thread_t *thp)
4630 {
4631  /* every thread with an associated task - unlabeled fork-join will not */
4632  /* DBG remove --- */
4633  if (thp->th_itp == NULL || thp->th_ialw)
4634    __misc_terr(__FILE__, __LINE__);
4635  /* --- */
4636  __push_itstk(thp->th_itp);
4637  free_thd_stuff(thp);
4638  __pop_itstk();
4639  __my_free((char *) thp, sizeof(struct thread_t));
4640 }
4641 
4642 /*
4643  * routine used by disable to force finish (free all but thread itself)
4644  */
free_thd_stuff(struct thread_t * thp)4645 static void free_thd_stuff(struct thread_t *thp)
4646 {
4647  /* every thread with an associated task - unlabeled fork-join will not */
4648  if (thp->tthlst != NULL) unlink_tskthd(thp);
4649  if (thp->thdtevi != -1) __tevtab[thp->thdtevi].te_cancel = TRUE;
4650  /* notice if free statements (from iact) this will be set to nil */
4651  /* since when freeing dctrl and wait freeing the dctp */
4652  /* events freed later */
4653  if (thp->th_dctp != NULL)
4654   {
4655    if (thp->th_dctp->dceschd_tevs != NULL)
4656     thp->th_dctp->dceschd_tevs[thp->th_itp->itinum] = -1;
4657    thp->th_dctp = NULL;
4658   }
4659  if (thp->th_rhsform)
4660   {
4661    __my_free((char *) thp->th_rhswp, 2*WRDBYTES*thp->th_rhswlen);
4662    thp->th_rhswp = NULL;
4663   }
4664 }
4665 
4666 /*
4667  * unlink and free one task thead - remove from tasks list
4668  *
4669  * every thread that has assoc task has pointer to 1 tskthrd_t element
4670  * that is its entry on task's thread list for given instance
4671  */
unlink_tskthd(struct thread_t * thp)4672 static void unlink_tskthd(struct thread_t *thp)
4673 {
4674  struct tskthrd_t *ttp;
4675  struct task_t *tskp;
4676 
4677  ttp = thp->tthlst;
4678  /* DBG remove --- */
4679  if (__debug_flg && __st_tracing)
4680   {
4681    /* unlink of disabled thread to with no assoc. task */
4682    /* should emit the itree loc. here */
4683    if (thp->assoc_tsk == NULL) __misc_sgfterr(__FILE__, __LINE__);
4684    __tr_msg("++ unlink task %s for instance %s number %d\n",
4685     thp->assoc_tsk->tsksyp->synam, __inst_ptr->itip->isym->synam, __inum);
4686   }
4687  /* --- */
4688 
4689  /* lifo recursive enable freeing case */
4690  if (ttp->tthd_l == NULL)
4691   {
4692    tskp = thp->assoc_tsk;
4693    tskp->tthrds[__inum] = ttp->tthd_r;
4694    if (ttp->tthd_r != NULL) ttp->tthd_r->tthd_l = NULL;
4695   }
4696  else
4697   {
4698    /* any other order */
4699    ttp->tthd_l->tthd_r = ttp->tthd_r;
4700    if (ttp->tthd_r != NULL) ttp->tthd_r->tthd_l = ttp->tthd_l;
4701   }
4702  /* ttp has already been linked out */
4703  __my_free((char *) ttp, sizeof(struct tskthrd_t));
4704  thp->tthlst = NULL;
4705  /* DBG remove ---
4706  __dmp_tskthd(tskp, __inst_ptr->itip->imsym->el.emdp);
4707  --- */
4708 }
4709 
4710 /*
4711  * SYSTEM TASK/FUNCTION EXECUTION ROUTINES
4712  */
4713 
4714 /*
4715  * execute the system tasks
4716  *
4717  * for monitor and strobe effect is to set up later action
4718  */
__exec_stsk(struct st_t * stp,struct sy_t * tsyp,struct tskcall_t * tkcp)4719 extern struct st_t *__exec_stsk(struct st_t *stp, struct sy_t *tsyp,
4720  struct tskcall_t *tkcp)
4721 {
4722  int32 base, stav, oslen, slen;
4723  word32 wval;
4724  struct systsk_t *stbp;
4725  struct strblst_t *strblp;
4726  struct expr_t *argvx;
4727  char *chp;
4728 
4729  stbp = tsyp->el.esytbp;
4730  switch (stbp->stsknum) {
4731   /* file manipulation - most functions */
4732   case STN_FCLOSE:
4733    /* AIV 09/08/03 - for P1364 2001 must handle both MCD and FILE closes */
4734    fio_do_fclose(tkcp->targs);
4735    break;
4736   case STN_FFLUSH:
4737    /* AIV 09/08/03 - for P1364 2001 new sys task - not in 1995 std */
4738    /* SJM 09/09/03 - there is POSIX flush all that also flushes PLI */
4739    /* and other(?) open files - PORTABILITY? - works on Linux */
4740    if (tkcp->targs == NULL) fflush(NULL);
4741    else fio_fflush(tkcp->targs->lu.x);
4742    break;
4743   /* display write to terminal */
4744   case STN_DISPLAY: base = BDEC; goto nonf_disp;
4745   case STN_DISPLAYB: base = BBIN; goto nonf_disp;
4746   case STN_DISPLAYH: base = BHEX; goto nonf_disp;
4747   case STN_DISPLAYO:
4748    base = BOCT;
4749 nonf_disp:
4750    __do_disp(tkcp->targs, base);
4751    __cvsim_msg("\n");
4752    break;
4753 
4754   /* write to terminal with no ending nl */
4755   case STN_WRITE: base = BDEC; goto nonf_write;
4756   case STN_WRITEH: base = BHEX; goto nonf_write;
4757   case STN_WRITEB: base = BBIN; goto nonf_write;
4758   case STN_WRITEO: base = BOCT;
4759 nonf_write:
4760    __do_disp(tkcp->targs, base);
4761    /* if tracing to stdout need the new line just to stdout */
4762    /* LOOKATME - could change to separate verilog.trace file ?? */
4763    /* NOTICE - this is not __tr_msg */
4764    if (__st_tracing && __tr_s == stdout) __cv_msg("\n");
4765    break;
4766 
4767   /* multi-channel descriptor display to file */
4768   case STN_FDISPLAY: base = BDEC; goto f_disp;
4769   case STN_FDISPLAYB: base = BBIN; goto f_disp;
4770   case STN_FDISPLAYH: base = BHEX; goto f_disp;
4771   case STN_FDISPLAYO:
4772    base = BOCT;
4773 f_disp:
4774    __fio_do_disp(tkcp->targs, base, TRUE, tsyp->synam);
4775    break;
4776 
4777   /* multi-channel descriptor write to file */
4778   case STN_FWRITE: base = BDEC; goto f_write;
4779   case STN_FWRITEH: base = BHEX; goto f_write;
4780   case STN_FWRITEB: base = BBIN; goto f_write;
4781   case STN_FWRITEO: base = BOCT;
4782 f_write:
4783    /* if tracing need the new line */
4784    __fio_do_disp(tkcp->targs, base, __st_tracing, tsyp->synam);
4785    break;
4786   case STN_SWRITE: base = BDEC; goto s_write;
4787   case STN_SWRITEH: base = BHEX; goto s_write;
4788   case STN_SWRITEB: base = BBIN; goto s_write;
4789   case STN_SWRITEO: base = BOCT;
4790    /* $swrite([output reg], ...) */
4791 s_write:
4792    fio_swrite(tkcp->targs, base);
4793    break;
4794   case STN_SFORMAT:
4795    /* SJM 05/14/04 - LOOKATME - LRM is unclear and suggests that $sformat */
4796    /* returns a val but it is called a system task in LRM */
4797    fio_sformat(tkcp->targs);
4798    break;
4799   /* like display except write at end of current time */
4800   case STN_FSTROBE: case STN_FSTROBEH: case STN_FSTROBEB: case STN_FSTROBEO:
4801   case STN_STROBE: case STN_STROBEH: case STN_STROBEB: case STN_STROBEO:
4802    /* if same strobe statement repeated in one time slot - warn/inform */
4803    if (stp->strb_seen_now)
4804     {
4805      /* if dup. of same inst. and statement, do not re-add */
4806      if (!chk_strobe_infloop(stp, tsyp)) break;
4807     }
4808    if (__strb_freelst != NULL)
4809     {
4810      strblp = __strb_freelst;
4811      __strb_freelst = __strb_freelst->strbnxt;
4812     }
4813    else strblp = (struct strblst_t *) __my_malloc(sizeof(struct strblst_t));
4814    strblp->strbstp = stp;
4815    stp->strb_seen_now = TRUE;
4816    strblp->strb_itp = __inst_ptr;
4817    strblp->strbnxt = NULL;
4818    __iact_can_free = FALSE;
4819    if (__strobe_hdr == NULL)
4820     {
4821      __strobe_hdr = __strobe_end = strblp;
4822      __slotend_action |= SE_STROBE;
4823     }
4824    else { __strobe_end->strbnxt = strblp; __strobe_end = strblp; }
4825    break;
4826   /* monitor control sys tasks */
4827   case STN_MONITOROFF: __monit_active = FALSE; break;
4828   case STN_MONITORON:
4829    __monit_active = TRUE;
4830    __iact_can_free = FALSE;
4831    /* when monitor turned on (even if on), trigger even if no changes */
4832    /* and update save dce values to current */
4833    __slotend_action |= SE_MONIT_CHG;
4834    break;
4835   case STN_FMONITOR: case STN_FMONITORH: case STN_FMONITORB:
4836   case STN_FMONITORO:
4837    __start_fmonitor(stp);
4838    __iact_can_free = FALSE;
4839    /* DBG remove ---
4840    if (__debug_flg)
4841     __dmpmod_nplst(__inst_mod, TRUE);
4842    -- */
4843    break;
4844   /* change monitor write to terminal system tasks */
4845   case STN_MONITOR: case STN_MONITORH: case STN_MONITORB: case STN_MONITORO:
4846    __start_monitor(stp);
4847    __iact_can_free = FALSE;
4848    break;
4849   /* time releated system tasks */
4850   case STN_PRINTTIMESCALE:
4851    exec_prttimscale(tkcp->targs);
4852    break;
4853   case STN_TIMEFORMAT:
4854    /* if no `timescale in design, $timeformat is a noop */
4855    if (__des_has_timescales) exec_timefmt(tkcp->targs);
4856    break;
4857   case STN_READMEMB:
4858    __exec_readmem(tkcp->targs, BBIN);
4859    break;
4860   case STN_READMEMH:
4861    __exec_readmem(tkcp->targs, BHEX);
4862    break;
4863   case STN_SREADMEMB:
4864    __exec_sreadmem(tkcp->targs, BBIN);
4865    break;
4866   case STN_SREADMEMH:
4867    __exec_sreadmem(tkcp->targs, BHEX);
4868    break;
4869 
4870   /* dump variables tasks */
4871   case STN_DUMPVARS:
4872    __exec_dumpvars(tkcp->targs);
4873    break;
4874   case STN_DUMPALL:
4875    if (__dv_state == DVST_NOTSETUP)
4876     {
4877      __sgferr(703, "$dumpall ignored because: $dumpvars not set up");
4878      break;
4879     }
4880    /* dumpall is independent of other dumpvars except past file size limit */
4881    /* but still must dump at end of time slot */
4882    if ((__slotend_action & SE_DUMPALL) != 0)
4883     __sgfinform(445,
4884      "$dumpall ignored beause: $dumpall already executed at this time");
4885    /* turn on need dumpall plus need some dump vars action */
4886    __slotend_action |= (SE_DUMPALL | SE_DUMPVARS);
4887    break;
4888   case STN_DUMPFILE:
4889    /* SJM 10/26/00 - fix to match XL */
4890    /* can set dumpvars file name before time of dumpvars setup */
4891    /* but not after dumpvars started */
4892    if (__dv_seen)
4893     {
4894      __sgferr(1066,
4895       "$dumpfile name set at time after $dmmpvars started - name not changed");
4896      break;
4897     }
4898    /* if no argument just leaves default - cannot be called more than once */
4899    if (tkcp->targs == NULL) break;
4900 
4901    /* set the file to dump too */
4902    argvx = tkcp->targs->lu.x;
4903    chp = __get_eval_cstr(argvx, &slen);
4904    /* cannot open yet but must save */
4905    oslen = strlen(__dv_fnam);
4906    if (__dv_fnam != NULL) __my_free((char *) __dv_fnam, oslen + 1);
4907    __dv_fnam = chp;
4908    break;
4909   case STN_DUMPFLUSH:
4910    /* flush the file now since need to flush before adding this times */
4911    /* dumpvars */
4912    if (__dv_state == DVST_NOTSETUP)
4913     {
4914      __sgferr(703,
4915       "$dumpflush ignored because: dumping of variables not begun");
4916      break;
4917     }
4918    if (__dv_fd == -1) __arg_terr(__FILE__, __LINE__);
4919    /* flush when called - i.e. flush is before this time's dumping */
4920    /* this call OS functions that may set errno */
4921    __my_dv_flush();
4922    break;
4923   case STN_DUMPLIMIT:
4924    /* notice can call even if not set up and can change if not over limit */
4925    argvx = tkcp->targs->lu.x;
4926    if (!__get_eval_word(argvx, &wval) || ((wval & (1 << (WBITS - 1))) != 0))
4927     {
4928      __sgferr(1036, "$dumplimit value %s illegal positive integer - not set",
4929       __msgexpr_tostr(__xs, tkcp->targs));
4930      break;
4931     }
4932 
4933    /* if already over limit cannot change */
4934    if (__dv_state == DVST_OVERLIMIT)
4935     {
4936      __sgferr(1069,
4937       "$dumplimit not set to %d - dump file already over previous limit %d",
4938       (int32) wval, __dv_dumplimit_size);
4939      break;
4940     }
4941    /* else inform if already set */
4942    if (__dv_dumplimit_size != 0)
4943     {
4944      __sgfinform(449, "$dumplimit changed from %d to %d",
4945       __dv_dumplimit_size, (int32) wval);
4946     }
4947    __dv_dumplimit_size = (int32) wval;
4948    break;
4949   case STN_DUMPON:
4950    switch ((byte) __dv_state) {
4951     case DVST_NOTSETUP:
4952      __sgferr(703, "$dumpon ignored because: $dumpvars not set up");
4953      break;
4954     /* if over limit silently ignore */
4955     case DVST_OVERLIMIT: break;
4956     case DVST_DUMPING:
4957      if ((__slotend_action & SE_DUMPOFF) != 0)
4958       {
4959        __sgfinform(453, "$dumpon overrides $dumpoff executed at this time");
4960        __slotend_action &= ~SE_DUMPOFF;
4961       }
4962      __sgfinform(446, "$dumpon ignored because: dumping already on");
4963      break;
4964     case DVST_NOTDUMPING:
4965      if ((__slotend_action & SE_DUMPON) != 0)
4966       __sgfinform(445,
4967        "$dumpon ignored because: $dumpon already executed at this time");
4968      /* also indicate need some dumpvars action */
4969      __slotend_action |= (SE_DUMPON | SE_DUMPVARS);
4970      break;
4971     default: __case_terr(__FILE__, __LINE__);
4972    }
4973    break;
4974   case STN_DUMPOFF:
4975    switch ((byte) __dv_state) {
4976     case DVST_NOTSETUP:
4977      __sgferr(703, "$dumpoff ignored because: $dumpvars not set up");
4978      break;
4979     case DVST_OVERLIMIT: break;
4980     case DVST_NOTDUMPING:
4981      if ((__slotend_action & SE_DUMPON) != 0)
4982       {
4983        __sgfinform(453, "$dumpoff overrides $dumpon executed at this time");
4984        __slotend_action &= ~SE_DUMPON;
4985       }
4986      __sgfinform(446, "$dumpoff ignored because: dumping already off");
4987      break;
4988     case DVST_DUMPING:
4989      if ((__slotend_action & SE_DUMPON) != 0)
4990       __sgfinform(445,
4991        "$dumpoff ignored because: $dumpoff already executed at this time");
4992      /* also indicate need some dumpvars action even if no changes */
4993      __slotend_action |= (SE_DUMPOFF | SE_DUMPVARS);
4994      break;
4995     default: __case_terr(__FILE__, __LINE__);
4996    }
4997    break;
4998   case STN_INPUT:
4999    __exec_input_fnamchg(tkcp->targs);
5000    break;
5001   case STN_HISTORY:
5002    /* LRM strictly requires all element here */
5003    __exec_history_list(__hist_cur_listnum);
5004    break;
5005   case STN_NOKEY:
5006 no_key:
5007    __sgfwarn(560, "%s no effect - obsolete key file not supported",
5008     tsyp->synam);
5009    /* DBGER ---
5010    __save_key_s = __key_s;
5011    __nokey_seen = TRUE;
5012    __key_s = NULL;
5013    break;
5014    -- */
5015   case STN_KEY:
5016    goto no_key;
5017   case STN_KEEPCMDS:
5018    if (__history_on)
5019     __sgfinform(458, "%s ignored - command history saving already on",
5020      tsyp->synam);
5021    __history_on = TRUE;
5022    break;
5023   case STN_NOKEEPCMDS:
5024    if (!__history_on)
5025     __sgfinform(458, "%s ignored - command history saving already off",
5026      tsyp->synam);
5027    __history_on = FALSE;
5028    break;
5029   case STN_NOLOG:
5030    if (__log_s != NULL) fflush(__log_s);
5031    __save_log_s = __log_s;
5032 
5033    /* notice cannot close log file */
5034    /* SJM 03/26/00 - 2 in Verilog 2000 not used for log file lumped with */
5035    /*  stdout (bit 0 value 1) */
5036    /* ---
5037    if (__mulchan_tab[2].mc_s != NULL)
5038     {
5039      __mulchan_tab[2].mc_s = NULL;
5040      chp = __mulchan_tab[2].mc_fnam;
5041      __my_free(chp, strlen(chp) + 1);
5042      __mulchan_tab[2].mc_fnam = NULL;
5043     }
5044    --- */
5045    __log_s = NULL;
5046    break;
5047   case STN_LOG:
5048    exec_log_fnamchg(tkcp->targs);
5049    break;
5050   case STN_TRACEFILE:
5051    argvx = tkcp->targs->lu.x;
5052    exec_trace_fnamchg(argvx);
5053    break;
5054   case STN_SCOPE:
5055    exec_expr_schg(tkcp->targs->lu.x);
5056    break;
5057   /* listing off because no interactive environment */
5058   case STN_LIST:
5059    /* list current scope - */
5060    if (tkcp->targs != NULL)
5061     {
5062      struct itree_t *sav_scope_ptr = __scope_ptr;
5063      struct task_t *sav_tskp = __scope_tskp;
5064 
5065      exec_expr_schg(tkcp->targs->lu.x);
5066      __do_scope_list();
5067      __scope_ptr = sav_scope_ptr;
5068      __scope_tskp = sav_tskp;
5069     }
5070    else __do_scope_list();
5071    break;
5072 
5073   /* unimplemented - need complicated state write file mechanism */
5074   case STN_SAVE: case STN_INCSAVE: case STN_RESTART:
5075    goto un_impl;
5076 
5077   case STN_FINISH:
5078    if (__tfrec_hdr != NULL) __call_misctfs_finish();
5079    if (__have_vpi_actions) __vpi_endsim_trycall();
5080    stav = get_opt_starg(tkcp->targs, 1);
5081    if (stav >= 1 || __verbose)
5082     {
5083      /* LOOKATME - why needed - if (!__quiet_msgs) __cv msg("\n"); */
5084      __cv_msg("Halted at location %s time %s from call to $finish.\n",
5085       __bld_lineloc(__xs2, (word32) __sfnam_ind, __slin_cnt),
5086       __to_timstr(__xs, &__simtime));
5087     }
5088    if (stav >= 2 || __verbose) __emit_stsk_endmsg();
5089    /* notice must always print error counts if any */
5090    if (__pv_err_cnt != 0 || __pv_warn_cnt != 0 || __inform_cnt != 0)
5091     __cv_msg("  There were %d error(s), %d warning(s), and %d inform(s).\n",
5092      __pv_err_cnt, __pv_warn_cnt, __inform_cnt);
5093    __my_exit(0, TRUE);
5094   case STN_STOP:
5095    if (__no_iact)
5096     {
5097      __sgfwarn(560, "%s no effect - interactive environment disabled",
5098       stbp->stsknam);
5099      break;
5100     }
5101    if (__iact_state)
5102     {
5103      __sgfwarn(587, "%s no effect - enabled from interactive debugger",
5104       stbp->stsknam);
5105      break;
5106     }
5107    stav = get_opt_starg(tkcp->targs, 1);
5108    if (stav >= 1)
5109     {
5110      if (!__quiet_msgs) __cv_msg("\n");
5111      __cv_msg(
5112       "$stop executed at time %s from source location %s.\n",
5113       __to_timstr(__xs, &__simtime), __bld_lineloc(__xs2,
5114       (word32) __sfnam_ind, __slin_cnt));
5115     }
5116    if (stav >= 2) __emit_stsk_endmsg();
5117    __pending_enter_iact = TRUE;
5118    __iact_reason = IAER_STOP;
5119    signal(SIGINT, SIG_IGN);
5120    __stmt_suspend = TRUE;
5121    suspend_curthd(stp->stnxt);
5122    return(NULL);
5123   case STN_SETTRACE:
5124    /* statement tracing change requires suspend of thread */
5125    __st_tracing = TRUE;
5126    /* if enabled from interactive state, suspend will cause core dump */
5127    if (!__iact_state) suspend_curthd(stp->stnxt);
5128    /* if trace file name set from command option open now if not open */
5129    __maybe_open_trfile();
5130    return(NULL);
5131   case STN_CLEARTRACE:
5132    __st_tracing = FALSE;
5133    break;
5134   case STN_SETEVTRACE:
5135    __ev_tracing = TRUE;
5136    /* if trace file name set from command option open now if not open */
5137    __maybe_open_trfile();
5138    break;
5139   case STN_CLEAREVTRACE:
5140    /* notice leave file open */
5141    __ev_tracing = FALSE;
5142    break;
5143   case STN_SETDEBUG:
5144    __debug_flg = TRUE;
5145    break;
5146   case STN_CLEARDEBUG:
5147    __debug_flg = FALSE;
5148    break;
5149   case STN_SHOWVARS:
5150    do_showvars_stask(tkcp->targs);
5151    break;
5152   case STN_SHOWVARIABLES:
5153    /* for now same as showvars - i.e. skip 1st control arg. */
5154    do_showvars_stask(tkcp->targs->ru.x);
5155    break;
5156   case STN_SYSTEM:
5157    /* $system with no args, means run interactive shell */
5158    if (tkcp->targs == NULL) chp = __pv_stralloc(" ");
5159    else
5160     {
5161      argvx = tkcp->targs->lu.x;
5162      if (argvx->optyp == OPEMPTY) { chp = __pv_stralloc(" "); slen = 1; }
5163      else chp = __get_eval_cstr(argvx, &slen);
5164     }
5165    __escape_to_shell(chp);
5166    slen = strlen(chp);
5167    __my_free(chp, slen + 1);
5168    break;
5169   case STN_SUPWARNS:
5170    do_warn_supp_chg(stbp->stsknam, tkcp->targs, TRUE);
5171    break;
5172   case STN_ALLOWWARNS:
5173    do_warn_supp_chg(stbp->stsknam, tkcp->targs, FALSE);
5174    break;
5175   case STN_MEMUSE:
5176    /* this will force output */
5177    __cvsim_msg("Approximately %ld bytes allocated dynamic storage.\n",
5178      __mem_use);
5179    __cvsim_msg("Verilog arrays (memories) require %ld bytes.\n", __arrvmem_use);
5180    break;
5181   case STN_FLUSHLOG:
5182    /* LOOKATME - maybe should check for rare but possible error */
5183    if (__log_s != NULL) fflush(__log_s);
5184    if (__tr_s != NULL) fflush(__tr_s);
5185    break;
5186   case STN_RESET:
5187    /* do reset processing - final step is long jmp to top level */
5188    do_reset(tkcp->targs);
5189    break;
5190   case STN_SNAPSHOT:
5191    stav = get_opt_starg(tkcp->targs, DFLT_SNAP_EVS);
5192    __write_snapshot(stav);
5193    break;
5194   case STN_SHOWALLINSTANCES:
5195    __prt2_mod_typetab(FALSE);
5196    break;
5197   case STN_SHOWSCOPES:
5198    do_showscopes(tkcp->targs);
5199    break;
5200   /* graphical output tasks - ignore with warn */
5201   case STN_GRREMOTE:
5202   case STN_PSWAVES:
5203   case STN_GRSYNCHON:
5204   case STN_GRREGS:
5205   case STN_GRWAVES:
5206   case STN_FREEZEWAVES:
5207   case STN_DEFINEGROUPWAVES:
5208    /* earlier warning - just ignore */
5209    break;
5210 
5211   /* internal simulation state printng tasks */
5212   case STN_SHOWEXPANDEDNETS: goto un_impl;
5213 
5214   /* q manipulation tasks - also q_full function */
5215   case STN_Q_INITIALIZE:
5216    do_q_init(tkcp->targs);
5217    break;
5218   case STN_Q_ADD:
5219    do_q_add(tkcp->targs);
5220    break;
5221   case STN_Q_REMOVE:
5222    do_q_remove(tkcp->targs);
5223    break;
5224   case STN_Q_EXAM:
5225    do_q_examine(tkcp->targs);
5226    break;
5227   case STN_SDF_ANNOTATE:
5228    __exec_sdf_annotate_systsk(tkcp->targs);
5229    break;
5230   default:
5231    /* DBG remove --- */
5232    if (stbp->stsknum < BASE_VERIUSERTFS || (int32) stbp->stsknum > __last_systf)
5233      __case_terr(__FILE__, __LINE__);
5234    /* --- */
5235    /* exec (call) pli user tf system function here */
5236    if (stbp->stsknum <= __last_veriusertf) __pli_task_calltf(stp);
5237    else __vpi_syst_calltf(stp);
5238  }
5239  return(stp->stnxt);
5240 
5241 un_impl:
5242  __sgfwarn(550, "system task %s not implemented - ignored", stbp->stsknam);
5243  return(stp->stnxt);
5244 }
5245 
5246 /*
5247  * MISCELLANEOUS SYSTEM TASK EXEC ROUTINES
5248  */
5249 
5250 /*
5251  * check strobe statement repeated in same strobe system task call
5252  *
5253  * notice this only called if know strobe task enable statement repeated
5254  * checking for strobe repeated but in different instance
5255  */
chk_strobe_infloop(struct st_t * stp,struct sy_t * tsksyp)5256 static int32 chk_strobe_infloop(struct st_t *stp, struct sy_t *tsksyp)
5257 {
5258  register struct strblst_t *strbp;
5259  int32 match;
5260 
5261  match = FALSE;
5262  for (strbp = __strobe_hdr; strbp != NULL; strbp = strbp->strbnxt)
5263   {
5264    if (strbp->strbstp == stp)
5265     {
5266      match = TRUE;
5267      if (strbp->strb_itp == __inst_ptr)
5268       {
5269        __sgfwarn(527, "%s enable for instance %s repeated at this time",
5270         tsksyp->synam, __msg2_blditree(__xs, __inst_ptr));
5271        return(FALSE);
5272       }
5273      /* maybe should only inform one inform per call ? */
5274      __sgfinform(434, "%s enable in instance %s repeated in %s at this time",
5275       tsksyp->synam, __msg2_blditree(__xs, __inst_ptr),
5276       __msg2_blditree(__xs2, strbp->strb_itp));
5277     }
5278   }
5279  if (!match) __case_terr(__FILE__, __LINE__);
5280  return(TRUE);
5281 }
5282 
5283 /*
5284  * setup event from suspend (^c or $stop or stmt. break) of cur. thread
5285  * stp is place to begin after wake up
5286  * links new event on front of current event list
5287  */
suspend_curthd(struct st_t * stp)5288 static void suspend_curthd(struct st_t *stp)
5289 {
5290  i_tev_ndx tevpi;
5291 
5292  alloc_tev_(tevpi, TE_THRD, __inst_ptr, __simtime);
5293  __cur_thd->thdtevi = tevpi;
5294  __tevtab[tevpi].tu.tethrd = __cur_thd;
5295  __cur_thd->thnxtstp = stp;
5296  __stmt_suspend = TRUE;
5297  __suspended_thd = __cur_thd;
5298  __suspended_itp = __inst_ptr;
5299  /* must save suspended, but popping done in event processing loop */
5300  __cur_thd = NULL;
5301 
5302  /* if hit break or step in func. save event, must unde (extr. and cancel) */
5303  /* to continue in function without going through event processing loop */
5304  if (__fcspi >= 0) __fsusp_tevpi = tevpi; else __fsusp_tevpi = -1;
5305 
5306  /* since just suspending and want to continue from here, put on front */
5307  __add_ev_to_front(tevpi);
5308  /* maybe remove this since - will print interactive msg anyway ? */
5309  if (__debug_flg && __st_tracing)
5310   {
5311    if (stp != NULL)
5312     sprintf(__xs2,  "at %s", __bld_lineloc(__xs, stp->stfnam_ind,
5313      stp->stlin_cnt));
5314    else strcpy(__xs2, "**past end");
5315    __tr_msg("-- suspend of current thread, was enabled at %s, continue %s\n",
5316     __bld_lineloc(__xs, __suspended_thd->thenbl_sfnam_ind,
5317       __suspended_thd->thenbl_slin_cnt), __xs2);
5318   }
5319 }
5320 
5321 /*
5322  * routine to open trace output file when needed
5323  */
__maybe_open_trfile(void)5324 extern void __maybe_open_trfile(void)
5325 {
5326  if (strcmp(__tr_fnam, "stdout") == 0 || __tr_s != NULL) return;
5327  if ((__tr_s = __tilde_fopen(__tr_fnam, "w")) == NULL)
5328   {
5329    __sgferr(1247, "cannot open trace output file %s - stdout used",
5330     __tr_fnam);
5331    __tr_s = stdout;
5332    __my_free(__tr_fnam, strlen(__tr_fnam) + 1);
5333    __tr_fnam = __my_malloc(7);
5334    strcpy(__tr_fnam, "stdout");
5335   }
5336 }
5337 
5338 /*
5339  * execute the multi-channel descriptor file close
5340  * this is a system task not function
5341  *
5342  * SJM 08/09/03 - FIXME ??? - need to disable pending f monit or strobe
5343  */
mcd_do_fclose(struct expr_t * axp)5344 static void mcd_do_fclose(struct expr_t *axp)
5345 {
5346  word32 mcd;
5347  struct xstk_t *xsp;
5348 
5349  xsp = __eval_xpr(axp->lu.x);
5350  if (xsp->bp[0] != 0L)
5351   {
5352    __sgfwarn(611,
5353     "$fclose multi-channel descriptor %s contains x or z bits - no action",
5354     __regab_tostr(__xs, xsp->ap, xsp->bp, xsp->xslen, BHEX, FALSE));
5355    __pop_xstk();
5356    return;
5357   }
5358  /* system task does not return anything but vpi_ call does */
5359  mcd = xsp->ap[0];
5360  __pop_xstk();
5361  __close_mcd((word32) mcd, FALSE);
5362 }
5363 
5364 /*
5365  * close mcd
5366  */
__close_mcd(word32 mcd,int32 from_vpi)5367 extern word32 __close_mcd(word32 mcd, int32 from_vpi)
5368 {
5369  register int32 i;
5370  int32 err;
5371 
5372  err = FALSE;
5373  if (mcd == 0L)
5374   {
5375    if (!from_vpi)
5376     {
5377      __sgfinform(431,
5378       "$fclose passed empty (no bits on) multi-channel descriptor");
5379     }
5380    return(bld_open_mcd());
5381   }
5382  if ((mcd & 1L) != 0)
5383   {
5384    if (!from_vpi)
5385     {
5386      __sgfinform(432,
5387       "$fclose bit 1 (stdout) multi-channel descriptor cannot be closed");
5388     }
5389    err = TRUE;
5390   }
5391  if ((mcd & 2L) != 0)
5392   {
5393    if (!from_vpi)
5394     {
5395      __sgfinform(432,
5396       "$fclose bit 2 (stderr) multi-channel descriptor cannot be closed");
5397     }
5398    err = TRUE;
5399   }
5400  for (i = 2; i < 31; i++)
5401   {
5402    if (((mcd >> i) & 1L) == 0L) continue;
5403 
5404    if (__mulchan_tab[i].mc_s == NULL)
5405     {
5406      if (!from_vpi)
5407       {
5408        __sgfwarn(611,
5409         "$fclose multi-channel descriptor bit %d on, but file already closed",
5410         i + 1);
5411       }
5412      err = TRUE;
5413      continue;
5414     }
5415    __my_fclose(__mulchan_tab[i].mc_s);
5416    __mulchan_tab[i].mc_s = NULL;
5417    __my_free(__mulchan_tab[i].mc_fnam, strlen(__mulchan_tab[i].mc_fnam) + 1);
5418    __mulchan_tab[i].mc_fnam = NULL;
5419   }
5420  if (!from_vpi)
5421   {
5422    if (((mcd >> 31) & 1L) != 0L)
5423     {
5424      __sgfwarn(611,
5425       "$fclose multi-channel descriptor bit 31 on, but no open file - unusable because reserved for new Verilog 2000 file I/O");
5426      err = TRUE;
5427     }
5428   }
5429 
5430  if (err) return(bld_open_mcd());
5431  return(0);
5432 }
5433 
5434 /*
5435  * build a mc descriptor for open channels
5436  */
bld_open_mcd(void)5437 static word32 bld_open_mcd(void)
5438 {
5439  word32 mcd;
5440  register int32 i;
5441 
5442  /* SJM 03/26/00 - high bit 32 reserved for new Verilog 2000 file I/O */
5443  for (i = 0, mcd = 0; i < 31; i++)
5444   {
5445    if (__mulchan_tab[i].mc_s == NULL) continue;
5446    mcd |= (1 << i);
5447   }
5448  return(mcd);
5449 }
5450 
5451 /*
5452  * execute the multi-channel descriptor file open
5453  * assigns to next free descriptor slot if one available
5454  *
5455  * this is system function that returns 0 on fail
5456  * 1 (index 0) is stdout and log file, 2 (index 1) is stder
5457  */
mc_do_fopen(struct expr_t * axp)5458 static word32 mc_do_fopen(struct expr_t *axp)
5459 {
5460  int32 slen;
5461  char *chp;
5462 
5463  chp = __get_eval_cstr(axp, &slen);
5464  return(__mc1_fopen(chp, strlen(chp), FALSE));
5465 }
5466 
5467 /*
5468  * do the mcd fopen if possible
5469  */
__mc1_fopen(char * chp,int32 slen,int32 from_vpi)5470 extern word32 __mc1_fopen(char *chp, int32 slen, int32 from_vpi)
5471 {
5472  register int32 i;
5473  FILE *tmp_s;
5474 
5475  /* SJM 03/26/00 - changed to match Verilog 2000 LRM */
5476  /* if name matches exactly return open - this is only heuristic */
5477  /* notice 2 is bit 3 (or value 4) that is first to use */
5478  /* bit 31 is rserved for new c style file open enhancement */
5479  for (i = 2; i < 31; i++)
5480   {
5481    if (__mulchan_tab[i].mc_s == NULL) continue;
5482 
5483    /* LOOKATME - not storing in tilde expanded form - same name can */
5484    /* mismatch but will just get open error from OS */
5485    if (strcmp(__mulchan_tab[i].mc_fnam, chp) == 0)
5486     {
5487      if (!from_vpi)
5488       {
5489        __sgfinform(433,
5490         "$fopen of %s failed: file already open and assigned to channel %d",
5491           chp, i + 1);
5492         __my_free(chp, slen + 1);
5493       }
5494      return((word32) (1L << i));
5495     }
5496   }
5497 
5498  for (i = 2; i < 31; i++)
5499   { if (__mulchan_tab[i].mc_s == NULL) goto found_free; }
5500  if (!from_vpi)
5501   {
5502    __sgfinform(433,
5503     "$fopen of %s failed: no available multi-channel descriptor", chp);
5504   }
5505 err_done:
5506  __my_free(chp, slen + 1);
5507  return(0);
5508 
5509 found_free:
5510  if ((tmp_s = __tilde_fopen(chp, "w")) == NULL)
5511   {
5512    if (!from_vpi)
5513     {
5514      __sgfinform(433, "$fopen of %s multi-channel bit %d failed: %s",
5515       chp, i, strerror(errno));
5516     }
5517    goto err_done;
5518   }
5519  __mulchan_tab[i].mc_s = tmp_s;
5520  /* know this is closed so no previous name to free */
5521  __mulchan_tab[i].mc_fnam = chp;
5522  /* notice first unused is 3 which is bit 4 on (if low bit is 1) */
5523  return((word32) (1L << i));
5524 }
5525 
5526 
5527 /*
5528  * execute showvars system task
5529  * this is called with fcall comma arg. list header not value
5530  */
do_showvars_stask(struct expr_t * argxp)5531 static void do_showvars_stask(struct expr_t *argxp)
5532 {
5533  register int32 ni;
5534  register struct expr_t *xp;
5535  register struct net_t *np;
5536  int32 nd_itpop;
5537  struct gref_t *grp;
5538  struct task_t *tskp;
5539  struct expr_t *ndp;
5540 
5541  if (__iact_state) tskp = __scope_tskp;
5542  else tskp = __getcur_scope_tsk();
5543 
5544  /* notice here, calling itree location correct */
5545  if (argxp == NULL)
5546   {
5547    /* if no arguments - all variables in current scope */
5548    __cvsim_msg(">>> $showvars all local variables - scope %s type %s.\n",
5549     __msg_blditree(__xs, __inst_ptr, tskp), __inst_ptr->itip->imsym->synam);
5550    if (tskp != NULL)
5551     {
5552      if (tskp->trnum != 0)
5553       {
5554        np = &(tskp->tsk_regs[0]);
5555        for (ni = 0; ni < tskp->trnum; ni++, np++) __emit_1showvar(np, NULL);
5556       }
5557     }
5558    else
5559     {
5560      if (__inst_mod->mnnum != 0)
5561       {
5562        for (ni = 0, np = &(__inst_mod->mnets[0]); ni < __inst_mod->mnnum;
5563         ni++, np++)
5564         __emit_1showvar(np, NULL);
5565       }
5566     }
5567   }
5568  else
5569   {
5570    /* go through list of variables - may be xmr's */
5571    /* these can be only var, bit select or part select */
5572    __cvsim_msg(
5573     ">>> $showvars list of variables form - current scope %s type %s.\n",
5574     __msg_blditree(__xs, __inst_ptr, tskp), __inst_ptr->itip->imsym->synam);
5575    for (xp = argxp; xp != NULL; xp = xp->ru.x)
5576     {
5577      nd_itpop = FALSE;
5578      grp = NULL;
5579      ndp = xp->lu.x;
5580      if (ndp->optyp == LSB || ndp->optyp == PARTSEL)
5581       {
5582        np = ndp->lu.x->lu.sy->el.enp;
5583        if (ndp->lu.x->optyp == GLBREF)
5584         {
5585          grp = ndp->lu.x->ru.grp;
5586          __xmrpush_refgrp_to_targ(grp);
5587          nd_itpop = TRUE;
5588         }
5589       }
5590      else
5591       {
5592        if (ndp->optyp == GLBREF)
5593         { grp = ndp->ru.grp; __xmrpush_refgrp_to_targ(grp); nd_itpop = TRUE; }
5594        np = ndp->lu.sy->el.enp;
5595       }
5596      __emit_1showvar(np, grp);
5597      if (nd_itpop) __pop_itstk();
5598     }
5599   }
5600 }
5601 
5602 /*
5603  * set new suppressed warnings during simulation
5604  */
do_warn_supp_chg(char * stnam,struct expr_t * argxp,int32 supp)5605 static void do_warn_supp_chg(char *stnam, struct expr_t *argxp, int32 supp)
5606 {
5607  int32 argi;
5608  word32 ernum;
5609  struct expr_t *ndp;
5610 
5611  for (argi = 1; argxp != NULL; argxp = argxp->ru.x, argi++)
5612   {
5613    ndp = argxp->lu.x;
5614    if (!__get_eval_word(ndp, &ernum))
5615     {
5616 bad_num:
5617      __sgferr(714,
5618       "%s argument %d value %s illegal or outside of inform/warning number range",
5619       stnam, argi, __msgexpr_tostr(__xs, ndp));
5620      continue;
5621     }
5622    if (!__enum_is_suppressable(ernum)) goto bad_num;
5623 
5624    if (supp) __wsupptab[ernum/WBITS] |= (1 << (ernum % WBITS));
5625    else __wsupptab[ernum/WBITS] &= ~(1 << (ernum % WBITS));
5626   }
5627 }
5628 
5629 /*
5630  * execute reset system task
5631  */
do_reset(struct expr_t * axp)5632 static void do_reset(struct expr_t *axp)
5633 {
5634  int32 enter_iact, reset_val, diag_val;
5635 
5636  /* assume interactive entry in case reset value (2nd) arg missing */
5637  enter_iact = TRUE;
5638  reset_val = 0;
5639  diag_val = 0;
5640  if (axp == NULL) goto do_it;
5641  if (get_opt_starg(axp, 0) != 0) enter_iact = FALSE;
5642  if ((axp = axp->ru.x) == NULL) goto do_it;
5643  reset_val = get_opt_starg(axp, 0);
5644  if ((axp = axp->ru.x) == NULL) goto do_it;
5645  diag_val = get_opt_starg(axp, 0);
5646 
5647 do_it:
5648  if (diag_val >= 1)
5649   {
5650    if (!__quiet_msgs) __cv_msg("\n");
5651    __cv_msg("$reset to time 0 called from location %s at time %s.\n",
5652     __bld_lineloc(__xs2, (word32) __sfnam_ind, __slin_cnt),
5653     __to_timstr(__xs, &__simtime));
5654   }
5655  if (diag_val >= 2) __emit_stsk_endmsg();
5656  /* enter interactive unless reset value given and non zero */
5657  if (reset_val != 0) enter_iact = FALSE;
5658 
5659  if (enter_iact) __stop_before_sim = TRUE;
5660  else __stop_before_sim = FALSE;
5661  /* record state changes caused by arguments */
5662  __reset_value = reset_val;
5663 
5664  /* reenable the normal ^c signal handler - when variables reset */
5665  /* sim will replace with sim handler for entering interactive */
5666 #if defined(INTSIGS)
5667  signal(SIGINT, __comp_sigint_handler);
5668 #else
5669  signal(SIGINT, (void (*)()) __comp_sigint_handler);
5670 #endif
5671 
5672  /* this does not return - uses lng jmp */
5673  longjmp(__reset_jmpbuf, 1);
5674 }
5675 
5676 /*
5677  * write the scope information
5678  * uses current scope not interactive - except $scope also changes current
5679  * if in interactive mode
5680  */
do_showscopes(struct expr_t * axp)5681 static void do_showscopes(struct expr_t *axp)
5682 {
5683  word32 flag;
5684  struct task_t *tskp;
5685  struct mod_t *imdp;
5686  struct sy_t *syp;
5687 
5688  if (axp == NULL) flag = 0;
5689  else if (!__get_eval_word(axp->lu.x, &flag))
5690   {
5691    __sgfwarn(646, "$showscopes argument value %s has x/z bits - made 0",
5692     __msgexpr_tostr(__xs, axp->lu.x));
5693    flag = 0;
5694   }
5695  /* use current thread to determine if in task */
5696  /* if no thread (sim. not started) cannot be active task */
5697  if (__cur_thd == NULL) tskp = NULL; else tskp = __getcur_scope_tsk();
5698 
5699  /* 0 means current level, other value all underneath */
5700  if (flag == 0)
5701   {
5702    if (tskp == NULL) prt_1m_scopelist(__inst_ptr);
5703    else prt_1tsk_scopelist(tskp, TRUE);
5704   }
5705  else
5706   {
5707    __cvsim_msg("Nested scopes:\n");
5708    __outlinpos = 0;
5709    __pv_stlevel = 0;
5710 
5711    if (tskp == NULL) prt_1m_nestscopes(__inst_ptr);
5712    /* if current scope is task, must print out named blocks inside */
5713    else prt_1tsk_nestscopes(tskp->tsksymtab->sytofs);
5714 
5715    __pv_stlevel = 0;
5716    __outlinpos = 0;
5717   }
5718 
5719  /* final step is printing current scope and list of top level modules */
5720  imdp = __inst_mod;
5721 
5722  if (tskp == NULL) syp = imdp->msym; else syp = tskp->tsksyp;
5723  __cvsim_msg("Current scope: %s (file %s line %d)\n",
5724   __msg_blditree(__xs, __inst_ptr, tskp), __schop(__xs2,
5725   __in_fils[syp->syfnam_ind]), syp->sylin_cnt);
5726  __prt_top_mods();
5727 }
5728 
5729 /*
5730  * show one module scope level given itree location
5731  *
5732  * notice this is sort of static since once at itree location under same
5733  * 4 catagories of scopes: instances, tasks, functions, named blocks
5734  * everything here but named blockes in tasks/functions or named blocks
5735  */
prt_1m_scopelist(struct itree_t * itp)5736 static void prt_1m_scopelist(struct itree_t *itp)
5737 {
5738  register int32 i;
5739  register struct task_t *tskp;
5740  int32 none, first_time;
5741  struct mod_t *imdp;
5742  struct inst_t *ip;
5743 
5744  if (__outlinpos != 0) __misc_terr(__FILE__, __LINE__);
5745  /* first instances */
5746  __pv_stlevel = 0;
5747  imdp = itp->itip->imsym->el.emdp;
5748  if (imdp->minum != 0) __wrap_puts("  Instances:", stdout);
5749  __pv_stlevel = 3;
5750  for (i = 0; i < imdp->minum; i++)
5751   {
5752    ip = &(imdp->minsts[i]);
5753    __wrap_putc(' ', stdout);
5754    __wrap_puts(ip->isym->synam, stdout);
5755    __wrap_putc('(', stdout);
5756    __wrap_puts(ip->imsym->synam, stdout);
5757    if (i < imdp->minum - 1) __wrap_puts("),", stdout);
5758    else __wrap_putc(')', stdout);
5759   }
5760  if (__outlinpos != 0) { __wrap_putc('\n', stdout); __outlinpos = 0; }
5761  __pv_stlevel = 0;
5762 
5763  /* next tasks */
5764  for (none = TRUE, tskp = imdp->mtasks; tskp != NULL; tskp = tskp->tsknxt)
5765   { if (tskp->tsktyp == TASK) { none = FALSE; break; } }
5766  if (!none)
5767   {
5768    __wrap_puts("  Tasks:", stdout);
5769    __pv_stlevel = 3;
5770    first_time = TRUE;
5771    for (tskp = imdp->mtasks; tskp != NULL; tskp = tskp->tsknxt)
5772     {
5773      if (tskp->tsktyp != TASK) continue;
5774      if (first_time) { __wrap_putc(' ', stdout); first_time = FALSE; }
5775      else __wrap_puts(", ", stdout);
5776      __wrap_puts(tskp->tsksyp->synam, stdout);
5777     }
5778    if (__outlinpos != 0) { __wrap_putc('\n', stdout); __outlinpos = 0; }
5779    __pv_stlevel = 0;
5780   }
5781  /* next functons */
5782  for (none = TRUE, tskp = imdp->mtasks; tskp != NULL; tskp = tskp->tsknxt)
5783   { if (tskp->tsktyp == FUNCTION) { none = FALSE; break; } }
5784  if (!none)
5785   {
5786    __wrap_puts("  Functions:", stdout);
5787    __pv_stlevel = 3;
5788    first_time = TRUE;
5789    for (tskp = imdp->mtasks; tskp != NULL; tskp = tskp->tsknxt)
5790     {
5791      if (tskp->tsktyp != FUNCTION) continue;
5792      if (first_time) { __wrap_putc(' ', stdout); first_time = FALSE; }
5793      else __wrap_puts(", ", stdout);
5794      __wrap_puts(tskp->tsksyp->synam, stdout);
5795     }
5796    if (__outlinpos != 0) { __wrap_putc('\n', stdout); __outlinpos = 0; }
5797    __pv_stlevel = 0;
5798   }
5799  /* finally named blocks */
5800  for (none = TRUE, tskp = imdp->mtasks; tskp != NULL; tskp = tskp->tsknxt)
5801   {
5802 
5803    if (tskp->tsktyp == FORK || tskp->tsktyp == Begin)
5804     { none = FALSE; break; }
5805   }
5806  if (!none)
5807   {
5808    __wrap_puts("  Named blocked:", stdout);
5809    __pv_stlevel = 3;
5810    first_time = TRUE;
5811    for (tskp = imdp->mtasks; tskp != NULL; tskp = tskp->tsknxt)
5812     {
5813 
5814      if (tskp->tsktyp == TASK || tskp->tsktyp == FUNCTION) continue;
5815      if (first_time) { __wrap_putc(' ', stdout); first_time = FALSE; }
5816      else __wrap_puts(", ", stdout);
5817      __wrap_puts(tskp->tsksyp->synam, stdout);
5818     }
5819    if (__outlinpos != 0) { __wrap_putc('\n', stdout); __outlinpos = 0; }
5820    __pv_stlevel = 0;
5821   }
5822 }
5823 
5824 /*
5825  * print the scopes in a task scope
5826  * here can only be named blocks located from symbol table
5827  * separate routine for recursive named block listing
5828  */
prt_1tsk_scopelist(struct task_t * tskp,int32 nd_msg)5829 static void prt_1tsk_scopelist(struct task_t *tskp, int32 nd_msg)
5830 {
5831  register struct symtab_t *sytp2;
5832  struct symtab_t *sytp;
5833  int32 first_time;
5834 
5835  sytp = tskp->tsksymtab;
5836  if (sytp->sytofs == NULL && nd_msg) return;
5837  __wrap_puts("  Named blocks:", stdout);
5838  __pv_stlevel = 3;
5839  first_time = FALSE;
5840  for (sytp2 = sytp->sytofs; sytp2 != NULL; sytp2 = sytp2->sytsib)
5841   {
5842    if (first_time) { first_time = FALSE; __wrap_putc(' ', stdout); }
5843    else __wrap_puts(", ", stdout);
5844    __wrap_puts(sytp2->sypofsyt->synam, stdout);
5845   }
5846  if (__outlinpos != 0) { __wrap_putc('\n', stdout); __outlinpos = 0; }
5847  __pv_stlevel = 0;
5848  if (__outlinpos != 0) __misc_terr(__FILE__, __LINE__);
5849  /* first instances */
5850  __pv_stlevel = 0;
5851 }
5852 
5853 /*
5854  * for module print nested scopes with indent - to show the scope structure
5855  */
prt_1m_nestscopes(struct itree_t * itp)5856 static void prt_1m_nestscopes(struct itree_t *itp)
5857 {
5858  register int32 i;
5859  register struct task_t *tskp;
5860  struct mod_t *mdp;
5861  struct itree_t *down_itp;
5862  struct inst_t *ip;
5863 
5864  __pv_stlevel++;
5865  mdp = itp->itip->imsym->el.emdp;
5866  for (i = 0; i < mdp->minum; i++)
5867   {
5868    down_itp = &(itp->in_its[i]);
5869    ip = down_itp->itip;
5870    __wrap_putc(' ', stdout);
5871    __wrap_puts(ip->isym->synam, stdout);
5872    __wrap_putc('(', stdout);
5873    __wrap_puts(ip->imsym->synam, stdout);
5874    __wrap_putc(')', stdout);
5875    if (__outlinpos != 0) { __wrap_putc('\n', stdout); __outlinpos = 0; }
5876    prt_1m_nestscopes(down_itp);
5877   }
5878  /* next tasks */
5879  __pv_stlevel++;
5880  for (tskp = mdp->mtasks; tskp != NULL; tskp = tskp->tsknxt)
5881   {
5882 
5883    sprintf(__xs, "%s: ", __to_tsktyp(__xs2, tskp->tsktyp));
5884    __wrap_puts(__xs, stdout);
5885    __wrap_puts(tskp->tsksyp->synam, stdout);
5886    if (__outlinpos != 0) { __wrap_putc('\n', stdout); __outlinpos = 0; }
5887    if (tskp->tsksymtab->sytofs != NULL)
5888     {
5889      __pv_stlevel++;
5890      prt_1tsk_nestscopes(tskp->tsksymtab->sytofs);
5891      __pv_stlevel--;
5892     }
5893   }
5894  __pv_stlevel -= 2;
5895 }
5896 
prt_1tsk_nestscopes(struct symtab_t * up_sytp)5897 static void prt_1tsk_nestscopes(struct symtab_t *up_sytp)
5898 {
5899  struct symtab_t *sytp;
5900  struct task_t *tskp;
5901 
5902  for (sytp = up_sytp->sytofs; sytp != NULL; sytp = sytp->sytsib)
5903   {
5904    tskp = sytp->sypofsyt->el.etskp;
5905    sprintf(__xs, "%s: ", __to_tsktyp(__xs2, tskp->tsktyp));
5906    __wrap_puts(__xs, stdout);
5907    __wrap_puts(tskp->tsksyp->synam, stdout);
5908    if (__outlinpos != 0) { __wrap_putc('\n', stdout); __outlinpos = 0; }
5909    if (tskp->tsksymtab->sytofs != NULL)
5910     {
5911      __pv_stlevel++;
5912      prt_1tsk_nestscopes(tskp->tsksymtab->sytofs);
5913      __pv_stlevel--;
5914     }
5915   }
5916 }
5917 
5918 /*
5919  * BUILT INTO VERILOG STOCHASTIC QUEUE SYSTEM TASKS
5920  */
5921 
5922 /*
5923  * execute the qfull function - must push 1 (room), 0 no room onto xstk
5924  *
5925  * LOOKATME - is this a 1 bit 0/1?
5926  */
exec_qfull(struct expr_t * argxp)5927 static void exec_qfull(struct expr_t *argxp)
5928 {
5929  int32 q_id, rv;
5930  word32 val;
5931  struct q_hdr_t *q_p;
5932  struct expr_t *xp, *a1xp, *a2xp;
5933  struct xstk_t *xsp;
5934 
5935  rv = 0;
5936  /* access the required 4 arguments */
5937  if ((xp = argxp) == NULL) __arg_terr(__FILE__, __LINE__);
5938  /* first element in function arg. list is return variable */
5939  if ((xp = xp->ru.x) == NULL) __arg_terr(__FILE__, __LINE__);
5940  a1xp = xp->lu.x;
5941  if ((xp = xp->ru.x) == NULL) __arg_terr(__FILE__, __LINE__);
5942  a2xp = xp->lu.x;
5943 
5944  if (!__get_eval_word(a1xp, &val))
5945   {
5946    __sgfwarn(596, "$q_full argument 1, q_id value %s x/z or out of range",
5947     __msgexpr_tostr(__xs, a1xp));
5948 ret_x:
5949    push_xstk_(xsp, 1);
5950    xsp->ap[0] = 1;
5951    xsp->bp[0] = 1;
5952    rv = 2;
5953    goto done;
5954   }
5955  q_id = (int32) val;
5956 
5957  /* find q that matches passed q id */
5958  if ((q_p = find_q_from_id(q_id)) == NULL) goto ret_x;
5959 
5960  push_xstk_(xsp, 1);
5961  xsp->bp[0] = 0;
5962  if (q_p->q_size >= q_p->q_maxlen) xsp->ap[0] = 1;
5963  else xsp->ap[0] = 0;
5964 
5965 done:
5966  if (a2xp->optyp == OPEMPTY) return;
5967 
5968  push_xstk_(xsp, WBITS);
5969  xsp->ap[0] = (word32) rv;
5970  xsp->bp[0] = 0L;
5971 
5972  /* SJM 09/29/03 - change to handle sign extension and separate types */
5973  /* know xsp WBITS but can widen or narow */
5974  if (xsp->xslen > a2xp->szu.xclen) __narrow_sizchg(xsp, a2xp->szu.xclen);
5975  else if (xsp->xslen < a2xp->szu.xclen)
5976   {
5977    if (a2xp->has_sign) __sgn_xtnd_widen(xsp, a2xp->szu.xclen);
5978    else __sizchg_widen(xsp, a2xp->szu.xclen);
5979   }
5980 
5981  __exec2_proc_assign(a2xp, xsp->ap, xsp->bp);
5982  __pop_xstk();
5983 }
5984 
5985 /*
5986  * initialize a queue
5987  *
5988  * know exactly 4 args (possibly ,,) or will not get here
5989  */
do_q_init(struct expr_t * argxp)5990 static void do_q_init(struct expr_t *argxp)
5991 {
5992  int32 q_id, q_type, q_maxlen, rv;
5993  word32 val;
5994  struct q_hdr_t *q_p;
5995  struct expr_t *xp, *a1xp, *a2xp, *a3xp, *a4xp;
5996  struct xstk_t *xsp;
5997 
5998  rv = 0;
5999  /* access the required 4 arguments */
6000  if ((xp = argxp) == NULL) __arg_terr(__FILE__, __LINE__);
6001  a1xp = xp->lu.x;
6002  if ((xp = xp->ru.x) == NULL) __arg_terr(__FILE__, __LINE__);
6003  a2xp = xp->lu.x;
6004  if ((xp = xp->ru.x) == NULL) __arg_terr(__FILE__, __LINE__);
6005  a3xp = xp->lu.x;
6006  if ((xp = xp->ru.x) == NULL) __arg_terr(__FILE__, __LINE__);
6007  a4xp = xp->lu.x;
6008  if (xp->ru.x != NULL) __arg_terr(__FILE__, __LINE__);
6009 
6010  /* access the rhs arguments */
6011  if (!__get_eval_word(a1xp, &val))
6012   {
6013    __sgfwarn(596, "$q_initialize argument 1, q_id value %s x/z or out of range",
6014     __msgexpr_tostr(__xs, a1xp));
6015    rv = 2;
6016    q_id = 0;
6017   }
6018  else q_id = (int32) val;
6019  if (!__get_eval_word(a2xp, &val) || val < 1 || val > 2)
6020   {
6021    __sgfwarn(596,
6022     "$q_initialize argument 2, q_type value %s x/z or out of range",
6023     __msgexpr_tostr(__xs, a2xp));
6024    if (rv == 0) rv = 4;
6025    q_type = 0;
6026   }
6027  else q_type = (int32) val;
6028  if (!__get_eval_word(a3xp, &val))
6029   {
6030 bad_qlen:
6031    __sgfwarn(596,
6032     "$q_initialize argument 3, max_length value %s x/z or negative",
6033     __msgexpr_tostr(__xs, a3xp));
6034    if (rv == 0) rv = 5;
6035    q_maxlen = 0;
6036   }
6037  else
6038   {
6039    q_maxlen = (int32) val;
6040    if (q_maxlen <= 0) goto bad_qlen;
6041   }
6042  if (rv != 0) goto done;
6043 
6044  /* make sure id is unqiue */
6045  if (find_q_from_id(q_id) != NULL) { rv = 6; goto done; }
6046 
6047  /* allocate the new q header and link into q list */
6048  q_p = (struct q_hdr_t *) __my_malloc(sizeof(struct q_hdr_t));
6049  init_q(q_p);
6050  if (__qlist_hdr == NULL) __qlist_hdr = q_p;
6051  else { q_p->qhdrnxt = __qlist_hdr; __qlist_hdr = q_p; }
6052  if (q_type == 1) q_p->q_fifo = TRUE; else q_p->q_fifo = FALSE;
6053  q_p->qarr = (struct q_val_t *) __my_malloc(q_maxlen*sizeof(struct q_val_t));
6054  memset(q_p->qarr, 0, q_maxlen*sizeof(struct q_val_t));
6055  q_p->q_id = q_id;
6056  q_p->q_maxlen = q_maxlen;
6057 
6058 done:
6059  if (a4xp->optyp == OPEMPTY) return;
6060 
6061  push_xstk_(xsp, WBITS);
6062  xsp->ap[0] = (word32) rv;
6063  xsp->bp[0] = 0L;
6064 
6065  /* SJM 09/29/03 - change to handle sign extension and separate types */
6066  /* know xsp WBITS but can widen or narow */
6067  if (xsp->xslen > a4xp->szu.xclen) __narrow_sizchg(xsp, a4xp->szu.xclen);
6068  else if (xsp->xslen < a4xp->szu.xclen)
6069   {
6070    if (a2xp->has_sign) __sgn_xtnd_widen(xsp, a4xp->szu.xclen);
6071    else __sizchg_widen(xsp, a4xp->szu.xclen);
6072   }
6073 
6074  __exec2_proc_assign(a4xp, xsp->ap, xsp->bp);
6075  __pop_xstk();
6076 }
6077 
6078 /*
6079  * initialize a q
6080  */
init_q(struct q_hdr_t * q_p)6081 static void init_q(struct q_hdr_t *q_p)
6082 {
6083  q_p->q_fifo = FALSE;
6084  q_p->q_id = 0;
6085  q_p->q_hdr = -1;
6086  q_p->q_tail = -1;
6087  q_p->q_maxlen = 0;
6088  q_p->q_size = 0;
6089  q_p->q_minwait = 0xffffffffffffffffULL;
6090  q_p->qhdrnxt = NULL;
6091 }
6092 
6093 /*
6094  * find q header record from identifying q id number
6095  *
6096  * LOOKATME - could use binary search but think will not be many queues
6097  */
find_q_from_id(int32 id)6098 static struct q_hdr_t *find_q_from_id(int32 id)
6099 {
6100  register struct q_hdr_t *qp;
6101 
6102  for (qp = __qlist_hdr; qp != NULL; qp = qp->qhdrnxt)
6103   {
6104    if (qp->q_id == id) return(qp);
6105   }
6106  return(NULL);
6107 }
6108 
6109 /*
6110  * add an element to a queue
6111  *
6112  * know exactly 4 args (possibly ,,) or will not get here
6113  */
do_q_add(struct expr_t * argxp)6114 static void do_q_add(struct expr_t *argxp)
6115 {
6116  int32 q_id, qjob_id, qinform_id, rv;
6117  word32 val;
6118  struct q_hdr_t *q_p;
6119  struct q_val_t *qvp;
6120  struct expr_t *xp, *a1xp, *a2xp, *a3xp, *a4xp;
6121  struct xstk_t *xsp;
6122 
6123  rv = 0;
6124  /* access the required 4 arguments */
6125  if ((xp = argxp) == NULL) __arg_terr(__FILE__, __LINE__);
6126  a1xp = xp->lu.x;
6127  if ((xp = xp->ru.x) == NULL) __arg_terr(__FILE__, __LINE__);
6128  a2xp = xp->lu.x;
6129  if ((xp = xp->ru.x) == NULL) __arg_terr(__FILE__, __LINE__);
6130  a3xp = xp->lu.x;
6131  if ((xp = xp->ru.x) == NULL) __arg_terr(__FILE__, __LINE__);
6132  a4xp = xp->lu.x;
6133  if (xp->ru.x != NULL) __arg_terr(__FILE__, __LINE__);
6134 
6135  /* access the rhs arguments */
6136  if (!__get_eval_word(a1xp, &val))
6137   {
6138    __sgfwarn(596, "$q_add argument 1, q_id value %s x/z or out of range",
6139     __msgexpr_tostr(__xs, a1xp));
6140    rv = 2;
6141    q_id = 0;
6142   }
6143  else q_id = (int32) val;
6144  if (a2xp->optyp == OPEMPTY) qjob_id = 0;
6145  else
6146   {
6147    if (!__get_eval_word(a2xp, &val))
6148     {
6149      __sgfwarn(596,
6150       "$q_add argument 2, job_id value %s x/z or too wide (0 used)",
6151       __msgexpr_tostr(__xs, a2xp));
6152      val = 0;
6153     }
6154    qjob_id = (int32) val;
6155   }
6156  if (a3xp->optyp == OPEMPTY) qinform_id = 0;
6157  else
6158   {
6159    if (!__get_eval_word(a3xp, &val))
6160     {
6161      __sgfwarn(596,
6162       "$q_add argument 3, inform_id value %s x/z or too wide (0 used)",
6163       __msgexpr_tostr(__xs, a3xp));
6164      val = 0;
6165     }
6166    qinform_id = (int32) val;
6167   }
6168  if (rv != 0) goto done;
6169 
6170  /* find q that matches passed q id */
6171  if ((q_p = find_q_from_id(q_id)) == NULL) { rv = 2; goto done; }
6172 
6173  /* add the element */
6174  if (q_p->q_fifo)
6175   {
6176    if (q_p->q_hdr == -1) q_p->q_hdr = q_p->q_tail = 0;
6177    else
6178     {
6179      if (q_p->q_size >= q_p->q_maxlen) { rv = 1; goto done; }
6180      (q_p->q_hdr)++;
6181      /* wrap queue around - since size not too big know empty */
6182      if (q_p->q_hdr >= q_p->q_maxlen) q_p->q_hdr = 0;
6183     }
6184   }
6185  else
6186   {
6187    /* easy stack lifo case - q tail not used */
6188    if (q_p->q_hdr == -1) q_p->q_hdr = 0;
6189    else
6190     {
6191      if (q_p->q_size >= q_p->q_maxlen) { rv = 1; goto done; }
6192      (q_p->q_hdr)++;
6193     }
6194   }
6195  qvp = &(q_p->qarr[q_p->q_hdr]);
6196  (q_p->q_size)++;
6197  if (q_p->q_size > q_p->q_maxsize) q_p->q_maxsize = q_p->q_size;
6198  qvp->job_id = qjob_id;
6199  qvp->inform_id = qinform_id;
6200  qvp->enter_tim = __simtime;
6201 
6202 done:
6203  if (a4xp->optyp == OPEMPTY) return;
6204 
6205  push_xstk_(xsp, WBITS);
6206  xsp->ap[0] = (word32) rv;
6207  xsp->bp[0] = 0L;
6208 
6209  /* SJM 09/29/03 - change to handle sign extension and separate types */
6210  /* know xsp WBITS but can widen or narow */
6211  if (xsp->xslen > a4xp->szu.xclen) __narrow_sizchg(xsp, a4xp->szu.xclen);
6212  else if (xsp->xslen < a4xp->szu.xclen)
6213   {
6214    if (a2xp->has_sign) __sgn_xtnd_widen(xsp, a4xp->szu.xclen);
6215    else __sizchg_widen(xsp, a4xp->szu.xclen);
6216   }
6217 
6218  __exec2_proc_assign(a4xp, xsp->ap, xsp->bp);
6219  __pop_xstk();
6220 }
6221 
6222 /*
6223  * delete an element from a queue
6224  *
6225  * know exactly 4 args (possibly ,,) or will not get here
6226  */
do_q_remove(struct expr_t * argxp)6227 static void do_q_remove(struct expr_t *argxp)
6228 {
6229  int32 q_id, qjob_id, qinform_id, rv;
6230  word32 val;
6231  word64 timval;
6232  struct q_hdr_t *q_p;
6233  struct q_val_t *qvp;
6234  struct expr_t *xp, *a1xp, *a2xp, *a3xp, *a4xp;
6235  struct xstk_t *xsp;
6236 
6237  rv = 0;
6238  /* access the required 4 arguments - last 3 outputs can be empty */
6239  if ((xp = argxp) == NULL) __arg_terr(__FILE__, __LINE__);
6240  a1xp = xp->lu.x;
6241  if ((xp = xp->ru.x) == NULL) __arg_terr(__FILE__, __LINE__);
6242  a2xp = xp->lu.x;
6243  if ((xp = xp->ru.x) == NULL) __arg_terr(__FILE__, __LINE__);
6244  a3xp = xp->lu.x;
6245  if ((xp = xp->ru.x) == NULL) __arg_terr(__FILE__, __LINE__);
6246  a4xp = xp->lu.x;
6247  if (xp->ru.x != NULL) __arg_terr(__FILE__, __LINE__);
6248 
6249  /* access the rhs arguments */
6250  if (!__get_eval_word(a1xp, &val))
6251   {
6252    __sgfwarn(596, "$q_remove argument 1, q_id value %s x/z or out of range",
6253     __msgexpr_tostr(__xs, a1xp));
6254    rv = 2;
6255    goto done;
6256   }
6257  else q_id = (int32) val;
6258 
6259  /* find q that matches passed q id */
6260  if ((q_p = find_q_from_id(q_id)) == NULL) { rv = 2; goto done; }
6261 
6262  /* here no assignment to output values */
6263  if (q_p->q_size == 0) { rv = 3; goto done; }
6264 
6265  qvp = &(q_p->qarr[q_p->q_tail]);
6266  /* delete the element - take off from tail */
6267  if (q_p->q_fifo)
6268   {
6269    if (q_p->q_size == 1) q_p->q_hdr = q_p->q_tail = -1;
6270    else
6271     {
6272      (q_p->q_tail)++;
6273      /* wrap queue around - since size not too big know empty */
6274      if (q_p->q_tail >= q_p->q_maxlen) q_p->q_tail = 0;
6275     }
6276   }
6277  /* easy stack lifo case - q tail not used */
6278  else (q_p->q_hdr)--;
6279 
6280  /* save minimum time in q (wait time) */
6281  timval = __simtime - qvp->enter_tim;
6282  if (timval < q_p->q_minwait) q_p->q_minwait = timval;
6283 
6284  (q_p->q_size)--;
6285  qjob_id = qvp->job_id;
6286  qinform_id = qvp->inform_id;
6287 
6288  if (a2xp->optyp != OPEMPTY)
6289   {
6290    push_xstk_(xsp, WBITS);
6291    xsp->ap[0] = (word32) qjob_id;
6292    xsp->bp[0] = 0L;
6293 
6294    /* SJM 09/29/03 - change to handle sign extension and separate types */
6295    /* know xsp WBITS but can widen or narow */
6296    if (xsp->xslen > a2xp->szu.xclen) __narrow_sizchg(xsp, a2xp->szu.xclen);
6297    else if (xsp->xslen < a2xp->szu.xclen)
6298     {
6299      if (a2xp->has_sign) __sgn_xtnd_widen(xsp, a2xp->szu.xclen);
6300      else __sizchg_widen(xsp, a2xp->szu.xclen);
6301     }
6302 
6303    __exec2_proc_assign(a2xp, xsp->ap, xsp->bp);
6304    __pop_xstk();
6305   }
6306 
6307  if (a3xp->optyp != OPEMPTY)
6308   {
6309    push_xstk_(xsp, WBITS);
6310    xsp->ap[0] = (word32) qinform_id;
6311    xsp->bp[0] = 0L;
6312 
6313    /* SJM 09/29/03 - change to handle sign extension and separate types */
6314    /* know xsp WBITS but can widen or narow */
6315    if (xsp->xslen > a3xp->szu.xclen) __narrow_sizchg(xsp, a3xp->szu.xclen);
6316    else if (xsp->xslen < a3xp->szu.xclen)
6317     {
6318      if (a3xp->has_sign) __sgn_xtnd_widen(xsp, a3xp->szu.xclen);
6319      else __sizchg_widen(xsp, a3xp->szu.xclen);
6320     }
6321 
6322    __exec2_proc_assign(a3xp, xsp->ap, xsp->bp);
6323    __pop_xstk();
6324   }
6325 
6326 done:
6327  if (a4xp->optyp == OPEMPTY) return;
6328 
6329  push_xstk_(xsp, WBITS);
6330  xsp->ap[0] = (word32) rv;
6331  xsp->bp[0] = 0L;
6332 
6333  /* SJM 09/29/03 - change to handle sign extension and separate types */
6334  /* know xsp WBITS but can widen or narow */
6335  if (xsp->xslen > a4xp->szu.xclen) __narrow_sizchg(xsp, a4xp->szu.xclen);
6336  else if (xsp->xslen < a4xp->szu.xclen)
6337   {
6338    if (a4xp->has_sign) __sgn_xtnd_widen(xsp, a4xp->szu.xclen);
6339    else __sizchg_widen(xsp, a4xp->szu.xclen);
6340   }
6341 
6342  __exec2_proc_assign(a4xp, xsp->ap, xsp->bp);
6343  __pop_xstk();
6344 }
6345 
6346 /*
6347  * examine a queue
6348  *
6349  * know exactly 4 args (possibly ,,) or will not get here
6350  */
do_q_examine(struct expr_t * argxp)6351 static void do_q_examine(struct expr_t *argxp)
6352 {
6353  int32 q_id, q_stat_code, rv;
6354  word32 val;
6355  word64 timval;
6356  struct q_hdr_t *q_p;
6357  struct expr_t *xp, *a1xp, *a2xp, *a3xp, *a4xp;
6358  struct xstk_t *xsp;
6359 
6360  rv = 0;
6361  /* access the required 4 arguments - last 3 outputs can be empty */
6362  if ((xp = argxp) == NULL) __arg_terr(__FILE__, __LINE__);
6363  a1xp = xp->lu.x;
6364  if ((xp = xp->ru.x) == NULL) __arg_terr(__FILE__, __LINE__);
6365  a2xp = xp->lu.x;
6366  if ((xp = xp->ru.x) == NULL) __arg_terr(__FILE__, __LINE__);
6367  a3xp = xp->lu.x;
6368  if ((xp = xp->ru.x) == NULL) __arg_terr(__FILE__, __LINE__);
6369  a4xp = xp->lu.x;
6370  if (xp->ru.x != NULL) __arg_terr(__FILE__, __LINE__);
6371 
6372  /* access the rhs arguments */
6373  if (!__get_eval_word(a1xp, &val))
6374   {
6375    __sgfwarn(596, "$q_examine argument 1, q_id value %s x/z or out of range",
6376     __msgexpr_tostr(__xs, a1xp));
6377    rv = 2;
6378    goto done;
6379   }
6380  q_id = (int32) val;
6381 
6382  if (!__get_eval_word(a2xp, &val) || val < 1 || val > 6)
6383   {
6384    __sgfwarn(596,
6385     "$q_examine argument 2, q_stat_code value %s x/z or out of range",
6386     __msgexpr_tostr(__xs, a2xp));
6387    /* LOOKATME - really no good value for this error */
6388    q_stat_code = 0;
6389    rv = 4;
6390   }
6391  else q_stat_code = (int32) val;
6392 
6393  if (rv != 0) goto done;
6394 
6395  /* find q that matches passed q id */
6396  if ((q_p = find_q_from_id(q_id)) == NULL) { rv = 2; goto done; }
6397 
6398  switch (q_stat_code) {
6399   case 1:
6400    /* current size of q */
6401    push_xstk_(xsp, WBITS);
6402    xsp->ap[0] = (word32) q_p->q_size;
6403    xsp->bp[0] = 0L;
6404    break;
6405   case 2:
6406    /* mean inter arrival time for elements currently in the q */
6407    cmp_mean_interarriv_tim(&timval, q_p);
6408 push_cmp_tim:
6409    push_xstk_(xsp, 64);
6410    xsp->ap[0] = (word32) (timval & WORDMASK_ULL);
6411    xsp->ap[1] = (word32) ((timval >> 32) & WORDMASK_ULL);
6412    xsp->bp[0] = xsp->bp[1] = 0L;
6413    break;
6414   case 3:
6415    /* maximum size queue ever attained */
6416    push_xstk_(xsp, WBITS);
6417    xsp->ap[0] = (word32) q_p->q_maxsize;
6418    xsp->bp[0] = 0L;
6419    break;
6420   case 4:
6421    push_xstk_(xsp, 64);
6422    xsp->ap[0] = (word32) (q_p->q_minwait & WORDMASK_ULL);
6423    xsp->ap[1] = (word32) ((q_p->q_minwait >> 32) & WORDMASK_ULL);
6424    xsp->bp[0] = xsp->bp[1] = 0L;
6425    break;
6426   case 5:
6427    cmp_max_wait(&timval, q_p);
6428    goto push_cmp_tim;
6429   case 6:
6430    cmp_mean_wait_tim(&timval, q_p);
6431    goto push_cmp_tim;
6432   default: __case_terr(__FILE__, __LINE__); return;
6433  }
6434 
6435  /* only assign result, lhs arg. passed */
6436  if (a3xp->optyp != OPEMPTY)
6437   {
6438    /* SJM 09/29/03 - change to handle sign extension and separate types */
6439    /* know xsp WBITS but can widen or narow */
6440    if (xsp->xslen > a3xp->szu.xclen) __narrow_sizchg(xsp, a3xp->szu.xclen);
6441    else if (xsp->xslen < a3xp->szu.xclen)
6442     {
6443      if (a3xp->has_sign) __sgn_xtnd_widen(xsp, a3xp->szu.xclen);
6444      else __sizchg_widen(xsp, a3xp->szu.xclen);
6445     }
6446 
6447    __exec2_proc_assign(a3xp, xsp->ap, xsp->bp);
6448   }
6449  __pop_xstk();
6450 
6451 done:
6452  if (a4xp->optyp == OPEMPTY) return;
6453 
6454  push_xstk_(xsp, WBITS);
6455  xsp->ap[0] = (word32) rv;
6456  xsp->bp[0] = 0L;
6457 
6458  /* SJM 09/29/03 - change to handle sign extension and separate types */
6459  /* know xsp WBITS but can widen or narow */
6460  if (xsp->xslen > a4xp->szu.xclen) __narrow_sizchg(xsp, a4xp->szu.xclen);
6461  else if (xsp->xslen < a4xp->szu.xclen)
6462   {
6463    if (a4xp->has_sign) __sgn_xtnd_widen(xsp, a4xp->szu.xclen);
6464    else __sizchg_widen(xsp, a4xp->szu.xclen);
6465   }
6466 
6467  __exec2_proc_assign(a4xp, xsp->ap, xsp->bp);
6468  __pop_xstk();
6469 }
6470 
6471 /*
6472  * compute average inter (between 2) arrival time for qs currently in queue
6473  */
cmp_mean_interarriv_tim(word64 * timvalp,struct q_hdr_t * q_p)6474 static void cmp_mean_interarriv_tim(word64 *timvalp, struct q_hdr_t *q_p)
6475 {
6476  register int32 qi, i;
6477  word64 avgtim, arrdif, quot, rem;
6478 
6479  /* for one or less size q mean always 0 */
6480  if (q_p->q_size <= 1) { *timvalp = 0ULL; return; }
6481  avgtim = 0ULL;
6482  if (q_p->q_fifo)
6483   {
6484    for (qi = q_p->q_hdr, i = 0; i < q_p->q_size; i++)
6485     {
6486      if ((++qi) >= q_p->q_size) qi = 0;
6487      if (i == 0) continue;
6488 
6489      arrdif = q_p->qarr[qi].enter_tim - q_p->qarr[qi - 1].enter_tim;
6490      avgtim += arrdif;
6491     }
6492   }
6493  else
6494   {
6495    /* easy lifo stack case */
6496    for (qi = 0; qi < q_p->q_size; qi++)
6497     {
6498      if (qi == 0) continue;
6499      arrdif = q_p->qarr[qi].enter_tim - q_p->qarr[qi - 1].enter_tim;
6500      avgtim += arrdif;
6501     }
6502   }
6503  /* divide - round - know q at least 2 elements to get here */
6504  /* SJM 02/03/00 - cast of negative (>2**31) sign extends need word32 1st */
6505  quot = avgtim/((word64) (((word32) q_p->q_size) - 1));
6506  rem = avgtim % ((word64) (((word32) q_p->q_size) - 1));
6507  avgtim = quot;
6508  if (rem >= ((word64) (((word32) q_p->q_size)/2))) avgtim++;
6509  *timvalp = avgtim;
6510 }
6511 
6512 /*
6513  * compute longest wait (in queue) time for elements in queue
6514  */
cmp_max_wait(word64 * timvalp,struct q_hdr_t * q_p)6515 static void cmp_max_wait(word64 *timvalp, struct q_hdr_t *q_p)
6516 {
6517  register int32 qi, i;
6518  word64 inqtim;
6519 
6520  if (q_p->q_size <= 1) { *timvalp = 0ULL; return; }
6521  if (q_p->q_fifo)
6522   {
6523    for (qi = q_p->q_hdr, i = 0; i < q_p->q_size; i++)
6524     {
6525      if ((++qi) >= q_p->q_size) qi = 0;
6526      if (i == 0)
6527       {
6528        *timvalp = q_p->qarr[qi].enter_tim;
6529        continue;
6530       }
6531      inqtim = __simtime - q_p->qarr[qi].enter_tim;
6532      if (inqtim < *timvalp) *timvalp = inqtim;
6533     }
6534   }
6535  else
6536   {
6537    /* easy lifo stack case */
6538    for (qi = 0; qi < q_p->q_size; qi++)
6539     {
6540      if (qi == 0)
6541       {
6542        *timvalp = q_p->qarr[qi].enter_tim;
6543        continue;
6544       }
6545      inqtim = __simtime - q_p->qarr[qi].enter_tim;
6546      if (inqtim < *timvalp) *timvalp = inqtim;
6547     }
6548   }
6549 }
6550 
6551 /*
6552  * compute average (mean) time each element has spent in queue
6553  */
cmp_mean_wait_tim(word64 * timvalp,struct q_hdr_t * q_p)6554 static void cmp_mean_wait_tim(word64 *timvalp, struct q_hdr_t *q_p)
6555 {
6556  register int32 qi, i;
6557  word64 avgtim, waitdif, quot, rem;
6558 
6559  if (q_p->q_size <= 0) { *timvalp = 0ULL; return; }
6560  avgtim = 0ULL;
6561  if (q_p->q_fifo)
6562   {
6563    for (qi = q_p->q_hdr, i = 0; i < q_p->q_size; i++)
6564     {
6565      if ((++qi) >= q_p->q_size) qi = 0;
6566      waitdif = __simtime - q_p->qarr[qi].enter_tim;
6567      avgtim += waitdif;
6568     }
6569   }
6570  else
6571   {
6572    /* easy lifo stack case */
6573    for (qi = 0; qi < q_p->q_size; qi++)
6574     {
6575      waitdif = __simtime - q_p->qarr[qi].enter_tim;
6576      avgtim += waitdif;
6577     }
6578   }
6579  /* divide - round - know q at least 1 element to get here */
6580  quot = avgtim/((word64) ((word32) q_p->q_size));
6581  rem = avgtim % ((word64) ((word32) q_p->q_size));
6582  avgtim = quot;
6583  if (rem >= ((word64) (((word32) q_p->q_size)/2))) avgtim++;
6584  *timvalp = avgtim;
6585 }
6586 
6587 /*
6588  * TIMESCALE TASK ROUTINES
6589  */
6590 
6591 /*
6592  * execute the print time scale
6593  * know the 1 arg. is xmr or no arg means current scope
6594  *
6595  * know arg. is xmr even if only has one component
6596  * axp is nil (for none) or function call comma operator (head of list)
6597  */
exec_prttimscale(struct expr_t * axp)6598 static void exec_prttimscale(struct expr_t *axp)
6599 {
6600  struct mod_t *mdp;
6601  struct expr_t *ndp;
6602  char s1[RECLEN], s2[RECLEN], s3[RECLEN];
6603 
6604  __cur_sofs = 0;
6605  __adds("Time scale of (");
6606  if (axp == NULL)
6607   {
6608    mdp = __scope_ptr->itip->imsym->el.emdp;
6609    __disp_itree_path(__inst_ptr, (struct task_t *) NULL);
6610   }
6611  else
6612   {
6613    ndp = axp->lu.x;
6614    if (ndp->optyp == GLBREF)
6615     { mdp = ndp->ru.grp->targmdp; __adds(ndp->ru.grp->gnam); }
6616    else if (ndp->lu.sy->sytyp == SYM_M)
6617     { mdp = ndp->lu.sy->el.emdp; __adds(mdp->msym->synam); }
6618    else { __case_terr(__FILE__, __LINE__);  return; }
6619   }
6620  sprintf(s1, ") is %s / %s\n",
6621   __to_timunitnam(s2, mdp->mtime_units),
6622   __to_timunitnam(s3, mdp->mtime_units + mdp->mtime_prec));
6623  __adds(s1);
6624  /* notice cannot truncate here */
6625  my_puts_(__exprline, stdout);
6626  __cur_sofs = 0;
6627 }
6628 
6629 /*
6630  * execute the time format system task - just sets some internal values
6631  * know exactly four arguments or will not get here
6632  *
6633  * this allows ,, and missing arguments that mean use 0 - error
6634  */
exec_timefmt(struct expr_t * argxp)6635 static void exec_timefmt(struct expr_t *argxp)
6636 {
6637  int32 argi, i1, slen;
6638  word32 val, val1, val2, val3;
6639  struct expr_t *xp, *ndp;
6640  char *chp;
6641 
6642  /* set values for missing arguments */
6643  val1 = val2 = val3 = 0;
6644 
6645  argi = 1;
6646  /* empty arg. list already checked for */
6647  if ((xp = argxp) == NULL) __arg_terr(__FILE__, __LINE__);
6648  ndp = xp->lu.x;
6649  if (ndp->optyp != OPEMPTY)
6650   {
6651    /* eval. here is just word32 stored in 2 complement */
6652    if (!__get_eval_word(ndp, &val)) goto bad_arg;
6653    i1 = (int32) val;
6654    if (i1 > 0 || i1 < -15) goto bad_arg;
6655    i1 = -i1;
6656    val1 = (word32) i1;
6657    if (val1 > __des_timeprec)
6658     {
6659      __sgferr(1240,
6660       "$timeformat units %s (%d) impossible - must be larger than %s (%d) tick",
6661        __to_timunitnam(__xs, (word32) val1), -((int32) val1),
6662        __to_timunitnam(__xs2, (word32) __des_timeprec),
6663        -((int32) __des_timeprec));
6664      /* change nothing if this does not change */
6665      return;
6666     }
6667   }
6668  if ((xp = xp->ru.x) == NULL)
6669   { chp = __my_malloc(1); *chp = '\0'; slen = 1; goto do_chg; }
6670 
6671  ndp = xp->lu.x;
6672  argi++;
6673  if (ndp->optyp != OPEMPTY)
6674   {
6675    if (!__get_eval_word(ndp, &val)) goto bad_arg;
6676    i1 = (int32) val;
6677    if (i1 < 0 || i1 >= RECLEN) goto bad_arg;
6678    val2 = val;
6679   }
6680 
6681  if ((xp = xp->ru.x) == NULL)
6682   { chp = __my_malloc(1); *chp = '\0'; slen = 1; goto do_chg; }
6683  ndp = xp->lu.x;
6684  argi++;
6685  if (ndp->optyp != OPEMPTY)
6686   {
6687    chp = __get_eval_cstr(ndp, &slen);
6688    /* must fit in RECLEN style string - but maybe should be narrower */
6689    if (slen >= RECLEN) { __my_free(chp, slen + 1); goto bad_arg; }
6690   }
6691  else { chp = __my_malloc(1); *chp = '\0'; slen = 1; }
6692 
6693  if ((xp = xp->ru.x) == NULL) goto do_chg;
6694  ndp = xp->lu.x;
6695  argi++;
6696  /* must allow ,) form */
6697  if (ndp->optyp != OPEMPTY)
6698   {
6699    if (!__get_eval_word(ndp, &val) || val > 40)
6700     {
6701      __sgferr(1047,
6702       "$timeformat minimum field width must be between 0 and 40 - not changed");
6703      __my_free(chp, slen + 1);
6704      return;
6705     }
6706    val3 = val;
6707   }
6708 
6709 do_chg:
6710  if (slen > (int32) (val3 + 1))
6711   {
6712    __sgferr(1047,
6713     "$timeformat suffix length %d wider than minimum field width (%d) - not changed",
6714     slen, val3);
6715    __my_free(chp, slen + 1);
6716    return;
6717   }
6718  __tfmt_units = val1;
6719  __tfmt_precunits = val2;
6720  __my_free((char *) __tfmt_suf, strlen(__tfmt_suf) + 1);
6721  __tfmt_suf = chp;
6722  __tfmt_minfwid = val3;
6723  return;
6724 
6725 bad_arg:
6726  __sgferr(713, "$timeformat argument %d value %s x/z or out of range",
6727   argi, __msgexpr_tostr(__xs, ndp));
6728 }
6729 
6730 /*
6731  * get an optional system task control argument
6732  * gets converted to machine int
6733  * this must be called with xp head of fcall list (comma operator)
6734  */
get_opt_starg(struct expr_t * xp,int32 dflt_val)6735 static int32 get_opt_starg(struct expr_t *xp, int32 dflt_val)
6736 {
6737  int32 val;
6738  word32 rval;
6739  struct expr_t *axp;
6740 
6741  if (xp == NULL) return(dflt_val);
6742  axp = xp->lu.x;
6743  if (axp->optyp == OPEMPTY) return(dflt_val);
6744 
6745  if (!__get_eval_word(axp, &rval))
6746   {
6747    __sgfwarn(519,
6748     "optional system task numeric argument has x/z bits - default used");
6749    return(dflt_val);
6750   }
6751  val = (int32) rval;
6752  return(val);
6753 }
6754 
6755 /*
6756  * evaluate a value to an int32 (return F if not a non x/z WBIT int32)
6757  * this must be called with actual argument expr. not fcall comma expr.
6758  */
__get_eval_word(struct expr_t * xp,word32 * wval)6759 extern int32 __get_eval_word(struct expr_t *xp, word32 *wval)
6760 {
6761  int32 rval;
6762  struct xstk_t *xsp;
6763 
6764  *wval = 0;
6765  xsp = __eval_xpr(xp);
6766  /* semantics says there is an implied conversion from real to int32 */
6767  /* but not across system task/func. arguments */
6768  /* however this routine is only called when int32 needed */
6769  if (xp->optyp == REALNUM || xp->optyp == ISREALNUM)
6770   {
6771    double d1;
6772 
6773    /* truncating since for getting 32 bit value */
6774    memcpy(&d1, xsp->ap, sizeof(double));
6775    *wval = (word32) d1;
6776    rval = TRUE;
6777    goto done;
6778   }
6779  if (xsp->xslen > WBITS)
6780   {
6781    if (!vval_is0_(&(xsp->ap[1]), xsp->xslen - WBITS)
6782     || !vval_is0_(&(xsp->bp[1]), xsp->xslen - WBITS))
6783     { rval = FALSE; goto done; }
6784   }
6785  if (xsp->bp[0] != 0L) { rval = FALSE; goto done; }
6786  *wval = xsp->ap[0];
6787  rval = TRUE;
6788 
6789 done:
6790  __pop_xstk();
6791  return(rval);
6792 }
6793 
6794 /*
6795  * exec the $log file system task
6796  * this is called with fcall comma operator header
6797  */
exec_log_fnamchg(struct expr_t * axp)6798 static void exec_log_fnamchg(struct expr_t *axp)
6799 {
6800  int32 slen;
6801  FILE *tmp_s;
6802  char *chp;
6803 
6804  if (axp == NULL) { __log_s = __save_log_s; return; }
6805  chp = __get_eval_cstr(axp->lu.x, &slen);
6806  if ((tmp_s = __tilde_fopen(chp, "w")) == NULL)
6807   {
6808    __sgferr(1243,
6809     "cannot open new $log output transcript file %s - not changed",
6810     __exprline);
6811    __my_free(chp, slen + 1);
6812    return;
6813   }
6814  if (__log_s != NULL && __log_s != stdout && __log_s != stderr)
6815   {
6816    __my_fclose(__log_s);
6817    __my_free(__log_fnam, strlen(__log_fnam) + 1);
6818    __log_fnam = NULL;
6819   }
6820  __log_fnam = chp;
6821  __log_s = tmp_s;
6822  __save_log_s = NULL;
6823  /* SJM 03/26/00 - log file now not an mcd - lumped with 0 (stdout) */
6824  /* ---
6825  __mulchan_tab[2].mc_fnam = __pv_stralloc(__log_fnam);
6826  __mulchan_tab[2].mc_fnam = __pv_stralloc(__log_fnam);
6827  --- */
6828  if (__verbose)
6829   __cv_msg("  Now writing output log to file \"%s\".\n", __log_fnam);
6830 }
6831 
6832 /*
6833  * exec the $tracefile system task
6834  * always open - if no writing into then just empty file
6835  *
6836  * will not get here if name argument missing
6837  * this is called with actual file name argument not fcall list header op
6838  *
6839  */
exec_trace_fnamchg(struct expr_t * argvx)6840 static void exec_trace_fnamchg(struct expr_t *argvx)
6841 {
6842  int32 slen;
6843  FILE *tmp_s;
6844  char *chp;
6845 
6846  chp = __get_eval_cstr(argvx, &slen);
6847  if (strcmp(chp, "STDOUT") == 0) strcpy(chp, "stdout");
6848  if (strcmp(__tr_fnam, chp) == 0)
6849   {
6850    __sgfwarn(625, "$tracefile file name %s same as previous - task ignored",
6851     __tr_fnam);
6852    goto done;
6853   }
6854  /* if changing to stdout set it, but cannot open */
6855  if (strcmp(chp, "stdout") == 0)
6856   {
6857    if (__tr_s != NULL && __tr_s != stdout && __tr_s != stderr)
6858     __my_fclose(__tr_s);
6859 
6860    if (__tr_fnam != NULL) __my_free(__tr_fnam, strlen(__tr_fnam) + 1);
6861    __tr_fnam = chp;
6862    __tr_s = stdout;
6863    goto new_tr;
6864   }
6865  /* know new file not stdout - always open system task new trace file */
6866  if ((tmp_s = __tilde_fopen(chp, "w")) == NULL)
6867   {
6868    __sgferr(1247, "cannot open new trace output file %s - not changed",
6869     chp);
6870    goto done;
6871   }
6872  if (__tr_s != NULL && __tr_s != stdout && __tr_s != stderr)
6873   __my_fclose(__tr_s);
6874 
6875  if (__tr_fnam != NULL) __my_free(__tr_fnam, strlen(__tr_fnam) + 1);
6876  __tr_fnam = chp;
6877  __tr_s = tmp_s;
6878 
6879 new_tr:
6880  if (__verbose)
6881   {
6882    __cv_msg(
6883    "  Now writing statement and/or event trace output to file \"%s\".\n",
6884    __tr_fnam);
6885   }
6886  return;
6887 
6888 done:
6889  __my_free(chp, slen + 1);
6890 }
6891 
6892 /*
6893  * execute a $scope change
6894  * this can be used for scope changes into local task from instance
6895  */
exec_expr_schg(struct expr_t * xp)6896 static void exec_expr_schg(struct expr_t *xp)
6897 {
6898  struct itree_t *itp;
6899  struct task_t *tskp;
6900  struct sy_t *syp;
6901 
6902  /* will not get here if no argument */
6903 
6904  /* need to handle scope change into local task - inst. does not change */
6905  /* scope changes of local [lb].[lb].[lb] simple task target by here */
6906  if (xp->optyp == ID)
6907   {
6908    syp = xp->lu.sy;
6909    /* DBG remove */
6910    if (syp->sytyp != SYM_TSK && syp->sytyp != SYM_F && syp->sytyp != SYM_LB)
6911     __arg_terr(__FILE__, __LINE__);
6912    /* --- */
6913    __scope_tskp = xp->lu.sy->el.etskp;
6914    if (__iact_state) __set_scopchg_listline();
6915    return;
6916   }
6917 
6918  /* DBG remove --- */
6919  if (xp->optyp != GLBREF) __arg_terr(__FILE__, __LINE__);
6920  /* --- */
6921 
6922  /* this converts from gref to itree location */
6923  __xmrpush_refgrp_to_targ(xp->ru.grp);
6924  itp = __inst_ptr;
6925  __pop_itstk();
6926  if (xp->lu.sy->sytyp != SYM_I && xp->lu.sy->sytyp != SYM_M)
6927   tskp = xp->lu.sy->el.etskp;
6928  else tskp = NULL;
6929  __scope_ptr = itp;
6930  __scope_tskp = tskp;
6931  /* if called from interactive must update list line to scope */
6932  if (__iact_state)
6933   {
6934    /* in iact, need top of inst. stack to be same as scope ptr */
6935    __pop_itstk();
6936    __push_itstk(__scope_ptr);
6937    __set_scopchg_listline();
6938 
6939    if (__tfrec_hdr != NULL) __call_misctfs_scope();
6940    if (__have_vpi_actions) __vpi_iactscopechg_trycall();
6941   }
6942 }
6943 
6944 /*
6945  * emit various systask time end message - task passed >= 2 arg
6946  */
__emit_stsk_endmsg(void)6947 extern void __emit_stsk_endmsg(void)
6948 {
6949  /* notice must know current end time */
6950  __my_ftime(&__end_time, &__end_mstime);
6951  __prt_end_msg();
6952 }
6953 
6954 /*
6955  * ROUTINES TO MAKE VARIABLE DECLARATION INITIALIZE ASSIGNMENTS
6956  */
6957 
6958 /*
6959  * after init sim and any -i interactive running, set all var decl initials
6960  *
6961  * semantics is same as: reg [r1:r2] x; initial x = [expr];
6962  */
__exec_var_decl_init_assigns(void)6963 extern void __exec_var_decl_init_assigns(void)
6964 {
6965  register struct varinitlst_t *initp;
6966  register struct net_t *np;
6967  register struct expr_t *xp;
6968  struct xstk_t *xsp;
6969  struct mod_t *mdp;
6970  int32 ii;
6971 
6972  for (mdp = __modhdr; mdp != NULL; mdp = mdp->mnxt)
6973   {
6974    if (mdp->mvarinits == NULL) continue;
6975 
6976    for (ii = 0; ii < mdp->flatinum; ii++)
6977     {
6978      __push_itstk(mdp->moditps[ii]);
6979 
6980      for (initp = mdp->mvarinits; initp != NULL; initp = initp->varinitnxt)
6981       {
6982        xp = initp->init_xp;
6983        np = initp->init_syp->el.enp;
6984        /* notice this code is almost same as eval assign rhsexpr except */
6985        /* do not have lhs expr but instead have net */
6986        xsp = __eval_xpr(initp->init_xp);
6987        if (np->ntyp == N_REAL)
6988         {
6989          if (!xp->is_real) __cnv_stk_fromreg_toreal(xsp, (xp->has_sign == 1));
6990         }
6991        else
6992         {
6993          if (xp->is_real) __cnv_stk_fromreal_toreg32(xsp);
6994 
6995          if (xsp->xslen > np->nwid) __narrow_sizchg(xsp, np->nwid);
6996          else if (xsp->xslen < np->nwid)
6997           {
6998            if (xp->has_sign) __sgn_xtnd_widen(xsp, np->nwid);
6999            else __sizchg_widen(xsp, np->nwid);
7000           }
7001         }
7002 
7003        /* notice may need change store here - works because netchg list hd */
7004        /* initialized in init stim so at end of first time 0 queue segment */
7005        /* the changes will be processed */
7006        if (np->nchg_nd_chgstore) __chg_st_val(np, xsp->ap, xsp->bp);
7007        else __st_val(np, xsp->ap, xsp->bp);
7008        __pop_xstk();
7009       }
7010      __pop_itstk();
7011     }
7012   }
7013 }
7014 
7015 /*
7016  * ROUTINES TO IMPLEMENT FILE IO SYS TASKS AND FUNCS (INTERMIXED)
7017  */
7018 
7019 /*
7020  * open a OS file system and return the 32 bit file descriptor
7021  * fd is OS file descriptor although using buffered read/write I/O
7022  */
fio_do_fopen(struct expr_t * axp,struct expr_t * mode_xp)7023 static word32 fio_do_fopen(struct expr_t *axp, struct expr_t *mode_xp)
7024 {
7025  int32 slen, slen2;
7026  word32 rv;
7027  char *chp, *chp2;
7028 
7029  /* these always return something as a string - can never fail */
7030  chp = __get_eval_cstr(axp, &slen);
7031  chp2 = __get_eval_cstr(mode_xp, &slen2);
7032  rv = fio_fopen(chp, chp2);
7033 
7034  /* get eval cstr puts string into malloc memory, must free */
7035  __my_free(chp, slen + 1);
7036  __my_free(chp2, slen2 + 1);
7037  return(rv);
7038 }
7039 
7040 /*
7041  * file descriptor fopen and update fio used file table
7042  * returns 0 on error else file Verilog fd number (with high bit on)
7043  *
7044  * notice the verilog file I/O number may not match the OS one
7045  */
fio_fopen(char * chp,char * fmode)7046 static word32 fio_fopen(char *chp, char *fmode)
7047 {
7048  int32 fd;
7049  FILE *fd_s;
7050  struct fiofd_t *fdtp;
7051  char os_mode[RECLEN];
7052 
7053  /* check the fmode string */
7054  if (!chk_cnvt_fd_modes(os_mode, fmode)) { errno = EINVAL; return(0); }
7055 
7056  /* notice if too many open files (use PLI plus Verilog fd open) this fails */
7057  if ((fd_s = __tilde_fopen(chp, os_mode)) == NULL)
7058   {
7059    /* notice errno set by OS file open call */
7060    return(0);
7061   }
7062  fd = fileno(fd_s);
7063  /* SJM 09/08/03 - ??? can file name be "stdin" here - think not */
7064  if (fd == -1 || fd < FIO_STREAM_ST) { errno = EBADF; return(0); }
7065 
7066  /* SJM 08/09/03 - change so always uses OS file number as index */
7067  /* internal error if same returned twice for open file */
7068  if (__fio_fdtab[fd] != NULL)
7069   {
7070    /* not quite right since error really fd number in use */
7071    errno = EEXIST;
7072    __misc_terr(__FILE__, __LINE__);
7073    return(0);
7074   }
7075 
7076  /* notice index with high bit on is the Verilog side file descriptor no. */
7077  fdtp = (struct fiofd_t *) __my_malloc(sizeof(struct fiofd_t));
7078  fdtp->fd_error = FALSE;
7079  fdtp->fd_name = __pv_stralloc(chp);
7080  /* notice can always get fd from stream using fileno C lib func */
7081  fdtp->fd_s = fd_s;
7082  __fio_fdtab[fd] = fdtp;
7083 
7084  return(fd | FIO_MSB);
7085 }
7086 
7087 /*
7088  * check and convert the file modes (types for file descriptions) strings
7089  * returns F on fail else T
7090  *
7091  * ending 'b' allowed but never used for unix
7092  * SJM 09/08/03 - must fix for other OSes
7093  */
chk_cnvt_fd_modes(char * os_mode,char * ver_mode)7094 static int32 chk_cnvt_fd_modes(char *os_mode, char *ver_mode)
7095 {
7096  /* assume ver mode string and OS mode string same */
7097  strcpy(os_mode, ver_mode);
7098 
7099  if (strcmp(ver_mode, "r") == 0) return(TRUE);
7100  if (strcmp(ver_mode, "rb") == 0) { strcpy(os_mode, "r"); return(TRUE); }
7101  if (strcmp(ver_mode, "w") == 0) return(TRUE);
7102  if (strcmp(ver_mode, "wb") == 0) { strcpy(os_mode, "w"); return(TRUE); }
7103  if (strcmp(ver_mode, "a") == 0) return(TRUE);
7104  if (strcmp(ver_mode, "ab") == 0) { strcpy(os_mode, "a"); return(TRUE); }
7105  if (strcmp(ver_mode, "r+") == 0) return(TRUE);
7106  if (strcmp(ver_mode, "r+b") == 0) { strcpy(os_mode, "r+"); return(TRUE); }
7107  if (strcmp(ver_mode, "rb+") == 0) { strcpy(os_mode, "r+"); return(TRUE); }
7108  if (strcmp(ver_mode, "w+") == 0) return(TRUE);
7109  if (strcmp(ver_mode, "w+b") == 0) { strcpy(os_mode, "w+"); return(TRUE); }
7110  if (strcmp(ver_mode, "wb+") == 0) { strcpy(os_mode, "w+"); return(TRUE); }
7111  if (strcmp(ver_mode, "a+") == 0) return(TRUE);
7112  if (strcmp(ver_mode, "a+b") == 0) { strcpy(os_mode, "a+"); return(TRUE); }
7113  if (strcmp(ver_mode, "ab+") == 0) { strcpy(os_mode, "a+"); return(TRUE); }
7114  return(FALSE);
7115 }
7116 
7117 /*
7118  * close either an mcd (all files - bits) or one file if fd passed
7119  * this is sys task so just sets errno on error - no error return
7120  *
7121  * SJM 09/08/03 - FIXME ??? need to cancel pending f monits and strobes
7122  */
fio_do_fclose(struct expr_t * axp)7123 static void fio_do_fclose(struct expr_t *axp)
7124 {
7125  int32 fd, is_mcd;
7126 
7127  /* this sets error nunber */
7128  if ((fd = chk_get_mcd_or_fd(axp->lu.x, &is_mcd)) == -1) return;
7129 
7130  /* case close mcd */
7131  if (is_mcd)
7132   {
7133    /* just have this re-eval mcd */
7134    mcd_do_fclose(axp);
7135    return;
7136   }
7137 
7138  /* notice $fclose does not return anything but vpi mcd fclose with fd does */
7139  __fd_do_fclose(fd);
7140 }
7141 
7142 /*
7143  * close a file descriptor and return 0 on success and 1 on error
7144  */
__fd_do_fclose(int32 fd)7145 extern int32 __fd_do_fclose(int32 fd)
7146 {
7147  int32 slen;
7148  FILE *f;
7149 
7150  /* know fd in range but if not open error */
7151  if (__fio_fdtab[fd] == NULL)
7152   {
7153    errno = EBADF;
7154    /* SJM 09/23/03 - STRANGE but LRM says return open mcd numbers even here */
7155    return(bld_open_mcd());
7156   }
7157 
7158  /* must save fd stream before freeing */
7159  f = __fio_fdtab[fd]->fd_s;
7160  slen = strlen(__fio_fdtab[fd]->fd_name);
7161  __my_free(__fio_fdtab[fd]->fd_name, slen + 1);
7162  __my_free((char *) __fio_fdtab[fd], sizeof(struct fiofd_t));
7163  __fio_fdtab[fd] = NULL;
7164  __my_fclose(f);
7165 
7166  return(0);
7167 }
7168 
7169 /*
7170  * check and then convert mcd or fd expressions to int
7171  * returns -1 on error else mcd or fd number (with high bit off)
7172  * sets is_mcd arg to 1 if mcd to 0 for Unix fd
7173  *
7174  * there is implied truncation to 32 bits so if wider with x's ok
7175  */
chk_get_mcd_or_fd(struct expr_t * fdxp,int32 * is_mcd)7176 static int32 chk_get_mcd_or_fd(struct expr_t *fdxp, int32 *is_mcd)
7177 {
7178  word32 fd;
7179  struct xstk_t *xsp;
7180 
7181  /* assume new file descriptor passed */
7182  *is_mcd = FALSE;
7183  xsp = __eval_xpr(fdxp);
7184  if (xsp->bp[0] != 0L) { errno = EBADF; __pop_xstk(); return(-1); }
7185 
7186  fd = xsp->ap[0];
7187  __pop_xstk();
7188 
7189  /* if high bit 0, then know mcd */
7190  /* SJM 09/30/06 - using wrong mask - need only high bit on for test */
7191  /* was using fio fd wrongly */
7192  if ((fd & FIO_MSB) == 0)
7193   {
7194    *is_mcd = TRUE;
7195    return(fd);
7196   }
7197  /* turn off high bit for file descriptor */
7198  fd &= ~(FIO_FD);
7199  if (fd >= FOPEN_MAX) { errno = EBADF; return(-1); }
7200  if (__fio_fdtab[fd] == NULL) { errno = EBADF; return(-1); }
7201  return(fd);
7202 }
7203 
7204 /*
7205  * flush either an mcd (all bits on) or one fd file
7206  */
fio_fflush(struct expr_t * axp)7207 static void fio_fflush(struct expr_t *axp)
7208 {
7209  register int32 i;
7210  int32 fd, is_mcd;
7211  word32 mcd;
7212 
7213  /* this sets error nunber */
7214  if ((fd = chk_get_mcd_or_fd(axp, &is_mcd)) == -1) return;
7215 
7216  /* case close mcd */
7217  if (is_mcd)
7218   {
7219    mcd = (word32) fd;
7220    /* SJM 09/09/03 - bit 31 now not used for mcds */
7221    for (i = 1; i < 30; i++)
7222     {
7223      if (((mcd >> i) & 1L) != 0L)
7224       {
7225        if (__mulchan_tab[i].mc_s == NULL)
7226         {
7227          __sgfinform(583,
7228           "multi-channel descriptor bit %d on, but file not open",  i);
7229         }
7230        else fflush(__mulchan_tab[i].mc_s);
7231       }
7232     }
7233    return;
7234   }
7235 
7236  /* know fd in range but if not open error */
7237  if (__fio_fdtab[fd] == NULL) { errno = EBADF; return; }
7238  fflush(__fio_fdtab[fd]->fd_s);
7239 }
7240 
7241 /*
7242  * get a character from stream with verilog file descripter expr fdxp
7243  *
7244  * SJM 08/09/03 - using literal -1 but maybe should be using EOF define?
7245  * SJM 08/09/03 - LOOKATME - assuming OS will catch seeking on std[in,out,err]
7246  * files
7247  */
fio_ungetc(struct expr_t * chxp,struct expr_t * fdxp)7248 static int32 fio_ungetc(struct expr_t *chxp, struct expr_t *fdxp)
7249 {
7250  int32 c, fd, ival;
7251  struct xstk_t *xsp;
7252 
7253  /* implied assign to 8 bits - if b part non zero implied assign to 32 bits */
7254  xsp = __eval_xpr(chxp);
7255  if (xsp->bp[0] != 0) { errno = EINVAL; __pop_xstk(); return(-1); }
7256  /* this insures good char */
7257  c = (int32) (xsp->ap[0] & 0xff);
7258  __pop_xstk();
7259 
7260  /* fd is OS file number with high bit anded off */
7261  if ((fd = chk_get_ver_fd(fdxp)) == -1) return(-1);
7262 
7263  /* returns c if success else -1 */
7264  ival = ungetc(c, __fio_fdtab[fd]->fd_s);
7265  return(ival);
7266 }
7267 
7268 /*
7269  * check and then convert fd expressions to int
7270  * return -1 on error else fd number with high bit off (know positive or 0)
7271  *
7272  * there is implied truncation to 32 bits so if wider with x's ok
7273  */
chk_get_ver_fd(struct expr_t * fdxp)7274 static int32 chk_get_ver_fd(struct expr_t *fdxp)
7275 {
7276  int32 fd;
7277  struct xstk_t *xsp;
7278 
7279  xsp = __eval_xpr(fdxp);
7280  if (xsp->bp[0] != 0L) { errno = EBADF; __pop_xstk(); return(-1); }
7281 
7282  fd = xsp->ap[0] & FIO_FD;
7283  __pop_xstk();
7284  if (fd >= FOPEN_MAX) { errno = EBADF; return(-1); }
7285  /* AIV 06/27/05 - fd cannot be greater than max file size */
7286  if (fd >= MY_FOPEN_MAX || __fio_fdtab[fd] == NULL)
7287   { errno = EBADF; return(-1); }
7288  return(fd);
7289 }
7290 
7291 /*
7292  * get a string from stream with verilog file descripter expr fdxp
7293  *
7294  * SJM 09/08/03 - assuming following C lib fgets new line included in string
7295  */
fio_fgets(struct expr_t * str_xp,struct expr_t * fdxp)7296 static int32 fio_fgets(struct expr_t *str_xp, struct expr_t *fdxp)
7297 {
7298  int32 fd, slen, chlen;
7299  struct xstk_t *xsp;
7300  char *lp;
7301 
7302  /* result string can't be empty "(, fd)" */
7303  if (str_xp->optyp == OPEMPTY) { errno = EINVAL; return(0); }
7304 
7305  /* fd is OS file number with high bit anded off - on error OS err num set */
7306  if ((fd = chk_get_ver_fd(fdxp)) == -1) return(0);
7307 
7308  /* len rounds down if not div by 8 following LRM */
7309  slen = str_xp->szu.xclen/8;
7310  lp = __my_malloc(slen + 1);
7311  /* fgets returns ptr to lp or nil not number of read chars */
7312  if (fgets(lp, slen, __fio_fdtab[fd]->fd_s) == NULL)
7313   {
7314    __my_free(lp, slen + 1);
7315    return(0);
7316   }
7317 
7318  /* SJM 10/20/03 - think fgets should return nil if at eof but check */
7319  /* DBG remove -- */
7320  if (*lp == '\0') __misc_terr(__FILE__, __LINE__);
7321  /* --- */
7322 
7323  chlen = strlen(lp);
7324 
7325  xsp = __cstr_to_vval(lp);
7326  /* now done with read c string must free */
7327  __my_free(lp, slen + 1);
7328 
7329  /* following verilog convention if not enough chars (EOF) zero fill */
7330 
7331  /* 05/16/04 - Verilog strings can't be signed */
7332  if (xsp->xslen != str_xp->szu.xclen) __sizchgxs(xsp, str_xp->szu.xclen);
7333 
7334  __exec2_proc_assign(str_xp, xsp->ap, xsp->bp);
7335  __pop_xstk();
7336  /* notice num chars read my be differ than len of lhs assign to reg */
7337  return(chlen);
7338 }
7339 
7340 /*
7341  * rewind within an OS stream - returns -1 on error 0 on success
7342  *
7343  * equivalent to C lib fseek(FILE *, 0, SEEK_SET)
7344  */
fio_rewind(struct expr_t * fdxp)7345 static int32 fio_rewind(struct expr_t *fdxp)
7346 {
7347  int32 fd;
7348 
7349  /* fd is OS file number with high bit anded off - on error OS err num set */
7350  if ((fd = chk_get_ver_fd(fdxp)) == -1) return(-1);
7351 
7352  fseek(__fio_fdtab[fd]->fd_s, 0L, SEEK_SET);
7353  /* returns 0 on success */
7354  return(0);
7355 }
7356 
7357 /*
7358  * seek within an OS stream - returns -1 on error and 0 on success
7359  */
fio_fseek(struct expr_t * fdxp,struct expr_t * ofs_xp,struct expr_t * whence_xp)7360 static int32 fio_fseek(struct expr_t *fdxp, struct expr_t *ofs_xp,
7361  struct expr_t *whence_xp)
7362 {
7363  int32 fd, offset, whence, seek_typ;
7364  struct xstk_t *xsp;
7365 
7366  /* fd is OS file number with high bit anded off - on error OS err num set */
7367  if ((fd = chk_get_ver_fd(fdxp)) == -1) return(-1);
7368 
7369  /* there is an implied convert to 32 bits here */
7370  xsp = __eval_xpr(ofs_xp);
7371  if (xsp->bp[0] != 0) { errno = EINVAL; __pop_xstk(); return(-1); }
7372  /* offset can be negative */
7373  offset = (int32) xsp->ap[0];
7374  __pop_xstk();
7375 
7376  /* there is an implied convert to 32 bits here */
7377  xsp = __eval_xpr(whence_xp);
7378  if (xsp->bp[0] != 0) { errno = EINVAL; __pop_xstk(); return(-1); }
7379  /* only 3 possibilities */
7380  whence = (int32) xsp->ap[0];
7381  __pop_xstk();
7382  /* check for legal whence seek type */
7383  if (whence == 0) seek_typ = SEEK_SET;
7384  else if (whence == 1) seek_typ = SEEK_CUR;
7385  else if (whence == 2) seek_typ = SEEK_END;
7386  else { errno = EINVAL; return(-1); }
7387 
7388  if (__fio_fdtab[fd] == NULL) { errno = EBADF; return(-1); }
7389  fseek(__fio_fdtab[fd]->fd_s, (long) offset, seek_typ);
7390  /* returns 0 on success */
7391  return(0);
7392 }
7393 
7394 /*
7395  * get error status - verilog equivalent of strerror function
7396  * return 0 on no error else set error number and copies err str to str xp
7397  *
7398  * if user passes string narrower than 80 chars, silently truncates err str
7399  * notice if this has error it overwrites the pending errno error
7400  *
7401  * SJM 08/09/03 - although LRM does not say it, returns -1 on error here
7402  */
fio_ferror(struct expr_t * fdxp,struct expr_t * str_xp)7403 static int32 fio_ferror(struct expr_t *fdxp, struct expr_t *str_xp)
7404 {
7405  int32 fd, rv, stream_err;
7406  char *cp;
7407  struct xstk_t *xsp;
7408 
7409  /* result string can't be empty "(, fd)" */
7410  if (str_xp->optyp == OPEMPTY) { errno = EINVAL; return(-1); }
7411 
7412  /* fd is OS file number with high bit anded off - on error OS err num set */
7413  /* notice if fails can change error number */
7414  if ((fd = chk_get_ver_fd(fdxp)) == -1) return(-1);
7415 
7416  if ((stream_err = ferror(__fio_fdtab[fd]->fd_s)) == 0)
7417   {
7418    rv = 0;
7419 err_ret:
7420    push_xstk_(xsp, str_xp->szu.xclen);
7421    zero_allbits_(xsp->ap, xsp->xslen);
7422    zero_allbits_(xsp->bp, xsp->xslen);
7423    __exec2_proc_assign(str_xp, xsp->ap, xsp->bp);
7424    __pop_xstk();
7425    return(rv);
7426   }
7427 
7428  /* use the reentrant posix form of str error function */
7429  /* SJM 01/26/05 - no reason for reentrant version strerr here */
7430  if ((cp = strerror(stream_err)) == NULL) { rv = -1; goto err_ret; }
7431 
7432  /* know buf ends with '\0' */
7433  xsp = __cstr_to_vval(cp);
7434  /* 05/16/04 - Verilog strings can't be signed */
7435  if (xsp->xslen != str_xp->szu.xclen) __sizchgxs(xsp, str_xp->szu.xclen);
7436 
7437  __exec2_proc_assign(str_xp, xsp->ap, xsp->bp);
7438  __pop_xstk();
7439  return(errno);
7440 }
7441 
7442 /*
7443  * fread data into reg or memory - only 0 or 1 can be read
7444  * on error 0 else number of 8 bit chars read
7445  *
7446  * SJM 09/20/03 - LRM wrong for memories fread can't read addresses
7447  */
fio_fread(struct expr_t * ndp)7448 static int32 fio_fread(struct expr_t *ndp)
7449 {
7450  int32 fd, vlen, nbytes, bufi;
7451  byte *buf;
7452  struct expr_t *lhsx, *fdxp, *startxp, *cntxp;
7453  struct net_t *np;
7454  struct xstk_t *xsp;
7455 
7456  lhsx = ndp->lu.x;
7457  /* result string can't be empty "(, fd)" */
7458  if (lhsx->optyp == OPEMPTY) { errno = EINVAL; return(-1); }
7459 
7460  fdxp = ndp->ru.x->lu.x;
7461  /* fd is OS file number with high bit anded off - on error OS err num set */
7462  if ((fd = chk_get_ver_fd(fdxp)) == -1) return(0);
7463 
7464  startxp = cntxp = NULL;
7465  if (lhsx->optyp == ID || lhsx->optyp == GLBREF)
7466   {
7467    /* for array element, won't be ID */
7468    np = lhsx->lu.sy->el.enp;
7469    if (np->n_isarr)
7470     {
7471      if ((ndp = ndp->ru.x->ru.x) != NULL)
7472       {
7473        startxp = ndp->lu.x;
7474        if ((ndp = ndp->ru.x) != NULL) cntxp = ndp->lu.x;
7475       }
7476      return(fio_arr_fread(lhsx, fd, startxp, cntxp));
7477     }
7478   }
7479 
7480  /* case 1: read into reg - start and end args ignored if present */
7481  /* len rounds down if not div by 8 following LRM */
7482  /* SJM 09/20/03 LRM says round down but that doesn't make sense */
7483  /* so round up following PLI implementation */
7484  vlen = (lhsx->szu.xclen + 7)/8;
7485 
7486  /* must store into stack value and then assign */
7487  buf = (byte *) __my_malloc(vlen);
7488 
7489  nbytes = fread(buf, 1, vlen, __fio_fdtab[fd]->fd_s);
7490  /* if unable to read entire reg, return error and do not assign */
7491  /* if part read and EOF, correct for reg to not be changed */
7492  if (nbytes != vlen)
7493   {
7494    __my_free((char *) buf, vlen);
7495    /* for short last section, reg not assigned and bytes in stream read */
7496    /* returned - user must call ferror or feof system task to find error */
7497    /* to mimic stdio lib beheavior - if error will probably be 0 */
7498    return(nbytes);
7499   }
7500 
7501  push_xstk_(xsp, lhsx->szu.xclen);
7502  /* 0 value so only need to turn 1 bits on */
7503  zero_allbits_(xsp->ap, lhsx->szu.xclen);
7504  zero_allbits_(xsp->bp, lhsx->szu.xclen);
7505  bufi = vlen - 1;
7506 
7507  fread_onto_stk(xsp, buf, bufi);
7508 
7509  __my_free((char *) buf, vlen);
7510  /* know xsp width exactly match lhs expr width */
7511  __exec2_proc_assign(lhsx, xsp->ap, xsp->bp);
7512  __pop_xstk();
7513  return(0);
7514 }
7515 
7516 /*
7517  * read one reg (also used for cell of array)
7518  * can't fail
7519  *
7520  * know correct width location pushed onto x stack that is filled
7521  * also know that f read buf value big enough and bufi starts at high end byte
7522  */
fread_onto_stk(struct xstk_t * xsp,byte * buf,int32 bufi)7523 static void fread_onto_stk(struct xstk_t *xsp, byte *buf, int32 bufi)
7524 {
7525  register int32 bi;
7526  int32 hbused, hbi, wi, bi2;
7527  word32 bitval, bval;
7528 
7529  /* know have char 0/1 value for every bit */
7530  /* handle partially filled high byte as special case */
7531  hbused = xsp->xslen % 8;
7532  bi = xsp->xslen - 1;
7533  if (hbused != 0)
7534   {
7535    bval = (word32) buf[0];
7536    for (hbi = hbused - 1; hbi >= 0; hbi--, bi--)
7537     {
7538      wi = get_wofs_(bi);
7539      bi2 = get_bofs_(bi);
7540      bitval = ((bval >> hbi) & 1) << bi2;
7541      if (bitval != 0) xsp->ap[wi] |= bitval;
7542     }
7543    bufi--;
7544   }
7545  /* handle simple all bits in all fread bytes used */
7546  /* bi correct next high bit to set from read byte */
7547  for (; bufi >= 0; bufi--)
7548   {
7549    bval = (word32) buf[bufi];
7550    for (hbi = 7; hbi >= 0; hbi--, bi--)
7551     {
7552      /* DBG remove -- */
7553      if (bi < 0) __misc_terr(__FILE__, __LINE__);
7554      /* --- */
7555      wi = get_wofs_(bi);
7556      bi2 = get_bofs_(bi);
7557      bitval = ((buf[bufi] >> hbi) & 1) << bi2;
7558      if (bitval != 0) xsp->ap[wi] |= bitval;
7559     }
7560   }
7561 }
7562 
7563 /*
7564  * fread into array (memory)
7565  *
7566  * fread of memory differs from read mem because no addresses in file
7567  * and can only read non x/z values
7568  */
fio_arr_fread(struct expr_t * lhsx,int32 fd,struct expr_t * startxp,struct expr_t * cntxp)7569 static int32 fio_arr_fread(struct expr_t *lhsx, int32 fd,
7570  struct expr_t *startxp, struct expr_t *cntxp)
7571 {
7572  register int32 i, arri;
7573  int32 ri1, ri2, arrwid, starti, cnt, nbytes, tot_bytes, nd_itpop, vlen;
7574  byte *buf;
7575  struct net_t *np;
7576  struct xstk_t *xsp;
7577  struct gref_t *grp;
7578 
7579  np = lhsx->lu.sy->el.enp;
7580  __getarr_range(np, &ri1, &ri2, &arrwid);
7581 
7582  /* array elements stored h:0 normalized so index h to high */
7583  /* but loading is from low to high array words */
7584  starti = 0;
7585  cnt = arrwid - 1;
7586 
7587  /* ,,) form possible for start and count expressions */
7588  if (startxp != NULL)
7589   {
7590    if (startxp->optyp != OPEMPTY)
7591     {
7592      /* can't use comp ndx here because value is just normal expr */
7593      xsp = __eval_xpr(cntxp);
7594      if (!vval_is0_(xsp->bp, xsp->xslen) ||
7595       (xsp->xslen > WBITS && !vval_is0_(&(xsp->ap[1]), xsp->xslen - WBITS)))
7596       {
7597        __sgfwarn(588,
7598         "array $fread of %s start value has x/z bits or wide - low a part used",
7599         np->nsym->synam);
7600       }
7601      arri = (int32) xsp->ap[0];
7602      /* stsk arg. in Verilog source is actual index - must convert to h:0 */
7603      starti = normalize_ndx_(arri, ri1, ri2);
7604      __pop_xstk();
7605      if (starti < 0 || starti >= arrwid)
7606       {
7607        errno = EINVAL;
7608        return(0);
7609       }
7610     }
7611   }
7612  if (cntxp != NULL)
7613   {
7614    if (cntxp->optyp != OPEMPTY)
7615     {
7616      /* if count present but not start then use first addr in mem */
7617      xsp = __eval_xpr(cntxp);
7618      if (!vval_is0_(xsp->bp, xsp->xslen) ||
7619       (xsp->xslen > WBITS && !vval_is0_(&(xsp->ap[1]), xsp->xslen - WBITS)))
7620       {
7621        __sgfwarn(588,
7622         "array $fread of %s count value has x/z bits or wide - low a part used",
7623         np->nsym->synam);
7624       }
7625      cnt = (int32) xsp->ap[0];
7626      if (cnt < 0 || starti + cnt >= arrwid)
7627       {
7628        errno = EINVAL;
7629        return(0);
7630       }
7631     }
7632   }
7633 
7634  nd_itpop = FALSE;
7635  if (lhsx->optyp == GLBREF)
7636   { grp = lhsx->ru.grp; __xmrpush_refgrp_to_targ(grp); nd_itpop = TRUE; }
7637  push_xstk_(xsp, np->nwid);
7638 
7639  /* round up so 1 bit memory still requires 1 byte per cell */
7640  vlen = (arrwid + 7)/8;
7641  buf = (byte *) __my_malloc(vlen);
7642  tot_bytes = 0;
7643  for (arri = starti, i = 0; i < cnt; i++, arri++)
7644   {
7645    nbytes = fread(buf, 1, vlen, __fio_fdtab[fd]->fd_s);
7646    tot_bytes += nbytes;
7647    /* if unable to read entire reg, return error and do not assign */
7648    /* if part read and EOF, correct for reg to not be changed */
7649    if (nbytes != vlen) goto done;
7650 
7651    /* 0 value so only need to turn 1 bits on */
7652    zero_allbits_(xsp->ap, lhsx->szu.xclen);
7653    zero_allbits_(xsp->bp, lhsx->szu.xclen);
7654 
7655    fread_onto_stk(xsp, buf, vlen - 1);
7656 
7657    /* SJM 03/15/01 - change to fields in net record */
7658    if (np->nchg_nd_chgstore)
7659     {
7660      __chg_st_arr_val(np->nva, arrwid, np->nwid, arri, xsp->ap, xsp->bp);
7661 
7662      /* SJM - 06/25/00 - lhs changed possible from change store */
7663      /* and must only trigger change for right array index */
7664      if (__lhs_changed) record_sel_nchg_(np, arri, arri);
7665     }
7666    else __st_arr_val(np->nva, arrwid, np->nwid, arri, xsp->ap, xsp->bp);
7667   }
7668 done:
7669  __my_free((char *) buf, vlen);
7670  __pop_xstk();
7671  if (nd_itpop) __pop_itstk();
7672  return(tot_bytes);
7673 }
7674 
7675 /*
7676  * implement the swrite to string (instead of file) Verilog formatted
7677  * print sys tasks
7678  *
7679  * easy since because of mcds formatting always goes into c string
7680  * using the _expr line and cur sofs mechanism
7681  */
fio_swrite(struct expr_t * axp,int32 dflt_fmt)7682 static void fio_swrite(struct expr_t *axp, int32 dflt_fmt)
7683 {
7684  struct expr_t *str_xp;
7685  struct xstk_t *xsp;
7686 
7687  str_xp = axp->lu.x;
7688  axp = axp->ru.x;
7689  __str_do_disp(axp, dflt_fmt);
7690  xsp = __cstr_to_vval(__exprline);
7691 
7692  /* now done with expr line */
7693  __cur_sofs = 0;
7694 
7695  /* do the assign to string after formatting into __expr line */
7696  /* following verilog convention if not enough chars (EOF) zero fill */
7697 
7698  /* 05/16/04 - Verilog strings can't be signed */
7699  if (xsp->xslen != str_xp->szu.xclen) __sizchgxs(xsp, str_xp->szu.xclen);
7700 
7701  __exec2_proc_assign(str_xp, xsp->ap, xsp->bp);
7702  __pop_xstk();
7703 }
7704 
7705 /*
7706  * implement $sformat version of $swrite that has only 1 format but can
7707  * be variable unlike $swrite
7708  *
7709  * first arg is string to write into, 2nd arg is format that can be
7710  * var so needs to be evaled - rest are the format args - error if
7711  * too few format args and ignores extra (unlike $swrite that prints
7712  * them with format)
7713  */
fio_sformat(struct expr_t * axp)7714 static void fio_sformat(struct expr_t *axp)
7715 {
7716  int32 blen, flen;
7717  struct expr_t *str_xp, *fmt_xp;
7718  struct xstk_t *xsp;
7719  char *fmtstr;
7720 
7721  /* lhs expr to store formatted string into */
7722  str_xp = axp->lu.x;
7723 
7724  /* evaluate the format into a Verilog string */
7725  axp = axp->ru.x;
7726  fmt_xp = axp->lu.x;
7727 
7728  xsp = __eval_xpr(fmt_xp);
7729  if (!vval_is0_(xsp->bp, xsp->xslen))
7730   {
7731    errno = EINVAL;
7732    return;
7733   }
7734 
7735  /* trim high 0's of a part only */
7736  blen = __trim1_0val(xsp->ap, xsp->xslen);
7737  if (blen == 0)
7738   {
7739    errno = EINVAL;
7740    return;
7741   }
7742 
7743  /* this mallocs the input string to scan from */
7744  fmtstr = __vval_to_vstr(xsp->ap, blen, &flen);
7745  __pop_xstk();
7746 
7747  /* assuming 8 bit bytes */
7748  axp = __disp_1fmt_to_exprline(fmtstr, axp);
7749  if (axp != NULL)
7750   {
7751    __sgfwarn(3133,
7752     "$sformat extra unused arguments after format exhausted");
7753   }
7754 
7755  __my_free(fmtstr, flen);
7756 
7757  xsp = __cstr_to_vval(__exprline);
7758  /* now done with expr line */
7759  __cur_sofs = 0;
7760 
7761  /* do the assign to string after formatting into __expr line */
7762  /* following verilog convention if not enough chars (EOF) zero fill */
7763 
7764  /* 05/16/04 - Verilog strings can't be signed */
7765  if (xsp->xslen != str_xp->szu.xclen) __sizchgxs(xsp, str_xp->szu.xclen);
7766 
7767  __exec2_proc_assign(str_xp, xsp->ap, xsp->bp);
7768  __pop_xstk();
7769 }
7770 
7771 /*
7772  * implement $fscanf for now using old scin_s scanf code
7773  */
fio_fscanf(struct expr_t * ndp)7774 static int32 fio_fscanf(struct expr_t *ndp)
7775 {
7776  int32 fd, blen, flen, rv;
7777  char *fmtstr;
7778  struct expr_t *fmt_xp;
7779  struct xstk_t *xsp;
7780 
7781  /* fd is OS file number with high bit anded off - on error OS err num set */
7782  /* notice if fails can change error number */
7783  if ((fd = chk_get_ver_fd(ndp->lu.x)) == -1) return(-1);
7784 
7785  /* know fd in range but if not open error */
7786  if (__fio_fdtab[fd] == NULL) { errno = EBADF; return(-1); }
7787 
7788  ndp = ndp->ru.x;
7789  fmt_xp = ndp->lu.x;
7790  xsp = __eval_xpr(fmt_xp);
7791  if (!vval_is0_(xsp->bp, xsp->xslen))
7792   {
7793    errno = EINVAL;
7794    return(-1);
7795   }
7796  /* trim high 0's of a part only */
7797  blen = __trim1_0val(xsp->ap, xsp->xslen);
7798  if (blen == 0)
7799   {
7800    errno = EINVAL;
7801    return(-1);
7802   }
7803  fmtstr = __vval_to_vstr(xsp->ap, blen, &flen);
7804  __fiofp = fmtstr;
7805 
7806  /* ndp now ptr to comma operator of first arg past fmt */
7807  ndp = ndp->ru.x;
7808  rv = fio_exec_scanf(__fio_fdtab[fd]->fd_s, ndp);
7809  __my_free(fmtstr, flen);
7810  __pop_xstk();
7811  return(rv);
7812 }
7813 
7814 /*
7815  * implement $sscanf for now using old scin_s scanf code
7816  */
fio_sscanf(struct expr_t * ndp)7817 static int32 fio_sscanf(struct expr_t *ndp)
7818 {
7819  int32 blen, slen, flen, rv;
7820  char *instr, *fmtstr;
7821  struct expr_t *str_xp, *fmt_xp;
7822  struct xstk_t *xsp;
7823 
7824  /* first arg is string to read from */
7825  str_xp = ndp->lu.x;
7826  xsp = __eval_xpr(str_xp);
7827  if (!vval_is0_(xsp->bp, xsp->xslen))
7828   {
7829    errno = EINVAL;
7830    return(-1);
7831   }
7832  /* trim high 0's of a part only */
7833  blen = __trim1_0val(xsp->ap, xsp->xslen);
7834  if (blen == 0)
7835   {
7836    errno = EINVAL;
7837    return(-1);
7838   }
7839 
7840  /* this mallocs the input string to scan from */
7841  instr = __vval_to_vstr(xsp->ap, blen, &slen);
7842  /* implied global used for reading input char by char */
7843  __fiolp = instr;
7844  __pop_xstk();
7845 
7846  ndp = ndp->ru.x;
7847  fmt_xp = ndp->lu.x;
7848  xsp = __eval_xpr(fmt_xp);
7849  if (!vval_is0_(xsp->bp, xsp->xslen))
7850   {
7851    errno = EINVAL;
7852    return(-1);
7853   }
7854  /* trim high 0's of a part only */
7855  blen = __trim1_0val(xsp->ap, xsp->xslen);
7856  if (blen == 0)
7857   {
7858    errno = EINVAL;
7859    return(-1);
7860   }
7861 
7862  /* this mallocs the fmt string to scan from */
7863  /* notice for new routines (especially input), only one format string */
7864  fmtstr = __vval_to_vstr(xsp->ap, blen, &flen);
7865  __fiofp = fmtstr;
7866  __pop_xstk();
7867 
7868  /* AIV 09/29/03 - forgot to assign ndp to first arg past format */
7869  ndp = ndp->ru.x;
7870 
7871  rv = fio_exec_scanf(NULL, ndp);
7872  /* free the version in malloced storage */
7873  __my_free(instr, slen);
7874  __my_free(fmtstr, flen);
7875  return(rv);
7876 }
7877 
7878 /* SJM 09/24/03 - why need defines here? */
7879 /* SJM 09/24/03 - eliminated EOL since no significance of new line now */
7880 #define infmt() ((*__fiofp == '\0') ? EOF : *__fiofp++)
7881 
7882 /*
7883  * execute the scan input system task
7884  * returns number of successfully read items
7885  *
7886  * on entry axp points to arg list comma operator of first scan into arg
7887  * if f nil, gets char from global file io work char ptr else read char
7888  *
7889  * know globals __fiolp points to string (for sscanf) and __fiofp always
7890  * points to first char in format string on entry
7891  *
7892  * SJM 09/24/03 - seems that unlike c lib no \ escaping of % allowed - true?
7893  * now must check format syntax correctness here because format can be var
7894  */
fio_exec_scanf(FILE * f,struct expr_t * axp)7895 static int32 fio_exec_scanf(FILE *f, struct expr_t *axp)
7896 {
7897  register char *wchp;
7898  register int32 c, fch, width;
7899  int32 len, num_matched, base, signc, ival;
7900  int32 retval, assgn_sup, stval, sav_sofs, lmatch;
7901  double d1;
7902  struct expr_t *lhsx;
7903  struct xstk_t *xsp;
7904  struct task_t *tskp;
7905 
7906  /* if F, illegal format so return EOF */
7907  if (!chk_scanf_fmt(__fiofp))
7908   {
7909    errno = EINVAL;
7910    return(-1);
7911   }
7912 
7913  /* start by readin first input char - may push back */
7914  /* axp always points to comma operator of next arg (maybe nil) */
7915  retval = -1;
7916 
7917  /* if EOF on input file before any matches return EOF */
7918  if ((c = scanf_getc(f)) == EOF) return(-1);
7919  for (lmatch = num_matched = 0;;)
7920   {
7921    if (f != NULL && lmatch != num_matched)
7922     {
7923      if ((__scanf_pos = ftell(f)) == -1) return(-1);
7924     }
7925    lmatch = num_matched;
7926 
7927    /* at beginning of loop c is next input line char to process */
7928    /* but fch is last processed format char */
7929    if ((fch = infmt()) == EOF) break;
7930    if (fch != '%')
7931     {
7932      /* fmt white space matches optional any width input line white space */
7933      if (isspace(fch))
7934       {
7935        while(isspace(c))
7936         {
7937          if ((c = scanf_getc(f)) == EOF) break;
7938         }
7939        if (c == EOF) break;
7940        continue;
7941       }
7942      else if (c == fch)
7943       {
7944        c = scanf_getc(f);
7945        continue;
7946       }
7947      /* mismatched input char - finished ret count of assigned */
7948      retval = 0;
7949      break;
7950     }
7951    if ((fch = infmt()) == EOF) break;
7952    /* check for format suppress char */
7953    if (fch == '*')
7954     {
7955      assgn_sup = TRUE;
7956      if ((fch = infmt()) == EOF) break;
7957     }
7958    else assgn_sup = FALSE;
7959 
7960    /* find maximum field width */
7961    width = 0;
7962    while (isdigit(fch))
7963     {
7964      width *= 10;
7965      width += fch - '0';
7966      if ((fch = infmt()) == EOF) goto done;
7967     }
7968    if (width == 0) width = -1;
7969 
7970    /* LOOKATME - possible portability problem since isspace of */
7971    /* special -2 may or may be space - checking both */
7972    /* consume input line white space unless special c format */
7973    if (fch != 'c')
7974     {
7975      while (isspace(c)) { if ((c = scanf_getc(f)) == EOF) break; }
7976     }
7977 
7978    retval = 0;
7979    switch (fch) {
7980     case '%':
7981      /* %% matches % - i.e. it is % escaping mechanism */
7982      if (c != '%') goto done;
7983      break;
7984     case 'd': base = BDEC; goto do_num;
7985     case 'b': base = BBIN; goto do_num;
7986     case 'o': base = BOCT; goto do_num;
7987     case 'x': case 'h': base = BHEX;
7988 do_num:
7989      /* return F if no characters collected */
7990      if (!collect_scanf_num(&signc, f, c, base, width)) goto done;
7991      if (!assgn_sup)
7992       {
7993        num_matched++;
7994        if (axp == NULL) goto done;
7995        lhsx = axp->lu.x;
7996 
7997        /* also convert into ac/bc wrk globals */
7998        /* conversion requires knowing arg expr width - can only do here */
7999        __itoklen = lhsx->szu.xclen;
8000        /* converted number converted to exactly lhs expr size */
8001        /* use expr. width as imputed [num]' form - always succeeds */
8002        __to_dhboval(base, FALSE);
8003 
8004        /* try to correct value for minus sign */
8005        if (signc == '-')
8006         {
8007          /* SJM 05/14/04 - must handle any width signed */
8008          if (vval_is0_(__bcwrk, __itoklen))
8009           {
8010            if (__itoklen == WBITS)
8011             { ival = (int32) __acwrk[0]; __acwrk[0] = (word32) -ival; }
8012            else __inplace_lnegate(__acwrk, __itoklen);
8013           }
8014         }
8015 
8016        /* know __acwrk and _bcwrk have right width number */
8017        if (lhsx->optyp != OPEMPTY)
8018         {
8019          __exec2_proc_assign(lhsx, __acwrk, __bcwrk);
8020         }
8021        /* know c has 1 char after number */
8022        axp = axp->ru.x;
8023       }
8024      break;
8025     case 'f': case 'e': case 'g': case 't':
8026      if (!collect_scanf_realnum(&(d1), f, c, width, fch)) goto done;
8027      if (!assgn_sup)
8028       {
8029        if (axp == NULL) goto done;
8030        lhsx = axp->lu.x;
8031        axp = axp->ru.x;
8032        num_matched++;
8033        if (lhsx->optyp != OPEMPTY)
8034         {
8035          push_xstk_(xsp, WBITS);
8036          memcpy(xsp->ap, &d1, sizeof(double));
8037          if (!lhsx->is_real)
8038           {
8039            __cnv_stk_fromreal_toreg32(xsp);
8040 
8041            /* SJM 09/29/03 - chg to handle sign extend and separate types */
8042            if (xsp->xslen > lhsx->szu.xclen)
8043             __narrow_sizchg(xsp, lhsx->szu.xclen);
8044            else if (xsp->xslen < lhsx->szu.xclen)
8045             {
8046              /* know always signed */
8047              __sgn_xtnd_widen(xsp, lhsx->szu.xclen);
8048             }
8049           }
8050 
8051          __exec2_proc_assign(lhsx, xsp->ap, xsp->bp);
8052          __pop_xstk();
8053         }
8054       }
8055      /* know c has 1 char after number */
8056      break;
8057     case 'v':
8058      wchp = __numtoken;
8059      /* know there is always look ahead char */
8060      wchp[0] = c;
8061      if ((c = scanf_getc(f)) == EOF) goto done;
8062      wchp[1] = c;
8063      if ((c = scanf_getc(f)) == EOF) goto done;
8064      wchp[2] = c;
8065      wchp[3] = '\0';
8066      if ((stval = cnvt_scanf_stnam_to_val(wchp)) == 0) goto done;
8067      if (!assgn_sup)
8068       {
8069        lhsx = axp->lu.x;
8070        if (lhsx->optyp != OPEMPTY)
8071         {
8072          push_xstk_(xsp, 1);
8073          /* SJM 09/25/03 - since can only assign to reg remove stren */
8074          xsp->ap[0] = stval & 1;
8075          xsp->bp[0] = (stval >> 1) & 1;
8076 
8077          /* SJM 09/29/03 - since 1 bit rhs never signed - can only widen */
8078          if (xsp->xslen != lhsx->szu.xclen)
8079           __sizchg_widen(xsp, lhsx->szu.xclen);
8080 
8081          __exec2_proc_assign(lhsx, xsp->ap, xsp->bp);
8082          __pop_xstk();
8083         }
8084       }
8085      break;
8086     case 'c':
8087      /* SJM 09/24/03 - old sscanf multiple chars removed - now 1 char only */
8088      /* SJM 03/20/00 - know never need to grow num token - f get used */
8089      /* notice unlike clib, width can't be used for "string" of chars */
8090      /* SJM 05/14/04 - know the char already read and in c */
8091      /* must be one char left on input stream */
8092      if (c == EOF) goto done;
8093      wchp = __numtoken;
8094      wchp[0] = (byte) c;
8095      wchp[1] = '\0';
8096      len = 1;
8097      /* if past end of formats, no more assignments to do */
8098      /* convert to pascal style string as Verilog value on stack */
8099 do_str_assign:
8100      /* DBG remove ---
8101      if (__debug_flg)
8102       { __dbg_msg("read string [%s]\n", __numtoken); }
8103      --- */
8104      if (!assgn_sup)
8105       {
8106        num_matched++;
8107        if (axp == NULL) goto done;
8108        lhsx = axp->lu.x;
8109        axp = axp->ru.x;
8110        push_xstk_(xsp, 8*len);
8111        zero_allbits_(xsp->bp, xsp->xslen);
8112        __vstr_to_vval(xsp->ap, __numtoken, 8*len);
8113        if (lhsx->optyp != OPEMPTY)
8114         {
8115          /* size chg never needs sign extend - can narrow or widen */
8116          if (xsp->xslen != lhsx->szu.xclen) __sizchgxs(xsp, lhsx->szu.xclen);
8117 
8118          __exec2_proc_assign(lhsx, xsp->ap, xsp->bp);
8119         }
8120        __pop_xstk();
8121        /* c has next char to process */
8122       }
8123      break;
8124     case 's':
8125      /* s is for white space delimited strings */
8126      wchp = __numtoken;
8127      /* notice works since added \0 to end of input line */
8128      /* i.e. empty string ok */
8129      for (len = 0;;)
8130       {
8131        *wchp++ = c;
8132        len++;
8133        c = scanf_getc(f);
8134        if (width > 0 && --width == 0) break;
8135        if (c == EOF || isspace(c)) break;
8136       }
8137      *wchp = '\0';
8138      goto do_str_assign;
8139     case 'u':
8140      /* no way to detemine num words to read */
8141      if (assgn_sup)
8142       {
8143        __sgferr(3417,
8144         "scanf assignment suppression character illegal with %%u binary data format");
8145        errno = EINVAL;
8146        return(-1);
8147       }
8148      if (width != -1)
8149       {
8150        __sgfinform(3008,
8151         "scanf field width meaningless with %%u binary data format - width ignored");
8152       }
8153      if (axp == NULL) goto done;
8154      lhsx = axp->lu.x;
8155      xsp = collect_ufmt_binval(f, lhsx, c);
8156      if (xsp == NULL) goto done;
8157      axp = axp->ru.x;
8158      /* since use scanf assign to reg arg for size - never need size chg */
8159      __exec2_proc_assign(lhsx, xsp->ap, xsp->bp);
8160      __pop_xstk();
8161      break;
8162     case 'z':
8163      /* no way to detemine num words to read */
8164      if (assgn_sup)
8165       {
8166        __sgferr(3417,
8167         "scanf assignment suppression character illegal with %%z binary data format");
8168        errno = EINVAL;
8169        return(-1);
8170       }
8171      if (width != -1)
8172       {
8173        __sgfinform(3008,
8174         "scanf field width meaningless with %%z binary data format - width ignored");
8175       }
8176      if (axp == NULL) goto done;
8177      lhsx = axp->lu.x;
8178      axp = axp->ru.x;
8179      xsp = collect_zfmt_binval(f, lhsx, c);
8180      if (xsp == NULL) goto done;
8181 
8182      /* since use scanf assign to reg arg for size - never need size chg */
8183      __exec2_proc_assign(lhsx, xsp->ap, xsp->bp);
8184      __pop_xstk();
8185      break;
8186     case 'm':
8187      sav_sofs = __cur_sofs;
8188      if (__cur_thd == NULL) tskp = __scope_tskp;
8189      else tskp = __getcur_scope_tsk();
8190      __disp_itree_path(__inst_ptr, tskp);
8191      /* use optional width field to truncate */
8192      if (width > 1 && (__cur_sofs - sav_sofs) > width)
8193       {
8194        __cur_sofs = sav_sofs + width;
8195        __exprline[__cur_sofs] = '\0';
8196       }
8197      len = __cur_sofs - sav_sofs;
8198      if (!assgn_sup)
8199       {
8200        num_matched++;
8201        if (axp == NULL) { __cur_sofs = sav_sofs; goto done; }
8202 
8203        lhsx = axp->lu.x;
8204        axp = axp->ru.x;
8205        push_xstk_(xsp, 8*len);
8206        zero_allbits_(xsp->bp, xsp->xslen);
8207        __vstr_to_vval(xsp->ap, __exprline, 8*len);
8208        if (lhsx->optyp != OPEMPTY)
8209         {
8210          /* widening adds high 0 bits */
8211          /* again can narrow or widen and neve need sign extend */
8212          if (xsp->xslen != lhsx->szu.xclen) __sizchgxs(xsp, lhsx->szu.xclen);
8213 
8214          __exec2_proc_assign(lhsx, xsp->ap, xsp->bp);
8215         }
8216        __pop_xstk();
8217       }
8218      /* c has next char to process */
8219      continue;
8220     default:
8221      /* invalid format char after % */
8222      errno = EINVAL;
8223      goto done;
8224    }
8225    /* SJM 05/14/04 - top of loop expects one ahead */
8226    c = scanf_getc(f);
8227   }
8228  /* good exit from scan processing of fmt - but still read one too far */
8229  scanf_ungetc(c, f);
8230 
8231  /* this is nothing read case */
8232  if (retval == -1) return(-1);
8233  return(num_matched);
8234 
8235 done:
8236  if (f != NULL && __scanf_pos > 0)
8237   {
8238    if (fseek(f, __scanf_pos - 1, SEEK_SET) == -1) return(-1);
8239   }
8240  /* this is nothing read case */
8241  if (retval == -1) return(-1);
8242  return(num_matched);
8243 }
8244 
8245 /*
8246  * version of getc that read from passed scanf input file or buf for sscanf
8247  */
scanf_getc(FILE * f)8248 static int32 scanf_getc(FILE *f)
8249 {
8250  int32 c;
8251 
8252  if (f == NULL)
8253   {
8254    if (*__fiolp == '\0') return(EOF);
8255    return(*__fiolp++);
8256   }
8257  c = fgetc(f);
8258  return(c);
8259 }
8260 
8261 /*
8262  * version of ungetc that backup up buffer for string file io operations
8263  * BEWARE - can't call ungetc unless something read
8264  */
scanf_ungetc(int32 c,FILE * f)8265 static void scanf_ungetc(int32 c, FILE *f)
8266 {
8267  if (f == NULL) __fiolp--; else ungetc(c, f);
8268 }
8269 
8270 /*
8271  * check new fileio $fscanf or $sscanf format string
8272  *
8273  * SJM 09/24/03 - now must check at run time each time called because
8274  * format can be variable - also only check fmt not arg matching
8275  *
8276  * LOOKATME - could check only once for constant fmt string
8277  */
chk_scanf_fmt(char * fmt)8278 static int32 chk_scanf_fmt(char *fmt)
8279 {
8280  register char *fp;
8281  int32 fmt_pos, rv, has_width;
8282 
8283  rv = TRUE;
8284  fp = fmt;
8285  fmt_pos = 0;
8286  while (*fp != '\0')
8287   {
8288    /* just char in fmt to match */
8289    if (*fp++ != '%') continue;
8290 
8291    /* %% is way to match % in input */
8292    /* SJM 09/24/03 - assuming %[* and/or width digs]% illegal */
8293    if (*fp == '%') { fp++; continue; }
8294 
8295    /* assign suppress char legal */
8296    if (*fp == '*') fp++;
8297 
8298    /* possible %ddd[fmt letter] */
8299    has_width = FALSE;
8300    while (isdigit(*fp))
8301     {
8302      fp++;
8303      if (*fp == '\0')
8304       {
8305        __sgferr(1186,
8306          "end of format while reading maximum field width (pos. %d)",
8307         fmt_pos);
8308        rv = FALSE;
8309        goto done;
8310       }
8311      has_width = TRUE;
8312     }
8313    fmt_pos++;
8314    /* string formats must be multiple of 8 bits */
8315    switch (*fp) {
8316     case 'b': case 'o': case 'h': case 'x': case 'd':
8317      break;
8318     case 'f': case 'e': case 'g':
8319      break;
8320     case 'v':
8321      break;
8322     case 't':
8323      break;
8324     case 'c':
8325      if (has_width)
8326       {
8327        __sgfwarn(3104,
8328         "maximum field width used with %%c format (pos. %d) - width ignored",
8329         fmt_pos);
8330       }
8331      break;
8332     case 's':
8333      break;
8334     case 'u':
8335      break;
8336     case 'z':
8337      break;
8338     case 'm':
8339      break;
8340     default:
8341      __sgferr(1274,
8342       "$scanf %%%c (pos. %d) is not legal FILE IO format letter",
8343       *fp, fmt_pos);
8344      rv = FALSE;
8345    }
8346    fp++;
8347   }
8348 done:
8349  return(rv);
8350 }
8351 
8352 /*
8353  * collect a dhbo number from input into num token global
8354  * returns F on error - if so num token invalid
8355  */
collect_scanf_num(int32 * signc,FILE * f,int32 c,int32 base,int32 width)8356 static int32 collect_scanf_num(int32 *signc, FILE *f, int32 c, int32 base, int32 width)
8357 {
8358  register char *wchp;
8359 
8360  wchp = __numtoken;
8361  /* collect number */
8362  if (c == '-' || c == '+')
8363   {
8364    /* minus only legal for %d (and real) format(s) */
8365    if (base != BDEC)
8366     {
8367      __sgfinform(3008,
8368       "numeric non decimal (%%d) scanf format illegally begins with sign");
8369      return(FALSE);
8370     }
8371    *signc = c;
8372    if (width > 0) --width;
8373    c = scanf_getc(f);
8374   }
8375  else *signc = ' ';
8376 
8377  for (;;)
8378   {
8379    if (isspace(c) || c == EOF) break;
8380    /* skip _ space holder */
8381    if (c != '_')
8382     {
8383      /* non number char ends number if not ended with white space */
8384      if ((c = __is_vdigit(c, base)) < 0) break;
8385 
8386      if (base == BDEC)
8387       {
8388        /* SJM 05/14/04 - decimal format ended by non beginning xz, i.e. */
8389        /* it is assumed to be start of a string */
8390        if ((c == 'x' || c == 'z') && wchp != __numtoken) break;
8391       }
8392      *wchp++ = c;
8393     }
8394    c = scanf_getc(f);
8395    if (width > 0 && --width == 0) break;
8396   }
8397  *wchp = '\0';
8398  if (wchp == __numtoken) return(FALSE);
8399  /* SJM 05/14/04 - if ends with non white space, need to start reading with */
8400  /* ending char */
8401  if (!isspace(c) && c != EOF) scanf_ungetc(c, f);
8402 
8403  return(TRUE);
8404 }
8405 
8406 /*
8407  * collect a ral (f,g, e, and t) real number from input into num token global
8408  * returns F on error - if so dret not changed
8409  */
collect_scanf_realnum(double * dret,FILE * f,int32 c,int32 width,int32 fch)8410 static int32 collect_scanf_realnum(double *dret, FILE *f, int32 c, int32 width,
8411  int32 fch)
8412 {
8413  register char *wchp;
8414  double d1;
8415  int32 got_dot, got_e, signc, unit, errnum;
8416  char *endp;
8417 
8418  /* collect the string */
8419  wchp = __numtoken;
8420  if (c == '-' || c == '+')
8421   { signc = c; if (width > 0) --width; c = scanf_getc(f); }
8422  else signc = ' ';
8423  got_dot = got_e = 0;
8424  for (;;)
8425   {
8426    if (isdigit(c)) *wchp++ = c;
8427    else if (got_e && wchp[-1] == 'e' && (c == '-' || c == '+'))
8428     *wchp++ = c;
8429    else if (!got_e && (c == 'e' || c == 'E'))
8430     { *wchp++ = 'e'; got_e = got_dot = 1; }
8431    else if (c == '.' && !got_dot) { *wchp++ = c; got_dot = 1; }
8432    else break;
8433 
8434    if ((c = scanf_getc(f)) == EOF) break;
8435    if (width > 0 && --width == 0) break;
8436   }
8437  *wchp = '\0';
8438  /* terminate if no characters collected */
8439  if (wchp == __numtoken) return(FALSE);
8440 
8441  /* SJM 05/14/04 - if ends with non white space, need to start reading with */
8442  /* ending char */
8443  if (!isspace(c) && c != EOF) scanf_ungetc(c, f);
8444 
8445  d1 = __my_strtod(__numtoken, &endp, &errnum);
8446  if (errnum != 0 || *endp != '\0') return(FALSE);
8447  if (signc == '-') d1 = -d1;
8448 
8449  /* SJM 09/24/03 - LOOKATME - maybe should only do if not suppresed */
8450  if (fch == 't')
8451   {
8452    /* t format same as real except need to scale time format */
8453    if (__inst_mod->mtime_units != __tfmt_units)
8454     {
8455      if (__inst_mod->mtime_units > __tfmt_units)
8456       {
8457        /* here d1 module ticks higher exp (more precision) - divide */
8458        unit = __inst_mod->mtime_units - __tfmt_units;
8459        d1 /= __dbl_toticks_tab[unit];
8460       }
8461      else
8462       {
8463        /* here d1 module ticks lower (less precision) - multiply */
8464        unit = __tfmt_units - __inst_mod->mtime_units;
8465        d1 *= __dbl_toticks_tab[unit];
8466       }
8467     }
8468   }
8469  *dret = d1;
8470  return(TRUE);
8471 }
8472 
8473 /*
8474  * collect 'u' format binary 0/1 one word32 values onto top of pushed xstk
8475  */
collect_ufmt_binval(FILE * f,struct expr_t * lhsx,int32 c)8476 static struct xstk_t *collect_ufmt_binval(FILE *f, struct expr_t *lhsx, int32 c)
8477 {
8478  register int32 wi;
8479  register word32 wrd;
8480  int32 b1, b2, b3, b4;
8481  struct xstk_t *xsp;
8482 
8483  push_xstk_(xsp, lhsx->szu.xclen);
8484  /* b part always 0 */
8485  zero_allbits_(xsp->bp, xsp->xslen);
8486  for (wi = 0; wi < wlen_(lhsx->szu.xclen); wi++)
8487   {
8488    b1 = (word32) c;
8489    if ((c = scanf_getc(f)) == EOF) return(NULL);
8490    b2 = (word32) c;
8491    if ((c = scanf_getc(f)) == EOF) return(NULL);
8492    b3 = (word32) c;
8493    if ((c = scanf_getc(f)) == EOF) return(NULL);
8494    b4 = (word32) c;
8495 #if (BYTE_ORDER == BIG_ENDIAN)
8496    wrd = (b1 & 0xff) | ((b2 & 0xff) << 8) | ((b3 & 0xff) << 16)
8497     | ((b4 & 0xff) << 24);
8498 #else
8499    wrd = (b4 & 0xff) | ((b3 & 0xff) << 8) | ((b2 & 0xff) << 16)
8500     | ((b1 & 0xff) << 24);
8501 #endif
8502    xsp->ap[wi] = wrd;
8503   }
8504  return(xsp);
8505 }
8506 
8507 /*
8508  * collect 'z' format binary 4 value 2 word32 values onto top of pushed xstk
8509  */
collect_zfmt_binval(FILE * f,struct expr_t * lhsx,int32 c2)8510 static struct xstk_t *collect_zfmt_binval(FILE *f, struct expr_t *lhsx,
8511  int32 c2)
8512 {
8513  register int32 wi;
8514  register word32 wrd, wrd2;
8515  int32 c, b1, b2, b3, b4;
8516  struct xstk_t *xsp;
8517 
8518  push_xstk_(xsp, lhsx->szu.xclen);
8519  for (wi = 0; wi < wlen_(lhsx->szu.xclen); wi++)
8520   {
8521    /* binary format by convention is a/b pairs following PLI t_vecval */
8522    b1 = (word32) c2;
8523    if ((c = scanf_getc(f)) == EOF) return(NULL);
8524    b2 = (word32) c;
8525    if ((c = scanf_getc(f)) == EOF) return(NULL);
8526    b3 = (word32) c;
8527    if ((c = scanf_getc(f)) == EOF) return(NULL);
8528    b4 = (word32) c;
8529 #if (BYTE_ORDER == BIG_ENDIAN)
8530    wrd = (b1 & 0xff) | ((b2 & 0xff) << 8) | ((b3 & 0xff) << 16)
8531     | ((b4 & 0xff) << 24);
8532 #else
8533    wrd = (b4 & 0xff) | ((b3 & 0xff) << 8) | ((b2 & 0xff) << 16)
8534     | ((b1 & 0xff) << 24);
8535 #endif
8536    xsp->ap[wi] = wrd;
8537 
8538    if ((c = scanf_getc(f)) == EOF) return(NULL);
8539    b1 = (word32) c;
8540    if ((c = scanf_getc(f)) == EOF) return(NULL);
8541    b2 = (word32) c;
8542    if ((c = scanf_getc(f)) == EOF) return(NULL);
8543    b3 = (word32) c;
8544    if ((c = scanf_getc(f)) == EOF) return(NULL);
8545    b4 = (word32) c;
8546 #if (BYTE_ORDER == BIG_ENDIAN)
8547    wrd2 = (b1 & 0xff) | ((b2 & 0xff) << 8) | ((b3 & 0xff) << 16)
8548     | ((b4 & 0xff) << 24);
8549 #else
8550    wrd2 = (b4 & 0xff) | ((b3 & 0xff) << 8) | ((b2 & 0xff) << 16)
8551     | ((b1 & 0xff) << 24);
8552 #endif
8553    xsp->bp[wi] = wrd2;
8554   }
8555  return(xsp);
8556 }
8557 
8558 /*
8559  * convert scanf stren name to one byte stren value
8560  * return byte value or 0 (impossible stren) on error
8561  *
8562  * since scanf can only assign to regs, stren has stren removed
8563  * but must check for legal and then remove stren
8564  */
cnvt_scanf_stnam_to_val(char * s)8565 static int32 cnvt_scanf_stnam_to_val(char *s)
8566 {
8567  int32 stval, st0, st1;
8568  char val;
8569  char stren[RECLEN];
8570 
8571  if (strcmp(s, "HiZ") == 0) return(2);
8572 
8573  val = s[2];
8574  strncpy(stren, s, 2);
8575  stren[2] = '\0';
8576  if (strcmp(stren, "Su") == 0) st0 = st1 = ST_SUPPLY;
8577  else if (strcmp(stren, "St") == 0) st0 = st1 = ST_STRONG;
8578  else if (strcmp(stren, "Pu") == 0) st0 = st1 = ST_PULL;
8579  else if (strcmp(stren, "La") == 0) st0 = st1 = ST_LARGE;
8580  else if (strcmp(stren, "We") == 0) st0 = st1 = ST_WEAK;
8581  else if (strcmp(stren, "Me") == 0) st0 = st1 = ST_MEDIUM;
8582  else if (strcmp(stren, "Sm") == 0) st0 = st1 = ST_SMALL;
8583  else return(-1);
8584 
8585  /* only use of Z aready eliminated */
8586  /* notice st1 and st0 must be same here */
8587  switch(val) {
8588   case '0':
8589    stval = 0 | (st1 << 2) | (st0 << 5);
8590    break;
8591   case '1':
8592    stval = 1 | (st1 << 2) | (st0 << 5);
8593    break;
8594   case 'X':
8595    stval = 3 | (st1 << 2) | (st0 << 5);
8596    break;
8597   case 'L':
8598    stval = 3 | (st0 << 5);
8599    break;
8600   case 'H':
8601    stval = 3 | (st1 << 2);
8602    break;
8603   default: return(0);
8604  }
8605  return(stval);
8606 }
8607 
8608