mirror of
https://github.com/open-simh/simh.git
synced 2026-02-28 17:29:55 +00:00
HP3000: HP 3000 release 7
See HP3000/hp3000_release.txt for details of the release
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
/* hp3000_atc.c: HP 3000 30032B Asynchronous Terminal Controller simulator
|
||||
|
||||
Copyright (c) 2014-2016, J. David Bryan
|
||||
Copyright (c) 2014-2017, J. David Bryan
|
||||
Copyright (c) 2002-2012, Robert M Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@@ -26,6 +26,10 @@
|
||||
|
||||
ATCD,ATCC HP 30032B Asynchronous Terminal Controller
|
||||
|
||||
18-Dec-17 JDB Return event time instead of status from "activate_unit"
|
||||
11-Dec-17 JDB Reschedule "line_service" if receive buffer has data
|
||||
26-Oct-17 JDB Call "tmxr_poll_tx" if transmit buffer is full
|
||||
05-Sep-17 JDB Changed REG_A (permit any symbolic override) to REG_X
|
||||
16-Sep-16 JDB Fixed atcd_detach to skip channel cancel if SIM_SW_REST
|
||||
12-Sep-16 JDB Changed DIB register macro usage from SRDATA to DIB_REG
|
||||
20-Jul-16 JDB Corrected poll_unit "wait" field initializer.
|
||||
@@ -782,7 +786,7 @@ static void tci_master_reset (void);
|
||||
|
||||
static t_stat line_service (UNIT *uptr);
|
||||
static t_stat poll_service (UNIT *uptr);
|
||||
static t_stat activate_unit (UNIT *uptr, ACTIVATOR reason);
|
||||
static int32 activate_unit (UNIT *uptr, ACTIVATOR reason);
|
||||
static uint32 service_time (HP_WORD control, ACTIVATOR reason);
|
||||
static void store (HP_WORD control, HP_WORD data);
|
||||
static void receive (int32 channel, int32 data, t_bool loopback);
|
||||
@@ -926,17 +930,17 @@ static REG atcd_reg [] = {
|
||||
/* ------ ------ ------------------- ----- ----- ------ ---------------- --------------- */
|
||||
{ ORDATA (CNTL, tdi_control_word, 16), REG_FIT },
|
||||
{ ORDATA (STAT, tdi_status_word, 16), REG_FIT },
|
||||
{ ORDATA (READ, tdi_read_word, 16), REG_A | REG_FIT },
|
||||
{ ORDATA (WRITE, tdi_write_word, 16), REG_A | REG_FIT },
|
||||
{ ORDATA (READ, tdi_read_word, 16), REG_X | REG_FIT },
|
||||
{ ORDATA (WRITE, tdi_write_word, 16), REG_X | REG_FIT },
|
||||
{ FLDATA (FLAG, tdi_data_flag, 0) },
|
||||
{ FLDATA (MASK, tdi_interrupt_mask, 0) },
|
||||
{ DRDATA (FTIME, fast_data_time, 24), PV_LEFT },
|
||||
{ BRDATA (RSTAT, recv_status, 8, 16, RECV_CHAN_COUNT) },
|
||||
{ BRDATA (RPARM, recv_param, 8, 16, RECV_CHAN_COUNT) },
|
||||
{ BRDATA (RBUFR, recv_buffer, 8, 16, RECV_CHAN_COUNT), REG_A },
|
||||
{ BRDATA (RBUFR, recv_buffer, 8, 16, RECV_CHAN_COUNT), REG_X },
|
||||
{ BRDATA (SSTAT, send_status, 8, 16, SEND_CHAN_COUNT) },
|
||||
{ BRDATA (SPARM, send_param, 8, 16, SEND_CHAN_COUNT) },
|
||||
{ BRDATA (SBUFR, send_buffer, 8, 16, SEND_CHAN_COUNT), REG_A },
|
||||
{ BRDATA (SBUFR, send_buffer, 8, 16, SEND_CHAN_COUNT), REG_X },
|
||||
{ FLDATA (POLL, atc_is_polling, 0), REG_HRO },
|
||||
|
||||
DIB_REGS (atcd_dib),
|
||||
@@ -1723,6 +1727,7 @@ tdi_master_reset (); /* perform a master rese
|
||||
if (sim_switches & SWMASK ('P')) { /* if this is a power-on reset */
|
||||
sim_rtcn_init (poll_unit.wait, TMR_ATC); /* then initialize the poll timer */
|
||||
fast_data_time = FAST_IO_TIME; /* restore the initial fast data time */
|
||||
atcd_ldsc [0].xmte = 1; /* enable transmission on the system console port */
|
||||
}
|
||||
|
||||
if (atc_is_polling) { /* if we're polling for the simulation console */
|
||||
@@ -1825,6 +1830,14 @@ return status;
|
||||
unit 16 if it is attached. In all cases, it is imperative that we not reject
|
||||
the request for unit 16; otherwise any remaining device detaches will not be
|
||||
performed.
|
||||
|
||||
|
||||
Implementation notes:
|
||||
|
||||
1. Detaching the multiplexer resets each line first, which flushes the
|
||||
output buffer. This ensures that buffered data that has not been output
|
||||
via a poll_service entry before the DETACH command was issued is written
|
||||
before the line is disconnected.
|
||||
*/
|
||||
|
||||
static t_stat atcd_detach (UNIT *uptr)
|
||||
@@ -1975,8 +1988,9 @@ return;
|
||||
The channel service routine runs only when there are characters to read or
|
||||
write. It is scheduled either at a realistic rate corresponding to the
|
||||
programmed baud rate of the channel to be serviced, or at a somewhat faster
|
||||
optimized rate. It is entered when a channel buffer is ready for output or
|
||||
when the poll routine determines that there are characters ready for input.
|
||||
optimized rate. It is entered when a channel buffer is ready for output,
|
||||
when the poll routine determines that there are characters ready for input,
|
||||
or while waiting for an ACK to complete an ENQ/ACK handshake.
|
||||
|
||||
On entry, the receive channel buffer is checked for a character. If one is
|
||||
not already present, then the terminal multiplexer library is called to
|
||||
@@ -1984,6 +1998,12 @@ return;
|
||||
processed. If the receive channel has its "diagnose" bit set, the character
|
||||
is also passed to the auxiliary channels.
|
||||
|
||||
If a received character is not available, then the unit's "wait" field is
|
||||
checked to see if an ACK is expected in reply to an earlier ENQ. If a wait
|
||||
time is present, it is doubled, and the service is rescheduled. However, if
|
||||
the new wait time is longer than the current poll time, service rescheduling
|
||||
is abandoned in favor of the normal poll for received characters.
|
||||
|
||||
The send channel buffer is then checked for a character to output. If one is
|
||||
present, then if it is an all-mark (sync) character, it is discarded, as the
|
||||
receiver would never see it. Otherwise, if the TDI is in diagnostic mode,
|
||||
@@ -1998,18 +2018,36 @@ return;
|
||||
simulation console (if output is to channel 0) or to the terminal multiplexer
|
||||
library for output via Telnet or a serial port on the host machine. If the
|
||||
channel has its "diagnose" bit set, the character is also passed to the
|
||||
auxiliary channels.
|
||||
auxiliary channels. If an ENQ was transmitted, service is rescheduled to
|
||||
wait for reception of the ACK.
|
||||
|
||||
If the data flag is clear, the indicated receive and send channels are
|
||||
checked for completion flags. If either is set, an interrupt is requested.
|
||||
|
||||
If characters remain in the Telnet receive buffer, the service routine is
|
||||
rescheduled to receive the next one. Otherwise, the routine goes idle until
|
||||
the next character is output or the next poll determines that there are
|
||||
characters to receive.
|
||||
|
||||
|
||||
Implementation notes:
|
||||
|
||||
1. Calling "tmxr_getc_ln" for channel 0 is OK, as reception is disabled by
|
||||
1. The "wait" fields of the channel units are not used (i.e., are set to
|
||||
zero) except when channels are waiting for ACKs. Because we want to
|
||||
retrieve the ACK as quickly as possible but also minimize the load on the
|
||||
host system, we initially wait the normal reception time (fast or
|
||||
realistic) and then double the wait each time it expires without
|
||||
reception. Therefore, a non-zero "wait" value indicates that an ACK is
|
||||
expected.
|
||||
|
||||
2. Receipt of any character cancels a pending ACK wait, even though it is
|
||||
possible that the character is not an ACK (for example, if the character
|
||||
was received but not processed before the ENQ was sent).
|
||||
|
||||
3. Calling "tmxr_getc_ln" for channel 0 is OK, as reception is disabled by
|
||||
default and therefore will return 0.
|
||||
|
||||
2. The send channel buffer will always be non-zero if a character is present
|
||||
4. The send channel buffer will always be non-zero if a character is present
|
||||
(even a NUL) because the data word will have DDS_IS_SEND set.
|
||||
|
||||
The receive buffer will always be non-zero if a character is present
|
||||
@@ -2018,27 +2056,45 @@ return;
|
||||
TMXR_VALID set, and characters looped back from sending will have
|
||||
DDS_IS_SEND set.
|
||||
|
||||
3. Reception of a loopback character is performed immediately because the
|
||||
5. Reception of a loopback character is performed immediately because the
|
||||
reception occurs concurrently with transmission. Reception of a locally
|
||||
generated ACK is scheduled with a one-character delay to reflect the
|
||||
remote device transmission delay.
|
||||
|
||||
4. If storing an ACK locally overwrites a character already present but not
|
||||
6. If storing an ACK locally overwrites a character already present but not
|
||||
yet processed, then the receive routine will set the character lost flag.
|
||||
|
||||
5. Both TMXR_VALID and SCPE_KFLAG are set on internally generated ACKs only
|
||||
7. Both TMXR_VALID and SCPE_KFLAG are set on internally generated ACKs only
|
||||
so that a debug trace will record the generation correctly.
|
||||
|
||||
6. The console library "sim_putchar_s" routine and the terminal multiplexer
|
||||
library "tmxr_putc_ln" routine return SCPE_STALL if the Telnet output
|
||||
buffer is full. In this case, transmission is rescheduled with a delay
|
||||
to allow the buffer to drain.
|
||||
8. The console library "sim_putchar_s" routine and the terminal multiplexer
|
||||
library "tmxr_putc_ln" routine return SCPE_STALL if they are called when
|
||||
the transmit buffer is full. When called to add the last character to
|
||||
the buffer, the routines return SCPE_OK but also change the "xmte" field
|
||||
of the terminal multiplexer line (TMLN) structure from 1 to 0 to indicate
|
||||
that further calls will be rejected; the value is set back to 1 when the
|
||||
transmit buffer empties.
|
||||
|
||||
They also return SCPE_LOST if the line has been dropped on the remote
|
||||
end. We ignore the error here to allow the simulation to continue while
|
||||
ignoring the output.
|
||||
Entry with the transmit buffer full causes the service to be rescheduled
|
||||
to retry the write after a short delay. The "tmxr_poll_tx" routine must
|
||||
be called in this case, as it is responsible for transmitting the buffer
|
||||
contents and therefore freeing space in the buffer.
|
||||
|
||||
7. The receive/send completion flag (buffer flag) will not set unless the
|
||||
Both library "put" routines also return SCPE_LOST if the line has been
|
||||
dropped on the remote end. We ignore that error here to allow the
|
||||
simulation to continue while ignoring the output to a disconnected
|
||||
terminal.
|
||||
|
||||
9. Characters written using "tmxr_putc_ln" are buffered and not transmitted
|
||||
until the buffer is full, the character is an ENQ (and so we will be
|
||||
waiting to receive an ACK), or the next input poll is performed. The
|
||||
last case ensures that the buffer is flushed when output is complete, as
|
||||
there is no indication from the CPU that the last character has been
|
||||
sent. This does incur a delay of up to 10 milliseconds, but this is
|
||||
imperceptible by the user. Buffering offers significantly better
|
||||
throughput compared to transmitting each character as it is written.
|
||||
|
||||
10. The receive/send completion flag (buffer flag) will not set unless the
|
||||
interrupt enable flag for that channel is also set. If enable is not
|
||||
set, the completion indication will be lost.
|
||||
*/
|
||||
@@ -2057,18 +2113,36 @@ dprintf (atcd_dev, DEB_SERV, "Channel %d service entered\n",
|
||||
|
||||
/* Reception service */
|
||||
|
||||
recv_data = recv_buffer [channel]; /* get the current buffer character */
|
||||
recv_data = recv_buffer [channel]; /* get the current buffer character */
|
||||
|
||||
if (recv_data == 0) /* if there's none present */
|
||||
recv_data = tmxr_getc_ln (&atcd_ldsc [channel]); /* then see if there's a character ready via Telnet */
|
||||
if (recv_data == 0) { /* if no character is present */
|
||||
if (uptr->wait) /* then if the channel is waiting for an ACK */
|
||||
tmxr_poll_rx (&atcd_mdsc); /* then poll the line to see if it has arrived */
|
||||
|
||||
if (recv_data & ~DDR_DATA_MASK) { /* if we now have a valid character */
|
||||
receive (channel, recv_data, loopback); /* then process the reception */
|
||||
|
||||
if (recv_param [channel] & DPI_DIAGNOSE) /* if a diagnosis is requested */
|
||||
diagnose (recv_param [channel], recv_data); /* then route the data to the auxiliary channels */
|
||||
recv_data = tmxr_getc_ln (&atcd_ldsc [channel]); /* see if there's now a character ready */
|
||||
}
|
||||
|
||||
if (recv_data & ~DDR_DATA_MASK) { /* if we now have a valid character */
|
||||
receive (channel, recv_data, loopback); /* then process the reception */
|
||||
|
||||
if (recv_param [channel] & DPI_DIAGNOSE) /* if a diagnosis is requested */
|
||||
diagnose (recv_param [channel], recv_data); /* then route the data to the auxiliary channels */
|
||||
|
||||
uptr->wait = 0; /* clear any pending ACK wait */
|
||||
}
|
||||
|
||||
else if (uptr->wait) { /* otherwise if an ACK is expected but has not arrived */
|
||||
uptr->wait = uptr-> wait * 2; /* then double the wait time for the next check */
|
||||
|
||||
if (uptr->wait < poll_unit.wait) { /* if the wait is shorter than the standard poll wait */
|
||||
sim_activate (uptr, uptr->wait); /* then reschedule the line service */
|
||||
|
||||
dprintf (atcd_dev, DEB_SERV, "Channel %d delay %d service rescheduled for ACK\n",
|
||||
channel, uptr->wait);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Transmission service */
|
||||
|
||||
if (send_buffer [channel]) { /* if data is available to send */
|
||||
@@ -2132,43 +2206,56 @@ if (send_buffer [channel]) { /* if data is availa
|
||||
cvtd_data = sim_tt_outcvt (LOWER_BYTE (send_data), /* so convert it as directed */
|
||||
TT_GET_MODE (uptr->flags)); /* by the output mode flag */
|
||||
|
||||
if (cvtd_data >= 0) /* if the converted character is printable */
|
||||
if (channel == 0) /* then if we are writing to channel 0 */
|
||||
result = sim_putchar_s (cvtd_data); /* then output it to the simulation console */
|
||||
else /* otherwise */
|
||||
result = tmxr_putc_ln (&atcd_ldsc [channel], /* output it to the multiplexer line */
|
||||
cvtd_data);
|
||||
|
||||
if (result == SCPE_STALL) { /* if the buffer is full */
|
||||
if (cvtd_data >= 0 && atcd_ldsc [channel].xmte == 0) { /* if it's printable but the transmit buffer is full */
|
||||
activate_unit (uptr, Stall); /* then retry the output a while later */
|
||||
result = SCPE_OK; /* and return OK to continue */
|
||||
|
||||
tmxr_poll_tx (&atcd_mdsc); /* transmit the line buffer */
|
||||
|
||||
dprintf (atcd_dev, DEB_XFER, "Channel %d character %s transmission stalled for full buffer\n",
|
||||
channel, fmt_char (cvtd_data));
|
||||
}
|
||||
|
||||
else if (result == SCPE_OK || result == SCPE_LOST) { /* otherwise if the character is queued to transmit */
|
||||
tmxr_poll_tx (&atcd_mdsc); /* then send (or ignore) it */
|
||||
else { /* otherwise the character will be consumed */
|
||||
if (cvtd_data >= 0) /* if the converted character is printable */
|
||||
if (channel == 0) /* then if we are writing to channel 0 */
|
||||
result = sim_putchar_s (cvtd_data); /* then output it to the simulation console */
|
||||
|
||||
if (DPRINTING (atcd_dev, DEB_XFER))
|
||||
if (result == SCPE_LOST)
|
||||
hp_debug (&atcd_dev, DEB_XFER, "Channel %d character %s discarded by connection loss\n",
|
||||
channel, fmt_char (char_data));
|
||||
else { /* otherwise */
|
||||
result = tmxr_putc_ln (&atcd_ldsc [channel], /* output it to the multiplexer line */
|
||||
cvtd_data);
|
||||
|
||||
else if (cvtd_data >= 0)
|
||||
hp_debug (&atcd_dev, DEB_XFER, "Channel %d character %s sent\n",
|
||||
channel, fmt_char (cvtd_data));
|
||||
if (char_data == ENQ /* if sending an ENQ */
|
||||
|| atcd_ldsc [channel].xmte == 0) /* or the output buffer is full */
|
||||
tmxr_poll_tx (&atcd_mdsc); /* then transmit the line buffer */
|
||||
}
|
||||
|
||||
else
|
||||
hp_debug (&atcd_dev, DEB_XFER, "Channel %d character %s discarded by output filter\n",
|
||||
channel, fmt_char (char_data));
|
||||
if (result == SCPE_OK || result == SCPE_LOST) { /* if the character is queued to transmit */
|
||||
if (DPRINTING (atcd_dev, DEB_XFER))
|
||||
if (result == SCPE_LOST)
|
||||
hp_debug (&atcd_dev, DEB_XFER, "Channel %d character %s discarded by connection loss\n",
|
||||
channel, fmt_char (char_data));
|
||||
|
||||
if (send_param [channel] & DPI_DIAGNOSE) /* if a diagnosis is requested */
|
||||
diagnose (send_param [channel], send_data); /* then route the data to the auxiliary channels */
|
||||
else if (cvtd_data >= 0)
|
||||
hp_debug (&atcd_dev, DEB_XFER, "Channel %d character %s sent\n",
|
||||
channel, fmt_char (cvtd_data));
|
||||
|
||||
send_buffer [channel] = 0; /* clear the buffer */
|
||||
else
|
||||
hp_debug (&atcd_dev, DEB_XFER, "Channel %d character %s discarded by output filter\n",
|
||||
channel, fmt_char (char_data));
|
||||
|
||||
if (send_param [channel] & DPI_ENABLE_IRQ) /* if this channel is enabled to interrupt */
|
||||
send_status [channel] |= DST_COMPLETE; /* then set the completion flag */
|
||||
if (send_param [channel] & DPI_DIAGNOSE) /* if a diagnosis is requested */
|
||||
diagnose (send_param [channel], send_data); /* then route the data to the auxiliary channels */
|
||||
|
||||
result = SCPE_OK; /* return OK in case the connection was lost */
|
||||
send_buffer [channel] = 0; /* clear the buffer */
|
||||
|
||||
if (send_param [channel] & DPI_ENABLE_IRQ) /* if this channel is enabled to interrupt */
|
||||
send_status [channel] |= DST_COMPLETE; /* then set the completion flag */
|
||||
|
||||
if (cvtd_data == ENQ && result == SCPE_OK) /* if an ENQ was successfully sent */
|
||||
uptr->wait = activate_unit (uptr, Receive); /* then schedule the ACK reception */
|
||||
|
||||
result = SCPE_OK; /* return OK in case the connection was lost */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2177,6 +2264,9 @@ if (send_buffer [channel]) { /* if data is availa
|
||||
if (tdi_data_flag == CLEAR) /* if an interrupt is not currently pending */
|
||||
scan_channels (channel); /* then scan the channels for completion flags */
|
||||
|
||||
if (tmxr_rqln (&atcd_ldsc [channel])) /* if characters are still available on this channel */
|
||||
activate_unit (uptr, Receive); /* then reschedule the line service */
|
||||
|
||||
return result; /* return the result of the service */
|
||||
}
|
||||
|
||||
@@ -2184,10 +2274,9 @@ return result; /* return the result of
|
||||
/* Multiplexer poll service.
|
||||
|
||||
The poll service routine is used to poll for Telnet connections and incoming
|
||||
characters. It also polls the simulation console for channel 0. Polling
|
||||
starts at simulator startup or when the TDI is enabled and stops when it is
|
||||
disabled.
|
||||
|
||||
characters. It also polls the simulation console for channel 0 and flushes
|
||||
the output buffers for all channels. Polling starts at simulator startup or
|
||||
when the TDI is enabled and stops when it is disabled.
|
||||
|
||||
Implementation notes:
|
||||
|
||||
@@ -2200,20 +2289,30 @@ return result; /* return the result of
|
||||
may be shorter than the channel service time, and as the console provides
|
||||
no buffering, a second character received before the channel service had
|
||||
been entered would be lost.
|
||||
|
||||
3. A channel that is waiting for an ACK to complete an ENQ/ACK handshake has
|
||||
its unit "wait" field set non-zero. If the field value is greater than
|
||||
the realistic reception time, then the line service is scheduled
|
||||
immediately, as the channel has already waited the minimum time necessary
|
||||
(the "wait" field value is doubled each time the line service is entered
|
||||
before the ACK has been received). Otherwise, the service is scheduled
|
||||
using the normal reception time.
|
||||
*/
|
||||
|
||||
static t_stat poll_service (UNIT *uptr)
|
||||
{
|
||||
int32 chan, line_state;
|
||||
int32 chan, line_state;
|
||||
t_stat status = SCPE_OK;
|
||||
|
||||
dprintf (atcd_dev, DEB_PSERV, "Poll service entered\n");
|
||||
dprintf (atcd_dev, DEB_PSERV, "Poll delay %d service entered\n",
|
||||
uptr->wait);
|
||||
|
||||
if ((atcc_dev.flags & DEV_DIS) == 0)
|
||||
dprintf (atcc_dev, DEB_PSERV, "Poll service entered\n");
|
||||
dprintf (atcc_dev, DEB_PSERV, "Poll delay %d service entered\n",
|
||||
uptr->wait);
|
||||
|
||||
if ((atcd_dev.flags & DEV_DIAG) == 0) { /* if we're not in diagnostic mode */
|
||||
chan = tmxr_poll_conn (&atcd_mdsc); /* then check for a new multiplex connection */
|
||||
chan = tmxr_poll_conn (&atcd_mdsc); /* then check for a new multiplexer connection */
|
||||
|
||||
if (chan != -1) { /* if a new connection was established */
|
||||
atcd_ldsc [chan].rcve = TRUE; /* then enable the channel to receive */
|
||||
@@ -2223,7 +2322,8 @@ if ((atcd_dev.flags & DEV_DIAG) == 0) { /* if we're not in diagn
|
||||
}
|
||||
}
|
||||
|
||||
tmxr_poll_rx (&atcd_mdsc); /* poll the multiplex connections for input */
|
||||
tmxr_poll_tx (&atcd_mdsc); /* flush the multiplexer output buffers */
|
||||
tmxr_poll_rx (&atcd_mdsc); /* and poll the multiplexer connections for input */
|
||||
|
||||
if ((atcc_dev.flags & (DEV_DIAG | DEV_DIS)) == 0) /* if we're not in diagnostic mode or are disabled */
|
||||
for (chan = FIRST_TERM; chan <= LAST_TERM; chan++) /* then scan the channels for line state changes */
|
||||
@@ -2257,9 +2357,15 @@ if (status >= SCPE_KFLAG) { /* if a character was pr
|
||||
line_service (&line_unit [0]); /* run the system console's I/O service */
|
||||
}
|
||||
|
||||
for (chan = FIRST_TERM; chan <= LAST_TERM; chan++) /* check each of the receive channels for available input */
|
||||
if (tmxr_rqln (&atcd_ldsc [chan])) /* if characters are available on this channel */
|
||||
activate_unit (&line_unit [chan], Receive); /* then activate the channel's I/O service */
|
||||
for (chan = FIRST_TERM; chan <= LAST_TERM; chan++) /* check each of the channels for available input */
|
||||
if (tmxr_rqln (&atcd_ldsc [chan])) /* if characters are available on this channel */
|
||||
if (line_unit [chan].wait > line_unit [chan].recv_time) { /* then if the channel is waiting for an ACK */
|
||||
sim_cancel (&line_unit [chan]); /* then cancel any current wait */
|
||||
activate_unit (&line_unit [chan], Loop); /* and activate the line service immediately */
|
||||
}
|
||||
|
||||
else /* otherwise this is a normal input */
|
||||
activate_unit (&line_unit [chan], Receive); /* so schedule with the normal receive timing */
|
||||
|
||||
if (cpu_is_calibrated) /* if the process clock is calibrated */
|
||||
uptr->wait = sim_activate_time (cpu_pclk_uptr); /* then synchronize with it */
|
||||
@@ -2291,7 +2397,7 @@ return status; /* return the service st
|
||||
called.
|
||||
*/
|
||||
|
||||
static t_stat activate_unit (UNIT *uptr, ACTIVATOR reason)
|
||||
static int32 activate_unit (UNIT *uptr, ACTIVATOR reason)
|
||||
{
|
||||
const int32 channel = (int32) (uptr - line_unit); /* the channel number */
|
||||
int32 delay = 0;
|
||||
@@ -2339,7 +2445,8 @@ else /* otherwise, we are in
|
||||
dprintf (atcd_dev, DEB_SERV, "Channel %d delay %d service scheduled\n",
|
||||
channel, delay);
|
||||
|
||||
return sim_activate (uptr, delay); /* activate the unit and return the activation status */
|
||||
sim_activate (uptr, delay); /* activate the unit */
|
||||
return delay; /* and return the activation delay */
|
||||
}
|
||||
|
||||
|
||||
@@ -2639,17 +2746,20 @@ else { /* otherwise a normal ch
|
||||
recv_buffer [channel] = recv_data | pad; /* and replace the character in the buffer */
|
||||
}
|
||||
|
||||
if (recv_param [channel] & DPI_ENABLE_ECHO) { /* if the channel has echo enabled */
|
||||
char_echo = sim_tt_outcvt (recv_data, /* then convert the character per the output mode */
|
||||
if (recv_param [channel] & DPI_ENABLE_ECHO) { /* if the channel has echo enabled */
|
||||
char_echo = sim_tt_outcvt (recv_data, /* then convert the character per the output mode */
|
||||
TT_GET_MODE (line_unit [channel].flags));
|
||||
|
||||
if (char_echo >= 0) { /* if the converted character is valid for the mode */
|
||||
if (channel == 0) /* then if this is for channel 0 */
|
||||
sim_putchar (char_echo); /* then write it back to the simulation console */
|
||||
if (char_echo >= 0) { /* if the converted character is valid for the mode */
|
||||
if (channel == 0) /* then if this is for channel 0 */
|
||||
sim_putchar (char_echo); /* then write it back to the simulation console */
|
||||
|
||||
else { /* otherwise */
|
||||
tmxr_putc_ln (&atcd_ldsc [channel], char_echo); /* write it to the multiplexer output line */
|
||||
tmxr_poll_tx (&atcd_mdsc); /* and poll to transmit it now */
|
||||
else { /* otherwise */
|
||||
tmxr_putc_ln (&atcd_ldsc [channel], /* write it to the multiplexer output line */
|
||||
char_echo);
|
||||
|
||||
if (atcd_ldsc [channel].xmte == 0) /* if the output buffer is full */
|
||||
tmxr_poll_tx (&atcd_mdsc); /* then transmit the line buffer */
|
||||
}
|
||||
|
||||
dprintf (atcd_dev, DEB_XFER, ("Channel %d character %s echoed\n"),
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
CPU HP 3000 Series III Central Processing Unit
|
||||
|
||||
05-Sep-17 JDB Removed the -B (binary display) option; use -2 instead
|
||||
Changed REG_A (permit any symbolic override) to REG_X
|
||||
19-Jan-17 JDB Added comments describing the OPND and EXEC trace options
|
||||
29_Dec-16 JDB Changed the status mnemonic flag from REG_S to REG_T
|
||||
07-Nov-16 JDB Renamed cpu_byte_to_word_ea to cpu_byte_ea
|
||||
@@ -1024,8 +1026,7 @@ UNIT cpu_unit [] = {
|
||||
modification. User flags describe the permitted and default display formats,
|
||||
as follows:
|
||||
|
||||
- REG_A permits any display
|
||||
- REG_B permits binary display
|
||||
- REG_X permits any symbolic display
|
||||
- REG_M defaults to CPU instruction mnemonic display
|
||||
- REG_T defaults to CPU status mnemonic display
|
||||
|
||||
@@ -1058,15 +1059,15 @@ static REG cpu_reg [] = {
|
||||
{ ORDATA (SR, SR, 3), REG_FIT }, /* stack register counter */
|
||||
{ ORDATA (Z, Z, 16), REG_FIT }, /* stack limit register */
|
||||
{ ORDATA (SBANK, SBANK, 4), REG_FIT }, /* stack segment bank register */
|
||||
{ ORDATA (RA, TR [0], 16), REG_A | REG_FIT }, /* top of stack register */
|
||||
{ ORDATA (RB, TR [1], 16), REG_A | REG_FIT }, /* top of stack - 1 register */
|
||||
{ ORDATA (RC, TR [2], 16), REG_A | REG_FIT }, /* top of stack - 2 register */
|
||||
{ ORDATA (RD, TR [3], 16), REG_A | REG_FIT }, /* top of stack - 3 register */
|
||||
{ ORDATA (X, X, 16), REG_A | REG_FIT }, /* index register */
|
||||
{ ORDATA (STA, STA, 16), REG_T | REG_B | REG_FIT }, /* status register */
|
||||
{ ORDATA (SWCH, SWCH, 16), REG_A | REG_FIT }, /* switch register */
|
||||
{ ORDATA (CPX1, CPX1, 16), REG_B | REG_FIT }, /* run-mode interrupt flags */
|
||||
{ ORDATA (CPX2, CPX2, 16), REG_B | REG_FIT }, /* halt-mode interrupt flags */
|
||||
{ ORDATA (RA, TR [0], 16), REG_X | REG_FIT }, /* top of stack register */
|
||||
{ ORDATA (RB, TR [1], 16), REG_X | REG_FIT }, /* top of stack - 1 register */
|
||||
{ ORDATA (RC, TR [2], 16), REG_X | REG_FIT }, /* top of stack - 2 register */
|
||||
{ ORDATA (RD, TR [3], 16), REG_X | REG_FIT }, /* top of stack - 3 register */
|
||||
{ ORDATA (X, X, 16), REG_X | REG_FIT }, /* index register */
|
||||
{ ORDATA (STA, STA, 16), REG_T | REG_FIT }, /* status register */
|
||||
{ ORDATA (SWCH, SWCH, 16), REG_X | REG_FIT }, /* switch register */
|
||||
{ ORDATA (CPX1, CPX1, 16), REG_FIT }, /* run-mode interrupt flags */
|
||||
{ ORDATA (CPX2, CPX2, 16), REG_FIT }, /* halt-mode interrupt flags */
|
||||
{ ORDATA (PCLK, PCLK, 16), REG_FIT }, /* process clock register */
|
||||
{ ORDATA (CNTR, CNTR, 6), REG_HRO | REG_FIT }, /* microcode counter */
|
||||
{ ORDATA (MOD, MOD, 16), REG_HRO | REG_FIT }, /* module control register */
|
||||
@@ -1331,8 +1332,8 @@ DEVICE cpu_dev = {
|
||||
volatile-qualified type and have been changed between the setjmp
|
||||
invocation and longjmp call are indeterminate."
|
||||
|
||||
Therefore, after a microcode abort, we cannot depend upon the values of
|
||||
any local variables.
|
||||
Therefore, the "device" and "status" variables are marked volatile to
|
||||
ensure that they are reloaded after a longjmp caused by a micrcode abort.
|
||||
|
||||
2. In hardware, the NEXT microcode order present at the end of each
|
||||
instruction transfers the NIR content to the CIR, reads the memory word
|
||||
@@ -1398,10 +1399,11 @@ static const char *const stack_formats [] = { /* stack register displa
|
||||
};
|
||||
|
||||
int abortval;
|
||||
HP_WORD label, parameter, device;
|
||||
HP_WORD label, parameter;
|
||||
TRAP_CLASS trap;
|
||||
t_bool exec_test;
|
||||
t_stat status = SCPE_OK;
|
||||
volatile HP_WORD device;
|
||||
volatile t_stat status = SCPE_OK;
|
||||
|
||||
|
||||
/* Instruction prelude */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* hp3000_defs.h: HP 3000 simulator general declarations
|
||||
|
||||
Copyright (c) 2016, J. David Bryan
|
||||
Copyright (c) 2016-2017, J. David Bryan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -23,7 +23,8 @@
|
||||
in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from the author.
|
||||
|
||||
29_Dec-16 JDB Changed the status mnemonic flag from REG_S to REG_T
|
||||
16-Oct-17 JDB Suppressed logical-not-parentheses warning on clang
|
||||
29-Dec-16 JDB Changed the status mnemonic flag from REG_S to REG_T
|
||||
20-Nov-16 JDB Added mapped memory access classes
|
||||
24-Oct-16 JDB Added half-byte definitions for CIS decoding
|
||||
10-Oct-16 JDB Moved ACCESS_CLASS definition here from hp3000_cpu.h
|
||||
@@ -134,6 +135,7 @@
|
||||
*/
|
||||
|
||||
#if defined (__clang__)
|
||||
#pragma clang diagnostic ignored "-Wlogical-not-parentheses"
|
||||
#pragma clang diagnostic ignored "-Wlogical-op-parentheses"
|
||||
#pragma clang diagnostic ignored "-Wbitwise-op-parentheses"
|
||||
#pragma clang diagnostic ignored "-Wshift-op-parentheses"
|
||||
@@ -147,10 +149,12 @@
|
||||
|
||||
/* Device register display mode flags */
|
||||
|
||||
#define REG_A (1u << REG_V_UF + 0) /* permit any display */
|
||||
#define REG_B (1u << REG_V_UF + 1) /* permit binary display */
|
||||
#define REG_M (1u << REG_V_UF + 2) /* default to instruction mnemonic display */
|
||||
#define REG_T (1u << REG_V_UF + 3) /* default to status mnemonic display */
|
||||
#define REG_X REG_VMIO /* permit symbolic display overrides */
|
||||
|
||||
#define REG_A (1u << REG_V_UF + 0) /* default format is -A (one ASCII character) */
|
||||
#define REG_C (1u << REG_V_UF + 1) /* default format is -C (two ASCII characters) */
|
||||
#define REG_M (1u << REG_V_UF + 2) /* default format is -M (mnemonic) */
|
||||
#define REG_T (1u << REG_V_UF + 3) /* default format is -T (status mnemonic) */
|
||||
|
||||
|
||||
/* Register macros.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* hp3000_ds.c: HP 3000 30229B Cartridge Disc Interface simulator
|
||||
|
||||
Copyright (c) 2016, J. David Bryan
|
||||
Copyright (c) 2016-2017, J. David Bryan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
DS HP 30229B Cartridge Disc Interface
|
||||
|
||||
05-Sep-17 JDB Changed REG_A (permit any symbolic override) to REG_X
|
||||
12-Sep-16 JDB Changed DIB register macro usage from SRDATA to DIB_REG
|
||||
09-Jun-16 JDB Added casts for ptrdiff_t to int32 values
|
||||
08-Jun-16 JDB Corrected %d format to %u for unsigned values
|
||||
@@ -435,7 +436,7 @@ static REG ds_reg [] = {
|
||||
{ FLDATA (OVRUN, flags, 5) },
|
||||
{ FLDATA (XFRNG, flags, 6) },
|
||||
|
||||
{ ORDATA (BUFFER, buffer_word, 16), REG_A | REG_FIT | PV_RZRO },
|
||||
{ ORDATA (BUFFER, buffer_word, 16), REG_X | REG_FIT | PV_RZRO },
|
||||
{ ORDATA (STATUS, status_word, 16), REG_FIT | PV_RZRO },
|
||||
{ DRDATA (RETRY, retry_counter, 4), REG_FIT | PV_LEFT },
|
||||
|
||||
|
||||
@@ -321,15 +321,15 @@ struct dib { /* the Device Information Block
|
||||
};
|
||||
|
||||
#define DIB_REGS(dib) \
|
||||
/* Macro Name Location Width Flags */ \
|
||||
/* ------ ------- -------------------------- ----- ------- */ \
|
||||
{ DRDATA (DIBDN, dib.device_number, 32), REG_HRO }, \
|
||||
{ DRDATA (DIBSRN, dib.service_request_number, 32), REG_HRO }, \
|
||||
{ DRDATA (DIBPRI, dib.interrupt_priority, 32), REG_HRO }, \
|
||||
{ ORDATA (DIBMASK, dib.interrupt_mask, 32), REG_HRO }, \
|
||||
{ ORDATA (DIBIRQ, dib.interrupt_request, 32), REG_HRO }, \
|
||||
{ ORDATA (DIBACT, dib.interrupt_active, 32), REG_HRO }, \
|
||||
{ ORDATA (DIBSR, dib.service_request, 32), REG_HRO }
|
||||
/* Macro Name Location Width Flags */ \
|
||||
/* ------ ------- -------------------------- ----- ------- */ \
|
||||
{ DRDATA (DIBDN, dib.device_number, 32), REG_HRO }, \
|
||||
{ DRDATA (DIBSRN, dib.service_request_number, 32), REG_HRO }, \
|
||||
{ DRDATA (DIBPRI, dib.interrupt_priority, 32), REG_HRO }, \
|
||||
{ ORDATA (DIBMASK, dib.interrupt_mask, 32), REG_HRO }, \
|
||||
{ ORDATA (DIBIRQ, dib.interrupt_request, 32), REG_HRO }, \
|
||||
{ ORDATA (DIBACT, dib.interrupt_active, 32), REG_HRO }, \
|
||||
{ ORDATA (DIBSR, dib.service_request, 32), REG_HRO }
|
||||
|
||||
|
||||
/* Calibrated timer numbers */
|
||||
|
||||
@@ -25,6 +25,12 @@
|
||||
|
||||
LP HP 30209A Line Printer Interface
|
||||
|
||||
07-Sep-17 JDB Changed PCHR and UPCHR registers to PUNCHR and UNPCHR
|
||||
Changed PRTBUF, OVPCHR, PUNCHR, and UNPCHR to REG_A
|
||||
05-Sep-17 JDB Changed REG_A (permit any symbolic override) to REG_X
|
||||
20-Jul-17 JDB Added a forced detach option (-F switch) to "lp_detach"
|
||||
24-Jun-17 JDB Added "report_error", fixed "lp_set_model" times bug
|
||||
22-Jun-17 JDB Moved deferred offline/detach cancel to SET ONLINE
|
||||
26-Apr-17 JDB Fixed "lp_service" return for VFU channel not punched
|
||||
Restricted auto-print on buffer full to the 2607
|
||||
Paper fault is now delayed until the TOF for the 2607
|
||||
@@ -205,19 +211,17 @@
|
||||
issued while the print buffer contains data or the printer unit is busy
|
||||
executing a print action.
|
||||
|
||||
The SET LP OFFLINE and SET LP DETACH commands check for data in the print
|
||||
buffer or a print operation in progress. If either condition is true, they
|
||||
set their respective deferred-action flags and display "Command deferred." A
|
||||
SHOW LP will show that the device is still online and attached. Once
|
||||
The SET LP OFFLINE and DETACH LP commands check for data in the print buffer
|
||||
or a print operation in progress. If either condition is true, they set
|
||||
their respective deferred-action flags and display "Command not completed."
|
||||
A SHOW LP will show that the device is still online and attached. Once
|
||||
simulation is resumed and the print operation completes, the printer is set
|
||||
offline or detached as requested. No console message reports this, as it is
|
||||
assumed that the executing program will detect the condition and report
|
||||
accordingly. A subsequent SHOW LP will indicate the new status.
|
||||
|
||||
A SET LP ONLINE or ATTACH LP command when the corresponding deferred-action
|
||||
flag is set simply clears the flag. In particular, an ATTACH LP command must
|
||||
not specify a new image filename; if one is specified while a deferred detach
|
||||
is in progress, the routine returns SCPE_NOFNC ("Command not allowed").
|
||||
A SET LP ONLINE command when a deferred-action flag is set simply clears the
|
||||
flag, which cancels the pending offline or detach condition.
|
||||
|
||||
A RESET LP command also clears the deferred-action flags and so clears any
|
||||
pending offline or detach. However, it also clears the print buffer and
|
||||
@@ -480,11 +484,22 @@
|
||||
#define DEV_REALTIME (1u << DEV_REALTIME_SHIFT) /* realistic timing flag */
|
||||
|
||||
|
||||
/* Printer unit flags */
|
||||
/* Printer unit flags.
|
||||
|
||||
#define UNIT_MODEL_SHIFT (UNIT_V_UF + 0) /* bits 0-2: printer model ID */
|
||||
#define UNIT_EXPAND_SHIFT (UNIT_V_UF + 3) /* bits 3-3: printer uses expanded output */
|
||||
#define UNIT_OFFLINE_SHIFT (UNIT_V_UF + 4) /* bits 4-4: printer is offline */
|
||||
UNIT_V_UF + 7 6 5 4 3 2 1 0
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| - | - | - | O | E | model |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
Where:
|
||||
|
||||
O = offline
|
||||
E = expanded output
|
||||
*/
|
||||
|
||||
#define UNIT_MODEL_SHIFT (UNIT_V_UF + 0) /* printer model ID */
|
||||
#define UNIT_EXPAND_SHIFT (UNIT_V_UF + 3) /* printer uses expanded output */
|
||||
#define UNIT_OFFLINE_SHIFT (UNIT_V_UF + 4) /* printer is offline */
|
||||
|
||||
#define UNIT_MODEL_MASK 0000007u /* model ID mask */
|
||||
|
||||
@@ -541,10 +556,10 @@ typedef enum {
|
||||
|
||||
This table contains the characteristics that vary between printer models.
|
||||
The "char_set" field values reflect printer Option 001, 96/128-character set.
|
||||
The "not_ready" field indicates whether a paper fault sets not-ready status
|
||||
or simply takes the printer offline. The "fault_at_eol" field indicates
|
||||
whether a paper fault is reported at the end of any line (TRUE) or only at
|
||||
the top of the next form (FALSE).
|
||||
The "not_ready" field indicates whether a paper fault sets a separate
|
||||
not-ready status or simply takes the printer offline. The "fault_at_eol"
|
||||
field indicates whether a paper fault is reported at the end of any line or
|
||||
only at the top of the next form.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
@@ -579,9 +594,10 @@ static const PRINTER_PROPS print_props [] = { /* printer properties, indexed b
|
||||
Implementation notes:
|
||||
|
||||
1. Although all of the printers operate more slowly with a 96/128-character
|
||||
set than with a 64-character set, the times reflect the smaller set size.
|
||||
Also, some models provide different print rates, depending on how many
|
||||
and/or which characters are printed. These variances are not simulated.
|
||||
set installed than with a 64-character set, the times reflect the smaller
|
||||
set size. Also, some models provide different print rates, depending on
|
||||
how many and/or which characters are printed. These variations are not
|
||||
simulated.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
@@ -1046,7 +1062,7 @@ static t_bool power_warning = FALSE; /* PFWARN is not asserted to the
|
||||
/* Printer state */
|
||||
|
||||
static t_bool paper_fault = TRUE; /* TRUE if the printer is out of paper */
|
||||
static t_bool tape_fault = FALSE; /* TRUE if there is no punch in a VFU channel command */
|
||||
static t_bool tape_fault = FALSE; /* TRUE if there is no punch in a commanded VFU channel */
|
||||
static t_bool offline_pending = FALSE; /* TRUE if an offline request is waiting for the printer to finish */
|
||||
static uint32 overprint_char = DEL; /* character to use if overprinted */
|
||||
static uint32 current_line = 1; /* current form line */
|
||||
@@ -1077,6 +1093,7 @@ static t_stat ui_reset (DEVICE *dptr);
|
||||
static t_stat master_reset (t_bool programmed_clear);
|
||||
static void clear_interface_logic (void);
|
||||
static void activate_unit (UNIT *uptr);
|
||||
static void report_error (FILE *stream);
|
||||
static OUTBOUND_SET set_interrupt (uint32 interrupt);
|
||||
static OUTBOUND_SET set_device_status (uint32 status_mask, uint32 new_status_word);
|
||||
static OUTBOUND_SET handshake_xfer (void);
|
||||
@@ -1177,12 +1194,12 @@ static REG lp_reg [] = {
|
||||
{ ORDATA (CNTL, control_word, 16), PV_RZRO },
|
||||
{ ORDATA (ISTAT, int_status_word, 16), PV_RZRO },
|
||||
{ ORDATA (DSTAT, dev_status_word, 16), PV_RZRO },
|
||||
{ ORDATA (READ, read_word, 16), PV_RZRO | REG_A },
|
||||
{ ORDATA (WRITE, write_word, 16), PV_RZRO | REG_A },
|
||||
{ ORDATA (READ, read_word, 16), PV_RZRO | REG_X },
|
||||
{ ORDATA (WRITE, write_word, 16), PV_RZRO | REG_X },
|
||||
{ YRDATA (J2WX, jumper_set, 10, PV_RZRO) },
|
||||
|
||||
{ ORDATA (DATOUT, data_out, 16), PV_RZRO | REG_A },
|
||||
{ ORDATA (DATIN, data_in, 16), PV_RZRO | REG_A },
|
||||
{ ORDATA (DATOUT, data_out, 16), PV_RZRO | REG_X },
|
||||
{ ORDATA (DATIN, data_in, 16), PV_RZRO | REG_X },
|
||||
|
||||
{ FLDATA (DCOUT, device_command_out, 0) },
|
||||
{ FLDATA (DFIN, device_flag_in, 0) },
|
||||
@@ -1206,8 +1223,8 @@ static REG lp_reg [] = {
|
||||
{ DRDATA (FORMLN, form_length, 8), PV_LEFT | REG_RO },
|
||||
{ BRDATA (TITLE, vfu_title, 8, 8, LINE_SIZE), REG_HRO },
|
||||
{ BRDATA (VFU, VFU, 2, VFU_WIDTH, VFU_SIZE), PV_RZRO | REG_RO },
|
||||
{ ORDATA (PCHR, punched_char, 8), PV_RZRO | REG_A },
|
||||
{ ORDATA (UPCHR, unpunched_char, 8), PV_RZRO | REG_A },
|
||||
{ ORDATA (PUNCHR, punched_char, 8), PV_RZRO | REG_A },
|
||||
{ ORDATA (UNPCHR, unpunched_char, 8), PV_RZRO | REG_A },
|
||||
|
||||
{ DRDATA (BTIME, fast_times.buffer_load, 24), PV_LEFT | REG_NZ },
|
||||
{ DRDATA (PTIME, fast_times.print, 24), PV_LEFT | REG_NZ },
|
||||
@@ -1795,7 +1812,7 @@ return SCPE_OK; /* return success */
|
||||
|
||||
Implementation notes:
|
||||
|
||||
1. Calling "master_clear" with a FALSE parameter indicates that this is a
|
||||
1. Calling "master_reset" with a FALSE parameter indicates that this is a
|
||||
commanded reset. This allows the connected device-specific reset
|
||||
routines to distinguish from a Programmed Master Clear.
|
||||
*/
|
||||
@@ -1911,6 +1928,23 @@ return;
|
||||
}
|
||||
|
||||
|
||||
/* Report a stream I/O error to the console.
|
||||
|
||||
If a stream I/O error has been detected, this routine will print an error
|
||||
message to the simulation console and clear the stream's error indicator.
|
||||
*/
|
||||
|
||||
static void report_error (FILE *stream)
|
||||
{
|
||||
cprintf ("%s simulator printer I/O error: %s\n", /* report the error to the console */
|
||||
sim_name, strerror (errno));
|
||||
|
||||
clearerr (stream); /* clear the error */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Set an interrupt.
|
||||
|
||||
The interrupt bit specified is set in the interrupt status word. If enabled,
|
||||
@@ -2491,11 +2525,12 @@ return outbound_signals; /* return INTREQ if any
|
||||
conclude the handshake.
|
||||
|
||||
Control word bit 10 determines whether the code on the data out lines is
|
||||
interpreted as a character (0) or a format command (1). Character data is
|
||||
loaded into the buffer; if the line length is exceeded, the printer
|
||||
automatically prints the buffer contents, advances the paper one line, and
|
||||
stores the new character in the empty buffer. If a control character is sent
|
||||
but the printer cannot print it, a space is loaded in its place.
|
||||
interpreted as a character (0) or a format command (1). If there is room in
|
||||
the print buffer, the character is loaded. If not, then depending on the
|
||||
model, the printer either discards the character or automatically prints the
|
||||
buffer contents, advances the paper one line, and stores the new character in
|
||||
the empty buffer. If a control character is sent but the printer cannot
|
||||
print it, a space is loaded in its place.
|
||||
|
||||
A format command causes the current buffer to be printed, and then the paper
|
||||
is advanced by a prescribed amount. Two output modes are provided: compact
|
||||
@@ -2545,14 +2580,18 @@ return outbound_signals; /* return INTREQ if any
|
||||
|
||||
Implementation notes:
|
||||
|
||||
1. Because attached files are opened in binary mode, newline translation
|
||||
1. When a paper-out condition is detected, the 2607 printer goes offline
|
||||
only when the next top-of-form is reached. The 2613/17/18 printers go
|
||||
offline as soon as the current line completes.
|
||||
|
||||
2. Because attached files are opened in binary mode, newline translation
|
||||
(i.e., from LF to CR LF) is not performed by the host system. Therefore,
|
||||
we write explicit CR LF pairs to end lines, even in compact mode, as
|
||||
required for fidelity to HP peripherals. If bare LFs are used by the
|
||||
host system, the printer output file must be postprocessed to remove the
|
||||
CRs.
|
||||
|
||||
2. Overprinting in expanded mode is simulated by merging the lines in the
|
||||
3. Overprinting in expanded mode is simulated by merging the lines in the
|
||||
buffer. A format command to suppress spacing resets the buffer index but
|
||||
saves the previous buffer length as a "high water mark" that will be
|
||||
extended if the overlaying line is longer. This process may be repeated
|
||||
@@ -2565,25 +2604,31 @@ return outbound_signals; /* return INTREQ if any
|
||||
"overprint character" (which defaults to DEL, but can be changed by the
|
||||
user) replaces the character in the buffer.
|
||||
|
||||
3. Printers that support 12-channel VFUs treat the VFU format command as
|
||||
4. Printers that support 12-channel VFUs treat the VFU format command as
|
||||
modulo 16. Printers that support 8-channel VFUs treat the command as
|
||||
modulo 8.
|
||||
|
||||
4. As a convenience to the user, the printer output file is flushed when a
|
||||
TOF operation is performed.
|
||||
5. As a convenience to the user, the printer output file is flushed when a
|
||||
TOF operation is performed. This permits inspection of the output file
|
||||
from the SCP command prompt while output is ongoing.
|
||||
|
||||
5. The user may examine the TFAULT and PFAULT registers to determine why the
|
||||
6. The user may examine the TFAULT and PFAULT registers to determine why the
|
||||
printer went offline.
|
||||
|
||||
6. The transfer service may be called with a null pointer to update the
|
||||
7. The transfer service may be called with a null pointer to update the
|
||||
potential change in the flag state.
|
||||
|
||||
7. If printing is attempted with the printer offline, this routine will be
|
||||
8. If printing is attempted with the printer offline, this routine will be
|
||||
called with STROBE asserted (device_command_in TRUE) and DEMAND denied
|
||||
(device_flag_in TRUE). The printer ignores STROBE if DEMAND is not
|
||||
asserted, so we simply return in this case. This will hang the handshake
|
||||
until the printer is set online, and we are reentered with DEMAND
|
||||
asserted.
|
||||
asserted. As a consequence, explicit protection against "uptr->fileref"
|
||||
being NULL is not required.
|
||||
|
||||
9. Explicit tests for lowercase and control characters are much faster and
|
||||
are used rather than calls to "islower" and "iscntrl", which must
|
||||
consider the current locale.
|
||||
*/
|
||||
|
||||
static t_stat lp_service (UNIT *uptr)
|
||||
@@ -2828,14 +2873,11 @@ else if (device_flag_in == FALSE) { /* otherwise if STROBE h
|
||||
slew_count, (slew_count == 1 ? "" : "s"), current_line);
|
||||
}
|
||||
|
||||
if (ferror (uptr->fileref)) { /* if a host file system error occurred */
|
||||
cprintf ("%s simulator printer I/O error: %s\n", /* then report the error to the console */
|
||||
sim_name, strerror (errno));
|
||||
if (ferror (uptr->fileref)) { /* if a host file system error occurred */
|
||||
report_error (uptr->fileref); /* then report the error to the console */
|
||||
|
||||
clearerr (uptr->fileref); /* clear the error */
|
||||
|
||||
lp_set_alarm (uptr); /* set an alarm condition */
|
||||
return SCPE_IOERR; /* and stop the simulator */
|
||||
lp_set_alarm (uptr); /* set an alarm condition */
|
||||
return SCPE_IOERR; /* and stop the simulator */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2849,7 +2891,7 @@ return SCPE_OK; /* return event service
|
||||
equivalent of loading paper into the printer and pressing the ONLINE button.
|
||||
The transition from offline to online causes an interrupt.
|
||||
|
||||
A new image file may be requested by giving the "-N" switch to the attach
|
||||
A new image file may be requested by giving the "-N" switch to the ATTACH
|
||||
command. If an existing file is specified with "-N", it will be cleared; if
|
||||
specified without "-N", printer output will be appended to the end of the
|
||||
existing file content. In all cases, the paper is positioned at the top of
|
||||
@@ -2869,7 +2911,7 @@ return SCPE_OK; /* return event service
|
||||
|
||||
static t_stat lp_attach (UNIT *uptr, CONST char *cptr)
|
||||
{
|
||||
t_stat result = SCPE_OK;
|
||||
t_stat result;
|
||||
|
||||
result = attach_unit (uptr, cptr); /* attach the specified printer image file */
|
||||
|
||||
@@ -2879,15 +2921,20 @@ if (result == SCPE_OK /* if the attach was suc
|
||||
|
||||
current_line = 1; /* reset the line counter to the top of the form */
|
||||
|
||||
if (sim_switches & SWMASK ('N')) /* if a new (empty) file was requested */
|
||||
uptr->pos = 0; /* then position at the start of the file */
|
||||
|
||||
else if (fseek (uptr->fileref, 0, SEEK_END) == 0) /* otherwise append by seeking to the end of the file */
|
||||
if (fseek (uptr->fileref, 0, SEEK_END) == 0) { /* append by seeking to the end of the file */
|
||||
uptr->pos = (t_addr) ftell (uptr->fileref); /* and repositioning if the seek succeeded */
|
||||
|
||||
dprintf (lp_dev, DEB_CMD, "Printer paper loaded\n");
|
||||
dprintf (lp_dev, DEB_CMD, "Printer paper loaded\n");
|
||||
|
||||
lp_set_locality (uptr, Online); /* set the printer online */
|
||||
lp_set_locality (uptr, Online); /* set the printer online */
|
||||
}
|
||||
|
||||
else { /* otherwise a host file system error occurred */
|
||||
report_error (uptr->fileref); /* so report the error to the console */
|
||||
|
||||
lp_set_alarm (uptr); /* set an alarm condition */
|
||||
result = SCPE_IOERR; /* and report that the attached failed */
|
||||
}
|
||||
}
|
||||
|
||||
paper_fault = FALSE; /* clear any existing paper fault */
|
||||
@@ -2904,10 +2951,10 @@ return result; /* return the result of
|
||||
/* Detach the printer image file.
|
||||
|
||||
The specified file is detached from the indicated unit. This is the
|
||||
simulation equivalent to unloading the paper from the printer or the printer
|
||||
running out of paper. The out-of-paper condition cause a paper fault alarm,
|
||||
and the printer goes offline. The transition from online to offline causes
|
||||
an interrupt.
|
||||
simulation equivalent of running out of paper or unloading the paper from the
|
||||
printer. The out-of-paper condition cause a paper fault alarm, and the
|
||||
printer goes offline. The transition from online to offline causes an
|
||||
interrupt.
|
||||
|
||||
When the printer runs out of paper, it will not go offline until characters
|
||||
present in the buffer are printed and paper motion stops. In addition, the
|
||||
@@ -2916,7 +2963,10 @@ return result; /* return the result of
|
||||
|
||||
In simulation, entering a DETACH LP command while the printer is busy will
|
||||
defer the file detach until print operations reach the top of the next form
|
||||
(2607) or until the current print operation completes (2613/17/18).
|
||||
(2607) or until the current print operation completes (2613/17/18). An
|
||||
immediate detach may be forced by adding the -F switch to the DETACH command.
|
||||
This simulates physically removing the paper from the printer and succeeds
|
||||
regardless of the current printer state.
|
||||
|
||||
|
||||
Implementation notes:
|
||||
@@ -2943,25 +2993,32 @@ if (uptr->flags & UNIT_ATTABLE) /* if we're being called
|
||||
if ((uptr->flags & UNIT_ATT) == 0) /* then if the unit is not currently attached */
|
||||
return SCPE_UNATT; /* then report it */
|
||||
|
||||
else if ((print_props [model].fault_at_eol /* otherwise if the printer faults at the end of any line */
|
||||
|| current_line == 1) /* or the printer is at the top of the form */
|
||||
&& lp_set_alarm (uptr) /* and a paper alarm is accepted */
|
||||
|| (sim_switches & SIM_SW_SHUT)) { /* or this is a shutdown call */
|
||||
paper_fault = TRUE; /* then set the out-of-paper condition */
|
||||
else {
|
||||
if (sim_switches & (SWMASK ('F') | SIM_SW_SHUT)) { /* if this is a forced detach or shut down request */
|
||||
current_line = 1; /* then reset the printer to TOF to enable detaching */
|
||||
sim_cancel (uptr); /* and terminate */
|
||||
device_command_out = FALSE; /* any print action in progress */
|
||||
}
|
||||
|
||||
dprintf (lp_dev, DEB_CMD, "Printer is out of paper\n");
|
||||
if ((print_props [model].fault_at_eol /* otherwise if the printer faults at the end of any line */
|
||||
|| current_line == 1) /* or the printer is at the top of the form */
|
||||
&& lp_set_alarm (uptr)) { /* and a paper alarm is accepted */
|
||||
paper_fault = TRUE; /* then set the out-of-paper condition */
|
||||
|
||||
return detach_unit (uptr); /* and detach the unit */
|
||||
}
|
||||
dprintf (lp_dev, DEB_CMD, "Printer is out of paper\n");
|
||||
|
||||
else { /* otherwise the alarm was rejected at this time */
|
||||
paper_fault = TRUE; /* so set the out-of-paper condition */
|
||||
offline_pending = TRUE; /* but defer the detach */
|
||||
return detach_unit (uptr); /* and detach the unit */
|
||||
}
|
||||
|
||||
dprintf (lp_dev, DEB_CMD, "Paper out request deferred until print completes\n");
|
||||
else { /* otherwise the alarm was rejected at this time */
|
||||
paper_fault = TRUE; /* so set the out-of-paper condition */
|
||||
offline_pending = TRUE; /* but defer the detach */
|
||||
|
||||
cputs ("Command deferred\n"); /* but the actual detach must be deferred */
|
||||
return SCPE_OK; /* until the buffer prints */
|
||||
dprintf (lp_dev, DEB_CMD, "Paper out request deferred until print completes\n");
|
||||
|
||||
cprintf ("%s\n", sim_error_text (SCPE_INCOMP)); /* report that the actual detach must be deferred */
|
||||
return SCPE_OK; /* until the buffer has been printed */
|
||||
}
|
||||
}
|
||||
|
||||
else /* otherwise */
|
||||
@@ -3018,7 +3075,7 @@ switch ((DEVICE_MODES) value) { /* dispatch the mode to
|
||||
break;
|
||||
}
|
||||
|
||||
return SCPE_OK; /* the mode change succeeds */
|
||||
return SCPE_OK; /* mode changes always succeed */
|
||||
}
|
||||
|
||||
|
||||
@@ -3033,7 +3090,7 @@ return SCPE_OK; /* the mode change succe
|
||||
static t_stat lp_set_model (UNIT *uptr, int32 value, CONST char *cptr, void *desc)
|
||||
{
|
||||
if (lp_dev.flags & DEV_REALTIME) /* if the printer is in real-time mode */
|
||||
dlyptr = &real_times [GET_MODEL (uptr->flags)]; /* then use the times for the new model */
|
||||
dlyptr = &real_times [GET_MODEL (value)]; /* then use the times for the new model */
|
||||
|
||||
return SCPE_OK; /* allow the reassignment to proceed */
|
||||
}
|
||||
@@ -3044,26 +3101,29 @@ return SCPE_OK; /* allow the reassignmen
|
||||
This validation routine is called to set the printer online or offline. The
|
||||
"value" parameter is UNIT_OFFLINE if the printer is going offline and is zero
|
||||
if the printer is going online. This simulates pressing the ON/OFFLINE
|
||||
button on the printer.
|
||||
button on the printer. The unit must be attached (i.e., paper must be
|
||||
loaded), before the printer may be set online or offline.
|
||||
|
||||
If the printer is being taken offline, the buffer is checked to see if any
|
||||
characters are present. If they are, or if the printer unit is currently
|
||||
scheduled (i.e., executing a print operation), the offline request is
|
||||
deferred until printing completes, and the routine prints "Command deferred"
|
||||
to inform the user. Otherwise, the unit is set offline, DEMAND is denied,
|
||||
and DEV END is asserted to indicate that the printer is not ready.
|
||||
//
|
||||
As a special case, a detach (out-of-paper condition) that has been deferred
|
||||
until printing completes may be cancelled by setting the printer online.
|
||||
deferred until printing completes, and the routine returns "Command not
|
||||
complete" status to inform the user. Otherwise, the unit is set offline,
|
||||
DEMAND is denied, and DEV END is asserted to indicate that the printer is not
|
||||
ready.
|
||||
|
||||
If the printer is being put online, the unit must be attached (i.e., paper
|
||||
must be loaded), or the command is rejected. If paper is present, the unit
|
||||
is set online, and any tape fault present is cleared. If the sequencer
|
||||
If the printer is being put online and paper is present, the unit is set
|
||||
online, and any paper or tape fault present is cleared. If the sequencer
|
||||
indicates an incomplete handshake, as would occur if paper ran out while
|
||||
printing, the transfer service is called to complete the handshake by
|
||||
asserting DEMAND. Otherwise, DEMAND is asserted explicitly, and DEV END is
|
||||
denied.
|
||||
|
||||
As a special case, a detach (out-of-paper condition) or offline request that
|
||||
has been deferred until printing completes may be cancelled by setting the
|
||||
printer online. No other action is taken, because the printer has never
|
||||
transitioned to the offline state.
|
||||
|
||||
Transitions between the offline and online state cause interrupts, and INTREQ
|
||||
is asserted to the IOP if a transition occurred (but not, e.g., for a SET LP
|
||||
OFFLINE command where the printer is already offline).
|
||||
@@ -3071,9 +3131,9 @@ return SCPE_OK; /* allow the reassignmen
|
||||
|
||||
Implementation notes:
|
||||
|
||||
1. Because a deferred offline request is not fatal, we return SCPE_OK to
|
||||
allow command files to continue to execute, but we print a warning to the
|
||||
user.
|
||||
1. Although a deferred offline request is not fatal, we return SCPE_INCOMP
|
||||
to prevent "set_cmd" from setting the UNIT_OFFLINE bit in the unit flags
|
||||
before the printer actually goes offline.
|
||||
*/
|
||||
|
||||
static t_stat lp_set_on_offline (UNIT *uptr, int32 value, CONST char *cptr, void *desc)
|
||||
@@ -3091,8 +3151,8 @@ else if (value == UNIT_ONLINE) /* otherwise if this is
|
||||
lp_set_locality (uptr, Online); /* so set the printer online */
|
||||
|
||||
else if (lp_set_locality (uptr, Offline) == FALSE) { /* otherwise if it cannot be set offline now */
|
||||
cputs ("Command deferred\n"); /* then let the user know */
|
||||
dprintf (lp_dev, DEB_CMD, "Offline request deferred until print completes\n");
|
||||
return SCPE_INCOMP; /* then let the user know */
|
||||
}
|
||||
|
||||
return SCPE_OK; /* return operation success */
|
||||
@@ -3189,8 +3249,8 @@ static t_stat lp_show_vfu (FILE *st, UNIT *uptr, int32 value, CONST void *desc)
|
||||
static const char header_1 [] = " Ch 1 Ch 2 Ch 3 Ch 4 Ch 5 Ch 6 Ch 7 Ch 8 Ch 9 Ch10 Ch11 Ch12";
|
||||
static const char header_2 [] = " ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----";
|
||||
|
||||
const PRINTER_TYPE model = GET_MODEL (uptr->flags);
|
||||
const uint32 channel_count = print_props [model].vfu_channels;
|
||||
const PRINTER_TYPE model = GET_MODEL (uptr->flags); /* the printer model number */
|
||||
const uint32 channel_count = print_props [model].vfu_channels; /* the count of VFU channels */
|
||||
uint32 chan, line, current_channel;
|
||||
|
||||
if (value == 0) /* if we're called for a summary display */
|
||||
@@ -3328,8 +3388,8 @@ return NO_SIGNALS; /* no special control ac
|
||||
|
||||
This routine is called when an alarm condition exists. An alarm occurs when
|
||||
paper is out (paper fault) or a VFU command addresses a channel that does not
|
||||
contain a punch (tape fault). In response, the printer goes not ready and
|
||||
offline.
|
||||
contain a punch (tape fault). In response, the printer goes offline and,
|
||||
for all models except the 2607, becomes not-ready.
|
||||
|
||||
On entry, the routine attempts to set the printer offline. If this succeeds,
|
||||
the printer is set not-ready. If it fails (for reasons explained in the
|
||||
@@ -3430,9 +3490,8 @@ dprintf (lp_dev, DEB_CMD, "Printer set %s\n",
|
||||
if (signals & INTREQ) /* if the transition caused an interrupt */
|
||||
iop_assert_INTREQ (&lp_dib); /* then assert the INTREQ signal */
|
||||
|
||||
offline_pending = FALSE;
|
||||
|
||||
return TRUE;
|
||||
offline_pending = FALSE; /* the operation completed */
|
||||
return TRUE; /* successfully */
|
||||
}
|
||||
|
||||
|
||||
@@ -3442,8 +3501,8 @@ return TRUE;
|
||||
associated with the stream "vf" or with the standard 66-line tape if the
|
||||
stream is NULL. The "uptr" parameter points to the printer unit.
|
||||
|
||||
The standard VFU tape (1535-2655 for the 8-channel HP 2607 and 2613-80001 for
|
||||
the 12-channel HP 2613, 2617, and 2618) defines the channels as:
|
||||
The standard VFU tape (02607-80024 for the 8-channel HP 2607 and 02613-80001
|
||||
for the 12-channel HP 2613, 2617, and 2618) defines the channels as:
|
||||
|
||||
Chan Description
|
||||
---- --------------
|
||||
@@ -3457,12 +3516,12 @@ return TRUE;
|
||||
8 Sixth page
|
||||
9 Bottom of form
|
||||
|
||||
...with channels 10-12 uncommitted. A custom tape must dedicate channel 1 to
|
||||
the top-of-form, but the other channels may be defined as desired.
|
||||
...with channels 10-12 uncommitted.
|
||||
|
||||
A custom tape file starts with a VFU definition line and then contains one
|
||||
channel-definition line for each line of the form. The number of lines
|
||||
establishes the form length.
|
||||
establishes the form length. Channel 1 must be dedicated to the top-of-form,
|
||||
but the other channels may be defined as desired.
|
||||
|
||||
A semicolon appearing anywhere on a line begins a comment, and the semicolon
|
||||
and all following characters are ignored. Zero-length lines, including lines
|
||||
@@ -3542,7 +3601,7 @@ return TRUE;
|
||||
|
||||
static t_stat lp_load_vfu (UNIT *uptr, FILE *vf)
|
||||
{
|
||||
const PRINTER_TYPE model = GET_MODEL (uptr->flags); /* get the printer type */
|
||||
const PRINTER_TYPE model = GET_MODEL (uptr->flags); /* the printer model number */
|
||||
uint32 line, channel, vfu_status;
|
||||
int32 len;
|
||||
char buffer [LINE_SIZE], punch [LINE_SIZE], no_punch;
|
||||
@@ -3550,10 +3609,8 @@ char *bptr, *tptr;
|
||||
uint16 tape [VFU_SIZE] = { 0 };
|
||||
|
||||
if (vf == NULL) { /* if the standard VFU is requested */
|
||||
strcpy (vfu_title, "Standard VFU"); /* then set the title */
|
||||
|
||||
tape [ 1] = VFU_CHANNEL_1; /* punch channel 1 for the top of form */
|
||||
tape [60] = VFU_CHANNEL_2 | VFU_CHANNEL_9; /* punch channels 2 and 9 for the bottom of form */
|
||||
tape [ 1] = VFU_CHANNEL_1; /* then punch channel 1 for the top of form */
|
||||
tape [60] = VFU_CHANNEL_2 | VFU_CHANNEL_9; /* and channels 2 and 9 for the bottom of form */
|
||||
|
||||
for (line = 1; line <= 60; line++) { /* load each of the 60 printable lines */
|
||||
tape [line] |= VFU_CHANNEL_3 /* punch channel 3 for single space */
|
||||
@@ -3567,6 +3624,7 @@ if (vf == NULL) { /* if the standard VFU i
|
||||
}
|
||||
|
||||
form_length = 66; /* set the form length */
|
||||
strcpy (vfu_title, "Standard VFU"); /* and set the title */
|
||||
}
|
||||
|
||||
else { /* otherwise load a custom VFU from the file */
|
||||
@@ -3690,12 +3748,9 @@ while (len == 0) {
|
||||
if (feof (vf)) /* then if the end of file was seen */
|
||||
return 0; /* then return an EOF indication */
|
||||
|
||||
else { /* otherwise report the error to the console */
|
||||
cprintf ("%s simulator line printer I/O error: %s\n",
|
||||
sim_name, strerror (errno));
|
||||
|
||||
clearerr (vf); /* clear the error */
|
||||
return -1; /* and return an error indication */
|
||||
else { /* otherwise */
|
||||
report_error (vf); /* report the error to the console */
|
||||
return -1; /* and return an error indication */
|
||||
}
|
||||
|
||||
len = strlen (line); /* get the current line length */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* hp3000_ms.c: HP 3000 30215A Magnetic Tape Controller Interface simulator
|
||||
|
||||
Copyright (c) 2016, J. David Bryan
|
||||
Copyright (c) 2016-2017, J. David Bryan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
MS HP 30215A Magnetic Tape Controller Interface
|
||||
|
||||
05-Sep-17 JDB Changed REG_A (permit any symbolic override) to REG_X
|
||||
12-Sep-16 JDB Changed DIB register macro usage from SRDATA to DIB_REG
|
||||
09-Jun-16 JDB Added casts for ptrdiff_t to int32 values
|
||||
08-Jun-16 JDB Corrected %d format to %u for unsigned values
|
||||
@@ -514,7 +515,7 @@ static REG ms_reg [] = {
|
||||
{ FLDATA (UINTRP, unit_interrupt, 0) },
|
||||
{ FLDATA (DEVEND, device_end, 0) },
|
||||
{ FLDATA (XFRERR, xfer_error, 0) },
|
||||
{ ORDATA (BUFWRD, buffer_word, 16), REG_A | REG_FIT | PV_RZRO },
|
||||
{ ORDATA (BUFWRD, buffer_word, 16), REG_X | REG_FIT | PV_RZRO },
|
||||
{ DRDATA (ATUNIT, attention_unit, 16), REG_FIT | PV_LEFT },
|
||||
{ DRDATA (CLASS, command_class, 4), PV_LEFT },
|
||||
{ YRDATA (FLAGS, flags, 8, PV_RZRO) },
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
SIMH/HP 3000 RELEASE NOTES
|
||||
==========================
|
||||
Last update: 2017-04-30
|
||||
Last update: 2018-01-12
|
||||
|
||||
|
||||
This file documents the release history of the Hewlett-Packard 3000 simulator.
|
||||
@@ -47,7 +47,7 @@ General Information
|
||||
The simulator passes the HP 32230 offline diagnostic suite with some expected
|
||||
failures due to unimplemented features. For example, the disc diagnostic
|
||||
error-correction logic tests and the tape diagnostic CRCC and LRCC tests fail,
|
||||
as these features are not supported. However, all features that are required
|
||||
as these features are not simulated. However, all features that are required
|
||||
for MPE operation pass their respective diagnostic tests.
|
||||
|
||||
The simulator has been tested with MPE-V/R version E.01.00. Specifically:
|
||||
@@ -176,6 +176,180 @@ the MPE version used:
|
||||
|
||||
|
||||
|
||||
=====================
|
||||
Release 7, 2018-01-12
|
||||
=====================
|
||||
|
||||
This release of the HP 3000 simulator adds the following features:
|
||||
|
||||
- Reading and writing to terminal sessions connected to the ATC have been
|
||||
improved significantly. File uploads via Telnet using the Reflection
|
||||
terminal emulator are now over 100 times faster than before, e.g., the
|
||||
transfer time for a one-megabyte file has decreased from 69 minutes to 30
|
||||
seconds. Block mode reads show similar speed improvements. Copy-and-paste
|
||||
into the terminal window, Reflection file downloads, and output to the
|
||||
terminal window in REMOTEACK mode show speed improvements of five to fifteen
|
||||
times. Output in LOCALACK mode has been improved by around 50%.
|
||||
|
||||
- Information regarding Reflection file transfers and serial port disconnection
|
||||
options has been added to Section 4.1.1, "Terminal Data Interface," of the HP
|
||||
3000 Simulator User's Guide.
|
||||
|
||||
|
||||
--------------------
|
||||
Implementation Notes
|
||||
--------------------
|
||||
|
||||
- File transfer using the Reflection terminal emulator requires an 8-bit data
|
||||
path. To achieve this, the session must use MPE terminal type 12 (this may
|
||||
be configured either during a system reload or by specifying the TERM=12
|
||||
parameter when logging on with :HELLO), and the channel must be set to 8B,
|
||||
REMOTEACK, and NOCAPSLOCK modes. Note that MPE's default terminal type 10
|
||||
writes 7-bit data with odd parity, and characters with the parity bit on may
|
||||
be displayed by the terminal emulator as extended characters in the Roman-8
|
||||
symbol set. To avoid a garbled display when using the TERM=12 parameter to
|
||||
override the default, the channel should be set to 8B mode after logging on
|
||||
and back to 7B after logging off.
|
||||
|
||||
- The MPE-V/R software kit has been updated to increase the number of terminal
|
||||
buffers per port from 3 to 5. Using the default of 3 may cause the system
|
||||
to report "MPE Table TBUF has overflowed!!!" to the system console while
|
||||
performing Reflection file uploads.
|
||||
|
||||
|
||||
----------
|
||||
Bugs Fixed
|
||||
----------
|
||||
|
||||
1. PROBLEM: Serial port output stalls are not handled properly.
|
||||
|
||||
VERSION: Release 6.
|
||||
|
||||
OBSERVATION: The ATCD device supports I/O via host serial ports as well as
|
||||
via Telnet connections. While output via Telnet works correctly, output
|
||||
via serial ports fails. Attempting to output to the ATCD results in a few
|
||||
characters written, and then the line hangs. Sometimes pressing ENTER at
|
||||
the system console (ATCD channel 0) causes a few more characters to appear
|
||||
on the serial terminal. Eventually, the line hangs permanently.
|
||||
|
||||
CAUSE: The terminal multiplexer library (sim_tmxr.c, part of the SIMH
|
||||
framework) had provided a 256-byte output buffer for each line, independent
|
||||
of the connection type (Telnet or serial). The library was changed to
|
||||
reduce the serial buffer size to one byte. If the library output routine
|
||||
receives the second character before the first one has been written to the
|
||||
serial port, it returns SCPE_STALL status to indicate a buffer overflow.
|
||||
The ATCD simulation correctly responds to this status by rescheduling the
|
||||
output attempt. However, it fails to call the "tmxr_poll_tx" routine to
|
||||
write to the serial port, so the rescheduled attempt fails as well.
|
||||
|
||||
RESOLUTION: Modify "line_service" (hp3000_atc.c) to call "tmxr_poll_tx" if
|
||||
a buffer overflow occurs.
|
||||
|
||||
STATUS: Fixed in Release 7.
|
||||
|
||||
|
||||
|
||||
=====================
|
||||
Release 6, 2017-09-07
|
||||
=====================
|
||||
|
||||
This release of the HP 3000 simulator adds the following features:
|
||||
|
||||
- The new "-F" switch to the DETACH LP command forces an immediate detach,
|
||||
regardless of the current paper position. This is the simulation equivalent
|
||||
of physically removing the paper from the printer. Without the switch,
|
||||
detaching is the equivalent of running out of paper, which permits printing
|
||||
to continue to the end of the line (2613/17/18) or the page (2607) before the
|
||||
printer goes offline.
|
||||
|
||||
- The HP 3000 Simulator User's Guide has been revised to add a new section
|
||||
describing the simulator commands corresponding to hardware actions and to
|
||||
rewrite the "Realistic, Calibrated, and Optimized Timing" section to describe
|
||||
the three timing modes more clearly.
|
||||
|
||||
|
||||
--------------------
|
||||
Implementation Notes
|
||||
--------------------
|
||||
|
||||
- The LP device's PCHR (punched channel character) and UPCHR (unpunched channel
|
||||
character) registers have been renamed to PUNCHR and UNPCHR, respectively,
|
||||
for compatibility with the HP 2100 simulator's LPT device.
|
||||
|
||||
- The manual clarifies that the display radix for shift counts, bit positions,
|
||||
starting bits and counts, and the CIR values for the PAUS and HALT
|
||||
instructions may be overridden with command-line switches.
|
||||
|
||||
|
||||
----------
|
||||
Bugs Fixed
|
||||
----------
|
||||
|
||||
1. PROBLEM: Cancelling a deferred detach with ATTACH LP is rejected.
|
||||
|
||||
VERSION: Release 5.
|
||||
|
||||
OBSERVATION: The line printer "Unit Options" section of the HP 3000
|
||||
Simulator User's Guide states that a DETACH LP command will be deferred if
|
||||
there are characters in the print buffer. It further states that entering
|
||||
ATTACH LP without specifying a filename will cancel the action. This does
|
||||
not work. Entering ATTACH LP prints "Too few arguments" and does not alter
|
||||
a pending detach.
|
||||
|
||||
CAUSE: The SCP routine "attach_cmd" checks for the presence of a filename
|
||||
before calling the line printer simulator's "lp_attach" routine. If the
|
||||
filename is omitted, "lp_attach" is never called to cancel the pending
|
||||
detach.
|
||||
|
||||
RESOLUTION: Modify "lp_set_on_offline" (hp3000_lp.c) to cancel a deferred
|
||||
detach, and modify the User's Guide to state that SET LP ONLINE is used to
|
||||
cancel both the deferred offline and deferred detach actions.
|
||||
|
||||
STATUS: Fixed in Release 6.
|
||||
|
||||
|
||||
2. PROBLEM: Changing printer models does not change the REALTIME delays.
|
||||
|
||||
VERSION: Release 5.
|
||||
|
||||
OBSERVATION: In REALTIME mode, the line printer simulator attempts to
|
||||
model the print buffer load and print-and-space operation delays inherent
|
||||
in the physical hardware. However, after setting a different model, the
|
||||
buffer load, print, and paper advance times have not been changed.
|
||||
|
||||
CAUSE: The "lp_set_model" routine that is called in response to a "SET
|
||||
LP <model>" command sets the realistic times to those of the current model
|
||||
rather than those of the new model.
|
||||
|
||||
RESOLUTION: Modify "lp_set_model" (hp3000_lp.c) to use the new model value
|
||||
to index into the realistic times array.
|
||||
|
||||
STATUS: Fixed in Release 6.
|
||||
|
||||
|
||||
3. PROBLEM: Paper cannot be removed from a 2607 printer except at the TOF.
|
||||
|
||||
VERSION: Release 5.
|
||||
|
||||
OBSERVATION: Printing a few lines on a 2607 and then attempting to remove
|
||||
the paper with the DETACH LP command displays "Command not completed" on
|
||||
the simulation console. The file remains attached and therefore cannot be
|
||||
manipulated externally.
|
||||
|
||||
CAUSE: The DETACH command simulates both running out of paper and removing
|
||||
the paper from the printer. For the former, the 2607 continues to print
|
||||
until the current form is complete (i.e., the top of what would be the next
|
||||
form is reached). For the latter, the paper may be physically removed by
|
||||
the operator while at any print position. The simulator incorrectly
|
||||
forbids the latter operation unless the paper is positioned at the TOF.
|
||||
|
||||
RESOLUTION: Modify "lp_detach" (hp3000_lp.c) to add a "forced detach"
|
||||
option ("DETACH -F LP") to detach the printer regardless of print position.
|
||||
|
||||
STATUS: Fixed in Release 6.
|
||||
|
||||
|
||||
|
||||
=====================
|
||||
Release 5, 2017-04-30
|
||||
=====================
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* hp3000_sel.c: HP 3000 30030C Selector Channel simulator
|
||||
|
||||
Copyright (c) 2016, J. David Bryan
|
||||
Copyright (c) 2016-2017, J. David Bryan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
SEL HP 3000 Series III Selector Channel
|
||||
|
||||
05-Sep-17 JDB Changed REG_A (permit any symbolic override) to REG_X
|
||||
10-Oct-16 JDB Renumbered debug flags to start at 0
|
||||
Added port_read_memory, port_write_memory macros
|
||||
11-Jul-16 JDB Change "sel_unit" from a UNIT to an array of one UNIT
|
||||
@@ -458,8 +459,8 @@ static REG sel_reg [] = {
|
||||
{ ORDATA (CNBUF, control_buffer, 16), REG_FIT },
|
||||
{ ORDATA (ADDR, address_word, 16), REG_FIT },
|
||||
{ ORDATA (ADBUF, address_buffer, 16), REG_FIT },
|
||||
{ ORDATA (INBUF, input_buffer, 16), REG_A | REG_FIT },
|
||||
{ ORDATA (OUTBUF, output_buffer, 16), REG_A | REG_FIT },
|
||||
{ ORDATA (INBUF, input_buffer, 16), REG_X | REG_FIT },
|
||||
{ ORDATA (OUTBUF, output_buffer, 16), REG_X | REG_FIT },
|
||||
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from the author.
|
||||
|
||||
05-Sep-17 JDB Removed the -B (binary display) option; use -2 instead
|
||||
Rewrote "fprint_sym" for better coverage
|
||||
11-May-17 JDB Corrected comment in "fprint_value"
|
||||
28-Apr-17 JDB Added void cast to "fprint_instruction" call for left stackop
|
||||
03-Mar-17 JDB Added an implementation note to the "parse_sym" routine
|
||||
29-Dec-16 JDB Changed the switch for STA format from -S to -T;
|
||||
@@ -33,7 +36,7 @@
|
||||
27-Sep-16 JDB Added COBOL firmware mnemonics
|
||||
Modified "fprint_instruction" to handle two-word instructions
|
||||
15-Sep-16 JDB Modified "one_time_init" to set aux_cmds "message" field
|
||||
03-Sep-16 JDB Added the STOP_POWER and STOP_ARSINH messages
|
||||
03-Sep-16 JDB Added the STOP_POWER and STOP_ARSINH status messages
|
||||
01-Sep-16 JDB Moved the "hp_cold_cmd" routine to the CPU (as "cpu_cold_cmd")
|
||||
Added the POWER command
|
||||
03-Aug-16 JDB Improved "fmt_char" and "fmt_bitset" to allow multiple calls
|
||||
@@ -100,6 +103,26 @@ extern DEVICE ms_dev; /* 7970 Magnetic Tape */
|
||||
#define SCPE_OK_3_WORDS ((t_stat) -2) /* three words produced or consumed */
|
||||
|
||||
|
||||
/* Symbolic mode and format override switches */
|
||||
|
||||
#define A_SWITCH SWMASK ('A')
|
||||
#define B_SWITCH SWMASK ('B')
|
||||
#define C_SWITCH SWMASK ('C')
|
||||
#define D_SWITCH SWMASK ('D')
|
||||
#define E_SWITCH SWMASK ('E')
|
||||
#define H_SWITCH SWMASK ('H')
|
||||
#define I_SWITCH SWMASK ('I')
|
||||
#define M_SWITCH SWMASK ('M')
|
||||
#define O_SWITCH SWMASK ('O')
|
||||
#define T_SWITCH SWMASK ('T')
|
||||
|
||||
#define MODE_SWITCHES (C_SWITCH | E_SWITCH | I_SWITCH | M_SWITCH | T_SWITCH)
|
||||
#define FORMAT_SWITCHES (A_SWITCH | B_SWITCH | D_SWITCH | H_SWITCH | O_SWITCH)
|
||||
|
||||
#define SYMBOLIC_SWITCHES (MODE_SWITCHES | A_SWITCH) /* -A is both a mode and a format switch */
|
||||
#define ALL_SWITCHES (MODE_SWITCHES | FORMAT_SWITCHES)
|
||||
|
||||
|
||||
/* Address parsing configuration flags */
|
||||
|
||||
typedef enum {
|
||||
@@ -952,7 +975,7 @@ static t_stat hp_brk_cmd (int32 arg, CONST char *buf);
|
||||
|
||||
/* System interface local utility routines */
|
||||
|
||||
static void fprint_value (FILE *ofile, t_value val, uint32 radix, uint32 width, uint32 format);
|
||||
static t_stat fprint_value (FILE *ofile, t_value val, uint32 radix, uint32 width, uint32 format);
|
||||
static t_stat fprint_order (FILE *ofile, t_value *val, uint32 radix);
|
||||
static t_stat fprint_subop (FILE *ofile, t_value *val, uint32 radix, t_addr addr, int32 switches);
|
||||
static t_stat fprint_instruction (FILE *ofile, const OP_TABLE ops, t_value *val,
|
||||
@@ -1177,58 +1200,85 @@ return SCPE_ARG; /* return an error if ca
|
||||
|
||||
/* Print a value in symbolic format.
|
||||
|
||||
Print the data value in the format specified by the optional switches on the
|
||||
output stream supplied. This routine is called to print:
|
||||
This routine prints a data value in the format specified by the optional
|
||||
switches on the output stream provided. On entry, "ofile" is the opened
|
||||
output stream, and the other parameters depend on the reason the routine was
|
||||
called, as follows:
|
||||
|
||||
- the next instruction mnemonic when the simulator stops
|
||||
- the result of EXAMining a register marked with a user flag
|
||||
- the result of EXAMining a memory address
|
||||
- the result of EVALuating a symbol
|
||||
* To print the next instruction mnemonic when the simulator stops:
|
||||
- addr = the program counter
|
||||
- val = a pointer to sim_eval [0]
|
||||
- uptr = NULL
|
||||
- sw = "-M" | SIM_SW_STOP
|
||||
|
||||
On entry, "ofile" is the opened output stream, "addr" is respectively the
|
||||
program counter, register radix and flags, memory address, or symbol index,
|
||||
"val" is a pointer to an array of t_values of depth "sim_emax" representing
|
||||
the value to be printed, "uptr" is respectively NULL, NULL, a pointer to the
|
||||
named unit, or a pointer to the default unit, and "sw" contains any switches
|
||||
passed on the command line. "sw" also includes SIM_SW_STOP for a simulator
|
||||
stop call or SIM_SW_REG for a register call.
|
||||
* To print the result of EXAMining a register with REG_VMIO or a user flag:
|
||||
- addr = the ORed register radix and user flags
|
||||
- val = a pointer to a single t_value
|
||||
- uptr = NULL
|
||||
- sw = the command line switches | SIM_SW_REG
|
||||
|
||||
* To print the result of EXAMining a memory address:
|
||||
- addr = the memory address
|
||||
- val = a pointer to sim_eval [0]
|
||||
- uptr = a pointer to the named unit
|
||||
- sw = the command line switches
|
||||
|
||||
* To print the result of EVALuating a symbol:
|
||||
- addr = the symbol index
|
||||
- val = a pointer to sim_eval [addr]
|
||||
- uptr = a pointer to the default unit (cpu_unit)
|
||||
- sw = the command line switches
|
||||
|
||||
On exit, a status code is returned to the caller. If the format requested is
|
||||
not supported, SCPE_ARG status is returned, which causes the caller to print
|
||||
the value in numeric format. Otherwise, SCPE_OK status is returned if a
|
||||
single-word value was consumed, or the negative number of extra words (beyond
|
||||
the first) consumed in printing the symbol is returned. For example,
|
||||
printing a two-word symbol would return SCPE_OK_2_WORDS (= -1).
|
||||
the value in numeric format with the default radix. Otherwise, SCPE_OK
|
||||
status is returned if a single-word value was consumed, or the negative
|
||||
number of extra words (beyond the first) consumed in printing the symbol is
|
||||
returned. For example, printing a two-word symbol would return
|
||||
SCPE_OK_2_WORDS (= -1).
|
||||
|
||||
The following symbolic formats are supported by the listed switches:
|
||||
The following symbolic modes are supported by including the indicated
|
||||
switches on the command line:
|
||||
|
||||
Switch Interpretation
|
||||
Switch Display Interpretation
|
||||
------ --------------------------------------------------
|
||||
-a a single character in the right-hand byte
|
||||
-b a 16-bit binary value
|
||||
-c a two-character packed string
|
||||
-e an EDIT instruction subprogram mnemonic
|
||||
-i an I/O program instruction mnemonic
|
||||
-m a CPU instruction mnemonic
|
||||
-s a CPU status mnemonic
|
||||
-A a single character in the right-hand byte
|
||||
-C a two-character packed string
|
||||
-E an EDIT instruction subprogram mnemonic
|
||||
-ER an EDIT mnemonic starting with the right-hand byte
|
||||
-I an I/O program instruction mnemonic
|
||||
-M a CPU instruction mnemonic
|
||||
-T a CPU status mnemonic
|
||||
|
||||
-o override numeric output to octal
|
||||
-d override numeric output to decimal
|
||||
-h override numeric output to hex
|
||||
-r begin EDIT interpretation with the right-hand byte
|
||||
In the absence of a mode switch, the value is displayed in a numeric format.
|
||||
|
||||
Memory may be displayed in any format. All registers may be overridden to
|
||||
display in octal, decimal, or hexadecimal numeric format. Only registers
|
||||
marked with the REG_A flag may be displayed in any format. Registers marked
|
||||
with REG_B may be displayed in binary format. Registers marked with REG_M
|
||||
will default to CPU instruction mnemonic display. Registers marked with
|
||||
REG_T will default to CPU status mnemonic display.
|
||||
When displaying data in one of the mnemonic modes, an additional switch may
|
||||
be specified to indicate the desired operand format, as follows:
|
||||
|
||||
When displaying mnemonics, operand values are displayed in a radix suitable
|
||||
to the type of the value. Address values are displayed in the CPU's address
|
||||
radix, which is octal, and data values are displayed in the CPU's data radix,
|
||||
which defaults to octal but may be set to a different radix or overridden by
|
||||
a switch on the command line.
|
||||
Switch Operand Interpretation
|
||||
------ --------------------------------------------------
|
||||
-A a single character in the right-hand byte
|
||||
-B a binary value
|
||||
-O an octal value
|
||||
-D a decimal value
|
||||
-H a hexadecimal value
|
||||
|
||||
Except for -B, these switches may be used without a mode switch to display a
|
||||
numeric value in the specified form. To summarize, the valid switch
|
||||
combinations are:
|
||||
|
||||
-A
|
||||
-C
|
||||
-E [ -R ] [ -A | -B | -O | -D | -H ]
|
||||
-I [ -A | -B | -O | -D | -H ]
|
||||
-M [ -A | -B | -O | -D | -H ]
|
||||
-T [ -A | -B | -O | -D | -H ]
|
||||
|
||||
When displaying mnemonics, operand values by default are displayed in a radix
|
||||
suitable to the type of the value. Address values are displayed in the CPU's
|
||||
address radix, which is octal, and data values are displayed in the CPU's
|
||||
data radix, which defaults to octal but may be set to a different radix or
|
||||
overridden by a switch on the command line.
|
||||
|
||||
|
||||
Implementation notes:
|
||||
@@ -1241,76 +1291,116 @@ return SCPE_ARG; /* return an error if ca
|
||||
2. Displaying a register having a symbolic default format (e.g., CIR) will
|
||||
use the default unless the radix is overridden on the command line. For
|
||||
example, "EXAMINE CIR" displays the CIR value as an instruction mnemonic,
|
||||
whereas "EXAMINE -O CIR" displays the value as octal. Adding "-M" will
|
||||
whereas "EXAMINE -D CIR" displays the value as decimal. Adding "-M" will
|
||||
force mnemonic display and allow the radix switch to override the operand
|
||||
display. For example, "EXAMINE -M -O CIR" displays the value as mnemonic
|
||||
and overrides the operand radix to octal.
|
||||
display. For example, "EXAMINE -M -D CIR" displays the value as mnemonic
|
||||
and overrides the operand radix to decimal.
|
||||
|
||||
3. We return SCPE_INVSW when multiple modes or formats are specified, but
|
||||
the callers do not act on this; they use the fallback formatter if any
|
||||
status error is returned. We could work around this by printing "Invalid
|
||||
switch" to the console and returning SCPE_OK, but this does not stop
|
||||
IEXAMINE from prompting for the replacement value(s) or EXAMINE from
|
||||
printing a range.
|
||||
|
||||
4. Radix switches and the -C switch are conceptually mutually exclusive.
|
||||
However, if we return an error when "format" is non-zero, then -C will be
|
||||
ignored, and the fallback formatter will use the radix switch. The other
|
||||
choice is to process -C and ignore the radix switch; this is the option
|
||||
implemented.
|
||||
|
||||
5. Because -A is both a mode and a format switch, we must check its presence
|
||||
using SYMBOLIC_SWITCHES separately from the other modes to allow (e.g.)
|
||||
both "EXAMINE -A" and "EXAMINE -M -A". If -A is added to MODE_SWITCHES,
|
||||
the latter form would be rejected as having conflicting modes.
|
||||
|
||||
6. The penultimate condition of the multiway "if-else if" mode test checks
|
||||
for no mode switches. This succeeds when -A is specified alone because
|
||||
the earlier SYMBOLIC_SWITCHES test failed (so -A is present), but none of
|
||||
the other mode switches are present.
|
||||
*/
|
||||
|
||||
t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, UNIT *uptr, int32 sw)
|
||||
{
|
||||
const t_bool is_reg = (sw & SIM_SW_REG) != 0; /* TRUE if this is a register access */
|
||||
uint32 radix_override;
|
||||
int32 formats, modes;
|
||||
uint32 radix;
|
||||
|
||||
if (sw & SWMASK ('A') && (!is_reg || addr & REG_A)) /* if ASCII character display is requested and permitted */
|
||||
if (val [0] <= D8_SMAX) { /* then if the value is a single character */
|
||||
fputs (fmt_char ((uint32) val [0]), ofile); /* then format and print it */
|
||||
return SCPE_OK;
|
||||
}
|
||||
if ((sw & (SIM_SW_REG | ALL_SWITCHES)) == SIM_SW_REG) /* if we are formatting a register without overrides */
|
||||
if (addr & REG_A) /* then if the default format is character */
|
||||
sw |= A_SWITCH; /* then set the -A switch */
|
||||
|
||||
else /* otherwise */
|
||||
return SCPE_ARG; /* report that it cannot be displayed */
|
||||
else if (addr & REG_C) /* otherwise if the default mode is string */
|
||||
sw |= C_SWITCH; /* then set the -C switch */
|
||||
|
||||
else if (sw & SWMASK ('C') && (!is_reg || addr & REG_A)) { /* if ASCII string display is requested and permitted */
|
||||
fputs (fmt_char (UPPER_BYTE (val [0])), ofile); /* then format and print the upper byte */
|
||||
fputc (',', ofile); /* followed by a separator */
|
||||
fputs (fmt_char (LOWER_BYTE (val [0])), ofile); /* then format and print the lower byte */
|
||||
else if (addr & REG_M) /* otherwise if the default mode is instruction mnemonic */
|
||||
sw |= M_SWITCH; /* then set the -M switch */
|
||||
|
||||
else if (addr & REG_T) /* otherwise if the default mode is status */
|
||||
sw |= T_SWITCH; /* then set the -T switch */
|
||||
|
||||
if ((sw & SYMBOLIC_SWITCHES) == 0) /* if there are no symbolic mode overrides */
|
||||
return SCPE_ARG; /* then return an error to use the standard formatter */
|
||||
|
||||
|
||||
formats = sw & FORMAT_SWITCHES; /* separate the format switches */
|
||||
modes = sw & MODE_SWITCHES; /* from the mode switches */
|
||||
|
||||
if (formats == A_SWITCH) /* if the -A switch is specified */
|
||||
radix = 256; /* then override the radix to character */
|
||||
|
||||
else if (formats == B_SWITCH) /* otherwise if the -B switch is specified */
|
||||
radix = 2; /* then override the radix to binary */
|
||||
|
||||
else if (formats == D_SWITCH) /* otherwise if the -D switch is specified */
|
||||
radix = 10; /* then override the radix to decimal */
|
||||
|
||||
else if (formats == H_SWITCH) /* otherwise if the -H switch is specified */
|
||||
radix = 16; /* then override the radix to hexadecimal */
|
||||
|
||||
else if (formats == O_SWITCH) /* otherwise if the -O switch is specified */
|
||||
radix = 8; /* then override the radix to octal */
|
||||
|
||||
else if (formats == 0) /* otherwise if no format switch is specified */
|
||||
radix = 0; /* then indicate that the default radix is to be used */
|
||||
|
||||
else /* otherwise more than one format is specified */
|
||||
return SCPE_INVSW; /* so return an error */
|
||||
|
||||
if (modes == M_SWITCH) /* if mnemonic mode is specified */
|
||||
return fprint_cpu (ofile, val, radix, sw); /* then format and print the value in mnemonic format */
|
||||
|
||||
else if (modes == I_SWITCH) /* otherwise if I/O channel order mode is specified */
|
||||
return fprint_order (ofile, val, radix); /* then format and print it */
|
||||
|
||||
else if (modes == E_SWITCH) /* otherwise if an EDIT subop memory display is requested */
|
||||
return fprint_subop (ofile, val, radix, addr, sw); /* then format and print it */
|
||||
|
||||
else if (modes == T_SWITCH) { /* otherwise if status display is requested */
|
||||
fputs (fmt_status ((uint32) val [0]), ofile); /* then format the status flags and condition code */
|
||||
fputc (' ', ofile); /* and add a separator */
|
||||
|
||||
if (fprint_value (ofile, STATUS_CS (val [0]), /* if the code segment number */
|
||||
(radix ? radix : cpu_dev.dradix), /* prints with the specified radix */
|
||||
STATUS_CS_WIDTH, PV_RZRO) == SCPE_OK)
|
||||
return SCPE_OK; /* then return success */
|
||||
|
||||
else /* otherwise print it */
|
||||
return fprint_val (ofile, STATUS_CS (val [0]), /* in the CPU's default data radix */
|
||||
cpu_dev.dradix, D8_WIDTH, PV_RZRO);
|
||||
}
|
||||
|
||||
else if (modes == C_SWITCH) { /* otherwise if ASCII string mode is specified */
|
||||
fputs (fmt_char (UPPER_BYTE (val [0])), ofile); /* then format and print the upper byte */
|
||||
fputc (',', ofile); /* followed by a separator */
|
||||
fputs (fmt_char (LOWER_BYTE (val [0])), ofile); /* followed by the lower byte */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
else if (sw & SWMASK ('B') /* if binary display is requested */
|
||||
&& (!is_reg || addr & (REG_A | REG_B))) { /* and is permitted */
|
||||
fprint_val (ofile, val [0], 2, DV_WIDTH, PV_RZRO); /* then format and print the value */
|
||||
return SCPE_OK;
|
||||
}
|
||||
else if (modes == 0) /* otherwise if single-character mode was specified */
|
||||
return fprint_value (ofile, val [0], radix, 0, 0); /* then format and print it */
|
||||
|
||||
else { /* otherwise display as numeric or mnemonic */
|
||||
if (sw & SWMASK ('O')) /* if an octal override is present */
|
||||
radix_override = 8; /* then print the value in base 8 */
|
||||
else if (sw & SWMASK ('D')) /* otherwise if a decimal override is present */
|
||||
radix_override = 10; /* then print the value in base 10 */
|
||||
else if (sw & SWMASK ('H')) /* otherwise if a hex override is present */
|
||||
radix_override = 16; /* then print the value in base 16 */
|
||||
else /* otherwise */
|
||||
radix_override = 0; /* use the default radix setting */
|
||||
|
||||
if (sw & SWMASK ('I') && !is_reg) /* if I/O channel order memory display is requested */
|
||||
return fprint_order (ofile, val, radix_override); /* then format and print it */
|
||||
|
||||
else if (sw & SWMASK ('E') && !is_reg) /* otherwise if an EDIT subop memory display is requested */
|
||||
return fprint_subop (ofile, val, radix_override, addr, sw);
|
||||
|
||||
else if (sw & SWMASK ('M') /* otherwise if CPU instruction display is requested */
|
||||
&& (!is_reg || addr & (REG_A | REG_M)) /* and is permitted */
|
||||
|| is_reg && addr & REG_M && radix_override == 0) /* or if displaying a register that defaults to mnemonic */
|
||||
return fprint_cpu (ofile, val, radix_override, sw); /* then format and print it */
|
||||
|
||||
else if (sw & SWMASK ('T') /* otherwise if status display is requested */
|
||||
&& (!is_reg || addr & (REG_A | REG_T)) /* and is permitted */
|
||||
|| is_reg && addr & REG_T && radix_override == 0) { /* or if displaying a register that defaults to status */
|
||||
fputs (fmt_status ((uint32) val [0]), ofile); /* then format the status flags and condition code */
|
||||
fputc (' ', ofile); /* and add a separator */
|
||||
|
||||
fprint_value (ofile, STATUS_CS (val [0]), /* print the code segment number */
|
||||
(radix_override ? radix_override : cpu_dev.dradix),
|
||||
STATUS_CS_WIDTH, PV_RZRO);
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
else /* otherwise */
|
||||
return SCPE_ARG; /* request that the value be printed numerically */
|
||||
}
|
||||
else /* otherwise the modes conflict */
|
||||
return SCPE_INVSW; /* so return an error */
|
||||
}
|
||||
|
||||
|
||||
@@ -2025,11 +2115,11 @@ return formatted; /* return a pointer to t
|
||||
|
||||
/* Format a character for printing.
|
||||
|
||||
This routine formats single 8-bit character value into a printable string and
|
||||
returns a pointer to that string. Printable characters retain their original
|
||||
form but are enclosed in single quotes. Control characters are translated to
|
||||
readable strings. Characters outside of the ASCII range are presented as
|
||||
escaped octal values.
|
||||
This routine formats a single 8-bit character value into a printable string
|
||||
and returns a pointer to that string. Printable characters retain their
|
||||
original form but are enclosed in single quotes. Control characters are
|
||||
translated to readable strings. Characters outside of the ASCII range are
|
||||
presented as escaped octal values.
|
||||
|
||||
|
||||
Implementation notes:
|
||||
@@ -2914,24 +3004,39 @@ return status; /* return the handler st
|
||||
/* System interface local utility routines */
|
||||
|
||||
|
||||
/* Print a numeric value with a radix identifier.
|
||||
/* Print a numeric value in a given radix with a radix identifier.
|
||||
|
||||
This routine prints a numeric value with a leading radix indicator if the
|
||||
specified print radix is not the same as the current CPU data radix. It uses
|
||||
the HP 3000 convention of a leading "%", "#", or "!" character to indicate
|
||||
an octal, decimal, or hexadecimal number.
|
||||
This routine prints a numeric value using the specified radix, width, and
|
||||
output format. If the radix is 256, then the value is printed as a single
|
||||
character. Otherwise, it is printed as a numeric value with a leading radix
|
||||
indicator if the specified print radix is not the same as the current CPU
|
||||
data radix. It uses the HP 3000 convention of a leading "%", "#", or "!"
|
||||
character to indicate an octal, decimal, or hexadecimal number (there is no
|
||||
binary convention, so a leading "@" is used arbitrarily).
|
||||
|
||||
On entry, the "ofile" parameter is the opened output stream, "val" is the
|
||||
value to print, "radix" is the desired print radix, "width" is the number of
|
||||
significant bits in the value, and "format" is a format specifier (PV_RZRO,
|
||||
PV_RSPC, or PV_LEFT). On exit, the status of the print operation is
|
||||
returned.
|
||||
PV_RSPC, or PV_LEFT). On exit, the routine returns SCPE_OK if the value was
|
||||
printed successfully, or SCPE_ARG if the value could not be printed.
|
||||
*/
|
||||
|
||||
static void fprint_value (FILE *ofile, t_value val, uint32 radix, uint32 width, uint32 format)
|
||||
static t_stat fprint_value (FILE *ofile, t_value val, uint32 radix, uint32 width, uint32 format)
|
||||
{
|
||||
if (radix != cpu_dev.dradix) /* if the requested radix is not the current data radix */
|
||||
if (radix == 8) /* then if the requested radix is octal */
|
||||
if (radix == 256) /* if ASCII character display is requested */
|
||||
if (val <= D8_SMAX) { /* then if the value is a single character */
|
||||
fputs (fmt_char ((uint32) val), ofile); /* then format and print it */
|
||||
return SCPE_OK; /* and report success */
|
||||
}
|
||||
|
||||
else /* otherwise */
|
||||
return SCPE_ARG; /* report that it cannot be displayed */
|
||||
|
||||
else if (radix != cpu_dev.dradix) /* otherwise if the requested radix is not the current data radix */
|
||||
if (radix == 2) /* then if the requested radix is binary */
|
||||
fputc ('@', ofile); /* then print the binary indicator */
|
||||
|
||||
else if (radix == 8) /* otherwise if the requested radix is octal */
|
||||
fputc ('%', ofile); /* then print the octal indicator */
|
||||
|
||||
else if (radix == 10) /* otherwise if it is decimal */
|
||||
@@ -2945,7 +3050,7 @@ if (radix != cpu_dev.dradix) /* if the requested radi
|
||||
|
||||
fprint_val (ofile, val, radix, width, format); /* print the value in the radix specified */
|
||||
|
||||
return;
|
||||
return SCPE_OK; /* return success */
|
||||
}
|
||||
|
||||
|
||||
@@ -2979,16 +3084,15 @@ return;
|
||||
|
||||
- Address values are printed in the CPU's address radix, which is octal.
|
||||
|
||||
- Counts are printed in decimal.
|
||||
- Counts are printed by default in decimal.
|
||||
|
||||
- Control and status values are printed in the CPU's data radix, which
|
||||
defaults to octal but may be set to a different radix with SET CPU
|
||||
OCT|DEC|HEX.
|
||||
defaults to octal.
|
||||
|
||||
The radix for operand values other than addresses may be overridden by a
|
||||
switch on the command line. A value printed in a radix other than the
|
||||
current data radix is preceded by a radix identifier ("%" for octal, "#" for
|
||||
decimal, or "!" for hexadecimal).
|
||||
current data radix is preceded by a radix identifier ("@" for binary, "%" for
|
||||
octal, "#" for decimal, or "!" for hexadecimal).
|
||||
|
||||
The routine returns SCPE_OK_2_WORDS to indicate that two words were consumed.
|
||||
|
||||
@@ -3031,7 +3135,7 @@ switch (order) { /* dispatch operand prin
|
||||
|
||||
case sioJUMP:
|
||||
case sioJUMPC: /* print the jump target address */
|
||||
fprint_value (ofile, ioaw, cpu_dev.aradix,
|
||||
fprint_value (ofile, ioaw, cpu_dev.aradix, /* in the CPU's address radix */
|
||||
LA_WIDTH, PV_RZRO);
|
||||
break;
|
||||
|
||||
@@ -3042,7 +3146,7 @@ switch (order) { /* dispatch operand prin
|
||||
break;
|
||||
|
||||
case sioSBANK: /* print the bank address */
|
||||
fprint_value (ofile, ioaw & BA_MASK,
|
||||
fprint_value (ofile, ioaw & BA_MASK, /* in the CPU's address radix */
|
||||
cpu_dev.aradix, BA_WIDTH, PV_RZRO);
|
||||
break;
|
||||
|
||||
@@ -3078,7 +3182,7 @@ switch (order) { /* dispatch operand prin
|
||||
|
||||
fputc (',', ofile);
|
||||
|
||||
fprint_value (ofile, ioaw, cpu_dev.aradix,
|
||||
fprint_value (ofile, ioaw, cpu_dev.aradix, /* prnit the address in the CPU's address radix */
|
||||
LA_WIDTH, PV_RZRO);
|
||||
break;
|
||||
}
|
||||
@@ -3562,7 +3666,6 @@ switch (ops [op_index].operand) { /* dispatch by the opera
|
||||
prefix = " "; /* so just use a space to separate the value */
|
||||
|
||||
op_value = (op_value & ~op_mask [opS11]) >> EIS_SDEC_SHIFT; /* remove the flags from the S decrement value */
|
||||
op_radix = (radix ? radix : cpu_dev.dradix); /* and set the print radix */
|
||||
break;
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* hp_disclib.h: HP MAC/ICD disc controller simulator library declarations
|
||||
|
||||
Copyright (c) 2011-2016, J. David Bryan
|
||||
Copyright (c) 2011-2017, J. David Bryan
|
||||
Copyright (c) 2004-2011, Robert M. Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@@ -24,6 +24,7 @@
|
||||
in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from the authors.
|
||||
|
||||
05-Sep-17 JDB Changed REG_A (permit any symbolic override) to REG_X
|
||||
10-Oct-16 JDB Moved "hp3000_defs.h" inclusion to "hp_disclib.c"
|
||||
13-May-16 JDB Modified for revised SCP API function parameter types
|
||||
24-Mar-16 JDB Added the DL_BUFFER type to define the disc buffer array
|
||||
@@ -479,7 +480,7 @@ typedef CNTLR_VARS *CVPTR; /* pointer to a controller state
|
||||
{ DRDATA (HEAD, (cntlr).head, 6), PV_LEFT }, \
|
||||
{ DRDATA (SECTOR, (cntlr).sector, 8), PV_LEFT }, \
|
||||
{ DRDATA (COUNT, (cntlr).count, 16), PV_LEFT }, \
|
||||
{ BRDATA (SECBUF, (buffer), 8, 16, DL_BUFSIZE), REG_A }, \
|
||||
{ BRDATA (SECBUF, (buffer), 8, 16, DL_BUFSIZE), REG_X }, \
|
||||
{ DRDATA (INDEX, (cntlr).index, 8), PV_LEFT }, \
|
||||
{ DRDATA (LENGTH, (cntlr).length, 8), PV_LEFT }, \
|
||||
{ DRDATA (POLLU, (cntlr).poll_unit, 4), REG_HRO }, \
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* hp_tapelib.h: HP magnetic tape controller simulator library declarations
|
||||
|
||||
Copyright (c) 2013-2016, J. David Bryan
|
||||
Copyright (c) 2013-2017, J. David Bryan
|
||||
Copyright (c) 2004-2011, Robert M. Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@@ -24,6 +24,7 @@
|
||||
in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from the authors.
|
||||
|
||||
05-Sep-17 JDB Changed REG_A (permit any symbolic override) to REG_X
|
||||
10-Oct-16 JDB Moved "hp3000_defs.h" inclusion to "hp_tapelib.c"
|
||||
13-May-16 JDB Modified for revised SCP API function parameter types
|
||||
24-Mar-16 JDB Added the TL_BUFFER type to define the tape buffer array
|
||||
@@ -419,7 +420,7 @@ typedef CNTLR_VARS *CVPTR; /* a pointer to a controller sta
|
||||
{ ORDATA (STATUS, (cntlr).status, 16), REG_RO }, \
|
||||
{ DRDATA (USEL, (cntlr).unit_selected, 4), PV_LEFT | REG_RO }, \
|
||||
{ YRDATA (UATTN, (cntlr).unit_attention, 4, PV_RZRO) }, \
|
||||
{ BRDATA (RECBUF, (buffer), 8, 8, TL_BUFSIZE), REG_A }, \
|
||||
{ BRDATA (RECBUF, (buffer), 8, 8, TL_BUFSIZE), REG_X }, \
|
||||
{ DRDATA (LIBSTA, (cntlr).call_status, 16), PV_LEFT }, \
|
||||
{ DRDATA (LENGTH, (cntlr).length, 24), PV_LEFT }, \
|
||||
{ DRDATA (INDEX, (cntlr).index, 24), PV_LEFT }, \
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user