分类: 嵌入式
2014-04-26 19:10:45
原文地址:mini2440启动代码分析之第九篇 作者:
;==========================================================================================
;下面这段代码进行复制前的判断,因为从 NAND Flash 与从NOR Flash 启动的复制过程是大不相同的。这段程序能在nor nand flash 运行,也可以在内存中运行。在nor nand flash运行,需要拷贝数据; BWSCON 的[2:1]反映了外部引脚 OM[1:0]:若 OM[1:0] != 00, 从NOR FLash 启动或直接在内存运行;若 OM[1:0] 00,则为从Nand Flash 启动
;===========================================================================================
ldr r0, =BWSCON
ldr r0, [r0]
ands r0, r0, #6
bne copy_proc_beg ;若从NOR启动,跳转到标号copy_proc_beg
adr r0, ResetEntry ;从NOR或NAND启动,ResetEntry 都为0, 但上面已经排除了NOR启动
cmp r0, #0 ;所以入口是0 地址表示是从 NAND 的 StepingStone启动
bne copy_proc_beg ;若从 NOR 启动,跳转到标号 copy_proc_beg。否则往下执行
;nop
;===============================================================================
nand_boot_beg
[ {TRUE}
bl CopyProgramFromNand ;执行从nandflash拷贝数据子程序,此时nandflash代码已经被拷贝到了SDRAM中
|
;nand flash启动,拷贝程序到steppingstone区域
mov r5, #NFCONF ;拷贝完成后进入SDRAM中执行程序(在运行域中执行代码),pc指向SDRAM中代码
;set timing value
ldr r0, =(7<<12)|(7<<8)|(7<<4)
str r0, [r5]
;enable control
ldr r0, =(0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0)
str r0, [r5, #4]
bl ReadNandID ;接着读取NAND的ID号,结果保存在r5里
mov r6, #0 ;r6设初值0.
ldr r0, =0xec73 ;期望的NAND ID号
cmp r5, r0 ;这里进行比较,r5是读取到的ID
beq %F1 ;相等的话就跳到下一个1标号处
ldr r0, =0xec75 ;这是另一个期望值
cmp r5, r0 ;这里进行比较
beq %F1 ;相等的话就跳到下一个1标号处
mov r6, #1 ;若ID不是0xec73 或 0xec75, 设置 r6=1,否则 r61
bl ReadNandStatus ;读取NAND状态,结果放在r1里
mov r8, #0 ;r8设初值0,意义为页号(start page address)
ldr r9,=ResetEntry ;r9设初值为 ResetEntry 的绝对地址 |Image$$RO$$Base|=0x30000000,
2
ands r0, r8, #0x1f ;若r8为32的整数倍(0,32,64...),eq有效,ne无效
bne %F3 ;若不是32的整数倍,不是当前块的头一页,跳转到标号3处,不用检查坏块。
mov r0, r8 ;若ands结果所有位为0,即r8是32的整数倍或为0,是每个Block 的头一页
bl CheckBadBlk ;检查NAND的坏区,结果保存到r0,r0是 0说明当前块不是坏块
cmp r0, #0 ;比较 r0 和0, r0 0, not bad block
addne r8, r8, #32 ;存在坏块的话就跳过这个坏块: +32得到下一块.(1 block=32 page);
bne %F4 ;若有坏块就跳到4进行循环条件判断。没有坏块的话就跳到标号3处copy 当前页
3
mov r0, r8 ;加载当前页号到r0
mov r1, r9 ;加载复制数据的目标地址到r1 (0x30000000)
bl ReadNandPage ;读取该页的NAND数据到SDRAM中由r1指定的地址
add r9, r9, #512 ;目标地址+512(每一页的大小是512Bytes) 用于复制下一页数据
add r8, r8, #1 ;r8指向下一页
4
cmp r8, #256 ;比较是否读完256页即128KBytes 共复制 8blocks 128KB 到SDRAM
bcc %B2 ;如果r8小于 256(没读完256页),就返回前面的标号2处读取下一页,复制完成后要关闭 NAND控制器
mov r5, #NFCONF ;Disable NandFlash
ldr r0, [r5]
and r0, r0, #~0x8000 ;clear bit15, Disable NAND Controller
str r0, [r5]
ldr pc, =copy_proc_beg
;========================================================================================
copy_proc_beg
adr r0, ResetEntry ;从这里开始ResetEntry变成了0x30000000
ldr r2, BaseOfROM ;加载BaseOfROM内的数据即|Image$$RO$$Base|=0x30000000
cmp r0, r2 ;如果从norflash启动,那么 ResetEntry=0 BaseOfROM=0x3000000,显然不相同
ldreq r0, TopOfROM ;如果相等的话,加载|Image$$RO$$Limit|到r0,作为复制RW数据段的起始地址
beq InitRam ;同时跳到InitRam进行RW数据段的复制
ldr r3, TopOfROM
0 ;循环复制Code数据
ldmia r0!, {r4-r7} r0的初始值ResetEntry=0
stmia r2!, {r4-r7} ;r2的初始值RO Base(0x30000000)
;上面的2行代码将从0开始的地址内的数据保存到SDRAM内以RO Base 开始的地址内
cmp r2, r3 ;复制的终止条件:复制了(RO Limit - RO Base) 大小,即整个RO数据段
bcc %B0 ;若r2
sub r2, r2, r3 ;r0+16,r2+16 every time,if r2>r3
sub r0, r0, r2 ;将可能多加的部分减回来,让r0对准ROM 内RO段的结束点,也是RW数据段的开始点
InitRam ;从NOR Flash 复制RW段到SDRM中预设的RW BASE位置
ldr r2, BaseOfBSS ;r2= |Image$$RW$$Base|=|Image$$RO$$Limit|
ldr r3, BaseOfZero ;r3= |Image$$ZI$$Base|
0 ;复制RW数据到BaseOfBSS
cmp r2, r3 ;比较r2,r3;看RW数据段有没有复制完
ldrcc r1, [r0], #4 ;R2
strcc r1, [r2], #4 ;r2 为|Image$$RW$$Base|地址,由编译器指定
bcc %B0 ;若r2
mov r0, #0 ;用0 初始化ZI 区
ldr r3, EndOfBSS ;r3 = |Image$$ZI$$Limit| ; ZI 段的结束地址
1
cmp r2, r3 ;r2 是RW limit,也就是 ZI 段的起始地址
strcc r0, [r2], #4 ;ZI 数据段清 0
bcc %B1
ldr pc, =%F2 ;goto compiler address
2
; [ CLKDIV_VAL>1 ; means Fclk:Hclk is not 1:1.
; bl MMU_SetAsyncBusMode
; |
; bl MMU_SetFastBusMode ; default value.
; ]
;bl Led_Test
;==========================================================================================
;进入C语言前的最后一步了,就是把我们用说查二级向量表的中断例程安装到一级向量表(异常向量表)里.
;==========================================================================================
; Setup IRQ handler
ldr r0,=HandleIRQ ;IRQ中断服务程序存储地址
ldr r1,=IsrIRQ ;中断查询子程序入口地址
str r1,[r0] ;将中断查询子程序入口地址放入IRQ中断服务程序存储处
; ;Copy and paste RW data/zero initialized data
; ldr r0, =|Image$$RO$$Limit| ; Get pointer to ROM data
; ldr r1, =|Image$$RW$$Base| ; and RAM copy
; ldr r3, =|Image$$ZI$$Base|
;
; ;Zero init base => top of initialised data
; cmp r0, r1 ; Check that they are different
; beq %F2
;1
; cmp r1, r3 ; Copy init data
; ldrcc r2, [r0], #4 ;--> LDRCC r2, [r0] + ADD r0, r0, #4
; strcc r2, [r1], #4 ;--> STRCC r2, [r1] + ADD r1, r1, #4
; bcc %B1
;2
; ldr r1, =|Image$$ZI$$Limit| ; Top of zero init segment
; mov r2, #0
;3
; cmp r3, r1 ; Zero init
; strcc r2, [r3], #4
; bcc %B3
[ :LNOT:THUMBCODE
bl Main ;//跳转到 Main()主函数; 它把$main_entry 的绝对地址赋给 PC,由于程序已经复制到 SDRAM 中,而且$main_entry 的绝对地址是在 SDRAM 范围内,所以从这句代码以后,程序就开
始从 ROM 跳到 SDRAM 内执行了。
;ldr pc, =Main
b . ;就是仍跳回这一指令...不做任何事情的死循环
]
;if thumbcod={ture}
[ THUMBCODE ;若是处于THUMB指令状态
orr lr,pc,#1 ;将pc最低位置1 ,(当操作数寄存器的状态位(位[0])为1时,执行BX指令进入Thumb状态.
bx lr ;转换到THUMB模式
CODE16
bl Main ;Do not use main() because ......
b .
CODE32
]