2012-01-28 7 views
5

Qualcuno può spiegare ARM bit turni a me come se fossi a cinque? ho una scarsa comprensione di tutto ciò che comporta sistemi di numerazione non decimali in modo da comprendere i concetti di turni di bit e operatori bit a bit è difficile per me.Qualcuno può spiegare a me le operazioni di bit bit ARM?

Cosa farebbero ciascuno dei seguenti casi e perché (cosa finirebbe nel R3 e cosa succede dietro le quinte a livello di bit)?

/** 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. Non spiegarlo in termini di operatori bit a bit C. Non so quello che fanno sia (i >>, <<, |, & quelli).

risposta

15

tabelle di verità, due ingressi, i due numeri sulla sinistra ed un'uscita, il numero a destra:

O

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

due ingressi sinistra A e B rappresentano i quattro combinazioni possibili di input, né più né meno che è la lista.

consideri un 1 a significare veri e 0 per falso. E la parola OR in questo caso significa che se OR è vero allora c è vero. E come vedi nella tabella, orizzontalmente se a o b è vero allora c è vero.

E

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

E significa che entrambi devono essere vero se A e B sono entrambe vere, allora c è vero. C'è solo un caso in cui esiste sopra.

Ora prendete due byte 0x12 e 0x34, che in decimali sono 18 e 52, ma abbiamo davvero non importa molto di decimali. ci preoccupiamo 0x12 binario è 0b00010010 e 0x34 è 0b00110100. Gli operatori bit a bit come AND e OR e XOR in linguaggio assembly significa che si prende un po 'da ogni operando e che dà il risultato nella stessa posizione bit. Non è come aggiungere dove si hanno cose come questa in più che equivale a blah portare l'uno.

così siamo in fila i bit

0b00010010 0x12 
0b00110100 0x34 

Quindi inclinare la testa sidways come si sta andando a prendere un morso di un taco tenuto con la mano sinistra e visualizzare la tabella di verità di cui sopra. Se guardiamo i due bit sulla destra sono 0 e 0, i prossimi due bit sono 1 e 0, e così via.Quindi, se volessimo fare un'operazione OR, la regola è che se A o B è vero allora c, il risultato, è vero

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

testa inclinata verso destra, bit meno significativo (il bit in quelli colonna nel numero) 0 o 0 = 0, nessuno dei due è impostato. colonna successiva (la colonna twos) 1 o 0 = 1 almeno una è vera. e così via in modo

0x12 OR 0x34 = 0x36

Nel complesso di braccio che sarebbe

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

dopo l'operazione o r2 ostacolare il valore 0x36.

Ora immobili in quei numeri

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

Ricordando la nostra tabella di verità e dello Stato sia A che B deve essere vero (un 1) abbiamo inclinare la testa verso destra, 0 e 0 è 0, sia non sono veri e tramite l'ispezione solo una colonna ha entrambi gli input con una colonna 1, la 16s. Questo ci lascia con 0x12 E 0x34 = 0x10

Nel gruppo del braccio che sarebbe

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

Ora arriviamo al istruzioni BIC. Che sta per bitwise chiaro, che si spera avrà un senso in un po '. Bic sul braccio è un ande con non b. Non è un'altra tabella di verità, ma solo un ingresso e un'uscita

NON

a c 
0 1 
1 0 

Con un solo ingresso abbiamo solo due scelte 0 e 1, 1 vale 0 è falso. NON significa se non un allora c è vero. quando a non è vero c è vero, quando a è vero c non è vero. Fondamentalmente inverte.

Quello che il BIC fa è avere due ingressi A e B, l'operazione è c = a AND (NOT B) in modo che la tabella di verità per questo sarebbe:

un AND (NOT b)

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

Ho iniziato con la tabella di verità AND, quindi ho aggiunto i bit b, dove b era uno 0 nella tabella di verità AND l'ho creato a 1 dove b era un 1 nella tabella di verità AND l'ho reso uno 0.

Quindi l'operazione bic su 0x12 e 0x34 è

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

Perché si chiama bit clear? Capire che lo rende molto più facile da usare. Se guardi la tabella della verità e pensi al primo e al secondo input. Dove il secondo, b, input è un 1, l'uscita è 0. dove il secondo input, b, è uno 0, l'output è a se stesso non modificato. Quindi, ciò che sta facendo questa tabella di verità o operazione è dire ovunque b è impostato o azzerare quei bit in A. Quindi se ho il numero 0x1234 e voglio azzerare gli 8 bit più bassi, vorrei BIC che con 0x00FF. E la tua prossima domanda è: perché no? E con 0xFF00? (analizza la tabella AND verità e vedi che dovunque b è un 1 mantieni il valore così com'è, e dovunque b è uno 0 azzeri l'output). L'ARM utilizza registri a 32 bit e un set di istruzioni a 32 bit fisso, almeno per tradizione.Le istruzioni immediate

mov r0,#0x12 

Nel braccio sono limitati a 8 bit non zero spostati ovunque all'interno del numero, si arriva a spostare in un po '. Quindi, se ho avuto la 0x12345678 valore e la voglia di azzerare gli 8 bit inferiori avrei potuto fare questo

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

o

; 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 

o

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

che non è orribile, rispetto ai utilizzando una mossa e due orrs, ma continua a bruciare più cicli di clock rispetto alla soluzione bic perché si brucia il ciclo di memoria extra leggendo my_byte_mask da ram, che può richiedere un po 'di tempo.

o

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

Quest'ultimo non essendo un cattivo penalizzare. nota che mvn nella documentazione del braccio è bit a bit non immediato, che significa rx = NOT (immediato). L'immediato qui è 0xFF. NOT (0xFF) significa invertire tutti i bit, è un registro a 32 bit che stiamo andando a significare che 0xFFFFFF00 è il risultato di NOT (0xFF) e che è ciò che ottiene il registro r1, prima di fare il e.

così è per questo bic ha un posto nel set di istruzioni ARM, perché volte ci vuole un minor numero di istruzioni o cicli di clock per mascherare (maschera = e usato per fare alcuni bit zeri) utilizzando l'istruzione bic al posto del e istruzioni.

Ho usato la parola maschera come un concetto per creare bit in un numero zero lasciando gli altri soli. orring può essere pensato come fare bit in un numero uno lasciando gli altri da soli, se si guarda la tabella di verità OR ogni volta che b è un 1 allora c è un 1. Quindi 0x12345678 OR 0x000000FF restituisce 0x123456FF i bit nel secondo gli operandi sono impostati. Sì, è anche vero che ogni volta che viene impostato nella tabella di verità OR l'output viene impostato, ma molto tempo quando si usano queste operazioni bit a bit si ha un operando a cui si vuole fare qualcosa, impostare un certo numero di bit a uno senza modificare il resto o impostare un certo numero di bit a zero senza modificare il resto o si desidera azzerare tutti i bit tranne un certo numero di bit. Quando viene utilizzato in questo modo si ha un operando in cui è ciò su cui si vuole operare e si crea il secondo operando in base a ciò che si desidera sia l'effetto complessivo, ad esempio in C se si desidera mantenere solo il byte inferiore che potremmo avere un un parametro in, un parametro out funzione:

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

~ mezzo che non sia così ~ 0xFF, per i numeri a 32 bit significa 0xffffff00 poi & mezzi e, così torniamo un & 0xffffff00. a era l'unico vero operando in arrivo e abbiamo inventato il secondo in base all'operazione che volevamo fare ... La maggior parte delle operazioni bit a bit è possibile scambiare gli operandi nell'istruzione e tutto si risolve, istruzioni come il braccio di ARM anche se gli operandi sono in un certo ordine, proprio come una sottrazione devi usare l'ordine corretto degli operandi.

Spostamento ... ci sono due tipi, logico e aritmetico. logico è più semplice ed è quello che ottieni quando usi >> o < < in C.

Inizia con 0x12 che è 0b00010010.Spostando che tre posizioni a sinistra (0x12 < < 3) significa

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

Nei bit ottenere "spostato in" alle posizioni vuote, le x'es sopra, varia in funzione della operazione. Per la programmazione C è sempre zeri:

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

Ma a volte (di solito ogni set di istruzioni supporta una rotazione così come un turno di lavoro) ci sono altri modi per spostare e le differenze hanno a che fare con quello che po 'si sposta in punto vuoto, e anche a volte il bit che hai spostato alla fine non sempre scompare, a volte lo salvi in ​​una posizione speciale del porta-bit.

Alcuni set di istruzioni hanno solo un significato di spostamento di bit singolo per ciascuna istruzione che si programma, è possibile spostare solo un bit, quindi quanto sopra sarebbe 3 istruzioni, un bit alla volta. Altri set di istruzioni, come arm, ti permettono di avere una singola istruzione e tu specifichi nell'istruzione quanti bit vuoi spostare in quella direzione. così uno spostamento a sinistra di tre

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

Questa variante di ciò che si sposta in è dimostrato tra LSR e ASR, spostamento a destra logica e l'aritmetica spostamento a destra (vedrete che non v'è alcuna slm, shift aritmetico lasciato perché questo rende non ha senso, alcuni assemblatori ti permetteranno di usare un'istruzione asl ma la codificheranno come un lsl).

Uno scorrimento a destra LOGICAL:

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

Come con C v'è una versione che sposta in zeri, cioè lo spostamento a destra logico, spostando in zeri

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

ARITHMETIC spostare mezzi giusti preservano il "bit di segno" qual è il bit di segno? che entra in due numeri complementari che devi anche imparare se non lo hai. Fondamentalmente se si considera il modello/valore di bit come un numero complementare di due, il bit più significativo, quello a sinistra, è il bit di segno. se è 0 il numero è positivo e 1 il numero è negativo. Potresti aver notato che uno spostamento lasciato da un bit equivale a moltiplicare per 2 e uno spostamento a destra equivale a dividere per 2. 0x12 >> 1 = 0x9, 18 >> 1 = 9 ma cosa succede se dovessimo spostare un meno 2 a destra, meno due è 0xFE utilizzando byte o 0b11111110. usando lo spostamento logico di stile C a destra 0xFE >> 1 = 0x7F, o in decimale -2 >> 1 = 0x127. Non possiamo risolvere che in C con una sola operazione, purtroppo, ma in assemblea possiamo utilizzare uno spostamento aritmetico, supponendo che il set di istruzioni ha uno, che il braccio non

ARITMETICA spostamento a destra

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 

Quindi, se il bit di segno s era un 0 quando abbiamo iniziato, se il numero era 01.100.100 poi

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

ma se questo bit di segno era stato uno

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

E possiamo risolvere il 0xFE spostato destra:

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

così in pseudo codice 0xFE ASR 1 = 0xFF, -2 ASR 1 = -1.-2 diviso per 2 = -1

L'ultima cosa che devi leggere da solo ha a che fare con i giri e/o ciò che accade al bit che viene spostato alla fine. uno spostamento a destra l'lsbit viene spostato "alla fine" del numero come i blocchi che vengono fatti scivolare da un tavolo e quello che cade potrebbe semplicemente entrare nel "bit bucket" (etere, paradiso o inferno, uno di questi luoghi in cui i bit andare a morire quando scompaiono da questo mondo). Ma alcune istruzioni in alcuni set di istruzioni prenderanno quel bit spostato fuori e metterlo nel flag Carry (leggi su add e sottrarre), non perché è necessariamente un carry ma perché ci sono bit di stato nell'alluminio e nel bit Carry è uno che ha un senso. Ora che cos'è una rotazione, diciamo che avevi un processore a 8 bit e hai ruotato un bit, il bit che cadeva dalla fine atterra nel bit Carry, E il bit che si sposta nell'altro lato è quello che era nel carry bit prima dell'operazione. Fondamentalmente si tratta di sedie musicali, i pezzi girano intorno alle sedie con una persona rimasta in piedi, la persona in piedi è il riporto, le persone nelle sedie sono i pezzi nel registro. Perché questo è utile a tutti? diciamo che avessimo un processore a 8 bit come l'AVR Atmel, ma volevamo fare uno spostamento a 64 bit. 64 bit impiegano 8, 8 bit, registri, diciamo che ho il mio numero a 64 bit in questi 8 registri e voglio fare uno spostamento di 64 bit a sinistra di un bit. Vorrei iniziare con il byte meno significativo e fare un lsl che sposta uno zero ma il bit che si sposta va nel bit di trasferimento. poi il byte successivo più significativo faccio un rol, ruota a sinistra un bit, il bit che entra è il bit che esce dal byte precedente e il bit che esce va al bit di carry. Ripeto le istruzioni rol per gli altri byte, guardando uno spostamento di 16 bit:

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 

che è quello che le ruota sono per e questo è il motivo per cui il manuale di montaggio preoccupa di dirvi quali flag vengono modificati quando si esegue una operazione logica.

+0

Wow, la tua risposta mi ha colpito! –

+0

Questa è davvero una buona risposta! Potremmo chiedere all'amministratore di salvare questo? – 71GA

+0

@old_timer Potresti sapere perché mi viene richiesto un registro non ridotto - bic r0, r0, # 0x3 durante la compilazione per Thumb quando utilizzo la sintassi BIC? È ancora un bug del 2007? https://gcc.gnu.org/bugzilla/show_bug.cgi?id=34436 – 71GA

3

farò la prima uno e poi forse si può cercare di capire il resto utilizzando un approccio simile:

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

Nota tuttavia che se non avete ancora capito le operazioni booleane, come O (|), E (&), ecc, allora si avrà difficoltà a capire le istruzioni ARM corrispondenti (ORR, AND, ecc).