⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 os_cpu_a.s

📁 The latest release, ver 1.16 of the ARM (7TDMI, 720T, 920T) port for uC/OS-II V2.61 (and higher) inc
💻 S
字号:
/*
*********************************************************************************************************
*                                               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              : http://geocities.com/michaelanburaj/    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
        mov r1,#1
        str r1,[r0]
        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}

        bl OSIntEnter
        bl C_IRQHandler
        bl OSIntExit

        // Is OSIntCtxSwFlag == True ?
        ldr r0,=OSIntCtxSwFlag
        ldr r1,[r0]
        cmp r1,#1
        beq _IntCtxSw

		ldmfd sp!,{r0-r3,r12,pc}^


_IntCtxSw:
        // OSIntCtxSwFlag = False
        mov r1,#0
        str r1,[r0]

        // Get old task's sp & lr
        mrs r0,spsr
        orr r0,r0,#NOINT
        bic r0,r0,#TBIT
        msr cpsr_c,r0
        mov r1,sp
        mov r2,lr
        bic r0,r0,#MODEMASK
        orr r0,r0,#IRQMODE
        msr cpsr_c,r0

        // Unwind IRQ's sp without poping r0-r3
        mov r3,sp
        add sp,sp,#(4*4)
        ldmfd sp!,{r12,lr}

        stmfd r1!,{r2,lr}           // push old task's pc & lr
        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
        ldr r5,[r4]
        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]
        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

        // Leave IRQ mode
        orr r0,r4,#NOINT
        bic r0,r0,#TBIT
        msr cpsr_c,r0

        msr spsr_cxsf,r4
        mov sp,r5

        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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -