1. 程式人生 > >Thumb指令集程序示例

Thumb指令集程序示例

flash 數據段 如果 tex start.s ash tile tro PC

在上節課中我們介紹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. 對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 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為單位,不需要省那麽點空間。所以後續使用很少。

Thumb指令集程序示例