1 /* 2 * PIC32 microcontroller interrupt handling code. 3 * 4 * Copyright (C) 2017, 2018 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include "mips.h" 21 #include "pic32.h" 22 #include "cpu.h" 23 24 #define IRQ_STACK_LIMIT (KSEG0_BASE + IRQ_STACK_SIZE) 25 #define IRQ_STACK_TOP (IRQ_STACK_LIMIT - 34 * 4) 26 27 .globl enable_interrupts 28 .globl handle_error_level 29 .globl init_interrupts 30 .extern exception_handler 31 .extern interrupt_handler 32 33 /* Put general routines in the text section. */ 34 35 .text 36 37 /* 38 Clear the error and exception status flags, making interrupts and exceptions 39 possible. 40 */ 41 42 handle_error_level: 43 mfc0 $t3, CP0_STATUS 44 45 /* Clear error level and exception level. */ 46 47 li $t4, ~(STATUS_ERL | STATUS_EXL) 48 and $t3, $t3, $t4 49 mtc0 $t3, CP0_STATUS 50 51 jr $ra 52 nop 53 54 /* Enable interrupts and direct interrupt requests to non-bootloader vectors. */ 55 56 enable_interrupts: 57 mfc0 $t3, CP0_STATUS 58 59 /* Clear interrupt priority bits. */ 60 61 li $t4, ~STATUS_IRQ 62 and $t3, $t3, $t4 63 64 /* Set interrupt priority. */ 65 66 ori $t3, $t3, (CPU_INT_PRIORITY << STATUS_IRQ_SHIFT) 67 68 /* CP0_STATUS &= ~STATUS_BEV (use non-bootloader vectors) */ 69 70 li $t4, ~STATUS_BEV 71 and $t3, $t3, $t4 72 73 /* Enable interrupts. */ 74 75 ori $t3, $t3, STATUS_IE 76 mtc0 $t3, CP0_STATUS 77 78 jr $ra 79 nop 80 81 /* Initialise the interrupt system parameters. */ 82 83 init_interrupts: 84 /* Clear debug mode. */ 85 86 mfc0 $t3, CP0_DEBUG 87 li $t4, ~DEBUG_DM 88 and $t3, $t3, $t4 89 mtc0 $t3, CP0_DEBUG 90 91 /* Update the exception base. */ 92 93 mfc0 $t3, CP0_STATUS 94 li $t4, STATUS_BEV /* BEV = 1 or EBASE cannot be set */ 95 or $t3, $t3, $t4 96 mtc0 $t3, CP0_STATUS 97 98 la $t3, ebase 99 mtc0 $t3, CP0_EBASE 100 101 /* Set vector spacing. */ 102 103 li $t3, 0x20 /* Must be non-zero or the CPU gets upset */ 104 mtc0 $t3, CP0_INTCTL 105 106 li $t3, CAUSE_IV /* IV = 1 (use EBASE+0x200 for interrupts) */ 107 mtc0 $t3, CP0_CAUSE 108 109 jr $ra 110 nop 111 112 113 114 /* Exception servicing, positioned at EBASE at the start of program memory. */ 115 116 .section .vectors, "a" 117 118 /* TLB error servicing. */ 119 120 ebase: 121 tlb_handler: 122 j exception_handler 123 nop 124 125 126 127 /* General exception servicing. */ 128 129 .org 0x180 130 131 exc_handler: 132 move $k0, $sp 133 move $k1, $t9 134 135 /* Switch to the IRQ stack. */ 136 137 lui $sp, %hi(IRQ_STACK_TOP) 138 ori $sp, $sp, %lo(IRQ_STACK_TOP) 139 140 /* Obtain the address directly to avoid initialising $gp here. */ 141 142 lui $t9, %hi(exception_handler) 143 ori $t9, $t9, %lo(exception_handler) 144 jr $t9 145 nop 146 147 148 149 /* Interrupt servicing. */ 150 151 .org 0x200 152 .set noat 153 154 int_handler: 155 156 /* Store affected registers from IRQ_STACK_LIMIT - 4 downwards. */ 157 158 lui $k0, %hi(IRQ_STACK_LIMIT) 159 ori $k0, $k0, %lo(IRQ_STACK_LIMIT) 160 161 .irp reg, \ 162 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 \ 163 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, \ 164 28, 29, 30, 31 165 sw $\reg, -(\reg * 4)($k0) 166 .endr 167 168 mflo $k1 169 sw $k1, -(32 * 4)($k0) 170 mfhi $k1 171 sw $k1, -(33 * 4)($k0) 172 173 /* Switch to the IRQ stack. */ 174 175 lui $sp, %hi(IRQ_STACK_TOP) 176 ori $sp, $sp, %lo(IRQ_STACK_TOP) 177 178 /* Obtain the address directly to avoid initialising $gp here. */ 179 180 lui $t9, %hi(interrupt_handler) 181 ori $t9, $t9, %lo(interrupt_handler) 182 jalr $t9 183 nop 184 185 /* Restore affected registers. */ 186 187 lw $k1, -(32 * 4)($k0) 188 mtlo $k1 189 lw $k1, -(33 * 4)($k0) 190 mthi $k1 191 192 .irp reg, \ 193 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 \ 194 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, \ 195 28, 29, 30, 31 196 lw $\reg, -(\reg * 4)($k0) 197 .endr 198 199 eret 200 nop