您尚未登录。

楼主 #1 2018-09-04 13:54:02

晕哥
管理员
所在地: wechat: whycan_cn
注册时间: 2017-09-06
已发帖子: 9,481
积分: 9207

网友【肠子】分享的 V3s 启动代码 start.S

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 = 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

/*
***********************************************
*
*
*
***********************************************
*/
@包含头文件
#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




离线

楼主 #3 2018-09-04 14:02:25

晕哥
管理员
所在地: wechat: whycan_cn
注册时间: 2017-09-06
已发帖子: 9,481
积分: 9207

Re: 网友【肠子】分享的 V3s 启动代码 start.S

BROM 代码是指什么?





离线

楼主 #5 2018-09-04 14:53:28

晕哥
管理员
所在地: wechat: whycan_cn
注册时间: 2017-09-06
已发帖子: 9,481
积分: 9207

Re: 网友【肠子】分享的 V3s 启动代码 start.S

达克罗德 wrote:

晕哥 wrote:

BROM 代码是指什么?

就是spl

那没有,只分享了这一个文件.





离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn


东莞哇酷科技有限公司开发