板牙  
失败是什么?没有什么,只是更走近成功一步;而成功是走过了所有通向失败的路...只要你心够决!
;=========================================
; NAME: 2440INIT.S
; DESC: C start up codes
;       Configure memory, ISR ,stacks
;    Initialize C-variables
; HISTORY:
; 2002.02.25:kwtark: ver 0.0
; 2002.03.20:purnnamu: Add some functions for testing STOP,Sleep mode
; 2003.03.14:DonGo: Modified for 2440.
;=========================================
;//GET类似于C语言的include,option.inc文件内定义了一些全局变量,memcfg.inc文件内定义了关于内存bank的符号和数字常量,2440addr.inc文件内定义了用于汇编的s3c2440寄存器变量和地址

    GET option.inc
    GET memcfg.inc
    GET 2440addr.inc

BIT_SELFREFRESH EQU    (1<<22)      ;//#define BIT_SELFREFRESH (1<<22)

;//下面是对arm处理器模式寄存器对应的常数进行赋值,arm处理器有一个CPSR寄存器,它的后五位决定了处理器处于哪个模式下。
;//可以看出常数的定义都不会超过后5位的。

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

;//定义了7种处理器模式下的栈的起始地址,其中用户模式和系统模式共有一个栈空间
UserStack    EQU    (_STACK_BASEADDRESS-0x3800)    ;0x33ff4800 ~
SVCStack    EQU    (_STACK_BASEADDRESS-0x2800)    ;0x33ff5800 ~
UndefStack    EQU    (_STACK_BASEADDRESS-0x2400)    ;0x33ff5c00 ~
AbortStack    EQU    (_STACK_BASEADDRESS-0x2000)    ;0x33ff6000 ~
IRQStack    EQU    (_STACK_BASEADDRESS-0x1000)    ;0x33ff7000 ~
FIQStack    EQU    (_STACK_BASEADDRESS-0x0)    ;0x33ff8000 ~




;//这一段是统一arm的工作状态和对应的软件编译方式(16位编译环境使用tasm.exe编译)。
;//arm处理器的工作状态分为两种:32位,arm执行字对齐的arm指令集;16位,arm执行半字对齐的Thumb指令集。
;//不同的工作状态,编译方式也不一样。所以下面的程序就是判断arm的工作方式来确定它的编译方式。

;//difine grobal parameters 定义THUMBCODE这个变量   GBLL声明一个全局逻辑变量并初始化为{FALSE}
;//初始化为{FALSE}    GBLA(算术变量),GBLL(逻辑变量),GBLS(字符串变量)
;Check if tasm.exe(armasm -16 ...@ADS 1.0) is used.
    GBLL    THUMBCODE
    [ {CONFIG} = 16        ;//CONFIG为汇编器的内置变量  对于CONFIG是在ADS编译中定义的内部变量
THUMBCODE SETL  {TRUE}];//如果ARM是在16位的工作状态的话,就使全局变量THUMBCODE设置为ture
        CODE32
         |
THUMBCODE SETL  {FALSE}
    ]

         MACRO
    MOV_PC_LR
         [ THUMBCODE
        bx lr
         |
        mov    pc,lr
         ]
    MEND

         MACRO
    MOVEQ_PC_LR
         [ THUMBCODE
        bxeq lr
         |
        moveq pc,lr
         ]
    MEND

         MACRO
$HandlerLabel HANDLER $HandleLabel

$HandlerLabel   //
    sub    sp,sp,#4    ;decrement sp(to store jump address)//预留一个值来保存 服务子程序的地址
    stmfd    sp!,{r0}    ;//保存R0,因为下面使用了   PUSH the work register to stack(lr does not push because it return to original address)
    ldr     r0,=$HandleLabel;//将$HandleLabel这个地址装载到R0  ;load the address of HandleXXX to r0
    ldr     r0,[r0]     ;//取出$HandleLabel地址存储的数据,该数据就是服务子程序的地址  load the contents(service routine start address) of HandleXXX
    str     r0,[sp,#4] ;//str不是入栈,只是把r0值放到 sp+4 这个地址上面      ;store the contents(ISR) of HandleXXX to stack
    ldmfd   sp!,{r0,pc} //都出栈,pc指向服务子程序的地址    ;POP the work register and pc(jump to ISR)
    MEND

    IMPORT  |Image$$RO$$Base|    ; Base of ROM code
    IMPORT  |Image$$RO$$Limit|  ; End of ROM code (=start of ROM data)
    IMPORT  |Image$$RW$$Base|   ; Base of RAM to initialise
    IMPORT  |Image$$ZI$$Base|   ; Base and limit of area
    IMPORT  |Image$$ZI$$Limit|  ; to zero initialise

    IMPORT    MMU_SetAsyncBusMode
    IMPORT    MMU_SetFastBusMode    ;

    IMPORT  Main    ; The main entry of mon program//引入主函数地址
    IMPORT  CopyProgramFromNand                ;//引入把代码从nandflash复制到内存

    AREA    Init,CODE,READONLY  ;//这表明下面的是一个名为Init的代码段

    ENTRY   ;//定义程序的入口(调试用)  
    
    EXPORT    __ENTRY ;//导出符号_ENTRY,但在那用到就还没查明
__ENTRY
ResetEntry
    ;1)The code, which converts to Big-endian, should be in little endian code.
    ;2)The following little endian code will be compiled in Big-Endian mode.
    ;  The code byte order should be changed as the memory bus width.
    ;3)The pseudo instruction,DCD can not be used here because the linker generates error.
    ASSERT    :DEF:ENDIAN_CHANGE ;//判断模式改变是否定义过(ASSERT是伪指令,:DEF:lable判断lable是否定义过了)
    [ ENDIAN_CHANGE;//下面是大小端的一个判断,在Option.inc里已经设为FALSE
        ASSERT  :DEF:ENTRY_BUS_WIDTH
        [ ENTRY_BUS_WIDTH=32
        b    ChangeBigEndian        ;DCD 0xea000007
        ]

        [ ENTRY_BUS_WIDTH=16
        andeq    r14,r7,r0,lsl #20   ;DCD 0x0007ea00
        ]

        [ ENTRY_BUS_WIDTH=8
        streq    r0,[r0,-r10,ror #1] ;DCD 0x070000ea
        ]
    |
        b    ResetHandler;//中断向量表 --设成FALSE的话就来到这了,转跳到复位程序入口
    ]
    b    HandlerUndef    ;handler for Undefined mode   //转跳到Undefined mode程序入口
    b    HandlerSWI    ;handler for SWI interrupt        //转跳到SWI 中断程序入口
    b    HandlerPabort    ;handler for PAbort            //转跳到PAbort(指令异常)程序入口
    b    HandlerDabort    ;handler for DAbort            //转跳到DAbort(数据异常)程序入口
    b    .        ;reserved                            //保留
    b    HandlerIRQ    ;handler for IRQ interrupt        //转跳到IRQ 中断程序入口
    b    HandlerFIQ    ;handler for FIQ interrupt        //转跳到FIQ 中断程序入口

;@0x20
    b    EnterPWDN    ; Must be @0x20.
    

;//==================================================================================
;//下面是改变大小端的程序,这里采用直接定义机器码的方式,至说为什么这么做就得问三星了
;//反正我们程序里这段代码也不会去执行,不用去管它
;//==================================================================================
ChangeBigEndian
;@0x24
    [ ENTRY_BUS_WIDTH=32
        DCD    0xee110f10    ;0xee110f10 => mrc p15,0,r0,c1,c0,0
        DCD    0xe3800080    ;0xe3800080 => orr r0,r0,#0x80;  //Big-endian
        DCD    0xee010f10    ;0xee010f10 => mcr p15,0,r0,c1,c0,0
    ]
    [ ENTRY_BUS_WIDTH=16
        DCD 0x0f10ee11
        DCD 0x0080e380
        DCD 0x0f10ee01
    ]
    [ ENTRY_BUS_WIDTH=8
        DCD 0x100f11ee
        DCD 0x800080e3
        DCD 0x100f01ee
    ]
    DCD 0xffffffff  ;swinv 0xffffff is similar with NOP and run well in both endian mode.
    DCD 0xffffffff
    DCD 0xffffffff
    DCD 0xffffffff
    DCD 0xffffffff
    b ResetHandler
    
HandlerFIQ      HANDLER HandleFIQ
HandlerIRQ      HANDLER HandleIRQ
HandlerUndef    HANDLER HandleUndef
HandlerSWI      HANDLER HandleSWI
HandlerDabort   HANDLER HandleDabort
HandlerPabort   HANDLER HandlePabort

;===================================================================================
;//这一段程序是用来进行第二次查表的过程了.
;//如果说第一次查表是由硬件来完成的,那这一次查表就是由软件来实现的了.
;//为什么要查两次表??
;//没有办法,ARM把所有的中断都归纳成一个IRQ中断异常和一个FIRQ中断异常
;//第一次查表主要是查出是什么异常,可我们总要知道是这个中断异常中的什么中断呀!
;//没办法了,再查一次表呗!
;===================================================================================
IsrIRQ
    sub    sp,sp,#4       ;reserved for PC  //预留一个值来保存 服务子程序的地址
    stmfd    sp!,{r8-r9}  ; //将r8 r9入栈

    ldr    r9,=INTOFFSET  ;//偏移量
    ldr    r9,[r9]
    ldr    r8,=HandleEINT0
    add    r8,r8,r9,lsl #2  ;//将INTOFFSET和HandleEINT0结合起来
    ldr    r8,[r8]            ;//装入中断服务程序的入口
    str    r8,[sp,#8]        ;//str不是入栈,只是把r0值放到 sp+8 这个地址上面
    ldmfd    sp!,{r8-r9,pc}   ;//一个个出栈


    LTORG     ;//声明文字池,因为我们用了ldr伪指令

;=======
; ENTRYY//(好了,我们的CPU要在这复位了.)
;=======
ResetHandler
    ldr    r0,=WTCON       ;watch dog disable  //关开门狗
    ldr    r1,=0x0
    str    r1,[r0]

    ldr    r0,=INTMSK
    ldr    r1,=0xffffffff  ;all interrupt disable //关中断
    str    r1,[r0]

    ldr    r0,=INTSUBMSK
    ldr    r1,=0x7fff        ;all sub interrupt disable  //关子中断
    str    r1,[r0]

    [ {TRUE}    ;//点LED灯
    ;rGPFDAT = (rGPFDAT & ~(0xf<<4)) | ((~data & 0xf)<<4);
    ; Led_Display
    ldr    r0,=GPBCON
    ldr    r1,=0x00555555
    str    r1,[r0]
    ldr    r0,=GPBDAT
    ldr    r1,=0x07fe
    str    r1,[r0]
    ]

    ;//为了减少PLL的lock time, 调整LOCKTIME寄存器.
    ;To reduce PLL lock time, adjust the LOCKTIME register.
    ldr    r0,=LOCKTIME
    ldr    r1,=0xffffff
    str    r1,[r0]

    [ PLL_ON_START;//6.下面就来设置PLL了,你的板快不快就看这了!!
    ; Added for confirm clock divide. for 2440.
    ; Setting value //Fclk:Hclk:Pclk
    ldr    r0,=CLKDIVN
    ldr    r1,=CLKDIV_VAL        ; 0=1:1:1, 1=1:1:2, 2=1:2:2, 3=1:2:4, 4=1:4:4, 5=1:4:8, 6=1:3:3, 7=1:3:6.
    str    r1,[r0]
;    MMU_SetAsyncBusMode and MMU_SetFastBusMode over 4K, so do not call here
;    call it after copy
;    [ CLKDIV_VAL>1         ; means Fclk:Hclk is not 1:1.
;    bl MMU_SetAsyncBusMode   ;//MMU_SetAsyncBusMode在4k以后,所以现在还不能调用
;    |
;    bl MMU_SetFastBusMode    ; default value.
;    ]
    ;program has not been copied, so use these directly
    [ CLKDIV_VAL>1         ; means Fclk:Hclk is not 1:1.//意思是 Fclk:Hclk 不是 1:1.
    mrc p15,0,r0,c1,c0,0
    orr r0,r0,#0xc0000000;R1_nF:OR:R1_iA
    mcr p15,0,r0,c1,c0,0
    |
    mrc p15,0,r0,c1,c0,0
    bic r0,r0,#0xc0000000;R1_iA:OR:R1_nF
    mcr p15,0,r0,c1,c0,0
    ]
    
    ;Configure UPLL    //配置 UPLL
    ldr    r0,=UPLLCON
    ldr    r1,=((U_MDIV<<12)+(U_PDIV<<4)+U_SDIV)  
    str    r1,[r0]
    nop    ; Caution: After UPLL setting, at least 7-clocks delay must be inserted for setting hardware be completed.
    nop
    nop
    nop
    nop
    nop
    nop
    ;Configure MPLL//配置 MPLL 一定要使最后的频率为16.9344MHz,不然你甭想用USB接口了,哈哈.
    ldr    r0,=MPLLCON
    ldr    r1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV)  ;Fin=16.9344MHz
    str    r1,[r0]
    ]

    ;//检查是否从SLEEP模式中恢复
    ;Check if the boot is caused by the wake-up from SLEEP mode.
    ldr    r1,=GSTATUS2
    ldr    r0,[r1]
    tst    r0,#0x2
    ;In case of the wake-up from SLEEP mode, go to SLEEP_WAKEUP handler.
    ;//如果是从SLEEP模式中恢复, 转跳到SLEEP_WAKEUP.
    bne    WAKEUP_SLEEP

    EXPORT StartPointAfterSleepWakeUp ;//导出符号StartPointAfterSleepWakeUp
StartPointAfterSleepWakeUp


;//设置内存控制器等寄存器的值,因为这些寄存器是连续排列的,所以采用如下办法对这些
;//寄存器进行连续设置.其中用到了SMRDATA的数据,这在代码后面有定义
    ;Set memory control registers    //给adram的寄存器赋值
     ;ldr    r0,=SMRDATA   
     adrl    r0, SMRDATA    ;be careful! //得到SMRDATA的首地址
    ldr    r1,=BWSCON    ;BWSCON Address  //得到BWSCON的地址
    add    r2, r0, #52    ;End address of SMRDATA

;//用于把(存储器总线宽度&等待控制寄存器BWSCON,Bank控制寄存器BANKCON0-5)   赋值
0
    ldr    r3, [r0], #4
    str    r3, [r1], #4
    cmp    r2, r0
    bne    %B0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;       When EINT0 is pressed,  Clear SDRAM
;//如果 EINT0 产生(这中断就是我们按键产生的), 就清除SDRAM ,不过好像没人会在这个时候按
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; check if EIN0 button is pressed

       ldr    r0,=GPFCON
    ldr    r1,=0x0
    str    r1,[r0]
    ldr    r0,=GPFUP
    ldr    r1,=0xff
    str    r1,[r0]

    ldr    r1,=GPFDAT
    ldr    r0,[r1]
       bic    r0,r0,#(0x1e<<1)  ; bit clear
    tst    r0,#0x1   ;//r0&&0x01 当按键0没有被按下的时候,也就是不相等,就跳转啦。不过好像没人会在这个时候按
    bne %F1
    
    

; Clear SDRAM Start//这就是清零内存的代码
 
    ldr    r0,=GPFCON
    ldr    r1,=0x55aa
    str    r1,[r0]
;    ldr    r0,=GPFUP
;    ldr    r1,=0xff
;    str    r1,[r0]
    ldr    r0,=GPFDAT
    ldr    r1,=0x0
    str    r1,[r0]    ;LED=****

    mov r1,#0
    mov r2,#0
    mov r3,#0
    mov r4,#0
    mov r5,#0
    mov r6,#0
    mov r7,#0
    mov r8,#0
    
    ldr    r9,=0x4000000   ;64MB  ;//清零内存
    ldr    r0,=0x30000000
0    
    stmia    r0!,{r1-r8}  ;//stm出栈,把r1-r8的值赋到r0上,然后r0+4
    subs    r9,r9,#32
    bne    %B0

;Clear SDRAM End

1

         ;Initialize stacks//初始化各种处理器模式下的堆栈
    bl    InitStacks

;===========================================================
    
    ldr    r0, =BWSCON
    ldr    r0, [r0]
    ands    r0, r0, #6        ;OM[1:0] != 0, NOR FLash boot //从norflash启动就跳转到copy_proc_beg
    bne    copy_proc_beg        ;do not read nand flash
    adr    r0, ResetEntry        ;OM[1:0] == 0, NAND FLash boot//从nandflash启动
    cmp    r0, #0                
    ;if use Multi-ice   //在进行比较,是否入口地址是在0处
    ;//如果不是,则表示主板设置了从NAND启动,但这个程序由于其它原因, 并没有从NAND从启动,这种情况最有可能的原因就是用仿真器.
 
    bne    copy_proc_beg        ;do not read nand flash for boot//仿真器也不需要在NAND FLASH启动
    ;nop
;===========================================================
;//bl 带返回的跳转指令
;//l 决定是否保存返回地址。当有l时,当前的PC寄存器的值将保存到lr寄存器中
;//    当无l时,指令仅执行跳转,当前的PC寄存器的值将不会保存到lr寄存器中
nand_boot_beg
    [ {TRUE}
    bl CopyProgramFromNand  //把nandflash中的程序全部copy到sdram中,从???
    |
    mov    r5, #NFCONF ;//首先设定NAND的一些控制寄存器
    ;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         ;//这里进行比较
    beq    %F1             ;//相等的话就跳到下一个1标号处
    ldr    r0, =0xec75  ;//这是另一个期望值
    cmp    r5, r0
    beq    %F1            ;//相等的话就跳到下一个1标号处
    mov    r6, #1        ;//不相等了,设置r6=1.
1    
    bl    ReadNandStatus  ;//读取NAND状态,结果放在r1里
    
    mov    r8, #0 ;//r8设初值0,意义为页号
    ldr    r9, =ResetEntry  ;// r9设初值为初始化程序入口地址
;// 注意,在这里使用的是ldr伪指令,而不是上面用的adr伪指令,它加载的是ResetEntry
;// 的绝对地址,也就是我们期望的RAM中的地址,在这里,它和|Image$$RO$$Base|一样
;// 也就是说,如我们编译程序时RO base指定的地址在RAM里,而把生成的文件拷到
;// NAND里运行,由ldr加载的r9的值还是定位在内存. ???

2    
    ands    r0, r8, #0x1f;//r8为0x1f(32)的整数倍-1,eq有效,ne无效
    bne        %F3            ;//这句的意思是对每个块(32页)进行检错
    mov        r0, r8        ;//r8->r0
    bl        CheckBadBlk ;//检查NAND的坏区
    cmp        r0, #0        ;//比较r0和0
    addne    r8, r8, #32 ;//存在坏块的话就跳过这个坏块
    bne        %F4            ;//没有的话就跳到标号4处
3    
    mov    r0, r8            ;//当前页号->r0
    mov    r1, r9            ;//当前目标地址->r1
    bl    ReadNandPage    ;//读取该页的NAND数据到RAM
    add    r9, r9, #512    ;//每一页的大小是512Bytes
    add    r8, r8, #1        ;//r8指向下一页
4    
    cmp    r8, #5120        ;//比较是否读完5120页即128KBytes
    bcc    %B2                ;//如果r8小于256(没读完),就返回前面的标号2处
    
    mov    r5, #NFCONF            ;DsNandFlash
    ldr    r0, [r5, #4]
    bic r0, r0, #1
    str    r0, [r5, #4]
    ]
    ldr    pc, =copy_proc_beg   ;//ldr指令 加载了绝对地址,现在pc指向的是sdram中的copy_proc_beg,程序在sdram上运行了
;===========================================================
copy_proc_beg      
    adr    r0, ResetEntry    ;//程序在sdram上运行了,该取值方式 取到的地址就是相对于pc的偏移地址了也就是0x30000000
    ;//这里应该注意,使用的是adr,而不是ldr。使用ldr说明ResetEntry是个绝对地址,这个地址是在程序链接的时候
    ;//确定的。而使用adr则说明ResetEntry的地址和当前代码的执行位置有关,它是一个相对的地址。比如这段代码
    ;//在stepingstone里面执行,那么ResetEntry的地址就是零。如果在sdRAM里执行,那么ResetEntry就应是sdRAM的一个
    ;//地址,应该等于RO base 为0x30000000。

    ldr    r2, BaseOfROM     ;//0x30000000  ldr 是把BaseOfROM(一地址)中的值放到r2中
    cmp    r0, r2
    ldreq    r0, TopOfROM  ;//相等就跳转  相等说明程序是从nandflash或者sdram中运行的。不相等是从norflash运行的
    beq    InitRam    
    
    ldr r3, TopOfROM      ;//以下代码是针对代码在NOR FLASH时的拷贝方法,这个程序 从norflash也要copy程序
0    
    ldmia    r0!, {r4-r7}   ;//搬运代码
    stmia    r2!, {r4-r7}
    cmp    r2, r3
    bcc    %B0
    
    sub    r2, r2, r3  ;//上面拷贝时每次拷贝4个双字(32位)大小,但是RO段大小不一定是4的整数倍,所以可能多拷贝了几个双字大小,r2-r3得到多拷贝的个数
    sub    r0, r0, r2    ;//r0-(r2-r3)可以使r0指向在boot nand中RO的结束地址            
        
InitRam            //复制SW区域
    ldr    r2, BaseOfBSS
    ldr    r3, BaseOfZero    
0
    cmp    r2, r3;//比较BaseOfBSS和BaseOfZero
    ldrcc    r1, [r0], #4
    strcc    r1, [r2], #4
    bcc    %B0    

    mov    r0,    #0
    ldr    r3,    EndOfBSS
1    
    cmp    r2,    r3
    strcc    r0, [r2], #4
    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       ;This routine is needed
    ldr    r1,=IsrIRQ      ;if there is not 'subs pc,lr,#4' at 0x18, 0x1c
    str    r1,[r0]        //把IsrIRQ的地址放到HandleIRQ中

;    ;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    ;Do not use main() because ......
         ;ldr    pc, =Main    ;
         b    .
    ]

    [ THUMBCODE     ;for start-up code for Thumb mode
         orr    lr,pc,#1
         bx    lr
         CODE16
         bl    Main    ;Do not use main() because ......
         b    .
        CODE32
    ]


;function initializing stacks
InitStacks ;//-----------------------7个模式堆栈初始化
    ;Do not use DRAM,such as stmfd,ldmfd......
    ;SVCstack is initialized before
    ;Under toolkit ver 2.5, 'msr cpsr,r1' can be used instead of 'msr cpsr_cxsf,r1'
    mrs    r0,cpsr            ;//cpsr为状态寄存器
    bic    r0,r0,#MODEMASK  ;//清空低5位的数据
    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

    ;USER mode has not be initialized.

    mov    pc,lr
    ;The LR register will not be valid if the current mode is not SVC mode.
    
;===========================================================
    [ {TRUE}
    |
ReadNandID
    mov      r7,#NFCONF
    ldr      r0,[r7,#4]        ;NFChipEn();
    bic      r0,r0,#2
    str      r0,[r7,#4]
    mov      r0,#0x90        ;WrNFCmd(RdIDCMD);
    strb     r0,[r7,#8]
    mov      r4,#0            ;WrNFAddr(0);
    strb     r4,[r7,#0xc]
1                            ;while(NFIsBusy());
    ldr      r0,[r7,#0x20]
    tst      r0,#1
    beq      %B1
    ldrb     r0,[r7,#0x10]    ;id  = RdNFDat()<<8;
    mov      r0,r0,lsl #8
    ldrb     r1,[r7,#0x10]    ;id |= RdNFDat();
    orr      r5,r1,r0
    ldr      r0,[r7,#4]        ;NFChipDs();
    orr      r0,r0,#2
    str      r0,[r7,#4]
    mov         pc,lr    
    
ReadNandStatus
    mov         r7,#NFCONF
    ldr      r0,[r7,#4]        ;NFChipEn();
    bic      r0,r0,#2
    str      r0,[r7,#4]
    mov      r0,#0x70        ;WrNFCmd(QUERYCMD);
    strb     r0,[r7,#8]    
    ldrb     r1,[r7,#0x10]    ;r1 = RdNFDat();
    ldr      r0,[r7,#4]        ;NFChipDs();
    orr      r0,r0,#2
    str      r0,[r7,#4]
    mov         pc,lr

WaitNandBusy
    mov      r0,#0x70        ;WrNFCmd(QUERYCMD);
    mov      r1,#NFCONF
    strb     r0,[r1,#8]
1                            ;while(!(RdNFDat()&0x40));    
    ldrb     r0,[r1,#0x10]
    tst      r0,#0x40
    beq         %B1
    mov      r0,#0            ;WrNFCmd(READCMD0);
    strb     r0,[r1,#8]
    mov      pc,lr

CheckBadBlk
    mov        r7, lr
    mov        r5, #NFCONF
    
    bic      r0,r0,#0x1f    ;addr &= ~0x1f;
    ldr      r1,[r5,#4]        ;NFChipEn()
    bic      r1,r1,#2
    str      r1,[r5,#4]

    mov      r1,#0x50        ;WrNFCmd(READCMD2)
    strb     r1,[r5,#8]
    mov      r1, #5;6        ;6->5
    strb     r1,[r5,#0xc]    ;WrNFAddr(5);(6) 6->5
    strb     r0,[r5,#0xc]    ;WrNFAddr(addr)
    mov      r1,r0,lsr #8    ;WrNFAddr(addr>>8)
    strb     r1,[r5,#0xc]
    cmp      r6,#0            ;if(NandAddr)        
    movne    r0,r0,lsr #16    ;WrNFAddr(addr>>16)
    strneb   r0,[r5,#0xc]
    
;    bl        WaitNandBusy    ;WaitNFBusy()
    ;do not use WaitNandBusy, after WaitNandBusy will read part A!
    mov    r0, #100
1
    subs    r0, r0, #1
    bne    %B1
2
    ldr    r0, [r5, #0x20]
    tst    r0, #1
    beq    %B2    

    ldrb    r0, [r5,#0x10]    ;RdNFDat()
    sub        r0, r0, #0xff
    
    mov      r1,#0            ;WrNFCmd(READCMD0)
    strb     r1,[r5,#8]
    
    ldr      r1,[r5,#4]        ;NFChipDs()
    orr      r1,r1,#2
    str      r1,[r5,#4]
    
    mov        pc, r7
    
ReadNandPage
    mov         r7,lr
    mov      r4,r1
    mov      r5,#NFCONF

    ldr      r1,[r5,#4]        ;NFChipEn()
    bic      r1,r1,#2
    str      r1,[r5,#4]    

    mov      r1,#0            ;WrNFCmd(READCMD0)
    strb     r1,[r5,#8]    
    strb     r1,[r5,#0xc]    ;WrNFAddr(0)
    strb     r0,[r5,#0xc]    ;WrNFAddr(addr)
    mov      r1,r0,lsr #8    ;WrNFAddr(addr>>8)
    strb     r1,[r5,#0xc]    
    cmp      r6,#0            ;if(NandAddr)        
    movne    r0,r0,lsr #16    ;WrNFAddr(addr>>16)
    strneb   r0,[r5,#0xc]
    
    ldr      r0,[r5,#4]        ;InitEcc()
    orr      r0,r0,#0x10
    str      r0,[r5,#4]
    
    bl       WaitNandBusy    ;WaitNFBusy()
    
    mov      r0,#0            ;for(i=0; i<512; i++)
1
    ldrb     r1,[r5,#0x10]    ;buf[i] = RdNFDat()
    strb     r1,[r4,r0]
    add      r0,r0,#1
    bic      r0,r0,#0x10000
    cmp      r0,#0x200
    bcc      %B1
    
    ldr      r0,[r5,#4]        ;NFChipDs()
    orr      r0,r0,#2
    str      r0,[r5,#4]
        
    mov         pc,r7
    ]


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

    LTORG

;GCS0->SST39VF1601
;GCS1->16c550
;GCS2->IDE
;GCS3->CS8900
;GCS4->DM9000
;GCS5->CF Card
;GCS6->SDRAM
;GCS7->unused

SMRDATA DATA  ;//这是一块连续的地址,用于存放 存储器总线宽度&等待控制寄存器BWSCON,Bank控制寄存器BANKCON0-5
; Memory configuration should be optimized for best performance
; The following parameter is not optimized.
; Memory access cycle parameter strategy
; 1) The memory settings is  safe parameters even at HCLK=75Mhz.
; 2) SDRAM refresh period is for HCLK<=75Mhz.

    DCD (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
    DCD ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))   ;GCS0
    DCD ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))   ;GCS1
    DCD ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))   ;GCS2
    DCD ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))   ;GCS3
    DCD ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))   ;GCS4
    DCD ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))   ;GCS5
    DCD ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))    ;GCS6
    DCD ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))    ;GCS7
    DCD ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Tsrc<<18)+(Tchr<<16)+REFCNT)

    DCD 0x32        ;SCLK power saving mode, BANKSIZE 128M/128M

    DCD 0x30        ;MRSR6 CL=3clk
    DCD 0x30        ;MRSR7 CL=3clk
    
BaseOfROM    DCD    |Image$$RO$$Base|
TopOfROM    DCD    |Image$$RO$$Limit|
BaseOfBSS    DCD    |Image$$RW$$Base|
BaseOfZero    DCD    |Image$$ZI$$Base|
EndOfBSS    DCD    |Image$$ZI$$Limit|

    ALIGN
    
;Function for entering power down mode
; 1. SDRAM should be in self-refresh mode.
; 2. All interrupt should be maksked for SDRAM/DRAM self-refresh.
; 3. LCD controller should be disabled for SDRAM/DRAM self-refresh.
; 4. The I-cache may have to be turned on.
; 5. The location of the following code may have not to be changed.

;void EnterPWDN(int CLKCON);
EnterPWDN     ;//掉电工作模式
    mov r2,r0        ;//r2=rCLKCON   r0为该函数输入参数clkcon
    tst r0,#0x8        ;SLEEP mode?
    bne ENTER_SLEEP

ENTER_STOP   ;//待机模式
    ldr r0,=REFRESH
    ldr r3,[r0]        ;r3=rREFRESH
    mov r1, r3
    orr r1, r1, #BIT_SELFREFRESH
    str r1, [r0]        ;Enable SDRAM self-refresh

    mov r1,#16            ;wait until self-refresh is issued. may not be needed.
0    subs r1,r1,#1
    bne %B0

    ldr r0,=CLKCON        ;enter STOP mode.
    str r2,[r0]

    mov r1,#32
0    subs r1,r1,#1    ;1) wait until the STOP mode is in effect.
    bne %B0        ;2) Or wait here until the CPU&Peripherals will be turned-off
            ;   Entering SLEEP mode, only the reset by wake-up is available.

    ldr r0,=REFRESH ;exit from SDRAM self refresh mode.
    str r3,[r0]

    MOV_PC_LR

ENTER_SLEEP   ;//SLEEP模式
    ;NOTE.
    ;1) rGSTATUS3 should have the return address after wake-up from SLEEP mode.

    ldr r0,=REFRESH
    ldr r1,[r0]        ;r1=rREFRESH
    orr r1, r1, #BIT_SELFREFRESH
    str r1, [r0]        ;Enable SDRAM self-refresh

    mov r1,#16            ;Wait until self-refresh is issued,which may not be needed.
0    subs r1,r1,#1
    bne %B0

    ldr    r1,=MISCCR
    ldr    r0,[r1]
    orr    r0,r0,#(7<<17)  ;Set SCLK0=0, SCLK1=0, SCKE=0.
    str    r0,[r1]

    ldr r0,=CLKCON        ; Enter sleep mode
    str r2,[r0]

    b .            ;CPU will die here.


WAKEUP_SLEEP   ;//从SLEEP模式下被唤醒函数
    ;Release SCLKn after wake-up from the SLEEP mode.
    ldr    r1,=MISCCR
    ldr    r0,[r1]
    bic    r0,r0,#(7<<17)  ;SCLK0:0->SCLK, SCLK1:0->SCLK, SCKE:0->=SCKE.
    str    r0,[r1]

    ;Set memory control registers
     ldr    r0,=SMRDATA    ;be careful!      //得到SMRDATA的首地址
    ldr    r1,=BWSCON    ;BWSCON Address   //得到BWSCON的地址
    add    r2, r0, #52    ;End address of SMRDATA
0
    ldr    r3, [r0], #4
    str    r3, [r1], #4
    cmp    r2, r0
    bne    %B0

    mov r1,#256
0    subs r1,r1,#1    ;1) wait until the SelfRefresh is released.
    bne %B0

    ldr r1,=GSTATUS3     ;GSTATUS3 has the start address just after SLEEP wake-up
    ldr r0,[r1]

    mov pc,r0
    
;=====================================================================
; Clock division test
; Assemble code, because VSYNC time is very short
;=====================================================================
    EXPORT CLKDIV124
    EXPORT CLKDIV144
    
CLKDIV124
    
    ldr     r0, = CLKDIVN
    ldr     r1, = 0x3        ; 0x3 = 1:2:4
    str     r1, [r0]
;    wait until clock is stable
    nop
    nop
    nop
    nop
    nop

    ldr     r0, = REFRESH   ;//SDRAM刷新控制寄存器
    ldr     r1, [r0]
    bic        r1, r1, #0xff
    bic        r1, r1, #(0x7<<8) ;//设置刷新计数的值
    orr        r1, r1, #0x470    ;// REFCNT135
    str     r1, [r0]
    nop
    nop
    nop
    nop
    nop
    mov     pc, lr

CLKDIV144
    ldr     r0, = CLKDIVN
    ldr     r1, = 0x4        ; 0x4 = 1:4:4
    str     r1, [r0]
;    wait until clock is stable
    nop
    nop
    nop
    nop
    nop

    ldr     r0, = REFRESH
    ldr     r1, [r0]
    bic        r1, r1, #0xff
    bic        r1, r1, #(0x7<<8)
    orr        r1, r1, #0x630    ; REFCNT675 - 1520
    str     r1, [r0]
    nop
    nop
    nop
    nop
    nop
    mov     pc, lr


    ALIGN

    AREA RamData, DATA, READWRITE  ;//相应中断跳转的地址存放处

    ^   _ISR_STARTADDRESS        ; _ISR_STARTADDRESS=0x33FF_FF00
HandleReset     #   4
HandleUndef     #   4
HandleSWI        #   4
HandlePabort    #   4
HandleDabort    #   4
HandleReserved  #   4
HandleIRQ        #   4
HandleFIQ        #   4

;Do not use the label 'IntVectorTable',
;The value of IntVectorTable is different with the address you think it may be.
;IntVectorTable
;@0x33FF_FF20
HandleEINT0        #   4
HandleEINT1        #   4
HandleEINT2        #   4
HandleEINT3        #   4
HandleEINT4_7    #   4
HandleEINT8_23    #   4
HandleCAM        #   4        ; Added for 2440.
HandleBATFLT    #   4
HandleTICK        #   4
HandleWDT        #   4
HandleTIMER0     #   4
HandleTIMER1     #   4
HandleTIMER2     #   4
HandleTIMER3     #   4
HandleTIMER4     #   4
HandleUART2      #   4
;@0x33FF_FF60
HandleLCD         #   4
HandleDMA0        #   4
HandleDMA1        #   4
HandleDMA2        #   4
HandleDMA3        #   4
HandleMMC        #   4
HandleSPI0        #   4
HandleUART1        #   4
HandleNFCON        #   4        ; Added for 2440.
HandleUSBD        #   4
HandleUSBH        #   4
HandleIIC        #   4
HandleUART0     #   4
HandleSPI1         #   4
HandleRTC         #   4
HandleADC         #   4
;@0x33FF_FFA0
    END
posted on 2010-08-07 21:10  板牙  阅读(1353)  评论(0)    收藏  举报