- This release of the HP 3000 simulator adds the following device simulation: - 30209A Line Printer Controller with One 2607/13/17/18 Line Printer The simulation supports the use of custom VFU tape images, as well as the built-in HP-standard VFU tape. The simulated device name is "LP". The full set of configurable options is detailed in a new section of the HP 3000 Simulator User's Guide. In addition, the preconfigured MPE-V/R disc image has been updated to add the following features: - The MPE cold load command files attach the line printer to the "lp.txt" output file and specify the "-n" option to clear the file before use. - Preinstalled User-Defined Commands (UDCs) provide access to the COBOL 74 compiler with the MPE-V/E :COBOLII, :COBOLIIPREP, and :COBOLIIGO commands, and to the COBOL 85 compiler with :COBOLIIX, :COBOLIIXPREP, and :COBOLIIXGO. However, see the implementation note below. -------------------- Implementation Notes -------------------- - MPE requires a line printer, so it is recommended that the MPE startup simulator command file include an ATTACH LP <filename> command to load paper into the printer before cold loading. If the printer is not attached, it will appear to MPE to be out of paper. - The line printer terminates each print line with an HP-standard CR/LF pair. If the output file is to be retained as a text file on a Unix system, removal of the carriage returns, e.g., via the "dos2unix" utility, may be desirable. - The simulator currently does not provide the HP 32234A COBOL II firmware instructions, so programs generated by the COBOLII compiler will abort at run time with an "ILLEGAL INSTRUCTION" error. Programs generated by the COBOL compiler do not use these instructions and therefore are not affected. ---------- Bugs Fixed ---------- 1. PROBLEM: The effective address of a byte pointer with a negative index is calculated incorrectly. VERSION: Release 1 OBSERVATION: Defining a :WELCOME message in MPE appears to work, but when the next logon attempts to print the message, an infinite number of CRLFs are printed instead. CAUSE: The welcome message is stored in an extra data segment. The format for each message line is a line length stored in the lower byte of the word preceding the message string. The code defines BYTE POINTER NEXTLINE and points NEXTLINE to the first message character. The line length is set with NEXTLINE(-1) := IOCOUNT. This generates a LOAD <IOCOUNT> ; LDXN 1 ; STB <NEXTLINE>,I,X sequence. In the "cpu_ea" routine, the indexing adds the X register value (-1) to the byte pointer (NEXTLINE). This causes an overflow that is not masked to 16 bits. For a word access, this displacement is added to the base register and then masked to 16 bits, which gives the correct value. However, for byte accesses, the displacement is divided by 2 and then added, and the sum is masked. Dividing by 2 shifts the overflow bit into the MSB, causing the addition result to be off by 32K. The STB goes to the wrong location, the original zero in the length byte location is retained, and when the welcome message is printed, a zero-length line is printed, and the byte pointer is incremented by zero, so the null line is printed forever. RESOLUTION: Modify "cpu_ea" (hp3000_cpu.c) to mask indexed displacements to 16 bits after adding the X register value. STATUS: Fixed in Release 2. 2. PROBLEM: An SMSK instruction may clear the interrupt mask flip-flop of a device that specifies that it is should be "always enabled." VERSION: Release 1 OBSERVATION: If the TOS word is zero, an SMSK instruction will clear the interrupt mask flip-flop of a device whose mask jumper is set to "E" (always enabled). CAUSE: In response to a DSETMASK signal, device interfaces set their interrupt mask flip-flops by "anding" the incoming data word with the interrupt mask jumper setting. The jumper setting value for "always enabled" is %177777, which sets the mask flip-flop in all cases, except when the data word is zero. RESOLUTION: Modify hp3000_atc.c, hp3000_ds.c, and hp3000_ms.c to set their mask flip-flops unconditionally if the jumper setting is "E". STATUS: Fixed in Release 2. 3. PROBLEM: The "SET <dev> INTMASK=<n>" command sets the wrong bit in the device interface's interrupt mask jumper setting. VERSION: Release 1 OBSERVATION: The interrupt mask jumper on a device interface is set by specifying the mask bit number in a "SET <dev> INTMASK=<n>" command. This sets a bit in the device's interrupt mask jumper word corresponding to the bit number requested. However, the bit numbering is incorrect; setting the jumper for bit 15, for example, sets bit 0 of the jumper word. Therefore, the interface's mask flip-flop is not set as expected when an SMSK instruction is executed. CAUSE: The bit numbers were counted from the wrong end of the word. RESOLUTION: Modify "hp_set_dib" and "hp_show_dib" (hp3000_sys.c) to number the bits from the MSB instead of the LSB. STATUS: Fixed in Release 2. 4. PROBLEM: The Multiplexer Channel is not generating the ACKSR signal correctly. VERSION: Release 1 OBSERVATION: The line printer controller hangs when an SIO chained write is performed. The first programmed write completes normally, but the second does not start. The channel is waiting for a service request that does not occur. CAUSE: The service request from the last write of the first block transfer is being cleared by an ACKSR generated by the Multiplexer Channel when it performs the IOCW fetch in State A for the second write request. The channel should omit this ACKSR when the previous I/O order was a chained read or write. However, the simulator is testing the order just fetched (Write) instead of the order that has just completed (Write Chained). RESOLUTION: Modify "mpx_service" (hp3000_mpx.c) to test the correct I/O order in State A. STATUS: Fixed in Release 2.
365 lines
19 KiB
C
365 lines
19 KiB
C
/* hp3000_io.h: HP 3000 device-to-IOP/MPX/SEL interface declarations
|
|
|
|
Copyright (c) 2016, J. David Bryan
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
Except as contained in this notice, the name of the author shall not be used
|
|
in advertising or otherwise to promote the sale, use or other dealings in
|
|
this Software without prior written authorization from the author.
|
|
|
|
11-Jun-16 JDB Bit mask constants are now unsigned
|
|
21-Mar-16 JDB Changed type of inbound_value of CNTLR_INTRF to HP_WORD
|
|
20-Jan-16 JDB First release version
|
|
11-Dec-12 JDB Created
|
|
|
|
|
|
This file contains declarations used by I/O devices to interface with the HP
|
|
3000 I/O Processor, Multiplexer Channel, and Selector Channel. It is
|
|
required by any module that uses Device Information Blocks (DIBs).
|
|
*/
|
|
|
|
|
|
|
|
/* I/O bus signals.
|
|
|
|
The INBOUND_SIGNAL and OUTBOUND_SIGNAL declarations mirror the hardware
|
|
signals that are received and asserted, respectively, by the I/O interfaces
|
|
on the IOP, selector/multiplexer channel, and power buses. A set of one or
|
|
more signals forms an INBOUND_SET or OUTBOUND_SET that is sent to or returned
|
|
from a device interface. Under simulation, the IOP and channels dispatch one
|
|
INBOUND_SET to the target device interface per I/O cycle. The interface
|
|
returns a combined OUTBOUND_SET and data value to the caller.
|
|
|
|
Hardware allows parallel action for concurrent signals. Under simulation, a
|
|
"concurrent" set of signals is processed sequentially by the interface in
|
|
order of ascending numerical value.
|
|
|
|
In addition, some signals must be asserted asynchronously, e.g., in response
|
|
to an event service call. The IOP and channels provide asynchronous
|
|
assertion via function calls for the INTREQ, REQ, SRn, and CHANSR signals.
|
|
|
|
|
|
Implementation notes:
|
|
|
|
1. The enumerations describe signals. A set of signals normally would be
|
|
modeled as an unsigned integer, as a set may contain more than one
|
|
signal. However, we define a set as the enumeration, as the "gdb"
|
|
debugger has special provisions for an enumeration of discrete bit values
|
|
and will display the set in "ORed" form.
|
|
|
|
2. The null set -- NO_SIGNALS -- cannot be defined as an enumeration
|
|
constant because the C language has a single name space for all
|
|
enumeration constants, so separate "no inbound signals" and "no outbound
|
|
signals" identifiers would be required, and because including them would
|
|
require handlers for them in "switch" statements, which is undesirable.
|
|
Therefore, we define NO_SIGNALS as an explicit integer 0, so that it is
|
|
compatible with both enumerations.
|
|
|
|
3. Outbound signal values are restricted to the upper 16 bits to allow the
|
|
combined signal/data value to fit in 32 bits.
|
|
|
|
4. Inbound and outbound signal definitions are separated to allow for future
|
|
inbound expansion, if necessary.
|
|
|
|
5. In hardware, the IOP encodes direct I/O commands as a 3-bit IOCMD signal
|
|
set on the IOP bus. Each device interface decodes these signals into
|
|
individual strobes to control the logic. Under simulation, the IOCMD
|
|
values are decoded by the IOP into individual signals for inclusion in
|
|
the INBOUND_SIGNAL set that is passed to the interfaces.
|
|
|
|
6. The ACKSR signal must come before the programmed I/O and TOGGLESR
|
|
signals, as they may set an interface's Service Request flip-flop.
|
|
|
|
7. The READNEXTWD signal must come after PREADSTB, as the former overwrites
|
|
the input data word used by the latter.
|
|
|
|
8. The TOGGLEnXFER signals must come after PREADSTB and PWRITESTB and before
|
|
READNEXTWD, so that the strobes can test the interface's Device End
|
|
flip-flop before the toggles can reset it.
|
|
|
|
9. The EOT signal must come after PREADSTB and PWRITESTB and before the
|
|
TOGGLEnXFER signals. The former condition is required for the SCMB to
|
|
return the correct EOT count, and the latter is required for the DS to
|
|
set its End-of-Data flip-flop correctly.
|
|
|
|
10. The SETINT signal must come before, and the TOGGLESIOOK signal must come
|
|
after, the PSTATSTB signal so that the status of the interrupt request
|
|
and SIO Busy flip-flops can be reported correctly.
|
|
|
|
11. The CHANSO signal must come after all programmed I/O signals, as it is
|
|
used by channel devices to assert CHANSR when needed.
|
|
*/
|
|
|
|
#define NO_SIGNALS 0 /* a universal "no signals are asserted" value */
|
|
|
|
typedef enum { /* --- source of signal --- */
|
|
DSETINT = 000000000001, /* SIN instruction */
|
|
DCONTSTB = 000000000002, /* CIO instruction */
|
|
DSTARTIO = 000000000004, /* SIO instruction */
|
|
DWRITESTB = 000000000010, /* WIO instruction */
|
|
DRESETINT = 000000000020, /* IXIT instruction */
|
|
DSTATSTB = 000000000040, /* TIO instruction */
|
|
DSETMASK = 000000000100, /* SMSK instruction */
|
|
DREADSTB = 000000000200, /* RIO instruction */
|
|
ACKSR = 000000000400, /* Multiplexer SR response */
|
|
TOGGLESR = 000000001000, /* Read/Write/Control/End order */
|
|
SETINT = 000000002000, /* Interrupt/End channel order */
|
|
PCMD1 = 000000004000, /* Control channel order */
|
|
PCONTSTB = 000000010000, /* Control channel order */
|
|
SETJMP = 000000020000, /* Jump channel order */
|
|
PSTATSTB = 000000040000, /* Sense channel order */
|
|
PWRITESTB = 000000100000, /* Write channel order */
|
|
PREADSTB = 000000200000, /* Read channel order */
|
|
EOT = 000000400000, /* Read/Write channel order */
|
|
TOGGLEINXFER = 000001000000, /* Read channel order */
|
|
TOGGLEOUTXFER = 000002000000, /* Write channel order */
|
|
READNEXTWD = 000004000000, /* Read channel order */
|
|
TOGGLESIOOK = 000010000000, /* End channel order */
|
|
DEVNODB = 000020000000, /* Multiplexer DRT Fetch */
|
|
INTPOLLIN = 000040000000, /* IOP interrupt poll */
|
|
XFERERROR = 000100000000, /* Multiplexer channel abort */
|
|
CHANSO = 000200000000, /* Channel service call to interface */
|
|
PFWARN = 000400000000 /* SET CPU POWERFAIL */
|
|
/* = 001000000000 (available) */
|
|
/* = 002000000000 (available) */
|
|
/* = 004000000000 (available) */
|
|
/* = 010000000000 (available) */
|
|
/* = 020000000000 (available) */
|
|
} INBOUND_SIGNAL;
|
|
|
|
typedef INBOUND_SIGNAL INBOUND_SET; /* a set of INBOUND_SIGNALs */
|
|
|
|
|
|
typedef enum { /* --- destination of signal --- */
|
|
INTREQ = 000000200000, /* IOP, to request an external interrupt */
|
|
INTACK = 000000400000, /* IOP, to acknowledge an external interrupt request */
|
|
INTPOLLOUT = 000001000000, /* IOP, to clear an external interrupt request */
|
|
DEVEND = 000002000000, /* Channel, to terminate a read/write order */
|
|
JMPMET = 000004000000, /* Channel, to enable a Conditional Jump order */
|
|
CHANACK = 000010000000, /* Channel, to acknowledge interface call */
|
|
CHANSR = 000020000000, /* Selector channel, to request service */
|
|
SRn = 000040000000 /* Multiplexer channel, to request service */
|
|
/* = 000100000000 (available) */
|
|
/* = 000200000000 (available) */
|
|
/* = 000400000000 (available) */
|
|
/* = 001000000000 (available) */
|
|
/* = 002000000000 (available) */
|
|
/* = 004000000000 (available) */
|
|
/* = 010000000000 (available) */
|
|
/* = 020000000000 (available) */
|
|
} OUTBOUND_SIGNAL;
|
|
|
|
typedef OUTBOUND_SIGNAL OUTBOUND_SET; /* a set of OUTBOUND_SIGNALs */
|
|
|
|
|
|
typedef uint32 SIGNALS_DATA; /* a combined outbound signal set and data value */
|
|
|
|
|
|
/* I/O macros.
|
|
|
|
The following macros are useful in device interface signal handlers and unit
|
|
service routines. The parameter definition symbols employed are:
|
|
|
|
P = a priority set value
|
|
S = an INBOUND_SET or OUTBOUND_SET value
|
|
L = an INBOUND_SIGNAL value
|
|
D = an outbound 16-bit data value
|
|
C = a SIGNALS_DATA value
|
|
B = a DIB value
|
|
|
|
A priority set is an unsigned value, where each bit represents an assertion
|
|
of some nature (e.g., I/O signals, interrupt requests, etc.), and the
|
|
position of the bit represents its priority, which increases from LSB to MSB.
|
|
The IOPRIORITY macro isolates the highest-priority bit from the set. It does
|
|
this by ANDing the value with its two's complement; only the lowest-order bit
|
|
will differ. For example (bits are numbered here from the LSB):
|
|
|
|
priority set : ...0 0 1 1 0 1 0 0 0 0 0 0 (bits 6, 8, and 9 are asserted)
|
|
one's compl : ...1 1 0 0 1 0 1 1 1 1 1 1
|
|
two's compl : ...1 1 0 0 1 1 0 0 0 0 0 0
|
|
ANDed value : ...0 0 0 0 0 1 0 0 0 0 0 0 (bit 6 is highest priority)
|
|
|
|
If the request set indicates requests by 0 bits, rather than 1 bits, the
|
|
IOPRIORITY macro must be called with the one's complement of the bits.
|
|
|
|
The IONEXTSIG macro isolates the next inbound signal in sequence to process
|
|
from the inbound signal set S.
|
|
|
|
The IOCLEARSIG macro removes the processed signal L from the inbound signal
|
|
set S.
|
|
|
|
The IORETURN macro forms the 32-bit combined outbound signal set and data
|
|
value to be returned by an interface from the signal set S and the 16-bit
|
|
data value D.
|
|
|
|
The IOSIGNALS macro isolates the outbound signal set from a 32-bit combined
|
|
status and data value value C.
|
|
|
|
The IODATA macro isolates the 16-bit data value from a 32-bit combined signal
|
|
set and data value value C.
|
|
|
|
|
|
Implementation notes:
|
|
|
|
1. The IOPRIORITY macro implements two's complement explicitly, rather than
|
|
using a signed negation, to be compatible with machines using a
|
|
sign-magnitude integer format. "gcc" and "clang" optimize the complement
|
|
and add to a single NEG instruction on x86 machines.
|
|
*/
|
|
|
|
#define IOPRIORITY(P) ((P) & ~(P) + 1)
|
|
|
|
#define IONEXTSIG(S) ((INBOUND_SIGNAL) IOPRIORITY (S))
|
|
#define IOCLEARSIG(S,L) S = (INBOUND_SIGNAL) ((S) ^ (L))
|
|
|
|
#define IORETURN(S,D) ((SIGNALS_DATA) ((S) & ~D16_MASK | (D) & D16_MASK))
|
|
#define IOSIGNALS(C) ((OUTBOUND_SET) ((C) & ~D16_MASK))
|
|
#define IODATA(C) ((HP_WORD) ((C) & D16_MASK))
|
|
|
|
|
|
/* I/O structures.
|
|
|
|
The Device Information Block (DIB) allows devices to be relocated in the
|
|
machine's I/O space. Each DIB contains a pointer to the device controller
|
|
interface routine, values corresponding to hardware jumpers on the controller
|
|
(e.g., device number), and flip-flops that indicate the interrupt and channel
|
|
service states.
|
|
|
|
For fast access during I/O, interrupt, and channel service requests, devices
|
|
are accessed via indexed tables. The index employed depends on the
|
|
application. For example, I/O commands are routed via a table that is
|
|
indexed by device number. The tables are built during the instruction
|
|
execution prelude by scanning the DIBs of all devices and placing pointers to
|
|
the DIBs into the tables at the entries associated with the index values.
|
|
Between execution runs, the user may reassign device properties, so the
|
|
tables must be rebuilt each time.
|
|
|
|
|
|
Implementation notes:
|
|
|
|
1. The device number (DEVNO) bus is eight bits in width, and the CPU
|
|
microcode, the IOP, and the device controllers all support device numbers
|
|
up to 255. However, MPE limits the size of the device reference table to
|
|
correspond with a device number of 127, while the CPU reserves memory
|
|
that would correspond to device numbers 0-2. As a result, most device
|
|
controllers provide only seven-bit configurable device numbers. One
|
|
exception is the Selector Channel Maintenance Board. The Selector
|
|
Channel diagnostic tests programmable device numbers > 127, which the
|
|
SCMB provides via bits 8-15 of the counter/buffer register, although only
|
|
seven preset jumpers are provided to set the standard device number for
|
|
the board.
|
|
|
|
2. The device_number, service_request_number, and interrupt_priority fields
|
|
could be smaller than the defined 32-bit sizes, but IA-32 processors
|
|
execute instructions with 32-bit operands much faster than those with
|
|
16- or 8-bit operands.
|
|
*/
|
|
|
|
#define DEVNO_MAX 127 /* the maximum device number */
|
|
#define DEVNO_MASK 0177u /* the mask for the device number */
|
|
#define DEVNO_BASE 10 /* the radix for the device number */
|
|
#define DEVNO_UNUSED D32_UMAX /* the unused device number indicator */
|
|
|
|
#define INTMASK_MAX 15 /* the maximum interrupt mask number */
|
|
#define INTMASK_MASK 017u /* the mask for the interrupt mask number */
|
|
#define INTMASK_BASE 10 /* the radix for the interrupt mask number */
|
|
#define INTMASK_D 0000000u /* the interrupt mask disabled always value */
|
|
#define INTMASK_E 0177777u /* the interrupt mask enabled always value */
|
|
#define INTMASK_UNUSED D32_UMAX /* the unused interrupt mask indicator */
|
|
|
|
#define INTPRI_MAX 31 /* the maximum interrupt priority */
|
|
#define INTPRI_MASK 037u /* the mask for the interrupt priority */
|
|
#define INTPRI_BASE 10 /* the radix for the interrupt priority */
|
|
#define INTPRI_UNUSED D32_UMAX /* the unused interrupt priority indicator */
|
|
|
|
#define SRNO_MAX 15 /* the maximum service request number */
|
|
#define SRNO_MASK 017u /* the mask for the service request number */
|
|
#define SRNO_BASE 10 /* the radix for the service request number */
|
|
#define SRNO_UNUSED D32_UMAX /* the unused service request number indicator */
|
|
|
|
typedef struct dib DIB; /* an incomplete definition */
|
|
|
|
typedef SIGNALS_DATA CNTLR_INTRF /* the I/O device controller interface function prototype */
|
|
(DIB *dibptr, /* a pointer to the device information block */
|
|
INBOUND_SET inbound_signals, /* a set of inbound signals */
|
|
HP_WORD inbound_value); /* a 16-bit inbound value */
|
|
|
|
struct dib { /* the Device Information Block */
|
|
CNTLR_INTRF *io_interface; /* the controller I/O interface function pointer */
|
|
uint32 device_number; /* the device number 0-255 */
|
|
uint32 service_request_number; /* the service request number 0-15 */
|
|
uint32 interrupt_priority; /* the interrupt priority 0-31 */
|
|
uint32 interrupt_mask; /* the interrupt mask (16 bits) */
|
|
uint32 card_index; /* the card index if multiple interfaces are supported */
|
|
FLIP_FLOP interrupt_request; /* an interrupt has been requested */
|
|
FLIP_FLOP interrupt_active; /* an interrupt is active */
|
|
t_bool service_request; /* channel service has been requested */
|
|
};
|
|
|
|
|
|
/* Calibrated timer numbers */
|
|
|
|
#define TMR_PCLK 0 /* the CPU process clock timer */
|
|
#define TMR_CLK 1 /* the CLK system clock timer */
|
|
#define TMR_ATC 2 /* the ATC input polling timer */
|
|
|
|
|
|
/* CPU front panel command identifiers */
|
|
|
|
typedef enum {
|
|
Run, /* a run request */
|
|
Cold_Load, /* a cold load request */
|
|
Cold_Dump /* a cold dump request */
|
|
} PANEL_TYPE;
|
|
|
|
|
|
/* Global CPU state and functions */
|
|
|
|
extern UNIT *cpu_pclk_uptr; /* pointer to the process clock unit */
|
|
extern t_bool cpu_is_calibrated; /* TRUE if the process clock is calibrated */
|
|
|
|
extern void cpu_front_panel (HP_WORD switch_reg, /* set the front panel switches as directed */
|
|
PANEL_TYPE request);
|
|
|
|
|
|
/* Global asynchronous signal assertion functions */
|
|
|
|
extern void iop_assert_INTREQ (DIB *dib_pointer); /* assert the interrupt request signal */
|
|
|
|
extern void mpx_assert_REQ (DIB *dib_pointer); /* assert the multiplexer channel request signal */
|
|
extern void mpx_assert_SRn (DIB *dib_pointer); /* assert the multiplexer channel service request signal */
|
|
|
|
extern void sel_assert_REQ (DIB *dib_pointer); /* assert the selector channel request signal */
|
|
extern void sel_assert_CHANSR (DIB *dib_pointer); /* assert the selector channel service request signal */
|
|
|
|
|
|
/* Global channel state */
|
|
|
|
extern t_bool mpx_is_idle; /* TRUE if the multiplexer channel is idle */
|
|
extern t_bool sel_is_idle; /* TRUE if the selector channel is idle */
|
|
|
|
|
|
/* Global ATC state */
|
|
|
|
extern t_bool atc_is_polling; /* TRUE if the ATC is polling for the simulation console */
|
|
|
|
|
|
/* Global CLK functions */
|
|
|
|
extern void clk_update_counter (void); /* update the system clock counter register */
|