免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1140 | 回复: 0
打印 上一主题 下一主题

2440init.s 学习 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-10-12 21:41 |只看该作者 |倒序浏览
;=========================================
; 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 s for testing STOP,Sleep mode
; 2003.03.14:DonGo: Modified for 2440.
;=========================================

;首先,启动代码定义了一些常量
;汇编不能使用include包含头文件,所有用Get
;汇编也不认识*.h 文件,所有只能用*.inc
GET option.inc    ;定义芯片相关的配置
GET memcfg.inc    ;定义存储器配置
GET 2440addr.inc  ;定义了寄存器符号
;REFRESH寄存器[22]bit : 0- auto refresh; 1 - self refresh
;用于节电模式中,SDRAM自动刷新
BIT_SELFREFRESH EQU (1 ;处理器模式常量: CPSR寄存器的后5位决定目前处理器模式 M[4:0]
USERMODE    EQU  0x10
FIQMODE     EQU  0x11
IRQMODE     EQU  0x12
SVCMODE     EQU  0x13
ABORTMODE   EQU  0x17
UNDEFMODE   EQU  0x1b
MODEMASK    EQU  0x1f
NOINT       EQU  0xc0

;定义处理器各模式下堆栈地址常量 ;_STACK_BASEADDRESS定义在option.inc中
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处理器有两种工作状态 1.arm:32位 这种工作状态下执行字对准的arm指令 2.Thumb:16位 这种工状;态执行半字对准的Thumb指令
;因为处理器分为16位 32位两种工作状态 程序的编译器也是分16位和32两种编译方式 所以下面的程序用
;于根据处理器工作状态确定编译器编译方式
;code16伪指令指示汇编编译器后面的指令为16位的thumb指令
;code32伪指令指示汇编编译器后面的指令为32位的arm指令
;
;Arm上电时处于ARM状态,故无论指令为ARM集或Thumb集,都先强制成ARM集,待init.s初始化完成后
;再根据用户的编译配置转换成相应的指令模式。为此,定义变量THUMBCODE作为指示,跳转到main之前
;根据其值切换指令模式
;
;这段是为了统一目前的处理器工作状态和软件编译方式(16位编译环境使用tasm.exe编译

;检查在tasm.exe里是否设置了采用THUMB(16位)代码(armasm -16 ...@ADS 1.0)


GBLL    THUMBCODE                ;定义THUMBCODE全局变量
   [ {CONFIG} = 16  
                                 ;如果发现是在用16位代码的话(编译选项中指定使用thumb指令
     
THUMBCODE SETL  {TRUE}    ;把THUMBCODE设置为TURE
     
       CODE32                    ;把处理器从新设置成为ARM模式  
        
         |                       ;如果处理器现在就是ARM模式
   
THUMBCODE SETL  {FALSE}    ;把THUMBCODE设置为FALSE就行了
   
   ]
   
MACRO
              ;一个根据THUMBCODE把PC寄存的值保存到LR的宏, 宏 MOV_PC_LR

MOV_PC_LR    [   THUMBCODE
     bx lr   ;([表示if)
                                     ;在ARM模式中要使用BX指令转跳到THUMB指令,并转换模式
                  
  |          ;(|表示else)如果编译选项本来就指定为ARM模式
                      mov pc,lr  ;如果目标地址也是ARM指令的话就采用这种方式
                ]               ;(]表示endif)
    MEND

   MACRO             ;和上面的宏一样,只是多了一个相等的条件
    MOVEQ_PC_LR
   [     THUMBCODE
           bxeq lr
   |
         moveq pc,lr
   ]
MEND

;=======================================================================================
;下面这个宏是用于第一次查表过程的实现中断向量的重定向,如果你比较细心的话就是发现
;在_ISR_STARTADDRESS=0x33FF_FF00里定义的第一级中断向量表是采用型如Handle***的方式的.
;而在程序的ENTRY处(程序开始处)采用的是b Handler***的方式.
;在这里Handler***就是通过HANDLER这个宏和Handle***进立联系的.
;这种方式的优点就是正真定义的向量数据在内存空间里,而不是在ENTRY处的ROM(FLASH)空间里,
;这样,我们就可以在程序里灵活的改动向量的数据了.
;========================================================================================
;;这段程序用于把中断服务程序的首地址装载到pc中,有人称之为“加载程序”。
;本初始化程序定义了一个数据区(在文件最后),34个字空间,存放相应中断服务程序的首地址。每个字
;空间都有一个标号,以Handle***命名。
;在向量中断模式下使用“加载程序”来执行中断服务程序。
;这里就必须讲一下向量中断模式和非向量中断模式的概念
;向量中断模式是当cpu读取位于0x18处的IRQ中断指令的时候系统自动读取对应于该中断源确定地址上的;
;指令取代0x18处的指令,通过跳转指令系统就直接跳转到对应地址
;函数中 节省了中断处理时间提高了中断处理速度标 例如 ADC中断的向量地址为0xC0,则在0xC0处放如下
;代码:ldr PC,=HandlerADC 当ADC中断产生的时候系统会
;自动跳转到HandlerADC函数中
;非向量中断模式处理方式是一种传统的中断处理方法,当系统产生中断的时候,系统将interrupt
;pending寄存器中对应标志位置位
然后跳转到位于0x18处的统一中断
;函数中 该函数通过读取interrupt pending寄存器中对应标志位 来判断中  断  源 并根据优先级关系再跳到
;对应中断源的处理代码中
;
  MACRO
$HandlerLabel HANDLER $HandleLabel

$HandlerLabel       ;标号
sub sp,sp,#4        ;减少sp(用于存放转跳地址)
stmfd sp!,{r0}      ;把工作寄存器压入栈(lr does not push because it return to original address)
ldr     r0,=$HandleLabel    ;将HandleXXX的址址放入r0
ldr     r0,[r0]                          ;把HandleXXX所指向的内容(也就是中断程序的入口)放入r0
str     r0,[sp,#4]                    ;把中断服务程序(ISR)压入栈
ldmfd   sp!,{r0,pc}               ;用出栈的方式恢复r0的原值和为pc设定新值(也就完成了到ISR的转跳)
MEND


;=========================================================================================
;在这里用IMPORT伪指令(和c语言的extren一样)引入
|Image$$RO$$Base|,|Image$$RO$$Limit|...
;这些变量是通过ADS的工程设置里面设定的RO BaseRW Base设定的,
;最终由编译脚本和连接程序导入程序.
;那为什么要引入这玩意呢,最简单的用处是可以根据它们拷贝自已
;==========================================================================================
IMPORT  |Image$$RO$$Base|   ; ROM code(也就是代码)的开始地址
IMPORT  |Image$$RO$$Limit|    ; ROM code的结束地址 (=ROM data的开始地址)
IMPORT  |Image$$RW$$Base|   ; 要初始化的RAM的开始地址
IMPORT  |Image$$ZI$$Base|      ; area(需要清零的RAM区域)的开始地址
IMPORT  |Image$$ZI$$Limit|       ; area的结束地址

    ;这里引入一些在其它文件中实现在函数,包括为我们所熟知的main函数
IMPORT MMU_SetAsyncBusMode
IMPORT MMU_SetFastBusMode ;hzh



IMPORT Main
  •                                                             ; The main entry of mon program

                                                                ;从这里开始就是正真的代码入口了!
    AREA    Init,CODE,READONLY     ;这表明下面的是一个名为Init的代码段

    ENTRY
                                                   ;定义程序的入口(调试用)  
      
    EXPORT __ENTRY                         ;导出符号_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
    [               ENDIAN_CHANGE            
          ;下面是大小端的一个判断,在Option.inc里已经设 FALSE
    ASSERT  :DEF:ENTRY_BUS_WIDTH        ;判断ENTRY_BUS_WIDTH是否已定义
         [          ENTRY_BUS_WIDTH=32        ;如果已经定义了ENTRY_BUS_WIDTH,则判断是不是为32
                    b ChangeBigEndian                   ;DCD 0xea000007
                   ;在bigendian中,地址为A的字单元包括字节单元A,A+1,A+2,A+3,字节单元由高位到低位为A,A+1,A+2,A+3
    ;    地址为A的字单元包括半字单元A,A+2,半字单元由高位到低位为A,A+2
         ]

         [         ENTRY_BUS_WIDTH=16
                     andeq r14,r7,r0,lsl #20                ;DCD 0x0007ea00
         ]                                                             b ChangeBigEndian指令,只是由于总线不一样而取机                                                         器码的顺序不一样

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

                                        ;@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
    ;=========================================================================================
    ; 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
       ldr  r0,=rCLKCON  
       mov r2,r0                     ;r2=rCLKCON 保存原始数据 0x4c00000c 使能各模块的时钟输入
       tst r0,#0x8                   ;测试bit[3] SLEEP mode? 1=>sleep
       bne ENTER_SLEEP     ;C=0,即TST结果非0,bit[3]=1
                                         ;//进入PWDN后如果不是sleep则进入stop
                                         ;//进入Stop mode
    ENTER_STOP
    ldr r0,=REFRESH          ;0x48000024   DRAM/SDRAM refresh config
    ldr r3,[r0]                       ;r3=rREFRESH
    mov r1, r3
    orr r1, r1, #BIT_SELFREFRESH                 ;Enable SDRAM self-refresh
    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                                                   ; %B 表示向前找 到 0处
                                                                     ;//wait 16 fclks for self-refresh
    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                                  ;back to main process
      
    ENTER_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
                                                    ;//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
                                                      ;//Wait until self-refresh is issued,which may not be needed
    ldr r1,=MISCCR                          ;IO register
    ldr r0,[r1]
    orr r0,r0,#(7SCLK, SCLK1:0->SCLK, SCKE:0->=SCKE.
    str r0,[r1]
                                             ;//设置MISCCR
                                      ;Set memory control registers
      ;ldr r0,=SMRDATA
      adrl r0, SMRDATA
      ldr r1,=BWSCON                      ;BWSCON Address ;//总线宽度和等待控制寄存器
    add r2, r0, #52                           ;End address of SMRDATA
    0
    ldr r3, [r0], #4                             ;数据处理后R0自加4,[R0]->R3,R0+4->R0
    str r3, [r1], #4
    cmp r2, r0
    bne %B0
                                             ;//设置所有的memory control register,他的初始地址为BWSCON,初始
                                             ;//数据在以SMRDATA为起始的存储区
    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
                                             ;//跳出Sleep Mode,进入Sleep状态前的PC
      
    ;如上所说,这里采用HANDLER宏去建立Hander***和Handle***之间的联系
    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 ;给PC寄存器保留
    stmfd sp!,{r8-r9} ;把r8-r9压入栈

    ldr r9,=INTOFFSET ;把INTOFFSET的地址装入r9  INTOFFSET是一个内部的寄存器,存着中断的偏移
      ldr r9,[r9]  ;把INTOFFSET的值装入r9
      ldr r8,=HandleEINT0 ;这就是我们第二个中断向量表的入口的,先装入r8
    ;===================================================================================
    ;哈哈,这查表方法够好了吧,r8(入口)+index*4(别望了一条指令是4 bytes的喔),
    ;这不就是我们要找的那一项了吗.找到了表项,下一步做什么?肯定先装入了!
    ;==================================================================================  
    add r8,r8,r9,lsl #2         ;地址对齐,因为每个中断向量占4个字节,即isr = IvectTable + Offeset * 4
    ldr r8,[r8]                     ;装入中断服务程序的入口
    str r8,[sp,#8]               ;把入口也入栈,准备用旧招
    ldmfd sp!,{r8-r9,pc}       ;施招,弹出栈,哈哈,顺便把r8弹出到PC,O了,跳转成功!


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


    ;==============================================================================
    ; ENTRY(好了,我们的CPU要在这复位了.)
    ;==============================================================================
    ResetHandler
    ldr r0,=WTCON       ;1.关看门狗
    ldr r1,=0x0                 ;bit[5]: 0 - disable; 1 - enable (reset 默认)
    str r1,[r0]

    ldr r0,=INTMSK
    ldr r1,=0xffffffff  ;2.关中断
    str r1,[r0]

    ldr r0,=INTSUBMSK
    ldr r1,=0x7fff ;3.关子中断
    str r1,[r0]

    [ {FALSE}
                                                     ;4.得有些表示了,该点点LED灯了,不过被FALSE掉了.
                                                      ;rGPFDAT = (rGPFDAT & ~(0xf1   ; 意思是 Fclk:Hclk 不是 1:1.
    ; bl MMU_SetAsyncBusMode
    ; |
    ; bl MMU_SetFastBusMode ; default value.
    ; ]

    [ CLKDIV_VAL>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
    ]
      
    ;配置 UPLL
    ;//Configure UPLL Fin=12.0MHz UFout=48MHz
      ldr r0,=UPLLCON
      ldr r1,=((U_MDIVSMRDATA的数据,这在代码后面有定义
    ;===============================================================================
      ;ldr r0,=SMRDATA

      adrl r0, SMRDATA                  ;be careful!, hzh
       ldr r1,=BWSCON                  ;BWSCON 地址
    add r2, r0, #52 ;                        SMRDATA数据的结束地址,共有52字节的数据

    0
    ldr r3, [r0], #4
    str r3, [r1], #4
    cmp r2, r0
    bne %B0

    ;================================================================================
    ;如果 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 bne copy_proc_beg               ;不读取NAND FLASH
    adr r0, ResetEntry                     ;OM[1:0] == 0, 为从NAND FLash启动
    cmp r0, #0                                  ;再比较入口是否为0地址处
    ;==========================================================================
    ;如果不是,则表示主板设置了从NAND启动,但这个程序由于其它原因,
    ;并没有从NAND启动,这种情况最有可能的原因就是用仿真器.
    ;==========================================================================
    bne copy_proc_beg      ;这种情况也不读取NAND FLASH.
    ;nop                                   ;如果是0才是真正从NAND 启动,因为其4k被复制到0地址                                                    开始的stepingstone 内部sram中
           ; 注意adr得到的是 相对 地址,非绝对地址 == if use Multi-ice,
    ;===========================================================
    nand_boot_beg                          ;这一段代码完成从NAND读代码到RAM
    mov r5, #NFCONF                        ;首先设定NAND的一些控制寄存器
                                                            ;set timing value
    ldr r0, =(7r0
    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, #256                                 ;比较是否读完256页即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                             ;调用copy_proc_beg
    ;===========================================================
    copy_proc_beg
    adr r0, ResetEntry                             ;ResetEntry值->r0
    ldr r2, BaseOfROM                          ;BaseOfROM值(后面有定义)->r2
    cmp r0, r2                                          ;比较r0和r2
    ldreq r0, TopOfROM                         ;如果相等的话(在内存运行),TopOfROM->r0
    beq InitRam                                     ;同时跳到InitRam

    ;=========================================================
    ;下面这个是针对代码在NOR FLASH时的拷贝方法
    ;功能为把从ResetEntry起,TopOfROM-BaseOfROM大小的数据拷到BaseOfROM
    ;TopOfROM和BaseOfROM为|Image$$RO$$Limit|和|Image$$RO$$Base|
    ;|Image$$RO$$Limit|和|Image$$RO$$Base|由连接器生成
    ;为生成的代码的代码段运行时的起启和终止地址
    ;BaseOfBSS和BaseOfZero为|Image$$RW$$Base|和|Image$$ZI$$Base|
    ;|Image$$RW$$Base|和|Image$$ZI$$Base|也是由连接器生成
    ;两者之间就是初始化数据的存放地放
    ;=======================================================

    ldr r3, TopOfROM  
    0
    ldmia r0!, {r4-r7}
    stmia r2!, {r4-r7}
    cmp r2, r3
    bcc %B0
      
    sub r2, r2, r3  ;r2=BaseOfROM-TopOfROM=(-)代码长度   
    sub r0, r0, r2 ;r0=ResetEntry-(-)代码长度=ResetEntry+代码长度  
       
    InitRam  
    ldr r2, BaseOfBSS                            ;BaseOfBSS->r2
    ldr r3, BaseOfZero                             ;BaseOfZero->r3
    0
    cmp r2, r3                           ;比较BaseOfBSS和BaseOfZero
    ldrcc r1, [r0], #4  ;要是r21   ; means Fclk:Hclk is not 1:1.
    ; bl MMU_SetAsyncBusMode
    ; |
    ; bl MMU_SetFastBusMode ; default value.
    ; ]
      
    ;bl Led_Test

    ;===========================================================
       ; 进入C语言前的最后一步了,就是把我们用说查二级向量表
    ; 的中断例程安装到一级向量表(异常向量表)里.
    ldr r0,=HandleIRQ       ;This routine is needed
    ldr r1,=IsrIRQ   ;if there is not 'subs pc,lr,#4' at 0x18, 0x1c
    str r1,[r0]

    ; ;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


    ;*****************************************************************************
    ;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    ; 妈呀,终说见到艳阳天了!!!!!!!!!!
    ;       跳到C语言的main函数处了.
    ;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    ;*****************************************************************************
        [ :LNOT:THUMBCODE
       bl Main ;Do not use main() because ......
       ;ldr pc, =Main ;hzh
       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
        ]


    ; initializing stacks
    InitStacks
    ;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
    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

    ;USER mode has not be initialized.

    mov pc,lr
    ;The LR register will not be valid if the current mode is not SVC mode.
      
    ;===========================================================
    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()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; iSST39VF1601
    ;GCS1->16c550
    ;GCS2->IDE
    ;GCS3->CS8900
    ;GCS4->DM9000
    ;GCS5->CF Card
    ;GCS6->SDRAM
    ;GCS7->unused

    SMRDATA DATA
    ; 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 HCLKof the following code may have not to be changed.

    ;void EnterPWDN(int CLKCON);
    EnterPWDN
    mov r2,r0  ;r2=rCLKCON
    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
    ;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,#(7SCLK, SCLK1:0->SCLK, SCKE:0->=SCKE.
    str r0,[r1]

    ;Set memory control registers
      ldr r0,=SMRDATA ;be careful!, hzh
    ldr r1,=BWSCON ;BWSCON Address
    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
    ldr     r1, [r0]
    bic  r1, r1, #0xff
    bic  r1, r1, #(0x7of 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


    本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/93992/showart_2068791.html
  • 您需要登录后才可以回帖 登录 | 注册

    本版积分规则 发表回复

      

    北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
    未成年举报专区
    中国互联网协会会员  联系我们:huangweiwei@itpub.net
    感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

    清除 Cookies - ChinaUnix - Archiver - WAP - TOP