2 * FreeRTOS Kernel V10.4.1
3 * Copyright (C) 2020 Synopsys, Inc. or its affiliates. All Rights Reserved.
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
6 * this software and associated documentation files (the "Software"), to deal in
7 * the Software without restriction, including without limitation the rights to
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 * the Software, and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 * https://www.FreeRTOS.org
23 * https://github.com/FreeRTOS
30 * \ingroup OS_FREERTOS
31 * \brief freertos support for arc processor
32 * like task dispatcher, interrupt handler
34 /** @cond OS_FREERTOS_ASM_ARC_SUPPORT */
37 * core-dependent part in assemble language (for arc)
41 #include "arc/arc_asm_common.h"
52 * the pre-conditions of this routine are task context, CPU is
53 * locked, dispatch is enabled.
55 SAVE_NONSCRATCH_REGS /* save callee save registers */
57 PUSH r1 /* save return address */
61 /* return routine when task dispatch happened in task context */
63 RESTORE_NONSCRATCH_REGS /* recover registers */
69 .global start_dispatch
73 * this routine is called in the non-task context during the startup of the kernel
74 * , and all the interrupts are locked.
76 * when the dispatcher is called, the cpu is locked, no nest exception (CPU exception/interrupt).
77 * In target_initialize, all interrupt priority mask should be cleared, cpu should be
78 * locked, the interrupts outside the kernel such as fiq can be
83 st r0, [exc_nest_count]
89 ld r1, [ulCriticalNesting]
90 PUSH r1 /* save critical nesting */
91 st sp, [r0] /* save stack pointer of current task, r0->pxCurrentTCB */
92 jl vTaskSwitchContext /* change the value of pxCurrentTCB */
94 * before dispatcher is called, task context | cpu locked | dispatch enabled
95 * should be satisfied. In this routine, the processor will jump
96 * into the entry of next to run task
98 * i.e. kernel mode, IRQ disabled, dispatch enabled
101 ld r1, [pxCurrentTCB]
102 ld sp, [r1] /* recover task stack */
103 #if ARC_FEATURE_STACK_CHECK
104 #if ARC_FEATURE_SEC_PRESENT
105 lr r0, [AUX_SEC_STAT]
106 bclr r0, r0, AUX_SEC_STAT_BIT_SSC
109 lr r0, [AUX_STATUS32]
110 bclr r0, r0, AUX_STATUS_BIT_SC
113 jl vPortSetStackCheck
114 #if ARC_FEATURE_SEC_PRESENT
115 lr r0, [AUX_SEC_STAT]
116 bset r0, r0, AUX_SEC_STAT_BIT_SSC
119 lr r0, [AUX_STATUS32]
120 bset r0, r0, AUX_STATUS_BIT_SC
124 POP r0 /* get critical nesting */
125 st r0, [ulCriticalNesting]
126 POP r0 /* get return address */
130 * task startup routine
137 seti /* unlock cpu */
138 mov blink, vPortEndTask /* set return address */
139 POP r1 /* get task function body */
140 POP r0 /* get task parameters */
143 /****** exceptions and interrupts handing ******/
144 /****** entry for exception handling ******/
145 .global exc_entry_cpu
152 mov r3, sp /* as exception handler's para(p_excinfo) */
154 ld r0, [exc_nest_count]
156 st r1, [exc_nest_count]
157 brne r0, 0, exc_handler_1
158 /* change to exception stack if interrupt happened in task context */
165 mov r1, exc_int_handler_table
169 jl [r2] /* !!!!jump to exception handler where interrupts are not allowed! */
171 /* interrupts are not allowed */
174 mov r1, exc_nest_count
178 brne r0, 0, ret_exc_1 /* nest exception case */
179 lr r1, [AUX_IRQ_ACT] /* nest interrupt case */
180 brne r1, 0, ret_exc_1
182 ld r0, [context_switch_reqflg]
183 brne r0, 0, ret_exc_2
184 ret_exc_1: /* return from non-task context, interrupts or exceptions are nested */
189 /* there is a dispatch request */
191 /* clear dispatch request */
193 st r0, [context_switch_reqflg]
195 ld r0, [pxCurrentTCB]
196 breq r0, 0, ret_exc_1
198 SAVE_CALLEE_REGS /* save callee save registers */
200 lr r0, [AUX_STATUS32]
201 bclr r0, r0, AUX_STATUS_BIT_AE /* clear exception bit */
204 mov r1, ret_exc_r /* save return address */
207 bl dispatcher /* r0->pxCurrentTCB */
210 /* recover exception status */
211 lr r0, [AUX_STATUS32]
212 bset r0, r0, AUX_STATUS_BIT_AE
215 RESTORE_CALLEE_REGS /* recover registers */
219 /****** entry for normal interrupt exception handling ******/
220 .global exc_entry_int /* entry for interrupt handling */
223 #if ARC_FEATURE_FIRQ == 1
224 #if ARC_FEATURE_RGF_NUM_BANKS > 1
225 lr r0, [AUX_IRQ_ACT] /* check whether it is P0 interrupt */
230 lr r10, [AUX_IRQ_ACT]
240 clri /* disable interrupt */
241 ld r3, [exc_nest_count]
243 st r2, [exc_nest_count]
244 seti /* enable higher priority interrupt */
246 brne r3, 0, irq_handler_1
247 /* change to exception stack if interrupt happened in task context */
249 #if ARC_FEATURE_STACK_CHECK
250 #if ARC_FEATURE_SEC_PRESENT
251 lr r0, [AUX_SEC_STAT]
252 bclr r0, r0, AUX_SEC_STAT_BIT_SSC
255 lr r0, [AUX_STATUS32]
256 bclr r0, r0, AUX_STATUS_BIT_SC
263 lr r0, [AUX_IRQ_CAUSE]
264 mov r1, exc_int_handler_table
265 ld.as r2, [r1, r0] /* r2 = exc_int_handler_table + irqno *4 */
266 /* handle software triggered interrupt */
267 lr r3, [AUX_IRQ_HINT]
269 bne.d irq_hint_handled
271 sr r3, [AUX_IRQ_HINT]
274 jl [r2] /* jump to interrupt handler */
275 /* no interrupts are allowed from here */
277 clri /* disable interrupt */
280 mov r1, exc_nest_count
284 /* if there are multi-bits set in IRQ_ACT, it's still in nest interrupt */
285 lr r0, [AUX_IRQ_CAUSE]
286 sr r0, [AUX_IRQ_SELECT]
287 lr r3, [AUX_IRQ_PRIORITY]
290 brne r2, 0, ret_int_1
292 ld r0, [context_switch_reqflg]
293 brne r0, 0, ret_int_2
294 ret_int_1: /* return from non-task context */
297 /* there is a dispatch request */
299 /* clear dispatch request */
301 st r0, [context_switch_reqflg]
303 ld r0, [pxCurrentTCB]
304 breq r0, 0, ret_int_1
306 /* r1 has old AUX_IRQ_ACT */
308 /* clear related bits in IRQ_ACT manually to simulate a irq return */
311 SAVE_CALLEE_REGS /* save callee save registers */
312 mov r1, ret_int_r /* save return address */
315 bl dispatcher /* r0->pxCurrentTCB */
318 RESTORE_CALLEE_REGS /* recover registers */
323 #if ARC_FEATURE_FIRQ == 1
324 .global exc_entry_firq
327 #if ARC_FEATURE_STACK_CHECK && ARC_FEATURE_RGF_NUM_BANKS > 1
328 #if ARC_FEATURE_SEC_PRESENT
329 lr r0, [AUX_SEC_STAT]
330 bclr r0, r0, AUX_SEC_STAT_BIT_SSC
333 lr r0, [AUX_STATUS32]
334 bclr r0, r0, AUX_STATUS_BIT_SC
342 ld r3, [exc_nest_count]
344 st r2, [exc_nest_count]
346 brne r3, 0, firq_handler_1
347 #if ARC_FEATURE_STACK_CHECK && ARC_FEATURE_RGF_NUM_BANKS == 1
348 #if ARC_FEATURE_SEC_PRESENT
349 lr r0, [AUX_SEC_STAT]
350 bclr r0, r0, AUX_SEC_STAT_BIT_SSC
353 lr r0, [AUX_STATUS32]
354 bclr r0, r0, AUX_STATUS_BIT_SC
358 /* change to exception stack if interrupt happened in task context */
363 lr r0, [AUX_IRQ_CAUSE]
364 mov r1, exc_int_handler_table
365 ld.as r2, [r1, r0] /* r2 = exc_int_handler_table + irqno *4 */
366 /* handle software triggered interrupt */
367 lr r3, [AUX_IRQ_HINT]
368 brne r3, r0, firq_hint_handled
370 sr r3, [AUX_IRQ_HINT]
373 jl [r2] /* jump to interrupt handler */
374 /* no interrupts are allowed from here */
379 mov r1, exc_nest_count
383 /* if there are multi-bits set in IRQ_ACT, it's still in nest interrupt */
386 brne r1, 0, ret_firq_1
388 ld r0, [context_switch_reqflg]
389 brne r0, 0, ret_firq_2
390 ret_firq_1: /* return from non-task context */
393 /* there is a dispatch request */
395 /* clear dispatch request */
397 st r0, [context_switch_reqflg]
399 ld r0, [pxCurrentTCB]
400 breq r0, 0, ret_firq_1
402 /* reconstruct the interruptted context
403 * When ARC_FEATURE_RGF_BANKED_REGS >= 16 (16, 32), sp is banked
404 * so need to restore the fast irq stack.
406 #if ARC_FEATURE_RGF_BANKED_REGS >= 16
408 #if ARC_FEATURE_CODE_DENSITY
414 /* when BANKED_REGS == 16, r4-r9 wiil be also saved in fast irq stack
417 #if ARC_FEATURE_RGF_BANKED_REGS == 16 && !defined(ARC_FEATURE_RF16)
426 /* for other cases, unbanked regs are already in interrupted context's stack,
427 * so just need to save and pop the banked regs
430 /* save the interruptted context */
431 #if ARC_FEATURE_RGF_BANKED_REGS > 0
432 /* switch back to bank0 */
433 lr r0, [AUX_STATUS32]
438 #if ARC_FEATURE_RGF_BANKED_REGS == 4
439 /* r4 - r12, gp, fp, r30, blink already saved */
444 #elif ARC_FEATURE_RGF_BANKED_REGS == 8
445 /* r4 - r9, r0, r11 gp, fp, r30, blink already saved */
451 #elif ARC_FEATURE_RGF_BANKED_REGS >= 16
452 /* nothing is saved, */
458 PUSH r30 /* general purpose */
461 #if ARC_FEATURE_CODE_DENSITY
467 lr r0, [AUX_STATUS32_P0]
474 SAVE_CALLEE_REGS /* save callee save registers */
476 mov r1, ret_firq_r /* save return address */
478 ld r0, [pxCurrentTCB]
479 bl dispatcher /* r0->pxCurrentTCB */
482 RESTORE_CALLEE_REGS /* recover registers */
484 POPAX AUX_STATUS32_P0
487 #if ARC_FEATURE_RGF_NUM_BANKS > 1
488 #if ARC_FEATURE_RGF_BANKED_REGS == 4
489 /* r4 - r12, gp, fp, r30, blink already saved */
495 #elif ARC_FEATURE_RGF_BANKED_REGS == 8
496 /* r4 - r9, gp, fp, r30, blink already saved */
503 #elif ARC_FEATURE_RGF_BANKED_REGS >= 16
505 #if ARC_FEATURE_CODE_DENSITY
515 #endif /* ARC_FEATURE_RGF_BANKED_REGS */
518 #endif /* ARC_FEATURE_RGF_NUM_BANKS */