官术网_书友最值得收藏!

第3章 ARM指令及其尋址方式

3.1 ARM處理器的程序狀態(tài)寄存器(PSR)

ARM中的當(dāng)前程序狀態(tài)寄存器(Current Program Status Register,CPSR)可以在任何處理器模式下被訪問,而在5種異常中斷(exception)模式中又各自擁有一個獨立的備份程序狀態(tài)寄存器(Saved Program Status Register,SPSR)用來保存CPSR中的內(nèi)容。當(dāng)特定的異常中斷發(fā)生時,SPSR_xxx用來保存CPSR,當(dāng)異常中斷程序退出時,可以用SPSR_xxx中保存的值來恢復(fù)CPSR。

由于用戶(user)模式和系統(tǒng)(system)模式不是異常模式,所以它們沒有SPSR,當(dāng)在用戶模式或系統(tǒng)模式下訪問SPSR時,將會產(chǎn)生不可預(yù)知的結(jié)果。

當(dāng)前程序狀態(tài)寄存器共32位,當(dāng)前只實現(xiàn)了16位。該寄存器的各位定義說明如下:

表3-1 ARM中的程序狀態(tài)寄存器(PSR)

3.2 ARM指令的條件碼

3.3 ARM指令介紹

3.3.1 跳轉(zhuǎn)指令

跳轉(zhuǎn)指令是程序跳轉(zhuǎn)到-32MB~+32MB范圍內(nèi)地址處執(zhí)行。

b{<cond>} <target_address>

程序跳轉(zhuǎn)到<target_address>處執(zhí)行。

bl{<cond>} <target_address>

程序跳轉(zhuǎn)到<target_address>處執(zhí)行,將當(dāng)前pc的值保存到lr中。

blx <target_address>

程序跳轉(zhuǎn)到<target_address>處執(zhí)行,將程序狀態(tài)從ARM態(tài)切換到Thumb態(tài),將當(dāng)前pc的值保存到lr中。

blx{<cond>} <rm>

程序跳轉(zhuǎn)到rm值所指的地址處執(zhí)行,目標(biāo)地址處的指令可以是ARM指令也可以是Thumb指令,將當(dāng)前pc的值保存到lr中。

bx{<cond>} <rm>

程序跳轉(zhuǎn)到rm值所指的地址處執(zhí)行,目標(biāo)地址處的指令可以是ARM指令(rm[bit0=0]),也可以是Thumb指令(rm[bit0=1])。

3.3.2 數(shù)據(jù)處理指令

mov{<cond>}{s} <rd>, <shifter_operand>

將<shifter_operand>表示的數(shù)據(jù)傳遞給rd。

mvn{<cond>}{s} <rd>, <shifter_operand>

將<shifter_operand>表示的數(shù)據(jù)的反碼傳遞給rd。

add{<cond>}{s} <rd>, <rn>, <shifter_operand>

將<shifter_operand>表示的數(shù)據(jù)與<rn>的值相加,并把結(jié)果保存到<rd>中。

adc{<cond>}{s} <rd>, <rn>, <shifter_operand>

將<shifter_operand>表示的數(shù)據(jù)與<rn>的值相加,再加上CPSR中C標(biāo)志的值,并把結(jié)果保存到<rd>中。

sub{<cond>}{s} <rd>, <rn>, <shifter_operand>

將<rn>的值減去<shifter_operand>表示的數(shù)據(jù),并把結(jié)果保存到<rd>中。

sbc{<cond>}{s} <rd>, <rn>, <shifter_operand>

將<rn>的值減去<shifter_operand>表示的數(shù)據(jù),再減去CPSR中C標(biāo)志的值,并把結(jié)果保存到<rd>中。

rsb{<cond>}{s} <rd>, <rn>, <shifter_operand>

將<shifter_operand>表示的數(shù)據(jù)減去<rn>的值,并把結(jié)果保存到<rd>中。

將<shifter_operand>表示的數(shù)據(jù)減去<rn>的值,再減去CPSR中C標(biāo)志的值,并把結(jié)果保存到<rd>中。

and{<cond>}{s} <rd>, <rn>, <shifter_operand>

將<shifter_operand>表示的數(shù)據(jù)與<rn>的值按位做邏輯與操作,并把結(jié)果保存到<rd>中。

orr{<cond>}{s} <rd>, <rn>, <shifter_operand>

將<shifter_operand>表示的數(shù)據(jù)與<rn>的值按位做邏輯或操作,并把結(jié)果保存到<rd>中。

eor{<cond>}{s} <rd>, <rn>, <shifter_operand>

將<shifter_operand>表示的數(shù)據(jù)與<rn>的值按位做邏輯異或操作,并把結(jié)果保存到<rd>中。

bic{<cond>}{s} <rd>, <rn>, <shifter_operand>

將<shifter_operand>表示的數(shù)據(jù)與<rn>的值的反碼按位做邏輯與操作,并把結(jié)果保存到<rd>中。

cmp{<cond>} <rn>, <shifter_operand>

將<rn>的值減去<shifter_operand>表示的數(shù)據(jù),根據(jù)操作結(jié)果更新CPSR中相應(yīng)的條件標(biāo)志位。

cmn{<cond>} <rn>, <shifter_operand>

將<rn>的值加上<shifter_operand>表示的數(shù)據(jù),根據(jù)操作結(jié)果更新CPSR中相應(yīng)的條件標(biāo)志位。

tst{<cond>} <rn>, <shifter_operand>

將<shifter_operand>表示的數(shù)據(jù)與<rn>的值按位做邏輯與操作,根據(jù)操作結(jié)果更新CPSR中相應(yīng)的條件標(biāo)志位。

teq{<cond>} <rn>, <shifter_operand>

將<shifter_operand>表示的數(shù)據(jù)與<rn>的值按位做邏輯異或操作,根據(jù)操作結(jié)果更新CPSR中相應(yīng)的條件標(biāo)志位。

3.3.3 乘法指令

考慮到操作結(jié)果,指令中所有操作數(shù)都放在寄存器中。

mul{<cond>}{s} <rd>, <rm>, <rs>

將兩個32位(有/無)符號操作數(shù)相乘,將結(jié)果保存到32位寄存器<rd>中。

mla{<cond>}{s} <rd>, <rm>, <rs>, <rn>

將兩個32位(有/無)符號操作數(shù)相乘,再將乘積加上第3個操作數(shù),將結(jié)果保存到32位寄存器<rd>中。

smull{<cond>}{s} <rdLo>, <rdHi>, <rm>, <rs>

將兩個32位有符號操作數(shù)相乘,將結(jié)果的高32位保存到寄存器<rdHi>中,將結(jié)果的低32位保存到寄存器<rdLo>中。

smlal{<cond>}{s} <rdLo>, <rdHi>, <rm>, <rs>

將兩個32位有符號操作數(shù)的64位乘積結(jié)果與<rdHi>和<rdLo>中原來的64位數(shù)相加,將最后加法結(jié)果的高32位保存到寄存器<rdHi>中,低32位保存到寄存器<rdLo>中。

umull{<cond>}{s} <rdLo>, <rdHi>, <rm>, <rs>

將兩個32位無符號操作數(shù)相乘,將結(jié)果的高32位保存到寄存器<rdHi>中,將結(jié)果的低32位保存到寄存器<rdLo>中。

umlal{<cond>}{s} <rdLo>, <rdHi>, <rm>, <rs>

將兩個32位無符號操作數(shù)的64位乘積結(jié)果與<rdHi>和<rdLo>中原來的64位數(shù)相加,將最后加法結(jié)果的高32位保存到寄存器<rdHi>中,低32位保存到寄存器<rdLo>中。

3.3.4 雜類算術(shù)指令

clz{<cond>} <rd>, <rm>

計算寄存器<rm>的值的最高端0的個數(shù),如果bit31為1,那么指令返回0,如果<rm>=0,則指令返回32。

3.3.5 狀態(tài)寄存器訪問指令

mrs{<cond>} <rd>, cpsr

將當(dāng)前狀態(tài)寄存器的內(nèi)容傳送到<rd>中。

mrs{<cond>} <rd>, spsr

將處理器當(dāng)前工作模式的保存狀態(tài)寄存器的內(nèi)容傳送到<rd>中。

msr{<cond>} cpsr_<fields>, #<immediate>

將立即數(shù)傳給當(dāng)前狀態(tài)寄存器。

msr{<cond>} cpsr_<fields>, <rm>

將<rm>的值傳給當(dāng)前狀態(tài)寄存器。

msr{<cond>} spsr_<fields>, #<immediate>

將立即數(shù)傳給處理器當(dāng)前工作模式的保存狀態(tài)寄存器。

msr{<cond>} spsr_<fields>, <rm>

將<rm>的值傳給處理器當(dāng)前工作模式的保存狀態(tài)寄存器。

說明:

<fields>設(shè)置狀態(tài)寄存器中需要操作的位。狀態(tài)寄存器的32位可以分為4個8位的域:bits[31:24]為條件標(biāo)志位域,用f表示;bits[23:16]為狀態(tài)標(biāo)志位域,用s表示;bits[15:8]為擴(kuò)展位域,用x表示;bits[7:0]為控制標(biāo)志位域,用c表示。4部分狀態(tài)寄存器對應(yīng)的表示方法為:cpsr_f、cpsr_s、cpsr_x、cpsr_c及spsr_f、spsr_s、spsr_x、spsr_c。

3.3.6 Load/Store內(nèi)存訪問指令

ldr{<cond>} <rd>, <addressing_mode>

將<addressing_mode>尋址模式表示的內(nèi)存地址處的32位字讀取到<rd>中,如果地址不是字對齊的,那么從內(nèi)存中讀出的數(shù)據(jù)要進(jìn)行循環(huán)右移操作,移位的位數(shù)為地址的bits[1:0]表示的值的8倍,這樣對于little-endian的內(nèi)存模式,指令要讀取的字節(jié)數(shù)據(jù)存放在<rd>的低8位;對于big-endian的內(nèi)存模式,指令要讀取的字節(jié)數(shù)據(jù)存放在<rd>的bits[31:24]。

ldr{<cond>}b <rd>, <addressing_mode>

從內(nèi)存中將一個8位字節(jié)數(shù)讀取到<rd>中,并將<rd>的高24位清0。

ldr{<cond>}bt <rd>, <post_indexed_addressing_mode>

從內(nèi)存中將一個8位字節(jié)數(shù)讀取到<rd>中,并將<rd>的高24位清0;當(dāng)在特權(quán)級處理器模式下使用本指令時,內(nèi)存系統(tǒng)將該操作當(dāng)作一般用戶模式下的內(nèi)存訪問操作。

ldr{<cond>}h <rd>, <addressing_mode>

從內(nèi)存中將一個16位數(shù)據(jù)讀取到<rd>中,并將<rd>的高16位清0。如果內(nèi)存地址不是半字對齊的,將產(chǎn)生不可預(yù)知的結(jié)果。

ldr{<cond>}sb <rd>, <addressing_mode>

從內(nèi)存中將一個8位有符號字節(jié)數(shù)讀取到<rd>中,并將<rd>的高24位設(shè)置成該字節(jié)數(shù)據(jù)符號位的值。

ldr{<cond>}sh <rd>, <addressing_mode>

從內(nèi)存中將一個16位有符號數(shù)據(jù)讀取到<rd>中,并將<rd>的高16位設(shè)置成該半字?jǐn)?shù)據(jù)的符號位的值。如果內(nèi)存地址不是半字對齊的,將產(chǎn)生不可預(yù)知的結(jié)果。

ldr{<cond>}t <rd>, <post_indexed_addressing_mode>

從內(nèi)存中將一個32位字讀取到<rd>中,如果地址不是字對齊的,那么從內(nèi)存中讀出的數(shù)據(jù)要進(jìn)行循環(huán)右移操作,移位的位數(shù)為地址的bits[1:0]表示的值的8倍,這樣對于little-endian的內(nèi)存模式,指令要讀取的字節(jié)數(shù)據(jù)存放在<rd>的低8位;對于big-endian的內(nèi)存模式,指令要讀取的字節(jié)數(shù)據(jù)存放在<rd>的bits[31:24]。當(dāng)在特權(quán)級處理器模式下使用本指令時,內(nèi)存系統(tǒng)將該操作當(dāng)作一般用戶模式下的內(nèi)存訪問操作。

str{<cond>} <rd>, <addressing_mode>

將<rd>中的32位字寫入到<addressing_mode>尋址模式表示的內(nèi)存地址處。

str{<cond>}b <rd>, <addressing_mode>

將<rd>中的低8位字節(jié)數(shù)據(jù)寫入到<addressing_mode>尋址模式表示的內(nèi)存地址處。

str{<cond>}h <rd>, <addressing_mode>

將<rd>中的低16位半字?jǐn)?shù)據(jù)寫入到<addressing_mode>尋址模式表示的內(nèi)存地址處。如果內(nèi)存地址不是半字對齊的,將產(chǎn)生不可預(yù)知的結(jié)果。

str{<cond>}t <rd>, <addressing_mode>

將<rd>中的32位字寫入到<addressing_mode>尋址模式表示的內(nèi)存地址處。當(dāng)在特權(quán)級處理器模式下使用本指令時,內(nèi)存系統(tǒng)將該操作當(dāng)作一般用戶模式下的內(nèi)存訪問操作。

將<rd>中的低8位字節(jié)數(shù)據(jù)寫入到<addressing_mode>尋址模式表示的內(nèi)存地址處。當(dāng)在特權(quán)級處理器模式下使用本指令時,內(nèi)存系統(tǒng)將該操作當(dāng)作一般用戶模式下的內(nèi)存訪問操作。

str{<cond>}bt <rd>, <addressing_mode>

3.3.7 批量Load/Store內(nèi)存訪問指令

ldm{<cond>}<addressing_mode> <rn>!, <registers>

將數(shù)據(jù)從連續(xù)的內(nèi)存單元中讀取32位字到寄存器列表中。

ldm{<cond>}<addressing_mode> <rn>!, <registers_without_pc>^

將數(shù)據(jù)從連續(xù)的內(nèi)存單元中讀取32位字到寄存器列表中,但r15/pc寄存器不在寄存器列表中,此時指示指令中所有的寄存器為用戶模式下的寄存器。

ldm{<cond>}<addressing_mode> <rn>!, <registers_and_pc>^

將數(shù)據(jù)從連續(xù)的內(nèi)存單元中讀取32位字到寄存器列表中,且r15/pc寄存器必須在寄存器列表中,同時將當(dāng)前處理器模式對應(yīng)的SPSR寄存器的內(nèi)容復(fù)制到CPSR寄存器中。

stm{<cond>}<addressing_mode> <rn>!, <registers>

將寄存器列表中的32位字?jǐn)?shù)據(jù)寫入連續(xù)的內(nèi)存單元中。

stm{<cond>}<addressing_mode> <rn>!, <registers>^

將寄存器列表中的32位字?jǐn)?shù)據(jù)寫入連續(xù)的內(nèi)存單元中,并指示指令中所有的寄存器為用戶模式下的寄存器。

3.3.8 LDREX和STREX指令

■ 獨占加載和存儲寄存器

指令語法格式如下所示:

        LDREX{cond} Rt, [Rn {, #offset}]
        STREX{cond} Rd, Rt, [Rn {, #offset}]
        LDREXB{cond} Rt, [Rn]
        STREXB{cond} Rd, Rt, [Rn]
        LDREXH{cond} Rt, [Rn]
        STREXH{cond} Rd, Rt, [Rn]
        LDREXD{cond} Rt, Rt2, [Rn]
        STREXD{cond} Rd, Rt, Rt2, [Rn]

說明:

con可選的條件代碼。

Rd存放返回狀態(tài)的目標(biāo)寄存器。

Rt要加載或存儲的寄存器。

Rt2進(jìn)行雙字加載或存儲時要用到的第二個寄存器。

Rn內(nèi)存地址所基于的寄存器。

offset要應(yīng)用到Rn中的值的可選偏移量。offset只可用于Thumb-2指令中。如果省略offset,則認(rèn)為偏移量為0。

■ LDREX(獨占裝載指令)

LDREX可從內(nèi)存中加載數(shù)據(jù)。

如果物理地址有共享TLB屬性,那么LDREX會將該物理地址標(biāo)記為由當(dāng)前處理器獨占訪問,并且會清除該處理器對其他任何物理地址的獨占訪問標(biāo)簽。否則,會標(biāo)記為“執(zhí)行處理器已經(jīng)標(biāo)記了一個物理地址,但訪問尚未完畢”。

■ STREX(獨占存儲指令)

STREX可在一定條件下向內(nèi)存中存儲數(shù)據(jù)。條件具體如下:

● 如果物理地址沒有共享TLB屬性,執(zhí)行處理器有一個已標(biāo)記物理地址,但尚未訪問完畢,那么將會進(jìn)行存儲,清除該標(biāo)記,并向Rd中返回值0;

● 如果物理地址沒有共享TLB屬性,且執(zhí)行處理器也沒有已標(biāo)記但尚未訪問完畢的物理地址,那么將不會進(jìn)行存儲,而會向Rd返回值1;

● 如果物理地址有共享TLB屬性,且已被標(biāo)記為由執(zhí)行處理器獨占訪問,則將進(jìn)行存儲,清除標(biāo)簽,并向Rd返回值0;

● 如果物理地址有共享TLB屬性,但卻沒有標(biāo)記為由執(zhí)行處理器獨占訪問,則不會進(jìn)行存儲,而會向Rd中返回值1。

■ 限制

offset不可用于ARM指令中;offset的值可為0~1020范圍內(nèi)的任意一個4的倍數(shù)。

r15不可用于Rd、Rt、Rt2或Rn。

對于STREX,Rd一定不能與Rt、Rt2或Rn為同一寄存器。

對于LDREX,Rt和Rt2不可為同一寄存器。

在ARM指令中,Rt必須是一個編號為偶數(shù)的寄存器,且不能為r14;同時Rt2必須為R(d+1)。

■ 用法

利用LDREX和STREX可在多處理器和共享內(nèi)存系統(tǒng)間實現(xiàn)進(jìn)程間通信。

出于性能方面的考慮,請將相應(yīng)LDREX指令和STREX指令間的指令數(shù)控制到最少。

■ 注意

STREX指令中所用的地址必須要與近期執(zhí)行次數(shù)最多的LDREX指令所用的地址相同。如果使用不同的地址,則STREX指令的執(zhí)行結(jié)果將不可預(yù)知。

■ 適用體系結(jié)構(gòu)

ARM LDREX和STREX可用于ARMv6及更高版本中。

ARM LDREXB、LDREXH、LDREXD、STREXB、STREXD和STREXH可用于ARMv6K及更高版本中。

所有這些32位Thumb指令均可用于ARMv6T2和ARMv7,但LDREXD和STREXD不可用于ARMv7-M架構(gòu)。

這些指令均無16位版本。

■ 示例

        MOV r1, #0x1
        try
        LDREX r0, [LockAddr]
        CMP r0, #0
        STREXEQ r0, r1, [LockAddr]
        CMPEQ r0, #0
        BNE try
        ...

3.3.9 信號量操作指令

swp{<cond>} <rd>, <rm>, [<rn>]

將<rn>的值所指的內(nèi)存地址處的字節(jié)讀取到<rd>中,同時將<rm>的值寫入到<rn>的值所指的內(nèi)存地址中,當(dāng)<rd>和<rm>是同一寄存器時,指令交換該寄存器<rd>和內(nèi)存單元的內(nèi)容。

swp{<cond>}b <rd>, <rm>, [<rn>]

將<rn>的值所指的內(nèi)存地址處的字節(jié)數(shù)據(jù)讀取到<rd>的低8位中,<rd>的高24位清0,同時將<rm>的低8位寫入到<rn>的值所指的內(nèi)存地址中,當(dāng)<rd>和<rm>是同一寄存器時,指令交換該寄存器<rd>的低8位和內(nèi)存單元的內(nèi)容。

3.3.10 異常中斷產(chǎn)生指令

swi{<cond>} <immed_24>

產(chǎn)生軟中斷。ARM通過swi中斷機(jī)制來實現(xiàn)在用戶模式下對操作系統(tǒng)中特權(quán)模式程序的調(diào)用。<immed_24>又叫軟中斷號,被操作系統(tǒng)用來判斷用戶程序請求的服務(wù)類型。

bkpt <immed_16>

產(chǎn)生軟件斷點中斷。軟件調(diào)試程序可以使用該中斷,當(dāng)系統(tǒng)使用硬件調(diào)試器時可以忽略該中斷。<immed_16>被調(diào)試軟件用來保存額外的斷點信息。

3.3.11 ARM協(xié)處理器指令

cdp{<cond>} <coproc>, <opcode_1>, <crd>, <crn>, <crm>, <opcode_2>

ARM處理器通知ARM協(xié)處理器執(zhí)行特定的操作,該操作由協(xié)處理器完成,如果協(xié)處理器不能成功執(zhí)行該操作,將產(chǎn)生未定義的指令異常中斷。

說明:

<coproc> 協(xié)處理器的編號。

<opcode_1> 協(xié)處理器將執(zhí)行的操作的操作碼。

<crd> 作為目標(biāo)寄存器的協(xié)處理器寄存器。

<crn> 存放第1個操作數(shù)的協(xié)處理器寄存器。

<crm> 存放第1個操作數(shù)的協(xié)處理器寄存器。

<opcode_2> 協(xié)處理器將執(zhí)行的操作的操作碼。

示例

        cdp p5, 2, c12, c10, c3, 4 ;初始化協(xié)處理器p5,操作碼1為2,操作碼2為4,目標(biāo)
    寄存器為c12,源操作數(shù)寄存器為c10和c3

ldc{<cond>}{L} <coproc>, <crd>, <addressing_mode>

從一系列連續(xù)的內(nèi)存單元中將數(shù)據(jù)讀取到協(xié)處理器的寄存器中,如果協(xié)處理器不能成功執(zhí)行該操作,將產(chǎn)生未定義的指令異常中斷。

說明:

{L} 指示指令為長讀取操作,比如用于雙精度的數(shù)據(jù)傳送。

示例

        ldc p6, cr4, [r2, #4]  ;讀取內(nèi)存單元[r2+4]的字?jǐn)?shù)據(jù)并寫入到協(xié)處理器p6的cr4的
    寄存器中
        stc{<cond>}{L}  <coproc>, <crd>, <addressing_mode>

將協(xié)處理器的寄存器中的數(shù)據(jù)寫入到一系列連續(xù)的內(nèi)存單元中,如果協(xié)處理器不能成功執(zhí)行該操作,將產(chǎn)生未定義的指令異常中斷。

示例

        stc p6, cr6, [r2, #4]! ;將協(xié)處理器p6的cr6的寄存器中的字?jǐn)?shù)據(jù)寫入到內(nèi)存單元
    [r2+4]中,然后r2=r2+4
        mcr{<cond>} <coproc>, <opcode_1>, <rd>, <crn>, <crm>, {<opcode_2>}

將ARM處理器寄存器中的數(shù)據(jù)寫到協(xié)處理器的寄存器中,如果協(xié)處理器不能成功執(zhí)行該操作,將產(chǎn)生未定義的指令異常中斷。

示例

        mcr p14, 3, r7, c7, c11, 6 ;將r7中的數(shù)據(jù)寫到協(xié)處理器p14的寄存器c7和c11中,操作碼1為3,操作碼2為6
        mrc{<cond>} <coproc>, <opcode_1>, <rd>, <crn>, <crm>, {<opcode_2>}

將協(xié)處理器的寄存器中的數(shù)據(jù)寫到ARM處理器的寄存器中,如果協(xié)處理器不能成功執(zhí)行該操作,將產(chǎn)生未定義的指令異常中斷。

示例

        mrc p15, 2, r5, c0, c2, 4      ;將協(xié)處理器p15的寄存器中的數(shù)據(jù)寫到r5中,操作
    碼1為2,操作碼2為4

3.4 ARM指令尋址方式

3.4.1 數(shù)據(jù)處理指令的操作數(shù)的尋址方式

數(shù)據(jù)處理指令的一般編碼格式如下所示:

數(shù)據(jù)處理指令的一般語法格式如下所示:

<opcode>{<cond>}{S} <Rd>,<Rn>,<shifter_operand>

數(shù)據(jù)操作指令的操作數(shù)的尋址方式是針對第2個操作數(shù)shifter_operand的,粗分為3種尋址方式,具體細(xì)分為11種尋址方式。

數(shù)據(jù)處理指令的(第2個)操作數(shù)的尋址方式粗分為以下3種方式:

■ 立即數(shù)方式

立即數(shù)是32位的,但它只能占用指令格式中12位的<shifter_operand>,所以在匯編代碼時是要將32位的立即數(shù)編碼成12位的<shifter_operand>。立即數(shù)編碼有固定的規(guī)則,每個立即數(shù)由一個8位的常數(shù)循環(huán)右移偶數(shù)位得到,右移的位數(shù)由一個4位的二進(jìn)制數(shù)的兩倍表示,所以立即數(shù)尋址方式的指令編碼格式如下:

其中4位的roate_imm是二進(jìn)制移位數(shù)的一半,8位的immed_8是常數(shù),兩者剛好組成了指令中的第2個操作數(shù)<shifter_operand>。如果立即數(shù)記作<immediate>,那么:

<immediate> = immed_8循環(huán)右移(2*rotate_imm)

千萬不要錯誤直觀地認(rèn)為:

<immediate> = immed_8 |(rotate_imm<<8)

由以上立即數(shù)的編碼規(guī)則可以判斷立即數(shù)的合法性,舉例說明:

0xFF、0x104、0xFF0、0xFF00等都是合法的立即數(shù);而0x101、0x102、0xFF1等則是非法的立即數(shù),因為無法根據(jù)上面的編碼規(guī)則對它們進(jìn)行編碼。

另外同一個合法立即數(shù)可能有若干種編碼方法,比如0x3F可以有以下兩種編碼方法:

由于這種立即數(shù)的構(gòu)造方法中包含了循環(huán)移位操作,而循環(huán)移位操作會影響CPSR的條件標(biāo)志位C,因此同一個合法立即數(shù)采用不同的編碼方式將使某些指令的執(zhí)行產(chǎn)生不同的結(jié)果,這是不允許的。ARM匯編編譯器遵守下面的規(guī)則:

immed_8=0x3F,rotate_imm=0或者immed_8=0xFC,rotate_imm=0xF

當(dāng)立即數(shù)數(shù)值在0~0xFF范圍時,令immed_8=<immediate>,rotate_imm=0;

在其他情況下,匯編編譯器選擇使rotate_imm數(shù)值最小的編碼方式。

心得:如何快速判斷一個32位立即數(shù)是否合法?只要看該立即數(shù)能否通過右移偶數(shù)位把該立即數(shù)的所有非0位都移到最低8位中,如果能,那么這個立即數(shù)肯定能通過上面的編碼規(guī)則進(jìn)行編碼,是合法立即數(shù);否則該立即數(shù)一定是非法立即數(shù)。

■ 寄存器方式

第2個操作數(shù)即是Rm寄存器的值。

■ 寄存器移位方式

移位的方式有5種,它們的助記符和含義說明如下:

ASR 算術(shù)右移

LSL 邏輯左移

LSR 邏輯右移

ROR 循環(huán)右移

RRX擴(kuò)展的循環(huán)右移

數(shù)據(jù)處理指令的(第2個)操作數(shù)的尋址方式具體細(xì)分為以下11種方式:

① #<immediate>

指令編碼格式:

示例:

        mov r0, #0xfc0

② <Rm>

指令編碼格式:

示例:

        mov r3,r2

注意:當(dāng)R15/pc用作第1個源操作數(shù)Rn或者第2個操作數(shù)Rm時,操作數(shù)即為當(dāng)前指令地址加常數(shù)8,見前面“ARM流水線操作”說明。

③ <Rm>,LSL #<shift_imm>

指令編碼格式:

示例:

        mov r0,r0,LSL #n   ;將r0的值左移n位,右邊空位用0補充,循環(huán)器進(jìn)位標(biāo)志的值等于
    最后從寄存器r0中移出位的值,如果沒有移位,那么循環(huán)器進(jìn)位標(biāo)志的值等于CPSR中C標(biāo)志位的值

注意:當(dāng)R15/pc用作第1個源操作數(shù)Rn或者第2個操作數(shù)Rm時,操作數(shù)即為當(dāng)前指令地址加常數(shù)8。

④ <Rm>,LSL <Rs>

指令編碼格式:

注意:當(dāng)R15/pc用作Rn、Rm、Rd或Rs時,會產(chǎn)生不可預(yù)知的結(jié)果。

⑤ <Rm>,LSR #<shift_imm>

指令編碼格式:

示例:

        mov r0,r0,LSR #n   ;將r0的值右移n位,左邊空位用0補充,循環(huán)器進(jìn)位標(biāo)志的值等于
    最后從寄存器r0中移出位的值,如果n等于0,那么右移32位

注意:當(dāng)R15/pc用作第1個源操作數(shù)Rn或者第2個操作數(shù)Rm時,操作數(shù)即為當(dāng)前指令地址加常數(shù)8。

⑥ <Rm>,LSR <Rs>

指令編碼格式:

注意:當(dāng)R15/pc用作Rn、Rm、Rd或Rs時,會產(chǎn)生不可預(yù)知的結(jié)果。

⑦ <Rm>,ASR #<shift_imm>

指令編碼格式:

示例:

        mov r0,r0,ASR #n   ;將r0的值右移n位,左邊空位用R0[31]位的值補充,循環(huán)器進(jìn)位標(biāo)志的值等于最后從寄存器r0中移出位的值,如果n等于0,則沒有移位,那么循環(huán)器進(jìn)位標(biāo)志的值等于CPSR中C標(biāo)志位的值
    R0[31]

注意:當(dāng)R15/pc用作第1個源操作數(shù)Rn或者第2個操作數(shù)Rm時,操作數(shù)即為當(dāng)前指令地址加常數(shù)8。

⑧ <Rm>,ASR <Rs>

指令編碼格式:

注意:當(dāng)R15/pcP用作Rn、Rm、Rd或Rs時,會產(chǎn)生不可預(yù)知的結(jié)果。

⑨ <Rm>,ROR #<shift_imm>

指令編碼格式:

示例:

      mov r0,r0,ROR #n   ;將r0的值右移n位,移出的位右移入寄存器的左邊空位,循環(huán)器進(jìn)位
      標(biāo)志的值等于最后從r0寄存器右邊移出位的值;如果n等于0,那么操作與下面的RRX移位操作相同

注意:當(dāng)R15/pc用作第1個源操作數(shù)Rn或者第2個操作數(shù)Rm時,操作數(shù)即為當(dāng)前指令地址加常數(shù)8。

⑩ <Rm>,ROR <Rs>

指令編碼格式:

注意:當(dāng)R15/pc用作第1個源操作數(shù)Rn或者第2個操作數(shù)Rm時,操作數(shù)即為當(dāng)前指令地址加常數(shù)8。

? <Rm>,RRX

指令編碼格式:

示例:

        mov r0,r0,RRX  ;將r0的值右移1位,將CPSR的C標(biāo)志填充左邊移出的位,而CPSR的C
    標(biāo)志位用從右邊移出位的值替代

注意:當(dāng)R15/pc用作第1個源操作數(shù)Rn或者第2個操作數(shù)Rm時,操作數(shù)即為當(dāng)前指令地址加常數(shù)8。

3.4.2 字及無符號字節(jié)的Load/Store指令的尋址方式

字及無符號字節(jié)Load/Store指令的一般編碼格式如下所示:

字及無符號字節(jié)Load/Store指令的一般語法格式如下所示:

ldr|str{<cond>}{B} {T}<Rd>, <addressing_mode>

各種類型的Load/Store指令的尋址方式由兩部分組成:一部分為一個基址寄存器,另一部分為一個地址偏移量。基址寄存器可以是任一通用寄存器,地址偏移量則有以下3種格式:

● 立即數(shù)

● 寄存器

● 寄存器加一個移位常數(shù)

同樣,尋址方式的地址計算方法有如下3種:

● 不更新基址寄存器方法

● 事先更新基址寄存器方法

● 事后更新基址寄存器方法

字及無符號字節(jié)Load/Store指令的操作數(shù)的尋址方式是針對第2個操作數(shù)Addressing_mode的,具體細(xì)分為以下9種尋址方式。

① [<Rn>, #+/-<offset_12>]

指令編碼格式:

示例:

        ldr r0, [r1,-#4]   ;將內(nèi)存單元r1-4中的字讀取到r0寄存器中

注意:當(dāng)R15/pc用作Rn時,內(nèi)存基地址為當(dāng)前指令地址加8字節(jié)偏移量。

② [<Rn>, +/-<Rm>]

指令編碼格式:

示例:

        ldr r0, [r1,-r2]   ;將內(nèi)存單元r1-r2中的字讀取到r0寄存器中

注意:當(dāng)R15/pc用作Rn時,內(nèi)存基地址為當(dāng)前指令地址加8字節(jié)偏移量;當(dāng)R15/pc用作索引寄存器Rm時,會產(chǎn)生不可預(yù)知的結(jié)果。

③ [<Rn>, +/-<Rm>, <shift>#<shift_imm>]

指令編碼格式:

示例:

        ldr r0, [r1, r2, LSL #2]       ;將內(nèi)存單元(r1+r2*4)中的字讀取到r0中

注意:當(dāng)R15/pc用作Rn時,內(nèi)存基地址為當(dāng)前指令地址加8字節(jié)偏移量;當(dāng)R15/pc用作索引寄存器Rm時,會產(chǎn)生不可預(yù)知的結(jié)果。

④ [<Rn>, #+/-<offset_12>]!

指令編碼格式:

示例:

        ldr r0, [r1,#4]!   ;將內(nèi)存單元(r1+4)中的字讀取到r0中,同時r1=r1+4

注意:當(dāng)R15/pc用作Rn時,會產(chǎn)生不可預(yù)知的結(jié)果。

⑤ [<Rn>, +/-<Rm>]!

指令編碼格式:

示例:

        ldr r0, [r1, r2]!  ;將內(nèi)存單元(r1+r2)中的字讀取到r0中,同時r1=r1+r2

注意:當(dāng)R15/pc用作Rn或Rm時,會產(chǎn)生不可預(yù)知的結(jié)果;當(dāng)Rn和Rm是同一個寄存器時,會產(chǎn)生不可預(yù)知的結(jié)果。

⑥ [<Rn>, +/-<Rm>, <shift>#<shift_imm>]!

指令編碼格式:

示例:

        ldr r0, [r1, r2, LSL #2]!      ;將內(nèi)存單元(r1+r2*4)中的字讀取到r0中,同時
    r1=r1+r2*4

注意:當(dāng)R15/pc用作Rn或Rm時,會產(chǎn)生不可預(yù)知的結(jié)果;當(dāng)Rn和Rm是同一寄存器時,會產(chǎn)生不可預(yù)知的結(jié)果。

⑦ [<Rn>], #+/-<offset_12>

指令編碼格式:

示例:

        ldr r0, [r1], #4   ;將內(nèi)存單元r1中的字讀取到r0中,然后r1=r1+4,這叫事后更新
    方法

注意:當(dāng)R15/pc用作Rn或Rm時,會產(chǎn)生不可預(yù)知的結(jié)果。

      ⑧ [<Rn>],   +/-<Rm>

指令編碼格式:

示例:

        ldr r0, [r1], r2   ;將內(nèi)存單元r1中的字讀取到r0中,然后r1=r1+r2,這叫事后更新
    方法

注意:當(dāng)R15/pc用作Rn或Rm時,會產(chǎn)生不可預(yù)知的結(jié)果;當(dāng)Rn和Rm是同一寄存器時,會產(chǎn)生不可預(yù)知的結(jié)果。

      ⑨ [<Rn>],   +/-<Rm>,    <shift>#<shift_imm>

指令編碼格式:示例:

        ldr r0, [r1], r2, LSL #2       ;將內(nèi)存單元r1中的字讀取到r0中,然后
    r1=r1+r2*4,這叫事后更新方法

注意:當(dāng)R15/pc用作Rn或Rm時,會產(chǎn)生不可預(yù)知的結(jié)果;當(dāng)Rn和Rm是同一寄存器時,會產(chǎn)生不可預(yù)知的結(jié)果。

3.4.3 雜類Load/Store指令的尋址方式

雜類Load/Store指令包括半字、帶符號字節(jié)、雙字的Load/Store指令。

雜類Load/Store指令的一般編碼格式如下所示:

雜類Load/Store指令的一般語法格式如下所示:

ldr|str{<cond>}H|SH|SB|D <Rd>, <addressing_mode>;addressing_mode為bit[11:0];

雜類Load/Store指令操作數(shù)的尋址方式是針對第2個操作數(shù)Address_mode的,具體細(xì)分為以下6種尋址方式:

① [<Rn>, #+/-<offset_8>];offset_8=(offsetH<<4)|offsetL

指令編碼格式:示例:

        ldrsb   r0, [r1, #3]   ;將內(nèi)存單元(r1+3)中的有符號字節(jié)讀取到r0中,r0中高24
    位為字節(jié)的符號位

注意:當(dāng)R15/pc用作Rn時,內(nèi)存基地址為當(dāng)前指令地址加8字節(jié)偏移量。

② [<Rn>, +/-<Rm>]

指令編碼格式:

示例:

        strh    r0, [r1, r2]   ;將r0中的低16位數(shù)據(jù)保存到內(nèi)存單元(r1+r2)中

注意:當(dāng)R15/pc用作Rn時,內(nèi)存基地址為當(dāng)前指令地址加8字節(jié)偏移量;當(dāng)R15/pc用作索引寄存器Rm時,會產(chǎn)生不可預(yù)知的結(jié)果。

③ [<Rn>, #+/-<offset_8>]!;offset_8=(offsetH<<4)|offsetL

指令編碼格式:

示例:

        ldrsh   r0, [r1, #2]!  ;將內(nèi)存單元(r1+2)中的有符號半字讀取到r0中,r0中高16
    位為半字的符號位,同時r1=r1+2

注意:當(dāng)R15/pc用作Rn時,會產(chǎn)生不可預(yù)知的結(jié)果。

④ [<Rn>, +/-<Rm>]!

指令編碼格式:

示例:

        ldrh    r0, [r1, r2]!  ;將存單元(r1+r2)中的半字?jǐn)?shù)據(jù)讀取到r0中,r0中的高16
    位設(shè)置為0,同時r1=r1+r2

注意:當(dāng)R15/pc用作Rn或Rm時,會產(chǎn)生不可預(yù)知的結(jié)果;當(dāng)Rn和Rm是同一寄存器時,會產(chǎn)生不可預(yù)知的結(jié)果。

⑤ [<Rn>], #+/-<offset_8>;offset_8=(offsetH<<4)|offsetL

指令編碼格式:示例:

        strh    r0, [r1], #2   ;將r0中低16位數(shù)據(jù)保存到內(nèi)存單元(r1)中,然后r1=r1+2

注意:當(dāng)R15/pc用作Rn或Rm時,會產(chǎn)生不可預(yù)知的結(jié)果。

⑥ [<Rn>], +/-<Rm>

指令編碼格式:

示例:

        strh    r0, [r1], r2   ;將r0中低16位數(shù)據(jù)保存到內(nèi)存單元(r1)中,然后r1=r1+r2

注意:當(dāng)R15/pc用作Rn或Rm時,會產(chǎn)生不可預(yù)知的結(jié)果;當(dāng)Rn和Rm是同一寄存器時,會產(chǎn)生不可預(yù)知的結(jié)果。

3.4.4 批量Load/Store指令的尋址方式

批量Load/Store指令的一般編碼格式如下所示:

批量Load/Store指令的一般語法格式如下所示:

ldm|stm{<cond>}<addressing_mode> <Rn>{!}, <registers>{^};addressing_mode為bit[11:0];

一條批量Load/Store指令可以實現(xiàn)在一組寄存器和一塊連續(xù)的內(nèi)存單元之間傳輸數(shù)據(jù),指令中的寄存器組和內(nèi)存單元的對應(yīng)關(guān)系有固定的規(guī)則,即:低編號的寄存器對應(yīng)于內(nèi)存單元中低地址單元,高編號的寄存器對應(yīng)于內(nèi)存中高地址單元,基址寄存器<Rn>中存放地址塊的起始地址值,可能是最高地址值,也可能是最低地址值。

指令中的<addressing_mode>表示地址的變化方式,共有如下4種方式:

① IA-Increment After 事后遞增方式

指令編碼格式如下所示:

② IB-Increment Before 事先遞增方式

指令編碼格式如下所示:

③ DA-Decrement After 事后遞減方式

指令編碼格式如下所示:

④ DB-Decrement Before 事先遞減方式

指令編碼格式如下所示:

除了可以在一組寄存器和一塊連續(xù)的內(nèi)存單元之間批量傳輸數(shù)據(jù)外,還可以在數(shù)據(jù)棧中批量傳輸數(shù)據(jù)。數(shù)據(jù)棧的棧指針通常可以指向不同的位置,棧指針指向棧頂元素(即最后一個入棧的數(shù)據(jù)元素)的叫Full棧。棧指針指向棧頂元素相鄰的一個可用數(shù)據(jù)單元的稱為Empty棧。

另外數(shù)據(jù)棧的增長方向也可以不同,數(shù)據(jù)棧向內(nèi)存地址減小的方向增長叫Descending棧;數(shù)據(jù)棧向內(nèi)存地址增加的方向增長的叫Ascending棧。

綜合以上兩種特點,總共有下面4種數(shù)據(jù)棧:

● FD Full Descending

● ED Empty Descending

● FA Full Ascending

● EA Empty Ascending

不同數(shù)據(jù)棧對應(yīng)的批量Load/Store指令的尋址方式如表3-2所示。

表3-2 Load/Store尋址方式

3.4.5 協(xié)處理器Load/Store指令的尋址方式

雜類Load/Store指令的一般編碼格式如下所示:

協(xié)處理器Load/Store指令的一般語法格式如下所示:

mcr|mrc{<cond>}{L} <coproc>,<Rd>,<addressing_mode>

其中<addressing_mode>表示地址變化方式,有以下4種格式:

① 偏移量[<Rn>, #+/-<offset_8>*4]

指令編碼格式如下所示:

注意:當(dāng)R15/pc作為Rn時,其值為當(dāng)前指令的地址加8。

② 事前更新[<Rn>, #+/-<offset_8>*4]!

指令編碼格式如下所示:

注意:當(dāng)R15/pc作為Rn時,會產(chǎn)生不可預(yù)知的結(jié)果。

③ 事后更新[<Rn>], #+/-<offset_8>*4

指令編碼格式如下所示:

注意:當(dāng)R15/pc作為Rn時,會產(chǎn)生不可預(yù)知的結(jié)果。

④ 非索引[<Rn>], <option>;<option>未被ARM使用,可用作協(xié)處理器來擴(kuò)展指令。

指令編碼格式如下所示:

注意:當(dāng)R15/pc作為Rn時,其值為當(dāng)前指令的地址加8。

3.4.6 ARM指令的尋址方式總結(jié)

所謂尋址方式就是處理器根據(jù)指令中給出的地址信息來尋找物理地址的方式,總結(jié)上面的詳細(xì)描述,可以把ARM指令的尋址方式歸納成以下7種:

3.5 ARM匯編偽操作(Directive)

ARM匯編語言源程序的語句由指令、偽操作和宏指令組成,偽操作叫Derective,宏指令叫pseudo-instruction,宏指令也是通過偽操作來定義的。

偽操作是由匯編器在對源程序匯編期間進(jìn)行處理的;宏則是一段獨立的程序代碼,在程序中通過宏指令調(diào)用宏,當(dāng)程序被匯編時,匯編器對每個宏調(diào)用進(jìn)行展開,用宏定義體取代源程序中的宏指令。

ARM偽操作主要包括以下幾類:

1)符號定義(Symbol definition)偽操作;

2)數(shù)據(jù)定義(Data definition)偽操作;

3)匯編控制(Assembly control)偽操作;

4)棧中數(shù)據(jù)幀描述(Frame description)偽操作;

5)信息報告(Reporting)偽操作;

6)其他(Miscellaneous)偽操作。

3.5.1 符號定義偽操作

3.5.2 數(shù)據(jù)定義偽操作

續(xù)表

3.5.4 棧中數(shù)據(jù)幀描述偽操作

主要用于調(diào)試,此處不做介紹。

3.5.5 信息報告?zhèn)尾僮?/h4>

表3-2 opt偽操作選項編碼

ttl

在列表文件每一頁的開頭插入一個標(biāo)題,它將作用于其后的每一頁直到遇到新的ttl。

語法格式

        ttl title

subt

在列表文件每一頁的開頭插入一個子標(biāo)題,它將作用于其后的每一頁直到遇到新的subt。

語法格式

        subt    title

3.5.6 其他偽操作

續(xù)表

3.6 ARM匯編偽指令

ARM偽指令不是真正的ARM指令或Thumb指令,偽指令在匯編編譯器對源程序進(jìn)行匯編處理時被替換成對應(yīng)的ARM或Thumb指令序列。

3.7 Thumb指令介紹

Thumb指令集是將ARM指令集的一個子集重新編碼形成的一個指令集。ARM指令長度為32位而Thumb指令長度為16位,所以使用Thumb指令集可以得到密度更高的代碼,這對于需要嚴(yán)格控制產(chǎn)品成本的設(shè)計是非常有意義的。

與ARM指令集相比,Thumb指令集有以下局限:

1)完成相同的操作,通常需要更多的Thumb指令,所以在對系統(tǒng)運行時間要求苛刻的應(yīng)用場合ARM指令集更為合適;

2)Thumb指令集沒有包含進(jìn)行異常處理的一些指令,因此在異常處理低級處理時,還是需要ARM指令,這就使得Thumb指令必須與ARM指令配合使用。

Thumb指令集有兩個版本:版本1用于ARMv4的T變種;而版本2用于ARMv5及以上的T變種。

Thumb指令集的版本2相對于版本1有以下特點:

1)通過增加指令和對已有指令的修改,提高ARM指令和Thumb指令混合使用時的效率;

2)增加了軟件斷點指令;

3)更嚴(yán)格定義了Thumb乘法指令對條件標(biāo)志位的影響。

主站蜘蛛池模板: 湖南省| 武冈市| 荆州市| 连江县| 梧州市| 隆昌县| 韶山市| 井陉县| 雷山县| 古丈县| 民权县| 高尔夫| 丰顺县| 涟源市| 察隅县| 宿州市| 若尔盖县| 甘洛县| 嘉义市| 万盛区| 太湖县| 尤溪县| 上饶县| 桂东县| 运城市| 许昌县| 麻阳| 珲春市| 田阳县| 沿河| 辽阳市| 凭祥市| 海城市| 兴和县| 莆田市| 黑龙江省| 南召县| 罗定市| 调兵山市| 友谊县| 静安区|