summaryrefslogtreecommitdiff
path: root/libcpu/nds32/context_gcc.S
blob: 8d5f3287e9cc026dbfbbedaac48af35eaec83118 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
#include "nds32.h"
#include "os_cpu_common.h"
#include "config.h"

	.align 4
! void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
! R0 --> from
! R1 --> to
    .section .text
    .global rt_hw_context_switch_interrupt
    .global rt_hw_context_switch
rt_hw_context_switch_interrupt:
rt_hw_context_switch:
	push25 $r6,#8    ! {$r6, $fp, $gp, $lp}

    la     $r2, rt_thread_switch_interrupt_flag
    lw     $r3, [$r2]
    movi   $r4, #1
    beq    $r3, $r4, _reswitch
    sw     $r4, [$r2]                           ! set rt_thread_switch_interrupt_flag to 1

    la     $r2, rt_interrupt_from_thread
    sw     $r0, [$r2]                           ! set rt_interrupt_from_thread
_reswitch:
	la     $r2, rt_interrupt_to_thread
    sw     $r1, [$r2]                           ! set rt_interrupt_to_thread
    bal    hal_intc_swi_trigger                 ! trigger the swi exception (causes context switch)

	pop25  $r6,#8    ! {$r6, $fp, $gp, $lp}

! R0 --> switch from thread stack
! R1 --> switch to thread stack
! psr, pc, LR, R12, R3, R2, R1, R0 are pushed into [from] stack

	.align 4
	.global OS_Trap_Interrupt_SWI
OS_Trap_Interrupt_SWI:
!	pushm $r0, $r5
    setgie.d                                     ! disable interrupt to protect context switch
	dsb

    IntlDescend                                  ! Descend interrupt level

	movi	$r0, 0x0
	mtsr	$r0, $INT_PEND                       ! clean SWI pending

	la      $r0, rt_thread_switch_interrupt_flag ! get rt_thread_switch_interrupt_flag
	lw      $r1, [$r0]
	beqz    $r1, pendsv_exit                     ! swi has already been handled

	movi    $r1, #0
	sw      $r1, [$r0]                           ! clear rt_thread_switch_interrupt_flag to 0

	la      $r0, rt_interrupt_from_thread
	lw      $r1, [$r0]
	beqz    $r1, switch_to_thread                ! skip register save at the first time(os startup phase)

	SAVE_ALL

	move    $r1, $sp
	la      $r0, rt_interrupt_from_thread
	lw      $r0, [$r0]
	sw      $r1, [$r0]

switch_to_thread:
    la     $r1, rt_interrupt_to_thread
    lw     $r1, [$r1]
    lw     $r1, [$r1]                            ! load thread stack pointer
	move   $sp, $r1                              ! update stack pointer
	RESTORE_ALL                                  ! pop registers

pendsv_exit:
	setgie.e
	iret

	.align 4
! void rt_hw_context_switch_to(rt_uint32 to);
! R0 --> to
    .global rt_hw_context_switch_to
rt_hw_context_switch_to:
    la     $r1, rt_interrupt_to_thread
    sw     $r0, [$r1]

    ! set from thread to 0
    la     $r1, rt_interrupt_from_thread
    movi   $r0, #0
    sw     $r0, [$r1]

    ! set interrupt flag to 1
    la     $r1, rt_thread_switch_interrupt_flag
    movi   $r0, #1
    sw     $r0, [$r1]

    ! set the SWI exception priority(must be the lowest level)
	! todo

    ! trigger the SWI exception (causes context switch)
    jal    hal_intc_swi_trigger

    setgie.e            ! enable interrupts at processor level

1:
	b   1b              ! never reach here

#ifndef VECTOR_NUMINTRS
#define VECTOR_NUMINTRS		32
#endif

	.global OS_Trap_Int_Common

	! Set up Interrupt vector ISR
	! HW#IRQ_SWI_VECTOR : OS_Trap_Interrupt_SWI (SWI)
	! HW#n : OS_Trap_Int_Common

	.macro	SET_HWISR num
	.global OS_Trap_Interrupt_HW\num
	.if	\num == IRQ_SWI_VECTOR
	.set	OS_Trap_Interrupt_HW\num, OS_Trap_Interrupt_SWI
	.else
	.set	OS_Trap_Interrupt_HW\num, OS_Trap_Int_Common
	.endif
	.endm

	.altmacro
	.set	irqno, 0
	.rept	VECTOR_NUMINTRS
	SET_HWISR %irqno
	.set	irqno, irqno+1
	.endr
	.noaltmacro

!	.global OS_Trap_Int_Common
OS_Trap_Int_Common:
#ifdef MPU_SUPPORT
	mfsr	$p1, $PSW
	ori	$p1, $p1, (PSW_mskIT | PSW_mskDT)
	mtsr	$p1, $PSW                       ! enable IT/DT
	dsb
	pushm	$r0, $r5
	move	$r0, $p0                        ! IRQ number
#endif
	! $r0 : HW Interrupt vector number
	SAVE_CALLER

	IntlDescend                             ! Descend interrupt level

	mfsr	$r1, $IPSW                      ! Use IPSW.CPL to check come from thread or ISR
	srli45	$r1, #PSW_offCPL
	fexti33	$r1, #0x2                       ! IPSW.CPL
	bnec	$r1, #0x7, 2f                   ! IPSW.CPL != 7, come form ISR, reentrant

	move	$fp, $sp                        ! save old stack pointer
	la	    $sp, __OS_Int_Stack             ! switch to interrupt stack
2:
	setgie.e                                ! allow nested now

	! The entire CPU state is now stashed on the stack,
	! and the stack is also 8-byte alignment.
	! We can call C program based interrupt handler now.
	la	    $r1, OS_CPU_Vector_Table
	lw	    $r1, [$r1+($r0<<2)]             ! ISR function pointer
	jral	$r1                             ! Call ISR

	la	    $r1, __OS_Int_Stack             ! Check for nested interruption return
	bne	    $r1, $sp, 3f                    ! $sp != __OS_Int_Stack?

	move	$sp, $fp                        ! Move back to the thread stack
3:
	RESTORE_CALLER

	iret

!	.set	OS_Trap_Interrupt_HW9, OS_Trap_Interrupt_SWI
!	.set	OS_Trap_Interrupt_HW19, OS_Trap_Int_Common

!*********************************************
! POINTERS TO VARIABLES
!*********************************************
#ifdef MPU_SUPPORT
	.section privileged_data
#else
	.section .bss
#endif
	.skip IRQ_STACK_SIZE
	.align 3
__OS_Int_Stack:

	.end