首先决定看ARM模板的启动文件,光这个启动文件就不简单啊,因为ARM汇编不了解,看见一个汇编词都是翻阅手册,不懂的就上网或者看书查找,争取明了。
首先就是启动代码的作用,它包含了异常向量入口,还有初始化了堆栈。启动代码的开始时定义了一些堆栈的大小。
FIQ_STACK_LEGTH EQU 0 IRQ_STACK_LEGTH EQU 9*8 ;每层嵌套需要9个字堆栈,允许8层嵌套 ABT_STACK_LEGTH EQU 0 UND_STACK_LEGTH EQU 0
NoInt EQU 0x80 USR32Mode EQU 0x10 SVC32Mode EQU 0x13 SYS32Mode EQU 0x1f IRQ32Mode EQU 0x12 FIQ32Mode EQU 0x11
;引入的外部标号在这声明 IMPORT FIQ_Exception ;快速中断异常处理程序 IMPORT __main ;C语言主程序入口 IMPORT TargetResetInit ;目标板基本初始化 IMPORT StackUsr IMPORT bottom_of_heap IMPORT SoftwareInterrupt ;给外部使用的标号在这声明 EXPORT Reset EXPORT __rt_div0 EXPORT __user_initial_stackheap
此伪指令指示编译器当前的符号不是在本源文件中定义的,而是其他源文件中定义的,在本源文件中可能引用该符号。
EXPORT
声明一个符号可以被其他文件中引用,相当于声明了一个全局变量。
接下来就是ARM首先执行的代码了.
CODE32 AREA vectors,CODE,READONLY ENTRY ;中断向量表 Reset LDR PC, ResetAddr LDR PC, UndefinedAddr LDR PC, SWI_Addr LDR PC, PrefetchAddr LDR PC, DataAbortAddr DCD 0xb9205f80 LDR PC, [PC, #-0xff0] LDR PC, FIQ_Addr ResetAddr DCD ResetInit UndefinedAddr DCD Undefined SWI_Addr DCD SoftwareInterrupt PrefetchAddr DCD PrefetchAbort DataAbortAddr DCD DataAbort Nouse DCD 0 IRQ_Addr DCD 0 FIQ_Addr DCD FIQ_Handler
AREA伪指令用于定义一个代码段和数据段。这是因为ARM汇编程序设计采用分段式设计,一个ARM源程序至少需要一个代码段,大的程序可以包含多个代码段及数据段。
CODE和READONLY表明下面的为代码段且只读。
LDR为大范围的地址读取伪指令。LDR伪指令用于加载32位的立即数或一个地址值到指定寄存器。
DCD用于分配一段字内存单元,并用伪指令中的expr初始化。DCD伪指令分配的内存需要字对齐,一般可用来定义数据表格或其他常数。
看完上面的代码后,我有几个疑问。
疑问1:既然是加载异常地址到PC,为什么不一下就把地址值赋给PC,而非要先LDR后DCD呢。
搜索资料后得出答案:
因为LDR指令只能跳转到当前PC 4KB范围内,而B指令能跳转到32M范围,像上面所写LDR PC,"XXXX"这条指令不远处用“XXXX”DCD定义一个字,而这个字里存放最终异常服务程序的地址,这样可以实现4GB范围跳转。而LDR伪指令通过设置指令缓冲池才能实现全范围跳转。
疑问2:
DCD 0xb9205f80
这句话突然出现在这里是什么意思?
答案:是为了让异常响亮跳转那8句机器码和为0.为什么这样,暂时不知道。
接下来是一些异常的处理
;未定义指令 Undefined B Undefined ;取指令中止 PrefetchAbort B PrefetchAbort ;取数据中止 DataAbort B DataAbort ;快速中断 FIQ_Handler STMFD SP!, {R0-R3, LR} BL FIQ_Exception LDMFD SP!, {R0-R3, LR} SUBS PC, LR, #4
接着是初始化堆栈,这是MCU复位后首先进行的工作。
InitStack MOV R0, LR ;设置中断模式堆栈 MSR CPSR_c, #0xd2 LDR SP, StackIrq ;设置快速中断模式堆栈 MSR CPSR_c, #0xd1 LDR SP, StackFiq ;设置中止模式堆栈 MSR CPSR_c, #0xd7 LDR SP, StackAbt ;设置未定义模式堆栈 MSR CPSR_c, #0xdb LDR SP, StackUnd ;设置系统模式堆栈 MSR CPSR_c, #0xdf LDR SP, =StackUsr MOV PC, R0
ResetInit BL InitStack ;初始化堆栈 BL TargetResetInit ;目标板基本初始化 B __main ;跳转到c语言入口
__user_initial_stackheap LDR r0,=bottom_of_heap MOV pc,lr
__rt_div0 B __rt_div0
StackIrq DCD IrqStackSpace + (IRQ_STACK_LEGTH - 1)* 4 StackFiq DCD FiqStackSpace + (FIQ_STACK_LEGTH - 1)* 4 StackAbt DCD AbtStackSpace + (ABT_STACK_LEGTH - 1)* 4 StackUnd DCD UndtStackSpace + (UND_STACK_LEGTH - 1)* 4
IF :DEF: EN_CRP IF . >= 0x1fc INFO 1,"\nThe data at 0x000001fc must be 0x87654321.\nPlease delete some source before this line." ENDIF CrpData WHILE . < 0x1fc NOP WEND CrpData1 DCD 0x87654321 ;/* 当此数为0x87654321时,用户程序被保护 */
;/* 分配堆栈空间 */ AREA MyStacks, DATA, NOINIT, ALIGN=2 IrqStackSpace SPACE IRQ_STACK_LEGTH * 4 ;中断模式堆栈空间 FiqStackSpace SPACE FIQ_STACK_LEGTH * 4 ;快速中断模式堆栈空间 AbtStackSpace SPACE ABT_STACK_LEGTH * 4 ;中止义模式堆栈空间 UndtStackSpace SPACE UND_STACK_LEGTH * 4 ;未定义模式堆栈 END