2012-01-28 23 views
5

Może ktoś wyjaśnić ARM-bitowych przesunięcia do mnie jak pięć? mam bardzo słabe zrozumienie wszystkiego, co wiąże się non-dziesiętne systemy numeryczne więc zrozumienie pojęć i operatorów bitowych przesunięcia bitowe jest dla mnie trudne.Czy ktoś może mi wyjaśnić operacje bitowe ARM?

Co zrobi każdy z poniższych przypadków i dlaczego (co skończy się w R3 i co dzieje się za kulisami na poziomie bitów)?

/** 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. Nie tłumacz tego w kategoriach operatorów C-bitowych. Nie wiem, co robią albo (z >>, <<, |, & nich).

Odpowiedz

15

tablica prawdy, dwa wejścia, dwie cyfry po lewej i jedno wyjście, liczba po prawej:

LUB

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

lewej dwa wejścia A i B oznaczają cztery możliwe kombinacje danych wejściowych, nie więcej nie mniej niż ta lista.

Rozważmy 1 oznacza prawdziwe i 0 oznacza fałsz. A słowo OR w tym przypadku oznacza, że ​​jeśli OR b jest prawdziwe, wówczas c jest prawdziwe. Jak widać w tabeli, w poziomie, jeśli a lub b jest prawdziwe, wówczas c jest prawdziwe.

I

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

I oznacza, że ​​oba muszą być prawdziwe, jeśli A i B są zarówno prawdziwe wtedy c jest prawdą. Jest tylko jeden przypadek, w którym istnieje powyżej.

Teraz weź dwa bajty 0x12 i 0x34, który w systemie dziesiętnym mają 18 i 52, ale my naprawdę nie obchodzi wiele o przecinku. zależy nam na binarnym 0x12 jest 0b00010010, a 0x34 jest 0b00110100. Operatory bitowe, takie jak AND i OR oraz XOR w języku asemblerowym, oznaczają, że bierze się jeden bit z każdego operandu, co daje wynik w tej samej lokalizacji bitowej. To nie jest jak dodawanie, gdzie masz takie rzeczy plus to, że równa się bla, nieść jeden.

więc wyrównać bity

0b00010010 0x12 
0b00110100 0x34 

Więc przechylić sidways głowę jak idziesz do gryza z taco, która odbyła się w lewej ręce i wizualizacji powyżej tabeli prawdy. Jeśli spojrzymy na dwa bity po prawej, to 0 i 0, kolejne dwa bity to 1 i 0 i tak dalej.Więc jeśli chcemy wykonać operację OR, regułą jest, jeśli A lub B jest prawdziwe wtedy c, w rezultacie, jest prawdą

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

Głowa przechylona w prawo, najmniej znaczący bit (bit w tych kolumna w liczbie) 0 lub 0 = 0, żadna z nich nie jest ustawiona. następna kolumna (kolumna 2) 1 lub 0 = 1 co najmniej jedna jest prawdziwa. i tak dalej, tak

I 0x34 0x12 0x36 =

W zespole ramienia byłoby

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

po lub R2 operacja przyjmować wartość 0x36.

Teraz pozwala i te numery

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

Pamiętając naszą tablicę prawdy i zasada zarówno A i B muszą być prawdziwe (a 1) możemy przechylić naszą głowę w prawo, 0 i 0 wynosi 0, zarówno nie są prawdziwe. i przez inspekcję tylko jedna kolumna ma oba wejścia z kolumną 1, 16s. to pozostawia nam 0x12 I 0x34 = 0x10

W zespole ramienia że byłoby

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

Teraz mamy do dyspozycji BIC. Co oznacza bitowe jasne, co, mam nadzieję, będzie miało sens. Bic na ramieniu jest aed z nie b. Nie jest kolejna tabela prawdy, ale tylko jedno wejście i jedno wyjście

NIE

a c 
0 1 
1 0 

Z jednym tylko wejściem mamy tylko dwie możliwości 0 i 1, 1 jest prawdą 0 jest fałszywe. NOT oznacza, że ​​jeśli nie, wówczas c jest prawdą. kiedy a nie jest prawdą c jest prawdą, gdy a jest prawdziwe c nie jest prawdą. Zasadniczo odwraca się.

Co robi bic jest mieć dwa wejścia A i B, operacja jest c = a I (nie b) tak tabeli prawdy dla że byłoby:

a AND (NOT b)

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

Zacząłem od tabeli ORAZ, a następnie Zanotowałem bity, gdzie b było 0 w tabeli ORAZ I zrobiłem to 1, gdzie b było 1 w tabeli ORAZ I zrobiłem to 0.

Tak więc operacja bic na 0x12 i 0x34 jest

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

Dlaczego jest to nazywane bit clear? Zrozumienie, dzięki czemu jest znacznie łatwiejsze w użyciu. Jeśli spojrzysz na tabelę prawdy i myślisz o pierwszym i drugim wejściu. Gdzie drugie, b, wejście jest 1, wyjście wynosi 0. gdzie drugie wejście, b, jest 0, wyjście jest samo w sobie niezmodyfikowane. To, co robi tabela lub operacja prawdy, oznacza, że ​​gdziekolwiek b jest ustawione jednoznacznie lub zeruje te bity w A. Więc jeśli mam numer 0x1234 i chcę zerować niższe 8 bitów, chciałbym BIC z 0x00FF. I następne pytanie brzmi: dlaczego nie AND to z 0xFF00? (przeanalizuj tabelę ORAZ i zobacz, że gdziekolwiek b jest a 1, zachowujesz wartość taką jaka jest, a gdziekolwiek b jest 0, zerujesz wyjście). ARM używa 32-bitowych rejestrów i ustalonego 32-bitowego zestawu instrukcji, przynajmniej tradycyjnie.Bezpośrednie instrukcje

mov r0,#0x12 

W ramieniu są ograniczone do 8 bitów niezerowych przesunięte w dowolnym miejscu numeru, dostanie się do zmieniających się trochę. Więc gdybym miał wartość 0x12345678 i chciał wyzerować dolne 8 bitów mogłem zrobić to

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

lub

; 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 

lub

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

który nie jest straszne, w porównaniu do za pomocą ruchu i dwóch orr, ale nadal wypala więcej cykli zegara niż rozwiązanie bic, ponieważ wypalasz dodatkowy cykl pamięci czytając my_byte_mask z pamięci RAM, co może trochę potrwać.

lub

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

Ta ostatnia to nie jest zły compromize. zauważ, że mvn w dokumentacji ramienia nie jest bitowe, a nie natychmiastowe, co oznacza, że ​​rx = NOT (natychmiastowy). Bezpośredni tutaj jest 0xFF. NOT (0xFF) oznacza odwrócenie wszystkich bitów, jest to rejestr 32-bitowy, który zamierzamy więc oznacza, że ​​0xFFFFFF00 jest wynikiem NOT (0xFF) i to jest to, co rejestru r1 dostaje, przed wykonaniem i.

Dlatego właśnie bic ma miejsce w zestawie instrukcji ARM, ponieważ czasami wymaga mniej instrukcji lub cykli zegara do maskowania (maska ​​= I używane do zrobienia zer) przy użyciu instrukcji bic zamiast instrukcja.

Użyłem słowa maska ​​jako koncepcja, aby bity w liczbie zero pozostawiając innych w spokoju. Orring można uważać za robiący bitów w numerze jeden, pozostawiając innych w spokoju, jeśli spojrzysz na tabelę prawdy OR za każdym razem, gdy b jest 1, to c jest 1. Więc 0x12345678 LUB 0x000000FF daje 0x123456FF bity w drugim operand są ustawione. Tak, prawdą jest również to, że za każdym razem, gdy ustawiona jest wartość w tabeli prawdy LUB, wyjście jest ustawione, ale dużo czasu, gdy używasz tych operacji bitowych, że masz jeden operand, do którego chcesz coś zrobić, ustaw określoną liczbę bitów do jednego bez modyfikowania reszty lub ustawić określoną liczbę bitów na zero bez modyfikowania reszty lub chcesz wyzerować wszystkie bity oprócz pewnej liczby bitów. Użyty w ten sposób masz jeden operand, w którym chcesz operować, i tworzysz drugi operand na podstawie tego, jaki chcesz efekt, na przykład w C, jeśli chcemy zachować tylko niższy bajt, który możemy posiada jeden parametr w funkcji, jeden z parametrów:

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

~ oznacza nie tak ~ 0xFF, dla 32-bitowych liczb oznacza 0xFFFFFF00 następnie & środków i tak wracamy do & 0xFFFFFF00. a był jedynym prawdziwym operandem wchodzącym i wymyśliliśmy drugi na podstawie operacji, którą chcieliśmy wykonać ... Większość bitowych operacji można zamienić operandami w instrukcji i wszystko okazuje się w porządku, instrukcje takie jak ARM, choć operandy są w pewnej kolejności, podobnie jak odejmowanie, musisz użyć poprawnej kolejności operandów.

Przeniesienie ... Istnieją dwa rodzaje, logiczne i arytmetyczne. logiczne jest najłatwiejsze i można je uzyskać, używając >> lub < < w C.

Zacznij od 0x12, która jest 0b00010010.Przesunięcie to trzy lokalizacje w lewo (0x12 < < 3) Oznacza

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

Co bity dostać „przesunięte” do pustych miejsc, powyższe x'es, różni się w zależności od operacji. Do programowania C jest zawsze zerami:

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

Ale czasami (zazwyczaj każdy zestaw instrukcji obsługuje obracania, a także przesunięcie) istnieją inne sposoby, aby w systemie zmianowym oraz różnice mają do czynienia z co bit Ci przejście w puste miejsce, a czasami nawet kawałek, który przesunąłeś z końca, nie zawsze po prostu znika, czasami zapisujesz to w specjalnej lokalizacji uchwytu na bity.

Niektóre zestawy instrukcji mają tylko znaczenie przesunięcia bitowego dla każdej zaprogramowanej instrukcji, którą można przesunąć tylko o jeden bit, więc powyższe instrukcje będą 3 instrukcjami, po jednym bitem na raz. Inne zestawy instrukcji, takie jak ramię, pozwalają na uzyskanie pojedynczej instrukcji, a ty w instrukcji określasz, ile bitów chcesz przesunąć w tym kierunku. więc przesunięcie w lewo trzy

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

Ten różnym od czego przesunięcie w wykazano między LSR i ASR, logicznego prawa zmianowym oraz arytmetycznej prawej zmianowym (widać, że nie ma npm, arytmetyczne przesunięcie w lewo, ponieważ sprawia, że nie ma sensu, niektóre asemblery pozwolą ci użyć instrukcji asl, ale zakodować ją jako lsl).

logicznym prawy shift:

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

Jak w C istnieje wersja, która przesuwa się zerami, to jest logiczne prawo zmiany, przesunięcia w zerami

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

arytmetyka przesunąć prawy środki utrzymania "bit znaku" jaki jest bit znaku? to daje dwie dodatkowe liczby, których również musisz się nauczyć, jeśli tego nie zrobiłeś. Zasadniczo, jeśli wziąłeś pod uwagę bitowy wzór/wartość jako liczbę uzupełnień dwójek, to najbardziej znaczącym bitem, po lewej, jest bit znaku. jeśli jest 0, liczba jest dodatnia i 1 liczba jest ujemna. Być może zauważyłeś, że przesunięcie o jeden bit jest takie samo, jak pomnożenie przez 2, a przesunięcie w prawo to to samo, co dzielenie przez 2. 0x12 >> 1 = 0x9, 18 >> 1 = 9, ale co by było, gdybyśmy przesunęli a minus 2 na prawo, minus dwa to 0xFE przy użyciu bajtów lub 0b11111110. za pomocą przesunięcia logicznego w stylu C w prawo 0xFE >> 1 = 0x7F, lub w systemie dziesiętnym -2 >> 1 = 0x127. Nie możemy rozwiązać to w C w jednej operacji, niestety, ale w zespole możemy za pomocą arytmetycznego przesunięcia, zakładając, że zestaw instrukcji ma jedną, której ramię robi

arytmetyka przesunięcie w prawo

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 

Więc jeśli bit znaku s było 0, kiedy zaczynaliśmy, jeśli liczba była 01100100 następnie

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

ale jeśli bit znaku był jeden

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

I można rozwiązać 0xFE przesuwany w prawo o jedną:

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

więc w pseudokodzie 0xFE ASR 1 = 0xFF, -2 ASR 1 = 1.-2 podzielone przez 2 = -1

Ostatnią rzeczą, którą musisz przeczytać na własną rękę, jest rotacja i/lub to, co dzieje się z bitem przesuniętym od końca. przesunięcie w prawo, lsbit przesuwa się "z końca" liczby, tak jak bloki są przesuwane ze stołu, a ten, który odpadnie, może po prostu przejść do "wiadra bitów" (eteru, nieba lub piekła, jednego z tych miejsc, gdzie bitów idź na śmierć, gdy znikną z tego świata). Jednak niektóre instrukcje w niektórych zestawach instrukcji przejmą ten bit i zostaną przeniesione do flagi Carry (odczytaj przy dodawaniu i odejmowaniu), nie dlatego, że jest to konieczne, ale dlatego, że istnieją aliasy statusu w alu i klucz Carry to taki, który ma sens. Teraz co to jest rotacja, powiedzmy, że masz 8-bitowy procesor i obróciłeś jeden bit, a bit spadł z krańców końcowych w bitwie Carry, i przesunięcie bitów z drugiej strony jest tym, co było w bicie nośnym przed operacją. Zasadniczo są to krzesła muzyczne, bity chodzą wokół krzeseł z jedną osobą stojącą, osoba stojąca to kawałek, ludzie w fotelach są drobiazgami w rejestrze. Dlaczego w ogóle jest to przydatne? powiedzmy, że mamy 8-bitowy procesor, na przykład Atmel AVR, ale chcieliśmy zrobić 64-bitową zmianę. 64 bity zajmuje 8, 8 bitów, rejestry, powiedzmy, że mam mój 64-bitowy numer w tych 8 rejestrach i chcę zrobić przesunięcie 64-bitowe w lewo o jeden bit. Zacznę od najmniej znaczącego bajtu i zrobię lsl, który przesuwa zero, ale przesunięcie bitu przechodzi do bitu przenoszenia. następnie następny najbardziej znaczący bajt robię rolkę, obracam lewy jeden bit, a bit przychodzi, to kawałek wychodzący z poprzedniego bajtu, a bit wychodzący przechodzi do bitu przenoszenia. Powtarzam instrukcji ROL dla pozostałych bajtów, patrząc na przesunięcie 16 bitowe:

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 

To, co obraca się na i dlatego instrukcja montażu przeszkadza ci powiedzieć co flagi są modyfikowane podczas wykonywania operacja logiczna.

+0

Wow, twoja odpowiedź zaimponowała mi! –

+0

To naprawdę dobra odpowiedź! Czy możemy poprosić administratora o zapisanie tego? – 71GA

+0

@old_timer Czy mógłbyś wiedzieć, dlaczego wymagany jest rejestr unshifted - bic r0, r0, # 0x3 podczas kompilacji dla Thumb kiedy używam twojej składni BIC? Czy to nadal jest błąd z 2007 roku? https://gc.gnu.org/bugzilla/show_bug.cgi?id=34436 – 71GA

3

zrobię pierwszy z nich, a następnie być może można spróbować wypracować resztę stosując podobne podejście:

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

Należy jednak pamiętać, że jeśli jeszcze nie rozumieją operacji logicznych, takich jak OR (|) i (&), etc, to będziesz mieć trudności ze zrozumieniem odpowiednie instrukcje ARM (ORR, AND, etc).

Powiązane problemy