Page 433 - Programming Microcontrollers in C
P. 433

418    Chapter 8  MCORE, A RISC Machine

                          save these registers on the stack. The following two assembly
                          instructions load the address of table into R2 and the address of
                          fIpnd1 into R3. We want the contents of the value found in the
                          FPIND register. Therefore, we must dereference the value in R3 twice,
                          once to get the address of FPIND and then to get the contents of
                          FPIND. This value has a bit set for every pending fast interrupt. When
                          this value is operated on by the FF1 instruction, the register R3 will
                          contain the 32 minus the bit number of the highest priority pending
                          interrupt. If you look at how table() is constructed, you will find
                          that the highest priority interrupts are listed first down to the lowest
                          priority. Each entry in the table requires four bytes to hold a function
                          pointer with this system. Therefore, we must multiply the value found
                          in R3 by 4, shift it left 2, and then add the result to the value in R2 to
                          find the address of the desired interrupt service routine.
                              All of that is exactly what is done with the assembly language
                          insert shown above. The last instruction jsr R2 passes control of
                          the computer to the specified interrupt service routine. If you look at
                          the C code generated by handler() you will find first that the
                          necessary computer status is saved and then the assembly code in the
                          macro Do_Interrupt() is executed. The last instruction here is
                          the jsr R2 instruction mentioned above. After the code needed for
                          the interrupt service routine is completed, control is returned to
                          handler() where the machine status is restored and control is
                          returned to the interrupted program with an rfi, return from fast
                          interrupt, instruction.
                              The compiler has a #pragma interrupt isr_function. This
                          #pragma causes the function specified by the isr_function to
                          be compiled as an interrupt service routine. These functions save a
                          portion of the machine status, execute the code specified in the
                          isr_function, and restore the machine status before returning
                          to the interrupted program with an rfi instruction. When writing a
                          general function such as the one above, it was found that the partial
                          status save was not enough. No functions could be called from within
                          the interrupt service routine. This limitation was too great for a
                          general-purpose handler like that above, so in this routine, the entire
                          status of the computer is saved and restored rather than the partial
                          save and restore generated by the #pragma. It is safe to execute
                          functions within the interrupt service routines in the handler above.
   428   429   430   431   432   433   434   435   436   437   438