【原创】从2440init.s修改成的启动代码,nandflash启动

   由于jtag-mini是并口的,笔记本没有,不能烧写norflash,所以,用mini2440出厂前norflash中固化的supervivi配合dnw软件,用usb烧写nandflash。使用nandflash也是现在比较节省、流行的做法。以下代码是从2440init.s裁剪而来,其中norflash、sdram等启动方式已被删减,仅支持从nandflash启动。

   注意,由于从nandflash仅拷贝128KB,所以程序大小需要把握一下,当然还可以修改以下代码实现支持更大的代码长度。

 GET memcfg.inc
 GET 2440addr.inc
 ;GET option.inc

 IMPORT  |Image$$RO$$Base| ; Base of ROM code
 IMPORT  |Image$$RO$$Limit|  ; End of ROM code (=start of ROM data)
 IMPORT  |Image$$RW$$Base|   ; Base of RAM to initialise
 IMPORT  |Image$$ZI$$Base|   ; Base and limit of area
 IMPORT  |Image$$ZI$$Limit|  ; to zero initialise
 
 IMPORT  Main    ; The main entry of mon program
 
 AREA    RESET,CODE,READONLY
 
 EXPORT __ENTRY      ;导出__ENTRY标号
__ENTRY
ResetEntry
 b ResetHandler
 
 LTORG
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]

;===============================================================================
 ;设置内存控制器等寄存器的值,因为这些寄存器是连续排列的,所以采用如下办法对这些
 ;寄存器进行连续设置.其中用到了SMRDATA的数据,这在代码后面有定义
;===============================================================================
    adrl r0, SMRDATA;be careful!
 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 �
;上面这段代码的作用就是设置存储控制器。在代码的后面有一个SMRDATA的数据区,
;用r0来定义它的起始地址,用r2来定义它的结束地址。r3是代表那13个存储控制器.
;代码很明显,就是把内存的数据赋给这13个存储控制器里面的。
;================================================================================
 ;清除SDRAM
;================================================================================

; 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 �
;很明显可以看出,程序利用r1~r8这几个寄存器把0x30000000到0x34000000的内存全部清零了。

;===============================================================================
;设计堆栈指针
;===============================================================================
 ldr sp, =0x33ff5800
;===============================================================================
;初始化nandflash及代码搬移
;===============================================================================

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 �  ;相等的话就跳到下一个1标号处
 ldr r0, =0xec75  ;这是另一个期望值
 cmp r5, r0
 beq �  ;相等的话就跳到下一个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 �      ;这句的意思是对每个块(32页)进行检错
 mov r0, r8  ;r8->r0
 bl CheckBadBlk    ;检查NAND的坏区
 cmp r0, #0      ;比较r0和0
 addne r8,r8,#32   ;存在坏块的话就跳过这个坏块
 bne �       ;没有的话就跳到标号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 �       ;如果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,已经在SDRAM里啦!

;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
 ldr r0, TopOfROM
 ldr r2, BaseOfBSS
 ldr r3, BaseOfZero
0
 cmp r2, r3
 ldrcc r1, [r0], #4
 strcc r1, [r2], #4
 bcc �                 ;可以看出这一段是对ResetEntry里面定义好的数据拷贝到RW段。
        ;接着就是将所有的ZI 段全部清零,这个很简单,因为只需要知道运行域就OK,
        ;而这个参数是直接从编译器传递而来的。
 mov r0, #0
 ldr r3, EndOfBSS
1
 cmp r2, r3
 strcc r0, [r2], #4
 bcc �                ;如果拷贝完数据后还剩下多余的空间的话,就往里面填充0
;===============================================================================
;检验代码运行位置
;===============================================================================
 ldr r0, =ResetEntry
 ldr r1, =0x30000000
 cmp r0, r1
 beq �
 
 ;灯全亮
 ldr r0,=GPBCON
 ldr r1,=0x00555555
 str r1,[r0]
 ldr r0,=GPBDAT
 ldr r1,=0
 str r1,[r0]
loop
  b loop

 ldr pc, =�   ;goto compiler address
2

 bl Main
 

;===============================================================================
; nandflash相关函数
;===============================================================================

ReadNandID
 mov      r7,#NFCONF
 ldr      r0,[r7,#4]   ;NFChipEn();
 bic      r0,r0,#2
 str      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,#1
 beq      �
 ldrb     r0,[r7,#0x10]  ;id  = RdNFDat()<<8;
 mov      r0,r0,lsl #8
 ldrb     r1,[r7,#0x10]  ;id |= RdNFDat();
 orr      r5,r1,r0
 ldr      r0,[r7,#4]    ;NFChipDs();
 orr      r0,r0,#2
 str      r0,[r7,#4]
 mov pc,lr
    ;bx  lr
ReadNandStatus
 mov  r7,#NFCONF
 ldr      r0,[r7,#4]   ;NFChipEn();
 bic      r0,r0,#2
 str      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,#2
 str      r0,[r7,#4]
 mov pc,lr
    ;bx  lr
WaitNandBusy
 mov      r0,#0x70     ;WrNFCmd(QUERYCMD);
 mov      r1,#NFCONF
 strb     r0,[r1,#8]
1        ;while(!(RdNFDat()&0x40));
 ldrb     r0,[r1,#0x10]
 tst      r0,#0x40
 beq  �
 mov     

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值