FRONTPANEL: General Enhancements
- added verification of the existence of simulator registers which they are referenced. - sim_frontpanel API version checking to make sure that the invoking API and the simulator support the same capabilities. - added the ability for a simulator to reference data in simh register data which is not in the set of registers defined in the default simh device (usually the CPU). - added a simulator time reference relating to a set of register data which is provided. - added example automatically creating a console terminal port from a simulator startup (front panel or not).
This commit is contained in:
parent
26ef9b566a
commit
059a54152a
4 changed files with 272 additions and 81 deletions
|
@ -59,7 +59,7 @@ const char *sim_config =
|
||||||
unsigned int PC, SP, FP, AP, R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11;
|
unsigned int PC, SP, FP, AP, R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
DisplayCallback (PANEL *panel, void *context)
|
DisplayCallback (PANEL *panel, unsigned long long simulation_time, void *context)
|
||||||
{
|
{
|
||||||
char buf1[100], buf2[100], buf3[100];
|
char buf1[100], buf2[100], buf3[100];
|
||||||
static const char *states[] = {"Halt", "Run "};
|
static const char *states[] = {"Halt", "Run "};
|
||||||
|
@ -139,6 +139,15 @@ if ((f = fopen (sim_config, "w"))) {
|
||||||
fprintf (f, "set cpu 64\n");
|
fprintf (f, "set cpu 64\n");
|
||||||
fprintf (f, "set console telnet=buffered\n");
|
fprintf (f, "set console telnet=buffered\n");
|
||||||
fprintf (f, "set console telnet=1927\n");
|
fprintf (f, "set console telnet=1927\n");
|
||||||
|
/* Start a terminal emulator for the console port */
|
||||||
|
#if defined(_WIN32)
|
||||||
|
fprintf (f, "set env PATH=%%PATH%%;%%ProgramFiles%%\\PuTTY;%%ProgramFiles(x86)%%\\PuTTY\n");
|
||||||
|
fprintf (f, "! start PuTTY telnet://localhost:1927\n");
|
||||||
|
#elif defined(__linux) || defined(__linux__)
|
||||||
|
fprintf (f, "! xterm -e 'telnet localhost 1927' &\n");
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
fprintf (f, "! osascript -e 'tell application \"Terminal\" to do script \"telnet localhost 1927; exit\"'\n");
|
||||||
|
#endif
|
||||||
fclose (f);
|
fclose (f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,80 +174,84 @@ if (!tape) {
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sim_panel_add_register (panel, "PC", sizeof(PC), &PC)) {
|
if (!sim_panel_add_register (panel, "ZPC", NULL, sizeof(PC), &PC)) {
|
||||||
|
printf ("Unexpecdted success adding non-existent register 'ZPC'\n");
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
if (sim_panel_add_register (panel, "PC", NULL, sizeof(PC), &PC)) {
|
||||||
printf ("Error adding register 'PC': %s\n", sim_panel_get_error());
|
printf ("Error adding register 'PC': %s\n", sim_panel_get_error());
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
if (sim_panel_add_register (panel, "SP", sizeof(SP), &SP)) {
|
if (sim_panel_add_register (panel, "SP", NULL, sizeof(SP), &SP)) {
|
||||||
printf ("Error adding register 'SP': %s\n", sim_panel_get_error());
|
printf ("Error adding register 'SP': %s\n", sim_panel_get_error());
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
if (sim_panel_add_register (panel, "FP", sizeof(FP), &FP)) {
|
if (sim_panel_add_register (panel, "FP", "CPU", sizeof(FP), &FP)) {
|
||||||
printf ("Error adding register 'FP': %s\n", sim_panel_get_error());
|
printf ("Error adding register 'FP': %s\n", sim_panel_get_error());
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
if (sim_panel_add_register (panel, "AP", sizeof(SP), &AP)) {
|
if (sim_panel_add_register (panel, "AP", NULL, sizeof(SP), &AP)) {
|
||||||
printf ("Error adding register 'AP': %s\n", sim_panel_get_error());
|
printf ("Error adding register 'AP': %s\n", sim_panel_get_error());
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
if (sim_panel_add_register (panel, "R0", sizeof(R0), &R0)) {
|
if (sim_panel_add_register (panel, "R0", NULL, sizeof(R0), &R0)) {
|
||||||
printf ("Error adding register 'R0': %s\n", sim_panel_get_error());
|
printf ("Error adding register 'R0': %s\n", sim_panel_get_error());
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
if (sim_panel_add_register (panel, "R1", sizeof(R1), &R1)) {
|
if (sim_panel_add_register (panel, "R1", NULL, sizeof(R1), &R1)) {
|
||||||
printf ("Error adding register 'R1': %s\n", sim_panel_get_error());
|
printf ("Error adding register 'R1': %s\n", sim_panel_get_error());
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
if (sim_panel_add_register (panel, "R2", sizeof(R2), &R2)) {
|
if (sim_panel_add_register (panel, "R2", NULL, sizeof(R2), &R2)) {
|
||||||
printf ("Error adding register 'R2': %s\n", sim_panel_get_error());
|
printf ("Error adding register 'R2': %s\n", sim_panel_get_error());
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
if (sim_panel_add_register (panel, "R3", sizeof(R3), &R3)) {
|
if (sim_panel_add_register (panel, "R3", NULL, sizeof(R3), &R3)) {
|
||||||
printf ("Error adding register 'R3': %s\n", sim_panel_get_error());
|
printf ("Error adding register 'R3': %s\n", sim_panel_get_error());
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
if (sim_panel_add_register (panel, "R4", sizeof(R4), &R4)) {
|
if (sim_panel_add_register (panel, "R4", NULL, sizeof(R4), &R4)) {
|
||||||
printf ("Error adding register 'R4': %s\n", sim_panel_get_error());
|
printf ("Error adding register 'R4': %s\n", sim_panel_get_error());
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
if (sim_panel_add_register (panel, "R5", sizeof(R5), &R5)) {
|
if (sim_panel_add_register (panel, "R5", NULL, sizeof(R5), &R5)) {
|
||||||
printf ("Error adding register 'R5': %s\n", sim_panel_get_error());
|
printf ("Error adding register 'R5': %s\n", sim_panel_get_error());
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
if (sim_panel_add_register (panel, "R6", sizeof(R6), &R6)) {
|
if (sim_panel_add_register (panel, "R6", NULL, sizeof(R6), &R6)) {
|
||||||
printf ("Error adding register 'R6': %s\n", sim_panel_get_error());
|
printf ("Error adding register 'R6': %s\n", sim_panel_get_error());
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
if (sim_panel_add_register (panel, "R7", sizeof(R7), &R7)) {
|
if (sim_panel_add_register (panel, "R7", NULL, sizeof(R7), &R7)) {
|
||||||
printf ("Error adding register 'R7': %s\n", sim_panel_get_error());
|
printf ("Error adding register 'R7': %s\n", sim_panel_get_error());
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
if (sim_panel_add_register (panel, "R8", sizeof(R8), &R8)) {
|
if (sim_panel_add_register (panel, "R8", NULL, sizeof(R8), &R8)) {
|
||||||
printf ("Error adding register 'R8': %s\n", sim_panel_get_error());
|
printf ("Error adding register 'R8': %s\n", sim_panel_get_error());
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
if (sim_panel_add_register (panel, "R9", sizeof(R9), &R9)) {
|
if (sim_panel_add_register (panel, "R9", NULL, sizeof(R9), &R9)) {
|
||||||
printf ("Error adding register 'R9': %s\n", sim_panel_get_error());
|
printf ("Error adding register 'R9': %s\n", sim_panel_get_error());
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
if (sim_panel_add_register (panel, "R10", sizeof(R10), &R10)) {
|
if (sim_panel_add_register (panel, "R10", NULL, sizeof(R10), &R10)) {
|
||||||
printf ("Error adding register 'R10': %s\n", sim_panel_get_error());
|
printf ("Error adding register 'R10': %s\n", sim_panel_get_error());
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
if (sim_panel_add_register (panel, "R11", sizeof(R11), &R11)) {
|
if (sim_panel_add_register (panel, "R11", NULL, sizeof(R11), &R11)) {
|
||||||
printf ("Error adding register 'R11': %s\n", sim_panel_get_error());
|
printf ("Error adding register 'R11': %s\n", sim_panel_get_error());
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
if (sim_panel_get_registers (panel)) {
|
if (sim_panel_get_registers (panel, NULL)) {
|
||||||
printf ("Error getting register data: %s\n", sim_panel_get_error());
|
printf ("Error getting register data: %s\n", sim_panel_get_error());
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
DisplayCallback (panel, NULL);
|
DisplayCallback (panel, 0ll, NULL);
|
||||||
if (sim_panel_set_display_callback (panel, &DisplayCallback, NULL, 5)) {
|
if (sim_panel_set_display_callback (panel, &DisplayCallback, NULL, 5)) {
|
||||||
printf ("Error setting automatic display callback: %s\n", sim_panel_get_error());
|
printf ("Error setting automatic display callback: %s\n", sim_panel_get_error());
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
if (!sim_panel_get_registers (panel)) {
|
if (!sim_panel_get_registers (panel, NULL)) {
|
||||||
printf ("Unexpected success getting register data: %s\n", sim_panel_get_error());
|
printf ("Unexpected success getting register data: %s\n", sim_panel_get_error());
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
|
|
6
scp.c
6
scp.c
|
@ -225,6 +225,7 @@
|
||||||
#include "sim_video.h"
|
#include "sim_video.h"
|
||||||
#endif
|
#endif
|
||||||
#include "sim_sock.h"
|
#include "sim_sock.h"
|
||||||
|
#include "sim_frontpanel.h"
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
@ -4246,6 +4247,9 @@ if (flag) {
|
||||||
#endif
|
#endif
|
||||||
#if defined (SIM_ASYNCH_CLOCKS)
|
#if defined (SIM_ASYNCH_CLOCKS)
|
||||||
fprintf (st, "\n\t\tAsynchronous Clock support");
|
fprintf (st, "\n\t\tAsynchronous Clock support");
|
||||||
|
#endif
|
||||||
|
#if defined (SIM_FRONTPANEL_VERSION)
|
||||||
|
fprintf (st, "\n\t\tFrontPanel API Version %d", SIM_FRONTPANEL_VERSION);
|
||||||
#endif
|
#endif
|
||||||
fprintf (st, "\n\tHost Platform:");
|
fprintf (st, "\n\tHost Platform:");
|
||||||
#if defined (__GNUC__) && defined (__VERSION__)
|
#if defined (__GNUC__) && defined (__VERSION__)
|
||||||
|
@ -4418,7 +4422,7 @@ t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr)
|
||||||
{
|
{
|
||||||
if (cptr && (*cptr != 0))
|
if (cptr && (*cptr != 0))
|
||||||
return SCPE_2MARG;
|
return SCPE_2MARG;
|
||||||
fprintf (st, "Time:\t%.0f\n", sim_time);
|
fprintf (st, "Time:\t%.0f\n", sim_gtime());
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
231
sim_frontpanel.c
231
sim_frontpanel.c
|
@ -108,24 +108,27 @@ return 0;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *name;
|
char *name;
|
||||||
|
char *device_name;
|
||||||
void *addr;
|
void *addr;
|
||||||
size_t size;
|
size_t size;
|
||||||
} REG;
|
} REG;
|
||||||
|
|
||||||
struct PANEL {
|
struct PANEL {
|
||||||
PANEL *parent; /* Device Panels can have parent panels */
|
PANEL *parent; /* Device Panels can have parent panels */
|
||||||
char *name; /* simulator path or device name */
|
char *path; /* simulator path */
|
||||||
char *config;
|
char *config;
|
||||||
|
char *device_name; /* device name */
|
||||||
char *temp_config;
|
char *temp_config;
|
||||||
char hostport[64];
|
char hostport[64];
|
||||||
size_t device_count;
|
size_t device_count;
|
||||||
PANEL **devices;
|
PANEL **devices;
|
||||||
SOCKET sock;
|
SOCKET sock;
|
||||||
int reg_count;
|
size_t reg_count;
|
||||||
REG *regs;
|
REG *regs;
|
||||||
char *reg_query;
|
char *reg_query;
|
||||||
size_t reg_query_size;
|
size_t reg_query_size;
|
||||||
OperationalState State;
|
OperationalState State;
|
||||||
|
unsigned long long simulation_time;
|
||||||
pthread_mutex_t lock;
|
pthread_mutex_t lock;
|
||||||
pthread_t io_thread;
|
pthread_t io_thread;
|
||||||
int io_thread_running;
|
int io_thread_running;
|
||||||
|
@ -133,6 +136,9 @@ struct PANEL {
|
||||||
pthread_mutex_t io_send_lock;
|
pthread_mutex_t io_send_lock;
|
||||||
int io_reg_query_pending;
|
int io_reg_query_pending;
|
||||||
int io_waiting;
|
int io_waiting;
|
||||||
|
char *io_response;
|
||||||
|
size_t io_response_data;
|
||||||
|
size_t io_response_size;
|
||||||
pthread_cond_t io_done;
|
pthread_cond_t io_done;
|
||||||
pthread_cond_t startup_cond;
|
pthread_cond_t startup_cond;
|
||||||
PANEL_DISPLAY_PCALLBACK callback;
|
PANEL_DISPLAY_PCALLBACK callback;
|
||||||
|
@ -141,6 +147,7 @@ struct PANEL {
|
||||||
void *callback_context;
|
void *callback_context;
|
||||||
int callbacks_per_second;
|
int callbacks_per_second;
|
||||||
int debug;
|
int debug;
|
||||||
|
char *simulator_version;
|
||||||
FILE *Debug;
|
FILE *Debug;
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
HANDLE hProcess;
|
HANDLE hProcess;
|
||||||
|
@ -150,7 +157,9 @@ struct PANEL {
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *sim_prompt = "sim> ";
|
static const char *sim_prompt = "sim> ";
|
||||||
|
static const char *register_get_prefix = "show time";
|
||||||
static const char *register_get_echo = "# REGISTERS-DONE";
|
static const char *register_get_echo = "# REGISTERS-DONE";
|
||||||
|
static const char *register_dev_echo = "# REGISTERS-FOR-DEVICE:";
|
||||||
static const char *command_done_echo = "# COMMAND-DONE";
|
static const char *command_done_echo = "# COMMAND-DONE";
|
||||||
static int little_endian;
|
static int little_endian;
|
||||||
static void *_panel_reader(void *arg);
|
static void *_panel_reader(void *arg);
|
||||||
|
@ -324,17 +333,18 @@ return sent;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_panel_sendf (PANEL *p, int wait_for_completion, const char *fmt, ...);
|
_panel_sendf (PANEL *p, int wait_for_completion, char **response, const char *fmt, ...);
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_panel_register_query_string (PANEL *panel, char **buf, size_t *buf_size)
|
_panel_register_query_string (PANEL *panel, char **buf, size_t *buf_size)
|
||||||
{
|
{
|
||||||
int i;
|
size_t i, j, buf_data, buf_needed = 0;
|
||||||
size_t buf_data, buf_needed = 0;
|
char *dev;
|
||||||
|
|
||||||
pthread_mutex_lock (&panel->io_lock);
|
pthread_mutex_lock (&panel->io_lock);
|
||||||
|
buf_needed = 2 + strlen (register_get_prefix); /* SHOW TIME */
|
||||||
for (i=0; i<panel->reg_count; i++)
|
for (i=0; i<panel->reg_count; i++)
|
||||||
buf_needed += 7 + strlen (panel->regs[i].name);
|
buf_needed += 9 + strlen (panel->regs[i].name) + (panel->regs[i].device_name ? strlen (panel->regs[i].device_name) : 0);
|
||||||
buf_needed += 10 + strlen (register_get_echo); /* # REGISTERS-DONE */
|
buf_needed += 10 + strlen (register_get_echo); /* # REGISTERS-DONE */
|
||||||
if (buf_needed > *buf_size) {
|
if (buf_needed > *buf_size) {
|
||||||
free (*buf);
|
free (*buf);
|
||||||
|
@ -347,21 +357,40 @@ if (buf_needed > *buf_size) {
|
||||||
*buf_size = buf_needed;
|
*buf_size = buf_needed;
|
||||||
}
|
}
|
||||||
buf_data = 0;
|
buf_data = 0;
|
||||||
#if SEPARATE_REGISTERS
|
sprintf (*buf + buf_data, "%s\r", register_get_prefix);
|
||||||
for (i=0; i<panel->reg_count; i++) {
|
|
||||||
sprintf (*buf + buf_data, "E -H %s\r", panel->regs[i].name);
|
|
||||||
buf_data += strlen (*buf + buf_data);
|
buf_data += strlen (*buf + buf_data);
|
||||||
|
dev = "";
|
||||||
|
for (i=j=0; i<panel->reg_count; i++) {
|
||||||
|
char *reg_dev = panel->regs[i].device_name ? panel->regs[i].device_name : "";
|
||||||
|
|
||||||
|
if (strcmp (dev, reg_dev)) {/* devices are different */
|
||||||
|
char *tbuf;
|
||||||
|
|
||||||
|
buf_needed += 4 + strlen (register_dev_echo) + strlen (reg_dev); /* # REGISTERS-for-DEVICE:XXX */
|
||||||
|
tbuf = (char *)_panel_malloc (buf_needed);
|
||||||
|
if (tbuf == NULL) {
|
||||||
|
panel->State = Error;
|
||||||
|
pthread_mutex_unlock (&panel->io_lock);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
#else
|
strcpy (tbuf, *buf);
|
||||||
sprintf (*buf + buf_data, "E -H ");
|
free (*buf);
|
||||||
|
*buf = tbuf;
|
||||||
|
sprintf (*buf + buf_data, "%s%s%s\r", (i == 0)? "" : "\r", register_dev_echo, reg_dev);
|
||||||
buf_data += strlen (*buf + buf_data);
|
buf_data += strlen (*buf + buf_data);
|
||||||
for (i=0; i<panel->reg_count; i++) {
|
dev = reg_dev;
|
||||||
sprintf (*buf + buf_data, "%s%s", (i>0) ? "," : "", panel->regs[i].name);
|
j = 0;
|
||||||
|
*buf_size = buf_needed;
|
||||||
|
}
|
||||||
|
if (j == 0)
|
||||||
|
sprintf (*buf + buf_data, "E -H %s %s", dev, panel->regs[i].name);
|
||||||
|
else
|
||||||
|
sprintf (*buf + buf_data, ",%s", panel->regs[i].name);
|
||||||
|
++j;
|
||||||
buf_data += strlen (*buf + buf_data);
|
buf_data += strlen (*buf + buf_data);
|
||||||
}
|
}
|
||||||
strcpy (*buf + buf_data, "\r");
|
strcpy (*buf + buf_data, "\r");
|
||||||
buf_data += strlen (*buf + buf_data);
|
buf_data += strlen (*buf + buf_data);
|
||||||
#endif
|
|
||||||
strcpy (*buf + buf_data, register_get_echo);
|
strcpy (*buf + buf_data, register_get_echo);
|
||||||
buf_data += strlen (*buf + buf_data);
|
buf_data += strlen (*buf + buf_data);
|
||||||
strcpy (*buf + buf_data, "\r");
|
strcpy (*buf + buf_data, "\r");
|
||||||
|
@ -461,10 +490,10 @@ if (p == NULL)
|
||||||
goto Error_Return;
|
goto Error_Return;
|
||||||
memset (p, 0, sizeof(*p));
|
memset (p, 0, sizeof(*p));
|
||||||
p->sock = INVALID_SOCKET;
|
p->sock = INVALID_SOCKET;
|
||||||
p->name = (char *)_panel_malloc (strlen (sim_path) + 1);
|
p->path = (char *)_panel_malloc (strlen (sim_path) + 1);
|
||||||
if (p->name == NULL)
|
if (p->path == NULL)
|
||||||
goto Error_Return;
|
goto Error_Return;
|
||||||
strcpy (p->name, sim_path);
|
strcpy (p->path, sim_path);
|
||||||
p->config = (char *)_panel_malloc (strlen (sim_config) + 1);
|
p->config = (char *)_panel_malloc (strlen (sim_config) + 1);
|
||||||
if (p->config == NULL)
|
if (p->config == NULL)
|
||||||
goto Error_Return;
|
goto Error_Return;
|
||||||
|
@ -577,6 +606,22 @@ if (device_panel_count) {
|
||||||
memset (p->devices, 0, device_panel_count*sizeof(*p->devices));
|
memset (p->devices, 0, device_panel_count*sizeof(*p->devices));
|
||||||
p->device_count = device_panel_count;
|
p->device_count = device_panel_count;
|
||||||
}
|
}
|
||||||
|
msleep (1000);
|
||||||
|
/* Validate existence of requested register */
|
||||||
|
if (_panel_sendf (p, 1, &p->simulator_version, "SHOW VERSION\r")) {
|
||||||
|
goto Error_Return;
|
||||||
|
}
|
||||||
|
if (1) {
|
||||||
|
int api_version = 0;
|
||||||
|
char *c = strstr (p->simulator_version, "FrontPanel API Version");
|
||||||
|
|
||||||
|
if ((!c) ||
|
||||||
|
(1 != sscanf (c, "FrontPanel API Version %d", &api_version)) ||
|
||||||
|
(api_version != SIM_FRONTPANEL_VERSION)) {
|
||||||
|
sim_panel_set_error ("Inconsistent sim_frontpanel API version %d in simulator. Version %d needed.-", api_version, SIM_FRONTPANEL_VERSION);
|
||||||
|
goto Error_Return;
|
||||||
|
}
|
||||||
|
}
|
||||||
_panel_register_panel (p);
|
_panel_register_panel (p);
|
||||||
return p;
|
return p;
|
||||||
|
|
||||||
|
@ -608,13 +653,17 @@ for (device_num=0; device_num < simulator_panel->device_count; ++device_num)
|
||||||
if (simulator_panel->devices[device_num] == NULL)
|
if (simulator_panel->devices[device_num] == NULL)
|
||||||
break;
|
break;
|
||||||
if (device_num == simulator_panel->device_count) {
|
if (device_num == simulator_panel->device_count) {
|
||||||
sim_panel_set_error ("No free panel devices slots available %s simulator. All %d slots are used.", simulator_panel->name, (int)simulator_panel->device_count);
|
sim_panel_set_error ("No free panel devices slots available %s simulator. All %d slots are used.", simulator_panel->path, (int)simulator_panel->device_count);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
p = (PANEL *)_panel_malloc (sizeof(*p));
|
p = (PANEL *)_panel_malloc (sizeof(*p));
|
||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
goto Error_Return;
|
goto Error_Return;
|
||||||
memset (p, 0, sizeof(*p));
|
memset (p, 0, sizeof(*p));
|
||||||
|
p->device_name = (char *)_panel_malloc (1 + strlen (device_name));
|
||||||
|
if (p->device_name == NULL)
|
||||||
|
goto Error_Return;
|
||||||
|
strcpy (p->device_name, device_name);
|
||||||
p->parent = simulator_panel;
|
p->parent = simulator_panel;
|
||||||
p->sock = INVALID_SOCKET;
|
p->sock = INVALID_SOCKET;
|
||||||
for (i=0; i<5; i++) {
|
for (i=0; i<5; i++) {
|
||||||
|
@ -665,7 +714,7 @@ sim_panel_destroy (PANEL *panel)
|
||||||
REG *reg;
|
REG *reg;
|
||||||
|
|
||||||
if (panel) {
|
if (panel) {
|
||||||
_panel_debug (panel, DBG_XMT|DBG_RCV, "Closing Panel %s\n", NULL, 0, panel->name);
|
_panel_debug (panel, DBG_XMT|DBG_RCV, "Closing Panel %s\n", NULL, 0, panel->device_name? panel->device_name : panel->path);
|
||||||
if (panel->devices) {
|
if (panel->devices) {
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
|
@ -678,7 +727,8 @@ if (panel) {
|
||||||
}
|
}
|
||||||
|
|
||||||
_panel_deregister_panel (panel);
|
_panel_deregister_panel (panel);
|
||||||
free (panel->name);
|
free (panel->path);
|
||||||
|
free (panel->device_name);
|
||||||
free (panel->config);
|
free (panel->config);
|
||||||
if (panel->sock != INVALID_SOCKET) {
|
if (panel->sock != INVALID_SOCKET) {
|
||||||
SOCKET sock = panel->sock;
|
SOCKET sock = panel->sock;
|
||||||
|
@ -724,10 +774,13 @@ if (panel) {
|
||||||
reg = panel->regs;
|
reg = panel->regs;
|
||||||
while (panel->reg_count--) {
|
while (panel->reg_count--) {
|
||||||
free (reg->name);
|
free (reg->name);
|
||||||
|
free (reg->device_name);
|
||||||
reg++;
|
reg++;
|
||||||
}
|
}
|
||||||
free (panel->regs);
|
free (panel->regs);
|
||||||
free (panel->reg_query);
|
free (panel->reg_query);
|
||||||
|
free (panel->io_response);
|
||||||
|
free (panel->simulator_version);
|
||||||
sim_cleanup_sock ();
|
sim_cleanup_sock ();
|
||||||
free (panel);
|
free (panel);
|
||||||
}
|
}
|
||||||
|
@ -745,10 +798,13 @@ return panel->State;
|
||||||
int
|
int
|
||||||
sim_panel_add_register (PANEL *panel,
|
sim_panel_add_register (PANEL *panel,
|
||||||
const char *name,
|
const char *name,
|
||||||
|
const char *device_name,
|
||||||
size_t size,
|
size_t size,
|
||||||
void *addr)
|
void *addr)
|
||||||
{
|
{
|
||||||
REG *regs, *reg;
|
REG *regs, *reg;
|
||||||
|
char *response = NULL;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
if (!panel || (panel->State == Error)) {
|
if (!panel || (panel->State == Error)) {
|
||||||
sim_panel_set_error ("Invalid Panel");
|
sim_panel_set_error ("Invalid Panel");
|
||||||
|
@ -770,8 +826,71 @@ if (reg->name == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
strcpy (reg->name, name);
|
strcpy (reg->name, name);
|
||||||
|
for (i=0; i<strlen (reg->name); i++) {
|
||||||
|
if (islower (reg->name[i]))
|
||||||
|
reg->name[i] = toupper (reg->name[i]);
|
||||||
|
}
|
||||||
|
if (device_name) {
|
||||||
|
reg->device_name = (char *)_panel_malloc (1 + strlen (device_name));
|
||||||
|
if (reg->device_name == NULL) {
|
||||||
|
free (reg->name);
|
||||||
|
panel->State = Error;
|
||||||
|
free (regs);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
strcpy (reg->device_name, device_name);
|
||||||
|
for (i=0; i<strlen (reg->device_name); i++) {
|
||||||
|
if (islower (reg->device_name[i]))
|
||||||
|
reg->device_name[i] = toupper (reg->device_name[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i=0; i<panel->reg_count; i++) {
|
||||||
|
char *t1 = (char *)_panel_malloc (2 + strlen (regs[i].name) + (regs[i].device_name? strlen (regs[i].device_name) : 0));
|
||||||
|
char *t2 = (char *)_panel_malloc (2 + strlen (reg->name) + (reg->device_name? strlen (reg->device_name) : 0));
|
||||||
|
|
||||||
|
if ((t1 == NULL) || (t2 == NULL)) {
|
||||||
|
free (t1);
|
||||||
|
free (t2);
|
||||||
|
free (reg->name);
|
||||||
|
free (reg->device_name);
|
||||||
|
panel->State = Error;
|
||||||
|
free (regs);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
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)) {
|
||||||
|
sim_panel_set_error ("Duplicate Register Declaration");
|
||||||
|
free (t1);
|
||||||
|
free (t2);
|
||||||
|
free (reg->name);
|
||||||
|
free (reg->device_name);
|
||||||
|
free (regs);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
free (t1);
|
||||||
|
free (t2);
|
||||||
|
}
|
||||||
reg->addr = addr;
|
reg->addr = addr;
|
||||||
reg->size = size;
|
reg->size = size;
|
||||||
|
pthread_mutex_unlock (&panel->io_lock);
|
||||||
|
/* Validate existence of requested register */
|
||||||
|
if (_panel_sendf (panel, 1, &response, "EXAMINE %s %s\r", device_name? device_name : "", name)) {
|
||||||
|
free (reg->name);
|
||||||
|
free (reg->device_name);
|
||||||
|
free (regs);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!strcmp ("Invalid argument\r\n", response)) {
|
||||||
|
sim_panel_set_error ("Invalid Register: %s %s", device_name? device_name : "", name);
|
||||||
|
free (response);
|
||||||
|
free (reg->name);
|
||||||
|
free (reg->device_name);
|
||||||
|
free (regs);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
free (response);
|
||||||
|
pthread_mutex_lock (&panel->io_lock);
|
||||||
++panel->reg_count;
|
++panel->reg_count;
|
||||||
free (panel->regs);
|
free (panel->regs);
|
||||||
panel->regs = regs;
|
panel->regs = regs;
|
||||||
|
@ -783,7 +902,7 @@ return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
sim_panel_get_registers (PANEL *panel)
|
sim_panel_get_registers (PANEL *panel, unsigned long long *simulation_time)
|
||||||
{
|
{
|
||||||
if ((!panel) || (panel->State == Error)) {
|
if ((!panel) || (panel->State == Error)) {
|
||||||
sim_panel_set_error ("Invalid Panel");
|
sim_panel_set_error ("Invalid Panel");
|
||||||
|
@ -806,6 +925,8 @@ if (panel->reg_query_size != _panel_send (panel, panel->reg_query, panel->reg_qu
|
||||||
panel->io_waiting = 1;
|
panel->io_waiting = 1;
|
||||||
while (panel->io_waiting)
|
while (panel->io_waiting)
|
||||||
pthread_cond_wait (&panel->io_done, &panel->io_lock);
|
pthread_cond_wait (&panel->io_done, &panel->io_lock);
|
||||||
|
if (simulation_time)
|
||||||
|
*simulation_time = panel->simulation_time;
|
||||||
pthread_mutex_unlock (&panel->io_lock);
|
pthread_mutex_unlock (&panel->io_lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -871,7 +992,7 @@ if (panel->State == Run) {
|
||||||
sim_panel_set_error ("Not Halted");
|
sim_panel_set_error ("Not Halted");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (_panel_sendf (panel, 0, "BOOT %s\r", device))
|
if (_panel_sendf (panel, 0, NULL, "BOOT %s\r", device))
|
||||||
return -1;
|
return -1;
|
||||||
panel->State = Run;
|
panel->State = Run;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -888,7 +1009,7 @@ if (panel->State == Run) {
|
||||||
sim_panel_set_error ("Not Halted");
|
sim_panel_set_error ("Not Halted");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (_panel_sendf (panel, 0, "CONT\r", 5))
|
if (_panel_sendf (panel, 0, NULL, "CONT\r", 5))
|
||||||
return -1;
|
return -1;
|
||||||
panel->State = Run;
|
panel->State = Run;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -925,7 +1046,7 @@ if (panel->callback) {
|
||||||
sim_panel_set_error ("Callback provides register data");
|
sim_panel_set_error ("Callback provides register data");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (_panel_sendf (panel, 1, "D %s %s", name, value))
|
if (_panel_sendf (panel, 1, NULL, "DEPOSIT %s %s", name, value))
|
||||||
return -1;
|
return -1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -972,9 +1093,16 @@ while ((p->sock != INVALID_SOCKET) &&
|
||||||
*eol++ = '\0';
|
*eol++ = '\0';
|
||||||
e = strchr (s, ':');
|
e = strchr (s, ':');
|
||||||
if (e) {
|
if (e) {
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
*e++ = '\0';
|
*e++ = '\0';
|
||||||
|
if (!strcmp("Time", s)) {
|
||||||
|
p->simulation_time = strtoull (e, NULL, 10);
|
||||||
|
s = eol;
|
||||||
|
while (isspace(0xFF & (*s)))
|
||||||
|
++s;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
for (i=0; i<p->reg_count; i++) {
|
for (i=0; i<p->reg_count; i++) {
|
||||||
if (!strcmp(p->regs[i].name, s)) {
|
if (!strcmp(p->regs[i].name, s)) {
|
||||||
unsigned long long data;
|
unsigned long long data;
|
||||||
|
@ -987,17 +1115,22 @@ while ((p->sock != INVALID_SOCKET) &&
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i == p->reg_count) {
|
if (i != p->reg_count) {
|
||||||
/* Unexpected Register Data Found */
|
s = eol;
|
||||||
|
while (isspace(0xFF & (*s)))
|
||||||
|
++s;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
--e;
|
||||||
|
*e = ':';
|
||||||
|
/* Unexpected Register Data Found (or other output containing a : character) */
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
if (!strcmp (s + strlen (sim_prompt), register_get_echo)) {
|
if (!strcmp (s + strlen (sim_prompt), register_get_echo)) {
|
||||||
pthread_mutex_lock (&p->io_lock);
|
pthread_mutex_lock (&p->io_lock);
|
||||||
--p->io_reg_query_pending;
|
--p->io_reg_query_pending;
|
||||||
if (p->callback) {
|
if (p->callback) {
|
||||||
pthread_mutex_unlock (&p->io_lock);
|
pthread_mutex_unlock (&p->io_lock);
|
||||||
p->callback (p, p->callback_context);
|
p->callback (p, p->simulation_time, p->callback_context);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
p->io_waiting = 0;
|
p->io_waiting = 0;
|
||||||
|
@ -1006,19 +1139,37 @@ while ((p->sock != INVALID_SOCKET) &&
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!strcmp (s + strlen (sim_prompt), command_done_echo)) {
|
|
||||||
pthread_mutex_lock (&p->io_lock);
|
pthread_mutex_lock (&p->io_lock);
|
||||||
|
if (!strcmp (s + strlen (sim_prompt), command_done_echo)) {
|
||||||
p->io_waiting = 0;
|
p->io_waiting = 0;
|
||||||
pthread_cond_signal (&p->io_done);
|
pthread_cond_signal (&p->io_done);
|
||||||
pthread_mutex_unlock (&p->io_lock);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Non Register Data Found (echo of EXAMINE or other commands) */
|
/* Non Register Data Found (echo of EXAMINE or other commands and/or command output) */
|
||||||
|
if (p->io_waiting) {
|
||||||
|
char *t;
|
||||||
|
if (p->io_response_data + strlen (s) + 2 > p->io_response_size) {
|
||||||
|
t = (char *)_panel_malloc (p->io_response_data + strlen (s) + 3);
|
||||||
|
if (t == NULL) {
|
||||||
|
_panel_debug (p, DBG_RCV, "%s", NULL, 0, sim_panel_get_error());
|
||||||
|
p->State = Error;
|
||||||
|
pthread_mutex_unlock (&p->io_lock);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
memcpy (t, p->io_response, p->io_response_data);
|
||||||
|
free (p->io_response);
|
||||||
|
p->io_response = t;
|
||||||
|
p->io_response_size = p->io_response_data + strlen (s) + 3;
|
||||||
|
}
|
||||||
|
strcpy (p->io_response + p->io_response_data, s);
|
||||||
|
strcat (p->io_response, "\r\n");
|
||||||
|
p->io_response_data += strlen(s) + 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pthread_mutex_unlock (&p->io_lock);
|
||||||
}
|
}
|
||||||
s = eol;
|
s = eol;
|
||||||
while (isspace(*s))
|
while (isspace(0xFF & (*s)))
|
||||||
++s;
|
++s;
|
||||||
}
|
}
|
||||||
pthread_mutex_lock (&p->io_lock);
|
pthread_mutex_lock (&p->io_lock);
|
||||||
|
@ -1157,7 +1308,7 @@ return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_panel_sendf (PANEL *p, int wait_for_completion, const char *fmt, ...)
|
_panel_sendf (PANEL *p, int wait_for_completion, char **response, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
char stackbuf[1024];
|
char stackbuf[1024];
|
||||||
int bufsize = sizeof(stackbuf);
|
int bufsize = sizeof(stackbuf);
|
||||||
|
@ -1187,7 +1338,10 @@ while (1) { /* format passed string, arg
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (len && (buf[len-1] != '\r')) {
|
||||||
strcat (buf, "\r"); /* Make sure command line is terminated */
|
strcat (buf, "\r"); /* Make sure command line is terminated */
|
||||||
|
++len;
|
||||||
|
}
|
||||||
|
|
||||||
if (wait_for_completion) {
|
if (wait_for_completion) {
|
||||||
strcat (buf, command_done_echo);
|
strcat (buf, command_done_echo);
|
||||||
|
@ -1202,6 +1356,15 @@ if (wait_for_completion) {
|
||||||
p->io_waiting = 1;
|
p->io_waiting = 1;
|
||||||
while (p->io_waiting)
|
while (p->io_waiting)
|
||||||
pthread_cond_wait (&p->io_done, &p->io_lock); /* Wait for completion */
|
pthread_cond_wait (&p->io_done, &p->io_lock); /* Wait for completion */
|
||||||
|
if (response) {
|
||||||
|
*response = (char *)_panel_malloc (p->io_response_data + 1);
|
||||||
|
if (0 == memcmp (buf, p->io_response + strlen (sim_prompt), len)) {
|
||||||
|
memcpy (*response, p->io_response + strlen (sim_prompt) + len + 1, p->io_response_data + 1 - (strlen (sim_prompt) + len + 1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
memcpy (*response, p->io_response, p->io_response_data + 1);
|
||||||
|
}
|
||||||
|
p->io_response_data = 0;
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock (&p->io_lock);
|
pthread_mutex_unlock (&p->io_lock);
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,9 +49,13 @@ extern "C" {
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#if !defined(__VAX) /* Supported platform */
|
||||||
|
|
||||||
|
#define SIM_FRONTPANEL_VERSION 1
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
||||||
sim_panel_start_simulator A starts a simulatir with a particular
|
sim_panel_start_simulator A starts a simulator with a particular
|
||||||
configuration
|
configuration
|
||||||
|
|
||||||
sim_path the path to the simulator binary
|
sim_path the path to the simulator binary
|
||||||
|
@ -114,9 +118,12 @@ sim_panel_destroy (PANEL *panel);
|
||||||
The registers that a particular frontpanel application mught need
|
The registers that a particular frontpanel application mught need
|
||||||
access to are described by the application by calling:
|
access to are described by the application by calling:
|
||||||
|
|
||||||
sim_pabel_add_register
|
sim_panel_add_register
|
||||||
|
|
||||||
name the name the simulator knows this register by
|
name the name the simulator knows this register by
|
||||||
|
device_name the device this register is part of. Defaults to
|
||||||
|
the device of the panel (in a device panel) or the
|
||||||
|
default device in the simulator (usually the CPU).
|
||||||
size the size (in local storage) of the buffer which will
|
size the size (in local storage) of the buffer which will
|
||||||
receive the data in the simulator's register
|
receive the data in the simulator's register
|
||||||
addr a pointer to the location of the buffer which will
|
addr a pointer to the location of the buffer which will
|
||||||
|
@ -126,6 +133,7 @@ sim_panel_destroy (PANEL *panel);
|
||||||
int
|
int
|
||||||
sim_panel_add_register (PANEL *panel,
|
sim_panel_add_register (PANEL *panel,
|
||||||
const char *name,
|
const char *name,
|
||||||
|
const char *device_name,
|
||||||
size_t size,
|
size_t size,
|
||||||
void *addr);
|
void *addr);
|
||||||
|
|
||||||
|
@ -150,13 +158,14 @@ sim_panel_add_register (PANEL *panel,
|
||||||
|
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
sim_panel_get_registers (PANEL *panel);
|
sim_panel_get_registers (PANEL *panel, unsigned long long *simulation_time);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
typedef void (*PANEL_DISPLAY_PCALLBACK)(PANEL *panel,
|
typedef void (*PANEL_DISPLAY_PCALLBACK)(PANEL *panel,
|
||||||
|
unsigned long long simulation_time,
|
||||||
void *context);
|
void *context);
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -250,6 +259,8 @@ sim_panel_set_debug_mode (PANEL *panel, int debug_bits);
|
||||||
void
|
void
|
||||||
sim_panel_flush_debug (PANEL *panel);
|
sim_panel_flush_debug (PANEL *panel);
|
||||||
|
|
||||||
|
#endif /* !defined(__VAX) */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Reference in a new issue