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

b     .                           ;reserved 保留未用 注意小圆点         0X14

b     HandlerIRQ    ;handlerfor IRQ interrupt                          0X18

b     HandlerFIQ    ;handlerfor FIQ interrupt                          0X1C

;这7个中断,每个中断都有固定的中断入口地址,它们位于代码的最前端,不允许另作他用

;@0x20

b     EnterPWDN   ;Must be                                               0x20

;下面是改变大小端的程序,采用直接定义  <机器码>  的方式,为什么这么做就得问三星了

;反正我们程序里这段代码也不会去执行,不用去管它

;每一个汇编指令,都对应着一个二进制机器码,这里没有使用指令,直接用了机器码,含义未知

ChangeBigEndian

;@0x24

[ENTRY_BUS_WIDTH=32

DCD       0xee110f10     ;0xee110f10 => mrc p15,0,r0,c1,c0,0

DCD       0xe3800080    ;0xe3800080 => orr r0,r0,#0x80;  //Big-endian

DCD       0xee010f10     ;0xee010f10 => mcr p15,0,r0,c1,c0,0

;对存储器控制寄存器操作,指定内存模式为Big-endian

;因为刚开始CPU都是按照32位总线的指令格式运行的,如果采用其他的话,CPU别不了,必须转化

;但当系统初始化好以后,则CPU能自动识别

]

[ENTRY_BUS_WIDTH=16

DCD0x0f10ee11

DCD0x0080e380

DCD0x0f10ee01

;因为采用Big-endian模式,采用16位总线时,物理地址的高位和数据的地位对应

;所以指令的机器码也相应的高低对调

]

[ENTRY_BUS_WIDTH=8

DCD0x100f11ee

DCD0x800080e3

DCD0x100f01ee

]

DCD0xffffffff  ;swinv 0xffffff is similarwith NOP and run well in both endian mode.

DCD0xffffffff

DCD0xffffffff

DCD0xffffffff

DCD0xffffffff

bResetHandler                     ;设置成大端后,再次跳到复位指令处

;本文件底部定义了一个数据区(在文件最后),34个字空间,存放相应中断服务程序的首地址。每个字

;空间都有一个标号,以Handle***命名。

;这是宏实例   在这里Handler***就是通过HANDLER这个宏和Handle***建立联系的.

;详细分析:

;    这是宏示例,也就是宏的调用指令,当编译时编译器会把宏调用指令展开

;    这是向量中断

;展开方式(举例):

;HandlerFIQ   HANDLERHandleFIQ

;展开后变成:

;HandlerFIQ                                ;标号,由 " b       HandlerFIQ  "指令使用(见上,复位处)

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

;     

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

;     

;         ldr    r0,=HandleFIQ  ;HandleFIQ标号,在本文件最下方定义

;     

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

;     

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

;     

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

;     

; 后边的语句展开方式,同上。编译后,代码都展开放置

HandlerFIQ    HANDLERHandleFIQ

HandlerIRQ    HANDLERHandleIRQ

HandlerUndef HANDLER HandleUndef

HandlerSWI   HANDLERHandleSWI

HandlerDabort       HANDLER HandleDabort

HandlerPabort HANDLER HandlePabort

;非向量中断总入口(需要自己判断中断类型,而不是直��跳转到相应程序)

;产生中断后,需要中断服务程序自己来判断,到底是哪个中断请求,根据的就是INTOFFSET寄存器中的偏移,再计算中断服务地址

IsrIRQ

sub  sp,sp,#4      ;reserved for PC,预留返回指针的存储位置

stmfd      sp!,{r8-r9}

ldr   r9,=INTOFFSET    ;the interrupt request source offset

ldr   r9,[r9]

ldr   r8,=HandleEINT0         ;HandleEINT0 ,在本文件最下边定义的

add  r8,r8,r9,lsl #2        ;r9中只是偏移单位的个数,需要*4变成具体字节偏移(相对于EINT0)

ldr   r8,[r8]

str    r8,[sp,#8]                     ;pc值放在了高位置

ldmfd      sp!,{r8-r9,pc}

LTORG

;LTORG用于声明一个文字池,在使用LDR伪指令时,要在适当的地方加入LTORG声明文字池,这样就会把要加载的数据保存在

;文字池内,再用ARM的《加载指令》读出数据。(若没有使用LTORG声明文字池,则汇编器会在程序末尾自动声明)

;LTORG 伪指令常放在无条件跳转指令之后,或者子程序返回指令之后,这样处理器就不会错误地将文字池中的数据当做指令来执行

;注:在此,文字池内存储的是INTOFFSET宏所代表的值:0x4a000014  。毕竟,当把指令编译成二进制代码时,arm指令(32位)

;不能既表示出指令内容,又表示出数据地址(32位)。估计在编译时,会被汇编成其他的加载指令,再编译成机器码

;LTORG 只要单独写出来就可以了,其他的交给编译器来做,而且它跟它下面的代码没有任何关系

;=======

; ENTRY

;=======            

ResetHandler               

ldr   r0,=WTCON       ;watch dog disable   编译时就是 ldr r0,=53000000;伪指令有=号

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

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