diff --git a/doc/simh_breakpoints.doc b/doc/simh_breakpoints.doc index f40b6b61..80b75cde 100644 Binary files a/doc/simh_breakpoints.doc and b/doc/simh_breakpoints.doc differ diff --git a/scp.c b/scp.c index f5762b4d..f8a0fb61 100644 --- a/scp.c +++ b/scp.c @@ -393,7 +393,9 @@ t_stat sim_brk_clrall (int32 sw); t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw); t_stat sim_brk_showall (FILE *st, int32 sw); CONST char *sim_brk_getact (char *buf, int32 size); -BRKTAB *sim_brk_new (t_addr loc); +BRKTAB *sim_brk_new (t_addr loc, uint32 btyp); +char *sim_brk_clract (void); + FILE *stdnul; /* Command support routines */ @@ -475,12 +477,10 @@ uint32 sim_brk_types = 0; uint32 sim_brk_dflt = 0; char *sim_brk_act[MAX_DO_NEST_LVL]; char *sim_brk_act_buf[MAX_DO_NEST_LVL]; -BRKTAB *sim_brk_tab = NULL; +BRKTAB **sim_brk_tab = NULL; int32 sim_brk_ent = 0; int32 sim_brk_lnt = 0; int32 sim_brk_ins = 0; -t_bool sim_brk_pend[SIM_BKPT_N_SPC] = { FALSE }; -t_addr sim_brk_ploc[SIM_BKPT_N_SPC] = { 0 }; int32 sim_quiet = 0; int32 sim_step = 0; static double sim_time; @@ -4604,7 +4604,8 @@ t_stat r; if (cptr && (*cptr != 0)) r = ssh_break (st, cptr, 1); /* more? */ -else r = sim_brk_showall (st, sim_switches); +else + r = sim_brk_showall (st, sim_switches); return r; } @@ -5045,7 +5046,7 @@ t_addr lo, hi, max = uptr->capac - 1; int32 cnt; if (sim_brk_types == 0) - return SCPE_NOFNC; + return sim_messagef (SCPE_NOFNC, "No breakpoint support in this simulator\n"); if ((dptr == NULL) || (uptr == NULL)) return SCPE_IERR; abuf[sizeof(abuf)-1] = '\0'; @@ -5077,9 +5078,11 @@ while (*cptr) { if ((lo == 0) && (hi == max)) { if (flg == SSH_CL) sim_brk_clrall (sim_switches); - else if (flg == SSH_SH) - sim_brk_showall (st, sim_switches); - else return SCPE_ARG; + else + if (flg == SSH_SH) + sim_brk_showall (st, sim_switches); + else + return SCPE_ARG; } else { for ( ; lo <= hi; lo = lo + 1) { @@ -5094,6 +5097,8 @@ return SCPE_OK; t_stat ssh_break_one (FILE *st, int32 flg, t_addr lo, int32 cnt, CONST char *aptr) { +if (!sim_brk_types) + return sim_messagef (SCPE_NOFNC, "No breakpoint support in this simulator\n"); switch (flg) { case SSH_ST: @@ -8917,7 +8922,7 @@ return cnt; instruction breakpoint capability. Breakpoints are stored in table sim_brk_tab, which is ordered by address for - efficient binary searching. A breakpoint consists of a four entry structure: + efficient binary searching. A breakpoint consists of a six entry structure: addr address of the breakpoint type types of breakpoints set on the address @@ -8925,10 +8930,12 @@ return cnt; cnt number of iterations before breakp is taken action pointer command string to be executed when break is taken + next list of other breakpoints with the same addr specifier + time_fired array of when this breakpoint was fired for each class sim_brk_summ is a summary of the types of breakpoints that are currently set (it is the bitwise OR of all the type fields). A simulator need only check for - a breakpoint of type X if bit SWMASK('X') is set in sim_brk_sum. + a breakpoint of type X if bit SWMASK('X') is set in sim_brk_summ. The package contains the following public routines: @@ -8948,10 +8955,25 @@ return cnt; t_stat sim_brk_init (void) { +int32 i; + +for (i=0; inext; + + free (bp->act); + free (bp); + bp = bpt; + } + } +memset (sim_brk_tab, 0, sim_brk_lnt*sizeof (BRKTAB*)); sim_brk_lnt = SIM_BRK_INILNT; -sim_brk_tab = (BRKTAB *) calloc (sim_brk_lnt, sizeof (BRKTAB)); +sim_brk_tab = (BRKTAB **) realloc (sim_brk_tab, sim_brk_lnt*sizeof (BRKTAB*)); if (sim_brk_tab == NULL) return SCPE_MEM; +memset (sim_brk_tab, 0, sim_brk_lnt*sizeof (BRKTAB*)); sim_brk_ent = sim_brk_ins = 0; sim_brk_clract (); sim_brk_npc (0); @@ -8973,9 +8995,11 @@ lo = 0; /* initial bounds */ hi = sim_brk_ent - 1; do { p = (lo + hi) >> 1; /* probe */ - bp = sim_brk_tab + p; /* table addr */ - if (loc == bp->addr) /* match? */ + bp = sim_brk_tab[p]; /* table addr */ + if (loc == bp->addr) { /* match? */ + sim_brk_ins = p; return bp; + } else if (loc < bp->addr) /* go down? p is upper */ hi = p - 1; else lo = p + 1; /* go up? p is lower */ @@ -8986,37 +9010,56 @@ else sim_brk_ins = p + 1; /* after last sch */ return NULL; } +BRKTAB *sim_brk_fnd_ex (t_addr loc, uint32 btyp, t_bool any_typ) +{ +BRKTAB *bp = sim_brk_fnd (loc); + +while (bp) { + if (any_typ ? (bp->typ & btyp) : (bp->typ == btyp)) + return bp; + bp = bp->next; + } +return bp; +} + /* Insert a breakpoint */ -BRKTAB *sim_brk_new (t_addr loc) +BRKTAB *sim_brk_new (t_addr loc, uint32 btyp) { int32 i, t; -BRKTAB *bp, *newp; +BRKTAB *bp, **newp; if (sim_brk_ins < 0) return NULL; if (sim_brk_ent >= sim_brk_lnt) { /* out of space? */ t = sim_brk_lnt + SIM_BRK_INILNT; /* new size */ - newp = (BRKTAB *) calloc (t, sizeof (BRKTAB)); /* new table */ + newp = (BRKTAB **) calloc (t, sizeof (BRKTAB*)); /* new table */ if (newp == NULL) /* can't extend */ return NULL; - for (i = 0; i < sim_brk_lnt; i++) /* copy table */ - *(newp + i) = *(sim_brk_tab + i); + memcpy (newp, sim_brk_tab, sim_brk_lnt * sizeof (*sim_brk_tab));/* copy table */ + memset (newp + sim_brk_lnt, 0, SIM_BRK_INILNT * sizeof (*newp));/* zero new entries */ free (sim_brk_tab); /* free old table */ sim_brk_tab = newp; /* new base, lnt */ sim_brk_lnt = t; } -if (sim_brk_ins != sim_brk_ent) { /* move needed? */ - for (bp = sim_brk_tab + sim_brk_ent; - bp > sim_brk_tab + sim_brk_ins; bp--) - *bp = *(bp - 1); +if ((sim_brk_ins == sim_brk_ent) || + ((sim_brk_ins != sim_brk_ent) && + (sim_brk_tab[sim_brk_ins]->addr != loc))) { /* need to open a hole? */ + for (i = sim_brk_ent; i > sim_brk_ins; --i) + sim_brk_tab[i] = sim_brk_tab[i - 1]; + sim_brk_tab[sim_brk_ins] = NULL; } -bp = sim_brk_tab + sim_brk_ins; +bp = calloc (1, sizeof (*bp)); +bp->next = sim_brk_tab[sim_brk_ins]; +sim_brk_tab[sim_brk_ins] = bp; +if (bp->next == NULL) + sim_brk_ent += 1; bp->addr = loc; -bp->typ = 0; +bp->typ = btyp; bp->cnt = 0; bp->act = NULL; -sim_brk_ent = sim_brk_ent + 1; +for (i = 0; i < SIM_BKPT_N_SPC; i++) + bp->time_fired[i] = -1.0; return bp; } @@ -9035,12 +9078,17 @@ if (~sim_brk_types & sw) { } if ((sw & BRK_TYP_DYN_ALL) && act) /* can't specify an action with a dynamic breakpoint */ return SCPE_ARG; -bp = sim_brk_fnd (loc); /* present? */ +bp = sim_brk_fnd (loc); /* loc present? */ if (!bp) /* no, allocate */ - bp = sim_brk_new (loc); + bp = sim_brk_new (loc, sw); +else { + while (bp && (bp->typ != sw)) + bp = bp->next; + if (!bp) + bp = sim_brk_new (loc, sw); + } if (!bp) /* still no? mem err */ return SCPE_MEM; -bp->typ |= sw; /* set type */ bp->cnt = ncnt; /* set count */ if ((!(sw & BRK_TYP_DYN_ALL)) && /* Not Dynamic and */ (bp->act != NULL) && (act != NULL)) { /* replace old action? */ @@ -9054,7 +9102,7 @@ if ((act != NULL) && (*act != 0)) { /* new action? */ strncpy (newp, act, CBUFSIZE); /* copy action */ bp->act = newp; /* set pointer */ } -sim_brk_summ = sim_brk_summ | sw; +sim_brk_summ = sim_brk_summ | (sw & ~BRK_TYP_TEMP); return SCPE_OK; } @@ -9062,23 +9110,42 @@ return SCPE_OK; t_stat sim_brk_clr (t_addr loc, int32 sw) { -BRKTAB *bp = sim_brk_fnd (loc); +BRKTAB *bpl, *bp = sim_brk_fnd (loc); +int32 i; if (!bp) /* not there? ok */ return SCPE_OK; if (sw == 0) sw = SIM_BRK_ALLTYP; -bp->typ = bp->typ & ~sw; -if (bp->typ) /* clear all types? */ - return SCPE_OK; -if (bp->act != NULL) /* deallocate action */ - free (bp->act); -for ( ; bp < (sim_brk_tab + sim_brk_ent - 1); bp++) /* erase entry */ - *bp = *(bp + 1); -sim_brk_ent = sim_brk_ent - 1; /* decrement count */ + +while (bp) { + if (bp->typ == (bp->typ & sw)) { + free (bp->act); /* deallocate action */ + if (bp == sim_brk_tab[sim_brk_ins]) + bpl = sim_brk_tab[sim_brk_ins] = bp->next; + else + bpl->next = bp->next; + free (bp); + bp = bpl; + } + else { + bpl = bp; + bp = bp->next; + } + } +if (sim_brk_tab[sim_brk_ins] == NULL) { /* erased entry */ + sim_brk_ent = sim_brk_ent - 1; /* decrement count */ + for (i = sim_brk_ins; i < sim_brk_ent; i++) /* shuffle remaining entries */ + sim_brk_tab[i] = sim_brk_tab[i+1]; + } sim_brk_summ = 0; /* recalc summary */ -for (bp = sim_brk_tab; bp < (sim_brk_tab + sim_brk_ent); bp++) - sim_brk_summ = sim_brk_summ | bp->typ; +for (i = 0; i < sim_brk_ent; i++) { + bp = sim_brk_tab[i]; + while (bp) { + sim_brk_summ |= (bp->typ & ~BRK_TYP_TEMP); + bp = bp->next; + } + } return SCPE_OK; } @@ -9086,13 +9153,16 @@ return SCPE_OK; t_stat sim_brk_clrall (int32 sw) { -BRKTAB *bp; +int32 i; -if (sw == 0) sw = SIM_BRK_ALLTYP; -for (bp = sim_brk_tab; bp < (sim_brk_tab + sim_brk_ent); ) { - if (bp->typ & sw) - sim_brk_clr (bp->addr, sw); - else bp++; +if (sw == 0) + sw = SIM_BRK_ALLTYP; +for (i = 0; i < sim_brk_ent;) { + t_addr loc = sim_brk_tab[i]->addr; + sim_brk_clr (loc, sw); + if ((i < sim_brk_ent) && + (loc == sim_brk_tab[i]->addr)) + ++i; } return SCPE_OK; } @@ -9101,7 +9171,7 @@ return SCPE_OK; t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw) { -BRKTAB *bp = sim_brk_fnd (loc); +BRKTAB *bp = sim_brk_fnd_ex (loc, sw & (~SWMASK ('C')), FALSE); DEVICE *dptr; int32 i, any; @@ -9150,13 +9220,60 @@ return SCPE_OK; t_stat sim_brk_showall (FILE *st, int32 sw) { -BRKTAB *bp; +int32 bit, mask, types; +BRKTAB **bpt; if ((sw == 0) || (sw == SWMASK ('C'))) sw = SIM_BRK_ALLTYP | ((sw == SWMASK ('C')) ? SWMASK ('C') : 0); -for (bp = sim_brk_tab; bp < (sim_brk_tab + sim_brk_ent); bp++) { - if (bp->typ & sw) - sim_brk_show (st, bp->addr, sw); +for (types=bit=0; bit <= ('Z'-'A'); bit++) + if (sim_brk_types & (1 << bit)) + ++types; +if ((!(sw & SWMASK ('C'))) && sim_brk_types && (types > 1)) { + fprintf (st, "Supported Breakpoint Types:"); + for (bit=0; bit <= ('Z'-'A'); bit++) + if (sim_brk_types & (1 << bit)) + fprintf (st, " -%c", 'A' + bit); + fprintf (st, "\n"); + } +if (((sw & sim_brk_types) != sim_brk_types) && (types > 1)) { + mask = (sw & sim_brk_types); + fprintf (st, "Displaying Breakpoint Types:"); + for (bit=0; bit <= ('Z'-'A'); bit++) + if (mask & (1 << bit)) + fprintf (st, " -%c", 'A' + bit); + fprintf (st, "\n"); + } +for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) { + BRKTAB *prev = NULL; + BRKTAB *cur = *bpt; + BRKTAB *next; + /* First reverse the list */ + while (cur) { + next = cur->next; + cur->next = prev; + prev = cur; + cur = next; + } + /* save reversed list in the head pointer so lookups work */ + *bpt = prev; + /* Walk the reversed list and print it in the order it was defined in */ + cur = prev; + while (cur) { + if (cur->typ & sw) + sim_brk_show (st, cur->addr, cur->typ | ((sw & SWMASK ('C')) ? SWMASK ('C') : 0)); + cur = cur->next; + } + /* reversing the list again */ + cur = prev; + prev = NULL; + while (cur) { + next = cur->next; + cur->next = prev; + prev = cur; + cur = next; + } + /* restore original list */ + *bpt = prev; } return SCPE_OK; } @@ -9172,22 +9289,19 @@ uint32 res = 0; if (sim_brk_summ & BRK_TYP_DYN_ALL) btyp |= BRK_TYP_DYN_ALL; -if ((bp = sim_brk_fnd (loc)) && (btyp & bp->typ)) { /* in table, and type match? */ - if ((sim_brk_pend[spc] && (loc == sim_brk_ploc[spc])) || /* previous location? */ - (--bp->cnt > 0)) /* count > 0? */ +if ((bp = sim_brk_fnd_ex (loc, btyp, TRUE))) { /* in table, and type match? */ + if (bp->time_fired[spc] == sim_gtime()) /* already taken? */ + return 0; + bp->time_fired[spc] = sim_time; /* remember match time */ + if (--bp->cnt > 0) /* count > 0? */ return 0; bp->cnt = 0; /* reset count */ sim_brk_setact (bp->act); /* set up actions */ res = btyp & bp->typ; /* set return value */ if (bp->typ & BRK_TYP_TEMP) - sim_brk_clr (loc, btyp | BRK_TYP_TEMP); /* delete one-shot breakpoint */ - else { - sim_brk_ploc[spc] = loc; /* save location */ - sim_brk_pend[spc] = TRUE; /* don't do twice */ - } + sim_brk_clr (loc, bp->typ); /* delete one-shot breakpoint */ return res; } -sim_brk_pend[spc] = FALSE; return res; } @@ -9243,26 +9357,33 @@ else void sim_brk_npc (uint32 cnt) { -uint32 i; +uint32 spc; +BRKTAB **bpt, *bp; if ((cnt == 0) || (cnt > SIM_BKPT_N_SPC)) cnt = SIM_BKPT_N_SPC; -for (i = 0; i < cnt; i++) { - sim_brk_pend[i] = FALSE; - sim_brk_ploc[i] = 0; +for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) { + for (bp = *bpt; bp; bp = bp->next) { + for (spc = 0; spc < cnt; spc++) + bp->time_fired[spc] = -1.0; + } } -return; } /* Clear breakpoint space */ -void sim_brk_clrspc (uint32 spc) +void sim_brk_clrspc (uint32 spc, uint32 btyp) { +BRKTAB **bpt, *bp; + if (spc < SIM_BKPT_N_SPC) { - sim_brk_pend[spc] = FALSE; - sim_brk_ploc[spc] = 0; + for (bpt = sim_brk_tab; bpt < (sim_brk_tab + sim_brk_ent); bpt++) { + for (bp = *bpt; bp; bp = bp->next) { + if (bp->typ & btyp) + bp->time_fired[spc] = -1.0; + } + } } -return; } /* Expect package. This code provides a mechanism to stop and control simulator diff --git a/scp.h b/scp.h index 5bd9e930..5d8e5379 100644 --- a/scp.h +++ b/scp.h @@ -183,9 +183,8 @@ SHTAB *find_shtab (SHTAB *tab, const char *gbuf); t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr); BRKTAB *sim_brk_fnd (t_addr loc); uint32 sim_brk_test (t_addr bloc, uint32 btyp); -void sim_brk_clrspc (uint32 spc); +void sim_brk_clrspc (uint32 spc, uint32 btyp); void sim_brk_npc (uint32 cnt); -char *sim_brk_clract (void); void sim_brk_setact (const char *action); t_stat sim_send_input (SEND *snd, uint8 *data, size_t size, uint32 after, uint32 delay); t_stat sim_show_send_input (FILE *st, const SEND *snd); @@ -273,8 +272,6 @@ extern volatile int32 stop_cpu; extern uint32 sim_brk_types; /* breakpoint info */ extern uint32 sim_brk_dflt; extern uint32 sim_brk_summ; -extern t_bool sim_brk_pend[SIM_BKPT_N_SPC]; -extern t_addr sim_brk_ploc[SIM_BKPT_N_SPC]; extern FILE *stdnul; extern t_bool sim_asynch_enabled; diff --git a/sim_defs.h b/sim_defs.h index d96aef86..5cc4b22a 100644 --- a/sim_defs.h +++ b/sim_defs.h @@ -714,6 +714,7 @@ struct SCHTAB { struct BRKTAB { t_addr addr; /* address */ uint32 typ; /* mask of types */ +#define BRK_TYP_USR_TYPES ((1 << ('Z'-'A'+1)) - 1)/* all types A-Z */ #define BRK_TYP_DYN_STEPOVER (SWMASK ('Z'+1)) #define BRK_TYP_DYN_USR (SWMASK ('Z'+2)) #define BRK_TYP_DYN_ALL (BRK_TYP_DYN_USR|BRK_TYP_DYN_STEPOVER) /* Mask of All Dynamic types */ @@ -721,6 +722,8 @@ struct BRKTAB { #define BRK_TYP_MAX (('Z'-'A')+3) /* Maximum breakpoint type */ int32 cnt; /* proceed count */ char *act; /* action string */ + double time_fired[SIM_BKPT_N_SPC]; /* instruction count when match occurred */ + BRKTAB *next; /* list with same address value */ }; /* Expect rule */