ARM启动文件2440init.s分析

;=========================================
; NAME: 2440INIT.S
; DESC: C start up codes
;       Configure memory, ISR ,stacks
;Initialize C-variables
;========================================= 

;注意:axd调试时,可以看到指令pc地址从0x30000000开始,这是因为ram的起始地址是0x30000000.
;并且如果从nand启动,则处理器自动把nand首部的4k字节,复制到ram中,然后pc跳到0x30000000,开始执行。

;此源文件通常包含一些宏定义和常量定义

;通用的《启动流程图》:
;入口->屏蔽所有中断,禁止看门狗->根据工作频率设置PLL寄存器->初始化存储控制相关寄存器
;->初始化各模式下的栈指针->设置缺省中断处理函数->将数据拷贝到RAM中,数据段清零
;->跳转到c语言main入口函数中

;GET伪指令用于将一个源文件包含到当前源文件中,并将被包含文件在当前位置进行汇编处理
;类似于c的include指令

;GET INLCUDE伪指令不能用来包含目标文件,INCBIN伪指令可以包含目标文件,
;被INCBIN伪指令包含的文件,不进行汇编处理,该执行文件或数据直接放入当前文件,
;编译器从INCBIN后边开始继续处理

        GET option.inc     ;定义芯片相关配置
        GET memcfg.inc     ;定义存储器配置
        GET 2440addr.inc   ;定义寄存器符号

;REFRESH寄存器[22]bit :SDRAM刷新模式 0 - auto refresh
;                                     1 - self refresh
;用于节电模式中,SDRAM自动刷新

BIT_SELFREFRESH EQU   (1<<22)

;Pre-defined constants
;模式预定义常量,给cpsr【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 ;1100 0000,中断屏蔽掩码

 

;The location of stacks
;0x30000000 = 768M 
;定义各模式下的堆栈常量,是一个递减栈,后边标上了各个栈的大小

UserStack       EQU       (_STACK_BASEADDRESS-0x3800) ; ~ 0x33ff4800 大小不定,跟堆大小相对应
                                                      ;毕竟是用户态栈
SVCStack       EQU       (_STACK_BASEADDRESS-0x2800)   ; ~ 0x33ff5800       4M
UndefStack     EQU       (_STACK_BASEADDRESS-0x2400)   ; ~ 0x33ff5c00       1M
AbortStack     EQU       (_STACK_BASEADDRESS-0x2000)   ; ~ 0x33ff6000       1M
IRQStack       EQU       (_STACK_BASEADDRESS-0x1000)   ; ~ 0x33ff7000       4M
FIQStack       EQU       (_STACK_BASEADDRESS-0x0)     ; ~ 0x33ff8000       4M

;处理器分为16位 32位两种工作状态 程序的编译器也是分16位和32两种编译方式 
;下面程序根据处理器工作状态确定编译器编译方式

;code16伪指令指示汇编编译器后面的指令为16位的thumb指令
;code32伪指令指示汇编编译器后面的指令为32位的arm指令

;Arm上电时处于ARM状态,故无论指令为ARM集或Thumb集,都先强制成ARM集,待init.s初始化完成后,再根据用
;户的编译配置转换成相应的指令模式。为此,定义变量THUMBCODE作为指示,跳转到main之前根据其值切换指令
;模式

;Check if tasm.exe(armasm -16 ...@ADS 1.0)is used.
;检测工作模式,根据CONFIG的数值,确定工作模式
;{CONFIG}应该来自于ADS环境,在本环境中设置是进入时在ARM环境下,没有设置ARM/THUMB混合环境
;关于是否设置混合编程,在环境设置选项里的ARM Assembler 选项下,由ATPCS -> ARM/Thumb interworking选
;项负责

;IF ELSE ENDIF指令
;[ 为 IF ; | 为 ELSE ; ] 为 ENDIF

        GBLL     THUMBCODE
        [{CONFIG} = 16        
THUMBCODE SETL   {TRUE}     ;如果设置了config,则允许thumb指令,
                                          ;但THUMBCODE为真并不表明以下就是thumb指令,只是允许
                CODE32           ;code32表示以下是arm指令,在处理器刚开始时,必须以arm模式运行
        |                         ;此处容易产生错觉,丢掉CODE32这一行
THUMBCODE SETL   {FALSE}
        ]
;-------------------------------------------------------------------------------------------------
;bx是带状态切换的跳转指令,跳转到Rm指定的地址执行程序,若Rm的位[0]为1,则跳转时自动将CPSR的标志T
;T置位,即把目标地址的代码解释为Thumb代码;若Rm的位[0]为0,则跳转时自动将CPSR中的标志T复位,即把
;目标地址的代码解释为ARM代码

;定义两个宏,宏的作用:子函数返回(无条件,有条件)。

              MACRO 
      MOV_PC_LR
              [ THUMBCODE               ;如果允许thumb指令,则需要根据最低位设置状态。
                  bx lr             ;跳转,附带状态切换
              |
                  mov pc,lr
              ]
                MEND

              MACRO
        MOVEQ_PC_LR   ;相等则跳转,相等与否由寄存器某些位确定,在此处,有其上一句的指令执行结果决定
              [ THUMBCODE
                    bxeq lr
              |
                    moveq pc,lr
              ]
              MEND

;MACRO和MEND伪指令用于宏定义,MACRO标识开始,MEND标识结束。用MACRO和MEND定义的一段代码,称为宏定义
;体,这样在程序中就可以通过宏指令多次调用该代码段。

;伪指令格式:
;MACRO
;{$label} macroname {$parameter} {$parameter} ...
              ;宏定义体
;MEND
 
;其中   $label 宏指令被展开时,label可被替换成相应的符号,通常为一个标号,
;在一个标号前使用$表示被汇编时将使用相应的值替代$后的符号。
;macroname 所定义的宏的名称
;$parameter 宏指令的参数,当宏指令被展开时将被替换成相应的值,类似于函数中的形式参数

;对于子程序代码较短,而需要传递的参数比较多的情况下,可以使用汇编技术。
;首先要用MACRO和MEND伪指令定义宏,包括宏定义体代码。在MACRO伪指令之后的第一行定义宏的原型,其中包
;含该宏定义的名称,及需要的参数。在汇编程序中可以通过该宏定义的名称来调用它,当源程序被汇编时,汇
;编编译器将展开每个宏调用,用宏定义体代替源程序中的宏定义的名称,并用实际的参数值代替宏定义时的形
;式参数

;-------------------------------------------------------------------------------------------------
;在arm中,用的是满递减堆栈:stmfd,ldmfd,如果用其他的方式,arm可能不能有效识别
;注意:满递减指的是在入栈时的操作方式,在出栈时则正好相反的次序

;例子:
;STMFD sp!,{R0-R7,LR}:(满递减:先减再放数值)sp根据数据个数,减小相应个数值的数据单位(一步到
;位),然后利用for循环语句,从当前sp位置,依次存储R0-R7,LR.即:sp处最后指向的是R0数据处

;LDMFD sp!,{R0-R7,LR}:复制一个变量为sp值,用该变量依次将数据存入R0-R7,LR,变量值增加,最后,变量指
;向下一个将要取的值,完成后sp获得该变量值;

;重点分析下面这个宏,它对中断处理函数的调用很重要
;确切说,这是宏函数,编译时对调用语句要做相应的展开
              MACRO
$HandlerLabel HANDLER $HandleLabel
$HandlerLabel                   ;标号
        sub     sp,sp,#4         ;留出一个空间,为了存放跳转地址给pc。
        stmfd   sp!,{r0}         ;把r0中的内容入栈,保存起来
        ldr     r0,=$HandleLabel ;这是一个伪指令,不是汇编指令,
                                ;目的:把$HandleLabel本身所在的地址给r0
        ldr     r0,[r0]           ;把$ HandleLabel所指向的内容(也就是中断程序的入口地址)放入r0
        str     r0,[sp,#4]       ;把入口地址放入刚才留出的一个空间里
        ldmfd   sp!,{r0,pc}       ;出栈的方式恢复r0原值和为pc设定新值(也就完成了到ISR的转跳)。
                                ;注:栈中r0内容在低地址
              MEND
;-------------------------------------------------------------------------------------------------
;下面几个变量是ads环境下自动设置的,可以见环境配置选项里:ARM Linker->Output下,RO Base,RW Base

;IMPORT 引用变量

        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 to zero initialise
        IMPORT   |Image$$ZI$$Limit| 

        IMPORT MMU_SetAsyncBusMode
        IMPORT MMU_SetFastBusMode ;想知道代码具体内容见cp15手册,并以cp15指令内容搜索2440a手册

        IMPORT   Main             ;The main entry of mon program
        IMPORT   RdNF2SDRAM       ;Copy Image from Nand Flash to SDRAM

;-------------------------------------------------------------------------------------------------
;AREA伪指令用于定义一个代码段或数据段,一个ARM源程序至少需要一个代码段,大的程序可以包含多个代码段
;及数据段
;格式:AREA sectionname {,attr} {,attr}...

        AREA     Init,CODE,READONLY
;-------------------------------------------------------------------------------------------------
;ENTRY伪指令用于指定程序的入口点
;一个程序(可以包含多个源文件)中至少要有一个ENTRY,可以有多个ENTRY,但一个源文件中最多只有一个
;ENTRY.

        ENTRY
;-------------------------------------------------------------------------------------------------
;EXPORT声明一个符号可以被其他文件引用,相当于声明了一个全局变量。GLOBAL与EXPORT相同    
;格式:EXPORT symbol{[WEAK]}   [WEAK]声明其他的同名符优先于本符号被引用

;导出符号__ENTRY

        EXPORT __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 thememory bus width.
        ;3)Thepseudo instruction,DCD can not be used here because the linker generates error.
   
;条件编译,在编译成机器码前就设定好大小端转换

;判断ENDIAN_CHANGE是否已定义,ASSERT 是断言伪指令,语法是:ASSERT + 逻辑表达式,def 是逻辑伪操作符,
;格式为::DEF:label,作用是:判断label是否定义过

        ASSERT :DEF:ENDIAN_CHANGE
        [ ENDIAN_CHANGE           ;在 option.inc 有定义。默认是FALSE,所以此句不会加入代码中
              ASSERT   :DEF:ENTRY_BUS_WIDTH       ;断言指令,检测是否定义该变量,若未定义,报错
              [ ENTRY_BUS_WIDTH=32               ;defined in option.inc
                      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                   ;本硬件用的是小端模式,这是第一个执行语句,
                                                ;直接跳转到复位指令处 0X00
        ]
;-------------------------------------------------------------------------------------------------
;这7个中断,每个中断都有固定的中断入口地址,它们位于代码的最前端,不允许另作他用
        b     HandlerUndef   ;handler for Undefined mode           0X04
        b     HandlerSWI     ;handlerfor SWI interrupt             0X08
        b     HandlerPabort ;handler for PAbort,指令预取中止     0X0C            
        b     HandlerDabort ;handler for DAbort,数据中止         0X10
        b     .             ;reserved 保留未用 注意小圆点         0X14
        b     HandlerIRQ     ;handlerfor IRQ interrupt             0X18
        b     HandlerFIQ     ;handlerfor FIQ interrupt             0X1C
;-------------------------------------------------------------------------------------------------
;@0x20
        b     EnterPWDN     ;Must be @0x20

;------------------------------------------------------------------------------------------------
;下面是改变大小端的程序,采用直接定义   <机器码>   的方式,为什么这么做就得问三星了
;反正我们程序里这段代码也不会去执行,不用去管它
;每一个汇编指令,都对应着一个二进制机器码,这里没有使用指令,直接用了机器码,含义未知

ChangeBigEndian
;@0x24
;对存储器控制寄存器操作,指定内存模式为Big-endian
;因为刚开始CPU都是按照32位总线的指令格式运行的,如果采用其他的话,CPU运行不了,必须转化
;但当系统初始化好以后,则CPU能自动识别       
        [ 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
       ]

;因为采用Big-endian模式,采用16位总线时,物理地址的高位和数据的地位对应
;所以指令的机器码也相应的高低对调
        [ 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 similarwith NOP and run well in both endian mode.
        DCD 0xffffffff
        DCD 0xffffffff
        DCD 0xffffffff
        DCD 0xffffffff
        b   ResetHandler                     ;设置成大端后,再次跳到复位指令处

;-------------------------------------------------------------------------------------------------
;本文件底部定义了一个数据区(在文件最后),34个字空间,存放相应中断服务程序的首地址。每个字空间都
;有一个标号,以Handle***命名。
;这是宏实例,在这里Handler***就是通过HANDLER这个宏和Handle***建立联系的.

;详细分析:
; Handle***      这是宏示例,也就是宏的调用指令,当编译时编译器会把宏调用指令展开
; Handler***      这是向量中断

 
;展开方式(举例):
;HandlerFIQ   HANDLER   HandleFIQ
;展开后变成:
; 标号 HandlerFIQ,由 " b       HandlerFIQ   "指令使用(见上,复位处)
;         sub     sp,sp,#4              
;留出一个空间,为了存放跳转地址给pc。见:str r0,[sp,#4] ,注意sp值并未改变
;         stmfd sp!,{r0}      
;把r0中的内容入栈,保存起来
;         ldr     r0,=HandleFIQ  
;HandleFIQ标号,在本文件最下方定义
;         ldr     r0,[r0]                
;把 HandleFIQ  所指向的内容(也就是中断程序的入口地址)放入r0
;         str     r0,[sp,#4]        
;把入口地址放入刚才留出的一个空间里 
;         ldmfd   sp!,{r0,pc}            
;出栈的方式恢复r0原值和为pc设定新值(也就完成了到ISR的转跳)。注:栈中r0内容在低地址
;后边的语句展开方式,同上。编译后,代码都展开放置

HandlerFIQ       HANDLER     HandleFIQ
HandlerIRQ       HANDLER     HandleIRQ
HandlerUndef     HANDLER     HandleUndef
HandlerSWI       HANDLER     HandleSWI
HandlerDabort     HANDLER     HandleDabort
HandlerPabort     HANDLER     HandlePabort

;-------------------------------------------------------------------------------------------------
;非向量中断总入口(需要自己判断中断类型,而不是直接跳转到相应程序)
;产生中断后,需要中断服务程序自己来判断,到底是哪个中断请求,根据的就是INTOFFSET寄存器中的偏移,再
;计算中断服务地址

IsrIRQ
        sub     sp,sp,#4           ;reserved for PC,预留返回指针的存储位置
        stmfd   sp!,{r8-r9}
        ldr     r9,=INTOFFSET     ;the interrupt request source offset
        ldr     r9,[r9]
        ldr     r8,=HandleEINT0   ;HandleEINT0 ,在本文件最下边定义的
        add     r8,r8,r9,lsl #2   ;r9中只是偏移单位的个数,需要*4变成具体字节偏移(相对于EINT0)
        ldr     r8,[r8]
        str     r8,[sp,#8]         ;pc值放在了高位置
        ldmfd   sp!,{r8-r9,pc}
;-------------------------------------------------------------------------------------------------
;LTORG用于声明一个文字池,在使用LDR伪指令时,要在适当的地方加入LTORG声明文字池,这样就会把要加载的
;数据保存在文字池内,再用ARM的《加载指令》读出数据。(若没有使用LTORG声明文字池,则汇编器会在程序
;末尾自动声明)

;LTORG 伪指令常放在无条件跳转指令之后,或者子程序返回指令之后,这样处理器就不会错误地将文字池中的
;数据当做指令来执行

;注:在此,文字池内存储的是INTOFFSET宏所代表的值:0x4a000014   。毕竟,当把指令编译成二进制代码时,
;arm指令(32位)不能既表示出指令内容,又表示出数据地址(32位)。估计在编译时,会被汇编成其他的加载
;指令,再编译成机器码

;LTORG 只要单独写出来就可以了,其他的交给编译器来做,而且它跟它下面的代码没有任何关系

        LTORG
;-------------------------------------------------------------------------------------------------
;=======
; ENTRY
;=======            

ResetHandler                
;关看门狗
        ldr   r0,=WTCON       ;watch dog disable   编译时就是 ldr r0,=53000000;伪指令有=号
        ldr   r1,=0x0         ;这些宏定义都位于2440addr.inc中。   区分:变量定义 && 宏定义
        str     r1,[r0]
;-------------------------------------------------------------------------------------------------
;屏蔽所有中断
        ldr   r0,=INTMSK       ;在 INTMSK 寄存器设置屏蔽所有中断
        ldr   r1,=0xffffffff   ;all interrupt disable   要理解子中断和中断之间的关系
        str   r1,[r0]

        ldr   r0,=INTSUBMSK   ; INTSUBMSK 子中断屏蔽寄存器,屏蔽所有子中断
        ldr   r1,=0x7fff       ;allsub interrupt disable
        str   r1,[r0]
;-------------------------------------------------------------------------------------------------
        [ {FALSE}
              ;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和时钟
;锁相环 PLL ,作用是将外部晶振的输入频率倍频到一个较高的频率

        ;To reduce PLL lock time, adjust the LOCKTIME register.
        ldr   r0,=LOCKTIME       ; LOCKTIME  锁定时间计数寄存器
        ldr   r1,=0xffffff          
        str   r1,[r0]
 
        [ PLL_ON_START                   ;defined inoption.inc {TRUE},选择要不要设置频率值
              ;Added for confirm clock divide. for 2440.
              ;Setting value Fclk:Hclk:Pclk
              ldr   r0,=CLKDIVN         ; 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]

        ;programhas not been copied, so use these directly

              [ CLKDIV_VAL>1           ; means Fclk:Hclk is not 1:1.
                                       ;Fclk为cpu的运行时钟, Hclk驱动 AHB总线设备(例如:SDRAM)
                      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
              ]

;在配置UPLLCON和MPLLCON寄存器时,必须先配置UPLLCON,然后再配置MPLLCON,而且两者之间要有7 nop的间
;隔。(这是2440文档明确要求的)

              ;Configure UPLL
              ldr   r0,=UPLLCON     ;UPLLCON: UPLL configuration register
              ldr   r1,=((U_MDIV<<12)+(U_PDIV<<4)+U_SDIV)   ;Fin = 12.0MHz, UCLK =48MHz,
                                                            ;对于usb来说必须是48MHz
              str     r1,[r0]
              nop             ; Caution: After UPLL setting, at least7-clocks delay must be inserted
                            ; for setting hardware be completed.
              nop
              nop
              nop
              nop
              nop
              nop

              ;Configure MPLL
              ldr   r0,=MPLLCON       ;MPLLCON: MPLL configuration register          
              ldr   r1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV)     ;Fin = 12.0MHz, FCLK= 400MHz
              str     r1,[r0]
        ]
;-------------------------------------------------------------------------------------------------

        ;Check if the boot is caused by the wake-up from SLEEP mode.
        ldr   r1,=GSTATUS2           ;这个寄存器数值表示哪个信号引起的复位动作产生
                                    ;检测 GSTATUS2[2]来判断是否是由 sleep 模式唤醒引起的电源开启。
        ldr   r0,[r1]
        tst     r0,#0x2

        ;Incase of the wake-up from SLEEP mode, go to SLEEP_WAKEUP handler.
        bne   WAKEUP_SLEEP
;-------------------------------------------------------------------------------------------------
;设置 总线宽度&等待状态控制寄存器

        EXPORT   StartPointAfterSleepWake Up

StartPointAfterSleepWake Up
      ;Set memory control registers
      ;ldr r0,=SMRDATA   ;(等效于下边的指令)
      adrl r0,SMRDATA   ;be careful!中等范围的地址读取伪指令,
                        ;用法类似于ldr(大范围地址读取)伪指令
      ldr   r1,=BWSCON   ;BWSCON Address 总线宽度&等待状态控制寄存器
      add   r2, r0, #52   ;End address of SMRDATA,共有13个寄存器地址(4字节)需要赋值,13*4=52字节

0
        ldr   r3, [r0], #4             ;这些都是后变址指令
        str   r3, [r1], #4
        cmp   r2, r0
        bne   % B0                     ;当<的时候,跳转到0标号处继续执行

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

; check if EIN0 button is pressed

        ldr   r0,=GPFCON   ;input,无上拉电阻
        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
        bne� % F1���               ; 当按键0没有被按下的时候,也就是不相等,则向下跳到1标号

; 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 ,这几条指令目的是:擦除sdram的所有数据
        ldr   r0,=0x30000000
0    
        stmia   r0!,{r1-r8}
        subs   r9,r9,#32
        bne   �% B0�

;Clear SDRAM End

1

        ;Initializestacks
        bl     InitStacks

;------------------------------------------------------------------------------------------------
;===========================================================

;OM0是flash选择开关,OM0接地时从nand 启动,悬空时(核心板上有上拉电阻)从nor启动
;OM1在核心板上,始终是接地,为0
;OM1:OM0取值:00 nandflash mode
;               01 16bit nor
;               10 32bit nor
;               11 test mode
;详见:s3c2440 用户手册 5.memory controller 一节

;ands指令,加s表示结果影响cpsr寄存器的值 

        ldr   r0, =BWSCON       ; BWSCON 总线宽度&等待控制寄存器
        ldr   r0, [r0]
        ands   r0, r0, #6         ;OM[1:0]!= 0, NOR FLash boot 
        bne   copy_proc_beg     ; do not read nand flash       
        adr   r0, ResetEntry     ;OM[1:0] == 0, NAND FLash boot
        cmp   r0, #0             ;ifuse Multi-ice,
        bne   copy_proc_beg     ;donot read nand flash for boot
        ;nop

;===========================================================
;把nand中的数据,拷贝到ram中

nand_boot_beg
        [ {TRUE}
              bl RdNF2SDRAM                      
        ]

        ldr   pc, =copy_proc_beg
;===========================================================
;这里的一段代码时对内存数据的初始化,涉及代码段,数据段,bss段等
;因对这里的变量设置等有异议,暂时未全面分析,但是基本原理想通,就是一个比较地址,复制数据的过程

copy_proc_beg
        adr     r0, ResetEntry
        ldr     r2, BaseOfROM
        cmp     r0, r2
        ldreq   r0, TopOfROM
        beq     InitRam  
        ldrr3,   TopOfROM
0    
        ldmia   r0!, {r4-r7}
        stmia   r2!, {r4-r7}
        cmp     r2, r3
        bcc     % B0���

        sub   r2, r2, r3
        sub   r0, r0, r2                      
   
InitRam  
        ldr   r2, BaseOfBSS
        ldr   r3, BaseOfZero      
0
        cmp   r2, r3
        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           ;gotocompiler address
2
;       [CLKDIV_VAL>1               ; meansFclk:Hclk is not 1:1.
;       bl     MMU_SetAsyncBusMode
;       |
;       blMMU_SetFastBusMode       ; default value.
;      


;===========================================================
        ; Setup IRQ handler
        ; 把中断服务函数的总入口地址,赋给HandleIRQ地址(文件最低端定义)

        ldr   r0,=HandleIRQ       ;Thisroutine is needed
        ldr   r1,=IsrIRQ         ;ifthere is not 'subs pc,lr,#4' at 0x18, 0x1c
        str   r1,[r0]

    [ :LNOT:THUMBCODE
              bl     Main       ;Do not use main() because ......
              b     .
    ]

    [ THUMBCODE               ;for start-up code for Thumbmode
              orr   lr,pc,#1
              bx     lr
              CODE16
              bl     Main       ;Do not use main() because ......
              b     .
              CODE32
    ]
;------------------------------------------------------------------------------------------------
;function initializing stacks
; 初始化栈空间(各个模式下的),为c函数运行做准备
InitStacks  

        ;Donot use DRAM,such as stmfd,ldmfd......
        ;SVCstackis initialized before
        ;Undertoolkit 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

        ;USERmode has not be initialized.

        mov pc,lr
        ;TheLR register will not be valid if the current mode is not SVC mode.

        LTORG

;------------------------------------------------------------------------------------------------
SMRDATA DATA  

;配置存储器的管理方式

; Memory configuration should be optimizedfor 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 forHCLK<=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           ; 按照4的倍数对齐
;------------------------------------------------------------------------------------------------ 
;Function for entering power down mode
; 1. SDRAM should be in self-refresh mode.
; 2. All interrupt should be maksked forSDRAM/DRAM self-refresh.
; 3. LCD controller should be disabled forSDRAM/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
        tst   r0,#0x8             ;SLEEP mode?
        bne   ENTER_SLEEP

ENTER_STOP
        ldr   r0,=REFRESH         ;REFRESH 是刷新控制寄存器
        ldr   r3,[r0]             ;r3=rREFRESH
        mov   r1, r3
        orr   r1, r1, #BIT_SELFREFRESH
        str   r1, [r0]             ;Enable SDRAMself-refresh

        mov   r1,#16                   ;wait untilself-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 isin effect.
        bne� % B0       ;2) Or wait here until theCPU&Peripherals will be turned-off
                        ;Entering SLEEP mode, only the reset bywake-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 SDRAMself-refresh

        mov   r1,#16               ;Wait untilself-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
        ;ReleaseSCLKn 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]

        ;Setmemory control registers
        ldr   r0,=SMRDATA       ;be careful!
        ldr   r1,=BWSCON       ;BWSCONAddress
        add   r2, r0, #52       ;Endaddress 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 SelfRefreshis released.
        bne� % B0�

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

        mov pc,r0

;=====================================================================
; Clock division test
; Assemble code, because VSYNC time is veryshort
;=====================================================================

        EXPORT CLKDIV124
        EXPORT CLKDIV144

CLKDIV124

        ldr   r0, = CLKDIVN     ;CLKDIVN   时钟分频器控制寄存器
        ldr   r1, = 0x3         ;0x3 = 1:2:4
        str   r1, [r0]
;       waituntil 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, #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]
;       waituntil 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

;------------------------------------------------------------------------------------------------ 
;定义数据段

;^ 标志等价于MAP伪指令
;MAP用于定义一个结构化的内存表首地址,此时内存表的位置计数器值,也变成该首地址值,就相当于在这个地
;址处操作

;#于FIELD同义,用于定义一个结构化的内存表的数据域,后边数字表示该数据占用的字节数

;Handle*** 在此就是一个标号,为了标示数据量

;用法:把对应的终端处理函数的首地址,放到这里的对应的预留空间处,当发生中断时,就能根据宏函数,直
;接跳转
 
        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 differentwith 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
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值