1
0
mirror of https://github.com/simh/simh.git synced 2026-03-04 18:44:11 +00:00

HP2100: Release 28

See HP2100/hp2100_release.txt for details of the release.
This commit is contained in:
Mark Pizzolato
2018-06-03 15:30:52 -07:00
parent 839c5ac3ce
commit d6d188f5f1
38 changed files with 23760 additions and 10321 deletions

View File

@@ -1,6 +1,6 @@
/* hp2100_baci.c: HP 12966A buffered asynchronous communications interface simulator
/* hp2100_baci.c: HP 12966A Buffered Asynchronous Communications Interface simulator
Copyright (c) 2007-2016, J. David Bryan
Copyright (c) 2007-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"),
@@ -23,8 +23,13 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from the author.
BACI 12966A BACI card
BACI 12966A Buffered Asynchronous Communications Interface
01-Nov-17 JDB Fixed serial output buffer overflow handling
15-Mar-17 JDB Trace flags are now global
Changed DEBUG_PRI calls to tprintfs
10-Mar-17 JDB Added IOBUS to the debug table
17-Jan-17 JDB Changed "hp_---sc" and "hp_---dev" to "hp_---_dib"
02-Aug-16 JDB "baci_poll_svc" now calls "tmxr_poll_conn" unilaterally
13-May-16 JDB Modified for revised SCP API function parameter types
24-Dec-14 JDB Added casts for explicit downward conversions
@@ -83,13 +88,13 @@
an "external rate" that is equivalent to 9600 baud, as most terminals were
set to their maximum speeds.
We support the 12966A connected to an HP terminal emulator via Telnet.
Internally, we model the BACI as a terminal multiplexer with one line. The
simulation is complicated by the half-duplex nature of the card (there is
only one FIFO, used selectively either for transmission or reception) and the
double-buffered UART (a Western Digital TR1863A), which has holding registers
as well as a shift registers for transmission and reception. We model both
sets of device registers.
We support the 12966A connected to an HP terminal emulator via Telnet or a
serial port. Internally, we model the BACI as a terminal multiplexer with
one line. The simulation is complicated by the half-duplex nature of the
card (there is only one FIFO, used selectively either for transmission or
reception) and the double-buffered UART (a Western Digital TR1863A), which
has holding registers as well as a shift registers for transmission and
reception. We model both sets of device registers.
During an output operation, the first character output to the card passes
through the FIFO and into the transmitter holding register. Subsequent
@@ -118,12 +123,12 @@
as an "optimized (fast) timing" option. Optimization makes three
improvements:
1. On output, characters in the FIFO are emptied into the Telnet buffer as a
1. On output, characters in the FIFO are emptied into the line buffer as a
block, rather than one character per service call, and on input, all of
the characters available in the Telnet buffer are loaded into the FIFO as
a block.
the characters available in the line buffer are loaded into the FIFO as a
block.
2. The ENQ/ACK handshake is done locally, without involving the Telnet
2. The ENQ/ACK handshake is done locally, without involving the terminal
client.
3. Input occurring during an output operation is delayed until the second or
@@ -184,14 +189,6 @@
#define UNIT_CAPSLOCK (1 << UNIT_V_CAPSLOCK)
/* Debug flags */
#define DEB_CMDS (1 << 0) /* commands and status */
#define DEB_CPU (1 << 1) /* CPU I/O */
#define DEB_BUF (1 << 2) /* buffer gets and puts */
#define DEB_XFER (1 << 3) /* character reads and writes */
/* Bit flags */
#define OUT_MR 0100000 /* common master reset */
@@ -322,7 +319,7 @@
/* Unit references */
#define baci_term baci_unit[0] /* terminal I/O unit */
#define baci_poll baci_unit[1] /* Telnet polling unit */
#define baci_poll baci_unit[1] /* line polling unit */
/* BACI state variables */
@@ -395,11 +392,11 @@ t_stat baci_detach (UNIT *uptr);
baci_deb BACI debug list
baci_dev BACI device descriptor
Two units are used: one to handle character I/O via the Telnet library, and
another to poll for connections and input. The character I/O service routine
runs only when there are characters to read or write. It operates at the
approximate baud rate of the terminal (in CPU instructions per second) in
order to be compatible with the OS drivers. The Telnet poll must run
Two units are used: one to handle character I/O via the multiplexer library,
and another to poll for connections and input. The character I/O service
routine runs only when there are characters to read or write. It operates at
the approximate baud rate of the terminal (in CPU instructions per second) in
order to be compatible with the OS drivers. The line poll must run
continuously, but it can operate much more slowly, as the only requirement is
that it must not present a perceptible lag to human input. To be compatible
with CPU idling, it is co-scheduled with the master poll timer, which uses a
@@ -408,59 +405,61 @@ t_stat baci_detach (UNIT *uptr);
DEVICE baci_dev;
TMLN baci_ldsc = { 0 }; /* line descriptor */
TMXR baci_desc = { 1, 0, 0, &baci_ldsc }; /* device descriptor */
TMLN baci_ldsc = { 0 }; /* line descriptor */
TMXR baci_desc = { 1, 0, 0, &baci_ldsc, NULL, &baci_dev }; /* device descriptor */
DIB baci_dib = { &baci_io, BACI, 0 };
UNIT baci_unit[] = {
{ UDATA (&baci_term_svc, UNIT_ATTABLE | UNIT_FASTTIME, 0) }, /* terminal I/O unit */
{ UDATA (&baci_poll_svc, UNIT_DIS, POLL_FIRST) } /* Telnet poll unit */
{ UDATA (&baci_poll_svc, UNIT_DIS, POLL_FIRST) } /* line poll unit */
};
REG baci_reg[] = {
{ ORDATA (IBUF, baci_ibuf, 16), REG_FIT },
{ ORDATA (OBUF, baci_obuf, 16), REG_FIT },
{ ORDATA (STATUS, baci_status, 16), REG_FIT },
REG baci_reg [] = {
/* Macro Name Location Radix Width Offset Depth Flags */
/* ------ -------- -------------------- ----- ----- ------ ---------- --------------- */
{ ORDATA (IBUF, baci_ibuf, 16), REG_FIT | REG_X },
{ ORDATA (OBUF, baci_obuf, 16), REG_FIT | REG_X },
{ GRDATA (STATUS, baci_status, 2, 16, 0), REG_FIT },
{ ORDATA (EDSIW, baci_edsiw, 16), REG_FIT },
{ ORDATA (DSRW, baci_dsrw, 16), REG_FIT },
{ ORDATA (CFCW, baci_cfcw, 16), REG_FIT },
{ ORDATA (ICW, baci_icw, 16), REG_FIT },
{ ORDATA (ISRW, baci_isrw, 16), REG_FIT },
{ ORDATA (EDSIW, baci_edsiw, 16), REG_FIT },
{ ORDATA (DSRW, baci_dsrw, 16), REG_FIT },
{ ORDATA (CFCW, baci_cfcw, 16), REG_FIT },
{ ORDATA (ICW, baci_icw, 16), REG_FIT },
{ ORDATA (ISRW, baci_isrw, 16), REG_FIT },
{ DRDATA (FIFOPUT, baci_fput, 8) },
{ DRDATA (FIFOGET, baci_fget, 8) },
{ DRDATA (FIFOCNTR, baci_fcount, 8) },
{ DRDATA (BRKCNTR, baci_bcount, 16) },
{ DRDATA (FIFOPUT, baci_fput, 8) },
{ DRDATA (FIFOGET, baci_fget, 8) },
{ DRDATA (FIFOCNTR, baci_fcount, 8) },
{ DRDATA (BRKCNTR, baci_bcount, 16) },
{ BRDATA (FIFO, baci_fifo, 8, 8, FIFO_SIZE) },
{ BRDATA (SPCHAR, baci_spchar, 8, 1, 256) },
{ BRDATA (FIFO, baci_fifo, 8, 8, FIFO_SIZE), REG_A },
{ BRDATA (SPCHAR, baci_spchar, 8, 1, 256) },
{ ORDATA (UARTTHR, baci_uart_thr, 16), REG_FIT },
{ ORDATA (UARTTR, baci_uart_tr, 16), REG_NZ },
{ ORDATA (UARTRHR, baci_uart_rhr, 16), REG_FIT },
{ ORDATA (UARTRR, baci_uart_rr, 16), REG_NZ },
{ DRDATA (UARTCLK, baci_uart_clk, 16) },
{ ORDATA (UARTTHR, baci_uart_thr, 16), REG_FIT | REG_X },
{ ORDATA (UARTTR, baci_uart_tr, 16), REG_NZ | REG_X },
{ ORDATA (UARTRHR, baci_uart_rhr, 16), REG_FIT | REG_X },
{ ORDATA (UARTRR, baci_uart_rr, 16), REG_NZ | REG_X },
{ DRDATA (UARTCLK, baci_uart_clk, 16) },
{ DRDATA (CTIME, baci_term.wait, 19), REG_RO },
{ DRDATA (CTIME, baci_term.wait, 19) },
{ FLDATA (ENQFLAG, baci_enq_seen, 0), REG_HRO },
{ DRDATA (ENQCNTR, baci_enq_cntr, 16), REG_HRO },
{ FLDATA (ENQFLAG, baci_enq_seen, 0), REG_HRO },
{ DRDATA (ENQCNTR, baci_enq_cntr, 16), REG_HRO },
{ FLDATA (LKO, baci.lockout, 0) },
{ FLDATA (CTL, baci.control, 0) },
{ FLDATA (FLG, baci.flag, 0) },
{ FLDATA (FBF, baci.flagbuf, 0) },
{ FLDATA (SRQ, baci.srq, 0) },
{ ORDATA (SC, baci_dib.select_code, 6), REG_HRO },
{ ORDATA (DEVNO, baci_dib.select_code, 6), REG_HRO },
{ FLDATA (LKO, baci.lockout, 0) },
{ FLDATA (CTL, baci.control, 0) },
{ FLDATA (FLG, baci.flag, 0) },
{ FLDATA (FBF, baci.flagbuf, 0) },
{ FLDATA (SRQ, baci.srq, 0) },
{ ORDATA (SC, baci_dib.select_code, 6), REG_HRO },
{ ORDATA (DEVNO, baci_dib.select_code, 6), REG_HRO },
{ NULL }
};
MTAB baci_mod[] = {
{ UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", NULL, NULL, NULL },
{ UNIT_DIAG, 0, "terminal mode", "TERMINAL", NULL, NULL, NULL },
{ UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAGNOSTIC", NULL, NULL, NULL },
{ UNIT_DIAG, 0, "terminal mode", "TERMINAL", NULL, NULL, NULL },
{ UNIT_FASTTIME, UNIT_FASTTIME, "fast timing", "FASTTIME", NULL, NULL, NULL },
{ UNIT_FASTTIME, 0, "realistic timing", "REALTIME", NULL, NULL, NULL },
@@ -468,24 +467,25 @@ MTAB baci_mod[] = {
{ UNIT_CAPSLOCK, UNIT_CAPSLOCK, "CAPS LOCK down", "CAPSLOCK", NULL, NULL, NULL },
{ UNIT_CAPSLOCK, 0, "CAPS LOCK up", "NOCAPSLOCK", NULL, NULL, NULL },
{ MTAB_XTD | MTAB_VDV | MTAB_NC, 0, "LOG", "LOG", &tmxr_set_log, &tmxr_show_log, &baci_desc },
{ MTAB_XTD | MTAB_VDV | MTAB_NC, 0, NULL, "NOLOG", &tmxr_set_nolog, NULL, &baci_desc },
{ MTAB_XDV | MTAB_NC, 0, "LOG", "LOG", &tmxr_set_log, &tmxr_show_log, &baci_desc },
{ MTAB_XDV | MTAB_NC, 0, NULL, "NOLOG", &tmxr_set_nolog, NULL, &baci_desc },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTION", NULL, NULL, &tmxr_show_cstat, &baci_desc },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, NULL, &tmxr_show_cstat, &baci_desc },
{ MTAB_XTD | MTAB_VDV, 0, NULL, "DISCONNECT", &tmxr_dscln, NULL, &baci_desc },
{ MTAB_XDV | MTAB_NMO, 1, "CONNECTION", NULL, NULL, &tmxr_show_cstat, &baci_desc },
{ MTAB_XDV | MTAB_NMO, 0, "STATISTICS", NULL, NULL, &tmxr_show_cstat, &baci_desc },
{ MTAB_XDV, 0, NULL, "DISCONNECT", &tmxr_dscln, NULL, &baci_desc },
{ MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &baci_dev },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &baci_dev },
{ MTAB_XDV, 1u, "SC", "SC", &hp_set_dib, &hp_show_dib, (void *) &baci_dib },
{ MTAB_XDV | MTAB_NMO, ~1u, "DEVNO", "DEVNO", &hp_set_dib, &hp_show_dib, (void *) &baci_dib },
{ 0 }
};
DEBTAB baci_deb[] = {
{ "CMDS", DEB_CMDS },
{ "CPU", DEB_CPU },
{ "BUF", DEB_BUF },
{ "XFER", DEB_XFER },
{ NULL, 0 }
DEBTAB baci_deb [] = {
{ "CMDS", DEB_CMDS },
{ "CPU", DEB_CPU },
{ "BUF", DEB_BUF },
{ "XFER", DEB_XFER },
{ "IOBUS", TRACE_IOBUS }, /* interface I/O bus signals and data words */
{ NULL, 0 }
};
DEVICE baci_dev = {
@@ -560,8 +560,7 @@ while (working_set) {
baci.flag = baci.flagbuf = CLEAR; /* clear flag and flag buffer */
baci.srq = CLEAR; /* clear SRQ */
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fputs (">>BACI cmds: [CLF] Flag and SRQ cleared\n", sim_deb);
tprintf (baci_dev, DEB_CMDS, "[CLF] Flag and SRQ cleared\n");
update_status (); /* FLG might set when SRQ clears */
break;
@@ -572,8 +571,7 @@ while (working_set) {
baci.lockout = SET; /* set lockout */
baci.srq = SET; /* set SRQ */
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fputs (">>BACI cmds: [STF] Flag, SRQ, and lockout set\n", sim_deb);
tprintf (baci_dev, DEB_CMDS, "[STF] Flag, SRQ, and lockout set\n");
break;
@@ -602,15 +600,15 @@ while (working_set) {
data = baci_ibuf; /* return received data */
if (DEBUG_PRI (baci_dev, DEB_CPU))
fprintf (sim_deb, ">>BACI cpu: [LIx%s] Received data = %06o\n", hold_or_clear, baci_ibuf);
tprintf (baci_dev, DEB_CPU, "[LIx%s] Received data = %06o\n",
hold_or_clear, baci_ibuf);
}
else { /* control clear? */
data = baci_status; /* return status */
if (DEBUG_PRI (baci_dev, DEB_CPU))
fprintf (sim_deb, ">>BACI cpu: [LIx%s] Status = %06o\n", hold_or_clear, baci_status);
tprintf (baci_dev, DEB_CPU, "[LIx%s] Status = %06o\n",
hold_or_clear, baci_status);
}
stat_data = IORETURN (SCPE_OK, data); /* merge in return status */
@@ -620,15 +618,14 @@ while (working_set) {
case ioIOO: /* I/O data output */
baci_obuf = IODATA (stat_data); /* get data value */
if (DEBUG_PRI (baci_dev, DEB_CPU))
fprintf (sim_deb, ">>BACI cpu: [OTx%s] Command = %06o\n", hold_or_clear, baci_obuf);
tprintf (baci_dev, DEB_CPU, "[OTx%s] Command = %06o\n",
hold_or_clear, baci_obuf);
if (baci_obuf & OUT_MR) { /* master reset? */
master_reset (); /* do before processing */
baci_io (&baci_dib, ioSIR, 0); /* set interrupt request */
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fprintf (sim_deb, ">>BACI cmds: [OTx%s] Master reset\n", hold_or_clear);
tprintf (baci_dev, DEB_CMDS, "[OTx%s] Master reset\n", hold_or_clear);
}
switch (GET_ID (baci_obuf)) { /* isolate ID code */
@@ -639,10 +636,10 @@ while (working_set) {
fifo_put (ch); /* queue character */
if (baci_term.flags & UNIT_ATT) { /* attached to network? */
if (DEBUG_PRI (baci_dev, DEB_CMDS) && /* debugging? */
if (TRACING (baci_dev, DEB_CMDS) && /* debugging? */
(sim_is_active (&baci_term) == 0)) /* service stopped? */
fprintf (sim_deb, ">>BACI cmds: [OTx%s] Terminal service scheduled, "
"time = %d\n", hold_or_clear, baci_term.wait);
hp_trace (&baci_dev, DEB_CMDS, "[OTx%s] Terminal service scheduled, "
"time = %d\n", hold_or_clear, baci_term.wait);
if (baci_fcount == 1) /* first char to xmit? */
sim_activate_abs (&baci_term, /* start service with full char time */
@@ -683,17 +680,15 @@ while (working_set) {
sim_activate (&baci_term, /* activate I/O service */
baci_term.wait);
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fprintf (sim_deb, ">>BACI cmds: [OTx%s] Terminal service scheduled, "
"time = %d\n", hold_or_clear, baci_term.wait);
tprintf (baci_dev, DEB_CMDS, "[OTx%s] Terminal service scheduled, "
"time = %d\n", hold_or_clear, baci_term.wait);
}
else { /* external rate */
sim_cancel (&baci_term); /* stop I/O service */
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fprintf (sim_deb, ">>BACI cmds: [OTx%s] Terminal service stopped\n",
hold_or_clear);
tprintf (baci_dev, DEB_CMDS, "[OTx%s] Terminal service stopped\n",
hold_or_clear);
}
}
@@ -724,16 +719,14 @@ while (working_set) {
case ioCRS: /* control reset */
master_reset (); /* issue master reset */
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fputs (">>BACI cmds: [CRS] Master reset\n", sim_deb);
tprintf (baci_dev, DEB_CMDS, "[CRS] Master reset\n");
break;
case ioCLC: /* clear control flip-flop */
baci.control = CLEAR; /* clear control */
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fprintf (sim_deb, ">>BACI cmds: [CLC%s] Control cleared\n", hold_or_clear);
tprintf (baci_dev, DEB_CMDS, "[CLC%s] Control cleared\n", hold_or_clear);
break;
@@ -741,8 +734,7 @@ while (working_set) {
baci.control = SET; /* set control */
baci.lockout = CLEAR; /* clear lockout */
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fprintf (sim_deb, ">>BACI cmds: [STC%s] Control set and lockout cleared\n", hold_or_clear);
tprintf (baci_dev, DEB_CMDS, "[STC%s] Control set and lockout cleared\n", hold_or_clear);
if (!(signal_set & ioCLF)) /* STC without ,C ? */
update_status (); /* clearing lockout might interrupt */
@@ -777,7 +769,7 @@ return stat_data;
The terminal service routine is used to transmit and receive characters.
In terminal mode, it is started when a character is ready for output or when
the Telnet poll routine determines that there are characters ready for input
the line poll routine determines that there are characters ready for input
and stopped when there are no more characters to output or input. When the
terminal is quiescent, this routine does not run.
@@ -817,11 +809,11 @@ return stat_data;
first character after an ENQ is not an ACK.
Finally, fast timing enables buffer combining. For output, all characters
present in the FIFO are unloaded into the Telnet buffer before initiating a
packet send. For input, all characters present in the Telnet buffer are
loaded into the FIFO. This reduces network traffic and decreases simulator
overhead (there is only one service routine entry per block, rather than one
per character).
present in the FIFO are unloaded into the line buffer before initiating a
packet send. For input, all characters present in the line buffer are loaded
into the FIFO. This reduces network traffic and decreases simulator overhead
(there is only one service routine entry per block, rather than one per
character).
In fast output mode, it is imperative that not less than 1500 instructions
elapse between the first character load to the FIFO and the initiation of
@@ -835,6 +827,46 @@ return stat_data;
To avoid this, the OTx output character handler does an absolute schedule for
the first character to ensure that a full character time is used.
Implementation notes:
1. The terminal multiplexer library "tmxr_putc_ln" routine returns
SCPE_STALL if it is called when the transmit buffer is full. When the
last character is added to the buffer, the routine returns SCPE_OK but
also changes the "xmte" field of the terminal multiplexer line (TMLN)
structure from 1 to 0 to indicate that further calls will be rejected.
The "xmte" value is set back to 1 when the tranmit buffer empties.
This presents two approaches to handling buffer overflows: either call
"tmxr_putc_ln" unconditionally and test for SCPE_STALL on return, or call
"tmxr_putc_ln" only if "xmte" is 1. The former approach adds a new
character to the transmit buffer as soon as space is available, while the
latter adds a new character only when the buffer has completely emptied.
With either approach, transmission must be rescheduled after a delay to
allow the buffer to drain.
It would seem that the former approach is more attractive, as it would
allow the simulated I/O operation to complete more quickly. However,
there are two mitigating factors. First, the library attempts to write
the entire transmit buffer in one host system call, so there is usually
no time difference between freeing one buffer character and freeing the
entire buffer (barring host system buffer congestion). Second, the
routine increments a "character dropped" counter when returning
SCPE_STALL status. However, the characters actually would not be lost,
as the SCPE_STALL return would schedule retransmission when buffer space
is available, . This would lead to erroneous reporting in the SHOW
<unit> STATISTICS command.
Therefore, we adopt the latter approach and reschedule transmission if
the "xmte" field is 0. Note that the "tmxr_poll_tx" routine still must
be called in this case, as it is responsible for transmitting the buffer
contents and therefore freeing space in the buffer.
2. The "tmxr_putc_ln" library routine returns SCPE_LOST if the line is not
connected. We ignore this error so that an OS may output an
initialization "welcome" message even when the terminal is not connected.
This permits the simulation to continue while ignoring the output.
*/
t_stat baci_term_svc (UNIT *uptr)
@@ -843,12 +875,16 @@ uint32 data_bits, data_mask;
const t_bool fast_timing = (baci_term.flags & UNIT_FASTTIME) != 0;
const t_bool is_attached = (baci_term.flags & UNIT_ATT) != 0;
t_stat status = SCPE_OK;
t_bool xmit_loop = TRUE;
t_bool recv_loop = TRUE;
t_bool xmit_loop = (baci_ldsc.xmte != 0); /* TRUE if the transmit buffer is not full */
/* Transmission */
if (baci_ldsc.xmte == 0) /* if the transmit buffer is full */
tprintf (baci_dev, DEB_XFER, "Transmission stalled for full buffer\n");
while (xmit_loop && (baci_uart_thr & IN_VALID)) { /* valid character in UART? */
data_bits = 5 + (baci_cfcw & OUT_CHARSIZE); /* calculate number of data bits */
data_mask = (1 << data_bits) - 1; /* generate mask for data bits */
@@ -859,9 +895,8 @@ while (xmit_loop && (baci_uart_thr & IN_VALID)) { /* valid character in UA
baci_enq_cntr = baci_enq_cntr + 1; /* bump ENQ counter */
recv_loop = FALSE; /* skip recv to allow time before ACK */
if (DEBUG_PRI (baci_dev, DEB_XFER))
fprintf (sim_deb, ">>BACI xfer: Character ENQ absorbed internally, "
"ENQ count = %d\n", baci_enq_cntr);
tprintf (baci_dev, DEB_XFER, "Character ENQ absorbed internally, "
"ENQ count = %d\n", baci_enq_cntr);
}
else { /* character is not ENQ or not fast timing */
@@ -871,11 +906,17 @@ while (xmit_loop && (baci_uart_thr & IN_VALID)) { /* valid character in UA
status = tmxr_putc_ln (&baci_ldsc, /* transmit the character */
baci_uart_tr);
if ((status == SCPE_OK) && /* transmitted OK? */
DEBUG_PRI (baci_dev, DEB_XFER))
fprintf (sim_deb, ">>BACI xfer: Character %s "
"transmitted from UART\n",
fmt_char ((uint8) baci_uart_tr));
if (status == SCPE_OK) /* transmitted OK? */
tprintf (baci_dev, DEB_XFER, "Character %s transmitted from the UART\n",
fmt_char ((uint8) baci_uart_tr));
else {
tprintf (baci_dev, DEB_XFER, "Character %s transmission failed with status %d\n",
fmt_char ((uint8) baci_uart_tr), status);
if (status == SCPE_LOST) /* if the line is not connected */
status = SCPE_OK; /* then ignore the output */
}
}
}
@@ -891,11 +932,12 @@ while (xmit_loop && (baci_uart_thr & IN_VALID)) { /* valid character in UA
else /* receive mode */
baci_uart_thr = CLEAR_HR; /* clear holding register */
xmit_loop = fast_timing && !baci_enq_seen; /* loop if fast mode and char not ENQ */
xmit_loop = (fast_timing && ! baci_enq_seen /* loop if fast mode and char not ENQ */
&& baci_ldsc.xmte != 0); /* and buffer space is available */
}
else
xmit_loop = FALSE;
else /* otherwise transmission failed */
xmit_loop = FALSE; /* so drop out of the loop */
}
@@ -907,9 +949,8 @@ if (recv_loop && /* ok to process? */
baci_uart_rhr = baci_uart_rhr & ~IN_VALID; /* clear valid bit */
if (DEBUG_PRI (baci_dev, DEB_XFER))
fprintf (sim_deb, ">>BACI xfer: Deferred character %s processed\n",
fmt_char ((uint8) baci_uart_rhr));
tprintf (baci_dev, DEB_XFER, "Deferred character %s processed\n",
fmt_char ((uint8) baci_uart_rhr));
fifo_put ((uint8) baci_uart_rhr); /* move deferred character to FIFO */
baci_uart_rhr = CLEAR_HR; /* clear RHR */
@@ -928,8 +969,7 @@ while (recv_loop) { /* OK to process? */
if (baci_uart_rr & SCPE_BREAK) { /* break detected? */
baci_status = baci_status | IN_BREAK; /* set break status */
if (DEBUG_PRI (baci_dev, DEB_XFER))
fputs (">>BACI xfer: Break detected\n", sim_deb);
tprintf (baci_dev, DEB_XFER, "Break detected\n");
}
data_bits = 5 + (baci_cfcw & OUT_CHARSIZE); /* calculate number of data bits */
@@ -937,9 +977,8 @@ while (recv_loop) { /* OK to process? */
baci_uart_rhr = (uint16) (baci_uart_rr & data_mask); /* mask data into holding register */
baci_uart_rr = CLEAR_R; /* clear receiver register */
if (DEBUG_PRI (baci_dev, DEB_XFER))
fprintf (sim_deb, ">>BACI xfer: Character %s received by UART\n",
fmt_char ((uint8) baci_uart_rhr));
tprintf (baci_dev, DEB_XFER, "Character %s received by the UART\n",
fmt_char ((uint8) baci_uart_rhr));
if (baci_term.flags & UNIT_CAPSLOCK) /* caps lock mode? */
baci_uart_rhr = (uint16) toupper (baci_uart_rhr); /* convert to upper case if lower */
@@ -967,8 +1006,7 @@ while (recv_loop) { /* OK to process? */
if (recv_loop && baci_enq_seen) { /* OK to process and ENQ seen? */
baci_enq_seen = FALSE; /* reset flag */
if (DEBUG_PRI (baci_dev, DEB_XFER))
fputs (">>BACI xfer: Character ACK generated internally\n", sim_deb);
tprintf (baci_dev, DEB_XFER, "Character ACK generated internally\n");
fifo_put (ACK); /* fake ACK from terminal */
update_status (); /* update FIFO status */
@@ -981,19 +1019,17 @@ if ((baci_uart_thr & IN_VALID) || baci_enq_seen || /* more to transmit? */
tmxr_rqln (&baci_ldsc)) /* or more to receive? */
sim_activate (uptr, uptr->wait); /* reschedule service */
else
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fputs (">>BACI cmds: Terminal service stopped\n", sim_deb);
tprintf (baci_dev, DEB_CMDS, "Terminal service stopped\n");
return status;
}
/* BACI Telnet poll service.
/* BACI line poll service.
This service routine is used to poll for Telnet connections and incoming
characters. If characters are available, the terminal I/O service routine is
scheduled. It starts when the socket is attached and stops when the socket
is detached.
This service routine is used to poll for connections and incoming characters.
If characters are available, the terminal I/O service routine is scheduled.
It starts when the line is attached and stops when the line is detached.
Implementation notes:
@@ -1042,16 +1078,16 @@ baci_term.wait = service_time (baci_icw); /* set terminal I/O time
if (baci_term.flags & UNIT_ATT) { /* device attached? */
baci_poll.wait = POLL_FIRST; /* set up poll */
sim_activate (&baci_poll, baci_poll.wait); /* start Telnet poll immediately */
sim_activate (&baci_poll, baci_poll.wait); /* start line poll immediately */
}
else
sim_cancel (&baci_poll); /* else stop Telnet poll */
sim_cancel (&baci_poll); /* else stop line poll */
return SCPE_OK;
}
/* Attach controller */
/* Attach line */
t_stat baci_attach (UNIT *uptr, CONST char *cptr)
{
@@ -1061,20 +1097,20 @@ status = tmxr_attach (&baci_desc, uptr, cptr); /* attach to socket */
if (status == SCPE_OK) {
baci_poll.wait = POLL_FIRST; /* set up poll */
sim_activate (&baci_poll, baci_poll.wait); /* start Telnet poll immediately */
sim_activate (&baci_poll, baci_poll.wait); /* start line poll immediately */
}
return status;
}
/* Detach controller */
/* Detach line */
t_stat baci_detach (UNIT *uptr)
{
t_stat status;
baci_ldsc.rcve = 0; /* disable line reception */
sim_cancel (&baci_poll); /* stop Telnet poll */
sim_cancel (&baci_poll); /* stop line poll */
status = tmxr_detach (&baci_desc, uptr); /* detach socket */
return status;
}
@@ -1122,8 +1158,10 @@ baci_dsrw = 0; /* clear status referenc
baci_cfcw = baci_cfcw & ~OUT_ECHO; /* clear echo flag */
baci_icw = baci_icw & OUT_BAUDRATE; /* clear interface control */
if (baci_term.flags & UNIT_DIAG) /* diagnostic mode? */
if (baci_term.flags & UNIT_DIAG) { /* diagnostic mode? */
baci_status = baci_status & ~IN_MODEM | IN_SPARE; /* clear loopback status, set BA */
baci_ldsc.xmte = 1; /* enable transmitter */
}
return;
}
@@ -1179,48 +1217,37 @@ if ((baci_status & IN_STDIRQ) || /* standard interrupt? *
(baci_edsiw & OUT_ENCM) && /* and char mode */
(baci_fget != baci_fput)) { /* and FIFO not empty? */
if (baci.lockout) { /* interrupt lockout? */
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fputs (">>BACI cmds: Lockout prevents flag set", sim_deb);
}
if (baci.lockout) /* interrupt lockout? */
tprintf (baci_dev, DEB_CMDS, "Lockout prevents flag set, status = %06o\n",
baci_status);
else if (baci.srq) { /* SRQ set? */
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fputs (">>BACI cmds: SRQ prevents flag set", sim_deb);
}
else if (baci.srq) /* SRQ set? */
tprintf (baci_dev, DEB_CMDS, "SRQ prevents flag set, status = %06o\n",
baci_status);
else {
baci_io (&baci_dib, ioENF, 0); /* set flag */
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fputs (">>BACI cmds: Flag and lockout set", sim_deb);
tprintf (baci_dev, DEB_CMDS, "Flag and lockout set, status = %06o\n",
baci_status);
}
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fprintf (sim_deb, ", status = %06o\n", baci_status);
}
if ((baci_icw & OUT_DCPC) && /* DCPC enabled? */
((IO_MODE == XMIT) && (baci_fcount < 128) || /* and xmit and room in FIFO */
(IO_MODE == RECV) && (baci_fcount > 0))) { /* or recv and data in FIFO? */
if (baci.lockout) { /* interrupt lockout? */
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fputs (">>BACI cmds: Lockout prevents SRQ set", sim_deb);
}
(IO_MODE == RECV) && (baci_fcount > 0))) /* or recv and data in FIFO? */
if (baci.lockout) /* interrupt lockout? */
tprintf (baci_dev, DEB_CMDS, "Lockout prevents SRQ set, status = %06o\n",
baci_status);
else {
baci.srq = SET; /* set SRQ */
baci_io (&baci_dib, ioSIR, 0); /* set interrupt request */
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fputs (">>BACI cmds: SRQ set", sim_deb);
tprintf (baci_dev, DEB_CMDS, "SRQ set, status = %06o\n",
baci_status);
}
if (DEBUG_PRI (baci_dev, DEB_CMDS))
fprintf (sim_deb, ", status = %06o\n", baci_status);
}
return;
}
@@ -1340,10 +1367,9 @@ if ((baci_fget != baci_fput) || (baci_fcount >= 128)) { /* FIFO occupied? */
if (IO_MODE == RECV) /* receive mode? */
baci_fcount = baci_fcount - 1; /* decrement occupancy counter */
if (DEBUG_PRI (baci_dev, DEB_BUF))
fprintf (sim_deb, ">>BACI buf: Character %s get from FIFO [%d], "
"character counter = %d\n",
fmt_char ((uint8) data), baci_fget, baci_fcount);
tprintf (baci_dev, DEB_BUF, "Character %s get from FIFO [%d], "
"character counter = %d\n",
fmt_char ((uint8) data), baci_fget, baci_fcount);
baci_fget = (baci_fget + 1) % FIFO_SIZE; /* bump index modulo array size */
@@ -1354,9 +1380,8 @@ if ((baci_fget != baci_fput) || (baci_fcount >= 128)) { /* FIFO occupied? */
}
else /* FIFO empty */
if (DEBUG_PRI (baci_dev, DEB_BUF))
fprintf (sim_deb, ">>BACI buf: Attempted get on empty FIFO, "
"character count = %d\n", baci_fcount);
tprintf (baci_dev, DEB_BUF, "Attempted get on empty FIFO, "
"character count = %d\n", baci_fcount);
if (baci_fcount == 0) /* count now zero? */
baci_status = baci_status | IN_BUFEMPTY; /* set buffer empty flag */
@@ -1398,13 +1423,12 @@ else { /* RECV or THR occupied
baci_fcount = baci_fcount + 1; /* increment occupancy counter */
if (DEBUG_PRI (baci_dev, DEB_BUF))
if (pass_thru)
fprintf (sim_deb, ">>BACI buf: Character %s put to UART transmitter holding register, "
"character counter = 1\n", fmt_char (ch));
else
fprintf (sim_deb, ">>BACI buf: Character %s put to FIFO [%d], "
"character counter = %d\n", fmt_char (ch), index, baci_fcount);
if (pass_thru)
tprintf (baci_dev, DEB_BUF, "Character %s put to UART transmitter holding register, "
"character counter = 1\n", fmt_char (ch));
else
tprintf (baci_dev, DEB_BUF, "Character %s put to FIFO [%d], "
"character counter = %d\n", fmt_char (ch), index, baci_fcount);
if ((IO_MODE == RECV) && (baci_spchar [ch])) /* receive mode and special character? */
baci_status = baci_status | IN_SPCHAR; /* set special char seen flag */
@@ -1477,8 +1501,7 @@ if (baci_uart_clk > 0) { /* transfer in progress?
if (baci_bcount == 160) { /* break held long enough? */
baci_status = baci_status | IN_BREAK; /* set break flag */
if (DEBUG_PRI (baci_dev, DEB_XFER))
fputs (">>BACI xfer: Break detected\n", sim_deb);
tprintf (baci_dev, DEB_XFER, "Break detected\n");
}
}
@@ -1499,9 +1522,8 @@ if (baci_uart_clk > 0) { /* transfer in progress?
baci_uart_thr = fifo_get (); /* get next char into THR */
update_status (); /* update FIFO status */
if (DEBUG_PRI (baci_dev, DEB_XFER))
fprintf (sim_deb, ">>BACI xfer: UART transmitter empty, "
"holding register = %06o\n", baci_uart_thr);
tprintf (baci_dev, DEB_XFER, "UART transmitter empty, "
"holding register = %06o\n", baci_uart_thr);
}
else if ((IO_MODE == RECV) && /* receive mode? */
@@ -1517,10 +1539,8 @@ if (baci_uart_clk > 0) { /* transfer in progress?
baci_uart_rhr = (uint16) (baci_uart_rr >> (16 - uart_bits)); /* position data to right align */
baci_uart_rr = CLEAR_R; /* clear receiver register */
if (DEBUG_PRI (baci_dev, DEB_XFER))
fprintf (sim_deb, ">>BACI xfer: UART receiver = %06o (%s)\n",
baci_uart_rhr,
fmt_char ((uint8) (baci_uart_rhr & data_mask)));
tprintf (baci_dev, DEB_XFER, "UART receiver = %06o (%s)\n",
baci_uart_rhr, fmt_char ((uint8) (baci_uart_rhr & data_mask)));
fifo_put ((uint8) (baci_uart_rhr & data_mask)); /* put data in FIFO */
update_status (); /* update FIFO status */
@@ -1539,8 +1559,7 @@ if (baci_uart_clk > 0) { /* transfer in progress?
if (parity & 1) { /* parity error? */
baci_status = baci_status | IN_OVRUNPE; /* report it */
if (DEBUG_PRI (baci_dev, DEB_XFER))
fputs (">>BACI xfer: Parity error detected\n", sim_deb);
tprintf (baci_dev, DEB_XFER, "Parity error detected\n");
}
}
}
@@ -1578,19 +1597,17 @@ if ((baci_uart_clk == 0) && /* start of transfer? */
baci_uart_tr = (~data_mask | baci_uart_tr) << 2 | 1; /* form serial data stream */
if (DEBUG_PRI (baci_dev, DEB_XFER))
fprintf (sim_deb, ">>BACI xfer: UART transmitter = %06o (%s), "
"clock count = %d\n", baci_uart_tr & DMASK,
fmt_char ((uint8) (baci_uart_thr & data_mask)),
baci_uart_clk);
tprintf (baci_dev, DEB_XFER, "UART transmitter = %06o (%s), "
"clock count = %d\n", baci_uart_tr & DMASK,
fmt_char ((uint8) (baci_uart_thr & data_mask)),
baci_uart_clk);
}
else {
baci_uart_rr = CLEAR_R; /* clear receiver register */
if (DEBUG_PRI (baci_dev, DEB_XFER))
fprintf (sim_deb, ">>BACI xfer: UART receiver empty, "
"clock count = %d\n", baci_uart_clk);
tprintf (baci_dev, DEB_XFER, "UART receiver empty, "
"clock count = %d\n", baci_uart_clk);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,28 +1,41 @@
/* hp2100_cpu.h: HP 2100 CPU definitions
/* hp2100_cpu.h: HP 2100 CPU declarations
Copyright (c) 2005-2016, Robert M. Supnik
Copyright (c) 2017-2018, 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 in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
Except as contained in this notice, the names of the authors shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from the authors.
22-Feb-18 JDB Reworked "cpu_ibl" into "cpu_copy_loader"
Cleaned up IBL definitions, added loader structure
22-Jul-17 JDB Renamed "intaddr" to CIR; added IR
14-Jul-17 JDB Removed calc_defer() prototype
11-Jul-17 JDB Moved "ibl_copy" and renamed to "cpu_ibl"
10-Jul-17 JDB Renamed the global routine "iogrp" to "cpu_iog"
07-Jul-17 JDB Changed "iotrap" from uint32 to t_bool
07-Jun-17 JDB Added maximum instruction length for sim_emax definition
06-Jun-17 JDB Added instruction group decoding macros
04-Apr-17 JDB Added "cpu_configuration" for symbolic ex/dep validation
08-Mar-17 JDB Added "cpu_speed" for TBG service access
15-Feb-17 JDB Deleted unneeded guard macro definition
05-Aug-16 JDB Renamed the P register from "PC" to "PR"
24-Dec-14 JDB Added casts for explicit downward conversions
18-Mar-13 JDB Added declarations for the MP abort handler and CPU registers
@@ -50,73 +63,213 @@
encode the series within the type.
*/
#ifndef HP2100_CPU_H_
#define HP2100_CPU_H_ 0
#include <setjmp.h>
/* CPU model definition flags */
#define CPU_V_SERIES 0
#define CPU_V_TYPE 2
#define CPU_V_FAMILY 3
/* Memory access macros.
#define FAMILY_21XX (0 << CPU_V_FAMILY)
#define FAMILY_1000 (1 << CPU_V_FAMILY)
These macros provide simplified function call sequences for memory reads and
writes by the CPU. They supply the correct access classification. The
following macro routines are provided:
#define TYPE_211X (0 << CPU_V_TYPE) /* 2114, 2115, 2116 */
#define TYPE_2100 (1 << CPU_V_TYPE) /* 2100A, 2100S */
#define TYPE_1000MEF (0 << CPU_V_TYPE) /* 1000-M, 1000-E, 1000-F */
#define TYPE_1000AL (1 << CPU_V_TYPE) /* 1000-L, A600, A700, A900, A990 */
Name Action
------- ------------------------------------------------------------
ReadF Read an instruction word using the current map
ReadW Read a data word using the current map
ReadWA Read a data word using the alternate map
ReadS Read a data word using the system map
ReadU Read a data word using the user map
ReadB Read a data byte using the current map
ReadBA Read a data byte using the alternate map
WriteW Write a data word using the current map
WriteWA Write a data word using the alternate map
WriteS Write a data word using the system map
WriteU Write a data word using the user map
WriteB Write a data byte using the current map
WriteBA Write a data byte using the alternate map
The MP_ABORT macro performs a "longjmp" to the memory protect handler in the
instruction execution loop. The parameter is the address of the violation.
The conditions that initiate a MP abort must be tested explicitly before
calling MP_ABORT.
*/
#define ReadF(a) mem_read (&cpu_dev, Fetch, a)
#define ReadW(a) mem_read (&cpu_dev, Data, a)
#define ReadWA(a) mem_read (&cpu_dev, Data_Alternate, a)
#define ReadS(a) mem_read (&cpu_dev, Data_System, a)
#define ReadU(a) mem_read (&cpu_dev, Data_User, a)
#define ReadB(a) mem_read_byte (&cpu_dev, Data, a)
#define ReadBA(a) mem_read_byte (&cpu_dev, Data_Alternate, a)
#define WriteW(a,v) mem_write (&cpu_dev, Data, a, v)
#define WriteWA(a,v) mem_write (&cpu_dev, Data_Alternate, a, v)
#define WriteS(a,v) mem_write (&cpu_dev, Data_System, a, v)
#define WriteU(a,v) mem_write (&cpu_dev, Data_User, a, v)
#define WriteB(a,v) mem_write_byte (&cpu_dev, Data, a, v)
#define WriteBA(a,v) mem_write_byte (&cpu_dev, Data_Alternate, a, v)
#define MP_ABORT(va) longjmp (save_env, (va))
/* CPU tracing flags */
#define DEBUG_NOOS (1u << 0) /* configure RTE-6/VM not to use OS firmware */
#define TRACE_INSTR (1u << 1) /* trace instruction executions */
#define TRACE_DATA (1u << 2) /* trace memory data accesses */
#define TRACE_FETCH (1u << 3) /* trace memory instruction fetches */
#define TRACE_REG (1u << 4) /* trace register values */
#define TRACE_OPND (1u << 5) /* trace instruction operands */
#define TRACE_EXEC (1u << 6) /* trace matching instruction execution states */
#define TRACE_SR (1u << 7) /* trace service requests received */
#define TRACE_ALL ~DEBUG_NOOS /* trace everything */
#define DMS_FORMAT "%c %04o %05o %06o " /* map | physical page | logical address | value format */
#define REGA_FORMAT "%c **** %05o %06o " /* protection | fence | S register format for working registers */
#define REGB_FORMAT "%c **** ***** ****** " /* protection format for MP/MEM registers */
#define OPND_FORMAT "* **** %05o %06o " /* address | data format for operands */
#define EXEC_FORMAT "******************** " /* null format for EXEC separation */
/* CPU stop flags */
#define SS_INHIBIT (t_stat) (~0u) /* inhibit stops for the first instruction executed */
#define STOP(s) ((s) & ~cpu_ss_inhibit) /* stop if the condition is enabled and not inhibited */
/* Supported breakpoint switches */
#define BP_EXEC (SWMASK ('E')) /* an execution breakpoint */
#define BP_ENONE (SWMASK ('N')) /* an execution breakpoint when mapping is off */
#define BP_ESYS (SWMASK ('S')) /* an execution breakpoint in the system map */
#define BP_EUSER (SWMASK ('U')) /* an execution breakpoint in the user map */
#define BP_SUPPORTED (BP_EXEC | BP_ENONE | BP_ESYS | BP_EUSER)
/* CPU unit flags.
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| R | - | G | V | O | E | D | F | M | I | P | U | CPU model |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| f | t | series|
+---+---+---+---+
Where:
R = reserved
G = SIGNAL/1000 firmware is present
V = Vector Instruction Set firmware is present
O = RTE-6/VM VMA and OS firmware is present
E = RTE-IV EMA firmware is present
D = Double Integer firmware is present
F = Fast FORTRAN Processor firmware is present
M = Dynamic Mapping System firmware is present
I = 2000 I/O Processor firmware is present
P = Floating Point hardware or firmware is present
U = Extended Arithmetic Unit is present
f = CPU family
t = CPU type
CPU Models:
0 0 00 = HP 2116
0 0 01 = HP 2115
0 0 10 = HP 2114
0 0 11 = unused
0 1 00 = HP 2100
0 1 01 = unused
0 1 10 = unused
0 1 11 = unused
1 0 00 = HP 1000 M-Series
1 0 01 = HP 1000 E-Series
1 0 10 = HP 1000 F-Series
1 0 11 = unused
1 1 00 = unused (1000 A-Series)
1 1 01 = unused (1000 A-Series)
1 1 10 = unused (1000 A-Series)
1 1 11 = unused (1000 A-Series)
*/
#define CPU_V_SERIES 0
#define CPU_V_TYPE 2
#define CPU_V_FAMILY 3
#define FAMILY_21XX (0 << CPU_V_FAMILY)
#define FAMILY_1000 (1 << CPU_V_FAMILY)
#define TYPE_211X (0 << CPU_V_TYPE) /* 2114, 2115, 2116 */
#define TYPE_2100 (1 << CPU_V_TYPE) /* 2100A, 2100S */
#define TYPE_1000MEF (0 << CPU_V_TYPE) /* 1000-M, 1000-E, 1000-F */
#define TYPE_1000AL (1 << CPU_V_TYPE) /* 1000-L, A600, A700, A900, A990 */
#define SERIES_16 (0 << CPU_V_SERIES) /* 211X */
#define SERIES_15 (1 << CPU_V_SERIES) /* 211X */
#define SERIES_14 (2 << CPU_V_SERIES) /* 211X */
#define SERIES_00 (0 << CPU_V_SERIES) /* 2100 */
#define SERIES_M (0 << CPU_V_SERIES) /* 1000 */
#define SERIES_E (1 << CPU_V_SERIES) /* 1000 */
#define SERIES_F (2 << CPU_V_SERIES) /* 1000 */
#define SERIES_16 (0 << CPU_V_SERIES) /* 211X */
#define SERIES_15 (1 << CPU_V_SERIES) /* 211X */
#define SERIES_14 (2 << CPU_V_SERIES) /* 211X */
#define SERIES_00 (0 << CPU_V_SERIES) /* 2100 */
#define SERIES_M (0 << CPU_V_SERIES) /* 1000 */
#define SERIES_E (1 << CPU_V_SERIES) /* 1000 */
#define SERIES_F (2 << CPU_V_SERIES) /* 1000 */
/* CPU unit flags */
#define UNIT_M_CPU 017 /* CPU model mask [3:0] */
#define UNIT_M_TYPE 014 /* CPU type mask [3:2] */
#define UNIT_M_FAMILY 010 /* CPU family mask [3:3] */
#define UNIT_M_CPU 017 /* CPU model mask [3:0] */
#define UNIT_M_TYPE 014 /* CPU type mask [3:2] */
#define UNIT_M_FAMILY 010 /* CPU family mask [3:3] */
#define UNIT_V_CPU (UNIT_V_UF + 0) /* CPU model bits 0-3 */
#define UNIT_V_EAU (UNIT_V_UF + 4) /* EAU installed */
#define UNIT_V_FP (UNIT_V_UF + 5) /* FP installed */
#define UNIT_V_IOP (UNIT_V_UF + 6) /* IOP installed */
#define UNIT_V_DMS (UNIT_V_UF + 7) /* DMS installed */
#define UNIT_V_FFP (UNIT_V_UF + 8) /* FFP installed */
#define UNIT_V_DBI (UNIT_V_UF + 9) /* DBI installed */
#define UNIT_V_EMA (UNIT_V_UF + 10) /* RTE-4 EMA installed */
#define UNIT_V_VMAOS (UNIT_V_UF + 11) /* RTE-6 VMA/OS installed */
#define UNIT_V_VIS (UNIT_V_UF + 12) /* VIS installed */
#define UNIT_V_SIGNAL (UNIT_V_UF + 13) /* SIGNAL/1000 installed */
#define UNIT_V_CPU (UNIT_V_UF + 0) /* CPU model bits 0-3 */
#define UNIT_V_EAU (UNIT_V_UF + 4) /* EAU installed */
#define UNIT_V_FP (UNIT_V_UF + 5) /* FP installed */
#define UNIT_V_IOP (UNIT_V_UF + 6) /* IOP installed */
#define UNIT_V_DMS (UNIT_V_UF + 7) /* DMS installed */
#define UNIT_V_FFP (UNIT_V_UF + 8) /* FFP installed */
#define UNIT_V_DBI (UNIT_V_UF + 9) /* DBI installed */
#define UNIT_V_EMA (UNIT_V_UF + 10) /* RTE-4 EMA installed */
#define UNIT_V_VMAOS (UNIT_V_UF + 11) /* RTE-6 VMA/OS installed */
#define UNIT_V_VIS (UNIT_V_UF + 12) /* VIS installed */
#define UNIT_V_SIGNAL (UNIT_V_UF + 13) /* SIGNAL/1000 installed */
/* Future microcode expansion; reuse flags bottom-up if needed */
#define UNIT_V_DS (UNIT_V_UF + 14) /* DS installed */
#define UNIT_V_DS (UNIT_V_UF + 14) /* DS installed */
/* Unit models */
#define UNIT_MODEL_MASK (UNIT_M_CPU << UNIT_V_CPU)
#define UNIT_MODEL_MASK (UNIT_M_CPU << UNIT_V_CPU)
#define UNIT_2116 ((FAMILY_21XX | TYPE_211X | SERIES_16) << UNIT_V_CPU)
#define UNIT_2115 ((FAMILY_21XX | TYPE_211X | SERIES_15) << UNIT_V_CPU)
#define UNIT_2114 ((FAMILY_21XX | TYPE_211X | SERIES_14) << UNIT_V_CPU)
#define UNIT_2100 ((FAMILY_21XX | TYPE_2100 | SERIES_00) << UNIT_V_CPU)
#define UNIT_1000_M ((FAMILY_1000 | TYPE_1000MEF | SERIES_M) << UNIT_V_CPU)
#define UNIT_1000_E ((FAMILY_1000 | TYPE_1000MEF | SERIES_E) << UNIT_V_CPU)
#define UNIT_1000_F ((FAMILY_1000 | TYPE_1000MEF | SERIES_F) << UNIT_V_CPU)
#define UNIT_2116 ((FAMILY_21XX | TYPE_211X | SERIES_16) << UNIT_V_CPU)
#define UNIT_2115 ((FAMILY_21XX | TYPE_211X | SERIES_15) << UNIT_V_CPU)
#define UNIT_2114 ((FAMILY_21XX | TYPE_211X | SERIES_14) << UNIT_V_CPU)
#define UNIT_2100 ((FAMILY_21XX | TYPE_2100 | SERIES_00) << UNIT_V_CPU)
#define UNIT_1000_M ((FAMILY_1000 | TYPE_1000MEF | SERIES_M) << UNIT_V_CPU)
#define UNIT_1000_E ((FAMILY_1000 | TYPE_1000MEF | SERIES_E) << UNIT_V_CPU)
#define UNIT_1000_F ((FAMILY_1000 | TYPE_1000MEF | SERIES_F) << UNIT_V_CPU)
/* Unit types */
#define UNIT_TYPE_MASK (UNIT_M_TYPE << UNIT_V_CPU)
#define UNIT_TYPE_MASK (UNIT_M_TYPE << UNIT_V_CPU)
#define UNIT_TYPE_211X ((FAMILY_21XX | TYPE_211X) << UNIT_V_CPU)
#define UNIT_TYPE_2100 ((FAMILY_21XX | TYPE_2100) << UNIT_V_CPU)
#define UNIT_TYPE_1000 ((FAMILY_1000 | TYPE_1000MEF) << UNIT_V_CPU)
#define UNIT_TYPE_211X ((FAMILY_21XX | TYPE_211X) << UNIT_V_CPU)
#define UNIT_TYPE_2100 ((FAMILY_21XX | TYPE_2100) << UNIT_V_CPU)
#define UNIT_TYPE_1000 ((FAMILY_1000 | TYPE_1000MEF) << UNIT_V_CPU)
/* Unit families */
@@ -125,92 +278,282 @@
#define UNIT_FAMILY_21XX (FAMILY_21XX << UNIT_V_CPU)
#define UNIT_FAMILY_1000 (FAMILY_1000 << UNIT_V_CPU)
/* Unit accessors */
#define UNIT_CPU_MODEL (cpu_unit.flags & UNIT_MODEL_MASK)
#define UNIT_CPU_TYPE (cpu_unit.flags & UNIT_TYPE_MASK)
#define UNIT_CPU_FAMILY (cpu_unit.flags & UNIT_FAMILY_MASK)
#define UNIT_CPU_MODEL (cpu_unit.flags & UNIT_MODEL_MASK)
#define UNIT_CPU_TYPE (cpu_unit.flags & UNIT_TYPE_MASK)
#define UNIT_CPU_FAMILY (cpu_unit.flags & UNIT_FAMILY_MASK)
#define CPU_MODEL_INDEX (UNIT_CPU_MODEL >> UNIT_V_CPU)
#define CPU_MODEL_INDEX (UNIT_CPU_MODEL >> UNIT_V_CPU)
/* Unit features */
#define UNIT_EAU (1 << UNIT_V_EAU)
#define UNIT_FP (1 << UNIT_V_FP)
#define UNIT_IOP (1 << UNIT_V_IOP)
#define UNIT_DMS (1 << UNIT_V_DMS)
#define UNIT_FFP (1 << UNIT_V_FFP)
#define UNIT_DBI (1 << UNIT_V_DBI)
#define UNIT_EMA (1 << UNIT_V_EMA)
#define UNIT_VMAOS (1 << UNIT_V_VMAOS)
#define UNIT_VIS (1 << UNIT_V_VIS)
#define UNIT_DS (1 << UNIT_V_DS)
#define UNIT_SIGNAL (1 << UNIT_V_SIGNAL)
#define UNIT_EAU (1u << UNIT_V_EAU)
#define UNIT_FP (1u << UNIT_V_FP)
#define UNIT_IOP (1u << UNIT_V_IOP)
#define UNIT_DMS (1u << UNIT_V_DMS)
#define UNIT_FFP (1u << UNIT_V_FFP)
#define UNIT_DBI (1u << UNIT_V_DBI)
#define UNIT_EMA (1u << UNIT_V_EMA)
#define UNIT_VMAOS (1u << UNIT_V_VMAOS)
#define UNIT_VIS (1u << UNIT_V_VIS)
#define UNIT_DS (1u << UNIT_V_DS)
#define UNIT_SIGNAL (1u << UNIT_V_SIGNAL)
#define UNIT_EMA_VMA (UNIT_EMA | UNIT_VMAOS)
#define UNIT_EMA_VMA (UNIT_EMA | UNIT_VMAOS)
#define UNIT_OPTS (UNIT_EAU | UNIT_FP | UNIT_IOP | \
UNIT_DMS | UNIT_FFP | UNIT_DBI | \
UNIT_EMA | UNIT_VMAOS | \
UNIT_VIS | UNIT_DS | UNIT_SIGNAL)
#define UNIT_OPTS (UNIT_EAU | UNIT_FP | UNIT_IOP | \
UNIT_DMS | UNIT_FFP | UNIT_DBI | \
UNIT_EMA | UNIT_VMAOS | \
UNIT_VIS | UNIT_DS | UNIT_SIGNAL)
/* "Pseudo-option" flags used only for option testing; never set into UNIT structure. */
#define UNIT_V_PFAIL (UNIT_V_UF - 1) /* Power fail installed */
#define UNIT_V_DMA (UNIT_V_UF - 2) /* DMA installed */
#define UNIT_V_MP (UNIT_V_UF - 3) /* Memory protect installed */
#define UNIT_V_PFAIL (UNIT_V_UF - 1) /* Power fail installed */
#define UNIT_V_DMA (UNIT_V_UF - 2) /* DMA installed */
#define UNIT_V_MP (UNIT_V_UF - 3) /* Memory protect installed */
#define UNIT_PFAIL (1 << UNIT_V_PFAIL)
#define UNIT_DMA (1 << UNIT_V_DMA)
#define UNIT_MP (1 << UNIT_V_MP)
#define UNIT_PFAIL (1 << UNIT_V_PFAIL)
#define UNIT_DMA (1 << UNIT_V_DMA)
#define UNIT_MP (1 << UNIT_V_MP)
#define UNIT_NONE 0 /* no options */
#define UNIT_NONE 0 /* no options */
/* Debug flags */
#define DEB_OS (1 << 0) /* RTE-6/VM OS firmware non-TBG processing */
#define DEB_OSTBG (1 << 1) /* RTE-6/VM OS firmware TBG processing */
#define DEB_VMA (1 << 2) /* RTE-6/VM VMA firmware instructions */
#define DEB_EMA (1 << 3) /* RTE-6/VM EMA firmware instructions */
#define DEB_VIS (1 << 4) /* E/F-Series VIS firmware instructions */
#define DEB_SIG (1 << 5) /* F-Series SIGNAL/1000 firmware instructions */
/* CPU configuration model flags */
#define CPU_MASK D16_MASK
#define CPU_2116 (1u << (FAMILY_21XX | TYPE_211X | SERIES_16))
#define CPU_2115 (1u << (FAMILY_21XX | TYPE_211X | SERIES_15))
#define CPU_2114 (1u << (FAMILY_21XX | TYPE_211X | SERIES_14))
#define CPU_2100 (1u << (FAMILY_21XX | TYPE_2100 | SERIES_00))
#define CPU_1000_M (1u << (FAMILY_1000 | TYPE_1000MEF | SERIES_M))
#define CPU_1000_E (1u << (FAMILY_1000 | TYPE_1000MEF | SERIES_E))
#define CPU_1000_F (1u << (FAMILY_1000 | TYPE_1000MEF | SERIES_F))
#define CPU_1000 (CPU_1000_M | CPU_1000_E | CPU_1000_F)
#define CPU_ALL (CPU_2116 | CPU_2115 | CPU_2114 | \
CPU_2100 | \
CPU_1000_M | CPU_1000_E | CPU_1000_F)
/* PC queue. */
#define PCQ_SIZE 64 /* must be 2**n */
#define PCQ_MASK (PCQ_SIZE - 1)
#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = (uint16) err_PC
#define PCQ_ENTRY pcq [pcq_p = (pcq_p - 1) & PCQ_MASK] = (uint16) err_PC
/* Memory reference instructions */
#define I_IA 0100000 /* indirect address */
#define I_AB 0004000 /* A/B select */
#define I_CP 0002000 /* current page */
#define I_DISP 0001777 /* page displacement */
#define I_PAGENO 0076000 /* page number */
/* Maximum instruction length.
This value is the length in words of the longest machine instruction. It is
used to set "sim_emax", which, in turn, is used to allocate the "sim_eval"
array. This array holds the words of a machine instruction to be formatted
and printed or to be parsed and stored.
The longest instruction in the 21xx/1000 family is the [D]VPIV (vector pivot)
instruction in the Vector Instruction Set.
*/
#define MAX_INSTR_LENGTH 10
/* Instruction group decoding.
The HP 21xx/1000 instruction set consists of five groups: the Memory
Reference Group (MRG), the Shift-Rotate Group (SRG), the Alter-Skip Group
(ASG), the I/O Group (IOG), and the Macro Group (MAC). Group membership is
determined by a multi-level decoding of bits 15-10, as follows:
Bits
15-10 Group
------ -----
xnnnx MRG
00000 SRG
00001 ASG
10001 IOG
10000 MAC
Where:
x = 0 or 1
n = any collective value other than 0
The MAC group is subdivided into the Extended Arithmetic Group (EAG), the
first User Instruction Group (UIG-0), and the second User Instruction Group
(UIG-1). Decoding is by bits 11-8, as follows (note that bit 10 = 0 for the
MAC group):
Bits
11-8 Group
---- -----
0000 EAG
0001 EAG
0010 EAG
0011 UIG-1
1000 EAG
1001 EAG
1010 UIG-0
1011 UIG-1
Bits 7-4 further decode the UIG instruction feature group.
*/
#define GROUP_MASK 0172000u /* instruction group mask */
#define MRG 0070000u /* Memory Reference Group indicator */
#define SRG 0000000u /* Shift-Rotate Group indicator */
#define ASG 0002000u /* Alter-Skip Group indicator */
#define IOG 0102000u /* I/O Group indicator */
#define MRGOP(v) (((v) & MRG) != 0) /* MRG membership test */
#define SRGOP(v) (((v) & GROUP_MASK) == SRG) /* SRG membership test */
#define ASGOP(v) (((v) & GROUP_MASK) == ASG) /* ASG membership test */
#define IOGOP(v) (((v) & GROUP_MASK) == IOG) /* IOG membership test */
#define SRG_CLE 0000040u /* SRG CLE opcode */
#define SRG_SLx 0000010u /* SRG SLA/SLB opcode */
#define SRG_NOP 0000000u /* SRG no-operation opcode */
#define SRG1_DE_MASK 0001000u /* SRG disable/enable first micro-op field bit */
#define SRG1_MASK 0001700u
#define SRG1_SHIFT 6
#define SRG2_DE_MASK 0000020u /* SRG disable/enable second micro-op field bit */
#define SRG2_MASK 0000027u
#define SRG2_SHIFT 0
#define SRG1(u) (((u) & SRG1_MASK) >> SRG1_SHIFT)
#define SRG2(u) (((u) & SRG2_MASK) >> SRG2_SHIFT)
#define UIG_MASK 0000360u /* UIG feature group mask */
#define UIG_SHIFT 4 /* UIG feature group alignment shift */
#define UIG(i) (((i) & UIG_MASK) >> UIG_SHIFT)
#define UIG_0_MASK 0177400u /* UIG-0 opcode mask */
#define UIG_0_RANGE 0105000u /* UIG-0 opcode range */
#define UIG_1_MASK 0173400u /* UIG-1 opcode mask */
#define UIG_1_RANGE 0101400u /* UIG-1 opcode range */
#define UIG_0_OP(i) (((i) & UIG_0_MASK) == UIG_0_RANGE) /* UIG-0 membership test */
#define UIG_1_OP(i) (((i) & UIG_1_MASK) == UIG_1_RANGE) /* UIG-1 membership test */
#define RTE_IRQ_RANGE 0105354 /* RTE-6/VM interrupt request instructions range */
/* Memory Reference Group instructions */
#define I_IA 0100000u /* indirect address */
#define I_AB 0004000u /* A/B select */
#define I_CP 0002000u /* current page */
#define I_DISP 0001777u /* page displacement */
#define I_PAGENO 0076000u /* page number */
/* Alter/Skip Group instructions */
#define I_CMx 0001000u /* CMA/B */
#define I_CLx 0000400u /* CLA/B */
#define I_CME 0000200u /* CME */
#define I_CLE 0000100u /* CLE */
#define I_SEZ 0000040u /* SEZ */
#define I_SSx 0000020u /* SSA/B */
#define I_SLx 0000010u /* SLA/B */
#define I_INx 0000004u /* INA/B */
#define I_SZx 0000002u /* SZA/B */
#define I_RSS 0000001u /* RSS */
#define I_SSx_SLx_RSS (I_SSx | I_SLx | I_RSS) /* a special case */
#define I_ALL_SKIPS (I_SEZ | I_SZx | I_SSx_SLx_RSS) /* another special case */
/* Shift/Rotate Group micro-ops */
#define I_xLS 0000000u /* ALS/BLS */
#define I_xRS 0000001u /* ARS/BRS */
#define I_RxL 0000002u /* RAL/RBL */
#define I_RxR 0000003u /* RAR/RBR */
#define I_xLR 0000004u /* ALR/BLR */
#define I_ERx 0000005u /* ERA/ERB */
#define I_ELx 0000006u /* ELA/ELB */
#define I_xLF 0000007u /* ALF/BLF */
#define SRG_DIS 0000000u
#define SRG1_EN 0000010u
#define SRG2_EN 0000020u
/* Other instructions */
#define I_NMRMASK 0172000 /* non-mrf opcode */
#define I_ASKP 0002000 /* alter/skip */
#define I_IO 0102000 /* I/O */
#define I_CTL 0004000 /* CTL on/off */
#define I_HC 0001000 /* hold/clear */
#define I_DEVMASK 0000077 /* device select code mask */
#define I_GETIOOP(x) (((x) >> 6) & 07) /* I/O sub op */
#define I_NOP 0000000u /* no operation */
#define I_NMRMASK 0172000u /* non-mrf opcode */
#define I_ASKP 0002000u /* alter/skip */
#define I_IO 0102000u /* I/O */
#define I_CTL 0004000u /* CTL on/off */
#define I_HC 0001000u /* hold/clear */
#define I_DEVMASK 0000077u /* device select code mask */
#define I_GETIOOP(x) (((x) >> 6) & 07u) /* I/O sub op */
/* Instruction masks */
#define I_MRG 0074000 /* MRG instructions */
#define I_MRG 0074000u /* MRG instructions */
#define I_MRG_I (I_MRG | I_IA) /* MRG indirect instruction group */
#define I_JSB 0014000 /* JSB instruction */
#define I_JSB 0014000u /* JSB instruction */
#define I_JSB_I (I_JSB | I_IA) /* JSB,I instruction */
#define I_JMP 0024000 /* JMP instruction */
#define I_ISZ 0034000 /* ISZ instruction */
#define I_JMP 0024000u /* JMP instruction */
#define I_ISZ 0034000u /* ISZ instruction */
#define I_IOG 0107700u /* I/O group instruction */
#define I_SFS 0102300u /* SFS instruction */
#define I_STF 0102100u /* STF instruction */
/* Initial Binary Loader.
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| ROM # | - - | select code | - - - - - - |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
*/
#define IBL_WIDTH 6 /* loader ROM address width */
#define IBL_MASK ((1u << IBL_WIDTH) - 1) /* loader ROM address mask (2 ** 6 - 1) */
#define IBL_MAX ((1u << IBL_WIDTH) - 1) /* loader ROM address maximum (2 ** 6 - 1) */
#define IBL_SIZE (IBL_MAX + 1) /* loader ROM size in words */
#define IBL_START 0 /* ROM array index of the program start */
#define IBL_DMA (IBL_MAX - 1) /* ROM array index of the DMA configuration word */
#define IBL_FWA (IBL_MAX - 0) /* ROM array index of the negative starting address */
#define IBL_NA (IBL_MAX + 1) /* "not-applicable" ROM array index */
#define IBL_S_CLEAR 0000000u /* cpu_copy_loader mask to clear the S register */
#define IBL_S_NOCLEAR 0177777u /* cpu_copy_loader mask to preserve the S register */
#define IBL_S_NOSET 0000000u /* cpu_copy_loader mask to preserve the S register */
#define IBL_ROM_MASK 0140000u /* ROM socket selector mask */
#define IBL_SC_MASK 0007700u /* device select code mask */
#define IBL_USER_MASK ~(IBL_ROM_MASK | IBL_SC_MASK)
#define IBL_ROM_SHIFT 14
#define IBL_SC_SHIFT 6
#define IBL_ROM(s) (((s) & IBL_ROM_MASK) >> IBL_ROM_SHIFT)
#define IBL_SC(s) (((s) & IBL_SC_MASK) >> IBL_SC_SHIFT)
#define IBL_TO_SC(c) ((c) << IBL_SC_SHIFT & IBL_SC_MASK)
typedef struct {
uint32 start_index; /* the array index of the start of the program */
uint32 dma_index; /* the array index of the DMA configuration word */
uint32 fwa_index; /* the array index of the negative starting address */
MEMORY_WORD loader [IBL_SIZE]; /* the 64-word bootstrap loader program */
} BOOT_LOADER;
typedef BOOT_LOADER LOADER_ARRAY [2]; /* array (21xx, 1000) of bootstrap loaders */
#define I_IOG 0107700 /* I/O group instruction */
#define I_SFS 0102300 /* SFS instruction */
#define I_STF 0102100 /* STF instruction */
/* Memory management */
@@ -243,17 +586,19 @@
#define MAP_N_PAG (PA_N_SIZE - VA_N_OFF) /* page width */
#define MAP_V_PAG (VA_N_OFF)
#define MAP_M_PAG ((1 << MAP_N_PAG) - 1)
#define MAP_GETPAG(x) (((x) & MAP_M_PAG) << MAP_V_PAG)
#define MAP_PAGE(r) ((r) & MAP_M_PAG) /* extract the page number from a map register */
#define TO_PAGE(n) ((n) << MAP_V_PAG) /* position the page number in a physical address */
/* MEM status register */
#define MST_ENBI 0100000 /* MEM enabled at interrupt */
#define MST_UMPI 0040000 /* User map selected at inerrupt */
#define MST_ENB 0020000 /* MEM enabled currently */
#define MST_UMP 0010000 /* User map selected currently */
#define MST_PRO 0004000 /* Protected mode enabled currently */
#define MST_FLT 0002000 /* Base page portion mapped */
#define MST_FENCE 0001777 /* Base page fence */
#define MST_ENBI 0100000u /* MEM enabled at interrupt */
#define MST_UMPI 0040000u /* User map selected at interrupt */
#define MST_ENB 0020000u /* MEM enabled currently */
#define MST_UMP 0010000u /* User map selected currently */
#define MST_PRO 0004000u /* Protected mode enabled currently */
#define MST_FLT 0002000u /* Base page portion mapped */
#define MST_FENCE 0001777u /* Base page fence */
/* MEM violation register */
@@ -261,76 +606,104 @@
#define MVI_V_WPR 14 /* MAP_V_xPR */
#define MVI_RPR (1 << MVI_V_RPR) /* rd viol */
#define MVI_WPR (1 << MVI_V_WPR) /* wr viol */
#define MVI_BPG 0020000 /* base page viol */
#define MVI_PRV 0010000 /* priv viol */
#define MVI_MEB 0000200 /* me bus enb @ viol */
#define MVI_MEM 0000100 /* mem enb @ viol */
#define MVI_UMP 0000040 /* usr map @ viol */
#define MVI_PAG 0000037 /* pag sel */
#define MVI_BPG 0020000u /* base page viol */
#define MVI_PRV 0010000u /* priv viol */
#define MVI_MEB 0000200u /* me bus enb @ viol */
#define MVI_MEM 0000100u /* mem enb @ viol */
#define MVI_UMP 0000040u /* usr map @ viol */
#define MVI_PAG 0000037u /* pag sel */
/* CPU registers */
#define AR ABREG[0] /* A = reg 0 */
#define BR ABREG[1] /* B = reg 1 */
#define AR ABREG [0] /* A = reg 0 */
#define BR ABREG [1] /* B = reg 1 */
extern HP_WORD ABREG [2]; /* A/B regs (use AR/BR) */
extern HP_WORD PR; /* P register */
extern HP_WORD SR; /* S register */
extern HP_WORD MR; /* M register */
extern HP_WORD TR; /* T register */
extern HP_WORD XR; /* X register */
extern HP_WORD YR; /* Y register */
extern uint32 E; /* E register */
extern uint32 O; /* O register */
extern HP_WORD IR; /* Instruction Register */
extern HP_WORD CIR; /* Central Interrupt Register */
extern uint16 ABREG[2]; /* A/B regs (use AR/BR) */
extern uint32 PR; /* P register */
extern uint32 SR; /* S register */
extern uint32 MR; /* M register */
extern uint32 TR; /* T register */
extern uint32 XR; /* X register */
extern uint32 YR; /* Y register */
extern uint32 E; /* E register */
extern uint32 O; /* O register */
/* CPU state */
extern uint32 err_PC;
extern HP_WORD err_PC;
extern uint32 dms_enb;
extern uint32 dms_ump;
extern uint32 dms_sr;
extern uint32 dms_vr;
extern HP_WORD dms_sr;
extern FLIP_FLOP mp_control;
extern uint32 mp_fence;
extern uint32 mp_viol;
extern HP_WORD mp_fence;
extern HP_WORD mp_viol;
extern FLIP_FLOP mp_mevff;
extern uint32 iop_sp;
extern HP_WORD iop_sp;
extern t_bool ion_defer;
extern uint32 intaddr;
extern uint16 pcq [PCQ_SIZE];
extern uint32 pcq_p;
extern uint32 stop_inst;
extern UNIT cpu_unit;
extern DEVICE cpu_dev;
extern REG cpu_reg [];
extern jmp_buf save_env;
extern t_bool mp_mem_changed;
extern t_stat cpu_ss_unimpl; /* status return for unimplemented instruction execution */
extern t_stat cpu_ss_undef; /* status return for undefined instruction execution */
extern t_stat cpu_ss_unsc; /* status return for I/O to an unassigned select code */
extern t_stat cpu_ss_ioerr; /* status return for an unreported I/O error */
extern t_stat cpu_ss_indir; /* status return for indirect loop execution */
extern t_stat cpu_ss_inhibit; /* simulation stop inhibition mask */
extern UNIT *cpu_ioerr_uptr; /* pointer to a unit with an unreported I/O error */
extern uint32 cpu_configuration; /* the current CPU option set and model */
extern uint32 cpu_speed; /* the CPU speed, expressed as a multiplier of a real machine */
extern t_bool is_1000; /* TRUE if the CPU is a 1000 M/E/F-Series */
/* CPU functions */
/* CPU global SCP support routines declared in scp.h
#define MP_ABORT(va) longjmp (save_env, (va))
extern t_stat sim_instr (void);
*/
extern t_stat resolve (uint32 MA, uint32 *addr, uint32 irq);
extern uint16 ReadPW (uint32 pa);
extern uint8 ReadB (uint32 va);
extern uint8 ReadBA (uint32 va);
extern uint16 ReadW (uint32 va);
extern uint16 ReadWA (uint32 va);
extern uint16 ReadIO (uint32 va, uint32 map);
extern void WritePW (uint32 pa, uint32 dat);
extern void WriteB (uint32 va, uint32 dat);
extern void WriteBA (uint32 va, uint32 dat);
extern void WriteW (uint32 va, uint32 dat);
extern void WriteWA (uint32 va, uint32 dat);
extern void WriteIO (uint32 va, uint32 dat, uint32 map);
extern t_stat iogrp (uint32 ir, uint32 iotrap);
extern uint32 calc_int (void);
extern t_bool calc_defer (void);
extern void mp_dms_jmp (uint32 va, uint32 plb);
extern uint16 dms_rmap (uint32 mapi);
extern void dms_wmap (uint32 mapi, uint32 dat);
extern void dms_viol (uint32 va, uint32 st);
extern uint32 dms_upd_vr (uint32 va);
extern uint32 dms_upd_sr (void);
#endif
/* CPU global SCP support routines */
extern void cpu_post_cmd (t_bool from_scp);
/* CPU global utility routines */
extern t_stat cpu_copy_loader (const LOADER_ARRAY boot, uint32 sc, HP_WORD sr_clear, HP_WORD sr_set);
extern t_stat cpu_iog (HP_WORD IR, t_bool iotrap);
extern uint32 calc_int (void);
extern t_stat resolve (HP_WORD MA, HP_WORD *address, uint32 irq);
/* Memory global utility routines */
extern HP_WORD mem_read (DEVICE *dptr, ACCESS_CLASS classification, HP_WORD address);
extern void mem_write (DEVICE *dptr, ACCESS_CLASS classification, HP_WORD address, HP_WORD value);
extern uint8 mem_read_byte (DEVICE *dptr, ACCESS_CLASS classification, HP_WORD byte_address);
extern void mem_write_byte (DEVICE *dptr, ACCESS_CLASS classification, HP_WORD byte_address, uint8 value);
extern HP_WORD mem_fast_read (HP_WORD address, uint32 map);
extern HP_WORD mem_examine (uint32 address);
extern void mem_deposit (uint32 address, HP_WORD value);
/* Memory Expansion Unit global utility routines */
extern uint16 dms_rmap (uint32 mapi);
extern void dms_wmap (uint32 mapi, uint32 dat);
extern void dms_viol (uint32 va, HP_WORD st);
extern HP_WORD dms_upd_vr (uint32 va);
extern HP_WORD dms_upd_sr (void);
/* Memory Protect global utility routines */
extern void mp_dms_jmp (uint32 va, uint32 plb);

View File

@@ -1,6 +1,6 @@
/* hp2100_cpu0.c: HP 1000 user microcode and unimplemented instruction set stubs
Copyright (c) 2006-2012, J. David Bryan
Copyright (c) 2006-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"),
@@ -25,6 +25,7 @@
CPU0 User microcode and unimplemented firmware options
01-Aug-17 JDB Changed .FLUN and self-tests to test for unimplemented stops
09-May-12 JDB Separated assignments from conditional expressions
04-Nov-10 JDB Removed DS note regarding PIF card (is now implemented)
18-Sep-08 JDB .FLUN and self-tests for VIS and SIGNAL are NOP if not present
@@ -138,8 +139,8 @@ if (op_ds [entry] != OP_N) {
switch (entry) { /* decode IR<3:0> */
default: /* others undefined */
reason = stop_inst;
default: /* others unimplemented */
reason = STOP (cpu_ss_unimpl);
}
return reason;
@@ -151,7 +152,7 @@ return reason;
All UIG instructions unclaimed by installed firmware options are directed
here. User- or site-specific firmware may be simulated by dispatching to the
appropriate simulator routine. Unimplemented instructions should return
"stop_inst" to cause a simulator stop if enabled.
"STOP (cpu_ss_unimpl)" to cause a simulator stop if enabled.
Implementation notes:
@@ -182,15 +183,7 @@ t_stat cpu_user (uint32 IR, uint32 intrq)
t_stat reason = SCPE_OK;
if (UNIT_CPU_TYPE == UNIT_TYPE_211X) /* 2116/15/14 CPU? */
return stop_inst; /* user microprograms not supported */
switch (IR) {
case 0105226: /* firmware detection: FFP .FLUN */
case 0105355: /* firmware detection: RTE-6/VM OS self-test */
case 0105477: /* firmware detection: VIS self-test */
case 0105617: /* firmware detection: SIGNAL/1000 self-test */
return SCPE_OK; /* execute as NOP */
}
return STOP (cpu_ss_unimpl); /* user microprograms not supported */
switch ((IR >> 4) & 037) { /* decode IR<8:4> */
@@ -212,8 +205,8 @@ switch ((IR >> 4) & 037) { /* decode IR<8:4> */
/* case 0nn: ** other cases as needed */
/* return cpu_user_nn (IR, intrq); ** uncomment to handle instruction */
default: /* others undefined */
reason = stop_inst;
default: /* others unimplemented */
reason = STOP (cpu_ss_unimpl);
}
return reason;
@@ -223,8 +216,8 @@ return reason;
/* Example user microprogram simulator.
User- or site-specific firmware may be simulated by writing the appropriate
code below. Unimplemented instructions should return "stop_inst" to cause a
simulator stop if enabled.
code below. Unimplemented instructions should return "STOP (cpu_ss_unimpl)"
to cause a simulator stop if enabled.
For information on the operand patterns used in the "op_user" array, see the
comments preceding the "cpu_ops" routine in "hp2100_cpu1.c" and the "operand
@@ -263,8 +256,8 @@ switch (entry) { /* decode IR<4:0> */
/* case 0nn: ** other cases as needed */
/* break; ** uncomment to handle instruction */
default: /* others undefined */
reason = stop_inst;
default: /* others unimplemented */
reason = STOP (cpu_ss_unimpl);
}
return reason;

View File

@@ -26,8 +26,14 @@
CPU1 Extended arithmetic and optional microcode dispatchers
07-Sep-17 JDB Removed unnecessary "uint16" casts
01-Aug-17 JDB Changed TIMER and RRR 16 to test for undefined stops
07-Jul-17 JDB Changed "iotrap" from uint32 to t_bool
26-Jun-17 JDB Replaced SEXT with SEXT16
22-Apr-17 JDB Improved the EAU shift/rotate instructions
21-Mar-17 JDB Fixed UIG 1 comment regarding 2000 IOP and F-Series
31-Jan-17 JDB Added fmt_ab to print A/B-register error codes
30-Jan-17 JDB Removed fprint_ops, fprint_regs (now redundant)
05-Aug-16 JDB Renamed the P register from "PC" to "PR"
24-Dec-14 JDB Added casts for explicit downward conversions
05-Apr-14 JDB Corrected typo in comments for cpu_ops
@@ -121,16 +127,18 @@
The design of the 1000 microinstruction set was such that executing an
instruction for which no microcode was present (e.g., executing a FFP
instruction when the FFP firmware was not installed) resulted in a NOP.
Under simulation, such execution causes an undefined instruction stop if
"stop_inst" is non-zero and a NOP otherwise.
Under simulation, such execution causes an unimplemented instruction stop if
"STOP (cpu_ss_unimpl)" is non-zero and a no-operation otherwise.
*/
#include "hp2100_defs.h"
#include "hp2100_cpu.h"
#include "hp2100_cpu1.h"
/* EAU
The Extended Arithmetic Unit (EAU) adds ten instructions with double-word
@@ -175,13 +183,15 @@
EXECUTE (100120), is also described but was never implemented, and the
E/F-series microcode execute a NOP for this instruction code.
If the EAU is not installed in a 2115 or 2116, EAU instructions execute as
NOPs or cause unimplemented instruction stops if enabled.
Implementation notes:
1. Under simulation, TIMER, DIAG, and EXECUTE cause undefined instruction
stops if the CPU is set to 21xx. DIAG and EXECUTE also cause stops on
the 1000-M. TIMER does not, because it is used by several HP programs
to differentiate between M- and E/F-series machines.
1. Under simulation, TIMER and DIAG cause undefined instruction stops if the
CPU is not an E/F-Series. Note that TIMER is intentionally executed by
several HP programs to differentiate between M- and E/F-series machines.
2. DIAG is not implemented under simulation. On the E/F, it performs a
destructive test of all installed memory. Because of this, it is only
@@ -189,9 +199,9 @@
executed with the INSTR STEP button. If it is executed in a program,
the result is NOP.
3. RRR is permitted and executed as NOP if the CPU is a 2114, as the
presence of the EAU is tested by the diagnostic configurator to
differentiate between 2114 and 2100/1000 CPUs.
3. The RRR 16 instruction is intentionally executed by the diagnostic
configurator on the 2114, which does not have an EAU, to differentiate
between 2114 and 2100/1000 CPUs.
4. The shift count is calculated unconditionally, as six of the ten
instructions will be using the value.
@@ -215,11 +225,8 @@ OPS op;
uint32 rs, qs, v1, v2, operand, fill, mask, shift;
int32 sop1, sop2;
if ((cpu_unit.flags & UNIT_EAU) == 0) /* option installed? */
if (UNIT_CPU_MODEL == UNIT_2114 && IR == 0101100) /* 2114 and RRR 16? */
return SCPE_OK; /* allowed as NOP */
else
return stop_inst; /* fail */
if ((cpu_unit.flags & UNIT_EAU) == 0) /* if the EAU is not installed */
return STOP (cpu_ss_unimpl); /* then the instructions execute as NOPs */
if (IR & 017) /* if the shift count is 1-15 */
shift = IR & 017; /* then use it verbatim */
@@ -232,10 +239,10 @@ switch ((IR >> 8) & 0377) { /* decode IR<15:8> */
switch ((IR >> 4) & 017) { /* decode IR<7:4> */
case 000: /* DIAG 100000 */
if ((UNIT_CPU_MODEL != UNIT_1000_E) && /* must be 1000 E-series */
(UNIT_CPU_MODEL != UNIT_1000_F)) /* or 1000 F-series */
return stop_inst; /* trap if not */
break; /* DIAG is NOP unless halted */
if (UNIT_CPU_MODEL != UNIT_1000_E /* if the CPU is not an E-series */
&& UNIT_CPU_MODEL != UNIT_1000_F) /* or an F-series */
return STOP (cpu_ss_undef); /* then the instruction is undefined */
break; /* and executes as NOP */
case 001: /* ASL 100020-100037 */
@@ -277,25 +284,31 @@ switch ((IR >> 8) & 0377) { /* decode IR<15:8> */
case 003: /* TIMER 100060 */
if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */
return stop_inst; /* trap if not */
if (UNIT_CPU_MODEL == UNIT_1000_E /* if the CPU is an E-series */
|| UNIT_CPU_MODEL == UNIT_1000_F) { /* or an F-series */
BR = BR + 1 & R_MASK; /* then increment B */
if (UNIT_CPU_MODEL != UNIT_1000_M) { /* 1000 E/F-series? */
BR = (BR + 1) & DMASK; /* increment B */
if (BR) /* if !=0, repeat */
PR = err_PC;
if (BR != 0) /* if B did not roll over */
PR = err_PC; /* then repeat the instruction */
break;
}
else { /* otherwise it's a 21xx or 1000 M-Series */
reason = STOP (cpu_ss_undef); /* and the instruction is undefined */
if (reason != SCPE_OK /* if a stop is indicated */
|| UNIT_CPU_MODEL != UNIT_1000_M) /* or the CPU is a 21xx */
break; /* then the instruction executes as NOP */
}
/* fall into the MPY case if 1000 M-Series */
case 010: /* MPY 100200 (OP_K) */
reason = cpu_ops (OP_K, op, intrq); /* get operand */
if (reason == SCPE_OK) { /* successful eval? */
sop1 = SEXT (AR); /* sext AR */
sop2 = SEXT (op[0].word); /* sext mem */
sop1 = SEXT16 (AR); /* sext AR */
sop2 = SEXT16 (op[0].word); /* sext mem */
sop1 = sop1 * sop2; /* signed mpy */
BR = UPPER_WORD (sop1); /* to BR'AR */
AR = LOWER_WORD (sop1);
@@ -305,7 +318,7 @@ switch ((IR >> 8) & 0377) { /* decode IR<15:8> */
default: /* others undefined */
return stop_inst;
return STOP (cpu_ss_unimpl);
}
break;
@@ -392,7 +405,7 @@ switch ((IR >> 8) & 0377) { /* decode IR<15:8> */
default: /* others undefined */
return stop_inst;
return STOP (cpu_ss_undef);
}
break;
@@ -480,7 +493,7 @@ return reason;
user microcode dispatcher.
*/
t_stat cpu_uig_0 (uint32 IR, uint32 intrq, uint32 iotrap)
t_stat cpu_uig_0 (uint32 IR, uint32 intrq, t_bool iotrap)
{
if ((cpu_unit.flags & UNIT_IOP) && /* I/O Processor? */
(UNIT_CPU_TYPE == UNIT_TYPE_2100)) /* and 2100 CPU? */
@@ -621,10 +634,10 @@ return cpu_user (IR, intrq); /* try user microcode */
user microcode dispatcher.
*/
t_stat cpu_uig_1 (uint32 IR, uint32 intrq, uint32 iotrap)
t_stat cpu_uig_1 (uint32 IR, uint32 intrq, t_bool iotrap)
{
if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* 1000 execution? */
return stop_inst; /* no, so trap */
if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* if the CPU is not a 1000 */
return STOP (cpu_ss_unimpl); /* the the instruction is unimplemented */
switch ((IR >> 4) & 017) { /* decode IR<7:4> */
@@ -680,7 +693,7 @@ return cpu_user (IR, intrq); /* try user microcode */
/* Read a multiple-precision operand value. */
OP ReadOp (uint32 va, OPSIZE precision)
OP ReadOp (HP_WORD va, OPSIZE precision)
{
OP operand;
uint32 i;
@@ -702,7 +715,7 @@ return operand;
/* Write a multiple-precision operand value. */
void WriteOp (uint32 va, OP operand, OPSIZE precision)
void WriteOp (HP_WORD va, OP operand, OPSIZE precision)
{
uint32 i;
@@ -810,19 +823,29 @@ return;
An operand pattern consists of one or more operand encodings, corresponding
to the operands required by a given instruction. Values are returned in
sequence to the operand array.
Implementation notes:
1. The reads of address operand words that follow an instruction (e.g., the
DEFs above) are classified as instruction fetches. The reads of the
operands themselves are classified as data accesses.
*/
t_stat cpu_ops (OP_PAT pattern, OPS op, uint32 irq)
{
t_stat reason = SCPE_OK;
OP_PAT flags;
uint32 i, MA;
OP_PAT flags;
uint32 i;
HP_WORD MA, address;
t_stat reason = SCPE_OK;
for (i = 0; i < OP_N_F; i++) {
flags = pattern & OP_M_FLAGS; /* get operand pattern */
if (flags >= OP_ADR) { /* address operand? */
reason = resolve (ReadW (PR), &MA, irq); /* resolve indirects */
address = ReadF (PR); /* get the pointer */
reason = resolve (address, &MA, irq); /* resolve indirects */
if (reason != SCPE_OK) /* resolution failed? */
return reason;
}
@@ -849,11 +872,11 @@ for (i = 0; i < OP_N_F; i++) {
break;
case OP_VAR: /* inline variable operand */
(*op++).word = (uint16) PR; /* get pointer to variable */
(*op++).word = PR; /* get pointer to variable */
break;
case OP_ADR: /* inline address operand */
(*op++).word = (uint16) MA; /* get address (set by "resolve" above) */
(*op++).word = MA; /* get address (set by "resolve" above) */
break;
case OP_ADK: /* address of int constant */
@@ -892,117 +915,33 @@ return reason;
}
/* Print operands to the debug device.
/* Format an error code in the A and B registers.
The values of an operand array are printed to the debug device. The types of
the operands are specified by an operand pattern. Typically, the operand
pattern is the same one that was used to fill the array originally.
This routine conditionally formats the contents of the A and B registers into
an error message. If the supplied "success" flag is 0, the A and B registers
contain a four-character error code (e.g., "EM82"), with the leading
characters in the B register. The characters are moved into the error
message, and a pointer to the message is returned. If "success" is non-zero,
then a pointer to the message reporting normal execution is returned.
The routine is typically called from an instructio executor during operand
tracing.
*/
void fprint_ops (OP_PAT pattern, OPS op)
const char *fmt_ab (t_bool success)
{
OP_PAT flags;
uint32 i;
static const char good [] = "normal";
static char error [] = "error ....";
for (i = 0; i < OP_N_F; i++) {
flags = pattern & OP_M_FLAGS; /* get operand pattern */
if (success) /* if the instruction succeeded */
return good; /* then report a normal completion */
switch (flags) {
case OP_NUL: /* null operand */
return; /* no more, so quit */
else { /* otherwise */
error [6] = UPPER_BYTE (BR); /* format the */
error [7] = LOWER_BYTE (BR); /* error code */
error [8] = UPPER_BYTE (AR); /* into the */
error [9] = LOWER_BYTE (AR); /* error message */
case OP_IAR: /* int in A */
case OP_CON: /* inline constant operand */
case OP_VAR: /* inline variable operand */
case OP_ADR: /* inline address operand */
case OP_ADK: /* address of int constant */
fprintf (sim_deb,
", op[%d] = %06o",
i, op[i].word);
break;
case OP_JAB: /* dbl-int in A/B */
case OP_ADD: /* address of dbl-int constant */
fprintf (sim_deb,
", op[%d] = %011o",
i, op[i].dword);
break;
case OP_FAB: /* 2-word FP in A/B */
case OP_ADF: /* address of 2-word FP const */
fprintf (sim_deb,
", op[%d] = (%06o, %06o)",
i, op[i].fpk[0], op[i].fpk[1]);
break;
case OP_ADX: /* address of 3-word FP const */
fprintf (sim_deb,
", op[%d] = (%06o, %06o, %06o)",
i, op[i].fpk[0], op[i].fpk[1],
op[i].fpk[2]);
break;
case OP_ADT: /* address of 4-word FP const */
fprintf (sim_deb,
", op[%d] = (%06o, %06o, %06o, %06o)",
i, op[i].fpk[0], op[i].fpk[1],
op[i].fpk[2], op[i].fpk[3]);
break;
case OP_ADE: /* address of 5-word FP const */
fprintf (sim_deb,
", op[%d] = (%06o, %06o, %06o, %06o, %06o)",
i, op[i].fpk[0], op[i].fpk[1],
op[i].fpk[2], op[i].fpk[3], op[i].fpk[4]);
break;
default:
fprintf (sim_deb, "UNKNOWN OPERAND TYPE"); /* not implemented */
}
pattern = pattern >> OP_N_FLAGS; /* move next pattern into place */
return error; /* report an abnormal completion */
}
}
/* Print CPU registers to the debug device.
One or more CPU registers may be printed to the debug output device, which
must be valid before calling.
*/
void fprint_regs (char *caption, uint32 regs, uint32 base)
{
static uint32 ARX, BRX, PRL; /* static so addresses are constant */
static const char *reg_names[] = { "CIR", "A", "B", "E", "X", "Y", "O", "P", "return" };
static const uint32 *reg_ptrs[] = { &intaddr, &ARX, &BRX, &E, &XR, &YR, &O, &PR, &PRL };
static const char *formats[] = { "%02o", "%06o", "%06o", "%01o", "%06o", "%06o", "%01o", "%06o", "P+%d" };
static char format[20] = " %s = "; /* base format string */
static const int eos = 6; /* length of base format string */
uint32 i;
t_bool first = TRUE; /* first-time through flag */
ARX = AR; /* copy 16-bit value to static variable */
BRX = BR; /* copy 16-bit value to static variable */
PRL = PR - base; /* compute value in static variable */
for (i = 0; i < REG_COUNT; i++) {
if (regs & 1) { /* register requested? */
if (first) /* first time? */
fputs (caption, sim_deb); /* print caption */
else
fputc (',', sim_deb); /* print separator */
strcpy (&format[eos], formats[i]); /* copy format specifier */
fprintf (sim_deb, format, reg_names[i], *reg_ptrs[i]);
first = FALSE;
}
regs = regs >> 1; /* align next register flag */
}
return;
}

View File

@@ -1,6 +1,6 @@
/* hp2100_cpu1.h: HP 2100/1000 firmware dispatcher definitions
/* hp2100_cpu1.h: HP 2100/1000 firmware dispatcher declarations
Copyright (c) 2006-2013, J. David Bryan
Copyright (c) 2006-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"),
@@ -23,6 +23,10 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from the author.
07-Jul-17 JDB Changed "iotrap" from uint32 to t_bool
15-Feb-17 JDB Deleted unneeded guard macro definition
26-Jan-17 JDB Removed debug parameters from cpu_ema_* routines
17-Jan-17 JDB Removed register print encoding constants (now redundant)
18-Mar-13 JDB Added externs for microcode helper functions
14-Mar-13 MP Changed guard macro name to avoid reserved namespace
11-Sep-08 JDB Moved microcode function prototypes here
@@ -35,23 +39,6 @@
26-Sep-06 JDB Split from hp2100_cpu1.c
*/
#ifndef HP2100_CPU1_H_
#define HP2100_CPU1_H_
/* Register print encoding */
#define REG_COUNT 9 /* count of print flags */
#define REG_CIR (1 << 0) /* print central interrupt register */
#define REG_A (1 << 1) /* print A register */
#define REG_B (1 << 2) /* print B register */
#define REG_E (1 << 3) /* print E register */
#define REG_X (1 << 4) /* print X register */
#define REG_Y (1 << 5) /* print Y register */
#define REG_O (1 << 6) /* print O register */
#define REG_P (1 << 7) /* print P register */
#define REG_P_REL (1 << 8) /* print P register as relative */
/* Operand processing encoding */
@@ -246,7 +233,7 @@ typedef enum { in_s, in_d, fp_f, fp_x, fp_t, fp_e, fp_a } OPSIZE;
Actual value will use two, three, four, or five words, as needed.
*/
typedef uint16 FPK[5];
typedef HP_WORD FPK [5];
/* Operand processing types.
@@ -259,9 +246,9 @@ typedef uint16 FPK[5];
*/
typedef union { /* general operand */
FPK fpk; /* floating-point value */
uint16 word; /* 16-bit integer */
uint32 dword; /* 32-bit integer */
FPK fpk; /* floating-point value */
HP_WORD word; /* 16-bit integer */
uint32 dword; /* 32-bit integer */
} OP;
typedef OP OPS[OP_N_F]; /* operand array */
@@ -276,8 +263,8 @@ extern t_stat cpu_user (uint32 IR, uint32 intrq); /* [0] User
extern t_stat cpu_user_20 (uint32 IR, uint32 intrq); /* [0] Module 20 user microprograms stub */
extern t_stat cpu_eau (uint32 IR, uint32 intrq); /* [1] EAU group simulator */
extern t_stat cpu_uig_0 (uint32 IR, uint32 intrq, uint32 iotrap); /* [1] UIG group 0 dispatcher */
extern t_stat cpu_uig_1 (uint32 IR, uint32 intrq, uint32 iotrap); /* [1] UIG group 1 dispatcher */
extern t_stat cpu_uig_0 (uint32 IR, uint32 intrq, t_bool iotrap); /* [1] UIG group 0 dispatcher */
extern t_stat cpu_uig_1 (uint32 IR, uint32 intrq, t_bool iotrap); /* [1] UIG group 1 dispatcher */
#if !defined (HAVE_INT64) /* int64 support unavailable */
extern t_stat cpu_fp (uint32 IR, uint32 intrq); /* [2] Firmware Floating Point */
@@ -297,7 +284,7 @@ extern t_stat cpu_sis (uint32 IR, uint32 intrq); /* [4] Scien
extern t_stat cpu_rte_vma (uint32 IR, uint32 intrq); /* [5] RTE-6 VMA */
extern t_stat cpu_rte_ema (uint32 IR, uint32 intrq); /* [5] RTE-IV EMA */
extern t_stat cpu_rte_os (uint32 IR, uint32 intrq, uint32 iotrap); /* [6] RTE-6 OS */
extern t_stat cpu_rte_os (uint32 IR, uint32 intrq, t_bool iotrap); /* [6] RTE-6 OS */
#if defined (HAVE_INT64) /* int64 support available */
extern t_stat cpu_vis (uint32 IR, uint32 intrq); /* [7] Vector Instruction Set */
@@ -307,17 +294,14 @@ extern t_stat cpu_signal (uint32 IR, uint32 intrq); /* [7] SIGNA
/* Microcode helper functions */
extern OP ReadOp (uint32 va, OPSIZE precision); /* generalized operand read */
extern void WriteOp (uint32 va, OP operand, OPSIZE precision); /* generalized operand write */
extern t_stat cpu_ops (OP_PAT pattern, OPS op, uint32 irq); /* operand processor */
extern OP ReadOp (HP_WORD va, OPSIZE precision); /* generalized operand read */
extern void WriteOp (HP_WORD va, OP operand, OPSIZE precision); /* generalized operand write */
extern t_stat cpu_ops (OP_PAT pattern, OPS op, uint32 irq); /* operand processor */
extern void fprint_ops (OP_PAT pattern, OPS op); /* debug print operands */
extern void fprint_regs (char *caption, uint32 regs, uint32 base); /* debug print CPU registers */
extern const char *fmt_ab (t_bool success); /* format an error code in the A/B registers */
/* implemented in hp2100_cpu5.c (RTE-IV EMA functions) */
extern t_stat cpu_ema_eres (uint32 *rtn, uint32 dtbl, uint32 atbl, t_bool debug);
extern t_stat cpu_ema_eseg (uint32 *rtn, uint32 ir, uint32 tbl, t_bool debug);
extern t_stat cpu_ema_vset (uint32 *rtn, OPS op, t_bool debug);
#endif
extern t_stat cpu_ema_eres (HP_WORD *rtn, uint32 dtbl, uint32 atbl);
extern t_stat cpu_ema_eseg (HP_WORD *rtn, uint32 ir, uint32 tbl);
extern t_stat cpu_ema_vset (HP_WORD *rtn, OPS op);

View File

@@ -1,31 +1,37 @@
/* hp2100_cpu2.c: HP 2100/1000 FP/DMS/EIG/IOP instructions
Copyright (c) 2005-2016, Robert M. Supnik
Copyright (c) 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 in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not be
Except as contained in this notice, the names of the authors shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
in this Software without prior written authorization from the authors.
CPU2 Floating-point, dynamic mapping, extended, and I/O processor
instructions
07-Sep-17 JDB Removed unnecessary "uint16" casts
10-Jul-17 JDB Renamed the global routine "iogrp" to "cpu_iog"
26-Jun-17 JDB Replaced SEXT with SEXT16
22-Mar-17 JDB Corrected comments regarding IR bit 11 selecting A/B
25-Jan-17 JDB Set mp_mem_changed whenever MEM registers are changed
05-Aug-16 JDB Renamed the P register from "PC" to "PR"
24-Dec-14 JDB Added casts for explicit downward conversions
09-May-12 JDB Separated assignments from conditional expressions
@@ -202,12 +208,13 @@ return reason;
10x716 [nop] [nop] 10x736 UJP UJP
10x717 [nop] [nop] 10x737 UJS UJS
Instructions that use IR bit 9 to select the A or B register are designated
Instructions that use IR bit 11 to select the A or B register are designated
with a * above (e.g., 101710 is SYA, and 105710 is SYB). For those that do
not use this feature, either the 101xxx or 105xxx code will execute the
corresponding instruction, although the 105xxx form is the documented
instruction code.
Implementation notes:
1. Instruction code 10x700 will execute the XMM instruction, although 10x720
@@ -221,8 +228,8 @@ return reason;
- load map and CTL5 set (XMM, XMS, XM*, SY*, US*, PA*, PB*)
- load state or fence and UMAP set (JRS, DJP, DJS, SJP, SJS, UJP, UJS, LF*)
4. The 1000 manual is incorrect in stating that M*I, M*W, XS* are
privileged.
4. DM (write) violations for the use of the MBI, MWI, MBW, MWW, XSA, and XSB
instructions in protected mode are generated by the mem_write routine.
5. The protected memory lower bound for the DJP, SJP, UJP, and JRS
instructions is 2.
@@ -243,8 +250,9 @@ t_stat cpu_dms (uint32 IR, uint32 intrq)
{
t_stat reason = SCPE_OK;
OPS op;
uint32 entry, absel;
uint32 i, t, mapi, mapj;
uint8 byte;
uint32 entry, absel, i, mapi, mapj;
HP_WORD t;
absel = (IR & I_AB)? 1: 0; /* get A/B select */
entry = IR & 037; /* mask to entry point */
@@ -272,8 +280,8 @@ switch (entry) { /* decode IR<3:0> */
AR = AR & ~1; /* force A, B even */
BR = BR & ~1;
while (XR != 0) { /* loop */
t = ReadB (AR); /* read curr */
WriteBA (BR, t); /* write alt */
byte = ReadB (AR); /* read curr */
WriteBA (BR, byte); /* write alt */
AR = (AR + 1) & DMASK; /* incr ptrs */
BR = (BR + 1) & DMASK;
XR = (XR - 1) & DMASK;
@@ -288,8 +296,8 @@ switch (entry) { /* decode IR<3:0> */
AR = AR & ~1; /* force A, B even */
BR = BR & ~1;
while (XR != 0) { /* loop */
t = ReadBA (AR); /* read alt */
WriteB (BR, t); /* write curr */
byte = ReadBA (AR); /* read alt */
WriteB (BR, byte); /* write curr */
AR = (AR + 1) & DMASK; /* incr ptrs */
BR = (BR + 1) & DMASK;
XR = (XR - 1) & DMASK;
@@ -304,8 +312,8 @@ switch (entry) { /* decode IR<3:0> */
AR = AR & ~1; /* force A, B even */
BR = BR & ~1;
while (XR != 0) { /* loop */
t = ReadBA (AR); /* read alt */
WriteBA (BR, t); /* write alt */
byte = ReadBA (AR); /* read alt */
WriteBA (BR, byte); /* write alt */
AR = (AR + 1) & DMASK; /* incr ptrs */
BR = (BR + 1) & DMASK;
XR = (XR - 1) & DMASK;
@@ -391,10 +399,11 @@ switch (entry) { /* decode IR<3:0> */
dms_enb = 1;
if (op[0].word & 0040000) dms_ump = UMAP; /* set/clr usr */
}
mp_mem_changed = TRUE; /* set the MP/MEM registers changed flag */
mp_dms_jmp (op[1].word, 2); /* mpck jmp target */
PCQ_ENTRY; /* save old P */
PR = op[1].word; /* jump */
ion_defer = 1; /* defer intr */
ion_defer = TRUE; /* defer intr */
break;
/* DMS module 2 */
@@ -467,14 +476,16 @@ switch (entry) { /* decode IR<3:0> */
if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */
dms_sr = (dms_sr & ~(MST_FLT | MST_FENCE)) |
(ABREG[absel] & (MST_FLT | MST_FENCE));
mp_mem_changed = TRUE; /* set the MP/MEM registers changed flag */
break;
case 030: /* RSA, RSB 10x730 (OP_N) */
ABREG[absel] = (uint16) dms_upd_sr (); /* save stat */
ABREG [absel] = dms_upd_sr (); /* save stat */
break;
case 031: /* RVA, RVB 10x731 (OP_N) */
ABREG[absel] = (uint16) dms_upd_vr (err_PC); /* return updated violation register */
ABREG [absel] = dms_upd_vr (err_PC); /* return updated violation register */
break;
case 032: /* DJP 105732 (OP_A) */
@@ -484,7 +495,7 @@ switch (entry) { /* decode IR<3:0> */
mp_dms_jmp (op[0].word, 2); /* validate jump addr */
PCQ_ENTRY; /* save curr P */
PR = op[0].word; /* new P */
ion_defer = 1;
ion_defer = TRUE; /* defer interrupts */
break;
case 033: /* DJS 105733 (OP_A) */
@@ -494,7 +505,7 @@ switch (entry) { /* decode IR<3:0> */
PR = (op[0].word + 1) & VAMASK; /* new P */
dms_enb = 0; /* disable map */
dms_ump = SMAP;
ion_defer = 1; /* defer intr */
ion_defer = TRUE; /* defer intr */
break;
case 034: /* SJP 105734 (OP_A) */
@@ -504,7 +515,7 @@ switch (entry) { /* decode IR<3:0> */
mp_dms_jmp (op[0].word, 2); /* validate jump addr */
PCQ_ENTRY; /* save curr P */
PR = op[0].word; /* jump */
ion_defer = 1; /* defer intr */
ion_defer = TRUE; /* defer intr */
break;
case 035: /* SJS 105735 (OP_A) */
@@ -515,7 +526,7 @@ switch (entry) { /* decode IR<3:0> */
dms_enb = 1; /* enable system */
dms_ump = SMAP;
WriteW (op[0].word, t); /* store ret addr */
ion_defer = 1; /* defer intr */
ion_defer = TRUE; /* defer intr */
break;
case 036: /* UJP 105736 (OP_A) */
@@ -525,7 +536,7 @@ switch (entry) { /* decode IR<3:0> */
mp_dms_jmp (op[0].word, 2); /* validate jump addr */
PCQ_ENTRY; /* save curr P */
PR = op[0].word; /* jump */
ion_defer = 1; /* defer intr */
ion_defer = TRUE; /* defer intr */
break;
case 037: /* UJS 105737 (OP_A) */
@@ -536,7 +547,7 @@ switch (entry) { /* decode IR<3:0> */
dms_enb = 1; /* enable user */
dms_ump = UMAP;
WriteW (op[0].word, t); /* store ret addr */
ion_defer = 1; /* defer intr */
ion_defer = TRUE; /* defer intr */
break;
default: /* others NOP */
@@ -581,7 +592,7 @@ return reason;
10x756 ADY 10x776 CMW
10x757 X*Y 10x777 MVW
Instructions that use IR bit 9 to select the A or B register are designated
Instructions that use IR bit 11 to select the A or B register are designated
with a * above (e.g., 101740 is SAX, and 105740 is SBX). For those that do
not use this feature, either the 101xxx or 105xxx code will execute the
corresponding instruction, although the 105xxx form is the documented
@@ -611,8 +622,9 @@ t_stat cpu_eig (uint32 IR, uint32 intrq)
{
t_stat reason = SCPE_OK;
OPS op;
uint32 entry, absel;
uint32 t, v1, v2, wc;
uint8 byte, b1, b2;
uint32 entry, absel, sum;
HP_WORD t, v1, v2, wc;
int32 sop1, sop2;
absel = (IR & I_AB)? 1: 0; /* get A/B select */
@@ -648,7 +660,7 @@ switch (entry) { /* decode IR<4:0> */
break;
case 004: /* CXA, CXB 10x744 (OP_N) */
ABREG[absel] = (uint16) XR; /* copy from XR */
ABREG [absel] = XR; /* copy from XR */
break;
case 005: /* LDX 105745 (OP_K)*/
@@ -656,16 +668,16 @@ switch (entry) { /* decode IR<4:0> */
break;
case 006: /* ADX 105746 (OP_K) */
t = XR + op[0].word; /* add to XR */
if (t > DMASK) E = 1; /* set E, O */
if (((~XR ^ op[0].word) & (XR ^ t)) & SIGN) O = 1;
XR = t & DMASK;
sum = XR + op[0].word; /* add to XR */
if (sum > DMASK) E = 1; /* set E, O */
if (((~XR ^ op[0].word) & (XR ^ sum)) & SIGN) O = 1;
XR = sum & DMASK;
break;
case 007: /* XAX, XBX 10x747 (OP_N) */
t = XR; /* exchange XR */
XR = ABREG[absel];
ABREG[absel] = (uint16) t;
XR = ABREG [absel];
ABREG [absel] = t;
break;
case 010: /* SAY, SBY 10x750 (OP_A) */
@@ -687,7 +699,7 @@ switch (entry) { /* decode IR<4:0> */
break;
case 014: /* CYA, CYB 10x754 (OP_N) */
ABREG[absel] = (uint16) YR; /* copy from YR */
ABREG [absel] = YR; /* copy from YR */
break;
case 015: /* LDY 105755 (OP_K) */
@@ -695,16 +707,16 @@ switch (entry) { /* decode IR<4:0> */
break;
case 016: /* ADY 105756 (OP_K) */
t = YR + op[0].word; /* add to YR */
if (t > DMASK) E = 1; /* set E, O */
if (((~YR ^ op[0].word) & (YR ^ t)) & SIGN) O = 1;
YR = t & DMASK;
sum = YR + op[0].word; /* add to YR */
if (sum > DMASK) E = 1; /* set E, O */
if (((~YR ^ op[0].word) & (YR ^ sum)) & SIGN) O = 1;
YR = sum & DMASK;
break;
case 017: /* XAY, XBY 10x757 (OP_N) */
t = YR; /* exchange YR */
YR = ABREG[absel];
ABREG[absel] = (uint16) t;
YR = ABREG [absel];
ABREG [absel] = t;
break;
/* EIG module 2 */
@@ -732,7 +744,7 @@ switch (entry) { /* decode IR<4:0> */
break;
case 024: /* SBT 105764 (OP_N) */
WriteB (BR, AR); /* store byte */
WriteB (BR, LOWER_BYTE (AR)); /* store byte */
BR = (BR + 1) & DMASK; /* incr ptr */
break;
@@ -744,8 +756,8 @@ switch (entry) { /* decode IR<4:0> */
break; /* < 0 is NOP for 2100 IOP */
while (wc != 0) { /* while count */
WriteW (op[1].word, wc); /* for MP abort */
t = ReadB (AR); /* move byte */
WriteB (BR, t);
byte = ReadB (AR); /* move byte */
WriteB (BR, byte);
AR = (AR + 1) & DMASK; /* incr src */
BR = (BR + 1) & DMASK; /* incr dst */
wc = (wc - 1) & DMASK; /* decr cnt */
@@ -762,10 +774,10 @@ switch (entry) { /* decode IR<4:0> */
if (wc == 0) wc = op[0].word; /* none? get initiation count */
while (wc != 0) { /* while count */
WriteW (op[1].word, wc); /* for MP abort */
v1 = ReadB (AR); /* get src1 */
v2 = ReadB (BR); /* get src2 */
if (v1 != v2) { /* compare */
PR = (PR + 1 + (v1 > v2)) & VAMASK;
b1 = ReadB (AR); /* get src1 */
b2 = ReadB (BR); /* get src2 */
if (b1 != b2) { /* compare */
PR = (PR + 1 + (b1 > b2)) & VAMASK;
BR = (BR + wc) & DMASK; /* update BR */
wc = 0; /* clr interim */
break;
@@ -782,13 +794,13 @@ switch (entry) { /* decode IR<4:0> */
break;
case 027: /* SFB 105767 (OP_N) */
v1 = AR & 0377; /* test byte */
v2 = (AR >> 8) & 0377; /* term byte */
b1 = LOWER_BYTE (AR); /* test byte */
b2 = UPPER_BYTE (AR); /* term byte */
for (;;) { /* scan */
t = ReadB (BR); /* read byte */
if (t == v1) break; /* test match? */
byte = ReadB (BR); /* read byte */
if (byte == b1) break; /* test match? */
BR = (BR + 1) & DMASK;
if (t == v2) { /* term match? */
if (byte == b2) { /* term match? */
PR = (PR + 1) & VAMASK;
break;
}
@@ -838,8 +850,8 @@ switch (entry) { /* decode IR<4:0> */
WriteW (op[1].word, wc); /* for abort */
v1 = ReadW (AR & VAMASK); /* first op */
v2 = ReadW (BR & VAMASK); /* second op */
sop1 = (int32) SEXT (v1); /* signed */
sop2 = (int32) SEXT (v2);
sop1 = SEXT16 (v1); /* signed */
sop2 = SEXT16 (v2);
if (sop1 != sop2) { /* compare */
PR = (PR + 1 + (sop1 > sop2)) & VAMASK;
BR = (BR + wc) & DMASK; /* update BR */
@@ -954,8 +966,9 @@ t_stat cpu_iop (uint32 IR, uint32 intrq)
{
t_stat reason = SCPE_OK;
OPS op;
uint32 entry;
uint32 hp, tp, i, t, wc, MA;
uint8 byte;
uint32 entry, i;
HP_WORD hp, tp, t, wc, MA;
if (UNIT_CPU_TYPE == UNIT_TYPE_2100) { /* 2100 IOP? */
if ((IR >= 0105020) && (IR <= 0105057)) /* remap LAI */
@@ -982,7 +995,7 @@ if (UNIT_CPU_TYPE == UNIT_TYPE_2100) { /* 2100 IOP? */
case 0105362: IR = 0105474; break; /* SAVE */
default: /* all others invalid */
return stop_inst;
return STOP (cpu_ss_unimpl);
}
}
}
@@ -996,7 +1009,7 @@ if (entry <= 037) { /* LAI/SAI 10x400-437 */
return reason;
}
else if (entry <= 057) /* IR = 10x440-457? */
return stop_inst; /* not part of IOP */
return STOP (cpu_ss_unimpl); /* not part of IOP */
entry = entry - 060; /* offset 10x460-477 */
@@ -1032,7 +1045,7 @@ switch (entry) { /* decode IR<5:0> */
break;
case 002: /* READF 105462 (OP_N) */
AR = (uint16) iop_sp; /* copy stk ptr */
AR = iop_sp; /* copy stk ptr */
break;
case 003: /* INS 105463 (OP_N) */
@@ -1073,8 +1086,8 @@ switch (entry) { /* decode IR<5:0> */
if (wc & SIGN) break; /* cnt < 0? */
while (wc != 0) { /* loop */
MA = (AR + AR + ReadB (BR)) & VAMASK;
t = ReadB (MA); /* xlate */
WriteB (BR, t); /* store char */
byte = ReadB (MA); /* xlate */
WriteB (BR, byte); /* store char */
BR = (BR + 1) & DMASK; /* incr ptr */
wc = (wc - 1) & DMASK; /* decr cnt */
if (wc && intrq) { /* more and intr? */
@@ -1097,7 +1110,7 @@ switch (entry) { /* decode IR<5:0> */
case 011: /* PRFEI 105471 (OP_CVA) */
WriteW (op[1].word, 1); /* set flag */
reason = iogrp (op[0].word, 0); /* execute I/O instr */
reason = cpu_iog (op[0].word, 0); /* execute I/O instr */
op[0].word = op[2].word; /* set rtn and fall through */
case 012: /* PRFEX 105472 (OP_A) */
@@ -1108,7 +1121,7 @@ switch (entry) { /* decode IR<5:0> */
case 013: /* PRFIO 105473 (OP_CV) */
WriteW (op[1].word, 1); /* set flag */
reason = iogrp (op[0].word, 0); /* execute instr */
reason = cpu_iog (op[0].word, 0); /* execute instr */
break;
case 014: /* SAVE 105474 (OP_N) */
@@ -1116,15 +1129,15 @@ switch (entry) { /* decode IR<5:0> */
iop_sp = (iop_sp + 1) & VAMASK; /* incr stack ptr */
WriteW (iop_sp, BR); /* save B */
iop_sp = (iop_sp + 1) & VAMASK; /* incr stack ptr */
t = ((O ^ 1) << 1) | E; /* merge E and O */
t = (HP_WORD) ((O ^ 1) << 1 | E); /* merge E and O */
WriteW (iop_sp, t); /* save E and O */
iop_sp = (iop_sp + 1) & VAMASK; /* incr stack ptr */
if (UNIT_CPU_TYPE == UNIT_TYPE_2100)
mp_fence = iop_sp; /* 2100 keeps sp in MP FR */
break;
default: /* instruction undefined */
return stop_inst;
default: /* instruction unimplemented */
return STOP (cpu_ss_unimpl);
}
return reason;

View File

@@ -1,6 +1,6 @@
/* hp2100_cpu3.c: HP 2100/1000 FFP/DBI instructions
Copyright (c) 2005-2016, J. David Bryan
Copyright (c) 2005-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"),
@@ -25,6 +25,8 @@
CPU3 Fast FORTRAN and Double Integer instructions
24-Aug-17 JDB op_ffp_f definition is now conditional on HAVE_INT64
27-Mar-17 JDB Improved the comments for the FFP instructions
05-Aug-16 JDB Renamed the P register from "PC" to "PR"
24-Dec-14 JDB Added casts for explicit downward conversions
09-May-12 JDB Separated assignments from conditional expressions
@@ -41,15 +43,23 @@
18-Feb-05 JDB Add 2100/21MX Fast FORTRAN Processor instructions
Primary references:
- HP 1000 M/E/F-Series Computers Technical Reference Handbook
(5955-0282, Mar-1980)
- HP 1000 M/E/F-Series Computers Engineering and Reference Documentation
(92851-90001, Mar-1981)
- Macro/1000 Reference Manual (92059-90001, Dec-1992)
- HP 1000 M/E/F-Series Computers Technical Reference Handbook
(5955-0282, March 1980)
- HP 1000 M/E/F-Series Computers Engineering and Reference Documentation
(92851-90001, March 1981)
- Macro/1000 Reference Manual
(92059-90001, December 1992)
Firmware-specific references:
- DOS/RTE Relocatable Library Reference Manual
(24998-90001, October 1981)
- Implementing the HP 2100 Fast FORTRAN Processor
(12907-90010, November 1974)
- 93585A Microcode Source
(93585-18002 Rev. 2005)
- 93585A Double Integer Instructions Installation and Reference Manual
(93585-90007, February 1984)
Additional references are listed with the associated firmware
implementations, as are the HP option model numbers pertaining to the
applicable CPUs.
*/
#include "hp2100_defs.h"
@@ -143,12 +153,14 @@
9. The protected memory lower bound for the .GOTO instruction is 2.
Additional references:
- DOS/RTE Relocatable Library Reference Manual (24998-90001, Oct-1981)
- Implementing the HP 2100 Fast FORTRAN Processor (12907-90010, Nov-1974)
10. The OP_N (none) operand pattern is used here for all double-integer
instructions. They are dispatched to the DBI handler for execution,
where the correct operands will be retrieved
*/
static const OP_PAT op_ffp_f[32] = { /* patterns for F-Series only */
#if defined (HAVE_INT64) /* int64 support available */
static const OP_PAT op_ffp_f [32] = { /* patterns for F-Series only */
OP_N, OP_AAF, OP_AX, OP_N, /* [tst] DBLE SNGL .DNG */
OP_N, OP_AA, OP_A, OP_AAF, /* .DCO .DFER .XPAK .BLE */
OP_N, OP_N, OP_N, OP_N, /* .DIN .DDE .DIS .DDS */
@@ -159,7 +171,9 @@ static const OP_PAT op_ffp_f[32] = { /* patterns for F-Series
OP_N, OP_N, OP_N, OP_N /* --- --- --- --- */
};
static const OP_PAT op_ffp_e[32] = { /* patterns for 2100/M/E-Series */
#endif /* end of int64 support */
static const OP_PAT op_ffp_e [32] = { /* patterns for 2100/M/E-Series */
OP_N, OP_AAF, OP_AX, OP_AXX, /* [nop] DBLE SNGL .XMPY */
OP_AXX, OP_AA, OP_A, OP_AAXX, /* .XDIV .DFER .XPAK XADD */
OP_AAXX, OP_AAXX, OP_AAXX, OP_AXX, /* XSUB XMPY XDIV .XADD */
@@ -175,7 +189,7 @@ t_stat cpu_ffp (uint32 IR, uint32 intrq)
OP fpop;
OPS op, op2;
uint32 entry;
uint32 j, sa, sb, sc, da, dc, ra, MA;
HP_WORD j, sa, sb, sc, da, dc, ra, MA;
int32 expon;
t_stat reason = SCPE_OK;
@@ -267,7 +281,7 @@ switch (entry) { /* decode IR<4:0> */
case 000: /* [nop] 105200 (OP_N) */
if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 M/E-series */
return stop_inst; /* trap if not */
return STOP (cpu_ss_unimpl); /* trap if not */
break;
#if defined (HAVE_INT64) /* int64 support available */
@@ -302,7 +316,7 @@ switch (entry) { /* decode IR<4:0> */
case 006: /* .XPAK 105206 (OP_A) */
if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */
return stop_inst; /* trap if not */
return STOP (cpu_ss_unimpl); /* trap if not */
if (intrq) { /* interrupt pending? */
PR = err_PC; /* restart instruction */
@@ -310,7 +324,7 @@ switch (entry) { /* decode IR<4:0> */
}
fpop = ReadOp (op[0].word, fp_x); /* read unpacked */
O = fp_nrpack (&fpop, fpop, (int16) AR, fp_x); /* nrm/rnd/pack mantissa, exponent */
O = fp_nrpack (&fpop, fpop, SEXT16 (AR), fp_x); /* nrm/rnd/pack mantissa, exponent */
WriteOp (op[0].word, fpop, fp_x); /* write result */
break;
@@ -372,7 +386,7 @@ switch (entry) { /* decode IR<4:0> */
case 015: /* .XCOM 105215 (OP_A) */
if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */
return stop_inst; /* trap if not */
return STOP (cpu_ss_unimpl); /* trap if not */
fpop = ReadOp (op[0].word, fp_x); /* read unpacked */
AR = fp_ucom (&fpop, fp_x); /* complement and rtn exp adj */
@@ -381,7 +395,7 @@ switch (entry) { /* decode IR<4:0> */
case 016: /* ..DCM 105216 (OP_A) */
if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */
return stop_inst; /* trap if not */
return STOP (cpu_ss_unimpl); /* trap if not */
if (intrq) { /* interrupt pending? */
PR = err_PC; /* restart instruction */
@@ -395,7 +409,7 @@ switch (entry) { /* decode IR<4:0> */
case 017: /* DDINT 105217 (OP_AAX) */
if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */
return stop_inst; /* trap if not */
return STOP (cpu_ss_unimpl); /* trap if not */
if (intrq) { /* interrupt pending? */
PR = err_PC; /* restart instruction */
@@ -418,7 +432,7 @@ switch (entry) { /* decode IR<4:0> */
goto CFER; /* do transfer */
case 021: /* .GOTO 105221 (OP_AK) */
if ((int16) op[1].word < 1) /* index < 1? */
if (SEXT16 (op[1].word) < 1) /* index < 1? */
op[1].word = 1; /* reset min */
sa = PR + op[1].word - 1; /* point to jump target */
@@ -455,7 +469,7 @@ switch (entry) { /* decode IR<4:0> */
op[2].word - 1) * op2[0].word;
}
AR = (op[0].word + op[1].word * BR) & DMASK; /* return element address */
AR = (op[0].word + op[1].word * BR) & R_MASK; /* return element address */
break;
case 023: /* .ENTR 105223 (OP_A) */
@@ -480,8 +494,8 @@ switch (entry) { /* decode IR<4:0> */
WriteW (da++, MA); /* put addr into formal */
}
AR = (uint16) ra; /* return address */
BR = (uint16) da; /* addr of 1st unused formal */
AR = (HP_WORD) ra; /* return address */
BR = (HP_WORD) da; /* addr of 1st unused formal */
break;
case 024: /* .ENTP 105224 (OP_A) */
@@ -490,10 +504,10 @@ switch (entry) { /* decode IR<4:0> */
case 025: /* .PWR2 105225 (OP_RK) */
if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */
return stop_inst; /* trap if not */
return STOP (cpu_ss_unimpl); /* trap if not */
fp_unpack (&fpop, &expon, op[0], fp_f); /* unpack value */
expon = expon + (int16) (op[1].word); /* multiply by 2**n */
expon = expon + SEXT16 (op[1].word); /* multiply by 2**n */
fp_pack (&fpop, fpop, expon, fp_f); /* repack value */
AR = fpop.fpk[0]; /* return result */
BR = fpop.fpk[1]; /* to A/B registers */
@@ -501,10 +515,10 @@ switch (entry) { /* decode IR<4:0> */
case 026: /* .FLUN 105226 (OP_R) */
if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */
return stop_inst; /* trap if not */
return STOP (cpu_ss_unimpl); /* trap if not */
fp_unpack (&fpop, &expon, op[0], fp_f); /* unpack value */
AR = (int16) expon; /* return expon to A */
AR = expon & R_MASK; /* return expon to A */
BR = fpop.fpk[1]; /* and low mant to B */
break;
@@ -516,12 +530,12 @@ switch (entry) { /* decode IR<4:0> */
do {
WriteW (BR, j); /* write value to address */
j = (j + 1) & DMASK; /* incr value */
j = (j + 1) & D16_MASK; /* incr value */
BR = (BR + 1) & VAMASK; /* incr address */
op[0].word = op[0].word - 1; /* decr count */
if (op[0].word && intrq) { /* more and intr? */
AR = (uint16) sa; /* restore A */
BR = (uint16) sb; /* restore B */
AR = sa; /* restore A */
BR = sb; /* restore B */
PR = err_PC; /* restart instruction */
break;
}
@@ -531,10 +545,10 @@ switch (entry) { /* decode IR<4:0> */
case 030: /* .PACK 105230 (OP_RC) */
if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */
return stop_inst; /* trap if not */
return STOP (cpu_ss_unimpl); /* trap if not */
O = fp_nrpack (&fpop, op[0], /* nrm/rnd/pack value */
(int16) (op[1].word), fp_f);
SEXT16 (op[1].word), fp_f);
AR = fpop.fpk[0]; /* return result */
BR = fpop.fpk[1]; /* to A/B registers */
break;
@@ -542,7 +556,7 @@ switch (entry) { /* decode IR<4:0> */
case 031: /* .CFER 105231 (OP_AA) */
if ((UNIT_CPU_MODEL != UNIT_1000_E) && /* must be 1000 E-series */
(UNIT_CPU_MODEL != UNIT_1000_F)) /* or 1000 F-series */
return stop_inst; /* trap if not */
return STOP (cpu_ss_unimpl); /* trap if not */
BR = op[0].word; /* get destination address */
AR = op[1].word; /* get source address */
@@ -562,8 +576,8 @@ switch (entry) { /* decode IR<4:0> */
}
break;
default: /* others undefined */
reason = stop_inst;
default: /* others unimplemented */
reason = STOP (cpu_ss_unimpl);
}
return reason;
@@ -632,11 +646,6 @@ return reason;
execute the extended-precision multiply/divide, and then fixing the
product to a 32-bit double integer. We simulate these directly with 64-
or 32-bit integer arithmetic.
Additional references:
- 93585A Microcode Source (93585-18002 Rev. 2005)
- 93585A Double Integer Instructions Installation and Reference Manual
(93585-90007)
*/
static const OP_PAT op_dbi[16] = {
@@ -692,7 +701,7 @@ switch (entry) { /* decode IR<3:0> */
if (O)
t = ~SIGN32; /* if overflow, rtn max pos */
else
t = (uint32) (t64 & DMASK32); /* else lower 32 bits of result */
t = (uint32) (t64 & D32_MASK); /* else lower 32 bits of result */
#else /* int64 support unavailable */
@@ -814,14 +823,14 @@ switch (entry) { /* decode IR<3:0> */
op[1].dword = t;
goto DSB; /* continue at .DSB */
default: /* others undefined */
default: /* others unimplemented */
t = (AR << 16) | BR; /* set t for NOP */
reason = stop_inst;
reason = STOP (cpu_ss_unimpl);
}
if (reason == SCPE_OK) { /* if return OK */
AR = (t >> 16) & DMASK; /* break result */
BR = t & DMASK; /* into A and B */
AR = UPPER_WORD (t); /* break result */
BR = LOWER_WORD (t); /* into A and B */
}
return reason;

View File

@@ -1,6 +1,6 @@
/* hp2100_cpu4.c: HP 1000 FPP/SIS
Copyright (c) 2006-2016, J. David Bryan
Copyright (c) 2006-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"),
@@ -25,6 +25,7 @@
CPU4 Floating Point Processor and Scientific Instruction Set
07-Sep-17 JDB Replaced "uint16" cast with "HP_WORD" for FPK assignment
05-Aug-16 JDB Renamed the P register from "PC" to "PR"
24-Dec-14 JDB Added casts for explicit downward conversions
09-May-12 JDB Separated assignments from conditional expressions
@@ -252,7 +253,8 @@ t_stat cpu_fpp (uint32 IR, uint32 intrq)
OP fpop;
OPS op;
OPSIZE op1_prec, op2_prec, rslt_prec, cvt_prec;
uint16 opcode, rtn_addr, stk_ptr;
HP_WORD rtn_addr, stk_ptr;
uint16 opcode;
uint32 entry;
t_stat reason = SCPE_OK;
@@ -314,7 +316,7 @@ switch (entry) { /* decode IR<6:0> */
case 0007: /* [stk] 105007 (OP_A) */
O = 0; /* clear overflow */
stk_ptr = (uint16) PR; /* save ptr to next buf */
stk_ptr = PR; /* save ptr to next buf */
rtn_addr = op[0].word; /* save return address */
while (TRUE) {
@@ -428,8 +430,8 @@ switch (entry) { /* decode IR<6:0> */
case 0134: /* .DDIR 105134 (OP_N) */
return cpu_dbi (0105326, intrq); /* remap to double int handler */
default: /* others undefined */
reason = stop_inst;
default: /* others unimplemented */
reason = STOP (cpu_ss_unimpl);
}
return reason;
@@ -711,7 +713,7 @@ switch (entry) { /* decode IR<3:0> */
op[1].fpk[1] = op[1].fpk[1] | 2; /* set "exponent" to 1 */
}
op[2].fpk[0] = (uint16) exponent;
op[2].fpk[0] = (HP_WORD) exponent;
fp_exec (0120, &op[3], op[2], NOP); /* op3 = FLT(exponent) */
fp_exec (0020, &op[4], op[1], plus_1); /* op4 = op1 - 1.0 */
@@ -1117,8 +1119,8 @@ switch (entry) { /* decode IR<3:0> */
return reason;
default: /* others undefined */
return stop_inst;
default: /* others unimplemented */
return STOP (cpu_ss_unimpl);
}
AR = op[0].fpk[0]; /* save result */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
/* hp2100_cpu7.c: HP 1000 VIS and SIGNAL/1000 microcode
Copyright (c) 2008, Holger Veit
Copyright (c) 2006-2016, J. David Bryan
Copyright (c) 2006-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"),
@@ -26,6 +26,8 @@
CPU7 Vector Instruction Set and SIGNAL firmware
31-Jan-17 JDB Revised to use tprintf and TRACE_OPND for debugging
26-Jan-17 JDB Removed debug parameters from cpu_ema_* routines
05-Aug-16 JDB Renamed the P register from "PC" to "PR"
24-Dec-14 JDB Added casts for explicit downward conversions
18-Mar-13 JDB Moved EMA helper declarations to hp2100_cpu1.h
@@ -62,85 +64,6 @@
static const OP zero = { { 0, 0, 0, 0, 0 } }; /* DEC 0.0D0 */
/* Vector Instruction Set
The VIS provides instructions that operate on one-dimensional arrays of
floating-point values. Both single- and double-precision operations are
supported. VIS uses the F-Series floating-point processor to handle the
floating-point math.
Option implementation by CPU was as follows:
2114 2115 2116 2100 1000-M 1000-E 1000-F
------ ------ ------ ------ ------ ------ ------
N/A N/A N/A N/A N/A N/A 12824A
The routines are mapped to instruction codes as follows:
Single-Precision Double-Precision
Instr. Opcode Subcod Instr. Opcode Subcod Description
------ ------ ------ ------ ------ ------ -----------------------------
VADD 101460 000000 DVADD 105460 004002 Vector add
VSUB 101460 000020 DVSUB 105460 004022 Vector subtract
VMPY 101460 000040 DVMPY 105460 004042 Vector multiply
VDIV 101460 000060 DVDIV 105460 004062 Vector divide
VSAD 101460 000400 DVSAD 105460 004402 Scalar-vector add
VSSB 101460 000420 DVSSB 105460 004422 Scalar-vector subtract
VSMY 101460 000440 DVSMY 105460 004442 Scalar-vector multiply
VSDV 101460 000460 DVSDV 105460 004462 Scalar-vector divide
VPIV 101461 0xxxxx DVPIV 105461 0xxxxx Vector pivot
VABS 101462 0xxxxx DVABS 105462 0xxxxx Vector absolute value
VSUM 101463 0xxxxx DVSUM 105463 0xxxxx Vector sum
VNRM 101464 0xxxxx DVNRM 105464 0xxxxx Vector norm
VDOT 101465 0xxxxx DVDOT 105465 0xxxxx Vector dot product
VMAX 101466 0xxxxx DVMAX 105466 0xxxxx Vector maximum value
VMAB 101467 0xxxxx DVMAB 105467 0xxxxx Vector maximum absolute value
VMIN 101470 0xxxxx DVMIN 105470 0xxxxx Vector minimum value
VMIB 101471 0xxxxx DVMIB 105471 0xxxxx Vector minimum absolute value
VMOV 101472 0xxxxx DVMOV 105472 0xxxxx Vector move
VSWP 101473 0xxxxx DVSWP 105473 0xxxxx Vector swap
.ERES 101474 -- -- -- -- Resolve array element address
.ESEG 101475 -- -- -- -- Load MSEG maps
.VSET 101476 -- -- -- -- Vector setup
[test] -- -- -- 105477 -- [self test]
Instructions use IR bit 11 to select single- or double-precision format. The
double-precision instruction names begin with "D" (e.g., DVADD vs. VADD).
Most VIS instructions are two words in length, with a sub-opcode immediately
following the primary opcode.
Notes:
1. The .VECT (101460) and .DVCT (105460) opcodes preface a single- or
double-precision arithmetic operation that is determined by the
sub-opcode value. The remainder of the dual-precision sub-opcode values
are "don't care," except for requiring a zero in bit 15.
2. The VIS uses the hardware FPP of the F-Series. FPP malfunctions are
detected by the VIS firmware and are indicated by a memory-protect
violation and setting the overflow flag. Under simulation,
malfunctions cannot occur.
Additional references:
- 12824A Vector Instruction Set User's Manual (12824-90001, Jun-1979).
- VIS Microcode Source (12824-18059, revision 3).
*/
static const OP_PAT op_vis[16] = {
OP_N, OP_AAKAKAKK,OP_AKAKK, OP_AAKK, /* .VECT VPIV VABS VSUM */
OP_AAKK, OP_AAKAKK, OP_AAKK, OP_AAKK, /* VNRM VDOT VMAX VMAB */
OP_AAKK, OP_AAKK, OP_AKAKK, OP_AKAKK, /* VMIN VMIB VMOV VSWP */
OP_AA, OP_A, OP_AAACCC,OP_N /* .ERES .ESEG .VSET [test] */
};
static const t_bool op_ftnret[16] = {
FALSE, TRUE, TRUE, TRUE,
TRUE, TRUE, TRUE, TRUE,
TRUE, TRUE, TRUE, TRUE,
FALSE, TRUE, TRUE, FALSE,
};
/* handle the scalar/vector base ops */
static void vis_svop(uint32 subcode, OPS op, OPSIZE opsize)
{
@@ -361,115 +284,200 @@ for (i=0; i<n; i++) {
}
}
/* Vector Instruction Set
The VIS provides instructions that operate on one-dimensional arrays of
floating-point values. Both single- and double-precision operations are
supported. VIS uses the F-Series floating-point processor to handle the
floating-point math.
Option implementation by CPU was as follows:
2114 2115 2116 2100 1000-M 1000-E 1000-F
------ ------ ------ ------ ------ ------ ------
N/A N/A N/A N/A N/A N/A 12824A
The routines are mapped to instruction codes as follows:
Single-Precision Double-Precision
Instr. Opcode Subcod Instr. Opcode Subcod Description
------ ------ ------ ------ ------ ------ -----------------------------
VADD 101460 000000 DVADD 105460 004002 Vector add
VSUB 101460 000020 DVSUB 105460 004022 Vector subtract
VMPY 101460 000040 DVMPY 105460 004042 Vector multiply
VDIV 101460 000060 DVDIV 105460 004062 Vector divide
VSAD 101460 000400 DVSAD 105460 004402 Scalar-vector add
VSSB 101460 000420 DVSSB 105460 004422 Scalar-vector subtract
VSMY 101460 000440 DVSMY 105460 004442 Scalar-vector multiply
VSDV 101460 000460 DVSDV 105460 004462 Scalar-vector divide
VPIV 101461 0xxxxx DVPIV 105461 0xxxxx Vector pivot
VABS 101462 0xxxxx DVABS 105462 0xxxxx Vector absolute value
VSUM 101463 0xxxxx DVSUM 105463 0xxxxx Vector sum
VNRM 101464 0xxxxx DVNRM 105464 0xxxxx Vector norm
VDOT 101465 0xxxxx DVDOT 105465 0xxxxx Vector dot product
VMAX 101466 0xxxxx DVMAX 105466 0xxxxx Vector maximum value
VMAB 101467 0xxxxx DVMAB 105467 0xxxxx Vector maximum absolute value
VMIN 101470 0xxxxx DVMIN 105470 0xxxxx Vector minimum value
VMIB 101471 0xxxxx DVMIB 105471 0xxxxx Vector minimum absolute value
VMOV 101472 0xxxxx DVMOV 105472 0xxxxx Vector move
VSWP 101473 0xxxxx DVSWP 105473 0xxxxx Vector swap
.ERES 101474 -- -- -- -- Resolve array element address
.ESEG 101475 -- -- -- -- Load MSEG maps
.VSET 101476 -- -- -- -- Vector setup
[test] -- -- -- 105477 -- [self test]
Instructions use IR bit 11 to select single- or double-precision format. The
double-precision instruction names begin with "D" (e.g., DVADD vs. VADD).
Most VIS instructions are two words in length, with a sub-opcode immediately
following the primary opcode.
Notes:
1. The .VECT (101460) and .DVCT (105460) opcodes preface a single- or
double-precision arithmetic operation that is determined by the
sub-opcode value. The remainder of the dual-precision sub-opcode values
are "don't care," except for requiring a zero in bit 15.
2. The VIS uses the hardware FPP of the F-Series. FPP malfunctions are
detected by the VIS firmware and are indicated by a memory-protect
violation and setting the overflow flag. Under simulation,
malfunctions cannot occur.
Additional references:
- 12824A Vector Instruction Set User's Manual (12824-90001, Jun-1979).
- VIS Microcode Source (12824-18059, revision 3).
*/
static const OP_PAT op_vis [16] = {
OP_N, OP_AAKAKAKK, OP_AKAKK, OP_AAKK, /* .VECT VPIV VABS VSUM */
OP_AAKK, OP_AAKAKK, OP_AAKK, OP_AAKK, /* VNRM VDOT VMAX VMAB */
OP_AAKK, OP_AAKK, OP_AKAKK, OP_AKAKK, /* VMIN VMIB VMOV VSWP */
OP_AA, OP_A, OP_AAACCC, OP_N /* .ERES .ESEG .VSET [test] */
};
static const t_bool op_ftnret [16] = {
FALSE, TRUE, TRUE, TRUE,
TRUE, TRUE, TRUE, TRUE,
TRUE, TRUE, TRUE, TRUE,
FALSE, TRUE, TRUE, FALSE,
};
t_stat cpu_vis (uint32 IR, uint32 intrq)
{
static const char *const difficulty [2] = { "hard", "easy" };
t_stat reason = SCPE_OK;
OPS op;
OP ret;
uint32 entry, rtn, rtn1 = 0, subcode = 0;
OP_PAT pattern;
OPSIZE opsize;
t_bool debug = DEBUG_PRI (cpu_dev, DEB_VIS);
uint32 entry, subcode;
HP_WORD rtn = 0;
opsize = (IR & 004000) ? fp_t : fp_f; /* double or single precision */
entry = IR & 017; /* mask to entry point */
pattern = op_vis[entry];
pattern = op_vis [entry];
if (entry == 0) { /* retrieve sub opcode */
subcode = ReadF (PR); /* get it */
if (entry==0) { /* retrieve sub opcode */
ret = ReadOp (PR, in_s); /* get it */
subcode = ret.word;
if (subcode & 0100000) /* special property of ucode */
subcode = AR; /* for reentry */
PR = (PR + 1) & VAMASK; /* bump to real argument list */
pattern = (subcode & 0400) ? OP_AAKAKK : OP_AKAKAKK; /* scalar or vector operation */
}
if (pattern != OP_N) {
if (op_ftnret[entry]) { /* most VIS instrs ignore RTN addr */
ret = ReadOp(PR, in_s);
rtn = rtn1 = ret.word; /* but save it just in case */
if (op_ftnret [entry]) { /* most VIS instrs ignore RTN addr */
rtn = ReadF (PR); /* get it */
PR = (PR + 1) & VAMASK; /* move to next argument */
}
reason = cpu_ops (pattern, op, intrq); /* get instruction operands */
if (reason != SCPE_OK) /* evaluation failed? */
return reason; /* return reason for failure */
}
if (debug) { /* debugging? */
fprintf (sim_deb, ">>CPU VIS: IR = %06o/%06o (", /* print preamble and IR */
IR, subcode);
fprint_sym (sim_deb, err_PC, (t_value *) &IR, /* print instruction mnemonic */
NULL, SWMASK('M'));
fprintf (sim_deb, "), P = %06o", err_PC); /* print location */
fprint_ops (pattern, op); /* print operands */
fputc ('\n', sim_deb); /* terminate line */
}
switch (entry) { /* decode IR<3:0> */
case 000: /* .VECT (OP_special) */
if (subcode & 0400)
vis_svop(subcode,op,opsize); /* scalar/vector op */
else
vis_vvop(subcode,op,opsize); /* vector/vector op */
break;
case 001: /* VPIV (OP_(A)AAKAKAKK) */
vis_vpiv(op,opsize);
break;
case 002: /* VABS (OP_(A)AKAKK) */
vis_vabs(op,opsize);
break;
case 003: /* VSUM (OP_(A)AAKK) */
vis_vsmnm(op,opsize,FALSE);
break;
case 004: /* VNRM (OP_(A)AAKK) */
vis_vsmnm(op,opsize,TRUE);
break;
case 005: /* VDOT (OP_(A)AAKAKK) */
vis_vdot(op,opsize);
break;
case 006: /* VMAX (OP_(A)AAKK) */
vis_minmax(op,opsize,TRUE,FALSE);
break;
case 007: /* VMAB (OP_(A)AAKK) */
vis_minmax(op,opsize,TRUE,TRUE);
break;
case 010: /* VMIN (OP_(A)AAKK) */
vis_minmax(op,opsize,FALSE,FALSE);
break;
case 011: /* VMIB (OP_(A)AAKK) */
vis_minmax(op,opsize,FALSE,TRUE);
break;
case 012: /* VMOV (OP_(A)AKAKK) */
vis_movswp(op,opsize,FALSE);
break;
case 013: /* VSWP (OP_(A)AKAKK) */
vis_movswp(op,opsize,TRUE);
break;
case 014: /* .ERES (OP_(A)AA) */
reason = cpu_ema_eres(&rtn,op[2].word,PR,debug); /* handle the ERES instruction */
PR = rtn;
if (debug)
fprintf (sim_deb,
">>CPU VIS: return .ERES: AR = %06o, BR = %06o, rtn=%s\n",
AR, BR, PR==op[0].word ? "error" : "good");
reason = cpu_ema_eres(&PR,op[2].word,PR); /* handle the ERES instruction */
tprintf (cpu_dev, TRACE_OPND, OPND_FORMAT " return location is P+%u (%s)\n",
PR, IR, PR - err_PC, fmt_ab (PR - rtn));
break;
case 015: /* .ESEG (OP_(A)A) */
reason = cpu_ema_eseg(&rtn,IR,op[0].word,debug); /* handle the ESEG instruction */
PR = rtn;
if (debug)
fprintf (sim_deb,
">>CPU VIS: return .ESEG: AR = %06o , BR = %06o, rtn=%s\n",
AR, BR, rtn==rtn1 ? "error" : "good");
reason = cpu_ema_eseg(&PR,IR,op[0].word); /* handle the ESEG instruction */
tprintf (cpu_dev, TRACE_OPND, OPND_FORMAT " return location is P+%u (%s)\n",
PR, IR, PR - err_PC, fmt_ab (PR - rtn));
break;
case 016: /* .VSET (OP_(A)AAACCC) */
reason = cpu_ema_vset(&rtn,op,debug);
PR = rtn;
if (debug)
fprintf (sim_deb, ">>CPU VIS: return .VSET: AR = %06o BR = %06o, rtn=%s\n",
AR, BR,
rtn==rtn1 ? "error" : (rtn==(rtn1+1) ? "hard" : "easy") );
reason = cpu_ema_vset(&PR,op);
tprintf (cpu_dev, TRACE_OPND, OPND_FORMAT " return location is P+%u (%s)\n",
PR, IR, PR - err_PC,
(PR == rtn
? fmt_ab (0)
: difficulty [PR - rtn - 1]));
break;
case 017: /* [test] (OP_N) */
@@ -477,66 +485,20 @@ switch (entry) { /* decode IR<3:0> */
SR = 0102077; /* test passed code */
PR = (PR + 1) & VAMASK; /* P+2 return for firmware w/VIS */
break;
default: /* others undefined */
reason = stop_inst;
}
default: /* others unimplemented */
reason = STOP (cpu_ss_unimpl);
}
return reason;
}
/* SIGNAL/1000 Instructions
The SIGNAL/1000 instructions provide fast Fourier transforms and complex
arithmetic. They utilize the F-Series floating-point processor and the
Vector Instruction Set.
Option implementation by CPU was as follows:
2114 2115 2116 2100 1000-M 1000-E 1000-F
------ ------ ------ ------ ------ ------ ------
N/A N/A N/A N/A N/A N/A 92835A
The routines are mapped to instruction codes as follows:
Instr. 1000-F Description
------ ------ ----------------------------------------------
BITRV 105600 Bit reversal
BTRFY 105601 Butterfly algorithm
UNSCR 105602 Unscramble for phasor MPY
PRSCR 105603 Unscramble for phasor MPY
BITR1 105604 Swap two elements in array (alternate format)
BTRF1 105605 Butterfly algorithm (alternate format)
.CADD 105606 Complex number addition
.CSUB 105607 Complex number subtraction
.CMPY 105610 Complex number multiplication
.CDIV 105611 Complex number division
CONJG 105612 Complex conjugate
..CCM 105613 Complex complement
AIMAG 105614 Return imaginary part
CMPLX 105615 Form complex number
[nop] 105616 [no operation]
[test] 105617 [self test]
Notes:
1. SIGNAL/1000 ROM data are available from Bitsavers.
Additional references (documents unavailable):
- HP Signal/1000 User Reference and Installation Manual (92835-90002).
- SIGNAL/1000 Microcode Source (92835-18075, revision 2).
*/
/* SIGNAL/1000 routines */
#define RE(x) (x+0)
#define IM(x) (x+2)
static const OP_PAT op_signal[16] = {
OP_AAKK, OP_AAFFKK, OP_AAFFKK,OP_AAFFKK, /* BITRV BTRFY UNSCR PRSCR */
OP_AAAKK, OP_AAAFFKK,OP_AAA, OP_AAA, /* BITR1 BTRF1 .CADD .CSUB */
OP_AAA, OP_AAA, OP_AAA, OP_A, /* .CMPY .CDIV CONJG ..CCM */
OP_AA, OP_AAFF, OP_N, OP_N /* AIMAG CMPLX --- [test]*/
};
/* complex addition helper */
static void sig_caddsub(uint16 addsub,OPS op)
{
@@ -641,6 +603,56 @@ OP p;
(void)fp_exec(004, i, p, NOP); /* imag := ad+bc */
}
/* SIGNAL/1000 Instructions
The SIGNAL/1000 instructions provide fast Fourier transforms and complex
arithmetic. They utilize the F-Series floating-point processor and the
Vector Instruction Set.
Option implementation by CPU was as follows:
2114 2115 2116 2100 1000-M 1000-E 1000-F
------ ------ ------ ------ ------ ------ ------
N/A N/A N/A N/A N/A N/A 92835A
The routines are mapped to instruction codes as follows:
Instr. 1000-F Description
------ ------ ----------------------------------------------
BITRV 105600 Bit reversal
BTRFY 105601 Butterfly algorithm
UNSCR 105602 Unscramble for phasor MPY
PRSCR 105603 Unscramble for phasor MPY
BITR1 105604 Swap two elements in array (alternate format)
BTRF1 105605 Butterfly algorithm (alternate format)
.CADD 105606 Complex number addition
.CSUB 105607 Complex number subtraction
.CMPY 105610 Complex number multiplication
.CDIV 105611 Complex number division
CONJG 105612 Complex conjugate
..CCM 105613 Complex complement
AIMAG 105614 Return imaginary part
CMPLX 105615 Form complex number
[nop] 105616 [no operation]
[test] 105617 [self test]
Notes:
1. SIGNAL/1000 ROM data are available from Bitsavers.
Additional references (documents unavailable):
- HP Signal/1000 User Reference and Installation Manual (92835-90002).
- SIGNAL/1000 Microcode Source (92835-18075, revision 2).
*/
static const OP_PAT op_signal [16] = {
OP_AAKK, OP_AAFFKK, OP_AAFFKK, OP_AAFFKK, /* BITRV BTRFY UNSCR PRSCR */
OP_AAAKK, OP_AAAFFKK, OP_AAA, OP_AAA, /* BITR1 BTRF1 .CADD .CSUB */
OP_AAA, OP_AAA, OP_AAA, OP_A, /* .CMPY .CDIV CONJG ..CCM */
OP_AA, OP_AAFF, OP_N, OP_N /* AIMAG CMPLX --- [test]*/
};
t_stat cpu_signal (uint32 IR, uint32 intrq)
{
t_stat reason = SCPE_OK;
@@ -649,8 +661,6 @@ OP a,b,c,d,p1,p2,p3,p4,m1,m2,wr,wi;
uint32 entry, v, idx1, idx2;
int32 exc, exd;
t_bool debug = DEBUG_PRI (cpu_dev, DEB_SIG);
entry = IR & 017; /* mask to entry point */
if (op_signal [entry] != OP_N) {
@@ -659,15 +669,6 @@ if (op_signal [entry] != OP_N) {
return reason; /* return reason for failure */
}
if (debug) { /* debugging? */
fprintf (sim_deb, ">>CPU SIG: IR = %06o (", IR); /* print preamble and IR */
fprint_sym (sim_deb, err_PC, (t_value *) &IR, /* print instruction mnemonic */
NULL, SWMASK('M'));
fprintf (sim_deb, "), P = %06o", err_PC); /* print location */
fprint_ops (op_signal[entry], op); /* print operands */
fputc ('\n', sim_deb); /* terminate line */
}
switch (entry) { /* decode IR<3:0> */
case 000: /* BITRV (OP_AAKK) */
/* BITRV
@@ -933,8 +934,8 @@ switch (entry) { /* decode IR<3:0> */
break;
case 016: /* invalid */
default: /* others undefined */
reason = stop_inst;
default: /* others unimplemented */
reason = STOP (cpu_ss_unimpl);
}
return reason;

View File

@@ -1,29 +1,43 @@
/* hp2100_defs.h: HP 2100 System architectural declarations
Copyright (c) 1993-2016, Robert M. Supnik
Copyright (c) 2017 J. David Bryan
Copyright (c) 2017-2018 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 in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
Except as contained in this notice, the names of the authors shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from the authors.
07-May-18 JDB Added NOTE_SKIP, simplified setSKF macro
02-May-18 JDB Added "SIRDEV" for first device to receive the SIR signal
16-Oct-17 JDB Suppressed logical-not-parentheses warning on clang
30-Aug-17 JDB Replaced POLL_WAIT with POLL_PERIOD
07-Aug-17 JDB Added "hp_attach"
20-Jul-17 JDB Removed STOP_OFFLINE, STOP_PWROFF stop codes
11-Jul-17 JDB Moved "ibl_copy" to hp2100_cpu.h
26-Jun-17 JDB Moved I/O instruction subopcode constants to hp2100_cpu.c
14-Jun-17 JDB Renamed STOP_RSRV to STOP_UNIMPL (unimplemented instruction)
15-Mar-17 JDB Added global trace flags
27-Feb-17 JDB ibl_copy no longer returns a status code
15-Feb-17 JDB Deleted unneeded guard macro definition
16-Jan-17 JDB Added tracing and console output macros
13-Jan-17 JDB Added fprint_cpu
10-Jan-17 JDB Added architectural constants
05-Aug-16 JDB Removed PC_Global renaming; P register is now "PR"
13-May-16 JDB Modified for revised SCP API function parameter types
@@ -150,9 +164,6 @@
*/
#ifndef HP2100_DEFS_H_
#define HP2100_DEFS_H_ 0
#include "sim_rev.h"
#include "sim_defs.h"
@@ -177,6 +188,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"
@@ -188,18 +200,143 @@
#endif
/* Simulator stop and notification codes */
/* Device register display mode flags */
#define STOP_RSRV 1 /* must be 1 */
#define STOP_IODV 2 /* must be 2 */
#define STOP_HALT 3 /* HALT */
#define STOP_IBKPT 4 /* breakpoint */
#define STOP_IND 5 /* indirect loop */
#define NOTE_INDINT 6 /* indirect intr */
#define STOP_NOCONN 7 /* no connection */
#define STOP_OFFLINE 8 /* device offline */
#define STOP_PWROFF 9 /* device powered off */
#define NOTE_IOG 10 /* I/O instr executed */
#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) */
/* Global tracing flags.
Global tracing flags are allocated in descending order, as they may be used
by modules that allocate their own private flags in ascending order. No
check is made for overlapping values.
*/
#define TRACE_CMD (1u << 31) /* trace interface or controller commands */
#define TRACE_INCO (1u << 30) /* trace interface or controller command initiations and completions */
#define TRACE_CSRW (1u << 29) /* trace interface control, status, read, and write actions */
#define TRACE_STATE (1u << 28) /* trace state changes */
#define TRACE_SERV (1u << 27) /* trace unit service scheduling calls and entries */
#define TRACE_PSERV (1u << 26) /* trace periodic unit service scheduling calls and entries */
#define TRACE_XFER (1u << 25) /* trace data receptions and transmissions */
#define TRACE_IOBUS (1u << 24) /* trace I/O bus signals and data words received and returned */
#define DEB_CMDS (1u << 23) /* (old) trace command initiations and completions */
#define DEB_CPU (1u << 22) /* (old) trace words received from and sent to the CPU */
#define DEB_BUF (1u << 21) /* (old) trace data read from and written to the FIFO */
#define DEB_XFER (1u << 20) /* (old) trace data receptions and transmissions */
#define DEB_RWS (1u << 19) /* (old) trace tape reads, writes, and status returns */
#define DEB_RWSC (1u << 18) /* (old) trace disc read/write/status/control commands */
#define DEB_SERV (1u << 17) /* (old) trace unit service scheduling calls and entries */
/* Tracing and console output.
"tprintf" is used to write tracing messages. It does an "fprintf" to the
debug output stream if the stream is open and the trace "flag" is currently
enabled in device "dev". Otherwise, it's a NOP. "..." is the format string
and associated values.
"tpprintf" is identical to "tprintf", except that a device pointer is passed
instead of a device structure.
"TRACING" and "TRACINGP" implement the test conditions for device and device
pointer tracing, respectively. They are used explicitly only when several
trace statements employing the same flag are required, and it is desirable to
avoid repeating the stream and flag test for each one.
"cprintf", "cputs", and "cputc" are used to write messages to the console
and, if console logging is enabled, to the log output stream. They do
"(f)printf", "fputs", or "(f)putc", respectively. "..." is the format string
and associated values, "str" is the string to write, and "ch" is the
character to write.
Implementation notes:
1. The "cputs" macro uses "fputs" for both console and log file output
because "puts" appends a newline, whereas "fputs" does not.
*/
#define TRACING(d,f) (sim_deb != NULL && ((d).dctrl & (f)))
#define TRACINGP(d,f) (sim_deb != NULL && ((d)->dctrl & (f)))
#define tprintf(dev, flag, ...) \
if (TRACING (dev, flag)) \
hp_trace (&(dev), (flag), __VA_ARGS__); \
else \
(void) 0
#define tpprintf(dptr, flag, ...) \
if (TRACINGP (dptr, flag)) \
hp_trace ((dptr), (flag), __VA_ARGS__); \
else \
(void) 0
#define cprintf(...) \
do { \
printf (__VA_ARGS__); \
if (sim_log) \
fprintf (sim_log, __VA_ARGS__); \
} \
while (0)
#define cputs(str) \
do { \
fputs (str, stdout); \
if (sim_log) \
fputs (str, sim_log); \
} \
while (0)
#define cputc(ch) \
do { \
putc (ch); \
if (sim_log) \
fputc (ch, sim_log); \
} \
while (0)
/* Simulation stop and notification codes.
The STOP_* status codes stop the simulator. The "sim_stop_messages" array in
"hp2100_sys.c" contains the message strings that correspond one-for-one with
the stop codes.
The NOTE_* status codes do not stop the simulator. Instead, they inform the
instruction execution loop of special situations that occurred while
processing the current machine instruction..
Implementation notes:
1. Codes before STOP_RERUN cause the instruction to be rerun, so P is backed
up twice. For codes after, P points to the next instruction to be
executed (which is the current instruction for an infinite loop stop).
*/
#define STOP_UNIMPL 1 /* unimplemented instruction stop */
#define STOP_UNSC 2 /* stop on I/O to an unassigned select code */
#define STOP_UNDEF 3 /* undefined instruction stop */
#define STOP_INDIR 4 /* stop on an indirect loop */
#define STOP_RERUN 4 /* stops above here cause the instruction to be re-run */
#define STOP_HALT 5 /* programmed halt */
#define STOP_BRKPNT 6 /* breakpoint */
#define STOP_NOCONN 7 /* no connection */
#define STOP_NOTAPE 8 /* no tape */
#define STOP_EOT 9 /* end of tape */
#define NOTE_IOG 10 /* an I/O instruction was executed */
#define NOTE_INDINT 11 /* an interrupt occurred while resolving an indirect address */
#define NOTE_SKIP 12 /* the SKF signal was asserted by an I/O interface */
/* Modifier validation identifiers */
@@ -208,6 +345,54 @@
#define MTAB_XUN (MTAB_XTD | MTAB_VUN)
/* I/O event timing.
I/O events are scheduled for future service by specifying the desired delay
in units of event ticks. Typically, one event tick represents the execution
of one CPU instruction, and this is the way event ticks are defined in the
current simulator implementation. However, the various CPUs themselves not
only vary in speed, but the actual instruction times vary greatly, due to the
presence of block move, compare, and scan instructions. Variations of an
order of magnitude are common, and two orders or more are possible for longer
blocks.
The 24296-90001 Diagnostic Configurator provides a one millisecond timer for
use by the diagnostic programs. The timer is a two-instruction software
loop, plus four instructions of entry/exit overhead, based on the processor
type. The values provided are:
Loop Instr
CPU Count /msec
------ ----- -----
2114 246 496
2115 246 496
2116 309 622
2100 252 508
1000-M 203 410
1000-E 1573 * 1577
* The E-Series TIMER instruction is used instead of a software loop. TIMER
re-executes an internal decrement until the supplied value reaches zero.
To pass diagnostics that time peripheral operations, the simulator assumes
the E-Series execution rate for all devices (0.634 microseconds per event
tick), although this results in needlessly long delays for normal operation.
A correct implementation would change the timing base depending on the
currently selected CPU.
To accommodate possible future variable instruction timing, I/O service
activation times must not assume a constant 0.634 microseconds per event
tick. Delays should be defined in terms of the "uS" (microseconds), "mS"
(milliseconds), and "S" (seconds) macros below.
*/
#define USEC_PER_EVENT 0.634 /* average CPU instruction time in microseconds */
#define uS(t) (uint32) ((t) > USEC_PER_EVENT ? (t) / USEC_PER_EVENT + 0.5 : 1)
#define mS(t) (uint32) (((t) * 1000.0) / USEC_PER_EVENT + 0.5)
#define S(t) (uint32) (((t) * 1000000.0) / USEC_PER_EVENT + 0.5)
/* Architectural constants.
These macros specify the width, sign location, value mask, and minimum and
@@ -217,11 +402,52 @@
The HP_WORD type is used to declare variables that represent 16-bit registers
or buses in hardware.
Implementation notes:
1. The HP_WORD type is a 32-bit unsigned type, instead of the more logical
16-bit unsigned type. There are two reasons for this. First, SCP
requires that scalars referenced by REG (register) entries be 32 bits in
size. Second, IA-32 processors execute instructions with 32-bit operands
much faster than those with 16-bit operands.
Using 16-bit operands omits the masking required for 32-bit values. For
example, the code generated for the following operations is as follows:
uint16 a, b, c;
a = b + c & 0xFFFF;
movzwl _b, %eax
addw _c, %ax
movw %ax, _a
uint32 x, y, z;
x = y + z & 0xFFFF;
movl _z, %eax
addl _y, %eax
andl $65535, %eax
movl %eax, _x
However, the first case uses operand override prefixes, which require
substantially more time to decode (6 clock cycles vs. 1 clock cycle).
This time outweighs the additional 32-bit AND instruction, which executes
in 1 clock cycle.
2. The MEMORY_WORD type is a 16-bit unsigned type, corresponding with the
16-bit main memory in the HP 21xx/1000. Unlike the general data type,
which is a 32-bit type for speed, main memory does not benefit from the
faster 32-bit execution on IA-32 processors, as only one instruction in
the mem_read and mem_write routines has an operand override that invokes
the slower instruction fetch path. There is a negligible difference in
the Memory Pattern Test diagnostic execution speeds for the uint32 vs.
uint16 definition, whereas the VM requirements are doubled for the
former.
*/
typedef uint16 HP_WORD; /* HP 16-bit data word representation */
#define R_MASK 0177777u /* 16-bit register mask */
typedef uint32 HP_WORD; /* HP 16-bit data word representation */
typedef uint16 MEMORY_WORD; /* HP 16-bit memory word representation */
#define D4_WIDTH 4 /* 4-bit data bit width */
#define D4_MASK 0017u /* 4-bit data mask */
@@ -267,6 +493,11 @@ typedef uint16 HP_WORD; /* HP 16-bit data word r
#define S32_OVFL_MASK ((t_uint64) D32_UMAX << D32_WIDTH | \
D32_SIGN) /* 32-bit signed overflow mask */
#define LSB 1u /* least-significant bit */
#define D16_SIGN_LSB (D16_SIGN | LSB) /* bit 15 and bit 0 */
#define R_MASK 0177777u /* 16-bit register mask */
/* Memory constants */
@@ -293,6 +524,40 @@ typedef uint16 HP_WORD; /* HP 16-bit data word r
#define DV_SMAX ((1u << (DV_WIDTH - 1)) - 1) /* data value signed maximum (2 ** 15 - 1) */
/* Memory address macros.
These macros convert between logical and physical addresses. The functions
provided are:
- PAGE -- extract the page number part of a physical address
- OFFSET -- extract the offset part of a physical address
- TO_PA -- merge a page number and offset into a physical address
*/
#define PAGE(p) ((p) >> PG_WIDTH & PG_MASK)
#define OFFSET(p) ((p) & OF_MASK)
#define TO_PA(b,o) (((uint32) (b) & PG_MASK) << PG_WIDTH | (uint32) (o) & OF_MASK)
/* Memory access classifications.
The access classification determines the DMS map set and protections to use
when reading or writing memory words. The classification also is used to
label each data access when tracing is enabled. When DMS is disabled, or
when the CPU is one of the 21xx models, the classification is irrelevant.
*/
typedef enum {
Fetch, /* instruction fetch, current map */
Data, /* data access, current map */
Data_Alternate, /* data access, alternate map */
Data_System, /* data access, system map */
Data_User, /* data access, user map */
DMA_Channel_1, /* DMA channel 1, port A map */
DMA_Channel_2 /* DMA channel 2, port B map */
} ACCESS_CLASS;
/* Portable conversions.
SIMH is written with the assumption that the defined-size types (e.g.,
@@ -302,28 +567,28 @@ typedef uint16 HP_WORD; /* HP 16-bit data word r
negative_value_32 = (int32) negative_value_16;
...will not guarantee that bits 0-15 of "negative_value_32" are ones, whereas
the supplied sign-extension macro will.
...will not guarantee that the upper 16 bits of "negative_value_32" are all
ones, whereas the supplied sign-extension macro will.
The conversions available are:
- SEXT8 -- int8 sign-extended to int32
- SEXT16 -- int16 sign-extended to int32
- NEG16 -- int8 negated
- NEG16 -- int16 negated
- NEG32 -- int32 negated
- SEXT8 -- signed 8-bit value sign-extended to int32
- SEXT16 -- signed 16-bit value sign-extended to int32
- NEG8 -- signed 8-bit value negated
- NEG16 -- signed 16-bit value negated
- NEG32 -- signed 32-bit value negated
- INT16 -- uint16 to int16
- INT32 -- uint32 to int32
Implementation notes:
1. The routines assume that 16-bit values are masked to exactly 16 bits
before invoking.
1. The SEXTn and INTn routines assume that their values are masked to
exactly n bits before invoking.
*/
#define SEXT8(x) (int32) ((x) & D8_SIGN ? (x) | ~D8_MASK : (x))
#define SEXT16(x) (int32) ((x) & D16_SIGN ? (x) | ~D16_MASK : (x))
#define SEXT8(x) ((int32) ((x) & D8_SIGN ? (x) | ~D8_MASK : (x)))
#define SEXT16(x) ((int32) ((x) & D16_SIGN ? (x) | ~D16_MASK : (x)))
#define NEG8(x) ((~(x) + 1) & D8_MASK)
#define NEG16(x) ((~(x) + 1) & D16_MASK)
@@ -371,12 +636,43 @@ typedef enum {
#define TO_DWORD(u,l) ((uint32) (u) << D16_WIDTH | (l))
/* Portable conversions (sign-extension, unsigned-to-signed) */
/* CPU instruction symbolic source.
#define SEXT(x) ((int32) (((x) & SIGN)? ((x) | ~DMASK): ((x) & DMASK)))
The memory-reference group (MRG) instructions do not specify full logical
addresses of their targets. Instead, they specify offsets from either the
base page or the current page. Instructions specifying base-page offsets are
always displayed with target addresses between 0000-1777. The display and
parsing of instructions specifying current-page offsets depends on the source
of the instructions.
If the current-page CPU instruction is contained in main memory, the current
page is taken from the address of the word containing the instruction, and
the full target address between 00000-77777 is displayed or parsed. However,
if the instruction is contained in a device buffer, e.g., a disc drive sector
buffer, the destination memory address is unknown until the instruction is
transferred to memory. In this case, the target address is displayed or
parsed as the offset prefixed with the letter "C" (e.g., "LDA C 1200"). In
order to present the proper symbolic behavior, the mnemonic formatter and
parser must know the source of the request.
Additionally, display requests from the EXAMINE command have preloaded a
value array with the maximum number of words required to encode the longest
instruction. This is inefficient, as only a fraction of the instruction set
requires more than one word. For EXAMINE commands entered by the user at the
SCP prompt, this is unimportant. However, for calls from the CPU instruction
trace routine, the overhead is significant. In the latter case, the array is
loaded only with a single word, and the mnemonic formatter loads additional
words if the specific instruction to be displayed requires them.
*/
typedef enum {
Device_Symbol, /* called for an EXAMINE <device> or DEPOSIT <device> command */
CPU_Symbol, /* called for an EXAMINE CPU or DEPOSIT CPU command */
CPU_Trace /* called for a CPU trace command */
} SYMBOL_SOURCE;
/* Memory */
/* Memory constants (deprecated) */
#define MEMSIZE (cpu_unit.capac) /* actual memory size */
#define VA_N_SIZE 15 /* virtual addr size */
@@ -386,7 +682,7 @@ typedef enum {
#define PASIZE (1 << PA_N_SIZE)
#define PAMASK (PASIZE - 1) /* phys addr mask */
/* Architectural constants */
/* Architectural constants (deprecated) */
#define SIGN32 020000000000 /* 32b sign */
#define DMASK32 037777777777 /* 32b data mask/maximum value */
@@ -403,20 +699,10 @@ typedef enum {
#define POLL_RATE 100 /* poll 100 times per second */
#define POLL_FIRST 1 /* first poll is "immediate" */
#define POLL_WAIT 15800 /* initial poll ~ 10 msec. */
#define POLL_PERIOD mS (10) /* 10 millisecond poll period */
typedef enum { INITIAL, SERVICE } POLLMODE; /* poll synchronization modes */
/* I/O instruction sub-opcodes */
#define soHLT 0 /* halt */
#define soFLG 1 /* set/clear flag */
#define soSFC 2 /* skip on flag clear */
#define soSFS 3 /* skip on flag set */
#define soMIX 4 /* merge into A/B */
#define soLIX 5 /* load into A/B */
#define soOTX 6 /* output from A/B */
#define soCTL 7 /* set/clear control */
/* I/O devices - fixed select code assignments */
@@ -460,37 +746,11 @@ typedef enum { INITIAL, SERVICE } POLLMODE; /* poll synchronization
#define DI_DC 044 /* 12821A Disc Interface with CS/80 disc and tape devices */
#define OPTDEV 002 /* start of optional devices */
#define SIRDEV 004 /* start of devices that receive SIR */
#define CRSDEV 006 /* start of devices that receive CRS */
#define VARDEV 010 /* start of variable assignments */
#define MAXDEV 077 /* end of select code range */
/* IBL assignments */
#define IBL_V_SEL 14 /* ROM select <15:14> */
#define IBL_M_SEL 03
#define IBL_PTR 0000000 /* ROM 0: 12992K paper tape reader (PTR) */
#define IBL_DP 0040000 /* ROM 1: 12992A 7900 disc (DP) */
#define IBL_DQ 0060000 /* ROM 1: 12992A 2883 disc (DQ) */
#define IBL_MS 0100000 /* ROM 2: 12992D 7970 tape (MS) */
#define IBL_DS 0140000 /* ROM 3: 12992B 7905/06/20/25 disc (DS) */
#define IBL_MAN 0010000 /* RPL/manual boot <13:12> */
#define IBL_V_DEV 6 /* select code <11:6> */
#define IBL_OPT 0000070 /* options in <5:3> */
#define IBL_DP_REM 0000001 /* DP removable <0:0> */
#define IBL_DS_HEAD 0000003 /* DS head number <1:0> */
#define IBL_LNT 64 /* boot ROM length in words */
#define IBL_MASK (IBL_LNT - 1) /* boot length mask */
#define IBL_DPC (IBL_LNT - 2) /* DMA ctrl word */
#define IBL_END (IBL_LNT - 1) /* last location */
#define IBL_S_CLR 0000000 /* ibl_copy mask to clear the S register */
#define IBL_S_NOCLR 0177777 /* ibl_copy mask to preserve the S register */
#define IBL_S_NOSET 0000000 /* ibl_copy mask to preserve the S register */
#define IBL_SET_SC(s) ((s) << IBL_V_DEV) /* position the select code in the S register */
typedef uint16 BOOT_ROM [IBL_LNT]; /* boot ROM data */
/* I/O backplane signals.
@@ -526,9 +786,9 @@ typedef uint16 BOOT_ROM [IBL_LNT]; /* boot ROM data */
2. The ioSKF signal is never sent to an I/O handler. Rather, it is returned
from the handler if the SFC or SFS condition is true. If the condition
is false, ioNONE is returned instead. As these two values are returned
in the 16-bit data portion of the returned value, their assigned values
must be <= 100000 octal.
is false, ioNONE is returned instead. As the ioSKF value is returned in
the upper 16 bits of the returned value, its assigned value must be >=
200000 octal.
3. An I/O handler will receive ioCRS as a result of a CLC 0 instruction,
ioPOPIO and ioCRS as a result of a RESET command, and ioPON, ioPOPIO, and
@@ -563,21 +823,22 @@ typedef enum { ioNONE = 0000000, /* -- -- -- -- -- no sig
ioIOI = 0000004, /* -- -- T4 T5 -- I/O data input (CPU)
T2 T3 -- -- -- I/O data input (DMA) */
ioIOO = 0000010, /* -- T3 T4 -- -- I/O data output */
ioSKF = 0000020, /* -- T3 T4 T5 -- skip on flag */
ioSFS = 0000040, /* -- T3 T4 T5 -- skip if flag is set */
ioSFC = 0000100, /* -- T3 T4 T5 -- skip if flag is clear */
ioSTC = 0000200, /* -- -- T4 -- -- set control flip-flop (CPU)
ioSFS = 0000020, /* -- T3 T4 T5 -- skip if flag is set */
ioSFC = 0000040, /* -- T3 T4 T5 -- skip if flag is clear */
ioSTC = 0000100, /* -- -- T4 -- -- set control flip-flop (CPU)
-- T3 -- -- -- set control flip-flop (DMA) */
ioCLC = 0000400, /* -- -- T4 -- -- clear control flip-flop (CPU)
ioCLC = 0000200, /* -- -- T4 -- -- clear control flip-flop (CPU)
-- T3 T4 -- -- clear control flip-flop (DMA) */
ioSTF = 0001000, /* -- T3 -- -- -- set flag flip-flop */
ioCLF = 0002000, /* -- -- T4 -- -- clear flag flip-flop (CPU)
ioSTF = 0000400, /* -- T3 -- -- -- set flag flip-flop */
ioCLF = 0001000, /* -- -- T4 -- -- clear flag flip-flop (CPU)
-- T3 -- -- -- clear flag flip-flop (DMA) */
ioEDT = 0004000, /* -- -- T4 -- -- end data transfer */
ioCRS = 0010000, /* -- -- -- T5 -- control reset */
ioPOPIO = 0020000, /* -- -- -- T5 -- power-on preset to I/O */
ioIAK = 0040000, /* -- -- -- -- T6 interrupt acknowledge */
ioSIR = 0100000 } IOSIGNAL; /* -- -- -- T5 -- set interrupt request */
ioEDT = 0002000, /* -- -- T4 -- -- end data transfer */
ioCRS = 0004000, /* -- -- -- T5 -- control reset */
ioPOPIO = 0010000, /* -- -- -- T5 -- power-on preset to I/O */
ioIAK = 0020000, /* -- -- -- -- T6 interrupt acknowledge */
ioSIR = 0040000, /* -- -- -- T5 -- set interrupt request */
ioSKF = 0200000 } IOSIGNAL; /* -- T3 T4 T5 -- skip on flag */
typedef uint32 IOCYCLE; /* a set of signals forming one I/O cycle */
@@ -599,20 +860,50 @@ typedef enum {
#define D_FF(b) (FLIP_FLOP) ((b) != 0) /* use a Boolean expression for a D flip-flop */
/* I/O structures */
/* I/O structures.
typedef struct dib DIB; /* incomplete definition */
The Device Information Block (DIB) allows devices to be relocated in the
machine's I/O space. Each DIB contains a pointer to the device interface
routine, a value corresponding to the location of the interface card in the
CPU's I/O card cage (which determines the card's select code), and a card
index if the interface routine services multiple cards.
typedef uint32 IOHANDLER (DIB *dibptr, /* I/O signal handler prototype */
IOCYCLE signal_set,
uint32 stat_data);
struct dib { /* Device information block */
IOHANDLER *io_handler; /* pointer to device's I/O signal handler */
uint32 select_code; /* device's select code */
uint32 card_index; /* device's card index for state variables */
Implementation notes:
1. The select_code and card_index fields could be smaller than the defined
32-bit sizes, but IA-32 processors execute instructions with 32-bit
operands much faster than those with 16- or 8-bit operands.
2. The DIB_REGS macro provides hidden register entries needed to save and
restore the state of a DIB. Only the potentially variable fields are
referenced. In particular, the "io_interface" field must not be saved,
as the address of the device's interface routine may change from version
to version of the simulator.
*/
#define SC_MAX 077 /* the maximum select code */
#define SC_MASK 077u /* the mask for the select code */
#define SC_BASE 8 /* the radix for the select code */
typedef struct dib DIB; /* an incomplete definition */
typedef uint32 IOHANDLER /* the I/O device interface function prototype */
(DIB *dibptr, /* a pointer to the device information block */
IOCYCLE signal_set, /* a set of inbound signals */
uint32 stat_data); /* a 32-bit inbound value */
struct dib { /* the Device Information Block */
IOHANDLER *io_handler; /* the device's I/O interface function pointer */
uint32 select_code; /* the device's select code (02-77) */
uint32 card_index; /* the card index if multiple interfaces are supported */
};
#define DIB_REGS(dib) \
/* Macro Name Location Width Flags */ \
/* ------ ------- -------------------------- ----- ----------------- */ \
{ ORDATA (DIBSC, dib.select_code, 32), PV_LEFT | REG_HRO }
/* I/O signal and status macros.
@@ -654,12 +945,12 @@ struct dib { /* Device information bl
if the Boolean test B is true.
*/
#define IONEXT(I) (IOSIGNAL) ((I) & (IOCYCLE) (- (int32) (I))) /* extract next I/O signal to handle */
#define IONEXT(I) (IOSIGNAL) ((I) & ~(I) + 1) /* extract next I/O signal to handle */
#define IOADDSIR(I) ((I) & IOIRQSET ? (I) | ioSIR : (I)) /* add SIR if IRQ state might change */
#define IORETURN(E,D) ((uint32) ((E) << 16 | (D) & DMASK)) /* form I/O handler return value */
#define IOSTATUS(C) ((t_stat) ((C) >> 16) & DMASK) /* extract I/O status from combined value */
#define IODATA(C) ((uint16) ((C) & DMASK)) /* extract data from combined value */
#define IORETURN(E,D) ((uint32) ((E) << D16_WIDTH | (D) & D16_MASK)) /* form I/O handler return value */
#define IOSTATUS(C) ((t_stat) ((C) >> D16_WIDTH) & D16_MASK) /* extract I/O status from combined value */
#define IODATA(C) ((uint16) ((C) & D16_MASK)) /* extract data from combined value */
#define IOPOWERON(P) (P)->io_handler ((P), ioPON | ioPOPIO | ioCRS, 0) /* send power-on signals to handler */
#define IOPRESET(P) (P)->io_handler ((P), ioPOPIO | ioCRS, 0) /* send PRESET signals to handler */
@@ -718,7 +1009,7 @@ struct dib { /* Device information bl
#define BIT_V(S) ((S) & 037) /* convert select code to bit position */
#define BIT_M(S) (1u << BIT_V (S)) /* convert select code to bit mask */
#define setSKF(B) stat_data = IORETURN (SCPE_OK, (uint16) ((B) ? ioSKF : ioNONE))
#define setSKF(B) stat_data = ((B) ? ioSKF : ioNONE)
#define setPRL(S,B) dev_prl[(S)/32] = dev_prl[(S)/32] & ~BIT_M (S) | (((B) & 1) << BIT_V (S))
#define setIRQ(S,B) dev_irq[(S)/32] = dev_irq[(S)/32] & ~BIT_M (S) | (((B) & 1) << BIT_V (S))
@@ -736,26 +1027,81 @@ struct dib { /* Device information bl
#define setstdSRQ(N) setSRQ (dibptr->select_code, N.flag);
/* CPU state */
/* Bitset formatting.
See the comments at the "fmt_bitset" function (hp2100_sys.c) for details of
the specification of bitset names and format structures.
*/
typedef enum { /* direction of interpretation */
msb_first, /* left-to-right */
lsb_first /* right-to-left */
} BITSET_DIRECTION;
typedef enum { /* alternate names */
no_alt, /* no alternates are present in the name array */
has_alt /* the name array contains alternates */
} BITSET_ALTERNATE;
typedef enum { /* trailing separator */
no_bar, /* omit a trailing separator */
append_bar /* append a trailing separator */
} BITSET_BAR;
typedef const char *const BITSET_NAME; /* a bit name string pointer */
typedef struct { /* bit set format descriptor */
uint32 name_count; /* count of bit names */
BITSET_NAME *names; /* pointer to an array of bit names */
uint32 offset; /* offset from LSB to first bit */
BITSET_DIRECTION direction; /* direction of interpretation */
BITSET_ALTERNATE alternate; /* alternate interpretations presence */
BITSET_BAR bar; /* trailing separator choice */
} BITSET_FORMAT;
/* Bitset format specifier initialization */
#define FMT_INIT(names,offset,dir,alt,bar) \
sizeof (names) / sizeof (names) [0], \
(names), (offset), (dir), (alt), (bar)
/* System interface global data structures */
extern const HP_WORD odd_parity [256]; /* a table of parity bits for odd parity */
/* System interface global SCP support routines declared in scp.h
extern t_stat sim_load (FILE *fptr, CONST char *cptr, CONST char *fnam, int flag);
extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, UNIT *uptr, int32 sw);
extern t_stat parse_sym (CONST char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw);
*/
/* System interface global SCP support routines */
extern t_stat hp_attach (UNIT *uptr, CONST char *cptr);
extern t_stat hp_set_dib (UNIT *uptr, int32 count, CONST char *cptr, void *desc);
extern t_stat hp_show_dib (FILE *st, UNIT *uptr, int32 count, CONST void *desc);
/* System interface global utility routines */
extern t_stat fprint_cpu (FILE *ofile, t_addr addr, t_value *val, uint32 radix, SYMBOL_SOURCE source);
extern const char *fmt_char (uint32 charval);
extern const char *fmt_bitset (uint32 bitset, const BITSET_FORMAT bitfmt);
extern void hp_trace (DEVICE *dptr, uint32 flag, ...);
extern t_bool hp_device_conflict (void);
extern void hp_enbdis_pair (DEVICE *ccptr, DEVICE *dcptr);
/* I/O state */
extern uint32 dev_prl [2], dev_irq [2], dev_srq [2]; /* I/O signal vectors */
/* CPU functions */
extern t_stat ibl_copy (const BOOT_ROM rom, int32 dev, uint32 sr_clear, uint32 sr_set);
extern void hp_enbdis_pair (DEVICE *ccp, DEVICE *dcp);
/* System functions */
extern const char *fmt_char (uint8 ch);
extern t_stat hp_setsc (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
extern t_stat hp_setdev (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
extern t_stat hp_showsc (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
extern t_stat hp_showdev (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
extern t_bool hp_fprint_stopped (FILE *st, t_stat reason);
/* Device-specific functions */
extern int32 sync_poll (POLLMODE poll_mode);
#endif

View File

@@ -25,6 +25,8 @@
DI 12821A Disc Interface
15-Mar-17 JDB Converted debug fprintfs to tpprintfs
10-Mar-17 JDB Added IOBUS to the debug table
17-Jan-17 JDB Changed to use new byte accessors in hp2100_defs.h
13-May-16 JDB Modified for revised SCP API function parameter types
24-Dec-14 JDB Added casts for explicit downward conversions
@@ -177,6 +179,33 @@
#define TAG_MASK (TAG_ATN | TAG_EOI | TAG_EDT | TAG_LBR)
static const BITSET_NAME tag_names [] = { /* Bus signal names */
"ATN", /* bit 16 */
"EOI", /* bit 17 */
"EDT", /* bit 18 */
"LBR" /* bit 19 */
};
static const BITSET_FORMAT tag_format = /* names, offset, direction, alternates, bar */
{ FMT_INIT (tag_names, 16, lsb_first, no_alt, no_bar) };
/* Bus signals */
static const BITSET_NAME bus_names [] = { /* Bus signal names */
"ATN", /* bit 0 = attention */
"EOI", /* bit 1 = end or identify */
"DAV", /* bit 2 = data available */
"NRFD", /* bit 3 = not ready for data */
"NDAC", /* bit 4 = not data accepted */
"REN", /* bit 5 = remote enable */
"IFC", /* bit 6 = interface clear */
"SRQ" /* bit 7 = service request */
};
static const BITSET_FORMAT bus_format = /* names, offset, direction, alternates, bar */
{ FMT_INIT (bus_names, 0, lsb_first, no_alt, no_bar) };
/* FIFO access modes */
@@ -207,7 +236,6 @@ static void master_reset (CARD_ID card);
static void update_state (CARD_ID card);
static void fifo_load (CARD_ID card, uint16 data, FIFO_ACCESS access);
static uint16 fifo_unload (CARD_ID card, FIFO_ACCESS access);
static void fprint_bus (FILE *file, char *format, uint8 cntl);
@@ -251,7 +279,8 @@ DEVICE dc_dev = {
0, /* debug control flags */
di_deb, /* debug flag name table */
NULL, /* memory size change routine */
NULL }; /* logical device name */
NULL /* logical device name */
};
@@ -280,13 +309,14 @@ static RESPONDER *bus_respond [card_count] = { &da_bus_respond, NULL, NULL };
DEBTAB di_deb [] = {
{ "CPU", DEB_CPU },
{ "CMDS", DEB_CMDS },
{ "BUF", DEB_BUF },
{ "XFER", DEB_XFER },
{ "RWSC", DEB_RWSC },
{ "SERV", DEB_SERV },
{ NULL, 0 }
{ "RWSC", DEB_RWSC },
{ "CMDS", DEB_CMDS },
{ "CPU", DEB_CPU },
{ "BUF", DEB_BUF },
{ "XFER", DEB_XFER },
{ "SERV", DEB_SERV },
{ "IOBUS", TRACE_IOBUS },
{ NULL, 0 }
};
@@ -408,7 +438,6 @@ DEBTAB di_deb [] = {
optimization.
*/
uint32 di_io (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
{
static const char * const output_state [] = { "Control", "Data" };
@@ -434,9 +463,7 @@ while (working_set) {
di_card->flag = CLEAR; /* clear the flag */
di_card->flagbuf = CLEAR; /* and flag buffer */
if (DEBUG_PRJ (dptrs [card], DEB_CMDS))
fprintf (sim_deb, ">>%s cmds: [CLF] Flag cleared\n",
dptrs [card]->name);
tpprintf (dptrs [card], DEB_CMDS, "[CLF] Flag cleared\n");
if (update_required) /* if the card state has changed */
update_state (card); /* then update the state */
@@ -444,9 +471,7 @@ while (working_set) {
case ioSTF: /* set flag flip-flop */
if (DEBUG_PRJ (dptrs [card], DEB_CMDS))
fprintf (sim_deb, ">>%s cmds: [STF] Flag set\n",
dptrs [card]->name);
tpprintf (dptrs [card], DEB_CMDS, "[STF] Flag set\n");
/* fall into ENF handler */
@@ -472,9 +497,8 @@ while (working_set) {
di_card->status_register &= ~STAT_IRL; /* clear the input register loaded status */
if (FIFO_EMPTY && di_card->eor == CLEAR) { /* is the FIFO empty and end of record not seen? */
if (di_card->srq == SET && DEBUG_PRJ (dptrs [card], DEB_CMDS))
fprintf (sim_deb, ">>%s cmds: SRQ cleared\n",
dptrs [card]->name);
if (di_card->srq == SET)
tpprintf (dptrs [card], DEB_CMDS, "SRQ cleared\n");
di_card->srq = CLEAR; /* clear SRQ */
update_required = FALSE; /* the card state does not change */
@@ -505,10 +529,8 @@ while (working_set) {
data = di_card->status_register; /* return the status word */
}
if (DEBUG_PRJ (dptrs [card], DEB_CPU))
fprintf (sim_deb, ">>%s cpu: [LIx%s] %s = %06o\n",
dptrs [card]->name, hold_or_clear,
input_state [di_card->control], data);
tpprintf (dptrs [card], DEB_CPU, "[LIx%s] %s = %06o\n",
hold_or_clear, input_state [di_card->control], data);
if (update_required && !(signal_set & ioCLF)) /* if an update is required and CLF is not present, */
update_state (card); /* update the state, else ioCLF will update it */
@@ -520,10 +542,8 @@ while (working_set) {
case ioIOO: /* I/O data output */
data = IODATA (stat_data); /* get the data value */
if (DEBUG_PRJ (dptrs [card], DEB_CPU))
fprintf (sim_deb, ">>%s cpu: [OTx%s] %s = %06o\n",
dptrs [card]->name, hold_or_clear,
output_state [di_card->control], data);
tpprintf (dptrs [card], DEB_CPU, "[OTx%s] %s = %06o\n",
hold_or_clear, output_state [di_card->control], data);
if (di_card->control == SET) { /* is the card in data mode? */
if (signal_set & ioEDT) /* if end of DCPC transfer */
@@ -547,9 +567,8 @@ while (working_set) {
fifo_load (card, data, cpu_access); /* load the data word into the FIFO */
if (FIFO_FULL && (di_card->bus_cntl & BUS_NRFD)) { /* FIFO full and listener not ready? */
if (di_card->srq == SET && DEBUG_PRJ (dptrs [card], DEB_CMDS))
fprintf (sim_deb, ">>%s cmds: SRQ cleared\n",
dptrs [card]->name);
if (di_card->srq == SET)
tpprintf (dptrs [card], DEB_CMDS, "SRQ cleared\n");
di_card->srq = CLEAR; /* clear SRQ */
update_required = FALSE; /* the card state does not change */
@@ -638,16 +657,12 @@ while (working_set) {
di_card->flag = SET; /* set the flag */
di_card->flagbuf = SET; /* and flag buffer */
if (DEBUG_PRJ (dptrs [card], DEB_CMDS))
fprintf (sim_deb, ">>%s cmds: [POPIO] Flag set\n",
dptrs [card]->name);
tpprintf (dptrs [card], DEB_CMDS, "[POPIO] Flag set\n");
break;
case ioCRS: /* control reset */
if (DEBUG_PRJ (dptrs [card], DEB_CMDS))
fprintf (sim_deb, ">>%s cmds: [CRS] Master reset\n",
dptrs [card]->name);
tpprintf (dptrs [card], DEB_CMDS, "[CRS] Master reset\n");
di_card->status_register &= /* clear listen and talk status */
~(STAT_LSTN | STAT_TALK);
@@ -671,15 +686,8 @@ while (working_set) {
case ioCLC: /* clear control flip-flop */
di_card->control = CLEAR; /* clear control */
if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) {
fprintf (sim_deb, ">>%s cmds: [CLC%s] Control cleared (configure mode)",
dptrs [card]->name, hold_or_clear);
if (signal_set & ioCLF) /* if ioCLF is given, */
fputs (", master reset\n", sim_deb); /* then report a master reset */
else
fputc ('\n', sim_deb);
}
tpprintf (dptrs [card], DEB_CMDS, "[CLC%s] Control cleared (configure mode)%s\n",
hold_or_clear, (signal_set & ioCLF ? ", master reset" : ""));
if (signal_set & ioCLF) /* if ioCLF is given, */
master_reset (card); /* then do a master reset */
@@ -689,16 +697,13 @@ while (working_set) {
case ioSTC: /* set control flip-flop */
di_card->control = SET; /* set control */
if (DEBUG_PRJ (dptrs [card], DEB_CMDS))
fprintf (sim_deb, ">>%s cmds: [STC%s] Control set (data mode)\n",
dptrs [card]->name, hold_or_clear);
tpprintf (dptrs [card], DEB_CMDS, "[STC%s] Control set (data mode)\n",
hold_or_clear);
break;
case ioEDT: /* end data transfer */
if (DEBUG_PRJ (dptrs [card], DEB_CPU))
fprintf (sim_deb, ">>%s cpu: [EDT] DCPC transfer ended\n",
dptrs [card]->name);
tpprintf (dptrs [card], DEB_CPU, "[EDT] DCPC transfer ended\n");
break;
@@ -1017,10 +1022,8 @@ CARD_ID other;
uint32 acceptors, unit;
t_bool accepted = FALSE;
if (DEBUG_PRJ (dptrs [card], DEB_XFER)) {
fprintf (sim_deb, ">>%s xfer: HP-IB DIO %03o available ", dptrs [card]->name, data);
fprint_bus (sim_deb, "[%s]\n", di [card].bus_cntl);
}
tpprintf (dptrs [card], DEB_XFER, "HP-IB DIO %03o signals %s available\n",
data, fmt_bitset (di [card].bus_cntl, bus_format));
if (dptrs [card]->flags & DEV_DIAG) /* is this a diagnostic run? */
for (other = first_card; other <= last_card; other++) { /* look through the list of cards */
@@ -1048,9 +1051,8 @@ else if ((di [card].bus_cntl & BUS_PPOLL) != BUS_PPOLL) { /* this is a normal
}
}
if (DEBUG_PRJ (dptrs [card], DEB_XFER) && !accepted)
fprintf (sim_deb, ">>%s xfer: HP-IB no acceptors\n",
dptrs [card]->name);
if (!accepted)
tpprintf (dptrs [card], DEB_XFER, "HP-IB no acceptors\n");
return accepted;
}
@@ -1114,21 +1116,18 @@ new_denials = di [card].bus_cntl & deny; /* get the changing deni
di [card].bus_cntl = new_state; /* establish the new control state */
if (DEBUG_PRJ (dptrs [card], DEB_XFER)) {
if (unit == CONTROLLER)
fprintf (sim_deb, ">>%s xfer: HP-IB card %d", dptrs [card]->name, card);
else
fprintf (sim_deb, ">>%s xfer: HP-IB address %d",
dptrs [card]->name, GET_BUSADR (dptrs [card]->units [unit].flags));
if (new_assertions)
fprint_bus (sim_deb, " asserted [%s]", new_assertions);
if (new_denials)
fprint_bus (sim_deb, " denied [%s]", new_denials);
fprint_bus (sim_deb, ", bus is [%s]\n", new_state);
}
if (unit == CONTROLLER)
tpprintf (dptrs [card], DEB_XFER, "HP-IB card %d asserted %s denied %s bus is %s\n",
card,
fmt_bitset (new_assertions, bus_format),
fmt_bitset (new_denials, bus_format),
fmt_bitset (new_state, bus_format));
else
tpprintf (dptrs [card], DEB_XFER, "HP-IB address %d asserted %s denied %s bus is %s\n",
GET_BUSADR (dptrs [card]->units [unit].flags),
fmt_bitset (new_assertions, bus_format),
fmt_bitset (new_denials, bus_format),
fmt_bitset (new_state, bus_format));
if ((dptrs [card]->flags & DEV_DIAG) /* is the card in diagnostic mode? */
|| (new_assertions & ASSERT_SET) /* or are changed signals in the */
@@ -1158,9 +1157,8 @@ if ((dptrs [card]->flags & DEV_DIAG) /* is the card i
}
}
if (DEBUG_PRJ (dptrs [card], DEB_XFER) & !responded)
fprintf (sim_deb, ">>%s xfer: HP-IB no responders\n",
dptrs [card]->name);
if (!responded)
tpprintf (dptrs [card], DEB_XFER, "HP-IB no responders\n");
}
if ((new_state & BUS_PPOLL) == BUS_PPOLL) /* was a parallel poll requested? */
@@ -1191,10 +1189,9 @@ if (response == SET) { /* enable the poll respo
else /* disable the poll response */
di [card].poll_response &= ~PPR (address); /* by clearing the response bit */
if (DEBUG_PRJ (dptrs [card], DEB_XFER)
&& previous_response != di [card].poll_response)
fprintf (sim_deb, ">>%s xfer: HP-IB address %d parallel poll response %s\n",
dptrs [card]->name, address, (response == SET ? "enabled" : "disabled"));
if (previous_response != di [card].poll_response)
tpprintf (dptrs [card], DEB_XFER, "HP-IB address %d parallel poll response %s\n",
address, (response == SET ? "enabled" : "disabled"));
return;
}
@@ -1249,9 +1246,8 @@ if (dptrs [card]->flags & DEV_DIAG) /* is this a diagnos
PPR (GET_DIADR (dptrs [other]->flags));
if (response) { /* is a poll response indicated? */
if (DEBUG_PRJ (dptrs [card], DEB_XFER))
fprintf (sim_deb, ">>%s xfer: HP-IB parallel poll DIO %03o\n",
dptrs [card]->name, response);
tpprintf (dptrs [card], DEB_XFER, "HP-IB parallel poll DIO %03o\n",
response);
while (di [card].fifo_count != FIFO_SIZE) /* fill the card FIFO with the responses */
fifo_load (card, (uint16) response, diag_access); /* (hardware feature) */
@@ -1274,9 +1270,8 @@ return;
static t_bool di_bus_accept (CARD_ID card, uint8 data)
{
if (DEBUG_PRJ (dptrs [card], DEB_XFER))
fprintf (sim_deb, ">>%s xfer: HP-IB card %d accepted data %03o \n",
dptrs [card]->name, card, data);
tpprintf (dptrs [card], DEB_XFER, "HP-IB card %d accepted data %03o\n",
card, data);
fifo_load (card, data, bus_access); /* load the data byte into the FIFO */
update_state (card); /* and update the card state */
@@ -1339,9 +1334,7 @@ di [card].status_register &= /* clear the status flip
di [card].input_data_register = 0; /* clear the input data register */
di [card].fifo_count = 0; /* clear the FIFO */
if (DEBUG_PRJ (dptrs [card], DEB_BUF))
fprintf (sim_deb, ">>%s buf: FIFO cleared\n",
dptrs [card]->name);
tpprintf (dptrs [card], DEB_BUF, "FIFO cleared\n");
return;
}
@@ -1465,10 +1458,9 @@ else
di_card->srq = CLEAR; /* otherwise, DCPC service is not needed */
if (DEBUG_PRJ (dptrs [card], DEB_CMDS)
&& di_card->srq != previous_state)
fprintf (sim_deb, ">>%s cmds: SRQ %s\n",
dptrs [card]->name, di_card->srq == SET ? "set" : "cleared");
if (di_card->srq != previous_state)
tpprintf (dptrs [card], DEB_CMDS, "SRQ %s\n",
di_card->srq == SET ? "set" : "cleared");
if (di_card->status_register & STAT_IRL /* is the input register loaded */
@@ -1487,9 +1479,7 @@ if (di_card->status_register & STAT_IRL /* is the input register
&& di_card->status_register & STAT_IFC /* and IFC is asserted on the bus */
&& di_card->cntl_register & CNTL_IFC) { /* and notification is wanted? */
if (DEBUG_PRJ (dptrs [card], DEB_CMDS))
fprintf (sim_deb, ">>%s cmds: Flag set\n",
dptrs [card]->name);
tpprintf (dptrs [card], DEB_CMDS, "Flag set\n");
di_io (dibptr, ioENF, 0); /* set the flag and recalculate interrupts */
}
@@ -1596,9 +1586,8 @@ t_bool add_word = TRUE;
DI_STATE * const di_card = &di [card];
if (FIFO_FULL) { /* is the FIFO already full? */
if (DEBUG_PRJ (dptrs [card], DEB_BUF))
fprintf (sim_deb, ">>%s buf: Attempted load to full FIFO, data %0*o\n",
dptrs [card]->name, (access == bus_access ? 3 : 6), data);
tpprintf (dptrs [card], DEB_BUF, "Attempted load to full FIFO, data %0*o\n",
(access == bus_access ? 3 : 6), data);
return; /* return with the load ignored */
}
@@ -1665,12 +1654,9 @@ else { /* must be diagnostic ac
if (add_word) /* did we add a word to the FIFO? */
di_card->fifo_count = di_card->fifo_count + 1; /* increment the count of words stored */
if (DEBUG_PRJ (dptrs [card], DEB_BUF)) {
fprintf (sim_deb, ">>%s buf: Data %0*o tag ",
dptrs [card]->name, (access == bus_access ? 3 : 6), data);
fprint_val (sim_deb, tag >> BUS_SHIFT, 2, 4, PV_RZRO);
fprintf (sim_deb, " loaded into FIFO (%d)\n", di_card->fifo_count);
}
tpprintf (dptrs [card], DEB_XFER, "Data %0*o tag %s loaded into FIFO (%d)\n",
(access == bus_access ? 3 : 6), data,
fmt_bitset (tag, tag_format), di_card->fifo_count);
return;
}
@@ -1783,10 +1769,7 @@ t_bool remove_word = TRUE;
DI_STATE * const di_card = &di [card];
if (FIFO_EMPTY) { /* is the FIFO already empty? */
if (DEBUG_PRJ (dptrs [card], DEB_BUF))
fprintf (sim_deb, ">>%s buf: Attempted unload from empty FIFO\n",
dptrs [card]->name);
tpprintf (dptrs [card], DEB_BUF, "Attempted unload from empty FIFO\n");
return 0; /* return with no data */
}
@@ -1838,12 +1821,9 @@ if (remove_word) { /* remove the word from
}
if (DEBUG_PRJ (dptrs [card], DEB_BUF)) {
fprintf (sim_deb, ">>%s buf: Data %0*o tag ",
dptrs [card]->name, (access == cpu_access ? 6 : 3), data);
fprint_val (sim_deb, tag >> BUS_SHIFT, 2, 4, PV_RZRO);
fprintf (sim_deb, " unloaded from FIFO (%d)\n", di_card->fifo_count);
}
tpprintf (dptrs [card], DEB_BUF, "Data %0*o tag %s unloaded from FIFO (%d)\n",
(access == cpu_access ? 6 : 3), data,
fmt_bitset (tag, tag_format), di_card->fifo_count);
if (di_card->cntl_register & CNTL_TALK) /* is the card talking? */
@@ -1867,51 +1847,3 @@ if (di_card->cntl_register & CNTL_TALK) /* is the card talking?
return (uint16) data; /* return the data value */
}
/* Print the bus state for debugging.
The states of the supplied bus control lines are decoded and printed in
mnemonic form to the specified file using the indicated format string. An
asserted bus signal is indicated by its name; a denied signal is omitted.
Implementation notes:
1. The strings in the cntl_names array must appear in BUS_xxx order. The
first element corresponds to bus bit 0, etc.
*/
static void fprint_bus (FILE *file, char *format, uint8 cntl)
{
static const char *cntl_names [] = {
"ATN", /* bit 0: attention */
"EOI", /* bit 1: end or identify */
"DAV", /* bit 2: data available */
"NRFD", /* bit 3: not ready for data */
"NDAC", /* bit 4: not data accepted */
"REN", /* bit 5: remote enable */
"IFC", /* bit 6: interface clear */
"SRQ" /* bit 7: service request */
};
uint32 signal;
char mnemonics [40];
if (cntl == 0) /* are any control signals asserted? */
strcpy (mnemonics, "---"); /* no; use dashes in lieu of an empty string */
else { /* one or more signals are asserted */
mnemonics [0] = '\0';
for (signal = 0; signal <= 7; signal++) /* loop though the set of signals */
if (cntl & (1 << signal)) { /* is this signal asserted? */
if (strlen (mnemonics) > 0) /* yes; is it the first one asserted? */
strcat (mnemonics, " "); /* no, so append a space to separate */
strcat (mnemonics, cntl_names [signal]); /* append the name of the asserted signal */
}
}
fprintf (file, format, mnemonics); /* print the bus state */
return;
}

View File

@@ -25,6 +25,8 @@
DI 12821A Disc Interface
15-Mar-17 JDB Trace flags are now global
09-Mar-17 JDB Changed the DIAG option to DIAGNOSTIC
10-Jan-17 JDB Moved byte accessors to hp2100_defs.h
13-May-16 JDB Modified for revised SCP API function parameter types
14-Feb-12 JDB First release
@@ -89,16 +91,6 @@ typedef enum {
#define SET_BUSADR(f) (((f) & UNIT_M_BUSADR) << UNIT_V_BUSADR)
/* Debug flags */
#define DEB_CPU (1 << 0) /* words received from and sent to the CPU */
#define DEB_CMDS (1 << 1) /* interface commands received from the CPU */
#define DEB_BUF (1 << 2) /* data read from and written to the card FIFO */
#define DEB_XFER (1 << 3) /* data received and transmitted via HP-IB */
#define DEB_RWSC (1 << 4) /* device read/write/status/control commands */
#define DEB_SERV (1 << 5) /* unit service scheduling calls */
/* HP-IB control line state bit flags.
NOTE that these flags align with the corresponding flags in the DI status
@@ -140,31 +132,31 @@ typedef enum {
/* Per-card state variables */
typedef struct {
FLIP_FLOP control; /* control flip-flop */
FLIP_FLOP flag; /* flag flip-flop */
FLIP_FLOP flagbuf; /* flag buffer flip-flop */
FLIP_FLOP srq; /* SRQ flip-flop */
FLIP_FLOP edt; /* EDT flip-flop */
FLIP_FLOP eor; /* EOR flip-flop */
BYTE_SELECTOR ibp; /* input byte pointer selector */
BYTE_SELECTOR obp; /* output byte pointer selector */
FLIP_FLOP control; /* control flip-flop */
FLIP_FLOP flag; /* flag flip-flop */
FLIP_FLOP flagbuf; /* flag buffer flip-flop */
FLIP_FLOP srq; /* SRQ flip-flop */
FLIP_FLOP edt; /* EDT flip-flop */
FLIP_FLOP eor; /* EOR flip-flop */
BYTE_SELECTOR ibp; /* input byte pointer selector */
BYTE_SELECTOR obp; /* output byte pointer selector */
uint16 cntl_register; /* control word register */
uint16 status_register; /* status word register */
uint16 input_data_register; /* input data register */
uint16 cntl_register; /* control word register */
uint16 status_register; /* status word register */
uint16 input_data_register; /* input data register */
uint32 fifo [FIFO_SIZE]; /* FIFO buffer */
uint32 fifo_count; /* FIFO occupancy counter */
REG *fifo_reg; /* FIFO register pointer */
uint32 fifo [FIFO_SIZE]; /* FIFO buffer */
uint32 fifo_count; /* FIFO occupancy counter */
REG *fifo_reg; /* FIFO register pointer */
uint32 acceptors; /* unit bitmap of the bus acceptors */
uint32 listeners; /* unit bitmap of the bus listeners */
uint32 talker; /* unit bitmap of the bus talker */
uint32 acceptors; /* unit bitmap of the bus acceptors */
uint32 listeners; /* unit bitmap of the bus listeners */
uint32 talker; /* unit bitmap of the bus talker */
uint8 bus_cntl; /* HP-IB bus control state (ATN, EOI, etc.) */
uint8 poll_response; /* address bitmap of parallel poll responses */
uint8 bus_cntl; /* HP-IB bus control state (ATN, EOI, etc.) */
uint8 poll_response; /* address bitmap of parallel poll responses */
double ifc_timer; /* 100 microsecond IFC timer */
double ifc_timer; /* 100 microsecond IFC timer */
} DI_STATE;
@@ -212,17 +204,17 @@ typedef struct {
These definitions should be included before any device-specific modifiers.
*/
#define DI_MODS(dev) \
{ MTAB_XTD | MTAB_VDV, 1, "ADDRESS", "ADDRESS", &di_set_address, &di_show_address, &dev }, \
\
{ MTAB_XTD | MTAB_VDV, 1, NULL, "DIAG", &di_set_cable, NULL, &dev }, \
{ MTAB_XTD | MTAB_VDV, 0, NULL, "HPIB", &di_set_cable, NULL, &dev }, \
{ MTAB_XTD | MTAB_VDV, 0, "CABLE", NULL, NULL, &di_show_cable, &dev }, \
\
{ MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &dev }, \
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &dev }, \
\
{ MTAB_XTD | MTAB_VUN, 0, "BUS", "BUS", &di_set_address, &di_show_address, &dev }
#define DI_MODS(dev,dib) \
{ MTAB_XTD | MTAB_VDV, 1, "ADDRESS", "ADDRESS", &di_set_address, &di_show_address, &dev }, \
\
{ MTAB_XTD | MTAB_VDV, 1, NULL, "DIAGNOSTIC", &di_set_cable, NULL, &dev }, \
{ MTAB_XTD | MTAB_VDV, 0, NULL, "HPIB", &di_set_cable, NULL, &dev }, \
{ MTAB_XTD | MTAB_VDV, 0, "CABLE", NULL, NULL, &di_show_cable, &dev }, \
\
{ MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_set_dib, &hp_show_dib, (void *) &dib }, \
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, ~1u, "DEVNO", "DEVNO", &hp_set_dib, &hp_show_dib, (void *) &dib }, \
\
{ MTAB_XTD | MTAB_VUN, 0, "BUS", "BUS", &di_set_address, &di_show_address, &dev }
/* Disc interface global bus routine definitions */

View File

@@ -1,6 +1,6 @@
/* hp2100_di_da.c: HP 12821A HP-IB Disc Interface simulator for Amigo disc drives
Copyright (c) 2011-2017, J. David Bryan
Copyright (c) 2011-2018, 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"),
@@ -25,6 +25,11 @@
DA 12821A Disc Interface with Amigo disc drives
21-Feb-18 JDB ATTACH -N now creates a full-size disc image
11-Jul-17 JDB Renamed "ibl_copy" to "cpu_ibl"
15-Mar-17 JDB Changed DEBUG_PRI calls to tprintfs
09-Mar-17 JDB Deprecated LOCKED/WRITEENABLED for PROTECT/UNPROTECT
27-Feb-17 JDB ibl_copy no longer returns a status code
17-Jan-17 JDB Changed to use new byte accessors in hp2100_defs.h
13-May-16 JDB Modified for revised SCP API function parameter types
04-Mar-16 JDB Name changed to "hp2100_disclib" until HP 3000 integration
@@ -345,6 +350,7 @@
#include "hp2100_defs.h"
#include "hp2100_cpu.h"
#include "hp2100_di.h"
#include "hp2100_disclib.h"
@@ -553,20 +559,25 @@ REG da_reg [] = {
};
MTAB da_mod [] = {
DI_MODS (da_dev),
DI_MODS (da_dev, da_dib),
{ UNIT_UNLOAD, UNIT_UNLOAD, "heads unloaded", "UNLOADED", &da_load_unload, NULL, NULL },
{ UNIT_UNLOAD, 0, "heads loaded", "LOADED", &da_load_unload, NULL, NULL },
/* Mask Value Match Value Print String Match String Validation Display Descriptor */
/* ------------ ------------ ----------------- --------------- ---------------- ------- ---------- */
{ UNIT_UNLOAD, UNIT_UNLOAD, "heads unloaded", "UNLOADED", &da_load_unload, NULL, NULL },
{ UNIT_UNLOAD, 0, "heads loaded", "LOADED", &da_load_unload, NULL, NULL },
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL, NULL, NULL },
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL, NULL, NULL },
{ UNIT_WLK, UNIT_WLK, "protected", "PROTECT", NULL, NULL, NULL },
{ UNIT_WLK, 0, "unprotected", "UNPROTECT", NULL, NULL, NULL },
{ UNIT_FMT, UNIT_FMT, "format enabled", "FORMAT", NULL, NULL, NULL },
{ UNIT_FMT, 0, "format disabled", "NOFORMAT", NULL, NULL, NULL },
{ UNIT_WLK, UNIT_WLK, NULL, "LOCKED", NULL, NULL, NULL },
{ UNIT_WLK, 0, NULL, "WRITEENABLED", NULL, NULL, NULL },
{ UNIT_MODEL, MODEL_7906, "7906H", "7906H", &dl_set_model, NULL, NULL },
{ UNIT_MODEL, MODEL_7920, "7920H", "7920H", &dl_set_model, NULL, NULL },
{ UNIT_MODEL, MODEL_7925, "7925H", "7925H", &dl_set_model, NULL, NULL },
{ UNIT_FMT, UNIT_FMT, "format enabled", "FORMAT", NULL, NULL, NULL },
{ UNIT_FMT, 0, "format disabled", "NOFORMAT", NULL, NULL, NULL },
{ UNIT_MODEL, MODEL_7906, "7906H", "7906H", &dl_set_model, NULL, NULL },
{ UNIT_MODEL, MODEL_7920, "7920H", "7920H", &dl_set_model, NULL, NULL },
{ UNIT_MODEL, MODEL_7925, "7925H", "7925H", &dl_set_model, NULL, NULL },
{ 0 }
};
@@ -807,9 +818,8 @@ switch (if_state [unit]) { /* dispatch the inte
if_state [unit] = read_xfer; /* we are ready to transfer the data */
uptr->wait = cvptr->cmd_time; /* schedule the transfer */
if (DEBUG_PRI (da_dev, DEB_RWSC))
fprintf (sim_deb, ">>DA rwsc: Unit %d Amigo identify response %04XH\n",
unit, buffer [0]);
tprintf (da_dev, DEB_RWSC, "Unit %d Amigo identify response %04XH\n",
unit, buffer [0]);
break;
@@ -967,36 +977,31 @@ switch (if_state [unit]) { /* dispatch the inte
if (uptr->wait) /* is service requested? */
activate_unit (uptr); /* schedule the next event */
if (result == SCPE_IERR && DEBUG_PRI (da_dev, DEB_RWSC)) { /* did an internal error occur? */
fprintf (sim_deb, ">>DA rwsc: Unit %d ", unit); /* report it if debugging */
if (result == SCPE_IERR) /* did an internal error occur? */
if (if_state [unit] == command_exec
&& if_command [unit] == disc_command)
fprintf (sim_deb, "%s command %s phase ",
tprintf (da_dev, DEB_RWSC, "Unit %d %s command %s phase service not handled\n",
unit,
dl_opcode_name (ICD, (CNTLR_OPCODE) uptr->OP),
dl_phase_name ((CNTLR_PHASE) uptr->PHASE));
else
fprintf (sim_deb, "%s state %s ",
tprintf (da_dev, DEB_RWSC, "Unit %d %s state %s service not handled\n",
unit,
if_command_name [if_command [unit]],
if_state_name [if_state [unit]]);
fputs ("service not handled\n", sim_deb);
}
if (if_state [unit] == idle) { /* is the command now complete? */
if (if_command [unit] == disc_command) { /* did a disc command complete? */
if (cvptr->opcode != End) /* yes; if the command was not End, */
di_poll_response (da, unit, SET); /* then enable PPR */
if (DEBUG_PRI (da_dev, DEB_RWSC))
fprintf (sim_deb, ">>DA rwsc: Unit %d %s disc command completed\n",
unit, dl_opcode_name (ICD, cvptr->opcode));
tprintf (da_dev, DEB_RWSC, "Unit %d %s disc command completed\n",
unit, dl_opcode_name (ICD, cvptr->opcode));
}
else /* an interface command completed */
if (DEBUG_PRI (da_dev, DEB_RWSC))
fprintf (sim_deb, ">>DA rwsc: Unit %d %s command completed\n",
unit, if_command_name [if_command [unit]]);
tprintf (da_dev, DEB_RWSC, "Unit %d %s command completed\n",
unit, if_command_name [if_command [unit]]);
if (release_interface) /* if the next command is already pending */
di_bus_control (da, unit, 0, BUS_NRFD); /* deny NRFD to allow the card to resume */
@@ -1076,6 +1081,9 @@ return status;
The unspecified responses are illegal conditions; for example, the simulator
does not allow an attached unit to be disabled.
If a new file is specified, the file is initialized to its capacity by
writing a zero to the last byte in the file.
Implementation notes:
@@ -1087,19 +1095,36 @@ return status;
specifying a validation routine works for the DISABLED case but not the
ENABLED case -- set_unit_enbdis returns SCPE_UDIS before calling the
validation routine.
2. The C standard says, "A binary stream need not meaningfully support fseek
calls with a whence value of SEEK_END," so instead we determine the
offset from the start of the file to the last byte and seek there.
*/
t_stat da_attach (UNIT *uptr, CONST char *cptr)
{
t_stat result;
t_stat result;
t_addr offset;
const uint8 zero = 0;
const int32 unit = uptr - da_unit; /* calculate the unit number */
result = dl_attach (&icd_cntlr [unit], uptr, cptr); /* attach the drive */
if (result == SCPE_OK) /* was the attach successful? */
di [da].acceptors |= (1 << unit); /* set the unit's accepting bit */
if (result == SCPE_OK) { /* if the attach was successful */
di [da].acceptors |= (1 << unit); /* then set the unit's accepting bit */
return result;
if (sim_switches & SWMASK ('N')) { /* if this is a new disc image */
offset = (t_addr) /* then determine the offset of */
(uptr->capac * sizeof (int16) - sizeof zero); /* the last byte in a full-sized file */
if (sim_fseek (uptr->fileref, offset, SEEK_SET) != 0 /* seek to the last byte */
|| fwrite (&zero, sizeof zero, 1, uptr->fileref) == 0 /* and write a zero to fill */
|| fflush (uptr->fileref) != 0) /* the file to its capacity */
clearerr (uptr->fileref); /* clear and ignore any errors */
}
}
return result; /* return the result of the attach */
}
@@ -1126,17 +1151,131 @@ return result;
}
/* Boot an Amigo disc drive.
/* 7906H/20H/25H disc bootstrap loader (12992H).
The ICD disc bootstrap program is loaded from the HP 12992H Boot Loader ROM
into memory, the I/O instructions are configured for the interface card's
select code, and the program is run to boot from the specified unit. The
loader supports booting the disc at bus address 0 only. Before execution,
the S register is automatically set as follows:
The HP 1000 uses the 12992H boot loader ROM to bootstrap the ICD discs. Bit
12 of the S register determines whether an RPL or manual boot is performed.
Bits 1-0 specify the head number to use.
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
------ ------ ---------------------- ------------- -----
ROM # 0 1 select code reserved head
The loader reads 256 words from cylinder 0 sector 0 of the specified head
into memory starting at location 2011 octal. Loader execution ends with one
of the following instructions:
* HLT 11 - the drive aborted the transfer due to an unrecoverable error
* JSB 2055,I - the disc read succeeded
The ICD drives are not supported on the 2100/14/15/16 CPUs, so no 21xx loader
is provided.
*/
static const LOADER_ARRAY da_loaders = {
{ /* HP 21xx Loader does not exist */
IBL_NA, /* loader starting index */
IBL_NA, /* DMA index */
IBL_NA, /* FWA index */
{ 0 } },
{ /* HP 1000 Loader ROM (12992H) */
IBL_START, /* loader starting index */
IBL_DMA, /* DMA index */
IBL_FWA, /* FWA index */
{ 0102501, /* 77700: START LIA 1 GET SWITCH REGISTER SETTING */
0100044, /* 77701: LSL 4 SHIFT A LEFT 4 */
0006111, /* 77702: CLE,SLB,RSS SR BIT 12 SET FOR MANUAL BOOT? */
0100041, /* 77703: LSL 1 NO. SHIFT HEAD # FOR RPL BOOT */
0001424, /* 77704: ALR,ALR SHIFT HEAD 2, CLEAR SIGN */
0033744, /* 77705: IOR HDSEC SET EOI BIT */
0073744, /* 77706: STA HDSEC PLACE IN COMMAND BUFFER */
0017756, /* 77707: JSB BTCTL SEND DUMMY,U-CLR,PP */
0102510, /* 77710: LIA IBI READ INPUT REGISTER */
0101027, /* 77711: ASR 7 SHIFT DRIVE 0 RESPONSE TO LSB */
0002011, /* 77712: SLA,RSS DID DRIVE 0 RESPOND? */
0027710, /* 77713: JMP *-3 NO, GO LOOK AGAIN */
0107700, /* 77714: CLC 0,C */
0017756, /* 77715: JSB BTCTL SEND TALK, CL-RD,BUS HOLDER */
0002300, /* 77716: CCE */
0017756, /* 77717: JSB BTCTL TELL CARD TO LISTEN */
0063776, /* 77720: LDA DMACW LOAD DMA CONTROL WORD */
0102606, /* 77721: OTA 6 OUTPUT TO DCPC */
0106702, /* 77722: CLC 2 READY DCPC */
0063735, /* 77723: LDA ADDR1 LOAD DMA BUFFER ADDRESS */
0102602, /* 77724: OTA 2 OUTPUT TO DCPC */
0063740, /* 77725: LDA DMAWC LOAD DMA WORD COUNT */
0102702, /* 77726: STC 2 READY DCPC */
0102602, /* 77727: OTA 2 OUTPUT TO DCPC */
0103706, /* 77730: STC 6,C START DCPC */
0102206, /* 77731: TEST SFC 6 SKIP IF DMA NOT DONE */
0117750, /* 77732: JSB ADDR2,I SUCCESSFUL END OF TRANSFER */
0102310, /* 77733: SFS IBI SKIP IF DISC ABORTED TRANSFER */
0027731, /* 77734: JMP TEST RECHECK FOR TRANSFER END */
0102011, /* 77735: ADDR1 HLT 11B ERROR HALT */
0000677, /* 77736: UNCLR OCT 677 UNLISTEN */
0000737, /* 77737: OCT 737 UNTALK */
0176624, /* 77740: DMAWC OCT 176624 UNIVERSAL CLEAR,LBO */
0000440, /* 77741: LIST OCT 440 LISTEN BUS ADDRESS 0 */
0000550, /* 77742: CMSEC OCT 550 SECONDARY GET COMMAND */
0000000, /* 77743: BOOT OCT 0 COLD LOAD READ COMMAND */
0001000, /* 77744: HDSEC OCT 1000 HEAD,SECTOR PLUS EOI */
0000677, /* 77745: UNLST OCT 677 ATN,PRIMARY UNLISTEN,PARITY */
0000500, /* 77746: TALK OCT 500 SEND READ DATA */
0100740, /* 77747: RDSEC OCT 100740 SECONDARY READ DATA */
0102055, /* 77750: ADDR2 OCT 102055 BOOT EXTENSION STARTING ADDRESS */
0004003, /* 77751: CTLP OCT 4003 INT=LBO,T,CIC */
0000047, /* 77752: OCT 47 PPE,L,T,CIC */
0004003, /* 77753: OCT 4003 INT=LBO,T,CIC */
0000413, /* 77754: OCT 413 ATN,P,L,CIC */
0001015, /* 77755: OCT 1015 INT=EOI,P,L,CIC */
0000000, /* 77756: BTCTL NOP */
0107710, /* 77757: CLC IBI,C RESET IBI */
0063751, /* 77760: BM LDA CTLP LOAD CONTROL WORD */
0102610, /* 77761: OTA IBI OUTPUT TO CONTROL REGISTER */
0102710, /* 77762: STC IBI RETURN IBI TO DATA MODE */
0037760, /* 77763: ISZ BM INCREMENT CONTROL WORD POINTER */
0002240, /* 77764: SEZ,CME */
0127756, /* 77765: JMP BTCTL,I RETURN */
0063736, /* 77766: LABL LDA UNCLR LOAD DATA WORD */
0037766, /* 77767: ISZ LABL INCREMENT WORD POINTER */
0102610, /* 77770: OTA IBI OUTPUT TO HPIB */
0002021, /* 77771: SSA,RSS SKIP IF LAST WORD */
0027766, /* 77772: JMP LABL GO BACK FOR NEXT WORD */
0102310, /* 77773: SFS IBI SKIP IF LAST WORD SENT TO BUS */
0027773, /* 77774: JMP *-1 RECHECK ACCEPTANCE */
0027757, /* 77775: JMP BTCTL+1 */
0000010, /* 77776: DMACW ABS IBI */
0170100 } } /* 77777: ABS -START */
};
/* Device boot routine.
This routine is called directly by the BOOT DA and LOAD DA commands to copy
the device bootstrap into the upper 64 words of the logical address space. It
is also called indirectly by a BOOT CPU or LOAD CPU command when the
specified HP 1000 loader ROM socket contains a 12992H ROM.
When called in response to a BOOT DA or LOAD DA command, the "unitno"
parameter indicates the unit number specified in the BOOT command or is zero
for the LOAD command, and "dptr" points at the DA device structure. The
bootstrap supports loading only from the disc at bus address 0 only. The
12992F loader ROM will be copied into memory and configured for the DA select
code. The S register will be set as it would be by the front-panel
microcode.
When called for a BOOT/LOAD CPU command, the "unitno" parameter indicates the
select code to be used for configuration, and "dptr" will be NULL. As above,
the 12992H loader ROM will be copied into memory and configured for the
specified select code. The S register is assumed to be set correctly on entry
and is not modified.
The loader expects the S register to be is set as follows:
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| ROM # | 0 1 | select code | reserved | head |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
Bit 12 must be 1 for a manual boot. Bits 5-2 are nominally zero but are
reserved for the target operating system. For example, RTE uses bit 5 to
indicate whether a standard (0) or reconfiguration (1) boot is desired.
The boot routine sets bits 15-6 of the S register to appropriate values.
Bits 5-3 and 1-0 retain their original values, so S should be set before
@@ -1145,84 +1284,21 @@ return result;
than 0 is desired.
*/
static const BOOT_ROM da_rom = {
0102501, /* START LIA 1 GET SWITCH REGISTER SETTING */
0100044, /* LSL 4 SHIFT A LEFT 4 */
0006111, /* CLE,SLB,RSS SR BIT 12 SET FOR MANUAL BOOT? */
0100041, /* LSL 1 NO. SHIFT HEAD # FOR RPL BOOT */
0001424, /* ALR,ALR SHIFT HEAD 2, CLEAR SIGN */
0033744, /* IOR HDSEC SET EOI BIT */
0073744, /* STA HDSEC PLACE IN COMMAND BUFFER */
0017756, /* JSB BTCTL SEND DUMMY,U-CLR,PP */
0102510, /* LIA IBI READ INPUT REGISTER */
0101027, /* ASR 7 SHIFT DRIVE 0 RESPONSE TO LSB */
0002011, /* SLA,RSS DID DRIVE 0 RESPOND? */
0027710, /* JMP *-3 NO, GO LOOK AGAIN */
0107700, /* CLC 0,C */
0017756, /* JSB BTCTL SEND TALK, CL-RD,BUS HOLDER */
0002300, /* CCE */
0017756, /* JSB BTCTL TELL CARD TO LISTEN */
0063776, /* LDA DMACW LOAD DMA CONTROL WORD */
0102606, /* OTA 6 OUTPUT TO DCPC */
0106702, /* CLC 2 READY DCPC */
0063735, /* LDA ADDR1 LOAD DMA BUFFER ADDRESS */
0102602, /* OTA 2 OUTPUT TO DCPC */
0063740, /* LDA DMAWC LOAD DMA WORD COUNT */
0102702, /* STC 2 READY DCPC */
0102602, /* OTA 2 OUTPUT TO DCPC */
0103706, /* STC 6,C START DCPC */
0102206, /* TEST SFC 6 SKIP IF DMA NOT DONE */
0117750, /* JSB ADDR2,I SUCCESSFUL END OF TRANSFER */
0102310, /* SFS IBI SKIP IF DISC ABORTED TRANSFER */
0027731, /* JMP TEST RECHECK FOR TRANSFER END */
0102011, /* ADDR1 HLT 11B ERROR HALT */
0000677, /* UNCLR OCT 677 UNLISTEN */
0000737, /* OCT 737 UNTALK */
0176624, /* DMAWC OCT 176624 UNIVERSAL CLEAR,LBO */
0000440, /* LIST OCT 440 LISTEN BUS ADDRESS 0 */
0000550, /* CMSEC OCT 550 SECONDARY GET COMMAND */
0000000, /* BOOT OCT 0 COLD LOAD READ COMMAND */
0001000, /* HDSEC OCT 1000 HEAD,SECTOR PLUS EOI */
0000677, /* UNLST OCT 677 ATN,PRIMARY UNLISTEN,PARITY */
0000500, /* TALK OCT 500 SEND READ DATA */
0100740, /* RDSEC OCT 100740 SECONDARY READ DATA */
0102055, /* ADDR2 OCT 102055 BOOT EXTENSION STARTING ADDRESS */
0004003, /* CTLP OCT 4003 INT=LBO,T,CIC */
0000047, /* OCT 47 PPE,L,T,CIC */
0004003, /* OCT 4003 INT=LBO,T,CIC */
0000413, /* OCT 413 ATN,P,L,CIC */
0001015, /* OCT 1015 INT=EOI,P,L,CIC */
0000000, /* BTCTL NOP */
0107710, /* CLC IBI,C RESET IBI */
0063751, /* BM LDA CTLP LOAD CONTROL WORD */
0102610, /* OTA IBI OUTPUT TO CONTROL REGISTER */
0102710, /* STC IBI RETURN IBI TO DATA MODE */
0037760, /* ISZ BM INCREMENT CONTROL WORD POINTER */
0002240, /* SEZ,CME */
0127756, /* JMP BTCTL,I RETURN */
0063736, /* LABL LDA UNCLR LOAD DATA WORD */
0037766, /* ISZ LABL INCREMENT WORD POINTER */
0102610, /* OTA IBI OUTPUT TO HPIB */
0002021, /* SSA,RSS SKIP IF LAST WORD */
0027766, /* JMP LABL GO BACK FOR NEXT WORD */
0102310, /* SFS IBI SKIP IF LAST WORD SENT TO BUS */
0027773, /* JMP *-1 RECHECK ACCEPTANCE */
0027757, /* JMP BTCTL+1 */
0000010, /* DMACW ABS IBI */
0170100 /* ABS -START */
};
t_stat da_boot (int32 unitno, DEVICE *dptr)
{
if (GET_BUSADR (da_unit [unitno].flags) != 0) /* booting is supported on bus address 0 only */
return SCPE_NOFNC; /* report "Command not allowed" if attempted */
static const HP_WORD da_preserved = 0000073u; /* S-register bits 5-3 and 1-0 are preserved */
static const HP_WORD da_manual_boot = 0010000u; /* S-register bit 12 set for a manual boot */
if (ibl_copy (da_rom, da_dib.select_code, /* copy the boot ROM to memory and configure */
IBL_OPT | IBL_DS_HEAD, /* the S register accordingly */
IBL_DS | IBL_MAN | IBL_SET_SC (da_dib.select_code)))
return SCPE_IERR; /* return an internal error if the copy failed */
else
return SCPE_OK;
if (dptr == NULL) /* if we are being called for a BOOT/LOAD CPU */
return cpu_copy_loader (da_loaders, unitno, /* then copy the boot loader to memory */
IBL_S_NOCLEAR, IBL_S_NOSET); /* but do not alter the S register */
else if (GET_BUSADR (da_unit [unitno].flags) != 0) /* otherwise BOOT DA is supported on bus address 0 only */
return SCPE_NOFNC; /* so reject other addresses as unsupported */
else /* otherwise this is a BOOT/LOAD DA */
return cpu_copy_loader (da_loaders, da_dib.select_code, /* so copy the boot loader to memory */
da_preserved, da_manual_boot); /* and configure the S register if 1000 CPU */
}
@@ -1451,8 +1527,7 @@ if (di [da].bus_cntl & BUS_ATN) { /* is it a bus comma
case 0x04: /* selected device clear */
case 0x05: /* SDC with parity freeze */
case 0x14: /* universal clear */
if (DEBUG_PRI (da_dev, DEB_RWSC))
fprintf (sim_deb, ">>DA rwsc: Unit %d device cleared\n", unit);
tprintf (da_dev, DEB_RWSC, "Unit %d device cleared\n", unit);
sim_cancel (&da_unit [unit]); /* cancel any in-progress command */
dl_idle_controller (&icd_cntlr [unit]); /* idle the controller */
@@ -1460,7 +1535,7 @@ if (di [da].bus_cntl & BUS_ATN) { /* is it a bus comma
if_state [unit] = idle; /* idle the interface */
di_poll_response (da, unit, SET); /* enable PPR */
if (DEBUG_PRI (da_dev, DEB_XFER))
if (TRACING (da_dev, DEB_XFER))
strcpy (action, "device clear");
break;
@@ -1482,7 +1557,7 @@ if (di [da].bus_cntl & BUS_ATN) { /* is it a bus comma
addressed = TRUE; /* unit is now addressed */
stopped_talking = TRUE; /* MLA stops the unit from talking */
if (DEBUG_PRI (da_dev, DEB_XFER))
if (TRACING (da_dev, DEB_XFER))
sprintf (action, "listen %d", message_address);
}
@@ -1491,7 +1566,7 @@ if (di [da].bus_cntl & BUS_ATN) { /* is it a bus comma
stopped_listening = TRUE; /* UNL stops the unit from listening */
if (DEBUG_PRI (da_dev, DEB_XFER))
if (TRACING (da_dev, DEB_XFER))
strcpy (action, "unlisten");
}
@@ -1511,7 +1586,7 @@ if (di [da].bus_cntl & BUS_ATN) { /* is it a bus comma
addressed = TRUE; /* the unit is now addressed */
stopped_listening = TRUE; /* MTA stops the unit from listening */
if (DEBUG_PRI (da_dev, DEB_XFER))
if (TRACING (da_dev, DEB_XFER))
sprintf (action, "talk %d", message_address);
}
@@ -1524,7 +1599,7 @@ if (di [da].bus_cntl & BUS_ATN) { /* is it a bus comma
accepted = FALSE; /* are not accepted */
else /* it's an Untalk */
if (DEBUG_PRI (da_dev, DEB_XFER))
if (TRACING (da_dev, DEB_XFER))
strcpy (action, "untalk");
}
@@ -1670,7 +1745,7 @@ if (di [da].bus_cntl & BUS_ATN) { /* is it a bus comma
if (accepted) { /* was the command accepted? */
if (DEBUG_PRI (da_dev, DEB_XFER))
if (TRACING (da_dev, DEB_XFER))
sprintf (action, "secondary %02XH", message_address);
if (if_command [unit] != amigo_identify) /* disable PPR for all commands */
@@ -1685,8 +1760,7 @@ if (di [da].bus_cntl & BUS_ATN) { /* is it a bus comma
if_state [unit] = command_wait; /* change the interface state to wait */
di_bus_control (da, unit, BUS_NRFD, 0); /* and assert NRFD to hold off the card */
if (DEBUG_PRI (da_dev, DEB_RWSC))
fprintf (sim_deb, ">>DA rwsc: Unit %d addressed while controller is busy\n", unit);
tprintf (da_dev, DEB_RWSC, "Unit %d addressed while controller is busy\n", unit);
}
if (stopped_listening) { /* was the unit Unlistened? */
@@ -1715,7 +1789,7 @@ else { /* it is bus data (A
switch (if_state [unit]) { /* dispatch the interface state */
case opcode_wait: /* waiting for an opcode */
if (DEBUG_PRI (da_dev, DEB_XFER))
if (TRACING (da_dev, DEB_XFER))
sprintf (action, "opcode %02XH", data & DL_OPCODE_MASK);
buffer [0] = TO_WORD (data, 0); /* set the opcode into the buffer */
@@ -1737,7 +1811,7 @@ else { /* it is bus data (A
case parameter_wait: /* waiting for a parameter */
if (DEBUG_PRI (da_dev, DEB_XFER))
if (TRACING (da_dev, DEB_XFER))
sprintf (action, "parameter %02XH", data);
put_buffer_byte (&icd_cntlr [unit], data); /* add the byte to the buffer */
@@ -1761,7 +1835,7 @@ else { /* it is bus data (A
/* fall into error_sink handler */
case error_sink: /* sinking data after an error */
if (DEBUG_PRI (da_dev, DEB_XFER))
if (TRACING (da_dev, DEB_XFER))
sprintf (action, "data %03o", data);
if (di [da].bus_cntl & BUS_EOI) /* is this the last byte from the bus? */
@@ -1777,26 +1851,26 @@ else { /* it is bus data (A
abort_command (unit, io_program_error, /* report the error */
error_sink); /* and sink any data that follows */
if (DEBUG_PRI (da_dev, DEB_XFER))
if (TRACING (da_dev, DEB_XFER))
sprintf (action, "unhandled data %03o", data);
break;
}
}
if (accepted && DEBUG_PRI (da_dev, DEB_XFER))
fprintf (sim_deb, ">>DA xfer: HP-IB address %d accepted %s\n",
if (accepted)
tprintf (da_dev, DEB_XFER, "HP-IB address %d accepted %s\n",
GET_BUSADR (da_unit [unit].flags), action);
if (da_unit [unit].wait > 0) /* was service requested? */
activate_unit (&da_unit [unit]); /* schedule the unit */
if (initiated && DEBUG_PRI (da_dev, DEB_RWSC))
if (initiated)
if (if_command [unit] == disc_command)
fprintf (sim_deb, ">>DA rwsc: Unit %d position %" T_ADDR_FMT "d %s disc command initiated\n",
tprintf (da_dev, DEB_RWSC, "Unit %d position %" T_ADDR_FMT "d %s disc command initiated\n",
unit, da_unit [unit].pos, dl_opcode_name (ICD, icd_cntlr [unit].opcode));
else
fprintf (sim_deb, ">>DA rwsc: Unit %d %s command initiated\n",
tprintf (da_dev, DEB_RWSC, "Unit %d %s command initiated\n",
unit, if_command_name [if_command [unit]]);
return accepted; /* indicate the acceptance condition */
@@ -2123,15 +2197,10 @@ return;
static t_stat activate_unit (UNIT *uptr)
{
int32 unit;
t_stat result;
if (DEBUG_PRI (da_dev, DEB_SERV)) {
unit = uptr - da_unit;
fprintf (sim_deb, ">>DA serv: Unit %d state %s delay %d service scheduled\n",
unit, if_state_name [if_state [unit]], uptr->wait);
}
tprintf (da_dev, DEB_SERV, "Unit %d state %s delay %d service scheduled\n",
uptr - da_unit, if_state_name [if_state [uptr - da_unit]], uptr->wait);
result = sim_activate (uptr, uptr->wait); /* activate the unit */
uptr->wait = 0; /* reset the activation time */

View File

@@ -1,6 +1,6 @@
SIMH/HP 21XX DIAGNOSTICS PERFORMANCE
====================================
Last update: 2016-12-18
Last update: 2018-05-15
The HP 24396 diagnostic suite has been run against the SIMH HP 21xx simulation.
@@ -84,7 +84,7 @@ The results of the diagnostic runs are summarized below:
105000 2610/14 Line Printer 1451 - No simulation
105101 2767 Line Printer 1611 3.3-0 Passed
105102 2607 Line Printer 1446 3.3-0 Passed
145103 2613/17/18 Line Printer 1633 - No simulation
145103 2613/17/18 Line Printer 1633 4.0-0 Passed
105104 9866 Line Printer 1541 - No simulation
105106 2631 Printer 1913 - No simulation
105107 2635 Printing Terminal 1913 - No simulation
@@ -488,13 +488,13 @@ TEST RESULT: Passed.
-------------------------------------
DSN 143300 - General Purpose Register
-------------------------------------
-------------------------------------------
DSN 143300 - General Purpose Register (LPS)
-------------------------------------------
TESTED DEVICE: LPS (hp2100_lps.c)
CONFIGURATION: sim> set LPS diag
CONFIGURATION: sim> set LPS DIAGNOSTIC
sim> deposit S 000014
sim> reset
sim> go 100
@@ -1064,7 +1064,7 @@ DSN 103115 - Privileged Interrupt
TESTED DEVICE: PIF (hp2100_pif.c)
CONFIGURATION: sim> set PIF 12936A
sim> set LPT DEV=44
sim> set LPT SC=44
sim> deposit S 004414
sim> reset
@@ -1096,9 +1096,9 @@ TEST RESULT: Passed.
-------------------------------------
DSN 143300 - General Purpose Register
-------------------------------------
-------------------------------------------
DSN 143300 - General Purpose Register (PIF)
-------------------------------------------
TESTED DEVICE: PIF (hp2100_pif.c)
@@ -1136,6 +1136,81 @@ TEST REPORT: GENERAL PURPOSE REGISTER DIAGNOSTIC, DSN 143300
TEST RESULT: Passed.
TEST NOTES: Only test 00 (Basic I/O Test) is executed. The other tests are
not applicable, as the 12620A card has no data path circuitry.
--------------------------------------------
DSN 143300 - General Purpose Register (IPLI)
--------------------------------------------
TESTED DEVICE: IPLI (hp2100_ipl.c)
CONFIGURATION: sim> set IPLI DIAGNOSTIC
sim> deposit S 000032
sim> reset
sim> go 100
Programmed halt, T: 102074 (HLT 74)
sim> deposit S 000000
sim> go
TEST REPORT: GENERAL PURPOSE REGISTER DIAGNOSTIC, DSN 143300
H024 PRESS PRESET (EXT&INT),RUN
Programmed halt, T: 102024 (HLT 24)
sim> reset
sim> go
H025 BASIC I-O COMPLETED
PASS 000001
Programmed halt, T: 102077 (HLT 77)
TEST RESULT: Passed.
--------------------------------------------
DSN 143300 - General Purpose Register (IPLO)
--------------------------------------------
TESTED DEVICE: IPLO (hp2100_ipl.c)
CONFIGURATION: sim> set IPLI DIAGNOSTIC
sim> deposit S 000033
sim> reset
sim> go 100
Programmed halt, T: 102074 (HLT 74)
sim> deposit S 000000
sim> go
TEST REPORT: GENERAL PURPOSE REGISTER DIAGNOSTIC, DSN 143300
H024 PRESS PRESET (EXT&INT),RUN
Programmed halt, T: 102024 (HLT 24)
sim> reset
sim> go
H025 BASIC I-O COMPLETED
PASS 000001
Programmed halt, T: 102077 (HLT 77)
TEST RESULT: Passed.
---------------------------------------------------
@@ -1596,12 +1671,12 @@ DSN 105102 - 2607 Line Printer
TESTED DEVICE: LPT (hp2100_lpt.c)
CONFIGURATION: sim> attach LPT scratch.2607.printer
CONFIGURATION: sim> attach -n LPT scratch.2607.printer
sim> deposit S 100015
sim> reset
sim> go 100
HALT instruction 102074
Programmed halt, T: 102074 (HLT 74)
sim> deposit S 001000
sim> reset
@@ -1609,7 +1684,7 @@ CONFIGURATION: sim> attach LPT scratch.2607.printer
2607 LINE PRINTER DIAGNOSTIC
HALT instruction 102075
Programmed halt, T: 102075 (HLT 75)
sim> deposit A 000377
sim> deposit S 000000
@@ -1618,7 +1693,7 @@ CONFIGURATION: sim> attach LPT scratch.2607.printer
TEST REPORT: H024 PRESS PRESET (EXT&INT),RUN
HALT instruction 102024
Programmed halt, T: 102024 (HLT 24)
sim> reset
sim> go
@@ -1626,63 +1701,63 @@ TEST REPORT: H024 PRESS PRESET (EXT&INT),RUN
H025 BI-O COMP
H040 PWR OFF LP,PRESS RUN
HALT instruction 102040
Programmed halt, T: 102040 (HLT 40)
sim> set LPT poweroff
sim> set LPT POWEROFF
sim> go
H041 PWR ON LP,READY LP,PRESS RUN
HALT instruction 102041
Programmed halt, T: 102041 (HLT 41)
sim> set LPT poweron
sim> set LPT POWERON
sim> go
H042 PRINT SW OFF,PRESS RUN
HALT instruction 102042
Programmed halt, T: 102042 (HLT 42)
sim> set LPT offline
sim> set LPT OFFLINE
sim> go
H043 PRINT SW ON,PRESS RUN
HALT instruction 102043
Programmed halt, T: 102043 (HLT 43)
sim> set LPT online
sim> set LPT ONLINE
sim> go
H044 OPEN PLATEN,PRESS RUN
HALT instruction 102044
Programmed halt, T: 102044 (HLT 44)
sim> set LPT offline
sim> set LPT OFFLINE
sim> go
H045 CLOSE PLATEN,PRESS RUN
HALT instruction 102045
Programmed halt, T: 102045 (HLT 45)
sim> set LPT online
sim> set LPT ONLINE
sim> go
H046 REMOVE PAPER FROM LP,PRESS RUN
HALT instruction 102046
Programmed halt, T: 102046 (HLT 46)
sim> detach LPT
sim> go
H047 RESTORE PAPER IN LP, READY LP,PRESS RUN
HALT instruction 102047
Programmed halt, T: 102047 (HLT 47)
sim> attach LPT scratch.2607.printer
sim> go
PASS 000001
HALT instruction 102077
Programmed halt, T: 102077 (HLT 77)
TEST RESULT: Passed.
@@ -1692,6 +1767,90 @@ TEST NOTES: The standard tests 00-07 are executed. Test 08 (operator
------------------------------------
DSN 145103 - 2613/17/18 Line Printer
------------------------------------
TESTED DEVICE: LPT (hp2100_lpt.c)
CONFIGURATION: sim> set LPT 2613,DIAGNOSTIC
sim> attach -n LPT scratch.2613.printer
sim> deposit S 000015
sim> reset
sim> go 100
Programmed halt, T: 102074 (HLT 74)
sim> deposit S 000000
sim> reset
sim> go
TEST REPORT: 2613-2618 LINE PRINTER DIAG
H024 PRESS PRESET (EXT&INT),RUN
Programmed halt, T: 102024 (HLT 24)
sim> reset
sim> go
H025 BI-O COMP
H040 PWR OFF LP,PRESS RUN
Programmed halt, T: 102040 (HLT 40)
sim> set LPT POWEROFF
sim> go
H041 PWR ON, ON LINE LP,PRESS RUN
Programmed halt, T: 102041 (HLT 41)
sim> set LPT POWERON
sim> go
H042 LP TO OFF LINE,PRESS RUN
Programmed halt, T: 102042 (HLT 42)
sim> set LPT OFFLINE
sim> go
H043 LP TO ON LINE,PRESS RUN
Programmed halt, T: 102043 (HLT 43)
sim> set LPT ONLINE
sim> go
H044 OPEN DRUM GATE,PRESS RUN
Programmed halt, T: 102044 (HLT 44)
sim> detach LPT
sim> go
H046 REMOVE PAPER,CLOSE DRUM GATE,PRESS RUN
Programmed halt, T: 102046 (HLT 46)
sim> go
H047 RESTORE PAPER, ON LINE LP, PRESS RUN
Programmed halt, T: 102047 (HLT 47)
sim> attach LPT scratch.2613.printer
sim> set LPT ONLINE
sim> go
PASS 000001
Programmed halt, T: 102077 (HLT 77)
TEST RESULT: Passed.
-----------------------------------------------------
DSN 111001 - HP2100A Disc File (2883) (multiple unit)
-----------------------------------------------------
@@ -2044,7 +2203,7 @@ TEST REPORT: H0 7900/7901 CARTRIDGE DISC MEMORY DIAGNOSTIC
HALT instruction 102002
sim> set DPC0 unloaded
sim> set DPC0 unload
sim> go
H40 PROTECT U/D THEN READY UNIT 0
@@ -2052,15 +2211,14 @@ TEST REPORT: H0 7900/7901 CARTRIDGE DISC MEMORY DIAGNOSTIC
[CTRL+E]
Simulation stopped
sim> set DPC0 locked
sim> set DPC0 loaded
sim> set DPC0 load,protect
sim> go
H41 CLEAR U/D PROTECT,LOAD,PUSH RUN
HALT instruction 102002
sim> set DPC0 writeenabled
sim> set DPC0 unprotect
sim> go
H71 PRESS PRESET(S) THEN PRESS RUN
@@ -3271,8 +3429,8 @@ TESTED DEVICE: IPLI, IPLO (hp2100_ipl.c)
BINARY TAPE: 24197-60001 Rev. B
CONFIGURATION: sim> set IPLI DIAG
sim> set IPLO DIAG
CONFIGURATION: sim> set IPLI DIAGNOSTIC
sim> set IPLO DIAGNOSTIC
sim> deposit S 003332
sim> reset
sim> go 2

View File

@@ -24,6 +24,7 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from the authors.
03-Aug-17 JDB Changed perror call for I/O errors to cprintf
22-Apr-17 JDB A failed sim_fseek call now causes a drive fault
09-Mar-17 JDB Added the simulator name to the "perror" message.
17-Jan-17 JDB Moved "hp2100_defs.h" inclusion to "hp2100_disclib.c"
@@ -2279,8 +2280,10 @@ static t_stat io_error (CVPTR cvptr, UNIT *uptr, CNTLR_STATUS status)
{
dl_end_command (cvptr, status); /* terminate the command with an error */
perror ("HP 2100 simulator disc library I/O error"); /* report the error to the console */
clearerr (uptr->fileref); /* and clear the error in case we resume */
cprintf ("%s simulator disc library I/O error: %s\n", /* report the error to the console */
sim_name, strerror (errno));
clearerr (uptr->fileref); /* clear the error */
return SCPE_IOERR; /* return an I/O error to stop the simulator */
}

View File

@@ -1,33 +1,41 @@
/* hp2100_dp.c: HP 2100 12557A/13210A disk simulator
/* hp2100_dp.c: HP 2100 12557A/13210A disc simulator
Copyright (c) 1993-2016, Robert M. Supnik
Copyright (c) 2017 J. David Bryan
Copyright (c) 2017-2018 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 in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not be
Except as contained in this notice, the names of the authors shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
in this Software without prior written authorization from the authors.
DP 12557A 2870 disk subsystem
13210A 7900 disk subsystem
DP 12557A 2870 disc subsystem
13210A 7900 disc subsystem
27-Feb-18 JDB Corrected the conditions that clear drive status
Added the BMDL
13-Feb-18 JDB First Status is now cleared on Read, etc.
26-Jan-18 JDB ATTACH -N now creates a full-size disc image
03-Aug-17 JDB Changed perror call for I/O errors to cprintf
11-Jul-17 JDB Renamed "ibl_copy" to "cpu_ibl"
22-Apr-17 JDB Added fall-through comment for FNC_STA case in dpcio
09-Mar-17 JDB Deprecated LOCKED/WRITEENABLED for PROTECT/UNPROTECT
27-Feb-17 JDB ibl_copy no longer returns a status code
09-Nov-16 JDB Corrected disk subsystem model number from 2871 to 2870
13-May-16 JDB Modified for revised SCP API function parameter types
30-Dec-14 JDB Added S-register parameters to ibl_copy
@@ -75,11 +83,12 @@
21-Nov-00 RMS Fixed flag, buffer power up state
References:
- 7900A Disc Drive Operating and Service Manual (07900-90002, Feb-1975)
- 13210A Disc Drive Interface Kit Operating and Service Manual
(13210-90003, Nov-1974)
- 12557A Cartridge Disc Interface Kit Operating and Service Manual
(12557-90001, Sep-1970)
- 7900A Disc Drive Operating and Service Manual
(07900-90002, February 1975)
- 13210A Disc Drive Interface Kit Operating and Service Manual
(13210-90003, May 1978)
- 12557A Cartridge Disc Interface Kit Operating and Service Manual
(12557-90001, Sepember 1970)
The simulator uses a number of state variables:
@@ -119,15 +128,111 @@
drive's current position register during a read, i.e., the "on-disc" address
field is assumed to match the current position.
The following implemented behaviors have been inferred from secondary sources
(diagnostics, operating system drivers, etc.), due to absent or contradictory
authoritative information; future correction may be needed:
NOTE: 13210A manuals dated November 1974 and earlier contain errors in the
schematics. See the comments preceding the "dpcio" routine for details.
1. Status bit 15 (ATTENTION) does not set bit 0 (ANY ERROR) on the 12557A.
2. Omitting STC DC before Status Check does not set DC flag but does poll.
The 13210A interfaces respond to I/O instructions as follows:
Output Data Word format (OTA and OTB):
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| command | - - | P | D | - - - - - - | unit | command
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| write data | data
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| - - - - - - - - | cylinder address | data
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| - - - - - - | head | - - - | sector address | data
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| - - - - - - - - - - | sector count | data
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
Where:
D = Defective Track
P = Protected Track
Command:
0000 = Status Check
0001 = Write Data
0010 = Read Data
0011 = Seek Record
0101 = Refine Sector
0110 = Check Data
1001 = Initialize Data
1011 = Address Record
The 12557A interface responds identically, except that the sector address and
sector count fields use one fewer bit each, i.e., use bits 3-0 and 4-0,
respectively.
Input Data Word format (LIA and LIB):
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| - - - - - - - - - - - - | attention | command
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| read data | data
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| - | F | O | - | U | P | - | S | - | N | C | A | G | B | D | E | data
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
Where:
F = First Status
O = Overrun
U = Drive Unsafe
P = Data Protected
S = Seek Check
N = Not Ready
C = End of Cylinder
A = Address Error
G = Flagged Cylinder
B = Drive Busy
D = Data Error
E = Any Error
The 12557A interface responds identically, except that the status word is
extended as follows:
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| T | F | O | R | U | H | I | S | - | N | C | A | G | B | D | E | data
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
Where the differing bits are:
T = Attention
R = Read/Write Unsafe
H = Access Hunting
I = Seek Incomplete
Implementation notes:
1. The following implemented behaviors have been inferred from secondary
sources (diagnostics, operating system drivers, etc.), due to absent or
contradictory authoritative information; future correction may be needed:
- 12557A status bit 15 (ATTENTION) does not set bit 0 (ANY ERROR).
- 12557A clears status after a Check Status command, but 13210A does
not.
- Omitting STC DC before Status Check does not set DC flag but does
poll.
*/
#include "hp2100_defs.h"
#include "hp2100_cpu.h"
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
#define UNIT_V_UNLOAD (UNIT_V_UF + 1) /* heads unloaded */
@@ -148,7 +253,13 @@
#define DP_SIZE3 (DP_NUMSF * DP_NUMCY * DP_NUMSC3 * DP_NUMWD)
#define DP_NUMDRV 4 /* # drives */
/* Command word */
/* Command word.
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| command | - - | P | D | - - - - - - | unit |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
*/
#define CW_V_FNC 12 /* function */
#define CW_M_FNC 017
@@ -187,35 +298,51 @@
#define DA_CKMASK3 077
#define DA_CKMASK (dp_ctype ? DA_CKMASK3 : DA_CKMASK2)
/* Status in dpc_sta[drv], (u) = unused in 13210, (d) = dynamic */
/* Status in dpc_sta [drv].
#define STA_ATN 0100000 /* attention (u) */
#define STA_1ST 0040000 /* first status */
#define STA_OVR 0020000 /* overrun */
#define STA_RWU 0010000 /* rw unsafe NI (u) */
#define STA_ACU 0004000 /* access unsafe NI */
#define STA_HUNT 0002000 /* hunting NI (12557) */
#define STA_PROT 0002000 /* protected (13210) */
#define STA_SKI 0001000 /* incomplete NI (u) */
#define STA_SKE 0000400 /* seek error */
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| - | F | O | - | U | P | - | S | - | N | C | A | G | B | D | E | 13210A
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| T | F | O | R | U | H | I | S | - | N | C | A | G | B | D | E | 12557A
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
Implementation notes:
1. The Data Protected, Not Ready, and Any Error bits are determined
dynamically. The other status bits are stored in the drive status array.
*/
#define STA_ATN 0100000 /* (T) Attention (12557) */
#define STA_1ST 0040000 /* (F) First status */
#define STA_OVR 0020000 /* (O) Overrun */
#define STA_RWU 0010000 /* (R) Read/Write Unsafe (12557) */
#define STA_ACU 0004000 /* (U) Drive Unsafe */
#define STA_PROT 0002000 /* (P) Data Protected (13210) */
#define STA_HUNT 0002000 /* (H) Access Hunting (12557) */
#define STA_SKI 0001000 /* (I) Seek Incomplete (12557) */
#define STA_SKE 0000400 /* (S) Seek Check */
/* 0000200 (unused) */
#define STA_NRDY 0000100 /* not ready (d) */
#define STA_EOC 0000040 /* end of cylinder */
#define STA_AER 0000020 /* addr error */
#define STA_FLG 0000010 /* flagged */
#define STA_BSY 0000004 /* seeking */
#define STA_DTE 0000002 /* data error */
#define STA_ERR 0000001 /* any error (d) */
#define STA_NRDY 0000100 /* (N) Not Ready */
#define STA_EOC 0000040 /* (C) End of Cylinder */
#define STA_AER 0000020 /* (A) Address Error */
#define STA_FLG 0000010 /* (G) Flagged Cylinder */
#define STA_BSY 0000004 /* (B) Drive Busy */
#define STA_DTE 0000002 /* (D) Data Error */
#define STA_ERR 0000001 /* (E) Any Error */
#define STA_ERSET2 (STA_1ST | STA_OVR | STA_RWU | STA_ACU | \
STA_SKI | STA_SKE | STA_NRDY | \
STA_EOC | STA_AER | STA_DTE) /* 12557A error set */
#define STA_ERSET3 (STA_ATN | STA_1ST | STA_OVR | STA_RWU | STA_ACU | \
STA_SKI | STA_SKE | STA_NRDY | STA_EOC | STA_AER | \
STA_FLG | STA_BSY | STA_DTE) /* 13210A error set */
#define STA_ANYERR (dp_ctype ? STA_ERSET3 : STA_ERSET2)
#define STA_ANYERR (dp_ctype ? STA_ERSET3 : STA_ERSET2)
#define STA_UNLOADED (dp_ctype ? (STA_NRDY | STA_BSY) : STA_NRDY)
#define STA_MBZ13 (STA_ATN | STA_RWU | STA_SKI) /* zero in 13210 */
struct {
@@ -311,18 +438,46 @@ REG dpd_reg[] = {
{ NULL }
};
MTAB dpd_mod[] = {
{ MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &dpd_dev },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &dpd_dev },
MTAB dpd_mod [] = {
/* Entry Flags Value Print String Match String Validation Display Descriptor */
/* ------------------- ----- ------------ ------------ ------------ ------------- ---------------- */
{ MTAB_XDV, 2u, "SC", "SC", &hp_set_dib, &hp_show_dib, (void *) &dp_dib },
{ MTAB_XDV | MTAB_NMO, ~2u, "DEVNO", "DEVNO", &hp_set_dib, &hp_show_dib, (void *) &dp_dib },
{ 0 }
};
/* Debugging trace list */
static DEBTAB dpd_deb [] = {
{ "IOBUS", TRACE_IOBUS }, /* trace I/O bus signals and data words received and returned */
{ NULL, 0 }
};
/* Device descriptor */
DEVICE dpd_dev = {
"DPD", &dpd_unit, dpd_reg, dpd_mod,
1, 10, DP_N_NUMWD, 1, 8, 16,
NULL, NULL, &dpc_reset,
NULL, NULL, NULL,
&dpd_dib, DEV_DISABLE
"DPD", /* device name */
&dpd_unit, /* unit array */
dpd_reg, /* register array */
dpd_mod, /* modifier array */
1, /* number of units */
10, /* address radix */
DP_N_NUMWD, /* address width = 4 GB */
1, /* address increment */
8, /* data radix */
16, /* data width */
NULL, /* examine routine */
NULL, /* deposit routine */
&dpc_reset, /* reset routine */
NULL, /* boot routine */
NULL, /* attach routine */
NULL, /* detach routine */
&dpd_dib, /* device information block pointer */
DEV_DISABLE | DEV_DEBUG, /* device flags */
0, /* debug control flags */
dpd_deb, /* debug flag name array */
NULL, /* memory size change routine */
NULL /* logical device name */
};
/* DPC data structures
@@ -373,28 +528,58 @@ REG dpc_reg[] = {
{ NULL }
};
MTAB dpc_mod[] = {
{ UNIT_UNLOAD, UNIT_UNLOAD, "heads unloaded", "UNLOADED", dpc_load_unload },
{ UNIT_UNLOAD, 0, "heads loaded", "LOADED", dpc_load_unload },
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
{ MTAB_XTD | MTAB_VDV, 1, NULL, "13210A",
&dp_settype, NULL, NULL },
{ MTAB_XTD | MTAB_VDV, 0, NULL, "12557A",
&dp_settype, NULL, NULL },
{ MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL,
NULL, &dp_showtype, NULL },
{ MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &dpd_dev },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &dpd_dev },
MTAB dpc_mod [] = {
/* Mask Value Match Value Print String Match String Validation Display Descriptor */
/* ------------ ------------ ----------------- --------------- ----------------- ------- ---------- */
{ UNIT_UNLOAD, UNIT_UNLOAD, "heads unloaded", "UNLOADED", &dpc_load_unload, NULL, NULL },
{ UNIT_UNLOAD, 0, "heads loaded", "LOADED", &dpc_load_unload, NULL, NULL },
{ UNIT_WLK, UNIT_WLK, "protected", "PROTECT", NULL, NULL, NULL },
{ UNIT_WLK, 0, "unprotected", "UNPROTECT", NULL, NULL, NULL },
{ UNIT_WLK, UNIT_WLK, NULL, "LOCKED", NULL, NULL, NULL },
{ UNIT_WLK, 0, NULL, "WRITEENABLED", NULL, NULL, NULL },
/* Entry Flags Value Print String Match String Validation Display Descriptor */
/* ------------------- ----- ------------ ------------ ------------ ------------- ---------------- */
{ MTAB_XDV, 1, NULL, "13210A", &dp_settype, NULL, NULL },
{ MTAB_XDV, 0, NULL, "12557A", &dp_settype, NULL, NULL },
{ MTAB_XDV, 0, "TYPE", NULL, NULL, &dp_showtype, NULL },
{ MTAB_XDV, 2u, "SC", "SC", &hp_set_dib, &hp_show_dib, (void *) &dp_dib },
{ MTAB_XDV | MTAB_NMO, ~2u, "DEVNO", "DEVNO", &hp_set_dib, &hp_show_dib, (void *) &dp_dib },
{ 0 }
};
/* Debugging trace list */
static DEBTAB dpc_deb [] = {
{ "IOBUS", TRACE_IOBUS }, /* trace I/O bus signals and data words received and returned */
{ NULL, 0 }
};
/* Device descriptor */
DEVICE dpc_dev = {
"DPC", dpc_unit, dpc_reg, dpc_mod,
DP_NUMDRV, 8, 24, 1, 8, 16,
NULL, NULL, &dpc_reset,
&dpc_boot, &dpc_attach, &dpc_detach,
&dpc_dib, DEV_DISABLE
"DPC", /* device name */
dpc_unit, /* unit array */
dpc_reg, /* register array */
dpc_mod, /* modifier array */
DP_NUMDRV, /* number of units */
8, /* address radix */
24, /* address width = 4 GB */
1, /* address increment */
8, /* data radix */
16, /* data width */
NULL, /* examine routine */
NULL, /* deposit routine */
&dpc_reset, /* reset routine */
&dpc_boot, /* boot routine */
&dpc_attach, /* attach routine */
&dpc_detach, /* detach routine */
&dpc_dib, /* device information block pointer */
DEV_DISABLE | DEV_DEBUG, /* device flags */
0, /* debug control flags */
dpc_deb, /* debug flag name array */
NULL, /* memory size change routine */
NULL /* logical device name */
};
@@ -533,6 +718,7 @@ return stat_data;
flip-flops. Only the 12557A has a command flip-flop. IRQ, PRL, and SRQ are
standard.
Implementation notes:
1. In hardware, the command channel card passes PRH to PRL. The data card
@@ -542,6 +728,30 @@ return stat_data;
the command card is interrupting. This works in hardware, but we must
break PRL at the command card under simulation to allow the command card
to interrupt.
2. The 13210 manual says that a Check Status command clears the status
register, which consists of status word bits 14, 13, 11, 10, 8, 5, 4, 3,
1, and 0, i.e., all except bit 6 "Not Ready" and bit 2 "Drive Busy",
which are direct pass-throughs from the drive. However, the schematic
shows that the register is cleared on STC assertion for any command
OTHER than Check Status. In other words, every command except Check
Status clears the old status in order to assert new status (so two
successive Check Status commands will return the same status word,
contrary to the manual). The simulator implements the schematic
behavior.
3. The schematics contained in 13210A manuals dated November 1974 and
earlier show that CRS does not clear the status register, but examining
the hardware PCA shows that it does. The simulator implements the
hardware behavior.
4. The schematics contained in 13210A manuals dated November 1974 and
earlier show that CRS clears the attention register, but examining the
hardware PCA shows that it does not. The signal marked CRS is actually
the XFER CYL signal from the sequencer, so the register is actually
cleared when a Check Status or Seek command is issued. However, later
PCAs did add CRS to the other two clearing conditions. The simulator
implements this later behavior.
*/
uint32 dpcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
@@ -609,6 +819,11 @@ while (working_set) {
if (dp_ctype == A12557) /* 12557? */
dpc.command = CLEAR; /* clear command */
for (drv = 0; drv < DP_NUMDRV; drv++) /* clear drive status */
dpc_sta [drv] &= /* for each drive */
~(STA_1ST | STA_OVR | STA_RWU | STA_ACU | STA_EOC
| STA_AER | STA_FLG | STA_DTE);
break;
@@ -638,6 +853,11 @@ while (working_set) {
drv = CW_GETDRV (dpc_obuf); /* get fnc, drv */
fnc = CW_GETFNC (dpc_obuf); /* from cmd word */
if (fnc != FNC_STA) /* if this is not a status command */
dpc_sta [drv] &= /* then clear the status register */
~(STA_OVR | STA_RWU | STA_ACU | STA_EOC
| STA_AER | STA_FLG | STA_DTE);
switch (fnc) { /* case on fnc */
case FNC_SEEK: /* seek */
@@ -716,7 +936,7 @@ dpc_eoc = 0; /* clear end cyl */
dpc_busy = drv + 1; /* set busy */
dpd_xfer = 1; /* xfer in prog */
dpc_unit[drv].FNC = fnc; /* save function */
dpc_sta[drv] = dpc_sta[drv] & ~STA_ATN; /* clear ATN */
dpc_sta[drv] &= ~(STA_ATN | STA_1ST); /* clear Attention and First Status */
sim_activate (&dpc_unit[drv], time); /* activate unit */
return;
}
@@ -739,6 +959,8 @@ return;
Status check - transfer status, finish operation
Check data
chk - transfer sector count
The 12557A clears status after a Check Status command. The 13210A does not.
*/
t_stat dpd_svc (UNIT *uptr)
@@ -820,10 +1042,14 @@ switch (uptr->FNC) { /* case function */
dpdio (&dpd_dib, ioENF, 0); /* set dch flg */
}
dpc_sta[drv] = dpc_sta[drv] & /* clr sta flags */
~(STA_ATN | STA_1ST | STA_OVR |
STA_RWU | STA_ACU | STA_EOC |
STA_AER | STA_FLG | STA_DTE);
if (dp_ctype == A13210)
dpc_sta [drv] &= ~STA_ATN; /* clear the current drive's attention bit */
else
dpc_sta[drv] &=
~(STA_ATN | STA_1ST | STA_OVR |
STA_RWU | STA_ACU | STA_EOC |
STA_AER | STA_FLG | STA_DTE);
dpc_poll = 1; /* enable polling */
for (i = 0; i < DP_NUMDRV; i++) { /* loop thru drives */
if (dpc_sta[i] & STA_ATN) { /* any ATN set? */
@@ -997,8 +1223,10 @@ dpc_busy = 0; /* ctlr is free */
dpd_xfer = dpd_wval = 0;
if (err != 0) { /* error? */
perror ("DP I/O error");
clearerr (uptr->fileref);
cprintf ("%s simulator DP disc I/O error: %s\n", /* then report the error to the console */
sim_name, strerror (errno));
clearerr (uptr->fileref); /* clear the error */
return SCPE_IOERR;
}
return SCPE_OK;
@@ -1045,15 +1273,44 @@ return SCPE_OK;
}
/* Attach routine */
/* Attach a drive unit.
The specified file is attached to the indicated drive unit, and the heads are
loaded, which will will set the First Status and Attention bits in the drive
status. If a new file is specified, the file is initialized to its capacity
by writing a zero to the last byte in the file.
Implementation notes:
1. The C standard says, "A binary stream need not meaningfully support fseek
calls with a whence value of SEEK_END," so instead we determine the
offset from the start of the file to the last byte and seek there.
*/
t_stat dpc_attach (UNIT *uptr, CONST char *cptr)
{
t_stat r;
t_stat result;
t_addr offset;
const uint8 zero = 0;
r = attach_unit (uptr, cptr); /* attach unit */
if (r == SCPE_OK) dpc_load_unload (uptr, 0, NULL, NULL);/* if OK, load heads */
return r;
result = attach_unit (uptr, cptr); /* attach the drive */
if (result == SCPE_OK) { /* if the attach was successful */
dpc_load_unload (uptr, 0, NULL, NULL); /* then load the heads */
if (sim_switches & SWMASK ('N')) { /* if this is a new disc image */
offset = (t_addr) /* then determine the offset of */
(uptr->capac * sizeof (int16) - sizeof zero); /* the last byte in a full-sized file */
if (sim_fseek (uptr->fileref, offset, SEEK_SET) != 0 /* seek to the last byte */
|| fwrite (&zero, sizeof zero, 1, uptr->fileref) == 0 /* and write a zero to fill */
|| fflush (uptr->fileref) != 0) /* the file to its capacity */
clearerr (uptr->fileref); /* clear and ignore any errors */
}
}
return result; /* return the result of the attach */
}
@@ -1122,83 +1379,278 @@ return SCPE_OK;
}
/* 7900/7901 bootstrap routine (HP 12992F ROM) */
/* 7900/2870 disc bootstrap loaders (BMDL and 12992F).
const BOOT_ROM dp_rom = {
0106710, /*ST CLC DC ; clr dch */
0106711, /* CLC CC ; clr cch */
0017757, /* JSB STAT ; get status */
0067746, /*SK LDB SKCMD ; seek cmd */
0106610, /* OTB DC ; cyl # */
0103710, /* STC DC,C ; to dch */
0106611, /* OTB CC ; seek cmd */
0103711, /* STC CC,C ; to cch */
0102310, /* SFS DC ; addr wd ok? */
0027710, /* JMP *-1 ; no, wait */
0006400, /* CLB */
0102501, /* LIA 1 ; read switches */
0002011, /* SLA,RSS ; <0> set? */
0047747, /* ADB BIT9 ; head 2 = removable */
0106610, /* OTB DC ; head/sector */
0103710, /* STC DC,C ; to dch */
0102311, /* SFS CC ; seek done? */
0027720, /* JMP *-1 ; no, wait */
0017757, /* JSB STAT ; get status */
0067776, /* LDB DMACW ; DMA control */
0106606, /* OTB 6 */
0067750, /* LDB ADDR1 ; memory addr */
0106602, /* OTB 2 */
0102702, /* STC 2 ; flip DMA ctrl */
0067752, /* LDB CNT ; word count */
0106602, /* OTB 2 */
0063745, /* LDB RDCMD ; read cmd */
0102611, /* OTA CC ; to cch */
0103710, /* STC DC,C ; start dch */
0103706, /* STC 6,C ; start DMA */
0103711, /* STC CC,C ; start cch */
0102311, /* SFS CC ; done? */
0027737, /* JMP *-1 ; no, wait */
0017757, /* JSB STAT ; get status */
0027775, /* JMP XT ; done */
0037766, /*FSMSK 037766 ; status mask */
0004000, /*STMSK 004000 ; unsafe mask */
0020000, /*RDCMD 020000 ; read cmd */
0030000, /*SKCMD 030000 ; seek cmd */
0001000, /*BIT9 001000 ; head 2 select */
0102011, /*ADDR1 102011 */
0102055, /*ADDR2 102055 */
0164000, /*CNT -6144. */
0, 0, 0, 0, /* unused */
0000000, /*STAT 0 */
0002400, /* CLA ; status request */
0102611, /* OTC CC ; to cch */
0103711, /* STC CC,C ; start cch */
0102310, /* SFS DC ; done? */
0027763, /* JMP *-1 */
0102510, /* LIA DC ; get status */
0013743, /* AND FSMSK ; mask 15,14,3,0 */
0002003, /* SZA,RSS ; drive ready? */
0127757, /* JMP STAT,I ; yes */
0013744, /* AND STMSK ; fault? */
0002002, /* SZA */
0102030, /* HLT 30 ; yes */
0027700, /* JMP ST ; no, retry */
0117751, /*XT JSB ADDR2,I ; start program */
0120010, /*DMACW 120000+DC */
0000000 /* -ST */
The Basic Moving-Head Disc Loader (BMDL) consists of two programs. The
program starting at address x7700 loads absolute paper tapes into memory.
The program starting at address x7750 loads a disc-resident bootstrap from
the 7900 or 2870 disc drive into memory. The S register setting does not
affect loader operation.
For a 2100/14/15/16 CPU, entering a LOAD DPC or BOOT DPC command loads the
BMDL into memory and executes the disc portion starting at x7750. The
bootstrap reads 6144 (for a 7900) or 3072 (for a 2870) words from cylinder 0,
head 0, sector 0 into memory starting at location 2011 octal. Loader
execution ends with the following instruction:
* JSB 2055,I - the disc read completed.
The BMDL configures DMA for an oversize (~32000 word) transfer and expects
the disc to terminate the operation with End of Cylinder (EOC) status.
The HP 1000 uses the 12992F boot loader ROM to bootstrap the 7900 disc. Bit
0 of the S register determines whether the boot extension is read from
subchannel 0 (the fixed platter) or subchannel 1 (the removable platter).
The loader reads 6144 words from cylinder 0 sector 0 of the specified
subchannel into memory starting at location 2011 octal. Loader execution
ends with one of the following instructions:
* HLT 30 - a drive fault occurred.
* JSB 2055,I - the disc read succeeded.
The loader automatically retries the operations for all disc errors other
than a drive fault.
Implementation notes:
1. After the BMDL has been loaded into memory, the paper tape portion may be
executed manually by setting the P register to the starting address
(x7700).
2. For compatibility with the "cpu_copy_loader" routine, the BMDL device I/O
instructions address select codes 10 and 11.
3. As published, the BMDL is configured to read from head 0 (the removable
platter, a.k.a. subchannel 1). To read from head 2 (the fixed platter,
subchannel 0), the head/sector control word must be changed.
*/
#define BMDL_SUBCHANNEL_0 031000 /* BMDL control word to address subchannel 0 instead of 1 */
static const LOADER_ARRAY dp_loaders = {
{ /* HP 21xx Basic Moving-Head Disc Loader (BMDL-7900) */
050, /* loader starting index */
077, /* DMA index */
034, /* FWA index */
{ 0002401, /* 77700: PTAPE CLA,RSS Paper Tape start */
0063721, /* 77701: LDA 77721 */
0107700, /* 77702: CLC 0,C */
0002307, /* 77703: CCE,INA,SZA,RSS */
0102077, /* 77704: HLT 77 */
0017735, /* 77705: JSB 77735 */
0007307, /* 77706: CMB,CCE,INB,SZB,RSS */
0027702, /* 77707: JMP 77702 */
0077733, /* 77710: STB 77733 */
0017735, /* 77711: JSB 77735 */
0017735, /* 77712: JSB 77735 */
0074000, /* 77713: STB 0 */
0077747, /* 77714: STB 77747 */
0047734, /* 77715: ADB 77734 */
0002140, /* 77716: SEZ,CLE */
0102055, /* 77717: HLT 55 */
0017735, /* 77720: JSB 77735 */
0177747, /* 77721: STB 77747,I */
0040001, /* 77722: ADA 1 */
0067747, /* 77723: LDB 77747 */
0006104, /* 77724: CLE,INB */
0037733, /* 77725: ISZ 77733 */
0027714, /* 77726: JMP 77714 */
0017735, /* 77727: JSB 77735 */
0054000, /* 77730: CPB 0 */
0027701, /* 77731: JMP 77701 */
0102011, /* 77732: HLT 11 */
0000000, /* 77733: OCT 000000 */
0100100, /* 77734: OCT 1n0100 */
0000000, /* 77735: NOP */
0006400, /* 77736: CLB */
0103710, /* 77737: STC 10,C */
0102310, /* 77740: SFS 10 */
0027740, /* 77741: JMP 77740 */
0107410, /* 77742: MIB 10,C */
0002240, /* 77743: SEZ,CME */
0127735, /* 77744: JMP 77735,I */
0005727, /* 77745: BLF,BLF */
0027737, /* 77746: JMP 77737 */
0000000, /* 77747: OCT 000000 */
0030000, /* 77750: DISC IOR 0 Disc start */
0067741, /* 77751: LDB 77741 */
0106611, /* 77752: OTB 11 */
0103711, /* 77753: STC 11,C */
0063750, /* 77754: LDA 77750 */
0102610, /* 77755: OTA 10 */
0103710, /* 77756: STC 10,C */
0102611, /* 77757: OTA 11 */
0103711, /* 77760: STC 11,C */
0063777, /* 77761: LDA 77777 */
0102606, /* 77762: OTA 6 */
0063732, /* 77763: LDA 77732 */
0102602, /* 77764: OTA 2 */
0103710, /* 77765: STC 10,C */
0102702, /* 77766: STC 2 */
0102602, /* 77767: OTA 2 */
0106611, /* 77770: OTB 11 */
0103710, /* 77771: STC 10,C */
0103706, /* 77772: STC 6,C */
0103711, /* 77773: STC 11,C */
0102311, /* 77774: SFS 11 */
0027774, /* 77775: JMP 77774 */
0117717, /* 77776: JSB 77717,I */
0120010 } }, /* 77777: OCT 120010 */
{ /* HP 1000 Loader ROM (12992F) */
IBL_START, /* loader starting index */
IBL_DMA, /* DMA index */
IBL_FWA, /* FWA index */
{ 0106710, /* 77700: ST CLC DC ; clr dch */
0106711, /* 77701: CLC CC ; clr cch */
0017757, /* 77702: JSB STAT ; get status */
0067746, /* 77703: SK LDB SKCMD ; seek cmd */
0106610, /* 77704: OTB DC ; cyl # */
0103710, /* 77705: STC DC,C ; to dch */
0106611, /* 77706: OTB CC ; seek cmd */
0103711, /* 77707: STC CC,C ; to cch */
0102310, /* 77710: SFS DC ; addr wd ok? */
0027710, /* 77711: JMP *-1 ; no, wait */
0006400, /* 77712: CLB */
0102501, /* 77713: LIA 1 ; read switches */
0002011, /* 77714: SLA,RSS ; <0> set? */
0047747, /* 77715: ADB BIT9 ; head 2 = removable */
0106610, /* 77716: OTB DC ; head/sector */
0103710, /* 77717: STC DC,C ; to dch */
0102311, /* 77720: SFS CC ; seek done? */
0027720, /* 77721: JMP *-1 ; no, wait */
0017757, /* 77722: JSB STAT ; get status */
0067776, /* 77723: LDB DMACW ; DMA control */
0106606, /* 77724: OTB 6 */
0067750, /* 77725: LDB ADDR1 ; memory addr */
0106602, /* 77726: OTB 2 */
0102702, /* 77727: STC 2 ; flip DMA ctrl */
0067752, /* 77730: LDB CNT ; word count */
0106602, /* 77731: OTB 2 */
0063745, /* 77732: LDB RDCMD ; read cmd */
0102611, /* 77733: OTA CC ; to cch */
0103710, /* 77734: STC DC,C ; start dch */
0103706, /* 77735: STC 6,C ; start DMA */
0103711, /* 77736: STC CC,C ; start cch */
0102311, /* 77737: SFS CC ; done? */
0027737, /* 77740: JMP *-1 ; no, wait */
0017757, /* 77741: JSB STAT ; get status */
0027775, /* 77742: JMP XT ; done */
0037766, /* 77743: FSMSK OCT 037766 ; status mask */
0004000, /* 77744: STMSK OCT 004000 ; unsafe mask */
0020000, /* 77745: RDCMD OCT 020000 ; read cmd */
0030000, /* 77746: SKCMD OCT 030000 ; seek cmd */
0001000, /* 77747: BIT9 OCT 001000 ; head 2 select */
0102011, /* 77750: ADDR1 OCT 102011 */
0102055, /* 77751: ADDR2 OCT 102055 */
0164000, /* 77752: CNT DEC -6144. */
0000000, /* 77753: NOP */
0000000, /* 77754: NOP */
0000000, /* 77755: NOP */
0000000, /* 77756: NOP */
0000000, /* 77757: STAT NOP */
0002400, /* 77760: CLA ; status request */
0102611, /* 77761: OTC CC ; to cch */
0103711, /* 77762: STC CC,C ; start cch */
0102310, /* 77763: SFS DC ; done? */
0027763, /* 77764: JMP *-1 */
0102510, /* 77765: LIA DC ; get status */
0013743, /* 77766: AND FSMSK ; mask 15,14,3,0 */
0002003, /* 77767: SZA,RSS ; drive ready? */
0127757, /* 77770: JMP STAT,I ; yes */
0013744, /* 77771: AND STMSK ; fault? */
0002002, /* 77772: SZA */
0102030, /* 77773: HLT 30 ; yes */
0027700, /* 77774: JMP ST ; no, retry */
0117751, /* 77775: XT JSB ADDR2,I ; start program */
0120010, /* 77776: DMACW ABS 120000+DC */
0000000 } } /* 77777: ABS -ST */
};
/* Device boot routine.
This routine is called directly by the BOOT DPC and LOAD DPC commands to copy
the device bootstrap into the upper 64 words of the logical address space.
It is also called indirectly by a BOOT CPU or LOAD CPU command when the
specified HP 1000 loader ROM socket contains a 12992F ROM.
When called in response to a BOOT DPC or LOAD DPC command, the "unitno"
parameter indicates the unit number specified in the BOOT command or is zero
for the LOAD command, and "dptr" points at the DPC device structure. The
bootstrap supports loading only from unit 0, and the command will be rejected
if another unit is specified (e.g., BOOT DPC1). Otherwise, depending on the
current CPU model, the BMDL or 12992F loader ROM will be copied into memory
and configured for the DPD/DPC select code pair. If the CPU is a 1000, the S
register will be set as it would be by the front-panel microcode.
When called for a BOOT/LOAD CPU command, the "unitno" parameter indicates the
select code to be used for configuration, and "dptr" will be NULL. As above,
the BMDL or 12992F loader ROM will be copied into memory and configured for
the specified select code. The S register is assumed to be set correctly on
entry and is not modified.
In either case, if the CPU is a 21xx model, the paper tape portion of the
BMDL will be automatically configured for the select code of the paper tape
reader.
For the 12992F boot loader ROM for the HP 1000, the S register is set as
follows:
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| ROM # | 0 0 | select code | reserved | 0 0 | S |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
Where:
S = the subchannel number
Bit 0 specifies the subchannel containing the operating system. For the
7900, either the fixed (0) or removable (1) platter may be specified. For
the 7901, bit 0 must be 1. If the -R switch is specified for the BOOT or
LOAD command, the loader ROM will be configured to boot from the removable
platter instead of the fixed platter.
Bits 5-3 are nominally zero but are reserved for the target operating system.
For example, RTE uses bit 5 to indicate whether a standard (0) or
reconfiguration (1) boot is desired.
Implementation notes:
1. In hardware, the BMDL was hand-configured for the disc and paper tape
reader select codes when it was installed on a given system. Under
simulation, the LOAD and BOOT commands automatically configure the BMDL
to the current select codes of the PTR and DP devices.
2. As installed, the BMDL is configured to read from the removable platter
(a.k.a. subchannel 1). If the -R switch is specified to read from the
fixed platter (subchannel 0), the head number in the head/sector control
word in memory is changed from 0 to 2.
*/
t_stat dpc_boot (int32 unitno, DEVICE *dptr)
{
const int32 dev = dpd_dib.select_code; /* data chan select code */
static const HP_WORD dp_preserved = 0000070u; /* S-register bits 5-3 are preserved */
const uint32 subchannel = sim_switches & SWMASK ('R') ? 1 : 0; /* the selected boot subchannel */
t_stat status;
if (unitno != 0) /* boot supported on drive unit 0 only */
return SCPE_NOFNC; /* report "Command not allowed" if attempted */
if (dptr == NULL) /* if we are being called for a BOOT/LOAD CPU */
status = cpu_copy_loader (dp_loaders, unitno, /* then copy the boot loader to memory */
IBL_S_NOCLEAR, IBL_S_NOSET); /* but do not alter the S register */
if (ibl_copy (dp_rom, dev, IBL_OPT, /* copy the boot ROM to memory and configure */
IBL_DP | IBL_SET_SC (dev) /* the S register accordingly */
| (sim_switches & SWMASK ('R') ? IBL_DP_REM : 0)))
return SCPE_IERR; /* return an internal error if the copy failed */
else
return SCPE_OK;
else if (unitno != 0) /* otherwise a BOOT DPC for a non-zero unit */
return SCPE_NOFNC; /* is rejected as unsupported */
else /* otherwise this is a BOOT/LOAD DPC */
status = cpu_copy_loader (dp_loaders, dpd_dib.select_code, /* so copy the boot loader to memory */
dp_preserved, subchannel); /* and configure the S register if 1000 CPU */
if (status == SCPE_OK && subchannel == 0 /* if loader installed OK and boot is from subchan 0 */
&& (PR & IBL_MASK) == dp_loaders [0].start_index) /* and the BMDL was installed */
mem_deposit (PR, BMDL_SUBCHANNEL_0); /* then change the control word to use head 2 */
return status; /* return the status of the installation */
}

View File

@@ -1,31 +1,37 @@
/* hp2100_dq.c: HP 2100 12565A disk simulator
/* hp2100_dq.c: HP 2100 12565A Disc Interface and 2883 disc drive simulator
Copyright (c) 1993-2006, Bill McDermith
Copyright (c) 2004-2016 J. David Bryan
Copyright (c) 2004-2018, 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 in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the authors shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from the authors.
DQ 12565A 2883 disk system
DQ 12565A Disc Interface and 2883 disc drive
27-Feb-18 JDB Added the BMDL
15-Feb-18 JDB ATTACH -N now creates a full-size disc image
03-Aug-17 JDB Changed perror call for I/O errors to cprintf
11-Jul-17 JDB Renamed "ibl_copy" to "cpu_ibl"
09-Mar-17 JDB Deprecated LOCKED/WRITEENABLED for PROTECT/UNPROTECT
27-Feb-17 JDB ibl_copy no longer returns a status code
13-May-16 JDB Modified for revised SCP API function parameter types
30-Dec-14 JDB Added S-register parameters to ibl_copy
24-Dec-14 JDB Added casts for explicit downward conversions
@@ -52,10 +58,11 @@
09-Jan-02 WOM Copied dp driver and mods for 2883
Reference:
- 12565A Disc Interface Kit Operating and Service Manual (12565-90003, Aug-1973)
- 12565A Disc Interface Kit Operating and Service Manual
(12565-90003, August 1973)
Differences between 12559/13210 and 12565 controllers
Differences between 12559/13210 and 12565 controllers:
- 12565 stops transfers on address miscompares; 12559/13210 only stops writes
- 12565 does not set error on positioner busy
- 12565 does not set positioner busy if already on cylinder
@@ -82,7 +89,12 @@
1. Read Address command starts at the sector number in the RAR.
*/
#include "hp2100_defs.h"
#include "hp2100_cpu.h"
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
#define UNIT_V_UNLOAD (UNIT_V_UF + 1) /* heads unloaded */
@@ -234,9 +246,11 @@ REG dqd_reg[] = {
{ NULL }
};
MTAB dqd_mod[] = {
{ MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &dqd_dev },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &dqd_dev },
MTAB dqd_mod [] = {
/* Entry Flags Value Print String Match String Validation Display Descriptor */
/* ------------------- ----- ------------ ------------ ------------ ------------- ---------------- */
{ MTAB_XDV, 2u, "SC", "SC", &hp_set_dib, &hp_show_dib, (void *) &dq_dib },
{ MTAB_XDV | MTAB_NMO, ~2u, "DEVNO", "DEVNO", &hp_set_dib, &hp_show_dib, (void *) &dq_dib },
{ 0 }
};
@@ -288,13 +302,20 @@ REG dqc_reg[] = {
{ NULL }
};
MTAB dqc_mod[] = {
{ UNIT_UNLOAD, UNIT_UNLOAD, "heads unloaded", "UNLOADED", dqc_load_unload },
{ UNIT_UNLOAD, 0, "heads loaded", "LOADED", dqc_load_unload },
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
{ MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &dqd_dev },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &dqd_dev },
MTAB dqc_mod [] = {
/* Mask Value Match Value Print String Match String Validation Display Descriptor */
/* ------------ ------------ ----------------- --------------- ----------------- ------- ---------- */
{ UNIT_UNLOAD, UNIT_UNLOAD, "heads unloaded", "UNLOADED", &dqc_load_unload, NULL, NULL },
{ UNIT_UNLOAD, 0, "heads loaded", "LOADED", &dqc_load_unload, NULL, NULL },
{ UNIT_WLK, UNIT_WLK, "protected", "PROTECT", NULL, NULL, NULL },
{ UNIT_WLK, 0, "unprotected", "UNPROTECT", NULL, NULL, NULL },
{ UNIT_WLK, UNIT_WLK, NULL, "LOCKED", NULL, NULL, NULL },
{ UNIT_WLK, 0, NULL, "WRITEENABLED", NULL, NULL, NULL },
/* Entry Flags Value Print String Match String Validation Display Descriptor */
/* ------------------- ----- ------------ ------------ ------------ ------------- ---------------- */
{ MTAB_XDV, 2u, "SC", "SC", &hp_set_dib, &hp_show_dib, (void *) &dq_dib },
{ MTAB_XDV | MTAB_NMO, ~2u, "DEVNO", "DEVNO", &hp_set_dib, &hp_show_dib, (void *) &dq_dib },
{ 0 }
};
@@ -821,8 +842,10 @@ dqcio (&dqc_dib, ioENF, 0); /* set cch flg */
dqc_busy = 0; /* ctlr is free */
dqd_xfer = dqd_wval = 0;
if (err != 0) { /* error? */
perror ("DQ I/O error");
clearerr (uptr->fileref);
cprintf ("%s simulator DQ disc I/O error: %s\n", /* then report the error to the console */
sim_name, strerror (errno));
clearerr (uptr->fileref); /* clear the error */
return SCPE_IOERR;
}
return SCPE_OK;
@@ -864,15 +887,43 @@ for (drv = 0; drv < DQ_NUMDRV; drv++) { /* loop thru drives */
return SCPE_OK;
}
/* Attach routine */
/* Attach a drive unit.
The specified file is attached to the indicated drive unit, and the heads are
loaded. If a new file is specified, the file is initialized to its capacity
by writing a zero to the last byte in the file.
Implementation notes:
1. The C standard says, "A binary stream need not meaningfully support fseek
calls with a whence value of SEEK_END," so instead we determine the
offset from the start of the file to the last byte and seek there.
*/
t_stat dqc_attach (UNIT *uptr, CONST char *cptr)
{
t_stat r;
t_stat result;
t_addr offset;
const uint8 zero = 0;
r = attach_unit (uptr, cptr); /* attach unit */
if (r == SCPE_OK) dqc_load_unload (uptr, 0, NULL, NULL);/* if OK, load heads */
return r;
result = attach_unit (uptr, cptr); /* attach the drive */
if (result == SCPE_OK) { /* if the attach was successful */
dqc_load_unload (uptr, 0, NULL, NULL); /* then load the heads */
if (sim_switches & SWMASK ('N')) { /* if this is a new disc image */
offset = (t_addr) /* then determine the offset of */
(uptr->capac * sizeof (int16) - sizeof zero); /* the last byte in a full-sized file */
if (sim_fseek (uptr->fileref, offset, SEEK_SET) != 0 /* seek to the last byte */
|| fwrite (&zero, sizeof zero, 1, uptr->fileref) == 0 /* and write a zero to fill */
|| fflush (uptr->fileref) != 0) /* the file to its capacity */
clearerr (uptr->fileref); /* clear and ignore any errors */
}
}
return result; /* return the result of the attach */
}
/* Detach routine */
@@ -894,85 +945,227 @@ else uptr->flags = uptr->flags & ~UNIT_UNLOAD; /* indicate load */
return SCPE_OK;
}
/* 7900/7901/2883/2884 bootstrap routine (HP 12992A ROM) */
const BOOT_ROM dq_rom = {
0102501, /*ST LIA 1 ; get switches */
0106501, /* LIB 1 */
0013765, /* AND D7 ; isolate hd */
0005750, /* BLF,CLE,SLB */
0027741, /* JMP RD */
0005335, /* RBR,SLB,ERB ; <13>->E, set = 2883 */
0027717, /* JMP IS */
0102611, /*LP OTA CC ; do 7900 status to */
0103711, /* STC CC,C ; clear first seek */
0102310, /* SFS DC */
0027711, /* JMP *-1 */
0002004, /* INA ; get next drive */
0053765, /* CPA D7 ; all cleared? */
0002001, /* RSS */
0027707, /* JMP LP */
0067761, /*IS LDB SEEKC ; get seek comnd */
0106610, /* OTB DC ; issue cyl addr (0) */
0103710, /* STC DC,C ; to dch */
0106611, /* OTB CC ; seek cmd */
0103711, /* STC CC,C ; to cch */
0102310, /* SFS DC ; addr wd ok? */
0027724, /* JMP *-1 ; no, wait */
0006400, /* CLB */
0102501, /* LIA 1 ; get switches */
0002051, /* SEZ,SLA,RSS ; subchan = 1 or ISS */
0047770, /* ADB BIT9 ; head 2 */
0106610, /* OTB DC ; head/sector */
0103710, /* STC DC,C ; to dch */
0102311, /* SFS CC ; seek done? */
0027734, /* JMP *-1 ; no, wait */
0063731, /* LDA ISSRD ; get read read */
0002341, /* SEZ,CCE,RSS ; iss disc? */
0001100, /* ARS ; no, make 7900 read */
0067776, /*RD LDB DMACW ; DMA control */
0106606, /* OTB 6 */
0067762, /* LDB ADDR1 ; memory addr */
0077741, /* STB RD ; make non re-executable */
0106602, /* OTB 2 */
0102702, /* STC 2 ; flip DMA ctrl */
0067764, /* LDB COUNT ; word count */
0106602, /* OTB 2 */
0002041, /* SEZ,RSS */
0027766, /* JMP NW */
0102611, /* OTA CC ; to cch */
0103710, /* STC DC,C ; start dch */
0103706, /* STC 6,C ; start DMA */
0103711, /* STC CC,C ; start cch */
0037773, /* ISZ SK */
0027773, /* JMP SK */
0030000, /*SEEKC 030000 */
0102011, /*ADDR1 102011 */
0102055, /*ADDR2 102055 */
0164000, /*COUNT -6144. */
0000007, /*D7 7 */
0106710, /*NW CLC DC ; set 'next wd is cmd' flag */
0001720, /* ALF,ALF ; move to head number loc */
0001000, /*BIT9 ALS */
0103610, /* OTA DC,C ; output cold load cmd */
0103706, /* STC 6,C ; start DMA */
0102310, /* SFS DC ; done? */
0027773, /* JMP *-1 ; no, wait */
0117763, /*XT JSB ADDR2,I ; start program */
0120010, /*DMACW 120000+DC */
0000000 /* -ST */
/* 2883 disc bootstrap loaders (BMDL and 12992A).
The Basic Moving-Head Disc Loader (BMDL) consists of two programs. The
program starting at address x7700 loads absolute paper tapes into memory.
The program starting at address x7750 loads a disc-resident bootstrap from
the 2883 disc drive into memory. The S register setting does not affect
loader operation.
For a 2100/14/15/16 CPU, entering a LOAD DQC or BOOT DQC command loads the
BMDL into memory and executes the disc portion starting at x7750. For a 1000
CPU, the 12992A boot loader ROM is used. In either case, the bootstrap reads
128 words from cylinder 0, head 0, sector 0 into memory starting at location
2011 octal. Loader execution ends with the following instruction:
* JMP 2055,I - the disc read completed.
Note that the BMDL does a JMP 2055,I and the 12992A does a JSB 2055,I.
*/
static const LOADER_ARRAY dq_loaders = {
{ /* HP 21xx Basic Moving-Head Disc Loader (BMDL-2883) */
050, /* loader starting index */
076, /* DMA index */
077, /* FWA index */
{ 0002701, /* 77700: PTAPE CLA,CCE,RSS Paper Tape start */
0063722, /* 77701: LDA 77722 */
0002307, /* 77702: CCE,INA,SZA,RSS */
0102077, /* 77703: HLT 77 */
0017735, /* 77704: JSB 77735 */
0007307, /* 77705: CMB,CCE,INB,SZB,RSS */
0027702, /* 77706: JMP 77702 */
0077733, /* 77707: STB 77733 */
0017735, /* 77710: JSB 77735 */
0017735, /* 77711: JSB 77735 */
0074000, /* 77712: STB 0 */
0077734, /* 77713: STB 77734 */
0067734, /* 77714: LDB 77734 */
0047777, /* 77715: ADB 77777 */
0002040, /* 77716: SEZ */
0102055, /* 77717: HLT 55 */
0017735, /* 77720: JSB 77735 */
0040001, /* 77721: ADA 1 */
0177734, /* 77722: STB 77734,I */
0037734, /* 77723: ISZ 77734 */
0000040, /* 77724: CLE */
0037733, /* 77725: ISZ 77733 */
0027714, /* 77726: JMP 77714 */
0017735, /* 77727: JSB 77735 */
0054000, /* 77730: CPB 0 */
0027701, /* 77731: JMP 77701 */
0102011, /* 77732: HLT 11 */
0000000, /* 77733: NOP */
0000000, /* 77734: NOP */
0000000, /* 77735: NOP */
0006600, /* 77736: CLB,CME */
0103710, /* 77737: STC 10,C */
0102310, /* 77740: SFS 10 */
0027740, /* 77741: JMP 77740 */
0106410, /* 77742: MIB 10 */
0002041, /* 77743: SEZ,RSS */
0127735, /* 77744: JMP 77735,I */
0005767, /* 77745: BLF,CLE,BLF */
0027737, /* 77746: JMP 77737 */
0177600, /* 77747: OCT 177600 */
0063775, /* 77750: DISC LDA 77775 Disc start */
0102611, /* 77751: OTA 11 */
0103711, /* 77752: STC 11,C */
0102311, /* 77753: SFS 11 */
0027753, /* 77754: JMP 77753 */
0067776, /* 77755: LDB 77776 */
0106606, /* 77756: OTB 6 */
0067732, /* 77757: LDB 77732 */
0106602, /* 77760: OTB 2 */
0102702, /* 77761: STC 2 */
0067747, /* 77762: LDB 77747 */
0106602, /* 77763: OTB 2 */
0001000, /* 77764: ALS */
0106711, /* 77765: CLC 11 */
0102611, /* 77766: OTA 11 */
0103710, /* 77767: STC 10,C */
0103706, /* 77770: STC 6,C */
0103711, /* 77771: STC 11,C */
0102311, /* 77772: SFS 11 */
0027772, /* 77773: JMP 77772 */
0127717, /* 77774: JMP 77717,I */
0020000, /* 77775: OCT 020000 */
0120010, /* 77776: ABS 120000+DC */
0100100 } }, /* 77777: ABS -PTAPE */
{ /* HP 1000 Loader ROM (12992A) */
IBL_START, /* loader starting index */
IBL_DMA, /* DMA index */
IBL_FWA, /* FWA index */
{ 0102501, /* 77700: ST LIA 1 ; get switches */
0106501, /* 77701: LIB 1 */
0013765, /* 77702: AND D7 ; isolate hd */
0005750, /* 77703: BLF,CLE,SLB */
0027741, /* 77704: JMP RD */
0005335, /* 77705: RBR,SLB,ERB ; <13>->E, set = 2883 */
0027717, /* 77706: JMP IS */
0102611, /* 77707: LP OTA CC ; do 7900 status to */
0103711, /* 77710: STC CC,C ; clear first seek */
0102310, /* 77711: SFS DC */
0027711, /* 77712: JMP *-1 */
0002004, /* 77713: INA ; get next drive */
0053765, /* 77714: CPA D7 ; all cleared? */
0002001, /* 77715: RSS */
0027707, /* 77716: JMP LP */
0067761, /* 77717: IS LDB SEEKC ; get seek comnd */
0106610, /* 77720: OTB DC ; issue cyl addr (0) */
0103710, /* 77721: STC DC,C ; to dch */
0106611, /* 77722: OTB CC ; seek cmd */
0103711, /* 77723: STC CC,C ; to cch */
0102310, /* 77724: SFS DC ; addr wd ok? */
0027724, /* 77725: JMP *-1 ; no, wait */
0006400, /* 77726: CLB */
0102501, /* 77727: LIA 1 ; get switches */
0002051, /* 77730: SEZ,SLA,RSS ; subchan = 1 or ISS */
0047770, /* 77731: ADB BIT9 ; head 2 */
0106610, /* 77732: OTB DC ; head/sector */
0103710, /* 77733: STC DC,C ; to dch */
0102311, /* 77734: SFS CC ; seek done? */
0027734, /* 77735: JMP *-1 ; no, wait */
0063731, /* 77736: LDA ISSRD ; get read read */
0002341, /* 77737: SEZ,CCE,RSS ; iss disc? */
0001100, /* 77740: ARS ; no, make 7900 read */
0067776, /* 77741: RD LDB DMACW ; DMA control */
0106606, /* 77742: OTB 6 */
0067762, /* 77743: LDB ADDR1 ; memory addr */
0077741, /* 77744: STB RD ; make non re-executable */
0106602, /* 77745: OTB 2 */
0102702, /* 77746: STC 2 ; flip DMA ctrl */
0067764, /* 77747: LDB COUNT ; word count */
0106602, /* 77750: OTB 2 */
0002041, /* 77751: SEZ,RSS */
0027766, /* 77752: JMP NW */
0102611, /* 77753: OTA CC ; to cch */
0103710, /* 77754: STC DC,C ; start dch */
0103706, /* 77755: STC 6,C ; start DMA */
0103711, /* 77756: STC CC,C ; start cch */
0037773, /* 77757: ISZ SK */
0027773, /* 77760: JMP SK */
0030000, /* 77761: SEEKC OCT 030000 */
0102011, /* 77762: ADDR1 OCT 102011 */
0102055, /* 77763: ADDR2 OCT 102055 */
0164000, /* 77764: COUNT DEC -6144. */
0000007, /* 77765: D7 DEC 7 */
0106710, /* 77766: NW CLC DC ; set 'next wd is cmd' flag */
0001720, /* 77767: ALF,ALF ; move to head number loc */
0001000, /* 77770: BIT9 ALS */
0103610, /* 77771: OTA DC,C ; output cold load cmd */
0103706, /* 77772: STC 6,C ; start DMA */
0102310, /* 77773: SFS DC ; done? */
0027773, /* 77774: JMP *-1 ; no, wait */
0117763, /* 77775: XT JSB ADDR2,I ; start program */
0120010, /* 77776: DMACW ABS 120000+DC */
0170100 } } /* 77777: MAXAD ABS -ST ; max addr */
};
/* Device boot routine.
This routine is called directly by the BOOT DQC and LOAD DQC commands to copy
the device bootstrap into the upper 64 words of the logical address space.
It is also called indirectly by a BOOT CPU or LOAD CPU command when the
specified HP 1000 loader ROM socket contains a 12992A ROM.
When called in response to a BOOT DQC or LOAD DQC command, the "unitno"
parameter indicates the unit number specified in the BOOT command or is zero
for the LOAD command, and "dptr" points at the DQC device structure. The
bootstrap supports loading only from unit 0, and the command will be rejected
if another unit is specified (e.g., BOOT DQC1). Otherwise, depending on the
current CPU model, the BMDL or 12992A loader ROM will be copied into memory
and configured for the DQD/DQC select code pair. If the CPU is a 1000, the S
register will be set as it would be by the front-panel microcode.
When called for a BOOT/LOAD CPU command, the "unitno" parameter indicates the
select code to be used for configuration, and "dptr" will be NULL. As above,
the BMDL or 12992A loader ROM will be copied into memory and configured for
the specified select code. The S register is assumed to be set correctly on
entry and is not modified.
In either case, if the CPU is a 21xx model, the paper tape portion of the
BMDL will be automatically configured for the select code of the paper tape
reader.
For the 12992A boot loader ROM for the HP 1000, the S register is set as
follows:
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| ROM # | 1 0 | select code | reserved | 0 0 0 |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
Bits 5-3 are nominally zero but are reserved for the target operating system.
For example, RTE uses bit 5 to indicate whether a standard (0) or
reconfiguration (1) boot is desired.
Implementation notes:
1. In hardware, the BMDL was hand-configured for the disc and paper tape
reader select codes when it was installed on a given system. Under
simulation, the LOAD and BOOT commands automatically configure the BMDL
to the current select codes of the PTR and DQ devices.
*/
t_stat dqc_boot (int32 unitno, DEVICE *dptr)
{
const int32 dev = dqd_dib.select_code; /* data chan select code */
static const HP_WORD dq_preserved = 0000070u; /* S-register bits 5-3 are preserved */
static const HP_WORD dq_standard = 0020000u; /* S-register bit 13 set for a standard boot */
if (unitno != 0) /* boot supported on drive unit 0 only */
return SCPE_NOFNC; /* report "Command not allowed" if attempted */
if (dptr == NULL) /* if we are being called for a BOOT/LOAD CPU */
return cpu_copy_loader (dq_loaders, unitno, /* then copy the boot loader to memory */
IBL_S_NOCLEAR, IBL_S_NOSET); /* but do not alter the S register */
if (ibl_copy (dq_rom, dev, IBL_OPT, /* copy the boot ROM to memory and configure */
IBL_DQ | IBL_SET_SC (dev))) /* the S register accordingly */
return SCPE_IERR; /* return an internal error if the copy failed */
else
return SCPE_OK;
else if (unitno != 0) /* otherwise a BOOT DQC for a non-zero unit */
return SCPE_NOFNC; /* is rejected as unsupported */
else /* otherwise this is a BOOT/LOAD DQC */
return cpu_copy_loader (dq_loaders, dqd_dib.select_code, /* so copy the boot loader to memory */
dq_preserved, dq_standard); /* and configure the S register if 1000 CPU */
}

View File

@@ -1,31 +1,37 @@
/* hp2100_dr.c: HP 2100 12606B/12610B fixed head disk/drum simulator
Copyright (c) 1993-2016, Robert M. Supnik
Copyright (c) 2017-2018, 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 in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not be
Except as contained in this notice, the names of the authors shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
in this Software without prior written authorization from the authors.
DR 12606B 2770/2771 fixed head disk
12610B 2773/2774/2775 drum
27-Feb-18 JDB Added the BBDL, reworked drc_boot to use cpu_copy_loader
21-Feb-18 JDB ATTACH -N now creates a full-size disc image
19-Jul-17 JDB Removed "dr_stopioe" variable and register
11-Jul-17 JDB Renamed "ibl_copy" to "cpu_ibl"
27-Feb-17 JDB ibl_copy no longer returns a status code
10-Nov-16 JDB Modified the drc_boot routine to use the BBDL
05-Aug-16 JDB Renamed the P register from "PC" to "PR"
13-May-16 JDB Modified for revised SCP API function parameter types
@@ -109,10 +115,14 @@
- inst timing = 6 inst/word, 12288 inst/revolution
*/
#include "hp2100_defs.h"
#include "hp2100_cpu.h"
#include <math.h>
/* Constants */
#define DR_NUMWD 64 /* words/sector */
@@ -195,7 +205,6 @@ int32 drd_ibuf = 0; /* input buffer */
int32 drd_obuf = 0; /* output buffer */
int32 drd_ptr = 0; /* sector pointer */
int32 drc_pcount = 1; /* number of prot tracks */
int32 dr_stopioe = 1; /* stop on error */
int32 dr_time = DR_DTIME; /* time per word */
static int32 sz_tab[16] = {
@@ -252,8 +261,8 @@ REG drd_reg[] = {
};
MTAB drd_mod[] = {
{ MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &drd_dev },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &drd_dev },
{ MTAB_XTD | MTAB_VDV, 2u, "SC", "SC", &hp_set_dib, &hp_show_dib, (void *) &dr_dib },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, ~2u, "DEVNO", "DEVNO", &hp_set_dib, &hp_show_dib, (void *) &dr_dib },
{ 0 }
};
@@ -284,7 +293,6 @@ REG drc_reg[] = {
{ ORDATA (STA, drc_sta, 16) },
{ FLDATA (RUN, drc_run, 0) },
{ DRDATA (TIME, dr_time, 24), REG_NZ + PV_LEFT },
{ FLDATA (STOP_IOE, dr_stopioe, 0) },
{ ORDATA (SC, drc_dib.select_code, 6), REG_HRO },
{ ORDATA (DEVNO, drc_dib.select_code, 6), REG_HRO },
{ DRDATA (CAPAC, drc_unit.capac, 24), REG_HRO },
@@ -308,8 +316,8 @@ MTAB drc_mod[] = {
{ UNIT_PROT, 0, "unprotected", "UNPROTECTED", NULL },
{ MTAB_XTD | MTAB_VDV, 0, "TRACKPROT", "TRACKPROT",
&dr_set_prot, &dr_show_prot, NULL },
{ MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &drd_dev },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &drd_dev },
{ MTAB_XTD | MTAB_VDV, 2u, "SC", "SC", &hp_set_dib, &hp_show_dib, (void *) &dr_dib },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, ~2u, "DEVNO", "DEVNO", &hp_set_dib, &hp_show_dib, (void *) &dr_dib },
{ 0 }
};
@@ -522,7 +530,7 @@ uint16 *bptr = (uint16 *) uptr->filebuf;
if ((uptr->flags & UNIT_ATT) == 0) {
drc_sta = DRS_ABO;
return IOERROR (dr_stopioe, SCPE_UNATT);
return SCPE_OK;
}
trk = CW_GETTRK (drc_cw);
@@ -631,15 +639,29 @@ sim_cancel (&drd_unit[TMR_INH]);
return SCPE_OK;
}
/* Attach routine */
/* Attach a drive unit.
The specified file is attached to the indicated drive unit. If a new file is
specified, the file is initialized to its capacity by setting the high-water
mark to the last byte in the file.
*/
t_stat drc_attach (UNIT *uptr, CONST char *cptr)
{
int32 sz = sz_tab[DR_GETSZ (uptr->flags)];
t_stat result;
const int32 sz = sz_tab [DR_GETSZ (uptr->flags)];
if (sz == 0) return SCPE_IERR;
uptr->capac = sz;
return attach_unit (uptr, cptr);
if (sz == 0)
return SCPE_IERR;
else
uptr->capac = sz;
result = attach_unit (uptr, cptr); /* attach the drive */
if (result == SCPE_OK && (sim_switches & SWMASK ('N'))) /* if the attach was successful and a new image was specified */
uptr->hwmark = (uint32) uptr->capac; /* then set the high-water mark to the last byte */
return result; /* return the result of the attach */
}
/* Set protected track count */
@@ -706,126 +728,159 @@ return SCPE_OK;
}
/* Basic Binary Disc Loader.
/* 277x fixed disc/drum bootstrap loaders (BBDL).
The Basic Binary Disc Loader (BBDL) contains two programs. The program
The Basic Binary Disc Loader (BBDL) consists of two programs. The program
starting at address x7700 loads absolute paper tapes into memory. The
program starting at address x7760 loads a disc-resident bootstrap from the
277x fixed-head disc/drum. Entering a BOOT DRC command loads the BBDL into
memory and executes the disc portion starting at x7760. The bootstrap issues
a CLC 0,C to clear the disc track and sector address registers and then sets
up a 64-word read from track 0 sector 0 to memory locations 0-77 octal. It
then stores a JMP * instruction in location 77, starts the read, and jumps to
277x fixed-head disc/drum into memory. The S register setting does not
affect loader operation.
Entering a LOAD DRC or BOOT DRC command loads the BBDL into memory and
executes the disc portion starting at x7760. The bootstrap issues a CLC 0,C
to clear the disc track and sector address registers and then sets up a
64-word read from track 0 sector 0 to memory locations 0-77 octal. It then
stores a JMP * instruction in location 77, starts the read, and jumps to
location 77. The JMP * causes the CPU to loop until the last word read from
the disc overlays location 77 which, typically, would be a JMP instruction to
the start of the disc-resident bootstrap.
the disc extension overlays location 77 which, typically, would be a JMP
instruction to the start of the disc-resident bootstrap. The success or
failure of the transfer is not checked.
In hardware, the BBDL was hand-configured for the disc and paper tape reader
select codes when it was installed on a given system. Under simulation, we
treat it as a standard HP 1000 loader, even though it is not structured that
way, and so the ibl_copy mechanism used to load and configure it must be
augmented to account for the differences.
The HP 1000 does not support the 277x drives, so there is no 1000 boot loader
ROM for these peripherals. Attempting to LOAD DRC or BOOT DRC while the CPU
is configured as a 1000 will be rejected.
Implementaion notes:
Implementation notes:
1. The full BBDL is loaded into memory, even though only the disc portion
will be used.
1. After the BBDL is loaded into memory, the paper tape portion may be
executed manually by setting the P register to the starting address
(x7700).
2. For compatibility with the ibl_copy routine, the loader has been changed
from the standard HP version. The device I/O instructions are modified
to address locations 10 and 11.
2. For compatibility with the cpu_copy_loader routine, the BBDL has been
altered from the standard HP version. The device I/O instructions are
modified to address select codes 10 and 11.
3. The "HP 20854A Timeshared BASIC/2000, Level F System Operator's Manual"
(HP 02000-90074, November 1974) lists an IBL procedure for booting a 21MX
(i.e., 1000 M-Series) CPU from the fixed-head disc. However, there is no
evidence that a fixed-head disc boot loader ROM ever existed. Moreover,
the procedure listed is suspicious, as it specifies the command channel
select code instead of the data channel select code, so I/O instruction
configuration would be incorrect. Also, the equivalent 2100 boot
procedure printed adjacently gives the wrong BBDL starting address (it is
listed correctly in the 1973 version of the manual). Actually, the 21MX
and 2100 procedures appear to be verbatim copies of the moving-head disc
boot procedures listed two pages earlier. Consequently, it would appear
that 21MX-based 2000 F TSB systems with fixed-head drives must boot from
paper tape.
*/
static const BOOT_ROM dr_rom = {
0107700, /* ST2 CLC 0,C START OF PAPER TAPE LOADER */
0002401, /* CLA,RSS */
0063726, /* CONT2 LDA CM21 */
0006700, /* CLB,CCE */
0017742, /* JSB READ2 */
0007306, /* LEDR2 CMB,CCE,INB,SZB */
0027713, /* JMP RECL2 */
0002006, /* EOTC2 INA,SZA */
0027703, /* JMP CONT2+1 */
0102077, /* HLT 77B */
0027700, /* JMP ST2 */
0077754, /* RECL2 STB CNT2 */
0017742, /* JSB READ2 */
0017742, /* JSB READ2 */
0074000, /* STB A */
0077757, /* STB ADR11 */
0067757, /* SUCID LDB ADR11 */
0047755, /* ADB MAXAD */
0002040, /* SEZ */
0027740, /* JMP RESCU */
0017742, /* LOAD2 JSB READ2 */
0040001, /* ADA B */
0177757, /* CM21 STB ADR11,I */
0037757, /* ISZ ADR11 */
0000040, /* CLE */
0037754, /* ISZ CNT2 */
0027720, /* JMP SUCID */
0017742, /* JSB READ2 */
0054000, /* CPB A */
0027702, /* JMP CONT2 */
0102011, /* HLT 11B */
0027700, /* JMP ST2 */
0102055, /* RESCU HLT 55B */
0027700, /* JMP ST2 */
0000000, /* READ2 NOP */
0006600, /* CLB,CME */
0103710, /* RED2 STC PR,C */
0102310, /* SFS PR */
0027745, /* JMP *-1 */
0107410, /* MIB PR,C */
0002041, /* SEZ,RSS */
0127742, /* JMP READ2,I */
0005767, /* BLF,CLE,BLF */
0027744, /* JMP RED2 */
0000000, /* CNT2 NOP */
0000000, /* MAXAD NOP */
0020000, /* CWORD ABS 20000B+DC */
0000000, /* ADR11 NOP */
static const LOADER_ARRAY dr_loaders = {
{ /* HP 21xx Basic Binary Disc Loader (BBDL) */
060, /* loader starting index */
056, /* DMA index */
055, /* FWA index */
{ 0107700, /* 77700: ST2 CLC 0,C START OF PAPER TAPE LOADER */
0002401, /* 77701: CLA,RSS */
0063726, /* 77702: CONT2 LDA CM21 */
0006700, /* 77703: CLB,CCE */
0017742, /* 77704: JSB READ2 */
0007306, /* 77705: LEDR2 CMB,CCE,INB,SZB */
0027713, /* 77706: JMP RECL2 */
0002006, /* 77707: EOTC2 INA,SZA */
0027703, /* 77710: JMP CONT2+1 */
0102077, /* 77711: HLT 77B */
0027700, /* 77712: JMP ST2 */
0077754, /* 77713: RECL2 STB CNT2 */
0017742, /* 77714: JSB READ2 */
0017742, /* 77715: JSB READ2 */
0074000, /* 77716: STB A */
0077757, /* 77717: STB ADR11 */
0067757, /* 77720: SUCID LDB ADR11 */
0047755, /* 77721: ADB MAXAD */
0002040, /* 77722: SEZ */
0027740, /* 77723: JMP RESCU */
0017742, /* 77724: LOAD2 JSB READ2 */
0040001, /* 77725: ADA B */
0177757, /* 77726: CM21 STB ADR11,I */
0037757, /* 77727: ISZ ADR11 */
0000040, /* 77730: CLE */
0037754, /* 77731: ISZ CNT2 */
0027720, /* 77732: JMP SUCID */
0017742, /* 77733: JSB READ2 */
0054000, /* 77734: CPB A */
0027702, /* 77735: JMP CONT2 */
0102011, /* 77736: HLT 11B */
0027700, /* 77737: JMP ST2 */
0102055, /* 77740: RESCU HLT 55B */
0027700, /* 77741: JMP ST2 */
0000000, /* 77742: READ2 NOP */
0006600, /* 77743: CLB,CME */
0103710, /* 77744: RED2 STC PR,C */
0102310, /* 77745: SFS PR */
0027745, /* 77746: JMP *-1 */
0107410, /* 77747: MIB PR,C */
0002041, /* 77750: SEZ,RSS */
0127742, /* 77751: JMP READ2,I */
0005767, /* 77752: BLF,CLE,BLF */
0027744, /* 77753: JMP RED2 */
0000000, /* 77754: CNT2 NOP */
0000000, /* 77755: MAXAD NOP */
0020010, /* 77756: CWORD ABS 20000B+DC */
0000000, /* 77757: ADR11 NOP */
0107700, /* 77760: DLDR CLC 0,C START OF FIXED DISC LOADER */
0063756, /* 77761: LDA CWORD */
0102606, /* 77762: OTA 6 */
0002700, /* 77763: CLA,CCE */
0102611, /* 77764: OTA CC */
0001500, /* 77765: ERA */
0102602, /* 77766: OTA 2 */
0063777, /* 77767: LDA WRDCT */
0102702, /* 77770: STC 2 */
0102602, /* 77771: OTA 2 */
0103706, /* 77772: STC 6,C */
0102710, /* 77773: STC DC */
0067776, /* 77774: LDB JMP77 */
0074077, /* 77775: STB 77B */
0024077, /* 77776: JMP77 JMP 77B */
0177700 } }, /* 77777: WRDCT OCT -100 */
0107700, /* DLDR CLC 0,C START OF FIXED DISC LOADER */
0063756, /* LDA CWORD */
0102606, /* OTA 6 */
0002700, /* CLA,CCE */
0102611, /* OTA CC */
0001500, /* ERA */
0102602, /* OTA 2 */
0063777, /* LDA WRDCT */
0102702, /* STC 2 */
0102602, /* OTA 2 */
0103706, /* STC 6,C */
0102710, /* STC DC */
0067776, /* LDB JMP77 */
0074077, /* STB 77B */
0024077, /* JMP77 JMP 77B */
0177700 /* WRDCT OCT -100 */
{ /* HP 1000 Loader ROM does not exist */
IBL_NA, /* loader starting index */
IBL_NA, /* DMA index */
IBL_NA, /* FWA index */
{ 0 } }
};
#define BBDL_MAX_ADDR 0000055 /* ROM index of the maximum address word */
#define BBDL_DMA_CNTL 0000056 /* ROM index of the DMA control word */
#define BBDL_DISC_START 0000060 /* ROM index of the disc loader */
/* Device boot routine.
This routine is called by the LOAD DRC and BOOT DRC commands to copy the
device bootstrap into the upper 64 words of the logical address space. On
entry, the "unitno" parameter is checked to ensure that it is 0, as the
bootstrap only loads from unit 0. Then the BBDL is loaded into memory, the
disc portion is configured for the DRD/DRC select code pair, and the paper
tape portion is configured for the select code of the paper tape reader.
Implementation notes:
1. The fixed-head disc/drum device is not supported on the HP 1000, so this
routine cannot be called by a BOOT CPU or LOAD CPU command.
2. In hardware, the BBDL was hand-configured for the disc and paper tape
reader select codes when it was installed on a given system. Under
simulation, the LOAD and BOOT commands automatically configure the BBDL
to the current select codes of the PTR and DR devices.
*/
t_stat drc_boot (int32 unitno, DEVICE *dptr)
{
const int32 dev = drd_dib.select_code; /* data chan select code */
if (unitno != 0) /* a BOOT DRC for a non-zero unit */
return SCPE_NOFNC; /* is rejected as unsupported */
if (unitno != 0) /* boot supported on drive unit 0 only */
return SCPE_NOFNC; /* report "Command not allowed" if attempted */
if (ibl_copy (dr_rom, dev, IBL_S_NOCLR, IBL_S_NOSET)) /* copy the boot ROM to memory and configure */
return SCPE_IERR; /* return an internal error if the copy failed */
WritePW (PR + BBDL_MAX_ADDR, ReadPW (PR + IBL_END)); /* move the maximum address word */
WritePW (PR + BBDL_DMA_CNTL, dr_rom [BBDL_DMA_CNTL] + dev); /* set up the DMA control word */
WritePW (PR + IBL_DPC, dr_rom [IBL_DPC]); /* restore the overwritten word */
WritePW (PR + IBL_END, dr_rom [IBL_END]); /* restore the overwritten word */
PR = PR + BBDL_DISC_START; /* select the starting address */
return SCPE_OK;
else /* otherwise this is a BOOT/LOAD DRC */
return cpu_copy_loader (dr_loaders, drd_dib.select_code, /* so copy the boot loader to memory */
IBL_S_NOCLEAR, IBL_S_NOSET); /* and preserve the S register */
}

View File

@@ -1,7 +1,7 @@
/* hp2100_ds.c: HP 13037D/13175D disc controller/interface simulator
Copyright (c) 2004-2012, Robert M. Supnik
Copyright (c) 2012-2016 J. David Bryan
Copyright (c) 2012-2018 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"),
@@ -26,6 +26,14 @@
DS 13037D/13175D disc controller/interface
07-May-18 JDB Removed "dl_clear_controller" status return
27-Feb-18 JDB Added the BMDL
21-Feb-18 JDB ATTACH -N now creates a full-size disc image
11-Jul-17 JDB Renamed "ibl_copy" to "cpu_ibl"
15-Mar-17 JDB Trace flags are now global
Changed DEBUG_PRI calls to tprintfs
10-Mar-17 JDB Added IOBUS to the debug table
09-Mar-17 JDB Deprecated LOCKED/WRITEENABLED for PROTECT/UNPROTECT
13-May-16 JDB Modified for revised SCP API function parameter types
04-Mar-16 JDB Name changed to "hp2100_disclib" until HP 3000 integration
30-Dec-14 JDB Added S-register parameters to ibl_copy
@@ -122,6 +130,7 @@
#include "hp2100_defs.h"
#include "hp2100_cpu.h"
#include "hp2100_disclib.h"
@@ -142,16 +151,6 @@
#define PRESET_ENABLE TRUE /* Preset Jumper (W4) is enabled */
/* Debug flags */
#define DEB_CPU (1 << 0) /* words received from and sent to the CPU */
#define DEB_CMDS (1 << 1) /* interface commands received from the CPU */
#define DEB_BUF (1 << 2) /* data read from and written to the card FIFO */
#define DEB_RWSC (1 << 3) /* device read/write/status/control commands */
#define DEB_SERV (1 << 4) /* unit service scheduling calls */
/* Per-card state variables */
typedef struct {
@@ -305,17 +304,23 @@ static REG ds_reg [] = {
};
static MTAB ds_mod [] = {
/* mask match pstring mstring valid disp desc */
{ UNIT_UNLOAD, UNIT_UNLOAD, "heads unloaded", "UNLOADED", &ds_load_unload, NULL, NULL },
{ UNIT_UNLOAD, 0, "heads loaded", "LOADED", &ds_load_unload, NULL, NULL },
/* Mask Value Match Value Print String Match String Validation Display Descriptor */
/* ------------ ------------ ----------------- --------------- ---------------- ------- ---------- */
{ UNIT_UNLOAD, UNIT_UNLOAD, "heads unloaded", "UNLOADED", &ds_load_unload, NULL, NULL },
{ UNIT_UNLOAD, 0, "heads loaded", "LOADED", &ds_load_unload, NULL, NULL },
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL, NULL, NULL },
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL, NULL, NULL },
{ UNIT_WLK, UNIT_WLK, "protected", "PROTECT", NULL, NULL, NULL },
{ UNIT_WLK, 0, "unprotected", "UNPROTECT", NULL, NULL, NULL },
{ UNIT_FMT, UNIT_FMT, "format enabled", "FORMAT", NULL, NULL, NULL },
{ UNIT_FMT, 0, "format disabled", "NOFORMAT", NULL, NULL, NULL },
{ UNIT_WLK, UNIT_WLK, NULL, "LOCKED", NULL, NULL, NULL },
{ UNIT_WLK, 0, NULL, "WRITEENABLED", NULL, NULL, NULL },
/* mask match pstring mstring valid disp desc */
{ UNIT_FMT, UNIT_FMT, "format enabled", "FORMAT", NULL, NULL, NULL },
{ UNIT_FMT, 0, "format disabled", "NOFORMAT", NULL, NULL, NULL },
/* Print Match */
/* Mask Value Match Value String String Validation Disp Desc */
/* --------------------------------- --------------------- ---------- ---------- ------------- ---- ---- */
{ UNIT_AUTO | UNIT_ATT, UNIT_AUTO, "autosize", "AUTOSIZE", &dl_set_model, NULL, NULL },
{ UNIT_AUTO | UNIT_ATT | UNIT_MODEL, MODEL_7905, "7905", "7905", &dl_set_model, NULL, NULL },
{ UNIT_AUTO | UNIT_ATT | UNIT_MODEL, MODEL_7906, "7906", "7906", &dl_set_model, NULL, NULL },
@@ -326,18 +331,21 @@ static MTAB ds_mod [] = {
{ UNIT_ATT | UNIT_MODEL, UNIT_ATT | MODEL_7920, "7920", NULL, NULL, NULL, NULL },
{ UNIT_ATT | UNIT_MODEL, UNIT_ATT | MODEL_7925, "7925", NULL, NULL, NULL, NULL },
{ MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &ds_dev },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &ds_dev },
/* Entry Flags Value Print String Match String Validation Display Descriptor */
/* ------------------- ----- ------------ ------------ ------------ ------------- ---------------- */
{ MTAB_XDV, 1u, "SC", "SC", &hp_set_dib, &hp_show_dib, (void *) &ds_dib },
{ MTAB_XDV | MTAB_NMO, ~1u, "DEVNO", "DEVNO", &hp_set_dib, &hp_show_dib, (void *) &ds_dib },
{ 0 }
};
static DEBTAB ds_deb [] = {
{ "CPU", DEB_CPU },
{ "CMDS", DEB_CMDS },
{ "BUF", DEB_BUF },
{ "RWSC", DEB_RWSC },
{ "SERV", DEB_SERV },
{ NULL, 0 }
{ "RWSC", DEB_RWSC },
{ "CMDS", DEB_CMDS },
{ "CPU", DEB_CPU },
{ "BUF", DEB_BUF },
{ "SERV", DEB_SERV },
{ "IOBUS", TRACE_IOBUS },
{ NULL, 0 }
};
DEVICE ds_dev = {
@@ -431,7 +439,6 @@ static const char * const output_state [] = { "Data", "Command" };
const char * const hold_or_clear = (signal_set & ioCLF ? ",C" : "");
uint16 data;
t_stat status;
IOSIGNAL signal;
IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
t_bool command_issued = FALSE;
@@ -446,8 +453,7 @@ while (working_set) {
ds.flag = CLEAR; /* clear the flag */
ds.flagbuf = CLEAR; /* and flag buffer */
if (DEBUG_PRI (ds_dev, DEB_CMDS))
fputs (">>DS cmds: [CLF] Flag cleared\n", sim_deb);
tprintf (ds_dev, DEB_CMDS, "[CLF] Flag cleared\n");
break;
@@ -456,8 +462,7 @@ while (working_set) {
ds.flag = SET; /* set the flag */
ds.flagbuf = SET; /* and flag buffer */
if (DEBUG_PRI (ds_dev, DEB_CMDS))
fputs (">>DS cmds: [STF] Flag set\n", sim_deb);
tprintf (ds_dev, DEB_CMDS, "[STF] Flag set\n");
break;
@@ -475,12 +480,11 @@ while (working_set) {
data = fifo_unload (); /* unload the next word from the FIFO */
stat_data = IORETURN (SCPE_OK, data); /* merge in the return status */
if (DEBUG_PRI (ds_dev, DEB_CPU))
fprintf (sim_deb, ">>DS cpu: [LIx%s] Data = %06o\n", hold_or_clear, data);
tprintf (ds_dev, DEB_CPU, "[LIx%s] Data = %06o\n", hold_or_clear, data);
if (FIFO_EMPTY) { /* is the FIFO now empty? */
if (ds.srq == SET && DEBUG_PRI (ds_dev, DEB_CMDS))
fprintf (sim_deb, ">>DS cmds: [LIx%s] SRQ cleared\n", hold_or_clear);
if (ds.srq == SET)
tprintf (ds_dev, DEB_CMDS, "[LIx%s] SRQ cleared\n", hold_or_clear);
ds.srq = CLEAR; /* clear SRQ */
@@ -495,9 +499,8 @@ while (working_set) {
case ioIOO: /* I/O data output */
data = IODATA (stat_data); /* mask to just the data word */
if (DEBUG_PRI (ds_dev, DEB_CPU))
fprintf (sim_deb, ">>DS cpu: [OTx%s] %s = %06o\n",
hold_or_clear, output_state [ds.cmfol], data);
tprintf (ds_dev, DEB_CPU, "[OTx%s] %s = %06o\n",
hold_or_clear, output_state [ds.cmfol], data);
fifo_load (data); /* load the word into the FIFO */
@@ -514,8 +517,8 @@ while (working_set) {
}
if (FIFO_STOP) { /* is the FIFO now full enough? */
if (ds.srq == SET && DEBUG_PRI (ds_dev, DEB_CMDS))
fprintf (sim_deb, ">>DS cmds: [OTx%s] SRQ cleared\n", hold_or_clear);
if (ds.srq == SET)
tprintf (ds_dev, DEB_CMDS, "[OTx%s] SRQ cleared\n", hold_or_clear);
ds.srq = CLEAR; /* clear SRQ to stop filling */
}
@@ -528,14 +531,12 @@ while (working_set) {
ds.flagbuf = SET; /* and flag buffer */
ds.cmrdy = CLEAR; /* clear the command ready flip-flop */
if (DEBUG_PRI (ds_dev, DEB_CMDS))
fputs (">>DS cmds: [POPIO] Flag set\n", sim_deb);
tprintf (ds_dev, DEB_CMDS, "[POPIO] Flag set\n");
break;
case ioCRS: /* control reset */
if (DEBUG_PRI (ds_dev, DEB_CMDS))
fputs (">>DS cmds: [CRS] Master reset\n", sim_deb);
tprintf (ds_dev, DEB_CMDS, "[CRS] Master reset\n");
ds.control = CLEAR; /* clear the control */
ds.cmfol = CLEAR; /* and command follows flip-flops */
@@ -543,17 +544,14 @@ while (working_set) {
if (PRESET_ENABLE) { /* is preset enabled for this interface? */
fifo_clear (); /* clear the FIFO */
status = dl_clear_controller (&mac_cntlr, /* do a hard clear of the controller */
ds_unit, hard_clear);
stat_data = IORETURN (status, 0); /* return the status from the controller */
dl_clear_controller (&mac_cntlr, ds_unit, /* do a hard clear of the controller */
hard_clear);
}
break;
case ioCLC: /* clear control flip-flop */
if (DEBUG_PRI (ds_dev, DEB_CMDS))
fprintf (sim_deb, ">>DS cmds: [CLC%s] Control cleared\n", hold_or_clear);
tprintf (ds_dev, DEB_CMDS, "[CLC%s] Control cleared\n", hold_or_clear);
ds.control = CLEAR; /* clear the control */
ds.edt = CLEAR; /* and EDT flip-flops */
@@ -569,16 +567,14 @@ while (working_set) {
interrupt_enabled = TRUE; /* check for drive attention */
if (DEBUG_PRI (ds_dev, DEB_CMDS))
fprintf (sim_deb, ">>DS cmds: [STC%s] Control set\n", hold_or_clear);
tprintf (ds_dev, DEB_CMDS, "[STC%s] Control set\n", hold_or_clear);
break;
case ioEDT: /* end data transfer */
ds.edt = SET; /* set the EDT flip-flop */
if (DEBUG_PRI (ds_dev, DEB_CPU))
fputs (">>DS cpu: [EDT] DCPC transfer ended\n", sim_deb);
tprintf (ds_dev, DEB_CPU, "[EDT] DCPC transfer ended\n");
break;
@@ -698,10 +694,8 @@ return stat_data;
t_stat ds_service_drive (UNIT *uptr)
{
static const char completion_message [] = ">>DS rwsc: Unit %d %s command completed\n";
t_stat result;
t_bool seek_completion;
int32 unit;
FLIP_FLOP entry_srq = ds.srq; /* get the SRQ state on entry */
CNTLR_PHASE entry_phase = (CNTLR_PHASE) uptr->PHASE; /* get the operation phase on entry */
uint32 entry_status = uptr->STAT; /* get the drive status on entry */
@@ -777,9 +771,8 @@ if ((CNTLR_PHASE) uptr->PHASE == data_phase) /* is the drive in the d
} /* end of data phase operation dispatch */
if (DEBUG_PRI (ds_dev, DEB_CMDS) && entry_srq != ds.srq)
fprintf (sim_deb, ">>DS cmds: SRQ %s\n", ds.srq == SET ? "set" : "cleared");
if (entry_srq != ds.srq)
tprintf (ds_dev, DEB_CMDS, "SRQ %s\n", ds.srq == SET ? "set" : "cleared");
if (uptr->wait) /* was service requested? */
activate_unit (uptr); /* schedule the next event */
@@ -795,22 +788,18 @@ if (mac_cntlr.state != cntlr_busy) { /* is the command co
}
if (DEBUG_PRI (ds_dev, DEB_RWSC)) {
unit = uptr - ds_unit; /* get the unit number */
if (result == SCPE_IERR) /* did an internal error occur? */
tprintf (ds_dev, DEB_RWSC, "Unit %d %s command %s phase service not handled\n",
uptr - ds_unit, dl_opcode_name (MAC, (CNTLR_OPCODE) uptr->OP),
dl_phase_name ((CNTLR_PHASE) uptr->PHASE));
if (result == SCPE_IERR) /* did an internal error occur? */
fprintf (sim_deb, ">>DS rwsc: Unit %d %s command %s phase service not handled\n",
unit, dl_opcode_name (MAC, (CNTLR_OPCODE) uptr->OP),
dl_phase_name ((CNTLR_PHASE) uptr->PHASE));
else if (seek_completion) /* if a seek has completed */
tprintf (ds_dev, DEB_RWSC, "Unit %d %s command completed\n", /* report the unit command */
uptr - ds_unit, dl_opcode_name (MAC, (CNTLR_OPCODE) uptr->OP));
else if (seek_completion) /* if a seek has completed */
fprintf (sim_deb, completion_message, /* report the unit command */
unit, dl_opcode_name (MAC, (CNTLR_OPCODE) uptr->OP));
else if (mac_cntlr.state == cntlr_wait) /* if the controller has stopped */
fprintf (sim_deb, completion_message, /* report the controller command */
unit, dl_opcode_name (MAC, mac_cntlr.opcode));
}
else if (mac_cntlr.state == cntlr_wait) /* if the controller has stopped */
tprintf (ds_dev, DEB_RWSC, "Unit %d %s command completed\n", /* report the controller command */
uptr - ds_unit, dl_opcode_name (MAC, mac_cntlr.opcode));
return result; /* return the result of the service */
}
@@ -932,8 +921,8 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the current
} /* end of phase dispatch */
if (result == SCPE_IERR && DEBUG_PRI (ds_dev, DEB_RWSC)) /* did an internal error occur? */
fprintf (sim_deb, ">>DS rwsc: Controller %s command %s phase service not handled\n",
if (result == SCPE_IERR) /* did an internal error occur? */
tprintf (ds_dev, DEB_RWSC, "Controller %s command %s phase service not handled\n",
dl_opcode_name (MAC, opcode), dl_phase_name ((CNTLR_PHASE) uptr->PHASE));
@@ -941,9 +930,8 @@ if (mac_cntlr.state != cntlr_busy) { /* has the controller st
poll_interface (); /* poll the interface for the next command */
poll_drives (); /* poll the drives for Attention status */
if (DEBUG_PRI (ds_dev, DEB_RWSC))
fprintf (sim_deb, ">>DS rwsc: Controller %s command completed\n",
dl_opcode_name (MAC, opcode));
tprintf (ds_dev, DEB_RWSC, "Controller %s command completed\n",
dl_opcode_name (MAC, opcode));
}
return result; /* return the result of the service */
@@ -1027,23 +1015,43 @@ return SCPE_OK;
Attention bits in the drive status, so we poll the drives to ensure that the
CPU is notified that the drive is now online.
If a new file is specified, the file is initialized to its capacity by
writing a zero to the last byte in the file.
Implementation notes:
1. If we are called during a RESTORE command, the drive status will not be
changed, so polling the drives will have no effect.
2. The C standard says, "A binary stream need not meaningfully support fseek
calls with a whence value of SEEK_END," so instead we determine the
offset from the start of the file to the last byte and seek there.
*/
t_stat ds_attach (UNIT *uptr, CONST char *cptr)
{
t_stat result;
t_stat result;
t_addr offset;
const uint8 zero = 0;
result = dl_attach (&mac_cntlr, uptr, cptr); /* attach the drive */
if (result == SCPE_OK) /* was the attach successful? */
poll_drives (); /* poll the drives to notify the CPU */
if (result == SCPE_OK) { /* if the attach was successful */
poll_drives (); /* then poll the drives to notify the CPU */
return result;
if (sim_switches & SWMASK ('N')) { /* if this is a new disc image */
offset = (t_addr) /* then determine the offset of */
(uptr->capac * sizeof (int16) - sizeof zero); /* the last byte in a full-sized file */
if (sim_fseek (uptr->fileref, offset, SEEK_SET) != 0 /* seek to the last byte */
|| fwrite (&zero, sizeof zero, 1, uptr->fileref) == 0 /* and write a zero to fill */
|| fflush (uptr->fileref) != 0) /* the file to its capacity */
clearerr (uptr->fileref); /* clear and ignore any errors */
}
}
return result; /* return the result of the attach */
}
@@ -1068,116 +1076,259 @@ return result;
}
/* Boot a MAC disc drive.
/* MAC disc bootstrap loaders (BMDL and 12992B).
The MAC disc bootstrap program is loaded from the HP 12992B Boot Loader ROM
into memory, the I/O instructions are configured for the interface card's
select code, and the program is run to boot from the specified unit. The
loader supports booting from cylinder 0 of drive unit 0 only. Before
execution, the S register is automatically set as follows:
The Basic Moving-Head Disc Loader (BMDL) consists of two programs. The
program starting at address x7700 loads absolute paper tapes into memory.
The program starting at address x7750 loads a disc-resident bootstrap from
the MAC disc drive into memory. The S register specifies the head to use.
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
------ ------ ---------------------- --------- ---------
ROM # 0 1 select code reserved head
For a 2100/14/15/16 CPU, entering a LOAD DS or BOOT DS command loads the BMDL
into memory and executes the disc portion starting at x7750. The bootstrap
reads 2047 words from cylinder 0 sector 0 of the specified head into memory
starting at location 2011 octal. Loader execution ends with one of the
following instructions:
The boot routine sets bits 15-6 of the S register to appropriate values.
Bits 5-3 and 1-0 retain their original values, so S should be set before
booting. These bits are typically set to 0, although bit 5 is set for an RTE
reconfiguration boot, and bits 1-0 may be set if booting from a head other
than 0 is desired.
* HLT 11B - the disc read failed.
* JSB 2055,I - the disc read completed.
The HP 1000 uses the 12992B boot loader ROM to bootstrap the disc. The head
number is obtained from bits 2-0 of the existing S-register value when the
loader is executed. Bits 5-3 of the existing S-register value are also
retained and are available to the boot extension program. The loader reads
6144 words from cylinder 0 sector 0 of the specified head into memory
starting at location 2011 octal. Loader execution ends with one of the
following instructions:
* HLT 30 - the drive is not ready..
* JSB 2055,I - the disc read succeeded.
The loader automatically retries the operations for all disc errors other
than a drive fault.
Implementation notes:
1. The Loader ROMs manual indicates that bits 2-0 select the head to use,
implying that heads 0-7 are valid. However, Table 5 has entries only for
heads 0-3, and the boot loader code will malfunction if heads 4-7 are
specified. The code masks the head number to three bits but forms the
Cold Load Read command by shifting the head number six bits to the left.
As the head field in the command is only two bits wide, specifying heads
4-7 will result in bit 2 being shifted into the opcode field, resulting
in a Recalibrate command.
1. After the BMDL has been loaded into memory, the paper tape portion may be
executed manually by setting the P register to the starting address
(x7700).
2. For compatibility with the "cpu_copy_loader" routine, the BMDL device I/O
instructions address select codes 10 and 11.
*/
static const LOADER_ARRAY ds_loaders = {
{ /* HP 21xx Basic Moving-Head Disc Loader (BMDL-7905) */
050, /* loader starting index */
076, /* DMA index */
034, /* FWA index */
{ 0002401, /* 77700: PTAPE CLA,RSS Paper Tape start */
0063722, /* 77701: LDA 77722 */
0107700, /* 77702: CLC 0,C */
0002307, /* 77703: CCE,INA,SZA,RSS */
0102077, /* 77704: HLT 77 */
0017735, /* 77705: JSB 77735 */
0007307, /* 77706: CMB,CCE,INB,SZB,RSS */
0027702, /* 77707: JMP 77702 */
0077733, /* 77710: STB 77733 */
0017735, /* 77711: JSB 77735 */
0017735, /* 77712: JSB 77735 */
0074000, /* 77713: STB 0 */
0077747, /* 77714: STB 77747 */
0047734, /* 77715: ADB 77734 */
0002140, /* 77716: SEZ,CLE */
0102055, /* 77717: HLT 55 */
0017735, /* 77720: JSB 77735 */
0040001, /* 77721: ADA 1 */
0177747, /* 77722: STB 77747,I */
0067747, /* 77723: LDB 77747 */
0006104, /* 77724: CLE,INB */
0037733, /* 77725: ISZ 77733 */
0027714, /* 77726: JMP 77714 */
0017735, /* 77727: JSB 77735 */
0054000, /* 77730: CPB 0 */
0027701, /* 77731: JMP 77701 */
0102011, /* 77732: HLT 11 */
0000000, /* 77733: NOP */
0100100, /* 77734: RRL 16 */
0000000, /* 77735: NOP */
0006400, /* 77736: CLB */
0103710, /* 77737: STC 10,C */
0102310, /* 77740: SFS 10 */
0027740, /* 77741: JMP 77740 */
0106410, /* 77742: MIB 10 */
0002240, /* 77743: SEZ,CME */
0127735, /* 77744: JMP 77735,I */
0005727, /* 77745: BLF,BLF */
0027737, /* 77746: JMP 77737 */
0000000, /* 77747: NOP */
0067777, /* 77750: DISC LDB 77777 */
0174001, /* 77751: STB 1,I */
0006004, /* 77752: INB */
0063732, /* 77753: LDA 77732 */
0170001, /* 77754: STA 1,I */
0067776, /* 77755: LDB 77776 */
0106606, /* 77756: OTB 6 */
0106702, /* 77757: CLC 2 */
0102602, /* 77760: OTA 2 */
0102702, /* 77761: STC 2 */
0063751, /* 77762: LDA 77751 */
0102602, /* 77763: OTA 2 */
0102501, /* 77764: LIA 1 */
0001027, /* 77765: ALS,ALF */
0013767, /* 77766: AND 77767 */
0000160, /* 77767: CLE,ALS */
0106710, /* 77770: CLC 10 */
0103610, /* 77771: OTA 10,C */
0103706, /* 77772: STC 6,C */
0102310, /* 77773: SFS 10 */
0027773, /* 77774: JMP 77773 */
0117717, /* 77775: JSB 77717,I */
0000010, /* 77776: SLA */
0002055 } }, /* 77777: SEZ,SLA,INA,RSS */
const BOOT_ROM ds_rom = {
0017727, /* START JSB STAT GET STATUS */
0002021, /* SSA,RSS IS DRIVE READY ? */
0027742, /* JMP DMA YES, SET UP DMA */
0013714, /* AND B20 NO, CHECK STATUS BITS */
0002002, /* SZA IS DRIVE FAULTY OR HARD DOWN ? */
0102030, /* HLT 30B YES, HALT 30B, "RUN" TO TRY AGAIN */
0027700, /* JMP START NO, TRY AGAIN FOR DISC READY */
0102011, /* ADDR1 OCT 102011 */
0102055, /* ADDR2 OCT 102055 */
0164000, /* CNT DEC -6144 */
0000007, /* D7 OCT 7 */
0001400, /* STCMD OCT 1400 */
0000020, /* B20 OCT 20 */
0017400, /* STMSK OCT 17400 */
0000000, /* NOP */
0000000, /* NOP */
0000000, /* NOP */
0000000, /* NOP */
0000000, /* NOP */
0000000, /* NOP */
0000000, /* NOP */
0000000, /* NOP */
0000000, /* NOP */
0000000, /* STAT NOP STATUS CHECK SUBROUTINE */
0107710, /* CLC DC,C SET STATUS COMMAND MODE */
0063713, /* LDA STCMD GET STATUS COMMAND */
0102610, /* OTA DC OUTPUT STATUS COMMAND */
0102310, /* SFS DC WAIT FOR STATUS#1 WORD */
0027733, /* JMP *-1 */
0107510, /* LIB DC,C B-REG = STATUS#1 WORD */
0102310, /* SFS DC WAIT FOR STATUS#2 WORD */
0027736, /* JMP *-1 */
0103510, /* LIA DC,C A-REG = STATUS#2 WORD */
0127727, /* JMP STAT,I RETURN */
0067776, /* DMA LDB DMACW GET DMA CONTROL WORD */
0106606, /* OTB 6 OUTPUT DMA CONTROL WORD */
0067707, /* LDB ADDR1 GET MEMORY ADDRESS */
0106702, /* CLC 2 SET MEMORY ADDRESS INPUT MODE */
0106602, /* OTB 2 OUTPUT MEMORY ADDRESS TO DMA */
0102702, /* STC 2 SET WORD COUNT INPUT MODE */
0067711, /* LDB CNT GET WORD COUNT */
0106602, /* OTB 2 OUTPUT WORD COUNT TO DMA */
0106710, /* CLDLD CLC DC SET COMMAND INPUT MODE */
0102501, /* LIA 1 LOAD SWITCH */
0106501, /* LIB 1 REGISTER SETTINGS */
0013712, /* AND D7 ISOLATE HEAD NUMBER */
0005750, /* BLF,CLE,SLB BIT 12=0? */
0027762, /* JMP *+3 NO,MANUAL BOOT */
0002002, /* SZA YES,RPL BOOT. HEAD#=0? */
0001000, /* ALS NO,HEAD#1, MAKE HEAD#=2 */
0001720, /* ALF,ALS FORM COLD LOAD */
0001000, /* ALS COMMAND WORD */
0103706, /* STC 6,C ACTIVATE DMA */
0103610, /* OTA DC,C OUTPUT COLD LOAD COMMAND */
0102310, /* SFS DC IS COLD LOAD COMPLETED ? */
0027766, /* JMP *-1 NO, WAIT */
0017727, /* JSB STAT YES, GET STATUS */
0060001, /* LDA 1 */
0013715, /* AND STMSK A-REG = STATUS BITS OF STATUS#1 WD */
0002002, /* SZA IS TRANSFER OK ? */
0027700, /* JMP START NO,TRY AGAIN */
0117710, /* EXIT JSB ADDR2,I YES, EXEC LOADED PROGRAM _@ 2055B */
0000010, /* DMACW ABS DC */
0170100, /* ABS -START */
{ /* HP 1000 Loader ROM (12992B) */
IBL_START, /* loader starting index */
IBL_DMA, /* DMA index */
IBL_FWA, /* FWA index */
{ 0017727, /* 77700: START JSB STAT GET STATUS */
0002021, /* 77701: SSA,RSS IS DRIVE READY ? */
0027742, /* 77702: JMP DMA YES, SET UP DMA */
0013714, /* 77703: AND B20 NO, CHECK STATUS BITS */
0002002, /* 77704: SZA IS DRIVE FAULTY OR HARD DOWN ? */
0102030, /* 77705: HLT 30B YES, HALT 30B, "RUN" TO TRY AGAIN */
0027700, /* 77706: JMP START NO, TRY AGAIN FOR DISC READY */
0102011, /* 77707: ADDR1 OCT 102011 */
0102055, /* 77710: ADDR2 OCT 102055 */
0164000, /* 77711: CNT DEC -6144 */
0000007, /* 77712: D7 OCT 7 */
0001400, /* 77713: STCMD OCT 1400 */
0000020, /* 77714: B20 OCT 20 */
0017400, /* 77715: STMSK OCT 17400 */
0000000, /* 77716: NOP */
0000000, /* 77717: NOP */
0000000, /* 77720: NOP */
0000000, /* 77721: NOP */
0000000, /* 77722: NOP */
0000000, /* 77723: NOP */
0000000, /* 77724: NOP */
0000000, /* 77725: NOP */
0000000, /* 77726: NOP */
0000000, /* 77727: STAT NOP STATUS CHECK SUBROUTINE */
0107710, /* 77730: CLC DC,C SET STATUS COMMAND MODE */
0063713, /* 77731: LDA STCMD GET STATUS COMMAND */
0102610, /* 77732: OTA DC OUTPUT STATUS COMMAND */
0102310, /* 77733: SFS DC WAIT FOR STATUS#1 WORD */
0027733, /* 77734: JMP *-1 */
0107510, /* 77735: LIB DC,C B-REG = STATUS#1 WORD */
0102310, /* 77736: SFS DC WAIT FOR STATUS#2 WORD */
0027736, /* 77737: JMP *-1 */
0103510, /* 77740: LIA DC,C A-REG = STATUS#2 WORD */
0127727, /* 77741: JMP STAT,I RETURN */
0067776, /* 77742: DMA LDB DMACW GET DMA CONTROL WORD */
0106606, /* 77743: OTB 6 OUTPUT DMA CONTROL WORD */
0067707, /* 77744: LDB ADDR1 GET MEMORY ADDRESS */
0106702, /* 77745: CLC 2 SET MEMORY ADDRESS INPUT MODE */
0106602, /* 77746: OTB 2 OUTPUT MEMORY ADDRESS TO DMA */
0102702, /* 77747: STC 2 SET WORD COUNT INPUT MODE */
0067711, /* 77750: LDB CNT GET WORD COUNT */
0106602, /* 77751: OTB 2 OUTPUT WORD COUNT TO DMA */
0106710, /* 77752: CLDLD CLC DC SET COMMAND INPUT MODE */
0102501, /* 77753: LIA 1 LOAD SWITCH */
0106501, /* 77754: LIB 1 REGISTER SETTINGS */
0013712, /* 77755: AND D7 ISOLATE HEAD NUMBER */
0005750, /* 77756: BLF,CLE,SLB BIT 12=0? */
0027762, /* 77757: JMP *+3 NO,MANUAL BOOT */
0002002, /* 77760: SZA YES,RPL BOOT. HEAD#=0? */
0001000, /* 77761: ALS NO,HEAD#1, MAKE HEAD#=2 */
0001720, /* 77762: ALF,ALS FORM COLD LOAD */
0001000, /* 77763: ALS COMMAND WORD */
0103706, /* 77764: STC 6,C ACTIVATE DMA */
0103610, /* 77765: OTA DC,C OUTPUT COLD LOAD COMMAND */
0102310, /* 77766: SFS DC IS COLD LOAD COMPLETED ? */
0027766, /* 77767: JMP *-1 NO, WAIT */
0017727, /* 77770: JSB STAT YES, GET STATUS */
0060001, /* 77771: LDA 1 */
0013715, /* 77772: AND STMSK A-REG = STATUS BITS OF STATUS#1 WD */
0002002, /* 77773: SZA IS TRANSFER OK ? */
0027700, /* 77774: JMP START NO,TRY AGAIN */
0117710, /* 77775: EXIT JSB ADDR2,I YES, EXEC LOADED PROGRAM @ 2055B */
0000010, /* 77776: DMACW ABS DC */
0170100 } } /* 77777: ABS -START */
};
/* Device boot routine.
This routine is called directly by the BOOT DS and LOAD DS commands to copy
the device bootstrap into the upper 64 words of the logical address space.
It is also called indirectly by a BOOT CPU or LOAD CPU command when the
specified HP 1000 loader ROM socket contains a 12992B ROM.
When called in response to a BOOT DS or LOAD DS command, the "unitno"
parameter indicates the unit number specified in the BOOT command or is zero
for the LOAD command, and "dptr" points at the DS device structure. The
bootstrap supports loading only from unit 0, and the command will be rejected
if another unit is specified (e.g., BOOT DS1). Otherwise, depending on the
current CPU model, the BMDL or 12992B loader ROM will be copied into memory
and configured for the DS select code. If the CPU is a 1000, the S register
will be set as it would be by the front-panel microcode.
When called for a BOOT/LOAD CPU command, the "unitno" parameter indicates the
select code to be used for configuration, and "dptr" will be NULL. As above,
the BMDL or 12992B loader ROM will be copied into memory and configured for
the specified select code. The S register is assumed to be set correctly on
entry and is not modified.
In either case, if the CPU is a 21xx model, the paper tape portion of the
BMDL will be automatically configured for the select code of the paper tape
reader.
For the 12992B boot loader ROM for the HP 1000, the S register is set as
follows:
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| ROM # | 0 1 | select code | reserved | 0 | head |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
Bit 12 must be 1 for a manual boot. Bits 5-3 are nominally zero but are
reserved for the target operating system. For example, RTE uses bit 5 to
indicate whether a standard (0) or reconfiguration (1) boot is desired.
Implementation notes:
1. In hardware, the BMDL was hand-configured for the disc and paper tape
reader select codes when it was installed on a given system. Under
simulation, the LOAD and BOOT commands automatically configure the BMDL
to the current select codes of the PTR and DS devices.
2. The HP 1000 Loader ROMs manual indicates that bits 2-0 select the head to
use, implying that heads 0-7 are valid. However, Table 5 has entries
only for heads 0-3, and the boot loader code will malfunction if heads
4-7 are specified. The code masks the head number to three bits but
forms the Cold Load Read command by shifting the head number six bits to
the left. As the head field in the command is only two bits wide,
specifying heads 4-7 will result in bit 2 being shifted into the opcode
field, resulting in a Recalibrate command.
*/
t_stat ds_boot (int32 unitno, DEVICE *dptr)
{
if (unitno != 0) /* boot supported on drive unit 0 only */
return SCPE_NOFNC; /* report "Command not allowed" if attempted */
static const HP_WORD ds_preserved = 0000073u; /* S-register bits 5-3 and 1-0 are preserved */
static const HP_WORD ds_manual_boot = 0010000u; /* S-register bit 12 set for a manual boot */
if (ibl_copy (ds_rom, ds_dib.select_code, /* copy the boot ROM to memory and configure */
IBL_OPT | IBL_DS_HEAD, /* the S register accordingly */
IBL_DS | IBL_MAN | IBL_SET_SC (ds_dib.select_code)))
return SCPE_IERR; /* return an internal error if the copy failed */
else
return SCPE_OK;
if (dptr == NULL) /* if we are being called for a BOOT/LOAD CPU */
return cpu_copy_loader (ds_loaders, unitno, /* then copy the boot loader to memory */
IBL_S_NOCLEAR, IBL_S_NOSET); /* but do not alter the S register */
else if (unitno != 0) /* otherwise a BOOT DS for a non-zero unit */
return SCPE_NOFNC; /* is rejected as unsupported */
else /* otherwise this is a BOOT/LOAD DS */
return cpu_copy_loader (ds_loaders, ds_dib.select_code, /* so copy the boot loader to memory */
ds_preserved, ds_manual_boot); /* and configure the S register if 1000 CPU */
}
@@ -1273,23 +1424,16 @@ if (uptr) { /* did the command start
if (time) /* was the unit scheduled? */
activate_unit (uptr); /* activate it (and clear the "wait" field) */
if (DEBUG_PRI (ds_dev, DEB_RWSC)) {
unit = uptr - ds_unit; /* get the unit number */
if (time == 0) /* was the unit busy? */
tprintf (ds_dev, DEB_RWSC, "Unit %d %s in progress\n",
uptr - ds_unit, dl_opcode_name (MAC, drive_command));
if (time == 0) /* was the unit busy? */
fprintf (sim_deb, ">>DS rwsc: Unit %d %s in progress\n",
unit, dl_opcode_name (MAC, drive_command));
fputs (">>DS rwsc: ", sim_deb);
if (unit > DL_MAXDRIVE)
fputs ("Controller ", sim_deb);
else
fprintf (sim_deb, "Unit %d position %" T_ADDR_FMT "d ", unit, uptr->pos);
fprintf (sim_deb, "%s command initiated\n",
if (uptr - ds_unit > DL_MAXDRIVE)
tprintf (ds_dev, DEB_RWSC, "Controller %s command initiated\n",
dl_opcode_name (MAC, mac_cntlr.opcode));
}
else
tprintf (ds_dev, DEB_RWSC, "Unit %d position %" T_ADDR_FMT "d %s command initiated\n",
uptr - ds_unit, uptr->pos, dl_opcode_name (MAC, mac_cntlr.opcode));
}
else /* the command failed to start */
@@ -1380,8 +1524,7 @@ static void fifo_load (uint16 data)
uint32 index;
if (FIFO_FULL) { /* is the FIFO already full? */
if (DEBUG_PRI (ds_dev, DEB_BUF))
fprintf (sim_deb, ">>DS buf: Attempted load to full FIFO, data %06o\n", data);
tprintf (ds_dev, DEB_BUF, "Attempted load to full FIFO, data %06o\n", data);
return; /* return with the load ignored */
}
@@ -1391,9 +1534,8 @@ index = (ds.fifo_reg->qptr + ds.fifo_count) % FIFO_SIZE; /* calculate the ind
ds.fifo [index] = data; /* store the word in the FIFO */
ds.fifo_count = ds.fifo_count + 1; /* increment the count of words stored */
if (DEBUG_PRI (ds_dev, DEB_BUF))
fprintf (sim_deb, ">>DS buf: Data %06o loaded into FIFO (%d)\n",
data, ds.fifo_count);
tprintf (ds_dev, DEB_BUF, "Data %06o loaded into FIFO (%d)\n",
data, ds.fifo_count);
return;
}
@@ -1418,9 +1560,7 @@ static uint16 fifo_unload (void)
uint16 data;
if (FIFO_EMPTY) { /* is the FIFO already empty? */
if (DEBUG_PRI (ds_dev, DEB_BUF))
fputs (">>DS buf: Attempted unload from empty FIFO\n", sim_deb);
tprintf (ds_dev, DEB_BUF, "Attempted unload from empty FIFO\n");
return 0; /* return with no data */
}
@@ -1429,9 +1569,8 @@ data = ds.fifo [ds.fifo_reg->qptr]; /* get the word from
ds.fifo_reg->qptr = (ds.fifo_reg->qptr + 1) % FIFO_SIZE; /* update the FIFO queue pointer */
ds.fifo_count = ds.fifo_count - 1; /* decrement the count of words stored */
if (DEBUG_PRI (ds_dev, DEB_BUF))
fprintf (sim_deb, ">>DS buf: Data %06o unloaded from FIFO (%d)\n",
data, ds.fifo_count);
tprintf (ds_dev, DEB_BUF, "Data %06o unloaded from FIFO (%d)\n",
data, ds.fifo_count);
return data;
}
@@ -1446,8 +1585,7 @@ static void fifo_clear (void)
{
ds.fifo_count = 0; /* clear the FIFO */
if (DEBUG_PRI (ds_dev, DEB_BUF))
fputs (">>DS buf: FIFO cleared\n", sim_deb);
tprintf (ds_dev, DEB_BUF, "FIFO cleared\n");
return;
}
@@ -1461,19 +1599,14 @@ return;
static t_stat activate_unit (UNIT *uptr)
{
int32 unit;
t_stat result;
if (DEBUG_PRI (ds_dev, DEB_SERV)) {
unit = uptr - ds_unit; /* calculate the unit number */
if (uptr == &ds_cntlr)
fprintf (sim_deb, ">>DS serv: Controller delay %d service scheduled\n",
uptr->wait);
else
fprintf (sim_deb, ">>DS serv: Unit %d delay %d service scheduled\n",
unit, uptr->wait);
}
if (uptr == &ds_cntlr)
tprintf (ds_dev, DEB_SERV, "Controller delay %d service scheduled\n",
uptr->wait);
else
tprintf (ds_dev, DEB_SERV, "Unit %d delay %d service scheduled\n",
uptr - ds_unit, uptr->wait);
result = sim_activate (uptr, uptr->wait); /* activate the unit */
uptr->wait = 0; /* reset the activation time */

View File

@@ -1,28 +1,30 @@
/* hp2100_fp.c: HP 2100 floating point instructions
Copyright (c) 2002-2015, Robert M. Supnik
Copyright (c) 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 in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not be
Except as contained in this notice, the names of the authors shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
in this Software without prior written authorization from the authors.
26-Jun-17 JDB Replaced SEXT with SEXT16
03-Jan-15 JDB Made the utility routines static
21-Jan-08 JDB Corrected fp_unpack mantissa high-word return
(from Mark Pizzolato)
@@ -228,13 +230,13 @@ UnpackFP (&fop1, FPAB); /* unpack A-B */
UnpackFP (&fop2, opnd); /* unpack op */
if (fop1.fr && fop2.fr) { /* if both != 0 */
res.exp = fop1.exp + fop2.exp + 1; /* exp = sum */
shi1 = SEXT (fop1.fr >> 16); /* mpy hi */
shi2 = SEXT (fop2.fr >> 16); /* mpc hi */
shi1 = SEXT16 (UPPER_WORD (fop1.fr)); /* mpy hi */
shi2 = SEXT16 (UPPER_WORD (fop2.fr)); /* mpc hi */
t1 = shi2 * ((int32) ((fop1.fr >> 1) & 077600)); /* mpc hi * (mpy lo/2) */
t2 = shi1 * ((int32) ((fop2.fr >> 1) & 077600)); /* mpc lo * (mpy hi/2) */
t3 = t1 + t2; /* cross product */
t4 = (shi1 * shi2) & ~1; /* mpy hi * mpc hi */
t5 = (SEXT (t3 >> 16)) << 1; /* add in cross */
t5 = SEXT16 (UPPER_WORD (t3)) << 1; /* add in cross */
res.fr = (t4 + t5) & DMASK32; /* bit<0> is lost */
}
return StoreFP (&res); /* store */
@@ -282,7 +284,7 @@ if (fop1.fr) { /* dvd != 0? */
q1 = divx (ba, dvrh, NULL); /* Q1 = rem / dvrh */
ba = (fop2.fr & 0xFF00) << 13; /* dvrl / 8 */
q2 = divx (ba, dvrh, NULL); /* dvrl / dvrh */
ba = -(SEXT (q2)) * (SEXT (q0)); /* -Q0 * Q2 */
ba = - SEXT16 (LOWER_WORD (q2)) * SEXT16 (LOWER_WORD (q0)); /* -Q0 * Q2 */
ba = (ba >> 16) & 0xFFFF; /* save ms half */
if (q1 & SIGN) quo.fr = quo.fr - 0x00010000; /* Q1 < 0? -1 */
if (ba & SIGN) quo.fr = quo.fr - 0x00010000; /* -Q0*Q2 < 0? */
@@ -372,8 +374,8 @@ uint32 val;
fop.fr = ((uint32) mantissa.fpk[0] << 16) | mantissa.fpk[1];
fop.exp = exponent;
val = PackFP (&fop);
result->fpk[0] = (int16) (val >> 16);
result->fpk[1] = (int16) val;
result->fpk[0] = UPPER_WORD (val);
result->fpk[1] = LOWER_WORD (val);
return 0;
}
@@ -401,8 +403,8 @@ uint32 operand;
operand = ((uint32) packed.fpk[0] << 16) | packed.fpk[1];
UnpackFP (&fop, operand);
mantissa->fpk[0] = (uint16) (fop.fr >> 16);
mantissa->fpk[1] = (uint16) fop.fr;
mantissa->fpk[0] = UPPER_WORD (fop.fr);
mantissa->fpk[1] = LOWER_WORD (fop.fr);
*exponent = fop.exp;
return 0;
}

View File

@@ -1,35 +1,35 @@
/* hp2100_fp.h: HP 2100/21MX floating point definitions
/* hp2100_fp.h: HP 2100/21MX floating point declarations
Copyright (c) 2002-2013, Robert M. Supnik
Copyright (c) 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 in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not be
Except as contained in this notice, the names of the authors shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
in this Software without prior written authorization from the authors.
15-Feb-17 JDB Deleted unneeded guard macro definition
14-Mar-13 MP Changed guard macro name to avoid reserved namespace
01-Dec-06 JDB Reworked FFP helpers for 1000-F support, deleted f_pwr2
26-Sep-06 JDB Moved from hp2100_fp.c to simplify extensions
*/
#ifndef HP2100_FP_H_
#define HP2100_FP_H_
/* Firmware floating-point routines */
@@ -44,5 +44,3 @@ uint32 f_flt (void); /* FLT */
uint32 fp_pack (OP *result, OP mantissa, int32 exponent, OPSIZE precision);
uint32 fp_nrpack (OP *result, OP mantissa, int32 exponent, OPSIZE precision);
uint32 fp_unpack (OP *mantissa, int32 *exponent, OP packed, OPSIZE precision);
#endif

View File

@@ -1,6 +1,6 @@
/* hp2100_fp1.c: HP 1000 multiple-precision floating point routines
Copyright (c) 2005-2016, J. David Bryan
Copyright (c) 2005-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"),
@@ -23,6 +23,7 @@
in advertising or otherwise to promote the sale, use or other dealings in
this Software without prior written authorization from the author.
07-Sep-17 JDB Replaced "uint16" casts with "HP_WORD" for OP assignments
16-May-16 JDB Reformulated the definitions of op_mask
24-Dec-14 JDB Added casts for explicit downward conversions
Changed fp_ucom return from uint32 to uint16
@@ -480,7 +481,7 @@ int32 i;
OP packed;
if (precision == in_s)
packed.word = (uint16) (unpacked >> 48) & DMASK; /* pack single integer */
packed.word = (HP_WORD) (unpacked >> 48) & DMASK; /* pack single integer */
else if (precision == in_d)
packed.dword = (uint32) (unpacked >> 32) & DMASK32; /* pack double integer */
@@ -490,7 +491,7 @@ else {
precision = fp_t; /* only four mantissa words */
for (i = 3; i >= 0; i--) { /* pack fp 2 to 4 words */
packed.fpk[i] = (uint16) unpacked & DMASK;
packed.fpk[i] = (HP_WORD) unpacked & DMASK;
unpacked = unpacked >> 16;
}
}
@@ -530,8 +531,8 @@ switch (unpacked.precision) { /* merge exponent into c
break;
case fp_e: /* place in separate word */
packed.fpk[4] = (uint16) (unpacked.exponent << FP_V_EXP |
(unpacked.exponent < 0) << FP_V_ESIGN);
packed.fpk[4] = (HP_WORD) (unpacked.exponent << FP_V_EXP |
(unpacked.exponent < 0) << FP_V_ESIGN);
break;
case fp_a: /* no action for value in accum */

View File

@@ -1,6 +1,6 @@
/* hp2100_fp1.h: HP 2100/1000 multiple-precision floating point definitions
/* hp2100_fp1.h: HP 2100/1000 multiple-precision floating point declarations
Copyright (c) 2005-2014, J. David Bryan
Copyright (c) 2005-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"),
@@ -23,14 +23,13 @@
in advertising or otherwise to promote the sale, use or other dealings in
this Software without prior written authorization from the author.
15-Feb-17 JDB Deleted unneeded guard macro definition
24-Dec-14 JDB Changed fp_ucom return from uint32 to uint16
14-Mar-13 MP Changed guard macro name to avoid reserved namespace
16-Oct-06 JDB Generalized FP calling sequences for F-Series
12-Oct-06 JDB Altered x_trun for F-Series FFP compatibility
*/
#ifndef HP2100_FP1_H_
#define HP2100_FP1_H_ 0
/* Special operands. */
@@ -51,5 +50,3 @@ uint16 fp_ucom (OP *mantissa, OPSIZE precision);
uint32 fp_pcom (OP *packed, OPSIZE precision);
uint32 fp_trun (OP *result, OP source, OPSIZE precision);
uint32 fp_cvt (OP *result, OPSIZE source_precision, OPSIZE dest_precision);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,31 +1,35 @@
/* hp2100_lps.c: HP 2100 12653A/2767 line printer simulator
/* hp2100_lps.c: HP 2100 12653A Line Printer Interface simulator
Copyright (c) 1993-2016, Robert M. Supnik
Copyright (c) 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 in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not be
Except as contained in this notice, the names of the authors shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
in this Software without prior written authorization from the authors.
LPS 12653A 2767 line printer
12566B microcircuit interface with loopback diagnostic connector
LPS HP 12653A Line Printer Interface
03-Aug-17 JDB Changed perror call for I/O errors to cprintf
20-Jul-17 JDB Removed "lps_stopioe" variable and register
17-Mar-17 JDB Added "-N" handling to the attach routine
15-Mar-17 JDB Changed DEBUG_PRS calls to tprintfs
13-May-16 JDB Modified for revised SCP API function parameter types
10-Feb-12 JDB Deprecated DEVNO in favor of SC
28-Mar-11 JDB Tidied up signal handling
@@ -58,30 +62,17 @@
15-Oct-00 RMS Added variable device number support
References:
- 2767A Line Printer Operating and Service Manual (02767-90002, Oct-1973)
- 12566B, 12566B-001, 12566B-002, 12566B-003 Microcircuit Interface Kits
Operating and Service Manual (12566-90015, Apr-1976)
This module simulates two different devices. In "diagnostic mode," it
simulates a 12566B microcircuit interface card with a loopback connector. In
non-diagnostic mode, it simulates a 12653A line printer interface card and a
2767 line printer.
In diagnostic mode, the 12566B interface has a loopback connector that ties
the output data lines to the input data lines and the device command output
to the device flag input. In addition, card configuration jumpers are set as
needed for the diagnostic programs.
Jumper settings depend on the CPU model. For the 2114/15/16 CPUs, jumper W1
is installed in position B and jumper W2 in position C. In these positions,
the card flag sets two instructions after the STC, allowing DMA to steal
every third cycle. For the 2100 and 1000 CPUs, jumper W1 is installed in
position C and jumper W2 in position B. In these positions, the card flag
sets one instruction after the STC, allowing DMA to steal every other cycle.
For all CPUs, jumpers W3 and W4 are installed in position B, W5-W8 are
installed, and W9 is installed in position A.
- 2767A Line Printer Operating and Service Manual
(02767-90002, October 1973)
- General Purpose Register Diagnostic Reference Manual
(24391-90001, April 1982)
The HP 12653A Line Printer Interface Kit connects the 2767A printer to the HP
1000 family. The subsystem consists of an interface card employing TTL-level
line drivers and receivers, an interconnecting cable, and an HP 2767A (from
356 to 1110 lines per minute) line printer. The interface is supported by
RTE and DOS drivers DVR12. The interface supports DMA transfers, but the OS
drivers do not use them.
The 2767 impact printer has a rotating drum with 80 columns of 64 raised
characters. ASCII codes 32 through 95 (SPACE through "_") form the print
@@ -131,45 +122,75 @@
2. Print operation in progress sets BUSY instead of NOT READY.
3. Characters not in the print repertoire are replaced with blanks.
4. The 81st and succeeding characters overprint the current line.
*/
The "General Purpose Register Diagnostic Reference Manual" states that the
12653A is a "special microcircuit interface," suggesting that it is a
derivative of the 12566B Microcircuit Interface Kit. No specific manual for
this interface kit has been found.
A diagnostic mode is provided to simulate the installation of the 1251-0332
loopback connecctor, modified to connect pins Z/22 to pins AA/23 as required
by the diagnostic. This ties the output data lines to the input data lines
and the device command output to the device flag input.
Jumper settings depend on the CPU model. For the 2114/15/16 CPUs, jumper W1
is installed in position B and jumper W2 in position C. In these positions,
the card flag sets two instructions after the STC, allowing DMA to steal
every third cycle. For the 2100 and 1000 CPUs, jumper W1 is installed in
position C and jumper W2 in position B. In these positions, the card flag
sets one instruction after the STC, allowing DMA to steal every other cycle.
For all CPUs, jumpers W3 and W4 are installed in position B, W5-W8 are
installed, and W9 is installed in position A.
*/
#include "hp2100_defs.h"
#include "hp2100_cpu.h"
#define LPS_ZONECNT 20 /* zone char count */
#define LPS_PAGECNT 80 /* page char count */
#define LPS_PAGELNT 60 /* page line length */
#define LPS_FORMLNT 66 /* form line length */
/* Printer program constants */
#define CR '\r' /* carriage return */
#define LF '\n' /* line feed */
#define FF '\f' /* form feed */
#define DATA_MASK 0177u /* printer uses only 7 bits for data */
#define LPS_ZONECNT 20 /* zone char count */
#define LPS_PAGECNT 80 /* page char count */
#define LPS_PAGELNT 60 /* page line length */
#define LPS_FORMLNT 66 /* form line length */
/* Printer power states */
#define LPS_ON 0 /* power is on */
#define LPS_OFF 1 /* power is off */
#define LPS_TURNING_ON 2 /* power is turning on */
#define LPS_ON 0 /* power is on */
#define LPS_OFF 1 /* power is off */
#define LPS_TURNING_ON 2 /* power is turning on */
#define LPS_BUSY 0000001 /* busy status */
#define LPS_NRDY 0100000 /* not ready status */
#define LPS_PWROFF LPS_BUSY | LPS_NRDY /* power-off status */
#define LPS_BUSY 0000001 /* busy status */
#define LPS_NRDY 0100000 /* not ready status */
#define LPS_PWROFF LPS_BUSY | LPS_NRDY /* power-off status */
#define UNIT_V_DIAG (UNIT_V_UF + 0) /* diagnostic mode */
#define UNIT_V_POWEROFF (UNIT_V_UF + 1) /* unit powered off */
#define UNIT_V_OFFLINE (UNIT_V_UF + 2) /* unit offline */
#define UNIT_V_DIAG (UNIT_V_UF + 0) /* diagnostic mode */
#define UNIT_V_POWEROFF (UNIT_V_UF + 1) /* unit powered off */
#define UNIT_V_OFFLINE (UNIT_V_UF + 2) /* unit offline */
#define UNIT_DIAG (1 << UNIT_V_DIAG)
#define UNIT_POWEROFF (1 << UNIT_V_POWEROFF)
#define UNIT_OFFLINE (1 << UNIT_V_OFFLINE)
struct {
FLIP_FLOP control; /* control flip-flop */
FLIP_FLOP flag; /* flag flip-flop */
FLIP_FLOP flagbuf; /* flag buffer flip-flop */
static struct {
FLIP_FLOP control; /* control flip-flop */
FLIP_FLOP flag; /* flag flip-flop */
FLIP_FLOP flagbuf; /* flag buffer flip-flop */
} lps = { CLEAR, CLEAR, CLEAR };
int32 lps_ccnt = 0; /* character count */
int32 lps_lcnt = 0; /* line count */
int32 lps_stopioe = 0; /* stop on error */
int32 lps_sta = 0; /* printer status */
int32 lps_timing = 1; /* timing type */
uint32 lps_power = LPS_ON; /* power state */
static int32 lps_ccnt = 0; /* character count */
static int32 lps_lcnt = 0; /* line count */
static int32 lps_sta = 0; /* printer status */
static int32 lps_timing = 1; /* timing type */
static uint32 lps_power = LPS_ON; /* power state */
/* Hardware timing:
(based on 1580 instr/msec) instr msec calc msec
@@ -191,32 +212,32 @@ uint32 lps_power = LPS_ON; /* power state */
three-fourths when not executing on an E/F.
*/
int32 lps_ctime = 0; /* char xfer time */
int32 lps_ptime = 0; /* zone printing time */
int32 lps_stime = 0; /* paper slew time */
int32 lps_rtime = 0; /* power-on ready time */
static int32 lps_ctime = 0; /* char xfer time */
static int32 lps_ptime = 0; /* zone printing time */
static int32 lps_stime = 0; /* paper slew time */
static int32 lps_rtime = 0; /* power-on ready time */
typedef int32 TIMESET[4]; /* set of controller times */
typedef int32 TIMESET[4]; /* set of controller times */
int32 *const lps_timers[] = { &lps_ctime, &lps_ptime, &lps_stime, &lps_rtime };
static int32 *const lps_timers[] = { &lps_ctime, &lps_ptime, &lps_stime, &lps_rtime };
const TIMESET lps_times[2] = {
{ 2, 55300, 17380, 158000 }, /* REALTIME */
{ 2, 1000, 1000, 1000 } /* FASTTIME */
static const TIMESET lps_times[2] = {
{ 2, 55300, 17380, 158000 }, /* REALTIME */
{ 2, 1000, 1000, 1000 } /* FASTTIME */
};
DEVICE lps_dev;
IOHANDLER lpsio;
static IOHANDLER lpsio;
t_stat lps_svc (UNIT *uptr);
t_stat lps_reset (DEVICE *dptr);
t_stat lps_restart (UNIT *uptr, int32 value, CONST char *cptr, void *desc);
t_stat lps_poweroff (UNIT *uptr, int32 value, CONST char *cptr, void *desc);
t_stat lps_poweron (UNIT *uptr, int32 value, CONST char *cptr, void *desc);
t_stat lps_attach (UNIT *uptr, CONST char *cptr);
t_stat lps_set_timing (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat lps_show_timing (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
static t_stat lps_svc (UNIT *uptr);
static t_stat lps_reset (DEVICE *dptr);
static t_stat lps_restart (UNIT *uptr, int32 value, CONST char *cptr, void *desc);
static t_stat lps_poweroff (UNIT *uptr, int32 value, CONST char *cptr, void *desc);
static t_stat lps_poweron (UNIT *uptr, int32 value, CONST char *cptr, void *desc);
static t_stat lps_attach (UNIT *uptr, CONST char *cptr);
static t_stat lps_set_timing (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
static t_stat lps_show_timing (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
/* LPS data structures
@@ -225,57 +246,89 @@ t_stat lps_show_timing (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
lps_reg LPS register list
*/
DIB lps_dib = { &lpsio, LPS };
static DIB lps_dib = { &lpsio, LPS };
UNIT lps_unit = {
static UNIT lps_unit = {
UDATA (&lps_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_DISABLE+UNIT_TEXT, 0)
};
REG lps_reg[] = {
{ ORDATA (BUF, lps_unit.buf, 16) },
{ ORDATA (STA, lps_sta, 16) },
{ ORDATA (POWER, lps_power, 2), REG_RO },
{ FLDATA (CTL, lps.control, 0) },
{ FLDATA (FLG, lps.flag, 0) },
{ FLDATA (FBF, lps.flagbuf, 0) },
{ DRDATA (CCNT, lps_ccnt, 7), PV_LEFT },
{ DRDATA (LCNT, lps_lcnt, 7), PV_LEFT },
{ DRDATA (POS, lps_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (CTIME, lps_ctime, 24), PV_LEFT },
{ DRDATA (PTIME, lps_ptime, 24), PV_LEFT },
{ DRDATA (STIME, lps_stime, 24), PV_LEFT },
{ DRDATA (RTIME, lps_rtime, 24), PV_LEFT },
{ FLDATA (TIMING, lps_timing, 0), REG_HRO },
{ FLDATA (STOP_IOE, lps_stopioe, 0) },
{ ORDATA (SC, lps_dib.select_code, 6), REG_HRO },
{ ORDATA (DEVNO, lps_dib.select_code, 6), REG_HRO },
static REG lps_reg[] = {
/* Macro Name Location Width Offset Flags */
/* ------ ------ ------------------- --------- ------ ------- */
{ ORDATA (BUF, lps_unit.buf, 16), REG_X },
{ ORDATA (STA, lps_sta, 16) },
{ ORDATA (POWER, lps_power, 2), REG_RO },
{ FLDATA (CTL, lps.control, 0) },
{ FLDATA (FLG, lps.flag, 0) },
{ FLDATA (FBF, lps.flagbuf, 0) },
{ DRDATA (CCNT, lps_ccnt, 7), PV_LEFT },
{ DRDATA (LCNT, lps_lcnt, 7), PV_LEFT },
{ DRDATA (POS, lps_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (CTIME, lps_ctime, 24), PV_LEFT },
{ DRDATA (PTIME, lps_ptime, 24), PV_LEFT },
{ DRDATA (STIME, lps_stime, 24), PV_LEFT },
{ DRDATA (RTIME, lps_rtime, 24), PV_LEFT },
{ FLDATA (TIMING, lps_timing, 0), REG_HRO },
{ ORDATA (SC, lps_dib.select_code, 6), REG_HRO },
{ ORDATA (DEVNO, lps_dib.select_code, 6), REG_HRO },
{ NULL }
};
MTAB lps_mod[] = {
{ UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", NULL },
{ UNIT_DIAG, 0, "printer mode", "PRINTER", NULL },
{ UNIT_POWEROFF, UNIT_POWEROFF, "power off", "POWEROFF", lps_poweroff },
{ UNIT_POWEROFF, 0, "power on", "POWERON", lps_poweron },
{ UNIT_OFFLINE, UNIT_OFFLINE, "offline", "OFFLINE", NULL },
{ UNIT_OFFLINE, 0, "online", "ONLINE", lps_restart },
{ MTAB_XTD | MTAB_VDV, 0, NULL, "REALTIME",
&lps_set_timing, NULL, NULL },
{ MTAB_XTD | MTAB_VDV, 1, NULL, "FASTTIME",
&lps_set_timing, NULL, NULL },
{ MTAB_XTD | MTAB_VDV, 0, "TIMING", NULL,
NULL, &lps_show_timing, NULL },
{ MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &lps_dev },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &lps_dev },
static MTAB lps_mod[] = {
/* Mask Value Match Value Print String Match String Validation Display Descriptor */
/* ------------- ------------- ----------------- ------------- ------------------ ------- ---------- */
{ UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAGNOSTIC", NULL, NULL, NULL },
{ UNIT_DIAG, 0, "printer mode", "PRINTER", NULL, NULL, NULL },
{ UNIT_OFFLINE, UNIT_OFFLINE, "offline", "OFFLINE", NULL, NULL, NULL },
{ UNIT_OFFLINE, 0, "online", "ONLINE", &lps_restart, NULL, NULL },
{ UNIT_POWEROFF, UNIT_POWEROFF, "power off", "POWEROFF", &lps_poweroff, NULL, NULL },
{ UNIT_POWEROFF, 0, "power on", "POWERON", &lps_poweron, NULL, NULL },
/* Entry Flags Value Print String Match String Validation Display Descriptor */
/* ------------------- ----- ------------ ------------ ---------------- ----------------- ----------------- */
{ MTAB_XDV, 1, NULL, "FASTTIME", &lps_set_timing, NULL, NULL },
{ MTAB_XDV, 0, NULL, "REALTIME", &lps_set_timing, NULL, NULL },
{ MTAB_XDV, 0, "TIMING", NULL, NULL, &lps_show_timing, NULL },
{ MTAB_XDV, 1u, "SC", "SC", &hp_set_dib, &hp_show_dib, (void *) &lps_dib },
{ MTAB_XDV | MTAB_NMO, ~1u, "DEVNO", "DEVNO", &hp_set_dib, &hp_show_dib, (void *) &lps_dib },
{ 0 }
};
static DEBTAB lps_deb [] = {
{ "CMDS", DEB_CMDS },
{ "CPU", DEB_CPU },
{ "XFER", DEB_XFER },
{ "STATE", TRACE_STATE },
{ "IOBUS", TRACE_IOBUS }, /* interface I/O bus signals and data words */
{ NULL, 0 }
};
DEVICE lps_dev = {
"LPS", &lps_unit, lps_reg, lps_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &lps_reset,
NULL, &lps_attach, NULL,
&lps_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG
"LPS", /* device name */
&lps_unit, /* unit array */
lps_reg, /* register array */
lps_mod, /* modifier array */
1, /* number of units */
10, /* address radix */
31, /* address width */
1, /* address increment */
8, /* data radix */
8, /* data width */
NULL, /* examine routine */
NULL, /* deposit routine */
&lps_reset, /* reset routine */
NULL, /* boot routine */
&lps_attach, /* attach routine */
NULL, /* detach routine */
&lps_dib, /* device information block */
DEV_DISABLE | DEV_DIS | DEV_DEBUG, /* device flags */
0, /* debug control flags */
lps_deb, /* debug flag name table */
NULL, /* memory size change routine */
NULL /* logical device name */
};
@@ -288,9 +341,9 @@ DEVICE lps_dev = {
assertion of STC and CLC simultaneously will not.
*/
uint32 lpsio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
static uint32 lpsio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
{
int32 sched;
int32 current_line, current_char;
IOSIGNAL signal;
IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
@@ -335,18 +388,17 @@ while (working_set) {
lps_sta = LPS_PWROFF;
}
stat_data = IORETURN (SCPE_OK, lps_sta); /* diag, rtn status */
stat_data = IORETURN (SCPE_OK, lps_sta); /* diag, rtn status */
if (DEBUG_PRS (lps_dev))
fprintf (sim_deb, ">>LPS LIx: Status %06o returned\n", lps_sta);
tprintf (lps_dev, DEB_CPU, "Status %06o returned\n", lps_sta);
break;
case ioIOO: /* I/O data output */
lps_unit.buf = IODATA (stat_data);
if (DEBUG_PRS (lps_dev))
fprintf (sim_deb, ">>LPS OTx: Character %06o output\n", lps_unit.buf);
tprintf (lps_dev, DEB_CPU, "Control %06o (%s) output\n",
lps_unit.buf, fmt_char (lps_unit.buf & DATA_MASK));
break;
@@ -381,48 +433,47 @@ while (working_set) {
}
else { /* real lpt, sched */
if (DEBUG_PRS (lps_dev)) fprintf (sim_deb,
">>LPS STC: Character %06o scheduled for line %d, column %d, ",
lps_unit.buf, lps_lcnt + 1, lps_ccnt + 1);
current_char = lps_ccnt + 1;
current_line = lps_lcnt + 1;
if ((lps_unit.buf != '\f') &&
(lps_unit.buf != '\n') &&
(lps_unit.buf != '\r')) { /* normal char */
if ((lps_unit.buf != FF) &&
(lps_unit.buf != LF) &&
(lps_unit.buf != CR)) { /* normal char */
lps_ccnt = lps_ccnt + 1; /* incr char counter */
if (lps_ccnt % LPS_ZONECNT == 0) /* end of zone? */
sched = lps_ptime; /* print zone */
lps_unit.wait = lps_ptime; /* print zone */
else
sched = lps_ctime; /* xfer char */
lps_unit.wait = lps_ctime; /* xfer char */
}
else { /* print cmd */
if (lps_ccnt % LPS_ZONECNT == 0) /* last zone printed? */
sched = lps_ctime; /* yes, so just char time */
lps_unit.wait = lps_ctime; /* yes, so just char time */
else
sched = lps_ptime; /* no, so print needed */
lps_unit.wait = lps_ptime; /* no, so print needed */
lps_ccnt = 0; /* reset char counter */
if (lps_unit.buf == '\n') { /* line advance */
if (lps_unit.buf == LF) { /* line advance */
lps_lcnt = (lps_lcnt + 1) % LPS_PAGELNT;
if (lps_lcnt > 0)
sched = sched + lps_stime;
lps_unit.wait += lps_stime;
else
sched = sched + /* allow for perf skip */
lps_stime * (LPS_FORMLNT - LPS_PAGELNT);
lps_unit.wait += /* allow for perf skip */
lps_stime * (LPS_FORMLNT - LPS_PAGELNT);
}
else if (lps_unit.buf == '\f') { /* form advance */
sched = sched + lps_stime * (LPS_FORMLNT - lps_lcnt);
else if (lps_unit.buf == FF) { /* form advance */
lps_unit.wait += lps_stime * (LPS_FORMLNT - lps_lcnt);
lps_lcnt = 0;
}
}
sim_activate (&lps_unit, sched);
sim_activate (&lps_unit, lps_unit.wait);
if (DEBUG_PRS (lps_dev))
fprintf (sim_deb, "time = %d\n", sched);
tprintf (lps_dev, DEB_CMDS, "Character %s scheduled for line %d, column %d, time = %d\n",
fmt_char (lps_unit.buf & DATA_MASK), current_line, current_char, lps_unit.wait);
}
break;
@@ -450,66 +501,78 @@ return stat_data;
}
/* Unit service */
/* Unit service.
t_stat lps_svc (UNIT *uptr)
As a convenience to the user, the printer output file is flushed when a TOF
operation is performed.
*/
static t_stat lps_svc (UNIT *uptr)
{
int32 c = uptr->buf & 0177;
int32 c = uptr->buf & DATA_MASK;
if (lps_power == LPS_TURNING_ON) { /* printer warmed up? */
lps_power = LPS_ON; /* change state */
lps_restart (uptr, 0, NULL, NULL); /* restart I/O if hung */
if (DEBUG_PRS (lps_dev))
fputs (">>LPS svc: Power state is ON\n", sim_deb);
tprintf (lps_dev, TRACE_STATE, "Power state is ON\n");
return SCPE_OK; /* done */
}
if (uptr->flags & UNIT_DIAG) { /* diagnostic? */
lpsio (&lps_dib, ioENF, 0); /* set flag */
return SCPE_OK; /* done */
}
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
return IOERROR (lps_stopioe, SCPE_UNATT);
else if (uptr->flags & UNIT_OFFLINE) /* offline? */
return IOERROR (lps_stopioe, STOP_OFFLINE);
else if (uptr->flags & UNIT_POWEROFF) /* powered off? */
return IOERROR (lps_stopioe, STOP_PWROFF);
if ((uptr->flags & (UNIT_ATT | UNIT_OFFLINE | UNIT_POWEROFF)) != UNIT_ATT) /* not ready? */
return SCPE_OK;
lpsio (&lps_dib, ioENF, 0); /* set flag */
if (((c < ' ') || (c > '_')) && /* non-printing char? */
(c != '\f') && (c != '\n') && (c != '\r')) {
if (DEBUG_PRS (lps_dev))
fprintf (sim_deb, ">>LPS svc: Character %06o erased\n", c);
(c != FF) && (c != LF) && (c != CR)) {
tprintf (lps_dev, DEB_XFER, "Character %s erased\n", fmt_char (c));
c = ' '; /* replace with blank */
}
if (lps_ccnt > LPS_PAGECNT) { /* 81st character? */
fputc ('\r', uptr->fileref); /* return to line start */
fputc (CR, uptr->fileref); /* return to line start */
uptr->pos = uptr->pos + 1; /* update pos */
lps_ccnt = 1; /* reset char counter */
if (DEBUG_PRS (lps_dev))
fputs (">>LPS svc: Line wraparound to column 1\n", sim_deb);
tprintf (lps_dev, DEB_XFER, "Line wraparound to column 1\n");
}
fputc (c, uptr->fileref); /* "print" char */
uptr->pos = uptr->pos + 1; /* update pos */
if (DEBUG_PRS (lps_dev))
fprintf (sim_deb, ">>LPS svc: Character %06o printed\n", c);
if ((lps_lcnt == 0) && (c == '\n')) { /* LF did TOF? */
fputc ('\f', uptr->fileref); /* do perf skip */
uptr->pos = uptr->pos + 1; /* update pos */
if (DEBUG_PRS (lps_dev))
fputs (">>LPS svc: Perforation skip to TOF\n", sim_deb);
tprintf (lps_dev, DEB_XFER, "Character %s printed\n", fmt_char (c));
if (lps_lcnt == 0) { /* if the printer is at the TOF */
fflush (uptr->fileref); /* then flush the file buffer for inspection */
if (c == LF) { /* LF did TOF? */
fputc (FF, uptr->fileref); /* do perf skip */
uptr->pos = uptr->pos + 1; /* update pos */
tprintf (lps_dev, DEB_XFER, "Perforation skip to TOF\n");
}
}
if (ferror (uptr->fileref)) {
perror ("LPS I/O error");
clearerr (uptr->fileref);
if (ferror (uptr->fileref)) { /* if a host file I/O error occurred */
cprintf ("%s simulator printer I/O error: %s\n", /* then report the error to the console */
sim_name, strerror (errno));
clearerr (uptr->fileref); /* clear the error */
lps_unit.flags |= UNIT_OFFLINE; /* set offline */
return SCPE_IOERR;
}
return SCPE_OK;
}
/* Reset routine */
t_stat lps_reset (DEVICE *dptr)
static t_stat lps_reset (DEVICE *dptr)
{
if (sim_switches & SWMASK ('P')) { /* power-on reset? */
lps_power = LPS_ON; /* power is on */
@@ -538,7 +601,7 @@ return SCPE_OK;
original I/O request.
*/
t_stat lps_restart (UNIT *uptr, int32 value, CONST char *cptr, void *desc)
static t_stat lps_restart (UNIT *uptr, int32 value, CONST char *cptr, void *desc)
{
if (lps.control && !sim_is_active (uptr))
sim_activate (uptr, 0); /* reschedule I/O */
@@ -547,40 +610,68 @@ return SCPE_OK;
/* Printer power off */
t_stat lps_poweroff (UNIT *uptr, int32 value, CONST char *cptr, void *desc)
static t_stat lps_poweroff (UNIT *uptr, int32 value, CONST char *cptr, void *desc)
{
lps_power = LPS_OFF; /* change state */
if (DEBUG_PRS (lps_dev)) fputs (">>LPS set: Power state is OFF\n", sim_deb);
tprintf (lps_dev, TRACE_STATE, "Power state is OFF\n");
return SCPE_OK;
}
/* Printer power on */
t_stat lps_poweron (UNIT *uptr, int32 value, CONST char *cptr, void *desc)
static t_stat lps_poweron (UNIT *uptr, int32 value, CONST char *cptr, void *desc)
{
if (lps_unit.flags & UNIT_DIAG) { /* diag mode? */
lps_power = LPS_ON; /* no delay */
if (DEBUG_PRS (lps_dev))
fputs (">>LPS set: Power state is ON\n", sim_deb);
tprintf (lps_dev, TRACE_STATE, "Power state is ON\n");
}
else {
lps_power = LPS_TURNING_ON; /* change state */
lps_unit.flags |= UNIT_OFFLINE; /* set offline */
sim_activate (&lps_unit, lps_rtime); /* schedule ready */
if (DEBUG_PRS (lps_dev)) fprintf (sim_deb,
">>LPS set: Power state is TURNING ON, scheduled time = %d\n",
lps_rtime );
tprintf (lps_dev, TRACE_STATE, "Power state is TURNING ON, scheduled time = %d\n",
lps_rtime);
}
return SCPE_OK;
}
/* Attach routine */
/* Attach the printer image file.
t_stat lps_attach (UNIT *uptr, CONST char *cptr)
The specified file is attached to the indicated unit. This is the simulation
equivalent of loading paper into the printer and pressing the ONLINE button.
The transition from offline to online typically generates an interrupt.
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
the form.
Implementation notes:
1. If we are called during a RESTORE command to reattach a file previously
attached when the simulation was SAVEd, the device status and file
position are not altered. This is because SIMH 4.x restores the register
contents before reattaching, while 3.x reattaches before restoring the
registers.
*/
static t_stat lps_attach (UNIT *uptr, CONST char *cptr)
{
lps_ccnt = lps_lcnt = 0; /* top of form */
lps_restart (uptr, 0, NULL, NULL); /* restart I/O if hung */
return attach_unit (uptr, cptr);
t_stat result;
result = hp_attach (uptr, cptr); /* attach the specified printer image file for appending */
if (result == SCPE_OK /* if the attach was successful */
&& (sim_switches & SIM_SW_REST) == 0) { /* and we are not being called during a RESTORE command */
lps_ccnt = 0; /* then clear the character counter */
lps_lcnt = 0; /* and set top of form */
lps_restart (uptr, 0, NULL, NULL); /* restart I/O if hung */
}
return result;
}
/* Set printer timing
@@ -588,7 +679,7 @@ return attach_unit (uptr, cptr);
Realistic timing is factored, depending on CPU model, to account for the
timing method employed by the diagnostic. */
t_stat lps_set_timing (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
static t_stat lps_set_timing (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
uint32 i, factor = 1;
@@ -604,7 +695,7 @@ return SCPE_OK;
/* Show printer timing */
t_stat lps_show_timing (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
static t_stat lps_show_timing (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
if (lps_timing) fputs ("fast timing", st);
else fputs ("realistic timing", st);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,31 +1,42 @@
/* hp2100_ms.c: HP 2100 13181A/13183A magnetic tape simulator
/* hp2100_ms.c: HP 2100 13181B/13183B Digital Magnetic Tape Unit Interface simulator
Copyright (c) 1993-2016, Robert M. Supnik
Copyright (c) 2017-2018, 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 in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not be
Except as contained in this notice, the names of the authors shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
in this Software without prior written authorization from the authors.
MS 13181A 7970B 800bpi nine track magnetic tape
13183A 7970E 1600bpi nine track magnetic tape
MS 13181B Digital Magnetic Tape Unit Interface
13183B Digital Magnetic Tape Unit Interface
28-Feb-18 JDB Added the BMTL
23-Feb-18 JDB Eliminated "msc_boot" references to A and S registers
20-Jul-17 JDB Removed "msc_stopioe" variable and register
11-Jul-17 JDB Renamed "ibl_copy" to "cpu_ibl"
15-Mar-17 JDB Trace flags are now global
Changed DEBUG_PRI calls to tprintfs
13-Mar-17 JDB Deprecated LOCKED/WRITEENABLED for ATTACH -R
10-Mar-17 JDB Added IOBUS to the debug table
27-Feb-17 JDB ibl_copy no longer returns a status code
17-Jan-17 JDB Modified to use "odd_parity" array in hp2100_sys.c
13-May-16 JDB Modified for revised SCP API function parameter types
30-Dec-14 JDB Added S-register parameters to ibl_copy
24-Dec-14 JDB Use T_ADDR_FMT with t_addr values for 64-bit compatibility
@@ -75,18 +86,22 @@
22-Apr-02 RMS Added maximum record length test
References:
- 13181B Digital Magnetic Tape Unit Interface Kit Operating and Service Manual
(13181-90901, Nov-1982)
- 13183B Digital Magnetic Tape Unit Interface Kit Operating and Service Manual
(13183-90901, Nov-1983)
- SIMH Magtape Representation and Handling (Bob Supnik, 30-Aug-2006)
- 13181B Digital Magnetic Tape Unit Interface Kit Operating and Service Manual
(13181-90901, November 1982)
- 13183B Digital Magnetic Tape Unit Interface Kit Operating and Service Manual
(13183-90901, November 1983)
- SIMH Magtape Representation and Handling
(Bob Supnik, 30-Aug-2006)
*/
#include "hp2100_defs.h"
#include "hp2100_cpu.h"
#include "sim_tape.h"
#define UNIT_V_OFFLINE (MTUF_V_UF + 0) /* unit offline */
#define UNIT_OFFLINE (1 << UNIT_V_OFFLINE)
@@ -103,12 +118,6 @@
#define GAP_13183 30 /* gap is 3.0 inches for 13183 cntlr */
#define TCAP (300 * 12 * 800) /* 300 ft capacity at 800 bpi */
/* Debug flags */
#define DEB_CMDS (1 << 0) /* command init and compl */
#define DEB_CPU (1 << 1) /* CPU I/O */
#define DEB_RWS (1 << 2) /* tape reads, writes, status */
/* Command - msc_fnc */
#define FNC_CLR 00110 /* clear */
@@ -180,7 +189,6 @@ int32 msc_sta = 0; /* status */
int32 msc_buf = 0; /* buffer */
int32 msc_usl = 0; /* unit select */
int32 msc_1st = 0; /* first service */
int32 msc_stopioe = 1; /* stop on error */
struct {
FLIP_FLOP control; /* control flip-flop */
@@ -220,12 +228,12 @@ int32 msc_xtime = 0; /* data xfer time / word
typedef int32 TIMESET[6]; /* set of controller times */
int32 *const timers[] = { &msc_btime, &msc_ctime, &msc_gtime,
&msc_itime, &msc_rtime, &msc_xtime };
int32 *const timers [] = { &msc_btime, &msc_ctime, &msc_gtime,
&msc_itime, &msc_rtime, &msc_xtime };
const TIMESET msc_times[3] = {
{ 161512, 14044, 175553, 24885, 878, 88 }, /* 13181A */
{ 252800, 17556, 105333, 27387, 878, 44 }, /* 13183A */
const TIMESET msc_times [3] = {
{ 161512, 14044, 175553, 24885, 878, 88 }, /* 13181B */
{ 252800, 17556, 105333, 27387, 878, 44 }, /* 13183B */
{ 1, 1000, 1, 1, 100, 10 } /* FAST */
};
@@ -284,9 +292,11 @@ REG msd_reg[] = {
{ NULL }
};
MTAB msd_mod[] = {
{ MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &msd_dev },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &msd_dev },
MTAB msd_mod [] = {
/* Entry Flags Value Print String Match String Validation Display Descriptor */
/* ------------------- ----- ------------ ------------ ------------ ------------- ---------------- */
{ MTAB_XDV, 2u, "SC", "SC", &hp_set_dib, &hp_show_dib, (void *) &ms_dib },
{ MTAB_XDV | MTAB_NMO, ~2u, "DEVNO", "DEVNO", &hp_set_dib, &hp_show_dib, (void *) &ms_dib },
{ 0 }
};
@@ -337,46 +347,67 @@ REG msc_reg[] = {
{ DRDATA (RTIME, msc_rtime, 24), REG_NZ + PV_LEFT },
{ DRDATA (XTIME, msc_xtime, 24), REG_NZ + PV_LEFT },
{ FLDATA (TIMING, ms_timing, 0), REG_HRO },
{ FLDATA (STOP_IOE, msc_stopioe, 0) },
{ FLDATA (CTYPE, ms_ctype, 0), REG_HRO },
{ ORDATA (SC, msc_dib.select_code, 6), REG_HRO },
{ ORDATA (DEVNO, msc_dib.select_code, 6), REG_HRO },
{ NULL }
};
MTAB msc_mod[] = {
{ UNIT_OFFLINE, UNIT_OFFLINE, "offline", "OFFLINE", NULL },
{ UNIT_OFFLINE, 0, "online", "ONLINE", msc_online },
{ MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL },
{ MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL },
{ MTAB_XTD | MTAB_VUN, 0, "CAPACITY", "CAPACITY",
&ms_set_reelsize, &ms_show_reelsize, NULL },
{ MTAB_XTD | MTAB_VUN | MTAB_NMO, 1, "REEL", "REEL",
&ms_set_reelsize, &ms_show_reelsize, NULL },
{ MTAB_XTD | MTAB_VUN, 0, "FORMAT", "FORMAT",
&sim_tape_set_fmt, &sim_tape_show_fmt, NULL },
{ MTAB_XTD | MTAB_VDV, 0, NULL, "13181A",
&ms_settype, NULL, NULL },
{ MTAB_XTD | MTAB_VDV, 1, NULL, "13183A",
&ms_settype, NULL, NULL },
{ MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL,
NULL, &ms_showtype, NULL },
{ MTAB_XTD | MTAB_VDV, 0, NULL, "REALTIME",
&ms_set_timing, NULL, NULL },
{ MTAB_XTD | MTAB_VDV, 1, NULL, "FASTTIME",
&ms_set_timing, NULL, NULL },
{ MTAB_XTD | MTAB_VDV, 0, "TIMING", NULL,
NULL, &ms_show_timing, NULL },
{ MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &msd_dev },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &msd_dev },
/* Modifier list.
The LOCKED and WRITEENABLED modifiers are deprecated. The supported method
of write-protecting a tape drive is to attach the tape image with the -R
(read-only) switch or by setting the host operating system's read-only
attribute on the tape image file. This simulates removing the write ring
from the tape reel before mounting it on the drive. There is no hardware
method of write-protecting a mounted and positioned tape reel.
Implementation notes:
1. The UNIT_RO modifier displays "write ring" if the flag is not set. There
is no corresponding entry for the opposite condition because "read only"
is automatically printed after the attached filename.
*/
MTAB msc_mod [] = {
/* Mask Value Match Value Print String Match String Validation Display Descriptor */
/* ------------- ------------- ---------------- --------------- ------------ ------- ---------- */
{ UNIT_RO, 0, "write ring", NULL, NULL, NULL, NULL },
{ UNIT_OFFLINE, UNIT_OFFLINE, "offline", "OFFLINE", NULL, NULL, NULL },
{ UNIT_OFFLINE, 0, "online", "ONLINE", &msc_online, NULL, NULL },
{ MTUF_WLK, 0, NULL, "WRITEENABLED", NULL, NULL, NULL },
{ MTUF_WLK, MTUF_WLK, NULL, "LOCKED", NULL, NULL, NULL },
/* Entry Flags Value Print String Match String Validation Display Descriptor */
/* ------------------- ----- ------------ ------------ ----------------- ------------------ ---------------- */
{ MTAB_XUN, 0, "CAPACITY", "CAPACITY", &ms_set_reelsize, &ms_show_reelsize, NULL },
{ MTAB_XUN | MTAB_NMO, 1, "REEL", "REEL", &ms_set_reelsize, &ms_show_reelsize, NULL },
{ MTAB_XUN, 0, "FORMAT", "FORMAT", &sim_tape_set_fmt, &sim_tape_show_fmt, NULL },
{ MTAB_XDV, 0, NULL, "13181A/B", &ms_settype, NULL, NULL },
{ MTAB_XDV, 1, NULL, "13183A/B", &ms_settype, NULL, NULL },
{ MTAB_XDV, 0, "TYPE", NULL, NULL, &ms_showtype, NULL },
{ MTAB_XDV, 0, NULL, "REALTIME", &ms_set_timing, NULL, NULL },
{ MTAB_XDV, 1, NULL, "FASTTIME", &ms_set_timing, NULL, NULL },
{ MTAB_XDV, 0, "TIMING", NULL, NULL, &ms_show_timing, NULL },
{ MTAB_XDV, 2u, "SC", "SC", &hp_set_dib, &hp_show_dib, (void *) &ms_dib },
{ MTAB_XDV | MTAB_NMO, ~2u, "DEVNO", "DEVNO", &hp_set_dib, &hp_show_dib, (void *) &ms_dib },
{ 0 }
};
DEBTAB msc_deb[] = {
{ "CMDS", DEB_CMDS },
{ "CPU", DEB_CPU },
{ "RWS", DEB_RWS },
{ NULL, 0 }
{ "CMDS", DEB_CMDS },
{ "RWS", DEB_RWS },
{ "CPU", DEB_CPU },
{ "IOBUS", TRACE_IOBUS }, /* interface I/O bus signals and data words */
{ NULL, 0 }
};
DEVICE msc_dev = {
@@ -554,11 +585,10 @@ while (working_set) {
else
data = data | STA_TBSY | STA_LOCAL;
if (ms_ctype == A13183) /* 13183A? */
if (ms_ctype == A13183) /* 13183? */
data = data | STA_PE | (uint16) (msc_usl << STA_V_SEL);
if (DEBUG_PRI (msc_dev, DEB_CPU))
fprintf (sim_deb, ">>MSC LIx: Status = %06o\n", data);
tprintf (msc_dev, DEB_CPU, "Status = %06o\n", data);
stat_data = IORETURN (SCPE_OK, data); /* merge in return status */
break;
@@ -567,8 +597,7 @@ while (working_set) {
case ioIOO: /* I/O data output */
msc_buf = IODATA (stat_data); /* clear supplied status */
if (DEBUG_PRI (msc_dev, DEB_CPU))
fprintf (sim_deb, ">>MSC OTx: Command = %06o\n", msc_buf);
tprintf (msc_dev, DEB_CPU, "Command = %06o\n", msc_buf);
msc_sta = msc_sta & ~STA_REJ; /* clear reject */
@@ -583,8 +612,7 @@ while (working_set) {
if (msc_buf & FNF_CHS) { /* select change */
msc_usl = map_sel[FNC_GETSEL (msc_buf)]; /* is immediate */
uptr = msc_dev.units + msc_usl;
if (DEBUG_PRI (msc_dev, DEB_CMDS))
fprintf (sim_deb, ">>MSC OTx: Unit %d selected\n", msc_usl);
tprintf (msc_dev, DEB_CMDS, "Unit %d selected\n", msc_usl);
}
if (((msc_buf & FNF_MOT) && sim_is_active (uptr)) ||
@@ -614,8 +642,7 @@ while (working_set) {
working_set = working_set & ~ioCLF; /* eliminate possible CLF */
if (DEBUG_PRI (msc_dev, DEB_CMDS))
fputs (">>MSC STC: Controller cleared\n", sim_deb);
tprintf (msc_dev, DEB_CMDS, "Controller cleared\n");
break; /* command completes immediately */
}
@@ -645,16 +672,14 @@ while (working_set) {
if (msc_buf & ~FNC_SEL) { /* NOP for unit sel alone */
sim_activate (uptr, sched_time); /* else schedule op */
if (DEBUG_PRI (msc_dev, DEB_CMDS))
fprintf (sim_deb,
">>MSC STC: Unit %d command %03o (%s) scheduled, "
"pos = %" T_ADDR_FMT "d, time = %d\n",
msc_usl, uptr->FNC, ms_cmd_name (uptr->FNC),
uptr->pos, sched_time);
tprintf (msc_dev, DEB_CMDS, "Unit %d command %03o (%s) scheduled, "
"pos = %" T_ADDR_FMT "d, time = %d\n",
msc_usl, uptr->FNC, ms_cmd_name (uptr->FNC),
uptr->pos, sched_time);
}
else if (DEBUG_PRI (msc_dev, DEB_CMDS))
fputs (">>MSC STC: Unit select (NOP)\n", sim_deb);
else
tprintf (msc_dev, DEB_CMDS, "Unit select (NOP)\n");
msc_sta = STA_BUSY; /* ctrl is busy */
msc_1st = 1;
@@ -713,7 +738,7 @@ unum = uptr - msc_unit; /* get unit number */
if ((uptr->FNC != FNC_RWS) && (uptr->flags & UNIT_OFFLINE)) { /* offline? */
msc_sta = (msc_sta | STA_REJ) & ~STA_BUSY; /* reject */
mscio (&msc_dib, ioENF, 0); /* set flag */
return IOERROR (msc_stopioe, SCPE_UNATT);
return SCPE_OK;
}
switch (uptr->FNC) { /* case on function */
@@ -741,10 +766,8 @@ switch (uptr->FNC) { /* case on function */
goto DO_WFM; /* do plain file mark */
/* else fall into GAP */
case FNC_GAP: /* erase gap */
if (DEBUG_PRI (msc_dev, DEB_RWS))
fprintf (sim_deb,
">>MSC svc: Unit %d wrote gap\n",
unum);
tprintf (msc_dev, DEB_RWS, "Unit %d wrote gap\n", unum);
r = ms_write_gap (uptr); /* write tape gap*/
if (r || (uptr->FNC != FNC_GFM)) /* if error or not GFM */
@@ -752,10 +775,8 @@ switch (uptr->FNC) { /* case on function */
/* else drop into WFM */
case FNC_WFM: /* write file mark */
if ((ms_timing == 0) && sim_tape_bot (uptr)) { /* realistic timing + BOT? */
if (DEBUG_PRI (msc_dev, DEB_RWS))
fprintf (sim_deb,
">>MSC svc: Unit %d wrote initial gap\n",
unum);
tprintf (msc_dev, DEB_RWS, "Unit %d wrote initial gap\n", unum);
st = ms_write_gap (uptr); /* write initial gap*/
if (st != MTSE_OK) { /* error? */
r = ms_map_err (uptr, st); /* map error */
@@ -763,10 +784,8 @@ switch (uptr->FNC) { /* case on function */
}
}
DO_WFM:
if (DEBUG_PRI (msc_dev, DEB_RWS))
fprintf (sim_deb,
">>MSC svc: Unit %d wrote file mark\n",
unum);
tprintf (msc_dev, DEB_RWS, "Unit %d wrote file mark\n", unum);
st = sim_tape_wrtmk (uptr); /* write tmk */
if (st != MTSE_OK) /* error? */
r = ms_map_err (uptr, st); /* map error */
@@ -808,10 +827,8 @@ switch (uptr->FNC) { /* case on function */
if (msc_1st) { /* first svc? */
msc_1st = ms_ptr = ms_max = 0; /* clr 1st flop */
st = sim_tape_rdrecf (uptr, msxb, &ms_max, DBSIZE); /* read rec */
if (DEBUG_PRI (msc_dev, DEB_RWS))
fprintf (sim_deb,
">>MSC svc: Unit %d read %d word record\n",
unum, ms_max / 2);
tprintf (msc_dev, DEB_RWS, "Unit %d read %d word record\n",
unum, ms_max / 2);
if (st == MTSE_RECE) msc_sta = msc_sta | STA_PAR; /* rec in err? */
else if (st != MTSE_OK) { /* other error? */
r = ms_map_err (uptr, st); /* map error */
@@ -823,7 +840,7 @@ switch (uptr->FNC) { /* case on function */
break; /* err, done */
}
if (ms_ctype == A13183)
msc_sta = msc_sta | STA_ODD; /* set ODD for 13183A */
msc_sta = msc_sta | STA_ODD; /* set ODD for 13183 */
}
if (msd.control && (ms_ptr < ms_max)) { /* DCH on, more data? */
if (msd.flag) msc_sta = msc_sta | STA_TIM | STA_PAR;
@@ -854,10 +871,8 @@ switch (uptr->FNC) { /* case on function */
if (msc_1st) { /* first service? */
msc_1st = ms_ptr = 0; /* no data xfer on first svc */
if ((ms_timing == 0) && sim_tape_bot (uptr)) { /* realistic timing + BOT? */
if (DEBUG_PRI (msc_dev, DEB_RWS))
fprintf (sim_deb,
">>MSC svc: Unit %d wrote initial gap\n",
unum);
tprintf (msc_dev, DEB_RWS, "Unit %d wrote initial gap\n", unum);
st = ms_write_gap (uptr); /* write initial gap */
if (st != MTSE_OK) { /* error? */
r = ms_map_err (uptr, st); /* map error */
@@ -879,10 +894,8 @@ switch (uptr->FNC) { /* case on function */
return SCPE_OK;
}
if (ms_ptr) { /* any data? write */
if (DEBUG_PRI (msc_dev, DEB_RWS))
fprintf (sim_deb,
">>MSC svc: Unit %d wrote %d word record\n",
unum, ms_ptr / 2);
tprintf (msc_dev, DEB_RWS, "Unit %d wrote %d word record\n",
unum, ms_ptr / 2);
st = sim_tape_wrrecf (uptr, msxb, ms_ptr); /* write */
if (st != MTSE_OK) {
r = ms_map_err (uptr, st); /* map error */
@@ -900,19 +913,16 @@ switch (uptr->FNC) { /* case on function */
case FNC_RRR: /* not supported */
default: /* unknown command */
if (DEBUG_PRI (msc_dev, DEB_CMDS))
fprintf (sim_deb,
">>MSC svc: Unit %d command %03o is unknown (NOP)\n",
unum, uptr->FNC);
tprintf (msc_dev, DEB_CMDS, "Unit %d command %03o is unknown (NOP)\n",
unum, uptr->FNC);
break;
}
mscio (&msc_dib, ioENF, 0); /* set flag */
msc_sta = msc_sta & ~STA_BUSY; /* update status */
if (DEBUG_PRI (msc_dev, DEB_CMDS))
fprintf (sim_deb,
">>MSC svc: Unit %d command %03o (%s) complete\n",
unum, uptr->FNC & 0377, ms_cmd_name (uptr->FNC));
tprintf (msc_dev, DEB_CMDS, "Unit %d command %03o (%s) complete\n",
unum, uptr->FNC & 0377, ms_cmd_name (uptr->FNC));
return r;
}
@@ -939,10 +949,7 @@ t_stat ms_map_err (UNIT *uptr, t_stat st)
{
int32 unum = uptr - msc_unit; /* get unit number */
if (DEBUG_PRI (msc_dev, DEB_RWS))
fprintf (sim_deb,
">>MSC err: Unit %d tape library status = %d\n",
unum, st);
tprintf (msc_dev, DEB_RWS, "Unit %d tape library status = %d\n", unum, st);
switch (st) {
@@ -963,7 +970,7 @@ switch (st) {
msc_sta = msc_sta | STA_EOF;
if (ms_ctype == A13181)
msc_sta = msc_sta | STA_ODD; /* EOF also sets ODD for 13181A */
msc_sta = msc_sta | STA_ODD; /* EOF also sets ODD for 13181B */
break;
case MTSE_INVRL: /* invalid rec lnt */
@@ -972,8 +979,7 @@ switch (st) {
case MTSE_IOERR: /* IO error */
msc_sta = msc_sta | STA_PAR; /* error */
if (msc_stopioe) return SCPE_IOERR;
break;
return SCPE_IOERR;
case MTSE_RECE: /* record in error */
msc_sta = msc_sta | STA_PAR; /* error */
@@ -1002,9 +1008,7 @@ for (i = 0; i < MS_NUMDR; i++) { /* look for write in pro
if (sim_is_active (uptr) && /* unit active? */
(uptr->FNC == FNC_WC) && /* and last cmd write? */
(ms_ptr > 0)) { /* and partial buffer? */
if (DEBUG_PRI (msc_dev, DEB_RWS))
fprintf (sim_deb,
">>MSC rws: Unit %d wrote %d word partial record\n", i, ms_ptr / 2);
tprintf (msc_dev, DEB_RWS, "Unit %d wrote %d word partial record\n", i, ms_ptr / 2);
st = sim_tape_wrrecf (uptr, msxb, ms_ptr | MTR_ERF);
@@ -1143,9 +1147,9 @@ return SCPE_OK;
t_stat ms_showtype (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
if (ms_ctype == A13183)
fprintf (st, "13183A");
fprintf (st, "13183B");
else
fprintf (st, "13181A");
fprintf (st, "13181B");
return SCPE_OK;
}
@@ -1237,120 +1241,240 @@ switch (cmd & 0377) {
}
}
/* 7970B/7970E bootstrap routine (HP 12992D ROM) */
const BOOT_ROM ms_rom = {
0106501, /*ST LIB 1 ; read sw */
0006011, /* SLB,RSS ; bit 0 set? */
0027714, /* JMP RD ; no read */
0003004, /* CMA,INA ; A is ctr */
0073775, /* STA WC ; save */
0067772, /* LDA SL0RW ; sel 0, rew */
0017762, /*FF JSB CMD ; do cmd */
0102311, /* SFS CC ; done? */
0027707, /* JMP *-1 ; wait */
0067774, /* LDB FFC ; get file fwd */
0037775, /* ISZ WC ; done files? */
0027706, /* JMP FF ; no */
0067773, /*RD LDB RDCMD ; read cmd */
0017762, /* JSB CMD ; do cmd */
0103710, /* STC DC,C ; start dch */
0102211, /* SFC CC ; read done? */
0027752, /* JMP STAT ; no, get stat */
0102310, /* SFS DC ; any data? */
0027717, /* JMP *-3 ; wait */
0107510, /* LIB DC,C ; get rec cnt */
0005727, /* BLF,BLF ; move to lower */
0007000, /* CMB ; make neg */
0077775, /* STA WC ; save */
0102211, /* SFC CC ; read done? */
0027752, /* JMP STAT ; no, get stat */
0102310, /* SFS DC ; any data? */
0027727, /* JMP *-3 ; wait */
0107510, /* LIB DC,C ; get load addr */
0074000, /* STB 0 ; start csum */
0077762, /* STA CMD ; save address */
0027742, /* JMP *+4 */
0177762, /*NW STB CMD,I ; store data */
0040001, /* ADA 1 ; add to csum */
0037762, /* ISZ CMD ; adv addr ptr */
0102310, /* SFS DC ; any data? */
0027742, /* JMP *-1 ; wait */
0107510, /* LIB DC,C ; get word */
0037775, /* ISZ WC ; done? */
0027737, /* JMP NW ; no */
0054000, /* CPB 0 ; csum ok? */
0027717, /* JMP RD+3 ; yes, cont */
0102011, /* HLT 11 ; no, halt */
0102511, /*ST LIA CC ; get status */
0001727, /* ALF,ALF ; get eof bit */
0002020, /* SSA ; set? */
0102077, /* HLT 77 ; done */
0001727, /* ALF,ALF ; put status back */
0001310, /* RAR,SLA ; read ok? */
0102000, /* HLT 0 ; no */
0027714, /* JMP RD ; read next */
0000000, /*CMD 0 */
0106611, /* OTB CC ; output cmd */
0102511, /* LIA CC ; check for reject */
0001323, /* RAR,RAR */
0001310, /* RAR,SLA */
0027763, /* JMP CMD+1 ; try again */
0103711, /* STC CC,C ; start command */
0127762, /* JMP CMD,I ; exit */
0001501, /*SL0RW 001501 ; select 0, rewind */
0001423, /*RDCMD 001423 ; read record */
0000203, /*FFC 000203 ; space forward file */
0000000, /*WC 000000 */
0000000,
0000000
/* 7970B/7970E bootstrap loaders (BMTL and 12992D).
The Basic Magnetic Tape Loader (BMTL) reads an absolute binary program from
tape into memory. Before execution, the S register must be set as follows:
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| - - - - - - - - - - | file number |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
If S-register bits 5-0 are zero, the file located at the current tape
position is read. If the bits are non-zero, the tape is rewound, and the
file number (1 - n) specified by the bits is read.
The 12992D boot loader ROM reads an absolute program from tape into memory.
If S-register bit 0 is 0, the file located at the current tape position is
read. If bit 0 is 1, the tape is rewound, and the file number (1 - n)
specified by the A-register value is read.
For either loader, the tape format must be absolute binary, and a tape mark
must end the file. Loader execution ends with one of the following
instructions:
* HLT 00 - a tape read (parity) error occurred.
* HLT 11 - a checksum error occurred; A/B = the calculated/tape value.
* HLT 77 - the end of the file was reached with a successful read.
*/
static const LOADER_ARRAY ms_loaders = {
{ /* HP 21xx Basic Magnetic Tape Loader (BMTL) */
000, /* loader starting index */
IBL_NA, /* DMA index */
IBL_NA, /* FWA index */
{ 0102501, /* 77700: MTAPE LIA 1 */
0013775, /* 77701: AND 77775 */
0003007, /* 77702: CMA,INA,SZA,RSS */
0027714, /* 77703: JMP 77714 */
0073777, /* 77704: STA 77777 */
0067771, /* 77705: LDB 77771 */
0017761, /* 77706: JSB 77761 */
0102311, /* 77707: SFS 11 */
0027707, /* 77710: JMP 77707 */
0067773, /* 77711: LDB 77773 */
0037777, /* 77712: ISZ 77777 */
0027706, /* 77713: JMP 77706 */
0067772, /* 77714: LDB 77772 */
0017761, /* 77715: JSB 77761 */
0103710, /* 77716: STC 10,C */
0017740, /* 77717: JSB 77740 */
0005727, /* 77720: BLF,BLF */
0007004, /* 77721: CMB,INB */
0077777, /* 77722: STB 77777 */
0017740, /* 77723: JSB 77740 */
0074000, /* 77724: STB 0 */
0077776, /* 77725: STB 77776 */
0017740, /* 77726: JSB 77740 */
0177776, /* 77727: STB 77776,I */
0040001, /* 77730: ADA 1 */
0037776, /* 77731: ISZ 77776 */
0037777, /* 77732: ISZ 77777 */
0027726, /* 77733: JMP 77726 */
0017740, /* 77734: JSB 77740 */
0054000, /* 77735: CPB 0 */
0017740, /* 77736: JSB 77740 */
0102011, /* 77737: HLT 11 */
0000000, /* 77740: NOP */
0102310, /* 77741: SFS 10 */
0027745, /* 77742: JMP 77745 */
0107510, /* 77743: LIB 10,C */
0127740, /* 77744: JMP 77740,I */
0102311, /* 77745: SFS 11 */
0027741, /* 77746: JMP 77741 */
0102511, /* 77747: LIA 11 */
0013774, /* 77750: AND 77774 */
0067777, /* 77751: LDB 77777 */
0001727, /* 77752: ALF,ALF */
0002020, /* 77753: SSA */
0102077, /* 77754: HLT 77 */
0002003, /* 77755: SZA,RSS */
0006002, /* 77756: SZB */
0102000, /* 77757: HLT 0 */
0027714, /* 77760: JMP 77714 */
0000000, /* 77761: NOP */
0106611, /* 77762: OTB 11 */
0102511, /* 77763: LIA 11 */
0001323, /* 77764: RAR,RAR */
0001310, /* 77765: RAR,SLA */
0027762, /* 77766: JMP 77762 */
0103711, /* 77767: STC 11,C */
0127761, /* 77770: JMP 77761,I */
0001501, /* 77771: OCT 1501 */
0001423, /* 77772: OCT 1423 */
0000203, /* 77773: OCT 203 */
0016263, /* 77774: OCT 16263 */
0000077, /* 77775: OCT 77 */
0000000, /* 77776: NOP */
0000000 } }, /* 77777: NOP */
{ /* HP 1000 Loader ROM (12992D) */
IBL_START, /* loader starting index */
IBL_DMA, /* DMA index */
IBL_FWA, /* FWA index */
{ 0106501, /* 77700: ST LIB 1 ; read sw */
0006011, /* 77701: SLB,RSS ; bit 0 set? */
0027714, /* 77702: JMP RD ; no read */
0003004, /* 77703: CMA,INA ; A is ctr */
0073775, /* 77704: STA WC ; save */
0067772, /* 77705: LDA SL0RW ; sel 0, rew */
0017762, /* 77706: FF JSB CMD ; do cmd */
0102311, /* 77707: SFS CC ; done? */
0027707, /* 77710: JMP *-1 ; wait */
0067774, /* 77711: LDB FFC ; get file fwd */
0037775, /* 77712: ISZ WC ; done files? */
0027706, /* 77713: JMP FF ; no */
0067773, /* 77714: RD LDB RDCMD ; read cmd */
0017762, /* 77715: JSB CMD ; do cmd */
0103710, /* 77716: STC DC,C ; start dch */
0102211, /* 77717: SFC CC ; read done? */
0027752, /* 77720: JMP STAT ; no, get stat */
0102310, /* 77721: SFS DC ; any data? */
0027717, /* 77722: JMP *-3 ; wait */
0107510, /* 77723: LIB DC,C ; get rec cnt */
0005727, /* 77724: BLF,BLF ; move to lower */
0007000, /* 77725: CMB ; make neg */
0077775, /* 77726: STA WC ; save */
0102211, /* 77727: SFC CC ; read done? */
0027752, /* 77730: JMP STAT ; no, get stat */
0102310, /* 77731: SFS DC ; any data? */
0027727, /* 77732: JMP *-3 ; wait */
0107510, /* 77733: LIB DC,C ; get load addr */
0074000, /* 77734: STB 0 ; start csum */
0077762, /* 77735: STA CMD ; save address */
0027742, /* 77736: JMP *+4 */
0177762, /* 77737: NW STB CMD,I ; store data */
0040001, /* 77740: ADA 1 ; add to csum */
0037762, /* 77741: ISZ CMD ; adv addr ptr */
0102310, /* 77742: SFS DC ; any data? */
0027742, /* 77743: JMP *-1 ; wait */
0107510, /* 77744: LIB DC,C ; get word */
0037775, /* 77745: ISZ WC ; done? */
0027737, /* 77746: JMP NW ; no */
0054000, /* 77747: CPB 0 ; csum ok? */
0027717, /* 77750: JMP RD+3 ; yes, cont */
0102011, /* 77751: HLT 11 ; no, halt */
0102511, /* 77752: ST LIA CC ; get status */
0001727, /* 77753: ALF,ALF ; get eof bit */
0002020, /* 77754: SSA ; set? */
0102077, /* 77755: HLT 77 ; done */
0001727, /* 77756: ALF,ALF ; put status back */
0001310, /* 77757: RAR,SLA ; read ok? */
0102000, /* 77760: HLT 0 ; no */
0027714, /* 77761: JMP RD ; read next */
0000000, /* 77762: CMD NOP */
0106611, /* 77763: OTB CC ; output cmd */
0102511, /* 77764: LIA CC ; check for reject */
0001323, /* 77765: RAR,RAR */
0001310, /* 77766: RAR,SLA */
0027763, /* 77767: JMP CMD+1 ; try again */
0103711, /* 77770: STC CC,C ; start command */
0127762, /* 77771: JMP CMD,I ; exit */
0001501, /* 77772: SL0RW OCT 1501 ; select 0, rewind */
0001423, /* 77773: RDCMD OCT 1423 ; read record */
0000203, /* 77774: FFC OCT 203 ; space forward file */
0000000, /* 77775: WC NOP */
0000000, /* 77776: NOP */
0000000 } } /* 77777: NOP */
};
/* Device boot routine.
This routine is called directly by the BOOT MSC and LOAD MSC commands to copy
the device bootstrap into the upper 64 words of the logical address space.
It is also called indirectly by a BOOT CPU or LOAD CPU command when the
specified HP 1000 loader ROM socket contains a 12992D ROM.
When called in response to a BOOT MSC or LOAD MSC command, the "unitno"
parameter indicates the unit number specified in the BOOT command or is zero
for the LOAD command, and "dptr" points at the MSC device structure. The
bootstrap supports loading only from unit 0, and the command will be rejected
if another unit is specified (e.g., BOOT MSC1). Otherwise, depending on the
current CPU model, the BMTL or 12992D loader ROM will be copied into memory
and configured for the MSD/MSC select code pair. If the CPU is a 1000, the S
register will be set as it would be by the front-panel microcode.
When called for a BOOT/LOAD CPU command, the "unitno" parameter indicates the
select code to be used for configuration, and "dptr" will be NULL. As above,
the BMTL or 12992D loader ROM will be copied into memory and configured for
the specified select code. The S register is assumed to be set correctly on
entry and is not modified.
For the 12992D boot loader ROM for the HP 1000, the S register is set as
follows:
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| ROM # | 0 0 | select code | 0 0 0 0 0 | F |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
Where:
F = Read current/specified file (0/1)
If bit 0 is 0, the file located at the current tape position is read. If bit
0 is 1, the tape is rewound, and the file number (1 - n) specified by the
A-register content is read.
*/
t_stat msc_boot (int32 unitno, DEVICE *dptr)
{
const int32 dev = msd_dib.select_code; /* get data chan device no */
static const HP_WORD ms_preserved = 0000000u; /* no S-register bits are preserved */
static const HP_WORD ms_reposition = 0000001u; /* S-register bit 0 set for a repositioning boot */
if (unitno != 0) /* boot supported on drive unit 0 only */
return SCPE_NOFNC; /* report "Command not allowed" if attempted */
if (dptr == NULL) /* if we are being called for a BOOT/LOAD CPU */
return cpu_copy_loader (ms_loaders, unitno, /* then copy the boot loader to memory */
IBL_S_NOCLEAR, IBL_S_NOSET); /* but do not alter the S register */
if (ibl_copy (ms_rom, dev, IBL_OPT, /* copy the boot ROM to memory and configure */
IBL_MS | IBL_SET_SC (dev))) /* the S register accordingly */
return SCPE_IERR; /* return an internal error if the copy failed */
else if (unitno != 0) /* otherwise a BOOT MSC for a non-zero unit */
return SCPE_NOFNC; /* is rejected as unsupported */
if ((sim_switches & SWMASK ('S')) && AR) /* if -S is specified and the A register is non-zero */
SR = SR | 1; /* then set to skip to the file number in A */
return SCPE_OK;
else /* otherwise this is a BOOT/LOAD MSC */
return cpu_copy_loader (ms_loaders, msd_dib.select_code, /* so copy the boot loader to memory */
ms_preserved, /* and configure the S register if 1000 CPU */
sim_switches & SWMASK ('S') ? ms_reposition : 0);
}
/* Calculate tape record CRC and LRC characters */
#define E 0400 /* parity bit for odd parity */
#define O 0000 /* parity bit for odd parity */
static const uint16 odd_parity [256] = { /* parity table */
E, O, O, E, O, E, E, O, O, E, E, O, E, O, O, E, /* 000-017 */
O, E, E, O, E, O, O, E, E, O, O, E, O, E, E, O, /* 020-037 */
O, E, E, O, E, O, O, E, E, O, O, E, O, E, E, O, /* 040-067 */
E, O, O, E, O, E, E, O, O, E, E, O, E, O, O, E, /* 060-077 */
O, E, E, O, E, O, O, E, E, O, O, E, O, E, E, O, /* 100-117 */
E, O, O, E, O, E, E, O, O, E, E, O, E, O, O, E, /* 120-137 */
E, O, O, E, O, E, E, O, O, E, E, O, E, O, O, E, /* 140-157 */
O, E, E, O, E, O, O, E, E, O, O, E, O, E, E, O, /* 160-177 */
O, E, E, O, E, O, O, E, E, O, O, E, O, E, E, O, /* 200-217 */
E, O, O, E, O, E, E, O, O, E, E, O, E, O, O, E, /* 220-237 */
E, O, O, E, O, E, E, O, O, E, E, O, E, O, O, E, /* 240-267 */
O, E, E, O, E, O, O, E, E, O, O, E, O, E, E, O, /* 260-277 */
E, O, O, E, O, E, E, O, O, E, E, O, E, O, O, E, /* 300-317 */
O, E, E, O, E, O, O, E, E, O, O, E, O, E, E, O, /* 320-337 */
O, E, E, O, E, O, O, E, E, O, O, E, O, E, E, O, /* 340-357 */
E, O, O, E, O, E, E, O, O, E, E, O, E, O, O, E /* 360-377 */
};
static uint32 calc_crc_lrc (uint8 *buffer, t_mtrlnt length)
{
uint32 i;
uint16 byte, crc, lrc;
HP_WORD byte, crc, lrc;
lrc = crc = 0;

View File

@@ -1,30 +1,33 @@
/* hp2100_mt.c: HP 2100 12559A magnetic tape simulator
/* hp2100_mt.c: HP 2100 12559C 9-Track Magnetic Tape Unit Interface
Copyright (c) 1993-2016, Robert M. Supnik
Copyright (c) 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 in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not be
Except as contained in this notice, the names of the authors shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
in this Software without prior written authorization from the authors.
MT 12559A 3030 nine track magnetic tape
MT 12559C 9-Track Magnetic Tape Unit Interface
20-Jul-17 JDB Removed "mtc_stopioe" variable and register
13-Mar-17 JDB Deprecated LOCKED/WRITEENABLED for ATTACH -R
13-May-16 JDB Modified for revised SCP API function parameter types
24-Dec-14 JDB Added casts for explicit downward conversions
10-Jan-13 MP Added DEV_TAPE to DEVICE flags
@@ -58,9 +61,10 @@
04-Oct-98 RMS V2.4 magtape format
References:
- 12559A 9-Track Magnetic Tape Unit Interface Kit Operating and Service Manual
(12559-9001, Jul-1970)
- SIMH Magtape Representation and Handling (Bob Supnik, 30-Aug-2006)
- 12559A 9-Track Magnetic Tape Unit Interface Kit Operating and Service Manual
(12559-9001, July 1970)
- SIMH Magtape Representation and Handling
(Bob Supnik, 30-Aug-2006)
The 3030 was one of HP's earliest tape drives. The 12559A controller
@@ -76,6 +80,7 @@
feature of the 12578A DMA card for the 2116 computer. The second meant that
software drivers had to pad short records with blanks or nulls.
Implementation notes:
1. The HP 3030 Magnetic Tape Subsystem diagnostic, part number 20433-60001,
@@ -84,9 +89,12 @@
*/
#include "hp2100_defs.h"
#include "sim_tape.h"
#define DB_V_SIZE 16 /* max data buf */
#define DBSIZE (1 << DB_V_SIZE) /* max data cmd */
@@ -132,7 +140,6 @@ int32 mtc_1st = 0; /* first svc flop */
int32 mtc_ctime = 40; /* command wait */
int32 mtc_gtime = 1000; /* gap stop time */
int32 mtc_xtime = 15; /* data xfer time */
int32 mtc_stopioe = 1; /* stop on error */
uint8 mtxb[DBSIZE] = { 0 }; /* data buffer */
t_mtrlnt mt_ptr = 0, mt_max = 0; /* buffer ptrs */
static const uint32 mtc_cmd[] = {
@@ -180,8 +187,10 @@ REG mtd_reg[] = {
};
MTAB mtd_mod[] = {
{ MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &mtd_dev },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &mtd_dev },
/* Entry Flags Value Print String Match String Validation Display Descriptor */
/* ------------------- ----- ------------ ------------ ------------ ------------- ---------------- */
{ MTAB_XDV, 2u, "SC", "SC", &hp_set_dib, &hp_show_dib, (void *) &mt_dib },
{ MTAB_XDV | MTAB_NMO, ~2u, "DEVNO", "DEVNO", &hp_set_dib, &hp_show_dib, (void *) &mt_dib },
{ 0 }
};
@@ -216,19 +225,47 @@ REG mtc_reg[] = {
{ DRDATA (CTIME, mtc_ctime, 24), REG_NZ + PV_LEFT },
{ DRDATA (GTIME, mtc_gtime, 24), REG_NZ + PV_LEFT },
{ DRDATA (XTIME, mtc_xtime, 24), REG_NZ + PV_LEFT },
{ FLDATA (STOP_IOE, mtc_stopioe, 0) },
{ ORDATA (SC, mtc_dib.select_code, 6), REG_HRO },
{ ORDATA (DEVNO, mtc_dib.select_code, 6), REG_HRO },
{ NULL }
};
MTAB mtc_mod[] = {
{ MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL },
{ MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL },
{ MTAB_XTD | MTAB_VDV, 0, "FORMAT", "FORMAT",
&sim_tape_set_fmt, &sim_tape_show_fmt, NULL },
{ MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &mtd_dev },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &mtd_dev },
/* Modifier list.
The LOCKED and WRITEENABLED modifiers are deprecated. The supported method
of write-protecting a tape drive is to attach the tape image with the -R
(read-only) switch or by setting the host operating system's read-only
attribute on the tape image file. This simulates removing the write ring
from the tape reel before mounting it on the drive. There is no hardware
method of write-protecting a mounted and positioned tape reel.
Implementation notes:
1. The UNIT_RO modifier displays "write ring" if the flag is not set. There
is no corresponding entry for the opposite condition because "read only"
is automatically printed after the attached filename.
2. FORMAT is really a unit option, but as there is only one unit, it is
specified as MTAB_XDV so that SHOW MTC FORMAT is accepted, rather than
requiring SHOW MTC0 FORMAT.
*/
MTAB mtc_mod [] = {
/* Mask Value Match Value Print String Match String Validation Display Descriptor */
/* ------------- ------------- ---------------- --------------- ------------ ------- ---------- */
{ UNIT_RO, 0, "write ring", NULL, NULL, NULL, NULL },
{ MTUF_WLK, 0, NULL, "WRITEENABLED", NULL, NULL, NULL },
{ MTUF_WLK, MTUF_WLK, NULL, "LOCKED", NULL, NULL, NULL },
/* Entry Flags Value Print String Match String Validation Display Descriptor */
/* ------------------- ----- ------------ ------------ ----------------- ------------------ ---------------- */
{ MTAB_XDV, 0, "FORMAT", "FORMAT", &sim_tape_set_fmt, &sim_tape_show_fmt, NULL },
{ MTAB_XDV, 2u, "SC", "SC", &hp_set_dib, &hp_show_dib, (void *) &mt_dib },
{ MTAB_XDV | MTAB_NMO, ~2u, "DEVNO", "DEVNO", &hp_set_dib, &hp_show_dib, (void *) &mt_dib },
{ 0 }
};
@@ -484,7 +521,7 @@ t_stat st, r = SCPE_OK;
if ((mtc_unit.flags & UNIT_ATT) == 0) { /* offline? */
mtc_sta = STA_LOCAL | STA_REJ; /* rejected */
mtcio (&mtc_dib, ioENF, 0); /* set cch flg */
return IOERROR (mtc_stopioe, SCPE_UNATT);
return SCPE_OK;
}
switch (mtc_fnc) { /* case on function */
@@ -603,7 +640,7 @@ switch (st) {
case MTSE_IOERR: /* IO error */
mtc_sta = mtc_sta | STA_PAR; /* error */
if (mtc_stopioe) return SCPE_IOERR;
return SCPE_IOERR;
break;
case MTSE_INVRL: /* invalid rec lnt */

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/* hp2100_pif.c: HP 12620A/12936A privileged interrupt fence simulator
/* hp2100_pif.c: HP 12620A/12936A Privileged Interrupt Fence simulator
Copyright (c) 2008-2016, J. David Bryan
Copyright (c) 2008-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"),
@@ -23,8 +23,11 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from the author.
PIF 12620A/12936A privileged interrupt fence
PIF 12620A/12936A Privileged Interrupt Fence
15-Mar-17 JDB Trace flags are now global
11-Mar-17 JDB Revised the trace outputs
17-Jan-17 JDB Changed "hp_---sc" and "hp_---dev" to "hp_---_dib"
13-May-16 JDB Modified for revised SCP API function parameter types
10-Feb-12 JDB Deprecated DEVNO in favor of SC
28-Mar-11 JDB Tidied up signal handling
@@ -33,10 +36,10 @@
18-Jun-08 JDB Created PIF device
References:
- 12620A Breadboard Interface Kit Operating and Service Manual
(12620-90001, May-1978)
- 12936A Privileged Interrupt Fence Accessory Installation and Service Manual
(12936-90001, Mar-1974)
- 12620A Breadboard Interface Kit Operating and Service Manual
(12620-90001, May 1978)
- 12936A Privileged Interrupt Fence Accessory Installation and Service Manual
(12936-90001, March 1974)
The Privileged Interupt Fence (PIF) was used in DOS and RTE systems to
@@ -95,9 +98,11 @@
*/
#include "hp2100_defs.h"
/* Device flags */
#define DEV_V_12936 (DEV_V_UF + 0) /* 12936A card */
@@ -158,14 +163,26 @@ REG pif_reg [] = {
};
MTAB pif_mod [] = {
{ MTAB_XTD | MTAB_VDV, 0, NULL, "12620A", &pif_set_card, NULL, NULL },
{ MTAB_XTD | MTAB_VDV, 1, NULL, "12936A", &pif_set_card, NULL, NULL },
{ MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL, NULL, &pif_show_card, NULL },
{ MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &pif_dev },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &pif_dev },
/* Entry Flags Value Print String Match String Validation Display Descriptor */
/* ------------------- ----- ------------ ------------ -------------- -------------- ----------------- */
{ MTAB_XDV, 0, NULL, "12620A", &pif_set_card, NULL, NULL },
{ MTAB_XDV, 1, NULL, "12936A", &pif_set_card, NULL, NULL },
{ MTAB_XDV, 0, "TYPE", NULL, NULL, &pif_show_card, NULL },
{ MTAB_XDV, 1u, "SC", "SC", &hp_set_dib, &hp_show_dib, (void *) &pif_dib },
{ MTAB_XDV | MTAB_NMO, ~1u, "DEVNO", "DEVNO", &hp_set_dib, &hp_show_dib, (void *) &pif_dib },
{ 0 }
};
/* Debugging trace list */
static DEBTAB pif_deb [] = {
{ "CMD", TRACE_CMD }, /* interface commands */
{ "IOBUS", TRACE_IOBUS }, /* interface I/O bus signals and data words */
{ NULL, 0 }
};
DEVICE pif_dev = {
"PIF", /* device name */
&pif_unit, /* unit array */
@@ -186,7 +203,7 @@ DEVICE pif_dev = {
&pif_dib, /* device information block */
DEV_DEBUG | DEV_DISABLE, /* device flags */
0, /* debug control flags */
NULL, /* debug flag name table */
pif_deb, /* debug flag name table */
NULL, /* memory size change routine */
NULL }; /* logical device name */
@@ -218,9 +235,7 @@ DEVICE pif_dev = {
uint32 pif_io (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
{
const char *hold_or_clear = (signal_set & ioCLF ? ",C" : "");
const t_bool is_rte_pif = (pif_dev.flags & DEV_12936) == 0;
IOSIGNAL signal;
IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
@@ -231,19 +246,13 @@ while (working_set) {
case ioCLF: /* clear flag flip-flop */
pif.flag = pif.flagbuf = CLEAR; /* clear flag buffer and flag */
if (DEBUG_PRS (pif_dev))
fputs (">>PIF: [CLF] Flag cleared\n", sim_deb);
break;
case ioSTF: /* set flag flip-flop */
if (is_rte_pif) { /* RTE PIF? */
if (is_rte_pif) /* RTE PIF? */
pif.flag = pif.flagbuf = SET; /* set flag buffer and flag */
if (DEBUG_PRS (pif_dev))
fputs (">>PIF: [STF] Flag set\n", sim_deb);
}
break;
@@ -263,9 +272,6 @@ while (working_set) {
if (!is_rte_pif) { /* DOS PIF? */
pif.flag = pif.flagbuf = SET; /* set flag buffer and flag */
working_set = working_set | ioSIR; /* set SIR (not normally done for IOO) */
if (DEBUG_PRS (pif_dev))
fprintf (sim_deb, ">>PIF: [OTx%s] Flag set\n", hold_or_clear);
}
break;
@@ -274,27 +280,22 @@ while (working_set) {
pif.flag = pif.flagbuf = /* set or clear flag and flag buffer */
(is_rte_pif ? SET : CLEAR);
if (DEBUG_PRS (pif_dev))
fprintf (sim_deb, ">>PIF: [POPIO] Flag %s\n",
(is_rte_pif ? "set" : "cleared"));
tprintf (pif_dev, TRACE_CMD, "Power-on reset\n");
break;
case ioCRS: /* control reset */
tprintf (pif_dev, TRACE_CMD, "Control reset\n");
/* fall into ioCLC handler */
case ioCLC: /* clear control flip-flop */
pif.control = CLEAR; /* clear control */
if (DEBUG_PRS (pif_dev))
fprintf (sim_deb, ">>PIF: [%s%s] Control cleared\n",
(signal == ioCRS ? "CRS" : "CLC"), hold_or_clear);
break;
case ioSTC: /* set control flip-flop */
pif.control = SET; /* set control */
if (DEBUG_PRS (pif_dev))
fprintf (sim_deb, ">>PIF: [STC%s] Control set\n", hold_or_clear);
break;
@@ -310,10 +311,9 @@ while (working_set) {
setIRQ (dibptr->select_code, !pif.control & pif.flag & pif.flagbuf);
}
if (DEBUG_PRS (pif_dev))
fprintf (sim_deb, ">>PIF: [SIR] PRL = %d, IRQ = %d\n",
PRL (dibptr->select_code),
IRQ (dibptr->select_code));
tprintf (pif_dev, TRACE_CMD, "Fence %s%s lower-priority interrupts\n",
(IRQ (dibptr->select_code) ? "requests an interrupt and " : ""),
(PRL (dibptr->select_code) ? "allows" : "inhibits"));
break;

View File

@@ -1,6 +1,6 @@
SIMH/HP 2100 RELEASE NOTES
==========================
Last update: 2017-05-01
Last update: 2018-05-23
This file documents the release history of the simulator for the Hewlett-Packard
@@ -56,7 +56,7 @@ The simulator has been tested with the following operating systems:
- SIO, BCS, and MTS.
- 2000E, 2000F, and 2000/Access Time-Shared BASIC.
- 2000E, 2000F, and 2000 Access Time-Shared BASIC.
- DOS, DOS-M, and DOS-III.
@@ -68,6 +68,18 @@ PDF version of the same manual is available at:
http://alum.mit.edu/www/jdbryan/hp2100_doc.pdf
For those intending to run 2000F or 2000/Access Time-Shared BASIC, a monograph
entitled "Running HP 2000 Time-Shared BASIC on SIMH" is available at:
http://simh.trailing-edge.com/docs/running_hp_2000_tsb.pdf
It discusses the requirements for successful TSB startup and operation and the
issues involved in synchronizing the dual-CPU simulation setup required by TSB.
TSB has run successfully on SIMH for many years, but the advent of multi-core
host machines has increased the difficulty in getting the two SIMH instances to
coordinate properly. The paper presents some configuration guidelines that
improve the probability of successfully running TSB.
------------------
Available Software
@@ -98,6 +110,15 @@ restore programs is available from the HP Computer Museum at:
The archive contains instructions and a simulator command file.
Preconfigured 2000E, 2000F, and 2000 Access software kits are available from the
SIMH software repository here:
http://simh.trailing-edge.com/software.html
Each kit contains a bootable disc image and associated command files that
automate the system startup process. Command files to perform new system
generations are also included.
QCTerm, an HP 700 terminal emulator for Microsoft Windows, is available from the
HP Computer Museum at:
@@ -157,6 +178,535 @@ Revision 5010:
======================
Release 28, 2018-05-23
======================
This release of the HP 2100 simulator adds the following features:
- The IPLI and IPLO devices now use shared memory instead of network sockets to
simulate the 12875A Processor Interconnect kit that is used to communicate
between the System Processor and the I/O Processor of the HP 2000B, C, F, and
Access Time-Shared BASIC operating systems. This change, in addition to a
new, adaptive service scheduling routine, improves data transfer time between
the processes by a factor of 7 to 1.
- Commands have been added to the IPL device to permit synchronization between
the two simulator processes running the HP 2000 Time-Shared BASIC operating
system. This greatly improves system startup reliability and permits the use
of the HP-documented startup procedure of cross-loading the I/O Processor
program from the System Processor.
- The DIAGNOSTIC options of the IPLI and IPLO devices have been reworked to
permit testing with the HP General Register Diagnostic as well as the
Processor Interconnect Cable Diagnostic.
- The DEBUG options of the IPLI and IPLO devices have been expanded.
- The BOOT command now installs the correct binary loader for the CPU model.
For example, BOOT PTR installs and runs the Basic Binary Loader (BBL) if the
CPU is configured as a 2114/15/16 or 2100, or the 12992K Paper Tape Loader
ROM if the CPU is configured as a 1000 M/E/F-Series. Prior releases
installed the HP 1000 loader ROM regardless of the CPU model.
- The LOAD command has been extended to permit copying of internal device boot
loaders into memory. LOAD <dev> is identical to BOOT <dev> except that the
CPU is neither preset nor run. In particular, LOAD CPU is the equivalent of
pressing the IBL button on the HP 1000 front panel.
- The new SET CPU ROMS command permits altering the set of preinstalled boot
loader ROMs for 1000 CPUs. The new SHOW CPU ROMS command displays the
currently installed set.
- The -N (new file) option to the ATTACH command for disc devices now creates a
full-size image file, equivalent to formatting the new disc before use.
--------------------
Implementation Notes
--------------------
- The abbreviated "SET CPU 21MX" command no longer sets the CPU to an E-Series
model (i.e., to a 21MX-E, a.k.a. 1000-E); instead, it configures the CPU as
an original 21MX (a.k.a. 1000-M). If an E-Series configuration is desired,
it must be requested explicitly with the "SET CPU 21MX-E" command.
- The "RESET -P CPU" command no longer restores the BBL to the protected memory
area of 21xx machines. The "LOAD PTR" command may be used to perform this
function.
- The previous behavior of the "ATTACH -N" command for disc devices, i.e.,
creating a new zero-length image file, may be emulated by first deleting the
file and then attaching it without specifying the -N switch. For instance,
the "DELETE <file>" and "ATTACH <unit> <file>" commands produce a new
zero-length file as "ATTACH -N <unit> <file>" did before this change. The
"ATTACH -N" behavior of other devices, e.g., magnetic tape drives and
printers, did not change; a zero-length file is still created.
- With the change to a shared-memory implementation, only a single "ATTACH IPL"
command is required per instance to establish communication. The System
Processor instance issues an "ATTACH -S IPL <code>" command, and the I/O
Processor instance must issue a corresponding "ATTACH -I IPL <code>" command,
where the <code> parameter is a user-selected decimal number that identifies
the instance pair. The prior "ATTACH [-L | -C] [ IPLI | IPLO ] <port>"
commands are deprecated but retained, so that existing command files will
still work. However, they too will use shared memory rather than network
connections. Consequently, the SP and IOP instances are now required to
execute on the same machine, and the <ip-address> option is no longer
supported.
- Multiple consecutive CLC 0 instruction executions now cause only a single CRS
assertion to the I/O devices. Therefore, IOBUS tracing when running HP 2000
Time-Shared BASIC systems no longer generates a pair of trace lines for each
of the 131,072 consecutive CLC 0 executions typically used to initialize the
12920A Asynchronous Multiplexer.
- The 12875A Processor Interconnect section of the HP2100 User's Guide has been
revised to describe the new ATTACH protocol and process synchronization
commands.
- A list of device boot loaders installed for given device/CPU combinations has
been added to the user's guide.
- The "21MX-M" and "21MX-E" CPU options that had been inadvertently omitted
from the last release of the user's guide have been restored.
- The "Running HP 2000 Time-Shared BASIC on SIMH" monograph has been revised to
cover the application of the new process synchronization commands to TSB
startup command files.
- Preconfigured software kits for 2000E, 2000F, and 2000 Access that employ
the new shared memory and process synchronization commands are now available;
see the "Available Software" section above for details.
----------
Bugs Fixed
----------
1. PROBLEM: Serial port output stalls are not handled properly.
VERSION: Release 27.
OBSERVATION: The TTY, BACI, MPX, and MUX devices support I/O via host
serial ports as well as via Telnet connections. While TTY, BACI, and MPX
output via Telnet works correctly, output via serial ports fails. TTY
output drops characters if the serial port stalls. Attempting to output to
the BACI results in "Console Telnet output stall" and a simulator stop.
Output to the MPX results in dropped characters and eventually an "IOPE"
(parity error) message from RTE.
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. The BACI and MPX devices are
internally buffered and default to a "FASTTIME" mode that sends the entire
internal buffer to the library output routine. When the routine receives
the second character, it returns SCPE_STALL status to indicate a buffer
overflow. The device simulations did not expect and did not properly
handle this status.
The TTY and MUX devices are not buffered internally and were not affected
by the loss of serial buffering. However, the TTY would drop output
characters if the host serial buffer overflowed.
RESOLUTION: Modify "tto_svc" (hp2100_stddev.c), "baci_term_svc"
(hp2100_baci.c), and "line_service" (hp2100_mpx.c) to handle terminal
multiplexer library buffer overflows properly.
STATUS: Fixed in Release 28.
2. PROBLEM: The PTR device DIAGNOSTIC option shown in the user's guide does
not exist.
VERSION: Release 27.
OBSERVATION: The "HP2100 Simulator User's Guide" says that specifying the
DIAGNOSTIC option for the PTR device "converts the attached paper tape
image into a continuous loop" for use by the paper tape reader diagnostic
program. However, entering a "SET PTR DIAGNOSTIC" command gives a
"Non-existent parameter" error.
CAUSE: The option name specified in the PTR device's modifier table is
"DIAG". It should be "DIAGNOSTIC" to match the option names used in the
other device simulations.
RESOLUTION: Modify "ptr_mod" (hp_stddev.c) to use the correct option name.
STATUS: Fixed in Release 28.
3. PROBLEM: First Status is not cleared properly on the DP device.
VERSION: Release 27.
OBSERVATION: Execution of the RTE-I paper tape bootstrap for the 7900A and
the 2000F loader for the 7900A halts with disc errors. The offending disc
status word is 040001 octal, which denotes First Status and Any Error.
Both programs expect disc status to be clear after an initial Seek and Read
are performed. However, the disc drive and interface manuals state that
First Status is cleared by a Status Check command, which is not being
issued.
CAUSE: Examination of the schematics in the 7900A Disc Drive Operating and
Service Manual (07900-90002 February 1975) and the 13210A Disc Drive
Interface Kit Operating and Service Manual (13210-90003 November 1974)
shows that, contrary to the documentation, First Status is cleared on a
Read, Write, Check Data, or Initialize command, as well as on a Status
Check command. The current DP implementation follows the manual
description rather than the schematics, so it fails to clear First Status
when the initial Read is performed.
RESOLUTION: Modify "dp_goc" (hp2100_dp.c) to clear First Status as well as
Attention when one of the applicable commands is performed.
STATUS: Fixed in Release 28.
4. PROBLEM: 2000F and Access will not boot from a 7900 drive using the BMDL.
VERSION: Release 27.
OBSERVATION: Attempting to boot Time-Shared BASIC from a 7900 using the
Basic Moving-Head Disc Loader for the HP 2100 CPU results in a HLT 1
(unrecoverable disc error) in the TSB loader. Booting the same system with
the 12992A loader ROM for the HP 1000 succeeds.
The BMDL configures DMA for an oversize (~32000 word) transfer and expects
the disc to terminate the operation with End of Cylinder (EOC) status. The
TSB bootstrap successfully loads into memory. When it starts, it issues a
CLC 0,C followed by a Check Status command that is expected to return zero,
i.e., all status bits clear. However, the EOC bit is set, and the
bootstrap halts with a HLT 1.
CAUSE: The "Disc Interface 1 PCA Schematic Diagram" in the HP 13210A Disc
Drive Interface Kit Operating and Service Manual (13210-90003, August 1974)
shows that the CRS signal, which is generated by the CLC 0 instruction,
does not affect the Status Register contents. However, examination of an
actual hardware interface PCA shows that CRS assertion does clear the
register.
RESOLUTION: Modify "dpcio" (hp2100_dp.c) to clear the status register on
receipt of a CRS signal. Note that later versions of the service manual
(May 1975 and May 1978) show the correct CRS connection.
STATUS: Fixed in Release 28.
5. PROBLEM: Forcibly disconnected 2000E multiplexer ports are unresponsive.
VERSION: Release 27.
OBSERVATION: The HP Time-Shared BASIC system sets a limit on the time
allowed between dataset connection and login. By default, this is 120
seconds but may be changed by the PHONES system operator command. If the
user does not complete a login within the time allowed, the dataset will be
disconnected.
This action occurs as expected on the 2000E system, but while reconnecting
to the port succeeds, the line is unresponsive. More importantly,
attempting to SLEEP the system hangs after responding to the "MAG TAPE
SLEEP?" question.
CAUSE: Examining the source code where the SLEEP hang occurs shows that
the system is waiting in a loop for output to complete on the disconnected
port. The forced disconnect code, which is shared by the PHONES, KILLID,
and SLEEP commands, calls the BYE processor to log out an active user.
However, for a PHONES disconnect, the user is not logged in. The BYE
processor handles this condition correctly, but it returns to a common
routine (LLEND) that outputs a line feed to the port. The multiplexer
simulation omits a write to a disconnected port but also erroneously omits
the output completion interrupt request. Consequently, TSB believes that
the output is still in progress and therefore waits, in an infinite loop,
for the completion interrupt that never occurs. Also, while the port is in
output mode, input is turned off, so the port appears to be unresponsive
when reconnected.
RESOLUTION: Modify "muxo_svc" (hp2100_mux.c) to set "mux_xdon" to 1 to
trigger the completion interrupt regardless of whether or not the port is
connected to a Telnet session.
STATUS: Fixed in Release 28.
======================
Release 27, 2017-09-06
======================
This release of the HP 2100 simulator adds the following features:
- Support for the HP 2613, 2617, and 2618 line printers has been added to the
LPT device. The default printer remains the HP 2607.
- The LPT device simulation has been rewritten to support realistic and
optimized timing, compact and expanded output modes, custom VFU tape images,
and tracing of internal operations.
- The LOAD command has been rewritten to load files containing absolute binary
loaders into the protected address space of the 21xx machines and configure
the I/O instructions. For the 1000, LOAD can also be used to load boot
loader ROM images other than those provided directly by the simulator.
- The DUMP command has been added to write the binary loader currently resident
in memory to an absolute binary file.
- The TTY punch unit and the LPS, LPT, and PTP devices now position a newly
attached file at the end of the file rather than at the start. As a result,
output will append to, rather than overwrite, the existing content.
- The DA, DP, DQ, and DS disc devices add the PROTECT and UNPROTECT options.
These replace the now-deprecated LOCKED and WRITEENABLED options and more
accurately reflect the labelling of the data protection switches on the disc
drives.
- The simulator message that is displayed when a programmed halt occurs has
been changed to indicate that the halt code comes from the T-register value.
- The Basic Binary Loader (BBL) is now installed by default in the 21xx
machines. It is automatically configured to the select code of the paper
tape reader. It may be overwritten with a different loader (e.g., the Basic
Binary Disc Loader or Basic Moving-head Disc Loader) using the LOAD command.
Performing a power-on reset of the CPU reinstalls the BBL.
- Symbolic display and entry has been rewritten to improve efficiency and
expanded to cover the full instruction set including optional microcode
extensions that are currently enabled.
- CPU instruction execution and data accesses may be selectively traced. The
resulting trace listing is similar to the output of a logic analyzer
connected to the CPU and I/O buses.
- DMA/DCPC commands, status, and data accesses may be selectively traced.
- TBG commands, status, and service entries may be selectively traced.
- The DIAG option of the TBG device has been replaced with the REALTIME, W1A,
W1B, W2A, and W2B options. Configuring the TBG to run its diagnostic now
uses the REALTIME and W2B options, and restoring the normal configuration
uses the CALTIME and W2A options. The W1A and W1B options extend the
software compatibility of the TBG.
- The MUXM device has been renamed MUXC to reflect that it is the multiplexer
control card. The previous MUXM name is deprecated but will still work in
existing simulation command files.
- The multiplexer control card (MUXC) may be enabled and disabled independently
of the upper and lower data cards (MUX and MUXL), reflecting its optional
status in hardware configurations.
- Memory address parsing for commands has been changed to add <page>.<offset>
format for physical addresses, where both the page and the offset range from
0 to 1777 octal. Linear addressing is now restricted to the 32K logical
address space (0 to 77777 octal). Memory display uses linear addressing for
locations within the logical address space; locations above 32K use the
physical address format.
- The previously separate STOP_INST, STOP_DEV, STOP_IOE, and INDMAX
pseudo-registers used to stop the simulator under certain conditions have
been replaced by the SET CPU STOP=<stopname>[,<stopname>...] and the SET CPU
INDIR=<limit> commands. Stops may be temporarily bypassed by adding the -B
switch to the command that resumes execution.
- The HP 2100 Simulator User's Guide has been rewritten and significantly
expanded.
--------------------
Implementation Notes
--------------------
- The simulator passes the HP 2613/17/18 line printer diagnostic as described
in the "hp2100_diag.txt" file.
- The line printer terminates each print line with the HP-standard CR/LF pair.
If the output file is to be retained as a text file on a Unix system, removal
of the carriage returns, e.g., via the "dos2unix" utility, may be desirable.
- The LOAD command can no longer be used to read general absolute binary paper
tape images into memory. The ATTACH PTR and BOOT PTR commands must now be
used to read paper tapes.
- The OS, OSTBG, VMA, EMA, VIS, and SIGNAL CPU debug flags have been removed.
Tracing of these firmware instructions is now performed by specifying SET CPU
DEBUG=EXEC and SET CPU EXEC with the appropriate opcode range and mask, as
follows:
* SET CPU DEBUG=OS => SET CPU EXEC=105340;177760
* SET CPU DEBUG=VMA => SET CPU EXEC=105240;177760
* SET CPU DEBUG=EMA => SET CPU EXEC=105240;177760
* SET CPU DEBUG=VIS => SET CPU EXEC=101460;173760
* SET CPU DEBUG=SIGNAL => SET CPU EXEC=105600;177760
- The separate tracing of time-base generator interrupt instructions provided
by the OS and OSTBG CPU debug flags is no longer supported. Entering the
replacement command above traces all OS instructions, including the TBG
interrupt instructions.
- The TIMER, RRR 16, .FLUN, and the OS/VMA, VIS, and SIGNAL self-test
instructions are no longer exempt from the undefined/unimplemented
instruction stop tests. Attempted execution of these instructions without
the appropriate firmware options installed will cause simulation stops if the
UNDEF (TIMER and RRR) or UNIMPL (.FLUN and self-tests) option is enabled.
Because of this change, the default state of the unimplemented instruction
stop has been reversed from "on" to "off".
- The "stop on I/O error" features controlled by the STOP_IOE register values
have been removed from the DR, LPS, LPT, MSC, MTC, and PTP devices, as all of
these report I/O error status to the CPU via their interface input registers.
STOP_IOE has been removed from the PTR device and replaced with SET CPU
STOP=IOERR, as this device does not report I/O error status to the CPU
through its interface.
- The LOCKED and WRITEENABLED options for the MSC and MTC devices are
deprecated. The supported method of write-protecting a tape drive is to
attach the tape image with the -R (read-only) switch or by setting the host
operating system's read-only attribute on the tape image file. This
simulates removing the write ring from the tape reel before mounting it on
the drive. There is no hardware method of write-protecting a mounted and
positioned tape reel.
- If the previous ATTACH behavior (overwriting rather than appending) is
desired for the TTY punch unit and the LPS, LPT, and PTP devices, set the
device's (P)POS register to 0 after attaching.
----------
Bugs Fixed
----------
1. PROBLEM: EXAMINE -M for addresses > 32K displays misleading operands.
VERSION: Release 26.
OBSERVATION: Current-page memory references of instructions residing above
the 32K logical address space are printed as though they reside at their
locations modulo 32K. For example, DEPOSIT 170001 026020 and EXAMINE -M
170001 displays JMP 70020, and DEPOSIT 200001 026020 displays JMP 20.
CAUSE: The printed addresses assume that the instructions will be executed
from their respective pages (modulo 32). However, instructions can be
executed only when they are mapped into the logical address space, and any
given physical page may be mapped to any arbitrary logical page.
Therefore, the address printed may not represent the actual logical address
after mapping.
RESOLUTION: Modify "fprint_cpu" (hp2100_sys.c) to use Z/C address notation
for memory references in instructions residing in physical memory above
32K.
STATUS: Fixed in Release 27.
2. PROBLEM: Enabling IOP firmware should not be allowed on the 1000 F-Series.
VERSION: Release 26.
OBSERVATION: The command "SET CPU 1000-F,IOP" is allowed, but it should
not be, as the IOP firmware is not supported on this machine.
CAUSE: The F-Series does not provide the firmware mapping table entries
that permit operation of the 2000/Access I/O Processor firmware. IOP
instruction opcodes 10x400-17 and 10x420-37 are marked as "HP Reserved" in
the F-Series mapping table, and opcodes 10x460-77 are dedicated to the VIS
microcode.
RESOLUTION: Modify the "cpu_features" array (hp2100_cpu.c) to remove the
IOP option from the 1000 F-Series entry.
STATUS: Fixed in Release 27.
3. PROBLEM: A rejected model change still changes the CPU options.
VERSION: Release 26.
OBSERVATION: Changing to a CPU model that does not support the current
memory size will reduce memory to the maximum supported by the new model.
If the truncated portion contains non-zero values, the simulator will ask
for confirmation before proceeding. If the truncation is rejected, the CPU
options are still set to those of the new model, even though the old model
is retained. For example:
sim> SET CPU 1000-F,128K
sim> SHOW CPU
CPU idle disabled
128KW, 1000-F, EAU
FP, no IOP, DMS
FFP, DBI, no EMA/VMA
no VIS, no SIGNAL
sim> DEPOSIT 100000 1
sim> SET CPU 2116
Really truncate memory [N]?NO
Command not completed
sim> SHOW CPU
CPU idle disabled
128KW, 1000-F, no EAU
no FP, no IOP, no DMS
no FFP, no DBI, no EMA/VMA
no VIS, no SIGNAL
CAUSE: The CPU options are set before the memory size is changed, so when
the size change is rejected, the new CPU options are retained.
RESOLUTION: Modify "cpu_set_model" (hp2100_cpu.c) to perform the memory
size change first, so that if it is rejected, the CPU options have not been
changed.
STATUS: Fixed in Release 27.
4. PROBLEM: Virtual memory mapping fails for accesses above 126 MB.
VERSION: Release 26.
OBSERVATION: A program using virtual memory provided by the RTE-6/VM
operating system may access up to 128 MB of data, although VMA programs
default to a 16 MB limit. Accesses to data in virtual memory are mapped
through the last two DMS user map registers. Normally, each VMA access
maps in the memory page corresponding to the virtual address plus the
following memory page. This allows access to single items up to 1024 words
in size starting at any offset within the (first) page.
If a data item resides in the last 2 MB of virtual memory, access to an
item that crosses the page boundary is incorrect. Instead of accessing
words in the second page, the accesses wrap around within the first page.
CAUSE: The suit number part of the virtual address is not restored before
checking the allocation status of the page table entry corresponding to the
second (spillover) page. As a result, an unallocated second page in the
last 2 MB of virtual memory is seen as beyond the VM area limit, and
instead of generating a page fault to allocate the second page, the map
registers are set up to prevent access to the second page by setting the
first page address into both map registers.
RESOLUTION: Modify "cpu_vma_lbp" (hp2100_cpu5.c) to check for spill page
allocation correctly.
STATUS: Fixed in Release 27.
5. PROBLEM: Memory expansion is not disabled when DMS is disabled.
VERSION: Release 26.
OBSERVATION: If the Memory Expansion Module in a 1000-Series CPU has been
enabled, and then the DMS firmware option is disabled or the CPU is changed
to a model that does not support memory expansion (e.g., a 2100), memory
expansion remains enabled. In this case, memory accesses should revert to
physical addressing, but instead logical-to-physical address translation
through the currently enabled map remains in effect.
CAUSE: Disabling DMS should set the "dms_enb" flag to 0, but it does not.
RESOLUTION: Modify "set_model" and "set_option" (hp2100_cpu.c) to clear
the "dms_enb" flag if DMS is not enabled after the model or option change.
STATUS: Fixed in Release 27.
======================
Release 26, 2017-05-01
======================

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.