微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > s3c2440启动文件详细分析

s3c2440启动文件详细分析

时间:11-19 来源:互联网 点击:
总线模式
IMPORTMMU_SetAsyncBusMode
IMPORTMMU_SetFastBusMode;

;导入Main,它为C语言程序入口函数
IMPORTMain; The main entry of mon program
;导入用于复制从Nand Flash中的映像文件到SDRAM中的函数
IMPORTRdNF2SDRAM; Copy Image from Nand Flash to SDRAM

;定义代码段,名为Init
AREAInit,CODE,READONLY

;在入口处(0x0)开始的8个字单元空间内,存放的是ARM异常中断向量表,每个字单元空间都是一条跳转指令,当异常发生时,ARM会自动跳转到相应的中断向量处,并由该处的跳转指令再跳转到相应的执行函数处
ENTRY;程序入口处
EXPORT__ENTRY;导出__ENTRY,即导出代码段入口地址
__ENTRY;主要用于MMU
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.
;在0x0处的异常中断是复位异常中断,是上电后执行的第一条指令
;变量ENDIAN_CHANGE用于标记是否要从小端模式改变为大端模式,因为编译器初始模式是小端模式,如果要用大端模式,就要事先把该变量设置为TRUE,否则为FLASE
;变量ENTRY_BUS_WIDTH用于设置总线的宽度,因为用16位和8位宽度来表示32位数据时,在大端模式下,数据的含义是不同的
;由于要考虑到大端和小端模式,以及总线的宽度,因此该处看似较复杂,其实只是一条跳转指令:当为大端模式时,跳转到ChangeBigEndian函数处,否则跳转到ResetHandler函数处
ASSERT:DEF:ENDIAN_CHANGE;判断是否定义了ENDIAN_CHANGE
;如果没有定义,则报告该处错误信息
[ ENDIAN_CHANGE;if ENDIAN_CHANGE ==TRUE
ASSERT:DEF:ENTRY_BUS_WIDTH;判断是否定义了ENTRY_BUS_WIDTH
;如果没有定义,则报告该处错误信息

[ ENTRY_BUS_WIDTH=32;if ENTRY_BUS_WIDTH ==32
;跳转到ChangeBigEndian(ChangeBigEndian在0x24),因此该条指令的机器码为0xea000007
;所以该语句与在该处(即0x0处)直接放入0xea000007数据(即DCD 0xea000007)作用相同
bChangeBigEndian
]

[ ENTRY_BUS_WIDTH=16;if ENTRY_BUS_WIDTH ==16
;在小端模式下,用16位或8位数据总线宽度表示32位数据,与用32位总线宽度表示32位数据,格式完全一致。但在大端模式下,格式就会发生变化
;在复位时,系统默认的是小端模式,所以就要人为地改变数据格式,使得用16位大端数据表示的32位数据也能被小端模式的系统识别
;该语句的目的也是跳转到ChangeBigEndian,即机器码也应该是0xea000007,但为了让小端模式系统识别,就要把机器码的顺序做一下调整,改为0x0007ea00,那么我们就可以用DCD 0x0007ea00把机器码装载进去了,但由于该处不能使用DCD伪指令,因此我们就要用一条真实的指令来代替DCD 0x0007ea00,即该指令编译后的机器码也为0x0007ea00,而andeqr14,r7,r0,lsl #20就是一条编译后机器码为0x0007ea00的指令,所以我们在该处写上该条指令
andeqr14,r7,r0,lsl #20;DCD 0x0007ea00
]

[ ENTRY_BUS_WIDTH=8;if ENTRY_BUS_WIDTH ==8
;该语句的分析与上一段代码的分析相似
;streqr0,[r0,-r10,ror #1]编译后的机器码为0x070000ea
streqr0,[r0,-r10,ror #1] ;DCD 0x070000ea
]
|;else即ENDIAN_CHANGE ==FALSE
bResetHandler;跳转到ResetHandler处,复位
]
bHandlerUndef;未定义
bHandlerSWI;软件中断
bHandlerPabort;指令预取中止
bHandlerDabort;数据访问中止
b.;保留,跳转到自身地址处,即进入死循环
bHandlerIRQ;外部中断请求
bHandlerFIQ;快速中断请求
;以上为异常中断向量表

;跳转到EnterPWDN,处理电源管理的其他非正常模式,在C语言程序段中被调用
;该处地址为0x20,至于为什么要在该处执行,我认为可能是该处离异常中断向量表最近吧
bEnterPWDN; Must be @0x20.

;由0x0跳转至此,目的是把小端模式改为大端模式,即把CP15中的寄存器C1中的第7位置1
ChangeBigEndian
;@0x24
[ ENTRY_BUS_WIDTH=32;if ENTRY_BUS_WIDTH == 32
;执行mrc p15,0,r0,c1,c0,0,得到CP15中的寄存器C1,放入r0中
;由于mrc p15,0,r0,c1,c0,0的机器码为0xee110f10
;因此DCD0xee110f10的意思就是mrc p15,0,r0,c1,c0,0。下同
DCD0xee110f10;0xee110f10 => mrc p15,0,r0,c1,c0,0
;执行orr r0,r0,#0x80,置r0中的第7位为1,表示选择大端模式
DCD0xe3800080;0xe3800080 => orr r0,r0,#0x80;//Big-endian
;执行mcr p15,0,r0,c1,c0,0,把r0写入CP15中的寄存器C1
DCD0xee010f10;0xee010f10 => mcr p15,0,r0,c1,c0,0
]
[ ENTRY_BUS_WIDTH=16;if ENTRY_BUS_WIDTH == 16
;由于此时系统还不能识别16位或8位大端模式下表示的32为数据
;因此还需人为地进行数据调整,即把0xee110f10变为0x0f10ee11
;然后用DCD指令存入该数据。下同
DCD 0x0f10ee11
DCD 0x0080e380
DCD 0x0f10ee01
]
[ ENTRY_BUS_WIDTH=8;if ENTRY_BUS_WIDTH == 8
DCD 0x100f11ee
DCD 0x800080e3
DCD 0x100f01ee
]
;相当于NOP指令
;作用是等待系统从小端模式向大端模式转换
;此后系统就能够自动识别出不同总线宽度下的大端模式,因此以后就无需再人为调整指令了
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;跳转到ResetHandler

;当系统进入异常中断后,由存放在0x0~0x1C处的中断向量地址中的跳转指令,跳转到此处相应的位置,并由事先定义好的宏定义再次跳转到相应的中断服务程序中
HandlerFIQHANDLER HandleFIQ
HandlerIRQHANDLER HandleIRQ
HandlerUndefHANDLER HandleUndef
HandlerSWIHANDLER HandleSWI
HandlerDabortHANDLER HandleDabort
HandlerPabortHANDLER HandlePabort

;下面这段代码是用于处理非向量中断,即由软件程序来判断到底发生了哪种中断,然后跳转到相应地中断服务程序中
;具体地说就是,当发生中断时,会置INTOFFSET寄存器相应的位为1,然后通过查表(见该程序末端部分的中断向量表),找到相对应的中断入口地址
;观察中断向量表,会发现它与INTOFFSET寄存器中的中断源正好相对应,即向量表的顺序与INTOFFSET寄存器中的中断源的由小到大的顺序一致,因此我们可以用基址加变址的方式很容易找到相对应的中断入口地址。其中基址为向量表的首个中断源地址,变址为INTOFFSET寄存器的值乘以4(因为系统是用4个字节单元来存放一个中断向量)
IsrIRQ
subsp,sp,#4;在栈中留出4个字节空间,以便保存中断入口地址
stmfdsp!,{r8-r9};由于要用到r8和r9,因此保存这两个寄存器内的值

ldrr9,=INTOFFSET;把INTOFFSET寄存器地址装入r9内
ldrr9,[r9];读取INTOFFSET寄存器内容
ldrr8,=HandleEINT0;得到中断向量表的基址
addr8,r8,r9,lsl #2;用基址加变址的方式得到中断向量表的地址
ldrr8,[r8];得到中断服务程序入口地址
strr8,[sp,#8];使中断服务程序入口地址入栈
ldmfdsp!,{r8-r9,pc};使r8,r9和入口地址出栈,并跳到中断服务程序中

;定义一个数据缓冲池,供ldr伪指令使用
LTORG

;=======
; ENTRY
;=======
;系统上电或复位后,由0x0处的跳转指令,跳转到该处开始真正执行系统的初始化工作
ResetHandler
;在系统初始化过程中,不需要看门狗,因此关闭看门狗功能
ldrr0,=WTCON;watch dog disable
ldrr1,=0x0
strr1,[r0]

;同样,此时也不应该响应任何中断,因此屏蔽所有中断,以及子中断
ldrr0,=INTMSK
ldrr1,=0xffffffff;all

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top