1/*
2 * Copyright (c) 2018, Synopsys, Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6#define __ASSEMBLY__
7#include "include/arc/arc.h"
8#include "include/arc/arc_asm_common.h"
9
10.global rt_interrupt_enter;
11.global rt_interrupt_leave;
12.global rt_thread_switch_interrupt_flag;
13.global rt_interrupt_from_thread;
14.global rt_interrupt_to_thread;
15.global exc_nest_count;
16.global set_hw_stack_check;
17
18    .text
19    .align 4
20dispatcher:
21    st sp, [r0]
22    ld sp, [r1]
23#if ARC_FEATURE_STACK_CHECK
24#if ARC_FEATURE_SEC_PRESENT
25    lr r0, [AUX_SEC_STAT]
26    bclr r0, r0, AUX_SEC_STAT_BIT_SSC
27    sflag r0
28#else
29    lr r0, [AUX_STATUS32]
30    bclr r0, r0, AUX_STATUS_BIT_SC
31    kflag r0
32#endif
33    jl  set_hw_stack_check
34#if ARC_FEATURE_SEC_PRESENT
35    lr r0, [AUX_SEC_STAT]
36    bset r0, r0, AUX_SEC_STAT_BIT_SSC
37    sflag r0
38#else
39    lr r0, [AUX_STATUS32]
40    bset r0, r0, AUX_STATUS_BIT_SC
41    kflag r0
42#endif
43#endif
44    pop r0
45    j [r0]
46
47/* return routine when task dispatch happened in task context */
48dispatch_r:
49    RESTORE_NONSCRATCH_REGS
50    RESTORE_R0_TO_R12
51    j   [blink]
52
53/*
54 * rt_base_t rt_hw_interrupt_disable();
55 */
56    .global rt_hw_interrupt_disable
57    .align 4
58rt_hw_interrupt_disable:
59    clri r0
60    j [blink]
61
62
63/*
64 * void rt_hw_interrupt_enable(rt_base_t level);
65 */
66    .global rt_hw_interrupt_enable
67    .align 4
68rt_hw_interrupt_enable:
69    seti r0
70    j [blink]
71
72
73    .global rt_hw_context_switch_interrupt
74    .align 4
75rt_hw_context_switch_interrupt:
76    ld r2, [rt_thread_switch_interrupt_flag]
77    breq r2, 1, _reswitch    /* Check the flag, if it is 1, skip to reswitch */
78    mov r2, 1
79    st r2, [rt_thread_switch_interrupt_flag]
80    st r0, [rt_interrupt_from_thread]
81_reswitch:
82    st r1, [rt_interrupt_to_thread]
83    j [blink]
84
85
86/*
87 * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
88 * r0 --> from
89 * r1 --> to
90 */
91    .global rt_hw_context_switch
92    .align 4
93rt_hw_context_switch:
94    SAVE_R0_TO_R12
95    SAVE_NONSCRATCH_REGS
96    mov r2, dispatch_r
97    push r2
98    b dispatcher
99
100
101/*
102 * void rt_hw_context_switch_to(rt_uint32 to);
103 * r0 --> to
104 */
105    .global rt_hw_context_switch_to
106    .align 4
107rt_hw_context_switch_to:
108    ld sp, [r0]
109#if ARC_FEATURE_STACK_CHECK
110    mov r1, r0
111#if ARC_FEATURE_SEC_PRESENT
112    lr r0, [AUX_SEC_STAT]
113    bclr r0, r0, AUX_SEC_STAT_BIT_SSC
114    sflag r0
115#else
116    lr r0, [AUX_STATUS32]
117    bclr r0, r0, AUX_STATUS_BIT_SC
118    kflag r0
119#endif
120    jl  set_hw_stack_check
121#if ARC_FEATURE_SEC_PRESENT
122    lr r0, [AUX_SEC_STAT]
123    bset r0, r0, AUX_SEC_STAT_BIT_SSC
124    sflag r0
125#else
126    lr r0, [AUX_STATUS32]
127    bset r0, r0, AUX_STATUS_BIT_SC
128    kflag r0
129#endif
130#endif
131    pop r0
132    j [r0]
133
134    .global start_r
135    .align 4
136start_r:
137    pop blink;
138    pop r1
139    pop r2
140    pop r0
141
142    j_s.d [r1]
143    kflag r2
144
145/*
146 * int __rt_ffs(int value);
147 * r0 --> value
148 */
149    .global __rt_ffs
150    .align 4
151__rt_ffs:
152    breq r0, 0, __rt_ffs_return
153    ffs r1, r0
154    add r0, r1, 1
155__rt_ffs_return:
156    j [blink]
157
158/****** exceptions and interrupts handing ******/
159/****** entry for exception handling ******/
160    .global exc_entry_cpu
161    .align 4
162exc_entry_cpu:
163
164    EXCEPTION_PROLOGUE
165
166    mov blink,  sp
167    mov r3, sp      /* as exception handler's para(p_excinfo) */
168
169    ld  r0, [exc_nest_count]
170    add r1, r0, 1
171    st  r1, [exc_nest_count]
172    brne    r0, 0, exc_handler_1
173/* change to exception stack if interrupt happened in task context */
174    mov sp, _e_stack
175exc_handler_1:
176    PUSH    blink
177
178    lr  r0, [AUX_ECR]
179    lsr r0, r0, 16
180    mov r1, exc_int_handler_table
181    ld.as   r2, [r1, r0]
182
183    mov r0, r3
184    jl  [r2]
185
186/* interrupts are not allowed */
187ret_exc:
188    POP sp
189    mov r1, exc_nest_count
190    ld  r0, [r1]
191    sub r0, r0, 1
192    st  r0, [r1]
193    brne    r0, 0, ret_exc_1 /* nest exception case */
194    lr  r1, [AUX_IRQ_ACT] /* nest interrupt case */
195    brne    r1, 0, ret_exc_1
196
197    ld  r0, [rt_thread_switch_interrupt_flag]
198    brne    r0, 0, ret_exc_2
199ret_exc_1:  /* return from non-task context, interrupts or exceptions are nested */
200    EXCEPTION_EPILOGUE
201    rtie
202
203/* there is a dispatch request */
204ret_exc_2:
205    /* clear dispatch request */
206    mov r0, 0
207    st  r0, [rt_thread_switch_interrupt_flag]
208
209    SAVE_CALLEE_REGS    /* save callee save registers */
210
211    /* clear exception bit to do exception exit by SW */
212    lr  r0, [AUX_STATUS32]
213    bclr    r0, r0, AUX_STATUS_BIT_AE
214    kflag   r0
215
216    mov r1, ret_exc_r   /* save return address */
217    PUSH    r1
218
219    ld  r0, [rt_interrupt_from_thread]
220    ld  r1, [rt_interrupt_to_thread]
221    b   dispatcher
222
223ret_exc_r:
224    /* recover exception status */
225    lr  r0, [AUX_STATUS32]
226    bset    r0, r0, AUX_STATUS_BIT_AE
227    kflag   r0
228
229    RESTORE_CALLEE_REGS
230    EXCEPTION_EPILOGUE
231    rtie
232
233/****** entry for normal interrupt exception handling ******/
234    .global exc_entry_int   /* entry for interrupt handling */
235    .align 4
236exc_entry_int:
237#if ARC_FEATURE_FIRQ == 1
238/*  check whether it is P0 interrupt */
239#if ARC_FEATURE_RGF_NUM_BANKS > 1
240    lr  r0, [AUX_IRQ_ACT]
241    btst    r0, 0
242    jnz exc_entry_firq
243#else
244    PUSH    r10
245    lr  r10, [AUX_IRQ_ACT]
246    btst    r10, 0
247    POP r10
248    jnz exc_entry_firq
249#endif
250#endif
251    INTERRUPT_PROLOGUE
252
253    mov blink, sp
254
255    clri    /* disable interrupt */
256    ld  r3, [exc_nest_count]
257    add r2, r3, 1
258    st  r2, [exc_nest_count]
259    seti    /* enable higher priority interrupt */
260
261    brne    r3, 0, irq_handler_1
262/* change to exception stack if interrupt happened in task context */
263    mov sp, _e_stack
264#if ARC_FEATURE_STACK_CHECK
265#if ARC_FEATURE_SEC_PRESENT
266    lr r0, [AUX_SEC_STAT]
267    bclr r0, r0, AUX_SEC_STAT_BIT_SSC
268    sflag r0
269#else
270    lr r0, [AUX_STATUS32]
271    bclr r0, r0, AUX_STATUS_BIT_SC
272    kflag r0
273#endif
274#endif
275irq_handler_1:
276    PUSH    blink
277
278    jl  rt_interrupt_enter
279
280    lr  r0, [AUX_IRQ_CAUSE]
281    sr  r0, [AUX_IRQ_SELECT]
282    mov r1, exc_int_handler_table
283    ld.as   r2, [r1, r0]    /* r2 = exc_int_handler_table + irqno *4 */
284/* handle software triggered interrupt */
285    lr  r3, [AUX_IRQ_HINT]
286    cmp r3, r0
287    bne.d irq_hint_handled
288    xor r3, r3, r3
289    sr  r3, [AUX_IRQ_HINT]
290irq_hint_handled:
291    lr  r3, [AUX_IRQ_PRIORITY]
292    PUSH    r3      /* save irq priority */
293
294    jl  [r2]        /* jump to interrupt handler */
295    jl  rt_interrupt_leave
296ret_int:
297    clri            /* disable interrupt */
298    POP r3      /* irq priority */
299    POP sp
300    mov r1, exc_nest_count
301    ld  r0, [r1]
302    sub r0, r0, 1
303    st  r0, [r1]
304/* if there are multi-bits set in IRQ_ACT, it's still in nest interrupt */
305    lr  r0, [AUX_IRQ_CAUSE]
306    sr  r0, [AUX_IRQ_SELECT]
307    lr  r3, [AUX_IRQ_PRIORITY]
308    lr  r1, [AUX_IRQ_ACT]
309    bclr    r2, r1, r3
310    brne    r2, 0, ret_int_1
311
312    ld  r0, [rt_thread_switch_interrupt_flag]
313    brne    r0, 0, ret_int_2
314ret_int_1:  /* return from non-task context */
315    INTERRUPT_EPILOGUE
316    rtie
317/* there is a dispatch request */
318ret_int_2:
319    /* clear dispatch request */
320    mov r0, 0
321    st  r0, [rt_thread_switch_interrupt_flag]
322
323    /* interrupt return by SW */
324    lr  r10, [AUX_IRQ_ACT]
325    PUSH    r10
326    bclr    r10, r10, r3    /* clear related bits in IRQ_ACT */
327    sr  r10, [AUX_IRQ_ACT]
328
329    SAVE_CALLEE_REGS    /* save callee save registers */
330    mov r1, ret_int_r   /* save return address */
331    PUSH    r1
332
333    ld  r0, [rt_interrupt_from_thread]
334    ld  r1, [rt_interrupt_to_thread]
335    b   dispatcher
336
337ret_int_r:
338    RESTORE_CALLEE_REGS
339    /* recover AUX_IRQ_ACT to restore the interrup status */
340    POPAX   AUX_IRQ_ACT
341    INTERRUPT_EPILOGUE
342    rtie
343
344/****** entry for fast irq exception handling ******/
345    .global exc_entry_firq
346    .weak exc_entry_firq
347    .align 4
348exc_entry_firq:
349    SAVE_FIQ_EXC_REGS
350
351    lr  r0, [AUX_IRQ_CAUSE]
352    mov r1, exc_int_handler_table
353/* r2 = _kernel_exc_tbl + irqno *4 */
354    ld.as   r2, [r1, r0]
355
356/* for the case of software triggered interrupt */
357    lr  r3, [AUX_IRQ_HINT]
358    cmp r3, r0
359    bne.d   firq_hint_handled
360    xor r3, r3, r3
361    sr  r3, [AUX_IRQ_HINT]
362firq_hint_handled:
363/* jump to interrupt handler */
364    mov r0, sp
365    jl  [r2]
366
367firq_return:
368    RESTORE_FIQ_EXC_REGS
369    rtie
370