关于启动代码中NANDFLASH启动相关代码的解释

来源:互联网 发布:淘宝贝幼儿园收费 编辑:程序博客网 时间:2024/04/28 01:34
首先转载一篇文章。
转自:http://blog.csdn.net/canjiangsu/article/details/6584791
 

[置顶] 原来程序是这样从NandFlash拷贝并跳转到SDRAM的

重新看了一下FL2440的BootLoader,终于把程序是怎样从Nandflash拷贝并跳转到SDRAM的过程弄清楚了,在这边做一下笔记。先上张图:

1.

当S3C2440被配置成从Nand Flash启动时, S3C2440的Nand Flash控制器会在 S3C2440上电时自动把NandFlash上的前4K代码搬移到Boot Internal SRAM,然后系统从起始地址是0x0000_0000的Boot Internal SRAM启动,在这4K代码中我们必须完成CPU的核心配置,把NandFlash上的代码全部拷贝到SDRAM中去,然后跳转到SDRAM中去执行剩余的代码(进入操作系统等等);

 

2.

这一步完成的是把NandFlash上的代码拷贝到SDRAM的过程:

(1)先判断是从nor启动还是从nand启动      

     ldr        r0,=BWSCON

             ldr        r0,[r0]

             ands     r0,r0, #6                  ;OM[1:0] != 0, NOR FLash boot

             bne      NORRoCopy           ;don't read nand flash

             adr       r0,ResetEntry          ;OM[1:0] == 0, NAND FLash boot // ADR 装载参照的地址=subr0,pc,#off_set;

             cmp      r0,#0                      ;if use Multi-ice,//JTAG调试时是直接下载到SDRAM中运行,不需要再从nand拷贝

             bne      InitRamZero            ;don't read nand flash for boot


注意哦,执行adr r0,ResetEntry 后,r0 = PC - off_set,adr得到是相对地址而不是绝对地址。ResetEntry是整个程序的入口处,由链接器指定入口地址,如下图,ResetEntry=RO Base=0x3001_0000|Image$$RO$$Base|。当程序在SDRAM中运行时,当前PC=0x3001_0000+off_set,r0=0x3001_0000,当程序在Boot Internal SRAM运行时,由于程序是从0x0000_0000开始运行的,所以当前PC=0x0000_0000+off_set,即r0=0x0000_0000。所以可以通过 cmp r0,#0来判断程序是否运行在Boot Internal SRAM,如果是,则把NandFlash中的程序拷贝到SDRAM。


(2)从NandFlash拷贝程序到SDRAM

在这步中最让我困惑的是在SDRAM中从哪个地址开始存放从NandFlash拷过来的程序。

;===========================================================
;//将程序从nandflash拷贝到sdram
;===========================================================
nand_boot_beg
            bl         ClearSdram
            mov      r5,#NFCONF
            ;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
            mov      r6,#0
            ldr        r0,=0xecF1
            cmp      r5,        r0
            beq      %F1
;           ldr        r0,=0xecda
;           cmp      r5,r0
            mov      r6,#1                            ;Nandaddr(寻址周期 0:4 1:5)
1         
            bl         ReadNandStatus
           
            mov      r8,#0
            ldr        r9,=ResetEntry
            mov r10,#32                              ;+081010 feiling


上面代码中最关键的是这句:

 ldr        r9,=ResetEntry

其它都是一些NandFlash的相关设置与操作细节,先不管了。这据代码中用ldr来获得在SDRAM存放代码的起始地址,ldrResetEntry的绝对地址|Image$$RO$$Base|赋给了r9。也就是说,从NandFlash拷过来的代码放在了SDRAM中从|Image$$RO$$Base|开始的地址空间里。

 

3.

CPU配置完了,程序和数据也都拷到SDRAM里了,该跳转到SDRAM里去做其他事情了,怎么知道是否跳转到SDRAM呢?这还是地址啊。我之前一直搞不清楚为什么一句ldr pc,=CEntrybl Main 就能从Boot Internal SRAM直接跳到SDRAM,原来在编译的时候,像ResetEntryCEntry这些表示地址的标号都被赋于从|Image$$RO$$Base|开始之后的地址,只要|Image$$RO$$Base|大等于0x3000_0000,利用ldr取得绝对地址后赋给PC就能直接跳转到SDRAM里去了。我之前一直以为ResetEntry=0x0000_0000,而且分不清ldradr之间的差别,因此纠结了好久。  

ldr        pc,=CEntry                   ;goto compiler address
 
CEntry
            bl         Main                  ;Don t use main()because ......
            b          .

洗洗睡了,明天再看一下中断向量表。


评论:这也说不通, 因为程序中还有这样的代码: ADR R0,ResetEntry 这条指令R0最终存的也是ResetEntry的绝对地址, 只是编译器解释成pc+ResetEntry相对于当前pc的偏移地址, 如果ResetEntry的绝对地址是0x30000000,那这个偏移地址就太大了, 这条指令编译时应该通不过才对! 
如果你说的都对,那在执行ldr pc, =copy_proc_beg 的时候,它就已经进入SDRAM中了
Re: BugSu 2012-05-25 18:08发表 [回复]
回复shuizhonglinsname:ADR R0,ResetEntry
这条指令执行后,R0的值是当前PC值减去一个固定值得到的,这个固定值假设为off_set;当程序在SDRAM和Boot Internal SRAM里执行ADR R0,ResetEntry这句时的PC是不同的,这时的PC值在SDRAM比在Boot Internal SRAM里大0x3001_0000,所以当程序在Boot Internal SRAM里时得到的R0是0,而在Boot Internal SRAM里运行时得到的R0是0x3001_0000。


补充一点:关于启动代码中特殊寄存器赋值用LDR以及引用自定义标示用ADR的解释:

特殊寄存器赋值用LDR是因为位置固定。

引用自定义标示用ADR是为了保证代码与地址无关。启动时执行启动代码如果改用ADR的话,标号的值就为SDRAM中的地址去了,而不而不是IRAM中启动代码所标示的标示的位置了。举例如下:

在SDRAM初始化代码中有一句:

adrl   r0,SMRDATA

而在IsrIRQ中的:ldr    r8,=HandleEINT0处用了ldr的原因是IRQ中是不可能执行此处的代码的,因为启动时IRQ中断是关闭的。

原创粉丝点击