HP2100: Release 28

See HP2100/hp2100_release.txt for details of the release.
This commit is contained in:
Mark Pizzolato 2018-06-03 14:38:38 -07:00
parent c1f249ec66
commit 486427c9fe
23 changed files with 5151 additions and 1785 deletions

View file

@ -25,6 +25,7 @@
BACI 12966A Buffered Asynchronous Communications Interface 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 15-Mar-17 JDB Trace flags are now global
Changed DEBUG_PRI calls to tprintfs Changed DEBUG_PRI calls to tprintfs
10-Mar-17 JDB Added IOBUS to the debug table 10-Mar-17 JDB Added IOBUS to the debug table
@ -87,13 +88,13 @@
an "external rate" that is equivalent to 9600 baud, as most terminals were an "external rate" that is equivalent to 9600 baud, as most terminals were
set to their maximum speeds. set to their maximum speeds.
We support the 12966A connected to an HP terminal emulator via Telnet. We support the 12966A connected to an HP terminal emulator via Telnet or a
Internally, we model the BACI as a terminal multiplexer with one line. The serial port. Internally, we model the BACI as a terminal multiplexer with
simulation is complicated by the half-duplex nature of the card (there is one line. The simulation is complicated by the half-duplex nature of the
only one FIFO, used selectively either for transmission or reception) and the card (there is only one FIFO, used selectively either for transmission or
double-buffered UART (a Western Digital TR1863A), which has holding registers reception) and the double-buffered UART (a Western Digital TR1863A), which
as well as a shift registers for transmission and reception. We model both has holding registers as well as a shift registers for transmission and
sets of device registers. reception. We model both sets of device registers.
During an output operation, the first character output to the card passes During an output operation, the first character output to the card passes
through the FIFO and into the transmitter holding register. Subsequent through the FIFO and into the transmitter holding register. Subsequent
@ -122,12 +123,12 @@
as an "optimized (fast) timing" option. Optimization makes three as an "optimized (fast) timing" option. Optimization makes three
improvements: improvements:
1. On output, characters in the FIFO are emptied into the 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 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 the characters available in the line buffer are loaded into the FIFO as a
a block. 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. client.
3. Input occurring during an output operation is delayed until the second or 3. Input occurring during an output operation is delayed until the second or
@ -318,7 +319,7 @@
/* Unit references */ /* Unit references */
#define baci_term baci_unit[0] /* terminal I/O unit */ #define baci_term baci_unit[0] /* terminal I/O unit */
#define baci_poll baci_unit[1] /* Telnet polling unit */ #define baci_poll baci_unit[1] /* line polling unit */
/* BACI state variables */ /* BACI state variables */
@ -391,11 +392,11 @@ t_stat baci_detach (UNIT *uptr);
baci_deb BACI debug list baci_deb BACI debug list
baci_dev BACI device descriptor baci_dev BACI device descriptor
Two units are used: one to handle character I/O via the Telnet library, and Two units are used: one to handle character I/O via the multiplexer library,
another to poll for connections and input. The character I/O service routine and another to poll for connections and input. The character I/O service
runs only when there are characters to read or write. It operates at the routine runs only when there are characters to read or write. It operates at
approximate baud rate of the terminal (in CPU instructions per second) in 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 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 continuously, but it can operate much more slowly, as the only requirement is
that it must not present a perceptible lag to human input. To be compatible that it must not present a perceptible lag to human input. To be compatible
with CPU idling, it is co-scheduled with the master poll timer, which uses a with CPU idling, it is co-scheduled with the master poll timer, which uses a
@ -405,13 +406,13 @@ t_stat baci_detach (UNIT *uptr);
DEVICE baci_dev; DEVICE baci_dev;
TMLN baci_ldsc = { 0 }; /* line descriptor */ TMLN baci_ldsc = { 0 }; /* line descriptor */
TMXR baci_desc = { 1, 0, 0, &baci_ldsc }; /* device descriptor */ TMXR baci_desc = { 1, 0, 0, &baci_ldsc, NULL, &baci_dev }; /* device descriptor */
DIB baci_dib = { &baci_io, BACI, 0 }; DIB baci_dib = { &baci_io, BACI, 0 };
UNIT baci_unit[] = { UNIT baci_unit[] = {
{ UDATA (&baci_term_svc, UNIT_ATTABLE | UNIT_FASTTIME, 0) }, /* terminal I/O unit */ { UDATA (&baci_term_svc, UNIT_ATTABLE | UNIT_FASTTIME, 0) }, /* terminal I/O unit */
{ UDATA (&baci_poll_svc, UNIT_DIS, POLL_FIRST) } /* Telnet poll unit */ { UDATA (&baci_poll_svc, UNIT_DIS, POLL_FIRST) } /* line poll unit */
}; };
REG baci_reg [] = { REG baci_reg [] = {
@ -466,15 +467,15 @@ MTAB baci_mod[] = {
{ UNIT_CAPSLOCK, UNIT_CAPSLOCK, "CAPS LOCK down", "CAPSLOCK", NULL, NULL, NULL }, { UNIT_CAPSLOCK, UNIT_CAPSLOCK, "CAPS LOCK down", "CAPSLOCK", NULL, NULL, NULL },
{ UNIT_CAPSLOCK, 0, "CAPS LOCK up", "NOCAPSLOCK", 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_XDV | 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, NULL, "NOLOG", &tmxr_set_nolog, NULL, &baci_desc },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTION", NULL, NULL, &tmxr_show_cstat, &baci_desc }, { MTAB_XDV | 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_XDV | 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, 0, NULL, "DISCONNECT", &tmxr_dscln, NULL, &baci_desc },
{ MTAB_XTD | MTAB_VDV, 1u, "SC", "SC", &hp_set_dib, &hp_show_dib, (void *) &baci_dib }, { MTAB_XDV, 1u, "SC", "SC", &hp_set_dib, &hp_show_dib, (void *) &baci_dib },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, ~1u, "DEVNO", "DEVNO", &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 } { 0 }
}; };
@ -768,7 +769,7 @@ return stat_data;
The terminal service routine is used to transmit and receive characters. The terminal service routine is used to transmit and receive characters.
In terminal mode, it is started when a character is ready for output or when In terminal mode, it is started when a character is ready for output or when
the 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 and stopped when there are no more characters to output or input. When the
terminal is quiescent, this routine does not run. terminal is quiescent, this routine does not run.
@ -808,11 +809,11 @@ return stat_data;
first character after an ENQ is not an ACK. first character after an ENQ is not an ACK.
Finally, fast timing enables buffer combining. For output, all characters Finally, fast timing enables buffer combining. For output, all characters
present in the FIFO are unloaded into the Telnet buffer before initiating a present in the FIFO are unloaded into the line buffer before initiating a
packet send. For input, all characters present in the Telnet buffer are packet send. For input, all characters present in the line buffer are loaded
loaded into the FIFO. This reduces network traffic and decreases simulator into the FIFO. This reduces network traffic and decreases simulator overhead
overhead (there is only one service routine entry per block, rather than one (there is only one service routine entry per block, rather than one per
per character). character).
In fast output mode, it is imperative that not less than 1500 instructions In fast output mode, it is imperative that not less than 1500 instructions
elapse between the first character load to the FIFO and the initiation of elapse between the first character load to the FIFO and the initiation of
@ -826,6 +827,46 @@ return stat_data;
To avoid this, the OTx output character handler does an absolute schedule for 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. 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) t_stat baci_term_svc (UNIT *uptr)
@ -834,12 +875,16 @@ uint32 data_bits, data_mask;
const t_bool fast_timing = (baci_term.flags & UNIT_FASTTIME) != 0; const t_bool fast_timing = (baci_term.flags & UNIT_FASTTIME) != 0;
const t_bool is_attached = (baci_term.flags & UNIT_ATT) != 0; const t_bool is_attached = (baci_term.flags & UNIT_ATT) != 0;
t_stat status = SCPE_OK; t_stat status = SCPE_OK;
t_bool xmit_loop = TRUE;
t_bool recv_loop = TRUE; t_bool recv_loop = TRUE;
t_bool xmit_loop = (baci_ldsc.xmte != 0); /* TRUE if the transmit buffer is not full */
/* Transmission */ /* 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? */ 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_bits = 5 + (baci_cfcw & OUT_CHARSIZE); /* calculate number of data bits */
data_mask = (1 << data_bits) - 1; /* generate mask for data bits */ data_mask = (1 << data_bits) - 1; /* generate mask for data bits */
@ -864,6 +909,14 @@ while (xmit_loop && (baci_uart_thr & IN_VALID)) { /* valid character in UA
if (status == SCPE_OK) /* transmitted OK? */ if (status == SCPE_OK) /* transmitted OK? */
tprintf (baci_dev, DEB_XFER, "Character %s transmitted from the UART\n", tprintf (baci_dev, DEB_XFER, "Character %s transmitted from the UART\n",
fmt_char ((uint8) baci_uart_tr)); 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 */
}
} }
} }
@ -879,11 +932,12 @@ while (xmit_loop && (baci_uart_thr & IN_VALID)) { /* valid character in UA
else /* receive mode */ else /* receive mode */
baci_uart_thr = CLEAR_HR; /* clear holding register */ 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 else /* otherwise transmission failed */
xmit_loop = FALSE; xmit_loop = FALSE; /* so drop out of the loop */
} }
@ -971,12 +1025,11 @@ return status;
} }
/* BACI Telnet poll service. /* BACI line poll service.
This service routine is used to poll for Telnet connections and incoming This service routine is used to poll for connections and incoming characters.
characters. If characters are available, the terminal I/O service routine is If characters are available, the terminal I/O service routine is scheduled.
scheduled. It starts when the socket is attached and stops when the socket It starts when the line is attached and stops when the line is detached.
is detached.
Implementation notes: Implementation notes:
@ -1025,16 +1078,16 @@ baci_term.wait = service_time (baci_icw); /* set terminal I/O time
if (baci_term.flags & UNIT_ATT) { /* device attached? */ if (baci_term.flags & UNIT_ATT) { /* device attached? */
baci_poll.wait = POLL_FIRST; /* set up poll */ baci_poll.wait = POLL_FIRST; /* set up poll */
sim_activate (&baci_poll, baci_poll.wait); /* start Telnet poll immediately */ sim_activate (&baci_poll, baci_poll.wait); /* start line poll immediately */
} }
else else
sim_cancel (&baci_poll); /* else stop Telnet poll */ sim_cancel (&baci_poll); /* else stop line poll */
return SCPE_OK; return SCPE_OK;
} }
/* Attach controller */ /* Attach line */
t_stat baci_attach (UNIT *uptr, CONST char *cptr) t_stat baci_attach (UNIT *uptr, CONST char *cptr)
{ {
@ -1044,20 +1097,20 @@ status = tmxr_attach (&baci_desc, uptr, cptr); /* attach to socket */
if (status == SCPE_OK) { if (status == SCPE_OK) {
baci_poll.wait = POLL_FIRST; /* set up poll */ 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; return status;
} }
/* Detach controller */ /* Detach line */
t_stat baci_detach (UNIT *uptr) t_stat baci_detach (UNIT *uptr)
{ {
t_stat status; t_stat status;
baci_ldsc.rcve = 0; /* disable line reception */ 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 */ status = tmxr_detach (&baci_desc, uptr); /* detach socket */
return status; return status;
} }
@ -1105,8 +1158,10 @@ baci_dsrw = 0; /* clear status referenc
baci_cfcw = baci_cfcw & ~OUT_ECHO; /* clear echo flag */ baci_cfcw = baci_cfcw & ~OUT_ECHO; /* clear echo flag */
baci_icw = baci_icw & OUT_BAUDRATE; /* clear interface control */ 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_status = baci_status & ~IN_MODEM | IN_SPARE; /* clear loopback status, set BA */
baci_ldsc.xmte = 1; /* enable transmitter */
}
return; return;
} }

View file

@ -1,7 +1,7 @@
/* hp2100_cpu.c: HP 21xx/1000 Central Processing Unit/MEM/MP/DCPC simulator /* hp2100_cpu.c: HP 21xx/1000 Central Processing Unit/MEM/MP/DCPC simulator
Copyright (c) 1993-2016, Robert M. Supnik 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 Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -30,6 +30,11 @@
DCPC1,DCPC2 12897B Dual Channel Port Controller DCPC1,DCPC2 12897B Dual Channel Port Controller
MP 12581A/12892B Memory Protect MP 12581A/12892B Memory Protect
21-May-18 JDB Changed "access" to "mem_access" to avoid clashing
07-May-18 JDB Modified "io_dispatch" to display outbound signals
01-May-18 JDB Multiple consecutive CLC 0 operations are now omitted
02-Apr-18 JDB SET CPU 21MX now configures an M-Series model
22-Feb-18 JDB Reworked "cpu_ibl" into "cpu_copy_loader"
11-Aug-17 JDB MEM must be disabled when DMS is disabled 11-Aug-17 JDB MEM must be disabled when DMS is disabled
01-Aug-17 JDB Changed SET/SHOW CPU [NO]IDLE to use sim_*_idle routines 01-Aug-17 JDB Changed SET/SHOW CPU [NO]IDLE to use sim_*_idle routines
22-Jul-17 JDB Renamed "intaddr" to CIR; added IR 22-Jul-17 JDB Renamed "intaddr" to CIR; added IR
@ -892,14 +897,6 @@
/* External data */
extern DIB clk_dib; /* CLK DIB for idle check */
extern DIB ptr_dib; /* PTR DIB for BBL configuration */
extern const BOOT_ROM ptr_rom, dq_rom, ms_rom, ds_rom; /* boot ROMs for cpu_boot routine */
/* CPU program constants */ /* CPU program constants */
@ -961,6 +958,7 @@ REG *pcq_r = NULL; /* PC queue reg ptr */
uint32 cpu_configuration; /* the current CPU option set and model */ uint32 cpu_configuration; /* the current CPU option set and model */
uint32 cpu_speed = 1; /* the CPU speed, expressed as a multiplier of a real machine */ uint32 cpu_speed = 1; /* the CPU speed, expressed as a multiplier of a real machine */
t_bool is_1000 = FALSE; /* TRUE if the CPU is a 1000 M/E/F-Series */
uint32 dev_prl [2] = { ~0u, ~0u }; /* device priority low bit vector */ uint32 dev_prl [2] = { ~0u, ~0u }; /* device priority low bit vector */
uint32 dev_irq [2] = { 0u, 0u }; /* device interrupt request bit vector */ uint32 dev_irq [2] = { 0u, 0u }; /* device interrupt request bit vector */
@ -988,6 +986,10 @@ static uint32 jsb_plb = 2; /* protected lower bound for JSB
static uint32 exec_mask = 0; /* the current instruction execution trace mask */ static uint32 exec_mask = 0; /* the current instruction execution trace mask */
static uint32 exec_match = D16_UMAX; /* the current instruction execution trace matching value */ static uint32 exec_match = D16_UMAX; /* the current instruction execution trace matching value */
static uint32 indirect_limit = 16; /* the indirect chain length limit */ static uint32 indirect_limit = 16; /* the indirect chain length limit */
static uint32 last_select_code = 0; /* the last select code sent over the I/O backplane */
static uint32 tbg_select_code = 0; /* the time-base generator select code (for RTE idle check) */
static DEVICE *loader_rom [4] = { NULL }; /* the four boot loader ROM sockets in a 1000 CPU */
/* Memory Expansion Unit local state */ /* Memory Expansion Unit local state */
@ -1013,30 +1015,6 @@ static t_bool defer_tab [] = { /* deferral table, indexed by I/
}; };
/* Basic Binary Loader */
static const BOOT_ROM bbl = {
0107700, 0063770, 0106501, 0004010,
0002400, 0006020, 0063771, 0073736,
0006401, 0067773, 0006006, 0027717,
0107700, 0102077, 0027700, 0017762,
0002003, 0027712, 0003104, 0073774,
0017762, 0017753, 0070001, 0073775,
0063775, 0043772, 0002040, 0027751,
0017753, 0044000, 0000000, 0002101,
0102000, 0037775, 0037774, 0027730,
0017753, 0054000, 0027711, 0102011,
0027700, 0102055, 0027700, 0000000,
0017762, 0001727, 0073776, 0017762,
0033776, 0127753, 0000000, 0103710,
0102310, 0027764, 0102510, 0127762,
0173775, 0153775, 0100100, 0177765,
0000000, 0000000, 0000000, 0000000
};
#define BBL_FWA 072 /* BBL location to store negative FWA */
/* CPU features table. /* CPU features table.
The feature table is used to validate CPU feature changes within the subset The feature table is used to validate CPU feature changes within the subset
@ -1122,10 +1100,12 @@ static t_stat set_model (UNIT *uptr, int32 new_model, CONST char *cptr, void
static t_stat set_option (UNIT *uptr, int32 option, CONST char *cptr, void *desc); static t_stat set_option (UNIT *uptr, int32 option, CONST char *cptr, void *desc);
static t_stat clear_option (UNIT *uptr, int32 option, CONST char *cptr, void *desc); static t_stat clear_option (UNIT *uptr, int32 option, CONST char *cptr, void *desc);
static t_stat set_loader (UNIT *uptr, int32 enable, CONST char *cptr, void *desc); static t_stat set_loader (UNIT *uptr, int32 enable, CONST char *cptr, void *desc);
static t_stat set_roms (UNIT *uptr, int32 option, CONST char *cptr, void *desc);
static t_stat set_exec (UNIT *uptr, int32 option, CONST char *cptr, void *desc); static t_stat set_exec (UNIT *uptr, int32 option, CONST char *cptr, void *desc);
static t_stat show_stops (FILE *st, UNIT *uptr, int32 val, CONST void *desc); static t_stat show_stops (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
static t_stat show_model (FILE *st, UNIT *uptr, int32 val, CONST void *desc); static t_stat show_model (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
static t_stat show_roms (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
static t_stat show_exec (FILE *st, UNIT *uptr, int32 val, CONST void *desc); static t_stat show_exec (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
static t_stat show_speed (FILE *st, UNIT *uptr, int32 val, CONST void *desc); static t_stat show_speed (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
@ -1269,14 +1249,15 @@ static MTAB cpu_mod [] = {
{ UNIT_MODEL_MASK, UNIT_2114, "", "2114", &set_model, &show_model, (void *) "2114" }, { UNIT_MODEL_MASK, UNIT_2114, "", "2114", &set_model, &show_model, (void *) "2114" },
{ UNIT_MODEL_MASK, UNIT_2100, "", "2100", &set_model, &show_model, (void *) "2100" }, { UNIT_MODEL_MASK, UNIT_2100, "", "2100", &set_model, &show_model, (void *) "2100" },
{ UNIT_MODEL_MASK, UNIT_1000_E, "", "1000-E", &set_model, &show_model, (void *) "1000-E" }, { UNIT_MODEL_MASK, UNIT_1000_E, "", "1000-E", &set_model, &show_model, (void *) "1000-E" },
{ UNIT_MODEL_MASK, UNIT_1000_E, NULL, "21MX-E", &set_model, &show_model, (void *) "1000-E" },
{ UNIT_MODEL_MASK, UNIT_1000_M, "", "1000-M", &set_model, &show_model, (void *) "1000-M" }, { UNIT_MODEL_MASK, UNIT_1000_M, "", "1000-M", &set_model, &show_model, (void *) "1000-M" },
{ UNIT_MODEL_MASK, UNIT_1000_M, NULL, "21MX-M", &set_model, &show_model, (void *) "1000-M" },
#if defined (HAVE_INT64) #if defined (HAVE_INT64)
{ UNIT_MODEL_MASK, UNIT_1000_F, "", "1000-F", &set_model, &show_model, (void *) "1000-F" }, { UNIT_MODEL_MASK, UNIT_1000_F, "", "1000-F", &set_model, &show_model, (void *) "1000-F" },
#endif #endif
{ UNIT_MODEL_MASK, UNIT_1000_M, NULL, "21MX-M", &set_model, &show_model, (void *) "1000-M" },
{ UNIT_MODEL_MASK, UNIT_1000_E, NULL, "21MX-E", &set_model, &show_model, (void *) "1000-E" },
{ UNIT_EAU, UNIT_EAU, "EAU", "EAU", &set_option, NULL, NULL }, { UNIT_EAU, UNIT_EAU, "EAU", "EAU", &set_option, NULL, NULL },
{ UNIT_EAU, 0, "no EAU", NULL, NULL, NULL, NULL }, { UNIT_EAU, 0, "no EAU", NULL, NULL, NULL, NULL },
{ MTAB_XDV, UNIT_EAU, NULL, "NOEAU", &clear_option, NULL, NULL }, { MTAB_XDV, UNIT_EAU, NULL, "NOEAU", &clear_option, NULL, NULL },
@ -1345,6 +1326,8 @@ static MTAB cpu_mod [] = {
{ MTAB_XDV, 512 * 1024, NULL, "512K", &set_size, NULL, NULL }, { MTAB_XDV, 512 * 1024, NULL, "512K", &set_size, NULL, NULL },
{ MTAB_XDV, 1024 * 1024, NULL, "1024K", &set_size, NULL, NULL }, { MTAB_XDV, 1024 * 1024, NULL, "1024K", &set_size, NULL, NULL },
{ MTAB_XDV | MTAB_NMO, 0, "ROMS", "ROMS", &set_roms, &show_roms, NULL },
{ MTAB_XDV | MTAB_NMO, 1, "STOPS", "STOP", &set_stops, &show_stops, NULL }, { MTAB_XDV | MTAB_NMO, 1, "STOPS", "STOP", &set_stops, &show_stops, NULL },
{ MTAB_XDV, 0, NULL, "NOSTOP", &set_stops, NULL, NULL }, { MTAB_XDV, 0, NULL, "NOSTOP", &set_stops, NULL, NULL },
{ MTAB_XDV | MTAB_NMO, 2, "INDIR", "INDIR", &set_stops, &show_stops, NULL }, { MTAB_XDV | MTAB_NMO, 2, "INDIR", "INDIR", &set_stops, &show_stops, NULL },
@ -1472,7 +1455,7 @@ typedef struct {
const char *name; /* the classification name */ const char *name; /* the classification name */
} ACCESS_PROPERTIES; } ACCESS_PROPERTIES;
static const ACCESS_PROPERTIES access [] = { /* indexed by ACCESS_CLASS */ static const ACCESS_PROPERTIES mem_access [] = { /* indexed by ACCESS_CLASS */
/* debug_flag name */ /* debug_flag name */
/* ------------ ------------------- */ /* ------------ ------------------- */
{ TRACE_FETCH, "instruction fetch" }, /* instruction fetch */ { TRACE_FETCH, "instruction fetch" }, /* instruction fetch */
@ -1718,7 +1701,6 @@ t_bool mp_mem_changed; /* TRUE if the MP or MEM registe
static FLIP_FLOP mp_flag = CLEAR; /* MP flag flip-flop */ static FLIP_FLOP mp_flag = CLEAR; /* MP flag flip-flop */
static FLIP_FLOP mp_flagbuf = CLEAR; /* MP flag buffer flip-flop */ static FLIP_FLOP mp_flagbuf = CLEAR; /* MP flag buffer flip-flop */
static FLIP_FLOP mp_evrff = SET; /* enable violation register flip-flop */ static FLIP_FLOP mp_evrff = SET; /* enable violation register flip-flop */
static t_bool is_1000 = FALSE; /* TRUE if the CPU is a 1000 M/E/F-Series */
static char meu_indicator; /* last map access indicator (S | U | A | B | -) */ static char meu_indicator; /* last map access indicator (S | U | A | B | -) */
static uint32 meu_page; /* last physical page number accessed */ static uint32 meu_page; /* last physical page number accessed */
@ -1820,24 +1802,31 @@ static const BITSET_NAME inbound_names [] = { /* Inbound signal names, in IOSI
"ENF", /* 000000000002 */ "ENF", /* 000000000002 */
"IOI", /* 000000000004 */ "IOI", /* 000000000004 */
"IOO", /* 000000000010 */ "IOO", /* 000000000010 */
"SKF", /* 000000000020 */ "SFS", /* 000000000020 */
"SFS", /* 000000000040 */ "SFC", /* 000000000040 */
"SFC", /* 000000000100 */ "STC", /* 000000000100 */
"STC", /* 000000000200 */ "CLC", /* 000000000200 */
"CLC", /* 000000000400 */ "STF", /* 000000000400 */
"STF", /* 000000001000 */ "CLF", /* 000000001000 */
"CLF", /* 000000002000 */ "EDT", /* 000000002000 */
"EDT", /* 000000004000 */ "CRS", /* 000000004000 */
"CRS", /* 000000010000 */ "POPIO", /* 000000010000 */
"POPIO", /* 000000020000 */ "IAK", /* 000000020000 */
"IAK", /* 000000040000 */ "SIR" /* 000000040000 */
"SIR" /* 000000100000 */
}; };
static const BITSET_FORMAT inbound_format = /* names, offset, direction, alternates, bar */ static const BITSET_FORMAT inbound_format = /* names, offset, direction, alternates, bar */
{ FMT_INIT (inbound_names, 0, lsb_first, no_alt, no_bar) }; { FMT_INIT (inbound_names, 0, lsb_first, no_alt, no_bar) };
static const BITSET_NAME outbound_names [] = { /* Outbound signal names, in IOSIGNAL order */
"SKF" /* 000000200000 */
};
static const BITSET_FORMAT outbound_format = /* names, offset, direction, alternates, bar */
{ FMT_INIT (outbound_names, 16, lsb_first, no_alt, no_bar) };
/* I/O instruction sub-opcodes */ /* I/O instruction sub-opcodes */
#define soHLT 0 /* halt */ #define soHLT 0 /* halt */
@ -1890,9 +1879,10 @@ static uint32 io_dispatch (uint32 select_code, IOCYCLE signal_set, HP_WORD dat
execution. This involves verifying that there are no device conflicts (e.g., execution. This involves verifying that there are no device conflicts (e.g.,
two devices with the same select code) and initializing the I/O state. These two devices with the same select code) and initializing the I/O state. These
actions accommodate reconfiguration of the I/O device settings and program actions accommodate reconfiguration of the I/O device settings and program
counter while the simulator was stopped. The prelude also responds to one counter while the simulator was stopped. The prelude also picks up the
command-line switch: if "-B" is specified, the current set of simulation stop time-base generator's select code for use in idle testing, and it checks for
conditions is bypassed for the first instruction executed. one command-line switch: if "-B" is specified, the current set of simulation
stop conditions is bypassed for the first instruction executed.
Second, the memory protect abort mechanism is set up. MP aborts utilize the Second, the memory protect abort mechanism is set up. MP aborts utilize the
"setjmp/longjmp" mechanism to transfer control out of the instruction "setjmp/longjmp" mechanism to transfer control out of the instruction
@ -2139,6 +2129,7 @@ static const char *const mp_mem_formats [] = { /* MP/MEM regist
static uint32 exec_save; /* the trace flag settings saved by an EXEC match */ static uint32 exec_save; /* the trace flag settings saved by an EXEC match */
static uint32 idle_save; /* the trace flag settings saved by an idle match */ static uint32 idle_save; /* the trace flag settings saved by an idle match */
DEVICE *tbg_dptr;
int abortval; int abortval;
uint32 intrq, dmarq; /* set after setjmp */ uint32 intrq, dmarq; /* set after setjmp */
t_bool exec_test; /* set after setjmp */ t_bool exec_test; /* set after setjmp */
@ -2158,6 +2149,13 @@ sim_switches &= ~SWMASK ('P'); /* clear the power-on sw
if (hp_device_conflict ()) /* if device assignment is inconsistent */ if (hp_device_conflict ()) /* if device assignment is inconsistent */
return SCPE_STOP; /* then inhibit execution */ return SCPE_STOP; /* then inhibit execution */
tbg_dptr = find_dev ("CLK"); /* get a pointer to the time-base generator device */
if (tbg_dptr == NULL) /* if the TBG device is not present */
return SCPE_IERR; /* then something is seriously wrong */
else /* otherwise */
tbg_select_code = ((DIB *) tbg_dptr->ctxt)->select_code; /* get the select code from the device's DIB */
io_initialize (); /* set up the I/O data structures */ io_initialize (); /* set up the I/O data structures */
cpu_ioerr_uptr = NULL; /* and clear the I/O error unit pointer */ cpu_ioerr_uptr = NULL; /* and clear the I/O error unit pointer */
@ -2450,26 +2448,56 @@ return;
/* CPU global utility routines */ /* CPU global utility routines */
/* Install an initial binary loader into memory. /* Install a bootstrap loader into memory.
This routine copies the initial binary loader contained in "rom" to the last This routine copies the bootstrap loader specified by "boot" into the last 64
64 words of main memory, limited by a 32K memory size. If "dev" contains a words of main memory, limited by a 32K memory size. If "sc" contains the
select code of an I/O interface (i.e., select code 10 or above), this routine select code of an I/O interface (i.e., select code 10 or above), this routine
will configure the I/O instructions in the IBL to the supplied select code. will configure the I/O instructions in the loader to the supplied select
On exit, P will be set to point at the first word of the loader, and S will code. On exit, P will be set to point at the loader starting program
be altered as directed by the "sr_clear" and "sr_set" masks. address, and S will be altered as directed by the "sr_clear" and "sr_set"
masks if the current CPU is a 1000.
If I/O configuration is requested, each instruction in the IBL is examined as The currently configured CPU family (21xx or 1000) determines which of two
it is copied to memory. If the instruction is a non-HLT I/O instruction BOOT_LOADER structures is accessed from the "boot" array. Each structure
referencing a select code >= 10, the select code will be reset by subtracting contains the 64-word loader array and three indicies into the loader
10 and adding the value of the select code supplied in the "dev" parameter. array that specify the start of program execution, the element containing the
This permits configuration of IBLs that address two- or three-card DMA control word, and the element containing the (negative) address of the
interfaces. Passing a "dev" value of 0 will inhibit configuration. first loader word in memory.
As an example, passing a "dev" value of 24 octal will alter these 21xx-series loaders consist of subsections handling one or two devices. A
two-part loader is indicated by a starting program index other than 0, i.e.,
other than the beginning of the loader. An example is the Basic Moving-Head
Disc Loader (BMDL), which consists of a paper tape loader section starting at
index 0 and a disc loader section starting at index 50 octal. For these
loaders, I/O configuration depends on the "start_index" field of the selected
BOOTSTRAP structure: I/O instructions before the starting index are
configured to the current paper-tape reader select code, and instructions at
or after the starting index are configured to the device select code
specified by "sc". Single-part loaders specify a starting index of 0, and
all I/O instructions are configured to the "sc" select code.
1000-series loaders are always single part and always start at index 0, so
they are always configured to use the "sc" select code.
If a given device does not have both a 21xx-series and a 1000-series loader,
the "start_index" field of the undefined loader will be set to the "IBL_NA"
value. If this routine is called to copy an undefined loader, it will reject
the call with a "Command not allowed" error.
If I/O configuration is requested, each instruction in the loader array is
examined as it is copied to memory. If the instruction is a non-HLT I/O
instruction referencing a select code >= 10, the select code will be reset by
subtracting 10 and adding the value of the select code supplied by the "sc"
parameter (or the paper-tape reader select code, as above). This permits
configuration of loaders that address two- or three-card interfaces. Passing
an "sc" value of 0 will inhibit configuration, and the loader array will be
copied verbatim.
As an example, passing an "sc" value of 24 octal will alter these I/O-group
instructions as follows: instructions as follows:
IBL Configured Loader Configured
Instruction Instruction Note Instruction Instruction Note
----------- ----------- ------------------------------ ----------- ----------- ------------------------------
OTA 10 OTA 24 Normal configuration OTA 10 OTA 24 Normal configuration
@ -2477,46 +2505,92 @@ return;
STC 6 STC 6 DCPC configuration not changed STC 6 STC 6 DCPC configuration not changed
HLT 11 HLT 11 Halt instruction not changed HLT 11 HLT 11 Halt instruction not changed
If configuration is performed, the routine will also alter the next-to-last If configuration is performed, two additional operations may be performed.
word unconditionally as above. This word is assumed to contain a DCPC First, the routine will alter the word at the index specified by the
control word; it is configured to reference the supplied select code. "dma_index" field of the selected BOOTSTRAP structure unconditionally as
above. This word is assumed to contain a DMA control word; it is configured
to reference the supplied select code. Second, it will set the word at the
index specified by the "fwa_index" field to the two's-complement of the
starting address of the loader in memory. This value may be used by the
loader to check that it will not be overwritten by loaded data.
Finally, the routine sets the last word to the two's-complement of the If either field is set to the IBL_NA value, then the corresponding
starting address of the IBL. This value may be used by the loader to check modification is not made. For example, the 21xx Basic Binary Loader (BBL)
that it will not be overwritten by loaded data. does not use DMA, so its "dma_index" field is set to IBL_NA, and so no DMA
control word modification is done.
This routine also unconditionally sets the P register to the starting
address for loader execution. This is derived from the "start_index" field
and the starting memory address to which the loader is copied.
Finally, if the current CPU is a 1000-series machine, the S register bits
corresponding to those set in the "sr_clear" value are masked off, and the
bits corresponding to those in the "sr_set" value are set. In addition, the
select code from the "sc" value is shifted left and ORed into the value.
This action presets the S-register to the correct value for the selected
loader.
Implementation notes:
1. The paper-tape reader's select code is determined on each entry to the
routine to accommodate select code reassignment by the user.
*/ */
void cpu_ibl (const BOOT_ROM rom, int32 dev, HP_WORD sr_clear, HP_WORD sr_set) t_stat cpu_copy_loader (const LOADER_ARRAY boot, uint32 sc, HP_WORD sr_clear, HP_WORD sr_set)
{ {
int32 i; uint32 index, base, ptr_sc;
MEMORY_WORD wd; MEMORY_WORD word;
DEVICE *ptr_dptr;
set_loader (NULL, TRUE, NULL, NULL); /* enable loader (ignore errors) */ if (boot [is_1000].start_index == IBL_NA) /* if the bootstrap is not defined for the current CPU */
return SCPE_NOFNC; /* then reject the command */
PR = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */ else if (boot [is_1000].start_index > 0 && sc > 0) { /* if this is a two-part loader with I/O reconfiguration */
ptr_dptr = find_dev ("PTR"); /* then get a pointer to the paper tape reader device */
for (i = 0; i < IBL_LNT; i++) { /* copy bootstrap */
wd = rom [i]; /* get word */
if (dev >= VARDEV /* if reconfiguration is desired */
&& (wd & I_NMRMASK) == I_IO /* and this is an I/O instruction */
&& (wd & I_DEVMASK) >= VARDEV /* and the referenced select code is >= 10B */
&& I_GETIOOP (wd) != soHLT) /* and it's not a halt instruction */
M [PR + i] = (wd + (dev - VARDEV)) & DMASK; /* then reconfigure the select code */
if (ptr_dptr == NULL) /* if the PTR device is not present */
return SCPE_IERR; /* then something is seriously wrong */
else /* otherwise */ else /* otherwise */
M [PR + i] = wd; /* copy the instruction verbatim */ ptr_sc = ((DIB *) ptr_dptr->ctxt)->select_code; /* get the select code from the device's DIB */
} }
if (dev >= VARDEV) /* if reconfiguration was performed */ else /* otherwise this is a single-part loader */
M [PR + IBL_DPC] = M [PR + IBL_DPC] + dev - VARDEV /* then patch the DMA control word */ ptr_sc = 0; /* or I/O reconfiguration is not requested */
& DMASK;
M [PR + IBL_END] = (~PR + 1) & DMASK; /* fill in start of boot */ base = MEMSIZE - 1 & ~IBL_MASK & LA_MASK; /* get the base memory address of the loader */
PR = base + boot [is_1000].start_index & R_MASK; /* and store the starting program address in P */
SR = (SR & sr_clear) | sr_set; /* modify the S register as indicated */ set_loader (NULL, TRUE, NULL, NULL); /* enable the loader (ignore errors if not 21xx) */
return; for (index = 0; index < IBL_SIZE; index++) { /* copy the bootstrap loader to memory */
word = boot [is_1000].loader [index]; /* get the next word */
if (sc == 0) /* if reconfiguration is not requested */
M [base + index] = word; /* then copy the instruction verbatim */
else if ((word & I_NMRMASK) == I_IO /* otherwise if this is an I/O instruction */
&& (word & I_DEVMASK) >= VARDEV /* and the referenced select code is >= 10B */
&& I_GETIOOP (word) != soHLT) /* and it's not a halt instruction */
if (index < boot [is_1000].start_index) /* then if this is a split loader */
M [base + index] = word + (ptr_sc - VARDEV) & DV_MASK; /* then reconfigure the paper tape reader */
else /* otherwise */
M [base + index] = word + (sc - VARDEV) & DV_MASK; /* reconfigure the target device */
else if (index == boot [is_1000].dma_index) /* otherwise if this is the DMA configuration word */
M [base + index] = word + (sc - VARDEV) & DV_MASK; /* then reconfigure the target device */
else if (index == boot [is_1000].fwa_index) /* otherwise if this is the starting address word */
M [base + index] = NEG16 (base); /* then set the negative starting address of the bootstrap */
else /* otherwise the word is not a special one */
M [base + index] = word; /* so simply copy it */
}
if (is_1000) /* if the CPU is a 1000 */
SR = SR & sr_clear | sr_set | IBL_TO_SC (sc); /* then modify the S register as indicated */
return SCPE_OK; /* return success with the loader copied to memory */
} }
@ -2561,6 +2635,10 @@ return;
do this in preference to calling the recalculation routines directly, as do this in preference to calling the recalculation routines directly, as
some extended firmware instructions call this routine multiple times, and some extended firmware instructions call this routine multiple times, and
there is no point in recalculating until all calls are complete. there is no point in recalculating until all calls are complete.
6. The I/O dispatcher returns NOTE_SKIP if the interface asserted the SKF
signal. We must recalculate interrupts if the originating SFS or SFC
instruction included the CLF signal (e.g., SFS 0,C).
*/ */
t_stat cpu_iog (HP_WORD IR, t_bool iotrap) t_stat cpu_iog (HP_WORD IR, t_bool iotrap)
@ -2605,12 +2683,13 @@ ioreturn = io_dispatch (dev, signal_set, iodata); /* dispatch the I/O sign
iostat = IOSTATUS (ioreturn); /* extract status */ iostat = IOSTATUS (ioreturn); /* extract status */
iodata = IODATA (ioreturn); /* extract return data value */ iodata = IODATA (ioreturn); /* extract return data value */
if (iostat == SCPE_OK) { /* if instruction execution succeeded */ if (iostat == NOTE_SKIP) { /* if the interface asserted SKF */
if ((sop == soSFC || sop == soSFS) /* then if it is an SFC or SFS */
&& (IOSIGNAL) iodata == ioSKF) /* and SKF is asserted */
PR = PR + 1 & LA_MASK; /* then bump P to skip then next instruction */ PR = PR + 1 & LA_MASK; /* then bump P to skip then next instruction */
return (IR & I_HC ? NOTE_IOG : SCPE_OK); /* and request recalculation of interrupts if needed */
}
else if (sop == soLIX) /* otherwise if is it an LIA or LIB */ else if (iostat == SCPE_OK) { /* otherwise if instruction execution succeeded */
if (sop == soLIX) /* then if is it an LIA or LIB */
ABREG [ab] = iodata; /* then load the returned data */ ABREG [ab] = iodata; /* then load the returned data */
else if (sop == soMIX) /* otherwise if it is an MIA or MIB */ else if (sop == soMIX) /* otherwise if it is an MIA or MIB */
@ -2926,11 +3005,11 @@ if (index <= 1 && map < PAMAP) /* if the A/B register i
else /* otherwise */ else /* otherwise */
TR = (HP_WORD) M [index]; /* return the physical memory value */ TR = (HP_WORD) M [index]; /* return the physical memory value */
tpprintf (dptr, access [classification].debug_flag, tpprintf (dptr, mem_access [classification].debug_flag,
DMS_FORMAT " %s%s\n", DMS_FORMAT " %s%s\n",
meu_indicator, meu_page, MR, TR, meu_indicator, meu_page, MR, TR,
access [classification].name, mem_access [classification].name,
access [classification].debug_flag == TRACE_FETCH ? "" : " read"); mem_access [classification].debug_flag == TRACE_FETCH ? "" : " read");
return TR; return TR;
} }
@ -3056,10 +3135,10 @@ else if (index < fwanxm) /* otherwise if the loca
TR = value; /* save the value */ TR = value; /* save the value */
tpprintf (dptr, access [classification].debug_flag, tpprintf (dptr, mem_access [classification].debug_flag,
DMS_FORMAT " %s write\n", DMS_FORMAT " %s write\n",
meu_indicator, meu_page, MR, TR, meu_indicator, meu_page, MR, TR,
access [classification].name); mem_access [classification].name);
return; return;
} }
@ -3393,10 +3472,21 @@ return;
interrupt system and turn it off." interrupt system and turn it off."
4. Select code 0 cannot interrupt, so there is no SIR handler. 4. Select code 0 cannot interrupt, so there is no SIR handler.
5. To guarantee proper initialization, the 12920A terminal multiplexer
requires that the Control Reset (CRS) I/O signal be asserted for a
minimum of 100 milliseconds. In practice, this is achieved by executing
131,072 (128K) CLC 0 instructions in a tight loop. This is not necessary
in simulation, and in fact is detrimental, as 262,000+ trace lines will
be written for each device that enables IOBUS tracing. To avoid this,
consecutive CLC 0 operations after the first are omitted. This is
detected by checking the select code and signal set of the last I/O
operation.
*/ */
static uint32 cpuio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) static uint32 cpuio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
{ {
static IOCYCLE last_signal_set = ioNONE; /* the last set of I/O signals processed */
uint32 sc; uint32 sc;
IOSIGNAL signal; IOSIGNAL signal;
IOCYCLE working_set = signal_set; /* no SIR handler needed */ IOCYCLE working_set = signal_set; /* no SIR handler needed */
@ -3459,7 +3549,10 @@ while (working_set) {
break; break;
case ioCLC: /* clear control flip-flop */ case ioCLC: /* clear control flip-flop */
for (sc = CRSDEV; sc <= MAXDEV; sc++) /* send CRS to devices */ if (last_select_code != 0 /* if the last I/O instruction */
|| (last_signal_set & ioCLC) == 0) /* was not a CLC 0 */
for (sc = CRSDEV; sc <= MAXDEV; sc++) /* then assert the CRS signal */
if (devs [sc] != NULL) /* to all occupied I/O slots */
io_dispatch (sc, ioCRS, 0); /* from select code 6 and up */ io_dispatch (sc, ioCRS, 0); /* from select code 6 and up */
break; break;
@ -3470,6 +3563,8 @@ while (working_set) {
working_set = working_set & ~signal; /* remove current signal from set */ working_set = working_set & ~signal; /* remove current signal from set */
} }
last_signal_set = signal_set; /* save the current signal set for the next call */
return stat_data; return stat_data;
} }
@ -3682,11 +3777,10 @@ return SCPE_OK; /* return success status
If this is the first call after simulator startup, the initial memory array If this is the first call after simulator startup, the initial memory array
is allocated, the default CPU and memory size configuration is set, and the is allocated, the default CPU and memory size configuration is set, and the
SCP-required program counter pointer is set to point to the REG array element SCP-required program counter pointer is set to point to the REG array element
corresponding to the P register. corresponding to the P register. In addition, the loader ROM sockets of the
1000-series CPUs are populated with the initial ROM set, and the Basic Binary
If this is a power-on reset ("RESET -P"), the default Basic Binary Loader is Loader (BBL) is installed in protected memory (the upper 64 words of the
installed in protected memory (the upper 64 words of the defined memory defined memory size).
size).
Implementation notes: Implementation notes:
@ -3695,30 +3789,33 @@ return SCPE_OK; /* return success status
order automatically. A fixed setting runs the risk of it not being order automatically. A fixed setting runs the risk of it not being
updated if a change in the register order is made. updated if a change in the register order is made.
2. A power-on reset installs the BBL in 21xx machines. The IBL copy routine 2. The initial set of installed HP 1000 boot loader ROMs is:
sets the last loader word to the two's complement of the loader starting
address and configures the second-to-last word (nominally the DMA control Socket ROM Boot Device
word) to the I/O select code. For the BBL, the starting address location ------ ------ ------------------------
is five locations back, and the DMA control word is not used, so these 0 12992K 2748 Paper Tape Reader
fixups are performed after copying. 1 12992A 7900 or 2883 Disc Drive
2 12992D 7970 Magnetic Tape Drive
3 12992B 7905/06/20/25 Disc Drive
*/ */
static t_stat cpu_reset (DEVICE *dptr) static t_stat cpu_reset (DEVICE *dptr)
{ {
if (M == NULL) { /* initial call after startup? */ if (M == NULL) { /* if this is the initial call after simulator startup */
pcq_r = find_reg ("PCQ", NULL, dptr); /* get PC queue pointer */ pcq_r = find_reg ("PCQ", NULL, dptr); /* then get the PC queue pointer */
if (pcq_r) /* defined? */ if (pcq_r == NULL) /* if the PCQ register is not present */
pcq_r->qptr = 0; /* initialize queue */ return SCPE_IERR; /* then something is seriously wrong */
else /* not defined */ else /* otherwise */
return SCPE_IERR; /* internal error */ pcq_r->qptr = 0; /* initialize the register's queue pointer */
M = (MEMORY_WORD *) calloc (PASIZE, sizeof (MEMORY_WORD)); /* alloc mem */ M = (MEMORY_WORD *) calloc (PASIZE, /* allocate and zero the main memory array */
sizeof (MEMORY_WORD)); /* to the maximum configurable size */
if (M == NULL) /* alloc fail? */ if (M == NULL) /* if the allocation failed */
return SCPE_MEM; return SCPE_MEM; /* then report a "Memory exhausted" error */
else { /* do one-time init */ else { /* otherwise perform one-time initialization */
for (sim_PC = dptr->registers; /* find the P register entry */ for (sim_PC = dptr->registers; /* find the P register entry */
sim_PC->loc != &PR && sim_PC->loc != NULL; /* in the register array */ sim_PC->loc != &PR && sim_PC->loc != NULL; /* in the register array */
sim_PC++); /* for the SCP interface */ sim_PC++); /* for the SCP interface */
@ -3728,27 +3825,22 @@ if (M == NULL) { /* initial call after st
MEMSIZE = 32768; /* set the initial memory size */ MEMSIZE = 32768; /* set the initial memory size */
set_model (NULL, UNIT_2116, NULL, NULL); /* and the initial CPU model */ set_model (NULL, UNIT_2116, NULL, NULL); /* and the initial CPU model */
loader_rom [0] = find_dev ("PTR"); /* install the 12992K ROM in socket 0 */
loader_rom [1] = find_dev ("DQC"); /* and the 12992A ROM in socket 1 */
loader_rom [2] = find_dev ("MSC"); /* and the 12992D ROM in socket 2 */
loader_rom [3] = find_dev ("DS"); /* and the 12992B ROM in socket 3 */
loader_rom [0]->boot (0, loader_rom [0]); /* install the BBL via the paper tape reader boot routine */
set_loader (NULL, FALSE, NULL, NULL); /* and then disable the loader, which was enabled */
} }
} }
if (sim_switches & SWMASK ('P')) { /* if this is a power-on reset */ if (sim_switches & SWMASK ('P')) /* if this is a power-on reset */
if (! is_1000) { /* then if the CPU is configured as a 21xx machine */ IOPOWERON (&cpu_dib); /* then issue the PON signal to the CPU */
cpu_ibl (bbl, ptr_dib.select_code, /* then install the BBL and configure it */ else /* otherwise */
IBL_S_NOCLR, IBL_S_NOSET); /* to the paper tape reader's select code */ IOPRESET (&cpu_dib); /* issue a PRESET */
M [PR + BBL_FWA] = M [PR + IBL_END]; /* move the BBL starting address to correct location */
M [PR + IBL_DPC] = bbl [IBL_DPC]; /* and restore the last two words of the BBL */
M [PR + IBL_END] = bbl [IBL_END]; /* that are overwritten by the 1000 IBL */
set_loader (NULL, FALSE, NULL, NULL); /* disable the loader, which was enabled by cpu_ibl */
}
IOPOWERON (&cpu_dib); /* issue the PON signal to the CPU */
}
else /* PRESET */
IOPRESET (&cpu_dib);
sim_brk_dflt = SWMASK ('N'); /* the default breakpoint type is "nomap" as MEM is disabled */ sim_brk_dflt = SWMASK ('N'); /* the default breakpoint type is "nomap" as MEM is disabled */
@ -3756,36 +3848,68 @@ return SCPE_OK;
} }
/* IBL routine (CPU boot) */ /* Device boot routine.
This routine is called by the BOOT CPU and LOAD CPU commands to copy the
specified boot loader ROM program into the upper 64 words of the logical
address space. It is equivalent to pressing the IBL (Initial Binary Loader)
button on the front panel of a 1000 M/E/F-Series CPU.
On entry, the S register must be set to indicate the specific boot loader ROM
and the associated device select code to be copied, as follows:
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| ROM # | - - | select code | - - - - - - |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
Bits 15-14 select one of four loader ROM sockets on the CPU board that may
contain ROMs. If the specified socket does, the contents of the ROM are
copied into the upper 64 words of memory and configured to use the specified
select code. The unspecified bits of the S register are available for use by
the bootstrap program.
If the select code is less than 10 octal, the loader is not copied, and the
O (overflow) register is set to 1. A successful copy and configuration
clears the O register.
The 21xx-series CPUs do not provide the IBL function. If this routine is
invoked while the CPU is configured as one of these machines, the command is
rejected.
Implementation notes:
1. In hardware, a non-existent ROM (i.e., an empty socket) reads as though
all words contain 177777 octal. This would result in the loader area of
memory containing 62 all-ones words, followed by a word set to 177777 +
SC - 000010, where SC is the configured select code, followed by a word
set to the negative starting address of the loader. This is not
simulated; instead, an attempt to boot from an empty socket is rejected
with "Command not allowed."
*/
static t_stat cpu_boot (int32 unitno, DEVICE *dptr) static t_stat cpu_boot (int32 unitno, DEVICE *dptr)
{ {
int32 dev = (SR >> IBL_V_DEV) & I_DEVMASK; const int32 select_code = IBL_SC (SR); /* the select code from S register bits 11-6 */
int32 sel = (SR >> IBL_V_SEL) & IBL_M_SEL; const int32 rom_socket = IBL_ROM (SR); /* the ROM socket number from S register bits 15-14 */
if (dev < 010) if (is_1000) /* if this is a 1000-series CPU */
return SCPE_NOFNC; if (select_code < VARDEV) { /* then if the select code is invalid */
O = 1; /* then set the overflow register */
switch (sel) { return SCPE_ARG; /* and reject the IBL with "Invalid argument" */
case 0: /* PTR boot */
cpu_ibl (ptr_rom, dev, IBL_S_NOCLR, IBL_S_NOSET);
break;
case 1: /* DP/DQ boot */
cpu_ibl (dq_rom, dev, IBL_S_NOCLR, IBL_S_NOSET);
break;
case 2: /* MS boot */
cpu_ibl (ms_rom, dev, IBL_S_NOCLR, IBL_S_NOSET);
break;
case 3: /* DS boot */
cpu_ibl (ds_rom, dev, IBL_S_NOCLR, IBL_S_NOSET);
break;
} }
return SCPE_OK; else if (loader_rom [rom_socket] == NULL) /* otherwise if the ROM socket is empty */
return SCPE_NXDEV; /* then reject with "Non-existent device" */
else { /* otherwise */
O = 0; /* clear overflow to indicate a good IBL */
return loader_rom [rom_socket]->boot (select_code, NULL); /* and copy the ROM into memory */
}
else /* otherwise this is a 21xx machine */
return SCPE_NOFNC; /* and IBL isn't supported */
} }
@ -3930,7 +4054,7 @@ if (is_1000) /* loader unsupported */
else { /* 21xx CPU? */ else { /* 21xx CPU? */
set_loader (uptr, FALSE, NULL, NULL); /* save loader to shadow RAM */ set_loader (uptr, FALSE, NULL, NULL); /* save loader to shadow RAM */
MEMSIZE = new_size; /* set new memory size */ MEMSIZE = new_size; /* set new memory size */
fwanxm = (uint32) MEMSIZE - IBL_LNT; /* reserve memory for loader */ fwanxm = (uint32) MEMSIZE - IBL_SIZE; /* reserve memory for loader */
} }
for (i = fwanxm; i < old_size; i++) /* zero non-existent memory */ for (i = fwanxm; i < old_size; i++) /* zero non-existent memory */
@ -4052,7 +4176,7 @@ if (result == SCPE_OK) { /* if the ch
if (is_1000) if (is_1000)
fwanxm = (uint32) MEMSIZE; /* loader reserved only for 21xx */ fwanxm = (uint32) MEMSIZE; /* loader reserved only for 21xx */
else /* 2100 or 211x */ else /* 2100 or 211x */
fwanxm = (uint32) MEMSIZE - IBL_LNT; /* reserve memory for loader */ fwanxm = (uint32) MEMSIZE - IBL_SIZE; /* reserve memory for loader */
} }
return result; return result;
@ -4188,23 +4312,23 @@ return SCPE_OK;
static t_stat set_loader (UNIT *uptr, int32 enable, CONST char *cptr, void *desc) static t_stat set_loader (UNIT *uptr, int32 enable, CONST char *cptr, void *desc)
{ {
static BOOT_ROM loader; static MEMORY_WORD loader [IBL_SIZE];
int32 i; uint32 i;
t_bool is_enabled = (fwanxm == MEMSIZE); t_bool is_enabled = (fwanxm == MEMSIZE);
if (is_1000 || MEMSIZE == 0) /* valid only for 21xx and for initialized memory */ if (is_1000 || MEMSIZE == 0) /* valid only for 21xx and for initialized memory */
return SCPE_NOFNC; return SCPE_NOFNC;
if (is_enabled && (enable == 0)) { /* disable loader? */ if (is_enabled && (enable == 0)) { /* disable loader? */
fwanxm = (uint32) MEMSIZE - IBL_LNT; /* decrease available memory */ fwanxm = (uint32) MEMSIZE - IBL_SIZE; /* decrease available memory */
for (i = 0; i < IBL_LNT; i++) { /* copy loader */ for (i = 0; i < IBL_SIZE; i++) { /* copy loader */
loader [i] = M [fwanxm + i]; /* from memory */ loader [i] = M [fwanxm + i]; /* from memory */
M [fwanxm + i] = 0; /* and zero location */ M [fwanxm + i] = 0; /* and zero location */
} }
} }
else if ((!is_enabled) && (enable == 1)) { /* enable loader? */ else if ((!is_enabled) && (enable == 1)) { /* enable loader? */
for (i = 0; i < IBL_LNT; i++) /* copy loader */ for (i = 0; i < IBL_SIZE; i++) /* copy loader */
M [fwanxm + i] = loader [i]; /* to memory */ M [fwanxm + i] = loader [i]; /* to memory */
fwanxm = (uint32) MEMSIZE; /* increase available memory */ fwanxm = (uint32) MEMSIZE; /* increase available memory */
} }
@ -4213,6 +4337,100 @@ return SCPE_OK;
} }
/* Change the set of installed loader ROMs.
This validation routine is called to install loader ROMs in the four
available sockets of a 1000-series CPU. The routine processes commands of
the form:
SET CPU ROMS=[<dev0>][;[<dev1>][;[<dev2>][;[<dev3>]]]]
On entry, "cptr" points at the the first character of the ROM list. The
option value and the unit and description pointers are not used.
All four ROM sockets are set for each command. If no devices are specified,
then all sockets are emptied. Otherwise, specifying a valid device name
installs the device loader ROM into the socket corresponding to the position
of the device name in the list. Sockets may be left empty by omitting the
corresponding device name or by supplying fewer than four device names.
Loader ROMs may only be altered if the current CPU model is a 1000-series
machine, and a device must be bootable and have a loader ROM assigned, or the
command will be rejected. A rejected command does not alter any of the ROM
assignments.
Example commands and their effects on the installed ROM sockets follow:
Command Action
--------------------- -------------------------------------------------
SET CPU ROMS= Remove ROMs from sockets 0-3
SET CPU ROMS=PTR Install PTR in 0; leave 1-3 empty
SET CPU ROMS=DS;MS Install DS in 0 and MS in 1; leave 2 and 3 empty
SET CPU ROMS=;;DPC Install DPC in 2; leave 0, 1, and 3 empty
SET CPU ROMS=DQC;;;DA Install DQC in 0 and DA in 3; leave 1 and 2 empty
Implementation notes:
1. Entering "SET CPU ROMS" without an equals sign or list is rejected with a
"Missing value" error. This is to prevent accidental socket clearing
when "SHOW CPU ROMS" was intended.
*/
static t_stat set_roms (UNIT *uptr, int32 option, CONST char *cptr, void *desc)
{
DEVICE *dptr;
char gbuf [CBUFSIZE];
uint32 socket = 0;
DEVICE *rom [4] = { NULL };
if (is_1000 == FALSE) /* if the CPU is not a 1000-series unit */
return SCPE_NOFNC; /* then reject the command */
else if (cptr == NULL) /* otherwise if the list is not specified */
return SCPE_MISVAL; /* then report that the list is missing */
else if (*cptr == '\0') { /* otherwise if the list is null */
loader_rom [0] = NULL; /* then empty */
loader_rom [1] = NULL; /* all of the */
loader_rom [2] = NULL; /* ROM sockets */
loader_rom [3] = NULL;
}
else { /* otherwise */
while (*cptr) { /* loop through the arguments */
cptr = get_glyph (cptr, gbuf, ';'); /* get the next argument */
if (socket == 4) /* if all four sockets have been set */
return SCPE_2MARG; /* then reject the command */
else if (gbuf [0] == '\0') /* otherwise if the device name is omitted */
rom [socket++] = NULL; /* then empty the corresponding socket */
else { /* otherwise we have a device name */
dptr = find_dev (gbuf); /* so find the associated DEVICE pointer */
if (dptr == NULL) /* if the device name is not valid */
return SCPE_NXDEV; /* then reject the command */
else if (dptr->boot == NULL) /* otherwise if it's valid but not bootable */
return SCPE_NOFNC; /* then reject the command */
else /* otherwise */
rom [socket++] = dptr; /* install the boot loader ROM */
}
}
loader_rom [0] = rom [0]; /* install the ROM set */
loader_rom [1] = rom [1]; /* now that we have */
loader_rom [2] = rom [2]; /* a valid */
loader_rom [3] = rom [3]; /* device list */
}
return SCPE_OK; /* report that the command succeeded */
}
/* Change the instruction execution trace criteria. /* Change the instruction execution trace criteria.
This validation routine is called to configure the criteria that select This validation routine is called to configure the criteria that select
@ -4363,6 +4581,75 @@ return SCPE_OK;
} }
/* Show the set of installed loader ROMs.
This display routine is called to show the set of installed loader ROMs in
the four available sockets of a 1000-series CPU. On entry, the "st"
parameter is the open output stream. The other parameters are not used.
The routine prints a table of ROMs in this format:
Socket Device ROM
------ ------- ------
0 PTR 12992K
1 DQC 12992A
2 DS 12992B
3 <empty>
If a given socket contains a ROM, the associated device name and HP part
number for the loader ROM are printed.
This routine services an extended modifier entry, so it must add the trailing
newline to the output before returning.
*/
static t_stat show_roms (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
struct LOOKUP_TABLE {
char *name; /* device name */
char suffix; /* ROM part number suffix */
};
static const struct LOOKUP_TABLE lookup [] = { /* table of device names and ROM part numbers */
{ "DQC", 'A' }, /* 12992A 7900/7901/2883 Disc Loader */
{ "DS", 'B' }, /* 12992B 7905/7906/7920/7925 Disc Loader */
{ "MSC", 'D' }, /* 12992D 7970 Magnetic Tape Loader */
{ "DPC", 'F' }, /* 12992F 7900/7901 Disc Loader */
{ "DA", 'H' }, /* 12992H 7906H/7920H/7925H/9885 Disc Loader */
{ "IPLI", 'K' }, /* 12992K Paper Tape Loader */
{ "PTR", 'K' }, /* 12992K Paper Tape Loader */
{ NULL, '?' }
};
CONST char *dname;
uint32 socket, index;
char letter = '?';
fputc ('\n', st); /* skip a line */
fputs ("Socket Device ROM\n", st); /* and print */
fputs ("------ ------- ------\n", st); /* the table header */
for (socket = 0; socket < 4; socket++) /* loop through the sockets */
if (loader_rom [socket] == NULL) /* if the socket is empty */
fprintf (st, " %u <empty>\n", socket); /* then report it as such */
else { /* otherwise the socket is occupied */
dname = loader_rom [socket]->name; /* so get the device name */
for (index = 0; lookup [index].name; index++) /* search the lookup table */
if (strcmp (lookup [index].name, dname) == 0) { /* for a match to the device name */
letter = lookup [index].suffix; /* and get the part number suffix */
break;
}
fprintf (st, " %u %-4s 12992%c\n", /* print the ROM information */
socket, dname, letter);
}
return SCPE_OK; /* return success status */
}
/* Show the instruction execution trace criteria. /* Show the instruction execution trace criteria.
This display routine is called to show the criteria that select instruction This display routine is called to show the criteria that select instruction
@ -4722,7 +5009,7 @@ switch (UPPER_BYTE (IR)) { /* dispatch on bits 15-8
&& (mem_fast_read (PR, dms_ump) & I_MRG) == I_ISZ) /* and *-1 is ISZ <n> */ && (mem_fast_read (PR, dms_ump) & I_MRG) == I_ISZ) /* and *-1 is ISZ <n> */
&& mp_fence == 0 /* and the MP fence is zero */ && mp_fence == 0 /* and the MP fence is zero */
&& M [xeqt] == 0 /* and no program is executing */ && M [xeqt] == 0 /* and no program is executing */
&& M [tbg] == clk_dib.select_code) /* and the TBG select code is set */ && M [tbg] == tbg_select_code) /* and the TBG select code is set */
|| PR == err_PC - 3 /* or the jump target is *-3 (DOS through DOS-III) */ || PR == err_PC - 3 /* or the jump target is *-3 (DOS through DOS-III) */
&& M [PR] == I_STF /* and *-3 is STF 0 */ && M [PR] == I_STF /* and *-3 is STF 0 */
@ -5827,7 +6114,8 @@ for (i = 0; sim_devices [i] != NULL; i++) { /* loop through all of t
devs [dibptr->select_code] = dptr; /* then set the device pointer into the device table */ devs [dibptr->select_code] = dptr; /* then set the device pointer into the device table */
dibs [dibptr->select_code] = dibptr; /* and set the DIB pointer into the dispatch table */ dibs [dibptr->select_code] = dibptr; /* and set the DIB pointer into the dispatch table */
dibptr->io_handler (dibptr, ioSIR, 0); /* set the interrupt request state */ if (dibptr->select_code >= SIRDEV) /* if this device receives SIR */
dibptr->io_handler (dibptr, ioSIR, 0); /* then set the interrupt request state */
} }
} }
@ -5876,17 +6164,15 @@ return;
(high on the 1000, low on the 21xx). For select codes >= 10 octal, an (high on the 1000, low on the 21xx). For select codes >= 10 octal, an
IOI reads the floating I/O bus (low on all machines). IOI reads the floating I/O bus (low on all machines).
2. If the UNSC simulation stop is set, a stop will occur when an unassigned 2. The last select code used is saved for use by the CPU I/O handler in
device is accessed. An exception is a CLC 0 instruction, which asserts detecting consecutive CLC 0 executions.
the CRS signal to all I/O devices from select code 6 up. This is a
legitimate access and does not cause a stop.
*/ */
static uint32 io_dispatch (uint32 select_code, IOCYCLE signal_set, HP_WORD data) static uint32 io_dispatch (uint32 select_code, IOCYCLE signal_set, HP_WORD data)
{ {
uint32 stat_data; uint32 stat_data;
if (devs [select_code] != NULL) { /* if the I/O slot is occupied */ if (dibs [select_code] != NULL) { /* if the I/O slot is occupied */
tpprintf (devs [select_code], TRACE_IOBUS, "Received data %06o with signals %s\n", tpprintf (devs [select_code], TRACE_IOBUS, "Received data %06o with signals %s\n",
data, fmt_bitset (signal_set, inbound_format)); data, fmt_bitset (signal_set, inbound_format));
@ -5895,11 +6181,14 @@ if (devs [select_code] != NULL) { /* if the I/O slot i
signal_set, signal_set,
IORETURN (SCPE_OK, data)); IORETURN (SCPE_OK, data));
tpprintf (devs [select_code], TRACE_IOBUS, "Returned data %06o\n", IODATA (stat_data)); tpprintf (devs [select_code], TRACE_IOBUS, "Returned data %06o with signals %s\n",
} IODATA (stat_data), fmt_bitset (stat_data, outbound_format));
else if (signal_set == ioCRS) /* otherwise the slot is empty, but if this is a CRS */ last_select_code = select_code; /* save the select code for CLC 0 detection */
return SCPE_OK; /* then it's legal to send it to unassigned slots */
if (stat_data & ioSKF) /* if the interface asserted SKF */
stat_data = IORETURN (NOTE_SKIP, 0); /* then notify the caller to increment P */
}
else if (signal_set & ioIOI) /* otherwise if it is an input request */ else if (signal_set & ioIOI) /* otherwise if it is an input request */
if (select_code < VARDEV && is_1000) /* then if it is an internal device of a 1000 CPU */ if (select_code < VARDEV && is_1000) /* then if it is an internal device of a 1000 CPU */

View file

@ -1,7 +1,7 @@
/* hp2100_cpu.h: HP 2100 CPU declarations /* hp2100_cpu.h: HP 2100 CPU declarations
Copyright (c) 2005-2016, Robert M. Supnik Copyright (c) 2005-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 Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -24,6 +24,8 @@
used in advertising or otherwise to promote the sale, use or other dealings used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from the authors. 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 22-Jul-17 JDB Renamed "intaddr" to CIR; added IR
14-Jul-17 JDB Removed calc_defer() prototype 14-Jul-17 JDB Removed calc_defer() prototype
11-Jul-17 JDB Moved "ibl_copy" and renamed to "cpu_ibl" 11-Jul-17 JDB Moved "ibl_copy" and renamed to "cpu_ibl"
@ -507,32 +509,50 @@
#define I_SFS 0102300u /* SFS instruction */ #define I_SFS 0102300u /* SFS instruction */
#define I_STF 0102100u /* STF instruction */ #define I_STF 0102100u /* STF instruction */
/* IBL assignments */
#define IBL_V_SEL 14 /* ROM select <15:14> */ /* Initial Binary Loader.
#define IBL_M_SEL 03
#define IBL_PTR 0000000u /* ROM 0: 12992K paper tape reader (PTR) */
#define IBL_DP 0040000u /* ROM 1: 12992A 7900 disc (DP) */
#define IBL_DQ 0060000u /* ROM 1: 12992A 2883 disc (DQ) */
#define IBL_MS 0100000u /* ROM 2: 12992D 7970 tape (MS) */
#define IBL_DS 0140000u /* ROM 3: 12992B 7905/06/20/25 disc (DS) */
#define IBL_MAN 0010000u /* RPL/manual boot <13:12> */
#define IBL_V_DEV 6 /* select code <11:6> */
#define IBL_OPT 0000070u /* options in <5:3> */
#define IBL_DP_REM 0000001u /* DP removable <0:0> */
#define IBL_DS_HEAD 0000003u /* 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 0000000u /* cpu_ibl mask to clear the S register */ 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
#define IBL_S_NOCLR 0177777u /* cpu_ibl mask to preserve the S register */ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
#define IBL_S_NOSET 0000000u /* cpu_ibl mask to preserve the S register */ | ROM # | - - | select code | - - - - - - |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
*/
#define IBL_SET_SC(s) ((HP_WORD) ((s) << IBL_V_DEV)) /* position the select code in the S register */ #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 */
typedef MEMORY_WORD BOOT_ROM [IBL_LNT]; /* boot ROM data */ #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 */
/* Memory management */ /* Memory management */
@ -641,6 +661,7 @@ extern UNIT *cpu_ioerr_uptr; /* pointer to a unit with an unr
extern uint32 cpu_configuration; /* the current CPU option set and model */ 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 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 global SCP support routines declared in scp.h /* CPU global SCP support routines declared in scp.h
@ -656,7 +677,7 @@ extern void cpu_post_cmd (t_bool from_scp);
/* CPU global utility routines */ /* CPU global utility routines */
extern void cpu_ibl (const BOOT_ROM rom, int32 dev, HP_WORD sr_clear, HP_WORD sr_set); 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 t_stat cpu_iog (HP_WORD IR, t_bool iotrap);
extern uint32 calc_int (void); extern uint32 calc_int (void);
extern t_stat resolve (HP_WORD MA, HP_WORD *address, uint32 irq); extern t_stat resolve (HP_WORD MA, HP_WORD *address, uint32 irq);

View file

@ -26,6 +26,7 @@
CPU1 Extended arithmetic and optional microcode dispatchers 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 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 07-Jul-17 JDB Changed "iotrap" from uint32 to t_bool
26-Jun-17 JDB Replaced SEXT with SEXT16 26-Jun-17 JDB Replaced SEXT with SEXT16
@ -871,11 +872,11 @@ for (i = 0; i < OP_N_F; i++) {
break; break;
case OP_VAR: /* inline variable operand */ case OP_VAR: /* inline variable operand */
(*op++).word = (uint16) PR; /* get pointer to variable */ (*op++).word = PR; /* get pointer to variable */
break; break;
case OP_ADR: /* inline address operand */ 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; break;
case OP_ADK: /* address of int constant */ case OP_ADK: /* address of int constant */

View file

@ -27,6 +27,7 @@
CPU2 Floating-point, dynamic mapping, extended, and I/O processor CPU2 Floating-point, dynamic mapping, extended, and I/O processor
instructions instructions
07-Sep-17 JDB Removed unnecessary "uint16" casts
10-Jul-17 JDB Renamed the global routine "iogrp" to "cpu_iog" 10-Jul-17 JDB Renamed the global routine "iogrp" to "cpu_iog"
26-Jun-17 JDB Replaced SEXT with SEXT16 26-Jun-17 JDB Replaced SEXT with SEXT16
22-Mar-17 JDB Corrected comments regarding IR bit 11 selecting A/B 22-Mar-17 JDB Corrected comments regarding IR bit 11 selecting A/B
@ -480,11 +481,11 @@ switch (entry) { /* decode IR<3:0> */
break; break;
case 030: /* RSA, RSB 10x730 (OP_N) */ case 030: /* RSA, RSB 10x730 (OP_N) */
ABREG[absel] = (uint16) dms_upd_sr (); /* save stat */ ABREG [absel] = dms_upd_sr (); /* save stat */
break; break;
case 031: /* RVA, RVB 10x731 (OP_N) */ 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; break;
case 032: /* DJP 105732 (OP_A) */ case 032: /* DJP 105732 (OP_A) */
@ -659,7 +660,7 @@ switch (entry) { /* decode IR<4:0> */
break; break;
case 004: /* CXA, CXB 10x744 (OP_N) */ case 004: /* CXA, CXB 10x744 (OP_N) */
ABREG[absel] = (uint16) XR; /* copy from XR */ ABREG [absel] = XR; /* copy from XR */
break; break;
case 005: /* LDX 105745 (OP_K)*/ case 005: /* LDX 105745 (OP_K)*/
@ -676,7 +677,7 @@ switch (entry) { /* decode IR<4:0> */
case 007: /* XAX, XBX 10x747 (OP_N) */ case 007: /* XAX, XBX 10x747 (OP_N) */
t = XR; /* exchange XR */ t = XR; /* exchange XR */
XR = ABREG [absel]; XR = ABREG [absel];
ABREG[absel] = (uint16) t; ABREG [absel] = t;
break; break;
case 010: /* SAY, SBY 10x750 (OP_A) */ case 010: /* SAY, SBY 10x750 (OP_A) */
@ -698,7 +699,7 @@ switch (entry) { /* decode IR<4:0> */
break; break;
case 014: /* CYA, CYB 10x754 (OP_N) */ case 014: /* CYA, CYB 10x754 (OP_N) */
ABREG[absel] = (uint16) YR; /* copy from YR */ ABREG [absel] = YR; /* copy from YR */
break; break;
case 015: /* LDY 105755 (OP_K) */ case 015: /* LDY 105755 (OP_K) */
@ -715,7 +716,7 @@ switch (entry) { /* decode IR<4:0> */
case 017: /* XAY, XBY 10x757 (OP_N) */ case 017: /* XAY, XBY 10x757 (OP_N) */
t = YR; /* exchange YR */ t = YR; /* exchange YR */
YR = ABREG [absel]; YR = ABREG [absel];
ABREG[absel] = (uint16) t; ABREG [absel] = t;
break; break;
/* EIG module 2 */ /* EIG module 2 */
@ -1044,7 +1045,7 @@ switch (entry) { /* decode IR<5:0> */
break; break;
case 002: /* READF 105462 (OP_N) */ case 002: /* READF 105462 (OP_N) */
AR = (uint16) iop_sp; /* copy stk ptr */ AR = iop_sp; /* copy stk ptr */
break; break;
case 003: /* INS 105463 (OP_N) */ case 003: /* INS 105463 (OP_N) */

View file

@ -1,6 +1,6 @@
/* hp2100_cpu4.c: HP 1000 FPP/SIS /* 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 Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,7 @@
CPU4 Floating Point Processor and Scientific Instruction Set 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" 05-Aug-16 JDB Renamed the P register from "PC" to "PR"
24-Dec-14 JDB Added casts for explicit downward conversions 24-Dec-14 JDB Added casts for explicit downward conversions
09-May-12 JDB Separated assignments from conditional expressions 09-May-12 JDB Separated assignments from conditional expressions
@ -315,7 +316,7 @@ switch (entry) { /* decode IR<6:0> */
case 0007: /* [stk] 105007 (OP_A) */ case 0007: /* [stk] 105007 (OP_A) */
O = 0; /* clear overflow */ 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 */ rtn_addr = op[0].word; /* save return address */
while (TRUE) { while (TRUE) {
@ -712,7 +713,7 @@ switch (entry) { /* decode IR<3:0> */
op[1].fpk[1] = op[1].fpk[1] | 2; /* set "exponent" to 1 */ 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 (0120, &op[3], op[2], NOP); /* op3 = FLT(exponent) */
fp_exec (0020, &op[4], op[1], plus_1); /* op4 = op1 - 1.0 */ fp_exec (0020, &op[4], op[1], plus_1); /* op4 = op1 - 1.0 */

View file

@ -26,6 +26,7 @@
CPU5 RTE-6/VM and RTE-IV firmware option instructions CPU5 RTE-6/VM and RTE-IV firmware option instructions
07-Sep-17 JDB Replaced "uint16" casts with "HP_WORD" for A/B assignments
15-Jul-17 JDB Replaced "vma_resolve" with "resolve" 15-Jul-17 JDB Replaced "vma_resolve" with "resolve"
26-Jun-17 JDB Replaced SEXT with SEXT16 26-Jun-17 JDB Replaced SEXT with SEXT16
06-Jun-17 HV Fixed bug in cpu_vma_lbp "last suit + 1" handler 06-Jun-17 HV Fixed bug in cpu_vma_lbp "last suit + 1" handler
@ -623,7 +624,7 @@ if (!p30) /* matched suit for 1st
* must be in idx 0 of PTE */ * must be in idx 0 of PTE */
if (pgidx==01777) { /* suit switch situation */ if (pgidx==01777) { /* suit switch situation */
pgidx = 0; /* select correct idx 0 */ pgidx = 0; /* select correct idx 0 */
suit = (uint16) (pagid + 1); /* suit needs increment */ suit = (HP_WORD) (pagid + 1 & D16_MASK); /* suit needs increment with wraparound */
if (suit==0) { /* is it page 65536? */ if (suit==0) { /* is it page 65536? */
offset += 02000; /* adjust to 2nd page */ offset += 02000; /* adjust to 2nd page */
suit = NILPAGE; suit = NILPAGE;
@ -653,8 +654,8 @@ else {
return cpu_vma_fault(IR, pagid+1,page31,31,ptepg,faultab,faultpc); return cpu_vma_fault(IR, pagid+1,page31,31,ptepg,faultab,faultpc);
} }
AR = (uint16) pagid; /* return pagid in A */ AR = (HP_WORD) pagid; /* return pagid in A */
BR = (uint16) (page30 + offset); /* mapped address in B */ BR = (HP_WORD) (page30 + offset); /* mapped address in B */
return SCPE_OK; return SCPE_OK;
} }
@ -1261,7 +1262,7 @@ YR = ReadW(MA);
WriteW(vout++, MA); vin++; /* copy address of N */ WriteW(vout++, MA); vin++; /* copy address of N */
if (imax==0) goto easy; /* easy case */ if (imax==0) goto easy; /* easy case */
AR = (uint16) (k / imax); AR++; /* calculate K/IMAX */ AR = (HP_WORD) (k / imax); AR++; /* calculate K/IMAX */
if (negflag) goto hard; /* had a negative index? */ if (negflag) goto hard; /* had a negative index? */
if (YR > AR) goto hard; if (YR > AR) goto hard;
@ -1427,7 +1428,7 @@ if ((idext0 & 0100000) || /* was nonstd MSEG? */
e->npgs = msnum==e->msegno ? lastpgs : e->msegsz; /* for last MSEG, only map available pgs */ e->npgs = msnum==e->msegno ? lastpgs : e->msegsz; /* for last MSEG, only map available pgs */
if (!cpu_ema_mmap01(e)) return FALSE; /* map npgs pages at ipgs */ if (!cpu_ema_mmap01(e)) return FALSE; /* map npgs pages at ipgs */
} }
BR = (uint16) (e->mseg + e->msoff); /* return address of element */ BR = (HP_WORD) (e->mseg + e->msoff); /* return address of element */
return TRUE; /* and everything done */ return TRUE; /* and everything done */
} }
@ -1481,7 +1482,7 @@ if (npgs < e->msegsz) {
e->mseg = mseg; /* logical stat of MSEG */ e->mseg = mseg; /* logical stat of MSEG */
if (!cpu_ema_emat(e)) goto em16; /* do a std mapping */ if (!cpu_ema_emat(e)) goto em16; /* do a std mapping */
} else { } else {
BR = (uint16) (mseg + e->offs); /* logical start of buffer */ BR = (HP_WORD) (mseg + e->offs); /* logical start of buffer */
e->npgs = bufpgs; /* S5 # pgs required */ e->npgs = bufpgs; /* S5 # pgs required */
e->ipgs = e->pgoff; /* S6 page offset to reqd pg */ e->ipgs = e->pgoff; /* S6 page offset to reqd pg */
if (!cpu_ema_mmap02(e)) goto em16; /* do nonstd mapping */ if (!cpu_ema_mmap02(e)) goto em16; /* do nonstd mapping */
@ -1561,7 +1562,7 @@ if (xidex) { /* is EMA declared? */
idext0 = ReadWA(xidex+0) | 0100000; /* set NS flag in id extension */ idext0 = ReadWA(xidex+0) | 0100000; /* set NS flag in id extension */
WriteS (xidex + 0, idext0); /* save back value */ WriteS (xidex + 0, idext0); /* save back value */
AR = 0; /* was successful */ AR = 0; /* was successful */
BR = (uint16) (mseg + offs); /* calculate log address */ BR = (HP_WORD) (mseg + offs); /* calculate log address */
(*rtn)++; /* return via good exit */ (*rtn)++; /* return via good exit */
return SCPE_OK; return SCPE_OK;
} }
@ -1584,7 +1585,7 @@ while (ndim > 0) {
if (sum & 0xffff8000) goto em15; /* overflow? */ if (sum & 0xffff8000) goto em15; /* overflow? */
ndim--; ndim--;
} }
BR = (uint16) (abase + sum); /* add displacement */ BR = (HP_WORD) (abase + sum); /* add displacement */
(*rtn)++; /* return via good exit */ (*rtn)++; /* return via good exit */
return SCPE_OK; return SCPE_OK;

View file

@ -1,7 +1,7 @@
/* hp2100_defs.h: HP 2100 System architectural declarations /* hp2100_defs.h: HP 2100 System architectural declarations
Copyright (c) 1993-2016, Robert M. Supnik 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 Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -24,6 +24,9 @@
used in advertising or otherwise to promote the sale, use or other dealings used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from the authors. 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 30-Aug-17 JDB Replaced POLL_WAIT with POLL_PERIOD
07-Aug-17 JDB Added "hp_attach" 07-Aug-17 JDB Added "hp_attach"
20-Jul-17 JDB Removed STOP_OFFLINE, STOP_PWROFF stop codes 20-Jul-17 JDB Removed STOP_OFFLINE, STOP_PWROFF stop codes
@ -185,6 +188,7 @@
*/ */
#if defined (__clang__) #if defined (__clang__)
#pragma clang diagnostic ignored "-Wlogical-not-parentheses"
#pragma clang diagnostic ignored "-Wlogical-op-parentheses" #pragma clang diagnostic ignored "-Wlogical-op-parentheses"
#pragma clang diagnostic ignored "-Wbitwise-op-parentheses" #pragma clang diagnostic ignored "-Wbitwise-op-parentheses"
#pragma clang diagnostic ignored "-Wshift-op-parentheses" #pragma clang diagnostic ignored "-Wshift-op-parentheses"
@ -330,9 +334,9 @@
#define STOP_NOTAPE 8 /* no tape */ #define STOP_NOTAPE 8 /* no tape */
#define STOP_EOT 9 /* end of tape */ #define STOP_EOT 9 /* end of tape */
#define NOTE_IOG 10 /* I/O instr executed */ #define NOTE_IOG 10 /* an I/O instruction was executed */
#define NOTE_INDINT 11 /* indirect intr */ #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 */ /* Modifier validation identifiers */
@ -742,6 +746,7 @@ typedef enum { INITIAL, SERVICE } POLLMODE; /* poll synchronization
#define DI_DC 044 /* 12821A Disc Interface with CS/80 disc and tape devices */ #define DI_DC 044 /* 12821A Disc Interface with CS/80 disc and tape devices */
#define OPTDEV 002 /* start of optional 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 CRSDEV 006 /* start of devices that receive CRS */
#define VARDEV 010 /* start of variable assignments */ #define VARDEV 010 /* start of variable assignments */
#define MAXDEV 077 /* end of select code range */ #define MAXDEV 077 /* end of select code range */
@ -781,9 +786,9 @@ typedef enum { INITIAL, SERVICE } POLLMODE; /* poll synchronization
2. The ioSKF signal is never sent to an I/O handler. Rather, it is returned 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 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 is false, ioNONE is returned instead. As the ioSKF value is returned in
in the 16-bit data portion of the returned value, their assigned values the upper 16 bits of the returned value, its assigned value must be >=
must be <= 100000 octal. 200000 octal.
3. An I/O handler will receive ioCRS as a result of a CLC 0 instruction, 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 ioPOPIO and ioCRS as a result of a RESET command, and ioPON, ioPOPIO, and
@ -818,21 +823,22 @@ typedef enum { ioNONE = 0000000, /* -- -- -- -- -- no sig
ioIOI = 0000004, /* -- -- T4 T5 -- I/O data input (CPU) ioIOI = 0000004, /* -- -- T4 T5 -- I/O data input (CPU)
T2 T3 -- -- -- I/O data input (DMA) */ T2 T3 -- -- -- I/O data input (DMA) */
ioIOO = 0000010, /* -- T3 T4 -- -- I/O data output */ ioIOO = 0000010, /* -- T3 T4 -- -- I/O data output */
ioSKF = 0000020, /* -- T3 T4 T5 -- skip on flag */ ioSFS = 0000020, /* -- T3 T4 T5 -- skip if flag is set */
ioSFS = 0000040, /* -- T3 T4 T5 -- skip if flag is set */ ioSFC = 0000040, /* -- T3 T4 T5 -- skip if flag is clear */
ioSFC = 0000100, /* -- T3 T4 T5 -- skip if flag is clear */ ioSTC = 0000100, /* -- -- T4 -- -- set control flip-flop (CPU)
ioSTC = 0000200, /* -- -- T4 -- -- set control flip-flop (CPU)
-- T3 -- -- -- set control flip-flop (DMA) */ -- 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) */ -- T3 T4 -- -- clear control flip-flop (DMA) */
ioSTF = 0001000, /* -- T3 -- -- -- set flag flip-flop */ ioSTF = 0000400, /* -- T3 -- -- -- set flag flip-flop */
ioCLF = 0002000, /* -- -- T4 -- -- clear flag flip-flop (CPU) ioCLF = 0001000, /* -- -- T4 -- -- clear flag flip-flop (CPU)
-- T3 -- -- -- clear flag flip-flop (DMA) */ -- T3 -- -- -- clear flag flip-flop (DMA) */
ioEDT = 0004000, /* -- -- T4 -- -- end data transfer */ ioEDT = 0002000, /* -- -- T4 -- -- end data transfer */
ioCRS = 0010000, /* -- -- -- T5 -- control reset */ ioCRS = 0004000, /* -- -- -- T5 -- control reset */
ioPOPIO = 0020000, /* -- -- -- T5 -- power-on preset to I/O */ ioPOPIO = 0010000, /* -- -- -- T5 -- power-on preset to I/O */
ioIAK = 0040000, /* -- -- -- -- T6 interrupt acknowledge */ ioIAK = 0020000, /* -- -- -- -- T6 interrupt acknowledge */
ioSIR = 0100000 } IOSIGNAL; /* -- -- -- T5 -- set interrupt request */ 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 */ typedef uint32 IOCYCLE; /* a set of signals forming one I/O cycle */
@ -1003,7 +1009,7 @@ struct dib { /* the Device Information Block
#define BIT_V(S) ((S) & 037) /* convert select code to bit position */ #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 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 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)) #define setIRQ(S,B) dev_irq[(S)/32] = dev_irq[(S)/32] & ~BIT_M (S) | (((B) & 1) << BIT_V (S))
@ -1023,7 +1029,7 @@ struct dib { /* the Device Information Block
/* Bitset formatting. /* Bitset formatting.
See the comments at the "fmt_bitset" function (hp3000_sys.c) for details of See the comments at the "fmt_bitset" function (hp2100_sys.c) for details of
the specification of bitset names and format structures. the specification of bitset names and format structures.
*/ */

View file

@ -1,6 +1,6 @@
/* hp2100_di_da.c: HP 12821A HP-IB Disc Interface simulator for Amigo disc drives /* 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 Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,7 @@
DA 12821A Disc Interface with Amigo disc drives 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" 11-Jul-17 JDB Renamed "ibl_copy" to "cpu_ibl"
15-Mar-17 JDB Changed DEBUG_PRI calls to tprintfs 15-Mar-17 JDB Changed DEBUG_PRI calls to tprintfs
09-Mar-17 JDB Deprecated LOCKED/WRITEENABLED for PROTECT/UNPROTECT 09-Mar-17 JDB Deprecated LOCKED/WRITEENABLED for PROTECT/UNPROTECT
@ -1080,6 +1081,9 @@ return status;
The unspecified responses are illegal conditions; for example, the simulator The unspecified responses are illegal conditions; for example, the simulator
does not allow an attached unit to be disabled. 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: Implementation notes:
@ -1091,19 +1095,36 @@ return status;
specifying a validation routine works for the DISABLED case but not the specifying a validation routine works for the DISABLED case but not the
ENABLED case -- set_unit_enbdis returns SCPE_UDIS before calling the ENABLED case -- set_unit_enbdis returns SCPE_UDIS before calling the
validation routine. 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 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 */ const int32 unit = uptr - da_unit; /* calculate the unit number */
result = dl_attach (&icd_cntlr [unit], uptr, cptr); /* attach the drive */ result = dl_attach (&icd_cntlr [unit], uptr, cptr); /* attach the drive */
if (result == SCPE_OK) /* was the attach successful? */ if (result == SCPE_OK) { /* if the attach was successful */
di [da].acceptors |= (1 << unit); /* set the unit's accepting bit */ 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 */
} }
@ -1130,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 The HP 1000 uses the 12992H boot loader ROM to bootstrap the ICD discs. Bit
into memory, the I/O instructions are configured for the interface card's 12 of the S register determines whether an RPL or manual boot is performed.
select code, and the program is run to boot from the specified unit. The Bits 1-0 specify the head number to use.
loader supports booting the disc at bus address 0 only. Before execution,
the S register is automatically set as follows: 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 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
------ ------ ---------------------- ------------- ----- +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
ROM # 0 1 select code reserved head | 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. 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 Bits 5-3 and 1-0 retain their original values, so S should be set before
@ -1149,83 +1284,21 @@ return result;
than 0 is desired. 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) t_stat da_boot (int32 unitno, DEVICE *dptr)
{ {
if (GET_BUSADR (da_unit [unitno].flags) != 0) /* booting is supported on bus address 0 only */ static const HP_WORD da_preserved = 0000073u; /* S-register bits 5-3 and 1-0 are preserved */
return SCPE_NOFNC; /* report "Command not allowed" if attempted */ static const HP_WORD da_manual_boot = 0010000u; /* S-register bit 12 set for a manual boot */
cpu_ibl (da_rom, da_dib.select_code, /* copy the boot ROM to memory and configure */ if (dptr == NULL) /* if we are being called for a BOOT/LOAD CPU */
IBL_OPT | IBL_DS_HEAD, /* the S register accordingly */ return cpu_copy_loader (da_loaders, unitno, /* then copy the boot loader to memory */
IBL_DS | IBL_MAN | IBL_SET_SC (da_dib.select_code)); IBL_S_NOCLEAR, IBL_S_NOSET); /* but do not alter the S register */
return SCPE_OK; 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 */
} }

View file

@ -1,6 +1,6 @@
SIMH/HP 21XX DIAGNOSTICS PERFORMANCE SIMH/HP 21XX DIAGNOSTICS PERFORMANCE
==================================== ====================================
Last update: 2017-02-15 Last update: 2018-05-15
The HP 24396 diagnostic suite has been run against the SIMH HP 21xx simulation. The HP 24396 diagnostic suite has been run against the SIMH HP 21xx 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) TESTED DEVICE: LPS (hp2100_lps.c)
CONFIGURATION: sim> set LPS diag CONFIGURATION: sim> set LPS DIAGNOSTIC
sim> deposit S 000014 sim> deposit S 000014
sim> reset sim> reset
sim> go 100 sim> go 100
@ -1096,9 +1096,9 @@ TEST RESULT: Passed.
------------------------------------- -------------------------------------------
DSN 143300 - General Purpose Register DSN 143300 - General Purpose Register (PIF)
------------------------------------- -------------------------------------------
TESTED DEVICE: PIF (hp2100_pif.c) TESTED DEVICE: PIF (hp2100_pif.c)
@ -1136,6 +1136,81 @@ TEST REPORT: GENERAL PURPOSE REGISTER DIAGNOSTIC, DSN 143300
TEST RESULT: Passed. 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.
--------------------------------------------------- ---------------------------------------------------
@ -2128,7 +2203,7 @@ TEST REPORT: H0 7900/7901 CARTRIDGE DISC MEMORY DIAGNOSTIC
HALT instruction 102002 HALT instruction 102002
sim> set DPC0 unloaded sim> set DPC0 unload
sim> go sim> go
H40 PROTECT U/D THEN READY UNIT 0 H40 PROTECT U/D THEN READY UNIT 0
@ -2136,15 +2211,14 @@ TEST REPORT: H0 7900/7901 CARTRIDGE DISC MEMORY DIAGNOSTIC
[CTRL+E] [CTRL+E]
Simulation stopped Simulation stopped
sim> set DPC0 locked sim> set DPC0 load,protect
sim> set DPC0 loaded
sim> go sim> go
H41 CLEAR U/D PROTECT,LOAD,PUSH RUN H41 CLEAR U/D PROTECT,LOAD,PUSH RUN
HALT instruction 102002 HALT instruction 102002
sim> set DPC0 writeenabled sim> set DPC0 unprotect
sim> go sim> go
H71 PRESS PRESET(S) THEN PRESS RUN H71 PRESS PRESET(S) THEN PRESS RUN
@ -3355,8 +3429,8 @@ TESTED DEVICE: IPLI, IPLO (hp2100_ipl.c)
BINARY TAPE: 24197-60001 Rev. B BINARY TAPE: 24197-60001 Rev. B
CONFIGURATION: sim> set IPLI DIAG CONFIGURATION: sim> set IPLI DIAGNOSTIC
sim> set IPLO DIAG sim> set IPLO DIAGNOSTIC
sim> deposit S 003332 sim> deposit S 003332
sim> reset sim> reset
sim> go 2 sim> go 2

View file

@ -1,7 +1,7 @@
/* hp2100_dp.c: HP 2100 12557A/13210A disc simulator /* hp2100_dp.c: HP 2100 12557A/13210A disc simulator
Copyright (c) 1993-2016, Robert M. Supnik 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 Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -27,6 +27,10 @@
DP 12557A 2870 disc subsystem DP 12557A 2870 disc subsystem
13210A 7900 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 03-Aug-17 JDB Changed perror call for I/O errors to cprintf
11-Jul-17 JDB Renamed "ibl_copy" to "cpu_ibl" 11-Jul-17 JDB Renamed "ibl_copy" to "cpu_ibl"
22-Apr-17 JDB Added fall-through comment for FNC_STA case in dpcio 22-Apr-17 JDB Added fall-through comment for FNC_STA case in dpcio
@ -82,7 +86,7 @@
- 7900A Disc Drive Operating and Service Manual - 7900A Disc Drive Operating and Service Manual
(07900-90002, February 1975) (07900-90002, February 1975)
- 13210A Disc Drive Interface Kit Operating and Service Manual - 13210A Disc Drive Interface Kit Operating and Service Manual
(13210-90003, November 1974) (13210-90003, May 1978)
- 12557A Cartridge Disc Interface Kit Operating and Service Manual - 12557A Cartridge Disc Interface Kit Operating and Service Manual
(12557-90001, Sepember 1970) (12557-90001, Sepember 1970)
@ -124,12 +128,103 @@
drive's current position register during a read, i.e., the "on-disc" address drive's current position register during a read, i.e., the "on-disc" address
field is assumed to match the current position. field is assumed to match the current position.
The following implemented behaviors have been inferred from secondary sources NOTE: 13210A manuals dated November 1974 and earlier contain errors in the
(diagnostics, operating system drivers, etc.), due to absent or contradictory schematics. See the comments preceding the "dpcio" routine for details.
authoritative information; future correction may be needed:
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.
*/ */
@ -158,7 +253,13 @@
#define DP_SIZE3 (DP_NUMSF * DP_NUMCY * DP_NUMSC3 * DP_NUMWD) #define DP_SIZE3 (DP_NUMSF * DP_NUMCY * DP_NUMSC3 * DP_NUMWD)
#define DP_NUMDRV 4 /* # drives */ #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_V_FNC 12 /* function */
#define CW_M_FNC 017 #define CW_M_FNC 017
@ -197,35 +298,51 @@
#define DA_CKMASK3 077 #define DA_CKMASK3 077
#define DA_CKMASK (dp_ctype ? DA_CKMASK3 : DA_CKMASK2) #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) */ 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
#define STA_1ST 0040000 /* first status */ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
#define STA_OVR 0020000 /* overrun */ | - | F | O | - | U | P | - | S | - | N | C | A | G | B | D | E | 13210A
#define STA_RWU 0010000 /* rw unsafe NI (u) */ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
#define STA_ACU 0004000 /* access unsafe NI */ | T | F | O | R | U | H | I | S | - | N | C | A | G | B | D | E | 12557A
#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 */ 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) */ /* 0000200 (unused) */
#define STA_NRDY 0000100 /* not ready (d) */ #define STA_NRDY 0000100 /* (N) Not Ready */
#define STA_EOC 0000040 /* end of cylinder */ #define STA_EOC 0000040 /* (C) End of Cylinder */
#define STA_AER 0000020 /* addr error */ #define STA_AER 0000020 /* (A) Address Error */
#define STA_FLG 0000010 /* flagged */ #define STA_FLG 0000010 /* (G) Flagged Cylinder */
#define STA_BSY 0000004 /* seeking */ #define STA_BSY 0000004 /* (B) Drive Busy */
#define STA_DTE 0000002 /* data error */ #define STA_DTE 0000002 /* (D) Data Error */
#define STA_ERR 0000001 /* any error (d) */ #define STA_ERR 0000001 /* (E) Any Error */
#define STA_ERSET2 (STA_1ST | STA_OVR | STA_RWU | STA_ACU | \ #define STA_ERSET2 (STA_1ST | STA_OVR | STA_RWU | STA_ACU | \
STA_SKI | STA_SKE | STA_NRDY | \ STA_SKI | STA_SKE | STA_NRDY | \
STA_EOC | STA_AER | STA_DTE) /* 12557A error set */ STA_EOC | STA_AER | STA_DTE) /* 12557A error set */
#define STA_ERSET3 (STA_ATN | STA_1ST | STA_OVR | STA_RWU | STA_ACU | \ #define STA_ERSET3 (STA_ATN | STA_1ST | STA_OVR | STA_RWU | STA_ACU | \
STA_SKI | STA_SKE | STA_NRDY | STA_EOC | STA_AER | \ STA_SKI | STA_SKE | STA_NRDY | STA_EOC | STA_AER | \
STA_FLG | STA_BSY | STA_DTE) /* 13210A error set */ 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_UNLOADED (dp_ctype ? (STA_NRDY | STA_BSY) : STA_NRDY)
#define STA_MBZ13 (STA_ATN | STA_RWU | STA_SKI) /* zero in 13210 */ #define STA_MBZ13 (STA_ATN | STA_RWU | STA_SKI) /* zero in 13210 */
struct { struct {
@ -329,12 +446,38 @@ MTAB dpd_mod [] = {
{ 0 } { 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 = { DEVICE dpd_dev = {
"DPD", &dpd_unit, dpd_reg, dpd_mod, "DPD", /* device name */
1, 10, DP_N_NUMWD, 1, 8, 16, &dpd_unit, /* unit array */
NULL, NULL, &dpc_reset, dpd_reg, /* register array */
NULL, NULL, NULL, dpd_mod, /* modifier array */
&dpd_dib, DEV_DISABLE 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 /* DPC data structures
@ -405,12 +548,38 @@ MTAB dpc_mod [] = {
{ 0 } { 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 = { DEVICE dpc_dev = {
"DPC", dpc_unit, dpc_reg, dpc_mod, "DPC", /* device name */
DP_NUMDRV, 8, 24, 1, 8, 16, dpc_unit, /* unit array */
NULL, NULL, &dpc_reset, dpc_reg, /* register array */
&dpc_boot, &dpc_attach, &dpc_detach, dpc_mod, /* modifier array */
&dpc_dib, DEV_DISABLE 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 */
}; };
@ -549,6 +718,7 @@ return stat_data;
flip-flops. Only the 12557A has a command flip-flop. IRQ, PRL, and SRQ are flip-flops. Only the 12557A has a command flip-flop. IRQ, PRL, and SRQ are
standard. standard.
Implementation notes: Implementation notes:
1. In hardware, the command channel card passes PRH to PRL. The data card 1. In hardware, the command channel card passes PRH to PRL. The data card
@ -558,6 +728,30 @@ return stat_data;
the command card is interrupting. This works in hardware, but we must 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 break PRL at the command card under simulation to allow the command card
to interrupt. 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) uint32 dpcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
@ -625,6 +819,11 @@ while (working_set) {
if (dp_ctype == A12557) /* 12557? */ if (dp_ctype == A12557) /* 12557? */
dpc.command = CLEAR; /* clear command */ 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; break;
@ -654,6 +853,11 @@ while (working_set) {
drv = CW_GETDRV (dpc_obuf); /* get fnc, drv */ drv = CW_GETDRV (dpc_obuf); /* get fnc, drv */
fnc = CW_GETFNC (dpc_obuf); /* from cmd word */ 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 */ switch (fnc) { /* case on fnc */
case FNC_SEEK: /* seek */ case FNC_SEEK: /* seek */
@ -732,7 +936,7 @@ dpc_eoc = 0; /* clear end cyl */
dpc_busy = drv + 1; /* set busy */ dpc_busy = drv + 1; /* set busy */
dpd_xfer = 1; /* xfer in prog */ dpd_xfer = 1; /* xfer in prog */
dpc_unit[drv].FNC = fnc; /* save function */ 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 */ sim_activate (&dpc_unit[drv], time); /* activate unit */
return; return;
} }
@ -755,6 +959,8 @@ return;
Status check - transfer status, finish operation Status check - transfer status, finish operation
Check data Check data
chk - transfer sector count chk - transfer sector count
The 12557A clears status after a Check Status command. The 13210A does not.
*/ */
t_stat dpd_svc (UNIT *uptr) t_stat dpd_svc (UNIT *uptr)
@ -836,10 +1042,14 @@ switch (uptr->FNC) { /* case function */
dpdio (&dpd_dib, ioENF, 0); /* set dch flg */ dpdio (&dpd_dib, ioENF, 0); /* set dch flg */
} }
dpc_sta[drv] = dpc_sta[drv] & /* clr sta flags */ 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_ATN | STA_1ST | STA_OVR |
STA_RWU | STA_ACU | STA_EOC | STA_RWU | STA_ACU | STA_EOC |
STA_AER | STA_FLG | STA_DTE); STA_AER | STA_FLG | STA_DTE);
dpc_poll = 1; /* enable polling */ dpc_poll = 1; /* enable polling */
for (i = 0; i < DP_NUMDRV; i++) { /* loop thru drives */ for (i = 0; i < DP_NUMDRV; i++) { /* loop thru drives */
if (dpc_sta[i] & STA_ATN) { /* any ATN set? */ if (dpc_sta[i] & STA_ATN) { /* any ATN set? */
@ -1063,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 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 */ result = attach_unit (uptr, cptr); /* attach the drive */
if (r == SCPE_OK) dpc_load_unload (uptr, 0, NULL, NULL);/* if OK, load heads */
return r; 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 */
} }
@ -1140,82 +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 = { The Basic Moving-Head Disc Loader (BMDL) consists of two programs. The
0106710, /*ST CLC DC ; clr dch */ program starting at address x7700 loads absolute paper tapes into memory.
0106711, /* CLC CC ; clr cch */ The program starting at address x7750 loads a disc-resident bootstrap from
0017757, /* JSB STAT ; get status */ the 7900 or 2870 disc drive into memory. The S register setting does not
0067746, /*SK LDB SKCMD ; seek cmd */ affect loader operation.
0106610, /* OTB DC ; cyl # */
0103710, /* STC DC,C ; to dch */ For a 2100/14/15/16 CPU, entering a LOAD DPC or BOOT DPC command loads the
0106611, /* OTB CC ; seek cmd */ BMDL into memory and executes the disc portion starting at x7750. The
0103711, /* STC CC,C ; to cch */ bootstrap reads 6144 (for a 7900) or 3072 (for a 2870) words from cylinder 0,
0102310, /* SFS DC ; addr wd ok? */ head 0, sector 0 into memory starting at location 2011 octal. Loader
0027710, /* JMP *-1 ; no, wait */ execution ends with the following instruction:
0006400, /* CLB */
0102501, /* LIA 1 ; read switches */ * JSB 2055,I - the disc read completed.
0002011, /* SLA,RSS ; <0> set? */
0047747, /* ADB BIT9 ; head 2 = removable */ The BMDL configures DMA for an oversize (~32000 word) transfer and expects
0106610, /* OTB DC ; head/sector */ the disc to terminate the operation with End of Cylinder (EOC) status.
0103710, /* STC DC,C ; to dch */
0102311, /* SFS CC ; seek done? */ The HP 1000 uses the 12992F boot loader ROM to bootstrap the 7900 disc. Bit
0027720, /* JMP *-1 ; no, wait */ 0 of the S register determines whether the boot extension is read from
0017757, /* JSB STAT ; get status */ subchannel 0 (the fixed platter) or subchannel 1 (the removable platter).
0067776, /* LDB DMACW ; DMA control */ The loader reads 6144 words from cylinder 0 sector 0 of the specified
0106606, /* OTB 6 */ subchannel into memory starting at location 2011 octal. Loader execution
0067750, /* LDB ADDR1 ; memory addr */ ends with one of the following instructions:
0106602, /* OTB 2 */
0102702, /* STC 2 ; flip DMA ctrl */ * HLT 30 - a drive fault occurred.
0067752, /* LDB CNT ; word count */ * JSB 2055,I - the disc read succeeded.
0106602, /* OTB 2 */
0063745, /* LDB RDCMD ; read cmd */ The loader automatically retries the operations for all disc errors other
0102611, /* OTA CC ; to cch */ than a drive fault.
0103710, /* STC DC,C ; start dch */
0103706, /* STC 6,C ; start DMA */
0103711, /* STC CC,C ; start cch */ Implementation notes:
0102311, /* SFS CC ; done? */
0027737, /* JMP *-1 ; no, wait */ 1. After the BMDL has been loaded into memory, the paper tape portion may be
0017757, /* JSB STAT ; get status */ executed manually by setting the P register to the starting address
0027775, /* JMP XT ; done */ (x7700).
0037766, /*FSMSK 037766 ; status mask */
0004000, /*STMSK 004000 ; unsafe mask */ 2. For compatibility with the "cpu_copy_loader" routine, the BMDL device I/O
0020000, /*RDCMD 020000 ; read cmd */ instructions address select codes 10 and 11.
0030000, /*SKCMD 030000 ; seek cmd */
0001000, /*BIT9 001000 ; head 2 select */ 3. As published, the BMDL is configured to read from head 0 (the removable
0102011, /*ADDR1 102011 */ platter, a.k.a. subchannel 1). To read from head 2 (the fixed platter,
0102055, /*ADDR2 102055 */ subchannel 0), the head/sector control word must be changed.
0164000, /*CNT -6144. */ */
0, 0, 0, 0, /* unused */
0000000, /*STAT 0 */ #define BMDL_SUBCHANNEL_0 031000 /* BMDL control word to address subchannel 0 instead of 1 */
0002400, /* CLA ; status request */
0102611, /* OTC CC ; to cch */ static const LOADER_ARRAY dp_loaders = {
0103711, /* STC CC,C ; start cch */ { /* HP 21xx Basic Moving-Head Disc Loader (BMDL-7900) */
0102310, /* SFS DC ; done? */ 050, /* loader starting index */
0027763, /* JMP *-1 */ 077, /* DMA index */
0102510, /* LIA DC ; get status */ 034, /* FWA index */
0013743, /* AND FSMSK ; mask 15,14,3,0 */ { 0002401, /* 77700: PTAPE CLA,RSS Paper Tape start */
0002003, /* SZA,RSS ; drive ready? */ 0063721, /* 77701: LDA 77721 */
0127757, /* JMP STAT,I ; yes */ 0107700, /* 77702: CLC 0,C */
0013744, /* AND STMSK ; fault? */ 0002307, /* 77703: CCE,INA,SZA,RSS */
0002002, /* SZA */ 0102077, /* 77704: HLT 77 */
0102030, /* HLT 30 ; yes */ 0017735, /* 77705: JSB 77735 */
0027700, /* JMP ST ; no, retry */ 0007307, /* 77706: CMB,CCE,INB,SZB,RSS */
0117751, /*XT JSB ADDR2,I ; start program */ 0027702, /* 77707: JMP 77702 */
0120010, /*DMACW 120000+DC */ 0077733, /* 77710: STB 77733 */
0000000 /* -ST */ 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) 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 */ if (dptr == NULL) /* if we are being called for a BOOT/LOAD CPU */
return SCPE_NOFNC; /* report "Command not allowed" if attempted */ 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 */
cpu_ibl (dp_rom, dev, IBL_OPT, /* copy the boot ROM to memory and configure */ else if (unitno != 0) /* otherwise a BOOT DPC for a non-zero unit */
IBL_DP | IBL_SET_SC (dev) /* the S register accordingly */ return SCPE_NOFNC; /* is rejected as unsupported */
| (sim_switches & SWMASK ('R') ? IBL_DP_REM : 0));
return SCPE_OK; 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,7 +1,7 @@
/* hp2100_dq.c: HP 2100 12565A Disc Interface and 2883 disc drive simulator /* hp2100_dq.c: HP 2100 12565A Disc Interface and 2883 disc drive simulator
Copyright (c) 1993-2006, Bill McDermith Copyright (c) 1993-2006, Bill McDermith
Copyright (c) 2004-2017, J. David Bryan Copyright (c) 2004-2018, J. David Bryan
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -26,6 +26,8 @@
DQ 12565A Disc Interface and 2883 disc drive 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 03-Aug-17 JDB Changed perror call for I/O errors to cprintf
11-Jul-17 JDB Renamed "ibl_copy" to "cpu_ibl" 11-Jul-17 JDB Renamed "ibl_copy" to "cpu_ibl"
09-Mar-17 JDB Deprecated LOCKED/WRITEENABLED for PROTECT/UNPROTECT 09-Mar-17 JDB Deprecated LOCKED/WRITEENABLED for PROTECT/UNPROTECT
@ -885,15 +887,43 @@ for (drv = 0; drv < DQ_NUMDRV; drv++) { /* loop thru drives */
return SCPE_OK; 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 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 */ result = attach_unit (uptr, cptr); /* attach the drive */
if (r == SCPE_OK) dqc_load_unload (uptr, 0, NULL, NULL);/* if OK, load heads */
return r; 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 */ /* Detach routine */
@ -915,84 +945,227 @@ else uptr->flags = uptr->flags & ~UNIT_UNLOAD; /* indicate load */
return SCPE_OK; return SCPE_OK;
} }
/* 7900/7901/2883/2884 bootstrap routine (HP 12992A ROM) */
const BOOT_ROM dq_rom = { /* 2883 disc bootstrap loaders (BMDL and 12992A).
0102501, /*ST LIA 1 ; get switches */
0106501, /* LIB 1 */ The Basic Moving-Head Disc Loader (BMDL) consists of two programs. The
0013765, /* AND D7 ; isolate hd */ program starting at address x7700 loads absolute paper tapes into memory.
0005750, /* BLF,CLE,SLB */ The program starting at address x7750 loads a disc-resident bootstrap from
0027741, /* JMP RD */ the 2883 disc drive into memory. The S register setting does not affect
0005335, /* RBR,SLB,ERB ; <13>->E, set = 2883 */ loader operation.
0027717, /* JMP IS */
0102611, /*LP OTA CC ; do 7900 status to */ For a 2100/14/15/16 CPU, entering a LOAD DQC or BOOT DQC command loads the
0103711, /* STC CC,C ; clear first seek */ BMDL into memory and executes the disc portion starting at x7750. For a 1000
0102310, /* SFS DC */ CPU, the 12992A boot loader ROM is used. In either case, the bootstrap reads
0027711, /* JMP *-1 */ 128 words from cylinder 0, head 0, sector 0 into memory starting at location
0002004, /* INA ; get next drive */ 2011 octal. Loader execution ends with the following instruction:
0053765, /* CPA D7 ; all cleared? */
0002001, /* RSS */ * JMP 2055,I - the disc read completed.
0027707, /* JMP LP */
0067761, /*IS LDB SEEKC ; get seek comnd */ Note that the BMDL does a JMP 2055,I and the 12992A does a JSB 2055,I.
0106610, /* OTB DC ; issue cyl addr (0) */ */
0103710, /* STC DC,C ; to dch */
0106611, /* OTB CC ; seek cmd */ static const LOADER_ARRAY dq_loaders = {
0103711, /* STC CC,C ; to cch */ { /* HP 21xx Basic Moving-Head Disc Loader (BMDL-2883) */
0102310, /* SFS DC ; addr wd ok? */ 050, /* loader starting index */
0027724, /* JMP *-1 ; no, wait */ 076, /* DMA index */
0006400, /* CLB */ 077, /* FWA index */
0102501, /* LIA 1 ; get switches */ { 0002701, /* 77700: PTAPE CLA,CCE,RSS Paper Tape start */
0002051, /* SEZ,SLA,RSS ; subchan = 1 or ISS */ 0063722, /* 77701: LDA 77722 */
0047770, /* ADB BIT9 ; head 2 */ 0002307, /* 77702: CCE,INA,SZA,RSS */
0106610, /* OTB DC ; head/sector */ 0102077, /* 77703: HLT 77 */
0103710, /* STC DC,C ; to dch */ 0017735, /* 77704: JSB 77735 */
0102311, /* SFS CC ; seek done? */ 0007307, /* 77705: CMB,CCE,INB,SZB,RSS */
0027734, /* JMP *-1 ; no, wait */ 0027702, /* 77706: JMP 77702 */
0063731, /* LDA ISSRD ; get read read */ 0077733, /* 77707: STB 77733 */
0002341, /* SEZ,CCE,RSS ; iss disc? */ 0017735, /* 77710: JSB 77735 */
0001100, /* ARS ; no, make 7900 read */ 0017735, /* 77711: JSB 77735 */
0067776, /*RD LDB DMACW ; DMA control */ 0074000, /* 77712: STB 0 */
0106606, /* OTB 6 */ 0077734, /* 77713: STB 77734 */
0067762, /* LDB ADDR1 ; memory addr */ 0067734, /* 77714: LDB 77734 */
0077741, /* STB RD ; make non re-executable */ 0047777, /* 77715: ADB 77777 */
0106602, /* OTB 2 */ 0002040, /* 77716: SEZ */
0102702, /* STC 2 ; flip DMA ctrl */ 0102055, /* 77717: HLT 55 */
0067764, /* LDB COUNT ; word count */ 0017735, /* 77720: JSB 77735 */
0106602, /* OTB 2 */ 0040001, /* 77721: ADA 1 */
0002041, /* SEZ,RSS */ 0177734, /* 77722: STB 77734,I */
0027766, /* JMP NW */ 0037734, /* 77723: ISZ 77734 */
0102611, /* OTA CC ; to cch */ 0000040, /* 77724: CLE */
0103710, /* STC DC,C ; start dch */ 0037733, /* 77725: ISZ 77733 */
0103706, /* STC 6,C ; start DMA */ 0027714, /* 77726: JMP 77714 */
0103711, /* STC CC,C ; start cch */ 0017735, /* 77727: JSB 77735 */
0037773, /* ISZ SK */ 0054000, /* 77730: CPB 0 */
0027773, /* JMP SK */ 0027701, /* 77731: JMP 77701 */
0030000, /*SEEKC 030000 */ 0102011, /* 77732: HLT 11 */
0102011, /*ADDR1 102011 */ 0000000, /* 77733: NOP */
0102055, /*ADDR2 102055 */ 0000000, /* 77734: NOP */
0164000, /*COUNT -6144. */ 0000000, /* 77735: NOP */
0000007, /*D7 7 */ 0006600, /* 77736: CLB,CME */
0106710, /*NW CLC DC ; set 'next wd is cmd' flag */ 0103710, /* 77737: STC 10,C */
0001720, /* ALF,ALF ; move to head number loc */ 0102310, /* 77740: SFS 10 */
0001000, /*BIT9 ALS */ 0027740, /* 77741: JMP 77740 */
0103610, /* OTA DC,C ; output cold load cmd */ 0106410, /* 77742: MIB 10 */
0103706, /* STC 6,C ; start DMA */ 0002041, /* 77743: SEZ,RSS */
0102310, /* SFS DC ; done? */ 0127735, /* 77744: JMP 77735,I */
0027773, /* JMP *-1 ; no, wait */ 0005767, /* 77745: BLF,CLE,BLF */
0117763, /*XT JSB ADDR2,I ; start program */ 0027737, /* 77746: JMP 77737 */
0120010, /*DMACW 120000+DC */ 0177600, /* 77747: OCT 177600 */
0000000 /* -ST */ 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) 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 */ if (dptr == NULL) /* if we are being called for a BOOT/LOAD CPU */
return SCPE_NOFNC; /* report "Command not allowed" if attempted */ 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 */
cpu_ibl (dq_rom, dev, IBL_OPT, /* copy the boot ROM to memory and configure */ else if (unitno != 0) /* otherwise a BOOT DQC for a non-zero unit */
IBL_DQ | IBL_SET_SC (dev)); /* the S register accordingly */ return SCPE_NOFNC; /* is rejected as unsupported */
return SCPE_OK; 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,7 +1,7 @@
/* hp2100_dr.c: HP 2100 12606B/12610B fixed head disk/drum simulator /* hp2100_dr.c: HP 2100 12606B/12610B fixed head disk/drum simulator
Copyright (c) 1993-2016, Robert M. Supnik 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 Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -27,6 +27,8 @@
DR 12606B 2770/2771 fixed head disk DR 12606B 2770/2771 fixed head disk
12610B 2773/2774/2775 drum 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 19-Jul-17 JDB Removed "dr_stopioe" variable and register
11-Jul-17 JDB Renamed "ibl_copy" to "cpu_ibl" 11-Jul-17 JDB Renamed "ibl_copy" to "cpu_ibl"
27-Feb-17 JDB ibl_copy no longer returns a status code 27-Feb-17 JDB ibl_copy no longer returns a status code
@ -637,15 +639,29 @@ sim_cancel (&drd_unit[TMR_INH]);
return SCPE_OK; 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) 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; if (sz == 0)
return SCPE_IERR;
else
uptr->capac = sz; uptr->capac = sz;
return attach_unit (uptr, cptr);
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 */ /* Set protected track count */
@ -712,125 +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 starting at address x7700 loads absolute paper tapes into memory. The
program starting at address x7760 loads a disc-resident bootstrap from 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 277x fixed-head disc/drum into memory. The S register setting does not
memory and executes the disc portion starting at x7760. The bootstrap issues affect loader operation.
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 Entering a LOAD DRC or BOOT DRC command loads the BBDL into memory and
then stores a JMP * instruction in location 77, starts the read, and jumps to 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 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 disc extension overlays location 77 which, typically, would be a JMP
the start of the disc-resident bootstrap. 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 The HP 1000 does not support the 277x drives, so there is no 1000 boot loader
select codes when it was installed on a given system. Under simulation, we ROM for these peripherals. Attempting to LOAD DRC or BOOT DRC while the CPU
treat it as a standard HP 1000 loader, even though it is not structured that is configured as a 1000 will be rejected.
way, and so the cpu_ibl mechanism used to load and configure it must be
augmented to account for the differences.
Implementaion notes: Implementation notes:
1. The full BBDL is loaded into memory, even though only the disc portion 1. After the BBDL is loaded into memory, the paper tape portion may be
will be used. executed manually by setting the P register to the starting address
(x7700).
2. For compatibility with the cpu_ibl routine, the loader has been changed 2. For compatibility with the cpu_copy_loader routine, the BBDL has been
from the standard HP version. The device I/O instructions are modified altered from the standard HP version. The device I/O instructions are
to address locations 10 and 11. 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 = { static const LOADER_ARRAY dr_loaders = {
0107700, /* ST2 CLC 0,C START OF PAPER TAPE LOADER */ { /* HP 21xx Basic Binary Disc Loader (BBDL) */
0002401, /* CLA,RSS */ 060, /* loader starting index */
0063726, /* CONT2 LDA CM21 */ 056, /* DMA index */
0006700, /* CLB,CCE */ 055, /* FWA index */
0017742, /* JSB READ2 */ { 0107700, /* 77700: ST2 CLC 0,C START OF PAPER TAPE LOADER */
0007306, /* LEDR2 CMB,CCE,INB,SZB */ 0002401, /* 77701: CLA,RSS */
0027713, /* JMP RECL2 */ 0063726, /* 77702: CONT2 LDA CM21 */
0002006, /* EOTC2 INA,SZA */ 0006700, /* 77703: CLB,CCE */
0027703, /* JMP CONT2+1 */ 0017742, /* 77704: JSB READ2 */
0102077, /* HLT 77B */ 0007306, /* 77705: LEDR2 CMB,CCE,INB,SZB */
0027700, /* JMP ST2 */ 0027713, /* 77706: JMP RECL2 */
0077754, /* RECL2 STB CNT2 */ 0002006, /* 77707: EOTC2 INA,SZA */
0017742, /* JSB READ2 */ 0027703, /* 77710: JMP CONT2+1 */
0017742, /* JSB READ2 */ 0102077, /* 77711: HLT 77B */
0074000, /* STB A */ 0027700, /* 77712: JMP ST2 */
0077757, /* STB ADR11 */ 0077754, /* 77713: RECL2 STB CNT2 */
0067757, /* SUCID LDB ADR11 */ 0017742, /* 77714: JSB READ2 */
0047755, /* ADB MAXAD */ 0017742, /* 77715: JSB READ2 */
0002040, /* SEZ */ 0074000, /* 77716: STB A */
0027740, /* JMP RESCU */ 0077757, /* 77717: STB ADR11 */
0017742, /* LOAD2 JSB READ2 */ 0067757, /* 77720: SUCID LDB ADR11 */
0040001, /* ADA B */ 0047755, /* 77721: ADB MAXAD */
0177757, /* CM21 STB ADR11,I */ 0002040, /* 77722: SEZ */
0037757, /* ISZ ADR11 */ 0027740, /* 77723: JMP RESCU */
0000040, /* CLE */ 0017742, /* 77724: LOAD2 JSB READ2 */
0037754, /* ISZ CNT2 */ 0040001, /* 77725: ADA B */
0027720, /* JMP SUCID */ 0177757, /* 77726: CM21 STB ADR11,I */
0017742, /* JSB READ2 */ 0037757, /* 77727: ISZ ADR11 */
0054000, /* CPB A */ 0000040, /* 77730: CLE */
0027702, /* JMP CONT2 */ 0037754, /* 77731: ISZ CNT2 */
0102011, /* HLT 11B */ 0027720, /* 77732: JMP SUCID */
0027700, /* JMP ST2 */ 0017742, /* 77733: JSB READ2 */
0102055, /* RESCU HLT 55B */ 0054000, /* 77734: CPB A */
0027700, /* JMP ST2 */ 0027702, /* 77735: JMP CONT2 */
0000000, /* READ2 NOP */ 0102011, /* 77736: HLT 11B */
0006600, /* CLB,CME */ 0027700, /* 77737: JMP ST2 */
0103710, /* RED2 STC PR,C */ 0102055, /* 77740: RESCU HLT 55B */
0102310, /* SFS PR */ 0027700, /* 77741: JMP ST2 */
0027745, /* JMP *-1 */ 0000000, /* 77742: READ2 NOP */
0107410, /* MIB PR,C */ 0006600, /* 77743: CLB,CME */
0002041, /* SEZ,RSS */ 0103710, /* 77744: RED2 STC PR,C */
0127742, /* JMP READ2,I */ 0102310, /* 77745: SFS PR */
0005767, /* BLF,CLE,BLF */ 0027745, /* 77746: JMP *-1 */
0027744, /* JMP RED2 */ 0107410, /* 77747: MIB PR,C */
0000000, /* CNT2 NOP */ 0002041, /* 77750: SEZ,RSS */
0000000, /* MAXAD NOP */ 0127742, /* 77751: JMP READ2,I */
0020000, /* CWORD ABS 20000B+DC */ 0005767, /* 77752: BLF,CLE,BLF */
0000000, /* ADR11 NOP */ 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 */ { /* HP 1000 Loader ROM does not exist */
0063756, /* LDA CWORD */ IBL_NA, /* loader starting index */
0102606, /* OTA 6 */ IBL_NA, /* DMA index */
0002700, /* CLA,CCE */ IBL_NA, /* FWA index */
0102611, /* OTA CC */ { 0 } }
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 */
}; };
#define BBDL_MAX_ADDR 0000055 /* ROM index of the maximum address word */
#define BBDL_DMA_CNTL 0000056 /* ROM index of the DMA control word */ /* Device boot routine.
#define BBDL_DISC_START 0000060 /* ROM index of the disc loader */
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) t_stat drc_boot (int32 unitno, DEVICE *dptr)
{ {
const HP_WORD dev = (HP_WORD) 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 */ else /* otherwise this is a BOOT/LOAD DRC */
return SCPE_NOFNC; /* report "Command not allowed" if attempted */ 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 */
cpu_ibl (dr_rom, dev, IBL_S_NOCLR, IBL_S_NOSET); /* copy the boot ROM to memory and configure */
mem_deposit (PR + BBDL_MAX_ADDR, mem_examine (PR + IBL_END)); /* move the maximum address word */
mem_deposit (PR + BBDL_DMA_CNTL, (HP_WORD) dr_rom [BBDL_DMA_CNTL] + dev); /* set up the DMA control word */
mem_deposit (PR + IBL_DPC, (HP_WORD) dr_rom [IBL_DPC]); /* restore the overwritten word */
mem_deposit (PR + IBL_END, (HP_WORD) dr_rom [IBL_END]); /* restore the overwritten word */
PR = PR + BBDL_DISC_START; /* select the starting address */
return SCPE_OK;
} }

View file

@ -1,7 +1,7 @@
/* hp2100_ds.c: HP 13037D/13175D disc controller/interface simulator /* hp2100_ds.c: HP 13037D/13175D disc controller/interface simulator
Copyright (c) 2004-2012, Robert M. Supnik Copyright (c) 2004-2012, Robert M. Supnik
Copyright (c) 2012-2017 J. David Bryan Copyright (c) 2012-2018 J. David Bryan
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@ -26,6 +26,9 @@
DS 13037D/13175D disc controller/interface 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" 11-Jul-17 JDB Renamed "ibl_copy" to "cpu_ibl"
15-Mar-17 JDB Trace flags are now global 15-Mar-17 JDB Trace flags are now global
Changed DEBUG_PRI calls to tprintfs Changed DEBUG_PRI calls to tprintfs
@ -436,7 +439,6 @@ static const char * const output_state [] = { "Data", "Command" };
const char * const hold_or_clear = (signal_set & ioCLF ? ",C" : ""); const char * const hold_or_clear = (signal_set & ioCLF ? ",C" : "");
uint16 data; uint16 data;
t_stat status;
IOSIGNAL signal; IOSIGNAL signal;
IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
t_bool command_issued = FALSE; t_bool command_issued = FALSE;
@ -542,10 +544,8 @@ while (working_set) {
if (PRESET_ENABLE) { /* is preset enabled for this interface? */ if (PRESET_ENABLE) { /* is preset enabled for this interface? */
fifo_clear (); /* clear the FIFO */ fifo_clear (); /* clear the FIFO */
status = dl_clear_controller (&mac_cntlr, /* do a hard clear of the controller */ dl_clear_controller (&mac_cntlr, ds_unit, /* do a hard clear of the controller */
ds_unit, hard_clear); hard_clear);
stat_data = IORETURN (status, 0); /* return the status from the controller */
} }
break; break;
@ -1015,23 +1015,43 @@ return SCPE_OK;
Attention bits in the drive status, so we poll the drives to ensure that the Attention bits in the drive status, so we poll the drives to ensure that the
CPU is notified that the drive is now online. 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: Implementation notes:
1. If we are called during a RESTORE command, the drive status will not be 1. If we are called during a RESTORE command, the drive status will not be
changed, so polling the drives will have no effect. 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 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 */ result = dl_attach (&mac_cntlr, uptr, cptr); /* attach the drive */
if (result == SCPE_OK) /* was the attach successful? */ if (result == SCPE_OK) { /* if the attach was successful */
poll_drives (); /* poll the drives to notify the CPU */ 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 */
} }
@ -1056,115 +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 The Basic Moving-Head Disc Loader (BMDL) consists of two programs. The
into memory, the I/O instructions are configured for the interface card's program starting at address x7700 loads absolute paper tapes into memory.
select code, and the program is run to boot from the specified unit. The The program starting at address x7750 loads a disc-resident bootstrap from
loader supports booting from cylinder 0 of drive unit 0 only. Before the MAC disc drive into memory. The S register specifies the head to use.
execution, the S register is automatically set as follows:
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 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
ROM # 0 1 select code reserved head 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. * HLT 11B - the disc read failed.
Bits 5-3 and 1-0 retain their original values, so S should be set before * JSB 2055,I - the disc read completed.
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 The HP 1000 uses the 12992B boot loader ROM to bootstrap the disc. The head
than 0 is desired. 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: Implementation notes:
1. The Loader ROMs manual indicates that bits 2-0 select the head to use, 1. After the BMDL has been loaded into memory, the paper tape portion may be
implying that heads 0-7 are valid. However, Table 5 has entries only for executed manually by setting the P register to the starting address
heads 0-3, and the boot loader code will malfunction if heads 4-7 are (x7700).
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. 2. For compatibility with the "cpu_copy_loader" routine, the BMDL device I/O
As the head field in the command is only two bits wide, specifying heads instructions address select codes 10 and 11.
4-7 will result in bit 2 being shifted into the opcode field, resulting
in a Recalibrate command.
*/ */
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 = { { /* HP 1000 Loader ROM (12992B) */
0017727, /* START JSB STAT GET STATUS */ IBL_START, /* loader starting index */
0002021, /* SSA,RSS IS DRIVE READY ? */ IBL_DMA, /* DMA index */
0027742, /* JMP DMA YES, SET UP DMA */ IBL_FWA, /* FWA index */
0013714, /* AND B20 NO, CHECK STATUS BITS */ { 0017727, /* 77700: START JSB STAT GET STATUS */
0002002, /* SZA IS DRIVE FAULTY OR HARD DOWN ? */ 0002021, /* 77701: SSA,RSS IS DRIVE READY ? */
0102030, /* HLT 30B YES, HALT 30B, "RUN" TO TRY AGAIN */ 0027742, /* 77702: JMP DMA YES, SET UP DMA */
0027700, /* JMP START NO, TRY AGAIN FOR DISC READY */ 0013714, /* 77703: AND B20 NO, CHECK STATUS BITS */
0102011, /* ADDR1 OCT 102011 */ 0002002, /* 77704: SZA IS DRIVE FAULTY OR HARD DOWN ? */
0102055, /* ADDR2 OCT 102055 */ 0102030, /* 77705: HLT 30B YES, HALT 30B, "RUN" TO TRY AGAIN */
0164000, /* CNT DEC -6144 */ 0027700, /* 77706: JMP START NO, TRY AGAIN FOR DISC READY */
0000007, /* D7 OCT 7 */ 0102011, /* 77707: ADDR1 OCT 102011 */
0001400, /* STCMD OCT 1400 */ 0102055, /* 77710: ADDR2 OCT 102055 */
0000020, /* B20 OCT 20 */ 0164000, /* 77711: CNT DEC -6144 */
0017400, /* STMSK OCT 17400 */ 0000007, /* 77712: D7 OCT 7 */
0000000, /* NOP */ 0001400, /* 77713: STCMD OCT 1400 */
0000000, /* NOP */ 0000020, /* 77714: B20 OCT 20 */
0000000, /* NOP */ 0017400, /* 77715: STMSK OCT 17400 */
0000000, /* NOP */ 0000000, /* 77716: NOP */
0000000, /* NOP */ 0000000, /* 77717: NOP */
0000000, /* NOP */ 0000000, /* 77720: NOP */
0000000, /* NOP */ 0000000, /* 77721: NOP */
0000000, /* NOP */ 0000000, /* 77722: NOP */
0000000, /* NOP */ 0000000, /* 77723: NOP */
0000000, /* STAT NOP STATUS CHECK SUBROUTINE */ 0000000, /* 77724: NOP */
0107710, /* CLC DC,C SET STATUS COMMAND MODE */ 0000000, /* 77725: NOP */
0063713, /* LDA STCMD GET STATUS COMMAND */ 0000000, /* 77726: NOP */
0102610, /* OTA DC OUTPUT STATUS COMMAND */ 0000000, /* 77727: STAT NOP STATUS CHECK SUBROUTINE */
0102310, /* SFS DC WAIT FOR STATUS#1 WORD */ 0107710, /* 77730: CLC DC,C SET STATUS COMMAND MODE */
0027733, /* JMP *-1 */ 0063713, /* 77731: LDA STCMD GET STATUS COMMAND */
0107510, /* LIB DC,C B-REG = STATUS#1 WORD */ 0102610, /* 77732: OTA DC OUTPUT STATUS COMMAND */
0102310, /* SFS DC WAIT FOR STATUS#2 WORD */ 0102310, /* 77733: SFS DC WAIT FOR STATUS#1 WORD */
0027736, /* JMP *-1 */ 0027733, /* 77734: JMP *-1 */
0103510, /* LIA DC,C A-REG = STATUS#2 WORD */ 0107510, /* 77735: LIB DC,C B-REG = STATUS#1 WORD */
0127727, /* JMP STAT,I RETURN */ 0102310, /* 77736: SFS DC WAIT FOR STATUS#2 WORD */
0067776, /* DMA LDB DMACW GET DMA CONTROL WORD */ 0027736, /* 77737: JMP *-1 */
0106606, /* OTB 6 OUTPUT DMA CONTROL WORD */ 0103510, /* 77740: LIA DC,C A-REG = STATUS#2 WORD */
0067707, /* LDB ADDR1 GET MEMORY ADDRESS */ 0127727, /* 77741: JMP STAT,I RETURN */
0106702, /* CLC 2 SET MEMORY ADDRESS INPUT MODE */ 0067776, /* 77742: DMA LDB DMACW GET DMA CONTROL WORD */
0106602, /* OTB 2 OUTPUT MEMORY ADDRESS TO DMA */ 0106606, /* 77743: OTB 6 OUTPUT DMA CONTROL WORD */
0102702, /* STC 2 SET WORD COUNT INPUT MODE */ 0067707, /* 77744: LDB ADDR1 GET MEMORY ADDRESS */
0067711, /* LDB CNT GET WORD COUNT */ 0106702, /* 77745: CLC 2 SET MEMORY ADDRESS INPUT MODE */
0106602, /* OTB 2 OUTPUT WORD COUNT TO DMA */ 0106602, /* 77746: OTB 2 OUTPUT MEMORY ADDRESS TO DMA */
0106710, /* CLDLD CLC DC SET COMMAND INPUT MODE */ 0102702, /* 77747: STC 2 SET WORD COUNT INPUT MODE */
0102501, /* LIA 1 LOAD SWITCH */ 0067711, /* 77750: LDB CNT GET WORD COUNT */
0106501, /* LIB 1 REGISTER SETTINGS */ 0106602, /* 77751: OTB 2 OUTPUT WORD COUNT TO DMA */
0013712, /* AND D7 ISOLATE HEAD NUMBER */ 0106710, /* 77752: CLDLD CLC DC SET COMMAND INPUT MODE */
0005750, /* BLF,CLE,SLB BIT 12=0? */ 0102501, /* 77753: LIA 1 LOAD SWITCH */
0027762, /* JMP *+3 NO,MANUAL BOOT */ 0106501, /* 77754: LIB 1 REGISTER SETTINGS */
0002002, /* SZA YES,RPL BOOT. HEAD#=0? */ 0013712, /* 77755: AND D7 ISOLATE HEAD NUMBER */
0001000, /* ALS NO,HEAD#1, MAKE HEAD#=2 */ 0005750, /* 77756: BLF,CLE,SLB BIT 12=0? */
0001720, /* ALF,ALS FORM COLD LOAD */ 0027762, /* 77757: JMP *+3 NO,MANUAL BOOT */
0001000, /* ALS COMMAND WORD */ 0002002, /* 77760: SZA YES,RPL BOOT. HEAD#=0? */
0103706, /* STC 6,C ACTIVATE DMA */ 0001000, /* 77761: ALS NO,HEAD#1, MAKE HEAD#=2 */
0103610, /* OTA DC,C OUTPUT COLD LOAD COMMAND */ 0001720, /* 77762: ALF,ALS FORM COLD LOAD */
0102310, /* SFS DC IS COLD LOAD COMPLETED ? */ 0001000, /* 77763: ALS COMMAND WORD */
0027766, /* JMP *-1 NO, WAIT */ 0103706, /* 77764: STC 6,C ACTIVATE DMA */
0017727, /* JSB STAT YES, GET STATUS */ 0103610, /* 77765: OTA DC,C OUTPUT COLD LOAD COMMAND */
0060001, /* LDA 1 */ 0102310, /* 77766: SFS DC IS COLD LOAD COMPLETED ? */
0013715, /* AND STMSK A-REG = STATUS BITS OF STATUS#1 WD */ 0027766, /* 77767: JMP *-1 NO, WAIT */
0002002, /* SZA IS TRANSFER OK ? */ 0017727, /* 77770: JSB STAT YES, GET STATUS */
0027700, /* JMP START NO,TRY AGAIN */ 0060001, /* 77771: LDA 1 */
0117710, /* EXIT JSB ADDR2,I YES, EXEC LOADED PROGRAM _@ 2055B */ 0013715, /* 77772: AND STMSK A-REG = STATUS BITS OF STATUS#1 WD */
0000010, /* DMACW ABS DC */ 0002002, /* 77773: SZA IS TRANSFER OK ? */
0170100, /* ABS -START */ 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) t_stat ds_boot (int32 unitno, DEVICE *dptr)
{ {
if (unitno != 0) /* boot supported on drive unit 0 only */ static const HP_WORD ds_preserved = 0000073u; /* S-register bits 5-3 and 1-0 are preserved */
return SCPE_NOFNC; /* report "Command not allowed" if attempted */ static const HP_WORD ds_manual_boot = 0010000u; /* S-register bit 12 set for a manual boot */
cpu_ibl (ds_rom, ds_dib.select_code, /* copy the boot ROM to memory and configure */ if (dptr == NULL) /* if we are being called for a BOOT/LOAD CPU */
IBL_OPT | IBL_DS_HEAD, /* the S register accordingly */ return cpu_copy_loader (ds_loaders, unitno, /* then copy the boot loader to memory */
IBL_DS | IBL_MAN | IBL_SET_SC (ds_dib.select_code)); IBL_S_NOCLEAR, IBL_S_NOSET); /* but do not alter the S register */
return SCPE_OK; 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 */
} }

View file

@ -1,6 +1,6 @@
/* hp2100_fp1.c: HP 1000 multiple-precision floating point routines /* 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 Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), 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 in advertising or otherwise to promote the sale, use or other dealings in
this Software without prior written authorization from the author. 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 16-May-16 JDB Reformulated the definitions of op_mask
24-Dec-14 JDB Added casts for explicit downward conversions 24-Dec-14 JDB Added casts for explicit downward conversions
Changed fp_ucom return from uint32 to uint16 Changed fp_ucom return from uint32 to uint16
@ -480,7 +481,7 @@ int32 i;
OP packed; OP packed;
if (precision == in_s) 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) else if (precision == in_d)
packed.dword = (uint32) (unpacked >> 32) & DMASK32; /* pack double integer */ packed.dword = (uint32) (unpacked >> 32) & DMASK32; /* pack double integer */
@ -490,7 +491,7 @@ else {
precision = fp_t; /* only four mantissa words */ precision = fp_t; /* only four mantissa words */
for (i = 3; i >= 0; i--) { /* pack fp 2 to 4 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; unpacked = unpacked >> 16;
} }
} }
@ -530,7 +531,7 @@ switch (unpacked.precision) { /* merge exponent into c
break; break;
case fp_e: /* place in separate word */ case fp_e: /* place in separate word */
packed.fpk[4] = (uint16) (unpacked.exponent << FP_V_EXP | packed.fpk[4] = (HP_WORD) (unpacked.exponent << FP_V_EXP |
(unpacked.exponent < 0) << FP_V_ESIGN); (unpacked.exponent < 0) << FP_V_ESIGN);
break; break;

File diff suppressed because it is too large Load diff

View file

@ -25,6 +25,7 @@
MPX 12792C 8-Channel Asynchronous Multiplexer MPX 12792C 8-Channel Asynchronous Multiplexer
01-Nov-17 JDB Fixed serial output buffer overflow handling
26-Jul-17 JDB Changed BITFIELD macros to field constructors 26-Jul-17 JDB Changed BITFIELD macros to field constructors
22-Apr-17 JDB Corrected missing compound statements 22-Apr-17 JDB Corrected missing compound statements
15-Mar-17 JDB Trace flags are now global 15-Mar-17 JDB Trace flags are now global
@ -73,8 +74,8 @@
character editing, echoing, ENQ/ACK handshaking, and read terminator character editing, echoing, ENQ/ACK handshaking, and read terminator
detection, substantially reducing the load on the CPU over the earlier 12920 detection, substantially reducing the load on the CPU over the earlier 12920
multiplexer. It was supported by HP under RTE-MIII, RTE-IVB, and RTE-6/VM. multiplexer. It was supported by HP under RTE-MIII, RTE-IVB, and RTE-6/VM.
Under simulation, it connects with HP terminal emulators via Telnet to a Under simulation, it connects with HP terminal emulators via Telnet or serial
user-specified port. ports.
The single interface card contained a Z80 CPU, DMA controller, CTC, four The single interface card contained a Z80 CPU, DMA controller, CTC, four
two-channel SIO UARTs, 16K of RAM, 8K of ROM, and I/O backplane latches and two-channel SIO UARTs, 16K of RAM, 8K of ROM, and I/O backplane latches and
@ -246,7 +247,7 @@
#define MPX_CNTLS 2 /* number of control units */ #define MPX_CNTLS 2 /* number of control units */
#define mpx_cntl (mpx_unit [MPX_PORTS + 0]) /* controller unit */ #define mpx_cntl (mpx_unit [MPX_PORTS + 0]) /* controller unit */
#define mpx_poll (mpx_unit [MPX_PORTS + 1]) /* Telnet polling unit */ #define mpx_poll (mpx_unit [MPX_PORTS + 1]) /* polling unit */
/* Character constants */ /* Character constants */
@ -826,7 +827,7 @@ static int32 mpx_iolen = 0; /* length of current I/O xfer */
static t_bool mpx_uien = FALSE; /* unsolicited interrupts enabled */ static t_bool mpx_uien = FALSE; /* unsolicited interrupts enabled */
static uint32 mpx_uicode = 0; /* unsolicited interrupt reason and port */ static uint32 mpx_uicode = 0; /* unsolicited interrupt reason and port */
struct { static struct {
FLIP_FLOP control; /* control flip-flop */ FLIP_FLOP control; /* control flip-flop */
FLIP_FLOP flag; /* flag flip-flop */ FLIP_FLOP flag; /* flag flip-flop */
FLIP_FLOP flagbuf; /* flag buffer flip-flop */ FLIP_FLOP flagbuf; /* flag buffer flip-flop */
@ -955,16 +956,16 @@ static DIB mpx_dib = {
/* Unit list. /* Unit list.
The first eight units correspond to the eight multiplexer line ports. These The first eight units correspond to the eight multiplexer line ports. These
handle character I/O via the Telnet library. A ninth unit acts as the card handle character I/O via the multiplexer library. A ninth unit acts as the
controller, executing commands and transferring data to and from the I/O card controller, executing commands and transferring data to and from the I/O
buffers. A tenth unit is responsible for polling for connections and socket buffers. A tenth unit is responsible for polling for connections and line
I/O. It also holds the master socket. I/O. It also holds the master socket for Telnet connections.
The character I/O service routines run only when there are characters to read The character I/O service routines run only when there are characters to read
or write. They operate at the approximate baud rates of the terminals (in or write. They operate at the approximate baud rates of the terminals (in
CPU instructions per second) in order to be compatible with the OS drivers. CPU instructions per second) in order to be compatible with the OS drivers.
The controller service routine runs only when a command is executing or a The controller service routine runs only when a command is executing or a
data transfer to or from the CPU is in progress. The Telnet poll must run data transfer to or from the CPU is in progress. The poll service must run
continuously, but it may operate much more slowly, as the only requirement is continuously, but it may operate much more slowly, as the only requirement is
that it must not present a perceptible lag to human input. To be compatible that it must not present a perceptible lag to human input. To be compatible
with CPU idling, it is co-scheduled with the master poll timer, which uses a with CPU idling, it is co-scheduled with the master poll timer, which uses a
@ -986,7 +987,7 @@ static UNIT mpx_unit [] = {
{ UDATA (&line_service, UNIT_FASTTIME, 0) }, /* terminal I/O line 6 */ { UDATA (&line_service, UNIT_FASTTIME, 0) }, /* terminal I/O line 6 */
{ UDATA (&line_service, UNIT_FASTTIME, 0) }, /* terminal I/O line 7 */ { UDATA (&line_service, UNIT_FASTTIME, 0) }, /* terminal I/O line 7 */
{ UDATA (&cntl_service, UNIT_DIS, 0) }, /* controller unit */ { UDATA (&cntl_service, UNIT_DIS, 0) }, /* controller unit */
{ UDATA (&poll_service, POLL_FLAGS, 0), POLL_FIRST } /* Telnet poll unit */ { UDATA (&poll_service, POLL_FLAGS, 0), POLL_FIRST } /* poll unit */
}; };
@ -1626,21 +1627,20 @@ return SCPE_OK;
/* Multiplexer line service. /* Multiplexer line service.
The line service routine is used to transmit and receive characters. It is The line service routine is used to transmit and receive characters. It is
started when a buffer is ready for output or when the Telnet poll routine started when a buffer is ready for output or when the poll service routine
determines that there are characters ready for input, and it is stopped when determines that there are characters ready for input, and it is stopped when
there are no more characters to output or input. When a line is quiescent, there are no more characters to output or input. When a line is quiescent,
this routine does not run. Service times are selected to approximate the this routine does not run. Service times are selected to approximate the
baud rate setting of the multiplexer port. baud rate setting of the multiplexer port.
"Fast timing" mode enables three optimizations. First, buffered characters "Fast timing" mode enables three optimizations. First, buffered characters
are transferred via Telnet in blocks, rather than a character at a time; this are transferred in blocks, rather than a character at a time; this reduces
reduces network traffic and decreases simulator overhead (there is only one line traffic and decreases simulator overhead (there is only one service
service routine entry per block, rather than one per character). Second, routine entry per block, rather than one per character). Second, ENQ/ACK
ENQ/ACK handshaking is done locally, without involving the Telnet client. handshaking is done locally, without involving the client. Third, when
Third, when editing and echo is enabled, entering BS echoes a backspace, a editing and echo is enabled, entering BS echoes a backspace, a space, and a
space, and a backspace, and entering DEL echoes a backslash, a carriage backspace, and entering DEL echoes a backslash, a carriage return, and a line
return, and a line feed, providing better compatibility with prior RTE feed, providing better compatibility with prior RTE terminal drivers.
terminal drivers.
Each read and write buffer begins with a reserved header byte that stores Each read and write buffer begins with a reserved header byte that stores
per-buffer information, such as whether handshaking should be suppressed per-buffer information, such as whether handshaking should be suppressed
@ -1654,7 +1654,7 @@ return SCPE_OK;
write buffer is freed, and a UI check is made if the controller is idle, in write buffer is freed, and a UI check is made if the controller is idle, in
case a write buffer request is pending. case a write buffer request is pending.
For input, the character is retrieved from the Telnet buffer. If a BREAK was For input, the character is retrieved from the line buffer. If a BREAK was
received, break status is set, and the character is discarded (the current received, break status is set, and the character is discarded (the current
multiplexer library implementation always returns a NUL with a BREAK multiplexer library implementation always returns a NUL with a BREAK
indication). If the character is an XOFF, and XON/XOFF pacing is enabled, a indication). If the character is an XOFF, and XON/XOFF pacing is enabled, a
@ -1685,6 +1685,59 @@ return SCPE_OK;
service entry. This allows the CPU time to unload the first buffer service entry. This allows the CPU time to unload the first buffer
before the second fills up. Once the first buffer is freed, the routine before the second fills up. Once the first buffer is freed, the routine
shifts back to burst mode to fill the remainder of the second buffer. shifts back to burst mode to fill the remainder of the second buffer.
4. 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.
5. 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.
6. The serial transmit buffer provided by the terminal multiplexer library
is restricted to one character. Therefore, attempting to send several
characters in response to input, e.g., echoing "<BS> <space> <BS>" in
response to receiving a <BS>, will fail with SCPE_STALL. Calling
"tmxr_poll_tx" between characters will not clear the buffer if the line
speed has been set explicitly.
To avoid having to do our own buffering for echoed characters, we call
the "tmxr_linemsg" routine which loops internally until the characters
have been transmitted. This is ugly but is a consequence of the buffer
restriction imposed by the TMXR library.
7. Because ENQ/ACK handshaking is handled entirely on the multiplexer card
with no OS involvement, FASTTIME "local handling" consists simply of
omitting the handshake even if it is configured by the multiplexer.
*/ */
static t_stat line_service (UNIT *uptr) static t_stat line_service (UNIT *uptr)
@ -1700,14 +1753,19 @@ int32 chx;
uint32 buffer_count, write_count; uint32 buffer_count, write_count;
t_stat status = SCPE_OK; t_stat status = SCPE_OK;
t_bool recv_loop = !fast_binary_read; /* bypass if fast binary read */ t_bool recv_loop = !fast_binary_read; /* bypass if fast binary read */
t_bool xmit_loop = !(fast_binary_read || /* bypass if fast read or output suspended */ t_bool xmit_loop = !(fast_binary_read /* bypass if fast read */
(mpx_flags [port] & (FL_WAITACK | FL_XOFF))); || mpx_flags [port] & (FL_WAITACK | FL_XOFF) /* or output suspended */
|| mpx_ldsc [port].xmte == 0); /* or buffer full */
tprintf (mpx_dev, DEB_CMDS, "Port %d service entered\n", port); tprintf (mpx_dev, DEB_CMDS, "Port %d service entered\n", port);
/* Transmission service */ /* Transmission service */
if (mpx_ldsc [port].xmte == 0) /* if the transmit buffer is full */
tprintf (mpx_dev, DEB_XFER, "Port %d transmission stalled for full buffer\n",
port);
write_count = buf_len (iowrite, port, get); /* get the output buffer length */ write_count = buf_len (iowrite, port, get); /* get the output buffer length */
while (xmit_loop && write_count > 0) { /* character available to output? */ while (xmit_loop && write_count > 0) { /* character available to output? */
@ -1723,16 +1781,17 @@ while (xmit_loop && write_count > 0) { /* character available t
continue; /* continue with the first output character */ continue; /* continue with the first output character */
} }
if (mpx_flags [port] & FL_DO_ENQACK) /* do handshake for this buffer? */ if (mpx_enq_cntr [port] >= ENQ_LIMIT) { /* ready for ENQ? */
mpx_enq_cntr [port] = mpx_enq_cntr [port] + 1; /* bump character counter */
if (mpx_enq_cntr [port] > ENQ_LIMIT) { /* ready for ENQ? */
mpx_enq_cntr [port] = 0; /* clear ENQ counter */
mpx_ack_wait [port] = 0; /* clear ACK wait timer */
mpx_flags [port] |= FL_WAITACK; /* set wait for ACK */
ch = ENQ; ch = ENQ;
status = tmxr_putc_ln (&mpx_ldsc [port], ch); /* transmit ENQ */ status = tmxr_putc_ln (&mpx_ldsc [port], ch); /* transmit ENQ */
if (status == SCPE_OK || status == SCPE_LOST) { /* if transmission succeeded or is ignored */
mpx_enq_cntr [port] = 0; /* then clear the ENQ counter */
mpx_ack_wait [port] = 0; /* and the ACK wait timer */
mpx_flags [port] |= FL_WAITACK; /* set wait for ACK */
}
xmit_loop = FALSE; /* stop further transmission */ xmit_loop = FALSE; /* stop further transmission */
} }
@ -1740,17 +1799,32 @@ while (xmit_loop && write_count > 0) { /* character available t
ch = buf_get (iowrite, port) & data_mask; /* get char and mask to bit width */ ch = buf_get (iowrite, port) & data_mask; /* get char and mask to bit width */
status = tmxr_putc_ln (&mpx_ldsc [port], ch); /* transmit the character */ status = tmxr_putc_ln (&mpx_ldsc [port], ch); /* transmit the character */
write_count = write_count - 1; /* count the character */ if (status == SCPE_OK || status == SCPE_LOST) { /* if transmission succeeded or is ignored */
xmit_loop = (status == SCPE_OK) && fast_timing; /* and continue transmission if enabled */ write_count = write_count - 1; /* then count the character */
xmit_loop = (fast_timing /* continue transmission if enabled */
&& mpx_ldsc [port].xmte != 0); /* and buffer space is available */
if (mpx_flags [port] & FL_DO_ENQACK) /* if ENQ/ACK handshaking is enabled */
mpx_enq_cntr [port] += 1; /* then bump the character counter */
} }
if (status != SCPE_OK) /* if the transmission failed */ else /* otherwise transmission failed */
xmit_loop = FALSE; /* then exit the loop */ xmit_loop = FALSE; /* so exit the loop */
}
else if (status == SCPE_OK)
tprintf (mpx_dev, DEB_XFER, "Port %d character %s transmitted\n", tprintf (mpx_dev, DEB_XFER, "Port %d character %s transmitted\n",
port, fmt_char (ch)); port, fmt_char (ch));
else {
tprintf (mpx_dev, DEB_XFER, "Port %d character %s transmission failed with status %d\n",
port, fmt_char (ch), status);
if (status == SCPE_LOST) /* if the line is not connected */
status = SCPE_OK; /* then ignore the output */
}
if (write_count == 0) { /* buffer complete? */ if (write_count == 0) { /* buffer complete? */
buf_free (iowrite, port); /* free buffer */ buf_free (iowrite, port); /* free buffer */
@ -1831,10 +1905,8 @@ while (recv_loop) { /* OK to process? */
if (rt & RT_ENAB_ECHO) { /* echo enabled? */ if (rt & RT_ENAB_ECHO) { /* echo enabled? */
tmxr_putc_ln (&mpx_ldsc [port], BS); /* echo BS */ tmxr_putc_ln (&mpx_ldsc [port], BS); /* echo BS */
if (fast_timing) { /* fast timing mode? */ if (fast_timing) /* fast timing mode? */
tmxr_putc_ln (&mpx_ldsc [port], ' '); /* echo space */ tmxr_linemsg (&mpx_ldsc [port], " \b"); /* echo space and BS */
tmxr_putc_ln (&mpx_ldsc [port], BS); /* echo BS */
}
} }
continue; continue;
@ -1847,8 +1919,7 @@ while (recv_loop) { /* OK to process? */
if (fast_timing) /* fast timing mode? */ if (fast_timing) /* fast timing mode? */
tmxr_putc_ln (&mpx_ldsc [port], '\\'); /* echo backslash */ tmxr_putc_ln (&mpx_ldsc [port], '\\'); /* echo backslash */
tmxr_putc_ln (&mpx_ldsc [port], CR); /* echo CR */ tmxr_linemsg (&mpx_ldsc [port], "\r\n"); /* echo CR and LF */
tmxr_putc_ln (&mpx_ldsc [port], LF); /* and LF */
} }
continue; continue;
@ -1865,7 +1936,8 @@ while (recv_loop) { /* OK to process? */
if ((ch == CR) && (rt & RT_END_ON_CR)) { if ((ch == CR) && (rt & RT_END_ON_CR)) {
if (rt & RT_ENAB_ECHO) /* echo enabled? */ if (rt & RT_ENAB_ECHO) /* echo enabled? */
tmxr_putc_ln (&mpx_ldsc [port], LF); /* send LF */ tmxr_linemsg (&mpx_ldsc [port], "\n"); /* send LF */
mpx_param = RS_ETC_CR; /* set termination condition */ mpx_param = RS_ETC_CR; /* set termination condition */
} }
@ -1981,15 +2053,15 @@ else { /* normal service */
tprintf (mpx_dev, DEB_CMDS, "Port %d service stopped\n", port); tprintf (mpx_dev, DEB_CMDS, "Port %d service stopped\n", port);
} }
return SCPE_OK; return status;
} }
/* Telnet poll service. /* Poll service.
This service routine is used to poll for Telnet connections and incoming This service routine is used to poll for connections and incoming characters.
characters. It starts when the socket is attached and stops when the socket It is started when the listening socket or a serial line is attached and is
is detached. stopped when the socket and all lines are detached.
Each line is then checked for a pending ENQ/ACK handshake. If one is Each line is then checked for a pending ENQ/ACK handshake. If one is
pending, the ACK counter is incremented, and if it times out, another ENQ is pending, the ACK counter is incremented, and if it times out, another ENQ is
@ -2054,10 +2126,10 @@ return SCPE_OK;
1. Under simulation, we also clear the input buffer register, even though 1. Under simulation, we also clear the input buffer register, even though
the hardware doesn't. the hardware doesn't.
2. We set up the first poll for Telnet connections to occur "immediately" 2. We set up the first poll for connections to occur "immediately" upon
upon execution, so that clients will be connected before execution execution, so that clients will be connected before execution begins.
begins. Otherwise, a fast program may access the multiplexer before the Otherwise, a fast program may access the multiplexer before the poll
poll service routine activates. service routine activates.
3. We must set the "emptying_flags" and "filling_flags" values here, because 3. We must set the "emptying_flags" and "filling_flags" values here, because
they cannot be initialized statically, even though the values are they cannot be initialized statically, even though the values are
@ -2079,10 +2151,10 @@ mpx_ibuf = 0; /* clear input buffer */
if (mpx_poll.flags & UNIT_ATT) { /* network attached? */ if (mpx_poll.flags & UNIT_ATT) { /* network attached? */
mpx_poll.wait = POLL_FIRST; /* set up poll */ mpx_poll.wait = POLL_FIRST; /* set up poll */
sim_activate (&mpx_poll, mpx_poll.wait); /* start Telnet poll immediately */ sim_activate (&mpx_poll, mpx_poll.wait); /* start poll immediately */
} }
else else
sim_cancel (&mpx_poll); /* else stop Telnet poll */ sim_cancel (&mpx_poll); /* else stop poll */
return SCPE_OK; return SCPE_OK;
} }
@ -2092,23 +2164,32 @@ return SCPE_OK;
We are called by the ATTACH MPX <port> command to attach the multiplexer to We are called by the ATTACH MPX <port> command to attach the multiplexer to
the listening port indicated by <port>. Logically, it is the multiplexer the listening port indicated by <port>. Logically, it is the multiplexer
device that is attached; however, SIMH only allows units to be attached. device that is attached; however, SIMH only allows units to be attached. This
This makes sense for devices such as tape drives, where the attached media is makes sense for devices such as tape drives, where the attached media is a
a property of a specific drive. In our case, though, the listening port is a property of a specific drive. In our case, though, the listening port is a
property of the multiplexer card, not of any given serial line. As ATTACH property of the multiplexer card, not of any given line. As ATTACH MPX is
MPX is equivalent to ATTACH MPX0, the port would, by default, be attached to equivalent to ATTACH MPX0, the port would, by default, be attached to the
the first serial line and be reported there in a SHOW MPX command. first line and be reported there in a SHOW MPX command.
To preserve the logical picture, we attach the port to the Telnet poll unit, To preserve the logical picture, we attach the listening port to the poll
which is normally disabled to inhibit its display. Attaching to a disabled unit (unit 9), which is normally disabled to inhibit its display. Serial
unit is not allowed, so we first enable the unit, then attach it, then ports are attached to line units 0-7 normally. Attachment is reported by the
disable it again. Attachment is reported by the "show_status" routine below. "show_status" routine below.
A direct attach to the poll unit is only allowed when restoring a previously The connection poll service routine is synchronized with the other input
saved session. polling devices in the simulator to facilitate idling.
The Telnet poll service routine is synchronized with the other input polling
devices in the simulator to facilitate idling. Implementation notes:
1. If we are being called as part of RESTORE processing, we may see a
request to attach the poll unit (unit 9). This will occur if unit 9 was
attached when the SAVE was done. In this case, the SIM_SW_REST flag will
be set in "sim_switches", and we will allow the call to succeed.
2. If the poll unit is attached, it will be enabled as part of RESTORE
processing. We always unilaterally disable this unit to ensure that it
remains hidden.
*/ */
static t_stat mpx_attach (UNIT *uptr, CONST char *cptr) static t_stat mpx_attach (UNIT *uptr, CONST char *cptr)
@ -2133,15 +2214,21 @@ return status;
/* Detach the multiplexer. /* Detach the multiplexer.
Normally, we are called by the DETACH MPX command, which is equivalent to We are called by the DETACH MPX command to detach the listening port and all
DETACH MPX0. However, we may be called with other units in two cases. Telnet sessions. We will also be called by DETACH ALL, RESTORE, and during
simulator shutdown. For DETACH ALL and RESTORE, we must not fail the call,
or processing of other units will cease.
A DETACH ALL command will call us for unit 9 (the poll unit) if it is
attached. Also, during simulator shutdown, we will be called for units 0-8 Implementation notes:
(detach_all in scp.c calls the detach routines of all units that do NOT have
UNIT_ATTABLE), as well as for unit 9 if it is attached. In both cases, it is 1. During simulator shutdown, we will be called for units 0-8 (detach_all in
imperative that we return SCPE_OK, otherwise any remaining device detaches scp.c calls the detach routines of all units that do NOT have
will not be performed. UNIT_ATTABLE), as well as for unit 9 if it is attached.
2. We cannot fail a direct DETACH MPX9 (poll unit), because we cannot tell
that case apart from a DETACH ALL (a RESTORE will have the SIM_SW_REST
flag set in "sim_switches").
*/ */
static t_stat mpx_detach (UNIT *uptr) static t_stat mpx_detach (UNIT *uptr)
@ -2157,7 +2244,7 @@ if ((uptr == mpx_unit) || (uptr == &mpx_poll)) { /* base unit or poll uni
sim_cancel (&mpx_unit [i]); /* cancel any scheduled I/O */ sim_cancel (&mpx_unit [i]); /* cancel any scheduled I/O */
} }
sim_cancel (&mpx_poll); /* stop Telnet poll */ sim_cancel (&mpx_poll); /* stop poll */
} }
return status; return status;
@ -2413,9 +2500,8 @@ switch (mpx_cmd) {
mpx_enq_cntr [0] = 0; /* clear port 0 ENQ counter */ mpx_enq_cntr [0] = 0; /* clear port 0 ENQ counter */
mpx_ack_wait [0] = 0; /* clear port 0 ACK wait timer */ mpx_ack_wait [0] = 0; /* clear port 0 ACK wait timer */
tmxr_putc_ln (&mpx_ldsc [0], ESC); /* send fast binary read */ tmxr_linemsg (&mpx_ldsc [0], "\033e"); /* send the fast binary read escape sequence to port 0 */
tmxr_putc_ln (&mpx_ldsc [0], 'e'); /* escape sequence to port 0 */ tmxr_poll_tx (&mpx_desc); /* and flush the output */
tmxr_poll_tx (&mpx_desc); /* flush output */
next_state = exec; /* set execution state */ next_state = exec; /* set execution state */
break; break;
@ -2557,7 +2643,7 @@ return set_flag;
} }
/* Poll for new Telnet connections */ /* Poll for new connections */
static void poll_connection (void) static void poll_connection (void)
{ {

View file

@ -1,7 +1,7 @@
/* hp2100_ms.c: HP 2100 13181B/13183B Digital Magnetic Tape Unit Interface simulator /* hp2100_ms.c: HP 2100 13181B/13183B Digital Magnetic Tape Unit Interface simulator
Copyright (c) 1993-2016, Robert M. Supnik 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 Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -27,6 +27,8 @@
MS 13181B Digital Magnetic Tape Unit Interface MS 13181B Digital Magnetic Tape Unit Interface
13183B 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 20-Jul-17 JDB Removed "msc_stopioe" variable and register
11-Jul-17 JDB Renamed "ibl_copy" to "cpu_ibl" 11-Jul-17 JDB Renamed "ibl_copy" to "cpu_ibl"
15-Mar-17 JDB Trace flags are now global 15-Mar-17 JDB Trace flags are now global
@ -1239,91 +1241,234 @@ switch (cmd & 0377) {
} }
} }
/* 7970B/7970E bootstrap routine (HP 12992D ROM) */
const BOOT_ROM ms_rom = { /* 7970B/7970E bootstrap loaders (BMTL and 12992D).
0106501, /*ST LIB 1 ; read sw */
0006011, /* SLB,RSS ; bit 0 set? */ The Basic Magnetic Tape Loader (BMTL) reads an absolute binary program from
0027714, /* JMP RD ; no read */ tape into memory. Before execution, the S register must be set as follows:
0003004, /* CMA,INA ; A is ctr */
0073775, /* STA WC ; save */ 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0067772, /* LDA SL0RW ; sel 0, rew */ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
0017762, /*FF JSB CMD ; do cmd */ | - - - - - - - - - - | file number |
0102311, /* SFS CC ; done? */ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
0027707, /* JMP *-1 ; wait */
0067774, /* LDB FFC ; get file fwd */ If S-register bits 5-0 are zero, the file located at the current tape
0037775, /* ISZ WC ; done files? */ position is read. If the bits are non-zero, the tape is rewound, and the
0027706, /* JMP FF ; no */ file number (1 - n) specified by the bits is read.
0067773, /*RD LDB RDCMD ; read cmd */
0017762, /* JSB CMD ; do cmd */ The 12992D boot loader ROM reads an absolute program from tape into memory.
0103710, /* STC DC,C ; start dch */ If S-register bit 0 is 0, the file located at the current tape position is
0102211, /* SFC CC ; read done? */ read. If bit 0 is 1, the tape is rewound, and the file number (1 - n)
0027752, /* JMP STAT ; no, get stat */ specified by the A-register value is read.
0102310, /* SFS DC ; any data? */
0027717, /* JMP *-3 ; wait */ For either loader, the tape format must be absolute binary, and a tape mark
0107510, /* LIB DC,C ; get rec cnt */ must end the file. Loader execution ends with one of the following
0005727, /* BLF,BLF ; move to lower */ instructions:
0007000, /* CMB ; make neg */
0077775, /* STA WC ; save */ * HLT 00 - a tape read (parity) error occurred.
0102211, /* SFC CC ; read done? */ * HLT 11 - a checksum error occurred; A/B = the calculated/tape value.
0027752, /* JMP STAT ; no, get stat */ * HLT 77 - the end of the file was reached with a successful read.
0102310, /* SFS DC ; any data? */ */
0027727, /* JMP *-3 ; wait */
0107510, /* LIB DC,C ; get load addr */ static const LOADER_ARRAY ms_loaders = {
0074000, /* STB 0 ; start csum */ { /* HP 21xx Basic Magnetic Tape Loader (BMTL) */
0077762, /* STA CMD ; save address */ 000, /* loader starting index */
0027742, /* JMP *+4 */ IBL_NA, /* DMA index */
0177762, /*NW STB CMD,I ; store data */ IBL_NA, /* FWA index */
0040001, /* ADA 1 ; add to csum */ { 0102501, /* 77700: MTAPE LIA 1 */
0037762, /* ISZ CMD ; adv addr ptr */ 0013775, /* 77701: AND 77775 */
0102310, /* SFS DC ; any data? */ 0003007, /* 77702: CMA,INA,SZA,RSS */
0027742, /* JMP *-1 ; wait */ 0027714, /* 77703: JMP 77714 */
0107510, /* LIB DC,C ; get word */ 0073777, /* 77704: STA 77777 */
0037775, /* ISZ WC ; done? */ 0067771, /* 77705: LDB 77771 */
0027737, /* JMP NW ; no */ 0017761, /* 77706: JSB 77761 */
0054000, /* CPB 0 ; csum ok? */ 0102311, /* 77707: SFS 11 */
0027717, /* JMP RD+3 ; yes, cont */ 0027707, /* 77710: JMP 77707 */
0102011, /* HLT 11 ; no, halt */ 0067773, /* 77711: LDB 77773 */
0102511, /*ST LIA CC ; get status */ 0037777, /* 77712: ISZ 77777 */
0001727, /* ALF,ALF ; get eof bit */ 0027706, /* 77713: JMP 77706 */
0002020, /* SSA ; set? */ 0067772, /* 77714: LDB 77772 */
0102077, /* HLT 77 ; done */ 0017761, /* 77715: JSB 77761 */
0001727, /* ALF,ALF ; put status back */ 0103710, /* 77716: STC 10,C */
0001310, /* RAR,SLA ; read ok? */ 0017740, /* 77717: JSB 77740 */
0102000, /* HLT 0 ; no */ 0005727, /* 77720: BLF,BLF */
0027714, /* JMP RD ; read next */ 0007004, /* 77721: CMB,INB */
0000000, /*CMD 0 */ 0077777, /* 77722: STB 77777 */
0106611, /* OTB CC ; output cmd */ 0017740, /* 77723: JSB 77740 */
0102511, /* LIA CC ; check for reject */ 0074000, /* 77724: STB 0 */
0001323, /* RAR,RAR */ 0077776, /* 77725: STB 77776 */
0001310, /* RAR,SLA */ 0017740, /* 77726: JSB 77740 */
0027763, /* JMP CMD+1 ; try again */ 0177776, /* 77727: STB 77776,I */
0103711, /* STC CC,C ; start command */ 0040001, /* 77730: ADA 1 */
0127762, /* JMP CMD,I ; exit */ 0037776, /* 77731: ISZ 77776 */
0001501, /*SL0RW 001501 ; select 0, rewind */ 0037777, /* 77732: ISZ 77777 */
0001423, /*RDCMD 001423 ; read record */ 0027726, /* 77733: JMP 77726 */
0000203, /*FFC 000203 ; space forward file */ 0017740, /* 77734: JSB 77740 */
0000000, /*WC 000000 */ 0054000, /* 77735: CPB 0 */
0000000, 0017740, /* 77736: JSB 77740 */
0000000 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) 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 */ if (dptr == NULL) /* if we are being called for a BOOT/LOAD CPU */
return SCPE_NOFNC; /* report "Command not allowed" if attempted */ 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 */
cpu_ibl (ms_rom, dev, IBL_OPT, /* copy the boot ROM to memory and configure */ else if (unitno != 0) /* otherwise a BOOT MSC for a non-zero unit */
IBL_MS | IBL_SET_SC (dev)); /* the S register accordingly */ return SCPE_NOFNC; /* is rejected as unsupported */
if ((sim_switches & SWMASK ('S')) && AR) /* if -S is specified and the A register is non-zero */ else /* otherwise this is a BOOT/LOAD MSC */
SR = SR | 1; /* then set to skip to the file number in A */ 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 */
return SCPE_OK; sim_switches & SWMASK ('S') ? ms_reposition : 0);
} }
/* Calculate tape record CRC and LRC characters */ /* Calculate tape record CRC and LRC characters */
static uint32 calc_crc_lrc (uint8 *buffer, t_mtrlnt length) static uint32 calc_crc_lrc (uint8 *buffer, t_mtrlnt length)

View file

@ -1,7 +1,7 @@
/* hp2100_mux.c: HP 2100 12920A Asynchronous Multiplexer Interface simulator /* hp2100_mux.c: HP 2100 12920A Asynchronous Multiplexer Interface simulator
Copyright (c) 2002-2016, Robert M. Supnik Copyright (c) 2002-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 Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -26,6 +26,8 @@
MUX,MUXL,MUXC 12920A Asynchronous Multiplexer Interface MUX,MUXL,MUXC 12920A Asynchronous Multiplexer Interface
01-May-18 JDB Removed ioCRS counter, as consecutive ioCRS calls are no longer made
28-Apr-18 JDB Fixed output completion IRQ when port is not connected
03-Aug-17 JDB Control card device renamed from MUXM to MUXC 03-Aug-17 JDB Control card device renamed from MUXM to MUXC
MUXC now enabled/disabled independently of MUX and MUXL MUXC now enabled/disabled independently of MUX and MUXL
Modified to use the "odd_parity" array in hp2100_sys.c Modified to use the "odd_parity" array in hp2100_sys.c
@ -101,6 +103,124 @@
801-type automatic dialers). Under simulation, only one control card is 801-type automatic dialers). Under simulation, only one control card is
supported. supported.
The multiplexer responds to I/O instructions as follows:
Upper Data Card output word format (OTA and OTB):
15 |14 13 12 |11 10 9 | 8 7 6 | 5 4 3 | 2 1 0
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| - | channel number | - - - - - - - - - - |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
Upper Data Card input word format (LIA, LIB, MIA, and MIB):
15 |14 13 12 |11 10 9 | 8 7 6 | 5 4 3 | 2 1 0
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| S | channel number | - - - - - - | D | B | L | R |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
Where:
S = Seeking
D = Diagnose
B = Break status
L = Character lost
R = Receive/send (0/1) character interrupt
Lower Data Card output control word format (OTA and OTB):
15 |14 13 12 |11 10 9 | 8 7 6 | 5 4 3 | 2 1 0
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| 1 | R | I | E | D | char size | baud rate |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
Where:
R = Receive/send (0/1) configuration
I = Enable interrupt
E = Echo (receive)/parity (send)
D = Diagnose
Character size:
The three least-significant bits of the sum of the data, parity, and stop
bits. For example, 7E1 is 1001, so 001 is coded.
Baud rate:
The value (14400 / device bit rate) - 1. For example, 2400 baud is 005.
Lower Data Card output data word format (OTA and OTB):
15 |14 13 12 |11 10 9 | 8 7 6 | 5 4 3 | 2 1 0
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| 0 | 1 | - - | S | transmit data |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
Where:
S = Sync bit
Transmit data:
Right-justified with leading one bits.
Lower Data Card input word format (LIA, LIB, MIA, and MIB):
15 |14 13 12 |11 10 9 | 8 7 6 | 5 4 3 | 2 1 0
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| P | channel | receive data |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
Where:
P = Computed parity
Receive data:
Right-justified with leading one bits
Control Card output word format (OTA and OTB):
15 |14 13 12 |11 10 9 | 8 7 6 | 5 4 3 | 2 1 0
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| S | U |channel number | - - |EC2|EC1|C2 |C1 |ES2|ES1|SS2|SS1|
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
Control Card input word format (LIA, LIB, MIA, and MIB):
15 |14 13 12 |11 10 9 | 8 7 6 | 5 4 3 | 2 1 0
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| 1 1 |channel number |I2 |I1 | 0 0 0 0 |ES2|ES1|S2 |S1 |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
Where:
S = Scan
U = Update
ECx = Enable command bit x
Cx = Command bit x
ESx = Enable status bit x
Sx = Status bit x
SSx = Stored status bit x
Ix = Interrupt bit x
The control card provides two serial control outputs and two serial status
inputs for each of the 16 channels. The card connects to the Request to Send
(CA) and Data Terminal Ready (CD) control lines and the Data Carrier Detect
(CF) and Data Set Ready (CC) status lines. Addressable latches hold the
control line values and assert them continuously to the 16 channels. In
addition, a 16-word by 4-bit RAM holds the expected state for each channel's
status lines and the corresponding interrupt enable bits to provide
notification if those lines change.
Implementation notes: Implementation notes:
1. If a BREAK is detected during an input poll, and we are not in diagnostic 1. If a BREAK is detected during an input poll, and we are not in diagnostic
@ -142,6 +262,23 @@
before the output character transmit interrupt). If an output operation before the output character transmit interrupt). If an output operation
is not in progress, then the BREAK will be recognized at the next input is not in progress, then the BREAK will be recognized at the next input
poll. poll.
2. In simulation, establishing a port connection asserts DSR to the control
card. If the port is configured as a dataset connection (SET MUXLn
DATASET), DCD is also asserted. Disconnecting denies DSR and DCD. The
control card responds to DTR denying by dropping the port connection.
The RTS setting has no effect.
3. When a Bell 103 dataset answers a call, it asserts DSR first. After the
handshake with the remote dataset completes, DCD asserts, typically
between 1.3 and 3.6 seconds later. Similarly, when the remote dataset
terminates the call by sending a long (1.5 second) space, the local
dataset drops DSR first, followed by DCD after approximately 30
milliseconds. The dataset simulation does not model these delays; DSR
and DCD transition up and down together. This implies that the control
card software driver will see only one interrupt for each transition pair
instead of the expected two (presuming both DSR and DCD are enabled to
interrupt).
*/ */
@ -181,6 +318,7 @@
#define UNIT_MDM (1 << UNIT_V_MDM) #define UNIT_MDM (1 << UNIT_V_MDM)
#define UNIT_DIAG (1 << UNIT_V_DIAG) #define UNIT_DIAG (1 << UNIT_V_DIAG)
/* Channel number (OTA upper, LIA lower or upper) */ /* Channel number (OTA upper, LIA lower or upper) */
#define MUX_V_CHAN 10 /* channel num */ #define MUX_V_CHAN 10 /* channel num */
@ -205,12 +343,47 @@
#define OTL_CHAR 03777 /* char mask */ #define OTL_CHAR 03777 /* char mask */
#define OTL_PAR 0200 /* char parity */ #define OTL_PAR 0200 /* char parity */
#define BAUD_RATE(p) ((28800 / (OTL_BAUD (p) + 1) + 1) / 2)
static const uint32 bits_per_char [8] = { /* bits per character, indexed by OTL_LNT encoding */
9, 10, 11, 12, 5, 6, 7, 8
};
static const BITSET_NAME lower_parameter_names [] = { /* lower data card parameter word names */
"\1send\0receive", /* bit 14 */
"enable interrupt", /* bit 13 */
"enable parity/echo", /* bit 12 */
"diagnose" /* bit 11 */
};
static const BITSET_FORMAT lower_parameter_format = /* names, offset, direction, alternates, bar */
{ FMT_INIT (lower_parameter_names, 11, msb_first, has_alt, append_bar) };
static const BITSET_NAME lower_data_names [] = { /* lower data card output data word names */
"send", /* bit 14 */
NULL, /* bit 13 */
NULL, /* bit 12 */
"sync" /* bit 11 */
};
static const BITSET_FORMAT lower_data_format = /* names, offset, direction, alternates, bar */
{ FMT_INIT (lower_data_names, 11, msb_first, no_alt, append_bar) };
/* LIA, lower = received data */ /* LIA, lower = received data */
#define LIL_PAR 0100000 /* parity */ #define LIL_PAR 0100000 /* parity */
#define PUT_DCH(x) (((x) & MUX_M_CHAN) << MUX_V_CHAN) #define PUT_DCH(x) (((x) & MUX_M_CHAN) << MUX_V_CHAN)
#define LIL_CHAR 01777 /* character */ #define LIL_CHAR 01777 /* character */
static const BITSET_NAME lower_input_names [] = { /* lower data card input data word names */
"\1odd parity\0even parity", /* bit 15 */
};
static const BITSET_FORMAT lower_input_format = /* names, offset, direction, alternates, bar */
{ FMT_INIT (lower_input_names, 0, msb_first, has_alt, append_bar) };
/* LIA, upper = status */ /* LIA, upper = status */
#define LIU_SEEK 0100000 /* seeking NI */ #define LIU_SEEK 0100000 /* seeking NI */
@ -219,6 +392,29 @@
#define LIU_LOST 0000002 /* char lost */ #define LIU_LOST 0000002 /* char lost */
#define LIU_TR 0000001 /* trans/rcv */ #define LIU_TR 0000001 /* trans/rcv */
static const BITSET_NAME upper_status_names [] = { /* upper data card status word names */
"seeking", /* bit 15 */
NULL, /* bit 14 */
NULL, /* bit 13 */
NULL, /* bit 12 */
NULL, /* bit 11 */
NULL, /* bit 10 */
NULL, /* bit 9 */
NULL, /* bit 8 */
NULL, /* bit 7 */
NULL, /* bit 6 */
NULL, /* bit 5 */
NULL, /* bit 4 */
"diagnose", /* bit 3 */
"break" /* bit 2 */
"lost", /* bit 1 */
"\1send\0receive" /* bit 0 */
};
static const BITSET_FORMAT upper_status_format = /* names, offset, direction, alternates, bar */
{ FMT_INIT (upper_status_names, 0, msb_first, has_alt, no_bar) };
/* OTA, control */ /* OTA, control */
#define OTC_SCAN 0100000 /* scan */ #define OTC_SCAN 0100000 /* scan */
@ -237,8 +433,29 @@
#define OTC_SS2 0000002 /* SSn flops */ #define OTC_SS2 0000002 /* SSn flops */
#define OTC_SS1 0000001 #define OTC_SS1 0000001
#define OTC_RW (OTC_ES2|OTC_ES1|OTC_SS2|OTC_SS1) #define OTC_RW (OTC_ES2|OTC_ES1|OTC_SS2|OTC_SS1)
#define RTS OTC_C2 /* C2 = rts */
#define DTR OTC_C1 /* C1 = dtr */ static const BITSET_NAME cntl_control_names [] = { /* control card control word names */
"scan", /* bit 15 */
"update", /* bit 14 */
NULL, /* bit 13 */
NULL, /* bit 12 */
NULL, /* bit 11 */
NULL, /* bit 10 */
NULL, /* bit 9 */
NULL, /* bit 8 */
"EC2", /* bit 7 */
"EC1", /* bit 6 */
"\1C2\0~C2", /* bit 5 */
"\1C1\0~C1", /* bit 4 */
"ES2", /* bit 3 */
"ES1", /* bit 2 */
"\1S2\0~S2", /* bit 1 */
"\1S1\0~S1" /* bit 0 */
};
static const BITSET_FORMAT cntl_control_format = /* names, offset, direction, alternates, bar */
{ FMT_INIT (cntl_control_names, 0, msb_first, has_alt, no_bar) };
/* LIA, control */ /* LIA, control */
@ -251,13 +468,46 @@
#define LIC_S2 0000002 /* Sn flops */ #define LIC_S2 0000002 /* Sn flops */
#define LIC_S1 0000001 #define LIC_S1 0000001
#define LIC_V_I 8 /* S1 to I1 */ #define LIC_V_I 8 /* S1 to I1 */
#define CDET LIC_S2 /* S2 = cdet */
#define DSR LIC_S1 /* S1 = dsr */
#define LIC_TSTI(ch) (((muxc_lia[ch] ^ muxc_ota[ch]) & \ #define LIC_TSTI(ch) (((muxc_lia[ch] ^ muxc_ota[ch]) & \
((muxc_ota[ch] & (OTC_ES2|OTC_ES1)) >> OTC_V_ES)) \ ((muxc_ota[ch] & (OTC_ES2|OTC_ES1)) >> OTC_V_ES)) \
<< LIC_V_I) << LIC_V_I)
static const BITSET_NAME cntl_status_names [] = { /* control card status word names */
"I2", /* bit 9 */
"I1", /* bit 8 */
NULL, /* bit 7 */
NULL, /* bit 6 */
NULL, /* bit 5 */
NULL, /* bit 4 */
"ES2", /* bit 3 */
"ES1", /* bit 2 */
"\1S2\0~S2", /* bit 1 */
"\1S1\0~S1" /* bit 0 */
};
static const BITSET_FORMAT cntl_status_format = /* names, offset, direction, alternates, bar */
{ FMT_INIT (cntl_status_names, 0, msb_first, has_alt, no_bar) };
/* Control card #1 serial line bits */
#define RTS OTC_C2 /* Control card #1 C2 = Request to Send */
#define DTR OTC_C1 /* Control card #1 C1 = Data Terminal Ready */
#define DCD LIC_S2 /* Control card #1 S2 = Data Carrier Detect */
#define DSR LIC_S1 /* Control card #1 S1 = Data Set Ready */
static const BITSET_NAME cntl_line_names [] = { /* Control card serial line status names */
"RTS", /* bit 5 */
"DTR", /* bit 4 */
NULL, /* bit 3 */
NULL, /* bit 2 */
"DCD", /* bit 1 */
"DSR" /* bit 0 */
};
static const BITSET_FORMAT cntl_line_format = /* names, offset, direction, alternates, bar */
{ FMT_INIT (cntl_line_names, 0, msb_first, no_alt, no_bar) };
/* Program constants */ /* Program constants */
@ -440,9 +690,9 @@ static MTAB muxl_mod [] = {
/* Debugging trace list */ /* Debugging trace list */
static DEBTAB muxl_deb [] = { static DEBTAB muxl_deb [] = {
{ "CMDS", DEB_CMDS }, { "CSRW", TRACE_CSRW }, /* Interface control, status, read, and write actions */
{ "CPU", DEB_CPU }, { "SERV", TRACE_SERV }, /* Channel unit service scheduling calls */
{ "XFER", DEB_XFER }, { "XFER", TRACE_XFER }, /* Data receptions and transmissions */
{ "IOBUS", TRACE_IOBUS }, /* interface I/O bus signals and data words */ { "IOBUS", TRACE_IOBUS }, /* interface I/O bus signals and data words */
{ NULL, 0 } { NULL, 0 }
}; };
@ -520,7 +770,8 @@ static MTAB muxu_mod [] = {
/* Debugging trace list */ /* Debugging trace list */
static DEBTAB muxu_deb [] = { static DEBTAB muxu_deb [] = {
{ "CPU", DEB_CPU }, { "CSRW", TRACE_CSRW }, /* Interface control, status, read, and write actions */
{ "PSERV", TRACE_PSERV }, /* Poll unit service scheduling calls */
{ "IOBUS", TRACE_IOBUS }, /* interface I/O bus signals and data words */ { "IOBUS", TRACE_IOBUS }, /* interface I/O bus signals and data words */
{ NULL, 0 } { NULL, 0 }
}; };
@ -601,8 +852,8 @@ static MTAB muxc_mod [] = {
/* Debugging trace list */ /* Debugging trace list */
static DEBTAB muxc_deb [] = { static DEBTAB muxc_deb [] = {
{ "CMDS", DEB_CMDS }, { "CSRW", TRACE_CSRW }, /* Interface control, status, read, and write actions */
{ "CPU", DEB_CPU }, { "XFER", TRACE_XFER }, /* Data receptions and transmissions */
{ "IOBUS", TRACE_IOBUS }, /* interface I/O bus signals and data words */ { "IOBUS", TRACE_IOBUS }, /* interface I/O bus signals and data words */
{ NULL, 0 } { NULL, 0 }
}; };
@ -646,26 +897,16 @@ DEVICE muxc_dev = {
1. The operating manual says that "at least 100 milliseconds of CLC 0s must 1. The operating manual says that "at least 100 milliseconds of CLC 0s must
be programmed" by systems employing the multiplexer to ensure that the be programmed" by systems employing the multiplexer to ensure that the
multiplexer resets. In practice, such systems issue 128K CLC 0 multiplexer resets. In practice, such systems issue 128K CLC 0
instructions. As we provide debug logging of multiplexer resets, a CRS instructions. In simulation, only one ioCRS invocation is required to
counter is used to ensure that only one debug line is printed in response reset the multiplexer.
to these 128K CRS invocations.
*/ */
uint32 muxlio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) uint32 muxlio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
{ {
int32 ln; int32 ln;
const char *hold_or_clear = (signal_set & ioCLF ? ",C" : "");
static uint32 crs_count = 0; /* cntr for ioCRS repeat */
IOSIGNAL signal; IOSIGNAL signal;
IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
if (crs_count && !(signal_set & ioCRS)) { /* counting CRSes and not present? */
tprintf (muxl_dev, DEB_CMDS, "[CRS] Multiplexer reset %d times\n",
crs_count);
crs_count = 0; /* clear counter */
}
while (working_set) { while (working_set) {
signal = IONEXT (working_set); /* isolate next signal */ signal = IONEXT (working_set); /* isolate next signal */
@ -673,9 +914,6 @@ while (working_set) {
case ioCLF: /* clear flag flip-flop */ case ioCLF: /* clear flag flip-flop */
muxl.flag = muxl.flagbuf = CLEAR; muxl.flag = muxl.flagbuf = CLEAR;
tprintf (muxl_dev, DEB_CMDS, "[CLF] Flag cleared\n");
mux_data_int (); /* look for new int */ mux_data_int (); /* look for new int */
break; break;
@ -683,8 +921,6 @@ while (working_set) {
case ioSTF: /* set flag flip-flop */ case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */ case ioENF: /* enable flag */
muxl.flag = muxl.flagbuf = SET; muxl.flag = muxl.flagbuf = SET;
tprintf (muxl_dev, DEB_CMDS, "[STF] Flag set\n");
break; break;
@ -699,19 +935,28 @@ while (working_set) {
case ioIOI: /* I/O data input */ case ioIOI: /* I/O data input */
stat_data = IORETURN (SCPE_OK, muxl_ibuf); /* merge in return status */ tprintf (muxl_dev, TRACE_CSRW, "Input data is channel %u | %s%04o\n",
MUX_CHAN (muxl_ibuf),
fmt_bitset (muxl_ibuf, lower_input_format),
muxl_ibuf & LIL_CHAR);
tprintf (muxl_dev, DEB_CPU, "[LIx%s] Data = %06o\n", hold_or_clear, muxl_ibuf); stat_data = IORETURN (SCPE_OK, muxl_ibuf); /* merge in return status */
break; break;
case ioIOO: /* I/O data output */ case ioIOO: /* I/O data output */
muxl_obuf = IODATA (stat_data); /* store data */ muxl_obuf = IODATA (stat_data); /* store data */
if (muxl_obuf & OTL_P) if (muxl_obuf & OTL_P)
tprintf (muxl_dev, DEB_CPU, "[OTx%s] Parameter = %06o\n", hold_or_clear, muxl_obuf); tprintf (muxl_dev, TRACE_CSRW, "Parameter is %s%u bits | %u baud\n",
fmt_bitset (muxl_obuf, lower_parameter_format),
bits_per_char [OTL_LNT (muxl_obuf)],
BAUD_RATE (muxl_obuf));
else else
tprintf (muxl_dev, DEB_CPU, "[OTx%s] Data = %06o\n", hold_or_clear, muxl_obuf); tprintf (muxl_dev, TRACE_CSRW, "Output data is %s%04o\n",
fmt_bitset (muxl_obuf, lower_data_format),
muxl_obuf & OTL_CHAR);
break; break;
@ -721,7 +966,6 @@ while (working_set) {
case ioCRS: /* control reset */ case ioCRS: /* control reset */
if (crs_count == 0) { /* first reset? */
muxl.control = CLEAR; /* clear control flip-flop */ muxl.control = CLEAR; /* clear control flip-flop */
for (ln = 0; ln < SEND_CHAN_COUNT; ln++) { /* clear transmit info */ for (ln = 0; ln < SEND_CHAN_COUNT; ln++) { /* clear transmit info */
@ -733,16 +977,12 @@ while (working_set) {
mux_rbuf[ln] = mux_rpar[ln] = 0; /* clear receive info */ mux_rbuf[ln] = mux_rpar[ln] = 0; /* clear receive info */
mux_sta[ln] = mux_rchp[ln] = 0; mux_sta[ln] = mux_rchp[ln] = 0;
} }
}
crs_count = crs_count + 1; /* increment count */
break; break;
case ioCLC: /* clear control flip-flop */ case ioCLC: /* clear control flip-flop */
muxl.control = CLEAR; muxl.control = CLEAR;
tprintf (muxl_dev, DEB_CMDS, "[CLC%s] Data interrupt inhibited\n", hold_or_clear);
break; break;
@ -751,53 +991,62 @@ while (working_set) {
ln = MUX_CHAN (muxu_obuf); /* get chan # */ ln = MUX_CHAN (muxu_obuf); /* get chan # */
if (muxl_obuf & OTL_TX) { /* transmit? */ if (muxl_obuf & OTL_TX) /* if this is a send parameter or data */
if (ln < SEND_CHAN_COUNT) { /* line valid? */ if (ln >= SEND_CHAN_COUNT) /* then report if the channel number is out of range */
if (muxl_obuf & OTL_P) { /* parameter? */ tprintf (muxl_dev, TRACE_CSRW, "Send channel %d invalid\n",
mux_xpar[ln] = (uint16) muxl_obuf; /* store param value */ ln);
tprintf (muxl_dev, DEB_CMDS, "[STC%s] Transmit channel %d parameter %06o stored\n",
hold_or_clear, ln, muxl_obuf); else if (muxl_obuf & OTL_P) { /* otherwise if this is a parameter store */
mux_xpar[ln] = (uint16) muxl_obuf; /* then save it */
tprintf (muxl_dev, TRACE_CSRW, "Channel %d send parameter %06o stored\n",
ln, muxl_obuf);
} }
else { /* data */ else { /* otherwise this is a data store */
if (mux_xpar[ln] & OTL_TPAR) /* parity requested? */ if (mux_xpar[ln] & OTL_TPAR) /* if parity is enabled */
muxl_obuf = /* add parity bit */ muxl_obuf = muxl_obuf & ~OTL_PAR /* then replace the parity bit */
muxl_obuf & ~OTL_PAR | | XMT_PAR (muxl_obuf); /* with the calculated value */
XMT_PAR(muxl_obuf);
mux_xbuf[ln] = (uint16) muxl_obuf; /* load buffer */ mux_xbuf[ln] = (uint16) muxl_obuf; /* load buffer */
if (sim_is_active (&muxl_unit[ln])) { /* still working? */ if (sim_is_active (&muxl_unit[ln])) { /* still working? */
mux_sta[ln] = mux_sta[ln] | LIU_LOST; /* char lost */ mux_sta[ln] = mux_sta[ln] | LIU_LOST; /* char lost */
tprintf (muxl_dev, DEB_CMDS, "[STC%s] Transmit channel %d data overrun\n",
hold_or_clear, ln); tprintf (muxl_dev, TRACE_CSRW, "Channel %d send data overrun\n",
ln);
} }
else { else {
if (muxu_unit.flags & UNIT_DIAG) /* loopback? */ if (muxu_unit.flags & UNIT_DIAG) /* loopback? */
mux_ldsc[ln].conn = 1; /* connect this line */ mux_ldsc[ln].conn = 1; /* connect this line */
sim_activate (&muxl_unit[ln], muxl_unit[ln].wait); sim_activate (&muxl_unit[ln], muxl_unit[ln].wait);
tprintf (muxl_dev, DEB_CMDS, "[STC%s] Transmit channel %d data %06o scheduled\n",
hold_or_clear, ln, muxl_obuf); tprintf (muxl_dev, TRACE_CSRW, "Channel %d send data %06o stored\n",
ln, muxl_obuf);
tprintf (muxl_dev, TRACE_SERV, "Channel %d delay %d service scheduled\n",
ln, muxl_unit [ln].wait);
} }
} }
}
else
tprintf (muxl_dev, DEB_CMDS, "[STC%s] Transmit channel %d invalid\n", hold_or_clear, ln);
}
else /* receive */ else /* otherwise this is a receive parameter */
if (ln < RECV_CHAN_COUNT) /* line valid? */ if (ln >= RECV_CHAN_COUNT) /* report if the channel number is out of range */
if (muxl_obuf & OTL_P) { /* parameter? */ tprintf (muxl_dev, TRACE_CSRW, "Receive channel %d invalid\n",
mux_rpar[ln] = (uint16) muxl_obuf; /* store param value */ ln);
tprintf (muxl_dev, DEB_CMDS, "Receive channel %d parameter %06o stored\n",
else if (muxl_obuf & OTL_P) { /* otherwise if this is a parameter store */
mux_rpar[ln] = (uint16) muxl_obuf; /* then save it */
tprintf (muxl_dev, TRACE_CSRW, "Channel %d receive parameter %06o stored\n",
ln, muxl_obuf); ln, muxl_obuf);
} }
else else /* otherwise a data store to a receive channel is invalid */
tprintf (muxl_dev, DEB_CMDS, "Receive channel %d parameter %06o invalid action\n", tprintf (muxl_dev, TRACE_CSRW, "Channel %d receive output data word %06o invalid\n",
ln, muxl_obuf); ln, muxl_obuf);
else
tprintf (muxl_dev, DEB_CMDS, "[STC%s] Receive channel %d invalid\n", hold_or_clear, ln);
break; break;
@ -850,15 +1099,17 @@ while (working_set) {
case ioIOI: /* I/O data input */ case ioIOI: /* I/O data input */
stat_data = IORETURN (SCPE_OK, muxu_ibuf); /* merge in return status */ stat_data = IORETURN (SCPE_OK, muxu_ibuf); /* merge in return status */
tprintf (muxu_dev, DEB_CPU, "[LIx] Status = %06o, channel = %d\n", tprintf (muxu_dev, TRACE_CSRW, "Status is channel %u | %s\n",
muxu_ibuf, MUX_CHAN(muxu_ibuf)); MUX_CHAN (muxu_ibuf),
fmt_bitset (muxu_ibuf, upper_status_format));
break; break;
case ioIOO: /* I/O data output */ case ioIOO: /* I/O data output */
muxu_obuf = IODATA (stat_data); /* store data */ muxu_obuf = IODATA (stat_data); /* store data */
tprintf (muxu_dev, DEB_CPU, "[OTx] Data channel = %d\n", MUX_CHAN(muxu_obuf)); tprintf (muxu_dev, TRACE_CSRW, "Channel %d is selected\n",
MUX_CHAN (muxu_obuf));
break; break;
@ -882,7 +1133,6 @@ return stat_data;
uint32 muxcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) uint32 muxcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
{ {
const char *hold_or_clear = (signal_set & ioCLF ? ",C" : "");
uint16 data; uint16 data;
int32 ln, old; int32 ln, old;
IOSIGNAL signal; IOSIGNAL signal;
@ -895,9 +1145,6 @@ while (working_set) {
case ioCLF: /* clear flag flip-flop */ case ioCLF: /* clear flag flip-flop */
muxc.flag = muxc.flagbuf = CLEAR; muxc.flag = muxc.flagbuf = CLEAR;
tprintf (muxc_dev, DEB_CMDS, "[CLF] Flag cleared\n");
mux_ctrl_int (); /* look for new int */ mux_ctrl_int (); /* look for new int */
break; break;
@ -905,8 +1152,6 @@ while (working_set) {
case ioSTF: /* set flag flip-flop */ case ioSTF: /* set flag flip-flop */
case ioENF: /* enable flag */ case ioENF: /* enable flag */
muxc.flag = muxc.flagbuf = SET; muxc.flag = muxc.flagbuf = SET;
tprintf (muxc_dev, DEB_CMDS, "[STF] Flag set\n");
break; break;
@ -926,8 +1171,8 @@ while (working_set) {
(muxc_ota[muxc_chan] & (OTC_ES2 | OTC_ES1)) | /* ES2, ES1 */ (muxc_ota[muxc_chan] & (OTC_ES2 | OTC_ES1)) | /* ES2, ES1 */
(muxc_lia[muxc_chan] & (LIC_S2 | LIC_S1))); /* S2, S1 */ (muxc_lia[muxc_chan] & (LIC_S2 | LIC_S1))); /* S2, S1 */
tprintf (muxc_dev, DEB_CPU, "[LIx%s] Status = %06o, channel = %d\n", tprintf (muxc_dev, TRACE_CSRW, "Status is channel %u | %s\n",
hold_or_clear, data, muxc_chan); muxc_chan, fmt_bitset (data, cntl_status_format));
muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* incr channel */ muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* incr channel */
stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ stat_data = IORETURN (SCPE_OK, data); /* merge in return status */
@ -938,6 +1183,9 @@ while (working_set) {
data = IODATA (stat_data); /* clear supplied status */ data = IODATA (stat_data); /* clear supplied status */
ln = muxc_chan = OTC_CHAN (data); /* set channel */ ln = muxc_chan = OTC_CHAN (data); /* set channel */
tprintf (muxc_dev, TRACE_CSRW, "Control is channel %u | %s\n",
muxc_chan, fmt_bitset (data, cntl_control_format));
if (data & OTC_SCAN) muxc_scan = 1; /* set scan flag */ if (data & OTC_SCAN) muxc_scan = 1; /* set scan flag */
else muxc_scan = 0; else muxc_scan = 0;
@ -954,14 +1202,22 @@ while (working_set) {
muxc_ota[ln] = muxc_ota[ln] =
(muxc_ota[ln] & ~OTC_C1) | (data & OTC_C1); (muxc_ota[ln] & ~OTC_C1) | (data & OTC_C1);
if (muxu_unit.flags & UNIT_DIAG) /* loopback? */ tprintf (muxc_dev, TRACE_XFER, "Channel %d line status is %s\n",
ln, fmt_bitset (muxc_ota [ln], cntl_line_format));
if (muxu_unit.flags & UNIT_DIAG) { /* loopback? */
muxc_lia[ln ^ 1] = /* set S1, S2 to C1, C2 */ muxc_lia[ln ^ 1] = /* set S1, S2 to C1, C2 */
(muxc_lia[ln ^ 1] & ~(LIC_S2 | LIC_S1)) | (muxc_lia[ln ^ 1] & ~(LIC_S2 | LIC_S1)) |
(muxc_ota[ln] & (OTC_C1 | OTC_C2)) >> OTC_V_C; (muxc_ota[ln] & (OTC_C1 | OTC_C2)) >> OTC_V_C;
tprintf (muxc_dev, TRACE_XFER, "Channel %d line status is %s\n",
ln ^ 1, fmt_bitset (muxc_lia [ln ^ 1], cntl_line_format));
}
else if ((muxl_unit[ln].flags & UNIT_MDM) /* modem ctrl? */ else if ((muxl_unit[ln].flags & UNIT_MDM) /* modem ctrl? */
&& (old & DTR) && !(muxc_ota[ln] & DTR)) { /* DTR drop? */ && (old & DTR) && !(muxc_ota[ln] & DTR)) { /* DTR drop? */
tprintf (muxc_dev, DEB_CMDS, "Channel %d disconnected by DTR drop\n", ln); tprintf (muxc_dev, TRACE_CSRW, "Channel %d disconnected by DTR drop\n",
ln);
tmxr_linemsg (&mux_ldsc[ln], "\r\nDisconnected from the "); tmxr_linemsg (&mux_ldsc[ln], "\r\nDisconnected from the ");
tmxr_linemsg (&mux_ldsc[ln], sim_name); tmxr_linemsg (&mux_ldsc[ln], sim_name);
@ -969,12 +1225,12 @@ while (working_set) {
tmxr_reset_ln (&mux_ldsc[ln]); /* reset line */ tmxr_reset_ln (&mux_ldsc[ln]); /* reset line */
muxc_lia[ln] = 0; /* dataset off */ muxc_lia[ln] = 0; /* dataset off */
tprintf (muxc_dev, TRACE_XFER, "Channel %d disconnect dropped DCD and DSR\n",
ln);
} }
} /* end update */ } /* end update */
tprintf (muxc_dev, DEB_CPU, "[OTx%s] Parameter = %06o, channel = %d\n",
hold_or_clear, data, ln);
if ((muxu_unit.flags & UNIT_DIAG) && (!muxc.flag)) /* loopback and flag clear? */ if ((muxu_unit.flags & UNIT_DIAG) && (!muxc.flag)) /* loopback and flag clear? */
mux_ctrl_int (); /* status chg may interrupt */ mux_ctrl_int (); /* status chg may interrupt */
break; break;
@ -1030,6 +1286,9 @@ t_stat muxi_svc (UNIT *uptr)
int32 ln, c; int32 ln, c;
t_bool loopback; t_bool loopback;
tprintf (muxu_dev, TRACE_PSERV, "Poll delay %d service entered\n",
uptr->wait);
loopback = ((muxu_unit.flags & UNIT_DIAG) != 0); /* diagnostic mode? */ loopback = ((muxu_unit.flags & UNIT_DIAG) != 0); /* diagnostic mode? */
if (!loopback) { /* terminal mode? */ if (!loopback) { /* terminal mode? */
@ -1043,12 +1302,17 @@ if (!loopback) { /* terminal mode? */
ln = tmxr_poll_conn (&mux_desc); /* look for connect */ ln = tmxr_poll_conn (&mux_desc); /* look for connect */
if (ln >= 0) { /* got one? */ if (ln >= 0) { /* got one? */
mux_ldsc[ln].rcve = 1; /* rcv enabled */
muxc_lia[ln] = muxc_lia[ln] | DSR; /* set dsr */
if ((muxl_unit[ln].flags & UNIT_MDM) && /* modem ctrl? */ if ((muxl_unit[ln].flags & UNIT_MDM) && /* modem ctrl? */
(muxc_ota[ln] & DTR)) /* DTR? */ (muxc_ota[ln] & DTR)) /* DTR? */
muxc_lia[ln] = muxc_lia[ln] | CDET; /* set cdet */ muxc_lia[ln] = muxc_lia[ln] | DCD; /* set DCD */
muxc_lia[ln] = muxc_lia[ln] | DSR; /* set dsr */
mux_ldsc[ln].rcve = 1; /* rcv enabled */ tprintf (muxc_dev, TRACE_XFER, "Channel %d connected\n",
ln);
} }
tmxr_poll_rx (&mux_desc); /* poll for input */ tmxr_poll_rx (&mux_desc); /* poll for input */
} }
@ -1065,7 +1329,7 @@ for (ln = 0; ln < SEND_CHAN_COUNT; ln++) { /* loop thru lines
c = SCPE_BREAK; /* supply it now */ c = SCPE_BREAK; /* supply it now */
else else
c = tmxr_getc_ln (&mux_ldsc[ln]); /* get char from Telnet */ c = tmxr_getc_ln (&mux_ldsc[ln]); /* get char from line */
if (c) /* valid char? */ if (c) /* valid char? */
mux_receive (ln, c, loopback); /* process it */ mux_receive (ln, c, loopback); /* process it */
@ -1086,18 +1350,20 @@ return SCPE_OK;
t_stat muxo_svc (UNIT *uptr) t_stat muxo_svc (UNIT *uptr)
{ {
int32 c, fc, ln, altln; const int32 ln = uptr - muxl_unit; /* line # */
const int32 altln = ln ^ 1; /* alt. line for diag mode */
int32 c, fc;
t_bool loopback; t_bool loopback;
t_stat result = SCPE_OK;
ln = uptr - muxl_unit; /* line # */ tprintf (muxl_dev, TRACE_SERV, "Channel %d service entered\n",
altln = ln ^ 1; /* alt. line for diag mode */ ln);
fc = mux_xbuf[ln] & OTL_CHAR; /* full character data */ fc = mux_xbuf[ln] & OTL_CHAR; /* full character data */
c = fc & 0377; /* Telnet character data */ c = fc & 0377; /* line character data */
loopback = ((muxu_unit.flags & UNIT_DIAG) != 0); /* diagnostic mode? */ loopback = ((muxu_unit.flags & UNIT_DIAG) != 0); /* diagnostic mode? */
if (mux_ldsc[ln].conn) { /* connected? */
if (mux_ldsc[ln].xmte) { /* xmt enabled? */ if (mux_ldsc[ln].xmte) { /* xmt enabled? */
if (loopback) /* diagnostic mode? */ if (loopback) /* diagnostic mode? */
mux_ldsc[ln].conn = 0; /* clear connection */ mux_ldsc[ln].conn = 0; /* clear connection */
@ -1119,24 +1385,34 @@ if (mux_ldsc[ln].conn) { /* connected? */
else { /* no loopback */ else { /* no loopback */
if (c >= 0) /* valid? */ if (c >= 0) /* valid? */
tmxr_putc_ln (lp, c); /* output char */ result = tmxr_putc_ln (lp, c); /* output char */
tmxr_poll_tx (&mux_desc); /* poll xmt */ tmxr_poll_tx (&mux_desc); /* poll xmt */
} }
} }
else if (mux_ldsc [ln].conn == 0) /* sync character isn't seen by receiver */
result = SCPE_LOST; /* so report transfer success if connected */
mux_xdon[ln] = 1; /* set for xmit irq */ mux_xdon[ln] = 1; /* set for xmit irq */
if (loopback || c >= 0) if (loopback || c >= 0)
tprintf (muxl_dev, DEB_XFER, "Channel %d character %s sent\n", if (result == SCPE_LOST)
tprintf (muxl_dev, TRACE_XFER, "Channel %d character %s discarded by connection loss\n",
ln, fmt_char ((uint8) (loopback ? fc : c)));
else
tprintf (muxl_dev, TRACE_XFER, "Channel %d character %s sent\n",
ln, fmt_char ((uint8) (loopback ? fc : c))); ln, fmt_char ((uint8) (loopback ? fc : c)));
} }
else { /* buf full */ else { /* buf full */
tmxr_poll_tx (&mux_desc); /* poll xmt */ tmxr_poll_tx (&mux_desc); /* poll xmt */
sim_activate (uptr, muxl_unit[ln].wait); /* wait */ sim_activate (uptr, muxl_unit[ln].wait); /* wait */
tprintf (muxl_dev, TRACE_SERV, "Channel %d delay %d service rescheduled\n",
ln, muxl_unit [ln].wait);
return SCPE_OK; return SCPE_OK;
} }
}
if (!muxl.flag) mux_data_int (); /* scan for int */ if (!muxl.flag) mux_data_int (); /* scan for int */
return SCPE_OK; return SCPE_OK;
@ -1154,15 +1430,15 @@ if (c & SCPE_BREAK) { /* break? */
mux_sta[ln] = mux_sta[ln] | LIU_BRK; /* set break status */ mux_sta[ln] = mux_sta[ln] | LIU_BRK; /* set break status */
if (diag) if (diag)
tprintf (muxl_dev, DEB_XFER, "Channel %d break detected\n", ln); tprintf (muxl_dev, TRACE_XFER, "Channel %d break detected\n", ln);
else else
tprintf (muxl_dev, DEB_XFER, "Channel %d deferred break processed\n", ln); tprintf (muxl_dev, TRACE_XFER, "Channel %d deferred break processed\n", ln);
} }
else { else {
mux_defer[ln] = 1; /* defer break */ mux_defer[ln] = 1; /* defer break */
tprintf (muxl_dev, DEB_XFER, "Channel %d break detected and deferred\n", ln); tprintf (muxl_dev, TRACE_XFER, "Channel %d break detected and deferred\n", ln);
return; return;
} }
@ -1184,7 +1460,7 @@ else { /* normal */
mux_rchp[ln] = 1; /* char pending */ mux_rchp[ln] = 1; /* char pending */
tprintf (muxl_dev, DEB_XFER, "Channel %d character %s received\n", tprintf (muxl_dev, TRACE_XFER, "Channel %d character %s received\n",
ln, fmt_char ((uint8) c)); ln, fmt_char ((uint8) c));
if (mux_rpar[ln] & OTL_DIAG) /* diagnose this line? */ if (mux_rpar[ln] & OTL_DIAG) /* diagnose this line? */
@ -1209,7 +1485,8 @@ for (i = FIRST_TERM; i <= LAST_TERM; i++) { /* rcv lines */
mux_rchp[i] = 0; /* clr char, stat */ mux_rchp[i] = 0; /* clr char, stat */
mux_sta[i] = 0; mux_sta[i] = 0;
tprintf (muxl_dev, DEB_CMDS, "Receive channel %d interrupt requested\n", i); tprintf (muxl_dev, TRACE_CSRW, "Channel %d receive interrupt requested\n",
i);
muxlio (&muxl_dib, ioENF, 0); /* interrupt */ muxlio (&muxl_dib, ioENF, 0); /* interrupt */
return; return;
@ -1224,7 +1501,8 @@ for (i = FIRST_TERM; i <= LAST_TERM; i++) { /* xmt lines */
mux_xdon[i] = 0; /* clr done, stat */ mux_xdon[i] = 0; /* clr done, stat */
mux_sta[i] = 0; mux_sta[i] = 0;
tprintf (muxl_dev, DEB_CMDS, "Transmit channel %d interrupt requested\n", i); tprintf (muxl_dev, TRACE_CSRW, "Channel %d send interrupt requested\n",
i);
muxlio (&muxl_dib, ioENF, 0); /* interrupt */ muxlio (&muxl_dib, ioENF, 0); /* interrupt */
return; return;
@ -1239,7 +1517,8 @@ for (i = FIRST_AUX; i <= LAST_AUX; i++) { /* diag lines */
mux_rchp[i] = 0; /* clr char, stat */ mux_rchp[i] = 0; /* clr char, stat */
mux_sta[i] = 0; mux_sta[i] = 0;
tprintf (muxl_dev, DEB_CMDS, "Receive channel %d interrupt requested\n", i); tprintf (muxl_dev, TRACE_CSRW, "Channel %d receive interrupt requested\n",
i);
muxlio (&muxl_dib, ioENF, 0); /* interrupt */ muxlio (&muxl_dib, ioENF, 0); /* interrupt */
return; return;
@ -1267,10 +1546,10 @@ line_count = (muxc_scan ? TERM_COUNT : 1); /* check one or all line
for (i = 0; i < line_count; i++) { for (i = 0; i < line_count; i++) {
if (muxc_scan) /* scanning? */ if (muxc_scan) /* scanning? */
muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* step channel */ muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* step channel */
if (LIC_TSTI (muxc_chan)) { /* status change? */
tprintf (muxc_dev, DEB_CMDS, "Control channel %d interrupt requested (poll = %d)\n", if (LIC_TSTI (muxc_chan)) { /* status change? */
muxc_chan, i + 1); tprintf (muxc_dev, TRACE_CSRW, "Channel %u interrupt requested\n",
muxc_chan);
muxcio (&muxc_dib, ioENF, 0); /* set flag */ muxcio (&muxc_dib, ioENF, 0); /* set flag */
break; break;
@ -1310,10 +1589,12 @@ mux_rpar[i] = mux_xpar[i] = 0;
mux_rchp[i] = mux_xdon[i] = 0; mux_rchp[i] = mux_xdon[i] = 0;
mux_sta[i] = mux_defer[i] = 0; mux_sta[i] = mux_defer[i] = 0;
muxc_ota[i] = muxc_lia[i] = 0; /* clear modem */ muxc_ota[i] = muxc_lia[i] = 0; /* clear modem */
if (mux_ldsc[i].conn && /* connected? */
((muxu_unit.flags & UNIT_DIAG) == 0)) /* term mode? */ if (mux_ldsc [i].conn /* connected? */
muxc_lia[i] = muxc_lia[i] | DSR | /* cdet, dsr */ && (muxu_unit.flags & UNIT_DIAG) == 0) /* term mode? */
(muxl_unit[i].flags & UNIT_MDM? CDET: 0); muxc_lia[i] = muxc_lia[i] | DSR /* DCD, dsr */
| (muxl_unit[i].flags & UNIT_MDM ? DCD : 0);
sim_cancel (&muxl_unit[i]); sim_cancel (&muxl_unit[i]);
return; return;
} }
@ -1342,7 +1623,7 @@ muxc_chan = muxc_scan = 0; /* init modem scan */
if (muxu_unit.flags & UNIT_ATT) { /* master att? */ if (muxu_unit.flags & UNIT_ATT) { /* master att? */
muxu_unit.wait = POLL_FIRST; /* set up poll */ muxu_unit.wait = POLL_FIRST; /* set up poll */
sim_activate (&muxu_unit, muxu_unit.wait); /* start Telnet poll immediately */ sim_activate (&muxu_unit, muxu_unit.wait); /* start poll immediately */
} }
else else
sim_cancel (&muxu_unit); /* else stop */ sim_cancel (&muxu_unit); /* else stop */
@ -1370,7 +1651,7 @@ status = tmxr_attach (&mux_desc, uptr, cptr); /* attach */
if (status == SCPE_OK) { if (status == SCPE_OK) {
muxu_unit.wait = POLL_FIRST; /* set up poll */ muxu_unit.wait = POLL_FIRST; /* set up poll */
sim_activate (&muxu_unit, muxu_unit.wait); /* start Telnet poll immediately */ sim_activate (&muxu_unit, muxu_unit.wait); /* start poll immediately */
} }
return status; return status;
@ -1418,7 +1699,7 @@ t_stat mux_setdiag (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
int32 ln; int32 ln;
if (val) { /* set diag? */ if (val) { /* set diag? */
mux_detach (uptr); /* detach lines */ mux_detach (uptr); /* detach Telnet lines */
for (ln = 0; ln < TERM_COUNT; ln++) /* enable transmission */ for (ln = 0; ln < TERM_COUNT; ln++) /* enable transmission */
mux_ldsc[ln].xmte = 1; /* on all lines */ mux_ldsc[ln].xmte = 1; /* on all lines */
} }

View file

@ -1,6 +1,6 @@
SIMH/HP 2100 RELEASE NOTES SIMH/HP 2100 RELEASE NOTES
========================== ==========================
Last update: 2017-09-06 Last update: 2018-05-23
This file documents the release history of the simulator for the Hewlett-Packard 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. - 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. - 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 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 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. 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 QCTerm, an HP 700 terminal emulator for Microsoft Windows, is available from the
HP Computer Museum at: HP Computer Museum at:
@ -157,6 +178,259 @@ 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 Release 27, 2017-09-06
====================== ======================

View file

@ -1,7 +1,7 @@
/* hp2100_stddev.c: HP2100 standard devices simulator /* hp2100_stddev.c: HP2100 standard devices simulator
Copyright (c) 1993-2016, Robert M. Supnik 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 Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -29,6 +29,9 @@
TTY 12531C buffered teleprinter interface TTY 12531C buffered teleprinter interface
TBG 12539C time base generator TBG 12539C time base generator
27-Feb-18 JDB Added the BBL
22-Nov-17 JDB Fixed TTY serial output buffer overflow handling
18-Sep-17 JDB Changed PTR "DIAG" modifier to "DIAGNOSTIC"
03-Aug-17 JDB PTP and TTY now append to existing file data 03-Aug-17 JDB PTP and TTY now append to existing file data
18-Jul-17 JDB The PTR device now handles the IOERR simulation stop 18-Jul-17 JDB The PTR device now handles the IOERR simulation stop
11-Jul-17 JDB Renamed "ibl_copy" to "cpu_ibl" 11-Jul-17 JDB Renamed "ibl_copy" to "cpu_ibl"
@ -370,7 +373,7 @@ REG ptr_reg[] = {
}; };
MTAB ptr_mod[] = { MTAB ptr_mod[] = {
{ UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", NULL }, { UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAGNOSTIC", NULL },
{ UNIT_DIAG, 0, "reader mode", "READER", NULL }, { UNIT_DIAG, 0, "reader mode", "READER", NULL },
{ MTAB_XTD | MTAB_VDV, 1u, "SC", "SC", &hp_set_dib, &hp_show_dib, (void *) &ptr_dib }, { MTAB_XTD | MTAB_VDV, 1u, "SC", "SC", &hp_set_dib, &hp_show_dib, (void *) &ptr_dib },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, ~1u, "DEVNO", "DEVNO", &hp_set_dib, &hp_show_dib, (void *) &ptr_dib }, { MTAB_XTD | MTAB_VDV | MTAB_NMO, ~1u, "DEVNO", "DEVNO", &hp_set_dib, &hp_show_dib, (void *) &ptr_dib },
@ -710,69 +713,223 @@ return SCPE_OK;
} }
/* Paper tape reader bootstrap routine (HP 12992K ROM) */ /* Paper tape reader bootstrap loaders (BBL and 12992K).
const BOOT_ROM ptr_rom = { The Basic Binary Loader (BBL) performs three functions, depending on the
0107700, /*ST CLC 0,C ; intr off */ setting of the S register, as follows:
0002401, /* CLA,RSS ; skip in */
0063756, /*CN LDA M11 ; feed frame */ 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0006700, /* CLB,CCE ; set E to rd byte */ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
0017742, /* JSB READ ; get #char */ | C | - - - - - - - - - - - - - - | V |
0007306, /* CMB,CCE,INB,SZB ; 2's comp */ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
0027713, /* JMP *+5 ; non-zero byte */
0002006, /* INA,SZA ; feed frame ctr */ Where:
0027703, /* JMP *-3 */
0102077, /* HLT 77B ; stop */ C = Compare the paper tape to memory
0027700, /* JMP ST ; next */ V = Verify checksums on the paper tape
0077754, /* STA WC ; word in rec */
0017742, /* JSB READ ; get feed frame */ If bit 15 is set to 1, the loader will compare the absolute program on tape
0017742, /* JSB READ ; get address */ to the contents of memory. If bit 0 is set to 1, the loader will verify the
0074000, /* STB 0 ; init csum */ checksums of the absolute binary records on tape without altering memory. If
0077755, /* STB AD ; save addr */ neither bit is set, the loader will read the absolute program on the paper
0067755, /*CK LDB AD ; check addr */ tape into memory. Loader execution ends with one of the following halt
0047777, /* ADB MAXAD ; below loader */ instructions:
0002040, /* SEZ ; E =0 => OK */
0027740, /* JMP H55 */ * HLT 00 - a comparison error occurred; A = the tape value.
0017742, /* JSB READ ; get word */ * HLT 11 - a checksum error occurred; A/B = the tape/calculated value.
0040001, /* ADA 1 ; cont checksum */ * HLT 55 - the program load address would overlay the loader.
0177755, /* STA AD,I ; store word */ * HLT 77 - the end of tape was reached with a successful read.
0037755, /* ISZ AD */
0000040, /* CLE ; force wd read */ The 12992K boot loader ROM reads an absolute program on the paper tape into
0037754, /* ISZ WC ; block done? */ memory. The S register setting does not affect loader operation. Loader
0027720, /* JMP CK ; no */ execution ends with one of the following halt instructions:
0017742, /* JSB READ ; get checksum */
0054000, /* CPB 0 ; ok? */ * HLT 11 - a checksum error occurred; A/B = the calculated/tape value.
0027702, /* JMP CN ; next block */ * HLT 55 - the program load address would overlay the ROM loader.
0102011, /* HLT 11 ; bad csum */ * HLT 77 - the end of tape was reached with a successful read.
0027700, /* JMP ST ; next */
0102055, /*H55 HALT 55 ; bad address */ Note that the A/B register contents are in the opposite order of those in the
0027700, /* JMP ST ; next */ BBL when a checksum error occurs.
0000000, /*RD 0 */ */
0006600, /* CLB,CME ; E reg byte ptr */
0103710, /* STC RDR,C ; start reader */ static const LOADER_ARRAY ptr_loaders = {
0102310, /* SFS RDR ; wait */ { /* HP 21xx Basic Binary Loader (BBL) */
0027745, /* JMP *-1 */ 000, /* loader starting index */
0106410, /* MIB RDR ; get byte */ IBL_NA, /* DMA index (not used) */
0002041, /* SEZ,RSS ; E set? */ 072, /* FWA index */
0127742, /* JMP RD,I ; no, done */ { 0107700, /* 77700: START CLC 0,C */
0005767, /* BLF,CLE,BLF ; shift byte */ 0063770, /* 77701: LDA 77770 */
0027744, /* JMP RD+2 ; again */ 0106501, /* 77702: LIB 1 */
0000000, /*WC 000000 ; word count */ 0004010, /* 77703: SLB */
0000000, /*AD 000000 ; address */ 0002400, /* 77704: CLA */
0177765, /*M11 -11 ; feed count */ 0006020, /* 77705: SSB */
0, 0, 0, 0, 0, 0, 0, 0, /* unused */ 0063771, /* 77706: LDA 77771 */
0, 0, 0, 0, 0, 0, 0, /* unused */ 0073736, /* 77707: STA 77736 */
0000000 /*MAXAD -ST ; max addr */ 0006401, /* 77710: CLB,RSS */
0067773, /* 77711: LDB 77773 */
0006006, /* 77712: INB,SZB */
0027717, /* 77713: JMP 77717 */
0107700, /* 77714: CLC 0,C */
0102077, /* 77715: HLT 77 */
0027700, /* 77716: JMP 77700 */
0017762, /* 77717: JSB 77762 */
0002003, /* 77720: SZA,RSS */
0027712, /* 77721: JMP 77712 */
0003104, /* 77722: CMA,CLE,INA */
0073774, /* 77723: STA 77774 */
0017762, /* 77724: JSB 77762 */
0017753, /* 77725: JSB 77753 */
0070001, /* 77726: STA 1 */
0073775, /* 77727: STA 77775 */
0063775, /* 77730: LDA 77775 */
0043772, /* 77731: ADA 77772 */
0002040, /* 77732: SEZ */
0027751, /* 77733: JMP 77751 */
0017753, /* 77734: JSB 77753 */
0044000, /* 77735: ADB 0 */
0000000, /* 77736: NOP */
0002101, /* 77737: CLE,RSS */
0102000, /* 77740: HLT 0 */
0037775, /* 77741: ISZ 77775 */
0037774, /* 77742: ISZ 77774 */
0027730, /* 77743: JMP 77730 */
0017753, /* 77744: JSB 77753 */
0054000, /* 77745: CPB 0 */
0027711, /* 77746: JMP 77711 */
0102011, /* 77747: HLT 11 */
0027700, /* 77750: JMP 77700 */
0102055, /* 77751: HLT 55 */
0027700, /* 77752: JMP 77700 */
0000000, /* 77753: NOP */
0017762, /* 77754: JSB 77762 */
0001727, /* 77755: ALF,ALF */
0073776, /* 77756: STA 77776 */
0017762, /* 77757: JSB 77762 */
0033776, /* 77760: IOR 77776 */
0127753, /* 77761: JMP 77753,I */
0000000, /* 77762: NOP */
0103710, /* 77763: STC 10,C */
0102310, /* 77764: SFS 10 */
0027764, /* 77765: JMP 77764 */
0102510, /* 77766: LIA 10 */
0127762, /* 77767: JMP 77762,I */
0173775, /* 77770: STA 77775,I */
0153775, /* 77771: CPA 77775,I */
0100100, /* 77772: RRL 16 */
0177765, /* 77773: STB 77765,I */
0000000, /* 77774: NOP */
0000000, /* 77775: NOP */
0000000, /* 77776: NOP */
0000000 } }, /* 77777: NOP */
{ /* HP 1000 Loader ROM (12992K) */
IBL_START, /* loader starting index */
IBL_DMA, /* DMA index */
IBL_FWA, /* FWA index */
{ 0107700, /* 77700: ST CLC 0,C ; intr off */
0002401, /* 77701: CLA,RSS ; skip in */
0063756, /* 77702: CN LDA M11 ; feed frame */
0006700, /* 77703: CLB,CCE ; set E to rd byte */
0017742, /* 77704: JSB READ ; get #char */
0007306, /* 77705: CMB,CCE,INB,SZB ; 2's comp */
0027713, /* 77706: JMP *+5 ; non-zero byte */
0002006, /* 77707: INA,SZA ; feed frame ctr */
0027703, /* 77710: JMP *-3 */
0102077, /* 77711: HLT 77B ; stop */
0027700, /* 77712: JMP ST ; next */
0077754, /* 77713: STA WC ; word in rec */
0017742, /* 77714: JSB READ ; get feed frame */
0017742, /* 77715: JSB READ ; get address */
0074000, /* 77716: STB 0 ; init csum */
0077755, /* 77717: STB AD ; save addr */
0067755, /* 77720: CK LDB AD ; check addr */
0047777, /* 77721: ADB MAXAD ; below loader */
0002040, /* 77722: SEZ ; E =0 => OK */
0027740, /* 77723: JMP H55 */
0017742, /* 77724: JSB READ ; get word */
0040001, /* 77725: ADA 1 ; cont checksum */
0177755, /* 77726: STA AD,I ; store word */
0037755, /* 77727: ISZ AD */
0000040, /* 77730: CLE ; force wd read */
0037754, /* 77731: ISZ WC ; block done? */
0027720, /* 77732: JMP CK ; no */
0017742, /* 77733: JSB READ ; get checksum */
0054000, /* 77734: CPB 0 ; ok? */
0027702, /* 77735: JMP CN ; next block */
0102011, /* 77736: HLT 11 ; bad csum */
0027700, /* 77737: JMP ST ; next */
0102055, /* 77740: H55 HLT 55 ; bad address */
0027700, /* 77741: JMP ST ; next */
0000000, /* 77742: RD NOP */
0006600, /* 77743: CLB,CME ; E reg byte ptr */
0103710, /* 77744: STC RDR,C ; start reader */
0102310, /* 77745: SFS RDR ; wait */
0027745, /* 77746: JMP *-1 */
0106410, /* 77747: MIB RDR ; get byte */
0002041, /* 77750: SEZ,RSS ; E set? */
0127742, /* 77751: JMP RD,I ; no, done */
0005767, /* 77752: BLF,CLE,BLF ; shift byte */
0027744, /* 77753: JMP RD+2 ; again */
0000000, /* 77754: WC 000000 ; word count */
0000000, /* 77755: AD 000000 ; address */
0177765, /* 77756: M11 DEC -11 ; feed count */
0000000, /* 77757: NOP */
0000000, /* 77760: NOP */
0000000, /* 77761: NOP */
0000000, /* 77762: NOP */
0000000, /* 77763: NOP */
0000000, /* 77764: NOP */
0000000, /* 77765: NOP */
0000000, /* 77766: NOP */
0000000, /* 77767: NOP */
0000000, /* 77770: NOP */
0000000, /* 77771: NOP */
0000000, /* 77772: NOP */
0000000, /* 77773: NOP */
0000000, /* 77774: NOP */
0000000, /* 77775: NOP */
0000000, /* 77776: NOP */
0100100 } } /* 77777: MAXAD ABS -ST ; max addr */
}; };
/* Device boot routine.
This routine is called directly by the BOOT PTR and LOAD PTR 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 12992K 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 PTR device structure.
Depending on the current CPU model, the BBL or 12992K loader ROM will be
copied into memory and configured for the PTR 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 BBL or 12992K 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 12992K boot loader ROM, the S register will be set as follows:
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| ROM # | 0 0 | PTR select code | 0 0 0 0 0 0 |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
*/
t_stat ptr_boot (int32 unitno, DEVICE *dptr) t_stat ptr_boot (int32 unitno, DEVICE *dptr)
{ {
const int32 dev = ptr_dib.select_code; /* get device no */ if (dptr == NULL) /* if we are being called for a BOOT/LOAD CPU */
return cpu_copy_loader (ptr_loaders, unitno, /* then copy the boot loader to memory */
IBL_S_NOCLEAR, IBL_S_NOSET); /* but do not alter the S register */
cpu_ibl (ptr_rom, dev, IBL_S_CLR, /* copy the boot ROM to memory and configure */ else /* otherwise this is a BOOT/LOAD PTR */
IBL_PTR | IBL_SET_SC (dev)); /* the S register accordingly */ return cpu_copy_loader (ptr_loaders, ptr_dib.select_code, /* so copy the boot loader to memory */
IBL_S_CLEAR, IBL_S_NOSET); /* and configure the S register if 1000 CPU */
return SCPE_OK;
} }
@ -1132,23 +1289,23 @@ return SCPE_OK;
t_stat tto_svc (UNIT *uptr) t_stat tto_svc (UNIT *uptr)
{ {
int32 c;
t_stat r; t_stat r;
c = tty_buf; /* get char */ r = tto_out (tty_buf); /* output the character */
tty_buf = tty_shin; /* shift in */
tty_shin = 0377; /* line inactive */
r = tto_out (c); /* output the character */ if (r == SCPE_OK) { /* if the output succeeded */
tty_buf = tty_shin; /* then shift the input line into the buffer */
tty_shin = 0377; /* and set the input line to the marking state */
if (r != SCPE_OK) { /* if an error occurred */ ttyio (&tty_dib, ioENF, 0); /* set the flag */
sim_activate (uptr, uptr->wait); /* then schedule a retry */ return SCPE_OK; /* and return success */
return (r == SCPE_STALL ? SCPE_OK : r); /* report a stall as success */
} }
ttyio (&tty_dib, ioENF, 0); /* set flag */ else { /* otherwise an error occurred */
sim_activate (uptr, uptr->wait); /* so schedule a retry */
return SCPE_OK; return (r == SCPE_STALL ? SCPE_OK : r); /* report a stall as success */
}
} }

View file

@ -1,7 +1,7 @@
/* hp2100_sys.c: HP 2100 system common interface /* hp2100_sys.c: HP 2100 system common interface
Copyright (c) 1993-2016, Robert M. Supnik 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 Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -24,6 +24,9 @@
used in advertising or otherwise to promote the sale, use or other dealings used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from the authors. in this Software without prior written authorization from the authors.
07-Mar-18 JDB Added the GET_SWITCHES macro from scp.c
22-Feb-18 JDB Added the <dev> option to the LOAD command
07-Sep-17 JDB Replaced "uint16" cast with "MEMORY_WORD" for loader ROM
07-Aug-17 JDB Added "hp_attach" to attach a file for appending 07-Aug-17 JDB Added "hp_attach" to attach a file for appending
01-Aug-17 JDB Added "ispunct" test for implied mnemonic parse 01-Aug-17 JDB Added "ispunct" test for implied mnemonic parse
20-Jul-17 JDB Removed STOP_OFFLINE, STOP_PWROFF messages 20-Jul-17 JDB Removed STOP_OFFLINE, STOP_PWROFF messages
@ -108,6 +111,12 @@
/* Command-line switch parsing from scp.c */
#define GET_SWITCHES(cp) \
if ((cp = get_sim_sw (cp)) == NULL) return SCPE_INVSW
/* External I/O data structures */ /* External I/O data structures */
extern DEVICE mp_dev; /* Memory Protect */ extern DEVICE mp_dev; /* Memory Protect */
@ -1807,6 +1816,7 @@ static t_addr parse_addr (DEVICE *dptr, CONST char *cptr, CONST char **tptr)
static t_stat hp_exdep_cmd (int32 arg, CONST char *buf); static t_stat hp_exdep_cmd (int32 arg, CONST char *buf);
static t_stat hp_run_cmd (int32 arg, CONST char *buf); static t_stat hp_run_cmd (int32 arg, CONST char *buf);
static t_stat hp_brk_cmd (int32 arg, CONST char *buf); static t_stat hp_brk_cmd (int32 arg, CONST char *buf);
static t_stat hp_load_cmd (int32 arg, CONST char *buf);
/* System interface local utility routines */ /* System interface local utility routines */
@ -1953,6 +1963,8 @@ static CTAB aux_cmds [] = {
{ "BREAK", &hp_brk_cmd, 0, NULL }, { "BREAK", &hp_brk_cmd, 0, NULL },
{ "NOBREAK", &hp_brk_cmd, 0, NULL }, { "NOBREAK", &hp_brk_cmd, 0, NULL },
{ "LOAD", &hp_load_cmd, 0, NULL },
{ NULL } { NULL }
}; };
@ -2041,16 +2053,19 @@ t_stat sim_load (FILE *fptr, CONST char *cptr, CONST char *fnam, int flag)
const int reclen [2] = { TO_WORD (57, 0), /* the two DUMP record length words */ const int reclen [2] = { TO_WORD (57, 0), /* the two DUMP record length words */
TO_WORD (7, 0) }; TO_WORD (7, 0) };
const int reccnt [2] = { 57, 7 }; /* the two DUMP record word counts */ const int reccnt [2] = { 57, 7 }; /* the two DUMP record word counts */
BOOT_ROM loader; /* an array of 64 words */
int record, count, address, word, checksum; int record, count, address, word, checksum;
t_stat result; t_stat result;
int32 trailer = 1; /* > 0 while reading leader, < 0 while reading trailer */ int32 trailer = 1; /* > 0 while reading leader, < 0 while reading trailer */
HP_WORD select_code = 0; /* select code to configure; 0 implies no configuration */ HP_WORD select_code = 0; /* select code to configure; 0 implies no configuration */
LOADER_ARRAY boot = { /* an array of two BOOT_LOADER structures */
{ 000, IBL_NA, IBL_NA, { 0 } }, /* HP 21xx Loader */
{ IBL_START, IBL_DMA, IBL_FWA, { 0 } } /* HP 1000 Loader */
};
if (flag == 0) { /* if this is a LOAD command */ if (flag == 0) { /* if this is a LOAD command */
if (*cptr != '\0') { /* then if a parameter follows */ if (*cptr != '\0') { /* then if a parameter follows */
select_code = (HP_WORD) get_uint (cptr, 8, /* then parse it as an octal number */ select_code = /* then parse it as an octal number */
MAXDEV, &result); (HP_WORD) get_uint (cptr, 8, MAXDEV, &result);
if (result != SCPE_OK) /* if a parse error occurred */ if (result != SCPE_OK) /* if a parse error occurred */
return result; /* then report it */ return result; /* then report it */
@ -2059,8 +2074,6 @@ if (flag == 0) { /* if this is a LOAD com
return SCPE_ARG; /* then report a bad argument */ return SCPE_ARG; /* then report a bad argument */
} }
memset (loader, 0, sizeof loader); /* clear the boot loader ROM */
while (TRUE) { /* read absolute binary records from the file */ while (TRUE) { /* read absolute binary records from the file */
do { /* skip any blank leader or trailer present */ do { /* skip any blank leader or trailer present */
count = fgetc (fptr); /* get the next byte from the tape */ count = fgetc (fptr); /* get the next byte from the tape */
@ -2103,7 +2116,8 @@ if (flag == 0) { /* if this is a LOAD com
return SCPE_FMT; /* then the tape format is bad */ return SCPE_FMT; /* then the tape format is bad */
else { /* otherwise */ else { /* otherwise */
loader [address++] = (uint16) word; /* save the data word in the loader array */ boot [0].loader [address] = (MEMORY_WORD) word; /* save the data word in */
boot [1].loader [address++] = (MEMORY_WORD) word; /* both loader arrays */
checksum = checksum + word; /* and include it in the record checksum */ checksum = checksum + word; /* and include it in the record checksum */
} }
} }
@ -2121,8 +2135,8 @@ if (flag == 0) { /* if this is a LOAD com
trailer = -10; /* so prepare for a potential trailer */ trailer = -10; /* so prepare for a potential trailer */
} /* and loop until all records are read */ } /* and loop until all records are read */
cpu_ibl (loader, select_code, /* install the loader */ cpu_copy_loader (boot, select_code, /* install the loader */
IBL_S_NOCLR, IBL_S_NOSET); /* and configure the select code if requested */ IBL_S_NOCLEAR, IBL_S_NOSET); /* and configure the select code if requested */
} }
@ -3249,7 +3263,7 @@ while ((bitfmt.alternate || bitset) /* while more bits */
bnptr = bitfmt.names [index]; /* point at the name for the current bit */ bnptr = bitfmt.names [index]; /* point at the name for the current bit */
if (bnptr) /* if the name is defined */ if (bnptr) /* if the name is defined */
if (*bnptr == '\1') /* then if this name has an alternate */ if (*bnptr == '\1' && bitfmt.alternate) /* then if this name has an alternate */
if (bitset & test_bit) /* then if the bit is asserted */ if (bitset & test_bit) /* then if the bit is asserted */
bnptr++; /* then point at the name for the "1" state */ bnptr++; /* then point at the name for the "1" state */
else /* otherwise */ else /* otherwise */
@ -3854,6 +3868,62 @@ return brk_cmd (arg, buf); /* return the result of
} }
/* Execute the LOAD command.
This command is intercepted to permit a device boot routine to be loaded
into memory. The following command forms are valid:
LOAD <dev>
LOAD <filename> [ <select-code> ]
If the first form is used, and the device name is valid and bootable, the
corresponding boot loader is copied into memory in the highest 64 locations
of the logical address space. Upon return, the loader will have been
configured for the device's select code or for the device and paper tape
reader select codes, in the case of a dual-use 21xx boot loader, and the P
register will have been set to point at the start of the loader. The loader
then may be executed by a RUN command. If the device name is valid, but the
device is not bootable, or no boot loader exists for the current CPU
configuration, the command is rejected.
If the second form is used, the file containing a loader in absolute binary
form is read into memory and configured as above. See the "sim_load"
comments for details of this operation.
Implementation notes:
1. The "find_dev" routine requires that the device name be in upper case to
match. The "get_glyph" routine performs case-shifting on the input
buffer.
*/
static t_stat hp_load_cmd (int32 arg, CONST char *buf)
{
CONST char *cptr;
char cbuf [CBUFSIZE];
DEVICE *dptr = NULL;
GET_SWITCHES (buf); /* parse any switches present */
cptr = get_glyph (buf, cbuf, '\0'); /* parse a potential device name */
if (cbuf [0] != '\0') { /* if the name is present */
dptr = find_dev (cbuf); /* then see if it matches a device */
if (dptr != NULL) /* if it does */
if (dptr->boot == NULL) /* then if the device is not bootable */
return SCPE_NOFNC; /* then report "Command not allowed" */
else if (*cptr != '\0') /* otherwise if more characters follow */
return SCPE_2MARG; /* then report "Too many arguments" */
else /* otherwise the device name stands alone */
return dptr->boot (0, dptr); /* so load the corresponding boot loader */
}
return load_cmd (arg, buf); /* if it's not a device name, then try loading a file */
}
/* System interface local utility routines */ /* System interface local utility routines */

Binary file not shown.