FRONTPANEL: Added comments describing the frontpanel API use. Added Error state to a panel which reflects a panel which is currently non-operational and which hopefully will be indicated by calling sim_panel_get_error
This commit is contained in:
parent
d83060938e
commit
e1b7bb3b56
2 changed files with 153 additions and 14 deletions
|
@ -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)
|
||||
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);
|
||||
|
|
133
sim_frontpanel.h
133
sim_frontpanel.h
|
@ -40,6 +40,28 @@ extern "C" {
|
|||
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
|
||||
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);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue