2440INIT.s详解

 

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

; 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语言的includeoption.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寄存器,它的后五位决定了处理器处于哪个模式下

 

USERMODE    EQU     0x10
FIQMODE     EQU     0x11
IRQMODE     EQU     0x12
SVCMODE     EQU     0x13
ABORTMODE   EQU     0x17
UNDEFMODE   EQU     0x1b
MODEMASK    EQU     0x1f
NOINT          EQU     0xc0     ;//禁止IRQ中断,FIQ中断

 

;//定义了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 ~

 

 

 

 

;Check if tasm.exe(armasm -16 ...@ADS 1.0) is used.

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

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

         [ {CONFIG} = 16            ;//如果发现时采用16位代码的话   

THUMBCODE SETL  {TRUE}      ;//THUMBCODE设置为TRUE

             CODE32               ;//把处理器重新设置成ARM模式

                 |                    ;//如果处理器现在就是ARM模式

THUMBCODE SETL  {FALSE}         ;//THUMBCODE设置为FALSE

]

 

                 MACRO     ;定义一个宏,一个根据THUMBCODEPC寄存器的值保存到LR的宏

         MOV_PC_LR    

                 [ THUMBCODE

             bx lr            ;ARM模式中要使用BX指令跳转到THUMB指令,并转换模式

                 |

             mov pc,lr           ;如果目标地址也是Arm指令的话就采用这种方式

                 ]

         MEND

 

                 MACRO

         MOVEQ_PC_LR

                 [ THUMBCODE

        bxeq lr          ;//r14

                 |

             moveq pc,lr

                 ]

         MEND

 

                   MACRO

$HandlerLabel  HANDLER  $HandleLabel

$HandlerLabel        //

         sub   sp,sp,#4   ;decrement sp(to store jump address)减少sp(用于存放跳转地址)

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

         ldr     r0,=$HandleLabel  ;Handlexxx的地址放入r0

         ldr     r0,[r0]         ;Handlexxx所指向的内容(也就是中断程序的入口)放入r0

         str     r0,[sp,#4]      ;把中断服务程序(ISR)压入栈

         ldmfd   sp!,{r0,pc}     ;用出栈的方式恢复r0的原值和为pc设定新值(也就完成了到ISR的跳转)

         MEND

IMPORT  |Image$$RO$$Base|     ;代码的开始地址

IMPORT  |Image$$RO$$Limit|  ; ROM code的结束地址(=ROM data 的开始地址)

IMPORT  |Image$$RW$$Base|   ; 要初始化的RAM的开始地址

IMPORT  |Image$$ZI$$Base|   ; area(需要清零的RAM区域)的开始地址

IMPORT  |Image$$ZI$$Limit|  ; area的结束地址

 

IMPORT   MMU_SetAsyncBusMode

IMPORT   MMU_SetFastBusMode

 

IMPORT  Main    ; The main entry of mon program

 

 

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

 

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 the memory bus width.

;3)The pseudo instruction,DCD can t 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=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                  ;跳转到Undefined mode程序入口

b       HandlerSWI               ;跳转到SWI中断程序入口

b       HandlerPabort                   ;跳转到PAbort(指令异常)程序入口

b       HandlerDabort         ;跳转到DAbort(数据异常)程序入口

b       .                 ;保留

b       HandlerIRQ      ;跳转到IRQ中断程序入口

b       HandlerFIQ       ;跳转到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

 

 

;根据上述宏定义,HandlerHandle之间的联系

HandlerFIQ      HANDLER  HandleFIQ

HandlerIRQ      HANDLER  HandleIRQ

HandlerUndef    HANDLER  HandleUndef

HandlerSWI      HANDLER  HandleSWI

HandlerDabort   HANDLER  HandleDabort

HandlerPabort   HANDLER  HandlePabort

 

 

;===================================================================================
;
第二次查表的,不懂
;===================================================================================
IsrIRQ
sub sp,sp,#4      
;PC寄存器保留
stmfd sp!,{r8-r9} ;r8-r9压入栈

ldr r9,=INTOFFSET    ;
INTOFFSET的地址装入r9
ldr r9,[r9]                    ;INTOFFSET的值装入r9
ldr r8,=HandleEINT0   ;这就是我们第二个中断向量表的入口的,先装入r8

add r8,r8,r9,lsl #2
ldr r8,[r8]                   
;;装入中断服务程序的入口
str r8,[sp,#8]              ;str不是入栈,只是把r0值放到sp+8这个地址上面

ldmfd sp!,{r8-r9,pc}    ;一个个出栈,跳转

 

LTORG               ;//声明文字池,因为用了ldr伪指令 ldr存储器到寄存器的数据传输指令

 

;=======

; ENTRY

;=======

ResetHandler

ldr    r0,=WTCON       ;1watch dog disable关开门狗

ldr    r1,=0x0

str    r1,[r0]

 

ldr    r0,=INTMSK

ldr    r1,=0xffffffff                     ;2all interrupt disable关中断

str    r1,[r0]

 

ldr    r0,=INTSUBMSK

ldr    r1,=0x7fff                                      ;3all sub interrupt disable关子中断

str    r1,[r0]

 

         ;4led显示

         [ {FALSE}

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

         ; Led_Display

         ldr    r0,=GPFCON

         ldr    r1,=0x5500

         str    r1,[r0]

         ldr    r0,=GPFDAT

         ldr    r1,=0x10

         str    r1,[r0]

         ]

 

;5.为了减少PLLlock time, 调整LOCKTIME寄存器.
ldr r0,=LOCKTIME
ldr r1,=0xffffff
str r1,[r0]

[ PLL_ON_START   
 ;6.下面就来设置PLL,你的板快不快就看这了!!
                                  ; Added for confirm clock divide. for 2440.
                    ;
设定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,
str r1,[r0] ; 4=1:4:4, 5=1:4:8, 6=1:3:3, 7=1:3:6.

 

[ 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]

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]

 ]

 

;检查是否从SLEEP模式中恢复
ldr r1,=GSTATUS2
ldr r0,[r1]
tst r0,#0x2
;
如果是从SLEEP模式中恢复, 转跳到SLEEP_WAKEUP.
bne WAKEUP_SLEEP

EXPORT StartPointAfterSleepWakeUp ;
导出符号StartPointAfterSleepWakeUp
StartPointAfterSleepWakeUp

;===============================================================================
;
设置内存控制器等寄存器的值,因为这些寄存器是连续排列的,所以采用如下办法对这些
;
寄存器进行连续设置.其中用到了SMRDATA的数据,这在代码后面有定义
;===============================================================================
;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<<1) ; bit clear
tst r0,#0x1
bne %F1 ;
如果没有按,就跳到后面的1标号处



; 这就是清零内存的代码

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}
subs r9,r9,#32
bne %B0

;到这就结束了.
1
bl InitStacks
;初始化堆栈
;bl Led_Test ;又是LED,注掉了

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

;// 判断是从nor启动还是从nand启动

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

ldr    r0, =BWSCON

ldr    r0, [r0]

ands          r0, r0, #6           ;OM[1:0] != 0, NOR FLash bootNOR Flash启动或直接在内存运行

bne  NORRoCopy              ;don t read nand flash不读取NAND FLASH

adr   r0, ResetEntry          ;OM[1:0] == 0,否则,为从NAND FLASH启动

cmp    r0, #0                                 ;再比较入口是否为0地址处,如果不是,表示主板设置了NAND启动,但这个程序由于其他原因,并没有从NAND启动,这种情况最有可能用了仿真器

bne  InitRamZero              ;don t read nand flash for boot

;nop

 

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

;//将程序从nandflash拷贝到sdram

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

nand_boot_beg

         bl      ClearSdram

         mov r5, #NFCONF               ;首先设定NAND的一些控制寄存器

         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           ;接着读取NANDID号,结果保存在r5

         mov r6, #0                                             ;r6设初值0

         ldr    r0, =0xecF1                                  ;期望的NAND ID

         cmp r5,    r0                                          ;进行比较

         beq  %F1                                                相等的话跳到下一个1标号处

;        ldr    r0, =0xecda

;        cmp r5, r0

         mov r6, #1                          ;Nandaddr(寻址周期 0:4  1:5)不相等,设置r61

1      

         bl      ReadNandStatus               ;读取NAND状态,结果放在r1

        

         mov r8, #0                                    ;r8设初值0,意义为页号

         ldr    r9, =ResetEntry                 ;r9设初值为初始化程序入口地址

         mov r10,#32                       ;+081010 feiling

;=========================================================================
;
注意,在这里使用的是ldr伪指令,而不是上面用的adr伪指令,它加载的是ResetEntry
;
的决对地址,也就是我们期望的RAM中的地址,在这里,它和|Image$$RO$$Base|一样
;
也就是说,我如我们编译程序时RO BASE指定的地址在RAM,而把生成的文件拷到
; NAND
里运行,ldr加载的r9的值还是定位在内存.
;=========================================================================

2
ands r0, r8, #0x1f             
;r80x1f(32)的整数倍-1,eq有效,ne无效
bne %F3                    
;这句的意思是对每个块(32)进行检错
mov r0, r8                  ;r8->r0
bl CheckBadBlk          ;检查NAND的坏区
cmp r0, #0                  ;比较r00
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                                      
;比较r0r2
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                         
;比较BaseOfBSSBaseOfZero
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]

; 跳到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
]

 

Function::

InitStacks

       ReadNandID

       ReadNandStatus

       WaitNandBusy

       CheckBadBlk

       WaitNandBusy

       ReadNandPage

       Led_Test


1把需要的文件加载进来

2定义处理器模式常数

3定义处理器各模式下堆栈地址常数

4判断THUMBARM模式     THUMBCODE

5第一次查表,实现中断向量的重定向   $HandlerLabel HANDLER $HandleLabel

6

IMPORT引入|Image$$RO$$Base|,|Image$$RO$$Limit|,|RW Base|,|ZI Base|,|ZI Limit|

ROM code开始与结束地址,要初始化的RAM开始地址,需要清零的RAM区域的开始地址与结束地址

7 IMPORT引入其他文件中实现的函数,MMU_SetAsyncBusMode MMU_SetFastBusMode, Main

8 AREA Init,CODE,READONLY //init的代码段

9ENTRY

ResetEntry

10判断大小端

11跳转程序入口

12改变大小端的程序

13HandlerFIQ HANDLER HandleFIQ

14第二次查表 判断是什么中断

15 ENTRY复位

ResetHandler

i关看门狗

ii关中断

iii关子中断

iiii点灯

vPLL

vi MMU_SetAsyncBusMode

MMU_SetFastBusMode

viiUPLL

viiiMPLL

iv 检查是否从SLEEP模式中恢复

       WAKEUP_SLEEP

16设置内存控制器等寄存器的值

       SMRDATA

17清零内存的代码

18初始化堆栈InitStacks

19 NOR NAND拷贝的依据

20 NAND读代码到RAM

       设定NAND控制寄存器

       ReadNandID      

       ReadNandStatus

       CheckBadBlk

       ReadNandPage

21NOR FLASH拷贝

22 用二级向量表的中断例程安装到一级向量表里

23 跳到main函数处

WaitNandBusy

24时钟测试

25可读写数据段

AREA RamData ,DATA,READWRITE

 参考:http://www.cnblogs.com/dekun_1986/archive/2010/08/07/1790601.html

           http://hi.baidu.com/blue_belief/blog/item/ddee3b7c9a222d340dd7daca.html

         《ARM体系结构与编程》

          ARM汇编设计http://www.cnblogs.com/hoys/archive/2010/12/01/1892578.html

   伪指令MARCO http://www.360doc.com/content/10/1101/14/3038654_65704006.shtml

           bootloader启动流程http://hi.baidu.com/blue_belief/blog/item/db375aca04b1811b7e3e6f27.html

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值