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 PC, SP, FP, AP, PSL, R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, atPC;
unsigned int PCQ[32]; unsigned int PCQ[32];
int PSL_bits[32];
int PC_bits[32];
int PC_indirect_bits[32];
int update_display = 1; int update_display = 1;
static void 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()); printf ("Unexpected error establishing an output breakpoint: %s\n", sim_panel_get_error());
goto Done; 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 (); sim_panel_clear_error ();
while (1) { while (1) {
size_t i; 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); C1TAB *find_c1tab (C1TAB *tab, const char *gbuf);
SHTAB *find_shtab (SHTAB *tab, const char *gbuf); SHTAB *find_shtab (SHTAB *tab, const char *gbuf);
t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr); 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); BRKTAB *sim_brk_fnd (t_addr loc);
uint32 sim_brk_test (t_addr bloc, uint32 btyp); uint32 sim_brk_test (t_addr bloc, uint32 btyp);
void sim_brk_clrspc (uint32 spc, uint32 btyp); void sim_brk_clrspc (uint32 spc, uint32 btyp);
@ -264,6 +265,8 @@ t_stat scp_vhelpFromFile (FILE *st, DEVICE *dptr,
/* Global data */ /* Global data */
extern DEVICE *sim_dflt_dev; extern DEVICE *sim_dflt_dev;
extern DEVICE *sim_dfdev;
extern UNIT *sim_dfunit;
extern int32 sim_interval; extern int32 sim_interval;
extern int32 sim_switches; extern int32 sim_switches;
extern int32 sim_quiet; 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_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_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_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 */ 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_poll_unit (&sim_remote_console.units[0])
#define rem_con_data_unit (&sim_remote_console.units[1]) #define rem_con_data_unit (&sim_remote_console.units[1])
#define REM_CON_BASE_UNITS 2 #define REM_CON_BASE_UNITS 2
#define rem_con_repeat_units (&sim_remote_console.units[REM_CON_BASE_UNITS]) #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_MOD 0x00000004 /* Remote Console Mode activities */
#define DBG_REP 0x00000008 /* Remote Console Repeat 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[] = { DEBTAB sim_rem_con_debug[] = {
{"TRC", DBG_TRC, "routine calls"}, {"TRC", DBG_TRC, "routine calls"},
@ -445,6 +449,7 @@ DEBTAB sim_rem_con_debug[] = {
{"CMD", DBG_CMD, "Remote Console Command activity"}, {"CMD", DBG_CMD, "Remote Console Command activity"},
{"MODE", DBG_MOD, "Remote Console Mode activity"}, {"MODE", DBG_MOD, "Remote Console Mode activity"},
{"REPEAT", DBG_REP, "Remote Console Repeat activity"}, {"REPEAT", DBG_REP, "Remote Console Repeat activity"},
{"SAMPLE", DBG_SAM, "Remote Console Sample activity"},
{0} {0}
}; };
@ -464,6 +469,22 @@ DEVICE sim_remote_console = {
NULL, DEV_DEBUG | DEV_NOSAVE, 0, sim_rem_con_debug, NULL, DEV_DEBUG | DEV_NOSAVE, 0, sim_rem_con_debug,
NULL, NULL, NULL, NULL, NULL, sim_rem_con_description}; 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; typedef struct REMOTE REMOTE;
struct REMOTE { struct REMOTE {
int32 buf_size; int32 buf_size;
@ -474,16 +495,18 @@ struct REMOTE {
char *act; char *act;
t_bool single_mode; t_bool single_mode;
uint32 read_timeout; uint32 read_timeout;
int line; int line; /* remote console line number */
TMLN *lp; TMLN *lp; /* mux line/socket for remote session */
UNIT *uptr; UNIT *uptr; /* remote console unit */
uint32 repeat_interval; uint32 repeat_interval; /* usecs between repeat execution */
t_bool repeat_pending; t_bool repeat_pending; /* repeat delivery pending */
char *repeat_action; 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; REMOTE *sim_rem_consoles = NULL;
static TMXR sim_rem_con_tmxr = { 0, 0, 0, NULL, NULL, &sim_remote_console };/* remote console line mux */ 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_timeout = 30; /* seconds before automatic continue */
static uint32 *sim_rem_read_timeouts = NULL;/* per line read timeout (default from sim_rem_read_timeout) */ 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_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_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 */ /* 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, "The Command: %s\n", rem->repeat_action);
fprintf (st, " is repeated every %s\n", sim_fmt_secs (rem->repeat_interval / 1000000.0)); 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; 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 */ 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 */ 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 */ 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 t_stat x_help_cmd (int32 flag, CONST char *cptr);
static CTAB allowed_remote_cmds[] = { static CTAB allowed_remote_cmds[] = {
@ -642,6 +713,8 @@ static CTAB allowed_remote_cmds[] = {
{ "DEASSIGN", &deassign_cmd, 0 }, { "DEASSIGN", &deassign_cmd, 0 },
{ "CONTINUE", &x_continue_cmd, 0 }, { "CONTINUE", &x_continue_cmd, 0 },
{ "REPEAT", &x_repeat_cmd, 0 }, { "REPEAT", &x_repeat_cmd, 0 },
{ "COLLECT", &x_collect_cmd, 0 },
{ "SAMPLEOUT",&x_sampleout_cmd, 0 },
{ "STEP", &x_step_cmd, 0 }, { "STEP", &x_step_cmd, 0 },
{ "PWD", &pwd_cmd, 0 }, { "PWD", &pwd_cmd, 0 },
{ "SAVE", &save_cmd, 0 }, { "SAVE", &save_cmd, 0 },
@ -664,6 +737,8 @@ static CTAB allowed_master_remote_cmds[] = {
{ "DEASSIGN", &deassign_cmd, 0 }, { "DEASSIGN", &deassign_cmd, 0 },
{ "CONTINUE", &x_continue_cmd, 0 }, { "CONTINUE", &x_continue_cmd, 0 },
{ "REPEAT", &x_repeat_cmd, 0 }, { "REPEAT", &x_repeat_cmd, 0 },
{ "COLLECT", &x_collect_cmd, 0 },
{ "SAMPLEOUT",&x_sampleout_cmd, 0 },
{ "STEP", &x_step_cmd, 0 }, { "STEP", &x_step_cmd, 0 },
{ "PWD", &pwd_cmd, 0 }, { "PWD", &pwd_cmd, 0 },
{ "SAVE", &save_cmd, 0 }, { "SAVE", &save_cmd, 0 },
@ -693,6 +768,8 @@ static CTAB allowed_single_remote_cmds[] = {
{ "EXAMINE", &exdep_cmd, EX_E }, { "EXAMINE", &exdep_cmd, EX_E },
{ "EVALUATE", &eval_cmd, 0 }, { "EVALUATE", &eval_cmd, 0 },
{ "REPEAT", &x_repeat_cmd, 0 }, { "REPEAT", &x_repeat_cmd, 0 },
{ "COLLECT", &x_collect_cmd, 0 },
{ "SAMPLEOUT",&x_sampleout_cmd, 0 },
{ "PWD", &pwd_cmd, 0 }, { "PWD", &pwd_cmd, 0 },
{ "DIR", &dir_cmd, 0 }, { "DIR", &dir_cmd, 0 },
{ "LS", &dir_cmd, 0 }, { "LS", &dir_cmd, 0 },
@ -704,6 +781,8 @@ static CTAB allowed_single_remote_cmds[] = {
static CTAB remote_only_cmds[] = { static CTAB remote_only_cmds[] = {
{ "REPEAT", &x_repeat_cmd, 0 }, { "REPEAT", &x_repeat_cmd, 0 },
{ "COLLECT", &x_collect_cmd, 0 },
{ "SAMPLEOUT",&x_sampleout_cmd, 0 },
{ NULL, NULL } { NULL, NULL }
}; };
@ -864,7 +943,7 @@ return buf;
Parse and setup Remote Console REPEAT command: Parse and setup Remote Console REPEAT command:
REPEAT EVERY nnn USECS Command {; 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]; char gbuf[CBUFSIZE];
int32 val; int32 val;
@ -940,6 +1019,239 @@ if (stat == SCPE_OK) {
return stat; 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 */ /* Unit service for remote console data polling */
t_stat sim_rem_con_data_svc (UNIT *uptr) 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 (!lp->conn) {
if (rem->repeat_interval) { /* was repeated enabled? */ if (rem->repeat_interval) { /* was repeated enabled? */
cptr = strcpy (gbuf, "STOP"); 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; continue;
} }
@ -996,6 +1312,7 @@ for (i=(was_active_command ? sim_rem_cmd_active_line : 0);
} }
else { else {
sim_is_running = 0; sim_is_running = 0;
sim_rem_collect_all_registers ();
sim_stop_timer_services (); sim_stop_timer_services ();
for (j=0; j < sim_rem_con_tmxr.lines; j++) { for (j=0; j < sim_rem_con_tmxr.lines; j++) {
TMLN *lpj = &sim_rem_con_tmxr.ldsc[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 */ if (c == sim_int_char) { /* ^E (the interrupt character) must start continue mode console interaction */
rem->single_mode = FALSE; /* enter multi command mode */ rem->single_mode = FALSE; /* enter multi command mode */
sim_is_running = 0; sim_is_running = 0;
sim_rem_collect_all_registers ();
sim_stop_timer_services (); sim_stop_timer_services ();
stat = SCPE_STOP; stat = SCPE_STOP;
_sim_rem_message ("RUN", stat); _sim_rem_message ("RUN", stat);
@ -1254,7 +1572,7 @@ for (i=(was_active_command ? sim_rem_cmd_active_line : 0);
} }
else { else {
if ((cmdp = find_ctab (rem->single_mode ? allowed_single_remote_cmds : (master_session ? allowed_master_remote_cmds : allowed_remote_cmds), gbuf))) {/* lookup command */ 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) { if (cmdp->action == &x_continue_cmd) {
sim_debug (DBG_CMD, &sim_remote_console, "continue_cmd executing\n"); sim_debug (DBG_CMD, &sim_remote_console, "continue_cmd executing\n");
stat = SCPE_OK; stat = SCPE_OK;
@ -1293,10 +1611,21 @@ for (i=(was_active_command ? sim_rem_cmd_active_line : 0);
cmdp = find_ctab (allowed_master_remote_cmds, "CONTINUE"); cmdp = find_ctab (allowed_master_remote_cmds, "CONTINUE");
} }
} }
else {
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 { else {
if (cmdp->action == &x_repeat_cmd) { if (cmdp->action == &x_repeat_cmd) {
sim_debug (DBG_CMD, &sim_remote_console, "repeat_cmd executing\n"); sim_debug (DBG_CMD, &sim_remote_console, "repeat_cmd executing\n");
stat = _rem_repeat_cmd_setup (i, &cptr); stat = sim_rem_repeat_cmd_setup (i, &cptr);
}
else {
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 { else {
if (sim_con_stable_registers && if (sim_con_stable_registers &&
@ -1315,6 +1644,8 @@ for (i=(was_active_command ? sim_rem_cmd_active_line : 0);
} }
} }
} }
}
}
else else
stat = SCPE_INVREM; stat = SCPE_INVREM;
} }
@ -1402,20 +1733,6 @@ else
return SCPE_OK; /* keep going */ 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) t_stat sim_rem_con_reset (DEVICE *dptr)
{ {
if (sim_rem_con_tmxr.lines) { if (sim_rem_con_tmxr.lines) {
@ -1429,7 +1746,9 @@ if (sim_rem_con_tmxr.lines) {
continue; continue;
sim_debug (DBG_REP, &sim_remote_console, "sim_rem_con_reset(line=%d, usecs=%d)\n", i, rem->repeat_interval); sim_debug (DBG_REP, &sim_remote_console, "sim_rem_con_reset(line=%d, usecs=%d)\n", i, rem->repeat_interval);
if (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) if (i != sim_rem_con_tmxr.lines)
sim_activate_after (rem_con_data_unit, 100000); /* continue polling for open sessions */ 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->act);
free (rem->repeat_action); free (rem->repeat_action);
sim_cancel (&rem_con_repeat_units[i]); 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.lines = lines;
sim_rem_con_tmxr.ldsc = (TMLN *)realloc (sim_rem_con_tmxr.ldsc, sizeof(*sim_rem_con_tmxr.ldsc)*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); 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)); 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)*(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 = 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->action = &sim_rem_con_poll_svc;/* remote console connection polling unit */
rem_con_poll_unit->flags |= UNIT_IDLE; rem_con_poll_unit->flags |= UNIT_IDLE;
rem_con_data_unit->action = &sim_rem_con_data_svc;/* console data handling unit */ 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++) { for (i=0; i<lines; i++) {
rem_con_repeat_units[i].flags = UNIT_DIS; rem_con_repeat_units[i].flags = UNIT_DIS;
rem_con_repeat_units[i].action = &sim_rem_con_repeat_svc; 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 = &sim_rem_consoles[i];
rem->line = i; rem->line = i;
rem->lp = &sim_rem_con_tmxr.ldsc[i]; rem->lp = &sim_rem_con_tmxr.ldsc[i];

View file

@ -119,6 +119,8 @@ typedef struct {
size_t size; size_t size;
int indirect; int indirect;
size_t element_count; size_t element_count;
int *bits;
size_t bit_count;
} REG; } REG;
struct PANEL { struct PANEL {
@ -158,6 +160,8 @@ struct PANEL {
int callback_thread_running; int callback_thread_running;
void *callback_context; void *callback_context;
int usecs_between_callbacks; int usecs_between_callbacks;
unsigned int sample_frequency;
unsigned int sample_depth;
int debug; int debug;
char *simulator_version; char *simulator_version;
int radix; 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_stop_all = "repeat stop all";
static const char *register_repeat_units = " usecs "; static const char *register_repeat_units = " usecs ";
static const char *register_get_prefix = "show time"; 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_get_echo = "# REGISTERS-DONE";
static const char *register_repeat_echo = "# REGISTERS-REPEAT-DONE"; static const char *register_repeat_echo = "# REGISTERS-REPEAT-DONE";
static const char *register_dev_echo = "# REGISTERS-FOR-DEVICE:"; 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 static int
_panel_register_query_string (PANEL *panel, char **buf, size_t *buf_size) _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; const char *dev;
pthread_mutex_lock (&panel->io_lock); pthread_mutex_lock (&panel->io_lock);
buf_needed = 2 + strlen (register_get_prefix); /* SHOW TIME */ buf_needed = 2 + strlen (register_get_prefix); /* SHOW TIME */
for (i=0; i<panel->reg_count; i++) { for (i=0; i<panel->reg_count; i++) {
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); 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) if (panel->regs[i].element_count > 0)
buf_needed += 4 + 6 /* 6 digit register array index */; buf_needed += 4 + 6 /* 6 digit register array index */;
if (panel->regs[i].indirect) if (panel->regs[i].indirect)
buf_needed += 12 + strlen (register_ind_echo) + strlen (panel->regs[i].name); 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 */ buf_needed += 10 + strlen (register_get_echo); /* # REGISTERS-DONE */
if (buf_needed > *buf_size) { if (buf_needed > *buf_size) {
free (*buf); free (*buf);
@ -398,13 +413,15 @@ if (buf_needed > *buf_size) {
*buf_size = buf_needed; *buf_size = buf_needed;
} }
buf_data = 0; buf_data = 0;
if (reg_count) {
sprintf (*buf + buf_data, "%s\r", register_get_prefix); sprintf (*buf + buf_data, "%s\r", register_get_prefix);
buf_data += strlen (*buf + buf_data); buf_data += strlen (*buf + buf_data);
}
dev = ""; dev = "";
for (i=j=0; i<panel->reg_count; i++) { for (i=j=0; i<panel->reg_count; i++) {
const char *reg_dev = panel->regs[i].device_name ? panel->regs[i].device_name : ""; 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; continue;
if (strcmp (dev, reg_dev)) {/* devices are different */ if (strcmp (dev, reg_dev)) {/* devices are different */
char *tbuf; char *tbuf;
@ -447,11 +464,17 @@ if (buf_data && ((*buf)[buf_data-1] != '\r')) {
for (i=j=0; i<panel->reg_count; i++) { for (i=j=0; i<panel->reg_count; i++) {
const char *reg_dev = panel->regs[i].device_name ? panel->regs[i].device_name : ""; 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; 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); 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); 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); strcpy (*buf + buf_data, register_get_echo);
buf_data += strlen (*buf + buf_data); buf_data += strlen (*buf + buf_data);
strcpy (*buf + buf_data, "\r"); strcpy (*buf + buf_data, "\r");
@ -461,6 +484,53 @@ pthread_mutex_unlock (&panel->io_lock);
return 0; 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 PANEL **panels = NULL;
static int panel_count = 0; static int panel_count = 0;
@ -927,7 +997,9 @@ _panel_add_register (PANEL *panel,
size_t size, size_t size,
void *addr, void *addr,
int indirect, int indirect,
size_t element_count) size_t element_count,
int *bits,
size_t bit_count)
{ {
REG *regs, *reg; REG *regs, *reg;
char *response = NULL; char *response = NULL;
@ -942,6 +1014,10 @@ if (panel->State == Run) {
sim_panel_set_error ("Not Halted"); sim_panel_set_error ("Not Halted");
return -1; 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)); regs = (REG *)_panel_malloc ((1 + panel->reg_count)*sizeof(*regs));
if (regs == NULL) { if (regs == NULL) {
panel->State = Error; panel->State = Error;
@ -959,6 +1035,11 @@ if (reg->name == NULL) {
} }
strcpy (reg->name, name); strcpy (reg->name, name);
reg->indirect = indirect; 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++) { for (i=0; i<strlen (reg->name); i++) {
if (islower (reg->name[i])) if (islower (reg->name[i]))
reg->name[i] = toupper (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 (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); 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"); sim_panel_set_error ("Duplicate Register Declaration");
free (t1); free (t1);
free (t2); free (t2);
@ -1004,9 +1087,6 @@ for (i=0; i<panel->reg_count; i++) {
free (t1); free (t1);
free (t2); free (t2);
} }
reg->addr = addr;
reg->size = size;
reg->element_count = element_count;
pthread_mutex_unlock (&panel->io_lock); pthread_mutex_unlock (&panel->io_lock);
/* Validate existence of requested register/array */ /* 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]" : "")) { 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 */ /* Now build the register query string for the whole register list */
if (_panel_register_query_string (panel, &panel->reg_query, &panel->reg_query_size)) if (_panel_register_query_string (panel, &panel->reg_query, &panel->reg_query_size))
return -1; return -1;
if (bits) {
memset (bits, 0, sizeof (*bits) * bit_count);
if (_panel_establish_register_bits_collection (panel))
return -1;
}
return 0; return 0;
} }
@ -1060,7 +1145,17 @@ sim_panel_add_register (PANEL *panel,
size_t size, size_t size,
void *addr) 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 int
@ -1071,7 +1166,7 @@ sim_panel_add_register_array (PANEL *panel,
size_t size, size_t size,
void *addr) 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, size_t size,
void *addr) 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 static int
@ -1165,6 +1270,24 @@ pthread_mutex_unlock (&panel->io_lock);
return 0; 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 int
sim_panel_exec_halt (PANEL *panel) sim_panel_exec_halt (PANEL *panel)
{ {
@ -1760,6 +1883,8 @@ while ((p->sock != INVALID_SOCKET) &&
e = strchr (s, ':'); e = strchr (s, ':');
if (e) { if (e) {
size_t i; size_t i;
char smp_dev[32], smp_reg[32], smp_ind[32];
unsigned int bit;
*e++ = '\0'; *e++ = '\0';
if (!strcmp("Time", s)) { if (!strcmp("Time", s)) {
@ -1769,6 +1894,33 @@ while ((p->sock != INVALID_SOCKET) &&
++s; ++s;
continue; 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)) { if (!strncmp (s + strlen (sim_prompt), register_ind_echo, strlen (register_ind_echo) - 1)) {
e = s + strlen (sim_prompt) + strlen (register_ind_echo); e = s + strlen (sim_prompt) + strlen (register_ind_echo);
r = NULL; r = NULL;

View file

@ -43,7 +43,6 @@
into the application. into the application.
4) Use a simh simulator built from the same version of simh that the 4) Use a simh simulator built from the same version of simh that the
sim_frontpanel and sim_sock modules came from. sim_frontpanel and sim_sock modules came from.
*/ */
#ifndef SIM_FRONTPANEL_H_ #ifndef SIM_FRONTPANEL_H_
@ -57,7 +56,7 @@ extern "C" {
#if !defined(__VAX) /* Unsupported platform */ #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 Note 2: - Configuration file specified should contain device setup
statements (enable, disable, CPU types and attach commands). statements (enable, disable, CPU types and attach commands).
It should not start a simulator running. It should not start a simulator running.
*/ */
typedef struct PANEL PANEL; 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 simulator_panel the simulator panel to connect to
device_name the simulator's name for the device device_name the simulator's name for the device
*/ */
PANEL * PANEL *
sim_panel_add_device_panel (PANEL *simulator_panel, sim_panel_add_device_panel (PANEL *simulator_panel,
const char *device_name); 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 Note: destroying a simulator panel will also destroy any
related sub panels related sub panels
*/ */
int int
sim_panel_destroy (PANEL *panel); sim_panel_destroy (PANEL *panel);
@ -128,12 +126,14 @@ sim_panel_destroy (PANEL *panel);
simulator. simulator.
The registers that a particular frontpanel application mught need 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
sim_panel_add_register_bits
sim_panel_add_register_array sim_panel_add_register_array
and and
sim_panel_add_register_indirect sim_panel_add_register_indirect
sim_panel_add_register_indirect_bits
name the name the simulator knows this register by name the name the simulator knows this register by
device_name the device this register is part of. Defaults to device_name the device this register is part of. Defaults to
@ -144,8 +144,14 @@ and
receive the data in the simulator's register receive the data in the simulator's register
addr a pointer to the location of the buffer which will addr a pointer to the location of the buffer which will
be loaded with the data in the simulator's register 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 int
sim_panel_add_register (PANEL *panel, sim_panel_add_register (PANEL *panel,
const char *name, const char *name,
@ -153,6 +159,13 @@ sim_panel_add_register (PANEL *panel,
size_t size, size_t size,
void *addr); void *addr);
int
sim_panel_add_register_bits (PANEL *panel,
const char *name,
const char *device_name,
size_t bit_width,
int *bits);
int int
sim_panel_add_register_array (PANEL *panel, sim_panel_add_register_array (PANEL *panel,
const char *name, const char *name,
@ -167,11 +180,19 @@ sim_panel_add_register_indirect (PANEL *panel,
const char *device_name, const char *device_name,
size_t size, size_t size,
void *addr); 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 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 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 1) The values can be polled (when ever it is desired) by calling
sim_panel_get_registers(). sim_panel_get_registers().
@ -189,15 +210,11 @@ sim_panel_add_register_indirect (PANEL *panel,
or frontpanel interactions with the simulator may be disrupted. or frontpanel interactions with the simulator may be disrupted.
Setting a flag, signaling an event or posting a message are Setting a flag, signaling an event or posting a message are
reasonable activities to perform in a callback routine. reasonable activities to perform in a callback routine.
*/ */
int int
sim_panel_get_registers (PANEL *panel, unsigned long long *simulation_time); sim_panel_get_registers (PANEL *panel, unsigned long long *simulation_time);
/**
*/
typedef void (*PANEL_DISPLAY_PCALLBACK)(PANEL *panel, typedef void (*PANEL_DISPLAY_PCALLBACK)(PANEL *panel,
unsigned long long simulation_time, unsigned long long simulation_time,
void *context); void *context);
@ -208,6 +225,26 @@ sim_panel_set_display_callback_interval (PANEL *panel,
void *context, void *context,
int usecs_between_callbacks); 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 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_boot - Boot a simulator from a specific device
sim_panel_exec_run - Start/Resume a simulator running instructions sim_panel_exec_run - Start/Resume a simulator running instructions
sim_panel_exec_step - Have a simulator execute a single step sim_panel_exec_step - Have a simulator execute a single step
*/ */
int int
sim_panel_exec_halt (PANEL *panel); 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 Note: Any breakpoint switches/flags must be located at the
beginning of the condition string beginning of the condition string
*/ */
int 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_mem_deposit - Deposit to memory location
sim_panel_set_register_value - Deposit to a register or memory sim_panel_set_register_value - Deposit to a register or memory
location location
*/ */
@ -359,6 +394,7 @@ sim_panel_mem_deposit (PANEL *panel,
const void *value); const void *value);
/** /**
sim_panel_set_register_value sim_panel_set_register_value
name the name of a simulator register or a memory address 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 value the new value in character string form. The string
must be in the native/natural radix that the simulator must be in the native/natural radix that the simulator
uses when referencing that register uses when referencing that register
*/ */
int int
sim_panel_set_register_value (PANEL *panel, 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 in a simulated removable media device one of the following
routines should be called: routines should be called:
sim_panel_mount - mounts the indicated media file on a device sim_panel_mount - mounts the indicated media file on a device
sim_panel_dismount - dismounts the currently mounted media file sim_panel_dismount - dismounts the currently mounted media file
from a device from a device
*/ */
/** /**
sim_panel_mount sim_panel_mount
device the name of a simulator device/unit device the name of a simulator device/unit
switches any switches appropriate for the desire attach switches any switches appropriate for the desire attach
path the path on the local system to be attached path the path on the local system to be attached
*/ */
int int
sim_panel_mount (PANEL *panel, sim_panel_mount (PANEL *panel,
const char *device, const char *device,
@ -400,11 +435,12 @@ sim_panel_mount (PANEL *panel,
const char *path); const char *path);
/** /**
sim_panel_dismount sim_panel_dismount
device the name of a simulator device/unit device the name of a simulator device/unit
*/ */
int int
sim_panel_dismount (PANEL *panel, sim_panel_dismount (PANEL *panel,
const char *device); 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_get_error - the details of the most recent error
sim_panel_clear_error - clears the error buffer sim_panel_clear_error - clears the error buffer
*/ */
const char *sim_panel_get_error (void); const char *sim_panel_get_error (void);