您尚未登录。

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

晕哥
管理员
注册时间: 2017-09-06
已发帖子: 9,342
积分: 9202

网友【肠子】分享的 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




离线

#2 2018-09-04 13:59:27

达克罗德
会员
注册时间: 2018-04-10
已发帖子: 1,138
积分: 1090.5

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

BROM代码好像没看到?

离线

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

晕哥
管理员
注册时间: 2017-09-06
已发帖子: 9,342
积分: 9202

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

BROM 代码是指什么?





离线

#4 2018-09-04 14:51:02

达克罗德
会员
注册时间: 2018-04-10
已发帖子: 1,138
积分: 1090.5

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

晕哥 说:

BROM 代码是指什么?

就是spl

离线

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

晕哥
管理员
注册时间: 2017-09-06
已发帖子: 9,342
积分: 9202

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

达克罗德 说:
晕哥 说:

BROM 代码是指什么?

就是spl

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





离线

页脚

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

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