IT业行者,行者无疆
分类: 嵌入式
2010-09-27 09:18:09
from: http://fangheng1005.blog.163.com/blog/static/3291297200852493353569/
来看zlg的启动代码吧,因为ARM结构的特殊性,ARM只是卖他的内核,具体的芯片是授权给其他厂商生产的,这样有一个好处,就是ARM公司专心于ARM 内核的开发,可以使内核的功能更加强大,性能更强劲,但是也会造成另外一个问题,就是不同公司生产的芯片都得编写针对这个芯片的启动代码,对于应用来说确实会有一定的麻烦,因为启动代码是用汇编来写的,对于汇编,很多人都是可望不可企啊,嘿嘿,下面进入正题吧,分析zlg的启动代码。
Startup.s文件
FIQ_STACK_LEGTH
IRQ_STACK_LEGTH
ABT_STACK_LEGTH
UND_STACK_LEGTH
ARM 系统共有几种模式,当你使用FIQ中断的时候必须定义FIQ堆栈的长度,不能为0,否则堆栈会出错的;IRQ的堆栈长度是允许有8层嵌套的,每层需要使用的堆栈个数是9个,具体为什么是9个请看IRQ中断的方式,因为需要实现中断的嵌套,zlg是这样实现的,当是IRQ中断时统一进入一段代码,执行相关的保护然后开中断重新允许中断,从而实现了中断的嵌套,这里有一个重要的问题,当你不需要操作系统管理你的这个IRQ中断时,你可能不进行一个宏的定义,那么会出现一个问题,由于你的IRQ模式的堆栈是9×8,那么你的这个IRQ服务函数如果堆栈超过这个个数,那么后果是你的堆栈将溢出,出现不可预知的后果,所以这里建议应该所有的IRQ中断都由操作系统来管理,或者加大你的IRQ堆栈长度。后面的两个你应该可以自己解释了吧。
NoInt
定义一个常数,开关中断的掩码
USR32Mode
SVC32Mode
SYS32Mode
IRQ32Mode
FIQ32Mode
这几个也是常数的定义,具体请看后面的使用
IMPORT __use_no_semihosting_swi
;The imported labels
;引入的外部标号在这声明
IMPORT
IMPORT
IMPORT
IMPORT
;The emported labels
;给外部使用的标号在这声明
EXPORT
EXPORT
EXPORT
指示这段汇编代码是32位的汇编代码
vectors是数据块的名字,CODE代表这是一段代码,READONLY代表它是只读的
入口处,必须定义的哦^_^
;interrupt vectors
;中断向量表
Reset
LDR
LDR
LDR
LDR
LDR
DCD
为什么是0xb9205f80呢??ARM有一个规定,要求所有异常地址的执行代码相加起来必须是0,否则认为是无效的代码,ARM内核不会执行这段代码的,就是说你可能写的不是0xb9205f80,但是你的代码编译连接烧录都没有问题,但是ARM就是不执行你的代码,ARM的异常地址共有7个,把你的异常地址的指令编译成二进制之后与0xb9205f80相加就是0了,如果不是0那么请修改0xb9205f80的值。
这样定义是可以算出IRQ那个关键寄存器的地址,然后取出它的值存向PC,从而实现中断的跳转
ResetAddr
UndefinedAddr
SWI_Addr
PrefetchAddr
DataAbortAddr
Nouse
IRQ_Addr
FIQ_Addr
个人这么理解,ResetAddr
;未定义指令
Undefined
B
;取指令中止
PrefetchAbort
B
;取数据中止
DataAbort
B
以上三个异常的处理方式是死循环,等待看门狗的复位,嘿嘿,如果你狗没开的话你就惨了,呵呵
;快速中断
FIQ_Handler
STMFD
R0-R3是在函数调用时用来传送参数的,必须保存,因为在FIQ_Exception函数中可能有函数的调用,LR是返回地址寄存器,不用说,可定要保存啦
具体的FIQ函数的功能是在这里实现的
堆栈的恢复
FIQ中断要求这样才能正确的返回
FIQ中断的处理,这个FIQ中断是有错误的,因为上面定义了FIQ模式的堆栈是0,那么这样有可能造成堆栈的出错,除非你没有使能FIQ中断,否则你应该重新定义FIQ模式堆栈的长度,而不是0
ResetInit
这是系统复位时的第一入口,也就是启动代码的入口
BL
; Jump to the entry point of C program 跳转到c语言入口
B
在__main函数中会调用main函数,即会跑到你的main函数中的
InitStack
这是复位之后立刻执行的代码
MOV
保存返回地址
;Build the SVC stack
;设置中断模式堆栈
MSR
使ARM内核进入IRQ模式
LDR
;Build the FIQ stack
;设置快速中断模式堆栈
MSR
使ARM内核进入FIQ模式
LDR
;Build the DATAABORT stack
;设置中止模式堆栈
MSR
;Build the UDF stack
;设置未定义模式堆栈
MSR
LDR
;Build the SYS stack
;设置系统模式堆栈
MSR
LDR
R0保存的是LR的值,通过这个指令就能正确的返回
__user_initial_stackheap
LDR
;
MOV
这里应该是设置预留函数的堆栈空间,不是很清楚
StackIrq
StackFiq
StackAbt
StackUnd
通知编译器预留各个模式堆栈的空间,ADS的堆栈是向下发展的,故StackIrq
IrqStackSpace是栈空间的最低地址,通过IrqStackSpace + (IRQ_STACK_LEGTH - 1)* 4操作后就是只想了栈空间的最高地址了,从而满足了ADS栈空间向下发展的要求
IF
INFO
ENDIF
CrpData
WHILE . < 0x1fc
NOP
WEND
CrpData1
DCD
ENDIF
当再ROM地址的0x000001fc处存放的数据是0x87654321时,程序空间将会保护,不允许读取,只能一次性删除,从而起到了保护代码的作用
;
AREA
IrqStackSpace
FiqStackSpace
AbtStackSpace
UndtStackSpace
通知编译器预留栈空间
AREA
bottom_of_heap
预留一个没有初始化的数据空间,只是预留了一个字节的空间
StackUsr
只是定义了一个编号,没有定义空间,但是别的地方应该能正确的定义这个空间的大小
文件结束
;
(待续连载6)