研究arm也有2个月了,现在才感觉理解了arm在Nand flash模式下的启动过程,现在来这里记录下来以表达我无比喜悦的心情。闲话少说,趁着还没有忘记学习过程中的感受,直接进入正题。
大家都知道,arm在Nand flash启动模式下启动时系统会将Nand flash中的前4KB代码拷贝到SRAM(也就是Steppingstone中),由SRAM配置中断向量表和完成Nand flash访问的必要初始化,然后将Nand flash中的全部程序代码拷贝到SDRAM中,最后由SRAM跳转到SDRAM,然后程序就正常执行了,这一过程看上去很简单,但是真正理解这一过程还是不简单的,尽管这样,还是想告诉大家仔细理解还是比较容易理解这个过程的。如果您是ADS用户,你省去了很多麻烦,但我不确定你省去的这些麻烦是否值得,这里介绍的是一种麻烦的方式,linux下的led程序。
代码Head.s
.extern main .text .global _start _start: b reset reset: ldr sp,=4096 bl disable_watch_dog bl clock_init bl memsetup bl copy_steppingstone_to_sdram ldr pc,=on_sdram on_sdram: msr cpsr_c,#0xdf ldr sp,=0x34000000 ldr lr,=halt_loop ldr pc,=Main halt_loop: b halt_loop
我认为,最需要理解的就是这段代码了。先简单的解释下这段代码。
(1)由于arm执行reset之后pc会被清零,也就是reset中断的中断入口地址,因此,第一条指令就是b reset,跳转到reset中断处理函数。
(2)由于这里硬件配置都是C语言来完成的,而且我们的初始代码比较小,完全不会超出4KB,因此可以在SRAM使用堆栈,故将SP设置为4096,以提供C运行环境
(3)接下来的3个bl分别完成了关闭看门够定时器,配置时钟信号和存储器配置的工作,第四个bl是将SRAM的4KB空间内的代码拷贝到了SDRAM中。
(4)接下来的ldr句将pc赋值为on_sdram的地址,实现了从SRAM到SDRAM的跳转(下面会讲为什么)
(5)on_sdram中切换到了了系统模式然后分配了系统模式堆栈,将链接寄存器设置为halt_loop然后就跳转到了SDRAM中的Main
上面的解释只是大体上说明了代码的意思,但是初学者总会有个疑问就是为什么ldr pc,=on_sdram就实现了从SRAM到SDRAM的跳转呢?我被这个问题困扰了很长时间,到今天才想明白了这个问题,问题的关键就是相对跳转和绝对跳转的问题。为了说明这个问题我先解释一下bl指令跟ldr指令在执行过程中的区别。
B指令是相对跳转指令,B 指令是最简单的跳转指令。一旦遇到一个 B 指令,ARM 处理器将立即跳转到给定的目标地址,从那里继续执行。注意存储在跳转指令中的实际值是相对当前PC 值的一个偏移量,而不是一个绝对地址,它的值由汇编器来计算(参考寻址方式中的相对寻址)。它是 24 位有符号数,左移两位后有符号扩展为 32 位,表示的有效偏移为 26 位(前后32MB 的地址空间),同样的,BL、BX都是相对跳转。
LDR伪指令是将第二操作直接赋值给第一操作数,当执行ldr pc,=Main时是将Main的绝对地址赋值给了PC。
好了,知道这两个指令的区别之后我们来看代码是如何实现的从SRAM到SDRAM的跳转,首先需要指出,2440的开发板有SRAM和SDRAM,SRAM是从地址0x00000000开始的4KB内存空间,SDRAM是从0x30000000开始的64M空间。
无论用ADS编译还是用arm-linux-gcc编译都会将代码链接到0x30000000以后(也就是SDRAM中),ADS用户可以通过查看ADS的工程配置,其中有项配置是RO起始地址是0x30000000,linux用户在链接时需要用-T指定代码的其实地址为0x30000000。
根据编译原理,在链接阶段程序中函数的地址就已经确定了,也就是说函数的实际地址都在0x30000000之后,而程序的入口函数也就是这里的_start的地址就是0x300000000,其他函数都会大于这个数。 【Linux公社 】