2410Init.s详细注释分析Crealse.Sheng第1页共28页S3C2410启动程序设计——2410Init.s详细分析工程里面的头文件2410Init.s包括了板子上电后的初始化(与vivi很相似),具体有几个步骤:1.屏蔽所有中断,关看门狗。2.根据工作频率设置PLL寄存器3.初始化存储控制相关寄存器4.初始化各模式下的栈指针5.设置缺省中断处理函数6.将数据段拷贝到RAM中,将零初始化数据段清零7.跳转到C语言Main入口函数中在开发板上跑了一遍,基本过程已经清晰,还有些细节问题有待进一步深入研究!将这个程序注释了一下,可能有些地方不是很正确,只提供参考。;=========================================;NAME:2410INIT.S;DESC:Cstartupcodes;Configurememory,ISR,stacks;InitializeC-variables;HISTORY:;2002.02.25:kwtark:ver0.0;2002.03.20:purnnamu:AddsomefunctionsfortestingSTOP,POWER_OFFmode;2002.04.10:SJS:subinterruptdisable0x3ff-0x7ff;2002.11.29:Kong:DCDBANKSIZEResiger0x32-0xb2(ARMcoreburstenable);=========================================INCLUDEoption.incINCLUDEmemcfg.incINCLUDE2410addr.incBIT_SELFREFRESHEQU(122);下面是对arm处理器模式寄存器对应值的常数定义,arm处理器中有一个CPSR程序状态寄存器,它的后五位决定目前的处理器模式;Pre-definedconstants批注[Crealse1]:这些文件定义了一些地址数据等2410Init.s详细注释分析Crealse.Sheng第2页共28页USERMODEEQU0x10FIQMODEEQU0x11IRQMODEEQU0x12SVCMODEEQU0x13ABORTMODEEQU0x17UNDEFMODEEQU0x1bMODEMASKEQU0x1fNOINTEQU0xc0;ThelocationofstacksUserStackEQU(_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~;checkiftasm.exeisused.;arm处理器有两种工作状态:1.arm:32位这种工作状态下执行字对准的arm指令2.Thumb:16位这种工作状;态执行半字对准的Thumb指令;因为处理器分为16位32位两种工作状态,程序的编译器也是分16位和32两种编译方式,所以下面的程序用于根据处理器工作状态确定编译器编译方式;code16伪指令指示汇编编译器后面的指令为16位的thumb指令;code32伪指令指示汇编编译器后面的指令为32位的arm指令;这段是为了统一目前的处理器工作状态和软件编译方式(16位编译环境使用tasm.exe编译;Checkiftasm.exe(armasm-16...@ADS1.0)isused.GBLLTHUMBCODE[{CONFIG}=16;ifconfig==16这里表示你的目前处于领先地16位编译方式THUMBCODESETL{TRUE};设置THUMBCODE为trueCODE32;转入32位编译模式|;else批注[Crealse2]:_STACK_BASEADDRESSEQU0x33ff8000_MMUTT_STARTADDRESSEQU0x33ff8000_ISR_STARTADDRESSEQU0x33ffff00批注[Crealse3]:各有优缺点:执行效率、占用空间2410Init.s详细注释分析Crealse.Sheng第3页共28页THUMBCODESETL{FALSE};设置THUMBCODE为false]MACROMOV_PC_LR[THUMBCODEbxlr|movpc,lr]MENDMACROMOVEQ_PC_LR[THUMBCODEbxeqlr|moveqpc,lr]MEND;注意下面这段程序是个宏定义很多人对这段程序不理解我再次强调这是一个宏定义所以大家要注意了;下面包含的HandlerXXXHANDLERHandleXXX将都被下面这段程序展开;这段程序用于把中断服务程序的首地址装载到pc中,有人称之为“加载程序”。;本初始化程序定义了一个数据区(在文件最后),34个字空间,存放相应中断服务程序的首地址。;每个字空间都有一个标号,以Handle***命名。;在向量中断模式下使用“加载程序”来执行中断服务程序。;这里就必须讲一下向量中断模式和非向量中断模式的概念;向量中断模式是当cpu读取位于0x18处的IRQ中断指令的时候,系统自动读取对应于该中断源确定地址上的指令取代0x18处的指令,通过跳转指令系统就直接跳转到对应地址函数中,节省了中断处理时间提高了中断处理速度标。例如ADC中断的向量地址为0xC0,则在0xC0处放如下代码:ldrPC,=HandlerADC当ADC中断产生的时候系统会自动跳转到HandlerADC函数中。;非向量中断模式处理方式是一种传统的中断处理方法,当系统产生中断的时候,系统将interruptpendi批注[Crealse4]:宏定义!批注[Crealse5]:两种主要的中断方式!!2410Init.s详细注释分析Crealse.Sheng第4页共28页ng寄存器中对应标志位置位,然后跳转到位于0x18处的统一中断函数中,该函数通过读取interruptpending寄存器中对应标志位来判断中断源,并根据优先级关系再跳到对应中断源的处理代码中。MACRO$HandlerLabelHANDLER$HandleLabel;HandlerLabel为中断服务入口地址$HandlerLabelsubsp,sp,#4;decrementsp(tostorejumpaddress);将要使用的r0寄存器入栈stmfdsp!,{r0};PUSHtheworkregistertostack(lrdoes'tpushbecauseitreturntooriginaladdress)ldrr0,=$HandleLabel;loadtheaddressofHandleXXXtor0ldrr0,[r0];loadthecontents(serviceroutinestartaddress)ofHandleXXX;将对应的中断函数首地址入栈strr0,[sp,#4];storethecontents(ISR)ofHandleXXXtostack;将中断函数首地址出栈,放入程序指针中,系统将跳转到对应中断处理函数ldmfdsp!,{r0,pc};POPtheworkregisterandpc(jumptoISR)MEND;一个arm由RO,RW,ZI三个断组成——其中RO为代码段,RW是已经初始化的全局变量,ZI是未初始化的全局变量(对于GNU工具对应的概念是TEXT,DATA,BSS);bootloader要将RW段复制到ram中并将ZI段清零,编译器使用下列段来记录各段的起始和结束地址;|Image$$RO$$Base|;RO段起始地址;|Image$$RO$$Limit|;RO段结束地址加1;|Image$$RW$$Base|;RW段起始地址;|Image$$RW$$Limit|;RW段结束地址加1;|Image$$ZI$$Base|;ZI段起始地址;|Image$$ZI$$Limit|;ZI段结束地址加1;这些标号的值是通过编译器的设定来确定的,如编译软件中对ro-base和rw-base的设定,例如ro-;base=0x3000000rw-base=0x33F0000IMPORT|Image$$RO$$Limit|;EndofROMcode(=startofROMdata)批注[Crealse6]:中断服务宏:保存现场,装载中断函数地址,产生跳转批注[Crealse7]:在编译器中设置的地址作用在这里!2410Init.s详细注释分析Crealse.Sheng第5页共28页IMPORT|Image$$RW$$Base|;BaseofRAMtoinitialiseIMPORT|Image$$ZI$$Base|;BaseandlimitofareaIMPORT|Image$$ZI$$Limit|;tozeroinitialiseIMPORTMain;ThemainentryofmonprogramAREAInit,CODE,READONLY;异常中断矢量表(每个表项占4个字节),下面是中断向量表,一旦系统运行时有中断发生,即使移植了;操作系统如linux,处理器已经把控制权交给了操作系统,一旦发生中断,处理器还是会跳转到从0x0;开始中断向量表中某个中断表项(依据中断类型)开始执行;具体中断向量布局请参考s3c44b0spec,例如adc中断向量为0x000000c0,下面对应表中第49项位置向量地址0x0+4*(49-1)=0x000000c0ENTRY;板子上电和复位后,程序开始从位于0x0处开始执行硬件刚刚上电复位后,程序从这里开始执行跳转到;标为ResetHandler处执行;1)Thecode,whichconvertstoBig-endian,shouldbeinlittleendiancode.;2)ThefollowinglittleendiancodewillbecompiledinBig-Endianmode.;Thecodebyteordershouldbechangedasthememorybuswidth.;3)Thepseudoinstruction,DCDcan'tbeusedherebecausethelinkergenerateserror.;总线宽度判断;DCD用于分配一段字内存单片,并用后面的伪指令初始化;分配字节由expr个数决定ASSERT:DEF:ENDIAN_CHANGE[ENDIAN_CHANGEASSERT:DEF:ENTRY_BUS_WIDTH[ENTRY_BUS_WIDTH=32bChangeBigEndian;DCD0xea000007]批注[Crealse8]:相当于复位操作!2410Init.s详细注释分析Crealse.Sheng第6页共28页[ENTRY_BUS_WIDTH=16andeqr14,r7,r0,lsl#20;DCD0x0007ea00][ENTRY_BUS_WIDTH=8streqr0,[r0,-r10,ror#1];DCD0x070000ea]|bResetHandler]bHandlerUndef;handlerforUndefinedmodebHandlerSWI;handlerforSWIinterruptbHandlerPabort;handlerforPAbortbHandlerDabort;handlerforDAbortb.;reserved0x14bHandlerIRQ;handlerforIRQinterruptbHa