diff --git a/0readme_ethernet.txt b/0readme_ethernet.txt index 9a74e0f1..bfe3abe2 100644 --- a/0readme_ethernet.txt +++ b/0readme_ethernet.txt @@ -304,8 +304,15 @@ Building on Linux, {Free|Net|Open}BSD, OS/X, Solaris, other *nix: typing 'make USE_NETWORK=1'. You must build with gcc to do this. There is no observable benefit to statically linking against libpcap and as such support for this ia deprecated. + + 4. Some platforms (HP-UX in particular) may not have vendor supplied libpcap + components available and installed with the operating system. The packages + which are available for this platform install include and library files in + user specified locations. When building on these platforms the library + path must be specified on the make command line. This can be done with: + 'make LPATH=/usr/lib:/usr/local/lib' - 4. Build it! + 5. Build it! ------------------------------------------------------------------------------- diff --git a/PDP11/pdp11_cr.c b/PDP11/pdp11_cr.c index 467b03f7..28e6c1bf 100644 --- a/PDP11/pdp11_cr.c +++ b/PDP11/pdp11_cr.c @@ -1372,7 +1372,7 @@ t_stat cr_show_trans ( FILE *st, return (SCPE_OK); } -t_stat cr_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) +static t_stat cr_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) { #if defined(VM_PDP11) char *devtype = "CR11/CD11"; diff --git a/PDP11/pdp11_dz.c b/PDP11/pdp11_dz.c index efeb5998..e09aa377 100644 --- a/PDP11/pdp11_dz.c +++ b/PDP11/pdp11_dz.c @@ -242,6 +242,7 @@ TMXR dz_desc = { DZ_MUXES * DZ_LINES, 0, 0, NULL }; /* mux descriptor */ #define DBG_XMT TMXR_DBG_XMT /* display Transmitted Data */ #define DBG_RCV TMXR_DBG_RCV /* display Received Data */ #define DBG_MDM TMXR_DBG_MDM /* display Modem Signals */ +#define DBG_CON TMXR_DBG_CON /* display connection activities */ #define DBG_TRC TMXR_DBG_TRC /* display trace routine calls */ #define DBG_ASY TMXR_DBG_ASY /* display Asynchronous Activities */ @@ -251,6 +252,7 @@ DEBTAB dz_debug[] = { {"XMT", DBG_XMT}, {"RCV", DBG_RCV}, {"MDM", DBG_MDM}, + {"CON", DBG_CON}, {"TRC", DBG_TRC}, {"ASY", DBG_ASY}, {0} diff --git a/PDP11/pdp11_rc.c b/PDP11/pdp11_rc.c index dd77b426..c1103334 100644 --- a/PDP11/pdp11_rc.c +++ b/PDP11/pdp11_rc.c @@ -591,7 +591,7 @@ static t_stat rc_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) return (SCPE_OK); } -char *rc_description (DEVICE *dptr) +static char *rc_description (DEVICE *dptr) { return "RC11/RS64 fixed head disk controller"; } diff --git a/PDP11/pdp11_vh.c b/PDP11/pdp11_vh.c index 13e30131..5ddb9b5e 100644 --- a/PDP11/pdp11_vh.c +++ b/PDP11/pdp11_vh.c @@ -305,6 +305,8 @@ static TMLX vh_parm[VH_MUXES * VH_LINES_ALLOC] = { { 0 } }; #define DBG_TRC TMXR_DBG_TRC /* trace routine calls */ #define DBG_XMT TMXR_DBG_XMT /* display Transmitted Data */ #define DBG_RCV TMXR_DBG_RCV /* display Received Data */ +#define DBG_MDM TMXR_DBG_MDM /* display Modem Signals */ +#define DBG_CON TMXR_DBG_CON /* display connection activities */ #define DBG_TRC TMXR_DBG_TRC /* display trace routine calls */ #define DBG_ASY TMXR_DBG_ASY /* display Asynchronous Activities */ @@ -314,6 +316,8 @@ DEBTAB vh_debug[] = { {"TRC", DBG_TRC}, {"XMT", DBG_XMT}, {"RCV", DBG_RCV}, + {"MDM", DBG_MDM}, + {"CON", DBG_CON}, {"TRC", DBG_TRC}, {"ASY", DBG_ASY}, {0} @@ -1382,7 +1386,7 @@ static t_stat vh_detach ( UNIT *uptr ) return (tmxr_detach (&vh_desc, uptr)); } -t_stat vh_show_vec (FILE *st, UNIT *uptr, int32 arg, void *desc) +static t_stat vh_show_vec (FILE *st, UNIT *uptr, int32 arg, void *desc) { TMXR *mp = (TMXR *) desc; diff --git a/README.md b/README.md index 791dad6f..0964bbee 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,13 @@ #### Remote Console Facility A new capability has been added which allows a TELNET Connection to a user designated port so that some out of band commands can be entered to manipulate and/or adjust a running simulator. The commands which enable and control this capability are SET REMOTE TELNET=port, SET REMOTE CONNECTIONS=n, SET REMOTE TIMEOUT=seconds, and SHOW REMOTE. -A subset of normal simh commands are available for use in remote console sessions. These are: EXAMINE, IEXAMINE, DEPOSIT, EVALUATE, ATTACH, DETACH, ASSIGN, DEASSIGN, STEP, CONTINUE, PWD, SAVE, SET, SHOW, DIR, LS, ECHO, HELP +The remote console facility has two modes of operation: 1) single command mode. and 2) multiple command mode. +In single command mode you enter one command at a time and aren't concerned about what the simulated system is doing while you enter that command. The command is executed once you've hit return. +In multiple command mode you initiate your activities by entering the WRU character (usually ^E). This will suspend the current simulator execution. You then enter commands as needed and when you are done you enter a CONTINUE command. While entering Multiple Command commands, if you fail to enter a complete command before the timeout (specified by "SET REMOTE TIMEOUT=seconds"), a CONTINUE command is automatically processed and simulation proceeds. + +A subset of normal simh commands are available for use in remote console sessions. +The Single Command Mode commands are: ATTACH, DETACH, PWD, SHOW, DIR, LS, ECHO, HELP +The Multiple Command Mode commands are: EXAMINE, IEXAMINE, DEPOSIT, EVALUATE, ATTACH, DETACH, ASSIGN, DEASSIGN, STEP, CONTINUE, PWD, SAVE, SET, SHOW, DIR, LS, ECHO, HELP #### VAX/PDP11 Enhancements RQ has new disk types: RC25, RCF25, RA80 diff --git a/S3/s3_cpu.c b/S3/s3_cpu.c index 6906b7e2..b732cbe1 100644 --- a/S3/s3_cpu.c +++ b/S3/s3_cpu.c @@ -1315,7 +1315,7 @@ int32 PutMem(int32 addr, int32 data) /* Check the condition register against the qbyte and return 1 if true */ -int32 condition(int32 qbyte) +static int32 condition(int32 qbyte) { int32 r = 0, t, q; t = (qbyte & 0xf0) >> 4; @@ -1345,7 +1345,7 @@ return (r); condition register initial state in parameter 3 */ -int32 compare(int32 byte1, int32 byte2, int32 cond) +static int32 compare(int32 byte1, int32 byte2, int32 cond) { int32 r; diff --git a/VAX/vax_sysdev.c b/VAX/vax_sysdev.c index dda6a00b..98dbdbef 100644 --- a/VAX/vax_sysdev.c +++ b/VAX/vax_sysdev.c @@ -1580,8 +1580,10 @@ if ((tmr_inc[tmr] == TMR_INC) && (tmr_time > clk_time)) { tmr_inc[tmr] = (uint32) (((double) clk_time * TMR_INC) / tmr_poll); tmr_time = clk_time; + sim_clock_coschedule (&sysd_unit[tmr], tmr_time); } -sim_activate (&sysd_unit[tmr], tmr_time); +else + sim_activate (&sysd_unit[tmr], tmr_time); return; } diff --git a/Visual Studio Projects/ALTAIR.vcproj b/Visual Studio Projects/ALTAIR.vcproj index 28bda3c4..30204e21 100644 --- a/Visual Studio Projects/ALTAIR.vcproj +++ b/Visual Studio Projects/ALTAIR.vcproj @@ -27,7 +27,7 @@ NUL +if not exist ../../windows-build/winpcap/Wpdpack/Include/pcap.h goto _notice +if not exist ../../windows-build/pthreads/pthread.h goto _notice +goto _done_build +:_notice +echo **************************************************** +echo **************************************************** +echo ** The required build support is not available. ** +echo **************************************************** +echo **************************************************** +type 0ReadMe_Projects.txt +exit 1 +:_done_build + +if not exist ..\.git goto _done_hooks +if exist ..\.git\hooks\post-commit goto _done_hooks +echo ***************************************************** +echo ***************************************************** +echo ** Installing git hooks in newly cloned repository ** +echo ***************************************************** +echo ***************************************************** +copy git-hooks\post* ..\.git\hooks\ +:_done_hooks + +:_SetId +SET GIT_COMMIT_ID= +if not exist ..\.git-commit-id goto _NoId +for /F %%i in (..\.git-commit-id) do SET GIT_COMMIT_ID=%%i +:_NoId +SET OLD_GIT_COMMIT_ID= +if not exist .git-commit-id.h echo.>.git-commit-id.h +for /F "tokens=3" %%i in (.git-commit-id.h) do SET OLD_GIT_COMMIT_ID=%%i +if "%GIT_COMMIT_ID%" equ "%OLD_GIT_COMMIT_ID%" goto _IdGood +echo #define SIM_GIT_COMMIT_ID %GIT_COMMIT_ID% >.git-commit-id.h +:_IdGood +:_done_id \ No newline at end of file diff --git a/Visual Studio Projects/S3.vcproj b/Visual Studio Projects/S3.vcproj index c06bf470..74c4f754 100644 --- a/Visual Studio Projects/S3.vcproj +++ b/Visual Studio Projects/S3.vcproj @@ -27,7 +27,7 @@ &1 | grep 'Apple' | awk '{ print $$1 }')) @@ -167,15 +179,25 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) LIBEXT = a else ifeq (,$(findstring NetBSD,$(OSTYPE))) - LDSEARCH :=$(shell ldconfig -r | grep 'search directories' | awk '{print $$3}' | sed 's/:/ /g') + ifneq (no ldconfig,$(wordlist 1,2,$(shell which ldconfig))) + LDSEARCH :=$(shell ldconfig -r | grep 'search directories' | awk '{print $$3}' | sed 's/:/ /g') + endif ifneq (,$(LDSEARCH)) LIBPATH := $(LDSEARCH) else - $(info *** Warning ***) - $(info *** Warning *** The library search path on your $(OSTYPE) platform can't be) - $(info *** Warning *** determined. This should be resolved before you can expect) - $(info *** Warning *** to have fully working simulators.) - $(info *** Warning ***) + ifeq (,$(strip $(LPATH))) + $(info *** Warning ***) + $(info *** Warning *** The library search path on your $(OSTYPE) platform can't be) + $(info *** Warning *** determined. This should be resolved before you can expect) + $(info *** Warning *** to have fully working simulators.) + $(info *** Warning ***) + $(info *** Warning *** You can specify your library paths via the LPATH environment) + $(info *** Warning *** variable.) + $(info *** Warning ***) + else + LIBPATH = $(subst :, ,$(LPATH)) + OS_LDFLAGS += $(patsubst %,-L%,$(LIBPATH)) + endif endif endif ifeq (usrpkglib,$(shell if $(TEST) -d /usr/pkg/lib; then echo usrpkglib; fi)) @@ -192,6 +214,7 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) LIBEXT = sl endif OS_CCDEFS += -D_HPUX_SOURCE -D_LARGEFILE64_SOURCE + OS_LDFLAGS += -Wl,+b: NO_LTO = 1 else LIBEXT = a @@ -306,7 +329,7 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) NETWORK_LDFLAGS = -L$(dir $(call find_lib,$(PCAPLIB))) -Wl,-R,$(dir $(call find_lib,$(PCAPLIB))) -l$(PCAPLIB) NETWORK_FEATURES = - static networking support using libpcap components located in the cygwin directories else - NETWORK_CCDEFS := -DUSE_NETWORK -isystem $(dir $(call find_include,pcap)) $(call find_lib,$(PCAPLIB)) + NETWORK_CCDEFS := -DUSE_NETWORK -isystem -I$(dir $(call find_include,pcap)) $(call find_lib,$(PCAPLIB)) NETWORK_FEATURES = - networking support using libpcap components from www.tcpdump.org $(info *** Warning ***) $(info *** Warning *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) being built with networking support using) @@ -395,6 +418,9 @@ else else GCC_Path := $(dir $(shell where gcc.exe)) endif + ifeq (rename-build-support,$(shell if exist ..\windows-build-windows-build echo rename-build-support)) + FIXED_BUILD := $(shell move ..\windows-build-windows-build ..\windows-build >NUL) + endif GCC_VERSION = $(word 3,$(shell $(GCC) --version)) COMPILER_NAME = GCC Version: $(GCC_VERSION) LTO_EXCLUDE_VERSIONS = 4.5.2 diff --git a/scp.c b/scp.c index b7cac770..cde6982c 100644 --- a/scp.c +++ b/scp.c @@ -2923,20 +2923,22 @@ if (sim_wallclock_queue == QUEUE_LIST_END) else { fprintf (st, "%s wall clock event queue status, time = %.0f\n", sim_name, sim_time); - for (uptr = sim_wallclock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next) { + for (uptr = sim_wallclock_queue; uptr != QUEUE_LIST_END; uptr = uptr->a_next) { if ((dptr = find_dev_from_unit (uptr)) != NULL) { fprintf (st, " %s", sim_dname (dptr)); if (dptr->numunits > 1) fprintf (st, " unit %d", (int32) (uptr - dptr->units)); } else fprintf (st, " Unknown"); - fprintf (st, " after %d usec\n", uptr->a_usec_delay); + fprintf (st, " after "); + fprint_val (st, (t_value)uptr->a_usec_delay, 10, 0, PV_RCOMMA); + fprintf (st, " usec\n"); } } if (sim_clock_cosched_queue != QUEUE_LIST_END) { - fprintf (st, "%s clock co-schedule event queue status, time = %.0f\n", - sim_name, sim_time); - for (uptr = sim_clock_cosched_queue; uptr != QUEUE_LIST_END; uptr = uptr->next) { + fprintf (st, "%s clock (%s) co-schedule event queue status, time = %.0f\n", + sim_name, sim_uname(sim_clock_unit), sim_time); + for (uptr = sim_clock_cosched_queue; uptr != QUEUE_LIST_END; uptr = uptr->a_next) { if ((dptr = find_dev_from_unit (uptr)) != NULL) { fprintf (st, " %s", sim_dname (dptr)); if (dptr->numunits > 1) @@ -3146,6 +3148,8 @@ return SCPE_OK; t_stat set_default_cmd (int32 flg, char *cptr) { +if (sim_is_running) + return SCPE_INVREM; if ((!cptr) || (*cptr == 0)) return SCPE_2FARG; sim_trim_endspc(cptr); @@ -3932,6 +3936,8 @@ char *sim_uname (UNIT *uptr) DEVICE *d = find_dev_from_unit(uptr); static AIO_TLS char uname[CBUFSIZE]; +if (!d) + return ""; if (d->numunits == 1) return sim_dname (d); sprintf (uname, "%s%d", sim_dname (d), (int)(uptr-d->units)); @@ -6096,7 +6102,7 @@ switch (format) { ndigits = MAX_WIDTH - digit; commas = (ndigits - 1)/3; for (digit=0; digit 0) + d = MAX_WIDTH - width; break; case PV_RZRO: case PV_RSPC: @@ -6334,28 +6341,39 @@ AIO_CANCEL(uptr); AIO_UPDATE_QUEUE; if (sim_clock_queue == QUEUE_LIST_END) return SCPE_OK; +sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Event for %s\n", sim_uname(uptr)); UPDATE_SIM_TIME; /* update sim time */ if (!sim_is_active (uptr)) return SCPE_OK; nptr = QUEUE_LIST_END; -if (sim_clock_queue == uptr) +if (sim_clock_queue == uptr) { nptr = sim_clock_queue = uptr->next; + uptr->next = NULL; /* hygiene */ + } else { for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) { if (cptr->next == uptr) { nptr = cptr->next = uptr->next; + uptr->next = NULL; /* hygiene */ break; /* end queue scan */ } } } if (nptr != QUEUE_LIST_END) - nptr->time = nptr->time + uptr->time; -uptr->next = NULL; /* hygiene */ -uptr->time = 0; + nptr->time += (uptr->next) ? 0 : uptr->time; +if (!uptr->next) + uptr->time = 0; if (sim_clock_queue != QUEUE_LIST_END) sim_interval = sim_clock_queue->time; else sim_interval = noqueue_time = NOQUEUE_WAIT; +if (sim_is_active(uptr)) { + if (sim_deb) { + sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Cancel failed for %s\n", sim_uname(uptr)); + fclose(sim_deb); + } + abort (); + } return SCPE_OK; } @@ -6411,7 +6429,8 @@ return 0; double sim_gtime (void) { -UPDATE_SIM_TIME; +if (AIO_MAIN_THREAD) + UPDATE_SIM_TIME; return sim_time; } diff --git a/sim_console.c b/sim_console.c index aa359d59..6f072a3d 100644 --- a/sim_console.c +++ b/sim_console.c @@ -346,9 +346,12 @@ DEVICE sim_remote_console = { static int32 *sim_rem_buf_size = NULL; static int32 *sim_rem_buf_ptr = NULL; static char **sim_rem_buf = NULL; +static t_bool *sim_rem_single_mode = NULL; /* per line command mode (single command or must continue) */ static TMXR sim_rem_con_tmxr = { 0, 0, 0, NULL, NULL, &sim_remote_console };/* remote console line mux */ static uint32 sim_rem_read_timeout = 30; /* seconds before automatic continue */ static int32 sim_rem_step_line = -1; /* step in progress on line # */ +static t_bool sim_log_temp = FALSE; /* temporary log file active */ +static char sim_rem_con_temp_name[PATH_MAX+1]; /* SET REMOTE CONSOLE command */ @@ -413,11 +416,21 @@ int32 c; c = tmxr_poll_conn (&sim_rem_con_tmxr); if (c >= 0) { /* poll connect */ TMLN *lp = &sim_rem_con_tmxr.ldsc[c]; + char wru_name[8]; sim_activate_after(uptr+1, 1000000); /* start data poll after 100ms */ lp->rcve = 1; /* rcv enabled */ sim_rem_buf_ptr[c] = 0; /* start with empty command buffer */ - tmxr_linemsgf (lp, "%s Remote Console\r\nSimulator Running...", sim_name); + if (isprint(sim_int_char&0xFF)) + sprintf(wru_name, "'%c'", sim_int_char&0xFF); + else + if (sim_int_char <= 26) + sprintf(wru_name, "^%c", '@' + (sim_int_char&0xFF)); + else + sprintf(wru_name, "'\\%03o'", sim_int_char&0xFF); + tmxr_linemsgf (lp, "%s Remote Console\r\n" + "Enter single commands or to enter multiple command mode enter the %s character\r\n" + "Simulator Running...", sim_name, wru_name); tmxr_send_buffered_data (lp); /* flush buffered data */ } sim_activate_after(uptr, 1000000); /* check again in 1 second */ @@ -463,6 +476,18 @@ static CTAB allowed_remote_cmds[] = { { NULL, NULL } }; +static CTAB allowed_single_remote_cmds[] = { + { "ATTACH", &attach_cmd, 0 }, + { "DETACH", &detach_cmd, 0 }, + { "PWD", &pwd_cmd, 0 }, + { "DIR", &dir_cmd, 0 }, + { "LS", &dir_cmd, 0 }, + { "ECHO", &echo_cmd, 0 }, + { "SHOW", &show_cmd, 0 }, + { "HELP", &x_help_cmd, 0 }, + { NULL, NULL } + }; + static t_stat x_help_cmd (int32 flag, char *cptr) { CTAB *cmdp, *cmdph; @@ -537,50 +562,63 @@ for (i=(was_stepping ? sim_rem_step_line : 0); if (!(TMXR_VALID & c)) continue; c = c & ~TMXR_VALID; - if (c != sim_int_char) - continue; /* ^E (the interrupt character) must start console interaction */ - for (j=0; j < sim_rem_con_tmxr.lines; j++) { - lp = &sim_rem_con_tmxr.ldsc[j]; - if ((i == j) || (!lp->conn)) - continue; - tmxr_linemsgf (lp, "\nRemote Console(%s) Entering Commands\n", lp->ipad); + if (!sim_rem_single_mode[i]) { + if (c == sim_int_char) { /* ^E (the interrupt character) must start continue mode console interaction */ + sim_is_running = 0; + sim_stop_timer_services (); + for (j=0; j < sim_rem_con_tmxr.lines; j++) { + lp = &sim_rem_con_tmxr.ldsc[j]; + if ((i == j) || (!lp->conn)) + continue; + tmxr_linemsgf (lp, "\nRemote Console(%s) Entering Commands\n", lp->ipad); + tmxr_send_buffered_data (lp); /* flush any buffered data */ + } + lp = &sim_rem_con_tmxr.ldsc[i]; + tmxr_linemsg (lp, "\r\nSimulator paused.\r\n"); + if (sim_rem_read_timeout) + tmxr_linemsgf (lp, "Simulation will resume automatically if input is not received in %d seconds\n", sim_rem_read_timeout); + } + else { + sim_rem_single_mode[i] = TRUE; + tmxr_linemsgf (lp, "\r\n%s", sim_prompt); + tmxr_send_buffered_data (lp); /* flush any buffered data */ + } + } + } + got_command = FALSE; + while (1) { + if (!sim_rem_single_mode[i]) { + read_start_time = sim_os_msec(); + tmxr_linemsg (lp, sim_prompt); tmxr_send_buffered_data (lp); /* flush any buffered data */ } - lp = &sim_rem_con_tmxr.ldsc[i]; - tmxr_linemsg (lp, "\r\nSimulator paused.\r\n"); - if (sim_rem_read_timeout) - tmxr_linemsgf (lp, "Simulation will resume automatically if input is not received in %d seconds\n", sim_rem_read_timeout); - } - while (1) { - read_start_time = sim_os_msec(); - tmxr_linemsg (lp, "sim> "); - tmxr_send_buffered_data (lp); /* flush any buffered data */ - got_command = FALSE; - while (!got_command) { - c = tmxr_getc_ln (lp); - if (!(TMXR_VALID & c)) { - tmxr_send_buffered_data (lp); /* flush any buffered data */ - if (sim_rem_read_timeout && - ((sim_os_msec() - read_start_time)/1000 >= sim_rem_read_timeout)) { - while (sim_rem_buf_ptr[i] > 0) { /* Erase current input line */ - tmxr_linemsg (lp, "\b \b"); - --sim_rem_buf_ptr[i]; + do { + if (!sim_rem_single_mode[i]) { + c = tmxr_getc_ln (lp); + if (!(TMXR_VALID & c)) { + tmxr_send_buffered_data (lp); /* flush any buffered data */ + if (sim_rem_read_timeout && + ((sim_os_msec() - read_start_time)/1000 >= sim_rem_read_timeout)) { + while (sim_rem_buf_ptr[i] > 0) { /* Erase current input line */ + tmxr_linemsg (lp, "\b \b"); + --sim_rem_buf_ptr[i]; + } + if (sim_rem_buf_ptr[i]+80 >= sim_rem_buf_size[i]) { + sim_rem_buf_size[i] += 1024; + sim_rem_buf[i] = realloc (sim_rem_buf[i], sim_rem_buf_size[i]); + } + strcpy (sim_rem_buf[i], "CONTINUE ! Automatic continue due to timeout"); + tmxr_linemsgf (lp, "%s\n", sim_rem_buf[i]); + got_command = TRUE; + break; } - if (sim_rem_buf_ptr[i]+80 >= sim_rem_buf_size[i]) { - sim_rem_buf_size[i] += 1024; - sim_rem_buf[i] = realloc (sim_rem_buf[i], sim_rem_buf_size[i]); - } - strcpy (sim_rem_buf[i], "CONTINUE ! Automatic continue due to timeout"); - tmxr_linemsgf (lp, "%s\n", sim_rem_buf[i]); - got_command = TRUE; - break; + sim_os_ms_sleep (100); + tmxr_poll_rx (&sim_rem_con_tmxr);/* poll input */ + continue; } - sim_os_ms_sleep (100); - tmxr_poll_rx (&sim_rem_con_tmxr);/* poll input */ - continue; + read_start_time = sim_os_msec(); + c = c & ~TMXR_VALID; } - read_start_time = sim_os_msec(); - c = c & ~TMXR_VALID; switch (c) { case 0: /* no data */ break; @@ -598,6 +636,9 @@ for (i=(was_stepping ? sim_rem_step_line : 0); --sim_rem_buf_ptr[i]; } break; + case '\n': + if (sim_rem_buf_ptr[i] == 0) + break; case '\r': tmxr_linemsg (lp, "\r\n"); if (sim_rem_buf_ptr[i]+1 >= sim_rem_buf_size[i]) { @@ -619,13 +660,18 @@ for (i=(was_stepping ? sim_rem_step_line : 0); got_command = TRUE; /* command too long */ break; } - } + } while ((!got_command) && (!sim_rem_single_mode[i])); tmxr_send_buffered_data (lp); /* flush any buffered data */ + if ((sim_rem_single_mode[i]) && !got_command) + break; printf ("Remote Console Command from %s> %s\r\n", lp->ipad, sim_rem_buf[i]); if (sim_log) fprintf (sim_log, "Remote Console Command from %s> %s\n", lp->ipad, sim_rem_buf[i]); + got_command = FALSE; if (strlen(sim_rem_buf[i]) >= sizeof(cbuf)) { - printf ("\r\nLine too long. Ignored. Continuing Simulator execution\r\n"); + printf ("\nLine too long. Ignored. Continuing Simulator execution\n"); + if (sim_log) + fprintf (sim_log, "\r\nLine too long. Ignored. Continuing Simulator execution\r\n"); tmxr_linemsgf (lp, "\nLine too long. Ignored. Continuing Simulator execution\n"); tmxr_send_buffered_data (lp); /* try to flush any buffered data */ break; @@ -634,16 +680,30 @@ for (i=(was_stepping ? sim_rem_step_line : 0); sim_rem_buf_ptr[i] = 0; sim_rem_buf[i][sim_rem_buf_ptr[i]] = '\0'; if (cbuf[0] == '\0') - continue; + if (sim_rem_single_mode[i]) { + sim_rem_single_mode[i] = FALSE; + break; + } + else + continue; sim_sub_args (cbuf, sizeof(cbuf), argv); cptr = cbuf; cptr = get_glyph (cptr, gbuf, 0); /* get command glyph */ sim_switches = 0; /* init switches */ + if (!sim_log) { /* Not currently logging? */ + int32 save_quiet = sim_quiet; + + sim_quiet = 1; + sprintf (sim_rem_con_temp_name, "sim_remote_console_%d.temporary_log", (int)getpid()); + sim_set_logon (0, sim_rem_con_temp_name); + sim_quiet = save_quiet; + sim_log_temp = TRUE; + } cmd_log_start = sim_ftell (sim_log); if (!find_cmd (gbuf)) /* validate command */ stat = SCPE_UNK; else { - if ((cmdp = find_ctab (allowed_remote_cmds, gbuf))) {/* lookup command */ + if ((cmdp = find_ctab (sim_rem_single_mode[i] ? allowed_single_remote_cmds : allowed_remote_cmds, gbuf))) {/* lookup command */ if (cmdp->action == &x_continue_cmd) stat = SCPE_OK; else { @@ -688,20 +748,41 @@ for (i=(was_stepping ? sim_rem_step_line : 0); sim_fseeko (sim_log, cmd_log_start, SEEK_SET); cbuf[sizeof(cbuf)-1] = '\0'; while (fgets (cbuf, sizeof(cbuf)-1, sim_log)) { + int32 unwritten; + tmxr_linemsgf (lp, "%s", cbuf); - tmxr_send_buffered_data (lp); + do { + unwritten = tmxr_send_buffered_data (lp); + if (unwritten == lp->txbsz) + sim_os_ms_sleep (100); + } while (unwritten == lp->txbsz); } - if (cmdp && (cmdp->action == &x_continue_cmd)) { + if ((cmdp && (cmdp->action == &x_continue_cmd)) || + (sim_rem_single_mode[i])) { sim_rem_step_line = -1; /* Not stepping */ - tmxr_linemsg (lp, "Simulator Running..."); - tmxr_send_buffered_data (lp); - for (j=0; j < sim_rem_con_tmxr.lines; j++) { - lp = &sim_rem_con_tmxr.ldsc[j]; - if ((i == j) || (!lp->conn)) - continue; + if (sim_log_temp) { /* If we setup a temporary log, clean it now */ + int32 save_quiet = sim_quiet; + + sim_quiet = 1; + sim_set_logoff (0, NULL); + sim_quiet = save_quiet; + remove (sim_rem_con_temp_name); + sim_log_temp = FALSE; + } + if (!sim_rem_single_mode[i]) { tmxr_linemsg (lp, "Simulator Running..."); tmxr_send_buffered_data (lp); + for (j=0; j < sim_rem_con_tmxr.lines; j++) { + lp = &sim_rem_con_tmxr.ldsc[j]; + if ((i == j) || (!lp->conn)) + continue; + tmxr_linemsg (lp, "Simulator Running..."); + tmxr_send_buffered_data (lp); + } + sim_is_running = 1; + sim_start_timer_services (); } + sim_rem_single_mode[i] = FALSE; break; } if (cmdp && (cmdp->action == &x_step_cmd)) { @@ -731,10 +812,6 @@ t_stat r; if (flag) { r = sim_parse_addr (cptr, NULL, 0, NULL, NULL, 0, NULL, NULL); if (r == SCPE_OK) { - if (!sim_log) { - printf ("Logging must be enabled to activate Remote Console support\n"); - return SCPE_ARG; - } if (sim_rem_con_tmxr.master) /* already open? */ sim_set_rem_telnet (0, NULL); /* close first */ if (sim_rem_con_tmxr.lines == 0) /* Ir no connection limit set */ @@ -748,8 +825,18 @@ if (flag) { return SCPE_NOPARAM; } else { - if (sim_rem_con_tmxr.master) + if (sim_rem_con_tmxr.master) { + int32 i; + tmxr_detach (&sim_rem_con_tmxr, &sim_rem_con_unit[0]); + for (i=0; i #endif /* avoid macro names collisions */ @@ -748,7 +749,24 @@ extern int32 sim_asynch_inst_latency; /* It is primarily used only used in debugging messages */ #define AIO_TLS #endif - +#define AIO_QUEUE_CHECK(que, lock) \ + if (1) { \ + UNIT *_cptr; \ + if (lock) \ + pthread_mutex_lock (lock); \ + for (_cptr = que; \ + (_cptr != QUEUE_LIST_END); \ + _cptr = _cptr->next) \ + if (!_cptr->next) { \ + if (sim_deb) { \ + sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Queue Corruption detected\n");\ + fclose(sim_deb); \ + } \ + abort(); \ + } \ + if (lock) \ + pthread_mutex_unlock (lock); \ + } else (void)0 #define AIO_MAIN_THREAD (pthread_equal ( pthread_self(), sim_asynch_main_threadid )) #define AIO_LOCK \ pthread_mutex_lock(&sim_asynch_lock) @@ -762,6 +780,62 @@ extern int32 sim_asynch_inst_latency; else \ (void)0 #endif /* !defined(SIM_ASYNCH_MUX) && !defined(SIM_ASYNCH_CLOCKS) */ +#if !defined(SIM_ASYNCH_MUX) && defined(SIM_ASYNCH_CLOCKS) +#define AIO_CANCEL(uptr) \ + if ((uptr)->a_cancel) \ + (uptr)->a_cancel (uptr); \ + else { \ + AIO_UPDATE_QUEUE; \ + if ((uptr)->a_next) { \ + UNIT *cptr; \ + pthread_mutex_lock (&sim_timer_lock); \ + if ((uptr) == sim_wallclock_queue) { \ + sim_wallclock_queue = (uptr)->a_next; \ + (uptr)->a_next = NULL; \ + sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Timer Event for %s\n", sim_uname(uptr));\ + sim_timer_event_canceled = TRUE; \ + pthread_cond_signal (&sim_timer_wake); \ + } \ + else \ + for (cptr = sim_wallclock_queue; \ + (cptr != QUEUE_LIST_END); \ + cptr = cptr->a_next) \ + if (cptr->a_next == (uptr)) { \ + cptr->a_next = (uptr)->a_next; \ + (uptr)->a_next = NULL; \ + sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Timer Event for %s\n", sim_uname(uptr));\ + break; \ + } \ + if ((uptr)->a_next == NULL) \ + (uptr)->a_due_time = (uptr)->a_usec_delay = 0; \ + else { \ + if ((uptr) == sim_clock_cosched_queue) { \ + sim_clock_cosched_queue = (uptr)->a_next; \ + (uptr)->a_next = NULL; \ + } \ + else \ + for (cptr = sim_clock_cosched_queue; \ + (cptr != QUEUE_LIST_END); \ + cptr = cptr->a_next) \ + if (cptr->a_next == (uptr)) { \ + cptr->a_next = (uptr)->a_next; \ + (uptr)->a_next = NULL; \ + break; \ + } \ + if ((uptr)->a_next == NULL) { \ + sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Clock Coscheduling Event for %s\n", sim_uname(uptr));\ + } \ + } \ + while (sim_timer_event_canceled) { \ + pthread_mutex_unlock (&sim_timer_lock); \ + sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Waiting for Timer Event cancelation for %s\n", sim_uname(uptr));\ + sim_os_ms_sleep (0); \ + pthread_mutex_lock (&sim_timer_lock); \ + } \ + pthread_mutex_unlock (&sim_timer_lock); \ + } \ + } +#endif #if defined(SIM_ASYNCH_MUX) && !defined(SIM_ASYNCH_CLOCKS) #define AIO_CANCEL(uptr) \ if ((uptr)->a_cancel) \ @@ -780,63 +854,70 @@ extern int32 sim_asynch_inst_latency; if ((uptr)->a_cancel) \ (uptr)->a_cancel (uptr); \ else { \ + AIO_UPDATE_QUEUE; \ if (((uptr)->dynflags & UNIT_TM_POLL) && \ !((uptr)->next) && !((uptr)->a_next)) { \ (uptr)->a_polling_now = FALSE; \ sim_tmxr_poll_count -= (uptr)->a_poll_waiter_count; \ (uptr)->a_poll_waiter_count = 0; \ } \ - if (AIO_IS_ACTIVE (uptr)) { \ - UNIT *cptr, *nptr; \ - AIO_UPDATE_QUEUE; \ + if ((uptr)->a_next) { \ + UNIT *cptr; \ pthread_mutex_lock (&sim_timer_lock); \ - nptr = QUEUE_LIST_END; \ if ((uptr) == sim_wallclock_queue) { \ - sim_wallclock_queue = (uptr)->next; \ - (uptr)->next = NULL; \ + sim_wallclock_queue = (uptr)->a_next; \ + (uptr)->a_next = NULL; \ + sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Timer Event for %s\n", sim_uname(uptr));\ + sim_timer_event_canceled = TRUE; \ + pthread_cond_signal (&sim_timer_wake); \ } \ else \ for (cptr = sim_wallclock_queue; \ (cptr != QUEUE_LIST_END); \ - cptr = cptr->next) \ - if (cptr->next == (uptr)) { \ - cptr->next = (uptr)->next; \ - nptr = cptr; \ - (uptr)->next = NULL; \ + cptr = cptr->a_next) \ + if (cptr->a_next == (uptr)) { \ + cptr->a_next = (uptr)->a_next; \ + (uptr)->a_next = NULL; \ + sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Timer Event for %s\n", sim_uname(uptr));\ break; \ } \ - if (nptr == QUEUE_LIST_END) { \ - sim_timer_event_canceled = TRUE; \ - pthread_cond_signal (&sim_timer_wake); \ - } \ - if ((uptr)->next == NULL) \ + if ((uptr)->a_next == NULL) \ (uptr)->a_due_time = (uptr)->a_usec_delay = 0; \ else { \ - nptr = QUEUE_LIST_END; \ if ((uptr) == sim_clock_cosched_queue) { \ - sim_clock_cosched_queue = (uptr)->next; \ - (uptr)->next = NULL; \ + sim_clock_cosched_queue = (uptr)->a_next; \ + (uptr)->a_next = NULL; \ } \ else \ for (cptr = sim_clock_cosched_queue; \ (cptr != QUEUE_LIST_END); \ - cptr = cptr->next) \ - if (cptr->next == (uptr)) { \ - cptr->next = (uptr)->next; \ - nptr = cptr; \ - (uptr)->next = NULL; \ + cptr = cptr->a_next) \ + if (cptr->a_next == (uptr)) { \ + cptr->a_next = (uptr)->a_next; \ + (uptr)->a_next = NULL; \ break; \ } \ + if ((uptr)->a_next == NULL) { \ + sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Clock Coscheduling Event for %s\n", sim_uname(uptr));\ + } \ + } \ + while (sim_timer_event_canceled) { \ + pthread_mutex_unlock (&sim_timer_lock); \ + sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Waiting for Timer Event cancelation for %s\n", sim_uname(uptr));\ + sim_os_ms_sleep (0); \ + pthread_mutex_lock (&sim_timer_lock); \ } \ pthread_mutex_unlock (&sim_timer_lock); \ } \ } +#endif +#if defined(SIM_ASYNCH_CLOCKS) #define AIO_RETURN_TIME(uptr) \ if (1) { \ pthread_mutex_lock (&sim_timer_lock); \ for (cptr = sim_wallclock_queue; \ cptr != QUEUE_LIST_END; \ - cptr = cptr->next) \ + cptr = cptr->a_next) \ if ((uptr) == cptr) { \ double inst_per_sec = sim_timer_inst_per_sec (); \ int32 result; \ @@ -934,8 +1015,8 @@ extern int32 sim_asynch_inst_latency; do \ q = AIO_QUEUE_VAL; \ while (q != AIO_QUEUE_SET(QUEUE_LIST_END, q)); \ - sim_debug (SIM_DBG_AIO_QUEUE, sim_dflt_dev, "Found Asynch event for %s after %d instructions\n", sim_uname(q), q->a_event_time);\ while (q != QUEUE_LIST_END) { /* List !Empty */ \ + sim_debug (SIM_DBG_AIO_QUEUE, sim_dflt_dev, "Migrating Asynch event for %s after %d instructions\n", sim_uname(q), q->a_event_time);\ uptr = q; \ q = q->a_next; \ uptr->a_next = NULL; /* hygiene */ \ @@ -947,8 +1028,10 @@ extern int32 sim_asynch_inst_latency; else \ a_event_time = uptr->a_event_time; \ uptr->a_activate_call (uptr, a_event_time); \ - if (uptr->a_check_completion) \ + if (uptr->a_check_completion) { \ + sim_debug (SIM_DBG_AIO_QUEUE, sim_dflt_dev, "Calling Completion Check for asynch event on %s\n", sim_uname(uptr));\ uptr->a_check_completion (uptr); \ + } \ } \ } else (void)0 #define AIO_ACTIVATE(caller, uptr, event_time) \ @@ -960,8 +1043,8 @@ extern int32 sim_asynch_inst_latency; } else { \ UNIT *q, *qe; \ ouptr->a_event_time = event_time; \ - uptr->a_activate_call = caller; \ - uptr->a_next = QUEUE_LIST_END; /* Mark as on list */ \ + ouptr->a_activate_call = caller; \ + ouptr->a_next = QUEUE_LIST_END; /* Mark as on list */ \ do { \ do \ q = AIO_QUEUE_VAL; \ @@ -981,6 +1064,35 @@ extern int32 sim_asynch_inst_latency; } \ return SCPE_OK; \ } else (void)0 +#define AIO_ACTIVATE_LIST(caller, list, event_time) \ + if (list) { \ + UNIT *ouptr, *q, *qe; \ + sim_debug (SIM_DBG_AIO_QUEUE, sim_dflt_dev, "Queueing Asynch events for %s after %d instructions\n", sim_uname(list), event_time);\ + for (qe=(list); qe->a_next != QUEUE_LIST_END;) { \ + qe->a_event_time = event_time; \ + qe->a_activate_call = caller; \ + qe = qe->a_next; \ + } \ + qe->a_event_time = event_time; \ + qe->a_activate_call = caller; \ + ouptr = (list); \ + do { \ + do \ + q = AIO_QUEUE_VAL; \ + while (q != AIO_QUEUE_SET(QUEUE_LIST_END, q));/* Grab current list */ \ + for (qe = ouptr; qe->a_next != QUEUE_LIST_END; qe = qe->a_next); \ + qe->a_next = q; /* append current list */ \ + do \ + q = AIO_QUEUE_VAL; \ + while (q != AIO_QUEUE_SET(ouptr, q)); \ + ouptr = q; \ + } while (ouptr != QUEUE_LIST_END); \ + sim_asynch_check = 0; /* try to force check */ \ + if (sim_idle_wait) { \ + sim_debug (TIMER_DBG_IDLE, &sim_timer_dev, "waking due to event on %s after %d instructions\n", sim_uname(ouptr), event_time);\ + pthread_cond_signal (&sim_asynch_wake); \ + } \ + } else (void)0 #else /* !USE_AIO_INTRINSICS */ /* This approach uses a pthread mutex to manage access to the link list */ /* head sim_asynch_queue. It will always work, but may be slower than the */ @@ -1023,7 +1135,7 @@ extern int32 sim_asynch_inst_latency; while (sim_asynch_queue != QUEUE_LIST_END) { /* List !Empty */ \ int32 a_event_time; \ uptr = sim_asynch_queue; \ - sim_debug (SIM_DBG_AIO_QUEUE, sim_dflt_dev, "found asynch event for %s after %d instructions\n", sim_uname(uptr), uptr->a_event_time);\ + sim_debug (SIM_DBG_AIO_QUEUE, sim_dflt_dev, "Migrating Asynch event for %s after %d instructions\n", sim_uname(uptr), uptr->a_event_time);\ sim_asynch_queue = uptr->a_next; \ uptr->a_next = NULL; /* hygiene */ \ if (uptr->a_activate_call != &sim_activate_notbefore) { \ @@ -1034,18 +1146,19 @@ extern int32 sim_asynch_inst_latency; else \ a_event_time = uptr->a_event_time; \ AIO_UNLOCK; \ - sim_debug (SIM_DBG_AIO_QUEUE, sim_dflt_dev, "calling completion check for asynch event on %s\n", sim_uname(uptr));\ uptr->a_activate_call (uptr, a_event_time); \ - if (uptr->a_check_completion) \ + if (uptr->a_check_completion) { \ + sim_debug (SIM_DBG_AIO_QUEUE, sim_dflt_dev, "Calling Completion Check for asynch event on %s\n", sim_uname(uptr));\ uptr->a_check_completion (uptr); \ + } \ AIO_LOCK; \ } \ AIO_UNLOCK; \ } else (void)0 #define AIO_ACTIVATE(caller, uptr, event_time) \ if (!pthread_equal ( pthread_self(), sim_asynch_main_threadid )) { \ - sim_debug (SIM_DBG_AIO_QUEUE, sim_dflt_dev, "queueing asynch event for %s after %d instructions\n", sim_uname(uptr), event_time);\ - AIO_UNLOCK; \ + sim_debug (SIM_DBG_AIO_QUEUE, sim_dflt_dev, "Queueing Asynch event for %s after %d instructions\n", sim_uname(uptr), event_time);\ + AIO_LOCK; \ if (uptr->a_next) { /* already queued? */ \ uptr->a_activate_call = sim_activate_abs; \ } else { \ @@ -1054,12 +1167,35 @@ extern int32 sim_asynch_inst_latency; uptr->a_activate_call = caller; \ sim_asynch_queue = uptr; \ } \ - if (sim_idle_wait) \ + if (sim_idle_wait) { \ + sim_debug (TIMER_DBG_IDLE, &sim_timer_dev, "waking due to event on %s after %d instructions\n", sim_uname(uptr), event_time);\ pthread_cond_signal (&sim_asynch_wake); \ + } \ AIO_UNLOCK; \ sim_asynch_check = 0; \ return SCPE_OK; \ } else (void)0 +#define AIO_ACTIVATE_LIST(caller, list, event_time) \ + if (list) { \ + UNIT *qe; \ + sim_debug (SIM_DBG_AIO_QUEUE, sim_dflt_dev, "Queueing Asynch events for %s after %d instructions\n", sim_uname(list), event_time);\ + for (qe=list; qe->a_next != QUEUE_LIST_END;) { \ + qe->a_event_time = event_time; \ + qe->a_activate_call = caller; \ + qe = qe->a_next; \ + } \ + qe->a_event_time = event_time; \ + qe->a_activate_call = caller; \ + AIO_LOCK; \ + qe->a_next = sim_asynch_queue; \ + sim_asynch_queue = list; \ + sim_asynch_check = 0; /* try to force check */ \ + if (sim_idle_wait) { \ + sim_debug (TIMER_DBG_IDLE, &sim_timer_dev, "waking due to event on %s after %d instructions\n", sim_uname(list), event_time);\ + pthread_cond_signal (&sim_asynch_wake); \ + } \ + AIO_UNLOCK; \ + } else (void)0 #endif /* USE_AIO_INTRINSICS */ #define AIO_VALIDATE if (!pthread_equal ( pthread_self(), sim_asynch_main_threadid )) abort() #define AIO_CHECK_EVENT \ diff --git a/sim_serial.c b/sim_serial.c index 14678e95..15dee496 100644 --- a/sim_serial.c +++ b/sim_serial.c @@ -583,7 +583,7 @@ return ports; interest to a DCB retrieved from a call to "GetCommState". */ -SERHANDLE sim_open_os_serial (char *name) +static SERHANDLE sim_open_os_serial (char *name) { SERHANDLE port; DCB dcb; @@ -675,7 +675,7 @@ return port; /* return port handle on 1.5 stop bits. */ -t_stat sim_config_os_serial (SERHANDLE port, SERCONFIG config) +static t_stat sim_config_os_serial (SERHANDLE port, SERCONFIG config) { static const struct { char parity; @@ -868,7 +868,7 @@ else The serial port is closed. Errors are ignored. */ -void sim_close_os_serial (SERHANDLE port) +static void sim_close_os_serial (SERHANDLE port) { CloseHandle (port); /* close the port */ return; @@ -1000,7 +1000,7 @@ return ports; reading. */ -SERHANDLE sim_open_os_serial (char *name) +static SERHANDLE sim_open_os_serial (char *name) { static const tcflag_t i_clear = IGNBRK | /* ignore BREAK */ BRKINT | /* signal on BREAK */ @@ -1118,7 +1118,7 @@ return port; /* return port fd for su */ -t_stat sim_config_os_serial (SERHANDLE port, SERCONFIG config) +static t_stat sim_config_os_serial (SERHANDLE port, SERCONFIG config) { struct termios tio; int32 i; @@ -1339,7 +1339,7 @@ return (int32) written; /* return number of The serial port is closed. Errors are ignored. */ -void sim_close_os_serial (SERHANDLE port) +static void sim_close_os_serial (SERHANDLE port) { close (port); /* close the port */ return; @@ -1484,7 +1484,7 @@ return ports; */ -SERHANDLE sim_open_os_serial (char *name) +static SERHANDLE sim_open_os_serial (char *name) { uint32 status; uint32 chan = 0; @@ -1541,7 +1541,7 @@ return chan; /* return channel for su */ -t_stat sim_config_os_serial (SERHANDLE port, SERCONFIG config) +static t_stat sim_config_os_serial (SERHANDLE port, SERCONFIG config) { int32 i; SENSE_BUF sense; @@ -1780,7 +1780,7 @@ return (int32)iosb.count; /* return number of char The serial port is closed. Errors are ignored. */ -void sim_close_os_serial (SERHANDLE port) +static void sim_close_os_serial (SERHANDLE port) { sys$dassgn (port); /* close the port */ return; @@ -1800,7 +1800,7 @@ return 0; /* Open a serial port */ -SERHANDLE sim_open_os_serial (char *name) +static SERHANDLE sim_open_os_serial (char *name) { return INVALID_HANDLE; } @@ -1808,7 +1808,7 @@ return INVALID_HANDLE; /* Configure a serial port */ -t_stat sim_config_os_serial (SERHANDLE port, SERCONFIG config) +static t_stat sim_config_os_serial (SERHANDLE port, SERCONFIG config) { return SCPE_IERR; } @@ -1840,7 +1840,7 @@ return -1; /* Close a serial port */ -void sim_close_os_serial (SERHANDLE port) +static void sim_close_os_serial (SERHANDLE port) { return; } diff --git a/sim_sock.c b/sim_sock.c index 111e29c3..5f3b78ce 100644 --- a/sim_sock.c +++ b/sim_sock.c @@ -939,6 +939,10 @@ if (rbytes == SOCKET_ERROR) { err = WSAGetLastError (); if (err == WSAEWOULDBLOCK) /* no data */ return 0; +#if defined(EAGAIN) + if (err == EAGAIN) /* no data */ + return 0; +#endif if ((err != WSAETIMEDOUT) && /* expected errors after a connect failure */ (err != WSAEHOSTUNREACH) && (err != WSAECONNREFUSED)) diff --git a/sim_timer.c b/sim_timer.c index eca1b741..87d9799d 100644 --- a/sim_timer.c +++ b/sim_timer.c @@ -101,7 +101,7 @@ static uint32 sim_throt_val = 0; static uint32 sim_throt_state = 0; static uint32 sim_throt_sleep_time = 0; static int32 sim_throt_wait = 0; -static UNIT *sim_clock_unit = NULL; +UNIT *sim_clock_unit = NULL; t_bool sim_asynch_timer = #if defined (SIM_ASYNCH_CLOCKS) TRUE; @@ -1185,18 +1185,18 @@ while (sim_asynch_enabled && sim_asynch_timer && sim_is_running) { sim_wallclock_entry = NULL; prvptr = NULL; - for (cptr = sim_wallclock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) { + for (cptr = sim_wallclock_queue; cptr != QUEUE_LIST_END; cptr = cptr->a_next) { if (uptr->a_due_time < cptr->a_due_time) break; prvptr = cptr; } if (prvptr == NULL) { /* insert at head */ - cptr = uptr->next = sim_wallclock_queue; + cptr = uptr->a_next = sim_wallclock_queue; sim_wallclock_queue = uptr; } else { - cptr = uptr->next = prvptr->next; /* insert at prvptr */ - prvptr->next = uptr; + cptr = uptr->a_next = prvptr->a_next; /* insert at prvptr */ + prvptr->a_next = uptr; } } @@ -1216,7 +1216,7 @@ while (sim_asynch_enabled && sim_asynch_timer && sim_is_running) { if (sim_wallclock_queue == QUEUE_LIST_END) sim_debug (DBG_TIM, &sim_timer_dev, "_timer_thread() - waiting forever\n"); else - sim_debug (DBG_TIM, &sim_timer_dev, "_timer_thread() - waiting for %.0f usecs until %.6f\n", wait_usec, sim_wallclock_queue->a_due_time); + sim_debug (DBG_TIM, &sim_timer_dev, "_timer_thread() - waiting for %.0f usecs until %.6f for %s\n", wait_usec, sim_wallclock_queue->a_due_time, sim_uname(sim_wallclock_queue)); if ((wait_usec <= 0.0) || (0 != pthread_cond_timedwait (&sim_timer_wake, &sim_timer_lock, &due_time))) { if (sim_wallclock_queue == QUEUE_LIST_END) /* queue empty? */ @@ -1224,8 +1224,8 @@ while (sim_asynch_enabled && sim_asynch_timer && sim_is_running) { inst_per_sec = sim_timer_inst_per_sec (); uptr = sim_wallclock_queue; - sim_wallclock_queue = uptr->next; - uptr->next = NULL; /* hygiene */ + sim_wallclock_queue = uptr->a_next; + uptr->a_next = NULL; /* hygiene */ clock_gettime(CLOCK_REALTIME, &stop_time); if (1 != sim_timespec_compare (&due_time, &stop_time)) { @@ -1238,21 +1238,24 @@ while (sim_asynch_enabled && sim_asynch_timer && sim_is_running) { } sim_debug (DBG_TIM, &sim_timer_dev, "_timer_thread() - slept %.0fms - activating(%s,%d)\n", 1000.0*(_timespec_to_double (&stop_time)-_timespec_to_double (&start_time)), sim_uname(uptr), inst_delay); - sim_activate (uptr, inst_delay); - if (sim_clock_unit == uptr) - while (sim_clock_cosched_queue != QUEUE_LIST_END) { - uptr = sim_clock_cosched_queue; - sim_clock_cosched_queue = uptr->next; - uptr->next = NULL; - sim_activate (uptr, inst_delay); - } + if (sim_clock_unit == uptr) { + /* + * Some devices may depend on executing during the same instruction or immediately + * after the clock tick event. To satisfy this, we link the clock unit to the head + * of the clock coschedule queue and then insert that list in the asynch event + * queue in a single operation + */ + uptr->a_next = sim_clock_cosched_queue; + sim_clock_cosched_queue = QUEUE_LIST_END; + AIO_ACTIVATE_LIST(sim_activate, uptr, inst_delay); + } + else + sim_activate (uptr, inst_delay); } - else /* Something wants to adjust the queue */ + else {/* Something wants to adjust the queue since the wait condition was signaled */ if (sim_timer_event_canceled) sim_timer_event_canceled = FALSE; /* reset flag and continue */ - else - if (sim_wallclock_entry == NULL) /* nothing to insert? */ - break; /* stop processing entries */ + } } pthread_mutex_unlock (&sim_timer_lock); @@ -1275,7 +1278,7 @@ if (sim_asynch_enabled && sim_asynch_timer) { /* when restarting after being manually stopped the due times for all */ /* timer events needs to slide so they fire in the future. (clock ticks */ /* don't accumulate when the simulator is stopped) */ - for (cptr = sim_wallclock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) { + for (cptr = sim_wallclock_queue; cptr != QUEUE_LIST_END; cptr = cptr->a_next) { if (cptr == sim_wallclock_queue) { /* Handle first entry */ struct timespec now; double due_time; @@ -1330,9 +1333,9 @@ else { uptr = sim_wallclock_queue; if (uptr == QUEUE_LIST_END) break; - sim_wallclock_queue = uptr->next; + sim_wallclock_queue = uptr->a_next; accum += uptr->time; - uptr->next = NULL; + uptr->a_next = NULL; uptr->a_due_time = 0; uptr->a_usec_delay = 0; sim_activate_after (uptr, accum); @@ -1426,6 +1429,13 @@ if (1) { sim_uname(uptr), uptr->a_due_time); } pthread_mutex_lock (&sim_timer_lock); +while (sim_wallclock_entry) { + sim_debug (DBG_TIM, &sim_timer_dev, "sim_timer_activate_after() - queue insert entry %s busy waiting for 1ms\n", + sim_uname(sim_wallclock_entry)); + pthread_mutex_unlock (&sim_timer_lock); + sim_os_ms_sleep (1); + pthread_mutex_lock (&sim_timer_lock); + } sim_wallclock_entry = uptr; pthread_mutex_unlock (&sim_timer_lock); pthread_cond_signal (&sim_timer_wake); /* wake the timer thread to deal with it */ @@ -1451,18 +1461,26 @@ else if (sim_asynch_enabled && sim_asynch_timer) { if (!sim_is_active (uptr)) { /* already active? */ #if defined(SIM_ASYNCH_IO) && defined(SIM_ASYNCH_CLOCKS) - sim_debug (DBG_TIM, &sim_timer_dev, "sim_clock_coschedule() - queueing %s for clock co-schedule\n", sim_uname (uptr)); - pthread_mutex_lock (&sim_timer_lock); - uptr->next = sim_clock_cosched_queue; - sim_clock_cosched_queue = uptr; - pthread_mutex_unlock (&sim_timer_lock); + if ((sim_calb_tmr != -1) && + (rtc_elapsed[sim_calb_tmr ] >= sim_idle_stable)) { + sim_debug (DBG_TIM, &sim_timer_dev, "sim_clock_coschedule() - queueing %s for clock co-schedule\n", sim_uname (uptr)); + pthread_mutex_lock (&sim_timer_lock); + uptr->a_next = sim_clock_cosched_queue; + sim_clock_cosched_queue = uptr; + pthread_mutex_unlock (&sim_timer_lock); + return SCPE_OK; + } + else { #else - int32 t; - - t = sim_activate_time (sim_clock_unit); - return sim_activate (uptr, t? t - 1: interval); + if (1) { #endif + int32 t; + + t = sim_activate_time (sim_clock_unit); + return sim_activate (uptr, t? t - 1: interval); + } } + sim_debug (DBG_TIM, &sim_timer_dev, "sim_clock_coschedule() - %s is already active\n", sim_uname (uptr)); return SCPE_OK; } else { diff --git a/sim_timer.h b/sim_timer.h index d5f7981c..4448567f 100644 --- a/sim_timer.h +++ b/sim_timer.h @@ -119,6 +119,7 @@ uint32 sim_timer_idle_capable (uint32 *hoat_tick_ms); extern t_bool sim_idle_enab; /* idle enabled flag */ extern volatile t_bool sim_idle_wait; /* idle waiting flag */ +extern UNIT *sim_clock_unit; extern t_bool sim_asynch_timer; extern DEVICE sim_timer_dev; diff --git a/sim_tmxr.c b/sim_tmxr.c index 4d34b9b2..a368d87b 100644 --- a/sim_tmxr.c +++ b/sim_tmxr.c @@ -353,10 +353,44 @@ /* Options */ -#define TN_BIN 0 /* bin */ -#define TN_ECHO 1 /* echo */ -#define TN_SGA 3 /* sga */ -#define TN_LINE 34 /* line mode */ +#define TN_BIN 0 /* bin */ +#define TN_ECHO 1 /* echo */ +#define TN_SGA 3 /* sga */ +#define TN_STATUS 5 /* option status query */ +#define TN_TIMING 6 /* Timing Mark */ +#define TN_NAOCRD 10 /* Output Carriage-Return Disposition */ +#define TN_NAOHTS 11 /* Output Horizontal Tab Stops */ +#define TN_NAOHTD 12 /* Output Horizontal Tab Stop Disposition */ +#define TN_NAOFFD 13 /* Output Forfeed Disposition */ +#define TN_NAOVTS 14 /* Output Vertical Tab Stop */ +#define TN_NAOVTD 15 /* Output Vertical Tab Stop Disposition */ +#define TN_NAOLFD 16 /* Output Linefeed Disposition */ +#define TN_EXTEND 17 /* Extended Ascii */ +#define TN_LOGOUT 18 /* Logout */ +#define TN_BM 19 /* Byte Macro */ +#define TN_DET 20 /* Data Entry Terminal */ +#define TN_SENDLO 23 /* Send Location */ +#define TN_TERMTY 24 /* Terminal Type */ +#define TN_ENDREC 25 /* Terminal Type */ +#define TN_TUID 26 /* TACACS User Identification */ +#define TN_OUTMRK 27 /* Output Marking */ +#define TN_TTYLOC 28 /* Terminal Location Number */ +#define TN_3270 29 /* 3270 Regime */ +#define TN_X3PAD 30 /* X.3 PAD */ +#define TN_NAWS 31 /* Negotiate About Window Size */ +#define TN_TERMSP 32 /* Terminal Speed */ +#define TN_TOGFLO 33 /* Remote Flow Control */ +#define TN_LINE 34 /* line mode */ +#define TN_XDISPL 35 /* X Display Location */ +#define TN_ENVIRO 36 /* Environment */ +#define TN_AUTH 37 /* Authentication */ +#define TN_ENCRYP 38 /* Data Encryption */ +#define TN_NEWENV 39 /* New Environment */ +#define TN_TN3270 40 /* TN3270 Enhancements */ +#define TN_CHARST 42 /* CHARSET */ +#define TN_COMPRT 44 /* Com Port Control */ +#define TN_KERMIT 47 /* KERMIT */ + #define TN_CR 015 /* carriage return */ #define TN_LF 012 /* line feed */ #define TN_NUL 000 /* null */ @@ -782,7 +816,7 @@ if (mp->master) { if (newsock != INVALID_SOCKET) { /* got a live one? */ sprintf (msg, "tmxr_poll_conn() - Connection from %s", address); - tmxr_debug_trace (mp, msg); + tmxr_debug_connect (mp, msg); op = mp->lnorder; /* get line connection order list pointer */ i = mp->lines; /* play it safe in case lines == 0 */ ++mp->sessions; /* count the new session */ @@ -802,7 +836,7 @@ if (mp->master) { if (i >= mp->lines) { /* all busy? */ tmxr_msg (newsock, "All connections busy\r\n"); - tmxr_debug_trace (mp, "tmxr_poll_conn() - All connections busy"); + tmxr_debug_connect (mp, "tmxr_poll_conn() - All connections busy"); sim_close_sock (newsock, 0); free (address); } @@ -838,8 +872,12 @@ for (i = 0; i < mp->lines; i++) { /* check each line in se lp->ipad = realloc (lp->ipad, 1+strlen (lp->destination)); strcpy (lp->ipad, lp->destination); lp->cnms = sim_os_msec (); + sprintf (msg, "tmxr_poll_conn() - Line Connection to %s established", lp->destination); + tmxr_debug_connect_line (lp, msg); break; case -1: /* failed connection */ + sprintf (msg, "tmxr_poll_conn() - Line Connection to %s failed", lp->destination); + tmxr_debug_connect_line (lp, msg); tmxr_reset_ln (lp); /* retry */ break; } @@ -853,7 +891,7 @@ for (i = 0; i < mp->lines; i++) { /* check each line in se if (newsock != INVALID_SOCKET) { /* got a live one? */ sprintf (msg, "tmxr_poll_conn() - Line Connection from %s", address); - tmxr_debug_trace_line (lp, msg); + tmxr_debug_connect_line (lp, msg); ++mp->sessions; /* count the new session */ if (lp->destination) { /* Virtual Null Modem Cable? */ @@ -862,12 +900,14 @@ for (i = 0; i < mp->lines; i++) { /* check each line in se if (sim_parse_addr (lp->destination, host, sizeof(host), NULL, NULL, 0, NULL, address)) { tmxr_msg (newsock, "Rejecting connection from unexpected source\r\n"); sprintf (msg, "tmxr_poll_conn() - Rejecting line connection from: %s, Expected: %s", address, host); - tmxr_debug_trace_line (lp, msg); + tmxr_debug_connect_line (lp, msg); sim_close_sock (newsock, 0); free (address); continue; /* Move on to next line */ } if (lp->connecting) { + sprintf (msg, "tmxr_poll_conn() - aborting outgoing line connection attempt to: %s", lp->destination); + tmxr_debug_connect_line (lp, msg); sim_close_sock (lp->connecting, 0); /* abort our as yet unconnnected socket */ lp->connecting = 0; } @@ -887,7 +927,7 @@ for (i = 0; i < mp->lines; i++) { /* check each line in se } else { tmxr_msg (newsock, "Line connection busy\r\n"); - tmxr_debug_trace_line (lp, "tmxr_poll_conn() - Line connection busy"); + tmxr_debug_connect_line (lp, "tmxr_poll_conn() - Line connection busy"); sim_close_sock (newsock, 0); free (address); } @@ -905,8 +945,11 @@ for (i = 0; i < mp->lines; i++) { /* check each line in se /* Check for needed outgoing connection initiation */ if (lp->destination && (!lp->sock) && (!lp->connecting) && (!lp->serport) && - (!mp->modem_control || (lp->modembits & TMXR_MDM_DTR))) + (!mp->modem_control || (lp->modembits & TMXR_MDM_DTR))) { + sprintf (msg, "tmxr_poll_conn() - establishing outgoing connection to: %s", lp->destination); + tmxr_debug_connect_line (lp, msg); lp->connecting = sim_connect_sock (lp->destination, "localhost", NULL); + } } @@ -924,6 +967,8 @@ return -1; /* no new connections ma static t_stat tmxr_reset_ln_ex (TMLN *lp, t_bool closeserial) { +char msg[512]; + tmxr_debug_trace_line (lp, "tmxr_reset_ln_ex)"); if (lp->txlog) @@ -931,6 +976,9 @@ if (lp->txlog) tmxr_send_buffered_data (lp); /* send any buffered data */ +sprintf (msg, "tmxr_reset_ln_ex(%s)", closeserial ? "TRUE" : "FALSE"); +tmxr_debug_connect_line (lp, msg); + if (lp->serport) { if (closeserial) { sim_close_serial (lp->serport); @@ -961,10 +1009,15 @@ else /* Telnet connection */ free(lp->ipad); lp->ipad = NULL; if ((lp->destination) && (!lp->serport)) { - if (lp->connecting) + if (lp->connecting) { sim_close_sock (lp->connecting, 0); - if ((!lp->mp->modem_control) || (lp->modembits & TMXR_MDM_DTR)) + lp->connecting = 0; + } + if ((!lp->mp->modem_control) || (lp->modembits & TMXR_MDM_DTR)) { + sprintf (msg, "tmxr_reset_ln_ex() - connecting to %s", lp->destination); + tmxr_debug_connect_line (lp, msg); lp->connecting = sim_connect_sock (lp->destination, "localhost", NULL); + } } tmxr_init_line (lp); /* initialize line state */ /* Revise the unit's connect string to reflect the current attachments */ @@ -978,6 +1031,7 @@ return SCPE_OK; t_stat tmxr_close_ln (TMLN *lp) { tmxr_debug_trace_line (lp, "tmxr_close_ln()"); +tmxr_debug_connect_line (lp, "tmxr_close_ln()"); return tmxr_reset_ln_ex (lp, TRUE); } @@ -1110,8 +1164,13 @@ if (lp->mp && lp->mp->modem_control) { /* This API ONLY works on mo else { if ((lp->destination) && /* Virtual Null Modem Cable */ ((bits_to_set ^ before_modem_bits) & /* and DTR being Raised */ - TMXR_MDM_DTR)) + TMXR_MDM_DTR)) { + char msg[512]; + + sprintf (msg, "tmxr_set_get_modem_bits() - establishing outgoing connection to: %s", lp->destination); + tmxr_debug_connect_line (lp, msg); lp->connecting = sim_connect_sock (lp->destination, "localhost", NULL); + } } } return SCPE_OK; @@ -1280,9 +1339,12 @@ for (i = 0; i < mp->lines; i++) { /* loop thru lines */ case TNS_WILL: case TNS_WONT: /* IAC+WILL/WONT prev */ if (tmp == TN_BIN) { /* BIN? */ - if (lp->tsta == TNS_WILL) + if (lp->tsta == TNS_WILL) { lp->dstb = 0; - else lp->dstb = 1; + } + else { + lp->dstb = 1; + } } tmxr_rmvrc (lp, j); /* remove it */ lp->tsta = TNS_NORM; /* next normal */ @@ -3042,11 +3104,13 @@ while (1) { /* format passed string, arg for (i = 0; i < len; ++i) { if ('\n' == buf[i]) { - tmxr_putc_ln (lp, '\r'); - tmxr_putc_ln (lp, buf[i]); + while (SCPE_STALL == tmxr_putc_ln (lp, '\r')) + if (lp->txbsz == tmxr_send_buffered_data (lp)) + sim_os_ms_sleep (10); } - else - tmxr_putc_ln (lp, buf[i]); + while (SCPE_STALL == tmxr_putc_ln (lp, buf[i])) + if (lp->txbsz == tmxr_send_buffered_data (lp)) + sim_os_ms_sleep (10); } if (buf != stackbuf) free (buf); @@ -3514,9 +3578,40 @@ static struct { {TN_BIN, "TN_BIN"}, /* bin */ {TN_ECHO, "TN_ECHO"}, /* echo */ {TN_SGA, "TN_SGA"}, /* sga */ + {TN_STATUS, "TN_STATUS"}, /* option status query */ + {TN_TIMING, "TN_TIMING"}, /* Timing Mark */ + {TN_NAOCRD, "TN_NAOCRD"}, /* Output Carriage-Return Disposition */ + {TN_NAOHTS, "TN_NAOHTS"}, /* Output Horizontal Tab Stops */ + {TN_NAOHTD, "TN_NAOHTD"}, /* Output Horizontal Tab Stop Disposition */ + {TN_NAOFFD, "TN_NAOFFD"}, /* Output Forfeed Disposition */ + {TN_NAOVTS, "TN_NAOVTS"}, /* Output Vertical Tab Stop */ + {TN_NAOVTD, "TN_NAOVTD"}, /* Output Vertical Tab Stop Disposition */ + {TN_NAOLFD, "TN_NAOLFD"}, /* Output Linefeed Disposition */ + {TN_EXTEND, "TN_EXTEND"}, /* Extended Ascii */ + {TN_LOGOUT, "TN_LOGOUT"}, /* Logout */ + {TN_BM, "TN_BM"}, /* Byte Macro */ + {TN_DET, "TN_DET"}, /* Data Entry Terminal */ + {TN_SENDLO, "TN_SENDLO"}, /* Send Location */ + {TN_TERMTY, "TN_TERMTY"}, /* Terminal Type */ + {TN_ENDREC, "TN_ENDREC"}, /* Terminal Type */ + {TN_TUID, "TN_TUID"}, /* TACACS User Identification */ + {TN_OUTMRK, "TN_OUTMRK"}, /* Output Marking */ + {TN_TTYLOC, "TN_TTYLOC"}, /* Terminal Location Number */ + {TN_3270, "TN_3270"}, /* 3270 Regime */ + {TN_X3PAD, "TN_X3PAD"}, /* X.3 PAD */ + {TN_NAWS, "TN_NAWS"}, /* Negotiate About Window Size */ + {TN_TERMSP, "TN_TERMSP"}, /* Terminal Speed */ + {TN_TOGFLO, "TN_TOGFLO"}, /* Remote Flow Control */ {TN_LINE, "TN_LINE"}, /* line mode */ - {TN_CR, "TN_CR"}, /* carriage return */ - {TN_LF, "TN_LF"}, /* line feed */ + {TN_XDISPL, "TN_XDISPL"}, /* X Display Location */ + {TN_ENVIRO, "TN_ENVIRO"}, /* Environment */ + {TN_AUTH, "TN_AUTH"}, /* Authentication */ + {TN_ENCRYP, "TN_ENCRYP"}, /* Data Encryption */ + {TN_NEWENV, "TN_NEWENV"}, /* New Environment */ + {TN_TN3270, "TN_TN3270"}, /* TN3270 Enhancements */ + {TN_CHARST, "TN_CHARST"}, /* CHARSET */ + {TN_COMPRT, "TN_COMPRT"}, /* Com Port Control */ + {TN_KERMIT, "TN_KERMIT"}, /* KERMIT */ {0, NULL}}; static char *tmxr_debug_buf = NULL; @@ -3539,26 +3634,98 @@ while (*string) tmxr_buf_debug_char (*string++); } +static void tmxr_buf_debug_telnet_option (u_char chr) +{ +int j; + +for (j=0; 1; ++j) { + if (NULL == tn_chars[j].name) { + if (isprint(chr)) + tmxr_buf_debug_char (chr); + else { + tmxr_buf_debug_char ('_'); + if ((chr >= 1) && (chr <= 26)) { + tmxr_buf_debug_char ('^'); + tmxr_buf_debug_char ('A' + chr - 1); + } + else { + char octal[8]; + + sprintf(octal, "\\%03o", (u_char)chr); + tmxr_buf_debug_string (octal); + } + tmxr_buf_debug_char ('_'); + } + break; + } + if ((u_char)chr == tn_chars[j].value) { + tmxr_buf_debug_char ('_'); + tmxr_buf_debug_string (tn_chars[j].name); + tmxr_buf_debug_char ('_'); + break; + } + } +} + +static int tmxr_buf_debug_telnet_options (u_char *buf, int bufsize) +{ +int optsize = 2; + +tmxr_buf_debug_telnet_option ((u_char)buf[0]); +tmxr_buf_debug_telnet_option ((u_char)buf[1]); +switch ((u_char)buf[1]) { + case TN_IAC: + default: + return optsize; + break; + case TN_WILL: + case TN_WONT: + case TN_DO: + case TN_DONT: + ++optsize; + tmxr_buf_debug_telnet_option ((u_char)buf[2]); + break; + } +return optsize; +} + void _tmxr_debug (uint32 dbits, TMLN *lp, const char *msg, char *buf, int bufsize) { if ((lp->mp->dptr) && (dbits & lp->mp->dptr->dctrl)) { - int i, j; + int i; tmxr_debug_buf_used = 0; if (tmxr_debug_buf) tmxr_debug_buf[tmxr_debug_buf_used] = '\0'; for (i=0; i= 1) && (buf[i] <= 26)) { + tmxr_buf_debug_char ('^'); + tmxr_buf_debug_char ('A' + buf[i] - 1); + } + else { + char octal[8]; + + sprintf(octal, "\\%03o", (u_char)buf[i]); + tmxr_buf_debug_string (octal); + } + tmxr_buf_debug_char ('_'); + } break; - } } } sim_debug (dbits, lp->mp->dptr, "%s %d bytes '%s'\n", msg, bufsize, tmxr_debug_buf); diff --git a/sim_tmxr.h b/sim_tmxr.h index 147234fc..d1c26a08 100644 --- a/sim_tmxr.h +++ b/sim_tmxr.h @@ -69,8 +69,9 @@ typedef int SERHANDLE; #define TMXR_DBG_XMT 0x010000 /* Debug Transmit Data */ #define TMXR_DBG_RCV 0x020000 /* Debug Received Data */ #define TMXR_DBG_MDM 0x040000 /* Debug Modem Signals */ -#define TMXR_DBG_ASY 0x080000 /* Debug Asynchronous Activities */ -#define TMXR_DBG_TRC 0x100000 /* Debug trace routine calls */ +#define TMXR_DBG_CON 0x080000 /* Debug Connection Activities */ +#define TMXR_DBG_ASY 0x100000 /* Debug Asynchronous Activities */ +#define TMXR_DBG_TRC 0x200000 /* Debug trace routine calls */ /* Modem Control Bits */ @@ -202,6 +203,8 @@ extern FILE *sim_deb; /* debug file */ #define tmxr_debug(dbits, lp, msg, buf, bufsize) if (sim_deb && (lp)->mp->dptr && ((dbits) & (lp)->mp->dptr->dctrl)) _tmxr_debug (dbits, lp, msg, buf, bufsize); else (void)0 #define tmxr_debug_trace(mp, msg) if (sim_deb && (mp)->dptr && (TMXR_DBG_TRC & (mp)->dptr->dctrl)) sim_debug (TMXR_DBG_TRC, mp->dptr, "%s\n", (msg)); else (void)0 #define tmxr_debug_trace_line(lp, msg) if (sim_deb && (lp)->mp && (lp)->mp->dptr && (TMXR_DBG_TRC & (lp)->mp->dptr->dctrl)) sim_debug (TMXR_DBG_TRC, (lp)->mp->dptr, "%s\n", (msg)); else (void)0 +#define tmxr_debug_connect(mp, msg) if (sim_deb && (mp)->dptr && (TMXR_DBG_CON & (mp)->dptr->dctrl)) sim_debug (TMXR_DBG_CON, mp->dptr, "%s\n", (msg)); else (void)0 +#define tmxr_debug_connect_line(lp, msg) if (sim_deb && (lp)->mp && (lp)->mp->dptr && (TMXR_DBG_CON & (lp)->mp->dptr->dctrl)) sim_debug (TMXR_DBG_CON, (lp)->mp->dptr, "%s\n", (msg)); else (void)0 #if defined(SIM_ASYNCH_IO) && defined(SIM_ASYNCH_MUX) #define tmxr_attach(mp, uptr, cptr) tmxr_attach_ex(mp, uptr, cptr, TRUE)