s3c2440的2440init.s详解_补充

来源:互联网 发布:直流无刷电机pid算法 编辑:程序博客网 时间:2024/05/01 13:39

1.S3C2440支持两种启动方式:NAND FLASH和NOR FLASH。
网上有很多文章分析TQ2440的启动文件2440init.s。介绍的很详细,我这里只是把S3C2440上电后的程序流程描述下。
不管在哪种启动方式下,ARM上电启动都是从0X00000000开始运行。下面是复位程序入口。
AREA Init,CODE,READONLY
ENTRY
ResetEntry
b ResetHandler
……
ResetEntry的值在ARM上电运行时是0X00000000,在JTAG仿真时是0X30000000。这个值很关键,在拷贝程序时会用到。
从NAND FLASH启动时,在ARM上电时,ARM会自动把NAND FLASH前4K的内容拷贝到S3C2440内部SRAM中,同时把SRAM的地址映射到0X00000000。ARM上电后会从SRAM处开始运行。
从NOR FLASH启动时,因为NOR FLASH接在bank0。地址映射是0X00000000。所以ARM上电后直接运行NOR FLASH里的程序。此时S3C2440内部SRAM地址为0X40000000。

在ARM上电的情况下,流程如下:
1、 关闭看门狗,关闭所有中断。
2、 设置系统工作频率,FCLK,HCLK,PCLK,UCLK。
3、 初始化内存控制寄存器,初始化参数在段SMRDATA里定义。SDRAM初始化在这里处理。
4、 在开发板上电时,按住接在EINT0脚上的按键会清零64MSDRAM。
5、 初始化堆栈
6、 读OM0,OM1引脚状态,判断是从NAND FLASH启动还是从NOR FLASH启动。如果是从NAND FLASH启动,把NAND FLASH的代码拷贝到SDRAM中,接着程序开始在SDARM中运行。然后初始化数据段,最后跳转到main()函数开始运行。
如果是从NOR FLASH启动,判断ResetEntry值和BaseOfROM值是否相等,BaseOfROM值是在ADS里定义的RO BASE,如果定义为0X30000000,因为ARM上电ResetEntry值为0,所以接下来程序会把NOR FLASH里的程序拷贝到SDRAM中。如果RO BASE定义为0,将直接在NOR FLASH里运行。然后初始化数据段,最后跳转到main()函数开始运行。

2.现在,我们在ADS1.2中设为打断模式,并把ENDIAN_CHANGE设置FALSE设为TURE,现在问题就来了,请看下面的分析。

在编译程序时,根据ENTRY_BUS_WIDTH宏会将下面三条指令的之一放在0地址处

b   ChangeBigEndian    ;DCD 0xea000007
andeq   r14,r7,r0,lsl #20   ;DCD 0x0007ea00
streq   r0,[r0,-r10,ror #1] ;DCD 0x070000ea

其实这三条指令的功能都是一样,只是根据数据带宽调整了字节序,都是跳转到0x24处的ChangeBigEndian执行,ChangeBigEndian的作用就是通过协处理CP15中的寄存器C1来改变S3C2440的大小端模式。

先来看一下这三条指令。因为我们已经在ADS中设置为大端模式,所以这些指令是以大端模式进行编译的,而S3C2440此时还是小端模式,S3C2440怎么能执行大端模式下的指令呢,比如b   ChangeBigEndian     ;DCD 0xea000007???

原因如下:

    如果一个基于 ARM 芯片将存储器系统配置为其中一种存储器格式(如小端) ,而实际连接的存储器系统配置为相反的格式(如大端) ,那么只有以字为单位的指令取指、数据装载和数据保存能够可靠实现。其它的存储器访问将出现不可预期的结果。也就就是说在32位模式下,大小端模式对指令取指、数据装载和数据保存没有影响。(注意:如果实际的存储器格式与芯片的存储器格式不符时,只有以字为单位的数据存取才正确,否则将出现不可预期的结果。)

b   ChangeBigEndian在大端模式下机器码是0xea000007,这是32位模式下,其四个字节从低到高分别是:07 00 00 ea。那没b   ChangeBigEndian这条指令在8位模式下,要被小端模式的S3C2440执行,就要人为的修改为0x070000ea。在存储器中存储的顺序:从低地址到高地址分别是 07 00 00 ea,S3C2440按小端模式取指令时,取得是0xea000007。

b   ChangeBigEndian这条指令在16位模式下,要被小端模式的S3C2440执行,就要人为的修改为 0x0007ea00。在存储器中存储的顺序:从低地址到高地址分别是 0007 ea00,S3C2440按小端模式取指令时,取得是0xea000007。

后面修改协处理CP15中的寄存器C1的代码时类似的。

3.2440支持IRQ(普通中断)和FIQ(快速中断)。2440有60个中断源,不支持中断嵌套。

CPU每执行一条指令都会检查CPSR寄存器,当发现I或F位被置1时,就进行中断处理。需要两次查表过程(为什么要查两次表??没有办法,ARM把所有的中断都归纳成一个IRQ中断异常和一个FIQ中断异常;第一次查表主要是查出是什么异常,可我们总要知道是这个中断异常中的什么中断呀!没办法还需要查第二次)。2410不支持中断嵌套,中断产生后处理器进入到IRQ模式,只有在等到这个中断处理完之后才能响应下一次中断。
如果同时产生多个中断,就涉及到了中断优先级的问题。

4.在中断向量表中不直接LDR PC,"异常地址".而是使用一个标号,然后再在后面使用DCD定义这个标号,其原因是:

LDR 指令只能跳到当前PC 4kB 范围内,而B 指令能跳转到32MB 范围,而现在这样在LDR PC, "xxxx"这条指令不远处用"xxxx"DCD 定义一个字,而这

个字里面存放最终异常服务程序的地址,这样可以实现4GB 全范围跳转。

5. init.s中直接上机器码了,看的头晕,股割一下原来发现是这样滴

在init.s文件中有以下几段代码:

[   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   mode.  
DCD   0xffffffff
DCD   0xffffffff
DCD   0xffffffff
DCD   0xffffffff
b   ResetHandler
其中的0xee110f10为机器码并非汇编指令.汇编指令为 mrc   p15,0,r0,c1,c0,0.

以下为汇编的意思:

mrc p15,0,r0,c1,c0,0 //将c1读到r0
orr r0,r0,#0x80; //r0的第7位置1
mcr p15,0,r0,c1,c0,0 //将r0写到协处理器c1中
总的意思为:

如果总线是16位的就用ENTRY_BUS_WIDTH=16这个数据段来填充内存控制器寄存器。32位就用ENTRY_BUS_WIDTH=32数据段。
DCD   0xffffffff     这些只不过是NOP,在低对齐内存模式时用来填充的数据。

DCD指令用于分配一片连续的字存储单元并用指定的数据初始化。DCD分配内存之后,将二进制代码存储到内存中,马上就被程序指针读取,所以就可以执行相应的汇编代码了。

6.执行adr r0,ResetEntry 后,r0 = PC - off_set,adr得到是相对地址而不是绝对地址。ResetEntry是整个程序的入口处,由链接器指定入口地址,如下图,ResetEntry=RO Base=0x3001_0000即|Image$$RO$$Base|。当程序在SDRAM中运行时,当前PC=0x3001_0000+off_set,r0=0x3001_0000,当程序在Boot Internal SRAM运行时,由于程序是从0x0000_0000开始运行的,所以当前PC=0x0000_0000+off_set,即r0=0x0000_0000。所以可以通过 cmp r0,#0来判断程序是否运行在Boot Internal SRAM,如果是,则把NandFlash中的程序拷贝到SDRAM。

7.初始化完成的工作

8.copy_proc_beg语句这段程序的重点,这时候我们已经把所有的程序都复制到了SRAM中了,而在执行这条语句之前(包括这条语句)程序都是在Steppingstone中运行,那么接下来的程序是继续在Steppingstone中运行呢,还是在我们刚刚复制完程序的SRAM中运行呢?当然是在SRAM中运行!这样才能避免我们上面所提到的程序大于4k字节时遇到的问题。而如何从Steppingstone跳到SRAM呢?靠得就是这条语句——ldr  pc,  = copy_proc_beg,它把copy_proc_beg的绝对地址赋予pc,由于程序已经复制到了SRAM中,copy_proc_beg的绝对地址是在SRAM范围内,所以从这句代码以后,程序就开始到SRAM中执行了。在这句话之前的程序大小,我们是要控制在4k字节以内的,而这句代码以后,程序再大,也都会正常运行下去的。

 

0 0
原创粉丝点击