Chinaunix首页 | 论坛 | 博客
  • 博客访问: 395564
  • 博文数量: 68
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 491
  • 用 户 组: 普通用户
  • 注册时间: 2013-10-19 20:11
文章分类

全部博文(68)

文章存档

2015年(13)

2014年(30)

2013年(25)

我的朋友

分类: 嵌入式

2015-04-30 14:27:21

原文地址: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    ;NORNAND启动,ResetEntry 都为0, 但上面已经排除了NOR启动       

       cmp r0, #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        ;接着读取NANDID,结果保存在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   ;r832的整数倍(0,32,64...),eq有效,ne无效  

    bne     %F3         ;若不是32的整数倍,不是当前块的头一页,跳转到标号3处,不用检查坏块。  

    mov     r0, r8          ;ands结果所有位为0,即r832的整数倍或为0,是每个Block 的头一页  

    bl      CheckBadBlk     ;检查NAND的坏区,结果保存到r0r0是 0说明当前块不是坏块   

    cmp     r0, #0          ;比较 r0 0, r0  0, not bad block  

addne   r8, r8, #32      ;存在坏块的话就跳过这个坏块: +32得到下一块.(1 block=32 page);         

bne     %F4          ;若有坏块就跳到4进行循环条件判断。没有坏块的话就跳到标号3copy 当前页 

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往回跳转到标号0  

    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    ;R2r1,然后 r0=r0+4, r0RW 数据段在ROM 内的起始地址  

    strcc    r1, [r2], #4    ;r2 |Image$$RW$$Base|地址,由编译器指定  

    bcc %B0                  ;r2RW段还没有复制完  

   mov r0, #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

    ]

阅读(1776) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~