Chinaunix首页 | 论坛 | 博客
  • 博客访问: 721339
  • 博文数量: 124
  • 博客积分: 3156
  • 博客等级: 中校
  • 技术积分: 1584
  • 用 户 组: 普通用户
  • 注册时间: 2008-08-02 10:29
文章分类

全部博文(124)

文章存档

2012年(3)

2011年(2)

2010年(61)

2009年(34)

2008年(24)

我的朋友

分类: LINUX

2009-04-30 17:39:18

/*
*********************************************************************************************************
*                                               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
 
阅读(1907) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~