summaryrefslogtreecommitdiff
path: root/libcpu/arm/lpc214x/context_rvds.S
blob: 762b67d42e6fd3e2b8bb43bad3a7ab96d2f2a83d (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
;/*
; * File      : context_rvds.S
; * This file is part of RT-Thread RTOS
; * COPYRIGHT (C) 2006, RT-Thread Development Team
; *
; * The license and distribution terms for this file may be
; * found in the file LICENSE in this distribution or at
; * http://www.rt-thread.org/license/LICENSE
; *
; * Change Logs:
; * Date           Author       Notes
; * 2009-01-20     Bernard      first version
; * 2011-07-22     Bernard      added thumb mode porting
; */

Mode_USR        EQU     0x10
Mode_FIQ        EQU     0x11
Mode_IRQ        EQU     0x12
Mode_SVC        EQU     0x13
Mode_ABT        EQU     0x17
Mode_UND        EQU     0x1B
Mode_SYS        EQU     0x1F

I_Bit           EQU     0x80            ; when I bit is set, IRQ is disabled
F_Bit           EQU     0x40            ; when F bit is set, FIQ is disabled

NOINT	        EQU     0xc0	; disable interrupt in psr

	AREA |.text|, CODE, READONLY, ALIGN=2
	ARM
	REQUIRE8
	PRESERVE8

;/*
; * rt_base_t rt_hw_interrupt_disable();
; */
rt_hw_interrupt_disable	PROC
	EXPORT rt_hw_interrupt_disable
	MRS r0, cpsr
	ORR r1, r0, #NOINT
	MSR cpsr_c, r1
	BX	lr
	ENDP

;/*
; * void rt_hw_interrupt_enable(rt_base_t level);
; */
rt_hw_interrupt_enable	PROC
	EXPORT rt_hw_interrupt_enable
	MSR cpsr_c, r0
	BX	lr
	ENDP

;/*
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
; * r0 --> from
; * r1 --> to
; */
rt_hw_context_switch	PROC
	EXPORT rt_hw_context_switch
	STMFD	sp!, {lr}			; push pc (lr should be pushed in place of PC)
	STMFD	sp!, {r0-r12, lr}	; push lr & register file

	MRS		r4, cpsr
        TST     lr, #0x01
        BEQ     _ARM_MODE
        ORR     r4, r4, #0x20           ; it's thumb code
_ARM_MODE
	STMFD	sp!, {r4}			; push cpsr

	STR	sp, [r0]				; store sp in preempted tasks TCB
	LDR	sp, [r1]				; get new task stack pointer

    LDMFD   sp!, {r4}               ; pop new task cpsr to spsr
	MSR	spsr_cxsf, r4
    BIC     r4, r4, #0x20           ; must be ARM mode
	MSR	cpsr_cxsf, r4

    LDMFD   sp!, {r0-r12, lr, pc}^  ; pop new task r0-r12, lr & pc, copy spsr to cpsr
	ENDP

;/*
; * void rt_hw_context_switch_to(rt_uint32 to);
; * r0 --> to
; */
rt_hw_context_switch_to	PROC
	EXPORT rt_hw_context_switch_to
	LDR	sp, [r0]				; get new task stack pointer

    LDMFD   sp!, {r4}               ; pop new task cpsr to spsr
	MSR	spsr_cxsf, r4
    BIC     r4, r4, #0x20           ; must be ARM mode
	MSR	cpsr_cxsf, r4

    LDMFD   sp!, {r0-r12, lr, pc}^  ; pop new task r0-r12, lr & pc, copy spsr to cpsr
	ENDP

;/*
; * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to);
; */
	IMPORT rt_thread_switch_interrupt_flag
	IMPORT rt_interrupt_from_thread
	IMPORT rt_interrupt_to_thread

rt_hw_context_switch_interrupt	PROC
	EXPORT rt_hw_context_switch_interrupt
	LDR r2, =rt_thread_switch_interrupt_flag
	LDR r3, [r2]
	CMP r3, #1
	BEQ _reswitch
	MOV r3, #1							; set rt_thread_switch_interrupt_flag to 1
	STR r3, [r2]
	LDR r2, =rt_interrupt_from_thread	; set rt_interrupt_from_thread
	STR r0, [r2]
_reswitch
	LDR r2, =rt_interrupt_to_thread		; set rt_interrupt_to_thread
	STR r1, [r2]
	BX	lr
	ENDP

; /*
; * void rt_hw_context_switch_interrupt_do(rt_base_t flag)
; */
rt_hw_context_switch_interrupt_do	PROC
	EXPORT rt_hw_context_switch_interrupt_do
	MOV		r1,  #0			; clear flag
	STR		r1,  [r0]

	LDMFD	sp!, {r0-r12,lr}; reload saved registers
	STMFD	sp!, {r0-r3}	; save r0-r3
	MOV		r1,  sp
	ADD		sp,  sp, #16	; restore sp
	SUB		r2,  lr, #4		; save old task's pc to r2

	MRS		r3,  spsr		; get cpsr of interrupt thread

	; switch to SVC mode and no interrupt
	MSR     cpsr_c, #I_Bit:OR:F_Bit:OR:Mode_SVC

	STMFD	sp!, {r2}		; push old task's pc
	STMFD	sp!, {r4-r12,lr}; push old task's lr,r12-r4
	MOV		r4,  r1			; Special optimised code below
	MOV		r5,  r3
	LDMFD	r4!, {r0-r3}
	STMFD	sp!, {r0-r3}	; push old task's r3-r0
	STMFD	sp!, {r5}		; push old task's cpsr

	LDR		r4,  =rt_interrupt_from_thread
	LDR		r5,  [r4]
	STR		sp,  [r5]		; store sp in preempted tasks's TCB

	LDR		r6,  =rt_interrupt_to_thread
	LDR		r6,  [r6]
	LDR		sp,  [r6]		; get new task's stack pointer
	
	LDMFD   sp!, {r4}       ; pop new task's cpsr to spsr
	MSR		spsr_cxsf, r4
	BIC     r4, r4, #0x20   ; must be ARM mode
	MSR		cpsr_cxsf, r4

	LDMFD   sp!, {r0-r12,lr,pc}^ ; pop new task's r0-r12,lr & pc, copy spsr to cpsr
	ENDP

	END