1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
|
/****************************************************************************
* arch/avr/src/avr32/up_exceptions.S
*
* Copyright (C) 2010 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <arch/avr32/avr32.h>
#include <arch/irq.h>
/****************************************************************************
* External Symbols
****************************************************************************/
.global avr32_int0irqno /* Returns IRQ number of INT0 event */
.global avr32_int1irqno /* Returns IRQ number of INT1 event */
.global avr32_int2irqno /* Returns IRQ number of INT2 event */
.global avr32_int3irqno /* Returns IRQ number of INT3 event */
.global up_doirq /* Dispatch an IRQ */
.global up_fullcontextrestore /* Restore new task contex */
/****************************************************************************
* Macros
****************************************************************************/
/* Exception entry logic. On entry, thee context save area looks like: */
/* xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx SR PC */
/* ^ ^+2*4 */
/* Upon joining common logic, the context save are will look like: */
/* xx xx xx xx xx xx xx xx xx xx xx xx xx xx 10 SR PC */
/* ^ ^+3*4 */
/* and r10 will hold the exception's IRQ number */
.macro HANDLER, label, irqno
\label:
st.w --sp, r10
mov r10, \irqno
rjmp avr32_xcptcommon /* FIXME!!! Need IRQ in a register */
.endm
/****************************************************************************
* Exception Vector Table
****************************************************************************/
/* The Exception Vector Base Address (EVBA) register will contain "a */
/* pointer to the exception routines. All exception routines start at this */
/* address, or at a defined offset relative to the address. Special */
/* alignment requirements may apply for EVBA, depending on the */
/* implementation of the interrupt controller." */
/* REVISIT: This alignment requirement may be different on other AVR32s */
.text
.balign 0x200
.global vectortab
.type vectortab, @function
vectortab:
lda.w pc, avr32_unrec /* EVBA+0x00 Unrecoverable exception */
lda.w pc, avr32_tlbmult /* EVBA+0x04 TLB multiple hit */
lda.w pc, avr32_busdata /* EVBA+0x08 Bus error data fetch */
lda.w pc, avr32_businst /* EVBA+0x0c Bus error instr fetch */
lda.w pc, avr32_nmi /* EVBA+0x10 NMI */
lda.w pc, avr32_instaddr /* EVBA+0x14 Instruction Address */
lda.w pc, avr32_itlbrot /* EVBA+0x18 ITLB Protection */
lda.w pc, avr32_bp /* EVBA+0x1c Breakpoint */
lda.w pc, avr32_invinst /* EVBA+0x20 Illegal Opcode */
lda.w pc, avr32_unimpinst /* EVBA+0x24 Unimplemented instruction */
lda.w pc, avr32_priv /* EVBA+0x28 Privilege violation */
lda.w pc, avr32_fp /* EVBA+0x2c Floating-point */
lda.w pc, avr32_cop /* EVBA+0x30 Coprocessor absent */
lda.w pc, avr32_rddata /* EVBA+0x34 Data Address (Read) */
lda.w pc, avr32_wrdata /* EVBA+0x38 Data Address (Write) */
lda.w pc, avr32_tddtlbprot /* EVBA+0x3c DTLB Protection (Read) */
lda.w pc, avr32_wrdtlbprot /* EVBA+0x40 DTLB Protection (Write) */
lda.w pc, avr32_dltbmod /* EVBA+0x44 DTLB Modified */
.rept 2
lda.w pc, avr32_badvector /* EVBA+0x48-0x4c No such vector */
.endr
lda.w pc, avr32_itlbmiss /* EVBA+0x50 ITLB Miss */
.rept 3
lda.w pc, avr32_badvector /* EVBA+0x54-0x5c No such vector */
.endr
lda.w pc, avr32_rddtlb /* EVBA+0x60 DTLB Miss (Read) */
.rept 3
lda.w pc, avr32_badvector /* EVBA+0x64-0x6c No such vector */
.endr
lda.w pc, avr32_wrdtlb /* EVBA+0x70 DTLB Miss (Write) */
.rept (3+4*8)
lda.w pc, avr32_badvector /* EVBA+0x74-0xfc No such vector */
.endr
lda.w pc, avr32_super /* EVBA+0x100 Supervisor call */
/****************************************************************************
* Interrupts
****************************************************************************/
/* The interrupt controller must provide an address that is relative to the */
/* the EVBA so it is natural to define these interrupt vectors just after */
/* the exception table. On entry to each interrupt handler, R8-R12, LR, PC */
/* and SR have already been pushed onto the system stack by the MCU. */
/* */
/* An interrupt may disappear while it is being fetched by the CPU and, */
/* hence spurious interrupt may result. */
.balign 4
.global avr32_int0
avr32_int0:
mov r12, 0 /* r12=interrupt level 0 */
rjmp avr32_intcommon /* Jump to common interrupt handling logic */
.balign 4
.global avr32_int1
avr32_int1:
mov r12, 1 /* r12=interrupt level 1 */
rjmp avr32_intcommon /* Jump to common interrupt handling logic */
.balign 4
.global avr32_int2
avr32_int2:
mov r12, 2 /* r12=interrupt level 2 */
rjmp avr32_intcommon /* Jump to common interrupt handling logic */
.balign 4
.global avr32_int3
avr32_int3:
mov r12, 3 /* r12=interrupt level 3 */
/* Common interrupt handling logic. R12 holds the interrupt level index */
avr32_intcommon:
mcall .Lavr32_intirqno /* Get the IRQ number of the int0 event */
cp.w r12, 0 /* Negative returned if spurious interrupt */
brge avr32_common /* Jump to the common xcptn handling logic */
rete /* Ignore spurious interrupt */
.Lavr32_intirqno:
.word avr32_intirqno
/****************************************************************************
* Exception Vector Handlers
****************************************************************************/
/* Exception Handlers: */
/* On entry to each, the context save area looks like this: */
/* xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx SR PC */
/* ^ ^+2*4 */
HANDLER avr32_unrec, AVR32_IRQ_UNREC /* Unrecoverable xcptn */
HANDLER avr32_tlbmult, AVR32_IRQ_TLBMULT /* TLB multiple hit */
HANDLER avr32_busdata, AVR32_IRQ_BUSDATA /* Bus error data fetch */
HANDLER avr32_businst, AVR32_IRQ_BUSINST /* Bus err instr fetch */
HANDLER avr32_nmi, AVR32_IRQ_NMI /* NMI */
HANDLER avr32_instaddr, AVR32_IRQ_INSTADDR /* Instruction Address */
HANDLER avr32_itlbrot, AVR32_IRQ_ITLBPROT /* ITLB Protection */
HANDLER avr32_bp, AVR32_IRQ_BP /* Breakpoint */
HANDLER avr32_invinst, AVR32_IRQ_INVINST /* Illegal Opcode */
HANDLER avr32_unimpinst, AVR32_IRQ_UNIMPINST /* Unimplemented intsr */
HANDLER avr32_priv, AVR32_IRQ_PRIV /* Privilege violation */
HANDLER avr32_fp, AVR32_IRQ_FP /* Floating-point */
HANDLER avr32_cop, AVR32_IRQ_COP /* Coprocessor absent */
HANDLER avr32_rddata, AVR32_IRQ_RDDATA /* Data Address (RD) */
HANDLER avr32_wrdata, AVR32_IRQ_WRDATA /* Data Address (WR) */
HANDLER avr32_tddtlbprot, AVR32_IRQ_RDDTLBPROT /* DTLB Protection (RD) */
HANDLER avr32_wrdtlbprot, AVR32_IRQ_WRDTLBPROT /* DTLB Protection (WR) */
HANDLER avr32_dltbmod, AVR32_IRQ_DLTBMOD /* DTLB Modified */
HANDLER avr32_itlbmiss, AVR32_IRQ_ITLBMISS /* ITLB Miss */
HANDLER avr32_rddtlb, AVR32_IRQ_RDDTLB /* DTLB Miss (RD) */
HANDLER avr32_wrdtlb, AVR32_IRQ_WRDTLB /* DTLB Miss (WR) */
HANDLER avr32_super, AVR32_IRQ_SUPER /* Supervisor call */
HANDLER avr32_badvector, AVR32_IRQ_BADVECTOR /* No such vector */
/* Common exception handling logic. Unlike the interrupt handlers, the */
/* exception handlers do not save R8-R12, and LR on the stack. Only the PC */
/* and SR have been pushed onto the system stack by the MCU. The following */
/* logic creates a common stack frame for exception handlers prior to */
/* joining to the common interrupt/exception logic below. */
/* */
/* The context save area looks like this on entry to the HANDLER above. */
/* xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx SR PC */
/* ^ ^+2*4 */
/* Upon joining common logic here, the context save are will loke: */
/* xx xx xx xx xx xx xx xx xx xx xx xx xx xx 10 SR PC */
/* ^ ^+3*4 */
/* and r10 will hold the exception's IRQ number */
/* */
/* either (1) non-time-critical, or (2) fatal. Obvious, that would not be */
/* the case if TLB missing handling is required. Such time-critical vector */
/* handling should be handled differently. */
avr32_xcptcommon:
/* Save r10-r12, lr on the stack: */
/* xx xx xx xx xx xx xx xx xx xx xx LR 12 11 10 SR PC */
/* ^ ^+4*4 ^+6*4 */
stm --sp, r11-r12, lr
/* Move SR and PC into the expected position: */
/* xx xx xx xx xx xx xx xx xx SR PC LI 12 11 10 SR PC */
/* ^ ^+8*4 */
ld.w r12, sp[4*4]
ld.w r11, sp[5*4]
stm --sp, r11-r12
/* Save r8 and r8: */
/* xx xx xx xx xx xx xx xx xx SR PC LI 12 11 10 SR PC */
/* ^ ^+6*4 ^+8*4 */
st.w sp[6*4], r9
st.w sp[7*4], r8
/* Move the IRQ number in r12 and fall through to the common event handling */
/* logic. */
mov r12, r10
/****************************************************************************
* Common Event Handling Logic
****************************************************************************/
/* After this point, logic to manage interrupts and exceptions is */
/* equivalent. Here we have: */
/* */
/* R8-R12, LR, SR, and the PC on the stack. */
/* R12 holds the IRQ number to be dispatched. */
/* */
/* The context save area looks like this: */
/* xx xx xx xx xx xx xx xx xx SR PC LR 12 11 10 09 08 */
/* ^ ^+8*4 */
/* This function will finish construction of the register save structure */
/* and call the IRQ dispatching logic. */
avr32_common:
/* Disable interrupts in the current SR. This is necessary because the */
/* AVR32 permits nested interrupts (if they are of higher priority). */
/* We can support nested interrupts without some effort because: */
/* - The global variable current_regs permits only one interrupt, */
/* - If CONFIG_ARCH_INTERRUPTSTACK is defined, then there is a single */
/* interrupt stack, and */
/* - Probably other things. */
ssrf AVR32_SR_GM_SHIFT
/* Save the SP (as it was before the interrupt) in the conext save */
/* structure. */
/* xx xx xx xx xx xx xx xx SP SR PC LR 12 11 10 09 08 */
/* ^sp */
mov r8, sp
sub r8, -8*4
st.w --sp, r8
/* Saving R0-R7 is all that is left to complete the context save. */
/* 07 06 05 04 03 02 01 00 SP SR PC LR 12 11 10 09 08 */
/* ^sp */
stm --sp, r0-r7
/* Now call up_doirq passing the IRQ number in r12 and the base address */
/* of the register context save area in r11. */
mov r11, sp
/* Switch to the interrrupt stack if so configured. Move the current */
/* stack pointer into a preserved register (r7) and set the interrupt */
/* stack pointer. */
#if CONFIG_ARCH_INTERRUPTSTACK > 3
mov r7, sp
lddpc sp, .Linstackbaseptr
#endif
/* Call up_doirq with r12=IRQ number and r11=register save area */
mcall .Ldoirqptr
/* Restore the user stack pointer. */
/* 07 06 05 04 03 02 01 00 SP SR PC LR 12 11 10 09 08 */
/* ^sp */
#if CONFIG_ARCH_INTERRUPTSTACK > 3
mov sp, r7
#endif
/* On return, r12 will hold the new address of the register context */
/* save area. On an interrupt contex switch, this will (1) not be the */
/* same as the value of r12 passed to up_doirq(), and (2) may not */
/* reside on a stack. */
cp.w sp, r12
brne 1f
/* No context switch... do the simple return. First, restore r0-r7. */
/* xx xx xx xx xx xx xx xx SP SR PC LR 12 11 10 09 08 */
/* ^sp */
ldm sp++, r0-r7
/* Skip over the saved stack pointer and return from the interrupt. */
/* xx xx xx xx xx xx xx xx xx SR PC LR 12 11 10 09 08 */
/* ^sp */
sub sp, -4
rete
/* Context switch... jump to up_fullcontestrestor with r12=address of */
/* the task context to restore. */
1:
lddpc pc, .Lfullcontextrestoreptr
.Ldoirqptr:
.word up_doirq
.Lfullcontextrestoreptr:
.word up_fullcontextrestore
#if CONFIG_ARCH_INTERRUPTSTACK > 3
.Linstackbaseptr:
.word .Lintstackbase
#endif
.size vectortab, .-vectortab
/************************************************************************************
* Name: up_interruptstack
************************************************************************************/
#if CONFIG_ARCH_INTERRUPTSTACK > 3
.bss
.align 4
.globl up_interruptstack
.type up_interruptstack, object
up_interruptstack:
.skip (CONFIG_ARCH_INTERRUPTSTACK & ~3)
.Lintstackbase:
.size up_interruptstack, .-up_interruptstack
#endif
.end
|