2.2.1.1.2.1. Kalisto MIPS Processor Context Switching
.macro SAVE_REGISTERS base

        sw $zero, REGS_OFFSET_ZERO(\base)

        sw $at,   REGS_OFFSET_AT(\base)

        sw $v0,   REGS_OFFSET_V0(\base)
        sw $v1,   REGS_OFFSET_V1(\base)

        sw $a0,   REGS_OFFSET_A0(\base)
        sw $a1,   REGS_OFFSET_A1(\base)
        sw $a2,   REGS_OFFSET_A2(\base)
        sw $a3,   REGS_OFFSET_A3(\base)

        ...

        sw $gp,   REGS_OFFSET_GP(\base)
        sw $fp,   REGS_OFFSET_FP(\base)
        sw $ra,   REGS_OFFSET_RA(\base)

.endm SAVE_REGISTERS


.macro LOAD_REGISTERS base

        lw $ra,   REGS_OFFSET_RA(\base)
        lw $fp,   REGS_OFFSET_FP(\base)
        lw $gp,   REGS_OFFSET_GP(\base)

        ...

        lw $a3,   REGS_OFFSET_A3(\base)
        lw $a2,   REGS_OFFSET_A2(\base)
        lw $a1,   REGS_OFFSET_A1(\base)
        lw $a0,   REGS_OFFSET_A0(\base)

        lw $v1,   REGS_OFFSET_V1(\base)
        lw $v0,   REGS_OFFSET_V0(\base)

        lw $at,   REGS_OFFSET_AT(\base)

        lw $zero, REGS_OFFSET_ZERO(\base)

.endm LOAD_REGISTERS


switch_cpu_context:

        /* Allocate a frame on the stack of the old thread and update
           the address of the stack top of the old thread. */

        addiu $sp, -CONTEXT_SIZE        ;Allocate space on stack
        sw $sp, ($a0)                   ;Save the old stack

        SAVE_REGISTERS $sp              ;Save general registers

        mflo $t0                        ;Few other registers that
        mfhi $t1                         ;the macro does not handle
        sw $t0, REGS_OFFSET_LO($sp)       ;need to be saved as well
        sw $t1, REGS_OFFSET_HI($sp)

        mfc0 $t0, $status
        sw $t0, REGS_OFFSET_STATUS($sp)
        la $t1, ~CP0_STATUS_IE_MASK
        and $t0, $t1
        mtc0 $t0, $status               ;Disable interrupts

        lw $sp, ($a1)                   ;Switch to the new stack

        lw $t0, REGS_OFFSET_LO($sp)     ;Restore the registers in
        lw $t1, REGS_OFFSET_HI($sp)      ;roughly the opposite
        mtlo $t0                          ;order to fit the
        mthi $t1                           ;stack semantics

        LOAD_REGISTERS $sp

        lw $k0, REGS_OFFSET_STATUS($sp)

        addiu $sp, CONTEXT_SIZE         ;Free space on stack

        j $ra                           ;Return to the newly
        mtc0 $k0, $status                ;restored context