Thumb指令集程序示例
在上節課中我們介紹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.elf5 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. 對Makefile文件進行如下修改。
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 Statehttps://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為單位,不需要省那麽點空間。所以後續使用很少。
Thumb指令集程序示例