引言:
一直想要把长长的代码读明白。总算利用假期的时间看了个七七八八。也参考了他人博客的文章。http://hi.baidu.com/youjim/blog/item/666db92431aa7d094c088dfe.html许多地方自己进行了分析。对与不对还需要仔细推敲。
;=========================================
; NAME: 2440INIT.S
; DESC: C start up codes
; Configure memory, ISR ,stacks
; Initialize C-variables
; HISTORY:
; 2002.02.25:kwtark: ver 0.0
; 2002.03.20:purnnamu: Add some functions for testing STOP,Sleep mode
; 2003.03.14:DonGo: Modified for 2440.
;=========================================
GET option.inc
GET memcfg.inc
GET 2440addr.inc
BIT_SELFREFRESH EQU (1<<22)
;Pre-defined constants 预定义6种工作模式
USERMODE EQU 0x10 ;用户模式
FIQMODE EQU 0x11 ;快速中断模式
IRQMODE EQU 0x12 ;中断模式
SVCMODE EQU 0x13 ;监管模式
ABORTMODE EQU 0x17 ;异常中断模式
UNDEFMODE EQU 0x1b ;未定义模式
MODEMASK EQU 0x1f ;掩码
NOINT EQU 0xc0 ;取消中断
;设置6种工作模式的堆栈的起始地址
;在option.inc中定义了_STACK_BASEADDRESS EQU 0x33ff8000
UserStack EQU (_STACK_BASEADDRESS-0x3800) ;0x33ff4800 ~
SVCStack EQU (_STACK_BASEADDRESS-0x2800) ;0x33ff5800 ~
UndefStack EQU (_STACK_BASEADDRESS-0x2400) ;0x33ff5c00 ~
AbortStack EQU (_STACK_BASEADDRESS-0x2000) ;0x33ff6000 ~
IRQStack EQU (_STACK_BASEADDRESS-0x1000) ;0x33ff7000 ~
FIQStack EQU (_STACK_BASEADDRESS-0x0) ;0x33ff8000 ~
;检查在tasm.exe里是否设置了采用THUMB(16位)代码(armasm -16 ...@ADS 1.0)
;判断是不是thumb指令。
GBLL THUMBCODE ;定义THUMBCODE全局变量
[ {CONFIG} = 16 ;如果发现是用16位代码的话
THUMBCODE SETL {TRUE} ;把THUMBCODE设置为TURE
CODE32 ;否则是ARM模式
|
THUMBCODE SETL {FALSE} ;把THUMBCODE设置为FALSE
]
;宏定义MOV_PC_LR,作用:子程序返回
MACRO
MOV_PC_LR
[ THUMBCODE
bx lr ;在目标地址是THUMB指令,在ARM模式中
;要 用BX指令转THUMB 使 跳到THUMB
;指令,并转换模式
|
mov pc,lr ;否则,就是目标地址是ARM模式,
;就直接把函数返回地址赋给PC
]
MEND
;宏定义MOVEQ_PC_LR,作用:带相等条件判断的子程序返回 。与宏定义
;MOV_PC_LR类似
MACRO
MOVEQ_PC_LR
[ THUMBCODE
bxeq lr
|
moveq pc,lr
]
MEND
;===============================================================
;下面这个宏是用于第一次查表过程的实现中断向量的重定向,如果你比较细心的话就是发现
;在_ISR_STARTADDRESS=0x33FF_FF00里定义的第一级中断向量表
;是采用型如Handle***的方式的. 而在程序的ENTRY处(程序开始处)采用的是
;b Handler***的方式.
;在这里Handler***就是通过HANDLER这个宏和Handle***进立联系的.
;这种方式的优点就是正真定义的向量数据在内存空间里,而不是在ENTRY处
;的ROM(FLASH)空间里, 这样,我们就可以在程序里灵活的改动向量的数据了.
;===============================================================
MACRO
$HandlerLabel HANDLER $HandleLabel
$HandlerLabel
sub sp,sp,#4 ;减少sp(用于存放转跳地址)
stmfd sp!,{r0} ; 把工作寄存器压入栈
ldr r0,=$HandleLabel ; 将HandleXXX的址址放入r0
ldr r0,[r0] ; 把HandleXXX所指向的内容(也就是中断程序的入口)放入r0
str r0,[sp,#4] ;把中断服务程序(ISR)压入栈
ldmfd sp!,{r0,pc} ; 用出栈的方式恢复r0的原值和为pc设定新值(也就
;完成了到ISR的转跳)
MEND
;===============================================================
;在这里用IMPORT伪指令(和c语言的extren一样)引入|Image$$RO$$Base|,|Image$$RO$$Limit|...等比较古怪的变量是编译器生成的。
;RO, RW, ZI这三个段都保存在Flash中,但RW,ZI在Flash中
;的地址肯定不是程序运行时变量所存储的位置,因此我们的程序在初始化时应该
;把Flash中的RW,ZI拷贝到RAM的对应位置。
;这些变量是通过ADS的工程设置里面设定的RO Base和RW Base设定的,
;最终由编译脚本和连接程序导入程序.
; 实际上RW,ZI在Flash中的位置就紧接着RO存储。我们知道
;Image$$RO$$Base,Image$$RO$$Limit, 那么Image$$RO$$Limit就
;是RW(ROM data)的开始。
;===============================================================
IMPORT |Image$$RO$$Base| ; ROM code(也就是代码)的开始地址
IMPORT |Image$$RO$$Limit| ; ROM code的结束地址(=ROM data的开始地址) IMPORT |Image$$RW$$Base| ; RAM 的起始地址
IMPORT |Image$$ZI$$Base| ; 0初始化的起始地址
IMPORT |Image$$ZI$$Limit| ; 0初始化的结束地址
;===============================================================
;在这里用IMPORT伪指令(和c语言的extren一样)引入外部变量MMU的快速总线
;模式和同步总线模式两个变量
;===============================================================
IMPORT MMU_SetAsyncBusMode
IMPORT MMU_SetFastBusMode