Programación en Lenguaje Ensamblador

-El Verdadero Lenguaje de las Máquinas-

El Baile de Máscaras de Bit

–Usos interesantes de AND, OR y XOR–

Mejor me ahorro los chistes malos quería hacer relacionados con máscaras, lucha libre, computadoras, videojuegos y gente que no sabe programar y me voy directo al tema de las máscaras de bits. Las máscaras de bits son números binarios que se combinan con otros valores mediante una operación lógica como AND, OR y XOR para lograr algunos efectos bastante interesantes.

Y al igual que las máscaras usadas en los bailes de la antigua nobleza, las máscaras binarias son valores binarios compuestos de ceros y unos. Dependiendo de la operación lógica que se haga entre estas máscaras y el valor que deseamos ‘enmascarar’ obtendremos efectos diferentes. Efectos que dicho sea de paso serían imposibles o muy poco eficientes usando técnicas de programación convencionales. También se dice que a estos valores se les llama máscaras porque los ceros son como los agujeros para los ojos y los unos las partes cerradas de dichas prendas. Pero ahora sigamos con el asunto de las máscaras de bits

Es bueno que les recuerde que las máscaras de bits, al igual que las operaciones aritmético-lógicas usando como operadores AND, OR y XOR solo tienen sentido cuando trabajamos con números binarios. Algunos usos de las máscaras de bits son leer y escribir bits individuales en registros y memoria (cosa muy importante en programación de periféricos). Hacer operaciones de control de datos que de otro modo requerirían de sofisticada programación condicional y mi favorita de todas que es hacer comparaciones múltiples en un ciclo de reloj o menos. Ahora veamos las tres máscaras de bits mas importantes en la programación en ensamblador y en cualquier otro lenguaje donde tenga sentido trabajar con números binarios.


Máscara AND: Filtro y Delimitador

La máscara AND funciona como un colador o filtro. Nos permite conservar los bits que nos interesan en su valor actual mientras que los que no los podemos poner a cero. En este caso los bits cuya posición queremos dejar intacta le asignamos un 1 en la máscara y los que queramos borrar les asignamos un cero en esa posición. Esta técnica tiene muchos usos como por ejemplo mantener un valor por debajo de cierta cantidad. Digamos que queremos hacer un contador que solo pueda contar 0, 1, 2 y 3. Y cuando termine vuelva a empezar. Lo que cualquier scripter zoquete con título de ingeniería de universidad pública (o privada no especializada en tecnología) sería inicializar el contador en cero y probar continuamente que el contenido no fuera mayor que tres. Si esto sucediera tendría que llamar a una subrutina que inicializara el contador de nuevo y volviera a empezar. En cambio, alguien que supiera de máscaras de bits solo tendría que hacer un AND entre el contador y una máscara de bits cuyo valor sea 3. El 3 tiene en cero todos los bits menos los dos mas bajos. Si luego de incrementar el contador se hiciera un AND con un 3 todos los bits menos los 2 mas bajos se pondrían en cero. Con lo que el contador podría incrementarse de manera indefinida sin pasar nunca de la secuencia 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3… No habría necesidad de probar límites, dar saltos ni mucho menos llamar subrutinas de inicialización. Otro uso mas común de la máscara AND es obtener una porción de un registro. Por ejemplo en manejo de gráficos digitales es muy común que los valores de color de pixel se empaqueten en un solo valor de 16, 24 o 32 bits de modo que quepan los valores rojo, verde y azul en un solo valor de ese mismo ancho. En el caso de empaquetamiento de 16 bits el azul corresponde a los 5 bits mas bajos, el verde a los 5 de en medio y el rojo a los 5 bits que siguen del bit mas alto que no siempre se usa. Si queremos extraer los valores individuales por ejemplo del verde hacemos un AND con una máscara 0000001111100000 que en hexadecimal corresponde al 03E0. Al hacer esto el resultado conservaría solo los bits verdes y bastaría desplazar este resultado 5 bits a la derecha para obtener el valor verde de ese pixel. Otro uso mas obvio es el de poner pixeles individuales en cero sin afectar los otros. Por cierto, hay una máscara AND neutral que puede aplicarse a cualquier valor sin afectarlo. Esta máscara tiene todos los bits a uno.


Máscara OR: La Cinta del Pintor

La máscara OR funciona como la cinta conocida como masking-tape que usan los pintores. Se trata de tiras de papel con un adhesivo apenas lo bastante fuerte para sostenerse sobre la superficie a pintar. El artista coloca esta cinta sobre las partes que no quiere pintar. Tira el brochazo y cuando la pintura se ha secado retira la cinta. Con lo que consigue pintar lineas rectas o con la forma que quiera sin necesidad de tener una gran precisión con el pincel. En el mundo binario, una máscara OR puede poner bits a 1 sin afectar los bits contiguos. Solo hay que poner en la posición de bits de la máscara ceros en los que queremos respetar y unos en los que queremos activar. Los usos de la máscara OR son variados e interesantes.

Un uso de la máscara OR es asignar propiedades en comparaciones múltiples. Supongamos que queremos ver si la letra que estamos leyendo en el acumulador es o no una vocal y si se trata de una letra mayúscula o minúscula. La comparamos sucesivamente con A,E,I,O,U. Usamos CMP entre el acumulador y las posibles vocales. Pero en lugar de dar saltos condicionales usamos la instrucción SETE EDX que pondrá a uno EDX si hay coincidencia y cero si no la hay. El resultado de EDX lo usamos como máscara OR contra otro valor en memoria que usemos como registro de comparaciones. En el que previamente hemos acordado que el bit mas bajo estará a 1 si la letra es vocal y cero si no lo es. Y el bit que le sigue indica que la letra es mayúscula. Tras 5 instrucciones CMP el bit que indique si es o no vocal va a estar en 1 si EAX contiene una vocal y en 0 si no es así. Para ver si es mayúscula podrían hacerse otros CMP entre EAX y los valores en mayúscula o mejor aun probar el bit 20 si es que ya confirmamos que es una vocal. Usamos SHL para escribir el valor en otro bit del registro de comparación múltiple. Al final solo bastará comprobar bits individuales con una máscara AND para ver si la letra es vocal o mayúscula o cualquier otra propiedad que queramos definir. De nuevo, existe una máscara OR que no afecta el resultado. Dicha máscara tiene todos sus bits a cero.


Máscara XOR: Igualdad y Negador Discrecional

La máscara XOR es la mas interesante de todas, la llamo la mascara de la igualdad. La máscara XOR tiene 2 usos muy importantes. El primero es servir para hacer comparaciones múltiples en un solo ciclo de reloj y la otra es hacer un NOT selectivo a nivel de bit. Veamos primero como hacer comparaciones múltiples. Regresando al problema anterior de ver si un valor en el acumulador es vocal. Podemos hacer que el resto de los bits en el registro de atributos signifiquen algo como si es vocal, es mayuscula, es un número o cualquier otra cosa que se nos ocurra cuya respuesta sea un SI o un NO. Para ver si una serie de condiciones se cumplen hacemos una máscara XOR que tenga 1 en las condiciones verdaderas y 0 en las falsas. Si el valor que contiene las banderas de propiedades y la máscara XOR coinciden en todo. El resultado de la máscara XOR va a ser CERO. Si hay alguna diferencia aunque sea en un solo bit el resultado va a ser diferente de cero. Estas condiciones son muy fáciles de detectar y es mucho mas rápido que probar todas las propiedades cada vez. Un ejemplo mas divertido de esta máscara XOR es en los juegos donde las armas y los monstruos cuentan con propiedades que hacen que el ataque tenga mayor o menor efectividad. Digamos que en el juego tenemos por enemigos demonios y humanos. Y como arma tenemos la pistola y el agua bendita. Las balas pueden herir a los humanos pero no a los demonios y el agua bendita quema a estos últimos pero no tiene efecto en los primeros. Asignamos tanto a las armas como a los villanos un valor que registre los tipos de daño. En las armas un bit se activa si el arma tiene efecto en humanos y otro si lo tiene en demonios. Por su parte cada enemigo tiene un valor similar sobre el tipo de arma a la que es o no vulnerable. Entonces, al verificar el contacto se hace un XOR entre el valor de propiedades de las armas contra el de las vulnerabilidades del enemigo y podemos ver si hay o no coincidencia sin una sola comparación o salto condicional. De este modo podemos crear combinaciones mas raras como humanos poseidos que puedan ser heridos con agua bendita o crear mas propiedades y vulnerabilidades sin necesidad de complicarnos el código. Y lo mejor de todo es que no importa que tantas condiciones se prueben. Basta tan solo un XOR para probar tantas condiciones como bits tenga el registro en que estas se guarden.

El otro uso de la máscara XOR es el NOT selectivo. Como bien saben un NOT cambia los ceros por unos y los unos por ceros de la misma manera en la que un foco se enciende y se apaga cada vez que oprimimos el interruptor de la luz. Cuando solo queremos que un grupo de bits de un registro reciba el efecto del NOT sin molestar a los otros hacemos una máscara XOR que tenga 1 en los bits que queremos invertir y 0 en los que queramos dejar como están. Esto tiene aplicación cuando queremos hacer propiedades que puedan activarse o desactivarse. Pongamos como ejemplo el videojuego anterior. Supongamos que en algún momento el jugador es víctima de una maldición temporal que vuelve su armamento inutil o invoca un conjuro que lo hace invulnerable. Solo basta invertir la propiedad que nos interesa con una máscara XOR para lograr este efecto. Otro ejemplo es el uso de llaves. Digamos que en el juego hay puertas que solo pueden ser abiertas o cerradas si el jugador posee una llave. Se asigna un bit de status en el registro del jugador indicando si tiene o no la llave. La puerta tiene un bit que indica si está abierta o cerrada. Si hacemos un XOR entre el bit de la llave y la puerta sucederá lo siguiente: La puerta se abrirá o cerrará si el bit de la llave está a 1 (1 XOR 0 = 1, 1 XOR 1 = 0) pero si no la tiene y el bit de la llave está en cero la puerta va a seguir tal y como la encontró ( 0 XOR 0 = 0, 0 XOR 1 = 1).

En fin, el uso de máscaras de bits es indispensable no solo para manipular bits individuales dentro de valores mas grandes sino que casi siempre son la única manera eficiente de manejar verdadera lógica digital y toma de decisiones en un programa escrito en ensamblador. En entradas posteriores quiero hablarles de una interesante instrucción llamada SET que aunque parece muy sencilla es grande cuando se combina con las máscaras de bits que acabamos de ver. También tengo que confirmar unos rumores sobre un perturbador problema de socialización que parece estar ocurriendo entre los estudiantes de esas nuevas carreras profesionales enfocadas al desarrollo de videojuegos.

septiembre 5, 2011 - Posted by | Uncategorized | ,

5 comentarios »

  1. Podrías comentar más sobre ese perturbador problema que comentas al final del todo ?

    Comentarios por JuDelCo | septiembre 6, 2011 | Responder

    • Bueno, para empezar estas nuevas carreras de videojuegos tratan de combinar el aspecto artistico con el tecnologico y lo unico que cambia de una escuela a otra es la proporcion de estas dos cosas. Parece que el nivel de arte es bueno en la mayoria de ellas pero el nivel tecnologico parece ser demasiado alto para los estudiantes con vocacion artistica y a la vez muy bajo para los de habilidades mas tecnologicas. Esto causa que los primeros no quieran saber nada de videojuegos y prefieran mejor dedicarse a la animacion y efectos especiales mientras que los segundos se conforman con hacer juegos muy sencillos (como la mayoria de los juegos de iphone) por no atreverse a crear contenidos visuales.

      De esta division ya se especulaba en una vieja entrada del blog llamada «Programacion Grafica no es lo mismo que Arte Digital» pero ahora estoy juntando evidencia de esta posible division que parece estarse creando en las carreras de desarrollo de videojuegos

      Comentarios por asm86 | septiembre 6, 2011 | Responder

      • Pues estoy de acuerdo. Si bien es cierto que saber ambas cosas nunca te perjudicará, es sabido que para realizar un videojuego (en un tiempo y calidad razonable para el mercado actual) se requiere un equipo de desarrollo. El cual debe tener especialistas en cada rama, así que es razonable que las personas se especialicen en lo que más destaquen o prefieran.

        Viéndolo así no están de más estas escuelas, sin embargo no las consideraría para nada como el medio para aprender «definitivamente» (lo cual es utopía, en estas materias nunca se deja de aprender cosas) lo que es necesario para profesionalizarse en todo el sector.

        Ahí dejo eso, que son las 5 de la madrugada aquí y es posible que se me haya ido un poco la cabeza al escribir algo. Un saludo

        Comentarios por JuDelCo | septiembre 6, 2011

  2. Pues como siempre hay que tener en cuenta el contexto del ambiente donde se trabaja, las operaciones logicas son muy utiles, por ejemplo me sirvieron para convertir una imagen de escala de grises en B/N en c# (no vomites Mario jajajaja), cosa que hubiera sido dificil y lento si no lo hiciera con mascaras, pero hay que entender a la mercadotecnia, a poco eres tan inocente de cree que todos los que entran a las carreras van atraidos por el conocimiento en sí, yo he visto que en este negocio de la computación lo que a muchos les interesa solo es ganar precisamente tres salarios minimos o más.

    La mayoria de las empresas buscan hacer codigo que sea facil de manejar, para que cualquier programador lo pueda cambiar a la brevedad, ya que los clientes así lo exigen.Ver en el codigo un IF … THEN …ELSE es más fácil de entender para la mayoria de los mortales.

    Hacer un buen videojuego (a los ultimos estandares) en solitario, implica tener muchas habilidades ademas de ser buen programador hay que ser un artista, fisico, matematico, programador, musico, etc…

    Yo no me preocuparía por las escuelas en México, la mayoría obedecen a intereses monetarios más que academicos.

    En cuanto al blog, pienso que ya te deberías enfocar a temas más interesantes, por decir, implementar algoritmos graficos, de busqueda, inteligencia artificial, etc… claro esta en ensamblador.

    Saludos

    Comentarios por El Julio | septiembre 14, 2011 | Responder

    • Cierto, debo de dejar de perder el tiempo con discusiones inutiles y concentrarme en el ensamblador. No escribo sobre estos temas para las empresas sino para los interesados en el ensamblador sin importar su nivel. Por lo que respecta a las escuelas de videojuegos, salvo honrosas y muy contadas excepciones, tienen por maestros a antiguos ‘profesionales’ de la industria que simplemente no son capaces de vivir de hacer juegos porque estos son tan malos que casi nadie los compra. Espero que saquen juegos redituables aunque sean APPS de iphone para que puedan pagar esas nominas que les deben a sus empleados desde hace meses.

      Por lo que respecta al blog tengo pensado hacer algunas entradas explicando conceptos de graficas por computadora usando solo lapiz, calculadora y papel. Para que se vea que el tema no es solo cosa de API’s y Engines como muchos ‘profesionales’ todavia creen. Lo bueno es que el ensamblador tiene temas que me van a permitir seguir escribiendo durante mucho mucho tiempo.

      Comentarios por asm86 | septiembre 21, 2011 | Responder


Deja un comentario