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, <mp)) 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