/* hp3000_io.h: HP 3000 device-to-IOP/IMB/MPX/SEL interface declarations

   Copyright (c) 2016-2022, 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.

   24-Nov-22    JDB     Added the DEVNO and TO_DRT macros
   06-Sep-22    JDB     Added "io_initializer" and "imb_interface" definitions
                        Renamed CNTLR_INTRF to IOP_INTERFACE
   30-Sep-18    JDB     Corrected typo in I/O macro comments
   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).
*/



/* 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;


/* IOP 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 */


/* IOP 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 decreases 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))


/* IOP limits.


   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.
*/

#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 */

#define IMBA_DEVNO          125                 /* assigned device number of the IMB Adapter */

#define DEVNO(w)            (w & DEVNO_MASK)    /* extract a device number from a word */

#define TO_DRT(w)           (DEVNO (w) * 4)     /* convert a device number to a DRT address */


/* Intermodule Bus limits */

#define BUS_MAX             7                   /* the maximum bus address */
#define BUS_MASK            007u                /* the mask for the bus address */
#define BUS_BASE            10                  /* the radix for the bus address */
#define BUS_UNUSED          D32_UMAX            /* the unused bus address indicator */

#define CHAN_MAX            15                  /* the maximum channel number */
#define CHAN_MASK           017u                /* the mask for the channel number */
#define CHAN_BASE           10                  /* the radix for the channel number */
#define CHAN_UNUSED         D32_UMAX            /* the unused channel number indicator */

#define SLOT_MAX            15                  /* the maximum slot number */
#define SLOT_MASK           017u                /* the mask for the slot number */
#define SLOT_BASE           10                  /* the radix for the slot number */
#define SLOT_UNUSED         D32_UMAX            /* the unused slot number indicator */

#define IA_WIDTH            24                          /* IMB address bit width */
#define IA_MASK             ((1u << IA_WIDTH) - 1)      /* IMB address mask (2 ** 24 - 1) */
#define IA_MAX              ((1u << IA_WIDTH) - 1)      /* IMB address maximum (2 ** 24 - 1) */

typedef uint32              IMB_ADDRESS;        /* the IMB address bus type */
typedef HP_WORD             IMB_DATA;           /* the IMB data bus type */


/* Intermodule Bus signals.

   The IMB_INBOUND_SIGNAL and IMB_OUTBOUND_SIGNAL declarations mirror the
   hardware signals that are received and asserted, respectively, by the I/O
   interfaces on the Intermodule Bus.  A set of one or more signals forms an
   IMB_INBOUND_SET or IMB_OUTBOUND_SET that is sent to or returned from a device
   interface.  Under simulation, IMB cycles dispatch one IMB_INBOUND_SET to the
   target device interface per cycle.  The interface returns a combined
   IMB_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.  Asynchronous assertion is provided via function
   calls for the CSRQ1 and IRQ 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. Inbound and outbound signal definitions are separated to allow for future
       expansion, if necessary.
*/

typedef enum {                                  /* IMB inbound signals */
    BRQ           = 000000000001,               /*   Bus Request */
    ADO           = 000000000002,               /*   Address Do */
    DDO           = 000000000004,               /*   Data Do */
    WAIT          = 000000000010,               /*   Wait */
    SRST          = 000000000020,               /*   System Reset */
    PON           = 000000000040,               /*   Power On */
    PFW           = 000000000100,               /*   Power Fail Warning */
    PRI           = 000000000200                /*   Priority In */
/*                = 000000000400,                    (available) */
/*                = 000000001000,                    (available) */
/*                = 000000002000,                    (available) */
/*                = 000000004000,                    (available) */
/*                = 000000010000,                    (available) */
/*                = 000000020000,                    (available) */
/*                = 000000040000,                    (available) */
/*                = 000000100000,                    (available) */
/*                = 000000200000,                    (available) */
/*                = 000000400000,                    (available) */
/*                = 000001000000,                    (available) */
/*                = 000002000000,                    (available) */
/*                = 000004000000,                    (available) */
/*                = 000010000000,                    (available) */
/*                = 000020000000,                    (available) */
/*                = 000040000000,                    (available) */
/*                = 000100000000,                    (available) */
/*                = 000200000000,                    (available) */
/*                = 000400000000                     (available) */
/*                = 001000000000                     (available) */
/*                = 002000000000                     (available) */
/*                = 004000000000                     (available) */
/*                = 010000000000                     (available) */
/*                = 020000000000                     (available) */
    } IMB_INBOUND_SIGNAL;

typedef IMB_INBOUND_SIGNAL  IMB_INBOUND_SET;    /* a set of IMB_INBOUND_SIGNALs */


typedef enum {                                  /* IMB outbound signals */
    BACK          = 000000000001,               /*   Bus Acknowledge */
    ADN           = 000000000002,               /*   Address Done */
    DDN           = 000000000004,               /*   Data Done */
    IRQ           = 000000000010,               /*   Interrupt Request */
    CSRQ1         = 000000000020,               /*   Channel Service Request 1 */
    CSRQ2         = 000000000040,               /*   Channel Service Request 2 */
    DNV           = 000000000100,               /*   Data Not Valid */
    PER           = 000000000200,               /*   Parity Error */
    PRO           = 000000000400,               /*   Priority Out */
    PCRY          = 000000001000                /*   Priority Carry */
/*                = 000000002000,                    (available) */
/*                = 000000004000,                    (available) */
/*                = 000000010000,                    (available) */
/*                = 000000020000,                    (available) */
/*                = 000000040000,                    (available) */
/*                = 000000100000,                    (available) */
/*                = 000000200000,                    (available) */
/*                = 000000400000,                    (available) */
/*                = 000001000000,                    (available) */
/*                = 000002000000,                    (available) */
/*                = 000004000000,                    (available) */
/*                = 000010000000,                    (available) */
/*                = 000020000000,                    (available) */
/*                = 000040000000,                    (available) */
/*                = 000100000000,                    (available) */
/*                = 000200000000,                    (available) */
/*                = 000400000000                     (available) */
/*                = 001000000000                     (available) */
/*                = 002000000000                     (available) */
/*                = 004000000000                     (available) */
/*                = 010000000000                     (available) */
/*                = 020000000000                     (available) */
    } IMB_OUTBOUND_SIGNAL;

typedef IMB_OUTBOUND_SIGNAL  IMB_OUTBOUND_SET;  /* a set of IMB_OUTBOUND_SIGNALs */


/* IMB operation codes and commands.

   The three-bit opcode bus of the IMB defines six operations; the other two are
   undefined.  For the I/O Read and I/O Write opcodes, the upper four bits of
   the address bus contain command codes that specify the I/O operation to
   perform.  The read and write command code spaces are separate, and only seven
   and six of the sixteen possible commands, respectively, are assigned.  The
   LSB of the command code is always zero.


   Implementation notes:

    1. The Memory Read/Write Ones and Memory Write Control/Read Status opcodes
       are included in the enumeration but are not currently implemented.

    2. The I/O command enumeration takes advantage of the unused LSB to
       differentiate between read and write commands, arbitrarily assigning LSB
       = 0 to the read commands and LSB = 1 to the write commands. This allows
       the commands to be specified unambiguously.  When a command enumerator is
       converted to the command field of the address bus, the LSB is set to
       zero.  Conversion from the command field to the enumerator assigns the
       LSB as appropriate.
*/

typedef enum {                                  /* IMB operation codes */
    IMB_Read     = 0,                           /*   Memory Read */
    IMB_RW_Ones  = 1,                           /*   Memory Read/Write Ones */
    IMB_Write    = 2,                           /*   Memory Write */
    IMB_IO_Read  = 4,                           /*   I/O Read */
    IMB_Memory   = 5,                           /*   Memory Write Control/Read Status */
    IMB_IO_Write = 6                            /*   I/O Write */
    } IMB_OPCODE;


typedef enum {                                  /* IMB I/O commands */
    RIOC  = 000,                                /*   Read I/O Data */
    OBII  = 002,                                /*   Obtain Interrupt Information */
    OBSI  = 004,                                /*   Obtain Service Information */
    IPOLL = 010,                                /*   Interrupt Poll */
    ROCL  = 012,                                /*   Roll Call */
    SPOL1 = 014,                                /*   Service Poll 1 */
    SPOL2 = 016,                                /*   Service Poll 2 */

    WIOC  = 001,                                /*   Write I/O Data */
    INIT  = 003,                                /*   Initialize Channel */
    SIOP  = 005,                                /*   Start I/O Program */
    HIOP  = 007,                                /*   Halt I/O Program */
    SMSK  = 011,                                /*   Set Interrupt Mask */
    IOCL  = 013                                 /*   I/O Clear */
    } IMB_IO_COMMAND;

#define IS_WRITE_COMMAND(c) ((t_bool) (c) & 1)  /* TRUE if the command is an I/O write command */


/* IOP and IMB 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, a pointer to the IMB interface routine, an optional
   pointer to an execution-time initialization 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.

   A hardware interface that connects only to the IOP or IMB buses sets its DIB
   "io_interface" or "imb_interface" pointer, respectively, with the other
   pointer set to NULL.  Only the HP 30340A Intermodule Bus Adapter card
   connects to both and so sets both pointers.


   Implementation notes:

    1. 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.

    2. The DIB_REGS macro provides hidden register entries needed to save and
       restore the state of a DIB.  Only the potentially variable fields are
       referenced.  In particular, the pointer fields must not be saved, as the
       addresses of the pointer targets may change from version to version of
       the simulator.
*/

typedef struct dib          DIB;                /* an incomplete definition */

typedef SIGNALS_DATA IOP_INTERFACE              /* the IOP 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 */

typedef t_bool IO_INITIALIZER                   /* the I/O initializer function prototype */
    (DEVICE  *dptr,                             /*   a pointer to the device being initialized */
     DIB     *dibptr);                          /*   a pointer to the device information block being initialized */

typedef struct {                                /* the inbound IMB representation */
    IMB_OPCODE       opcode;                    /*   the operation code */
    IMB_ADDRESS      address;                   /*   the address */
    IMB_DATA         data;                      /*   the inbound data value */
    IMB_INBOUND_SET  signals;                   /*   the set of inbound signals */
    } IMB_INBOUND;

typedef struct {                                /* the outbound IMB representation */
    IMB_DATA          data;                     /*   the outbound data value */
    IMB_OUTBOUND_SET  signals;                  /*   the set of outbound signals */
    } IMB_OUTBOUND;

typedef IMB_OUTBOUND  IMB_INTERFACE             /* the IMB interface function prototype */
    (DIB          *dibptr,                      /*   a pointer to the device information block */
     IMB_INBOUND  inbound);                     /*   the inbound bus representation */


struct dib {                                    /* the Device Information Block */
    IOP_INTERFACE   *io_interface;              /*   the device's IOP interface function pointer */
    IO_INITIALIZER  *io_initializer;            /*   the execution initializer 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 */

    IMB_INTERFACE   *imb_interface;             /*   the device's IMB interface function pointer */
    uint32          channel_number;             /*   the IMB channel number 1-15 */
    uint32          slot_number;                /*   the IMB slot number */
    };


#define DIB_REGS(dib) \
/*    Macro   Name     Location                    Width  Flags   */ \
/*    ------  -------  --------------------------  -----  ------- */ \
    { DRDATA (DIBDEV,  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 }, \
    { DRDATA (DIBCHAN, dib.channel_number,          32),  REG_HRO }, \
    { DRDATA (DIBSLOT, dib.slot_number,             32),  REG_HRO }


/* Global CPU state and functions */

extern UNIT  *cpu_pclk_uptr;                            /* a 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 */
