SCP: Extended EXPECT and SEND to have more flexible activation delays

- EXPECT will now tolerate a HALTAFTER=n parameter which delay the simulator stopping execution for n instructions.  Unpredictable behavior will happen if multiple EXPECT conditions see matching data before the first actualy halt occurs.
- SEND has an AFTER=n argument which delays the initial stuffed data from being input for at least n instructions.  It also has a DELAY=m argument which specifies the minimum number of instructions which must execute between stuffed input data.
- Changed run_cmd() to no longer clear pending breakpoint actions before starting instruction execution.
- Added a -Q switch to the commands which dispatch through run_cmd() (RUN, STEP, NEXT, GO, BOOT, etc.).  This switch will suppress status output when execution stops.  This will allow sequences of breakpoint action commands to silently execute when needed.
This commit is contained in:
Mark Pizzolato 2014-10-20 16:47:33 -07:00
parent 7bb57ca979
commit 5a4bbbad8d
3 changed files with 77 additions and 36 deletions

65
scp.c
View file

@ -3025,6 +3025,7 @@ char gbuf[CBUFSIZE], *gptr = gbuf, *tptr;
uint8 dbuf[CBUFSIZE], *dptr = dbuf;
uint32 dsize = 0;
uint32 delay = 0;
uint32 after = 0;
t_stat r;
SEND *snd;
@ -3039,6 +3040,7 @@ if (isalpha(gbuf[0]) && (strchr (gbuf, ':'))) {
else
snd = sim_cons_get_send ();
while (*cptr) {
if ((!strncmp(gbuf, "DELAY=", 6)) && (gbuf[6])) {
delay = (uint32)get_uint (&gbuf[6], 10, 10000000, &r);
if (r != SCPE_OK) {
@ -3046,6 +3048,22 @@ if ((!strncmp(gbuf, "DELAY=", 6)) && (gbuf[6])) {
return SCPE_ARG|SCPE_NOMESSAGE;
}
cptr = tptr;
tptr = get_glyph (cptr, gbuf, ',');
continue;
}
if ((!strncmp(gbuf, "AFTER=", 6)) && (gbuf[6])) {
after = (uint32)get_uint (&gbuf[6], 10, 10000000, &r);
if (r != SCPE_OK) {
sim_printf ("Invalid Delay Value\n");
return SCPE_ARG|SCPE_NOMESSAGE;
}
cptr = tptr;
tptr = get_glyph (cptr, gbuf, ',');
continue;
}
if ((*cptr == '"') || (*cptr == '\''))
break;
return SCPE_ARG;
}
if (*cptr) {
if ((*cptr != '"') && (*cptr != '\'')) {
@ -3063,7 +3081,7 @@ if (*cptr) {
}
if ((dsize == 0) && (delay == 0))
return SCPE_2FARG;
return sim_send_input (snd, dbuf, dsize, delay);
return sim_send_input (snd, dbuf, dsize, after, delay);
}
t_stat sim_show_send (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr)
@ -5605,7 +5623,6 @@ fflush(stdout); /* flush stdout */
if (sim_log) /* flush log if enabled */
fflush (sim_log);
sim_throt_sched (); /* set throttle */
sim_brk_clract (); /* defang actions */
sim_rtcn_init_all (); /* re-init clocks */
sim_start_timer_services (); /* enable wall clock timing */
@ -5620,7 +5637,7 @@ do {
t_addr val;
BRKTAB *bp;
if (r >= SCPE_BASE) /* done if an error occurred */
if (SCPE_BARE_STATUS(r) >= SCPE_BASE) /* done if an error occurred */
break;
if (sim_vm_pc_value) /* done if didn't stop at a dynamic breakpoint */
val = (t_addr)(*sim_vm_pc_value)();
@ -5680,7 +5697,7 @@ sim_cancel (&sim_step_unit); /* cancel step timer */
sim_throt_cancel (); /* cancel throttle */
AIO_UPDATE_QUEUE;
UPDATE_SIM_TIME; /* update sim time */
return r;
return r | ((sim_switches & SWMASK ('Q')) ? SCPE_NOMESSAGE : 0);
}
/* run command message handler */
@ -8290,19 +8307,32 @@ return SCPE_OK;
t_stat sim_set_expect (EXPECT *exp, char *cptr)
{
char gbuf[CBUFSIZE], *c1ptr;
char gbuf[CBUFSIZE], *gptr = gbuf, *tptr, *c1ptr;
uint32 after = exp->after;
int32 cnt = 0;
t_stat r;
if ((cptr == NULL) || (*cptr == 0))
return SCPE_2FARG;
if (*cptr == '[') {
cnt = (int32) strtotv (cptr + 1, &c1ptr, 10);
if ((cptr == c1ptr) || (*c1ptr != ']'))
return SCPE_ARG;
if ((cptr == c1ptr) || (*c1ptr != ']')) {
sim_printf ("Invalid Repeat count specification\n");
return SCPE_ARG|SCPE_NOMESSAGE;
}
cptr = c1ptr + 1;
while (isspace(*cptr))
++cptr;
}
tptr = get_glyph (cptr, gbuf, ',');
if ((!strncmp(gbuf, "HALTAFTER=", 10)) && (gbuf[10])) {
after = (uint32)get_uint (&gbuf[10], 10, 100000000, &r);
if (r != SCPE_OK) {
sim_printf ("Invalid Halt After Value\n");
return SCPE_ARG|SCPE_NOMESSAGE;
}
cptr = tptr;
}
if ((*cptr != '"') && (*cptr != '\'')) {
sim_printf ("String must be quote delimited\n");
return SCPE_ARG|SCPE_NOMESSAGE;
@ -8310,7 +8340,7 @@ if ((*cptr != '"') && (*cptr != '\'')) {
cptr = get_glyph_quoted (cptr, gbuf, 0);
if (*cptr != '\0')
return SCPE_2MARG; /* No more arguments */
return sim_exp_set (exp, gbuf, cnt, sim_switches, cptr);
return sim_exp_set (exp, gbuf, cnt, after, sim_switches, cptr);
}
/* Clear expect */
@ -8398,7 +8428,7 @@ return SCPE_OK;
/* Set/Add an expect rule */
t_stat sim_exp_set (EXPECT *exp, const char *match, int32 cnt, int32 switches, char *act)
t_stat sim_exp_set (EXPECT *exp, const char *match, int32 cnt, uint32 after, int32 switches, char *act)
{
EXPTAB *ep;
uint8 *match_buf;
@ -8450,6 +8480,7 @@ if (ep) /* no, allocate */
exp->rules = (EXPTAB *) realloc (exp->rules, sizeof (*exp->rules)*(exp->size + 1));
ep = &exp->rules[exp->size];
exp->size += 1;
exp->after = after; /* set halt after value */
memset (ep, 0, sizeof(*ep));
ep->match_pattern = (char *)malloc (strlen (match) + 1);
strcpy (ep->match_pattern, match);
@ -8529,6 +8560,8 @@ if (exp->buf_size) {
fprintf (st, "Match Buffer Size: %d\n", exp->buf_size);
fprintf (st, "Buffer Insert Offset: %d\n", exp->buf_ins);
}
if (exp->after)
fprintf (st, "Halt After: %d instructions\n", exp->after);
if (!*match)
return sim_exp_showall (st, exp);
if (!ep)
@ -8645,7 +8678,7 @@ if (i != exp->size) { /* Found? */
sim_exp_clr_tab (exp, ep); /* delete it */
if (ep->switches & EXP_TYP_CLEARALL) /* One shot expect rule? */
sim_exp_clrall (exp); /* delete all rules */
sim_activate (&sim_expect_unit, 0); /* schedule simulation stop asap */
sim_activate (&sim_expect_unit, exp->after); /* schedule simulation stop when indicated */
}
}
return SCPE_OK;
@ -8653,7 +8686,7 @@ return SCPE_OK;
/* Queue input data for sending */
t_stat sim_send_input (SEND *snd, uint8 *data, size_t size, uint32 delay)
t_stat sim_send_input (SEND *snd, uint8 *data, size_t size, uint32 after, uint32 delay)
{
if (snd->extoff != 0) {
if (snd->insoff-snd->extoff > 0)
@ -8669,7 +8702,11 @@ memcpy(snd->buffer+snd->insoff, data, size);
snd->insoff += size;
if (delay)
snd->delay = delay;
snd->next_time = sim_gtime() + snd->delay;
if (after)
snd->after = after;
if (snd->after == 0)
snd->after = snd->delay;
snd->next_time = sim_gtime() + snd->after;
return SCPE_OK;
}
@ -8684,7 +8721,9 @@ if (snd->extoff < snd->insoff) {
}
else
fprintf (st, "No Pending Input Data\n");
fprintf (st, "Pending Input Delay=%d instructions per character\n", snd->delay);
if ((snd->next_time - sim_gtime()) > 0)
fprintf (st, "Minimum of %d instructions befor sending first character\n", (int)(snd->next_time - sim_gtime()));
fprintf (st, "Minimum of %d instructions between characters\n", (int)snd->delay);
return SCPE_OK;
}

4
scp.h
View file

@ -145,12 +145,12 @@ uint32 sim_brk_test (t_addr bloc, uint32 btyp);
void sim_brk_clrspc (uint32 spc);
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 delay);
t_stat sim_send_input (SEND *snd, uint8 *data, size_t size, uint32 after, uint32 delay);
t_stat sim_show_send_input (FILE *st, SEND *snd);
t_bool sim_send_poll_data (SEND *snd, t_stat *stat);
t_stat sim_set_expect (EXPECT *exp, char *cptr);
t_stat sim_set_noexpect (EXPECT *exp, char *cptr);
t_stat sim_exp_set (EXPECT *exp, const char *match, int32 cnt, int32 switches, char *act);
t_stat sim_exp_set (EXPECT *exp, const char *match, int32 cnt, uint32 after, int32 switches, char *act);
t_stat sim_exp_clr (EXPECT *exp, const char *match);
t_stat sim_exp_clrall (EXPECT *exp);
t_stat sim_exp_show (FILE *st, EXPECT *exp, const char *match);

View file

@ -668,6 +668,7 @@ struct sim_expect {
uint32 dbit; /* Debugging Bit */
struct sim_exptab *rules; /* match rules */
int32 size; /* count of match rules */
uint32 after; /* delay before halting */
uint8 *buf; /* buffer of output data which has produced */
uint32 buf_ins; /* buffer insertion point for the next output data */
uint32 buf_size; /* buffer size */
@ -676,10 +677,11 @@ struct sim_expect {
/* Send Context */
struct sim_send {
uint32 delay; /* instruction delay before/between sent data */
uint32 delay; /* instruction delay between sent data */
#define SEND_DEFAULT_DELAY 1000 /* default delay instruction count */
struct sim_device *dptr; /* Device (for Debug) */
uint32 dbit; /* Debugging Bit */
#define SEND_DEFAULT_DELAY 1000 /* default delay instruction count */
uint32 after; /* instruction delay before sending any data */
double next_time; /* execution time when next data can be sent */
uint8 *buffer; /* buffer */
size_t bufsize; /* buffer size */