2 * FreeRTOS Kernel <DEVELOPMENT BRANCH>
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
29 * \ingroup OS_FREERTOS
30 * \brief freertos support for arc processor
31 * like task dispatcher, interrupt handler
33 /** @cond OS_FREERTOS_ASM_ARC_SUPPORT */
36 * core-dependent part in assemble language (for arc)
40 #include "arc/arc_asm_common.h"
51 * the pre-conditions of this routine are task context, CPU is
52 * locked, dispatch is enabled.
54 SAVE_NONSCRATCH_REGS /* save callee save registers */
56 PUSH r1 /* save return address */
60 /* return routine when task dispatch happened in task context */
62 RESTORE_NONSCRATCH_REGS /* recover registers */
68 .global start_dispatch
72 * this routine is called in the non-task context during the startup of the kernel
73 * , and all the interrupts are locked.
75 * when the dispatcher is called, the cpu is locked, no nest exception (CPU exception/interrupt).
76 * In target_initialize, all interrupt priority mask should be cleared, cpu should be
77 * locked, the interrupts outside the kernel such as fiq can be
82 st r0, [exc_nest_count]
88 ld r1, [ulCriticalNesting]
89 PUSH r1 /* save critical nesting */
90 st sp, [r0] /* save stack pointer of current task, r0->pxCurrentTCB */
91 jl vTaskSwitchContext /* change the value of pxCurrentTCB */
93 * before dispatcher is called, task context | cpu locked | dispatch enabled
94 * should be satisfied. In this routine, the processor will jump
95 * into the entry of next to run task
97 * i.e. kernel mode, IRQ disabled, dispatch enabled
100 ld r1, [pxCurrentTCB]
101 ld sp, [r1] /* recover task stack */
102 #if ARC_FEATURE_STACK_CHECK
103 #if ARC_FEATURE_SEC_PRESENT
104 lr r0, [AUX_SEC_STAT]
105 bclr r0, r0, AUX_SEC_STAT_BIT_SSC
108 lr r0, [AUX_STATUS32]
109 bclr r0, r0, AUX_STATUS_BIT_SC
112 jl vPortSetStackCheck
113 #if ARC_FEATURE_SEC_PRESENT
114 lr r0, [AUX_SEC_STAT]
115 bset r0, r0, AUX_SEC_STAT_BIT_SSC
118 lr r0, [AUX_STATUS32]
119 bset r0, r0, AUX_STATUS_BIT_SC
123 POP r0 /* get critical nesting */
124 st r0, [ulCriticalNesting]
125 POP r0 /* get return address */
129 * task startup routine
136 seti /* unlock cpu */
137 mov blink, vPortEndTask /* set return address */
138 POP r1 /* get task function body */
139 POP r0 /* get task parameters */
142 /****** exceptions and interrupts handing ******/
143 /****** entry for exception handling ******/
144 .global exc_entry_cpu
151 mov r3, sp /* as exception handler's para(p_excinfo) */
153 ld r0, [exc_nest_count]
155 st r1, [exc_nest_count]
156 brne r0, 0, exc_handler_1
157 /* change to exception stack if interrupt happened in task context */
164 mov r1, exc_int_handler_table
168 jl [r2] /* !!!!jump to exception handler where interrupts are not allowed! */
170 /* interrupts are not allowed */
173 mov r1, exc_nest_count
177 brne r0, 0, ret_exc_1 /* nest exception case */
178 lr r1, [AUX_IRQ_ACT] /* nest interrupt case */
179 brne r1, 0, ret_exc_1
181 ld r0, [context_switch_reqflg]
182 brne r0, 0, ret_exc_2
183 ret_exc_1: /* return from non-task context, interrupts or exceptions are nested */
188 /* there is a dispatch request */
190 /* clear dispatch request */
192 st r0, [context_switch_reqflg]
194 ld r0, [pxCurrentTCB]
195 breq r0, 0, ret_exc_1
197 SAVE_CALLEE_REGS /* save callee save registers */
199 lr r0, [AUX_STATUS32]
200 bclr r0, r0, AUX_STATUS_BIT_AE /* clear exception bit */
203 mov r1, ret_exc_r /* save return address */
206 bl dispatcher /* r0->pxCurrentTCB */
209 /* recover exception status */
210 lr r0, [AUX_STATUS32]
211 bset r0, r0, AUX_STATUS_BIT_AE
214 RESTORE_CALLEE_REGS /* recover registers */
218 /****** entry for normal interrupt exception handling ******/
219 .global exc_entry_int /* entry for interrupt handling */
222 #if ARC_FEATURE_FIRQ == 1
223 #if ARC_FEATURE_RGF_NUM_BANKS > 1
224 lr r0, [AUX_IRQ_ACT] /* check whether it is P0 interrupt */
229 lr r10, [AUX_IRQ_ACT]
239 clri /* disable interrupt */
240 ld r3, [exc_nest_count]
242 st r2, [exc_nest_count]
243 seti /* enable higher priority interrupt */
245 brne r3, 0, irq_handler_1
246 /* change to exception stack if interrupt happened in task context */
248 #if ARC_FEATURE_STACK_CHECK
249 #if ARC_FEATURE_SEC_PRESENT
250 lr r0, [AUX_SEC_STAT]
251 bclr r0, r0, AUX_SEC_STAT_BIT_SSC
254 lr r0, [AUX_STATUS32]
255 bclr r0, r0, AUX_STATUS_BIT_SC
262 lr r0, [AUX_IRQ_CAUSE]
263 mov r1, exc_int_handler_table
264 ld.as r2, [r1, r0] /* r2 = exc_int_handler_table + irqno *4 */
265 /* handle software triggered interrupt */
266 lr r3, [AUX_IRQ_HINT]
268 bne.d irq_hint_handled
270 sr r3, [AUX_IRQ_HINT]
273 jl [r2] /* jump to interrupt handler */
274 /* no interrupts are allowed from here */
276 clri /* disable interrupt */
279 mov r1, exc_nest_count
283 /* if there are multi-bits set in IRQ_ACT, it's still in nest interrupt */
284 lr r0, [AUX_IRQ_CAUSE]
285 sr r0, [AUX_IRQ_SELECT]
286 lr r3, [AUX_IRQ_PRIORITY]
289 brne r2, 0, ret_int_1
291 ld r0, [context_switch_reqflg]
292 brne r0, 0, ret_int_2
293 ret_int_1: /* return from non-task context */
296 /* there is a dispatch request */
298 /* clear dispatch request */
300 st r0, [context_switch_reqflg]
302 ld r0, [pxCurrentTCB]
303 breq r0, 0, ret_int_1
305 /* r1 has old AUX_IRQ_ACT */
307 /* clear related bits in IRQ_ACT manually to simulate a irq return */
310 SAVE_CALLEE_REGS /* save callee save registers */
311 mov r1, ret_int_r /* save return address */
314 bl dispatcher /* r0->pxCurrentTCB */
317 RESTORE_CALLEE_REGS /* recover registers */
322 #if ARC_FEATURE_FIRQ == 1
323 .global exc_entry_firq
326 #if ARC_FEATURE_STACK_CHECK && ARC_FEATURE_RGF_NUM_BANKS > 1
327 #if ARC_FEATURE_SEC_PRESENT
328 lr r0, [AUX_SEC_STAT]
329 bclr r0, r0, AUX_SEC_STAT_BIT_SSC
332 lr r0, [AUX_STATUS32]
333 bclr r0, r0, AUX_STATUS_BIT_SC
341 ld r3, [exc_nest_count]
343 st r2, [exc_nest_count]
345 brne r3, 0, firq_handler_1
346 #if ARC_FEATURE_STACK_CHECK && ARC_FEATURE_RGF_NUM_BANKS == 1
347 #if ARC_FEATURE_SEC_PRESENT
348 lr r0, [AUX_SEC_STAT]
349 bclr r0, r0, AUX_SEC_STAT_BIT_SSC
352 lr r0, [AUX_STATUS32]
353 bclr r0, r0, AUX_STATUS_BIT_SC
357 /* change to exception stack if interrupt happened in task context */
362 lr r0, [AUX_IRQ_CAUSE]
363 mov r1, exc_int_handler_table
364 ld.as r2, [r1, r0] /* r2 = exc_int_handler_table + irqno *4 */
365 /* handle software triggered interrupt */
366 lr r3, [AUX_IRQ_HINT]
367 brne r3, r0, firq_hint_handled
369 sr r3, [AUX_IRQ_HINT]
372 jl [r2] /* jump to interrupt handler */
373 /* no interrupts are allowed from here */
378 mov r1, exc_nest_count
382 /* if there are multi-bits set in IRQ_ACT, it's still in nest interrupt */
385 brne r1, 0, ret_firq_1
387 ld r0, [context_switch_reqflg]
388 brne r0, 0, ret_firq_2
389 ret_firq_1: /* return from non-task context */
392 /* there is a dispatch request */
394 /* clear dispatch request */
396 st r0, [context_switch_reqflg]
398 ld r0, [pxCurrentTCB]
399 breq r0, 0, ret_firq_1
401 /* reconstruct the interruptted context
402 * When ARC_FEATURE_RGF_BANKED_REGS >= 16 (16, 32), sp is banked
403 * so need to restore the fast irq stack.
405 #if ARC_FEATURE_RGF_BANKED_REGS >= 16
407 #if ARC_FEATURE_CODE_DENSITY
413 /* when BANKED_REGS == 16, r4-r9 wiil be also saved in fast irq stack
416 #if ARC_FEATURE_RGF_BANKED_REGS == 16 && !defined(ARC_FEATURE_RF16)
425 /* for other cases, unbanked regs are already in interrupted context's stack,
426 * so just need to save and pop the banked regs
429 /* save the interruptted context */
430 #if ARC_FEATURE_RGF_BANKED_REGS > 0
431 /* switch back to bank0 */
432 lr r0, [AUX_STATUS32]
437 #if ARC_FEATURE_RGF_BANKED_REGS == 4
438 /* r4 - r12, gp, fp, r30, blink already saved */
443 #elif ARC_FEATURE_RGF_BANKED_REGS == 8
444 /* r4 - r9, r0, r11 gp, fp, r30, blink already saved */
450 #elif ARC_FEATURE_RGF_BANKED_REGS >= 16
451 /* nothing is saved, */
457 PUSH r30 /* general purpose */
460 #if ARC_FEATURE_CODE_DENSITY
466 lr r0, [AUX_STATUS32_P0]
473 SAVE_CALLEE_REGS /* save callee save registers */
475 mov r1, ret_firq_r /* save return address */
477 ld r0, [pxCurrentTCB]
478 bl dispatcher /* r0->pxCurrentTCB */
481 RESTORE_CALLEE_REGS /* recover registers */
483 POPAX AUX_STATUS32_P0
486 #if ARC_FEATURE_RGF_NUM_BANKS > 1
487 #if ARC_FEATURE_RGF_BANKED_REGS == 4
488 /* r4 - r12, gp, fp, r30, blink already saved */
494 #elif ARC_FEATURE_RGF_BANKED_REGS == 8
495 /* r4 - r9, gp, fp, r30, blink already saved */
502 #elif ARC_FEATURE_RGF_BANKED_REGS >= 16
504 #if ARC_FEATURE_CODE_DENSITY
514 #endif /* ARC_FEATURE_RGF_BANKED_REGS */
517 #endif /* ARC_FEATURE_RGF_NUM_BANKS */