2012-01-28 47 views
5

¿Alguien puede explicarme los cambios de bit de ARM como si tuviera cinco? Tengo una comprensión muy pobre de cualquier cosa que involucre sistemas de números no decimales, así que es difícil para mí entender los conceptos de los cambios de bit y los operadores bit a bit.¿Puede alguien explicarme las operaciones de bit a bit de ARM?

¿Qué harían cada uno de los siguientes casos y por qué (qué terminaría en R3 y lo que ocurre detrás de escena en el nivel de bits)?

/** 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. No lo explique en términos de operadores bit a bit en C. Tampoco sé lo que hacen (>>, <<, |, &).

Respuesta

15

tablas de verdad, dos entradas, los dos números de la izquierda y uno de salida, el número de la derecha:

O

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

la dos entradas izquierda A y B representan las cuatro combinaciones posibles de entradas, ni más ni menos que esa es la lista.

Considere que 1 significa verdadero y 0 quiere decir falso. Y la palabra O en este caso significa que si un O b es verdadero, entonces c es verdadero. Y como puede ver en la tabla, horizontalmente si a o b es verdadero, entonces c es verdadero.

Y

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

Y significa que ambos tienen que ser cierto si A y B son ambas verdaderas entonces c es cierto. Solo hay un caso donde eso existe arriba.

Ahora tome dos bytes 0x12 y 0x34 que en decimales son 18 y 52, pero realmente no nos importa mucho el decimal. nos importa que el 0x12 binario sea 0b00010010 y 0x34 sea 0b00110100. Los operadores bit a bit como AND y OR y XOR en lenguaje ensamblador significan que toma un bit de cada operando y eso le da el resultado en la misma ubicación de bit. No es como agregar donde tienes cosas como esta más que es igual a bla llevar el uno.

por lo que se alinean los bits

0b00010010 0x12 
0b00110100 0x34 

Así que incline la cabeza sidways como que se va a tomar un bocado de un taco, celebrada en la mano izquierda y visualizar la tabla de verdad anteriormente. Si miramos los dos bits a la derecha, son 0 y 0, los siguientes dos bits son 1 y 0, y así sucesivamente.Así que si lo que queríamos hacer una operación OR, la regla es si A o B es verdadero entonces c, el resultado, es cierto

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

cabeza inclinada hacia la derecha, el bit menos significativo (el bit en las columna en el número) 0 o 0 = 0, ninguno está configurado. siguiente columna (la columna de dos) 1 o 0 = 1 al menos uno es verdadero. y así sucesivamente de modo

0x12 OR 0x34 = 0x36

En conjunto del brazo que sería

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

después de la o r2 operación obstaculicen el 0x36 valor.

Ahora vamos y esos números

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

Recordando nuestra tabla de verdad y el Estado A y B tienen que ser verdad (a 1) que inclinar la cabeza hacia la derecha, 0 y 0 es 0, tanto no son verdad y por inspección, solo una columna tiene ambas entradas con una columna 1, la columna 16s. esto nos deja con 0x12 Y 0x34 = 0x10

En conjunto del brazo que sería

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

ahora llegamos a la instrucción BIC. Lo que significa bitwise clear, que con suerte tendrá sentido en un momento. Bic en el brazo está anded con not b. No es otra tabla de verdad, pero sólo una entrada y una salida

NO

a c 
0 1 
1 0 

Con sólo una entrada que tiene sólo dos opciones 0 y 1, 1 es verdadera 0 es falso. NO significa que si no a, entonces c es verdadero. cuando a no es verdadero c es verdadero, cuando a es verdadero c no es verdadero. Básicamente se invierte.

Lo que hace el BIC es tener dos entradas A y B, la operación es c = a Y (no aplicable b) por lo que la tabla de verdad de que sería:

una Y (NO b)

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

Comencé con la tabla de verdad Y luego noté los bits b, donde b era un 0 en la tabla de verdad Y lo convertí en un 1 donde b era un 1 en la tabla de verdad AND Lo hice 0.

Así que la operación bic en 0x12 y 0x34 es

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

¿Por qué se llama bit clear? Comprender eso hace que sea mucho más fácil de usar. Si miras la tabla de verdad y piensas en la primera y segunda entrada. Donde la segunda entrada, b, es un 1, la salida es 0. donde la segunda entrada, b, es un 0, la salida no está modificada. Entonces, ¿qué está haciendo esa tabla u operación de verdad? Es decir, donde b se establece claramente o pone a cero esos bits en A. Entonces, si tengo el número 0x1234 y quiero poner a cero los 8 bits inferiores, BIC lo haría con 0x00FF. Y tu siguiente pregunta es ¿por qué no Y con 0xFF00? (Analice la tabla de verdad AND y vea que dondequiera que b sea un 1, mantenga el valor tal como está, y donde sea que b sea un 0, ponga a cero el resultado). El ARM usa registros de 32 bits y un conjunto de instrucciones de 32 bits fijo, al menos tradicionalmente.El control directo de

mov r0,#0x12 

En el brazo se limitan a 8 bits no nulos desplazan en cualquier lugar dentro de la serie, se llega a cambio de un poco. Así que si tuviera el 0x12345678 valor y quería a cero fuera de los 8 bits más bajos que podía hacer esto

; 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 

que no es horrible, en comparación con usando un movimiento y dos orrs, pero aún quema más ciclos de reloj que la solución bic porque quema el ciclo de memoria extra leyendo my_byte_mask del ariete, lo que puede llevar un tiempo.

o

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

Este último no siendo mala compromize. tenga en cuenta que mvn en la documentación del brazo es bitwise no inmediata, eso significa rx = NOT (inmediato). El inmediato aquí es 0xFF. NOT (0xFF) significa invertir todos los bits, es un registro de 32 bits al que vamos, lo que significa que 0xFFFFFF00 es el resultado de NOT (0xFF) y eso es lo que obtiene el registro r1, antes de hacer el y.

así que por eso BIC tiene un lugar en el conjunto de instrucciones ARM, porque veces que se necesita un menor número de instrucciones o ciclos de reloj para enmascarar (máscara = y se utiliza para hacer algunos bits de ceros) usando la instrucción BIC en lugar de la y instrucción.

Utilicé la palabra máscara como concepto para hacer bits en un número cero, dejando a los demás en paz. Se puede pensar que orring está haciendo bits en un número uno mientras deja a los otros solos, si miras la tabla de verdad OR en cualquier momento b es un 1 entonces c es un 1. Entonces 0x12345678 O 0x000000FF resulta en 0x123456FF los bits en el segundo operando están configurados. Sí, también es cierto que cada vez que a se establece en la tabla de verdad OR, se establece la salida, pero muchas veces cuando utiliza estas operaciones bit a bit tiene un operando que desea hacer, establecer un cierto número de bits a uno sin modificar el resto o establecer un cierto número de bits a cero sin modificar el resto o si desea poner a cero todos los bits a excepción de un cierto número de bits. Cuando se usa de esa manera, tiene un operando que entra, que es en lo que quiere operar y crea el segundo operando en función de lo que quiere que sea el efecto general, por ejemplo, en C, si queríamos mantener solo el byte inferior que pudiéramos tener un parámetro en una función, un parámetro de salida:

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

~ significa no tan ~ 0xFF, para los números de 32 bits significa 0xffffff00 luego & manera Y, por lo que devuelven un & 0xffffff00. a era el único operando real que entraba y nosotros inventamos el segundo basado en la operación que queríamos hacer ... La mayoría de las operaciones bit a bit pueden intercambiar los operandos en las instrucciones y todo resulta bien, las instrucciones como bic de ARM aunque los operandos son en cierto orden, al igual que un resta, debe usar el orden correcto de operandos.

Desplazamiento ... hay dos tipos, lógico y aritmético. lógico es más fácil y es lo que obtienes cuando usas >> o < < en C.

Empieza con 0x12 que es 0b00010010.El cambio que tres lugares a la izquierda (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 

Lo consiguen bits de "desplazado" a los lugares vacíos, los x'es anteriores, varía en función de la operación. Para la programación C es siempre ceros:

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

Pero a veces (por lo general cada conjunto de instrucciones compatible con una rotación, así como un cambio) hay otras maneras de cambiar y las diferencias tienen que ver con lo Bit de cambiar a la lugar vacío, y también a veces el bit que cambiaste al final no siempre desaparece, a veces lo guardas en una ubicación especial para el bit holder.

Algunos juegos de instrucciones solo tienen un cambio de bit único, lo que significa que para cada instrucción que programes solo puedes cambiar un bit, por lo que lo anterior sería 3 instrucciones, un bit a la vez. Otros juegos de instrucciones, como el brazo, le permiten tener una sola instrucción y usted especifica en la instrucción cuántos bits quiere cambiar en esa dirección. por lo que un desplazamiento a la izquierda de cada tres

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

Esta variación de lo que cambio en está demostrada entre LSR y ASR, desplazamiento a la derecha lógica y aritmética desplazamiento a la derecha (verá que no existe el nivel del mar, desplazamiento aritmético a la izquierda ya que hace no tiene sentido, algunos ensambladores le permitirán usar una instrucción asl pero la codifican como un lsl).

Un desplazamiento a la derecha lógico:

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

Como con C hay una versión que cambia en ceros, es decir el desplazamiento a la derecha lógico, cambiando en ceros

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

ARITHMETIC medios de desplazamiento adecuados conservan el "bit de signo" ¿cuál es el bit de signo? eso se convierte en dos números de complemento que también debes aprender si no lo has hecho. Básicamente si considera que el patrón/valor de bit es un número de complemento a dos, entonces el bit más significativo, el de la izquierda, es el bit de signo. si es 0, el número es positivo y 1 el número es negativo. Tal vez hayas notado que un desplazamiento dejado por un bit es lo mismo que multiplicar por 2 y un desplazamiento a la derecha es lo mismo que dividir por 2. 0x12 >> 1 = 0x9, 18 >> 1 = 9 pero ¿qué pasaría si cambiáramos? a menos 2 a la derecha, menos dos es 0xFE utilizando bytes o 0b11111110. usando el desplazamiento lógico de estilo C derecho 0xFE >> 1 = 0x7F, o en decimal -2 >> 1 = 0x127. No podemos resolver que en C en una sola operación, por desgracia, pero en el montaje podemos usar un desplazamiento aritmético, asumiendo que su conjunto de instrucciones tiene uno, que el brazo hace

desplazamiento aritmético a la derecha

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 

Así que si el bit de signo s era un 0 cuando empezamos, si el número fue de 01.100.100 a continuación

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

pero si ese bit de signo había sido un

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

Y podemos resolver el 0xFE desplaza a la derecha uno:

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

por lo que en pseudo código 0xFE ASR 1 = 0xFF, -2 ASR 1 = -1.-2 dividido por 2 = -1

Lo último que debe leer por su cuenta tiene que ver con rota y/o qué sucede con el bit que se desplaza hacia el final. un desplazamiento a la derecha el lsbit se desplaza "fuera del extremo" del número como bloques que se deslizan de una tabla y el que se cae podría ir al "cubo de bits" (éter, cielo o infierno, uno de estos lugares donde las partes ir a morir cuando desaparezcan de este mundo). Pero algunas instrucciones en algunos conjuntos de instrucciones quitarán ese bit y lo colocarán en el indicador de acarreo (leer en agregar y restar), no porque sea un acarreo necesariamente, sino porque hay bits de estado en el alu y el bit de acarreo. es uno que tiene sentido. Ahora lo que es rotar, digamos que tiene un procesador de 8 bits y ha girado un bit, la broca que cae del extremo aterriza en el bit Carry, Y el bit que cambia en el otro lado es lo que estaba en el bit de acarreo antes de la operación. Básicamente son sillas musicales, los pedacitos caminan alrededor de las sillas con una persona que permanece de pie, la persona de pie es el bit de acarreo, las personas en sillas son las partes en el registro. ¿Por qué es esto útil en absoluto? Digamos que tenemos un procesador de 8 bits como el Atmel AVR, por ejemplo, pero quería hacer un cambio de 64 bits. 64 bits toma 8, 8 bit, registra, digamos que tengo mi número de 64 bits en esos 8 registros y quiero hacer un desplazamiento de 64 bits hacia la izquierda un bit. Comenzaría con el byte menos significativo y haré un lsl que cambia un cero pero el bit que se desplaza va al bit de acarreo. luego el siguiente byte más significativo hago un rol, giro un bit a la izquierda, el bit que entra es el bit que sale del byte anterior y el bit que sale va al bit de acarreo. Repito la instrucción rol de los otros bytes, mirando a un desplazamiento de 16 bits:

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 

que es lo que gira son para y es por eso que el manual de montaje molesta que le diga lo que se modifican las banderas cuando se realiza una operación lógica

+0

¡Guau, su respuesta me impresionó! –

+0

¡Esta es una muy buena respuesta! ¿Podríamos pedirle al administrador que guarde este? – 71GA

+0

@old_timer ¿Quizás sabrías por qué obtengo el registro sin cambios requerido? Bic r0, r0, # 0x3 durante la compilación de Thumb cuando uso tu sintaxis BIC? ¿Sigue siendo un error del 2007? https://gcc.gnu.org/bugzilla/show_bug.cgi?id=34436 – 71GA

3

voy a hacer lo primero uno y luego tal vez usted puede tratar de resolver el resto usando un enfoque similar:

/** 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 sin embargo que si usted todavía no entiende operaciones booleanas como O (|), Y (&), etc., entonces tendrá dificultades para entender las instrucciones ARM correspondientes (ORR, AND, etc.).

Cuestiones relacionadas