1 /* Copyrght (c) 1993-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 * debugger - interactive environment
30 */
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <ctype.h>
36
37 #ifdef __linux__
38 #include <sys/types.h>
39 #include <sys/wait.h>
40 #endif
41
42 #include <signal.h>
43
44 #include <unistd.h>
45 #include <setjmp.h>
46
47 #ifdef __DBMALLOC__
48 #include "../malloc.h"
49 #endif
50
51 #include "v.h"
52 #include "cvmacros.h"
53
54 /* local prototypes */
55 static void rem_escape_newlines(register char *);
56 static void snap_finish(void);
57 static void setup_interactive(void);
58 static void add_iahist(void);
59 static int32 get_iahcmdnum(void);
60 static void grow_iahtab(void);
61 static void rd_exec_iact_stmt(int32);
62 static void chk_iact_grefs(int32);
63 static void init_iahctrl(struct hctrl_t *);
64 static void init_sched_iathd(struct hctrl_t *);
65 static struct thread_t *bld_immed_iathrd(struct st_t *);
66 static void free_iact_glbs(struct gref_t *, int32);
67 static void renumber_1stmt(struct st_t *, int32, int32);
68 static void renumber_csitemlst(register struct csitem_t *, int32, int32);
69 static void renumber_stlst(register struct st_t *, int32, int32);
70 static int32 prt1_iahist_cmd(int32);
71 static void free_done_iact_control(struct hctrl_t *, int32);
72 static int32 do_dbg_cmd(void);
73 static void cmd_illegal_msg(char *);
74 static int32 dbcmd_prefix_rep(register int32, char *, int32, struct namlst_t *, int32);
75 static void do_dbg_help(void);
76 static void wr_dbg_hlpmsg(char **);
77 static void wr_dbg_lstofcmds(struct namlst_t *, int32);
78 static void dbg_print(void);
79 static char *dbg_bld_expr_val(char *, struct expr_t *, int32, int32, int32);
80 static void dbg_display(void);
81 static void prt_all_disp_exprs(void);
82 static char *bld_prtbasecode(char *, int32, int32, int32);
83 static void do_dbg_expris(void);
84 static char *bld_expr_telltale(char *, struct expr_t *);
85 static void do_dbg_varis(void);
86 static void print_iddecl_ref(struct sy_t *, struct sy_t *);
87 static void do_dbg_whatis(void);
88
89 /* extern prototypes (maybe defined in this module) */
90 extern char *__my_malloc(int32);
91 extern FILE *__tilde_fopen(char *, char *);
92 extern char *__pv_stralloc(char *);
93 extern struct task_t *__find_thrdtsk(struct thread_t *);
94 extern void __set_dbentry_listline(void);
95 extern void __call_misctfs_iact(void);
96 extern void __vpi_enteriact_trycall(void);
97 extern void __call_misctfs_scope(void);
98 extern void __vpi_iactscopechg_trycall(void);
99 extern int32 __rd_ialine(void);
100 extern void __my_fclose(FILE *);
101 extern void __call_misctfs_finish(void);
102 extern void __vpi_endsim_trycall(void);
103 extern void __get_vtok(void);
104 extern char *__msg_blditree(char *, struct itree_t *, struct task_t *);
105 extern char *__bld_lineloc(char *, word32, int32);
106 extern void __vpi_exitiact_trycall(void);
107 extern int32 __chk_extra_atend(int32);
108 extern char *__prt_vtok(void);
109 extern void __do_iact_disable(struct hctrl_t *, int32);
110 extern char *__to_timstr(char *, word64 *);
111 extern void __write_snapshot(int32);
112 extern void __my_ftime(time_t *, time_t *);
113 extern void __prt_end_msg(void);
114 extern void __add_infil(char *);
115 extern int32 __wide_vval_is0(register word32 *, int32);
116 extern char *__regab_tostr(char *, word32 *, word32 *, int32, int32, int32);
117 extern char *__my_realloc(char *, int32, int32);
118 extern void __grow_tevtab(void);
119 extern struct st_t *__rd_stmt(void);
120 extern void __chk_lstofsts(struct st_t *);
121 extern void __chk_nodel_lstofsts(struct st_t *);
122 extern struct st_t *__prep_lstofsts(struct st_t *, int32, int32);
123 extern void __free_1stmt(struct st_t *);
124 extern void __free_dceauxlst(struct dceauxlst_t *, int32);
125 extern void __free_dceauxs_only(struct dceauxlst_t *);
126 extern struct st_t *__brktr_exec_1stmt(struct st_t *);
127 extern void __my_free(char *, int32);
128 extern void __ia_warn(int32, char *, ...);
129 extern char *__msg2_blditree(char *, struct itree_t *);
130 extern struct thread_t *__alloc_thrd(void);
131 extern void __add_ev_to_front(register i_tev_ndx);
132 extern void __free_1glb_flds(struct gref_t *);
133 extern char *__get_eval_cstr(struct expr_t *, int32 *);
134 extern void __free_thd_list(struct thread_t *);
135 extern void __free_1thd(struct thread_t *);
136 extern int32 __get_dbcmdnum(char *, struct namlst_t *, int32);
137 extern char *__bld_ambiguous_list(char *, char *, struct namlst_t *, int32);
138 extern void __prt_where_msg(register struct thread_t *);
139 extern void __do_dbg_list(void);
140 extern void __do_dbg_set(void);
141 extern void __do_dbg_info(void);
142 extern void __do_dbg_dis_enable(int32);
143 extern void __dbg_undisplay(void);
144 extern int32 __get_dbg_val(void);
145 extern void __do_dbg_history(void);
146 extern void __do_dbg_emptyhistory(void);
147 extern void __do_dbg_brkpt(int32);
148 extern void __do_dbg_ibrkpt(int32);
149 extern int32 __do_dbg_nextb(void);
150 extern void __do_dbg_delbrkdis(void);
151 extern void __do_dbg_scope(void);
152 extern void __dbg_brk_ignore(void);
153 extern void __dbg_brk_cond(void);
154 extern void __wrap_puts(char *, FILE *);
155 extern void __wrap_putc(int32, FILE *);
156 extern struct expr_t *__rd_iact_expr(void);
157 extern int32 __colto_eol(void);
158 extern void __free_xtree(struct expr_t *);
159 extern char *__strenexpr_tostr(char *, struct expr_t *);
160 extern struct xstk_t *__eval2_xpr(register struct expr_t *);
161 extern int32 __trim1_0val(word32 *, int32);
162 extern char *__strab_tostr(char *, word32 *, int32, int32, int32);
163 extern char *__regab2_tostr(char *, word32 *, word32 *, int32, int32, int32, int32);
164 extern void __bld_xtree(int32);
165 extern int32 __chk_rhsexpr(struct expr_t *, int32);
166 extern int32 __bld_expnode(void);
167 extern void __set_xtab_errval(void);
168 extern char *__msgexpr_tostr(char *, struct expr_t *);
169 extern char *__to_opname(word32);
170 extern char *__to_sytyp(char *, word32);
171 extern char *__bld_showvars_prefix(char *, struct net_t *,
172 struct gref_t *grp);
173 extern struct sy_t *__get_sym(char *, struct symtab_t *);
174 extern int32 __do_vpi_stop(int32);
175 extern void __do_vpi_reset(int32, int32, int32);
176 extern void __emit_vpi_noiact_warn(void);
177 extern void __emit_vpi_iniact_warn(void);
178 extern void __emit_stsk_endmsg(void);
179 extern struct gref_t *__alloc_grtab(struct gref_t *, int32);
180 extern void __init_mod(struct mod_t *, struct sy_t *);
181 extern void __my_dv_flush(void);
182 extern void __wr_dvtimstr(void);
183 extern void __push_wrkitstk(struct mod_t *, int32);
184 extern void __pop_wrkitstk(void);
185 extern void __free_dce_prevval(struct dcevnt_t *, int32, int32);
186 extern int32 __get_dcewid(struct dcevnt_t *, struct net_t *);
187 extern int32 __get_pcku_chars(int32, int32);
188
189
190 extern void __cv_msg(char *, ...);
191 extern void __cvsim_msg(char *, ...);
192 extern void __cvsim2_msg(char *, ...);
193 extern void __cvsim3_msg(char *, ...);
194 extern void __pv_warn(int32, char *,...);
195 extern void __sgfwarn(int32, char *, ...);
196 extern void __sgferr(int32, char *, ...);
197 extern void __pv_terr(int32, char *, ...);
198 extern void __arg_terr(char *, int32);
199 extern void __case_terr(char *, int32);
200 extern void __misc_terr(char *, int32);
201 extern void __my_exit(int32, int32);
202 extern void __ia_err(int32 id_num, char *s, ...);
203
204 extern char __pv_ctab[];
205
206 /*
207 * STARTUP SIGNAL INITIALIZATION ROUTINES
208 */
209
210 /*
211 * signal handler during compilation
212 * should put in alarm here
213 */
__comp_sigint_handler(void)214 extern void __comp_sigint_handler(void)
215 {
216 char s1[RECLEN];
217
218 /* ignore ^c signal in here */
219 signal(SIGINT, SIG_IGN);
220 __cvsim2_msg(
221 "\nInterrupt (^C) occurred during translate/load, really quit? (y/n) ");
222 if (fgets(s1, RECLEN, stdin) == NULL) goto done;
223
224 if (s1[0] == 'y' || s1[0] == 'Y')
225 {
226 /* put back called signal */
227 #if defined(INTSIGS)
228 signal(SIGINT, __old_int_sig);
229 #else
230 signal(SIGINT, (void (*)()) __old_int_sig);
231 #endif
232 __pv_terr(311, "translate/load terminated by interrupt (^C) signal");
233 }
234 done:
235 /* why need to reset signal handler */
236 #if defined(INTSIGS)
237 signal(SIGINT, __comp_sigint_handler);
238 #else
239 signal(SIGINT, (void (*)()) __comp_sigint_handler);
240 #endif
241 }
242
243 /*
244 * signal during execution
245 * just set flag here - must be run to top level before catching
246 *
247 * all this does is set switch - caller must reset internal switch
248 * when processed or ignored
249 */
__sim_sigint_handler(void)250 extern void __sim_sigint_handler(void)
251 {
252 /* SJM 07/31/01 - think need message to indicate interrupt */
253 /* DBG remove -- */
254 __cvsim2_msg( "<INTERRUPT>\n");
255 /* --- */
256 __pending_enter_iact = TRUE;
257 __iact_reason = IAER_CTRLC;
258 /* if stepping, disable as if step completed */
259 __single_step = FALSE;
260 __step_rep_cnt = 0;
261 __step_lini = -1;
262 __step_ifi = -1;
263 /* REMOVEME - no longer supporting SunOS - maybe needed for hpux? */
264 #if (defined(__sparc) && defined(__SVR4))
265 /* LOOKATME _ not sure why needed iact ^c leaves EINTR uncleared ?? */
266 if (__cmd_s != NULL) clearerr(__cmd_s);
267 clearerr(stdin);
268 #endif
269 #if (defined(__i386__) && defined(__SVR4))
270 /* LOOKATME _ not sure why needed iact ^c leaves EINTR uncleared ?? */
271 if (__cmd_s != NULL) clearerr(__cmd_s);
272 clearerr(stdin);
273 #endif
274 }
275
276 /*
277 * interface to (only way program quits) to reset callers signal handler
278 *
279 * normally do_exit true but to return to caller called with do exit F
280 */
__my_exit(int32 rc,int32 do_exit)281 extern void __my_exit(int32 rc, int32 do_exit)
282 {
283 int32 i;
284
285
286 /* put back entry signal */
287 #ifdef INTSIGS
288 signal(SIGINT, __old_int_sig);
289 #else
290 signal(SIGINT, (void (*)()) __old_int_sig);
291 #endif
292
293 /* for antrim flush buffers */
294 /* always flush here in case of $finish */
295 if (__dv_fd != -1)
296 {
297 /* SJM 10/08/99 - need to write time at end for some wave form viewers */
298 __wr_dvtimstr();
299 __my_dv_flush();
300 }
301 if (__log_s != NULL) fflush(__log_s);
302 if (__tr_s != NULL) fflush(__tr_s);
303 for (i = 0; i < 31; i++)
304 {
305 if (__mulchan_tab[i].mc_s != NULL) fflush(__mulchan_tab[i].mc_s);
306 }
307 if (do_exit) exit(rc);
308 return;
309 }
310
311 /*
312 * INTERACTIVE SETUP ROUTINES
313 */
314
315 /*
316 * initialize interactive environment just before simulation begins
317 * but after all initialization wire evaluation finished
318 *
319 * since various interactive system tasks can appear in normal source
320 * this initializes those things - when interactive called real init done
321 * notice this is run with __iact_state off
322 */
__init_interactive(void)323 extern void __init_interactive(void)
324 {
325 register int32 i;
326 struct sy_t *syp;
327
328 /* set up listing file - nothing open and no line pos. file cached */
329 __filpostab = NULL;
330 __list_cur_fd = -1;
331 /* use can change this with :set - number is one less than no. to list */
332 /* since prt src lines is from - to */
333 __list_cur_listnum = 9;
334 /* start at 1st top level */
335 /* force setting on first :l command */
336 __list_cur_ifi = -1;
337 __nxt_bpnum = 1;
338 __bphdr = NULL;
339 __dispxhdr = NULL;
340 __nxt_dispxnum = 1;
341 __single_step = FALSE;
342 __step_rep_cnt = 0;
343 __step_from_thread = FALSE;
344 __step_match_itp = NULL;
345 __step_lini = -1;
346 __step_ifi = -1;
347 __verbose_step = FALSE;
348 __last_iasytp = NULL;
349
350 __last_stepitp = NULL;
351 __last_steptskp = NULL;
352 __last_stepifi = -1;
353 __last_brktime = 0xffffffffffffffffULL;
354
355 /* $scope start at first top level module - no old scope to push */
356 __scope_ptr = __it_roots[0];
357 __scope_tskp = NULL;
358
359 /* allocate interactive module - re-initialized each time iact entered */
360 /* 08/18/99 - for now only expr tab and glb tab fields used */
361 __iact_mdp = (struct mod_t *) __my_malloc(sizeof(struct mod_t));
362
363 syp = (struct sy_t *) __my_malloc(sizeof(struct sy_t));
364 syp->synam = __pv_stralloc("**IACT WORK**");
365 syp->sydecl = TRUE;
366
367 __init_mod(__iact_mdp, syp);
368 __iact_mdp->flatinum = 1;
369 syp->el.emdp = __iact_mdp;
370
371 /* default is now, use scope of entry in interactive, :set to use old */
372 __iact_scope_chg = TRUE;
373 __dbg_dflt_base = BHEX;
374
375 /* notice line count and :list command line are unrelated - line count is */
376 /* source line number or command history number */
377 __lin_cnt = 1;
378 /* this forces getc to read from read interactive line */
379 __in_s = NULL;
380 __file_just_op = FALSE;
381 __first_linetok = FALSE;
382 __cmd_fnam = NULL;
383 __cmd_s = NULL;
384
385 /* special code in get_env_sym so no environment here */
386 __venviron[0] = NULL;
387
388 /* LOOKATME - should read .[cverdbinit?] with history off */
389 __iahwrklen = 2*IDLEN + 8;
390 __iahwrkline = __my_malloc(__iahwrklen);
391 __hist_cur_listnum = 20;
392 __echo_iactcmds_tolog = TRUE;
393
394 /* setup history */
395 /* FIXME - need to wrap table not continue growing without limit */
396 __iahsiz = IAHISTSIZ;
397 __iahtab = (struct iahist_t *) __my_malloc(__iahsiz*sizeof(struct iahist_t));
398 /* must start with 0 since first add moves to real 1 start */
399 __iah_lasti = 0;
400 /* indexed from 1 but initialize from 0 */
401 for (i = 0; i < __iahsiz; i++)
402 { __iahtab[i].iah_lp = NULL; __iahtab[i].iah_hcp = NULL; }
403 __hctrl_hd =__hctrl_end = NULL;
404 }
405
406 /*
407 * INTERACTIVE DEBUGGER ROUTINES
408 */
409
410 /*
411 * execute the interactive control loop
412 *
413 * unless -<num> or <num> form or not history on put into history list
414 * only break (ctrl-c), $stop, or -s command option tranfer control to here
415 * continue (.) does not return here unless ctrl-c or $stop() execed
416 * when events exhausted looks like $finish hit
417 * commands executed from here return to here
418 *
419 * debugger commands are not added to the history list
420 * this runs with ctrl-c (int32) disabled
421 * upon entry, interrupt signal is SIGIGN
422 * also no current thread - run between processed events
423 * if entry from interactive non immediate $stop, no scope or file change
424 */
__do_interactive_loop(void)425 extern void __do_interactive_loop(void)
426 {
427 int32 histcmd_num, hist_rexec, rv, sav_lin_cnt, sav_cur_fnam_ind;
428 int32 chg_scope, still_stepping;
429 FILE *sav_cmd_s, *f;
430 char *sav_cmd_fnam;
431 struct iahist_t *iahp;
432 struct task_t *tskp;
433 struct sy_t *syp;
434 char s1[RECLEN], s2[RECLEN];
435
436 /* where call finish callbacks and exit when interactive turned off */
437 signal(SIGINT, SIG_IGN);
438
439 /* things needed on any entry to interactive */
440 /* if interactive mode off, just finish */
441 __iact_state = TRUE;
442 __pending_enter_iact = FALSE;
443 if (__no_iact) snap_finish();
444 /* if first time do some setup - not done after :reset or $reset */
445 if (!__iasetup)
446 {
447 setup_interactive();
448 __iasetup = TRUE;
449 __cvsim2_msg("Type :help for help\n");
450 }
451 if (!__ia_entered)
452 {
453 if (__cmd_start_fnam != NULL)
454 {
455 /* this was opened once to check but may be problem since then */
456 if ((f = __tilde_fopen(__cmd_start_fnam, "r")) == NULL)
457 {
458 __pv_warn(505,
459 "now cannot open -i startup interactive input file %s - using stdin",
460 __cmd_start_fnam);
461 }
462 else
463 {
464 __cmd_s = f;
465 __cmd_fnam = __pv_stralloc(__cmd_start_fnam);
466 }
467 }
468 __ia_entered = TRUE;
469 }
470 hist_rexec = FALSE;
471 sav_cmd_s = NULL;
472 sav_cmd_fnam = NULL;
473 sav_cur_fnam_ind = -1;
474 sav_lin_cnt = -1;
475
476 /* for entry from iact ($stop?), use original scope of interactive */
477 /* unless turned off or sim not started, use entry proc. scope as scope */
478 if (__iact_scope_chg && __suspended_thd != NULL)
479 {
480 /* scheme if that is last thread (pending) was in task move to task */
481 /* if enterered from ^c but evaling event, may want scope change */
482 if (__fcspi >= 0) tskp = __fcstk[__fcspi];
483 else if (__suspended_thd->th_fj) tskp = __find_thrdtsk(__suspended_thd);
484 else tskp = __suspended_thd->assoc_tsk;
485 /* this pushes scope since iact flag on */
486 __scope_ptr = __suspended_itp;
487 __scope_tskp = tskp;
488 chg_scope = TRUE;
489 }
490 else chg_scope = FALSE;
491 /* whenever enter iact, must push scope (needs to be in inst. ptr) */
492 __push_itstk(__scope_ptr);
493
494 /* notice list line and scope now unrelated - but always can set from */
495 /* suspended thread next statement */
496 __set_dbentry_listline();
497
498 /* if stepping repeat count, decrement and continue execing */
499 still_stepping = FALSE;
500 if (__iact_reason == IAER_STEP && --__step_rep_cnt > 0)
501 {
502 /* save moved to line but continue stepping */
503 __single_step = TRUE;
504 __verbose_step = TRUE;
505 if (__suspended_thd == NULL || __suspended_thd->thnxtstp == NULL)
506 __step_from_thread = FALSE;
507 still_stepping = TRUE;
508 goto do_ret;
509 }
510 if (__tfrec_hdr != NULL) __call_misctfs_iact();
511 if (__have_vpi_actions) __vpi_enteriact_trycall();
512
513 if (chg_scope)
514 {
515 if (__tfrec_hdr != NULL) __call_misctfs_scope();
516 if (__have_vpi_actions) __vpi_iactscopechg_trycall();
517 }
518 /* process and pending display commands */
519 if (__dispxhdr != NULL) prt_all_disp_exprs();
520
521 again:
522 /* hist rexec requires command and line no. from history - put back here */
523 /* re-execed history and now re-entering debugger so must change */
524 /* to input line world */
525 if (hist_rexec)
526 {
527 __cmd_s = sav_cmd_s;
528 __cmd_fnam = sav_cmd_fnam;
529 __cur_fnam_ind = sav_cur_fnam_ind;
530 __cur_fnam = __in_fils[__cur_fnam_ind];
531 __lin_cnt = sav_lin_cnt;
532 hist_rexec = FALSE;
533 }
534
535 /* write prompt if to screen if needed and/or to log file if exists */
536 /* here need to use next history location even though net yet filled */
537 if (__cmd_s == NULL && isatty(fileno(stdin)))
538 __cvsim2_msg("C%d > ", __iah_lasti + 1);
539 /* LOOKATME - log file output only because typed in from terminal */
540 if (__echo_iactcmds_tolog && __log_s != NULL)
541 __cvsim3_msg("C%d > ", __iah_lasti + 1);
542
543 /* first read the entire command (possible multiple \[new line] lines */
544 /* notice only $finish gets out of this loop */
545 if (__vin_top > 0) __misc_terr(__FILE__, __LINE__);
546 rv =__rd_ialine();
547 if (rv == TEOF)
548 {
549 if (__cmd_s != NULL)
550 {
551 /* LOOKATME - think this is unneeded */
552 clearerr(__cmd_s);
553 __my_fclose(__cmd_s);
554 __cmd_s = NULL;
555 __cmd_fnam = NULL;
556 __cur_fnam = __in_fils[1];
557 __cur_fnam_ind = __cmd_ifi;
558 /* after close file must emit prompt */
559 }
560 else
561 {
562 if (isatty(fileno(stdin)))
563 {
564 __ia_err(1403,
565 "EOF (^D or ^C) read from tty stdin - use :q or $finish; to exit program");
566 clearerr(stdin);
567 goto again;
568 }
569 /* cver run from batch file - on eof of stdin execute $finish */
570 __ia_err(1406,
571 "EOF on non tty stdin (simulation run from script) - $finish executed");
572 if (__tfrec_hdr != NULL) __call_misctfs_finish();
573 if (__have_vpi_actions) __vpi_endsim_trycall();
574 __my_exit(2, TRUE);
575 }
576 }
577 /* if no $input (or -i) file, line is command number */
578 if (__cmd_s == NULL) __lin_cnt = __iah_lasti;
579 num_reenable:
580 __visp->vichp = __iahwrkline;
581 /* since keywords ok in interactive, set beginning of line */
582 __first_num_eol = TRUE;
583
584 /* this is command parsing that requires tokenization */
585 __get_vtok();
586 if (__toktyp == TEOF) goto again;
587
588 switch ((byte) __toktyp) {
589 case TEOF: __case_terr(__FILE__, __LINE__); break;
590 case COLON:
591 __get_vtok();
592 if (__toktyp == TEOF)
593 {
594 if (__scope_tskp != NULL) syp = __scope_tskp->tsksyp;
595 else syp = __scope_ptr->itip->imsym;
596 __cvsim_msg("scope: %s (at %s and :list at %s)\n",
597 __msg_blditree(__xs, __scope_ptr, __scope_tskp),
598 __bld_lineloc(s1, syp->syfnam_ind, syp->sylin_cnt),
599 __bld_lineloc(s2, (word32) __list_cur_ifi, __list_arg_lini));
600 goto again;
601 }
602 /* : debugger commands always go on history list unless hist re-exec */
603 if (__history_on && !hist_rexec) add_iahist();
604 /* implement : [debugger command] - handles errors */
605 if (!do_dbg_cmd())
606 {
607 /* if debug command some kind of step, if rexeced restore iact loc. */
608 if (hist_rexec)
609 {
610 __cmd_s = sav_cmd_s;
611 __cmd_fnam = sav_cmd_fnam;
612 __cur_fnam_ind = sav_cur_fnam_ind;
613 __cur_fnam = __in_fils[__cur_fnam_ind];
614 __lin_cnt = sav_lin_cnt;
615 hist_rexec = FALSE;
616 }
617 /* here even if re-exec dot, still treat as new step */
618 __step_lini = -1;
619 __step_ifi = -1;
620 goto do_ret;
621 }
622 else goto again;
623 case DOT:
624 __step_lini = -1;
625 __step_ifi = -1;
626 do_ret:
627 if (!still_stepping && __have_vpi_actions) __vpi_exitiact_trycall();
628
629 __iact_state = FALSE;
630 /* if ^c hit in interactive debugger, unless command handles just ignore */
631 /* this is needed to stop, from immediate statement dbg enter */
632 /* on entry always push a scope, but must pop away before running again */
633 __pop_itstk();
634 /* need to enable sim sigint32 handler since turned off in iact loop */
635 #if defined(INTSIGS)
636 signal(SIGINT, __sim_sigint_handler);
637 #else
638 signal(SIGINT, (void (*)()) __sim_sigint_handler);
639 #endif
640 __pending_enter_iact = FALSE;
641 __iact_reason = IAER_UNKN;
642 return;
643 case SEMI:
644 if (__optimized_sim)
645 {
646 /* SJM 02/03/03 - breakpoint commands illegal if optimizer on */
647 cmd_illegal_msg("';' step with no trace (use '.')");
648 goto again;
649 }
650
651 /* ; statement step with no trace */
652 step_setup:
653 __single_step = TRUE;
654 __step_rep_cnt = 1;
655 if (__iact_reason == IAER_CTRLC || __suspended_thd == NULL
656 || __suspended_thd->thnxtstp == NULL) __step_from_thread = FALSE;
657 __chk_extra_atend(TRUE);
658 goto do_ret;
659 case COMMA:
660 if (__optimized_sim)
661 {
662 /* SJM 02/03/03 - breakpoint commands illegal if optimizer on */
663 cmd_illegal_msg("',' step with trace (use '.')");
664 goto again;
665 }
666 /* , statement step with debugger trace */
667 /* notice -t tracing additional and independent */
668 __verbose_step = TRUE;
669 goto step_setup;
670 case MINUS:
671 __get_vtok();
672 if (__toktyp != NUMBER)
673 {
674 __ia_err(1410, "minus disable command number expected: %s read",
675 __prt_vtok());
676 goto again;
677 }
678 /* this emits own error */
679 if ((histcmd_num = get_iahcmdnum()) == -1) goto again;
680
681 iahp = &(__iahtab[histcmd_num]);
682 if (iahp->iah_hcp == NULL)
683 {
684 __ia_err(1412, "-%d disable failed: command already completed",
685 histcmd_num);
686 goto again;
687 }
688 /* disable the command and free control record */
689 __do_iact_disable(iahp->iah_hcp, FALSE);
690 goto again;
691 case NUMBER:
692 /* this emits own error */
693 if ((histcmd_num = get_iahcmdnum()) == -1) goto again;
694 /* since need eventual history support, free if needed and reparse */
695 if (__iahtab[histcmd_num].iah_hcp != NULL)
696 {
697 __ia_err(1416, "attempt to re-execute C%d failed: command not completed",
698 histcmd_num);
699 goto again;
700 }
701 /* must copy since can edit new and new probably goes in history */
702 strcpy(__iahwrkline, __iahtab[histcmd_num].iah_lp);
703 rem_escape_newlines(__iahwrkline);
704 /* save all line loc. state and set to history command no. */
705 sav_cmd_s = __cmd_s;
706 __cmd_s = NULL;
707 sav_cmd_fnam = __cmd_fnam;
708 __cmd_fnam = NULL;
709 sav_cur_fnam_ind = __cur_fnam_ind;
710 __cur_fnam_ind = __cmd_ifi;
711 __cur_fnam = __in_fils[1];
712 sav_lin_cnt = __lin_cnt;
713 __lin_cnt = histcmd_num;
714 hist_rexec = TRUE;
715 goto num_reenable;
716 default:
717 /* schedule non immediate but never leave debugger from Verilog cmd */
718 rd_exec_iact_stmt(hist_rexec);
719 goto again;
720 }
721 }
722
723 /*
724 * when reparsing from history list must remove all escaped new lines
725 * since need to emit error message with only loc. history
726 */
rem_escape_newlines(register char * lp)727 static void rem_escape_newlines(register char *lp)
728 {
729 for (; *lp != '\0'; lp++)
730 {
731 if (*lp == '\\') { if (lp[1] == '\n') { *lp = ' '; lp[1] = ' '; lp++; } }
732 }
733 }
734
735 /*
736 * emit error if extra characters at end of line
737 * return F if more on line
738 */
__chk_extra_atend(int32 emit_err)739 extern int32 __chk_extra_atend(int32 emit_err)
740 {
741 register char *chp;
742
743 chp = __visp->vichp;
744 while (vis_white_(*chp)) chp++;
745 if (*chp != '\0')
746 {
747 if (emit_err)
748 {
749 __ia_err(1413,
750 "interactive command extra characters [%s] at end discarded", chp);
751 }
752 return(FALSE);
753 }
754 return(TRUE);
755 }
756
757 /*
758 * routine to write snapshot and quit on interrupt for debugging
759 * notice may not be scope when this called
760 */
snap_finish(void)761 static void snap_finish(void)
762 {
763 char s1[RECLEN];
764
765 __call_misctfs_finish();
766 if (__have_vpi_actions) __vpi_endsim_trycall();
767
768 /* return from interrupt signal handler */
769 __cvsim_msg(
770 "\nSimulation terminated by interrupt (^C) now %s (interactive debugger disabled)\n",
771 __to_timstr(s1, &__simtime));
772 if (__intsig_prt_snapshot)
773 {
774 /* DBG FIXME - for now just using large number */
775 if (__debug_flg) __write_snapshot(1000);
776 else __write_snapshot(DFLT_SNAP_EVS);
777 }
778
779 if (__verbose)
780 {
781 __my_ftime(&__end_time, &__end_mstime);
782 __prt_end_msg();
783 }
784 __my_exit(0, TRUE);
785 }
786
787 /*
788 * setup the interactive loop - called first time interactive started only
789 * once setup just leave special interactive file on visp stack
790 */
setup_interactive(void)791 static void setup_interactive(void)
792 {
793 /* input looks like reading from macro that is read ia line */
794 /* this justs stays present during simulation */
795 __visp = __vinstk[__vin_top];
796 __visp->vilin_cnt = 0;
797 __visp->vifnam_ind = __cmd_ifi;
798 __visp->vi_s = NULL;
799 /* this is set after each line is read */
800 __visp->vichp = NULL;
801
802 if (__cmd_s == NULL)
803 {
804 /* file is stdin */
805 __cur_fnam = __in_fils[1];
806 __cur_fnam_ind = __cmd_ifi;
807 /* line count will be set to command no. each time */
808 __lin_cnt = 0;
809 }
810 else
811 {
812 /* start reading from -i interactive file */
813 __add_infil(__cmd_fnam);
814 __cur_fnam_ind = __last_inf;
815 __cmd_fnam = __in_fils[__cur_fnam_ind];
816 __lin_cnt = 0;
817 }
818 __lasttoktyp = UNDEF;
819 return;
820
821 /* -- FIXME - ADD KEY (for now no key file)
822 -* first entry to interactive - open key file if possible *-
823 if (__key_fnam != NULL)
824 {
825 if ((__key_s = __tilde_fopen(__key_fnam, "w")) == NULL)
826 {
827 __ia_err(1414,
828 "cannot open -k interactive input key file %s - trying default",
829 __key_fnam);
830 __my_free(__key_fnam, strlen(__key_fnam) + 1);
831 __key_fnam = NULL;
832 goto no_explicit;
833 }
834 return;
835 }
836
837 no_explicit:
838 if ((__key_s = __tilde_fopen(DFLTKEYFNAM, "w")) == NULL)
839 {
840 __ia_err(1415, "cannot open default key file %s - no key file",
841 DFLTKEYFNAM);
842 return;
843 }
844 __key_fnam = __my_malloc(strlen(DFLTKEYFNAM) + 1);
845 strcpy(__key_fnam, DFLTKEYFNAM);
846 --- */
847 }
848
849 /*
850 * add a new entry to history queue - even if error entry must
851 * go in queue so can be edited
852 * this must be called after command read
853 *
854 * FIXME - ksh style editing not yet implemented
855 */
add_iahist(void)856 static void add_iahist(void)
857 {
858 struct iahist_t *iahp;
859
860 if (++__iah_lasti >= __iahsiz) grow_iahtab();
861 iahp = &(__iahtab[__iah_lasti]);
862 iahp->iah_lp = __pv_stralloc(__iahwrkline);
863 iahp->iah_hcp = NULL;
864 iahp->iah_itp = NULL;
865 }
866
867 /*
868 * check command number - message and F returned on error
869 * cannot use nd_ndxnum because no IS forms here and just need value
870 * notice both iahtab and command number start at 1 (0 unused)
871 */
get_iahcmdnum(void)872 static int32 get_iahcmdnum(void)
873 {
874 int32 base, cno;
875
876 if (__itoklen > WBITS)
877 {
878 if (!vval_is0_(&(__acwrk[1]), __itoklen - WBITS)
879 || !vval_is0_(__bcwrk, __itoklen))
880 {
881 base = BHEX;
882 prt_err:
883 __ia_err(1418, "command history number %s invalid or out of range",
884 __regab_tostr(__xs, __acwrk, __bcwrk, __itoklen, base, FALSE));
885 return(-1);
886 }
887 }
888 else
889 {
890 if (!vval_is0_(__bcwrk, __itoklen)) { base = BHEX; goto prt_err; }
891 }
892 cno = (int32) __acwrk[0];
893 if (cno < 1 || cno - 1 > __iah_lasti) { base = BDEC; goto prt_err; }
894 return(cno);
895 }
896
897 /*
898 * grow the interactive history table - no freeing and wrap for now
899 */
grow_iahtab(void)900 static void grow_iahtab(void)
901 {
902 register int32 i;
903 int32 old_iahsiz, osize, nsize;
904
905 old_iahsiz = __iahsiz;
906 osize = old_iahsiz*sizeof(struct iahist_t);
907 __iahsiz = (3*__iahsiz)/2;
908 nsize = __iahsiz*sizeof(struct iahist_t);
909 __iahtab = (struct iahist_t *) __my_realloc((char *) __iahtab, osize,
910 nsize);
911 for (i = old_iahsiz; i < __iahsiz; i++)
912 { __iahtab[i].iah_lp = NULL; __iahtab[i].iah_hcp = NULL; }
913 }
914 /*
915 * ROUTINES TO IMPLMENT VERILOG STATEMENT EXECUTION DEBUGGER
916 */
917
918 /* special external for setjmp environment - only used in v_ms.c */
919 jmp_buf __iact_jmpbuf;
920 jmp_buf __reset_jmpbuf;
921
922 /*
923 * read and execute a Verilog interactive statement
924 * errors here go into total but maybe should not
925 *
926 * must execute statement with delay as named block with no vars
927 */
rd_exec_iact_stmt(int32 hist_rexec)928 static void rd_exec_iact_stmt(int32 hist_rexec)
929 {
930 int32 sav_err_cnt, sav_sfnam_ind, sav_slin_cnt, immed_exec;
931 int32 sav_itspi, sav_st_trace, sfnind, slcnt, first_stmt;
932 struct st_t *stp, *stp2, *stp3;
933 struct iahist_t *iahp;
934 struct hctrl_t *hcp;
935
936 /* free any globals from immediate exec unless monitor/strobe sys task */
937 __iact_can_free = TRUE;
938
939 /* DBG remove -- */
940 if (__iact_dcehdr != NULL) __misc_terr(__FILE__, __LINE__);
941 /* --- */
942
943 sav_sfnam_ind = __sfnam_ind;
944 sav_slin_cnt = __slin_cnt;
945 __sfnam_ind = __cur_fnam_ind;
946 __slin_cnt = __lin_cnt;
947 sav_err_cnt = __pv_err_cnt;
948
949 /* on setup returns 0, if get here from call to long jump, all done */
950 if (setjmp(__iact_jmpbuf) != 0)
951 {
952 /* get here only on error - must skip and read token or macro vinstk */
953 /* will not be popped back to 0 */
954 for (;;) { if (__toktyp == TEOF) break; __get_vtok(); }
955 /* possible that parse error occured with something pushed back */
956 __lasttoktyp = UNDEF;
957 /* LOOKATME - may be minor memory leak for compound stmt with errors */
958 goto free_ds;
959 }
960 __iact_stmt_err = FALSE;
961 first_stmt = TRUE;
962 more_stmts:
963 /* if error almost certainly with go to setdump code */
964 /* unless undeclared problem */
965 if ((stp = __rd_stmt()) == NULL) { __iact_stmt_err = TRUE; goto free_ds; }
966
967 if (__pv_err_cnt != sav_err_cnt)
968 { __iact_stmt_err = TRUE; goto free_stmts_done; }
969
970 /* since know syntax good errors here, do not return */
971 __cur_tsk = NULL;
972 __iact_must_sched = FALSE;
973 __chk_lstofsts(stp);
974 if (__pv_err_cnt != sav_err_cnt)
975 { __iact_stmt_err = TRUE; goto free_stmts_done; }
976 __nbsti = -1;
977 __task_has_delay = FALSE;
978 __task_has_tskcall = FALSE;
979 /* $stop or any loop in interactive requires scheduling */
980 __chk_nodel_lstofsts(stp);
981 if (__pv_err_cnt != sav_err_cnt)
982 { __iact_stmt_err = TRUE; goto free_stmts_done; }
983 if (__task_has_delay || __task_has_tskcall || __iact_must_sched)
984 immed_exec = FALSE;
985 else immed_exec = TRUE;
986
987 /* notice always re-execing from history in current scope */
988 /* so to reenable an edge or change breakpoint user must insure either */
989 /* uses rooted names or scope is set to right place */
990 /* check and emit warning for non rooted interactive globals if from */
991 /* history re-exec since no way to tell if from same itree loc. */
992 chk_iact_grefs(hist_rexec);
993
994 /* delay times are tfmt time units not time unit from current scope */
995 __sav_mtime_units = __inst_mod->mtime_units;
996 __inst_mod->mtime_units = __tfmt_units;
997 /* rest of fields used from curr scope itree location */
998 __prpsti = 0;
999 __nbsti = -1;
1000 __prpstk[0] = NULL;
1001 __iact_dcehdr = NULL;
1002 stp = __prep_lstofsts(stp, FALSE, FALSE);
1003
1004 if (__pv_err_cnt != sav_err_cnt)
1005 {
1006 __iact_stmt_err = TRUE;
1007 free_stmts_done:
1008 /* interactive always exactly 1 inst. */
1009 if (__iact_can_free)
1010 {
1011 for (stp2 = stp; stp2 != NULL;)
1012 { stp3 = stp2->stnxt; __free_1stmt(stp2); stp2 = stp3; }
1013 }
1014 free_ds:
1015 /* SJM 01/02/03 - since never gening iops for interactive - ok because */
1016 /* only get here on error */
1017 if (__iact_can_free && __iact_dcehdr != NULL)
1018 {
1019 __free_dceauxlst(__iact_dcehdr, 1);
1020 __iact_dcehdr = NULL;
1021 }
1022
1023 if (__grwrknum > 0)
1024 {
1025 register int32 gri;
1026 int32 osize, nsize;
1027 struct gref_t *grp;
1028
1029 /* for monitor/strobe must add globals to iact mod table */
1030 if (__iact_can_free)
1031 {
1032 grp = &(__grwrktab[0]);
1033 for (gri = 0; gri < __grwrknum; gri++, grp++) __free_1glb_flds(grp);
1034 }
1035 else
1036 {
1037 /* need to copy grefs to iact module gr table so when interactive */
1038 /* scheduled statement executes can access grefs */
1039 if (__iact_mdp->mgrnum == 0)
1040 {
1041 __iact_mdp->mgrtab = (struct gref_t *)
1042 __my_malloc(__grwrknum*sizeof(struct gref_t));
1043 memcpy(__iact_mdp->mgrtab, __grwrktab,
1044 __grwrknum*sizeof(struct gref_t));
1045 }
1046 else
1047 {
1048 osize = __iact_mdp->mgrnum*sizeof(struct gref_t);
1049 nsize = (__iact_mdp->mgrnum + __grwrknum)*sizeof(struct gref_t);
1050 __iact_mdp->mgrtab = (struct gref_t *)
1051 __my_realloc((char *) __inst_mod->mgrtab, osize, nsize);
1052
1053 memcpy(&(__iact_mdp->mgrtab[__iact_mdp->mgrnum]), __grwrktab,
1054 __grwrknum*sizeof(struct gref_t));
1055 }
1056 __iact_mdp->mgrnum += __grwrknum;
1057 /* then fix up expr ptrs for all */
1058 grp = &(__iact_mdp->mgrtab[0]);
1059 for (gri = 0; gri < __iact_mdp->mgrnum; gri++, grp++)
1060 { grp->gxndp->ru.grp = grp; }
1061 }
1062 __grwrknum = 0;
1063 }
1064 goto done;
1065 }
1066
1067 if (immed_exec)
1068 {
1069 /* DBG remove -- */
1070 if (__iact_dcehdr != NULL) __misc_terr(__FILE__, __LINE__);
1071 /* --- */
1072
1073 if (__history_on && !hist_rexec && first_stmt) add_iahist();
1074 /* in case exit with ^c (infinite loop?) restore entry itree loc. */
1075 sav_itspi = __itspi;
1076 /* must never trace immediate debugger commands */
1077 sav_st_trace = __st_tracing;
1078 __st_tracing = FALSE;
1079 /* notice normally no thread while in interactive mode */
1080 __cur_thd = bld_immed_iathrd(stp);
1081 __cur_thd->th_itp = __scope_ptr;
1082 for (;;)
1083 {
1084 stp = __brktr_exec_1stmt(stp);
1085 if (stp == NULL) break;
1086 if (__pending_enter_iact)
1087 {
1088 __cvsim2_msg(
1089 "\nInterrupt (^C) during immediate interactive execution, reenter debugger? (y/n) ");
1090 if (fgets(__xs, RECLEN, stdin) != NULL
1091 && (__xs[0] == 'y' || __xs[0] == 'Y'))
1092 {
1093 __pending_enter_iact = FALSE;
1094 /* may be executing xmr func. when ^c hit */
1095 __itspi = sav_itspi;
1096 break;
1097 }
1098 }
1099 }
1100 __st_tracing = sav_st_trace;
1101 /* DBG remove --- */
1102 if (__cur_thd == NULL) __misc_terr(__FILE__, __LINE__);
1103 /* ---*/
1104 /* notice thread just used as dummy place holder so nothing used */
1105 __my_free((char *) __cur_thd, sizeof(struct thread_t));
1106 __cur_thd = NULL;
1107 goto free_stmts_done;
1108 }
1109
1110 /* build and link on to history list the ia statement */
1111 hcp = (struct hctrl_t *) __my_malloc(sizeof(struct hctrl_t));
1112 init_iahctrl(hcp);
1113
1114 sfnind = __cmd_ifi;
1115 if (hist_rexec)
1116 {
1117 iahp = &(__iahtab[__lin_cnt]);
1118 hcp->hc_lini = __lin_cnt;
1119 iahp->iah_hcp = hcp;
1120 hcp->hc_ifi = __cmd_ifi;
1121 hcp->hc_iahp = iahp;
1122 slcnt = __lin_cnt;
1123 }
1124 else if (__history_on)
1125 {
1126 add_iahist();
1127 iahp = &(__iahtab[__iah_lasti]);
1128 hcp->hc_lini = __iah_lasti;
1129 iahp->iah_hcp = hcp;
1130 hcp->hc_ifi = __cmd_ifi;
1131 hcp->hc_iahp = iahp;
1132 slcnt = __iah_lasti;
1133 }
1134 else slcnt = 1;
1135
1136 /* always put on end of doubly linked list */
1137 renumber_1stmt(stp, sfnind, slcnt);
1138
1139 hcp->hc_stp = stp;
1140 hcp->hc_itp = __scope_ptr;
1141 if (__hctrl_hd == NULL) __hctrl_hd = __hctrl_end = hcp;
1142 else
1143 {
1144 __hctrl_end->hc_nxt = hcp;
1145 hcp->hc_prev = __hctrl_end;
1146 __hctrl_end = hcp;
1147 }
1148 hcp->hc_dcelst = __iact_dcehdr;
1149 __iact_dcehdr = NULL;
1150
1151 /* allocate new gref table for later use if command in history list execed */
1152 /* only freed if statement removed from history list */
1153 if (__grwrknum > 0)
1154 {
1155 hcp->hc_grtab = __alloc_grtab(__grwrktab, __grwrknum);
1156 hcp->hc_numglbs = __grwrknum;
1157 __grwrknum = 0;
1158 }
1159
1160 init_sched_iathd(hcp);
1161
1162 done:;
1163 if (!__iact_stmt_err && !__chk_extra_atend(FALSE))
1164 {
1165 first_stmt = FALSE;
1166 __get_vtok();
1167 /* DBG remove --- */
1168 if (__toktyp == TEOF) __misc_terr(__FILE__, __LINE__);
1169 /* --- */
1170 goto more_stmts;
1171 }
1172 /* only way to exit exec iact stmt routine */
1173 __inst_mod->mtime_units = __sav_mtime_units;
1174 __sfnam_ind = sav_sfnam_ind;
1175 __slin_cnt = sav_slin_cnt;
1176 }
1177
1178 /*
1179 * check all xmr's from this statement
1180 */
chk_iact_grefs(int32 hist_rexec)1181 static void chk_iact_grefs(int32 hist_rexec)
1182 {
1183 register int32 gri;
1184 register struct gref_t *grp;
1185
1186 grp = &(__grwrktab[0]);
1187 for (gri = 0; gri < __grwrknum; gri++, grp++)
1188 {
1189 if (grp->gr_gone || grp->gr_err) continue;
1190 if (hist_rexec)
1191 {
1192 if (!grp->is_rooted)
1193 {
1194 __ia_warn(1601,
1195 "statement has non rooted global %s - scope instance %s may differ from original",
1196 grp->gnam, __msg2_blditree(__xs, __inst_ptr));
1197 }
1198 }
1199 }
1200 }
1201
1202 /*
1203 * initialize an history suspended statement record
1204 */
init_iahctrl(struct hctrl_t * hcp)1205 static void init_iahctrl(struct hctrl_t *hcp)
1206 {
1207 hcp->hc_stp = NULL;
1208 hcp->hc_thp = NULL;
1209 hcp->hc_itp = NULL;
1210 hcp->hc_lini = 0;
1211 hcp->hc_ifi = 0;
1212 hcp->hc_nxt = hcp->hc_prev = NULL;
1213 hcp->hc_iahp = NULL;
1214 hcp->hc_dcelst = NULL;
1215 hcp->hc_grtab = NULL;
1216 hcp->hc_numglbs = 0;
1217 }
1218
1219 /*
1220 * build the interactive statement thread and schedule event
1221 * this runs in current interactive scope itp
1222 * when finishes just terminates like any other thread - maybe in 0 time
1223 */
init_sched_iathd(struct hctrl_t * hcp)1224 static void init_sched_iathd(struct hctrl_t *hcp)
1225 {
1226 struct thread_t *thp;
1227 i_tev_ndx tevpi;
1228
1229 /* allocate thread and event and fill links */
1230 alloc_tev_(tevpi, TE_THRD, hcp->hc_itp, __simtime);
1231 thp = __alloc_thrd();
1232 thp->th_hctrl = hcp;
1233 thp->thdtevi = tevpi;
1234 thp->thenbl_sfnam_ind = __cmd_ifi;
1235 thp->thenbl_slin_cnt = __iah_lasti;
1236 thp->th_itp = hcp->hc_itp;
1237 __tevtab[tevpi].tu.tethrd = thp;
1238 thp->thnxtstp = hcp->hc_stp;
1239 thp->thpar = NULL;
1240 hcp->hc_thp = thp;
1241
1242 /* here can just add to front of event list - best to get started */
1243 /* LOOKATME - notice no longer need to add to front - just more coherent */
1244 __add_ev_to_front(tevpi);
1245 }
1246
1247 /*
1248 * for immediate exec, allocate and set dummy current thread
1249 */
bld_immed_iathrd(struct st_t * stp)1250 static struct thread_t *bld_immed_iathrd(struct st_t *stp)
1251 {
1252 struct thread_t *thp;
1253
1254 thp = __alloc_thrd();
1255 thp->thenbl_sfnam_ind = __cmd_ifi;
1256 thp->thenbl_slin_cnt = __iah_lasti;
1257 thp->thnxtstp = stp;
1258 thp->thpar = NULL;
1259 return(thp);
1260 }
1261
1262 /*
1263 * free iact globals
1264 * notice caller sets iact gref table to empty
1265 */
free_iact_glbs(struct gref_t * grtab,int32 grnum)1266 static void free_iact_glbs(struct gref_t *grtab, int32 grnum)
1267 {
1268 register int32 gri;
1269 register struct gref_t *grp;
1270
1271 for (gri = 0, grp = &(grtab[0]); gri < grnum; gri++, grp++)
1272 { __free_1glb_flds(grp); }
1273 __my_free((char *) grtab, grnum*sizeof(struct gref_t));
1274 }
1275
1276 /*
1277 * free a list dce's (for monit/fmonit, qcaf and tf_ parameter change)
1278 * if optimized sim on and no syntax error, nd regen T else F
1279 * only called when free interactive dce list vpi_ call back lists
1280 *
1281 * caller may need to set header to nil
1282 * this works (does nothing) if called with nil dcehdr
1283 * LOOKATME - if doubly linked would be faster
1284 *
1285 * SJM 06/21/02 - now only PLI and reset call this to remove from dce list
1286 * LOOKATME - think assuming trigger set to regen iops called
1287 *
1288 * SJM 12/30/02 - must not call this routine except on interactive debugger
1289 * syntax error if -O on
1290 *
1291 * LOOKATME - here removing monit dce's because only freed if added
1292 * from interactive mode
1293 */
__free_dceauxlst(struct dceauxlst_t * dcehdr,int32 numinsts)1294 extern void __free_dceauxlst(struct dceauxlst_t *dcehdr, int32 numinsts)
1295 {
1296 register struct dceauxlst_t *dclp;
1297 register struct dcevnt_t *dcep2;
1298 struct dcevnt_t *dcep, *last_dcep;
1299 struct net_t *np;
1300
1301 /* DBG remove -- must not call if -O used */
1302 if (__optimized_sim) __misc_terr(__FILE__, __LINE__);
1303 /* -- */
1304
1305 /* remove all dc events that were added for this delay control event */
1306 for (dclp = dcehdr; dclp != NULL; dclp = dclp->dclnxt)
1307 {
1308 /* get the dce to free */
1309 dcep = dclp->ldcep;
1310
1311 /* since list not doubly linked must search thru list saving last */
1312 /* BEWARE - except for dmpv on front removable dces can be put anywhere */
1313 /* on list so can not optimize this */
1314 np = dcep->dce_np;
1315
1316 last_dcep = NULL;
1317 for (dcep2 = np->dcelst; dcep2 != NULL; dcep2 = dcep2->dcenxt)
1318 {
1319 if (dcep == dcep2)
1320 {
1321 if (last_dcep == NULL)
1322 {
1323 np->dcelst = dcep->dcenxt;
1324 /* SJM - 06/30/00 - dce list now empty - deactivate ev ctrl wakeups */
1325 /* LOOKATME - can this really ever happen */
1326 if (np->dcelst == NULL)
1327 {
1328 /* SJM 07/24/00 - may be off if reg - turning off again ok */
1329 np->nchg_has_dces = FALSE;
1330 if (np->nlds == NULL && !np->n_hasdvars)
1331 np->nchg_nd_chgstore = FALSE;
1332 /* notice do not use all changed always on optimization here */
1333 }
1334 }
1335 else last_dcep->dcenxt = dcep->dcenxt;
1336
1337 /* now that linked out, can regen net's list */
1338 /* for XMR, may need to move to different mod */
1339 /* if remove last, still regen to free and does not stop recording */
1340
1341 /* if no dce value, does nothing */
1342 __free_dce_prevval(dcep, numinsts, __get_dcewid(dcep, np));
1343
1344 /* SJM 10/06/06 - if free dce aux list, called from a vpi cb value */
1345 /* change and the a freed dce is the same as the one that caused the */
1346 /* value chg user c routine to run, must indicate the one dce */
1347 /* that caused the cbvc callback to be called has been freed */
1348 if (dcep == __cbvc_causing_dcep) __cbvc_causing_dcep = NULL;
1349
1350 __my_free((char *) dcep, sizeof(struct dcevnt_t));
1351 dcep = NULL;
1352 goto nxt_dce;
1353 }
1354 last_dcep = dcep2;
1355 }
1356 __misc_terr(__FILE__, __LINE__);
1357 nxt_dce:;
1358 }
1359 /* finally free the dce list - know dce of element already freed */
1360 __free_dceauxs_only(dcehdr);
1361 }
1362
1363 /*
1364 * free a dce list - know dce of each element already freed
1365 */
__free_dceauxs_only(struct dceauxlst_t * dcehdr)1366 extern void __free_dceauxs_only(struct dceauxlst_t *dcehdr)
1367 {
1368 register struct dceauxlst_t *dclp, *dclp2;
1369
1370 for (dclp = dcehdr; dclp != NULL;)
1371 {
1372 dclp2 = dclp->dclnxt;
1373 __my_free((char *) dclp, sizeof(struct dceauxlst_t));
1374 dclp = dclp2;
1375 }
1376 }
1377
1378 /*
1379 * free a dce previous value field
1380 * if none, does nothing
1381 */
__free_dce_prevval(struct dcevnt_t * dcep,int32 insts,int32 dcewid)1382 extern void __free_dce_prevval(struct dcevnt_t * dcep, int32 insts, int32 dcewid)
1383 {
1384 int32 totchars;
1385 struct net_t *np;
1386
1387 /* SJM 05/05/03 - for rooted XMR dce - only 1 inst allocated */
1388 if (dcep->dce_1inst) insts = 1;
1389 if (dcep->dce_expr != NULL && dcep->dce_expr->mast_dcep == dcep)
1390 {
1391 totchars = __get_pcku_chars(dcewid, insts);
1392 __my_free((char *) dcep->dce_expr->bp, totchars);
1393 dcep->dce_expr->bp = NULL;
1394 }
1395
1396 /* if dce on array or entire non wire (reg), will not have saved val. */
1397 if (dcep->prevval.wp == NULL) return;
1398
1399 np = dcep->dce_np;
1400 if (np->n_stren) totchars = dcewid*insts;
1401 else totchars = __get_pcku_chars(dcewid, insts);
1402 __my_free((char *) dcep->prevval.bp, totchars);
1403 dcep->prevval.bp = NULL;
1404 }
1405
1406 /*
1407 * ROUTINES TO RENUMBER STATEMENTS
1408 */
1409
1410 /*
1411 * renumber a statement - for use when adding to commnd history
1412 * statement can be head of compound
1413 */
renumber_1stmt(struct st_t * stp,int32 sfnind,int32 slcnt)1414 static void renumber_1stmt(struct st_t *stp, int32 sfnind, int32 slcnt)
1415 {
1416 int32 fji;
1417 struct for_t *frp;
1418 struct st_t *fjstp;
1419
1420 if (stp == NULL) return;
1421
1422 /* always set statement body line */
1423 stp->stfnam_ind = (word32) sfnind;
1424 stp->stlin_cnt = slcnt;
1425
1426 switch ((byte) stp->stmttyp) {
1427 /* simple statement just set number */
1428 case S_NULL: case S_STNONE:
1429 case S_PROCA: case S_FORASSGN: case S_RHSDEPROCA: case S_NBPROCA:
1430 case S_TSKCALL: case S_QCONTA: case S_QCONTDEA: case S_CAUSE:
1431 case S_DSABLE: case S_REPSETUP: case S_REPDCSETUP: case S_GOTO:
1432 break;
1433 case S_IF:
1434 renumber_stlst(stp->st.sif.thenst, sfnind, slcnt);
1435 renumber_stlst(stp->st.sif.elsest, sfnind, slcnt);
1436 break;
1437 case S_CASE:
1438 /* first always default or place holder for missing default */
1439 renumber_csitemlst(stp->st.scs.csitems->csinxt, sfnind, slcnt);
1440 /* if has default, know has default statement */
1441 if (stp->st.scs.csitems->csist != NULL)
1442 renumber_stlst(stp->st.scs.csitems->csist, sfnind, slcnt);
1443 break;
1444 case S_REPEAT:
1445 renumber_stlst(stp->st.srpt.repst, sfnind, slcnt);
1446 break;
1447 case S_FOREVER:
1448 case S_WHILE:
1449 renumber_stlst(stp->st.swh.lpst, sfnind, slcnt);
1450 break;
1451 case S_WAIT:
1452 /* LOOKATME - is there a action statement that needs to be renumbered */
1453 renumber_stlst(stp->st.swait.lpst, sfnind, slcnt);
1454 break;
1455 case S_FOR:
1456 frp = stp->st.sfor;
1457 /* notice for assign already freed */
1458 renumber_1stmt(frp->forinc, sfnind, slcnt);
1459 renumber_stlst(frp->forbody, sfnind, slcnt);
1460 break;
1461 case S_DELCTRL:
1462 if (stp->st.sdc->actionst != NULL)
1463 renumber_stlst(stp->st.sdc->actionst, sfnind, slcnt);
1464 break;
1465 case S_UNBLK:
1466 renumber_stlst(stp->st.sbsts, sfnind, slcnt);
1467 break;
1468 case S_UNFJ:
1469 /* renumber statement ptr table each of which may be st list */
1470 for (fji = 0;; fji++)
1471 {
1472 if ((fjstp = stp->st.fj.fjstps[fji]) == NULL) break;
1473 renumber_stlst(fjstp, sfnind, slcnt);
1474 }
1475 break;
1476 /* notice named block non freeable (at least for now) */
1477 default: __case_terr(__FILE__, __LINE__);
1478 }
1479 }
1480
1481 /*
1482 * renumber case item list statements
1483 */
renumber_csitemlst(register struct csitem_t * csip,int32 sfnind,int32 slcnt)1484 static void renumber_csitemlst(register struct csitem_t *csip, int32 sfnind,
1485 int32 slcnt)
1486 {
1487 for (;csip != NULL; csip = csip->csinxt)
1488 { renumber_stlst(csip->csist, sfnind, slcnt); }
1489 }
1490
1491 /*
1492 * renumber each statement of a list to same history statement list number
1493 */
renumber_stlst(register struct st_t * stp,int32 sfnind,int32 slcnt)1494 static void renumber_stlst(register struct st_t *stp, int32 sfnind, int32 slcnt)
1495 {
1496 for (; stp != NULL; stp = stp->stnxt) renumber_1stmt(stp, sfnind, slcnt);
1497 }
1498
1499 /*
1500 * INTERACTIVE COMMAND EXECUTION ROUTINES
1501 */
1502
1503 /*
1504 * escape from debugging environment to unix shell
1505 * for now no system task - can use $input
1506 *
1507 * know interactive environment always run with SIG_IGN but shell needs
1508 * default so ^c get out of shell
1509 */
__escape_to_shell(char * argchp)1510 extern void __escape_to_shell(char *argchp)
1511 {
1512 int32 rc, status, pid;
1513 char *chp, *usersh;
1514
1515 /* signal(SIGINT, SIG_DFL); */
1516
1517 if ((usersh = (char *) getenv ("SHELL")) == NULL) usersh = "/bin/sh";
1518 if ((chp = strrchr(usersh, '/')) == NULL) chp = usersh; else chp++;
1519 if ((pid = fork()) == 0)
1520 {
1521 if (*argchp == '\0') execl(usersh, chp, (char *) 0);
1522 else execl(usersh, chp, "-c", argchp, (char *) 0);
1523 if (__iact_state)
1524 __ia_err(983, "OS Failure - user shell escape execl system call failed");
1525 else __sgferr(983,
1526 "OS Failure - user shell escape execl system call failed");
1527 return;
1528 }
1529 if (pid != -1) { while ((rc = wait(&status)) != pid && rc != -1) ; }
1530 else
1531 {
1532 if (__iact_state)
1533 __ia_err(983, "OS Failure - user shell escape fork system call failed");
1534 else __sgferr(983,
1535 "OS Failure - user shell escape fork system call failed");
1536 }
1537 /* need to enable sim sigint32 handler even if called from :shell */
1538 /* ---
1539 #if defined(INTSIGS)
1540 signal(SIGINT, __sim_sigint_handler);
1541 #else
1542 signal(SIGINT, (void (*)()) __sim_sigint_handler);
1543 #endif
1544 --- */
1545 }
1546
1547 /*
1548 * exec the $input for interactive command input source system task
1549 * here open cmd file and closes previous - new file is chained not nested
1550 * if this appears in source, just change for next time enter interactive
1551 */
__exec_input_fnamchg(struct expr_t * axp)1552 extern void __exec_input_fnamchg(struct expr_t *axp)
1553 {
1554 int32 slen;
1555 FILE *tmp_s;
1556 char *chp;
1557
1558 /* msgexpr uses __exprline but if error not filled anyway */
1559 chp = __get_eval_cstr(axp->lu.x, &slen);
1560 if ((tmp_s = __tilde_fopen(chp, "r")) == NULL)
1561 {
1562 __sgferr(1241, "cannot open $input interactive command file %s", chp);
1563 goto done;
1564 }
1565 if (__cmd_s != NULL) __my_fclose(__cmd_s);
1566 __cmd_s = tmp_s;
1567 if (feof(__cmd_s))
1568 {
1569 __sgfwarn(610, "$input interactive command file %s empty", chp);
1570 /* here just go back to stdin */
1571 __cmd_s = NULL;
1572 __cmd_fnam = NULL;
1573 __cur_fnam = __in_fils[1];
1574 __cur_fnam_ind = __cmd_ifi;
1575 __lin_cnt = __iah_lasti;
1576 goto done;
1577 }
1578 __add_infil(chp);
1579 __cur_fnam_ind = __last_inf;
1580 __cmd_fnam = __in_fils[__cur_fnam_ind];
1581 __lin_cnt = 0;
1582 if (__verbose)
1583 __cv_msg(" Reading interactive commands from file \"%s\".\n", __cur_fnam);
1584
1585 done:
1586 __my_free(chp, slen + 1);
1587 }
1588
1589 /*
1590 * execute the $history list system task
1591 * extension allows optional number (how many to list) arg
1592 * prompt after 20 lines (including embedded new lines) except finish
1593 */
__exec_history_list(int32 num)1594 extern void __exec_history_list(int32 num)
1595 {
1596 register int32 i;
1597 int32 h_start, nlines;
1598 char s1[RECLEN];
1599
1600 if (num == 0) h_start = 1;
1601 else { if ((h_start = __iah_lasti - num + 1) <= 1) h_start = 1; }
1602 for (nlines = 0, i = h_start; i <= __iah_lasti; i++)
1603 {
1604 nlines += prt1_iahist_cmd(i);
1605 if (nlines > __hist_cur_listnum)
1606 {
1607 nlines = 0;
1608 __cvsim2_msg("Press return to continue:");
1609 fgets(s1, RECLEN, stdin);
1610 }
1611 }
1612 }
1613
1614 /*
1615 * print one history entry - may be muliple line (with embedded new lines)
1616 * returns number of lines listed (for mulitple line)
1617 */
prt1_iahist_cmd(int32 iahi)1618 static int32 prt1_iahist_cmd(int32 iahi)
1619 {
1620 int32 first_time, prmplen, numlines;
1621 struct iahist_t *iahp;
1622 char c, save_ch, *chp, *chp2, s1[RECLEN];
1623
1624 numlines = 1;
1625 iahp = &(__iahtab[iahi]);
1626 /* notice when non immediate statement finishes, disable turned on */
1627 if (iahp->iah_hcp != NULL) c = '*'; else c = ' ';
1628 sprintf(s1, "C%d%c ", iahi, c);
1629 __cvsim_msg(s1);
1630
1631 prmplen = strlen(s1);
1632 __blnkline[prmplen] = '\0';
1633 for (chp = iahp->iah_lp, first_time = TRUE;;)
1634 {
1635 if ((chp2 = strchr(chp, '\\')) != NULL)
1636 {
1637 chp2++;
1638 if (*chp2 == '\n')
1639 {
1640 chp2++;
1641 save_ch = *chp2;
1642 *chp2 = '\0';
1643 /* notice this has the \\\n */
1644 if (first_time) { __cvsim_msg("%s", chp); first_time = FALSE; }
1645 else __cvsim_msg("%s%s", __blnkline, chp);
1646 *chp2 = save_ch;
1647 chp = chp2;
1648 numlines++;
1649 continue;
1650 }
1651 }
1652 /* notice no ending \n */
1653 if (first_time) __cvsim_msg("%s\n", chp);
1654 else __cvsim_msg("%s%s\n", __blnkline, chp);
1655 break;
1656 }
1657 __blnkline[prmplen] = ' ';
1658 return(numlines);
1659 }
1660
1661 /*
1662 * ROUTINES FOR INTERACTIVE DISABLE AND THREAD FREEING
1663 */
1664
1665 /*
1666 * exec disable of interactive thread
1667 * this disables and free entire statement
1668 */
__do_iact_disable(struct hctrl_t * hcp,int32 lv_ctrl)1669 extern void __do_iact_disable(struct hctrl_t *hcp, int32 lv_ctrl)
1670 {
1671 struct thread_t *thp;
1672
1673 thp = hcp->hc_thp;
1674 /* if any active down threads, task enables or fjs - free/disable all */
1675 if (thp->thofs != NULL) __free_thd_list(thp->thofs);
1676 free_done_iact_control(hcp, lv_ctrl);
1677 thp->th_dctp = NULL;
1678 /* thread frees cancel any pending events - no parent */
1679 __free_1thd(thp);
1680 }
1681
1682 /*
1683 * remove interactive thread and statement list
1684 *
1685 * also removes any globals associated with statement
1686 */
free_done_iact_control(struct hctrl_t * hcp,int32 lv_ctrl)1687 static void free_done_iact_control(struct hctrl_t *hcp, int32 lv_ctrl)
1688 {
1689 register struct st_t *stp;
1690 struct st_t *stp2;
1691
1692 /* free statements, if reenbled must parse again */
1693 __push_wrkitstk(__iact_mdp, 0);
1694 for (stp = hcp->hc_stp; stp != NULL;)
1695 { stp2 = stp->stnxt; __free_1stmt(stp); stp = stp2; }
1696 /* free any dces - know only 1 iact inst. */
1697 if (hcp->hc_dcelst != NULL)
1698 {
1699 /* know can only be called once sim started SIM STATE */
1700 __free_dceauxlst(hcp->hc_dcelst, 1);
1701 /* but always remove from list */
1702 hcp->hc_dcelst = NULL;
1703 }
1704 if (hcp->hc_numglbs > 0)
1705 {
1706 free_iact_glbs(hcp->hc_grtab, hcp->hc_numglbs);
1707 hcp->hc_grtab = NULL;
1708 hcp->hc_numglbs = 0;
1709 }
1710 __pop_wrkitstk();
1711
1712 /* thread freed by caller, lv ctrl when all freed at once above */
1713 if (!lv_ctrl)
1714 {
1715 if (hcp->hc_nxt != NULL) hcp->hc_nxt->hc_prev = hcp->hc_prev;
1716 else
1717 {
1718 __hctrl_end = hcp->hc_prev;
1719 if (__hctrl_end != NULL) __hctrl_end->hc_nxt = NULL;
1720 }
1721 if (hcp->hc_prev != NULL) hcp->hc_prev->hc_nxt = hcp->hc_nxt;
1722 else
1723 {
1724 __hctrl_hd = hcp->hc_nxt;
1725 if (__hctrl_hd != NULL) __hctrl_hd->hc_prev = NULL;
1726 }
1727 }
1728
1729 /* if on history, free and mark inactive */
1730 if (hcp->hc_iahp != NULL) hcp->hc_iahp->iah_hcp = NULL;
1731 if (!lv_ctrl) __my_free((char *) hcp, sizeof(struct hctrl_t));
1732 }
1733
1734 /*
1735 * ROUTINES TO IMPLEMENTED EXTENDED : DEBUGGER COMMANDS
1736 */
1737
1738 /* table of debugger commands values */
1739 #define DB_HELP 0
1740 #define DB_SH 1
1741 #define DB_QUIT 2
1742 #define DB_WHERE 3
1743 #define DB_PRINT 4
1744 #define DB_RESET 5
1745 #define DB_EXPRIS 6
1746 #define DB_VARIS 7
1747 #define DB_WHATIS 8
1748 #define DB_LIST 9
1749 #define DB_SET 10
1750 #define DB_INFO 11
1751 #define DB_SCOPE 12
1752 #define DB_BRKPT 13
1753 #define DB_IBRKPT 14
1754 #define DB_DELBRKDIS 15
1755 #define DB_BPDIS_ENABLE 16
1756 #define DB_BPDIS_DISABLE 17
1757 #define DB_STEP 18
1758 #define DB_ISTEP 19
1759 #define DB_HIST 20
1760 #define DB_EMPTHIST 21
1761 #define DB_DISPLAY 22
1762 #define DB_UNDISPLAY 23
1763 #define DB_TBRKPT 24
1764 #define DB_TIBRKPT 25
1765 #define DB_IGNORE 26
1766 #define DB_COND 27
1767 #define DB_SNAPSHOT 28
1768 #define DB_NEXTB 29
1769
1770 /* debugger command name table (unordered) */
1771 static struct namlst_t dbcmds[] = {
1772 { DB_HELP, ":help" },
1773 { DB_SH, ":shell" },
1774 { DB_QUIT, ":quit" },
1775 { DB_WHERE, ":where" },
1776 { DB_PRINT, ":print" },
1777 { DB_RESET, ":reset" },
1778 { DB_EXPRIS, ":expris" },
1779 { DB_VARIS, ":varis" },
1780 { DB_WHATIS, ":whatis" },
1781 { DB_LIST, ":list" },
1782 { DB_SET, ":set" },
1783 { DB_INFO, ":info" },
1784 { DB_SCOPE, ":scope" },
1785 { DB_BRKPT, ":breakpoint" },
1786 { DB_IBRKPT, ":ibreakpoint" },
1787 { DB_DELBRKDIS, ":delete" },
1788 { DB_BPDIS_ENABLE, ":enable" },
1789 { DB_BPDIS_DISABLE, ":disabl" },
1790 { DB_STEP, ":step" },
1791 { DB_ISTEP, ":istep" },
1792 { DB_HIST, ":history" },
1793 { DB_EMPTHIST, ":emptyhistory" },
1794 { DB_DISPLAY, ":display" },
1795 { DB_UNDISPLAY, ":undisplay" },
1796 { DB_TBRKPT, ":tbreakpoint" },
1797 { DB_TIBRKPT, ":tibreakpoint" },
1798 { DB_IGNORE, ":ignore" },
1799 { DB_COND, ":cond" },
1800 { DB_SNAPSHOT, ":snapshot" },
1801 { DB_NEXTB, ":nextb" }
1802 };
1803 #define NDBCMDS (sizeof(dbcmds) / sizeof(struct namlst_t))
1804
1805 /*
1806 * process a colon command
1807 *
1808 * this must handle history updating - returns F on exit interactive
1809 * know : followed by non white space to get here and command token read
1810 */
do_dbg_cmd(void)1811 static int32 do_dbg_cmd(void)
1812 {
1813 int32 rv, tmp;
1814 char s1[IDLEN];
1815
1816 if (__toktyp != ID)
1817 {
1818 sprintf(s1, ":%s", __prt_vtok());
1819 bad_colon_cmd:
1820 __ia_err(1421, "undefined extended :[command] debugger command %s", s1);
1821 return(TRUE);
1822 }
1823
1824 strcpy(s1, ":");
1825 strcat(s1, __token);
1826
1827 rv = __get_dbcmdnum(s1, dbcmds, NDBCMDS);
1828 switch (rv) {
1829 case -1: goto bad_colon_cmd;
1830 case -2:
1831 __ia_err(1422, "%s ambiguous debugger command: %s", s1,
1832 __bld_ambiguous_list(__xs, s1, dbcmds, NDBCMDS));
1833 break;
1834 case DB_HELP:
1835 do_dbg_help();
1836 chk_end:
1837 __chk_extra_atend(TRUE);
1838 break;
1839 case DB_SH:
1840 if (__cmd_s != NULL)
1841 {
1842 __ia_err(1424,
1843 "debugger shell escape cannot be invoked from $input file");
1844 break;
1845 }
1846 /* must pass rest of line */
1847 __escape_to_shell(__visp->vichp);
1848 break;
1849 case DB_QUIT:
1850 __chk_extra_atend(TRUE);
1851
1852 if (__tfrec_hdr != NULL) __call_misctfs_finish();
1853 if (__have_vpi_actions) __vpi_endsim_trycall();
1854 __my_exit(0, TRUE);
1855 case DB_WHERE:
1856 /* write the trace back using suspended thread */
1857 if (__suspended_thd == NULL)
1858 __ia_err(1496,
1859 ":where failed - no procedural context, single step and try again");
1860 else
1861 {
1862 __cvsim_msg("Procedural thread trace back:\n");
1863 __prt_where_msg(__suspended_thd);
1864 }
1865 goto chk_end;
1866 case DB_SNAPSHOT:
1867 __write_snapshot(5);
1868 goto chk_end;
1869 case DB_PRINT:
1870 dbg_print();
1871 break;
1872 case DB_RESET:
1873 /* here do not change reset count or value and only enter interactive */
1874 __get_vtok();
1875 __dbg_stop_before = 100;
1876 if (__toktyp != TEOF)
1877 {
1878 if (__toktyp == ID && (strcmp(__token, "s") == 0
1879 || strcmp(__token, "st") == 0 || strcmp(__token, "sto") == 0
1880 || strcmp(__token, "stop") == 0)) __dbg_stop_before = 101;
1881 else
1882 {
1883 __ia_err(1486, ":reset command argument %s not expected s or stop",
1884 __prt_vtok());
1885 }
1886 }
1887 __cvsim2_msg("Simulation begun, really reset to start over? (y/n) ");
1888 if (fgets(s1, RECLEN, stdin) == NULL || (s1[0] != 'y' && s1[0] != 'Y'))
1889 break;
1890 /* leaving interactive - and go back to compile ^c handler */
1891 __iact_state = FALSE;
1892 /* reenable the normal ^c signal handler */
1893 #if defined(INTSIGS)
1894 signal(SIGINT, __comp_sigint_handler);
1895 #else
1896 signal(SIGINT, (void (*)()) __comp_sigint_handler);
1897 #endif
1898 __pop_itstk();
1899 __reset_count--;
1900 longjmp(__reset_jmpbuf, 1);
1901 break;
1902 case DB_EXPRIS:
1903 do_dbg_expris();
1904 break;
1905 case DB_VARIS:
1906 do_dbg_varis();
1907 break;
1908 case DB_WHATIS:
1909 do_dbg_whatis();
1910 break;
1911 case DB_LIST:
1912 __do_dbg_list();
1913 break;
1914 case DB_SET:
1915 __do_dbg_set();
1916 break;
1917 case DB_INFO:
1918 __do_dbg_info();
1919 break;
1920 case DB_SCOPE:
1921 __do_dbg_scope();
1922 break;
1923 case DB_BRKPT:
1924 if (__optimized_sim)
1925 {
1926 /* SJM 02/03/03 - breakpoint commands illegal if optimizer on */
1927 cmd_illegal_msg(s1);
1928 break;
1929 }
1930 __do_dbg_brkpt(FALSE);
1931 break;
1932 case DB_TBRKPT:
1933 if (__optimized_sim)
1934 {
1935 /* SJM 02/03/03 - breakpoint commands illegal if optimizer on */
1936 cmd_illegal_msg(s1);
1937 break;
1938 }
1939 __do_dbg_brkpt(TRUE);
1940 break;
1941 case DB_IBRKPT:
1942 if (__optimized_sim)
1943 {
1944 /* SJM 02/03/03 - breakpoint commands illegal if optimizer on */
1945 cmd_illegal_msg(s1);
1946 break;
1947 }
1948 __do_dbg_ibrkpt(FALSE);
1949 break;
1950 case DB_TIBRKPT:
1951 if (__optimized_sim)
1952 {
1953 /* SJM 02/03/03 - breakpoint commands illegal if optimizer on */
1954 cmd_illegal_msg(s1);
1955 break;
1956 }
1957 __do_dbg_ibrkpt(TRUE);
1958 break;
1959 case DB_NEXTB:
1960 if (__optimized_sim)
1961 {
1962 /* SJM 02/03/03 - breakpoint commands illegal if optimizer on */
1963 cmd_illegal_msg(s1);
1964 break;
1965 }
1966 if (!__do_dbg_nextb()) return(FALSE);
1967 break;
1968 case DB_DELBRKDIS:
1969 __do_dbg_delbrkdis();
1970 break;
1971 case DB_BPDIS_DISABLE:
1972 __do_dbg_dis_enable(FALSE);
1973 break;
1974 case DB_BPDIS_ENABLE:
1975 __do_dbg_dis_enable(TRUE);
1976 break;
1977 case DB_DISPLAY:
1978 dbg_display();
1979 break;
1980 case DB_UNDISPLAY:
1981 __dbg_undisplay();
1982 break;
1983 case DB_STEP:
1984 __get_vtok();
1985 if (__toktyp == TEOF) __step_rep_cnt = 1;
1986 else
1987 {
1988 if ((tmp = __get_dbg_val()) == -1 || tmp < 1)
1989 {
1990 __ia_err(1470, ":istep command repeat count %s illegal", __prt_vtok());
1991 break;
1992 }
1993 __step_rep_cnt = tmp;
1994 }
1995 __single_step = TRUE;
1996 __verbose_step = TRUE;
1997 if (__iact_reason == IAER_CTRLC || __suspended_thd == NULL
1998 || __suspended_thd->thnxtstp == NULL) __step_from_thread = FALSE;
1999 __chk_extra_atend(TRUE);
2000 return(FALSE);
2001 case DB_ISTEP:
2002 if (__optimized_sim)
2003 {
2004 /* SJM 02/03/03 - breakpoint and ste cmds illegal if optimizer on */
2005 cmd_illegal_msg(s1);
2006 break;
2007 }
2008 __get_vtok();
2009 if (__toktyp == TEOF) __step_rep_cnt = 1;
2010 else
2011 {
2012 if ((tmp = __get_dbg_val()) == -1 || tmp < 1)
2013 {
2014 __ia_err(1470, ":step command repeat count %s illegal", __prt_vtok());
2015 break;
2016 }
2017 __step_rep_cnt = tmp;
2018 }
2019 __single_step = TRUE;
2020 __verbose_step = TRUE;
2021 if (__iact_reason == IAER_CTRLC || __suspended_thd == NULL
2022 || __suspended_thd->thnxtstp == NULL) __step_from_thread = FALSE;
2023 __step_match_itp = __scope_ptr;
2024 __chk_extra_atend(TRUE);
2025 return(FALSE);
2026 case DB_HIST:
2027 __do_dbg_history();
2028 break;
2029 case DB_EMPTHIST:
2030 __do_dbg_emptyhistory();
2031 break;
2032 case DB_IGNORE:
2033 __dbg_brk_ignore();
2034 break;
2035 case DB_COND:
2036 __dbg_brk_cond();
2037 break;
2038 default: __case_terr(__FILE__, __LINE__);
2039 }
2040 return(TRUE);
2041 }
2042
2043 /*
2044 * find a db style command
2045 * algorithm is that any unique prefix is sufficient
2046 * also need algorithm that does not require full table search each time
2047 *
2048 * this needs alias mechanism ala gdb
2049 */
__get_dbcmdnum(char * aval,struct namlst_t * cmdtab,int32 cmdnum)2050 extern int32 __get_dbcmdnum(char *aval, struct namlst_t *cmdtab, int32 cmdnum)
2051 {
2052 register int32 i;
2053 int32 alen, alen2;
2054
2055 /* first search for normal option (if arg white space separated) */
2056 alen = strlen(aval);
2057 for (i = 0; i < cmdnum; i++)
2058 {
2059 alen2 = strlen(cmdtab[i].lnam);
2060 if (alen2 > alen) alen2 = alen;
2061 if (strncmp(aval, cmdtab[i].lnam, alen2) == 0)
2062 {
2063 if (dbcmd_prefix_rep(i + 1, aval, alen2, cmdtab, cmdnum)) return(-2);
2064 return(cmdtab[i].namid);
2065 }
2066 }
2067 return(-1);
2068 }
2069
2070 /*
2071 * return T if find match in remaining part of db command table
2072 */
dbcmd_prefix_rep(register int32 i,char * aval,int32 alen,struct namlst_t * cmdtab,int32 cmdnum)2073 static int32 dbcmd_prefix_rep(register int32 i, char *aval, int32 alen,
2074 struct namlst_t *cmdtab, int32 cmdnum)
2075 {
2076 for (; i < cmdnum; i++)
2077 { if (strncmp(aval, cmdtab[i].lnam, alen) == 0) return(TRUE); }
2078 return(FALSE);
2079 }
2080
2081 /*
2082 * given a comman prefix where know ambiguous, built table of all possibilities
2083 */
__bld_ambiguous_list(char * s,char * aval,struct namlst_t * cmdtab,int32 cmdnum)2084 extern char *__bld_ambiguous_list(char *s, char *aval, struct namlst_t *cmdtab,
2085 int32 cmdnum)
2086 {
2087 register int32 i;
2088 int32 first_time, alen;
2089
2090 alen = strlen(aval);
2091 for (first_time = TRUE, i = 0; i < cmdnum; i++)
2092 {
2093 if (strncmp(aval, cmdtab[i].lnam, alen) == 0)
2094 {
2095 if (first_time) { strcpy(s, cmdtab[i].lnam); first_time = FALSE; }
2096 else { strcat(s, ", "); strcat(s, cmdtab[i].lnam); }
2097 }
2098 }
2099 return(s);
2100 }
2101
2102 /*
2103 * emit message for command illegal when running with -O
2104 *
2105 * all traces and steps
2106 */
cmd_illegal_msg(char * s)2107 static void cmd_illegal_msg(char *s)
2108 {
2109 __ia_err(1417,
2110 "%s illegal when -O optimized (compiled) simulation selected", s);
2111 }
2112
2113 /*
2114 * DEBUGGER HELP SCREEN LINE TABLES
2115 */
2116
2117 /*
2118 * define debugger general topic help screen
2119 */
2120 static char *dbg_topic_hlp[] = {
2121 "Type ':help [topic]' or ':help :[debugger command]' to print specific help",
2122 "message. Any name can be abbreviated by a unique prefix within : debugger.",
2123 "Colon is required for command name help but not allowed for help topics.",
2124 " ",
2125 "Help topics:",
2126 " debugging: Entering and supplying input for interactive debugging.",
2127 " optimizer: debugging limitations when -O optimized simulation selected",
2128 " tracing: Separate batch tracing system for debugging.",
2129 " differences: Debugger differences from Verilog standard.",
2130 " statements: Using traditional interactive Verilog statement debugger.",
2131 " data: Examining variables and expressions.",
2132 " source: Listing source and navigating between files.",
2133 " scope: Setting and navigating between instance and task scopes.",
2134 " break points: Behavioral statement breakpoints and single stepping.",
2135 " changes breaking: Breaking on net changes and edges.",
2136 " history: Command history and history number command enable/disable.",
2137 " info: Determining and setting debugger status and settings.",
2138 " tasks: System task and functions useful for interactive debugging.",
2139 " commands: A list of :[command] debugger commands.",
2140 ""
2141 };
2142
2143 static char *dbg_dbg_hlp[] = {
2144 "Debugging:",
2145 " Both the standard Verilog statement debugger and a command based debugger",
2146 " are supported. Input is typed from the terminal or read from a file.",
2147 " Input is terminated with a new line. For multi-line commands, all",
2148 " but the last line ends with a back slash escaped new line. The new",
2149 " command debugger commands begin with a colon as part of the name and",
2150 " cannot be executed from Verilog source. All interactive commands are",
2151 " echoed to the log file unless ':set noecholog' is used to to suppress log",
2152 " file command echoing (':set echolog' re-enables).",
2153 " ",
2154 " The debugger is entered by pressing the interrupt key (^c), by calling",
2155 " the $stop system task, by the -s command line option, by completing a",
2156 " step command, or by hitting a breakpoint.",
2157 " ",
2158 " The $input(\"[file]\") system task causes debugger commands to be read",
2159 " from [file] the first time interactive mode is entered (by -s?). $input",
2160 " files do not nest, instead $input in a file causes $input to chain to the",
2161 " new file. Output is written to the screen and the log file. stderr is",
2162 " not used. All typed user input including command prompts and $input",
2163 " commands is written to the log file. $nolog and $log plus",
2164 " $nokeepcommands and $keepcommands can minimize $input script output.",
2165 " +nokeepcommands option disables history saving. It is useful if",
2166 " simulation is run from a shell script.",
2167 ""
2168 };
2169
2170 static char *dbg_optimizer_hlp[] = {
2171 "Optimizer:",
2172 " When -O optimized simulation (compiled byte code simulation) is used,",
2173 " breakpoints and single stepping is not possible because statements",
2174 " are converted to basic blocks, i.e. statement separation is lost.",
2175 " Even when optimizatin is on, you still can use the debugger because",
2176 " the byte code compiler is incremental and recompiles code required",
2177 " by debugger Verilog statements. The debugger can be entered by executing",
2178 " $stop system task either from Verilog source or from statements",
2179 " entered as debugger commands, i.e. debugger can be entered by $stop",
2180 " system task, -s command option, or $stop entered as debugger command",
2181 " (such as '@(posedge clk) $stop;' statement), or by pressing ^c (interrupt",
2182 " key). All printing, scope and info commands work. Also, $input",
2183 " system task and -i command line options to load commands into debugger",
2184 " are legal when debugger is used with optimized simulation.",
2185 " ",
2186 " For designs that do not move time (mostly procedural without time",
2187 " movement and event scheduling), there may be a delay after interrupt",
2188 " key is pressed before interactive debugger is entered.",
2189 " ",
2190 " Debugger can only be exited by the dot ('.') continue command when used",
2191 " with optimized simulation. Use of step (';' or ',') and all break point",
2192 " commands are illegal. Error message is emitted and command is ignored.",
2193 " Also, $dumpvars can not be called from interactive mode during optimized",
2194 " simulation.",
2195 ""
2196 };
2197
2198 static char *dbg_trc_hlp[] = {
2199 "Debugging using the tracing mechanism:",
2200 " An alternative non interactive tracing mechanism is supported.",
2201 " Behavioral statement tracing is started with the -t option or $settrace",
2202 " system task and stopped by calling $cleartrace. Event tracing is started",
2203 " with the -et option or $setevtrace system task and stopped by calling",
2204 " $clearevtrace. The -et option allows pre time 0 initialization events",
2205 " to be traced. Trace output is written to stdout and the log file unless",
2206 " the +tracefile [file name] option or $settracefile([string]) system task",
2207 " are used to direct trace output to a separate file. The trace mechanism",
2208 " is intended to allow debugging of parallel activity by searching trace",
2209 " output with a debugger.",
2210 " ",
2211 " Trace statements and gates are reconstructed source with parameters",
2212 " replaced by numeric values. Interactive debugger breakpoint and step",
2213 " tracing also emit source lines. To avoid duplicate output if tracing",
2214 " and the interactive debugger are used, redirect trace output.",
2215 ""
2216 };
2217
2218 static char *dbg_dif_hlp[] = {
2219 "Debugger differences from standard:",
2220 " 1) Multiple line interactive debugger commands must end with escaped new",
2221 " lines. Verilog statements still require the ending semicolon.",
2222 " 2) The standard $settrace system task (also -t) are divided into the two",
2223 " tracing classes: $settrace and $setevtrace (-t and -et).",
2224 " 3) By default when interactive mode is entered the $scope interactive",
2225 " scope is set to the current scope. This allows examination of local",
2226 " variables on step or break but may require entering $scope command on",
2227 " every interactive entry to run standard scripts. In functions, named",
2228 " blocks do not have scope so function scope remains. Interactivbe variable",
2229 " access in function named block must use qualified reference from function",
2230 " scope. To duplicate standard behavior in which interactive scope can only",
2231 " be changed by $scope system task, type: ':set noscopechange' inside the",
2232 " interactive debugger. When re-enabling commands from the history list,",
2233 " either the command must use rooted names or the scope must be the same",
2234 " as the scope when the command was originally entered.",
2235 " 4) Delay back annotation by specparam assignments not supported, and",
2236 " $updatetiming, but similar standard SDF (LABEL form and PLI 2.0 assignment",
2237 " to defparams and specparam before delay elaboration supported.",
2238 ""
2239 };
2240
2241 static char *dbg_stmt_hlp[] = {
2242 "Interactive Verilog statement execution:",
2243 " Any Verilog statement can be entered at the interactive mode prompt (or",
2244 " in an $input file) except named blocks and initial or always statements.",
2245 " No new variables can be declared and all identifiers are accessed using",
2246 " the current scope (entry scope or change $scope location). Compound",
2247 " statements and statements with delay or event controls are legal.",
2248 " Commands are:",
2249 " ",
2250 " '.' Exit the debugger and continue execution (event processing).",
2251 " ':' Print the current instance and possibly task scope plus location",
2252 " of scope and current :list current location. Prints scope and",
2253 " listing location, use :where for procedural execution location.",
2254 " ';' Silently step through next procedural statement and process all",
2255 " events and time movement up to the next procedural statement. The",
2256 " current location for the :list command is not changed. Tasks and",
2257 " functions are stepped into.",
2258 " ',' Step through next statement and print next source statement. Same",
2259 " as ';' except the next source line to execute is printed.",
2260 " -[number] Disable history command [number] if it has not yet completed.",
2261 " The $history task indicates commands that are active with a '*'",
2262 " [number] Re-execute command [number] from the history list only if the",
2263 " command has finished (no '*' mark when printed with $history).",
2264 " Commands are re-executed in the current scope so if a command sets",
2265 " a change or edge breakpoint, it must contain rooted names or be",
2266 " executed from the same scope as it's original entry.",
2267 ""
2268 };
2269
2270 static char *dbg_data_hlp[] = {
2271 "Displaying internal circuit values:",
2272 " In addition to the normal $display (or $write) system tasks to display",
2273 " values use :print to override declared expression base or width (type",
2274 " ':help :print' for legal values). Use :display to define expressions that",
2275 " are printed whenever interactive mode is entered. :display and :print",
2276 " take same format and width modifiers. :expris [expr] to determine the",
2277 " width and type of an expression. Use :varis [var.] to determine type,",
2278 " width and declaration keywords of a variable. Use :whatis [name] to",
2279 " determine all uses of an identifier name. Entire qualified path from",
2280 " function scope required for accessing variables in named blocks in",
2281 " functions.",
2282 ""
2283 };
2284
2285 static char *dbg_src_hlp[] = {
2286 "Listing source statements:",
2287 " The normal $list([scope]) system task can list all of any task or module.",
2288 " The :list command lists 10 lines from a selected location that can be",
2289 " a scope or a [file:][line] reference or argument relative to last listed",
2290 " line. Type ':set listsize [number]' to change the number of lines listed.",
2291 " The current listing location is independent of current scope except when",
2292 " :scope or $scope is executed, the current list line is set to the first",
2293 " line of the scope. Also since ',' and :[i]step and hitting a breakpoint",
2294 " print a source line, those commands change the current list line.",
2295 " The explicit [file:][line] list command lists in a new file and :list ++",
2296 " lists the beginning of the next source file (:list -- the previous end).",
2297 " Only these three commands can change listing file. Type ':help :list'",
2298 " for the format of the various :list command options.",
2299 ""
2300 };
2301
2302 static char *dbg_scope_hlp[] = {
2303 "Setting interactive scope:",
2304 " The $scope([scope xmr]) system task changes interactive scope. The :scope",
2305 " command also changes scope but allows a more general reference. The",
2306 " :breakpoint command takes a scope reference argument. Format is:",
2307 " ",
2308 " [file:][line] - first instance of scope determined by [file:][line].",
2309 " [file] can be source file, -y or -v path or any path tail if it is",
2310 " unique. [line] must be between module - endmodule. Any ':' in",
2311 " [file] name must be escaped with a back slash. Scope set to type or",
2312 " first instance but other command argument may select instance for",
2313 " :breakpoint. Scope list line set to first line of scope not [line].",
2314 " [line] is same as [file:][line] where [file] is current file.",
2315 " .. or .u - upward scope first line - if scope in task - one up task or",
2316 " instance containing task (not up instance).",
2317 " .d - first line of scope of first contained instance (not contained task).",
2318 " [module name] - first instance of module unless name declared as instance",
2319 " in current scope, then normal downward hierarchical reference.",
2320 " [hierarchical ref.] - first line of instance - same as $scope argument.",
2321 ""
2322 };
2323
2324 static char *dbg_brkpt_hlp[] = {
2325 "Behavioral statement breakpoints:",
2326 " Use the :breakpoint or :ibreakpoint commands to set a breakpoint at a",
2327 " specific source statement. The break occurs before statement execution.",
2328 " :breakpoint breaks in all instances and :ibreakpoint breaks only in the",
2329 " specified instance. The :breakpoint argument can be any scope or line",
2330 " reference. If no line reference is given the break is at the first",
2331 " initial, always or task statement of the scope. For :ibreakpoint the",
2332 " argument must be an instance reference that may optionally be followed by",
2333 " a ',' and a line reference. For a line reference, the breakpoint is set",
2334 " at the first procedural statement at or following the line in the scope.",
2335 " ",
2336 " Type ':help :breakpoint' or ':help :ibreakpoint' for other options and",
2337 " argument format. Use ':info breakpoints' to print a list of breakpoints",
2338 " ':delete [number]' to delete breakpoint [number] (no argument deletes all),",
2339 " ':disabl [number]' to temporarily disable breakpoint and ':enable [number]'",
2340 " to re-enable. :tbreakpoint and :tibreakpoint are identical to :ibreak",
2341 " and :break except breakpoint removed when hit. :cond adds expression to",
2342 " breakpoint that must be true to cause stop. :ignore adds count of how many",
2343 " hits to ignore before halting.",
2344 ""
2345 };
2346
2347 static char *dbg_chgbrk_hlp[] = {
2348 "Breaking on net changes:",
2349 " Enter a delay or event control followed by the $stop system task to",
2350 " enter interactive mode on value change. Normally the event control",
2351 " statement will be in a loop (probably a forever) because otherwise the",
2352 " break is disabled after each trigger. Also when interactive mode is",
2353 " entered from an interactive $stop, a step (',', ':', :step, or :istep)",
2354 " command must be entered before using [number] to re-enable a history",
2355 " statement. For example: 'forever @(posedge clock) $stop;' is usually",
2356 " better than '@(posedge clock) $stop;'",
2357 ""
2358 };
2359
2360 static char *dbg_hist_hlp[] = {
2361 "History mechanism:",
2362 " A command is re-executed by entering its history number. A uncompleted",
2363 " command (such as a Verilog wait or delay control) is disabled by entering",
2364 " -[number] where [number] is command's assigned number in history list.",
2365 " ",
2366 " The $history system task prints the most recent 20 (or histlistsize if",
2367 " different) history entries. The debugger :history [optional number]",
2368 " command is more flexible because if an optional number argument appears,",
2369 " that many elements are printed (0 for all). The interactive command",
2370 " prompt is 'C[number] >' where [number] is a command's history number.",
2371 " The one character, [number] to execute, [-][number] to disable and",
2372 " incorrect (such as mistyped Verilog statement entered interactively)",
2373 " commands are not added to the history list.",
2374 " ",
2375 " All commands input during a run are retained. Use $nokeepcommands to",
2376 " suppress history accumulation and $keepcommands to re-enable in $input",
2377 " scripts. +nokeepcomands command line option disables history saving for",
2378 " programs that run a simulation by supplying command input through a pipe.",
2379 " :emptyhistory command discards all retained history commands and resets",
2380 " command number to one. If any history commands are enabled (have not yet",
2381 " completed or been disabled), :emptyhistory will fail. When an interactive",
2382 " Verilog statement is executed, if it can be executed immediately (no",
2383 " delays, events or tasks enables), it is executed from inside debugger and",
2384 " control remains in interactive mode. Non immediate statements are",
2385 " scheduled after already scheduled events and resumes. $stop or the",
2386 " interrupt signal (^c) must then be used to reenter interactive mode. Use",
2387 " ':set histlistsize' to set default number of history commands to list and",
2388 " ':info histlistsize' to see current number.",
2389 ""
2390 };
2391
2392 static char *dbg_info_hlp[] = {
2393 "Determining and setting internal debugger state values:",
2394 " The ':info [debugger value name]' command prints the current value of",
2395 " a debugger value. The ':set [debugger value name] [value]' command",
2396 " changes a debugger value. Type ':help :info' or ':help :set' for the list",
2397 " of debugger info value names.",
2398 ""
2399 };
2400
2401 static char *dbg_stsks_hlp[] = {
2402 "The following system tasks may be useful during interactive debugging:",
2403 " $finish; Terminate simulation.",
2404 " $list([scope reference]); list source lines of scope (:list is",
2405 " alternative). $list does not print variables values, use $showvars",
2406 " or :print <expr> for that. Also $list does not mark source lines",
2407 " with pending events.",
2408 " $system(\"[OS command string]\"); Escape to a sub shell and execute the",
2409 " command string (alternative is :shell [command string]). Use empty",
2410 " string (\"\") to invoke an interactive sub-shell.",
2411 " $flushlog; Call OS flush of buffers for log file and trace file. Can",
2412 " then use :shell to invoke your editor to inspect output.",
2413 " $history; Print history list to stdout and log file. Contrary to XL,",
2414 " '$history;' prints last 20 (or histlistsize) commands. Use",
2415 " ':history <num>' to print <num> commands. <num> 0 prints all. :set",
2416 " sets and :info prints debugger histlistsize parameter that determines",
2417 " number of commands to list.",
2418 " $keepcommands;, $nokeepcommands; Enable (or disable) saving of commands",
2419 " entered interactively to history list. Default is $keepcommands.",
2420 " Use the +nokeepcommands command line option to disable saving of",
2421 " commands to the history list unless '$keepcommands;' is executed.",
2422 " $input([string]); Process interactive commands from [string] file.",
2423 " $nolog;, $log; All commands in $input scripts will be copied to the",
2424 " log file unless $nolog is used. To re-enable log file output, use",
2425 " $log; with no argument. To change log file use $log([string]).",
2426 " $reset;, $reset_count;, $reset_value; During debugging reset to start",
2427 " of simulation. :reset command is better during debugging since it",
2428 " returns to time 0 leaving the reset count unaffected and allows stop.",
2429 " $scope; Change interactive environment scope to avoid a need to type",
2430 " full paths for variable names. :scope and automatic scope tracking",
2431 " are intended to lessen need to set explicit interactive scopes.",
2432 " $scope can set scope to function named block but next ineractive entry",
2433 " (from step?) will change scope to function body scope.",
2434 " $showallinstances; Print all instances in design with source file and",
2435 " line location. Useful to find module whose name is forgotten.",
2436 " +printstats and +printallstats give more detailed information.",
2437 " If no other window is available, use $flushlog; and :shell to view.",
2438 " $showscopes; Used to show scopes in current interactive scope. Can be",
2439 " called with non zero argument to list entire design scope map.",
2440 " $showvariables;, $showvars Print all variables in current scope. :print",
2441 " is more terse but $showvars prints more for multiple fan-in wires.",
2442 " $shapshot; print up to 5 pending procedural and 5 pending declarative",
2443 " events and status of every interactive thread. Same as :snapshot.",
2444 " $display, $write Write values. Alternative :print is more flexible but",
2445 " these tasks allow formatted output.",
2446 ""
2447 };
2448
2449 /* table of debugger help topic values */
2450 #define HLP_DBG 0
2451 #define HLP_OPTIM 1
2452 #define HLP_TRC 2
2453 #define HLP_DIF 3
2454 #define HLP_STMT 4
2455 #define HLP_DAT 5
2456 #define HLP_SRC 6
2457 #define HLP_SCP 7
2458 #define HLP_BP 8
2459 #define HLP_CHGBP 9
2460 #define HLP_HIST 10
2461 #define HLP_INF 11
2462 #define HLP_TSK 12
2463 #define HLP_CMD 13
2464
2465 /* debugger help topic name table */
2466 /* index and pos. in this table must be identical */
2467 static struct namlst_t hlptoptab[] = {
2468 { HLP_DBG, "debugging" },
2469 { HLP_OPTIM, "optimizer" },
2470 { HLP_TRC, "tracing" },
2471 { HLP_DIF, "differences" },
2472 { HLP_STMT, "statements" },
2473 { HLP_DAT, "data" },
2474 { HLP_SRC, "source" },
2475 { HLP_SCP, "scope" },
2476 { HLP_BP, "breakpoints" },
2477 { HLP_CHGBP, "changes" },
2478 { HLP_HIST, "history" },
2479 { HLP_INF, "info" },
2480 { HLP_TSK, "tasks" },
2481 { HLP_CMD, "commands" }
2482 };
2483 #define NHLPTOPS (sizeof(hlptoptab) / sizeof(struct namlst_t))
2484
2485 /* per help topic line tables - size is same help topices */
2486 /* index and pos. in this table must be identical */
2487 static struct hlplst_t hlp_topics[] = {
2488 { HLP_DBG, dbg_dbg_hlp },
2489 { HLP_OPTIM, dbg_optimizer_hlp },
2490 { HLP_TRC, dbg_trc_hlp },
2491 { HLP_DIF, dbg_dif_hlp },
2492 { HLP_STMT, dbg_stmt_hlp },
2493 { HLP_DAT, dbg_data_hlp },
2494 { HLP_SRC, dbg_src_hlp },
2495 { HLP_SCP, dbg_scope_hlp },
2496 { HLP_BP, dbg_brkpt_hlp },
2497 { HLP_CHGBP, dbg_chgbrk_hlp },
2498 { HLP_HIST, dbg_hist_hlp },
2499 { HLP_INF, dbg_info_hlp },
2500 { HLP_TSK, dbg_stsks_hlp },
2501 /* here must call special command list routine */
2502 { HLP_CMD, NULL, }
2503 };
2504
2505 /*
2506 * DEBUGGER INDIVIDUAL COMMAND HELP SCREEN LINE TABLES
2507 */
2508
2509 static char *help_msg[] = {
2510 ":help [optional topic or :[command] name prefix]",
2511 " Print help message.",
2512 ""
2513 };
2514
2515 static char *shell_msg[] = {
2516 ":shell [rest of line is OS command]",
2517 " Execute rest of line as OS command in sub-shell. Notice no quotes needed.",
2518 " Empty rest of line to spawn interactive shell. Equivalent to",
2519 " '$system([quotes OS command string]);' system task.",
2520 ""
2521 };
2522
2523 static char *snapshot_msg[] = {
2524 ":snapshot",
2525 " Print snapshot of current procedural location and list of statement at",
2526 " which each procedural (per instance) thread suspended at. Also lists",
2527 " pending events on head of event list. May be long so one way to view it",
2528 " is to type: $flushlog; then ':sh [evoke editor on verilog.log file]'.",
2529 ""
2530 };
2531
2532 static char *where_msg[] = {
2533 ":where",
2534 " Print back trace of most recently suspended control thread including all",
2535 " upward thread enables with source and scope locations. To see a listing",
2536 " of all pending scheduled event activity and thread states use $snapshot;",
2537 " or :snapshot. :where corresponds as closely as possible to normal",
2538 " call stack trace back. ':' prints instance scope and last source",
2539 " listing location. If :where fails, suspension was from declarative code.",
2540 " Try single step and entering :where again.",
2541 ""
2542 };
2543
2544 static char *quit_msg[] = {
2545 ":quit",
2546 " Exit. Equivalent to $finish;",
2547 ""
2548 };
2549
2550 static char *print_msg[] = {
2551 ":print [/format][#width] [expression]",
2552 " Evaluate and print expression. If [/format] is present, interpret the",
2553 " value according to format. Formats are: 'd' (decimal), 'u' (unsigned),",
2554 " 'b' (binary), 'h' or 'x' (hex), 's' (string), or 'c' (1 character). If",
2555 " the [/format] is omitted, use current default unless the expression is a",
2556 " string or real. Starting default base is hex, but use ':set printbase'",
2557 " to set different default base. /u format prints bit pattern as unsigned.",
2558 " If [#width] value is present, interpret as [width] wide, instead of width",
2559 " computed from operator width rules. Any format or width are ignored for",
2560 " reals, use $realtobits to view bit pattern.",
2561 ""
2562 };
2563
2564 static char *reset_msg[] = {
2565 ":reset [stop]",
2566 " Reset simulation back to time 0 and restart simulation. Interactive mode",
2567 " must be explicitly entered by interrupt (^c), calling $stop or [stop]",
2568 " option. If a -i startup file was given it is executed on interactive",
2569 " entry. $reset_count and $reset_value are not changed. If optional",
2570 " :reset stop argument is present, stop just before simulation, else rerun",
2571 " without stopping even if -s option was given on command line. Equivalent",
2572 " to $reset system task but can be used to restart for debugging models",
2573 " that use the $reset system task. The $reset system task uses the -s",
2574 " option unless the first argument is non zero and stops before simulation.",
2575 " All uncompleted interactive statements are disabled by either :reset",
2576 " or $reset. They are re-enabled by typing history command number or",
2577 " running -i start up interactive file. Debugger state : breakpoints",
2578 " (left enabled) and history are preserved.",
2579 ""
2580 };
2581
2582 static char *expris_msg[] = {
2583 ":expris [expression]",
2584 " Print type and width of expression. Use to determine Verilog width and",
2585 " property rules for complex expressions.",
2586 ""
2587 };
2588
2589 static char *varis_msg[] = {
2590 ":varis [variable]",
2591 " Print type and width and declaration keywords of variable.",
2592 ""
2593 };
2594
2595 static char *whatis_msg[] = {
2596 ":whatis [identifier]",
2597 " Print symbol information for every use of identifier. Also, emits one",
2598 " instance reference for each use, so a breakpoint can be set.",
2599 ""
2600 };
2601
2602 static char *list_msg[] = {
2603 ":list [range]",
2604 " List source within [range] lines. Some [range]s are relative to last",
2605 " printed line. Any scope change or $list or previous :list command",
2606 " changes the last printed line. Legal [range]s are:",
2607 " ",
2608 " + or [empty] 10 lines starting with last printed.",
2609 " +0 10 lines around current line.",
2610 " - 10 lines ending 1 before previous first line.",
2611 " ++ First 10 lines of next file.",
2612 " -- Last 10 lines of previous file.",
2613 " [file]:[number] 10 lines around [number] in file [file].",
2614 " [number] 10 lines around [number] in current file.",
2615 " [+/-][offset] 10 lines starting [offset] from current.",
2616 " [+/-][num1],[+/-][num2] Range, if [+/-] offset from current line.",
2617 " [scope reference] First 10 lines starting at [scope].",
2618 " ",
2619 " By default 10 lines are list, use ':set listsize [number]' to change",
2620 " number of printed lines to [number]. Notice stepping with ';' does not",
2621 " change last printed line. Use [file]:[number] to list inside `include",
2622 " files. ++ and -- exit to file and line of first inclusion of file.",
2623 " Read library files are same as source files.",
2624 ""
2625 };
2626
2627 static char *set_msg[] = {
2628 ":set [debugger parameter] [value]",
2629 " Set debugger internal parameter to [value]. Legal set parameters are:",
2630 " ",
2631 " :set listsize [number] Default is 10 lines to list.",
2632 " :set histlistsize [number] Default is 20 history commands to list.",
2633 " :set noscopechange Disable automatic scope setting on entry to",
2634 " interactive mode.",
2635 " :set scopechange Re-enable automatic scope setting on. Scope",
2636 " not set to named blocks in functions.",
2637 " :set printbase [base] Set default :print command base, values: hex",
2638 " (default), decimal, octal binary.",
2639 " :set nologecho Turn off writing of input interactive commands",
2640 " the log file (default).",
2641 " :set logecho Turn on writing of input commands.",
2642 ""
2643 };
2644
2645 static char *info_msg[] = {
2646 ":info [debugger parameter]",
2647 " Show value of debugger state or parameter setting. Legal info parameters",
2648 " are: listsize, histlistsize, scopechange, breakpoints, displays,",
2649 " printbase and logecho. For breakpoints and auto-display expressions",
2650 " prints status information for each.",
2651 ""
2652 };
2653
2654 static char *scope_msg[] = {
2655 ":scope [scope reference]",
2656 " Change interactive scope to [scope reference] location. Type",
2657 " ':help scope' for list of legal scope selection forms. Any [line] is",
2658 " used only to determine surrounding scope. Scope only applies to",
2659 " interactive mode and system tasks that explicitly are defined to use the",
2660 " interactive scope. Extended version of $scope system task. If scope",
2661 " set to function named block scope, next interactive entry will change",
2662 " scope to function body scope (assuming scopechange mode active).",
2663 ""
2664 };
2665
2666 static char *breakpoint_msg[] = {
2667 ":breakpoint [scope reference] or none",
2668 " Set statement breakpoint at all instances of [scope reference]. Type",
2669 " ':help scope' for a list of legal [scope reference] forms. If the",
2670 " reference selects an instance, only the type of the instance is used.",
2671 " If the [scope reference] is not a [file:][line] reference, use first",
2672 " initial, always or task statement of scope. If no argument, set at",
2673 " last :list argument (first if range, closest if backward) that must be",
2674 " within task, function or initial or always block. Setting a breakpoint",
2675 " at a line means the first procedural statement at or after the line (but",
2676 " must be within scope). Type ':help breakpoints' for discussion of other",
2677 " breakpoint commands.",
2678 "",
2679 };
2680
2681 static char *ibreakpoint_msg[] = {
2682 ":ibreakpoint [scope reference][,[file:][line]] or none",
2683 " Set statement breakpoint at instances of [scope reference] file [file]",
2684 " and [line] line. Type ':help scope' for a list of legal [scope ref.]s,",
2685 " but here only explicit instance scope references are legal. If the",
2686 " ',[file:][line]' argument is omitted, use first statement of first",
2687 " initial, always, or task (for task scope). If ',[line]' but no [file]",
2688 " is given, use first or only file of scope. If no scope reference and",
2689 " only ',[file:][line]' is given, use current scope. No argument means",
2690 " set at last :list argument (first if range, closest if backward)",
2691 " that must be within task, function, or initial or always block.",
2692 " Type ':help breakpoints' for discussion of other breakpoint commands.",
2693 "",
2694 };
2695
2696 static char *delete_msg[] = {
2697 ":delete [optional type] [number]",
2698 " Delete breakpoint or display expression with number [number] or all if",
2699 " number is omitted. [optional type] is breakpoints or displays (default",
2700 " if omitted is breakpoints). Type 'info breakpoints' or 'info displays'",
2701 " to determine breakpoint or auto-display number. If [number] is omitted,",
2702 " delete all breakpoints or auto-display expressions.",
2703 ""
2704 };
2705
2706 static char *disable_msg[] = {
2707 ":disabl [optional type] [number]",
2708 " Temporarily disable breakpoint or display with number [number].",
2709 " [optional type] is breakpoints or displays (breakpoints is default if",
2710 " omitted) and can be abbreviated to first letter. Type 'info breakpoints'",
2711 " or 'info displays' to determine breakpoint or auto-display number and",
2712 " enable state. Notice final e must not appear to avoid conflict with",
2713 " Verilog disable keyword (any unique prefix such as 'disa' works). Also",
2714 " notice that :disabl disables an added : debugger breakpoint, but disable",
2715 " statement or -[number] disables simulation of a Verilog statement.",
2716 ""
2717 };
2718
2719 static char *enable_msg[] = {
2720 ":enable [optional type] [number]",
2721 " Enable breakpoint or display with number [number]. [optional type]",
2722 " is either breakpoints or displays (breakpoints is default if omitted) and",
2723 " can be abbreviated to first letter. Type 'info breakpoints' or",
2724 " 'info displays' to determine breakpoint or auto-display expression",
2725 " number and enable state.",
2726 ""
2727 };
2728
2729 static char *step_msg[] = {
2730 ":step [optional repeat count]",
2731 " Step to next procedural line. Execute one statement or statements on",
2732 " current line, stop before first statement of next line. May process",
2733 " pending declarative events before stepping. Execution steps into any",
2734 " task or function. Equivalent to ',' interactive Verilog command.",
2735 " Always prints location after stopping. if optional repeat count, step",
2736 " that many times before stopping and printing message. If interrupt (^c)",
2737 " or breakpoint hit during stepping, stop stepping and enter interactive",
2738 " mode.",
2739 ""
2740 };
2741
2742 static char *istep_msg[] = {
2743 ":istep [optional repeat count]",
2744 " Step to next procedural statement that is in same instance tree location.",
2745 " Otherwise identical to :step. If debugger entered by interrupt, use one",
2746 " :step before :istep since scope may have been in module without any",
2747 " procedural statements. :istep uses currently executing instance not",
2748 " interactive scope set by $scope.",
2749 ""
2750 };
2751
2752 static char *hist_msg[] = {
2753 ":history [optional number]",
2754 " Print 20 (or value of histlistsize info debugger parameter) commands.",
2755 " If [number] appears, print [number] (0 means all) history commands.",
2756 " Pauses and prompts for CR every histlistsize lines.",
2757 ""
2758 };
2759
2760 static char *empthist_msg[] = {
2761 ":emptyhistory",
2762 " If all history commands have completed or are disabled with (-[number]",
2763 " command), discard retained history and set next history command to 1.",
2764 ""
2765 };
2766
2767 static char *disp_msg[] = {
2768 ":display [/format][#width] [expression]",
2769 " Set up [expression] in display table so that it is displayed on every",
2770 " entry to interactive mode. Arguments are identical to :print command.",
2771 " Use ':delete display' or ':undisplay' to delete all auto-display",
2772 " expressions. If either is followed by a number, delete that numbered",
2773 " display only. Use ':info display' to list current displays. ':display'",
2774 " with no arguments displays all current auto-display expressions.",
2775 " Use 'enable display' and 'disabl display' to temporarily turn off or on",
2776 " an auto-display expression.",
2777 ""
2778 };
2779
2780 static char *undisp_msg[] = {
2781 ":undisplay [optional number]",
2782 " Delete [number] auto-display expression or all current if [number] is",
2783 " not present. Same as ':delete display' command.",
2784 ""
2785 };
2786
2787 static char *tbreakpoint_msg[] = {
2788 ":tbreakpoint [scope reference] or none",
2789 " Command identical to :breakpoint except breakpoint is temporary and",
2790 " removed after it is hit the first time. To avoid tracing in task or",
2791 " function (approximate DBX/GDB next command), use the :nextb command.",
2792 " It sets a :tibreak at the next line and executes a '.' command. Because",
2793 " of delay and event controls, other threads may be executed before break",
2794 " is hit. The :ignore command can be used with :tbreakpoint. After",
2795 " ignore count hits, the break point is taken and then removed.",
2796 ""
2797 };
2798
2799 static char *tibreakpoint_msg[] = {
2800 ":tibreakpoint [scope reference][,[file:][line]] or none",
2801 " Command identical to :ibreakpoint except breakpoint is temporary and",
2802 " removed after it his the first time (see :tbreakpoint help). Only",
2803 " stops in instance that is same as scope reference instance.",
2804 ""
2805 };
2806
2807 static char *nextb_msg[] = {
2808 ":nextb",
2809 " Abbreviation for :tibreak [line number of next thread statement]",
2810 " followed by '.'. Analog of DBX/GDB next command steps over current",
2811 " statement. Break point is visible and can be removed before it is hit.",
2812 " If no next statement in thread, temporary break point not set and error",
2813 " message emitted. :nextb over task enable may execute other threads",
2814 " before stopping if the task contains event or delay controls. :nextb",
2815 " and for that matter any temporary break point do not use up a break",
2816 " point number unless a new break point is set before temporary break",
2817 " point is hit. See ':help :tbreakpoint' and ':help statements' for",
2818 " more information.",
2819 ""
2820 };
2821
2822 static char *ignorebrk_msg[] = {
2823 ":ignore [breakpoint number] [ignore count]",
2824 " Do not stop at break point [number] until [ignore count] hits of the",
2825 " break point have occurred. Ignore count assumes last hit was 0th.",
2826 " To remove an :ignore count, use 'ignore [break number] 0'. Use",
2827 " ':info breakpoints' to determine number of hits and any pending ignore",
2828 " count.",
2829 ""
2830 };
2831
2832 static char *condbrk_msg[] = {
2833 ":cond [breakpoint number] [optional condition expression]",
2834 " Do not stop at break point [number] unless [expression] evaluates to",
2835 " a positive non x/z value (i.e. true). Expression will be checked and",
2836 " evaluated in instance and task/function or named block scope of break",
2837 " point. Since Verilog variables persist, :cond expression variable always",
2838 " have values. Conditions are evaluated before ignore counts so if",
2839 " condition is false hit count does not rise. Use ':cond [break number]'",
2840 " to remove condition.",
2841 ""
2842 };
2843
2844 /* per command help line tables - size is same as dbcmds */
2845 /* this table must have value and index same (same order as constants) */
2846 static struct hlplst_t hlpcmds[] = {
2847 { DB_HELP, help_msg },
2848 { DB_SH, shell_msg },
2849 { DB_QUIT, quit_msg },
2850 { DB_WHERE, where_msg },
2851 { DB_PRINT, print_msg },
2852 { DB_RESET, reset_msg },
2853 { DB_EXPRIS, expris_msg },
2854 { DB_VARIS, varis_msg },
2855 { DB_WHATIS, whatis_msg },
2856 { DB_LIST, list_msg },
2857 { DB_SET, set_msg },
2858 { DB_INFO, info_msg },
2859 { DB_SCOPE, scope_msg },
2860 { DB_BRKPT, breakpoint_msg },
2861 { DB_IBRKPT, ibreakpoint_msg },
2862 { DB_DELBRKDIS, delete_msg },
2863 { DB_BPDIS_ENABLE, enable_msg },
2864 { DB_BPDIS_DISABLE, disable_msg },
2865 { DB_STEP, step_msg },
2866 { DB_ISTEP, istep_msg },
2867 { DB_HIST, hist_msg },
2868 { DB_EMPTHIST, empthist_msg },
2869 { DB_DISPLAY, disp_msg },
2870 { DB_UNDISPLAY, undisp_msg },
2871 { DB_TBRKPT, tbreakpoint_msg },
2872 { DB_TIBRKPT, tibreakpoint_msg },
2873 { DB_IGNORE, ignorebrk_msg },
2874 { DB_COND, condbrk_msg },
2875 { DB_SNAPSHOT, snapshot_msg },
2876 { DB_NEXTB, nextb_msg }
2877 };
2878
2879 /*
2880 * ROUTINES TO IMPLEMENT DEBUGGER HELP SYSTEM
2881 */
2882
2883 /*
2884 * write the debugger help screens
2885 * format is :help or :help [topic] where [topic] is special topic or
2886 * :[command]
2887 */
do_dbg_help(void)2888 static void do_dbg_help(void)
2889 {
2890 int32 rv;
2891 char s1[RECLEN];
2892
2893 /* number error here, but make sure not allocated */
2894 __get_vtok();
2895 /* case 1: no argument, emit topic list */
2896 if (__toktyp == TEOF) { wr_dbg_hlpmsg(dbg_topic_hlp); return; }
2897 /* case 2: argument is : debugger command */
2898 if (__toktyp == COLON)
2899 {
2900 __get_vtok();
2901 if (__toktyp != ID || strlen(__token) > 40)
2902 {
2903 bad_cmd:
2904 __ia_err(1438,
2905 ":help argument :%s illegal - not a : debugger command", __prt_vtok());
2906 return;
2907 }
2908 strcpy(s1, ":");
2909 strcat(s1, __token);
2910 rv = __get_dbcmdnum(s1, dbcmds, NDBCMDS);
2911 if (rv == -1) goto bad_cmd;
2912 if (rv == -2)
2913 {
2914 __ia_err(1422, ":help %s - ambiguous : debugger command: %s", s1,
2915 __bld_ambiguous_list(__xs, s1, dbcmds, NDBCMDS));
2916 return;
2917 }
2918 /* notice rv is found in command table but indexes hlpcmds table */
2919 /* therefore the 2 tables must be kept in indentical order */
2920 wr_dbg_hlpmsg(hlpcmds[rv].hmsgtab);
2921 goto done;
2922 }
2923 /* case 3: argument is help topic */
2924 if (__toktyp != ID)
2925 {
2926 bad_topic:
2927 __ia_err(1439, ":help topic %s unrecognized", __prt_vtok());
2928 goto done;
2929 }
2930 rv = __get_dbcmdnum(__token, hlptoptab, NHLPTOPS);
2931 if (rv == -1) goto bad_topic;
2932 if (rv == -2)
2933 {
2934 __ia_err(1422, ":help %s - ambiguous topic: %s", s1,
2935 __bld_ambiguous_list(__xs, s1, hlptoptab, NHLPTOPS));
2936 goto done;
2937 }
2938 /* for help command topic, routine to list all commands */
2939 /* hlptoptab and hlp_topics tables must be kept in identical order */
2940 if (rv == HLP_CMD) wr_dbg_lstofcmds(dbcmds, NDBCMDS);
2941 else wr_dbg_hlpmsg(hlp_topics[rv].hmsgtab);
2942
2943 done:
2944 __chk_extra_atend(TRUE);
2945 }
2946
2947 /*
2948 * write a debugger help message to standard output and log file
2949 */
wr_dbg_hlpmsg(char ** dbgmsg)2950 static void wr_dbg_hlpmsg(char **dbgmsg)
2951 {
2952 register int32 i;
2953
2954 for (i = 0; *dbgmsg[i] != '\0'; i++) __cvsim_msg("%s\n", dbgmsg[i]);
2955 }
2956
2957 /*
2958 * write the list of debugger commands
2959 */
wr_dbg_lstofcmds(struct namlst_t * cmdtab,int32 cmdnum)2960 static void wr_dbg_lstofcmds(struct namlst_t *cmdtab, int32 cmdnum)
2961 {
2962 register int32 i;
2963
2964 if (__outlinpos != 0) __misc_terr(__FILE__, __LINE__);
2965 __pv_stlevel = 0;
2966 __wrap_puts(":[command] debugger commands: ", stdout);
2967 for (i = 0; i < cmdnum; i++)
2968 {
2969 __wrap_puts(cmdtab[i].lnam, stdout);
2970 if (i != cmdnum - 1) __wrap_puts(", ", stdout);
2971 }
2972 if (__outlinpos != 0) __wrap_putc('\n', stdout);
2973 __outlinpos = 0;
2974 }
2975
2976 /*
2977 * ROUTINES TO IMPLEMENT DEBUGGER EXPRESSION EVALUATION
2978 */
2979
2980 /*
2981 * print an expression value - know :print read
2982 *
2983 * format - :print/[d,u,b,h(x),s,c]#[bits] <expr> - default h and expr width
2984 * p#42 - p/d#52
2985 * notice no f - since will always print real as real
2986 */
dbg_print(void)2987 static void dbg_print(void)
2988 {
2989 int32 prtfmt, prtwidth, force_unsign;
2990 struct expr_t *prtx;
2991
2992 prtfmt = BNONE;
2993 prtwidth = -1;
2994 force_unsign = FALSE;
2995 /* handle optional /[format letter] */
2996 __get_vtok();
2997 if (__toktyp == DIV)
2998 {
2999 __get_vtok();
3000 if (__toktyp == ID)
3001 {
3002 if (strlen(__token) > 1)
3003 {
3004 bad_prt_typ:
3005 __ia_err(1425, ":print type selector /%s illegal", __token);
3006 return;
3007 }
3008 switch (__token[0]) {
3009 case 'd': prtfmt = BDEC; break;
3010 case 'u': prtfmt = BDEC; force_unsign = TRUE; break;
3011 case 'o': prtfmt = BOCT; break;
3012 case 'b': prtfmt = BBIN; break;
3013 case 'h': case 'x': prtfmt = BHEX; break;
3014 case 's': prtfmt = BSTR; break;
3015 case 'c': prtfmt = BCHAR; break;
3016 default: goto bad_prt_typ;
3017 }
3018 }
3019 else
3020 {
3021 __ia_err(1426,
3022 ":print type selector / not followed by format letter - %s read",
3023 __prt_vtok());
3024 return;
3025 }
3026 __get_vtok();
3027 }
3028 /* handle optional #<width> */
3029 if (__toktyp == SHARP)
3030 {
3031 __get_vtok();
3032 if (__toktyp != NUMBER || __itoklen > WBITS || __bcwrk[0] != 0L)
3033 {
3034 __ia_err(1427, ":print width override # not followed by legal number");
3035 return;
3036 }
3037 prtwidth = (int32) __acwrk[0];
3038 __get_vtok();
3039 }
3040 /* if collect returns F, if NULL, know error emitted in routine */
3041 /* notice here if value, cannot free - need the iatok ptr allocated value */
3042 if ((prtx = __rd_iact_expr()) == NULL) return;
3043 /* know this will fit in RECLEN and truncates for readabililty for */
3044 /* very wide values */
3045 dbg_bld_expr_val(__xs, prtx, prtfmt, prtwidth, force_unsign);
3046 __cvsim_msg("%s\n", __xs);
3047
3048 /* can free expr. */
3049 __free_xtree(prtx);
3050 __chk_extra_atend(TRUE);
3051 }
3052
3053 /*
3054 * print an expression value for :print or :display commands
3055 */
dbg_bld_expr_val(char * s,struct expr_t * prtx,int32 prtfmt,int32 prtwidth,int32 force_unsign)3056 static char *dbg_bld_expr_val(char *s, struct expr_t *prtx, int32 prtfmt,
3057 int32 prtwidth, int32 force_unsign)
3058 {
3059 int32 blen;
3060 word32 av, bv;
3061 double d1;
3062 struct xstk_t *xsp;
3063 char s1[IDLEN];
3064
3065 /* strength only emitted if no strength override */
3066 if (prtx->x_stren && prtfmt == BNONE && prtwidth == -1)
3067 { __strenexpr_tostr(s, prtx); return(s); }
3068
3069 xsp = __eval_xpr(prtx);
3070 /* always print real as double - can use system task to get bit pattern */
3071 if (prtx->is_real)
3072 {
3073 memmove(&d1, xsp->ap, sizeof(double));
3074 sprintf(s, "%g", d1);
3075 goto do_prt;
3076 }
3077
3078 /* print as character ignore any print width */
3079 if (prtfmt == BCHAR)
3080 {
3081 /* if has x/z, print as 8 bit binary x/z value */
3082 av = xsp->ap[0] & 0xff;
3083 bv = xsp->bp[0] & 0xff;
3084 if (bv != 0)
3085 {
3086 __regab_tostr(s1, &av, &bv, 8, BBIN, FALSE);
3087 sprintf(s, "char: [%s]", s1);
3088 }
3089 /* if non printable, print as escaped */
3090 /* SJM 09/19/03 - must also print new line and tab - isprint does */
3091 /* not include new line and tab etc. */
3092 else if (isprint(av) || av == '\n' || av == '\r' || av == '\t')
3093 sprintf(s, "\\%x", (int32) av);
3094 else sprintf(s, "%c", (char) av);
3095 goto do_prt;
3096 }
3097 /* force print as string */
3098 if (prtfmt == BSTR)
3099 {
3100 /* if explicit width use it and do not trim, else trim leading 0's */
3101 if (prtwidth == -1) blen = __trim1_0val(xsp->ap, xsp->xslen);
3102 else blen = prtwidth;
3103 /* convert to string with escape octal for non printable */
3104 __strab_tostr(s, xsp->ap, blen, FALSE, FALSE);
3105 goto do_prt;
3106 }
3107 /* finally print according to values */
3108 if (prtwidth == -1) blen = xsp->xslen; else blen = prtwidth;
3109 if (prtfmt == BNONE) prtfmt = __dbg_dflt_base;
3110 __regab2_tostr(s, xsp->ap, xsp->bp, blen, prtfmt,
3111 (!force_unsign) ? TRUE : FALSE, (prtwidth == -1) ? TRUE : FALSE);
3112
3113 do_prt:
3114 __pop_xstk();
3115 return(s);
3116 }
3117
3118 /*
3119 * read and parse an interactive debugger expression
3120 * expects first token to have been read
3121 * this must be run in right scope
3122 */
__rd_iact_expr(void)3123 extern struct expr_t *__rd_iact_expr(void)
3124 {
3125 int32 sav_err_cnt;
3126 struct expr_t *xp;
3127
3128 if (!__colto_eol()) return(NULL);
3129 /* LOOKATME - needed because iact errors counted - maybe should not */
3130 sav_err_cnt = __pv_err_cnt;
3131 __bld_xtree(0);
3132 xp = __root_ndp;
3133 /* if already error, do not check expr. */
3134 if (__pv_err_cnt == sav_err_cnt) __chk_rhsexpr(xp, 0);
3135 if (__pv_err_cnt != sav_err_cnt)
3136 {
3137 __ia_err(1423, "invalid syntax in debugger expression");
3138 return(NULL);
3139 }
3140 return(xp);
3141 }
3142
3143 /*
3144 * for debugger collect expression to end of line
3145 * expects 1st token to have been read
3146 * if in file or interactive tty, same eof on end of line
3147 */
__colto_eol(void)3148 extern int32 __colto_eol(void)
3149 {
3150 for (__last_xtk = -1;;)
3151 {
3152 if (__toktyp == TEOF) return(TRUE);
3153 if (__toktyp == SEMI)
3154 {
3155 __ia_err(1487, "semicolon illegal end of interactive expression");
3156 goto bad_end;
3157 }
3158 if (!__bld_expnode()) goto bad_end;
3159 __get_vtok();
3160 }
3161
3162 bad_end:
3163 __set_xtab_errval();
3164 return(FALSE);
3165 }
3166
3167 /*
3168 * ROUTINES TO IMPLEMENT DISPLAY COMMANDS
3169 */
3170
3171 /*
3172 * set up display of expr on any interactive entry - know :display read
3173 *
3174 * always print on start
3175 * format - :display/[d,u,b,h(x),s,c]#[bits] <expr>
3176 */
dbg_display(void)3177 static void dbg_display(void)
3178 {
3179 int32 prtfmt, prtwidth, force_unsign;
3180 struct expr_t *prtx;
3181 struct dispx_t *dxp;
3182
3183 __get_vtok();
3184 if (__toktyp == TEOF)
3185 {
3186 /* display all current non disable display expressions */
3187 prt_all_disp_exprs();
3188 return;
3189 }
3190
3191 prtfmt = BNONE;
3192 prtwidth = -1;
3193 force_unsign = FALSE;
3194 if (__toktyp == DIV)
3195 {
3196 __get_vtok();
3197 if (__toktyp == ID)
3198 {
3199 if (strlen(__token) > 1)
3200 {
3201 bad_prt_typ:
3202 __ia_err(1425, ":display type selector /%s illegal", __token);
3203 return;
3204 }
3205 switch (__token[0]) {
3206 case 'd': prtfmt = BDEC; break;
3207 case 'u': prtfmt = BDEC; force_unsign = TRUE; break;
3208 case 'o': prtfmt = BOCT; break;
3209 case 'b': prtfmt = BBIN; break;
3210 case 'h': case 'x': prtfmt = BHEX; break;
3211 case 's': prtfmt = BSTR; break;
3212 case 'c': prtfmt = BCHAR; break;
3213 default: goto bad_prt_typ;
3214 }
3215 }
3216 else
3217 {
3218 __ia_err(1426,
3219 ":display type selector / not followed by format letter - %s read",
3220 __prt_vtok());
3221 return;
3222 }
3223 __get_vtok();
3224 }
3225 /* handle optional #<width> */
3226 if (__toktyp == SHARP)
3227 {
3228 __get_vtok();
3229 if (__toktyp != NUMBER || __itoklen > WBITS || __bcwrk[0] != 0L)
3230 {
3231 __ia_err(1427, ":display width override # not followed by legal number");
3232 return;
3233 }
3234 prtwidth = (int32) __acwrk[0];
3235 __get_vtok();
3236 }
3237 /* if collect returns F, if NULL, know error emitted in routine */
3238 /* notice here if value, cannot free - need the iatok ptr allocated value */
3239 if ((prtx = __rd_iact_expr()) == NULL) return;
3240
3241 /* add to display list but do not print anything */
3242 dxp = (struct dispx_t *) __my_malloc(sizeof(struct dispx_t));
3243 dxp->dsp_enable = TRUE;
3244 dxp->dsp_frc_unsign = force_unsign;
3245 dxp->dsp_num = __nxt_dispxnum++;
3246 dxp->dsp_prtfmt = prtfmt;
3247 dxp->dsp_prtwidth = prtwidth;
3248 dxp->dsp_xp = prtx;
3249 /* need to eval. in this instance (or use as start pt. for xmr) */
3250 dxp->dsp_itp = __inst_ptr;
3251 dxp->dsp_tskp = __scope_tskp;
3252 /* behavior is to print last first so need to put on front */
3253 dxp->dsp_nxt = __dispxhdr;
3254 __dispxhdr = dxp;
3255 __chk_extra_atend(TRUE);
3256 }
3257
3258 /*
3259 * print all expressions for display - prints nothing if none
3260 */
prt_all_disp_exprs(void)3261 static void prt_all_disp_exprs(void)
3262 {
3263 struct dispx_t *dxp;
3264 char s1[RECLEN];
3265
3266 for (dxp = __dispxhdr; dxp != NULL; dxp = dxp->dsp_nxt)
3267 {
3268 /* if disabled, do not print anything */
3269 if (!dxp->dsp_enable) continue;
3270
3271 __push_itstk(dxp->dsp_itp);
3272 dbg_bld_expr_val(__xs, dxp->dsp_xp, dxp->dsp_prtfmt,
3273 dxp->dsp_prtwidth, (dxp->dsp_frc_unsign) ? TRUE : FALSE);
3274 __cvsim_msg("%d:%s %s = %s\n", dxp->dsp_num,
3275 bld_prtbasecode(s1, dxp->dsp_prtfmt, (dxp->dsp_frc_unsign) ? TRUE : FALSE,
3276 dxp->dsp_prtwidth), __msgexpr_tostr(__xs2, dxp->dsp_xp), __xs);
3277 __pop_itstk();
3278 }
3279 }
3280
3281 /*
3282 * convert debug base code and width to string or empty string if none
3283 */
bld_prtbasecode(char * s,int32 bcod,int32 force_unsign,int32 prtwidth)3284 static char *bld_prtbasecode(char *s, int32 bcod, int32 force_unsign, int32 prtwidth)
3285 {
3286 char s1[RECLEN];
3287
3288 switch ((byte) bcod) {
3289 case BBIN: strcpy(s, " /b"); break;
3290 case BHEX: strcpy(s, " /x"); break;
3291 case BDEC:
3292 if (force_unsign) strcpy(s, " /u");
3293 else strcpy(s, " /d"); break;
3294 case BOCT: strcpy(s, " /o"); break;
3295 case BSTR: strcpy(s, " /s"); break;
3296 case BCHAR: strcpy(s, " /c"); break;
3297 case BNONE: strcpy(s, ""); break;
3298 default: strcpy(s, "?"); __case_terr(__FILE__, __LINE__);
3299 }
3300 if (prtwidth == -1) return(s);
3301 strcpy(s1, s);
3302 sprintf(s, "%s #%d", s1, prtwidth);
3303 return(s);
3304 }
3305
3306 /*
3307 * MISCELLANEOUS DEBUGGER EXPRESSION ROUTINES
3308 */
3309
3310 /*
3311 * emit description of expression information
3312 * notice expression must be variable not scope - no way to parse and
3313 * distinguish case where numeric expr. or scope can be mixed in Verilog
3314 */
do_dbg_expris(void)3315 static void do_dbg_expris(void)
3316 {
3317 struct expr_t *prtx;
3318 char s1[RECLEN];
3319
3320 __get_vtok();
3321 if ((prtx = __rd_iact_expr()) == NULL) return;
3322 __cvsim_msg("%s\n", bld_expr_telltale(s1, prtx));
3323 __chk_extra_atend(TRUE);
3324 }
3325
3326 /*
3327 * build an expression tell tale
3328 */
bld_expr_telltale(char * s,struct expr_t * xp)3329 static char *bld_expr_telltale(char *s, struct expr_t *xp)
3330 {
3331 sprintf(s, "<top operator %s width %d", __to_opname(xp->optyp),
3332 xp->szu.xclen);
3333 if (xp->has_sign) strcat(s, " signed");
3334 if (xp->optyp == NUMBER || xp->optyp == ISNUMBER)
3335 {
3336 if (xp->is_string) strcat(s, " string");
3337 if (!xp->unsiznum) strcat(s, " explicit width");
3338 if (xp->sizdflt) strcat(s, " default width");
3339 }
3340 if (xp->is_real) strcat(s, " real");
3341 if (xp->x_multfi) strcat(s, " fi>1 or tran wire");
3342 if (xp->x_stren) strcat(s, " has strength wire");
3343 if (xp->tf_isrw) strcat(s, " tf_ argument lvalue");
3344 if (xp->locqualnam) strcat(s, " local qualified name");
3345 strcat(s, ">");
3346 return(s);
3347 }
3348
3349 /*
3350 * emit description of variable information
3351 */
do_dbg_varis(void)3352 static void do_dbg_varis(void)
3353 {
3354 struct net_t *np;
3355 struct expr_t *prtx;
3356 struct sy_t *scope_syp;
3357
3358 __get_vtok();
3359 if ((prtx = __rd_iact_expr()) == NULL) return;
3360 if (prtx->optyp != ID)
3361 {
3362 __ia_err(1465, ":varis argument %s illegal - must be variable name",
3363 __msgexpr_tostr(__xs, prtx));
3364 return;
3365 }
3366 np = prtx->lu.sy->el.enp;
3367 if (__last_iasytp == NULL) __misc_terr(__FILE__, __LINE__);
3368 scope_syp = __last_iasytp->sypofsyt;
3369 print_iddecl_ref(np->nsym, scope_syp);
3370 __chk_extra_atend(TRUE);
3371 }
3372
3373 /*
3374 * print out a variable information line
3375 *
3376 * for module or system tf, scope is nil
3377 * for variable, scope is declaration symbol table (mod or task)
3378 * for user task/funct, scope is containing module (or task/func/named block)
3379 * for symbol declared in named block
3380 */
print_iddecl_ref(struct sy_t * syp,struct sy_t * scope_syp)3381 static void print_iddecl_ref(struct sy_t *syp, struct sy_t *scope_syp)
3382 {
3383 int32 nd_inst;
3384 struct net_t *np;
3385 struct mod_t *mdp;
3386 struct symtab_t *sytp;
3387 struct task_t *tskp;
3388 char s1[RECLEN], s2[RECLEN], s3[RECLEN];
3389
3390 mdp = NULL;
3391 np = NULL;
3392 tskp = NULL;
3393 nd_inst = TRUE;
3394 switch ((byte) syp->sytyp) {
3395 case SYM_M: case SYM_PRIM: case SYM_UDP: case SYM_STSK: case SYM_SF:
3396 /* DBG remove --- */
3397 if (scope_syp != NULL) __arg_terr(__FILE__, __LINE__);
3398 /* --- */
3399 nd_inst = FALSE;
3400 sprintf(s1, "%s %s", __to_sytyp(s2, syp->sytyp), syp->synam);
3401 if (syp->sy_giabase) strcat(s1, " (array of primitives base)");
3402 break;
3403 case SYM_I: case SYM_TSK: case SYM_F:
3404 /* DBG remove --- */
3405 if (scope_syp == NULL) __arg_terr(__FILE__, __LINE__);
3406 /* --- */
3407 sprintf(s1, "%s %s", __to_sytyp(s2, syp->sytyp), syp->synam);
3408 if (syp->sy_giabase) strcat(s1, " (instance array base)");
3409 if (scope_syp->sytyp == SYM_M) mdp = scope_syp->el.emdp;
3410 else mdp = scope_syp->el.eip->imsym->el.emdp;
3411 break;
3412 case SYM_LB:
3413 /* DBG remove --- */
3414 if (scope_syp == NULL) __arg_terr(__FILE__, __LINE__);
3415 /* --- */
3416 sprintf(s1, "%s %s", __to_sytyp(s2, syp->sytyp), syp->synam);
3417 /* for named block, can be inside task or other named block */
3418 if (scope_syp->sytyp == SYM_M) mdp = scope_syp->el.emdp;
3419 else
3420 {
3421 tskp = scope_syp->el.etskp;
3422 for (sytp = tskp->tsksymtab;; sytp = sytp->sytpar)
3423 {
3424 /* DBG remove --- */
3425 if (sytp == NULL) __misc_terr(__FILE__, __LINE__);
3426 /* --- */
3427 if (sytp->sypofsyt->sytyp == SYM_M) break;
3428 }
3429 mdp = sytp->sypofsyt->el.emdp;
3430 }
3431 break;
3432 case SYM_N:
3433 /* DBG remove --- */
3434 if (scope_syp == NULL) __arg_terr(__FILE__, __LINE__);
3435 /* --- */
3436 np = syp->el.enp;
3437 __bld_showvars_prefix(s1, np, NULL);
3438 if (scope_syp->sytyp == SYM_M) mdp = scope_syp->el.emdp;
3439 else
3440 {
3441 tskp = scope_syp->el.etskp;
3442 for (sytp = tskp->tsksymtab;; sytp = sytp->sytpar)
3443 {
3444 /* DBG remove --- */
3445 if (sytp == NULL) __misc_terr(__FILE__, __LINE__);
3446 /* --- */
3447 if (sytp->sypofsyt->sytyp == SYM_M) break;
3448 }
3449 mdp = sytp->sypofsyt->el.emdp;
3450 }
3451 break;
3452 default: __case_terr(__FILE__, __LINE__);
3453 }
3454 if (scope_syp == NULL) { __cvsim_msg(" %s (top level object)\n", s1); }
3455 else
3456 {
3457 __cvsim_msg("%s in %s %s %s\n", s1,
3458 __to_sytyp(s2, scope_syp->sytyp), scope_syp->synam,
3459 __bld_lineloc(s3, syp->syfnam_ind, syp->sylin_cnt));
3460 if (nd_inst)
3461 {
3462 __cvsim_msg(" [one instance: %s.%s]\n",
3463 __msg_blditree(s2, mdp->moditps[0], tskp), syp->synam);
3464 }
3465 }
3466 }
3467
3468 /*
3469 * emit information on every declaration of variable
3470 */
do_dbg_whatis(void)3471 static void do_dbg_whatis(void)
3472 {
3473 register struct mod_t *mdp;
3474 register struct task_t *tskp;
3475 int32 not_defed;
3476 struct sy_t *syp;
3477
3478 not_defed = TRUE;
3479 __get_vtok();
3480 if (__toktyp != ID)
3481 {
3482 __ia_err(1465, ":whatis argument %s illegal - must be legal identifier",
3483 __prt_vtok());
3484 return;
3485 }
3486 /* first look in top level symbol tables (top level object) */
3487 if ((syp = __get_sym(__token, __modsyms)) != NULL)
3488 { print_iddecl_ref(syp, (struct sy_t *) NULL); not_defed = FALSE; }
3489
3490 /* look in system functions and tasks */
3491 if ((syp = __get_sym(__token, __syssyms)) != NULL)
3492 { print_iddecl_ref(syp, (struct sy_t *) NULL); not_defed = FALSE; }
3493
3494 /* next look in each module's symbol table */
3495 for (mdp = __modhdr; mdp != NULL; mdp = mdp->mnxt)
3496 {
3497 if ((syp = __get_sym(__token, mdp->msymtab)) != NULL)
3498 {
3499 print_iddecl_ref(syp, mdp->msym);
3500 not_defed = FALSE;
3501 }
3502 }
3503 /* finally look at tasks and functions in every module */
3504 for (mdp = __modhdr; mdp != NULL; mdp = mdp->mnxt)
3505 {
3506 for (tskp = mdp->mtasks; tskp != NULL; tskp = tskp->tsknxt)
3507 {
3508 if ((syp = __get_sym(__token, tskp->tsksymtab)) != NULL)
3509 {
3510 print_iddecl_ref(syp, tskp->tsksyp);
3511 not_defed = FALSE;
3512 }
3513 }
3514 }
3515 if (not_defed) __cvsim_msg("%s undefined\n", __token);
3516 __chk_extra_atend(TRUE);
3517 }
3518
3519 /*
3520 * ROUTINES TO IMPLEMENT VPI_ SIM CONTROL INTERACTIVE ROUTINES
3521 */
3522
3523 /*
3524 * execute $stop (schedule it) from user vpi_ code
3525 */
__do_vpi_stop(int32 diag_level)3526 extern int32 __do_vpi_stop(int32 diag_level)
3527 {
3528 if (__no_iact)
3529 {
3530 __emit_vpi_noiact_warn();
3531 return(TRUE);
3532 }
3533 if (__iact_state)
3534 {
3535 __emit_vpi_iniact_warn();
3536 return(FALSE);
3537 }
3538 if (diag_level >= 1)
3539 {
3540 if (!__quiet_msgs) __cv_msg("\n");
3541 __cv_msg("vpi_control vpiStop executed at time %s.\n",
3542 __to_timstr(__xs, &__simtime));
3543 }
3544 if (diag_level >= 2) __emit_stsk_endmsg();
3545
3546 /* must leave signal on - if ^c hit before stop, same effect */
3547 /* but entry reason different and lost */
3548 __pending_enter_iact = TRUE;
3549 __iact_reason = IAER_STOP;
3550 return(TRUE);
3551 }
3552
3553 /*
3554 * do a reset from user vpi_ code (it's immediate)
3555 */
__do_vpi_reset(int32 stop_val,int32 reset_val,int32 diag_level)3556 extern void __do_vpi_reset(int32 stop_val, int32 reset_val, int32 diag_level)
3557 {
3558 int32 enter_iact;
3559
3560 if (diag_level >= 1)
3561 {
3562 if (!__quiet_msgs) __cv_msg("\n");
3563 __cv_msg("vpi_control vpiReset executed at time %s.\n",
3564 __to_timstr(__xs, &__simtime));
3565 }
3566 if (diag_level >= 2) __emit_stsk_endmsg();
3567
3568 /* enter interactive unless reset value non zero */
3569 if (stop_val != 0) enter_iact = FALSE; else enter_iact = TRUE;
3570 if (enter_iact) __stop_before_sim = TRUE; else __stop_before_sim = FALSE;
3571
3572 /* record state changes caused by arguments */
3573 __reset_value = reset_val;
3574
3575 /* reenable the normal ^c signal handler - when variables reset */
3576 /* sim will replace with sim handler for entering interactive */
3577 #if defined(INTSIGS)
3578 signal(SIGINT, __comp_sigint_handler);
3579 #else
3580 signal(SIGINT, (void (*)()) __comp_sigint_handler);
3581 #endif
3582
3583 /* this does not return - uses lng jmp */
3584 longjmp(__reset_jmpbuf, 1);
3585 }
3586