init.s文件详细解析
2440init.s文件详细解析;=========================================; 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 s for testing STOP,Sleep mode; 2003.03.14:DonGo: Modified for 2440.;=========================================;首先,启动代码定义了一些常量GET option.incGET memcfg.incGET 2440addr.incBIT_SELFREFRESH EQU (1<<22);处理器模式常量USERMODE EQU 0x10FIQMODE EQU 0x11IRQMODE EQU 0x12SVCMODE EQU 0x13ABORTMODE EQU 0x17UNDEFMODE EQU 0x1bMODEMASK EQU 0x1fNOINT EQU 0xc0;定义处理器各模式下堆栈地址常量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 ~;检查在tasm.exe里是否设置了采用THUMB(16位)代码(armasm -16 ...@ADS 1.0)GBLL THUMBCODE ;定义THUMBCODE全局变量[ {CONFIG} = 16 ;如果发现是才用16位代码的话,CONFIG为汇编器的内置变量THUMBCODE SETL {TRUE} ;把THUMBCODE设置为TURECODE32 ;把处理器从新设置成为ARM模式| ;如果处理器现在就是ARM模式THUMBCODE SETL {FALSE} ;把THUMBCODE设置为FALSE就行了]MACRO ;一个根据THUMBCODE把PC寄存的值保存到LR的宏, 宏 MOV_PC_LRMOV_PC_LR[ THUMBCODEbx lr ;在ARM模式中要使用BX指令转跳到THUMB指令,并转换模式|mov pc,lr ;如果目标地址也是ARM指令的话就采用这种方式]MENDMACRO ;和上面的宏一样,只是多了一个相等的条件MOVEQ_PC_LR[ THUMBCODEbxeq lr|moveq pc,lr]MEND;==================================================================== ===================;下面这个宏是用于第一次查表过程的实现中断向量的重定向,如果你比较细心的话就是发现;在_ISR_STARTADDRESS=0x33FF_FF00里定义的第一级中断向量表是采用型如Ha ndle***的方式的.;而在程序的ENTRY处(程序开始处)采用的是b Handler***的方式.;在这里Handler***就是通过HANDLER这个宏和Handle***进立联系的.;这种方式的优点就是正真定义的向量数据在内存空间里,而不是在ENTRY处的R OM(FLASH)空间里,;这样,我们就可以在程序里灵活的改动向量的数据了.;==================================================================== ====================MACRO$HandlerLabel HANDLER $HandleLabel$HandlerLabelsub sp,sp,#4 ;减少sp(用于存放转跳地址)stmfd sp!,{r0} ;把工作寄存器压入栈(lr does not push because it retur n to original address)ldr r0,=$HandleLabel;将HandleXXX的址址放入r0ldr r0,[r0] ;把HandleXXX所指向的内容(也就是中断程序的入口)放入r0 str r0,[sp,#4] ;把中断服务程序(ISR)压入栈ldmfd sp!,{r0,pc} ;用出栈的方式恢复r0的原值和为pc设定新值(也就完成了到ISR的转跳)MEND;========================================================== ===============================;在这里用IMPORT伪指令(和c语言的extren一样)引入|Image$$RO$$Base|,|I mage$$RO$$Limit|...;这些变量是通过ADS的工程设置里面设定的RO Base和RW Base设定的, ;最终由编译脚本和连接程序导入程序.;那为什么要引入这玩意呢,最简单的用处是可以根据它们拷贝自已;========================================================== ================================IMPORT |Image$$RO$$Base| ; ROM code(也就是代码)的开始地址IMPORT |Image$$RO$$Limit| ; ROM code的结束地址(=ROM data的开始地址)IMPORT |Image$$RW$$Base| ; 要初始化的RAM的开始地址IMPORT |Image$$ZI$$Base| ; area(需要清零的RAM区域)的开始地址IMPORT |Image$$ZI$$Limit| ; area的结束地址;这里引入一些在其它文件中实现在函数,包括为我们所熟知的main函数IMPORT MMU_SetAsyncBusModeIMPORT MMU_SetFastBusMode ;hzhIMPORT Main ; The main entry of mon program;从这里开始就是正真的代码入口了!AREA Init,CODE,READONLY ;这表明下面的是一个名为Init的代码段ENTRY ;定义程序的入口(调试用)EXPORT __ENTRY ;导出符号_ENTRY,但在那用到就还没查明__ENTRYResetEntry;1)The code, which converts to Big-endian, should be in little endian co de.;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_CHANGE ;下面是大小端的一个判断,在Option.inc里已经设为F ALSEASSERT :DEF:ENTRY_BUS_WIDTH[ ENTRY_BUS_WIDTH=32b ChangeBigEndian ;DCD 0xea000007][ ENTRY_BUS_WIDTH=16andeq r14,r7,r0,lsl #20 ;DCD 0x0007ea00][ ENTRY_BUS_WIDTH=8streq r0,[r0,-r10,ror #1] ;DCD 0x070000ea]|b ResetHandler ;设成FALSE的话就来到这了,转跳到复位程序入口]b HandlerUndef ;转跳到Undefined mode程序入口b HandlerSWI ;转跳到SWI 中断程序入口b HandlerPabort ;转跳到PAbort(指令异常)程序入口b HandlerDabort ;转跳到DAbort(数据异常)程序入口b . ;保留b HandlerIRQ ;转跳到IRQ 中断程序入口b HandlerFIQ ;转跳到FIQ 中断程序入口;@0x20b EnterPWDN ; Must be @0x20.;========================================================== ========================;下面是改变大小端的程序,这里采用直接定义机器码的方式,至说为什么这么做就得问三星了;反正我们程序里这段代码也不会去执行,不用去管它;========================================================== ========================ChangeBigEndian;@0x24[ ENTRY_BUS_WIDTH=32DCD 0xee110f10 ;0xee110f10 => mrc p15,0,r0,c1,c0,0DCD 0xe3800080 ;0xe3800080 => orr r0,r0,#0x80; //Big-endianDCD 0xee010f10 ;0xee010f10 => mcr p15,0,r0,c1,c0,0][ ENTRY_BUS_WIDTH=16DCD 0x0f10ee11DCD 0x0080e380DCD 0x0f10ee01][ ENTRY_BUS_WIDTH=8DCD 0x100f11eeDCD 0x800080e3DCD 0x100f01ee]DCD 0xffffffff ;swinv 0xffffff is similar with NOP and run well in both e ndian mode.DCD 0xffffffffDCD 0xffffffffDCD 0xffffffffDCD 0xffffffffb ResetHandler;如上所说,这里采用HANDLER宏去建立Hander***和Handle***之间的联系HandlerFIQ HANDLER HandleFIQHandlerIRQ HANDLER HandleIRQHandlerUndef HANDLER HandleUndefHandlerSWI HANDLER HandleSWIHandlerDabort HANDLER HandleDabortHandlerPabort HANDLER HandlePabort;========================================================== =========================;呵呵,来了来了.好戏来了,这一段程序就是用来进行第二次查表的过程了.;如果说第一次查表是由硬件来完成的,那这一次查表就是由软件来实现的了.;为什么要查两次表??;没有办法,ARM把所有的中断都归纳成一个IRQ中断异常和一个FIRQ中断异常;第一次查表主要是查出是什么异常,可我们总要知道是这个中断异常中的什么中断呀!;没办法了,再查一次表呗!;========================================================== =========================IsrIRQsub sp,sp,#4 ;给PC寄存器保留stmfd sp!,{r8-r9} ;把r8-r9压入栈ldr r9,=INTOFFSET ;把INTOFFSET的地址装入r9ldr r9,[r9] ;把INTOFFSET的值装入r9ldr r8,=HandleEINT0 ;这就是我们第二个中断向量表的入口的,先装入r8;========================================================== =========================;哈哈,这查表方法够好了吧,r8(入口)+index*4(别望了一条指令是4 bytes的喔), ;这不就是我们要找的那一项了吗.找到了表项,下一步做什么?肯定先装入了!;========================================================== ========================add r8,r8,r9,lsl #2ldr r8,[r8] ;装入中断服务程序的入口str r8,[sp,#8] ;把入口也入栈,准备用旧招ldmfd sp!,{r8-r9,pc} ;施招,弹出栈,哈哈,顺便把r8弹出到PC,O了,跳转成功! LTORG ;声明文字池,因为我们用了ldr伪指令;========================================================== ====================; ENTRY(好了,我们的CPU要在这复位了.);========================================================== ====================ResetHandlerldr r0,=WTCON ;1.关看门狗ldr r1,=0x0str r1,[r0]ldr r0,=INTMSKldr r1,=0xffffffff ;2.关中断str r1,[r0]ldr r0,=INTSUBMSKldr r1,=0x7fff ;3.关子中断str r1,[r0][ {FALSE} ;4.得有些表示了,该点点LED灯了,不过被FALSE掉了.;rGPFDAT = (rGPFDAT & ~(0xf<<4)) | ((~data & 0xf)<<4);; Led_Displayldr r0,=GPFCONldr r1,=0x5500str r1,[r0]ldr r0,=GPFDATldr r1,=0x10str r1,[r0]];5.为了减少PLL的lock time, 调整LOCKTIME寄存器.ldr r0,=LOCKTIMEldr r1,=0xffffffstr r1,[r0][ PLL_ON_START ;6.下面就来设置PLL了,你的板快不快就看这了!!; Added for confirm clock divide. for 2440.; 设定Fclk:Hclk:Pclkldr r0,=CLKDIVNldr r1,=CLKDIV_VAL ; 0=1:1:1, 1=1:1:2, 2=1:2:2, 3=1:2:4,str r1,[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.; bl MMU_SetAsyncBusMode; |; bl MMU_SetFastBusMode ; default value.; ][ CLKDIV_VAL>1 ; 意思是Fclk:Hclk 不是1:1.mrc p15,0,r0,c1,c0,0orr r0,r0,#0xc0000000;R1_nF:OR:R1_iAmcr p15,0,r0,c1,c0,0|mrc p15,0,r0,c1,c0,0bic r0,r0,#0xc0000000;R1_iA:OR:R1_nFmcr p15,0,r0,c1,c0,0];配置UPLLldr r0,=UPLLCONldr r1,=((U_MDIV<<12)+(U_PDIV<<4)+U_SDIV)str r1,[r0]nop ; Caution: After UPLL setting, at least 7-clocksnop ; delay must be inserted for setting hardware be completed.nopnopnopnopnop;配置MPLL 一定要使最后的频率为16.9344MHz,不然你甭想用USB接口了,哈哈.ldr r0,=MPLLCONldr r1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV)str r1,[r0]];检查是否从SLEEP模式中恢复ldr r1,=GSTATUS2ldr r0,[r1]tst r0,#0x2;如果是从SLEEP模式中恢复, 转跳到SLEEP_WAKEUP.bne WAKEUP_SLEEPEXPORT StartPointAfterSleepWakeUp ;导出符号StartPointAfterSleepWake UpStartPointAfterSleepWakeUp;========================================================== =====================;设置内存控制器等寄存器的值,因为这些寄存器是连续排列的,所以采用如下办法对这些;寄存器进行连续设置.其中用到了SMRDATA的数据,这在代码后面有定义;========================================================== =====================;ldr r0,=SMRDATAadrl r0, SMRDATA;be careful!, hzhldr r1,=BWSCON ;BWSCON 地址add r2, r0, #52 ;SMRDATA数据的结束地址,共有52字节的数据ldr r3, [r0], #4str r3, [r1], #4cmp r2, r0bne %B0;========================================================== ======================;如果EINT0 产生(这中断就是我们按键产生的), 就清除SDRAM ,不过好像没人会在这个时候按;========================================================== ======================; check if EIN0 button is pressedldr r0,=GPFCONldr r1,=0x0str r1,[r0]ldr r0,=GPFUPldr r1,=0xffstr r1,[r0]ldr r1,=GPFDATldr r0,[r1]bic r0,r0,#(0x1e<<1) ; bit cleartst r0,#0x1bne %F1 ;如果没有按,就跳到后面的1标号处; 这就是清零内存的代码ldr r0,=GPFCONldr r1,=0x55aastr r1,[r0]; ldr r0,=GPFUP; ldr r1,=0xff; str r1,[r0]ldr r0,=GPFDATldr r1,=0x0str r1,[r0] ;LED=****mov r1,#0mov r2,#0mov r3,#0mov r4,#0mov r5,#0mov r6,#0mov r7,#0mov r8,#0ldr r9,=0x4000000 ;64MBldr r0,=0x30000000stmia r0!,{r1-r8}subs r9,r9,#32bne %B0;到这就结束了.1bl InitStacks ;初始化堆栈;bl Led_Test ;又是LED,注掉了;========================================================== =============; 哈哈,下面又有看头了,这个初始化程序好像被名曰hzh的高手改过; 能在NOR NAND 还有内存中运行,当然了,在内存中运行最简单了.; 在NOR NAND中运行的话都要先把自己拷到内存中.; 此外,还记得上面提到的|Image$$RO$$Base|,|Image$$RO$$Limit|...吗?; 这就是拷贝的依据了!!!;========================================================== ===============ldr r0, =BWSCONldr r0, [r0]ands r0, r0, #6 ;OM[1:0] != 0, 从NOR FLash启动或直接在内存运行bne copy_proc_beg ;不读取NAND FLASHadr r0, ResetEntry ;OM[1:0] == 0, 否则,为从NAND FLash启动cmp r0, #0 ;再比较入口是否为0地址处;========================================================== ================;如果不是,则表示主板设置了从NAND启动,但这个程序由于其它原因,;并没有从NAND从启动,这种情况最有可能的原因就是用仿真器.;========================================================== ================bne copy_proc_beg ;这种情况也不读取NAND FLASH.;nop;========================================================== =nand_boot_beg ;这一段代码完成从NAND读代码到RAMmov r5, #NFCONF ;首先设定NAND的一些控制寄存器;set timing valueldr r0, =(7<<12)|(7<<8)|(7<<4)str r0, [r5];enable controlldr r0, =(0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1) |(1<<0)str r0, [r5, #4]bl ReadNandID ;按着读取NAND的ID号,结果保存在r5里mov r6, #0 ;r6设初值0.ldr r0, =0xec73 ;期望的NAND ID号cmp r5, r0 ;这里进行比较beq %F1 ;相等的话就跳到下一个1标号处ldr r0, =0xec75 ;这是另一个期望值cmp r5, r0beq %F1 ;相等的话就跳到下一个1标号处mov r6, #1 ;不相等了,设置r6=1.1bl ReadNandStatus ;读取NAND状态,结果放在r1里mov r8, #0 ;r8设初值0,意义为页号ldr r9, =ResetEntry ;r9设初值为初始化程序入口地址;========================================================== ===============; 注意,在这里使用的是ldr伪指令,而不是上面用的adr伪指令,它加载的是Rese tEntry; 的决对地址,也就是我们期望的RAM中的地址,在这里,它和|Image$$RO$$Bas e|一样; 也就是说,我如我们编译程序时RO BASE指定的地址在RAM里,而把生成的文件拷到; NAND里运行,由ldr加载的r9的值还是定位在内存.;========================================================== ===============2ands r0, r8, #0x1f ;凡r8为0x1f(32)的整数倍-1,eq有效,ne无效bne %F3 ;这句的意思是对每个块(32页)进行检错mov r0, r8 ;r8->r0bl CheckBadBlk ;检查NAND的坏区cmp r0, #0 ;比较r0和0addne r8, r8, #32 ;存在坏块的话就跳过这个坏块bne %F4 ;没有的话就跳到标号4处3mov r0, r8 ;当前页号->r0mov r1, r9 ;当前目标地址->r1bl ReadNandPage ;读取该页的NAND数据到RAMadd r9, r9, #512 ;每一页的大小是512Bytesadd r8, r8, #1 ;r8指向下一页4cmp r8, #256 ;比较是否读完256页即128KBytesbcc %B2 ;如果r8小于256(没读完),就返回前面的标号2处mov r5, #NFCONF ;DsNandFlashldr r0, [r5, #4]bic r0, r0, #1str r0, [r5, #4]ldr pc, =copy_proc_beg ;调用copy_proc_beg;========================================================== =copy_proc_begadr r0, ResetEntry ;ResetEntry值->r0ldr r2, BaseOfROM ;BaseOfROM值(后面有定义)->r2cmp r0, r2 ;比较r0和r2ldreq r0, TopOfROM ;如果相等的话(在内存运行),TopOfROM->r0beq InitRam ;同时跳到InitRam;========================================================= ;下面这个是针对代码在NOR FLASH时的拷贝方法;功能为把从ResetEntry起,TopOfROM-BaseOfROM大小的数据拷到BaseOfR OM;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|也是由连接器生成;两者之间就是初始化数据的存放地放;=======================================================ldr r3, TopOfROMldmia r0!, {r4-r7}stmia r2!, {r4-r7}cmp r2, r3bcc %B0sub r2, r2, r3 ;r2=BaseOfROM-TopOfROM=(-)代码长度sub r0, r0, r2 ;r0=ResetEntry-(-)代码长度=ResetEntry+代码长度InitRamldr r2, BaseOfBSS ;BaseOfBSS->r2ldr r3, BaseOfZero ;BaseOfZero->r3cmp r2, r3 ;比较BaseOfBSS和BaseOfZeroldrcc r1, [r0], #4 ;要是r21 ; means Fclk:Hclk is not 1:1.; bl MMU_SetAsyncBusMode; |; bl MMU_SetFastBusMode ; default value.; ];bl Led_Test;========================================================== =; 进入C语言前的最后一步了,就是把我们用说查二级向量表; 的中断例程安装到一级向量表(异常向量表)里.ldr r0,=HandleIRQ ;This routine is neededldr r1,=IsrIRQ ;if there is not 'subs pc,lr,#4' at 0x18, 0x1cstr r1,[r0]; ;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;*****************************************************************************;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!; 妈呀,终说见到艳阳天了!!!!!!!!!!; 跳到C语言的main函数处了.;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!;*****************************************************************************[ :LNOT:THUMBCODEbl Main ;Do not use main() because ......;ldr pc, =Main ;hzhb .][ THUMBCODE ;for start-up code for Thumb modeorr lr,pc,#1bx lrCODE16bl Main ;Do not use main() because ......b .CODE32]; initializing stacksInitStacks;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_c xsf,r1'mrs r0,cpsrbic r0,r0,#MODEMASKorr r1,r0,#UNDEFMODE|NOINTmsr cpsr_cxsf,r1 ;UndefModeldr sp,=UndefStack ; UndefStack=0x33FF_5C00orr r1,r0,#ABORTMODE|NOINTmsr cpsr_cxsf,r1 ;AbortModeldr sp,=AbortStack ; AbortStack=0x33FF_6000orr r1,r0,#IRQMODE|NOINTmsr cpsr_cxsf,r1 ;IRQModeldr sp,=IRQStack ; IRQStack=0x33FF_7000orr r1,r0,#FIQMODE|NOINTmsr cpsr_cxsf,r1 ;FIQModeldr sp,=FIQStack ; FIQStack=0x33FF_8000bic r0,r0,#MODEMASK|NOINTorr r1,r0,#SVCMODEmsr cpsr_cxsf,r1 ;SVCModeldr 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. ;========================================================== =ReadNandIDmov r7,#NFCONFldr r0,[r7,#4] ;NFChipEn();bic r0,r0,#2str 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,#1beq %B1ldrb r0,[r7,#0x10] ;id = RdNFDat()<<8;mov r0,r0,lsl #8ldrb r1,[r7,#0x10] ;id |= RdNFDat();orr r5,r1,r0ldr r0,[r7,#4] ;NFChipDs();orr r0,r0,#2str r0,[r7,#4]mov pc,lrReadNandStatusmov r7,#NFCONFldr r0,[r7,#4] ;NFChipEn();bic r0,r0,#2str r0,[r7,#4]mov r0,#0x70 ;WrNFCmd(QUERYCMD);strb r0,[r7,#8]ldrb r1,[r7,#0x10] ;r1 = RdNFDat();ldr r0,[r7,#4] ;NFChipDs();orr r0,r0,#2str r0,[r7,#4]mov pc,lrWaitNandBusymov r0,#0x70 ;WrNFCmd(QUERYCMD);mov r1,#NFCONFstrb r0,[r1,#8]1 ;while(!(RdNFDat()&0x40));ldrb r0,[r1,#0x10]tst r0,#0x40beq %B1mov r0,#0 ;WrNFCmd(READCMD0);strb r0,[r1,#8]mov pc,lrCheckBadBlkmov r7, lrmov r5, #NFCONFbic r0,r0,#0x1f ;addr &= ~0x1f;ldr r1,[r5,#4] ;NFChipEn()bic r1,r1,#2str r1,[r5,#4]mov r1,#0x50 ;WrNFCmd(READCMD2)strb r1,[r5,#8]mov r1, #5;6 ;6->5strb r1,[r5,#0xc] ;WrNFAddr(5);(6) 6->5strb 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, #1001subs r0, r0, #1bne %B12ldr r0, [r5, #0x20]tst r0, #1beq %B2ldrb r0, [r5,#0x10] ;RdNFDat()sub r0, r0, #0xffmov r1,#0 ;WrNFCmd(READCMD0) strb r1,[r5,#8]ldr r1,[r5,#4] ;NFChipDs()orr r1,r1,#2str r1,[r5,#4]mov pc, r7ReadNandPagemov r7,lrmov r4,r1mov r5,#NFCONFldr r1,[r5,#4] ;NFChipEn()bic r1,r1,#2str 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,#0x10str r0,[r5,#4]bl WaitNandBusy ;WaitNFBusy()mov r0,#0 ;for(i=0; i<512; i++)1ldrb r1,[r5,#0x10] ;buf[i] = RdNFDat() strb r1,[r4,r0]add r0,r0,#1bic r0,r0,#0x10000cmp r0,#0x200bcc %B1ldr r0,[r5,#4] ;NFChipDs()orr r0,r0,#2str r0,[r5,#4]mov pc,r7;--------------------LED testEXPORT Led_TestLed_Testmov r0, #0x56000000mov r1, #0x5500str r1, [r0, #0x50]mov r1, #0x50str r1, [r0, #0x54]mov r2, #0x1000001subs r2, r2, #1bne %B1mov r1, #0xa0str r1, [r0, #0x54]mov r2, #0x1000002subs r2, r2, #1bne %B2b %B0mov pc, lr;========================================================== =LTORG;GCS0->SST39VF1601;GCS1->16c550;GCS2->IDE;GCS3->CS8900;GCS4->DM9000;GCS5->CF Card;GCS6->SDRAM;GCS7->unusedSMRDATA DATA; 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 HCLK<=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)) ;GCS0DCD ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_ Tah<<4)+(B1_Tacp<<2)+(B1_PMC)) ;GCS1DCD ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_ Tah<<4)+(B2_Tacp<<2)+(B2_PMC)) ;GCS2DCD ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_ Tah<<4)+(B3_Tacp<<2)+(B3_PMC)) ;GCS3DCD ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_ Tah<<4)+(B4_Tacp<<2)+(B4_PMC)) ;GCS4DCD ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_ Tah<<4)+(B5_Tacp<<2)+(B5_PMC)) ;GCS5DCD ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN)) ;GCS6DCD ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN)) ;GCS7DCD ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Tsrc<<18)+(Tchr<<16)+ REFCNT)DCD 0x32 ;SCLK power saving mode, BANKSIZE 128M/128M DCD 0x30 ;MRSR6 CL=3clkDCD 0x30 ;MRSR7 CL=3clkBaseOfROM DCD |Image$$RO$$Base|TopOfROM DCD |Image$$RO$$Limit|BaseOfBSS DCD |Image$$RW$$Base|BaseOfZero DCD |Image$$ZI$$Base|EndOfBSS DCD |Image$$ZI$$Limit|ALIGN; for entering power down mode; 1. SDRAM should be in self-refresh mode.; 2. All interrupt should be maksked for SDRAM/DRAM self-refresh.; 3. LCD controller should be disabled for SDRAM/DRAM self-refresh.; 4. The I-cache may have to be turned on.; 5. The location of the following code may have not to be changed.;void EnterPWDN(int CLKCON);EnterPWDNmov r2,r0 ;r2=rCLKCONtst r0,#0x8 ;SLEEP mode?bne ENTER_SLEEPENTER_STOPldr r0,=REFRESHldr r3,[r0] ;r3=rREFRESHmov r1, r3orr r1, r1, #BIT_SELFREFRESHstr r1, [r0] ;Enable SDRAM self-refreshmov r1,#16 ;wait until self-refresh is issued. may not be needed.0 subs r1,r1,#1bne %B0ldr r0,=CLKCON ;enter STOP mode.str r2,[r0]mov r1,#320 subs r1,r1,#1 ;1) wait until the STOP mode is in effect.bne %B0 ;2) Or wait here until the CPU&Peripherals will be turned-off; Entering SLEEP mode, only the reset by wake-up is available.ldr r0,=REFRESH ;exit from SDRAM self refresh mode.str r3,[r0]MOV_PC_LRENTER_SLEEP;NOTE.;1) rGSTATUS3 should have the return address after wake-up from SL EEP mode.ldr r0,=REFRESHldr r1,[r0] ;r1=rREFRESHorr r1, r1, #BIT_SELFREFRESHstr r1, [r0] ;Enable SDRAM self-refreshmov r1,#16 ;Wait until self-refresh is issued,which may not be needed.0 subs r1,r1,#1bne %B0ldr r1,=MISCCRldr r0,[r1]orr r0,r0,#(7<<17) ;Set SCLK0=0, SCLK1=0, SCKE=0.str r0,[r1]ldr r0,=CLKCON ; Enter sleep modestr r2,[r0]b . ;CPU will die here.WAKEUP_SLEEP;Release SCLKn after wake-up from the SLEEP mode.ldr r1,=MISCCRldr r0,[r1]bic r0,r0,#(7<<17) ;SCLK0:0->SCLK, SCLK1:0->SCLK, SCKE:0->=SCKE. str r0,[r1];Set memory control registersldr r0,=SMRDATA;be careful!, hzhldr r1,=BWSCON ;BWSCON Addressadd r2, r0, #52 ;End address of SMRDATAldr r3, [r0], #4str r3, [r1], #4cmp r2, r0bne %B0mov r1,#2560 subs r1,r1,#1 ;1) wait until the SelfRefresh is released.bne %B0ldr r1,=GSTATUS3 ;GSTATUS3 has the start address just after SLEE P wake-upldr r0,[r1]mov pc,r0;========================================================== ===========; Clock division test; Assemble code, because VSYNC time is very short;========================================================== ===========EXPORT CLKDIV124EXPORT CLKDIV144CLKDIV124ldr r0, = CLKDIVNldr r1, = 0x3 ; 0x3 = 1:2:4str r1, [r0]; wait until clock is stablenopnopnopnopnopldr r0, = REFRESHldr r1, [r0]bic r1, r1, #0xffbic r1, r1, #(0x7<<8)orr r1, r1, #0x470 ; REFCNT135str r1, [r0]nopnopnopnopnopmov pc, lrCLKDIV144ldr r0, = CLKDIVNldr r1, = 0x4 ; 0x4 = 1:4:4str r1, [r0]; wait until clock is stablenopnopnopnopnopldr r0, = REFRESHldr r1, [r0]bic r1, r1, #0xffbic r1, r1, #(0x7<<8)orr r1, r1, #0x630 ; REFCNT675 - 1520str r1, [r0]nopnopnopnopnopmov pc, lrALIGNAREA RamData, DATA, READWRITE^ _ISR_STARTADDRESS ; _ISR_STARTADDRESS=0x33FF_FF00 HandleReset # 4HandleUndef # 4HandleSWI # 4HandlePabort # 4HandleDabort # 4HandleReserved # 4HandleIRQ # 4HandleFIQ # 4;Do not use the label 'IntVectorTable',;The value of IntVectorTable is different with the address you think it m ay be.;IntVectorTable;@0x33FF_FF20HandleEINT0 # 4HandleEINT1 # 4HandleEINT2 # 4HandleEINT3 # 4HandleEINT4_7 # 4HandleEINT8_23 # 4HandleCAM # 4 ; Added for 2440.HandleBATFLT # 4HandleTICK # 4HandleWDT # 4HandleTIMER0 # 4HandleTIMER1 # 4HandleTIMER2 # 4HandleTIMER3 # 4HandleTIMER4 # 4HandleUART2 # 4;@0x33FF_FF60HandleLCD # 4HandleDMA0 # 4HandleDMA1 # 4HandleDMA2 # 4HandleDMA3 # 4HandleMMC # 4HandleSPI0 # 4HandleUART1 # 4HandleNFCON # 4 ; Added for 2440. HandleUSBD # 4HandleUSBH # 4HandleIIC # 4HandleUART0 # 4HandleSPI1 # 4HandleRTC # 4HandleADC # 4;@0x33FF_FFA0END。
Android的初始化语言脚本init.rc解析
Android的初始化语言脚本init.rc解析Android的初始化语言脚本init.rc解析Android init.rc (Android init language)Android初始化语言由四大类声明组成:行为类(Actions),命令类(Commands),服务类(Services),选项类(Options).* 初始化语言以行为单位,由以空格间隔的语言符号组成。
C风格的反斜杠转义符可以用来插入空白到语言符号。
双引号也可以用来防止文本被空格分成多个语言符号。
当反斜杠在行末时,作为折行符。
* 以#开始(前面允许有空格)的行为注释行。
* Actions和Services隐含声明一个新的段落。
所有该段落下Commands或Options的声明属于该段落。
第一段落前的Commands或Options被忽略。
* Actions和Services拥有独一无二的命名。
在它们之后声明相同命名的类将被当作错误并忽略。
Actions-------Actions是一系列命令的命名。
Actions拥有一个触发器(trigger)用来决定action何时执行。
当一个action在符合触发条件被执行时,如果它还没被加入到待执行队列中的话,则加入到队列最后。
队列中的action依次执行,action中的命令也依次执行。
Init在执行命令的中间处理其它活动(设备创建/销毁,property设置,进程重启)。
Actions表现形式为:onServices--------Services是由init启动,在它们退出时重启(可选)。
Service表现形式为:service [ ]*...Options-------Options是Services的修饰,它们影响init何时、如何运行service.critical这是一个设备关键服务(device-critical service) .如果它在4分钟内退出超过4次,设备将重启并进入恢复模式。
lowlevel_init过程注释了一遍
lowlevel_init过程注释了一遍恩,大概以后再也不想看这块过程了。
解析的有点犯恶心了。
如果有问题,请各位看官斧正。
非常感谢。
#include <config.h>#include <version.h>#include <s3c6410.h>#include "smdk6410_val.h"_TEXT_BASE:.word TEXT_BASE.globl lowlevel_initlowlevel_init:mov r12, lr;保存当前链接寄存器地址,等跳转回start.s时继续执行使用ldr r0, =ELFIN_GPIO_BASE ;定基地址 0x7f008000ldr r1, =0x55555555str r1, [r0, #GPKCON0_OFFSET]; 0x7f008000 + 0x800 ;设置引脚GPIO-K[0-7]管脚为cfdata 模式ldr r1, =0x55555555str r1, [r0, #GPKCON1_OFFSET];0x7f008000 + 0x804 ;设置引脚GPIO-K[8-14]管脚为cfdata 模式ldr r1, =0x22222666 ;0010 0010 0010 0010 0010 0110 0110 0110str r1, [r0, #GPLCON0_OFFSET];0x7f008000 + 0x810;设置引脚GPIO-L;打开CF卡串口通信的0-2号三根地址线,其余不变,保持默认值ldr r1, =0x04000000 ;01 00 00 00 00 00 00 00 00 00 00 00 00 00str r1, [r0, #GPFCON_OFFSET];0x7f008000 + 0xA0;设置引脚GPIO-F14为输出;GPIO-F14连接CLKOUT输出ldr r1, =0x2000; 10000000000000str r1, [r0, #GPFDAT_OFFSET];0x7f008000 + 0xA4;通过向GPIO锁存器写1,维持一个高电平信号。
ARM9无操作系统实验(一)LED部分
开始
设置 GPB5 为输出状态
置位 GPB5,LED0 熄灭
设置 GPB 端口禁止上拉
清零 GPB5,点亮 LED0
结束
将程序加载到开发板上,就可以看实验的结果了,其它 LED 灯的控制和 LED0 一样,只是 寄存器的设置值不同罢了。
实验二、流水灯 终于能点亮一个 LED 灯了,那么它有什么用呢?它的主要用途在于一些状态的显示上,
GPB5 LED0 GPB6 LED1 GPB8 LED2 GPB10 LED3 ********************************************/
/*---------地址声明----------*/
#include "2440addr.h"
注释:在本程序的开头,引入一个 2440addr.h 的头文件,该文件中定义了我们要常用的 寄存器的地址,以后的程序中,只需引入即可。引入的方法是将这个头文件直接放在 ADS 安装文件的 include 中就行了。
S3C2440 无操作系统实验——LED 部分
S3C2440 无操作系统实验(一)——LED 部分
小小达摩 2011-6-23
硬件:飞凌 FL2440 开发板 软件:ADS1.2
拿到 ARM 开发板,应该从哪儿开始学习呢?困扰了很多初学者,当然也正在困扰我, 因为我也是初学者。所以我想与其困惑,还不如先做些自己能做的,将会做的做熟悉了,也 许就找到学习的方向了吧。那么从哪儿入手呢,想来想去,那就从点亮一个 LED 灯作为学 习的起点。虽然很多人,不推荐用学习单片机的模式来学习 ARM,但是我感觉基础还是重 要的,再说高级的学习暂时也不会呀,呵呵。虽然这样学习会慢点,但是总比开发板落厚厚 一层灰要划得来吧(开发板买了快 2 年了,拿来玩的时间不超过 2 个月,也许很多朋友都有 这样的经历吧)。所以,把它拿出来,开始学习吧。
init进程和inittab文件简要说明!Windows系统-电脑资料
init进程和inittab文件简要说明!Windows系统-电脑资料在坛子里看到有人问有关inittab文件的问题,找了下资料,总结一下,大家多提意见和补充吧!init进程是系统中所有进程的父进程,init进程繁衍出完成通常操作所需的子进程,这些操作包括:设置机器名、检查和安装磁盘及文件系统、启动系统日志、配置网络接在坛子里看到有人问有关inittab文件的问题,找了下资料,总结一下,大家多提意见和补充吧!init进程是系统中所有进程的父进程,init进程繁衍出完成通常操作所需的子进程,这些操作包括:设置机器名、检查和安装磁盘及文件系统、启动系统日志、配置网络接口并启动网络和邮件服务,启动打印服务等,。
Solaris中init进程的主要任务是按照inittab文件所提供的信息创建进程,由于进行系统初始化的那些进程都由init创建,所以init进程也称为系统初始化进程。
下面具体说明inittab文件的格式。
inittab文件中每一记录都从新的一行开始,每个记录项最多可有512个字符,每一项的格式通常如下:id:rstate:action:process,下面分别解释。
1.id字段是最多4个字符的字符串,用来唯一标志表项。
2.rstate(run state)字段定义该记录项被调用时的运行级别,rstate可以由一个或多个运行级别构成,也可以是空,空则代表运行级别0~6。
当请求init改变运行级别时,那些rstate字段中不包括新运行级别的进程将收到SIGTERM警告信号,并且最后被杀死;只有a、b、c启动的命令外(a、b、c不是真正的运行级别)3.action字段告诉init执行的动作,即如何处理process字段指定的进程,action字段允许的值及对应的动作分别为:1)respawn:如果process字段指定的进程不存在,则启动该进程,init不等待处理结束,而是继续扫描inittab文件中的后续进程,当这样的进程终止时,init会重新启动它,如果这样的进程已存在,则什么也不做。
Android系统启动流程(一)解析init进程
Android系统启动流程(一)解析init进程前言作为“Android框架层”这个大系列中的第一个系列,我们首先要了解的是Android系统启动流程,在这个流程中会涉及到很多重要的知识点,这个系列我们就来一一讲解它们,这一篇我们就来学习init进程。
1.init简介init进程是Android系统中用户空间的第一个进程,作为第一个进程,它被赋予了很多极其重要的工作职责,比如创建zygote(孵化器)和属性服务等。
init进程是由多个源文件共同组成的,这些文件位于源码目录system/core/init。
本文将基于Android7.0源码来分析Init进程。
2.引入init进程说到init进程,首先要提到Android系统启动流程的前几步:1.启动电源以及系统启动当电源按下时引导芯片代码开始从预定义的地方(固化在ROM)开始执行。
加载引导程序Bootloader到RAM,然后执行。
2.引导程序Bootloader引导程序是在Android操作系统开始运行前的一个小程序,它的主要作用是把系统OS拉起来并运行。
3.Linux内核启动内核启动时,设置缓存、被保护存储器、计划列表,加载驱动。
当内核完成系统设置,它首先在系统文件中寻找”init”文件,然后启动root进程或者系统的第一个进程。
4.init进程启动讲到第四步就发现我们这一节要讲的init进程了。
关于Android系统启动流程的所有步骤会在本系列的最后一篇做讲解。
3.init入口函数init的入口函数为main,代码如下所示。
system/core/init/init.cppint main(int argc, char** argv) {if (!strcmp(basename(argv[0]), "ueventd")) {return ueventd_main(argc, argv);}if (!strcmp(basename(argv[0]), "watchdogd")) {return watchdogd_main(argc, argv);}umask(0);add_environment("PATH", _PATH_DEFPATH);bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 0);//创建文件并挂载if (is_first_stage) {mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");mkdir("/dev/pts", 0755);mkdir("/dev/socket", 0755);mount("devpts", "/dev/pts", "devpts", 0, NULL);#define MAKE_STR(x) __STRING(x)mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));mount("sysfs", "/sys", "sysfs", 0, NULL);}open_devnull_stdio();klog_init();klog_set_level(KLOG_NOTICE_LEVEL);NOTICE("init %s started!\n", is_first_stage ? "first stage" : "second stage");if (!is_first_stage) {// Indicate that booting is in progress to background fw loaders, etc.close(open("/dev/.booting", O_WRONL Y | O_CREAT | O_CLOEXEC, 0000));//初始化属性相关资源property_init();//1process_kernel_dt();process_kernel_cmdline();export_kernel_boot_props();}...//启动属性服务start_property_service();//2const BuiltinFunctionMap function_map;Action::set_function_map(&function_map);Parser& parser = Parser::GetInstance();parser.AddSectionParser("service",std::make_unique<ServiceParser>());parser.AddSectionParser("on", std::make_unique<ActionParser>());parser.AddSectionParser("import", std::make_unique<ImportParser>());//解析init.rc配置文件parser.ParseConfig("/init.rc");//3...while (true) {if (!waiting_for_exec) {am.ExecuteOneCommand();restart_processes();}int timeout = -1;if (process_needs_restart) {timeout = (process_needs_restart - gettime()) * 1000;if (timeout < 0)timeout = 0;}if (am.HasMoreCommands()) {timeout = 0;}bootchart_sample(&timeout);epoll_event ev;int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));if (nr == -1) {ERROR("epoll_wait failed: %s\n", strerror(errno));} else if (nr == 1) {((void (*)()) ev.data.ptr)();}}return 0;}init的main方法做了很多事情,我们只需要关注主要的几点,在注释1处调用property_init 来对属性进行初始化并在注释2处的调用start_property_service启动属性服务,关于属性服务,后面会讲到。
Android系统init进程启动及init.rc全解析
Android系统init进程启动及init.rc全解析这是⼀篇⽤⼼写的博客,也希望⼤家⽤⼼看并帮忙找到⽂章的改进之处,谢谢;服务启动机制1. system/core/init/init.c⽂件main函数中parse_config_file(init.rc)读取并解析init.rc⽂件内容。
将service信息放置到system/core/init/init_parser.cpp的service_list中2. system/core/init/init.c⽂件main函数继续执⾏restart_servie_if_needed(…) -> service_start(…) -> Execve(…)建⽴service进程;为了让⼤伙看得更明⽩,上个图先《总体启动框架图》:init.rc 简介⽬前Linux有很多通讯机制可以在⽤户空间和内核空间之间交互,例如设备驱动⽂件(位于/dev⽬录中)、内存⽂件(/proc、/sys⽬录等)。
了解Linux的同学都应该知道Linux的重要特征之⼀就是⼀切都是以⽂件的形式存在的,例如,⼀个设备通常与⼀个或多个设备⽂件对应。
这些与内核空间交互的⽂件都在⽤户空间,所以在Linux内核装载完,需要⾸先建⽴这些⽂件所在的⽬录。
⽽完成这些⼯作的程序就是本⽂要介绍的init。
Init是⼀个命令⾏程序。
其主要⼯作之⼀就是建⽴这些与内核空间交互的⽂件所在的⽬录。
当Linux内核加载完后,要做的第⼀件事就是调⽤init程序,也就是说,init是⽤户空间执⾏的第⼀个程序。
尽管init完成的⼯作不算很多,不过代码还是⾮常复杂的。
Init程序并不是由⼀个源代码⽂件组成的,⽽是由⼀组源代码⽂件的⽬标⽂件链接⽽成的。
这些⽂件位于如下的⽬录。
需要明⽩的是,这些init.rc只是语法⽂件,并不是程序,真正的⼊⼝则是上⾯提到的system/core/init/init.c因为init.c⽂件⽐较⼤,在⽂章的第⼆部分我会简要的通过main函数分析init启动流程;init.rc有两个,分别位于:./system/core/rootdir/init.rc./bootable/recovery/etc/init.rc从⽬录上⼤致可以猜测,这两个init.rc使⽤场景不⼀样,⼀个是刷机⽤到的,也就是进⼊recorvery模式,⼀个是正常启动⽤到的;我们这⾥重点分析的是上⾯那个,也是init.c关联的那个;init.rc语法结构解析要了解init.rc是怎么解析的,我们需要先看看说明⽂档,说明⽂档在,当然也可以看下热⼼⽹友的;init.rc位于/bootable/recovery/etc/init.rcAndroid初始化语⾔包含了四种类型的声明:Actions(⾏为)、Commands(命令)、Services(服务)和Options(选项)所有这些都是以⾏为单位的,各种记号由空格来隔开。
init.s文件详细解析
init.s文件详细解析2440init.s文件详细解析;====================================== ===; 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 s for testing STOP,Sleep mode; 2003.03.14:DonGo: Modified for 2440.;====================================== ===;首先,启动代码定义了一些常量GET option.incGET memcfg.incGET 2440addr.incBIT_SELFREFRESH EQU (1<<22);处理器模式常量USERMODE EQU 0x10FIQMODE EQU 0x11IRQMODE EQU 0x12SVCMODE EQU 0x13ABORTMODE EQU 0x17UNDEFMODE EQU 0x1bMODEMASK EQU 0x1fNOINT EQU 0xc0;定义处理器各模式下堆栈地址常量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 ~;检查在tasm.exe里是否设置了采用THUMB(16位)代码(armasm -16 ...@ADS 1.0)GBLL THUMBCODE ;定义THUMBCODE全局变量[ {CONFIG} = 16 ;如果发现是才用16位代码的话,CONFIG为汇编器的内置变量THUMBCODE SETL {TRUE} ;把THUMBCODE设置为TURECODE32 ;把处理器从新设置成为ARM模式| ;如果处理器现在就是ARM模式THUMBCODE SETL {FALSE} ;把THUMBCODE设置为FALSE就行了]MACRO ;一个根据THUMBCODE把PC寄存的值保存到LR的宏, 宏 MOV_PC_LRMOV_PC_LR[ THUMBCODEbx lr ;在ARM模式中要使用BX指令转跳到THUMB指令,并转换模式|mov pc,lr ;如果目标地址也是ARM指令的话就采用这种方式]MENDMACRO ;和上面的宏一样,只是多了一个相等的条件MOVEQ_PC_LR[ THUMBCODEbxeq lr|moveq pc,lr]MEND;====================================== =================================================;下面这个宏是用于第一次查表过程的实现中断向量的重定向,如果你比较细心的话就是发现;在_ISR_STARTADDRESS=0x33FF_FF00里定义的第一级中断向量表是采用型如Ha ndle***的方式的.;而在程序的ENTRY处(程序开始处)采用的是b Handler***的方式.;在这里Handler***就是通过HANDLER这个宏和Handle***进立联系的.;这种方式的优点就是正真定义的向量数据在内存空间里,而不是在ENTRY处的R OM(FLASH)空间里,;这样,我们就可以在程序里灵活的改动向量的数据了.;====================================== ==================================================MACRO$HandlerLabel HANDLER $HandleLabel$HandlerLabelsub sp,sp,#4 ;减少sp(用于存放转跳地址)stmfd sp!,{r0} ;把工作寄存器压入栈(lr does not push because it retur n to original address)ldr r0,=$HandleLabel;将HandleXXX的址址放入r0ldr r0,[r0] ;把HandleXXX所指向的内容(也就是中断程序的入口)放入r0 str r0,[sp,#4] ;把中断服务程序(ISR)压入栈ldmfd sp!,{r0,pc} ;用出栈的方式恢复r0的原值和为pc设定新值(也就完成了到ISR的转跳)MEND;====================================== ===================================================;在这里用IMPORT伪指令(和c语言的extren一样)引入|Image$$RO$$Base|,|I mage$$RO$$Limit|...;这些变量是通过ADS的工程设置里面设定的RO Base和RW Base设定的, ;最终由编译脚本和连接程序导入程序.;那为什么要引入这玩意呢,最简单的用处是可以根据它们拷贝自已;====================================== ====================================================IMPORT |Image$$RO$$Base| ; ROM code(也就是代码)的开始地址IMPORT |Image$$RO$$Limit| ; ROM code的结束地址(=ROM data的开始地址)IMPORT |Image$$RW$$Base| ; 要初始化的RAM的开始地址IMPORT |Image$$ZI$$Base| ; area(需要清零的RAM区域)的开始地址IMPORT |Image$$ZI$$Limit| ; area的结束地址;这里引入一些在其它文件中实现在函数,包括为我们所熟知的main函数IMPORT MMU_SetAsyncBusModeIMPORT MMU_SetFastBusMode ;hzhIMPORT Main ; The main entry of mon program;从这里开始就是正真的代码入口了!AREA Init,CODE,READONLY ;这表明下面的是一个名为Init的代码段ENTRY ;定义程序的入口(调试用)EXPORT __ENTRY ;导出符号_ENTRY,但在那用到就还没查明__ENTRYResetEntry;1)The code, which converts to Big-endian, should be in little endian co de.;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_CHANGE ;下面是大小端的一个判断,在Option.inc里已经设为F ALSEASSERT :DEF:ENTRY_BUS_WIDTH[ ENTRY_BUS_WIDTH=32b ChangeBigEndian ;DCD 0xea000007][ ENTRY_BUS_WIDTH=16andeq r14,r7,r0,lsl #20 ;DCD 0x0007ea00][ ENTRY_BUS_WIDTH=8streq r0,[r0,-r10,ror #1] ;DCD 0x070000ea]|b ResetHandler ;设成FALSE的话就来到这了,转跳到复位程序入口]b HandlerUndef ;转跳到Undefined mode程序入口b HandlerSWI ;转跳到SWI 中断程序入口b HandlerPabort ;转跳到PAbort(指令异常)程序入口b HandlerDabort ;转跳到DAbort(数据异常)程序入口b . ;保留b HandlerIRQ ;转跳到IRQ 中断程序入口b HandlerFIQ ;转跳到FIQ 中断程序入口;@0x20b EnterPWDN ; Must be @0x20.;====================================== ============================================;下面是改变大小端的程序,这里采用直接定义机器码的方式,至说为什么这么做就得问三星了;反正我们程序里这段代码也不会去执行,不用去管它;====================================== ============================================ChangeBigEndian;@0x24[ ENTRY_BUS_WIDTH=32DCD 0xee110f10 ;0xee110f10 => mrc p15,0,r0,c1,c0,0DCD 0xe3800080 ;0xe3800080 => orr r0,r0,#0x80; //Big-endianDCD 0xee010f10 ;0xee010f10 => mcr p15,0,r0,c1,c0,0][ ENTRY_BUS_WIDTH=16DCD 0x0f10ee11DCD 0x0080e380DCD 0x0f10ee01][ ENTRY_BUS_WIDTH=8DCD 0x100f11eeDCD 0x800080e3DCD 0x100f01ee]DCD 0xffffffff ;swinv 0xffffff is similar with NOP and run well in both e ndian mode.DCD 0xffffffffDCD 0xffffffffDCD 0xffffffffDCD 0xffffffffb ResetHandler;如上所说,这里采用HANDLER宏去建立Hander***和Handle***之间的联系HandlerFIQ HANDLER HandleFIQHandlerIRQ HANDLER HandleIRQHandlerUndef HANDLER HandleUndefHandlerSWI HANDLER HandleSWIHandlerDabort HANDLER HandleDabortHandlerPabort HANDLER HandlePabort;====================================== =============================================;呵呵,来了来了.好戏来了,这一段程序就是用来进行第二次查表的过程了.;如果说第一次查表是由硬件来完成的,那这一次查表就是由软件来实现的了.;为什么要查两次表??;没有办法,ARM把所有的中断都归纳成一个IRQ中断异常和一个FIRQ中断异常;第一次查表主要是查出是什么异常,可我们总要知道是这个中断异常中的什么中断呀!;没办法了,再查一次表呗!;====================================== =============================================IsrIRQsub sp,sp,#4 ;给PC寄存器保留stmfd sp!,{r8-r9} ;把r8-r9压入栈ldr r9,=INTOFFSET ;把INTOFFSET的地址装入r9ldr r9,[r9] ;把INTOFFSET的值装入r9ldr r8,=HandleEINT0 ;这就是我们第二个中断向量表的入口的,先装入r8;====================================== =============================================;哈哈,这查表方法够好了吧,r8(入口)+index*4(别望了一条指令是4 bytes的喔), ;这不就是我们要找的那一项了吗.找到了表项,下一步做什么?肯定先装入了!;====================================== ============================================add r8,r8,r9,lsl #2ldr r8,[r8] ;装入中断服务程序的入口str r8,[sp,#8] ;把入口也入栈,准备用旧招ldmfd sp!,{r8-r9,pc} ;施招,弹出栈,哈哈,顺便把r8弹出到PC,O了,跳转成功! LTORG ;声明文字池,因为我们用了ldr伪指令;====================================== ==================== ==================== ; ENTRY(好了,我们的CPU要在这复位了.);====================================== ==================== ==================== ResetHandlerldr r0,=WTCON ;1.关看门狗ldr r1,=0x0str r1,[r0]ldr r0,=INTMSKldr r1,=0xffffffff ;2.关中断str r1,[r0]ldr r0,=INTSUBMSKldr r1,=0x7fff ;3.关子中断str r1,[r0][ {FALSE} ;4.得有些表示了,该点点LED灯了,不过被FALSE掉了.;rGPFDAT = (rGPFDAT & ~(0xf<<4)) | ((~data & 0xf)<<4);; Led_Displayldr r0,=GPFCONldr r1,=0x5500str r1,[r0]ldr r0,=GPFDATldr r1,=0x10str r1,[r0]];5.为了减少PLL的lock time, 调整LOCKTIME寄存器.ldr r0,=LOCKTIMEldr r1,=0xffffffstr r1,[r0][ PLL_ON_START ;6.下面就来设置PLL了,你的板快不快就看这了!!; Added for confirm clock divide. for 2440.; 设定Fclk:Hclk:Pclkldr r0,=CLKDIVNldr r1,=CLKDIV_VAL ; 0=1:1:1, 1=1:1:2, 2=1:2:2, 3=1:2:4,str r1,[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.; bl MMU_SetAsyncBusMode; |; bl MMU_SetFastBusMode ; default value.; ][ CLKDIV_VAL>1 ; 意思是Fclk:Hclk 不是1:1.mrc p15,0,r0,c1,c0,0orr r0,r0,#0xc0000000;R1_nF:OR:R1_iAmcr p15,0,r0,c1,c0,0|mrc p15,0,r0,c1,c0,0bic r0,r0,#0xc0000000;R1_iA:OR:R1_nFmcr p15,0,r0,c1,c0,0];配置UPLLldr r0,=UPLLCONldr r1,=((U_MDIV<<12)+(U_PDIV<<4)+U_SDIV)str r1,[r0]nop ; Caution: After UPLL setting, at least 7-clocksnop ; delay must be inserted for setting hardware be completed.nopnopnopnopnop;配置MPLL 一定要使最后的频率为16.9344MHz,不然你甭想用USB接口了,哈哈.ldr r0,=MPLLCONldr r1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV)str r1,[r0]];检查是否从SLEEP模式中恢复ldr r1,=GSTATUS2ldr r0,[r1]tst r0,#0x2;如果是从SLEEP模式中恢复, 转跳到SLEEP_WAKEUP.bne WAKEUP_SLEEPEXPORT StartPointAfterSleepWakeUp ;导出符号StartPointAfterSleepWake UpStartPointAfterSleepWakeUp;====================================== ==================== ===================== ;设置内存控制器等寄存器的值,因为这些寄存器是连续排列的,所以采用如下办法对这些;寄存器进行连续设置.其中用到了SMRDATA的数据,这在代码后面有定义;====================================== ==================== ===================== ;ldr r0,=SMRDATAadrl r0, SMRDATA;be careful!, hzhldr r1,=BWSCON ;BWSCON 地址add r2, r0, #52 ;SMRDATA数据的结束地址,共有52字节的数据ldr r3, [r0], #4str r3, [r1], #4cmp r2, r0bne %B0;====================================== ==========================================;如果EINT0 产生(这中断就是我们按键产生的), 就清除SDRAM ,不过好像没人会在这个时候按;====================================== ==========================================; check if EIN0 button is pressedldr r0,=GPFCONldr r1,=0x0str r1,[r0]ldr r0,=GPFUPldr r1,=0xffstr r1,[r0]ldr r1,=GPFDATldr r0,[r1]bic r0,r0,#(0x1e<<1) ; bit cleartst r0,#0x1bne %F1 ;如果没有按,就跳到后面的1标号处; 这就是清零内存的代码ldr r0,=GPFCONldr r1,=0x55aastr r1,[r0]; ldr r0,=GPFUP; ldr r1,=0xff; str r1,[r0]ldr r0,=GPFDATldr r1,=0x0str r1,[r0] ;LED=****mov r1,#0mov r2,#0mov r3,#0mov r4,#0mov r5,#0mov r6,#0mov r7,#0mov r8,#0ldr r9,=0x4000000 ;64MBldr r0,=0x30000000stmia r0!,{r1-r8}subs r9,r9,#32bne %B0;到这就结束了.1bl InitStacks ;初始化堆栈;bl Led_Test ;又是LED,注掉了;====================================== ==================== =============; 哈哈,下面又有看头了,这个初始化程序好像被名曰hzh的高手改过; 能在NOR NAND 还有内存中运行,当然了,在内存中运行最简单了.; 在NOR NAND中运行的话都要先把自己拷到内存中.; 此外,还记得上面提到的|Image$$RO$$Base|,|Image$$RO$$Limit|...吗?; 这就是拷贝的依据了;====================================== ==================== =============== ldr r0, =BWSCONldr r0, [r0]ands r0, r0, #6 ;OM[1:0] != 0, 从NOR FLash启动或直接在内存运行bne copy_proc_beg ;不读取NAND FLASHadr r0, ResetEntry ;OM[1:0] == 0, 否则,为从NAND FLash启动cmp r0, #0 ;再比较入口是否为0地址处;====================================== ==================== ================ ;如果不是,则表示主板设置了从NAND启动,但这个程序由于其它原因,;并没有从NAND从启动,这种情况最有可能的原因就是用仿真器.;====================================== ==================== ================ bne copy_proc_beg ;这种情况也不读取NAND FLASH.;nop;====================================== ==================== =nand_boot_beg ;这一段代码完成从NAND读代码到RAMmov r5, #NFCONF ;首先设定NAND的一些控制寄存器;set timing valueldr r0, =(7<<12)|(7<<8)|(7<<4)str r0, [r5];enable controlldr r0, =(0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4 )|(1<<1) |(1<<0)str r0, [r5, #4]bl ReadNandID ;按着读取NAND的ID号,结果保存在r5里mov r6, #0 ;r6设初值0.ldr r0, =0xec73 ;期望的NAND ID号cmp r5, r0 ;这里进行比较beq %F1 ;相等的话就跳到下一个1标号处ldr r0, =0xec75 ;这是另一个期望值cmp r5, r0beq %F1 ;相等的话就跳到下一个1标号处mov r6, #1 ;不相等了,设置r6=1.1bl ReadNandStatus ;读取NAND状态,结果放在r1里mov r8, #0 ;r8设初值0,意义为页号ldr r9, =ResetEntry ;r9设初值为初始化程序入口地址;====================================== ==================== =============== ; 注意,在这里使用的是ldr伪指令,而不是上面用的adr伪指令,它加载的是Rese tEntry; 的决对地址,也就是我们期望的RAM中的地址,在这里,它和|Image$$RO$$Bas e|一样; 也就是说,我如我们编译程序时RO BASE指定的地址在RAM里,而把生成的文件拷到; NAND里运行,由ldr加载的r9的值还是定位在内存.;====================================== ==================== =============== 2ands r0, r8, #0x1f ;凡r8为0x1f(32)的整数倍-1,eq有效,ne无效bne %F3 ;这句的意思是对每个块(32页)进行检错mov r0, r8 ;r8->r0bl CheckBadBlk ;检查NAND的坏区cmp r0, #0 ;比较r0和0addne r8, r8, #32 ;存在坏块的话就跳过这个坏块bne %F4 ;没有的话就跳到标号4处3mov r0, r8 ;当前页号->r0mov r1, r9 ;当前目标地址->r1bl ReadNandPage ;读取该页的NAND数据到RAMadd r9, r9, #512 ;每一页的大小是512Bytesadd r8, r8, #1 ;r8指向下一页4cmp r8, #256 ;比较是否读完256页即128KBytesbcc %B2 ;如果r8小于256(没读完),就返回前面的标号2处mov r5, #NFCONF ;DsNandFlashldr r0, [r5, #4]bic r0, r0, #1str r0, [r5, #4]ldr pc, =copy_proc_beg ;调用copy_proc_beg;====================================== ==================== =copy_proc_begadr r0, ResetEntry ;ResetEntry值->r0ldr r2, BaseOfROM ;BaseOfROM值(后面有定义)->r2cmp r0, r2 ;比较r0和r2ldreq r0, TopOfROM ;如果相等的话(在内存运行),TopOfROM->r0beq InitRam ;同时跳到InitRam;====================================== =================== ;下面这个是针对代码在NOR FLASH 时的拷贝方法;功能为把从ResetEntry起,T opOfROM-BaseOfROM大小的数据拷到BaseOfR OM;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|也是由连接器生成;两者之间就是初始化数据的存放地放;====================================== =================ldr r3, TopOfROMldmia r0!, {r4-r7}stmia r2!, {r4-r7}cmp r2, r3bcc %B0sub r2, r2, r3 ;r2=BaseOfROM-TopOfROM=(-)代码长度sub r0, r0, r2 ;r0=ResetEntry-(-)代码长度=ResetEntry+代码长度InitRamldr r2, BaseOfBSS ;BaseOfBSS->r2ldr r3, BaseOfZero ;BaseOfZero->r3cmp r2, r3 ;比较BaseOfBSS和BaseOfZeroldrcc r1, [r0], #4 ;要是r21 ; means Fclk:Hclk is not 1:1.; bl MMU_SetAsyncBusMode; |; bl MMU_SetFastBusMode ; default value.; ];bl Led_Test;====================================== ==================== =; 进入C语言前的最后一步了,就是把我们用说查二级向量表; 的中断例程安装到一级向量表(异常向量表)里.ldr r0,=HandleIRQ ;This routine is neededldr r1,=IsrIRQ ;if there is not 'subs pc,lr,#4' at 0x18, 0x1cstr r1,[r0]; ;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;************************************************************** ***************;; 妈呀,终说见到艳阳天了; 跳到C语言的main函数处了.;;************************************************************** ***************[ :LNOT:THUMBCODEbl Main ;Do not use main() because ......;ldr pc, =Main ;hzhb .][ THUMBCODE ;for start-up code for Thumb modeorr lr,pc,#1bx lrCODE16bl Main ;Do not use main() because ......b .CODE32]; initializing stacksInitStacks;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'msrcpsr_c xsf,r1'mrs r0,cpsrbic r0,r0,#MODEMASKorr r1,r0,#UNDEFMODE|NOINTmsr cpsr_cxsf,r1 ;UndefModeldr sp,=UndefStack ; UndefStack=0x33FF_5C00orr r1,r0,#ABORTMODE|NOINTmsr cpsr_cxsf,r1 ;AbortModeldr sp,=AbortStack ; AbortStack=0x33FF_6000orr r1,r0,#IRQMODE|NOINTmsr cpsr_cxsf,r1 ;IRQModeldr sp,=IRQStack ; IRQStack=0x33FF_7000orr r1,r0,#FIQMODE|NOINTmsr cpsr_cxsf,r1 ;FIQModeldr sp,=FIQStack ; FIQStack=0x33FF_8000bic r0,r0,#MODEMASK|NOINTorr r1,r0,#SVCMODEmsr cpsr_cxsf,r1 ;SVCModeldr 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 SVCmode. ;==================================== ====================== =ReadNandIDmov r7,#NFCONFldr r0,[r7,#4] ;NFChipEn();bic r0,r0,#2str 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,#1beq %B1ldrb r0,[r7,#0x10] ;id = RdNFDat()<<8; mov r0,r0,lsl #8ldrb r1,[r7,#0x10] ;id |= RdNFDat();orr r5,r1,r0ldr r0,[r7,#4] ;NFChipDs();orr r0,r0,#2str r0,[r7,#4]mov pc,lrReadNandStatusmov r7,#NFCONFldr r0,[r7,#4] ;NFChipEn();bic r0,r0,#2str r0,[r7,#4]mov r0,#0x70 ;WrNFCmd(QUERYCMD); strb r0,[r7,#8]ldrb r1,[r7,#0x10] ;r1 = RdNFDat();ldr r0,[r7,#4] ;NFChipDs();orr r0,r0,#2str r0,[r7,#4]mov pc,lrWaitNandBusymov r0,#0x70 ;WrNFCmd(QUERYCMD);mov r1,#NFCONFstrb r0,[r1,#8]1 ;while(!(RdNFDat()&0x40));ldrb r0,[r1,#0x10]tst r0,#0x40beq %B1mov r0,#0 ;WrNFCmd(READCMD0);strb r0,[r1,#8]mov pc,lrCheckBadBlkmov r7, lrmov r5, #NFCONFbic r0,r0,#0x1f ;addr &= ~0x1f;ldr r1,[r5,#4] ;NFChipEn()bic r1,r1,#2str r1,[r5,#4]mov r1,#0x50 ;WrNFCmd(READCMD2)strb r1,[r5,#8]mov r1, #5;6 ;6->5strb r1,[r5,#0xc] ;WrNFAddr(5);(6) 6->5strb 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, #1001subs r0, r0, #1bne %B12ldr r0, [r5, #0x20]tst r0, #1beq %B2ldrb r0, [r5,#0x10] ;RdNFDat()sub r0, r0, #0xffmov r1,#0 ;WrNFCmd(READCMD0) strb r1,[r5,#8]ldr r1,[r5,#4] ;NFChipDs()orr r1,r1,#2str r1,[r5,#4]mov pc, r7ReadNandPagemov r7,lrmov r4,r1mov r5,#NFCONFldr r1,[r5,#4] ;NFChipEn()bic r1,r1,#2str 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,#0x10str r0,[r5,#4]bl WaitNandBusy ;WaitNFBusy()mov r0,#0 ;for(i=0; i<512; i++)1ldrb r1,[r5,#0x10] ;buf[i] = RdNFDat() strb r1,[r4,r0] add r0,r0,#1bic r0,r0,#0x10000cmp r0,#0x200bcc %B1ldr r0,[r5,#4] ;NFChipDs()orr r0,r0,#2str r0,[r5,#4]mov pc,r7;--------------------LED testEXPORT Led_TestLed_Testmov r0, #0x56000000mov r1, #0x5500str r1, [r0, #0x50]mov r1, #0x50str r1, [r0, #0x54]mov r2, #0x1000001subs r2, r2, #1bne %B1mov r1, #0xa0str r1, [r0, #0x54]mov r2, #0x1000002subs r2, r2, #1bne %B2b %B0mov pc, lr;====================================== ==================== =LTORG;GCS0->SST39VF1601;GCS1->16c550;GCS2->IDE;GCS3->CS8900;GCS4->DM9000;GCS5->CF Card;GCS6->SDRAM;GCS7->unusedSMRDATA DATA; 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 HCLK<=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)) ;GCS0DCD((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_ Tah<<4)+(B1_Tacp<<2)+(B1_PMC)) ;GCS1DCD((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+( B2_ Tah<<4)+(B2_Tacp<<2)+(B2_PMC)) ;GCS2DCD((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+( B3_ Tah<<4)+(B3_Tacp<<2)+(B3_PMC)) ;GCS3DCD((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+( B4_ Tah<<4)+(B4_Tacp<<2)+(B4_PMC)) ;GCS4DCD((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+( B5_ Tah<<4)+(B5_Tacp<<2)+(B5_PMC)) ;GCS5DCD ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN)) ;GCS6DCD ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN)) ;GCS7DCD((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Tsrc<<18)+(T chr< <16)+ REFCNT)DCD 0x32 ;SCLK power saving mode, BANKSIZE 128M/128M DCD 0x30 ;MRSR6 CL=3clkDCD 0x30 ;MRSR7 CL=3clkBaseOfROM DCD |Image$$RO$$Base|TopOfROM DCD |Image$$RO$$Limit|BaseOfBSS DCD |Image$$RW$$Base|BaseOfZero DCD |Image$$ZI$$Base|EndOfBSS DCD |Image$$ZI$$Limit|ALIGN; for entering power down mode; 1. SDRAM should be in self-refresh mode.; 2. All interrupt should be maksked for SDRAM/DRAM self-refresh.; 3. LCD controller should be disabled for SDRAM/DRAM self-refresh.。
start.S详解 2
/********************************************************************** ****** CPU_init_critical registers** setup important registers* setup memory timing********************************************************************** *****/@CPU初始化#ifndef CONFIG_SKIP_LOWLEVEL_INITcpu_init_crit:/** flush v4 I/D caches*/@初始化CACHESmov r0, #0mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB *//** disable MMU stuff and caches*/@关闭MMU和CACHESmrc p15, 0, r0, c1, c0, 0bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)orr r0, r0, #0x00000002 @ set bit 2 (A) Alignorr r0, r0, #0x00001000 @ set bit 12 (I) I-Cachemcr p15, 0, r0, c1, c0, 0@对协处理器的操作还是看不懂,暂时先不管吧,有时间研究一下ARM技术手册的协处理器部分。
/** before relocating, we have to setup RAM timing* because memory timing is board-dependend, you will* find a lowlevel_init.S in your board directory.*/@初始化RAM时钟,因为内存是跟开发板密切相关的,所以这部分在/开发板目录/lowlevel_init.S中实现mov ip, lr@保存LR,以便正常返回,注意前面是通过BL跳到cpu_init_crit来的。
MHDD命令详解
MHDD扫描硬盘时色块的含义? TIME 超时略过x UNC 错误无法纠正! ABRT 命令非正常退出S IDNF (扇区)ID未找到A AMNF (扇区)地址掩码未找到O T0NF 0磁道未找到* BBK 逻辑块损坏]MHDD命令详解EXIT(热键Alt+X):退出到DOS。
ID:硬盘检测,包括硬盘容量、磁头数、扇区数、SN序列号、Firmware固件版本号、LBA 数值、支持的DMA级别、是否支持HPA、是否支持AAM、SMART开关状态、安全模式级别及开关状态……等)。
INIT:硬盘初始化,包括Device Reset(硬盘重置)、Setting Drive Parameters(设定硬盘参数)、Recalibrate(重校准)。
I(热键F2):同时执行ID命令和INIT命令。
ERASE:快速删除功能,每个删除单位等于255个扇区(数据恢复无效)。
AERASE:高级删除功能,可以将指定扇区段内的数据逐扇区地彻底删除(比ERASE慢,数据恢复同样无效),每个删除单位等于1个扇区。
HPA:硬盘容量剪切功能,可以减少硬盘的容量,使BIOS检测容量减少,但DM之类的独立于BIOS检测硬盘容量的软件仍会显示出硬盘原始容量。
NHPA:将硬盘容量恢复为真实容量。
RHPA:忽略容量剪切,显示硬盘的真实容量。
CLS:清屏。
PWD:给硬盘加USER密码,最多32位,什么也不输入表示取消。
被锁的硬盘完全无法读写,低格、分区等一切读写操作都无效。
如果加密码成功,按F2键后可以看到Security一项后面有红色的ON。
要注意,设置完密码后必须关闭电源后在开机才会使密码起作用;UNLOCK:对硬盘解锁。
先选择0(USER),再正确输入密码。
注意:选择1(Master)无法解开密码。
DISPWD:解除密码,先选择0(USER),再正确输入密码。
在用DISPWD之前必须先用UNLOCK命令解锁。
要注意,除了用UNLOCK和DISPWD命令可以解密码之外,没有任何办法可以解锁。
Android的initrc文件的语法详解
Android初始化语言包含了四种类型的声明:Actions(行动)、 Commands(命令)、Services(服务)和Options(选项)。
所有这些都是以行为单位的,各种记号由空格来隔开。
C语言风格的反斜杠号可用于在记号间插入空格。
双引号也可用于防止字符串被空格分割成多个记号。
行末的反斜杠用于折行。
注释行以井号(#)开头(允许以空格开头)。
Actions和Services声明一个新的分组。
所有的命令或选项都属于最近申明的分组。
位于第一个分组之前的命令或选项将会被忽略。
Actions和Services有唯一的名字。
如果有重名的情况,第二个申明的将会被作为错误忽略。
(我们是否应该以覆盖来代替忽略)Actions(行动)----------Actions其实就是一序列的Commands(命令)。
Actions都有一个trigger(触发器),它被用于决定action的执行时间。
当一个符合action触发条件的事件发生时,action会被加入到执行队列的末尾,除非它已经在队列里了。
队列中的每一个action都被依次提取出,而这个action中的每个command (命令)都将被依次执行。
Init在这些命令的执行期间还控制着其他的活动(设备节点的创建和注销、属性的设置、进程的重启)。
Actions的形式如下:on 《trigger》《command》《command》《command》Services(服务)----------Services(服务)是一个程序,他在初始化时启动,并在退出时重启(可选)。
Services(服务)的形式如下:service 《name》《pathname》 [ 《argument》 ]*《option》《option》...Options(选项)----------Options(选项)是一个Services(服务)的修正者。
他们影响Services(服务)在何时,并以何种方式运行。
