;/*
; * File      : context_rvds.S
; * This file is part of RT-Thread RTOS
; * COPYRIGHT (C) 2009, 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
; * 2010-01-25     Bernard      first version
; */

;/**
; * @addtogroup LPC1100
; */
;/*@{*/

NVIC_INT_CTRL   EQU     0xE000ED04               ; interrupt control state register
NVIC_SYSPRI2    EQU     0xE000ED20               ; system priority register (2)
NVIC_PENDSV_PRI EQU     0x00FF0000               ; PendSV priority value (lowest)
NVIC_PENDSVSET  EQU     0x10000000               ; value to trigger PendSV exception

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

	IMPORT rt_thread_switch_interrput_flag
	IMPORT rt_interrupt_from_thread
	IMPORT rt_interrupt_to_thread

;/*
; * rt_base_t rt_hw_interrupt_disable();
; */
rt_hw_interrupt_disable    PROC
	EXPORT  rt_hw_interrupt_disable
	MRS		r0, PRIMASK
	CPSID   I
	BX		LR
	ENDP

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

;/*
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
; * r0 --> from
; * r1 --> to
; */
rt_hw_context_switch_interrupt
	EXPORT rt_hw_context_switch_interrupt
rt_hw_context_switch    PROC
	EXPORT rt_hw_context_switch

	; set rt_thread_switch_interrput_flag to 1
	LDR 	r2, =rt_thread_switch_interrput_flag
	LDR 	r3, [r2]
	CMP 	r3, #1
	BEQ 	_reswitch
	MOVS 	r3, #0x1
	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]

    LDR     r0, =NVIC_INT_CTRL      		; trigger the PendSV exception (causes context switch)
    LDR     r1, =NVIC_PENDSVSET
	STR     r1, [r0]
	BX      LR
	ENDP

; r0 --> swith from thread stack
; r1 --> swith to thread stack
; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
rt_hw_pend_sv	PROC
	EXPORT rt_hw_pend_sv

	; disable interrupt to protect context switch
	MRS		r2, PRIMASK
	CPSID   I

	; get rt_thread_switch_interrupt_flag
	LDR		r0, =rt_thread_switch_interrput_flag
	LDR		r1, [r0]
	CMP		r1, #0x00
	BEQ		pendsv_exit				; pendsv already handled

	; clear rt_thread_switch_interrput_flag to 0
	MOVS	r1, #0x00
	STR		r1, [r0]

	LDR		r0, =rt_interrupt_from_thread
	LDR		r1, [r0]
	CMP		r1, #0x00
	BEQ		swtich_to_thread    	; skip register save at the first time

	MRS     r1, psp                 ; get from thread stack pointer
	SUBS	r1, r1, #0x10
	LDR		r0, [r0]
	STR		r1, [r0]				; update from thread stack pointer
	STMIA	r1!, {r4 - r7}			; push r4 - r7 register

swtich_to_thread
	LDR		r1, =rt_interrupt_to_thread
	LDR		r1, [r1]
	LDR		r1, [r1]				; load thread stack pointer

	LDMIA	r1!, {r4 - r7}			; pop r4 - r7 register
	MSR		psp, r1					; update stack pointer

pendsv_exit
	; restore interrupt
	MSR		PRIMASK, r2

	MOVS	r0, #0x04
	RSBS	r0, #0
	BX		r0
	ENDP

;/*
; * void rt_hw_context_switch_to(rt_uint32 to);
; * r0 --> to
; * this fucntion is used to perform the first thread switch
; */
rt_hw_context_switch_to    PROC
	EXPORT rt_hw_context_switch_to
	; set to thread
	LDR		r1, =rt_interrupt_to_thread
	STR		r0, [r1]

	; set from thread to 0
	LDR		r1, =rt_interrupt_from_thread
	MOVS	r0, #0x0
	STR		r0, [r1]

	; set interrupt flag to 1
	LDR 	r1, =rt_thread_switch_interrput_flag
	MOVS 	r0, #1
	STR 	r0, [r1]

	; set the PendSV exception priority
    ; LDR     r0, =NVIC_SYSPRI2
    ; LDR     r1, =NVIC_PENDSV_PRI
    ; STR     r1, [r0]

	; trigger the PendSV exception (causes context switch)
    LDR     r0, =NVIC_INT_CTRL
    LDR     r1, =NVIC_PENDSVSET
    STR     r1, [r0]

	; enable interrupts at processor level
    CPSIE   I

	; never reach here!
	ENDP

; compatible with old version
rt_hw_interrupt_thread_switch PROC
	EXPORT rt_hw_interrupt_thread_switch
	BX		lr
	ENDP

	END