2012-01-28 7 views
5

誰かが私のようにARMのビットシフトを私が5であると説明できますか?ビットシフトとビット演算子の概念を理解するのが難しいので、10進数以外のシステムを含むものについては、私は理解していません。誰かが私に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

真理値表は、2つの入力の左にある2つの数字と1つの出力、右に番号:

OR

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

左の2つの入力A及びBは、4つの可能な組み合わせを表します入力のうち、それ以上のものはリストではありません。

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がtrueの場合、それらの両方が真でなければならないことを意味します。それが上に存在するケースは1つだけです。

ここで、2進数の0x12と0x34を取ってください。小数点は18と52ですが、10進数についてはほとんど気にしません。バイナリ0x12は0b00010010、0x34は0b00110100です。アセンブリ言語でのANDやORやXORのようなビット演算子は、各オペランドから1ビットを取り出し、同じビット位置に結果を与えることを意味します。このようなものがある場所を追加するのではなく、それを運ぶことと同じです。

ので、我々はあなたがあなたの左手で開催されたタコスのうちの一口を取り、上記の真理値表を視覚化しようとしているようなあなたの頭がsidways傾けビット

0b00010010 0x12 
0b00110100 0x34 

をラインアップ。右の2ビットを見ると0と0、次の2ビットは1と0などとなります。私たちはOR演算をやってみたかった場合はAまたはBのどちらかが、その後、C trueの場合、ルールがあるので、結果は、真

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

右に傾いた頭、最下位ビット(ビットのものです数字の列)0または0 = 0のいずれも設定されていません。次の列(2列)1または0 = 1少なくとも1つは真です。そして、まあまあ

0x12を0x34のOR = 0x36または操作R2後

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

なりアームアセンブリで

に値0x36を保持するであろう。

今すぐことができますし、私たちの真理値表とルールAとBの両方を覚えてこれらの数字

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

が真である(1)を持っている私たちは、0と0が0で、右に私たちの頭を傾け、両方の本当ではない。検査によって1つの列のみが両方の入力を有し、16s列を有する。これは

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

今、私たちはBIC命令に着くだろうアームアセンブリでは0x12を0x34のAND = 0x10を

で私たちを残します。これは、bitwise clearの略です。ちょっと意味が分かります。腕の上のBicはaであり、bではない。ない別の真理値表であるが、唯一の1つの入力と一つだけの入力で1つの出力

ませ

a c 
0 1 
1 0 

は、我々は2つだけの選択肢0と1を持って、1は0が偽の真実です。 notは、そうでなければ、cが真であることを意味します。 aが真でないときはcが真、aが真のときは真ではない。基本的には反転します。 BICは何

は、2つの入力A、Bを持っている、操作は、c = Aであると、(B NOT)ので、そのための真理値表は次のようになります。

と(B NOT)

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

私はAND真理値表で始まり、次にbビットをNOTtedしました。ここでbはAND真理値表では0でした。私はそれを1としました。ここでbはAND真理値表の1で、0にしました。

0x12と0x34のbic演算は

です。
0b00010010 
    0b00110100 
BIC ========== 
    0b00000010 

なぜビットクリアと呼ばれますか?それを理解することで、使いやすくなります。真理値表を見て、第1と第2の入力を考えるならば。第2の入力bが0である場合、その出力自体は変更されていない。その真理値表または演算が行っていることは、どこでもbがAのビットをクリアまたはゼロに設定されているということです。したがって、数値が0x1234で、下位8ビットをゼロにしたい場合は、0x00FFでBICします。そして、あなたの次の質問は0xFF00と一緒にいないのです。 (AND真理値表を分析して、bが1の場合はそのままの値を保持し、bが0の場合は出力をゼロにする)を参照してください。 ARMは少なくとも伝統的に32ビットレジスタと固定32ビット命令セットを使用します。アームで

mov r0,#0x12 

8非零ビットに制限されている即値命令はどこでも数内でシフト、ビットにシフトに取得します。私は、値0x12345678のを持っていたし、下位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 

を行うことができますムーブと2つのorrsを使用していますが、余分なメモリサイクルをラムから読み出すmy_byte_maskを読み込むので、バイクのソリューションよりも多くのクロックサイクルを消費します。

または

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

この最後のものは悪いcompromizeないという。アームのドキュメントのmvnはビット単位ではなく、つまりrx = NOT(immediate)を意味することに注意してください。すぐそこは0xFFです。 NOT(0xFF)はすべてのビットを反転することを意味します。これは32ビットのレジスタで、これは0xFFFFFF00がNOT(0xFF)の結果であることを意味します。

が時々であるため、bicがARM命令セット内の場所を持つ理由は、bic命令の代わりに、bic命令を使用してマスク(mask = ANDはいくつかのビットをゼロにする)命令。

私は、ゼロという数字のビットを他のものだけを残して作る概念として、マスクという言葉を使用しました。あなたがOR真理値表を見れば、いつでもbが1、cが1であるならば、orringは他のものを残してビットを1にすると考えることができます。したがって、0x12345678または0x000000FFは0x123456FFオペランドが設定されます。はい、それはいつでも、真実は、OR真理値表に設定され、出力が設定されているが、これらのビット単位の操作を使用するときは、多くの時間をあなたは何かをしたい、ビット数を設定する残りの部分を変更せずに1に設定するか、残りの部分を変更せずに特定のビット数をゼロに設定するか、特定のビット数を除くすべてのビットをゼロにします。このように使用すると、操作したいオペランドが1つあり、全体のエフェクトが必要なものに基づいて2番目のオペランドを作成します。たとえば、Cの場合は下位バイトだけを残したい場合一つのパラメータアウト機能では、1つのパラメータを持っている:

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

〜と、とても32ビットの数値のための〜0xFFのは、その後、&手段を0xFFFFFF00を意味し、私たちは& 0xFFFFFF00を返さないことを意味します。 aは唯一の実数オペランドで、私たちがやりたい操作に基づいて2番目のものを考案しました。ほとんどのビット単位の操作で、命令のオペランドを入れ替えることができます。特定の順序で、減算のようにオペランドの正しい順序を使用する必要があります。

シフト...論理演算と算術演算の2種類があります。論理的には最も簡単で、>>または< <をC言語で使用すると得られるものです。

0x12で始まる0b00010010です。左(0x12を< < 3)3つの位置は空の場所、上記x'esに「にシフト」得るものビット

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

を意味シフト操作に基づいて変化します。 (通常は、すべての命令セットが回転だけでなく、シフトをサポートしている)がシフトする他の方法があるとの違いは、あなたがにシフト何ビットとしなければならない

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

しかし、時には:Cプログラミングのために、それは常にゼロであります空いている場所、そして時々あなたが最後からシフトしたビットは、時々あなたが特別なビットホルダーの場所にそれを保存するだけで消えません。

いくつかの命令セットは、プログラムする各命令に対して1つのビットシフトの意味しか持たないため、1ビットだけシフトすることができます。したがって、上記は3つの命令、1ビットずつです。アームのような他の命令セットでは、1つの命令を持つことができ、その方向にシフトしたいビット数を命令で指定します。それは作るためにあなたがにシフトするもののこの変化するがLSRとASRの間で実証されている3

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

の左シフト、論理右シフトと算術右シフト(あなたは何の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 

ARITHMETIC保存右手段をシフト"符号ビット"符号ビットは何ですか?あなたが持っていなければ学ばなければならない2つの補数になる。基本的には、ビットパターン/値を2の補数と見なした場合、左側の最上位ビットが符号ビットになります。 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は、私たちが始めたとき数は、その後

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

01100100だった場合、0だったが、その符号ビットが1

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

あなた自身で読み上げる必要がある最後のものは、回転や、最後からずれるビットに何が起こるかです。シフト右はlsbitはテーブルのスライドされているブロックのような数字の "オフ"にシフトされ、落ちるものはちょうど "ビットバケット"(エーテル、天国または地獄、これらの場所のいずれかのビット彼らがこの世界から消えると死ぬ)。しかし、いくつかの命令セットの命令の中には、そのビットがシフトされてキャリーフラグ(加算と減算で読み出される)に入れられるものがありますが、これは必ずしも桁上げではなく、aluおよびキャリービットちょっと意味があるものです。回転が何であるかは、あなたが8ビットプロセッサを搭載していて、1ビット回転したと言います。キャリービットの終わりの土地から落ちるビット、もう一方のビットシフトはキャリービット操作の前に。基本的にそれは音楽の椅子であり、ビットは椅子の周りを歩いていて、一人は立っていて、立っている人は桁上げのビットで、椅子の人々はレジスタのビットです。なぜこれはまったく役に立ちますか?たとえばAtmel AVRのような8ビットプロセッサがあったとしますが、64ビットシフトをしたいとします。 64ビットは8,8ビットのレジスタをとります。私はこれらの8つのレジスタに64ビットの番号があり、64ビットのシフトを1ビット残したいとします。私は最下位バイトから始め、0をシフトするLSLを実行しますが、シフトアウトするビットはキャリービットに入ります。次の最も重要なバイトは、私はロールを行い、左に1ビット回転し、入ってくるビットは前のバイトから出て行くビットで、出ていくビットはキャリービットに行く。

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 

回転をするためのものであり、組立マニュアルは、実行時にフラグが変更されている何を伝えるために気に理由があるものです:私は、16ビットのシフトを見て、他のバイトについてROL命令を繰り返し論理演算。

+0

うわー、あなたの答えは私に印象づけました! –

+0

これは本当に良い答えです!管理者にこれを保存するよう依頼できますか? – 71GA

+0

@old_timer BIC構文を使用してThumbのコンパイル時にbic r0、r0、#0x3が必要な理由が分かりますか?これはまだ2007年のバグですか? https://gcc.gnu.org/bugzilla/show_bug.cgi?id=34436 – 71GA

3

私は最初のものをやると、多分あなたは、同様のアプローチを使用して残りを試してみて、うまくすることができます(あなたはまだ、このようなORなどのブール演算を理解していない場合ということが

/** 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 

注意|)、AND(&)など、対応するARM命令(ORRANDなど)を理解するのは難しいでしょう。

関連する問題