From 2de2b9bd8006352e84c12d0e85ad7d69bbfee403 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Fri, 15 Dec 2017 13:57:20 -0800 Subject: [PATCH] FRONTPANEL: sim_frontpanel API release 10 - Reworked STEP, HALT, BOOT, and RUN API's to properly interlock with the receive thread. - Shorten destroy delay while debugging to 1 second. - Allow execution and text breakpoints to be set and/or cleared while simulator is running. --- frontpanel/FrontPanelTest.c | 46 ++++++++- sim_frontpanel.c | 195 ++++++++++++++++++++---------------- sim_frontpanel.h | 2 +- 3 files changed, 152 insertions(+), 91 deletions(-) diff --git a/frontpanel/FrontPanelTest.c b/frontpanel/FrontPanelTest.c index bb428e7b..0758f230 100644 --- a/frontpanel/FrontPanelTest.c +++ b/frontpanel/FrontPanelTest.c @@ -438,11 +438,11 @@ if (sim_panel_add_register_bits (panel, "PCQ[3]", NULL, 32, PCQ_3_bits)) { goto Done; } if (1) { - unsigned int noop_noop_noop_halt = 0x00010101, addr400 = 0x00000400, pc_value; + unsigned int noop_noop_noop_halt = 0x00010101, brb_self = 0x0000FE11, addr400 = 0x00000400, pc_value; int mstime = 0; if (sim_panel_mem_deposit (panel, sizeof(addr400), &addr400, sizeof(noop_noop_noop_halt), &noop_noop_noop_halt)) { - printf ("Error setting 00000000 to %08X: %s\n", noop_noop_noop_halt, sim_panel_get_error()); + printf ("Error setting %08X to %08X: %s\n", addr400, noop_noop_noop_halt, sim_panel_get_error()); goto Done; } if (sim_panel_gen_deposit (panel, "PC", sizeof(addr400), &addr400)) { @@ -488,6 +488,31 @@ if (1) { printf ("Unexpected PC value after STEP: %08X, expected: %08X\n", pc_value, addr400 + 1); goto Done; } + if (sim_panel_mem_deposit (panel, sizeof(addr400), &addr400, sizeof(brb_self), &brb_self)) { + printf ("Error setting %08X to %08X: %s\n", addr400, brb_self, sim_panel_get_error()); + goto Done; + } + if (sim_panel_gen_deposit (panel, "PC", sizeof(addr400), &addr400)) { + printf ("Error setting PC to %08X: %s\n", addr400, sim_panel_get_error()); + goto Done; + } + if (sim_panel_exec_run(panel)) { + printf ("Error starting simulator execution: %s\n", sim_panel_get_error()); + goto Done; + } + while ((sim_panel_get_state (panel) == Run) && + (mstime < 1000)) { + usleep (100000); + mstime += 100; + } + if (sim_panel_exec_halt (panel)) { + printf ("Error executing halt: %s\n", sim_panel_get_error()); + goto Done; + } + if (sim_panel_get_state (panel) != Halt) { + printf ("State not Halt after successful Halt\n"); + goto Done; + } } return 0; @@ -511,7 +536,7 @@ if (panel_setup()) if (1) { struct { unsigned int addr; - char *instr; + const char *instr; } long_running_program[] = { {0x2000, "MOVL #7FFFFFFF,R0"}, {0x2007, "MOVL #7FFFFFFF,R1"}, @@ -522,7 +547,7 @@ if (1) { }; int i; - sim_panel_debug (panel, "Testing sim_panel_destroy() with simulator in Run State"); + sim_panel_debug (panel, "Testing sim_panel_exec_halt and sim_panel_destroy() () with simulator in Run State"); for (i=0; long_running_program[i].instr; i++) if (sim_panel_mem_deposit_instruction (panel, sizeof(long_running_program[i].addr), &long_running_program[i].addr, long_running_program[i].instr)) { @@ -538,7 +563,18 @@ if (1) { printf ("Error starting simulator execution: %s\n", sim_panel_get_error()); goto Done; } - usleep (2000000); /* 2 Seconds */ + usleep (100000); /* .1 seconds */ + sim_panel_debug (panel, "Testing sim_panel_exec_halt"); + if (sim_panel_exec_halt (panel)) { + printf ("Error halting simulator execution: %s\n", sim_panel_get_error()); + goto Done; + } + sim_panel_debug (panel, "Testing sim_panel_exec_run"); + if (sim_panel_exec_run (panel)) { + printf ("Error resuming simulator execution: %s\n", sim_panel_get_error()); + goto Done; + } + usleep (2000000); /* 2 Seconds */ sim_panel_debug (panel, "Shutting down while simulator is running"); sim_panel_destroy (panel); } diff --git a/sim_frontpanel.c b/sim_frontpanel.c index 6310c3b4..71253dac 100644 --- a/sim_frontpanel.c +++ b/sim_frontpanel.c @@ -158,6 +158,7 @@ struct PANEL { char *io_response; size_t io_response_data; size_t io_response_size; + const char *completion_string; pthread_cond_t io_done; pthread_cond_t startup_done; PANEL_DISPLAY_PCALLBACK callback; @@ -392,6 +393,8 @@ static void * _panel_debugflusher(void *arg) { PANEL *p = (PANEL*)arg; +int flush_interval = 15; +int sleeps = 0; pthread_setspecific (panel_thread_id, "debugflush"); @@ -403,8 +406,9 @@ msleep (100); pthread_mutex_lock (&p->io_lock); while (p->sock != INVALID_SOCKET) { pthread_mutex_unlock (&p->io_lock); - msleep (15000); - sim_panel_flush_debug (p); + msleep (1000); + if (0 == (sleeps++)%flush_interval) + sim_panel_flush_debug (p); pthread_mutex_lock (&p->io_lock); } pthread_mutex_unlock (&p->io_lock); @@ -469,6 +473,9 @@ return sent; static int _panel_sendf (PANEL *p, int *completion_status, char **response, const char *fmt, ...); +static int +_panel_sendf_completion (PANEL *p, char **response, const char *completion, const char *fmt, ...); + static int _panel_register_query_string (PANEL *panel, char **buf, size_t *buf_size) { @@ -1046,15 +1053,8 @@ if (panel) { sim_panel_set_display_callback_interval (panel, NULL, NULL, 0); /* Next, attempt a simulator shutdown only with the master panel */ if (panel->parent == NULL) { - if (panel->State == Run) { - int i; - - _panel_send (panel, "\005\r", 2); - for (i=0; (panel->State == Run) && (i < 10); i++) - msleep(100); - if (panel->State == Run) - _panel_debug (panel, DBG_THR, "Unable to HALT running simulator for shutdown", NULL, 0); - } + if (panel->State == Run) + sim_panel_exec_halt (panel); _panel_send (panel, "EXIT\r", 5); } /* Wait for up to 2 seconds for a graceful shutdown */ @@ -1459,8 +1459,14 @@ if (panel->parent) { return -1; } if (panel->State == Run) { - if (1 != _panel_send (panel, "\005", 1)) + if (_panel_sendf_completion (panel, NULL, sim_prompt, "\005")) { + _panel_debug (panel, DBG_THR, "Error trying to HALT running simulator: %s", NULL, 0, sim_panel_get_error ()); return -1; + } + if (panel->State == Run) { + _panel_debug (panel, DBG_THR, "Unable to HALT running simulator", NULL, 0); + return -1; + } } return 0; } @@ -1469,6 +1475,7 @@ int sim_panel_exec_boot (PANEL *panel, const char *device) { int cmd_stat; +char *response, *simtime; if (!panel || (panel->State == Error)) { sim_panel_set_error (NULL, "Invalid Panel"); @@ -1485,12 +1492,17 @@ if (panel->State == Run) { /* A BOOT or RUN command will restart the simulator's time base. */ /* We account for that so that the frontpanel application sees ever */ /* increasing time values when register data is delivered. */ -if (_panel_sendf (panel, &cmd_stat, NULL, "SHOW TIME\r")) +if (_panel_sendf (panel, &cmd_stat, &response, "SHOW TIME\r")) return -1; -panel->simulation_time_base += panel->simulation_time; -if (_panel_sendf (panel, NULL, NULL, "BOOT %s\r", device)) +if ((simtime = strstr (response, "Time:"))) { + panel->simulation_time = strtoull (simtime + 5, NULL, 10); + panel->simulation_time_base += panel->simulation_time; + } +free (response); +if (_panel_sendf_completion (panel, NULL, "Simulator Running...", "BOOT %s\r", device)) { + _panel_debug (panel, DBG_THR, "Unable to BOOT simulator: %s", NULL, 0, sim_panel_get_error()); return -1; -msleep (100); /* Allow Run/Hslt state to settle */ + } return 0; } @@ -1498,6 +1510,7 @@ int sim_panel_exec_start (PANEL *panel) { int cmd_stat; +char *response, *simtime; if (!panel || (panel->State == Error)) { sim_panel_set_error (NULL, "Invalid Panel"); @@ -1514,12 +1527,20 @@ if (panel->State == Run) { /* A BOOT or RUN command will restart the simulator's time base. */ /* We account for that so that the frontpanel application sees ever */ /* increasing time values when register data is delivered. */ -if (_panel_sendf (panel, &cmd_stat, NULL, "SHOW TIME\r")) +if (_panel_sendf (panel, &cmd_stat, &response, "SHOW TIME\r")) { + _panel_debug (panel, DBG_THR, "Unable to send SHOW TIME command while starting simulator: %s", NULL, 0, sim_panel_get_error()); return -1; + } +if ((simtime = strstr (response, "Time:"))) { + panel->simulation_time = strtoull (simtime + 5, NULL, 10); + panel->simulation_time_base += panel->simulation_time; + } +free (response); panel->simulation_time_base += panel->simulation_time; -if (_panel_sendf (panel, NULL, NULL, "RUN -Q\r", 5)) +if (_panel_sendf_completion (panel, NULL, "Simulator Running...", "RUN -Q\r", 5)) { + _panel_debug (panel, DBG_THR, "Unable to start simulator: %s", NULL, 0, sim_panel_get_error()); return -1; -msleep (100); /* Allow Run/Hslt state to settle */ + } return 0; } @@ -1538,9 +1559,8 @@ if (panel->State == Run) { sim_panel_set_error (NULL, "Not Halted"); return -1; } -if (_panel_sendf (panel, NULL, NULL, "CONT\r", 5)) +if (_panel_sendf_completion (panel, NULL, "Simulator Running...", "CONT\r")) return -1; -msleep (100); /* Allow Run/Hslt state to settle */ return 0; } @@ -1559,9 +1579,10 @@ if (panel->State == Run) { sim_panel_set_error (NULL, "Not Halted"); return -1; } - -if (5 != _panel_send (panel, "STEP\r", 5)) +if (_panel_sendf_completion (panel, NULL, sim_prompt, "STEP")) { + _panel_debug (panel, DBG_THR, "Error trying to STEP running simulator: %s", NULL, 0, sim_panel_get_error ()); return -1; + } return 0; } @@ -1579,11 +1600,6 @@ if (panel->parent) { sim_panel_set_error (NULL, "Can't establish a breakpoint from device front panel"); return -1; } -if (panel->State == Run) { - sim_panel_set_error (NULL, "Not Halted"); - return -1; - } - if ((_panel_sendf (panel, &cmd_stat, &response, "BREAK %s\r", condition)) || (*response)) { sim_panel_set_error (NULL, "Error establishing breakpoint at '%s': %s", condition, response ? response : ""); @@ -1608,11 +1624,6 @@ if (panel->parent) { sim_panel_set_error (NULL, "Can't clear a breakpoint from device front panel"); return -1; } -if (panel->State == Run) { - sim_panel_set_error (NULL, "Not Halted"); - return -1; - } - if ((_panel_sendf (panel, &cmd_stat, &response, "NOBREAK %s\r", condition)) || (*response)) { sim_panel_set_error (NULL, "Error clearing breakpoint at '%s': %s", condition, response ? response : ""); @@ -1637,11 +1648,6 @@ if (panel->parent) { sim_panel_set_error (NULL, "Can't establish an output breakpoint from device front panel"); return -1; } -if (panel->State == Run) { - sim_panel_set_error (NULL, "Not Halted"); - return -1; - } - if ((_panel_sendf (panel, &cmd_stat, &response, "EXPECT %s\r", condition)) || (*response)) { sim_panel_set_error (NULL, "Error establishing output breakpoint for '%s': %s", condition, response ? response : ""); @@ -1666,11 +1672,6 @@ if (panel->parent) { sim_panel_set_error (NULL, "Can't clear an output breakpoint from device front panel"); return -1; } -if (panel->State == Run) { - sim_panel_set_error (NULL, "Not Halted"); - return -1; - } - if ((_panel_sendf (panel, &cmd_stat, &response, "NOEXPECT %s\r", condition)) || (*response)) { sim_panel_set_error (NULL, "Error clearing output breakpoint for '%s': %s", condition, response ? response : ""); @@ -1962,17 +1963,9 @@ if (!panel || (panel->State == Error)) { sim_panel_set_error (NULL, "Invalid Panel"); return -1; } -pthread_mutex_lock (&panel->io_lock); OrigState = panel->State; -if (OrigState == Run) { +if (OrigState == Run) sim_panel_exec_halt (panel); - while (panel->State == Run) { - pthread_mutex_unlock (&panel->io_lock); - msleep (100); - pthread_mutex_lock (&panel->io_lock); - } - } -pthread_mutex_unlock (&panel->io_lock); do { if (_panel_sendf (panel, &cmd_stat, &response, "ATTACH %s %s %s", switches, device, path)) { stat = -1; @@ -1983,10 +1976,8 @@ do { stat = -1; } } while (0); -pthread_mutex_lock (&panel->io_lock); if (OrigState == Run) sim_panel_exec_run (panel); -pthread_mutex_unlock (&panel->io_lock); free (response); return stat; } @@ -2010,17 +2001,9 @@ if (!panel || (panel->State == Error)) { sim_panel_set_error (NULL, "Invalid Panel"); return -1; } -pthread_mutex_lock (&panel->io_lock); OrigState = panel->State; -if (OrigState == Run) { +if (OrigState == Run) sim_panel_exec_halt (panel); - while (panel->State == Run) { - pthread_mutex_unlock (&panel->io_lock); - msleep (100); - pthread_mutex_lock (&panel->io_lock); - } - } -pthread_mutex_unlock (&panel->io_lock); do { if (_panel_sendf (panel, &cmd_stat, &response, "DETACH %s", device)) { stat = -1; @@ -2031,10 +2014,8 @@ do { stat = -1; } } while (0); -pthread_mutex_lock (&panel->io_lock); if (OrigState == Run) sim_panel_exec_run (panel); -pthread_mutex_unlock (&panel->io_lock); free (response); return stat; } @@ -2302,6 +2283,13 @@ Start_Next_Line: buf_data = strlen (buf); if (buf_data) _panel_debug (p, DBG_RSP, "Remnant Buffer Contents: '%s'", NULL, 0, buf); + if ((!p->parent) && + (p->completion_string) && + (!memcmp (buf, p->completion_string, strlen (p->completion_string)))) { + _panel_debug (p, DBG_RCV, "*Received Command Complete - Match: '%s'", NULL, 0, p->completion_string); + p->io_waiting = 0; + pthread_cond_signal (&p->io_done); + } if (!memcmp ("Simulator Running...", buf, 20)) { _panel_debug (p, DBG_RSP, "State transitioning to Run", NULL, 0); p->State = Run; @@ -2513,20 +2501,20 @@ return -1; } static int -_panel_sendf (PANEL *p, int *completion_status, char **response, const char *fmt, ...) +_panel_vsendf_completion (PANEL *p, int *completion_status, char **response, const char *completion_string, const char *fmt, va_list arglist) { char stackbuf[1024]; int bufsize = sizeof(stackbuf); char *buf = stackbuf; int len, status_echo_len = 0, sent_len; int post_fix_len = completion_status ? 7 + sizeof (command_done_echo) + sizeof (command_status) : 1; -va_list arglist; int ret; +if (completion_status && completion_string) /* one or the other, but */ + return -1; /* not both */ + while (1) { /* format passed string, args */ - va_start (arglist, fmt); len = vsnprintf (buf, bufsize-1, fmt, arglist); - va_end (arglist); if (len < 0) return sim_panel_set_error (NULL, "Format encoding error while processing '%s'", fmt); @@ -2554,17 +2542,20 @@ if (len && (buf[len-1] != '\r')) { pthread_mutex_lock (&p->io_command_lock); ++p->command_count; -if (completion_status) { - sprintf (&buf[len], "%s\r%s\r", command_status, command_done_echo); - status_echo_len = strlen (&buf[len]); +if (completion_status || completion_string) { + if (completion_status) { + sprintf (&buf[len], "%s\r%s\r", command_status, command_done_echo); + status_echo_len = strlen (&buf[len]); + } pthread_mutex_lock (&p->io_lock); + p->completion_string = completion_string; p->io_response_data = 0; } _panel_debug (p, DBG_REQ, "Command %d Request%s: %*.*s", NULL, 0, p->command_count, completion_status ? " (with response)" : "", len, len, buf); ret = ((len + status_echo_len) == (sent_len = _panel_send (p, buf, len + status_echo_len))) ? 0 : -1; -if (completion_status) { +if (completion_status || completion_string) { if (!ret) { /* Sent OK? */ char *tresponse = NULL; @@ -2575,29 +2566,39 @@ if (completion_status) { if (0 == memcmp (buf, p->io_response + strlen (sim_prompt), len)) { char *eol, *status; memcpy (tresponse, p->io_response + strlen (sim_prompt) + len + 1, p->io_response_data + 1 - (strlen (sim_prompt) + len + 1)); - *completion_status = -1; - status = strstr (tresponse, command_status); - if (status) { - *(status - strlen (sim_prompt)) = '\0'; - status += strlen (command_status) + 2; - eol = strchr (status, '\r'); - if (eol) - *eol = '\0'; - sscanf (status, "Status:%08X-", completion_status); + if (completion_status) { + *completion_status = -1; + status = strstr (tresponse, command_status); + if (status) { + *(status - strlen (sim_prompt)) = '\0'; + status += strlen (command_status) + 2; + eol = strchr (status, '\r'); + if (eol) + *eol = '\0'; + sscanf (status, "Status:%08X-", completion_status); + } } } else memcpy (tresponse, p->io_response, p->io_response_data + 1); if (response) { *response = tresponse; - _panel_debug (p, DBG_RSP, "Command %d Response(Status=%d): '%s'", NULL, 0, p->command_count, *completion_status, *response); + if (completion_status) + _panel_debug (p, DBG_RSP, "Command %d Response(Status=%d): '%s'", NULL, 0, p->command_count, *completion_status, *response); + else + _panel_debug (p, DBG_RSP, "Command %d Response - Match '%s': '%s'", NULL, 0, p->command_count, completion_string, *response); } else { free (tresponse); - if (p->io_response_data) - _panel_debug (p, DBG_RSP, "Discarded Unwanted Command %d Response Data(Status=%d):", p->io_response, p->io_response_data, p->command_count, *completion_status); + if (p->io_response_data) { + if (completion_status) + _panel_debug (p, DBG_RSP, "Discarded Unwanted Command %d Response Data(Status=%d):", p->io_response, p->io_response_data, p->command_count, *completion_status); + else + _panel_debug (p, DBG_RSP, "Discarded Unwanted Command %d Response Data - Match '%s':", p->io_response, p->io_response_data, p->command_count, completion_string); + } } } + p->completion_string = NULL; p->io_response_data = 0; p->io_response[0] = '\0'; pthread_mutex_unlock (&p->io_lock); @@ -2613,6 +2614,30 @@ if (buf != stackbuf) return ret; } +static int +_panel_sendf (PANEL *p, int *completion_status, char **response, const char *fmt, ...) +{ +va_list arglist; +int status; + +va_start (arglist, fmt); +status = _panel_vsendf_completion (p, completion_status, response, NULL, fmt, arglist); +va_end (arglist); +return status; +} + +static int +_panel_sendf_completion (PANEL *p, char **response, const char *completion, const char *fmt, ...) +{ +va_list arglist; +int status; + +va_start (arglist, fmt); +status = _panel_vsendf_completion (p, NULL, response, completion, fmt, arglist); +va_end (arglist); +return status; +} + #ifdef __cplusplus } diff --git a/sim_frontpanel.h b/sim_frontpanel.h index a96c8443..f6a52f3a 100644 --- a/sim_frontpanel.h +++ b/sim_frontpanel.h @@ -56,7 +56,7 @@ extern "C" { #if !defined(__VAX) /* Unsupported platform */ -#define SIM_FRONTPANEL_VERSION 9 +#define SIM_FRONTPANEL_VERSION 10 /**