arm启动代码分析
?
/*文件名:2440init.s ;*功能:2440启动代码,实现硬件初始化及存储空间的映射等 ;*设计者:enjoymylinux ;*设计时间:2010.2.10 ;*版本:V1.0 ;*参考程序:友善之臂启动代码及sumsang的bootloader源代码vivi ;*/ ? ;//注意点:由于ARM是32位的,一般都按照32位的字对齐 ? ;//64M SDRAM?内存空间分配状况 ;//0x3000_0000???内存起始地址 ;//???????????????????????>???supervivi下载程序的缓存空间???共16M ;//0x3100_0000 ;//???????????????????????>?????程序的运行空间 ;//0x31ff_0000 ;//???????????????????????>?????堆栈空间???????? ;//0x33ff_8000 ;//?????????????????????????????????预保留空间 ;//0x33ff_ff00 ;//???????????????????????>?????中断向量表 ;//0x3400_0000???内存结束地址 ? ;//系统引导及启动过程 ;//(1)硬件初始化????????关闭看门狗,屏蔽所有中断 ;//(2)时钟初始化????????调整PLL锁相环到合适频率 ;//(3)开启总线状态指示灯 ;//(4)检测启动状态??????boot启动还是外界唤醒恢复? ;//(5)初始化内存????????设置SDRAM寄存器,擦除内存 ;//(6)初始化FLASH???????设置FLASH寄存器,检测启动物理位置 ;//(7)拷贝代码到内存????NOR FLASH可以直接运行;NAND FLASH必须拷贝到RAM中才行 ;//(8)跳转到Main去执行 ? ? ? ? ;//包含头文件,注意:在汇编程序中头文件后缀名为.inc,而在C程序中后缀名为.h ;// option.inc???定义配置PLL及总线宽度寄存器位 ;// memcfg.inc???定义存储器的寄存器的位定义 ;// 2440addr.inc 2440各寄存器的地址 ;//获取头文件,其中GET可用include来代替,两者可以互换 ?????????GET option.inc ?????????GET memcfg.inc ?????????GET 2440addr.inc ? BIT_SELFREFRESH EQU???(1<<22) ? ;//定义一些常量,EQU相当#define语句 ;//处理器各工作模式定义,即CPSR中后五位CPSR[4:0] USERMODE????EQU?????0x10 FIQMODE?????EQU???????0x11 IRQMODE?????EQU??????0x12 SVCMODE?????EQU??????0x13 ABORTMODE???EQU????0x17 UNDEFMODE???EQU????0x1b MODEMASK????EQU????0x1f ;//CPSR[7:5] I_BIT??????EQU??????0x80??;//中断位 F_BIT??????EQU??????0x40??;//快速中断位 T_BIT??????EQU??????0x20??;//指令模式状态位 NOINT??????EQU?????????0xc0??;//屏蔽中断位 ? ;//定义stack的地址,其中_STACK_BASEADDRESS代表堆栈基地址 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 ~ ? ;//检测是thumb指令集还是arm指令集 ?????????GBLL????THUMBCODE???????????????????????;//定义一个全局变量 ?????????[ {CONFIG} = 16?????????????????????????;// #if(CONFIG=16) THUMBCODE SETL??{TRUE}??????????????????????;//????THUMBCODE=TRUE; ?????????????CODE32??;//说明此后代码为arm指令??????????? ?????????????????|??????????????????????????????????????????????????????????????????????????????????;// #else THUMBCODE SETL??{FALSE}?????????????????????;//????THUMBCODE=FALSE; ????] ;//宏定义 ?????????????????MACRO???????;//宏定义开始 ?????????MOV_PC_LR???????;//宏名称 ?????????????????[ THUMBCODE ?????????????bx lr ?????????????????| ?????????????mov?pc,lr ?????????????????] ?????????MEND???????????;//宏定义结束 ;//宏定义 ?????????????????MACRO ?????????MOVEQ_PC_LR ?????????????????[ THUMBCODE ????????bxeq lr ??????????????????| ?????????????moveq pc,lr ?????????????????] ?????????MEND ;//带参数的宏定义 ;//宏定义,作用是当发生中断时,将中断服务程序的首地址装载到PC中 ;//$HandlerLabel HANDLER(宏名称)?$HandleLabel(宏的参数) ;//********************************************************* ?????????????????MACRO $HandlerLabel HANDLER $HandleLabel ? $HandlerLabel ?????????sub???sp,sp,#4????????????;//SP减4,为了存储跳转地址 ?????????stmfd????????sp!,{r0}??????????;//将工作寄存器压入堆栈, ????ldr?????r0,=$HandleLabel ;//装载HandleLable的地址到r0 ?????????ldr?????r0,[r0]??????????????????;//装载HandleLable的内容到r0,即服务程序的地址 ?????????str?????r0,[sp,#4]???????;//存储HandleLable的内容到堆栈 ?????????ldmfd???sp!,{r0,pc}??????;//恢复r0的内容,并使PC跳转到HandleLable,即中断服务的首地址 ?????????MEND ;//********************************************************* ;//声明、通知编译器标号在其他源文件中定义,但要在本文件中调用 ;//一个ARM程序是由RO、RW、ZI三段组成(具体可见编译器生成的空间分配list文件) ;//RO代码段(只读)??RW?已经初始化的全局变量(读写)?ZI未初始化的全局变量(零初始化) ;//这些地址是通过编译器的设定来确定的 ?????????IMPORT??|Image$$RO$$Base|?????;//RO段起始地址 ?????????IMPORT??|Image$$RO$$Limit|??;//RO段结束地址加1 ?????????IMPORT??|Image$$RW$$Base|???;//RW段起始地址 ?????????IMPORT??|Image$$RW$$Limit|??;//RW段结束地址加1 ?????????IMPORT??|Image$$ZI$$Base|???;//ZI段起始地址 ?????????IMPORT??|Image$$ZI$$Limit|??;//ZI段结束地址加1 ??? ?????????IMPORT???MMU_SetAsyncBusMode ?????????IMPORT???MMU_SetFastBusMode??; ? ?????????IMPORT??Main????;//C代码的入口点 ;//**********************************************************8 ;//定义一个代码段,段名为Init,属性:代码,只读 ?????????AREA????Init,CODE,READONLY ;//声明入口点,整个镜像从这个地方开始执行,一般来说一个文件里只能有一个 ?????????ENTRY ;//声明一个全局标号,可以在其他文件中被引用???? ?????????EXPORT????__ENTRY __ENTRY?????;//__ENTRY标号 ResetEntry??;//ResetEntry标号 ;//指令?b?:跳转指令,后加代码段标号,程序执行到此处时将会跳转到相应的代码段执行? ?????????;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???;;//断言伪定义,假定后面的ENDIAN标识已经定义 ???????? ?????????[ ENDIAN_CHANGE ?????????????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 ????] ;/**********************************************************/ ;//中断向量表vertor table ?????????b???????HandlerUndef??;handler for Undefined mode ?????????b???????HandlerSWI??????????;handler for SWI interrupt ?????????b???????HandlerPabort??????????;handler for PAbort ?????????b???????HandlerDabort?????????;handler for DAbort ?????????b??????????????.??????????;reserved ?????????b???????HandlerIRQ??????????;handler for IRQ interrupt ?????????b???????HandlerFIQ???????????;handler for FIQ interrupt ? ? ?????????b???????EnterPWDN?????; Must be @0x20. ;/***********************************************************/ ;//ChangeBigEndian标号 ChangeBigEndian ;//?符号[]相当于编译指令#if····#else??????···· ;//通过编译指令,不同的总线宽度采取不同的存储单元分配措施 ;//伪汇编指令DCD?用于分配一片连续的字节存储单元 ?????????[ ENTRY_BUS_WIDTH=32 ?????????????DCD?0xee110f10??????;0xee110f10 => mrc p15,c1,c0,0 ?????????????DCD?0xe3800080?????;0xe3800080 => orr r0,#0x80;??//Big-endian ?????????????DCD?0xee010f10??????;0xee010f10 => mcr p15,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 ;//宏展开,正确理解代码内容,代码要按规则编写,不要引起误解 ;//代码标号相当于C语言中的函数,标号后的代码内容为函数的内容,即函数的具体实现过程????????????? HandlerFIQ??? ???????????HANDLER HandleFIQ HandlerIRQ??? ???????????HANDLER HandleIRQ HandlerUndef? ???????????HANDLER HandleUndef HandlerSWI??? ???????????HANDLER HandleSWI HandlerDabort? ???????????HANDLER HandleDabort HandlerPabort ??????HANDLER HandlePabort ;//IsrIRQ代码段,实现中断服务程序的跳转 IsrIRQ ?????????sub???sp,#4???????;reserved for PC ?????????stmfd????????sp!,{r8-r9} ? ?????????ldr????r9,=INTOFFSET ?????????ldr????r9,[r9] ?????????ldr????r8,=HandleEINT0 ?????????add??r8,r8,r9,lsl #2 ?????????ldr????r8,[r8] ?????????str????r8,#8] ?????????ldmfd????????sp!,{r8-r9,pc} ? ? ?????????LTORG ;/*************************************************************************************/ ;//声明一个标号ResetHandler,当其他处引用此标号时,程序跳转到此处执行 ;//ResetHandler代码段 ResetHandler ?????;//禁止看门狗 ?????????ldr????r0,=WTCON???????;//把寄存器WTCON的地址装入R0,watch dog disable ?????????ldr????r1,=0x0???????????????????????;//把0装入R1 ?????????str????r1,[r0]??????????;//把R1内的值赋给地址为R0的存储区域,即WTCON,这三条语句相当于?WTCON=0x0; ????;//禁止所有中断 ?????????ldr????r0,=INTMSK ?????????ldr????r1,=0xffffffff??;all interrupt disable ?????????str????r1,[r0]?????????;//这三条语句相当于?INTMSK=0xffffffff; ????;//禁止所有次级中断 ?????????ldr????r0,=INTSUBMSK ?????????ldr????r1,=0x7fff???????????????????;all sub interrupt disable ?????????str????r1,[r0]?????????;//这三条语句相当于?INTSUBMSK=0x7ffff; ? ????//打开状态指示灯LED ?????????[ {TRUE} ?????????;rGPFDAT = (rGPFDAT & ~(0xf<<4)) | ((~data & 0xf)<<4); ?????????; Led_Display ?????????ldr????r0,=GPBCON ?????????ldr????r1,=0x00555555 ?????????str????r1,[r0]?????????????????????????;//即GPCON=0x00555555; ???????? ?????????ldr????r0,=GPBDAT ?????????ldr????r1,=0x07fe ?????????str????r1,[r0]?????????????????????????;//即GPBDAT=0x07fe; ?????????] ? ?????????;//To reduce PLL lock time,adjust the LOCKTIME register. ?????????ldr????r0,=LOCKTIME ?????????ldr????r1,=0xffffff ?????????str????r1,[r0]?????????????????????????;//即LOCKTIME=0xffffff; ;/************************************************************************************/ ????[ 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]???????????????????????????????????;//即CLKDIVN=CLKDIV_VAL; ? ?????????;//协处理器操作,MMU和CACHE属于P15协处理器,ARM处理器共支持多达16个协处理器 ?? ?????????[ CLKDIV_VAL>1???????????????; means Fclk:Hclk is not 1:1. ?????????mrc p15,0???????;//???? ?????????orr r0,#0xc0000000??????;R1_nF:OR:R1_iA ?????????mcr p15,0 ?????????| ?????????mrc p15,0 ?????????bic r0,#0xc0000000;R1_iA:OR:R1_nF ?????????mcr p15,0 ?????????], ???????? ?????????;//Configure UPLL ?????????ldr????r0,=UPLLCON ?????????ldr????r1,=((U_MDIV<<12)+(U_PDIV<<4)+U_SDIV)? ?????????str????r1,[r0]?????????????????????????;//即UPLLCON=((U_MDIV<<12)+(U_PDIV<<4)+U_SDIV) ?????????;//nop指令,不进行任何操作,空指令 ?????????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]????????????????????????????????????????????;//即MPLLCON=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV) ????] ;/************************************************************************************/ ?????????;Check if the boot is caused by the wake-up from SLEEP mode. ?????????ldr????r1,=GSTATUS2 ?????????ldr????r0,[r1] ?????????tst????r0,#0x2??????????????????????????????????????????;//TST位测试指令,逻辑与操作,更新CPSR中相应的标志位 ?????????;In case of the wake-up from SLEEP mode,go to SLEEP_WAKEUP handler. ?????????bne??WAKEUP_SLEEP????????????;//条件跳转指令,bne(b if not equal),beq(b if equal) ? ?????????EXPORT StartPointAfterSleepWakeUp??;//声明外部可以引用 StartPointAfterSleepWakeUp ?????????;//内存控制初始化 ?????????;//adrl?地址读取伪指令,谨慎使用,编译器将其分解成两条指令,若不能成功分解会报错 ?????????;//这段代码实现了8个BANK寄存器值的设定 ????????adrl??r0,SMRDATA?? ?????????ldr????r1,=BWSCON???;BWSCON Address ?????????add??r2,#52????????;End address of SMRDATA ? 0 ?????????ldr????r3,[r0],#4??;//将地址为r0中的内容装载到r3,然后r0中的值加4,即指向下一个字 ?????????str????r3,[r1],#4??;//注意8个BANK控制寄存器的地址是靠着的 ?????????cmp?r2,r0????????????????????;//CMP指令会更新CPSR中的相应标志位,后面的指令根据此标志位来决定是否执行相应的操作 ?????????bne??%B0???????????;//如果不相等就向后跳转到标号0,类似一个循环,直到r0=r2 ? ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;???????When EINT0 is pressed,??Clear SDRAM ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;//check if EIN0 button is pressed ;//当EIN0发生时先清除SDRAM再初始化堆栈,若没有发生则跳过SDRAM的清除阶段, ;//直接去初始化堆栈 ????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,#(0x1e<<1)??;//bit clear?在值为1时清零 ?????????tst????r0,#0x1???????????????????????;//按位与 ?????????bne %F1??????;//如果not equal?向前跳转到标号1 ???????? ???????? ? ;// Clear SDRAM Start ? ?????????ldr????r0,=0x55aa ?????????str????r1,=GPFDAT ?????????ldr????r1,[r0]???????;LED=**** ;//所有的寄存器都清零 ?????????mov r1,#0 ?????????mov r2,#0 ?????????mov r3,#0 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |