欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

嵌入式Linux-JZ2440-04课-存储管理器代码的分析

程序员文章站 2022-05-11 14:49:37
...

嵌入式Linux-JZ2440-04课-存储管理器代码的分析
嵌入式Linux-JZ2440-04课-存储管理器代码的分析

启动文件初始化代码:

@*************************************************************************
@ File:head.S
@ 功能:设置SDRAM,将程序复制到SDRAM,然后跳到SDRAM继续执行
@ 代码流程:
@1> 关看门狗
@2> 设置存储控制寄存器(配置)
@3> 复制代码到SDRAM中
@4> 设置堆栈
@5> 跳转到main执行
@*************************************************************************       

.equ        MEM_CTL_BASE,       0x48000000          @.equ 命令用于把常量值设置为可以在文本段中使用的符号  
.equ        SDRAM_BASE,         0x30000000          @类似于C语言中#define
                                                    @0x48000000-BWSCON,0x30000000-BANK6

.text               @ .text 指定了后续编译出来的内容放在代码段【可执行】;
.global _start      @global 告诉编译器后续跟的是一个全局可见的名字【可能是变量,也可以是函数名】
_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  main                            @ 调用C程序的Main函数
halt_loop:                              @ 这是程序结束至死循环的意思
    b   halt_loop  

disable_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   @是将立即数0放到r1中。
    ldr r2, =SDRAM_BASE  @SDRAM_BASE  是我们定义的变量= 0x30000000  
    mov r3, #4*1024       @也就是0x30000000放到r2中。
1:  
    ldr r4, [r1],#4     @ 从Steppingstone读取4字节的数据,并让源地址加4
    str r4, [r2],#4     @ 将此4字节的数据复制到SDRAM中,并让目地地址加4
    cmp r1, r3          @ 判断是否完成:源地址等于Steppingstone的末地址?
    bne 1b              @ 若没有复制完,继续
    @b:backward 向后跳转  f:forward 向前跳转  
    mov pc,     lr      @ 返回
 //将Steppingstone的4K数据全部复制到SDRAM中去
memsetup:
    @ 设置存储控制器以便使用SDRAM等外设

    mov r1,     #MEM_CTL_BASE   @存储控制器的13个寄存器的开始地址,0x48000000
    adrl    r2, mem_cfg_val         @ 这13个值的起始存储地址
    add r3,     r1, #52             @ 13*4 = 54
1:  
    ldr r4,     [r2], #4            @ 读取设置值,并让r2加4
    str r4,     [r1], #4            @ 将此值写入寄存器,并让r1加4
    cmp r1,     r3                  @ 判断是否设置完所有13个寄存器
    bne 1b                          @ 若没有写成,继续
    @b:backward 向后跳转  f:forward 向前跳转  
    mov pc,     lr                  @ 返回


.align 4                                @以4字节对齐
mem_cfg_val:        
    @ 存储控制器13个寄存器的设置值
    .long   0x22011110      @ BWSCON   0x48000000
    .long   0x00000700      @ BANKCON0 0x48000004
    .long   0x00000700      @ BANKCON1 0x48000008
    .long   0x00000700      @ BANKCON2 0x4800000C
    .long   0x00000700      @ BANKCON3 0x48000010
    .long   0x00000700      @ BANKCON4 0x48000014
    .long   0x00000700      @ BANKCON5 0x48000018
    .long   0x00018005      @ BANKCON6 0x4800001C
    .long   0x00018005      @ BANKCON7 0x48000020
    .long   0x008C07A3      @ REFRESH  0x48000024
    .long   0x000000B1      @ BANKSIZE 0x48000028
    .long   0x00000030      @ MRSRB6   0x4800002C
    .long   0x00000030      @ MRSRB7   0x48000030

Makefile

sdram.bin : head.S  leds.c   @sdram.bin依赖 head.S  leds.c 
    arm-linux-gcc -c -o leds.o leds.c
    #-g:加入调试信息 -c只编译不连接
    arm-linux-ld -Ttext 0x30000000 head.o leds.o -o sdram_elf
    #-Ttext 0x0000000:指定代码段起始地址为0x30000000
    arm-linux-objcopy -O binary -S sdram_elf sdram.bin
    # binary:二进制的 -S:不从源文件复制重定位信息和符号信息到目标文件中去
    arm-linux-objdump -D -m arm  sdram_elf > sdram.dis
    # -D:反汇编所有段 -m arm:指定反汇编文件使用arm架构
clean:
    rm -f   sdram.dis sdram.bin sdram_elf *.o

反汇编文件
嵌入式Linux-JZ2440-04课-存储管理器代码的分析
嵌入式Linux-JZ2440-04课-存储管理器代码的分析
嵌入式Linux-JZ2440-04课-存储管理器代码的分析
bl disable_watch_dog @连接地址0x30000000
bl memsetup @连接地址0x30000004
bl copy_steppingstone_to_sdram @连接地址0x30000008
ldr pc, =on_sdram @连接地址0x3000000c
ldr sp, =0x34000000 @连接地址0x30000010

我们在Makefile中指定了连接地址为0x30000000(0x30000000是sdram中的初始地址),而当我们在跳转到sdram之前,还有几行代码是在steppingstone运行的?为什么可以运行而不出错了?
解释:虽然19~21行连接地址都在SDRAM中,但是由于它们都是位置无关的相对跳转指令,所以可以在Steppingstone里执行。详解点我!


#define GPFCON  (*(volatile unsigned long *)0x56000050)
#define GPFDAT      (*(volatile unsigned long *)0x56000054)

#define GPF4_out    (1<<(4*2))
#define GPF5_out    (1<<(5*2))
#define GPF6_out    (1<<(6*2))

void  wait(volatile unsigned long dly)
{
    for(; dly > 0; dly--);
}

int main(void)
{
    unsigned long i = 0;

    GPFCON = GPF4_out|GPF5_out|GPF6_out;        // 将LED1,2,4对应的GPF4/5/6三个引脚设为输出

    while(1){
        wait(30000);
        GPFDAT = (~(i<<4));        // 根据i的值,点亮LED1,2,4
        if(++i == 8)
            i = 0;
    }

    return 0;
}
相关标签: Linux笔记