尋址方式
數據都存在存儲器中,尋址簡單地說就是找到存儲數據或指令的地址。存儲器有很多存儲單元,用於存儲數據。或者說,尋址就是讀取數據所在儲存裝置中對應地址編號中存儲的內容;尋址方式是指某一個CPU指令系統中規定的尋找操作數所在地址的方式,或者說通過什麼的方式找到操作數。尋址方式的方便與快捷是衡量CPU性能的一個重要方面.
1.立即數尋址:
操作數在指令中,如: ADD R0,R0,#10 —->R0 = R0 + 10
2.寄存器尋址:
利用寄存器中的值作爲操作數,如:ADD R0,R1,R2 —->R0 = R 1 + R 2
3.寄存器移位尋址:
寄存器中的值移位後得到操作數,用到桶形移位器
介紹一下桶形移位器:
LSL:(邏輯左移),相當於無符號數x2;
ASR: (算術右移),相當於帶符號的數除2;
LSR: (邏輯右移),相當於無符號數除2;
ROR:(循環右移),相當於位輪換;
RRX:(帶擴展的循環右移),位輪換,從CF到MSB都參與;
如:ADD R0,R1,R2,LSL #2 ——–>R0 = R1 + R2<<2;
4.寄存器間接尋址:
寄存器中的值作爲操作數的地址,操作數本身放在存儲器中;
如:LDR R0,【R1】 —->R0 = 【R1】,取出R1存的地址中的值,賦給R0;
5.基址變址尋址:
基址寄存器的內容與指令中的偏移量相加,得到有效操作數的地址,然後訪問該地址空間;
分三種:
1)、前索引:
如:LDR R0,【R1,#4】 —>R1存的地址+4,訪問新地址裏面的值,放到R0;
2)、自動索引:
如:LDR R0, 【R1,#4】! —>在前索引的基礎上,新地址回寫進R1;注:!表示回寫地址:R1的存儲地址在原來基礎上加4;
3)、後索引:
如:LDR R0 【R1】,#4 —>R1存的地址的內容寫進R0,R1存的地址+4再寫進R1;
6.多寄存器尋址:
一條指令完成多個寄存器的傳送,最多16個寄存器;
如:STMxx R0!,{R1-R5}
注:xx是IDAB的任意組合:I-增;D-減;A-後;B-先;
執行這類指令要考慮如下幾個問題:
1)、基址寄存器指向原始地址有沒有放一個有效值?
2)、寄存器列表哪個寄存器被最先傳送?
3)、存儲器地址增長方向?
4)、指令執行完成後,基址寄存器有沒有指向一個有效值?
如:STMIA R0!,{R1-R5} 的答案分別是:有;R1;低-高;沒有。
爲什麼要考慮這麼多,因爲涉及到數據還原的問題;
如:STMIB r0!,[r1-r5]
LDMDA r0! , [r1-r5] ——還原
LDMIA R1! ,{R2-R4,R6}
將R1和R1之後寄存器中的值讀出保存到R2-R4,和R6中。其中R1每次自加一。
7.相對尋址:
pc當前值位基址,指令中值爲偏移量,相加作爲操作數的地址;
如 B/BL 不過有範圍限制 pc+-32Mbytes
ARM指令
arm 指令的分類:跳轉指令,數據處理指令,程序狀態寄存器傳輸指令,Load/Store指令,協處理指令,異常中斷產生指令;
1.跳轉指令
B 跳轉指令
BL 帶返回的跳轉指令,將PC寄存器的值保存到LR中
BLX 帶返回和狀態切換的跳轉指令
BX 帶狀態切換的跳轉指令
子程序當中如何實現還回 方式:
- BX LR
- MOV PC,LR
- 當子程序入口使用STMFD R13!,{register,R14},可以用LDMFD R13!,{register,PC}
- 也可用push {RX, lr} 然後pop {RX, pc}
BX:
BX指令跳轉到指令中所指定的目標地址,若目標地址的bit[0]爲0,則跳轉時自動將CPSR中的標誌位T復位,即把目標地址的代碼解釋爲ARM代碼;若目標地址的bit[0]爲1,則跳轉時自動將CPSR中的標誌位T置位,即把目標地址的代碼解釋爲Thumb代碼。
2.數據處理指令
數據處理指令大致可分爲3類:
1、數據傳送指令;
2、算術邏輯運算指令;
3、比較指令。
算數處理指令用法這裏可以字節參考書籍;
3.狀態寄存器訪問指令
在ARM處理器中,只有MRS指令可以對狀態寄存器CPSR和SPSR進行讀操作。通過讀CPSR可以瞭解當前處理器的工作狀態。讀SPSR寄存器可瞭解到進異常前的處理器狀態
應用示例:
MRS R1 CPSR ; 將CPSR狀態,寄存器讀取保存到R1中
MRS R2,SPSR ; 將SPSR 狀態寄存器讀取保存到R2中
用的地方:當異常中斷嵌套的時候,需要在進入異常中斷之後,嵌套中斷髮生之前保存當前處理器模式對應的SPSR,當進程切換的時候也需要保存當前狀態寄存器值;
4.內存訪問指令
一類用於操作32位的字節類型數據以及8位無符號的字節類型數據,另一類用於操作16位半字節類型數據以及8位的有符號的直接類型的數據;
LDR 字數據讀取指令:將一個32位的字讀取到指令中的目標寄存器當中;
例:LDR R0,【R1,#4】;將內存單元R1+4中的字讀取到R0寄存器中;
LDRB 字節數據讀取指令:將一個8位的字節數據讀取到指令中的目標寄存器當中;高24位補0;
例:LDRB R0,【R1】
LDRBT 用戶模式的字節數據讀取指令,與LDRB一樣操作,當特權模式下使用本指令時,內存系統將該操作當作一般用戶模式下的內存訪問操作;異常中斷程序時在特權級的處理模式下執行的,這時如果需要按照用戶模式的權限訪問內存可以使用LDRBT;
LDRH 從內存中將一個16位的半字節數據讀取到指令中的目標寄存器當中,高16位清0;
LDRSB 有符號的字節數據讀取指令;
LDRSH 有符號的半字數據讀取指令;
LDRT 用戶模式的字數據讀取指令;
STR 字數據寫入指令;
例子:STR R0,【R1,0X100】;將R0中的字數據保存到內存單元R1 + 0x100中去;
STRB,STRH,STRBT就參考LDR;
5.批處理Load/Store內存訪問指令
Load/Store單字型和無符號字節型數據:
Load指令把內存中的單個數據讀取出來並寫到某個通用寄存器中;
Store指令把單個寄存器中的數據讀取出來並寫到某個內存地址處;
Load/Store半字型、雙字型和有符號字節型數據:
Load指令把內存中的單個數據讀取出來並寫到某個通用寄存器或一對通用寄存器中(pair);
Store指令把單個通用寄存器或某對通用寄存器中(pair)的數據讀取出來並寫到某個內存地址處;
LDM(1) 批量內存字數據讀取指令;
LDM(2) 用戶模式的批量內存字數據讀取指令;理解對應LDRBT;
LDM(3)帶狀態寄存器的批量內存字數據讀取指令,它同時將當前處理器模式對應的SPSR寄存器內容複製到CPSR寄存器中;
STM(1) 批量內存字數據寫入指令;
STM(2) 用戶模式的批量內存字數局寫入指令;
Load/Store多個寄存器:
Load Multiple(LDM)指令可以一次性地把內存中的一個數據塊裝載到任意數量的通用寄存器中;
Store Multiple(STM)指令可以把任意數量的通用寄存器中的內容一次性地存儲到一個內存塊中;
Load/Store多個寄存器的指令分爲兩類:塊拷貝指令和棧操作指令;
例如:
STMFD R13!, {R0-R12, LR}
LDMFD R13!, {R0-R12, PC}
LDMIA R0, {R5-R8}
STMDA R0, {R1, R3, R5-R7, R9}
6.信號量操作指令
信號量用於進程間的同步和互斥;,一條指令當中完成信號量的讀取和修改操作;SWP 指令用於將一個內存字單元(該單元地址放在寄存器Rn中)的內容讀取到一個寄存器Rd中,同時將另一個寄存器Rm的內容寫入到該內存單元中
SWP Rd,Rm,Rn
SWP R1,R2,[R3]:將內存當中R3中字節數據讀取到R1寄存器當中,同時將R2寄存器的數據寫入到內存R3單元中;
SWP R1,R1,[R2]:R1寄存器的值和內存單元R2的內容互換;
7.異常中斷產生指令
ARM有兩條異常中斷產生的指令:軟中斷指令SWI用於產生SWI異常中斷,ARM正是通過這種機制實現用戶模式對操作系統中特權模式的程序的調用;斷點中斷指令BKPT。主要用於產生軟件斷點,供調試程序使用;
8.協處理器指令
協處理器(coprocessor)是一種芯片,用於減輕系統微處理器的某種處理任務。例如,數學協處理器可以控制數字處理;圖形協處理器可以處理視頻繪製。ARM支持16個協處理器,用於各種協處理器操作,例如協處理器15(CP15),ARM處理器使用CP15的寄存器來控制cache和存儲器管理。
CDP:數據操作指令,通常用於初始化協處理器。
LDC:數據加載指令,用於將存儲器中的數據傳送到協處理器寄存器中。
STC:數據存儲器指令,用於將協處理器寄存器中的數據傳送到存儲器中。
MCR:ARM處理器寄存器到協寄存器寄存器的數據傳送指令。
MRC:協處理器寄存器到ARM處理器寄存器的數據傳送指令。
如CP15是ARM協處理器中十分重要的一個,MCR指令將ARM處理器的寄存器中的數據傳送到協處理器的CP15寄存器中。如果協處理器不能成功地執行該操作,將產生未定義的指令異常中斷。
程序示例
1.簡單的串比較strcmp
strcmp:
LDRB R2,[R0],#1;//取出r0的數據放到R2中,r0地址加1;
LDRB R3,[R1],#1;
CMP R2,#0;//判斷第一個字串是否搜索完畢;
CMPNE R3,#0;//判斷第二個字串是否搜索完畢;
BEQ return;//if 1
CMP R2,R3; //if 0 就進行比較
BEQ strcmp;//如過相等繼續比較;
return:
SUB R0,R2,R3;//不等,判斷兩者大小;
MOV PC,LR;
2.子程序進入和退出時數據的保存和恢復
R0~R3通常用作傳遞傳輸和返回結果,這幾個值由程序調用這來保存,但是其他寄存器需要在入口保存,然後返回的時候恢復;
func:
STMFD R13!,{R4-R12,R14};
....
LDMFD R13!,{R4-R12,PC};
3.SWI中斷程序示例
SWI在特權模式下請求特定的系統服務,這裏只是簡單演練一下處理SWI 軟件中斷的過程,不做過多說明:
SWIHandler:
STMFD SP!,{R0-R3,R12,LR};
MRS R0,SPSR;//獲取狀態寄存器放到R0中;
TST R0,#0X20;//判斷程序狀態是否爲ARM狀態;
LDRNEH R0,[LR,#-2];//如果是Thumb狀態;
LDREQ R0,[LR,#-4];//如果是ARM狀態;
BICEQ R0,R0,#0XFF000000;
CMP R0,#MAXSWI;//是否超出合法範圍;
LDRLS PC,[PC,R0,LSL #2];
//跳轉到相應的服務程序執行;
//ls爲條件: 低於或同於(無符號) 如果一次比較操作之後清除了 C 標誌或設置了 Z 標誌。成立的話pc = pc+(r0*4);
B SWIOutOfRange//超出合法範圍;
Switable://各服務程序函數地址表;
DCD do_swi_0
DCD do_swi_1
do_swi_0: //服務程序的代碼;
...
LDMFD SP!,{R0-R3,R12,PC}^ //從服務程序當中返回;
參考書籍
ARM體系結構編程 - 杜春雷
附件添加條件碼: