2440init解析.docx
- 文档编号:9242858
- 上传时间:2023-05-17
- 格式:DOCX
- 页数:39
- 大小:27.83KB
2440init解析.docx
《2440init解析.docx》由会员分享,可在线阅读,更多相关《2440init解析.docx(39页珍藏版)》请在冰点文库上搜索。
2440init解析
引言:
一直想要把长长的代码读明白。
总算利用假期的时间看了个七七八八。
也参考了他人博客的文章。
;=========================================
;NAME:
2440INIT.S
;DESC:
Cstartupcodes
;Configurememory,ISR,stacks
;InitializeC-variables
;HISTORY:
;2002.02.25:
kwtark:
ver0.0
;2002.03.20:
purnnamu:
AddsomefunctionsfortestingSTOP,Sleepmode
;2003.03.14:
DonGo:
Modifiedfor2440.
;=========================================
GEToption.inc
GETmemcfg.inc
GET2440addr.inc
BIT_SELFREFRESHEQU(1<<22)
;Pre-definedconstants预定义6种工作模式
USERMODEEQU0x10;用户模式
FIQMODEEQU0x11;快速中断模式
IRQMODEEQU0x12;中断模式
SVCMODEEQU0x13;监管模式
ABORTMODEEQU0x17;异常中断模式
UNDEFMODEEQU0x1b;未定义模式
MODEMASKEQU0x1f;掩码
NOINTEQU0xc0;取消中断
;设置6种工作模式的堆栈的起始地址
;在option.inc中定义了_STACK_BASEADDRESSEQU0x33ff8000
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~
;检查在tasm.exe里是否设置了采用THUMB(16位)代码(armasm-16...@ADS1.0)
;判断是不是thumb指令。
GBLLTHUMBCODE;定义THUMBCODE全局变量
[{CONFIG}=16;如果发现是用16位代码的话
THUMBCODESETL{TRUE};把THUMBCODE设置为TURE
CODE32;否则是ARM模式
|
THUMBCODESETL{FALSE};把THUMBCODE设置为FALSE
]
;宏定义MOV_PC_LR,作用:
子程序返回
MACRO
MOV_PC_LR
[THUMBCODE
bxlr;在目标地址是THUMB指令,在ARM模式中
;要用BX指令转THUMB使跳到THUMB
;指令,并转换模式
|
movpc,lr;否则,就是目标地址是ARM模式,
;就直接把函数返回地址赋给PC
]
MEND
;宏定义MOVEQ_PC_LR,作用:
带相等条件判断的子程序返回。
与宏定义
;MOV_PC_LR类似
MACRO
MOVEQ_PC_LR
[THUMBCODE
bxeqlr
|
moveqpc,lr
]
MEND
;===============================================================
;下面这个宏是用于第一次查表过程的实现中断向量的重定向,如果你比较细心的话就是发现
;在_ISR_STARTADDRESS=0x33FF_FF00里定义的第一级中断向量表
;是采用型如Handle***的方式的.而在程序的ENTRY处(程序开始处)采用的是
;bHandler***的方式.
;在这里Handler***就是通过HANDLER这个宏和Handle***进立联系的.
;这种方式的优点就是正真定义的向量数据在内存空间里,而不是在ENTRY处
;的ROM(FLASH)空间里,这样,我们就可以在程序里灵活的改动向量的数据了.
;===============================================================
MACRO
$HandlerLabelHANDLER$HandleLabel
$HandlerLabel
subsp,sp,#4;减少sp(用于存放转跳地址)
stmfdsp!
{r0};把工作寄存器压入栈
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|...等比较古怪的变量是编译器生成的。
;RO,RW,ZI这三个段都保存在Flash中,但RW,ZI在Flash中
;的地址肯定不是程序运行时变量所存储的位置,因此我们的程序在初始化时应该
;把Flash中的RW,ZI拷贝到RAM的对应位置。
;这些变量是通过ADS的工程设置里面设定的ROBase和RWBase设定的,
;最终由编译脚本和连接程序导入程序.
;实际上RW,ZI在Flash中的位置就紧接着RO存储。
我们知道
;Image$$RO$$Base,Image$$RO$$Limit,那么Image$$RO$$Limit就
;是RW(ROMdata)的开始。
;===============================================================
IMPORT|Image$$RO$$Base|;ROMcode(也就是代码)的开始地址
IMPORT|Image$$RO$$Limit|;ROMcode的结束地址(=ROMdata的开始地址)IMPORT|Image$$RW$$Base|;RAM的起始地址
IMPORT|Image$$ZI$$Base|;0初始化的起始地址
IMPORT|Image$$ZI$$Limit|;0初始化的结束地址
;===============================================================
;在这里用IMPORT伪指令(和c语言的extren一样)引入外部变量MMU的快速总线
;模式和同步总线模式两个变量
;===============================================================
IMPORTMMU_SetAsyncBusMode
IMPORTMMU_SetFastBusMode
;这里引入一些在其它文件中实现在函数,包括为我们所熟知的main函数
IMPORTMain;Themainentryofmonprogram
;从这里开始就是真正的代码入口了!
AREAInit,CODE,READONLY;这表明下面的是一个名为Init的代码段
ENTRY;定义程序的入口(调试用)
EXPORT__ENTRY;导出符号_ENTRY
__ENTRY
ResetEntry
;1)Thecode,whichconvertstoBig-endian,shouldbeinlittleendiancode.
;2)ThefollowinglittleendiancodewillbecompiledinBig-Endianmode.
;Thecodebyteordershouldbechangedasthememorybuswidth.
;3)Thepseudoinstruction,DCDcannotbeusedherebecausethelinkergenerateserror.
;***********************************************************
1、ASSERT:
DEF:
ENDIAN_CHANGE
ASSERT是断言伪指令,语法是:
ASSERT+逻辑表达式
def是逻辑伪操作符,格式为:
:
DEF:
label,作用是:
判断label是否定义过
2、四句蓝色的指令能且只能执行一句,并且前三句若执行跳转后处理程序的最后一句也是
bResetHandler
3、"["相当于if
"|"相当于else
"]"相当于endif
;***************************************************************
ASSERT:
DEF:
ENDIAN_CHANGE;判断是否定义了模式改变
[ENDIAN_CHANGE
ASSERT:
DEF:
ENTRY_BUS_WIDTH;判断是否定义了总线宽度
;条件分支语句1:
如果存储器是32位的总线宽度
[ENTRY_BUS_WIDTH=32
bChangeBigEndian;DCD0xea000007
]
;条件分支语句2:
如果存储器是16位的总线宽度
[ENTRY_BUS_WIDTH=16
andeqr14,r7,r0,lsl#20;DCD0x0007ea00
]
;条件分支语句3:
如果存储器是8位的总线宽度
[ENTRY_BUS_WIDTH=8
streqr0,[r0,-r10,ror#1];DCD0x070000ea
]
|;如果没有定义总线宽度,则返回复位中断
bResetHandler
]
bHandlerUndef;handlerforUndefinedmode
bHandlerSWI;handlerforSWIinterrupt
bHandlerPabort;handlerforPAbort
bHandlerDabort;handlerforDAbort
b.;reserved
bHandlerIRQ;handlerforIRQinterrupt
bHandlerFIQ;handlerforFIQinterrupt
;@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
;如上所说,这里采用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的地址装入r9
ldrr9,[r9];把中断偏移INTOFFSET的值装入r9
ldrr8,=HandleEINT0;这就是向量表的入口HandleEINT0装入r8
;把中断服务程序装入
addr8,r8,r9,lsl#2;为什么左移两位?
不是很清楚
ldrr8,[r8];装入中断服务程序的入口
strr8,[sp,#8];把入口压入堆栈
ldmfdsp!
{r8-r9,pc};出栈
LTORG;声明文字池
;=======
;ENTRY(CPU复位的入口)
;=======
ResetHandler
ldrr0,=WTCON;关看门狗
ldrr1,=0x0
strr1,[r0]
ldrr0,=INTMSK
ldrr1,=0xffffffff;关中断
strr1,[r0]
ldrr0,=INTSUBMSK
ldrr1,=0x7fff;关子中断
strr1,[r0]
[{TRUE}
;rGPFDAT=(rGPFDAT&~(0xf<<4))|((~data&0xf)<<4);
;点led灯
ldrr0,=GPBCON
ldrr1,=0x00555555
strr1,[r0]
ldrr0,=GPBDAT
ldrr1,=0x07fe
strr1,[r0]
]
;ToreducePLLlocktime,adjusttheLOCKTIMEregister.
ldrr0,=LOCKTIME
ldrr1,=0xffffff
strr1,[r0]
[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,4=1:
4:
4,5=1:
4:
8,6=1:
3:
3,7=1:
3:
6.
strr1,[r0]
;MMU_SetAsyncBusModeandMMU_SetFastBusModeover4K,sodonotcallhere
;callitaftercopy
;[CLKDIV_VAL>1;meansFclk:
Hclkisnot1:
1.
;blMMU_SetAsyncBusMode
;|
;blMMU_SetFastBusMode;defaultvalue.
;]
;===============================================================
;MMU_SetAsyncBusMode和MMU_SetFastBusMode都在4K代码以上(三星就提供4K的内部SRAM),
;如果你想你编译出来的程序能在NAND上运行的话,就不能在这调用这两函数了.
;如果你不要求的话,你就可以直接调用
;下面的代码就是实现和上面两函数一样的功能.
;利用的协处理器的命令实现了对总线模式的设置
;===============================================================
;programhasnotbeencopied,sousethesedirectly
[CLKDIV_VAL>1;meansFclk:
Hclkisnot1:
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
]
;ConfigureUPLL.配置MPLL一定要使最后的频率为16.9344MHz,不然你甭想用USB接口了,
ldrr0,=UPLLCON
ldrr1,=((U_MDIV<<12)+(U_PDIV<<4)+U_SDIV)
strr1,[r0]
nop;Caution:
AfterUPLLsetting,atleast7-clocksdelaymustbeinsertedforsettinghardwarebecompleted.
nop
nop
nop
nop
nop
nop
;ConfigureMPLL
ldrr0,=MPLLCON
ldrr1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV);Fin=16.9344MHz
strr1,[r0]
]
;Checkifthebootiscausedbythewake-upfromSLEEPmode.
ldrr1,=GSTATUS2
ldrr0,[r1]
tstr0,#0x2;CheckGSTATUS2[2]inordertoknowwhetherornot
;thepower-upiscausedbythewake-upfromSLEEPmode.
bneWAKEUP_SLEEP;如果是,则跳转到WAKEUP_SLEEP
EXPORTStartPointAfterSleepWakeUp;定义外部的StartPointAfterSleepWakeUp
StartPointAfterSleepWakeUp
;===============================================================
;设置存储器控制寄存器,此段代码把13个存储控制器的内容批量的读取到了对应的特殊功能寄存器中
;首先是有一个数据区SMRDATA,在程序的后面有定义,这个数据区给13个寄存器分配52字节的地址空间。
在下面
;的代码中,r0是这个数据区的起始地址,r2是数据区的结束地址,r1是寄存器的起始地址。
这样,用一个判断语句
;cmpr2,r0
;bne%B0,就可以把内存中的数据赋给这13个存储控制寄存器了。
;===============================================================
;ldrr0,=SMRDATA
adrlr0,SMRDATA;becareful!
ldrr1,=BWSCON;BWSCONAddress
addr2,r0,#52;EndaddressofSMRDATA
0
ldrr3,[r0],#4
strr3,[r1],#4
cmpr2,r0
bne%B0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;WhenEINT0ispressed,ClearSDRAM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;checkifEIN0buttonispressed
ld
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 2440 init 解析