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) { if (debug) {
fprintf (f, "set verbose\n"); fprintf (f, "set verbose\n");
fprintf (f, "set debug -n -a simulator.dbg\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 remote telnet=2226\n");
fprintf (f, "set rem-con debug=XMT;RCV;MODE;REPEAT;CMD\n"); fprintf (f, "set rem-con debug=XMT;RCV;MODE;REPEAT;CMD\n");
fprintf (f, "set remote notelnet\n"); fprintf (f, "set remote notelnet\n");
@ -187,14 +187,54 @@ if (!panel) {
} }
if (debug) { 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);
} }
if (1) {
tape = sim_panel_add_device_panel (panel, "TAPE DRIVE"); tape = sim_panel_add_device_panel (panel, "TAPE DRIVE");
if (!tape) { if (!tape) {
printf ("Error adding tape device to simulator: %s\n", sim_panel_get_error()); printf ("Error adding tape device to simulator: %s\n", sim_panel_get_error());
goto Done; 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)) { if (sim_panel_add_register_array (panel, "PCQ", NULL, sizeof(PCQ)/sizeof(PCQ[0]), sizeof(PCQ[0]), &PCQ)) {
printf ("Error adding register array 'PCQ': %s\n", sim_panel_get_error()); printf ("Error adding register array 'PCQ': %s\n", sim_panel_get_error());
@ -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()); printf ("Unexpected success while dismounting media file from non mounted RL0: %s\n", sim_panel_get_error());
goto Done; 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()); printf ("Error while mounting media file TEST-RL.DSK on RL0: %s\n", sim_panel_get_error());
goto Done; 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()); printf ("Error adding register 'PSL' bits: %s\n", sim_panel_get_error());
goto Done; 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 (); sim_panel_clear_error ();
while (1) { while (1) {

View file

@ -1916,6 +1916,7 @@ if (sim_rem_master_mode) {
sim_printf ("Command input starting on Master Remote Console Session\n"); sim_printf ("Command input starting on Master Remote Console Session\n");
stat = sim_run_boot_prep (0); stat = sim_run_boot_prep (0);
sim_rem_master_was_enabled = TRUE; sim_rem_master_was_enabled = TRUE;
sim_last_cmd_stat = SCPE_OK;
while (sim_rem_master_mode) { while (sim_rem_master_mode) {
sim_rem_consoles[0].single_mode = FALSE; sim_rem_consoles[0].single_mode = FALSE;
sim_cancel (rem_con_data_unit); 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_nomessage = stat & SCPE_NOMESSAGE; /* extract possible message supression flag */
stat = _sim_rem_message ("RUN", stat); 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) if (stat == SCPE_EXIT)
sim_rem_master_mode = FALSE; 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_enabled = FALSE;
sim_rem_master_was_connected = FALSE; sim_rem_master_was_connected = FALSE;

View file

@ -35,6 +35,11 @@
simulator. Facilities provide ways to gather information from and to simulator. Facilities provide ways to gather information from and to
observe and control the state of a simulator. 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 #ifdef __cplusplus
@ -141,7 +146,7 @@ struct PANEL {
unsigned long long array_element_data; unsigned long long array_element_data;
OperationalState State; OperationalState State;
unsigned long long simulation_time; unsigned long long simulation_time;
pthread_mutex_t lock; unsigned long long simulation_time_base;
pthread_t io_thread; pthread_t io_thread;
int io_thread_running; int io_thread_running;
pthread_mutex_t io_lock; pthread_mutex_t io_lock;
@ -154,7 +159,7 @@ struct PANEL {
size_t io_response_data; size_t io_response_data;
size_t io_response_size; size_t io_response_size;
pthread_cond_t io_done; pthread_cond_t io_done;
pthread_cond_t startup_cond; pthread_cond_t startup_done;
PANEL_DISPLAY_PCALLBACK callback; PANEL_DISPLAY_PCALLBACK callback;
pthread_t callback_thread; pthread_t callback_thread;
int callback_thread_running; int callback_thread_running;
@ -173,6 +178,31 @@ struct PANEL {
#endif #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 *sim_prompt = "sim> ";
static const char *register_repeat_prefix = "repeat every "; static const char *register_repeat_prefix = "repeat every ";
static const char *register_repeat_stop = "repeat stop"; 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_reader(void *arg);
static void *_panel_callback(void *arg); static void *_panel_callback(void *arg);
static void sim_panel_set_error (const char *fmt, ...); 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_IAC 0xFFu /* -1 */ /* protocol delim */
#define TN_DONT 0xFEu /* -2 */ /* dont */ #define TN_DONT 0xFEu /* -2 */ /* dont */
@ -244,17 +274,18 @@ if (p && p->Debug && (dbits & p->debug)) {
struct timespec time_now; struct timespec time_now;
va_list arglist; va_list arglist;
char timestamp[32]; char timestamp[32];
char threadname[50];
size_t obufsize = 10240 + 8*bufsize; size_t obufsize = 10240 + 8*bufsize;
char *obuf = (char *)_panel_malloc (obufsize); char *obuf = (char *)_panel_malloc (obufsize);
clock_gettime(CLOCK_REALTIME, &time_now); clock_gettime(CLOCK_REALTIME, &time_now);
sprintf (timestamp, "%lld.%03d ", (long long)(time_now.tv_sec), (int)(time_now.tv_nsec/1000000)); 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); va_start (arglist, bufsize);
vsnprintf (obuf, obufsize - 1, fmt, arglist); vsnprintf (obuf, obufsize - 1, fmt, arglist);
va_end (arglist); va_end (arglist);
for (i=0; i<bufsize; ++i) { for (i=0; i<bufsize; ++i) {
switch ((unsigned char)buf[i]) { switch ((unsigned char)buf[i]) {
case TN_CR: case TN_CR:
@ -317,17 +348,18 @@ if (p && p->Debug && (dbits & p->debug)) {
break; break;
} }
} }
fprintf(p->Debug, "%s%s\n", timestamp, obuf); fprintf(p->Debug, "%s%s%s\n", timestamp, threadname, obuf);
free (obuf); free (obuf);
} }
} }
void static void
sim_panel_set_debug_file (PANEL *panel, const char *debug_file) _set_debug_file (PANEL *panel, const char *debug_file)
{ {
if (!panel) if (!panel)
return; return;
panel->Debug = fopen(debug_file, "w"); panel->Debug = fopen(debug_file, "w");
if (panel->Debug)
setvbuf (panel->Debug, NULL, _IOFBF, 65536); setvbuf (panel->Debug, NULL, _IOFBF, 65536);
} }
@ -544,6 +576,10 @@ while (panel_count)
static void static void
_panel_register_panel (PANEL *p) _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; ++panel_count;
panels = (PANEL **)realloc (panels, sizeof(*panels)*panel_count); panels = (PANEL **)realloc (panels, sizeof(*panels)*panel_count);
panels[panel_count-1] = p; panels[panel_count-1] = p;
@ -565,6 +601,8 @@ for (i=0; i<panel_count; i++) {
if (panel_count == 0) { if (panel_count == 0) {
free (panels); free (panels);
panels = NULL; panels = NULL;
pthread_setspecific (panel_thread_id, NULL);
pthread_key_delete (panel_thread_id);
} }
break; break;
} }
@ -603,11 +641,13 @@ if (simulator_panel) {
if (p == NULL) if (p == NULL)
goto Error_Return; goto Error_Return;
memset (p, 0, sizeof(*p)); memset (p, 0, sizeof(*p));
_panel_register_panel (p);
p->device_name = (char *)_panel_malloc (1 + strlen (device_name)); p->device_name = (char *)_panel_malloc (1 + strlen (device_name));
if (p->device_name == NULL) if (p->device_name == NULL)
goto Error_Return; goto Error_Return;
strcpy (p->device_name, device_name); strcpy (p->device_name, device_name);
p->parent = simulator_panel; p->parent = simulator_panel;
p->Debug = p->parent->Debug;
strcpy (p->hostport, simulator_panel->hostport); strcpy (p->hostport, simulator_panel->hostport);
p->sock = INVALID_SOCKET; p->sock = INVALID_SOCKET;
} }
@ -645,6 +685,7 @@ else {
if (p == NULL) if (p == NULL)
goto Error_Return; goto Error_Return;
memset (p, 0, sizeof(*p)); memset (p, 0, sizeof(*p));
_panel_register_panel (p);
p->sock = INVALID_SOCKET; p->sock = INVALID_SOCKET;
p->path = (char *)_panel_malloc (strlen (sim_path) + 1); p->path = (char *)_panel_malloc (strlen (sim_path) + 1);
if (p->path == NULL) if (p->path == NULL)
@ -687,7 +728,7 @@ else {
fOut = NULL; fOut = NULL;
} }
if (debug_file) { 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); 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); _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_send_lock, NULL);
pthread_mutex_init (&p->io_command_lock, NULL); pthread_mutex_init (&p->io_command_lock, NULL);
pthread_cond_init (&p->io_done, 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))) { 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")); sim_panel_set_error ("Error sending Telnet mantra (options): %s", sim_get_err_sock ("send"));
goto Error_Return; goto Error_Return;
@ -795,9 +836,9 @@ if (1) {
pthread_create (&p->io_thread, &attr, _panel_reader, (void *)p); pthread_create (&p->io_thread, &attr, _panel_reader, (void *)p);
pthread_attr_destroy(&attr); pthread_attr_destroy(&attr);
while (!p->io_thread_running) 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_mutex_unlock (&p->io_lock);
pthread_cond_destroy (&p->startup_cond); pthread_cond_destroy (&p->startup_done);
} }
if (simulator_panel) { if (simulator_panel) {
simulator_panel->devices[device_num] = p; simulator_panel->devices[device_num] = p;
@ -841,7 +882,6 @@ else {
} }
} }
} }
_panel_register_panel (p);
return p; return p;
Error_Return: Error_Return:
@ -915,10 +955,6 @@ if (panel) {
panel->devices = NULL; panel->devices = NULL;
} }
_panel_deregister_panel (panel);
free (panel->path);
free (panel->device_name);
free (panel->config);
if (panel->sock != INVALID_SOCKET) { if (panel->sock != INVALID_SOCKET) {
SOCKET sock = panel->sock; SOCKET sock = panel->sock;
int wait_count; int wait_count;
@ -962,6 +998,9 @@ if (panel) {
waitpid (panel->pidProcess, &status, 0); waitpid (panel->pidProcess, &status, 0);
} }
#endif #endif
free (panel->path);
free (panel->device_name);
free (panel->config);
if (panel->temp_config) if (panel->temp_config)
remove (panel->temp_config); remove (panel->temp_config);
free (panel->temp_config); free (panel->temp_config);
@ -975,9 +1014,10 @@ if (panel) {
free (panel->reg_query); free (panel->reg_query);
free (panel->io_response); free (panel->io_response);
free (panel->simulator_version); free (panel->simulator_version);
if (panel->Debug) if ((panel->Debug) && (!panel->parent))
fclose (panel->Debug); fclose (panel->Debug);
sim_cleanup_sock (); sim_cleanup_sock ();
_panel_deregister_panel (panel);
free (panel); free (panel);
} }
return 0; return 0;
@ -1245,27 +1285,27 @@ if (!panel) {
sim_panel_set_error ("Invalid Panel"); sim_panel_set_error ("Invalid Panel");
return -1; return -1;
} }
pthread_mutex_lock (&panel->io_lock); pthread_mutex_lock (&panel->io_lock); /* acquire access */
panel->callback = callback; panel->callback = callback;
panel->callback_context = context; panel->callback_context = context;
if (usecs_between_callbacks && (0 == panel->usecs_between_callbacks)) { /* Need to start/enable callbacks */ if (usecs_between_callbacks && (0 == panel->usecs_between_callbacks)) { /* Need to start/enable callbacks */
pthread_attr_t attr; pthread_attr_t attr;
panel->usecs_between_callbacks = usecs_between_callbacks; 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_init(&attr);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
pthread_create (&panel->callback_thread, &attr, _panel_callback, (void *)panel); pthread_create (&panel->callback_thread, &attr, _panel_callback, (void *)panel);
pthread_attr_destroy(&attr); pthread_attr_destroy(&attr);
while (!panel->callback_thread_running) while (!panel->callback_thread_running)
pthread_cond_wait (&panel->startup_cond, &panel->io_lock); /* Wait for thread to stabilize */ pthread_cond_wait (&panel->startup_done, &panel->io_lock); /* Wait for thread to stabilize */
pthread_cond_destroy (&panel->startup_cond); pthread_cond_destroy (&panel->startup_done);
} }
if ((usecs_between_callbacks == 0) && panel->usecs_between_callbacks) { /* Need to stop callbacks */ if ((usecs_between_callbacks == 0) && panel->usecs_between_callbacks) { /* Need to stop callbacks */
panel->usecs_between_callbacks = 0; panel->usecs_between_callbacks = 0; /* flag disabled */
pthread_mutex_unlock (&panel->io_lock); pthread_mutex_unlock (&panel->io_lock); /* allow access */
pthread_join (panel->callback_thread, NULL); pthread_join (panel->callback_thread, NULL); /* synchronize with thread rundown */
pthread_mutex_lock (&panel->io_lock); pthread_mutex_lock (&panel->io_lock); /* reacquire access */
} }
pthread_mutex_unlock (&panel->io_lock); pthread_mutex_unlock (&panel->io_lock);
return 0; return 0;
@ -1310,6 +1350,8 @@ return 0;
int int
sim_panel_exec_boot (PANEL *panel, const char *device) sim_panel_exec_boot (PANEL *panel, const char *device)
{ {
int cmd_stat;
if (!panel || (panel->State == Error)) { if (!panel || (panel->State == Error)) {
sim_panel_set_error ("Invalid Panel"); sim_panel_set_error ("Invalid Panel");
return -1; return -1;
@ -1322,12 +1364,47 @@ if (panel->State == Run) {
sim_panel_set_error ("Not Halted"); sim_panel_set_error ("Not Halted");
return -1; 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)) if (_panel_sendf (panel, NULL, NULL, "BOOT %s\r", device))
return -1; return -1;
panel->State = Run; panel->State = Run;
return 0; 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 int
sim_panel_exec_run (PANEL *panel) sim_panel_exec_run (PANEL *panel)
{ {
@ -1522,7 +1599,7 @@ if (_panel_sendf (panel, &cmd_stat, &response, "EXAMINE -H %s", name_or_addr)) {
} }
c = strchr (response, ':'); c = strchr (response, ':');
if (!c) { if (!c) {
sim_panel_set_error (response); sim_panel_set_error ("response: %s", response);
free (response); free (response);
return -1; return -1;
} }
@ -1824,6 +1901,8 @@ int buf_data = 0;
pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority); pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority);
++sched_priority.sched_priority; ++sched_priority.sched_priority;
pthread_setschedparam (pthread_self(), sched_policy, &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'; buf[buf_data] = '\0';
pthread_mutex_lock (&p->io_lock); pthread_mutex_lock (&p->io_lock);
@ -1855,7 +1934,7 @@ if (!p->parent) {
} }
p->io_thread_running = 1; p->io_thread_running = 1;
pthread_mutex_unlock (&p->io_lock); 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); msleep (100);
pthread_mutex_lock (&p->io_lock); pthread_mutex_lock (&p->io_lock);
while ((p->sock != INVALID_SOCKET) && while ((p->sock != INVALID_SOCKET) &&
@ -1865,8 +1944,8 @@ while ((p->sock != INVALID_SOCKET) &&
pthread_mutex_unlock (&p->io_lock); pthread_mutex_unlock (&p->io_lock);
new_data = sim_read_sock (p->sock, &buf[buf_data], sizeof(buf)-(buf_data+1)); new_data = sim_read_sock (p->sock, &buf[buf_data], sizeof(buf)-(buf_data+1));
if (new_data <= 0) {
pthread_mutex_lock (&p->io_lock); pthread_mutex_lock (&p->io_lock);
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; p->State = Error;
@ -1893,7 +1972,7 @@ while ((p->sock != INVALID_SOCKET) &&
s = eol; s = eol;
while (isspace(0xFF & (*s))) while (isspace(0xFF & (*s)))
++s; ++s;
continue; continue; /* process next line */
} }
if ((*s == '}') && if ((*s == '}') &&
(3 == sscanf (s, "}%s %s %s", smp_dev, smp_reg, smp_ind))) { /* Register bit Sample Data? */ (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))) while (isspace(0xFF & (*s)))
++s; ++s;
continue; r = NULL;
continue; /* process next line */
} }
if (!strncmp (s + strlen (sim_prompt), register_ind_echo, strlen (register_ind_echo) - 1)) { if (!strncmp (s + strlen (sim_prompt), register_ind_echo, strlen (register_ind_echo) - 1)) {
e = s + strlen (sim_prompt) + strlen (register_ind_echo); e = s + strlen (sim_prompt) + strlen (register_ind_echo);
@ -1935,8 +2015,9 @@ while ((p->sock != INVALID_SOCKET) &&
while (isspace(0xFF & (*s))) while (isspace(0xFF & (*s)))
++s; ++s;
if (r) if (r)
continue; continue; /* process next line */
} }
if (!p->io_waiting) {
if (r) { if (r) {
if (strcmp (s, r->name)) { if (strcmp (s, r->name)) {
unsigned long long data; unsigned long long data;
@ -1951,7 +2032,7 @@ while ((p->sock != INVALID_SOCKET) &&
s = eol; s = eol;
while (isspace(0xFF & (*s))) while (isspace(0xFF & (*s)))
++s; ++s;
continue; continue; /* process next line */
} }
for (i=0; i<p->reg_count; i++) { for (i=0; i<p->reg_count; i++) {
if (p->regs[i].element_count == 0) { if (p->regs[i].element_count == 0) {
@ -1995,6 +2076,7 @@ while ((p->sock != INVALID_SOCKET) &&
++s; ++s;
continue; continue;
} }
}
--e; --e;
*e = ':'; *e = ':';
/* Unexpected Register Data Found (or other output containing a : character) */ /* Unexpected Register Data Found (or other output containing a : character) */
@ -2002,19 +2084,16 @@ while ((p->sock != INVALID_SOCKET) &&
if (!strcmp (s + strlen (sim_prompt), register_repeat_echo)) { if (!strcmp (s + strlen (sim_prompt), register_repeat_echo)) {
if (p->callback) { if (p->callback) {
pthread_mutex_unlock (&p->io_lock); 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); pthread_mutex_lock (&p->io_lock);
} }
} }
if (!strcmp (s + strlen (sim_prompt), register_get_echo)) { if (!strcmp (s + strlen (sim_prompt), register_get_echo)) {
pthread_mutex_lock (&p->io_lock);
--p->io_reg_query_pending; --p->io_reg_query_pending;
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 {
pthread_mutex_lock (&p->io_lock);
if (!strcmp (s + strlen (sim_prompt), command_done_echo)) { if (!strcmp (s + strlen (sim_prompt), command_done_echo)) {
_panel_debug (p, DBG_RCV, "Received Command Complete", NULL, 0); _panel_debug (p, DBG_RCV, "Received Command Complete", NULL, 0);
p->io_waiting = 0; p->io_waiting = 0;
@ -2030,7 +2109,6 @@ while ((p->sock != INVALID_SOCKET) &&
if (t == NULL) { if (t == NULL) {
_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; p->State = Error;
pthread_mutex_unlock (&p->io_lock);
break; break;
} }
memcpy (t, p->io_response, p->io_response_data); memcpy (t, p->io_response, p->io_response_data);
@ -2047,19 +2125,19 @@ while ((p->sock != INVALID_SOCKET) &&
else else
_panel_debug (p, DBG_RCV, "Receive Data Discarded: '%s'", NULL, 0, s); _panel_debug (p, DBG_RCV, "Receive Data Discarded: '%s'", NULL, 0, s);
} }
pthread_mutex_unlock (&p->io_lock);
} }
s = eol; s = eol;
while (isspace(0xFF & (*s))) while (isspace(0xFF & (*s)))
++s; ++s;
} }
pthread_mutex_lock (&p->io_lock);
if ((p->State == Run) && (!strcmp (s, sim_prompt))) { if ((p->State == Run) && (!strcmp (s, sim_prompt))) {
_panel_debug (p, DBG_RSP, "State transitioning to Halt", NULL, 0);
p->State = Halt; p->State = Halt;
} }
memmove (buf, s, strlen (s)+1); memmove (buf, s, strlen (s)+1);
buf_data = strlen (buf); buf_data = strlen (buf);
if (!strcmp("Simulator Running...", buf)) { if (!strcmp("Simulator Running...", buf)) {
_panel_debug (p, DBG_RSP, "State transitioning to Run", NULL, 0);
p->State = Run; p->State = Run;
buf_data = 0; buf_data = 0;
buf[0] = '\0'; buf[0] = '\0';
@ -2070,6 +2148,8 @@ if (p->io_waiting) {
p->io_waiting = 0; p->io_waiting = 0;
pthread_cond_signal (&p->io_done); 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; p->io_thread_running = 0;
pthread_mutex_unlock (&p->io_lock); pthread_mutex_unlock (&p->io_lock);
return NULL; return NULL;
@ -2093,11 +2173,13 @@ int cmd_stat;
pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority); pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority);
++sched_priority.sched_priority; ++sched_priority.sched_priority;
pthread_setschedparam (pthread_self(), sched_policy, &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); pthread_mutex_lock (&p->io_lock);
p->callback_thread_running = 1; p->callback_thread_running = 1;
pthread_mutex_unlock (&p->io_lock); 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); msleep (100);
pthread_mutex_lock (&p->io_lock); pthread_mutex_lock (&p->io_lock);
while ((p->sock != INVALID_SOCKET) && while ((p->sock != INVALID_SOCKET) &&
@ -2174,6 +2256,8 @@ else {
_panel_sendf (p, &cmd_stat, NULL, "%s", register_repeat_stop); _panel_sendf (p, &cmd_stat, NULL, "%s", register_repeat_stop);
} }
pthread_mutex_lock (&p->io_lock); 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; p->callback_thread_running = 0;
pthread_mutex_unlock (&p->io_lock); pthread_mutex_unlock (&p->io_lock);
free (buf); free (buf);
@ -2239,8 +2323,6 @@ while (1) { /* format passed string, arg
} }
break; break;
} }
return;
} }
static int static int
@ -2249,7 +2331,7 @@ _panel_sendf (PANEL *p, int *completion_status, char **response, const char *fmt
char stackbuf[1024]; char stackbuf[1024];
int bufsize = sizeof(stackbuf); int bufsize = sizeof(stackbuf);
char *buf = 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; int post_fix_len = completion_status ? 7 + sizeof (command_done_echo) + sizeof (command_status) : 1;
va_list arglist; va_list arglist;
int ret; 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); _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 (completion_status) {
if (!ret) { /* Sent OK? */ if (!ret) { /* Sent OK? */
@ -2327,6 +2409,10 @@ if (completion_status) {
p->io_response[0] = '\0'; p->io_response[0] = '\0';
pthread_mutex_unlock (&p->io_lock); 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); pthread_mutex_unlock (&p->io_command_lock);
if (buf != stackbuf) if (buf != stackbuf)

View file

@ -56,7 +56,7 @@ extern "C" {
#if !defined(__VAX) /* Unsupported platform */ #if !defined(__VAX) /* Unsupported platform */
#define SIM_FRONTPANEL_VERSION 4 #define SIM_FRONTPANEL_VERSION 5
/** /**
@ -254,6 +254,8 @@ sim_panel_set_sampling_parameters (PANEL *panel,
sim_panel_exec_halt - Stop instruction execution sim_panel_exec_halt - Stop instruction execution
sim_panel_exec_boot - Boot a simulator from a specific device sim_panel_exec_boot - Boot a simulator from a specific device
sim_panel_exec_run - Start/Resume a simulator running instructions 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 sim_panel_exec_step - Have a simulator execute a single step
*/ */
@ -263,6 +265,9 @@ sim_panel_exec_halt (PANEL *panel);
int int
sim_panel_exec_boot (PANEL *panel, const char *device); sim_panel_exec_boot (PANEL *panel, const char *device);
int
sim_panel_exec_start (PANEL *panel);
int int
sim_panel_exec_run (PANEL *panel); 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. 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_set_debug_mode - Specifies the debug detail to be recorded
sim_panel_flush_debug - Flushes debug output to disk 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_XMT 1 /* Transmit Data */
#define DBG_RCV 2 /* Receive Data */ #define DBG_RCV 2 /* Receive Data */
#define DBG_REQ 4 /* Request Data */ #define DBG_REQ 4 /* Request Data */
#define DBG_RSP 8 /* Response Data */ #define DBG_RSP 8 /* Response Data */
#define DBG_THR 16 /* Thread Activities */
void void
sim_panel_set_debug_mode (PANEL *panel, int debug_bits); sim_panel_set_debug_mode (PANEL *panel, int debug_bits);