arm启动代码分析

 

/*文件名:2440init.s

;*功能:2440启动代码,实现硬件初始化及存储空间的映射等

;*设计者:enjoymylinux

;*设计时间:2010.2.10

;*版本:V1.0

;*参考程序:友善之臂启动代码及sumsang的bootloader源代码vivi

;*/

 

;//注意点:由于ARM是32位的,一般都按照32位的字对齐

 

;//64M SDRAM 内存空间分配状况

;//0x3000_0000   内存起始地址

;//                       >   supervivi下载程序的缓存空间   共16M

;//0x3100_0000

;//                       >     程序的运行空间

;//0x31ff_0000

;//                       >     堆栈空间        

;//0x33ff_8000

;//                                 预保留空间

;//0x33ff_ff00

;//                       >     中断向量表

;//0x3400_0000   内存结束地址

 

;//系统引导及启动过程

;//(1)硬件初始化        关闭看门狗,屏蔽所有中断

;//(2)时钟初始化        调整PLL锁相环到合适频率

;//(3)开启总线状态指示灯

;//(4)检测启动状态      boot启动还是外界唤醒恢复 

;//(5)初始化内存        设置SDRAM寄存器,擦除内存

;//(6)初始化FLASH       设置FLASH寄存器,检测启动物理位置

;//(7)拷贝代码到内存    NOR FLASH可以直接运行;NAND FLASH必须拷贝到RAM中才行

;//(8)跳转到Main去执行

 

 

 

 

;//包含头文件,注意:在汇编程序中头文件后缀名为.inc,而在C程序中后缀名为.h

;// option.inc   定义配置PLL及总线宽度寄存器位

;// memcfg.inc   定义存储器的寄存器的位定义

;// 2440addr.inc 2440各寄存器的地址

;//获取头文件,其中GET可用include来代替,两者可以互换

         GET option.inc

         GET memcfg.inc

         GET 2440addr.inc

 

BIT_SELFREFRESH EQU   (1<<22)

 

;//定义一些常量,EQU相当#define语句

;//处理器各工作模式定义,即CPSR中后五位CPSR[4:0]

USERMODE    EQU     0x10

FIQMODE     EQU       0x11

IRQMODE     EQU      0x12

SVCMODE     EQU      0x13

ABORTMODE   EQU    0x17

UNDEFMODE   EQU    0x1b

MODEMASK    EQU    0x1f

;//CPSR[7:5]

I_BIT      EQU      0x80  ;//中断位

F_BIT      EQU      0x40  ;//快速中断位

T_BIT      EQU      0x20  ;//指令模式状态位

NOINT      EQU         0xc0  ;//屏蔽中断位

 

;//定义stack的地址,其中_STACK_BASEADDRESS代表堆栈基地址

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 ~

 

;//检测是thumb指令集还是arm指令集

         GBLL    THUMBCODE                       ;//定义一个全局变量

         [ {CONFIG} = 16                         ;// #if(CONFIG=16)

THUMBCODE SETL  {TRUE}                      ;//    THUMBCODE=TRUE;

             CODE32  ;//说明此后代码为arm指令           

                 |                                                                                  ;// #else

THUMBCODE SETL  {FALSE}                     ;//    THUMBCODE=FALSE;

    ]

;//宏定义

                 MACRO       ;//宏定义开始

         MOV_PC_LR       ;//宏名称

                 [ THUMBCODE

             bx lr

                 |

             mov pc,lr

                 ]

         MEND           ;//宏定义结束

;//宏定义

                 MACRO

         MOVEQ_PC_LR

                 [ THUMBCODE

        bxeq lr

                  |

             moveq pc,lr

                 ]

         MEND

;//带参数的宏定义

;//宏定义,作用是当发生中断时,将中断服务程序的首地址装载到PC中

;//$HandlerLabel HANDLER(宏名称) $HandleLabel(宏的参数)

;//*********************************************************

                 MACRO

$HandlerLabel HANDLER $HandleLabel

 

$HandlerLabel

         sub   sp,sp,#4            ;//SP减4,为了存储跳转地址

         stmfd        sp!,{r0}          ;//将工作寄存器压入堆栈,

    ldr     r0,=$HandleLabel ;//装载HandleLable的地址到r0

         ldr     r0,[r0]                  ;//装载HandleLable的内容到r0,即服务程序的地址

         str     r0,[sp,#4]       ;//存储HandleLable的内容到堆栈

         ldmfd   sp!,{r0,pc}      ;//恢复r0的内容,并使PC跳转到HandleLable,即中断服务的首地址

         MEND

;//*********************************************************

;//声明、通知编译器标号在其他源文件中定义,但要在本文件中调用

;//一个ARM程序是由RO、RW、ZI三段组成(具体可见编译器生成的空间分配list文件)

;//RO代码段(只读)  RW 已经初始化的全局变量(读写) ZI未初始化的全局变量(零初始化)

;//这些地址是通过编译器的设定来确定的

         IMPORT  |Image$$RO$$Base|     ;//RO段起始地址

         IMPORT  |Image$$RO$$Limit|  ;//RO段结束地址加1

         IMPORT  |Image$$RW$$Base|   ;//RW段起始地址

         IMPORT  |Image$$RW$$Limit|  ;//RW段结束地址加1

         IMPORT  |Image$$ZI$$Base|   ;//ZI段起始地址

         IMPORT  |Image$$ZI$$Limit|  ;//ZI段结束地址加1

   

         IMPORT   MMU_SetAsyncBusMode

         IMPORT   MMU_SetFastBusMode  ;

 

         IMPORT  Main    ;//C代码的入口点

;//**********************************************************8

;//定义一个代码段,段名为Init,属性:代码,只读

         AREA    Init,CODE,READONLY

;//声明入口点,整个镜像从这个地方开始执行,一般来说一个文件里只能有一个

         ENTRY

;//声明一个全局标号,可以在其他文件中被引用    

         EXPORT    __ENTRY

__ENTRY     ;//__ENTRY标号

ResetEntry  ;//ResetEntry标号

;//指令 b :跳转指令,后加代码段标号,程序执行到此处时将会跳转到相应的代码段执行 

         ;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标识已经定义

        

         [ ENDIAN_CHANGE

             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

    ]

;/**********************************************************/

;//中断向量表vertor table

         b       HandlerUndef  ;handler for Undefined mode

         b       HandlerSWI          ;handler for SWI interrupt

         b       HandlerPabort          ;handler for PAbort

         b       HandlerDabort         ;handler for DAbort

         b              .          ;reserved

         b       HandlerIRQ          ;handler for IRQ interrupt

         b       HandlerFIQ           ;handler for FIQ interrupt

 

 

         b       EnterPWDN     ; Must be @0x20.

;/***********************************************************/

;//ChangeBigEndian标号

ChangeBigEndian

;// 符号[]相当于编译指令#if····#else      ····

;//通过编译指令,不同的总线宽度采取不同的存储单元分配措施

;//伪汇编指令DCD 用于分配一片连续的字节存储单元

         [ 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

;//宏展开,正确理解代码内容,代码要按规则编写,不要引起误解

;//代码标号相当于C语言中的函数,标号后的代码内容为函数的内容,即函数的具体实现过程             

HandlerFIQ   

           HANDLER HandleFIQ

HandlerIRQ   

           HANDLER HandleIRQ

HandlerUndef 

           HANDLER HandleUndef

HandlerSWI   

           HANDLER HandleSWI

HandlerDabort 

           HANDLER HandleDabort

HandlerPabort

      HANDLER HandlePabort

;//IsrIRQ代码段,实现中断服务程序的跳转

IsrIRQ

         sub   sp,sp,#4       ;reserved for PC

         stmfd        sp!,{r8-r9}

 

         ldr    r9,=INTOFFSET

         ldr    r9,[r9]

         ldr    r8,=HandleEINT0

         add  r8,r8,r9,lsl #2

         ldr    r8,[r8]

         str    r8,[sp,#8]

         ldmfd        sp!,{r8-r9,pc}

 

 

         LTORG

;/*************************************************************************************/

;//声明一个标号ResetHandler,当其他处引用此标号时,程序跳转到此处执行

;//ResetHandler代码段

ResetHandler

     ;//禁止看门狗

         ldr    r0,=WTCON       ;//把寄存器WTCON的地址装入R0,watch dog disable

         ldr    r1,=0x0                       ;//把0装入R1

         str    r1,[r0]          ;//把R1内的值赋给地址为R0的存储区域,即WTCON,这三条语句相当于 WTCON=0x0;

    ;//禁止所有中断

         ldr    r0,=INTMSK

         ldr    r1,=0xffffffff  ;all interrupt disable

         str    r1,[r0]         ;//这三条语句相当于 INTMSK=0xffffffff;

    ;//禁止所有次级中断

         ldr    r0,=INTSUBMSK

         ldr    r1,=0x7fff                   ;all sub interrupt disable

         str    r1,[r0]         ;//这三条语句相当于 INTSUBMSK=0x7ffff;

 

    //打开状态指示灯LED

         [ {TRUE}

         ;rGPFDAT = (rGPFDAT & ~(0xf<<4)) | ((~data & 0xf)<<4);

         ; Led_Display

         ldr    r0,=GPBCON

         ldr    r1,=0x00555555

         str    r1,[r0]                         ;//即GPCON=0x00555555;

        

         ldr    r0,=GPBDAT

         ldr    r1,=0x07fe

         str    r1,[r0]                         ;//即GPBDAT=0x07fe;

         ]

 

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

         ldr    r0,=LOCKTIME

         ldr    r1,=0xffffff

         str    r1,[r0]                         ;//即LOCKTIME=0xffffff;

;/************************************************************************************/

    [ PLL_ON_START

         ; 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]                                   ;//即CLKDIVN=CLKDIV_VAL;

 

         ;//协处理器操作,MMU和CACHE属于P15协处理器,ARM处理器共支持多达16个协处理器

 

 

         [ CLKDIV_VAL>1               ; means Fclk:Hclk is not 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

         ldr    r0,=UPLLCON

         ldr    r1,=((U_MDIV<<12)+(U_PDIV<<4)+U_SDIV) 

         str    r1,[r0]                         ;//即UPLLCON=((U_MDIV<<12)+(U_PDIV<<4)+U_SDIV)

         ;//nop指令,不进行任何操作,空指令

         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

         ldr    r0,=MPLLCON

         ldr    r1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV)  ;Fin=16.9344MHz

         str    r1,[r0]                                            ;//即MPLLCON=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV)

    ]

;/************************************************************************************/

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

         ldr    r1,=GSTATUS2

         ldr    r0,[r1]

         tst    r0,#0x2                                          ;//TST位测试指令,逻辑与操作,更新CPSR中相应的标志位

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

         bne  WAKEUP_SLEEP            ;//条件跳转指令,bne(b if not equal),beq(b if equal)

 

         EXPORT StartPointAfterSleepWakeUp  ;//声明外部可以引用

StartPointAfterSleepWakeUp

         ;//内存控制初始化

         ;//adrl 地址读取伪指令,谨慎使用,编译器将其分解成两条指令,若不能成功分解会报错

         ;//这段代码实现了8个BANK寄存器值的设定

        adrl  r0, SMRDATA  

         ldr    r1,=BWSCON   ;BWSCON Address

         add  r2, r0, #52        ;End address of SMRDATA

 

0

         ldr    r3, [r0], #4  ;//将地址为r0中的内容装载到r3,然后r0中的值加4,即指向下一个字

         str    r3, [r1], #4  ;//注意8个BANK控制寄存器的地址是靠着的

         cmp r2, r0                    ;//CMP指令会更新CPSR中的相应标志位,后面的指令根据此标志位来决定是否执行相应的操作

         bne  %B0           ;//如果不相等就向后跳转到标号0,类似一个循环,直到r0=r2

 

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

;;;;;;;;;;;;;       When EINT0 is pressed,  Clear SDRAM

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

;//check if EIN0 button is pressed

;//当EIN0发生时先清除SDRAM再初始化堆栈,若没有发生则跳过SDRAM的清除阶段,

;//直接去初始化堆栈

    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 在值为1时清零

         tst    r0,#0x1                       ;//按位与

         bne %F1      ;//如果not equal 向前跳转到标号1

        

        

 

;// Clear SDRAM Start

 

         ldr    r0,=GPFCON

         ldr    r1,=0x55aa

         str    r1,[r0]

        

         ldr    r0,=GPFDAT

         ldr    r1,=0x0

         str    r1,[r0]       ;LED=****

;//所有的寄存器都清零

         mov r1,#0

         mov r2,#0

         mov r3,#0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值