mini2440开发板中启动代码2440INIT.S分析
2011-09-14 20:31
489 查看
声明:文章转自别处,非本人自创
http://hi.baidu.com/haijie0707/blog/item/6ff41a3bff7ccef93a87ced5.html ;========================================= ;NAME:2440INIT.S ;DESC:Cstartupcodes ;Configurememory,ISR,stacks ;InitializeC-variables ;HISTORY: ;2002.02.25:kwtark:ver0.0 ;2002.03.20:purnnamu:AddsomesfortestingSTOP,Sleepmode ;2003.03.14:DonGo:Modifiedfor2440. ;========================================= ;首先,启动代码定义了一些常量 ;汇编不能使用include包含头文件,所有用Get ;汇编也不认识*.h文件,所有只能用*.inc GEToption.inc;定义芯片相关的配置 GETmemcfg.inc;定义存储器配置 GET2440addr.inc;定义了寄存器符号 ;REFRESH寄存器[22]bit:0-autorefresh;1-selfrefresh ;用于节电模式中,SDRAM自动刷新 BIT_SELFREFRESHEQU(1<<22)
;处理器模式常量:CPSR寄存器的后5位决定目前处理器模式M[4:0]
USERMODEEQU0x10
FIQMODEEQU0x11
IRQMODEEQU0x12
SVCMODEEQU0x13
ABORTMODEEQU0x17
UNDEFMODEEQU0x1b
MODEMASKEQU0x1f
NOINTEQU0xc0
;定义处理器各模式下堆栈地址常量
;_STACK_BASEADDRESS定义在option.inc中
UserStackEQU(_STACK_BASEADDRESS-0x3800);0x33ff4800~
SVCStackEQU(_STACK_BASEADDRESS-0x2800);0x33ff5800~
UndefStackEQU(_STACK_BASEADDRESS-0x2400);0x33ff5c00~
AbortStackEQU(_STACK_BASEADDRESS-0x2000);0x33ff6000~
IRQStackEQU(_STACK_BASEADDRESS-0x1000);0x33ff7000~
FIQStackEQU(_STACK_BASEADDRESS-0x0);0x33ff8000~
;arm处理器有两种工作状态1.arm:32位这种工作状态下执行字对准的arm指令2.Thumb:16位这种工状;态执行半字对准的Thumb指令
;因为处理器分为16位32位两种工作状态程序的编译器也是分16位和32两种编译方式所以下面的程序用
;于根据处理器工作状态确定编译器编译方式
;code16伪指令指示汇编编译器后面的指令为16位的thumb指令
;code32伪指令指示汇编编译器后面的指令为32位的arm指令
;
;Arm上电时处于ARM状态,故无论指令为ARM集或Thumb集,都先强制成ARM集,待init.s初始化完成后
;再根据用户的编译配置转换成相应的指令模式。为此,定义变量THUMBCODE作为指示,跳转到main之前
;根据其值切换指令模式
;
;这段是为了统一目前的处理器工作状态和软件编译方式(16位编译环境使用tasm.exe编译
;检查在tasm.exe里是否设置了采用THUMB(16位)代码(armasm-16...@ADS1.0)
GBLLTHUMBCODE;定义THUMBCODE全局变量
[{CONFIG}=16
;如果发现是在用16位代码的话(编译选项中指定使用thumb指令
THUMBCODESETL{TRUE};把THUMBCODE设置为TURE
CODE32;把处理器从新设置成为ARM模式
|;如果处理器现在就是ARM模式
THUMBCODESETL{FALSE};把THUMBCODE设置为FALSE就行了
]
MACRO
;一个根据THUMBCODE把PC寄存的值保存到LR的宏,宏MOV_PC_LR
MOV_PC_LR[THUMBCODEbxlr;([表示if)
;在ARM模式中要使用BX指令转跳到THUMB指令,并转换模式
|;(|表示else)如果编译选项本来就指定为ARM模式
movpc,lr;如果目标地址也是ARM指令的话就采用这种方式
];(]表示endif)
MEND
MACRO;和上面的宏一样,只是多了一个相等的条件
MOVEQ_PC_LR
[THUMBCODE
bxeqlr
|
moveqpc,lr
]
MEND
;=======================================================================================
;下面这个宏是用于第一次查表过程的实现中断向量的重定向,如果你比较细心的话就是发现
;在_ISR_STARTADDRESS=0x33FF_FF00里定义的第一级中断向量表是采用型如Handle***的方式的.
;而在程序的ENTRY处(程序开始处)采用的是bHandler***的方式.
;在这里Handler***就是通过HANDLER这个宏和Handle***进立联系的.
;这种方式的优点就是正真定义的向量数据在内存空间里,而不是在ENTRY处的ROM(FLASH)空间里,
;这样,我们就可以在程序里灵活的改动向量的数据了.
;========================================================================================
;;这段程序用于把中断服务程序的首地址装载到pc中,有人称之为“加载程序”。
;本初始化程序定义了一个数据区(在文件最后),34个字空间,存放相应中断服务程序的首地址。每个字
;空间都有一个标号,以Handle***命名。
;在向量中断模式下使用“加载程序”来执行中断服务程序。
;这里就必须讲一下向量中断模式和非向量中断模式的概念
;向量中断模式是当cpu读取位于0x18处的IRQ中断指令的时候,系统自动读取对应于该中断源确定地址上的;
;指令取代0x18处的指令,通过跳转指令系统就直接跳转到对应地址
;函数中节省了中断处理时间提高了中断处理速度标例如ADC中断的向量地址为0xC0,则在0xC0处放如下
;代码:ldrPC,=HandlerADC当ADC中断产生的时候系统会
;自动跳转到HandlerADC函数中
;非向量中断模式处理方式是一种传统的中断处理方法,当系统产生中断的时候,系统将interrupt
;pending寄存器中对应标志位置位然后跳转到位于0x18处的统一中断
;函数中该函数通过读取interruptpending寄存器中对应标志位来判断中断源并根据优先级关系再跳到
;对应中断源的处理代码中
;
MACRO
$HandlerLabelHANDLER$HandleLabel
$HandlerLabel;标号
subsp,sp,#4;减少sp(用于存放转跳地址)
stmfdsp!,{r0};把工作寄存器压入栈(lrdoesnotpushbecauseitreturntooriginal
address)
ldrr0,=$HandleLabel;将HandleXXX的址址放入r0
ldrr0,[r0];把HandleXXX所指向的内容(也就是中断程序的入口)放入r0
strr0,[sp,#4];把中断服务程序(ISR)压入栈
ldmfdsp!,{r0,pc};用出栈的方式恢复r0的原值和为pc设定新值(也就完成了到ISR的转跳)
MEND
;=========================================================================================
;在这里用IMPORT伪指令(和c语言的extren一样)引入|Image$$RO$$Base|,|Image$$RO$$Limit|...
;这些变量是通过ADS的工程设置里面设定的ROBase和RWBase设定的,
;最终由编译脚本和连接程序导入程序.
;那为什么要引入这玩意呢,最简单的用处是可以根据它们拷贝自已
;==========================================================================================
IMPORT|Image$$RO$$Base|;ROMcode(也就是代码)的开始地址
IMPORT|Image$$RO$$Limit|;ROMcode的结束地址(=ROMdata的开始地址)
IMPORT|Image$$RW$$Base|;要初始化的RAM的开始地址
IMPORT|Image$$ZI$$Base|;area(需要清零的RAM区域)的开始地址
IMPORT|Image$$ZI$$Limit|;area的结束地址
;这里引入一些在其它文件中实现在函数,包括为我们所熟知的main函数
IMPORTMMU_SetAsyncBusMode
IMPORTMMU_SetFastBusMode;hzh
IMPORTMain
;Themainentryofmonprogram
;从这里开始就是正真的代码入口了!
AREAInit,CODE,READONLY;这表明下面的是一个名为Init的代码段
ENTRY;定义程序的入口(调试用)
EXPORT__ENTRY;导出符号_ENTRY,告知__ENTRY不
是在本源文件中,是在别的中定义的在本源文件中要用到
__ENTRY
ResetEntry
;1)Thecode,whichconvertstoBig-endian,shouldbeinlittleendiancode.
;2)ThefollowinglittleendiancodewillbecompiledinBig-Endianmode.
;Thecodebyteordershouldbechangedasthememorybuswidth.
;3)Thepseudoinstruction,DCDcannotbeusedherebecausethelinkergenerateserror.
;条件编译,在编译成机器码前就设定好
ASSERT:DEF:ENDIAN_CHANGE
[ENDIAN_CHANGE
;下面是大小端的一个判断,在Option.inc里已经设FALSE
ASSERT:DEF:ENTRY_BUS_WIDTH;判断ENTRY_BUS_WIDTH是否已定义
[ENTRY_BUS_WIDTH=32;如果已经定义了ENTRY_BUS_WIDTH,则判断是不是为32
bChangeBigEndian;DCD0xea000007
;在bigendian中,地址为A的字单元包括字节单元A,A+1,A+2,A+3,字节单元由高位到低位为A,A+1,A+2,A+3
;地址为A的字单元包括半字单元A,A+2,半字单元由高位到低位为A,A+2
]
[ENTRY_BUS_WIDTH=16
andeqr14,r7,r0,lsl#20;DCD0x0007ea00
]bChangeBigEndian指令,只是由于总线不一样而取机器码的顺序不一样
[ENTRY_BUS_WIDTH=8
streqr0,[r0,-r10,ror#1];DCD0x070000ea
]
|
bResetHandler;设成FALSE的话就来到这了,转跳到复位程序入口
]
bHandlerUndef;转跳到Undefinedmode程序入口0x04
bHandlerSWI;转跳到SWI中断程序入口0x08
bHandlerPabort;转跳到PAbort(指令异常)程序入口0x0c
bHandlerDabort;转跳到DAbort(数据异常)程序入口0x10
b.;保留0x14
bHandlerIRQ;转跳到IRQ中断程序入口0x18
bHandlerFIQ;转跳到FIQ中断程序入口0x1c
;@0x20
bEnterPWDN;Mustbe@0x20.
;==================================================================================
;下面是改变大小端的程序,这里采用直接定义机器码的方式,至说为什么这么做就得问三星了
;反正我们程序里这段代码也不会去执行,不用去管它
;==================================================================================
ChangeBigEndian
;@0x24
[ENTRY_BUS_WIDTH=32
DCD0xee110f10;0xee110f10=>mrcp15,0,r0,c1,c0,0
DCD0xe3800080;0xe3800080=>orrr0,r0,#0x80;//Big-endian
DCD0xee010f10;0xee010f10=>mcrp15,0,r0,c1,c0,0
]
[ENTRY_BUS_WIDTH=16
DCD0x0f10ee11
DCD0x0080e380
DCD0x0f10ee01
]
[ENTRY_BUS_WIDTH=8
DCD0x100f11ee
DCD0x800080e3
DCD0x100f01ee
]
DCD0xffffffff;swinv0xffffffissimilarwithNOPandrunwellinbothendianmode.
DCD0xffffffff
DCD0xffffffff
DCD0xffffffff
DCD0xffffffff
bResetHandler
;=========================================================================================
;Functionforenteringpowerdownmode
;1.SDRAMshouldbeinself-refreshmode.
;2.AllinterruptshouldbemakskedforSDRAM/DRAMself-refresh.
;3.LCDcontrollershouldbedisabledforSDRAM/DRAMself-refresh.
;4.TheI-cachemayhavetobeturnedon.
;5.Thelocationofthefollowingcodemayhavenottobechanged.
;voidEnterPWDN(intCLKCON);
EnterPWDN
ldrr0,=rCLKCON
movr2,r0;r2=rCLKCON保存原始数据0x4c00000c使能各模块的时钟输入
tstr0,#0x8;测试bit[3]SLEEPmode?1=>sleep
bneENTER_SLEEP;C=0,即TST结果非0,bit[3]=1
;//进入PWDN后如果不是sleep则进入stop
;//进入Stopmode
ENTER_STOP
ldrr0,=REFRESH;0x48000024DRAM/SDRAMrefreshconfig
ldrr3,[r0];r3=rREFRESH
movr1,r3
orrr1,r1,#BIT_SELFREFRESH;EnableSDRAMself-refresh
strr1,[r0];EnableSDRAMself-refresh
movr1,#16;waituntilself-refreshisissued.maynotbeneeded.
0
subsr1,r1,#1
bne%B0;%B表示向前找到0处
;//wait16fclksforself-refresh
ldrr0,=CLKCON;enterSTOPmode.
strr2,[r0]
movr1,#32
0
subsr1,r1,#1;1)waituntiltheSTOPmodeisineffect.
bne%B0;2)OrwaithereuntiltheCPU&Peripheralswillbeturned-off
;EnteringSLEEPmode,onlytheresetbywake-upisavailable.
ldrr0,=REFRESH;exitfromSDRAMselfrefreshmode.
strr3,[r0]
MOV_PC_LR;backtomainprocess
ENTER_SLEEP
;NOTE.
;1)rGSTATUS3shouldhavethereturnaddressafterwake-upfromSLEEPmode.
ldrr0,=REFRESH
ldrr1,[r0];r1=rREFRESH
orrr1,r1,#BIT_SELFREFRESH
strr1,[r0];EnableSDRAMself-refresh
;//EnableSDRAMself-refresh
movr1,#16;Waituntilself-refreshisissued,whichmaynotbeneeded.
0
subsr1,r1,#1
bne%B0
;//Waituntilself-refreshisissued,whichmaynotbeneeded
ldrr1,=MISCCR;IOregister
ldrr0,[r1]
orrr0,r0,#(7<<17);SetSCLK0=1,SCLK1=1,SCKE=1.
strr0,[r1]
ldrr0,=CLKCON;Entersleepmode
strr2,[r0]
b.;CPUwilldiehere.
;//进入SleepMode,1)设置SDRAM为self-refresh
;//2)设置MISCCRbit[17]1:sclk0=sclk0:sclk0=0
;//bit[18]1:sclk1=sclk0:sclk1=0
;//bit[19]1:Selfrefreshretainenable
;//0:Selfrefreshretaindisable
;//When1,Afterwake-upfromsleep,Theself-refreshwillberetained.
WAKEUP_SLEEP
;ReleaseSCLKnafterwake-upfromtheSLEEPmode.
ldrr1,=MISCCR
ldrr0,[r1]
bicr0,r0,#(7<<17);SCLK0:0->SCLK,SCLK1:0->SCLK,SCKE:0->=SCKE.
strr0,[r1]
;//设置MISCCR
;Setmemorycontrolregisters
;ldrr0,=SMRDATA
adrlr0,SMRDATA
ldrr1,=BWSCON;BWSCONAddress;//总线宽度和等待控制寄存器
addr2,r0,#52;EndaddressofSMRDATA
0
ldrr3,[r0],#4;数据处理后R0自加4,[R0]->R3,R0+4->R0
strr3,[r1],#4
cmpr2,r0
bne%B0
;//设置所有的memorycontrolregister,他的初始地址为BWSCON,初始
;//数据在以SMRDATA为起始的存储区
movr1,#256
0
subsr1,r1,#1;1)waituntiltheSelfRefreshisreleased.
bne%B0
.
ldrr1,=GSTATUS3;GSTATUS3hasthestartaddressjustafterSLEEPwake-up
ldrr0,[r1]
movpc,r0
;//跳出SleepMode,进入Sleep状态前的PC
;如上所说,这里采用HANDLER宏去建立Hander***和Handle***之间的联系
HandlerFIQHANDLERHandleFIQ
HandlerIRQHANDLERHandleIRQ
HandlerUndefHANDLERHandleUndef
HandlerSWIHANDLERHandleSWI
HandlerDabortHANDLERHandleDabort
HandlerPabortHANDLERHandlePabort
;===================================================================================
,这一段程序就是用来进行第二次查表的过程了.
;如果说第一次查表是由硬件来完成的,那这一次查表就是由软件来实现的了.
;为什么要查两次表??
;没有办法,ARM把所有的中断都归纳成一个IRQ中断异常和一个FIRQ中断异常
;第一次查表主要是查出是什么异常,可我们总要知道是这个中断异常中的什么中断;
;===================================================================================
IsrIRQ
subsp,sp,#4;给PC寄存器保留
stmfdsp!,{r8-r9};把r8-r9压入栈
ldrr9,=INTOFFSET;把INTOFFSET的地址装入r9INTOFFSET是一个内部的寄存器,存着中断的偏移
ldrr9,[r9];把INTOFFSET的值装入r9
ldrr8,=HandleEINT0;这就是我们第二个中断向量表的入口的,先装入r8
;===================================================================================
;哈哈,这查表方法够好了吧,r8(入口)+index*4(别望了一条指令是4bytes的喔),
;这不就是我们要找的那一项了吗.找到了表项,下一步做什么?肯定先装入了!
;==================================================================================
addr8,r8,r9,lsl#2;地址对齐,因为每个中断向量占4个字节,即isr=IvectTable+Offeset*4
ldrr8,[r8];装入中断服务程序的入口
strr8,[sp,#8];把入口也入栈,准备用旧招
ldmfdsp!,{r8-r9,pc};施招,弹出栈,哈哈,顺便把r8弹出到PC,O了,跳转成功!
LTORG;声明文字池,因为我们用了ldr伪指令
;==============================================================================
;ENTRY(好了,我们的CPU要在这复位了.)
;==============================================================================
ResetHandler
ldrr0,=WTCON;1.关看门狗
ldrr1,=0x0;bit[5]:0-disable;1-enable(reset默认)
strr1,[r0]
ldrr0,=INTMSK
ldrr1,=0xffffffff;2.关中断
strr1,[r0]
ldrr0,=INTSUBMSK
ldrr1,=0x7fff;3.关子中断
strr1,[r0]
[{FALSE}
;4.得有些表示了,该点点LED灯了,不过被FALSE掉了.
;rGPFDAT=(rGPFDAT&~(0xf<<4))|((~data&0xf)<<4);
;Led_Display
ldrr0,=GPFCON
ldrr1,=0x5500
strr1,[r0]
ldrr0,=GPFDAT
ldrr1,=0x10
strr1,[r0]
]
;5.为了减少PLL的locktime,调整LOCKTIME寄存器.
ldrr0,=LOCKTIME
ldrr1,=0xffffff
strr1,[r0]
;6.下面就来设置PLL了,你的板快不快就看这了!!
;这里介绍一下计算公式
;//Fpllo=(m*Fin)/(p*2^s)
;//m=MDIV+8,p=PDIV+2,s=SDIV
;TheproperrangeofPandM:1<=P<=62,1<=M<=248
;Fpllo必须大于200Mhz小于600Mhz
;Fpllo*2^s必须小于1.2GHz
;如下面的PLLCON设定中的M_DIVP_DIVS_DIV是取自option.h中
;#elif(MCLK==40000000)
;#definePLL_M(0x48)
;#definePLL_P(0x3)
;#definePLL_S(0x2)
;所以m=MDIV+8=80,p=PDIV+2=5,s=SDIV=2
;硬件使用晶振为10Mhz,即Fin=10Mhz
;Fpllo=80*10/5*2^2=40Mhz
[PLL_ON_START
;Addedforconfirmclockdivide.for2440.
;SettingvalueFclk:Hclk:Pclk
ldrr0,=CLKDIVN
ldrr1,=CLKDIV_VAL;0=1:1:1,1=1:1:2,2=1:2:2,3=1:2:4,
strr1,[r0];4=1:4:4,5=1:4:8,6=1:3:3,7=1:3:6.
;//数据表示分频数
;===============================================================================
;MMU_SetAsyncBusMode和MMU_SetFastBusMode都在4K代码以上,
;如果你想你编译出来的程序能在NAND上运行的话,就不要在这调用这两函数了.
;如果你不要求的话,你就用把.啥事没有.
;为什么是4K,问三星吧,就提供4K的内部SRAM,要是提供400K多好呀.
;好了,好了,4K就4K吧,不能用这两函数,自己写还不行吗,下面的代码这这么来了,
;实现和上面两函数一样的功能.
;===============================================================================
;[CLKDIV_VAL>1;意思是Fclk:Hclk不是1:1.
;blMMU_SetAsyncBusMode
;|
;blMMU_SetFastBusMode;defaultvalue.
;]
[CLKDIV_VAL>1;意思是Fclk:Hclk不是1:1.
mrcp15,0,r0,c1,c0,0
orrr0,r0,#0xc0000000;R1_nF:OR:R1_iA
mcrp15,0,r0,c1,c0,0
|
mrcp15,0,r0,c1,c0,0
bicr0,r0,#0xc0000000;R1_iA:OR:R1_nF
mcrp15,0,r0,c1,c0,0
]
/****************************************************************************************************************************************************/
上接mini2440开发板中启动代码2440INIT.S分析(1)
;配置UPLL
;//ConfigureUPLLFin=12.0MHzUFout=48MHz
ldrr0,=UPLLCON
ldrr1,=((U_MDIV<<12)+(U_PDIV<<4)+U_SDIV)
strr1,[r0]
nop;Caution:AfterUPLLsetting,atleast7-clocks
nop;delaymustbeinsertedforsettinghardwarebecompleted.
nop
nop
nop
nop
nop
;配置MPLL
;//ConfigureMPLLFin=12.0MHzMFout=304.8MHz一定要使最后的频率为16.9344MHz,不然你甭想用USB接口了
ldrr0,=MPLLCON
ldrr1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV)
strr1,[r0]
]
;检查是否从SLEEP模式中恢复
ldrr1,=GSTATUS2
ldrr0,[r1]
tstr0,#0x2
;如果是从SLEEP模式中恢复,转跳到SLEEP_WAKEUP.
bneWAKEUP_SLEEP
EXPORTStartPointAfterSleepWakeUp;导出符号StartPointAfterSleepWakeUp
StartPointAfterSleepWakeUp
;===============================================================================
;设置内存控制器等寄存器的值,因为这些寄存器是连续排列的,所以采用如下办法对这些
;寄存器进行连续设置.其中用到了SMRDATA的数据,这在代码后面有定义
;===============================================================================
;ldrr0,=SMRDATA
adrlr0,SMRDATA;becareful!,hzh
ldrr1,=BWSCON;BWSCON地址
addr2,r0,#52;
SMRDATA数据的结束地址,共有52字节的数据
0
ldrr3,[r0],#4
strr3,[r1],#4
cmpr2,r0
bne%B0
;================================================================================
;如果EINT0产生(这中断就是我们按键产生的),就清除SDRAM,不过好像没人会在这个时候按
;================================================================================
;checkifEIN0buttonispressed
ldrr0,=GPFCON
ldrr1,=0x0
strr1,[r0]
ldrr0,=GPFUP
ldrr1,=0xff
strr1,[r0]
ldrr1,=GPFDAT
ldrr0,[r1]
bicr0,r0,#(0x1e<<1);bitclear
tstr0,#0x1
bne%F1;如果没有按,就跳到后面的1标号处
;这就是清零内存的代码
ldrr0,=GPFCON
ldrr1,=0x55aa
strr1,[r0]
;ldrr0,=GPFUP
;ldrr1,=0xff
;strr1,[r0]
ldrr0,=GPFDAT
ldrr1,=0x0
strr1,[r0];LED=****
movr1,#0
movr2,#0
movr3,#0
movr4,#0
movr5,#0
movr6,#0
movr7,#0
movr8,#0
ldrr9,=0x4000000;64MB
ldrr0,=0x30000000
0
stmiar0!,{r1-r8}
subsr9,r9,#32
bne%B0
;到这就结束了.
1
blInitStacks;初始化堆栈
;blLed_Test;又是LED,注掉了
;=======================================================================
;哈哈,下面又有看头了,这个初始化程序好像被名曰hzh的高手改过
;能在NORNAND还有内存中运行,当然了,在内存中运行最简单了.
;在NORNAND中运行的话都要先把自己拷到内存中.
;此外,还记得上面提到的|Image$$RO$$Base|,|Image$$RO$$Limit|...吗?
;这就是拷贝的依据了!!!
;=========================================================================
ldrr0,=BWSCON
ldrr0,[r0]
andsr0,r0,#6;OM[1:0]!=0,从NORFLash启动或直接在内存运行
bnecopy_proc_beg;不读取NANDFLASH
adrr0,ResetEntry;OM[1:0]==0,为从NANDFLash启动
cmpr0,#0;再比较入口是否为0地址处
;==========================================================================
;如果不是,则表示主板设置了从NAND启动,但这个程序由于其它原因,
;并没有从NAND启动,这种情况最有可能的原因就是用仿真器.
;==========================================================================
bnecopy_proc_beg;这种情况也不读取NANDFLASH.
;nop;如果是0才是真正从NAND启动,因为其4k被复制到0地址开始的stepingstone内部sram中
;注意adr得到的是相对地址,非绝对地址==ifuseMulti-ice,
;===========================================================
nand_boot_beg;这一段代码完成从NAND读代码到RAM
movr5,#NFCONF;首先设定NAND的一些控制寄存器
;settimingvalue
ldrr0,=(7<<12)|(7<<8)|(7<<4)
strr0,[r5]
;enablecontrol
ldrr0,=(0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0)
strr0,[r5,#4]
blReadNandID;按着读取NAND的ID号,结果保存在r5里
movr6,#0;r6设初值0.
ldrr0,=0xec73;期望的NANDID号
cmpr5,r0;这里进行比较
beq%F1;相等的话就跳到下一个1标号处
ldrr0,=0xec75;这是另一个期望值
cmpr5,r0
beq%F1;相等的话就跳到下一个1标号处
movr6,#1;不相等了,设置r6=1.
1
blReadNandStatus;读取NAND状态,结果放在r1里
movr8,#0;r8设初值0,意义为页号
ldrr9,=ResetEntry;r9设初值为初始化程序入口地址
;=========================================================================
;注意,在这里使用的是ldr伪指令,而不是上面用的adr伪指令,它加载的是ResetEntry
;的决对地址,也就是我们期望的RAM中的地址,在这里,它和|Image$$RO$$Base|一样
;也就是说,我如我们编译程序时ROBASE指定的地址在RAM里,而把生成的文件拷到
;NAND里运行,由ldr加载的r9的值还是定位在内存.
;=========================================================================
2
andsr0,r8,#0x1f;凡r8为0x1f(32)的整数倍-1,eq有效,ne无效
bne%F3;这句的意思是对每个块(32页)进行检错
movr0,r8;r8->r0
blCheckBadBlk;检查NAND的坏区
cmpr0,#0;比较r0和0
addner8,r8,#32;存在坏块的话就跳过这个坏块
bne%F4;没有的话就跳到标号4处
3
movr0,r8;当前页号->r0
movr1,r9;当前目标地址->r1
blReadNandPage;读取该页的NAND数据到RAM
addr9,r9,#512;每一页的大小是512Bytes
addr8,r8,#1;r8指向下一页
4
cmpr8,#256;比较是否读完256页即128KBytes
bcc%B2;如果r8小于256(没读完),就返回前面的标号2处
movr5,#NFCONF;DsNandFlash
ldrr0,[r5,#4]
bicr0,r0,#1
strr0,[r5,#4]
ldrpc,=copy_proc_beg;调用copy_proc_beg
;===========================================================
copy_proc_beg
adrr0,ResetEntry;ResetEntry值->r0
ldrr2,BaseOfROM;BaseOfROM值(后面有定义)->r2
cmpr0,r2;比较r0和r2
ldreqr0,TopOfROM;如果相等的话(在内存运行),TopOfROM->r0
beqInitRam;同时跳到InitRam
;=========================================================
;下面这个是针对代码在NORFLASH时的拷贝方法
;功能为把从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|也是由连接器生成
;两者之间就是初始化数据的存放地放
;=======================================================
ldrr3,TopOfROM
0
ldmiar0!,{r4-r7}
stmiar2!,{r4-r7}
cmpr2,r3
bcc%B0
subr2,r2,r3;r2=BaseOfROM-TopOfROM=(-)代码长度
subr0,r0,r2;r0=ResetEntry-(-)代码长度=ResetEntry+代码长度
InitRam
ldrr2,BaseOfBSS;BaseOfBSS->r2
ldrr3,BaseOfZero;BaseOfZero->r3
0
cmpr2,r3;比较BaseOfBSS和BaseOfZero
ldrccr1,[r0],#4;要是r21;meansFclk:Hclkisnot1:1.
;blMMU_SetAsyncBusMode
;|
;blMMU_SetFastBusMode;defaultvalue.
;]
;blLed_Test
;===========================================================
;进入C语言前的最后一步了,就是把我们用说查二级向量表
;的中断例程安装到一级向量表(异常向量表)里.
ldrr0,=HandleIRQ;Thisroutineisneeded
ldrr1,=IsrIRQ;ifthereisnot'subspc,lr,#4'at0x18,0x1c
strr1,[r0]
;;CopyandpasteRWdata/zeroinitializeddata
;ldrr0,=|Image$$RO$$Limit|;GetpointertoROMdata
;ldrr1,=|Image$$RW$$Base|;andRAMcopy
;ldrr3,=|Image$$ZI$$Base|
;
;;Zeroinitbase=>top
ofinitialiseddata
;cmpr0,r1;Checkthattheyaredifferent
;beq%F2
;1
;cmpr1,r3;Copyinitdata
;ldrccr2,[r0],#4;-->LDRCCr2,[r0]+ADDr0,r0,#4
;strccr2,[r1],#4;-->STRCCr2,[r1]+ADDr1,r1,#4
;bcc%B1
;2
;ldrr1,=|Image$$ZI$$Limit|;Top
ofzeroinitsegment
;movr2,#0
;3
;cmpr3,r1;Zeroinit
;strccr2,[r3],#4
;bcc%B3
;*****************************************************************************
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
;妈呀,终说见到艳阳天了!!!!!!!!!!
;跳到C语言的main函数处了.
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
;*****************************************************************************
[:LNOT:THUMBCODE
blMain;Donotusemain()because......
;ldrpc,=Main;hzh
b.
]
[THUMBCODE;forstart-upcodeforThumbmode
orrlr,pc,#1
bxlr
CODE16
blMain;Donotusemain()because......
b.
CODE32
]
;initializingstacks
InitStacks
;DonotuseDRAM,suchasstmfd,ldmfd......
;SVCstackisinitializedbefore
;Undertoolkitver2.5,'msrcpsr,r1'canbeusedinstead
of'msrcpsr_cxsf,r1'
mrsr0,cpsr
bicr0,r0,#MODEMASK
orrr1,r0,#UNDEFMODE|NOINT
msrcpsr_cxsf,r1;UndefMode
ldrsp,=UndefStack;UndefStack=0x33FF_5C00
orrr1,r0,#ABORTMODE|NOINT
msrcpsr_cxsf,r1;AbortMode
ldrsp,=AbortStack;AbortStack=0x33FF_6000
orrr1,r0,#IRQMODE|NOINT
msrcpsr_cxsf,r1;IRQMode
ldrsp,=IRQStack;IRQStack=0x33FF_7000
orrr1,r0,#FIQMODE|NOINT
msrcpsr_cxsf,r1;FIQMode
ldrsp,=FIQStack;FIQStack=0x33FF_8000
bicr0,r0,#MODEMASK|NOINT
orrr1,r0,#SVCMODE
msrcpsr_cxsf,r1;SVCMode
ldrsp,=SVCStack;SVCStack=0x33FF_5800
;USERmodehasnotbeinitialized.
movpc,lr
;TheLRregisterwillnotbevalidifthecurrentmodeisnotSVCmode.
;===========================================================
ReadNandID
movr7,#NFCONF
ldrr0,[r7,#4];NFChipEn();
bicr0,r0,#2
strr0,[r7,#4]
movr0,#0x90;WrNFCmd(RdIDCMD);
strbr0,[r7,#8]
movr4,#0;WrNFAddr(0);
strbr4,[r7,#0xc]
1;while(NFIsBusy());
ldrr0,[r7,#0x20]
tstr0,#1
beq%B1
ldrbr0,[r7,#0x10];id=RdNFDat()<<8;
movr0,r0,lsl#8
ldrbr1,[r7,#0x10];id|=RdNFDat();
orrr5,r1,r0
ldrr0,[r7,#4];NFChipDs();
orrr0,r0,#2
strr0,[r7,#4]
movpc,lr
ReadNandStatus
movr7,#NFCONF
ldrr0,[r7,#4];NFChipEn();
bicr0,r0,#2
strr0,[r7,#4]
movr0,#0x70;WrNFCmd(QUERYCMD);
strbr0,[r7,#8]
ldrbr1,[r7,#0x10];r1=RdNFDat();
ldrr0,[r7,#4];NFChipDs();
orrr0,r0,#2
strr0,[r7,#4]
movpc,lr
WaitNandBusy
movr0,#0x70;WrNFCmd(QUERYCMD);
movr1,#NFCONF
strbr0,[r1,#8]
1;while(!(RdNFDat()&0x40));
ldrbr0,[r1,#0x10]
tstr0,#0x40
beq%B1
movr0,#0;WrNFCmd(READCMD0);
strbr0,[r1,#8]
movpc,lr
CheckBadBlk
movr7,lr
movr5,#NFCONF
bicr0,r0,#0x1f;addr&=~0x1f;
ldrr1,[r5,#4];NFChipEn()
bicr1,r1,#2
strr1,[r5,#4]
movr1,#0x50;WrNFCmd(READCMD2)
strbr1,[r5,#8]
movr1,#5;6;6->5
strbr1,[r5,#0xc];WrNFAddr(5);(6)6->5
strbr0,[r5,#0xc];WrNFAddr(addr)
movr1,r0,lsr#8;WrNFAddr(addr>>8)
strbr1,[r5,#0xc]
cmpr6,#0;if(NandAddr)
movner0,r0,lsr#16;WrNFAddr(addr>>16)
strnebr0,[r5,#0xc]
;blWaitNandBusy;WaitNFBusy()
;donotuseWaitNandBusy,afterWaitNandBusywillreadpartA!
movr0,#100
1
subsr0,r0,#1
bne%B1
2
ldrr0,[r5,#0x20]
tstr0,#1
beq%B2
ldrbr0,[r5,#0x10];RdNFDat()
subr0,r0,#0xff
movr1,#0;WrNFCmd(READCMD0)
strbr1,[r5,#8]
ldrr1,[r5,#4];NFChipDs()
orrr1,r1,#2
strr1,[r5,#4]
movpc,r7
ReadNandPage
movr7,lr
movr4,r1
movr5,#NFCONF
ldrr1,[r5,#4];NFChipEn()
bicr1,r1,#2
strr1,[r5,#4]
movr1,#0;WrNFCmd(READCMD0)
strbr1,[r5,#8]
strbr1,[r5,#0xc];WrNFAddr(0)
strbr0,[r5,#0xc];WrNFAddr(addr)
movr1,r0,lsr#8;WrNFAddr(addr>>8)
strbr1,[r5,#0xc]
cmpr6,#0;if(NandAddr)
movner0,r0,lsr#16;WrNFAddr(addr>>16)
strnebr0,[r5,#0xc]
ldrr0,[r5,#4];InitEcc()
orrr0,r0,#0x10
strr0,[r5,#4]
blWaitNandBusy;WaitNFBusy()
movr0,#0;for(i=0;i<512;i++)
1
ldrbr1,[r5,#0x10];buf[i]=RdNFDat()
strbr1,[r4,r0]
addr0,r0,#1
bicr0,r0,#0x10000
cmpr0,#0x200
bcc%B1
ldrr0,[r5,#4];NFChipDs()
orrr0,r0,#2
strr0,[r5,#4]
movpc,r7
;--------------------LEDtest
EXPORTLed_Test
Led_Test
movr0,#0x56000000
movr1,#0x5500
strr1,[r0,#0x50]
0
movr1,#0x50
strr1,[r0,#0x54]
movr2,#0x100000
1
subsr2,r2,#1
bne%B1
movr1,#0xa0
strr1,[r0,#0x54]
movr2,#0x100000
2
subsr2,r2,#1
bne%B2
b%B0
movpc,lr
;===========================================================
LTORG
;GCS0->SST39VF1601
;GCS1->16c550
;GCS2->IDE
;GCS3->CS8900
;GCS4->DM9000
;GCS5->CFCard
;GCS6->SDRAM
;GCS7->unused
SMRDATADATA
;Memoryconfigurationshouldbeoptimizedforbestperformance
;Thefollowingparameterisnotoptimized.
;Memoryaccesscycleparameterstrategy
;1)ThememorysettingsissafeparametersevenatHCLK=75Mhz.
;2)SDRAMrefreshperiodisforHCLK<=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)
DCD0x32;SCLKpowersavingmode,BANKSIZE128M/128M
DCD0x30;MRSR6CL=3clk
DCD0x30;MRSR7CL=3clk
BaseOfROMDCD|Image$$RO$$Base|
TopOfROMDCD|Image$$RO$$Limit|
BaseOfBSSDCD|Image$$RW$$Base|
BaseOfZeroDCD|Image$$ZI$$Base|
EndOfBSSDCD|Image$$ZI$$Limit|
ALIGN
;forenteringpowerdownmode
;1.SDRAMshouldbeinself-refreshmode.
;2.AllinterruptshouldbemakskedforSDRAM/DRAMself-refresh.
;3.LCDcontrollershouldbedisabledforSDRAM/DRAMself-refresh.
;4.TheI-cachemayhavetobeturnedon.
;5.Thelocation
ofthefollowingcodemayhavenottobechanged.
;voidEnterPWDN(intCLKCON);
EnterPWDN
movr2,r0;r2=rCLKCON
tstr0,#0x8;SLEEPmode?
bneENTER_SLEEP
ENTER_STOP
ldrr0,=REFRESH
ldrr3,[r0];r3=rREFRESH
movr1,r3
orrr1,r1,#BIT_SELFREFRESH
strr1,[r0];EnableSDRAMself-refresh
movr1,#16;waituntilself-refreshisissued.maynotbeneeded.
0subsr1,r1,#1
bne%B0
ldrr0,=CLKCON;enterSTOPmode.
strr2,[r0]
movr1,#32
0subsr1,r1,#1;1)waituntiltheSTOPmodeisineffect.
bne%B0;2)OrwaithereuntiltheCPU&Peripheralswillbeturned-off
;EnteringSLEEPmode,onlytheresetbywake-upisavailable.
ldrr0,=REFRESH;exitfromSDRAMselfrefreshmode.
strr3,[r0]
MOV_PC_LR
ENTER_SLEEP
;NOTE.
;1)rGSTATUS3shouldhavethereturn
addressafterwake-upfromSLEEPmode.
ldrr0,=REFRESH
ldrr1,[r0];r1=rREFRESH
orrr1,r1,#BIT_SELFREFRESH
strr1,[r0];EnableSDRAMself-refresh
movr1,#16;Waituntilself-refreshisissued,whichmaynotbeneeded.
0subsr1,r1,#1
bne%B0
ldrr1,=MISCCR
ldrr0,[r1]
orrr0,r0,#(7<<17);SetSCLK0=0,SCLK1=0,SCKE=0.
strr0,[r1]
ldrr0,=CLKCON;Entersleepmode
strr2,[r0]
b.;CPUwilldiehere.
WAKEUP_SLEEP
;ReleaseSCLKnafterwake-upfromtheSLEEPmode.
ldrr1,=MISCCR
ldrr0,[r1]
bicr0,r0,#(7<<17);SCLK0:0->SCLK,SCLK1:0->SCLK,SCKE:0->=SCKE.
strr0,[r1]
;Setmemorycontrolregisters
ldrr0,=SMRDATA;becareful!,hzh
ldrr1,=BWSCON;BWSCON
Address
addr2,r0,#52;EndaddressofSMRDATA
0
ldrr3,[r0],#4
strr3,[r1],#4
cmpr2,r0
bne%B0
movr1,#256
0subsr1,r1,#1;1)waituntiltheSelfRefreshisreleased.
bne%B0
ldrr1,=GSTATUS3;GSTATUS3hasthestart
addressjustafterSLEEPwake-up
ldrr0,[r1]
movpc,r0
;=====================================================================
;Clockdivisiontest
;Assemblecode,becauseVSYNCtimeisveryshort
;=====================================================================
EXPORTCLKDIV124
EXPORTCLKDIV144
CLKDIV124
ldrr0,=CLKDIVN
ldrr1,=0x3;0x3=1:2:4
strr1,[r0]
;waituntilclockisstable
nop
nop
nop
nop
nop
ldrr0,=REFRESH
ldrr1,[r0]
bicr1,r1,#0xff
bicr1,r1,#(0x7<<8)
orrr1,r1,#0x470;REFCNT135
strr1,[r0]
nop
nop
nop
nop
nop
movpc,lr
CLKDIV144
ldrr0,=CLKDIVN
ldrr1,=0x4;0x4=1:4:4
strr1,[r0]
;waituntilclockisstable
nop
nop
nop
nop
nop
ldrr0,=REFRESH
ldrr1,[r0]
bicr1,r1,#0xff
bicr1,r1,#(0x7<<8)
orrr1,r1,#0x630;REFCNT675-1520
strr1,[r0]
nop
nop
nop
nop
nop
movpc,lr
ALIGN
AREARamData,DATA,READWRITE
^_ISR_STARTADDRESS;_ISR_STARTADDRESS=0x33FF_FF00
HandleReset#4
HandleUndef#4
HandleSWI#4
HandlePabort#4
HandleDabort#4
HandleReserved#4
HandleIRQ#4
HandleFIQ#4
;Donotusethelabel'IntVectorTable',
;ThevalueofIntVectorTableisdifferentwiththeaddressyouthinkitmaybe.
;IntVectorTable
;@0x33FF_FF20
HandleEINT0#4
HandleEINT1#4
HandleEINT2#4
HandleEINT3#4
HandleEINT4_7#4
HandleEINT8_23#4
HandleCAM#4;Addedfor2440.
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;Addedfor2440.
HandleUSBD#4
HandleUSBH#4
HandleIIC#4
HandleUART0#4
HandleSPI1#4
HandleRTC#4
HandleADC#4
;@0x33FF_FFA0
相关文章推荐
- mini2440(5) 2440init.s代码分段分析
- ARM启动代码分析(2440init.c)
- TQ2440裸奔程序>>2440init.s启动代码分析
- mini2440启动代码分析之第五篇(中断向量表)
- Linux内核启动代码分析二之开发板相关驱动程序加载分析
- ARM启动文件2440init.s分析
- mini2440启动代码分析之第六篇(DCD与二次查表判中断类型)
- mini2440(3) 2440init.s代码关键字注解
- Linux内核启动代码分析二之开发板相关驱动程序加载分析
- 关于mini2440启动代码中中断的产生原理分析
- mini2440启动代码分析之第七篇(ResetHandler和存储控制寄存器初始化)
- arm启动文件2440init.s分析
- EasyARM2200开发板学习笔记:启动代码分析
- S3C2440启动代码2440init.s彻底解析
- mini2440启动代码分析之第八篇(清空SDRAM)
- mini2440启动代码分析之第九篇
- ARM启动文件2440init.s分析
- mini2440启动代码分析之第十篇
- mini2440启动代码分析之第一篇(注意名字,不是bootloader)
- mini2440启动代码分析