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:
parent
097172f8a3
commit
e73d45ebcc
4 changed files with 273 additions and 102 deletions
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
264
sim_frontpanel.c
264
sim_frontpanel.c
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue