FRONTPANEL: Added better protocol debug support to debug simulator startup issues

This commit is contained in:
Mark Pizzolato 2015-02-26 11:28:08 -08:00
parent df6953bf82
commit 71fe58b33a
4 changed files with 135 additions and 64 deletions

View file

@ -58,12 +58,23 @@ const char *sim_config =
/* Registers visible on the Front Panel */ /* Registers visible on the Front Panel */
unsigned int PC, SP, FP, AP, R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11; unsigned int PC, SP, FP, AP, R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11;
int update_display = 1;
static void static void
DisplayCallback (PANEL *panel, unsigned long long simulation_time, void *context) DisplayCallback (PANEL *panel, unsigned long long simulation_time, void *context)
{ {
update_display = 1;
}
static void
DisplayRegisters (PANEL *panel)
{
char buf1[100], buf2[100], buf3[100]; char buf1[100], buf2[100], buf3[100];
static const char *states[] = {"Halt", "Run "}; static const char *states[] = {"Halt", "Run "};
if (!update_display)
return;
update_display = 0;
buf1[sizeof(buf1)-1] = buf2[sizeof(buf2)-1] = buf3[sizeof(buf3)-1] = 0; buf1[sizeof(buf1)-1] = buf2[sizeof(buf2)-1] = buf3[sizeof(buf3)-1] = 0;
sprintf (buf1, "%s PC: %08X SP: %08X AP: %08X FP: %08X\r\n", states[sim_panel_get_state (panel)], PC, SP, AP, FP); sprintf (buf1, "%s PC: %08X SP: %08X AP: %08X FP: %08X\r\n", states[sim_panel_get_state (panel)], PC, SP, AP, FP);
sprintf (buf2, "R0:%08X R1:%08X R2:%08X R3:%08X R4:%08X R5:%08X\r\n", R0, R1, R2, R3, R4, R5); sprintf (buf2, "R0:%08X R1:%08X R2:%08X R3:%08X R4:%08X R5:%08X\r\n", R0, R1, R2, R3, R4, R5);
@ -133,8 +144,8 @@ if ((argc > 1) && ((!strcmp("-d", argv[1])) || (!strcmp("-D", argv[1])) || (!str
if ((f = fopen (sim_config, "w"))) { 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 log simulator.dbg\n");
fprintf (f, "set log debug\n"); fprintf (f, "set debug -n -a log\n");
fprintf (f, "set cpu conhalt\n"); fprintf (f, "set cpu conhalt\n");
fprintf (f, "set remote telnet=2226\n"); fprintf (f, "set remote telnet=2226\n");
fprintf (f, "set rem-con debug=XMT;RCV\n"); fprintf (f, "set rem-con debug=XMT;RCV\n");
@ -149,7 +160,7 @@ if ((f = fopen (sim_config, "w"))) {
fprintf (f, "set env PATH=%%PATH%%;%%ProgramFiles%%\\PuTTY;%%ProgramFiles(x86)%%\\PuTTY\n"); fprintf (f, "set env PATH=%%PATH%%;%%ProgramFiles%%\\PuTTY;%%ProgramFiles(x86)%%\\PuTTY\n");
fprintf (f, "! start PuTTY telnet://localhost:1927\n"); fprintf (f, "! start PuTTY telnet://localhost:1927\n");
#elif defined(__linux) || defined(__linux__) #elif defined(__linux) || defined(__linux__)
fprintf (f, "! xterm -e 'telnet localhost 1927' &\n"); fprintf (f, "! nohup xterm -e 'telnet localhost 1927' &\n");
#elif defined(__APPLE__) #elif defined(__APPLE__)
fprintf (f, "! osascript -e 'tell application \"Terminal\" to do script \"telnet localhost 1927; exit\"'\n"); fprintf (f, "! osascript -e 'tell application \"Terminal\" to do script \"telnet localhost 1927; exit\"'\n");
#endif #endif
@ -158,9 +169,10 @@ if ((f = fopen (sim_config, "w"))) {
InitDisplay(); InitDisplay();
signal (SIGINT, halt_handler); signal (SIGINT, halt_handler);
panel = sim_panel_start_simulator (sim_path, panel = sim_panel_start_simulator_debug (sim_path,
sim_config, sim_config,
2); 2,
debug? "frontpanel.dbg" : NULL);
if (!panel) { if (!panel) {
printf ("Error starting simulator: %s\n", sim_panel_get_error()); printf ("Error starting simulator: %s\n", sim_panel_get_error());
@ -168,7 +180,6 @@ if (!panel) {
} }
if (debug) { if (debug) {
sim_panel_set_debug_file (panel, "frontpanel.dbg");
sim_panel_set_debug_mode (panel, DBG_XMT|DBG_RCV); sim_panel_set_debug_mode (panel, DBG_XMT|DBG_RCV);
} }
@ -251,7 +262,6 @@ if (sim_panel_get_registers (panel, NULL)) {
printf ("Error getting register data: %s\n", sim_panel_get_error()); printf ("Error getting register data: %s\n", sim_panel_get_error());
goto Done; goto Done;
} }
DisplayCallback (panel, 0ll, NULL);
if (sim_panel_set_display_callback (panel, &DisplayCallback, NULL, 5)) { if (sim_panel_set_display_callback (panel, &DisplayCallback, NULL, 5)) {
printf ("Error setting automatic display callback: %s\n", sim_panel_get_error()); printf ("Error setting automatic display callback: %s\n", sim_panel_get_error());
goto Done; goto Done;
@ -265,6 +275,7 @@ while (1) {
char cmd[512]; char cmd[512];
while (sim_panel_get_state (panel) == Halt) { while (sim_panel_get_state (panel) == Halt) {
DisplayRegisters (panel);
printf ("SIM> "); printf ("SIM> ");
if (!fgets (cmd, sizeof(cmd)-1, stdin)) if (!fgets (cmd, sizeof(cmd)-1, stdin))
break; break;
@ -295,6 +306,8 @@ while (1) {
} }
while (sim_panel_get_state (panel) == Run) { while (sim_panel_get_state (panel) == Run) {
usleep (100); usleep (100);
if (update_display)
DisplayRegisters(panel);
if (halt_cpu) { if (halt_cpu) {
halt_cpu = 0; halt_cpu = 0;
sim_panel_exec_halt (panel); sim_panel_exec_halt (panel);

View file

@ -188,84 +188,98 @@ static unsigned char mantra[] = {
TN_IAC, TN_DO, TN_BIN TN_IAC, TN_DO, TN_BIN
}; };
static void *
_panel_malloc (size_t size)
{
void *p = malloc (size);
if (p == NULL)
sim_panel_set_error ("Out of Memory");
return p;
}
static void _panel_debug (PANEL *p, int dbits, const char *fmt, const char *buf, int bufsize, ...) static void _panel_debug (PANEL *p, int dbits, const char *fmt, const char *buf, int bufsize, ...)
{ {
if (p && p->Debug && (dbits & p->debug)) { if (p && p->Debug && (dbits & p->debug)) {
int i; int i;
struct timespec time_now; struct timespec time_now;
va_list arglist; va_list arglist;
char timestamp[32];
size_t obufsize = 10240 + 8*bufsize;
char *obuf = (char *)_panel_malloc (obufsize);
clock_gettime(CLOCK_REALTIME, &time_now); clock_gettime(CLOCK_REALTIME, &time_now);
fprintf(p->Debug, "%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));
va_start (arglist, bufsize); va_start (arglist, bufsize);
vfprintf (p->Debug, 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:
fprintf(p->Debug, "_TN_CR_"); sprintf (&obuf[strlen (obuf)], "_TN_CR_");
break; break;
case TN_LF: case TN_LF:
fprintf(p->Debug, "_TN_LF_"); sprintf (&obuf[strlen (obuf)], "_TN_LF_");
break; break;
case TN_IAC: case TN_IAC:
fprintf(p->Debug, "_TN_IAC_"); sprintf (&obuf[strlen (obuf)], "_TN_IAC_");
switch ((unsigned char)buf[i+1]) { switch ((unsigned char)buf[i+1]) {
case TN_IAC: case TN_IAC:
fprintf(p->Debug, "_TN_IAC_"); ++i; sprintf (&obuf[strlen (obuf)], "_TN_IAC_"); ++i;
break; break;
case TN_DONT: case TN_DONT:
fprintf(p->Debug, "_TN_DONT_"); ++i; sprintf (&obuf[strlen (obuf)], "_TN_DONT_"); ++i;
break; break;
case TN_DO: case TN_DO:
fprintf(p->Debug, "_TN_DO_"); ++i; sprintf (&obuf[strlen (obuf)], "_TN_DO_"); ++i;
break; break;
case TN_WONT: case TN_WONT:
fprintf(p->Debug, "_TN_WONT_"); ++i; sprintf (&obuf[strlen (obuf)], "_TN_WONT_"); ++i;
break; break;
case TN_WILL: case TN_WILL:
fprintf(p->Debug, "_TN_WILL_"); ++i; sprintf (&obuf[strlen (obuf)], "_TN_WILL_"); ++i;
break; break;
default: default:
fprintf(p->Debug, "_0x%02X_", (unsigned char)buf[i+1]); ++i; sprintf (&obuf[strlen (obuf)], "_0x%02X_", (unsigned char)buf[i+1]); ++i;
break; break;
} }
switch ((unsigned char)buf[i+1]) { switch ((unsigned char)buf[i+1]) {
case TN_BIN: case TN_BIN:
fprintf(p->Debug, "_TN_BIN_"); ++i; sprintf (&obuf[strlen (obuf)], "_TN_BIN_"); ++i;
break; break;
case TN_ECHO: case TN_ECHO:
fprintf(p->Debug, "_TN_ECHO_"); ++i; sprintf (&obuf[strlen (obuf)], "_TN_ECHO_"); ++i;
break; break;
case TN_SGA: case TN_SGA:
fprintf(p->Debug, "_TN_SGA_"); ++i; sprintf (&obuf[strlen (obuf)], "_TN_SGA_"); ++i;
break; break;
case TN_LINE: case TN_LINE:
fprintf(p->Debug, "_TN_LINE_"); ++i; sprintf (&obuf[strlen (obuf)], "_TN_LINE_"); ++i;
break; break;
default: default:
fprintf(p->Debug, "_0x%02X_", (unsigned char)buf[i+1]); ++i; sprintf (&obuf[strlen (obuf)], "_0x%02X_", (unsigned char)buf[i+1]); ++i;
break; break;
} }
break; break;
default: default:
if (isprint((u_char)buf[i])) if (isprint((u_char)buf[i]))
fprintf(p->Debug, "%c", buf[i]); sprintf (&obuf[strlen (obuf)], "%c", buf[i]);
else { else {
fprintf(p->Debug, "_"); sprintf (&obuf[strlen (obuf)], "_");
if ((buf[i] >= 1) && (buf[i] <= 26)) if ((buf[i] >= 1) && (buf[i] <= 26))
fprintf(p->Debug, "^%c", 'A' + buf[i] - 1); sprintf (&obuf[strlen (obuf)], "^%c", 'A' + buf[i] - 1);
else else
fprintf(p->Debug, "\\%03o", (u_char)buf[i]); sprintf (&obuf[strlen (obuf)], "\\%03o", (u_char)buf[i]);
fprintf(p->Debug, "_"); sprintf (&obuf[strlen (obuf)], "_");
} }
break; break;
} }
} }
fprintf(p->Debug, "\n"); fprintf(p->Debug, "%s%s\n", timestamp, obuf);
free (obuf);
} }
} }
@ -294,16 +308,6 @@ if (panel->Debug)
} }
static void *
_panel_malloc (size_t size)
{
void *p = malloc (size);
if (p == NULL)
sim_panel_set_error ("Out of Memory");
return p;
}
static int static int
_panel_send (PANEL *p, const char *msg, int len) _panel_send (PANEL *p, const char *msg, int len)
{ {
@ -446,6 +450,15 @@ sim_panel_start_simulator (const char *sim_path,
const char *sim_config, const char *sim_config,
size_t device_panel_count) size_t device_panel_count)
{ {
return sim_panel_start_simulator_debug (sim_path, sim_config, device_panel_count, NULL);
}
PANEL *
sim_panel_start_simulator_debug (const char *sim_path,
const char *sim_config,
size_t device_panel_count,
const char *debug_file)
{
PANEL *p = NULL; PANEL *p = NULL;
FILE *fIn = NULL; FILE *fIn = NULL;
FILE *fOut = NULL; FILE *fOut = NULL;
@ -528,6 +541,11 @@ fprintf (fOut, "set remote -u telnet=%s\n", hostport);
fprintf (fOut, "set remote master\n"); fprintf (fOut, "set remote master\n");
fclose (fOut); fclose (fOut);
fOut = NULL; fOut = NULL;
if (debug_file) {
sim_panel_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);
}
if (1) { if (1) {
#if defined(_WIN32) #if defined(_WIN32)
char cmd[2048]; char cmd[2048];
@ -554,6 +572,7 @@ if (1) {
p->pidProcess = fork(); p->pidProcess = fork();
if (p->pidProcess == 0) { if (p->pidProcess == 0) {
close (0); close (1); close (2); /* make sure not to pass the open standard handles */ close (0); close (1); close (2); /* make sure not to pass the open standard handles */
dup (dup (open ("/dev/null", O_RDWR))); /* open standard handles to /dev/null */
if (execlp (sim_path, sim_path, p->temp_config, NULL, NULL)) { if (execlp (sim_path, sim_path, p->temp_config, NULL, NULL)) {
perror ("execl"); perror ("execl");
exit(errno); exit(errno);
@ -574,17 +593,25 @@ for (i=0; i<100; i++) { /* Allow up to 10 seconds waiting for simulator
break; break;
} }
if (p->sock == INVALID_SOCKET) { if (p->sock == INVALID_SOCKET) {
if (stat (sim_path, &statb) < 0)
sim_panel_set_error ("Can't stat simulator '%s': %s", sim_path, strerror(errno));
else
sim_panel_set_error ("Can't connect to simulator Remote Console on port %s", hostport); sim_panel_set_error ("Can't connect to simulator Remote Console on port %s", hostport);
goto Error_Return; goto Error_Return;
} }
strcpy (p->hostport, hostport); strcpy (p->hostport, hostport);
if (1) { _panel_debug (p, DBG_XMT|DBG_RCV, "Connected to simulator at %s after %dms\n", NULL, 0, hostport, i*100);
pthread_attr_t attr;
pthread_mutex_init (&p->io_lock, NULL); pthread_mutex_init (&p->io_lock, NULL);
pthread_mutex_init (&p->io_send_lock, NULL); pthread_mutex_init (&p->io_send_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_cond, 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;
}
if (1) {
pthread_attr_t attr;
pthread_attr_init(&attr); pthread_attr_init(&attr);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
pthread_mutex_lock (&p->io_lock); pthread_mutex_lock (&p->io_lock);
@ -595,10 +622,6 @@ if (1) {
pthread_mutex_unlock (&p->io_lock); pthread_mutex_unlock (&p->io_lock);
pthread_cond_destroy (&p->startup_cond); pthread_cond_destroy (&p->startup_cond);
} }
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;
}
if (device_panel_count) { if (device_panel_count) {
p->devices = (PANEL **)_panel_malloc (device_panel_count*sizeof(*p->devices)); p->devices = (PANEL **)_panel_malloc (device_panel_count*sizeof(*p->devices));
if (p->devices == NULL) if (p->devices == NULL)
@ -606,8 +629,7 @@ if (device_panel_count) {
memset (p->devices, 0, device_panel_count*sizeof(*p->devices)); memset (p->devices, 0, device_panel_count*sizeof(*p->devices));
p->device_count = device_panel_count; p->device_count = device_panel_count;
} }
msleep (1000); /* Validate sim_frontpanel API version */
/* Validate existence of requested register */
if (_panel_sendf (p, 1, &p->simulator_version, "SHOW VERSION\r")) { if (_panel_sendf (p, 1, &p->simulator_version, "SHOW VERSION\r")) {
goto Error_Return; goto Error_Return;
} }
@ -634,7 +656,15 @@ if (fOut) {
} }
if (buf) if (buf)
free (buf); free (buf);
if (1) {
const char *err = sim_panel_get_error();
char *errbuf = (char *)_panel_malloc (1 + strlen (err));
strcpy (errbuf, err); /* preserve error info while closing */
sim_panel_destroy (p); sim_panel_destroy (p);
sim_panel_set_error ("%s", errbuf);
free (errbuf);
}
return NULL; return NULL;
} }
@ -666,7 +696,7 @@ if (p->device_name == NULL)
strcpy (p->device_name, device_name); strcpy (p->device_name, device_name);
p->parent = simulator_panel; p->parent = simulator_panel;
p->sock = INVALID_SOCKET; p->sock = INVALID_SOCKET;
for (i=0; i<5; i++) { for (i=0; i<100; i++) {
p->sock = sim_connect_sock_ex (NULL, simulator_panel->hostport, NULL, NULL, SIM_SOCK_OPT_NODELAY | SIM_SOCK_OPT_BLOCKING); p->sock = sim_connect_sock_ex (NULL, simulator_panel->hostport, NULL, NULL, SIM_SOCK_OPT_NODELAY | SIM_SOCK_OPT_BLOCKING);
if (p->sock == INVALID_SOCKET) if (p->sock == INVALID_SOCKET)
msleep (100); msleep (100);
@ -678,13 +708,17 @@ if (p->sock == INVALID_SOCKET) {
goto Error_Return; goto Error_Return;
} }
strcpy (p->hostport, simulator_panel->hostport); strcpy (p->hostport, simulator_panel->hostport);
if (1) {
pthread_attr_t attr;
pthread_mutex_init (&p->io_lock, NULL); pthread_mutex_init (&p->io_lock, NULL);
pthread_mutex_init (&p->io_send_lock, NULL); pthread_mutex_init (&p->io_send_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_cond, 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;
}
if (1) {
pthread_attr_t attr;
pthread_attr_init(&attr); pthread_attr_init(&attr);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
pthread_mutex_lock (&p->io_lock); pthread_mutex_lock (&p->io_lock);
@ -695,10 +729,6 @@ if (1) {
pthread_mutex_unlock (&p->io_lock); pthread_mutex_unlock (&p->io_lock);
pthread_cond_destroy (&p->startup_cond); pthread_cond_destroy (&p->startup_cond);
} }
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;
}
simulator_panel->devices[device_num] = p; simulator_panel->devices[device_num] = p;
_panel_register_panel (p); _panel_register_panel (p);
return p; return p;
@ -1069,6 +1099,28 @@ pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority);
pthread_setschedparam (pthread_self(), sched_policy, &sched_priority); pthread_setschedparam (pthread_self(), sched_policy, &sched_priority);
pthread_mutex_lock (&p->io_lock); pthread_mutex_lock (&p->io_lock);
if (!p->parent) {
while (1) {
int new_data = sim_read_sock (p->sock, &buf[buf_data], sizeof(buf)-(buf_data+1));
if (new_data <= 0) {
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;
break;
}
_panel_debug (p, DBG_RCV, "Startup receive of %d bytes: ", &buf[buf_data], new_data, new_data);
buf_data += new_data;
buf[buf_data] = '\0';
if ((size_t)buf_data < strlen (sim_prompt))
continue;
if (!strcmp (sim_prompt, &buf[buf_data - strlen (sim_prompt)])) {
memmove (buf, &buf[buf_data - strlen (sim_prompt)], strlen (sim_prompt) + 1);
buf_data = strlen (sim_prompt);
break;
}
}
}
p->io_thread_running = 1; p->io_thread_running = 1;
pthread_cond_signal (&p->startup_cond); /* Signal we're ready to go */ pthread_cond_signal (&p->startup_cond); /* Signal we're ready to go */
while ((p->sock != INVALID_SOCKET) && while ((p->sock != INVALID_SOCKET) &&

View file

@ -82,6 +82,12 @@ sim_panel_start_simulator (const char *sim_path,
const char *sim_config, const char *sim_config,
size_t device_panel_count); size_t device_panel_count);
PANEL *
sim_panel_start_simulator_debug (const char *sim_path,
const char *sim_config,
size_t device_panel_count,
const char *debug_file);
/** /**
sim_panel_add_device_panel - creates a sub panel associated sim_panel_add_device_panel - creates a sub panel associated

View file

@ -3906,7 +3906,7 @@ while (1) { /* format passed string, arg
/* Output the formatted data expanding newlines where they exist */ /* Output the formatted data expanding newlines where they exist */
for (i = 0; i < len; ++i) { for (i = 0; i < len; ++i) {
if ('\n' == buf[i]) { if (('\n' == buf[i]) && ((i == 0) || ('\r' != buf[i-1]))) {
while (SCPE_STALL == tmxr_putc_ln (lp, '\r')) while (SCPE_STALL == tmxr_putc_ln (lp, '\r'))
if (lp->txbsz == tmxr_send_buffered_data (lp)) if (lp->txbsz == tmxr_send_buffered_data (lp))
sim_os_ms_sleep (10); sim_os_ms_sleep (10);