学习UBOOT前奏之hardware-sdram[s3c2440]
来源:互联网 发布:林彪军事才能 知乎 编辑:程序博客网 时间:2024/05/19 03:29
今天我们来学习下S3C2440的SDRAM,同样以代码的形式分析。
@*************************************************************************@ File:head.S@ 功能:设置SDRAM,将程序复制到SDRAM,然后跳到SDRAM继续执行@************************************************************************* .equ MEM_CTL_BASE, 0x48000000.equ SDRAM_BASE, 0x30000000.text.global _start_start: bl disable_watch_dog @ 关闭WATCHDOG,否则CPU会不断重启 bl memsetup @ 设置存储控制器 bl copy_steppingstone_to_sdram @ 复制代码到SDRAM中 ldr pc, =on_sdram @ 跳到SDRAM中继续执行on_sdram: ldr sp, =0x34000000 @ 设置堆栈 bl mainhalt_loop: b halt_loopdisable_watch_dog: @ 往WATCHDOG寄存器写0即可 mov r1, #0x53000000 mov r2, #0x0 str r2, [r1] mov pc, lr @ 返回copy_steppingstone_to_sdram: @ 将Steppingstone的4K数据全部复制到SDRAM中去 @ Steppingstone起始地址为0x00000000,SDRAM中起始地址为0x30000000 mov r1, #0 ldr r2, =SDRAM_BASE mov r3, #4*10241: ldr r4, [r1],#4 @ 从Steppingstone读取4字节的数据,并让源地址加4 str r4, [r2],#4 @ 将此4字节的数据复制到SDRAM中,并让目地地址加4 cmp r1, r3 @ 判断是否完成:源地址等于Steppingstone的未地址? bne 1b @ 若没有复制完,继续 mov pc, lr @ 返回memsetup: @ 设置存储控制器以便使用SDRAM等外设 mov r1, #MEM_CTL_BASE @ 存储控制器的13个寄存器的开始地址 adrl r2, mem_cfg_val @ 这13个值的起始存储地址 add r3, r1, #52 @ 13*4 = 541: ldr r4, [r2], #4 @ 读取设置值,并让r2加4 str r4, [r1], #4 @ 将此值写入寄存器,并让r1加4 cmp r1, r3 @ 判断是否设置完所有13个寄存器 bne 1b @ 若没有写成,继续 mov pc, lr @ 返回.align 4mem_cfg_val: @ 存储控制器13个寄存器的设置值 .long 0x22011110 @ BWSCON 总线宽度与等待控制寄存器 .long 0x00000700 @ BANKCON0 BANK控制寄存器 .long 0x00000700 @ BANKCON1 .long 0x00000700 @ BANKCON2 .long 0x00000700 @ BANKCON3 .long 0x00000700 @ BANKCON4 .long 0x00000700 @ BANKCON5 .long 0x00018005 @ BANKCON6 0001 1000 0000 0000 0101 .long 0x00018005 @ BANKCON7 .long 0x008C07A3 @ REFRESH 设置刷新周期 .long 0x000000B1 @ BANKSIZE 设置BANK6,和7的size .long 0x00000030 @ MRSRB6 .long 0x00000030 @ MRSRB7 0011 0000
这个程序的功能是初始化SDRAM,并将自身代码复制到SDRAM中,执行点灯的功能。点灯的功能main()函数在leds.c中定义,这里没有列出。代码编译的Makefile如下:
sdram.bin : head.S leds.c arm-linux-gcc -c -o head.o head.S arm-linux-gcc -c -o leds.o leds.c arm-linux-ld -Ttext 0x30000000 head.o leds.o -o sdram_elf arm-linux-objcopy -O binary -S sdram_elf sdram.bin arm-linux-objdump -D -m arm sdram_elf > sdram.disclean: rm -f sdram.dis sdram.bin sdram_elf *.o
这里我们重点关注下如下这句:
arm-linux-ld -Ttext 0x30000000 head.o leds.o -o sdram_elf
它表示链接完成后的代码运行地址是0x3000 0000
下面是反汇编生成的结果的部分片段:
30000000 <_start>:30000000: eb000005 bl 3000001c <disable_watch_dog> 30000004: eb000010 bl 3000004c <memsetup>30000008: eb000007 bl 3000002c <copy_steppingstone_to_sdram>3000000c: e59ff090 ldr pc, [pc, #144] ; 300000a4 <mem_cfg_val+0x34>30000010 <on_sdram>:30000010: e3a0d30d mov sp, #872415232 ; 0x3400000030000014: eb000032 bl 300000e4 <main>30000018 <halt_loop>:30000018: eafffffe b 30000018 <halt_loop>3000001c <disable_watch_dog>:3000001c: e3a01453 mov r1, #1392508928 ; 0x5300000030000020: e3a02000 mov r2, #0 ; 0x030000024: e5812000 str r2, [r1]30000028: e1a0f00e mov pc, lr3000002c <copy_steppingstone_to_sdram>:3000002c: e3a01000 mov r1, #0 ; 0x030000030: e3a02203 mov r2, #805306368 ; 0x3000000030000034: e3a03a01 mov r3, #4096 ; 0x100030000038: e4914004 ldr r4, [r1], #43000003c: e4824004 str r4, [r2], #430000040: e1510003 cmp r1, r330000044: 1afffffb bne 30000038 <copy_steppingstone_to_sdram+0xc>30000048: e1a0f00e mov pc, lr3000004c <memsetup>:3000004c: e3a01312 mov r1, #1207959552 ; 0x4800000030000050: e28f2018 add r2, pc, #24 ; 0x1830000054: e1a00000 nop (mov r0,r0)30000058: e2813034 add r3, r1, #52 ; 0x343000005c: e4924004 ldr r4, [r2], #430000060: e4814004 str r4, [r1], #430000064: e1510003 cmp r1, r330000068: 1afffffb bne 3000005c <memsetup+0x10>3000006c: e1a0f00e mov pc, lr
从上面的反汇编结果可以看出,代码运行地址从30000000开始,这就是arm-linux-ld -Ttext 0x30000000的作用。
我们知道S3C2440 NAND启动时,NAND flash的前4k字节的内容,被硬件直接拷贝的片内0地址开始的4K,也就是一开始的运行地址应该是从0开始的,为什么还能正常运行呢?
其实这里就是用到上一篇中说到位置无关代码的机制。请看下面的反汇编代码片段:
30000000 <_start>:30000000: eb000005 bl 3000001c <disable_watch_dog>30000004: eb000010 bl 3000004c <memsetup>30000008: eb000007 bl 3000002c <copy_steppingstone_to_sdram>3000000c: e59ff090 ldr pc, [pc, #144] ; 300000a4 <mem_cfg_val+0x34>30000010 <on_sdram>:30000010: e3a0d30d mov sp, #872415232 ; 0x3400000030000014: eb000032 bl 300000e4 <main>
前面三条都是BL跳转指令,我们说BL是可以实现位置无关代码的,为什么呢?很简单,因为他是相对于PC指针来进行寻址的,当代码从0地址开始运行时,相对PC指针的偏移并没有变,所以能够能够正常运行。
首先我们来解析下看看BL 指令如何跳转到指定的地方,分析下BL指令的机器码
32位的机器码分为以下3个部分[31:28]:条件码[27:24]:指令码[23:0]:用来表示偏移地址30000000: eb000005 bl 3000001c <disable_watch_dog>机器码:eb00 0005:1110 1010 0000 0000 0000 0000 0000 0101其中0xb:1010b 表示这条指令为BL指令0x00 0005:表示偏移地址如何通过偏移地址得到将要跳转的地方呢?方法:将指令中24位带符号的补码立即数扩展为32(扩展其符号位);将此32位数左移两位;将得到的值加到pc寄存器中,即得到跳转的目标地址通过上面的方法,我们能得到相对PC的偏移地址为0x14,那么此时的PC为多少呢?现在是零地址的开始执行的,我们知道ARM有三级流水线,也就是PC的值=当前执行的指令的地址+8,那么 bl disable_watch_dog 跳转到 0000 001c,这里刚好放置的disable_watch_dog函数,成功实现了跳转
当下面程序执行完成以后,代码已经被拷贝到SDRAM当中了
bl disable_watch_dog @ 关闭WATCHDOG,否则CPU会不断重启 bl memsetup @ 设置存储控制器 bl copy_steppingstone_to_sdram
接着一条ldr pc, =on_sdram伪指令,直接对pc进行赋值,实现跳转到SDRAM到执行,接着设置调用c程序必须的堆栈,最后通过bl main 跳转到点灯的程序,跳转地址计算方式跟上面的分析是一致的
ldr pc, =on_sdram @ 跳到SDRAM中继续执行on_sdram: ldr sp, =0x34000000 @ 设置堆栈 bl main
有问题,可直接留言讨论
如果想理解ARM流水线相关知识可以点这里
arm 流水线
阅读全文
0 0
- 学习UBOOT前奏之hardware-sdram[s3c2440]
- 学习uboot前奏之hardware-mmu[s3c2440]
- 学习uboot前奏之hardware-IRQ[s3c2440]
- 学习uboot前奏之hardware-clock[s3c2440]
- 学习uboot前奏之hardware-uart[s3c2440]
- 学习uboot前奏之hardware-arm基础知识[s3c2440]
- 学习uboot前奏之hardware-nand flash[s3c2440]
- S3C2440之uboot移植
- S3C2440-SDRAM
- S3C2440 SDRAM
- mini2440之S3C2440 SDRAM内存驱动
- 06-S3C2440学习之移植2012u-boot到S3C2440(移植过程一)新建单板+修改时钟+SDRAM+UART
- webService学习之前奏
- Uboot之四下载sdram运行,ok。
- uboot-2011.12移植到S3C2440(四序)——SDRAM分析
- STM8单片机学习之前奏
- S3C2440 SDRAM内存驱动
- S3C2440 SDRAM内存驱动
- 设计模式之访问者模式
- oracle中decode函数如何使用?
- Java书单
- ubuntu下安装配置QT
- React Native仿美团下拉菜单
- 学习UBOOT前奏之hardware-sdram[s3c2440]
- java 获取文件路径
- 3594: [Scoi2014]方伯伯的玉米田
- 剑指offer:二叉搜索树与双向链表
- css实现一行居中显示,两行靠左显示
- String 之 substring 提取字符串
- Java_6运算符
- 大数据时代
- Linux SPI总线和设备驱动架构之一:系统概述