首页 2440init

2440init

举报
开通vip

2440init E:\work\ARM9\ProgramExaple NEW\XYD2440_Test2011-01-15\src\2440init.s ;========================================= ; NAME: 2440INIT.S ; DESC: C start up codes ; Configure memory, ISR ,stacks ; Initialize C-variables ; HISTORY: ; 2002.02.25:kwtark: ver 0....

2440init
E:\work\ARM9\ProgramExaple NEW\XYD2440_Test2011-01-15\src\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 functions for testing STOP,Sleep mode ; 2003.03.14:DonGo: Modified for 2440. ;========================================= ;板子上电后就会从这里开始执行,主要完成基本初始化,还有判断是从nor还是nand启动, ;再实现把程序搬到SDRAM当中,在搬运成功后再跳到main函数里面执行。 ;我们现在开始来看看它的具体代码吧! ;GET和INCLUDE的功能是相同的,功能都是引进一些编译过的文件。 GET option.inc GET memcfg.inc GET 2440addr.inc ;定义SDRAM工作在Reflesh模式下,SDRAM有两种刷新模式:selfreflesh,autoreflesh。 ;后者是在其使用过程当中设置的。 BIT_SELFREFRESH EQU (1<<22) ;下面是对arm处理器模式寄存器对应的常数进行赋值,arm处理器有一个CPSR寄存器, ;它的后五位决定了处理器处于哪个模式下。可以看出常数的定义都不会超过后5位的。 ;Pre-defined constants USERMODE EQU 0x10 FIQMODE EQU 0x11 IRQMODE EQU 0x12 SVCMODE EQU 0x13 ABORTMODE EQU 0x17 UNDEFMODE EQU 0x1b MODEMASK EQU 0x1f NOINT EQU 0xc0 GPBCON EQU 0x56000010 GPBDAT EQU 0x56000014 ;各个异常模式的堆栈 ;The location of stacks 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 ~ ;------------------------------------------------------------------------------ UND_Stack_Size EQU 0x00000400 ; SVC_Stack_Size EQU 0x00000400 ABT_Stack_Size EQU 0x00000400 FIQ_Stack_Size EQU 0x00000400 IRQ_Stack_Size EQU 0x00000400 USR_Stack_Size EQU 0x00004000 Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \ FIQ_Stack_Size + IRQ_Stack_Size + USR_Stack_Size) AREA STACK, NOINIT, READWRITE, ALIGN=3 Stack_Mem SPACE Stack_Size Stack_Top EQU Stack_Mem + Stack_Size Heap_Size EQU 0x00000000 AREA HEAP, NOINIT, READWRITE, ALIGN=3 Page: 1 E:\work\ARM9\ProgramExaple NEW\XYD2440_Test2011-01-15\src\2440init.s Heap_Mem SPACE Heap_Size ;------------------------------------------------------------------------------- ;这一段是统一arm的工作状态和对应的软件编译方式(16位编译环境使用tasm.exe编译)。 ;arm处理器的工作状态分为两种:32位,arm执行字对齐的arm指令集;16位,arm执行半字 ;对齐的Thumb指令集。不同的工作状态,编译方式也不一样。所以下面的程序就是判断 ;arm的工作方式来确定它的编译方式。 ;Check if tasm.exe(armasm -16 ...@ADS 1.0) is used. GBLL THUMBCODE ;定义THUMBCODE 这个变量GBLL 声明一个全局逻辑变量并初始化为{FALSE} [ {CONFIG} = 16 ;"["表示"if","|"表示"else","]"表示"endif",对于CONFIG是在ADS编译中 定义的内部变量。 THUMBCODE SETL {TRUE} CODE32 | THUMBCODE SETL {FALSE} ] ;如果ARM是在16位的工作状态的话,就使全局变量THUMBCODE设置为ture。 MACRO ;这个是宏定义的关键字 MOV_PC_LR ;作用是子程序返回 [ THUMBCODE ;当目标程序是Thumb时,就要使用BX跳转返回,并转换模式。 bx lr | ; mov pc,lr ;目标程序是ARM指令集,直接把lr赋给pc就可以了。 bx lr ] MEND ;宏定义的结束标志。 MACRO MOVEQ_PC_LR ;这个是带“相等”条件的子程序返回。和上面说的类似。 [ THUMBCODE bxeq lr | moveq pc,lr ] MEND ;在宏定义下面的handlexxx HANDLER handlexxx都会展成以下的程序段, ;这段程序主要把中断服务程序的入口地址传送给pc,在程序的用34字节 ;空间来存放中断服务程序的入口地址,每个字空间都会有一个标号, ;以handlerxxx开头的。 ;这个宏用于第一次查表过程的实现中断向量的重定向,如果你比较细心 ;的话就会发现在_ISR_STARTADDRDSS=0x33ff_ff里定义的第一级中断向量 ;表是采用形如Handle***的方式的,而程序的ENTRY处(程序开始处)采用的是 ;b Hadnler***的方式。;在这里Handler**就是通过Handler这个宏和Handler***进行联系的。 ;这种方式的优点是真正定义的向量数据在内存空间里,而不是在ENTRY处的 ;ROM(FLASH)空间里,这样,我们就可以在程序里灵活的改动向量的数据了。 MACRO $HandlerLabel HANDLER $HandleLabel $HandlerLabel sub sp,sp,#4 ;decrement sp(to store jump address);先预留空间,为了存 储跳转地址。 ;把工作寄存器按入堆栈。 stmfd sp!,{r0} ;PUSH the work register to stack(lr does not push becau se it return to original address) ;这两句的功能是把中断程序的入口地址先放在中间变量r0处。 ldr r0,=$HandleLabel ;load the address of HandleXXX to r0 ;把HandlerXXX所指向的 内容 财务内部控制制度的内容财务内部控制制度的内容人员招聘与配置的内容项目成本控制的内容消防安全演练内容 放入到r0 ldr r0,[r0] ;load the contents(service routine start address) of Ha ndleXXX ;把中断服务程序的入口地址按入堆栈。 str r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stack Page: 2 E:\work\ARM9\ProgramExaple NEW\XYD2440_Test2011-01-15\src\2440init.s ;最后把堆栈中的中断程序入口地址弹给pc寄存器,这样就可以执行相应的中断服务程序了。 ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR) MEND ;S3C2440有两种中断模式:一种有中断向量表的,一种则没有。有表的话实时性比较好。 ;当一个外部中断0发生后,程序自动跳转到地址0x20处,0x20地址单元的指令为“ldr pc, = Handle rEINT0”, ;因此程序跳转到HandlerEINT0处执行这个宏操作,就是把外部中断地址赋给PC。 ;一个arm程序是由R0,RW,ZI三个段组成。其中R0为代码段,RW是已经初始化的全局变量, ;ZI是未初始化的全局变量,BOOTLOADER要将RW段复制到RAM中并将ZI段清零。 ;编译器使用下列段来记录各段的起始地址和结束地址 ;|Image$$RO$$Base|(ADS用这种写法), |Image$$ER_ROM1$$RO$$Base| (MDK用这种写法) ; RO 段起始地址 ;|Image$$RO$$Limit|(ADS用这种写法),|Image$$ER_ROM1$$RO$$Limit| (MDK用这种写法) ;RO 段结束地址加1 ;|Image$$RW$$Base| (ADS用这种写法),|Image$$RW_RAM1$$RW$$Base| (MDK用这种写法) ;RW 段起始地址 ;|Image$$RW$$Limit| (ADS用这种写法),|Image$$RW_RAM1$$ZI$$Limit|(MDK用这种写法) ;RW 段结束地址加1 ;|Image$$ZI$$Base| (ADS用这种写法),|Image$$RW_RAM1$$ZI$$Base| (MDK用这种写法) ; ZI 段起始地址 ;|Image$$ZI$$Limit| (ADS用这种写法),|Image$$RW_RAM1$$ZI$$Limit|(MDK用这种写法) ; ZI 段结束地址加1 IMPORT |Image$$ER_ROM1$$RO$$Base| ; Base of ROM code IMPORT |Image$$ER_ROM1$$RO$$Limit| ; End of ROM code (=start of ROM data) IMPORT |Image$$RW_RAM1$$RW$$Base| ; Base of RAM to initialise IMPORT |Image$$RW_RAM1$$ZI$$Base| ; Base and limit of area IMPORT |Image$$RW_RAM1$$ZI$$Limit| ; to zero initialise ;引入外部变量mmu的快速总线模式和同步总线模式两个变量 IMPORT MMU_SetAsyncBusMode IMPORT MMU_SetFastBusMode ;hzh ;引入外部标号我们所熟知的main函数 IMPORT __main ; The main entry of mon program PRESERVE8 ;定义arm汇编程序段,段名叫init段,为只读段 AREA RESET,CODE,READONLY ; ENTRY EXPORT __ENTRY ;导出__ENTRY标号 __ENTRY ResetEntry ;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 err or. ;判断模式改变是否定义过(ASSERT是伪指令,:DEF:lable判断lable是否定义过了) ASSERT :DEF:ENDIAN_CHANGE [ ENDIAN_CHANGE ;如果ENDIAN_CHANGE为真,则执行以下 ASSERT :DEF:ENTRY_BUS_WIDTH ;判断是否定义了总线宽度 [ ENTRY_BUS_WIDTH=32 ;如果存储器是32位的总线宽度 b ChangeBigEndian ;DCD 0xea000007 ] [ ENTRY_BUS_WIDTH=16 ;如果存储器是16位的总线宽度 andeq r14,r7,r0,lsl #20 ;DCD 0x0007ea00 ] [ ENTRY_BUS_WIDTH=8 ;如果是存储器是8位总线宽度 Page: 3 E:\work\ARM9\ProgramExaple NEW\XYD2440_Test2011-01-15\src\2440init.s streq r0,[r0,-r10,ror #1] ;DCD 0x070000ea ] | ;如果总线宽度没有定义的话,就直接跳转到复位中断 b ResetHandler ;程序执行的地跳跳转指令 ] 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 ;@0x20 b EnterPWDN ; Must be @0x20. ;进入powerdown模式 ;以上8条跳转指令,是8个异常中断处理向量,一定要按照顺序排好, ;据我了解,每次出现异常的话,是由硬件自行查表的。 ChangeBigEndian ;@0x24 [ ENTRY_BUS_WIDTH=32 DCD 0xee110f10 ;0xee110f10 => mrc p15,0,r0,c1,c0,0 DCD 0xe3800080 ;0xe3800080 => orr r0,r0,#0x80; //Big-endian DCD 0xee010f10 ;0xee010f10 => mcr p15,0,r0,c1,c0,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 mod e. DCD 0xffffffff DCD 0xffffffff DCD 0xffffffff DCD 0xffffffff b ResetHandler HandlerFIQ HANDLER HandleFIQ HandlerIRQ HANDLER HandleIRQ HandlerUndef HANDLER HandleUndef HandlerSWI HANDLER HandleSWI HandlerDabort HANDLER HandleDabort HandlerPabort HANDLER HandlePabort ;下面这段程序很重要,他是实现第二次查表的程序。arm把所有中断都归为一个IRQ和一个FIRQ中断 异常, ;我们为了要知道具体的中断,从而才可以跳到中断对应的中断服务程序。 IsrIRQ sub sp,sp,#4 ;reserved for PC ;保留pc寄存器的值 stmfd sp!,{r8-r9} ;把r8 r9按入堆栈 ldr r9,=INTOFFSET ;把中断偏移INTOFFSET的地址装入r9里面 ldr r9,[r9] ;取出INTOFFSET单元里面的值给r9 ldr r8,=HandleEINT0 ;向量表的入口地址赋给r8 add r8,r8,r9,lsl #2 ;求出具体中断向量的地址 ldr r8,[r8] ;中断向量里面存储的中断服务程序的入口地址赋给r8 str r8,[sp,#8] ;按入堆栈 ldmfd sp!,{r8-r9,pc} ;堆栈弹出,跳转到相应的中断服务程序 LTORG ;声明文字池 ;板子上电后就,程序就执行0x00处的b ResetHandler Page: 4 E:\work\ARM9\ProgramExaple NEW\XYD2440_Test2011-01-15\src\2440init.s ;======= ; ENTRY ;======= ResetHandler ldr r0,=WTCON ;关闭看门狗; watch dog disable ldr r1,=0x0 str r1,[r0] ldr r0,=INTMSK ldr r1,=0xffffffff ;关闭所有中断;all interrupt disable str r1,[r0] ldr r0,=INTSUBMSK ldr r1,=0x7fff ;关闭所有子中断;all sub interrupt disable str r1,[r0] ;[ {FALSE} ; Led_Display ldr r0,=GPBCON ldr r1,=0x15400 str r1,[r0] ;使GPB10~GPB4为输出口,GPB3~GPB0为输入口 ldr r0,=GPBDAT ldr r1,=0x3F str r1,[r0] ldr r0,=GPBDAT ;ldr r1,=0xFFFF ldr r1,=0x0 str r1,[r0] ;使GPB10~GPB4输出为低电平,GPB3~GPB0输入为低电平 ;] ;LOCKTIME是pll的lock time计数器。为了减少pll的lock time,调整LOCKTIME寄存器。 ;To reduce PLL lock time, adjust the LOCKTIME register. ldr r0,=LOCKTIME ;赋给这个值后,UPLL和MPLL的locktime的值都会设定好了。具体为什么是设定这个值,你就去 问问三星公司吧。 ldr r1,=0xffffff str r1,[r0] [ PLL_ON_START ;设置CLKDIVN的值在PLL锁存时间之后有效。 ; 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] ; MMU_SetAsyncBusMode and MMU_SetFastBusMode over 4K, so do not call here ; call it after copy, hzh ; 可以看出是对FCLK、PCLK以及HCLK三者的比率设置。只要通过对CLKDIVN执行操作就可以得到相 应需要的比率了。 ; [ CLKDIV_VAL>1 ;如果 Fclk:Hclk不是1:1的话执行下面; means Fclk:Hclk is not 1:1 . ; bl MMU_SetAsyncBusMode ; | ; bl MMU_SetFastBusMode ; default value. ; ] ;program has not been copied, so use these directly, hzh [ CLKDIV_VAL>1 ; means Fclk:Hclk is not 1:1. mrc p15,0,r0,c1,c0,0 orr r0,r0,#0xc0000000 ;R1_nF:OR:R1_iA mcr p15,0,r0,c1,c0,0 | mrc p15,0,r0,c1,c0,0 bic r0,r0,#0xc0000000 ;R1_iA:OR:R1_nF mcr p15,0,r0,c1,c0,0 ] ;这里可以看出,如果FCLK:HCLK不是1:1的关系的话,就要转成异步总线模式。反之,如果是 Page: 5 E:\work\ARM9\ProgramExaple NEW\XYD2440_Test2011-01-15\src\2440init.s 这个比例关系的话,就转成快速总线模式。 ;配置 UPLL ;Configure UPLL Fin=12.0MHz UFout=48MHz ldr r0,=UPLLCON ldr r1,=((U_MDIV<<12)+(U_PDIV<<4)+U_SDIV) ;这里就是非常熟悉的PMS啦,Fin = 12.0MHz, UCLK = 48MHz str r1,[r0] nop ; Caution: After UPLL setting, at least 7-clocks delay must be inserted for set ting hardware be completed. nop nop nop nop nop nop ;配置 MPLL ;Configure MPLL Fin=12.0MHz MFout=304.8MHz一定要使最后的频率为16.9344MHz,不然你甭想 用USB接口了 ldr r0,=MPLLCON ;对MPLL进行配置 ldr r1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV) ;Fin=16.9344MHz str r1,[r0] ] ;判断是否是从休眠模式唤醒的,对GSTATUS2[2]的 检测 工程第三方检测合同工程防雷检测合同植筋拉拔检测方案传感器技术课后答案检测机构通用要求培训 就可以判断出是否从休眠模式唤醒的。 ;Check if the boot is caused by the wake-up from SLEEP mode. ldr r1,=GSTATUS2 ldr r0,[r1] tst r0,#0x2 ;In case of the wake-up from SLEEP mode, go to SLEEP_WAKEUP handler. bne WAKEUP_SLEEP ;如果是的话就跳转。 EXPORT StartPointAfterSleepWakeUp ;定义一个外部的StartPointAfterSleepWakeUp StartPointAfterSleepWakeUp ;=============================================================================== ;设置内存控制器等寄存器的值,因为这些寄存器是连续排列的,所以采用如下办法对这些 ;寄存器进行连续设置.其中用到了SMRDATA的数据,这在代码后面有定义 ;=============================================================================== ;Set memory control registers ;ldr r0,=SMRDATA adrl r0, SMRDATA ;be careful!, hzh ldr r1,=BWSCON ;BWSCON Address ;SMRDATA数据的结束地址,共有52字节的数据 add r2, r0, #52 ;End address of SMRDATA 0 ldr r3, [r0], #4 str r3, [r1], #4 cmp r2, r0 bne %B0 ;上面这段代码的作用就是设置存储控制器。在代码的后面有一个SMRDATA的数据区, ;用r0来定义它的起始地址,用r2来定义它的结束地址。r3是代表那13个存储控制器. ;代码很明显,就是把内存的数据赋给这13个存储控制器里面的。 ;================================================================================ ;如果 EINT0 产生(这中断就是我们按键产生的), 就清除SDRAM ,不过好像没人会在这个时候按 ;================================================================================ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;; ;;;;;;;;;;;;; When EINT0 is pressed, Clear SDRAM ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;; ; check if EIN0 button is pressed ldr r0,=GPFCON Page: 6 E:\work\ARM9\ProgramExaple NEW\XYD2440_Test2011-01-15\src\2440init.s ldr r1,=0x0 str r1,[r0] ;对GPF设置为输入的功能 ldr r0,=GPFUP ldr r1,=0xff str r1,[r0] ;禁止上拉电阻 ldr r1,=GPFDAT ldr r0,[r1] bic r0,r0,#(0x1e<<1) ;bic是r0与#(0x1e<<1)的反码按位相与。; bit clear tst r0,#0x1 ;这里就是测试最后一位是否为0,为0时 说明 关于失联党员情况说明岗位说明总经理岗位说明书会计岗位说明书行政主管岗位说明书 是有按键按下了。 bne %F1 ;当按键0没有被按下的时候,就跳转啦。 ; Clear SDRAM Start ; 这就是清零内存的代码 mov r1,#0 mov r2,#0 mov r3,#0 mov r4,#0 mov r5,#0 mov r6,#0 mov r7,#0 mov r8,#0 ldr r9,=0x4000000 ;64MB ldr r0,=0x30000000 0 stmia r0!,{r1-r8} subs r9,r9,#32 bne %B0 ;很明显可以看出,程序利用r1~r8这几个寄存器把0x30000000到0x34000000的内存全部清零了。 ;Clear SDRAM End 1 ;Initialize stacks bl InitStacks ;初始化堆栈 ;=========================================================== ;bl Led_Test ;又是LED,注掉了 ;======================================================================= ; 下面又有看头了,这个初始化程序好像被名曰hzh的高手改过 ; 能在NOR NAND 还有内存中运行,当然了,在内存中运行最简单了. ; 在NOR NAND中运行的话都要先把自己拷到内存中. ; 此外,还记得上面提到的|Image$$RO$$Base|,|Image$$RO$$Limit|...吗? ; 这就是拷贝的依据了!!! ;========================================================================= ldr r0, =BWSCON ldr r0, [r0] ; ;OM[1:0] != 0, 从NOR FLash启动或直接在内存运行 ands r0, r0, #6 ;OM[1:0] != 0, NOR FLash boot ;不需要从NAND FLASH启动就在这里跳转啦 bne copy_proc_beg ;不用读取NAND FLASH;do not read nand flash ;OM[1:0] == 0,就从NAND FLash启动 adr r0, ResetEntry ;OM[1:0] == 0, NAND FLash boot ; ;再比较入口是否为0地址处 ,如果不是则是用仿真器 cmp r0, #0 ;if use Multi-ice, ;========================================================================== ;如果不是,则表示主板设置了从NAND启动,但这个程序由于其它原因, ;并没有从NAND启动,这种情况最有可能的原因就是用仿真器. Page: 7 E:\work\ARM9\ProgramExaple NEW\XYD2440_Test2011-01-15\src\2440init.s ;========================================================================== ;仿真器也不需要在NAND FLASH启动 bne copy_proc_beg ;do not read nand flash for boot ;nop ;如果是0才是真正从NAND 启动,因为其4k被复制到0地址开始的stepingstone 内部sram中 ; 注意adr得到的是相对地址,非绝对地址 == if use Multi-ice, ;=========================================================== nand_boot_beg ; 这一段代码完成从NAND读代码到RAM mov r5, #NFCONF ;首先设定NAND的一些控制寄存器 ;set timing value ldr r0, =(7<<12)|(7<<8)|(7<<4) str r0, [r5] ;enable control ldr 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, r0 beq %F1 ;相等的话就跳到下一个1标号处 mov r6, #1 1 bl ReadNandStatus ;读取NAND状态,结果放在r1里 mov r8, #0 ;r8设初值0,意义为页号 ldr r9, =ResetEntry ;r9设初值为初始化程序入口地址 ;========================================================================= ; 注意,在这里使用的是ldr伪指令,而不是上面用的adr伪指令,它加载的是ResetEntry ; 的决对地址,也就是我们期望的RAM中的地址,在这里,它和|Image$$RO$$Base|一样 ; 也就是说,我如我们编译程序时RO BASE指定的地址在RAM里,而把生成的文件拷到 ; NAND里运行,由ldr加载的r9的值还是定位在内存. ;========================================================================= 2 ands r0, r8, #0x1f ;凡r8为0x1f(32)的整数倍-1,eq有效,ne无效 bne %F3 ;这句的意思是对每个块(32页)进行检错 mov r0, r8 ;r8->r0 bl CheckBadBlk ;检查NAND的坏区 cmp r0, #0 ;比较r0和0 addne r8, r8, #32 ;存在坏块的话就跳过这个坏块 bne %F4 ;没有的话就跳到标 号4处 3 mov r0, r8 ;当前页号->r0 mov r1, r9 ;当前目标地址->r1 bl ReadNandPage ;读取该页的NAND数据到RAM add r9, r9, #512 ;每一页的大小是512Bytes ;SDRAM address increase add r8, r8, #1 ;r8指向下一页;flash page add 1 4 cmp r8, #256 ;比较是否读完256页即128KBytes;copy 256 pages except bad block bcc %B2 ;如果r8小于256(没读完),就返回前面的标号2处 mov r5, #NFCONF ;DsNandFlash;DsNandFlash ldr r0, [r5, #4] bic r0, r0, #1 str r0, [r5, #4] ldr pc, =copy_proc_beg ;调用copy_proc_beg ;=========================================================== ;=========================================================== ;Nor Flash操作部分 ;在前面也看到copy_proc_beg这个标号出现很多次, Page: 8 E:\work\ARM9\ProgramExaple NEW\XYD2440_Test2011-01-15\src\2440init.s ;这个标号下面的代码完成的功能就是把nand flash的内容拷贝到ram当中。 ;ADR装载的是当时运行的时候的地址 ;LDR装载的是连接时候的绝对地址 ;ResetEntry 是一个程序开头的地址,用了ADR,所以生成的是一个偏移量,也就是当时运行 ;的时候的地址,如果确实从从nor flash启动的话,那么这个地址就应该为 0,如果这程序 ;是用仿真器下载到 0x30000000 的SDRAM中运行的话,那么这个地址就应该等于 0x30000000 copy_proc_beg adr r0, ResetEntry ldr r2, BaseOfROM ;接着代码判断刚才的两个地址是否相等。我们可以分两种情况来看 ;1,如果从norflash启动,那么 ResetEntry=0 BaseOfROM=0x3000000,显然不相同 ;2,如果用工具将这个文件加载到 0x30000000 的话,那么这个时候 ResetEntry=0 ;BaseOfROM=0x3000000 显然这两个地址是相同的。 ;这么做的效果就是:如果从nor flash启动的话,那么就将程序代码 copy 到运行时地址,也 ;就是 |Image$$RO$$Base| ,如果地址是相同的,那么就不需要执行 COPY 动作了。 ; cmp r0, r2 ;两个进行比较 ldreq r0, TopOfROM ;如果相同的话,为r0赋上R0的结束位置,也是RW的起始位置。 ;如果相等的话(在内存运行),TopOfROM->r0 beq InitRam ;同时跳到InitRam ;========================================================= ;下面这个是针对代码在NOR FLASH时的拷贝 方法 快递客服问题件处理详细方法山木方法pdf计算方法pdf华与华方法下载八字理论方法下载 ;功能为把从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|也是由连接器生成 ;两者之间就是初始化数据的存放地放 ;======================================================= ldr r3, TopOfROM ;以下代码是针对代码在NOR FLASH时的拷贝方法。 0 ;R0就是当前代码的开始地址,R2是目标地址,R3-R2 就是代码的总长度, ;这里是包含了RO+RW的总大小,ZI不需要纳入输出段的。 ldmia r0!, {r4-r7} stmia r2!, {r4-r7} cmp r2, r3 bcc %B0 ;这几段代码的功能就是把ResetEntry的内容搬到BaseOfROM(R0的起始 位置,后面有声明的)。 ;下面两句是修正 ;原来是每4个字节一次赋值操作,这样很容易就产生边界问 快递公司问题件快递公司问题件货款处理关于圆的周长面积重点题型关于解方程组的题及答案关于南海问题 ,如果代码段的长度不是4的倍数的话 ;就会出问题,而且问题的关键不是复制多1-2个的问题,问题的是影响到下面RW段的复制操作的 ;所以必须修正,修正办法很简单,先算出现在超出多少,然后减回去 ......这就是2个减法语句的 作用了。 ;这两句结束之后,R0的数值就是指向代码段的末尾,加载段。所以接着处理RW段就OK了 sub r2, r2, r3 ;r2=BaseOfROM-TopOfROM=(-)代码长度 sub r0, r0, r2 ;r0=ResetEntry-(-)代码长度=ResetEntry+代码长度 ;这里使 ResetEntry的位置往下移,为了后面的数据拷贝做准备。 ;====================================================================================== ;====================================================================================== ;接着进行的就是重定位RW段。默认状态RW是紧跟着RO段的,但是是可以以不同的地址定位的。 ;首先,他不判断是否有效,一定进行定位操作,也就是说,就算是RW跟在RO后面也做一次重定位 ;操作。这个只是写代码的人的喜好。 ;下面分析一下这个COPY也有个精巧的地方,那就是,我怎么知道RW段应该从什么地方开始COPY ;要COPY多少,我们从编译器得到的只是运行时地址,而不是实际加载域的地址。怎么得到加载域 ;的地址? ;诀窍就在于,这个时候RO的运行域和加载域是一样的!!!(这是针对下载到SDRAM的情况) ;那么 TopOfROM 本来是运行域的 RO段的尾段!注意,这里不是RW运行域的开始段!这时的加载 Page: 9 E:\work\ARM9\ProgramExaple NEW\XYD2440_Test2011-01-15\src\2440init.s ;域和运行域是相同的,所以这个时候 TopOfROM 其实就是 RW 的加载域!!!要注意我们的前提 ;是 运行域和加载域是一样的 时候才有这个结论,RW的加载域是紧跟着RO的,RW的运行域就可以 ;简单的从编译器传过来的参数 BaseOfBSS 里面得到,既然加载域和运行域的实际地址都知道了 ;那么接着的COPY动作就很简单了。 InitRam ldr r2, BaseOfBSS ldr r3, BaseOfZero 0 cmp r2, r3 ldrcc r1, [r0], #4 strcc r1, [r2], #4 bcc %B0 ;可以看出这一段是对ResetEntry里面定义好的数据拷贝到RW段。 ;接着就是将所有的ZI 段全部清零,这个很简单,因为只需要知道运行域就OK, ;而这个参数是直接从编译器传递而来的。 mov r0, #0 ldr r3, EndOfBSS 1 cmp r2, r3 strcc r0, [r2], #4 bcc %B1 ;如果拷贝完数据后还剩下多余的空间的话,就往里面填充0 ;下面这个操作的最后一步,就是从加载域地址(也就是当前地址)跳转到运行域地址,理解好LDR指 令的话, ;这里就能理解了,2 这个标号的代表的是运行域地址,这个值只绝对的,编译的时候决定好的, ;所以将这个地址加载到 PC的话实现的就是从 加载域 到运行域 的无缝连接。 ;好了,下面接着的地址就是在运行域执行了,通常就是 SDRAM中了,这种COPY技术其实在bootload er ;中是很常用的。如果理解了,那么uboot 和vivi上面的工作原理,其实是一样,不过只是作者不同 ;代码的风格也不同,但原理是不变的。 ldr pc, =%F2 ;goto compiler address 2 ; [ CLKDIV_VAL>1 ; means Fclk:Hclk is not 1:1. ; bl MMU_SetAsyncBusMode ; | ; bl MMU_SetFastBusMode ; default value. ; ] ;bl Led_Test ;=========================================================== ;=========================================================== ; 进入C语言前的最后一步了,就是把我们用说查二级向量表 ; 的中断例程安装到一级向量表(异常向量表)里. ; Setup IRQ handler ldr r0,=HandleIRQ ;This routine is needed ldr r1,=IsrIRQ ;if there is not 'subs pc,lr,#4' at 0x18, 0x1c str r1,[r0] ;这三条语句很明显就是
本文档为【2440init】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_941224
暂无简介~
格式:pdf
大小:97KB
软件:PDF阅读器
页数:0
分类:互联网
上传时间:2011-04-06
浏览量:14