;=======
; ENTRY(CPU复位的入口)
;=======
ResetHandler
ldr r0,=WTCON ;关看门狗
ldr r1,=0x0
str r1,[r0]
ldr r0,=INTMSK
ldr r1,=0xffffffff ;关中断
str r1,[r0]
ldr r0,=INTSUBMSK
ldr r1,=0x7fff ;关子中断
str r1,[r0]
[ {TRUE}
;rGPFDAT = (rGPFDAT & ~(0xf<<4)) | ((~data & 0xf)<<4);
;点led灯
ldr r0,=GPBCON
ldr r1,=0x00555555
str r1,[r0]
ldr r0,=GPBDAT
ldr r1,=0x07fe
str r1,[r0]
]
;To reduce PLL lock time, adjust the LOCKTIME register.
ldr r0,=LOCKTIME
ldr r1,=0xffffff
str r1,[r0]
[ 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]
; 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
; |
; bl MMU_SetFastBusMode ; default value.
; ]
;===============================================================
;MMU_SetAsyncBusMode 和 MMU_SetFastBusMode 都在4K代码以上(三星就提供4K的内部SRAM),
;如果你想你编译出来的程序能在NAND上运行的话,就不能在这调用这两函数了.
;如果你不要求的话,你就可以直接调用
;下面的代码就是实现和上面两函数一样的功能.
;利用的协处理器的命令实现了对总线模式的设置
;===============================================================
;program has not been copied, so use these directly
[ 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.配置 MPLL 一定要使最后的频率为16.9344MHz,不然你甭想用USB接口了,
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]
]
;Check if the boot is caused by the wake-up from SLEEP mode.
ldr r1,=GSTATUS2
ldr r0,[r1]
tst r0,#0x2 ; Check GSTATUS2[2] in order to know whether or not
;the power-up is caused by the wake-up from SLEEP mode.
bne WAKEUP_SLEEP ;如果是,则跳转到WAKEUP_SLEEP
EXPORT StartPointAfterSleepWakeUp ;定义外部的StartPointAfterSleepWakeUp
StartPointAfterSleepWakeUp
;===============================================================
;设置存储器控制寄存器,此段代码把13个存储控制器的内容批量的读取到了对应的特殊功能寄存器中
;首先是有一个数据区SMRDATA,在程序的后面有定义,这个数据区给13个寄存器分配52字节的地址空间。在下面
;的代码中,r0是这个数据区的起始地址,r2是数据区的结束地址,r1是寄存器的起始地址。这样,用一个判断语句
; cmp r2, r0
; bne %B0,就可以把内存中的数据赋给这13个存储控制寄存器了。
;===============================================================
;ldr r0,=SMRDATA
adrl r0, SMRDATA ;be careful!
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
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;; When EINT0 is pressed, Clear SDRAM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; check if EIN0 button is pressed
ldr r0,=GPFCON
ldr r1,=0x0
str r1,[r0] ;置F(0:15)input
ldr r0,=GPFUP
ldr r1,=0xff
str r1,[r0] ;不使用上拉电阻
ldr r1,=GPFDAT ; GPFDAT=0xff
ldr r0,[r1]
bic r0,r0,#(0x1e<<1) ; bit clear
tst r0,#0x1
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
;64MB的SDRAM,0x30000000—0x34000000
ldr r9,=0x4000000
ldr r0,=0x30000000
0
stmia r0!,{r1-r8}
subs r9,r9,#32
bne %B0
;Clear SDRAM End
1
;Initialize stacks
bl InitStacks 初始化堆栈
;===========================================================
这段程序能在nor nand flash 运行,也可以在内存中运行。在nor nand flash运行,需要拷贝数据;
;===========================================================
ldr r0, =BWSCON
ldr r0, [r0]
ands r0, r0, #6 ;OM[1:0] != 0, NOR FLash 或者内存启动
bne copy_proc_beg ;不要读取 nand flash
adr r0, ResetEntry ;OM[1:0] == 0, NAND FLash 启动
cmp r0, #0 ;再比较入口是否为0地址处,如果不是则用了仿真器
bne copy_proc_beg ;用仿真器的情况也不要用 nand flash启动
;nop
;===========================================================
nand_boot_beg ;这一段代码完成从NAND读代码到RAM
mov r5, #NFCONF ;设置NAND FLASH的控制寄存器
;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] ;设置NFCONT,使能NAND FLASH
;控制;禁止片选;初始化ECC等,具体查看手册
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
;===============================================================
; 注意,在这里使用的是ldr伪指令,而不是上面用的adr伪指令,它加载的是ResetEntry
; 的绝对地址,也就是我们期望的RAM中的地址,在这里,它和|Image$$RO$$Base|
;一样 也就是说,我如我们编译程序时RO BASE指定的地址在RAM里,而把生成的
;文件拷到 NAND里运行,由ldr加载的r9的值还是定位在内存.
;Ldr与ADR的区别http://blog.163.com/ncx995/blog/static/28003127200851085043536/
;===============================================================
2
ands r0, r8, #0x1f ;凡r8为0x1f(32)的整数倍,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, #8192 ;比较是否读完8192页
bcc %B2 ;如果r8小于8192(没读完),就返回前面的标号2处
mov r5, #NFCONF ;设置NAND FLASH 控制寄存器
ldr r0, [r5, #4]
bic r0, r0, #1
str r0, [r5, #4] ; NAND flash controller enable
ldr pc, =copy_proc_beg ;copy nand flash 到ram
;===========================================================
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