2012-01-28 58 views
5

有人可以解釋ARM位移給我像我五?對於涉及非十進制數字系統的任何事情我都有很差的理解,因此理解位移和位運算符的概念對我來說很困難。有人可以向我解釋ARM按位操作嗎?

以下情況會發生什麼,以及爲什麼(什麼會以R3結束,以及在位級別的幕後發生了什麼)?

/** LSL **/ 
mov r0, #1 
mov r3, r0, LSL#10 

/** LSR **/ 
mov r0, #1 
mov r3, r0, LSR#10 

/** ORR **/ 
mov r0, #1 
mov r1, #4 
orr r3, r1, r0 

/** AND **/ 
mov r0, #1 
mov r1, #4 
and r3, r1, r0 

/** BIC **/ 
mov r0, #1 
mov r1, #4 
bic r3, r1, r0 

PS。不要用C位運算符來解釋它。我不知道他們做了什麼(>>,<<,|,&)。

回答

15

真值表,兩個輸入端,在左,一個輸出的兩個數字,右邊的數:

OR

a b c  
0 0 0 
0 1 1 
1 0 1 
1 1 1 

左側兩個輸入a和b表示的四種可能的組合的投入,沒有更多不少於這個清單。

考慮1代表真,0代表假。在這種情況下,OR這個詞意味着如果一個OR b是真的,那麼c是真的。正如你在表中看到的那樣,如果a或b是真的,那麼c就是水平的。

a b c 
0 0 0 
0 1 0 
1 0 0 
1 1 1 

而且意味着他們都有如果A和B都爲真,那麼c爲真令人難以置信。上面只存在一種情況。

現在取兩個字節0x12和0x34,其中十進制是18和52,但我們並不十分關心小數。我們關心二進制0x12是0b00010010而0x34是0b00110100。像彙編語言中的AND和OR和XOR這樣的按位運算符意味着您從每個操作數取一位,並將結果放在相同的位位置。它不像加上你有這樣的事情,加上等於等等等等。

所以我們排隊位

0b00010010 0x12 
0b00110100 0x34 

於是轉過頭sidways像你要採取咬了你,左手持塔科和可視化上面的真值表。如果我們看右邊的兩位,它們是0和0,接下來的兩位是1和0,依此類推。所以,如果我們想要做或操作,該規則是,如果A或B爲真,那麼C,其結果,是真正的

0b00010010 
    0b00110100 
OR ========== 
    0b00110110 

頭向右傾斜,至少顯著位(在那些位列中的數字)0或0 = 0,都沒有設置。下一列(二列)1或0 = 1至少有一個是真的。等這樣

0×12 OR 0x34 = 0x36

在臂組件,這將是

mov r0,#0x12 
mov r1,#0x34 
orr r2,r0,r1 
的或操作R2將持有的值0x36之後

現在,讓我們和這些數字

0b00010010 
    0b00110100 
AND ========== 
    0b00010000 

記住我們的真值表和規則A和B都爲真(1)我們我們的頭向右傾斜,0,0 0,無論是是不正確的。並且通過檢查,只有一列具有1個16s列的輸入。這給我們留下了0×12和0x34 = 0x10的

在臂組件,這將是

mov r0,#0x12 
mov r1,#0x34 
and r2,r0,r1 

現在我們要在BIC指令。其中代表清楚,希望稍微有意義。手臂上的BIC與B不同。那是另一真值表,但只有一個輸入和一個輸出

a c 
0 1 
1 0 

只有一個輸入我們只有兩個選擇,0和1,1爲真0是假的。不意味着如果沒有,那麼c是真實的。當a不正確時c是真實的,當a正確時c不正確。基本上它倒置。

什麼BIC確實是有兩個輸入A和B,操作C = A AND(非B),因此該真值表將是:

一個AND(非B)

a b c 
0 1 0 
0 0 0 
1 1 0 
1 0 1 

我開始與AND真值表,然後注意到b比特,其中b是在AND真值表中的0我讓它成爲1其中b是AND真值表中的1我使它成爲0.

所以0x12和0x34上的bic操作是

0b00010010 
    0b00110100 
BIC ========== 
    0b00000010 

爲什麼它被稱爲位清晰?瞭解這一點使它更容易使用。如果你看看真值表,並考慮第一個和第二個輸入。在第二個輸入是1的情況下,輸出是0.在第二輸入b是0的情況下,輸出本身是未修改的。因此,真值表或操作所做的是在任何地方將b設置爲清零或將A中的那些位置爲零。因此,如果我具有數字0x1234並且我想將較低的8位置零,那麼我將BIC與0x00FF進行比較。而你的下一個問題是爲什麼不與AND 0xFF00? (分析AND真值表,看看哪裏b是1,你保持a值原樣,並且無論b是0,你的輸出爲零)。 ARM至少使用32位寄存器和固定的32位指令集。立即指令

mov r0,#0x12 

支持限制在數字中任意位置移動的8位非零位,將會移位一位。所以,如果我有值0×12345678,想零出低8位,我可以做到這一點

; assume r0 already has 0x12345678 
bic r0,r0,#0xFF 

; assume r0 already has 0x12345678 
mov r1,#0xFF000000 
orr r1,r1,#0x00FF0000 
orr r1,r1,#0x0000FF00 
;r1 now contains the value 0xFFFFFF00 
and r0,r0,r1 

; assume r0 already contains 0x12345678 
ldr r1,my_byte_mask 
and r0,r0,r1 
my_byte_mask: .word 0xFFFFFF00 

這並不可怕,比起使用移動和兩個orrs,但仍比bic解決方案耗費更多的時鐘週期,因爲您將額外的內存循環從ram中讀取my_byte_mask,這可能需要一段時間。

; assume r0 already contains 0x12345678 
mvn r1,#0xFF 
and r0,r0,r1 

這最後一個是不是一個壞compromize。請注意arm文檔中的mvn不是立即數,這意味着rx = NOT(立即數)。這裏的直接是0xFF。 NOT(0xFF)表示反轉所有位,它是一個32位寄存器,我們將這樣做,這意味着0xFFFFFF00是NOT(0xFF)的結果,這就是寄存器r1在執行和之前得到的結果。

所以這就是爲什麼BIC在ARM指令集的地方,因爲有時它需要較少的指令或時鐘週期掩模(掩模= AND用於製造某些位零)使用BIC指令,而不是與指令。

我用單詞掩碼作爲一個概念,使數字零位留下其他人。如果你在任何時候b是1時看看OR真值表,那麼可以認爲它是在第一位中進行比特,然後c是1.因此,0x12345678或0x000000FF會導致0x123456FF中的第二個比特操作數被設置。是的,任何時候在OR真值表中設置a然後設置輸出也是真實的,但是當使用這些按位操作時,您有很多時間需要對某個操作數進行操作,設置一定數量的位到其中一個而不修改剩餘的位或者將一定數量的位設置爲零而不修改其餘位或者您想除了一定數量的位之外將所有位置零。當使用這種方式時,您將有一個操作數進入您想要操作的位置,並根據您想要的整體效果創建第二個操作數,例如在C中,如果我們只想保留低位字節有,一個參數功能的有一個參數:

unsigned int keep_lower_byte (unsigned int a) 
{ 
    return(a&(~0xFF)); 
} 

〜意味着不僅如此〜0xFF時,爲32位數字指0xFFFFFF00然後&手段和,所以我們返回& 0xFFFFFF00。 a是唯一真正的操作數,我們根據我們想要做的操作發明了第二個操作數...大多數按位操作可以交換指令中的操作數,一切都變好了,但是ARM的bic指令雖然操作數是按照某種順序,就像減法一樣,你必須使用正確的操作數順序。

移位...有兩種,邏輯和算術。邏輯是最容易的,當你使用>>或< <時得到的結果是C。

從0x12開始,它是0b00010010。搬那個三個位置向左(0×12 < < 3)指

00010010 < our original number 0x12 
0010010x < shift left one bit location 
010010xx < shift left another bit location 
10010xxx < shift left a third bit location 

什麼位獲得「轉移」到空的位置,上面的x'es,變化的基礎上的操作。對於C編程它始終是零:

00010010 < our original number 0x12 
00100100 < shift left one bit location 
01001000 < shift left another bit location 
10010000 < shift left a third bit location 

但有時(通常每指令集支持旋轉和移位)還有其他方法轉移,差異有什麼位你轉移到做空位,並且有時候你轉移到最後的位並不總是會消失,有時你會將它保存在一個特殊的位持有者位置。

一些指令集只有一個位移意味着你編程的每個指令只能移動一位,所以上面是3條指令,一次一位。其他指令集(如arm)允許您只有一條指令,並在指令中指定要在該方向上移位多少位。所以左移位三個

mov r0,#0x12 
mov r3,r0,lsl#3 ; shift the contents of r0 3 bits to the left and store in r3 

您在證明LSR和ASR,邏輯右移和算術右移之間切換一下這個變(你會看到,有沒有ASL算術左移,因爲這使沒有意義,一些彙編程序將允許您使用asl指令,但將其編碼爲lsl)。

邏輯右移:

00010010 - our original number 0x12 
x0001001 - shifted right one bit 
xx000100 - shifted right another bit 
xxx00010 - shifted right another bit 

與在C存在,在零偏移版本,也就是邏輯右移,在零偏移

00010010 - our original number 0x12 
00001001 - shifted right one bit 
00000100 - shifted right another bit 
00000010 - shifted right another bit 

算術右移裝置保存「符號位」是什麼符號位?如果沒有的話,你也需要學習兩個補碼。基本上,如果你認爲位模式/值是一個二進制補碼,那麼最重要的位,即左邊的位是符號位。如果它是0,則數字是正數,1是負數。您可能已經注意到,左移1位的移位等於乘以2,右移與2除相同。0x12 >> 1 = 0x9,18 >> 1 = 9但是如果我們要移位一個減2到正確的一個,減2是0xFE使用字節或0b11111110。使用C風格邏輯右移0xFE >> 1 = 0x7F,或以十進制-2 >> 1 = 0x127。我們解決不了,在C在一個單一的操作,很遺憾,但在裝配,我們可以使用算術移位,假設你的指令集有一個,它的手臂確實

算術右移

s1100100 - our starting value s is the sign bit whatever that is 0 or 1 
ss110010 - one shift right 
sss11001 - another shift right 
ssss1100 - another shift right 

所以,如果符號位S是0的時候我們就開始,如果該號碼爲01100100,然後

01100100 - our starting value 
00110010 - one shift right 
00011001 - another shift right 
00001100 - another shift right 

但如果該標誌位一直是一個

11100100 - our starting value 
11110010 - one shift right 
11111001 - another shift right 
11111100 - another shift right 

我們可以解決0xFE的右邊移動一個:

11111110 - 0xFE a minus 2 in twos complement for a byte 
11111111 - shifted right one 

所以在僞代碼0xFE的ASR 1 = 0xFF時,-2 ASR 1 = -1。-2除以2 = -1

您需要自行讀取的最後一件事情與旋轉和/或結束時偏移的位相關。右移位移到數字的「結尾」,就像塊被滑動的桌子一樣,掉落的塊可能會進入「位桶」(以太,天堂或地獄,其中一個位當他們從這個世界消失時去死)。但是某些指令集中的某些指令會將該位置移位並將其置於進位標誌(在加法和減法中進行讀取),並不是因爲它必須是進位,而是因爲alu中的狀態位和進位位是有道理的。現在旋轉的是什麼,可以說你有一個8位的處理器,並且你旋轉了一位,位在Carry位的末端降落,AND另一端的位移是進位位手術前。基本上它是音樂椅子,有些人在椅子周圍走來走去,一個人站着,站着的人是坐着的人,坐在椅子上的人是坐在椅子上的人。爲什麼這有用?可以說我們有一個像愛特梅爾AVR這樣的8位處理器,但是想要做一個64位的轉換。 64位需要8位,8位寄存器,比如說我在這8個寄存器中有64位數字,我想要做一個64位左移一位。我將從最低有效字節開始,並執行一個lsl,它將零移入,但移出的位進入進位位。那麼下一個最重要的字節就是一個字節,向左旋轉一位,進入的位是從先前字節出來的位,並且出去的位進入進位位。我重複ROL指令其他字節,看着一個16位移位:

00100010 z0001000 - our original number 
00100010 z 0001000 - lsl the least significant byte, the ms bit z is in carry 
0100010z 00010000 - rotate left the most significant byte pulling the z bit from carry 

00100010z0001000 - if it had been a 16 bit register 
0100010z00010000 - a logical shift left on a 16 bit with a zero coming in on the left 

是什麼旋轉是,這就是爲什麼在組裝手冊困擾告訴你標誌修改什麼,當你執行邏輯運算。

+0

哇,你的回答給我留下了深刻的印象! – 2015-12-17 09:07:51

+0

這是一個非常好的答案!我們可以讓管理員保存這個嗎? – 71GA 2018-02-08 10:32:22

+0

@old_timer你可能知道爲什麼我在使用BIC語法時爲Thumb編譯過程中需要unshifted register - bic r0,r0,#0x3嗎?這仍然是從2007年的錯誤? https://gcc.gnu.org/bugzilla/show_bug.cgi?id=34436 – 71GA 2018-02-08 17:17:28

3

我會做第一個,那麼也許你可以嘗試使用類似的方法計算出的其餘部分:

/** LSL **/ 
mov r0, #1   ; r0 = 0000 0000 0000 0000 0000 0000 0000 0001 
mov r3, r0, LSL#10 ; r3 = r0 logically shifted left by 10 bit positions 
          = 0000 0000 0000 0000 0000 0100 0000 0000 
                ^  ^
                 +<<<<<<<<<<<+ 
                shift left 10 bits 

不過請注意,如果你還不明白布爾運算,如OR( (|),AND(&)等,那麼您將很難理解相應的ARM指令(ORRAND等)。

相關問題