2012-01-28 2 views
5

내가 5 인 것처럼 ARM 비트 시프트를 설명 할 수 있습니까? 비트 소수점과 비트 연산자의 개념을 이해하는 것이 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

진리표 개의 입력과 왼쪽 및 하나 개의 출력에 대한 두 숫자는 오른쪽에 번호 :

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가 true입니다.

AND

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

그리고 수단 모두 A와 B 둘 다 진실 후 C가 참일 경우에 해당해야한다. 위에 존재하는 경우가 하나뿐입니다.

이제 2 진수 0x12와 0x34를 취합니다. 십진수는 18과 52이지만 십진수는별로 신경 쓰지 않습니다. 0x12는 0b00010010이고 0x34는 0b00110100입니다. 어셈블리 언어에서 AND, OR 및 XOR과 같은 비트 연산자는 각 피연산자에서 1 비트를 가져 와서 동일한 비트 위치에서 결과를 얻는다는 것을 의미합니다. 그게 당신이 이것과 같은 것을 가지고있는 곳을 더하는 것과 같지 않습니다.

그래서 우리는 비트 당신이 당신의 왼쪽 손에 개최 타코에서 물기를 가지고 위의 진리표를 시각화하려고처럼

0b00010010 0x12 
0b00110100 0x34 

그래서 머리 sidways을 기울를 줄. 오른쪽의 두 비트를 보면 0과 0, 다음 두 비트는 1과 0 등입니다.우리는 OR 연산을 수행하기를 원한다면 중 A 또는 B가 다음에 해당하는 결과, C, 사람의 오른쪽으로 기울어

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

머리, 최하위 비트 (비트에 해당하는 경우 그래서, 규칙은 숫자의 열) 0 또는 0 = 0, 둘 다 설정되지 않습니다. 다음 열 (2 열) 1 또는 0 = 1 적어도 하나 이상이 참입니다. 그래서 이렇게

0x12를 OR = 0x34 0x36

아암 어셈블리에 값 0x36을 길게 것 또는 동작 R2 후

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

을 것이라고.

지금 할 수와 (1)이 우리가 올바른 0으로 우리의 머리를 기울 그 숫자는

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

우리의 진실 테이블을 기억하고 규칙 A와 B 모두에 해당해야 0 0, 둘 다 사실이 아닙니다. 검사에 의해 하나의 열에는 16s 열의 1이있는 두 입력이 있습니다. 이

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

지금 우리가 BIC 명령어에 도착 될 것이라고 ARM 어셈블리에서 0x12를 및 0x34 = 0x10을

으로 우리를 떠난다. 어느 쪽이 bitwise clear의 약자입니다. 팔에있는 Bic은 a가 아니라 b와 함께있다. 아니 다른 진리표이지만, 단 하나의 입력과 하나의 입력을 하나 개의 출력

하지

a c 
0 1 
1 0 

우리는 두 가지 선택 0과 1을, 1은 0이 거짓 사실이다. not는 then이 c가 참이 아님을 의미합니다. a가 진실하지 않을 때 c는 진실하다, a가 진실하다 c는 진실하지 않다. 기본적으로 반전됩니다. BIC가 무엇

는 두 개의 입력 A와 B가있다, 작업은 C = A이다와 (b NOT) 그래서 대한 진리표는 다음과 같습니다

A와 (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 

왜 비트 클리어라고합니까? 이를 이해하면 훨씬 쉽게 사용할 수 있습니다. 당신이 진리표를보고 첫 번째와 두 번째 입력을 생각한다면. 두 번째 입력 (input)이 1이면 출력은 0입니다. 두 번째 입력 (b)이 0이면 출력은 자체가 수정되지 않습니다. 그 진리표 나 연산이하는 일은 어디서나 b가 A에있는 비트를 0으로 만들거나 0으로 설정하는 것입니다. 따라서 숫자가 0x1234이고 하위 8 비트가 0 인 경우 BIC를 0x00FF로 설정하면됩니다. 그리고 다음 질문은 왜 0xFF00이 아닌가하는 것입니다. (AND 진리표를 분석하여 b가 1이면 값을 그대로 유지하고 b는 0이면 출력을 0으로 만듭니다.) ARM은 적어도 전통적으로 32 비트 레지스터와 고정 된 32 비트 명령어 세트를 사용합니다.즉각적인 지시

팔은 숫자 내에서 아무 곳이나 이동하여 8 비트로 제한되어 있습니다. 약간의 변화가있을 것입니다. 그래서 만약 내가 값 0x12345678을했고이

; 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 

에 비해 내가 할 수있는 하위 8 개 비트를 제로로 원 이동과 두 개의 orrs를 사용하지만 bic 솔루션보다 더 많은 클럭 사이클을 소모합니다. 램에서 my_byte_mask를 읽는 추가 메모리 사이클을 구울 수 있기 때문에 시간이 걸릴 수 있습니다.

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

나쁜 compromize되는이 마지막

또는

. ARM 문서의 mvn은 bitwise 즉각적이 아니므로 rx = NOT (immediate)을 의미합니다. 즉각적인 것은 0xFF입니다. NOT (0xFF)은 모든 비트를 반전하는 것을 의미합니다. 32 비트 레지스터이므로 0xFFFFFF00은 NOT (0xFF)의 결과이며, 이는 r1이 도달하기 전의 것입니다. BIC는 ARM 명령어 세트에서 발생 이유를 때때로이 마스크 적은 명령들 또는 클럭 사이클이 소요 때문에

그래서 즉, (마스크 = 약간의 비트 0을 만들기 위해 사용) 대신의 BIC 명령어를 사용하여 교수.

나는 마스크를 사용하여 숫자 0의 비트를 다른 것만 남겨 두는 개념으로 사용했습니다. Orring은 다른 사람을 혼자 남겨두고 숫자 1의 비트를 만드는 것으로 생각할 수 있습니다. b가 1이면 OR 진리표를보고 1이면 c가 1입니다. 따라서 0x12345678 또는 0x000000FF는 두 번째 비트를 0x123456FF로 만듭니다 피연산자가 설정됩니다. 그렇습니다. 언제든지 OR 진리 테이블에 언제든지 값이 설정되면 출력이 설정되지만, 비트 연산을 사용할 때 많은 것을 할 수 있습니다. 하나의 피연산자를 사용하여 특정 비트 수를 설정하고 싶습니다. 하나를 나머지를 수정하지 않고 나머지 비트를 0으로 설정하거나 나머지를 수정하지 않고 특정 비트 수를 제외한 모든 비트를 0으로 만듭니다. 그런 식으로 사용하면 하나의 피연산자가 들어오고, 나머지 피연산자는 전체 효과를 원한다면 만들 수 있습니다. 예를 들어 C에서 하위 바이트 만 유지하려는 경우 하나 개의 매개 변수 밖으로 기능에서 하나 개의 매개 변수가 있습니다

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

그래서 ~ 0xFF로는, 32 개 비트 번호를 0xFFFFFF00에게 다음 & 수단을 의미하지 의미 ~ AND, 그래서 우리는 & 0xFFFFFF00을 반환합니다. a가 들어오는 유일한 실제 피연산자였습니다. 우리가하고 싶은 작업에 따라 두 번째를 발명했습니다 ... 대부분의 비트 연산은 명령에서 피연산자를 바꿀 수 있으며 모든 것이 괜찮습니다. 피연산자는 특정 순서로, 빼기처럼 피연산자의 올바른 순서를 사용해야합니다.

이동 ... 논리 연산 2 가지가 있습니다. 논리가 가장 쉽고 >> 또는 < <을 사용할 때 얻을 수 있습니다.

0x12로 시작하는 0b00010010입니다.좌측 (0x12를 < < 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는 조작에 기초하여 변화한다. 이 이동하는 다른 방법이 있고 차이가 당신이로 이동 비트 것과해야 할 (일반적으로 모든 명령어 세트가 변화뿐만 아니라 회전 지원) 때때로

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 프로그래밍을 위해 항상 제로입니다 빈 자리, 그리고 때로는 당신이 끝에서 벗어난 비트가 항상 사라지는 경우가 있습니다. 특별한 비트 홀더 위치에 저장하는 경우도 있습니다.

일부 명령어 세트는 프로그래밍하는 각 명령어에 대해 단일 비트 시프트 의미 만 가지므로 한 비트 만 이동할 수 있으므로 위의 명령어는 한 번에 한 비트 씩 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 명령어를 사용할 수 있지만 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 

산술 오른쪽 수단 보존 이동 제로로 이동한다 "부호 비트"부호 비트는 무엇입니까? 당신이 가지고 있지 않다면 당신은 또한 배울 필요가있는 2의 보충 수를 얻습니다. 근본적으로 비트 패턴/값을 2의 보수로 간주하면 가장 중요한 비트, 왼쪽에있는 비트는 부호 비트입니다. 숫자가 0이면 숫자가 양수이고 숫자가 1이면 음수입니다. 한 비트 남은 쉬프트는 2를 곱한 것과 같고 쉬프트 쉬프트는 2로 나눈 것과 같습니다. 0x12 >> 1 = 0x9, 18 >> 1 = 9 그러나 우리가 쉬프트했다면 어떨까요? 마이너스 2를 오른쪽으로, 마이너스 2는 바이트를 사용하는 0xFE 또는 0b11111110입니다. C 스타일 논리 시프트 오른쪽 0xFE >> 1 = 0x7F 또는 10 진수 -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 

그렇다면 않는 일을 가지고 부호 비트들 우리가 시작했을 때 수는 다음

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

01100100 인 경우, 0했지만 그 부호 비트는 하나

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가 테이블의 미끄러지는 블록처럼 숫자의 "끝에서 벗어나"이동하고 떨어져 나가는 것은 비트 버킷 (에테르, 천국 또는 지옥,이 장소들 중 하나 인 비트 그들이이 세상에서 사라지면 죽어라.) 그러나 일부 명령어 세트의 일부 명령어는이 비트가 이동되어 Carry 플래그에 넣고 (더하기 및 빼기에서 읽음), 반드시 carry가 아니기 때문에가 아니라 alu 및 Carry 비트에 상태 비트가 있으므로 다소 의미가있는 것입니다. 이제 회전이 무엇입니까, 당신은 8 비트 프로세서가 있다고 말하면서 1 비트를 회전 시켰습니다. 캐리 비트의 끝 부분에서 떨어지는 비트 반대편에서 비트가 이동하는 것은 캐리 비트 수술 전에. 근본적으로 그것은 음악 의자 다, 작은 조각은 한 사람이 서있는 채로 의자 주위를 걷고있다, 서있는 사람은 나르는 작은 조각이다, 의자의 사람은 계산대의 작은 조각이다. 왜 이것이 유용할까요? 예를 들어 Atmel AVR과 같은 8 비트 프로세서가 있었지만 64 비트 시프트를 원했습니다. 64 비트는 8 비트, 8 비트, 레지스터를가집니다, 나는이 8 개의 레지스터에 64 비트 수를 가지고 있고 64 비트 쉬프트를 1 비트 남기고 싶다고 말합니다. 내가 가장 중요하지 않은 바이트로 시작하고 0을 시프트하는 LSL을 수행 할 것이지만 밖으로 이동하는 비트는 캐리 비트로 들어간다. 다음 가장 중요한 바이트는 rol, 왼쪽으로 한 비트 회전, 들어오는 비트는 이전 바이트에서 나가는 비트, 나가는 비트는 캐리 비트로 이동합니다. 나는 16 비트 이동을보고, 다른 바이트의 ROL 명령을 반복 :

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

와우, 너의 대답이 나를 감동 시켰어! –

+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 명령어 (ORR, AND 등)를 이해하는 데 어려움을 겪습니다.

관련 문제