Better detection of concurrent ADC access.
[bertos.git] / bertos / cpu / arm / hw / switch.h
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos 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 2 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, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2008 Develer S.r.l. (http://www.develer.com/)
30  *
31  * -->
32  *
33  * \brief Kernel scheduler macros.
34  *
35  * \version $Id$
36  *
37  * \author Francesco Sacchi <batt@develer.com>
38  * \author Stefano Fedrigo <aleph@develer.com>
39  */
40
41 #ifndef CPU_ARM_HW_SWITCH_H
42 #define CPU_ARM_HW_SWITCH_H
43
44 #include <kern/proc_p.h>
45
46 /**
47  * Interrupt entry point.
48  * Needed because AT91 uses an Interrupt Controller with auto-vectoring.
49  */
50 #define SCHEDULER_IRQ_ENTRY \
51         asm volatile("sub   lr, lr, #4          \n\t"  /* Adjust LR */ \
52                      "stmfd sp!, {r0}           \n\t"  /* Save r0 */ \
53                      "stmfd sp, {sp}^           \n\t"  /* Save user SP */ \
54                      "sub   sp, sp, #4          \n\t"  /* Decrement irq SP, writeback is illegal */ \
55                      "ldmfd sp!, {r0}           \n\t"  /* Restore user SP immedately in r0 */ \
56                      "stmfd r0!, {lr}           \n\t"  /* Store system LR in user stack */ \
57                      "stmfd r0, {r1-r12,lr}^    \n\t"  /* Store registers on user stack (user LR too) */ \
58                      "sub   r0, r0, #52         \n\t"  /* Decrement r0, writeback is illegal */ \
59                      "ldmfd sp!, {r1}           \n\t"  /* Restore r0 */ \
60                      "stmfd r0!, {r1}           \n\t"  /* Store r0 in user stack too */ \
61                      "mrs   r1, spsr            \n\t"  /* Save SPSR... */ \
62                      "stmfd r0!, {r1}           \n\t"  /*  ... in user stack */ \
63                      "ldr   r1, =CurrentProcess \n\t"  /* Load in r1 &CurrentProcess->stack */ \
64                      "ldr   r1, [r1, %0]        \n\t"  \
65                      "str   r0, [r1]            \n\t"  /* Store the process SP */ \
66                      "sub   fp, sp, #4          \n\t"  /* Store the process SP */ \
67                      : /* no output */ \
68                      : "n" (offsetof(Process, stack)) \
69         )
70
71
72 #define SCHEDULER_IRQ_EXIT \
73         asm volatile("ldr   lr, =CurrentProcess \n\t"  /* Load &CurrentProcess->stack */ \
74                      "ldr   lr, [lr, %0]        \n\t"  \
75                      "ldr   lr, [lr]            \n\t"  /* Load current process SP */ \
76                      "ldr   r0, =0xFFFFF000     \n\t"  /* End of interrupt for AT91 */ \
77                      "str   r0, [r0, #0x130]    \n\t"  /* */ \
78                      "ldmfd lr!, {r0}           \n\t"  /* Pop status reg */ \
79                      "msr   spsr, r0            \n\t"  /* ... */ \
80                      "ldmfd lr, {r0-r12,lr}^    \n\t"  /* Restore user regs */ \
81                      "add   lr, lr, #56         \n\t"  /* 52 + irq link register (extracted below) */ \
82                      "stmfd sp!, {lr}           \n\t"  /* Push user stack pointer in irq stack */ \
83                      "ldmfd sp,  {sp}^          \n\t"  /* Restore user SP */ \
84                      "sub   sp, sp, #4          \n\t"  /* Align irq SP */ \
85                      "ldmdb lr, {pc}^           \n\t"  /* And return to user space (We use ldmdb cause lr is sp+4) */ \
86                      : /* no output */ \
87                      : "n" (offsetof(Process, stack))  \
88         )
89
90 #endif /* CPU_ARM_HW_SWITCH_H */