1/*
2 * FreeRTOS Kernel V11.1.0
3 * Copyright (C) 2020 Synopsys, Inc. or its affiliates.  All Rights Reserved.
4 *
5 * SPDX-License-Identifier: MIT
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy of
8 * this software and associated documentation files (the "Software"), to deal in
9 * the Software without restriction, including without limitation the rights to
10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11 * the Software, and to permit persons to whom the Software is furnished to do so,
12 * subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in all
15 * copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * https://www.FreeRTOS.org
25 * https://github.com/FreeRTOS
26 *
27 */
28
29/**
30 * \file
31 * \ingroup OS_FREERTOS
32 * \brief  freertos support for arc processor
33 *  like task dispatcher, interrupt handler
34 */
35/** @cond OS_FREERTOS_ASM_ARC_SUPPORT */
36
37/*
38 * core-dependent part in assemble language (for arc)
39 */
40#define __ASSEMBLY__
41#include "arc/arc.h"
42#include "arc/arc_asm_common.h"
43
44/*
45 *  task dispatcher
46 *
47 */
48    .text
49    .align 4
50    .global dispatch
51dispatch:
52/*
53 *  the pre-conditions of this routine are task context, CPU is
54 *  locked, dispatch is enabled.
55 */
56    SAVE_NONSCRATCH_REGS        /* save callee save registers */
57    mov r1, dispatch_r
58    PUSH    r1          /* save return address */
59    ld  r0, [pxCurrentTCB]
60    bl  dispatcher
61
62/* return routine when task dispatch happened in task context */
63dispatch_r:
64    RESTORE_NONSCRATCH_REGS     /* recover registers */
65    j   [blink]
66
67/*
68 *  start dispatch
69 */
70    .global start_dispatch
71    .align 4
72start_dispatch:
73/*
74 *  this routine is called in the non-task context during the startup of the kernel
75 *  , and all the interrupts are locked.
76 *
77 *  when the dispatcher is called, the cpu is locked, no nest exception (CPU exception/interrupt).
78 *  In target_initialize, all interrupt priority mask should be cleared, cpu should be
79 *  locked, the interrupts outside the kernel such as fiq can be
80 *  enabled.
81 */
82    clri
83    mov r0, 0
84    st  r0, [exc_nest_count]
85    b   dispatcher_0
86/*
87 *  dispatcher
88 */
89dispatcher:
90    ld  r1, [ulCriticalNesting]
91    PUSH    r1          /* save critical nesting */
92    st  sp, [r0]        /* save stack pointer of current task, r0->pxCurrentTCB */
93    jl  vTaskSwitchContext  /* change the value of pxCurrentTCB */
94/*
95 *  before dispatcher is called, task context | cpu locked | dispatch enabled
96 *  should be satisfied. In this routine, the processor will jump
97 *  into the entry of next to run task
98 *
99 *  i.e. kernel mode, IRQ disabled, dispatch enabled
100 */
101dispatcher_0:
102    ld  r1, [pxCurrentTCB]
103    ld  sp, [r1]    /* recover task stack */
104#if ARC_FEATURE_STACK_CHECK
105#if ARC_FEATURE_SEC_PRESENT
106    lr r0, [AUX_SEC_STAT]
107    bclr r0, r0, AUX_SEC_STAT_BIT_SSC
108    sflag r0
109#else
110    lr r0, [AUX_STATUS32]
111    bclr r0, r0, AUX_STATUS_BIT_SC
112    kflag r0
113#endif
114    jl  vPortSetStackCheck
115#if ARC_FEATURE_SEC_PRESENT
116    lr r0, [AUX_SEC_STAT]
117    bset r0, r0, AUX_SEC_STAT_BIT_SSC
118    sflag r0
119#else
120    lr r0, [AUX_STATUS32]
121    bset r0, r0, AUX_STATUS_BIT_SC
122    kflag r0
123#endif
124#endif
125    POP r0      /* get critical nesting */
126    st  r0, [ulCriticalNesting]
127    POP r0      /* get return address  */
128    j   [r0]
129
130/*
131 *  task startup routine
132 *
133 */
134    .text
135    .global start_r
136    .align 4
137start_r:
138    seti    /* unlock cpu */
139    mov blink, vPortEndTask /* set return address */
140    POP r1          /* get task function body */
141    POP r0          /* get task parameters */
142    j   [r1]
143
144/****** exceptions and interrupts handing ******/
145/****** entry for exception handling ******/
146    .global exc_entry_cpu
147    .align 4
148exc_entry_cpu:
149
150    EXCEPTION_PROLOGUE
151
152    mov blink,  sp
153    mov r3, sp      /* as exception handler's para(p_excinfo) */
154
155    ld  r0, [exc_nest_count]
156    add r1, r0, 1
157    st  r1, [exc_nest_count]
158    brne    r0, 0, exc_handler_1
159/* change to exception stack if interrupt happened in task context */
160    mov sp, _e_stack
161exc_handler_1:
162    PUSH    blink
163
164    lr  r0, [AUX_ECR]
165    lsr r0, r0, 16
166    mov r1, exc_int_handler_table
167    ld.as   r2, [r1, r0]
168
169    mov r0, r3
170    jl  [r2]        /* !!!!jump to exception handler where interrupts are not allowed! */
171
172/* interrupts are not allowed */
173ret_exc:
174    POP sp
175    mov r1, exc_nest_count
176    ld  r0, [r1]
177    sub r0, r0, 1
178    st  r0, [r1]
179    brne    r0, 0, ret_exc_1 /* nest exception case */
180    lr  r1, [AUX_IRQ_ACT] /* nest interrupt case */
181    brne    r1, 0, ret_exc_1
182
183    ld  r0, [context_switch_reqflg]
184    brne    r0, 0, ret_exc_2
185ret_exc_1:  /* return from non-task context, interrupts or exceptions are nested */
186
187    EXCEPTION_EPILOGUE
188    rtie
189
190/* there is a dispatch request */
191ret_exc_2:
192    /* clear dispatch request */
193    mov r0, 0
194    st  r0, [context_switch_reqflg]
195
196    ld  r0, [pxCurrentTCB]
197    breq    r0, 0, ret_exc_1
198
199    SAVE_CALLEE_REGS    /* save callee save registers */
200
201    lr  r0, [AUX_STATUS32]
202    bclr    r0, r0, AUX_STATUS_BIT_AE   /* clear exception bit */
203    kflag   r0
204
205    mov r1, ret_exc_r   /* save return address */
206    PUSH    r1
207
208    bl  dispatcher  /* r0->pxCurrentTCB */
209
210ret_exc_r:
211    /* recover exception status */
212    lr  r0, [AUX_STATUS32]
213    bset    r0, r0, AUX_STATUS_BIT_AE
214    kflag   r0
215
216    RESTORE_CALLEE_REGS /* recover registers */
217    EXCEPTION_EPILOGUE
218    rtie
219
220/****** entry for normal interrupt exception handling ******/
221    .global exc_entry_int   /* entry for interrupt handling */
222    .align 4
223exc_entry_int:
224#if ARC_FEATURE_FIRQ == 1
225#if ARC_FEATURE_RGF_NUM_BANKS > 1
226    lr  r0, [AUX_IRQ_ACT]           /*  check whether it is P0 interrupt */
227    btst    r0, 0
228    jnz exc_entry_firq
229#else
230    PUSH    r10
231    lr  r10, [AUX_IRQ_ACT]
232    btst    r10, 0
233    POP r10
234    jnz exc_entry_firq
235#endif
236#endif
237    INTERRUPT_PROLOGUE
238
239    mov blink, sp
240
241    clri    /* disable interrupt */
242    ld  r3, [exc_nest_count]
243    add r2, r3, 1
244    st  r2, [exc_nest_count]
245    seti    /* enable higher priority interrupt */
246
247    brne    r3, 0, irq_handler_1
248/* change to exception stack if interrupt happened in task context */
249    mov sp, _e_stack
250#if ARC_FEATURE_STACK_CHECK
251#if ARC_FEATURE_SEC_PRESENT
252    lr r0, [AUX_SEC_STAT]
253    bclr r0, r0, AUX_SEC_STAT_BIT_SSC
254    sflag r0
255#else
256    lr r0, [AUX_STATUS32]
257    bclr r0, r0, AUX_STATUS_BIT_SC
258    kflag r0
259#endif
260#endif
261irq_handler_1:
262    PUSH    blink
263
264    lr  r0, [AUX_IRQ_CAUSE]
265    mov r1, exc_int_handler_table
266    ld.as   r2, [r1, r0]    /* r2 = exc_int_handler_table + irqno *4 */
267/* handle software triggered interrupt */
268    lr  r3, [AUX_IRQ_HINT]
269    cmp r3, r0
270    bne.d irq_hint_handled
271    xor r3, r3, r3
272    sr  r3, [AUX_IRQ_HINT]
273irq_hint_handled:
274
275    jl  [r2]        /* jump to interrupt handler */
276/* no interrupts are allowed from here */
277ret_int:
278    clri    /* disable interrupt */
279
280    POP sp
281    mov r1, exc_nest_count
282    ld  r0, [r1]
283    sub r0, r0, 1
284    st  r0, [r1]
285/* if there are multi-bits set in IRQ_ACT, it's still in nest interrupt */
286    lr  r0, [AUX_IRQ_CAUSE]
287    sr  r0, [AUX_IRQ_SELECT]
288    lr  r3, [AUX_IRQ_PRIORITY]
289    lr  r1, [AUX_IRQ_ACT]
290    bclr    r2, r1, r3
291    brne    r2, 0, ret_int_1
292
293    ld  r0, [context_switch_reqflg]
294    brne    r0, 0, ret_int_2
295ret_int_1:  /* return from non-task context */
296    INTERRUPT_EPILOGUE
297    rtie
298/* there is a dispatch request */
299ret_int_2:
300    /* clear dispatch request */
301    mov r0, 0
302    st  r0, [context_switch_reqflg]
303
304    ld  r0, [pxCurrentTCB]
305    breq    r0, 0, ret_int_1
306
307/* r1 has old AUX_IRQ_ACT */
308    PUSH    r1
309/* clear related bits in IRQ_ACT manually to simulate a irq return  */
310    sr  r2, [AUX_IRQ_ACT]
311
312    SAVE_CALLEE_REGS    /* save callee save registers */
313    mov r1, ret_int_r   /* save return address */
314    PUSH    r1
315
316    bl  dispatcher  /* r0->pxCurrentTCB */
317
318ret_int_r:
319    RESTORE_CALLEE_REGS /* recover registers */
320    POPAX   AUX_IRQ_ACT
321    INTERRUPT_EPILOGUE
322    rtie
323
324#if ARC_FEATURE_FIRQ == 1
325    .global exc_entry_firq
326    .align 4
327exc_entry_firq:
328#if ARC_FEATURE_STACK_CHECK && ARC_FEATURE_RGF_NUM_BANKS > 1
329#if ARC_FEATURE_SEC_PRESENT
330    lr r0, [AUX_SEC_STAT]
331    bclr r0, r0, AUX_SEC_STAT_BIT_SSC
332    sflag r0
333#else
334    lr r0, [AUX_STATUS32]
335    bclr r0, r0, AUX_STATUS_BIT_SC
336    kflag r0
337#endif
338#endif
339    SAVE_FIQ_EXC_REGS
340
341    mov blink, sp
342
343    ld  r3, [exc_nest_count]
344    add r2, r3, 1
345    st  r2, [exc_nest_count]
346
347    brne    r3, 0, firq_handler_1
348#if ARC_FEATURE_STACK_CHECK && ARC_FEATURE_RGF_NUM_BANKS == 1
349#if ARC_FEATURE_SEC_PRESENT
350    lr r0, [AUX_SEC_STAT]
351    bclr r0, r0, AUX_SEC_STAT_BIT_SSC
352    sflag r0
353#else
354    lr r0, [AUX_STATUS32]
355    bclr r0, r0, AUX_STATUS_BIT_SC
356    kflag r0
357#endif
358#endif
359/* change to exception stack if interrupt happened in task context */
360    mov sp, _e_stack
361firq_handler_1:
362    PUSH    blink
363
364    lr  r0, [AUX_IRQ_CAUSE]
365    mov r1, exc_int_handler_table
366    ld.as   r2, [r1, r0]    /* r2 = exc_int_handler_table + irqno *4 */
367/* handle software triggered interrupt */
368    lr  r3, [AUX_IRQ_HINT]
369    brne    r3, r0, firq_hint_handled
370    xor r3, r3, r3
371    sr  r3, [AUX_IRQ_HINT]
372firq_hint_handled:
373
374    jl  [r2]        /* jump to interrupt handler */
375/* no interrupts are allowed from here */
376ret_firq:
377    clri
378    POP sp
379
380    mov r1, exc_nest_count
381    ld  r0, [r1]
382    sub r0, r0, 1
383    st  r0, [r1]
384/* if there are multi-bits set in IRQ_ACT, it's still in nest interrupt */
385    lr  r1, [AUX_IRQ_ACT]
386    bclr    r1, r1, 0
387    brne    r1, 0, ret_firq_1
388
389    ld  r0, [context_switch_reqflg]
390    brne    r0, 0, ret_firq_2
391ret_firq_1: /* return from non-task context */
392    RESTORE_FIQ_EXC_REGS
393    rtie
394/* there is a dispatch request */
395ret_firq_2:
396    /* clear dispatch request */
397    mov r0, 0
398    st  r0, [context_switch_reqflg]
399
400    ld  r0, [pxCurrentTCB]
401    breq    r0, 0, ret_firq_1
402
403/* reconstruct the interruptted context
404 * When ARC_FEATURE_RGF_BANKED_REGS >= 16 (16, 32), sp is banked
405 * so need to restore the fast irq stack.
406 */
407#if ARC_FEATURE_RGF_BANKED_REGS >= 16
408    RESTORE_LP_REGS
409#if ARC_FEATURE_CODE_DENSITY
410    RESTORE_CODE_DENSITY
411#endif
412    RESTORE_R58_R59
413#endif
414
415/* when BANKED_REGS == 16, r4-r9 wiil be also saved in fast irq stack
416 * so pop them out
417 */
418#if  ARC_FEATURE_RGF_BANKED_REGS == 16 && !defined(ARC_FEATURE_RF16)
419    POP     r9
420    POP     r8
421    POP     r7
422    POP     r6
423    POP     r5
424    POP     r4
425#endif
426
427/* for other cases, unbanked regs are already in interrupted context's stack,
428 * so just need to save and pop the banked regs
429 */
430
431/* save the interruptted context */
432#if ARC_FEATURE_RGF_BANKED_REGS > 0
433/* switch back to bank0  */
434    lr r0, [AUX_STATUS32]
435    bic     r0, r0, 0x70000
436    kflag   r0
437#endif
438
439#if ARC_FEATURE_RGF_BANKED_REGS == 4
440/* r4 - r12, gp, fp, r30, blink already saved */
441    PUSH    r0
442    PUSH    r1
443    PUSH    r2
444    PUSH    r3
445#elif ARC_FEATURE_RGF_BANKED_REGS == 8
446/* r4 - r9, r0, r11 gp, fp, r30, blink already saved */
447    PUSH    r0
448    PUSH    r1
449    PUSH    r2
450    PUSH    r3
451    PUSH    r12
452#elif ARC_FEATURE_RGF_BANKED_REGS >= 16
453/* nothing is saved, */
454    SAVE_R0_TO_R12
455
456    SAVE_R58_R59
457    PUSH    gp
458    PUSH    fp
459    PUSH    r30     /* general purpose */
460    PUSH    blink
461
462#if ARC_FEATURE_CODE_DENSITY
463    SAVE_CODE_DENSITY
464#endif
465    SAVE_LP_REGS
466#endif
467    PUSH    ilink
468    lr  r0, [AUX_STATUS32_P0]
469    PUSH    r0
470    lr  r0, [AUX_IRQ_ACT]
471    PUSH    r0
472    bclr    r0, r0, 0
473    sr  r0, [AUX_IRQ_ACT]
474
475    SAVE_CALLEE_REGS    /* save callee save registers */
476
477    mov r1, ret_firq_r  /* save return address */
478    PUSH    r1
479    ld  r0, [pxCurrentTCB]
480    bl  dispatcher  /* r0->pxCurrentTCB */
481
482ret_firq_r:
483    RESTORE_CALLEE_REGS /* recover registers */
484    POPAX   AUX_IRQ_ACT
485    POPAX   AUX_STATUS32_P0
486    POP ilink
487
488#if ARC_FEATURE_RGF_NUM_BANKS > 1
489#if ARC_FEATURE_RGF_BANKED_REGS == 4
490/* r4 - r12, gp, fp, r30, blink already saved */
491    POP r3
492    POP r2
493    POP r1
494    POP r0
495    RESTORE_FIQ_EXC_REGS
496#elif ARC_FEATURE_RGF_BANKED_REGS == 8
497/* r4 - r9, gp, fp, r30, blink already saved */
498    POP r12
499    POP r3
500    POP r2
501    POP r1
502    POP r0
503    RESTORE_FIQ_EXC_REGS
504#elif ARC_FEATURE_RGF_BANKED_REGS >= 16
505    RESTORE_LP_REGS
506#if ARC_FEATURE_CODE_DENSITY
507    RESTORE_CODE_DENSITY
508#endif
509    POP blink
510    POP r30
511    POP fp
512    POP gp
513
514    RESTORE_R58_R59
515    RESTORE_R0_TO_R12
516#endif /* ARC_FEATURE_RGF_BANKED_REGS  */
517#else
518    RESTORE_FIQ_EXC_REGS
519#endif /* ARC_FEATURE_RGF_NUM_BANKS */
520    rtie
521#endif
522/** @endcond */
523