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    lr r0, [AUX_STATUS32]
106    bclr r0, r0, AUX_STATUS_BIT_SC
107    flag r0
108    jl  vPortSetStackCheck
109    lr r0, [AUX_STATUS32]
110    bset r0, r0, AUX_STATUS_BIT_SC
111    flag r0
112#endif
113    POP r0      /* get critical nesting */
114    st  r0, [ulCriticalNesting]
115    POP r0      /* get return address  */
116    j   [r0]
117
118/*
119 *  task startup routine
120 *
121 */
122    .text
123    .global start_r
124    .align 4
125start_r:
126    seti    /* unlock cpu */
127    mov blink, vPortEndTask /* set return address */
128    POP r1          /* get task function body */
129    POP r0          /* get task parameters */
130    j   [r1]
131
132/****** exceptions and interrupts handing ******/
133/****** entry for exception handling ******/
134    .global exc_entry_cpu
135    .align 4
136exc_entry_cpu:
137
138    EXCEPTION_PROLOGUE
139
140
141    mov blink,  sp
142    mov r3, sp      /* as exception handler's para(p_excinfo) */
143
144    ld  r1, [exc_nest_count]
145    add r1, r1, 1
146    st  r1, [exc_nest_count]
147    brne    r1, 0, exc_handler_1
148/* change to exception stack if interrupt happened in task context */
149    mov sp, _e_stack
150exc_handler_1:
151    PUSH    blink
152
153/* find the exception cause */
154#if ARC_FEATURE_CORE_700
155    lr  r0, [AUX_ECR]
156    lsr r0, r0, 16
157    bmsk    r0, r0, 7
158#endif
159    mov r1, exc_int_handler_table
160    ld.as   r2, [r1, r0]
161
162    mov r0, r3
163    jl  [r2]        /* !!!!jump to exception handler where interrupts are not allowed! */
164
165/* interrupts are not allowed */
166ret_exc:
167    POP sp
168    mov r1, exc_nest_count
169    ld  r0, [r1]
170    sub r0, r0, 1
171    st  r0, [r1]
172    brne    r0, 0, ret_exc_1  /* nested exception case */
173    lr  r1, [AUX_IRQ_LV12]
174    brne    r1, 0, ret_exc_1  /* nested or pending interrupt case */
175
176    ld  r0, [context_switch_reqflg]
177    brne    r0, 0, ret_exc_2
178ret_exc_1:  /* return from non-task context, interrupts or exceptions are nested */
179
180    EXCEPTION_EPILOGUE
181#if ARC_FEATURE_CORE_600
182    rtie ilink2
183#else
184    rtie
185#endif
186
187/* there is a dispatch request */
188ret_exc_2:
189    /* clear dispatch request */
190    mov r0, 0
191    st  r0, [context_switch_reqflg]
192
193    ld  r0, [pxCurrentTCB]
194    breq    r0, 0, ret_exc_1
195
196    SAVE_CALLEE_REGS    /* save callee save registers */
197
198    lr  r0, [AUX_STATUS32]
199    bclr    r0, r0, AUX_STATUS_BIT_AE   /* clear exception bit */
200    flag    r0
201
202    mov r1, ret_exc_r   /* save return address */
203    PUSH    r1
204
205    bl  dispatcher  /* r0->pxCurrentTCB */
206
207ret_exc_r:
208    /* recover exception status */
209    lr  r0, [AUX_STATUS32]
210    bset    r0, r0, AUX_STATUS_BIT_AE
211    flag    r0
212
213    RESTORE_CALLEE_REGS /* recover registers */
214    EXCEPTION_EPILOGUE
215#if ARC_FEATURE_CORE_600
216    rtie ilink2
217#else
218    rtie
219#endif
220
221/****** entry for normal interrupt exception handling ******/
222    .global exc_entry_int   /* entry for interrupt handling */
223    .align 4
224exc_entry_int:
225
226    INTERRUPT_PROLOGUE
227
228    mov blink, sp
229
230    /* disable interrupt */
231    push r0
232    lr  r0, [AUX_STATUS32]
233    push r0
234    bclr r0, r0, AUX_STATUS_BIT_E1
235    bclr r0, r0, AUX_STATUS_BIT_E2
236    flag r0
237    ld  r3, [exc_nest_count]
238    add r2, r3, 1
239    st  r2, [exc_nest_count]
240    /* enable interrupt */
241    pop r0
242    flag r0
243    pop r0
244
245    brne    r3, 0, irq_handler_1
246/* change to exception stack if interrupt happened in task context */
247    mov sp, _e_stack
248#if ARC_FEATURE_STACK_CHECK
249    lr r0, [AUX_STATUS32]
250    bclr r0, r0, AUX_STATUS_BIT_SC
251    flag r0
252#endif
253irq_handler_1:
254    PUSH    blink
255
256/* critical area */
257#if ARC_FEATURE_CORE_700
258    lr  r0, [AUX_IRQ_CAUSE1]
259#endif
260    mov r1, exc_int_handler_table
261    ld.as   r2, [r1, r0]    /* r2 = exc_int_handler_table + irqno *4 */
262/* handle software triggered interrupt */
263    lr  r3, [AUX_IRQ_HINT]
264    cmp r3, r0
265    bne.d irq_hint_handled
266    xor r3, r3, r3
267    sr  r3, [AUX_IRQ_HINT]
268irq_hint_handled:
269
270    jl  [r2]        /* jump to interrupt handler */
271/* no interrupts are allowed from here */
272ret_int:
273    clri    /* disable interrupt */
274
275    POP sp
276    mov r1, exc_nest_count
277    ld  r0, [r1]
278    sub r0, r0, 1
279    st  r0, [r1]
280/* if there are multi-bits set in IRQ_LV12, it's still in nest interrupt */
281    lr  r1, [AUX_IRQ_LV12]
282
283    ld  r0, [context_switch_reqflg]
284    brne    r0, 0, ret_int_2
285ret_int_1:  /* return from non-task context */
286    INTERRUPT_EPILOGUE
287#if ARC_FEATURE_CORE_600
288/* TODO: series 600 IRQ6 and IRQ7 uses ilink2 */
289    rtie ilink1
290#else
291    rtie
292#endif
293/* there is a dispatch request */
294ret_int_2:
295    /* clear dispatch request */
296    mov r0, 0
297    st  r0, [context_switch_reqflg]
298
299    ld  r0, [pxCurrentTCB]
300    breq    r0, 0, ret_int_1
301
302/* r1 has old AUX_IRQ_LV12 */
303    PUSH    r1
304/* clear related bits in IRQ_ACT manually to simulate a irq return  */
305
306    SAVE_CALLEE_REGS    /* save callee save registers */
307    mov r1, ret_int_r   /* save return address */
308    PUSH    r1
309
310    bl  dispatcher  /* r0->pxCurrentTCB */
311
312ret_int_r:
313    RESTORE_CALLEE_REGS /* recover registers */
314    POPAX   AUX_IRQ_LV12
315    INTERRUPT_EPILOGUE
316#if ARC_FEATURE_CORE_600
317    rtie ilink1
318#else
319    rtie
320#endif
321
322/** @endcond */
323