查看: 16308|回复: 36

2410启动代码的分析

[复制链接]
发表于 2009-9-6 02:49:22 | 显示全部楼层 |阅读模式
关键词: 代码
本帖最后由 changyongid 于 2009-9-6 03:02 编辑

说明:
其实阿南的书里已经分析的很清楚了。这里再记录下来就显得啰嗦了。好吧,就让它啰嗦吧……



板子上电,那么cpu从地址0开始取得指令,然后一步一步的按照我们的程序执行下去。我们试着来画一下程序最开始时运行的流程图。

图片1.jpg

那么可以从上面图里看出,程序第一条指令执行的就是  b
ResetHandler  。即跳入我们正常执行程序里。那么这指令的下面,就是一些异常的入口。
这个异常入应该很好理解,每当异常发生时,cpu就会自动跳到相应的地址上来。比如,现在发生了一个外部中断IRQ,那么cpu就会自动的跳到 0x00000018 这个地址来扫行指令。在上面的中断向量表里,正好可以看到 0x00000018 这个地址里的指令是 b
HandlerIRQ,即跳到HandlerIRQ 这个位置去。那么只要我们在 HandlerIRQ 下面放上我们的IRQ 处理子程序,就可以了。
关于中断,在下面再讨论。现在我们给板子上电了,那么它就执行最开始的一条指令 b
ResetHandler 。即我们要跳到 ResetHandler 这个位置去执行程序。

再来画一下 ResetHandler 的简易流程图。
图片2.jpg


上面各步骤我给标了号,是为了方便对各子程序的分析,并不是刻意指它们之间的执行顺序。


1. 看门狗
代码很简单,就是对控制看门狗的特殊功能寄存器赋值。 图片3.jpg
为什么关掉看门狗呢?
其实就是为了防止看门狗计数溢出,引起系统再次复位,
因为此时我们还没有完成我们对系统的初始化。




2. 关中断
如右边的代码,给相应寄存器赋值即可。 图片4.jpg
具体的可以看2410的数据手册。
为中断源比较多,所以它的控制起来会显得复杂一些。


3. 系统时钟初始化
图片5.jpg


对MPLLCON 寄存器赋初值来产生相应的频率。

由于设定好MPLLCON寄存器之后,cpu还需要一段时间才能产生稳定的频率输出。

那么这段时间如果来设定呢?就是通过设定LOCKTIME寄存器来设定的。
具体可参考数据手册。

4. 判断此次启动是否是从掉电模式唤醒
图片6.jpg
这里是通过判断GSTATUS2 这个寄存器里的bit1 位来确定的。GSTATUS2 具体的说明如下:
图片7.jpg


可以看到,如果bit1 位为0,则说明此次的启动是从掉电模式唤醒。对于唤醒,程序的执行是不同的,因为唤醒时不需要进行下面的 5 6 7……步骤,在此就直接跳入醒前的状态开始执行。
bit1位为1,则我们继续下面的5 6 7……步骤。

5. 初始化内存控制器
图片8.jpg



这里是在对SDRAM 控制器的相关寄存器赋初始值,以控制它的工作模式。共有13个与SDRAM工作相关的寄存器,我们要一一对其赋值。
        从数据手册里可以看到,Sdram的相关寄存器是连续排布的,从0x48000000的BWSCON开始,一直往高地址排布,共13个。那么我们利用它的连续排布,即可用循环的语句来初始化。
ldr r3, [r0], #4    即 r3 <- [r0],  r0 <- r0+4
这里r0为SMRDATA的地址。注意上面这句是基址变址寻址,里面包含了间接寻址。汇编里的寻址方式真是有些多,以后再好好整理下。
程序里我们可以看到,从SMRDATA往下,初始化了13个数据,这里即把这13个数据一一的赋值到 BWSCON 之后连续的13个寄存器里。

6. 初始化堆栈

图片9.jpg


         这里初始化的程序都在一个子程序里,这里
调用这个子程序。用了 bl ,说明子程序执行完
之后是可用 lr 来返回的。

对于堆栈的初始化,每个异常模式需要自己的独立堆栈,恰好arm里每个异常模式有它自己的堆栈指针sp。对于不同模式,我们需要先设置程序状态寄存器cpsr,使arm进入某个异常模式,这样才能访问到该模式的堆栈指针sp。
我们来看一下子程序是具体怎么执行的吧。

图片10.jpg
对cpsr的操作是采用“读取-修改-写入”的方式。即先用mrs读出,再修改,最后用msr写入cpsr。注意上面写入时用的是cpsr_cxsf,下划线_后面的表示的是“域”的意思,用于设定cpsr中需要操作的位。
c control field mask byte (PSR[7:0]) 控制位域
        x extension field mask byte (PSR[15:8])
        s status field mask byte (PSR[23:16)
        f flags field mask byte (PSR[31:24]).
比如 msr  cpsr_c, r1 表示只修改控制位,即cpsr的低8位。具体的可查看cpsr各位的定义。

进入了相应模式之后,再把值赋给sp即可。例如 ldr sp,=UndefStack
这里的 UndefStack 等地址已经定义好了。如下:(相当于宏定义一个数值而已)
图片11.jpg



7. 保存IRQ地址
这里将IRQ中断处理程序的IsrIRQ标号导址保存到HandleIRQ中。
HandleIRQ是什么呢?
程序里有这一句
HandleIRQ   #   4
预留出一个4字节(一个字)的地址出来,那么这个地址里现在存放的就是IsrIRQ 这个标号本身的值。(注意标号本身是代表一个地址。)
这里的操作涉及到如何找到中断子程序,我们放在后面再来讲。
 楼主| 发表于 2009-9-6 03:11:50 | 显示全部楼层

2

本帖最后由 changyongid 于 2009-9-6 03:20 编辑

8. 运行域初始化


图片12.jpg

关于这一段代码,书上已经讲得很清楚了。具体的请看书。
不过理解起来确实需要费点力。主要是加载域和运行域的问题,还好之前读uboot时也遇到过这个问题,研究了一番。这里谈一点自己的理解,不知道对不对,还请指教。
1. 我们的程序都是放在Nandflash里的,而Nand flash里不能直接运行指令,2410内部的sram又只有4k。启动时只能把nandflash里的前4k放到sram里执行。问题来了,我们的程序大于4k里,又要如何运使其正确运行呢?
很简单,我们只需要在前4k的代码里完成一个工作,即把我们所要运行的程序全都复制到sdram里去,最后再跳入sdram里执行程序就可以了。我们的Sdram64M,足够我们用了。
2. 这里我们的启动程序只是把RWDATA复制到了sdram里,而没有把code部分也复制到sdram里,所以,此时我们的整个程序不能大于4k,且程序运行时一直是在内部的sram里的。
3. 指定链接地址。
这里涉及到一个概念,就是“位置无关代码”和“位置相关代码”。
位置无关代码,比如跳转指令 b 。它就是一个位置无关代码,它要跳转的地址,是在执行这条指令的时候,根据当前的pc值计算出来的。所以b 这种跳转方式称为相对寻址,以当前的pc值 为基地址,加上一定量的偏移量,得到操作数的有效地址。位置无关代码无论放在程序的哪里执行都可以。
位置相关代码,比如 ldr
r0,=SMRDATA 就是一句位置相关代码。SMRDATA的值是在链接后就已经确定了的。
假设这里我们的链接地址设为 0x30000000,链接完毕之后,SMRDATA的地址就已经确定了,假设为0x33ff0000。那么程序执行ldr
r0,=SMRDATA的时候,r0里的值就是0x33ff0000。如果我们没有把程序复制到0x30000000的话,那么相对来说SMRDATA(0x33ff0000)地址里的值自然就是不正确的,不是我们所要的。

说起来确实有点麻烦,可能是我还没能完全参透。要注意的是,即使我们把相关数据复制到了sdram里,但是链接的时候没有指定正确的链接地址,cpu则不会找到正确的数据。

9. 跳入C程序
汇编语言与c语言混合编程。没有涉及到参数的传递。由于是用的 bl ,跳指令 b bl只能向前或向后32M地址跳转。所以Main程序还是在前4k里。

如果我们已经把程序复制到sdram里了,要跳到那里去,就得直接向pc写值了。这样可以完成前后的4g跳转。


10 掉电唤醒。
直接跳转到WAKEUP_POWER_OFF 程序段里。
图片13.jpg



看看数据手册里关于从掉电唤醒过程的描述。书里也把过程描述的很清楚。这里就不废话了。最后进入程序里StartPointAfterPowerOffWakeUp这个位置开始继续执行。

图片14.jpg

图片15.jpg

11. 进入掉电模式。
这个过程在流程图里没画出来。
当我们的主程序执行时,如果我们要进入掉电模式的话,这该怎么办呢?
回过头我们去看下启动代码里中断向量表下面,可见,紧接着中断向量表的是b
EnterPWDN
那么,这条指令所在的位置也就是0x00000020喽。
书上这里也讲的很明白了。主程序只要调用EnterPWDN(参数) 这个函数即可,调用之后,程序即进入启动代码中的汇编段执行。
关于这段就不多说了,也不复杂。也可以看下数据手册里关于进入掉电模式的流程说明。在clock 那一章。



12. 异常服务的响应过程
出现一个异常,arm处理器会执行以下几个步骤:
A. 将下一条指令存入相应的lr里,以便程序从异常返回时能从正确的位置开始。
B. 将cpsr复制到相应的spsr。
C. 强制设置cpsr的运行模式位
D. 强制从异常向量地址取得下一条指令
Ok,经过以上步骤,就进入了异常里。以上步骤都是处理器自动执行的,不需要软件干涉。从上面的D步骤起,我们在向量地址上放置跳转指令,那么程序就可以跳到相关的处理程序里了。
我们顺着书上的例子走一遍吧。
(1)FIQ
A. 产生FIQ中断时,cpu自动跳到0x0000001c这个地址去执行代码。还记得中断向量表吧,里面这个地址的指令是 b
HandlerFIQ 。即要跳入HandlerFIQ 里了。
B. HandlerFIQ在哪里呢?
程序里有一段宏定义如下

图片16.jpg


且程序中间用到了这个宏

图片17.jpg

那么经过预编译替换之后,这一句就会变成下面这一段了。



图片18.jpg



可见,我们找到了HandlerFIQ 所在了。其中有个标号HandleFIQ是什么呢?
HandleFIQ   
#   4 就是这里预先分配的一个地址。至于这个地址里存的数据是什么呢?呆会再看。
好,顺着书里介绍的来走一下,直到str     r0,[sp,#4]  这句执行完为止,都是在将相关的数据入栈,如下图。接着分别将数据出栈到r0和pc里,pc里即为中断子程序入口。即cpu进入了中断处理程序里执行。疑问:最开始入栈的r0里的数据是什么呢?

图片19.jpg

(2)IRQ
查找IRQ中断处理程序入口的步骤比上面多了一个步骤,是因为有多个中断源共用一个IRQ中断入口,然后,再到IRQ处理程序中再判断具体是哪一个中断源产生的。最后进入对应的处理程序中执行。具体的中断过程最好先读一下数据手册。
所以对于IRQ来说,相当于二级查找。先找IRQ处理程序的入口,然后在处理程序中根据INTOFFSET 的值来找到对应中断源的入口。
具体书上讲的很明白。







启动代码的分析.pdf (234.13 KB)
 楼主| 发表于 2009-9-6 03:17:50 | 显示全部楼层
编辑这个贴子发现几点,给管理员提个意见:
1. 一个贴子只能有10000字。。。给多点吧
2. 我编辑贴子的时候,如果点击新窗口,会扣分。
3. 公社的logo太大了。每个图面都占了一大块,有点影响。建议可以做一个小点的图标放在右下脚。。
发表于 2009-9-6 16:15:20 | 显示全部楼层
感谢分享!!!
发表于 2009-9-6 17:17:26 | 显示全部楼层
顶!
发表于 2009-11-3 15:39:17 | 显示全部楼层
mark
发表于 2009-11-6 19:53:42 | 显示全部楼层
顶啊................
学习了
发表于 2009-12-5 16:44:27 | 显示全部楼层
这个详细啊
发表于 2009-12-7 21:44:34 | 显示全部楼层
感谢分享!
发表于 2009-12-10 13:08:52 | 显示全部楼层
很好,辛苦了
发表于 2010-1-6 14:13:30 | 显示全部楼层
好啊!
发表于 2010-5-11 09:48:28 | 显示全部楼层
很好
发表于 2010-7-21 16:49:59 | 显示全部楼层
好啊 。。。。。。。。。。。。。。。。。。。。
发表于 2010-8-3 17:27:02 | 显示全部楼层
发表于 2010-8-11 07:51:43 | 显示全部楼层
精典,学习了.
发表于 2010-8-11 14:13:06 | 显示全部楼层
好东西啊,谢谢分享
发表于 2010-8-16 00:24:09 | 显示全部楼层
学习了
发表于 2010-8-22 23:46:24 | 显示全部楼层
顶顶顶
发表于 2010-8-24 20:36:57 | 显示全部楼层
很需要
发表于 2010-9-7 09:08:34 | 显示全部楼层
不错,不错
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于我们  -  服务条款  -  使用指南  -  站点地图  -  友情链接  -  联系我们
电子工程网 © 版权所有   京ICP备16069177号 | 京公网安备11010502021702
快速回复 返回顶部 返回列表