1 /* Copyright (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 
19    We are selling our new Verilog compiler that compiles to X86 Linux
20    assembly language.  It is at least two times faster for accurate gate
21    level designs and much faster for procedural designs.  The new
22    commercial compiled Verilog product is called CVC.  For more information
23    on CVC visit our website at www.pragmatic-c.com/cvc.htm or contact
24    Andrew at avanvick@pragmatic-c.com
25 
26  */
27 
28 
29 /*
30  * debugger - 2nd file most listing and break point routines
31  */
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 
43 #include <signal.h>
44 
45 #ifdef __DBMALLOC__
46 #include "../malloc.h"
47 #endif
48 
49 /* REMOVEME - no longer supporting SunOS - maybe needed for hpux? */
50 #if defined(__sparc) && !defined(__SVR4) && !defined(__FreeBSD__)
51 extern int32 tolower(int32);
52 extern int32 sscanf(char *, char *, ...);
53 #endif
54 
55 #include "v.h"
56 #include "cvmacros.h"
57 
58 /* local prototypes */
59 static void get_middle_linrng(int32, int32 *, int32 *);
60 static struct incloc_t *find_incloc(register int32);
61 static int32 change_srcfile(int32);
62 static int32 get_lastfillin(int32);
63 static int32 bld_filpostab(int32);
64 static void prt_brkpts(void);
65 static char *to_brkptnam(char *, word32);
66 static char *to_basename(char *, int32);
67 static void dbg_info_disp(void);
68 static int32 parse_scope_ref(struct itree_t **, struct task_t **, int32 *,
69  int32 *, int32 *);
70 static int32 try_get_fillin_ref(char *, int32 *, int32 *, char **, char **);
71 static int32 local_scope_ref(char *, struct itree_t **, struct task_t **);
72 static int32 find_infil_ind(char *);
73 static int32 fil_lin_toscope(int32, int32, struct itree_t **, struct task_t **);
74 static int32 scope_lini_inrng(int32, int32, int32, int32, int32, int32);
75 static struct incloc_t *find2_incloc(int32);
76 static void set_scope_loc(struct itree_t *, struct task_t *, int32 *, int32 *);
77 static int32 get_ibrk_linref(struct itree_t *, struct task_t *, int32 *, int32 *);
78 static void init_brkpt(struct brkpt_t *);
79 static void insert_brkpt(struct brkpt_t *);
80 static struct st_t *conv_line_tostmt(struct mod_t *, struct task_t *, int32,
81  int32);
82 static struct st_t *find_nxtstp(struct st_t *, int32, int32);
83 static struct st_t *find_lstofsts_stp(struct st_t *, int32, int32);
84 static struct incloc_t *find3_incloc(int32, int32);
85 static struct st_t *find_case_stp(struct st_t *, int32, int32);
86 static struct st_t *find_afterdflt(struct csitem_t *);
87 static void del_all_brkpts(void);
88 static void del_brkpt_num(int32);
89 static int32 cnt_same_brkpts(int32, int32, struct brkpt_t **);
90 static void del_all_disps(void);
91 static void del_disp_num(void);
92 static struct brkpt_t *rd_brkpt_num(char *, int32);
93 static struct brkpt_t *find_bpp(int32);
94 static int32 elim_brkpt_fromcond(struct brkpt_t *);
95 static void reinit_vars_and_state(void);
96 static void wr_1ev_trace(int32, i_tev_ndx);
97 static void fill_near_evtab(int32, int32);
98 static struct telhdr_t *tfind_btnode_after(struct bt_t *, word64);
99 static int32 try_add_wrkevtab(i_tev_ndx, int32, int32 *, int32);
100 static int32 get_var_scope(struct itree_t **, struct task_t **, int32 *);
101 
102 /* extern prototypes (maybe defined in this module) */
103 extern void __do_scope_list(void);
104 extern void __do_dbg_list(void);
105 extern void __prt_src_lines(int32, int32, int32);
106 extern void __do_dbg_set(void);
107 extern int32 __get_dbg_val(void);
108 extern void __do_dbg_info(void);
109 extern void __do_dbg_scope(void);
110 extern void __set_dbentry_listline(void);
111 extern void __set_scopchg_listline(void);
112 extern void __do_dbg_history(void);
113 extern void __do_dbg_emptyhistory(void);
114 extern int32 __do_dbg_nextb(void);
115 extern void __do_dbg_brkpt(int32);
116 extern void __do_dbg_ibrkpt(int32);
117 extern void __do_dbg_delbrkdis(void);
118 extern void __dbg_undisplay(void);
119 extern void __do_dbg_dis_enable(int32);
120 extern void __dbg_brk_ignore(void);
121 extern void __dbg_brk_cond(void);
122 extern int32 __process_brkpt(struct st_t *);
123 extern void __reset_to_time0(void);
124 extern void __write_snapshot(int32);
125 extern void __prt_where_msg(register struct thread_t *);
126 extern void __dmp_tskthrds(void);
127 extern void __dmp_tskthd(struct task_t *, struct mod_t *);
128 extern void __dmp_initalw_thrd_tree(void);
129 extern void __dmp_thrd_tree(register struct thread_t *);
130 extern void __dmp_thrd_info(struct thread_t *);
131 extern void __dmp_all_thrds(void);
132 
133 extern char *__msg_blditree(char *, struct itree_t *, struct task_t *);
134 extern void __get_vtok(void);
135 extern char *__prt_vtok(void);
136 extern int32 __chk_extra_atend(int32);
137 extern int32 __tilde_open(char *, int32);
138 extern void __my_free(char *, int32);
139 extern char *__my_malloc(int32);
140 extern char *__my_realloc(char *, int32, int32);
141 extern int32 __get_dbcmdnum(char *, struct namlst_t *, int32);
142 extern char *__bld_ambiguous_list(char *, char *, struct namlst_t *, int32);
143 extern char *__schop(char *, char *);
144 extern char *__to_tsktyp(char *, word32);
145 extern char *__msgexpr_tostr(char *, struct expr_t *);
146 extern void __call_misctfs_scope(void);
147 extern void __vpi_iactscopechg_trycall(void);
148 extern struct sy_t *__get_sym(char *, struct symtab_t *);
149 extern int32 __is_scope_sym(struct sy_t *);
150 extern void __xmrpush_refgrp_to_targ(struct gref_t *);
151 extern void __exec_history_list(int32);
152 extern struct task_t *__find_thrdtsk(struct thread_t *);
153 extern char *__bld_lineloc(char *, word32, int32);
154 extern char *__msg2_blditree(char *, struct itree_t *);
155 extern struct expr_t *__rd_iact_expr(void);
156 extern int32 __colto_eol(void);
157 extern void __bld_xtree(int32);
158 extern void __free_xtree(struct expr_t *);
159 extern char *__to_timstr(char *, word64 *);
160 extern struct xstk_t *__eval2_xpr(register struct expr_t *);
161 extern int32 __cvt_lngbool(word32 *, word32 *, int32);
162 extern void __free_thd_list(struct thread_t *);
163 extern void __free_1thd(struct thread_t *);
164 extern void __do_iact_disable(struct hctrl_t *, int32);
165 extern void __free_telhdr_tevs(register struct telhdr_t *);
166 extern void __free_btree(struct bt_t *);
167 extern void __free_1tev(i_tev_ndx);
168 extern char *__pv_stralloc(char *);
169 extern void __my_fclose(FILE *);
170 extern void __my_close(int32);
171 extern void __reinit_tfrecs(void);
172 extern void __reinit_vpi(void);
173 extern void __reinit_sim(void);
174 extern void __reinitialize_vars(struct mod_t *);
175 extern void __initialize_dces(struct mod_t *);
176 extern void __set_init_gstate(struct gate_t *, int32, int32);
177 extern void __set_nchgaction_bits(void);
178 extern void __set_init_udpstate(struct gate_t *, int32, int32);
179 extern void __allocinit_perival(union pck_u *, int32, int32, int32);
180 extern void __reinit_mipd(struct mod_pin_t *, struct mod_t *);
181 extern char *__gstate_tostr(char *, struct gate_t *, int32);
182 extern char *__to_evtrcanam(char *, struct conta_t *, struct itree_t *);
183 extern void __grow_xstk(void);
184 extern void __chg_xstk_width(struct xstk_t *, int32);
185 extern void __ld_perinst_val(register word32 *, register word32 *, union pck_u,
186  int32);
187 extern void __st_standval(register byte *, register struct xstk_t *, byte);
188 extern char *__st_regab_tostr(char *, byte *, int32);
189 extern char *__regab_tostr(char *, word32 *, word32 *, int32, int32, int32);
190 extern char *__bld_valofsched(char *, struct tev_t *);
191 extern char *__to_evtrwnam(char *, struct net_t *, int32, int32, struct itree_t *);
192 extern char *__to_vvstnam(char *, word32);
193 extern void __ld_bit(register word32 *, register word32 *,
194  register struct net_t *, int32);
195 extern char *__to_vvnam(char *, word32);
196 extern char *__to_mpnam(char *, char *);
197 extern char *__xregab_tostr(char *, word32 *, word32 *, int32, struct expr_t *);
198 extern char *__get_tfcellnam(struct tfrec_t *);
199 extern char *__to_tetyp(char *, word32);
200 extern char *__to_dcenam(char *, word32);
201 extern char *__to_sytyp(char *, word32);
202 extern void __init_mod(struct mod_t *, struct sy_t *);
203 extern void __free_1glb_flds(struct gref_t *);
204 extern void __push_wrkitstk(struct mod_t *, int32);
205 extern void __pop_wrkitstk(void);
206 extern char *__to_ptnam(char *, word32);
207 
208 extern void __cv_msg(char *, ...);
209 extern void __cvsim_msg(char *, ...);
210 extern void __cvsim2_msg(char *, ...);
211 extern void __dbg_msg(char *, ...);
212 extern void __arg_terr(char *, int32);
213 extern void __case_terr(char *, int32);
214 extern void __misc_terr(char *, int32);
215 extern void __ia_err(int32 id_num, char *s, ...);
216 
217 extern char __pv_ctab[];
218 
219 /*
220  * ROUTINES TO IMPLEMENT SOURCE LISTING
221  */
222 
223 /*
224  * do the entire scope list for $list command
225  * know current scope needs to be listed - caller set and restores
226  *
227  * leave list line at end but if different scope form will be restored there
228  */
__do_scope_list(void)229 extern void __do_scope_list(void)
230 {
231  register int32 ifi;
232  int32 fr_ifi, to_ifi, fr_lini, to_lini, maxlini;
233  struct mod_t *mdp;
234 
235  if (__scope_tskp != NULL)
236   {
237    fr_ifi = (int32) __scope_tskp->tsksyp->syfnam_ind;
238    fr_lini = __scope_tskp->tsksyp->sylin_cnt;
239    to_ifi = __scope_tskp->tsk_last_ifi;
240    to_lini =  __scope_tskp->tsk_last_lini;
241   }
242  else
243   {
244    mdp = __scope_ptr->itip->imsym->el.emdp;
245    fr_ifi = (int32) mdp->msym->syfnam_ind;
246    fr_lini = mdp->msym->sylin_cnt;
247    to_ifi = mdp->mod_last_ifi;
248    to_lini = mdp->mod_last_lini;
249   }
250  /* normal case - all in one file - current file will include scope by here */
251 
252  if (fr_ifi == to_ifi)
253   {
254    __cvsim_msg("  Listing \"%s\" type %s file: %s\n",
255     __msg_blditree(__xs, __scope_ptr, __scope_tskp),
256     __scope_ptr->itip->imsym->synam, __in_fils[fr_ifi]);
257    __prt_src_lines(fr_ifi, fr_lini, to_lini);
258    return;
259   }
260 
261  __cvsim_msg("  File: %s\n", __in_fils[fr_ifi]);
262  if ((maxlini = get_lastfillin(fr_ifi)) == -1) return;
263  __prt_src_lines(fr_ifi, fr_lini, maxlini);
264  /* print intermediate files */
265  for (ifi = fr_ifi + 1; ifi < to_ifi; ifi++)
266   {
267    __cvsim_msg("  File: %s\n", __in_fils[ifi]);
268    if ((maxlini = get_lastfillin(ifi)) == -1) return;
269    __prt_src_lines(ifi, 1, maxlini);
270   }
271  __cvsim_msg("  File: %s\n", __in_fils[to_ifi]);
272  __prt_src_lines(to_ifi, 1, to_lini);
273  /* this leave current list line after last listed */
274 }
275 
276 /*
277  * execute a list command
278  * caller checks for any wrong extra characters at end
279  *
280  * current file is always file where header line of current scope is.
281  * can give explist [file]:num list - which does not change current file
282  * :l or ":l +" - list next ten lines (keep track of current list line)
283  * :l- (list 10 lines to previous first
284  * :l [+/-] number (list 10 lines with current in middle)
285  *   use :l +0 to list -5 to + 5 around current line
286  * :l [+/-][line1], [+/-][line2] or :l ,[+/-][line2] or :l [+/-][line1],
287  * :l ++/:l -- (move to next/prev. file)
288  * :l [file]:[line] (does not need to be in scope)
289  * :l [scope] (first line of scope)
290  *
291  * this does not change scope
292  */
__do_dbg_list(void)293 extern void __do_dbg_list(void)
294 {
295  int32 ltmp, lno1, lno2, rel_val, maxifi, maxlini, ifi, lini;
296  struct task_t *tskp;
297  struct itree_t *itp;
298  struct sy_t *syp;
299  struct incloc_t *ilp;
300  char *savchp, *endchp;
301 
302  rel_val = ' ';
303  /* here savchp is 1st char after leading white space - endchp first after */
304  /* return F on error, if is [file]:[line] form ifi not -1 */
305  if (!try_get_fillin_ref(__visp->vichp, &ifi, &lini, &savchp, &endchp))
306   return;
307 
308  /* [file]:[line] is lines around loc. */
309  if (ifi != -1)
310   {
311    if ((maxlini = get_lastfillin(ifi)) == -1) return;
312    if (lini > maxlini)
313     {
314      __ia_err(1469,
315       "[file]:[line] reference line number %d too large - %s has %d lines",
316       lini, __in_fils[ifi], maxlini);
317      return;
318     }
319    __visp->vichp = endchp;
320    __list_arg_lini = lini;
321    get_middle_linrng(lini, &lno1, &lno2);
322    __prt_src_lines(ifi, lno1, lno2);
323    goto done;
324   }
325 
326  /* parse from beginning of line */
327  __visp->vichp = savchp;
328  /* case 1: :l or ":l +" lists next 10 lines */
329  __get_vtok();
330  if (__toktyp == TEOF)
331   {
332 do_l:
333    /* here for :br, line current before list */
334    __list_arg_lini = __list_cur_lini;
335    __prt_src_lines(__list_cur_ifi, __list_cur_lini, __list_cur_lini
336     + __list_cur_listnum);
337    return;
338   }
339 
340  /* if starts with letter or _ or $ must be scope */
341  /* this is not around since want to see scope */
342  if (__toktyp == ID)
343   {
344    /* this reads xmr if needed */
345    if (!get_var_scope(&itp, &tskp, &ltmp)) return;
346 
347    if (tskp != NULL) syp = tskp->tsksyp; else syp = itp->itip->imsym;
348    ifi = (int32) syp->syfnam_ind;
349    lno1 = syp->sylin_cnt;
350    __list_arg_lini = lno1;
351    __prt_src_lines(ifi, lno1, lno1 + __list_cur_listnum + 1);
352    goto done;
353   }
354 
355  if (__toktyp == PLUS)
356   {
357    __get_vtok();
358 
359    /* :l ++ - move to next file if part of same scope - use task if set */
360    /* notice always have dbg current file and line */
361    if (__toktyp == PLUS)
362     {
363      /* if in include file exit to first included from place */
364      if ((ilp = find_incloc(__list_cur_ifi)) != NULL)
365       {
366        __list_arg_lini = ilp->incfrom_lcnt;
367        /* list from include line forward */
368        __prt_src_lines(ilp->incfrom_fnind, __list_arg_lini,
369         __list_arg_lini + __list_cur_listnum + 1);
370        goto done;
371       }
372 
373      maxifi = __last_srcf;
374      if (__list_cur_ifi >= maxifi)
375       {
376        __ia_err(1461, "':list ++' failed - no next source input file");
377        return;
378       }
379      /* notice this changes __list_cur_ifi and list cur fd if succeeds */
380      __list_arg_lini = 1;
381      __prt_src_lines(__list_cur_ifi + 1, 1, __list_cur_listnum + 1);
382      goto done;
383     }
384    if (__toktyp == TEOF) goto do_l;
385    rel_val = '+';
386   }
387  /* case 1a: "l -" lists previous 10 before the ten just listed */
388  else if (__toktyp == MINUS)
389   {
390    __get_vtok();
391    /* :l ++ - move to next file if part of same scope - use task if set */
392    /* notice always have dbg current file and line */
393    if (__toktyp == MINUS)
394     {
395      /* if in include file list back from first included from place */
396      if ((ilp = find_incloc(__list_cur_ifi)) != NULL)
397       {
398        __list_arg_lini = ilp->incfrom_lcnt - __list_cur_listnum;
399        if (__list_arg_lini < 1) __list_arg_lini = 1;
400        /* list from include line forward */
401        __prt_src_lines(ilp->incfrom_fnind, __list_arg_lini,
402         ilp->incfrom_lcnt);
403        goto done;
404       }
405 
406      /* first source file is 2 */
407      if (__list_cur_ifi <= 2)
408       {
409        __ia_err(1462, "':list --' failed - no previous source input file");
410        return;
411       }
412      maxlini = get_lastfillin(__list_cur_ifi - 1);
413      __list_arg_lini = maxlini - __list_cur_listnum;
414      if (__list_arg_lini < 1) __list_arg_lini = 1;
415      __prt_src_lines(__list_cur_ifi - 1, __list_arg_lini, maxlini);
416      goto done;
417     }
418    if (__toktyp == TEOF)
419     {
420      /* here :br argument is one before current line - place list ends */
421      ltmp = __list_cur_lini - 2*(__list_cur_listnum + 1);
422      __list_arg_lini = ltmp + __list_cur_listnum + 1;
423      if (__list_arg_lini < 1) __list_arg_lini = 1;
424      __prt_src_lines(__list_cur_ifi, ltmp, ltmp + __list_cur_listnum);
425      return;
426     }
427    rel_val = '-';
428   }
429 
430  /* know in current file */
431  maxlini = get_lastfillin(__list_cur_ifi);
432  if (__toktyp == COMMA)
433   {
434    if (rel_val != ' ')
435     {
436      __ia_err(1444, ":list command %c,[number] form illegal", rel_val);
437      return;
438     }
439    lno1 = -2;
440    goto get_2nd_rng;
441   }
442  /* get 1st range */
443  if ((ltmp = __get_dbg_val()) == -1)
444   {
445    __ia_err(1445, ":list command first range value %s illegal", __prt_vtok());
446    return;
447   }
448 
449  /* know dbg current line in range - silently fix relative lines */
450  if (rel_val == '-') lno1 = __list_cur_lini - ltmp;
451  else if (rel_val == '+') lno1 = __list_cur_lini + ltmp;
452  else
453   {
454    /* but fix line must be in range */
455    if (ltmp < 1 || ltmp > maxlini)
456     {
457 bad_lin_loc:
458      __ia_err(1463, ":list line %d impossible - %s has %d lines", ltmp,
459       __in_fils[__list_cur_ifi], maxlini);
460      return;
461     }
462    lno1 = ltmp;
463   }
464 
465  /* case 2: :l [+/-][number] form */
466  __get_vtok();
467  if (__toktyp == TEOF)
468   {
469    __list_arg_lini = lno1;
470    get_middle_linrng(lno1, &lno1, &lno2);
471    __prt_src_lines(__list_cur_ifi, lno1, lno2);
472    return;
473   }
474  if (__toktyp != COMMA)
475   {
476    __ia_err(1446,
477     ":list command line number range separator expected - %s read",
478     __prt_vtok());
479    return;
480   }
481  /* case 3: [num], form */
482 get_2nd_rng:
483  __get_vtok();
484  if (__toktyp == TEOF)
485   {
486    if (lno1 == -2)
487     {
488      __ia_err(1447,
489       ":list command line number range comma by itself illegal");
490      return;
491     }
492    lno2 = lno1 + __list_cur_listnum;
493    __list_arg_lini = lno1;
494    __prt_src_lines(__list_cur_ifi, lno1, lno2);
495    return;
496   }
497  if (__toktyp == PLUS || __toktyp == MINUS)
498   {
499    if (__toktyp == PLUS) rel_val = '+'; else rel_val = '-';
500    __get_vtok();
501   }
502  else rel_val = ' ';
503  /* get 2nd range */
504  if ((ltmp = __get_dbg_val()) == -1)
505   {
506    __ia_err(1448, ":list command second range value %s illegal", __prt_vtok());
507    return;
508   }
509  if (rel_val == '-') lno2 = __list_cur_lini - ltmp;
510  else if (rel_val == '+') lno2 = __list_cur_lini + ltmp - 1;
511  else
512   {
513    /* but fix line must be in range */
514    if (ltmp < 1 || ltmp > maxlini) goto bad_lin_loc;
515    lno2 = ltmp;
516   }
517  /* correct for ,[num] form */
518  if (lno1 == -1) lno1 = lno2 - __list_cur_listnum;
519  if (lno1 > lno2)
520   {
521    __ia_err(1464, ":list %d,%d - first range element larger than second",
522     lno1, lno2);
523    return;
524   }
525  __list_arg_lini = lno1;
526  __prt_src_lines(__list_cur_ifi, lno1, lno2);
527 
528 done:
529  /* if did not read eof, need to check for nothing els on line */
530  __chk_extra_atend(TRUE);
531 }
532 
533 /*
534  * compute range given line in middle and global number to list
535  */
get_middle_linrng(int32 mid,int32 * rng1,int32 * rng2)536 static void get_middle_linrng(int32 mid, int32 *rng1, int32 *rng2)
537 {
538  int32 ltmp;
539 
540  if ((__list_cur_listnum % 2) == 0) ltmp = mid - __list_cur_listnum/2;
541  else ltmp = mid - __list_cur_listnum/2 - 1;
542  *rng1 = ltmp;
543  *rng2 = ltmp + __list_cur_listnum;
544 }
545 
546 /*
547  * given an in_fils index that may be included find included loc record
548  * returns nil if not included file
549  */
find_incloc(register int32 ifi)550 static struct incloc_t *find_incloc(register int32 ifi)
551 {
552  register struct incloc_t *ilp;
553 
554  for (ilp = __inclst_hdr; ilp != NULL; ilp = ilp->inclocnxt)
555   if (ilp->inc_fnind == ifi) return(ilp);
556  return(NULL);
557 }
558 
559 /*
560  * print from frlini to stoplini in file fd (will open if needed)
561  * this uses same logic as gnu gdb list command
562  *
563  * frlini starts at 1 for first line
564  * for listing of multiple files, caller must decompose
565  * FIXME - need to output OS returned message
566  */
__prt_src_lines(int32 ifi,int32 frlini,int32 stoplini)567 extern void __prt_src_lines(int32 ifi, int32 frlini, int32 stoplini)
568 {
569  register int32 c;
570  int32 ctrlc_stop, nlines, cnt;
571  char ctab[8];
572  struct filpos_t *fposp;
573 
574  /* no source printing from interactive history event */
575  /* DBG remove --- */
576  if (ifi == 1) __arg_terr(__FILE__, __LINE__);
577  /* --- */
578  /* *** if (ifi == 1) return; */
579 
580  /* change source file if needed */
581  if (__list_cur_ifi != ifi)
582   {
583    /* this emits error on file problem */
584    if (!change_srcfile(ifi)) return;
585   }
586  if (stoplini - frlini > 20) ctrlc_stop = TRUE; else ctrlc_stop = FALSE;
587 
588  /* know file line start pos. cache built and current file open to get here */
589  fposp = &(__filpostab[__list_cur_ifi]);
590 
591  /* adjust range, if absolute line list argument, must check above */
592  if (frlini < 1) frlini = 1;
593  if (stoplini < 1) stoplini = 1;
594  if (stoplini > fposp->nlines) stoplini = fposp->nlines;
595  if (frlini > fposp->nlines) frlini = fposp->nlines;
596  __list_cur_lini = frlini;
597  /* notice 0 means 1 line */
598  nlines = stoplini - frlini;
599 
600  /* seek to line */
601  if ((cnt = lseek(__list_cur_fd, (off_t) fposp->lpostab[__list_cur_lini - 1],
602    0)) < 0)
603   {
604    __ia_err(1437, "unable to locate source line %d in %s",
605      frlini, __in_fils[__list_cur_ifi]);
606    return;
607   }
608 
609  while (nlines-- >= 0)
610   {
611    if ((cnt = read(__list_cur_fd, ctab, 1)) != 1) break;
612    __cvsim_msg("%d\t", __list_cur_lini++);
613 
614    do {
615     c = ctab[0];
616     if (c < 040 && c != '\t' && c != '\n' && c != '\r')
617      __cvsim_msg("^%c", c + 0100);
618     else if (c == 0177) __cvsim_msg("^?");
619     else __cvsim_msg("%c", c);
620     /* notice this handles any system */
621     /* under emx (dos vcpi and os2) sometimes will see return sometime not */
622     /* return sometimes appears after using ^c a few times */
623    } while (c != '\n' && (cnt = read(__list_cur_fd, ctab, 1)) == 1);
624    /* for long lists, must allow ^c to stop */
625    if (ctrlc_stop && __pending_enter_iact && __iact_reason == IAER_CTRLC)
626     {
627      __pending_enter_iact = FALSE;
628      __iact_reason = IAER_UNKN;
629      __cvsim_msg("Printing halted because interrupt (Ctrl-c) pressed.\n");
630      break;
631     }
632   }
633 }
634 
635 /*
636  * chnage current source file - open new current and if needed build
637  * the line pos. tab for source
638  * return F on error and do not change file
639  *
640  * only called if new_ifi different from current
641  * know there will always be current source file in fils index
642  */
change_srcfile(int32 new_ifi)643 static int32 change_srcfile(int32 new_ifi)
644 {
645  int32 fd;
646  struct filpos_t *fposp;
647  struct stat st;
648 
649  /* if char pos of source lines table not built - build it and return */
650  if (__filpostab == NULL) fposp = NULL;
651  else fposp = &(__filpostab[new_ifi]);
652  /* build file line start char pos. table */
653  if (fposp == NULL || fposp->lpostab == NULL)
654   {
655    /* if this fails, do not change current file */
656    if ((fd = bld_filpostab(new_ifi)) == -1) return(FALSE);
657    goto good_end;
658   }
659 
660  /* otherwise just open the file */
661  if ((fd = __tilde_open(__in_fils[new_ifi], O_RDONLY)) < 0)
662   {
663 op_err:
664    __ia_err(1428,
665     "unable to open or access new current debugger source file %s",
666     __in_fils[new_ifi]);
667    return(FALSE);
668   }
669  if (fstat(fd, &st) < 0) goto op_err;
670  if (__start_time <= st.st_mtime)
671   __ia_err(1429, "source file %s changed after simulation started",
672    __in_fils[new_ifi]);
673 
674  /* know succeeded */
675 good_end:
676  if (__list_cur_fd != -1)
677   {
678    /* LOOKATME - do not know name of source file here */
679    /* still change even if cannot close */
680    if (close(__list_cur_fd) != 0)
681     __ia_err(1451, "unable to close old current debugger source file");
682   }
683  __list_cur_ifi = new_ifi;
684  __list_cur_fd = fd;
685  return(TRUE);
686 }
687 
688 /*
689  * get last line in file
690  * this uses file position table - file can remain closed
691  */
get_lastfillin(int32 ifi)692 static int32 get_lastfillin(int32 ifi)
693 {
694  struct filpos_t *fposp;
695 
696  /* if char pos of source lines table not built - build it and return */
697  if (__filpostab == NULL) fposp = NULL;
698  else fposp = &(__filpostab[ifi]);
699  /* build file line start char pos. table */
700  if (fposp == NULL || fposp->lpostab == NULL)
701   {
702    /* if this fails, do not change current file */
703    if (bld_filpostab(ifi) == -1) return(-1);
704   }
705  return(fposp->nlines);
706 }
707 
708 /*
709  * build the line character position in file table for one file
710  * ifi is index of file in input file table
711  * return file descriptor number on success or -1 on error
712  * if success,  leaves file open
713  *
714  * know line char pos table not built and this adds to processed
715  * could free other linpostab when this built but now leaving all
716  * know file not open
717  */
bld_filpostab(int32 ifi)718 static int32 bld_filpostab(int32 ifi)
719 {
720  register int32 i, buf_base, buf_size, fsize, nlines;
721  int32 fd, bytes, alloc_lines;
722  int32 osize, nsize;
723  int32 *linpostab;
724  struct stat st;
725  char buf[RDBUFSIZ];
726 
727  if ((fd = __tilde_open(__in_fils[ifi], O_RDONLY)) < 0)
728   {
729 op_err:
730    __ia_err(1428, "unable to open or access debugger current source file %s",
731     __in_fils[ifi]);
732    return(-1);
733   }
734  if (fstat(fd, &st) < 0) goto op_err;
735  if (__start_time <= st.st_mtime)
736   __ia_err(1429, "source file %s changed after simulation started", __in_fils[ifi]);
737  fsize = (int32) st.st_size;
738  linpostab = NULL;
739  for (buf_base = 0, alloc_lines = 0, nlines = 0;;)
740   {
741    if (buf_base + RDBUFSIZ <= fsize) buf_size = RDBUFSIZ;
742    else buf_size = fsize - buf_base;
743 
744    if ((bytes = read(fd, buf, buf_size)) != buf_size)
745     {
746      __ia_err(1433,
747       "error reading source file %s when building line position table",
748       __in_fils[ifi]);
749      if (alloc_lines != 0) __my_free((char *) linpostab,
750       sizeof(int32)*alloc_lines);
751      if (close(fd) != 0)
752       __ia_err(1458, "unable to close source file %s after read error",
753        __in_fils[ifi]);
754      return(-1);
755     }
756    if (alloc_lines == 0)
757     {
758      alloc_lines = 1000;
759      linpostab = (int32 *) __my_malloc(alloc_lines*sizeof(int32));
760      linpostab[0] = 0;
761      nlines = 1;
762     }
763    for (i = 0; i < buf_size;)
764     {
765      /* a newline at the end of file does not start a new line */
766      if (buf[i++] == '\n' && i < buf_size)
767       {
768        if (nlines == alloc_lines)
769         {
770          osize = (word32) alloc_lines*sizeof(int32);
771          alloc_lines *= 2;
772          linpostab = (int32 *) __my_realloc((char *) linpostab, osize,
773           alloc_lines*sizeof(int32));
774         }
775        linpostab[nlines++] = buf_base + i;
776       }
777     }
778    if ((buf_base += buf_size) == fsize) break;
779   }
780 
781  /* final step is to allocate and fill parallel to __in_fils array of */
782  /* file line info */
783  if (__filpostab == NULL)
784   {
785    __filpostab = (struct filpos_t *)
786     __my_malloc((__last_srcf + 1)*sizeof(struct filpos_t));
787    for (i = 0; i <= __last_srcf; i++)
788     {
789      __filpostab[i].nlines = 0;
790      __filpostab[i].lpostab = NULL;
791     }
792   }
793  /* know line table not built or will not be called */
794  if (__filpostab[ifi].lpostab != NULL) __arg_terr(__FILE__, __LINE__);
795  /* must adjust allocated line table down to right size if needed */
796  if (nlines != alloc_lines)
797   {
798    osize = (word32) (alloc_lines*sizeof(int32));
799    nsize = (word32) (nlines*sizeof(int32));
800    linpostab = (int32 *) __my_realloc((char *) linpostab, osize, nsize);
801   }
802  __filpostab[ifi].lpostab = linpostab;
803  __filpostab[ifi].nlines = nlines;
804  return(fd);
805 }
806 
807 /*
808  * ROUTINES TO IMPLEMENT COLON DEBUGGER SET COMMANDS
809  */
810 
811 #define SET_LSIZE 0
812 #define SET_HLSIZE 1
813 #define SET_SCHG 2
814 #define SET_NOSCHG 3
815 #define SET_PRTBASE 4
816 #define SET_LOGECHO 5
817 #define SET_NOLOGECHO 6
818 
819 /* set command options table */
820 static struct namlst_t setargs[] = {
821  { SET_LSIZE, "listsize" },
822  { SET_HLSIZE, "histlistsize" },
823  { SET_SCHG, "scopechange" },
824  { SET_NOSCHG, "noscopechange" },
825  { SET_PRTBASE, "printbase" },
826  { SET_LOGECHO, "logecho" },
827  { SET_NOLOGECHO, "nologecho" }
828 };
829 #define NSETARGS (sizeof(setargs) / sizeof(struct namlst_t))
830 
831 /*
832  * execute debug set command - for now only :set listsize [number]
833  */
__do_dbg_set(void)834 extern void __do_dbg_set(void)
835 {
836  char blet;
837  int32 rv, lines;
838 
839  __get_vtok();
840  if (__toktyp != ID)
841   {
842 bad_setval:
843    __ia_err(1441, ":set %s - debugger set parameter illegal or unknown",
844     __prt_vtok());
845    return;
846   }
847  rv = __get_dbcmdnum(__token, setargs, NSETARGS);
848  switch (rv) {
849   case -1: goto bad_setval;
850   case -2:
851    __ia_err(1422, "ambiguous :set %s parameter: %s", __token,
852     __bld_ambiguous_list(__xs, __token, setargs, NSETARGS));
853    return;
854   case SET_LSIZE:
855    __get_vtok();
856    if ((lines = __get_dbg_val()) == -1)
857     {
858      __ia_err(1442,
859       ":set listsize required number of lines value expected - %s read",
860       __prt_vtok());
861      return;
862     }
863    __list_cur_listnum = lines - 1;
864    break;
865   case SET_HLSIZE:
866    __get_vtok();
867    if ((lines = __get_dbg_val()) == -1)
868     {
869      __ia_err(1442,
870       ":set histlistsize required command number value expected - %s read",
871       __prt_vtok());
872      return;
873     }
874    __hist_cur_listnum = lines;
875    break;
876   case SET_SCHG: __iact_scope_chg = TRUE; break;
877   case SET_NOSCHG: __iact_scope_chg = FALSE; break;
878   case SET_PRTBASE:
879    __get_vtok();
880    if (__toktyp != ID)
881     {
882 bad_base:
883      __ia_err(1449,
884       ":set printbase required default :print command base %s unrecognized",
885       __prt_vtok());
886      return;
887     }
888    blet = (isupper(__token[0])) ? tolower(__token[0]) : __token[0];
889    if (blet == 'b') __dbg_dflt_base = BBIN;
890    else if (blet == 'o') __dbg_dflt_base = BOCT;
891    else if (blet == 'h') __dbg_dflt_base = BHEX;
892    else if (blet == 'd') __dbg_dflt_base = BDEC;
893    else goto bad_base;
894    break;
895   case SET_NOLOGECHO: __echo_iactcmds_tolog = FALSE; break;
896   case SET_LOGECHO: __echo_iactcmds_tolog = TRUE; break;
897   default: __case_terr(__FILE__, __LINE__);
898  }
899  __chk_extra_atend(TRUE);
900 }
901 
902 /*
903  * get debugger value - return -1 on error - caller must emit message
904  * this is only for positive values and expects token to have been read
905  * this expects first token to have been read
906  *
907  * LOOKATME - notice slight memory link if error is string will not be freed
908  */
__get_dbg_val(void)909 extern int32 __get_dbg_val(void)
910 {
911  int32 val;
912 
913  if (__toktyp != NUMBER || __itoklen > WBITS || __bcwrk[0] != 0L) return(-1);
914  val = (int32) __acwrk[0];
915  if (val < -1) return(-1);
916  return(val);
917 }
918 
919 /*
920  * ROUTINES TO IMPLEMENT INFO COMMAND
921  */
922 #define INFO_LSIZE 0
923 #define INFO_HLSIZE 1
924 #define INFO_SCHG 2
925 #define INFO_BRKPT 3
926 #define INFO_PRTBASE 4
927 #define INFO_LOGECHO 5
928 #define INFO_DISPLAY 6
929 
930 /* info command options table */
931 static struct namlst_t infoargs[] = {
932  { INFO_LSIZE, "listsize" },
933  { INFO_HLSIZE, "histlistsize" },
934  { INFO_SCHG, "scopechange" },
935  { INFO_BRKPT, "breakpoints" },
936  { INFO_PRTBASE, "printbase" },
937  { INFO_LOGECHO, "logecho" },
938  { INFO_DISPLAY, "displays" }
939 };
940 #define NINFOARGS (sizeof(infoargs) / sizeof(struct namlst_t))
941 
942 /*
943  * execute debug info command
944  */
__do_dbg_info(void)945 extern void __do_dbg_info(void)
946 {
947  int32 rv;
948  char s1[RECLEN];
949 
950  __get_vtok();
951  if (__toktyp != ID)
952   {
953 bad_infoval:
954    __ia_err(1443, ":info command parameter %s unknown", __prt_vtok());
955    return;
956   }
957 
958  rv = __get_dbcmdnum(__token, infoargs, NINFOARGS);
959  switch (rv) {
960   case -1: goto bad_infoval;
961   case -2:
962    __ia_err(1422, "ambiguous info %s command parameter: %s", __token,
963     __bld_ambiguous_list(__xs, __token, infoargs, NINFOARGS));
964    return;
965   case INFO_LSIZE:
966    __cvsim_msg("number of lines to list is %d\n", __list_cur_listnum + 1);
967    break;
968   case INFO_HLSIZE:
969    __cvsim_msg("number of history commands to list is %d\n",
970     __hist_cur_listnum);
971    break;
972   case INFO_SCHG:
973    if (__iact_scope_chg)
974     __cvsim_msg("interactive scope set on debugger entry\n");
975    else __cvsim_msg("interactive scope only changed by $scope\n");
976    break;
977   case INFO_BRKPT:
978    prt_brkpts();
979    break;
980   case INFO_PRTBASE:
981    __cvsim_msg("default numeric base for :print command is %s\n",
982     to_basename(s1, __dbg_dflt_base));
983    break;
984   case INFO_LOGECHO:
985    if (__echo_iactcmds_tolog)
986     __cvsim_msg("interactive input commands echoed to log file\n");
987    else __cvsim_msg("interactive input command echo to log file off\n");
988    break;
989   case INFO_DISPLAY:
990    dbg_info_disp();
991    break;
992   default: __case_terr(__FILE__, __LINE__);
993  }
994  __chk_extra_atend(TRUE);
995 }
996 
997 /*
998  * routine to print the current breakpoints
999  */
prt_brkpts(void)1000 static void prt_brkpts(void)
1001 {
1002  register struct brkpt_t *bpp;
1003  char s1[RECLEN], s2[RECLEN];
1004 
1005  if (__bphdr == NULL)
1006   {
1007    __cvsim_msg("No Breakpoints.\n");
1008    return;
1009   }
1010 
1011  __cvsim_msg("Breakpoints:\n");
1012  __cvsim_msg("Number  Disp Filter  Source-Instance Location\n");
1013  for (bpp = __bphdr; bpp != NULL; bpp = bpp->bpnxt)
1014   {
1015    if (bpp->bp_enable)
1016     { if (bpp->bp_rm_when_hit) strcpy(s1, "del "); else strcpy(s1, "keep"); }
1017    else strcpy(s1, "dis ");
1018    __cvsim_msg("%-6d  %-4s  %-5s", bpp->bp_num, s1,
1019     to_brkptnam(s2, bpp->bp_type));
1020    __cvsim_msg("  %-s:%d", __schop(s1,
1021      __in_fils[bpp->bp_stp->stfnam_ind]), (int32) bpp->bp_stp->stlin_cnt);
1022    /* form is :[file]:[line]([inst or type]) */
1023    if (bpp->bp_itp == NULL) __arg_terr(__FILE__, __LINE__);
1024 
1025    if (bpp->bp_type == BP_INST)
1026     __cvsim_msg("(%s)\n", __msg_blditree(s1, bpp->bp_itp, bpp->bp_tskp));
1027    else
1028     {
1029      if (bpp->bp_tskp == NULL)
1030       __cvsim_msg("(in %s)\n", bpp->bp_itp->itip->imsym->synam);
1031      else __cvsim_msg("(in %s %s: %s)\n",
1032       bpp->bp_itp->itip->imsym->synam, __to_tsktyp(s1, bpp->bp_tskp->tsktyp),
1033       bpp->bp_tskp->tsksyp->synam);
1034     }
1035    if (bpp->bp_condx != NULL) __cvsim_msg("        stop if: %s\n",
1036      __msgexpr_tostr(__xs, bpp->bp_condx));
1037 
1038    if (bpp->bp_hit_cnt > 0)
1039     __cvsim_msg("        breakpoint now hit %d times\n", bpp->bp_hit_cnt);
1040    if (bpp->bp_ignore_cnt - bpp->bp_hit_cnt > 0)
1041     __cvsim_msg("        ignore next %d hits\n",
1042      bpp->bp_ignore_cnt - bpp->bp_hit_cnt);
1043   }
1044 }
1045 
1046 /*
1047  * convert breakpoint type value to its name
1048  */
to_brkptnam(char * s,word32 bptyp)1049 static char *to_brkptnam(char *s, word32 bptyp)
1050 {
1051  switch ((byte) bptyp) {
1052   case BP_INST: strcpy(s, "Inst"); break;
1053   case BP_TYPE: strcpy(s, "Type"); break;
1054   default: __case_terr(__FILE__, __LINE__);
1055  }
1056  return(s);
1057 }
1058 /*
1059  * convert base code to letter
1060  */
to_basename(char * s,int32 base)1061 static char *to_basename(char *s, int32 base)
1062 {
1063  switch ((byte) base) {
1064   case BBIN: strcpy(s, "binary"); break;
1065   case BHEX: strcpy(s, "hex"); break;
1066   case BOCT: strcpy(s, "octal"); break;
1067   case BDEC: strcpy(s, "decimal"); break;
1068   default: strcpy(s, "?"); __case_terr(__FILE__, __LINE__);
1069  }
1070  return(s);
1071 }
1072 
1073 /*
1074  * print info lines for all breakpoints
1075  */
dbg_info_disp(void)1076 static void dbg_info_disp(void)
1077 {
1078  struct dispx_t *dxp;
1079  char s1[RECLEN];
1080 
1081  if (__dispxhdr == NULL)
1082   {
1083    __cvsim_msg("No auto-display expressions.\n");
1084    return;
1085   }
1086  __cvsim_msg("Number  Enable Expression-(instance)\n");
1087  for (dxp = __dispxhdr; dxp != NULL; dxp = dxp->dsp_nxt)
1088   {
1089    if (dxp->dsp_enable) strcpy(s1, "y"); else strcpy(s1, "n");
1090    __cvsim_msg("%-7d   %s     %s (%s)\n", dxp->dsp_num, s1,
1091     __msgexpr_tostr(__xs, dxp->dsp_xp), __msg_blditree(__xs2, dxp->dsp_itp,
1092     dxp->dsp_tskp));
1093   }
1094 }
1095 
1096 /*
1097  * ROUTINES TO PARSE A SCOPE REFERNENCE
1098  */
1099 
1100 /*
1101  * : debugger :scope command normal scope except allow [file]:[line] form
1102  * where first instance is implied - other wide argument is normal scope
1103  * :sc [file]:[line], .u (..) .d , normal xmr
1104  * returns T if parsed all of args even if error
1105  *
1106  * notice scheme is to maybe use line to determine scope but then always
1107  * set at first line of scope not entered line?
1108  * ihea is that probably want to start by listing header and initial always
1109  * are ||
1110  */
__do_dbg_scope(void)1111 extern void __do_dbg_scope(void)
1112 {
1113  int32 ifi, lini, iref;
1114  struct itree_t *in_itp;
1115  struct task_t *in_tskp;
1116 
1117  /* if cannot parse scope location, error emitted in routine */
1118  if (!parse_scope_ref(&in_itp, &in_tskp, &ifi, &lini, &iref)) return;
1119  /* do the scope change - implies current line change */
1120  /* notice even if ifi and line set, not used */
1121  __scope_ptr = in_itp;
1122  __scope_tskp = in_tskp;
1123  /* replace top of inst. stack */
1124  __pop_itstk();
1125  __push_itstk(__scope_ptr);
1126  __set_scopchg_listline();
1127 
1128  if (__tfrec_hdr != NULL) __call_misctfs_scope();
1129  if (__have_vpi_actions) __vpi_iactscopechg_trycall();
1130 
1131  __chk_extra_atend(TRUE);
1132 }
1133 
1134 /*
1135  * routine to get scope line location for breakpoints and printing
1136  * return F on error
1137  * this may set values but invalid unless returns T
1138  * if T know all 5 return by ref. values set
1139  * for breakpoints - determines if one instance ref only (iref T)
1140  * because of file form this does not use get_vtok but access vichp
1141  * for scope but not line ref. sets ref_ifi and ref_lini to -1
1142  *
1143  * forms: .. .u .d scope change => scope,task,file,1st line
1144  *        [file]:[line] or [line] (current file) - scope,task,[file],[line]
1145  *        [module name] => scope 1st inst,no task, file,first line
1146  *        xmr => scope,task,file,1st line
1147  *
1148  * notice no spaces allowed in reference
1149  */
parse_scope_ref(struct itree_t ** ref_itp,struct task_t ** ref_tskp,int32 * ref_ifi,int32 * ref_lini,int32 * iref)1150 static int32 parse_scope_ref(struct itree_t **ref_itp, struct task_t **ref_tskp,
1151  int32 *ref_ifi, int32 *ref_lini, int32 *iref)
1152 {
1153  register char *chp;
1154  int32 ifi, lini, maxlini;
1155  struct itree_t *itp;
1156  struct task_t *tskp;
1157  char *savchp, *endchp, sref[RECLEN];
1158 
1159  /* assume instance ref. */
1160  *iref = TRUE;
1161  /* here savchp is 1st char of token - endchp first after */
1162  /* return F on error, if is not [file]:[line] ref - ifi is -1 */
1163  if (!try_get_fillin_ref(__visp->vichp, &ifi, &lini, &savchp, &endchp))
1164   return(FALSE);
1165 
1166  if (ifi != -1)
1167   {
1168 set_line_scope:
1169    if ((maxlini = get_lastfillin(ifi)) == -1) return(FALSE);
1170    if (lini > maxlini)
1171     {
1172      __ia_err(1469,
1173       "[file]:[line] reference line number %d too large - %s has %d lines",
1174       lini, __in_fils[ifi], maxlini);
1175      return(FALSE);
1176     }
1177 
1178    if (!fil_lin_toscope(ifi, lini, ref_itp, ref_tskp))
1179     {
1180      __ia_err(1454,
1181       "scope reference %s:%d illegal - line not inside any module",
1182       __in_fils[ifi], lini);
1183      return(FALSE);
1184     }
1185    *ref_ifi = ifi;
1186    *ref_lini = lini;
1187    /* if has line number, not an instance ref. */
1188    *iref = FALSE;
1189    /* current get tok place is just after [file]:[line] ref. */
1190    __visp->vichp = endchp;
1191    return(TRUE);
1192   }
1193 
1194  /* know not [file]:[line] ref - try scope or special abbrev. */
1195  /* build the token */
1196  strncpy(sref, savchp, endchp - savchp);
1197  sref[endchp - savchp] = '\0';
1198  /* assume will match local scope ref. or [number] implied file form */
1199  __visp->vichp = endchp;
1200  /* maybe special local .. form */
1201  if (sref[0] == '.')
1202   {
1203    *ref_ifi = -1;
1204    *ref_lini = -1;
1205    return(local_scope_ref(sref, ref_itp, ref_tskp));
1206   }
1207 
1208  /* does not have : not [file]:[line] but maybe [line] */
1209  if (isdigit(sref[0]))
1210   {
1211    for (chp = sref; *chp != '\0'; chp++)
1212     {
1213      if (!isdigit(*chp))
1214       {
1215 bad_lin:
1216        __ia_err(1452, "scope reference [line] form %s illegal format", sref);
1217        return(FALSE);
1218       }
1219     }
1220    if (sscanf(sref, "%d", &lini) != 1) goto bad_lin;
1221    ifi = __list_cur_ifi;
1222    goto set_line_scope;
1223   }
1224 
1225  /* must be identifier - need get vtok to check and parse GLBREF */
1226  /* put back and parse */
1227  __visp->vichp = savchp;
1228 
1229  /* know file form elminated before here */
1230  __get_vtok();
1231  if (__toktyp != ID)
1232   {
1233    __ia_err(1467, "scope reference %s illegal", __prt_vtok());
1234    return(FALSE);
1235   }
1236  if (!get_var_scope(&itp, &tskp, iref)) return(FALSE);
1237  *ref_itp = itp;
1238  *ref_tskp = tskp;
1239  *ref_ifi = -1;
1240  *ref_lini = -1;
1241  return(TRUE);
1242 }
1243 
1244 /*
1245  * attempt to read a file and line reference form
1246  * return F on error
1247  * set ifi to -1 if turns out not to be [file]:[line] form
1248  * lini and endchp only good if ifi not -1
1249  */
try_get_fillin_ref(char * st_chp,int32 * ifi,int32 * lini,char ** sav_chp,char ** endchp)1250 static int32 try_get_fillin_ref(char *st_chp, int32 *ifi, int32 *lini,
1251  char **sav_chp, char **endchp)
1252 {
1253  register char *chp;
1254  int32 rlen, arglen, rv;
1255  char *chp1, *sref, *argref;
1256  char s1[RECLEN];
1257 
1258  /* skip any leading white space */
1259  argref = NULL;
1260  arglen = 0;
1261  rv = TRUE;
1262  *ifi = *lini = -1;
1263  for (chp = st_chp;; chp++) { if (!vis_white_(*chp)) break; }
1264  *sav_chp = chp;
1265 
1266  /* separate scope reference into separate string in case file:line form */
1267  /* tricky because anything except \0 can go in file name */
1268  chp1 = chp;
1269  for (;; chp++)
1270   {
1271    /* any escaped cannot end */
1272    if (*chp == '\\') { chp++; continue; }
1273    if (vis_white_(*chp) || *chp == '\0') break;
1274   }
1275  rlen = chp - chp1;
1276  sref = __my_malloc(rlen + 1);
1277  strncpy(sref, chp1, rlen);
1278  sref[rlen] = '\0';
1279 
1280  /* set vichp to continuation place in case more arguments */
1281  *endchp = chp;
1282  /* have scope ref. in sref - rule if has unescaped : line, else scope */
1283  /* escaped ID always scope ref */
1284  if (sref[0] == '\\') goto done;
1285  /* if no : cannot be [file]:[line] form - [line] form handled elsewhere */
1286  if ((chp = strrchr(sref, ':')) == NULL) goto done;
1287  chp--;
1288  /* if last : escaped no possible number following */
1289  if (*chp == '\\')  goto done;
1290  chp++;
1291  arglen = chp - sref + 1;
1292  argref = __my_malloc(arglen);
1293  strncpy(argref, sref, chp - sref);
1294  argref[chp - sref] = '\0';
1295  /* must be all digits after : */
1296  chp++;
1297  for (chp1 = chp; *chp1 != '\0'; chp1++)
1298   {
1299    if (!isdigit(*chp1))
1300     {
1301 bad_fil_lin:
1302      __ia_err(1468, "[file]:[line] form %s illegal format", sref);
1303      rv = FALSE;
1304      goto done;
1305     }
1306   }
1307  strcpy(s1, chp);
1308  if (sscanf(s1, "%d", lini) != 1 || *lini < 1) goto bad_fil_lin;
1309  if ((*ifi = find_infil_ind(argref)) == -1)
1310   {
1311    __ia_err(1453,
1312     "scope reference file, path or path tail \"%s\" unrecognized", argref);
1313    rv = FALSE;
1314   }
1315 done:
1316  __my_free(sref, rlen + 1);
1317  if (argref != NULL) __my_free(argref, arglen);
1318  return(rv);
1319 }
1320 
1321 /*
1322  * get a ID or GLBREF expr. (know read token ID) scope location
1323  *
1324  * this reads to EOL - no other way to know end because of inst. array sel.
1325  *
1326  *
1327  * need to run with current module for counting any allocated globals
1328  * may alloc some globals in grwrk tab - need to free fields and empty tab
1329  */
get_var_scope(struct itree_t ** itpp,struct task_t ** tskpp,int32 * iref)1330 static int32 get_var_scope(struct itree_t **itpp, struct task_t **tskpp,
1331  int32 *iref)
1332 {
1333  int32 gri, rv, sav_ecnt;
1334  struct sy_t *syp;
1335  struct gref_t *grp;
1336  struct expr_t *glbndp;
1337  struct expridtab_t *xidp;
1338  struct mod_t wrkmod;
1339  struct sy_t wrksym;
1340  char s1[RECLEN];
1341 
1342  rv = TRUE;
1343  syp = NULL;
1344  /* collect to end of line (TEOF) */
1345  if (!__colto_eol())
1346   {
1347    __ia_err(1434, "scope reference bad format - extra tokens at end(?)");
1348    return(FALSE);
1349   }
1350 
1351  /* allow [module name] form if not instance name - not legal source xmr */
1352  /* must handle this before parsing since it is an error */
1353  if (__last_xtk == 0 && __exprtab[0]->optyp == ID)
1354   {
1355    xidp = __expr_idtab[0];
1356 
1357    /* know this has one component */
1358    /* case 1: not defined in cur. module or not scope in cur. mod */
1359    if ((syp = __get_sym(xidp->idnam,
1360     __scope_ptr->itip->imsym->el.emdp->msymtab)) == NULL
1361     || !__is_scope_sym(syp))
1362     {
1363      /* can scope to any module (implied first instance) */
1364      /* udp's are in mod syms */
1365      if ((syp = __get_sym(xidp->idnam, __modsyms)) != NULL
1366       && syp->sytyp == SYM_M)
1367       {
1368        *tskpp = NULL;
1369        *itpp = syp->el.emdp->moditps[0];
1370        /* if top then this is iref need for ibreak where required */
1371        if (syp->el.emdp->minstnum == 0) *iref = TRUE; else *iref = FALSE;
1372        return(TRUE);
1373       }
1374      /* must be some kind of one component global or maybe error */
1375     }
1376   }
1377 
1378  wrksym.synam = s1;
1379  wrksym.sydecl = TRUE;
1380  strcpy(wrksym.synam, "** DBG SCOPE WRK**");
1381  __init_mod(&wrkmod, &wrksym);
1382  wrkmod.flatinum = 1;
1383  wrksym.el.emdp = &wrkmod;
1384  __push_wrkitstk(&wrkmod, 0);
1385 
1386  /* try global - can be one component downward relative xmr */
1387  /* if fails will be set to x number */
1388  sav_ecnt = __pv_err_cnt;
1389  __allow_scope_var = TRUE;
1390  __bld_xtree(0);
1391  __allow_scope_var = FALSE;
1392  glbndp = __root_ndp;
1393  if (__pv_err_cnt > sav_ecnt) { rv = FALSE; goto done; }
1394 
1395  /* if local task/func/named block reference - just change task */
1396  /* if local reference may have been converted back to ID */
1397  if (glbndp->optyp == ID)
1398   {
1399    if (!__is_scope_sym(glbndp->lu.sy))
1400     {
1401      __ia_err(1440, "scope reference to non scope symbol %s type %s",
1402       glbndp->lu.sy->synam,  __to_sytyp(__xs, glbndp->lu.sy->sytyp));
1403      rv = FALSE;
1404      goto done;
1405     }
1406 
1407    /* know scope ptr always on top of inst. stack here */
1408    *itpp = __scope_ptr;
1409    *tskpp = glbndp->lu.sy->el.etskp;
1410    rv = TRUE;
1411    goto done;
1412   }
1413 
1414  if (glbndp->optyp != GLBREF)
1415   {
1416    __ia_err(1411, "scope reference illegal hierarchical reference");
1417    return(FALSE);
1418   }
1419  grp = glbndp->ru.grp;
1420  if (grp->gr_err) { rv = FALSE; goto done; }
1421 
1422  /* convert from gref reference to itree target location */
1423  __xmrpush_refgrp_to_targ(grp);
1424  *itpp = __inst_ptr;
1425  __pop_itstk();
1426 
1427  if (glbndp->lu.sy->sytyp != SYM_I && glbndp->lu.sy->sytyp != SYM_M)
1428   *tskpp = glbndp->lu.sy->el.etskp;
1429  else *tskpp = NULL;
1430 
1431 done:
1432  if (__grwrknum > 0)
1433   {
1434    grp = &(__grwrktab[0]);
1435    for (gri = 0; gri < __grwrknum; grp++, gri++) __free_1glb_flds(grp);
1436    __grwrknum = 0;
1437   }
1438  __free_xtree(glbndp);
1439  __pop_wrkitstk();
1440  return(rv);
1441 }
1442 
1443 /*
1444  * get a local form scope reference
1445  * know 1st token read
1446  */
local_scope_ref(char * refnam,struct itree_t ** ref_itp,struct task_t ** ref_tskp)1447 static int32 local_scope_ref(char *refnam, struct itree_t **ref_itp,
1448  struct task_t **ref_tskp)
1449 {
1450  struct itree_t *itp;
1451  struct task_t *tskp;
1452  struct symtab_t *sytp;
1453 
1454  if (refnam[1] == '.')
1455   {
1456    if (refnam[2] != '\0') goto bad_locchg;
1457 
1458 do_up:
1459    /* if in task, up is to next task up or enclosing named block */
1460    tskp = __scope_tskp;
1461    itp = __scope_ptr;
1462    if ((tskp = __scope_tskp) != NULL)
1463     {
1464      /* see what parent symbol table symbol of is */
1465      sytp = tskp->tsksymtab->sytpar;
1466      if (sytp == NULL) __misc_terr(__FILE__, __LINE__);
1467      /* if task top in module up is module scope */
1468      if (sytp->sypofsyt->sytyp == SYM_M) tskp = NULL;
1469      else tskp = sytp->sypofsyt->el.etskp;
1470     }
1471    else
1472     {
1473      if (__scope_ptr->up_it == NULL)
1474       {
1475        __ia_err(1455,
1476         "scope reference .. (up) change impossible - already at top level");
1477        return(FALSE);
1478       }
1479      itp = __scope_ptr->up_it;
1480      tskp = NULL;
1481     }
1482    goto do_change;
1483   }
1484  /* :scope .[dir. letter] */
1485  if ((refnam[1] != 'u' && refnam[1] != 'd') || refnam[2] != '\0')
1486   {
1487 bad_locchg:
1488    __ia_err(1459,
1489     "illegal scope reference local change argument %s", refnam);
1490    return(FALSE);
1491   }
1492  if (refnam[1] == 'u') goto do_up;
1493  /* down case - even if current task scope ignore */
1494  if (__scope_ptr->in_its == NULL)
1495   {
1496    __ia_err(1456,
1497     "scope reference local .d move down impossible - scope has no instances");
1498     return(FALSE);
1499   }
1500  itp = &(__scope_ptr->in_its[0]);
1501  tskp = NULL;
1502 
1503 do_change:
1504  *ref_itp = itp;
1505  *ref_tskp = tskp;
1506  return(TRUE);
1507 }
1508 
1509 /*
1510  * given a file name or path, convert to in_fils index number
1511  * return -1 if no match
1512  */
find_infil_ind(char * nam)1513 static int32 find_infil_ind(char *nam)
1514 {
1515  register int32 i;
1516  char *chp;
1517 
1518  /* file spec. if path - must match path exactly */
1519  if ((chp = strrchr(nam, '/')) != NULL)
1520   {
1521    /* 0 and 1 used for place holders */
1522    for (i = 2; i <= __last_srcf; i++)
1523     { if (strcmp(nam, __in_fils[i]) == 0) return(i); }
1524    return(-1);
1525   }
1526  /* simple file, first try to match exactly */
1527  for (i = 2; i <= __last_srcf; i++)
1528   { if (strcmp(nam, __in_fils[i]) == 0) return(i); }
1529  /* then try tails of paths */
1530  for (i = 2; i <= __last_srcf; i++)
1531   {
1532    if ((chp = strrchr(__in_fils[i], '/')) == NULL) continue;
1533    if (strcmp(++chp, __in_fils[i]) == 0) return(i);
1534   }
1535  return(-1);
1536 }
1537 
1538 /*
1539  * find scope from line number
1540  * do not need file pos. table for this
1541  */
fil_lin_toscope(int32 ifi,int32 lini,struct itree_t ** in_itp,struct task_t ** in_tskp)1542 static int32 fil_lin_toscope(int32 ifi, int32 lini, struct itree_t **in_itp,
1543  struct task_t **in_tskp)
1544 {
1545  register struct mod_t *mdp;
1546  register struct task_t *tskp;
1547  struct mod_t *in_mdp;
1548 
1549  /* module in means from first to last */
1550  for (in_mdp = NULL, mdp = __modhdr; mdp != NULL; mdp = mdp->mnxt)
1551   {
1552    if (scope_lini_inrng(lini, ifi, mdp->msym->sylin_cnt,
1553     (int32) mdp->msym->syfnam_ind, mdp->mod_last_lini, mdp->mod_last_ifi))
1554     {
1555      in_mdp = mdp;
1556      break;
1557     }
1558   }
1559  if (in_mdp == NULL) return(FALSE);
1560  *in_itp = in_mdp->moditps[0];
1561  /* next see if within task or function but not named block */
1562  /* since named blocks nests must handle as normal statements */
1563  *in_tskp = NULL;
1564  for (tskp = mdp->mtasks; tskp != NULL; tskp = tskp->tsknxt)
1565   {
1566    /* notice must include named blocks as well as task/funcs in scope */
1567    if (scope_lini_inrng(lini, ifi, tskp->tsksyp->sylin_cnt,
1568     (int32) tskp->tsksyp->syfnam_ind, tskp->tsk_last_lini, tskp->tsk_last_ifi))
1569     { *in_tskp = tskp; break; }
1570   }
1571  return(TRUE);
1572 }
1573 
1574 /*
1575  * determine if line inside module scope - scope can span multiple files
1576  *
1577  * here line can be anywhere in module scope providing followed by procedural
1578  * statement
1579  */
scope_lini_inrng(int32 lini,int32 ifi,int32 st_lini,int32 st_ifi,int32 last_lini,int32 last_ifi)1580 static int32 scope_lini_inrng(int32 lini, int32 ifi, int32 st_lini, int32 st_ifi,
1581  int32 last_lini, int32 last_ifi)
1582 {
1583  struct incloc_t *ilp;
1584 
1585  /* if ifi included (first) file ilp is non included location */
1586  /* that is right location for which to do in range check */
1587  if ((ilp = find2_incloc(ifi)) != NULL)
1588   { ifi = ilp->incfrom_fnind; lini = ilp->incfrom_lcnt; }
1589 
1590  /* debugger current location in file outside scope files */
1591  if (ifi < st_ifi || ifi > last_ifi) return(FALSE);
1592 
1593  /* in first (usually only) file of scope */
1594  if (ifi == st_ifi)
1595   {
1596    if (lini < st_lini) return(FALSE);
1597    if (last_ifi > ifi) return(TRUE);
1598    return(lini <= last_lini);
1599   }
1600  /* in last file of scope where scope spans files */
1601  if (ifi == last_ifi) return(lini <= last_lini);
1602  /* if in not first or last spanned file, then know in range */
1603  return(TRUE);
1604 }
1605 
1606 /*
1607  * find incloc that is non included file
1608  * for multiply included this returns location of outermost
1609  */
find2_incloc(int32 ifi)1610 static struct incloc_t *find2_incloc(int32 ifi)
1611 {
1612  struct incloc_t *ilp, *ilp2;
1613 
1614  if ((ilp2 = find_incloc(ifi)) == NULL) return(NULL);
1615  /* know included trace outward until finding one not included and */
1616  /* return that ilp */
1617  for (;;)
1618   {
1619    ifi = ilp2->incfrom_fnind;
1620    ilp = ilp2;
1621    if ((ilp2 = find_incloc(ifi)) == NULL) break;
1622   }
1623  return(ilp);
1624 }
1625 
1626 /*
1627  * set list line to suspended thread next statement first line if possible
1628  * else to first line of scope
1629  */
__set_dbentry_listline(void)1630 extern void __set_dbentry_listline(void)
1631 {
1632  int32 lini, ifi;
1633  struct st_t *stp;
1634 
1635  if (__suspended_thd == NULL || __suspended_thd->thnxtstp == NULL)
1636   {
1637    __set_scopchg_listline();
1638    goto done;
1639   }
1640 
1641  stp = __suspended_thd->thnxtstp;
1642  ifi = (int32) stp->stfnam_ind;
1643  /* never change dbg list line to interactive history */
1644  if (ifi == __cmd_ifi) goto done;
1645  lini = stp->stlin_cnt;
1646  __list_arg_lini = __list_cur_lini = lini;
1647  if (__list_cur_ifi != ifi)
1648   {
1649    /* this emits error on file problem */
1650    if (!change_srcfile(ifi)) return;
1651   }
1652  done:;
1653   /* DBG REMOVED ---
1654   if (__debug_flg)
1655    {
1656    __dbg_msg("=== IACT entry at %s scope %s\n",
1657     __bld_lineloc(__xs, (word32) __list_cur_ifi, __list_cur_lini),
1658     __msg_blditree(__xs2, __scope_ptr, __scope_tskp));
1659    }
1660  --- */
1661 }
1662 
1663 /*
1664  * set a scope change list line - for interactive only
1665  */
__set_scopchg_listline(void)1666 extern void __set_scopchg_listline(void)
1667 {
1668  int32 lini, ifi;
1669  struct sy_t *syp;
1670 
1671  /* no suspended thread use first line of scope */
1672  if (__scope_tskp != NULL) syp = __scope_tskp->tsksyp;
1673  else syp = __scope_ptr->itip->imsym;
1674  ifi = (int32) syp->syfnam_ind;
1675  /* start with list arg same as scope */
1676  lini = syp->sylin_cnt;
1677  __list_arg_lini = __list_cur_lini = lini;
1678  /* this emits error on file problem */
1679  if (__list_cur_ifi != ifi) change_srcfile(ifi);
1680 }
1681 
1682 /*
1683  * print history list - :history [number] command
1684  */
__do_dbg_history(void)1685 extern void __do_dbg_history(void)
1686 {
1687  int32 hnum;
1688 
1689  __get_vtok();
1690  if (__toktyp == TEOF) { __exec_history_list(__hist_cur_listnum); return; }
1691  /* notice since history starts at 1, last is same as size */
1692  if ((hnum = __get_dbg_val()) == -1 || hnum < 0)
1693   { __ia_err(1477, ":history %s argument illegal", __prt_vtok()); return; }
1694  __exec_history_list(hnum);
1695  __chk_extra_atend(TRUE);
1696 }
1697 
1698 /*
1699  * empty the history list if possible
1700  */
__do_dbg_emptyhistory(void)1701 extern void __do_dbg_emptyhistory(void)
1702 {
1703  register int32 iahi;
1704  struct iahist_t *iahp;
1705  int32 llen;
1706 
1707  /* first check to make sure nothing pending */
1708  for (iahi = 1; iahi <= __iah_lasti; iahi++)
1709   {
1710    iahp = &(__iahtab[iahi]);
1711    /* notice when non immediate statement finishes, disable turned on */
1712    if (iahp->iah_hcp != NULL)
1713     {
1714      __ia_err(1483,
1715       ":emptyhistory impossible because command %d not completed or disabled",
1716       iahi);
1717      return;
1718     }
1719   }
1720  for (iahi = 1; iahi <= __iah_lasti; iahi++)
1721   {
1722    iahp = &(__iahtab[iahi]);
1723    if (iahp->iah_hcp != NULL || iahp->iah_lp == NULL)
1724     __misc_terr(__FILE__, __LINE__);
1725    llen = strlen(iahp->iah_lp);
1726    __my_free(iahp->iah_lp, llen + 1);
1727    __my_free((char *) iahp, sizeof(struct iahist_t));
1728    __iahtab[iahi].iah_hcp = NULL;
1729    __iahtab[iahi].iah_lp = NULL;
1730   }
1731  __iah_lasti = 0;
1732  __chk_extra_atend(TRUE);
1733 }
1734 
1735 /*
1736  * ROUTINES TO IMPLEMENT BREAK POINTS
1737  */
1738 
1739 /*
1740  * : debugger command to stop over current statement
1741  * abbreviation for :tibreak [next line] if exists, '.'
1742  */
__do_dbg_nextb(void)1743 extern int32 __do_dbg_nextb(void)
1744 {
1745  struct thread_t *thp;
1746  struct st_t *stp;
1747  struct brkpt_t *bpp;
1748  struct task_t *tskp;
1749 
1750  /* need to have started execution to use :nextb */
1751  if ((thp = __suspended_thd) == NULL)
1752   {
1753    __ia_err(1494,
1754     ":nextb impossible exection not started - start with ',' or :step");
1755    return(TRUE);
1756   }
1757  if ((stp = thp->thnxtstp) == NULL || stp->stnxt == NULL)
1758   {
1759    __ia_err(1494,
1760     ":nextb impossible no next statement - set manual :tbreak");
1761    return(TRUE);
1762   }
1763  if (stp->stnxt->rl_stmttyp == S_REPEAT) stp = stp->stnxt;
1764  /* DBG remove --- */
1765  if (stp == NULL) __misc_terr(__FILE__, __LINE__);
1766  /* --- */
1767 
1768  bpp = (struct brkpt_t *) __my_malloc(sizeof(struct brkpt_t));
1769  init_brkpt(bpp);
1770  bpp->bp_type = BP_INST;
1771  bpp->bp_num = __nxt_bpnum++;
1772  bpp->bp_stp = stp->stnxt;
1773  bpp->bp_itp = thp->th_itp;
1774 
1775  if (__fcspi >= 0) tskp = __fcstk[__fcspi];
1776  else if (thp->th_fj) tskp = __find_thrdtsk(thp);
1777  else tskp = thp->assoc_tsk;
1778  bpp->bp_tskp = tskp;
1779  bpp->bp_rm_when_hit = TRUE;
1780  insert_brkpt(bpp);
1781  return(FALSE);
1782 }
1783 
1784 /*
1785  * : debugger command to set a breakpoint that applies to all insts of type
1786  */
__do_dbg_brkpt(int32 is_tmp)1787 extern void __do_dbg_brkpt(int32 is_tmp)
1788 {
1789  int32 ifi, lini, iref;
1790  struct brkpt_t *bpp;
1791  struct itree_t *in_itp;
1792  struct task_t *in_tskp;
1793  struct mod_t *mdp;
1794  struct st_t *stp, *stp2;
1795  char *sav_chp;
1796  char s1[RECLEN], s2[RECLEN];
1797 
1798  if (is_tmp) strcpy(s1, ":tbreakpoint"); else strcpy(s1, ":breakpoint");
1799  sav_chp = __visp->vichp;
1800  __get_vtok();
1801  if (__toktyp == TEOF)
1802   {
1803    /* here always use last printed file line type location - know exists */
1804    ifi = __list_cur_ifi;
1805    if (__list_arg_lini < 1)
1806     {
1807      __ia_err(1485, "%s no argument form failed - no last list line", s1);
1808      return;
1809     }
1810    lini = __list_arg_lini;
1811    if (!fil_lin_toscope(ifi, lini, &in_itp, &in_tskp))
1812     {
1813      __ia_err(1472,
1814       "%s not set at list location %s:%d - outside procedural region of scope",
1815       s1, __in_fils[ifi], lini);
1816      return;
1817     }
1818    iref = FALSE;
1819    __visp->vichp = sav_chp;
1820   }
1821  else
1822   {
1823    __visp->vichp = sav_chp;
1824    if (!parse_scope_ref(&in_itp, &in_tskp, &ifi, &lini, &iref)) return;
1825 
1826    /* must have line number which is first procedural statement of scope */
1827    if (ifi == -1) set_scope_loc(in_itp, in_tskp, &ifi, &lini);
1828   }
1829 
1830  /* convert to statement, if scope form, line and file will be set to 1st */
1831  /* first build the new breakpoint */
1832  mdp = in_itp->itip->imsym->el.emdp;
1833  if ((stp = conv_line_tostmt(mdp, in_tskp, ifi, lini)) == NULL)
1834   {
1835    __ia_err(1473,
1836     "%s reference location %s:%d outside task or initial/always block", s1,
1837     __in_fils[ifi], lini);
1838    return;
1839   }
1840 
1841  /* can't set stmt breakpoint on delay control must go on action stmt */
1842  if (stp->stmttyp == S_DELCTRL)
1843   {
1844    stp2 = stp->st.sdc->actionst;
1845    if (stp2 == NULL)
1846     {
1847      __ia_err(1488,
1848       "statement %s only on delay control with action statement", s1);
1849      return;
1850     }
1851    stp = stp2;
1852   }
1853 
1854  bpp = (struct brkpt_t *) __my_malloc(sizeof(struct brkpt_t));
1855  init_brkpt(bpp);
1856  bpp->bp_type = BP_TYPE;
1857  bpp->bp_num = __nxt_bpnum++;
1858  bpp->bp_stp = stp;
1859  bpp->bp_itp = in_itp;
1860  bpp->bp_tskp = in_tskp;
1861  if (is_tmp) bpp->bp_rm_when_hit = TRUE;
1862  insert_brkpt(bpp);
1863 
1864  if (bpp->bp_tskp == NULL) strcpy(s1, "");
1865  else sprintf(s1, " %s: %s", __to_tsktyp(__xs, bpp->bp_tskp->tsktyp),
1866   bpp->bp_tskp->tsksyp->synam);
1867  if (is_tmp) strcpy(s2, " (temp)"); else strcpy(s2, "");
1868 
1869  __cvsim_msg("Breakpoint%s %d set at %s in %s%s\n", s2,
1870   bpp->bp_num, __bld_lineloc(__xs, bpp->bp_stp->stfnam_ind,
1871   bpp->bp_stp->stlin_cnt), bpp->bp_itp->itip->imsym->synam, s1);
1872  __chk_extra_atend(TRUE);
1873 }
1874 
1875 /*
1876  * set a scope starting line number - for non line number forms
1877  * takes itp and tskp inputs, and sets addrs ref_ifi and ref_lini
1878  */
set_scope_loc(struct itree_t * itp,struct task_t * tskp,int32 * ref_ifi,int32 * ref_lini)1879 static void set_scope_loc(struct itree_t *itp, struct task_t *tskp,
1880  int32 *ref_ifi, int32 *ref_lini)
1881 {
1882  struct mod_t *mdp;
1883 
1884  if (tskp != NULL)
1885   {
1886    *ref_ifi = (int32) tskp->tskst->stfnam_ind;
1887    *ref_lini = tskp->tskst->stlin_cnt;
1888    return;
1889   }
1890  mdp = itp->itip->imsym->el.emdp;
1891  if (mdp->ialst == NULL)
1892   {
1893    __ia_err(1484,
1894     "scope %s module %s no initial always blocks - no procedural location",
1895     __msg2_blditree(__xs, itp), mdp->msym->synam);
1896    /* must use first line of scope - probably later another error */
1897    *ref_ifi = (int32) itp->itip->imsym->syfnam_ind;
1898    *ref_lini = itp->itip->imsym->sylin_cnt;
1899    return;
1900   }
1901  *ref_lini = mdp->ialst->ia_first_lini;
1902  *ref_ifi = mdp->ialst->ia_first_ifi;
1903 }
1904 
1905 /*
1906  * : debugger command to set a breakpoint that applies to all insts of type
1907  */
__do_dbg_ibrkpt(int32 is_tmp)1908 extern void __do_dbg_ibrkpt(int32 is_tmp)
1909 {
1910  int32 ifi, lini, iref;
1911  struct brkpt_t *bpp;
1912  struct itree_t *in_itp;
1913  struct task_t *in_tskp;
1914  struct mod_t *mdp;
1915  struct st_t *stp, *stp2;
1916  struct sy_t *syp;
1917  char *savchp;
1918  char s1[RECLEN];
1919 
1920  if (is_tmp) strcpy(s1, ":tibreakpoint"); else strcpy(s1, ":ibreakpoint");
1921  savchp = __visp->vichp;
1922  __get_vtok();
1923  /* case 1: no argument use current list and scope locations */
1924  if (__toktyp == TEOF)
1925   {
1926    /* here if not in scope instance use first instance of scope */
1927    ifi = __list_cur_ifi;
1928    if (__list_arg_lini < 1)
1929     {
1930      __ia_err(1485,
1931       "%s no argument form failed - no last list line", s1);
1932      return;
1933     }
1934    lini = __list_arg_lini;
1935    if (!fil_lin_toscope(ifi, lini, &in_itp, &in_tskp))
1936     {
1937      __ia_err(1474,
1938       "%s set at scope first line - list location %s:%d not in scope", s1,
1939       __in_fils[ifi], lini);
1940      in_itp = NULL;
1941     }
1942    if (in_itp != NULL)
1943     {
1944      if (in_itp->itip->imsym->el.emdp != __scope_ptr->itip->imsym->el.emdp)
1945       {
1946        __ia_err(1476,
1947         "%s set at scope first line - list location %s:%d outside current scope",
1948          s1, __in_fils[ifi], lini);
1949        in_itp = NULL;
1950       }
1951     }
1952    __visp->vichp = savchp;
1953    /* problem with line - use first line of scope */
1954    if (in_itp == NULL)
1955     {
1956      if (__scope_tskp != NULL) syp = __scope_tskp->tsksyp;
1957      else syp = __scope_ptr->itip->imsym;
1958      ifi = (int32) syp->syfnam_ind;
1959      lini = syp->sylin_cnt;
1960      in_itp = __scope_ptr;
1961      in_tskp = __scope_tskp;
1962     }
1963    __visp->vichp = savchp;
1964   }
1965  else
1966   {
1967    /* case 3: scope ref, maybe ,[line ref.] */
1968    __visp->vichp = savchp;
1969    __get_vtok();
1970    /* :ib ,[line ref] form legal */
1971    if (__toktyp == COMMA)
1972     {
1973      /* notice either need to use scope ptr here or scope from inst */
1974      in_itp = __scope_ptr;
1975      in_tskp = __scope_tskp;
1976      goto got_comma;
1977     }
1978 
1979    __visp->vichp = savchp;
1980    if (!parse_scope_ref(&in_itp, &in_tskp, &ifi, &lini, &iref)) return;
1981    if (!iref)
1982     {
1983      __ia_err(1478,
1984       "%s cannot be set - instance reference required", s1);
1985      return;
1986     }
1987    __get_vtok();
1988 got_comma:
1989    /* see if optional ,[file]:[line] form present - use for line */
1990    if (__toktyp == COMMA)
1991     { if (!get_ibrk_linref(in_itp, in_tskp, &ifi, &lini)) return; }
1992    /* else use first procedural statement line of scope not arg lini */
1993    else set_scope_loc(in_itp, in_tskp, &ifi, &lini);
1994   }
1995  /* convert to statement, if scope form, line and file will be set to 1st */
1996  /* first build the new breakpoint */
1997  mdp = in_itp->itip->imsym->el.emdp;
1998  if ((stp = conv_line_tostmt(mdp, in_tskp, ifi, lini)) == NULL)
1999   {
2000    __ia_err(1475,
2001     "%s reference location %s:%d outside task or initial/always block", s1,
2002     __in_fils[ifi], lini);
2003    return;
2004   }
2005  /* can't set stmt breakpoint on delay control must go on action stmt */
2006  if (stp->stmttyp == S_DELCTRL)
2007   {
2008    stp2 = stp->st.sdc->actionst;
2009    if (stp2 == NULL)
2010     {
2011      __ia_err(1488,
2012       "statement %s only on delay control with action statement", s1);
2013      return;
2014     }
2015    stp = stp2;
2016   }
2017 
2018  bpp = (struct brkpt_t *) __my_malloc(sizeof(struct brkpt_t));
2019  init_brkpt(bpp);
2020  bpp->bp_type = BP_INST;
2021  bpp->bp_num = __nxt_bpnum++;
2022  bpp->bp_stp = stp;
2023  bpp->bp_itp = in_itp;
2024  bpp->bp_tskp = in_tskp;
2025  if (is_tmp) bpp->bp_rm_when_hit = TRUE;
2026  insert_brkpt(bpp);
2027 
2028  if (is_tmp) strcpy(s1, " (temp)"); else strcpy(s1, "");
2029  __cvsim_msg("Breakpoint%s (inst) %d set at %s in %s\n", s1,
2030   bpp->bp_num, __bld_lineloc(__xs, bpp->bp_stp->stfnam_ind,
2031   bpp->bp_stp->stlin_cnt), __msg_blditree(__xs, bpp->bp_itp, bpp->bp_tskp));
2032  __chk_extra_atend(TRUE);
2033 }
2034 
2035 /*
2036  * get the [line ref. after , in ibreakpoint
2037  * know , read and reads end of [line] or [file]:[line] reference
2038  * return F on error
2039  */
get_ibrk_linref(struct itree_t * itp,struct task_t * tskp,int32 * ifi,int32 * lini)2040 static int32 get_ibrk_linref(struct itree_t *itp, struct task_t *tskp,
2041  int32 *ifi, int32 *lini)
2042 {
2043  register char *chp;
2044  struct sy_t *syp;
2045  struct mod_t *mdp;
2046  char *savchp, *endchp;
2047  char sref[RECLEN];
2048 
2049  /* return F on error, if not [file]:[line], ifi set to -1 */
2050  if (!try_get_fillin_ref(__visp->vichp, ifi, lini, &savchp, &endchp))
2051   return(FALSE);
2052 
2053  if (*ifi != -1) __visp->vichp = endchp;
2054  else
2055   {
2056    /* know not [file]:[line] ref - must be line by itself */
2057    strncpy(sref, savchp, endchp - savchp);
2058    sref[endchp - savchp] = '\0';
2059    __visp->vichp = endchp;
2060    /* does not have : not [file]:[line] but maybe [line] */
2061    if (!isdigit(sref[0]))
2062     {
2063 bad_lin_num:
2064      __ia_err(1481, ":ibreakpoint ,[number] expected - %s read", sref);
2065      return(FALSE);
2066     }
2067    for (chp = sref; *chp != '\0'; chp++)
2068     { if (!isdigit(*chp)) goto bad_lin_num; }
2069    if (sscanf(sref, "%d", lini) != 1) goto bad_lin_num;
2070    if (tskp != NULL) syp = tskp->tsksyp; else syp = itp->itip->imsym;
2071     /* have [line] form - file is first in scope */
2072    *ifi = (int32) syp->syfnam_ind;
2073   }
2074  /* make sure in range */
2075  if (tskp != NULL)
2076   {
2077    if (!scope_lini_inrng(*lini, *ifi, tskp->tsksyp->sylin_cnt,
2078     (int32) tskp->tsksyp->syfnam_ind, tskp->tsk_last_lini, tskp->tsk_last_ifi))
2079     {
2080 out_of_rng:
2081      __ia_err(1482, ":ibreakpoint %s:%d not before statement in scope %s",
2082       __in_fils[*ifi], *lini, __msg_blditree(__xs, itp, tskp));
2083      return(FALSE);
2084     }
2085    return(TRUE);
2086   }
2087  /* must be in scope with initial/always and before last */
2088  mdp = itp->itip->imsym->el.emdp;
2089  if (!scope_lini_inrng(*lini, *ifi, mdp->msym->sylin_cnt,
2090   (int32) mdp->msym->syfnam_ind, mdp->mod_last_lini, mdp->mod_last_ifi))
2091   goto out_of_rng;
2092  if (mdp->ialst == NULL) goto out_of_rng;
2093  /* if after last - error later */
2094  return(TRUE);
2095 }
2096 
2097 /*
2098  * initialize a breakpoint
2099  */
init_brkpt(struct brkpt_t * bpp)2100 static void init_brkpt(struct brkpt_t *bpp)
2101 {
2102  bpp->bp_type = BP_UNKN;
2103  bpp->bp_can_halt = TRUE;
2104  bpp->bp_enable = TRUE;
2105  /* unused for now */
2106  bpp->bp_prttyp = 0;
2107  bpp->bp_dup = FALSE;
2108  bpp->bp_rm_when_hit = FALSE;
2109  bpp->bp_num = -1;
2110  bpp->bp_ignore_cnt = 0;
2111  bpp->bp_hit_cnt = 0;
2112  bpp->bp_stp = NULL;
2113  bpp->bp_itp = NULL;
2114  bpp->bp_tskp = NULL;
2115  bpp->bp_condx = NULL;
2116  bpp->bpnxt = NULL;
2117 }
2118 
2119 /*
2120  * insert the breakpoint with duplicate same loc. flag setting
2121  * this traverses to end of list - know new number is one higher than last
2122  */
insert_brkpt(struct brkpt_t * bpp)2123 static void insert_brkpt(struct brkpt_t *bpp)
2124 {
2125  register struct brkpt_t *bpp2;
2126  struct brkpt_t *bpp_last;
2127  int32 seen_same_line;
2128 
2129  seen_same_line = FALSE;
2130  for (bpp_last = NULL, bpp2 = __bphdr; bpp2 != NULL; bpp2 = bpp2->bpnxt)
2131   {
2132    /* set dup if same line number seen */
2133    if (bpp->bp_stp->stfnam_ind == bpp2->bp_stp->stfnam_ind
2134     && bpp->bp_stp->stlin_cnt == bpp2->bp_stp->stlin_cnt)
2135     {
2136      if (!seen_same_line)
2137       {
2138        __cvsim_msg("Note: other statement breakpoint(s) set at %s\n",
2139         __bld_lineloc(__xs, bpp->bp_stp->stfnam_ind, bpp->bp_stp->stlin_cnt));
2140        seen_same_line = TRUE;
2141       }
2142      bpp2->bp_dup = bpp->bp_dup = TRUE;
2143     }
2144    bpp_last = bpp2;
2145   }
2146  /* insert on end - bpp last is recomputed tmp */
2147  if (__bphdr == NULL) __bphdr = bpp;
2148  else
2149   {
2150    /* SJM 08/02/01 - add if to keep lint happy */
2151    if (bpp_last != NULL) bpp_last->bpnxt = bpp;
2152   }
2153  /* finally arm breakpoint */
2154  if (!bpp->bp_dup)
2155   {
2156    /* DBG - remove */
2157    if (bpp->bp_stp->stmttyp == S_BRKPT) __misc_terr(__FILE__, __LINE__);
2158    bpp->bp_stp->stmttyp = S_BRKPT;
2159   }
2160 }
2161 
2162 /*
2163  * routine to find statement given ifi and lini
2164  * returns NULL on error
2165  * if not [file]:[line] - know will match first line if any exists
2166  * finds first statement after line - error if not found in scope
2167  * tricky because scope can extend across multiple files
2168  */
conv_line_tostmt(struct mod_t * in_mdp,struct task_t * in_tskp,int32 ifi,int32 lini)2169 static struct st_t *conv_line_tostmt(struct mod_t *in_mdp,
2170  struct task_t *in_tskp, int32 ifi, int32 lini)
2171 {
2172  register struct ialst_t *ialp;
2173  struct st_t *stp, *stp2;
2174  struct incloc_t *ilp;
2175  int32 st_ifi, st_lini, ifi2, lini2;
2176 
2177  /* if in included file, must use line included form in range tests */
2178  if ((ilp = find2_incloc(ifi)) != NULL)
2179   { ifi2 = ilp->incfrom_fnind; lini2 = ilp->incfrom_lcnt; }
2180  else { ifi2 = ifi; lini2 = lini; }
2181 
2182  /* if task, know will have statements and use last if after */
2183  if (in_tskp != NULL)
2184   {
2185    stp = in_tskp->tskst;
2186    /* know will always be at least an NONE - ; by itself */
2187    if (stp == NULL) __misc_terr(__FILE__, __LINE__);
2188    st_ifi = (int32) stp->stfnam_ind;
2189    st_lini = stp->stlin_cnt;
2190    /* if location in task and before first statement - use first statement */
2191    if (ifi2 <= st_ifi && lini2 <= st_lini) return(stp);
2192 
2193    /* here must use included file/line */
2194    if ((stp2 = find_lstofsts_stp(stp, ifi, lini)) != NULL) return(stp2);
2195    /* since know in task and not before any statement - must be after last */
2196    /* change to last */
2197    /* if after last - not found since know in scope becomes last */
2198    return(__blklast_stp);
2199   }
2200  /* in module, look through ia blocks - must be from 1st to last statement */
2201  /* after 1st part of last statement to end will be error not last stmt */
2202  for (ialp = in_mdp->ialst; ialp != NULL; ialp = ialp->ialnxt)
2203   {
2204    stp = ialp->iastp;
2205    /* if location before, begin of initial/always skip */
2206    if (ifi2 < ialp->ia_first_ifi || (ifi2 == ialp->ia_first_ifi
2207     && lini2 < ialp->ia_first_lini)) continue;
2208    /* if location after, end of initial/always skip */
2209    if (ifi2 > (int32) ialp->ia_last_ifi || (ifi2 == ialp->ia_last_ifi
2210     && lini2 > ialp->ia_last_lini)) continue;
2211 
2212    /* here must match include line */
2213    if ((stp2 = find_lstofsts_stp(stp, ifi, lini)) != NULL) return(stp2);
2214    /* if after last in init/always, just use last - know muat be there */
2215    return(__blklast_stp);
2216   }
2217  return(NULL);
2218 }
2219 
2220 /*
2221  * for searching source file, find next statement
2222  * passed last statement which know line number after (also file)
2223  * and before or equal to next statement (stnxt) if there is one
2224  *
2225  * return match or NULL if at last
2226  * know line after last_stp and before next statement
2227  * look inside statement if possible
2228  */
find_nxtstp(struct st_t * last_stp,int32 ifi,int32 lini)2229 static struct st_t *find_nxtstp(struct st_t *last_stp, int32 ifi, int32 lini)
2230 {
2231  int32 fji;
2232  byte styp;
2233  int32 st_ifi, st_lini, has_else;
2234  struct st_t *tmpstp, *stp2, *fjstp;
2235  struct task_t *tskp;
2236 
2237 again:
2238  styp = (byte) last_stp->stmttyp;
2239 brk_again:
2240  switch (styp) {
2241   case S_IF:
2242    /* know after if ( ) and before next stmtm */
2243    /* if no else, only look in if */
2244    if (last_stp->st.sif.elsest == NULL)
2245     {
2246      has_else = FALSE;
2247 try_then:
2248      if ((tmpstp = find_lstofsts_stp(last_stp->st.sif.thenst, ifi, lini))
2249       != NULL) return(tmpstp);
2250      if (has_else) return(last_stp->st.sif.elsest);
2251      break;
2252     }
2253    /* has else */
2254    tmpstp = last_stp->st.sif.elsest;
2255    st_ifi = (int32) tmpstp->stfnam_ind;
2256    st_lini = (int32) tmpstp->stlin_cnt;
2257    /* if match else statement, return it */
2258    if (ifi == st_ifi && lini == st_lini) return(tmpstp);
2259    if (ifi < st_ifi || (ifi == st_ifi && lini < st_lini))
2260     { has_else = TRUE; goto try_then; }
2261    /* can only in else or next statement */
2262    return(find_lstofsts_stp(last_stp->st.sif.elsest, ifi, lini));
2263   case S_FOR:
2264    return(find_lstofsts_stp(last_stp->st.sfor->forbody, ifi, lini));
2265   case S_FOREVER: case S_WHILE:
2266    return(find_lstofsts_stp(last_stp->st.swh.lpst, ifi, lini));
2267   case S_REPEAT:
2268    return(find_lstofsts_stp(last_stp->st.srpt.repst, ifi, lini));
2269   case S_WAIT:
2270    return(find_lstofsts_stp(last_stp->st.swait.lpst, ifi, lini));
2271 
2272   /* lists that need to be searched */
2273   case S_CASE:
2274    /* tricky since default can be anywhere - must find defl. insert loc */
2275    return(find_case_stp(last_stp, ifi, lini));
2276   case S_DELCTRL:
2277    /* know does not match location of # or @ <something> */
2278    /* if no action statement, done */
2279    if ((tmpstp = last_stp->st.sdc->actionst) == NULL) break;
2280    return(find_lstofsts_stp(tmpstp, ifi, lini));
2281   case S_NAMBLK:
2282    /* see if in name block, handles any where between begin and end */
2283    /* if inside name block must succeed */
2284    tskp = last_stp->st.snbtsk;
2285    if (scope_lini_inrng(lini, ifi, tskp->tsksyp->sylin_cnt,
2286     (int32) tskp->tsksyp->syfnam_ind, tskp->tsk_last_lini, tskp->tsk_last_ifi))
2287     {
2288      tmpstp = tskp->tskst;
2289      /* if location in task and before first sttt - use first statement */
2290      if (ifi <= (int32) tmpstp->stfnam_ind && lini <= tmpstp->stlin_cnt)
2291       return(tmpstp);
2292 
2293      /* this will set last if past last in block statement */
2294      if ((stp2 = find_lstofsts_stp(tmpstp, ifi, lini)) != NULL) return(stp2);
2295      return(__blklast_stp);
2296     }
2297    break;
2298   case S_UNBLK:
2299    /* know after begin */
2300    return(find_lstofsts_stp(last_stp->st.sbsts, ifi, lini));
2301   case S_UNFJ:
2302    /* know after fork */
2303    for (fji = 0;; fji++)
2304     {
2305      if ((fjstp = last_stp->st.fj.fjstps[fji]) == NULL) break;
2306 
2307      /* if find, done */
2308      if ((tmpstp = find_lstofsts_stp(fjstp, ifi, lini)) != NULL)
2309       return(tmpstp);
2310     }
2311    /* know after last - matches next one up */
2312    break;
2313   /* special simulation control statements */
2314   case S_REPSETUP:
2315    /* this must be invisible - has same line as next stmt */
2316    last_stp = last_stp->stnxt;
2317    goto again;
2318   case S_REPDCSETUP:
2319    /* this must be invisible - has same line as next stmt */
2320    last_stp = last_stp->stnxt;
2321    goto again;
2322   case S_GOTO:
2323    /* here there will never be a next */
2324    if (last_stp->stnxt != NULL) __misc_terr(__FILE__, __LINE__);
2325    break;
2326   case S_BRKPT:
2327    styp = (byte) last_stp->rl_stmttyp;
2328    goto brk_again;
2329   default: break;
2330  }
2331  return(NULL);
2332 }
2333 
2334 /*
2335  * find next statement in list
2336  * can be before first in which case return first, if after last, return nil
2337  */
find_lstofsts_stp(struct st_t * hdrstp,int32 ifi,int32 lini)2338 static struct st_t *find_lstofsts_stp(struct st_t *hdrstp, int32 ifi, int32 lini)
2339 {
2340  register struct st_t *stp;
2341  int32 st_ifi, st_lini, ifi2, lini2;
2342  struct st_t *stp2;
2343  struct incloc_t *ilp;
2344 
2345  for (__blklast_stp = NULL, stp = hdrstp; stp != NULL; stp = stp->stnxt)
2346   {
2347    /* know does not match header */
2348    st_ifi = (int32) stp->stfnam_ind;
2349    st_lini = (int32) stp->stlin_cnt;
2350    /* if line and statement in same file use if before or at */
2351    if (ifi == st_ifi && lini <= st_lini) return(stp);
2352 
2353    /* if next statement is inside include use it if before include point */
2354    /* notice if includes nested must find include line in current file */
2355    /* which may be included itself */
2356    if ((ilp = find3_incloc(st_ifi, ifi)) != NULL)
2357     {
2358      ifi2 = ilp->incfrom_fnind;
2359      lini2 = ilp->incfrom_lcnt;
2360      /* if before or at include use first statement of include */
2361      if (ifi < ifi2 || (ifi == ifi2 && lini <= lini2)) return(stp);
2362     }
2363    else
2364     {
2365      /* normal rule: if before or at next loop statement return it */
2366      if (ifi < st_ifi || (ifi == st_ifi && lini <= st_lini)) return(stp);
2367     }
2368    /* this statement may be block or other complicated */
2369    if ((stp2 = find_nxtstp(stp, ifi, lini)) != NULL) return(stp2);
2370    /* after current and any substatement structure */
2371    __blklast_stp = stp;
2372   }
2373  /* after block - will probably be at next statement */
2374  return(NULL);
2375 }
2376 
2377 /*
2378  * find incloc that is non included file
2379  * for multiply included this returns location of outermost or caller if
2380  * caller is itself an included file
2381  */
find3_incloc(int32 ifi,int32 call_ifi)2382 static struct incloc_t *find3_incloc(int32 ifi, int32 call_ifi)
2383 {
2384  struct incloc_t *ilp, *ilp2;
2385 
2386  if ((ilp2 = find_incloc(ifi)) == NULL) return(NULL);
2387  /* know included trace outward until finding one not included and */
2388  /* return that ilp */
2389  for (;;)
2390   {
2391    ifi = ilp2->incfrom_fnind;
2392    if (ifi == call_ifi) return(ilp2);
2393    ilp = ilp2;
2394    if ((ilp2 = find_incloc(ifi)) == NULL) break;
2395   }
2396  return(ilp);
2397 }
2398 
2399 /*
2400  * find statement inside (or after case)
2401  * know after case header and can have default case somwwhere
2402  * each case statement or default can be list (begin elided)
2403  */
find_case_stp(struct st_t * last_stp,int32 ifi,int32 lini)2404 static struct st_t *find_case_stp(struct st_t *last_stp, int32 ifi, int32 lini)
2405 {
2406  register struct csitem_t *csip;
2407  struct st_t *stp, *tmpstp, *stp_after_dflt;
2408  struct csitem_t *dflt_csip;
2409 
2410  dflt_csip = last_stp->st.scs.csitems;
2411  if (dflt_csip->csist != NULL) stp_after_dflt = find_afterdflt(dflt_csip);
2412  else stp_after_dflt = NULL;
2413  for (csip = dflt_csip->csinxt; csip != NULL; csip = csip->csinxt)
2414   {
2415    stp = csip->csist;
2416 
2417    /* if this case statement list after default, see if in default range */
2418    /* only T if has default, i.e. no stp non nil so will never match */
2419    if (stp_after_dflt == stp)
2420     {
2421      if ((tmpstp = find_lstofsts_stp(dflt_csip->csist, ifi, lini)) != NULL)
2422       return(tmpstp);
2423      /* if after default end, look at next case */
2424     }
2425    /* see if in this case range */
2426    if ((tmpstp = find_lstofsts_stp(stp, ifi, lini)) != NULL) return(tmpstp);
2427   }
2428  /* this will move up stack to connect ending stnxt to next exec. place */
2429  if (dflt_csip->csist != NULL && stp_after_dflt == NULL)
2430   return(find_lstofsts_stp(dflt_csip->csist, ifi, lini));
2431  return(NULL);
2432 }
2433 
2434 /*
2435  * find case statement immediately after default
2436  * only called if has default
2437  * returns nil on common default at end case
2438  */
find_afterdflt(struct csitem_t * dflt_csip)2439 static struct st_t *find_afterdflt(struct csitem_t *dflt_csip)
2440 {
2441  register struct csitem_t *csip;
2442  int32 st_ifi, st_lini, dflt_ifi, dflt_lini;
2443  struct st_t *dfltstp, *stp;
2444 
2445  dfltstp = dflt_csip->csist;
2446  dflt_ifi = (int32) dfltstp->stfnam_ind;
2447  dflt_lini = dfltstp->stlin_cnt;
2448 
2449  /* key is that know all case items except default in source order */
2450  /* also one after default is always first in source order */
2451  for (csip = dflt_csip->csinxt; csip != NULL; csip = csip->csinxt)
2452   {
2453    stp = csip->csist;
2454    st_ifi = (int32) stp->stfnam_ind;
2455    st_lini = stp->stlin_cnt;
2456    if (st_ifi > dflt_ifi || (st_ifi == dflt_ifi && st_lini >= dflt_lini))
2457     return(stp);
2458   }
2459  return(NULL);
2460 }
2461 
2462 #define TYP_BRKPTS 0
2463 #define TYP_DISP 1
2464 
2465 /* info command options table */
2466 static struct namlst_t dtyparg[] = {
2467  { TYP_BRKPTS, "breakpoints" },
2468  { TYP_DISP, "displays" }
2469 };
2470 #define NTYPARGS (sizeof(dtyparg) / sizeof(struct namlst_t))
2471 
2472 /*
2473  * : debugger breakpint32 delete command
2474  */
__do_dbg_delbrkdis(void)2475 extern void __do_dbg_delbrkdis(void)
2476 {
2477  int32 bpnum, deltyp;
2478 
2479  __get_vtok();
2480  if (__toktyp == ID)
2481   { deltyp = __get_dbcmdnum(__token, dtyparg, NTYPARGS); __get_vtok(); }
2482  else deltyp = TYP_BRKPTS;
2483 
2484  if (deltyp == TYP_BRKPTS)
2485   {
2486    if (__toktyp == TEOF) del_all_brkpts();
2487    else
2488     {
2489      if ((bpnum = __get_dbg_val()) == -1 || bpnum < 1)
2490       {
2491        __ia_err(1471, "breakpoint number %s illegal - can not delete",
2492         __prt_vtok());
2493        return;
2494       }
2495      del_brkpt_num(bpnum);
2496      __chk_extra_atend(TRUE);
2497     }
2498   }
2499  else
2500   {
2501    if (__toktyp == TEOF) del_all_disps();
2502    else { del_disp_num(); __chk_extra_atend(TRUE); }
2503   }
2504 }
2505 
2506 /*
2507  * delete all breakpoints
2508  */
del_all_brkpts(void)2509 static void del_all_brkpts(void)
2510 {
2511  register struct brkpt_t *bpp, *bpp2;
2512  char s1[RECLEN];
2513 
2514  if (__bphdr == NULL)
2515   { __ia_err(1466, "no breakpoints to delete"); return; }
2516  __cvsim2_msg("Delete all breakpoints? (y/n) ");
2517  /* FIXME - how read input from vendor 1 side */
2518  if (fgets(s1, RECLEN, stdin) == NULL || (s1[0] != 'y' && s1[0] != 'Y'))
2519   return;
2520  for (bpp = __bphdr; bpp != NULL;)
2521   {
2522    bpp2 = bpp->bpnxt;
2523    /* if triggered, untrigger */
2524    if (bpp->bp_stp->stmttyp == S_BRKPT)
2525     bpp->bp_stp->stmttyp = bpp->bp_stp->rl_stmttyp;
2526    __my_free((char *) bpp, sizeof(struct brkpt_t));
2527    bpp = bpp2;
2528   }
2529  __bphdr = NULL;
2530 }
2531 
2532 /*
2533  * delete break in globals tok typ and token
2534  */
del_brkpt_num(int32 bpnum)2535 static void del_brkpt_num(int32 bpnum)
2536 {
2537  register struct brkpt_t *bpp;
2538  struct brkpt_t *last_bpp, *bpp2;
2539  int32 bpcnt;
2540 
2541  /* delete break numbered bpnum */
2542  for (last_bpp = NULL, bpp = __bphdr; bpp != NULL; bpp = bpp->bpnxt)
2543   {
2544    if (bpp->bp_num == bpnum)
2545     {
2546      if (last_bpp == NULL) __bphdr = bpp->bpnxt;
2547      else last_bpp->bpnxt = bpp->bpnxt;
2548 
2549      /* for temporary break points reuse number if last */
2550      if (bpp->bp_rm_when_hit)
2551       { if (bpp->bp_num == __nxt_bpnum - 1) __nxt_bpnum--; }
2552 
2553      /* notice by here one to delete removed from list */
2554      bpcnt = cnt_same_brkpts((int32) bpp->bp_stp->stfnam_ind,
2555       bpp->bp_stp->stlin_cnt, &bpp2);
2556      /* if no more at this location and triggered, untrigger */
2557      if (bpcnt == 0 && bpp->bp_stp->stmttyp == S_BRKPT)
2558       bpp->bp_stp->stmttyp = bpp->bp_stp->rl_stmttyp;
2559      /* if only one left at location unset the dup flag */
2560      if (bpcnt == 1) bpp2->bp_dup = FALSE;
2561      /* final step is to free the bp */
2562      __my_free((char *) bpp, sizeof(struct brkpt_t));
2563      return;
2564     }
2565    last_bpp = bpp;
2566   }
2567  __ia_err(1471, "no breakpoint number %d", bpnum);
2568 }
2569 
2570 /*
2571  * count number of breakpoints at same location
2572  */
cnt_same_brkpts(int32 ifi,int32 lini,struct brkpt_t ** last_bpp)2573 static int32 cnt_same_brkpts(int32 ifi, int32 lini, struct brkpt_t **last_bpp)
2574 {
2575  int32 cnt;
2576  register struct brkpt_t *bpp;
2577 
2578  cnt = 0;
2579  *last_bpp = NULL;
2580  for (bpp = __bphdr; bpp != NULL; bpp = bpp->bpnxt)
2581   {
2582    if (ifi == (int32) bpp->bp_stp->stfnam_ind && lini == bpp->bp_stp->stlin_cnt)
2583     {
2584      cnt++;
2585      *last_bpp = bpp;
2586     }
2587   }
2588  return(cnt);
2589 }
2590 
2591 /*
2592  * undisplay breakpoints - same as delete display [optional number]
2593  */
__dbg_undisplay(void)2594 extern void __dbg_undisplay(void)
2595 {
2596  __get_vtok();
2597  if (__toktyp == TEOF) del_all_disps();
2598  else { del_disp_num(); __chk_extra_atend(TRUE); }
2599 }
2600 
2601 /*
2602  * delete all auto-display points
2603  */
del_all_disps(void)2604 static void del_all_disps(void)
2605 {
2606  register struct dispx_t *dxp, *dxp2;
2607  char s1[RECLEN];
2608 
2609  if (__dispxhdr == NULL)
2610   { __ia_err(1466, "no displays to delete"); return; }
2611  __cvsim2_msg("Delete all displays? (y/n) ");
2612  if (fgets(s1, RECLEN, stdin) == NULL || (s1[0] != 'y' && s1[0] != 'Y'))
2613   return;
2614  for (dxp = __dispxhdr; dxp != NULL;)
2615   {
2616    dxp2 = dxp->dsp_nxt;
2617    __my_free((char *) dxp, sizeof(struct dispx_t));
2618    dxp = dxp2;
2619   }
2620  __dispxhdr = NULL;
2621 }
2622 
2623 /*
2624  * delelete a display by number from tok typ and token
2625  * know token read before calling this
2626  */
del_disp_num(void)2627 static void del_disp_num(void)
2628 {
2629  register struct dispx_t *dxp;
2630  struct dispx_t *last_dxp;
2631  int32 disnum;
2632 
2633  if ((disnum = __get_dbg_val()) == -1 || disnum < 1)
2634   {
2635    __ia_err(1471, "auto-display number %s illegal - can not delete",
2636     __prt_vtok());
2637    return;
2638   }
2639  /* delete auto-display numbered disnum */
2640  for (last_dxp = NULL, dxp = __dispxhdr; dxp != NULL; dxp = dxp->dsp_nxt)
2641   {
2642    if (dxp->dsp_num == disnum)
2643     {
2644      if (last_dxp == NULL) __dispxhdr = dxp->dsp_nxt;
2645      else last_dxp->dsp_nxt = dxp->dsp_nxt;
2646 
2647      /* final step is to free the bp */
2648      __my_free((char *) dxp, sizeof(struct dispx_t));
2649      return;
2650     }
2651    last_dxp = dxp;
2652   }
2653  __ia_err(1471, "no auto-display number %d", disnum);
2654 }
2655 
2656 /*
2657  * disable or enable a breakpoint or display
2658  */
__do_dbg_dis_enable(int32 do_enable)2659 extern void __do_dbg_dis_enable(int32 do_enable)
2660 {
2661  register struct brkpt_t *bpp;
2662  register struct dispx_t *dxp;
2663  int32 denum, disentyp;
2664  char s1[RECLEN];
2665 
2666  if (do_enable) strcpy(s1, "enable"); else strcpy(s1, "disable");
2667  __get_vtok();
2668  if (__toktyp == ID)
2669   {
2670    disentyp = __get_dbcmdnum(__token, dtyparg, NTYPARGS);
2671    __get_vtok();
2672   }
2673  else disentyp = TYP_BRKPTS;
2674 
2675  if (disentyp == TYP_BRKPTS)
2676   {
2677    if (__toktyp == TEOF) denum = -2;
2678    else
2679     {
2680      if ((denum = __get_dbg_val()) == -1 || denum < 1)
2681       {
2682        __ia_err(1477, ":%s expected breakpoint number %s illegal", s1,
2683         __prt_vtok());
2684        return;
2685       }
2686     }
2687    /* delete break numbered bpnum */
2688    for (bpp = __bphdr; bpp != NULL; bpp = bpp->bpnxt)
2689     {
2690      if (denum == -2 || bpp->bp_num == denum)
2691       {
2692        bpp->bp_enable = (do_enable) ? TRUE : FALSE;
2693        if (denum != -2) goto done;
2694       }
2695     }
2696    if (denum == -2) goto done;
2697    __ia_err(1479, ":%s breakpoint failed - no breakpoint number %d",
2698      s1, denum);
2699    return;
2700   }
2701  /* display case */
2702  if (__toktyp == TEOF) denum = -2;
2703  else
2704   {
2705    if ((denum = __get_dbg_val()) == -1 || denum < 1)
2706     {
2707      __ia_err(1477, ":%s expected auto-display number %s illegal", s1,
2708       __prt_vtok());
2709      return;
2710     }
2711   }
2712  /* delete break numbered bpnum */
2713  for (dxp = __dispxhdr; dxp != NULL; dxp = dxp->dsp_nxt)
2714   {
2715    if (denum == -2 || dxp->dsp_num == denum)
2716     {
2717      dxp->dsp_enable = (do_enable) ? TRUE : FALSE;
2718      if (denum != -2) goto done;
2719     }
2720   }
2721  if (denum == -2) goto done;
2722  __ia_err(1479, ":%s displays failed - no auto-display number %d",
2723   s1, denum);
2724  return;
2725 
2726 done:
2727  __chk_extra_atend(TRUE);
2728 }
2729 
2730 /*
2731  * set ignore count for a break point (add to current hit count)
2732  *
2733  * :cond [bp num] [ingore count]
2734  * ignore next count breakpoints before breaking
2735  */
__dbg_brk_ignore(void)2736 extern void __dbg_brk_ignore(void)
2737 {
2738  int32 icnt;
2739  struct brkpt_t *bpp;
2740 
2741  __get_vtok();
2742  if ((bpp = rd_brkpt_num(":ignore", 1)) == NULL) return;
2743  __get_vtok();
2744  if (__toktyp == TEOF)
2745   {
2746    __ia_err(1491,
2747     ":ignore second argument (number of hits to ignore) missing");
2748    return;
2749   }
2750  if ((icnt = __get_dbg_val()) == -1 || icnt < 0)
2751   {
2752    __ia_err(1492,
2753     ":ignore second argument (number of hits to ignore) illegal - %s read",
2754     __prt_vtok());
2755    return;
2756   }
2757 
2758  /* ignore count value in brk pt record is number from current hit number */
2759  /* count is number to ignore so 0 is next, 1 is skip 1, and stop on next */
2760  /* and so on */
2761  bpp->bp_ignore_cnt = bpp->bp_hit_cnt + icnt;
2762  if (icnt == 0)
2763   __cvsim_msg("Stopping next time breakpoint %d is reached.\n", bpp->bp_num);
2764  else __cvsim_msg("Ignoring next %d crossings of breakpoint %d.\n", icnt,
2765   bpp->bp_num);
2766 }
2767 
2768 /*
2769  * read a break point number argument and return break point record
2770  * returns nil on error
2771  * expects number token to have been read and reads no more
2772  */
rd_brkpt_num(char * cmdnam,int32 argnum)2773 static struct brkpt_t *rd_brkpt_num(char *cmdnam, int32 argnum)
2774 {
2775  int32 bpnum;
2776  struct brkpt_t *bpp;
2777 
2778  if (__toktyp == TEOF)
2779   {
2780    __ia_err(1491,
2781     "%s argument number %d (break point number) missing", cmdnam, argnum);
2782    return(NULL);
2783   }
2784  if ((bpnum = __get_dbg_val()) == -1)
2785   {
2786    __ia_err(1492, "%s argument number %d break point number %s illegal",
2787     cmdnam, argnum, __prt_vtok());
2788    return(NULL);
2789   }
2790  if ((bpp = find_bpp(bpnum)) == NULL)
2791   {
2792    __ia_err(1493,
2793     "there is no break point number %d (argument %d)", bpnum, argnum);
2794    return(NULL);
2795   }
2796  return(bpp);
2797 }
2798 
2799 /*
2800  * set up condition filter expresson for break point
2801  : :cond [bp num] [cond expr]
2802  */
__dbg_brk_cond(void)2803 extern void __dbg_brk_cond(void)
2804 {
2805  struct itree_t *sav_scope_ptr;
2806  struct task_t *sav_scope_tskp;
2807  struct expr_t *xp;
2808  struct brkpt_t *bpp;
2809 
2810  __get_vtok();
2811  if ((bpp = rd_brkpt_num(":cond", 1)) == NULL) return;
2812 
2813  /* if collect returns nil, know error emitted in routine */
2814  __get_vtok();
2815  /* ":cond [number]" turns off condition */
2816  if (__toktyp == TEOF)
2817   {
2818    __cvsim_msg("Breakpoint %d now unconditional.\n", bpp->bp_num);
2819    xp = NULL;
2820   }
2821  else
2822   {
2823    sav_scope_ptr = __scope_ptr;
2824    sav_scope_tskp = __scope_tskp;
2825    __scope_ptr = bpp->bp_itp;
2826    __scope_tskp = bpp->bp_tskp;
2827    __push_itstk(__scope_ptr);
2828    xp = __rd_iact_expr();
2829    __pop_itstk();
2830    __scope_ptr = sav_scope_ptr;
2831    __scope_tskp = sav_scope_tskp;
2832    if (xp == NULL) return;
2833   }
2834  bpp->bp_condx = xp;
2835  __chk_extra_atend(TRUE);
2836 }
2837 
2838 /*
2839  * find a break point given its number
2840  */
find_bpp(int32 bpnum)2841 static struct brkpt_t *find_bpp(int32 bpnum)
2842 {
2843  register struct brkpt_t *bpp;
2844 
2845  for (bpp = __bphdr; bpp != NULL; bpp = bpp->bpnxt)
2846   { if (bpp->bp_num == bpnum) return(bpp); }
2847  return(NULL);
2848 }
2849 
2850 /*
2851  * process a breakpoint
2852  *
2853  * called from v_ex using exec itree loc.
2854  * tricky because possibly multiple breaks at one statement
2855  * if returns FALSE, does not enter iact and execs and reenables stmt brk
2856  * whenever statement with break execed, rearms but setting type to S BRK
2857  *
2858  * complicated breakpoint logic - every hit stmt breakpoint must change to
2859  * can not halt so will be execed
2860  */
__process_brkpt(struct st_t * stp)2861 extern int32 __process_brkpt(struct st_t *stp)
2862 {
2863  register struct brkpt_t *bpp;
2864  int32 stop_from_dup;
2865  struct brkpt_t *brk_bpp, *bpp2, *first_hitbpp;
2866 
2867  /* always find first in list */
2868  brk_bpp = NULL;
2869  first_hitbpp = NULL;
2870  for (bpp = __bphdr; bpp != NULL; bpp = bpp->bpnxt)
2871   { if (bpp->bp_stp == stp) goto found_stmt_match; }
2872  /* if have statement with type breakpoint must be in table */
2873  __arg_terr(__FILE__, __LINE__);
2874 
2875 found_stmt_match:
2876  brk_bpp = bpp;
2877  /* if any on same line in not can halt state all are, cont from break, */
2878  /* scheme is once exec of SBRK stmt, turn off can halt so next time */
2879  /* stmt execed not S BRK */
2880  if (!brk_bpp->bp_can_halt)
2881   {
2882    /* rearm (all on line if needed) and return F - will exec stmt. */
2883    /* notice brk_bpp is first on stmt */
2884    if (brk_bpp->bp_dup)
2885     {
2886      for (bpp = brk_bpp; bpp != NULL; bpp = bpp->bpnxt)
2887       { if (bpp->bp_stp == stp) bpp->bp_can_halt = TRUE; }
2888     }
2889    else brk_bpp->bp_can_halt = TRUE;
2890    /* now all breakpoints at statement armed and will exec statement */
2891    return(FALSE);
2892   }
2893 
2894  /* found breakpoints on line - see if filters eliminate stop */
2895  if (!brk_bpp->bp_dup)
2896   {
2897    if (elim_brkpt_fromcond(brk_bpp))
2898     {
2899      /* make sure stmt gets execed next time it is execed */
2900      /* when hit stmt does not get advanced, go thru here first */
2901      brk_bpp->bp_can_halt = TRUE;
2902      return(FALSE);
2903     }
2904    first_hitbpp = brk_bpp;
2905   }
2906  else
2907   {
2908    stop_from_dup = FALSE;
2909    for (bpp = brk_bpp; bpp != NULL; bpp = bpp->bpnxt)
2910     {
2911      if (bpp->bp_stp != stp) continue;
2912      /* if find any that stop, must stop */
2913      if (!elim_brkpt_fromcond(bpp))
2914       {
2915        stop_from_dup = TRUE;
2916        if (first_hitbpp == NULL) first_hitbpp = bpp;
2917       }
2918     }
2919    if (!stop_from_dup)
2920     {
2921      /* all are filtered out, no stop */
2922      for (bpp = brk_bpp; bpp != NULL; bpp = bpp->bpnxt)
2923       { if (bpp->bp_stp == stp) bpp->bp_can_halt = TRUE; }
2924      return(FALSE);
2925     }
2926   }
2927 
2928  /* mark all as cannot stop for next exec and inc count on all */
2929  if (!brk_bpp->bp_dup) brk_bpp->bp_can_halt = FALSE;
2930  else
2931   {
2932    for (bpp = brk_bpp; bpp != NULL; bpp = bpp->bpnxt)
2933     { if (bpp->bp_stp != stp) continue; bpp->bp_can_halt = FALSE; }
2934   }
2935  /* need to indicate at this line in case step since have hit this line */
2936  __step_lini = stp->stlin_cnt;
2937  __step_ifi = (int32) stp->stfnam_ind;
2938 
2939  /* hit breakpoint - write message and setup suspend into interactive dbger */
2940  __cvsim_msg("\nBreakpoint %d scope %s", first_hitbpp->bp_num,
2941   __msg_blditree(__xs, __inst_ptr, first_hitbpp->bp_tskp));
2942  __cvsim_msg(" (%s line %d)", __in_fils[stp->stfnam_ind], stp->stlin_cnt);
2943  if (__last_brktime != __simtime)
2944   {
2945    __cvsim_msg(" time %s\n", __to_timstr(__xs, &__simtime));
2946    __last_brktime = __simtime;
2947   }
2948  else __cvsim_msg("\n");
2949  __prt_src_lines((int32) stp->stfnam_ind, stp->stlin_cnt, stp->stlin_cnt);
2950 
2951  /* remove all temp (t) breaks at this statement */
2952  /* know break always put on first statement of line */
2953  if (brk_bpp->bp_dup)
2954   {
2955    for (bpp = brk_bpp; bpp != NULL;)
2956     {
2957      bpp2 = bpp->bpnxt;
2958      if (bpp->bp_stp == stp)
2959       { if (bpp->bp_rm_when_hit) del_brkpt_num(bpp->bp_num); }
2960      bpp = bpp2;
2961     }
2962   }
2963  else { if (brk_bpp->bp_rm_when_hit) del_brkpt_num(brk_bpp->bp_num); }
2964 
2965  /* must not suspend thread here since when hit enter iact test will */
2966  /* supsend, suspend on entry needed in case ^c entry to interact */
2967  /* even if interrupt (^c) received, doing again does not hurt */
2968  signal(SIGINT, SIG_IGN);
2969 
2970  __pending_enter_iact = TRUE;
2971  __iact_reason = IAER_BRKPT;
2972  return(TRUE);
2973 }
2974 
2975 /*
2976  * process all conditions that disable stopping from a break point
2977  * returns T if break point eliminated (i.e. not stopped at)
2978  * F => break hit need to enter iact mode
2979  */
elim_brkpt_fromcond(struct brkpt_t * bpp)2980 static int32 elim_brkpt_fromcond(struct brkpt_t *bpp)
2981 {
2982  struct xstk_t *xsp;
2983  word32 tmp;
2984 
2985  /* handle all not dup cases */
2986  if (!bpp->bp_enable || (bpp->bp_type == BP_INST
2987    && bpp->bp_itp != __inst_ptr)) return(TRUE);
2988 
2989  /* evaluate conditional expression if present */
2990  if (bpp->bp_condx != NULL)
2991   {
2992    __push_itstk(bpp->bp_itp);
2993    xsp = __eval_xpr(bpp->bp_condx);
2994    /* normal loop T condition, if any bit 1, then T (non zero) */
2995    if (xsp->xslen <= WBITS)
2996     {
2997      /* SJM 07/20/00 - must convert to real if real */
2998      if (bpp->bp_condx->is_real)
2999       {
3000        double d1;
3001 
3002        memcpy(&d1, xsp->ap, sizeof(double));
3003        tmp = (d1 != 0.0);
3004       }
3005      else tmp = ((xsp->ap[0] & ~xsp->bp[0]) != 0L);
3006     }
3007    else tmp = (__cvt_lngbool(xsp->ap, xsp->bp, wlen_(xsp->xslen)) == 1);
3008    __pop_xstk();
3009    __pop_itstk();
3010    /* non 1 (F) so routine returns T to cancel */
3011    if (!tmp) return(TRUE);
3012   }
3013  /* must always increment hit count before checking ignore count */
3014  /* otherwide will never advance to ignore count */
3015  (bpp->bp_hit_cnt)++;
3016 
3017  /* being ignored because not yet hit enough times */
3018  /* if hit is 0, and ignore is 1, 1st time here will both be 1 */
3019  /* so not hit, 2nd time hit will be 2, so hit */
3020  /* DBG remove ---
3021  __dbg_msg("=== hit count for break %d is %d and ignore count is %d ===\n",
3022   bpp->bp_num, bpp->bp_hit_cnt, bpp->bp_ignore_cnt);
3023  --- */
3024 
3025  if (bpp->bp_hit_cnt <= bpp->bp_ignore_cnt) return(TRUE);
3026  return(FALSE);
3027 }
3028 
3029 /*
3030  * ROUTINES TO RESET STATE TO START OF SIM
3031  */
3032 
3033 /*
3034  * reset simulation back to time 0
3035  * LOOKATME - could just save after initializing values then just reload
3036  */
__reset_to_time0(void)3037 extern void __reset_to_time0(void)
3038 {
3039  register int32 i;
3040  register struct thread_t *thp;
3041  char *chp;
3042  struct telhdr_t *telp;
3043  struct thread_t *thp2;
3044  struct fmonlst_t *fmonp, *fmonp2;
3045  struct dceauxlst_t *dclp;
3046  struct mdvmast_t *mdvp, *mdvp2;
3047  struct dvchgnets_t *dvchgp, *dvchg_last;
3048  struct hctrl_t *hcp, *hcp2;
3049  struct strblst_t *strbp;
3050  struct mod_t *mdp;
3051  struct task_t *tskp;
3052  struct brkpt_t *bpp;
3053 
3054  /* --- debug remove --
3055  -* if (__debug_flg) __dmp_tskthrds(); *-
3056  if (__debug_flg) __dmp_all_thrds();
3057  --- */
3058 
3059  /* free the procedural threads and subthreads */
3060  /* this mark events so must be done first */
3061  /* know here thread always top level */
3062  for (thp = __initalw_thrd_hdr; thp != NULL;)
3063   {
3064    thp2 = thp->thright;
3065    /* free thp and all underneath */
3066    if (thp->thofs != NULL) __free_thd_list(thp->thofs);
3067    thp->th_ialw = FALSE;
3068    __free_1thd(thp);
3069    thp = thp2;
3070   }
3071  __initalw_thrd_hdr = NULL;
3072  /* disable all active interactive statements */
3073  for (hcp = __hctrl_hd; hcp != NULL;)
3074   {
3075    hcp2 = hcp->hc_nxt;
3076    /* unlink interactive leaving hcp since can just free element without */
3077    /* unlinking */
3078    __do_iact_disable(hcp, TRUE);
3079    __my_free((char *) hcp, sizeof(struct hctrl_t));
3080    hcp = hcp2;
3081   }
3082  /* DBG remove - check to make sure all tasks freed */
3083  for (mdp = __modhdr; mdp != NULL; mdp = mdp->mnxt)
3084   {
3085    for (tskp = mdp->mtasks; tskp != NULL; tskp = tskp->tsknxt)
3086     {
3087      if (tskp->tsktyp == FUNCTION)
3088       {
3089        if (tskp->tthrds != NULL) __misc_terr(__FILE__, __LINE__);
3090        continue;
3091       }
3092      for (i = 0; i < mdp->flatinum; i++)
3093       { if (tskp->tthrds[i] != NULL) __misc_terr(__FILE__, __LINE__); }
3094     }
3095   }
3096  /* --- */
3097 
3098  __hctrl_hd = __hctrl_end = NULL;
3099  /* any breakpoints halted but not yet continued from reset, reenable */
3100  /* when breakpoint counts added, will reset here */
3101  for (bpp = __bphdr; bpp != NULL; bpp = bpp->bpnxt)
3102   {
3103    bpp->bp_can_halt = TRUE;
3104    bpp->bp_ignore_cnt = 0;
3105   }
3106 
3107  /* free timing wheel and overflow queue - __twhsize index el fence left */
3108  /* this is needed because need to free guts of events and need to leave */
3109  /* tevtab action cb elements */
3110  for (i = 0; i < __twhsize; i++)
3111   { telp = __twheel[i]; __free_telhdr_tevs(telp); }
3112 
3113  /* after here overflow q empty, ready to be rebuilt - events freed elsewhere */
3114  if (__btqroot != NULL) __free_btree(__btqroot);
3115  __btqroot = NULL;
3116  __topi = 0;
3117 
3118  /* cur te hdr/end is same as one of twheel lists if hdr non nil */
3119  __cur_te_hdri = __cur_te_endi = -1;
3120 
3121  /* but no timing wheel te hdr corresponds to #0s */
3122  if (__p0_te_hdri != -1)
3123   {
3124    register i_tev_ndx tevpi, tevp2i;
3125 
3126    for (tevpi = __p0_te_hdri; tevpi != -1;)
3127     {
3128      tevp2i = __tevtab[tevpi].tenxti;
3129      __free_1tev(tevpi);
3130      tevpi = tevp2i;
3131     }
3132    __p0_te_hdri = __p0_te_endi = -1;
3133 
3134    for (tevpi = __nb_te_hdri; tevpi != -1;)
3135     {
3136      tevp2i = __tevtab[tevpi].tenxti;
3137      __free_1tev(tevpi);
3138      tevpi = tevp2i;
3139     }
3140    __nb_te_hdri = __nb_te_endi = -1;
3141   }
3142 
3143  /* free pending strobes for this time slot - if none added does nothing */
3144  if (__strobe_hdr != NULL)
3145   {
3146    /* must mark any seen but not output strobe as not seen */
3147    for (strbp = __strobe_hdr; strbp != NULL; strbp = strbp->strbnxt)
3148     strbp->strbstp->strb_seen_now = FALSE;
3149 
3150    __strobe_end->strbnxt = __strb_freelst;
3151    __strb_freelst = __strobe_hdr;
3152   }
3153  __strobe_hdr = __strobe_end = NULL;
3154 
3155  /* free pending dce list  */
3156  /* notice here dcevnts turned off when needed net dcelst's turned off */
3157  for (fmonp = __fmon_hdr; fmonp != NULL;)
3158   {
3159    fmonp2 = fmonp->fmonnxt;
3160    /* free all fmon aux list since only on if re-added after reset */
3161    for (dclp = fmonp->fmon_dcehdr; dclp != NULL; dclp = dclp->dclnxt)
3162     {
3163      /* AIV 11/26/02 dc events now built during elaboration and not freed */
3164      dclp->ldcep->dce_off = TRUE;
3165     }
3166    __my_free((char *) fmonp, sizeof(struct fmonlst_t));
3167    fmonp = fmonp2;
3168   }
3169  __fmon_hdr = __fmon_end = NULL;
3170 
3171  /* free any activated but not yet executed slot end fmonitors */
3172  if (__fmonse_hdr != NULL)
3173   {
3174    __fmonse_end->fmsenxt = __fmse_freelst;
3175    __fmse_freelst = __fmonse_hdr;
3176   }
3177 
3178  /* free monitor - same as call to $monitor with no arguments */
3179  /* know only 1 inst. */
3180  /* indcate no pending monitor */
3181  /* SJM 06/21/02 - never free monit dces - just turn off - but free list */
3182  for (dclp = __monit_dcehdr; dclp != NULL; dclp = dclp->dclnxt)
3183   {
3184    /* turn off the dce but do not free */
3185    /* AIV 11/26/02 dc events now built during elaboration and not freed */
3186    dclp->ldcep->dce_off = TRUE;
3187   }
3188  if (__monit_dcehdr != NULL) __monit_dcehdr = NULL;
3189  __monit_stp = NULL;
3190  __monit_itp = NULL;
3191 
3192  /* re-initialize vars and state and the dce list for each wire */
3193  /* dce list both scheduled events tables reset and triggered dmpv bits */
3194  reinit_vars_and_state();
3195  /* DBG remove ---
3196  for (mdp = __modhdr; mdp != NULL; mdp = mdp->mnxt)
3197   {
3198    __push_wrkitstk(mdp, 0);
3199    __dmpmod_nplst(mdp, TRUE);
3200    __pop_wrkitstk();
3201   }
3202  --- */
3203 
3204  /* free dumpvars setup master records - will be setup again */
3205  for (mdvp = __dv_hdr; mdvp != NULL;)
3206   {
3207    mdvp2 = mdvp->mdvnxt;
3208    __my_free((char *) mdvp, sizeof(struct mdvmast_t));
3209    mdvp = mdvp2;
3210   }
3211  __dv_hdr = __dv_end = NULL;
3212  /* close any open dumpvars file */
3213  if (strcmp(__dv_fnam, DFLTDVFNAM) != 0)
3214   {
3215    __my_free(__dv_fnam, strlen(__dv_fnam) + 1);
3216    __dv_fnam = __pv_stralloc(DFLTDVFNAM);
3217   }
3218  /* close any dv file, if running gets to dv will then overwrite */
3219  if (__dv_fd != -1L) { __my_close(__dv_fd); __dv_fd = -1; }
3220 
3221  /* add any pending until slot end tim chk changes to free list */
3222  if (__tcpendlst_end != NULL)
3223   {
3224    __tcpendlst_end->tc_plnxt = __tcpendfreelst;
3225    __tcpendfreelst = __tcpendlst_hdr;
3226    __tcpendlst_hdr = __tcpendlst_end = NULL;
3227   }
3228 
3229  /* free any pending but unprocessed net change records */
3230  if (__nchg_futend != NULL)
3231   {
3232    __nchg_futend->nchglnxt = __nchgfreelst;
3233    __nchgfreelst = __nchg_futhdr;
3234   }
3235 
3236  /* add any pending dumpvars changes to end of free list for next time */
3237  if (__dv_chgnethdr != NULL)
3238   {
3239    dvchg_last = NULL;
3240    for (dvchgp = __dv_chgnethdr; dvchgp != NULL; dvchgp = dvchgp->dvchgnxt)
3241     dvchg_last = dvchgp;
3242 
3243    /* SJM 08/02/01 - add if to keep lint happy */
3244    if (dvchg_last != NULL) dvchg_last->dvchgnxt = __dv_netfreelst;
3245    __dv_netfreelst = __dv_chgnethdr;
3246    __dv_chgnethdr = NULL;
3247   }
3248  /* must close any open multi-channel descriptors and turn bit off */
3249  /* initialize the multichannel descriptor table */
3250  /* SJM 03/26/00 - bit 3 (value 4) no longer log file - lumped with stdout */
3251  /* leave stdout (1) and stderr (2) */
3252  for (i = 2; i < 31; i++)
3253   {
3254    if (__mulchan_tab[i].mc_s == NULL) continue;
3255 
3256    __my_fclose(__mulchan_tab[i].mc_s);
3257    chp = __mulchan_tab[i].mc_fnam;
3258    __my_free(chp, strlen(chp) + 1);
3259    __mulchan_tab[i].mc_s = NULL;
3260    __mulchan_tab[i].mc_fnam = NULL;
3261   }
3262  /* free all tfrec for tf_ tasks and functions to initial state */
3263  __reinit_tfrecs();
3264  /* putv records reinitialized during wire reset */
3265  __reinit_vpi();
3266 
3267  /* can leave any pending repeat counts since will be reset when entered */
3268  /* rerun initialize to propagate all initial events */
3269  __reinit_sim();
3270  /* must leave any breakpoints and debugger states */
3271  /* will start up as previous so if -s set, will again enter interactive */
3272 }
3273 
3274 /*
3275  * re-initialize variables and state information
3276  * traverse static circuit freeing all values and pending scheduled values
3277  */
reinit_vars_and_state(void)3278 static void reinit_vars_and_state(void)
3279 {
3280  register int32 gi, i, bi;
3281  register struct conta_t *cap, *pbcap;
3282  register struct mod_pin_t *mpp;
3283  register struct mod_t *mdp;
3284  int32 cai, insts;
3285  struct gate_t *gp;
3286  i_tev_ndx *itevpp;
3287 
3288  for (mdp = __modhdr; mdp != NULL; mdp = mdp->mnxt)
3289   {
3290    __push_wrkitstk(mdp, 0);
3291    /* turn off dumpvars in mod here and in caller */
3292    mdp->mod_hasdvars = FALSE;
3293    __reinitialize_vars(mdp);
3294    __pop_wrkitstk();
3295   }
3296  for (mdp = __modhdr; mdp != NULL; mdp = mdp->mnxt)
3297   {
3298    __push_wrkitstk(mdp, 0);
3299 
3300    /* turn off dumpvars in mod here and in caller */
3301    mdp->mod_hasdvars = FALSE;
3302 
3303    insts = mdp->flatinum;
3304    /* since can't init dces until cgen .bss .so linking done - same as init */
3305    __initialize_dces(mdp);
3306    for (gi = 0; gi < mdp->mgnum; gi++)
3307     {
3308      gp = &(mdp->mgates[gi]);
3309      /* no scheduled event table if no delay */
3310      if ((itevpp = gp->schd_tevs) != NULL)
3311       { for (i = 0; i < insts; i++) itevpp[i] = -1; }
3312 
3313      if (gp->g_class == GC_UDP) __set_init_udpstate(gp, insts, FALSE);
3314      else
3315       {
3316        if (gp->g_class == GC_PULL || gp->g_class == GC_TRAN) goto nxt_mod;
3317        /* if output unc. (OPEMPTY), changes are not seen (do not propagate) */
3318        if (gp->g_class != GC_TRANIF && gp->gpins[0]->optyp == OPEMPTY)
3319         goto nxt_mod;
3320 
3321        __set_init_gstate(gp, insts, FALSE);
3322       }
3323     }
3324    for (cai = 0, cap = &(mdp->mcas[0]); cai < mdp->mcanum; cai++, cap++)
3325     {
3326      if (!cap->ca_pb_sim)
3327       {
3328        if (cap->lhsx->x_multfi || cap->ca_delrep != DT_NONE)
3329         __allocinit_perival(&(cap->ca_drv_wp), insts, cap->lhsx->szu.xclen,
3330          FALSE);
3331        if (cap->ca_delrep != DT_NONE)
3332         {
3333          __allocinit_perival(&(cap->schd_drv_wp), insts, cap->lhsx->szu.xclen,
3334           FALSE);
3335          if ((itevpp = cap->caschd_tevs) != NULL)
3336          { for (i = 0; i < insts; i++) itevpp[i] = -1; }
3337         }
3338       }
3339      else
3340       {
3341        for (bi = 0; bi < cap->lhsx->szu.xclen; bi++)
3342         {
3343          pbcap = &(cap->pbcau.pbcaps[bi]);
3344          /* DBG remove */
3345          if (pbcap->lhsx->szu.xclen != 1) __misc_terr(__FILE__, __LINE__);
3346          /* -- */
3347          /* SJM 09/28/02 - notice if any PB fi>1 or del, need drv for each */
3348          if (cap->lhsx->x_multfi || cap->ca_delrep != DT_NONE)
3349           __allocinit_perival(&(pbcap->ca_drv_wp), insts, 1, FALSE);
3350          if (cap->ca_delrep != DT_NONE)
3351           {
3352            __allocinit_perival(&(pbcap->schd_drv_wp), insts, 1, FALSE);
3353            if ((itevpp = pbcap->caschd_tevs) != NULL)
3354             { for (i = 0; i < insts; i++) itevpp[i] = -1; }
3355           }
3356         }
3357       }
3358     }
3359    if (mdp->mod_has_mipds)
3360     {
3361      for (i = 0; i < mdp->mpnum; i++)
3362       {
3363        mpp = &(mdp->mpins[i]);
3364        if (!mpp->has_mipd) continue;
3365 
3366        __reinit_mipd(mpp, mdp);
3367       }
3368     }
3369 nxt_mod:
3370    __pop_wrkitstk();
3371   }
3372  __set_nchgaction_bits();
3373 }
3374 
3375 /*
3376  * NON DEBUGGER ONLY ROUTINES
3377  */
3378 
3379 /*
3380  * ROUTINES TO IMPLEMENT PENDING EVENT TRACE
3381  */
3382 
3383 /*
3384  * write event location trace - assume basic event message already printed
3385  * for active thread could actually give trace back of enables
3386  * may be no scope here
3387  */
__write_snapshot(int32 pend_num)3388 extern void __write_snapshot(int32 pend_num)
3389 {
3390  int32 i;
3391  i_tev_ndx tevpi;
3392  struct thread_t *thp;
3393 
3394  __cvsim_msg("*** Activity snapshot at %s ***\n", __to_timstr(__xs,
3395   &__simtime));
3396  if (__cur_tevpi == -1)
3397   {
3398    if (__inst_ptr == NULL) strcpy(__xs, "<none>");
3399    else __msg2_blditree(__xs, __inst_ptr);
3400 
3401    if (__sfnam_ind <= 0)
3402     __cvsim_msg("Current event: <none> last scope %s - no last statement\n",
3403       __xs);
3404    else __cvsim_msg(
3405     "Current event: <none> last scope %s - last statement %s\n", __xs,
3406     __bld_lineloc(__xs2, (word32) __sfnam_ind, __slin_cnt));
3407    if (__suspended_thd != NULL)
3408     {
3409      __cvsim_msg("Trace back of just suspended statements:\n");
3410      __prt_where_msg(__suspended_thd);
3411     }
3412   }
3413  else
3414   {
3415    /* current event is one being processed now */
3416    if (__tevtab[__cur_tevpi].tetyp == TE_THRD)
3417     {
3418      thp = __tevtab[__cur_tevpi].tu.tethrd;
3419      __cvsim_msg("Trace back of enabled statements:\n");
3420      __prt_where_msg(thp);
3421     }
3422    else
3423     {
3424      /* this write the end new line */
3425      wr_1ev_trace(-1, __cur_tevpi);
3426     }
3427   }
3428  /* FIXME - think this is wrong for CG thrd but rarely used feature */
3429  fill_near_evtab(pend_num, TE_THRD);
3430  if (__last_wevti >= 0)
3431   __cvsim_msg("\nNext %d pending procedural events:\n", __last_wevti + 1);
3432 
3433  for (i = 0; i <= __last_wevti; i++)
3434   {
3435    tevpi = __wrkevtab[i];
3436    wr_1ev_trace(i, tevpi);
3437   }
3438  fill_near_evtab(pend_num, TE_G);
3439  if (__last_wevti >= 0)
3440   __cvsim_msg("\nNext %d pending declarative events:\n", __last_wevti + 1);
3441  for (i = 0; i <= __last_wevti; i++)
3442   {
3443    tevpi = __wrkevtab[i];
3444    wr_1ev_trace(i, tevpi);
3445   }
3446  __dmp_all_thrds();
3447  __cvsim_msg("*** End of snapshot ***\n");
3448 }
3449 
3450 /*
3451  * print where message
3452  * LOOKATME - maybe this should not use global __fcspi
3453  */
__prt_where_msg(register struct thread_t * thp)3454 extern void __prt_where_msg(register struct thread_t *thp)
3455 {
3456  register int32 i;
3457  struct st_t *stp;
3458  struct task_t *tskp;
3459  struct thread_t *down_thp;
3460  char s1[RECLEN], s2[RECLEN], s3[RECLEN];
3461 
3462  if (__fcspi >= 0) tskp = __fcstk[__fcspi];
3463  else if (thp->th_fj) tskp = __find_thrdtsk(thp);
3464  else tskp = thp->assoc_tsk;
3465 
3466  if ((stp = thp->thnxtstp) == NULL) strcpy(s1, "**END**");
3467  else __bld_lineloc(s1, (word32) stp->stfnam_ind, stp->stlin_cnt);
3468  __cvsim_msg("In scope %s next statement at %s\n",
3469   __msg_blditree(s2, thp->th_itp, tskp), s1);
3470 
3471  if (__fcspi >= 0)
3472   {
3473    for (i = __fcspi - 1; i >= 0; i--)
3474     {
3475      tskp = __fcstk[i];
3476      __cvsim_msg(" -- function %s\n", __msg_blditree(s1,
3477      thp->th_itp, tskp));
3478     }
3479    i = 0;
3480   }
3481  else i = 1;
3482  down_thp = thp;
3483  for (thp = down_thp->thpar; thp != NULL; thp = thp->thpar, i++)
3484   {
3485    if (down_thp->th_fj) tskp = __find_thrdtsk(down_thp);
3486    else tskp = down_thp->assoc_tsk;
3487    if (tskp == NULL) strcpy(s1, "");
3488    else sprintf(s1, " %s", __to_tsktyp(s2, tskp->tsktyp));
3489    if (down_thp->th_itp == NULL) __misc_terr(__FILE__, __LINE__);
3490    __msg_blditree(s3, down_thp->th_itp, tskp);
3491 
3492    __cvsim_msg("%2d)%s enabled from %s in %s\n", i, s1,
3493     __bld_lineloc(s2, down_thp->thenbl_sfnam_ind, down_thp->thenbl_slin_cnt),
3494     s3);
3495    down_thp = thp;
3496   }
3497  __cvsim_msg("%2d) started from initial/always at %s in %s\n", i,
3498   __bld_lineloc(s1, down_thp->thenbl_sfnam_ind, down_thp->thenbl_slin_cnt),
3499   __msg_blditree(s2, down_thp->th_itp, (struct task_t *) NULL));
3500 }
3501 
3502 /*
3503  * ROUTINES TO WRITE THREAD TRACE BACK
3504  */
3505 
3506 /*
3507  * write trace of 1 thread event
3508  * for procedural scheduled but not active
3509  */
wr_1ev_trace(int32 i,i_tev_ndx tevpi)3510 static void wr_1ev_trace(int32 i, i_tev_ndx tevpi)
3511 {
3512  int32 lhslen, bi, wlen;
3513  byte *sbp;
3514  word32 *wp, av, bv;
3515  struct tev_t *tevp;
3516  struct conta_t *cap;
3517  struct gate_t *gp;
3518  struct net_t *np;
3519  struct thread_t *thp;
3520  struct tfrec_t *tfrp;
3521  struct st_t *stp;
3522  struct itree_t *sav_tritp;
3523  struct xstk_t *xsp, *xsp2;
3524  struct task_t *tskp;
3525  struct tedputp_t *tedp;
3526  struct expr_t *xp;
3527  struct tfarg_t *tfap;
3528  char s1[RECLEN], s2[RECLEN];
3529 
3530  tevp = &(__tevtab[tevpi]);
3531  sav_tritp = __last_tritp;
3532  __last_tritp = NULL;
3533  if (i == -1) __cvsim_msg("Current event: ");
3534  else __cvsim_msg("  %2d) time %s ", i + 1, __to_timstr(__xs, &(tevp->etime)));
3535  if (tevp->te_cancel) __cvsim_msg("[canceled] ");
3536  __push_itstk(tevp->teitp);
3537  switch ((byte) tevp->tetyp) {
3538   case TE_THRD:
3539    /* SJM 03/15/01 - now using normal stmt thread mechanism */
3540    /* ithrd interpreter use stmt ithrd cod ptr */
3541    thp = tevp->tu.tethrd;
3542    stp = thp->thnxtstp;
3543    /* here may have hit breakpoint in func. so ok */
3544    if (thp->th_fj) tskp = __find_thrdtsk(thp); else tskp = thp->assoc_tsk;
3545    __cvsim_msg("procedural event in %s resume", __msg_blditree(__xs,
3546     __inst_ptr, tskp));
3547    if (stp == NULL) __cvsim_msg(" **at end**\n");
3548    else __cvsim_msg(" %s\n", __bld_lineloc(__xs, stp->stfnam_ind,
3549     stp->stlin_cnt));
3550    __cvsim_msg("      enabled from %s\n", __bld_lineloc(__xs,
3551     thp->thenbl_sfnam_ind, thp->thenbl_slin_cnt));
3552    break;
3553   case TE_G:
3554    gp = tevp->tu.tegp;
3555    __cvsim_msg("gate line %s:\n", __bld_lineloc(__xs,
3556     gp->gsym->syfnam_ind, gp->gsym->sylin_cnt));
3557    __cvsim_msg("        %s\n", __gstate_tostr(__xs2, gp, TRUE));
3558    break;
3559   case TE_CA:
3560    /* SJM 09/28/02 - notice for decomposed into per bit, this is PB el */
3561    cap = tevp->tu.tecap;
3562    __cvsim_msg("%s:\n", __to_evtrcanam(__xs, cap, tevp->teitp));
3563    lhslen = cap->lhsx->szu.xclen;
3564    push_xstk_(xsp, lhslen);
3565    /* notice will never be called unless drv_wp exists - else no event */
3566    __ld_perinst_val(xsp->ap, xsp->bp, cap->ca_drv_wp, lhslen);
3567    /* build a conta driving string - may need to add strength */
3568    if (cap->ca_hasst)
3569     {
3570      push_xstk_(xsp2, 4*lhslen);
3571      sbp = (byte *) xsp2->ap;
3572      __st_standval(sbp, xsp, cap->ca_stval);
3573      __st_regab_tostr(s1, sbp, lhslen);
3574      __pop_xstk();
3575     }
3576    else __regab_tostr(s1, xsp->ap, xsp->bp, lhslen, BBIN, FALSE);
3577    __pop_xstk();
3578    xsp = __eval_xpr(cap->rhsx);
3579    /* notice for conta if 0 delay fi==1, never get here */
3580    __cvsim_msg("      %s = %s %s\n", s1,
3581     __regab_tostr(__xs, xsp->ap, xsp->bp, cap->rhsx->szu.xclen, BBIN,
3582      FALSE), __bld_valofsched(__xs2, tevp));
3583    __pop_xstk();
3584    break;
3585   case TE_WIRE: case TE_BIDPATH:
3586    np = tevp->tu.tenp->tenu.np;
3587    bi = tevp->tu.tenp->nbi;
3588    if (tevp->tetyp == TE_WIRE) strcpy(s2, "wire event");
3589    else strcpy(s2, "inout path dest. event");
3590    __cvsim_msg("%s %s declared line %s\n",
3591     __to_evtrwnam(__xs, np, bi, bi, __inst_ptr), s2,
3592     __bld_lineloc(__xs2, np->nsym->syfnam_ind, np->nsym->sylin_cnt));
3593    if (np->n_stren)
3594     { get_stwire_addr_(sbp, np); __to_vvstnam(s1, (word32) sbp[bi]); }
3595    else
3596     { __ld_bit(&av, &bv, np, bi); __to_vvnam(s1, (word32) (av | (bv << 1))); }
3597    __cvsim_msg("       value %s %s\n", s1, __bld_valofsched(__xs2, tevp));
3598    break;
3599   case TE_MIPD_NCHG:
3600    /* FIXME - maybe add info so can print port bit too */
3601    np = tevp->tu.tenp->tenu.np;
3602    bi = tevp->tu.tenp->nbi;
3603    __cvsim_msg("MIPD on %s net %s\n", __to_ptnam(__xs2, np->iotyp),
3604     __to_evtrwnam(__xs, np, bi, bi, __inst_ptr));
3605    break;
3606   case TE_NBPA:
3607    stp = tevp->tu.tenbpa->nbastp;
3608    __cvsim_msg("non blocking assign event in %s line %s",
3609     __msg2_blditree(__xs, __inst_ptr), __bld_lineloc(__xs2, stp->stfnam_ind,
3610     stp->stlin_cnt));
3611    if (stp->st.sdc->repcntx != NULL)
3612     {
3613      sprintf(__xs, "waiting for repeat count events (now %s)\n",
3614       __to_timstr(__xs2, &(tevp->etime)));
3615     }
3616    else sprintf(__xs, "assign at %s\n", __to_timstr(__xs2, &(tevp->etime)));
3617    wp = tevp->tu.tenbpa->nbawp;
3618    /* SJM 08/08/99 - use copied lhs expr. with ndxes converted to con if set */
3619    if ((xp = tevp->tu.tenbpa->nblhsxp) == NULL) xp = stp->st.spra.lhsx;
3620 
3621    lhslen = xp->szu.xclen;
3622    wlen = wlen_(lhslen);
3623    __cvsim_msg("       new value %s %s\n",
3624     __xregab_tostr(s1, wp, &(wp[wlen]), lhslen, xp), __xs);
3625    break;
3626   case TE_TFSETDEL:
3627    tfrp = tevp->tu.tetfrec;
3628    __cvsim_msg("tf_ set delay misctf call of %s in %s at %s\n",
3629     __get_tfcellnam(tfrp), __msg_blditree(__xs, __inst_ptr, tfrp->tf_intskp),
3630     __bld_lineloc(__xs2, tfrp->tffnam_ind, tfrp->tflin_cnt));
3631    break;
3632   case TE_SYNC:
3633    tfrp = tevp->tu.tetfrec;
3634    __cvsim_msg("tf_ #0 synchronize misctf call of %s in %s at %s\n",
3635     __get_tfcellnam(tfrp), __msg_blditree(__xs, __inst_ptr, tfrp->tf_intskp),
3636     __bld_lineloc(__xs2, tfrp->tffnam_ind, tfrp->tflin_cnt));
3637    break;
3638   case TE_TFPUTPDEL:
3639    tedp = tevp->tu.tedputp;
3640    tfrp = tedp->tedtfrp;
3641    __cvsim_msg("tf_ strdel putp assign to arg %d of %s in %s at %s\n",
3642     tedp->tedpnum, __get_tfcellnam(tfrp), __msg_blditree(__xs, __inst_ptr,
3643     tfrp->tf_intskp), __bld_lineloc(__xs2, tfrp->tffnam_ind, tfrp->tflin_cnt));
3644 
3645    tfap = &(tfrp->tfargs[tedp->tedpnum]);
3646    if (tfap->anp->ntyp >= NONWIRE_ST) strcpy(__xs, "procedural assign of");
3647    else strcpy(__xs, "tf_ driver is");
3648    xp = tfap->arg.axp;
3649    wp = tedp->tedwp;
3650    lhslen = xp->szu.xclen;
3651    wlen = wlen_(lhslen);
3652    __cvsim_msg("       %s %s\n", __xs, __xregab_tostr(s1, wp,
3653     &(wp[wlen]), lhslen, xp));
3654    break;
3655   default: __case_terr(__FILE__, __LINE__);
3656  }
3657  __last_tritp = sav_tritp;
3658  __pop_itstk();
3659 }
3660 
3661 /*
3662  * routine to fill table (known big enough) with future events
3663  * starts with next event must match event type to passed number
3664  *
3665  * puts in global table __wrkevtab index __last_wevti size __size_wrkevtab
3666  * this must skip current event
3667  */
fill_near_evtab(int32 ntevs,int32 tefilt)3668 static void fill_near_evtab(int32 ntevs, int32 tefilt)
3669 {
3670  register i_tev_ndx tevpi;
3671  int32 evnum, osize, twi, added_pnd0s;
3672  word64 t1, t2;
3673  struct telhdr_t *ovfl_telp, *twp;
3674 
3675  /* make sure work event table allocated and large enough */
3676  if (__wrkevtab == NULL)
3677   {
3678    __wrkevtab = (i_tev_ndx *) __my_malloc(ntevs*sizeof(i_tev_ndx));
3679    __size_wrkevtab = ntevs;
3680   }
3681  else
3682   {
3683    if (ntevs > __size_wrkevtab)
3684     {
3685      osize = __size_wrkevtab*sizeof(i_tev_ndx);
3686      __wrkevtab = (i_tev_ndx *) __my_realloc((char *) __wrkevtab, osize,
3687       ntevs*sizeof(i_tev_ndx));
3688      __size_wrkevtab = ntevs;
3689     }
3690   }
3691  __last_wevti = -1;
3692  evnum = 0;
3693 
3694  /* first rest of current list */
3695  /* if not in pound 0's, first rest of current slot list */
3696  added_pnd0s = FALSE;
3697  if (!__processing_pnd0s)
3698   {
3699    /* if cur tevp index set, 1st pending event must be next */
3700    if (__cur_tevpi != -1) tevpi = __tevtab[__cur_tevpi].tenxti;
3701    else tevpi = __cur_te_hdri;
3702    for (; tevpi != -1; tevpi = __tevtab[tevpi].tenxti)
3703     {
3704      if (!try_add_wrkevtab(tevpi, ntevs, &evnum, tefilt)) return;
3705     }
3706    /* add pnd0's or nb pnd0's if no pnd0s */
3707    if (__p0_te_hdri != -1) { tevpi = __p0_te_hdri; added_pnd0s = TRUE; }
3708    else tevpi = __nb_te_hdri;
3709   }
3710  else
3711   {
3712    /* SJM - also add nb's if no pound 0's */
3713    if (__cur_tevpi != -1) tevpi = __tevtab[__cur_tevpi].tenxti;
3714    else if (__p0_te_hdri != -1) { added_pnd0s = TRUE; tevpi = __p0_te_hdri; }
3715    else tevpi = __nb_te_hdri;
3716   }
3717  /* next try pound 0's */
3718  for (; tevpi != -1; tevpi = __tevtab[tevpi].tenxti)
3719   {
3720    if (!try_add_wrkevtab(tevpi, ntevs, &evnum, tefilt)) return;
3721 
3722    /* if processing pnd0s and added pnd0's, must also add any nb pnd0s */
3723    /* before moving forward in time */
3724    if (tevpi == -1 && added_pnd0s)
3725     {
3726      added_pnd0s = FALSE;
3727      tevpi = __nb_te_hdri;
3728     }
3729   }
3730 
3731  /* t1 is one time unit afer now */
3732  t1 = __simtime + 1;
3733  /* first overflow q location must be set before processing wheel */
3734  if (__btqroot != NULL) ovfl_telp = tfind_btnode_after(__btqroot, t1);
3735  else ovfl_telp = NULL;
3736  if (__num_twhevents > 0)
3737   {
3738    /* go through timing wheel to end (know all events here in wheel) */
3739    /* and not in overflow q */
3740    for (twi = __cur_twi + 1; twi < __twhsize; twi++)
3741     {
3742      twp = __twheel[twi];
3743      if (twp->te_hdri != -1)
3744       {
3745        for (tevpi = twp->te_hdri; tevpi != -1; tevpi = __tevtab[tevpi].tenxti)
3746         { if (!try_add_wrkevtab(tevpi, ntevs, &evnum, tefilt)) return; }
3747       }
3748     }
3749    for (twi = 0; twi < __cur_twi; twi++)
3750     {
3751      twp = __twheel[twi];
3752      /* know twi at least as early as any overflow queue event */
3753      /* do next timing wheel events, if any */
3754      if (twp->te_hdri != -1)
3755       {
3756        for (tevpi = twp->te_hdri; tevpi != -1; tevpi = __tevtab[tevpi].tenxti)
3757         { if (!try_add_wrkevtab(tevpi, ntevs, &evnum, tefilt)) return; }
3758       }
3759      if (ovfl_telp != NULL)
3760       {
3761        /* t2 is index + 1 of time of wrap around current slot */
3762        t2 = (word64) (twi + 1);
3763        /* t1 is time of wheel position */
3764        t1 = __whetime + t2;
3765        if (twp->te_hdri != -1 && t1 != __tevtab[twp->te_hdri].etime)
3766         __misc_terr(__FILE__, __LINE__);
3767 
3768        tevpi = ovfl_telp->te_hdri;
3769        if (t1 == __tevtab[tevpi].etime)
3770         {
3771          for (; tevpi != -1; tevpi = __tevtab[tevpi].tenxti)
3772           if (!try_add_wrkevtab(tevpi, ntevs, &evnum, tefilt)) return;
3773          /* move to next overflow tree place */
3774          t1++;
3775          ovfl_telp = tfind_btnode_after(__btqroot, t1);
3776         }
3777       }
3778     }
3779   }
3780  if (ovfl_telp == NULL) return;
3781  for (;;)
3782   {
3783    tevpi = ovfl_telp->te_hdri;
3784    t1 = __tevtab[tevpi].etime;
3785    for (; tevpi != -1; tevpi = __tevtab[tevpi].tenxti)
3786     if (!try_add_wrkevtab(tevpi, ntevs, &evnum, tefilt)) return;
3787    t1++;
3788    if ((ovfl_telp = tfind_btnode_after(__btqroot, t1)) == NULL) return;
3789   }
3790 }
3791 
3792 /*
3793  * find btree node after or same as tim
3794  */
tfind_btnode_after(struct bt_t * btphdr,word64 tim)3795 static struct telhdr_t *tfind_btnode_after(struct bt_t *btphdr, word64 tim)
3796 {
3797  register struct bt_t *btp;
3798  struct telhdr_t *telp;
3799 
3800  if (btphdr->bttyp == BTFRNGE)
3801   {
3802    for (btp = btphdr; btp != NULL; btp = btp->btnxt)
3803     { if (btp->btltim >= tim) return(btp->ofsu.telp); }
3804    return(NULL);
3805   }
3806  for (btp = btphdr; btp != NULL; btp = btp->btnxt)
3807   {
3808    if ((telp = tfind_btnode_after(btp->ofsu.btofs, tim)) != NULL)
3809     return(telp);
3810   }
3811  return(NULL);
3812 }
3813 
3814 /*
3815  * add to work ev tab if not elminated by filter
3816  * filter is threads only or all but thread
3817  * this return FALSE when table full
3818  */
try_add_wrkevtab(i_tev_ndx tevpi,int32 ntevs,int32 * evnum,int32 tefilt)3819 static int32 try_add_wrkevtab(i_tev_ndx tevpi, int32 ntevs, int32 *evnum,
3820  int32 tefilt)
3821 {
3822  struct tev_t *tevp;
3823 
3824  tevp = &(__tevtab[tevpi]);
3825  if (tefilt != -1)
3826   {
3827    /* FIXME for new cg threads this looks wrong but maybe return T right */
3828    if (tefilt == TE_THRD)
3829     { if (tevp->tetyp != TE_THRD) return(TRUE); }
3830    else if (tevp->tetyp == TE_THRD) return(TRUE);
3831   }
3832  if (++(*evnum) > ntevs) return(FALSE);
3833  __wrkevtab[++__last_wevti] = tevpi;
3834  return(TRUE);
3835 }
3836 
3837 /*
3838  * TASK THREAD DUMP ROUTINES
3839  */
3840 
__dmp_all_thrds()3841 extern void __dmp_all_thrds()
3842 {
3843  __dmp_initalw_thrd_tree();
3844  __dmp_tskthrds();
3845 }
3846 
__dmp_tskthrds(void)3847 extern void __dmp_tskthrds(void)
3848 {
3849  register struct mod_t *mdp;
3850  register struct task_t *tskp;
3851  int32 first_time = TRUE;
3852 
3853  for (mdp = __modhdr; mdp != NULL; mdp = mdp->mnxt)
3854   {
3855    if (mdp->mtasks == NULL) continue;
3856    if (first_time) { __cv_msg("\n"); first_time = FALSE; }
3857 
3858    __cvsim_msg("Task threads in module %s:\n", mdp->msym->synam);
3859    for (tskp = mdp->mtasks; tskp != NULL; tskp = tskp->tsknxt)
3860     {
3861 
3862      __dmp_tskthd(tskp, mdp);
3863     }
3864   }
3865 }
3866 
3867 /*
3868  * dump 1 task thread
3869  */
__dmp_tskthd(struct task_t * tskp,struct mod_t * mdp)3870 extern void __dmp_tskthd(struct task_t *tskp, struct mod_t *mdp)
3871 {
3872  register int32 i;
3873  register struct tskthrd_t *ttp;
3874 
3875  if (tskp->tsktyp == FUNCTION)
3876   {
3877    if (tskp->tthrds != NULL) __misc_terr(__FILE__, __LINE__);
3878    return;
3879   }
3880  for (i = 0; i < mdp->flatinum; i++)
3881   {
3882    if ((ttp = tskp->tthrds[i]) == NULL)
3883     {
3884      if (__debug_flg)
3885       __dbg_msg("*** task %s instance %d has no task threads\n",
3886        tskp->tsksyp->synam, i);
3887      continue;
3888     }
3889    __cvsim_msg("*** dumping threads for task %s (%s)\n",
3890     tskp->tsksyp->synam, __msg_blditree(__xs, mdp->moditps[i],
3891     (struct task_t *) NULL));
3892    for (; ttp != NULL; ttp = ttp->tthd_r) __dmp_thrd_info(ttp->tthrd);
3893   }
3894 }
3895 
3896 /*
3897  * dump top level init/always thread tree
3898  */
__dmp_initalw_thrd_tree(void)3899 extern void __dmp_initalw_thrd_tree(void)
3900 {
3901  register struct thread_t *thp;
3902 
3903  __cvsim_msg("Initial/always threads:\n");
3904  for (thp = __initalw_thrd_hdr; thp != NULL; thp = thp->thright)
3905   {
3906    if (thp->thdtevi == -1 && thp->th_dctp == NULL && thp->thofscnt == 0)
3907     {
3908      __cvsim_msg("   initial/always thread enabled at %s completed\n",
3909       __bld_lineloc(__xs, thp->thenbl_sfnam_ind, thp->thenbl_slin_cnt));
3910      continue;
3911     }
3912    __dmp_thrd_info(thp);
3913    if (thp->thofs != NULL) __dmp_thrd_tree(thp->thofs);
3914   }
3915  __cvsim_msg("  *** end of initial/always threads ***\n");
3916 }
3917 
__dmp_thrd_tree(register struct thread_t * thp)3918 extern void __dmp_thrd_tree(register struct thread_t *thp)
3919 {
3920  for (; thp != NULL; thp = thp->thright)
3921   {
3922    __dmp_thrd_info(thp);
3923    if (thp->thofs != NULL) __dmp_thrd_tree(thp->thofs);
3924   }
3925 }
3926 
__dmp_thrd_info(struct thread_t * thp)3927 extern void __dmp_thrd_info(struct thread_t *thp)
3928 {
3929  i_tev_ndx tevpi;
3930  struct delctrl_t *dctp;
3931  struct tev_t *tevp;
3932  char s1[RECLEN], s2[RECLEN], s3[RECLEN];
3933 
3934  if (thp->thnxtstp == NULL) strcpy(s2, "**at end");
3935  else __bld_lineloc(s2, thp->thnxtstp->stfnam_ind, thp->thnxtstp->stlin_cnt);
3936 
3937  __cvsim_msg("   enabled %s statement %s in %s\n",
3938   __bld_lineloc(s1, thp->thenbl_sfnam_ind, thp->thenbl_slin_cnt), s2,
3939   __msg_blditree(s3, thp->th_itp, thp->assoc_tsk));
3940 
3941  if ((tevpi = thp->thdtevi) != -1)
3942   {
3943    tevp = &(__tevtab[tevpi]);
3944    __cvsim_msg("   [%s event for time %s cancel=%d]\n",
3945     __to_tetyp(s1, tevp->tetyp), __to_timstr(s2, &(tevp->etime)),
3946     tevp->te_cancel);
3947   }
3948  if ((dctp = thp->th_dctp) != NULL)
3949   {
3950    if (dctp->actionst != NULL)
3951     sprintf(s1, "%s action at %s", __to_dcenam(s2, dctp->dctyp),
3952     __bld_lineloc(s3, dctp->actionst->stfnam_ind, dctp->actionst->stlin_cnt));
3953    else sprintf(s1, "%s no action", __to_dcenam(s2, dctp->dctyp));
3954   }
3955  else strcpy(s1, "not waiting for event ctrl");
3956  __cvsim_msg("   [has task outs=%d, disable=%d, fork=%d, %s]\n",
3957    thp->tsk_stouts, thp->th_dsable, thp->th_fj, s1);
3958 }
3959