/*
*********************************************************************************************************
* uC/OS-II
* The Real-Time Kernel
*
* (c) Copyright 1992-2002, Jean J. Labrosse, Weston, FL
* All Rights Reserved
*
* File : OS_CPU_A.ASM
* By : Jean J. Labrosse
*********************************************************************************************************
*********************************************************************************************************
* ARM Port
*
* Target : ARM (Includes ARM7, ARM9)
* Ported by : Michael Anburaj
* URL : Email : michaelanburaj@hotmail.com
*
*********************************************************************************************************
*/
//Pre-defined constants
#define USERMODE 0x10
#define FIQMODE 0x11
#define IRQMODE 0x12
#define SVCMODE 0x13
#define ABORTMODE 0x17
#define UNDEFMODE 0x1b
#define MODEMASK 0x1f
#define NOINT 0xc0
#define TBIT 0x20
//*********************************************************************************************************
// START MULTITASKING
// void OSStartHighRdy(void)
//
// Note : OSStartHighRdy() MUST:
// a) Call OSTaskSwHook() then,
// b) Set OSRunning to TRUE,
// c) Switch to the highest priority task.
//*********************************************************************************************************
.global OSStartHighRdy
OSStartHighRdy:
bl OSTaskSwHook // Call user defined task switch hook
ldr r4,=OSRunning // Indicate that multitasking has started
mov r5,#1
strb r5,[r4]
ldr r4,=OSTCBHighRdy // Get highest priority task TCB address
ldr r4,[r4] // get stack pointer
ldr sp,[r4] // switch to the new stack
ldmfd sp!,{r4} // pop new task's spsr
ldmfd sp!,{r4} // pop new task's psr
msr SPSR_cxsf,r4
ldmfd sp!,{r0-r12,lr,pc}^ // pop new task's r0-r12,lr & pc
//*********************************************************************************************************
// PERFORM A CONTEXT SWITCH (From task level)
// void OSCtxSw(void)
//
// Note(s): Upon entry,
// OSTCBCur points to the OS_TCB of the task to suspend
// OSTCBHighRdy points to the OS_TCB of the task to resume
//
//*********************************************************************************************************
.global OSCtxSw
OSCtxSw:
// Special optimised code below:
stmfd sp!,{lr} // push pc (lr should be pushed in place of PC)
ldr lr,=0xdead1eaf // Just a dummy value is pushed for lr (for actual lr is safe inside callers stack)
stmfd sp!,{r0-r12,lr} // push lr & register file
mrs r4,cpsr
#ifdef THUMB_TASKS
orr r4,r4,#TBIT
#endif
stmfd sp!,{r4} // push current psr
mrs r4,spsr
stmfd sp!,{r4} // push current spsr
// OSPrioCur = OSPrioHighRdy
ldr r4,=OSPrioCur
ldr r5,=OSPrioHighRdy
ldrb r6,[r5]
strb r6,[r4]
// Get current task TCB address
ldr r4,=OSTCBCur
ldr r5,[r4]
str sp,[r5] // store sp in preempted tasks's TCB
bl OSTaskSwHook // call Task Switch Hook
// Get highest priority task TCB address
ldr r6,=OSTCBHighRdy
ldr r6,[r6]
ldr sp,[r6] // get new task's stack pointer
// OSTCBCur = OSTCBHighRdy
str r6,[r4] // set new current task TCB address
ldmfd sp!,{r4} // pop new task's spsr
ldmfd sp!,{r4} // pop new task's psr
msr SPSR_cxsf,r4
ldmfd sp!,{r0-r12,lr,pc}^ // pop new task's r0-r12,lr & pc
//*********************************************************************************************************
// PERFORM A CONTEXT SWITCH (From an ISR)
// void OSIntCtxSw(void)
//
// Note(s): This function only flags a context switch to the ISR Handler
//
//*********************************************************************************************************
.global OSIntCtxSw
OSIntCtxSw:
//OSIntCtxSwFlag = True
ldr r0,=OSIntCtxSwFlag //R0=&OSIntCtxSwFlag;取地址
mov r1,#1
str r1,[r0] //OSIntCtxSwFlag = 0
bx lr
//*********************************************************************************************************
// IRQ HANDLER
//
// This handles all the IRQs
// Note: FIQ Handler should be written similar to this
//
//*********************************************************************************************************
.global UCOS_IRQHandler
UCOS_IRQHandler:
// Fix the return address
sub lr,lr,#4
stmfd sp!,{r0-r3,r12,lr} //R4~R11 没有用到,用到了也会自动保护
bl OSIntEnter
bl C_IRQHandler //OSTick()函数中会确定OSIntCtxSwFlag的值。
bl OSIntExit
// Is OSIntCtxSwFlag == True ?
ldr r0,=OSIntCtxSwFlag
ldr r1,[r0]
cmp r1,#1 //OSIntCtxSwFlag=1的话就进行任务切换。
beq _IntCtxSw
ldmfd sp!,{r0-r3,r12,pc}^ //没有切换会运行这段代码。
_IntCtxSw:
// OSIntCtxSwFlag = False
mov r1,#0
str r1,[r0] //OSIntCtxSwFlag = 0;清零
// Get old task's sp & lr
mrs r0,spsr //读apsr物理状态寄存器。
orr r0,r0,#NOINT //或;
bic r0,r0,#TBIT //位清除;
msr cpsr_c,r0 //写状态寄存器,模式切换,irq-->usr
mov r1,sp //R1=(old task's)sp
mov r2,lr //R2=(old tasks's)lr
bic r0,r0,#MODEMASK //
orr r0,r0,#IRQMODE //
msr cpsr_c,r0 //模式切换,usr-->irq
// Unwind IRQ's sp without poping r0-r3
mov r3,sp //保存IRQ模式下的SP
add sp,sp,#(4*4) //不弹R0~R3
ldmfd sp!,{r12,lr} //弹出R12_usr和LR_usr ,
/////////////////////////////////////////////////////////////////////////////////////////////
stmfd r1!,{r2,lr} //R1=old task's SP;r2=old task's lr;lr =old task's pc
//保存老任务的lr 和 PC 到老任务的栈中
stmfd r1!,{r4-r12} //push old task's r12-r4
// Get r0-r3 from IRQ's stack
mov r6,r1
ldmfd r3,{r0-r3}
stmfd r6!,{r0-r3} // push old task's r3-r0
mrs r3,spsr
stmfd r6!,{r3} // push old task's psr
stmfd r6!,{r3} // push old task's spsr (don't care)
///////////////////////////////////以上是保存现场///////////////////////////////////////////
// OSPrioCur = OSPrioHighRdy
ldr r4,=OSPrioCur
ldr r5,=OSPrioHighRdy
ldrb r5,[r5]
strb r5,[r4]
// Get current task's TCB address
ldr r4,=OSTCBCur //从TCB结构体可以看出:
ldr r5,[r4] //OSTCBCur的地址也是OSTCBCur->OSTCBStkPtr的地址
str r6,[r5] // store sp in preempted tasks's TCB
bl OSTaskSwHook // call Task Switch Hook
// Get highest priority task's TCB address
ldr r6,=OSTCBHighRdy
ldr r6,[r6] ////OSTCBCur的地址也是OSTCBCur->OSTCBStkPtr的地址
ldr r5,[r6] // get new task's stack pointer
// OSTCBCur = OSTCBHighRdy
str r6,[r4] // set new current task TCB address
ldmfd r5!,{r4} // pop new task's spsr (don't care)
ldmfd r5!,{r4} // pop new task's psr 并放到R4中
// Leave IRQ mode
orr r0,r4,#NOINT //利用R4转到usr模式
bic r0,r0,#TBIT
msr cpsr_c,r0
msr spsr_cxsf,r4
mov sp,r5 //sp=new task's sp;
ldmfd sp!,{r0-r12,lr,pc}^ // pop new task's r0-r12,lr & pc
/////////////////////////////////新任务运行///////////////////////////////////////////////////
//*********************************************************************************************************
// CRITICAL SECTION METHOD 3 FUNCTIONS
//
// Description: Disable/Enable interrupts by preserving the state of interrupts. Generally speaking you
// would store the state of the interrupt disable flag in the local variable 'cpu_sr' and then
// disable interrupts. 'cpu_sr' is allocated in all of uC/OS-II's functions that need to
// disable interrupts. You would restore the interrupt disable state by copying back 'cpu_sr'
// into the CPU's status register.
//
// OS_CPU_SR OSCPUSaveSR()
// Arguments : none
//
// Returns : OS_CPU_SR
//
// OSCPURestoreSR(OS_CPU_SR cpu_sr)
// Arguments : OS_CPU_SR
//
// Returns : none
//
// Note(s) : These functions are used in general like this,
//
// void Task (void *data)
// {
// #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
// OS_CPU_SR cpu_sr;
// #endif
// :
// :
// OS_ENTER_CRITICAL(); /* cpu_sr = OSCPUSaveSR(); */
// :
// :
// OS_EXIT_CRITICAL(); /* OSCPURestoreSR(cpu_sr); */
// :
// :
// }
//*********************************************************************************************************
.global OSCPUSaveSR
OSCPUSaveSR:
mrs r0,CPSR
orr r1,r0,#NOINT
msr CPSR_c,r1
bx lr
.global OSCPURestoreSR
OSCPURestoreSR:
msr CPSR_c,r0
bx lr
阅读(2002) | 评论(0) | 转发(0) |