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)