FRONTPANEL: sim_frontpanel API release 7

- Add explicit support for referencing register array elements.
- Reworked the parsing of the grouped output sets for explicitly queried
   registers and the auto repeat output sets.
- Fix race conditions in the various RUN, START, BOOT, and CONT commands.
- Fix incorrect RUN/HALT state after STEP commands
- Tolerate input TCP traffic that has been legitimately coalesced into
   different
This commit is contained in:
Mark Pizzolato 2017-12-09 01:25:34 -08:00
parent 0e4ee6ecce
commit b4c3fa1656
3 changed files with 208 additions and 164 deletions

View file

@ -62,6 +62,7 @@ unsigned int PCQ[32];
int PSL_bits[32];
int PC_bits[32];
int PC_indirect_bits[32];
int PCQ_3_bits[32];
int update_display = 1;
@ -422,7 +423,7 @@ if (sim_panel_set_sampling_parameters_ex (panel, 500, 10, 100)) {
goto Done;
}
if (sim_panel_add_register_indirect_bits (panel, "PC", NULL, 32, PC_indirect_bits)) {
printf ("Error adding register 'PSL' bits: %s\n", sim_panel_get_error());
printf ("Error adding register 'PC' indirect bits: %s\n", sim_panel_get_error());
goto Done;
}
if (sim_panel_add_register_bits (panel, "PSL", NULL, 32, PSL_bits)) {
@ -433,6 +434,10 @@ 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 (sim_panel_add_register_bits (panel, "PCQ[3]", NULL, 32, PCQ_3_bits)) {
printf ("Error adding register 'PCQ[3]' bits: %s\n", sim_panel_get_error());
goto Done;
}
if (1) {
unsigned int noop_noop_noop_halt = 0x00010101, addr400 = 0x00000400, pc_value;
int mstime = 0;
@ -464,7 +469,24 @@ if (1) {
goto Done;
}
if (pc_value != addr400 + 4) {
printf ("Unexpected error getting PC value: %08X, expected: %08X\n", pc_value, addr400 + 4);
printf ("Unexpected PC value after HALT: %08X, expected: %08X\n", pc_value, addr400 + 4);
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_step (panel)) {
printf ("Error executing a single step: %s\n", sim_panel_get_error());
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 + 1) {
printf ("Unexpected PC value after STEP: %08X, expected: %08X\n", pc_value, addr400 + 1);
goto Done;
}
}

View file

@ -217,8 +217,10 @@ static const char *register_collect_mid1 = " samples every ";
static const char *register_collect_mid2 = " cycles dither ";
static const char *register_collect_mid3 = " percent ";
static const char *register_get_postfix = "sampleout";
static const char *register_get_echo = "# REGISTERS-DONE";
static const char *register_repeat_echo = "# REGISTERS-REPEAT-DONE";
static const char *register_get_start = "# REGISTERS-START";
static const char *register_get_end = "# REGISTERS-DONE";
static const char *register_repeat_start = "# REGISTERS-REPEAT-START\r";
static const char *register_repeat_end = "# REGISTERS-REPEAT-DONE";
static const char *register_dev_echo = "# REGISTERS-FOR-DEVICE:";
static const char *register_ind_echo = "# REGISTER-INDIRECT:";
static const char *command_status = "ECHO Status:%STATUS%-%TSTATUS%";
@ -451,7 +453,9 @@ size_t i, j, buf_data, buf_needed = 0, reg_count = 0, bit_reg_count = 0;
const char *dev;
pthread_mutex_lock (&panel->io_lock);
buf_needed = 2 + strlen (register_get_prefix); /* SHOW TIME */
buf_needed = 3 +
strlen (register_get_start) + /* # REGISTERS-START */
strlen (register_get_prefix); /* SHOW TIME */
for (i=0; i<panel->reg_count; i++) {
if (panel->regs[i].bits)
++bit_reg_count;
@ -466,7 +470,7 @@ for (i=0; i<panel->reg_count; i++) {
}
if (bit_reg_count)
buf_needed += 2 + strlen (register_get_postfix);
buf_needed += 10 + strlen (register_get_echo); /* # REGISTERS-DONE */
buf_needed += 10 + strlen (register_get_end); /* # REGISTERS-DONE */
if (buf_needed > *buf_size) {
free (*buf);
*buf = (char *)_panel_malloc (buf_needed);
@ -479,7 +483,7 @@ if (buf_needed > *buf_size) {
}
buf_data = 0;
if (reg_count) {
sprintf (*buf + buf_data, "%s\r", register_get_prefix);
sprintf (*buf + buf_data, "%s\r%s\r", register_get_start, register_get_prefix);
buf_data += strlen (*buf + buf_data);
}
dev = "";
@ -540,7 +544,7 @@ if (bit_reg_count) {
strcpy (*buf + buf_data, "\r");
buf_data += strlen (*buf + buf_data);
}
strcpy (*buf + buf_data, register_get_echo);
strcpy (*buf + buf_data, register_get_end);
buf_data += strlen (*buf + buf_data);
strcpy (*buf + buf_data, "\r");
buf_data += strlen (*buf + buf_data);
@ -1435,7 +1439,7 @@ if (_panel_sendf (panel, &cmd_stat, NULL, "SHOW TIME\r"))
panel->simulation_time_base += panel->simulation_time;
if (_panel_sendf (panel, NULL, NULL, "BOOT %s\r", device))
return -1;
panel->State = Run;
msleep (100); /* Allow Run/Hslt state to settle */
return 0;
}
@ -1464,7 +1468,7 @@ if (_panel_sendf (panel, &cmd_stat, NULL, "SHOW TIME\r"))
panel->simulation_time_base += panel->simulation_time;
if (_panel_sendf (panel, NULL, NULL, "RUN -Q\r", 5))
return -1;
panel->State = Run;
msleep (100); /* Allow Run/Hslt state to settle */
return 0;
}
@ -1485,7 +1489,7 @@ if (panel->State == Run) {
}
if (_panel_sendf (panel, NULL, NULL, "CONT\r", 5))
return -1;
panel->State = Run;
msleep (100); /* Allow Run/Hslt state to settle */
return 0;
}
@ -1507,7 +1511,6 @@ if (panel->State == Run) {
if (5 != _panel_send (panel, "STEP\r", 5))
return -1;
panel->State = Run;
return 0;
}
@ -1951,11 +1954,12 @@ static void *
_panel_reader(void *arg)
{
PANEL *p = (PANEL*)arg;
REG *r;
REG *r = NULL;
int sched_policy;
struct sched_param sched_priority;
char buf[4096];
int buf_data = 0;
int processing_register_output = 0;
/*
Boost Priority for this response processing thread to quickly digest
@ -2020,183 +2024,194 @@ while ((p->sock != INVALID_SOCKET) &&
s = buf;
while ((eol = strchr (s, '\n'))) {
/* Line to process */
r = NULL;
*eol++ = '\0';
while ((*s) && (s[strlen(s)-1] == '\r'))
s[strlen(s)-1] = '\0';
e = strchr (s, ':');
if (e) {
size_t i;
char smp_dev[32], smp_reg[32], smp_ind[32];
unsigned int bit;
if (processing_register_output) {
e = strchr (s, ':');
if (e) {
size_t i;
char smp_dev[32], smp_reg[32], smp_ind[32];
unsigned int bit;
*e++ = '\0';
if (!strcmp("Time", s)) {
p->simulation_time = strtoull (e, NULL, 10);
s = eol;
while (isspace(0xFF & (*s)))
++s;
continue; /* process next line */
}
if ((*s == '}') &&
(3 == sscanf (s, "}%s %s %s", smp_dev, smp_reg, smp_ind))) { /* Register bit Sample Data? */
r = NULL;
for (i=0; i<p->reg_count; i++) {
if (p->regs[i].bits == NULL)
continue;
if ((!strcmp (smp_reg, p->regs[i].name)) &&
((!p->device_name) || (!strcmp (smp_dev, p->device_name)))) {
r = &p->regs[i];
break;
}
}
if (r) {
for (bit = 0; bit < r->bit_count; bit++) {
int val = (int)strtol (e, &e, 10);
r->bits[bit] = val;
if (*e == ',')
++e;
else
break;
}
*e++ = '\0';
if (!strcmp("Time", s)) {
p->simulation_time = strtoull (e, NULL, 10);
s = eol;
while (isspace(0xFF & (*s)))
++s;
continue; /* process next line */
}
while (isspace(0xFF & (*s)))
++s;
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);
r = NULL;
for (i=0; i<p->reg_count; i++) {
if (p->regs[i].indirect && (!strcmp(p->regs[i].name, e))) {
r = &p->regs[i];
break;
if ((*s == '}') &&
(3 == sscanf (s, "}%s %s %s", smp_dev, smp_reg, smp_ind))) { /* Register bit Sample Data? */
r = NULL;
for (i=0; i<p->reg_count; i++) {
if (p->regs[i].bits == NULL)
continue;
if ((!strcmp (smp_reg, p->regs[i].name)) &&
((!p->device_name) || (!strcmp (smp_dev, p->device_name)))) {
r = &p->regs[i];
break;
}
}
if (r) {
for (bit = 0; bit < r->bit_count; bit++) {
int val = (int)strtol (e, &e, 10);
r->bits[bit] = val;
if (*e == ',')
++e;
else
break;
}
s = eol;
}
while (isspace(0xFF & (*s)))
++s;
r = NULL;
continue; /* process next line */
}
s = eol;
while (isspace(0xFF & (*s)))
++s;
if (r)
continue; /* process next line */
}
if (!p->io_waiting) {
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;
if (!strncmp (s + strlen (sim_prompt), register_ind_echo, strlen (register_ind_echo) - 1)) {
e = s + strlen (sim_prompt) + strlen (register_ind_echo);
r = NULL;
for (i=0; i<p->reg_count; i++) {
if (p->regs[i].indirect && (!strcmp(p->regs[i].name, e))) {
r = &p->regs[i];
break;
}
}
s = eol;
while (isspace(0xFF & (*s)))
++s;
continue; /* process next line */
if (r)
continue; /* process next line */
}
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 = ':';
/* Unexpected Register Data Found (or other output containing a : character) */
}
--e;
*e = ':';
/* Unexpected Register Data Found (or other output containing a : character) */
}
if (!strcmp (s + strlen (sim_prompt), register_repeat_echo)) {
if (!strcmp (s + strlen (sim_prompt), register_repeat_end)) {
_panel_debug (p, DBG_RCV, "*Repeat Block Complete", NULL, 0);
if (p->callback) {
pthread_mutex_unlock (&p->io_lock);
p->callback (p, p->simulation_time_base + p->simulation_time, p->callback_context);
pthread_mutex_lock (&p->io_lock);
}
processing_register_output = 0;
goto Start_Next_Line;
}
if (!strcmp (s + strlen (sim_prompt), register_get_echo)) {
if ((!strcmp (s + strlen (sim_prompt), register_repeat_start)) ||
(!strcmp (s + strlen (sim_prompt), register_get_start))) {
_panel_debug (p, DBG_RCV, "*Repeat/Register Block Starting", NULL, 0);
processing_register_output = 1;
goto Start_Next_Line;
}
if (!strcmp (s + strlen (sim_prompt), register_get_end)) {
_panel_debug (p, DBG_RCV, "*Register Block Complete", NULL, 0);
--p->io_reg_query_pending;
p->io_waiting = 0;
pthread_cond_signal (&p->io_done);
goto Start_Next_Line;
}
else {
if (!strcmp (s + strlen (sim_prompt), command_done_echo)) {
_panel_debug (p, DBG_RCV, "Received Command Complete", NULL, 0);
p->io_waiting = 0;
pthread_cond_signal (&p->io_done);
}
else {
/* Non Register Data Found (echo of EXAMINE or other commands and/or command output) */
if (p->io_waiting) {
char *t;
if (!strcmp (s + strlen (sim_prompt), command_done_echo)) {
_panel_debug (p, DBG_RCV, "*Received Command Complete", NULL, 0);
p->io_waiting = 0;
pthread_cond_signal (&p->io_done);
goto Start_Next_Line;
}
/* Non Register Data Found (echo of EXAMINE or other commands and/or command output) */
if (p->io_waiting) {
char *t;
if (p->io_response_data + strlen (s) + 3 > p->io_response_size) {
t = (char *)_panel_malloc (p->io_response_data + strlen (s) + 3);
if (t == NULL) {
_panel_debug (p, DBG_RCV, "%s", NULL, 0, sim_panel_get_error());
p->State = Error;
break;
}
memcpy (t, p->io_response, p->io_response_data);
free (p->io_response);
p->io_response = t;
p->io_response_size = p->io_response_data + strlen (s) + 3;
}
_panel_debug (p, DBG_RCV, "Receive Data Accumulated: '%s'", NULL, 0, s);
strcpy (p->io_response + p->io_response_data, s);
p->io_response_data += strlen(s);
strcpy (p->io_response + p->io_response_data, "\r\n");
p->io_response_data += 2;
if (p->io_response_data + strlen (s) + 3 > p->io_response_size) {
t = (char *)_panel_malloc (p->io_response_data + strlen (s) + 3);
if (t == NULL) {
_panel_debug (p, DBG_RCV, "%s", NULL, 0, sim_panel_get_error());
p->State = Error;
break;
}
else
_panel_debug (p, DBG_RCV, "Receive Data Discarded: '%s'", NULL, 0, s);
memcpy (t, p->io_response, p->io_response_data);
free (p->io_response);
p->io_response = t;
p->io_response_size = p->io_response_data + strlen (s) + 3;
}
_panel_debug (p, DBG_RCV, "Receive Data Accumulated: '%s'", NULL, 0, s);
strcpy (p->io_response + p->io_response_data, s);
p->io_response_data += strlen(s);
strcpy (p->io_response + p->io_response_data, "\r\n");
p->io_response_data += 2;
}
else
_panel_debug (p, DBG_RCV, "Receive Data Discarded: '%s'", NULL, 0, s);
Start_Next_Line:
s = eol;
while (isspace(0xFF & (*s)))
++s;
}
memmove (buf, s, strlen (s)+1);
buf_data = strlen (buf);
_panel_debug (p, DBG_RSP, "Remnant Buffer Contents: '%s'", NULL, 0, buf);
if (buf_data)
_panel_debug (p, DBG_RSP, "Remnant Buffer Contents: '%s'", NULL, 0, buf);
if (!memcmp ("Simulator Running...", buf, 20)) {
_panel_debug (p, DBG_RSP, "State transitioning to Run", NULL, 0);
p->State = Run;
@ -2280,22 +2295,25 @@ while ((p->sock != INVALID_SOCKET) &&
strlen (register_repeat_units) + /* units and spacing */
buf_data + /* command contents */
1 + /* carriage return */
strlen (register_repeat_echo) + /* auto repeat completion */
strlen (register_repeat_start) + /* auto repeat begin */
1 + /* carriage return */
strlen (register_repeat_end) + /* auto repeat completion */
1 + /* carriage return */
1; /* NUL */
char *repeat = (char *)malloc (repeat_data);
char *c;
sprintf (repeat, "%s%d%s%*.*s", register_repeat_prefix,
sprintf (repeat, "%s%d%s%s%*.*s", register_repeat_prefix,
p->usecs_between_callbacks,
register_repeat_units,
register_repeat_start,
(int)buf_data, (int)buf_data, buf);
pthread_mutex_unlock (&p->io_lock);
for (c = strchr (repeat, '\r'); c != NULL; c = strchr (c, '\r'))
*c = ';'; /* replace carriage returns with semicolons */
c = strstr (repeat, register_get_echo); /* remove register_done_echo string and */
c = strstr (repeat, register_get_end); /* remove register_done_echo string and */
if (c) /* always true */
strcpy (c, register_repeat_echo); /* replace it with the register_repeat_echo string */
strcpy (c, register_repeat_end); /* replace it with the register_repeat_end string */
if (_panel_sendf (p, &cmd_stat, NULL, "%s", repeat)) {
pthread_mutex_lock (&p->io_lock);
free (repeat);
@ -2450,32 +2468,36 @@ ret = ((len + status_echo_len) == (sent_len = _panel_send (p, buf, len + status_
if (completion_status) {
if (!ret) { /* Sent OK? */
char *tresponse = NULL;
p->io_waiting = 1;
while (p->io_waiting)
pthread_cond_wait (&p->io_done, &p->io_lock); /* Wait for completion */
if (response) {
*response = (char *)_panel_malloc (p->io_response_data + 1);
if (0 == memcmp (buf, p->io_response + strlen (sim_prompt), len)) {
char *eol, *status;
memcpy (*response, p->io_response + strlen (sim_prompt) + len + 1, p->io_response_data + 1 - (strlen (sim_prompt) + len + 1));
*completion_status = -1;
status = strstr (*response, command_status);
if (status) {
*(status - strlen (sim_prompt)) = '\0';
status += strlen (command_status) + 2;
eol = strchr (status, '\r');
if (eol)
*eol = '\0';
sscanf (status, "Status:%08X-", completion_status);
}
tresponse = (char *)_panel_malloc (p->io_response_data + 1);
if (0 == memcmp (buf, p->io_response + strlen (sim_prompt), len)) {
char *eol, *status;
memcpy (tresponse, p->io_response + strlen (sim_prompt) + len + 1, p->io_response_data + 1 - (strlen (sim_prompt) + len + 1));
*completion_status = -1;
status = strstr (tresponse, command_status);
if (status) {
*(status - strlen (sim_prompt)) = '\0';
status += strlen (command_status) + 2;
eol = strchr (status, '\r');
if (eol)
*eol = '\0';
sscanf (status, "Status:%08X-", completion_status);
}
else
memcpy (*response, p->io_response, p->io_response_data + 1);
}
else
memcpy (tresponse, p->io_response, p->io_response_data + 1);
if (response) {
*response = tresponse;
_panel_debug (p, DBG_RSP, "Command %d Response(Status=%d): '%s'", NULL, 0, p->command_count, *completion_status, *response);
}
else {
free (tresponse);
if (p->io_response_data)
_panel_debug (p, DBG_RSP, "Discarded Unwanted Command %d Response Data:", p->io_response, p->io_response_data, p->command_count);
_panel_debug (p, DBG_RSP, "Discarded Unwanted Command %d Response Data(Status=%d):", p->io_response, p->io_response_data, p->command_count, *completion_status);
}
}
p->io_response_data = 0;

View file

@ -56,7 +56,7 @@ extern "C" {
#if !defined(__VAX) /* Unsupported platform */
#define SIM_FRONTPANEL_VERSION 6
#define SIM_FRONTPANEL_VERSION 7
/**