From 665ebf0fd1a99df8611359d8634e21c9c3b31c4d Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Sat, 4 Feb 2017 10:48:13 -0800 Subject: [PATCH] FRONTPANEL: sim_frontpanel API version 4 release Add simulator side register bit sampling with averaged sample values delivered across the API at specified rates. --- frontpanel/FrontPanelTest.c | 33 +++ scp.h | 3 + sim_console.c | 406 ++++++++++++++++++++++++++++++++---- sim_frontpanel.c | 188 +++++++++++++++-- sim_frontpanel.h | 79 +++++-- 5 files changed, 627 insertions(+), 82 deletions(-) diff --git a/frontpanel/FrontPanelTest.c b/frontpanel/FrontPanelTest.c index 612b4313..988ee09b 100644 --- a/frontpanel/FrontPanelTest.c +++ b/frontpanel/FrontPanelTest.c @@ -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; diff --git a/scp.h b/scp.h index 7cb0814e..29ed7d2a 100644 --- a/scp.h +++ b/scp.h @@ -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; diff --git a/sim_console.c b/sim_console.c index e16f1c7f..163ee706 100644 --- a/sim_console.c +++ b/sim_console.c @@ -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; irepeat_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 (®->bits[i], val&1); + else + sim_rem_set_reg_bit (®->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; iact); 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; iline = i; rem->lp = &sim_rem_con_tmxr.ldsc[i]; diff --git a/sim_frontpanel.c b/sim_frontpanel.c index fde13a2f..30ef6f20 100644 --- a/sim_frontpanel.c +++ b/sim_frontpanel.c @@ -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; ireg_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; ireg_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; ireg_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; ireg_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; ireg_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; iname); i++) { if (islower (reg->name[i])) reg->name[i] = toupper (reg->name[i]); @@ -992,7 +1073,9 @@ for (i=0; ireg_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; ireg_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; ireg_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; diff --git a/sim_frontpanel.h b/sim_frontpanel.h index 86aa4d6d..9ff82cba 100644 --- a/sim_frontpanel.h +++ b/sim_frontpanel.h @@ -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);