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