Remember, an interrupt causes an unscheduled jump to a subroutine. Basically, all you have to know to handle interrupts is the location the machine jumps to on an interrupt, how to identify the type of interrupt, and how to return to where you came from. In MIPS, coprocessor 0 handles the interrupts. In order to enable the interrupts, you need to set a bit in a couple of places. In particular, the receiver and transmitter control bits need to have their ability to cause an interrupt enabled, and you also need to turn interrupts on in the coprocessor. The receiver and transmitter control regs are at location 0xffff0000 and 0xffff0008, respectively. As stated in the SPIM manual, setting bit 1 (the second bit) in these two locations will enable that particular type of interrupt.
Once the interrupt has been enabled in the receiver/transmitter control register, it also needs to be enabled in the coprocessor. As the SPIM manual explains, this is accomplished by setting the appropriate bits in the status register of coprocessor 0. Bit 0 of the status register must be set, which enables the recognition of interrupts. The types of interrupts you want to recognize must also be enabled - in SPIM the interrupts you can enable are level 0 (receive) and level 1 (transmit) interrupts. These are represented by bits 8 and 9 of the status register (not 10 and 11, as the SPIM manual implies).
Once receive and transmit interrupts have been enabled, code needs to be put in the appropriate place to handle the interrupts. In SPIM, an interrupt causes an unscheduled jump to location 0x80000080. This is in the OS (kernel) space, so the code you write to handle the interrupt must be in the kernel code segment. This means you type ".ktext 0x80000080" before your interrupt handling program, instead of just ".text". What does your code at 0x80000080 do? Well, keep in mind a couple of things. First - coprocessor 0 register 13 is the "cause" register. If you look at the SPIM manual, you will see that bits 2-5 contain a 4-bit code that tells what the exception was. A 0000 in this field indicates an External Interrupt, which is what the transmit or receive interrupts are. I would suggest checking this field first, to see if the "right" kind of exception occurred, and if not, exit.
Once you are sure it is the right kind of interrupt, you need to check the type of the interrupt. Bit 8 of the cause register contains the status of the received character interrupt, while bit 9 contains the transmit character ready interrupt status. If it is a received character, then the character will be accessable through the received data register (0xffff0004).
Some more information for the curious - in most machines, when you are servicing an interrupt, you want to turn off all (maskable) interrupts so you can be left to service the one you are working on in peace. In MIPS, interrupts are actually turned off automatically upon interrupt. That is what the bottom 6 bits of the status register tell you - when an interrupt occurs, the thing is shifted left, with 0's being put into the bottom 2 bits. This turns off interrupts, so no maskable interrupts will be recognized until you enable them again. This is what the SPIM manual is talking about in the description of the status register.
So you have finished servicing the interrupt routine - now what? How do you return from the interrupt? In many machines, there is an actual "return from interrupt" instruction. As usual, in MIPS there is no specific instruction, so you have to fabricate one. You do this by getting the return address from the coprocessor, where it is stored in register 14. Put the return address in a local register, then execute an "rfe" instruction. This will restore the status register to it's state before the interrupt, which if you think about it will also turn interrupts back on (since they were on before). Finally, execute a jump to the register you loaded from coprocessor 0, and you are done.
The exit code looks like this:
------------------------ done: mfc0 $k1,$14 # get the return address from the coprocessor rfe # restore the status register jr $k1 # jump back to where you were when interrupted. ------------------------