IntCortex.fth (9694B)
1 \ Cortex exception (interrupt) handlers 2 3 (( 4 Copyright (c) 2010, 2011 5 MicroProcessor Engineering 6 133 Hill Lane 7 Southampton SO15 5AF 8 England 9 10 tel: +44 (0)23 8063 1441 11 fax: +44 (0)23 8033 9691 12 net: mpe@mpeforth.com 13 tech-support@mpeforth.com 14 web: www.mpeforth.com 15 16 From North America, our telephone and fax numbers are: 17 011 44 23 8063 1441 18 011 44 23 8033 9691 19 20 21 To do 22 ===== 23 24 Change history 25 ============== 26 20110627 SFP001 Cortex M0/M1 changes. 27 )) 28 29 only forth definitions decimal 30 31 \ ============ 32 \ *! intcortex 33 \ *T Exception and Interrupt handlers 34 \ ============ 35 \ *P The file *\i{Cortex\IntCortex.fth} contains generic interrupt 36 \ ** handlers for Cortex-M0/M1/M3/M4 processors. 37 \ ** *\i{IntCortex.fth} requires *\i{Cortex\CortexDef} to be compiled 38 \ ** before the *\i{SFRxxxx} file for your particular CPU. The file 39 \ ** *\i{Cortex/StackDef.fth} provides default main task and stack 40 \ ** layouts and should be compiled from the control file or copied 41 \ ** into your control file. Default stack initialisation code is 42 \ ** provided in *\i{Cortex/StackDef.fth}. 43 44 \ *P The high-level interrupt handlers all share a common "stack 45 \ ** of stacks". On entry to the interrupt handler, Forth system 46 \ ** registers are allocated. Your initialisation code *\b{must} 47 \ ** set up R13. This is normally provided by the MPE wrapper code 48 \ ** for each exception. 49 50 \ *P In order to support exception nesting the equate *\fo{#IRQs} in the 51 \ ** control file must be set to the maximum number of nestings 52 \ ** required. 53 \ ** The equate *\fo{#IRQs} is used to calculate the size of the 54 \ ** required exception stack, together with the equate *\fo{#SVCs}. 55 \ ** in the control file. 56 57 \ *P Each interrupt has its own *\fo{USER} area. No user variables 58 \ ** are initialised except for *\fo{S0} and *\fo{R0} in SVC 59 \ ** handlers. 60 61 \ *P It is assumed that the banked stack pointers have 62 \ ** already been set up by the hardware initialisation code. 63 64 \ *P It is implicit throughout the code that the three 65 \ ** system registers UP, PSP, RSP are always set so that: 66 \ *C UP > PSP > RSP 67 \ *P Because of this layout, data stack underflows may corrupt 68 \ ** the first part of the *\fo{USER} area. You have been warned. 69 \ ** During testing, it may be as well to set the equate 70 \ ** *\fo{SP-GUARD} to 2 or 3 in your control file to leave a few 71 \ ** guard cells on the data stack. 72 73 74 \ ************************************ 75 \ *S Cortex-M3 NVIC Exception handlers 76 \ ************************************ 77 \ *P This section is not a treatise on the Nested Vectored 78 \ ** Interrupt Controller. These words provide a fairly basic 79 \ ** set of tools for using the NVIC, which is fully 80 \ ** documented in the Cortex-M3 Technical Reference Manual 81 \ ** (ARM DDI 0337)from *\i{www.arm.com}. 82 83 \ *P This code requires *\i{Kernel62.fth} and the equate 84 \ ** *\fo{COLDCHAIN?} must be set non-zero in the control file. 85 \ ** The NVIC address and register offsets are defined in the 86 \ ** file *\i{Cortex/CortexDef.fth}. 87 88 \ *P The MPE code works in terms of vector numbers, which are 89 \ ** 16 greater than the external interrupt numbers. 90 91 Not-M0/M1? [if] 92 PROC ExcEntry \ -- 93 \ *G This is the template code for M3+ vectored exception handlers. 94 \ --- CPU has saved ---- 95 \ xPSR PC LR R12 R3 R2 R1 R0 96 \ --- save state --- 97 push { r4-r11, r14 } \ registers not saved by core + link 98 sub rsp, rsp, # up-size sp-size + \ make space for USER area and data stack 99 100 \ --- set up Forth --- 101 add up, rsp, # sp-size \ USER area at top 102 sub psp, up, # sp-guard cells \ generate new PSP 103 sub r4, psp, # tos-cached? cells \ generate new S0 104 str r4, [ up, # s0-offset ] \ that is compatible with SP! 105 str rsp, [ up, # r0-offset ] \ set R0 106 \ --- call high level handler --- 107 l: ExcCall 108 bl ' noop \ call the high level handler 109 \ --- restore state --- 110 add rsp, rsp, # up-size sp-size + \ remove space for USER area and data stack 111 pop { r4-r11, pc } \ restore and exit 112 end-code 113 chere ExcEntry - equ /ExcEntry \ size of template 114 ExcCall ExcEntry - equ /ExcCall \ offset to call instruction 115 [else] 116 sp-size 3 and [if] cr ." bad SP-SIZE" abort [then] 117 sp-size 2 rshift equ sp-cells 118 up-size 3 and [if] cr ." bad UP-SIZE" abort [then] 119 up-size 2 rshift equ up-cells 120 121 SP-SIZE #256 u< 0= UP-SIZE #256 u< 0= or equ LargeISR? \ -- flag 122 \ *G The interrupt is often larger than 256 bytes, which requires 123 \ ** larger ISR entry code. 124 125 LargeISR? [if] 126 PROC ExcEntry \ -- 127 \ *G This is the template code for M0/M1 vectored exception handlers 128 \ ** with a large ISR frame. 129 \ --- CPU has saved ---- 130 \ xPSR PC LR R12 R3 R2 R1 R0 131 \ --- save state --- 132 push { r4-r7, r14 } \ registers not saved by core + link 133 mov r0, r8 134 mov r1, r9 135 mov r2, r10 136 mov r3, r11 137 push { r0-r3 } 138 139 \ --- set up Forth --- 140 \ calculate the offsets 141 mov .s r0, # up-cells \ R0 = UP-SIZE 142 lsl .s r0, r0, # 2 143 mov .s r2, # sp-cells \ R2 = SP-SIZE 144 lsl .s r2, r2, # 2 145 add .s r3, r0, r2 \ R3 = SP-SIZE + UP-SIZE 146 \ set new RSP 147 mov r1, rsp 148 sub .s r1, r3 149 mov rsp, r1 \ RSP = RSP - SP-SIZE - UP-SIZE 150 push { r3 } \ how much we dropped the stack by 151 \ set new UP 152 add .s r1, r1, r2 \ UP = RSP + SP-SIZE 153 mov up, r1 \ will need R1 later 154 \ set new PSP 155 mov psp, r1 \ generate new PSP 156 sub .s psp, # sp-guard cells 157 \ set new S0 and R0 user vars 158 sub .s r4, psp, # tos-cached? cells \ generate new S0 159 str r4, [ r1, # s0-offset ] \ that is compatible with SP! 160 mov r0, rsp 161 str r0, [ r1, # r0-offset ] \ set R0 162 \ --- call high level handler --- 163 l: ExcCall 164 bl ' noop \ call the high level handler 165 \ --- restore state --- 166 \ restore RSP 167 pop { r3 } \ amount by which stack was dropped 168 mov r1, rsp 169 add .s r1, r3 170 mov rsp, r1 171 \ restore regs 172 pop { r0-r3 } 173 mov r8, r0 174 mov r9, r1 175 mov r10, r2 176 mov r11, r3 177 pop { r4-r7, pc } \ restore and exit 178 end-code 179 chere ExcEntry - equ /ExcEntry \ size of template 180 ExcCall ExcEntry - equ /ExcCall \ offset to call instruction 181 [else] 182 PROC ExcEntry \ -- 183 \ *G This is the template code for M0/M1 vectored exception handlers 184 \ ** with a small ISR frame. 185 \ --- CPU has saved ---- 186 \ xPSR PC LR R12 R3 R2 R1 R0 187 \ --- save state --- 188 push { r4-r7, r14 } \ registers not saved by core + link 189 mov r0, r8 190 mov r1, r9 191 mov r2, r10 192 mov r3, r11 193 push { r0-r3 } 194 195 \ --- set up Forth --- 196 \ set new UP 197 mov r1, rsp 198 sub .s r1, # UP-SIZE 199 mov up, r1 \ will need R1 later 200 \ set new RSP 201 mov .s r2, r1 202 sub .s r2, # SP-SIZE 203 mov rsp, r2 \ RSP = RSP - SP-SIZE - UP-SIZE 204 \ set new PSP 205 mov psp, r1 \ generate new PSP = UP - abit 206 sub .s psp, # sp-guard cells 207 \ set new S0 and R0 user vars 208 sub .s r4, psp, # tos-cached? cells \ generate new S0 209 str r4, [ r1, # s0-offset ] \ that is compatible with SP! 210 mov r0, rsp 211 str r0, [ r1, # r0-offset ] \ set R0 212 \ --- call high level handler --- 213 l: ExcCall 214 bl ' noop \ call the high level handler 215 \ --- restore state --- 216 \ restore RSP 217 mov r1, rsp 218 add .s r1, # SP-SIZE 219 add .s r1, # UP-SIZE 220 mov rsp, r1 221 \ restore regs 222 pop { r0-r3 } 223 mov r8, r0 224 mov r9, r1 225 mov r10, r2 226 mov r11, r3 227 pop { r4-r7, pc } \ restore and exit 228 end-code 229 chere ExcEntry - equ /ExcEntry \ size of template 230 ExcCall ExcEntry - equ /ExcCall \ offset to call instruction 231 [then] \ LargeISR? 232 233 [then] \ Not-M0/M1? 234 235 interpreter 236 : EXC: \ xt vec# -- ; -- isr 237 \ *G Creates an exception handler that runs the given Forth word. 238 \ ** At run time the entry point of the ISR is returned. Use in 239 \ ** the form: 240 \ *C ' <action> <vec#> EXC: <actionISR> 241 \ *P The example below will define a handler for the SysTick 242 \ ** interrupt/exception that runs the Forth word *\fo{SysTickHandler}. 243 \ *C ' SysTickHandler #15 EXC: SysTickEntry 244 swap align chere /ExcEntry callot \ -- vec# xt isr ; reserve space 245 ExcEntry over /ExcEntry move \ copy template 246 tuck /ExcCall + !call \ -- vec# isr ; form call instruction 247 tuck swap setExcVec 248 label \ returns entry point 249 ; 250 target 251 252 : int>bit \ int# -- mask offset 253 \ Convert an interrupt number into its bit mask and ofset 254 \ into an array of 32 bit registers. 255 dup $1F and 1 swap lshift 256 swap 5 rshift 2 lshift 257 ; 258 259 : EnInt \ vec# -- 260 \ *G Enable the requested NVIC interrupt source. 261 \ ** NVIC interrupts have vector numbers in the range 16..255. 262 dup #15 u> if 263 #16 - int>bit _SCS + nvSetEnR0 + ! 264 exit 265 endif 266 drop 267 ; 268 269 : DisInt \ vec# -- 270 \ *G Disable the requested NVIC interrupt source. 271 \ ** NVIC interrupts have vector numbers in the range 16..255. 272 dup #15 u> if 273 #16 - int>bit _SCS + nvClrEnR0 + ! 274 exit 275 endif 276 drop 277 ; 278 279 : SetPri \ pri vec# 280 \ *G Set the priority of the given NVIC interrupt source. 281 \ ** NVIC interrupts have vector numbers in the range 16..255. 282 \ ** The priority numbers are in the range 0..255, where 0 is 283 \ ** the highest priority. The number of bits actually used 284 \ ** is implementation dependent, but unused bits are always 285 \ ** the low-order bits. Hence, using $10, $20 and so on is 286 \ ** fairly portable. 287 dup #15 u> if 288 16 - _SCS + nvPR0 + c! exit 289 endif 290 drop 291 ; 292 293 : SWINT \ vec# -- 294 \ *G Generate interrupt from software. 295 dup #15 u> if 296 #16 - int>bit _SCS + nvSetPendR0 + ! 297 exit 298 endif 299 drop 300 ; 301 302 303 \ ====== 304 \ *> ### 305 \ ====== 306