;移植,huangsl。
;********************************************************************************************************/
INCLUDE ../boot/CONDEFINE.s
;定义系统模式堆栈的大小
CODE32
AREA |OSIRQ|, CODE, READONLY ;OSSCHEDE
;import here , 080301,huangsl,下面的变量 必须放到 SRAM,以避免 CACHE问题.
IMPORT OSTCBCur ;指向当前任务TCB的指针
IMPORT OSTCBHighRdy ;指向将要运行的任务TCB的指针
IMPORT OSPrioCur ;当前任务的优先级
IMPORT OSPrioHighRdy ;将要运行的任务的优先级
IMPORT OSRunning ;uC/OS-II运行标志
; IMPORT OSIntNesting
IMPORT OSIntEnter
IMPORT IrqCHandler ;IRQ C语言中断处理函数
IMPORT OSIntExit
IF {FALSE}
IMPORT OSTaskStackCheck
ENDIF
;export here
EXPORT OSCtxSw
EXPORT OSStartHighRdy
EXPORT OSIntCtxSw ;中断退出时的入口,参见startup.s中的IRQ_Handler
; EXPORT SoftwareInterrupt ;软中断入口
EXPORT OSIrqIsr
EXPORT OSDisableInt
EXPORT OSEnableInt
;/*********************************************************************************************************
;** 函数名称: OSIrqIsr
;** 功能描述: IRQ 中断服务程序
;** 输 入: 依功能而定
;** 输 出 : 依功能而定
;** 全局变量: 无
;具体功能可以通过 C函数实现.
;**-------------------------------------------------------------------------------------------------------
;********************************************************************************************************/
OSIrqIsr
IF :DEF: ARMULATE
;| LR |
;| SPSR |
STR R0 , [SP,#-4]
LDR R0 , [SP]
LDR LR , [SP,#4]
MSR SPSR_cxsf, R0
LDR R0 , [SP,#-4]
ADD SP , SP , #8 ; adjust sp.
ENDIF
SUB LR, LR, #4 ;计算返回地址
STMFD SP!, {R0-R3, R12, LR} ;保存任务环境,因为可能在调用 C 语言处理函数时会改变
MRS R3, SPSR ;保存状态
STMFD SP!, {R3} ;防止中断嵌透时丢失
IF {FALSE}
LDR R2, =OSIntNesting ;OSIntNesting++
LDRB R1, [R2]
ADD R1, R1, #1
STRB R1, [R2]
ELSE
BL OSIntEnter
ENDIF
BL IrqCHandler ;调用C语言的中断处理程序
;MSR写状态寄存器指令使得CPSR[7:0]=0b10010010
;作用为关IRQ中断
MSR CPSR_c, #IRQMODE|NOINT ;关中断
BL OSIntExit ;调用OSIntExit(该函数需要修改,内部不能调用 OSIntCtxSw)
;比较OSTCBHighRdy和OSTCBCur
;作用为判断在退出中断处理之后是否进行任务切换
LDR R0, =OSTCBHighRdy
LDR R0, [R0]
LDR R1, =OSTCBCur
LDR R1, [R1]
CMP R0, R1
LDMFD SP!, {R3}
MSR SPSR_cxsf, R3 ;SPSR[31:0]=R3
LDMEQFD SP!, {R0-R3, R12, PC}^ ;不进行任务切换则恢复任务环境
LDR PC, =OSIntCtxSw
OSCtxSw
STMFD sp!, {lr} ; OSCtxSw是被调用的,lr的值就是调用前的PC值,入栈
STMFD sp!, {r0-r12,lr} ; 将lr和其他寄存器入栈
MRS r4, cpsr ;通过MRS指令将cpsr入栈
STMFD sp!, {r4} ; 被挂起的当前任务的寄存器保存完毕,下面接着保存该
;任务的堆栈指针,以便下次恢复时,可以找到其堆栈指针,便可恢复其寄存器
LDR r4, =OSTCBCur ; 得到当前TCB块的地址,传给r4
LDR r5, [r4] ; 将OSTCBCur中的值传给r5,注意OSTCBCur存的是指针
STR sp, [r5] ; 将当前任务的sp传到OSTCBCur存的指针中去
;进行任务切换
B OSIntCtxSw_0
;/*********************************************************************************************************
;** 函数名称: OSIntCtxSw
;** 功能描述: 中断退出时的入口
;** 输 入: R3 :当前任务的状态寄存器CPSR(即SPSR的值)
;** R4-R12:当前任务的R4-R11
;** 当前处理器模式的堆栈结构(出栈次序):R0-R3、R12、PC(当前任务的)
;** 输 出 : 无
;** 全局变量: OSPrioCur,OSPrioHighRdy,OSPrioCur,OSPrioHighRdy
;** 调用模块: 无
;**
;任务切换退出中断
;080204,huangsl,任务切换时必须保证 R13 指向正确的堆栈,否则会 DATA ABORT.目前发现 FFT 运算会使用 R13 作为
;临时寄存器,此时中断发生 任务切换会 死机.
;**-------------------------------------------------------------------------------------------------------
;********************************************************************************************************/
OSIntCtxSw
;下面为保存任务环境
;前 处于 IRQ 状态,并且 堆栈次序为 R0-R3、R12、PC,里面保存的时被中断的任务的 context.
;首先出栈
LDR R2, [SP, #20] ;获取PC
LDR R12, [SP, #16] ;获取R12
;保存当前 CPSR(IRQ STATE)
MRS R0, CPSR
;切换到 SVC模式(任务运行模式)
MSR CPSR_c, #SVCMODE|NOINT ;局部修改 CPSR,该指令可能不支持
MOV R1, LR
STMFD SP!, {R1-R2} ;保存LR,PC
STMFD SP!, {R4-R12} ;保存R4-R12
;下面保存 R0-R3,需要先出 IRQ STACK,然后保存到 SVC STACK.
MSR CPSR_cxfs, R0
LDMFD SP!, {R4-R7} ;获取R0-R3
ADD SP, SP, #8 ;出栈R12,PC,即忽略这两个数据
MSR CPSR_c, #SVCMODE|NOINT ;局部修改 CPSR,该指令可能不支持
STMFD SP!, {R4-R7} ;保存R0-R3
STMFD SP!,{R3} ;保存CPSR
;保存当前任务堆栈指针到当前任务的TCB
LDR R1, =OSTCBCur
LDR R1, [R1]
STR SP, [R1]
;BL OSTaskSwHook ;调用钩子函数
OSIntCtxSw_0 ;OSPrioCur LDR R4, =OSPrioCur
LDR R5, =OSPrioHighRdy
LDRB R6, [R5]
STRB R6, [R4]
;OSTCBCur LDR R6, =OSTCBHighRdy
LDR R6, [R6]
LDR R4, =OSTCBCur
STR R6, [R4]
OSIntCtxSw_1
LDR sp, [r6] ; 切换到新任务的堆栈
;********测试堆栈数据***********
IF {FALSE}
MOV R0,SP
BL OSTaskStackCheck
ENDIF
;********测试堆栈数据结束***********
LDMFD sp!, {r4} ;从新任务堆栈中读取第一个参数(CPSR)到(r4)
MSR spsr_cxsf, r4 ;再传给cpsr,堆栈中的CPSR弹出到CPU的cpsr寄存器
LDMFD sp!, {r0-r12,lr,pc}^ ;依次恢复该任务r0~r12,lr,pc,切换到该任务
; MSR cpsr_cxsf, r4 ;直接传递给 CPSR,会导致开中断.
; LDMFD sp!, {r0-r12,lr,pc} ;依次恢复该任务r0~r12,lr,pc,切换到该任务
;/*********************************************************************************************************
;** 函数名称: __OSStartHighRdy
;** 功能描述: uC/OS-II启动时使用OSStartHighRdy运行第一个任务,
;** OSStartHighRdy会调用__OSStartHighRdy
;** 输 入: 无
;** 输 出 : 无
;** 全局变量: OSRunning,OSTCBCur,OSTCBHighRdy,OsEnterSum
;** 调用模块: OSTaskSwHook
;**-------------------------------------------------------------------------------------------------------
;********************************************************************************************************/
OSStartHighRdy
;告诉uC/OS-II自身已经运行
LDR R4, =OSRunning
MOV R5, #1
STRB R5, [R4]
;BL OSTaskSwHook ;调用钩子函数
LDR R6, =OSTCBHighRdy
LDR R6, [R6]
B OSIntCtxSw_1
OSDisableInt
MRS r0, cpsr ;由于任务和内核都运行在svc模式下,因此可方便地操作cpsr
; STMFD sp!, {r0} ; 保存当前的cpsr
ORR r1, r0, #0xc0 ;屏蔽FIQ,IRQ中断
MSR cpsr_c, r1 ;回写cpsr,只屏蔽IRQ中断
MOV pc, lr ;返回
OSEnableInt ;必须和 OSDisableInt 成对使用
; LDMFD sp!, {r0} ;弹出在 OSDisableInt 中被保存的cpsr
MSR cpsr_c, r0 ;恢复关中断前的cpsr
MOV pc, lr ;返回
END
;/*********************************************************************************************************
;** End Of File
;********************************************************************************************************/