📄 os_cpu_a.s
字号:
#------------------------------------------------------------------------------
#- File: os_cpu_a.s
#------------------------------------------------------------------------------
#- (c) Copyright ARM Limited 1999. All rights reserved.
#-
#- ARM Specific code
#------------------------------------------------------------------------------
#-
#-
#- Functions defined in this module:
#-
#- void ARMDisableInt(void) disable interrupts when in SVC
#- void ARMEnableInt(void) enable interrupts when in SVC
#- void OS_TASK_SWAP(void) context switch
#- void OSStartHighRdy(void) start highest priority task
.include "asmdef.a"
.EQU SwiV, 0x08
.EQU IrqV, 0x18
.EQU FiqV, 0x1C
.EQU NoInt, 0x80
.EQU INTPEND, 0x03FF4004
.EQU BIT_TIMER0, (0x1<<10)
.EQU SVC32Mode, 0x13
.EQU IRQ32Mode, 0x12
.EQU FIQ32Mode, 0x11
.EQU OSEnterSWI, 0x00
.EQU INTMSK, 0x1e0000c
# AREA |subr|, CODE, READONLY
# External symbols we need the addresses of
.EXTERN OSTCBCur
addr_OSTCBCur: .LONG OSTCBCur
.EXTERN OSTCBHighRdy
addr_OSTCBHighRdy: .LONG OSTCBHighRdy
.EXTERN OSPrioCur
addr_OSPrioCur: .LONG OSPrioCur
.EXTERN OSPrioHighRdy
addr_OSPrioHighRdy: .LONG OSPrioHighRdy
.EXTERN OSIntNesting
addr_OSIntNesting: .LONG OSIntNesting
.EXTERN OSTimeTick
.EXTERN ISR_IrqHandler
.EXTERN OSIntEnter
.EXTERN OSIntExit
.EXTERN OutDebug
.EXTERN BreakPoint
# .GLOBAL TickHandler
#TickHandler:
.GLOBAL ArmIRQIsr
ArmIRQIsr:
STMDB sp!,{r0-r11,lr}
#IMPORTANT CAUTION
#Reseted!INTOFFSET'value is 0x000054.
ldr r8,=INTOFFSET_ADDR
ldr r8,[r8]
cmp r8, #0x00054 /* If all interrupt pending bits are "0", */
/* r8 may be 0x00054 sometimes. */
# beq HAVE_NOPENDING
bne HAVE_PENDING
HAVE_NOPENDING:
LDMIA sp!,{r0-r11,lr}
subs pc,lr,#4
HAVE_PENDING:
mov r8, r8, lsr #2
str r8, INTR_OFFSET @STR OFFSET
#clear pend bit
mov r9, #0x1
mov r9, r9, lsl r8
# mov r8, r8, lsl #2
LDR r10, =INTPEND
STR r9, [r10]
#interrupt disable(not nessary)
# mrs r0, CPSR
# orr r0, r0, #0x80 @ and set IRQ disable flag
# msr CPSR_cxsf, r0
#End of interrupt
#(Clear pending bit of INTPEND that don't accessed it.)
# rI_ISPC= BIT_TIMER0;
# LDR r0, =INTPEND
# LDR r1, =BIT_TIMER0
# STR r1, [r0]
#now context switching
LDMIA sp!,{r0-r11,lr}
SUB lr, lr, #4
STR lr, SAVED_LR @STR lr, [pc, #SAVED_LR-.-8]
#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#Change Supervisor mode
#!!!r12 register don't preserved. (r12 that PC of task)
MRS lr, SPSR
AND lr, lr, #0xFFFFFFE0
ORR lr, lr, #0x13
MSR CPSR_cxsf, lr
#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#Now Supervisor mode
#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
STR r12, [sp, #-8] @ saved r12
LDR r12, SAVED_LR @LDR r12, [pc, #SAVED_LR-.-8]
STMFD sp!, {r12} @ r12 that PC of task
SUB sp, sp, #4 @ inclease stack point
LDMIA sp!, {r12} @ restore r12
STMFD sp!, {lr} @ save lr
STMFD sp!, {r0-r12} @ save register file and ret address
MRS r4, CPSR
STMFD sp!, {r4} @ save current PSR
MRS r4, SPSR @ YYY+
STMFD sp!, {r4} @ YYY+ save SPSR
BL OSIntEnter
# OSIntNesting == 1?
LDR r4, addr_OSIntNesting
LDR r5, [r4]
CMP r5, #1
LDRNE pc, =INTR_NESTING
@ Get current task TCB address and save current task stack pointer
LDR r4, addr_OSTCBCur
LDR r5, [r4]
STR sp, [r5] @ store sp in preempted tasks's TCB
INTR_NESTING:
ldr a1, INTR_OFFSET @LDR a1, [pc, #INTR_OFFSET-.-8]
bl ISR_IrqHandler
BL OSIntExit
# CMP a1, #0
# LDRNE pc, =_CON_SWAP
#_NOT_CON_SWAP:
#not context switching
# LDMIA sp!,{r0-r11, lr}
# SUBS pc, lr, #4
#_CON_SWAP:
# OSPrioCur = OSPrioHighRdy
# LDR r4, addr_OSPrioCur
# LDR r5, addr_OSPrioHighRdy
# LDRB r6, [r5]
# STRB r6, [r4]
# Get current task TCB address
# LDR r4, addr_OSTCBCur
# LDR r5, [r4]
## STR sp, [r5] @ store sp in preempted tasks's TCB
# Get highest priority task TCB address
# LDR r6, addr_OSTCBHighRdy
# LDR r6, [r6]
# LDR sp, [r6] @ get new task's stack pointer
# OSTCBCur = OSTCBHighRdy
# STR r6, [r4] @ set new current task TCB address
_NO_CONSWAP:
LDMFD sp!, {r4} @ YYY+
MSR SPSR_cxsf, r4 @ YYY+
LDMFD sp!, {r4} @ YYY+
MSR CPSR_cxsf, r4 @ YYY+
LDMFD sp!, {r0-r12, lr, pc} @ YYY+
SAVED_LR: .LONG 0
INTR_OFFSET: .LONG 0
.GLOBAL OSIntCtxSw
OSIntCtxSw:
# OSPrioCur = OSPrioHighRdy
LDR r4, addr_OSPrioCur
LDR r5, addr_OSPrioHighRdy
LDRB r6, [r5]
STRB r6, [r4]
# Get current task TCB address
LDR r4, addr_OSTCBCur
LDR r5, [r4]
# STR sp, [r5] @ store sp in preempted tasks's TCB
# Get highest priority task TCB address
LDR r6, addr_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} @ YYY+
MSR SPSR_cxsf, r4 @ YYY+
LDMFD sp!, {r4} @ YYY+
MSR CPSR_cxsf, r4 @ YYY+
LDMFD sp!, {r0-r12, lr, pc} @ YYY+
#SAVED_LR: .LONG 0
# void DisableInt(void)
# void EnableInt(void)
#
# Disable and enable IRQ and FIQ preserving current CPU mode.
#
.GLOBAL ARMDisableInt
ARMDisableInt:
STMDB sp!, {r0}
MRS r0, CPSR
ORR r0, r0, #NoInt
MSR CPSR_cxsf, r0
LDMIA sp!, {r0}
MOV pc, lr
.GLOBAL ARMEnableInt
ARMEnableInt:
STMDB sp!, {r0}
MRS r0, CPSR
BIC r0, r0, #NoInt
MSR CPSR_cxsf, r0
LDMIA sp!, {r0}
MOV pc, lr
.GLOBAL ARMIsDisableInt
ARMIsDisableInt: @return value [disable: 1 enable: 0]
MRS a1, CPSR
AND a1, a1, #NoInt
MOV pc, lr
# void OS_TASK_SW(void)
#
# Perform a context switch.
#
# On entry, OSTCBCur and OSPrioCur hold the current TCB and priority
# and OSTCBHighRdy and OSPrioHighRdy contain the same for the task
# to be switched to.
#
# The following code assumes that the virtual memory is directly
# mapped into physical memory. If this is not true, the cache must
# be flushed at context switch to avoid address aliasing.
.GLOBAL OSCtxSw
OSCtxSw:
STMFD sp!, {lr} @ save pc
STMFD sp!, {lr} @ save lr
STMFD sp!, {r0-r12} @ save register file and ret address
MRS r4, CPSR
STMFD sp!, {r4} @ save current PSR
MRS r4, SPSR @ YYY+
STMFD sp!, {r4} @ YYY+ save SPSR
# OSPrioCur = OSPrioHighRdy
LDR r4, addr_OSPrioCur
LDR r5, addr_OSPrioHighRdy
LDRB r6, [r5]
STRB r6, [r4]
@ Get current task TCB address and save current task stack pointer
LDR r4, addr_OSTCBCur
LDR r5, [r4]
STR sp, [r5] @ store sp in preempted tasks's TCB
# Get highest priority task TCB address
LDR r6, addr_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} @ YYY+
MSR SPSR_cxsf, r4 @ YYY+
LDMFD sp!, {r4} @ YYY+
MSR CPSR_cxsf, r4 @ YYY+
LDMFD sp!, {r0-r12, lr, pc} @ YYY+
# void OSStartHighRdy(void)
#
# Start the task with the highest priority;
#
.GLOBAL OSStartHighRdy
OSStartHighRdy:
LDR r4, addr_OSTCBCur @ Get current task TCB address
LDR r5, addr_OSTCBHighRdy @ Get highest priority task TCB address
LDR r5, [r5] @ get stack pointer
LDR sp, [r5] @ switch to the new stack
STR r5, [r4] @ set new current task TCB address
LDMFD sp!, {r4} @ YYY
MSR SPSR_cxsf, r4
LDMFD sp!, {r4} @ get new state from top of the stack
MSR CPSR_cxsf, r4 @ CPSR should be SVC32Mode
LDMFD sp!, {r0-r12, lr, pc } @ start the new task
.END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -