;这里引入一些在其它文件中实现在函数,包括为我们所熟知的main函数
IMPORT Main ; The main entry of mon program
;从这里开始就是真正的代码入口了!
AREA Init,CODE,READONLY;这表明下面的是一个名为Init的代码段
ENTRY ;定义程序的入口(调试用)
EXPORT __ENTRY ;导出符号_ENTRY
__ENTRY
ResetEntry
;1)The code, which converts to Big-endian, should be in little endian code.
;2)The following little endian code will be compiled in Big-Endian mode.
; The code byte order should be changed as the memory bus width.
;3)The pseudo instruction,DCD can not be used here because the linker generates error.
;***********************************************************
1、ASSERT :DEF:ENDIAN_CHANGE
ASSERT 是断言伪指令,语法是:ASSERT +逻辑表达式
def 是逻辑伪操作符,格式为: :DEF:label,作用是:判断label是否定义过
2、四句蓝色的指令能且只能执行一句,并且前三句若执行跳转后处理程序的最后一句也是
b ResetHandler
3、" [ " 相当于 if
" | "相当于else
" ] " 相当于endif
;***************************************************************
ASSERT :DEF:ENDIAN_CHANGE ;判断是否定义了模式改变
[ ENDIAN_CHANGE
ASSERT :DEF:ENTRY_BUS_WIDTH ;判断是否定义了总线宽度
;条件分支语句1:如果存储器是32位的总线宽度
[ ENTRY_BUS_WIDTH=32
b ChangeBigEndian ;DCD 0xea000007
]
;条件分支语句2:如果存储器是16位的总线宽度
[ ENTRY_BUS_WIDTH=16
andeq r14,r7,r0,lsl #20 ;DCD 0x0007ea00
]
;条件分支语句3:如果存储器是8位的总线宽度
[ ENTRY_BUS_WIDTH=8
streq r0,[r0,-r10,ror #1] ;DCD 0x070000ea
]
| ;如果没有定义总线宽度,则返回复位中断
b ResetHandler
]
b HandlerUndef ;handler for Undefined mode
b HandlerSWI ;handler for SWI interrupt
b HandlerPabort ;handler for PAbort
b HandlerDabort ;handler for DAbort
b . ;reserved
b HandlerIRQ ;handler for IRQ interrupt
b HandlerFIQ ;handler for FIQ interrupt
;@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
]
[ ENTRY_BUS_WIDTH=16
DCD 0x0f10ee11
DCD 0x0080e380
DCD 0x0f10ee01
]
[ ENTRY_BUS_WIDTH=8
DCD 0x100f11ee
DCD 0x800080e3
DCD 0x100f01ee
]
DCD 0xffffffff ;swinv 0xffffff is similar with NOP and run well in both endian mode.
DCD 0xffffffff
DCD 0xffffffff
DCD 0xffffffff
DCD 0xffffffff
b ResetHandler
;如上所说,这里采用HANDLER宏去建立Hander***和Handle***之间的联系
HandlerFIQ HANDLER HandleFIQ
HandlerIRQ HANDLER HandleIRQ
HandlerUndef HANDLER HandleUndef
HandlerSWI HANDLER HandleSWI
HandlerDabort HANDLER HandleDabort
HandlerPabort HANDLER HandlePabort
;=========================================================================
;呵呵,来了来了.好戏来了,这一段程序就是用来进行第二次查表的过程了.
;如果说第一次查表是由硬件来完成的,那这一次查表就是由软件来实现的了.
;为什么要查两次表??
;没有办法,ARM把所有的中断都归纳成一个IRQ中断异常和一个FIRQ中断异常
;第一次查表主要是查出是什么异常,可我们总要知道是这个中断异常中的什么中断呀!
;没办法了,再查一次表呗!
;========================================================================
IsrIRQ
sub sp,sp,#4 ; 给PC寄存器保留
stmfd sp!,{r8-r9} ; 把r8-r9压入栈
ldr r9,=INTOFFSET ; 把中断偏移INTOFFSET的地址装入r9
ldr r9,[r9] ; 把中断偏移INTOFFSET的值装入r9
ldr r8,=HandleEINT0 ; 这就是向量表的入口HandleEINT0装入r8
;把中断服务程序装入
add r8,r8,r9,lsl #2 ;为什么左移两位?不是很清楚
ldr r8,[r8] ; 装入中断服务程序的入口
str r8,[sp,#8] ;把入口压入堆栈
ldmfd sp!,{r8-r9,pc} ;出栈
LTORG ;声明文字池