FRONTPANEL: sim_frontpanel API version 4 release

Add simulator side register bit sampling with averaged sample values
delivered across the API at specified rates.
This commit is contained in:
Mark Pizzolato 2017-02-04 10:48:13 -08:00
parent f171055809
commit 665ebf0fd1
5 changed files with 627 additions and 82 deletions

View file

@ -59,6 +59,10 @@ const char *sim_config =
unsigned int PC, SP, FP, AP, PSL, R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, atPC;
unsigned int PCQ[32];
int PSL_bits[32];
int PC_bits[32];
int PC_indirect_bits[32];
int update_display = 1;
static void
@ -357,6 +361,35 @@ if (sim_panel_break_output_set (panel, "-P \"Device? [XQA0]: \"")) {
printf ("Unexpected error establishing an output breakpoint: %s\n", sim_panel_get_error());
goto Done;
}
if (!sim_panel_set_sampling_parameters (panel, 0, 199)) {
printf ("Unexpected success setting sampling parameters to 0, 199\n");
goto Done;
}
if (!sim_panel_set_sampling_parameters (panel, 199, 0)) {
printf ("Unexpected success setting sampling parameters to 199, 0\n");
goto Done;
}
if (!sim_panel_add_register_bits (panel, "PSL", NULL, 32, PSL_bits)) {
printf ("Unexpected success setting PSL bits before setting sampling parameters\n");
goto Done;
}
if (sim_panel_set_sampling_parameters (panel, 500, 100)) {
printf ("Unexpected error setting sampling parameters to 200, 100: %s\n", sim_panel_get_error());
goto Done;
}
if (sim_panel_add_register_indirect_bits (panel, "PC", NULL, 32, PC_indirect_bits)) {
printf ("Error adding register 'PSL' bits: %s\n", sim_panel_get_error());
goto Done;
}
if (sim_panel_add_register_bits (panel, "PSL", NULL, 32, PSL_bits)) {
printf ("Error adding register 'PSL' bits: %s\n", sim_panel_get_error());
goto Done;
}
if (sim_panel_add_register_bits (panel, "PC", NULL, 32, PC_bits)) {
printf ("Error adding register 'PSL' bits: %s\n", sim_panel_get_error());
goto Done;
}
sim_panel_clear_error ();
while (1) {
size_t i;

3
scp.h
View file

@ -195,6 +195,7 @@ CTAB *find_ctab (CTAB *tab, const char *gbuf);
C1TAB *find_c1tab (C1TAB *tab, const char *gbuf);
SHTAB *find_shtab (SHTAB *tab, const char *gbuf);
t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr);
t_value get_rval (REG *rptr, uint32 idx);
BRKTAB *sim_brk_fnd (t_addr loc);
uint32 sim_brk_test (t_addr bloc, uint32 btyp);
void sim_brk_clrspc (uint32 spc, uint32 btyp);
@ -264,6 +265,8 @@ t_stat scp_vhelpFromFile (FILE *st, DEVICE *dptr,
/* Global data */
extern DEVICE *sim_dflt_dev;
extern DEVICE *sim_dfdev;
extern UNIT *sim_dfunit;
extern int32 sim_interval;
extern int32 sim_switches;
extern int32 sim_quiet;

View file

@ -428,14 +428,18 @@ return SCPE_OK;
t_stat sim_rem_con_poll_svc (UNIT *uptr); /* remote console connection poll routine */
t_stat sim_rem_con_data_svc (UNIT *uptr); /* remote console connection data routine */
t_stat sim_rem_con_repeat_svc (UNIT *uptr); /* remote auto repeat command console timing routine */
t_stat sim_rem_con_smp_collect_svc (UNIT *uptr); /* remote remote register data sampling routine */
t_stat sim_rem_con_reset (DEVICE *dptr); /* remote console reset routine */
#define rem_con_poll_unit (&sim_remote_console.units[0])
#define rem_con_data_unit (&sim_remote_console.units[1])
#define REM_CON_BASE_UNITS 2
#define rem_con_repeat_units (&sim_remote_console.units[REM_CON_BASE_UNITS])
#define rem_con_smp_smpl_units (&sim_remote_console.units[REM_CON_BASE_UNITS+sim_rem_con_tmxr.lines])
#define DBG_MOD 0x00000004 /* Remote Console Mode activities */
#define DBG_REP 0x00000008 /* Remote Console Repeat activities */
#define DBG_CMD 0x00000010 /* Remote Console Command activities */
#define DBG_SAM 0x00000010 /* Remote Console Sample activities */
#define DBG_CMD 0x00000020 /* Remote Console Command activities */
DEBTAB sim_rem_con_debug[] = {
{"TRC", DBG_TRC, "routine calls"},
@ -445,6 +449,7 @@ DEBTAB sim_rem_con_debug[] = {
{"CMD", DBG_CMD, "Remote Console Command activity"},
{"MODE", DBG_MOD, "Remote Console Mode activity"},
{"REPEAT", DBG_REP, "Remote Console Repeat activity"},
{"SAMPLE", DBG_SAM, "Remote Console Sample activity"},
{0}
};
@ -464,6 +469,22 @@ DEVICE sim_remote_console = {
NULL, DEV_DEBUG | DEV_NOSAVE, 0, sim_rem_con_debug,
NULL, NULL, NULL, NULL, NULL, sim_rem_con_description};
typedef struct BITSAMPLE BITSAMPLE;
struct BITSAMPLE {
int tot; /* total of all values */
int ptr; /* pointer to next value cell */
int depth; /* number of values */
int *vals; /* values */
};
typedef struct BITSAMPLE_REG BITSAMPLE_REG;
struct BITSAMPLE_REG {
REG *reg; /* Register to be sampled */
t_bool indirect; /* Register value points at memory */
DEVICE *dptr; /* Device register is part of */
UNIT *uptr; /* Unit Register is related to */
uint32 width; /* number of bits to sample */
BITSAMPLE *bits;
};
typedef struct REMOTE REMOTE;
struct REMOTE {
int32 buf_size;
@ -474,16 +495,18 @@ struct REMOTE {
char *act;
t_bool single_mode;
uint32 read_timeout;
int line;
TMLN *lp;
UNIT *uptr;
uint32 repeat_interval;
t_bool repeat_pending;
char *repeat_action;
int line; /* remote console line number */
TMLN *lp; /* mux line/socket for remote session */
UNIT *uptr; /* remote console unit */
uint32 repeat_interval; /* usecs between repeat execution */
t_bool repeat_pending; /* repeat delivery pending */
char *repeat_action; /* command(s) to repeatedly execute */
int smp_sample_interval; /* cycles between samples */
uint32 smp_reg_count; /* sample register count */
BITSAMPLE_REG *smp_regs; /* registers being sampled */
};
REMOTE *sim_rem_consoles = NULL;
static TMXR sim_rem_con_tmxr = { 0, 0, 0, NULL, NULL, &sim_remote_console };/* remote console line mux */
static uint32 sim_rem_read_timeout = 30; /* seconds before automatic continue */
static uint32 *sim_rem_read_timeouts = NULL;/* per line read timeout (default from sim_rem_read_timeout) */
@ -498,6 +521,26 @@ static t_bool sim_rem_master_was_enabled = FALSE; /* Master was Enabled */
static t_bool sim_rem_master_was_connected = FALSE; /* Master Mode has been connected */
static t_offset sim_rem_cmd_log_start = 0; /* Log File saved position */
static t_stat sim_rem_sample_output (FILE *st, int32 line)
{
REMOTE *rem = &sim_rem_consoles[line];
uint32 reg;
if (rem->smp_reg_count == 0) {
fprintf (st, "Samples are not being collected\n");
return SCPE_OK;
}
for (reg = 0; reg < rem->smp_reg_count; reg++) {
uint32 bit;
fprintf (st, "}%s %s%s %d:", rem->smp_regs[reg].dptr->name, rem->smp_regs[reg].reg->name, rem->smp_regs[reg].indirect ? " -I" : "", rem->smp_regs[reg].bits[0].depth);
for (bit = 0; bit < rem->smp_regs[reg].width; bit++)
fprintf (st, "%s%d", (bit != 0) ? "," : "", rem->smp_regs[reg].bits[bit].tot);
fprintf (st, "\n");
}
return SCPE_OK;
}
/* SET REMOTE CONSOLE command */
@ -567,6 +610,24 @@ for (i=connections=0; i<sim_rem_con_tmxr.lines; i++) {
fprintf (st, "The Command: %s\n", rem->repeat_action);
fprintf (st, " is repeated every %s\n", sim_fmt_secs (rem->repeat_interval / 1000000.0));
}
if (rem->smp_reg_count) {
uint32 reg;
DEVICE *dptr = NULL;
fprintf (st, "Register Bit Sampling is occurring every %d cycles\n", rem->smp_sample_interval);
fprintf (st, " Registers being sampled are: ");
for (reg = 0; reg < rem->smp_reg_count; reg++) {
if (rem->smp_regs[reg].indirect)
fprintf (st, " indirect ");
if (dptr != rem->smp_regs[reg].dptr)
fprintf (st, "%s ", rem->smp_regs[reg].dptr->name);
fprintf (st, "%s%s", rem->smp_regs[reg].reg->name, ((reg + 1) < rem->smp_reg_count) ? ", " : "");
dptr = rem->smp_regs[reg].dptr;
}
fprintf (st, "\n");
if (sim_switches & SWMASK ('D'))
sim_rem_sample_output (st, rem->line);
}
}
return SCPE_OK;
}
@ -620,16 +681,26 @@ static t_stat x_repeat_cmd (int32 flag, CONST char *cptr)
return 2+SCPE_IERR; /* This routine should never be called */
}
static t_stat x_step_cmd (int32 flag, CONST char *cptr)
static t_stat x_collect_cmd (int32 flag, CONST char *cptr)
{
return 3+SCPE_IERR; /* This routine should never be called */
}
static t_stat x_run_cmd (int32 flag, CONST char *cptr)
static t_stat x_sampleout_cmd (int32 flag, CONST char *cptr)
{
return 4+SCPE_IERR; /* This routine should never be called */
}
static t_stat x_step_cmd (int32 flag, CONST char *cptr)
{
return 5+SCPE_IERR; /* This routine should never be called */
}
static t_stat x_run_cmd (int32 flag, CONST char *cptr)
{
return 6+SCPE_IERR; /* This routine should never be called */
}
static t_stat x_help_cmd (int32 flag, CONST char *cptr);
static CTAB allowed_remote_cmds[] = {
@ -642,6 +713,8 @@ static CTAB allowed_remote_cmds[] = {
{ "DEASSIGN", &deassign_cmd, 0 },
{ "CONTINUE", &x_continue_cmd, 0 },
{ "REPEAT", &x_repeat_cmd, 0 },
{ "COLLECT", &x_collect_cmd, 0 },
{ "SAMPLEOUT",&x_sampleout_cmd, 0 },
{ "STEP", &x_step_cmd, 0 },
{ "PWD", &pwd_cmd, 0 },
{ "SAVE", &save_cmd, 0 },
@ -664,6 +737,8 @@ static CTAB allowed_master_remote_cmds[] = {
{ "DEASSIGN", &deassign_cmd, 0 },
{ "CONTINUE", &x_continue_cmd, 0 },
{ "REPEAT", &x_repeat_cmd, 0 },
{ "COLLECT", &x_collect_cmd, 0 },
{ "SAMPLEOUT",&x_sampleout_cmd, 0 },
{ "STEP", &x_step_cmd, 0 },
{ "PWD", &pwd_cmd, 0 },
{ "SAVE", &save_cmd, 0 },
@ -693,6 +768,8 @@ static CTAB allowed_single_remote_cmds[] = {
{ "EXAMINE", &exdep_cmd, EX_E },
{ "EVALUATE", &eval_cmd, 0 },
{ "REPEAT", &x_repeat_cmd, 0 },
{ "COLLECT", &x_collect_cmd, 0 },
{ "SAMPLEOUT",&x_sampleout_cmd, 0 },
{ "PWD", &pwd_cmd, 0 },
{ "DIR", &dir_cmd, 0 },
{ "LS", &dir_cmd, 0 },
@ -704,6 +781,8 @@ static CTAB allowed_single_remote_cmds[] = {
static CTAB remote_only_cmds[] = {
{ "REPEAT", &x_repeat_cmd, 0 },
{ "COLLECT", &x_collect_cmd, 0 },
{ "SAMPLEOUT",&x_sampleout_cmd, 0 },
{ NULL, NULL }
};
@ -864,7 +943,7 @@ return buf;
Parse and setup Remote Console REPEAT command:
REPEAT EVERY nnn USECS Command {; command...}
*/
static t_stat _rem_repeat_cmd_setup (int32 line, CONST char **iptr)
static t_stat sim_rem_repeat_cmd_setup (int32 line, CONST char **iptr)
{
char gbuf[CBUFSIZE];
int32 val;
@ -940,6 +1019,239 @@ if (stat == SCPE_OK) {
return stat;
}
/*
Parse and setup Remote Console REPEAT command:
COLLECT nnn SAMPLES EVERY nnn CYCLES reg{,reg...}
*/
static t_stat sim_rem_collect_cmd_setup (int32 line, CONST char **iptr)
{
char gbuf[CBUFSIZE];
int32 samples, cycles;
t_bool all_stop = FALSE;
t_stat stat = SCPE_OK;
CONST char *cptr = *iptr;
REMOTE *rem = &sim_rem_consoles[line];
sim_debug (DBG_SAM, &sim_remote_console, "Collect Setup: %s\n", cptr);
if (*cptr == 0) /* required argument? */
return SCPE_2FARG;
cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */
samples = (int32) get_uint (gbuf, 10, INT_MAX, &stat);
if ((stat != SCPE_OK) || (samples <= 0)) { /* error? */
if (MATCH_CMD (gbuf, "STOP") == 0) {
stat = SCPE_OK;
if (*cptr) { /* more command arguments? */
cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */
if ((MATCH_CMD (gbuf, "ALL") != 0) || /* */
(*cptr != 0) || /* */
(line != 0)) /* master line? */
stat = SCPE_ARG;
else
all_stop = TRUE;
}
if (stat == SCPE_OK) {
for (line = all_stop ? 0 : rem->line; line < (all_stop ? sim_rem_con_tmxr.lines : (rem->line + 1)); line++) {
uint32 i, j;
rem = &sim_rem_consoles[line];
for (i = 0; i< rem->smp_reg_count; i++) {
for (j = 0; j < rem->smp_regs[i].width; j++)
free (rem->smp_regs[i].bits[j].vals);
free (rem->smp_regs[i].bits);
}
free (rem->smp_regs);
rem->smp_regs = NULL;
rem->smp_reg_count = 0;
sim_cancel (&rem_con_smp_smpl_units[rem->line]);
rem->smp_sample_interval = 0;
}
}
}
else
stat = sim_messagef (SCPE_ARG, "Expected value or STOP found: %s\n", gbuf);
}
else {
const char *tptr;
cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */
if (MATCH_CMD (gbuf, "SAMPLES") != 0) {
*iptr = cptr;
return sim_messagef (SCPE_ARG, "Expected SAMPLES found: %s\n", gbuf);
}
cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */
if (MATCH_CMD (gbuf, "EVERY") != 0) {
*iptr = cptr;
return sim_messagef (SCPE_ARG, "Expected EVERY found: %s\n", gbuf);
}
cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */
cycles = (int32) get_uint (gbuf, 10, INT_MAX, &stat);
if ((stat != SCPE_OK) || (cycles <= 0)) { /* error? */
*iptr = cptr;
return sim_messagef (SCPE_ARG, "Expected value found: %s\n", gbuf);
}
cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */
if ((MATCH_CMD (gbuf, "CYCLES") != 0) || (*cptr == 0)) {
*iptr = cptr;
return sim_messagef (SCPE_ARG, "Expected CYCLES found: %s\n", gbuf);
}
tptr = strcpy (gbuf, "STOP"); /* Start from a clean slate */
sim_rem_collect_cmd_setup (rem->line, &tptr);
rem->smp_sample_interval = cycles;
rem->smp_reg_count = 0;
while (cptr && *cptr) {
const char *comma = strchr (cptr, ',');
char tbuf[2*CBUFSIZE];
uint32 bit, width;
REG *reg;
int32 saved_switches = sim_switches;
t_bool indirect = FALSE;
BITSAMPLE_REG *smp_regs;
if (comma) {
strncpy (tbuf, cptr, comma - cptr);
tbuf[comma - cptr] = '\0';
cptr = comma + 1;
}
else {
strcpy (tbuf, cptr);
cptr += strlen (cptr);
}
tptr = tbuf;
if (strchr (tbuf, ' ')) {
sim_switches = 0;
tptr = get_sim_opt (CMD_OPT_SW|CMD_OPT_DFT, tbuf, &stat); /* get switches and device */
indirect = ((sim_switches & SWMASK('I')) != 0);
sim_switches = saved_switches;
}
if (stat != SCPE_OK)
break;
tptr = get_glyph (tptr, gbuf, 0); /* get next glyph */
reg = find_reg (gbuf, &tptr, sim_dfdev);
if (reg == NULL) {
stat = sim_messagef (SCPE_NXREG, "Nonexistent Register: %s\n", gbuf);
break;
}
smp_regs = (BITSAMPLE_REG *)realloc (rem->smp_regs, (rem->smp_reg_count + 1) * sizeof(*smp_regs));
if (smp_regs == NULL) {
stat = SCPE_MEM;
break;
}
rem->smp_regs = smp_regs;
smp_regs[rem->smp_reg_count].reg = reg;
smp_regs[rem->smp_reg_count].dptr = sim_dfdev;
smp_regs[rem->smp_reg_count].uptr = sim_dfunit;
smp_regs[rem->smp_reg_count].indirect = indirect;
width = indirect ? sim_dfdev->dwidth : reg->width;
smp_regs[rem->smp_reg_count].width = width;
smp_regs[rem->smp_reg_count].bits = (BITSAMPLE *)calloc (width, sizeof (*smp_regs[rem->smp_reg_count - 1].bits));
if (smp_regs[rem->smp_reg_count].bits == NULL) {
stat = SCPE_MEM;
break;
}
rem->smp_reg_count += 1;
for (bit = 0; bit < width; bit++) {
smp_regs[rem->smp_reg_count - 1].bits[bit].depth = samples;
smp_regs[rem->smp_reg_count - 1].bits[bit].vals = (int *)calloc (samples, sizeof (int));
if (smp_regs[rem->smp_reg_count - 1].bits[bit].vals == NULL) {
stat = SCPE_MEM;
break;
}
}
if (stat != SCPE_OK)
break;
}
if (stat != SCPE_OK) { /* Error? */
*iptr = cptr;
cptr = strcpy (gbuf, "STOP");
sim_rem_collect_cmd_setup (line, &cptr);/* Cleanup mess */
return stat;
}
sim_activate (&rem_con_smp_smpl_units[rem->line], rem->smp_sample_interval);
}
*iptr = cptr;
return stat;
}
t_stat sim_rem_con_repeat_svc (UNIT *uptr)
{
int line = uptr - rem_con_repeat_units;
REMOTE *rem = &sim_rem_consoles[line];
sim_debug (DBG_REP, &sim_remote_console, "sim_rem_con_repeat_svc(line=%d) - interval=%d\n", line, rem->repeat_interval);
if (rem->repeat_interval) {
rem->repeat_pending = TRUE;
sim_activate_after (uptr, rem->repeat_interval); /* reschedule */
sim_activate_abs (rem_con_data_unit, -1); /* wake up to process */
}
return SCPE_OK;
}
static void sim_rem_record_reg_bit (BITSAMPLE *bit, int val)
{
bit->tot -= bit->vals[bit->ptr]; /* remove retired value */
bit->tot += val; /* accumulate new value */
bit->vals[bit->ptr] = val; /* save new value */
++bit->ptr; /* increment next pointer */
if (bit->ptr >= bit->depth) /* if too big */
bit->ptr = 0; /* wrap around */
}
static void sim_rem_set_reg_bit (BITSAMPLE *bit, int val)
{
int i;
bit->tot = bit->depth * val; /* compute total */
for (i = 0; i < bit->depth; i++) /* set all value bits */
bit->vals[i] = val;
}
static void sim_rem_collect_reg_bits (BITSAMPLE_REG *reg)
{
uint32 i;
t_value val = get_rval (reg->reg, 0);
if (reg->indirect)
val = get_aval ((t_addr)val, reg->dptr, reg->uptr);
val = val >> reg->reg->offset;
for (i = 0; i < reg->width; i++) {
if (sim_is_running)
sim_rem_record_reg_bit (&reg->bits[i], val&1);
else
sim_rem_set_reg_bit (&reg->bits[i], val&1);
val = val >> 1;
}
}
static void sim_rem_collect_registers (REMOTE *rem)
{
uint32 i;
for (i = 0; i < rem->smp_reg_count; i++)
sim_rem_collect_reg_bits (&rem->smp_regs[i]);
}
static void sim_rem_collect_all_registers (void)
{
int32 line;
for (line = 0; line < sim_rem_con_tmxr.lines; line++)
sim_rem_collect_registers (&sim_rem_consoles[line]);
}
t_stat sim_rem_con_smp_collect_svc (UNIT *uptr)
{
int line = uptr - rem_con_smp_smpl_units;
REMOTE *rem = &sim_rem_consoles[line];
sim_debug (DBG_SAM, &sim_remote_console, "sim_rem_con_smp_collect_svc(line=%d) - interval=%d\n", line, rem->smp_sample_interval);
if (rem->smp_sample_interval && (rem->smp_reg_count != 0)) {
sim_rem_collect_registers (rem);
sim_activate (uptr, rem->smp_sample_interval); /* reschedule */
}
return SCPE_OK;
}
/* Unit service for remote console data polling */
t_stat sim_rem_con_data_svc (UNIT *uptr)
@ -969,7 +1281,11 @@ for (i=(was_active_command ? sim_rem_cmd_active_line : 0);
if (!lp->conn) {
if (rem->repeat_interval) { /* was repeated enabled? */
cptr = strcpy (gbuf, "STOP");
_rem_repeat_cmd_setup (i, &cptr); /* make sure it is now disabled */
sim_rem_repeat_cmd_setup (i, &cptr); /* make sure it is now disabled */
}
if (rem->smp_reg_count) { /* were bit samples being collected? */
cptr = strcpy (gbuf, "STOP");
sim_rem_collect_cmd_setup (i, &cptr); /* make sure it is now disabled */
}
continue;
}
@ -996,6 +1312,7 @@ for (i=(was_active_command ? sim_rem_cmd_active_line : 0);
}
else {
sim_is_running = 0;
sim_rem_collect_all_registers ();
sim_stop_timer_services ();
for (j=0; j < sim_rem_con_tmxr.lines; j++) {
TMLN *lpj = &sim_rem_con_tmxr.ldsc[j];
@ -1016,6 +1333,7 @@ for (i=(was_active_command ? sim_rem_cmd_active_line : 0);
if (c == sim_int_char) { /* ^E (the interrupt character) must start continue mode console interaction */
rem->single_mode = FALSE; /* enter multi command mode */
sim_is_running = 0;
sim_rem_collect_all_registers ();
sim_stop_timer_services ();
stat = SCPE_STOP;
_sim_rem_message ("RUN", stat);
@ -1254,7 +1572,7 @@ for (i=(was_active_command ? sim_rem_cmd_active_line : 0);
}
else {
if ((cmdp = find_ctab (rem->single_mode ? allowed_single_remote_cmds : (master_session ? allowed_master_remote_cmds : allowed_remote_cmds), gbuf))) {/* lookup command */
sim_debug (DBG_CMD, &sim_remote_console, "gbuf='%s', basecmd='%s', cmd='%s', action=%p, continue_cmd=%p, repeat_cmd=%p\n", gbuf, basecmdp->name, cmdp->name, cmdp->action, &x_continue_cmd, &x_repeat_cmd);
sim_debug (DBG_CMD, &sim_remote_console, "gbuf='%s', basecmd='%s', cmd='%s'\n", gbuf, basecmdp->name, cmdp->name);
if (cmdp->action == &x_continue_cmd) {
sim_debug (DBG_CMD, &sim_remote_console, "continue_cmd executing\n");
stat = SCPE_OK;
@ -1294,21 +1612,34 @@ for (i=(was_active_command ? sim_rem_cmd_active_line : 0);
}
}
else {
if (cmdp->action == &x_repeat_cmd) {
sim_debug (DBG_CMD, &sim_remote_console, "repeat_cmd executing\n");
stat = _rem_repeat_cmd_setup (i, &cptr);
if (cmdp->action == &x_sampleout_cmd) {
sim_debug (DBG_CMD, &sim_remote_console, "sampleout_cmd executing\n");
sim_oline = lp; /* specify output socket */
stat = sim_rem_sample_output (NULL, i);
}
else {
if (sim_con_stable_registers &&
sim_rem_master_mode) { /* can we process command now? */
sim_debug (DBG_CMD, &sim_remote_console, "Processing Command directly\n");
sim_oline = lp; /* specify output socket */
sim_remote_process_command ();
stat = SCPE_OK; /* any message has already been emitted */
if (cmdp->action == &x_repeat_cmd) {
sim_debug (DBG_CMD, &sim_remote_console, "repeat_cmd executing\n");
stat = sim_rem_repeat_cmd_setup (i, &cptr);
}
else {
sim_debug (DBG_CMD, &sim_remote_console, "Processing Command via SCPE_REMOTE\n");
stat = SCPE_REMOTE; /* force processing outside of sim_instr() */
if (cmdp->action == &x_collect_cmd) {
sim_debug (DBG_CMD, &sim_remote_console, "sample_cmd executing\n");
stat = sim_rem_collect_cmd_setup (i, &cptr);
}
else {
if (sim_con_stable_registers &&
sim_rem_master_mode) { /* can we process command now? */
sim_debug (DBG_CMD, &sim_remote_console, "Processing Command directly\n");
sim_oline = lp; /* specify output socket */
sim_remote_process_command ();
stat = SCPE_OK; /* any message has already been emitted */
}
else {
sim_debug (DBG_CMD, &sim_remote_console, "Processing Command via SCPE_REMOTE\n");
stat = SCPE_REMOTE; /* force processing outside of sim_instr() */
}
}
}
}
}
@ -1402,20 +1733,6 @@ else
return SCPE_OK; /* keep going */
}
t_stat sim_rem_con_repeat_svc (UNIT *uptr)
{
int line = uptr - rem_con_repeat_units;
REMOTE *rem = &sim_rem_consoles[line];
sim_debug (DBG_REP, &sim_remote_console, "sim_rem_con_repeat_svc(line=%d) - interval=%d\n", line, rem->repeat_interval);
if (rem->repeat_interval) {
rem->repeat_pending = TRUE;
sim_activate_after (uptr, rem->repeat_interval); /* reschedule */
sim_activate_abs (rem_con_data_unit, -1); /* wake up to process */
}
return SCPE_OK;
}
t_stat sim_rem_con_reset (DEVICE *dptr)
{
if (sim_rem_con_tmxr.lines) {
@ -1429,7 +1746,9 @@ if (sim_rem_con_tmxr.lines) {
continue;
sim_debug (DBG_REP, &sim_remote_console, "sim_rem_con_reset(line=%d, usecs=%d)\n", i, rem->repeat_interval);
if (rem->repeat_interval)
sim_activate_after (rem_con_repeat_units + i, rem->repeat_interval);/* schedule */
sim_activate_after (&rem_con_repeat_units[rem->line], rem->repeat_interval); /* schedule */
if (rem->smp_reg_count)
sim_activate (&rem_con_smp_smpl_units[rem->line], rem->smp_sample_interval); /* schedule */
}
if (i != sim_rem_con_tmxr.lines)
sim_activate_after (rem_con_data_unit, 100000); /* continue polling for open sessions */
@ -1501,13 +1820,14 @@ for (i=0; i<sim_rem_con_tmxr.lines; i++) {
free (rem->act);
free (rem->repeat_action);
sim_cancel (&rem_con_repeat_units[i]);
sim_cancel (&rem_con_smp_smpl_units[i]);
}
sim_rem_con_tmxr.lines = lines;
sim_rem_con_tmxr.ldsc = (TMLN *)realloc (sim_rem_con_tmxr.ldsc, sizeof(*sim_rem_con_tmxr.ldsc)*lines);
memset (sim_rem_con_tmxr.ldsc, 0, sizeof(*sim_rem_con_tmxr.ldsc)*lines);
sim_remote_console.units = (UNIT *)realloc (sim_remote_console.units, sizeof(*sim_remote_console.units)*(lines + REM_CON_BASE_UNITS));
memset (sim_remote_console.units, 0, sizeof(*sim_remote_console.units)*(lines + REM_CON_BASE_UNITS));
sim_remote_console.numunits = lines + REM_CON_BASE_UNITS;
sim_remote_console.units = (UNIT *)realloc (sim_remote_console.units, sizeof(*sim_remote_console.units)*((2 * lines) + REM_CON_BASE_UNITS));
memset (sim_remote_console.units, 0, sizeof(*sim_remote_console.units)*((2 * lines) + REM_CON_BASE_UNITS));
sim_remote_console.numunits = (2 * lines) + REM_CON_BASE_UNITS;
rem_con_poll_unit->action = &sim_rem_con_poll_svc;/* remote console connection polling unit */
rem_con_poll_unit->flags |= UNIT_IDLE;
rem_con_data_unit->action = &sim_rem_con_data_svc;/* console data handling unit */
@ -1519,6 +1839,8 @@ memset (sim_rem_command_buf, 0, 4*CBUFSIZE+1);
for (i=0; i<lines; i++) {
rem_con_repeat_units[i].flags = UNIT_DIS;
rem_con_repeat_units[i].action = &sim_rem_con_repeat_svc;
rem_con_smp_smpl_units[i].flags = UNIT_DIS;
rem_con_smp_smpl_units[i].action = &sim_rem_con_smp_collect_svc;
rem = &sim_rem_consoles[i];
rem->line = i;
rem->lp = &sim_rem_con_tmxr.ldsc[i];

View file

@ -119,6 +119,8 @@ typedef struct {
size_t size;
int indirect;
size_t element_count;
int *bits;
size_t bit_count;
} REG;
struct PANEL {
@ -158,6 +160,8 @@ struct PANEL {
int callback_thread_running;
void *callback_context;
int usecs_between_callbacks;
unsigned int sample_frequency;
unsigned int sample_depth;
int debug;
char *simulator_version;
int radix;
@ -175,6 +179,10 @@ static const char *register_repeat_stop = "repeat stop";
static const char *register_repeat_stop_all = "repeat stop all";
static const char *register_repeat_units = " usecs ";
static const char *register_get_prefix = "show time";
static const char *register_collect_prefix = "collect ";
static const char *register_collect_mid1 = " samples every ";
static const char *register_collect_mid2 = " cycles ";
static const char *register_get_postfix = "sampleout";
static const char *register_get_echo = "# REGISTERS-DONE";
static const char *register_repeat_echo = "# REGISTERS-REPEAT-DONE";
static const char *register_dev_echo = "# REGISTERS-FOR-DEVICE:";
@ -374,18 +382,25 @@ _panel_sendf (PANEL *p, int *completion_status, char **response, const char *fmt
static int
_panel_register_query_string (PANEL *panel, char **buf, size_t *buf_size)
{
size_t i, j, buf_data, buf_needed = 0;
size_t i, j, buf_data, buf_needed = 0, reg_count = 0, bit_reg_count = 0;
const char *dev;
pthread_mutex_lock (&panel->io_lock);
buf_needed = 2 + strlen (register_get_prefix); /* SHOW TIME */
for (i=0; i<panel->reg_count; i++) {
buf_needed += 9 + strlen (panel->regs[i].name) + (panel->regs[i].device_name ? strlen (panel->regs[i].device_name) : 0);
if (panel->regs[i].element_count > 0)
buf_needed += 4 + 6 /* 6 digit register array index */;
if (panel->regs[i].indirect)
buf_needed += 12 + strlen (register_ind_echo) + strlen (panel->regs[i].name);
if (panel->regs[i].bits)
++bit_reg_count;
else {
++reg_count;
buf_needed += 9 + strlen (panel->regs[i].name) + (panel->regs[i].device_name ? strlen (panel->regs[i].device_name) : 0);
if (panel->regs[i].element_count > 0)
buf_needed += 4 + 6 /* 6 digit register array index */;
if (panel->regs[i].indirect)
buf_needed += 12 + strlen (register_ind_echo) + strlen (panel->regs[i].name);
}
}
if (bit_reg_count)
buf_needed += 2 + strlen (register_get_postfix);
buf_needed += 10 + strlen (register_get_echo); /* # REGISTERS-DONE */
if (buf_needed > *buf_size) {
free (*buf);
@ -398,13 +413,15 @@ if (buf_needed > *buf_size) {
*buf_size = buf_needed;
}
buf_data = 0;
sprintf (*buf + buf_data, "%s\r", register_get_prefix);
buf_data += strlen (*buf + buf_data);
if (reg_count) {
sprintf (*buf + buf_data, "%s\r", register_get_prefix);
buf_data += strlen (*buf + buf_data);
}
dev = "";
for (i=j=0; i<panel->reg_count; i++) {
const char *reg_dev = panel->regs[i].device_name ? panel->regs[i].device_name : "";
if (panel->regs[i].indirect)
if ((panel->regs[i].indirect) || (panel->regs[i].bits))
continue;
if (strcmp (dev, reg_dev)) {/* devices are different */
char *tbuf;
@ -447,11 +464,17 @@ if (buf_data && ((*buf)[buf_data-1] != '\r')) {
for (i=j=0; i<panel->reg_count; i++) {
const char *reg_dev = panel->regs[i].device_name ? panel->regs[i].device_name : "";
if (!panel->regs[i].indirect)
if ((!panel->regs[i].indirect) || (panel->regs[i].bits))
continue;
sprintf (*buf + buf_data, "%s%s\rE -H %s %s,$\r", register_ind_echo, panel->regs[i].name, reg_dev, panel->regs[i].name);
buf_data += strlen (*buf + buf_data);
}
if (bit_reg_count) {
strcpy (*buf + buf_data, register_get_postfix);
buf_data += strlen (*buf + buf_data);
strcpy (*buf + buf_data, "\r");
buf_data += strlen (*buf + buf_data);
}
strcpy (*buf + buf_data, register_get_echo);
buf_data += strlen (*buf + buf_data);
strcpy (*buf + buf_data, "\r");
@ -461,6 +484,53 @@ pthread_mutex_unlock (&panel->io_lock);
return 0;
}
static int
_panel_establish_register_bits_collection (PANEL *panel)
{
size_t i, buf_data, buf_needed = 0, reg_count = 0, bit_reg_count = 0;
int cmd_stat, bits_count = 0;
char *buf, *response = NULL;
pthread_mutex_lock (&panel->io_lock);
for (i=0; i<panel->reg_count; i++) {
if (panel->regs[i].bits)
buf_needed += 9 + strlen (panel->regs[i].name) + (panel->regs[i].device_name ? strlen (panel->regs[i].device_name) : 0);
}
buf = (char *)_panel_malloc (buf_needed);
if (!buf) {
panel->State = Error;
pthread_mutex_unlock (&panel->io_lock);
return -1;
}
*buf = '\0';
buf_data = 0;
for (i=0; i<panel->reg_count; i++) {
if (panel->regs[i].bits) {
++bits_count;
sprintf (buf + buf_data, "%s%s", (bits_count != 1) ? "," : "", panel->regs[i].indirect ? "-I " : "");
buf_data += strlen (buf + buf_data);
if (panel->regs[i].device_name) {
sprintf (buf + buf_data, "%s ", panel->regs[i].device_name);
buf_data += strlen (buf + buf_data);
}
sprintf (buf + buf_data, "%s", panel->regs[i].name);
buf_data += strlen (buf + buf_data);
}
}
pthread_mutex_unlock (&panel->io_lock);
if (_panel_sendf (panel, &cmd_stat, &response, "%s%u%s%u%s%s\r", register_collect_prefix, panel->sample_depth,
register_collect_mid1, panel->sample_frequency,
register_collect_mid2, buf)) {
sim_panel_set_error ("Error establishing bit data collection:%s", response);
free (response);
free (buf);
return -1;
}
free (response);
free (buf);
return 0;
}
static PANEL **panels = NULL;
static int panel_count = 0;
@ -927,7 +997,9 @@ _panel_add_register (PANEL *panel,
size_t size,
void *addr,
int indirect,
size_t element_count)
size_t element_count,
int *bits,
size_t bit_count)
{
REG *regs, *reg;
char *response = NULL;
@ -942,6 +1014,10 @@ if (panel->State == Run) {
sim_panel_set_error ("Not Halted");
return -1;
}
if ((bit_count != 0) && (panel->sample_depth == 0)) {
sim_panel_set_error ("sim_panel_set_sampling_parameters() must be called first");
return -1;
}
regs = (REG *)_panel_malloc ((1 + panel->reg_count)*sizeof(*regs));
if (regs == NULL) {
panel->State = Error;
@ -959,6 +1035,11 @@ if (reg->name == NULL) {
}
strcpy (reg->name, name);
reg->indirect = indirect;
reg->addr = addr;
reg->size = size;
reg->element_count = element_count;
reg->bits = bits;
reg->bit_count = bit_count;
for (i=0; i<strlen (reg->name); i++) {
if (islower (reg->name[i]))
reg->name[i] = toupper (reg->name[i]);
@ -992,7 +1073,9 @@ for (i=0; i<panel->reg_count; i++) {
}
sprintf (t1, "%s %s", regs[i].device_name ? regs[i].device_name : "", regs[i].name);
sprintf (t2, "%s %s", reg->device_name ? reg->device_name : "", reg->name);
if ((!strcmp (t1, t2)) && (reg->indirect == regs[i].indirect)) {
if ((!strcmp (t1, t2)) &&
(reg->indirect == regs[i].indirect) &&
((reg->bits == NULL) == (regs[i].bits == NULL))) {
sim_panel_set_error ("Duplicate Register Declaration");
free (t1);
free (t2);
@ -1004,9 +1087,6 @@ for (i=0; i<panel->reg_count; i++) {
free (t1);
free (t2);
}
reg->addr = addr;
reg->size = size;
reg->element_count = element_count;
pthread_mutex_unlock (&panel->io_lock);
/* Validate existence of requested register/array */
if (_panel_sendf (panel, &cmd_stat, &response, "EXAMINE %s %s%s\r", device_name? device_name : "", name, (element_count > 0) ? "[0]" : "")) {
@ -1050,6 +1130,11 @@ pthread_mutex_unlock (&panel->io_lock);
/* Now build the register query string for the whole register list */
if (_panel_register_query_string (panel, &panel->reg_query, &panel->reg_query_size))
return -1;
if (bits) {
memset (bits, 0, sizeof (*bits) * bit_count);
if (_panel_establish_register_bits_collection (panel))
return -1;
}
return 0;
}
@ -1060,7 +1145,17 @@ sim_panel_add_register (PANEL *panel,
size_t size,
void *addr)
{
return _panel_add_register (panel, name, device_name, size, addr, 0, 0);
return _panel_add_register (panel, name, device_name, size, addr, 0, 0, NULL, 0);
}
int
sim_panel_add_register_bits (PANEL *panel,
const char *name,
const char *device_name,
size_t bit_width,
int *bits)
{
return _panel_add_register (panel, name, device_name, 0, NULL, 0, 0, bits, bit_width);
}
int
@ -1071,7 +1166,7 @@ sim_panel_add_register_array (PANEL *panel,
size_t size,
void *addr)
{
return _panel_add_register (panel, name, device_name, size, addr, 0, element_count);
return _panel_add_register (panel, name, device_name, size, addr, 0, element_count, NULL, 0);
}
@ -1082,7 +1177,17 @@ sim_panel_add_register_indirect (PANEL *panel,
size_t size,
void *addr)
{
return _panel_add_register (panel, name, device_name, size, addr, 1, 0);
return _panel_add_register (panel, name, device_name, size, addr, 1, 0, NULL, 0);
}
int
sim_panel_add_register_indirect_bits (PANEL *panel,
const char *name,
const char *device_name,
size_t bit_width,
int *bits)
{
return _panel_add_register (panel, name, device_name, 0, NULL, 1, 0, bits, bit_width);
}
static int
@ -1165,6 +1270,24 @@ pthread_mutex_unlock (&panel->io_lock);
return 0;
}
int
sim_panel_set_sampling_parameters (PANEL *panel,
unsigned int sample_frequency,
unsigned int sample_depth)
{
if (sample_frequency == 0) {
sim_panel_set_error ("Invalid sample frequency value: %u", sample_frequency);
return -1;
}
if (sample_depth == 0) {
sim_panel_set_error ("Invalid sample depth value: %u", sample_depth);
return -1;
}
panel->sample_frequency = sample_frequency;
panel->sample_depth = sample_depth;
return 0;
}
int
sim_panel_exec_halt (PANEL *panel)
{
@ -1760,6 +1883,8 @@ while ((p->sock != INVALID_SOCKET) &&
e = strchr (s, ':');
if (e) {
size_t i;
char smp_dev[32], smp_reg[32], smp_ind[32];
unsigned int bit;
*e++ = '\0';
if (!strcmp("Time", s)) {
@ -1769,6 +1894,33 @@ while ((p->sock != INVALID_SOCKET) &&
++s;
continue;
}
if ((*s == '}') &&
(3 == sscanf (s, "}%s %s %s", smp_dev, smp_reg, smp_ind))) { /* Register bit Sample Data? */
r = NULL;
for (i=0; i<p->reg_count; i++) {
if (p->regs[i].bits == NULL)
continue;
if ((!strcmp (smp_reg, p->regs[i].name)) &&
((!p->device_name) || (!strcmp (smp_dev, p->device_name)))) {
r = &p->regs[i];
break;
}
}
if (r) {
for (bit = 0; bit < r->bit_count; bit++) {
int val = (int)strtol (e, &e, 10);
r->bits[bit] = val;
if (*e == ',')
++e;
else
break;
}
s = eol;
}
while (isspace(0xFF & (*s)))
++s;
continue;
}
if (!strncmp (s + strlen (sim_prompt), register_ind_echo, strlen (register_ind_echo) - 1)) {
e = s + strlen (sim_prompt) + strlen (register_ind_echo);
r = NULL;

View file

@ -43,7 +43,6 @@
into the application.
4) Use a simh simulator built from the same version of simh that the
sim_frontpanel and sim_sock modules came from.
*/
#ifndef SIM_FRONTPANEL_H_
@ -57,7 +56,7 @@ extern "C" {
#if !defined(__VAX) /* Unsupported platform */
#define SIM_FRONTPANEL_VERSION 3
#define SIM_FRONTPANEL_VERSION 4
/**
@ -78,7 +77,6 @@ extern "C" {
Note 2: - Configuration file specified should contain device setup
statements (enable, disable, CPU types and attach commands).
It should not start a simulator running.
*/
typedef struct PANEL PANEL;
@ -101,8 +99,8 @@ sim_panel_start_simulator_debug (const char *sim_path,
simulator_panel the simulator panel to connect to
device_name the simulator's name for the device
*/
PANEL *
sim_panel_add_device_panel (PANEL *simulator_panel,
const char *device_name);
@ -113,8 +111,8 @@ sim_panel_add_device_panel (PANEL *simulator_panel,
Note: destroying a simulator panel will also destroy any
related sub panels
*/
int
sim_panel_destroy (PANEL *panel);
@ -128,12 +126,14 @@ sim_panel_destroy (PANEL *panel);
simulator.
The registers that a particular frontpanel application mught need
access to are described by the application when it calls:
access to are specified by the application when it calls:
sim_panel_add_register
sim_panel_add_register_bits
sim_panel_add_register_array
and
sim_panel_add_register_indirect
sim_panel_add_register_indirect_bits
name the name the simulator knows this register by
device_name the device this register is part of. Defaults to
@ -144,8 +144,14 @@ and
receive the data in the simulator's register
addr a pointer to the location of the buffer which will
be loaded with the data in the simulator's register
bit_width the number of values to populate in the bits array
bits an array of integers which is bit_width long that
will receive each bit's current accumulated value.
The accumulated value will range from 0 thru the
the sample_depth specified when calling
sim_panel_set_sampling_parameters().
*/
int
sim_panel_add_register (PANEL *panel,
const char *name,
@ -153,6 +159,13 @@ sim_panel_add_register (PANEL *panel,
size_t size,
void *addr);
int
sim_panel_add_register_bits (PANEL *panel,
const char *name,
const char *device_name,
size_t bit_width,
int *bits);
int
sim_panel_add_register_array (PANEL *panel,
const char *name,
@ -167,11 +180,19 @@ sim_panel_add_register_indirect (PANEL *panel,
const char *device_name,
size_t size,
void *addr);
int
sim_panel_add_register_indirect_bits (PANEL *panel,
const char *name,
const char *device_name,
size_t bit_width,
int *bits);
/**
A panel application has a choice of two different methods of getting
the values contained in the set of registers it has declared interest in via
the sim_panel_add_register API.
the sim_panel_add_register APIs.
1) The values can be polled (when ever it is desired) by calling
sim_panel_get_registers().
@ -189,15 +210,11 @@ sim_panel_add_register_indirect (PANEL *panel,
or frontpanel interactions with the simulator may be disrupted.
Setting a flag, signaling an event or posting a message are
reasonable activities to perform in a callback routine.
*/
int
sim_panel_get_registers (PANEL *panel, unsigned long long *simulation_time);
/**
*/
typedef void (*PANEL_DISPLAY_PCALLBACK)(PANEL *panel,
unsigned long long simulation_time,
void *context);
@ -208,6 +225,26 @@ sim_panel_set_display_callback_interval (PANEL *panel,
void *context,
int usecs_between_callbacks);
/**
When a front panel application wants to get averaged bit sample
values, it must first declare the sampling parameters that will
be used while collecting the bit values.
sim_panel_set_sampling_parameters
sample_frequency cycles/instructions between sample captures
sample_depth how many samples to accumulate in the rolling
average for each bit sample. Returned bit
sample values will range from 0 thru this
value.
*/
int
sim_panel_set_sampling_parameters (PANEL *panel,
unsigned int sample_frequency,
unsigned int sample_depth);
/**
When a front panel application needs to change the running
@ -218,8 +255,8 @@ sim_panel_set_display_callback_interval (PANEL *panel,
sim_panel_exec_boot - Boot a simulator from a specific device
sim_panel_exec_run - Start/Resume a simulator running instructions
sim_panel_exec_step - Have a simulator execute a single step
*/
int
sim_panel_exec_halt (PANEL *panel);
@ -249,7 +286,6 @@ sim_panel_exec_step (PANEL *panel);
Note: Any breakpoint switches/flags must be located at the
beginning of the condition string
*/
int
@ -277,7 +313,6 @@ sim_panel_break_output_clear (PANEL *panel, const char *condition);
sim_panel_mem_deposit - Deposit to memory location
sim_panel_set_register_value - Deposit to a register or memory
location
*/
@ -359,6 +394,7 @@ sim_panel_mem_deposit (PANEL *panel,
const void *value);
/**
sim_panel_set_register_value
name the name of a simulator register or a memory address
@ -366,7 +402,6 @@ sim_panel_mem_deposit (PANEL *panel,
value the new value in character string form. The string
must be in the native/natural radix that the simulator
uses when referencing that register
*/
int
sim_panel_set_register_value (PANEL *panel,
@ -375,24 +410,24 @@ sim_panel_set_register_value (PANEL *panel,
/**
When a front panel application may needs to change the media
When a front panel application needs to change the media
in a simulated removable media device one of the following
routines should be called:
sim_panel_mount - mounts the indicated media file on a device
sim_panel_dismount - dismounts the currently mounted media file
from a device
*/
/**
sim_panel_mount
device the name of a simulator device/unit
switches any switches appropriate for the desire attach
path the path on the local system to be attached
*/
int
sim_panel_mount (PANEL *panel,
const char *device,
@ -400,11 +435,12 @@ sim_panel_mount (PANEL *panel,
const char *path);
/**
sim_panel_dismount
device the name of a simulator device/unit
*/
int
sim_panel_dismount (PANEL *panel,
const char *device);
@ -430,7 +466,6 @@ sim_panel_get_state (PANEL *panel);
sim_panel_get_error - the details of the most recent error
sim_panel_clear_error - clears the error buffer
*/
const char *sim_panel_get_error (void);