460 Notes #7 Interrupts

                  EECS 460 NOTES on Interrupts.

1. Interrupts are EXTERNAL signals from devices to CPU, requesting for service.

2. Intel CPU:  
     2 binary interrupt request lines: NMI (Non-Maskable Interrupt) and INTR:
              asserted to logical 1 if a request is present.
 
     The CPU always accepts any NMI request, hence the name NMI.

     For INTR requests, the CPU may mask it out as follows:
     CPU.flagReg.I  bit = 0 ===> keep INTR pending
                          1 ===> may accept INTR now
   
     CLI/STI instructions clear/set the I bit.

3. Interrupt Routing:
   In Intel-based PCs, interrupts are setup as shown below.

                           -------- 
       (timer)   IRQ0      |      |            ------- 
       (KBD)     IRQ1      |      |            | CPU:|
 SLAVE_8259 ===> IRQ2      |      |   INT      |     |
       (port2)   IRQ3 ====>| 8259 |----->----> |INTR |
       (port1)   IRQ4      |      |            |     | 
       (HD)      IRQ5      |      |<--ACK----- |     |<---NMI request
       (FF)      IRQ6      |      |            |-----|
       (printer) IRQ7      | 0x20 = CNTL reg)
                           | 0x21 = MASK reg)
                           --------

    Among the IRQ's, IRQ0 has the highest priority. The 8259 is a dog-fight 
    box, where the top-dog (highest priority IRQ) emerges, i.e. the smallest 
    IRQn is sent to the CPU's INTR.  The 8259 has an
              INT_CNTL register at  0x20
              INT_MASK register at  0x21  
    Their roles are explained below.
    ==============================================================
    In 32-bit PCs, a slave 8259 is added BEFORE the master 8259. The
    slave's INT request is fed to the IRQ2 of the master 8259. 
    Its registers are at 0xA0, 0xA1.  The added IRQs are known as

              IRQ8 = real-time clock
              IRQ9 = re-directed IRQ2
              IRQ10-12 = general use
              IRQ13=FPU
              IRQ14=IDE channel 1 (HDs)
              IRQ15=IDE channel 2 (CDROMs?)

    ============================================================== 

    Each 8259 has a                  
              INT_CNTL    register at 0x20     (Slave : 0xA0)
              INT_MASK    register at 0x21     (Slave : 0xA1) 

   (1). Consider the Master 8259 only. 
        First, the INT_CNTL register emable/disable ALL IRQs. 
        Second, with INT_CNTL == enabled (0x20), each individual IRQn
        (n = 0 to 7) can be selectively enabled/disabled by the INT_MASK 
        register:  IRQn is enabled if and only if
                   bit n of INT_MASK register == 0;
                   (bit n == 1 means IRQn is disabled)
  
   (2). After an interrupt IRQi, the 8259 automatically "masks out" all IRQj
        of the same or lower prioirty. The SOFTWARE interrupt handler must
        explicitly re-enable the 8259 again by writing

         0x20  to the INT_CNTL register (at 0x20 or 0xA0)

        Otherwise, no further interrupts (of the same or lower priority) can 
        occur again. This is perhaps the most unusual aspect of the PC 
        architecture.

4. Priority, enable/disable maskIn/maskOut:  

   The above INFO is repeated here once again.
  
(1). The 8259 orders the interrupt requests from IRQ0 (highest) to IRQ7 
     (lowest). Each IRQ level yields a VECTOR Number = IRQn + 8

(2). It can be programmed (by writing into its control register) to 
     enable/disable any of the 8 interrupts. The I/O location 0x21 is the 
     INT Mask Register. A 0 at bit n enables IRQn, a 1 disable IRQn.

(3). When interrupt requests occur (at its IRQi lines), the request with the 
     highest priority is routed to INTR of the CPU.  Meanwhile, it stops 
     routing any interrupt requests of the same or lower level BUT will route 
     any higher lever requests to CPU.

(4). CPU: Even though INTR may be asserted, the CPU will not accept the request
     until its flagReg.I bit is 1.  While the flagReg bit is 0, INTR will 
     remain Hi, keeping the request pending.

5. Interrupt Processing:
   When an interrupt IRQi occurs, the CPU will start interrupt processing (at 
   the end of current instruction) if its I bit is 1.
 
   (1). CPU issues an INT_ACK signal to 8259 (asking for interrupt ID).
   (2). The 8259 spits out a byte value, called a VECTOR, to the data bus,
        allowing the CPU to read the vector value, which is IRQi+8, (which can
        be changed by programming the 8259 but we will use the default value).

   (3). After acquiring the vector n, the CPU's actions are identical to
        those of INT n, i.e. it first pushes [flag, CS, PC] onto the CURRENT
        stack, (changes flag's T and I bits to 0), load [PC,CS] from vector
        locations [4*n, 4*n+2], and continues execution from the new [PC,CS].

    Example:   
    Suppose we want to handle timer interrupts, IRQ0, in our MTX kernel. We 
    must do as follows:

    (1). Make sure IRQ0 is "un-masked", i.e. bit0 of 5259's mask register 
         (0x21) is cleared to 0. If not, write to the IO port 0x21 to clear
         that bit. (For convenience, a function enable_irq(IRQ) is provided).

    (2). Install timer handler to vector #8: Write 
                [ _tinth, 0x1000 ] to [4*8, 4*8+2]. 
         where _tinth() is the entry point of timer interrupt handler, similar
         to _inth() for INT 80 which we used for syscalls. As before. these can
         done by    put_word(W, 0x0000, offset);

    (3). With (1) and (2), timer interrupts will occur immediately. 
         If we do not want to accept these interrupts yet, we can mask them out
         by CLI (which clears the I bit), and STI when we are ready to handle 
         them.,  Again, for convenience, the functions lock()/unlock() can be 
         used to CLI/STI. 
 
    (4). Once execution begins from _tinth() in OUR kenrel, we must have a
         kernel mode stack to support the interrupt processing. Details will be
         given in the TIMER LAB assignment. 

6. Motorola 680xy
    A 680xy CPU has 3 (binary) interrupt request input lines, which may be 
    regarded as a single DECIMAL request INTR with values ranging from 0 to 7;
    0 means no INTR,  1 to 7 means an INTR of that level. The CPU's status 
    register also has a 3-bit "(interrupt) priority level" field, which can be
    set to 0 to 7 by software. INTR = 7  behaves as NMI, i.e. an INTR 7 is 
    accepted immediately. When an INTR = 1 to 6 occurs, the CPU will accept the
    request only if its PS.priority value is less than the INTR value. The CPU
    can raise or lower its own PS.priority while in K mode, thereby maskIn/out
    any level of interrupt requests.

    When the CPU accepts an INTR, say at level 5, it saves old PS PC on sstack,
    changes PS.priority to that of INTR, i.e. also 5, which effectively maskOut
    any further requests at level 5 or lower.  As long as the level-5 handler 
    routine does not change PS.priority, CPU will run at level 5. While at 
    level 5, it will accept any reuest of level 6 (naturally 7 also) but not 
    any requests at level-5 or below.  Such interrupts may occur (from their 
    devices) but they will be kept pending until they become higher than the
    CPU's priority.

    Assume 7 Devices, each has an Interface, which can generate an IRQ.  
    Fed these IRQs as inputs to 1,2,3,4,5,6,7  of  an 8-to-3 priority encoder,
    e.g. the 74183 IC. The 3-line outputs of the 74183 can be fed to the INTR 
    lines of the 680xx CPU.

    To support more interrupts, simply use more encoders.  To the CPU, there 
    is only ONE interrupt request but with a (decimal) value of 1 to 7.  
    In contrast, the Intel CPU also sees ONLY one binary INTR (and an NMI).