?? os_cpu_a.asm
字號:
/*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; $Workfile: os_cpu_a.asm $
; $Revision: 1.0 $
; $Author: WellsK $
; $Date: Sep 09 2003 14:55:46 $
;
; Project: Lh7A400 MicroCos-II assembly code
;
; Description:
; Assembly language files for the MicroCos-II OS and the LH7A400
; port. (This file is used with the GNU assembler)
;
; Revision history:
; $Log: //smaicnt2/pvcs/VM/sharpmcu/archives/sharpmcu/software/csps/lh7a404/ports/ucosii/os_cpu_a.asm-arc $
;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; SHARP MICROELECTRONICS OF THE AMERICAS MAKES NO REPRESENTATION
; OR WARRANTIES WITH RESPECT TO THE PERFORMANCE OF THIS SOFTWARE,
; AND SPECIFICALLY DISCLAIMS ANY RESPONSIBILITY FOR ANY DAMAGES,
; SPECIAL OR CONSEQUENTIAL, CONNECTED WITH THE USE OF THIS SOFTWARE.
;
; SHARP MICROELECTRONICS OF THE AMERICAS PROVIDES THIS SOFTWARE SOLELY
; FOR THE PURPOSE OF SOFTWARE DEVELOPMENT INCORPORATING THE USE OF A
; SHARP MICROCONTROLLER OR SYSTEM-ON-CHIP PRODUCT. USE OF THIS SOURCE
; FILE IMPLIES ACCEPTANCE OF THESE CONDITIONS.
;
; COPYRIGHT (C) 2001 SHARP MICROELECTRONICS OF THE AMERICAS, INC.
; CAMAS, WA
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*/
.global ucos_irq_handler
.global OSStartHighRdy
.global OS_TASK_SW
.global OSCtxSw
.global OSIntCtxSw
.global OSRunning
.global OSTaskSwHook
.global OSTCBHighRdy
.global OSTCBCur
.global OSPrioHighRdy
.global OSPrioCur
.global OSIntNesting
.global OSIntEnter
.global OSTimeTick
.global OSIntExit
.global irq_func_ptrs
/*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Private defines and data
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*/
.EQU MODE_SVC, 0x00000013
.EQU MODE_DIS_IRQ, 0x00000080
.EQU INTC_BASE_ADDR, 0x80000500
.EQU INTC_SOURCE_OFF, 0x00000000
.EQU INTC_TIMER1_INT_MASK, 0x00000100
.EQU TIMER1_INT_CLR, 0x80000C0C
.EQU INTC_FIRST_IRQ, 5
.text
.code 32
.align 2
/*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Function: OSStartHighRdy
;
; Purpose: Set highest priority uCos-II task ready to run
;
; Description:
; Call the OSTaskSwHook() function. Set OSRunning to TRUE. Get the
; address of the highest priority task control block. Get the
; stack pointer for the highest prior task (from the fetched TCB).
; Set the current stack pointer to the fetched stack pointer. Set
; the current task control block pointer to the highest priority
; task control block pointer. Restore the new task's SPSR and CPSR
; registers. Restore all ARM registers for the task and continue
; the task.
;
; Parameters: NA
;
; Outputs; NA
;
; Returns: NA
;
; Notes: This function should never be called from the IRQ level.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*/
OSStartHighRdy:
BL OSTaskSwHook /* Call OSTaskSwHook */
LDR r0, =OSRunning
MOV r1, #1
STRB r1, [r0] /* OSRunning = TRUE */
LDR r0, =OSTCBHighRdy /* Get highest priority TCB */
LDR r0, [r0] /* Get waiting task TCB address */
LDR sp, [r0] /* Switch to the new task stack */
B OSCtxSw_from_start /* Start first task */
/*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Function: OS_TASK_SW (also known as OSCtxSw)
;
; Purpose: Task level context switch
;
; Description:
; Save the current task registers and status on the task stack.
; Save the current task stack pointer in the current TCB. Call
; the OSTaskSwHook() function. Set OSPrioCur = OSPrioHighRdy.
; Branch to the switch_tcb() function to restore the context of
; the new task.
;
; Parameters: NA
;
; Outputs; NA
;
; Returns: NA
;
; Notes: This function should never be called from the IRQ level.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*/
OS_TASK_SW:
OSCtxSw:
STMFD sp!, {lr} /* Save resume address */
STMFD sp!, {r0-r12, lr} /* Save current task registers */
MRS r0, cpsr
STMFD sp!, {r0} /* Save current CPSR */
LDR r0, =OSTCBCur
LDR r0, [r0] /* Get pointer to current TCB */
STR sp, [r0] /* Save stack ptr of cur task */
BL OSTaskSwHook /* Call OSTaskSwHook */
OSCtxSw_from_int:
LDR r0, =OSTCBHighRdy /* Get highest priority TCB */
LDR r2, [r0] /* Get waiting task TCB addr */
LDR r0, =OSTCBCur /* Get current TCB */
STR r2, [r0] /* OSTCBCur = OSTCBHighRdy */
LDR sp, [r2] /* Get new task stack pointer */
LDR r0, =OSPrioHighRdy /* Get highest priority addr */
LDRB r1, [r0] /* Get highest priority */
LDR r0, =OSPrioCur /* Get current priority addr */
STRB r1, [r0] /* OSPrioCur = OSPrioHighRdy */
OSCtxSw_from_start:
LDMFD sp!, {r0} /* Get CPSR val - this will be */
MSR spsr_cf, r0 /* restored on function resume */
LDMFD sp!, {r0-r12, lr, pc}^ /* Load task registers and
continue task */
/*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Function: OSTickISR
;
; Purpose: OS timer tick
;
; Description:
; See function comments.
;
; Parameters: NA
;
; Outputs; NA
;
; Returns: NA
;
; Notes:
; This function will always be called from ucos_irq_handler() on
; a timer interrupt. All other interrupts are handled directly in
; the ucos_irq_handler() function.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*/
OSTickISR:
/* At this point, the real handling of the interrupt is done and the
context change for the task and ARM core may need to be done. The ARM
core is presently in the ARM IRQ mode and may have nested interrupts.
Call the OSIntEnter(), OSTimeTick(), and OSIntExit() functions. */
BL OSIntEnter /* Call OSIntEnter() */
BL OSTimeTick /* Call OSTimeTick() */
BL OSIntExit /* Call OSIntExit() */
/* A task context is not needed if the current and highest priority
tasks are the same. Check the TCB pointers. If they are the same,
just return from the interrupt and continue the task that was
already running. */
LDR r8, =OSTCBCur
LDR r9, =OSTCBHighRdy
LDR r8, [r8]
LDR r9, [r9]
CMP r8, r9 /* Are current and next TCB's */
/* the same? */
BEQ no_switch /* If the same, then just exit
IRQ */
/* The ARM core is still in IRQ mode. The task's r0-12 registers and the
task resume address (lr) are saved on the IRQ mode stack, but need to
be saved on the task's stack. The task's original link register (lr
in the task's mode) and the task's ARM core mode (CSPR) also need to
be saved on the task's stack). */
BL OSTaskSwHook /* Call OSTaskSwHook() */
MRS r0, spsr /* Get interrupted task's mode */
STMFD sp!, {r0} /* Save task's CPSR on IRQ
stack */
/* so task mode can use it */
/* Restore the IRQ stack pointer */
ADD sp, sp, #4 /* Restore stack ptr from CPSR */
LDMFD sp!, {r0-r12, lr} /* Restore regs to task state */
/* Go into task mode with interrupts disabled */
MRS r0, spsr /* Get interrupted task's mode */
ORR r0, r0, #MODE_DIS_IRQ /* Disable ints in task mode */
MOV r1, sp /* Get IRQ stack pointer - this is
need for task mode */
MSR cpsr_cf, r0 /* Switch to task mode with
interrupts disabled */
/* Get task's PC from IRQ stack */
LDR r0, [r1, #-4] /* Get task's resume address */
STMFD sp!, {r0} /* Save resume address */
STMFD sp!, {r2-r12, lr} /* Save task's registers */
LDR r0, [r1, #-60] /* Get task's CPSR */
LDR r2, [r1, #-52] /* Restore task's r1 */
LDR r1, [r1, #-56] /* Restore task's r0 */
STMFD sp!, {r0-r2} /* Save r0, r1, and CPSR */
/* The task state is now saved on the task stack. Adjsut the stack size
by one more word to account for the saved resume address and save
the task stack pointer */
LDR r0, =OSTCBCur
LDR r0, [r0] /* Get pointer to current TCB */
STR sp, [r0] /* Save stack ptr of cur task */
B OSCtxSw_from_int /* Switch to new task */
no_switch:
LDMFD sp!, {r0-r12, pc}^ /* Restore and exit */
/*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Function: OSIntCtxSw
;
; Purpose: OS interrupt level task context switch
;
; Description:
; This function does nothing. The real interrupt level task context
; switch is done after the return from the OSIntExit() function in
; OSTickISR() function. It's a bit easier to do it there, makes
; register restoration easier, and the IRQ mode stack pointer is
; already in the correct position. The call to OSTaskSwHook() is
; still performed here.
;
; Parameters: NA
;
; Outputs; NA
;
; Returns: NA
;
; Notes:
; This function is called from OSIntExit() to perform a task level
; context switch.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*/
OSIntCtxSw:
MOV pc, lr
/*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Function: ucos_irq_handler
;
; Purpose: Main interrupt (IRQ) handler for uCos-II
;
; Description:
; See function comments.
;
; Parameters: NA
;
; Outputs; NA
;
; Returns: NA
;
; Notes:
; This function works with the LH7A400 interrupt driver and uses
; data initialized and maintained with that driver.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*/
ucos_irq_handler:
/* Save registers we use for the interrupt */
SUB lr, lr, #4 /* Adjust lr to real ret addr */
STMFD sp!, {r0-r12, lr}
/* Read the interrupt controller pending register */
LDR r1, =INTC_BASE_ADDR
LDR r0, [r1, #INTC_SOURCE_OFF]
/* Was it a timer 1 interrupt? */
LDR r2, =INTC_TIMER1_INT_MASK
AND r3, r0, r2 /* Mask off timer 1 int bit */
CMP r3, r2 /* Was it a timer 1 interrupt? */
BNE intc_not_timer /* Not a timer interrupt */
/* This was a timer interrupt, so clear the timer and perform ThreadX
context switching */
LDR r3, =TIMER1_INT_CLR /* Timer 1 interrupt clear addr */
STR r0, [r3] /* Clear the timer 1 interrupt */
B OSTickISR /* Perform OS timer tick */
intc_not_timer:
/* Loop through all the enabled interrupts and jump to the function
for the first pending interrupt */
LDR r1, =INTC_FIRST_IRQ /* Get first interrupt to check */
MOV r2, #0x00000001 /* Interrupt bit mask */
/* Start checking pending interrupt states */
int_check:
MOV r3, r2, LSL r1 /* Build interrupt mask */
AND r4, r0, r3 /* Check just one bit at a time */
CMP r4, r3 /* Is interrupt pending? */
BEQ int_found /* Int was found, handle it */
ADD r1, r1, #1 /* Check next interrupt bit */
CMP r1, #0x1F /* Was this the last interrupt? */
BLE int_check /* Check next interrupt */
/* If the program made it to here, then the interrupt was not found,
so just return to the caller, as we can do nothing */
int_not_found:
B int_exit
/* A pending interrupt was found, so jump to it's handler */
int_found:
LDR r0, =irq_func_ptrs /* Get address of jump table */
ADD r0, r0, r1, LSL #2 /* Add by interrupt offset */
LDR r0, [r0] /* Get handler address */
CMP r0, #0 /* Is handler address NULL? */
BEQ int_exit /* If null, the exit */
MOV lr, pc /* Will return to int_exit */
/* handler, best to save all */
/* regs, so none get corrupted */
MOV pc, r0 /* Jump to handler */
/* Exit the interrupt function */
int_exit:
LDMFD sp!, {r0-r12, pc}^ /* Restore and exit */
.end
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -