
VMIPS interrupt controller
--------------------------

 There are 8 interrupt lines in the R3000/R3000A, 6 of which (7..2) are
 hardware interrupts (readable by software), and the other 2 of which
 (1..0) are software interrupts (readable/writable by software).

                          _     IP0   _____
                         /       o----|    \
                        |             | AND |-----.
                        |        o----|____/       \
                        |       IM0                 |
               from    /                            |
             software -         IP1   _____         |
               regs    \         o----|    \        |
                        |             | AND |-.     |
                        |        o----|____/   \    |
                         \_     IM1             \   |
 Dv1.2-------._____                              \  |
       Inputs \    \  IP2             _____       | |
 Dv2.2---------) OR )-----------------|    \      | |
         :    /    /                  | AND |-.   | |
 DvN.2-------'----'   (from reg) o----|____/   \  | |                      Int
                                IM2             \ \ \                       o
 Dv1.3-------._____                              \ \ \._______              |
       Inputs \    \  IP3             _____       \ `--\      \       _____  \
 Dv2.3---------) OR )-----------------|    \       `----\      \    .-|    \  |
         :    /    /                  | AND |------------\      \__/  | AND |-'
 DvN.3-------'----'   (from reg) o----|____/      .------/ OR   /  .--|____/
                                IM3              //-----/      /  /
                                      _____     //.----/      /   |
                           .----------|    \   ///  .-/______/    o
                          / IP4       | AND |-'/ |  |             IEc
                          |      o----|____/  /  |  |            (from
                          |     IM4           |  |  |             reg)
              .           .  (from reg)       o  o  o
              .           .                   5  6  7
              .           .                                 

  DvI.j - `device interrupt input for line j'
          becomes true when device I calls assertInt(j); becomes false
          when device I calls deassertInt(j)
  IPj   - `interrupt pending on line j'
          true if any of the DvI.j is true (becomes true when assertInt(j)
          is called by any DvI.j; becomes false when some DvI.j calls
          deassertInt(j) and no other DvI.j is asserted)
  IMj   - `interrupt mask for line j'
          true if interrupts from line j are enabled, false if they are
          to be ignored. Note that IMj's setting does not change IPj;
          it only exposes it to or shields it from influencing the
          processor's exception state.
  Int   - `interrupt pending'
          asserted if any interrupt is pending which is not masked, and
          if interrupts are enabled; Int = ((IP & IM != 0) && IEc)

 The interrupt controller maps each device to some number of the 6 hardware
 interrupt lines, in response to calls to attachLine().  When a device
 wants to interrupt the processor, it asserts a hardware interrupt input,
 using assertInt(j). If at least one of the devices tied to a particular
 hardware interrupt line j has asserted that line, then IP for line j+2
 is asserted.  (Therefore, assertInt() always causes IP to become nonzero.)

 When a device decides that the interrupt condition has been satisfied,
 then it can deassert its input for the interrupt line by calling
 deassertInt(). This causes all the other devices tied to that hardware
 interrupt line (call it j) to be checked to see if they are currently
 asserting the hardware interrupt input; if none of them are, then IP
 for line j+2 is deasserted. (Therefore, deassertInt() does not always
 cause IP to become zero.)

 An exception is triggered in the processor at the beginning of a cycle
 if there is an interrupt pending (at least one IPj for j=0..7 must be
 set; i.e., IP != 0), and the IEc field of Status is set (interrupts are
 enabled), and for each IPj which is set, IMj is also set (IP & IM != 0).


How the interrupt controller is integrated
------------------------------------------

 What if there were more than one cpu? Then you'd still want to have at
 most one interrupt controller, and you'd want it to be attached to a
 certain processor. This means that you'd create the interrupt controller
 object and attach it to a "primary" cpu at boot time. The primary cpu's
 cpzero would check at the beginning of each cycle whether there was a
 pending interrupt, and call exception(Int) if there was.  The sequence
 of events would be something like this, for every cpu:

  Ask the cpzero to see if there is an interrupt.
   If there is no attached interrupt controller, there is no interrupt.
   If IEc is deasserted, there is no interrupt.
   Ask the interrupt controller to calculate IP.
    The interrupt controller calculates IP, by querying each device.
   If IP & IM == 0, then there is no interrupt.
   Otherwise, there is an interrupt.
  If there is an interrupt, raise an Int exception.

