在上节课中我们介绍CPU有两种工作状态,一种ARM状态,一种Thumb状态。
本节课主要介绍Thumb状态及Thumb指令集。
在012_relocate的程序基础上修改,创建013_thumb_014_003程序,并打开start.S和Makefile代码。
1. 对Makefile文件进行如下修改。
1 all: led_on2.o uart.o init.o main.o start.o 2 3 #arm-linux-ld -Ttext 0 -Tdata 0x3000000 start.o led_on2.o uart.o init.o main.o -o sdram.elf 4 arm-linux-ld -T sdram.lds start.o led_on2.o uart.o init.o main.o -o sdram.elf 5 arm-linux-objcopy -O binary -S sdram.elf sdram.bin 6 arm-linux-objdump -D sdram.elf > sdram.dis 7 8 %.o : %.c 9 arm-linux-gcc -mthumb -c -o $@ $< 10 %.o : %.S 11 arm-linux-gcc -c -o $@ $< # 在汇编文件中不需要做-mthumb的指定,在代码里边进行指定 12 13 .PHONY: clean 14 15 clean: 16 rm *.bin *.o *.elf *.dis
2. 对start.S文件进行如下修改。
1 .text 2 .global _start 3 .code 32 /* 表示后续指令使用ARM指令集 */ 4 5 _start: 6 7 ... 8 9 /* 怎么从 ARM_State 切换到 Thumb_State ? */ 10 adr r0, thumb_func /* 得到thumb_func标号的地址 */ 11 add r0, r0, #1 /* 为什么 +1 ?bit0 = 1 时, bx就会切换CPU State到thumb State https://blog.csdn.net/u011449588/article/details/44634977 */ 12 bx r0 /* bx 命令后边那个值如果最低位为1的话,它会跳转到Thumb指令 */ 13 14 .code 16 15 thumb_func: 16 17 bl sdram_init /* */ 18 //bl sdram_init2 /* 用到有初始值的数组,不是位置无关码 */ 19 20 ... 21 22 /* 调用main函数 */ 23 //bl main /* 使用BL命令相对跳转,程序仍然在NOR/片内SRAM上运行 */ 24 /*ldr pc, =main*/ /* 绝对跳转,跳到SDRAM */ 25 26 ldr r0, =main 27 mov pc, r0 28 29 halt: 30 b halt
其中,(1) 最后不再允许使用ldr pc, =main直接对PC进行赋值,而改用 ldr r0, =main, mov pc, r0 进行间接赋值。否则出现如下错误:
(2) 其中 adr r0, thumb_func、add r0, r0, #1
首先得到thumb_func 标号的地址,并且对其进行+1操作(∵32位处理器指令总是以4字节为单位进行存放,PC每次移动也是进行+4,一般最后一位bit0=0),这里进行+1后,使r0最后一位bit0=1。
执行到bx r0时,若rm的bit0为1,则跳转时自动将CPSR中的标志T置位,即把目标地址的代码解释为Thumb代码,如果为bit0位为0的话,则跳转时自动将CPSR中的标志T复位,即把目标地址的代码解释为ARM代码。
(3)再次进行编译后,出现如下错误:
显示“memcpy”的错误,原因是出在init.c文件中的sdram_init2函数上。
3. 打开init.c文件
找到init_init2函数后,进行如下修改:
1 void sdram_init2(void) /* 没有任何输出,推断这里应该是位置无关的 */ /* 这个函数并不会修改这个数组,它只是把这些值拷贝到寄存器里边去,∴可以加一个const*/ 2 { 3 const static unsigned int arr[] = { // 使用static静态变量,静态变量就会放在数据段里,最终重定位时, 4 0x22000000, //BWSCON 会把值从数据段中拷贝到arr[]数组多对应的地址去 5 0x00000700, //BANKCON0 6 0x00000700, //BANKCON1 7 0x00000700, //BANKCON2 在学习Thumb指令时,编译器用到memcpy函数导致make出错,原因是∵这些值肯定是保存在代码里边的,为了构造这个数组, 8 0x00000700, //BANKCON3 编译器把这些代码段里值拷贝到arr[]这个局部变量里。 9 0x00000700, //BANKCON4 10 0x00000700, //BANKCON5 11 0x18001, //BANKCON6 12 0x18001, //BANKCON7 13 0x8404f5, //REFRESH, HCLK=12MHZz: 0x008e07a3, HCLK=100MHz: 14 0xb1, //BANKSIZE 15 0x20, //MRSRB6 16 0x20, //MRSRB7 17 }; 18 volatile unsigned int *p = (volatile unsigned int *)0x48000000; 19 int i; 20 21 for ( i=0; i<13; i ++ ) 22 { 23 *p = arr[i]; 24 p ++; 25 } 26 27 }
最后,通过ls -l进行查看生成的.bin文件的大小。
使用Thumb指令后,
4. 看反汇编代码
前边地址仍然是4字节相加,
其他指令除bl仍为4字节外,其他指令均变为2字节增长。
总结:
如果Flash空间比较小的话,可以使用Thumb指令集,但对于ARM系统、Linux系统,Flash 空间一般以M为单位,不需要省那么点空间。所以后续使用很少。