1.Remap
对重映射控制寄存器(地址0xffffff00)写0x1——保存或取消重映射
重映射原因:
由于板子启动是从地址0x00开始,并且中断向量表从0x00开始。但是当调试程序时,程序放在SRAM中,其地址在at91rm9200中是从0x200000开始的。当程序中需要进入中断的时候,要访问中断向量表。Arm架构将中断向量表放置在0x00处。实际上物理地址中0x00处并没有,中断向量表定义在物理地址中SRAM开始处。所以需要重映射,将0x00对应的地址指向了0x200000的空间。
重映射实际上是以0x00对应的地址指向了0x200000的空间,也就是重映射以后,0x0与0x200000指向同一片空间。
而这些功能对于有中断的情况时是必须的。
但是如果用不到中断的话,就不需要重映射,只需要在开始的时候,也就是pc为0x0的时候,将其值修改为程序的存储空间,也就是0x200000,这样就可以了
判断重映射标准:
修改0x0对应的地址中的值,如果可以修改则已经重映射,如果修改不了,就没有重映射。
中断向量的定义:
AREA RESET, CODE, READONLY ARM EXPORT Vectors Vectors LDR PC,Reset_Addr LDR PC,Undef_Addr LDR PC,SWI_Addr LDR PC,PAbt_Addr LDR PC,DAbt_Addr NOP ; Reserved Vector ldr pc, [pc,#-0xf20] LDR PC,FIQ_Addr
Reset_Addr DCD Reset_Handler Undef_Addr DCD Undef_Handler SWI_Addr DCD SWI_Handler PAbt_Addr DCD PAbt_Handler DAbt_Addr DCD DAbt_Handler DCD 0 ; Reserved Address FIQ_Addr DCD FIQ_Handler
Undef_Handler B Undef_Handler SWI_Handler B SWI_Handler PAbt_Handler B PAbt_Handler DAbt_Handler B DAbt_Handler FIQ_Handler B FIQ_Handler
|
2.关于ldr pc, [pc,#-0xf20]
AIC采用硬件中断向量化。硬件中断向量化将到达中断处理入口所需的指令减少到只有一条,即位于地址0x00000018的ldr pc, [pc,#-0xf20]
US、TC、PIO的中断都属于IRQ中断。ARM核的中断只有reset、undefined、prefetch abort、data abort、SWI、IRQ和FIQ这7种。其中IRQ的向量位于第7位。从地址0算起,地址为(7-1)*4=24=0x18
执行此条指令时,由ARM的流水线结构可知,现时的PC为0x00000018+2*4=0x20
(#define AT91C_AIC_IVR ((AT91_REG *) 0xFFFFF100) // (AIC) IRQ Vector Register)
因此,执行后PC被赋予了地址0x20-0xF20=0x FFFFF100的内容,即IRQ向量寄存器AIC_IVR的内容。程序跳转到相应的中断例程中。
执行上述指令后,PC被赋予了保存于AIC_IVR的中断处理例程的入口地址。于是程序开始执行当前中断的处理例程。
3.如果SRAM中程序大于16k,启动就出错
SRAM(片内)只有16k,程序需要放在SDRAM中(片外)。
而SDRAM需要初始化,重映射,这样就需要preload。
Preload的代码在0x200000处,而目标程序放在0x20000000处
改变pc的值,指向0x20000000.
启动代码
一上电就运行的程序,完成各种初始化工作并引导进入c程序。
Cpu在上电之后,紧接着就从地址0开始取得第一条指令的代码来执行
所以说地址0的地方必须在上电的时候就存在可执行的正确代码,也就是地址0的地方应该是ROM区,至少在上电之后一小段时间内是ROM区。
有如下一些部分的初始化:
一、定义入口点
AREA RESET, CODE, READONLY ARM EXPORT Vectors
|
二、设置中断向量
Remap之前是地址为0的地方
Vectors LDR PC,Reset_Addr LDR PC,Undef_Addr LDR PC,SWI_Addr LDR PC,PAbt_Addr LDR PC,DAbt_Addr NOP ; Reserved Vector ldr pc, [pc,#-0xf20] LDR PC,FIQ_Addr Reset_Addr DCD Reset_Handler Undef_Addr DCD Undef_Handler SWI_Addr DCD SWI_Handler PAbt_Addr DCD PAbt_Handler DAbt_Addr DCD DAbt_Handler DCD 0 ; Reserved Address FIQ_Addr DCD FIQ_Handler
Undef_Handler B Undef_Handler SWI_Handler B SWI_Handler PAbt_Handler B PAbt_Handler DAbt_Handler B DAbt_Handler FIQ_Handler B FIQ_Handler
|
三、初始化堆栈指针寄存器
EXPORT Reset_Handler Reset_Handler LDR R0, =Stack_Top
; Enter Undefined Instruction Mode and set its Stack Pointer MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit MOV SP, R0 SUB R0, R0, #UND_Stack_Size
; Enter Abort Mode and set its Stack Pointer MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit MOV SP, R0 SUB R0, R0, #ABT_Stack_Size
; Enter FIQ Mode and set its Stack Pointer MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit MOV SP, R0 SUB R0, R0, #FIQ_Stack_Size
; Enter IRQ Mode and set its Stack Pointer MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit MOV SP, R0 SUB R0, R0, #IRQ_Stack_Size
; Enter Supervisor Mode and set its Stack Pointer MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit MOV SP, R0 SUB R0, R0, #SVC_Stack_Size
; Enter User Mode and set its Stack Pointer MSR CPSR_c, #Mode_USR IF :DEF:__MICROLIB
EXPORT __initial_sp
ELSE
MOV SP, R0 SUB SL, SP, #USR_Stack_Size
ENDIF
|
四、初始化存储器系统(调用一段c程序)
IMPORT AT91F_LowLevelInit
ldr r0, = AT91F_LowLevelInit mov lr, pc bx r0
|
五、初始化c环境(c程序用到的存储区)
IMPORT |Image$$RO$$Limit| IMPORT |Image$$RW$$Base| IMPORT |Image$$ZI$$Base| IMPORT |Image$$ZI$$Limit| LDR R0,=|Image$$RO$$Limit| ;RO段结束地址加1 ,表示RO区末地址后面的地址,即RW数据源的起始地址,应该是RW数据的加载地址 ;RW数据总数为:|Image$$ZI$$Base|-|Image$$RW$$Base|。 ;即RW数据源的值放在区间 LDR R1,=|Image$$RW$$Base| ;RW区在RAM里的执行区起始地址,也就是编译器选项RW_Base指定的地址,应该是RW运行地址 LDR R3,=|Image$$ZI$$Base|;RW型数据初值挎贝(R0为当前要挎贝数据地址) CMP R0,R1 BEQ LOOP1 ;如果当前挎贝源地址和目标地址(RW型数据空间起始点)相等,结束。 LOOP0 CMP R1,R3 ;比较当前挎贝目标地址和ZI型数据空间起始点 LDRCC R2,[R0],#4 ;如果不等时,取出当前挎贝源地址所对应空间的值,同时源地址加4(指向下一空间) STRCC R2,[R1],#4 ;将取出的值放到当前挎贝目标地址所对应空间,同时目标地址加4(指向下一空间) BCC LOOP0 ;继续挎贝 ;否则,进入ZI型数据空间置零操作。 LOOP1 LDR R1,=|Image$$ZI$$Limit| MOV R2,#0 LOOP2 CMP R3,R1 ;比较当前目标地址是不是和ZI型数据空间结束点后一空间地址相同 STRCC R2,[R3],#4 ;如果不相同,当前目标地址所对应的空间置零,目标地址加4(指向下一空间) ; BCC LOOP2 ;继续置零 ;否则,结束初始化。
|
先把ROM里|Image$$RO$$Limt|开始的RW初始数据拷贝到RAM里面|Image$$RW$$Base|开始的地址,当RAM这边的目标地址到达|Image$$ZI$$Base|后就表示RW区的结束和ZI区的开始,接下去就对这片ZI区进行清零操作,直到遇到结束地址|Image$$ZI$$Limit|。只有这样,程序执行才能可靠运行。
六、进入c程序
IMPORT main LDR R0, =main BX R0
|
附件里的源代码是把程序映射到0x20000000开始的sdrm中