bootloader---13.将程序搬到sdram中

来源:互联网 发布:产品网络推广ynbbc 编辑:程序博客网 时间:2024/06/05 21:53
  初始化好了sdram之后,下面就试一下把sram中的前4k搬到sdram中并跳转到链接地址处执行,这样就不用老是担心写的代码是不是位置无关(PIC)的了,下面是程序的所有文件。

点击(此处)折叠或打开

  1. root@ubuntu:~/myboot# tree
  2. .
  3. ├── main.c
  4. ├── Makefile
  5. ├── sdram.c
  6. ├── start.S
  7. └── u-boot.lds
  8. 0 directories, 5 files

1. start.S

点击(此处)折叠或打开

  1. .text
  2. .global _start
  3. _start:
  4.     /*关闭看门狗*/
  5.     ldr r0, =0x53000000    
  6.     mov r1, #0x0
  7.     str r1, [r0]

  8.     /*初始化系统时钟: FCLK=400M HCLK=100M PCLK=50M */
  9. #define COCKTIME    0x4C000000    
  10. #define MPLLCON        0x4C000004
  11. #define UPLLCON        0x4C000008
  12. #define CLKCON        0x4C00000C
  13. #define CLKSLOW        0x4C000010
  14. #define CLKDIVN     0x4C000014
  15. #define CAMDIVN     0x4C000018
  16.     /*FCLK:HCLK:PCLK=1:4:8*/
  17.     ldr r0, =CLKDIVN
  18.     mov r1, #0x05
  19.     str r1, [r0]

  20.     mrc p15, 0, r0, c1, c0, 0
  21.     orr r0, r0, #0xc0000000
  22.     mcr p15, 0, r0, c1, c0,0

  23.     /*MPLL=(2*m*Fin)/(P*(1<<s)), m="(MDIV+8)," p="PDIV+2" s="SDIV*/
  24.     ldr r0, =MPLLCON
  25.     ldr r1, =((0x5C<<12)|(0x01<<4)|(0x01))
  26.     str r1, [r0]
  27.     
  28.     ldr r0, =0x10000
  29. 1:
  30.     sub r0, r0, #1
  31.     bne 1b

  32.     /*UPLL=(m*Fin)/(P*(1<<s)), m="(MDIV+8)," p="(PDIV+2)," s="SDIV*/
  33.     ldr r0, =UPLLCON
  34.     ldr r1, =((0x10<<12)|(0x01<<4)|(0x01))
  35.     str r1, [r0]

  36.     ldr r0, =0x10000
  37. 1:
  38.     sub r0, r0, #1
  39.     bne 1b
  40.     
  41.     /*设置栈,因为下一步要调用c函数init_sdram*/
  42.     ldr sp, =1024*4
  43.     bl init_sdram

  44.     /*sdram初始化好之后,重新设置栈到内存 0x33d80000+128k*/
  45.     ldr sp, =0x33dA0000
  46.     
  47.     /*复制 steppingstone 到内存: r0=src r1=dest r2=size=4k*/
  48.     mov r0, #0x0
  49.     ldr r1, =0x33d80000
  50.     ldr r2, =1024*4

  51. copy_loop:
  52.     ldmia     {r3-r10}        /* copy from source address [r0] */
  53.     stmia     {r3-r10}        /* copy to target address [r1] */
  54.     cmp    r0, r2                    /* until source end addreee [r2] */
  55.     ble    copy_loop    
  56.     
  57.     /*跳转到main中 此处bl与ldr跳转不一样*/
  58.     /*bl main*/
  59.     ldr pc, _main
  60. loop:
  61.     b loop
  62. _main: .word main
2. main.c

点击(此处)折叠或打开

  1. #define GPBCON (*(volatile unsigned int *) 0x56000010)
  2. #define GPBDAT (*(volatile unsigned int *) 0x56000014)

  3. static inline void delay (unsigned long loops)
  4. {
  5.     __asm__ volatile ("1:\n"
  6.             "subs %0, %1, #1\n"
  7.             "bne 1b":"=r" (loops):"0" (loops));
  8. }
  9. /* 闪灯测试: sram快 sdram稍慢 */
  10. void main(void)
  11. {
  12.     int i = 1;
  13.     GPBCON = 0x15400;
  14.     while(1)
  15.     {
  16.         GPBDAT = 0x7FF&(~i<<5);
  17.         i *= 2;
  18.         if(16==i)
  19.             i = 1;
  20.         delay(400000);
  21.     }
  22.     return ;
  23. }
3. sdram.c 与 u-boot.lds都无改动
4. Makefile 中 OBJS :=  start.o main.o sdram.o
5. 把start.S中的ldr pc, _main 改为 bl main, 编译后分别烧到板子中,可以发现程序运行在sram比sdram中灯闪烁的速度快一些。
把这两个程序反汇编进行比较:

点击(此处)折叠或打开

  1. root@ubuntu:~/myboot# diff u-boot.dis_sdram u-boot.dis_sram 
  2. 44c44
  3. < 33d80084:    e59ff000     ldr    pc, [pc, #0]    ; 33d8008c <_main>
  4. ---
  5. > 33d80084:    eb000008     bl    33d800ac
ldr    pc, [pc, #0] 
把当前pc地址处的值赋给pc,当前pc=(0x33d80084+8)-0x33d80000=0x008C, 0x008C处的值为0x33d800ac,所以执行这条指令后pc指向了0x33d800ac,也就是内存中main函数的入口地址。

33d80084:   eb000008    bl  33d800ac
以当前pc地址进行相对跳转,当前pc=(0x33d80084+8)-0x33d80000=0x008C,根据跳转的指令格式可知跳转到的地址为:0x8C+8<<2=0xAC,执行这条指令的后pc指向了0xAC, 还是在sram中的main函数的入口地址。


注意:1. 虽然反汇编文件中的地址都是0x33d80000,但是实现上程序并没有运行在0x33d80000,而是运行在0x0地址,所以在计算时要减去0x33d80000.同时虽然地址不吻合,但是地址里面的值却是正确的,可以放心用。
2. arm9五级流水,pc地址要加8,至于为什么可以看下面:
http://hi.baidu.com/lijiebdzd/blog/item/7bb27ffa195b3bdf7831aaf6.html
http://hi.baidu.com/lijiebdzd/blog/item/420e3d8dbc20a136c75cc3f0.html
3. eb000008 转为二进制
   1110 1011 0000 0000 0000 0000 1000

   1110: always
   101:
   1:   说明这是一条bl指令
   0000 0000 0000 0000 1000: word 对齐,最右边两位总是0,所以省略,计算时需要向左移两位,即乘以4。
   
出自《ARM7TDMI-S Data Sheet》chapter_4 “arm instruction set”   


0 0
原创粉丝点击