Change to support serial ports on multiplexer devices without any changes to existing multiplexer device emulation code.
Added support for per line tcp listen ports. Added support for per line outgoing tcp/telnet connections. Removed DEV_NET from pdp11_dz and pdp11_vh emulators to allow proper restore of
This commit is contained in:
parent
24696892fd
commit
02cb620c9b
21 changed files with 2360 additions and 1405 deletions
|
@ -29,8 +29,6 @@
|
||||||
28-Mar-11 JDB Tidied up signal handling
|
28-Mar-11 JDB Tidied up signal handling
|
||||||
26-Oct-10 JDB Changed I/O signal handler for revised signal model
|
26-Oct-10 JDB Changed I/O signal handler for revised signal model
|
||||||
25-Nov-08 JDB Revised for new multiplexer library SHOW routines
|
25-Nov-08 JDB Revised for new multiplexer library SHOW routines
|
||||||
19-Nov-08 JDB [serial] Removed DEV_NET to allow restoration of listening port
|
|
||||||
17-Oct-08 JDB [serial] Added serial port support
|
|
||||||
11-Sep-08 JDB Fixed STC,C losing interrupt request on BREAK
|
11-Sep-08 JDB Fixed STC,C losing interrupt request on BREAK
|
||||||
07-Sep-08 JDB Fixed IN_LOOPBACK conflict with netinet/in.h
|
07-Sep-08 JDB Fixed IN_LOOPBACK conflict with netinet/in.h
|
||||||
Changed Telnet poll to connect immediately after reset or attach
|
Changed Telnet poll to connect immediately after reset or attach
|
||||||
|
@ -80,13 +78,13 @@
|
||||||
an "external rate" that is equivalent to 9600 baud, as most terminals were
|
an "external rate" that is equivalent to 9600 baud, as most terminals were
|
||||||
set to their maximum speeds.
|
set to their maximum speeds.
|
||||||
|
|
||||||
We support the 12966A connected to an HP terminal emulator via Telnet or a
|
We support the 12966A connected to an HP terminal emulator via Telnet.
|
||||||
serial port. Internally, we model the BACI as a terminal multiplexer with
|
Internally, we model the BACI as a terminal multiplexer with one line. The
|
||||||
one line. The simulation is complicated by the half-duplex nature of the
|
simulation is complicated by the half-duplex nature of the card (there is
|
||||||
card (there is only one FIFO, used selectively either for transmission or
|
only one FIFO, used selectively either for transmission or reception) and the
|
||||||
reception) and the double-buffered UART (a Western Digital TR1863A), which
|
double-buffered UART (a Western Digital TR1863A), which has holding registers
|
||||||
has holding registers as well as a shift registers for transmission and
|
as well as a shift registers for transmission and reception. We model both
|
||||||
reception. We model both sets of device registers.
|
sets of device registers.
|
||||||
|
|
||||||
During an output operation, the first character output to the card passes
|
During an output operation, the first character output to the card passes
|
||||||
through the FIFO and into the transmitter holding register. Subsequent
|
through the FIFO and into the transmitter holding register. Subsequent
|
||||||
|
@ -115,12 +113,12 @@
|
||||||
as an "optimized (fast) timing" option. Optimization makes three
|
as an "optimized (fast) timing" option. Optimization makes three
|
||||||
improvements:
|
improvements:
|
||||||
|
|
||||||
1. On output, characters in the FIFO are emptied into the line buffer as a
|
1. On output, characters in the FIFO are emptied into the Telnet buffer as a
|
||||||
block, rather than one character per service call, and on input, all of
|
block, rather than one character per service call, and on input, all of
|
||||||
the characters available in the line buffer are loaded into the FIFO as a
|
the characters available in the Telnet buffer are loaded into the FIFO as
|
||||||
block.
|
a block.
|
||||||
|
|
||||||
2. The ENQ/ACK handshake is done locally, without involving the terminal
|
2. The ENQ/ACK handshake is done locally, without involving the Telnet
|
||||||
client.
|
client.
|
||||||
|
|
||||||
3. Input occurring during an output operation is delayed until the second or
|
3. Input occurring during an output operation is delayed until the second or
|
||||||
|
@ -320,7 +318,7 @@
|
||||||
/* Unit references */
|
/* Unit references */
|
||||||
|
|
||||||
#define baci_term baci_unit[0] /* terminal I/O unit */
|
#define baci_term baci_unit[0] /* terminal I/O unit */
|
||||||
#define baci_poll baci_unit[1] /* line polling unit */
|
#define baci_poll baci_unit[1] /* Telnet polling unit */
|
||||||
|
|
||||||
|
|
||||||
/* BACI state variables */
|
/* BACI state variables */
|
||||||
|
@ -393,11 +391,11 @@ t_stat baci_detach (UNIT *uptr);
|
||||||
baci_deb BACI debug list
|
baci_deb BACI debug list
|
||||||
baci_dev BACI device descriptor
|
baci_dev BACI device descriptor
|
||||||
|
|
||||||
Two units are used: one to handle character I/O via the multiplexer library,
|
Two units are used: one to handle character I/O via the Telnet library, and
|
||||||
and another to poll for connections and input. The character I/O service
|
another to poll for connections and input. The character I/O service routine
|
||||||
routine runs only when there are characters to read or write. It operates at
|
runs only when there are characters to read or write. It operates at the
|
||||||
the approximate baud rate of the terminal (in CPU instructions per second) in
|
approximate baud rate of the terminal (in CPU instructions per second) in
|
||||||
order to be compatible with the OS drivers. The line poll must run
|
order to be compatible with the OS drivers. The Telnet poll must run
|
||||||
continuously, but it can operate much more slowly, as the only requirement is
|
continuously, but it can operate much more slowly, as the only requirement is
|
||||||
that it must not present a perceptible lag to human input. To be compatible
|
that it must not present a perceptible lag to human input. To be compatible
|
||||||
with CPU idling, it is co-scheduled with the master poll timer, which uses a
|
with CPU idling, it is co-scheduled with the master poll timer, which uses a
|
||||||
|
@ -407,13 +405,13 @@ t_stat baci_detach (UNIT *uptr);
|
||||||
DEVICE baci_dev;
|
DEVICE baci_dev;
|
||||||
|
|
||||||
TMLN baci_ldsc = { 0 }; /* line descriptor */
|
TMLN baci_ldsc = { 0 }; /* line descriptor */
|
||||||
TMXR baci_desc = { 1, 0, 0, &baci_ldsc, NULL, &baci_dev }; /* device descriptor */
|
TMXR baci_desc = { 1, 0, 0, &baci_ldsc }; /* device descriptor */
|
||||||
|
|
||||||
DIB baci_dib = { &baci_io, BACI, 0 };
|
DIB baci_dib = { &baci_io, BACI, 0 };
|
||||||
|
|
||||||
UNIT baci_unit[] = {
|
UNIT baci_unit[] = {
|
||||||
{ UDATA (&baci_term_svc, UNIT_ATTABLE | UNIT_FASTTIME, 0) }, /* terminal I/O unit */
|
{ UDATA (&baci_term_svc, UNIT_ATTABLE | UNIT_FASTTIME, 0) }, /* terminal I/O unit */
|
||||||
{ UDATA (&baci_poll_svc, UNIT_DIS, POLL_FIRST) } /* line poll unit */
|
{ UDATA (&baci_poll_svc, UNIT_DIS, POLL_FIRST) } /* Telnet poll unit */
|
||||||
};
|
};
|
||||||
|
|
||||||
REG baci_reg[] = {
|
REG baci_reg[] = {
|
||||||
|
@ -771,7 +769,7 @@ return stat_data;
|
||||||
The terminal service routine is used to transmit and receive characters.
|
The terminal service routine is used to transmit and receive characters.
|
||||||
|
|
||||||
In terminal mode, it is started when a character is ready for output or when
|
In terminal mode, it is started when a character is ready for output or when
|
||||||
the line poll routine determines that there are characters ready for input
|
the Telnet poll routine determines that there are characters ready for input
|
||||||
and stopped when there are no more characters to output or input. When the
|
and stopped when there are no more characters to output or input. When the
|
||||||
terminal is quiescent, this routine does not run.
|
terminal is quiescent, this routine does not run.
|
||||||
|
|
||||||
|
@ -811,11 +809,11 @@ return stat_data;
|
||||||
first character after an ENQ is not an ACK.
|
first character after an ENQ is not an ACK.
|
||||||
|
|
||||||
Finally, fast timing enables buffer combining. For output, all characters
|
Finally, fast timing enables buffer combining. For output, all characters
|
||||||
present in the FIFO are unloaded into the line buffer before initiating a
|
present in the FIFO are unloaded into the Telnet buffer before initiating a
|
||||||
packet send. For input, all characters present in the line buffer are loaded
|
packet send. For input, all characters present in the Telnet buffer are
|
||||||
into the FIFO. This reduces network traffic and decreases simulator overhead
|
loaded into the FIFO. This reduces network traffic and decreases simulator
|
||||||
(there is only one service routine entry per block, rather than one per
|
overhead (there is only one service routine entry per block, rather than one
|
||||||
character).
|
per character).
|
||||||
|
|
||||||
In fast output mode, it is imperative that not less than 1500 instructions
|
In fast output mode, it is imperative that not less than 1500 instructions
|
||||||
elapse between the first character load to the FIFO and the initiation of
|
elapse between the first character load to the FIFO and the initiation of
|
||||||
|
@ -978,11 +976,12 @@ return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* BACI line poll service.
|
/* BACI Telnet poll service.
|
||||||
|
|
||||||
This service routine is used to poll for connections and incoming characters.
|
This service routine is used to poll for Telnet connections and incoming
|
||||||
If characters are available, the terminal I/O service routine is scheduled.
|
characters. If characters are available, the terminal I/O service routine is
|
||||||
It starts when the line is attached and stops when the line is detached.
|
scheduled. It starts when the socket is attached and stops when the socket
|
||||||
|
is detached.
|
||||||
|
|
||||||
As there is only one line, we only poll for a new connection when the line is
|
As there is only one line, we only poll for a new connection when the line is
|
||||||
disconnected.
|
disconnected.
|
||||||
|
@ -1029,57 +1028,42 @@ baci_term.wait = service_time (baci_icw); /* set terminal I/O time
|
||||||
|
|
||||||
if (baci_term.flags & UNIT_ATT) { /* device attached? */
|
if (baci_term.flags & UNIT_ATT) { /* device attached? */
|
||||||
baci_poll.wait = POLL_FIRST; /* set up poll */
|
baci_poll.wait = POLL_FIRST; /* set up poll */
|
||||||
sim_activate (&baci_poll, baci_poll.wait); /* start line poll immediately */
|
sim_activate (&baci_poll, baci_poll.wait); /* start Telnet poll immediately */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
sim_cancel (&baci_poll); /* else stop line poll */
|
sim_cancel (&baci_poll); /* else stop Telnet poll */
|
||||||
|
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Attach line */
|
/* Attach controller */
|
||||||
|
|
||||||
t_stat baci_attach (UNIT *uptr, char *cptr)
|
t_stat baci_attach (UNIT *uptr, char *cptr)
|
||||||
{
|
{
|
||||||
t_stat status = SCPE_OK;
|
t_stat status = SCPE_OK;
|
||||||
|
|
||||||
if (uptr->flags & UNIT_DIS) /* unit disabled? */
|
status = tmxr_attach (&baci_desc, uptr, cptr); /* attach to socket */
|
||||||
return SCPE_UDIS; /* report it */
|
|
||||||
|
|
||||||
status = tmxr_attach (&baci_desc, uptr, cptr); /* try to attach to socket */
|
if (status == SCPE_OK) {
|
||||||
|
|
||||||
if (status == SCPE_ARG) /* invalid numeric port supplied? */
|
|
||||||
status = tmxr_attach_line (uptr, 0, cptr, &baci_desc); /* try to attach to serial port */
|
|
||||||
|
|
||||||
if (status == SCPE_OK) { /* attach successful? */
|
|
||||||
baci_poll.wait = POLL_FIRST; /* set up poll */
|
baci_poll.wait = POLL_FIRST; /* set up poll */
|
||||||
sim_activate (&baci_poll, baci_poll.wait); /* start line poll immediately */
|
sim_activate (&baci_poll, baci_poll.wait); /* start Telnet poll immediately */
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Detach controller */
|
||||||
/* Detach line */
|
|
||||||
|
|
||||||
t_stat baci_detach (UNIT *uptr)
|
t_stat baci_detach (UNIT *uptr)
|
||||||
{
|
{
|
||||||
t_stat status;
|
t_stat status;
|
||||||
|
|
||||||
if (uptr->flags & UNIT_DIS) /* unit disabled? */
|
status = tmxr_detach (&baci_desc, uptr); /* detach socket */
|
||||||
return SCPE_UDIS; /* report it */
|
|
||||||
|
|
||||||
status = tmxr_detach_line (uptr, 0, NULL, &baci_desc); /* attempt to detach serial line */
|
|
||||||
|
|
||||||
if (status == SCPE_UNATT) /* not attached to serial? */
|
|
||||||
status = tmxr_detach (&baci_desc, uptr); /* attempt to detach listening socket */
|
|
||||||
|
|
||||||
baci_ldsc.rcve = 0; /* disable line reception */
|
baci_ldsc.rcve = 0; /* disable line reception */
|
||||||
sim_cancel (&baci_poll); /* stop line poll */
|
sim_cancel (&baci_poll); /* stop Telnet poll */
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Local routines */
|
/* Local routines */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,6 @@
|
||||||
27-Oct-10 JDB Revised I/O signal enum values for concurrent signals
|
27-Oct-10 JDB Revised I/O signal enum values for concurrent signals
|
||||||
Revised I/O macros for new signal handling
|
Revised I/O macros for new signal handling
|
||||||
09-Oct-10 JDB Added DA and DC device select code assignments
|
09-Oct-10 JDB Added DA and DC device select code assignments
|
||||||
21-Oct-08 JDB [serial] Added "sim_unit_ref" external
|
|
||||||
07-Sep-08 JDB Added POLL_FIRST to indicate immediate connection attempt
|
07-Sep-08 JDB Added POLL_FIRST to indicate immediate connection attempt
|
||||||
15-Jul-08 JDB Rearranged declarations with hp2100_cpu.h
|
15-Jul-08 JDB Rearranged declarations with hp2100_cpu.h
|
||||||
26-Jun-08 JDB Rewrote device I/O to model backplane signals
|
26-Jun-08 JDB Rewrote device I/O to model backplane signals
|
||||||
|
@ -461,7 +460,6 @@ extern FILE *sim_deb;
|
||||||
extern FILE *sim_log;
|
extern FILE *sim_log;
|
||||||
extern int32 sim_step;
|
extern int32 sim_step;
|
||||||
extern int32 sim_switches;
|
extern int32 sim_switches;
|
||||||
extern UNITREF sim_unit_ref;
|
|
||||||
|
|
||||||
/* CPU functions */
|
/* CPU functions */
|
||||||
|
|
||||||
|
|
|
@ -29,9 +29,7 @@
|
||||||
28-Mar-11 JDB Tidied up signal handling
|
28-Mar-11 JDB Tidied up signal handling
|
||||||
26-Oct-10 JDB Changed I/O signal handler for revised signal model
|
26-Oct-10 JDB Changed I/O signal handler for revised signal model
|
||||||
25-Nov-08 JDB Revised for new multiplexer library SHOW routines
|
25-Nov-08 JDB Revised for new multiplexer library SHOW routines
|
||||||
19-Nov-08 JDB [serial] Removed DEV_NET to allow restoration of listening port
|
|
||||||
14-Nov-08 JDB Cleaned up VC++ size mismatch warnings for zero assignments
|
14-Nov-08 JDB Cleaned up VC++ size mismatch warnings for zero assignments
|
||||||
20-Oct-08 JDB [serial] Added serial port support
|
|
||||||
03-Oct-08 JDB Fixed logic for ENQ/XOFF transmit wait
|
03-Oct-08 JDB Fixed logic for ENQ/XOFF transmit wait
|
||||||
07-Sep-08 JDB Changed Telnet poll to connect immediately after reset or attach
|
07-Sep-08 JDB Changed Telnet poll to connect immediately after reset or attach
|
||||||
10-Aug-08 JDB Added REG_FIT to register variables < 32-bit size
|
10-Aug-08 JDB Added REG_FIT to register variables < 32-bit size
|
||||||
|
@ -59,8 +57,8 @@
|
||||||
character editing, echoing, ENQ/ACK handshaking, and read terminator
|
character editing, echoing, ENQ/ACK handshaking, and read terminator
|
||||||
detection, substantially reducing the load on the CPU over the earlier 12920
|
detection, substantially reducing the load on the CPU over the earlier 12920
|
||||||
multiplexer. It was supported by HP under RTE-MIII, RTE-IVB, and RTE-6/VM.
|
multiplexer. It was supported by HP under RTE-MIII, RTE-IVB, and RTE-6/VM.
|
||||||
Under simulation, it connects with HP terminal emulators via Telnet or serial
|
Under simulation, it connects with HP terminal emulators via Telnet to a
|
||||||
ports.
|
user-specified port.
|
||||||
|
|
||||||
The single interface card contained a Z80 CPU, DMA controller, CTC, four
|
The single interface card contained a Z80 CPU, DMA controller, CTC, four
|
||||||
two-channel SIO UARTs, 16K of RAM, 8K of ROM, and I/O backplane latches and
|
two-channel SIO UARTs, 16K of RAM, 8K of ROM, and I/O backplane latches and
|
||||||
|
@ -201,7 +199,7 @@
|
||||||
#define MPX_CNTLS 2 /* number of control units */
|
#define MPX_CNTLS 2 /* number of control units */
|
||||||
|
|
||||||
#define mpx_cntl (mpx_unit [MPX_PORTS + 0]) /* controller unit */
|
#define mpx_cntl (mpx_unit [MPX_PORTS + 0]) /* controller unit */
|
||||||
#define mpx_poll (mpx_unit [MPX_PORTS + 1]) /* polling unit */
|
#define mpx_poll (mpx_unit [MPX_PORTS + 1]) /* Telnet polling unit */
|
||||||
|
|
||||||
|
|
||||||
/* Character constants */
|
/* Character constants */
|
||||||
|
@ -613,16 +611,16 @@ t_stat mpx_show_frev (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||||
mpx_dev MPX device descriptor
|
mpx_dev MPX device descriptor
|
||||||
|
|
||||||
The first eight units correspond to the eight multiplexer line ports. These
|
The first eight units correspond to the eight multiplexer line ports. These
|
||||||
handle character I/O via the multiplexer library. A ninth unit acts as the
|
handle character I/O via the Telnet library. A ninth unit acts as the card
|
||||||
card controller, executing commands and transferring data to and from the I/O
|
controller, executing commands and transferring data to and from the I/O
|
||||||
buffers. A tenth unit is responsible for polling for connections and line
|
buffers. A tenth unit is responsible for polling for connections and socket
|
||||||
I/O. It also holds the master socket for Telnet connections.
|
I/O. It also holds the master socket.
|
||||||
|
|
||||||
The character I/O service routines run only when there are characters to read
|
The character I/O service routines run only when there are characters to read
|
||||||
or write. They operate at the approximate baud rates of the terminals (in
|
or write. They operate at the approximate baud rates of the terminals (in
|
||||||
CPU instructions per second) in order to be compatible with the OS drivers.
|
CPU instructions per second) in order to be compatible with the OS drivers.
|
||||||
The controller service routine runs only when a command is executing or a
|
The controller service routine runs only when a command is executing or a
|
||||||
data transfer to or from the CPU is in progress. The poll service must run
|
data transfer to or from the CPU is in progress. The Telnet poll must run
|
||||||
continuously, but it may operate much more slowly, as the only requirement is
|
continuously, but it may operate much more slowly, as the only requirement is
|
||||||
that it must not present a perceptible lag to human input. To be compatible
|
that it must not present a perceptible lag to human input. To be compatible
|
||||||
with CPU idling, it is co-scheduled with the master poll timer, which uses a
|
with CPU idling, it is co-scheduled with the master poll timer, which uses a
|
||||||
|
@ -636,7 +634,7 @@ DEVICE mpx_dev;
|
||||||
|
|
||||||
int32 mpx_order [MPX_PORTS] = { -1 }; /* connection order */
|
int32 mpx_order [MPX_PORTS] = { -1 }; /* connection order */
|
||||||
TMLN mpx_ldsc [MPX_PORTS] = { { 0 } }; /* line descriptors */
|
TMLN mpx_ldsc [MPX_PORTS] = { { 0 } }; /* line descriptors */
|
||||||
TMXR mpx_desc = { MPX_PORTS, 0, 0, mpx_ldsc, mpx_order, &mpx_dev }; /* device descriptor */
|
TMXR mpx_desc = { MPX_PORTS, 0, 0, mpx_ldsc, mpx_order }; /* device descriptor */
|
||||||
|
|
||||||
DIB mpx_dib = { &mpx_io, MPX };
|
DIB mpx_dib = { &mpx_io, MPX };
|
||||||
|
|
||||||
|
@ -650,7 +648,7 @@ UNIT mpx_unit [] = {
|
||||||
{ UDATA (&mpx_line_svc, UNIT_FASTTIME, 0) }, /* terminal I/O line 6 */
|
{ UDATA (&mpx_line_svc, UNIT_FASTTIME, 0) }, /* terminal I/O line 6 */
|
||||||
{ UDATA (&mpx_line_svc, UNIT_FASTTIME, 0) }, /* terminal I/O line 7 */
|
{ UDATA (&mpx_line_svc, UNIT_FASTTIME, 0) }, /* terminal I/O line 7 */
|
||||||
{ UDATA (&mpx_cntl_svc, UNIT_DIS, 0) }, /* controller unit */
|
{ UDATA (&mpx_cntl_svc, UNIT_DIS, 0) }, /* controller unit */
|
||||||
{ UDATA (&mpx_poll_svc, UNIT_ATTABLE | UNIT_DIS, POLL_FIRST) } /* line poll unit */
|
{ UDATA (&mpx_poll_svc, UNIT_ATTABLE | UNIT_DIS, POLL_FIRST) } /* Telnet poll unit */
|
||||||
};
|
};
|
||||||
|
|
||||||
REG mpx_reg [] = {
|
REG mpx_reg [] = {
|
||||||
|
@ -1604,20 +1602,21 @@ return SCPE_OK;
|
||||||
/* Multiplexer line service.
|
/* Multiplexer line service.
|
||||||
|
|
||||||
The line service routine is used to transmit and receive characters. It is
|
The line service routine is used to transmit and receive characters. It is
|
||||||
started when a buffer is ready for output or when the poll service routine
|
started when a buffer is ready for output or when the Telnet poll routine
|
||||||
determines that there are characters ready for input, and it is stopped when
|
determines that there are characters ready for input, and it is stopped when
|
||||||
there are no more characters to output or input. When a line is quiescent,
|
there are no more characters to output or input. When a line is quiescent,
|
||||||
this routine does not run. Service times are selected to approximate the
|
this routine does not run. Service times are selected to approximate the
|
||||||
baud rate setting of the multiplexer port.
|
baud rate setting of the multiplexer port.
|
||||||
|
|
||||||
"Fast timing" mode enables three optimizations. First, buffered characters
|
"Fast timing" mode enables three optimizations. First, buffered characters
|
||||||
are transferred in blocks, rather than a character at a time; this reduces
|
are transferred via Telnet in blocks, rather than a character at a time; this
|
||||||
line traffic and decreases simulator overhead (there is only one service
|
reduces network traffic and decreases simulator overhead (there is only one
|
||||||
routine entry per block, rather than one per character). Second, ENQ/ACK
|
service routine entry per block, rather than one per character). Second,
|
||||||
handshaking is done locally, without involving the client. Third, when
|
ENQ/ACK handshaking is done locally, without involving the Telnet client.
|
||||||
editing and echo is enabled, entering BS echoes a backspace, a space, and a
|
Third, when editing and echo is enabled, entering BS echoes a backspace, a
|
||||||
backspace, and entering DEL echoes a backslash, a carriage return, and a line
|
space, and a backspace, and entering DEL echoes a backslash, a carriage
|
||||||
feed, providing better compatibility with prior RTE terminal drivers.
|
return, and a line feed, providing better compatibility with prior RTE
|
||||||
|
terminal drivers.
|
||||||
|
|
||||||
Each read and write buffer begins with a reserved header byte that stores
|
Each read and write buffer begins with a reserved header byte that stores
|
||||||
per-buffer information, such as whether handshaking should be suppressed
|
per-buffer information, such as whether handshaking should be suppressed
|
||||||
|
@ -1631,7 +1630,7 @@ return SCPE_OK;
|
||||||
write buffer is freed, and a UI check is made if the controller is idle, in
|
write buffer is freed, and a UI check is made if the controller is idle, in
|
||||||
case a write buffer request is pending.
|
case a write buffer request is pending.
|
||||||
|
|
||||||
For input, the character is retrieved from the line buffer. If a BREAK was
|
For input, the character is retrieved from the Telnet buffer. If a BREAK was
|
||||||
received, break status is set, and the character is discarded (the current
|
received, break status is set, and the character is discarded (the current
|
||||||
multiplexer library implementation always returns a NUL with a BREAK
|
multiplexer library implementation always returns a NUL with a BREAK
|
||||||
indication). If the character is an XOFF, and XON/XOFF pacing is enabled, a
|
indication). If the character is an XOFF, and XON/XOFF pacing is enabled, a
|
||||||
|
@ -1940,11 +1939,11 @@ return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Poll service.
|
/* Telnet poll service.
|
||||||
|
|
||||||
This service routine is used to poll for connections and incoming characters.
|
This service routine is used to poll for Telnet connections and incoming
|
||||||
It is started when the listening socket or a serial line is attached and is
|
characters. It starts when the socket is attached and stops when the socket
|
||||||
stopped when the socket and all lines are detached.
|
is detached.
|
||||||
|
|
||||||
Each line is then checked for a pending ENQ/ACK handshake. If one is
|
Each line is then checked for a pending ENQ/ACK handshake. If one is
|
||||||
pending, the ACK counter is incremented, and if it times out, another ENQ is
|
pending, the ACK counter is incremented, and if it times out, another ENQ is
|
||||||
|
@ -2008,10 +2007,10 @@ return SCPE_OK;
|
||||||
1. Under simulation, we also clear the input buffer register, even though
|
1. Under simulation, we also clear the input buffer register, even though
|
||||||
the hardware doesn't.
|
the hardware doesn't.
|
||||||
|
|
||||||
2. We set up the first poll for connections to occur "immediately" upon
|
2. We set up the first poll for Telnet connections to occur "immediately"
|
||||||
execution, so that clients will be connected before execution begins.
|
upon execution, so that clients will be connected before execution
|
||||||
Otherwise, a fast program may access the multiplexer before the poll
|
begins. Otherwise, a fast program may access the multiplexer before the
|
||||||
service routine activates.
|
poll service routine activates.
|
||||||
|
|
||||||
3. We must set the "emptying_flags" and "filling_flags" values here, because
|
3. We must set the "emptying_flags" and "filling_flags" values here, because
|
||||||
they cannot be initialized statically, even though the values are
|
they cannot be initialized statically, even though the values are
|
||||||
|
@ -2031,70 +2030,47 @@ IOPRESET (&mpx_dib); /* PRESET device (does n
|
||||||
|
|
||||||
mpx_ibuf = 0; /* clear input buffer */
|
mpx_ibuf = 0; /* clear input buffer */
|
||||||
|
|
||||||
if (tmxr_mux_free (&mpx_desc)) /* any lines attached? */
|
if (mpx_poll.flags & UNIT_ATT) { /* network attached? */
|
||||||
sim_cancel (&mpx_poll); /* no, so stop poll */
|
|
||||||
else { /* attached or listening */
|
|
||||||
mpx_poll.wait = POLL_FIRST; /* set up poll */
|
mpx_poll.wait = POLL_FIRST; /* set up poll */
|
||||||
sim_activate (&mpx_poll, mpx_poll.wait); /* start poll immediately */
|
sim_activate (&mpx_poll, mpx_poll.wait); /* start Telnet poll immediately */
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
sim_cancel (&mpx_poll); /* else stop Telnet poll */
|
||||||
|
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Attach the multiplexer or a line.
|
/* Attach the multiplexer to a Telnet port.
|
||||||
|
|
||||||
We are called by the ATTACH MPX <port> command to attach the multiplexer to
|
We are called by the ATTACH MPX <port> command to attach the multiplexer to
|
||||||
the listening port indicated by <port> and by ATTACH MPX<n> <ser> to attach
|
the listening port indicated by <port>. Logically, it is the multiplexer
|
||||||
line <n> to serial port <ser>. Logically, it is the multiplexer device that
|
device that is attached; however, SIMH only allows units to be attached.
|
||||||
is attached; however, SIMH only allows units to be attached. This makes
|
This makes sense for devices such as tape drives, where the attached media is
|
||||||
sense for devices such as tape drives, where the attached media is a property
|
a property of a specific drive. In our case, though, the listening port is a
|
||||||
of a specific drive. In our case, though, the listening port is a property
|
property of the multiplexer card, not of any given serial line. As ATTACH
|
||||||
of the multiplexer card, not of any given serial line.
|
MPX is equivalent to ATTACH MPX0, the port would, by default, be attached to
|
||||||
|
the first serial line and be reported there in a SHOW MPX command.
|
||||||
|
|
||||||
To preserve the logical picture, we attach the listening port to the poll
|
To preserve the logical picture, we attach the port to the Telnet poll unit,
|
||||||
unit (unit 9), which is normally disabled to inhibit its display. Serial
|
which is normally disabled to inhibit its display. Attaching to a disabled
|
||||||
ports are attached to line units 0-7 normally. Attachment is reported by the
|
unit is not allowed, so we first enable the unit, then attach it, then
|
||||||
"mpx_status" routine below.
|
disable it again. Attachment is reported by the "mpx_status" routine below.
|
||||||
|
|
||||||
The connection poll service routine is synchronized with the other input
|
The Telnet poll service routine is synchronized with the other input polling
|
||||||
polling devices in the simulator to facilitate idling.
|
devices in the simulator to facilitate idling.
|
||||||
|
|
||||||
Implementation notes:
|
|
||||||
|
|
||||||
1. ATTACH MPX will pass a pointer unit 0. This is because the common
|
|
||||||
simulator code treats ATTACH MPX as equivalent to ATTACH MPX0. We
|
|
||||||
differentiate these cases by examining the "sim_unit_ref" global to see
|
|
||||||
if a device was referenced.
|
|
||||||
|
|
||||||
2. Directly attempting to attach to units 8 (controller) or 9 (poll) will be
|
|
||||||
rejected.
|
|
||||||
|
|
||||||
3. If we are being called as part of RESTORE processing, we may see a
|
|
||||||
request to attach the poll unit (unit 9). This will occur if unit 9 was
|
|
||||||
attached when the SAVE was done. In this case, the SIM_SW_REST flag will
|
|
||||||
be set in "sim_switches", and we will allow the call to succeed.
|
|
||||||
|
|
||||||
4. If the poll unit is attached, it will be enabled as part of RESTORE
|
|
||||||
processing. We always unilaterally disable this unit to ensure that it
|
|
||||||
remains hidden.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
t_stat mpx_attach (UNIT *uptr, char *cptr)
|
t_stat mpx_attach (UNIT *uptr, char *cptr)
|
||||||
{
|
{
|
||||||
t_stat status = SCPE_OK;
|
t_stat status = SCPE_OK;
|
||||||
|
|
||||||
if ((uptr == &mpx_cntl) || /* attaching controller? */
|
if (uptr != mpx_unit) /* not unit 0? */
|
||||||
(uptr == &mpx_poll) && !(sim_switches & SIM_SW_REST)) /* or poll unit directly? */
|
return SCPE_NOATT; /* can't attach */
|
||||||
return SCPE_NOATT; /* disallow */
|
|
||||||
|
|
||||||
if (sim_unit_ref == ref_dev || (uptr == &mpx_poll)) { /* device attach or poll restore request? */
|
mpx_poll.flags = mpx_poll.flags & ~UNIT_DIS; /* enable unit */
|
||||||
status = tmxr_attach (&mpx_desc, &mpx_poll, cptr); /* attach to socket */
|
status = tmxr_attach (&mpx_desc, &mpx_poll, cptr); /* attach to socket */
|
||||||
mpx_poll.flags = mpx_poll.flags | UNIT_DIS; /* disable unit */
|
mpx_poll.flags = mpx_poll.flags | UNIT_DIS; /* disable unit */
|
||||||
}
|
|
||||||
|
|
||||||
else /* line attach request */
|
|
||||||
status = tmxr_attach_line (uptr, 0, cptr, &mpx_desc); /* attach line */
|
|
||||||
|
|
||||||
if (status == SCPE_OK) {
|
if (status == SCPE_OK) {
|
||||||
mpx_poll.wait = POLL_FIRST; /* set up poll */
|
mpx_poll.wait = POLL_FIRST; /* set up poll */
|
||||||
|
@ -2104,56 +2080,33 @@ return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Detach the multiplexer or a line.
|
/* Detach the multiplexer.
|
||||||
|
|
||||||
We are called by the DETACH MPX command to detach the listening port and all
|
Normally, we are called by the DETACH MPX command, which is equivalent to
|
||||||
Telnet sessions and by the DETACH MPX<n> to detach a serial port from line
|
DETACH MPX0. However, we may be called with other units in two cases.
|
||||||
<n>. We will also be called by DETACH ALL, RESTORE, and during simulator
|
|
||||||
shutdown. For DETACH ALL and RESTORE, we must not fail the call, or
|
|
||||||
processing of other units will cease.
|
|
||||||
|
|
||||||
Implementation notes:
|
A DETACH ALL command will call us for unit 9 (the poll unit) if it is
|
||||||
|
attached. Also, during simulator shutdown, we will be called for units 0-8
|
||||||
1. Because DETACH MPX will pass unit 0, we check the "sim_unit_ref" global
|
(detach_all in scp.c calls the detach routines of all units that do NOT have
|
||||||
to see if MPX or MPX0 was specified in the command.
|
UNIT_ATTABLE), as well as for unit 9 if it is attached. In both cases, it is
|
||||||
|
imperative that we return SCPE_OK, otherwise any remaining device detaches
|
||||||
2. Directly attempting to detach unit 8 (controller) will be rejected. We
|
will not be performed.
|
||||||
cannot fail a direct DETACH MPX9 (poll unit), because we cannot tell that
|
|
||||||
case apart from a DETACH ALL (a RESTORE will have the SIM_SW_REST flag
|
|
||||||
set in "sim_switches").
|
|
||||||
|
|
||||||
3. During simulator shutdown, we will be called for units 0-8 (detach_all in
|
|
||||||
scp.c calls the detach routines of all units that do NOT have
|
|
||||||
UNIT_ATTABLE), as well as for unit 9 if it is attached.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
t_stat mpx_detach (UNIT *uptr)
|
t_stat mpx_detach (UNIT *uptr)
|
||||||
{
|
{
|
||||||
uint32 ln;
|
t_stat status = SCPE_OK;
|
||||||
t_stat status;
|
int32 i;
|
||||||
t_bool mux_free = TRUE;
|
|
||||||
|
|
||||||
if (uptr == &mpx_cntl) /* detaching controller directly? */
|
if ((uptr == mpx_unit) || (uptr == &mpx_poll)) { /* base unit or poll unit? */
|
||||||
return SCPE_NOATT; /* disallow */
|
|
||||||
|
|
||||||
if (sim_unit_ref == ref_dev || uptr == &mpx_poll) /* device detach or detach all request? */
|
|
||||||
status = tmxr_detach (&mpx_desc, &mpx_poll); /* detach socket */
|
status = tmxr_detach (&mpx_desc, &mpx_poll); /* detach socket */
|
||||||
|
|
||||||
else /* line detach request */
|
for (i = 0; i < MPX_PORTS; i++) {
|
||||||
status = tmxr_detach_line (uptr, 0, NULL, &mpx_desc); /* detach line */
|
mpx_ldsc [i].rcve = 0; /* disable line reception */
|
||||||
|
sim_cancel (&mpx_unit [i]); /* cancel any scheduled I/O */
|
||||||
if (status == SCPE_OK) {
|
|
||||||
for (ln = 0; ln < MPX_PORTS; ln++) /* loop through lines */
|
|
||||||
if (tmxr_line_free (&mpx_ldsc[ln])) { /* is line free? */
|
|
||||||
mpx_ldsc[ln].rcve = 0; /* disable rcv as line was reset */
|
|
||||||
sim_cancel (&mpx_unit [ln]); /* cancel any scheduled I/O */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
sim_cancel (&mpx_poll); /* stop Telnet poll */
|
||||||
mux_free = FALSE; /* mux isn't free if line is in use */
|
|
||||||
|
|
||||||
if (mux_free && !(mpx_poll.flags & UNIT_ATT)) /* all lines free and not listening? */
|
|
||||||
sim_cancel (&mpx_poll); /* stop poll */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
|
@ -2214,7 +2167,7 @@ return SCPE_OK;
|
||||||
/* Local routines */
|
/* Local routines */
|
||||||
|
|
||||||
|
|
||||||
/* Poll for new connections */
|
/* Poll for new Telnet connections */
|
||||||
|
|
||||||
static void poll_connection (void)
|
static void poll_connection (void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -29,8 +29,6 @@
|
||||||
28-Mar-11 JDB Tidied up signal handling
|
28-Mar-11 JDB Tidied up signal handling
|
||||||
26-Oct-10 JDB Changed I/O signal handler for revised signal model
|
26-Oct-10 JDB Changed I/O signal handler for revised signal model
|
||||||
25-Nov-08 JDB Revised for new multiplexer library SHOW routines
|
25-Nov-08 JDB Revised for new multiplexer library SHOW routines
|
||||||
19-Nov-08 JDB [serial] Removed DEV_NET to allow restoration of listening port
|
|
||||||
20-Oct-08 JDB [serial] Added serial port support
|
|
||||||
09-Oct-08 JDB "muxl_unit" defined one too many units (17 instead of 16)
|
09-Oct-08 JDB "muxl_unit" defined one too many units (17 instead of 16)
|
||||||
10-Sep-08 JDB SHOW MUX CONN/STAT with SET MUX DIAG is no longer disallowed
|
10-Sep-08 JDB SHOW MUX CONN/STAT with SET MUX DIAG is no longer disallowed
|
||||||
07-Sep-08 JDB Changed Telnet poll to connect immediately after reset or attach
|
07-Sep-08 JDB Changed Telnet poll to connect immediately after reset or attach
|
||||||
|
@ -329,7 +327,6 @@ t_stat muxo_svc (UNIT *uptr);
|
||||||
t_stat muxc_reset (DEVICE *dptr);
|
t_stat muxc_reset (DEVICE *dptr);
|
||||||
t_stat mux_attach (UNIT *uptr, char *cptr);
|
t_stat mux_attach (UNIT *uptr, char *cptr);
|
||||||
t_stat mux_detach (UNIT *uptr);
|
t_stat mux_detach (UNIT *uptr);
|
||||||
t_stat muxl_detach (UNIT *uptr);
|
|
||||||
t_stat mux_setdiag (UNIT *uptr, int32 val, char *cptr, void *desc);
|
t_stat mux_setdiag (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||||
|
|
||||||
|
|
||||||
|
@ -433,8 +430,8 @@ DEVICE muxl_dev = {
|
||||||
NULL, /* deposit routine */
|
NULL, /* deposit routine */
|
||||||
&muxc_reset, /* reset routine */
|
&muxc_reset, /* reset routine */
|
||||||
NULL, /* boot routine */
|
NULL, /* boot routine */
|
||||||
&mux_attach, /* attach routine */
|
NULL, /* attach routine */
|
||||||
&muxl_detach, /* detach routine */
|
NULL, /* detach routine */
|
||||||
&muxl_dib, /* device information block */
|
&muxl_dib, /* device information block */
|
||||||
DEV_DISABLE, /* device flags */
|
DEV_DISABLE, /* device flags */
|
||||||
0, /* debug control flags */
|
0, /* debug control flags */
|
||||||
|
@ -461,7 +458,7 @@ DEVICE muxu_dev;
|
||||||
|
|
||||||
int32 mux_order [MUX_LINES] = { -1 }; /* connection order */
|
int32 mux_order [MUX_LINES] = { -1 }; /* connection order */
|
||||||
TMLN mux_ldsc [MUX_LINES] = { { 0 } }; /* line descriptors */
|
TMLN mux_ldsc [MUX_LINES] = { { 0 } }; /* line descriptors */
|
||||||
TMXR mux_desc = { MUX_LINES, 0, 0, mux_ldsc, mux_order, &muxu_dev }; /* device descriptor */
|
TMXR mux_desc = { MUX_LINES, 0, 0, mux_ldsc, mux_order }; /* device descriptor */
|
||||||
|
|
||||||
UNIT muxu_unit = { UDATA (&muxi_svc, UNIT_ATTABLE, 0), POLL_FIRST };
|
UNIT muxu_unit = { UDATA (&muxi_svc, UNIT_ATTABLE, 0), POLL_FIRST };
|
||||||
|
|
||||||
|
@ -923,7 +920,7 @@ while (working_set) {
|
||||||
(old & DTR) && /* DTR drop? */
|
(old & DTR) && /* DTR drop? */
|
||||||
!(muxc_ota[ln] & DTR)) {
|
!(muxc_ota[ln] & DTR)) {
|
||||||
tmxr_linemsg (&mux_ldsc[ln], "\r\nLine hangup\r\n");
|
tmxr_linemsg (&mux_ldsc[ln], "\r\nLine hangup\r\n");
|
||||||
tmxr_clear_ln (&mux_desc, &mux_ldsc[ln]); /* disconnect line */
|
tmxr_reset_ln (&mux_ldsc[ln]); /* reset line */
|
||||||
muxc_lia[ln] = 0; /* dataset off */
|
muxc_lia[ln] = 0; /* dataset off */
|
||||||
}
|
}
|
||||||
} /* end update */
|
} /* end update */
|
||||||
|
@ -1308,12 +1305,12 @@ IOPRESET (dibptr); /* PRESET device (does n
|
||||||
|
|
||||||
muxc_chan = muxc_scan = 0; /* init modem scan */
|
muxc_chan = muxc_scan = 0; /* init modem scan */
|
||||||
|
|
||||||
if (tmxr_mux_free (&mux_desc)) /* any lines attached? */
|
if (muxu_unit.flags & UNIT_ATT) { /* master att? */
|
||||||
sim_cancel (&muxu_unit); /* no, so stop poll */
|
|
||||||
else { /* attached or listening */
|
|
||||||
muxu_unit.wait = POLL_FIRST; /* set up poll */
|
muxu_unit.wait = POLL_FIRST; /* set up poll */
|
||||||
sim_activate (&muxu_unit, muxu_unit.wait); /* start poll immediately */
|
sim_activate (&muxu_unit, muxu_unit.wait); /* start Telnet poll immediately */
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
sim_cancel (&muxu_unit); /* else stop */
|
||||||
|
|
||||||
for (i = 0; i < MUX_LINES; i++)
|
for (i = 0; i < MUX_LINES; i++)
|
||||||
mux_reset_ln (i); /* reset lines 0-15 */
|
mux_reset_ln (i); /* reset lines 0-15 */
|
||||||
|
@ -1325,7 +1322,7 @@ return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Attach master unit or line */
|
/* Attach master unit */
|
||||||
|
|
||||||
t_stat mux_attach (UNIT *uptr, char *cptr)
|
t_stat mux_attach (UNIT *uptr, char *cptr)
|
||||||
{
|
{
|
||||||
|
@ -1334,14 +1331,11 @@ t_stat status = SCPE_OK;
|
||||||
if (muxu_unit.flags & UNIT_DIAG) /* diag mode? */
|
if (muxu_unit.flags & UNIT_DIAG) /* diag mode? */
|
||||||
return SCPE_NOFNC; /* command not allowed */
|
return SCPE_NOFNC; /* command not allowed */
|
||||||
|
|
||||||
if (uptr == &muxu_unit) /* master unit? */
|
status = tmxr_attach (&mux_desc, uptr, cptr); /* attach */
|
||||||
status = tmxr_attach (&mux_desc, uptr, cptr); /* attach socket */
|
|
||||||
else
|
|
||||||
status = tmxr_attach_line (uptr, 0, cptr, &mux_desc); /* attach line */
|
|
||||||
|
|
||||||
if (status == SCPE_OK) { /* attach successful? */
|
if (status == SCPE_OK) {
|
||||||
muxu_unit.wait = POLL_FIRST; /* set up poll */
|
muxu_unit.wait = POLL_FIRST; /* set up poll */
|
||||||
sim_activate (&muxu_unit, muxu_unit.wait); /* start poll immediately */
|
sim_activate (&muxu_unit, muxu_unit.wait); /* start Telnet poll immediately */
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
|
@ -1352,45 +1346,13 @@ return status;
|
||||||
|
|
||||||
t_stat mux_detach (UNIT *uptr)
|
t_stat mux_detach (UNIT *uptr)
|
||||||
{
|
{
|
||||||
uint32 ln;
|
int32 i;
|
||||||
t_stat status;
|
t_stat r;
|
||||||
t_bool free = TRUE;
|
|
||||||
|
|
||||||
status = tmxr_detach (&mux_desc, uptr); /* detach unit */
|
r = tmxr_detach (&mux_desc, uptr); /* detach */
|
||||||
|
for (i = 0; i < MUX_LINES; i++) mux_ldsc[i].rcve = 0; /* disable rcv */
|
||||||
if (status == SCPE_OK) {
|
|
||||||
for (ln = 0; ln < MUX_LINES; ln++) /* loop through lines */
|
|
||||||
if (tmxr_line_free (&mux_ldsc[ln])) /* is line free? */
|
|
||||||
mux_ldsc[ln].rcve = 0; /* yes, so disable rcv as line was reset */
|
|
||||||
else
|
|
||||||
free = FALSE; /* mux isn't free if line is in use */
|
|
||||||
|
|
||||||
if (free) /* all lines free? */
|
|
||||||
sim_cancel (uptr); /* stop poll */
|
sim_cancel (uptr); /* stop poll */
|
||||||
}
|
return r;
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Detach line */
|
|
||||||
|
|
||||||
t_stat muxl_detach (UNIT *uptr)
|
|
||||||
{
|
|
||||||
uint32 ln;
|
|
||||||
t_stat status;
|
|
||||||
|
|
||||||
status = tmxr_detach_line (uptr, 0, NULL, &mux_desc); /* detach line */
|
|
||||||
|
|
||||||
if (status == SCPE_OK) {
|
|
||||||
ln = uptr - muxl_unit; /* determine line number */
|
|
||||||
mux_ldsc[ln].rcve = 0; /* disable line reception */
|
|
||||||
|
|
||||||
if (tmxr_mux_free (&mux_desc)) /* all lines free and not listening? */
|
|
||||||
sim_cancel (&muxu_unit); /* stop poll */
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1405,7 +1367,7 @@ return status;
|
||||||
for normal character transfers, which is undesirable.
|
for normal character transfers, which is undesirable.
|
||||||
|
|
||||||
Therefore, to enable diagnostic mode, we must force a disconnect of the
|
Therefore, to enable diagnostic mode, we must force a disconnect of the
|
||||||
master socket and all Telnet and serial lines, which clears the connection
|
master socket and any connected Telnet lines, which clears the connection
|
||||||
flags on all lines. Then we set the "transmission enabled" flags on all
|
flags on all lines. Then we set the "transmission enabled" flags on all
|
||||||
lines to enable output character processing for the diagnostic. (Normally,
|
lines to enable output character processing for the diagnostic. (Normally,
|
||||||
all of the flags are set when the multiplexer is first attached. Until then,
|
all of the flags are set when the multiplexer is first attached. Until then,
|
||||||
|
@ -1418,12 +1380,9 @@ t_stat mux_setdiag (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||||
int32 ln;
|
int32 ln;
|
||||||
|
|
||||||
if (val) { /* set diag? */
|
if (val) { /* set diag? */
|
||||||
mux_detach (uptr); /* detach Telnet lines */
|
mux_detach (uptr); /* detach lines */
|
||||||
|
for (ln = 0; ln < MUX_LINES; ln++) /* enable transmission */
|
||||||
for (ln = 0; ln < MUX_LINES; ln++) {
|
mux_ldsc[ln].xmte = 1; /* on all lines */
|
||||||
muxl_detach (&muxl_unit[ln]); /* detach all serial lines */
|
|
||||||
mux_ldsc[ln].xmte = 1; /* enable transmission on all lines */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else { /* set term */
|
else { /* set term */
|
||||||
for (ln = 0; ln < MUX_LINES; ln++) /* clear connections */
|
for (ln = 0; ln < MUX_LINES; ln++) /* clear connections */
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
|
|
||||||
18-Apr-2012 RMS Modified to use clock coscheduling
|
18-Apr-2012 RMS Modified to use clock coscheduling
|
||||||
17-Aug-2011 RMS Added AUTOCONFIGURE modifier
|
17-Aug-2011 RMS Added AUTOCONFIGURE modifier
|
||||||
26-Nov-2008 JDB [serial] Added serial port support
|
|
||||||
19-Nov-2008 RMS Revised for common TMXR show routines
|
19-Nov-2008 RMS Revised for common TMXR show routines
|
||||||
Revised to autoconfigure vectors
|
Revised to autoconfigure vectors
|
||||||
|
|
||||||
|
@ -132,7 +131,6 @@ t_stat dci_svc (UNIT *uptr);
|
||||||
t_stat dco_svc (UNIT *uptr);
|
t_stat dco_svc (UNIT *uptr);
|
||||||
t_stat dcx_attach (UNIT *uptr, char *cptr);
|
t_stat dcx_attach (UNIT *uptr, char *cptr);
|
||||||
t_stat dcx_detach (UNIT *uptr);
|
t_stat dcx_detach (UNIT *uptr);
|
||||||
t_stat dcl_detach (UNIT *uptr);
|
|
||||||
t_stat dcx_set_lines (UNIT *uptr, int32 val, char *cptr, void *desc);
|
t_stat dcx_set_lines (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||||
void dcx_enbdis (int32 dis);
|
void dcx_enbdis (int32 dis);
|
||||||
void dci_clr_int (int32 ln);
|
void dci_clr_int (int32 ln);
|
||||||
|
@ -254,7 +252,7 @@ DEVICE dco_dev = {
|
||||||
"DCO", dco_unit, dco_reg, dco_mod,
|
"DCO", dco_unit, dco_reg, dco_mod,
|
||||||
DCX_LINES, 10, 31, 1, 8, 8,
|
DCX_LINES, 10, 31, 1, 8, 8,
|
||||||
NULL, NULL, &dcx_reset,
|
NULL, NULL, &dcx_reset,
|
||||||
NULL, &dcx_attach, &dcl_detach,
|
NULL, NULL, NULL,
|
||||||
NULL, DEV_UBUS | DEV_DISABLE | DEV_DIS
|
NULL, DEV_UBUS | DEV_DISABLE | DEV_DIS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -368,6 +366,8 @@ t_stat dci_svc (UNIT *uptr)
|
||||||
{
|
{
|
||||||
int32 ln, c, temp;
|
int32 ln, c, temp;
|
||||||
|
|
||||||
|
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
|
||||||
|
return SCPE_OK;
|
||||||
sim_activate (uptr, clk_cosched (tmxr_poll)); /* continue poll */
|
sim_activate (uptr, clk_cosched (tmxr_poll)); /* continue poll */
|
||||||
ln = tmxr_poll_conn (&dcx_desc); /* look for connect */
|
ln = tmxr_poll_conn (&dcx_desc); /* look for connect */
|
||||||
if (ln >= 0) { /* got one? */
|
if (ln >= 0) { /* got one? */
|
||||||
|
@ -510,12 +510,9 @@ t_stat dcx_reset (DEVICE *dptr)
|
||||||
int32 ln;
|
int32 ln;
|
||||||
|
|
||||||
dcx_enbdis (dptr->flags & DEV_DIS); /* sync enables */
|
dcx_enbdis (dptr->flags & DEV_DIS); /* sync enables */
|
||||||
//
|
sim_cancel (&dci_unit); /* assume stop */
|
||||||
if (tmxr_mux_free (&dcx_desc)) /* any lines attached? */
|
if (dci_unit.flags & UNIT_ATT) /* if attached, */
|
||||||
sim_cancel (&dci_unit); /* no, so stop poll */
|
sim_activate (&dci_unit, tmxr_poll); /* activate */
|
||||||
else /* attached or listening */
|
|
||||||
sim_activate (&dci_unit, tmxr_poll); /* start poll immediately */
|
|
||||||
//
|
|
||||||
for (ln = 0; ln < DCX_LINES; ln++) /* for all lines */
|
for (ln = 0; ln < DCX_LINES; ln++) /* for all lines */
|
||||||
dcx_reset_ln (ln);
|
dcx_reset_ln (ln);
|
||||||
return auto_config (dci_dev.name, dcx_desc.lines); /* auto config */
|
return auto_config (dci_dev.name, dcx_desc.lines); /* auto config */
|
||||||
|
@ -535,22 +532,16 @@ dco_clr_int (ln);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Attach master unit or line */
|
/* Attach master unit */
|
||||||
|
|
||||||
t_stat dcx_attach (UNIT *uptr, char *cptr)
|
t_stat dcx_attach (UNIT *uptr, char *cptr)
|
||||||
{
|
{
|
||||||
t_stat r;
|
t_stat r;
|
||||||
|
|
||||||
//
|
r = tmxr_attach (&dcx_desc, uptr, cptr); /* attach */
|
||||||
if (uptr == &dci_unit) /* master unit? */
|
|
||||||
r = tmxr_attach (&dcx_desc, uptr, cptr); /* attach socket */
|
|
||||||
else
|
|
||||||
r = tmxr_attach_line (uptr, 0, cptr, &dcx_desc); /* attach line */
|
|
||||||
//
|
|
||||||
|
|
||||||
if (r != SCPE_OK) /* error? */
|
if (r != SCPE_OK) /* error? */
|
||||||
return r;
|
return r;
|
||||||
sim_activate (&dci_unit, tmxr_poll); /* start poll */
|
sim_activate (uptr, tmxr_poll); /* start poll */
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -560,48 +551,14 @@ t_stat dcx_detach (UNIT *uptr)
|
||||||
{
|
{
|
||||||
int32 i;
|
int32 i;
|
||||||
t_stat r;
|
t_stat r;
|
||||||
t_bool free = TRUE;
|
|
||||||
|
|
||||||
r = tmxr_detach (&dcx_desc, uptr); /* detach */
|
r = tmxr_detach (&dcx_desc, uptr); /* detach */
|
||||||
|
for (i = 0; i < DCX_LINES; i++) /* all lines, */
|
||||||
//
|
dcx_ldsc[i].rcve = 0; /* disable rcv */
|
||||||
if (r == SCPE_OK) {
|
|
||||||
for (i = 0; i < DCX_LINES; i++) /* loop through lines */
|
|
||||||
if (tmxr_line_free (&dcx_ldsc[i])) /* is line free? */
|
|
||||||
dcx_ldsc[i].rcve = 0; /* yes, so disable rcv as line was reset */
|
|
||||||
else
|
|
||||||
free = FALSE; /* mux isn't free if line is in use */
|
|
||||||
|
|
||||||
if (free) /* all lines free? */
|
|
||||||
sim_cancel (uptr); /* stop poll */
|
sim_cancel (uptr); /* stop poll */
|
||||||
}
|
|
||||||
//
|
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Detach line */
|
|
||||||
|
|
||||||
//
|
|
||||||
t_stat dcl_detach (UNIT *uptr)
|
|
||||||
{
|
|
||||||
uint32 ln;
|
|
||||||
t_stat status;
|
|
||||||
|
|
||||||
status = tmxr_detach_line (uptr, 0, NULL, &dcx_desc); /* detach line */
|
|
||||||
|
|
||||||
if (status == SCPE_OK) {
|
|
||||||
ln = uptr - dco_unit; /* determine line number */
|
|
||||||
dcx_ldsc[ln].rcve = 0; /* disable line reception */
|
|
||||||
|
|
||||||
if (tmxr_mux_free (&dcx_desc)) /* all lines free and not listening? */
|
|
||||||
sim_cancel (&dci_unit); /* stop poll */
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
//
|
|
||||||
|
|
||||||
/* Enable/disable device */
|
/* Enable/disable device */
|
||||||
|
|
||||||
void dcx_enbdis (int32 dis)
|
void dcx_enbdis (int32 dis)
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
dz DZ11 terminal multiplexor
|
dz DZ11 terminal multiplexor
|
||||||
|
|
||||||
29-Dec-08 RMS Added MTAB_NC to SET LOG command (Walter Mueller)
|
29-Dec-08 RMS Added MTAB_NC to SET LOG command (Walter Mueller)
|
||||||
24-Nov-08 JDB [serial] Added serial port support
|
|
||||||
19-Nov-08 RMS Revised for common TMXR show routines
|
19-Nov-08 RMS Revised for common TMXR show routines
|
||||||
18-Jun-07 RMS Added UNIT_IDLE flag
|
18-Jun-07 RMS Added UNIT_IDLE flag
|
||||||
29-Oct-06 RMS Synced poll and clock
|
29-Oct-06 RMS Synced poll and clock
|
||||||
|
@ -166,12 +165,16 @@ TMXR dz_desc = { DZ_MUXES * DZ_LINES, 0, 0, dz_ldsc }; /* mux descriptor */
|
||||||
#define DBG_INT 0x0002 /* display transfer requests */
|
#define DBG_INT 0x0002 /* display transfer requests */
|
||||||
#define DBG_XMT TMXR_DBG_XMT /* display Transmitted Data */
|
#define DBG_XMT TMXR_DBG_XMT /* display Transmitted Data */
|
||||||
#define DBG_RCV TMXR_DBG_RCV /* display Received Data */
|
#define DBG_RCV TMXR_DBG_RCV /* display Received Data */
|
||||||
|
#define DBG_TRC TMXR_DBG_TRC /* display trace routine calls */
|
||||||
|
#define DBG_ASY TMXR_DBG_ASY /* display Asynchronous Activities */
|
||||||
|
|
||||||
DEBTAB dz_debug[] = {
|
DEBTAB dz_debug[] = {
|
||||||
{"REG", DBG_REG},
|
{"REG", DBG_REG},
|
||||||
{"INT", DBG_INT},
|
{"INT", DBG_INT},
|
||||||
{"XMT", DBG_XMT},
|
{"XMT", DBG_XMT},
|
||||||
{"RCV", DBG_RCV},
|
{"RCV", DBG_RCV},
|
||||||
|
{"TRC", DBG_TRC},
|
||||||
|
{"ASY", DBG_ASY},
|
||||||
{0}
|
{0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -232,12 +235,8 @@ MTAB dz_mod[] = {
|
||||||
{ TT_MODE, TT_MODE_7B, "7b", "7B", NULL },
|
{ TT_MODE, TT_MODE_7B, "7b", "7B", NULL },
|
||||||
{ TT_MODE, TT_MODE_8B, "8b", "8B", NULL },
|
{ TT_MODE, TT_MODE_8B, "8b", "8B", NULL },
|
||||||
{ TT_MODE, TT_MODE_7P, "7p", "7P", NULL },
|
{ TT_MODE, TT_MODE_7P, "7p", "7P", NULL },
|
||||||
//
|
|
||||||
{ MTAB_XTD | MTAB_VDV | MTAB_NC, ':', NULL, "CONNECT",
|
|
||||||
&tmxr_attach_line, NULL, &dz_desc },
|
|
||||||
{ MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT",
|
{ MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT",
|
||||||
&tmxr_detach_line, NULL, &dz_desc },
|
&tmxr_dscln, NULL, &dz_desc },
|
||||||
//
|
|
||||||
{ UNIT_ATT, UNIT_ATT, "summary", NULL,
|
{ UNIT_ATT, UNIT_ATT, "summary", NULL,
|
||||||
NULL, &tmxr_show_summ, (void *) &dz_desc },
|
NULL, &tmxr_show_summ, (void *) &dz_desc },
|
||||||
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL,
|
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL,
|
||||||
|
@ -268,7 +267,7 @@ DEVICE dz_dev = {
|
||||||
1, DEV_RDX, 8, 1, DEV_RDX, 8,
|
1, DEV_RDX, 8, 1, DEV_RDX, 8,
|
||||||
&tmxr_ex, &tmxr_dep, &dz_reset,
|
&tmxr_ex, &tmxr_dep, &dz_reset,
|
||||||
NULL, &dz_attach, &dz_detach,
|
NULL, &dz_attach, &dz_detach,
|
||||||
&dz_dib, DEV_FLTA | DEV_DISABLE | DEV_NET | DEV_UBUS | DEV_QBUS | DEV_DEBUG,
|
&dz_dib, DEV_FLTA | DEV_DISABLE | DEV_UBUS | DEV_QBUS | DEV_DEBUG,
|
||||||
0, dz_debug
|
0, dz_debug
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -296,12 +296,16 @@ static TMLX vh_parm[VH_MUXES * VH_LINES] = { { 0 } };
|
||||||
#define DBG_INT 0x0002 /* display transfer requests */
|
#define DBG_INT 0x0002 /* display transfer requests */
|
||||||
#define DBG_XMT TMXR_DBG_XMT /* display Transmitted Data */
|
#define DBG_XMT TMXR_DBG_XMT /* display Transmitted Data */
|
||||||
#define DBG_RCV TMXR_DBG_RCV /* display Received Data */
|
#define DBG_RCV TMXR_DBG_RCV /* display Received Data */
|
||||||
|
#define DBG_TRC TMXR_DBG_TRC /* display trace routine calls */
|
||||||
|
#define DBG_ASY TMXR_DBG_ASY /* display Asynchronous Activities */
|
||||||
|
|
||||||
DEBTAB vh_debug[] = {
|
DEBTAB vh_debug[] = {
|
||||||
{"REG", DBG_REG},
|
{"REG", DBG_REG},
|
||||||
{"INT", DBG_INT},
|
{"INT", DBG_INT},
|
||||||
{"XMT", DBG_XMT},
|
{"XMT", DBG_XMT},
|
||||||
{"RCV", DBG_RCV},
|
{"RCV", DBG_RCV},
|
||||||
|
{"TRC", DBG_TRC},
|
||||||
|
{"ASY", DBG_ASY},
|
||||||
{0}
|
{0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -407,7 +411,7 @@ DEVICE vh_dev = {
|
||||||
&vh_attach, /* attach routine */
|
&vh_attach, /* attach routine */
|
||||||
&vh_detach, /* detach routine */
|
&vh_detach, /* detach routine */
|
||||||
(void *)&vh_dib,/* context */
|
(void *)&vh_dib,/* context */
|
||||||
DEV_FLTA | DEV_DISABLE | DEV_DIS |DEV_NET | DEV_QBUS | DEV_UBUS | DEV_DEBUG, /* flags */
|
DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_QBUS | DEV_UBUS | DEV_DEBUG, /* flags */
|
||||||
0, vh_debug
|
0, vh_debug
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
UsePrecompiledHeader="0"
|
UsePrecompiledHeader="0"
|
||||||
WarningLevel="3"
|
WarningLevel="3"
|
||||||
Detect64BitPortabilityProblems="false"
|
Detect64BitPortabilityProblems="false"
|
||||||
DebugInformationFormat="4"
|
DebugInformationFormat="3"
|
||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCManagedResourceCompilerTool"
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
|
184
scp.c
184
scp.c
|
@ -57,7 +57,6 @@
|
||||||
08-Feb-09 RMS Fixed warnings in help printouts
|
08-Feb-09 RMS Fixed warnings in help printouts
|
||||||
29-Dec-08 RMS Fixed implementation of MTAB_NC
|
29-Dec-08 RMS Fixed implementation of MTAB_NC
|
||||||
24-Nov-08 RMS Revised RESTORE unit logic for consistency
|
24-Nov-08 RMS Revised RESTORE unit logic for consistency
|
||||||
21-Oct-08 JDB [serial] Added sim_unit_ref global to indicate type of reference
|
|
||||||
05-Sep-08 JDB "detach_all" ignores error status returns if shutting down
|
05-Sep-08 JDB "detach_all" ignores error status returns if shutting down
|
||||||
17-Aug-08 RMS Revert RUN/BOOT to standard, rather than powerup, reset
|
17-Aug-08 RMS Revert RUN/BOOT to standard, rather than powerup, reset
|
||||||
25-Jul-08 JDB DO cmd missing params now default to null string
|
25-Jul-08 JDB DO cmd missing params now default to null string
|
||||||
|
@ -377,7 +376,7 @@ char *get_sim_sw (char *cptr);
|
||||||
t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr);
|
t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr);
|
||||||
t_value get_rval (REG *rptr, uint32 idx);
|
t_value get_rval (REG *rptr, uint32 idx);
|
||||||
void put_rval (REG *rptr, uint32 idx, t_value val);
|
void put_rval (REG *rptr, uint32 idx, t_value val);
|
||||||
t_value strtotv (char *inptr, char **endptr, uint32 radix);
|
t_value strtotv (const char *inptr, char **endptr, uint32 radix);
|
||||||
void fprint_help (FILE *st);
|
void fprint_help (FILE *st);
|
||||||
void fprint_stopped (FILE *st, t_stat r);
|
void fprint_stopped (FILE *st, t_stat r);
|
||||||
void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr);
|
void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr);
|
||||||
|
@ -420,15 +419,16 @@ void run_cmd_message (const char *unechod_cmdline, t_stat r);
|
||||||
|
|
||||||
/* Global data */
|
/* Global data */
|
||||||
|
|
||||||
UNITREF sim_unit_ref;
|
|
||||||
DEVICE *sim_dflt_dev = NULL;
|
DEVICE *sim_dflt_dev = NULL;
|
||||||
UNIT *sim_clock_queue = NULL;
|
UNIT *sim_clock_queue = QUEUE_LIST_END;
|
||||||
int32 sim_interval = 0;
|
int32 sim_interval = 0;
|
||||||
int32 sim_switches = 0;
|
int32 sim_switches = 0;
|
||||||
FILE *sim_ofile = NULL;
|
FILE *sim_ofile = NULL;
|
||||||
SCHTAB *sim_schptr = FALSE;
|
SCHTAB *sim_schptr = FALSE;
|
||||||
DEVICE *sim_dfdev = NULL;
|
DEVICE *sim_dfdev = NULL;
|
||||||
UNIT *sim_dfunit = NULL;
|
UNIT *sim_dfunit = NULL;
|
||||||
|
DEVICE **sim_internal_devices = NULL;
|
||||||
|
uint32 sim_internal_device_count = 0;
|
||||||
int32 sim_opt_out = 0;
|
int32 sim_opt_out = 0;
|
||||||
int32 sim_is_running = 0;
|
int32 sim_is_running = 0;
|
||||||
uint32 sim_brk_summ = 0;
|
uint32 sim_brk_summ = 0;
|
||||||
|
@ -635,6 +635,10 @@ static CTAB cmd_table[] = {
|
||||||
"set console TELNET=UNBUFFERED\n"
|
"set console TELNET=UNBUFFERED\n"
|
||||||
" disables console telnet buffering\n"
|
" disables console telnet buffering\n"
|
||||||
"set console NOTELNET disable console telnet\n"
|
"set console NOTELNET disable console telnet\n"
|
||||||
|
"set console SERIAL=serialport[;config]\n"
|
||||||
|
" specify console serial port and optionally\n"
|
||||||
|
" the port config (i.e. ;9600-8n1)\n"
|
||||||
|
"set console NOSERIAL disable console serial session\n"
|
||||||
"set console LOG=log_file enable console logging to the\n"
|
"set console LOG=log_file enable console logging to the\n"
|
||||||
" specified destination {STDOUT,DEBUG or filename)\n"
|
" specified destination {STDOUT,DEBUG or filename)\n"
|
||||||
"set console NOLOG disable console logging\n"
|
"set console NOLOG disable console logging\n"
|
||||||
|
@ -801,7 +805,7 @@ stop_cpu = 0;
|
||||||
sim_interval = 0;
|
sim_interval = 0;
|
||||||
sim_time = sim_rtime = 0;
|
sim_time = sim_rtime = 0;
|
||||||
noqueue_time = 0;
|
noqueue_time = 0;
|
||||||
sim_clock_queue = NULL;
|
sim_clock_queue = QUEUE_LIST_END;
|
||||||
sim_is_running = 0;
|
sim_is_running = 0;
|
||||||
sim_log = NULL;
|
sim_log = NULL;
|
||||||
if (sim_emax <= 0)
|
if (sim_emax <= 0)
|
||||||
|
@ -2051,6 +2055,8 @@ static SHTAB show_glob_tab[] = {
|
||||||
{ "ASYNCH", &sim_show_asynch, 0 },
|
{ "ASYNCH", &sim_show_asynch, 0 },
|
||||||
{ "ETHERNET", ð_show_devices, 0 },
|
{ "ETHERNET", ð_show_devices, 0 },
|
||||||
{ "SERIAL", &sim_show_serial, 0 },
|
{ "SERIAL", &sim_show_serial, 0 },
|
||||||
|
{ "MULTIPLEXER", &tmxr_show_open_devices, 0 },
|
||||||
|
{ "MUX", &tmxr_show_open_devices, 0 },
|
||||||
{ "ON", &show_on, 0 },
|
{ "ON", &show_on, 0 },
|
||||||
{ NULL, NULL, 0 }
|
{ NULL, NULL, 0 }
|
||||||
};
|
};
|
||||||
|
@ -2286,7 +2292,7 @@ int32 accum;
|
||||||
|
|
||||||
if (cptr && (*cptr != 0))
|
if (cptr && (*cptr != 0))
|
||||||
return SCPE_2MARG;
|
return SCPE_2MARG;
|
||||||
if (sim_clock_queue == NULL) {
|
if (sim_clock_queue == QUEUE_LIST_END) {
|
||||||
fprintf (st, "%s event queue empty, time = %.0f\n",
|
fprintf (st, "%s event queue empty, time = %.0f\n",
|
||||||
sim_name, sim_time);
|
sim_name, sim_time);
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
|
@ -2294,7 +2300,7 @@ if (sim_clock_queue == NULL) {
|
||||||
fprintf (st, "%s event queue status, time = %.0f\n",
|
fprintf (st, "%s event queue status, time = %.0f\n",
|
||||||
sim_name, sim_time);
|
sim_name, sim_time);
|
||||||
accum = 0;
|
accum = 0;
|
||||||
for (uptr = sim_clock_queue; uptr != NULL; uptr = uptr->next) {
|
for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next) {
|
||||||
if (uptr == &sim_step_unit)
|
if (uptr == &sim_step_unit)
|
||||||
fprintf (st, " Step timer");
|
fprintf (st, " Step timer");
|
||||||
else if ((dptr = find_dev_from_unit (uptr)) != NULL) {
|
else if ((dptr = find_dev_from_unit (uptr)) != NULL) {
|
||||||
|
@ -2309,10 +2315,10 @@ for (uptr = sim_clock_queue; uptr != NULL; uptr = uptr->next) {
|
||||||
#if defined (SIM_ASYNCH_IO)
|
#if defined (SIM_ASYNCH_IO)
|
||||||
pthread_mutex_lock (&sim_asynch_lock);
|
pthread_mutex_lock (&sim_asynch_lock);
|
||||||
fprintf (st, "asynchronous pending event queue\n");
|
fprintf (st, "asynchronous pending event queue\n");
|
||||||
if (sim_asynch_queue == AIO_LIST_END)
|
if (sim_asynch_queue == QUEUE_LIST_END)
|
||||||
fprintf (st, "Empty\n");
|
fprintf (st, "Empty\n");
|
||||||
else {
|
else {
|
||||||
for (uptr = sim_asynch_queue; uptr != AIO_LIST_END; uptr = uptr->a_next) {
|
for (uptr = sim_asynch_queue; uptr != QUEUE_LIST_END; uptr = uptr->a_next) {
|
||||||
if ((dptr = find_dev_from_unit (uptr)) != NULL) {
|
if ((dptr = find_dev_from_unit (uptr)) != NULL) {
|
||||||
fprintf (st, " %s", sim_dname (dptr));
|
fprintf (st, " %s", sim_dname (dptr));
|
||||||
if (dptr->numunits > 1) fprintf (st, " unit %d",
|
if (dptr->numunits > 1) fprintf (st, " unit %d",
|
||||||
|
@ -2418,6 +2424,8 @@ if (cptr && (*cptr != 0)) /* now eol? */
|
||||||
return SCPE_2MARG;
|
return SCPE_2MARG;
|
||||||
for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
|
for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
|
||||||
show_dev_modifiers (st, dptr, NULL, flag, cptr);
|
show_dev_modifiers (st, dptr, NULL, flag, cptr);
|
||||||
|
for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i)
|
||||||
|
show_dev_modifiers (st, dptr, NULL, flag, cptr);
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2508,6 +2516,8 @@ if (cptr && (*cptr != 0)) /* now eol? */
|
||||||
return SCPE_2MARG;
|
return SCPE_2MARG;
|
||||||
for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
|
for (i = 0; (dptr = sim_devices[i]) != NULL; i++)
|
||||||
show_dev_show_commands (st, dptr, NULL, flag, cptr);
|
show_dev_show_commands (st, dptr, NULL, flag, cptr);
|
||||||
|
for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i)
|
||||||
|
show_dev_show_commands (st, dptr, NULL, flag, cptr);
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2685,6 +2695,13 @@ for (i = start; (dptr = sim_devices[i]) != NULL; i++) {
|
||||||
return reason;
|
return reason;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
|
||||||
|
if (dptr->reset != NULL) {
|
||||||
|
reason = dptr->reset (dptr);
|
||||||
|
if (reason != SCPE_OK)
|
||||||
|
return reason;
|
||||||
|
}
|
||||||
|
}
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2756,7 +2773,8 @@ if (dptr == NULL) /* found dev? */
|
||||||
return SCPE_NXDEV;
|
return SCPE_NXDEV;
|
||||||
if (uptr == NULL) /* valid unit? */
|
if (uptr == NULL) /* valid unit? */
|
||||||
return SCPE_NXUN;
|
return SCPE_NXUN;
|
||||||
if (uptr->flags & UNIT_ATT) { /* already attached? */
|
if ((uptr->flags & UNIT_ATT) && /* already attached? */
|
||||||
|
!(uptr->flags & UNIT_ATTMULT)) { /* and only single attachable */
|
||||||
r = scp_detach_unit (dptr, uptr); /* detach it */
|
r = scp_detach_unit (dptr, uptr); /* detach it */
|
||||||
if (r != SCPE_OK) /* error? */
|
if (r != SCPE_OK) /* error? */
|
||||||
return r;
|
return r;
|
||||||
|
@ -2896,7 +2914,6 @@ DEVICE *dptr;
|
||||||
UNIT *uptr;
|
UNIT *uptr;
|
||||||
t_stat r;
|
t_stat r;
|
||||||
|
|
||||||
sim_unit_ref = ref_unit_all; /* we will reference all units */
|
|
||||||
if ((start < 0) || (start > 1))
|
if ((start < 0) || (start > 1))
|
||||||
return SCPE_IERR;
|
return SCPE_IERR;
|
||||||
for (i = start; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */
|
for (i = start; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */
|
||||||
|
@ -2915,6 +2932,7 @@ for (i = start; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Call device-specific or file-oriented detach unit routine */
|
/* Call device-specific or file-oriented detach unit routine */
|
||||||
|
|
||||||
t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr)
|
t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr)
|
||||||
|
@ -3040,6 +3058,19 @@ char *sim_dname (DEVICE *dptr)
|
||||||
return (dptr->lname? dptr->lname: dptr->name);
|
return (dptr->lname? dptr->lname: dptr->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get unit display name */
|
||||||
|
|
||||||
|
char *sim_uname (UNIT *uptr)
|
||||||
|
{
|
||||||
|
DEVICE *d = find_dev_from_unit(uptr);
|
||||||
|
static AIO_TLS char uname[CBUFSIZE];
|
||||||
|
|
||||||
|
if (d->numunits == 1)
|
||||||
|
return sim_dname (d);
|
||||||
|
sprintf (uname, "%s%d", sim_dname (d), (int)(uptr-d->units));
|
||||||
|
return uname;
|
||||||
|
}
|
||||||
|
|
||||||
/* Save command
|
/* Save command
|
||||||
|
|
||||||
sa[ve] filename save state to specified file
|
sa[ve] filename save state to specified file
|
||||||
|
@ -3216,8 +3247,6 @@ t_bool force_restore = sim_switches & SWMASK ('F');
|
||||||
#define READ_I(xx) if (sim_fread (&xx, sizeof (xx), 1, rfile) == 0) \
|
#define READ_I(xx) if (sim_fread (&xx, sizeof (xx), 1, rfile) == 0) \
|
||||||
return SCPE_IOERR;
|
return SCPE_IOERR;
|
||||||
|
|
||||||
sim_unit_ref = ref_unit_all; /* we will reference all units */
|
|
||||||
|
|
||||||
fstat (fileno (rfile), &rstat);
|
fstat (fileno (rfile), &rstat);
|
||||||
READ_S (buf); /* [V2.5+] read version */
|
READ_S (buf); /* [V2.5+] read version */
|
||||||
v35 = v32 = FALSE;
|
v35 = v32 = FALSE;
|
||||||
|
@ -3612,7 +3641,7 @@ for (i = 1; (dptr = sim_devices[i]) != NULL; i++) { /* flush attached files
|
||||||
sim_cancel (&sim_step_unit); /* cancel step timer */
|
sim_cancel (&sim_step_unit); /* cancel step timer */
|
||||||
sim_throt_cancel (); /* cancel throttle */
|
sim_throt_cancel (); /* cancel throttle */
|
||||||
AIO_UPDATE_QUEUE;
|
AIO_UPDATE_QUEUE;
|
||||||
if (sim_clock_queue != NULL) { /* update sim time */
|
if (sim_clock_queue != QUEUE_LIST_END) { /* update sim time */
|
||||||
UPDATE_SIM_TIME (sim_clock_queue->time);
|
UPDATE_SIM_TIME (sim_clock_queue->time);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -3643,10 +3672,15 @@ if (sim_log) /* log if enabled */
|
||||||
|
|
||||||
t_stat run_boot_prep (void)
|
t_stat run_boot_prep (void)
|
||||||
{
|
{
|
||||||
|
UNIT *uptr;
|
||||||
|
|
||||||
sim_interval = 0; /* reset queue */
|
sim_interval = 0; /* reset queue */
|
||||||
sim_time = sim_rtime = 0;
|
sim_time = sim_rtime = 0;
|
||||||
noqueue_time = 0;
|
noqueue_time = 0;
|
||||||
sim_clock_queue = NULL;
|
for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = sim_clock_queue) {
|
||||||
|
sim_clock_queue = uptr->next;
|
||||||
|
uptr->next = NULL;
|
||||||
|
}
|
||||||
return reset_all (0);
|
return reset_all (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4605,6 +4639,12 @@ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
|
||||||
(strcmp (cptr, dptr->lname) == 0)))
|
(strcmp (cptr, dptr->lname) == 0)))
|
||||||
return dptr;
|
return dptr;
|
||||||
}
|
}
|
||||||
|
for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
|
||||||
|
if ((strcmp (cptr, dptr->name) == 0) ||
|
||||||
|
(dptr->lname &&
|
||||||
|
(strcmp (cptr, dptr->lname) == 0)))
|
||||||
|
return dptr;
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4617,8 +4657,6 @@ return NULL;
|
||||||
result = pointer to device (null if no dev)
|
result = pointer to device (null if no dev)
|
||||||
*iptr = pointer to unit (null if nx unit)
|
*iptr = pointer to unit (null if nx unit)
|
||||||
|
|
||||||
The "sim_unit_ref" global is set to the type of reference specified by cptr
|
|
||||||
(device or unit).
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
DEVICE *find_unit (char *cptr, UNIT **uptr)
|
DEVICE *find_unit (char *cptr, UNIT **uptr)
|
||||||
|
@ -4628,13 +4666,11 @@ char *nptr, *tptr;
|
||||||
t_stat r;
|
t_stat r;
|
||||||
DEVICE *dptr;
|
DEVICE *dptr;
|
||||||
|
|
||||||
sim_unit_ref = ref_unit; /* assume unit reference */
|
|
||||||
if (uptr == NULL) /* arg error? */
|
if (uptr == NULL) /* arg error? */
|
||||||
return NULL;
|
return NULL;
|
||||||
if ((dptr = find_dev (cptr))) { /* exact match? */
|
if ((dptr = find_dev (cptr))) { /* exact match? */
|
||||||
if (qdisable (dptr)) /* disabled? */
|
if (qdisable (dptr)) /* disabled? */
|
||||||
return NULL;
|
return NULL;
|
||||||
sim_unit_ref = ref_dev; /* flag device reference */
|
|
||||||
*uptr = dptr->units; /* unit 0 */
|
*uptr = dptr->units; /* unit 0 */
|
||||||
return dptr;
|
return dptr;
|
||||||
}
|
}
|
||||||
|
@ -4660,6 +4696,29 @@ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* base + unit#? */
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* sim_register_internal_device Add device to internal device list
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
dptr = pointer to device
|
||||||
|
*/
|
||||||
|
|
||||||
|
t_stat sim_register_internal_device (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
uint32 i;
|
||||||
|
|
||||||
|
for (i = 0; (sim_devices[i] != NULL); ++i)
|
||||||
|
if (sim_devices[i] == dptr)
|
||||||
|
return SCPE_OK;
|
||||||
|
for (i = 0; i < sim_internal_device_count; ++i)
|
||||||
|
if (sim_internal_devices[i] == dptr)
|
||||||
|
return SCPE_OK;
|
||||||
|
++sim_internal_device_count;
|
||||||
|
sim_internal_devices = realloc(sim_internal_devices, (sim_internal_device_count+1)*sizeof(*sim_internal_devices));
|
||||||
|
sim_internal_devices[sim_internal_device_count-1] = dptr;
|
||||||
|
sim_internal_devices[sim_internal_device_count] = NULL;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/* Find_dev_from_unit find device for unit
|
/* Find_dev_from_unit find device for unit
|
||||||
|
|
||||||
Inputs:
|
Inputs:
|
||||||
|
@ -4681,6 +4740,13 @@ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
|
||||||
return dptr;
|
return dptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (i = 0; i<sim_internal_device_count; ++i) {
|
||||||
|
dptr = sim_internal_devices[i];
|
||||||
|
for (j = 0; j < dptr->numunits; j++) {
|
||||||
|
if (uptr == (dptr->units + j))
|
||||||
|
return dptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5028,13 +5094,13 @@ return 0;
|
||||||
On an error, the endptr will equal the inptr.
|
On an error, the endptr will equal the inptr.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
t_value strtotv (char *inptr, char **endptr, uint32 radix)
|
t_value strtotv (const char *inptr, char **endptr, uint32 radix)
|
||||||
{
|
{
|
||||||
int32 nodigit;
|
int32 nodigit;
|
||||||
t_value val;
|
t_value val;
|
||||||
uint32 c, digit;
|
uint32 c, digit;
|
||||||
|
|
||||||
*endptr = inptr; /* assume fails */
|
*endptr = (char *)inptr; /* assume fails */
|
||||||
if ((radix < 2) || (radix > 36))
|
if ((radix < 2) || (radix > 36))
|
||||||
return 0;
|
return 0;
|
||||||
while (isspace (*inptr)) /* bypass white space */
|
while (isspace (*inptr)) /* bypass white space */
|
||||||
|
@ -5056,7 +5122,7 @@ for (c = *inptr; isalnum(c); c = *++inptr) { /* loop through char */
|
||||||
}
|
}
|
||||||
if (nodigit) /* no digits? */
|
if (nodigit) /* no digits? */
|
||||||
return 0;
|
return 0;
|
||||||
*endptr = inptr; /* result pointer */
|
*endptr = (char *)inptr; /* result pointer */
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5110,6 +5176,7 @@ return SCPE_OK;
|
||||||
/* Event queue package
|
/* Event queue package
|
||||||
|
|
||||||
sim_activate add entry to event queue
|
sim_activate add entry to event queue
|
||||||
|
sim_activate_after add entry to event queue after a specified amount of wall time
|
||||||
sim_cancel remove entry from event queue
|
sim_cancel remove entry from event queue
|
||||||
sim_process_event process entries on event queue
|
sim_process_event process entries on event queue
|
||||||
sim_is_active see if entry is on event queue
|
sim_is_active see if entry is on event queue
|
||||||
|
@ -5145,7 +5212,7 @@ t_stat reason;
|
||||||
if (stop_cpu) /* stop CPU? */
|
if (stop_cpu) /* stop CPU? */
|
||||||
return SCPE_STOP;
|
return SCPE_STOP;
|
||||||
AIO_UPDATE_QUEUE;
|
AIO_UPDATE_QUEUE;
|
||||||
if (sim_clock_queue == NULL) { /* queue empty? */
|
if (sim_clock_queue == QUEUE_LIST_END) { /* queue empty? */
|
||||||
UPDATE_SIM_TIME (noqueue_time); /* update sim time */
|
UPDATE_SIM_TIME (noqueue_time); /* update sim time */
|
||||||
sim_interval = noqueue_time = NOQUEUE_WAIT; /* flag queue empty */
|
sim_interval = noqueue_time = NOQUEUE_WAIT; /* flag queue empty */
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
|
@ -5156,7 +5223,7 @@ do {
|
||||||
sim_clock_queue = uptr->next; /* remove first */
|
sim_clock_queue = uptr->next; /* remove first */
|
||||||
uptr->next = NULL; /* hygiene */
|
uptr->next = NULL; /* hygiene */
|
||||||
uptr->time = 0;
|
uptr->time = 0;
|
||||||
if (sim_clock_queue != NULL)
|
if (sim_clock_queue != QUEUE_LIST_END)
|
||||||
sim_interval = sim_clock_queue->time;
|
sim_interval = sim_clock_queue->time;
|
||||||
else sim_interval = noqueue_time = NOQUEUE_WAIT;
|
else sim_interval = noqueue_time = NOQUEUE_WAIT;
|
||||||
if (uptr->action != NULL)
|
if (uptr->action != NULL)
|
||||||
|
@ -5180,13 +5247,18 @@ return reason;
|
||||||
|
|
||||||
t_stat sim_activate (UNIT *uptr, int32 event_time)
|
t_stat sim_activate (UNIT *uptr, int32 event_time)
|
||||||
{
|
{
|
||||||
|
return _sim_activate (uptr, event_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat _sim_activate (UNIT *uptr, int32 event_time)
|
||||||
|
{
|
||||||
UNIT *cptr, *prvptr;
|
UNIT *cptr, *prvptr;
|
||||||
int32 accum;
|
int32 accum;
|
||||||
|
|
||||||
AIO_ACTIVATE (sim_activate, uptr, event_time);
|
AIO_ACTIVATE (_sim_activate, uptr, event_time);
|
||||||
if (sim_is_active (uptr)) /* already active? */
|
if (sim_is_active (uptr)) /* already active? */
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
if (sim_clock_queue == NULL) {
|
if (sim_clock_queue == QUEUE_LIST_END) {
|
||||||
UPDATE_SIM_TIME (noqueue_time);
|
UPDATE_SIM_TIME (noqueue_time);
|
||||||
}
|
}
|
||||||
else { /* update sim time */
|
else { /* update sim time */
|
||||||
|
@ -5195,7 +5267,7 @@ else { /* update sim time */
|
||||||
|
|
||||||
prvptr = NULL;
|
prvptr = NULL;
|
||||||
accum = 0;
|
accum = 0;
|
||||||
for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr->next) {
|
for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
|
||||||
if (event_time < (accum + cptr->time))
|
if (event_time < (accum + cptr->time))
|
||||||
break;
|
break;
|
||||||
accum = accum + cptr->time;
|
accum = accum + cptr->time;
|
||||||
|
@ -5210,7 +5282,7 @@ else {
|
||||||
prvptr->next = uptr;
|
prvptr->next = uptr;
|
||||||
}
|
}
|
||||||
uptr->time = event_time - accum;
|
uptr->time = event_time - accum;
|
||||||
if (cptr != NULL)
|
if (cptr != QUEUE_LIST_END)
|
||||||
cptr->time = cptr->time - uptr->time;
|
cptr->time = cptr->time - uptr->time;
|
||||||
sim_interval = sim_clock_queue->time;
|
sim_interval = sim_clock_queue->time;
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
|
@ -5256,6 +5328,28 @@ else
|
||||||
return sim_activate (uptr, urtime-rtimenow);
|
return sim_activate (uptr, urtime-rtimenow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* sim_activate_after - activate (queue) event
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
uptr = pointer to unit
|
||||||
|
usec_delay = relative timeout (in microseconds)
|
||||||
|
Outputs:
|
||||||
|
reason = result (SCPE_OK if ok)
|
||||||
|
*/
|
||||||
|
|
||||||
|
t_stat sim_activate_after (UNIT *uptr, int32 event_time)
|
||||||
|
{
|
||||||
|
return _sim_activate_after (uptr, event_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat _sim_activate_after (UNIT *uptr, int32 usec_delay)
|
||||||
|
{
|
||||||
|
if (sim_is_active_bool (uptr)) /* already active? */
|
||||||
|
return SCPE_OK;
|
||||||
|
AIO_ACTIVATE (_sim_activate_after, uptr, usec_delay);
|
||||||
|
return sim_timer_activate_after (uptr, usec_delay);
|
||||||
|
}
|
||||||
|
|
||||||
/* sim_cancel - cancel (dequeue) event
|
/* sim_cancel - cancel (dequeue) event
|
||||||
|
|
||||||
Inputs:
|
Inputs:
|
||||||
|
@ -5270,30 +5364,43 @@ t_stat sim_cancel (UNIT *uptr)
|
||||||
UNIT *cptr, *nptr;
|
UNIT *cptr, *nptr;
|
||||||
|
|
||||||
AIO_VALIDATE;
|
AIO_VALIDATE;
|
||||||
if (sim_clock_queue == NULL)
|
if (sim_clock_queue == QUEUE_LIST_END)
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
UPDATE_SIM_TIME (sim_clock_queue->time); /* update sim time */
|
UPDATE_SIM_TIME (sim_clock_queue->time); /* update sim time */
|
||||||
nptr = NULL;
|
nptr = QUEUE_LIST_END;
|
||||||
if (sim_clock_queue == uptr)
|
if (sim_clock_queue == uptr)
|
||||||
nptr = sim_clock_queue = uptr->next;
|
nptr = sim_clock_queue = uptr->next;
|
||||||
else {
|
else {
|
||||||
for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr->next) {
|
for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
|
||||||
if (cptr->next == uptr) {
|
if (cptr->next == uptr) {
|
||||||
nptr = cptr->next = uptr->next;
|
nptr = cptr->next = uptr->next;
|
||||||
break; /* end queue scan */
|
break; /* end queue scan */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nptr != NULL)
|
if (nptr != QUEUE_LIST_END)
|
||||||
nptr->time = nptr->time + uptr->time;
|
nptr->time = nptr->time + uptr->time;
|
||||||
uptr->next = NULL; /* hygiene */
|
uptr->next = NULL; /* hygiene */
|
||||||
uptr->time = 0;
|
uptr->time = 0;
|
||||||
if (sim_clock_queue != NULL)
|
if (sim_clock_queue != QUEUE_LIST_END)
|
||||||
sim_interval = sim_clock_queue->time;
|
sim_interval = sim_clock_queue->time;
|
||||||
else sim_interval = noqueue_time = NOQUEUE_WAIT;
|
else sim_interval = noqueue_time = NOQUEUE_WAIT;
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* sim_is_active_bool - test for entry in queue, return activation time
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
uptr = pointer to unit
|
||||||
|
Outputs:
|
||||||
|
result = TRUE if active FALSE if inactive
|
||||||
|
*/
|
||||||
|
|
||||||
|
t_bool sim_is_active_bool (UNIT *uptr)
|
||||||
|
{
|
||||||
|
return (uptr->next != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/* sim_is_active - test for entry in queue, return activation time
|
/* sim_is_active - test for entry in queue, return activation time
|
||||||
|
|
||||||
Inputs:
|
Inputs:
|
||||||
|
@ -5305,11 +5412,10 @@ return SCPE_OK;
|
||||||
int32 sim_is_active (UNIT *uptr)
|
int32 sim_is_active (UNIT *uptr)
|
||||||
{
|
{
|
||||||
UNIT *cptr;
|
UNIT *cptr;
|
||||||
int32 accum;
|
int32 accum = 0;
|
||||||
|
|
||||||
AIO_VALIDATE;
|
AIO_VALIDATE;
|
||||||
accum = 0;
|
for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
|
||||||
for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr->next) {
|
|
||||||
if (cptr == sim_clock_queue) {
|
if (cptr == sim_clock_queue) {
|
||||||
if (sim_interval > 0)
|
if (sim_interval > 0)
|
||||||
accum = accum + sim_interval;
|
accum = accum + sim_interval;
|
||||||
|
@ -5331,7 +5437,7 @@ return 0;
|
||||||
|
|
||||||
double sim_gtime (void)
|
double sim_gtime (void)
|
||||||
{
|
{
|
||||||
if (sim_clock_queue == NULL) {
|
if (sim_clock_queue == QUEUE_LIST_END) {
|
||||||
UPDATE_SIM_TIME (noqueue_time);
|
UPDATE_SIM_TIME (noqueue_time);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -5342,7 +5448,7 @@ return sim_time;
|
||||||
|
|
||||||
uint32 sim_grtime (void)
|
uint32 sim_grtime (void)
|
||||||
{
|
{
|
||||||
if (sim_clock_queue == NULL) {
|
if (sim_clock_queue == QUEUE_LIST_END) {
|
||||||
UPDATE_SIM_TIME (noqueue_time);
|
UPDATE_SIM_TIME (noqueue_time);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -5364,7 +5470,7 @@ int32 cnt;
|
||||||
UNIT *uptr;
|
UNIT *uptr;
|
||||||
|
|
||||||
cnt = 0;
|
cnt = 0;
|
||||||
for (uptr = sim_clock_queue; uptr != NULL; uptr = uptr->next)
|
for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next)
|
||||||
cnt++;
|
cnt++;
|
||||||
return cnt;
|
return cnt;
|
||||||
}
|
}
|
||||||
|
|
13
scp.h
13
scp.h
|
@ -24,7 +24,6 @@
|
||||||
in this Software without prior written authorization from Robert M Supnik.
|
in this Software without prior written authorization from Robert M Supnik.
|
||||||
|
|
||||||
05-Dec-10 MP Added macro invocation of sim_debug
|
05-Dec-10 MP Added macro invocation of sim_debug
|
||||||
07-Jan-09 JDB Added UNITREF typedef
|
|
||||||
09-Aug-06 JDB Added assign_device and deassign_device
|
09-Aug-06 JDB Added assign_device and deassign_device
|
||||||
14-Jul-06 RMS Added sim_activate_abs
|
14-Jul-06 RMS Added sim_activate_abs
|
||||||
06-Jan-06 RMS Added fprint_stopped_gen
|
06-Jan-06 RMS Added fprint_stopped_gen
|
||||||
|
@ -53,10 +52,6 @@
|
||||||
#define CMD_OPT_SCH 004 /* search */
|
#define CMD_OPT_SCH 004 /* search */
|
||||||
#define CMD_OPT_DFT 010 /* defaults */
|
#define CMD_OPT_DFT 010 /* defaults */
|
||||||
|
|
||||||
/* unit references */
|
|
||||||
|
|
||||||
typedef enum { ref_dev, ref_unit, ref_unit_all } UNITREF;
|
|
||||||
|
|
||||||
/* Command processors */
|
/* Command processors */
|
||||||
|
|
||||||
t_stat reset_cmd (int32 flag, char *ptr);
|
t_stat reset_cmd (int32 flag, char *ptr);
|
||||||
|
@ -90,9 +85,13 @@ t_stat echo_cmd (int32 flag, char *ptr);
|
||||||
|
|
||||||
t_stat sim_process_event (void);
|
t_stat sim_process_event (void);
|
||||||
t_stat sim_activate (UNIT *uptr, int32 interval);
|
t_stat sim_activate (UNIT *uptr, int32 interval);
|
||||||
|
t_stat _sim_activate (UNIT *uptr, int32 interval);
|
||||||
t_stat sim_activate_abs (UNIT *uptr, int32 interval);
|
t_stat sim_activate_abs (UNIT *uptr, int32 interval);
|
||||||
t_stat sim_activate_notbefore (UNIT *uptr, int32 rtime);
|
t_stat sim_activate_notbefore (UNIT *uptr, int32 rtime);
|
||||||
|
t_stat sim_activate_after (UNIT *uptr, int32 usecs_walltime);
|
||||||
|
t_stat _sim_activate_after (UNIT *uptr, int32 usecs_walltime);
|
||||||
t_stat sim_cancel (UNIT *uptr);
|
t_stat sim_cancel (UNIT *uptr);
|
||||||
|
t_bool sim_is_active_bool (UNIT *uptr);
|
||||||
int32 sim_is_active (UNIT *uptr);
|
int32 sim_is_active (UNIT *uptr);
|
||||||
double sim_gtime (void);
|
double sim_gtime (void);
|
||||||
uint32 sim_grtime (void);
|
uint32 sim_grtime (void);
|
||||||
|
@ -104,6 +103,7 @@ t_stat deassign_device (DEVICE *dptr);
|
||||||
t_stat reset_all (uint32 start_device);
|
t_stat reset_all (uint32 start_device);
|
||||||
t_stat reset_all_p (uint32 start_device);
|
t_stat reset_all_p (uint32 start_device);
|
||||||
char *sim_dname (DEVICE *dptr);
|
char *sim_dname (DEVICE *dptr);
|
||||||
|
char *sim_uname (UNIT *dptr);
|
||||||
t_stat get_yn (char *ques, t_stat deflt);
|
t_stat get_yn (char *ques, t_stat deflt);
|
||||||
char *get_sim_opt (int32 opt, char *cptr, t_stat *st);
|
char *get_sim_opt (int32 opt, char *cptr, t_stat *st);
|
||||||
char *get_glyph (char *iptr, char *optr, char mchar);
|
char *get_glyph (char *iptr, char *optr, char mchar);
|
||||||
|
@ -111,12 +111,13 @@ char *get_glyph_nc (char *iptr, char *optr, char mchar);
|
||||||
t_value get_uint (char *cptr, uint32 radix, t_value max, t_stat *status);
|
t_value get_uint (char *cptr, uint32 radix, t_value max, t_stat *status);
|
||||||
char *get_range (DEVICE *dptr, char *cptr, t_addr *lo, t_addr *hi,
|
char *get_range (DEVICE *dptr, char *cptr, t_addr *lo, t_addr *hi,
|
||||||
uint32 rdx, t_addr max, char term);
|
uint32 rdx, t_addr max, char term);
|
||||||
t_value strtotv (char *cptr, char **endptr, uint32 radix);
|
t_value strtotv (const char *cptr, char **endptr, uint32 radix);
|
||||||
t_stat fprint_val (FILE *stream, t_value val, uint32 rdx, uint32 wid, uint32 fmt);
|
t_stat fprint_val (FILE *stream, t_value val, uint32 rdx, uint32 wid, uint32 fmt);
|
||||||
CTAB *find_cmd (char *gbuf);
|
CTAB *find_cmd (char *gbuf);
|
||||||
DEVICE *find_dev (char *ptr);
|
DEVICE *find_dev (char *ptr);
|
||||||
DEVICE *find_unit (char *ptr, UNIT **uptr);
|
DEVICE *find_unit (char *ptr, UNIT **uptr);
|
||||||
DEVICE *find_dev_from_unit (UNIT *uptr);
|
DEVICE *find_dev_from_unit (UNIT *uptr);
|
||||||
|
t_stat sim_register_internal_device (DEVICE *dptr);
|
||||||
REG *find_reg (char *ptr, char **optr, DEVICE *dptr);
|
REG *find_reg (char *ptr, char **optr, DEVICE *dptr);
|
||||||
CTAB *find_ctab (CTAB *tab, char *gbuf);
|
CTAB *find_ctab (CTAB *tab, char *gbuf);
|
||||||
C1TAB *find_c1tab (C1TAB *tab, char *gbuf);
|
C1TAB *find_c1tab (C1TAB *tab, char *gbuf);
|
||||||
|
|
368
sim_console.c
368
sim_console.c
|
@ -118,10 +118,20 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "sim_defs.h"
|
#include "sim_defs.h"
|
||||||
#include "sim_sock.h"
|
|
||||||
#include "sim_tmxr.h"
|
#include "sim_tmxr.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
/* Forward Declaraations of Platform specific routines */
|
||||||
|
|
||||||
|
t_stat sim_os_poll_kbd (void);
|
||||||
|
t_bool sim_os_poll_kbd_ready (int ms_timeout);
|
||||||
|
t_stat sim_os_putchar (int32 out);
|
||||||
|
t_stat sim_os_ttinit (void);
|
||||||
|
t_stat sim_os_ttrun (void);
|
||||||
|
t_stat sim_os_ttcmd (void);
|
||||||
|
t_stat sim_os_ttclose (void);
|
||||||
|
t_bool sim_os_ttisatty (void);
|
||||||
|
|
||||||
#define KMAP_WRU 0
|
#define KMAP_WRU 0
|
||||||
#define KMAP_BRK 1
|
#define KMAP_BRK 1
|
||||||
#define KMAP_DEL 2
|
#define KMAP_DEL 2
|
||||||
|
@ -136,8 +146,51 @@ int32 sim_del_char = '\b'; /* delete character */
|
||||||
#else
|
#else
|
||||||
int32 sim_del_char = 0177;
|
int32 sim_del_char = 0177;
|
||||||
#endif
|
#endif
|
||||||
|
t_stat sim_con_poll_svc (UNIT *uptr); /* console connection poll routine */
|
||||||
|
t_stat sim_con_reset (DEVICE *dptr); /* console connection poll routine */
|
||||||
|
UNIT sim_con_unit = { UDATA (&sim_con_poll_svc, 0, 0) }; /* console connection unit */
|
||||||
|
/* debugging bitmaps */
|
||||||
|
#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_ASY TMXR_DBG_ASY /* asynchronous thread activity */
|
||||||
|
|
||||||
|
DEBTAB sim_con_debug[] = {
|
||||||
|
{"TRC", DBG_TRC},
|
||||||
|
{"XMT", DBG_XMT},
|
||||||
|
{"RCV", DBG_RCV},
|
||||||
|
{"ASY", DBG_ASY},
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
|
||||||
|
MTAB sim_con_mod[] = {
|
||||||
|
{ 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE sim_con_telnet = {
|
||||||
|
"CON-TEL", &sim_con_unit, NULL, sim_con_mod,
|
||||||
|
1, 0, 0, 0, 0, 0,
|
||||||
|
NULL, NULL, sim_con_reset, NULL, NULL, NULL,
|
||||||
|
NULL, DEV_DEBUG, 0, sim_con_debug};
|
||||||
TMLN sim_con_ldsc = { 0 }; /* console line descr */
|
TMLN sim_con_ldsc = { 0 }; /* console line descr */
|
||||||
TMXR sim_con_tmxr = { 1, 0, 0, &sim_con_ldsc }; /* console line mux */
|
TMXR sim_con_tmxr = { 1, 0, 0, &sim_con_ldsc, NULL, &sim_con_telnet };/* console line mux */
|
||||||
|
|
||||||
|
/* Unit service for console connection polling */
|
||||||
|
|
||||||
|
t_stat sim_con_poll_svc (UNIT *uptr)
|
||||||
|
{
|
||||||
|
if (sim_con_tmxr.master == 0) /* not Telnet? done */
|
||||||
|
return SCPE_OK;
|
||||||
|
if (tmxr_poll_conn (&sim_con_tmxr) >= 0) /* poll connect */
|
||||||
|
sim_con_ldsc.rcve = 1; /* rcv enabled */
|
||||||
|
sim_activate_after(uptr, 1000000); /* check again in 1 second */
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat sim_con_reset (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
return sim_con_poll_svc (&dptr->units[0]); /* establish polling as needed */
|
||||||
|
}
|
||||||
|
|
||||||
extern volatile int32 stop_cpu;
|
extern volatile int32 stop_cpu;
|
||||||
extern int32 sim_quiet;
|
extern int32 sim_quiet;
|
||||||
|
@ -154,6 +207,8 @@ static CTAB set_con_tab[] = {
|
||||||
{ "PCHAR", &sim_set_pchar, 0 },
|
{ "PCHAR", &sim_set_pchar, 0 },
|
||||||
{ "TELNET", &sim_set_telnet, 0 },
|
{ "TELNET", &sim_set_telnet, 0 },
|
||||||
{ "NOTELNET", &sim_set_notelnet, 0 },
|
{ "NOTELNET", &sim_set_notelnet, 0 },
|
||||||
|
{ "SERIAL", &sim_set_serial, 0 },
|
||||||
|
{ "NOSERIAL", &sim_set_noserial, 0 },
|
||||||
{ "LOG", &sim_set_logon, 0 },
|
{ "LOG", &sim_set_logon, 0 },
|
||||||
{ "NOLOG", &sim_set_logoff, 0 },
|
{ "NOLOG", &sim_set_logoff, 0 },
|
||||||
{ "DEBUG", &sim_set_debon, 0 },
|
{ "DEBUG", &sim_set_debon, 0 },
|
||||||
|
@ -182,6 +237,12 @@ static CTAB set_con_telnet_tab[] = {
|
||||||
{ NULL, NULL, 0 }
|
{ NULL, NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static CTAB set_con_serial_tab[] = {
|
||||||
|
{ "LOG", &sim_set_cons_log, 0 },
|
||||||
|
{ "NOLOG", &sim_set_cons_nolog, 0 },
|
||||||
|
{ NULL, NULL, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
static int32 *cons_kmap[] = {
|
static int32 *cons_kmap[] = {
|
||||||
&sim_int_char,
|
&sim_int_char,
|
||||||
&sim_brk_char,
|
&sim_brk_char,
|
||||||
|
@ -438,7 +499,10 @@ while (*cptr != 0) { /* do all mods */
|
||||||
if (r == SCPE_OK) {
|
if (r == SCPE_OK) {
|
||||||
if (sim_con_tmxr.master) /* already open? */
|
if (sim_con_tmxr.master) /* already open? */
|
||||||
sim_set_notelnet (0, NULL); /* close first */
|
sim_set_notelnet (0, NULL); /* close first */
|
||||||
return tmxr_open_master (&sim_con_tmxr, gbuf); /* open master socket */
|
r = tmxr_attach (&sim_con_tmxr, &sim_con_unit, gbuf);/* open master socket */
|
||||||
|
if (r == SCPE_OK)
|
||||||
|
sim_activate_after(&sim_con_unit, 1000000); /* check for connection in 1 second */
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
return SCPE_NOPARAM;
|
return SCPE_NOPARAM;
|
||||||
}
|
}
|
||||||
|
@ -463,9 +527,15 @@ t_stat sim_show_telnet (FILE *st, DEVICE *dunused, UNIT *uunused, int32 flag, ch
|
||||||
{
|
{
|
||||||
if (cptr && (*cptr != 0))
|
if (cptr && (*cptr != 0))
|
||||||
return SCPE_2MARG;
|
return SCPE_2MARG;
|
||||||
if (sim_con_tmxr.master == 0)
|
if ((sim_con_tmxr.master == 0) &&
|
||||||
|
(sim_con_ldsc.serport == 0))
|
||||||
fprintf (st, "Connected to console window\n");
|
fprintf (st, "Connected to console window\n");
|
||||||
else {
|
else {
|
||||||
|
if (sim_con_ldsc.serport) {
|
||||||
|
fprintf (st, "Connected to ");
|
||||||
|
tmxr_fconns (st, &sim_con_ldsc, -1);
|
||||||
|
}
|
||||||
|
else
|
||||||
if (sim_con_ldsc.conn == 0)
|
if (sim_con_ldsc.conn == 0)
|
||||||
fprintf (st, "Listening on port %s\n", sim_con_tmxr.port);
|
fprintf (st, "Listening on port %s\n", sim_con_tmxr.port);
|
||||||
else {
|
else {
|
||||||
|
@ -541,6 +611,59 @@ else
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set console to Serial port (and parameters) */
|
||||||
|
|
||||||
|
t_stat sim_set_serial (int32 flag, char *cptr)
|
||||||
|
{
|
||||||
|
char *cvptr, gbuf[CBUFSIZE], ubuf[CBUFSIZE];
|
||||||
|
CTAB *ctptr;
|
||||||
|
t_stat r;
|
||||||
|
|
||||||
|
if ((cptr == NULL) || (*cptr == 0))
|
||||||
|
return SCPE_2FARG;
|
||||||
|
while (*cptr != 0) { /* do all mods */
|
||||||
|
cptr = get_glyph_nc (cptr, gbuf, ','); /* get modifier */
|
||||||
|
if ((cvptr = strchr (gbuf, '='))) /* = value? */
|
||||||
|
*cvptr++ = 0;
|
||||||
|
get_glyph (gbuf, ubuf, 0); /* modifier to UC */
|
||||||
|
if ((ctptr = find_ctab (set_con_serial_tab, ubuf))) { /* match? */
|
||||||
|
r = ctptr->action (ctptr->arg, cvptr); /* do the rest */
|
||||||
|
if (r != SCPE_OK)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SERHANDLE serport = sim_open_serial (gbuf, NULL, &r);
|
||||||
|
if (serport != INVALID_HANDLE) {
|
||||||
|
sim_close_serial (serport);
|
||||||
|
if (r == SCPE_OK) {
|
||||||
|
char cbuf[CBUFSIZE];
|
||||||
|
if ((sim_con_tmxr.master) || /* already open? */
|
||||||
|
(sim_con_ldsc.serport))
|
||||||
|
sim_set_noserial (0, NULL); /* close first */
|
||||||
|
sprintf(cbuf, "Connect=%s", gbuf);
|
||||||
|
r = tmxr_attach (&sim_con_tmxr, &sim_con_unit, cbuf);/* open master socket */
|
||||||
|
sim_con_ldsc.rcve = 1; /* rcv enabled */
|
||||||
|
if (r == SCPE_OK)
|
||||||
|
sim_activate_after(&sim_con_unit, 1000000); /* check for connection in 1 second */
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SCPE_NOPARAM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Close console Serial port */
|
||||||
|
|
||||||
|
t_stat sim_set_noserial (int32 flag, char *cptr)
|
||||||
|
{
|
||||||
|
if (cptr && (*cptr != 0)) /* too many arguments? */
|
||||||
|
return SCPE_2MARG;
|
||||||
|
if (sim_con_ldsc.serport == 0) /* ignore if already closed */
|
||||||
|
return SCPE_OK;
|
||||||
|
return tmxr_close_master (&sim_con_tmxr); /* close master socket */
|
||||||
|
}
|
||||||
|
|
||||||
/* Log File Open/Close/Show Support */
|
/* Log File Open/Close/Show Support */
|
||||||
|
|
||||||
|
@ -687,9 +810,12 @@ t_stat sim_poll_kbd (void)
|
||||||
int32 c;
|
int32 c;
|
||||||
|
|
||||||
c = sim_os_poll_kbd (); /* get character */
|
c = sim_os_poll_kbd (); /* get character */
|
||||||
if ((c == SCPE_STOP) || (sim_con_tmxr.master == 0)) /* ^E or not Telnet? */
|
if ((c == SCPE_STOP) || /* ^E or not Telnet? */
|
||||||
|
((sim_con_tmxr.master == 0) && /* and not serial? */
|
||||||
|
(sim_con_ldsc.serport == 0)))
|
||||||
return c; /* in-window */
|
return c; /* in-window */
|
||||||
if (sim_con_ldsc.conn == 0) { /* no Telnet conn? */
|
if ((sim_con_ldsc.conn == 0) && /* no Telnet conn */
|
||||||
|
(sim_con_ldsc.serport == 0)) { /* and no serial conn? */
|
||||||
if (!sim_con_ldsc.txbfd) /* unbuffered? */
|
if (!sim_con_ldsc.txbfd) /* unbuffered? */
|
||||||
return SCPE_LOST; /* connection lost */
|
return SCPE_LOST; /* connection lost */
|
||||||
if (tmxr_poll_conn (&sim_con_tmxr) >= 0) /* poll connect */
|
if (tmxr_poll_conn (&sim_con_tmxr) >= 0) /* poll connect */
|
||||||
|
@ -707,14 +833,16 @@ return SCPE_OK;
|
||||||
|
|
||||||
t_stat sim_putchar (int32 c)
|
t_stat sim_putchar (int32 c)
|
||||||
{
|
{
|
||||||
if (sim_con_tmxr.master == 0) { /* not Telnet? */
|
if ((sim_con_tmxr.master == 0) && /* not Telnet? */
|
||||||
|
(sim_con_ldsc.serport == 0)) { /* and not serial port */
|
||||||
if (sim_log) /* log file? */
|
if (sim_log) /* log file? */
|
||||||
fputc (c, sim_log);
|
fputc (c, sim_log);
|
||||||
return sim_os_putchar (c); /* in-window version */
|
return sim_os_putchar (c); /* in-window version */
|
||||||
}
|
}
|
||||||
if (sim_log && !sim_con_ldsc.txlog) /* log file, but no line log? */
|
if (sim_log && !sim_con_ldsc.txlog) /* log file, but no line log? */
|
||||||
fputc (c, sim_log);
|
fputc (c, sim_log);
|
||||||
if (sim_con_ldsc.conn == 0) { /* no Telnet conn? */
|
if ((sim_con_ldsc.serport == 0) && /* no serial port */
|
||||||
|
(sim_con_ldsc.conn == 0)) { /* and no Telnet conn? */
|
||||||
if (!sim_con_ldsc.txbfd) /* unbuffered? */
|
if (!sim_con_ldsc.txbfd) /* unbuffered? */
|
||||||
return SCPE_LOST; /* connection lost */
|
return SCPE_LOST; /* connection lost */
|
||||||
if (tmxr_poll_conn (&sim_con_tmxr) >= 0) /* poll connect */
|
if (tmxr_poll_conn (&sim_con_tmxr) >= 0) /* poll connect */
|
||||||
|
@ -729,14 +857,16 @@ t_stat sim_putchar_s (int32 c)
|
||||||
{
|
{
|
||||||
t_stat r;
|
t_stat r;
|
||||||
|
|
||||||
if (sim_con_tmxr.master == 0) { /* not Telnet? */
|
if ((sim_con_tmxr.master == 0) && /* not Telnet? */
|
||||||
|
(sim_con_ldsc.serport == 0)) { /* and not serial port */
|
||||||
if (sim_log) /* log file? */
|
if (sim_log) /* log file? */
|
||||||
fputc (c, sim_log);
|
fputc (c, sim_log);
|
||||||
return sim_os_putchar (c); /* in-window version */
|
return sim_os_putchar (c); /* in-window version */
|
||||||
}
|
}
|
||||||
if (sim_log && !sim_con_ldsc.txlog) /* log file, but no line log? */
|
if (sim_log && !sim_con_ldsc.txlog) /* log file, but no line log? */
|
||||||
fputc (c, sim_log);
|
fputc (c, sim_log);
|
||||||
if (sim_con_ldsc.conn == 0) { /* no Telnet conn? */
|
if ((sim_con_ldsc.serport == 0) && /* no serial port */
|
||||||
|
(sim_con_ldsc.conn == 0)) { /* and no Telnet conn? */
|
||||||
if (!sim_con_ldsc.txbfd) /* non-buffered Telnet conn? */
|
if (!sim_con_ldsc.txbfd) /* non-buffered Telnet conn? */
|
||||||
return SCPE_LOST; /* lost */
|
return SCPE_LOST; /* lost */
|
||||||
if (tmxr_poll_conn (&sim_con_tmxr) >= 0) /* poll connect */
|
if (tmxr_poll_conn (&sim_con_tmxr) >= 0) /* poll connect */
|
||||||
|
@ -791,6 +921,69 @@ else c = c & 0377;
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
t_stat sim_ttinit (void)
|
||||||
|
{
|
||||||
|
sim_register_internal_device (&sim_con_telnet);
|
||||||
|
tmxr_startup ();
|
||||||
|
return sim_os_ttinit ();
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat sim_ttrun (void)
|
||||||
|
{
|
||||||
|
if (!sim_con_tmxr.ldsc->uptr) /* If simulator didn't declare its input polling unit */
|
||||||
|
sim_con_unit.flags &= ~UNIT_TM_POLL; /* we can't poll asynchronously */
|
||||||
|
#if defined(SIM_ASYNCH_IO) && defined(SIM_ASYNCH_MUX)
|
||||||
|
pthread_mutex_lock (&sim_tmxr_poll_lock);
|
||||||
|
if (sim_asynch_enabled) {
|
||||||
|
pthread_attr_t attr;
|
||||||
|
|
||||||
|
pthread_cond_init (&sim_console_startup_cond, NULL);
|
||||||
|
pthread_attr_init (&attr);
|
||||||
|
pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);
|
||||||
|
pthread_create (&sim_console_poll_thread, &attr, _console_poll, NULL);
|
||||||
|
pthread_attr_destroy( &attr);
|
||||||
|
pthread_cond_wait (&sim_console_startup_cond, &sim_tmxr_poll_lock); /* Wait for thread to stabilize */
|
||||||
|
pthread_cond_destroy (&sim_console_startup_cond);
|
||||||
|
sim_console_poll_running = TRUE;
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock (&sim_tmxr_poll_lock);
|
||||||
|
#endif
|
||||||
|
tmxr_start_poll ();
|
||||||
|
return sim_os_ttrun ();
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat sim_ttcmd (void)
|
||||||
|
{
|
||||||
|
#if defined(SIM_ASYNCH_IO) && defined(SIM_ASYNCH_MUX)
|
||||||
|
pthread_mutex_lock (&sim_tmxr_poll_lock);
|
||||||
|
if (sim_console_poll_running) {
|
||||||
|
pthread_cond_signal (&sim_tmxr_poll_cond);
|
||||||
|
pthread_mutex_unlock (&sim_tmxr_poll_lock);
|
||||||
|
pthread_join (sim_console_poll_thread, NULL);
|
||||||
|
sim_console_poll_running = FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pthread_mutex_unlock (&sim_tmxr_poll_lock);
|
||||||
|
#endif
|
||||||
|
tmxr_stop_poll ();
|
||||||
|
return sim_os_ttcmd ();
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat sim_ttclose (void)
|
||||||
|
{
|
||||||
|
tmxr_shutdown ();
|
||||||
|
return sim_os_ttclose ();
|
||||||
|
}
|
||||||
|
|
||||||
|
t_bool sim_ttisatty (void)
|
||||||
|
{
|
||||||
|
return sim_os_ttisatty ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Platform specific routine definitions */
|
||||||
|
|
||||||
/* VMS routines, from Ben Thomas, with fixes from Robert Alan Byer */
|
/* VMS routines, from Ben Thomas, with fixes from Robert Alan Byer */
|
||||||
|
|
||||||
#if defined (VMS)
|
#if defined (VMS)
|
||||||
|
@ -798,6 +991,7 @@ return c;
|
||||||
#if defined(__VAX)
|
#if defined(__VAX)
|
||||||
#define sys$assign SYS$ASSIGN
|
#define sys$assign SYS$ASSIGN
|
||||||
#define sys$qiow SYS$QIOW
|
#define sys$qiow SYS$QIOW
|
||||||
|
#define sys$dassgn SYS$DASSGN
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <descrip.h>
|
#include <descrip.h>
|
||||||
|
@ -810,6 +1004,7 @@ return c;
|
||||||
|
|
||||||
#define EFN 0
|
#define EFN 0
|
||||||
uint32 tty_chan = 0;
|
uint32 tty_chan = 0;
|
||||||
|
int buffered_character = 0;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned short sense_count;
|
unsigned short sense_count;
|
||||||
|
@ -826,7 +1021,7 @@ typedef struct {
|
||||||
SENSE_BUF cmd_mode = { 0 };
|
SENSE_BUF cmd_mode = { 0 };
|
||||||
SENSE_BUF run_mode = { 0 };
|
SENSE_BUF run_mode = { 0 };
|
||||||
|
|
||||||
t_stat sim_ttinit (void)
|
t_stat sim_os_ttinit (void)
|
||||||
{
|
{
|
||||||
unsigned int status;
|
unsigned int status;
|
||||||
IOSB iosb;
|
IOSB iosb;
|
||||||
|
@ -869,17 +1064,19 @@ if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL))
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
t_stat sim_ttclose (void)
|
t_stat sim_os_ttclose (void)
|
||||||
{
|
{
|
||||||
return sim_ttcmd ();
|
sim_ttcmd ();
|
||||||
|
sys$dassgn (tty_chan);
|
||||||
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
t_bool sim_ttisatty (void)
|
t_bool sim_os_ttisatty (void)
|
||||||
{
|
{
|
||||||
return isatty (fileno (stdin));
|
return isatty (fileno (stdin));
|
||||||
}
|
}
|
||||||
|
|
||||||
t_stat sim_os_poll_kbd (void)
|
t_stat sim_os_poll_kbd_data (void)
|
||||||
{
|
{
|
||||||
unsigned int status, term[2];
|
unsigned int status, term[2];
|
||||||
unsigned char buf[4];
|
unsigned char buf[4];
|
||||||
|
@ -904,6 +1101,40 @@ if (sim_brk_char && (buf[0] == sim_brk_char))
|
||||||
return (buf[0] | SCPE_KFLAG);
|
return (buf[0] | SCPE_KFLAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t_stat sim_os_poll_kbd (void)
|
||||||
|
{
|
||||||
|
t_stat response;
|
||||||
|
|
||||||
|
if (response = buffered_character) {
|
||||||
|
buffered_character = 0;
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
return sim_os_poll_kbd_data ();
|
||||||
|
}
|
||||||
|
|
||||||
|
t_bool sim_os_poll_kbd_ready (int ms_timeout)
|
||||||
|
{
|
||||||
|
unsigned int status, term[2];
|
||||||
|
unsigned char buf[4];
|
||||||
|
IOSB iosb;
|
||||||
|
|
||||||
|
term[0] = 0; term[1] = 0;
|
||||||
|
status = sys$qiow (EFN, tty_chan,
|
||||||
|
IO$_READLBLK | IO$M_NOECHO | IO$M_NOFILTR | IO$M_TIMED | IO$M_TRMNOECHO,
|
||||||
|
&iosb, 0, 0, buf, 1, (ms_timeout+999)/1000, term, 0, 0);
|
||||||
|
if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL))
|
||||||
|
return FALSE;
|
||||||
|
if (buf[0] == sim_int_char)
|
||||||
|
buffered_character = SCPE_STOP;
|
||||||
|
else
|
||||||
|
if (sim_brk_char && (buf[0] == sim_brk_char))
|
||||||
|
buffered_character = SCPE_BREAK;
|
||||||
|
else
|
||||||
|
buffered_character = (buf[0] | SCPE_KFLAG)
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
t_stat sim_os_putchar (int32 out)
|
t_stat sim_os_putchar (int32 out)
|
||||||
{
|
{
|
||||||
unsigned int status;
|
unsigned int status;
|
||||||
|
@ -960,7 +1191,7 @@ ControlHandler(DWORD dwCtrlType)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
t_stat sim_ttinit (void)
|
t_stat sim_os_ttinit (void)
|
||||||
{
|
{
|
||||||
SetConsoleCtrlHandler( ControlHandler, TRUE );
|
SetConsoleCtrlHandler( ControlHandler, TRUE );
|
||||||
std_input = GetStdHandle (STD_INPUT_HANDLE);
|
std_input = GetStdHandle (STD_INPUT_HANDLE);
|
||||||
|
@ -971,7 +1202,7 @@ if ((std_input) && /* Not Background proces
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
t_stat sim_ttrun (void)
|
t_stat sim_os_ttrun (void)
|
||||||
{
|
{
|
||||||
if ((std_input) && /* If Not Background process? */
|
if ((std_input) && /* If Not Background process? */
|
||||||
(std_input != INVALID_HANDLE_VALUE) &&
|
(std_input != INVALID_HANDLE_VALUE) &&
|
||||||
|
@ -986,7 +1217,7 @@ SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
t_stat sim_ttcmd (void)
|
t_stat sim_os_ttcmd (void)
|
||||||
{
|
{
|
||||||
if (sim_log) {
|
if (sim_log) {
|
||||||
fflush (sim_log);
|
fflush (sim_log);
|
||||||
|
@ -1000,12 +1231,12 @@ if ((std_input) && /* If Not Background pro
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
t_stat sim_ttclose (void)
|
t_stat sim_os_ttclose (void)
|
||||||
{
|
{
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
t_bool sim_ttisatty (void)
|
t_bool sim_os_ttisatty (void)
|
||||||
{
|
{
|
||||||
DWORD Mode;
|
DWORD Mode;
|
||||||
|
|
||||||
|
@ -1018,7 +1249,7 @@ int c = -1;
|
||||||
DWORD nkbevents, nkbevent;
|
DWORD nkbevents, nkbevent;
|
||||||
INPUT_RECORD rec;
|
INPUT_RECORD rec;
|
||||||
|
|
||||||
\
|
sim_debug (DBG_TRC, &sim_con_telnet, "sim_os_poll_kbd()\n");
|
||||||
|
|
||||||
if ((std_input == NULL) || /* No keyboard for */
|
if ((std_input == NULL) || /* No keyboard for */
|
||||||
(std_input == INVALID_HANDLE_VALUE)) /* background processes */
|
(std_input == INVALID_HANDLE_VALUE)) /* background processes */
|
||||||
|
@ -1055,6 +1286,17 @@ if ((sim_brk_char && ((c & 0177) == sim_brk_char)) || (c & SCPE_BREAK))
|
||||||
return c | SCPE_KFLAG;
|
return c | SCPE_KFLAG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t_bool sim_os_poll_kbd_ready (int ms_timeout)
|
||||||
|
{
|
||||||
|
sim_debug (DBG_TRC, &sim_con_telnet, "sim_os_poll_kbd_ready()\n");
|
||||||
|
if ((std_input == NULL) || /* No keyboard for */
|
||||||
|
(std_input == INVALID_HANDLE_VALUE)) { /* background processes */
|
||||||
|
Sleep (ms_timeout);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return (WAIT_OBJECT_0 == WaitForSingleObject (std_input, ms_timeout));
|
||||||
|
}
|
||||||
|
|
||||||
t_stat sim_os_putchar (int32 c)
|
t_stat sim_os_putchar (int32 c)
|
||||||
{
|
{
|
||||||
DWORD unused;
|
DWORD unused;
|
||||||
|
@ -1070,27 +1312,27 @@ return SCPE_OK;
|
||||||
|
|
||||||
#include <conio.h>
|
#include <conio.h>
|
||||||
|
|
||||||
t_stat sim_ttinit (void)
|
t_stat sim_os_ttinit (void)
|
||||||
{
|
{
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
t_stat sim_ttrun (void)
|
t_stat sim_os_ttrun (void)
|
||||||
{
|
{
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
t_stat sim_ttcmd (void)
|
t_stat sim_os_ttcmd (void)
|
||||||
{
|
{
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
t_stat sim_ttclose (void)
|
t_stat sim_os_ttclose (void)
|
||||||
{
|
{
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
t_bool sim_ttisatty (void)
|
t_bool sim_os_ttisatty (void)
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -1126,6 +1368,12 @@ if (sim_brk_char && ((c & 0177) == sim_brk_char))
|
||||||
return c | SCPE_KFLAG;
|
return c | SCPE_KFLAG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t_bool sim_os_poll_kbd_ready (int ms_timeout) /* Don't know how to do this on this platform */
|
||||||
|
{
|
||||||
|
sim_os_ms_sleep (MIN(20,ms_timeout)); /* Wait a little */
|
||||||
|
return TRUE; /* force a poll */
|
||||||
|
}
|
||||||
|
|
||||||
t_stat sim_os_putchar (int32 c)
|
t_stat sim_os_putchar (int32 c)
|
||||||
{
|
{
|
||||||
if (c != 0177) {
|
if (c != 0177) {
|
||||||
|
@ -1253,7 +1501,7 @@ int ps_getch(void) {
|
||||||
|
|
||||||
/* Note that this only works if the call to sim_ttinit comes before any output to the console */
|
/* Note that this only works if the call to sim_ttinit comes before any output to the console */
|
||||||
|
|
||||||
t_stat sim_ttinit (void) {
|
t_stat sim_os_ttinit (void) {
|
||||||
int i;
|
int i;
|
||||||
/* this blank will later be replaced by the number of characters */
|
/* this blank will later be replaced by the number of characters */
|
||||||
char title[50] = " ";
|
char title[50] = " ";
|
||||||
|
@ -1276,22 +1524,22 @@ t_stat sim_ttinit (void) {
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
t_stat sim_ttrun (void)
|
t_stat sim_os_ttrun (void)
|
||||||
{
|
{
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
t_stat sim_ttcmd (void)
|
t_stat sim_os_ttcmd (void)
|
||||||
{
|
{
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
t_stat sim_ttclose (void)
|
t_stat sim_os_ttclose (void)
|
||||||
{
|
{
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
t_bool sim_ttisatty (void)
|
t_bool sim_os_ttisatty (void)
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -1311,6 +1559,12 @@ if (sim_brk_char && ((c & 0177) == sim_brk_char))
|
||||||
return c | SCPE_KFLAG;
|
return c | SCPE_KFLAG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t_bool sim_os_poll_kbd_ready (int ms_timeout) /* Don't know how to do this on this platform */
|
||||||
|
{
|
||||||
|
sim_os_ms_sleep (MIN(20,ms_timeout)); /* Wait a little */
|
||||||
|
return TRUE; /* force a poll */
|
||||||
|
}
|
||||||
|
|
||||||
t_stat sim_os_putchar (int32 c)
|
t_stat sim_os_putchar (int32 c)
|
||||||
{
|
{
|
||||||
if (c != 0177) {
|
if (c != 0177) {
|
||||||
|
@ -1333,7 +1587,7 @@ struct tchars cmdtchars,runtchars; /* V7 editing */
|
||||||
struct ltchars cmdltchars,runltchars; /* 4.2 BSD editing */
|
struct ltchars cmdltchars,runltchars; /* 4.2 BSD editing */
|
||||||
int cmdfl,runfl; /* TTY flags */
|
int cmdfl,runfl; /* TTY flags */
|
||||||
|
|
||||||
t_stat sim_ttinit (void)
|
t_stat sim_os_ttinit (void)
|
||||||
{
|
{
|
||||||
cmdfl = fcntl (0, F_GETFL, 0); /* get old flags and status */
|
cmdfl = fcntl (0, F_GETFL, 0); /* get old flags and status */
|
||||||
runfl = cmdfl | FNDELAY;
|
runfl = cmdfl | FNDELAY;
|
||||||
|
@ -1360,7 +1614,7 @@ runltchars.t_lnextc = 0xFF;
|
||||||
return SCPE_OK; /* return success */
|
return SCPE_OK; /* return success */
|
||||||
}
|
}
|
||||||
|
|
||||||
t_stat sim_ttrun (void)
|
t_stat sim_os_ttrun (void)
|
||||||
{
|
{
|
||||||
runtchars.t_intrc = sim_int_char; /* in case changed */
|
runtchars.t_intrc = sim_int_char; /* in case changed */
|
||||||
fcntl (0, F_SETFL, runfl); /* non-block mode */
|
fcntl (0, F_SETFL, runfl); /* non-block mode */
|
||||||
|
@ -1374,7 +1628,7 @@ nice (10); /* lower priority */
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
t_stat sim_ttcmd (void)
|
t_stat sim_os_ttcmd (void)
|
||||||
{
|
{
|
||||||
nice (-10); /* restore priority */
|
nice (-10); /* restore priority */
|
||||||
fcntl (0, F_SETFL, cmdfl); /* block mode */
|
fcntl (0, F_SETFL, cmdfl); /* block mode */
|
||||||
|
@ -1387,12 +1641,12 @@ if (ioctl (0, TIOCSLTC, &cmdltchars) < 0)
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
t_stat sim_ttclose (void)
|
t_stat sim_os_ttclose (void)
|
||||||
{
|
{
|
||||||
return sim_ttcmd ();
|
return sim_ttcmd ();
|
||||||
}
|
}
|
||||||
|
|
||||||
t_bool sim_ttisatty (void)
|
t_bool sim_os_ttisatty (void)
|
||||||
{
|
{
|
||||||
return isatty (0);
|
return isatty (0);
|
||||||
}
|
}
|
||||||
|
@ -1409,6 +1663,22 @@ if (sim_brk_char && (buf[0] == sim_brk_char))
|
||||||
else return (buf[0] | SCPE_KFLAG);
|
else return (buf[0] | SCPE_KFLAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t_bool sim_os_poll_kbd_ready (int ms_timeout)
|
||||||
|
{
|
||||||
|
fd_set readfds;
|
||||||
|
struct timeval timeout;
|
||||||
|
|
||||||
|
if (!isatty (0)) { /* skip if !tty */
|
||||||
|
sim_os_ms_sleep (ms_timeout);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
FD_ZERO (&readfds);
|
||||||
|
FD_SET (0, &readfds);
|
||||||
|
timeout.tv_sec = (ms_timeout*1000)/1000000;
|
||||||
|
timeout.tv_usec = (ms_timeout*1000)%1000000;
|
||||||
|
return (1 == select (1, &readfds, NULL, NULL, &timeout));
|
||||||
|
}
|
||||||
|
|
||||||
t_stat sim_os_putchar (int32 out)
|
t_stat sim_os_putchar (int32 out)
|
||||||
{
|
{
|
||||||
char c;
|
char c;
|
||||||
|
@ -1428,7 +1698,7 @@ return SCPE_OK;
|
||||||
struct termios cmdtty, runtty;
|
struct termios cmdtty, runtty;
|
||||||
static int prior_norm = 1;
|
static int prior_norm = 1;
|
||||||
|
|
||||||
t_stat sim_ttinit (void)
|
t_stat sim_os_ttinit (void)
|
||||||
{
|
{
|
||||||
if (!isatty (fileno (stdin))) /* skip if !tty */
|
if (!isatty (fileno (stdin))) /* skip if !tty */
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
|
@ -1470,7 +1740,7 @@ runtty.c_cc[VSTATUS] = 0;
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
t_stat sim_ttrun (void)
|
t_stat sim_os_ttrun (void)
|
||||||
{
|
{
|
||||||
if (!isatty (fileno (stdin))) /* skip if !tty */
|
if (!isatty (fileno (stdin))) /* skip if !tty */
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
|
@ -1485,7 +1755,7 @@ if (prior_norm) { /* at normal pri? */
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
t_stat sim_ttcmd (void)
|
t_stat sim_os_ttcmd (void)
|
||||||
{
|
{
|
||||||
if (!isatty (fileno (stdin))) /* skip if !tty */
|
if (!isatty (fileno (stdin))) /* skip if !tty */
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
|
@ -1499,12 +1769,12 @@ if (tcsetattr (0, TCSAFLUSH, &cmdtty) < 0)
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
t_stat sim_ttclose (void)
|
t_stat sim_os_ttclose (void)
|
||||||
{
|
{
|
||||||
return sim_ttcmd ();
|
return sim_ttcmd ();
|
||||||
}
|
}
|
||||||
|
|
||||||
t_bool sim_ttisatty(void)
|
t_bool sim_os_ttisatty (void)
|
||||||
{
|
{
|
||||||
return isatty (fileno (stdin));
|
return isatty (fileno (stdin));
|
||||||
}
|
}
|
||||||
|
@ -1521,6 +1791,22 @@ if (sim_brk_char && (buf[0] == sim_brk_char))
|
||||||
else return (buf[0] | SCPE_KFLAG);
|
else return (buf[0] | SCPE_KFLAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t_bool sim_os_poll_kbd_ready (int ms_timeout)
|
||||||
|
{
|
||||||
|
fd_set readfds;
|
||||||
|
struct timeval timeout;
|
||||||
|
|
||||||
|
if (!sim_os_ttisatty()) { /* skip if !tty */
|
||||||
|
sim_os_ms_sleep (ms_timeout);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
FD_ZERO (&readfds);
|
||||||
|
FD_SET (0, &readfds);
|
||||||
|
timeout.tv_sec = (ms_timeout*1000)/1000000;
|
||||||
|
timeout.tv_usec = (ms_timeout*1000)%1000000;
|
||||||
|
return (1 == select (1, &readfds, NULL, NULL, &timeout));
|
||||||
|
}
|
||||||
|
|
||||||
t_stat sim_os_putchar (int32 out)
|
t_stat sim_os_putchar (int32 out)
|
||||||
{
|
{
|
||||||
char c;
|
char c;
|
||||||
|
|
|
@ -55,6 +55,8 @@ t_stat sim_set_console (int32 flag, char *cptr);
|
||||||
t_stat sim_set_kmap (int32 flag, char *cptr);
|
t_stat sim_set_kmap (int32 flag, char *cptr);
|
||||||
t_stat sim_set_telnet (int32 flag, char *cptr);
|
t_stat sim_set_telnet (int32 flag, char *cptr);
|
||||||
t_stat sim_set_notelnet (int32 flag, char *cptr);
|
t_stat sim_set_notelnet (int32 flag, char *cptr);
|
||||||
|
t_stat sim_set_serial (int32 flag, char *cptr);
|
||||||
|
t_stat sim_set_noserial (int32 flag, char *cptr);
|
||||||
t_stat sim_set_logon (int32 flag, char *cptr);
|
t_stat sim_set_logon (int32 flag, char *cptr);
|
||||||
t_stat sim_set_logoff (int32 flag, char *cptr);
|
t_stat sim_set_logoff (int32 flag, char *cptr);
|
||||||
t_stat sim_set_debon (int32 flag, char *cptr);
|
t_stat sim_set_debon (int32 flag, char *cptr);
|
||||||
|
|
86
sim_defs.h
86
sim_defs.h
|
@ -279,6 +279,14 @@ typedef uint32 t_addr;
|
||||||
|
|
||||||
#define MATCH_CMD(ptr,cmd) strncmp ((ptr), (cmd), strlen (ptr))
|
#define MATCH_CMD(ptr,cmd) strncmp ((ptr), (cmd), strlen (ptr))
|
||||||
|
|
||||||
|
/* End of Linked List/Queue value */
|
||||||
|
/* Chosen for 2 reasons: */
|
||||||
|
/* 1 - to not be NULL, this allowing the NULL value to */
|
||||||
|
/* indicate inclusion on a list */
|
||||||
|
/* and */
|
||||||
|
/* 2 - to not be a valid/possible pointer (alignment) */
|
||||||
|
#define QUEUE_LIST_END ((void *)1)
|
||||||
|
|
||||||
/* Device data structure */
|
/* Device data structure */
|
||||||
|
|
||||||
struct sim_device {
|
struct sim_device {
|
||||||
|
@ -380,21 +388,25 @@ struct sim_unit {
|
||||||
#define UNIT_V_UF 16 /* device specific */
|
#define UNIT_V_UF 16 /* device specific */
|
||||||
#define UNIT_V_RSV 31 /* reserved!! */
|
#define UNIT_V_RSV 31 /* reserved!! */
|
||||||
|
|
||||||
#define UNIT_ATTABLE 000001 /* attachable */
|
#define UNIT_ATTABLE 0000001 /* attachable */
|
||||||
#define UNIT_RO 000002 /* read only */
|
#define UNIT_RO 0000002 /* read only */
|
||||||
#define UNIT_FIX 000004 /* fixed capacity */
|
#define UNIT_FIX 0000004 /* fixed capacity */
|
||||||
#define UNIT_SEQ 000010 /* sequential */
|
#define UNIT_SEQ 0000010 /* sequential */
|
||||||
#define UNIT_ATT 000020 /* attached */
|
#define UNIT_ATT 0000020 /* attached */
|
||||||
#define UNIT_BINK 000040 /* K = power of 2 */
|
#define UNIT_BINK 0000040 /* K = power of 2 */
|
||||||
#define UNIT_BUFABLE 000100 /* bufferable */
|
#define UNIT_BUFABLE 0000100 /* bufferable */
|
||||||
#define UNIT_MUSTBUF 000200 /* must buffer */
|
#define UNIT_MUSTBUF 0000200 /* must buffer */
|
||||||
#define UNIT_BUF 000400 /* buffered */
|
#define UNIT_BUF 0000400 /* buffered */
|
||||||
#define UNIT_ROABLE 001000 /* read only ok */
|
#define UNIT_ROABLE 0001000 /* read only ok */
|
||||||
#define UNIT_DISABLE 002000 /* disable-able */
|
#define UNIT_DISABLE 0002000 /* disable-able */
|
||||||
#define UNIT_DIS 004000 /* disabled */
|
#define UNIT_DIS 0004000 /* disabled */
|
||||||
#define UNIT_RAW 010000 /* raw mode */
|
#define UNIT_RAW 0010000 /* raw mode */
|
||||||
#define UNIT_TEXT 020000 /* text mode */
|
#define UNIT_TEXT 0020000 /* text mode */
|
||||||
#define UNIT_IDLE 040000 /* idle eligible */
|
#define UNIT_IDLE 0040000 /* idle eligible */
|
||||||
|
#define UNIT_ATTMULT 0100000 /* Allow multiple attach commands */
|
||||||
|
#define UNIT_TM_POLL 0400000 /* TMXR Polling unit */
|
||||||
|
/* This flag is ONLY set dynamically */
|
||||||
|
/* it should NOT be set via initialization */
|
||||||
|
|
||||||
#define UNIT_UFMASK_31 (((1u << UNIT_V_RSV) - 1) & ~((1u << UNIT_V_UF_31) - 1))
|
#define UNIT_UFMASK_31 (((1u << UNIT_V_RSV) - 1) & ~((1u << UNIT_V_UF_31) - 1))
|
||||||
#define UNIT_UFMASK (((1u << UNIT_V_RSV) - 1) & ~((1u << UNIT_V_UF) - 1))
|
#define UNIT_UFMASK (((1u << UNIT_V_RSV) - 1) & ~((1u << UNIT_V_UF) - 1))
|
||||||
|
@ -573,20 +585,38 @@ extern int32 sim_asynch_check;
|
||||||
extern int32 sim_asynch_latency;
|
extern int32 sim_asynch_latency;
|
||||||
extern int32 sim_asynch_inst_latency;
|
extern int32 sim_asynch_inst_latency;
|
||||||
|
|
||||||
#define AIO_LIST_END ((void *)1) /* Chosen to deliberately not be a valid pointer (alignment) */
|
/* Thread local storage */
|
||||||
|
#if defined(__GNUC__) && !defined(__APPLE__)
|
||||||
|
#define AIO_TLS __thread
|
||||||
|
#elif defined(__DECC_VER) || defined(_MSC_VER)
|
||||||
|
#define AIO_TLS __declspec(thread)
|
||||||
|
#else
|
||||||
|
/* Other compiler environment, then don't worry about thread local storage. */
|
||||||
|
/* It is primarily used only used in debugging messages */
|
||||||
|
#define AIO_TLS
|
||||||
|
#endif
|
||||||
|
|
||||||
#define AIO_INIT \
|
#define AIO_INIT \
|
||||||
if (1) { \
|
if (1) { \
|
||||||
sim_asynch_main_threadid = pthread_self(); \
|
sim_asynch_main_threadid = pthread_self(); \
|
||||||
/* Empty list/list end uses the point value (void *)1. \
|
/* Empty list/list end uses the point value (void *)1. \
|
||||||
This allows NULL in an entry's a_next pointer to \
|
This allows NULL in an entry's a_next pointer to \
|
||||||
indicate that the entry is not currently in any list */ \
|
indicate that the entry is not currently in any list */ \
|
||||||
sim_asynch_queue = AIO_LIST_END; \
|
sim_asynch_queue = QUEUE_LIST_END; \
|
||||||
}
|
} \
|
||||||
|
else \
|
||||||
|
(void)0
|
||||||
#define AIO_CLEANUP \
|
#define AIO_CLEANUP \
|
||||||
if (1) { \
|
if (1) { \
|
||||||
pthread_mutex_destroy(&sim_asynch_lock); \
|
pthread_mutex_destroy(&sim_asynch_lock); \
|
||||||
pthread_cond_destroy(&sim_asynch_wake); \
|
pthread_cond_destroy(&sim_asynch_wake); \
|
||||||
}
|
} \
|
||||||
|
else \
|
||||||
|
(void)0
|
||||||
|
#define AIO_LOCK \
|
||||||
|
pthread_mutex_lock(&sim_asynch_lock)
|
||||||
|
#define AIO_UNLOCK \
|
||||||
|
pthread_mutex_unlock(&sim_asynch_lock)
|
||||||
|
|
||||||
#if defined(__DECC_VER)
|
#if defined(__DECC_VER)
|
||||||
#include <builtins>
|
#include <builtins>
|
||||||
|
@ -616,13 +646,13 @@ extern int32 sim_asynch_inst_latency;
|
||||||
#define AIO_QUEUE_VAL InterlockedCompareExchangePointer(&sim_asynch_queue, sim_asynch_queue, NULL)
|
#define AIO_QUEUE_VAL InterlockedCompareExchangePointer(&sim_asynch_queue, sim_asynch_queue, NULL)
|
||||||
#define AIO_QUEUE_SET(val, queue) InterlockedCompareExchangePointer(&sim_asynch_queue, val, queue)
|
#define AIO_QUEUE_SET(val, queue) InterlockedCompareExchangePointer(&sim_asynch_queue, val, queue)
|
||||||
#define AIO_UPDATE_QUEUE \
|
#define AIO_UPDATE_QUEUE \
|
||||||
if (AIO_QUEUE_VAL != AIO_LIST_END) { /* List !Empty */ \
|
if (AIO_QUEUE_VAL != QUEUE_LIST_END) { /* List !Empty */ \
|
||||||
UNIT *q, *uptr; \
|
UNIT *q, *uptr; \
|
||||||
int32 a_event_time; \
|
int32 a_event_time; \
|
||||||
do \
|
do \
|
||||||
q = AIO_QUEUE_VAL; \
|
q = AIO_QUEUE_VAL; \
|
||||||
while (q != AIO_QUEUE_SET(AIO_LIST_END, q)); \
|
while (q != AIO_QUEUE_SET(QUEUE_LIST_END, q)); \
|
||||||
while (q != AIO_LIST_END) { /* List !Empty */ \
|
while (q != QUEUE_LIST_END) { /* List !Empty */ \
|
||||||
uptr = q; \
|
uptr = q; \
|
||||||
q = q->a_next; \
|
q = q->a_next; \
|
||||||
uptr->a_next = NULL; /* hygiene */ \
|
uptr->a_next = NULL; /* hygiene */ \
|
||||||
|
@ -646,18 +676,18 @@ extern int32 sim_asynch_inst_latency;
|
||||||
UNIT *q, *qe; \
|
UNIT *q, *qe; \
|
||||||
uptr->a_event_time = event_time; \
|
uptr->a_event_time = event_time; \
|
||||||
uptr->a_activate_call = sim_activate; \
|
uptr->a_activate_call = sim_activate; \
|
||||||
uptr->a_next = AIO_LIST_END; /* Mark as on list */ \
|
uptr->a_next = QUEUE_LIST_END; /* Mark as on list */ \
|
||||||
do { \
|
do { \
|
||||||
do \
|
do \
|
||||||
q = AIO_QUEUE_VAL; \
|
q = AIO_QUEUE_VAL; \
|
||||||
while (q != AIO_QUEUE_SET(AIO_LIST_END, q));/* Grab current list */ \
|
while (q != AIO_QUEUE_SET(QUEUE_LIST_END, q));/* Grab current list */\
|
||||||
for (qe = uptr; qe->a_next != AIO_LIST_END; qe = qe->a_next); \
|
for (qe = uptr; qe->a_next != QUEUE_LIST_END; qe = qe->a_next); \
|
||||||
qe->a_next = q; /* append current list */\
|
qe->a_next = q; /* append current list */\
|
||||||
do \
|
do \
|
||||||
q = AIO_QUEUE_VAL; \
|
q = AIO_QUEUE_VAL; \
|
||||||
while (q != AIO_QUEUE_SET(uptr, q)); \
|
while (q != AIO_QUEUE_SET(uptr, q)); \
|
||||||
uptr = q; \
|
uptr = q; \
|
||||||
} while (uptr != AIO_LIST_END); \
|
} while (uptr != QUEUE_LIST_END); \
|
||||||
} \
|
} \
|
||||||
if (sim_idle_wait) \
|
if (sim_idle_wait) \
|
||||||
pthread_cond_signal (&sim_asynch_wake); \
|
pthread_cond_signal (&sim_asynch_wake); \
|
||||||
|
@ -671,7 +701,7 @@ extern int32 sim_asynch_inst_latency;
|
||||||
if (1) { \
|
if (1) { \
|
||||||
UNIT *uptr; \
|
UNIT *uptr; \
|
||||||
pthread_mutex_lock (&sim_asynch_lock); \
|
pthread_mutex_lock (&sim_asynch_lock); \
|
||||||
while (sim_asynch_queue != AIO_LIST_END) { /* List !Empty */ \
|
while (sim_asynch_queue != QUEUE_LIST_END) { /* List !Empty */ \
|
||||||
int32 a_event_time; \
|
int32 a_event_time; \
|
||||||
uptr = sim_asynch_queue; \
|
uptr = sim_asynch_queue; \
|
||||||
sim_asynch_queue = uptr->a_next; \
|
sim_asynch_queue = uptr->a_next; \
|
||||||
|
@ -728,7 +758,9 @@ extern int32 sim_asynch_inst_latency;
|
||||||
#define AIO_CHECK_EVENT
|
#define AIO_CHECK_EVENT
|
||||||
#define AIO_INIT
|
#define AIO_INIT
|
||||||
#define AIO_CLEANUP
|
#define AIO_CLEANUP
|
||||||
|
#define AIO_RETURN_TIME(uptr)
|
||||||
#define AIO_SET_INTERRUPT_LATENCY(instpersec)
|
#define AIO_SET_INTERRUPT_LATENCY(instpersec)
|
||||||
|
#define AIO_TLS
|
||||||
#endif /* SIM_ASYNCH_IO */
|
#endif /* SIM_ASYNCH_IO */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
309
sim_serial.c
309
sim_serial.c
|
@ -41,7 +41,7 @@
|
||||||
|
|
||||||
sim_open_serial open a serial port
|
sim_open_serial open a serial port
|
||||||
sim_config_serial change baud rate and character framing configuration
|
sim_config_serial change baud rate and character framing configuration
|
||||||
sim_control_serial connect or disconnect a serial port (controls DTR)
|
sim_control_serial manipulate and/or return the modem bits on a serial port
|
||||||
sim_read_serial read from a serial port
|
sim_read_serial read from a serial port
|
||||||
sim_write_serial write to a serial port
|
sim_write_serial write to a serial port
|
||||||
sim_close_serial close a serial port
|
sim_close_serial close a serial port
|
||||||
|
@ -60,8 +60,8 @@
|
||||||
returned.
|
returned.
|
||||||
|
|
||||||
|
|
||||||
t_stat sim_config_serial (SERHANDLE port, SERCONFIG config)
|
t_stat sim_config_serial (SERHANDLE port, const char *config)
|
||||||
-----------------------------------------------------------
|
-------------------------------------------------------------
|
||||||
|
|
||||||
The baud rate and framing parameters (character size, parity, and number of
|
The baud rate and framing parameters (character size, parity, and number of
|
||||||
stop bits) of the serial port associated with "port" are set. If any
|
stop bits) of the serial port associated with "port" are set. If any
|
||||||
|
@ -70,13 +70,17 @@
|
||||||
is returned. If the configuration is successful, SCPE_OK is returned.
|
is returned. If the configuration is successful, SCPE_OK is returned.
|
||||||
|
|
||||||
|
|
||||||
t_bool sim_control_serial (SERHANDLE port, t_bool connect)
|
sim_control_serial (SERHANDLE port, int32 bits_to_set, int32 bits_to_clear, int32 *incoming_bits)
|
||||||
----------------------------------------------------------
|
-------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
If "connect" is TRUE, the DTR (modem control) line of the serial port
|
The DTR and RTS line of the serial port is set or cleared as indicated in
|
||||||
associated with "port" is asserted. If "connect" is false, the line is
|
the respective bits_to_set or bits_to_clear parameters. If the
|
||||||
denied. If the DTR change is successful, the function returns TRUE. FALSE
|
incoming_bits parameter is not NULL, then the modem status bits DCD, RNG,
|
||||||
is returned if an error occurs.
|
DSR and CTS are returned.
|
||||||
|
|
||||||
|
If unreasonable or nonsense bits_to_set or bits_to_clear bits are
|
||||||
|
specified, then the return status is SCPE_ARG;
|
||||||
|
If an error occurs, SCPE_IOERR is returned.
|
||||||
|
|
||||||
|
|
||||||
int32 sim_read_serial (SERHANDLE port, char *buffer, int32 count, char *brk)
|
int32 sim_read_serial (SERHANDLE port, char *buffer, int32 count, char *brk)
|
||||||
|
@ -134,9 +138,17 @@ typedef struct serial_list {
|
||||||
char desc[SER_DEV_DESC_MAX];
|
char desc[SER_DEV_DESC_MAX];
|
||||||
} SERIAL_LIST;
|
} SERIAL_LIST;
|
||||||
|
|
||||||
|
typedef struct serial_config { /* serial port configuration */
|
||||||
|
uint32 baudrate; /* baud rate */
|
||||||
|
uint32 charsize; /* character size in bits */
|
||||||
|
char parity; /* parity (N/O/E/M/S) */
|
||||||
|
uint32 stopbits; /* 0/1/2 stop bits (0 implies 1.5) */
|
||||||
|
} SERCONFIG;
|
||||||
|
|
||||||
static int sim_serial_os_devices (int max, SERIAL_LIST* list);
|
static int sim_serial_os_devices (int max, SERIAL_LIST* list);
|
||||||
static SERHANDLE sim_open_os_serial (char *name);
|
static SERHANDLE sim_open_os_serial (char *name);
|
||||||
static void sim_close_os_serial (SERHANDLE port);
|
static void sim_close_os_serial (SERHANDLE port);
|
||||||
|
static t_stat sim_config_os_serial (SERHANDLE port, SERCONFIG config);
|
||||||
|
|
||||||
|
|
||||||
static struct open_serial_device {
|
static struct open_serial_device {
|
||||||
|
@ -147,7 +159,17 @@ static struct open_serial_device {
|
||||||
} *serial_open_devices = NULL;
|
} *serial_open_devices = NULL;
|
||||||
static int serial_open_device_count = 0;
|
static int serial_open_device_count = 0;
|
||||||
|
|
||||||
static void _serial_add_to_open_list (SERHANDLE port, TMLN *line, const char *name, const char *desc)
|
static struct open_serial_device *_get_open_device (SERHANDLE port)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; i<serial_open_device_count; ++i)
|
||||||
|
if (serial_open_devices[i].port == port)
|
||||||
|
return &serial_open_devices[i];
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct open_serial_device *_serial_add_to_open_list (SERHANDLE port, TMLN *line, const char *name, const char *desc)
|
||||||
{
|
{
|
||||||
serial_open_devices = realloc(serial_open_devices, (++serial_open_device_count)*sizeof(*serial_open_devices));
|
serial_open_devices = realloc(serial_open_devices, (++serial_open_device_count)*sizeof(*serial_open_devices));
|
||||||
memset(&serial_open_devices[serial_open_device_count-1], 0, sizeof(serial_open_devices[serial_open_device_count-1]));
|
memset(&serial_open_devices[serial_open_device_count-1], 0, sizeof(serial_open_devices[serial_open_device_count-1]));
|
||||||
|
@ -156,6 +178,7 @@ serial_open_devices[serial_open_device_count-1].line = line;
|
||||||
strcpy(serial_open_devices[serial_open_device_count-1].name, name);
|
strcpy(serial_open_devices[serial_open_device_count-1].name, name);
|
||||||
if (desc)
|
if (desc)
|
||||||
strcpy(serial_open_devices[serial_open_device_count-1].desc, desc);
|
strcpy(serial_open_devices[serial_open_device_count-1].desc, desc);
|
||||||
|
return &serial_open_devices[serial_open_device_count-1];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _serial_remove_from_open_list (SERHANDLE port)
|
static void _serial_remove_from_open_list (SERHANDLE port)
|
||||||
|
@ -336,7 +359,7 @@ else {
|
||||||
if ((len = strlen(list[i].name)) > min)
|
if ((len = strlen(list[i].name)) > min)
|
||||||
min = len;
|
min = len;
|
||||||
for (i=0; i<number; i++)
|
for (i=0; i<number; i++)
|
||||||
fprintf(st," ser%d\t%-*s (%s)\n", i, (int)min, list[i].name, list[i].desc);
|
fprintf(st," ser%d\t%-*s%s%s%s\n", i, (int)min, list[i].name, list[i].desc[0] ? " (" : "", list[i].desc, list[i].desc[0] ? ")" : "");
|
||||||
}
|
}
|
||||||
if (serial_open_device_count) {
|
if (serial_open_device_count) {
|
||||||
int i;
|
int i;
|
||||||
|
@ -345,54 +368,86 @@ if (serial_open_device_count) {
|
||||||
fprintf(st,"Open Serial Devices:\n");
|
fprintf(st,"Open Serial Devices:\n");
|
||||||
for (i=0; i<serial_open_device_count; i++) {
|
for (i=0; i<serial_open_device_count; i++) {
|
||||||
d = sim_serial_getdesc_byname(serial_open_devices[i].name, desc);
|
d = sim_serial_getdesc_byname(serial_open_devices[i].name, desc);
|
||||||
if (d)
|
fprintf(st, " %s\tLn%02d %s%s%s%s\tConfig: %s\n", serial_open_devices[i].line->mp->dptr->name, (int)(serial_open_devices[i].line->mp->ldsc-serial_open_devices[i].line),
|
||||||
fprintf(st, " %s\tLn%02d %s (%s)\n", serial_open_devices[i].line->mp->dptr->name, (int)(serial_open_devices[i].line->mp->ldsc-serial_open_devices[i].line), serial_open_devices[i].line->sername, d);
|
serial_open_devices[i].line->destination, d ? " {" : "", d ? d : "", d ? ")" : "", serial_open_devices[i].line->serconfig);
|
||||||
else
|
|
||||||
fprintf(st, " %s\tLn%02d %s\n", serial_open_devices[i].line->mp->dptr->name, (int)(serial_open_devices[i].line->mp->ldsc-serial_open_devices[i].line), serial_open_devices[i].line->sername);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
SERHANDLE sim_open_serial (char *name, TMLN *lp)
|
SERHANDLE sim_open_serial (char *name, TMLN *lp, t_stat *stat)
|
||||||
{
|
{
|
||||||
char temp1[1024], temp2[1024];
|
char temp1[1024], temp2[1024], devname [1024];
|
||||||
char *savname = name;
|
char *savname = name;
|
||||||
char *savdesc = NULL;
|
char *savdesc = NULL;
|
||||||
SERHANDLE port;
|
SERHANDLE port = INVALID_HANDLE;
|
||||||
|
char *config;
|
||||||
|
t_stat status;
|
||||||
|
|
||||||
|
config = get_glyph_nc (name, devname, ';'); /* separate port name from optional config params */
|
||||||
|
|
||||||
|
if ((config == NULL) || (*config == '\0'))
|
||||||
|
config = "9600-8N1";
|
||||||
|
|
||||||
|
if (stat)
|
||||||
|
*stat = SCPE_OK;
|
||||||
|
|
||||||
/* translate name of type "serX" to real device name */
|
/* translate name of type "serX" to real device name */
|
||||||
if ((strlen(name) <= 5)
|
if ((strlen(devname) <= 5)
|
||||||
&& (tolower(name[0]) == 's')
|
&& (tolower(devname[0]) == 's')
|
||||||
&& (tolower(name[1]) == 'e')
|
&& (tolower(devname[1]) == 'e')
|
||||||
&& (tolower(name[2]) == 'r')
|
&& (tolower(devname[2]) == 'r')
|
||||||
&& (isdigit(name[3]))
|
&& (isdigit(devname[3]))
|
||||||
&& (isdigit(name[4]) || (name[4] == '\0'))
|
&& (isdigit(devname[4]) || (devname[4] == '\0'))
|
||||||
) {
|
) {
|
||||||
int num = atoi(&name[3]);
|
int num = atoi(&devname[3]);
|
||||||
savname = sim_serial_getname(num, temp1);
|
savname = sim_serial_getname(num, temp1);
|
||||||
if (savname == NULL) /* didn't translate */
|
if (savname == NULL) { /* didn't translate */
|
||||||
return INVALID_HANDLE;
|
if (stat)
|
||||||
|
*stat = SCPE_OPENERR;
|
||||||
|
return port;
|
||||||
|
}
|
||||||
savdesc = sim_serial_getdesc_byname (savname, temp2);
|
savdesc = sim_serial_getdesc_byname (savname, temp2);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* are they trying to use device description? */
|
/* are they trying to use device description? */
|
||||||
savname = sim_serial_getname_bydesc(name, temp1);
|
savname = sim_serial_getname_bydesc(devname, temp1);
|
||||||
if (savname == NULL) { /* didn't translate */
|
if (savname == NULL) { /* didn't translate */
|
||||||
/* probably is not serX and has no description */
|
/* probably is not serX and has no description */
|
||||||
savname = sim_serial_getname_byname(name, temp1);
|
savname = sim_serial_getname_byname(devname, temp1);
|
||||||
if (savname == NULL) /* didn't translate */
|
if (savname == NULL) /* didn't translate */
|
||||||
savname = name;
|
savname = devname;
|
||||||
else
|
else
|
||||||
savdesc = sim_serial_getdesc_byname(savname, temp2);
|
savdesc = sim_serial_getdesc_byname(savname, temp2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
savdesc = name;
|
savdesc = devname;
|
||||||
}
|
}
|
||||||
|
|
||||||
port = sim_open_os_serial (savname);
|
port = sim_open_os_serial (savname);
|
||||||
|
|
||||||
|
if (port == INVALID_HANDLE) {
|
||||||
|
if (stat)
|
||||||
|
*stat = SCPE_OPENERR;
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = sim_config_serial (port, config); /* set serial configuration */
|
||||||
|
|
||||||
|
if (status != SCPE_OK) { /* port configuration error? */
|
||||||
|
sim_close_serial (port); /* close the port */
|
||||||
|
if (stat)
|
||||||
|
*stat = status;
|
||||||
|
port = INVALID_HANDLE; /* report error */
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((port != INVALID_HANDLE) && (*config) && (lp)) {
|
||||||
|
lp->serconfig = realloc (lp->serconfig, 1 + strlen (config));
|
||||||
|
strcpy (lp->serconfig, config);
|
||||||
|
}
|
||||||
if (port != INVALID_HANDLE)
|
if (port != INVALID_HANDLE)
|
||||||
_serial_add_to_open_list (port, lp, savname, savdesc);
|
_serial_add_to_open_list (port, lp, savname, config);
|
||||||
|
|
||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -402,11 +457,51 @@ sim_close_os_serial (port);
|
||||||
_serial_remove_from_open_list (port);
|
_serial_remove_from_open_list (port);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Windows serial implementation */
|
t_stat sim_config_serial (SERHANDLE port, const char *sconfig)
|
||||||
|
{
|
||||||
|
const char *pptr;
|
||||||
|
char *sptr, *tptr;
|
||||||
|
SERCONFIG config = { 0 };
|
||||||
|
t_bool arg_error = FALSE;
|
||||||
|
t_stat r;
|
||||||
|
struct open_serial_device *dev;
|
||||||
|
|
||||||
|
if ((sconfig == NULL) || (*sconfig == '\0'))
|
||||||
|
sconfig = "9600-8N1"; /* default settings */
|
||||||
|
pptr = sconfig;
|
||||||
|
|
||||||
|
config.baudrate = (uint32)strtotv (pptr, &sptr, 10); /* parse baud rate */
|
||||||
|
arg_error = (pptr == sptr); /* check for bad argument */
|
||||||
|
|
||||||
|
if (*sptr) /* separator present? */
|
||||||
|
sptr++; /* skip it */
|
||||||
|
|
||||||
|
config.charsize = (uint32)strtotv (sptr, &tptr, 10); /* parse character size */
|
||||||
|
arg_error = arg_error || (sptr == tptr); /* check for bad argument */
|
||||||
|
|
||||||
|
if (*tptr) /* parity character present? */
|
||||||
|
config.parity = toupper (*tptr++); /* save parity character */
|
||||||
|
|
||||||
|
config.stopbits = (uint32)strtotv (tptr, &sptr, 10); /* parse number of stop bits */
|
||||||
|
arg_error = arg_error || (tptr == sptr); /* check for bad argument */
|
||||||
|
|
||||||
|
if (arg_error) /* bad conversions? */
|
||||||
|
return SCPE_ARG; /* report argument error */
|
||||||
|
if (strcmp (sptr, ".5") == 0) /* 1.5 stop bits requested? */
|
||||||
|
config.stopbits = 0; /* code request */
|
||||||
|
|
||||||
|
r = sim_config_os_serial (port, config);
|
||||||
|
dev = _get_open_device (port);
|
||||||
|
if (dev) {
|
||||||
|
dev->line->serconfig = realloc (dev->line->serconfig, 1 + strlen (sconfig));
|
||||||
|
strcpy (dev->line->serconfig, sconfig);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined (_WIN32)
|
#if defined (_WIN32)
|
||||||
|
|
||||||
|
/* Windows serial implementation */
|
||||||
|
|
||||||
/* Enumerate the available serial ports.
|
/* Enumerate the available serial ports.
|
||||||
|
|
||||||
|
@ -566,7 +661,7 @@ return port; /* return port handle on
|
||||||
1.5 stop bits.
|
1.5 stop bits.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
t_stat sim_config_serial (SERHANDLE port, SERCONFIG config)
|
t_stat sim_config_os_serial (SERHANDLE port, SERCONFIG config)
|
||||||
{
|
{
|
||||||
static const struct {
|
static const struct {
|
||||||
char parity;
|
char parity;
|
||||||
|
@ -628,20 +723,54 @@ return SCPE_OK; /* return success status
|
||||||
|
|
||||||
/* Control a serial port.
|
/* Control a serial port.
|
||||||
|
|
||||||
The DTR line of the serial port is set or cleared. If "connect" is true,
|
The DTR and RTS line of the serial port is set or cleared as indicated in
|
||||||
then the line is set to enable the serial device. If "connect" is false, the
|
the respective bits_to_set or bits_to_clear parameters. If the
|
||||||
line is disabled to disconnect the device. If the line change was
|
incoming_bits parameter is not NULL, then the modem status bits DCD, RNG,
|
||||||
successful, the function returns TRUE.
|
DSR and CTS are returned.
|
||||||
|
|
||||||
|
If unreasonable or nonsense bits_to_set or bits_to_clear bits are
|
||||||
|
specified, then the return status is SCPE_ARG;
|
||||||
|
If an error occurs, SCPE_IOERR is returned.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
t_bool sim_control_serial (SERHANDLE port, t_bool connect)
|
t_stat sim_control_serial (SERHANDLE port, int32 bits_to_set, int32 bits_to_clear, int32 *incoming_bits)
|
||||||
{
|
{
|
||||||
if (!EscapeCommFunction (port, connect ? SETDTR : CLRDTR)) {
|
if ((bits_to_set & ~(TMXR_MDM_OUTGOING)) || /* Assure only settable bits */
|
||||||
|
(bits_to_clear & ~(TMXR_MDM_OUTGOING)) ||
|
||||||
|
(bits_to_set & bits_to_clear)) /* and can't set and clear the same bits */
|
||||||
|
return SCPE_ARG;
|
||||||
|
if (bits_to_set&TMXR_MDM_DTR)
|
||||||
|
if (!EscapeCommFunction (port, SETDTR)) {
|
||||||
sim_error_serial ("EscapeCommFunction", (int) GetLastError ());
|
sim_error_serial ("EscapeCommFunction", (int) GetLastError ());
|
||||||
return FALSE;
|
return SCPE_IOERR;
|
||||||
}
|
}
|
||||||
|
if (bits_to_clear&TMXR_MDM_DTR)
|
||||||
return TRUE;
|
if (!EscapeCommFunction (port, CLRDTR)) {
|
||||||
|
sim_error_serial ("EscapeCommFunction", (int) GetLastError ());
|
||||||
|
return SCPE_IOERR;
|
||||||
|
}
|
||||||
|
if (bits_to_set&TMXR_MDM_RTS)
|
||||||
|
if (!EscapeCommFunction (port, SETRTS)) {
|
||||||
|
sim_error_serial ("EscapeCommFunction", (int) GetLastError ());
|
||||||
|
return SCPE_IOERR;
|
||||||
|
}
|
||||||
|
if (bits_to_clear&TMXR_MDM_RTS)
|
||||||
|
if (!EscapeCommFunction (port, CLRRTS)) {
|
||||||
|
sim_error_serial ("EscapeCommFunction", (int) GetLastError ());
|
||||||
|
return SCPE_IOERR;
|
||||||
|
}
|
||||||
|
if (incoming_bits) {
|
||||||
|
DWORD ModemStat;
|
||||||
|
if (GetCommModemStatus (port, &ModemStat)) {
|
||||||
|
sim_error_serial ("GetCommModemStatus", (int) GetLastError ());
|
||||||
|
return SCPE_IOERR;
|
||||||
|
}
|
||||||
|
*incoming_bits = ((ModemStat&MS_CTS_ON) ? TMXR_MDM_CTS : 0) |
|
||||||
|
((ModemStat&MS_DSR_ON) ? TMXR_MDM_DSR : 0) |
|
||||||
|
((ModemStat&MS_RING_ON) ? TMXR_MDM_RNG : 0) |
|
||||||
|
((ModemStat&MS_RLSD_ON) ? TMXR_MDM_DCD : 0);
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -733,11 +862,10 @@ return;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#elif defined (__unix__) || defined(__APPLE__)
|
||||||
|
|
||||||
/* UNIX implementation */
|
/* UNIX implementation */
|
||||||
|
|
||||||
|
|
||||||
#elif defined (__unix__)
|
|
||||||
|
|
||||||
/* Enumerate the available serial ports.
|
/* Enumerate the available serial ports.
|
||||||
|
|
||||||
The serial port names generated by attempting to open /dev/ttyS0 thru
|
The serial port names generated by attempting to open /dev/ttyS0 thru
|
||||||
|
@ -772,6 +900,15 @@ for (i=0; (ports < max) && (i < 64); ++i) {
|
||||||
close (port);
|
close (port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (i=1; (ports < max) && (i < 64); ++i) {
|
||||||
|
sprintf (list[ports].name, "/dev/tty.serial%d", i);
|
||||||
|
port = open (list[ports].name, O_RDWR | O_NOCTTY | O_NONBLOCK); /* open the port */
|
||||||
|
if (port != -1) { /* open OK? */
|
||||||
|
if (isatty (port)) /* is device a TTY? */
|
||||||
|
++ports;
|
||||||
|
close (port);
|
||||||
|
}
|
||||||
|
}
|
||||||
return ports;
|
return ports;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -907,7 +1044,7 @@ return port; /* return port fd for su
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
t_stat sim_config_serial (SERHANDLE port, SERCONFIG config)
|
t_stat sim_config_os_serial (SERHANDLE port, SERCONFIG config)
|
||||||
{
|
{
|
||||||
struct termios tio;
|
struct termios tio;
|
||||||
int32 i;
|
int32 i;
|
||||||
|
@ -983,30 +1120,52 @@ return SCPE_OK; /* configuration set suc
|
||||||
|
|
||||||
/* Control a serial port.
|
/* Control a serial port.
|
||||||
|
|
||||||
The DTR line of the serial port is set or cleared. If "connect" is true,
|
The DTR and RTS line of the serial port is set or cleared as indicated in
|
||||||
then the line is set to enable the serial device. If "connect" is false, the
|
the respective bits_to_set or bits_to_clear parameters. If the
|
||||||
line is disabled to disconnect the device. If the line change was
|
incoming_bits parameter is not NULL, then the modem status bits DCD, RNG,
|
||||||
successful, the function returns TRUE.
|
DSR and CTS are returned.
|
||||||
|
|
||||||
|
If unreasonable or nonsense bits_to_set or bits_to_clear bits are
|
||||||
|
specified, then the return status is SCPE_ARG;
|
||||||
|
If an error occurs, SCPE_IOERR is returned.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
t_bool sim_control_serial (SERHANDLE port, t_bool connect)
|
t_stat sim_control_serial (SERHANDLE port, int32 bits_to_set, int32 bits_to_clear, int32 *incoming_bits)
|
||||||
{
|
{
|
||||||
int request;
|
int bits;
|
||||||
static const int dtr = TIOCM_DTR;
|
|
||||||
|
|
||||||
if (connect) /* request for DTR set? */
|
if ((bits_to_set & ~(TMXR_MDM_OUTGOING)) || /* Assure only settable bits */
|
||||||
request = TIOCMBIS; /* use "set" control request */
|
(bits_to_clear & ~(TMXR_MDM_OUTGOING)) ||
|
||||||
else /* DTR clear */
|
(bits_to_set & bits_to_clear)) /* and can't set and clear the same bits */
|
||||||
request = TIOCMBIC; /* use "clear" control request */
|
return SCPE_ARG;
|
||||||
|
if (bits_to_set) {
|
||||||
if (ioctl (port, request, &dtr)) { /* set or clear the DTR line */
|
bits = ((bits_to_set&TMXR_MDM_DTR) ? TIOCM_DTR : 0) |
|
||||||
if (errno != EINVAL) /* DTR control not supported? */
|
((bits_to_set&TMXR_MDM_RTS) ? TIOCM_RTS : 0);
|
||||||
sim_error_serial ("ioctl", errno); /* no, so report unexpected error */
|
if (ioctl (port, TIOCMBIS, &bits)) { /* set the desired bits */
|
||||||
|
sim_error_serial ("ioctl", errno); /* report unexpected error */
|
||||||
return FALSE; /* return failure status */
|
return SCPE_IOERR; /* return failure status */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bits_to_clear) {
|
||||||
|
bits = ((bits_to_clear&TMXR_MDM_DTR) ? TIOCM_DTR : 0) |
|
||||||
|
((bits_to_clear&TMXR_MDM_RTS) ? TIOCM_RTS : 0);
|
||||||
|
if (ioctl (port, TIOCMBIC, &bits)) { /* clear the desired bits */
|
||||||
|
sim_error_serial ("ioctl", errno); /* report unexpected error */
|
||||||
|
return SCPE_IOERR; /* return failure status */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (incoming_bits) {
|
||||||
|
if (ioctl (port, TIOCMGET, &bits)) { /* get the modem bits */
|
||||||
|
sim_error_serial ("ioctl", errno); /* report unexpected error */
|
||||||
|
return SCPE_IOERR; /* return failure status */
|
||||||
|
}
|
||||||
|
*incoming_bits = ((bits&TIOCM_CTS) ? TMXR_MDM_CTS : 0) |
|
||||||
|
((bits&TIOCM_DSR) ? TMXR_MDM_DSR : 0) |
|
||||||
|
((bits&TIOCM_RNG) ? TMXR_MDM_RNG : 0) |
|
||||||
|
((bits&TIOCM_CAR) ? TMXR_MDM_DCD : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE; /* control request succeeded */
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1109,19 +1268,11 @@ return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
/* Non-implemented stubs */
|
/* Non-implemented stubs */
|
||||||
|
|
||||||
#else
|
/* Enumerate the available serial ports. */
|
||||||
|
|
||||||
/* Enumerate the available serial ports.
|
|
||||||
|
|
||||||
The serial port names are extracted from the appropriate place in the
|
|
||||||
windows registry (HKLM\HARDWARE\DEVICEMAP\SERIALCOMM\). The resulting
|
|
||||||
list is sorted alphabetically by device name (COMn). The device description
|
|
||||||
is set to the OS internal name for the COM device.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int sim_serial_os_devices (int max, SERIAL_LIST* list)
|
static int sim_serial_os_devices (int max, SERIAL_LIST* list)
|
||||||
{
|
{
|
||||||
|
@ -1130,7 +1281,7 @@ return -1;
|
||||||
|
|
||||||
/* Open a serial port */
|
/* Open a serial port */
|
||||||
|
|
||||||
SERHANDLE sim_open_serial (char *name)
|
SERHANDLE sim_open_os_serial (char *name)
|
||||||
{
|
{
|
||||||
return INVALID_HANDLE;
|
return INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
|
@ -1138,7 +1289,7 @@ return INVALID_HANDLE;
|
||||||
|
|
||||||
/* Configure a serial port */
|
/* Configure a serial port */
|
||||||
|
|
||||||
t_stat sim_config_serial (SERHANDLE port, SERCONFIG config)
|
t_stat sim_config_os_serial (SERHANDLE port, SERCONFIG config)
|
||||||
{
|
{
|
||||||
return SCPE_IERR;
|
return SCPE_IERR;
|
||||||
}
|
}
|
||||||
|
@ -1146,9 +1297,9 @@ return SCPE_IERR;
|
||||||
|
|
||||||
/* Control a serial port */
|
/* Control a serial port */
|
||||||
|
|
||||||
t_bool sim_control_serial (SERHANDLE port, t_bool connect)
|
t_stat sim_control_serial (SERHANDLE port, int32 bits_to_set, int32 bits_to_clear, int32 *incoming_bits)
|
||||||
{
|
{
|
||||||
return FALSE;
|
return SCPE_NOFNC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
31
sim_serial.h
31
sim_serial.h
|
@ -30,10 +30,9 @@
|
||||||
#ifndef _SIM_SERIAL_H_
|
#ifndef _SIM_SERIAL_H_
|
||||||
#define _SIM_SERIAL_H_ 0
|
#define _SIM_SERIAL_H_ 0
|
||||||
|
|
||||||
/* Windows definitions */
|
|
||||||
|
|
||||||
#if defined (_WIN32)
|
#if defined (_WIN32)
|
||||||
|
|
||||||
|
/* Windows definitions */
|
||||||
|
|
||||||
/* We need the basic Win32 definitions, but including "windows.h" also includes
|
/* We need the basic Win32 definitions, but including "windows.h" also includes
|
||||||
"winsock.h" as well. However, "sim_sock.h" explicitly includes "winsock2.h,"
|
"winsock.h" as well. However, "sim_sock.h" explicitly includes "winsock2.h,"
|
||||||
|
@ -52,13 +51,12 @@ typedef HANDLE SERHANDLE;
|
||||||
#define INVALID_HANDLE INVALID_HANDLE_VALUE
|
#define INVALID_HANDLE INVALID_HANDLE_VALUE
|
||||||
|
|
||||||
|
|
||||||
|
#elif defined (__unix__) || defined(__APPLE__)
|
||||||
|
|
||||||
/* UNIX definitions */
|
/* UNIX definitions */
|
||||||
|
|
||||||
#elif defined (__unix__)
|
|
||||||
|
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <termio.h>
|
#include <termios.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
@ -67,29 +65,24 @@ typedef int SERHANDLE;
|
||||||
#define INVALID_HANDLE -1
|
#define INVALID_HANDLE -1
|
||||||
|
|
||||||
|
|
||||||
/* Non-implemented definitions */
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
/* Non-implemented definitions */
|
||||||
|
|
||||||
typedef int SERHANDLE;
|
typedef int SERHANDLE;
|
||||||
|
|
||||||
|
#define INVALID_HANDLE -1
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Common definitions */
|
/* Common definitions */
|
||||||
|
|
||||||
typedef struct serial_config { /* serial port configuration */
|
|
||||||
uint32 baudrate; /* baud rate */
|
|
||||||
uint32 charsize; /* character size in bits */
|
|
||||||
char parity; /* parity (N/O/E/M/S) */
|
|
||||||
uint32 stopbits; /* 0/1/2 stop bits (0 implies 1.5) */
|
|
||||||
} SERCONFIG;
|
|
||||||
|
|
||||||
/* Global routines */
|
/* Global routines */
|
||||||
#include "sim_tmxr.h" /* need TMLN definition */
|
#include "sim_tmxr.h" /* need TMLN definition and modem definitions */
|
||||||
|
|
||||||
extern SERHANDLE sim_open_serial (char *name, TMLN *lp);
|
extern SERHANDLE sim_open_serial (char *name, TMLN *lp, t_stat *status);
|
||||||
extern t_stat sim_config_serial (SERHANDLE port, SERCONFIG config);
|
extern t_stat sim_config_serial (SERHANDLE port, const char *config);
|
||||||
extern t_bool sim_control_serial (SERHANDLE port, t_bool connect);
|
extern t_stat sim_control_serial (SERHANDLE port, int32 bits_to_set, int32 bits_to_clear, int32 *incoming_bits);
|
||||||
extern int32 sim_read_serial (SERHANDLE port, char *buffer, int32 count, char *brk);
|
extern int32 sim_read_serial (SERHANDLE port, char *buffer, int32 count, char *brk);
|
||||||
extern int32 sim_write_serial (SERHANDLE port, char *buffer, int32 count);
|
extern int32 sim_write_serial (SERHANDLE port, char *buffer, int32 count);
|
||||||
extern void sim_close_serial (SERHANDLE port);
|
extern void sim_close_serial (SERHANDLE port);
|
||||||
|
|
11
sim_sock.c
11
sim_sock.c
|
@ -23,6 +23,8 @@
|
||||||
used in advertising or otherwise to promote the sale, use or other dealings
|
used in advertising or otherwise to promote the sale, use or other dealings
|
||||||
in this Software without prior written authorization from Robert M Supnik.
|
in this Software without prior written authorization from Robert M Supnik.
|
||||||
|
|
||||||
|
15-Oct-12 MP Added definitions needed to detect possible tcp
|
||||||
|
connect failures
|
||||||
25-Sep-12 MP Reworked for RFC3493 interfaces supporting IPv6 and IPv4
|
25-Sep-12 MP Reworked for RFC3493 interfaces supporting IPv6 and IPv4
|
||||||
22-Jun-10 RMS Fixed types in sim_accept_conn (from Mark Pizzolato)
|
22-Jun-10 RMS Fixed types in sim_accept_conn (from Mark Pizzolato)
|
||||||
19-Nov-05 RMS Added conditional for OpenBSD (from Federico G. Schwindt)
|
19-Nov-05 RMS Added conditional for OpenBSD (from Federico G. Schwindt)
|
||||||
|
@ -538,7 +540,11 @@ if (err != 0)
|
||||||
#if defined(AF_INET6)
|
#if defined(AF_INET6)
|
||||||
load_ws2 ();
|
load_ws2 ();
|
||||||
#endif /* endif AF_INET6 */
|
#endif /* endif AF_INET6 */
|
||||||
#endif /* endif Win32 */
|
#else /* Use native addrinfo APIs */
|
||||||
|
p_getaddrinfo = (void *)getaddrinfo;
|
||||||
|
p_getnameinfo = (void *)getnameinfo;
|
||||||
|
p_freeaddrinfo = (void *)freeaddrinfo;
|
||||||
|
#endif /* endif _WIN32 */
|
||||||
#if defined (SIGPIPE)
|
#if defined (SIGPIPE)
|
||||||
signal (SIGPIPE, SIG_IGN); /* no pipe signals */
|
signal (SIGPIPE, SIG_IGN); /* no pipe signals */
|
||||||
#endif
|
#endif
|
||||||
|
@ -771,6 +777,9 @@ if (rbytes == SOCKET_ERROR) {
|
||||||
err = WSAGetLastError ();
|
err = WSAGetLastError ();
|
||||||
if (err == WSAEWOULDBLOCK) /* no data */
|
if (err == WSAEWOULDBLOCK) /* no data */
|
||||||
return 0;
|
return 0;
|
||||||
|
if ((err != WSAETIMEDOUT) && /* expected errors after a connect failure */
|
||||||
|
(err != WSAEHOSTUNREACH) &&
|
||||||
|
(err != WSAECONNREFUSED))
|
||||||
printf ("Sockets: read error %d\n", err);
|
printf ("Sockets: read error %d\n", err);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
used in advertising or otherwise to promote the sale, use or other dealings
|
used in advertising or otherwise to promote the sale, use or other dealings
|
||||||
in this Software without prior written authorization from Robert M Supnik.
|
in this Software without prior written authorization from Robert M Supnik.
|
||||||
|
|
||||||
|
15-Oct-12 MP Added definitions needed to detect possible tcp
|
||||||
|
connect failures
|
||||||
25-Sep-12 MP Reworked for RFC3493 interfaces supporting IPv6 and IPv4
|
25-Sep-12 MP Reworked for RFC3493 interfaces supporting IPv6 and IPv4
|
||||||
04-Jun-08 RMS Addes sim_create_sock, for IBM 1130
|
04-Jun-08 RMS Addes sim_create_sock, for IBM 1130
|
||||||
14-Apr-05 RMS Added WSAEINPROGRESS (from Tim Riker)
|
14-Apr-05 RMS Added WSAEINPROGRESS (from Tim Riker)
|
||||||
|
@ -54,6 +56,9 @@
|
||||||
#define SOCKET int32
|
#define SOCKET int32
|
||||||
#define WSAEWOULDBLOCK EWOULDBLOCK
|
#define WSAEWOULDBLOCK EWOULDBLOCK
|
||||||
#define WSAEINPROGRESS EINPROGRESS
|
#define WSAEINPROGRESS EINPROGRESS
|
||||||
|
#define WSAETIMEDOUT ETIMEDOUT
|
||||||
|
#define WSAECONNREFUSED ECONNREFUSED
|
||||||
|
#define WSAEHOSTUNREACH EHOSTUNREACH
|
||||||
#define INVALID_SOCKET ((SOCKET)-1)
|
#define INVALID_SOCKET ((SOCKET)-1)
|
||||||
#define SOCKET_ERROR -1
|
#define SOCKET_ERROR -1
|
||||||
#include <sys/types.h> /* for fcntl, getpid */
|
#include <sys/types.h> /* for fcntl, getpid */
|
||||||
|
|
96
sim_timer.c
96
sim_timer.c
|
@ -82,6 +82,8 @@
|
||||||
t_bool sim_idle_enab = FALSE; /* global flag */
|
t_bool sim_idle_enab = FALSE; /* global flag */
|
||||||
volatile t_bool sim_idle_wait = FALSE; /* global flag */
|
volatile t_bool sim_idle_wait = FALSE; /* global flag */
|
||||||
|
|
||||||
|
static int32 sim_calb_tmr = -1; /* the system calibrated timer */
|
||||||
|
|
||||||
static uint32 sim_idle_rate_ms = 0;
|
static uint32 sim_idle_rate_ms = 0;
|
||||||
static uint32 sim_os_sleep_min_ms = 0;
|
static uint32 sim_os_sleep_min_ms = 0;
|
||||||
static uint32 sim_idle_stable = SIM_IDLE_STDFLT;
|
static uint32 sim_idle_stable = SIM_IDLE_STDFLT;
|
||||||
|
@ -866,3 +868,97 @@ switch (sim_throt_state) {
|
||||||
sim_activate (uptr, sim_throt_wait); /* reschedule */
|
sim_activate (uptr, sim_throt_wait); /* reschedule */
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Instruction Execution rate. */
|
||||||
|
/* returns a double since it is mostly used in double expressions and
|
||||||
|
to avoid overflow if/when strange timing delays might produce unexpected results */
|
||||||
|
|
||||||
|
double sim_timer_inst_per_sec (void)
|
||||||
|
{
|
||||||
|
double inst_per_sec = SIM_INITIAL_IPS;
|
||||||
|
|
||||||
|
if (sim_calb_tmr == -1)
|
||||||
|
return inst_per_sec;
|
||||||
|
inst_per_sec = ((double)rtc_currd[sim_calb_tmr])*rtc_hz[sim_calb_tmr];
|
||||||
|
if (0 == inst_per_sec)
|
||||||
|
inst_per_sec = SIM_INITIAL_IPS;
|
||||||
|
return inst_per_sec;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat sim_timer_activate_after (UNIT *uptr, int32 usec_delay)
|
||||||
|
{
|
||||||
|
int32 inst_delay;
|
||||||
|
double inst_per_sec;
|
||||||
|
|
||||||
|
AIO_VALIDATE;
|
||||||
|
if (sim_is_active_bool (uptr)) /* already active? */
|
||||||
|
return SCPE_OK;
|
||||||
|
inst_per_sec = sim_timer_inst_per_sec ();
|
||||||
|
inst_delay = (int32)((inst_per_sec*usec_delay)/1000000.0);
|
||||||
|
#if defined(SIM_ASYNCH_IO) && defined(SIM_ASYNCH_CLOCKS)
|
||||||
|
if ((sim_calb_tmr == -1) || /* if No timer initialized
|
||||||
|
(inst_delay < rtc_currd[sim_calb_tmr]) || /* or sooner than next clock tick? */
|
||||||
|
(rtc_elapsed[sim_calb_tmr] < sim_idle_stable) || /* or not idle stable yet */
|
||||||
|
(!(sim_asynch_enabled && sim_asynch_timer))) { /* or asynch disabled */
|
||||||
|
sim_debug (DBG_TIM, &sim_timer_dev, "sim_timer_activate_after() - activating %s after %d instructions\n",
|
||||||
|
sim_uname(uptr), inst_delay);
|
||||||
|
return _sim_activate (uptr, inst_delay); /* queue it now */
|
||||||
|
}
|
||||||
|
if (1) {
|
||||||
|
struct timespec now;
|
||||||
|
double d_now;
|
||||||
|
|
||||||
|
clock_gettime (CLOCK_REALTIME, &now);
|
||||||
|
d_now = _timespec_to_double (&now);
|
||||||
|
/* Determine if this is a clock tick like invocation
|
||||||
|
or an ocaisional measured device delay */
|
||||||
|
if ((uptr->a_usec_delay == usec_delay) &&
|
||||||
|
(uptr->a_due_time != 0.0) &&
|
||||||
|
(1)) {
|
||||||
|
double d_delay = ((double)usec_delay)/1000000.0;
|
||||||
|
|
||||||
|
uptr->a_due_time += d_delay;
|
||||||
|
if (uptr->a_due_time < (d_now + d_delay*0.1)) { /* Accumulate lost time */
|
||||||
|
uptr->a_skew += (d_now + d_delay*0.1) - uptr->a_due_time;
|
||||||
|
uptr->a_due_time = d_now + d_delay/10.0;
|
||||||
|
if (uptr->a_skew > 30.0) { /* Gap too big? */
|
||||||
|
uptr->a_usec_delay = usec_delay;
|
||||||
|
uptr->a_skew = uptr->a_last_fired_time = 0.0;
|
||||||
|
uptr->a_due_time = d_now + (double)(usec_delay)/1000000.0;
|
||||||
|
}
|
||||||
|
if (uptr->a_skew > rtc_clock_skew_max[sim_calb_tmr])
|
||||||
|
rtc_clock_skew_max[sim_calb_tmr] = uptr->a_skew;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (uptr->a_skew > 0.0) { /* Lost time to make up? */
|
||||||
|
if (uptr->a_skew > d_delay*0.9) {
|
||||||
|
uptr->a_skew -= d_delay*0.9;
|
||||||
|
uptr->a_due_time -= d_delay*0.9;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uptr->a_due_time -= uptr->a_skew;
|
||||||
|
uptr->a_skew = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uptr->a_usec_delay = usec_delay;
|
||||||
|
uptr->a_skew = uptr->a_last_fired_time = 0.0;
|
||||||
|
uptr->a_due_time = d_now + (double)(usec_delay)/1000000.0;
|
||||||
|
}
|
||||||
|
uptr->time = usec_delay;
|
||||||
|
|
||||||
|
sim_debug (DBG_TIM, &sim_timer_dev, "sim_timer_activate_after() - queue addition %s at %.6f\n",
|
||||||
|
sim_uname(uptr), uptr->a_due_time);
|
||||||
|
}
|
||||||
|
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 */
|
||||||
|
return SCPE_OK;
|
||||||
|
#else
|
||||||
|
return _sim_activate (uptr, inst_delay); /* queue it now */
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,9 @@ int clock_gettime(int clock_id, struct timespec *tp);
|
||||||
#define SIM_NTIMERS 8 /* # timers */
|
#define SIM_NTIMERS 8 /* # timers */
|
||||||
#define SIM_TMAX 500 /* max timer makeup */
|
#define SIM_TMAX 500 /* max timer makeup */
|
||||||
|
|
||||||
|
#define SIM_INITIAL_IPS 50000 /* uncalibrated assumption */
|
||||||
|
/* about instructions per second */
|
||||||
|
|
||||||
#define SIM_IDLE_CAL 10 /* ms to calibrate */
|
#define SIM_IDLE_CAL 10 /* ms to calibrate */
|
||||||
#define SIM_IDLE_MAX 10 /* max granularity idle */
|
#define SIM_IDLE_MAX 10 /* max granularity idle */
|
||||||
#define SIM_IDLE_STMIN 10 /* min sec for stability */
|
#define SIM_IDLE_STMIN 10 /* min sec for stability */
|
||||||
|
@ -97,5 +100,7 @@ uint32 sim_os_msec (void);
|
||||||
void sim_os_sleep (unsigned int sec);
|
void sim_os_sleep (unsigned int sec);
|
||||||
uint32 sim_os_ms_sleep (unsigned int msec);
|
uint32 sim_os_ms_sleep (unsigned int msec);
|
||||||
uint32 sim_os_ms_sleep_init (void);
|
uint32 sim_os_ms_sleep_init (void);
|
||||||
|
t_stat sim_timer_activate_after (UNIT *uptr, int32 usec_delay);
|
||||||
|
double sim_timer_inst_per_sec (void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
1639
sim_tmxr.c
1639
sim_tmxr.c
File diff suppressed because it is too large
Load diff
70
sim_tmxr.h
70
sim_tmxr.h
|
@ -26,11 +26,11 @@
|
||||||
Based on the original DZ11 simulator by Thord Nilson, as updated by
|
Based on the original DZ11 simulator by Thord Nilson, as updated by
|
||||||
Arthur Krewat.
|
Arthur Krewat.
|
||||||
|
|
||||||
|
10-Oct-12 MP Added extended attach support for serial, per line
|
||||||
|
listener and outgoing connections
|
||||||
17-Jan-11 MP Added buffered line capabilities
|
17-Jan-11 MP Added buffered line capabilities
|
||||||
20-Nov-08 RMS Added three new standardized SHOW routines
|
20-Nov-08 RMS Added three new standardized SHOW routines
|
||||||
07-Oct-08 JDB [serial] Added serial port support to TMXR, TMLN,
|
07-Oct-08 JDB Added serial port support to TMXR, TMLN
|
||||||
added tmxr_attach_line, tmxr_detach_line,
|
|
||||||
tmxr_line_free, tmxr_mux_free
|
|
||||||
27-May-08 JDB Added lnorder to TMXR structure,
|
27-May-08 JDB Added lnorder to TMXR structure,
|
||||||
added tmxr_set_lnorder and tmxr_set_lnorder
|
added tmxr_set_lnorder and tmxr_set_lnorder
|
||||||
14-May-08 JDB Added dptr to TMXR structure
|
14-May-08 JDB Added dptr to TMXR structure
|
||||||
|
@ -56,8 +56,32 @@
|
||||||
#define TMXR_MAXBUF 256 /* buffer size */
|
#define TMXR_MAXBUF 256 /* buffer size */
|
||||||
#define TMXR_GUARD 12 /* buffer guard */
|
#define TMXR_GUARD 12 /* buffer guard */
|
||||||
|
|
||||||
|
#define TMXR_DTR_DROP_TIME 500 /* milliseconds to drop DTR for 'pseudo' modem control */
|
||||||
|
#define TMXR_CONNECT_POLL_INTERVAL 1000 /* milliseconds between connection polls */
|
||||||
|
|
||||||
#define TMXR_DBG_XMT 0x10000 /* Debug Transmit Data */
|
#define TMXR_DBG_XMT 0x10000 /* Debug Transmit Data */
|
||||||
#define TMXR_DBG_RCV 0x20000 /* Debug Received Data */
|
#define TMXR_DBG_RCV 0x20000 /* Debug Received Data */
|
||||||
|
#define TMXR_DBG_ASY 0x40000 /* Debug Asynchronous Activities */
|
||||||
|
#define TMXR_DBG_TRC 0x80000 /* Debug trace routine calls */
|
||||||
|
|
||||||
|
/* Modem Control Bits */
|
||||||
|
|
||||||
|
#define TMXR_MDM_DTR 0x01 /* Data Terminal Ready */
|
||||||
|
#define TMXR_MDM_RTS 0x02 /* Request To Send */
|
||||||
|
#define TMXR_MDM_DCD 0x04 /* Data Carrier Detect */
|
||||||
|
#define TMXR_MDM_RNG 0x08 /* Ring Indicator */
|
||||||
|
#define TMXR_MDM_CTS 0x10 /* Clear To Send */
|
||||||
|
#define TMXR_MDM_DSR 0x20 /* Data Set Ready */
|
||||||
|
#define TMXR_MDM_INCOMING (TMXR_MDM_DCD|TMXR_MDM_RNG|TMXR_MDM_CTS|TMXR_MDM_DSR) /* Settable Modem Bits */
|
||||||
|
#define TMXR_MDM_OUTGOING (TMXR_MDM_DTR|TMXR_MDM_DTR) /* Settable Modem Bits */
|
||||||
|
|
||||||
|
/* Unit flags */
|
||||||
|
|
||||||
|
#define TMUF_V_NOASYNCH (UNIT_V_UF + 12) /* Asynch Disabled unit */
|
||||||
|
#define TMUF_NOASYNCH (1u << TMUF_V_NOASYNCH) /* This flag can be defined */
|
||||||
|
/* statically in a unit's flag field */
|
||||||
|
/* This will disable the unit from */
|
||||||
|
/* supporting asynchronmous mux behaviors */
|
||||||
|
|
||||||
typedef struct tmln TMLN;
|
typedef struct tmln TMLN;
|
||||||
typedef struct tmxr TMXR;
|
typedef struct tmxr TMXR;
|
||||||
|
@ -65,11 +89,15 @@ typedef struct tmxr TMXR;
|
||||||
struct tmln {
|
struct tmln {
|
||||||
SOCKET conn; /* line conn */
|
SOCKET conn; /* line conn */
|
||||||
char *ipad; /* IP address */
|
char *ipad; /* IP address */
|
||||||
|
SOCKET master; /* line specific master socket */
|
||||||
|
char *port; /* line specific listening port */
|
||||||
|
int32 sessions; /* count of tcp connections received */
|
||||||
uint32 cnms; /* conn time */
|
uint32 cnms; /* conn time */
|
||||||
int32 tsta; /* Telnet state */
|
int32 tsta; /* Telnet state */
|
||||||
int32 rcve; /* rcv enable */
|
int32 rcve; /* rcv enable */
|
||||||
int32 xmte; /* xmt enable */
|
int32 xmte; /* xmt enable */
|
||||||
int32 dstb; /* disable Tlnt bin */
|
int32 dstb; /* disable Tlnt bin */
|
||||||
|
t_bool notelnet; /* raw binary data (no telnet interpretation) */
|
||||||
int32 rxbpr; /* rcv buf remove */
|
int32 rxbpr; /* rcv buf remove */
|
||||||
int32 rxbpi; /* rcv buf insert */
|
int32 rxbpi; /* rcv buf insert */
|
||||||
int32 rxcnt; /* rcv count */
|
int32 rxcnt; /* rcv count */
|
||||||
|
@ -86,8 +114,12 @@ struct tmln {
|
||||||
char rbr[TMXR_MAXBUF]; /* rcv break */
|
char rbr[TMXR_MAXBUF]; /* rcv break */
|
||||||
char *txb; /* xmt buffer */
|
char *txb; /* xmt buffer */
|
||||||
TMXR *mp; /* back pointer to mux */
|
TMXR *mp; /* back pointer to mux */
|
||||||
|
char *serconfig; /* line config */
|
||||||
SERHANDLE serport; /* serial port handle */
|
SERHANDLE serport; /* serial port handle */
|
||||||
char *sername; /* serial port name */
|
SOCKET connecting; /* Outgoing socket while connecting */
|
||||||
|
char *destination; /* Outgoing destination address:port */
|
||||||
|
UNIT *uptr; /* input polling unit (default to mp->uptr) */
|
||||||
|
UNIT *o_uptr; /* output polling unit (default to lp->uptr)*/
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tmxr {
|
struct tmxr {
|
||||||
|
@ -97,14 +129,17 @@ struct tmxr {
|
||||||
TMLN *ldsc; /* line descriptors */
|
TMLN *ldsc; /* line descriptors */
|
||||||
int32 *lnorder; /* line connection order */
|
int32 *lnorder; /* line connection order */
|
||||||
DEVICE *dptr; /* multiplexer device */
|
DEVICE *dptr; /* multiplexer device */
|
||||||
|
UNIT *uptr; /* polling unit (connection) */
|
||||||
char logfiletmpl[FILENAME_MAX]; /* template logfile name */
|
char logfiletmpl[FILENAME_MAX]; /* template logfile name */
|
||||||
int32 buffered; /* Buffered Line Behavior and Buffer Size Flag */
|
int32 buffered; /* Buffered Line Behavior and Buffer Size Flag */
|
||||||
uint32 pending; /* count of pending serial connections */
|
int32 sessions; /* count of tcp connections received */
|
||||||
|
uint32 last_poll_time; /* time of last connection poll */
|
||||||
|
t_bool notelnet; /* default telnet capability for incoming connections */
|
||||||
|
t_bool modem_control; /* multiplexer supports modem control behaviors */
|
||||||
};
|
};
|
||||||
|
|
||||||
int32 tmxr_poll_conn (TMXR *mp);
|
int32 tmxr_poll_conn (TMXR *mp);
|
||||||
void tmxr_reset_ln (TMLN *lp);
|
t_stat tmxr_reset_ln (TMLN *lp);
|
||||||
t_stat tmxr_clear_ln (TMXR *mp, TMLN *lp);
|
|
||||||
int32 tmxr_getc_ln (TMLN *lp);
|
int32 tmxr_getc_ln (TMLN *lp);
|
||||||
void tmxr_poll_rx (TMXR *mp);
|
void tmxr_poll_rx (TMXR *mp);
|
||||||
t_stat tmxr_putc_ln (TMLN *lp, int32 chr);
|
t_stat tmxr_putc_ln (TMLN *lp, int32 chr);
|
||||||
|
@ -114,10 +149,12 @@ t_stat tmxr_open_master (TMXR *mp, char *cptr);
|
||||||
t_stat tmxr_close_master (TMXR *mp);
|
t_stat tmxr_close_master (TMXR *mp);
|
||||||
t_stat tmxr_attach (TMXR *mp, UNIT *uptr, char *cptr);
|
t_stat tmxr_attach (TMXR *mp, UNIT *uptr, char *cptr);
|
||||||
t_stat tmxr_detach (TMXR *mp, UNIT *uptr);
|
t_stat tmxr_detach (TMXR *mp, UNIT *uptr);
|
||||||
t_stat tmxr_attach_line (UNIT *uptr, int32 val, char *cptr, void *desc);
|
t_stat tmxr_set_modem_control_passthru (TMXR *mp);
|
||||||
t_stat tmxr_detach_line (UNIT *uptr, int32 val, char *cptr, void *desc);
|
t_stat tmxr_set_get_modem_bits (TMLN *lp, int32 bits_to_set, int32 bits_to_clear, int32 *incoming_bits);
|
||||||
t_bool tmxr_line_free (TMLN *lp);
|
t_stat tmxr_set_config_line (TMLN *lp, char *config);
|
||||||
t_bool tmxr_mux_free (TMXR *mp);
|
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_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
|
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);
|
t_stat tmxr_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
|
||||||
void tmxr_msg (SOCKET sock, char *msg);
|
void tmxr_msg (SOCKET sock, char *msg);
|
||||||
|
@ -135,7 +172,16 @@ t_stat tmxr_show_lnorder (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||||
t_stat tmxr_show_summ (FILE *st, UNIT *uptr, int32 val, void *desc);
|
t_stat tmxr_show_summ (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||||
t_stat tmxr_show_cstat (FILE *st, UNIT *uptr, int32 val, void *desc);
|
t_stat tmxr_show_cstat (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||||
t_stat tmxr_show_lines (FILE *st, UNIT *uptr, int32 val, void *desc);
|
t_stat tmxr_show_lines (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||||
void tmxr_debug (uint32 dbits, TMLN *lp, const char *msg, char *buf, int bufsize);
|
t_stat tmxr_show_open_devices (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, char* desc);
|
||||||
|
t_stat tmxr_startup (void);
|
||||||
|
t_stat tmxr_shutdown (void);
|
||||||
|
t_stat tmxr_start_poll (void);
|
||||||
|
t_stat tmxr_stop_poll (void);
|
||||||
|
void _tmxr_debug (uint32 dbits, TMLN *lp, const char *msg, char *buf, int bufsize);
|
||||||
|
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
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue