CE STEPLDR

时间:2023-03-09 07:08:47
CE STEPLDR

作用:初始化CPU、内存、Flash,复制EBoot到内存并跳入EBoot中运行。

原理:S3C2416有 8-KB 的steppingstone(暂时翻译为垫脚石),在Nand启动模式下可把Nand的前8K内容在CPU上电后自动复制到物理地址(0x40000000)上面并运行。

CE STEPLDR

程序入口:startup.s

常见汇编指令下载

     OPT 

     INCLUDE kxarm.h
     INCLUDE s3c2416.inc

     OPT
     OPT 

 ; Pre-defined constants.

 USERMODE      EQU    0x10
 FIQMODE        EQU    0x11
 IRQMODE        EQU    0x12
 SVCMODE        EQU    0x13
 ABORTMODE     EQU    0x17
 UNDEFMODE     EQU    0x1b
 MODEMASK      EQU    0x1f
 NOINT         EQU    0xc0

 ; Amount of memory (in bytes) allocated for stacks

 Len_FIQ_Stack    EQU
 Len_IRQ_Stack    EQU
 Len_ABT_Stack    EQU
 Len_UND_Stack    EQU
 Len_SVC_Stack    EQU    

 ; Offsets will be loaded as immediate values.
 ; Offsets must be 8 byte aligned.

 Offset_FIQ_Stack    EQU
 Offset_IRQ_Stack    EQU    Offset_FIQ_Stack + Len_FIQ_Stack
 Offset_ABT_Stack    EQU    Offset_IRQ_Stack + Len_IRQ_Stack
 Offset_UND_Stack    EQU    Offset_ABT_Stack + Len_ABT_Stack
 Offset_SVC_Stack    EQU    Offset_UND_Stack + Len_UND_Stack

 ; Stack locations.

 FIQStack        EQU    (top_of_stacks - 0x0)              ; 0x33ffff00 ~
 IRQStack        EQU    (FIQStack   - Offset_FIQ_Stack)    ; 0x33fffe00 ~
 AbortStack      EQU    (IRQStack   - Offset_IRQ_Stack)    ; 0x33fffd00 ~
 UndefStack      EQU    (AbortStack - Offset_ABT_Stack)    ; 0x33fffc00 ~
 SVCStack        EQU    (UndefStack - Offset_UND_Stack)    ; 0x33fffb00 ~
 UserStack       EQU    (SVCStack   - Offset_SVC_Stack)    ; 0x33fff700 ~

 ;------------------------------------------------------------------------------
 ; Sleep state constants
 ;
 ; Location of sleep data

 ; BUGBUG - this needs to be declared as a local var.

 SLEEPDATA_BASE_PHYSICAL        EQU    0x30028000
 ; WORD_SIZE                    EQU    0x4
 ; Sleep State memory locations

 SleepState_Data_Start    EQU    ()
 SleepState_WakeAddr      EQU    (SleepState_Data_Start    + )
 SleepState_MMUCTL        EQU    (SleepState_WakeAddr      + WORD_SIZE)
 SleepState_MMUTTB        EQU    (SleepState_MMUCTL        + WORD_SIZE)
 SleepState_MMUDOMAIN     EQU    (SleepState_MMUTTB        + WORD_SIZE)
 SleepState_SVC_SP        EQU    (SleepState_MMUDOMAIN     + WORD_SIZE)
 SleepState_SVC_SPSR      EQU    (SleepState_SVC_SP        + WORD_SIZE)
 SleepState_FIQ_SPSR      EQU    (SleepState_SVC_SPSR      + WORD_SIZE)
 SleepState_FIQ_R8        EQU    (SleepState_FIQ_SPSR      + WORD_SIZE)
 SleepState_FIQ_R9        EQU    (SleepState_FIQ_R8        + WORD_SIZE)
 SleepState_FIQ_R10       EQU    (SleepState_FIQ_R9        + WORD_SIZE)
 SleepState_FIQ_R11       EQU    (SleepState_FIQ_R10       + WORD_SIZE)
 SleepState_FIQ_R12       EQU    (SleepState_FIQ_R11       + WORD_SIZE)
 SleepState_FIQ_SP        EQU    (SleepState_FIQ_R12       + WORD_SIZE)
 SleepState_FIQ_LR        EQU    (SleepState_FIQ_SP        + WORD_SIZE)
 SleepState_ABT_SPSR      EQU    (SleepState_FIQ_LR        + WORD_SIZE)
 SleepState_ABT_SP        EQU    (SleepState_ABT_SPSR      + WORD_SIZE)
 SleepState_ABT_LR        EQU    (SleepState_ABT_SP        + WORD_SIZE)
 SleepState_IRQ_SPSR      EQU    (SleepState_ABT_LR        + WORD_SIZE)
 SleepState_IRQ_SP        EQU    (SleepState_IRQ_SPSR      + WORD_SIZE)
 SleepState_IRQ_LR        EQU    (SleepState_IRQ_SP        + WORD_SIZE)
 SleepState_UND_SPSR      EQU    (SleepState_IRQ_LR        + WORD_SIZE)
 SleepState_UND_SP        EQU    (SleepState_UND_SPSR      + WORD_SIZE)
 SleepState_UND_LR        EQU    (SleepState_UND_SP        + WORD_SIZE)
 SleepState_SYS_SP        EQU    (SleepState_UND_LR        + WORD_SIZE)
 SleepState_SYS_LR        EQU    (SleepState_SYS_SP        + WORD_SIZE)
 SleepState_Data_End      EQU    (SleepState_SYS_LR        + WORD_SIZE)
 SLEEPDATA_SIZE           EQU    (SleepState_Data_End - SleepState_Data_Start) / 

 ;---------------------------------------------------------------------------
 ;
 ; Macro to feed the LED Reg (The GPIO) with the value desired for debugging.
 ; Uses physical address
 ;
 ; GPFDAT [7:4] is assigned to LEDs.

     IMPORT main        ; C entrypoint for Steppingstone loader.

     EXPORT MMU_EnableICache
      EXPORT MMU_SetAsyncBusMode

     STARTUPTEXT

     LEAF_ENTRY StartUp

     b        ResetHandler    ;1、进入入口函数
     b        .
     b        .
     b        .
     b        .
     b        .
     b        .
     b        .

 ;----------------------------
 ; 1st NAND Bootloader Entry Point
 ;----------------------------

 ResetHandler                ;2、入口函数

     ;------------------------
     ; disable the watchdog timer.    ;2.1、关看门狗,此阶段用不上,若不关在指定时间内不喟狗CPU就会重启。

     ldr        r0, =WTCON

     str        r1, [r0]

     ;------------------------
     ; EBI configuration

     ;ldr        r0, =EBICON            ; EBI
     ;ldr        r1, =EBICON_VAL        ; Refer s3c2416.inc
     ;str        r1, [r0]

     ;-------------------------
     ; Configure GPA data High
     ldr        r0, = GPACDH
     ldr     r1, = 0x1AA8A
     str        r1, [r0]

     ;------------------------
     ; GIPO configuration for LED

     ldr        r0, =GPFCON
     ldr        r1, =0x5500
     str        r1, [r0]

     ;------------------------
     ; Interrupt configuration        ;2.2、屏蔽所有的中断,此阶段用不上,若不屏蔽程序运行过程会被中断且因没有填充中断处理函数会造成死循环。

     ldr    r0, =INTMSK1          ; mask all first-level interrupts.
     ldr    r1, =0xffffffff
     str    r1, [r0]

     ldr    r0, =INTMSK2          ; mask all first-level interrupts.
     ldr    r1, =0xffffffff
     str    r1, [r0]

     ldr    r0, =INTSUBMSK       ; mask all second-level interrupts.
     ldr    r1, =0x1fffffff
     str    r1, [r0]

     ldr   r0, = INTMOD1
     mov   r1, #0x0            ; set all interrupt as IRQ
     str   r1, [r0]

     ldr   r0, = INTMOD2
     mov   r1, #0x0            ; set all interrupt as IRQ
     str   r1, [r0]

     ;------------------------
     ; Clock configuration            ;2.3、设置时钟,初始时CPU的时钟为外部输入的12MHz频率的时钟信号,设置完分频后可在400MHz时钟下运行。

     ldr        r0, =CLKDIV0            ; Set Clock Divider
     ldr        r1, [r0]
     bic        r1, r1, #0x37            ; clear HCLKDIV, PREDIV, PCLKDIV
     bic        r1, r1, #(0xf<<)        ; clear ARMCLKDIV
     ldr        r2, =((Startup_ARMCLKdiv<<)+(Startup_PREdiv<<)+(Startup_PCLKdiv<<)+(Startup_HCLKdiv))
     orr        r1, r1, r2
     str        r1, [r0]

     ldr        r0, =LOCKCON0            ; Set lock time of MPLL. added by junon
     mov        r1, #0xe10                ; Fin = 12MHz -0x800, 16.9844MHz -0xA00
     str        r1, [r0]

     ldr        r0,=LOCKCON1            ;    Set lock time of EPLL. added by junon
     mov        r1,#0x800                ;    Fin = 12MHz - 0x800, 16.9844MHz - 0xA00
     str        r1,[r0]

     ldr        r0, =MPLLCON            ; Set MPLL
     ldr        r1,=((<<)+(Startup_Mdiv<<)+(Startup_Pdiv<<)+(Startup_Sdiv))
     str        r1, [r0]

       ldr        r0,=EPLLCON                ;    Set EPLL
     ldr        r1,=((<<)+(Startup_EMdiv<<)+(Startup_EPdiv<<)+(Startup_ESdiv))
     str        r1,[r0]

     ldr        r0, =CLKSRC                ; Select MPLL clock out for SYSCLK
     ldr        r1, [r0]
     orr        r1, r1, #0x50
     str        r1, [r0]

     ;----------------------------
     ; MMU set Asynchonous Bus Mode     ;2.4、设置MMU为异步模式

     bl        MMU_SetAsyncBusMode

        ;----------------------------
     ; Memory Controller initialize     ;2.5、初始化内存控制器

     bl        InitMEM

        ;----------------------------
     ; SMC initialize                 ;2.6、初始化CPU的SD控制器

     bl        InitSSMC

        ;----------------------------
     ; Reset Case handling                 ;2.7.1、判断复位状态,如果不是唤醒则跳到下面的标号2中运行

     ldr        r1, =RSTSTAT
     ldr        r0, [r1]
     tst        r0, #0x8
     beq        %F2                                ; if not wakeup from PowerOffmode case, Jump to normal booting seauence

        ;------------------------------        ;2.7.2、判断唤醒状态,如果不是RTC唤醒则跳到下面的标号6中运行
     ; Wakeup from PowerOff Mode case

     ldr        r1, =WKUPSTAT
     ldr        r0, [r1]
     tst        r0, #(<<)
     beq        %f6                             ; if not wakeup from PowerOffmode Skip

                                          ;2.7.3、直接跳入内存中运行
     ldr        r2, =0x200000                    ; offset into the RAM
     add        r2, r2, #0x30000000                ; add physical base
     mov        pc, r2                            ; & jump to StartUp address
     nop
     nop
     nop
     b        .

     ldr        r1, =RSTSTAT                ;2.7.4、判断唤醒状态,如果不是深度休眠唤醒则跳到下面的标号BringUpWinCE中运行
     ldr        r0, [r1]
     tst        r0, #(<<)
     beq        BringUpWinCE                    ; if not wakeup from PowerOffmode Skip

 JumpToRAM                                 ;2.7.5、直接跳入内存中运行
     ldr        r2, =0x200000                    ; offset into the RAM
     add        r2, r2, #0x30000000                ; add physical base
     mov       pc, r2                            ;  & jump to StartUp address
     nop
     nop
     nop
     b .

 BringUpWinCE                         ;2.8、执行冷启动流程
     ;--------------------
     ; Clear RAM                         ;2.8.1、清空内存

     ldr        r0, =0x30000000        ; Start address (physical 0x3000.0000).
     ldr        r9, =0x04000000        ; 64MB of RAM.

     stmia     r0!, {r1-r8}
     subs      r9, r9, #
     bne        %B20

     ;---------------------
     ; Initialize stacks.                 ;2.8.2、初始化堆栈,为进入C语言的代码作环境准备

     mrs        r0, cpsr
     bic        r0, r0, #MODEMASK

 ;    orr        r1, r0, #UNDEFMODE | NOINT
 ;    msr        cpsr_cxsf, r1            ; UndefMode
 ;    ldr        sp, =UndefStack            ; UndefStack=0x33FF_5C00

 ;    orr        r1, r0, #ABORTMODE | NOINT
 ;    msr        cpsr_cxsf, r1            ; AbortMode
 ;    ldr        sp, =AbortStack            ; AbortStack=0x33FF_6000

     orr        r1, r0, #IRQMODE | NOINT
     msr        cpsr_cxsf, r1            ; IRQMode
     ldr        sp, =IRQStack            ; IRQStack=0x33FF_7000

 ;    orr        r1, r0, #FIQMODE | NOINT
 ;    msr        cpsr_cxsf, r1            ; FIQMode
 ;    ldr        sp, =FIQStack            ; FIQStack=0x33FF_8000

     bic        r0, r0, #MODEMASK | NOINT
     orr        r1, r0, #SVCMODE
     msr        cpsr_cxsf, r1            ; SVCMode
     ldr        sp, =SVCStack            ; SVCStack=0x33FF_5800

     ;----------------------
     ; Jump to main C routine.             ;2.8.3、跳入C语言代码编写的main函数里面继续执行

     bl        main

     b         .

     ENTRY_END

 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

 ;------------------------------
 ; Sub Routines for Boot Loader
 ;-------------------------------

     LTORG

     ;------------------------
     ; Memory Controller initialize

 IF :DEF: mSDR         ;2.5、如果定义了mSDR则内存初始化函数为下面所示

 InitMEM

         ;Set GPK port when using x32 bus width.
             ldr        r0,=GPKCON
             ldr        r1,=0xaaaaaaaa    ; set Sdata[31:16]
             str        r1, [r0]

             ;Set SDR Memory parameter control registers
             ldr        r0,=BANKCFG
             ldr        r1,=BANKCFGVAL     ; set Sdata[31:16]
             str        r1, [r0]

             ldr        r0,=BANKCON1
             ldr        r1,=BANKCON1VAL      ; set Sdata[31:16]
             str        r1, [r0]

             ldr        r0,=BANKCON2
             ldr        r1,=BANKCON2VAL       ; set Sdata[31:16]
             str        r1, [r0]

             ldr        r0,=BANKCON3
             ldr        r1,=BANKCON3VAL       ; set Sdata[31:16]
             str        r1, [r0]

             ldr        r2,=BANKCON1
             ldr        r1,[r2]
             bic        r1,r1,#(0x3<<)
             orr        r1,r1,#(0x1<<)       ;4nd:Issue a PALL command
             str        r1,[r2]

             ldr        r4,=REFRESH           ;5fh : refresh cycle every 255-clock cycles
             ldr        r0,=0xff
             str        r0,[r4]

             mov    r0, #0x100                 ;6th : wait 2 auto - clk
             subs    r0, r0,#;
             bne    %B02

             bic        r1,r1,#(0x3<<)        ;7th:Issue a MRS command
             orr        r1,r1,#(0x2<<)
             str        r1,[r2]

             ldr        r4,=REFRESH            ;8fh : refresh  normal
             ldr        r0,=REFCYC
             str        r0,[r4]

             orr        r1,r1,#(0x3<<)         ;9th: Issue a EMRS command
             str        r1,[r2]

             bic        r1,r1,#(0x3<<)         ;10th:Issue a Normal mode
             str        r1,[r2]

             mov        pc, lr

 ENDIF

 IF :DEF: mDDR         ;2.5、如果定义了mDDR则内存初始化函数为下面所示
 InitMEM
         ;Set GPK port when using x32 bus width.
             ldr        r0,=GPKCON
             ldr        r1,=0xaaaaaaaa    ; set Sdata[31:16]
             str        r1, [r0]

             ;Set DDR Memory parameter control registers
             ldr        r0,=BANKCFG
             ldr        r1,=BANKCFGVAL     ; set Sdata[31:16]
             str        r1, [r0]

             ldr        r0,=BANKCON1
             ldr        r1,=BANKCON1VAL      ; set Sdata[31:16]
             str        r1, [r0]

             ldr        r0,=BANKCON2
             ldr        r1,=BANKCON2VAL       ; set Sdata[31:16]
             str        r1, [r0]

             ldr        r0,=BANKCON3
             ldr        r1,=BANKCON3VAL       ; set Sdata[31:16]
             str        r1, [r0]

             ldr        r2,=BANKCON1
             ldr        r1,[r2]
             bic        r1,r1,#(0x3<<)
             orr        r1,r1,#(0x1<<)       ; 4nd:Issue a PALL command
             str        r1,[r2]

             ldr        r4,=REFRESH            ;    5fh : refresh cycle every 255-clock cycles
             ldr        r0,=0xff
             str        r0,[r4]

             mov    r0, #0x100                    ;    6th : wait 2 auto - clk
             subs    r0, r0,#;
             bne    %B02

             bic        r1,r1,#(0x3<<)            ;    7th    :    Issue a MRS command
             orr        r1,r1,#(0x2<<)
             str        r1,[r2]

             ldr        r4,=REFRESH            ;    8fh : refresh  normal
             ldr        r0,=REFCYC
             str        r0,[r4]

             orr        r1,r1,#(0x3<<)            ;    9th    :    Issue a EMRS command
             str        r1,[r2]

             bic        r1,r1,#(0x3<<)            ;    10th    :    Issue a Normal mode
             str        r1,[r2]

             mov        pc, lr

 ENDIF

 IF :DEF: DDR2             ;2.5、如果定义了DDR2则内存初始化函数为下面所示,此定义在SRC\Inc\s3c2416.inc里面有定义 GBLL DDR2
 InitMEM

         ;Set GPK port when using x32 bus width.
             ldr        r0,=GPKCON
             ldr        r1,=0xaaaaaaaa    ; set Sdata[31:16]
             str        r1, [r0]

             ;Set DDR2 Memory parameter control registers
             ldr        r0,=BANKCFG
             ldr        r1,=BANKCFGVAL     ; set Sdata[31:16]
             str        r1, [r0]

             ldr        r0,=BANKCON1
             ldr        r1,=BANKCON1VAL      ; set Sdata[31:16]
             str        r1, [r0]

             ldr        r0,=BANKCON2
             ldr        r1,=BANKCON2VAL       ; set Sdata[31:16]
             str        r1, [r0]

             ldr        r2,=BANKCON1            ;    4nd    :    Issue a PALL command
             ldr        r1,[r2]
             bic        r1,r1,#(0x3<<)
             orr        r1,r1,#(0x1<<)
             str        r1,[r2]

             ldr        r2,=BANKCON3            ;    5th    :    Issue a EMRS2 command
             ldr        r3,=0xffff0000
             ldr        r1,[r2]
             bic        r1,r1,r3
             orr        r1,r1,#(BA_EMRS2<<)
             str        r1,[r2]

             ldr        r2,=BANKCON1
             ldr        r1,[r2]
             bic        r1,r1,#(0x3<<)
             orr        r1,r1,#(0x3<<)
             str        r1,[r2]

             ldr        r2,=BANKCON3            ;    6th    :    Issue a EMRS3 command
             ldr        r3,=0xffff0000
             ldr        r1,[r2]
             bic        r1,r1,r3
             orr        r1,r1,#(BA_EMRS3<<)
             str        r1,[r2]

             ldr        r2,=BANKCON1
             ldr        r1,[r2]
             bic        r1,r1,#(0x3<<)
             orr        r1,r1,#(0x3<<)
             str        r1,[r2]

             ldr        r2,=BANKCON3            ;    7th    :    Issue a EMRS1 command
             ldr        r3,=0xffff0000
             ldr        r4,=((BA_EMRS1<<)+(RDQS_DIS<<)+(nDQS_DIS<<)+(OCD_MODE_EXIT<<)+(DLL_EN<<))
                                   ; (0x1<<30)|(0x0<<27)|(0x1<<26)|(0x0<<23)|(0x0<<16)
             ldr        r1,[r2]
             bic        r1,r1,r3
             orr        r1,r1,r4
             str        r1,[r2]

             ldr        r2,=BANKCON1
             ldr        r1,[r2]
             bic        r1,r1,#(0x3<<)
             orr        r1,r1,#(0x3<<)
             str        r1,[r2]

             ldr        r2,=BANKCON3            ;    8th    :    Issue a MRS command
             ldr        r3,=0xffff
             ldr        r1,[r2]
             bic        r1,r1,r3
             orr        r1,r1,#((BA_MRS<<)+(DLL_RESET_HIGH<<)+(TM<<)+(CL_MRS<<))
             str        r1,[r2]

             ldr        r2,=BANKCON1
             ldr        r1,[r2]
             bic        r1,r1,#(0x3<<)
             orr        r1,r1,#(0x2<<)
             str        r1,[r2]

             ldr        r2,=BANKCON1            ;    9nd    :    Issue a PALL command
             ldr        r1,[r2]
             bic        r1,r1,#(0x3<<)
             orr        r1,r1,#(0x1<<)
             str        r1,[r2]

             ldr        r4,=REFRESH                ;    10th : wait 2 auto - clk
             ldr        r0,=0x20
             str        r0,[r4]

             ldr        r2,=BANKCON3            ;    11th    :    Issue a MRS command
             ldr        r3,=0xffff
             ldr        r1,[r2]
             bic        r1,r1,r3
             orr        r1,r1,#((BA_MRS<<)+(DLL_RESET_LOW<<)+(TM<<)+(CL_MRS<<))
             str        r1,[r2]

             ldr        r2,=BANKCON1
             ldr        r1,[r2]
             bic        r1,r1,#(0x3<<)
             orr        r1,r1,#(0x2<<)
             str        r1,[r2]

             mov     r0, #0x100                    ; Wait 200 clock
            subs    r0, r0,#;
             bne     %B2

             ldr        r2,=BANKCON3             ; 12th : Issue a EMRS1 command For OCD Mode Set to default
             ldr        r3,=0xffff0000
             ldr        r4,=((BA_EMRS1<<)+(RDQS_DIS<<)+(nDQS_DIS<<)+(OCD_MODE_DEFAULT<<)+(DLL_EN<<))
             ldr        r1,[r2]
             bic        r1,r1,r3
             orr        r1,r1,r4
             str        r1,[r2]

             ldr        r2,=BANKCON1
             ldr        r1,[r2]
             bic        r1,r1,#(0x3<<)
             orr        r1,r1,#(0x3<<)
             str        r1,[r2]

             ldr        r2,=BANKCON3
             ldr        r3,=0xffff0000
             ldr        r4,=((BA_EMRS1<<)+(RDQS_DIS<<)+(nDQS_DIS<<)+(OCD_MODE_EXIT<<)+(DLL_EN<<))
             ldr        r1,[r2]
             bic        r1,r1,r3
             orr        r1,r1,r4
             str        r1,[r2]

             ldr        r2,=BANKCON1
             ldr        r1,[r2]
             bic        r1,r1,#(0x3<<)
             orr        r1,r1,#(0x3<<)
             str        r1,[r2]

             ldr        r4,=REFRESH            ;    13fh : refresh  normal
             ldr        r0,=REFCYC
             str        r0,[r4]

             ldr        r2,=BANKCON1          ;    14th : Issue a Normal mode
             ldr        r1,[r2]
             bic        r1,r1,#(0x3<<)
             str        r1,[r2]
 ENDIF

     ;-----------------------------
     ; Static Memory Controller Initialize     ;2.6、初始化CPU的SD控制器

 InitSSMC

     ; Set SMC Memory parameter control registers : AMD Flash
         ldr        r0, =SMBIDCYR0
         ldr        r1, =IDCY0
         str        r1, [r0]

         ldr        r0, =SMBWSTRDR0
         ldr        r1, =WSTRD0
         str        r1, [r0]

         ldr        r0, =SMBWSTWRR0
         ldr        r1, =WSTWR0
         str        r1, [r0]

         ldr        r0, =SMBWSTOENR0
         ldr        r1, =WSTOEN0
         str        r1, [r0]

         ldr        r0, =SMBWSTWENR0
         ldr        r1, =WSTWEN0
         str        r1, [r0]

         ldr        r0, =SMBCR0
         ldr        r1, =(SMBCR0_2+SMBCR0_1+SMBCR0_0)
         str        r1, [r0]

         ldr        r0,=SMBWSTBRDR0
         ldr        r1,=WSTBRD0
         str        r1,[r0]

         ldr        r0, =SMBWSTBRDR0
         ldr        r1, =WSTBRD0
         str        r1, [r0]

         ldr        r0, =SSMCCR
         ldr        r1, =((MemClkRatio<<)+(SMClockEn<<))
         str        r1, [r0]

         ldr        r0, =SMBWSTRDR5
         ldr        r1, =0xe
         str        r1, [r0]

         mov        pc, lr

         LTORG

         ;------------------------------------
         ; MMU Cache/TLB/etc on/off functions

         R1_I     EQU    (<<)
         R1_C    EQU    (<<)
         R1_A    EQU    (<<)
         R1_M    EQU    ()
         ;R1_iA    EQU    (1<<31)
         ;R1_nF    EQU    (1<<30)

     ;------------------------------------
     ; void MMU_EnableICache(void);
     LEAF_ENTRY    MMU_EnableICache

         mrc        p15, , r0, c1, c0,
         orr        r0, r0, #R1_I
         mcr        p15, , r0, c1, c0,
         mov        pc, lr

         ; void MMU_SetAsyncBusMode(void);
         ; FCLK:HCLK= 1:2

     ;------------------------------------
     LEAF_ENTRY    MMU_SetAsyncBusMode

         mrc        p15, , r0, c1, c0,
         orr        r0, r0, #R1_nF:OR:R1_iA
         mcr        p15, , r0, c1, c0,
         mov       pc, lr

     ; NAND code...         ;3.0、Nand操作相关
     ;
     A410_BASE_ADDR    EQU    0x2000000

     ;;;    MACRO
     ;;;    LDR4STR1 $src,$tmp1,$tmp2
     ;;;    ldrb    $tmp1,[$src]
     ;;;    ldrb    $tmp2,[$src]
     ;;;    orr        $tmp1,$tmp1,$tmp2,LSL #8
     ;;;    ldrb    $tmp2,[$src]
     ;;;    orr        $tmp1,$tmp1,$tmp2,LSL #16
     ;;;    ldrb    $tmp2,[$src]
     ;;;    orr        $tmp1,$tmp1,$tmp2,LSL #24
     ;;;    MEND

     EXPORT    __RdPage512
 __RdPage512
     ;input:a1(r0)=pPage
     stmfd    sp!,{r1-r11}

     ldr        r1,=0x4e000010      ;NFDATA
     mov        r2,#0x200

     ldr     r4,[r1]
     ldr     r5,[r1]
     ldr     r6,[r1]
     ldr     r7,[r1]
     ldr     r8,[r1]
     ldr     r9,[r1]
     ldr     r10,[r1]
     ldr     r11,[r1]
     stmia    r0!,{r4-r11}
     subs    r2,r2,#
     bne        %B10

     ldmfd    sp!,{r1-r11}
     mov        pc,lr

 END

程序跳转:main.c

 #include <windows.h>
 #include <pehdr.h>
 #include <romldr.h>
 #include "option.h"
 #include "s2416ADDR.h"

 // Constants.
 //
 #define MESSAGE_ON        FALSE  //TRUE
 #define LED_ON            0xa
 #define LED_OFF            0x0

 #define NAND_SB_PAGE_SIZE_BYTES        (0x200)        // 1 Page = 0x200 (512 Bytes)
 #define NAND_SB_BLOCK_SIZE_BYTES    (0x4000)    // 1 Block = 16 KB
 #define NAND_SB_PAGES_PER_BLOCK        (NAND_SB_BLOCK_SIZE_BYTES / NAND_SB_PAGE_SIZE_BYTES)    // 32-pages

 #define NAND_LB_PAGE_SIZE_BYTES        (0x800)        // 1 Page = 0x800 (2048 Bytes)
 #define NAND_LB_BLOCK_SIZE_BYTES    (0x20000)    // 1 Block = 128 KB
 #define NAND_LB_PAGES_PER_BLOCK        (NAND_LB_BLOCK_SIZE_BYTES / NAND_LB_PAGE_SIZE_BYTES)    // 64-pages

 // NOTE: we assume that this Steppingstone loader occupies *part* the first (good) NAND flash block.  More
 // specifically, the loader takes up 4096 bytes (or 8 NAND pages) of the first block.  We'll start our image
 // copy on the very next page.
 #define NAND_COPY_PAGE_OFFSET       (2*((bLARGEBLOCK==TRUE)?NAND_LB_PAGES_PER_BLOCK:NAND_SB_PAGES_PER_BLOCK))

 #define LOAD_ADDRESS_PHYSICAL       0x30038000
 #define LOAD_SIZE_BYTES                 0x00040000
 #define LOAD_SIZE_PAGES                 (LOAD_SIZE_BYTES / ((bLARGEBLOCK==TRUE)?NAND_LB_PAGE_SIZE_BYTES:NAND_SB_PAGE_SIZE_BYTES))

 // Globals variables.
 //
 ROMHDR * ;

 // Function prototypes.
 //
 void MMU_EnableICache(void);
 void Led_Display(int);
 void Port_Init(void);
 void NF_Init(void);
 DWORD ReadFlashID(void);
 int NF_ReadPage(UINT32 block, UINT32 page, volatile BYTE *buffer);

 extern BOOL bLARGEBLOCK;
 //
 typedef void (*PFN_IMAGE_LAUNCH)();

 /*
     @func   BOOLEAN | SetupCopySection | Copies the IPL image's copy section data (initialized globals) to the correct fix-up location.  Once completed, the IPLs initialized globals are valid.
     @rdesc  TRUE == Success and FALSE == Failure.
     @comm
     @xref
 */
 static BOOLEAN SetupCopySection(ROMHDR *const pTOC)
 {
     // This code doesn't make use of global variables so there are no copy sections.  To reduce code size, this is a stub function...
     //
     return(TRUE);
 }

 /*
     @func   void | main | C entrypoint function for the Steppingstone loader.
     @rdesc  None.
     @comm
     @xref
 */
 void main(void)
 {
     register nBlock;
     register nPage;
     register nBadBlocks;
     volatile BYTE *pCopyPtr;

 #if MESSAGE_ON==1
     volatile DWORD boot_code;
 #endif

     // Set up copy section (initialized globals).
     //
     // NOTE: after this call, globals become valid.
     //
     //SetupCopySection(pTOC);

     // Enable the ICache.
     //
     MMU_EnableICache();

     // Set up all GPIO ports.
     //
     // TBD - DonGo
     Port_Init();        //1、初始化IO口

     Uart_Init();        //2、初始化打印信息的串口

     Uart_SendString("\rMicrosoft Windows CE 5.0 Stepldr for DMA2416\r\n");

     // Initialize the NAND flash interface.
     //
     //Uart_SendString("NF_Init...");
     NF_Init();         //3、初始化Flash

     // Turn the LEDs off.
     Led_Display(LED_OFF);

     //---------------------------------
     // Copy image from NAND flash to RAM.//4、准备复制Flash文件到内存中运行
     //
     pCopyPtr = (BYTE *)LOAD_ADDRESS_PHYSICAL;

 #if MESSAGE_ON==1
     Uart_SendString("Image copy NAND block from ");
     Uart_SendDWORD(NAND_COPY_PAGE_OFFSET/NAND_PAGES_PER_BLOCK,);
     Uart_SendString(" to ");
     Uart_SendDWORD((LOAD_SIZE_PAGES + NAND_COPY_PAGE_OFFSET)/NAND_PAGES_PER_BLOCK,);
     Uart_SendString("Download memory address at ");
     Uart_SendDWORD(LOAD_ADDRESS_PHYSICAL,);
 #endif

     if (ReadFlashID() != TRUE)
     {
         //Uart_SendString("NAND Flash is not supported!!\r\n");
         );
     }

     nBadBlocks = ;
     for (nPage = NAND_COPY_PAGE_OFFSET ; nPage < (LOAD_SIZE_PAGES + NAND_COPY_PAGE_OFFSET) ; nPage++)  //5、执行拷贝操作
     {
         nBlock = ((nPage / ((bLARGEBLOCK==TRUE)?NAND_LB_PAGES_PER_BLOCK:NAND_SB_PAGES_PER_BLOCK)) + nBadBlocks);
         //Uart_SendDWORD(nPage,1);
         //Uart_SendString(" ");
         if (!NF_ReadPage(nBlock, (nPage % ((bLARGEBLOCK==TRUE)?NAND_LB_PAGES_PER_BLOCK:NAND_SB_PAGES_PER_BLOCK)), pCopyPtr))//6、读取Flash写入内存
         {
             //Uart_SendString(hex2char(nBlock));
             )
             {
                 //Led_Display(0x9);    // real ECC Error.
                 //Uart_SendString("ECC Error.\r\n");
                 // Spin forever...
                 )
                 {
                 }
             }

             // ECC error on a block boundary is (likely) a bad block - retry the page 0 read on the next block.
             nBadBlocks++;
             nPage--;
             continue;
         }
         //Uart_SendDWORD(*pCopyPtr,0);
         //Uart_SendString("\n");

         pCopyPtr += ((bLARGEBLOCK==TRUE)?NAND_LB_PAGE_SIZE_BYTES:NAND_SB_PAGE_SIZE_BYTES);
     }

     // Turn the LEDs on.
     //
     //Led_Display(0x5);

 #if MESSAGE_ON==1
     boot_code = *(volatile DWORD *)LOAD_ADDRESS_PHYSICAL;
     Uart_SendString("Bboot code : ");
     Uart_SendDWORD(boot_code,);
     //-----------------------------
     // Jump to the image...
     //
     Uart_SendString("Now Jump to ");
     Uart_SendDWORD(LOAD_ADDRESS_PHYSICAL,);
 #endif

     ((PFN_IMAGE_LAUNCH)(LOAD_ADDRESS_PHYSICAL))();    //7、跳入内存指定地址运行

 }

程序编译配置文件:stepldr.bib

MEMORY
;   Name      Start     Size      Type
;   -------   --------  --------  ----
    STEPLDR        RAMIMAGE ;此处地址是CPU内置的RAM的地址文章最上面的图所示,大小为8K,即2416所支持的最大的自动复制大小
    STACK    33ff5800     RESERVED ;程序运行时的栈指针
    RAM      33ff0000     RAM    ;程序运行内存

CONFIG
    COMPRESSION=ON
    PROFILE=OFF
    KERNELFIXUPS=ON

    ROMSTART=
    ROMWIDTH=
    ROMSIZE=00001000              ;实际大小只用了4K

MODULES
;   Name        Path                                                               Memory Type
;   ----------  --------------------------------------------------------------     -----------
    nk.exe      $(_TARGETPLATROOT)\target\$(_TGTCPU)\$(WINCEDEBUG)\stepldr.exe     STEPLDR