martes, 21 de mayo de 2013

Curso Ensámblalo! Cap. 5.3 - El apartado Lógico de la ALU



En el anterior capitulo aprendimos como el 6502 realiza operaciones aritméticas gracias a la ALU, se dijo además que este subsistema era también el encargado de tratar todo lo que tuviera que ver con las decisiones lógicas y es precisamente en este apartado donde profundizaremos a lo largo de este capitulo.

Todo programa es un conjunto de instrucciones ordenadas con el único fin de solucionar un problema. Todo problema puede y debe ser estructurado en una serie de pasos lógicos a través de varias ramificaciones que nos irán resolviendo partes del problema que se interconectan hasta darnos finalmente su solución. A estos pasos los llamaremos su algoritmo. Un programa complejo estará compuesto de varios problemas a resolver y por tanto contendrá sus pertinentes algoritmos que a su vez se estructuran en un algoritmo general que los enlaza a todos.

A la hora de elaborar un programa complejo es recomendable (aunque no absolutamente necesario) hacer antes un esquema en el que se detalle de forma lógica su algoritmo, en el que se reflejen todas las posibles opciones (ramificaciones). Este tipo de esquemas se conocen en la jerga informática como diagramas de flujo u organigramas. Para esta tarea también podemos echar mano de pseudocódigo, otra forma de definir nuestro programa mediante instrucciones bien claras de entender por nosotros (una especie de lenguaje de programación universal). Lo verdaderamente importante aqui es comprender a la perfección lo que se quiere hacer antes de teclear ni una sóla linea de código.

En el Basic v2 del c64 el apartado lógico de un programa se lleva a cabo mediante las instrucciones IF ... THEN, ON ... GOTO, ON ... GOSUB, GOSUB y GOTO, que son instrucciones capaces de alterar el flujo normal de un programa según la comprobación lógica de una condición.

Como cabria esperar existe un juego de intrucciones código máquina que realizan idénticas labores aunque, como descubriréis, no se es tan directo como en Basic.

Esto no quiere decir que sea excesivamente más complicado programar decisiones lógicas en CM, simplemente requiere que comprendáis perfectamente como funciona el micro por dentro y esto implica que comprendáis que son las banderas ("flags") del procesador ya que el testeo de condiciones está ligado a sus banderas. En capitulos anteriores ya se las ha ido haciendo referencia pero ahora las veremos con todo el detenimiento que merecen.

Las banderas del procesador



En el 6502 hay siete banderas, todas ellas ocupan un bit y se hallan agrupadas dentro del registro de 8 bits "P" (palabra de estado del procesador). El bit 5 se dejó reservado para futuras implementaciones del chip y no tiene uso en el 6502.

Cada una de estas banderas cambiará según se vayan ejecutando instrucciones. Hay instrucciones que las cambian directamente y otras indirectamente (afectando a una o más banderas) como resultado de una operación.

El significado de cada bit es el siguiente:

Bandera N, Negative (Negativo)


También llamada bandera de signo, tendrá su bit puesto a uno si el resultado de la última operación (incluida una operación de carga) fue un número negativo (en representación de complemento a dos). Tiene una correspondencia directa con el bit 7 del registro acumulador por lo que una buena forma de comprobar el estado de este bit en el acumulador seria comprobando esta bandera. Fijaos a su vez que la bandera N ocupa muy convenientemente el bit 7 dentro del registro P (su bit más a la izquierda).

Bandera V, oVerflow (Rebasamiento)


La bandera de rebasamiento nos indica si hubo un acarreo (en la última operación efectuada) desde el bit 6 al 7, algo que deberemos tener en cuenta solamente si estamos sumando o restando números que sabemos que son expresados en complemento a dos. Si hubo dicho rebasamiento el bit V será igual a uno, reseteándose a cero en caso contrario.

Bandera B, Break (Interrupción por software)


Esta bandera se pondrá a uno cuando se ejecute una instrucción BRK, la cual fuerza a generar una interrupción que detiene el programa en curso. Se usa esta bandera para diferenciarse de los demás tipos de interrupciones y que los programas puedan saber que se interrumpió manualmente (por software).

Bandera D, Decimal


El 6502 puede operar aritméticamente de dos formas distintas: en Modo Binario (por defecto) y en Modo Decimal. Para fijar el modo de operación activo se usa esta bandera. En el modo decimal los números son entendidos como codificados en binario-decimal (BCD, de "Binary Coded Decimal"). En este modo, el número diez por ejemplo se expresa como "0001 0000" (uno-cero), en lugar de su representación binaria normal "0000 1010" (diez). Este modo se pensó para manejar eficientemente programas de tipo financiero que trabajen con cifras astronómicas, ya que en estos casos la precisión es más importante que la velocidad de cálculo.

Bandera I, Interrupt Disable (Desactivador de Interrupciones)


Este bit indica si las interrupciones están o no habilitadas (a excepción de las NMI ó no emmascarables). Si I=1 no se producirán interrupciones normales, y si I=0 éstas estarán permitidas (valor por defecto en el momento del encendido).

Bandera Z, Zero (Cero)


Esta bandera refleja si el resultado de la última operación fue cero (incluida una operación de carga como LDA #0), activándose si fuera el caso (Z=1). Si el resultado hubiese sido distinto de cero, la bandera permaneceria intacta. Es una bandera muy usada en bifurcaciones lógicas. Cuando un número es igual a otro, al restarlos el resultado es cero. Con esta sencilla premisa es posible comparar números entre si y saltar a un punto u otro del programa mediante instrucciones de bifurcación condicional como BEQ y BNE. Éstas testean el estado de Z y actúan en consecuencia. Sin embargo, para comparar dos números no es estrictamente necesario realizar su resta. La instrucción CMP (que compara el acumulador con un byte en memoria), y las respectivas para los registros X e Y: CPX, CPY, realizarán esta resta internamente (sin almacenar el resultado) y actualizarán el flag cero de acuerdo a ésta.

Bandera C, Carry (Acarreo)


Esta bandera refleja si en la anterior operación se produjo un acarreo. Esta bandera, como algunas de las otras también encenderse o apagarse a voluntad. Las instrucciones SEC y CLC se ocupan de ello respectivamente. Ya se vió en el capitulo anterior en que consistia el acarreo por lo que no redundaré más explicando el concepto. Las instrucciones de salto condicional que tienen que ver con esta bandera son BCS y BCC, que saltarán si el acarreo está fijado o borrado respectivamente. Como podemos fijar la bandera a nuestro antojo es usual para algunos programadores usen esta bandera para indicar posibles errores al llamador de una subrutina a modo de código de terminación.


A continuación, vistas las banderas, conoceremos las instrucciones que permiten programar el apartado de las decisiones lógicas en nuestros programas (separados en subcategorias):

* Instrucciones que permiten realizar tests lógicos.

* Instrucciones que modifican las banderas de Control

* Instrucciones que modifican las demás banderas

* Instrucciones de bifurcación condicional.



Instrucciones que permiten realizar tests lógicos


Aqui vereis agrupadas las instrucciones que comparan dos números como CMP, y las que permiten testear bits específicos como AND y BIT.
Al emplear estas instrucciones el resultado quedará reflejado en una (o varias) de las banderas. Este resultado permitirá más tarde bifurcar a un punto u otro del programa gracias a las instrucciones de bifurcación condicional tales como BEQ ó BNE, como veremos en su correspondiente apartado más abajo.

CMP

 
Compara memoria con el acumulador
(CoMPare Memory with accumulator)
Operación: A - M
N Z C I D V
x x x - - -
 
                     * Añadir 1 si cruza límite de página.
Modo de direccionamiento   Sintaxis Cód. Oper.  Nº. Bytes Nº. Ciclos
Inmediato cmp # Oper $c9  2  2
Página Cero cmp   Oper $c5  2  3
Página Cero, x cmp   Oper, x $d5  2  4
Absoluto cmp   Oper $cd  3  4
Absoluto, x cmp   Oper, x $dd  3  4*
Absoluto, y cmp   Oper, y $d9  3  4*
(Indirecto, x) cmp  (Oper, x) $c1  2  6
(Indirecto), y cmp  (Oper),y $d1  2  5*

Compara una posición de la memoria (el siguiente byte de la instrucción, en direccionamiento Inmediato) con el acumulador, modificando las banderas del registro de estado pertinentes (ver esquema con banderas afectadas, en la tabla superior).

Para la comparación, internamente se resta el registro acumulador (a) menos el operando (a-M), ignorando el resultado (el acumulador y la memoria permanecen intactos) pero modificando las banderas que hayan sido afectadas. Luego se pueden usar instrucciones de salto condicional según éstas para bifurcar a diferentes puntos del programa.

Ejemplo de uso:

lda #$25 // a = $25
cmp valor // modifica Z y C según resultado "resta"
  beq igual // salta a iguales (si Z = 1)
  bcs mayor // salta a mayor (si C = 1)
  bcc menor // salta a menor (si C = 0)
  ...  


CPX

 
Compara memoria con el registro de índice x
(ComPare memory and index X)
Operación: X - M
N Z C I D V
x x x - - -
 
Modo de direccionamiento   Sintaxis Cód. Oper.  Nº. Bytes Nº. Ciclos
Inmediato cpx # Oper $e0  2  2
Página Cero cpx   Oper $e4  2  3
Absoluto cpx   Oper $ec  3  4

Compara una posición de la memoria (el siguiente byte de la instrucción, en direccionamiento Inmediato) con el registro de índice x, modificando las banderas del registro de estado pertinentes (ver esquema con banderas afectadas, en la tabla superior).

CPY

 
Compara memoria con el registro de índice y
(ComPare memory and index Y)
Operación: Y - M
N Z C I D V
x x x - - -
 
Modo de direccionamiento   Sintaxis Cód. Oper.  Nº. Bytes Nº. Ciclos
Inmediato cpy # Oper $c0  2  2
Página Cero cpy   Oper $c4  2  3
Absoluto cpy   Oper $cc  3  4

Compara una posición de la memoria (el siguiente byte de la instrucción, en direccionamiento Inmediato) con el registro de índice y, modificando las banderas del registro de estado pertinentes (ver esquema con banderas afectadas, en la tabla superior).

AND

 
"Y" lógico con el acumulador
("AND" memory with accumulator)
Operación: A & M => A
N Z C I D V
x x - - - -
 
                     * Añadir 1 si cruza límite de página.
Modo de direccionamiento   Sintaxis Cód. Oper.  Nº. Bytes Nº. Ciclos
Inmediato and # Oper $29  2  2
Página Cero and   Oper $25  2  3
Página Cero, x and   Oper, x $35  2  4
Absoluto and   Oper $2d  3  4
Absoluto, x and   Oper, x $3d  3  4*
Absoluto, y and   Oper, y $39  3  4*
(Indirecto, x) and  (Oper, x) $21  2  6
(Indirecto), y and  (Oper),y $31  2  5

Realiza un Y lógico entre el acumulador y el Operando de la memoria. El resultado de la operación "Y lógico" será 1 sólo cuando ambos patrones de bit sean igual a 1, en caso contrario el resultado será siempre 0.

Un uso muy común para and, es usarlo para desactivar determinados bits colocando un cero en el lugar que queramos desactivar, y poniendo unos en los lugares que queramos dejar inalterados, a través de una máscara de bits predeterminada. Para activar bits usariamos eor, y hariamos lo contrario: pondriamos en la máscara un 1 en los lugares que quisieramos tener el bit activado y ceros en los que queramos dejar inalterados.

Por Ejemplo, si queremos desactivar el bit 5 (y sólo ese bit) de la variable "valor":

lda valor // carga un valor en a
  and #%11011111 // máscara: cero en el bit 5, el resto unos
sta valor // actualiza valor (con el bit 5 apagado)

En el ejemplo, pongamos que valor = %11110010 (tendria el bit5 = 1)

Al ejecutar and, y guardarlo en valor, éste valdria %11010010. Sólo habria cambiado el valor del bit de la posición en la que habiamos puesto un 0 (en  la quinta posición).

 



BIT

 
Comprueba bits en memoria con el acumulador
(Test bits in memory with accumulator)
Operación: A & M, M7 => N, M6 => V
N Z C I D V
M7 x - - - M6
 
Modo de direccionamiento   Sintaxis Cód. Oper.  Nº. Bytes Nº. Ciclos
Página Cero bit   Oper $24  2  3
Absoluto bit   Oper $2c  3  4

Esta instrucción es una versión lógica de las operaciones de comparación, en las que el contenido del acumulador no se modifica, pero las banderas se ajustan al resultado obtenido.

Lo que hace es que el bit 6 (V, overflow) y el bit 7 (N, negative) del acumulador se transfieren al registro de estado. Si el resultado de A & M es cero, entonces Z=1, en cualquier otro caso Z=0

Se trata de una forma de testear bits importantes del acumulador sin afectar su contenido, como si sucederia si lo hicieramos con and, por ejemplo.



Instrucciones que modifican las banderas de Control


En este grupo se incluyen todas aquellas instrucciones que permiten modificar directamente las banderas, pero no todas las instrucciones que las afectan (¡casi todo el juego de instrucciones!). Éstas son las que afectan a las cuatro banderas que tienen que ver con decisiones de tipo lógico, oséase las banderas Zero, Carry, Negative y Overflow.

Sin embargo, instrucciones que afectan directamente a banderas de control, sólo podemos modificar la bandera de acarreo, (SEC, CLC) y borrar la bandera de rebasamiento con CLV. El resto de banderas se modifican operando con las instrucciones de carga y/o aritméticas pertinentes que indirectamente ajusten la bandera adecuada. Recordad que las instrucciones de almacenamiento del 6502 no modifican las banderas.

Tambien habria que incluir aqui las instrucciones PHP y PLP, y es que ellas solas guardan/recuperan en la pila el registro P (¡con todas las banderas!), pero sólo las mencionaré por aqui de pasada ya que se verán con más detalle cuando se hable de la pila.



SEC

 
Activa Bandera de Acarreo
(SEt Carry Flag)
Operación: 1 => C
N Z C I D V
- - 1 - - -
 
Modo de direccionamiento   Sintaxis Cód. Oper.  Nº. Bytes Nº. Ciclos
Implícito sec $38  1  2

Pone la bandera de acarreo (C) = 1.

CLC

 
Borra Bandera de Acarreo
(CLear Carry flag)
Operación: 0 => C
N Z C I D V
- - 0 - - -
 
Modo de direccionamiento   Sintaxis Cód. Oper.  Nº. Bytes Nº. Ciclos
Implícito clc $18  1  2

Pone la bandera de acarreo (C) = 0.

CLV

 
Borra la bandera de rebasamiento
(Clear OVerflow flag)
Operación: 0 => V
N Z C I D V
- - - - - 0
 
Modo de direccionamiento   Sintaxis Cód. Oper.  Nº. Bytes Nº. Ciclos
Implícito clv $b8  1  2

Borra la bandera de rebasamiento, V = 0.

Cabe destacar que no existe la instrucción equivalente para poner la bandera a uno.




Instrucciones que modifican las demás banderas


En este apartado veremos esas otras instrucciones que aunque no tengan que ver con banderas de control lógico si que permiten modificar el estado de esas otras banderas de estado.

BRK

 
Forzar Break (interrupción software)
(Forced Break)
Operación: Fuerza interrupción software, transf. a pila PC+2 y P
N Z C I D V
- - - x - -
 
Modo de direccionamiento   Sintaxis Cód. Oper.  Nº. Bytes Nº. Ciclos
Implícito brk $00  1  7

Esta instrucción fuerza una interrupción por software. El Sistema toma control y ejecuta una rutina de servicio de interrupción, que devuelve el sistema al BASIC. Sin embargo, el usuario puede cambiar el salto a esta rutina de interrupción.

Es una instrucción que resulta muy útil para crear "breakpoints" (puntos de interrupción del flujo del programa) a lo largo de los programas para facilitar así la depuración de posibles errores, ya que detendremos el flujo de ejecución en aquellos puntos que deseemos comprobar.


CLD

 
Desactiva modo Decimal
(CLear Decimal mode)
Operación: 0 => D
N Z C I D V
- - - - 0 -
 
Modo de direccionamiento   Sintaxis Cód. Oper.  Nº. Bytes Nº. Ciclos
Implícito cld $d8  1  2

Desactiva el modo decimal, D = 0.


CLI

 
Permite interrupciones.
(Clear Interrupt disable bit)
Operación: 0 => I
N Z C I D V
- - - 0 - -
 
Modo de direccionamiento   Sintaxis Cód. Oper.  Nº. Bytes Nº. Ciclos
Implícito cli $58  1  2

Desactiva la bandera de desactivación de interrupciones, I = 0, (con lo cual las permite).

SED

 
Activa modo Decimal
(SEt Decimal mode)
Operación: 1 => D
N Z C I D V
- - - - 1 -
 
Modo de direccionamiento   Sintaxis Cód. Oper.  Nº. Bytes Nº. Ciclos
Implícito sed $f8  1  2

Coloca el procesador en modo decimal (o BCD).


SEI

 
Deshabilita interrupciones.
(Set Interrupt disable status)
Operación: 1 => I
N Z C I D V
- - - 1 - -
 
Modo de direccionamiento   Sintaxis Cód. Oper.  Nº. Bytes Nº. Ciclos
Implícito sei $78  1  2

Activa la bandera de desactivación de interrupciones, I = 1, (con lo cual las deshabilita).



Instrucciones de Bifurcación Condicional


Como hay cuatro banderas de control lógico (Z,C,N,V) tenemos derivadas de éstas 8 instrucciones de salto condicional:

BEQ

 
Saltar si el resultado es cero
(Branch on result zero)
Operación: Salta si Z = 1
N Z C I D V
- - - - - -
 
* Añadir 1 si salto ocurre dentro de la misma página.
* Añadir 2 si salto ocurre en una página diferente.
Modo de direccionamiento   Sintaxis Cód. Oper.  Nº. Bytes Nº. Ciclos
Relativo beq   Oper $f0  2  2*

Si la bandera de cero = 1, salta un número de bytes indicado por el siguiente byte de la instrucción, en formato byte con signo, pudiendo avanzar (127 bytes) o retroceder (128 bytes).

BNE

 
Saltar si el resultado no es cero
(Branch on result not zero)
Operación: Salta si Z = 0
N Z C I D V
- - - - - -
 
* Añadir 1 si salto ocurre dentro de la misma página.
* Añadir 2 si salto ocurre en una página diferente.
Modo de direccionamiento   Sintaxis Cód. Oper.  Nº. Bytes Nº. Ciclos
Relativo bne   Oper $d0  2  2*

Si la bandera de cero = 0, salta un número de bytes indicado por el siguiente byte de la instrucción, en formato byte con signo, pudiendo avanzar (127 bytes) o retroceder (128 bytes).

BCS

 
Saltar si acarreo está a uno.
(Branch on Carry Set)
Operación: Salta si C = 1
N Z C I D V
- - - - - -
 
* Añadir 1 si salto ocurre dentro de la misma página.
* Añadir 2 si salto ocurre en una página diferente.
Modo de direccionamiento   Sintaxis Cód. Oper.  Nº. Bytes Nº. Ciclos
Relativo bcs   Oper $b0  2  2*

Si la bandera de acarreo = 1, salta un número de bytes indicado por el siguiente byte de la instrucción, en formato byte con signo, pudiendo avanzar (127 bytes) o retroceder (128 bytes).

BCC

 
Saltar si acarreo está a cero.
(Branch on Carry Clear)
Operación: Salta si C = 0
N Z C I D V
- - - - - -
 
* Añadir 1 si salto ocurre dentro de la misma página.
* Añadir 2 si salto ocurre en una página diferente.
Modo de direccionamiento   Sintaxis Cód. Oper.  Nº. Bytes Nº. Ciclos
Relativo bcc   Oper $90  2  2*

Si la bandera de acarreo = 0, salta un número de bytes indicado por el siguiente byte de la instrucción, en formato byte con signo, pudiendo avanzar (127 bytes) o retroceder (128 bytes).

BPL

 
Saltar si resultado Positivo
(Branch on result PLus)
Operación: Salta si N = 0
N Z C I D V
- - - - - -
 
* Añadir 1 si salto ocurre dentro de la misma página.
* Añadir 2 si salto ocurre en una página diferente.
Modo de direccionamiento   Sintaxis Cód. Oper.  Nº. Bytes Nº. Ciclos
Relativo bpl   Oper $10  2  2*

Si la bandera de negativo (N) = 0, salta un número de bytes indicado por el siguiente byte de la instrucción, en formato byte con signo, pudiendo avanzar (127 bytes) o retroceder (128 bytes).

BMI

 
Saltar si resultado Negativo
(Branch on result MInus)
Operación: Salta si N = 1
N Z C I D V
- - - - - -
 
* Añadir 1 si salto ocurre dentro de la misma página.
* Añadir 2 si salto ocurre en una página diferente.
Modo de direccionamiento   Sintaxis Cód. Oper.  Nº. Bytes Nº. Ciclos
Relativo bmi   Oper $30  2  2*

Si la bandera de negativo (N) = 1, salta un número de bytes indicado por el siguiente byte de la instrucción, en formato byte con signo, pudiendo avanzar (127 bytes) o retroceder (128 bytes).

BVS

 
Saltar si Rebasamiento está a 1
(Branch on oVerflow Set)
Operación: Salta si V = 1
N Z C I D V
- - - - - -
 
* Añadir 1 si salto ocurre dentro de la misma página.
* Añadir 2 si salto ocurre en una página diferente.
Modo de direccionamiento   Sintaxis Cód. Oper.  Nº. Bytes Nº. Ciclos
Relativo bvs   Oper $70  2  2*

Si la bandera de rebasamiento (V, overflow) = 1, salta un número de bytes indicado por el siguiente byte de la instrucción, en formato byte con signo, pudiendo avanzar (127 bytes) o retroceder (128 bytes).

BVC

 
Saltar si Rebasamiento está a 0
(Branch on oVerflow Clear)
Operación: Salta si V = 0
N Z C I D V
- - - - - -
 
* Añadir 1 si salto ocurre dentro de la misma página.
* Añadir 2 si salto ocurre en una página diferente.
Modo de direccionamiento   Sintaxis Cód. Oper.  Nº. Bytes Nº. Ciclos
Relativo bvc   Oper $50  2  2*

Si la bandera de rebasamiento (V, overflow) = 0, salta un número de bytes indicado por el siguiente byte de la instrucción, en formato byte con signo, pudiendo avanzar (127 bytes) o retroceder (128 bytes).

No hay comentarios:

Publicar un comentario en la entrada