INSTRUCCIONES ARITMÉTICAS Y LÓGICAS

El microprocesador Z-80 dispone de una unidad aritmética-lógica que le permite realizar una serie de operaciones, tanto aritméticas, como lógicas. Las aritméticas incluyen la suma y resta con o sin acarreo, incremento y decremento de un registro, comparaciones, ajuste decimal, complemento y negación. Las lógicas incluyen las operaciones que se realizan con los operadores "AND", "OR" y "XOR".

Antes de adentrarnos en el estudio de las instrucciones concretas, daremos una serie de definiciones útiles:

SUMA SIN ACARREO:

Consiste en sumar al contenido del registro "A" un número y obtener el resultado en el registro "A". El indicador de acarreo no se tiene en cuenta para esta operación. Su esquema sería:

A A+n

SUMA CON ACARREO:

Exactamente igual que la anterior, pero se suma también el indicador de acarreo del registro "F". De esta forma, sepuede incluir en la suma el acarreo procedente de una suma anterior. Su esquema sería:

A A+n+CF

RESTA SIN ACARREO:

Consiste en restar un número del contenido del registro "A", y obtener el resultado en este mismo registro. El indicador de acarreo no interviene en la operación. Se consideran números negativos los superiores a 127 (7Fh) de la forma que se explicó en el capítulo relativo a los sistemas de numeración; es decir, el número 255 (FFh) se considera "-1", el 254 (FEh) se considera "-2" y así sucesivamente, hasta 128 (80h) que se considera "-128". El paso de 127 a 128 o viceversa se indica poniendo a "1" el flag de "overflow" (P/V) del registro "F". Su esquema sería:

A A-n

RESTA CON ACARREO:

Igual que el anterior, salvo que también se resta el indicador de acarreo (CF) del registro "F". Su esquema sería:

A A-n-CF

INCREMENTO:

Consiste en sumar uno al contenido de un registro que se especifica en la instrucción. Su esquema es:

R R+1

Donde "R" representa un registro cualquiera de 8 a 16 bits. Si se trata de un registro doble (de 16 bits) se incrementa el registro de orden bajo (por ejemplo, en el "BC" se incrementa "C"), y si ello hace que este pase a valer "0", se incrementa también el de orden alto.

DECREMENTO:

Es la inversa de la anterior, consiste en restar uno al contenido de un registro. Su esquema es:

R R-1

Si se trata de un registro doble, se decrementa el de orden bajo y, si esto hace que pase a valer 255 (FFh), se decrementa también el de orden alto.

Si el registro incrementado o decrementado es de 8 bits, resultan afectados los indicadores del registro "F".

COMPARACIONES:

Estas instrucciones permiten comparar el contenido del acumulador con un número. Para ello, se resta el número del contenido del acumulador, pero el resultado no se almacena en ninguna parte, simplemente, se alteran determinados flags del registro "F", lo que nos indica si el número era menor, igual o mayor que el contenido del acumulador. Si era igual, se pone a "1" el flag "Z" (indicador de "cero"). Si el número era mayor, se pone a "1" el flag "S" (indicador de "signo").

AJUSTE DECIMAL:

Esta instrucción realiza un ajuste del contenido del acumulador para que, en vez de estar comprendido entre "00h" y "FFh", lo esté entre "00h" y "99h". Si se produce acarreo, se indica mediante el flag correspondiente. Para realizar esta operación se toma en cuenta el estado de los indicadores de "acarreo" (C) y "semi-acarreo" (H). Su finalidad es la de permitir realizar operaciones en "BCD" (Decimal Codificado en Binario).

COMPLEMENTO:

Consiste en realizar un "complemento a 1" del acumulador, es decir, cambiar los "unos" por "ceros" y los "ceros" por "unos".

NEGACIÓN:

Consiste en realizar un "complemento a 2" del acumulador, es decir, realizar un "complemento a 1" y, luego, sumarle "1". Lo que se obtiene es el "negativo" del número que teníamos en el acumulador. El efecto es el mismo que si restáramos el acumulador de "cero", es decir:

A 0-A

EL FLAG DE ACARREO:

Existen dos instrucciones que afectan al indicador de acarreo del registro "F", es posible ponerlo a "1" o "complementarlo" (ponerlo a "1" si era "0" y viceversa). No se ha previsto una instrucción para poner a "0" el flag de acarreo, dado que esto se puede conseguir haciendo un "AND" o un "OR" del acumulador consigo mismo.

Veamos ya las instrucciones:

Grupo de instrucciones aritméticas para 8 bits

En este grupo de instrucciones los registros usados se indican con "r" según el siguiente código:

"r"
código
A
111
B
000
C
001
D
010
E
011
H
100
L
101

ADD, «sumar» en inglés: La función básica de esta instrucción es sumar sobre el registro acumulador el valor indicado por el operando. Ejecuta una suma binaria de ambos datos y no altera el contenido del operando.

ADD A,r
OBJETO:
Suma el registro acumulador "A" con el registro indicado por "r", dejando el resultado en el registro acumulador.
CODIGO MAQUINA:
1 0 0 0 0 <--- r --->
INDICADORES DE CONDICIÓN A LOS QUE AFECTA:
S
;
pone 1 - si el resultado es negativo
pone 0 - en cualquier otro caso
Z
;
pone 1 - si el resultado es cero
pone 0 - en cualquier otro caso
H
;
pone 1 - si hay acarreo desde el bit 3
pone 0 - en cualquier otro caso
N
;
pone 0 - siempre
C
;
pone 1 - si hay acarreo desde el bit 7
pone 0 - en cualquier otro caso
P/V
;
pone 1 - si hay desbordamiento (overflow)
pone 0 - en cualquier otro caso

NOTA: Se entiende que hay acarreo desde el bit 3 cuando éste pasa de ser "1" a ser "0". Se entiende que hay desbordamiento si el resultado pasa de ser "positivo" a ser "negativo" o viceversa. Estas observaciones son válidas para todas las operaciones aritméticas.

CICLOS DE MEMORIA:
1
CICLOS DE RELOJ:
4

EJEMPLO:

ADD A,B

Valor del registro "A":

(A):
0 0 1 0 1 0 0 1
29h

Valor del registro "B":

(B):
0 1 0 0 1 0 1 0
4Ah

Ejecutamos la instrucción:

ADD A,B:
1 0 0 0 0 0 0 0
80h

Valor del registro "A" después de la ejecución:

(A):
0 1 1 1 0 0 1 1
73h

El valor del registro "B" después de la ejecución no varía.

Indicadores de condición después de la ejecución:

S
Z
H
P/V
N
C
0
0
x
1
x
0
0
0

Observe que hubo acarreo desde el bit 3.

ADD A,n
OBJETO:
Suma el registro acumulador "A" con el número entero de 8 bits "n", dejando el resultado en el registro acumulador.
CODIGO MAQUINA:
1 1 0 0 0 1 1 0
<-------- n -------->
C6h
 
INDICADORES DE CONDICIÓN A LOS QUE AFECTA:
S
;
pone 1 - si el resultado es negativo
pone 0 - en cualquier otro caso
Z
;
pone 1 - si el resultado es cero
pone 0 - en cualquier otro caso
H
;
pone 1 - si hay acarreo desde el bit 3
pone 0 - en cualquier otro caso
N
;
pone 0 - siempre
C
;
pone 1 - si hay acarreo desde el bit 7
pone 0 - en cualquier otro caso
P/V
;
pone 1 - si hay desbordamiento (overflow)
pone 0 - en cualquier otro caso
CICLOS DE MEMORIA:
2
CICLOS DE RELOJ:
7

EJEMPLO:

ADD A,24

Valor del registro "A":

(A):
0 0 1 0 0 1 1 0
26h

Instrucción:

ADD A,24:
1 1 0 0 0 1 1 0
0 0 0 1 1 0 0 0
C6h
18h

Valor del registro "A" después de la ejecución:

(A):
0 0 1 1 1 1 1 0
3Eh

Indicadores de condición después de la ejecución:

S
Z
H
P/V
N
C
0
0
x
0
x
0
0
0
ADD A,(HL)
OBJETO:
Suma el registro acumulador "A" con el octeto de la posición de memoria direccionada por el contenido del par de registros "HL", y deja el resultado en el registro acumulador.
CODIGO MAQUINA:
1 0 0 0 0 1 1 0
86h
INDICADORES DE CONDICIÓN A LOS QUE AFECTA:
S
;
pone 1 - si el resultado es negativo
pone 0 - en cualquier otro caso
Z
;
pone 1 - si el resultado es cero
pone 0 - en cualquier otro caso
H
;
pone 1 - si hay acarreo desde el bit 3
pone 0 - en cualquier otro caso
N
;
pone 0 - siempre
C
;
pone 1 - si hay acarreo desde el bit 7
pone 0 - en cualquier otro caso
P/V
;
pone 1 - si hay desbordamiento (overflow)
pone 0 - en cualquier otro caso
CICLOS DE MEMORIA:
2
CICLOS DE RELOJ:
7

EJEMPLO:

ADD A,(HL)

Valor del par de registros "HL":

(H):
(L):
0 1 0 0 1 1 0 0
1 1 1 1 0 0 1 1
4Ch
F3h

Valor de la posición de memoria 4CF3h:

(4CF3h):
1 0 0 1 1 1 0 0
9Ch

Valor del registro "A":

(A):
1 0 1 1 0 0 0 0
B0h

Instrucción:

ADD A,(HL):
1 0 0 0 0 1 1 0
86h

Valor del registro "A" después de la ejecución:

(A):
0 1 0 0 1 1 0 0
46h

Indicadores de condición después de la ejecución:

S
Z
H
P/V
N
C
0
0
x
0
x
0
0
1

Observe, que ha habido acarreo desde el bit 7.

ADD A,(IX+d)
OBJETO:
Suma el registro acumulador "A" con el octeto de la posición de memoria direccionada por el valor que resulta de: añadir al contenido del registro índice "IX" el entero de desplazamiento "d", el cual puede adquirir los valores desde -128 a +127. Deja el resultado en el registro acumulador.
CODIGO MAQUINA:
1 1 0 1 1 1 0 1
1 0 0 0 0 1 1 0
<-------- d -------->
DDh
86h
 
INDICADORES DE CONDICIÓN A LOS QUE AFECTA:
S
;
pone 1 - si el resultado es negativo
pone 0 - en cualquier otro caso
Z
;
pone 1 - si el resultado es cero
pone 0 - en cualquier otro caso
H
;
pone 1 - si hay acarreo desde el bit 3
pone 0 - en cualquier otro caso
N
;
pone 0 - siempre
C
;
pone 1 - si hay acarreo desde el bit 7
pone 0 - en cualquier otro caso
P/V
;
pone 1 - si hay desbordamiento (overflow)
pone 0 - en cualquier otro caso
CICLOS DE MEMORIA:
5
CICLOS DE RELOJ:
19

EJEMPLO:

ADD A,(IX+7)

Suponemos que el registro "A" contiene el número 80h (128) y vamos a sumarle el contenido de la posición de memoria 9318h que suponemos que es también 80h (128). Para acceder a esta posición utilizamos direccionamiento indexado. El resultado deberá ser 256, es decir, 100h; pero como este número excede la capacidad del acumulador, obtendremos "00h" en el acumulador y "1" en el indicador de acarreo.

Esto ocurrirá con frecuencia. Cuando el resultado de una suma sea mayor de 255 (FFh), nos aparecerá el flag de acarreo a "1", y el acumulador contendrá ese número menos 256, para los matemáticos, lo que obtenemos en el acumulador es el "módulo 256" del resultado de la suma. Cuando, después de una suma, el indicador de acarreo sea "1", podemos saber el verdadero resultado si sumamos 256 al contenido del acumulador. Veamos ahora el ejemplo.

Valor del registro "IX":

(IX):
1 0 0 1 0 0 1 1
0 0 0 1 0 0 0 1
93h
11h

Valor de la posición de memoria 9318h:

(9318h):
1 0 0 0 0 0 0 0
80h

Valor del registro "A":

(A):
1 0 0 0 0 0 0 0
80h

Instrucción:

ADD A,(IX+7):
1 1 0 1 1 1 0 1
1 0 0 0 0 1 1 0
0 0 0 0 0 1 1 1
DDh
86h
07h

Valor del registro "A" después de la ejecución:

(A):
0 0 0 0 0 0 0 0
00h

Indicadores de condición después de la ejecución:

S
Z
H
P/V
N
C
0
1
x
0
x
1
0
1

Observe que se nos han puesto a "1" los indicadores de acarreo, cero y rebosamiento. El de acarreo, porque el resultado es mayor de 255; el de cero, porque el acumulador contiene "cero"; y el de rebosamiento, porque el bit 7 ha pasado de ser "1" a "0", lo que se interpreta como un cambio de signo; en este caso, el signo no nos interesa porque el numero no puede ser negativo, por lo que, simplemente, ignoramos el indicador "P/V".

ADD A,(IY+d)
OBJETO:
Suma el registro acumulador "A" con el octeto de la posición de memoria direccionada por el valor que resulta de: añadir al contenido del registro índice "IY" el entero de desplazamiento "d", el cual puede adquirir los valores desde -128 a +127. Deja el resultado en el registro acumulador.
CODIGO MAQUINA:
1 1 1 1 1 1 0 1
1 0 0 0 0 1 1 0
<-------- d -------->
FDh
86h
 
INDICADORES DE CONDICIÓN A LOS QUE AFECTA:
S
;
pone 1 - si el resultado es negativo
pone 0 - en cualquier otro caso
Z
;
pone 1 - si el resultado es cero
pone 0 - en cualquier otro caso
H
;
pone 1 - si hay acarreo desde el bit 3
pone 0 - en cualquier otro caso
N
;
pone 0 - siempre
C
;
pone 1 - si hay acarreo desde el bit 7
pone 0 - en cualquier otro caso
P/V
;
pone 1 - si hay desbordamiento (overflow)
pone 0 - en cualquier otro caso
CICLOS DE MEMORIA:
5
CICLOS DE RELOJ:
19

EJEMPLO:

ADD A,(IY-6)

En esta ocasión vamos a usar, de nuevo, direccionamiento indexado para acceder al operando. Los dos números a sumar serán 7Fh y 03h, el resultado será 82h (F más 3 = 2 y nos llevamos una; 7 más 0 más 1 = 8). Como se vé, sumar en hexadecimal es lo mismo que hacerlo en decimal.

Valor del registro "IY":

(IY):
1 0 1 0 0 0 1 1
0 1 1 1 1 0 0 0
A3h
78h

Valor de la posición de memoria A372h:

(A372h):
0 1 1 1 1 1 1 1
7Fh

Valor del registro "A":

(A):
0 0 0 0 0 0 1 1
03h

Instrucción:

ADD A,(IY-6):
1 1 1 1 1 1 0 1
1 0 0 0 0 1 1 0
1 1 1 1 1 0 1 0
FDh
86h
FAh

Valor del registro "A" después de la ejecución:

(A):
1 0 0 0 0 0 1 0
82h

Indicadores de condición después de la ejecución:

S
Z
H
P/V
N
C
1
0
x
1
x
1
0
0

Observe, que el indicador de signo (S) se activa por estar activo el bit 7, el tratar este número como negativo o no, dependerá del programador. El indicador P/V se activa por superar el máximo valor del octeto en complemento a dos (el bit de signo ha pasado de "0" a "1"). Finalmente, el indicador H está a "1" porque hubo acarreo desde el bit 3.

Las instrucciones de sumar, como su nombre indica, suman; pero con lo visto hasta el momento sólo suman un octeto. Por lo tanto se limita la suma al número 255, considerando todos los positivos.

Este problema se soluciona con las instrucciones que se explican a continuación.

ADC (ADd with Carry), sumar con acarreo. Básicamente consiste en una suma binaria de dos octetos más el bit de acarreo. Esto quiere decir que si en una suma anterior el bit de acarreo está activo, "nos llevamos una", esa unidad hay que tenerla en cuenta en el octeto superior si existe.

Por ejemplo en una suma convencional en decimal.

7328 + 4256

al sumar las unidades 8 y 6 nos llevamos un 1 a las decenas; con las decenas y las centenas no hay acarreo, y de nuevo en las unidades de millar hay acarreo a las decenas de millar.

1
1
acarreo
7
3
2
8
+
4
2
5
6
1
1
5
8
4

Visto esto, se entenderá fácilmente, que sumando octetos se acarrea 1 al octeto superior cuando se supera el valor decimal 255 (FFh). Ver figura 6-1.

BINARIO

11000110
10011100
01001001
10000000
SUMANDO
00011000
10110000
00111010
10000000
SUMANDO
0
+
1
0
1
ACARREO

11011111
01001100
10000100
00000000
RESULTADO


HEXADECIMAL

C6
9C
49
80
SUMANDO
18
B0
3A
80
SUMANDO
+
1
0
1
ACARREO

DF
4C
84
00
RESULTADO


DECIMAL

190
156
73
128
SUMANDO
24
176
58
128
SUMANDO
+
1
0
1
ACARREO

223
76
132
0
RESULTADO
Fig 6-1. Suma de varios objetos con acarreo.

Esta es la manera de sumar, en binario, cantidades superiores a 255 decimal; usando las instrucciones que se describen a continuación.

ADC A,r
OBJETO:
Suma el registro acumulador "A", más el bit de acarreo, con el registro indicado por "r", dejando el resultado en el registro acumulador.
CODIGO MAQUINA:
1 0 0 0 1 <--- r --->
INDICADORES DE CONDICIÓN A LOS QUE AFECTA:
S
;
pone 1 - si el resultado es negativo
pone 0 - en cualquier otro caso
Z
;
pone 1 - si el resultado es cero
pone 0 - en cualquier otro caso
H
;
pone 1 - si hay acarreo desde el bit 3
pone 0 - en cualquier otro caso
N
;
pone 0 - siempre
C
;
pone 1 - si hay acarreo desde el bit 7
pone 0 - en cualquier otro caso
P/V
;
pone 1 - si hay desbordamiento (overflow)
pone 0 - en cualquier otro caso

NOTA: Se entiende que hay acarreo desde el bit 3 cuando éste pasa de ser "1" a ser "0". Se entiende que hay desbordamiento si el resultado pasa de ser "positivo" a ser "negativo" o viceversa. Estas observaciones son válidas para todas las operaciones aritméticas.

CICLOS DE MEMORIA:
1
CICLOS DE RELOJ:
4

EJEMPLO:

ADC A,D

Suponemos que tenemos el flag de acarreo a "1", puede ser, por ejemplo, como resultado de una suma anterior. Por tanto, vamos a sumar 49h + 22h + 1. El resultado debe ser 6Ch.

Valor del registro "A":

(A):
0 1 0 0 1 0 0 1
49h

Valor del registro "D":

(D):
0 0 1 0 0 0 1 0
22h

Bit de acarreo = 1

Ejecutamos la instrucción:

ADC A,D:
1 0 0 0 1 0 1 0
8Ah

Valor del registro "A" después de la ejecución:

(A):
0 1 1 0 1 1 0 0
6Ch

Indicadores de condición después de la ejecución:

S
Z
H
P/V
N
C
0
0
x
0
x
0
0
0

Esta vez no ha habido acarreo, semi-acarreo ni cambio de signo.

ADC A,n
OBJETO:
Suma el registro acumulador "A", más el bit de acarreo, con el número entero de 8 bits "n", dejando el resultado en el registro acumulador.
CODIGO MAQUINA:
1 1 0 0 1 1 1 0
<-------- n -------->
CEh
 
INDICADORES DE CONDICIÓN A LOS QUE AFECTA:
S
;
pone 1 - si el resultado es negativo
pone 0 - en cualquier otro caso
Z
;
pone 1 - si el resultado es cero
pone 0 - en cualquier otro caso
H
;
pone 1 - si hay acarreo desde el bit 3
pone 0 - en cualquier otro caso
N
;
pone 0 - siempre
C
;
pone 1 - si hay acarreo desde el bit 7
pone 0 - en cualquier otro caso
P/V
;
pone 1 - si hay desbordamiento (overflow)
pone 0 - en cualquier otro caso
CICLOS DE MEMORIA:
2
CICLOS DE RELOJ:
7

EJEMPLO:

ADC A,120

Vamos a sumar A5h (165) más 78h (120) más 1, porque suponemos que el indicador de acarreo está a "1". El resultado deberá ser 11Eh (286); puesto que este resultado excede la capacidad del acumulador, el indicador de acarreo se pondrá a "1" y el acumulador contendrá 1Eh (30). Podemos comprobar que 256 + 30 = 286, por tanto, el resultado es correcto.

Valor del registro "A":

(A):
1 0 1 0 0 1 0 1
A5h

Bit de acarreo = 1

Instrucción:

ADC A,120:
1 1 0 0 1 1 1 0
0 1 1 1 1 0 0 0
CEh
78h

Valor del registro "A" después de la ejecución:

(A):
0 0 0 1 1 1 1 0
1Eh

Indicadores de condición después de la ejecución:

S
Z
H
P/V
N
C
0
0
x
0
x
0
0
1

Como indicábamos antes, se nos ha "levantado" el flag de acarreo para indicar que el verdadero resultado es 256 más el contenido del acumulador. Si ahora sumáramos otros dos octetos de orden superior a éstos, deberíamos tener en cuenta el acarreo.

ADC A,(HL)
OBJETO:
Suma el registro acumulador "A", más el bit de acarreo, con el octeto de la posición de memoria direccionada por el contenido del par de registros "HL", y deja el resultado en el registro acumulador.
CODIGO MAQUINA:
1 0 0 0 1 1 1 0
8Eh
INDICADORES DE CONDICIÓN A LOS QUE AFECTA:
S
;
pone 1 - si el resultado es negativo
pone 0 - en cualquier otro caso
Z
;
pone 1 - si el resultado es cero
pone 0 - en cualquier otro caso
H
;
pone 1 - si hay acarreo desde el bit 3
pone 0 - en cualquier otro caso
N
;
pone 0 - siempre
C
;
pone 1 - si hay acarreo desde el bit 7
pone 0 - en cualquier otro caso
P/V
;
pone 1 - si hay desbordamiento (overflow)
pone 0 - en cualquier otro caso
CICLOS DE MEMORIA:
2
CICLOS DE RELOJ:
7

EJEMPLO:

ADC A,(HL)

Valor del par de registros "HL":

(H):
(L):
0 1 1 1 0 1 1 0
1 0 0 0 1 1 1 0
76h
8Eh

Valor de la posición de memoria 768Eh:

(768Eh):
1 0 0 0 1 1 0 1
8Dh

Valor del registro "A":

(A):
0 0 1 0 1 0 0 1
29h

Instrucción:

ADC A,(HL):
1 0 0 0 1 1 1 0
8Eh

Valor del registro "A" después de la ejecución:

(A):
1 0 1 1 0 1 1 1
B7h

Indicadores de condición después de la ejecución:

S
Z
H
P/V
N
C
1
0
x
1
x
0
0
0
ADC A,(IX+d)
OBJETO:
Suma el registro acumulador "A", más el bit de acarreo, con el octeto de la posición de memoria direccionada por el valor que resulta de: añadir al contenido del registro índice "IX" el entero de desplazamiento "d", el cual puede adquirir los valores desde -128 a +127. Deja el resultado en el registro acumulador.
CODIGO MAQUINA:
1 1 0 1 1 1 0 1
1 0 0 0 1 1 1 0
<-------- d -------->
DDh
8Eh
 
INDICADORES DE CONDICIÓN A LOS QUE AFECTA:
S
;
pone 1 - si el resultado es negativo
pone 0 - en cualquier otro caso
Z
;
pone 1 - si el resultado es cero
pone 0 - en cualquier otro caso
H
;
pone 1 - si hay acarreo desde el bit 3
pone 0 - en cualquier otro caso
N
;
pone 0 - siempre
C
;
pone 1 - si hay acarreo desde el bit 7
pone 0 - en cualquier otro caso
P/V
;
pone 1 - si hay desbordamiento (overflow)
pone 0 - en cualquier otro caso
CICLOS DE MEMORIA:
5
CICLOS DE RELOJ:
19

EJEMPLO:

ADD A,(IX-3)

Valor del registro "IX":

(IX):
1 0 0 0 0 1 1 1
1 0 1 0 1 0 1 0
87h
AAh

Valor de la posición de memoria 87A7h:

(87A7h):
0 0 0 0 0 0 0 1
01h

Valor del registro "A":

(A):
0 1 1 1 1 1 1 1
7Fh

Bit de acarreo = 0

Instrucción:

ADD A,(IX-3):
1 1 0 1 1 1 0 1
1 0 0 0 1 1 1 0
1 1 1 1 1 1 0 1
DDh
8Eh
FDh

Valor del registro "A" después de la ejecución:

(A):
1 0 0 0 0 0 0 0
80h

Indicadores de condición después de la ejecución:

S
Z
H
P/V
N
C
1
0
x
1
x
1
0
0
ADC A,(IY+d)
OBJETO:
Suma el registro acumulador "A", más el bit de acarreo, con el octeto de la posición de memoria direccionada por el valor que resulta de: añadir al contenido del registro índice "IY" el entero de desplazamiento "d", el cual puede adquirir los valores desde -128 a +127. Deja el resultado en el registro acumulador.
CODIGO MAQUINA:
1 1 1 1 1 1 0 1
1 0 0 0 1 1 1 0
<-------- d -------->
FDh
8Eh
 
INDICADORES DE CONDICIÓN A LOS QUE AFECTA:
S
;
pone 1 - si el resultado es negativo
pone 0 - en cualquier otro caso
Z
;
pone 1 - si el resultado es cero
pone 0 - en cualquier otro caso
H
;
pone 1 - si hay acarreo desde el bit 3
pone 0 - en cualquier otro caso
N
;
pone 0 - siempre
C
;
pone 1 - si hay acarreo desde el bit 7
pone 0 - en cualquier otro caso
P/V
;
pone 1 - si hay desbordamiento (overflow)
pone 0 - en cualquier otro caso
CICLOS DE MEMORIA:
5
CICLOS DE RELOJ:
19

EJEMPLO:

ADC A,(IY+25)

Valor del registro "IY":

(IY):
1 1 1 1 0 0 0 0
1 0 0 1 0 0 0 1
F0h
91h

Valor de la posición de memoria F0AAh:

(F0AAh):
0 0 0 0 1 1 1 1
0Fh

Valor del registro "A":

(A):
1 1 1 1 0 0 0 0
F0h

Bit de acarreo = 0

Instrucción:

ADC A,(IY+25):
1 1 1 1 1 1 0 1
1 0 0 0 1 1 1 0
0 0 0 1 1 0 0 1
FDh
8Eh
19h

Valor del registro "A" después de la ejecución:

(A):
1 1 1 1 1 1 1 1
FFh

Indicadores de condición después de la ejecución:

S
Z
H
P/V
N
C
1
0
x
0
x
0
0
0

La actividad de los indicadores, de condición, tanto en la suma (ADD) como en la suma con acarreo (ADC), se hace según las siguientes condiciones:

"S": En este indicador se pone el mismo valor que tenga el bit siete del acumulador después de la ejecución.

"Z": Este indicador se activa, valor igual a 1, siempre que todos los bits del registro acumulador sean cero después de la ejecución.

"H": Este indicador de acarreo desde el bit 3, se activa siempre que los cuatro bits inferiores del registro acumulador superen el valor Fh (15 decimal) después de la ejecución. Esto es independiente del valor que tengan los cuatro bits superiores.

"N": Este indicador no tiene significado para este grupo de instrucciones y se pone siempre a 0.

"C": Este indicador de acarreo desde el bit 7, se activa siempre que el registro acumulador supere el valor FFh ( 355 decimal) después de la ejecución.

"P/V": Este indicador de desbordamiento (overflow), se activa si, después de la ejecución, el registro acumulador supera el valor +127 o -128. Esto es, indica el cambio de signo del número en complemento a 2.

SUB (SUBstract), "restar" en inglés. Básicamente esta función consiste en restar del registro acumulador el valor indicado por el operando. Esto es una resta binaria en la que el registro acumulador es el minuendo y el operando indica el sustraendo.

La operación real que efectúa el microprocesador es: complementar a dos el sustraendo y sumarlo con el minuendo. Conocer esta operativa es interesante para entender cómo funciona el acarreo, pero no es necesario tenerla presente en el momento de construir el programa.

En una resta algebraica el sustraendo es un número negativo y como se sabe para el microprocesador Z80, los números negativos se expresan con el complemento a 2. Por lo tanto la resta para el ordenador es la suma de un número positivo (minuendo) con un número negativo (sustraendo); y dependiendo de los valores absolutos, el resultado será un número negativo o positivo.

SUB r
OBJETO:
Resta del registro acumulador "A" el contenido del registro especificado por "r", dejando el resultado en el registro acumulador.
CODIGO MAQUINA:
1 0 0 1 0 <--- r --->
INDICADORES DE CONDICIÓN A LOS QUE AFECTA:
S
;
pone 1 - si el resultado es negativo
pone 0 - en cualquier otro caso
Z
;
pone 1 - si el resultado es cero
pone 0 - en cualquier otro caso
H
;
pone 1 - si no hay acarreo desde el bit 3
pone 0 - en cualquier otro caso
N
;
pone 1 - siempre
C
;
pone 1 - si no hay acarreo desde el bit 7
pone 0 - en cualquier otro caso
P/V
;
pone 1 - si hay desbordamiento (overflow)
pone 0 - en cualquier otro caso
CICLOS DE MEMORIA:
1
CICLOS DE RELOJ:
4

EJEMPLO:

SUB B

En este ejemplo, vamos a restar el contenido del registro "B" del contenido del acumulador "A". La operación se podría representar como:

A A-B

Valor del registro "A":

(A):
0 0 1 1 0 1 0 1
35h

Valor del registro "B":

(B):
0 0 0 1 0 0 1 1
13h

Instrucción:

SUB B:
1 0 0 1 0 0 0 0
90h

Operación:

00110101
+
11101101
00100010

El valor del registro "B" después de la ejecución, no varía.

Valor del registro "A" después de la ejecución:

(A):
0 0 1 0 0 0 1 0
22h

Indicadores de condición después de la ejecución:

S
Z
H
P/V
N
C
0
0
x
0
x
0
1
0

En este caso, el resultado ha sido positivo y no ha habido acarreo ni desbordamiento. Vemos que el indicador "N" (SUMA/RESTA) se ha puesto a "1"; al igual que todas las instrucciones de suma ponían este indicador a "cero", todas las de resta lo ponen a "uno".

Vamos a ver detenidamente lo que ha ocurrido: Le hemos pedido al microprocesador que reste 35h menos 13h. Como el segundo número es menor que el primero, el resultado será positivo; concretamente el resultado deberá ser 22h. El microprocesador coje primero el número 13h y le hace el complemento a 2 (lo cambia de signo) resultando EDh. A continuación, suma 35h +EDh, de lo que resulta 22h y un acarreo de "1". Como estamos restando, invertimos el acarreo, con lo que resulta el número 22h sin acarreo.

Vamos a ver qué hubiera ocurrido de hacerlo al revés: restemos 13h menos 35h. El resultado deberá ser -(22h), es decir, el complemento a 2 de 22h o, lo que es lo mismo, DEh. Primero cojemos el número 35h y lo complementamos a 2 (lo cambiamos de signo) obteniendo CBh. Ahora, sumamos 13h más CBh y obtenemos DEh con un acarreo de "cero". Como complementamos el acarreo, resulta ser "uno", con lo que sabemos que se trata de un resultado negativo. Efectivamente, si complementamos a 2 el número DEh, obtenemos 22h que es lo que teníamos que obtener.

SUB n
OBJETO:
Resta del registro acumulador "A" el entero de 8 bits "n", dejando el resultado en el registro acumulador.
CODIGO MAQUINA:
1 1 0 1 0 1 1 0
<-------- d -------->
D6h
 
INDICADORES DE CONDICIÓN A LOS QUE AFECTA:
S
;
pone 1 - si el resultado es negativo
pone 0 - en cualquier otro caso
Z
;
pone 1 - si el resultado es cero
pone 0 - en cualquier otro caso
H
;
pone 1 - si no hay acarreo desde el bit 3
pone 0 - en cualquier otro caso
N
;
pone 1 - siempre
C
;
pone 1 - si no hay acarreo desde el bit 7
pone 0 - en cualquier otro caso
P/V
;
pone 1 - si hay desbordamiento (overflow)
pone 0 - en cualquier otro caso
CICLOS DE MEMORIA:
2
CICLOS DE RELOJ:
7

EJEMPLO:

SUB 12

En este caso, el sustraendo es mayor que el minuendo, por lo que el resultado deberá ser negativo. Veamos qué ocurre:

Valor del registro "A":

(A):
0 0 0 0 0 1 0 1
05h

Instrucción:

SUB 12:
1 1 0 1 0 1 1 0
0 0 0 0 1 1 0 0
D6h
0Ch

Operación:

00000101
+
11110100
11111001

Valor del registro "A" después de la ejecución:

(A):
1 1 1 1 1 0 0 1
F9h

Indicadores de condición después de la ejecución:

S
Z
H
P/V
N
C
1
0
x
1
x
0
1
1

Observamos que cuando el minuendo es menor que el sustraendo no hay acarreo en la suma que realiza el microprocesador, por tanto, se activa el indicador "C" que, como sabemos, va invertido cuando se resta.

El resultado de la operación es F9h, es decir, -7 expresado en complemento a 2.

SUB (HL)
OBJETO:
Resta del registro acumulador "A" el valor del octeto de memoria direccionado por el contenido del par de registros "HL". El resultado se deja en el registro acumulador.
CODIGO MAQUINA:
1 0 0 1 0 1 1 0
96h
INDICADORES DE CONDICIÓN A LOS QUE AFECTA:
S
;
pone 1 - si el resultado es negativo
pone 0 - en cualquier otro caso
Z
;
pone 1 - si el resultado es cero
pone 0 - en cualquier otro caso
H
;
pone 1 - si no hay acarreo desde el bit 3
pone 0 - en cualquier otro caso
N
;
pone 1 - siempre
C
;
pone 1 - si no hay acarreo desde el bit 7
pone 0 - en cualquier otro caso
P/V
;
pone 1 - si hay desbordamiento (overflow)
pone 0 - en cualquier otro caso
CICLOS DE MEMORIA:
2
CICLOS DE RELOJ:
7

EJEMPLO:

SUB (HL)

Valor del par de registros "HL":

(H):
(L):
0 1 1 1 1 0 1 1
0 1 1 0 0 0 1 0
7Bh
62h

Valor de la posición de memoria 7B62h:

(7B62h):
0 0 1 1 1 0 1 0
3Ah

Valor del registro "A":

(A):
0 1 1 0 1 1 1 1
6Fh

Instrucción:

SUB (HL):
1 0 0 1 0 1 1 0
96h

Operación:

01101111
+
11000110
00110101

Valor del registro "A" después de la ejecución:

(A):
0 0 1 1 0 1 0 1
35h

Indicadores de condición después de la ejecución:

S
Z
H
P/V
N
C
0
0
x
0
x
0
1
0

El funcionamiento del indicador "P/V" (Paridad/Rebosamiento) requiere una explicación por tratarse de uno de los puntos más oscuros de la programación en C/M. Este indicador tiene una doble función, en las operaciones lógicas actúa como indicador de paridad y en las aritméticas, como indicador de rebosamiento. Su función como indicador de paridad se verá cuando estudiemos las operaciones lógicas; ahora vamos a ver cómo actúa para indicarnos un rebosamiento.

Sabemos que nos es posible trabajar con números negativos si consideramos negativo a todo número cuyo bit de más a la izquierda sea "1". En el caso de trabajar sólo con positivos, el rango permitido va de "0" a "FFh" (255) y si, tras una suma, el número resultante pasa de este rango, se nos pone a "1" el indicador de acarreo "C". Por otro lado, es posible que estemos trabajando con números positivos y negativos, en este caso, el rango permitido es de "80h" (-128) a "7Fh" (+127). El microprocesador nunca sabe cómo vamos a considerar el número contenido en el acumulador, así que, por si acaso, nos indica también si está fuera de este rango, poniendo a "1" el indicador de rebosamiento "P/V".

Vemos, por tanto, que "P/V" se pondrá a "1" siempre que un número pase de ser positivo a ser negativo, o viceversa, sin pasar por cero. Para verlo más claro, representemos todos los valores posibles en una recta que vaya desde "0" a "255"; en mitad de la recta tenemos el número "127". Cuando el contenido del acumulador pase de una mitad de una recta a otra a través del número "127", se pone a "1" el indicador "P/V" y cuando lo haga a través del número "255" y "0", se pone a "1" el indicador "C".

Veamos un ejemplo: Tenemos en el acumulador el número "7Fh" (127) y le sumamos "1", el resultado será "80h" que puede ser 128 o -128, según consideremos el número como positivo o como negativo; en este caso, se nos habrá puesto a "1" el indicador "P/V". Supongamos ahora que tenemos el número "FFh" que puede ser 255 o -1; si le sumamos "1", obtenemos como resultado "0"; en este caso, se habrá puesto a "1" el indicador de acarreo "C".

Otro tanto ocurriría si restáramos "1" a "80h", obtendríamos "7Fh" y "P/V" a "1". O si restáramos "1" a "0", resultaría "FFh" y el indicador "C" a "1". Cuando trabajemos sólo con números positivos, tendremos que tomar en cuenta el indicador "C", y cuando lo hagamos con números positivos y negativos, tomaremos en cuenta el indicador "P/V".

SUB (IX+d)
OBJETO:
Resta al contenido del registro acumulador, el valor del octeto de memoria direccionado por el valor que resulta de: añadir al contenido del registro índice IX el entero de desplazamiento d, el cual puede adquirir los valores desde -128 a +127.
CODIGO MAQUINA:
1 1 0 1 1 1 0 1
1 0 0 1 0 1 1 0
<-------- d -------->
DDh
96h
 
INDICADORES DE CONDICIÓN A LOS QUE AFECTA:
S
;
pone 1 - si el resultado es negativo
pone 0 - en cualquier otro caso
Z
;
pone 1 - si el resultado es cero
pone 0 - en cualquier otro caso
H
;
pone 1 - si no hay acarreo desde el bit 3
pone 0 - en cualquier otro caso
N
;
pone 1 - siempre
C
;
pone 1 - si no hay acarreo desde el bit 7
pone 0 - en cualquier otro caso
P/V
;
pone 1 - si hay desbordamiento (overflow)
pone 0 - en cualquier otro caso
CICLOS DE MEMORIA:
5
CICLOS DE RELOJ:
19

EJEMPLO:

SUB (IX+24)

Valor del registro "IX":

(IX):
1 0 0 0 0 1 0 1
0 1 1 1 0 0 1 1
85h
73h

Valor de la posición de memoria 858Bh:

(858Bh):
0 0 1 1 0 1 1 0
36h

Valor del registro "A":

(A):
1 0 0 1 0 0 0 1
91h

Instrucción:

SUB (IX+24):
1 1 0 1 1 1 0 1
1 0 0 1 0 1 1 0
0 0 0 1 1 0 0 0
DDh
96h
18h

Operación:

10010001
+
11001010
01011011

Valor del registro "A" después de la ejecución:

(A):
0 1 0 1 1 0 1 1
5Bh

Indicadores de condición después de la ejecución:

S
Z
H
P/V
N
C
0
0
x
1
x
1
1
0

En este caso, hemos restado 91h menos 36h, obteniendo 5Bh. El número 81h puede ser negativo (-111) y 5Bh es siempre positivo, de forma que el microprocesador nos pone a "1" el indicador "P/V" por si estábamos considerando los números como negativos.

SUB (IY+d)
OBJETO:
Resta al contenido del registro acumulador, el valor del octeto de memoria direccionado por el valor que resulta de: añadir al contenido del registro índice IY el entero de desplazamiento d, el cual puede adquirir los valores desde -128 a +127.
CODIGO MAQUINA:
1 1 1 1 1 1 0 1
1 0 0 1 0 1 1 0
<-------- d -------->
FDh
96h
 
INDICADORES DE CONDICIÓN A LOS QUE AFECTA:
S
;
pone 1 - si el resultado es negativo
pone 0 - en cualquier otro caso
Z
;
pone 1 - si el resultado es cero
pone 0 - en cualquier otro caso
H
;
pone 1 - si no hay acarreo desde el bit 3
pone 0 - en cualquier otro caso
N
;
pone 1 - siempre
C
;
pone 1 - si no hay acarreo desde el bit 7
pone 0 - en cualquier otro caso
P/V
;
pone 1 - si hay desbordamiento (overflow)
pone 0 - en cualquier otro caso
CICLOS DE MEMORIA:
5
CICLOS DE RELOJ:
19

EJEMPLO:

SUB (IY-34)

Valor del registro "IY":

(IY):
1 0 1 0 1 0 1 0
0 1 0 0 1 0 0 1
AAh
49h

Valor de la posición de memoria AA27h:

(AA27h):
0 0 1 1 0 1 0 1
35h

Valor del registro "A":

(A):
0 0 1 1 0 1 0 1
35h

Instrucción:

SUB (IY-34):
1 1 1 1 1 1 0 1
1 0 0 1 0 1 1 0
1 1 0 1 1 1 1 0
FDh
96h
DEh

Operación:

00110101
+
11001011
00000000

Valor del registro "A" después de la ejecución:

(A):
0 0 0 0 0 0 0 0
00h

Indicadores de condición después de la ejecución:

S
Z
H
P/V
N
C
0
1
x
0
x
0
1
0

En la suma que ha hecho el microprocesador ha habido acarreo y semiacarreo ("H"), pero como en la resta los acarreos se invierten, los indicadores "C" y "H" permanecen a "0".

Con las instrucciones de restar vistas hasta el momento, la operación está limitada por el valor que puede contener un octeto, es decir, 255 considerando todos los valores como positivos. Para restar números más grandes, están las instrucciones cuyo nemotécnico es SBC.

SBC (SuBstract with Carry), restar con acarreo. Se trata de una resta binaria de un octeto , con las mismas características que en las instrucciones SUB, sólo que al minuendo se le resta primero el bit de acarreo del indicador de condición (C). Este bit se activa en una operación de resta cuando no hay acarreo desde el bit 7 y esto ocurre cuando el sustraendo es mayor que el minuendo (ver ejemplos de las instrucciones SUB).

En una resta convencional, operando con números decimales, cuando el valor del sustraendo es mayor que el minuendo en la unidad enfrentada, sumamos diez al valor del minuendo, restamos y "nos llevamos una" para la siguiente unidad, esto es, restamos el diez que habíamos sumado al minuendo:

5724-3615

Al restar 4-5 en realidad se hace 14-5 y nos llevamos una (acarreo), este acarreo lo sumamos a la decena 1 del sustraendo, que es lo mismo que restarlo en el minuendo a la decena 2 y resulta 2-2 ó 1-1.

5
7
2
4
-
3
6
1
5
1
acarreo
2
1
0
9

Pues esto mismo ocurre al sumar octetos, cuando el octeto sustraendo es mayor que el octeto minuendo y activarse por tanto el bit de acarreo, al tenerlo en cuenta con los octetos de orden superior; es como si en el minuendo se sumara 256 al octeto inferior y se restara uno al octeto superior.

Ver figura 6-2. Este es el uso más importante de la condición de acarreo para la resta.

BINARIO

01001000
10100011
00101010
MINUENDO
00100101
00000111
01000001
SUSTRAENDO
0
0
1
ACARREO
11011011
11111000
10111111
SUSTR. COMPLEMENTADO

00100011
10011011
11101001
RESULTADO


HEXADECIMAL

48
A3
2A
MINUENDO
-
25
07
41
SUSTRAENDO
0
0
1
ACARREO

23
9B
E9
RESULTADO


DECIMAL

72
163
42
MINUENDO
-
37
7
65
SUSTRAENDO
0
0
1
ACARREO

35
155
-23
RESULTADO
Fig 6-2. Resta de varios objetos con acarreo.
SBC A,r
OBJETO:
Resta del registro acumulador "A" el contenido del registro especificado por "r", más el indicador de acarreo. Deja el resultado en el registro acumulador.
CODIGO MAQUINA:
1 0 0 1 1 <--- r --->
INDICADORES DE CONDICIÓN A LOS QUE AFECTA:
S
;
pone 1 - si el resultado es negativo
pone 0 - en cualquier otro caso
Z
;
pone 1 - si el resultado es cero
pone 0 - en cualquier otro caso
H
;
pone 1 - si no hay acarreo desde el bit 3
pone 0 - en cualquier otro caso
N
;
pone 1 - siempre
C
;
pone 1 - si no hay acarreo desde el bit 7
pone 0 - en cualquier otro caso
P/V
;
pone 1 - si hay desbordamiento (overflow)
pone 0 - en cualquier otro caso
CICLOS DE MEMORIA:
1
CICLOS DE RELOJ:
4

EJEMPLO:

SBC A,H

Valor del registro "A":

(A):
1 1 1 1 1 1 1 1
FFh

Valor del registro "H":

(H):
0 1 1 1 0 1 1 1
77h

Indicador de acarreo (C) = 0

Instrucción:

SBC A,H:
1 0 0 1 1 1 0 0
9Ch

Operación:

(H)
01110111
+C
0
01110111

compl. a 2
10001001
+(A)
11111111
10001000

Valor del registro "A" después de la ejecución:

(A):
1 0 0 0 1 0 0 0
88h

Indicadores de condición después de la ejecución:

S
Z
H
P/V
N
C
1
0
x
0
x
0
1
0
SBC A,n
OBJETO:
Resta del registro acumulador "A" el entero de 8 bits "n" más el bit de acarreo. Deja el resultado en el registro acumulador.
CODIGO MAQUINA:
1 1 0 1 1 1 1 0
<-------- d -------->
DEh
 
INDICADORES DE CONDICIÓN A LOS QUE AFECTA:
S
;
pone 1 - si el resultado es negativo
pone 0 - en cualquier otro caso
Z
;
pone 1 - si el resultado es cero
pone 0 - en cualquier otro caso
H
;
pone 1 - si no hay acarreo desde el bit 3
pone 0 - en cualquier otro caso
N
;
pone 1 - siempre
C
;
pone 1 - si no hay acarreo desde el bit 7
pone 0 - en cualquier otro caso
P/V
;
pone 1 - si hay desbordamiento (overflow)
pone 0 - en cualquier otro caso
CICLOS DE MEMORIA:
2
CICLOS DE RELOJ:
7

EJEMPLO:

SBC A,40

Valor del registro "A":

(A):
0 0 0 0 0 0 0 0
00h

Indicador de acarreo (C) = 1

Instrucción:

SBC A,40:
1 1 0 1 1 1 1 0
0 0 1 0 1 0 0 0
DEh
28h

Operación:

n
00101000
+C
1
00101001

compl. a 2
11010111
+(A)
00000000
11010111

Valor del registro "A" después de la ejecución:

(A):
1 1 0 1 0 1 1 1
D7h

Indicadores de condición después de la ejecución:

S
Z
H
P/V
N
C
1
0
x
1
x
1
1
1

Observe que hubo desbordamiento por pasar el registro "A" de un valor positivo a uno negativo.

SBC A,(HL)
OBJETO:
Resta del registro acumulador "A", el valor del octeto de memoria direccionado por el contenido del par de registros "HL", más el indicador de acarreo. El resultado se deja en el registro acumulador.
CODIGO MAQUINA:
1 0 0 1 1 1 1 0
9Eh
INDICADORES DE CONDICIÓN A LOS QUE AFECTA:
S
;
pone 1 - si el resultado es negativo
pone 0 - en cualquier otro caso
Z
;
pone 1 - si el resultado es cero
pone 0 - en cualquier otro caso
H
;
pone 1 - si no hay acarreo desde el bit 3
pone 0 - en cualquier otro caso
N
;
pone 1 - siempre
C
;
pone 1 - si no hay acarreo desde el bit 7
pone 0 - en cualquier otro caso
P/V
;
pone 1 - si hay desbordamiento (overflow)
pone 0 - en cualquier otro caso
CICLOS DE MEMORIA:
2
CICLOS DE RELOJ:
7

EJEMPLO:

SBC A,(HL)

Valor del par de registros "HL":

(H):
(L):
1 1 0 0 0 1 0 1
0 0 0 1 1 0 0 0
C5h
18h

Valor de la posición de memoria C518h:

(C518h):
1 1 1 1 1 1 1 1
FFh

Valor del registro "A":

(A):
1 1 1 1 1 1 1 1
FFh

Indicador de acarreo (C) = 0

Instrucción:

SBC A,(HL):
1 0 0 1 1 1 1 0
9Eh

Operación:

(C518h)
11111111
+C
0
11111111

compl. a 2
00000001
+(A)
11111111
00000000

Valor del registro "A" después de la ejecución:

(A):
0 0 0 0 0 0 0 0
00h

Indicadores de condición después de la ejecución:

S
Z
H
P/V
N
C
0
1
x
0
x
1
1
0

Observe que hubo desbordamiento al pasar el registro "A" de un valor negativo a uno positivo.

SBC A,(IX+d)
OBJETO:
Resta al contenido del registro acumulador, el valor del octeto de memoria direccionado por el operando, más el indicador de acarreo. La dirección de memoria se calcula añadiendo al contenido del registro índice IX el valor del entero de desplazamiento "d", el cual puede adquirir los valores desde -128 a +127. El resultado se deja en el registro acumulador.
CODIGO MAQUINA:
1 1 0 1 1 1 0 1
1 0 0 1 1 1 1 0
<-------- d -------->
DDh
9Eh
 
INDICADORES DE CONDICIÓN A LOS QUE AFECTA:
S
;
pone 1 - si el resultado es negativo
pone 0 - en cualquier otro caso
Z
;
pone 1 - si el resultado es cero
pone 0 - en cualquier otro caso
H
;
pone 1 - si no hay acarreo desde el bit 3
pone 0 - en cualquier otro caso
N
;
pone 1 - siempre
C
;
pone 1 - si no hay acarreo desde el bit 7
pone 0 - en cualquier otro caso
P/V
;
pone 1 - si hay desbordamiento (overflow)
pone 0 - en cualquier otro caso
CICLOS DE MEMORIA:
5
CICLOS DE RELOJ:
19

EJEMPLO:

SBC A,(IX+30)

Valor del registro "IX":

(IX):
1 1 1 1 0 0 1 1
0 0 0 1 1 0 0 1
F3h
19h

Valor de la posición de memoria F337h:

(F337h):
0 1 1 0 1 0 1 0
6Ah

Valor del registro "A":

(A):
0 1 1 1 1 0 1 1
91h

Indicador de acarreo (C) = 1

Instrucción:

SBC A,(IX+30):
1 1 0 1 1 1 0 1
1 0 0 1 1 1 1 0
0 0 0 1 1 1 1 0
DDh
9Eh
1Eh

Operación:

(F337h)
01101010
+C
1
01101011

compl. a 2
10010101
+(A)
01111011
00010000

Valor del registro "A" después de la ejecución:

(A):
0 0 0 1 0 0 0 0
10h

Indicadores de condición después de la ejecución:

S
Z
H
P/V
N
C
0
0
x
0
x
0
1
0
SBC A,(IY+d)
OBJETO:
Resta al contenido del registro acumulador "A", el valor del octeto de la memoria direccionado por el operando, más el indicador de acarreo. La dirección de memoria se calcula añadiendo al contenido del registro índice "IY" el valor del entero de desplazamiento "d", el cual puede adquirir los valores desde -128 a +127. El resultado se deja en el registro acumulador.
CODIGO MAQUINA:
1 1 1 1 1 1 0 1
1 0 0 1 1 1 1 0
<-------- d -------->
FDh
9Eh
 
INDICADORES DE CONDICIÓN A LOS QUE AFECTA:
S
;
pone 1 - si el resultado es negativo
pone 0 - en cualquier otro caso
Z
;
pone 1 - si el resultado es cero
pone 0 - en cualquier otro caso
H
;
pone 1 - si no hay acarreo desde el bit 3
pone 0 - en cualquier otro caso
N
;
pone 1 - siempre
C
;
pone 1 - si no hay acarreo desde el bit 7
pone 0 - en cualquier otro caso
P/V
;
pone 1 - si hay desbordamiento (overflow)
pone 0 - en cualquier otro caso
CICLOS DE MEMORIA:
5
CICLOS DE RELOJ:
19

EJEMPLO:

SBC A,(IY-1)

Valor del registro "IY":

(IY):
0 1 1 0 0 1 1 0
1 1 1 0 0 0 0 1
66h
E1h

Valor de la posición de memoria 66E0h:

(66E0h):
1 1 0 1 0 0 1 1
D3h

Valor del registro "A":

(A):
0 1 1 0 0 0 1 0
62h

Indicador de acarreo (C) = 1

Instrucción:

SBC A,(IY-1):
1 1 1 1 1 1 0 1
1 0 0 1 1 1 1 0
1 1 1 1 1 1 1 1
FDh
9Eh
FFh

Operación:

(66E0h)
11010011
+C
1
11010100

compl. a 2
00101100
+(A)
01100010
10001110

Valor del registro "A" después de la ejecución:

(A):
1 0 0 0 1 1 1 0
8Eh

Indicadores de condición después de la ejecución:

S
Z
H
P/V
N
C
1
0
x
1
x
1
1
1

Observe que no hubo acarreo desde el bit 7, esto ocurre cuando el sustraendo es menor que el minuendo, como el indicador "C" está invertido en las instrucciones de resta, se pone a "1"; esta situación da como resultado un número negativo. Si se hace el complemento a 2 del resultado en el registro "A" nos da el valor 72h, que con el signo "-" es el resultado entero de la operación (-72h)

La activación de los indicadores de condición, tanto en la resta (SUB) como en la resta con acarreo (SBC), se hace según las siguientes reglas:

"S": En este indicador se copia el bit 7 del acumulador para indicar si el número que contiene es positivo o negativo.

"Z": Este indicador se activa (valor igual 1) siempre que todos los bits del registro acumulador sean cero después de la ejecución.

"H": Este indicador se activa (valor igual 1) cuando no hay acarreo desde el bit 3 después de la ejecución. Esto ocurre siempre que el valor absoluto de los cuatro bits inferiores del sustraendo es mayor que el valor absoluto de los cuatro inferiores del minuendo.

"N": Este indicador lo toma en cuenta el microprocesador cuando hace un ajuste BCD del acumulador (se verá más adelante) y le indica si la última operación realizada ha sido una suma o una resta. Por tanto, todas las sumas lo ponen a "0" y todas las restas lo ponen a "1".

"C": Este indicador se activa (valor igual 1) cuando no hay acarreo desde el but 7, después de la ejecución. Esto ocurre siempre que el valor absoluto del octeto del sustraendo es mayor que el valor absoluto del octeto del minuendo. Es el indicador que se emplea para las instrucciones de restar con acarreo. Interesa observar que este indicador funciona, en la resta, de forma contraria a como lo hace en la suma, es decir, se activa cuando NO hay acarreo en la suma que realiza el microprocesador tras complementar el sustraendo.

"P/V": Este indicador de desbordamiento (overflow) se activa (valor igual 1) siempre que el resultado de la resta haga que el acumulador pase de contener un número menor de 127 a contener uno mayor, o de contener uno mayor de -128 a contener uno menor. Indica, por tanto, un rebosamiento del margen comprendido entre -128 y +127. Se utiliza como indicador de rebosamiento cuando se trabaja con números en complemento a 2.

GRUPO ARITMETICO DE 8 BITS (SUMA Y RESTA)
Código Fuente
Hexadecimal
Decimal
ADD A,A
87
135
ADD A,B
80
128
ADD A,C
81
129
ADD A,D
82
130
ADD A,E
83
131
ADD A,H
84
132
ADD A,L
85
133
ADD A,n
C6,n
198,n
ADD A,(HL)
86
134
ADD A,(IX+d)
DD,86,d
221,134,d
ADD A,(IY+d)
FD,86,d
253,134,d
ADC A,A
8F
143
ADC A,B
88
136
ADC A,C
89
137
ADC A,D
8A
138
ADC A,E
8B
139
ADC A,H
8C
140
ADC A,L
8D
141
ADC A,n
CE,n
206,n
ADC A,(HL)
8E
142
ADC A,(IX+d)
DD,8E,d
221,142,d
ADC A,(IY+d)
FD,8E,d
253,142,d
SUB A
97
151
SUB B
90
144
SUB C
91
145
SUB D
92
146
SUB E
93
147
SUB H
94
148
SUB L
95
149
SUB n
D6,n
214,n
SUB (HL)
96
150
SUB (IX+d)
DD,96,d
221,150,d
SUB (IY+d)
FD,96,d
253,150,d
SBC A,A
9F
159
SBC A,B
98
152
SBC A,C
99
153
SBC A,D
9A
154
SBC A,E
9B
155
SBC A,H
9C
156
SBC A,L
9D
157
SBC A,n
DE,n
222,n
SBC A,(HL)
9E
158
SBC A,(IX+d)
DD,9E,d
221,158,d
SBC A,(IY+d)
FD,9E,d
253,158,d
Tabla de codificación para suma y resta.

Hasta aquí hemos visto las instrucciones que nos han de servir para sumar y restar en código máquina. A continuación veremos las que se encargan de realizar operaciones lógicas tales como AND, OR y XOR. Pero antes, realizaremos unos cuantos ejemplos que podamos ejecutar en el ordenador, y que sirvan para aclarar lo estudiado. También invitamos al lector a que intente resolver los ejercicios que se proponen, y que le darán una medida de cómo va asimilando los conocimientos.

EJEMPLOS:

Al igual que en el capítulo anterior, vamos a hacer algunos programas en código máquina que nos demuestren el funcionamiento de las instrucciones de suma y resta. Al mismo tiempo, iremos cogiendo práctica en la realización y ensamblado de programas en Assembler.

Recomendamos al lector que no se limite a «leer por encima» este curso. Si desea, de verdad, aprender a programar en código máquina, debe seguir el curso encima de una mesa con lápiz y papel en la mano. Intente ensamblar cada programa usted mismo y no se limite a ver cómo lo hacemos nosotros; e incluso, atrévase a escribir sis propias rutinas. No se preocupe si el ordenador se le «cuelga» cincuenta veces, es totalmente normal, una rutina en código máquina rara vez funciona a la primera.

Vamos con el primero de nuestros programas. Se trata de sumar dos números sin acarreo. Utilizaremos un programa en Basic que se encargará de gestionar la entrada de datos, llamar a la rutina en C/M e imprimir los resultados, pero la suma la realizaremos en código máquina.

En principio, necesitamos POKEar los dos números que vamos a sumar en dos direcciones de memoria, desde donde serán leidos por la rutina C/M. Estas dos direcciones serán la 5CB0h (23728) para el primer operando, y la 5CB1h (23729) para el segundo; estas direcciones corresponden a una variable del sistema que no se usa.

Primero escribiremos el programa en C/M y luego el Basic. En Assembler, nuestra rutina podría ser algo así:

10
LD
A,(#5CB1)
20
LD
B,A
30
LD
A,(#5CB0)
40
ADD
A,B
50
PUSH
AF
60
POP
BC
70
RET

Las líneas 10, 20 y 30 leen los dos operandos desde las posiciones de memoria donde los almacenó el Basic. La línea 40 realizará la suma equivalente a:

"LET A=A+B"

Las líneas 50 y 60 transfieren el resultado al registro "B" y los indicadores de estado del registro "F", al registro "C". Recuerde que el registro "BC" es lo que nos devuelve USR cuando retornamos a Basic. Mirando las tablas de codificación, podemos ensamblar el programa:

Assembler
Hexadecimal
Decimal
LD A,(#5CB1)
3A,B1,5C
58,177,92
LD B,A
47
71
LD A,(#5CB0)
3A,B0,5C
58,176,92
ADD A,B
80
128
PUSH AF
F5
245
POP BC
C1
193
RET
C9
201

Habría sido interesante que el propio lector hubiera ensamblado el programa antes de mirar la tabla anterior. Prométase a sí mismo que la próxima vez lo intentará.

Ya tenemos preparada la rutina en código máquina para sumar dos números. Seamos buenos con los que aún tienen solo 16K, y carguemos la rutina a partir de la dirección 31000.

Ha llegado el momento de pasar al olvidado Basic. El PROGRAMA 1 se encarga de todo. La línea 10 baja RAMTOP, las líneas 20 y 30 introducen en memoria nuestra rutina que se encuentra en los DATA de la línea 40. Las líneas 50 a 100 nos piden los dos operandos y los POKEan en memoria tras comprobar si están dentro de rango.

Programa 1
PROGRAMA 1.

La línea 110 llama a nuestra rutina en C/M de forma que, al retornar, el contenido del registro "BC" se almacena en la variable "a". En 120 llamamos a la rutina 3100 que nos pasa el número a binario, esta subrutina es la mism que usábamos en el programa para cambiar de base, del capítulo 3. Las líneas 130 y 140 completan el número con ceros a la izquierda para obtener, de nuevo, 16 bits. Finalmente, las líneas 200 a 220 imprimen en pantalla el valor que contenía el acumulador después de efectuar la suma y el estado de los indicadores en el registro "F". El significado de los indicadores es el siguiente:

S
:
Signo
Z
:
Cero
H
:
Semi-acarreo
V
:
Desbordamiento
N
:
Suma/Resta
C
:
Acarreo

Los indicadores marcados "x" presentan un estado indeterminado y no habrá que tomarlos en cuenta.

Una vez que tenga el programa en memoria, pruebe a introducir distintos operandos comprendidos entre 0 y 255. Le sugerimos unos cuantos:

17
+
17
=
34
15
+
240
=
255
(S)
128
+
128
=
0
(Z,V,C)
127
+
1
=
128
(S,H,V)
3
+
127
=
130
(S,H,V)

Puede utilizar este mismo programa para la resta cambiando "ADD A,B" por "SUB A,B", es decir, el "128" de la línea 40 por un "144". Haga el cambio y ejecute el programa de nuevo, esta vez restará el segundo operando del primero. Si el segundo operando es mayor que el primero (resultado negativo) el indicador "C" se pondrá a "1" y el resultado aparecerá en complemento a 2.

Ahora vamos a complicar un poco más la cosa, se trata de hacer una rutina qeu permita sumar números superiores a 255. En este caso, usaremos la instrucción "ADC" (sumar con acarreo) para poder tener en cuenta, cuando sumemos un octeto, el acarreo procedente del anterior.

Introduciremos el primer operando en las posiciones 5CB0h (23728) y 5CB1h (23729) (primero el octeto menos significativo y luego el más significativo), y el segundo operando en 5C76h (23670) y 5C77h (23677).

El programa en Assembler puede ser algo como:

10
AND
A
20
LD
A,(#5C76)
30
LD
D,A
40
LD
A,(#5CB0)
50
ADC
A,D
60
LD
C,A
70
LD
A,(#5C77)
80
LD
D,A
90
LD
A,(#5CB1)
100
ADC
A,D
110
LD
B,A
120
PUSH
AF
130
POP
DE
140
LD
(#5CB0),DE
150
RET

La línea 10 pone a «cero» el indicador de acarreo; se trata de un pequeño "truco" que consiste en realizar un "AND" lógico del acumulador consigo mismo, con lo que el contenido no varía, pero se pone a cero el indicador de acarreo. Más adelante, y dentro de este mismo capítulo, veremos las operaciones lógicas.

Las líneas 20, 30 y 40 cargan los octetos de orden bajo de los dos operandos. La línea 50 los opera (suma) y, si hay acarreo, lo guarda para la suma siguiente. La línea 60 guarda el resultado en "C" (octeto bajo de "BC").

La operación se vuelve a repetir para los octetos altos; las líneas 70, 80 y 90 cargan los operandos. La línea 100 los suma tomando en cuenta el acarreo procedente de la operación anterior. Finalmente, la línea 110 transfiere el resultado al registro "B" (octeto alto de "BC").

La operación ya se ha realizado, tenemos el resultado en "BC" y, por tanto, será lo que obtengamos al retornar a Basic. Ahora sólo nos falta sacar, de alguna forma, el contenido del registro "F" (indicadores) de forma que lo podamos leer desde Basic. Para ello, las líneas 120 y 130 pasan los contenidos de "A" y "F" a "DE" y la línea 140 almacena el contenido de "E" en la posición de memoria 5CB0h (23728), desde donde será leido por el Basic. En esta operación, también se guarda en 23729 el contenido del registro "D" pero, en este caso, no nos interesa.

Sería interesante que el lector intentara, ahora ensamblar por su cuenta este programa, para ello, deberá proceder como hicimos nosotros en el caso anterior. Primero, copie el programa en un papel, ahora, vaya buscando cada instrucción en las tablas ("AND A" se ensambla como A7h ó 167d). A continuación, escriba los operandos numéricos sin olvidar invertir el orden de los octetos y finalmente, acuérdese de ensamblar "RET" como C9h o 201d.

¿Ya lo tiene? Correcto, ahora compruebe si lo que ustes ha ensamblado coincide con lo nuestro.

Assembler
Hexadecimal
Decimal
AND A
A7
167
LD A,(#5C76)
3A,76,5C
58,118,92
LD D,A
57
87
LD A,(#5CB0)
3A,B0,5C
58,176,92
ADC A,D
8A
138
LD C,A
4F
79
LD A,(#5C77)
3A,77,5C
58,119,92
LD D,A
57
87
LD A,(#5CB1)
3A,B1,5C
58,177,92
ADC A,D
8A
138
LD B,A
47
71
PUSH AF
F5
245
POP DE
D1
209
LD (#5CB0),DE
ED,53,B0,5C
237,83,176,92
RET
C9
201

No se preocupe si se ha equivocado en algo, sería mucho pedir que el primer programa que ensambla le saliera sin errores. Ahora, con los datos de la tercera columna (donde dice: "Decimal") podemos construir el programa en Basic que introduzca esta rutina en memoria, y la utilice para sumar dos números. Este programa es el listado que aparece con el nombre de PROGRAMA 2. No hace falta que lo copie entero, si lo desea, puede cargar el PROGRAMA 1 y reescribir las líneas 20, 40, 60, 70, 90, 100, 110, 120, 130, 210 y 220 ya que son las únicas que varían.

Programa 2
PROGRAMA 2.

El funcionamiento es muy similar al del PROGRAMA 1, pero observe que en las líneas 70 y 100 partimos los operandos en dos octetos antes de meterlos en sus direcciones de memoria correspondiente.

Pruebe con distintos operandos y verá que el programa suma correctamente; siempre que el resultado sea mayor de 65535, obtendrá ese resultado menos 65536 y el indicador de acarreo se pondrá a "1".

Puede también restar números si cambia "ADC A,D" por "SBC A,D"; para ello, puede cambiar los dos "138" de la línea 40 (del Basic) por "154", o bien, detener el programa (con STOP) y teclear: POKE 31008,154: POKE 31017,154. Luego, no lo arranque con "RUN", sino, con "GO TO 50".

Como verá, el hecho de POKEar en la zona de programa hace que éste se comporte de forma distinta; he aquí la razón de los famosos "POKES" de "vidas infinitas" y similares que se utilizan en juegos comerciales (sección "Patas Arriba" de la revista MICROMANIA).