1 /*****************************************************************************
2 * Product: QK port to ARM7-9, GNU-ARM assembler
3 * Last Updated for Version: 6.3.6
4 * Date of the Last Update: 2018-10-29
6 * Q u a n t u m L e a P s
7 * ------------------------
8 * Modern Embedded Software
10 * Copyright (C) Quantum Leaps, LLC. All rights reserved.
12 * This program is open source software: you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License as published
14 * by the Free Software Foundation, either version 3 of the License, or
15 * (at your option) any later version.
17 * Alternatively, this program may be distributed and modified under the
18 * terms of Quantum Leaps commercial licenses, which expressly supersede
19 * the GNU General Public License and are specifically designed for
20 * licensees interested in retaining the proprietary status of their code.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program. If not, see <http://www.gnu.org/licenses/>.
30 * Contact information:
31 * https://www.state-machine.com/licensing
32 * mailto:info@state-machine.com
33 *****************************************************************************/
35 .equ NO_IRQ, 0x80 /* mask to disable interrupts (IRQ) */
36 .equ NO_FIQ, 0x40 /* mask to disable interrupts (FIQ) */
41 /* NOTE: keep in synch with the QK_Attr struct in "qk.h" !!! */
47 /* use the special section (.text.fastcode), to enable fine-tuning
48 * of the placement of this section inside the linker script
50 .section .text.fastcode
52 /*****************************************************************************
53 * unsigned int QF_int_disable_SYS(void);
55 .global QF_int_disable_SYS
56 .func QF_int_disable_SYS
58 MRS r0,cpsr /* get the original CPSR in r0 to return */
59 MSR cpsr_c,#(SYS_MODE | NO_IRQ) /* disable IRQ only, FIQ enabled! */
60 BX lr /* return the original CPSR in r0 */
62 .size QF_int_disable_SYS, . - QF_int_disable_SYS
66 /*****************************************************************************
67 * void QF_int_enable_SYS(unsigned int key);
69 .global QF_int_enable_SYS
70 .func QF_int_enable_SYS
72 MSR cpsr_c,r0 /* restore the original CPSR from r0 */
73 BX lr /* return to ARM or THUMB */
75 .size QF_int_enable_SYS, . - QF_int_enable_SYS
79 /*****************************************************************************
85 BX lr /* return to ARM or THUMB */
87 .size QK_init, . - QK_init
91 /*****************************************************************************
99 MOV r13,r0 /* save r0 in r13_IRQ */
100 SUB r0,lr,#4 /* put return address in r0_SYS */
101 MOV lr,r1 /* save r1 in r14_IRQ (lr) */
102 MRS r1,spsr /* put the SPSR in r1_SYS */
104 MSR cpsr_c,#(SYS_MODE | NO_IRQ) /* SYSTEM, no IRQ, but FIQ enabled! */
105 STMFD sp!,{r0,r1} /* save SPSR and PC on SYS stack */
106 STMFD sp!,{r2-r3,r12,lr} /* save APCS-clobbered regs on SYS stack */
107 MOV r0,sp /* make the sp_SYS visible to IRQ mode */
108 SUB sp,sp,#(2*4) /* make room for stacking (r0_SYS, r1_SYS) */
110 MSR cpsr_c,#(IRQ_MODE | NO_IRQ) /* IRQ mode, IRQ disabled */
111 STMFD r0!,{r13,r14} /* finish saving the context (r0_SYS,r1_SYS)*/
113 MSR cpsr_c,#(SYS_MODE | NO_IRQ) /* SYSTEM mode, IRQ disabled */
116 LDR r0,=QK_attr_ /* load address in already saved r0 */
117 LDRB r12,[r0,#QK_INT_NEST] /* load QK_attr_.intNest into saved r12 */
118 ADD r12,r12,#1 /* increment the nesting level */
119 STRB r12,[r0,#QK_INT_NEST] /* store the value in QK_attr_.intNest */
121 /* MSR cpsr_c,#(SYS_MODE | NO_IRQ) ; enable FIQ
122 * NOTE: BSP_irq might re-enable IRQ interrupts (the FIQ is enabled
123 * already), if IRQs are prioritized by the interrupt controller.
126 MOV lr,pc /* copy the return address to link register */
127 BX r12 /* call the C IRQ-handler (ARM/THUMB) */
129 MSR cpsr_c,#(SYS_MODE | NO_IRQ) /* make sure IRQs are disabled */
130 LDR r0,=QK_attr_ /* load address */
131 LDRB r12,[r0,#QK_INT_NEST] /* load QK_attr_.intNest into saved r12 */
132 SUBS r12,r12,#1 /* decrement the nesting level */
133 STRB r12,[r0,#QK_INT_NEST] /* store the value in QK_attr_.intNest */
134 BNE QK_irq_exit /* branch if interrupt nesting not zero */
137 MOV lr,pc /* copy the return address to link register */
138 BX r12 /* call QK_sched_ (ARM/THUMB) */
139 CMP r0,#0 /* check the returned priority */
140 BEQ QK_irq_exit /* branch if priority zero */
142 LDR r12,=QK_activate_
143 MOV lr,pc /* copy the return address to link register */
144 BX r12 /* call QK_activate_ (ARM/THUMB) */
147 /* IRQ exit {{{ */ /* IRQ/FIQ disabled--return from scheduler */
148 MOV r0,sp /* make sp_SYS visible to IRQ mode */
149 ADD sp,sp,#(8*4) /* fake unstacking 8 registers from sp_SYS */
151 MSR cpsr_c,#(IRQ_MODE | NO_IRQ) /* IRQ mode, IRQ disabled */
152 MOV sp,r0 /* copy sp_SYS to sp_IRQ */
153 LDR r0,[sp,#(7*4)] /* load the saved SPSR from the stack */
154 MSR spsr_cxsf,r0 /* copy it into spsr_IRQ */
156 LDMFD sp,{r0-r3,r12,lr}^ /* unstack all saved USER/SYSTEM registers */
157 NOP /* can't access banked reg immediately */
158 LDR lr,[sp,#(6*4)] /* load return address from the SYS stack */
159 MOVS pc,lr /* return restoring CPSR from SPSR */
162 .size QK_irq, . - QK_irq
166 /*****************************************************************************
167 * void QF_reset(void);
175 .size QF_reset, . - QF_reset
178 /*****************************************************************************
179 * void QF_undef(void);
187 .size QF_undef, . - QF_undef
190 /*****************************************************************************
199 .size QF_swi, . - QF_swi
202 /*****************************************************************************
203 * void QF_pAbort(void);
209 LDR r0,=Csting_pAbort
211 .size QF_pAbort, . - QF_pAbort
214 /*****************************************************************************
215 * void QF_dAbort(void);
221 LDR r0,=Csting_dAbort
223 .size QF_dAbort, . - QF_dAbort
226 /*****************************************************************************
227 * void QF_reserved(void);
233 LDR r0,=Csting_reserved
235 .size QF_reserved, . - QF_reserved
238 /*****************************************************************************
239 * void QF_fiq_dummy(void);
247 .size QF_fiq_dummy, . - QF_fiq_dummy
250 /*****************************************************************************
251 * void QF_except(void);
257 /* r0 is set to the string with the exception name */
258 SUB r1,lr,#4 /* set line number to the exception address */
259 MSR cpsr_c,#(SYS_MODE | NO_IRQ | NO_FIQ) /* SYSTEM,IRQ/FIQ disabled */
261 MOV lr,pc /* store the return address */
262 BX r12 /* call the assertion-handler (ARM/THUMB) */
263 /* the assertion handler should not return, but in case it does
264 * hang up the machine in this endless loop
268 Csting_reset: .string "Reset"
269 Csting_undef: .string "Undefined"
270 Csting_swi: .string "Software Int"
271 Csting_pAbort: .string "Prefetch Abort"
272 Csting_dAbort: .string "Data Abort"
273 Csting_reserved: .string "Reserved"
274 Csting_fiq: .string "FIQ dummy"
276 .size QF_except, . - QF_except