start.S
/*
***********************************************
*
*
*
***********************************************
*/
@包含头文件
#include <armv7.h>
#include <v3s-base.h>/* 代码段 */
.text
/* 定义.globl函数等同 EXPORT,外部文件可调用 */
.globl _start
.globl _undefined_instruction
.globl _software_interrupt
.globl _prefetch_abort
.globl _data_abort
.globl _not_used
.globl _irq
.globl _fiq/* 定义.extern函数等同 IMPORT,调用外部文件 */
.extern SWI_Handler
.extern IRQ_Handler.extern TinyRTOS_SwitchTask
/* 全局变量 */
.extern Exit_IRQ_Switch_Flag
.extern IRQ_Nesting_Count/* 程序入口_start函数 */
_start: /* _start程序入口 */
_vector: /* 中断向量函数 */
b reset /* 跳转至reset函数 */
ldr pc, _undefined_instruction /* 为定义指令中断向量 */
ldr pc, _software_interrupt /* SWI软中断向量 */
ldr pc, _prefetch_abort /* 指令预取中止中断向量 */
ldr pc, _data_abort /* 数据访问中止中断向量 */
ldr pc, _not_used /* 未使用 */
ldr pc, _irq /* 外部中断向量 */
ldr pc, _fiq /* 快速中断向量 */_undefined_instruction: .word undefined_instruction
_software_interrupt: .word software_interrupt
_prefetch_abort: .word prefetch_abort
_data_abort: .word data_abort
_not_used: .word not_used
_irq: .word irq
_fiq: .word fiq/*
***********************************************
*
*
*
***********************************************
*/
reset:
/* 设置处理器状态为SVC特权模式并关闭IRQ和FIQ */
cps #SVC_MODE @ 设置为SVC模式
cpsid if @ 关闭中断和快速中断/* 关闭TLBs分支预测,失效Cache */
mov r0, #0 @ r0 = 0
mcr p15, 0, r0, c8, c7, 0 @ 禁止从TLB中取地址描述符,也就是禁止虚拟地址到物理地址的转换,因为刚开始操作的都是物理寄存器
mcr p15, 0, r0, c7, c5, 0 @ 失效指令cache
mcr p15, 0, r0, c7, c5, 6 @ 关闭分支预测
mcr p15, 0, r0, c7, c10, 4 @ 多核cpu之间进行数据同步
mcr p15, 0, r0, c7, c5, 4 @ 进行指令同步,放弃流水线中已经取到的指令,重新取指令/* 关闭D-Cache MMU */
mrc p15, 0, r0, c1, c0, 0 @ 读取SCTLR到r0寄存器
bic r0, r0, #0x2000 @ bit13 位(V) 清零,设置成正常异常模式,即异常向量表的基地址为0x00000000
bic r0, r0, #0x00000005 @ bit0位(M),bit2位(C)清零,关闭D-cache,关闭mmu
orr r0, r0, #0x0000002 @ bit2位(A)置1, 使能对齐位检查
orr r0, r0, #0x00000800 @ bit11位(Z)置1, 使能分支预测
orr r0, r0, #0x00001000 @ bit12位 (I)置1, 使能I-cache
mcr p15, 0, r0, c1, c0, 0 @ 写入SCTLR
mrc p15, 0, r0, c1, c0, 0 @ 读取SCTLR到r0寄存器/* 设置中断向量表地址CP15 C12 */
ldr r0, =_vector @ r0 = &(_start)
mcr p15, 0, r0, c12, c0, 0 @ CP15->C12->VBAR = r0
mrc p15, 0, r0, c1, c0, 0 @ r0 = CP15->C1->C0 系统控制寄存器
bic r0, #(1<<13) @ 第13位V清零,设置中断向量地址是VBAR设置的地址
mcr p15, 0, r0, c1, c0, 0 @ 写入系统控制寄存器/* 使能smp */
mrc p15, 0, r0, c1, c0, 1
orr r0, r0, #(1 << 6)
mcr p15, 0, r0, c1, c0, 1/* 使能vfp */
mrc p15, 0, r0, c1, c0, 2
orr r0, r0, #(0xf << 20)
mcr p15, 0, r0, c1, c0, 2
isb @ 以保证所有它前面的指令都执行完毕之后,才执行它后面的指令
mov r0, #0x40000000
vmsr fpexc, r0/* 子函数调用 */
bl Init_Stack @ 初始化各模式栈
bl clear_bss @ 清空bss
ldr pc, =main @ 跳转到main函数/**
************************************************
* 函数名: Init_Stack
* 参数: void
* 返回值: void
* 作用: 初始化c语言用的栈
* 说明:
************************************************
**/
Init_Stack:ldr sp, =stack_svc_start @ 设置SVC模式栈
cps #FIQ_MODE @ 切换至快速中断FIQ模式
ldr sp, =stack_fiq_start @ 设置FIQ模式栈指针cps #IRQ_MODE @ 切换至中断IRQ模式
ldr sp, =stack_irq_start @ 设置IRQ模式栈指针cps #ABT_MODE @ 切换至ABT访问终止模式
ldr sp, =stack_abort_start @ 设置访问终止模式栈cps #UND_MODE @ 切换至快未定义指令模式
ldr sp, =stack_und_start @ 设置未定义指令模式栈cps #SVC_MODE @ 返回SVC模式
mov pc, lr @ 函数返回
/**
************************************************
* 函数名: clear_bss
* 参数: void
* 返回值: void
* 作用: 清空bss段
* 说明: 为初始化全局变量清零
************************************************
**/
clear_bss:
ldr r0, =bss_start @ r0 = bss_start, ld脚本中定义的地址符号
ldr r1, =bss_end @ r1 = bss_end, ld脚本中定义的地址符号
mov r2, #0 @ r2 = 0
clear_loop:
str r2, [r0], #4 @ *r0 = r2(0), r0 += 4
cmp r0, r1 @ 比较r0 与 r1
bne clear_loop @ 不相等则继续循环
mov pc, lr @ 运行到这里就是bss清除完, 函数返回/***********************************************************************************************/
/*
***********************************************
*
* 函数名: undefined_instruction
* 作用: 未定义指令中断服务函数
*
***********************************************
*/
undefined_instruction:
b undefined_instruction/*
***********************************************
*
* 函数名: software_interrupt
* 作用: SWI软中断服务函数
* 说明: SWI中断使用SVC栈
* 本函数设计的是只能返回到SYS模式
*
***********************************************
*/
software_interrupt:
cpsid if @ 关中断
str lr, [sp, #-4] @ 将lr存入svc栈空间
mrs lr, spsr @ lr = spsr_svc
str lr, [sp, #-8] @ 将spsr_svc存入svc栈空间
str r0, [sp, #-12] @ 将 r0 存入svc栈空间
mov r0, sp; @ 使用 r0 传递栈指针@ 此时 r0 中是栈指针, lr 中是spsr 即发生中断前cpsr寄存器的值
@ 回到原来运行模式, 进行状态保存
orr lr, lr, #CPU_INTRRUPT_MASK @ 清除中断使能位, 直到退出前都是禁用中断状态
msr cpsr, lr @ 回到中断前的运行模式str lr, [sp, #-8]! @ 对中断前的 lr 进行入栈, 压栈到原来的模式的栈中
ldr lr, [r0, #-4] @ 从svc栈空间中提取 lr_svc 到寄存器 lr, 实际是中断返回的pc指针
str lr, [sp, #4] @ 将 lr_svc (pc)压入到原来的模式的栈中ldr lr, [r0, #-8] @ 提取 spsr_svc 到寄存器
push {lr} @ 将 spsr_svc 压入中断前的模式的栈中ldr r0, [r0, #-12] @ 从svc栈中提取r0到寄存器r0
push {r0-r3, r12} @ r0-r3, r12压入中断前的模式的栈中ldr r0, [sp, #28] @ 提取lr_svc到寄存器
ldr r0, [r0, #-4] @ r0 = lr - 4, 即SWI指令所在地址
bic r0, r0, #SWI_MASK @ 提取SWI软中断号push {r4-r11} @ 压栈r4-r11
vpush {s0-s31} @ vfp寄存器入栈
vmrs r2, fpscr @ 浮点状态寄存器fpscr读取到r2
push {r2} @ 浮点状态寄存器fpscr入栈mov r1, sp @ 保存原模式栈指针到r1
@到这里,相当于中断前的pc, lr, cpsr, {r0-r3, r12}, {r4-r11}, {s0-s31}, fpscr寄存器依次入栈到原模式栈中
@此时, r0是软中断号, r1是原模式栈指针
cps #SVC_MODE @ 使用cps指令设置模式为SVC
@下面进入到SVC模式
bl SWI_Handler @ 跳转到软中断服务函数, 有两个参数, 1 软中断号, 2 保存有中断前上下文的栈指针
@SWI_Handler函数有一个32位返回值, 这个值是修改过的栈指针
cps #SYS_MODE @ 使用cps指令设置模式为SYS_MODE
mov sp, r0 @ SWI_Handler返回的是一个线程的栈指针
pop {r0} @ fpscr 寄存器的值出栈到r0
vmsr fpscr, r0 @ 恢复fpscr
vpop {s0-s31} @ 出栈vfp寄存器s0-s31
pop {r4-r11} @ 出栈通用寄存器r4-r11
pop {r0-r3, r12} @ 出栈通用寄存器r0-r3, r12
pop {lr} @ 出栈spsr寄存器的值到lr
msr cpsr, lr @ 恢复cpsr
pop {lr} @ 出栈lr寄存器
ldmfd sp!, {pc} @ 满栈减栈出栈pc寄存器, 进行跳转到线程
/*
***********************************************
*
* 函数名: prefetch_abort
* 作用: 预取指令终止中断服务函数
*
***********************************************
*/
prefetch_abort:
b prefetch_abort
/*
***********************************************
*
* 函数名: data_abort
* 作用: 数据访问终止中断服务函数
*
***********************************************
*/
data_abort:
b data_abort
/*
***********************************************
*
* 函数名: not_used
* 作用: 空
*
***********************************************
*/
not_used:
b not_used
/*
***********************************************
*
* 函数名: irq
* 作用: 中断服务函数
*
***********************************************
*/
irq:
sub lr, lr, #4 @ 计算返回地址
str lr, [sp, #-4] @ 将lr存入irq模式的栈空间mrs lr, spsr @ lr = spsr_irq, 即中断发生前的cpsr寄存器的值
str lr, [sp, #-8] @ 将spsr_irq存入irq栈空间
str r0, [sp, #-12] @ 将r0存入irq模式的栈空间
mov r0, sp; @ 使用r0传递irq模式的栈指针@回到中断发生前的模式, 进行上下文保存
orr lr, lr, #CPU_INTRRUPT_MASK @ 清除中断使能位, 之后直到进入中断端口选择函数开中断前,一直是禁用中断的
msr cpsr, lr @ 回到中断前的运行模式str lr, [sp, #-8]! @ 对中断前的lr进行压栈, 压栈到中断前的栈空间
ldr lr, [r0, #-4] @ 提取lr_irq到寄存器, 实际是中断返回地址pc
str lr, [sp, #4] @ 将lr_irq压入中断发生前的模式的栈空间中ldr lr, [r0, #-8] @ 提取spsr_irq到寄存器
push {lr} @ 将spsr_irq压入中断发生前的模式的栈空间中ldr r0, [r0, #-12] @ 从irq模式的栈中提取r0到寄存器
push {r0-r3, r12} @ 压栈r0-r3, r12到中断发生前的模式的栈中
mrs r3, cpsr @ 使用r3保存中断发生前的cpsr寄存器值
orr r3, r3, #CPU_INTRRUPT_MASK @ 屏蔽掉中断@到这里,相当于中断前的pc, lr, cpsr, r0-r3, r12寄存器依次入栈到原模式栈中
@转到SVC模式以使能中断嵌套
cps #SVC_MODE @ 使用cps指令设置模式为SVC@下面进入到SVC模式
@中断嵌套计数器递增
ldr r0, =IRQ_Nesting_Count @ r0 = &IRQ_Nesting_Count 中断嵌套计数器
ldr r1, [r0] @ r1 = IRQ_Nesting_Count
add r1, r1, #1 @ r1 += 1
str r1, [r0] @ IRQ_Nesting_Count = r1push {r3} @ 压栈r3
bl IRQ_Handler @ 跳转到中断服务函数
cpsid i @ 在IRQ_Handler中打开了中断, 这里下面的操作需要关闭中断
pop {r3} @ 出栈r3
@中断嵌套计数器递减
ldr r0, =IRQ_Nesting_Count @ r0 = &IRQ_Nesting_Count 中断嵌套计数器
ldr r1, [r0] @ r1 = IRQ_Nesting_Count
subs r1, r1, #1 @ r1 -= 1
str r1, [r0] @ IRQ_Nesting_Count = r1
bne Exit_This_IRQ @ 如果中断嵌套未结束则直接退出@判断中断退出时是否需要进行任务切换
ldr r0, =Exit_IRQ_Switch_Flag @ r0 = &Exit_IRQ_Switch_Flag 任务切换标志
ldr r1, [r0] @ r1 = Exit_IRQ_Switch_Flag
cmp r1, #1 @ 比较Exit_IRQ_Switch_Flag是否是1, 既是否需要任务切换
bne Exit_This_IRQ @ Exit_IRQ_Switch_Flag != 1, 直接跳去执行Exit_This_IRQ
mov r1, #0
str r1, [r0] @ Exit_IRQ_Switch_Flag = 0;@运行到这里说明要进行任务切换
msr cpsr, r3 @ 恢复中断前的模式@在发生中断时已经对 pc, lr, cpsr, r0-r3, r12寄存器依次入栈到原模式栈中了
@所以, 这里只需要入栈r4-r11和vfp相关寄存器即可
push {r4-r11} @ 压栈r4-r11
vpush {s0-s31} @ vfp寄存器入栈
vmrs r2, fpscr @ 浮点状态寄存器fpscr读取到r2
push {r2} @ 浮点状态寄存器fpscr入栈mov r0, sp @ 任务栈指针保存到r0寄存器
@到这里旧任务现场保存完, r0中是旧任务栈指针
cps #SVC_MODE @ 使用cps指令设置模式为SVCbl TinyRTOS_SwitchTask @ 跳去执行TinyRTOS_SwitchTask函数, 函数有一个参数是旧任务栈指针
@返回后r0的值是新任务的栈指针
cps #SYS_MODE @ 使用cps指令设置模式为SYS模式,进行任务栈操作mov sp, r0 @ 任务栈改为新任务的
pop {r0} @ vfp寄存器出栈
vmsr fpscr, r0 @ 恢复vfp状态寄存器
vpop {s0-s31} @ 恢复vfp通用寄存器
pop {r4-r11} @ 恢复r4-r11b Exit_IRQ_Switch @ 下面恢复r0-r3, r12, cpsr, lr, pc
Exit_This_IRQ:
@不需要任务切换直接退出
msr cpsr, r3 @ 切换到中断前的模式
Exit_IRQ_Switch:
pop {r0-r3, r12} @ 出栈r0-r3, r12pop {lr} @ 出栈cpsr寄存器
msr cpsr, lr @ 恢复cpsrpop {lr} @ 出栈lr返回地址指针
ldmfd sp!, {pc} @ 满栈减栈出栈pc寄存器, 中断返回
/*
***********************************************
*
* 函数名: fiq
* 作用: 快速中断服务函数
*
***********************************************
*/
fiq:
b fiq
/*
***********************************************
*
*
*
***********************************************
*/
@包含头文件
#include <armv7.h>
#include <v3s-base.h>
/* 代码段 */
.text
/* 定义.globl函数等同 EXPORT,外部文件可调用 */
.globl _start
.globl _undefined_instruction
.globl _software_interrupt
.globl _prefetch_abort
.globl _data_abort
.globl _not_used
.globl _irq
.globl _fiq
/* 定义.extern函数等同 IMPORT,调用外部文件 */
.extern SWI_Handler
.extern IRQ_Handler
.extern TinyRTOS_SwitchTask
/* 全局变量 */
.extern Exit_IRQ_Switch_Flag
.extern IRQ_Nesting_Count
/* 程序入口_start函数 */
_start: /* _start程序入口 */
_vector: /* 中断向量函数 */
b reset /* 跳转至reset函数 */
ldr pc, _undefined_instruction /* 为定义指令中断向量 */
ldr pc, _software_interrupt /* SWI软中断向量 */
ldr pc, _prefetch_abort /* 指令预取中止中断向量 */
ldr pc, _data_abort /* 数据访问中止中断向量 */
ldr pc, _not_used /* 未使用 */
ldr pc, _irq /* 外部中断向量 */
ldr pc, _fiq /* 快速中断向量 */
_undefined_instruction: .word undefined_instruction
_software_interrupt: .word software_interrupt
_prefetch_abort: .word prefetch_abort
_data_abort: .word data_abort
_not_used: .word not_used
_irq: .word irq
_fiq: .word fiq
/*
***********************************************
*
*
*
***********************************************
*/
reset:
/* 设置处理器状态为SVC特权模式并关闭IRQ和FIQ */
cps #SVC_MODE @ 设置为SVC模式
cpsid if @ 关闭中断和快速中断
/* 关闭TLBs分支预测,失效Cache */
mov r0, #0 @ r0 = 0
mcr p15, 0, r0, c8, c7, 0 @ 禁止从TLB中取地址描述符,也就是禁止虚拟地址到物理地址的转换,因为刚开始操作的都是物理寄存器
mcr p15, 0, r0, c7, c5, 0 @ 失效指令cache
mcr p15, 0, r0, c7, c5, 6 @ 关闭分支预测
mcr p15, 0, r0, c7, c10, 4 @ 多核cpu之间进行数据同步
mcr p15, 0, r0, c7, c5, 4 @ 进行指令同步,放弃流水线中已经取到的指令,重新取指令
/* 关闭D-Cache MMU */
mrc p15, 0, r0, c1, c0, 0 @ 读取SCTLR到r0寄存器
bic r0, r0, #0x2000 @ bit13 位(V) 清零,设置成正常异常模式,即异常向量表的基地址为0x00000000
bic r0, r0, #0x00000005 @ bit0位(M),bit2位(C)清零,关闭D-cache,关闭mmu
orr r0, r0, #0x0000002 @ bit2位(A)置1, 使能对齐位检查
orr r0, r0, #0x00000800 @ bit11位(Z)置1, 使能分支预测
orr r0, r0, #0x00001000 @ bit12位 (I)置1, 使能I-cache
mcr p15, 0, r0, c1, c0, 0 @ 写入SCTLR
mrc p15, 0, r0, c1, c0, 0 @ 读取SCTLR到r0寄存器
/* 设置中断向量表地址CP15 C12 */
ldr r0, =_vector @ r0 = &(_start)
mcr p15, 0, r0, c12, c0, 0 @ CP15->C12->VBAR = r0
mrc p15, 0, r0, c1, c0, 0 @ r0 = CP15->C1->C0 系统控制寄存器
bic r0, #(1<<13) @ 第13位V清零,设置中断向量地址是VBAR设置的地址
mcr p15, 0, r0, c1, c0, 0 @ 写入系统控制寄存器
/* 使能smp */
mrc p15, 0, r0, c1, c0, 1
orr r0, r0, #(1 << 6)
mcr p15, 0, r0, c1, c0, 1
/* 使能vfp */
mrc p15, 0, r0, c1, c0, 2
orr r0, r0, #(0xf << 20)
mcr p15, 0, r0, c1, c0, 2
isb @ 以保证所有它前面的指令都执行完毕之后,才执行它后面的指令
mov r0, #0x40000000
vmsr fpexc, r0
/* 子函数调用 */
bl Init_Stack @ 初始化各模式栈
bl clear_bss @ 清空bss
ldr pc, =main @ 跳转到main函数
/**
************************************************
* 函数名: Init_Stack
* 参数: void
* 返回值: void
* 作用: 初始化c语言用的栈
* 说明:
************************************************
**/
Init_Stack:
ldr sp, =stack_svc_start @ 设置SVC模式栈
cps #FIQ_MODE @ 切换至快速中断FIQ模式
ldr sp, =stack_fiq_start @ 设置FIQ模式栈指针
cps #IRQ_MODE @ 切换至中断IRQ模式
ldr sp, =stack_irq_start @ 设置IRQ模式栈指针
cps #ABT_MODE @ 切换至ABT访问终止模式
ldr sp, =stack_abort_start @ 设置访问终止模式栈
cps #UND_MODE @ 切换至快未定义指令模式
ldr sp, =stack_und_start @ 设置未定义指令模式栈
cps #SVC_MODE @ 返回SVC模式
mov pc, lr @ 函数返回
/**
************************************************
* 函数名: clear_bss
* 参数: void
* 返回值: void
* 作用: 清空bss段
* 说明: 为初始化全局变量清零
************************************************
**/
clear_bss:
ldr r0, =bss_start @ r0 = bss_start, ld脚本中定义的地址符号
ldr r1, =bss_end @ r1 = bss_end, ld脚本中定义的地址符号
mov r2, #0 @ r2 = 0
clear_loop:
str r2, [r0], #4 @ *r0 = r2(0), r0 += 4
cmp r0, r1 @ 比较r0 与 r1
bne clear_loop @ 不相等则继续循环
mov pc, lr @ 运行到这里就是bss清除完, 函数返回
/***********************************************************************************************/
/*
***********************************************
*
* 函数名: undefined_instruction
* 作用: 未定义指令中断服务函数
*
***********************************************
*/
undefined_instruction:
b undefined_instruction
/*
***********************************************
*
* 函数名: software_interrupt
* 作用: SWI软中断服务函数
* 说明: SWI中断使用SVC栈
* 本函数设计的是只能返回到SYS模式
*
***********************************************
*/
software_interrupt:
cpsid if @ 关中断
str lr, [sp, #-4] @ 将lr存入svc栈空间
mrs lr, spsr @ lr = spsr_svc
str lr, [sp, #-8] @ 将spsr_svc存入svc栈空间
str r0, [sp, #-12] @ 将 r0 存入svc栈空间
mov r0, sp; @ 使用 r0 传递栈指针
@ 此时 r0 中是栈指针, lr 中是spsr 即发生中断前cpsr寄存器的值
@ 回到原来运行模式, 进行状态保存
orr lr, lr, #CPU_INTRRUPT_MASK @ 清除中断使能位, 直到退出前都是禁用中断状态
msr cpsr, lr @ 回到中断前的运行模式
str lr, [sp, #-8]! @ 对中断前的 lr 进行入栈, 压栈到原来的模式的栈中
ldr lr, [r0, #-4] @ 从svc栈空间中提取 lr_svc 到寄存器 lr, 实际是中断返回的pc指针
str lr, [sp, #4] @ 将 lr_svc (pc)压入到原来的模式的栈中
ldr lr, [r0, #-8] @ 提取 spsr_svc 到寄存器
push {lr} @ 将 spsr_svc 压入中断前的模式的栈中
ldr r0, [r0, #-12] @ 从svc栈中提取r0到寄存器r0
push {r0-r3, r12} @ r0-r3, r12压入中断前的模式的栈中
ldr r0, [sp, #28] @ 提取lr_svc到寄存器
ldr r0, [r0, #-4] @ r0 = lr - 4, 即SWI指令所在地址
bic r0, r0, #SWI_MASK @ 提取SWI软中断号
push {r4-r11} @ 压栈r4-r11
vpush {s0-s31} @ vfp寄存器入栈
vmrs r2, fpscr @ 浮点状态寄存器fpscr读取到r2
push {r2} @ 浮点状态寄存器fpscr入栈
mov r1, sp @ 保存原模式栈指针到r1
@到这里,相当于中断前的pc, lr, cpsr, {r0-r3, r12}, {r4-r11}, {s0-s31}, fpscr寄存器依次入栈到原模式栈中
@此时, r0是软中断号, r1是原模式栈指针
cps #SVC_MODE @ 使用cps指令设置模式为SVC
@下面进入到SVC模式
bl SWI_Handler @ 跳转到软中断服务函数, 有两个参数, 1 软中断号, 2 保存有中断前上下文的栈指针
@SWI_Handler函数有一个32位返回值, 这个值是修改过的栈指针
cps #SYS_MODE @ 使用cps指令设置模式为SYS_MODE
mov sp, r0 @ SWI_Handler返回的是一个线程的栈指针
pop {r0} @ fpscr 寄存器的值出栈到r0
vmsr fpscr, r0 @ 恢复fpscr
vpop {s0-s31} @ 出栈vfp寄存器s0-s31
pop {r4-r11} @ 出栈通用寄存器r4-r11
pop {r0-r3, r12} @ 出栈通用寄存器r0-r3, r12
pop {lr} @ 出栈spsr寄存器的值到lr
msr cpsr, lr @ 恢复cpsr
pop {lr} @ 出栈lr寄存器
ldmfd sp!, {pc} @ 满栈减栈出栈pc寄存器, 进行跳转到线程
/*
***********************************************
*
* 函数名: prefetch_abort
* 作用: 预取指令终止中断服务函数
*
***********************************************
*/
prefetch_abort:
b prefetch_abort
/*
***********************************************
*
* 函数名: data_abort
* 作用: 数据访问终止中断服务函数
*
***********************************************
*/
data_abort:
b data_abort
/*
***********************************************
*
* 函数名: not_used
* 作用: 空
*
***********************************************
*/
not_used:
b not_used
/*
***********************************************
*
* 函数名: irq
* 作用: 中断服务函数
*
***********************************************
*/
irq:
sub lr, lr, #4 @ 计算返回地址
str lr, [sp, #-4] @ 将lr存入irq模式的栈空间
mrs lr, spsr @ lr = spsr_irq, 即中断发生前的cpsr寄存器的值
str lr, [sp, #-8] @ 将spsr_irq存入irq栈空间
str r0, [sp, #-12] @ 将r0存入irq模式的栈空间
mov r0, sp; @ 使用r0传递irq模式的栈指针
@回到中断发生前的模式, 进行上下文保存
orr lr, lr, #CPU_INTRRUPT_MASK @ 清除中断使能位, 之后直到进入中断端口选择函数开中断前,一直是禁用中断的
msr cpsr, lr @ 回到中断前的运行模式
str lr, [sp, #-8]! @ 对中断前的lr进行压栈, 压栈到中断前的栈空间
ldr lr, [r0, #-4] @ 提取lr_irq到寄存器, 实际是中断返回地址pc
str lr, [sp, #4] @ 将lr_irq压入中断发生前的模式的栈空间中
ldr lr, [r0, #-8] @ 提取spsr_irq到寄存器
push {lr} @ 将spsr_irq压入中断发生前的模式的栈空间中
ldr r0, [r0, #-12] @ 从irq模式的栈中提取r0到寄存器
push {r0-r3, r12} @ 压栈r0-r3, r12到中断发生前的模式的栈中
mrs r3, cpsr @ 使用r3保存中断发生前的cpsr寄存器值
orr r3, r3, #CPU_INTRRUPT_MASK @ 屏蔽掉中断
@到这里,相当于中断前的pc, lr, cpsr, r0-r3, r12寄存器依次入栈到原模式栈中
@转到SVC模式以使能中断嵌套
cps #SVC_MODE @ 使用cps指令设置模式为SVC
@下面进入到SVC模式
@中断嵌套计数器递增
ldr r0, =IRQ_Nesting_Count @ r0 = &IRQ_Nesting_Count 中断嵌套计数器
ldr r1, [r0] @ r1 = IRQ_Nesting_Count
add r1, r1, #1 @ r1 += 1
str r1, [r0] @ IRQ_Nesting_Count = r1
push {r3} @ 压栈r3
bl IRQ_Handler @ 跳转到中断服务函数
cpsid i @ 在IRQ_Handler中打开了中断, 这里下面的操作需要关闭中断
pop {r3} @ 出栈r3
@中断嵌套计数器递减
ldr r0, =IRQ_Nesting_Count @ r0 = &IRQ_Nesting_Count 中断嵌套计数器
ldr r1, [r0] @ r1 = IRQ_Nesting_Count
subs r1, r1, #1 @ r1 -= 1
str r1, [r0] @ IRQ_Nesting_Count = r1
bne Exit_This_IRQ @ 如果中断嵌套未结束则直接退出
@判断中断退出时是否需要进行任务切换
ldr r0, =Exit_IRQ_Switch_Flag @ r0 = &Exit_IRQ_Switch_Flag 任务切换标志
ldr r1, [r0] @ r1 = Exit_IRQ_Switch_Flag
cmp r1, #1 @ 比较Exit_IRQ_Switch_Flag是否是1, 既是否需要任务切换
bne Exit_This_IRQ @ Exit_IRQ_Switch_Flag != 1, 直接跳去执行Exit_This_IRQ
mov r1, #0
str r1, [r0] @ Exit_IRQ_Switch_Flag = 0;
@运行到这里说明要进行任务切换
msr cpsr, r3 @ 恢复中断前的模式
@在发生中断时已经对 pc, lr, cpsr, r0-r3, r12寄存器依次入栈到原模式栈中了
@所以, 这里只需要入栈r4-r11和vfp相关寄存器即可
push {r4-r11} @ 压栈r4-r11
vpush {s0-s31} @ vfp寄存器入栈
vmrs r2, fpscr @ 浮点状态寄存器fpscr读取到r2
push {r2} @ 浮点状态寄存器fpscr入栈
mov r0, sp @ 任务栈指针保存到r0寄存器
@到这里旧任务现场保存完, r0中是旧任务栈指针
cps #SVC_MODE @ 使用cps指令设置模式为SVC
bl TinyRTOS_SwitchTask @ 跳去执行TinyRTOS_SwitchTask函数, 函数有一个参数是旧任务栈指针
@返回后r0的值是新任务的栈指针
cps #SYS_MODE @ 使用cps指令设置模式为SYS模式,进行任务栈操作
mov sp, r0 @ 任务栈改为新任务的
pop {r0} @ vfp寄存器出栈
vmsr fpscr, r0 @ 恢复vfp状态寄存器
vpop {s0-s31} @ 恢复vfp通用寄存器
pop {r4-r11} @ 恢复r4-r11
b Exit_IRQ_Switch @ 下面恢复r0-r3, r12, cpsr, lr, pc
Exit_This_IRQ:
@不需要任务切换直接退出
msr cpsr, r3 @ 切换到中断前的模式
Exit_IRQ_Switch:
pop {r0-r3, r12} @ 出栈r0-r3, r12
pop {lr} @ 出栈cpsr寄存器
msr cpsr, lr @ 恢复cpsr
pop {lr} @ 出栈lr返回地址指针
ldmfd sp!, {pc} @ 满栈减栈出栈pc寄存器, 中断返回
/*
***********************************************
*
* 函数名: fiq
* 作用: 快速中断服务函数
*
***********************************************
*/
fiq:
b fiq
离线