lunes, 18 de julio de 2016

¿Par o impar? ¿Cero o no cero? ¿Multiplo de algo? ¿Bit o no bit? (parte 2)

En la primera parte de este tema vimos que luego de una operación aritmética, de carga, etc, que actualice el flag Z de la palabra de estado podemos verificar si el resultado fue cero (o si se cargó o guardó un cero) y actuar conforme a ello. Las dos instrucciones de salto que solo actúan por la condición Zero son BNE (branch not equal) y BEQ (branch equal). ¿Por qué tienen ese nombre?
Entender bien esto le ayudará a emplear bien las instrucciones de la familia Branch. Consideremos por un momento lo siguiente:
¿Cómo se determina si dos operandos son iguales? En alto nivel seguramente alcanzará con hacer algo como:
if (a == b)  { 
       algunas otras instrucciones 
}
¿Qué es lo que hace CPU para saber si a y b son iguales? Seguramente ya lo dedujo: los resta. Si la operación da por resultado cero, son iguales. Caso contrario, son distintos. Aun cuando estemos comparando dos cadenas de texto, estructuras o construcciones más complejas, determinar si son iguales se reduce a restar cada byte de su contraparte. ¿Cómo se comparan dos valores en bajo nivel? De la misma manera: restando. Veamos en el set de instrucciones el detalle de las instrucciones de comparación:


Note la diferencia con las instrucciones de resta (recorté una parte del set):

¿En qué se diferencian? La comparación es una resta de la que no nos interesa el resultado. Por lo demás, se comportan igual. Por lo tanto, ¿cómo sabemos en bajo nivel si dos operandos son iguales? Comparándolos y luego realizando un branch en función del flag Z. 
Vayamos entonces a un dilema existencial de muchos newbies: si hay que determinar si un valor es cero... ¿tengo que compararlo con cero? En otras palabras, supongamos que estamos recorriendo un vector usando el índice IX y estamos llevando la cuenta de los ceros en la posición de memoria CUENTAZ, ¿estaría bien hacer esto...?

        CLR CuentaZ
        ....
        LDAA 0,x
        CMPA #0
        BNE noCero
        INC CuentaZ
noCero  ....

Si leyó el post anterior ya debería saber la respuesta (sugiero releerlo para llegar a la conclusión por usted mismo).
El caso es que como hemos visto la instrucción LDAA también actualiza el flag Z en función del operando. Por lo tanto aunque no realicemos ninguna comparación, también podemos usar el flag Z para decidir un salto si el resultado de la última operación (o el operando cargado) es cero.

El flag N (Negative) es copia del MSB (most significant bit, bit más significativo) del operando cargado o del resultado de la última operación. Cuando representamos negativos en complemento a la base (Cb), complemento a la base menos uno (Cb-1) o módulo y signo (MyS) el flag N nos indica si se trata de un número negativo. 
Obviamente, si no manejamos números signados, si estamos manejando números negativos representados en exceso (como ocurre con el exponente de las representaciones de punto flotante), o si es otro dato como ser un caracter ascii, por solo citar dos casos, el flag N se actualizará pero no nos indicará el signo del número. Es el programador el que sabe en qué formato representa los operandos y por tanto puede determinar si aplica el uso del flag N como indicador de números negativos.
Por lo tanto, si el formato de representación empleado implica que el MSB coincide con el bit de signo, podremos usar los branch BMI (salta si N=1) y BPL (salta si N=0) para tomar decisiones en función del bit negative.

Supongamos entonces que necesitamos contar los números negativos de un vector, sabiendo que se almacenan en Cb. Siguiendo una pauta similar al resto de los ejemplos del post podríamos hacer algo así:
        CLR CuentaNeg
        ....
        LDAA 0,x

        BPL positi
        INC CuentaNeg
positi  ....

¿Y si necesitásemos contar tanto los ceros como los negativos? Dado que las instrucciones de la familia branch no modifican el estado de los flags, podríamos incluir varios branch consecutivos:

        CLR CuentaNeg
        CLR CuentaZ
        ....
        LDAA 0,x
        BEQ esCero     ; puedo hacer dos BRANCH seguidos, o mas!

        BPL positi     ; porque el estado de los flags no cambia
        INC CuentaNeg
positi  ...
        BRA noZ
esCero  INC CuentaZ
noZ     ...

El ejemplo no busca ser la solución óptima al problema, solo ilustrar el uso de dos branch consecutivos.
En la próxima parte veremos cómo verificar fácilmente si un número es par o impar.

No hay comentarios.:

Publicar un comentario

Aunque no es obligatorio, es de buena educación firmar los comentarios.