diff --git a/sim_frontpanel.c b/sim_frontpanel.c index 52969f6f..69ed909a 100644 --- a/sim_frontpanel.c +++ b/sim_frontpanel.c @@ -269,6 +269,7 @@ int sent = 0; if (p->sock == INVALID_SOCKET) { sim_panel_set_error ("Invalid Socket for write"); + p->State = Error; return -1; } pthread_mutex_lock (&p->io_send_lock); @@ -276,6 +277,7 @@ while (len) { int bsent = sim_write_sock (p->sock, msg, len); if (bsent < 0) { sim_panel_set_error ("%s", sim_get_err_sock("Error writing to socket")); + p->State = Error; pthread_mutex_unlock (&p->io_send_lock); return bsent; } @@ -305,6 +307,7 @@ if (buf_needed > *buf_size) { free (*buf); *buf = (char *)_panel_malloc (buf_needed); if (!*buf) { + panel->State = Error; pthread_mutex_unlock (&panel->io_lock); return -1; } @@ -640,6 +643,7 @@ if (panel) { free (panel->devices); panel->devices = NULL; } + _panel_deregister_panel (panel); free (panel->name); free (panel->config); @@ -713,19 +717,22 @@ sim_panel_add_register (PANEL *panel, { REG *regs, *reg; -if (!panel) { +if (!panel || (panel->State == Error)) { sim_panel_set_error ("Invalid Panel"); return -1; } -regs = (REG *)_panel_malloc ((1 + panel->reg_count)*sizeof(*regs)); -if (regs == NULL) +regs = (REG *)_panel_malloc ((1 + panel->reg_count)*sizeof(*regs)); +if (regs == NULL) { + panel->State = Error; return -1; + } pthread_mutex_lock (&panel->io_lock); memcpy (regs, panel->regs, panel->reg_count*sizeof(*regs)); reg = ®s[panel->reg_count]; memset (reg, 0, sizeof(*regs)); reg->name = (char *)_panel_malloc (1 + strlen (name)); if (reg->name == NULL) { + panel->State = Error; free (regs); return -1; } @@ -745,7 +752,7 @@ return 0; int sim_panel_get_registers (PANEL *panel) { -if (!panel) { +if ((!panel) || (panel->State == Error)) { sim_panel_set_error ("Invalid Panel"); return -1; } @@ -808,7 +815,7 @@ return 0; int sim_panel_exec_halt (PANEL *panel) { -if (!panel) { +if (!panel || (panel->State == Error)) { sim_panel_set_error ("Invalid Panel"); return -1; } @@ -822,7 +829,7 @@ return 0; int sim_panel_exec_boot (PANEL *panel, const char *device) { -if (!panel) { +if (!panel || (panel->State == Error)) { sim_panel_set_error ("Invalid Panel"); return -1; } @@ -839,7 +846,7 @@ return 0; int sim_panel_exec_run (PANEL *panel) { -if (!panel) { +if (!panel || (panel->State == Error)) { sim_panel_set_error ("Invalid Panel"); return -1; } @@ -856,7 +863,7 @@ return 0; int sim_panel_exec_step (PANEL *panel) { -if (!panel) { +if (!panel || (panel->State == Error)) { sim_panel_set_error ("Invalid Panel"); return -1; } @@ -876,7 +883,7 @@ sim_panel_set_register_value (PANEL *panel, const char *name, const char *value) { -if (!panel) { +if (!panel || (panel->State == Error)) { sim_panel_set_error ("Invalid Panel"); return -1; } @@ -909,7 +916,8 @@ pthread_setschedparam (pthread_self(), sched_policy, &sched_priority); pthread_mutex_lock (&p->io_lock); p->io_thread_running = 1; pthread_cond_signal (&p->startup_cond); /* Signal we're ready to go */ -while (p->sock != INVALID_SOCKET) { +while ((p->sock != INVALID_SOCKET) && + (p->State != Error)) { int new_data; char *s, *e, *eol; @@ -918,6 +926,7 @@ while (p->sock != INVALID_SOCKET) { if (new_data <= 0) { sim_panel_set_error ("%s", sim_get_err_sock("Unexpected socket read")); _panel_debug (p, DBG_RCV, "%s", NULL, 0, sim_panel_get_error()); + p->State = Error; break; } _panel_debug (p, DBG_RCV, "Received:", &buf[buf_data], new_data); @@ -1020,12 +1029,13 @@ pthread_mutex_lock (&p->io_lock); p->callback_thread_running = 1; pthread_cond_signal (&p->startup_cond); /* Signal we're ready to go */ while ((p->sock != INVALID_SOCKET) && - (p->callbacks_per_second)) { + (p->callbacks_per_second) && + (p->State != Error)) { int rate = p->callbacks_per_second; pthread_mutex_unlock (&p->io_lock); ++callback_count; - if (1 == callback_count%rate) { + if (1 == callback_count%rate) { /* once a second update the query string */ _panel_register_query_string (p, &buf, &buf_data); } msleep (1000/rate); diff --git a/sim_frontpanel.h b/sim_frontpanel.h index 9dfc8096..04ef6da0 100644 --- a/sim_frontpanel.h +++ b/sim_frontpanel.h @@ -40,6 +40,28 @@ extern "C" { #include +/** + + sim_panel_start_simulator A starts a simulatir with a particular + configuration + + sim_path the path to the simulator binary + sim_config the configuration to run the simulator with + device_panel_count the number of sub panels for connected devices + + Note 1: - The path specified must be either a fully specified path or + it could be merey the simulator name if the simulator binary + is located in the current PATH. + - The simulator binary must be built from the same version + simh source code that the frontpanel API was acquired fron + (the API and the simh framework must speak the same language) + + 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; PANEL * @@ -47,22 +69,84 @@ sim_panel_start_simulator (const char *sim_path, const char *sim_config, size_t device_panel_count); +/** + + sim_panel_add_device_panel - creates a sub panel associated + with a specific simulator panel + + 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); +/** + + sim_panel_destroy to shutdown a panel or sub panel. + + Note: destroying a simulator panel will also destroy any + related sub panels + + */ int sim_panel_destroy (PANEL *panel); +/** + + The frontpanel API exposes the state of a simulator via access to + simh register variables that the simulator and its devices define. + These registers certainly include any architecturally described + registers (PC, PSL, SP, etc.), but also include anything else + the simulator uses as internal state to implement the running + simulator. + + The registers that a particular frontpanel application mught need + access to are described by the application by calling: + + sim_pabel_add_register + + name the name the simulator knows this register by + size the size (in local storage) of the buffer which will + 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 + + */ int sim_panel_add_register (PANEL *panel, const char *name, size_t size, void *addr); +/** + + 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. + + 1) The values can be polled (when ever it is desired) by calling + sim_panel_get_registers(). + 2) The panel can call sim_panel_set_display_callback() to specify a + callback routine and a periodic rate that the callback routine + should be called. The panel API will make a best effort to deliver + the current register state at the desired rate. + + + Note 1: The buffers described in a panel's register set will be dynamically + revised as soon as data is available from the simulator. The + callback routine merely serves as a notification that a complete + register set has arrived. + + */ int sim_panel_get_registers (PANEL *panel); +/** + + + */ typedef void (*PANEL_DISPLAY_PCALLBACK)(PANEL *panel, void *context); @@ -72,6 +156,18 @@ sim_panel_set_display_callback (PANEL *panel, void *context, int callbacks_per_second); +/** + + When a front panel application needs to change the running + state of a simulator one of the following routines should + be called: + + sim_panel_exec_halt - Stop instruction execution + 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); @@ -84,22 +180,55 @@ sim_panel_exec_run (PANEL *panel); int sim_panel_exec_step (PANEL *panel); +/** + sim_panel_set_register_value + + name the name of a simulator register which is to receive + a new value + 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, const char *name, const char *value); + typedef enum { - Halt, - Run + Halt, /* Simulation is halted (instructions not being executed) */ + Run, /* Simulation is executing instructions */ + Error /* Panel simulator is in an error state and should be */ + /* closed (destroyed). sim_panel_get_error might help */ + /* explain why */ } OperationalState; OperationalState sim_panel_get_state (PANEL *panel); +/** + + All APIs routines which return an int return 0 for + success and -1 for an error. + + 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); void sim_panel_clear_error (void); +/** + + The panek<->simulator wire protocol can be traced if protocol problems arise. + + sim_panel_set_debug_file - Specifies the log file to record debug traffic + sim_panel_set_debug_mode - Specifies the debug detail to be recorded + sim_panel_flush_debug - Flushes debug output to disk + + */ void sim_panel_set_debug_file (PANEL *panel, const char *debug_file);