/* 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. | |
12-Sep-16 JDB Added the DIB_REGS macro | |
02-Sep-16 JDB Added the iop_assert_PFWARN routine | |
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 /* POWER FAIL command */ | |
/* = 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. | |
3. The DIB_REGS macro provides hidden register entries needed to save and | |
restore the state of a DIB. Only the potentially variable fields are | |
referenced. In particular, the "io_interface" field must not be saved, | |
as the address of the device's interface routine may change from version | |
to version of the simulator. | |
*/ | |
#define 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 */ | |
}; | |
#define DIB_REGS(dib) \ | |
/* Macro Name Location Width Flags */ \ | |
/* ------ ------- -------------------------- ----- ------- */ \ | |
{ DRDATA (DIBDN, dib.device_number, 32), REG_HRO }, \ | |
{ DRDATA (DIBSRN, dib.service_request_number, 32), REG_HRO }, \ | |
{ DRDATA (DIBPRI, dib.interrupt_priority, 32), REG_HRO }, \ | |
{ ORDATA (DIBMASK, dib.interrupt_mask, 32), REG_HRO }, \ | |
{ ORDATA (DIBIRQ, dib.interrupt_request, 32), REG_HRO }, \ | |
{ ORDATA (DIBACT, dib.interrupt_active, 32), REG_HRO }, \ | |
{ ORDATA (DIBSR, dib.service_request, 32), REG_HRO } | |
/* 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 CPU 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 iop_assert_PFWARN (void); /* assert the power failure warning 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 */ |