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) {
|
if (p->sock == INVALID_SOCKET) {
|
||||||
sim_panel_set_error ("Invalid Socket for write");
|
sim_panel_set_error ("Invalid Socket for write");
|
||||||
|
p->State = Error;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
pthread_mutex_lock (&p->io_send_lock);
|
pthread_mutex_lock (&p->io_send_lock);
|
||||||
|
@ -276,6 +277,7 @@ while (len) {
|
||||||
int bsent = sim_write_sock (p->sock, msg, len);
|
int bsent = sim_write_sock (p->sock, msg, len);
|
||||||
if (bsent < 0) {
|
if (bsent < 0) {
|
||||||
sim_panel_set_error ("%s", sim_get_err_sock("Error writing to socket"));
|
sim_panel_set_error ("%s", sim_get_err_sock("Error writing to socket"));
|
||||||
|
p->State = Error;
|
||||||
pthread_mutex_unlock (&p->io_send_lock);
|
pthread_mutex_unlock (&p->io_send_lock);
|
||||||
return bsent;
|
return bsent;
|
||||||
}
|
}
|
||||||
|
@ -305,6 +307,7 @@ if (buf_needed > *buf_size) {
|
||||||
free (*buf);
|
free (*buf);
|
||||||
*buf = (char *)_panel_malloc (buf_needed);
|
*buf = (char *)_panel_malloc (buf_needed);
|
||||||
if (!*buf) {
|
if (!*buf) {
|
||||||
|
panel->State = Error;
|
||||||
pthread_mutex_unlock (&panel->io_lock);
|
pthread_mutex_unlock (&panel->io_lock);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -640,6 +643,7 @@ if (panel) {
|
||||||
free (panel->devices);
|
free (panel->devices);
|
||||||
panel->devices = NULL;
|
panel->devices = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
_panel_deregister_panel (panel);
|
_panel_deregister_panel (panel);
|
||||||
free (panel->name);
|
free (panel->name);
|
||||||
free (panel->config);
|
free (panel->config);
|
||||||
|
@ -713,19 +717,22 @@ sim_panel_add_register (PANEL *panel,
|
||||||
{
|
{
|
||||||
REG *regs, *reg;
|
REG *regs, *reg;
|
||||||
|
|
||||||
if (!panel) {
|
if (!panel || (panel->State == Error)) {
|
||||||
sim_panel_set_error ("Invalid Panel");
|
sim_panel_set_error ("Invalid Panel");
|
||||||
return -1;
|
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;
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
pthread_mutex_lock (&panel->io_lock);
|
pthread_mutex_lock (&panel->io_lock);
|
||||||
memcpy (regs, panel->regs, panel->reg_count*sizeof(*regs));
|
memcpy (regs, panel->regs, panel->reg_count*sizeof(*regs));
|
||||||
reg = ®s[panel->reg_count];
|
reg = ®s[panel->reg_count];
|
||||||
memset (reg, 0, sizeof(*regs));
|
memset (reg, 0, sizeof(*regs));
|
||||||
reg->name = (char *)_panel_malloc (1 + strlen (name));
|
reg->name = (char *)_panel_malloc (1 + strlen (name));
|
||||||
if (reg->name == NULL) {
|
if (reg->name == NULL) {
|
||||||
|
panel->State = Error;
|
||||||
free (regs);
|
free (regs);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -745,7 +752,7 @@ return 0;
|
||||||
int
|
int
|
||||||
sim_panel_get_registers (PANEL *panel)
|
sim_panel_get_registers (PANEL *panel)
|
||||||
{
|
{
|
||||||
if (!panel) {
|
if ((!panel) || (panel->State == Error)) {
|
||||||
sim_panel_set_error ("Invalid Panel");
|
sim_panel_set_error ("Invalid Panel");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -808,7 +815,7 @@ return 0;
|
||||||
int
|
int
|
||||||
sim_panel_exec_halt (PANEL *panel)
|
sim_panel_exec_halt (PANEL *panel)
|
||||||
{
|
{
|
||||||
if (!panel) {
|
if (!panel || (panel->State == Error)) {
|
||||||
sim_panel_set_error ("Invalid Panel");
|
sim_panel_set_error ("Invalid Panel");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -822,7 +829,7 @@ return 0;
|
||||||
int
|
int
|
||||||
sim_panel_exec_boot (PANEL *panel, const char *device)
|
sim_panel_exec_boot (PANEL *panel, const char *device)
|
||||||
{
|
{
|
||||||
if (!panel) {
|
if (!panel || (panel->State == Error)) {
|
||||||
sim_panel_set_error ("Invalid Panel");
|
sim_panel_set_error ("Invalid Panel");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -839,7 +846,7 @@ return 0;
|
||||||
int
|
int
|
||||||
sim_panel_exec_run (PANEL *panel)
|
sim_panel_exec_run (PANEL *panel)
|
||||||
{
|
{
|
||||||
if (!panel) {
|
if (!panel || (panel->State == Error)) {
|
||||||
sim_panel_set_error ("Invalid Panel");
|
sim_panel_set_error ("Invalid Panel");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -856,7 +863,7 @@ return 0;
|
||||||
int
|
int
|
||||||
sim_panel_exec_step (PANEL *panel)
|
sim_panel_exec_step (PANEL *panel)
|
||||||
{
|
{
|
||||||
if (!panel) {
|
if (!panel || (panel->State == Error)) {
|
||||||
sim_panel_set_error ("Invalid Panel");
|
sim_panel_set_error ("Invalid Panel");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -876,7 +883,7 @@ sim_panel_set_register_value (PANEL *panel,
|
||||||
const char *name,
|
const char *name,
|
||||||
const char *value)
|
const char *value)
|
||||||
{
|
{
|
||||||
if (!panel) {
|
if (!panel || (panel->State == Error)) {
|
||||||
sim_panel_set_error ("Invalid Panel");
|
sim_panel_set_error ("Invalid Panel");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -909,7 +916,8 @@ pthread_setschedparam (pthread_self(), sched_policy, &sched_priority);
|
||||||
pthread_mutex_lock (&p->io_lock);
|
pthread_mutex_lock (&p->io_lock);
|
||||||
p->io_thread_running = 1;
|
p->io_thread_running = 1;
|
||||||
pthread_cond_signal (&p->startup_cond); /* Signal we're ready to go */
|
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;
|
int new_data;
|
||||||
char *s, *e, *eol;
|
char *s, *e, *eol;
|
||||||
|
|
||||||
|
@ -918,6 +926,7 @@ while (p->sock != INVALID_SOCKET) {
|
||||||
if (new_data <= 0) {
|
if (new_data <= 0) {
|
||||||
sim_panel_set_error ("%s", sim_get_err_sock("Unexpected socket read"));
|
sim_panel_set_error ("%s", sim_get_err_sock("Unexpected socket read"));
|
||||||
_panel_debug (p, DBG_RCV, "%s", NULL, 0, sim_panel_get_error());
|
_panel_debug (p, DBG_RCV, "%s", NULL, 0, sim_panel_get_error());
|
||||||
|
p->State = Error;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_panel_debug (p, DBG_RCV, "Received:", &buf[buf_data], new_data);
|
_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;
|
p->callback_thread_running = 1;
|
||||||
pthread_cond_signal (&p->startup_cond); /* Signal we're ready to go */
|
pthread_cond_signal (&p->startup_cond); /* Signal we're ready to go */
|
||||||
while ((p->sock != INVALID_SOCKET) &&
|
while ((p->sock != INVALID_SOCKET) &&
|
||||||
(p->callbacks_per_second)) {
|
(p->callbacks_per_second) &&
|
||||||
|
(p->State != Error)) {
|
||||||
int rate = p->callbacks_per_second;
|
int rate = p->callbacks_per_second;
|
||||||
pthread_mutex_unlock (&p->io_lock);
|
pthread_mutex_unlock (&p->io_lock);
|
||||||
|
|
||||||
++callback_count;
|
++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);
|
_panel_register_query_string (p, &buf, &buf_data);
|
||||||
}
|
}
|
||||||
msleep (1000/rate);
|
msleep (1000/rate);
|
||||||
|
|
133
sim_frontpanel.h
133
sim_frontpanel.h
|
@ -40,6 +40,28 @@ extern "C" {
|
||||||
|
|
||||||
#include <stdlib.h>
|
#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;
|
typedef struct PANEL PANEL;
|
||||||
|
|
||||||
PANEL *
|
PANEL *
|
||||||
|
@ -47,22 +69,84 @@ sim_panel_start_simulator (const char *sim_path,
|
||||||
const char *sim_config,
|
const char *sim_config,
|
||||||
size_t device_panel_count);
|
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 *
|
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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
sim_panel_destroy to shutdown a panel or sub panel.
|
||||||
|
|
||||||
|
Note: destroying a simulator panel will also destroy any
|
||||||
|
related sub panels
|
||||||
|
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
sim_panel_destroy (PANEL *panel);
|
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
|
int
|
||||||
sim_panel_add_register (PANEL *panel,
|
sim_panel_add_register (PANEL *panel,
|
||||||
const char *name,
|
const char *name,
|
||||||
size_t size,
|
size_t size,
|
||||||
void *addr);
|
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
|
int
|
||||||
sim_panel_get_registers (PANEL *panel);
|
sim_panel_get_registers (PANEL *panel);
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
typedef void (*PANEL_DISPLAY_PCALLBACK)(PANEL *panel,
|
typedef void (*PANEL_DISPLAY_PCALLBACK)(PANEL *panel,
|
||||||
void *context);
|
void *context);
|
||||||
|
|
||||||
|
@ -72,6 +156,18 @@ sim_panel_set_display_callback (PANEL *panel,
|
||||||
void *context,
|
void *context,
|
||||||
int callbacks_per_second);
|
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
|
int
|
||||||
sim_panel_exec_halt (PANEL *panel);
|
sim_panel_exec_halt (PANEL *panel);
|
||||||
|
|
||||||
|
@ -84,22 +180,55 @@ sim_panel_exec_run (PANEL *panel);
|
||||||
int
|
int
|
||||||
sim_panel_exec_step (PANEL *panel);
|
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
|
int
|
||||||
sim_panel_set_register_value (PANEL *panel,
|
sim_panel_set_register_value (PANEL *panel,
|
||||||
const char *name,
|
const char *name,
|
||||||
const char *value);
|
const char *value);
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
Halt,
|
Halt, /* Simulation is halted (instructions not being executed) */
|
||||||
Run
|
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;
|
||||||
|
|
||||||
OperationalState
|
OperationalState
|
||||||
sim_panel_get_state (PANEL *panel);
|
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);
|
const char *sim_panel_get_error (void);
|
||||||
void sim_panel_clear_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
|
void
|
||||||
sim_panel_set_debug_file (PANEL *panel, const char *debug_file);
|
sim_panel_set_debug_file (PANEL *panel, const char *debug_file);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue