arm:启动代码判断是从nand启动还是从norflash启动,拷贝程序到内存的过程

2023-09-01  

一、nand启动和nor启动:[1]


  CPU从0x00000000位置开始运行程序。


  1、nand启动:


  如果将S3C2440配置成从NANDFLASH启动(将开发板的启动开关拔到nand端,此时OM0管脚拉低)S3C2440的Nand控制器会自动把Nandflash中的前4K代码数据搬到内部SRAM中(地址为0x40000000),同时还把这块SRAM地址映射到了0x00000000地址。CPU从0x00000000位置开始运行程序。 


  2、如果将S3C2440配置成从Norflash启动(将开发的启动开关拔到nor端,此时OM0管脚拉高),0x00000000就是norflash实际的起始地址,norflash中的程序就从这里开始运行,不涉及到数据拷贝和地址映射


  3、总结:


  nand启动时,地址0x00000000为内部SRAM映射的地址;


  nor启动时,地址0x00000000为norflash的实际起始地址。


  向Norflash中写数据需要特定的命令时序,而向内存中写数据可以直接向内存地址赋值。


 


二、判断是从nand启动还是从norflash启动:


1.根据硬件接线,


  引脚OM1、OM0  :  00: Nand-boot 01: 16-bit 10: 32-bit 11: Test mode


  


  总线宽度和等待控制寄存器(BWSCON)0x48000000      BWSCON_bit[2:1] Indicate data bus width for bank 0 (read only).


  The states are selected by OM[1:0] pins 。(01 = 16-bit, 10 = 32-bit  ...)


what's done before copy?


ResetHandler

    ;WTCON  watch dog disable

    ;INTMSK

    ;INTSUBMSK

    ;To reduce PLL lock time, adjust the LOCKTIME register.

    ;Setting value Fclk:Hclk:Pclk

    ;Configure UPLL 

    ;Configure MPLL

    ;Check if the boot is caused by the wake-up from SLEEP mode.

      ;In case of the wake-up from SLEEP mode, go to SLEEP_WAKEUP handler.

    ;Set memory control registers

    ;Initialize stacks

    bl    InitStacks 

 ; Setup IRQ handler

    ldr r0,=HandleIRQ ;This routine is needed

    ldr    r1,=IsrIRQ    ;if there isn t 'subs pc,lr,#4' at 0x18, 0x1c

    str    r1,[r0]


now copy:


;===========================================================

;// 判断是从nor启动还是从nand启动

;===========================================================

    ldr    r0, =BWSCON

    ldr    r0, [r0]

    ands    r0, r0, #6                ;0110

    bne    NORRoCopy                  ;BWSCON的[2:1]反映了外部引脚OM[1:0].

                                    ;bne:若OM[1:0] != 00, 是从NOR FLash启动.  

                                    ;若OM[1:0]==00,则为Nand Flash Mode.


NandFlashMode

    adr    r0, ResetEntry        ;注意adr得到的是相对地址,非绝对地址.    Cpu刚启动时,ResetEntry==0.

    cmp    r0, #0                ;再比较入口是否为0地址处 

    bne    InitRamZero           ;如果不是0,直接初始化bss段,进入CEntry.

    ;nop

    

    

;===========================================================

;如果ResetEntry==0,说明是cpu刚启动(注意此处是nand启动),那就应该将nand中的代码搬运到sdram中。

;===========================================================

nand_boot_beg

    bl    ClearSdram             ;将内存清零。从内存起始地址--->指定的足够大的范围,不超过内存的实际大小。

    

    mov    r5, #NFCONF            ;nand控制器初始化    

    ;set clk value

    ldr    r0,    =(7<<12):OR:(7<<8):OR:(7<<4)

    str    r0,    [r5]

    ;enable control

    ldr    r0, =(0<<13):OR:(0<<12):OR:(0<<10):OR:(0<<9):OR:(0<<8):OR:(1<<6):OR:(1<<5):OR:(1<<4):OR:(1<<1):OR:(1<<0)

    str    r0, [r5, #4]

    

    bl    ReadNandID            ;读nandId,从而判断nand芯片的种类. r5 = nandId

    mov    r6, #0

    ldr    r0, =0xecF1

    cmp    r5, r0

    beq    %F1                    ;if(nandId==0xecf1){r6=0;//addr_cycle=4}else{r6=1;//addr_cycle=5}

    mov    r6, #1                ;Nandaddr(寻址周期 0:4  1:5)

1    

    bl    ReadNandStatus        ;r1 = ret_of_ReadNandStatus ,这里似乎没有用。

    

    mov        r8, #0                ;page_addr = r8 = 0;

    ldr        r9, =ResetEntry        ;r9 = size_copyed = pBuff = 0;

    mov        r10,#64             ;+081010 feiling     nPages_need_to_copy=64(128KB);

2    

    ands    r0, r8, #0x3f        ;R0 = R8 & 0X3F ; 如果是第一页(mov r8, #0),本式子equal 0;

    bne        %F3                  

    mov        r0, r8                ;如果是第一页,则检测坏块

    bl        CheckBadBlk            ;unsigned int CheckBadBlk(unsigned int    page_addr)

    cmp        r0, #0        

    addne    r8, r8, #64            ;每块的页数 r8 同时也做计数用。 

    addne    r10,r10,#64         ;+081010 feiling  if(is_bad_block){page_addr+=64;nPages_need_to_copy+=64;}

    bne        %F4

3    

    mov    r0, r8

    mov    r1, r9           ;r1 = r9 = size_copyed 

    bl    ReadNandPage 

    add    r9, r9, #2048    ;size_copyed+=2048

    add    r8, r8, #1       ;page_addr+1

4    

    cmp    r8, r10           ;要拷贝的页数 081010 pht .  if(page_addr < nPages_need_to_copy ){copy_loop;}

    bcc    %B2

    

    mov    r5, #NFCONF        ;DsNandFlash

    ldr    r0, [r5, #4]

    bic r0, r0, #1

    str    r0, [r5, #4]

    

    ldr    pc, =InitRamZero    ;此处跳转到内存空间 LDR 装载数据,寻址灵活。 但不改变PSR

                            ;要装载一个被存储的‘状态’并正确的恢复它 可以这样写:ldr r0, [base] 换行  moves pc, r0

;=============================================================================================

;若是从NAND启动,则先清零内存,再从nand[0 ~ user_set_size]拷贝到内存(ro 和.data),再初始化bss段,进入main。

;若是从NOR启动,同样是先清零,后拷贝,再初始化bss段,进入main。为了考虑jlink等调试的情况,避免二次拷贝,才使代码显得复杂。

;其实可以不管,直接全部拷贝过来,nor拷贝比nand拷贝更简单,逐个字节复制即可。;=============================================================================================

NORRoCopy                    ;copy_proc_from_nor_to_sdram

    bl    ClearSdram            ;clear all sdram needed


    adr    r0, ResetEntry        ;判断是否在ROM中运行,ROM即RO指定的地址,从NOR启动时ResetEntry为0

    ldr    r2, BaseOfROM         ;如果相等,说明是jlink调试,调试器将程序.ro段直接下载到了内存,就不需再拷贝。

    cmp    r0, r2                ;pFrom = r0 = ResetEntry(活的) ; pTo = r2 = BaseOfROM(链接文件写死的) ;pEnd = TopOfROM(链接文件写死的)

    beq    NORRwCopy             ;if(ResetEntry==BaseOfROM){skip RoCopyLoop ,directly do RwCopy;}

    

RoCopyLoop                

    ldr r3, TopOfROM             ;

0                            

    ldmia    r0!, {r4-r7}    

    stmia    r2!, {r4-r7}        ;mem_ResetEntry----> mem_BaseOfROM ; pFrom+=4;pTo+=4;

    cmp    r2, r3                ;if(pTo    bcc    %B0

    

NORRwCopy               ;拷贝.data段(已初始化的全局变量、静态变量等),它在固件里占有空间。  

    ldr    r0, TopOfROM        ;根据链接文件sct, TopOfROM == BaseOfRW

    ldr    r1, BaseOfROM       ; 

    sub    r0, r0, r1          ;pFrom = r0 = (TopOfROM - BaseOfROM)

    ldr    r2, BaseOfRW        ;pTo = BaseOfRW  ,pEnd = BaseOfZero

    ldr    r3, BaseOfZero    

0

    cmp    r2, r3              ;if(r2    ldrcc    r1, [r0], #4      ;    r1 = [r0] ;  r0+=4;

    strcc    r1, [r2], #4      ;    [r2] = r1 ;  r2+=4;

                               ;}

    bcc    %B0                    


                   

InitRamZero                   ;初始化Bss段,之后立即进入CEntry

    mov r0, #0  

    ldr    r2,  BaseOfZero

    ldr    r3,  EndOfBSS

1    

    cmp  r2, r3               ;清零bss段,bss段(未初始化的全局变量、静态变量)在bin文件中不占空间,只有占位符,因此需要在系统初始化时,手动初始化(一般memset为0);

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。