From 71fe58b33abf16ffe17cd9c8dc40591c58b48662 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Thu, 26 Feb 2015 11:28:08 -0800 Subject: [PATCH] FRONTPANEL: Added better protocol debug support to debug simulator startup issues --- frontpanel/FrontPanelTest.c | 29 +++++-- sim_frontpanel.c | 160 ++++++++++++++++++++++++------------ sim_frontpanel.h | 8 +- sim_tmxr.c | 2 +- 4 files changed, 135 insertions(+), 64 deletions(-) diff --git a/frontpanel/FrontPanelTest.c b/frontpanel/FrontPanelTest.c index e2d9e12b..9afa4140 100644 --- a/frontpanel/FrontPanelTest.c +++ b/frontpanel/FrontPanelTest.c @@ -58,12 +58,23 @@ const char *sim_config = /* Registers visible on the Front Panel */ unsigned int PC, SP, FP, AP, R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11; +int update_display = 1; + static void 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]; 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; 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); @@ -133,8 +144,8 @@ if ((argc > 1) && ((!strcmp("-d", argv[1])) || (!strcmp("-D", argv[1])) || (!str 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 log debug\n"); + fprintf (f, "set log simulator.dbg\n"); + fprintf (f, "set debug -n -a log\n"); fprintf (f, "set cpu conhalt\n"); fprintf (f, "set remote telnet=2226\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, "! start PuTTY telnet://localhost:1927\n"); #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__) fprintf (f, "! osascript -e 'tell application \"Terminal\" to do script \"telnet localhost 1927; exit\"'\n"); #endif @@ -158,9 +169,10 @@ if ((f = fopen (sim_config, "w"))) { InitDisplay(); signal (SIGINT, halt_handler); -panel = sim_panel_start_simulator (sim_path, - sim_config, - 2); +panel = sim_panel_start_simulator_debug (sim_path, + sim_config, + 2, + debug? "frontpanel.dbg" : NULL); if (!panel) { printf ("Error starting simulator: %s\n", sim_panel_get_error()); @@ -168,7 +180,6 @@ if (!panel) { } if (debug) { - sim_panel_set_debug_file (panel, "frontpanel.dbg"); 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()); goto Done; } -DisplayCallback (panel, 0ll, NULL); if (sim_panel_set_display_callback (panel, &DisplayCallback, NULL, 5)) { printf ("Error setting automatic display callback: %s\n", sim_panel_get_error()); goto Done; @@ -265,6 +275,7 @@ while (1) { char cmd[512]; while (sim_panel_get_state (panel) == Halt) { + DisplayRegisters (panel); printf ("SIM> "); if (!fgets (cmd, sizeof(cmd)-1, stdin)) break; @@ -295,6 +306,8 @@ while (1) { } while (sim_panel_get_state (panel) == Run) { usleep (100); + if (update_display) + DisplayRegisters(panel); if (halt_cpu) { halt_cpu = 0; sim_panel_exec_halt (panel); diff --git a/sim_frontpanel.c b/sim_frontpanel.c index 2d664eb3..98059230 100644 --- a/sim_frontpanel.c +++ b/sim_frontpanel.c @@ -188,84 +188,98 @@ static unsigned char mantra[] = { 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, ...) { if (p && p->Debug && (dbits & p->debug)) { int i; struct timespec time_now; va_list arglist; + char timestamp[32]; + size_t obufsize = 10240 + 8*bufsize; + char *obuf = (char *)_panel_malloc (obufsize); 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); - vfprintf (p->Debug, fmt, arglist); + vsnprintf (obuf, obufsize - 1, fmt, arglist); va_end (arglist); for (i=0; iDebug, "_TN_CR_"); + sprintf (&obuf[strlen (obuf)], "_TN_CR_"); break; case TN_LF: - fprintf(p->Debug, "_TN_LF_"); + sprintf (&obuf[strlen (obuf)], "_TN_LF_"); break; case TN_IAC: - fprintf(p->Debug, "_TN_IAC_"); + sprintf (&obuf[strlen (obuf)], "_TN_IAC_"); switch ((unsigned char)buf[i+1]) { case TN_IAC: - fprintf(p->Debug, "_TN_IAC_"); ++i; + sprintf (&obuf[strlen (obuf)], "_TN_IAC_"); ++i; break; case TN_DONT: - fprintf(p->Debug, "_TN_DONT_"); ++i; + sprintf (&obuf[strlen (obuf)], "_TN_DONT_"); ++i; break; case TN_DO: - fprintf(p->Debug, "_TN_DO_"); ++i; + sprintf (&obuf[strlen (obuf)], "_TN_DO_"); ++i; break; case TN_WONT: - fprintf(p->Debug, "_TN_WONT_"); ++i; + sprintf (&obuf[strlen (obuf)], "_TN_WONT_"); ++i; break; case TN_WILL: - fprintf(p->Debug, "_TN_WILL_"); ++i; + sprintf (&obuf[strlen (obuf)], "_TN_WILL_"); ++i; break; 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; } switch ((unsigned char)buf[i+1]) { case TN_BIN: - fprintf(p->Debug, "_TN_BIN_"); ++i; + sprintf (&obuf[strlen (obuf)], "_TN_BIN_"); ++i; break; case TN_ECHO: - fprintf(p->Debug, "_TN_ECHO_"); ++i; + sprintf (&obuf[strlen (obuf)], "_TN_ECHO_"); ++i; break; case TN_SGA: - fprintf(p->Debug, "_TN_SGA_"); ++i; + sprintf (&obuf[strlen (obuf)], "_TN_SGA_"); ++i; break; case TN_LINE: - fprintf(p->Debug, "_TN_LINE_"); ++i; + sprintf (&obuf[strlen (obuf)], "_TN_LINE_"); ++i; break; 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; default: if (isprint((u_char)buf[i])) - fprintf(p->Debug, "%c", buf[i]); + sprintf (&obuf[strlen (obuf)], "%c", buf[i]); else { - fprintf(p->Debug, "_"); + sprintf (&obuf[strlen (obuf)], "_"); 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 - fprintf(p->Debug, "\\%03o", (u_char)buf[i]); - fprintf(p->Debug, "_"); + sprintf (&obuf[strlen (obuf)], "\\%03o", (u_char)buf[i]); + sprintf (&obuf[strlen (obuf)], "_"); } 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 _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, 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; FILE *fIn = NULL; FILE *fOut = NULL; @@ -528,6 +541,11 @@ fprintf (fOut, "set remote -u telnet=%s\n", hostport); fprintf (fOut, "set remote master\n"); fclose (fOut); 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 defined(_WIN32) char cmd[2048]; @@ -553,7 +571,8 @@ if (1) { #else p->pidProcess = fork(); 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)) { perror ("execl"); exit(errno); @@ -574,17 +593,25 @@ for (i=0; i<100; i++) { /* Allow up to 10 seconds waiting for simulator break; } if (p->sock == INVALID_SOCKET) { - sim_panel_set_error ("Can't connect to simulator Remote Console on port %s", hostport); + 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); goto Error_Return; } strcpy (p->hostport, hostport); +_panel_debug (p, DBG_XMT|DBG_RCV, "Connected to simulator at %s after %dms\n", NULL, 0, hostport, i*100); +pthread_mutex_init (&p->io_lock, NULL); +pthread_mutex_init (&p->io_send_lock, NULL); +pthread_cond_init (&p->io_done, 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_mutex_init (&p->io_lock, NULL); - pthread_mutex_init (&p->io_send_lock, NULL); - pthread_cond_init (&p->io_done, NULL); - pthread_cond_init (&p->startup_cond, NULL); pthread_attr_init(&attr); pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); pthread_mutex_lock (&p->io_lock); @@ -595,10 +622,6 @@ if (1) { pthread_mutex_unlock (&p->io_lock); 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) { p->devices = (PANEL **)_panel_malloc (device_panel_count*sizeof(*p->devices)); if (p->devices == NULL) @@ -606,8 +629,7 @@ if (device_panel_count) { memset (p->devices, 0, device_panel_count*sizeof(*p->devices)); p->device_count = device_panel_count; } -msleep (1000); -/* Validate existence of requested register */ +/* Validate sim_frontpanel API version */ if (_panel_sendf (p, 1, &p->simulator_version, "SHOW VERSION\r")) { goto Error_Return; } @@ -634,7 +656,15 @@ if (fOut) { } if (buf) free (buf); -sim_panel_destroy (p); +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_set_error ("%s", errbuf); + free (errbuf); + } return NULL; } @@ -666,7 +696,7 @@ if (p->device_name == NULL) strcpy (p->device_name, device_name); p->parent = simulator_panel; 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); if (p->sock == INVALID_SOCKET) msleep (100); @@ -678,13 +708,17 @@ if (p->sock == INVALID_SOCKET) { goto Error_Return; } strcpy (p->hostport, simulator_panel->hostport); +pthread_mutex_init (&p->io_lock, NULL); +pthread_mutex_init (&p->io_send_lock, NULL); +pthread_cond_init (&p->io_done, 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_mutex_init (&p->io_lock, NULL); - pthread_mutex_init (&p->io_send_lock, NULL); - pthread_cond_init (&p->io_done, NULL); - pthread_cond_init (&p->startup_cond, NULL); pthread_attr_init(&attr); pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); pthread_mutex_lock (&p->io_lock); @@ -695,10 +729,6 @@ if (1) { pthread_mutex_unlock (&p->io_lock); 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; _panel_register_panel (p); return p; @@ -1069,6 +1099,28 @@ pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority); pthread_setschedparam (pthread_self(), sched_policy, &sched_priority); 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; pthread_cond_signal (&p->startup_cond); /* Signal we're ready to go */ while ((p->sock != INVALID_SOCKET) && diff --git a/sim_frontpanel.h b/sim_frontpanel.h index 5b80ead1..50fd08af 100644 --- a/sim_frontpanel.h +++ b/sim_frontpanel.h @@ -82,6 +82,12 @@ sim_panel_start_simulator (const char *sim_path, const char *sim_config, 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 @@ -265,4 +271,4 @@ sim_panel_flush_debug (PANEL *panel); } #endif -#endif /* SIM_FRONTPANEL_H_ */ \ No newline at end of file +#endif /* SIM_FRONTPANEL_H_ */ diff --git a/sim_tmxr.c b/sim_tmxr.c index a44d635c..4490a203 100644 --- a/sim_tmxr.c +++ b/sim_tmxr.c @@ -3906,7 +3906,7 @@ while (1) { /* format passed string, arg /* Output the formatted data expanding newlines where they exist */ 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')) if (lp->txbsz == tmxr_send_buffered_data (lp)) sim_os_ms_sleep (10);