| 1 | /********************************************************************************* | 
|---|
| 2 | *    File : giet.s | 
|---|
| 3 | *    Author : Franck Wajsburt & Alain Greiner & Joel Porquet | 
|---|
| 4 | *    Date : 2009 - 2010 | 
|---|
| 5 | ********************************************************************************** | 
|---|
| 6 | *    Interruption/Exception/Trap Handler for MIPS32 processor | 
|---|
| 7 | *    The base address of the segment containing this code | 
|---|
| 8 | *    MUST be 0x80000000, in order to have the entry point | 
|---|
| 9 | *    at address 0x80000180 !!! | 
|---|
| 10 | *    All messages are printed on the TTY defined by the processor ID. | 
|---|
| 11 | ********************************************************************************** | 
|---|
| 12 | *    History : | 
|---|
| 13 | *    15/09/2009 : The GIET entry point has been modified to comply with | 
|---|
| 14 | *        the MIPS32 specification : 0x80000180 | 
|---|
| 15 | *    5/10/2009  : The syscall handler has been modified to comply with the | 
|---|
| 16 | *        MIPS32 specification : the value stored in EPC register is the | 
|---|
| 17 | *        syscall instruction address => it must be incremented by 4 | 
|---|
| 18 | *        to obtain the return address. | 
|---|
| 19 | *    15/10/2009 : The Interrupt handler has been modified to comply with the | 
|---|
| 20 | *        VCI_ICU specification : The IRQ index is obtained by a read | 
|---|
| 21 | *        to (icu_base_address + 16). | 
|---|
| 22 | *    26/10/2009 : The interrupt handler has been modified to support | 
|---|
| 23 | *        multi-processors architectures with one ICU per processor. | 
|---|
| 24 | *        Finally, the mfc0 instruction uses now the select parameter | 
|---|
| 25 | *        to comply with the MIPS32 specification when accessing the | 
|---|
| 26 | *        processor_id (mtfc0 $x, $15, 1) | 
|---|
| 27 | *    08/11/2009 : The syscall handler has been extended to support 32 values | 
|---|
| 28 | *        for the syscall index, and to enable interrupts when processing | 
|---|
| 29 | *        a system call. | 
|---|
| 30 | *        Five new syscalls have been introduced to access the frame buffer | 
|---|
| 31 | *        Three new syscalls have been introduced to access the block device | 
|---|
| 32 | *        The two syscalls associated to the DMA have been removed. | 
|---|
| 33 | *    18/11/2009 : The syscall handler has been modified to save the SR in | 
|---|
| 34 | *        the stack before enabling interrupts. | 
|---|
| 35 | *    15/03/2010 : replace the itoa_print assembler function by the itoa_hex() | 
|---|
| 36 | *        function defined in the syscalls.c file. | 
|---|
| 37 | *    10/04/2010 : modify the interrupt handler to use the new ICU component | 
|---|
| 38 | *        supporting up to 8 output IRQs for 8 processors. | 
|---|
| 39 | *        The active IRQ index is obtained as ICU[32*PROC_ID+16]. | 
|---|
| 40 | *    12/09/2010 : The ctx_switch functionhas been included in this file to | 
|---|
| 41 | *        simplify the compilation process. | 
|---|
| 42 | *   25/09/2010 : add '.end' directive to end the _giet function | 
|---|
| 43 | *        and modify the 'sharp' comment character into the regular "slash | 
|---|
| 44 | *        asterix ... asterix slash" comment syntax | 
|---|
| 45 | *   27/09/2010 : respect stack convention with 4 minimum slots before calling | 
|---|
| 46 | *        C functions | 
|---|
| 47 | *   28/09/2010 : Save all the non-persistant registers in the int_handler | 
|---|
| 48 | *   02/02/2011 : Introduce the "segment_increment" parameter in the interrupt | 
|---|
| 49 | *        handler to support clusterised multi-processing. | 
|---|
| 50 | *        Introducing the barrier_init() & barrier_wait() system calls. | 
|---|
| 51 | *   04/04/2011 : introducing the system call proc_num()  | 
|---|
| 52 | *   12/04/2011 : modifying the _int_handler to support the XICU component in | 
|---|
| 53 | *        multi_clusters/multi-processors architectures: | 
|---|
| 54 | *        the XICU base address depends the cluster_id and the PRIO register | 
|---|
| 55 | *        address depends on the local_id. | 
|---|
| 56 | **********************************************************************************/ | 
|---|
| 57 |  | 
|---|
| 58 |     .section .giet,"ax",@progbits | 
|---|
| 59 |     .align 2 | 
|---|
| 60 |     .global _interrupt_vector    # makes interrupt_vector an external symbol  | 
|---|
| 61 |  | 
|---|
| 62 |     .extern seg_icu_base | 
|---|
| 63 |     .extern seg_tty_base | 
|---|
| 64 |     .extern NB_CLUSTERS | 
|---|
| 65 |     .extern NB_PROCS | 
|---|
| 66 |  | 
|---|
| 67 |     .extern isr_default | 
|---|
| 68 |  | 
|---|
| 69 |     .extern _procid | 
|---|
| 70 |     .extern _proctime | 
|---|
| 71 |     .extern _tty_write | 
|---|
| 72 |     .extern _tty_read | 
|---|
| 73 |     .extern _tty_read_irq | 
|---|
| 74 |     .extern _timer_write | 
|---|
| 75 |     .extern _timer_read | 
|---|
| 76 |     .extern _icu_write | 
|---|
| 77 |     .extern _icu_read | 
|---|
| 78 |     .extern _gcd_write | 
|---|
| 79 |     .extern _gcd_read | 
|---|
| 80 |     .extern _locks_read | 
|---|
| 81 |     .extern _locks_write | 
|---|
| 82 |     .extern _exit | 
|---|
| 83 |     .extern _fb_sync_write | 
|---|
| 84 |     .extern _fb_sync_read | 
|---|
| 85 |     .extern _fb_write | 
|---|
| 86 |     .extern _fb_read | 
|---|
| 87 |     .extern _fb_completed | 
|---|
| 88 |     .extern _ioc_write | 
|---|
| 89 |     .extern _ioc_read | 
|---|
| 90 |     .extern _ioc_completed | 
|---|
| 91 |     .extern _itoa_hex | 
|---|
| 92 |     .extern _barrier_init | 
|---|
| 93 |     .extern _barrier_wait | 
|---|
| 94 |  | 
|---|
| 95 |     .ent _giet | 
|---|
| 96 |  | 
|---|
| 97 | /*************************************************************** | 
|---|
| 98 | *    Cause Table (indexed by the Cause register) | 
|---|
| 99 | ***************************************************************/ | 
|---|
| 100 | tab_causes: | 
|---|
| 101 |     .word _int_handler  # 0000 : external interrupt  | 
|---|
| 102 |     .word _cause_ukn    # 0001 : undefined exception  | 
|---|
| 103 |     .word _cause_ukn    # 0010 : undefined exception  | 
|---|
| 104 |     .word _cause_ukn    # 0011 : undefined exception  | 
|---|
| 105 |     .word _cause_adel   # 0100 : illegal address read exception  | 
|---|
| 106 |     .word _cause_ades   # 0101 : illegal address write exception  | 
|---|
| 107 |     .word _cause_ibe    # 0110 : instruction bus error exception  | 
|---|
| 108 |     .word _cause_dbe    # 0111 : data bus error exception  | 
|---|
| 109 |     .word _sys_handler  # 1000 : system call  | 
|---|
| 110 |     .word _cause_bp     # 1001 : breakpoint exception  | 
|---|
| 111 |     .word _cause_ri     # 1010 : illegal codop exception  | 
|---|
| 112 |     .word _cause_cpu    # 1011 : illegal coprocessor access  | 
|---|
| 113 |     .word _cause_ovf    # 1100 : arithmetic overflow exception  | 
|---|
| 114 |     .word _cause_ukn    # 1101 : undefined exception  | 
|---|
| 115 |     .word _cause_ukn    # 1110 : undefined exception  | 
|---|
| 116 |     .word _cause_ukn    # 1111 : undefined exception  | 
|---|
| 117 |  | 
|---|
| 118 |     .space 320 | 
|---|
| 119 |  | 
|---|
| 120 | /*************************************************************** | 
|---|
| 121 | *    Entry point (at address 0x80000180) | 
|---|
| 122 | ***************************************************************/ | 
|---|
| 123 | _giet: | 
|---|
| 124 |     mfc0    $27,    $13             # Cause Register analysis  | 
|---|
| 125 |     lui     $26,    0x8000          # $26 <= tab_causes  | 
|---|
| 126 |     andi    $27,    $27,    0x3c | 
|---|
| 127 |     addu    $26,    $26,    $27 | 
|---|
| 128 |     lw      $26,    ($26) | 
|---|
| 129 |     jr      $26                     # Jump indexed by CR  | 
|---|
| 130 |     .end _giet | 
|---|
| 131 |  | 
|---|
| 132 | /**************************************************************** | 
|---|
| 133 | *   System Call Handler | 
|---|
| 134 | * A system call is handled as a special function call. | 
|---|
| 135 | *   - $2 contains the system call index (< 16). | 
|---|
| 136 | *   - $3 is used to store the syscall address | 
|---|
| 137 | *   - $4, $5, $6, $7 contain the arguments values. | 
|---|
| 138 | *   - The return address (EPC) iand the SR are saved in the stack. | 
|---|
| 139 | *   - Interrupts are enabled before branching to the syscall. | 
|---|
| 140 | *   - All syscalls must return to the syscall handler. | 
|---|
| 141 | *   - $2, $3, $4, $5, $6, $7 as well as $26 & $27 can be modified. | 
|---|
| 142 | * | 
|---|
| 143 | * In case of undefined system call, an error message displays | 
|---|
| 144 | * the value of EPC on the TTY corresponding to the processor, | 
|---|
| 145 | * and the user program is killed. | 
|---|
| 146 | ****************************************************************/ | 
|---|
| 147 | _sys_handler: | 
|---|
| 148 |     addiu   $29,    $29,    -24     # 2 slots for SR&EPC, 4 slots for args passing  | 
|---|
| 149 |     mfc0    $26,    $12             # load SR  | 
|---|
| 150 |     sw      $26,    16($29)         # save it in the stack  | 
|---|
| 151 |     mfc0    $27,    $14             # load EPC  | 
|---|
| 152 |     addiu   $27,    $27,    4       # increment EPC for return address  | 
|---|
| 153 |     sw      $27,    20($29)         # save it in the stack  | 
|---|
| 154 |  | 
|---|
| 155 |     andi    $26,    $2,     0x1F    # $26 <= syscall index (i < 32)  | 
|---|
| 156 |     sll     $26,    $26,    2       # $26 <= index * 4  | 
|---|
| 157 |     la      $27,    tab_syscalls    # $27 <= &tab_syscalls[0]  | 
|---|
| 158 |     addu    $27,    $27,    $26     # $27 <= &tab_syscalls[i]  | 
|---|
| 159 |     lw      $3,     0($27)          # $3  <= syscall address  | 
|---|
| 160 |  | 
|---|
| 161 |     li      $27,    0xFFFFFFED      # Mask for UM & EXL bits  | 
|---|
| 162 |     mfc0    $26,    $12             # $26 <= SR  | 
|---|
| 163 |     and     $26,    $26,    $27     # UM = 0 / EXL = 0  | 
|---|
| 164 |     mtc0    $26,    $12             # interrupt enabled  | 
|---|
| 165 |     jalr    $3                      # jump to the proper syscall  | 
|---|
| 166 |     mtc0    $0,     $12             # interrupt disbled  | 
|---|
| 167 |  | 
|---|
| 168 |     lw      $26,    16($29)         # load SR from stack  | 
|---|
| 169 |     mtc0    $26,    $12             # restore SR  | 
|---|
| 170 |     lw      $26,    20($29)         # load EPC from stack  | 
|---|
| 171 |     mtc0    $26,    $14             # restore EPC  | 
|---|
| 172 |     addiu   $29,    $29,     24     # restore stack pointer  | 
|---|
| 173 |     eret                            # exit GIET  | 
|---|
| 174 |  | 
|---|
| 175 | _sys_ukn:                           # undefined system call  | 
|---|
| 176 |     la      $4,     msg_uknsyscall  # $4 <= message address  | 
|---|
| 177 |     li      $5,    36               # $5 <= message length  | 
|---|
| 178 |     jal     _tty_write              # print unknown message  | 
|---|
| 179 |  | 
|---|
| 180 |     la      $4,     msg_epc         # $4 <= message address  | 
|---|
| 181 |     li      $5,    8                # $5 <= message length  | 
|---|
| 182 |     jal     _tty_write              # print EPC message  | 
|---|
| 183 |  | 
|---|
| 184 |     mfc0    $4,     $14             # $4 <= EPC  | 
|---|
| 185 |     la      $5,     itoa_buffer     # $5 <= buffer address  | 
|---|
| 186 |     addiu   $5,     $5,     2       # skip the 0x prefix  | 
|---|
| 187 |     jal     _itoa_hex               # fill the buffer  | 
|---|
| 188 |  | 
|---|
| 189 |     la      $4,     itoa_buffer     # $4 <= buffer address  | 
|---|
| 190 |     li      $5,     10              # $5 <= buffer length  | 
|---|
| 191 |     jal     _tty_write              # print EPC value  | 
|---|
| 192 |  | 
|---|
| 193 |     j       _exit                   # end of program  | 
|---|
| 194 |  | 
|---|
| 195 | itoa_buffer: .ascii "0x00000000" | 
|---|
| 196 |  | 
|---|
| 197 |     .align 2 | 
|---|
| 198 |  | 
|---|
| 199 | /**************************************************************** | 
|---|
| 200 | * System Call Table (indexed by syscall index)  | 
|---|
| 201 | ****************************************************************/ | 
|---|
| 202 | tab_syscalls: | 
|---|
| 203 |     .word _procid           # 0x00  | 
|---|
| 204 |     .word _proctime         # 0x01  | 
|---|
| 205 |     .word _tty_write        # 0x02  | 
|---|
| 206 |     .word _tty_read         # 0x03  | 
|---|
| 207 |     .word _timer_write      # 0x04  | 
|---|
| 208 |     .word _timer_read       # 0x05  | 
|---|
| 209 |     .word _gcd_write        # 0x06  | 
|---|
| 210 |     .word _gcd_read         # 0x07  | 
|---|
| 211 |     .word _icu_write        # 0x08  | 
|---|
| 212 |     .word _icu_read         # 0x09  | 
|---|
| 213 |     .word _tty_read_irq     # 0x0A  | 
|---|
| 214 |     .word _sys_ukn          # 0x0B  | 
|---|
| 215 |     .word _locks_write      # 0x0C  | 
|---|
| 216 |     .word _locks_read       # 0x0D  | 
|---|
| 217 |     .word _exit             # 0x0E  | 
|---|
| 218 |     .word _procnumber       # 0x0F  | 
|---|
| 219 |     .word _fb_sync_write    # 0x10  | 
|---|
| 220 |     .word _fb_sync_read     # 0x11  | 
|---|
| 221 |     .word _fb_write         # 0x12  | 
|---|
| 222 |     .word _fb_read          # 0x13  | 
|---|
| 223 |     .word _fb_completed     # 0x14  | 
|---|
| 224 |     .word _ioc_write        # 0x15  | 
|---|
| 225 |     .word _ioc_read         # 0x16  | 
|---|
| 226 |     .word _ioc_completed    # 0x17  | 
|---|
| 227 |     .word _barrier_init     # 0x18  | 
|---|
| 228 |     .word _barrier_wait     # 0x19  | 
|---|
| 229 |     .word _sys_ukn          # 0x1A  | 
|---|
| 230 |     .word _sys_ukn          # 0x1B  | 
|---|
| 231 |     .word _sys_ukn          # 0x1C  | 
|---|
| 232 |     .word _sys_ukn          # 0x1D  | 
|---|
| 233 |     .word _sys_ukn          # 0x1E  | 
|---|
| 234 |     .word _sys_ukn          # 0x1F  | 
|---|
| 235 |  | 
|---|
| 236 | /****************************************************************** | 
|---|
| 237 | *    Interrupt Handler | 
|---|
| 238 | * This simple interrupt handler cannot be interrupted. | 
|---|
| 239 | * It uses an external ICU component (Interrupt Controler Unit) | 
|---|
| 240 | * that concentrates up to 32 interrupts lines to a single IRQ | 
|---|
| 241 | * line that can be connected to any of the 6 MIPS IT inputs. | 
|---|
| 242 | * This component returns the highest priority active interrupt index | 
|---|
| 243 | * (smaller indexes have the highest priority). | 
|---|
| 244 | * | 
|---|
| 245 | * In case of a multi-clusters architecture, it exist one ICU  | 
|---|
| 246 | * per cluster. The base address of the ICU segment depends on both | 
|---|
| 247 | * the cluster_id and the proc_id: | 
|---|
| 248 | * - icu_base_address = seg_icu_base + (32 * local_id) + | 
|---|
| 249 | *                    (cluster_increment * cluster _id) | 
|---|
| 250 | * - cluster_id = proc_id / NB_PROCS  | 
|---|
| 251 | * - local_id = proc_id % NB_PROCS | 
|---|
| 252 | * - cluster_increment = 4G / NB_CLUSTERS | 
|---|
| 253 | * | 
|---|
| 254 | * The interrupt handler reads the XICU PRIO register, | 
|---|
| 255 | * using the offset 16. | 
|---|
| 256 | * This component returns the highest priority interrupt index | 
|---|
| 257 | * (smaller indexes have the highest priority). | 
|---|
| 258 | * Any value larger than 31 means "no active interrupt", and | 
|---|
| 259 | * the default ISR (that does nothing) is executed. | 
|---|
| 260 | * The interrupt vector (32 ISR addresses array stored at | 
|---|
| 261 | * _interrupt_vector address) is initialised with the default | 
|---|
| 262 | * ISR address. The actual ISR addresses are supposed to be written | 
|---|
| 263 | * in the interrupt vector array by the boot code. | 
|---|
| 264 | * All non persistant registers, such as $1 to $15, and $24 to $25, | 
|---|
| 265 | * as well as register $31 and EPC, are saved in the interrupted | 
|---|
| 266 | * program stack, before calling the Interrupt Service Routine. | 
|---|
| 267 | * These registers can be used by the ISR code. | 
|---|
| 268 | *******************************************************************/ | 
|---|
| 269 | _int_handler: | 
|---|
| 270 |     addiu   $29,    $29,    -23*4   # stack space reservation  | 
|---|
| 271 |     .set noat | 
|---|
| 272 |     sw      $1,     4*4($29)        # save $1  | 
|---|
| 273 |     .set at | 
|---|
| 274 |     sw      $2,     4*5($29)        # save $2  | 
|---|
| 275 |     sw      $3,     4*6($29)        # save $3  | 
|---|
| 276 |     sw      $4,     4*7($29)        # save $4  | 
|---|
| 277 |     sw      $5,     4*8($29)        # save $5  | 
|---|
| 278 |     sw      $6,     4*9($29)        # save $6  | 
|---|
| 279 |     sw      $7,     4*10($29)       # save $7  | 
|---|
| 280 |     sw      $8,     4*11($29)       # save $8  | 
|---|
| 281 |     sw      $9,     4*12($29)       # save $9  | 
|---|
| 282 |     sw      $10,    4*13($29)       # save $10  | 
|---|
| 283 |     sw      $11,    4*14($29)       # save $11  | 
|---|
| 284 |     sw      $12,    4*15($29)       # save $12  | 
|---|
| 285 |     sw      $13,    4*16($29)       # save $13  | 
|---|
| 286 |     sw      $14,    4*17($29)       # save $14  | 
|---|
| 287 |     sw      $15,    4*18($29)       # save $15  | 
|---|
| 288 |     sw      $24,    4*19($29)       # save $24  | 
|---|
| 289 |     sw      $25,    4*20($29)       # save $25  | 
|---|
| 290 |     sw      $31,    4*21($29)       # save $31  | 
|---|
| 291 |     mfc0    $27,    $14 | 
|---|
| 292 |     sw      $27,    4*22($29)       # save EPC  | 
|---|
| 293 |  | 
|---|
| 294 |     # XICU PRIO register address computation (depending on cluster_id & local_id) | 
|---|
| 295 |     mfc0    $10,    $15,    1       # $10 <= proc_id  | 
|---|
| 296 |     andi    $10,    $10,    0x3FF   # at most 1024 processors  | 
|---|
| 297 |     la      $11,    NB_PROCS        # $11 <= NB_PROCS  | 
|---|
| 298 |     divu    $10,    $11 | 
|---|
| 299 |     mflo    $12                     # $12 <= cluster_id  | 
|---|
| 300 |     mfhi    $13                     # $13 <= local_id  | 
|---|
| 301 |     la      $11,    NB_CLUSTERS     # $11 <= NB_CLUSTERS  | 
|---|
| 302 |     li      $14,    0x80000000       | 
|---|
| 303 |     divu    $14,    $11 | 
|---|
| 304 |     mflo    $15  | 
|---|
| 305 |     sll     $15,    $15,    1       # $15 <= cluster_increment = 4G / NB_CLUSTERS  | 
|---|
| 306 |     multu   $15,    $12 | 
|---|
| 307 |     mflo    $6                      # $6 <= cluster_increment * cluster_id  | 
|---|
| 308 |     li      $7,     0b011110000000  # $7 <= PRIO offset  | 
|---|
| 309 |     sll     $8,     $13,    2       # $8 <= local_id*4  | 
|---|
| 310 |     addu    $9,     $7,     $8      # $9 <= PRIO offset + local_id*4  | 
|---|
| 311 |     la      $27,    seg_icu_base     | 
|---|
| 312 |     addu    $26,    $9,     $27     # $26 <= seg_icu_base + PRIO offset + local_id*4  | 
|---|
| 313 |     addu    $26,    $26,    $6      # $26 <= seg_icu_base + increment*cluster_id + PRIO offset + local_id*4  | 
|---|
| 314 |  | 
|---|
| 315 |     # XICU access and interrupt vector access | 
|---|
| 316 |     lw      $26,    ($26)           # $26 <= PRIO register value  | 
|---|
| 317 |     andi    $27,    $26,    0x2     # test bit HWI active | 
|---|
| 318 |     beq     $27,    $0,     restore # do nothing if no active IRQ  | 
|---|
| 319 |     srl     $26,    $26,    14      # $26 <= $26 >> 14  | 
|---|
| 320 |     andi    $26,    $26,    0x7C    # $26 <= interrupt_index * 4  | 
|---|
| 321 |     la      $27,    _interrupt_vector | 
|---|
| 322 |     addu    $26,    $26,    $27 | 
|---|
| 323 |     lw      $26,    ($26)           # read ISR address  | 
|---|
| 324 |     jalr    $26                     # call ISR  | 
|---|
| 325 | restore: | 
|---|
| 326 |     .set noat | 
|---|
| 327 |     lw      $1,     4*4($29)        # restore $1  | 
|---|
| 328 |     .set at | 
|---|
| 329 |     lw      $2,     4*5($29)        # restore $2  | 
|---|
| 330 |     lw      $3,     4*6($29)        # restore $3  | 
|---|
| 331 |     lw      $4,     4*7($29)        # restore $4  | 
|---|
| 332 |     lw      $5,     4*8($29)        # restore $5  | 
|---|
| 333 |     lw      $6,     4*9($29)        # restore $6  | 
|---|
| 334 |     lw      $7,     4*10($29)       # restore $7  | 
|---|
| 335 |     lw      $8,     4*11($29)       # restore $8  | 
|---|
| 336 |     lw      $9,     4*12($29)       # restore $9  | 
|---|
| 337 |     lw      $10,    4*13($29)       # restore $10  | 
|---|
| 338 |     lw      $11,    4*14($29)       # restore $11  | 
|---|
| 339 |     lw      $12,    4*15($29)       # restore $12  | 
|---|
| 340 |     lw      $13,    4*16($29)       # restore $13  | 
|---|
| 341 |     lw      $14,    4*17($29)       # restore $14  | 
|---|
| 342 |     lw      $15,    4*18($29)       # restore $15  | 
|---|
| 343 |     lw      $24,    4*19($29)       # restore $24  | 
|---|
| 344 |     lw      $25,    4*20($29)       # restore $25  | 
|---|
| 345 |     lw      $31,    4*21($29)       # restore $31  | 
|---|
| 346 |     lw      $27,    4*22($29)       # return address (EPC)  | 
|---|
| 347 |     addiu   $29,    $29,    23*4    # restore stack pointer  | 
|---|
| 348 |     mtc0    $27,    $14             # restore EPC  | 
|---|
| 349 |     eret                            # exit GIET  | 
|---|
| 350 |  | 
|---|
| 351 | /* The default ISR is called when no specific ISR has been installed in the | 
|---|
| 352 |  interrupt vector. It simply displays a message on TTY 0. */ | 
|---|
| 353 |  | 
|---|
| 354 | isr_default: | 
|---|
| 355 |     addiu   $29,    $29,    -20     # get space in stack  | 
|---|
| 356 |     sw      $31,    16($29)         # to save the return address  | 
|---|
| 357 |     la      $4,     msg_default     # $4 <= string address  | 
|---|
| 358 |     addi    $5,     $0,     36      # $5 <= string length  | 
|---|
| 359 |     jal     _tty_write              # print  | 
|---|
| 360 |     lw      $31,    16($29)         # restore return address  | 
|---|
| 361 |     addiu   $29,    $29,    20      # free space  | 
|---|
| 362 |     jr      $31                     # returns to interrupt handler  | 
|---|
| 363 |  | 
|---|
| 364 | /***************************************************** | 
|---|
| 365 |  Interrupt Vector Table (indexed by interrupt index) | 
|---|
| 366 |   32 words corresponding to 32 ISR addresses  | 
|---|
| 367 | ******************************************************/ | 
|---|
| 368 | _interrupt_vector: | 
|---|
| 369 |     .word isr_default   # ISR 0  | 
|---|
| 370 |     .word isr_default   # ISR 1  | 
|---|
| 371 |     .word isr_default   # ISR 2  | 
|---|
| 372 |     .word isr_default   # ISR 3  | 
|---|
| 373 |     .word isr_default   # ISR 4  | 
|---|
| 374 |     .word isr_default   # ISR 5  | 
|---|
| 375 |     .word isr_default   # ISR 6  | 
|---|
| 376 |     .word isr_default   # ISR 7  | 
|---|
| 377 |     .word isr_default   # ISR 8  | 
|---|
| 378 |     .word isr_default   # ISR 9  | 
|---|
| 379 |     .word isr_default   # ISR 10  | 
|---|
| 380 |     .word isr_default   # ISR 11  | 
|---|
| 381 |     .word isr_default   # ISR 12  | 
|---|
| 382 |     .word isr_default   # ISR 13  | 
|---|
| 383 |     .word isr_default   # ISR 14  | 
|---|
| 384 |     .word isr_default   # ISR 15  | 
|---|
| 385 |     .word isr_default   # ISR 16  | 
|---|
| 386 |     .word isr_default   # ISR 17  | 
|---|
| 387 |     .word isr_default   # ISR 18  | 
|---|
| 388 |     .word isr_default   # ISR 19  | 
|---|
| 389 |     .word isr_default   # ISR 20  | 
|---|
| 390 |     .word isr_default   # ISR 21  | 
|---|
| 391 |     .word isr_default   # ISR 22  | 
|---|
| 392 |     .word isr_default   # ISR 23  | 
|---|
| 393 |     .word isr_default   # ISR 24  | 
|---|
| 394 |     .word isr_default   # ISR 25  | 
|---|
| 395 |     .word isr_default   # ISR 26  | 
|---|
| 396 |     .word isr_default   # ISR 27  | 
|---|
| 397 |     .word isr_default   # ISR 28  | 
|---|
| 398 |     .word isr_default   # ISR 29  | 
|---|
| 399 |     .word isr_default   # ISR 30  | 
|---|
| 400 |     .word isr_default   # ISR 31  | 
|---|
| 401 |  | 
|---|
| 402 | /*********************************************************** | 
|---|
| 403 | *    Exception Handler | 
|---|
| 404 | * Same code for all fatal exceptions : | 
|---|
| 405 | * Print the exception type and the values of EPC & BAR | 
|---|
| 406 | * on the TTY correspondintg to the processor PROCID, | 
|---|
| 407 | * and the user program is killed. | 
|---|
| 408 | ***********************************************************/ | 
|---|
| 409 | _cause_bp: | 
|---|
| 410 | _cause_ukn: | 
|---|
| 411 | _cause_ri: | 
|---|
| 412 | _cause_ovf: | 
|---|
| 413 | _cause_adel: | 
|---|
| 414 | _cause_ades: | 
|---|
| 415 | _cause_ibe: | 
|---|
| 416 | _cause_dbe: | 
|---|
| 417 | _cause_cpu: | 
|---|
| 418 |     mfc0    $26,    $13             # $26 <= CR  | 
|---|
| 419 |     andi    $26,    $26,    0x3C    # $26 <= _cause_index * 4  | 
|---|
| 420 |     la      $27,    mess_causes     # mess_cause table base address  | 
|---|
| 421 |     addu    $27,    $26,    $27     # pointer on the message base address  | 
|---|
| 422 |  | 
|---|
| 423 |     lw      $4,     ($27)           # $4 <= message address  | 
|---|
| 424 |     li      $5,     36              # $5 <= message length  | 
|---|
| 425 |     jal     _tty_write              # print message cause  | 
|---|
| 426 |  | 
|---|
| 427 |     la      $4,     msg_epc         # $4 <= message address  | 
|---|
| 428 |     li      $5,     8               # $5 <= message length  | 
|---|
| 429 |     jal     _tty_write              # print message EPC  | 
|---|
| 430 |  | 
|---|
| 431 |     mfc0    $4,     $14             # $4 <= EPC value  | 
|---|
| 432 |     la      $5,     itoa_buffer     # $5 <= buffer address  | 
|---|
| 433 |     addiu   $5,     $5,     2       # skip 0x prefix  | 
|---|
| 434 |     jal     _itoa_hex               # fill buffer  | 
|---|
| 435 |  | 
|---|
| 436 |     la      $4,     itoa_buffer     # $4 <= buffer address  | 
|---|
| 437 |     li      $5,     10              # $5 <= buffer length  | 
|---|
| 438 |     jal     _tty_write              # print EPC value  | 
|---|
| 439 |  | 
|---|
| 440 |     la      $4,     msg_bar         # $4 <= mesage address  | 
|---|
| 441 |     li      $5,     8               # $5 <= message length  | 
|---|
| 442 |     jal     _tty_write              # print message BAR  | 
|---|
| 443 |  | 
|---|
| 444 |     mfc0    $4,     $8              # $4 <= BAR value  | 
|---|
| 445 |     la      $5,     itoa_buffer     # $5 <= buffer address  | 
|---|
| 446 |     addiu   $5,     $5,     2       # skip 0x prefix  | 
|---|
| 447 |     jal     _itoa_hex               # fill buffer  | 
|---|
| 448 |  | 
|---|
| 449 |     la      $4,     itoa_buffer     # $4 <= mesage address  | 
|---|
| 450 |     li      $5,     10              # $5 <= message length  | 
|---|
| 451 |     jal     _tty_write              # print BAR value  | 
|---|
| 452 |  | 
|---|
| 453 |     j       _exit                   # end program  | 
|---|
| 454 |  | 
|---|
| 455 | # Exceptions Messages table (indexed by CAUSE)   | 
|---|
| 456 | mess_causes: | 
|---|
| 457 |     .word msg_ukncause | 
|---|
| 458 |     .word msg_ukncause | 
|---|
| 459 |     .word msg_ukncause | 
|---|
| 460 |     .word msg_ukncause | 
|---|
| 461 |     .word msg_adel | 
|---|
| 462 |     .word msg_ades | 
|---|
| 463 |     .word msg_ibe | 
|---|
| 464 |     .word msg_dbe | 
|---|
| 465 |     .word msg_ukncause | 
|---|
| 466 |     .word msg_bp | 
|---|
| 467 |     .word msg_ri | 
|---|
| 468 |     .word msg_cpu | 
|---|
| 469 |     .word msg_ovf | 
|---|
| 470 |     .word msg_ukncause | 
|---|
| 471 |     .word msg_ukncause | 
|---|
| 472 |     .word msg_ukncause | 
|---|
| 473 |  | 
|---|
| 474 | /***************************************************************** | 
|---|
| 475 | *    All messages | 
|---|
| 476 | * Messages length are fixed : 8 or 36 characters... | 
|---|
| 477 | *****************************************************************/ | 
|---|
| 478 | msg_bar:        .asciiz "\nBAR  = " | 
|---|
| 479 | msg_epc:        .asciiz "\nEPC  = " | 
|---|
| 480 | msg_default:    .asciiz "\n\n  !!! Default ISR  !!!           \n" | 
|---|
| 481 | msg_uknsyscall: .asciiz "\n\n  !!! Undefined System Call !!!  \n" | 
|---|
| 482 | msg_ukncause:   .asciiz "\n\nException : strange unknown cause\n" | 
|---|
| 483 | msg_adel:       .asciiz "\n\nException : illegal read address \n" | 
|---|
| 484 | msg_ades:       .asciiz "\n\nException : illegal write address\n" | 
|---|
| 485 | msg_ibe:        .asciiz "\n\nException : inst bus error       \n" | 
|---|
| 486 | msg_dbe:        .asciiz "\n\nException : data bus error       \n" | 
|---|
| 487 | msg_bp:         .asciiz "\n\nException : breakpoint           \n" | 
|---|
| 488 | msg_ri:         .asciiz "\n\nException : reserved instruction \n" | 
|---|
| 489 | msg_ovf:        .asciiz "\n\nException : arithmetic overflow  \n" | 
|---|
| 490 | msg_cpu:        .asciiz "\n\nException : illegal coproc access\n" | 
|---|
| 491 |     .align 2 | 
|---|
| 492 |  | 
|---|
| 493 |  | 
|---|
| 494 | /*************************************************************************** | 
|---|
| 495 | *        _ctx_switch | 
|---|
| 496 | *   The _ctx_switch function performs a context switch between the | 
|---|
| 497 | *   current task and another task. | 
|---|
| 498 | *   It can be used in a multi-processor architecture, with the assumption | 
|---|
| 499 | *   that the tasks are statically allocated to processors. | 
|---|
| 500 | *   The max number of processorsi is 8, and the max number of tasks is 4. | 
|---|
| 501 | *   The scheduling policy is very simple : For each processor, the task index | 
|---|
| 502 | *   is incremented,  modulo the number of tasks allocated to the processor. | 
|---|
| 503 | * | 
|---|
| 504 | *   It has no argument, and no return value. | 
|---|
| 505 | * | 
|---|
| 506 | *   It uses three global variables: | 
|---|
| 507 | *    - _current_task_array :  an array of 8 task index: | 
|---|
| 508 | *      (index of the task actually running on each processor) | 
|---|
| 509 | *    - _task_number_array : an array of 8 numbers: | 
|---|
| 510 | *      (the number of tasks allocated to each processor) | 
|---|
| 511 | *       - _task_context_array : an array of 32 task contexts: | 
|---|
| 512 | *      (at most 8 processors / each processor can run up to 4 tasks) | 
|---|
| 513 | *   A task context is an array of 64 words = 256 bytes. | 
|---|
| 514 | *   It is indexed by m = (proc_id*4 + task_id) | 
|---|
| 515 | *   It contains copies of the processor registers. | 
|---|
| 516 | *   As much as possible a register is stored at the index defined by its number | 
|---|
| 517 | *   ( for example, $8 is saved in ctx[8]). | 
|---|
| 518 | *   The exception are : | 
|---|
| 519 | *   $0 is not saved since always 0 | 
|---|
| 520 | *   $26, $27 are not saved since not used by the task | 
|---|
| 521 | * | 
|---|
| 522 | *   0*4(ctx) SR    8*4(ctx) $8    16*4(ctx) $16   24*4(ctx) $24   32*4(ctx) EPC | 
|---|
| 523 | *   1*4(ctx) $1    9*4(ctx) $9    17*4(ctx) $17   25*4(ctx) $25   33*4(ctx) CR | 
|---|
| 524 | *   2*4(ctx) $2   10*4(ctx) $10   18*4(ctx) $18   26*4(ctx) LO    34*4(ctx) reserved | 
|---|
| 525 | *   3*4(ctx) $3   11*4(ctx) $11   19*4(ctx) $19   27*4(ctx) HI    35*4(ctx) reserved | 
|---|
| 526 | *   4*4(ctx) $4   12*4(ctx) $12   20*4(ctx) $20   28*4(ctx) $28   36*4(ctx) reserved | 
|---|
| 527 | *   5*4(ctx) $5   13*4(ctx) $13   21*4(ctx) $21   29*4(ctx) $29   37*4(ctx) reserved | 
|---|
| 528 | *   6*4(ctx) $6   14*4(ctx) $14   22*4(ctx) $22   30*4(ctx) $30   38*4(ctx) reserved | 
|---|
| 529 | *   7*4(ctx) $7   15*4(ctx) $15   23*4(ctx) $23   31*4(ctx) $31   39*4(ctx) reserved | 
|---|
| 530 | * | 
|---|
| 531 | *   The return address contained in $31 is saved in the _current task context | 
|---|
| 532 | *   (in the ctx[31] slot), and the function actually returns to the address contained | 
|---|
| 533 | *   in the ctx[31] slot of the new task context. | 
|---|
| 534 | * | 
|---|
| 535 | *   Caution : This function is intended to be used with periodic interrupts. | 
|---|
| 536 | *   It can be directly called by the OS, but interrupts must be disabled before calling. | 
|---|
| 537 | ***************************************************************************************/ | 
|---|
| 538 |  | 
|---|
| 539 |     .section .ksave | 
|---|
| 540 |  | 
|---|
| 541 |     .global _task_context_array # initialised in reset.s  | 
|---|
| 542 |     .global _current_task_array # initialised in reset.s  | 
|---|
| 543 |     .global _task_number_array  # initialised in reset.s  | 
|---|
| 544 |  | 
|---|
| 545 | _task_context_array:    # 32 contexts : indexed by (proc_id*4 + task_id)  | 
|---|
| 546 |     .space  8192 | 
|---|
| 547 |  | 
|---|
| 548 | _current_task_array:    # 8 words : indexed by the proc_id  | 
|---|
| 549 |     .word   0           # _current_task_array[0] <= 0  | 
|---|
| 550 |     .word   0           # _current_task_array[1] <= 0  | 
|---|
| 551 |     .word   0           # _current_task_array[2] <= 0  | 
|---|
| 552 |     .word   0           # _current_task_array[3] <= 0  | 
|---|
| 553 |     .word   0           # _current_task_array[4] <= 0  | 
|---|
| 554 |     .word   0           # _current_task_array[5] <= 0  | 
|---|
| 555 |     .word   0           # _current_task_array[6] <= 0  | 
|---|
| 556 |     .word   0           # _current_task_array[7] <= 0  | 
|---|
| 557 |  | 
|---|
| 558 | _task_number_array:     # 8 words : indexed by the proc_id  | 
|---|
| 559 |     .word   1           # _task_number_array[0] <= 1  | 
|---|
| 560 |     .word   1           # _task_number_array[1] <= 1  | 
|---|
| 561 |     .word   1           # _task_number_array[2] <= 1  | 
|---|
| 562 |     .word   1           # _task_number_array[3] <= 1  | 
|---|
| 563 |     .word   1           # _task_number_array[4] <= 1  | 
|---|
| 564 |     .word   1           # _task_number_array[5] <= 1  | 
|---|
| 565 |     .word   1           # _task_number_array[6] <= 1  | 
|---|
| 566 |     .word   1           # _task_number_array[7] <= 1  | 
|---|
| 567 |  | 
|---|
| 568 | /***************************************************************************************/ | 
|---|
| 569 |  | 
|---|
| 570 |     .section .switch | 
|---|
| 571 |  | 
|---|
| 572 |     .global _ctx_switch # makes it an external symbol  | 
|---|
| 573 |     .align  2 | 
|---|
| 574 |  | 
|---|
| 575 | _ctx_switch: | 
|---|
| 576 |  | 
|---|
| 577 |     # test if more than one task on the processor  | 
|---|
| 578 |  | 
|---|
| 579 |     mfc0    $26,    $15,    1 | 
|---|
| 580 |     andi    $26,    $26,    0x7         # $26 <= proc_id  | 
|---|
| 581 |     sll     $26,    $26,    2           # $26 <= 4*proc_id  | 
|---|
| 582 |     la      $27,    _task_number_array  # $27 <= base address of _task_number_array  | 
|---|
| 583 |     addu    $27,    $27,    $26         # $27 <= _task_number_array + 4*proc_id  | 
|---|
| 584 |     lw      $27,    ($27)               # $27 <= task number  | 
|---|
| 585 |     addi    $26,    $27,    -1          # $26 <= _task_number - 1  | 
|---|
| 586 |     bnez    $26,    do_it               # 0 if only one task  | 
|---|
| 587 |     jr      $31                         # return  | 
|---|
| 588 |  | 
|---|
| 589 |     # save _current task context  | 
|---|
| 590 |  | 
|---|
| 591 | do_it: | 
|---|
| 592 |     mfc0    $26,    $15,    1 | 
|---|
| 593 |     andi    $26,    $26,    0x7         # $26 <= proc_id  | 
|---|
| 594 |     sll     $26,    $26,    2           # $26 <= 4*proc_id  | 
|---|
| 595 |     la      $27,    _current_task_array # $27 <= base address of _current_task_array  | 
|---|
| 596 |     addu    $27,    $27,    $26         # $27 <= _current_task_array + 4*proc_id  | 
|---|
| 597 |     lw      $26,    ($27)               # $26 <= current task index  | 
|---|
| 598 |     sll     $26,    $26,    8           # $26 <= 256*task_id  | 
|---|
| 599 |     la      $27,    _task_context_array # $27 <= base address of context array  | 
|---|
| 600 |     addu    $27,    $27,    $26         # $27 <= _task_context_array + 256*task_id  | 
|---|
| 601 |     mfc0    $26,    $15,    1 | 
|---|
| 602 |     andi    $26,    $26,    0x7         # $26 <= proc_id  | 
|---|
| 603 |     sll     $26,    $26,    10          # $26 <= 1024*proc_id  | 
|---|
| 604 |     addu    $27,    $27,    $26         # $27 <= taxk_context_array + 256*(proc_id*4 + task_id)  | 
|---|
| 605 |  | 
|---|
| 606 |     mfc0    $26,    $12         # $26 <= SR  | 
|---|
| 607 |     sw      $26,    0*4($27)    # ctx[0] <= SR  | 
|---|
| 608 |     .set noat | 
|---|
| 609 |     sw      $1,     1*4($27)    # ctx[1] <= $1  | 
|---|
| 610 |     .set at | 
|---|
| 611 |     sw      $2,     2*4($27)    # ctx[2] <= $2  | 
|---|
| 612 |     sw      $3,     3*4($27)    # ctx[3] <= $3  | 
|---|
| 613 |     sw      $4,     4*4($27)    # ctx[4] <= $4  | 
|---|
| 614 |     sw      $5,     5*4($27)    # ctx[5] <= $5  | 
|---|
| 615 |     sw      $6,     6*4($27)    # ctx[6] <= $6  | 
|---|
| 616 |     sw      $7,     7*4($27)    # ctx[7] <= $7  | 
|---|
| 617 |     sw      $8,     8*4($27)    # ctx[8] <= $8  | 
|---|
| 618 |     sw      $9,     9*4($27)    # ctx[9] <= $9  | 
|---|
| 619 |     sw      $10,    10*4($27)   # ctx[10] <= $10  | 
|---|
| 620 |     sw      $11,    11*4($27)   # ctx[11] <= $11  | 
|---|
| 621 |     sw      $12,    12*4($27)   # ctx[12] <= $12  | 
|---|
| 622 |     sw      $13,    13*4($27)   # ctx[13] <= $13  | 
|---|
| 623 |     sw      $14,    14*4($27)   # ctx[14] <= $14  | 
|---|
| 624 |     sw      $15,    15*4($27)   # ctx[15] <= $15  | 
|---|
| 625 |     sw      $16,    16*4($27)   # ctx[16] <= $16  | 
|---|
| 626 |     sw      $17,    17*4($27)   # ctx[17] <= $17  | 
|---|
| 627 |     sw      $18,    18*4($27)   # ctx[18] <= $18  | 
|---|
| 628 |     sw      $19,    19*4($27)   # ctx[19] <= $19  | 
|---|
| 629 |     sw      $20,    20*4($27)   # ctx[20] <= $20  | 
|---|
| 630 |     sw      $21,    21*4($27)   # ctx[21] <= $21  | 
|---|
| 631 |     sw      $22,    22*4($27)   # ctx[22] <= $22  | 
|---|
| 632 |     sw      $23,    23*4($27)   # ctx[23] <= $23  | 
|---|
| 633 |     sw      $24,    24*4($27)   # ctx[24] <= $24  | 
|---|
| 634 |     sw      $25,    25*4($27)   # ctx[25] <= $25  | 
|---|
| 635 |     mflo    $26 | 
|---|
| 636 |     sw      $26,    26*4($27)   # ctx[26] <= LO  | 
|---|
| 637 |     mfhi    $26 | 
|---|
| 638 |     sw      $26,    27*4($27)   # ctx[27] <= H1  | 
|---|
| 639 |     sw      $28,    28*4($27)   # ctx[28] <= $28  | 
|---|
| 640 |     sw      $29,    29*4($27)   # ctx[29] <= $29  | 
|---|
| 641 |     sw      $30,    30*4($27)   # ctx[30] <= $30  | 
|---|
| 642 |     sw      $31,    31*4($27)   # ctx[31] <= $31  | 
|---|
| 643 |     mfc0    $26,    $14 | 
|---|
| 644 |     sw      $26,    32*4($27)   # ctx[32] <= EPC  | 
|---|
| 645 |     mfc0    $26,    $13 | 
|---|
| 646 |     sw      $26,    33*4($27)   # ctx[33] <= CR  | 
|---|
| 647 |  | 
|---|
| 648 |     # select  the new task  | 
|---|
| 649 |  | 
|---|
| 650 |     mfc0    $15,    $15,    1 | 
|---|
| 651 |     andi    $15,    $15,    0x7         # $15 <= proc_id  | 
|---|
| 652 |     sll     $16,    $15,    2           # $16 <= 4*proc_id  | 
|---|
| 653 |     la      $17,    _current_task_array # $17 <= base address of _current_task_array  | 
|---|
| 654 |     addu    $17,    $17,    $16         # $17 <= _current_task_array + 4*proc_id  | 
|---|
| 655 |     lw      $18,    ($17)               # $18 <= _current task index  | 
|---|
| 656 |     la      $19,    _task_number_array  # $19 <= base address of _task_number_array  | 
|---|
| 657 |     addu    $19,    $19,    $16         # $19 <= _task_number_array + 4*proc_id  | 
|---|
| 658 |     lw      $20,    ($19)               # $20 <= max = number of tasks  | 
|---|
| 659 |     addiu   $18,    $18,    1           # $18 <= new task index  | 
|---|
| 660 |     sub     $2,     $18,    $20         # test modulo max  | 
|---|
| 661 |     bne     $2,     $0,     no_wrap | 
|---|
| 662 |     add     $18,    $0,     $0          # $18 <= new task index  | 
|---|
| 663 | no_wrap: | 
|---|
| 664 |     sw      $18,    ($17)               # update _current_task_array  | 
|---|
| 665 |  | 
|---|
| 666 |     # restore next task context  | 
|---|
| 667 |  | 
|---|
| 668 |     sll     $19,    $18,    8           # $19 <= 256*task_id  | 
|---|
| 669 |     la      $27,    _task_context_array # $27 <= base address of context array  | 
|---|
| 670 |     addu    $27,    $27,    $19         # $27 <= _task_context_array + 256*task_id  | 
|---|
| 671 |     sll     $19,    $15,    10          # $19 <= 1024*proc_id  | 
|---|
| 672 |     addu    $27,    $27,    $19         # $27 <= _task_context_array + 256*(proc_id*4 + task_id)  | 
|---|
| 673 |  | 
|---|
| 674 |     lw      $26,    0*4($27) | 
|---|
| 675 |     mtc0    $26,    $12                 # restore SR  | 
|---|
| 676 |     .set noat | 
|---|
| 677 |     lw      $1,     1*4($27)            # restore $1  | 
|---|
| 678 |     .set at | 
|---|
| 679 |     lw      $2,     2*4($27)            # restore $2  | 
|---|
| 680 |     lw      $3,     3*4($27)            # restore $3  | 
|---|
| 681 |     lw      $4,     4*4($27)            # restore $4  | 
|---|
| 682 |     lw      $5,     5*4($27)            # restore $5  | 
|---|
| 683 |     lw      $6,     6*4($27)            # restore $6  | 
|---|
| 684 |     lw      $7,     7*4($27)            # restore $7  | 
|---|
| 685 |     lw      $8,     8*4($27)            # restore $8  | 
|---|
| 686 |     lw      $9,     9*4($27)            # restore $9  | 
|---|
| 687 |     lw      $10,    10*4($27)           # restore $10  | 
|---|
| 688 |     lw      $11,    11*4($27)           # restore $11  | 
|---|
| 689 |     lw      $12,    12*4($27)           # restore $12  | 
|---|
| 690 |     lw      $13,    13*4($27)           # restore $13  | 
|---|
| 691 |     lw      $14,    14*4($27)           # restore $14  | 
|---|
| 692 |     lw      $15,    15*4($27)           # restore $15  | 
|---|
| 693 |     lw      $16,    16*4($27)           # restore $16  | 
|---|
| 694 |     lw      $17,    17*4($27)           # restore $17  | 
|---|
| 695 |     lw      $18,    18*4($27)           # restore $18  | 
|---|
| 696 |     lw      $19,    19*4($27)           # restore $19  | 
|---|
| 697 |     lw      $20,    20*4($27)           # restore $20  | 
|---|
| 698 |     lw      $21,    21*4($27)           # restore $21  | 
|---|
| 699 |     lw      $22,    22*4($27)           # restore $22  | 
|---|
| 700 |     lw      $23,    23*4($27)           # restore $23  | 
|---|
| 701 |     lw      $24,    24*4($27)           # restore $24  | 
|---|
| 702 |     lw      $25,    25*4($27)           # restore $25  | 
|---|
| 703 |     lw      $26,    26*4($27) | 
|---|
| 704 |     mtlo    $26                         # restore LO  | 
|---|
| 705 |     lw      $26,    27*4($27) | 
|---|
| 706 |     mthi    $26                         # restore HI  | 
|---|
| 707 |     lw      $28,    28*4($27)           # restore $28  | 
|---|
| 708 |     lw      $29,    29*4($27)           # restore $29  | 
|---|
| 709 |     lw      $30,    30*4($27)           # restore $30  | 
|---|
| 710 |     lw      $31,    31*4($27)           # restore $31  | 
|---|
| 711 |     lw      $26,    32*4($27) | 
|---|
| 712 |     mtc0    $26,    $14                 # restore EPC  | 
|---|
| 713 |     lw      $26,    33*4($27) | 
|---|
| 714 |     mtc0    $26,    $13                 # restore CR  | 
|---|
| 715 |  | 
|---|
| 716 |     jr      $31                         # returns to caller  | 
|---|
| 717 |  | 
|---|
| 718 | /* Local Variables: | 
|---|
| 719 |    tab-width: 4; | 
|---|
| 720 |    c-basic-offset: 4; | 
|---|
| 721 |    c-file-offsets:((innamespace . 0)(inline-open . 0)); | 
|---|
| 722 |    indent-tabs-mode: nil; | 
|---|
| 723 |    End: */ | 
|---|
| 724 |  | 
|---|
| 725 | /* vim: set filetype=asm expandtab shiftwidth=4 tabstop=4 softtabstop=4: */ | 
|---|
| 726 |  | 
|---|