(嵌入式)关于arm中的存储控制器(三)终!

来源:互联网 发布:照片图库 mac 密码 编辑:程序博客网 时间:2024/06/06 00:48
.equ:
.equ symbol, expression: 把某一个符号(symbol)定义成某一个值(expression),该指令并不分配空间,相当于C语言中的#define宏定义。

LR寄存器:
LR(link register)连接寄存器,在ARM体系结构中LR的特殊用途有两种:
1.用来保存子程序的返回地址。
2.当异常发生时,LR中保存的值等于异常发生时PC的值减4(或者减2),因此在各种异常模式下可以根据LR的值返回到异常发生前的位置继续执行。
当通过BL或者BLX指令调用子程序时,硬件自动将子程序返回地址保存在R14(LR)寄存器中,在子程序返回时,把LR的值赋值到程序计数器PC即可实现子程序返回(eg:MOV PC,LR)。


ADR指令:
这是一条小范围的地址读取伪指令,它将基于PC的相对偏移地址值读到目标寄存器中。
使用格式: ADR register,exper
在编译源程序时,编译器首先计算出当前PC到exper的偏移值#offset_to_exper,然后使用一条ADD或者SUB指令来替换这些伪指令,例如,ADD resister,PC,#offset_to_exper
注意标号exper与指令必须在统一代码段。
ADRL指令:
这是一条中等范围的地址读取伪指令,它将基于PC的相对偏移地址值读到目标寄存器中。
原理和ADR一样,不同的是它在编译的时候,会被用两条合适的指令来替换伪指令。
eg:ADD register,PC,offset1
       ADD register,register,offset2
所以上面adrl    r2, mem_cfg_val  意思是把下面那13个值的起始存储地址存入到r2寄存器。


.long:
定义一个4字节数据,并为它分配空间 

.align n:
它的作用是对指令或者数据存放的地址按 2^n 进行对齐。下面是指定按 2^4 对齐。


汇编语言head.S:(作用是将 RAM 程序复制到 SDRAM中,并在SDRAM 中执行)

.equ  MEM_CTL_BASE, 0x48000000  @ MEM_CTL_BASE 为芯片内存中的13个存储控制器中寄存器的起始地址.equ  SDRAM_BASE,   0x30000000  @ SDRAM_BASE 为SDRAM在芯片中的内存地址.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:mov r1,  #0x53000000   @ WATCHDOG在芯片中的内存地址mov r2,  #0x0str r2, [r1]     @ 把WATCHDOG寄存器写0mov pc, lr       @ 把连接寄存器 lr 的值赋值给程序计数器 PC。用来子程序返回继续执行主程序copy_steppingstone_to_sdram:@ 我们这里将steppingstonede 4K数据全部复制到SDRAM中去@ steppingstone的 起始地址为0x00000000, SDRAM中的起始地址为0x30000000mov r1,#0ldr r2,=SDRAM_BASEmov r3,#4*1024      @ 因为我们要复制4K的大小1:ldr r4,[r1],#4    @ 从steppingstone 读取4字节的数据,然后让源地址加4str r4,[r2],#4    @ 将r4 里4字节的数据复制SDRAM中,然后目的地址加4cmp r1, r3        @ 参考我下面的解释bne 1bmov pc, lrmemsetup:mov r1, #MEM_CTL_BASEadrl r2, mem_cfg_val   @ 注意这里 adr 后面是L 而不是数字1,反正我开始就是傻傻分不清。                       @ 这个语句就是把 mem_cfg_val 段定义的几个数据的其实地址传递给 r2add r3, r1,#52         @ 把 r1+13*4 传递给r3,cpu是32bit的,即一个寄存器包含4个字节,所以13个就包含52个字节                       @ 那么,如果把13个寄存器全部赋值结束后地址就应该是 r1+13*4。1:ldr r4, [r2],#4        @ 读取设置值,并让r2+4。        str r4, [r1],#4       @ 将此值写入寄存器,并让r1+4,以便下一个数据写入下一个寄存器                          cmp r1, r3             @ 关于 cmp 指令其实也就是计算r1-r3,但是它的结果并不改变其寄存器的值,只是改变程序状态寄存器 CPSR的标志位                               @ 然后下一条语句在指令后加上条件判断就能完成我们想要的循环。                        bne 1b                 @ ne(如果不相等) 1b 这里的b(backwark),向后跳转到局部标签1处执行。         @ 相应的还有1f(foward),向前跳转到局部标签1处执行,注意理解这里的前和后,前代表地址增的方向,后代表地址减的方向                        mov pc, lr.align 4mem_cfg_val:.long  0x22011110  @ BWSCON 寄存器要写入的值  .long  0x00000700  @ BANKCON0 寄存器要写入的值.long  0x00000700  @ BANKCON1 寄存器要写入的值.long  0x00000700  @ BANKCON2 寄存器要写入的值.long  0x00000700  @ BANKCON3 寄存器要写入的值.long  0x00000700  @ BANKCON4 寄存器要写入的值.long  0x00000700  @ BANKCON5 寄存器要写入的值.long  0x00018005  @ BANKCON6 寄存器要写入的值.long  0x00018005  @ BANKCON7 寄存器要写入的值.long  0x008C07A3  @ REFRSH 寄存器要写入的值.long  0x000000B1  @ BANKSIZE 寄存器要写入的值.long  0x00000030  @ MRSRB6 寄存器要写入的值.long  0x00000030  @ MRSRB7 寄存器要写入的值

c语言main函数:

#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 = CPF4_out | GPF5_out | GPF6_out; // 将LED对应的引脚设置为输出while(1){wait(30000);GPFDAT = (~(1<<4)); // 根据i的值,点亮LEDif(++1 == 8)i=0;}return 0;}


Makefile:

sdram.bin : head.S leds.Carm-linux-gcc -c -o head.o head.Sarm-linux-gcc -c -o leds.o leds.carm-linux-ld -Ttext 0x30000000 head.o leds.o -o sdram_elfarm-linux-objcopy -O binary -S sdram_elf sdram.binarm-linux-objdump -D -m arm sdram_elf > sdram.disclean:rm -f sdram.dis sdram_elf sdram.bin *.o

注: objdump 命令是Linux下的反汇编目标文件或者可执行文件的命令

    -D 表示反汇编 (要反汇编的文件) 中的所有section
    -m 后面跟的cpu架构,arm就表示arm架构的cpu
    >  表示将这个程序的反汇编文件西写入到led1.dis这个文件中,在终端中不显示出来
       如果不加这个> ,那么你在终端上就可以看到输出的LED1_elf反汇编程序 
阅读全文
0 0
原创粉丝点击