FRONTPANEL: sim_frontpanel API version 5 release

- Add API to start execution with device reset
- Fix synchronization between panel application threads and simulator
  traffic reader thread.
This commit is contained in:
Mark Pizzolato 2017-11-04 10:28:00 -07:00
parent 097172f8a3
commit e73d45ebcc
4 changed files with 273 additions and 102 deletions

View file

@ -153,7 +153,7 @@ if ((f = fopen (sim_config, "w"))) {
if (debug) {
fprintf (f, "set verbose\n");
fprintf (f, "set debug -n -a simulator.dbg\n");
fprintf (f, "set cpu conhalt\n");
fprintf (f, "set cpu simhalt\n");
fprintf (f, "set remote telnet=2226\n");
fprintf (f, "set rem-con debug=XMT;RCV;MODE;REPEAT;CMD\n");
fprintf (f, "set remote notelnet\n");
@ -187,13 +187,53 @@ if (!panel) {
}
if (debug) {
sim_panel_set_debug_mode (panel, DBG_XMT|DBG_RCV|DBG_REQ|DBG_RSP);
sim_panel_set_debug_mode (panel, DBG_XMT|DBG_RCV|DBG_REQ|DBG_RSP|DBG_THR);
}
tape = sim_panel_add_device_panel (panel, "TAPE DRIVE");
if (1) {
tape = sim_panel_add_device_panel (panel, "TAPE DRIVE");
if (!tape) {
printf ("Error adding tape device to simulator: %s\n", sim_panel_get_error());
goto Done;
if (!tape) {
printf ("Error adding tape device to simulator: %s\n", sim_panel_get_error());
goto Done;
}
if (debug) {
sim_panel_set_debug_mode (tape, DBG_XMT|DBG_RCV|DBG_REQ|DBG_RSP|DBG_THR);
}
}
if (1) {
long noop_noop_noop_halt = 0x00010101, 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());
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_start (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_get_state (panel) != Halt) {
printf ("Unexpected execution state not Halt: %d\n", sim_panel_get_state (panel));
goto Done;
}
pc_value = 0;
if (sim_panel_gen_examine (panel, "PC", sizeof(pc_value), &pc_value)) {
printf ("Unexpected error getting PC value: %s\n", sim_panel_get_error());
goto Done;
}
if (pc_value != addr400 + 4) {
printf ("Unexpected error getting PC value: %08X, expected: %08X\n", pc_value, addr400 + 4);
goto Done;
}
}
if (sim_panel_add_register_array (panel, "PCQ", NULL, sizeof(PCQ)/sizeof(PCQ[0]), sizeof(PCQ[0]), &PCQ)) {
@ -328,7 +368,7 @@ if (!sim_panel_dismount (panel, "RL0")) {
printf ("Unexpected success while dismounting media file from non mounted RL0: %s\n", sim_panel_get_error());
goto Done;
}
if (sim_panel_mount (panel, "RL0", "-N", "TEST-RL.DSK")) {
if (sim_panel_mount (panel, "RL0", "-NQ", "TEST-RL.DSK")) {
printf ("Error while mounting media file TEST-RL.DSK on RL0: %s\n", sim_panel_get_error());
goto Done;
}
@ -389,6 +429,42 @@ if (sim_panel_add_register_bits (panel, "PC", NULL, 32, PC_bits)) {
printf ("Error adding register 'PSL' bits: %s\n", sim_panel_get_error());
goto Done;
}
if (1) {
long noop_noop_noop_halt = 0x00010101, 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());
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_get_state (panel) != Halt) {
printf ("Unexpected execution state not Halt\n");
goto Done;
}
pc_value = 0;
if (sim_panel_gen_examine (panel, "PC", sizeof(pc_value), &pc_value)) {
printf ("Unexpected error getting PC value: %s\n", sim_panel_get_error());
goto Done;
}
if (pc_value != addr400 + 4) {
printf ("Unexpected error getting PC value: %08X, expected: %08X\n", pc_value, addr400 + 4);
goto Done;
}
}
sim_panel_clear_error ();
while (1) {

View file

@ -1916,6 +1916,7 @@ if (sim_rem_master_mode) {
sim_printf ("Command input starting on Master Remote Console Session\n");
stat = sim_run_boot_prep (0);
sim_rem_master_was_enabled = TRUE;
sim_last_cmd_stat = SCPE_OK;
while (sim_rem_master_mode) {
sim_rem_consoles[0].single_mode = FALSE;
sim_cancel (rem_con_data_unit);
@ -1925,8 +1926,14 @@ if (sim_rem_master_mode) {
stat_nomessage = stat & SCPE_NOMESSAGE; /* extract possible message supression flag */
stat = _sim_rem_message ("RUN", stat);
}
sim_debug (DBG_MOD, &sim_remote_console, "Master Session Returned: Status - %d Active_Line: %d, Mode: %s, Active Cmd: %s\n", stat, sim_rem_cmd_active_line, sim_rem_consoles[0].single_mode ? "Single" : "^E Stopped", sim_rem_active_command ? sim_rem_active_command->name : "");
if (stat == SCPE_EXIT)
sim_rem_master_mode = FALSE;
sim_rem_cmd_active_line = 0; /* Make it look like */
sim_rem_consoles[0].single_mode = FALSE;
if (stat != SCPE_STEP)
sim_rem_active_command = &allowed_single_remote_cmds[0];/* Dummy */
sim_last_cmd_stat = SCPE_BARE_STATUS(stat); /* make exit status available to remote console */
}
sim_rem_master_was_enabled = FALSE;
sim_rem_master_was_connected = FALSE;

View file

@ -35,6 +35,11 @@
simulator. Facilities provide ways to gather information from and to
observe and control the state of a simulator.
The details of the 'wire protocol' are internal to the API interfaces
provided here and described in sim_frontpanel.h. These details are subject
to change from one sim_frontpanel version to the next, while all efforts
will be made to retain any prior sim_frontpanel API interfaces.
*/
#ifdef __cplusplus
@ -141,7 +146,7 @@ struct PANEL {
unsigned long long array_element_data;
OperationalState State;
unsigned long long simulation_time;
pthread_mutex_t lock;
unsigned long long simulation_time_base;
pthread_t io_thread;
int io_thread_running;
pthread_mutex_t io_lock;
@ -154,7 +159,7 @@ struct PANEL {
size_t io_response_data;
size_t io_response_size;
pthread_cond_t io_done;
pthread_cond_t startup_cond;
pthread_cond_t startup_done;
PANEL_DISPLAY_PCALLBACK callback;
pthread_t callback_thread;
int callback_thread_running;
@ -173,6 +178,31 @@ struct PANEL {
#endif
};
/*
* Thread synchronization model:
*
* Mutex: Role:
* io_lock Serialize access to panel state variables
* acquired and released in application threads:
* _panel_register_query_string,
* _panel_establish_register_bits_collection,
* _panel_sendf
* acquired and released in internal threads:
* _panel_callback
* _panel_reader
* io_send_lock Serializes writes to a panel's sockets so that complete
* command/request data can be delivered before another
* thread attempts to write to the socket.
* acquired and released in: _panel_send
* io_command_lock To serialize frontpanel application command requests
* acquired and released in: _panel_get_registers, _panel_sendf
*
* Condition Var: Sync Mutex: Purpose & Duration:
* io_done io_lock
* startup_done io_lock Indicate background thread setup is complete.
* Once signaled, it is immediately destroyed.
*/
static const char *sim_prompt = "sim> ";
static const char *register_repeat_prefix = "repeat every ";
static const char *register_repeat_stop = "repeat stop";
@ -193,7 +223,7 @@ static int little_endian;
static void *_panel_reader(void *arg);
static void *_panel_callback(void *arg);
static void sim_panel_set_error (const char *fmt, ...);
static pthread_key_t panel_thread_id;
#define TN_IAC 0xFFu /* -1 */ /* protocol delim */
#define TN_DONT 0xFEu /* -2 */ /* dont */
@ -244,17 +274,18 @@ if (p && p->Debug && (dbits & p->debug)) {
struct timespec time_now;
va_list arglist;
char timestamp[32];
char threadname[50];
size_t obufsize = 10240 + 8*bufsize;
char *obuf = (char *)_panel_malloc (obufsize);
clock_gettime(CLOCK_REALTIME, &time_now);
sprintf (timestamp, "%lld.%03d ", (long long)(time_now.tv_sec), (int)(time_now.tv_nsec/1000000));
sprintf (threadname, "%s:%s ", p->parent ? p->device_name : "CPU", (pthread_getspecific (panel_thread_id)) ? (char *)pthread_getspecific (panel_thread_id) : "");
va_start (arglist, bufsize);
vsnprintf (obuf, obufsize - 1, fmt, arglist);
va_end (arglist);
for (i=0; i<bufsize; ++i) {
switch ((unsigned char)buf[i]) {
case TN_CR:
@ -317,18 +348,19 @@ if (p && p->Debug && (dbits & p->debug)) {
break;
}
}
fprintf(p->Debug, "%s%s\n", timestamp, obuf);
fprintf(p->Debug, "%s%s%s\n", timestamp, threadname, obuf);
free (obuf);
}
}
void
sim_panel_set_debug_file (PANEL *panel, const char *debug_file)
static void
_set_debug_file (PANEL *panel, const char *debug_file)
{
if (!panel)
return;
panel->Debug = fopen(debug_file, "w");
setvbuf (panel->Debug, NULL, _IOFBF, 65536);
if (panel->Debug)
setvbuf (panel->Debug, NULL, _IOFBF, 65536);
}
void
@ -544,6 +576,10 @@ while (panel_count)
static void
_panel_register_panel (PANEL *p)
{
if (panel_count == 0)
pthread_key_create (&panel_thread_id, free);
if (!pthread_getspecific (panel_thread_id))
pthread_setspecific (panel_thread_id, p->device_name ? p->device_name : "PanelCreator");
++panel_count;
panels = (PANEL **)realloc (panels, sizeof(*panels)*panel_count);
panels[panel_count-1] = p;
@ -565,6 +601,8 @@ for (i=0; i<panel_count; i++) {
if (panel_count == 0) {
free (panels);
panels = NULL;
pthread_setspecific (panel_thread_id, NULL);
pthread_key_delete (panel_thread_id);
}
break;
}
@ -603,11 +641,13 @@ if (simulator_panel) {
if (p == NULL)
goto Error_Return;
memset (p, 0, sizeof(*p));
_panel_register_panel (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->Debug = p->parent->Debug;
strcpy (p->hostport, simulator_panel->hostport);
p->sock = INVALID_SOCKET;
}
@ -645,6 +685,7 @@ else {
if (p == NULL)
goto Error_Return;
memset (p, 0, sizeof(*p));
_panel_register_panel (p);
p->sock = INVALID_SOCKET;
p->path = (char *)_panel_malloc (strlen (sim_path) + 1);
if (p->path == NULL)
@ -687,7 +728,7 @@ else {
fOut = NULL;
}
if (debug_file) {
sim_panel_set_debug_file (p, debug_file);
_set_debug_file (p, debug_file);
sim_panel_set_debug_mode (p, DBG_XMT|DBG_RCV);
_panel_debug (p, DBG_XMT|DBG_RCV, "Creating Simulator Process %s\n", NULL, 0, sim_path);
@ -780,7 +821,7 @@ pthread_mutex_init (&p->io_lock, NULL);
pthread_mutex_init (&p->io_send_lock, NULL);
pthread_mutex_init (&p->io_command_lock, NULL);
pthread_cond_init (&p->io_done, NULL);
pthread_cond_init (&p->startup_cond, NULL);
pthread_cond_init (&p->startup_done, NULL);
if (sizeof(mantra) != _panel_send (p, (char *)mantra, sizeof(mantra))) {
sim_panel_set_error ("Error sending Telnet mantra (options): %s", sim_get_err_sock ("send"));
goto Error_Return;
@ -795,9 +836,9 @@ if (1) {
pthread_create (&p->io_thread, &attr, _panel_reader, (void *)p);
pthread_attr_destroy(&attr);
while (!p->io_thread_running)
pthread_cond_wait (&p->startup_cond, &p->io_lock); /* Wait for thread to stabilize */
pthread_cond_wait (&p->startup_done, &p->io_lock); /* Wait for thread to stabilize */
pthread_mutex_unlock (&p->io_lock);
pthread_cond_destroy (&p->startup_cond);
pthread_cond_destroy (&p->startup_done);
}
if (simulator_panel) {
simulator_panel->devices[device_num] = p;
@ -841,7 +882,6 @@ else {
}
}
}
_panel_register_panel (p);
return p;
Error_Return:
@ -915,10 +955,6 @@ if (panel) {
panel->devices = NULL;
}
_panel_deregister_panel (panel);
free (panel->path);
free (panel->device_name);
free (panel->config);
if (panel->sock != INVALID_SOCKET) {
SOCKET sock = panel->sock;
int wait_count;
@ -962,6 +998,9 @@ if (panel) {
waitpid (panel->pidProcess, &status, 0);
}
#endif
free (panel->path);
free (panel->device_name);
free (panel->config);
if (panel->temp_config)
remove (panel->temp_config);
free (panel->temp_config);
@ -975,9 +1014,10 @@ if (panel) {
free (panel->reg_query);
free (panel->io_response);
free (panel->simulator_version);
if (panel->Debug)
if ((panel->Debug) && (!panel->parent))
fclose (panel->Debug);
sim_cleanup_sock ();
_panel_deregister_panel (panel);
free (panel);
}
return 0;
@ -1245,27 +1285,27 @@ if (!panel) {
sim_panel_set_error ("Invalid Panel");
return -1;
}
pthread_mutex_lock (&panel->io_lock);
pthread_mutex_lock (&panel->io_lock); /* acquire access */
panel->callback = callback;
panel->callback_context = context;
if (usecs_between_callbacks && (0 == panel->usecs_between_callbacks)) { /* Need to start/enable callbacks */
pthread_attr_t attr;
panel->usecs_between_callbacks = usecs_between_callbacks;
pthread_cond_init (&panel->startup_cond, NULL);
pthread_cond_init (&panel->startup_done, NULL);
pthread_attr_init(&attr);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
pthread_create (&panel->callback_thread, &attr, _panel_callback, (void *)panel);
pthread_attr_destroy(&attr);
while (!panel->callback_thread_running)
pthread_cond_wait (&panel->startup_cond, &panel->io_lock); /* Wait for thread to stabilize */
pthread_cond_destroy (&panel->startup_cond);
pthread_cond_wait (&panel->startup_done, &panel->io_lock); /* Wait for thread to stabilize */
pthread_cond_destroy (&panel->startup_done);
}
if ((usecs_between_callbacks == 0) && panel->usecs_between_callbacks) { /* Need to stop callbacks */
panel->usecs_between_callbacks = 0;
pthread_mutex_unlock (&panel->io_lock);
pthread_join (panel->callback_thread, NULL);
pthread_mutex_lock (&panel->io_lock);
panel->usecs_between_callbacks = 0; /* flag disabled */
pthread_mutex_unlock (&panel->io_lock); /* allow access */
pthread_join (panel->callback_thread, NULL); /* synchronize with thread rundown */
pthread_mutex_lock (&panel->io_lock); /* reacquire access */
}
pthread_mutex_unlock (&panel->io_lock);
return 0;
@ -1310,6 +1350,8 @@ return 0;
int
sim_panel_exec_boot (PANEL *panel, const char *device)
{
int cmd_stat;
if (!panel || (panel->State == Error)) {
sim_panel_set_error ("Invalid Panel");
return -1;
@ -1322,12 +1364,47 @@ if (panel->State == Run) {
sim_panel_set_error ("Not Halted");
return -1;
}
/* 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"))
return -1;
panel->simulation_time_base += panel->simulation_time;
if (_panel_sendf (panel, NULL, NULL, "BOOT %s\r", device))
return -1;
panel->State = Run;
return 0;
}
int
sim_panel_exec_start (PANEL *panel)
{
int cmd_stat;
if (!panel || (panel->State == Error)) {
sim_panel_set_error ("Invalid Panel");
return -1;
}
if (panel->parent) {
sim_panel_set_error ("Can't RUN simulator from device front panel");
return -1;
}
if (panel->State == Run) {
sim_panel_set_error ("Not Halted");
return -1;
}
/* 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"))
return -1;
panel->simulation_time_base += panel->simulation_time;
if (_panel_sendf (panel, NULL, NULL, "RUN -Q\r", 5))
return -1;
panel->State = Run;
return 0;
}
int
sim_panel_exec_run (PANEL *panel)
{
@ -1392,7 +1469,7 @@ if (panel->State == Run) {
if ((_panel_sendf (panel, &cmd_stat, &response, "BREAK %s\r", condition)) ||
(*response)) {
sim_panel_set_error ("Error establishing breakpoint at '%s': %s", condition, response ? response : "");
sim_panel_set_error ("Error establishing breakpoint at '%s': %s", condition, response ? response : "");
free (response);
return -1;
}
@ -1522,7 +1599,7 @@ if (_panel_sendf (panel, &cmd_stat, &response, "EXAMINE -H %s", name_or_addr)) {
}
c = strchr (response, ':');
if (!c) {
sim_panel_set_error (response);
sim_panel_set_error ("response: %s", response);
free (response);
return -1;
}
@ -1824,6 +1901,8 @@ int buf_data = 0;
pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority);
++sched_priority.sched_priority;
pthread_setschedparam (pthread_self(), sched_policy, &sched_priority);
pthread_setspecific (panel_thread_id, "reader");
_panel_debug (p, DBG_THR, "Starting", NULL, 0);
buf[buf_data] = '\0';
pthread_mutex_lock (&p->io_lock);
@ -1855,7 +1934,7 @@ if (!p->parent) {
}
p->io_thread_running = 1;
pthread_mutex_unlock (&p->io_lock);
pthread_cond_signal (&p->startup_cond); /* Signal we're ready to go */
pthread_cond_signal (&p->startup_done); /* Signal we're ready to go */
msleep (100);
pthread_mutex_lock (&p->io_lock);
while ((p->sock != INVALID_SOCKET) &&
@ -1865,8 +1944,8 @@ while ((p->sock != INVALID_SOCKET) &&
pthread_mutex_unlock (&p->io_lock);
new_data = sim_read_sock (p->sock, &buf[buf_data], sizeof(buf)-(buf_data+1));
pthread_mutex_lock (&p->io_lock);
if (new_data <= 0) {
pthread_mutex_lock (&p->io_lock);
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;
@ -1893,7 +1972,7 @@ while ((p->sock != INVALID_SOCKET) &&
s = eol;
while (isspace(0xFF & (*s)))
++s;
continue;
continue; /* process next line */
}
if ((*s == '}') &&
(3 == sscanf (s, "}%s %s %s", smp_dev, smp_reg, smp_ind))) { /* Register bit Sample Data? */
@ -1920,7 +1999,8 @@ while ((p->sock != INVALID_SOCKET) &&
}
while (isspace(0xFF & (*s)))
++s;
continue;
r = NULL;
continue; /* process next line */
}
if (!strncmp (s + strlen (sim_prompt), register_ind_echo, strlen (register_ind_echo) - 1)) {
e = s + strlen (sim_prompt) + strlen (register_ind_echo);
@ -1935,65 +2015,67 @@ while ((p->sock != INVALID_SOCKET) &&
while (isspace(0xFF & (*s)))
++s;
if (r)
continue;
continue; /* process next line */
}
if (r) {
if (strcmp (s, r->name)) {
unsigned long long data;
data = strtoull (e, NULL, 16);
if (little_endian)
memcpy (r->addr, &data, r->size);
else
memcpy (r->addr, ((char *)&data) + sizeof(data)-r->size, r->size);
r = NULL;
}
s = eol;
while (isspace(0xFF & (*s)))
++s;
continue;
}
for (i=0; i<p->reg_count; i++) {
if (p->regs[i].element_count == 0) {
if (!strcmp(p->regs[i].name, s)) {
if (!p->io_waiting) {
if (r) {
if (strcmp (s, r->name)) {
unsigned long long data;
data = strtoull (e, NULL, 16);
if (little_endian)
memcpy (p->regs[i].addr, &data, p->regs[i].size);
memcpy (r->addr, &data, r->size);
else
memcpy (p->regs[i].addr, ((char *)&data) + sizeof(data)-p->regs[i].size, p->regs[i].size);
break;
memcpy (r->addr, ((char *)&data) + sizeof(data)-r->size, r->size);
r = NULL;
}
s = eol;
while (isspace(0xFF & (*s)))
++s;
continue; /* process next line */
}
else {
size_t name_len = strlen (p->regs[i].name);
for (i=0; i<p->reg_count; i++) {
if (p->regs[i].element_count == 0) {
if (!strcmp(p->regs[i].name, s)) {
unsigned long long data;
if ((0 == memcmp (p->regs[i].name, s, name_len)) && (s[name_len] == '[')) {
size_t array_index = (size_t)atoi (s + name_len + 1);
size_t end_index = array_index;
char *end = strchr (s + name_len + 1, '[');
if (end)
end_index = (size_t)atoi (end + 1);
if (strcmp (e, " same as above"))
p->array_element_data = strtoull (e, NULL, 16);
while (array_index <= end_index) {
data = strtoull (e, NULL, 16);
if (little_endian)
memcpy ((char *)(p->regs[i].addr) + (array_index * p->regs[i].size), &p->array_element_data, p->regs[i].size);
memcpy (p->regs[i].addr, &data, p->regs[i].size);
else
memcpy ((char *)(p->regs[i].addr) + (array_index * p->regs[i].size), ((char *)&p->array_element_data) + sizeof(p->array_element_data)-p->regs[i].size, p->regs[i].size);
++array_index;
memcpy (p->regs[i].addr, ((char *)&data) + sizeof(data)-p->regs[i].size, p->regs[i].size);
break;
}
}
else {
size_t name_len = strlen (p->regs[i].name);
if ((0 == memcmp (p->regs[i].name, s, name_len)) && (s[name_len] == '[')) {
size_t array_index = (size_t)atoi (s + name_len + 1);
size_t end_index = array_index;
char *end = strchr (s + name_len + 1, '[');
if (end)
end_index = (size_t)atoi (end + 1);
if (strcmp (e, " same as above"))
p->array_element_data = strtoull (e, NULL, 16);
while (array_index <= end_index) {
if (little_endian)
memcpy ((char *)(p->regs[i].addr) + (array_index * p->regs[i].size), &p->array_element_data, p->regs[i].size);
else
memcpy ((char *)(p->regs[i].addr) + (array_index * p->regs[i].size), ((char *)&p->array_element_data) + sizeof(p->array_element_data)-p->regs[i].size, p->regs[i].size);
++array_index;
}
break;
}
break;
}
}
}
if (i != p->reg_count) {
s = eol;
while (isspace(0xFF & (*s)))
++s;
continue;
if (i != p->reg_count) {
s = eol;
while (isspace(0xFF & (*s)))
++s;
continue;
}
}
--e;
*e = ':';
@ -2002,19 +2084,16 @@ while ((p->sock != INVALID_SOCKET) &&
if (!strcmp (s + strlen (sim_prompt), register_repeat_echo)) {
if (p->callback) {
pthread_mutex_unlock (&p->io_lock);
p->callback (p, p->simulation_time, p->callback_context);
p->callback (p, p->simulation_time_base + p->simulation_time, p->callback_context);
pthread_mutex_lock (&p->io_lock);
}
}
if (!strcmp (s + strlen (sim_prompt), register_get_echo)) {
pthread_mutex_lock (&p->io_lock);
--p->io_reg_query_pending;
p->io_waiting = 0;
pthread_cond_signal (&p->io_done);
pthread_mutex_unlock (&p->io_lock);
}
else {
pthread_mutex_lock (&p->io_lock);
if (!strcmp (s + strlen (sim_prompt), command_done_echo)) {
_panel_debug (p, DBG_RCV, "Received Command Complete", NULL, 0);
p->io_waiting = 0;
@ -2030,7 +2109,6 @@ while ((p->sock != INVALID_SOCKET) &&
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);
@ -2047,19 +2125,19 @@ while ((p->sock != INVALID_SOCKET) &&
else
_panel_debug (p, DBG_RCV, "Receive Data Discarded: '%s'", NULL, 0, s);
}
pthread_mutex_unlock (&p->io_lock);
}
s = eol;
while (isspace(0xFF & (*s)))
++s;
}
pthread_mutex_lock (&p->io_lock);
if ((p->State == Run) && (!strcmp (s, sim_prompt))) {
_panel_debug (p, DBG_RSP, "State transitioning to Halt", NULL, 0);
p->State = Halt;
}
memmove (buf, s, strlen (s)+1);
buf_data = strlen (buf);
if (!strcmp("Simulator Running...", buf)) {
_panel_debug (p, DBG_RSP, "State transitioning to Run", NULL, 0);
p->State = Run;
buf_data = 0;
buf[0] = '\0';
@ -2070,6 +2148,8 @@ if (p->io_waiting) {
p->io_waiting = 0;
pthread_cond_signal (&p->io_done);
}
_panel_debug (p, DBG_THR, "Exiting", NULL, 0);
pthread_setspecific (panel_thread_id, NULL);
p->io_thread_running = 0;
pthread_mutex_unlock (&p->io_lock);
return NULL;
@ -2093,11 +2173,13 @@ int cmd_stat;
pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority);
++sched_priority.sched_priority;
pthread_setschedparam (pthread_self(), sched_policy, &sched_priority);
pthread_setspecific (panel_thread_id, "callback");
_panel_debug (p, DBG_THR, "Starting", NULL, 0);
pthread_mutex_lock (&p->io_lock);
p->callback_thread_running = 1;
pthread_mutex_unlock (&p->io_lock);
pthread_cond_signal (&p->startup_cond); /* Signal we're ready to go */
pthread_cond_signal (&p->startup_done); /* Signal we're ready to go */
msleep (100);
pthread_mutex_lock (&p->io_lock);
while ((p->sock != INVALID_SOCKET) &&
@ -2174,6 +2256,8 @@ else {
_panel_sendf (p, &cmd_stat, NULL, "%s", register_repeat_stop);
}
pthread_mutex_lock (&p->io_lock);
_panel_debug (p, DBG_THR, "Exiting", NULL, 0);
pthread_setspecific (panel_thread_id, NULL);
p->callback_thread_running = 0;
pthread_mutex_unlock (&p->io_lock);
free (buf);
@ -2239,8 +2323,6 @@ while (1) { /* format passed string, arg
}
break;
}
return;
}
static int
@ -2249,7 +2331,7 @@ _panel_sendf (PANEL *p, int *completion_status, char **response, const char *fmt
char stackbuf[1024];
int bufsize = sizeof(stackbuf);
char *buf = stackbuf;
int len, status_echo_len = 0;
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;
@ -2291,7 +2373,7 @@ if (completion_status) {
}
_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) == _panel_send (p, buf, len + status_echo_len)) ? 0 : -1;
ret = ((len + status_echo_len) == (sent_len = _panel_send (p, buf, len + status_echo_len))) ? 0 : -1;
if (completion_status) {
if (!ret) { /* Sent OK? */
@ -2327,6 +2409,10 @@ if (completion_status) {
p->io_response[0] = '\0';
pthread_mutex_unlock (&p->io_lock);
}
else {
if (ret)
sim_panel_set_error ("Unexpected send length: %d, expected: %d", sent_len, len + status_echo_len);
}
pthread_mutex_unlock (&p->io_command_lock);
if (buf != stackbuf)

View file

@ -56,7 +56,7 @@ extern "C" {
#if !defined(__VAX) /* Unsupported platform */
#define SIM_FRONTPANEL_VERSION 4
#define SIM_FRONTPANEL_VERSION 5
/**
@ -194,7 +194,7 @@ sim_panel_add_register_indirect_bits (PANEL *panel,
the values contained in the set of registers it has declared interest in via
the sim_panel_add_register APIs.
1) The values can be polled (when ever it is desired) by calling
1) The values can be polled (whenever it is desired) by calling
sim_panel_get_registers().
2) The panel can call sim_panel_set_display_callback_interval() to
specify a callback routine and a periodic rate that the callback
@ -254,6 +254,8 @@ sim_panel_set_sampling_parameters (PANEL *panel,
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_start - Start a simulator running instructions
after resetting all devices
sim_panel_exec_step - Have a simulator execute a single step
*/
@ -263,6 +265,9 @@ sim_panel_exec_halt (PANEL *panel);
int
sim_panel_exec_boot (PANEL *panel, const char *device);
int
sim_panel_exec_start (PANEL *panel);
int
sim_panel_exec_run (PANEL *panel);
@ -475,18 +480,15 @@ 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);
#define DBG_XMT 1 /* Transmit Data */
#define DBG_RCV 2 /* Receive Data */
#define DBG_REQ 4 /* Request Data */
#define DBG_RSP 8 /* Response Data */
#define DBG_THR 16 /* Thread Activities */
void
sim_panel_set_debug_mode (PANEL *panel, int debug_bits);