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.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為單位,不需要省那么點空間。所以后續使用很少。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM