Untangle circular include references between tmxr serial and sock include files.
This commit is contained in:
parent
4a5b7a78c5
commit
d46ebc7d49
9 changed files with 190 additions and 52 deletions
|
@ -170,3 +170,149 @@ device layer (in sim_tape.c) which combined these multiple operations.
|
|||
This approach will dovetail well with a potential future addition of
|
||||
operations on physical tapes as yet another supported tape format.
|
||||
|
||||
Programming Console and Multiplexer devices to leverage Asynch I/O to
|
||||
minimize 'unproductive' polling.
|
||||
|
||||
There are two goals for asynchronous Multiplexer I/O: 1) Minimize polling
|
||||
to only happen when data is available, not arbitrarily on every clock tick,
|
||||
and 2) to have polling actually happen as soon as data may be available.
|
||||
In most cases no effort is required to add Asynch I/O support to a
|
||||
multiplexer device emulation. If a device emulation takes the normal
|
||||
model of polling for arriving data on every simulated clock tick, then if
|
||||
Asynch I/O is enabled, the device will operate asynchronously and behave
|
||||
well. There is one restriction in this model. Specifically, the device
|
||||
emulation logic can't expect that there will be a particular number (clock
|
||||
tick rate maybe) of invocations of a unit service routine to perform polls
|
||||
in any interval of time (this is what we're trying to change, right?).
|
||||
Therefore presumptions about measuring time by counting polls is not
|
||||
valid. If a device needs to manage time related activities, then the
|
||||
device should create a separate unit which is dedicated to the timing
|
||||
activities and which explicitly schedules a different unit service routine
|
||||
for those activities as needed. Such scheduled polling should only be
|
||||
enabled when actual timing is required.
|
||||
|
||||
A device which is unprepared to operate asynchronously can specifically
|
||||
disable multiplexer Asynch I/O for that device by explicitly defining
|
||||
NO_ASYNCH_MUX at compile time. This can be defined at the top of a
|
||||
particular device emulation which isn't capable of asynch operation, or
|
||||
it can be defined globally on the compile command line for the simulator.
|
||||
Alternatively, if a specific Multiplexer device doesn't function correctly
|
||||
under the multiplexer asynchronous environment and it will never be
|
||||
revised to operate correctly, it may statically set the TMUF_NOASYNCH bit
|
||||
in its unit flags field.
|
||||
|
||||
Some devices will need a small amount of extra coding to leverage the
|
||||
Multiplexer Asynch I/O capabilties. Devices which require extra coding
|
||||
have one or more of the following characteristics:
|
||||
- they poll for input data on a different unit (or units) than the unit
|
||||
which was provided when tmxr_attach was called.
|
||||
- they poll for connections on a different unit than the unit which was
|
||||
provided when tmxr_attach was called.
|
||||
|
||||
The extra coding required for proper operation is to call
|
||||
tmxr_set_line_unit() to associate the appropriate input polling unit to
|
||||
the respective multiplexer line (ONLY if input polling is done by a unit
|
||||
different than the unit specified when the MUX was attached). If output
|
||||
polling is done on a different unit, then tmxr_set_line_output_unit()
|
||||
should be called to describe that fact.
|
||||
|
||||
Console I/O can operate asynchronously if the simulator notifies the
|
||||
tmxr/console subsystem which device unit is used by the simulator to poll
|
||||
for console input and output units. This is done by including sim_tmxr.h
|
||||
in the source module which contains the console input device definition
|
||||
and calling tmxr_set_console_units(). tmxr_set_console_units would usually
|
||||
be called in a device reset routine.
|
||||
|
||||
sim_tmxr consumers:
|
||||
- Altair Z80 SIO devices = 1, units = 1, lines = 4, flagbits = 8, Untested Asynch
|
||||
- HP2100 BACI devices = 1, units = 1, lines = 1, flagbits = 3, Untested Asynch
|
||||
- HP2100 MPX devices = 1, units = 10, lines = 8, flagbits = 2, Untested Asynch
|
||||
- HP2100 MUX devices = 3, units = 1/16/1, lines = 16, flagbits = 4, Untested Asynch
|
||||
- I7094 COM devices = 2, units = 4/33, lines = 33, flagbits = 4, Untested Asynch
|
||||
- Interdata PAS devices = 2, units = 1/32, lines = 32, flagbits = 3, Untested Asynch
|
||||
- Nova QTY devices = 1, units = 1, lines = 64, flagbits = 1, Untested Asynch
|
||||
- Nova TT1 devices = 2, units = 1/1, lines = 1, flagbits = 1, Untested Asynch
|
||||
- PDP-1 DCS devices = 2, units = 1/32, lines = 32, flagbits = 0, Untested Asynch
|
||||
- PDP-8 TTX devices = 2, units = 1/4, lines = 4, flagbits = 0, Untested Asynch
|
||||
- PDP-11 DC devices = 2, units = 1/16, lines = 16, flagbits = 5, Untested Asynch
|
||||
- PDP-11 DL devices = 2, units = 1/16, lines = 16, flagbits = 3, Untested Asynch
|
||||
- PDP-11 DZ devices = 1, units = 1/1, lines = 32, flagbits = 0, Good Asynch
|
||||
- PDP-11 VH devices = 1, units = 4, lines = 32, flagbits = 4, Good Asynch
|
||||
- PDP-18b TT1 devices = 2, units = 1/16, lines = 16, flagbits = 0, Untested Asynch
|
||||
- SDS MUX devices = 2, units = 1/32, lines = 32, flagbits = 0, Untested Asynch
|
||||
- sim_console Good Asynch
|
||||
|
||||
Program Clock Devices to leverage Asynsh I/O
|
||||
|
||||
simh's concept of time is calibrated by counting the number of
|
||||
instructions which the simulator can execute in a given amount of wall
|
||||
clock time. Once this is determined, the appropriate value is continually
|
||||
recalibrated and used throughout a simulator to schedule device time
|
||||
related delays as needed. Historically, this was fine until modern
|
||||
processors started having dynamically variable processor clock rates.
|
||||
On such host systems, the simulator's concept of time passing can vary
|
||||
drastically. This dynamic adjustment of the host system's execution rate
|
||||
may cause dramatic drifting of the simulated operating system's concept
|
||||
of time. Once all devices are disconnected from the calibrated clock's
|
||||
instruction count, the only concern for time in the simulated system is
|
||||
that it's clock tick be as accurate as possible. This has worked well
|
||||
in the past, however each simulator was burdened with providing code
|
||||
which facilitated managing the concept of the relationship between the
|
||||
number of instructions executed and the passage of wall clock time.
|
||||
To accomodate the needs of activities or events which should be measured
|
||||
against wall clock time (vs specific number of instructions executed),
|
||||
the simulator framework has been extended to specifically provide event
|
||||
scheduling based on elapsed wall time. A new API can be used by devices
|
||||
to schedule unit event delivery after the passage of a specific amount
|
||||
of wall clock time. The api sim_activate_after() provides this
|
||||
capability. This capability is not limited to being available ONLY when
|
||||
compiling with SIM_SYNCH_IO defined. When SIM_ASYNCH_IO is defined, this
|
||||
facility is implemented by a thread which drives the delivery of these
|
||||
events from the host system's clock ticks (interpolated as needed to
|
||||
accomodate hosts with relatively large clock ticks). When SIM_ASYNCH_IO
|
||||
is not defined, this facility is implemented using the traditional simh
|
||||
calibrated clock approach. This new approach has been measured to provide
|
||||
clocks which drift far less than the drift realized in prior simh versions.
|
||||
Using the released simh v3.9-0 vax simulator with idling enabled, the clock
|
||||
drifted some 4 minutes in 35 minutes time (approximately 10%). The same OS
|
||||
disk also running with idling enabled booted for 4 hours had less that 5
|
||||
seconds of clock drift (approximately 0.03%).
|
||||
|
||||
Co-Scheduling Clock and Multiplexer (or other devices)
|
||||
|
||||
Many simulator devices have needs to periodically executed with timing on the
|
||||
order of the simulated system's clock ticks. There are numerous reasons for
|
||||
this type of execution. Meanwhile, many of these events aren't particular
|
||||
about exactly when they execute as long as they execute frequently enough.
|
||||
Frequently executing events has the potential to interfere with a simulator's
|
||||
attempts to idle when the simulated system isn't actually doing useful work.
|
||||
|
||||
Interactions with attempts to 'co-schedule' multiplexer polling with clock
|
||||
ticks can cause strange simulator behaviors. These strange behaviors only
|
||||
happen under a combination of conditions:
|
||||
1) a multiplexer device is defined in the simulator configuration,
|
||||
2) the multiplexor device is NOT attached, and thus is not being managed by
|
||||
the asynchronous multiplexer support
|
||||
3) the multiplexer device schedules polling (co-scheduled) when not
|
||||
attached (such polling will never produce any input, so this is probably
|
||||
a bug).
|
||||
In prior simh versions support for clock co-scheduling was implmented
|
||||
separately by each simulator, and usually was expressed by code of the form:
|
||||
sim_activate (uptr, clk_cosched (tmxr_poll));
|
||||
As a part of asynchronous timer support, the simulator framework has been
|
||||
extended to generically provide clock co-scheduling support. The use of this
|
||||
new capability requires an initial call (usually in the clock device reset
|
||||
routing) of the form:
|
||||
sim_register_clock_unit (&clk_unit);
|
||||
Once the clock unit has been registered, co-scheduling is achieved by replacing
|
||||
the earlier sim_activate with the following:
|
||||
sim_clock_coschedule (&dz_unit, tmxr_poll);
|
||||
|
||||
Run time requirements to use SIM_ASYNCH_IO.
|
||||
The Posix threads API (pthreads) is required for asynchronous execution.
|
||||
Most *nix platforms have these APIs available and on these platforms
|
||||
simh is typically built with these available since on these platforms,
|
||||
pthreads is required for simh networking support. Windows can also
|
||||
utilize the pthreads APIs if the compile and run time support for the
|
||||
win32Pthreads package has been installed on the build system.
|
||||
|
||||
|
|
2
scp.c
2
scp.c
|
@ -328,6 +328,8 @@ t_bool sim_asynch_enabled = TRUE;
|
|||
int32 sim_asynch_check;
|
||||
int32 sim_asynch_latency = 4000; /* 4 usec interrupt latency */
|
||||
int32 sim_asynch_inst_latency = 20; /* assume 5 mip simulator */
|
||||
#else
|
||||
t_bool sim_asynch_enabled = FALSE;
|
||||
#endif
|
||||
|
||||
/* The per-simulator init routine is a weak global that defaults to NULL
|
||||
|
|
1
scp.h
1
scp.h
|
@ -162,6 +162,7 @@ extern volatile int32 stop_cpu;
|
|||
extern uint32 sim_brk_types; /* breakpoint info */
|
||||
extern uint32 sim_brk_dflt;
|
||||
extern uint32 sim_brk_summ;
|
||||
extern t_bool sim_asynch_enabled;
|
||||
|
||||
/* VM interface */
|
||||
|
||||
|
|
|
@ -119,6 +119,7 @@
|
|||
|
||||
#include "sim_defs.h"
|
||||
#include "sim_tmxr.h"
|
||||
#include "sim_serial.h"
|
||||
#include "sim_timer.h"
|
||||
#include <ctype.h>
|
||||
|
||||
|
|
14
sim_defs.h
14
sim_defs.h
|
@ -113,6 +113,12 @@
|
|||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#undef PACKED /* avoid macro name collision */
|
||||
#undef ERROR /* avoid macro name collision */
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
@ -662,7 +668,6 @@ extern UNIT * volatile sim_wallclock_queue;
|
|||
extern UNIT * volatile sim_wallclock_entry;
|
||||
extern UNIT * volatile sim_clock_cosched_queue;
|
||||
extern volatile t_bool sim_idle_wait;
|
||||
extern t_bool sim_asynch_enabled;
|
||||
extern int32 sim_asynch_check;
|
||||
extern int32 sim_asynch_latency;
|
||||
extern int32 sim_asynch_inst_latency;
|
||||
|
@ -846,13 +851,6 @@ extern int32 sim_asynch_inst_latency;
|
|||
else \
|
||||
(void)0
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#ifdef PACKED
|
||||
#undef PACKED
|
||||
#endif /* PACKED */
|
||||
#ifdef ERROR
|
||||
#undef ERROR
|
||||
#endif /* ERROR */
|
||||
#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)
|
||||
#define InterlockedCompareExchangePointer(Destination, Exchange, Comparand) __sync_val_compare_and_swap(Destination, Comparand, Exchange)
|
||||
#elif defined(__DECC_VER)
|
||||
|
|
49
sim_serial.h
49
sim_serial.h
|
@ -30,9 +30,7 @@
|
|||
#ifndef _SIM_SERIAL_H_
|
||||
#define _SIM_SERIAL_H_ 0
|
||||
|
||||
#if defined (_WIN32)
|
||||
|
||||
/* Windows definitions */
|
||||
#if defined (_WIN32) /* Windows definitions */
|
||||
|
||||
/* We need the basic Win32 definitions, but including "windows.h" also includes
|
||||
"winsock.h" as well. However, "sim_sock.h" explicitly includes "winsock2.h,"
|
||||
|
@ -43,50 +41,49 @@
|
|||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
typedef HANDLE SERHANDLE;
|
||||
|
||||
#if !defined(INVALID_HANDLE)
|
||||
#define INVALID_HANDLE INVALID_HANDLE_VALUE
|
||||
#endif /* !defined(INVALID_HANDLE) */
|
||||
|
||||
|
||||
#elif defined (__unix__) || defined(__APPLE__)
|
||||
|
||||
/* UNIX definitions */
|
||||
#elif defined (__unix__) || defined(__APPLE__) /* UNIX definitions */
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
typedef int SERHANDLE;
|
||||
|
||||
#if !defined(INVALID_HANDLE)
|
||||
#define INVALID_HANDLE -1
|
||||
#endif /* !defined(INVALID_HANDLE) */
|
||||
|
||||
|
||||
#elif defined (VMS)
|
||||
|
||||
/* VMS definitions */
|
||||
|
||||
typedef int SERHANDLE;
|
||||
|
||||
#elif defined (VMS) /* VMS definitions */
|
||||
#if !defined(INVALID_HANDLE)
|
||||
#define INVALID_HANDLE (uint32)(-1)
|
||||
#endif /* !defined(INVALID_HANDLE) */
|
||||
|
||||
#else
|
||||
|
||||
/* Non-implemented definitions */
|
||||
|
||||
typedef int SERHANDLE;
|
||||
#else /* Non-implemented definitions */
|
||||
|
||||
#if !defined(INVALID_HANDLE)
|
||||
#define INVALID_HANDLE -1
|
||||
#endif /* !defined(INVALID_HANDLE) */
|
||||
|
||||
#endif /* OS variants */
|
||||
|
||||
#ifndef _SERHANDLE_DEFINED
|
||||
#define _SERHANDLE_DEFINED 0
|
||||
#if defined (_WIN32) /* Windows definitions */
|
||||
typedef void *SERHANDLE;
|
||||
#else /* all other platforms */
|
||||
typedef int SERHANDLE;
|
||||
#endif
|
||||
#endif /* _SERHANDLE_DEFINED */
|
||||
|
||||
|
||||
/* Common definitions */
|
||||
|
||||
/* Global routines */
|
||||
#include "sim_tmxr.h" /* need TMLN definition and modem definitions */
|
||||
#include "sim_tmxr.h" /* need TMLN definition and modem definitions */
|
||||
|
||||
extern SERHANDLE sim_open_serial (char *name, TMLN *lp, t_stat *status);
|
||||
extern t_stat sim_config_serial (SERHANDLE port, const char *config);
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
#define _SIM_SOCK_H_ 0
|
||||
|
||||
#if defined (_WIN32) /* Windows */
|
||||
#undef INT_PTR /* hack, hack */
|
||||
#include <winsock2.h>
|
||||
|
||||
#elif !defined (__OS2__) || defined (__EMX__) /* VMS, Mac, Unix, OS/2 EMX */
|
||||
|
|
13
sim_tmxr.c
13
sim_tmxr.c
|
@ -1853,19 +1853,6 @@ mp->ldsc[line].uptr = uptr_poll;
|
|||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat tmxr_set_console_input_unit (UNIT *uptr)
|
||||
{
|
||||
extern TMLN sim_con_ldsc;
|
||||
|
||||
sim_con_ldsc.uptr = uptr;
|
||||
if (!(uptr->dynflags & UNIT_TM_POLL)) {
|
||||
uptr->dynflags |= UNIT_TM_POLL; /* tag as polling unit */
|
||||
}
|
||||
else
|
||||
sim_cancel (uptr);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Declare which unit polls for output
|
||||
|
||||
Inputs:
|
||||
|
|
15
sim_tmxr.h
15
sim_tmxr.h
|
@ -44,12 +44,19 @@
|
|||
added tmxr_rqln, tmxr_tqln
|
||||
*/
|
||||
|
||||
#include "sim_serial.h" /* We need serial I/O (SERHANDLE) */
|
||||
|
||||
#ifndef _SIM_TMXR_H_
|
||||
#define _SIM_TMXR_H_ 0
|
||||
|
||||
#include "sim_sock.h" /* We need sockets */
|
||||
#ifndef _SERHANDLE_DEFINED
|
||||
#define _SERHANDLE_DEFINED 0
|
||||
#if defined (_WIN32) /* Windows definitions */
|
||||
typedef void *SERHANDLE;
|
||||
#else /* all other platforms */
|
||||
typedef int SERHANDLE;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "sim_sock.h"
|
||||
|
||||
#define TMXR_V_VALID 15
|
||||
#define TMXR_VALID (1 << TMXR_V_VALID)
|
||||
|
@ -159,7 +166,7 @@ t_stat tmxr_set_get_modem_bits (TMLN *lp, int32 bits_to_set, int32 bits_to_clear
|
|||
t_stat tmxr_set_config_line (TMLN *lp, char *config);
|
||||
t_stat tmxr_set_line_unit (TMXR *mp, int line, UNIT *uptr_poll);
|
||||
t_stat tmxr_set_line_output_unit (TMXR *mp, int line, UNIT *uptr_poll);
|
||||
t_stat tmxr_set_console_input_unit (UNIT *uptr);
|
||||
t_stat tmxr_set_console_units (UNIT *rxuptr, UNIT *txuptr);
|
||||
t_stat tmxr_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
|
||||
t_stat tmxr_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
|
||||
void tmxr_msg (SOCKET sock, char *msg);
|
||||
|
|
Loading…
Add table
Reference in a new issue