📄 os_cpu_a.s
字号:
AREA |subr|, CODE, READONLY
AIC_BASE EQU 0xFFFFF000
AIC_IVR EQU 0x94
AIC_EOICR EQU 0x130
TC1_BASE EQU 0xFFFE0040
ARM_MODE_USER EQU 0x10
ARM_MODE_FIQ EQU 0x11
ARM_MODE_IRQ EQU 0x12
ARM_MODE_SVC EQU 0x13
ARM_MODE_ABORT EQU 0x17
ARM_MODE_UNDEF EQU 0x1B
ARM_MODE_SYS EQU 0x1F
I_BIT EQU 0x80
F_BIT EQU 0x40
T_BIT EQU 0x20
;-------------------------------------------------------------------------------------
; Function: OSStartHighRdy
; Purpose:
; To start the task with the highest priority during OS startup
; Notes:
; Called once during OSStart()
;-------------------------------------------------------------------------------------
EXPORT OSStartHighRdy
IMPORT OSTaskSwHook
IMPORT OSTCBCur
IMPORT OSTCBHighRdy
IMPORT OSRunning
OSStartHighRdy
BL OSTaskSwHook ; Call user-defined hook function
LDR r4,=OSRunning ; Indicate that multitasking has started
MOV r5,#1
STRB r5,[r4] ; OSRunning = true
LDR r4, =OSTCBCur ; Get current task TCB address
LDR r5, =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}
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 }
;-------------------------------------------------------------------------------------
; Function: OSCtxSw
; Purpose:
; To perform a context switch from the Task Level.
; Notes:
; The whole function is executed in CRITICAL state. See OSSched().
;-------------------------------------------------------------------------------------
EXPORT OSCtxSw
IMPORT OSTCBCur
IMPORT OSTCBHighRdy
IMPORT OSPrioCur
IMPORT OSPrioHighRdy
OSCtxSw
STMFD sp!, {lr} ; save lr
STMFD sp!, {r0-r12} ; save registers and ret address
mrs r4, CPSR ; load current psr to r4
stmfd sp!, {r4} ; save current PSR to stack
mrs r4, SPSR ; load saved psr to r4
stmfd sp!, {r4} ; saved saved psr to stack
;OSPrioCur = OSPrioHighRdy
ldr r4, =OSPrioCur ; load the current priority pointer
ldr r5, =OSPrioHighRdy ; load address of highest prio task
ldrb r6, [r5] ; load value of highest prio task
strb r6, [r4] ; store value of highest in current
; Get current task TCB address
ldr r4, =OSTCBCur ; load pointer
ldr r5, [r4] ; load current tcb sp
str sp, [r5] ; store sp in preempted tasks's TCB
; Get highest priority task TCB address
ldr r6, =OSTCBHighRdy
ldr r6, [r6] ; get highrdy's sp
ldr sp, [r6] ; set sp = highrdy[sp]
; OSTCBCur = OSTCBHighRdy
str r6, [r4] ; set new current task TCB address
ldmfd sp!, {r4} ; load saved SPSR from stack
msr SPSR_c, r4 ; spsr = saved spsr
ldmfd sp!, {r4} ; load saved cpsr from stack
msr CPSR_c, r4 ; cpsr = saved cpsr
ldmfd sp!, {r0-r12, r14} ; restore r0-r12 and lr interworking
bx r14 ; interworking branch on lr
;--------------------------------------------------------------------------------------
;--------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------
; Function: OSIntCtxSw
; Purpose:
; To perform a context switch from the interrupt level.
; Notes:
; Sets up the stacks and registers to call the task level context switch
;-------------------------------------------------------------------------------------
EXPORT OSIntCtxSw
IMPORT OSTaskSwHook
IMPORT OSTCBCur
IMPORT OSTCBHighRdy
IMPORT OSPrioCur
IMPORT OSPrioHighRdy
OSIntCtxSw
; Interrupt Exit if higher priority task ready to run
; New Task Context switch
add sp,sp, #8 ; adjust sp to compensate for the call to OSIntExit
msr CPSR_c, #0x92 ; switch to IRQ mode and disable IRQ's ; the following 2 lines keep the stack
ldmfd sp!, {r12, r14} ; restore the stack
ldmfd sp!, {r12}
ldr r12, =AIC_BASE
str r12, [r12, #AIC_EOICR] ; write any value to EOICR to signal end of int
msr CPSR_c, #ARM_MODE_SYS ; switch back to system mode with IRQ and FIQ enabled
mrs r4, CPSR ; load current psr to r4
stmfd sp!, {r4} ; save current PSR to stack
mrs r4, SPSR ; load saved psr to r4
stmfd sp!, {r4} ; saved saved psr to stack
;OSPrioCur = OSPrioHighRdy
ldr r4, =OSPrioCur ; load the current priority pointer
ldr r5, =OSPrioHighRdy ; load address of highest prio task
ldrb r6, [r5] ; load value of highest prio task
strb r6, [r4] ; store value of highest in current
; Get current task TCB address
ldr r4, =OSTCBCur ; load pointer
ldr r5, [r4] ; load current tcb sp
str sp, [r5] ; store sp in preempted tasks's TCB
; Get highest priority task TCB address
ldr r6, =OSTCBHighRdy
ldr r6, [r6] ; get highrdy's sp
ldr sp, [r6] ; set sp = highrdy[sp]
; OSTCBCur = OSTCBHighRdy
str r6, [r4] ; set new current task TCB address
ldmfd sp!, {r4} ; load saved SPSR from stack
msr SPSR_c, r4 ; spsr = saved spsr
ldmfd sp!, {r4} ; load saved cpsr from stack
msr CPSR_c, r4 ; cpsr = saved cpsr
ldmfd sp!, {r0-r12, r14} ; restore r0-r12 and lr interworking
bx r14 ; interworking branch on lr
;-------------------------------------------------------------------------------------
; Function: OSISR
; Purpose:
; The IRQ interrupt handler EXPORT OSTickISR
;-------------------------------------------------------------------------------------
EXPORT OSTickISR
IMPORT OSIntEnter
IMPORT OSTimeTick
IMPORT OSIntExit
OSTickISR
;- Adjust and save LR_irq in IRQ stack
sub r14, r14, #4
stmfd sp!, {r14}
;- Save SPSR and r0 in IRQ stack
mrs r14, SPSR
stmfd sp!, {r12, r14}
;read the interrupt status reg to clear it
ldr r12,=TC1_BASE ; load tc0 base address
ldr r12,[r12, #0x020] ; read from status register offse
;- Enable Interrupt and Switch in SYS Mode
mrs r12, CPSR
bic r12, r12, #I_BIT
orr r12, r12, #ARM_MODE_SYS
msr CPSR_c, r12
;- Save scratch/used registers and LR in SYS Stack
stmfd sp!, { r0-r12,r14}
bl OSIntEnter
bl OSIntExit
; Interrupt Exit if no higher priority task ready to run
; restore interrupted task
;- Restore scratch/used registers and LR from System Stack
ldmfd sp!, { r0-r12, r14}
;- Disable Interrupt and switch back in IRQ mode
mrs r12, CPSR
bic r12, r12, #ARM_MODE_SYS
orr r12, r12, #I_BIT:OR:ARM_MODE_IRQ
msr CPSR_c, r12
;- Mark the End of Interrupt on the AIC
ldr r12, =AIC_BASE
str r12, [r12, #AIC_EOICR]
;- Restore SPSR_irq and r0 from IRQ stack
ldmfd sp!, {r12, r14}
msr SPSR_c, r14
;- Restore adjusted LR_irq from IRQ stack directly in the PC
ldmfd sp!, {pc}^
;-------------------------------------------------------------------------------------
; Functions: ARMDisableInt ARMEnableInt
; Purpose:
; Disable and enable IRQ and FIQ preserving current CPU mode.
;-------------------------------------------------------------------------------------
EXPORT ARMDisableInt
ARMDisableInt
mrs r0,cpsr ; current CSR
mov r1, r0 ; make a copy for masking
orr r1, r1, #0xC0 ; mask off int bits
msr CPSR_cxsf, r1 ; disable ints (IRQ and FIQ)
and r0, r0, #0x80 ; return FIQ bit from original CSR
mov pc,lr
EXPORT ARMEnableInt
ARMEnableInt
mrs r0, cpsr ; current CSR
bic r0, r0, #0x80 ; mask on ints
msr CPSR_cxsf, r0 ; enable ints (IRQ and FIQ)
mov pc,lr ; return
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -