mini2440之2440init.s启动文件分析
2011年05月18日
;=========================================
; 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语言的include,option.inc文件内定义了一些全局变量,memcfg.inc文件内定义了关于内存bank的符号和数字常量,2440addr.inc文件内定义了用于汇编的s3c2440寄存器变量和地址
GET option.inc
GET memcfg.inc
GET 2440addr.inc
BIT_SELFREFRESH EQU (1内存
AREA Init,CODE,READONLY ;//这表明下面的是一个名为Init的代码段
ENTRY ;//定义程序的入口(调试用)
EXPORT __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 ;//判断模式改变是否定义过(ASSERT是伪指令,:DEF:lable判断lable是否定义过了)
[ 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 ;handler for Undefined mode //转跳到Undefined mode程序入口
b HandlerSWI ;handler for SWI interrupt //转跳到SWI 中断程序入口
b HandlerPabort ;handler for PAbort //转跳到PAbort(指令异常)程序入口
b HandlerDabort ;handler for DAbort //转跳到DAbort(数据异常)程序入口
b . ;reserved //保留
b HandlerIRQ ;handler for IRQ interrupt //转跳到IRQ 中断程序入口
b HandlerFIQ ;handler for FIQ interrupt //转跳到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
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 ;reserved for PC //预留一个值来保存 服务子程序的地址
stmfd sp!,{r8-r9} ; //将r8 r9入栈
ldr r9,=INTOFFSET ;//偏移量
ldr r9,[r9]
ldr r8,=HandleEINT0
add r8,r8,r9,lsl #2 ;//将INTOFFSET和HandleEINT0结合起来
ldr r8,[r8] ;//装入中断服务程序的入口
str r8,[sp,#8] ;//str不是入栈,只是把r0值放到 sp+8 这个地址上面
ldmfd sp!,{r8-r9,pc} ;//一个个出栈
LTORG ;//声明文字池,因为我们用了ldr伪指令
;=======
; ENTRYY//(好了,我们的CPU要在这复位了.)
;=======
ResetHandler
ldr r0,=WTCON ;watch dog disable //关开门狗
ldr r1,=0x0
str r1,[r0]
ldr r0,=INTMSK
ldr r1,=0xffffffff ;all interrupt disable //关中断
str r1,[r0]
ldr r0,=INTSUBMSK
ldr r1,=0x7fff ;all sub interrupt disable //关子中断
str r1,[r0]
[ {TRUE} ;//点LED灯
;rGPFDAT = (rGPFDAT & ~(0xf1 ; means Fclk:Hclk is not 1:1.
; bl MMU_SetAsyncBusMode ;//MMU_SetAsyncBusMode在4k以后,所以现在还不能调用
; |
; bl MMU_SetFastBusMode ; default value.
; ]
;program has not been copied, so use these directly
[ CLKDIV_VAL>1 ; means Fclk:Hclk is not 1: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
]
;Configure UPLL //配置 UPLL
ldr r0,=UPLLCON
ldr r1,=((U_MDIV内存控制器等寄存器的值,因为这些寄存器是连续排列的,所以采用如下办法对这些
;//寄存器进行连续设置.其中用到了SMRDATA的数据,这在代码后面有定义
;Set memory control registers //给adram的寄存器赋值
;ldr r0,=SMRDATA
adrl r0, SMRDATA ;be careful! //得到SMRDATA的首地址
ldr r1,=BWSCON ;BWSCON Address //得到BWSCON的地址
add r2, r0, #52 ;End address of SMRDATA
;//用于把(存储器总线宽度&等待控制寄存器BWSCON,Bank控制寄存器BANKCON0-5) 赋值
0
ldr r3, [r0], #4
str r3, [r1], #4
cmp r2, r0
bne %B0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;; When EINT0 is pressed, Clear SDRAM
;//如果 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内存的代码
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} ;//stm出栈,把r1-r8的值赋到r0上,然后r0+4
subs r9,r9,#32
bne %B0
;Clear SDRAM End
1
;Initialize stacks//初始化各种处理器模式下的堆栈
bl InitStacks
;===========================================================
ldr r0, =BWSCON
ldr r0, [r0]
ands r0, r0, #6 ;OM[1:0] != 0, NOR FLash boot //从norflash启动就跳转到copy_proc_beg
bne copy_proc_beg ;do not read nand flash
adr r0, ResetEntry ;OM[1:0] == 0, NAND FLash boot//从nandflash启动
cmp r0, #0
;if use Multi-ice //在进行比较,是否入口地址是在0处
;//如果不是,则表示主板设置了从NAND启动,但这个程序由于其它原因, 并没有从NAND从启动,这种情况最有可能的原因就是用仿真器.
bne copy_proc_beg ;do not read nand flash for boot//仿真器也不需要在NAND FLASH启动
;nop
;===========================================================
;//bl 带返回的跳转指令
;//l 决定是否保存返回地址。当有l时,当前的PC寄存器的值将保存到lr寄存器中
;// 当无l时,指令仅执行跳转,当前的PC寄存器的值将不会保存到lr寄存器中
nand_boot_beg
[ {TRUE}
bl CopyProgramFromNand //把nandflash中的程序全部copy到sdram中,从???
|
mov r5, #NFCONF ;//首先设定NAND的一些控制寄存器
;set timing value
ldr r0, =(7运行,由ldr加载的r9的值还是定位在内存. ???
2
ands r0, r8, #0x1f;//r8为0x1f(32)的整数倍-1,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, #5120 ;//比较是否读完5120页即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 ;//ldr指令 加载了绝对地址,现在pc指向的是sdram中的copy_proc_beg,程序在sdram上运行了
;===========================================================
copy_proc_beg
adr r0, ResetEntry ;//程序在sdram上运行了,该取值方式 取到的地址就是相对于pc的偏移地址了也就是0x30000000
;//这里应该注意,使用的是adr,而不是ldr。使用ldr说明ResetEntry是个绝对地址,这个地址是在程序链接的时候
;//确定的。而使用adr则说明ResetEntry的地址和当前代码的执行位置有关,它是一个相对的地址。比如这段代码
;//在stepingstone里面执行,那么ResetEntry的地址就是零。如果在sdRAM里执行,那么ResetEntry就应是sdRAM的一个
;//地址,应该等于RO base 为0x30000000。
ldr r2, BaseOfROM ;//0x30000000 ldr 是把BaseOfROM(一地址)中的值放到r2中
cmp r0, r2
ldreq r0, TopOfROM ;//相等就跳转 相等说明程序是从nandflash或者sdram中运行的。不相等是从norflash运行的
beq InitRam
ldr r3, TopOfROM ;//以下代码是针对代码在NOR FLASH时的拷贝方法,这个程序 从norflash也要copy程序
0
ldmia r0!, {r4-r7} ;//搬运代码
stmia r2!, {r4-r7}
cmp r2, r3
bcc %B0
sub r2, r2, r3 ;//上面拷贝时每次拷贝4个双字(32位)大小,但是RO段大小不一定是4的整数倍,所以可能多拷贝了几个双字大小,r2-r3得到多拷贝的个数
sub r0, r0, r2 ;//r0-(r2-r3)可以使r0指向在boot nand中RO的结束地址
InitRam //复制SW区域
ldr r2, BaseOfBSS
ldr r3, BaseOfZero
0
cmp r2, r3;//比较BaseOfBSS和BaseOfZero
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 ;goto compiler address
2
; [ CLKDIV_VAL>1 ; means Fclk:Hclk is not 1:1.
; bl MMU_SetAsyncBusMode
; |
; bl MMU_SetFastBusMode ; default value.
; ]
; bl Led_Test
;===========================================================
; //进入C语言前的最后一步了,就是把我们用说查二级向量表的中断例程安装到一级向量表(异常向量表)里.
; Setup IRQ handler
ldr r0,=HandleIRQ ;This routine is needed
ldr r1,=IsrIRQ ;if there is not 'subs pc,lr,#4' at 0x18, 0x1c
str r1,[r0] //把IsrIRQ的地址放到HandleIRQ中
; ;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
[ :LNOT:THUMBCODE
bl Main ;Do not use main() because ......
;ldr pc, =Main ;
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 initializing stacks
InitStacks ;//-----------------------7个模式堆栈初始化
;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 ;//cpsr为状态寄存器
bic r0,r0,#MODEMASK ;//清空低5位的数据
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.
;===========================================================
[ {TRUE}
|
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 ;//这是一块连续的地址,用于存放 存储器总线宽度&等待控制寄存器BWSCON,Bank控制寄存器BANKCON0-5
; 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 HCLKSCLK, SCLK1:0->SCLK, SCKE:0->=SCKE.
str r0,[r1]
;Set memory control registers
ldr r0,=SMRDATA ;be careful! //得到SMRDATA的首地址
ldr r1,=BWSCON ;BWSCON Address //得到BWSCON的地址
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 ;//SDRAM刷新控制寄存器
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]
; wait until 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
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 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
2011年05月18日
;=========================================
; 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语言的include,option.inc文件内定义了一些全局变量,memcfg.inc文件内定义了关于内存bank的符号和数字常量,2440addr.inc文件内定义了用于汇编的s3c2440寄存器变量和地址
GET option.inc
GET memcfg.inc
GET 2440addr.inc
BIT_SELFREFRESH EQU (1内存
AREA Init,CODE,READONLY ;//这表明下面的是一个名为Init的代码段
ENTRY ;//定义程序的入口(调试用)
EXPORT __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 ;//判断模式改变是否定义过(ASSERT是伪指令,:DEF:lable判断lable是否定义过了)
[ 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 ;handler for Undefined mode //转跳到Undefined mode程序入口
b HandlerSWI ;handler for SWI interrupt //转跳到SWI 中断程序入口
b HandlerPabort ;handler for PAbort //转跳到PAbort(指令异常)程序入口
b HandlerDabort ;handler for DAbort //转跳到DAbort(数据异常)程序入口
b . ;reserved //保留
b HandlerIRQ ;handler for IRQ interrupt //转跳到IRQ 中断程序入口
b HandlerFIQ ;handler for FIQ interrupt //转跳到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
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 ;reserved for PC //预留一个值来保存 服务子程序的地址
stmfd sp!,{r8-r9} ; //将r8 r9入栈
ldr r9,=INTOFFSET ;//偏移量
ldr r9,[r9]
ldr r8,=HandleEINT0
add r8,r8,r9,lsl #2 ;//将INTOFFSET和HandleEINT0结合起来
ldr r8,[r8] ;//装入中断服务程序的入口
str r8,[sp,#8] ;//str不是入栈,只是把r0值放到 sp+8 这个地址上面
ldmfd sp!,{r8-r9,pc} ;//一个个出栈
LTORG ;//声明文字池,因为我们用了ldr伪指令
;=======
; ENTRYY//(好了,我们的CPU要在这复位了.)
;=======
ResetHandler
ldr r0,=WTCON ;watch dog disable //关开门狗
ldr r1,=0x0
str r1,[r0]
ldr r0,=INTMSK
ldr r1,=0xffffffff ;all interrupt disable //关中断
str r1,[r0]
ldr r0,=INTSUBMSK
ldr r1,=0x7fff ;all sub interrupt disable //关子中断
str r1,[r0]
[ {TRUE} ;//点LED灯
;rGPFDAT = (rGPFDAT & ~(0xf1 ; means Fclk:Hclk is not 1:1.
; bl MMU_SetAsyncBusMode ;//MMU_SetAsyncBusMode在4k以后,所以现在还不能调用
; |
; bl MMU_SetFastBusMode ; default value.
; ]
;program has not been copied, so use these directly
[ CLKDIV_VAL>1 ; means Fclk:Hclk is not 1: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
]
;Configure UPLL //配置 UPLL
ldr r0,=UPLLCON
ldr r1,=((U_MDIV内存控制器等寄存器的值,因为这些寄存器是连续排列的,所以采用如下办法对这些
;//寄存器进行连续设置.其中用到了SMRDATA的数据,这在代码后面有定义
;Set memory control registers //给adram的寄存器赋值
;ldr r0,=SMRDATA
adrl r0, SMRDATA ;be careful! //得到SMRDATA的首地址
ldr r1,=BWSCON ;BWSCON Address //得到BWSCON的地址
add r2, r0, #52 ;End address of SMRDATA
;//用于把(存储器总线宽度&等待控制寄存器BWSCON,Bank控制寄存器BANKCON0-5) 赋值
0
ldr r3, [r0], #4
str r3, [r1], #4
cmp r2, r0
bne %B0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;; When EINT0 is pressed, Clear SDRAM
;//如果 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内存的代码
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} ;//stm出栈,把r1-r8的值赋到r0上,然后r0+4
subs r9,r9,#32
bne %B0
;Clear SDRAM End
1
;Initialize stacks//初始化各种处理器模式下的堆栈
bl InitStacks
;===========================================================
ldr r0, =BWSCON
ldr r0, [r0]
ands r0, r0, #6 ;OM[1:0] != 0, NOR FLash boot //从norflash启动就跳转到copy_proc_beg
bne copy_proc_beg ;do not read nand flash
adr r0, ResetEntry ;OM[1:0] == 0, NAND FLash boot//从nandflash启动
cmp r0, #0
;if use Multi-ice //在进行比较,是否入口地址是在0处
;//如果不是,则表示主板设置了从NAND启动,但这个程序由于其它原因, 并没有从NAND从启动,这种情况最有可能的原因就是用仿真器.
bne copy_proc_beg ;do not read nand flash for boot//仿真器也不需要在NAND FLASH启动
;nop
;===========================================================
;//bl 带返回的跳转指令
;//l 决定是否保存返回地址。当有l时,当前的PC寄存器的值将保存到lr寄存器中
;// 当无l时,指令仅执行跳转,当前的PC寄存器的值将不会保存到lr寄存器中
nand_boot_beg
[ {TRUE}
bl CopyProgramFromNand //把nandflash中的程序全部copy到sdram中,从???
|
mov r5, #NFCONF ;//首先设定NAND的一些控制寄存器
;set timing value
ldr r0, =(7运行,由ldr加载的r9的值还是定位在内存. ???
2
ands r0, r8, #0x1f;//r8为0x1f(32)的整数倍-1,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, #5120 ;//比较是否读完5120页即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 ;//ldr指令 加载了绝对地址,现在pc指向的是sdram中的copy_proc_beg,程序在sdram上运行了
;===========================================================
copy_proc_beg
adr r0, ResetEntry ;//程序在sdram上运行了,该取值方式 取到的地址就是相对于pc的偏移地址了也就是0x30000000
;//这里应该注意,使用的是adr,而不是ldr。使用ldr说明ResetEntry是个绝对地址,这个地址是在程序链接的时候
;//确定的。而使用adr则说明ResetEntry的地址和当前代码的执行位置有关,它是一个相对的地址。比如这段代码
;//在stepingstone里面执行,那么ResetEntry的地址就是零。如果在sdRAM里执行,那么ResetEntry就应是sdRAM的一个
;//地址,应该等于RO base 为0x30000000。
ldr r2, BaseOfROM ;//0x30000000 ldr 是把BaseOfROM(一地址)中的值放到r2中
cmp r0, r2
ldreq r0, TopOfROM ;//相等就跳转 相等说明程序是从nandflash或者sdram中运行的。不相等是从norflash运行的
beq InitRam
ldr r3, TopOfROM ;//以下代码是针对代码在NOR FLASH时的拷贝方法,这个程序 从norflash也要copy程序
0
ldmia r0!, {r4-r7} ;//搬运代码
stmia r2!, {r4-r7}
cmp r2, r3
bcc %B0
sub r2, r2, r3 ;//上面拷贝时每次拷贝4个双字(32位)大小,但是RO段大小不一定是4的整数倍,所以可能多拷贝了几个双字大小,r2-r3得到多拷贝的个数
sub r0, r0, r2 ;//r0-(r2-r3)可以使r0指向在boot nand中RO的结束地址
InitRam //复制SW区域
ldr r2, BaseOfBSS
ldr r3, BaseOfZero
0
cmp r2, r3;//比较BaseOfBSS和BaseOfZero
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 ;goto compiler address
2
; [ CLKDIV_VAL>1 ; means Fclk:Hclk is not 1:1.
; bl MMU_SetAsyncBusMode
; |
; bl MMU_SetFastBusMode ; default value.
; ]
; bl Led_Test
;===========================================================
; //进入C语言前的最后一步了,就是把我们用说查二级向量表的中断例程安装到一级向量表(异常向量表)里.
; Setup IRQ handler
ldr r0,=HandleIRQ ;This routine is needed
ldr r1,=IsrIRQ ;if there is not 'subs pc,lr,#4' at 0x18, 0x1c
str r1,[r0] //把IsrIRQ的地址放到HandleIRQ中
; ;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
[ :LNOT:THUMBCODE
bl Main ;Do not use main() because ......
;ldr pc, =Main ;
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 initializing stacks
InitStacks ;//-----------------------7个模式堆栈初始化
;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 ;//cpsr为状态寄存器
bic r0,r0,#MODEMASK ;//清空低5位的数据
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.
;===========================================================
[ {TRUE}
|
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 ;//这是一块连续的地址,用于存放 存储器总线宽度&等待控制寄存器BWSCON,Bank控制寄存器BANKCON0-5
; 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 HCLKSCLK, SCLK1:0->SCLK, SCKE:0->=SCKE.
str r0,[r1]
;Set memory control registers
ldr r0,=SMRDATA ;be careful! //得到SMRDATA的首地址
ldr r1,=BWSCON ;BWSCON Address //得到BWSCON的地址
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 ;//SDRAM刷新控制寄存器
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]
; wait until 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
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 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