ARM启动文件2440init.s分析(2)

CODE32                      ;code32表示以下是arm指令,在处理器刚开始时,必须以arm模式运行

|                                  ;此处容易产生错觉,丢掉CODE32这一行

THUMBCODE SETL  {FALSE}

]

;bx是带状态切换的跳转指令,跳转到Rm指定的地址执行程序,若Rm的位[0]为1,则跳转时自动将CPSR的标志T

;T置位,即把目标地址的代码解释为Thumb代码;若Rm的位[0]为0,则跳转时自动将CPSR中的标志T复位,即把

;目标地址的代码解释为ARM代码

;定义两个宏,宏的作用:子函数返回(无条件,有条件)。

MACRO 

MOV_PC_LR

[ THUMBCODE                         ;如果允许thumb指令,则需要根据最低位设置状态。

bx lr                                   ;跳转,附带状态切换

|

mov pc,lr

]

MEND

MACRO

MOVEQ_PC_LR   ;相等则跳转,相等与否由寄存器某些位确定,在此处,有其上一句的指令执行结果决定

[ THUMBCODE

bxeq lr

|

moveq pc,lr

]

MEND

;重点分析下面这个宏,它对中断处理函数的调用很重要

;MACRO和MEND伪指令用于宏定义,MACRO标识开始,MEND标识结束。用MACRO和MEND定义的一段代码,称为

;宏定义体,这样在程序中就可以通过宏指令多次调用该代码段。伪指令格式:

;MACRO

;{$label} macroname {$parameter} {$parameter} ...

;宏定义体

;MEND

;其中  $label 宏指令被展开时,label可被替换成相应的符号,通常为一个标号,在一个标号前使用$表示被汇编时将

;使用相应的值替代$后的符号。

;macroname 所定义的宏的名称

;$parameter 宏指令的参数,当宏指令被展开时将被替换成相应的值,类似于函数中的形式参数

;对于子程序代码较短,而需要传递的参数比较多的情况下,可以使用汇编技术。首先要用MACRO和MEND伪指令定义宏,包括宏定义

;体代码。在MACRO伪指令之后的第一行定义宏的原型,其中包含该宏定义的名称,及需要的参数。在汇编程序中可以通过该宏定义

;的名称来调用它,当源程序被汇编时,汇编编译器将  展开 每个宏调用,用宏定义体代替源程序中的宏定义的名称,并用实际的参数

;值代替宏定义时的形式参数

;在arm中,用的是满递减堆栈:stmfd,ldmfd,如果用其他的方式,arm可能不能有效识别

;注意:满递减指的是在入栈时的操作方式,在出栈时则正好相反的次序

;关于堆栈在数据放置方式,存取顺序上,可以参见《自学手册》P84中的实例分析

;例子:

;STMFD sp!,{R0-R7,LR}:(满递减:先减再放数值)sp根据数据个数,减小相应个数值的数据单位(一步到位),然后利用for循环语句,从当前sp位置,依次存储R0-R7,LR.即:sp处最后指向的是R0数据处

;LDMFD sp!,{R0-R7,LR}:复制一个变量为sp值,用该变量依次将数据存入R0-R7,LR,变量值增加,最后,变量指向下一个将要取的值,完成后sp获得该变量值;

;risc模式,这是对ram的操作

;确切说,这是宏函数,编译时对调用语句要做相应的展开

MACRO

$HandlerLabel HANDLER $HandleLabel

$HandlerLabel                            ;标号

sub  sp,sp,#4          ;留出一个空间,为了存放跳转地址给pc。见:str r0,[sp,#4] ,注意sp值并未改变

stmfd      sp!,{r0}  ;把r0中的内容入栈,保存起来

ldr     r0,=$HandleLabel    ;这是一个伪指令,不是汇编指令,目的:把$HandleLabel本身所在的地址给r0

ldr     r0,[r0]                           ;把HandleXXX所指向的内容(也就是中断程序的入口地址)放入r0

str     r0,[sp,#4]                  ;把入口地址放入刚才留出的一个空间里

ldmfd   sp!,{r0,pc}         ;出栈的方式恢复r0原值和为pc设定新值(也就完成了到ISR的转跳)。注:栈中r0内容在低地址

MEND

;这几个变量是ads环境下自动设置的,可以见环境配置选项里:ARM Linker->Output下,RO Base,RW Base

;RW Base 没设置,因为代码段的结束便是数据段的开始,这个ads可以自动设置

;IMPORT 引用变量

IMPORT  |Image$$RO$$Base|    ; Base of ROM code

IMPORT  |Image$$RO$$Limit|  ; End of ROM code (=start of ROM data)

IMPORT  |Image$$RW$$Base|   ; Base of RAM to initialise

IMPORT  |Image$$ZI$$Base|   ; Base and limit of area to zero initialise

IMPORT  |Image$$ZI$$Limit| 

IMPORT MMU_SetAsyncBusMode

IMPORT MMU_SetFastBusMode ;想知道代码具体内容见cp15手册,并以cp15指令内容搜索2440a手册

IMPORT  Main            ;The main entry of mon program

IMPORT  RdNF2SDRAM   ;Copy Image from Nand Flash to SDRAM

;AREA伪指令用于定义一个代码段或数据段,一个ARM源程序至少需要一个代码段,大的程序可以包含多个代码段及数据段

;格式:AREA sectionname {,attr} {,attr}...

AREA    Init,CODE,READONLY

;ENTRY伪指令用于指定程序的入口点

;一个程序(可以包含多个源文件)中至少要有一个ENTRY,可以有多个ENTRY,但一个源文件中最多只有一个ENTRY.

ENTRY

;EXPORT声明一个符号可以被其他文件引用,相当于声明了一个全局变量。GLOBAL与EXPORT相同    

;格式:EXPORT symbol{[WEAK]}   [WEAK]声明其他的同名符优先于本符号被引用

;导出符号__ENTRY

EXPORT __ENTRY

__ENTRY

ResetEntry

;1)Thecode, which converts to Big-endian, should be in little endian code.

;2)Thefollowing little endian code will be compiled in Big-Endian mode.

;  The code byte order should be changed as thememory bus width.

;3)Thepseudo instruction,DCD can not be used here because the linker generates error.

;条件编译,在编译成机器码前就设定好  大小端转换

;判断ENDIAN_CHANGE是否已定义,ASSERT 是断言伪指令,语法是:ASSERT +逻辑表达式 ,def 是逻辑伪操作符,格式为::DEF:label,作用是:判断label是否定义过

ASSERT :DEF:ENDIAN_CHANGE

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wyjjdd.html