/* hp3000_gic.c: HP 3000 31262A General I/O Channel simulator

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

   GIC          31262A General I/O Channel

   09-Jun-23    JDB     First release
   03-Jun-23    JDB     COLOSSUS passes with multiple drives
   15-Feb-23    JDB     CS80DIAG passes
   07-Feb-23    JDB     GICDIAG passes
   07-Nov-22    JDB     First MPE CS/80 system disc use
   31-Oct-22    JDB     First MPE CS/80 foreign disc use
   01-Jun-22    JDB     Created

   References:
     - HP 13255 HP-IB Interface Module
         (13255-91128, April 1979) [pp. 20 to 41]
     - HP 3000 Series 40/44 Computer Systems Reference/Training Manual
         (30090-90001, July 1981) [pp. 7-21 to 7-39]
     - HP 3000 Series 39/40/42/44/48 Computer Systems Engineering Diagrams Set
         (30090-90034, October 1984) [pp. 3-30 to 3-35]
     - "PHI, the HP-IB Interface Chip"
         (HP Journal, July 1978) [pp. 16 to 17]
     - "A Computer Input/Output System Based on the HP Interface Bus"
         (HP Journal, July 1979) [pp. 9 to 13]


   The HP 31262A General I/O Channel (GIC) is a component of the 30341A HP-IB
   Interface Module ("Starfish").  It is installed in the Starfish chassis and
   serves as the gateway between the Series III and the Hewlett-Packard
   Interface Bus (HP-IB).

   Each GIC provides a Processor to HP-IB (PHI) chip that acts as the bus
   controller to manage up to eight connected devices.  Each device may be from
   a different protocol class (disc vs. tape vs. printer, CS/80 vs. Amigo).
   Although in hardware there are restrictions on the type and number of devices
   that may be connected to a single GIC, those restrictions are not present in
   simulation.

   In addition to the PHI, each GIC contains a DMA sequencer, a watchdog timer,
   and bus request and handshake circuitry.  It connects to the Intermodule Bus
   and decodes 13 IMB commands:

     Mnemonic  Opcode  Command  Operation
     --------  ------  -------  ----------------------------
       RIOC     100     0000    Read I/O Data
       OBII     100     0010    Obtain Interrupt Information
       OBSI     100     0100    Obtain Service Information
       IPOLL    100     1000    Interrupt Poll
       ROCL     100     1010    Roll Call
       SPOL1    100     1100    Service Poll 1
       SPOL2    100     1110    Service Poll 2
       WIOC     110     0000    Write I/O Data
       INIT     110     0010    Initialize Channel
       SIOP     110     0100    Start I/O Program
       HIOP     110     0110    Halt I/O Program
       SMSK     110     1000    Set Interrupt Mask
       IOCL     110     1010    I/O Clear

   INIT, IOCL, and the IMB SRST (Soft Reset) signal all cause the GIC to reset
   its internal state to the power-on condition.

   Five hardware switches are present on the GIC PCA.  They control the
   following aspects of the GIC hardware:

                        Normal
     Switch   Choices   Setting  Action
     ------  ---------  -------  -----------------------
       S1     CPU/CPP     CPU    Asserts CSRQ1
       S2       A/B        A     Denies HYBRID
       S3     OFF/ON      ON     Asserts SCTRL to PHI
       S4      0-15       11     Sets the channel number
       S5    OPER/TEST   OPER    Denies DIAGSW

   The normal settings are used for MPE operation.  The alternates are used only
   when running the GIC diagnostic.

   The GIC has sixteen addressable registers -- eight provided by the PHI, and
   eight provided by the DMA sequencer.  The sequencer is a state machine with
   27 states; the current five-bit state number is presented as bits 3-7 of
   Register 8.  Once the target device is addressed to talk or listen and the
   DMA sequencer is configured with the starting address, byte count, and
   direction, the GIC is able to transfer the entire block to or from main
   memory without CPU intervention.  Transfers are performed with IMB memory
   read and write cycles.  For the Starfish, these are handled by the IMBA,
   which passes the requests through to a dedicated Series III port controller
   that interfaces to main memory.

   There is an additional register that is addressed indirectly.  The New Status
   register is eight bits wide, and each addressable bit is set or cleared in
   response to a four-bit field within the IMB SIOP and HIOP commands.  Setting
   a bit in the register causes the GIC to assert a channel service request to
   the processor, which in turn begins execution of the Channel Program
   Processor microcode.  This stimulus is an indication that the CPU has changed
   the channel program execution status, e.g., from stopped to running or vice
   versa, and that the CPP should begin or end channel operations on the GIC.

   The GIC inverts register address bit 1 (bit 6 of the Command / Register /
   Channel IMB command word), so that this mapping occurs:

     IMB Register  PHI Register  IMB Register Description
     ------------  ------------  -------------------------------
          0             2        FIFO
          1             3        Status
          2             0        Interrupt Conditions
          3             1        Interrupt Mask
          4             6        Parallel Poll Mask
          5             7        Parallel Poll Sense
          6             4        Control
          7             5        Address
          8             -        DMA Extended Address
          9             -        DMA Address
          A             -        DMA Byte Count
          B             -        DMA Status/Control
          C             -        Interrupt Register
          D             -        Interrupt Information
          E             -        Channel Configuration/DMA Abort
          F             -        Channel Service Information

   The 264x manual and the GIC schematic both show the PHI part number as
   1AA6-6004.  However, the descriptions of the registers does not always agree.
   Comments in the 264x manual suggest that the description in the Series 4x
   manual describes an earlier revision of the PHI chip, although why they
   should have the same part number is unclear.  Differences between the manuals
   are noted in the following register descriptions.

   The PHI registers (0-7) are each 10 bits wide.  The PHI bus is connected to
   present these as a 16-bit value on bits 0-1 and 8-15, respectively.

   The 16 registers are structured as follows:

   Register 0 - FIFO

       0 | 1   2   3 | 4   5   6 | 7   8   9 |10  11  12 |13  14  15
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | 0   0 | -   -   -   -   -   - |    parallel poll responses    | read
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | 0   1 | -   -   -   -   -   - | 0   0 | T |     secondary     | read
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | 0   0 | -   -   -   -   -   - |           data byte           | read
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | 1   0 | -   -   -   -   -   - |        final data byte        | read
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | 1   1 | -   -   -   -   -   - |       tagged data byte        | read
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

       0 | 1   2   3 | 4   5   6 | 7   8   9 |10  11  12 |13  14  15
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | E | 0 | -   -   -   -   -   - |           data byte           | write
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | 0   1 | -   -   -   -   -   - | 0 |   bus interface command   | write
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | L | 0 | -   -   -   -   -   - |         receive count         | write
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | 1   1 | -   -   -   -   -   - | 0   0   0   0   0   0   0   0 | write
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | 1   1 | -   -   -   -   -   - | 0 |       receive count       | write
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | 1   1 | -   -   -   -   -   - | 1 |        send count         | write
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

   Where:

     T = Talk secondary
     E = Tag byte with EOI
     L = Inhibit LF detection

   The PHI has an eight-byte outbound FIFO and an eight-byte inbound FIFO.

   If the inbound FIFO is empty and a read is performed, then if the PHI is the
   controller and has been conducting a parallel poll for at least two
   microseconds, then the poll responses will be read, masked and normalized by
   Registers 4 and 5.  Otherwise, an indeterminate value is returned, and bit 9
   (handshake abort) of Register 2 is set.

   Data bytes are received into the FIFO only when the PHI is addressed to
   listen.  Secondaries are received only when the preceding bus command is is a
   Talk or Listen that addresses the PHI.  If the inbound FIFO is full, the PHI
   holds off the handshake (NDAC asserted) until a byte has been read by the
   host.

   Bits 0 and 1 of the FIFO word indicate a the type of byte received -- a
   secondary, a data byte that is not the last byte of a transfer, a data byte
   that is the final byte of a counted transfer, or a data byte that is tagged
   with EOI or is a LF (if enabled).

   If the outbound FIFO is full and a write is performed, the FIFO contents are
   not altered, and and bit 9 (handshake abort) of Register 2 is set.  If the
   outbound FIFO is empty while PHI is not the controller and is addressed to
   talk, the bus remains idle until a byte is written to the FIFO.  If either
   the Outbound data freeze bit in Register 1 or the Device Clear bit in
   Register 2 is set, the FIFO will not be unloaded to the bus until both bits
   are cleared.  Neither bit can set if the PHI is the controller.  However, if
   either is set when the PHI becomes the controller, FIFO unloads are held off
   as before.

   When the outbound FIFO is empty, the PHI conducts a continuous parallel poll.
   Bit 10 (parallel poll response) of Register 2 is set if any device responds
   affirmatively during the poll.  The poll terminates when a byte is written to
   the FIFO.

   The outbound FIFO is cleared when bit 15 (clear outbound FIFO) of Register 6
   is set or the Soft Reset pin (pin 15, PON) is low.  When the FIFO is cleared,
   a parallel poll begins immediately, asserting ATN and EOI.  Caution must be
   exercised if a data byte is on the bus at that time, as it may be
   misinterpreted as a command.

   Bytes written to the FIFO are interpreted by the PHI in one of six modes,
   with bits 0 and 1 of each word partially indicating the mode.

   If the PHI is not the controller and is addressed to talk (mode 1), then data
   bytes are sent over the bus, optionally tagged with EOI.  If the PHI is also
   addressed to listen, the bytes are loaded back into the inbound FIFO.
   However, bits 0 and 1 will be undefined, i.e., will not contain the last byte
   indicators.

   If the PHI is the controller and is addressed to talk (mode 2), then a bus
   interface command may be sent over the bus.  The PHI will assert ATN with the
   command and will assert odd parity on DIO8 automatically.

   If the PHI is the controller and has addressed another device to talk,
   reception may be configured to end on a byte count or LF reception (mode 3),
   or only when a byte tagged with EOI is received (mode 4); they represent
   counted and uncounted transfer enables, respectively.  The words remove the
   ATN assertion after the Talk command when they are unloaded from the FIFO.
   The PHI will automatically terminate either transfer when a byte tagged with
   EOI is received.  Counted transfers additionally terminate when a LF
   character is received (if the inhibit bit is clear) or the number of bytes in
   the count field is received (a zero count specifies a 256-byte transfer).

   Modes 5 and 6 are deprecated in the terminal interface manual but appear in
   the Series 4x manual.  They are implemented by the PHI for backward
   compatibility.


   Register 1 - Status

       0 | 1   2   3 | 4   5   6 | 7   8   9 |10  11  12 |13  14  15
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | 0   0   0   0   0   0   0   0 | -   - | R | C | S | T | L | F | read
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | -   -   -   -   -   -   -   -   -   -   -   -   -   -   - | F | write
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

   Where:

     R = PHI is in remote mode
     C = PHI is the controller
     S = PHI is the system controller
     T = PHI is addressed to talk
     L = PHI is addressed to listen
     F = Outbound data freeze

   The data freeze bit is set whenever a byte enters the inbound FIFO.  While it
   is set, it prevents data being sent from the outbound FIFO.  Writing a 1 to
   this bit while the inbound FIFO is empty clears the freeze.

   NOTE: Bits 0 and 1 are stated as reading as zeros in the terminal interface
   manual but as ones in the Series 4x manual.


   Register 2 - Interrupt Conditions

       0 | 1   2   3 | 4   5   6 | 7   8   9 |10  11  12 |13  14  15
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | I | P | 0   0   0   0   0   0 | C | H | R | S | F | D | E | L | read
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | - | P | -   -   -   -   -   - | C | H | -   -   -   -   - | L | write
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

   Where:

     I = Interrupt pending (OR of the other bits after masking)
     P = Parity error detected on received command
     C = Status has changed
     H = Processor handshake aborted due to FIFO overflow/underflow
     R = Parallel poll response is present
     S = Service Request (SRQ) is asserted on the bus
     F = Outbound FIFO is not full
     D = Data available in the inbound FIFO
     E = Outbound FIFO is empty
     L = Device Clear (DCL) universal command has been received

   Each bit in the register is associated with a particular interrupting
   condition but can be unconditionally masked off by setting the corresponding
   bit in Register 3.  Bit 0 is the OR of the other bits after masking; when
   set, the PHI asserts IRQ continuously until the interrupt is reset, either by
   writing a 1 to the indicated bits, or by clearing or masking off the
   resulting condition.


   Register 3 - Interrupt Mask

       0 | 1   2   3 | 4   5   6 | 7   8   9 |10  11  12 |13  14  15
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | I | P | 0   0   0   0   0   0 | C | H | R | S | F | D | E | L | read
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | I | P | -   -   -   -   -   - | C | H | R | S | F | D | E | L | write
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

   Where:

     I = Enable all interrupts
     P = Enable parity errors
     C = Enable status changes
     H = Enable FIFO overflows/underflows
     R = Enable parallel poll responses
     S = Enable Service Requests (SRQ)
     F = Enable outbound FIFO space available
     D = Enable data available
     E = Enable outbound FIFO empty
     L = Enable Device Clears (DCL)

   Writing a 0 to a given bit masks that interrupt source.  The corresponding
   bit in Register 2 will read 0 while it is masked.  Writing a 0 to bit 0 masks
   all interrupts.  Register 3 is cleared when the PHI SRST (soft reset) line is
   asserted.


   Register 4 - Parallel Poll Mask

       0 | 1   2   3 | 4   5   6 | 7   8   9 |10  11  12 |13  14  15
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | 0   0   0   0   0   0   0   0 |  parallel poll response mask  | read
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | -   -   -   -   -   -   -   - |  parallel poll response mask  | write
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

   Each mask bit is ANDed with the corresponding parallel poll response received
   over the bus.  A mask bit of 0 prevents recognition of the poll response.

   Note that bits 8-15 correspond to HP-IB signal lines DIO8-DIO1, which
   correspond to poll responses from bus addresses 0-7, respectively.

   NOTE: Bits 0 and 1 are stated as reading as zeros in the terminal interface
   manual but as ones in the Series 4x manual.


   Register 5 - Parallel Poll Sense

       0 | 1   2   3 | 4   5   6 | 7   8   9 |10  11  12 |13  14  15
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | 0   0   0   0   0   0   0   0 | parallel poll response sense  | read
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | -   -   -   -   -   -   -   - | parallel poll response sense  | write
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

   Each sense bit is XORed with the corresponding parallel poll response
   received over the bus.  A mask bit of 1 reverses the poll response sense
   (i.e., a 0 bit on the bus represents a request for service).

   Note that bits 8-15 correspond to HP-IB signal lines DIO8-DIO1, which
   correspond to poll responses from bus addresses 0-7, respectively.

   NOTE: Bits 0 and 1 are stated as reading as zeros in the terminal interface
   manual but as ones in the Series 4x manual.


   Register 6 - Control

       0 | 1   2   3 | 4   5   6 | 7   8   9 |10  11  12 |13  14  15
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | 0   0   0   0   0   0   0   0 | B | F | R | I | P | S | D | C | read
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | 0   0 | -   -   -   -   -   - | B | F | R | I | P | S | D | C | write
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

   Where:

     B = 8-bit processor
     F = Parity freeze
     R = Remote Enable (REN) bus line
     I = Interface Clear (IFC) bus line
     P = Set Parallel Poll response
     S = Service Request (SRQ) bus line
     D = DMA direction (0/1 = inbound/outbound)
     C = Clear outbound FIFO

   NOTE: Bits 0 and 1 are stated as reading as zeros in the terminal interface
   manual but as ones in the Series 4x manual.

   NOTE: Bits 8 and 9 are shown as "must be written as 0" in the terminal
   manual.  This corresponds to "16-bit processor" and "accept incorrect parity"
   functions.


   Register 7 - HP-IB Address

       0 | 1   2   3 | 4   5   6 | 7   8   9 |10  11  12 |13  14  15
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | 0   0   0   0   0   0   0   0 | O | T | L |    bus address    | read
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | 0   0 | -   -   -   -   -   - | O | T | L |    bus address    | write
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

   Where:

     O = PHI is online
     T = PHI is talk always
     L = PHI is listen always

   NOTE: Bits 0 and 1 are stated as reading as zeros in the terminal interface
   manual but as ones in the Series 4x manual.


   Register 8 - DMA Extended Address

       0 | 1   2   3 | 4   5   6 | 7   8   9 |10  11  12 |13  14  15
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | E | 0   0 |     DMA state     |      upper address bits       | read
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | 0   0   0   0   0   0   0   0 |      upper address bits       | write
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

   Where:

     E = DMA is enabled

   Specifies the upper 8 bits (bank number) of the 24 bit transfer word address.
   Bit 0 indicates the state of the DMA Enable flip-flop.  The DMA State value
   is the address supplied to the DMA ROM state machine.


   Register 9 - DMA Address

       0 | 1   2   3 | 4   5   6 | 7   8   9 |10  11  12 |13  14  15
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     |                      lower address bits                       | read/write
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

   Specifies the lower 16 bits of the 24 bit transfer word address.  The
   register is incremented once for each two data bytes transferred.  When the
   transfer ends, the register will contain the address of the byte following
   the final byte transferred.  The register is updated and may be read during
   transfers.


   Register A - DMA Byte Count

       0 | 1   2   3 | 4   5   6 | 7   8   9 |10  11  12 |13  14  15
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     |                          byte count                           | read/write
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

   Specifies the number of bytes to transfer (a value of 0 means 64KB).  The
   register is decremented for each byte transferred.  If a transfer completes,
   the value will be zero.  Otherwise, it will be the number of bytes not
   transferred when the abort occurred.


   Register B - DMA Status/Control

       0 | 1   2   3 | 4   5   6 | 7   8   9 |10  11  12 |13  14  15
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | I | P | V | T | 0 | stat  | B | C | R | E | D | S |  Device   | read
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | 0   0   0   0   0   0   0 | A | C | R | E | D | G |  Device   | write
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

   Where:

     I = PHI interrupt
     P = Parity error
     V = Address overflow
     T = Memory timeout
     B = DMA busy
     C = Inhibit CSRQ on parallel poll
     R = Right-hand byte
     E = Inhibit EOI on the last byte
     D = DMA direction (0/1 = inbound/outbound)
     S = Diagnostic switch position (0/1 = OPERATE/TEST)

     A = Disable address increment / assert SRQ (only when S5 = TEST)
     G = Diagnostic disabled (only when S5 = TEST)

   Status:

     00 = ~DMASTATA * ~DMASTATB
     01 = ~DMASTATA *  DMASTATB
     10 =  DMASTATA * ~DMASTATB
     11 =  DMASTATA *  DMASTATB

   Writing sets DMA control parameters and starts DMA.  Bit 7 (A) must be 0 to
   allow the DMA address register to increment.  Bit 8 (C) disables CSRQ
   assertion when a parallel poll response is detected (see page 7-32 of the
   Series 44 RTM).  It is copied from the Record/Burst Mode bit in the DMA
   instruction configuration, so it is set for Burst Mode (is this so that a
   higher-priority poll response does not interrupt a set of burst transfers,
   which if allowed would lead to overruns/underruns?).

   Bit 10 (E) = 1 inhibits DMA from asserting EOI when the byte count reaches
   zero.

   Reading obtains DMA status.  DMASTATA and DMASTATB represent the states of
   the corresponding flip-flops at the end of a transfer.  They have the
   following significance:

     Status    Flip-Flop States        Read        Write
     ------  --------------------- -----------   ---------
       00    ~DMASTATA * ~DMASTATB  tagged byte  DMA count
       01    ~DMASTATA *  DMASTATB  final byte   (unused)
       10     DMASTATA * ~DMASTATB  DMA count    (unused)
       11     DMASTATA *  DMASTATB  abort        abort

   The DMA count terminations are implied.  For reads, the condition occurs only if
   DMA ended after receiving a normal data byte.  For writes, the condition is
   the default if a DMA abort did not occur.


   Register C - Interrupt Register

       0 | 1   2   3 | 4   5   6 | 7   8   9 |10  11  12 |13  14  15
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | 0   0   0   0   0   0   0   0 |   device interrupt requests   | read
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | -   -   -   -   -   -   -   -   -   -   -   - | S |  device   | write
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

   Where:

     S = Set interrupt request for specified device number

   Setting a device IRQ bit will cause the GIC to assert the IMB IRQ signal if
   the interrupt mask bit is set.


   Register D - Interrupt Information

       0 | 1   2   3 | 4   5   6 | 7   8   9 |10  11  12 |13  14  15
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | 0   0   0   0   0   0   0   0 | N |    channel    |  device   | read
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

   Where:

     N = Channel and device numbers are not valid

   This register is read in response to an Obtain Interrupt Information (OBII)
   IMB command.  The N bit is set if no device has an interrupt request pending.


   Register E - Channel Configuration/DMA Abort

       0 | 1   2   3 | 4   5   6 | 7   8   9 |10  11  12 |13  14  15
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | 0 | H | C | 0   0   0   0   0   0   0   0   0 | 0   0   0   0 | read
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | 0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0 | write
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

   Where:

     H = Hybrid (switch S2 position 0/1 = A/B)
     C = CPU/CPP (switch S1 position 0/1 = CPU/CPP)

   Writing to this register aborts the current DMA operation.  Reading this
   register reports the position of the configuration switches S1 and S2 and the
   channel ID.  Bits 12-15 supply the channel identifier, which is 0 for the
   GIC.


   Register F - Channel Service Information

       0 | 1   2   3 | 4   5   6 | 7   8   9 |10  11  12 |13  14  15
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | 0   0   0 | T | A | S | V | H | N |    Channel    |  Device   | read
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | 0   0   0   0   0   0   0 | A | C | R | E | D | G |  Device   | write
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

   Where:

     T = Timeout
     A = DMA abort
     S = SRQ request (always 0 for GIC Revision D)
     V = Device request
     H = Channel request (including DMA completion)
     N = Channel and device numbers are not valid

     A = Disable address increment / assert SRQ (only when S5 = TEST)
     C = Disable CSRQ for parallel polls
     R = Right-hand byte
     E = EOI disabled
     D = DMA direction (0/1 = inbound/outbound)
     G = Diagnostic disabled (only when S5 = TEST)

   This register is read in response to an Obtain Service Information (OBSI) IMB
   command.  The N bit is set if no device has a channel service request
   pending.  Writing to this register is the same as writing to Register B,
   except that DMA is not started.

   A Device Request is indicated when the New Status register has a bit set, or
   when the PHI is asserting a bit on its data lines for a parallel poll and
   OBSIDN is asserted.


   A one-second watchdog timer is used to ensure that the channel does not hang
   if a bus device stops communicating with the PHI.  It consists of an astable
   555 timer running at 15 Hz and a 4-bit binary down counter that sets a
   flip-flop to assert the TIMEOUT signal when the counter underflows.  This
   signal causes a DMA abort (identical to writing to Register E), forces a PHI
   interrupt and thus a channel request, and presents on bit 3 of Register F.
   The timer is inhibited by DIAG signal assertion, which occurs when switch S5
   is in the TEST position and bit 12 of Register B or F is zero.

   If DMA is active, then each DMA cycle will reset the counter to its initial
   state.  Should a DMA cycle hang, the timer will eventually expire.  The timer
   is also cleared each time channel service is requested, unless it was for a
   timeout.  Finally, an I/O clear will reset the timer.

   The timer is also released to run when bit 8 of Register F is set.  This is
   done before initiating HP-IB Identify sequences and ensures that sending an
   Identify to an absent device address will not hang the channel.


   Implementation notes:

    1. The GIC device can be cloned.  Although the Starfish is designed to host
       only a single GIC, MPE V/R can employ more than one.  Two GICs are needed
       to run the GIC diagnostic.  The clone count is limited by the available
       channel numbers (14).

    2. Setting the GIC device to DIAGNOSTIC mode connects it to one end of an
       HP-IB cable.  The other end is connected to the next GIC device also in
       DIAGNOSTIC mode.  This satisfies the GIC diagnostic criteria.

    3. The PHI chip can be configured to act as a device controller rather than
       the bus controller, and the GIC diagnostic tests this capability.
       However, for MPE, the PHI is always both the system controller and the
       controller-in-charge.

    4. The following features of the PHI-as-controller are not implemented:

        - SRQ asserted on bus by a device and serial poll
        - 8-bit processor and high-order bit access
        - DMA FIFO select

       The following features of the PHI-as-device are not implemented:

        - Amigo ID response
        - command with even parity received interrupt
        - outbound data freeze DCL inhibit
        - parity freeze control option

    5. It might appear that routines that take "gic_id" and derive "dptr",
       "gic", and "phi" locally might be more efficient if passed the latter as
       parameters instead.  However, the code involved in stacking the extra
       parameters at each call outweighs the code within the routine to derive
       the values locally.
*/



#include "hp3000_defs.h"
#include "hp3000_mem.h"
#include "hp3000_io.h"
#include "hp3000_imb.h"                         /* must be included after hp3000_io.h */
#include "hp3000_gic.h"



/* Program constants */

#define CHANNEL_COUNT       (CHAN_MAX + 1)      /* number of separate IMB channel addresses */

#define MAX_GIC_COUNT       (CHANNEL_COUNT - 2) /* count of potential GIC assignments */

#define GIC_CHANNEL         11                  /* default GIC channel number */
#define CIC_ADDRESS         30                  /* PHI controller address */

#define TIMEOUT_PERIOD      S (1)               /* DMA operation timeout delay */
#define NRFD_PERIOD         uS (4)              /* NRFD holdoff clearance delay */

#define Timeout_Unit        0                   /* DMA timeout unit number */
#define NRFD_Unit           1                   /* NRFD holdoff unit number */

#define LF                  012                 /* ASCII line feed */


/* Common per-unit state variables */

#define Instance            u3                  /* timeout unit instance identifier */

#define Channel             u3                  /* NRFD unit channel number */
#define Address             u4                  /* NRFD unit bus address */


/* Device flags and accessors.

   DEV_V_UF + 15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
             +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
             | - | - | - | - | - | - | - | - | - | - | - | P | T | S | M | D |
             +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

   Where:

     P = S1 Processor switch (0/1 = CPU/CPP)
     T = S2 Device Type switch (0/1 = A/B)
     S = S3 System Controller switch (0/1 = ON/OFF)
     M = S5 Mode switch (0/1 = OPER/TEST)
     D = diagnostic cable is connected
*/

#define DEV_CPP             BIT (DEV_V_UF + 4)  /* (P) processor is CPP */
#define DEV_TYPE_B          BIT (DEV_V_UF + 3)  /* (T) device type is B */
#define DEV_NOT_SYS         BIT (DEV_V_UF + 2)  /* (S) system controller is off */
#define DEV_TEST            BIT (DEV_V_UF + 1)  /* (M) mode is test */
#define DEV_DIAG            BIT (DEV_V_UF + 0)  /* (D) diagnostic cable is connected */


/* First-in first-out memory declarations.

   The PHI contains independent inbound and outbound FIFOs between the data bus
   and the HP-IB.  Each of the two FIFOs is 10 bits wide and 8 words deep and
   accepts eight bits of data plus two "tag" bits that associate actions with
   the data words.  The tag bits are necessary to ensure that the actions are
   coordinated with the data bytes when they emerge after falling through the
   FIFO.

   In simulation, they are implemented as circular arrays of 32-bit unsigned
   integers organized as follows:

      15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     |  tag  | -   -   -   -   -   - |           data byte           |
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

   Read (inbound) tag:

     00 = data byte or parallel poll response
     01 = bus command secondary (ATN was asserted)
     10 = final data byte terminating a counted transfer
     11 = EOI or LF terminating a counted or uncounted transfer

   Write (outbound) tag:

     00 = data byte or counted transfer with LF detection
     01 = bus command (ATN is asserted)
     10 = data byte + EOI or counted transfer without LF detection
     11 = uncounted transfer

   Commands written to Register 0 (outbound FIFO) while the PHI is not addressed
   to talk and tagged with values 00, 10, or 11 are interpreted as transfer
   configurations.  Interpretations are applied when the word(s) are unloaded
   from the FIFO.
*/

#define FIFO_MODES          2                   /* two FIFOs (inbound and outbound) */
#define FIFO_SIZE           8                   /* each FIFO is eight words deep */

#define FIFO_TAG(w)         BITS_TO (15, 14, w) /* extract the tag bits */
#define FIFO_DATA(w)        BITS_TO ( 7,  0, w) /* extract the data bits */


typedef enum {                                  /* FIFO mode selector */
    Inbound,                                    /*   inbound FIFO is selected */
    Outbound                                    /*   outbound FIFO is selected */
    } FIFO_MODE;

static const char *mode_names [] = {            /* FIFO mode selector names */
    "inbound",                                  /*   inbound FIFO */
    "outbound"                                  /*   outbound FIFO */
    };

typedef enum {                                  /* FIFO action selector */
    Load,                                       /*   FIFO loading is selected */
    Unload                                      /*   FIFO unloading is selected */
    } FIFO_ACTION;

static const char *action_names [] = {          /* FIFO action selector names */
    "loaded into",                              /*   load a byte into the FIFO */
    "unloaded from"                             /*   unload a byte from the FIFO */
    };


/* PHI state structure declarations.

   The PHI state structure collects all of the PHI-specific state.  This
   structure is included as part of the GIC state structure.


   Implementation notes:

    1. The PHI_REGISTER and GIC_REGISTER enumerations both define identifiers
       with values 0 to 7.  These are used to index into the PHI and GIC
       register arrays.  However, because C enumerators are all of type "int",
       the compiler will not catch the use of a PHI enumerator to index into the
       GIC register array, or vice versa.  Hopefully, the names will help
       reinforce their usage.

    2. The REGISTER enumeration defines identifiers with values 0 to 15.  These
       are used to specify a register for use.  However, they are not intended
       to be used to index into the PHI and GIC register arrays, although the
       first eight REGISTER enumerators map 1:1 to the PHI_REGISTER values.
*/

typedef enum {                                  /* PHI register index */
    Phi_0 = 0,                                  /*   FIFO */
    Phi_1,                                      /*   Status */
    Phi_2,                                      /*   Interrupt Conditions */
    Phi_3,                                      /*   Interrupt Mask */
    Phi_4,                                      /*   Parallel Poll Mask */
    Phi_5,                                      /*   Parallel Poll Sense */
    Phi_6,                                      /*   Control */
    Phi_7                                       /*   HP-IB Address */
    } PHI_REGISTER;

typedef enum {                                  /* GIC register index */
    Gic_8 = 0,                                  /*   DMA Extended Address */
    Gic_9,                                      /*   DMA Address */
    Gic_A,                                      /*   DMA Byte Count */
    Gic_B,                                      /*   DMA Status/Control */
    Gic_C,                                      /*   Interrupt Register */
    Gic_D,                                      /*   Interrupt Information */
    Gic_E,                                      /*   Channel Configuration/DMA Abort */
    Gic_F                                       /*   Channel Service Information */
    } GIC_REGISTER;

typedef struct {                                /* PHI state */
    HP_WORD    registers [8];                   /*   registers 0-7 */
    BUS_CABLE  bus;                             /*   bus control and data state */
    uint32     talker;                          /*   bus address of the talker */
    uint32     listeners;                       /*   bus address bitmap of the listeners */
    uint32     address;                         /*   bus address of the PHI */
    t_bool     serial_poll_active;              /*   TRUE if a serial poll is enabled */
    t_bool     poll_configure;                  /*   TRUE if parallel poll configuration is enabled */
    t_bool     poll_active;                     /*   TRUE if a parallel poll is in progress */
    BUS_DATA   poll_response;                   /*   configured PHI poll response */
    BUS_DATA   response_set;                    /*   set of parallel poll responses */
    BUS_DATA   command;                         /*   last bus command */
    uint32     byte_count;                      /*   reception byte count */
    t_bool     tag_lf;                          /*   TRUE if tagging reception of a line feed character */
    uint32     fifo [FIFO_MODES] [FIFO_SIZE];   /*   inbound and outbound FIFOs */
    uint32     fifo_count [FIFO_MODES];         /*   inbound and outbound FIFO occupancy counters */
    } PHI_STATE;


/* GIC state structure declarations.

   The GIC state structure collects all of the card-specific state.  This
   structure is replicated when multiple GIC instances are created.


   Implementation notes:

    1. The "interrupts" and "new_status" fields are kept in C bit order, rather
       than HP bit order, for ease of processing.

    2. The "irq_mask" field has the bit corresponding to the channel number set
       if the same bit was set in the SMSK instruction.  It is equivalent to the
       Mask Bit flip-flop in hardware.

    3. The "dma_run" and "dma_busy" fields correspond in hardware to the DMAENF
       signal and the -DMINACT signal, respectively.  DMAENF denies when the DMA
       transfer completes, but the DMA state machine does not return to the idle
       state until the CSRQ has been acknowledged with an OBSI.  DMA is inactive
       when dma_busy is FALSE.

    4. The DMA clock counter is 0 for automatic operation and 1-3 for single
       stepping during diagnostics.

    5. The dispatcher array has two extra elements to hold a cross-connected GIC
       entry for diagnostics and a trailing NULL in lieu of a dispatcher count.

    6. When the PHI is offline, devices present on the bus are not affected by
       changes to the bus state.  The separate "gic_dispatcher" pointer into the
       dispatch table provides this capability by bypassing the other protocol
       handlers, which always precede the GIC handler(s) in the table,
*/

typedef enum {                                  /* DMA cycle termination reasons */
    End_of_Cycle,                               /*   normal end of the cycle */
    Parity_Error,                               /*   abort for a parity error */
    Address_Overflow,                           /*   abort for an address overflow */
    Memory_Timeout                              /*   abort for a memory timeout */
    } DMA_STOP;

typedef enum {                                  /* channel request reasons */
    DMA_Interrupt    = 001,                     /*   DMA interrupt request */
    PHI_Interrupt    = 002,                     /*   PHI interrupt request */
    Status_Interrupt = 004                      /*   New Status interrupt request */
    } GIC_IRQ;

typedef struct {                                    /* GIC state */
    PHI_STATE     phi;                              /*   PHI */
    HP_WORD       registers [8];                    /*   registers 8-15 */
    HP_WORD       interrupts;                       /*   set of device interrupt requests */
    HP_WORD       irq_mask;                         /*   interrupt request mask channel bit */
    HP_WORD       new_status;                       /*   New Status register */
    GIC_IRQ       channel_requests;                 /*   set of CSRQ assertion reasons */
    t_bool        dma_run;                          /*   TRUE if DMA is active */
    t_bool        dma_busy;                         /*   TRUE if DMA is not idle */
    t_bool        dma_obsi;                         /*   TRUE if OBSI has acknowledged the DMA CSRQ */
    t_bool        dma_frozen;                       /*   TRUE if the address is not incremented */
    uint32        dma_status;                       /*   DMA end status */
    uint32        dma_address;                      /*   linear (bank and offset) DMA address */
    uint32        dma_count;                        /*   DMA byte count remaining */
    HP_WORD       dma_buffer;                       /*   DMA word buffer */
    uint32        dma_tag;                          /*   DMA FIFO tag */
    uint32        dma_state;                        /*   DMA execution state */
    uint32        dma_clock;                        /*   DMA clock counter */
    BUS_DISPATCH  dispatcher [Protocol_Count + 2];  /*   protocol dispatcher */
    BUS_DISPATCH  *gic_dispatcher;                  /*   pointer to the GIC dispatcher table entry */
    REG           *fifo_reg  [FIFO_MODES];          /*   inbound and outbound FIFO index register pointers */
    t_bool        header_printed;                   /*   TRUE if the bus trace header has been printed */
    } GIC_STATE;


/* Multiple instance structure declarations */

typedef struct {                                /* GIC card instance structure */
    DEVICE     *dptr;                           /*   a pointer to the device instance */
    GIC_STATE  *sptr;                           /*   a pointer to the state instance */
    } CARD_ENTRY;


/* Trace structure declarations.

   These structures are used to assist the trace routines.


   Implementation notes:

    1. The format for Register 8 defines an alternate for bit 0 when reading but
       no alternate when writing.  This suppresses the "DMA disabled/enabled"
       indicator for a write, as that bit is not defined for writing.

    2. The write format for Register B defines a dummy bit (bit 8).  This is
       used to print "start DMA" to indicate that DMA is activated by writing to
       the register.

    3. Writing to Register E aborts DMA; the value written is irrelevant.
*/

/* Trace CSRQ assertion reason declarations */

static const BITSET_NAME csrq_names [] = {      /* Channel service request reason names */
    "DMA completion",                           /*   bit 0 */
    "PHI interrupt",                            /*   bit 1 */
    "New Status change"                         /*   bit 2 */
    };

static const BITSET_FORMAT csrq_format =        /* names, offset, direction, alternates, bar */
    { FMT_INIT (csrq_names, 0, lsb_first, no_alt, no_bar) };


/* Trace FIFO action declarations */

typedef enum {                                  /* outbound data tags (disambiguated) */
    Tag_Data,                                   /*   R0_MODE_DATA */
    Tag_EOI_Data,                               /*   R0_MODE_TAGGED */
    Tag_Command,                                /*   R0_MODE_COMMAND */
    Tag_Uncounted,                              /*   R0_MODE_UNCOUNTED */
    Tag_Counted,                                /*   R0_MODE_COUNTED */
    Tag_LF_Counted                              /*   R0_MODE_LF_COUNTED */
    } OUTBOUND_TAG;

static const char *inbound_tags [4] = {         /* inbound FIFO tags, indexed by R0_MODE */
    "Data byte",                                /*   R0_MODE_DATA */
    "Secondary",                                /*   R0_MODE_SECONDARY */
    "Final data byte",                          /*   R0_MODE_FINAL */
    "Tagged data byte"                          /*   R0_MODE_TAGGED */
    };

static const char *outbound_fmts [] = {                 /* outbound FIFO formats, indexed by OUTBOUND_TAG */
    "Data byte %03o %s %s %u\n",                        /*   Tag_Data */
    "EOI | data byte %03o %s %s %u\n",                  /*   Tag_EOI_Data */
    "Command byte %03o %s %s %u\n",                     /*   Tag_Command */
    "Enable reception uncounted%.0o %s %s %u\n",        /*   Tag_Uncounted */
    "Enable reception count %u %s %s %u\n",             /*   Tag_Counted */
    "LF | enable reception count %u %s %s %u\n"         /*   Tag_LF_Counted */
    };


/* Trace register read and write declarations */

typedef enum {                                  /* register format index selector */
    Read  = 0,                                  /*   read format */
    Write = 1                                   /*   write format */
    } FORMAT_MODE;

typedef BITSET_FORMAT BITSET_ARRAY [2];         /* an array of read and write formats */

static const char *register_0_tags [] = {       /* Register 0 read tags, indexed by R0_MODE */
    "",                                         /*   R0_MODE_DATA */
    "",                                         /*   R0_MODE_SECONDARY */
    "Final | ",                                 /*   R0_MODE_FINAL */
    "Tagged | "                                 /*   R0_MODE_TAGGED */
    };

static const char *register_0_fmts [] = {       /* Register 0 write formats, indexed by OUTBOUND_TAG */
    "Data %03o sent to bus\n",                  /*   Tag_Data */
    "Data EOI | %03o sent to bus\n",            /*   Tag_EOI_Data */
    "Data ATN | %03o sent to bus\n",            /*   Tag_Command */
    "Reception enabled%.0u\n",                  /*   Tag_Uncounted */
    "Reception enabled for count %u\n",         /*   Tag_Counted */
    "Reception enabled for LF | count %u\n"     /*   Tag_LF_Counted */
    };


/* Register 0 is handled independently */

static const BITSET_NAME R1_names [] = {        /* Register 1 bit names */
    "remote",                                   /*   bit 10 */
    "controller",                               /*   bit 11 */
    "system controller",                        /*   bit 12 */
    "talker",                                   /*   bit 13 */
    "listener",                                 /*   bit 14 */
    "frozen"                                    /*   bit 15 */
    };

static const BITSET_ARRAY R1_format =           /* names, offset, direction, alternates, bar */
    { { FMT_INIT (R1_names, 0, msb_first, no_alt, no_bar) },
      { FMT_INIT (R1_names, 0, msb_first, no_alt, no_bar) } };


static const BITSET_NAME R23_names [] = {       /* Registers 2 and 3 bit names */
    "IRQ",                                      /* bit  0 */
    "parity error",                             /* bit  1 */
    NULL,                                       /* bit  2 */
    NULL,                                       /* bit  3 */
    NULL,                                       /* bit  4 */
    NULL,                                       /* bit  5 */
    NULL,                                       /* bit  6 */
    NULL,                                       /* bit  7 */
    "status change",                            /* bit  8 */
    "FIFO abort",                               /* bit  9 */
    "poll response",                            /* bit 10 */
    "SRQ",                                      /* bit 11 */
    "available",                                /* bit 12 */
    "data",                                     /* bit 13 */
    "empty",                                    /* bit 14 */
    "DCL"                                       /* bit 15 */
    };

static const BITSET_ARRAY R23_format =         /* names, offset, direction, alternates, bar */
    { { FMT_INIT (R23_names, 0, msb_first, no_alt, no_bar) },
      { FMT_INIT (R23_names, 0, msb_first, no_alt, no_bar) } };


static const BITSET_NAME R45_names [] = {       /* Registers 4 and 5 bit names */
    "PP 0",                                     /*   bit  8 */
    "PP 1",                                     /*   bit  9 */
    "PP 2",                                     /*   bit 10 */
    "PP 3",                                     /*   bit 11 */
    "PP 4",                                     /*   bit 12 */
    "PP 5",                                     /*   bit 13 */
    "PP 6",                                     /*   bit 14 */
    "PP 7"                                      /*   bit 15 */
    };

static const BITSET_ARRAY R45_format =         /* names, offset, direction, alternates, bar */
    { { FMT_INIT (R45_names, 0, msb_first, no_alt, no_bar) },
      { FMT_INIT (R45_names, 0, msb_first, no_alt, no_bar) } };


static const BITSET_NAME R6_names [] = {        /* Register 6 bit names */
    "8 bit",                                    /*   bit  8 */
    "parity freeze",                            /*   bit  9 */
    "REN",                                      /*   bit 10 */
    "IFC",                                      /*   bit 11 */
    "poll response",                            /*   bit 12 */
    "SRQ",                                      /*   bit 13 */
    "\1DMA outbound\0DMA inbound",              /*   bit 14 */
    "clear FIFO"                                /*   bit 15 */
    };

static const BITSET_ARRAY R6_format =          /* names, offset, direction, alternates, bar */
    { { FMT_INIT (R6_names, 0, msb_first, has_alt, no_bar) },
      { FMT_INIT (R6_names, 0, msb_first, has_alt, no_bar) } };


static const BITSET_NAME R7_names [] = {        /* Register 7 bit names */
    "\1online\0offline",                        /*   bit  8 */
    "talk always",                              /*   bit  9 */
    "listen always"                             /*   bit 10 */
    };

static const BITSET_ARRAY R7_format =          /* names, offset, direction, alternates, bar */
    { { FMT_INIT (R7_names, 5, msb_first, has_alt, append_bar) },
      { FMT_INIT (R7_names, 5, msb_first, has_alt, append_bar) } };


static const BITSET_NAME R8_names [] = {        /* Register 8 bit names */
    "\1DMA enabled\0DMA disabled"               /*   bit 0 */
    };

static const BITSET_ARRAY R8_format =          /* names, offset, direction, alternates, bar */
    { { FMT_INIT (R8_names, 15, msb_first, has_alt, append_bar) },
      { FMT_INIT (R8_names, 15, msb_first, no_alt,  append_bar) } };


/* Registers 9 and A are handled independently */

static const BITSET_NAME RB_status_names [] = { /* Register B status bit names */
    "PHI IRQ",                                  /*   bit  0 */
    "parity error",                             /*   bit  1 */
    "address overflow",                         /*   bit  2 */
    "memory timeout",                           /*   bit  3 */
    NULL,                                       /*   bit  4 */
    NULL,                                       /*   bit  5 */
    NULL,                                       /*   bit  6 */
    "busy",                                     /*   bit  7 */
    "inhibit CSRQ",                             /*   bit  8 */
    "\1right byte\0left byte",                  /*   bit  9 */
    "inhibit EOI",                              /*   bit 10 */
    "\1outbound\0inbound",                      /*   bit 11 */
    "diagnostic"                                /*   bit 12 */
    };

static const BITSET_NAME RB_control_names [] = {    /* Register B control bit names */
    "\1start DMA\0start DMA",                       /*   dummy bit 8 */
    "address freeze",                               /*   bit  7 */
    "inhibit CSRQ",                                 /*   bit  8 */
    "\1right byte\0left byte",                      /*   bit  9 */
    "inhibit EOI",                                  /*   bit 10 */
    "\1outbound\0inbound",                          /*   bit 11 */
    "disable diagnostic"                            /*   bit 12 */
    };

static const BITSET_ARRAY RB_format =           /* names, offset, direction, alternates, bar */
    { { FMT_INIT (RB_status_names,  3, msb_first, has_alt, append_bar) },
      { FMT_INIT (RB_control_names, 3, msb_first, has_alt, append_bar) } };


static const BITSET_NAME RC_status_names [] = { /* Register C status bit names */
    "IRQ 0",                                    /*   bit  8 */
    "IRQ 1",                                    /*   bit  9 */
    "IRQ 2",                                    /*   bit 10 */
    "IRQ 3",                                    /*   bit 11 */
    "IRQ 4",                                    /*   bit 12 */
    "IRQ 5",                                    /*   bit 13 */
    "IRQ 6",                                    /*   bit 14 */
    "IRQ 7"                                     /*   bit 15 */
    };

static const BITSET_NAME RC_control_names [] = {    /* Register C control bit names */
    "\1set\0clear"                                  /*   bit 12 */
    };

static const BITSET_ARRAY RC_format =           /* names, offset, direction, alternates, bar */
    { { FMT_INIT (RC_status_names,  0, msb_first, no_alt,  no_bar)     },
      { FMT_INIT (RC_control_names, 3, msb_first, has_alt, append_bar) } };


static const BITSET_NAME RD_names [] = {        /* Register D control bit names */
    "not valid"                                 /*   bit  8 */
    };

static const BITSET_ARRAY RD_format =           /* names, offset, direction, alternates, bar */
    { { FMT_INIT (RD_names, 7, msb_first, no_alt, append_bar) },
      { FMT_INIT (RD_names, 7, msb_first, no_alt, append_bar) } };


static const BITSET_NAME RE_status_names [] = { /* Register E status bit names */
    "\1S2 B\0S2 A",                             /*   bit  1 */
    "\1S1 CPP\0S1 CPU"                          /*   bit  2 */
    };

static const BITSET_NAME RE_control_names [] = {    /* Register E control bit names */
    "\1DMA abort\0DMA abort"                        /*   bit 15 */
    };

static const BITSET_ARRAY RE_format =           /* names, offset, direction, alternates, bar */
    { { FMT_INIT (RE_status_names,  13, msb_first, has_alt, append_bar) },
      { FMT_INIT (RE_control_names,  0, msb_first, has_alt, no_bar)     } };


static const BITSET_NAME RF_status_names [] = { /* Register F status bit names */
    "timeout",                                  /*   bit  3 */
    "DMA abort",                                /*   bit  4 */
    "SRQ",                                      /*   bit  5 */
    "device request",                           /*   bit  6 */
    "channel request",                          /*   bit  7 */
    "not valid"                                 /*   bit  8 */
    };

static const BITSET_NAME RF_control_names [] = {    /* Register F control bit names */
    "DMA SRQ",                                      /*   bit  7 */
    "inhibit CSRQ",                                 /*   bit  8 */
    "right byte",                                   /*   bit  9 */
    "inhibit EOI",                                  /*   bit 10 */
    "\1DMA outbound\0DMA inbound",                  /*   bit 11 */
    "disable diagnostic"                            /*   bit 12 */
    };

static const BITSET_ARRAY RF_format =           /* names, offset, direction, alternates, bar */
    { { FMT_INIT (RF_status_names,  7, msb_first, no_alt,  append_bar) },
      { FMT_INIT (RF_control_names, 3, msb_first, has_alt, append_bar) } };


/* Trace formatter declarations.

   The trace formatter table is used to semi-automate tracing of register reads
   and writes.


   Implementation notes:

    1. The formatter entry for Register 0 uses the Register 4/5 format (parallel
       poll mask and sense).  This is used to trace Register 0 when it contains
       a poll response.  When Register 0 contains data or control bytes, they
       are handled with custom formats.

    2. Some write masks, e.g., for Register 1, contain more bits than are
       defined in the documentation.  This is to satisfy the GIC diagnostic,
       which tests bits that have storage capability even though they have no
       function.

    3. The first additional format ("format_1") applies only when reading a
       register value.  It is omitted when writing.  The second additional
       format ("format_2") applies to both reading and writing.
*/

typedef struct {                                /* register format descriptor structure */
    const char           *label;                /*   the register label */
    const BITSET_ARRAY   *bit_format;           /*   a pointer to the array of read/write formats, or NULL if not used */
    uint32               write_mask;            /*   a mask to keep the significant bits of the write value */
    const char           *format_1;             /*   the first additional format, or NULL if not used */
    uint32               start_1;               /*   the starting bit of the first value to format */
    uint32               end_1;                 /*   the ending bit of the first value to format */
    const char           *format_2;             /*   the second additional format, or NULL if not used */
    uint32               start_2;               /*   the starting bit of the second value to format */
    uint32               end_2;                 /*   the ending bit of the second value to format */
    } FORMAT_DESCRIPTOR;

static const FORMAT_DESCRIPTOR formatter [] = { /* an array of format descriptors, indexed by register number */

/*    Label             Format       Wrt Mask  Format String 1    S1  E1  Format String 2   S2  E2 */
/*    ----------------  -----------  --------  -----------------  --  --  ---------------   --  -- */
    { "FIFO",           &R45_format, 0140377u, NULL,               0,  0, NULL,              0,  0 },   /* R0 */
    { "Status",         &R1_format,  0000301u, NULL,               0,  0, NULL,              0,  0 },   /* R1 */
    { "IRQ conditions", &R23_format, 0040301u, NULL,               0,  0, NULL,              0,  0 },   /* R2 */
    { "IRQ mask",       &R23_format, 0140377u, NULL,               0,  0, NULL,              0,  0 },   /* R3 */
    { "Poll mask",      &R45_format, 0000377u, NULL,               0,  0, NULL,              0,  0 },   /* R4 */
    { "Poll sense",     &R45_format, 0000377u, NULL,               0,  0, NULL,              0,  0 },   /* R5 */
    { "Control",        &R6_format,  0000377u, NULL,               0,  0, NULL,              0,  0 },   /* R6 */
    { "Bus address",    &R7_format,  0000377u, NULL,               0,  0, "bus address %u", 11, 15 },   /* R7 */
    { "DMA bank",       &R8_format,  0000377u, "state %u | ",      3,  7, "bank %03o",       8, 15 },   /* R8 */
    { "DMA address",    NULL,        0177777u, NULL,               0,  0, "address %06o",    0, 15 },   /* R9 */
    { "DMA byte count", NULL,        0177777u, NULL,               0,  0, "byte count %u",   0, 15 },   /* RA */
    { "DMA control",    &RB_format,  0000777u, "status %u | ",     5,  6, "device %u",      13, 15 },   /* RB */
    { "Interrupt",      &RC_format,  0000017u, NULL,               0,  0, "device %u",      13, 15 },   /* RC */
    { "Interrupt info", &RD_format,  0000000u, "channel %u | ",    9, 12, "device %u",      13, 15 },   /* RD */
    { "DMA abort",      &RE_format,  0177777u, "channel ID %u",   12, 15, NULL,              0,  0 },   /* RE */
    { "Service info",   &RF_format,  0000777u, "channel %u | ",    9, 12, "device %u",      13, 15 },   /* RF */
    };


/* Trace bus signal declarations */

static const BITSET_NAME bus_names [] = {       /* Bus state names, rotated from BUS_SIGNALS */
    "\1REN\0   ",                               /*   bit 5 = remote enable */
    "\1IFC\0   ",                               /*   bit 6 = interface clear */
    "\1SRQ\0   ",                               /*   bit 7 = service request */
    "\1ATN\0   ",                               /*   bit 0 = attention */
    "\1EOI\0   ",                               /*   bit 1 = end or identify */
    "\1DAV\0   ",                               /*   bit 2 = data available */
    "\1NRFD\0    ",                             /*   bit 3 = not ready for data */
    "\1NDAC\0    "                              /*   bit 4 = not data accepted */
    };

static const BITSET_FORMAT bus_format =         /* names, offset, direction, alternates, bar */
    { FMT_INIT (bus_names, 0, lsb_first, has_alt, no_bar) };


/* Trace event scheduling declarations */

static const char *timeout_names [] = {         /* timeout counter actions */
    "disabled",                                 /*   CLEAR */
    "enabled"                                   /*   SET */
    };


/* Interface local state declarations.

   The local state consists of the GIC state structure and two mapping arrays.

   The original device's state structure is used as a template to create a new
   state instance for each new device instance.  The two arrays support multiple
   device protocols and multiple device instances.

   The first array contains the set of protocol descriptors for all supported
   protocols.  Each available protocol (e.g., CS/80, Amigo tape) registers
   itself with us during power-on reset.  During run-time initialization, each
   registered protocol handler is called to report the set of devices present on
   the bus that are controlled by the particular handler.  The GIC's dispatch
   table is set up from this data and is used to source data and control to the
   devices present on the bus.

   The second array is set up during run-time initialization and is used to map
   channel addresses to device instance (card) identifiers.  This allows
   functions that take a channel number to determine the local state instance to
   use.


   Implementation notes:

    1. The protocol and id_map arrays are rebuilt at power-up reset and run-time
       initialization, so they do not need to be included in the register list
       for SAVE/RESTORE.
*/

static GIC_STATE    gic_state;                  /* original device instance state structure */
static BUS_PROTOCOL protocol [Protocol_Count];  /* available protocols table */
static uint32       id_map   [CHANNEL_COUNT];   /* map from channel number to instance ID */


/* Interface local SCP support routine declarations */

static IMB_INTERFACE gic_imb_interface;
static t_stat        timeout_service (UNIT *uptr);
static t_stat        NRFD_service    (UNIT *uptr);
static t_stat        gic_reset       (DEVICE *dptr);
static t_bool        gic_initialize  (DEVICE *dptr, DIB *dibptr);
static uint32        gic_adjust      (DEVICE **dvptr, int32 delta);


/* Interface local bus routine declarations */

static ACCEPTOR gic_hpib_accept;
static REPORTER gic_report;


/* Interface local utility routine declarations */

static IMB_OUTBOUND read_register   (uint32 channel, REGISTER Register, IMB_IO_COMMAND command);
static IMB_OUTBOUND write_register  (uint32 channel, REGISTER Register, IMB_DATA data);
static t_bool       dma_cycle       (uint32 gic_id);
static void         transfer_data   (uint32 gic_id);
static void         timer_enable    (uint32 gic_id, FLIP_FLOP action);
static t_bool       phi_interrupts  (GIC_STATE *const gic, PHI_STATE *const phi);
static void         request_service (GIC_STATE *const gic, PHI_STATE *const phi);
static void         fifo_load       (uint32 gic_id, FIFO_MODE mode, IMB_DATA data);
static IMB_DATA     fifo_unload     (uint32 gic_id, FIFO_MODE mode);
static OUTBOUND_TAG tag_word        (PHI_STATE *const phi, uint32 word);


/* Interface local trace routine declarations */

static void trace_hpib     (uint32 gic_id, BUS_CABLE signals);
static void trace_register (uint32 gic_id, FORMAT_MODE mode, REGISTER Register, IMB_DATA data);
static void trace_fifo     (uint32 gic_id, FIFO_MODE mode, FIFO_ACTION action, HP_WORD data);


/* HP-IB registration declaration */

static const BUS_REGISTER gic_registration = {  /* bus registration */
    PHI_Index,                                  /*   the dispatcher table index */
    { &gic_report,                              /*   a pointer to the protocol reporting routine */
      &gic_hpib_accept }                        /*   a pointer to the bus acceptor routine */
    };


/* Interface SCP data structure declarations */


/* Device information block */

static DIB gic_dib = {
    NULL,                                       /* the device's IOP interface function pointer */
    &gic_initialize,                            /* the execution initialization function pointer */
    DEVNO_UNUSED,                               /* the device number */
    SRNO_UNUSED,                                /* the service request number */
    INTPRI_UNUSED,                              /* the interrupt priority */
    INTMASK_UNUSED,                             /* the interrupt mask */
    0,                                          /* the card index */
    CLEAR,                                      /* the interrupt request flip-flop */
    CLEAR,                                      /* the interrupt active flip-flop */
    FALSE,                                      /* TRUE if service has been requested */
    &gic_imb_interface,                         /* the device's IMB interface function pointer */
    GIC_CHANNEL,                                /* the IMB channel number */
    0                                           /* the IMB slot number */
    };

/* Unit list */

static UNIT gic_unit [] = {
/*           Event Routine    Unit Flags  Capacity  Wait           */
/*           ---------------  ----------  --------  -------------- */
    { UDATA (timeout_service, UNIT_DIS,   0),       TIMEOUT_PERIOD },
    { UDATA (NRFD_service,    UNIT_DIS,   0),       NRFD_PERIOD    }
    };


/* Register list */

static REG gic_reg [] = {
/*    Macro   Name      Location                       Radix  Width  Offset     Depth      Flags   */
/*    ------  --------  -----------------------------  -----  -----  ------  -----------  -------- */
    { FLDATA (REN,      gic_state.phi.bus,                            13)                          },
    { FLDATA (IFC,      gic_state.phi.bus,                            14)                          },
    { FLDATA (SRQ,      gic_state.phi.bus,                            15)                          },
    { FLDATA (ATN,      gic_state.phi.bus,                             8)                          },
    { FLDATA (EOI,      gic_state.phi.bus,                             9)                          },
    { FLDATA (DAV,      gic_state.phi.bus,                            10)                          },
    { FLDATA (NRFD,     gic_state.phi.bus,                            11)                          },
    { FLDATA (NDAC,     gic_state.phi.bus,                            12)                          },
    { HRDATA (DIO,      gic_state.phi.bus,                      8),                       PV_RZRO  },
    { YRDATA (TALK,     gic_state.phi.talker,                  32),                       PV_RZRO  },
    { YRDATA (LSTN,     gic_state.phi.listeners,               32),                       PV_RZRO  },
    { BRDATA (INFIFO,   gic_state.phi.fifo [Inbound],    8,    16,           FIFO_SIZE),  REG_CIRC },
    { BRDATA (OUTFIFO,  gic_state.phi.fifo [Outbound],   8,    16,           FIFO_SIZE),  REG_CIRC },
    { BRDATA (PHIREG,   gic_state.phi.registers,         8,    16,               8),      PV_RZRO  },
    { BRDATA (GICREG,   gic_state.registers,             8,    16,               8),      PV_RZRO  },
    { FLDATA (DMBUSY,   gic_state.dma_busy,                            0)                          },
    { GRDATA (DMSTATUS, gic_state.dma_status,           10,     2,     9)                          },
    { DRDATA (DMSTATE,  gic_state.dma_state,                    5),                       PV_LEFT  },
    { ORDATA (DMADDRS,  gic_state.dma_address,                 16),                       PV_RZRO  },
    { DRDATA (DMCOUNT,  gic_state.dma_count,                   16),                       PV_LEFT  },
    { ORDATA (IRQMASK,  gic_state.irq_mask,                    16),                       PV_RZRO  },

    { SVDATA (STATE,    gic_state)                                                         },
    { NULL }
    };


/* Modifier list */

#define ETAB_DEVICE         (MTAB_EDV)
#define ETAB_CHANNEL        (MTAB_EDV | MTAB_ERX (10))

static MTAB gic_mod [] = {
/*    Mask Value     Match/Max    Print String         Match String  Valid  Display  Descr  4.x   Expansion Flags */
/*    ------------  ------------  -------------------  ------------  -----  -------  -----  ----  --------------- */
    { CHAN_MASK,    15,           "channel",           "CHANNEL",    NULL,  NULL,    &gic_dib.channel_number, \
                                                                                            NULL, ETAB_CHANNEL    },
    { DEV_DIAG,     0,            "HP-IB cable",       "HPIB",       NULL,  NULL,    NULL,  NULL, ETAB_DEVICE     },
    { DEV_DIAG,     DEV_DIAG,     "diagnostic cable",  "DIAGNOSTIC", NULL,  NULL,    NULL,  NULL, ETAB_DEVICE     },
    { DEV_CPP,      0,            "CPU",               "CPU",        NULL,  NULL,    NULL,  NULL, ETAB_DEVICE     },
    { DEV_CPP,      DEV_CPP,      "CPP",               "CPP",        NULL,  NULL,    NULL,  NULL, ETAB_DEVICE     },
    { DEV_TYPE_B,   0,            "type A",            "A",          NULL,  NULL,    NULL,  NULL, ETAB_DEVICE     },
    { DEV_TYPE_B,   DEV_TYPE_B,   "type B",            "B",          NULL,  NULL,    NULL,  NULL, ETAB_DEVICE     },
    { DEV_NOT_SYS,  0,            "system controller", "SYS",        NULL,  NULL,    NULL,  NULL, ETAB_DEVICE     },
    { DEV_NOT_SYS,  DEV_NOT_SYS,  "device controller", "NOSYS",      NULL,  NULL,    NULL,  NULL, ETAB_DEVICE     },
    { DEV_TEST,     0,            "operate",           "OPER",       NULL,  NULL,    NULL,  NULL, ETAB_DEVICE     },
    { DEV_TEST,     DEV_TEST,     "test",              "TEST",       NULL,  NULL,    NULL,  NULL, ETAB_DEVICE     },

    { 0 }
    };


/* Debugging trace list */

static DEBTAB gic_deb [] = {
    { "CMD",   TRACE_CMD   },                   /* trace PHI and DMA commands */
    { "CSRW",  TRACE_CSRW  },                   /* trace interface control, status, read, and write actions */
    { "SERV",  TRACE_SERV  },                   /* trace unit service scheduling calls and entries */
    { "XFER",  TRACE_XFER  },                   /* trace data transmissions and receptions */
    { "BUF",   TRACE_FIFO  },                   /* trace FIFO buffer reads and writes */
    { "STATE", TRACE_STATE },                   /* trace DMA state machine changes */
    { "IMBUS", TRACE_IMBUS },                   /* trace IMB signals and data words (used by IMB calls) */
    { NULL,    0           }
    };


/* Device descriptor */

DEVICE gic_dev = {
    "GIC",                                      /* device name */
    gic_unit,                                   /* unit array */
    gic_reg,                                    /* register array */
    gic_mod,                                    /* modifier array */
    2,                                          /* number of units */
    10,                                         /* address radix */
    32,                                         /* address width = 4 GB */
    1,                                          /* address increment */
    8,                                          /* data radix */
    8,                                          /* data width */
    NULL,                                       /* examine routine */
    NULL,                                       /* deposit routine */
    gic_reset,                                  /* reset routine */
    NULL,                                       /* boot routine */
    NULL,                                       /* attach routine */
    NULL,                                       /* detach routine */
    &gic_dib,                                   /* device information block pointer */
    DEV_DISABLE | DEV_DEBUG,                    /* device flags */
    0,                                          /* debug control flags */
    gic_deb,                                    /* debug flag name array */
    NULL,                                       /* memory size change routine */
    NULL,                                       /* logical device name */
    NULL,                                       /* (4.0 dummy) help routine */
    NULL,                                       /* (4.0 dummy) help attach routine */
    NULL,                                       /* (4.0 dummy) help context */
    NULL,                                       /* (4.0 dummy) description */
    gic_adjust                                  /* the device adjustment function pointer */
    };


/* Interface local allocation state declarations */

static uint32 gic_count = 1;                    /* current count of GIC device instances */

static CARD_ENTRY gics [MAX_GIC_COUNT] = {      /* GIC card entries, indexed by the instance ID */
    { &gic_dev, &gic_state }                    /*   instance 0 (original) */
    };



/*********************************
 *                               *
 * Interface global bus routines *
 *                               *
 *********************************/


/* Register a bus protocol.

   This routine is called by a protocol handler, typically during its power-on
   reset routine, to register itself with the HP-IB controller.  The
   registration index number determines the handler's position in the protocol
   table and thereby its priority when called to transfer data across the bus.
   Lower index numbers are called before higher index numbers.
*/

void hpib_register (BUS_REGISTER registration)
{
protocol [registration.index] = registration.protocol;
return;
}


/* Source a byte or control signals to the bus.

   This routine is called to change the bus state by asserting a specified set
   of control signals and optionally placing a data byte on the bus.  It is
   called by the current talker to send data to the current listener(s) and by
   the controller, talker, or a listener to change the control state of the bus.

   When sourcing a byte with DAV asserted, it corresponds in hardware to
   performing the IEEE-488 SH (Source Handshake) interface function.  When
   changing the control signals without sourcing a byte, i.e., with DAV denied,
   it corresponds to performing the IEEE-488 SR (Service Request), RL (Remote
   Local), PP (Parallel Poll), and C (Controller) interface functions.  Control
   signal changes and command bytes, i.e., those with ATN asserted, are sent to
   all registered protocol handlers.  Data bytes are sent only to those handlers
   hosting the current listeners.  This optimization avoids sending bytes to
   acceptor functions that have no interest in them.

   On entry, "channel" is the channel number of the GIC controlling the bus,
   "address" is the bus address of the caller (i.e., the device or controller),
   and "bus" is the desired bus state consisting of the eight control lines and
   the eight data lines.  The routine returns the updated bus state to the
   caller.  If a data byte is sourced, and there are no listeners, the returned
   bus state will have NDAC asserted.  The returned state will also have DAV and
   EOI denied, so that the caller does not have to remove these signals
   explicitly between successive calls.

   Devices, the controller, and the system controller have differing
   restrictions concerning the bus lines they can control, as follows:

      Caller                  Can Control
       Type     IFC  REN  ATN  EOI  SRQ  DAV  NRFD  NDAC
     ---------  ---  ---  ---  ---  ---  ---  ----  ----
        DEV      -    -    -    Y    Y    Y    Y     Y

        CIC      -    -    Y    Y    Y    Y    Y     Y

        SCN      Y    Y    -    Y    Y    Y    Y     Y

     SCN + CIC   Y    Y    Y    Y    Y    Y    Y     Y

   Where:

     DEV = device
     CIC = controller-in-charge
     SCN = system controller

   On entry, the caller type is ascertained by first examining the supplied bus
   address.  If the address is the PHI address, then the controller and
   system controller bits in Register 1 are used to index into the table of
   restrictions.  If the address is not the PHI address, then the caller is a
   device, and the device restrictions are used.

   After the new bus state is determined, it is sent to the acceptor functions
   for the protocol handlers listed in the dispatch table that was set up during
   run-time initialization.  If the PHI is in online mode, all acceptors are
   notified.  If the PHI is offline, then only the acceptor of the GIC (and the
   cross-connected GIC, if in diagnostic mode) is notified; this implements the
   internal bus loopback capability of the PHI.

   Certain bus primary commands want to be followed by a parallel poll.  The GIC
   acceptor will set the "poll_active" variable TRUE if a poll should be
   conducted.  Examples of such commands are DCL (Device Clear), SPD (Serial
   Poll Disable), and UNL (Unlisten).  A poll request also follows the reception
   of the last byte of a counted transfer.


   Implementation notes:

    1. In diagnostic mode, the dispatch table contains only the entries for the
       local GIC and the cross-connected GIC.  These reside on different IMB
       channels but must share the bus state.  To do this, the GIC acceptor
       function sets its copy of the bus state to the supplied bus state
       parameter value.  For control calls where both GIC acceptors are called,
       one of the copy operations is redundant, as the GIC is calling its own
       acceptor.  For data source calls, only the listening GIC acceptor is
       called.  However, the caller is the talking GIC, so the acceptor copy
       ensures that both GIC bus states remain synchronized.

    2. The DAV and EOI signals are denied in the GIC acceptor function to ensure
       that both GIC bus states remain synchronized in diagnostic mode.  They
       are also denied here, as for sourced data, the GIC acceptor is not called
       if the PHI is the talker.

    3. Each acceptor returns its current set of listening bus addresses.  These
       sets, which are used for the data sourcing optimization, are
       reestablished during each device addressing sequence when all protocol
       acceptors are called.
*/

BUS_CABLE hpib_source (uint32 channel, uint32 address, BUS_CABLE bus)
{
static const uint32 restrictions [4] = {        /* a table of signal restrictions, indexed by R1_CNTLRS */
    Bus_IFC | Bus_REN | Bus_ATN,                /*   device restrictions */
    Bus_ATN,                                    /*   system controller restrictions */
    Bus_IFC | Bus_REN,                          /*   controller-in-charge restrictions */
    BUS_NONE };                                 /*   system controller + controller-in-charge restrictions */

const uint32     gic_id = id_map [channel];     /* the instance ID of the associated GIC */
DEVICE    *const dptr   = gics [gic_id].dptr;   /* the per-instance device pointer */
GIC_STATE *const gic    = gics [gic_id].sptr;   /* the per-instance GIC state pointer */
PHI_STATE *const phi    = &gic->phi;            /* the per-instance PHI state pointer */
uint32           acceptors;
BUS_SIGNALS      restricted;
BUS_DISPATCH     *dsptr;

if (address == phi->address)                                        /* if the caller is the PHI */
    restricted = restrictions [R1_CNTLRS (phi->registers [Phi_1])]; /*   then use the PHI configuration */
else                                                                /* otherwise */
    restricted = restrictions [0];                                  /*   use the device restrictions */

if (bus & Bus_DAV)                                      /* if this is a data transfer */
    restricted |= Bus_REN;                              /*   then preserve the remote signal */
else                                                    /* otherwise */
    bus &= BUS_CONTROL_MASK;                            /*   clear the data byte from the bus */

bus &= ~Bus_NDAC;                                       /* deny any prior NDAC signal */

phi->bus = bus = phi->bus & restricted                  /* set the bus to its new state */
                   | bus & ~restricted;                 /*   without altering any restricted signals */

if (TRACINGP (dptr, TRACE_XFER))                            /* if bus tracing is enabled */
    if (not (phi->bus & Bus_DAV))                           /*   then if this is a control change */
        trace_hpib (gic_id, phi->bus | address);            /*     then include the controlling address */
    else if (not (phi->bus & Bus_ATN || phi->listeners))    /*   otherwise if there are no data acceptors */
        trace_hpib (gic_id, phi->bus | Bus_NDAC);           /*     then include NDAC as an indicator */
    else                                                    /*   otherwise */
        trace_hpib (gic_id, phi->bus);                      /*     report the source data */

if (phi->registers [Phi_7] & R7_ONLINE)                 /* if the PHI is online */
    dsptr = gic->dispatcher;                            /*   then include all dispatch table entries */
else                                                    /* otherwise */
    dsptr = gic->gic_dispatcher;                        /*   include only the GIC entry */


if ((phi->bus & (Bus_ATN | Bus_DAV)) == Bus_DAV) {      /* if sourcing a data byte */
    phi->bus &= ~(Bus_DAV | Bus_EOI);                   /*   then deny the DAV and EOI return signals */

    acceptors = phi->listeners;                         /* data is accepted only by the listeners */

    if (acceptors == 0)                                 /* if there are no active listeners */
        return phi->bus | Bus_NDAC;                     /*   then assert NDAC in the returned bus state */

    else while (acceptors && dsptr->accept != NULL) {   /* otherwise while there are more acceptors to notify */
        if (dsptr->listeners & acceptors) {             /*   then if this acceptor has listeners */
            dsptr->accept (dsptr->instance, bus);       /*     then call the acceptor */
            acceptors &= ~dsptr->listeners;             /*       and clear the listeners from the acceptors */
            }

        dsptr++;                                        /* move to the next protocol handler */
        }                                               /*   and loop until all listeners are notified */
    }

else if ((phi->bus & BUS_PPOLL) == BUS_PPOLL) {         /* otherwise if conducting a parallel poll */
    dsptr = gic->gic_dispatcher;                        /*   then dispatch only to the GIC(s) */

    while (dsptr->accept != NULL) {                     /* while there are more acceptors to notify */
        dsptr->accept (dsptr->instance, bus);           /*   call the GIC acceptor to conduct the poll */
        dsptr++;                                        /*     and move to the next protocol handler */
        }                                               /*       and loop until all GIcs are notified */

    return phi->bus;                                    /* return the current bus condition */
    }

else                                                                /* otherwise source a command or assert control */
    while (dsptr->accept != NULL) {                                 /* while there are more acceptors to notify */
        dsptr->listeners = dsptr->accept (dsptr->instance, bus);    /*   then call it and update the listeners */
        dsptr++;                                                    /*     and move to the next protocol handler */
        }                                                           /*       and loop until all acceptors are notified */

if (phi->poll_active && phi->registers [Phi_1] & R1_CNTLR) {    /* if a parallel poll is requested */
    hpib_source (channel, phi->address, phi->bus | BUS_PPOLL);  /*   then conduct it */
    }

return phi->bus;                                        /* return the current bus condition */
}



/****************************************
 *                                      *
 * Interface local SCP support routines *
 *                                      *
 ****************************************/


/* GIC interface.

   The General I/O Channel is installed on the Intermodule Bus and provides
   control of peripherals connected via the Hewlett-Packard Interface Bus
   (HP-IB).  The GIC consists of a PHI (Processor to HP-IB) chip, a DMA
   sequencer, and bus request and handshake circuitry.  It connects to the IMB
   on one end and the HP-IB on the other.  It can drive up to eight HP-IB
   devices.

   IMB commands are defined by an operation code asserted on OP0-OP2.  For
   memory reads and writes, ADRE8-E1 and ADR0-15 give the 24-bit address, and
   DATA0-15 supply or accept the 16-bit data, respectively.  For I/O commands,
   ADR0-15 give the command code, register number, and channel number, and
   DATA0-15 supply or accept the 16-bit data, respectively.  The command format
   is:

   IMB Command Code Format:

       0 | 1   2   3 | 4   5   6 | 7   8   9 |10  11  12 |13  14  15
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     |    Command    |   Register    | - |    Channel    | -   -   - |
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

   The GIC decodes 13 IMB commands:

     Mnemonic  Opcode  Command  Operation
     --------  ------  -------  ----------------------------
       RIOC     100     0000    Read I/O Data
       OBII     100     0010    Obtain Interrupt Information
       OBSI     100     0100    Obtain Service Information
       IPOLL    100     1000    Interrupt Poll
       ROCL     100     1010    Roll Call
       SPOL1    100     1100    Service Poll 1
       SPOL2    100     1110    Service Poll 2
       WIOC     110     0000    Write I/O Data
       INIT     110     0010    Initialize Channel
       SIOP     110     0100    Start I/O Program
       HIOP     110     0110    Halt I/O Program
       SMSK     110     1000    Set Interrupt Mask
       IOCL     110     1010    I/O Clear

   In hardware, the GIC has five user-settable switches that are modeled in
   simulation as user device flags.  The switch functions are:

     Switch   Choices   Setting  Action                Alternate Action
     ------  ---------  -------  --------------------  -------------------
       S1     CPU/CPP     CPU    Asserts CSRQ1         Asserts CSRQ2
       S2       A/B        A     Denies HYBRID         Asserts HYBRID
       S3     OFF/ON      ON     Asserts SCTRL to PHI  Denies SCTRL to PHI
       S4      0-15       11     Sets channel number   (not applicable)
       S5    OPER/TEST   OPER    Denies DIAGSW         Asserts DIAGSW

   When switch SW5 is in the TEST position and bit 12 of Register B is zero,
   then the free-running DMA state machine clock is inhibited, and each IMB read
   or write command causes the clock to step once.  After every third clock
   steps, a DMA state machine cycle occurs.  This allows the diagnostic to step
   through DMA states and verify proper DMA operation.


   Implementation notes:

    1. PHI and GIC registers generally maintain their read values.  Writes, to
       the extent that they are reflected in bit-for-bit changes, are copied
       into the register values.  Writes that perform actions or whose bits do
       not appear in the read values are not stored.  Some register bits are set
       at read time, especially those dependent on switch settings.  This is so
       we don't have to capture switch changes but can simply insert those
       changes at the time the register is read.

    2. The "dma_clock" value indicates whether the DMA clock is running free
       (value is 0) or single-stepping (value is 1-3).
*/

static IMB_OUTBOUND gic_imb_interface (DIB *dibptr, IMB_INBOUND inbound)
{
const uint32     channel = dibptr->channel_number;      /* the IMB channel number */
const uint32     gic_id  = dibptr->card_index;          /* the instance identifier */
DEVICE    *const dptr    = gics [gic_id].dptr;          /* the per-instance device pointer */
GIC_STATE *const gic     = gics [gic_id].sptr;          /* the per-instance GIC state pointer */
PHI_STATE *const phi     = &gic->phi;                   /* the per-instance PHI state pointer */
IMB_IO_COMMAND   command;
IMB_OUTBOUND     outbound = { 0, ADN | DDN | PRO };     /* the initial outbound value and signal set */

switch (inbound.opcode) {                               /* dispatch the IMB opcode */

    case IMB_IO_Write:                                  /* I/O Write */
    case IMB_IO_Read:                                   /* I/O Read */
        command  = IMB_COMMAND (inbound.address,        /* get the IMB command */
                                inbound.opcode);

        switch (command) {                              /* dispatch the IMB I/O command */

            case SPOL1:                                 /* Service Poll 1 */
                if (not (dptr->flags & DEV_CPP))        /* if S1 is in the CPU position */
                    outbound.data = HP_BIT (channel);   /*   then respond with our channel bit */
                break;


            case SPOL2:                                 /* Service Poll 2 */
                if (dptr->flags & DEV_CPP)              /* if S1 is in the CPP position */
                    outbound.data = HP_BIT (channel);   /*   then respond with our channel bit */
                break;


            case IOCL:                                  /* I/O Clear */
            case INIT:                                  /* Initialize Channel */
                gic_reset (dptr);                       /* reset the GIC */
                break;


            case ROCL:                                  /* Roll Call */
                outbound.data = HP_BIT (channel);       /* respond with our channel bit */
                break;


            case SIOP:                                  /* Start I/O Program */
            case HIOP:                                  /* Halt I/O Program */
                if (inbound.data & SIOP_CLEAR_STATUS)                       /* if the S bit is set */
                    gic->new_status &= ~BIT (SIOP_DEVICE (inbound.data));   /*   then clear the status bit */
                else                                                        /* otherwise */
                    gic->new_status |= BIT (SIOP_DEVICE (inbound.data));    /*   set the status bit */

                if (gic->new_status)                            /* if any status bits are set */
                    request_service (gic, phi);                 /*   then request service if enabled */
                else                                            /* otherwise */
                    gic->channel_requests &= ~Status_Interrupt; /*   deny the status request */
                break;


            case RIOC:                                      /* Read I/O Data */
                outbound = read_register (channel,  /* read the specified register */
                                          IMB_REGISTER (inbound.address),
                                          command);
                break;


            case WIOC:                                      /* Write I/O Data */
                outbound = write_register (channel, /* write the specified register */
                                           IMB_REGISTER (inbound.address),
                                           inbound.data);
                break;


            case OBSI:                                      /* Obtain Service Information */
                outbound = read_register (channel,  /* read the Channel Service Information register */
                                          Reg_F, command);
                break;


            case OBII:                                      /* Obtain Interrupt Information */
                outbound = read_register (channel,  /* read the Channel Interrupt Information register */
                                          Reg_D, command);
                break;


            case IPOLL:                                 /* Interrupt Poll */
                if (gic->interrupts && gic->irq_mask)   /* if the request is still pending and enabled */
                    outbound.data = HP_BIT (channel);   /*   then assert the channel bit */
                break;


            case SMSK:                                  /* Set Interrupt Mask */
                gic->irq_mask = inbound.data            /* mask to our channel bit */
                                  & HP_BIT (channel);   /*   and save the result */
                break;
            }

        break;                                          /* end of I/O Read and Write cases */


    case IMB_Read:                                      /* not used by this interface */
    case IMB_Write:                                     /* not used by this interface */
    case IMB_RW_Ones:                                   /* not used by this interface */
    case IMB_Memory:                                    /* not used by this interface */
        break;
    }                                                   /* all defined cases are handled */

if (gic->dma_clock > 0)                                 /* if DMA is being single-stepped */
    if (gic->dma_clock < 3)                             /*   then if the counter is not at maximum */
        gic->dma_clock++;                               /*     then count the slave handshake */
    else                                                /*   otherwise */
        transfer_data (gic_id);                         /*     clock the state machine */

if (gic->interrupts && gic->irq_mask)                   /* if an interrupt request is pending and not masked */
    outbound.signals |= IRQ;                            /*   then assert IRQ on the IMB */

else if (gic->channel_requests                          /* otherwise if a channel request is pending */
  && not (dptr->flags & DEV_TEST))                      /*   and not inhibited by diagnostic testing */
    if (dptr->flags & DEV_CPP)                          /*     then if switch S1 is in the CPP position */
        outbound.signals |= CSRQ2;                      /*       then assert CSRQ2 on the IMB */
    else                                                /*     otherwise */
        outbound.signals |= CSRQ1;                      /*       assert CSRQ1 on the IMB */

return outbound;                                        /* return the outbound signals and data */
}


/* Service a timeout event.

   This event service routine is called when a GIC timeout occurs.  The GIC has
   a one-second watchdog timer, consisting in hardware of an astable 555 timer
   running at 15 Hz and a 4-bit binary down counter that sets a flip-flop to
   assert the TIMEOUT signal when the counter underflows.  This signal causes a
   DMA abort (identical to writing to Register E), forces a PHI interrupt and
   thus a channel request, and presents on bit 3 of Register F.  The timer is
   inhibited by DIAG signal assertion, which occurs when switch S5 is in the
   TEST position and bit 12 of Register B or F is zero.

   When DMA is idle, the timer is frozen if bit 8 of Register F is clear and
   released to run if the bit is set.  The IOMAP program sets bit 8 before
   initiating the HP-IB Identify sequences.  This ensures that sending Identify
   sequences to absent device addresses will not hang the GIC.

   When DMA is active, each DMA cycle will reset the counter to its initial
   state.  Should a DMA cycle hang, the timer will eventually expire.

   On entry, uptr->Instance is the instance ID of the GIC.
*/

static t_stat timeout_service (UNIT *uptr)
{
DEVICE    *const dptr   = gics [uptr->Instance].dptr;   /* the per-instance device pointer */
GIC_STATE *const gic    = gics [uptr->Instance].sptr;   /* the per-instance GIC state pointer */
DIB       *const dibptr = (DIB *) dptr->ctxt;           /* the device context pointer */

tpprintf (dptr, TRACE_SERV, "Timeout service entered\n");

gic->registers [Gic_F] |= RF_TIMEOUT;                   /* set the timeout status bit */
gic->channel_requests |= PHI_Interrupt;                 /*   and request service for the channel */

if (gic->registers [Gic_8] & R8_DMA_ENABLED) {          /* if DMA is enabled */
    gic->registers [Gic_8] &= ~R8_DMA_ENABLED;          /*   then clear the enable flip-flop */
    gic->dma_status = RB_STATUS_ERROR;                  /*     and indicate a DMA abort */

    tpprintf (dptr, TRACE_CMD, "DMA aborted\n");

    dma_cycle (uptr->Instance);                         /* run a DMA cycle to recognize the abort */
    }

else                                                    /* otherwise DMA is idle */
    imb_assert_CSRQ (dibptr->channel_number);           /*   so request channel service */

return SCPE_OK;                                         /* the event always succeeds */
}


/* Service an NRFD holdoff event.

   This event service routine is called when the GIC is listening and has
   asserted NRFD (Not Ready For Data) to hold off the talker while the current
   byte is being processed.  When the delay expires, this routine is called to
   deny NRFD to allow the talker to continue.

   On entry, uptr->Channel is the channel number, and uptr->Address is the PHI
   bus address.
*/

static t_stat NRFD_service (UNIT *uptr)
{
const uint32     gic_id = id_map [uptr->Channel];       /* the instance ID of the associated GIC */
PHI_STATE *const phi    = &gics [gic_id].sptr->phi;     /* the pointer to the PHI state */

hpib_source (uptr->Channel, uptr->Address, phi->bus & ~Bus_NRFD);   /* clear the data hold off */

return SCPE_OK;                                         /* the event always succeeds */
}


/* GIC reset.

   This routine is called for a RESET or RESET GIC command and when an IOCL or
   INIT command is received over the Intermodule Bus interface.  In the former
   cases, the presence of the "-P" switch indicates that this is a power-on
   reset.

   Four signals are involved in resetting the GIC.  They are:

    - PON  (Power On)
    - SRST (System Reset)
    - IOCL (I/O Clear)
    - INIT (Initialize Channel)

   The first two are IMB signals and are combined to generate the PONB signal.
   The latter two are IMB Commands that are combined with the PONB signal to
   generate the PONINCL and PONDLAY signals.

   Asserting the PONB signal:

    - resets the DMA Clock flip-flop

   Asserting the PONDLAY signal:

    - clears the DMA state machine to state 0
    - resets the PHI via its PON (Soft Reset) pin

   A soft reset signal assertion clears all PHI registers except Register 1
   (status).  Clearing Register 2 drops the IRQ line, clearing bit 0 of Register
   B.

   Asserting the PONINCL signal:

    - releases the IMB if the GIC has obtained it
    - releases the master handshake
    - clears bits 7-8 and 12-15 of Registers B and F
    - clears DMASTATA and DMASTATB flip-flops (bits 5-6 of Register B)
    - clears the DMAENF flip-flop
    - clears the New Status register
    - clears Register C
    - clears the Interrupt Mask flip-flop
    - generates the CLRERR signal
    - clear bits 1-3 of Register B (via CLRERR)
    - clears the timeout flip-flop and presets the timeout counter (via CLRERR)

   For the GIC registers, a reset clears:

    - Register B bits 0-8 and 12-15
    - Register C bits 8-15
    - Register F bits 7-8 and 12-15

   Registers 8, 9, and A are unaffected,  Register D is read-only, and Register
   E reflects switch settings and has no programmable bits.
*/

static t_stat gic_reset (DEVICE *dptr)
{
DIB       *const dibptr = (DIB *) dptr->ctxt;   /* the pointer to the device context */
const uint32     gic_id = dibptr->card_index;   /* the instance ID */
GIC_STATE *const gic    = gics [gic_id].sptr;   /* the pointer to the GIC state */
PHI_STATE *const phi    = &gic->phi;            /* the pointer to the PHI state */
REG       *rptr;

if (sim_switches & SWMASK ('P')) {                      /* if this a power-on reset */
    hpib_register (gic_registration);                   /*   then register our protocol */

    memset (gic, 0, sizeof (GIC_STATE));                /* clear the GIC local state */

    for (rptr = dptr->registers; rptr->loc != NULL; rptr++) {   /* search through the register list */
        if (rptr->loc == &phi->fifo [Inbound]) {                /* if this is the inbound FIFO register */
            gic->fifo_reg [Inbound] = rptr;                     /*   then save a pointer to the register */
            rptr->qptr = 0;                                     /*     and initialize the FIFO queue index */
            }

        else if (rptr->loc == &phi->fifo [Outbound]) {  /* otherwise if this is the outbound FIFO register */
            gic->fifo_reg [Outbound] = rptr;            /*   then save a pointer to the register */
            rptr->qptr = 0;                             /*     and initialize the FIFO queue index */
            }
        }
    }

else                                                    /* otherwise it's a normal reset */
    memset (phi, 0, sizeof (PHI_STATE));                /*   so assert SRST to clear the PHI */

gic->channel_requests = 0;                              /* clear the channel request set */
gic->new_status = 0;                                    /*   and the New Status register */
gic->interrupts = 0;                                    /*   and the interrupt set */
gic->irq_mask   = 0;                                    /*   and the interrupt mask flip-flop */

gic->dma_run    = FALSE;                                /* reset the */
gic->dma_busy   = FALSE;                                /*   DMA state machine */
gic->dma_obsi   = FALSE;                                /*     to the */
gic->dma_state  = 0;                                    /*       idle state */

gic->dma_status = 0;                                    /* clear the DMA termination status */
gic->dma_clock  = 0;                                    /*   and reset the DMA clock to automatic operation */

tpprintf (dptr, TRACE_CMD, "PHI becomes system controller and goes offline with reset\n");

phi->registers [Phi_1] = R1_SYSCNTLR;                   /* the PHI is the system controller as it is offline */
phi->registers [Phi_2] = R2_EMPTY | R2_AVAIL;           /* the outbound FIFO is empty and has space available */

gic->registers [Gic_B] &= RB_RIGHT_BYTE | RB_NO_EOI | RB_DIRECTION; /* keep bits 9-11 of the status register */
gic->registers [Gic_C] = 0;                                         /*   and clear the interrupt register */
gic->registers [Gic_F] &= RF_RIGHT_BYTE | RF_NO_EOI | RF_OUTBOUND;  /*     and keep bits 9-11 of the service register */

sim_cancel (&dptr->units [Timeout_Unit]);               /* stop the timeout counter */
sim_cancel (&dptr->units [NRFD_Unit]);                  /*   and the NRFD delay */

return SCPE_OK;                                         /* the routine always succeeds */
}


/* Run-time initialization.

   This routine is called to initialize the GIC tables prior to beginning CPU
   execution.  It has three major functions:

     1. It sets up the global ID table that is used to map channel numbers to
        instance (card) identifiers.

     2. It sets up the local dispatcher table that is used to source bytes and
        control signals to the devices present on the bus.

     3. It verifies that no bus address conflicts exists.

   The dispatcher is initialized by calling each of the protocol "report"
   routines to obtain the set of devices present on the bus and supported by
   that protocol.  If any of the reported sets overlap, a conflict is present
   that must be characterized.

   If the GIC is in diagnostic mode, then a search is made to find another GIC
   also in diagnostic mode.  If one is found, it is added to the dispatch table,
   so that both GICs are present.  This simulates an interconnecting cable
   between the GICs.

   Four types of conflicts can occur:

     1. Multiple channels sharing the same IMB address (e.g., two GIC instances
        with the same CHANNEL setting).

     2. Multiple protocol handlers sharing the same IMB address (e.g., two DC
        instances with the same CHANNEL setting).

     3. Multiple peripheral devices of the same protocol sharing the same bus
        address (e.g., two DC units with the same BUS setting).

     4. Multiple peripheral devices with differing protocols sharing the same
        bus address (e.g., a DC unit and an MA unit with the same BUS setting).

   If a conflict is noted, another pass is made through the dispatch table to
   identify the interfering devices and report them to the console.  The routine
   then returns FALSE to indicate that execution cannot proceed until the
   conflict is resolved.  If all bus assignments are unique, the routine returns
   TRUE to allow execution to continue.


   Implementation notes:

     1. The id_map table is cleared when the routine is entered for the original
        device.  As the original device always precedes any additional device
        instances in the sim_devices table, it will always be initialized first.

     2. The protocol report returns the set of devices present on the bus.  This
        set is entered into the dispatch table as the set of current listeners.
        Some or all of these devices actually may not be listening, but this is
        OK, as the protocol handler will simply return if its acceptor routine
        is called when no devices are listening.  The updated set of listeners
        is returned from the call to the acceptor routine, so the next source
        call will skip calling those protocol acceptors not actively listening.

     3. The GIC is always the last entry (or, in diagnostic mode, the GICs are
        the last two entries) in the dispatcher table.

     4. Of the four conflict types, channel IMB address conflicts are detected
        by the IMB simulator, protocol handler IMB address conflicts are
        detected by the protocol handlers, same protocol bus address conflicts
        are detected by the individual protocol handlers, and cross-protocol bus
        address conflicts are detected here.

     5. Hardware switch changes could have been picked up here, as execution
        must stop and restart to change a switch.  However, it is just as easy
        to test the switches, which are kept in the device flags, each time they
        are needed.
*/

static t_bool gic_initialize (DEVICE *dptr, DIB *dibptr)
{
const uint32     channel = dibptr->channel_number;  /* the IMB channel number */
const uint32     gic_id  = dibptr->card_index;      /* the instance identifier */
GIC_STATE *const gic     = gics [gic_id].sptr;      /* the pointer to the GIC state */
BUS_DISPATCH     *dsptr, *ckptr;
BUS_REPORT       report;
uint32           cntr, conflicts, address;
uint32           occupied = 0;
t_bool           proceed = TRUE;

if (dptr == &gic_dev)                                   /* if initializing the original device */
    memset (id_map, 0, sizeof id_map);                  /*   then clear the ID map table */

id_map [channel] = gic_id;                              /* set the map entry for the channel */

dsptr = gic->dispatcher;                                /* point at the dispatcher table */
memset (dsptr, 0, sizeof gic_state.dispatcher);         /*   and clear the table */

for (cntr = 0; cntr < Protocol_Count; cntr++) {         /* scan through the protocols */
    report = protocol [cntr].report (channel);          /*   and get the next protocol report */

    if (report.present) {                               /* if any devices are present on the bus */
        dsptr->listeners  = report.present;             /*   then assume they might be listeners */
        dsptr->dptr       = report.dptr;                /* save the device pointer */
        dsptr->instance   = report.instance;            /*   and instance ID */
        dsptr->accept     = protocol [cntr].accept;     /*     and a pointer to the acceptor */

        if (occupied & report.present)                  /* if any device uses an occupied address */
            proceed = FALSE;                            /*   then a conflict occurs */

        occupied |= report.present;                     /* merge into the set of occupied addresses */
        dsptr++;                                        /*   and move to the next dispatcher entry */
        }
    }

gic->gic_dispatcher = dsptr - 1;                        /* point at the GIC entry in the table */

if (dptr->flags & DEV_DIAG)                             /* if the GIC is in diagnostic mode */
    for (cntr = 0; cntr < gic_count; cntr++)            /*   then search through the instance table */
        if (gics [cntr].dptr->flags & DEV_DIAG          /*     to find a second instance in diagnostic mode */
          && gics [cntr].dptr != dptr) {                /*       other than our instance */
            dsptr->listeners = report.present;          /*         and enter it in the dispatcher */

            dsptr->dptr     = gics [cntr].dptr;         /* use the other GIC's device pointer */
            dsptr->instance = cntr;                     /*   and instance ID */

            dsptr->accept = gic_registration.protocol.accept;   /* all GICs use the same acceptor */
            break;
            }

if (not proceed)                                                /* if a conflict is present */
    for (dsptr = gic->dispatcher; dsptr->dptr; dsptr++)         /*   then for each dispatcher entry */
        for (ckptr = dsptr + 1; ckptr->dptr; ckptr++) {         /*     search for another entry */
            conflicts = dsptr->listeners & ckptr->listeners;    /*       whose addresses conflict */

            while (conflicts != 0) {                    /* if a conflict is found */
                address = BIT_NUMBER (conflicts);       /*   then report each conflicting address */

                cprintf ("%s and %s have conflicting assignments for %s bus address %u\n",
                         sim_dname (dsptr->dptr), sim_dname (ckptr->dptr),
                         sim_dname (dptr), address);

                conflicts &= ~BIT (address);            /* clear the current address and check for more */
                }
            }

return proceed;                                         /* indicate whether or not it is safe to proceed */
}


/* Adjust the device instances.

   This routine is called by SCP to adjust device instances that are newly
   allocated or pending deletion.  On entry, "dvptr" points at the "sim_devices"
   element that contains a pointer to the first of potentially several device
   instances to be adjusted, and "delta" contains the number of instances just
   created (if positive) or to be deleted (if negative).

   When the "dvptr" parameter is NULL, SCP expects the return value to be
   formatted as follows:

      31  30  ... 25  24 |23  22  ..  17  16 |15  14 13  ...  2   1   0
     +---+---+---+---+---+---+---+---+---+---+---+--+---+---+---+---+---+
     | clone identifier  |  instance limit   |     sim_devices size     |
     +---+---+---+---+---+---+---+---+---+---+---+--+---+---+---+---+---+

   The fields have the following meanings:

     sim_devices size      The total number of elements defined in the
                           "sim_devices" array, including the NULL element at
                           the end.  The difference between this number and the
                           number of initialized elements gives the number of
                           new device instances that can be added by the user.

     instance limit        The maximum number of instances allowed.  The count
                           includes the original instance.

     clone identifier      A character used to produce unique names for new
                           device instances.  The ID will be appended to the
                           original device name and incremented by the device
                           instance number.

   When the adjust function is called with a non-NULL pointer parameter, the
   routine performs the actions are necessary to prepare the indicated device
   instances for use or destruction.  The return value is either SCPE_OK if all
   adjustments succeeded, or an SCPE error code indicating the nature of the
   failure.  In the latter case, any allocations made by the routine prior to
   the failure must be freed before returning.


   Implementation notes:

    1. The deallocation part of the routine is entered either for a deletion
       request or for an addition request when a required allocation fails.
*/

static uint32 gic_adjust (DEVICE **dvptr, int32 delta)
{
GIC_STATE *nsptr;
DEVICE    *dptr;
DIB       *dibptr;
REG       *rptr;
MTAB      *mptr;
char      *nptr;
int32     count;
t_stat    status = SCPE_OK;

if (dvptr == NULL)                                      /* if this is a limits request */
    return TO_DWORD (TO_WORD ('A', MAX_GIC_COUNT),      /*   then return the clone ID and instance limit */
                     SIM_DEVICE_SIZE);                  /*     and device array size */

else if (delta > 0) {                                   /* otherwise if device clones are being added */
    for (count = 0; count < delta; count++)             /*   then for each new device clone */
        dvptr [count]->modifiers = NULL;                /*     clear its modifier table pointer */

    for (count = 0; count < delta; count++) {           /* for each new device clone */
        dptr = dvptr [count];                           /*   get a pointer to the new device */

        status = SCPE_INCOMP;                           /* preset for name duplication error recovery */

        nptr = dptr->name;                              /* save the newly assigned name */
        dptr->name = "";                                /*   and temporarily remove it */

        if (find_dev (nptr) != NULL) {                      /* if the device name is duplicated */
            cprintf ("Duplicate device name %s\n", nptr);   /*   then report it to the user */

            dptr->name = nptr;                          /* restore the assigned name */
            break;                                      /*   and fail at this point */
            }

        else                                            /* otherwise the name is unique */
            dptr->name = nptr;                          /*   so restore it to the device */

        status = SCPE_MEM;                              /* preset for memory error recovery */

        dibptr = malloc (sizeof (DIB));                 /* allocate a new DIB structure */

        if (dibptr == NULL)                             /* if the allocation failed */
            break;                                      /*   then clean up before exiting */

        dptr->ctxt = dibptr;                            /* save the new DIB pointer */

        memcpy (dibptr, &gic_dib, sizeof (DIB));        /* copy the original DIB structure */
        dibptr->card_index = gic_count + count;         /*   and set the new card index */

        nsptr = calloc (1, sizeof (GIC_STATE));         /* allocate a new GIC state structure */

        if (nsptr == NULL)                              /* if the allocation failed */
            break;                                      /*   then clean up before exiting */

        gics [gic_count + count].sptr = nsptr;          /* save the new state pointer */
        gics [gic_count + count].dptr = dptr;           /*   and device pointer in the table */

        mptr = malloc (sizeof gic_mod);                 /* allocate a new modifier table */

        if (mptr == NULL)                               /* if the allocation failed */
            break;                                      /*   then clean up before exiting */

        dptr->modifiers = mptr;                         /* save the new modifiers pointer */

        memcpy (mptr, gic_mod, sizeof gic_mod);         /* copy the original modifier array */

        do                                                              /* loop through the modifiers */
            if (mptr->desc != NULL)                                     /*   and if the descriptor is a pointer */
                mptr->desc = (char *) mptr->desc - (char *) &gic_dib    /*     then relocate it */
                               + (char *) dibptr;                       /*       to point into the new DIB */
        while ((++mptr)->mask != 0);

        for (rptr = dptr->registers; rptr->name != NULL; rptr++)    /* loop through the register entries */
            rptr->loc = (char *) rptr->loc - (char *) &gic_state    /*   to get the location offsets */
                          + (char *) nsptr;                         /*     and relocate them to the new state */

        status = SCPE_OK;                               /* this pass succeeded */
        }                                               /* end of the for loop */

    gic_count = gic_count + delta;                      /* bump the count of GIC instances */
    }


if (delta < 0 || status != SCPE_OK) {                   /* if device clones are being deallocated */
    if (delta < 0)                                      /*   then if existing entries are to be deleted */
        delta = - delta;                                /*     then make the deletion count positive */

    gic_count = gic_count - delta;                      /* drop the count of GIC instances */

    for (count = 0; count < delta; count++) {           /* for each device clone to be deleted */
        dptr = dvptr [count];                           /*   get the device pointer */

        if (dptr != NULL) {                             /* if it is defined */
            free (dptr->ctxt);                          /*   then free the device context */
            free (dptr->modifiers);                     /*     and the modifier array */
            }

        if (gics [gic_count + count].sptr != NULL)      /* if the GIC state was allocated */
            free (gics [gic_count + count].sptr);       /*   then free it */

        gics [gic_count + count].dptr = NULL;           /* clear the */
        gics [gic_count + count].sptr = NULL;           /*   table entries */
        }
    }

return (uint32) status;                                 /* return the adjustment status */
}



/********************************
 *                              *
 * Interface local bus routines *
 *                              *
 ********************************/


/* Accept a command or data byte from the bus.

   This routine is called whenever the controller or talker has sourced a data
   byte to the bus, or whenever a controller, talker, or listener has changed
   the control state of the bus.

   When accepting a byte with DAV asserted, it corresponds in hardware to
   performing the IEEE-488 AH (Acceptor Handshake), T (Talker), L (Listener),
   RL (Remote Local), and DC (Device Clear) interface functions.  When changing
   the control signals without sourcing a byte, i.e., with DAV denied, it
   corresponds to performing the IEEE-488 SR (Service Request), PP (Parallel
   Poll), and C (Controller) interface functions.

   If data is present, it decodes primary, secondary, talk, and listen commands,
   and receives data bytes if the PHI is a current listener.  For control
   changes, it conducts parallel polls if the PHI is the controller or provides
   a poll response if the PHI is a device, and it responds to the IFC (Interface
   Clear) and SPE (Serial Poll Enable) commands.

   On entry, the "gic_id" parameter is the instance identifier of the GIC
   connected to the bus, and the "bus" parameter is the set of eight control and
   eight data lines representing the HP-IB.  If a poll is in progress, the
   routine returns the current set of poll responses (if the controller) or the
   device-specific poll response (if a device).  Otherwise, it returns the bit
   corresponding to the PHI address if the PHI is currently a listener.

   When called, the routine begins by updating the PHI's local copy of the bus
   state.  This is normally redundant, as the bus source routine also makes a
   local copy but is required when two GICs are cross-connected on the same bus
   during diagnostics.

   Then, the bus is checked for the presence of an active parallel poll (i.e.,
   ATN and EOI are both asserted).  If the poll is active, then if a New Status
   register bit is set, the channel request is not inhibited, and DMA is
   inactive, then a status interrupt is generated.

   If the PHI is the controller, then each bus acceptor other than the current
   GIC acceptor is called to obtain that acceptor's list of poll responses.
   These are merged to produce the set of active responses.  If the PHI is
   offline, then only its own bus response is included in the set; otherwise, it
   is merged with the other responses.

   The poll responses are then normalized with the poll state register value and
   masked by the poll mask register value.  If a normalized response remains,
   and the inbound FIFO is empty, then the poll response interrupt bit is set,
   and a channel request is asserted.  Otherwise, the response interrupt bit is
   cleared.

   If the PHI is not the controller, and the poll response bit in Register 6 is
   set, the device poll response is returned to the caller, which will be the
   other GIC that is the controller-in-charge.

   For a control request (DAV is denied), IFC assertion unaddresses all bus
   devices, including the PHI.  If IFC is denied, and a serial poll is enabled,
   then the PHI sources its serial poll response byte to the bus.  The byte is
   either the Status Byte Affirmative or the Status Byte Negative, depending on
   the state of the SRQ bit in Register 6.  Per the IEEE-488 spec, the bytes are
   sourced repeatedly until data transfer is inhibited or a Serial Poll Disable
   command is issued.  Finally, if data transfer is enabled (i.e., ATN and NRFD
   are denied), any pending outbound data is transferred to the bus.  In the
   specific case of a call that denies NRFD, this reenables the PHI-as-talker to
   resume sourcing data.

   For a data request (DAV is asserted), the ATN signal is checked to determine
   if a command byte or a data byte is being accepted.  For commands, the
   command group -- primary, secondary, talker, or listener -- is initially
   determined, and then the specific command within the indicated group is
   decoded.  The following primary commands are recognized and processed by the
   PHI:

     Code  Command
     ----  -------------------------
     DCL   Device Clear
     GTL   Go To Local
     TCT   Take Control
     PPC   Parallel Poll Configure
     PPU   Parallel Poll Unconfigure
     SPE   Serial Poll Enable
     SPD   Serial Poll Disable

   All other primary commands are ignored.

   If the PHI is not the controller, and a Go To Local command or a change in
   the REN (Remote Enable) signal state causes the PHI to go from remote to
   local mode or vice versa, or a Take Control command causes the PHI to gain or
   lose controller status, then the Status Change bit in Register 2 is set.  If
   the interrupt is not masked, channel service is requested.

   The PHI maintains the bus address of the current talker and a bitmap of the
   bus addresses of the current listeners.  Commands in the Talk Address Group
   and Listen Address Group are decoded to determine the current talker and
   listener(s).

   Secondary Command Group commands are examined only when a Parallel Poll
   Configure operation is in progress.  Otherwise, the command is loaded into
   the inbound FIFO with a tag indicating that it is a secondary; it is then up
   to the program using the GIC to determine its significance.

   For data bytes, if the PHI is a listener, then it accepts the byte, tags it
   appropriately, and loads it into the inbound FIFO.  The byte will be
   transferred to memory if inbound DMA is active or will remain in the FIFO for
   programmatic access.  If the PHI is not a listener, the data byte is ignored.

   When processing is complete, the routine returns the PHI's address bit if it
   is listening.  Otherwise, it returns a zero value.


   Implementation notes:

    1. Poll responses are traced using the response set present on the bus.
       Response recognition is conditioned by the values present in Registers 4
       (Poll Response Mask) and 5 (Poll Response Sense), e.g., a response could
       be if masked off to prevent recognition, or the sense could be inverted
       to recognize a response where one is not present on the bus.

    2. The DAV signal must be denied on the PHI bus here, as well as in the
       "hpib_source" routine, to ensure that the signal is denied during
       diagnostics in both cross-connected GICs.

    3. The IEEE-488 spec says that TADS is optional if TCT is received in CADS.
       Consequently, we check that the PHI is the talker when taking control but
       not when losing control.

    4. When the controller or a device is addressed to talk, data transfer is
       inhibited if either ATN or NRFD is asserted.  In particular, it cannot
       send the first data byte until the ATN that accompanies the Talk command
       is denied, and it must stop when ATN is asserted to send the Untalk
       command.  In hardware, this corresponds to the transition from TADS
       (talker addressed state) to TACS (talker active state) and vice versa.
       Once ATN is denied, to then source a byte to the bus, NRFD must be
       denied, corresponding to the transition from SDYS (source delay state) to
       STRS (source transfer state).  A listener may hold off the talker by
       asserting NRFD until it is ready to receive.

    5. In hardware, when the PHI is the controller, it conducts an automatic
       continuous parallel poll whenever the outbound FIFO is empty and a byte
       transfer enable is not in effect.  The poll terminates when a byte is
       loaded into the outbound FIFO.  Following this behavior in simulation
       would generate a lot of overhead, as each acceptor would receive a poll
       after every command or data byte sent by the PHI; this doesn't happen in
       hardware if the host sends the bytes fast enough to prevent the FIFO from
       emptying.  Instead, we request a poll by setting the "poll_active" field
       TRUE after the Device Clear, Serial Poll Disable, and Unlisten commands,
       as well as when an inbound transfer completes.  The "hpib_source" routine
       will see this and call us again to conduct the poll.

    6. When the last byte in a transfer is received, a parallel poll is
       requested.  Assertion of ATN for the poll additionally stops the sourcing
       of serial poll response bytes.

    7. The IEEE-488 spec defines the MSB (DIO8) of bus commands as "don't care",
       while the PHI defines this bit as the odd parity bit.  In hardware, the
       PHI checks received commands for odd parity, and incorrect parity will
       set the parity error bit in Register 2.  If the parity freeze bit of
       Register 6 is set, the command will not executed, and the bus handshake
       is held off until the controller denies DAV.  If the freeze bit is clear,
       the command will be allowed to execute in spite of the bad parity.

       This behavior is not simulated.  Parity is not checked, so the parity
       error bit is never set, and commands are executed regardless of the
       setting of the parity freeze bit.

    8. In hardware, the PHI responds to the SDC (Selected Device Clear), GET
       (Group Execute Trigger), and LLO (Local Lockout) primary commands.  These
       are not implemented in simulation.

    9. In hardware, the PHI can respond to an Amigo Identify sequence when it is
       configured as a device.  This behavior is not simulated.

   10. In hardware, the PHI honors the Sense bit of the PPE (Parallel Poll
       Enable) command that indicates the polarity of the poll response.  This
       behavior is not simulated.
*/

static uint32 gic_hpib_accept (uint32 gic_id, BUS_CABLE bus)
{
DEVICE    *const dptr    = gics [gic_id].dptr;          /* the per-instance device pointer */
GIC_STATE *const gic     = gics [gic_id].sptr;          /* the per-instance GIC state pointer */
PHI_STATE *const phi     = &gic->phi;                   /* the per-instance PHI state pointer */
DIB       *const dibptr  = (DIB *) dptr->ctxt;          /* the device context pointer */
const uint32     channel = dibptr->channel_number;      /* the IMB channel number */
BUS_DISPATCH     *dsptr;
BUS_DATA         data;

phi->bus = bus;                                         /* synchronize the bus signals */

phi->poll_active = (bus & BUS_PPOLL) == BUS_PPOLL;      /* TRUE if a parallel poll is in progress */

if (not phi->poll_active)                               /* if the poll is not in progress */
    phi->registers [Phi_2] &= ~R2_POLL;                 /*   then clear the poll available interrupt */

if (phi->poll_active) {                                 /* if the poll is currently active */
    if (gic->new_status)                                /*   then if a New Status register bit is set */
        request_service (gic, phi);                     /*   then request service if enabled */

    if (phi->registers [Phi_1] & R1_CNTLR) {            /* if the PHI is the controller-in-charge */
        if (phi->registers [Phi_7] & R7_ONLINE)         /*   then if the PHI is online */
            dsptr = gic->dispatcher;                    /*     then point at the start of the dispatch table */
        else                                            /*   otherwise */
            dsptr = gic->gic_dispatcher;                /*     point at the (final) GIC entry */

        if (phi->registers [Phi_6] & R6_POLL)           /* if the poll response bit is set */
            phi->response_set = phi->poll_response;     /*   then include the PHI poll response */
        else                                            /* otherwise */
            phi->response_set = 0;                      /*   exclude it */

        while (dsptr->accept != NULL) {                 /* while there are more acceptors to notify */
            if (dsptr->dptr != dptr)                    /*   if we are not notifying ourself */
                phi->response_set |=                    /*     then merge in the acceptor's poll responses */
                  dsptr->accept (dsptr->instance, phi->bus);
            dsptr++;                                    /*       and continue with the next acceptor */
            }

        if (TRACINGP (dptr, TRACE_XFER)                 /* if bus tracing is active */
          && phi->response_set)                         /*   and a response is present, then report it */
            trace_hpib (gic_id, phi->bus | Bus_DAV | phi->response_set);

        phi->response_set = (phi->response_set          /* normalize the response set */
                             ^ phi->registers [Phi_5])  /*   with the poll sense */
                             & phi->registers [Phi_4];  /*     and qualify with the poll mask */

        if (phi->response_set                           /* if a normalized response is present */
          && not (phi->registers [Phi_2] & R2_DATA)) {  /*   and the inbound FIFO is empty */
            phi->registers [Phi_2] |= R2_POLL;          /*     then set the poll available bit */

            if (phi_interrupts (gic, phi))              /* if the PHI is interrupting */
                imb_assert_CSRQ (channel);              /*   then request channel service */
            }

        else                                            /* otherwise */
            phi->registers [Phi_2] &= ~R2_POLL;         /*   clear the poll response bit */

        return phi->response_set;                       /* return the response set to our caller */
        }

    else if (phi->registers [Phi_6] & R6_POLL)          /* otherwise if the poll response bit is set */
        return phi->poll_response;                      /*   then return the PHI poll response */
    }

else if (not (bus & Bus_DAV)) {                                 /* otherwise if this is a control request */
    if (bus & Bus_IFC) {                                        /*   then if Interface Clear is asserted */
        phi->talker = 0;                                        /*     then unaddress the current talker */
        phi->listeners = 0;                                     /*       and all listeners */
        phi->registers [Phi_1] &= ~(R1_TALKER | R1_LISTENER);   /*         including the PHI if addressed */
        }

    else {                                              /* otherwise */
        while (phi->serial_poll_active                  /*   while a serial poll is active */
          && not (phi->bus & (Bus_ATN | Bus_NRFD)))     /*     and ATN and NRFD are denied */
            if (phi->registers [Phi_6] & R6_SRQ)        /*       if the Request Service bit is set */
                hpib_source (channel, phi->address,     /*         then respond with affirmative status */
                             Bus_DAV | BUS_SBA);
            else                                        /*       otherwise */
                hpib_source (channel, phi->address,     /*         respond with negative status */
                             Bus_DAV | BUS_SBN);

        if (not (phi->bus & (Bus_ATN | Bus_NRFD)))      /* if data transfer is enabled */
            transfer_data (gic_id);                     /*   then transfer any outbound data */
        }
    }

else if (bus & Bus_ATN) {                               /* otherwise if this is a command byte */
    phi->bus &= ~Bus_DAV;                               /*   then clear the data handshake */

    switch (BUS_GROUP (bus)) {                          /* dispatch the bus group */

        case BUS_PCG:                                   /* Primary Command Group */
            phi->poll_configure = FALSE;                /* all primaries disable poll configuration */

            switch (BUS_COMMAND (bus)) {                /* dispatch the primary command */

                case BUS_DCL:                                   /* Universal Device Clear */
                    if (phi->registers [Phi_1] & R1_CNTLR) {    /* if the PHI is the controller */
                        phi->registers [Phi_2] &= ~R2_EVENTS;   /*   then clear the interrupt events */
                        phi->poll_active = TRUE;                /*     and request a parallel poll */
                        }

                    else                                    /* otherwise */
                        phi->registers [Phi_2] |= R2_DCL;   /*   set the DCL interrupt bit */
                    break;


                case BUS_GTL:                                   /* Go To Local */
                    if (phi->registers [Phi_1] & R1_LISTENER    /* if the PHI is listening */
                      && phi->registers [Phi_1] & R1_REMOTE) {  /*   and is in remote mode */
                        phi->registers [Phi_1] &= ~R1_REMOTE;   /*     then set the mode to local */

                        if (not (phi->registers [Phi_1] & R1_CNTLR))    /* if the PHI is not the controller */
                            phi->registers [Phi_2] |= R2_STATUS;        /*   then set the Status Change bit */
                        }
                    break;


                case BUS_TCT:                                   /* Take Control */
                    if (phi->registers [Phi_1] & R1_CNTLR) {    /* if the PHI is the controller */
                        phi->registers [Phi_1] &= ~R1_CNTLR;    /*   then lose control */
                        phi->registers [Phi_2] |= R2_STATUS;    /*     and set the Status Change bit */

                        phi->address = R7_ADDRESS (phi->registers [Phi_7]); /* change to the device address */
                        }

                    else if (phi->registers [Phi_1] & R1_TALKER) {  /* otherwise if the PHI is addressed to talk */
                        phi->registers [Phi_1] |= R1_CNTLR;         /*   then take control */
                        phi->registers [Phi_2] |= R2_STATUS;        /*     and set the Status Change bit */

                        phi->address = CIC_ADDRESS;     /* change to the controller address */
                        }
                    break;


                case BUS_PPC:                                   /* Parallel Poll Configure */
                    if (phi->registers [Phi_1] & R1_LISTENER)   /* if the PHI is addressed to listen */
                        phi->poll_configure = TRUE;             /*   then enable poll configuration */
                    break;


                case BUS_PPU:                           /* Parallel Poll Unconfigure */
                    phi->poll_response = BUS_NONE;      /* clear our response bit */
                    break;


                case BUS_SPE:                               /* Serial Poll Enable */
                    if (phi->registers [Phi_1] & R1_TALKER) /* if the PHI is the talker */
                        phi->serial_poll_active = TRUE;     /*   then enable the serial poll response */
                    break;


                case BUS_SPD:                           /* Serial Poll Disable */
                    phi->serial_poll_active = FALSE;    /* disable the serial poll response */

                    if (phi->registers [Phi_1] & R1_CNTLR)  /* if the PHI is the controller */
                        phi->poll_active = TRUE;            /*   and request a parallel poll */
                    break;


                default:                                /* unknown primaries */
                    break;                              /*   are ignored */
                }

            if (phi_interrupts (gic, phi))              /* if the PHI is interrupting */
                imb_assert_CSRQ (channel);              /*   then request channel service */
            break;


        case BUS_LAG:                                               /* Listen Address Group */
            if (not (phi->registers [Phi_7] & R7_LISTEN_ALWAYS))    /* if not addressed to listen always */
                if (BUS_ADDRESS (bus) == BUS_UNADDRESS) {           /*   then if this is an unlisten */
                    phi->listeners = 0;                             /*     then clear all listeners */
                    phi->registers [Phi_1] &= ~R1_LISTENER;         /*       and exit LADS */

                    if (phi->registers [Phi_1] & R1_CNTLR)  /* if the PHI is the controller */
                        phi->poll_active = TRUE;            /*   then request a parallel poll */
                    }

                else {                                              /*   otherwise */
                    phi->listeners |= BIT (BUS_ADDRESS (bus));      /*     set the listener address bit */

                    if (BUS_ADDRESS (bus) == phi->address) {        /* if the PHI is addressed to listen */
                        phi->registers [Phi_1] |= R1_LISTENER;      /*   then enter LADS */

                        if (bus & Bus_REN                               /* if Remote Enable is asserted */
                          && not (phi->registers [Phi_1] & R1_REMOTE))  /*   and the PHI is in local mode */
                            phi->registers [Phi_1] |= R1_REMOTE;        /*     then set the mode to remote */

                        else if (phi->registers [Phi_1] & R1_REMOTE /* otherwise if the PHI is in remote mode */
                          && not (bus & Bus_REN))                   /*   but Remote Enable is denied */
                            phi->registers [Phi_1] &= ~R1_REMOTE;   /*     then set the mode to local */

                        else                            /* otherwise the mode did not change */
                            break;                      /*   so skip the status change */

                        if (not (phi->registers [Phi_1] & R1_CNTLR)) {  /* if the PHI is not the controller */
                            phi->registers [Phi_2] |= R2_STATUS;        /*   then set the Status Change bit */

                            if (phi_interrupts (gic, phi))  /* if the PHI is interrupting */
                                imb_assert_CSRQ (channel);  /*   then request channel service */
                            }
                        }
                    }
            break;


        case BUS_TAG:                                               /* Talk Address Group */
            if (not (phi->registers [Phi_7] & R7_TALK_ALWAYS)) {    /* if not addressed to talk always */
                if (BUS_ADDRESS (bus) == BUS_UNADDRESS)             /*   then if this is an untalk */
                    phi->talker = 0;                                /*     then clear all talk bits */
                else                                                /*   otherwise */
                    phi->talker = BIT (BUS_ADDRESS (bus));          /*     set the talker address bit */

                if (BUS_ADDRESS (bus) == phi->address)      /* if the PHI is addressed to talk */
                    phi->registers [Phi_1] |= R1_TALKER;    /*   then enter TADS */
                else                                        /* otherwise */
                    phi->registers [Phi_1] &= ~R1_TALKER;   /*   exit TADS */
                }
            break;


        case BUS_SCG:                                                   /* Secondary Command Group */
            if (phi->poll_configure) {                                  /* if poll configuration is enabled */
                if ((bus & BUS_PPD) == BUS_PPD)                         /*   then if this disables the poll response */
                    phi->poll_response = BUS_NONE;                      /*     then clear our response bit */
                else                                                    /*   otherwise it enables the PPR */
                    phi->poll_response = BIT (BUS_PPE_RESPONSE (bus));  /*     at the address specified */
                }

            else {                                      /* otherwise poll configuration is not enabled */
                data = BUS_ADDRESS (bus);               /*   so pick up the secondary address */

                if (phi->command == (BUS_TALK | phi->address))          /* if the PHI is the talker */
                    data |= R0_TO_MODE (R0_MODE_SECONDARY) | R0_TALK;   /*   then tag as a talk secondary */
                else if (phi->command == (BUS_LISTEN | phi->address))   /* otherwise if it is a listener */
                    data |= R0_TO_MODE (R0_MODE_SECONDARY);             /*   then tag as a listen secondary */
                else                                                    /* otherwise */
                    break;                                              /*   it is not our secondary */

                fifo_load (gic_id, Inbound, data);      /* load the secondary into the FIFO */
                transfer_data (gic_id);                 /*   and transfer it if DMA is active */
                }
            break;
        }

    phi->command = BUS_COMMAND (bus);                   /* save the last primary command */
    }

else if (phi->registers [Phi_1] & R1_LISTENER) {        /* otherwise if the PHI is listening */
    data = BUS_DATA (bus);                              /*   then get the data byte */

    if (bus & Bus_EOI                                   /* if EOI is asserted */
      || data == LF && phi->tag_lf)                     /*   or it's a line feed and detection is enabled */
        data |= R0_TO_MODE (R0_MODE_TAGGED);            /*     then tag the byte */

    else if (phi->byte_count == 1)                      /* otherwise if this exhausts the byte count */
        data |= R0_TO_MODE (R0_MODE_FINAL);             /*   then tag it as final */

    phi->bus &= ~(Bus_EOI | Bus_DAV);                   /* clear the data handshake */

    fifo_load (gic_id, Inbound, data);                  /* load the data into the inbound FIFO */

    if (phi->byte_count > 0)                            /* if this is a counted transfer */
        phi->byte_count--;                              /*   then count the byte */

    if (R0_MODE (data) != R0_MODE_DATA)                 /* if the last byte of a counted transfer is in */
        phi->poll_active = TRUE;                        /*   then request a parallel poll */

    transfer_data (gic_id);                             /* transfer the data if DMA is active */
    }

else                                                    /* otherwise the PHI is not listening */
    phi->bus &= ~(Bus_EOI | Bus_DAV);                   /*   so just clear the data handshake */

if (gic->new_status)                                    /* if any status bits are set */
    request_service (gic, phi);                         /*   then request service if enabled */

return phi->listeners & BIT (phi->address);             /* return the PHI address bit if listening */
}


/* Report the protocol configuration.

   This routine is called during run-time initialization to report the
   configuration of the GIC protocol handler.  On entry, "channel" contains the
   channel number for which the report is requested.  The routine returns a
   structure containing a pointer to the GIC device, the instance ID of the
   protocol handler, and a bitmap of the devices present on the bus and
   supported by the protocol.


   Implementation notes:

    1. The routine reports that the PHI is present on its controller address
       (CIC_ADDRESS) rather than at its current address (phi->address).  This is
       because the PHI defaults to a device controller at bus address 0 until it
       is made the controller-in-charge by a bus Interface Clear command.  Were
       that address returned, a bus conflict would occur, preventing the CPU
       from issuing the IMB INIT command that would make the PHI the controller
       and shifting to the controller address.
*/

static BUS_REPORT gic_report (uint32 channel)
{
const uint32 gic_id = id_map [channel];         /* the instance ID of the associated GIC */
BUS_REPORT   report;

report.dptr     = gics [gic_id].dptr;                   /* report the device pointer */
report.instance = gic_id;                               /*   and the GIC instance */
report.present  = BIT (CIC_ADDRESS);                    /*     and the controller address */

return report;                                          /* return the configuration report */
}



/************************************
 *                                  *
 * Interface local utility routines *
 *                                  *
 ************************************/


/* Read a PHI or GIC register.

   This routine reads a specified register from the PHI or GIC and returns the
   result as a structure containing outbound data and signals fields.  On entry,
   "channel" contains the GIC channel address, "Register" contains the
   identifier of the register to read, and "command" contains the IMB command
   requesting the read.  The command typically is RIOC but may also be OBII or
   OBSI.  The read of Register F responds differently depending on whether the
   command is RIOC or OBSI.

   If DMA is currently active, then access to the PHI registers (Register 0
   through Register 7) will result in a Data Not Valid response.


   Implementation notes:

    1. The parallel poll response trace is handled locally in the register 0
       handler below, rather than using the "trace_register" call at the bottom
       of the routine.  The reason is that the CPP unloads any spurious data
       from the inbound FIFO when DMA ends unexpectedly, e.g., after an abort.
       This occurs after the Unlisten has been sent, i.e., while a parallel poll
       is being conducted.  The common call cannot differentiate between a poll
       response that exists with the FIFO empty on entry and the last spurious
       byte in the FIFO that is not empty on entry.  After the last byte has
       been unloaded, then in both cases, the poll is active, and the inbound
       FIFO is empty.  So the poll case is handled locally, while the data case
       is handled within the "trace_register" routine.

    2. Where the read and write values of registers differ, registers generally
       hold the read value.  However, some bits are set dynamically, such as
       hardware switch settings, so as to return the current settings without
       having to track the changes.
*/

static IMB_OUTBOUND read_register (uint32 channel, REGISTER Register, IMB_IO_COMMAND command)
{
const uint32     gic_id   = id_map [channel];           /* the instance ID of the associated GIC */
DEVICE    *const dptr     = gics [gic_id].dptr;         /* the per-instance device pointer */
GIC_STATE *const gic      = gics [gic_id].sptr;         /* the per-instance GIC state pointer */
PHI_STATE *const phi      = &gic->phi;                  /* the per-instance PHI state pointer */
IMB_OUTBOUND     outbound = { 0, ADN | DDN | PRO };     /* the initial outbound value and signal set */

if (gic->dma_busy && Register <= Reg_7)                 /* if DMA is active */
    outbound.signals |= DNV;                            /*   then PHI register access is prohibited */

else switch (Register) {                                /* otherwise dispatch the register read */

    case Reg_0:                                             /* FIFO Inbound */
        if (not (phi->registers [Phi_2] & R2_DATA))         /* if the inbound FIFO is empty */
            if (phi->poll_active) {                         /*   then if a parallel poll is active */
                phi->registers [Phi_0] = phi->response_set; /*     then get the poll responses */

                tpprintf (dptr, TRACE_CSRW, "Register 0 (FIFO) Poll response %s\n",
                          fmt_bitset (phi->response_set, (*formatter [Reg_0].bit_format) [Read]));

                outbound.data = phi->registers [Phi_0]; /* assign the register content */
                return outbound;                        /*   and return the data and signals */
                }

            else {                                      /* otherwise */
                phi->registers [Phi_2] |= R2_HSABORT;   /*   a handshake abort occurs */

                if (phi->registers [Phi_6] & R6_OUTBOUND    /* if DMARQ is asserted because */
                  && phi->registers [Phi_2] & R2_AVAIL)     /*   space is available in the outbound FIFO */
                    phi->registers [Phi_0] = 0;             /*     then return an arbitrary value */
                else                                        /*   otherwise */
                    outbound.signals |= DNV;                /*     assert Data Not Valid */
                }

        else {                                                      /* otherwise */
            phi->registers [Phi_0] = fifo_unload (gic_id, Inbound); /*   unload a byte from the FIFO */

            if (not (phi->registers [Phi_2] & R2_DATA)  /* if the FIFO is now empty */
              && phi->poll_active                       /*   and a parallel poll is active */
              && phi->response_set                      /*   and device responses are present */
              && phi->registers [Phi_1] & R1_CNTLR) {   /*   and the PHI is the controller-in-charge */
                phi->registers [Phi_2] |= R2_POLL;      /*     then set the poll available bit */
                transfer_data (gic_id);                 /*       and transfer more if DMA is active */
                }
            }

        outbound.data = phi->registers [Phi_0];         /* return the register content */
        break;


    case Reg_1:                                         /* Status */
        if (not (phi->registers [Phi_7] & R7_ONLINE)    /* if the PHI is offline */
          || not (dptr->flags & DEV_NOT_SYS))           /*   or the system controller switch is on */
            phi->registers [Phi_1] |= R1_SYSCNTLR;      /*     then set the bit */
        else                                            /* otherwise */
            phi->registers [Phi_1] &= ~R1_SYSCNTLR;     /*   clear it */

        outbound.data = phi->registers [Phi_1];         /* return the register content */
        break;


    case Reg_2:                                         /* Interrupt Conditions */
        if (phi->bus & Bus_SRQ)                         /* if SRQ is asserted on the bus */
            phi->registers [Phi_2] |= R2_SRQ;           /*   then set the SRQ active bit */
        else                                            /* otherwise */
            phi->registers [Phi_2] &= ~R2_SRQ;          /*   clear the SRQ bit */

        outbound.data = phi->registers [Phi_2]          /* return the interrupt conditions */
                          & phi->registers [Phi_3];     /*   masked by the interrupt mask */

        if (outbound.data != 0)                                     /* if an unmasked interrupt is present */
            outbound.data |= phi->registers [Phi_3] & R3_ENABLE;    /*   then set the pending bit if enabled */
        break;


    case Reg_3:                                         /* Interrupt Mask */
    case Reg_4:                                         /* Parallel Poll Mask */
    case Reg_5:                                         /* Parallel Poll Sense */
    case Reg_6:                                         /* Control */
    case Reg_7:                                         /* HP-IB Address */
        outbound.data = phi->registers [Register];      /* return the register content */
        break;


    case Reg_8:                                                         /* DMA Extended Address */
        gic->registers [Gic_8] = gic->registers [Gic_8]                 /* keep just the */
                                   & R8_DMA_ENABLED                     /*   enable flip-flop state */
                                   | R8_TO_DMA_STATE (gic->dma_state)   /*     and add the state number and bank */
                                   | R8_TO_BANK (UPPER_WORD (gic->dma_address));

        outbound.data = gic->registers [Gic_8];         /* return the register content */
        break;


    case Reg_9:                                         /* DMA Address */
        outbound.data =                                 /* return the current DMA lower address */
          gic->registers [Gic_9] = TO_OFFSET (gic->dma_address);
        break;


    case Reg_A:                                         /* DMA Byte Count */
        outbound.data =                                 /* return the current DMA byte count */
          gic->registers [Gic_A] = gic->dma_count & D16_MASK;
        break;


    case Reg_B:                                             /* DMA Status/Control */
        gic->registers [Gic_B] &= ~(RB_TEST | RB_DMA_BUSY   /* clear the test and busy bits */
                                      | RB_DMA_STATUS);     /*   and the termination status field */

        if (dptr->flags & DEV_TEST)                     /* if switch S5 is in the TEST position */
            gic->registers [Gic_B] |= RB_TEST;          /*   then set the TEST bit */

        if (gic->dma_busy)                              /* if DMA is not idle */
            gic->registers [Gic_B] |= RB_DMA_BUSY;      /*   then set the busy bit */

        gic->registers [Gic_B] |= RB_TO_STATUS (gic->dma_status);   /* add the termination status */

        outbound.data = gic->registers [Gic_B];         /* return the register content */
        break;


    case Reg_C:                                         /* Interrupt Register */
        outbound.data = gic->registers [Gic_C];         /* return the register content */
        break;


    case Reg_D:                                             /* Interrupt Information */
        gic->registers [Gic_D] = RD_TO_CHANNEL (channel);   /* set the channel number field */

        if (not gic->interrupts || not gic->irq_mask)   /* if there are no interrupts or the mask inhibits */
            gic->registers [Gic_D] |= RD_INVALID;       /*   then the register value is invalid */

        if (gic->interrupts)                            /* if interrupts are present */
            gic->registers [Gic_D] |=                   /*   then get the highest priority device number */
              RD_TO_DEVICE (BIT_NUMBER (gic->interrupts));
        else                                            /* otherwise */
            gic->registers [Gic_D] |= RD_TO_DEVICE (7); /*   the device number is defaulted */

        outbound.data = gic->registers [Gic_D];         /* return the register content */
        break;


    case Reg_E:                                         /* Channel Configuration/DMA Abort */
        gic->registers [Gic_E] = 0;                     /* set the channel type to 0 (GIC) */

        if (dptr->flags & DEV_TYPE_B)                   /* if switch S2 is set to the B position */
            gic->registers [Gic_E] |= RE_HYBRID;        /*   then set the hybrid bit */

        if (dptr->flags & DEV_CPP)                      /* if switch S1 is set to the CPP position */
            gic->registers [Gic_E] |= RE_CPP;           /*   then set the CPP bit */

        outbound.data = gic->registers [Gic_E];         /* return the register content */
        break;


    case Reg_F:                                         /* Channel Service Information */
        tpprintf (dptr, TRACE_CSRW, "CSRQ asserted for %s\n",
                        fmt_bitset (gic->channel_requests, csrq_format));


        gic->dma_obsi = (gic->dma_busy && not gic->dma_run  /* set the OBSI seen flag */
                          && command == OBSI);              /*   if waiting for this OBSI request */

        gic->registers [Gic_F] = gic->registers [Gic_F]         /* keep just the */
                                  & (RF_TIMEOUT | RF_DMA_ABORT) /*   timeout and abort bits */
                                  | RF_TO_CHANNEL (channel);    /*     and merge the channel number */

        if (gic->channel_requests & DMA_Interrupt)      /* if a DMA interrupt is present */
            gic->registers [Gic_F] |= RF_CHNRQ          /*   then set a channel request for the target device */
                                        | RB_DEVICE (gic->registers [Gic_B]);

        else if (gic->channel_requests & PHI_Interrupt) {   /* otherwise if a PHI interrupt is present */
            if (command == OBSI                             /*   then if this is an OBSI request */
              && phi->poll_active                           /*   and a parallel poll is in progress */
              && phi->registers [Phi_2] & R2_POLL           /*   and a poll response is available */
              && not (gic->registers [Gic_B] & RB_NO_POLL)  /*   and channel service is not disabled */
              && phi->registers [Phi_1] & R1_CNTLR)         /*   and the PHI is the controller */
                gic->registers [Gic_F] |= RF_DEVRQ          /*     then set a device request for the responder */
                                            | RF_DEVICE (HPIB_BIT_NUMBER (phi->response_set));

            else                                        /* otherwise */
                gic->registers [Gic_F] |= RF_CHNRQ      /*   set a channel request for the target device */
                                            | RB_DEVICE (gic->registers [Gic_B]);
            }

        else if (gic->channel_requests & Status_Interrupt) {    /* otherwise if a new status request is present */
            gic->registers [Gic_F] |= RF_DEVRQ                  /*   then set a device request for the changed device */
                                        | RF_TO_DEVICE (BIT_NUMBER (gic->new_status));
            }

        else
            gic->registers [Gic_F] |= RF_INVALID            /* otherwise no request is active */
                                        | RF_TO_DEVICE (7); /*   so the device number is defaulted */

        outbound.data = gic->registers [Gic_F];         /* return the register content */

        if (command == OBSI                             /* if this is an OBSI request */
          && gic->channel_requests & DMA_Interrupt) {   /*   and a DMA interrupt is present */
            gic->registers [Gic_F] &= ~RF_DMA_ABORT;    /*     then clear the abort bit */

            if (not (gic->registers [Gic_B] & RB_NO_POLL)) {    /* if poll requests are not disabled */
                gic->registers [Gic_F] &= ~RF_TIMEOUT;          /*   then clear the timeout event */
                timer_enable (gic_id, CLEAR);                   /*     and disable the timeout clock */
                }

            if (gic->dma_clock == 0)                    /* if DMA is automatic */
                dma_cycle (gic_id);                     /*   then allow DMA to return to the idle state */
            }
        break;
    }                                                   /* all defined cases are handled */

if (TRACINGP (dptr, TRACE_CSRW))
    trace_register (gic_id, Read, Register, outbound.data);

return outbound;                                        /* return the register data and signals */
}


/* Write a PHI or GIC register.

   This routine writes a specified PHI or GIC register from and returns the
   result as a structure containing an outbound data field, which is always
   zero, and signals field.  On entry, "channel" contains the GIC channel
   address, "Register" contains the identifier of the register to read, and
   "data" contains the data value to be written.


   Implementation notes:

    1. Writes to Register 0 do not alter the array element, which keeps its
       last-read value.

    2. Undefined bits 8-9 of Register 1 are written and read back by the CS/80
       diagnostic, so we cannot restrict the write to the freeze bit alone.

    3. When writing to Registers 8 or 9, the TO_PA macro cannot be used to form
       the physical DMA address because it masks the bank number to the number
       of bits supported by the current CPU.  The GIC diagnostic tests that all
       eight upper address (bank) bits can be written and read and will fail if
       some bits are masked.

    4. The device bits in Register C (Interrupts) are kept in HP 3000 bit order,
       i.e., device 0 corresponds with bit 8.  Rather than use the HP_BIT macro
       and offset the device number by 8, we use the HPIB_BIT macro, which
       positions the device bit correctly.
*/

static IMB_OUTBOUND write_register (uint32 channel, REGISTER Register, IMB_DATA data)
{
const uint32     gic_id = id_map [channel];     /* the instance ID of the associated GIC */
DEVICE    *const dptr   = gics [gic_id].dptr;   /* the per-instance device pointer */
GIC_STATE *const gic    = gics [gic_id].sptr;   /* the per-instance GIC state pointer */
PHI_STATE *const phi    = &gic->phi;            /* the per-instance PHI state pointer */
uint32           device;
BUS_SIGNALS      bus;
IMB_OUTBOUND     outbound = { 0, ADN | DDN | PRO };     /* the initial outbound value and signal set */

data &= formatter [Register].write_mask;                /* retain only the bits that can be written */

if (TRACINGP (dptr, TRACE_CSRW))
    trace_register (gic_id, Write, Register, data);

if (gic->dma_busy && Register <= Reg_7)                 /* if DMA is active */
    outbound.signals |= DNV;                            /*   then PHI register access is prohibited */

else switch (Register) {                                /* otherwise dispatch the register write */

    case Reg_0:                                         /* Outbound FIFO */
        fifo_load (gic_id, Outbound, data);             /* load the word into the FIFO */
        transfer_data (gic_id);                         /*   and transfer it out to the bus */
        break;


    case Reg_1:                                             /* Status */
        phi->registers [Phi_1] = phi->registers [Phi_1]     /* update the register */
                                   & ~(data & R1_FREEZE)    /*   by clearing the freeze bit if it is set */
                                   | data & ~R1_FREEZE;     /*     and then merging the other bits */
        break;


    case Reg_2:                                         /* Interrupt Conditions */
        phi->registers [Phi_2] &= ~data;                /* clear the indicated conditions */
        phi_interrupts (gic, phi);                      /*   and update the PHI interrupt state */
        break;


    case Reg_3:                                         /* Interrupt Mask */
        phi->registers [Phi_3] = data;                  /* write the new value */
        phi_interrupts (gic, phi);                      /*   and update the PHI interrupt state */
        break;


    case Reg_4:                                         /* Parallel Poll Mask */
    case Reg_5:                                         /* Parallel Poll Sense */
        phi->registers [Register] = data;               /* write the new value */

        if (phi->poll_active && phi->registers [Phi_1] & R1_CNTLR)  /* if a poll is currently active */
            hpib_source (channel, phi->address, phi->bus);          /*   then pick up any new poll responses */
        break;


    case Reg_6:                                         /* Control */
        if (phi->poll_active)                           /* if a parallel poll is active */
            bus = BUS_PPOLL;                            /*   then assert ATN and EOI on the bus */
        else                                            /* otherwise */
            bus = phi->bus & Bus_ATN;                   /*   retain the current ATN state */

        if (data & R6_SRQ)                              /* if the SRQ control is set */
            bus |= Bus_SRQ;                             /*   then assert SRQ on the bus */

        if (phi->registers [Phi_1] & R1_SYSCNTLR) {     /* if the PHI is the system controller */
            if (data & R6_REN)                          /*   then if the REN control is set */
                bus |= Bus_REN;                         /*     then assert REN on the bus */

            if (data & R6_IFC) {                        /* if the IFC control is set */
                bus = bus & ~BUS_PPOLL | Bus_IFC;       /* then assert IFC and deny ATN and EOI (poll) */

                if (not (phi->registers [Phi_1] & R1_CNTLR)) {  /* if the PHI is not the controller-in-charge */
                    phi->registers [Phi_1] |= R1_CNTLR;         /*   then the PHI gains controller status */
                    phi->registers [Phi_2] |= R2_STATUS;        /*     and the status has changed */

                    phi->address = CIC_ADDRESS;         /* change to the controller address */
                    phi_interrupts (gic, phi);          /*   and update the PHI interrupt state */

                    tpprintf (dptr, TRACE_CMD, "PHI becomes controller-in-charge with IFC\n");
                    }
                }

            else if (phi->registers [Phi_1] & R1_CNTLR  /* otherwise if the PHI is the controller */
              && (data & R6_POLL                        /*   and the poll response bit is set */
              || data & R6_CLEAR                        /*   or the outbound FIFO will be cleared */
              || phi->bus & Bus_IFC                     /*   or IFC is currently asserted */
              && phi->registers [Phi_2] & R2_EMPTY))    /*     and the outbound FIFO is empty */
                bus |= BUS_PPOLL;                       /*       then request a parallel poll */
            }

        if (data & R6_CLEAR) {                              /* if the outbound FIFO is to be cleared */
            phi->fifo_count [Outbound] = 0;                 /*   then reset the occupancy count */
            phi->registers [Phi_2] |= R2_EMPTY | R2_AVAIL;  /*     and mark it empty with space available */
            }

        phi->registers [Phi_6] = data;                  /* write the value before asserting the new bus state */

        if ((bus ^ phi->bus) & (BUS_PPOLL | Bus_IFC | Bus_REN | Bus_SRQ)    /* if a bus signal was changed */
          || phi->bus & BUS_PPOLL && data & R6_POLL)                        /*   or a poll response is asserted */
            hpib_source (channel, phi->address, bus);                       /*     then update the bus */
        break;


    case Reg_7:                                         /* HP-IB Address */
        if (not (phi->registers [Phi_7] & R7_ONLINE)    /* if the PHI is going */
          && data & R7_ONLINE) {                        /*   from offline to online */
            if (phi->registers [Phi_1] & R1_CNTLR) {    /*     then if it's the controller-in-charge */
                phi->registers [Phi_1] &= ~R1_CNTLR;    /*       then the PHI loses controller status */
                phi->registers [Phi_2] |= R2_STATUS;    /*         and the status has changed */

                tpprintf (dptr, TRACE_CMD, "PHI relinquishes controller-in-charge by going online\n");

                phi_interrupts (gic, phi);              /* update the PHI interrupt state */
                }

            if (dptr->flags & DEV_NOT_SYS)              /* if the SYS CNTLR switch is OFF */
                phi->registers [Phi_1] &= ~R1_SYSCNTLR; /*   then the PHI becomes a device controller */
            }

        if (not (data & R7_ONLINE))                     /* if the PHI is going offline */
            phi->registers [Phi_1] |= R1_SYSCNTLR;      /*   then it becomes the system controller */

        if (not (phi->registers [Phi_1] & R1_CNTLR))    /* if the PHI is a device */
            phi->address = R7_ADDRESS (data);           /*   then change to the new device address */

        if (data & R7_TALK_ALWAYS) {                    /* if the PHI is becoming the talker */
            phi->talker = BIT (phi->address);           /*   then set my talker address bit */
            phi->registers [Phi_1] |= R1_TALKER;        /*     and enter TADS */
            }

        if (data & R7_LISTEN_ALWAYS) {                              /* if the PHI is becoming a listener */
            phi->listeners |= BIT (phi->address);                   /*   then set my listener address */
            gic->gic_dispatcher->listeners = BIT (phi->address);    /*     in the set of listeners */
            phi->registers [Phi_1] |= R1_LISTENER;                  /*       and enter LADS */
            }

        if (phi->address <= 7)                              /* if the PHI address is 0-7 */
            phi->poll_response = HPIB_BIT (phi->address);   /*   then set the corresponding poll response */
        else                                                /* otherwise */
            phi->poll_response = 0;                         /*   the PHI cannot respond to a parallel poll */

        phi->registers [Phi_7] = data;                  /* write the new register value */
        break;


    case Reg_8:                                         /* DMA Extended Address */
        gic->registers [Gic_8] = gic->registers [Gic_8] /* replace the upper address bits */
                                   & ~R8_BANK_MASK      /*   in the register */
                                   | R8_BANK (data);    /*     with the new value */

    /* fall through into DMA Address case */

    case Reg_9:                                         /* DMA Address */
        if (Register == Reg_9)                          /* if writing to the address register */
            gic->registers [Gic_9] = R9_OFFSET (data);  /*   then write the new register value */

        gic->dma_address = TO_DWORD (R8_BANK   (gic->registers [Gic_8]),    /* form the new */
                                     R9_OFFSET (gic->registers [Gic_9]));   /*   linear address */
        break;


    case Reg_A:                                         /* DMA Byte Count */
        gic->dma_count =                                /* save the new byte count */
          gic->registers [Gic_A] = RA_COUNT (data);     /*   and write the new register value */
        break;


    case Reg_B:                                                 /* DMA Status/Control */
        if (not gic->dma_busy) {                                /* if DMA is inactive */
            gic->registers [Gic_B] = gic->registers [Gic_B]     /*   then update the bits */
                                       & ~RB_COMMON_BITS        /*     that are common */
                                       | data & RB_COMMON_BITS; /*       to the read and write values */

            gic->dma_frozen = (data & RB_NO_INCREMENT) != 0;    /* TRUE if the address is not to be incremented */

            gic->registers [Gic_8] |= R8_DMA_ENABLED;   /* enable DMA */

            gic->dma_run = TRUE;                        /* the DMA state machine */
            gic->dma_busy = TRUE;                       /*   is now running and busy */

            gic->dma_status = 0;                        /* reset the DMA termination status */

            if (dptr->flags & DEV_TEST                  /* if switch S5 is in the TEST position */
              && not (data & RB_NO_TEST)) {             /*   and the TEST bit is set */
                gic->dma_clock = 1;                     /*     then set the clock for single-stepping */
                timer_enable (gic_id, CLEAR);           /*       and disable the timeout clock */
                }

            else {                                      /* otherwise */
                gic->dma_clock = 0;                     /*   set the clock to run automatically */
                timer_enable (gic_id, SET);             /*     and enable the timeout clock */
                }

            gic->registers [Gic_F] &= ~RF_TIMEOUT;      /* clear the timeout flip-flop */

            transfer_data (gic_id);                     /* start the data transfer */
            }
        break;


    case Reg_C:                                         /* Interrupt Register */
        device = RC_DEVICE (data);                      /* get the interrupting device number */

        if (data & RC_SET_IRQ) {                            /* if an interrupt is requested */
            gic->registers [Gic_C] |= HPIB_BIT (device);    /*   then set the device bit in HPIB order */
            gic->interrupts |= BIT (device);                /*     and in C bit order */
            }

        else {                                              /* otherwise */
            gic->registers [Gic_C] &= ~HPIB_BIT (device);   /*   clear the */
            gic->interrupts &= ~BIT (device);               /*     device bits */
            }
        break;


    case Reg_D:                                         /* Interrupt Information */
        break;                                          /* the register is read-only */


    case Reg_E:                                         /* DMA Abort */
        if (gic->registers [Gic_8] & R8_DMA_ENABLED) {  /* if DMA is enabled */
            gic->registers [Gic_8] &= ~R8_DMA_ENABLED;  /*   then clear the enable flip-flop */
            gic->dma_status = RB_STATUS_ERROR;          /*     and indicate an abort */

            tpprintf (dptr, TRACE_CMD, "DMA aborted\n");
            }
        break;


    case Reg_F:                                                 /* Channel Service Information */
        if (not gic->dma_busy) {                                /* if DMA is inactive */
            gic->registers [Gic_B] = gic->registers [Gic_B]     /*   then update the bits in Register B */
                                       & ~RB_COMMON_BITS        /*     that are common */
                                       | data & RB_COMMON_BITS; /*       to the read and write values */

            gic->dma_frozen = (data & RF_NO_INCREMENT) != 0;    /* TRUE if the address is not to be incremented */

            if (data & RF_NO_POLL                           /* if poll requests are disabled */
              && (not (dptr->flags & DEV_TEST)              /*   and switch S5 is not in the TEST position */
              || data & RF_NO_TEST))                        /*   or testing is inhibited */
                timer_enable (gic_id, SET);                 /*     then enable the timer */

            else {                                          /* otherwise */
                gic->registers [Gic_F] &= ~RF_TIMEOUT;      /*   then clear the timeout event */
                timer_enable (gic_id, CLEAR);               /*     and freeze the timeout clock */
                }
            }
        break;
    }                                                   /* all defined cases are handled */

if (gic->new_status)                                    /* if any status bits are set */
    request_service (gic, phi);                         /*   then request service if enabled */

return outbound;                                        /* return the result of the write */
}


/* Execute one or more DMA cycles.

   This routine is called while DMA is active to cycle the DMA sequencer.  On
   entry, "gic_id" is the instance ID of the GIC.  The routine returns TRUE if
   the content of the PHI FIFOs were changed, i.e., a byte was loaded or
   unloaded, and FALSE if no data transfer occurred.  Effectively, TRUE means
   that progress was made, so the routine should be called again to continue the
   transfer.

   The DMA sequencer is a state machine with 27 states.  The five-bit state
   number is presented as bits 3-7 of Register 8.  It is normally run from a
   free-running clock or, under diagnostic control, it may be single-stepped,
   with the current state available to the diagnostic.

   Three conditions indicate the current state of the DMA sequencer:

     dma_run  dma_busy  R8_DMA_ENABLED  State
     -------  --------  --------------  --------------------------------------------
      FALSE    FALSE          0         Idle
      TRUE     TRUE           1         Running
      FALSE    TRUE           0         Completed (DMINT asserted, waiting for OBSI)
      FALSE    FALSE          0         Idle (OBSI asserted)

      TRUE     TRUE           0         Aborting (Register E write)
      FALSE    TRUE           0         Aborted (DMINT asserted, waiting for OBSI)

   State 0 is the idle state.  From there, four state paths are provided: two
   for read transfers starting with the left or right byte, and two for write
   transfers starting with the left or right byte.  Once started, the sequencer
   continues stepping through the states until continued execution is blocked
   by a temporary condition, e.g., waiting for an input byte.  Once the
   condition is satisfied, this routine will be called again to continue the
   transfer from the last state.

   In diagnostic mode, each entry executes only a single state, and then only on
   every third entry.  This corresponds in hardware to the divide-by-3 DMA
   clock counter, which is pulsed by IMB bus handshakes.


   Implementation notes:

    1. The numeric state values follow the hardware DMA sequencer states.

    2. In hardware, if a read transfer ends with a tagged byte at count = 0, the
       tag is reported instead of the count termination.  The simulator follows
       this behavior.

    3. States that block until an external condition occurs will be reentered
       when the condition is satisfied and may be reentered while waiting for
       the condition.  Therefore, such states must ensure that any operations
       that alter external values, such as incrementing the address or
       decrementing the byte count, execute only once.

    4. The "R8_DMA_ENABLED" bit of Register 8 corresponds in hardware to the
       DMAENF signal, and the "dma_busy" field of the GIC state structure
       corresponds the -DMINACT signal.  The "dma_run" field shadows the
       enabled bit, except when an abort occurs.  In this case, the enabled bit
       is cleared, which causes the DMA sequencer to go to state 5.  For the
       first entry, "dma_run" is still TRUE, so the DMA termination is performed
       and "dma_run" is set FALSE.  Subsequent state 5 entries then simply exit
       to wait for the OBSI command, which then will go to state 4.
*/

static t_bool dma_cycle (uint32 gic_id)
{
DEVICE    *const dptr   = gics [gic_id].dptr;   /* the per-instance device pointer */
GIC_STATE *const gic    = gics [gic_id].sptr;   /* the per-instance GIC state pointer */
PHI_STATE *const phi    = &gic->phi;            /* the per-instance PHI state pointer */
DIB       *const dibptr = (DIB *) dptr->ctxt;   /* the pointer to the device context */
IMB_OUTBOUND     response;
IMB_DATA         word;
t_bool           cycling;
t_bool           transfer = FALSE;              /* TRUE if a data transfer occurred */
DMA_STOP         condition = End_of_Cycle;      /* the DMA termination condition */

if (gic->dma_clock == 0)                                /* if the sequencer is running automatically */
    cycling = TRUE;                                     /*   then cycle until blocked */

else if (gic->dma_clock == 3) {                         /* otherwise if single-stepping */
    cycling = FALSE;                                    /*   then execute only one state */
    gic->dma_clock = 1;                                 /*     and reset the DMA clock */
    }

else                                                    /* otherwise */
    return FALSE;                                       /*   continue the slave handshake clocks */

do {                                                    /* run one or more DMA cycles */
    tpprintf (dptr, TRACE_STATE, "DMA executing state %u count %u\n",
              gic->dma_state, gic->dma_count);

    switch (gic->dma_state) {
        case 0:                                         /* assert DMOFF, DMRDIO */
            if (gic->dma_run) {                         /* if DMA is active */
                gic->dma_obsi = FALSE;                  /*   then clear the OBSI seen flag */

                if (gic->registers [Gic_B] & RB_OUTBOUND)       /* if this is an outbound transfer */
                    if (gic->registers [Gic_B] & RB_RIGHT_BYTE) /*   then if starting with the right-hand byte */
                        gic->dma_state = 28;                    /*     then start a right-byte write */
                    else                                        /*   otherwise */
                        gic->dma_state = 26;                    /*     then start a left-byte write */

                else                                            /* otherwise it's an inbound transfer */
                    if (gic->registers [Gic_B] & RB_RIGHT_BYTE) /*   so if starting with the right-hand byte */
                        gic->dma_state = 6;                     /*     then start a right-byte read */
                    else                                        /*   otherwise */
                        gic->dma_state = 8;                     /*     then start a left-byte read */
                }

            else                                        /* otherwise DMA is idle */
                cycling = FALSE;                        /*   so exit */
            break;


        case 1:                                         /* assert DMPHIGO2, ELOUT */
            word = UPPER_BYTE (gic->dma_buffer);        /* get the left-hand byte from the buffer */

            if (not (gic->registers [Gic_B] & RB_NO_EOI))   /* if EOI is not inhibited */
                word |= R0_EOI;                             /*   then tag the byte with EOI */

            fifo_load (gic_id, Outbound, word);         /* load the byte into the outbound FIFO */
            transfer = TRUE;                            /*   and set the FIFO changed flag */

            gic->dma_status = RB_STATUS_WCOUNT;         /* end with the DMA count complete */
            gic->dma_state = 5;                         /*   and proceed to the interrupt state */
            break;


        case 2:                                         /* assert LLIN, ELOUT */
            gic->dma_state = 10;                        /*   and proceed to decrement the count */
            break;


        case 3:                                         /* unused state */
            break;


        case 4:                                         /* assert DMINT */
            gic->channel_requests &= ~DMA_Interrupt;    /* clear he DMA interrupt request */
            gic->dma_busy = FALSE;                      /* idle the DMA */

            if (gic->new_status)                        /* if any status bits are set */
                request_service (gic, phi);             /*   then request service if enabled */

            gic->dma_state = 0;                         /* end in the idle state */
            break;


        case 5:                                         /* assert DMINT */
            if (gic->dma_obsi)                          /* if an OBSI has occurred */
                gic->dma_state = 4;                     /*   then wrap up  DMA completion */

            else {                                              /* otherwise */
                if (gic->dma_run) {                             /* if DMA is active */
                    if (gic->dma_status == RB_STATUS_ERROR)     /*   then if an error occurred */
                        gic->registers [Gic_F] |= RF_DMA_ABORT; /*     then set the DMA abort event */

                    tpprintf (dptr, TRACE_CMD, "DMA completed with status %u\n", gic->dma_status);

                    gic->registers [Gic_8] &= ~R8_DMA_ENABLED;  /* clear the enable flip-flop */
                    gic->dma_run = FALSE;                       /*   and the active state */

                    if (not (gic->registers [Gic_B] & RB_OUTBOUND)  /* if an inbound transfer is ending */
                      || gic->dma_status == RB_STATUS_ERROR) {      /*   or an abort occurred */
                        gic->channel_requests |= DMA_Interrupt;     /*     then request a DMA interrupt */
                        imb_assert_CSRQ (dibptr->channel_number);   /*       and assert a service request */
                        }
                    }

                cycling = FALSE;                        /* block until the condition occurs */
                }
            break;


        case 6:                                         /* assert DMRDRQ, ELOUT */
            response = imb_cycle (IMB_Read,             /* read the next word from memory */
                                  gic->dma_address, 0);

            if (not (response.signals & DDN))           /* if Data Done never asserted */
                condition = Memory_Timeout;             /*   then record a memory timeout */

            else if (response.signals & PER)            /* otherwise if Parity Error asserted */
                condition = Parity_Error;               /*   then record a parity error */

            gic->dma_buffer = response.data;            /* save the word in the data buffer */
            gic->dma_state = 2;                         /*   and proceed with the memory read done */
            break;


        case 7:                                         /* assert DMPHOGO2, EROUT */
            word = LOWER_BYTE (gic->dma_buffer);        /* get the right-hand byte from the buffer */

            if (not (gic->registers [Gic_B] & RB_NO_EOI))   /* if EOI is not inhibited */
                word |= R0_EOI;                             /*   then tag the byte with EOI */

            fifo_load (gic_id, Outbound, word);         /* load the byte into the outbound FIFO */
            transfer = TRUE;                            /*   and set the FIFO changed flag */

            gic->dma_status = RB_STATUS_WCOUNT;         /* end with the DMA count complete */
            gic->dma_state = 5;                         /*   and proceed to the interrupt state */
            break;


        case 8:                                                 /* assert DMRDIO, DECCNT, DMPHIGO1 */
            if (not (gic->registers [Gic_B] & RB_RIGHT_BYTE)) { /* if the left byte indicator is set */
                gic->dma_count--;                               /*   then count the byte */
                gic->registers [Gic_B] ^= RB_RIGHT_BYTE;        /*     and flip to the right byte */
                }

            if (not (gic->registers [Gic_8] & R8_DMA_ENABLED))  /* if DMA has been aborted */
                gic->dma_state = 5;                             /*   then proceed to the interrupt state */

            else if (phi->registers [Phi_2] & R2_DATA)  /* otherwise if inbound data is available */
                gic->dma_state = 9;                     /*   then proceed to set up the FIFO unload */

            else                                        /* otherwise */
                cycling = FALSE;                        /*   block until data arrives */
            break;


        case 9:                                         /* assert DMRDIO, LLIN, DMPHIGO1 */
            gic->dma_state = 20;                        /*   and proceed unload the FIFO */
            break;


        case 10:                                            /* assert DMRDIO, DECCNT, DMPHIGO1 */
            if (gic->registers [Gic_B] & RB_RIGHT_BYTE) {   /* if the right byte indicator is set */
                gic->dma_count--;                           /*   then count the byte */
                gic->registers [Gic_B] ^= RB_RIGHT_BYTE;    /*     and flip to the left byte */
                }

            if (not (gic->registers [Gic_8] & R8_DMA_ENABLED))  /* if DMA has been aborted */
                gic->dma_state = 18;                            /*   then proceed to tag the final byte */

            else if (phi->registers [Phi_2] & R2_DATA)  /* otherwise if inbound data is available */
                gic->dma_state = 11;                    /*   then proceed to unload the FIFO */

            else                                        /* otherwise */
                cycling = FALSE;                        /*   block until data arrives */
            break;


        case 11:                                        /* assert DMRDIO, DMPHIGO1 */
            word = fifo_unload (gic_id, Inbound);       /* unload the byte from the inbound FIFO */
            transfer = TRUE;                            /*   and set the FIFO changed flag */

            gic->dma_tag = R0_MODE (word);              /* get the data tag */

            gic->dma_buffer = REPLACE_LOWER (gic->dma_buffer, R0_DATA (word));  /* replace the right-hand byte */
            gic->dma_state = 15;                                                /*   and proceed to write the word */

            if (dptr->flags & DEV_DIAG) {                           /* if the GIC is in diagnostic mode */
                hpib_source (dibptr->channel_number,                /*   then hold off the data transfer */
                             phi->address, phi->bus | Bus_NRFD);    /*     by asserting NRFD */

                dptr->units [NRFD_Unit].Channel = dibptr->channel_number;   /* save the channel number */
                dptr->units [NRFD_Unit].Address = phi->address;             /*   and bus address in the NRFD unit */

                sim_activate (&dptr->units [NRFD_Unit],         /* schedule the holdoff release event */
                              dptr->units [NRFD_Unit].wait);    /*   to deny NRFD and resume the transfer */
                }
            break;


        case 12:                                        /* unused state */
            break;


        case 13:                                        /* assert SETEND, INCADR */
            if (gic->dma_tag == R0_MODE_TAGGED)         /* if the last byte is tagged */
                gic->dma_status = RB_STATUS_TAGGED;     /*   then end in the tagged state */

            else if (gic->dma_tag == R0_MODE_FINAL)     /* otherwise if the last byte is final */
                gic->dma_status = RB_STATUS_FINAL;      /*   then end in the final count state */

            else                                        /* otherwise the last byte is a normal byte */
                gic->dma_status = RB_STATUS_RCOUNT;     /*   so end in the DMA count complete state */

            if (not gic->dma_frozen) {                  /* if address increment is enabled */
                gic->dma_address++;                     /*   then bump the address */

                if ((gic->dma_address & LA_MASK) == 0)  /* if the address has overflowed */
                    condition = Address_Overflow;       /*   then record an address overflow */
                }

            gic->dma_state = 5;                         /* proceed to the interrupt state */
            break;


        case 14:                                        /* assert INCADR, DMRDIO */
            if (not gic->dma_frozen) {                  /* if address increment is enabled */
                gic->dma_address++;                     /*   then bump the address */

                if ((gic->dma_address & LA_MASK) == 0)  /* if the address has overflowed */
                    condition = Address_Overflow;       /*   then record an address overflow */
                }

            gic->dma_state = 8;                         /* proceed to decrement the count */
            break;


        case 15:                                        /* assert DMWRRQ, DMRDIO, DMPHIGO1 */
            response = imb_cycle (IMB_Write,            /* write the buffer word to memory */
                                  gic->dma_address, gic->dma_buffer);

            if (not (response.signals & DDN))           /* if Data Done never asserted */
                condition = Memory_Timeout;             /*   then record a memory timeout */

            else if (response.signals & PER)            /* otherwise if Parity Error asserted */
                condition = Parity_Error;               /*   then record a parity error */

            if (gic->dma_count == 0                     /* if the byte count is exhausted */
              || gic->dma_tag != R0_MODE_DATA)          /*   or a termination condition is present */
                gic->dma_state = 13;                    /*     then proceed to tag the result */
            else                                        /*   otherwise */
                gic->dma_state = 14;                    /*     proceed to update the address */
            break;


        case 16:                                        /* assert DMPHIGO2, ELOUT */
            word = UPPER_BYTE (gic->dma_buffer);        /* get the right-hand byte from the buffer */

            fifo_load (gic_id, Outbound, word);         /* load the byte into the outbound FIFO */
            transfer = TRUE;                            /*   and set the FIFO changed flag */

            gic->dma_state = 24;                        /* proceed to decrement the count */
            break;


        case 17:                                        /* assert DMRDRQ, ELOUT */
            response = imb_cycle (IMB_Read,             /* read the next word from memory */
                                  gic->dma_address, 0);

            if (not (response.signals & DDN))           /* if Data Done never asserted */
                condition = Memory_Timeout;             /*   then record a memory timeout */

            else if (response.signals & PER)            /* otherwise if Parity Error asserted */
                condition = Parity_Error;               /*   then record a parity error */

            gic->dma_buffer = response.data;            /* save the word in the data buffer */

            if (gic->dma_count == 0)                    /* if the byte count is exhausted */
                gic->dma_state = 1;                     /*   then load the final byte into the FIFO */
            else                                        /* otherwise */
                gic->dma_state = 16;                    /*   load the next byte into the FIFO */
            break;


        case 18:                                        /* assert DMRDRQ, SETEND */
            if (gic->dma_tag == R0_MODE_TAGGED)         /* if the last byte is tagged */
                gic->dma_status = RB_STATUS_TAGGED;     /*   then end in the tagged state */

            else if (gic->dma_tag == R0_MODE_FINAL)     /* otherwise if the last byte is final */
                gic->dma_status = RB_STATUS_FINAL;      /*   then end in the final count state */

            else                                        /* otherwise the last byte is a normal byte */
                gic->dma_status = RB_STATUS_RCOUNT;     /*   so end in the DMA count complete state */

            gic->dma_state = 19;                        /* proceed to read the final word */
            break;


        case 19:                                        /* assert DMRDRQ, EROUT */
            response = imb_cycle (IMB_Read,             /* read the next word from memory */
                                  gic->dma_address, 0);

            if (not (response.signals & DDN))           /* if Data Done never asserted */
                condition = Memory_Timeout;             /*   then record a memory timeout */

            else if (response.signals & PER)            /* otherwise if Parity Error asserted */
                condition = Parity_Error;               /*   then record a parity error */

            gic->dma_buffer = REPLACE_LOWER (gic->dma_buffer, response.data);   /* replace the right-hand byte */
            gic->dma_state = 23;                                                /*   and prepare for the write */
            break;


        case 20:                                        /* assert DMRDIO, LLIN, DMPHIGO1 */
            word = fifo_unload (gic_id, Inbound);       /* unload the byte from the inbound FIFO */
            transfer = TRUE;                            /*   and set the FIFO changed flag */

            gic->dma_tag = R0_MODE (word);              /* save the byte tag */
            gic->dma_buffer = TO_WORD (word, 0);        /*   and store the left-hand byte */
            gic->dma_state = 22;                        /*     and proceed to check the byte count */
            break;


        case 21:                                        /* assert LRIN, DMWRRQ */
            response = imb_cycle (IMB_Write,            /* write the buffer word to memory */
                                  gic->dma_address, gic->dma_buffer);

            if (not (response.signals & DDN))           /* if Data Done never asserted */
                condition = Memory_Timeout;             /*   then record a memory timeout */

            else if (response.signals & PER)            /* otherwise if Parity Error asserted */
                condition = Parity_Error;               /*   then record a parity error */

            gic->dma_state = 5;                         /* proceed to the interrupt state */
            break;


        case 22:                                        /* assert DMRDIO */
            if (gic->dma_count == 0                     /* if the byte count is exhausted */
              || gic->dma_tag != R0_MODE_DATA)          /*   or a termination condition is present */
                gic->dma_state = 18;                    /*     then proceed to tag the result */
            else                                        /*   otherwise */
                gic->dma_state = 10;                    /*     proceed to decrement the count */
            break;


        case 23:                                        /* assert LRIN, EROUT */
            gic->dma_state = 21;                        /* proceed to update the final word */
            break;


        case 24:                                            /* assert DECCNT */
            if (gic->registers [Gic_B] & RB_RIGHT_BYTE) {   /* if the right byte indicator is set */
                gic->dma_count--;                           /*   then count the byte */
                gic->registers [Gic_B] ^= RB_RIGHT_BYTE;    /*     and flip to the left byte */
                }

            if (gic->registers [Gic_8] & R8_DMA_ENABLED)        /* if DMA has not been aborted */
                if (not (phi->registers [Phi_2] & R2_AVAIL))    /*   then if the outbound FIFO is full */
                    cycling = FALSE;                            /*     then block until data departs */
                else                                            /*    otherwise */
                    gic->dma_state = 25;                        /*      proceed to update the address */

            else                                        /* otherwise DMA has been aborted */
                gic->dma_state = 5;                     /*   so proceed to the interrupt state */
            break;


        case 25:                                        /* assert EROUT, INCADR */
            if (not gic->dma_frozen) {                  /* if address increment is enabled */
                gic->dma_address++;                     /*   then bump the address */

                if ((gic->dma_address & LA_MASK) == 0)  /* if the address has overflowed */
                    condition = Address_Overflow;       /*   then record an address overflow */
                }

            gic->dma_state = 29;                        /* proceed to check the byte count */
            break;


        case 26:                                                /* assert DMRDRQ, DECCNT */
            if (not (gic->registers [Gic_B] & RB_RIGHT_BYTE)) { /* if the left byte indicator is set */
                gic->dma_count--;                               /*   then count the byte */
                gic->registers [Gic_B] ^= RB_RIGHT_BYTE;        /*     and flip to the right byte */
                }

            if (gic->registers [Gic_8] & R8_DMA_ENABLED)        /* if DMA has not been aborted */
                if (not (phi->registers [Phi_2] & R2_AVAIL))    /*   then if the outbound FIFO is full */
                    cycling = FALSE;                            /*     then block until data departs */
                else                                            /*    otherwise */
                    gic->dma_state = 27;                        /*      prepare for the next memory read */

            else                                        /* otherwise DMA has been aborted */
                gic->dma_state = 5;                     /*   so proceed to the interrupt state */
            break;


        case 27:                                        /* assert DMRDRQ */
            gic->dma_state = 17;                        /* proceed to read the word from memory */
            break;


        case 28:                                        /* assert DMRDRQ */
            response = imb_cycle (IMB_Read,             /* read the next word from memory */
                                  gic->dma_address, 0);

            if (not (response.signals & DDN))           /* if Data Done never asserted */
                condition = Memory_Timeout;             /*   then record a memory timeout */

            else if (response.signals & PER)            /* otherwise if Parity Error asserted */
                condition = Parity_Error;               /*   then record a parity error */

            gic->dma_buffer = response.data;            /* save the right-hand byte */
            gic->dma_state = 24;                        /*   and proceed to count the byte */
            break;


        case 29:                                        /* assert EROUT, DMRDRQ, DMPHIGO2 */
            if (gic->dma_count == 0)                    /* if the byte count is exhausted */
                gic->dma_state = 7;                     /*   then load the final byte into the FIFO */
            else                                        /* otherwise */
                gic->dma_state = 30;                    /*   load the next byte into the FIFO */
            break;


        case 30:                                        /* assert EROUT, DMRDRQ, DMPHIGO2 */
            word = LOWER_BYTE (gic->dma_buffer);        /* get the right-hand byte from the buffer */

            fifo_load (gic_id, Outbound, word);         /* load the byte into the outbound FIFO */
            transfer = TRUE;                            /*   and set the FIFO changed flag */

            gic->dma_state = 26;                        /* proceed to count the byte */
            break;


        case 31:                                        /* unused state */
            break;
        }                                               /* all defined cases are handled */
    }
while (cycling);                                        /* continue cycling until blocked */

if (condition != End_of_Cycle) {                        /* if an error condition occurred */
    gic->registers [Gic_8] &= ~R8_DMA_ENABLED;          /*   then disable DMA */
    gic->dma_status = RB_STATUS_ERROR;                  /*     and set DMA error status */

    if (condition == Parity_Error)                      /* if a parity error was reported */
        gic->registers [Gic_B] |= RB_PARITY;            /*   then set parity error status */

    else if (condition == Address_Overflow)             /* otherwise if an address overflow was reported */
        gic->registers [Gic_B] |= RB_OVERFLOW;          /*   then set overflow status */

    if (condition == Memory_Timeout)                    /* if a memory timeout was reported */
        gic->registers [Gic_B] |= RB_TIMEOUT;           /*   then set timeout status */
    }

tpprintf (dptr, TRACE_STATE, "DMA exiting in state %u count %u\n",
          gic->dma_state, gic->dma_count);

return transfer;                                        /* return TRUE if a FIFO transfer occurred */
}


/* Transfer data to the bus.

   This routine is called to transfer data from the outbound FIFO to the bus.
   If DMA is active, one or more outbound DMA cycles will be executed to refill
   the FIFO.  Transfers continue until the FIFO is empty, the DMA sequencer
   blocks without loading data into the FIFO, or the listener asserts NRFD to
   hold off the transfer.  The routine is typically called multiple times until
   DMA completes and the FIFO empties.  It must be called any time the FIFO
   occupancy changes or the NRFD signal denies on the bus.

   On entry, "gic_id" is the instance ID of the GIC.  The routine begins by
   unloading data from the outbound FIFO and sourcing the data to the bus.  This
   continues until the FIFO is empty.  Then, if DMA is active, DMA cycles are
   executed to refill the FIFO.  This pair of operations continues until the
   FIFO is empty and DMA does not refill it.  Before returning, the interrupt
   state of the FIFO is checked, and a channel request is asserted if needed.

   As each byte is unloaded from the FIFO, the tag is checked to determine the
   course of action.  For command bytes, the MSB is set to odd parity before
   transmission.


   Implementation notes:

    1. The odd_parity array produces a ninth parity bit.  For HP-IB commands,
       parity is in the eighth bit, so we shift the parity bit right one place
       before merging.

    2. In hardware, when the PHI is configured as a device, it must be addressed
       to talk to send bytes to the bus; if it is not, the byte remains in the
       outbound FIFO until the PHI is addressed.  When the PHI is the
       controller, it sends bytes regardless of whether or not it is the talker.
       However, if it is not addressed to talk or is in serial poll mode, the
       data byte will be erroneously interpreted as a byte transfer enable
       command.  The simulator follows this behavior.

    3. In hardware when configured as a device and addressed to talk, the PHI
       will not send data to the bus if the Outbound Data Freeze bit in Register
       1 or the Device Clear Received bit in Register 2 bit is set.  This
       behavior is not implemented in the simulator.

    4. If the word at the head of the FIFO is an uncounted transfer enable but
       the PHI is not addressed to listen, then the word is not unloaded but
       remains in the FIFO.  This behavior is tested by the GIC diagnostic and
       is implemented in the "fifo_unload" routine, which returns the data word
       but does not alter the FIFO count.  Consequently, we check for the
       condition here and exit the data transfer loop if it is present.
*/

static void transfer_data (uint32 gic_id)
{
DEVICE    *const dptr    = gics [gic_id].dptr;      /* the per-instance device pointer */
GIC_STATE *const gic     = gics [gic_id].sptr;      /* the per-instance GIC state pointer */
PHI_STATE *const phi     = &gic->phi;               /* the per-instance PHI state pointer */
DIB       *const dibptr  = (DIB *) dptr->ctxt;      /* the pointer to the device context */
const uint32     channel = dibptr->channel_number;  /* the IMB channel number */
IMB_DATA         data;
OUTBOUND_TAG     tag;
BUS_CABLE        bus;
t_bool           partial_transfer;

do {                                                    /* do while data is transferred */
    while (not (phi->registers [Phi_2] & R2_EMPTY)      /* while data remains in the outbound FIFO */
      && not (phi->bus & Bus_NRFD))                     /*   and NRFD is denied */
        if (phi->registers [Phi_1] & R1_CNTLR) {        /*     if the PHI is the controller */
            data = fifo_unload (gic_id, Outbound);      /*       then unload a FIFO byte */
            tag = tag_word (phi, data);                 /*         and tag it */

            if (tag == Tag_Command)                             /* if the word is a command byte */
                bus = Bus_ATN | Bus_DAV                         /*   then assert ATN and DAV */
                        | odd_parity [R0_COMMAND (data)] >> 1   /*   and merge the odd parity bit */
                        | R0_COMMAND (data);                    /*     with the command */

            else if (tag == Tag_Data)                   /* otherwise if the word is a data byte */
                bus = Bus_DAV | BUS_DATA (data);        /*   then assert DAV with the data */

            else if (tag == Tag_EOI_Data)                   /* otherwise if the word is the last data byte */
                bus = Bus_EOI | Bus_DAV | BUS_DATA (data);  /*   then assert EOI and DAV with the data */

            else if (phi->registers [Phi_1] & R1_LISTENER) {        /* otherwise if the PHI is listening */
                if (tag != Tag_Uncounted && R0_COUNT (data) == 0)   /*   then if this is a zero-count transfer */
                    phi->byte_count = 256;                          /*     then receive 256 bytes */
                else                                                /*   otherwise */
                    phi->byte_count = R0_COUNT (data);              /*     enable reception of the specified count */

                phi->tag_lf = (tag == Tag_LF_Counted);  /* set the end-on-LF flag */
                bus = phi->bus & ~BUS_PPOLL;            /*   and clear the bus for reception */
                }

            else if ((data & R0_MODE_MASK) == R0_MODE_UNCOUNTED) {  /* otherwise if the word was not unloaded */
                partial_transfer = FALSE;                           /*   then kill any potential transfer */
                break;                                              /*     and quit leaving the word in the FIFO */
                }

            else                                        /* otherwise the PHI is not talking or listening */
                bus = phi->bus & ~BUS_PPOLL;            /*   so ignore the transfer enable */

            hpib_source (channel, phi->address, bus);   /* source the byte to the bus */
            }

        else if (phi->registers [Phi_1] & R1_TALKER     /* otherwise if the PHI device is talking */
          && not (phi->bus & Bus_ATN)) {                /*   and ATN has been denied */
            data = fifo_unload (gic_id, Outbound);      /*     then unload a FIFO byte */
            tag = tag_word (phi, data);                 /*       and tag it */

            bus = Bus_DAV | BUS_DATA (data);            /* assert DAV with the data byte */

            if (tag == Tag_EOI_Data)                    /* if the EOI tag is requested */
                bus |= Bus_EOI;                         /*   then assert EOI with the last byte */

            hpib_source (channel, phi->address, bus);   /* source the byte to the bus */
            }

        else                                            /* otherwise no data is transferred */
            break;                                      /*   until the PHI is addressed to talk */

    if (gic->dma_busy || gic->dma_clock > 0)            /* if DMA is active or is single-stepping */
        partial_transfer = dma_cycle (gic_id);          /*   then transfer between memory and the FIFO */
    else                                                /* otherwise */
        partial_transfer = FALSE;                       /*   the transfer stops */
    }
while (partial_transfer);                               /* continue as long as data can be sent */

if (phi_interrupts (gic, phi))                          /* if a PHI interrupt is present */
    imb_assert_CSRQ (channel);                          /*   then request channel service */

return;                                                 /* return with the outbound transfer complete or blocked */
}


/* Start or stop the GIC timer.

   This routine enables or disables the timeout counter.  On entry, "dptr"
   points to the GIC device, and "action" is either SET to enable the timer or
   CLEAR to disable and reset the timer.  The timeout period is approximately
   one second.

   The timer is automatically enabled when a DMA transfer starts and is disabled
   when the transfer completes.  If the timeout period expires, any in-progress
   DMA transfer is aborted, and channel service is requested.  This ensures that
   a non-responding device does not prevent bus use with other operational
   devices.

   The timer is also enabled if the Disable CSRQ for Parallel Polls bit of
   Register F is set.  This is useful if a programmed operation, e.g., waiting
   for the inbound FIFO to receive data, may not complete due to a missing or
   unresponsive device.
*/

static void timer_enable (uint32 gic_id, FLIP_FLOP action)
{
DEVICE *const dptr = gics [gic_id].dptr;        /* the per-instance device pointer */

tpprintf (dptr, TRACE_SERV, "Timeout clock %s\n", timeout_names [action]);

if (action == CLEAR)                                    /* if the timer is disabled */
    sim_cancel (&dptr->units [Timeout_Unit]);           /*   then cancel the timeout event */

else {                                                  /* otherwise */
    dptr->units [Timeout_Unit].Instance = gic_id;       /*   save the instance ID for the service routine */

    sim_activate (&dptr->units [Timeout_Unit],          /* schedule the timeout event */
                  dptr->units [Timeout_Unit].wait);     /*   with the specified delay */
    }

return;
}


/* Check for PHI interrupt conditions.

   This routine is called to check the interrupt state of the PHI.  It returns
   TRUE if a PHI interrupt is present and FALSE if one is not.

   For the PHI to assert its interrupt line, an interrupt condition must have
   set a bit in Register 2, the corresponding bit in Register 3, the interrupt
   mask register, must also be set, and the Interrupt Enable bit in Register 3
   must be set.  If these conditions are met, the PHI asserts its interrupt
   request line, which is reflected in bit 0 of Register B.

   PHI interrupts may be independent of DMA or asserted as part of DMA
   completion.  If DMA has finished its transfer operation and is waiting for
   the PHI to send the remaining bytes in its outbound FIFO, the PHI interrupt
   is reported as a DMA interrupt.  Either way, the routine returns TRUE, and
   the caller will request channel service.
*/

static t_bool phi_interrupts (GIC_STATE *const gic, PHI_STATE *const phi)
{
if (phi->registers [Phi_3] & R3_ENABLE                  /* if interrupts are enabled */
  && phi->registers [Phi_2]                             /*   and an interrupt condition exists */
   & phi->registers [Phi_3]) {                          /*   after applying the mask */
    gic->registers [Gic_B] |= RB_IRQ;                   /*     then assert the PHI interrupt */

    if (gic->dma_busy) {                                /* if DMA is active */
        gic->channel_requests &= ~PHI_Interrupt;        /*   then PHI service is inhibited */

        if (not gic->dma_run) {                         /* if DMA has completed */
            gic->channel_requests |= DMA_Interrupt;     /*   then assert a DMA interrupt */
            return TRUE;                                /*     and request channel service */
            }
        }

    else {                                              /* otherwise */
        gic->channel_requests |= PHI_Interrupt;         /*   request channel service */
        return TRUE;
        }
    }

else {                                                  /* otherwise */
    gic->registers [Gic_B] &= ~RB_IRQ;                  /*   deny the PHI interrupt */
    gic->channel_requests &= ~PHI_Interrupt;            /*     and cancel any service request */
    }

return FALSE;
}


/* Request service for a status change.

   This routine is called if a bit in the New Status register is set.  It
   determines if the GIC can request service from the channel program processor
   for a change in the program status.

   A status change channel request can be issued only when the GIC is not using
   the bus, i.e., when the request would not disturb an active bus transaction.
*/

static void request_service (GIC_STATE *const gic, PHI_STATE *const phi)
{
if (not gic->dma_busy                                   /* if DMA is inactive */
  && not (gic->registers [Gic_B] & RB_NO_POLL)          /*   and poll requests are not disabled */
  && (not (phi->registers [Phi_1] & R1_CNTLR)           /*   and the PHI is not the controller */
  || phi->poll_active))                                 /*     or a parallel poll is active */
    gic->channel_requests |= Status_Interrupt;          /*       then assert a status request */
else                                                    /* otherwise */
    gic->channel_requests &= ~Status_Interrupt;         /*   deny the status request */

return;
}


/* Load a word into the FIFO.

   This routine loads a word into the next available location in the FIFO, and
   increments the FIFO occupancy count.  On entry, "gic_id" contains the
   instance ID, "mode" is either "Inbound" or "Outbound" to indicate the FIFO to
   load, and "data" is the word containing the data plus tag bits to load.

   If the outbound FIFO is full on entry, a Handshake Abort occurs, and the load
   is ignored.  If the inbound FIFO is full, the load is silently ignored.

   Assuming space is available, loading a word into the inbound FIFO sets the
   Data Available status bit in Register 2.  If the FIFO is now full, NRFD is
   asserted on the bus to hold off the talker until space becomes available.

   Loading a word into the outbound FIFO clears the FIFO Empty status bit in
   Register 2.  If the FIFO is now full, the Space Available status bit is also
   cleared.


   Implementation notes:

    1. The FIFO is implemented as circular queue to take advantage of REG_CIRC
       EXAMINE semantics.  REG->qptr is the index of the first word currently in
       the FIFO.  By specifying REG_CIRC, examining FIFO[0-n] will always
       display the words in load order, regardless of the actual array index of
       the start of the list.  The number of words currently present in the FIFO
       is kept in phi->fifo_count (0 = empty, 1-8 = number of words occupied).

       If fifo_count < FIFO_SIZE, (REG->qptr + fifo_count) mod FIFO_SIZE is the
       index of the new word location.  Loading stores the word there and then
       increments fifo_count.

    2. To permit this routine to access the qptr field in the REG structure, a
       pointer to the structure is stored in the phi->fifo_reg state field
       during device reset.
*/

static void fifo_load (uint32 gic_id, FIFO_MODE mode, IMB_DATA data)
{
DEVICE    *const dptr   = gics [gic_id].dptr;   /* the per-instance device pointer */
GIC_STATE *const gic    = gics [gic_id].sptr;   /* the per-instance GIC state pointer */
PHI_STATE *const phi    = &gic->phi;            /* the per-instance PHI state pointer */
DIB       *const dibptr = (DIB *) dptr->ctxt;   /* the device context pointer */
uint32           index;

if (phi->fifo_count [mode] == FIFO_SIZE) {              /* if the FIFO is full */
    if (mode == Outbound)                               /*   then if the outbound FIFO is full */
        phi->registers [Phi_2] |= R2_HSABORT;           /*     then set the Handshake Abort bit */

    tpprintf (dptr, TRACE_FIFO, "Attempted load into full %s FIFO data %06o\n",
              mode_names [mode], data);

    return;                                             /* return with the load ignored */
    }

index = (gic->fifo_reg [mode]->qptr + phi->fifo_count [mode])   /* calculate the index */
          % FIFO_SIZE;                                          /*   of the next available location */

phi->fifo [mode] [index] = data;                        /* store the word in the FIFO */
phi->fifo_count [mode]++;                               /* increment the count of words stored */

if (TRACINGP (dptr, TRACE_FIFO))
    trace_fifo (gic_id, mode, Load, data);

if (mode == Inbound) {                                  /* if the inbound FIFO is being loaded */
    phi->registers [Phi_2] |= R2_DATA;                  /*   then set the data available bit */

    if (phi->fifo_count [Inbound] == FIFO_SIZE)             /* if the FIFO is now full */
        hpib_source (dibptr->channel_number, phi->address,  /*   then assert NRFD to hold off future loads */
                     phi->bus | Bus_NRFD);
    }

else {                                                  /* otherwise the outbound FIFO is being loaded */
    phi->registers [Phi_2] &= ~R2_EMPTY;                /*   so clear the empty bit */

    if (phi->fifo_count [Outbound] == FIFO_SIZE)        /* if the FIFO is full */
        phi->registers [Phi_2] &= ~R2_AVAIL;            /*   then clear the space available bit */
    }

return;
}


/* Unload a word from the FIFO.

   This routine unloads a word from the first location in the FIFO, and
   decrements the FIFO occupancy count.  On entry, "gic_id" contains the
   instance ID, and "mode" is either "Inbound" or "Outbound" to indicate the
   FIFO to unload.

   If the inbound FIFO is empty on entry, a Handshake Abort occurs.  If the
   outbound FIFO is empty, the unload is silently ignored.  In either case,
   arbitrary data is returned.

   Assuming data is available, unloading the last word from the inbound FIFO
   clears the Data Available status bit in Register 2.  If the FIFO had been
   full, the NRFD unit is scheduled to deny NRFD on the bus; this will allow the
   talker to resume sending data.

   Unloading the last word from the outbound FIFO sets the FIFO Empty status bit
   in Register 2.  If the FIFO is not full, the Space Available status bit is
   also set.


   Implementation notes:

    1. If phi->fifo_count > 0, then REG->qptr is the index of the word to
       remove.  Removal gets the word and then increments qptr (mod FIFO_SIZE)
       and decrements fifo_count.

    2. To permit this routine to access the qptr field in the REG structure, a
       pointer to the structure is stored in the phi->fifo_reg state field
       during device reset.

    3. If the word at the head of the FIFO is an uncounted transfer enable but
       the PHI is not addressed to listen, then the word is not unloaded but
       remains in the FIFO.  This behavior is tested by the GIC diagnostic,
       which writes the hex value C07F to Register 0 eight times and expects the
       Outbound FIFO Has Space Available bit in Register 2 to be clear, so we
       implement it here.

    4. While the fifo_load routine can assert NRFD directly when the inbound
       FIFO is full, we cannot deny NRFD directly here.  Instead, the denial
       event must be scheduled to be serviced after the unload routine exits.
       If the denial were done directly, then during GIC-to-GIC transfers in the
       GIC diagnostic, dma_cycle state 20 would do a FIFO unload of first byte,
       which denies NRFD by calling hpib_control.  That routine then calls
       gic_hpib_respond, which sees the denial and calls transfer_data to resume
       the transfer.  But that routine calls dma_cycle, which reenters state 20
       recursively and does another FIFO unload.  This time, NRFD is already
       denied, so the unload skips the hpib_control call, and upon returning,
       dma_cycle continues on to states 22, 10, 11, which unloads another FIFO
       byte (the third) before continuing into state 15, which writes the last
       two bytes as the first memory word.  The first byte is now lost.
*/

static IMB_DATA fifo_unload (uint32 gic_id, FIFO_MODE mode)
{
DEVICE    *const dptr   = gics [gic_id].dptr;   /* the per-instance device pointer */
GIC_STATE *const gic    = gics [gic_id].sptr;   /* the per-instance GIC state pointer */
PHI_STATE *const phi    = &gic->phi;            /* the per-instance PHI state pointer */
DIB       *const dibptr = (DIB *) dptr->ctxt;   /* the pointer to the device context */
IMB_DATA         data;

if (phi->fifo_count [mode] == 0) {                      /* if the FIFO is empty */
    if (mode == Inbound)                                /*   then if the inbound FIFO is empty */
        phi->registers [Phi_2] |= R2_HSABORT;           /*     then set the Handshake Abort bit */

    tpprintf (dptr, TRACE_FIFO, "Attempted unload from empty %s FIFO\n",
              mode_names [mode]);

    return 0;                                           /* return with arbitrary data */
    }

data = phi->fifo [mode] [gic->fifo_reg [mode]->qptr];   /* get the word from the FIFO */

if (mode == Outbound                                    /* if the outbound FIFO is unloading */
  && (data & R0_MODE_MASK) == R0_MODE_UNCOUNTED         /*   and it's an uncounted transfer enable */
  && not (phi->registers [Phi_1] & R1_LISTENER)         /*   and the PHI is not listening */
  && phi->registers [Phi_1] & R1_CNTLR)                 /*   but it is the controller */
    return data;                                        /*     then leave the enable in the FIFO */

gic->fifo_reg [mode]->qptr = (gic->fifo_reg [mode]->qptr + 1)   /* update the FIFO queue pointer */
                               % FIFO_SIZE;
phi->fifo_count [mode]--;                               /* decrement the count of words stored */

if (TRACINGP (dptr, TRACE_FIFO))
    trace_fifo (gic_id, mode, Unload, data);

if (mode == Inbound) {                                  /* if the inbound FIFO is being unloaded */
    if (phi->fifo_count [Inbound] == 0)                 /*   then if the FIFO is now empty */
        phi->registers [Phi_2] &= ~R2_DATA;             /*     the clear the data available bit */

    else if (phi->fifo_count [Inbound] + 1 == FIFO_SIZE) {          /* if the FIFO was previously full */
        dptr->units [NRFD_Unit].Channel = dibptr->channel_number;   /*   then save the channel number */
        dptr->units [NRFD_Unit].Address = phi->address;             /*     and bus address in the NRFD unit */

        sim_activate (&dptr->units [NRFD_Unit],             /* schedule the holdoff release event */
                      dptr->units [NRFD_Unit].wait);        /*   to deny NRFD and resume the transfer */
        }
    }

else {                                                  /* otherwise the outbound FIFO is being unloaded */
    if (phi->fifo_count [Outbound] == 0)                /*   so if the FIFO is now empty */
        phi->registers [Phi_2] |= R2_EMPTY;             /*     then set the empty bit */

    if (phi->fifo_count [Outbound] < FIFO_SIZE)         /* if the FIFO is not full */
        phi->registers [Phi_2] |= R2_AVAIL;             /*   then set the space available bit */
    }

return data;                                            /* return the unloaded data word */
}



/**********************************
 *                                *
 * Interface local trace routines *
 *                                *
 **********************************/


/* Trace the HP-IB signals.

   This routine is called to print a trace of the bus state.  On entry, "gic_id"
   is the instance ID of the GIC, and "bus" is the set of eight control and
   eight data lines representing the HP-IB.  Entry assumes that the TRACE_XFER
   condition has already been qualified.  The trace format is patterned after a
   logic analyzer listing, with the separate states of the eight control lines,
   the data byte from the eight DIO lines, and an interpretive mnemonic listed
   for each call.  For the first entry following a power-on clear, the routine
   prints a header line to aid interpretation.

   The bus condition is separated into control and data traces, depending on the
   state of the DAV (Data Available) line.  When DAV is denied, a control change
   is present.  For this case, the data lines (DIO8-DIO1) are not relevant;
   however, the address of the device making the change is passed on the data
   lines to augment the trace information.  If the control state is the same as
   that from the previous call, the trace is skipped.  This reduces listing
   clutter by eliminating sequential duplicate control traces.

   DAV assertion accompanies all bus transactions where the data lines
   (DIO8-DIO1) are valid, i.e., all commands and data.  Concurrent ATN and EOI
   assertion indicates a parallel poll, and the value on the DIO lines
   represents the poll response(s).  ATN asserted with EOI denied indicates that
   a command is present.  The data byte is decoded first to determine the
   command group (primary, secondary, talk, or listen).  Then, per-group
   decoding is applied to characterize the command.

   If ATN is denied, then a data byte is present on the bus.  This is reported
   as such, unless the NDAC (Not Data Accepted) signal is also present.  The
   latter indicates that no acceptors are present (i.e., there are no listeners
   on the bus), so this notation is appended.


   Implementation notes:

    1. The order of the simulation bit assignments of the SRQ, IFC, REN, EOI,
       and ATN signals are for the convenience of the HP 1000 HP-IB Disc
       Interface card, which uses this order in its status register and so
       provides a simple mapping.  To provide for easier user interpretation
       when the signals are traced, the upper eight bits are rotated left by
       three places, producing this order when printed LSB first:

         REN | IFC | SRQ | ATN | EOI | DAV | NRFD | NDAC

    2. In hardware, DAV is not asserted with a parallel poll (ATN and EOI).  In
       simulation, it is asserted to differentiate between the signal change
       that initiates the poll and the resulting poll response.

    3. A temporary format buffer is used to hold those mnemonics that have
       variable content.  It need be only large enough to hold the longest
       variable string, which is "Parallel poll enable response n sense n" (40
       bytes).
*/

static void trace_hpib (uint32 gic_id, BUS_CABLE signals)
{
static uint32    last_gic_id  = 0;                      /* prior instance ID */
static BUS_CABLE last_signals = BUS_NONE;               /* prior bus state */
DEVICE    *const dptr         = gics [gic_id].dptr;     /* the per-instance device pointer */
GIC_STATE *const gic          = gics [gic_id].sptr;     /* the per-instance GIC state pointer */
PHI_STATE *const phi          = &gic->phi;              /* the per-instance PHI state pointer */
const uint32     address      = BUS_ADDRESS (signals);  /* the bus address present on the DIO lines */
uint32           control;
char             format [64];
char             *mnemonic = format;

if (not gic->header_printed) {                          /* if the header for this instance has not been printed */
    hp_trace (dptr, TRACE_XFER, "REN | IFC | SRQ | ATN | EOI | DAV | NRFD | NDAC | DIO | HP-IB Mnemonic\n");
    gic->header_printed = TRUE;                         /* mark it as already printed */
    }

if (not (signals & Bus_DAV)) {                                      /* if this is a control change */
    if (signals == last_signals && gic_id == last_gic_id)           /*   then if the bus state has not changed */
        return;                                                     /*     then skip the redundant trace */
    else                                                            /*   otherwise */
        sprintf (format, "Signal change by device %u", address);    /*     note the signal change */
    }

else if (signals & Bus_ATN)                             /* otherwise if this is a command */
    if (signals & Bus_EOI)                              /*   then if it's a parallel poll response */
       mnemonic = "Parallel poll";                      /*     then note it */

    else switch BUS_GROUP (signals) {                   /* otherwise dispatch the command group */

        case BUS_PCG:                                   /* Primary Command Group */
            switch (BUS_COMMAND (signals)) {            /* dispatch the primary command */

                case BUS_DCL:                           /* Universal Device Clear */
                    mnemonic = "Universal device clear";
                    break;

                case BUS_SDC:                           /* Selected Device Clear */
                    mnemonic = "Selected device clear";
                    break;

                case BUS_GTL:                           /* Go To Local */
                    mnemonic = "Go to local";
                    break;

                case BUS_TCT:                           /* Take Control */
                    mnemonic = "Take control";
                    break;

                case BUS_PPC:                           /* Parallel Poll Configure */
                    mnemonic = "Parallel poll configure";
                    break;

                case BUS_PPU:                           /* Parallel Poll Unconfigure */
                    mnemonic = "Parallel poll unconfigure";
                    break;

                case BUS_SPE:                           /* Serial Poll Enable */
                    mnemonic = "Serial poll enable";
                    break;

                case BUS_SPD:                           /* Serial Poll Disable */
                    mnemonic = "Serial poll disable";
                    break;

                default:                                /* unknown primary */
                    mnemonic = "Unknown primary";
                }
            break;


        case BUS_LAG:                                   /* Listen Address Group */
            if (address == BUS_UNADDRESS)
                mnemonic = "Unlisten";
            else
                sprintf (format, "Listen %u", address);
            break;


        case BUS_TAG:                                   /* Talk Address Group */
            if (address == BUS_UNADDRESS)
                mnemonic = "Untalk";
            else
                sprintf (format, "Talk %u", address);
            break;


        case BUS_SCG:                                   /* Secondary Command Group */
            if (phi->poll_configure)                    /* if poll configuration is enabled */
                if ((signals & BUS_PPD) == BUS_PPD)     /*   then if the secondary is a poll disable */
                    sprintf (format, "Parallel poll disable");
                else                                    /*   otherwise it must be a poll enable */
                    sprintf (format, "Parallel poll enable response %u sense %u",
                             BUS_PPE_RESPONSE (address) + 1,
                             (BUS_PPE_SENSE & address ? 1 : 0));
            else                                        /* otherwise the secondary is not interpreted */
                sprintf (format, "Secondary %02XH", address);
            break;
        }

else if (signals & Bus_NDAC)                            /* otherwise if the data won't be accepted */
    mnemonic = "Data (no bus acceptors)";               /*   then note it */

else                                                    /* otherwise */
    mnemonic = "Data";                                  /*   it's a normal data byte */

control = LOWER_BYTE (BUS_CONTROL (signals) << 3        /* rotate the bus control signals */
                        | BUS_CONTROL (signals) >> 5);  /*   three bits to the left */

if (signals & Bus_DAV)                                  /* if tracing a data transaction */
    hp_trace (dptr, TRACE_XFER, "%s | %02XH | %s\n",    /*   then include the data byte value */
              fmt_bitset (control, bus_format),         /*     in the trace */
              BUS_DATA (signals),                       /*       with the control signals */
              mnemonic);                                /*         and the mnemonic */
else                                                    /* otherwise */
    hp_trace (dptr, TRACE_XFER, "%s | --- | %s\n",      /*   omit the data byte */
              fmt_bitset (control, bus_format),         /*     which is irrelevant */
              mnemonic);                                /*       to a control transaction */

last_gic_id = gic_id;                                   /* save the instance ID and bus state */
last_signals = signals;                                 /*   for comparison at the next entry */

return;
}


/* Trace a register access.

   This routine is called to trace the value of a register during a read or
   write operation.  On entry, "gic_id" is the instance ID of the GIC, "mode" is
   either Read or Write, depending on the mode of access, "Register" is the
   enumerator designating the register to trace, and "data" is the register data
   value.  Entry assumes that the TRACE_CSRW condition has already been qualified.

   All of the registers except Register 0 use formatting driven by the data in
   the "formatter" array.  This array is used to assemble the trace from the
   various fields within the register values, as follows:

     Reg  Label           Control is                Status is
     ---  --------------  ------------------------  ---------------------------------
      1   PHI status      <bits>                    <bits>
      2   IRQ conditions  <bits>                    <bits>
      3   IRQ mask        <bits>                    <bits>
      4   Poll mask       <bits>                    <bits>
      5   Poll sense      <bits>                    <bits>
      6   PHI control     <bits>                    <bits>
      7   Bus address     <bits> | bus address <n>  <bits> | bus address <n>
      8   DMA bank        <bits> | bank <n>         <bits> | state <n> | bank <n>
      9   DMA address     address <n>               address <n>
      A   DMA byte count  byte count <n>            byte count <n>
      B   DMA status      <bits> | device <n>       <bits> | code <n> | device <n>
      C   Interrupt       <bits> | device <n>       <bits>
      D   Interrupt info  ignored                   <bits> | channel <n> | device <n>
      E   Configuration   DMA abort                 <bits> | id <n>
      F   Service info    <bits> | device <n>       <bits> | channel <n> | device <n>

   Register 0 is handled separately, due to the variety of output formats and
   because interpretation is value-dependent.  The various Register 0 traces are
   summarized in the examples below:

     Mode   Trace
     -----  ------------------------------------
     Read   Talk secondary 12H
     Read   Listen secondary 05H
     Read   Data 020 received from bus
     Read   Data Final | 126 received from bus
     Read   Data Tagged | 040 received from bus

     Write  Data 104 sent to bus
     Write  Data EOI | 001 sent to bus
     Write  Data ATN | 136 sent to bus
     Write  Reception enabled
     Write  Reception enabled for count 12
     Write  Reception enabled for LF | count 256

   Read operations may be determined unambiguously from the mode bits in the
   data word.  The mode bits for write operations have overlapping meanings,
   which the "tag_word" routine differentiates.


   Implementation notes:

    1. Tracing of the parallel poll response case for Register 0 is handled in
       the "read_register" routine rather than here, for the reason outlined in
       the implementation note there.
*/

static void trace_register (uint32 gic_id, FORMAT_MODE mode, REGISTER Register, IMB_DATA data)
{
DEVICE    *const dptr = gics [gic_id].dptr;             /* the per-instance device pointer */
PHI_STATE *const phi  = &gics [gic_id].sptr->phi;       /* the per-instance PHI state pointer */
OUTBOUND_TAG     tag;
uint32           value;

if (Register == Reg_0) {                                /* if tracing Register 0 */
    hp_trace (dptr, TRACE_CSRW, "Register 0 (FIFO) ");  /*   then print the label */

    if (mode == Read)                                       /* if this is a read trace */
        if (R0_MODE (data) == R0_MODE_SECONDARY)            /*   then if the byte is a secondary */
            fprintf (sim_deb, "%s secondary %02XH\n",       /*     then report it */
                     (data & R0_TALK ? "Talk" : "Listen"),  /*       along with the Talk/Listen mode */
                     R0_SECONDARY (data));                  /*         and the secondary address */

        else                                                        /*   otherwise */
            fprintf (sim_deb, "Data %s%03o received from bus\n",    /*     report a normal data read */
                     register_0_tags [R0_MODE (data)],              /*       along with the optional tag */
                     R0_DATA (data));                               /*         and data byte */

    else {                                              /* otherwise this is a write trace */
        tag = tag_word (phi, data);                     /*   so get the data tag */
        value = R0_DATA (data);                         /*     and value */

        if ((tag == Tag_Counted || tag == Tag_LF_Counted)   /* if this is a counted transfer enable */
          && value == 0)                                    /*   and the count is zero */
            value = 256;                                    /*     then use a count of 256 */

        else if (tag == Tag_Command)                    /* otherwise if this is a command byte */
            value = R0_COMMAND (data);                  /*   then mask off the parity bit */

        fprintf (sim_deb, register_0_fmts [tag], value);    /* report the register write */
        }
    }

else {                                                      /* otherwise the rest of the registers */
    hp_trace (dptr, TRACE_CSRW, "Register %0X (%s) %s is ", /*   can be formatted */
              Register, formatter [Register].label,         /*     with the formatter label */
              (mode == Read ? "status" : "control"));       /*       and a read/write indication */

    if (mode == Write                                   /* if writing */
      && formatter [Register].write_mask == 0) {        /*   is not supported */
        fputs ("ignored\n", sim_deb);                   /*     then ignore the register value */
        return;                                         /*       and formatting is complete */
        }

    if (formatter [Register].bit_format != NULL) {      /* if a bit format is defined */
        fputs (fmt_bitset (data,                        /*   then use it to format the data */
                           (*formatter [Register].bit_format) [mode]), sim_deb);

        if ((*formatter [Register].bit_format) [mode].bar == no_bar) {  /* if nothing follows the bits */
            fputc ('\n', sim_deb);                                      /*   then the format is complete */
            return;                                                     /*     and we're done */
            }
        }

    if (mode == Read                                        /* if reading */
      && formatter [Register].format_1 != NULL)             /*   and an additional format is present */
        fprintf (sim_deb, formatter [Register].format_1,    /*     then use it to format the data field */
                 HP_BITS_TO (formatter [Register].start_1,  /*       indicated by the start and end bits */
                             formatter [Register].end_1, data));

    if (formatter [Register].format_2 != NULL)              /* if a second additional format is present */
        fprintf (sim_deb, formatter [Register].format_2,    /*   then use it to format the data field */
                 HP_BITS_TO (formatter [Register].start_2,  /*     indicated by the start and end bits */
                             formatter [Register].end_2, data));

    fputc ('\n', sim_deb);                              /* end the trace with a new line */
    }

return;                                                 /* return with the register trace printed */
}


/* Trace a FIFO operation.

   This routine is called to trace a FIFO load or unload operation.  On entry,
   "mode" is either Inbound or Outbound, depending on the FIFO to trace,
   "action" is either Load or Unload, depending on the operation, "dptr" is a
   pointer to the GIC device, "phi" is a pointer to the PHI state structure,
   and "data" is the data value being loaded or unloaded.  Entry assumes that
   the TRACE_FIFO condition has already been qualified.
*/

static void trace_fifo (uint32 gic_id, FIFO_MODE mode, FIFO_ACTION action, HP_WORD data)
{
DEVICE    *const dptr = gics [gic_id].dptr;             /* the per-instance device pointer */
PHI_STATE *const phi  = &gics [gic_id].sptr->phi;       /* the per-instance PHI state pointer */
OUTBOUND_TAG tag;
uint32       value;

if (mode == Inbound)                                                    /* if the mode is inbound */
    hp_trace (dptr, TRACE_FIFO, "%s %03o %s inbound FIFO count %u\n",   /*   then the trace */
              inbound_tags [FIFO_TAG (data)], FIFO_DATA (data),         /*     may be derived directly */
              action_names [action], phi->fifo_count [Inbound]);        /*       from the data */

else {                                                  /* otherwise the mode is outbound */
    tag = tag_word (phi, data);                         /*   so get the data tag */
    value = FIFO_DATA (data);                           /*     and value */

    if ((tag == Tag_Counted || tag == Tag_LF_Counted)   /* if this is a counted transfer enable */
      && value == 0)                                    /*   and the count is zero */
        value = 256;                                    /*     then use a count of 256 */

    hp_trace (dptr, TRACE_FIFO, outbound_fmts [tag],    /* trace the outbound action */
              value, action_names [action],
              "outbound FIFO count", phi->fifo_count [Outbound]);
    }

return;
}


/* Tag the outbound data word.

   This routine determines the type of outbound data word supplied and returns a
   corresponding tag.  On entry, "phi" is a pointer to the PHI state structure,
   and "data" is the data value to be sent.

   The upper two bits of the 16-bit data word form an outbound mode field to
   indicate the type of output operation to be performed.  While inbound
   operations may be determined unambiguously from the mode bits in the data
   word, the bits for outbound operations have overlapping meanings.  Operation
   interpretation therefore depends on the mode bits and the state of the PHI
   when the word is accessed.  The outbound interpretation rules are:

     if PHI is CIC then
       if tag is COMMAND then command byte
       else if talker and not serial poll enable then data byte
       else if tag is UNCOUNTED and count is 0 then uncounted transfer enable
       else counted transfer enable
     else
       data byte

   An uncounted transfer enable word has the mode bits set to 11 binary, with
   the bits of the byte count field set to zero.  However, for backward
   compatibility, if the byte count is > 0, then the word is interpreted as a
   counted transfer.
*/

static OUTBOUND_TAG tag_word (PHI_STATE *const phi, uint32 word)
{
if (phi->registers [Phi_1] & R1_CNTLR)                  /* if the PHI is the controller */
    if ((word & R0_MODE_MASK) == R0_MODE_COMMAND)       /*   then if it's a command byte */
        return Tag_Command;                             /*     then return the command tag */

    else if (phi->registers [Phi_1] & R1_TALKER         /* otherwise if the PHI is talking */
      && not phi->serial_poll_active)                   /*   and a serial poll is not active */
        if (word & R0_EOI)                              /*   then if the "add EOI" bit is set */
            return Tag_EOI_Data;                        /*     then return the EOI + data tag */
        else                                            /*   otherwise */
            return Tag_Data;                            /*     return the data tag */

    else if ((word & R0_MODE_MASK) == R0_MODE_UNCOUNTED /* otherwise if it's an uncounted transfer enable */
      && R0_COUNT (word) == 0)                          /*   and the word count is zero */
        return Tag_Uncounted;                           /*     then return the uncounted tag */

    else if (word & R0_NO_LF)                           /* otherwise if the "no LF match" bit is set */
        return Tag_Counted;                             /*   then return the counted enable tag */

    else                                                /* otherwise */
        return Tag_LF_Counted;                          /*   return the end-on-LF or counted enable tag */

else if (word & R0_EOI)                                 /* otherwise if the PHI device has the "add-EOI" bit set */
    return Tag_EOI_Data;                                /*     then return the EOI + data tag */

else                                                    /*   otherwise */
    return Tag_Data;                                    /*     return the data tag */
}
