CÓDIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD Codigo Maquina OCR

User Manual: Codigo Maquina Para Principiantes Con Amstrad La Biblioteca de los 8 bits

Open the PDF directly: View PDF PDF.
Page Count: 182 [warning: Documents this large are best viewed by clicking the View PDF Link!]

CÓDIGO MÁQUINA
PARA PRINCIPIANTES
CON AMSTRAD
Steve Kramer
CÓDIG O MÁQUINA PAR A PRINCIPIANTES CON AMSTRAD
edic n espola de la obra
MACHIN E CODE FOR BEGINNERS O N THE AMSTRAD
Steve Krame r
publicada en castellano bajo licencia de
MICRO PRESS
Castle Hous e
27 London Road
Tunbridg e Wells, Kent
Traducción
Pablo de la Fuente Redondo
Director del Centro de Proceso de Dato s
Universidad de Valladolid
Revisada por
Jesús Rojo García
Profesor de Matemática Aplicad a
Escuela T. S. de Ing. Industriales de Valladoli d
INDESCOMP, S.A.
Avda. del Mediterráneo, 9
28007 Madri d
© 1984 Steve Kramer
© 1985 Indescomp, S.A.
Reservados todos los derechos. Prohibida la reproducción total o parcial
de la obra, por cualquier medio, sin el permiso escrito de los editores.
ISBN 84 86176 24 7
Depósito legal: M-10847-85
impresión:
Gráficas EMA . Miguel Yuste, 27. Madrid
Producció n de la edición española:
Vector Ediciones. Gut ierr e de Cetina, 61, Madri d . (91) 40 8 52 17
Contenido
1. Introduccn 1
2. Qué es y para qué sirve el código de máquina 3
3. Primeras nociones 7
4. Diagramas de flujo 13
5. Primeras instrucciones en código de máquina 17
LD, CALL, RET, JP, JR
6. Arittica elementa! 39
ADD, ADC , SUB, SBC, DEC, INC
7. Indicadores, condiciones y decisiones condicionadas 59
CP, Z, NZ, C, NC, M, P, PE, PO, CCF , SCF, DJNZ
8. Operaciones lógicas 71
AND, OR, XOR, CPL, NEG
9. Utilización de la pila 79
PUSH, POP e instrucciones con el SP
10. Instrucciones que trabajan con un solo bit 87
SET, RES, BIT
11. Rotaciones y desplazamientos 95
RL, RLA, RLC, RLCA, RLD, SLA, SLL, RR,
RRA, RRC, RRCA, RRD, SRA, SRL
12. Búsquedas y transferencias automática s 113
LDD, LDDR, CPD, CPDR, LDI , LDIR, CPI, CPIR
13. Comunicación con el exterior 125
IN , OU T
14. Otra s instrucciones 129
15. Consejos sobre cómo utilizar el sistema operativo 141
Apéndices A Conjunto de instrucciones del Z80 145
B Cargador HEX .. . . . 155
C Conversn d e HEX a DECIMAL para el byte más
significativo 157
D Conversn de HEX a DECIMAL para el byte menos
significativo 159
E Conversión de HEX en complemento a 2 a DECIMA L 161
F Mapa de pantalla del Amstrad 163
G Dirección de las rutinas s usuales del sistema operativo. . .. 167
1
Introducción
El Amstrad CPC464 es probablemente la novedad más interesante en mate-
ria de ordenadores domésticos tras la aparición del Spectrum. Su BASIC es-
tá dotado de funciones avanzadas que hasta ahora sólo se incluían en máqui-
nas de precio muy superior; además, en cuanto a posibilidades de amplia-
ción a precio razonable, no tiene nada que envidiar a los demás ordenadores
de su categoría.
Ahora bien, la diferencia fundamental entre éste y otros ordenadores, por
lo que al programador concierne, está en la decisión de Amstrad de publicar
su exhaustiva documentación sobre el sistema operativo. Este hecho, sin pre-
cedentes en la industria de los ordenadores dosticos, ofrece la posibilidad
de aprender programación en digo de máquina por la vía fácil y de obtener
resultados casi inmediatos utilizando rutinas del sistema operativo.
Superado queda el circulo vicioso en que antes nos encontrábamos: si no
entiendo el código de máquina, no puedo utilizarlo, y por lo tanto nunca po-
dré averiguar cómo funciona en mi ordenador, pues no sé mo hacer que
éste responda.
Este libro se dirige a los principiantes que deseen aprender a programar
en código de máquina en el Amstrad CPC464. Empezaremos por examinar
los conceptos básicos de programación en código de máquina, explicando
las instrucciones reconocibles por el microprocesador Z80 y cómo utilizar-
las. A lo largo del libro describiremos también algunas rutinas del sistema
operativo.
Dos personas totalmente noveles en digo de máquina me han servido de
banc o de pruebas en la elaboración de este libro; sus preguntas y observacio-
nes forman la base de la estructura de la obra. Su ayuda ha sido especialmen-
te valiosa para asegurar que no se omitiera ninguna información o explica-
ción que, aunque obvia para el experto, para el principiante pudiera ser cla-
rificadora. Estas omisiones suelen ser las que dejan desconcertado al princi-
piante; algo así como decirle a un forastero que la calle Desengo está junto
a la Gran Vía. ¿De qué le sirve esa información si no sabe dónd e está la Gran
Vía?
Daremos algunos pequeños programas en BASIC con los que se podrá in-
1
2 CÓDIGO MÁQUIN A PAR A PRINCIPIANTES CON AMSTRA D
troducir programas en código de quina, así como examinar y modificar
el contenido de zonas de la memoria. No obstante, sugerimos al lector que
haga lo posible por adquirir el programa ensamblador/desensamblador de
Amsoft. Esto le permitirá introducir los programas empleando los códigos
nemotécnicos (una especie de abreviaturas de las instrucciones que entiende
el Z80) en lugar de números; además, con un ensamblador, las modificacio-
nes de los programas son más sencillas y las instrucciones en sí son más p-
ximas a BASIC.
Evidentemente, es posible leer este libro de principio a fin de una sentada.
Pero no lo recomendamos. El digo de máquina es un tema potencialmente
tan confuso, y son tantos los conceptos que se manejan, que lo conveniente
es que el lector se siente ante su ordenador e introduzca y ejecute los progra-
mas que van apareciendo en cada capítulo, y que no pase al catulo siguien-
te mientras no esté seguro de haber comprendido su funcionamiento.
Hemos utilizado ampliamente el sistema operativo de la máquina, lo que
hace posible ver inmediatamente los resultados de los programas. Las ruti-
nas del sistema operativo están excelentement e documentadas en la publica-
ción "Amstrad Firmware Specification (Soft 158)". Aunque este texto será
totalmente ininteligible par a el lector en este momento, no debería dudar en
incorporarlo a su biblioteca en cuanto haya terminado de leer este libro.
El microprocesador Z80 es uno de ¡os más utilizados en los ordenadores
dosticos y, hasta hac e poco tiempo, también en los ordenadores profesio-
nales. Para él se ha escrito la más amplia variedad de programas existente
en el mercado, utilizable a través del sistema operativo CP/M, el cual es
disponible en disco para los ordenadores Amstrad . Ades, el Z80 es sien-
do incluido como segundo microprocesador en ordenadores profesionales,
y como opcn en el BBC, el Commodore 64, el Apple y otros. Así pues,
los conocimientos que el lector va a adquirir en este libro le servirán también
para programar ordenadores de muchas otras marcas.
2
Qué es y para qué sirve el código de máquina
El microprocesador del Amstrad es una criatura básicamente ignorante.
Desde luego, ejecuta muy bien todos los programas de BASIC y hace su tra-
bajo a la perfección, pero ello no significa que el Z80 sea inteligente. Lo que
hace que la máquina parezca tan bil es el firmware, esto es, los programas
que están grabados permanentemente en la memoria del ordenador y entran
en funcionamiento en cuanto se enciende la quina. En el Amstrad no am-
pliado estos programas son un sistema operativo y el inrprete de BASIC.
El sistema operativo se ocupa de tareas tales como examinar el teclado pa-
ra averiguar si se ha pulsado una tecla, leer datos de la cinta o escribir un
cacter en la pantalla. El lector puede imaginarlo como organizador de to-
das las comunicaciones, sin el cual no sería posible saber si el ordenador está
encendido o apagado ya que no se le podría suministrar información ni él
podría reaccionar ante ningún estímulo.
El intérprete de BASIC hace justamente lo que su nombre sugiere: conver-
tir BASIC en un lenguaje comprensible para el Z80. Imagine el lector que
le decimos que abra el libro por la página 35. Fácil, ¿verdad? Pero ¿qué ocu-
rre si le decimos que ? Empiezan los problemas; no sólo no sabrá q
tiene que hacer, sino que incluso puede no reconocer la forma de la
instrucción.
Esto es más o menos lo que le ocurriría al Z80 si le pidiéramos que ejecuta-
se una instruccn de BASIC. El microprocesador no entiende BASIC; pero
no es lo eso. La palabra china que hemos citado utiliza sólo un símbolo,
pero para transcribirla a nuestros caracteres son necesarios varios: "tsung".
La transcripcn tampoco nos ha servido de mucho; "tsung" significa: sem-
brar semillas sin antes arar la tierra. El microprocesador experimenta las
mismas dificultades si le damos una orden e n BASIC; una instrucción de
BASIC representa muchas veces gran mero de instrucciones en código de
máquina y, ¡o que es peor, los caracteres utilizados por BASIC no pueden
ser entendidos por el microprocesador, que solamente reconoce dos estados:
1 y 0 (on/off, encendido/apagado, etc.) .
Afortunadamente, los ceros y los unos se agrupan de ocho en ocho, lo que
da 256 combinaciones diferentes posibles. Son estas combinaciones las que
3
4 DIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
utilizamos como códigos de máquina. Podríamos considerarlas como análo-
gas al cacter chino que vimos antes.
Pero no termina aquí la lista de nuestros problemas. Puesto que un carác-
ter represent a una palabra completa y sólo hay 256 combinaciones posibles,
podría parecer que el vocabulario de! Z80 está limitado a tan sólo 256 pala-
bras. Esto es básicamente correcto pero, al igual que en los lenguajes ordina-
rios, hay palabras compuestas.
Por un lado, hay palabras cuyo significado cambia cuando se presentan
asociadas: no e s lo mismo "tio vivo" que "tiovivo" por ejemplo. Ades
el sentido de una palabra puede cambiar radicalmente mediante el empleo
de prefijos: es el caso de "justicia" e "injusticia", o de "venido", "aveni-
do" , "desavenido" y "revenido", o de muchos otros ejemplos. Estas cni-
cas se emplean también para proporcionar al microprocesador mayor varie-
dad de palabras. A pesar de todo, el vocabulario es muy limitado.
La limitación no afecta a la cantidad de conceptos que puede reflejar el
vocabulario, sino a la cantidad de palabras que se necesitan para
expresarlos.
Generalmente se suelen necesitar varias instrucciones en código de máqui-
na para realizar lo mismo que con una instrucción de BASIC. En cambio ,
pcticamente no hay limitaciones en cuanto a la forma en que deben ir or-
denadas las instrucciones en código de máquina. Es más, en algunos casos
el código de máquina puede requerir menos instrucciones que BASIC para
una misma tarea.
El intérprete BASIC debe comprobar la validez de cada una de las instruc-
ciones, traducirlas a instrucciones de código de máquina para que el micro-
procesador pueda ejecutarlas, comprobar ciertos resultados y archivarlos
para utilizaciones posteriores. Todas estas cosas llevan mucho tiempo. Por
el contrario, con el código de máquina no deben verificarse los posibles erro-
res, no hay que traduci r las instrucciones y no se crea un almacén de datos
salvo que se le pida expresamente al microprocesador.
Para comprobar el ahorro de tiempo, teclee el siguiente programa en BA-
SIC. (Antes de hacerlo apague el ordenador y vuelva a encenderlo para ase-
gurarse de que está, por así decirlo, "virgen".) Observe que empleamos el
mbolo ? en lugar de PRINT para ganar tiempo.
10 MM = 43903
20 MEMORY 43799
30 FOR N = 43800 TO 43809 : READ D : POKE N,D : A
= A + D : NEX T
40 IF A <> 1338 THEN CLS : PEN 3 : PRINT "ERROR EN
DATA" : PEN 1 : EDIT 90
QUÉ ES y PARA QUÉ SIRVE EL CÓDIGO DE MÁQUINA 5
50 INPUT "PULSE ENTER PARA EMPEZAR";A : B = 255
60 PRINT "A";: B = B - 1 : IF B < 0 THEN 60
70 PRINT
80 CAL L 4380 0
90 DATA 6,255,62,65,205,90,187,16,251,201
100 END
Cuando haya introducido el programa, ejecútelo con el comando RUN.
Si lo que aparece en pantalla es la nea 90 en modo de edicn, lo que ocurre
de que se ha equivocado al teclear los datos de esta nea; corrija entonces
la línea vuelva a ejecutar el programa. Si ya no hay errores, aparecerá en
pantalla el mensaje 'PULSE ENTER PARA EMPEZAR'.
A! pulsar dicha tecla, la línea 60 hará que se escriba 255 veces la letra 'A';
a continuación, línea 80 llama a la rutina en código de máquina que el pro-
grama ha cargado con la sentencia POKE de la línea 30; esta rutina tiene por
efecto escribir otras 255 veces la letra 'A'. Compare la velocidad de estas dos
maneras de hacer lo mismo. El programa no tiene nada de apasionante, pero
le demostrará la rapidez del código de máquina.
La rutina en código de máquina ha ocupado 10 caracteres (que son los que
figuran en la línea del DATA), el último de los cuales, el 201, sirve para or-
denar a la rutina que retorne a BASIC. El programa equivalente en BASIC
ha ocupado 37 caracteres, sin contar el número de línea; incluso sin blancos
innecesarios no ocuparía menos del equivalente a 25 caracteres de código de
máquina.
Para comprobar la longitud que ocupa realmente la línea 60, añada al pro-
grama las líneas
110 B=0:FOR N=520 TO 639:A=PEEK(N)
120 IF B=0 THEN PEN 2:PRINT:PRINT N;
130 PEN 3:PRINT USING "####";A;
140 IF A>32 AND A<129 THEN PEN 1:PRINT
CHR$(A);:GOTO 160
150 PRINT " ";
160 B=B+1:IF B=5 THEN B=0
170 NEXT: PEN 1:END
y ejecútelas con el comando RUN 110. La pantalla mostrará en color rojo
los valores que ocupan las posiciones de memoria entre la 520 y la 639; cuan-
do el valor representa un carácter, éste aparece en amarillo a su derecha. Los
números en azul corresponden a la primera direccn de memoria de la línea.
La línea 50 se reconoce por el mensaje "PULS E ENTER PARA EMPE-
ZAR" . A continuación viene la línea 60. El número de línea está donde apa-
rece 0 60 en rojo seguido de < en amarillo y de 0 en rojo; el mero de línea
es el 60 0 y el número que aparece antes del primer 0 es el número de caracte-
res de la línea.
6 CÓDIG O MÁQUINA PARA PRINCIPIANTES CON AMSTRA D
Podemos observar que sólo las cadenas literales, como "A ", se almace-
nan como las escribimos. Los demás caracteres son codificados por el inter-
prete a una forma que le permita un manejo más fácil. Cada vez que se eje-
cuta el comando LIST, el intérprete debe decodificar el texto para dejarlo
en la forma en que lo hemos escrito.
La conclusión que se obtiene de todo esto es que un programa en código
de máquin a no sólo es más rápido, sino también más económico de almace-
nar. Estas son las dos ventajas principales de programar en código de máqui-
na. De hecho, un programa en BASIC puede ser unas cien veces más lento
que su equivalente en código de máquina.
Por el contrario, las desventajas consisten en que los programas son prác-
ticamente incomprensibles y, por tanto, difíciles de depurar, y suelen reque-
rir mayor número de instrucciones que sus equivalentes en BASIC o en otro
lenguaje de alto nivel.
Se puede mejorar !a comprensn de los programas en código de máquina
utilizando ensambladores y desensambladores, de los que hablaremos en el
próximo capítulo. El problema de la cantidad de instrucciones no es normal-
mente resoluble, pero el Amstrad CPC 464 tiene la ventaja de que permite
utilizar las rutinas de su sistema operativo. La información que Amstra d
proporciona sobre estas rutinas le permitirá utilizarlas rápidamente, de ma-
nera que en realidad buena parte de sus programas ya ha sido escrita de he-
cho por Locomotive Software al desarrollar el sistema operativo del orde-
nador.
3
Primeras nociones
Antes de introducirse en el digo de máquina, es necesario conocer algunos
conceptos, aunque sea de manera elemental; comenzaremos por explicar
brevemente estas nociones.
Hexadecimal y binario
Son dos sistemas de numeracn: el binario en base 2, y el hexadecimal en
base 16. El lector posiblemente conocerá ya el sistema binario y no le parece-
muy pctico para realizar operaciones. Sin embargo, es el único método
que puede utilizar el ordenador. Como el microprocesador sólo reconoce
dos estados, encendido y apagado (correspondiendo 1 a encendido y 0 a apa-
gado), debe trabajar en sistema binario.
Cada cifra binaria, o bit para abreviar (de binary digit), posee un valor
relativo que depende de su posición. Ocurre como con el sistema decimal,
donde hay la cifra de las unidades, la de las decenas, la de las centenas, etc.
En el sistema binario cada cifra puede tener sólo el valor uno o cero, luego
los valores relativos a la posición deben ser reducidos. Si utilizásemos los
mismos valores que en el sistema decimal sólo podríamos representar los nú-
meros cero, uno, diez, once, cien, ciento uno, etc .
El Amstrad almacena la información en conjuntos de 8 bits; cada uno de
ellos es un byte (se pronuncia 'bait'). También maneja grupos de dos bytes
o 16 bits: las denominadas palabras. En una palabra, los valores relativos
correspondientes a los diferentes bits son los siguientes:
BIT NUMERO
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
32768 16384 8192 4096 2048 1024 512 256 12 8 64 32 16 8 4 2 1
7
8 DIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
Con este sistema de numeración, una palabra puede representar con los sím-
bolos 0 y 1 cualquier número comprendido entre 0 y 65535. Observe que el
bit menos significativo se numera como bit 0.
Muchas veces hay que representar números negativos. Vamos a ver lo que
ocurre cuando restamos a 0 el número 1 para obtener - 1 . Por brevedad lo
haremos sólo con un grupo de 4 bits; se tiene que
0000
-1 0- l = 1 y llevamos 1
-1 0 - 1 = 1 y llevamos 1
-1 0 - 1 = 1 y llevamos 1
-1 0 - 1 = 1 y llevamos 1
1111
luego la respuesta es el mero binario 1111, que es el decimal 15. Utilizando
8 bits o 16 bits hubiésemos obtenido 255 o 65535, respectivamente.
Cuando el resultado de una resta es un número negativo, ocurre siempre
que el bit más significativo (el de la izquierda) se coloca a 1. Estos nos da
la pista de cómo se representan los meros negativos.
Cuando se usan meros negativos, se utiliza el convenio de que el bit más
significativo representa el signo: 1 para el signo menos y 0 para el signo s.
Esto cambia el intervalo de los números que podemos representar. Con 16
bits los números van de -3276 8 a +32767; con 8 bits, de -128 a +127 . Para
cambiar un número de signo el procedimiento consiste en cambiar los unos
por ceros, y viceversa, y finalmente sumar 1. Esta técnica de representacn
es la que se denomina "de complemento a dos".
En nuestros programas deberemos emplear, dependiendo del caso, la re-
presentacn binaria normal sin signo o la representacn en complemento
a dos. Mencionaremos en cada instrucción el tipo de representación
requerido.
El ensamblador GENS permite utilizar números binarios; éstos debe ir
precedidos del símbolo %.
Pero, ¿por qué el sistema hexadecimal? Para el ordenador no representa
ningún problema trabajar con ceros y unos, pero para nosotros constituye
una enorme dificultad. Normalmente el sistema decimal será el que utilizare-
mos con menor dificultad, pero en ciertas ocasiones nos será mas fácil razo-
nar en binario. Por ejemplo, para cargar un byte de manera que cada medio
byte represente el número decimal 9, es más fácil trabajar en binario. Como
PRIMERAS NOCIONES 9
1*8 + 0*4+0*2+1*1=9, 9 equivale a 1001, luego lo que necesitaremos te-
ner es Í001 1001; el valor decimal es entonces
1*128 + 0*64+0*32+1*16+1*8+0*4 + 0*2+1*1
o sea, 153. Sorprendido,¿verdad?
En medio byte se pueden almacenar número s entre el 0 y el 15, es decir,
un total de 16 números. Para trabajar con números binarios es cómodo
agruparlos por medios bytes, utilizando así el sistema de numeración en base
16 o hexadecimal. En el ejemplo anterior hubiésemos dicho que había que
cargar el número hexadecimal 99, así de sencillo.
Este sistema necesita 16 cifras diferentes. Las primeras son las que van del
0 al 9; para las restantes no se emplean nuevos símbolos, sino que se utilizan
las primeras letras del alfabeto. La letra A representa en número decimal 10,
la B el 11, y así sucesivamente hasta la F, que representa el 15.
Otro problema que hay que resolver es el de señalar de alguna manera que
un número está en hexadecimal, para que no se confunda con uno decimal.
Lamentablemente, no existe para ello ningún convenio que se emplee con
generalidad. El Amstrad utiliza el símbolo &, el Firmware Speccation Ma-
nual utiliza £ y el ensamblador GENS utiliza #; otros ensambladores utilizan
una h miscula o mayúscula.
En este libro los meros hexadecimales in seguidos de la letra minúscu-
la h, excepto en los listados del ensamblador GENS, en los que aparecerán
precedidos de #.
ASCII
ASCII es la abreviatura de American Standard Code for Information Inter-
change, que es un código (el más utilizado) para representar caracteres alfa-
ticos, numéricos y de control mediante números. Este digo está impreso
en el andice III de la Ga del Usuario de Amstrad.
Dirección
Es un número que se utiliza para referenciar las posiciones de memoria. Ca-
da posición de memoria posee una dirección; se comienza por la 0 para la
primera posición y se llega hasta la 65535 (FFFFh). Las direcciones se suelen
dar en hexadecimal. Casi todos los ensambladores dan en la primera colum-
na de sus listados la dirección en la que se coloca cada instruccn.
10 DIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRA D
Ensamblador
Hemos hablado varias veces de ensambladores, pero ¿qué es un ensambla-
dor? Vamos a explicarlo.
Un ensamblador es un programa que nos permite crear programas en có-
digo de máquina escribiendo las instrucciones en forma descriptiva y fácil
de recordar en lugar de hacerlo con ceros y unos. Los códigos que sirven pa-
ra representar así las instrucciones se llaman códigos nemotécnicas. El en-
samblador nos permite escribir los programas en esta forma y, cuando he-
mos terminado, los traduce (los ensambla) a ceros y unos, que es lo que en-
tiende el microprocesador.
Normalmente los ensambladores disponen también de un editor, que per-
mite realizar con facilidad la escritura y corrección del texto de los progra-
mas. Si no fuera por esta ayuda habría que reescribir completamente el pro-
grama cada vez que se encontrase un error en alguna de las instrucciones.
El programa que se escribe con el editor se denomina programa fuente;
es un programa que no se puede ejecutar mientras no se lo haya ensamblado
con éxito. El programa fuente se puede guardar en cinta para su utilización
posterior. El programa ya ensamblado, que es el ejecutable, se denomina
programa objeto o digo objeto.
El programa objeto también puede ser grabado en cinta, bien sea con el
comando T del ensamblador GENS o desde BASIC. Para grabar en cinta
desde BASIC un programa objeto, se utiliza el comando SAVE, cuyo for-
mato es
SAVE "nombre",B,dirección inicial,longitud,punto de entrada
El punto de entrada es la dirección de memoria en la que comenzará la ejecu-
ción del programa cuando éste sea cargado con el comando "RUN" . Si no
se ha especificado esta dirección y este utiliza el comando "RUN", se produ-
cirá una reinicializacn del ordenador.
Un ensamblador permite utilizar lo que se conoce por etiquetas para rea-
lizar llamadas a las distintas partes de un programa en código de máqui-
na, en lugar de hacer las llamadas directamente a las posiciones de memoria.
Se trata de una de las funciones más importantes de los ensambladores y
permite hacer las llamada s de manera similar al Pascal. (Pascal en un len-
guaje de alto nivel, como lo es BASIC, pero sus programas no son ejecuta-
dos hasta haber sido ensamblados. Los programas objeto que se crean con
este lenguaje no son tan rápidos como los que se programan en lenguaje en-
samblador, y ocupan más espacio, pero son mucho más rápidos que los de
BASIC).
En lugar de llamar a las subrutinas con GOSUB seguido de un número de
nea, lo que se hace en Pascal es dar un nombre a cada subrutina . Este nora-
PRIMERAS NOCIONES 11
bre se puede colocar en el programa y, cuando se la encuentra, se ejecuta
la subrutina. El ensamblador permite poner una etiqueta (que será un nom-
bre seguido del símbolo ':') al lado de una instrucción; para llamar dicha ins-
trucción se utiliza entonces la etiqueta. Es como si en BASIC se pudiera utili-
zar GOSUB seguido del nombre de la subrutina, sin necesidad de especificar
en qué línea comienza ésta.
El ensamblador utiliza también seudo-operaciones; se las escribe de mane-
ra semejante a las operaciones normales del Z80, pero su efecto es diferente.
Las principales son:
; Hace que el resto de la línea sea considerado un comentario (co-
mo el REM de BASIC); el ensamblador ignora lo que sigue al
punto y coma.
EQU de EQUate oEQUals. Sirve para representar un número por una
etiqueta. Primero se escribe la etiqueta, seguida de los dos pun-
tos; a continuación se pone EQU y luego el número. Si se utiliza
por ejemplo ETIQ: EQU #1234, entonces la etiqueta ETIQ se in-
terpretará como el número 1234h (4660 decimal) cada vez que
aparezca.
DEFB de DEFine Byte. Define el contenido de un byte. El byte que co-
rresponda a la instrucción será cargado con el valor que sigue a
DEFB. Por ejemplo DEFB #20 cargará el mero 20h en el byte
que corresponda al ensamblar el programa.
DEFW de DEFine Word. Es como la anterior, pero carga un número de
16 bits en dos posiciones sucesivas de memoria.
DEFM de DEFine Message. Coloca los códigos ASCII del mensaje en-
trecomillado que se escriba después de DEFM en posiciones su-
cesivas de memoria.
DEFS de DEFine Space. El ensamblador dejará en blando tantas posi-
ciones de memoria como indique el mero que sigue a DEFS .
ORG de ORiGinate. El mero que sigue a ORG será la dirección que
se dará a la instrucción siguiente al ensamblar el programa.
ENT de ENTry. El número que sigue a ENT indica la direccn en que
comenzará la ejecución del programa objeto cuando se utilice el
comando J del ensamblador.
El programa CARGADOR HEX (que se encuentra en el apéndice B y del
que hablaremos más adelante) necesitará que le proporcionemos la dirección
inicial de una sección de programa; la encontraremos en los listados a conti-
nuación de ORG.
Cuando se desee ejecutar un programa desde BASIC se deberá llamar con
CALL a la posición en que debe arrancar el programa; en los listados, esta
dirección figura a continuación de ENT.
12 CÓDIGO MÁQUIN A PARA PRINCIPIANTES CON AMSTRAD
Listados de ensamblador
Los listados de los programas que proporciona el ensamblador se componen
de 5 columnas, o de 6 cuando se utilizan comentarios (que in precedidos
de ';').
La primera columna contiene las direcciones en que comienzan las instruc-
ciones. Habitualmente la dirección figura en forma hexadecimal.
La segunda proporciona la versión hexadecimal de la instrucción de códi-
go de máquina, correspondiendo cada byte a dos cifras hexadecimales. Para
cargar un programa con el CARGADOR HEX del apéndice B, ésta será la
versión que tendremos que utilizar.
La tercera es un mero de línea y no se utiliza más que al escribir el
programa.
La cuarta columna la ocupan las etiquetas. En el listado no figuran los dos
puntos que deben colocarse detrás del nombre de la etiqueta al escribir el
programa. Si se copia un programa de un listado hay que acordarse de colo-
car los dos puntos detrás de cada etiqueta.
La quinta está ocupada por el código nemotécnico de la operación, tal co-
mo se escribe cuando se utiliza un ensamblador.
En la sexta columna puede aparecer un comentario.
Tras esta información básica, puede usted continuar la lectura.
4
Diagramas de flujo
Como ayuda para el diseño y el desarrollo de un programa se utilizan a veces
diagramas de flujo, que son esquemas simbólicos de las distintas partes del
programa. Existe una serie de símbolos, con significado estándar, que se uti-
lizan para realizar estos diagramas. Los más utilizados son los que se mues-
tran en la figura 4.1.
Terminador Proceso/operacn Decisión
ne a de comunicación Entrada/salida Dirección del flujo
Figura 4. 1
Hay muchos otros símbolos, pero son menos utilizados.
Los diagramas de flujo sirven para aclarar la secuencia de operaciones que
realiza el programa. En la preparación de muchos programas es casi impres-
cindible comenzar por realizar el diagrama de flujo, para analizar las dife-
rentes acciones que se deben realizar. También ayuda a prevenir los fallos
antes de que ocurran, ya que permiten abarcar todo el programa de un
vistazo.
Como ejemplo, la figura 4.2 nos muestra el diagrama de la operación que
consiste en cargar en el ordenador un programa grabado en cinta.
13
14 CÓDIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
Figura 4.2
Los diagrama s de la figura 4.3 ilustran la diferencia entre los bucles WHI-
LE y los bucles FOR NEXT de BASIC. La diferencia entre ambos es
evidente.
PRINCIPIO
ENCENDER
ORDENADOR
CINTA
PUESTA
?
N
PONER
CINTA
NCINTA
REBOB.
?
REBOBINAR
CINTA
PULSAR
CTRL + ENTER
PEQUEÑA
FIN
Figura 4.3
DIAGRAMAS DE FLUJO 15
EJECUTAR
INTERIOR
BUCLE
FIN FIN
ESTABLECER
LIMITES DEL
BUCLE
PRINCIPIO PRINCIPIO
WHILE/WEND FOR/NEXT
ESTABLECER
LIMITES
DEL BUCLE
EJECUTAR
INTERIOR
BUCLE
LIMITE
ALCANZADO
?
LIMITE
ALCANZAD O
?
N
S
N
5
Primeras instrucciones en código de quina
Instrucciones de carga
El Z80 tien e 14 registros, en los que se almacenan valores de manera similar
a como lo hacen las variables enteras en BASIC. La figura siguiente repre-
senta esqueticamente estos registros y la función que realizan. No se preo-
cupe si hay muchas cosas que no entiende; el objetivo de este libro es precisa-
mente aclarárselas.
Acumulado r
REGISTROS
DE USO
GENERAL
R. DE
INTERRUPCIÓN
REGISTROS
ÍNDICE
PUNTERO
DE PILA
CONTADOR DE
PROGRAMA
REGISTRO
DE ESTADO
REG. DE
REGENERACIÓN
DE MEMORIA
Figura 5.1
17
18 CÓDIGO MÁQUINA PARA PRINCIPIANTE S CON AMSTRA D
En este capítulo vamos a utilizar los seis registros de uso general: B, C,
D, E, H y L; usaremos tambn el registro acumulador, A, y el registro con-
tador de programa, PC, que se utilizan para tareas especiales.
El acumulador y los registros de uso general pueden almacenar un número
comprendido entre 0 y 255, están formados por 8 bits y pueden ser cargados
de tres maneras diferentes. Par a entender las formas en que se pueden cargar
estos registros, continuando con la analogía entre un registro y una variable
de BASIC, escriba el programa de la figura 5.2. No es necesario que borre
el primer programa si está todavía en la memoria.
180 CLS
190 WINDOW#1, 1, 40, 1, 10
200 WINDOW#2, 1, 40, 13, 23
210 WINDOW#3, 1, 40, 12, 12
220 PEN#3, 2 : PRINT#3, " DECIMAL BINAR
IO
HEX"
230 INPUT#1, "INTRODUZCA UN NUMERO ";A
240 IF A > 255 THEN PRINT#1, "NUMERO NO
VALIDO, DEBE SE R MENOR DE 256": GOTO 230
250 A = INT (A)
260 PRINT#2,USING "######"; A; : PRINT#2
, " "; BIN$(A,8); " "; HEX$ (A,2)
270 PRINT#1 : PRINT#2
280 GOTO 230
Figura 5.2
Al ejecutar el programa con RUN 180, se le pedirá que introduzca un nú-
mero. La variable A del programa representa el acumulador. Al introducir
un mero éste se carga en A, donde queda almacenado para su posterior
utilización en otras tareas del programa. En este caso, si el número está entre
0 y 255, aparecerá en la pantalla en tres formas: decimal (que es como se lo
ha introducido) , binaria (que es como lo almacena el ordenador) y hexadeci-
mal. Si, por ejemplo, el número introducido es 77, se cargará en A el valor 77.
La instrucción en código de máquina que permite cargar 77 en el acumula-
dor es 'LD A,77', que es bastante fácil de recordar. 'A' es el símbolo del acu-
mulador y 'LD' es la abreviatura de load, que es cargar en inglés. En reali-
dad, LD A,77 no es una instruccn que entienda el ordenador directamente.
Lo que el ordenador necesita es 00111110 seguido de 01001101, o bien 3Eh
seguido de 4Dh, o 62 y 77 en decimal. Pero, si tenemos un ensamblador,
podremos escribir LD A,77 y el ensamblador se encargará de traducirlo.
LD A,77 es el código nemotécnico de la operación.
PRIMERAS INSTRUCCIONES EN CÓDIGO DE QUINA 19
Volvamos ahora a la línea 90 del programa del capítulo 2. Era una senten-
cia DATA y el tercer dato era 62, el código de la instrucción para cargar el
acumulador. El dalo siguiente era 65, el código ASCII de la 'A', que era la
letra que queamos escribir 255 veces. Justamente, 255 es el segundo dato
de la línea. Pero el 6, ¿qué representa? El código de la operacn que sirve
para cargar el registro B con un número es 00000110 en binario o 6 en deci-
mal y hexadecimal. Las dos primeras instrucciones del programa en código
de máquina eran, pues,
LD B,255
LD A,65
No tendrá ahora dificultades para cambiar un poco aquel programa. Puede
cambiar el número de veces que es escribe el carácter y tambn el cacter
que se debe escribir.
Al cambiar el programa deberá suprimir o modificar la línea 40. Estaba
pensada para comprobar, mediante el resultado de una suma, la exactitud
de los datos de la línea 90. Si usted los cambia sin s, la suma le daa
incorrecta.
Para cambiar el carácter que se escribe tendrá que consultar la tabla de
códigos ASCII y encontrar el del cacter que desea; la tabla está en el apén-
dice III de la Ga del usuario de su Amstrad. Cambie el 65 por el digo
que desee, pero no utilice ninn valor inferior a 32, pues se trata de códigos
de control y obtenda resultados inesperados.
Cambie también el 255 por el número de veces que desea que se imprima
el carácter; este mero no puede exceder de 255. Sin embargo, si reemplaza
255 por 0 encontrará que el carácter se escribe 256 veces; ¿por qué? La línea
60 del programa, que contiene en BASIC el proceso alogo al que realiza
la rutina de código de máquina, puede darnos la explicación. El registro B
contiene 0 y en el primer paso se cambia este valor por B-1=0-1. Ahora
bien, la operación en binario da 00000000b-00000001b=11111111B, que es
255. La misma respuesta le dará el ordenador si usted escribe '?BIN$(-1)'.
¿Le parece confuso?; repase entonces el catulo 3 de este libro o el apéndice
II de la Guía del usuario.
Todos los registros de uso general pueden ser cargados con un número de
8 bits de la misma manera que A y B. Los códigos de las operaciones son
los que se muestran en la figura 5.3. En todos los casos, n representa el nú-
mero, entre 0 y 255 decimal (FFh y 11111111b), que se debe cargar en el
registro.
Si observa atentamente el digo binario debe notar dos cosas. Lo prime-
ro que comienza y termina igual en todos los casos. Estas dos partes son las
que indican al microprocesador que debe cargar un número en un registro.
En segundo lugar, el registro que se carga viene indicado por los bits 5,
2 0 CÓDIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
ENSA MBLADOR D EC IM A L HEX B I N A R I O
LD B,n
LD C,n
LD D.n
LD E,n
LD H,n
LD L,n
06
14
22
30
38
46
n
n
n
n
n
n
06
0E
16
1E
26
2E
n
n
n
n
n
n
00
00
00
00
00
00
000
001
010
011
100
101
110
110
110
110
110
110
n
n
n
n
n
n
LD A,n 62 n 3E n 00 111 110 n
Figura 5.3
4 y 3. Siempre que una operación concierne a uno de los registros de uso ge-
neral se utilizan estas mismas combinaciones de 3 bits para decirle de qué
registro se trata. Así pues,
B es siempre 000
C es siempre 001
D es siempre 010
E es siempre 011
H es siempre 100
L es siempre 101
A es siempre 111
Figura 5.4
De las 8 posibles combinaciones de 3 bits falta la 110; ésta se utiliza para
un objetivo especial que explicaremos en este mismo capítulo.
De la misma manera que es posible cargar un registro directamente con
un número, también es posible hacerlo indirectamente con el contenido de
otro registro o con el contenido de una posición de memoria.
Piense en la sentencia de BASIC A=B. Lo que hace es cargar en la varia-
ble A el mismo valor que hay cargado en la variable B. Esto, sin embargo,
PRIMERAS INSTRUCCIONES EN CÓDIGO DE MÁQUINA 21
no cambia el valor que haya en B. Puede comprobarlo escribiendo las líneas
de la figura 5.5 y ejecutándolas con RUN 300; tras la línea 320, A tendrá
el mismo valor que B, pero B no habrá cambiado.
300 B = 10
310 PRINT " ANTES: A=";A;" B=";B
320 A = B
330 PRINT "DESPUES: A=";A;" B=";B
Figura 5.5
Sabiendo que el digo de máquina nemotécnico equivalente a la senten-
cia de 300 es LD B,10, ¿cual será el equivalente a la sentencia de la línea 320?
No es difícil imaginar que es LD A,B- De manera similar se obtienen todas
las instrucciones de carga de un registro en otro.
En lo que se refiere al digo binario de estas instrucciones, se forma de
manera parecida al de la carga de un registro con un número. Los bits 7 y
6 son ahora 01 en lugar de 00; los siguientes 3 bits son el identificador del
registro de destino; finalmente, los 3 últimos se completan con el código del
registro de origen en lugar del fijo 110. Así, tenemos ahora
ENSAMBLADOR DECIMAL HEX BINARI O
LD A,B 120 78 01 111 000
Recuérdelo, el código para cargar un registro en otro tiene fijos los bits
7 y 6 con 01, los 3 bits siguientes representan al registro de destino y los 3
últimos al registro origen. Puede usted ejercitarse en encontrar los digos
de las diferentes posibilidades.
Ya conocemos dos formas de cargar registros. Habrá observado que la
forma de construir ías instrucciones es completamente lógica. Si lo ha enten-
dido así no tendrá dificultades para seguir.
Tocios los registros de uso general poseen aspectos específicos que serán
examinados a lo largo del libro. Lamentablemente, y en esto se diferencian
mucho de las variables de BASIC, no está en la mano del usuario decidir las
limitaciones que posee cada registro. Cuando se enciende el ordenador, cual-
quier variable puede servir para cualquier cosa; por el contrario, sólo ciertos
registros pueden servir para determinadas tareas.
Esto puede entenderse mejor con ayuda de un ejemplo. Añada usted al
programa del capítulo 2 la línea '21 DEFSTR A' y ejecute el programa. Ob-
2 2 CÓDIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
tendrá un mensaje de error que se debe a la utilizacn como variable numé-
rica de una variable que sólo puede ser una cadena literal.
Observemos asimismo la diferencia que existe entre las instrucciones de
BASIC '?8' y '?PEEK(8)' La respuesta a la primera se 8, mientras que
la segunda imprimirá 195. No es lo mismo preguntar "qué es 8" que pregun-
tar "qué hay en la posición 8 de la memoria".
Pues bien, también es posible cargar en un registro "el contenido" de una
posición de memoria. Pero ahora el acumulador A es el único registro de 8
bits que se puede cargar de esta manera. Vamos a explicar el equivalente a
la instrucción de BASIC
A=PEEK(nn)
donde nn es un número de 16 bits.
Si se desea cargar el acumulador A con el contenido de la posición de me-
moria número 8, la instruccn nemotécnica no puede ser LD A,8, pues ésta
cargaría en el acumulador el número 8. Para indicar que se trata del contení--
do de la posición 8 (y no del número 8) se emplea el paréntesis, como en
PEEK(8), y se escribe LD A,(8). O sea, (nn) significa "el contenido de nn".
También se puede realizar la operación contraria, equivalente a POKE
nn,A, para cargar una posición de memoria con el contenido del acumula-
dor A. Su código nemotécnico es LD (nn),A. Por ejemplo, la instrucción
LD (40000),A sirve para cargar en la posición de memoria 40000 el conteni-
do de A.
Si no se dispone de ensamblador, las cosas se complican un poco más,
aunque no demasiado. Los códigos son
ENSAMBLADO R DECIMA L HEX BINARIO
LD A,(nn) 58 n n 3A n n 00 111 010 n n
LD (nn),A 50 n n 32 n n 00 110 010 n n
El número nn representa una dirección de memoria y es de 16 bits, es de-
cir, ocupa dos posiciones de memoria. Es fundamental saber y recordar que
para el mero nn cada una de las dos n se debe calcular mediante la
rmula:
nl=número MOD 256 y n2=INT(número/256)
Puede parecer sorprendente que, de los dos bytes que componen el número
nn, el menos significativo se deba colocar primero y el más significativo el
segundo. El Z80 trabaja siempre de esta manera con los números de 16 bits,
tanto para cargarlos como para almacenarlos en memoria.
PRIMERAS INSTRUCCIONES EN CÓDIGO DE QUIN A 23
Es fácil escribir un pequeño programa que calcule para cada número de
16 bits los números n1 y n2. Pero no conviene utilizar la funcn MOD del
ordenador ya que, al utilizarse a veces la representación normal de un entero
y otras la notacn en complemento a 2, resulta desaconsejable para núme-
ros mayores de 32767. Es mejor utilizar nuestra propia fórmula y escribir
1010 N2 = INT(NUMERO/256) : N1 = NUMER O
- N2 * 256 : PRINT "N1 =";N1;" N2 =";N2
Si ahora ejecutamos esta linea con
N U M E RO = 40 0 0 0 : G O T O 1010
obtendremos N1=64 N2=156 como respuesta. Con estos números pode-
mos construir los códigos completos de carga y descarga de la posición
40000,
ENSAMBLADOR DECIMAL HEX
LD A,(40000) 5B 64 156 3A 40 9C
LD (40000),A 50 64 156 32 40 9C
BINARI O
LD A,(40000) 00 111 010 0100 0000 1001 1100
LD (40000),A 00 110 010 0100 0000 1001 1100
y, análogamente, los de la posicn 8,
ENSAMBLADO R DE CI MA L HEX
LD A,(8) 58 8 0 3A O8 00
LD (8),A 50 8 0 32 O8 00
BINARIO
LD A,(8) 00 111 010 0000 1000 0000 0000
LD (8),A 00 110 010 0000 1000 0000 0000
24 CÓDIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
Puede practicar con lo que acabamos de ver cambiando el programa del
capítulo segundo. En aquel programa se utilizaba la instrucción LD A,65,
que ahora podemos sustituir por LD A,(8), por ejemplo. Para ello la linea
90 se debe sustituir por
90 DATA 6,255,58,8,0,205,90,187,16,251,20 1
cambiando en consecuencia la cantidad de la linea 40 que se emplea en la
comprobación por 1277.
Es importante cambiar la línea 30 por
30 FOR N=43800 TO 43810:READ D:POK E N,D:A=A+D:NEXT
ya que hay un byte más en la rutina.
Para hacer que la rutina BASIC de la línea 60 corresponda a la nueva ruti-
na en código de máquina, la línea 60 se debe sustituir por
60 PRINT CHR$(PEEK(8)); : B=B-1 : IF B<>0 THEN 60
Finalmente, se debe borrar la línea '21 D E F S T R A' si fue introducida. Al
ejecutar ahora el programa se obtendrá el símbolo que corresponde al códi-
go 195 (una barra \) en lugar de la A.
Pasaremos a continuación a explicar otra forma de utilizacn de los regis-
tros de uso general. Los registros de uso general pueden ser utilizados agru-
pados en los pares BC, DE y HL, constituyendo así 3 registros de 16 bits .
Esto permite utilizar registros que pueden cargar números comprendidos en-
tre 0 y 65535, en lugar de entre 0 y 255 como antes.
Una diferencia con respecto de la utilización individual de los registros es
que no hay ninguna instrucción del tipo LD rr,rr', que permita cargar un par
de registros con el contenido de otro par. Por el contrario, existen otras dife-
rencias en sentido positivo.
Para cargar en un par de registros rr un número nn de 16 bits, el código
nemocnico es LD rr,nn (rr representa BC, DE o HL). Así, las instrucciones
LD BC,40000
LD HL,8
sirven para cargar 40000 en el par BC y 8 en el par HL, respectivamente.
La construccn de los códigos binarios es similar a la de los códigos de
las instrucciones LD r,n. Los 2 primeros bits son 00 como en aquel caso.
Después vienen 2 bits que indican el par que se carga; son simplemente los
mismos cuando actúa un par de registros:
PRIMERAS INSTRUCCIONES EN CÓDIGO DE MÁQUINA 25
00 es siempre el par BC
01 es siempre el par DE
10 es siempre el par HL
Luego viene un 0 y finalmente los 3 bits 001. Tenemos así
ENSAMBLADOR DECIMAL HEX BINARIO
LD BC,n n 1 n n 01 n n 00 000 001 n n
LD DE,n n 17 n n 11 n n 00 010 001 n n
LD HL,nn 33 n n 21 n n 00 10 0 001 n n
El código del número nn ocupa 2 bytes y se obtiene como indicamos ante-
riormente (primero el byte menos significativo). Por ejemplo,
ENSAMBLADOR DECIMAL HEX BINARIO
LD BC,40000 1 64 156 01 40 9C 00 000 001 0100 0000 1001 1100
LD HL,8 33 8 0 21 08 00 00 100 001 0000 1000 0000 0000
Como los pares de registros cargan números de 16 bits y éste es también
el tamaño de las direcciones de memoria, se los utiliza particularmente para
apuntar a posiciones de la memoria. Ya hemos dicho que no existen las ins-
trucciones LD r,(nn) ni LD (nn),r cuando r es un registro de uso general; pe-
ro hay una forma de suplir esa carencia. Se trata de apunta r a la dirección
cuyo contenido se desea cargar (o viceversa) con el par HL. Todo ocurre co-
mo si en BASIC estuviese prohibido utilizar 'B= PEEK (8)', pero se pudiese
hacer 'B=PEEK(HL)' dando a HL el valor 8.
Se puede cargar cualquier registro de uso general, y tambn A, con el
contenido de la memoria a la que apunta el par HL. Tambn se puede car-
gar la posición de memoria a la que apunta HL con el contenido del acu-
mulador o de un registro de uso general. Estos dos tipos de instrucciones
tienen códigos nemocnicos de la forma LD r,(HL) y LD (HL),r. Aquí re-
presenta A, B, C, D, E, H o L. Los paréntesis que rodean HL significan que
se trata del contenido de una posicn de memoria (y no del contenido de
HL).
Sus códigos binarios completan el vacío que existía en los códigos que co-
menzaban por 01; interviene aquí justamente el código de 3 bits 110b, que
no representaba ningún registro. Los códigos de ambas comienzan por 01.
Los de LD r,(HL) son de la forma
[01] [código de 3 bits del registro] [110]
26 DIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
y los de LD (HL),r, de la forma
[01] [110] [código de 3 bits del registro]
Po r ejemplo, los código s
ENSAMBLADOR DECIMAL HEX BINARIO
LD HL,40000 33 64 156 21 40 9C 00 100 001 0100 0000 1001 1100
LD D,(HL) 86 56 01 010 110
sirven para cargar en D el contenido de la posición 40000 de memoria, y los
digos
ENSAMBLADO R DECIMAL HEX BINARIO
LD HL,8 33 8 0 21 08 00 00 100 001 0000 1000 0000 0000
LD B,(HL) 70 46 01 000 110
para carga r en B el contenido de la dirección 8 de memoria.
Para probar sus nuevos conocimientos puede cambiar la rutina ya utiliza-
da, sustituyendo la línea 90 por
90 DATA 33,8,0,70,58,8,0,205,90,187,16,251,201
y realizando en el programa los cambios necesarios. La suma de comproba-
ción de la linea
40
será ahora
1127
; en la línea
30
el límite superior del bucle
debe ser
43812
. Finalmente, par a que la rutina BASIC de la línea
60
coincida
con la de digo de máquina , deberá poner
HL=8:B=PEEK(HL )
en lugar
de
B=255
en la línea
50
. El comienzo de la rutina en código de máquina es
ahora
ENSAMBLADOR
LD HL,8
LD B,(HL)
LD A,(8)
DECIMAL
33 8 0
70
58 8 0
El código 110b significa, pues, (HL) cuando se lo coloca en la posicn
que debe ocupar un registro. En otros casos tiene un significado diferente;
así, una instruccn del tipo LD r,n cuyo código es '[00] [código de r] [110]',
el 110 significa que el siguiente byte debe ser interpretado como un número.
Pero en esta misma instrucción, si 110b se coloca en el lugar de r formando
el código 00 110 110, este código es el de la instrucción LD (HL),n, cuya
PRIMERAS INSTRUCCIONES EN CÓDIGO DE MÁQUINA 27
finalidad es colocar el número n en la posicn de memoria a la que apunta
HL.
Observe finalmente que la sustitución en la instruccn LD r,r' de ambos
registros por (HL) carece de sentido y que por lo tanto el código 01 110 110
no tendrá el significado de una instrucción de carga. De hecho, este digo
posee un sentido completamente diferente: su efecto es detener el Z80.
Cuando se utiliza el acumulador, las instrucciones de carga relativas a una
posición apuntada por un par de registros pueden usar como puntero, no só-
lo el par HL, sino tambn los pares BC y DE. Es decir, son válidas .las ins-
trucciones LD A,(rr) y LD (rr),A cuando rr es cualquiera de los pares BC,
DE y HL, lo que nos da las nuevas instrucciones
LD DE,8
LD A,(DE )
El diso de los códigos binarios de estas operaciones difiere del de las ins-
trucciones LD A,(HL ) y LD (HL),A, que empezaban por 01 (recuerde que
las posibilidades de comenzar por 01 están agotadas). Lo que hacen es seguir
el modelo de las instrucciones LD A,(nn) y LD (nn),A.
Los códigos que representan pares de registros y los que representan un
registro están relacionados de forma sencilla: el código 00 representa el par
BC, y los códigos para B y C son 000 y 001, es decir, comienzan con 00. Lo
mismo ocurre con DE, D y E (01, 010 y 011) y con HL, H y L (10, 100 y 101).
El código de LD A,(nn) es 00 111 010. En las instrucciones de carga de
un par, que también comenzaban por 00, los bits 5 y 4 representaban el códi-
go del par. Aquí esos bits contienen 11, que es el único código de dos bits
que no estaba asignado. Esto explica que el digo de LD A,(BC) sea 00 001
010 y el de LD A,(DE) sea 00 011 010.
Siguiendo esta lógica, 00 101 010 debea ser el digo de LD A,(HL),
pero ya sabemos que no es asi; pronto diremos a qué corresponde este -
digo.
El código de LD A,(nn) es 00 110 010; la misma lógica que antes lleva a
que el código de LD (BC),A sea 00 000 010 y el de LD (DE),A 00 010 010.
Tampoco en este caso 00 100 010 es el código de LD (HL),A.
Estas instrucciones de carga se refieren a cantidades que ocupan un byte.
Las que vamos a ver a continuacn transfieren cantidades que ocupan dos
bytes. Además vamos a encontrar un dueño para los dos códigos que no lo
tenían.
Se trata de las intrucciones LD HL,(nn) y LD (nn),HL, que funcionan de
manera similar a LD A,(nn) y LD (nn),A, es decir, cargando el contenido
del registro en una posición de memoria o viceversa. En primer lugar está
la cuestión del código binario. Este código consta de un byte con el digo
de operación y dos bytes con el número de 16 bits nn, que indica una posi-
28 DIGO QUINA PARA PRINCIPIANTES CON AMSTRAD
ción de memoria. Ya hemos explicado cómo se obtienen las dos partes n1
y n2 del número nn. Por ejemplo, para nn=8 se obtiene n1 0000 1000 y n2
0000 0000.
Los códigos de operación son justamente
E N S A M B L A D O R B I N A R I O
LD HL,(nn) 00 101 010 n n
LD (nn),HL 00 100 010 n n
o sea, los que habíamos echado en falta.
Ha y sin embargo una dificultad que hemos eludido: HL almacena canti-
dades de 16 bits, mientras que la capacidad de una posicn de memoria es
de solamente de 8 bits. ¿Cómo se produce entonces la transferencia? Lo que
ocurre es que no se utiliza una posición de memoria, sino dos. La posición
de memoria nn efectúa la transferencia con L y la posición siguiente (nn+1)
con H; es decir, se tiene el esquema
Las palabras inglesas low (bajo) y high (alto) justifican las denominaciones
L y H y una manera cómoda de recordar cómo se efectúan las transferencias
con los pares de registros. De hecho, esta misma técnica se emplea para cual-
quier par de registros; el registro que se escribe a la derech a (L, C o E, según
el caso) se corresponde con la primera de dos posiciones de memoria y con
el byte menos significativo; el registro que se escribe a la izquierda (H,B o
D) se corresponde con la segunda de dos posiciones de memoria y con el byte
s significativo.
Las últimas instrucciones de carga que vamos a ver son similares, pero uti-
lizan los pares BC y DE. Son
LD BC,(nn) LD DE,(nn) LD (nn),BC y LD (nn),DE
Figura 5.6
PRIMERAS INSTRUCCIONES EN CÓDIGO DE MÁQUINA 29
Se las utiliza con menor frecuencia que las de HL porque su digo ocupa
más espacio; exactamente 4 bytes, dos para el digo y dos para nn. Los có-
digos son
ENSAMBLADOR DECIMA L HE X BINARIO
LD BC,(nn) 237 75 n n ED 4B n n 1110 1101 0 1 001 011 n n
LD DE, (nn) 237 91 n n ED 5B n n 1110 1101 01 011 011 n n
LD (nn),BC 237 67 n n ED 43 n n 1110 1101 01 000 011 n n
LD (nn),DE 237 83 n n ED 53 n n 1110 1101 01 010 O11 n n
Figura 5.7
Se observará que todos ellos comienzan por el hexadecimal ED (1110 1101b
o 237 decimal, pero el hexadecimal es más fácil de recordar). El prefijo ED
es el que sirve para alterar el significado del segundo byte, lo que debe recor-
darle algunas consideraciones sobre el lenguaje que hicimos en el catulo 2.
Al final de este catulo incluimos un pequo resumen de las instruccio-
nes que comienzan por LD. También encontrará una descripción más gráfi-
ca y detallada en el apéndice A.
Llamadas. El contador de programa (PC)
Siempre que el ordenador está encendido, y salvo que el microprocesador es-
té detenido por alguna razón, el registro contador de programa (que se deno-
ta por PC como consecuencia de su nombre en inglés, que es Program Coun-
ter) se ocupa de controlar las operaciones del Z80. Actúa como si su finali-
dad consistiese en aumentar su valor hasta llegar al final de la memoria y
recomenzar nuevamente. El valor almacenado en PC es el de la dirección de
memoria de la instrucción que el microprocesador debe ejecutar. Al encen-
der el ordenador el valor que se carga en PC es 0; por lo tanto debe estar
ahí la primera instrucción a ejecutar. Lo que el ordenador hace entonces es
ejecutar un programa que lo coloca a disposición del usuario, en modo BA-
SIC para el caso del Amstrad. Este programa inicial recibe el nombre de
arranque en frío.
En todo momento el microprocesador está ejecutando algún programa y,
lógicamente, es esencial tener un control sobre su evolución, o sea, sobre el
contador de programa. Si el microprocesador ejecutase linealmente las ins-
30 DIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
trucciones que hay en la memoria, el ordenador tendría la misma utilidad
que un piano en el que sólo se pudiesen tocar las teclas desde la primera a
la última. Cambiando la afinación del piano llegaríamos a tocar alguna me-
lodía, pero, a continuación, sólo podríamos hacer que la repitiese sin parar.
Por suerte es posible cambiar el orden en que el microprocesador ejecuta
las instrucciones. Las instrucciones de BASIC que alteran el orden de ejecu-
ción de las líneas de un programa BASIC son GOTO, GOSUB y RETURN,
GOTO hace que se salte a la línea indicada; GOSUB hace saltar a una subru-
tina y RETURN termina la subrutina y devuelve el control al programa prin-
cipal. En código de quina existen las instrucciones equivalentes a éstas.
Las que equivalen a GOTO tienen como códigos nemotécnicos JP y JR, que
provienen de la palabra jump (salto). Las que se asemejan a GOSUB y RE-
TURN tienen los códigos CALL (llamar) y RET {return, volver).
CALL y RETURN funcionan como sus equivalentes de BASIC. La ins-
trucción CALL debe ir acompañada de la posición de memoria de la primera
instrucción de la subrutina (es lo que equivale al número de linea de BASIC).
Esta direccn de memoria ocupa 2 bytes y se carga en la forma habitual de
menos significativo y más significativo; el cálculo de estos 2 bytes se realiza
como ya hemos explicado. La instrucción CALL ocupa pues 3 bytes; uno
para el código y dos para la dirección. Los códigos de ambas instrucciones
son:
ENSAMBLADOR DECIMAL HEX BINARIO
CALL nn 205 n n CD n n 11 001 101 n n
RET 201 C9 11 001 001
Vuelva al programa BASIC del capítulo 2, cuya nea 90 contiene los datos
de un programa en código de máquina. Detrás de los valores con los que ha
experimentado anteriormente encontrará 205,90,187; se trata de una instruc-
ción CALL. El primer número es el código de CALL y los dos siguientes
proporcionan la dirección de la instruccn que se llama. Ya sabemos desci-
frar esta dirección; hay que sumar al segundo número el tercero multiplicado
por 256:
187*256 = 47872. 47872 + 90 = 47962 o BB5Ah
El programa en código de máquina comienza, pues, por cargar en el regis-
tro A el código del cacter que se debe escribir, y en el registro B el número
de veces que va a ser escrito; a continuación llama a la subrutina que comien-
za en la dirección 47962(BB5Ah). Esta subrutina es parte del sistema operati-
vo; es probablemente la subrutina del sistema operativo que deberá utilizar
con mayor frecuencia. Amsoft le ha dado el nombre de TXT OUTPUT y
PRIMERAS INSTRUCCIONES EN CÓDIGO DE MÁQUINA 31
lo que hace es escribir el cacter cuyo código se encuentra en el acumulador
en la ventana de pantalla que se esté utilizando en la actualidad.
Esta subrutina entiende tambié n los digos de control que se explican en
el catulo 9 de la Guía del usuario. Para ver cómo responde a los códigos
de control, cambie la línea 90 del programa por
90 DATA 62,7,205,90,187.201
el mero que sigue a TO en la línea 30 por 43805 y la suma de comproba-
ción de la línea 40 por 752. El programa que se carga así es, en ensamblador,
LD A.7
CALL 47962
RET
Al ejecutarlo debe usted oir un pitido. Si no es a, vuelva a intentarlo te-
cleando directamente CALL 43800 seguido de la tecla [ENTER]; de esta ma-
nera estará llamando directamente al programa en código de máquina sin
necesidad de volver a ejecutar el programa en BASIC.
Al contrario de lo que ocurría en las instrucciones LD, aquí no es posible
dar la dirección de llamada como la dirección a la que apunta un par de re-
gistros. La instrucción CALL debe ir seguida de 2 bytes que representen la
dirección explícita.
Cuando al final de la subrutina se ejecuta la instruccn RET, el control
pasará a la posicn de memoria que sigue a los 3 bytes ocupados por la ins-
trucción CALL. Para poder hacer esto el microprocesador debe recordar
dónde estaba situada la instruccn CALL. Esto es posible mediante la utili-
zación de la pila, que es un pequeño archivo que utiliza el Z80. Vamos a ver
mo se utiliza la pila en el caso de las instrucciones CALL y RET, dejando
para el catulo 9 una descripción más detallada de la utilizacn de la pila.
Para imaginarse el funcionamiento de la pila viene bien compararla con
un clavo situado en el techo en el que los bytes de información se almacenan
como se haría con trozos de papel que se pinchasen en el clavo. A medida
que un dato se introduce en la pila, ésta crece hacia abajo. Po r otra parte,
la informacn de la pila sólo puede recuperarse a partir de la que está situa-
da más abajo, que es la última que se ha introducido.
La pila ocupa cierto área de la memoria. La posición de memoria más ba-
ja ocupada por la pila está siempre almacenada en el registro puntero de pi-
la, que se denota por SP (del inglés Stack Pointer). Hay que preocuparse de
que el programa no modifique involuntariamente la zona de memoria ocu-
pada por la pila; de otra manera, el programa fallaa con toda seguridad.
Lo mejor es situar la pila en lo alto de una gran zona libre de la memoria,
lo que permitirá que la pila crezca hacia abajo sin topar con otra cosa.
32 CÓDIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
MEMORIA HEX ENSAMBLADOR
AB68 3E07 LD A, #07
AB6A CD5ABB CALL #BB5A
BB5A aqui comienza
l a s u b r u t i n a
???? C9 RET
AB6D C9 RET
PUNTERO
DE PILA
PUNTERO
DE FILA
PUNTERO
DE PILA
PUNTERO
DE PILA
PUNTERO
DE PILA
PUNTERO
DE PILA
PC PILA
PRIMERAS INSTRUCCIONES EN CÓDIG O DE MAQUINA 33
Cuando el programa llega a una instrucción CALL, el microprocesador
coloca la dirección que está en el PC (la dirección de la instrucción que sigue
a CALL) en la pila y carga en el PC la dirección de la subrutina. De esta
manera, la siguiente instrucción que se ejecuta es la primera de la subrutina.
Al final de la subrutina, cuando se llega una instrucción RET, el micropro-
cesador recupera de la pila la dirección a la que debe volver y la coloca en
el PC, de manera que la instrucción que se ejecute a continuación sea la que
sigue a la instrucc n CALL.
La secuencia de la figura 5.8 muestra esqueticamente lo que sucede
cuando se ejecutan las instrucciones CALL y RET. La primera columna de
la figura contiene las direcciones (en hexadecimal) de comienzo de las ins-
trucciones; la segunda contiene el código hexadecimal de cada instrucción y
la tercera los códigos nemotécnícos de las instrucciones, con los datos numé-
ricos en versión hexadecimal. Si se ha utilizado la forma hexadecimal es para
mostrar más claramente lo que sucede, ya que así cada dos cifras hexadeci-
males corresponden a un byte de memoria. El ejemplo que se utiliza es el
programa de antes, cuyo efecto consistía en hacer sonar un pitido.
La menica es simple: al colocar un dato en la pila, ésta crece en 2 bytes;
al recuperar un dato, la pila decrece en 2 bytes. La precaución fundamental
que hay que tener al manejar la pila es no introducir ningún dato que no va-
ya a ser extraído posteriormente. Si no se tiene este cuidado se puede produ-
cir alguno de los dos errores siguientes: que la pila crezca demasiado, inva-
diendo el espacio reservado al programa, o que se recupere un dato que no
es el que se desea. Más adelante veremos instrucciones que utilizan la pila
y con las que hay que ser cuidadoso para respetar la regla fundamental de
su manejo: la cantidad de información que entra debe coincidir con la que
sale. El desequilibrio de la pila es la causa más frecuente de fracaso de los
programas. Ai contrario que en BASIC, aquí ocurre frecuentemente que lo
único que se puede hacer cuando fracasa un programa es desconectar el or-
dendor y comenzar de nuevo.
Saltos
Existen dos tipos de instrucciones de salto; el primero se asemeja totalmente
a la sentencia GOTO de BASIC. La sentencia GOTO 100 tiene el efecto de
saltar a una línea número 100 que debe existir en el programa. Como no exis-
ten números de línea en código de máquina, las instrucciones de salto trans-
fieren el control a una dirección de memoria.
El código nemocnico de este primer tipo de instrucciones es JP (abrevia-
tura de jump, o sea, salto). Este digo va seguido normalmente de 2 bytes
con una dirección, que es la del salto. La forma del salto es semejante a la
34 CÓDIG O MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
de la instrucción CALL, pero ahora no está previsto ningún regreso y en
consecuencia no se utiliza la pila. La forma completa de esta instrucción es
JP nn; permite saltar a cualquier dirección de memoria accesible. Al igual
que CALL, la instrucción se compone de 3 bytes, pero el primero, que era
11 001 101 para CALL, es ahora 11 000 011 para JP. Si en nuestro último
program a utilizamos una instruccn JP en lugar de CALL, el digo será
ENSAMBLADOR DECIMAL HEX BINARIO
JP 47962 195 70 187 C3 5A BB 11 000 011 0101 1010 1011 1011
También es posible utilizar el par de registros HL para indicar la dirección
del salto; en este caso el salto se realiza a la direccn contenida en el par
HL. El digo nemocnico de esta instrucción es fácil de averigurar si se re-
cuerda la notación de "contenido en" . El código binario ocupa sólamente
un byte. Estos códigos son:
ENSAMBLADOR DE CI MAL HE X BINARIO
J P (HL ) 2 3 3 E9 1 1 101 00 1
Los saltos están entre las instrucciones que más se utilizan. Modificados
convenientemente y combinados con la instrucción CALL, permiten crear
instrucciones análogas a las ON GOTO y ON GOSUB de BASIC; pero esto
lo explicaremos en el pximo capítulo.
Vamos a explicar ahora el segundo tipo de instrucciones de salto. Muchos
de los saltos necesarios se hacen a direcciones de memoria muy cercanas a
la dirección en la que se es, que es la del PC. Puede resultar mejor ordenar
un salto a 5 posiciones más adelante en lugar de explicitar la dirección del
salto. Para ello existe la instrucción de salto relativo, cuyo digo es JR
(abreviatura de jump relative).
La instrucción JR se compone de 2 bytes. El primero contiene el código
de operación y el segundo la magnitud del salto o, más exactamente, la dis-
tancia del salto desde la posicn marcada por el PC (que es la de la instruc-
ción siguiente) a la instrucción a la que se desea saltar. El salto puede ser ha-
cia adelante o hacia atrás, siendo así su magnitud un número positivo o ne-
gativo. En la codificación en 1 byte de este número se emplea la notacn
del complemento a 2 que explicamos en el capítulo 3; esto hace posible que
el mero vae entre +127 y 128. Los códigos de JR son:
ENSAMBLADOR D E C I M A L H E X BINA Rl O
JR n 24 n 18 n 00 01 1 00 0 n
PRIMERAS INSTRUCCIONES EN CÓDICO DE MÁQUINA 35
La utilizacn de un ensamblador evita tener que calcular la magnitud de los
saltos relativos, ya que se puede utilizar una etiqueta para marcar la posición
a la que se debe saltar (el ensamblador se encargará de los cálculos). La eti-
queta se puede definir colocándola en el programa o también mediante
la seudo-operación EQU que explicamos en el capitulo 3. Veamos dos
ejemplos.
El programa del primer ejemplo tiene por efecto hacer sonar un pitido y
escribir repetidamente la letra 'A':
ETIQUETA ENSAMBLADOR DECIMAL HEX
43880 {AB68h} LD A,7 62 3E 07
43882 {AB6Ah} PRINT: CALL 47962 205 90 167 CD 5A BB
43885 {AB6Dh} LD A,65 62 65 3E 41
43887 {AB6Fh} JR PRINT 24 249 18 F9
En este ejemplo, el 249 que hay después del digo de operación 24 sirve pa-
ra transferir la ejecución a la posición -7 en relacn con el contenido del PC
en ese momento, que será de 43889 ya que apunta a la siguiente instruccn.
Como 43889-7 = 43882, el salto se hará al comienzo de la instrucción CALL.
En el segundo ejemplo no sona el pitido, ya que la instrucción LD A,7
no se ejecuta y lo primero que se escribe es la letra 'A':
ETIQUETA ENSAMBLADOR DECIMAL HEX
43880 {AB68h} JR GO 24 5 18 05
43882 {AB6Ah} LD A,7 62 7 3E 07
43884 {AB6Ch} PRINT: CALL 47962 205 90 187 CD 5A BB
43887 {AB6Fh} GO: LD A,65 62 65 3E 41
43889 {AB71h} JR PRINT 24 249 18 F9
tese que aquí la instrucción JR GO tiene por efecto realizar un salto ¡da-
tivo de 5 posiciones a partir del contenid o del PC, pues éste contendrá la di-
rección en la que comienza la instrucción LD A,7.
En general no habrá que efectuar cálculos cuando se utilice un ensambla-
dor , salvo en el caso de programa s muy largos, pues en ellos puede ser im-
portante ahorrarse etiquetas para utilizar menos espacio.
Aquí hay que advertir que el ensamblador GENSA3 del paquete DEV-
PAC de Highsoft complica singularmente la situacn, ya que las distancias
36 DIGO MÁQUINA PAR A PRINCIPIANTE S CON AMSTRAD
de salto se calculan a partir del contador de posición del ensamblador y no
del contenido del PC; esto es lo que se explica en la página 2.6 del manual
del DEVPAC. El contador de posicn, al que se hace referencia a tras del
mbolo $, contiene la posición del comienzo de la instrucción JR cuando se
llega a esta instrucción, luego hay que añadir 2 a la magnitud del salto si se
la ha calculado de la forma habitual (a través de PC). Por ejemplo, si se de-
sea suprimir la etiqueta en el anterior ejemplo, la instruccn JR PRINT se
deberá escribir en la forma J R$- 5. en lugar del lógico JR - 7.
Por el contrario, no hay que preocuparse de esta diferencia si se utilizan
etiquetas, ya que entonces el salto se realiza en cualquier caso a la dirección
que señala la etiqueta.
Antes de terminar el catulo veremos una última instruccn que es muy
sencilla pero de gran utilidad ; permite intercambiar entre sí los contenidos
de los pares DE y HL, lo que resulta sumamente interesante cuando se tiene
HL cargado con una dirección y se desea utilizarlo para cualquier otra cosa.
Su digo es EX DE,HL, donde EX se utiliza como abreviatura de exchange
(intercambio). Los distintos digos de la instrucción son:
ENSAMBLADOR DECIMAL HEX BINARIO
E X DE , H L 2 35 EB 11 1 01 0 1 1
Por ejemplo, si DE está cargado con el mero 10 y HL con 37, tras la
ejecucn de la instrucción el par DE contendrá 37 y HL contendrá 10.
Resumen
Vamos a resumir las instrucciones explicadas en este capítulo. Utilizaremos
los símbolos:
r = cualquiera de los registros de 8 bits (A, B, C, D, E, H o L)
rr = cualquier par de registros que se utilicen como uno de 16 bits
n = un número de 8 bits, o sea, entre 0 255
nn = un mero de 16 bits, o sea, entre 0 y 65535
( ) rodeando un número o un par de registros=el contenido de la
direccn.
PC = contador de programa
SP -puntero de pila
El digo de las operaciones de carga es LD.
Todo r puede ser cargado con cualquier n; la instrucción tiene la forma
L D r,n .
PRIMERAS INSTRUCCIONE S EN CÓDIGO DE MÁQUINA 3 7
Todo r puede ser cargado con el contenido de cualquier otro r; la instruc-
ción tiene la forma LD r,r'.
El registro A puede ser cargado con el contenido de una dirección de la
memoria; la instrucción tiene la forma LD A,(nn).
Una dirección de la memoria puede ser cargada con el contenido del regis-
tro A; la instrucción tiene la forma LD (nn),A.
En las dos instrucciones que acabamos de citar se puede utilizar el conteni-
do del par HL en lugar de nn; las instrucciones se convierten en LD A,(HL)
y LD (HL),A.
Todo rr puede ser cargado con cualquier nn; la instrucción tiene la forma
LD rr,nn.
Todo rr puede ser cargado con el contenido de una posición de memoria
y la siguiente; la instrucción tiene la forma LD rr,(nn).
Una posición de memoria y la siguiente pueden ser cargadas con el conte-
nido de un par de registros; la instruccn tiene la form a LD (nn),rr.
Usando el par HL se puede reducir la longitud de las dos instrucciones
precedentes en un byte.
La llamada a una subrutina se efectúa con CALL nn. La llamada puede
ser a cualquier dirección accesible de la memoria.
Toda subrutina debe terminar con un RET.
Las instrucciones CALL y RET utilizan la pila.
Se puede saltar a cualquier posición de la memoria mediante la instrucción
JP nn.
En la instrucción precedente se puede dar la dirección del salto mediante
el contenido de HL; se ocupa así 1 byte en lugar de 3. La instrucción toma
entonces la forma JP (HL).
La magnitud de un salto relativo se cuenta a partir del comienzo de la si-
guiente instrucción y debe estar en el intervalo de +127 a -128. La forma
de la instruccn es JR n.
Los números de 16 bits se almacenan en memoria en orden invertido. El
mero está formado por 4 cifras hexadecimales; las dos más significativas
se almacenan en la posición alta (posterior) de memoria y las dos menos sig-
nificativas en la posición baja. En un par de registros el número se almacena
en la forma natural (high o alto en H y low o bajo en L para el caso del par
HL).
Los diversos códigos de estas operaciones y la función que realizan están
en el apéndice A del libro.
6
Aritmética elemental
En el catulo precedente hemos visto las instrucciones LD r,n y LD r,r, que
permian cargar un número de 8 bits en un registro, o bien un registro en
otro. Existe tambn un surtido completo de instrucciones para sumar y res-
tar; la estructura de los códigos es semejante a la de las instrucciones LD r,n
y LD r,r.
El registro A se denomina acumulador. Algunas instrucciones de carga de
un registro sólo son posibles usando el acumulador. Pero donde este registro
adquiere verdadera importancia es en las operaciones aritticas de 8 bits,
ya que es el único registro que almacena el resultado de estas operaciones.
Antes de estudiar las verdaderas operaciones aritméticas nos referiremos
a dos instrucciones con un cierto contenido matemático; pueden ser ejecuta-
das con cualquier registro de uso general. La primera incrementa en 1 el con-
tenido del registro; la segunda lo decrementa en 1. Sus códigos son INC r
y DEC r, donde r es un registro de uso general. Por ejemplo, para un regis-
tro cuyo contenido sea 99, la instruccn INC lo transformará en 100 y la
instruccn DEC en 98. También se puede hacer lo mismo con una direccn
de la memoria, apuntando a ésta con el par HL; las instrucciones son enton-
ces INC (HL) y DEC (HL). Los códigos de estas operaciones son los que se
muestran en la figura 6.1.
Se reconocen en los bits 5, 4 y 3 de la codificación binaria los digos de
3 bits correspondientes a los diferentes registros.
El funcionamiento de INC y DEC no presenta complicaciones, salvo una
muy leve en dos casos. Si el contenido de un registro es 255, una instrucción
INC lo convierte en 0. ¿Por qué? Ocurre como en los relojes: las horas
aumentan da 1 a 23, pero la hora que sigue a 23 no es 24 sino 0. Observe
que el contenido del registro es 1111 1111 en binario y que debe aumentar
en 0000 0001; el resultado será 1 0000 0000, pero sólo se pueden cargar 8
bits; se adivina así la lógica de la operación en este caso.
El otro caso se da cuando un registro contiene el valor 0 y se efectúa con
él la operación DEC. Usted mismo puede averiguar lo que ocurre entonces
si tiene en cuenta que el registro está cargado con el valor 0000 0000 y que
39
40 DIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
ENSAMBLADO R
INC B
INC C
INC D
INC E
INC H
INC L
INC (HL)
INC A
DECIMAL
4
12
20
28
36
44
52
60
HEX
04
0C
14
1C
24
2C
34
3C
BINARIO
00
00
00
00
00
00
00
00
000
001
010
011
100
101
110
111
100
100
100
100
100
100
100
100
ENSAMBLADOR
DEC
DEC
DEC
DEC
DEC
DEC
DEC
DEC
B
C
D
E
H
L
(HL)
A
DECIMAL
5
13
21
29
37
45
53
61
HEX
05
0D
15
1D
25
2D
35
3D
BINARIO
00
00
00
00
00
00
00
00
000 101
001 101
010 101
011 101
100 101
101 101
110 101
111 101
de este valor se debe restar 1. Si no encuentra la solución, relea en el capítulo
3 la parte relativa a la notación de complemento a 2.
Para comprobar el funcionamiento de estas instrucciones puede escribir
el programa de la figura 6.2, el cual, mediante las lineas 30 y 90, carga en
memoria un programa en código de máquina y luego lo ejecuta en la línea
70. La línea 60 contiene una rutina en BASIC que produce el mismo efecto
que la de código de máquina. La figura 6.3 contiene los códigos hexadecimal
y nemotécnico de la rutina.
Notará que aparece antes de RE T una instruccn que todavía no hemos
explicado (lo haremos en el próximo capítulo); sin embargo, sabiendo que
ARITMÉTICA ELEMENTAL 41
10 MM=HIMEM
20 MEMORY 43799
30 FOR N=43800 TO 43811:READ D:POKE N,D:
A=A+D:NEXT
40 IF A<>1353 THEN CLS:PEN 3:PRINT "ERRO
R EN DATA":PEN 1:EDIT 90
50 INPUT "PULSE ENTER PARA EMPEZAR";A:A=
32:B=224
60 PRINT CHR$(A);:A=A+1:B=B-1:IF B<>0 TH
EN 60
70 PRINT:CALL 43800
90 DATA 6,224,62,32,205,90,187,60,5,32,2
49,201
100 END
Figura 6.2
la rutina de la línea 60 realiza las mismas operaciones, es posible que llegue
a comprender su significado. Las letras NZ significan 'no cero' y se refieren
al resultado de la última operación aritmética efectuada. La instrucción pro-
duce entonces un salto relativo a la etiqueta PRINT cuando el resultado de
la última operación arittica efectuada ha sido diferente de 0.
HEX ENSAMBLADOR
06 E9 LD B,224
3E 20 LD A,32
CD 5A BB PRINT: CALL 47962
3C INC A
05 DEC B
20 F9 JR NZ,,PRINT
C9 RET
Figura 6.3
La ejecución del programa producirá la impresn en la pantalla del juego
de caracteres del Amstrad, comenzando por el espacio en blanco (el 32) y
siguiendo con todos los caracteres del apéndice 3 de la Ga del usuario.
Pasaremos ahora a las instrucciones que sirven para sumar algo al registro
42 DIGO MÁQUIN A PAR A PRINCIPIANTE S CON AMSTRAD
A o restar algo de él. En su forma más sencilla, estas instrucciones son muy
simples. Para la suma se utiliza el código nemocnico ADD y para la resta
SUB. Como lo se puede utilizar el registro A para la aritmética de 8 bits,
parece innecesario especificar el registro; de hecho, esto es así para SUB, pe-
ro no para ADD, que también se puede utilizar para sumar 16 bits usando
el par HL, como explicaremos más adelante. En la práctica no puede existir
en ningún caso confusión respecto al sentido de ADD; por eso algunos en-
sambladores no requieren que se especifique el registro. Por el contrario, el
ensamblador de DEVPAC no acepta ADD si no va seguido del registro.
Para sumar o restar del acumulador un número de 8 bits las instrucciones
son ADD A, n y SUB n; los códigos completos son:
ENSA MBl ADOR DECIMA L HEX B I N A R IO
ADD A,n 198 n C6 n 11 000 110 n
SUB n 214 n D6 n 11 010 110 n
Para probar estas instrucciones se pueden cambiar las líneas 30 y 90 del
programa anterior por
30 FOR N=43800 TO 43812:READ D:POKE N,D:A=A+D:NEXT
90 DATA 6,224,62,32,205,90,187,198,1,5,32,248,201
sustituyendo 1353 por 1491 en la línea 40. Así se cambia la instrucción INC
A por la equivalente ADD A,l. Como ahora hay un byte más, ha sido nece-
sario aumentar en 1 la magnitud del salto relativo. Cuando se ejecute el pro-
grama el resultado será el mismo que antes; sin embargo, el programa ocupa
un byte más.
Para probar la instrucción SUB los cambios son
50 INPUT "PULSE ENTER PARA EMPEZAR";A:A=255:B=224
60 PRINT CHR$(A);:A=A-1:B=B-1:IF B<>0 THEN 60
90 DATA 6,224,62,255,205,90,187,214,1,5,32,248,201
ades de sustituir 1491 por 1529 en la línea 40. Los códigos hexadecimal
y nemotécnico de la rutina que resulta son los que aparecen en la figura 6.4.
Aunque se trata de algo que estudiaremos sobre todo en el próximo capí-
tulo, vamos a referirnos brevemente a la acción sobre los indicadores que tie-
-en las últimas instrucciones que hemos visto. Cada indicador es un bit del
registro de estado del microprocesador; el registro de estado se denota por
F (de flag). Un indicador puede contener un 0, en cuyo caso se dice que 'está
a 0' o puede contener un 1, y se dice que 'está a 1'. El indicador de cero (zero
ARITMÉTICA ELEMENTAL 43
LD B,224
LD A,255
BB PRINT: CALL 47962
SUB 1
DEC B
JR NZ,PRINT
RET
Figura 6.4
flag) detecta si el resultado de la última operación realizada ha sido 0; este
indicador suele ser representado por Z. Si el resultado de la operación ha si-
do 0, este indicador se pone 'a 1', o sea, activado; si el resultado de la opera-
ción ha sido diferente de 0, el indicador se pone 'a 0'. Se suele denotar estas
dos alternativas por Z y NZ.
Otro indicador es el indicador de arrastre (carry flag), que se suele repre-
sentar por C. En las operaciones aritticas de 8 bits sirve para detectar si
la operación ha necesitado un noveno bits; en ese caso el indicador se pone
'a 1'. Si no es así, el indicador se pone 'a 0'. Se suele denotar estas dos alter-
nativas por C y NC. Una suma de 8 bits activa el indicador de arrastre cuan-
do el resultado es mayor que 255. Una rest a lo hace cuando el resultado es
menor que 0.
Las instrucciones INC y DEC modifican el indicador de cero en el sentido
adecuado al resultado de la instrucción. Las instrucciones ADD y SUB mo-
difican tanto el indicador de cero como el de arrastre.
De la misma manera que se puede sumar o restar al acumulador un me-
ro de 8 bits, también se puede sumar y restar el contenido de cualquier regis-
tro de uso general o del propio acumulador. Se tienen así las instrucciones
ADD A,r y SUB r, cuyos códigos completos son:
ENSAMBLADOR DECIMAL HEX BINARIO
ADD A,r 128 - 135 8 0 - 87 10 000 r
SUB r 144 - 151 90 - 97 10 010 r
La r representa el código de 3 bits correspondiente al registro ; se trata de los
digos que ya vimos, es decir, de
06 E9
3E FF
CD 5A
D6 01
05
20 F8
C9
4 4 CÓDIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
B=000 C=001
D=010 E=011
H=100 L=101
A=111
También se puede utilizar en esta ocasión el código 110 para representar
el contenido de la dirección de memoria a la que apunta el par HL. Esto pro-
porciona las operaciones ADD A,(HL) y SUB (HL).
El funcionamiento de SUB r y ADD A,r es similar al de ADD A,n y SUB
n, incluso en la forma en que afectan las instrucciones a los indicadores de
cero y de arrastre.
Vamos a propornerle un ejercicio sencillo que usted podrá realizar con los
conocimientos adquiridos hasta ahora. Le proponemo s que escriba una ruti-
na que sume el contenido de la direccn de memoria 43894 con el de la di-
rección 43896 y coloque el resultado en la dirección 43898; convendrá ade-
más que la rutina esté disada para ser cargada a partir de la posicn
43850. Cuando haya terminado la rutina, deberá cargarla en la memoria.
Utilice un ensamblador, si dispone de él. Si no, codifique la rutina utilizando
la información que hemos dado hasta ahora y cárguela desde un programa
BASIC similar al que hemos venido utilizando.
Si no ha conseguido escribir la rutina le proporcionaremos algunas solu-
ciones posibles en este capítulo. Si ha podido realizarla, deberá comprobar
que funciona correctamente. Vamos a ver en qué forma puede hacerse esta
comprobación, que exigirá lógicamente imprimir los resultados en la panta-
lla. En primer lugar termine su rutina con:
ENSAMBLADO R DECIMAL HEX
CALL 43800 205 24 171 CD 18 AB
RET 201 C9
Con ello llama a una subrutina que aún no existe; es la que debe introducir
a continuación y que le proporcionamos en la figura 6.5. Esta rutina sirve
para imprimir el resultado.
Para introducir esta rutina puede emplear un programa BASIC como el
que ya hemos utilizado; debe entonces tener en cuenta que la rutina consta
de 35 bytes y que la suma de comprobación es 3966. Tambn debe recordar
que la ejecución debe comenzar en 43850.
En cualquier caso, por si usted carece de ensamblador, le proporcionare-
mos en el apéndice B de este libro un programa, que hemos llamado CAR-
GADOR HEX, que le servirá para introducir todas las rutinas que le dare-
mos en este libro. Dedique el tiempo necesario a cargarlo y grabarlo en cinta.
Aprenderá en seguida a utilizarlo, ya que la mecánica es siempre la misma:
ARITMÉTICA ELEMENTAL 4 5
ENSAMBLADOR
ORG
ENT
LD
LD
LD
LD
CALL
LD
CALL
LD
JR
LD
INC
ADD
JR
SBC
DEC
ADD
CALL
RET
43800
43800
A , (4 3 8 9 8)
L,A
H,0
DE,-10 0
REDN
E,- 10
REDN
A,L
PRIN
A , 0
A
HL,DE
C,FNUM
HL,DE
A
A,#3 0
47962
DECIMAL
58 122 171
111
38 0
17 156 255
205 4 4 171
30 246
20 5 4 4 171
125
24 9
62 0
60
25
56 25 2
237 82
61
19 8 48
205 90 187
20 1
Figur a 6.5
el cargador le solicitará la dirección en que comienza la parte protegida de
la memoria, la dirección en que comienza la rutina, y luego, sucesivamente,
los bytes de la rutina en codificación hexadecimal. Cuando se teclea END
en lugar de un byte, termina la introducción de la rutina. Cada 10 bytes le
pedirá la suma de los mismos para su comprobación. Cuando en el libro le
proporcionemos una rutina, le daremos también las sumas de comproba-
ción. En la rutina de la figura 6.5 estas sumas eran 046D, 042D, 0409 y
02DB.
Después de cargar la rutina, el problema consistirá en introducir en la me-
moria los datos que se deben sumar. Para ello recurriremos a BASIC. Copie
el programa
400 INPUT "PRIMER NUMERO";A:INPU T "SEGUNDO NUMERO";B
410 PRINT A;"+";B;"=";
420 POKE 43894,A:POKE 43896,B
430 CALL 43800
440 GOTO 400
HEX
HIMEM EN AB17
DIR INIC AB18
3A 7A AB CHECK
6F
26 00
11 9C FF
CD 046D
2C AB
1E F6
CD 2C AB
7D
18 09 042D
3E 00
3C
19
38 FC
ED 52
3D
C6 0409
30
CD 5A BB
C9 END 02DB
Figura 6.6
REDN:
FNUM:
PRIN:
46 DIGO QUINA PARA PRINCIPIANTES CON AMSTRA D
y ejecútelo con GOTO 400, El programa le pedirá los datos, los cargará en
la memoria y llamará a su rutina; el resultado se imprimirá en la pantalla.
Cuando desee terminar el programa, pulse la tecla [ESC] dos veces.
Hab observado que, cuando se suman dos meros cuya suma sobrepa-
sa 255, la respuesta es incorrecta. Recordará que ya hemos explicado por
qué, y también que entonces se activa el indicador de arrastre. La forma en
que esto tiene solución se comprende mejor cuando se reflexiona sobre la
manera en que habitualmente sumamos números. Si se desea hacer la suma
9 + 6 + 8, lo que se hace es
9+6=5 con 1 de arrastre
5+8=3 con 1 de arrastre,
luego la respuesta es 3 con 2 de arrastre, o sea, 23, Lo mismo ocurre con
una suma binaria: se suma por columnas y cuando se arrastre un 1 se lo aña-
de a la siguiente columna.
1010 0101 (165)
+ 1011 0000 (176)
1
+0
= 1
01
+0
=01
101
+0
= 101
0101
+0
=0101
0
+1
= 1
11
+1
= 101
101
+0
+0
= 101
1101
+1
= 0101
0101
010 1
0101
0101
0101
0101
0101
0101 (85)
= con 1 de arrastre (256), o sea, 341
ARITMÉTICA ELEMENTAL 47
Al terminar la suma hay un arrastre de una unidad: su valor relativo es de
256 veces el valor del bit menos significativo.
Así pues, lo que se requiere para sumar números más grandes es una serie
de bytes: el arrastre de cada byte se debe añadir entonces al byte siguiente.
Hay instrucciones que permiten hacer esto automáticamente. Se trata de
las instrucciones de 'suma con arrastre' y 'resta con arrastre', cuyos códigos
nemotécnicos son ADC y SBC (C de carry). Cuando se realizan estas opera-
ciones se incluye automáticamente en la suma o resta el valor del indicador
de arrastre.
Pensemos, por ejemplo, en el programa de la figura 6.7
LD HL,43896
LD A,(43894)
ADD A,(HL)
LD (43898),A
LD A,(43895)
INC HL
ADD A,(HL)
LD (43899),A Figura 6.7
imaginando que 43894 tiene 1010 0101 (165),43896 tiene 1011 0000 (176) y
que las restantes direcciones tienen 0. La primera parte del programa sumará
165 con 176 y almacenará en 43898 el resultado, que es 85. La segunda parte
sumará los contenidos de 43895 y 43897 (o sea, 0 + 0), almacenando el resul-
tado en 43899. Veamos qué ocurre ahora si cambiamos la segunda instruc-
ción ADD por ADC . La primera parte será la igual, pero en la segunda la
suma será 0+0+arrastre y el resultado, que es 1, se almacenará en 43899.
De esta manera se obtiene la suma correcta en las direcciones 43898 y 43899.
Si se añade la instruccn LD HL,(43898) al final del programa, el registro
L cargará el byte menos signíficativo y el registro H el más significativo; de
esta manera el par HL contendrá el valor 0000 0001 0101 0101b o 01 55 Hex
que corresponde a la suma correcta.
Las instrucciones de suma y resta con arrastre tienen los digos
ENSAMBLADOR DECIMA L HEX BINARIO
ADC A,n 206 n CE n 11 001 110 n
SBC A,n 222 n DE n 11 011 110 n
ADC A,r 136 - 143 88 -8F 10 001 r
SBC A,r 152 - 159 98 - 9F 10 011 r
48 CÓDIGO MÁQUINA PARA PRINCIPIANTE S CON AMSTRAD
ASSEMBLER
HEX
ORG
ENT
LD
CALL
ADD
LD
LD
INC
ADC
LD
CALL
RET
ORG
LD
NOP
NOP
NOP
NOP
NOP
NOP
LD
CALL
LD
CALL
LD
CALL
LD
JR
REDN: LD
FNUM: INC
ADD
JR
SBC
DEC
PRIN: ADD
CALL
RET
43850
43850
HL,43896
47896
A,(HL)
(43898),A
A,(43895)
HL
A,(HL)
(43899),A
43800
43800
HL,(43898)
DE,-1000
REDN
DE,-100
REDN
E,-10
REDN
A,L
PRIN
A,0
A
HL,DE
C,FNUM
HL,DE
A
A,#30
47962
HIMEM EN AB17
DIR INIC AB4A
SUMA
21 78 AB
CD 18 BB
86
32 7A AB 04C1
3A 77 AB
23
8E
32 7B AB
CD 18 044A
AB
C9 END 0174
MAS? S/N S
DIR INIC AB18
SUMA
2A 7A AB
00
00
00
00
00
00
11 0160
18 FC
CD 36 AB
11 9C FF
CD 36 0571
AB
11 F6 FF
CD 36 AB
7D
18 09 04FD
3E
00
3C
19
38 FC
ED 52
3D
C6 0409
30 CD 5A BB
C9 END 02DB
MAS? S/N N
Figura 6.8
ARITTICA ELEMENTAL 49
Como de costumbre, r representa cualquier registro de uso general, A o
(HL); los códigos son también los de siempre. Observe que SBC requiere que
se precise el registro A, lo que no ocura con SUB ; esto se debe a que el di-
go SBC admite otras interpretaciones que veremos más adelante.
Para comprobar el funcionamiento de las instrucciones ADC y SBC intro-
duzca el programa de la figura 6.8.
Este programa es demasiado largo para utilizar el método del DATA,
así que hemos omitido el código decimal. Utilice el CARGADOR HE X a
falta de un ensamblador. Para ejecutar el programa utilice el comand o R
del ensamblador o bien la instrucción CALL 43850 desde el sistema opera-
tivo.
Lo que hace el programa es sumar el digo ASCII de la primera tecla que
se pulse con el contenido de la dirección 43896, almacenando el resultado en
la posición 43898. A continuacn se suma 'con arrastre' el contenido de
43895 y 43897 y el resultado se almacena en 43899. La lectura de la tecla pul-
sada se realiza mediante la llamada CALL 47896 a una rutina del sistema
operativo que espera que se pulse una tecla y almacena su digo ASCII en
el acumulador.
Si no ha colocado nada en las direcciones cuyo contenido se suma, lo úni-
co que obtendrá como respuesta será el código ASCII de la tecla que pulse,
como podrá comprobar consultando la tabla del apéndice 3 de la guía del
usuario.
Para realizar otra s pruebas deberá cargar algo en dichas posiciones, sitúe-
se en BASIC, utilizando el comando B si está utilizando el ensamblador. En-
tonces, para sumar 220 y 89 por ejemplo, pulse
P O K E 43896,220[ENTER] C A L L 43850 [ENTER]
y luego SHIFT y Y (el código de Y es 89); obtendrá 309 como respuesta.
Para sumar 23260 y 345 pulse
P O K E 43896,220[ENTER] P O K E 43897,90[ENTER]
P O K E 43895,1[ENTER] C A L L 43850[ENTER]
y luego SHIFT y Y. La respuesta debería ser 23605, pero no lo es; ¿por qué?
En realidad todo ha sido hecho correctamente . 23260 es 5ADCh y ha sido
correctamente introducido: el byte bajo DCh, que es 220, en 43896; el byte
alto 5Ah, que es 90, en 43897. El 345 es 0159h; se ha introducido 59h, que
es 89, como código de la Y; el 1 se ha introducido en 43895. El programa
ha sumado el código de la Y con el contenido de 43896, colocando el resulta-
do en 43898. Como 59h+DCh=135h, en 43898 debe haber 35h o 53. Eso
es lo que ocurre, como se puede comprobar con
?PEEK(43898) [ENTER]
5 0 CÓDIGO MÁQUINA PAR A PRINCIPIANTE S CON AMSTRA D
Además, el indicador de arrastre estará a I. A continuación el programa ha
sumado los contenidos de 43895 y 43897 y el bit de arrastre. Como
5Ah+01h + arrastre=5Ch o 92, el programa habrá colocado en 43899 el nú-
mero 92. Se puede comprobar que esto ha ocurrido asi. La respuesta de la
suma es entonces 92*256+53 = 23552 + 53 = 23605 que es lo correcto, pero no
lo que ha aparecido en la pantalla.
La respuesta hay que buscarla en la segunda parte del programa, que es
la parte que se encarga de visualizar el resultado. De hecho, tantos bytes con
la instrucción NOP (que no hace nada) le habrán sugerido posiblemente que
la verdadera intencn es rellenar este espacio más adelante.
Hay dos instrucciones (ADD HL,DE y SBC HL,DE) que no hemos descri-
to todavía. Daremos una idea de ellas, aunque vamos a explicarlas con más
detalle en los siguientes catulos.
La instruccn SUB se utiliza exclusivamente con números de 8 bits, pero
las instrucciones ADD, ADC y SBC se pueden utilizar con números de 16
bits. Para ello, el acumulador A se sustituye por el par HL, que desempeña
así el papel de acumulador; contiene uno de los números que se operan y al-
macena desps el resultado de la operación. El segundo de los meros que
se operan debe estar en alguno de los pares BC, DE o HL, o también en el
registro de 16 bits SP (el puntero de pila). Sin embargo este segundo número
no puede ser dado explícitamente, ni indicado como contenido en una direc-
ción de memoria, ni siquiera dando esta dirección mediante un par de regis-
tros; en otras palabras, no existen instrucciones del tipo ADD HL,23456,
ADC HL,(23456) o SBC HL,(DE). La lista de las operaciones posibles, con
sus códigos, es la que se muestra en la figura 6.9.
Funcionan como sus equivalentes ADD A,B ADC A,B y SBC A,B , salvo
por el hecho de que trabajan con números de 16 bits. Por ejemplo, para su-
mar los números 55536 y 2000 se puede utilizar la siguiente sucesión de
instrucciones:
LD DE,55536
LD HL,2000
ADD HL,DE
Tras la ejecución de estas instrucciones, el par HL contendrá la suma 57536
(E0C0h en H C0h en L) y el par DE contendrá el sumando 55536 (D8F0h
D8h en D F0h en E); el indicador de arrastre quedará a 0. Si la suma realiza-
da hubiera sido 55536+23605, la respuesta correcta 79141 (13525h) no ha-
bría podido ser almacenada en 16 bits; por lo tanto la respuesta habría sido
13605 (3525h) y el indicador de arrastre habría quedado a 1. El valor del bit
de arrastre sería en ese caso de 65536 (o sea, 2^16) veces el del bit menos
significativo de par de registros, mientras que para las operaciones de 8 bits
este valor es de 256 (o sea, 2^8) veces el del bit menos significativo.
A R I T M É T I C A ELEM EN TAL 51
ENSAMBLADOR
ADD HL,BC
ADD HL,DE
ADD HL,H L
ADD HL,SP
DECIMAL
9
2 5
4 1
5 7
HEX
0 9
1 9
29
39
BINARIO
00 001 001
0 0 011 001
00 101 001
0 0 111 001
ADC
ADC
ADC
ADC
HL,
HL,
HL,
HL,
BC
DE
HL
SP
237
237
237
237
74
9 0
106
122
ED 4A
ED 5A
ED 6A
ED 7A
SBC HL,BC
SB C H L,DE
SB C H L,HL
SBC HL,SP
237
237
237
237
6 6
8 2
9 8
114
ED 4 2
ED 52
ED 62
ED 7 2
Figura 6.9
11 101 101 01 001 010
11 101 101 01 011 010
11 101 101 01 101 010
11 101 101 01 111 010
11 101 101 01 000 010
11 101 101 01 010 010
11 101 101 01 100 010
11 101 101 01 110 010
Cuando se desea realizar la suma o resta incluyendo el bit de arrastre, se
deben utilizar las instrucciones ADC o SBC. Sin embargo, no existe la instruc-
ción SUR para 16 bits. En consecuencia, si se desea efectuar una resta sin
restar al mismo tiempo el bit de arrastre, hay que poner a 0 el indicador de
arrastre si se encuentra activado.
Hay instrucciones que permiten activar (poner a 1} el indicador de arrastre,
y también para poner este indicador a su valor complementario (el contrario
del que tenga); son las instrucciones SCF y CCF. Por el contrario, no existe
una instruccn para poner a 0 el indicador de arrastre. Lo que se puede ha-
cer es ponerlo a 1 y complementarlo después, o sea, efectuar SCF y CCF. Lo
que se hace habitualmente es utilizar para esta finalidad la instruccn lógica
AND A, que es más breve; explicaremos esta instruccn en el capítulo 8.
Volvamos ahora a nuestro programa de suma; como ya vimos, realizaba
correctamente la operación pero imprimía un resultado incorrecto. La pri-
mera parle del programa almacenaba el byte alto de la respuesta en la direc-
ción 43899, y el byte bajo en 43898.
5 2 CÓDIG O MÁQUINA PARA PRINCIPIANTE S CON AMSTRA D
La segunda part e comienza por LD HL,(43898), que carga en L el conteni-
do de la posicn indicada, y en H el de la posicn siguiente. La instruccn
cargará 35h en L y 5Ch en H, haciendo HL=5C35h o 23605, que es lo co-
rrecto. El problema no reside en esta instrucción. Tampoco está en las 6 ins-
trucciones NOP, que no tienen ningún efecto.
A continuación se carga DE con -1000, que es FC18h (de momento no
se verá a qué conduce esto); luego se produce una llamada a la rutina que
comienza en la etiqueta REDN. Vamos a examinar en detalle las operaciones
que se producen.
1) LD A,0 hace A=0.
2) INC A hace A= A+ 1
3) ADD HL,DE realiza la suma de HL = 5C35h y DE = FC18h. 5C35h es
23605. FC18h es 64536 en decimal o -1000 si se interpreta en comple-
mento a 2. 23605+64536 = 88141. Como el mayor número que cabe en
16 bits es 65535, el indicador de arrastre se pone a 1. Además,
88141-65536=22605, luego el efecto final será restar 1000 del conteni-
do de HL.
4) JR C,FNUM produce el salto a la etiqueta FNUM si el indicador de
arrastre está a 1. En tal caso el efecto que se produce es incrementar
el contenido de A en 1 y volver a restar 1000 del contenido de HL. El
registro A contará el mero de veces que se ha repetido esta
operación.
5) SBC HL,DE Se llega a esta instrucción cuando ya no existe arrastre en
ADD HL,DE. En ese caso se devuelve a HL el número 1000 que se ha-
a restado (restar un número negativo equivale a sumar).
6) DEC A anula el último incremento de A. El resultado ahora es que en
A está el número de veces que HL contenía a 1000, y en HL el resto
de la división por 1000. En nuestro caso estos valores son HL=605 y
A =
23.
7) ADD A, #30 suma a A el númer o hexadecimal 30 (para el ensamblador
de Highsoft el símbolo # significa hexadecimal). En nuestro caso 23
(17h) más 30h (48) da 71 (47h).
8) CALL 47962 llama a la rutina de la ROM que se encarga de escribir
el carácter cuyo código figura en A.
9) RET señala el fin de la rutina.
Lo que se pretende es escribir la primera cifra decimal del resultado, o sea,
el número de miles que hay en HL. Como las cifras de 0 y 9 tienen por di-
gos ASCII los que van de 30h a 39h, todo hubiese marchado bien si este -
mero de miles hubiera estado entre 0 y 9. Pero como era 23, el resultado ha
sido escribir la letra G, cuyo código es 71, en lugar de las cifras 2 y 3. Vamos
a ver cómo se puede arreglar el programa.
ARITTICA ELEMENTAL 53
Si está usando el ensamblador, escriba CALL 30004 [ENTER] y a conti-
nuación L[ENTER] para listar el programa. Introduzca las dos nuevas ins-
trucciones que le damos más abajo en el lugar de las dos primeras NOP y
borre las cuatro restantes NOP. A continuación escriba A [ENTER]
[ENTER] [ENTER] para ensamblar de nuevo el programa.
Si no dispone de ensamblador, reemplace los seis bytes con el CARGA-
DOR HEX, suministrándole AB17 como valor para HIMEM y AB1B como
dirección inicial. Cargue así las instrucciones
ENSAMBLADOR HEX
LD DE,-10000 11 F0 D8
CALL REDN CD 36 AB END 0387
MAS?' S//N N
Ejecute ahora el programa y verá como trabaja perfectamente con números
cuya suma quepa en 16 bits (hasta 65535).
Puede cambiar la primera parte del programa para experimentar con las
restantes instrucciones de suma y resta de 8 bits. Mientras siga utilizando
(HL) para señalar las direcciones que almacenan los números, y no utilice
instrucciones que usen expcitamente n o nn, le bastará con cambiar el byte
que contiene la instruccn. Recuerde que en digo de máquina no ocurre
como en BASIC, en el que se pueden insertar instrucciones.
Si ha entendido bien todo esto, no le resultará difícil escribir programas
para sumar o restar dos meros cualesquiera utilizando operaciones de 8
bits. Otra cosa será conseguir visualizar el resultado. Si desea una impresión
en pantalla le bastará con modificar el programa que hemos utilizado.
En este tipo de tareas es donde se observan las ventajas del trabajo con 16
bits. Las sumas de meros de 16 bits proporcionan resultados que ocupan
17 bits; mientras que el resultado de un producto necesita 32 bits. La ventaja
está en que trabajar con 16 bits para obtener resultados de 32 bits no requie-
re más instrucciones que para obtener 24 bits con aritmética de 16 y 8 bits.
Observe que con 32 bits se pueden representar números hasta 4294967295
(2^32).
Puede parecer molesta la imposibilidad de utilizar operandos numéricos
en las instrucciones aritticas de 16 bits, pero esto es fácil de solucionar.
De hecho, la primera parte del programa de la figura 6.8, que utilizaba arit-
mética de 8 bits, se puede escribir también como muestra la figura 6.10.
Esta alternativa utiliza 21 bytes, uno menos que la original. Además, con-
serva el resultado en HL, lo que ahorra posteriormente la instrucción
LD HL,(43898), de 3 bits , a la hora de ejecutar la rutina de impresn.
54 DIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
ORE
ENT
LD
LD
INC
LD
INC
LD
LD
CALL
LD
ADD
LD
CALL
RET
4 3 8 50
4 3 8 5 0
HL , (4 3 8 9 5 )
A , ( H L )
HL
E , ( H L )
HL
D , ( H L)
H, A
47896
L , A
H L , DE
( 4 3 8 9 B)
43800
, HL
Figur a 6.10
HIMEM EN AB17
DIR INIC AB18
21 77 AB SUMA
7E
23
5E
23
56
67
CD 03E F
18 BB
6F
19
22 7A AB
CD 18 AB 0432
C9 END 00C9
También se puede mejorar utilizando instrucciones de carga de 16 bits, co-
mo hacemos en el programa de la figura 6.11. A se emplean solamente 19
bytes.
El programa que hemos escrito puede ser un buen ejercicio, pero no es una
rutina útil. Para que lo fuese, debea ser una rutina utilizable por un progra-
ma en circunstancias cualesquiera, lo que no es el caso por estar ligada a po-
siciones concretas de memoria en las que deben figurar los números que se
suman. Lo que podríamos hacer es reescribir la rutina de manera que se limi-
te a sumar los números que haya en los pares HL y DE, a escribir el resulta-
do en pantalla y a conservarlo en el par HL. De esta manera, si por ejemplo
estamos realizando un juego de marcianos en el que se pueden obtener pun-
tuaciones de 10, 20, 50, 100 y 400, lo que haríamos cada vez que se elimina
un invasor es cargar su valor en DE y llamar a la rutina; el total de puntua-
ARITMÉTICA ELEMENTAL 55
O R G 4 3 8 5 0
E N T 4 3 8 5 0
L D H L , ( 4 3 8 9 6 )
L D A , ( 4 3 8 9 5 )
L D D , A
C A L L 4 7 8 9 6
L D E , A
A D D H L , D E
L D ( 4 3 8 9 8 ) , H L
C A L L 4 3 8 0 0
R E T
HIMEM EN AB17
DIR INIC AB18
21 78 AB SUMA
3A 77 AB
57
CD 18 BB 0 49 6
19
2 2 7A AB
CD 18 AB
END
0418
Figura 6.11
ORG
ÉNT
LD
LD
LD
CALL
LD
AND
SBC
LD
CALL
RET
4 3 8 30
4 3 8 5 0
H L , ( 4 3 8 9 6 )
A , ( 4 3 9 9 5 )
D,
A
47896
E, A
A
H L , D E
( 4 3 8 9 8 ) , H L
4 3 8 00
HIME M EN AB17
DIR INIC AB18
21 78 AB SUMA
3A 7 7 AB
57
CD 18 BB 049 6
5F
A7
ED 52
22 7A AB
CD 18 AB 051C
C9 EMD 0OC9
Figura 6.12
C9
5F
19
2 2 7A AB
CD 18 AB
56 CÓDIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
ción acumulada se iría así escribiendo en la pantalla y quedaría acumulado
en HL para una nueva suma.
Las rutinas de las figuras 6.10 y 6.11 pueden servir tambn para restar
números, pero hay que tener en ese caso la precaución de poner a 0 el indica-
dor de arrastre para no falsear inadvertidamente los resultados. Para ello se
puede utilizar la instrucción AND A, como ya dijimos. Es lo que hacemos
en el ejemplo de la figura 6.12, que es como el de 6.11 pero modificad o para
la resta; resta el contenido de DE de HL y deja el resultado en HL.
Como ejercicio final de este capítulo, el lector puede escribir un programa
que sume meros de 16 bits y almacene el resultado en la memoria como
un número de 32 bits. Si es usted capaz de escribir este programa, nosotros
le ayudaremos a comprobar su funcionamiento si respeta algunas premisas:
almacene el resultado en las posiciones de memoria que van de la 43896 a
la 43899, de menos significativo a más significativo; haga que el programa
comience en 43840 (AB40h) y que termine con CALL 43700 y RET.
La figura 6.13 contiene la rutina que llamará su programa para compro-
bar que funciona correctamente; está tal y como lo muestra el listado del en-
samblador, para evitar errores. Si utiliza el ensamblador debe cargar la co-
lumna de códigos nemotécnicos, cuidando de añadir el símbolo ':' dets de
las etiquetas.
Hisoft GENA3 A ss emb le r . Pag e 1.
P a s s
AAB4
AAB4
AAB4
AAB7
AABA
AABD
AAC0
AAC3
AAC6
AAC9
AACC
AACF
AAD2
AAD5
AAD8
AAD B
AADE
1 e r r o r s :
2A7BAB
223EAB
2A7AAB
2 2 4 0 A B
110036
0 1 6 5 C 4
CD0CAB
11001F
010AFA
CD0CAB
118069
0167FF
CD0CAB
11C0BD
0 1 F 0 F F
00
10
;
20
30
40
50
60
70
B0
90
1 00
110
120
130
140
150
160
170
1B0
190
SUBRU
DECIM
ORG
ENT
LD
LD
LD
LD
LD
LD
CAL L
LD
LD
CALL
LD
LD
CAL L
LD
LD
TINA PARA IMPRIMIR EN
AL UN NUMERO DE 32 BITS
4 3 7 0 0
4 3 7 0 0
H L , ( 4 3 8 9 6 )
( 4 3 8 3 8 ) , H L
H L , ( 4 3 8 9 B )
( 4 3 8 4 0 ) , HL
D E , # 3 6 0 0 ; B Y T E S B A J O S
B C , # C 4 65 ;
BYTES ALTOS D E -1 00 0 00 0 000
REDN
D E , # 1 F 0 0 ; B Y T E S B A J O S Y
BC , #F A 0A ;
BYTES ALTOS DE 0 00 000 000
REDN
DE, # 6 9 80 ; B Y E S B A J O S Y
B C , # F F 67 ;
BYTES ALTOS DE -10 000 000
REDN
D E , #B D C 0 ; BYTES BAJOS Y
B C , # F F F0 ;
AAE 1
AAE4
AAE7
CD0CAB
1 1 6 0 7 9
I1F EF F
2 00
2 1 0
2 20
BYTES ALTO S DE - 1 000 000
CALL RED N
L D D E , # 7 9 6 0 ;
BYTES BAJOS Y
L D B C , # F F F E ;
BYTES ALTOS DE - 100 000
BYTES BAJO
AAEA
AAED
AAF0
AAF3
AAF6
AAF 9
AAFC
AAFF
AB02
AB04
AB07
AB0 A
AB0C
AB0E
A80F
AB12
AB13
AB16
AB1 9
AB1B
AB1E
AB20
AB2 3
AB25
AB28
AB2B
AB2D
AB3 0
AB31
AB33
AB3 6
CD0CAB
11F0DB
01FFFF
CD0CA B
1118FC
CD0CAB
119CFF
CD0CAB
1EF6
CD0CA8
3A3EA B
1B25
3E0 0
3C
2A3EAB
19
223EA B
2A40AB
ED4A
2240A B
3BEE
2A3EAB
ED52
223EA B
2A40AB
ED42
2240AB
3D
C63 0
CD5ABB
C9
230
240
250
260
270
2B0
290
300
310
320
330
340
350 RED N
360 FNUM
370
380
390
400
410
420
430
44 0
450
460
470
4B0
490
500
510 PRIN
520
530
CALL
LD
LD
CALL
LD
CALL
LD
CALL
LD
CALL
LD
JR
LD
INC
LD
ADD
LD
LD
ADC
LD
JR
LD
SBC
LD
LD
SBC
LD
DEC
ADD
CALL
RET
REDN
DE,-10000 ;
BC,#FFF F ;
BYTES ALTOS DE
REDN
DE,-1000
REDN
DE,-100
REDN
E,-10
REDN
A,(43838)
PRI N
A,0
A
HL,(43B38)
HL,DE
(43838),HL
HL,(43B40)
HL,BC
(43B40),HL
C,FNUM
HL, (43838)
HL,DE
(43838),H L
HL, (43840)
HL,BC
(43B40),HL
A
A,«30
47962
58 DIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
Resumen
Vamos a resumir las instrucciones explicadas en este capítulo. Utilizaremos
los símbolos:
r = cualquiera de los registros de 8 bits (A, B, C, D, E, H o L)
rr = cualquier par de registros que se utilicen como uno de 16 bits
n =un número de 8 bits, o sea, entre 0 y 255
nn =un número de 16 bits, o sea, entre 0 y 65535
( ) rodeando un mero o un par de registros =el contenido de la
direccn.
PC = contador de programa
SP = puntero de pila
INC r y DEC r suman 1 o restan 1 a r; el resultado afecta al indicador
de cero. Si el resultado es 0, el indicador se pon e a 1; si no, a 0.
INC rr y DEC rr hacen lo mismo, pero con un par de registros; estas ins-
trucciones no afectan a los indicadores.
El acumulador A es el único registro que sirve para almacenar el resultado
de las operaciones aritticas de 8 bits.
Las operaciones aritméticas de 8 bits son:
SUBr SUBn SUB (nn) SUB (HL) para restar una cantidad de A.
ADD A,r ADD A,n ADD A,(nn) ADD A,(HL) para sumar a A una
cantidad.
SBC A,r SBC A,n SBC A,(nn) SBC A,(HL) para restar con arras-
tre una cantidad de A.
ADC A,r ADC A,n ADC A,(nn) ADC A,(HL) para sumar con
arrastre una cantidad a A.
Se debe utilizar el par HL para almacenar el resultado de las operaciones
aritticas de 16 bits.
Las operaciones aritméticas de 16 bits son:
ADD HL.rr para sumar al par HL el contenido del par rr.
ADC HL,rr para sumar con arrastre al par HL el contenido del par rr.
SBC HL,rr para restar con arrastr e el contenido de rr del par HL.
Todas estas operaciones aritméticas afectan al indicador de arrastre según
sea el resultado de la operación. Lo mismo ocurre con el indicador de cero,
salvo para la instrucción ADD de 16 bits, que no le afecta.
Si no se desea que la instruccn SBC se efectúe con el bit de arrastre, se
puede poner a 0 el indicador de arrastre mediante la instruccn AND A.
7
Indicadores, condiciones y decisiones
condicionadas
Ya hemos visto algo del funcionamiento de los indicadores de cero y de
arrastre (Z y C) en relacn con las operaciones aritticas. Cada uno de es-
tos indicadores es un bit del registro de estado (flag), que se denota por F.
Puesto que este registro es de 8 bits, se puede sospechar que existirán otros
indicadores; así es. La estructura del registro de estado F es la siguiente:
:
| SIGNO
:
| M/A
i
:
; Z
|CERO
!
|Z/NZ
NO SE
USA
H
| SEMI-
ARRAS TRE.
NO SE
USA
P/ V
PARIDAD/
SOBREPASAM
PE/PO
IENTO
;N
| SUMA/
| RESTA
¡
:
:
c :
ARRASTRE |!
C / N C |
La letra que hay sobr e cada indicador es la abreviatura usada por el fabri-
cante del microprocesador, Zilog, para representarlo; es el simbolo con el
que se identifica cada indicador en las tablas del andice A. Después viene
el nombre del indicador; los nombres que se utilizan en inglés son:
SIGNO es SIGN
CERO es ZERO
SEMIARRASTRE es HALF CARRY
PARIDAD/SOBREPASAMIENTO es PARITY/OVERFLOW
SUMA/RESTA es ADD/SUBTRACT
ARRASTRE es CARRY
Para cuatro de los indicadores, figuran también los mbolos con que se re-
presentan los estados posibles del indicador. SóLo estos cuatro indicadores
son accesibles al usuario; los restantes los utiliza internamente el Z80.
En las situaciones más diversas, existen decisiones cuyo signo depende de
que se den o no determinadas condiciones. Son las denominadas decisiones
condicionadas. En código de máquina, el recurso de que dispone el progra-
ma para saber si se dan o no ciertas condiciones son los indicadores. Dado
que sólo hay 4 indicadores accesibles, se requiere algo de ingenio para com-
probar con ellos un amplio abanico de condiciones.
59
60 DIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
Supongamos por ejemplo que al programar un juego necesitamos compa-
rar el tanteo obtenido con el tanteo más alto hasta el momento, para la reali-
zar la sustitución si se ha batido el récord. Lo que podemos hacer es restar
de la nueva puntuación el antiguo récord y observar el indicador de arrastre.
Si no se activa (o sea, si se produce NC), sabremos que se ha obtenido un
nuevo récord. Pero hay un problema: si el récord anterior era 15575 y el nue-
vo 21024, sabremos así que se ha obtenido un nuevo récord, pero habremos
perdido ambas cifras para quedarnos con 5449, que es la diferencia. Hay
formas de solucionar este incoveniente.
Lo ideal sea realizar un falsa resta, es decir, una instrucción que active
los indicadores como si fuese una resta pero sin realizar la operación.
Existe una instrucción de este tipo y se llama comparación. Su código nemo-
técnico es CP y funciona como la instrucción SUB salvo por el hecho de que
no altera el valor de los registros, excepcn hecha del registro de estado. La
instrucción SUB podía realizarse solamente con el registro A: lo mismo ocu-
rre con CP.
El comportamiento de los indicadores tras la instrucción CP es también
el mismo que en caso de SUB.
Su código se construye como el de las operaciones de 8 bits; ahora bien,
los bits 5, 4 y 3 llevan 111 en el caso de CP, Así se tiene
SUB n
CP n
SUB r
CP r
SUB (HL)
CP (HL)
10 010 110
10 111 110
10 010 r
10 111 r
10 010 110
10 111 110
n
n
8
C
D
E
H
L
(HL)
A
000
001
010
011
100
101
110
111
Los indicadores se utilizan para la toma de decisiones, esto es, para ejecu-
tar alternativamente unas u otras instrucciones en función de una condición
impuesta acerca del estado de un indicador. Lo análogo en BASIC es la ins-
trucción 'IF condición THEN instrucción a ejecutar'. La analoa va aún
más allá; lo que suele ponerse tras THEN es una instrucción GOTO de salto
(aunque la palabra GOTO puede generalmente omitirse, como ocurre en el
Amstrad). Lo mismo ocurre en digo de máquina. El programa de la figura
r es,
como siempre,
INDICADORES, CONDICIONES Y DECISIONES CONDICIONADAS 61
6.3 realizaba un salto (JR) dependiendo de una condición sobre el indicador
de cero. El programa de la figura 6.5 hacía lo mismo, pero con el indicador
de arrastre.
Puede parecer que son pocas las comprobaciones que se pueden realizar,
pero no es a. Veremos que los indicadores sirven para 'indicar' muchas
cosas.
Examinaremos primero el indicador de arrastre, sobre el que ya tenemos
cierta experiencia.
Salvo INC y DEC, todas las operaciones que provoquen el sobrepasa-
miento del registro o registros sobre los que actúan, hacen que se active el
indicador de arrastre. Por el contrario, este indicador se desactiva cuando
la operación no ha producido este sobrepasamiento. Por ejemplo, LD A, 0
y DEC A no modificarían el indicador de arrastre, mientras que LD A,0 y
SUB 1, en este orden, sí lo activaan. Las secuencias
LD B,156 LD BC,65000 LD BC,65000
LD A, 100 LD HL,5536 o LD HL,5536
ADD A,B ADC HL,BC ' SBC HL,BC
activan el indicador de arrastre, mientras que las secuencias
LD BC,5536 LD A,225
LD HL,65000 y ADD A,25
SBC HL,BC
desactivan dicho indicador. En el caso de la instrucción CP, ésta activará el
indicador de arrastre cuando el número n, o el contenido de r o de la posi-
ción HL sean superiores al contenido del acumulador A y lo desactiva en
caso contrario. El indicador de arrastre se emplea en código de máquina con
una finalidad similar a la de los operadores > y < de BASIC.
Todas las operaciones aritticas afectan al indicador de cero, salvo la
ADD de 16 bits. Este indicador se activa cuando el resultado de la operación
es 0 y se desactiva en caso contrario. La instruccn CP activa el indicador
de cero cuando las cantidades que se comparan son iguales y lo desactiva en
caso contrario. Por eso el indicador de cero se emplea en código de máquina
de la misma manera que el operador-de BASIC.
Además de las instrucciones INC y DEC de 8 bits, hay otras instrucciones
que afectan al indicador de cero sin modificar e l indicador de arrastre; ya
iremos viendo estas instrucciones. En lo sucesivo, al presentar una instruc-
ción nueva, diremos en qué forma afecta a los indicadores accesibles al
programador.
Mediante una programac n adecuada, es posible contestar a todas las
cuestiones relativas al programa que se respondan con sí o no, comprobando
6 2 CÓDIG O MÁQUINA PARA PRINCIPIANTE S CON A M S T R A D
los indicadores de cero y de arrastre. En ocasiones bastará con la comproba-
ción de un sólo indicador; otras requerirán varias comprobaciones comple-
mentarias .
Claro que esto no es fácil de hacer al principio, e incluso proporciona-
en un primer momento resultados diferentes de los previstos; pero es po-
sible lograrlo si se aprende a pensar un poco como lo hace e l microproce-
sador.
Observe el ejemplo siguiente. Su finalidad es averiguar si el valor almace-
nado en el acumulador A corresponde a aln código ASCII, si es el código
de una letra y si es el código de la letra 'A'; según sea el caso, el programa
saltará a las etiquetas:
NOTASC si no se trata de un código ASCII;
NOTLET si no es el código de ninguna letra;
ISA si es el código de la 'A';
ISLET sí es el digo de una letra diferente.
Las 'preguntas' se van realizando en el siguiente orden: 1) ¿contiene A un
digo ASCII?; 2) si lo contiene, ¿es el código de una letra?; 3) si es así, ¿se
trata del digo de la primera letra del alfabeto? La secuencia de instruccio-
nes es la siguiente:
CP 128 Los códigos ASCII válidos van de 0 a 127.
JR NC,NOTASC Si el registro A almacena un valor que no es un có-
digo ASCII (128 o superior), se pondrá a 0 (sim-
licamente NC) el indicador de arrastre; el programa
saltará entonces a la etiqueta NOTASC. Si A alma-
cena un digo ASCII, existirá arrastr e y el progra-
ma pasará a la instrucción siguiente.
CP 32 Los códigos ASCII para letras son todos superiores
a 31.
JR C,NOTLET Si el valor almacenado en A es igual o menor que
31, se habrá activado el indicador de arrastre (sim-
licamente C); el programa saltará a NOTLET.
CP 65 Se compara con el digo de la letra 'A'.
JR Z,ISA Si se produce la igualdad, se activa el indicador de
cero (simbólicamente Z) y el programa saltará a
ISA.
Cabría pensar que si el programa no ha realizado el salto en ningún mo-
mento, lo que hay en el acumulador es el digo de una letra diferente de
'A' y que por lo tanto el program a debe saltar a ISLET, pero esto no es así.
Hay códigos entre 32 y 127 que no corresponden a letras. De hecho, sólo son
letras los códigos 65 . . . 90 y 97.. . 122.
INDICADORES, CONDICIONES Y DECISIONES CONDICIONADAS 6 3
Cambiando CP 32 por CP 65 y eliminando la CP 65 de dónde es, se me-
jora un poco la situación. Pero quedan aún las lagunas 91...96 y 123...127
por evitar. Esto se consigue añadiendo ahora las siguientes instrucciones:
CP 123
JR NC,NOTLET Si el valor de A es igual o mayor que 123 (luego está
en 123.. . 127), se trata de un digo que no es de
una letra.
CP 91
JR C,ISLET Si el valor de A es menor que 91 (luego está en
66...90), se trata de una letra diferente de 'A'.
CP 97
JR C,NOTLET Si el valor de A es menor de 97 (luego está en
91...96), se trata de un código que no es de una
letra.
Normalmente, si se trata de distinguir una 'A ' pulsada en el teclado, con-
viene aceptar 'a' tanto como 'A'. Para que así sea, hay que adir una ins-
trucción al programa.
JR Z,ISA Si el valor de A es exactamente 97, el código corres-
ponde a la 'a' .
Si el programa ha superado todos los saltos, el contenido de A estará en
el intervalo 98... 122 y será una letra miscula diferente de 'a'. Por lo tanto,
la etiqueta ISLET se debe colocar justamente en este punto, evitando así un
nuevo salto.
Introduzca este programa y experimente con él. Cuando lo entienda per-
fectamente, cambie de letra. Naturalmente, el ensamblador le permitirá rea-
lizar cilmente las modificaciones precisas, mientras que con el CARGA-
DOR HEX deberá volver a cargar todo el programa.
El programa que presentamos en la figura 7.1 no es más que el que acaba-
mos de comentar, pero completado para permitir la entrada del valor me-
diante el teclado e imprimir ciertos mensajes elegidos según sea la entrada
efectuada. Observe la manera de escribir mensajes y de elegirlos; analizare-
mos esto más adelante.
Si utiliza el CARGADOR HEX ya sabrá que el valor para HIMEM debe
ser AAB3 y la dirección inicial AAB4; los códigos hexadecimales que se in-
troducen son los de ía segunda columna de la figura, que comienza por
CD18BB. Las sumas de comprobación que pedirá el programa son 05EA,
0380, 036C, 023A, 0567, 0395, 02DB, 0226, 02A5, 0248, 0264, 01C8.
Si utiliza el ensamblador no es necesario que divida los mensajes en trozos
pequos; nosotros lo hemos hecho así porque el ensamblador lo lista en
64 CÓDIG O MÁQUINA PARA PRINCIPIANTES CON AMSTRA D
AAB4
AAB4
AAB4
AAB7
AAB9
AABB
AAB C
AABE
AACO
AAC2
AAC4
AAC6
AAC8
AACA
AACC
AAC E
AADO
AAD2
AAD4
AAD5
AAD6
AAD7
AADA
AADC
AADD
AADE
AAEO
AAE2
AAE3
AAE6
AAE8
AAEA
AAE B
AAED
AAEE
AAF2
AAF6
AAF A
AAFE
AB00
AB02
AB06
A80A
ABOE
AB10
AB14
AB18
AB19
AB1B
AB1F
AB23
AB27
AB29
CD1BBB
0604
FEFC
C8
FE8O
3016
FE41
3811
2811
FE7 B
300B
FE5B
3806
FE61
3803
2803
05
05
05
21EDAA
3E0A
BE
23
20F C
10FA
7E
CD5AB8
FE0A
2BCA
23
18F5
OA
41204C45
54544552
20425554
204E4F54
2041
ODOA
4E4F5420
41204C45
54544552
ODOA
4E4F5420
41534349
49
ODOA
594F552 0
50524553
5345442 0
4121
ODOA
30
20
30 START
40
50
60
70
80
90
100
110
120
130
140
150
160
170
180
190 ISLET
200 NOTLET
210 NOTASC
220 ISA
230
24 0 LOOKMS
250
260
270
28 0 PRINT
290
300
310
320
330
340 MESST
350
360
370
380
390
400
410
420
430
440
450
460
470
480
490
500
510
520
530
ORG
ENT
CAL L
LD
CP
RET
CP
JR
CP
JR
JR
CP
JR
CP
JR
CP
JR
JR
DEC
DEC
DEC
LD
LD
CP
INC
JR
DJNZ
LD
CALL
CP
JR
INC
JR
DEFB
DEFM
DEFM
DEFM
DEFM
DEFM
DEF W
DEFM
DEFM
DEFM
DEF M
DEFM
DEFM
DEFM
DEFW
DEFM
DEFM
DEFM
DEFM
DEF W
4370 0
43700
47896
B,4
252
Z
128
NC,NOTASC
65
C,NOTLET
Z, ISA
123
NC,NOTLET
91
C, ISLET
97
C,NOTLET
Z,ISA
B
B
B
HL,MESST
A,#0A
(HL)
HL
NZ,LOOKMS
LOOKMS
A,(HL)
47962
#0A
Z,START
HL
PRINT
#0A
"A LE "
"TTER"
" BUT"
" NOT"
" A"
#0A0D
"NOT "
"A LE "
"TTER"
#0A0D
"NOT "
"ASCI "
"I "
#0A0D
"YOU "
"PRES"
"SED "
" A ! "
# O A O D
Figura 7.1
INDICADORES, CONDICIONES Y DECISIONES CONDICIONADAS 65
hexadecimal los cuatro primeros bytes de cada nea. La línea 350 podría ha-
ber sido perfectamente
DEFM "A LETTER BUT NOT A"
suprimiendo entonces las líneas 360 a 390.
Los mensajes que genera el programa son los siguientes:
"A LETTER BUT NOT A" (una letra diferente de A)
"NOT A LETTER" (no es una letra)
NOT ASCII " (no es un código ASCII)
"YOU PRESSED A!" (ha pulsado la A)
Corresponden a las posibles alternativas que analizaba el programa.
Algunos puntos especiales del programa merecen un comentario.
Cuando un programa en código de máquina realiza un bucle sin fin, su
ejecucn no se detiene salvo que se apague el ordenador. Para que no ocu-
rra esto, conviene preparar una salida del programa. En nuestro caso esta
salida se produce cuando, tras la ejecución de la rutina WAIT KEY de la
dirección 47896, el acumulador queda cargado con el valo r 252, que es el có-
digo que genera la tecla [ESC]. En ese caso se ejecuta una instrucción RET.
La sección siguiente del programa es la que ya ha sido comentada; termina
por enviar el programa a una de las cuatro etiquetas que hemos descrito. Pe-
ro conviene hacer notar que el registro B ha sido cargado con el número 4,
y que el resultado de saltar a una u otra etiqueta es hacer que B llegue a la
línea 220 con un valor entre 1 y 4 que dependerá de la etiqueta. Este es el
comienzo del mecanismo que permite elegir el mensaje apropiado.
El par HL se coloca entonces en la direccn de la etiqueta MESST, que
es el comienzo de los mensajes. El byte 0Ah marca la separación entre uno
y otro mensaje. El mecanismo selector consiste entonces en disminuir B en
una unidad cada vez que se encuentra el byte 0Ah, hasta que el valor de B
se haga 0, en cuyo caso comienza a escribirse el mensaje. Aunque no se ob-
serve en esta zona ninguna instrucción que disminuya B en una unidad, lo
que ocurre es que la instrucción está implícita en una nueva instruccn que
no habíamos mencionado todavía: la instrucción DJNZ.
La instrucción DJNZ actúa como las instrucciones DEC B y JR NZ jun-
tas, pero ocupa un byte menos que ellas y además no afecta a los indicado-
res. Sus códigos son
ENSAMBLADOR DECIMAL HEX BINARIO
DJNZ n 16 n 10 n 00 001 010 n
6 6 CÓDIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
El número n representa, como en los saltos relativos, la magnitud del salto
contada desde el comienzo de la instruccn siguiente.
Obsérvese que cada marca 0Ah de fin de mensaje está precedida del byte
0DH, que es el código que, al ser impreso, produce un salto de línea que dis-
pone el cursor en la posición adecuada para el próximo mensaje.
Finalmente, el control vuelve al comienzo del programa y el proceso se re-
pite para 3a siguiente tecla pulsada.
Antes de comenzar la explicación de otro nuevo indicador, vamos a dar
una relación completa de las instrucciones condicionales de salto relativo.
Para este tipo de salto sólo se pueden utilizar condiciones relativas a los indi-
cadores de cero y de arrastre. El detalle de estas instrucciones y de sus di-
gos es el siguiente:
ENSAMBLADOR
DJNZ
JR
JR
J R
JR
JR
n
n
N Z , n
Z , n
N C , n
C, n
D EC IM A L
16
24
32
40
48
56
n
n
n
n
n
n
HEX
10
18
2 0
28
30
3B
n
n
n
n
n
n
BINARIO
00
00
00
00
00
00
0 1 0
0 1 1
1 00
1 0 1
11 0
11 1
0 00
0 0 0
0 00
0 0 0
0 0 0
0 0 0
n
n
n
n
n
n
Figura 7.2
Como es fácil de imaginar, también los saltos absolutos, JP, pueden con-
vertirse en saltos condicionados al valor de los indicadores. Lo mismo ocurre
con las instrucciones CALL y RET, pero con éstas se pueden utilizar condi-
ciones referidas a los cuatro indicadores accesibles al programador.
Ya hemos explicado cómo funcionan los indicadores de cero y de arrastre;
veamos cómo lo hacen los dos restantes.
El indicador de signo (sign flag) se representa por S; sus dos alternativas
son la de signo negativo (minus sign) que pone a 1 el indicador y se represen-
ta por M, y la de signo positivo (plus sign) que pone a 0 el indicador y se
representa por P.
El indicador de paridad/sobrepasamiento (parity/overflow flag) se repre-
senta por P/V; sus dos alternativas son la de paridad par (parity even) que
pone a 1 el indicador y se representa por PE, y la de paridad impar (parity
odd) que pone a 0 el indicador y se representa por PO.
INDICADORES, CONDICIONES YDECISIONES CONDICIONADAS 67
Como usted recordará, los registros de uso general tenían asociado un có-
digo de 3 bits, que se utilizaba para formar los digos binarios de las ins-
trucciones. Lo mismo ocurre con las condiciones sobre los indicadores. Es-
tos códigos son:
NZ no cero (not zero) 000
Z cero (zero) 001
NC sin arrastre (no carry) 010
C arrastre (carry) 011
PO paridad impar (parity odd) 100
PE paridad par (parity even) 101
P signo positivo (plus sign) 110
M signo negativo (minus sign) 111
En el cuadro que sigue, las letras cc representan una de estas condiciones;
en el código binario, cc se debe sustituir por su código de 3 bits.
ENSAMBLADOR BINARIO
JP cc,nn 11 cc 010 n n
CALL cc,nn 1 1 cc 100 nn
RET cc 11 cc 000
Así, por ejemplo,
JP NC,47962 es 11 010 010 0101 1010 1011 1011
y CALL Z,47960 es 11 001 100 0101 1000 1011 1011
Lo que indica el indicador de signo es, obviamente, el signo del resultado
de una operación. Ahora bien, sólo tiene este significado cuando el resultado
deba interpretarse escrito en la notación de complemento a 2. Para lo que
se utiliza en cualquier caso este indicador es para comprobar el valor del bit
7 de un byte. Por ejemplo, si el registro A contiene el número 254 después
de una operación aritmética, e! indicador de signo reflejará signo negativo
puesto que el bit 7 de A es 1; sin embargo, puede ser erróneo interpretar esto
en el sentido de que el resultado es un número negativo. En lo que sigue, em-
plearemos a veces la expresión 'entero con signo' para referirnos a un entero
que hay que interpretar en notación de complemento a 2.
Todas las instrucciones aritticas de 8 bits, incluyendo CP (la compara-
ción), las INC y DEC de 8 bits y las instrucciones ADC y SBC de 16 bits
afectan al indicador de signo. No le afecta ninguna de las restantes instruc-
ciones que hemos visto hasta ahora. Para las nuevas instrucciones que vaya-
68 DIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
mos introduciendo se indicará en qué medida afectan a los indicadores, en
particular al de signo. El apéndice A describe también la influencia sobre los
indicadores de todas las instrucciones.
El indicador de paridad/sobrepasamiento tiene, como indica su nombre,
un doble significado. De hecho, lo que tiene es uno de los dos significados
dependiendo de la instrucción (pero no ambos al mismo tiempo).
Todas las instrucciones que afectan al indicador de cero afectan al indica-
dor de paridad/sobrepasamiento, y todas las que hemos visto por ahora lo
hacen en el sentido de indicador de sobrepasamiento.
El indicador de sobrepasamiento se activa cuando en un cálculo, interpre-
tado como lculo de un número con signo, el resultado sobrepasa el tamaño
en que debe ser almacenado; se desactiva cuando esto no ocurre. El concepto
es un poco complicado y vamos a explicarlo con algún ejemplo. El programa
LD A,-8 0
ADD A ,- 8 0
tiene por efecto almacenar en A el número binario 0110 0000, que es %o
60h y no es el resultado esperado, ya que es un número positivo. tese que
en este caso se habrá activado el indicador de arrastre. El programa
LD A,80
ADD A,80
almacenaría en A el número 1010 0000, que es -96, y desactivaría el indica-
dor de arrastre. En ambos programas queda activado el indicador de
sobrepasamiento.
Así pues, el indicador de sobrepasamiento señala el exceso en las operacio-
nes con signo (en complemento a 2) mientras que el de arrastre sala el ex-
ceso en las operaciones de números positivos. Como dejan claro los ejem-
plos anteriores, estos dos indicadores son completamente independientes
uno de otro.
Las operaciones aritticas que producen resultados fuera del intervalo
-128<=n<=l27 en el caso de 8 bits, y de -32768<=nn<=32767 en el de 16 bits,
activan el indicador de sobrepasamiento. Obsérvese que dos meros de sig-
no diferente no pueden originar sobrepasamiento cuando se suman. Por el
contrarío, dos meros del mismo signo no pueden dar sobrepasamiento
cuando se restan.
En los códigos nemotécnicos, los símbolos que se emplean son PE para
sobrepasamiento y PO para no sobrepasamiento. No son símbolos nada ne-
motécnicos (ni siquiera en inglés) pero es que se usan los mismos que para
la paridad.
Cuando se emplea este indicador como indicador de paridad (no hemos
visto aún operaciones que lo afecten en este sentido) lo que mide es la pa-
INDICADORES , CONDICIONES y DECISIONES CONDICIONADAS 69
dad del número de bits iguales a 1 en un byte. El indicador se activa (PE)
cuando hay un mero par de bits 1 en el byte y se desactiva cuando dicho
número es impar.
Veamos por fin dos instrucciones de las que ya hemos hablado, SCF y
CCF. La instrucción SCF (set carry flag) tiene por efecto poner a }el indica-
dor de arrastre. La instrucció n CCF {complement carryflag) cambia el valor
del indicador de arrastre a su valor contrari o (cualquiera que fuera el valor
anterior del indicador). Los códigos de estas instrucciones son:
ENSAMBL ADOR DE CI MA L H E X B I N A R I O
CCF 63 3F 00 111 111
SCF 55 37 00 110 1 11
Resumen
Vamos a resumir las instrucciones explicadas en este capítulo. Utilizaremos
los símbolos:
r = cualquiera de los registros de 8 bits (A, B, C, D, E, H o L)
rr = cualquier par de registros que se utilicen como uno de 16 bits
n =u n número de 8 bits, o sea, entre 0 y 65535
nn =un número de 16 bits, o sea, entre 0 y 65535
() rodeando un número o un par de registros = el contenido de ¡a
direccn.
PC = contador de programa
SP = puntero de pila
Los indicadores accesibles al programador son C (arrastre), Z (cero), S
(signo) y P/V (paridad/sobrepasamiento).
El indicador de sobrepasamiento señala el hecho de que en una operación
aritmética de números con signo, el resultado ha cambiad o de signo y es
incorrecto.
cc puede ser C, NC, Z, NZ, PE, PO, M y P.
CP realiza una falsa resta (SUB) de] resgistro A y altera los indicadores
en consecuencia, pero no cambia ninguna otra cosa.
JR sólo admite condiciones sobre los indicadores C y Z.
DJNZ equivale a DEC B y JR NZ, pero no altera los indicadores .
JP, CALL y RET pueden convertirse en condicionadas al valor de un
indicador.
Ninguna de las instrucciones LD, CALL, JP, JR o RET afecta a los
indicadores.
8
Operaciones lógicas
El microprocesador Z80 posee un juego de instrucciones lógicas similar al
de operadores lógicos del BASIC del Amstrad, lo que no es sorprendente ya
que es justamente el Z80 e! que realiza el trabajo cuando se está ejecutando
un programa BASIC. Como usted estará familiarizado con la utilizacn de
los AND, OR y XOR de BASIC, nos resultará s sencillo explicar sus aná-
logas de código de máquina. Si no es así, le convendría leer lo que sobre este
aspecto se dice en el capítulo 4 de la Guía del usuario, así como practicar
un poco . En lo que sigue supondremos que se conocen bien ¡as expresiones
lógicas del BASIC del Amstrad.
Las instrucciones lógicas AND, OR y XOR se consideran instrucciones
aritméticas; sólo pueden ser utilizadas para valores de 8 bits y usando el re-
gistro A. Los códigos son semejantes a los de las restantes operaciones arit-
méticas de 8 bits; los bits 5, 4 y 3 son los que determinan la naturaleza de
la operación. E! código nemocnico no requiere que se haga referencia al
registro A, ya que en este aspecto no puede haber confusn, como ocurriría
con SUB. Las instrucciones lógicas afectan a los indicadores en el sentido
que corresponda al resultado de ¡a operación. El de arrastre queda siempre
a 0, ya que AND, OR y XOR no pueden producir un resultado que precise
más de 8 bits. La consideración de sobrepasamiento en estas instrucciones
carece de sentido, de manera que el indicador P/V se interpreta como indica-
dor de paridad. El indicador de signo refleja el estado del bit 7 de A tras la
operación. El indicador de cero se activa cuando A no tiene ninn bit a 1
y se desactiva en caso contrario.
ENSAMBLADOR
AND n
AND r
XOR n
XOR r
OR n
OR r
DEC IMA L
2 3 0
160 -
238
168 -
246
176 -
167
175
183
HEX
E 6
AO -
EE
A S -
F6
BO -
A7
A F
B 7
BINARIO
1 1
10
11
10
11
10
100 110
100 r
101 110
101 r
110 110
1 10 r
71
7 2 CÓDIGO MÁQUIN A PARA PRINCIPIANTES CON AMSTRAD
Para entender bien la utilidad de las operaciones lógicas hay que empezar
por pensar en binario; sólo así se comprende el sentido de muchos de los as-
pectos en los que se las puede utilizar, Por ello es muy probable que usted
no alcance a ver ahora toda la utilidad que tienen estas instrucciones.
Volvamos al programa de la figura 7.1. La comprobación de los digos
se hacía independientemente para las letras masculas, para las minúsculas
y para el intervalo entre ambas. Per o de hecho, la única diferencia entre los
dos tipos de letras está en el bit 5 de su código. Par a las mayúsculas es un
0 y para las minúsculas un 1. Con la instruccn AND es posible convertir
todas las letras en mayúsculas, y con OR se pueden convertir todas las letras
en misculas. ¿De qué manera? Podrá verlo a tras de las modificaciones
que vamos a realizar en el programa de la figura 7.1.
Cambie la línea 220 del programa por
HEX ENSAMBLADOR
AAD7 CD 2B AB CAL L EXTRA
que requiere 01A3 como suma de comprobación, y ada al final del
programa
AB2B
AB2E
AB2F
AB30
AB33
AB35
AB38
AB3B
CD
0 0
0 0
CD
3 E
CD
21
C9
5A BB
5A BB
2 0
5A BB
E D AA
EXTRA CALL 4 7 9 6 2
NO P
NO P
CAL L 4 7 9 62
LD A , 3 2 ;
CALL 4 7 9 6 2
LD HL,MESS T
RET
THE CODE FOR SPACE
Esta última parte tiene las sumas 0422, 0463.
Al ejecutar ahora el programa, el caracter correspondiente a la tecla pulsa-
da aparecerá repetido dos veces, seguido de un espacio y del correspondiente
mensaje. Las dos instrucciones NOP le proporcionan espacio para que pue-
da experimentar con AND, OR y XOR y vea el efecto que producen. Co-
mience por cambiar las dos NOP por
HEX ENSAMBLADOR
AB2E F6 2 0 OR # 2 0
OPERACIONES LÓGICAS 73
Si no dispone de ensamblador, lo más sencillo será que utilice POK E
&AB2E,&F6:POKE&AB2F,&20 como comando directo.
Ejecute el programa probando con varias teclas y pulsando unas veces sí
y otras no la tecla [SHIFT] . (Asegúrese de que no está activada [CAPS
LOCK] ya que Amstrad no ha puesto un indicador luminoso que nos permi-
ta saberlo). Verá ahora que las masculas cambian a minúsculas, las mis-
culas y los números quedan como están y los símbolos cambian o no según
sea el bit 5 de su código. Incorporando la instrucción OR#20 al programa
principal se ahorran unas cuantas instrucciones CP.
La versn reformada del programa de la figura 7.1 está en la figura 8.1.
Ahora se utiliza el indicador de signo para saber cuándo no se trata de un
digo ASCII (si el bit 7 vale 1 el código será 128 o superior)- La instrucción
OR sirve indirectamente para activar (si es el caso) el indicador de signo, sin
necesidad de un CP 0 que habría añadido un byte al programa.
Ahora ha habido un ahorro de un byte tras sustituir JR por JP.
Hisoft GENA3 Assembler . Page 1.
Pass 1 errors: 00
AAB4
AAB4
AAB4
AAB7
AAB9
AAB B
AABC
AABE
AAC1
AAC3
AAC5
AAC7
A A C9
AACB
AACC
AACD
AACE
AAD1
AAD3
AAD4
A A D5
AAD7
A A D9
AADA
AADD
AADF
A AE 1
A A E2
CD18BB
0604
FEFC
CB
F620
FACDAA
FE7B
3007
FE61
380 3
2B03
0 5
05
0 5
21E4AA
3E0A
BE
2 3
20FC
10FA
7E
CD5AB B
FE0A
28D3
23
1BF5
1
2
10
20
30
40
50
60
90
100
120
130
160
170
180
190
200
210
220
230
240
250
260
270
280
290
300'
310
320
330
¡ FIG
O TR A
START
ISLE T
NOTLET
NOTASE
ISA
LOOKMS
PRINT
8, 1
VERSION DE L PROGRAMA DE 7.1
ORE
ENT
CALL
LD
CP
RET
OR
JP
CP
JR
CP
JR
JR
DEC
DEC
DEC
LD
LD
CP
INC
JR
DJNZ
LD
CALL
CP
JR
INC
JR
43700
4370 0
47896
B,4
252
Z
#20
M,NOTASC
123
NC,NOTLE T
97
C,NOTLET
Z,ISA
B
B
B
HL,MESST
A,#0A
(HL)
HL
NZ,LOOKMS
LOOKM S
A,(HL)
4796 2
#0A
Z,START
HL
PRINT
74 DIGO MÁQUINA PARA PRINCIPIANTE S CON AMSTRA D
AAE4
AAE5
AAE9
AAED
AAF 1
AAF5
AAF7
AAF9
AAF D
AB01
AB05
AB07
ABO B
ABOF
AB1O
AB12
AB16
AB1A
AB1E
AB20
Pass
Tabl e
Execu
OA
41204C45
54544552
20425554
204E4F54
2041
ODOA
4E4F5420
41204C45
54544552
ODOA
4E4F5420
41534349
49
ODOA
594F5520
50524553
53454420
4121
ODOA
2 errors:
340 MESST
350
360
370
3B0
390
400
410
420
430
440
450
460
470
4B0
490
500
510
520
530
00
used: 110 fro m
tes: 43700
DEF B
DEFM
DEF M
DEFM
DEFM
DEFM
DEFW
DEFM
DEFM
DEFM
DEFW
DEFM
DEFM
DEFM
DEFW
DEFM
DEFM
DEFM
DEFM
DEFW
184
Figura 8.1. Sumas de comprobación: 0582, 05B8, 0215, 04B6, 0439, 02A7, 022B, 02A2,
0251, 0268, 020D, 0608, 0278.
En lugar de la instrucción OR se puede usar AND para cambiar miscu-
las en mayúsculas. La forma exacta de la instrucción para cambiar a 0 el bit
5 es AND #DF.
También se puede utilizar XOR en lugar de OR . En este caso las mascu-
las pasan a minúsculas y viceversa. Pero ahora hay que tener cuidado para
no pulsar teclas que no sean alfanuméricas, ya que los códigos de algunas
teclas se transforman con XOR en códigos de control.
La instruccn AND se puede utilizar para 'enmascarar' ciertos bits. Ésta
es la terminoloa que se emplea cuando se ignoran determinados bits, con-
virtiéndolos en ceros. Por ejemplo, si en un programa se necesita que las le-
tras lleven códigos del 1 (para A) al 26 (para Z), la solución es enmascarar
los 3 bits superiores del código de la letra con AND%00011111.
La instrucción OR tiene el efecto opuesto y puede servir para recuperar los
bits enmascarados por la instrucción AND. Una de las aplicaciones más fre-
cuentes y apropiadas de esta instrucción es la 'sobreescritura' en pantalla; con-
siste en escribrir sobre lo que ya está escrito sin suprimirlo. También se la uti-
liza, como ya hemos dicho, para recuperar bits enmascarados o modificados.
#OA
"A LE"
"TTER"
" BUT"
" NOT"
" A"
#0A0D
"NOT "
"A LE"
"TTER"
#0A0D
"NOT "
"ASCI"
"I "
#0A0D
"YOU "
"PRES"
"SED "
"
A
! "
#OA0D
OPERACIONES LÓGICAS 75
Por ejemplo, para pasar del valor de una cifra decimal a su código ASCII
se puede utilizar la instruccn ADDA,#30 y, de hecho, es lo que hicimos
en el programa que fuimos desarrollando a lo largo del capítulo 6. Pero el
mismo efecto se consigue con la instruccn OR#30, que es la que hubiése-
mos utilizado si la hubiésemos conocido entonces.
La instrucción XOR sirve para cambiar el valor de ciertos bits a su valor
opuesto. Al igual que la OR, se la usa a menudo en rutinas de escritura en
pantalla. Por ejemplo, el Amstrad la utiliza para la escritura 'transparente'
(consulte el capítulo 5 de la Guía del usuario).
La siguiente instrucción lógica es la de complementación, CPL, cuya aná-
loga en BASIC es el operador NOT. Sólo puede operar sobre el registro A.
Su efecto es cambiar e! valor de todos los bits al valor opuesto, o sea, tiene
el mismo efecto que XOR#FF. La instrucción CPL no afecta a ninguno de
los indicadores accesibles al programador .
El programa de la figura 8.2 realiza una demostración gráfica de la aplica-
ción de CPL. Lo que hace es complementar todas las posiciones del 'mapa
de pantalla', o sea, del área de la memoria en que se almacena la informa-
ción que aparece en la pantalla. Se invierten los bits correspondientes a las
tintas de papel y de pluma, lo que en modo 2 tiene el efecto de crear el negati-
vo de la pantalla; sin embargo, en los modos 0 y 1 el efecto es más complejo,
ya que admiten más de 2 colores de tinta. En modo 2, donde lo hay 2 colo-
res, cada byte controla 8 puntos de la pantalla (pixels), de manera que si el
bit de un punto está a 0 su color es el de la tinta 0, y si está a 1 su color es
el de la tinta 1. Al invertir los bits con CPL, lo que se hace justamente es in-
vertir el número de la tinta que corresponde a cada punto.
En modo 1 hay 4 colores de tinta. La tinta que colorea cada punto de la
pantalla se determina con 2 bits, de acuerdo con el código natural que asigna
00 para la tinta 0, 01 para la 1, 10 para la 2 y 11 para la 3. Cada byte controla
entonces 4 puntos de la pantalla. Si, por ejemplo, la tinta del papel es la 0
y la de la pluma es la I, después de la ejecución del programa el papel se
verá del color de la tinta 3 y la pluma del de la tinta 2.
En modo 0 la cosa se complica más, puesto que hay 16 tintas a distinguir;
cada punto necesita 4 bits y cada byte controla entonces 2 puntos.
Ahora se ve claramente por qué la resolución se hace más baja cuando
aumenta el número de tintas que se emplean simulneamente. Lo que ocu-
rre ades es que sólo en modo 2 los bits de un byte se corresponden con
los punto s de la pantalla en el orden que pudiera esperarse . En los otros mo-
dos existe una mezcla de bytes que hace las cosas s complicadas, Po r
ejemplo, en modo 1, los bits 3 y 7 controlan el punto más a la izquierda de
los que corresponden al byte, los bits 2 y 6 el que le sigue a la derecha, y
así sucesivamente.
76 C Ó D I G O M Á Q U IN A P A RA P R I N CI P I A N T ES C O N A M S T R A D
Hisoft GENA3 Assembler. Page 1 .
Pas s 1 errors: 00
AA B 4
AAB4
AA B 4
AA B 7
AA B B
AA B 9
AAB A
AABB
AABC
AABD
AABE
2 1 00 C O
7 C
B 5
C 8
7 E
2 F
7 7
2 3
1 8 F7
1
2
1 0
2 0
3 0
4 0
5 0
6 0
7 0
8 0
9 0
1 0 0
1 1 0
;
F I G
8,2
; PROGRAMA PAR A COMPLEMENTAR
E L MAPA D E
LOOP
ORG
ENT
LD
L D
DR
RET
LD
CPL
L D
IN C
JR
P A N TA L LA
43700
4 3 7 0 0
H L , # C 0 0 0
A , H
L
Z
A , ( H L )
( H L ) ,A
HL
LOOP
P a s s 2 e r r o r s : 0 0
Sumas de comprobación:042 J, 010F.
Figura 8.2
H i s o f t GENA3 A s s e m b l e r . P a ge
P a s s 1 e r r o r s : 0 0
1 0 ; PROGRAM A PARA D I V I D I R LA P ANT A L L A
2 0 ; EN COLUMNA S D E COLORE S
INK 0 , 1 , 2 , 5
AA B 4
AAB4
AA B 4
AA B 7
AAB B
A AB 9
AABA
AABC
AABD
AABE
210 0 C O
7C
B5
C 8
3E5C
7 7
2 3
1 BF 7
3 0
4 0
5 0
60 LOOP
7 0
8 0
9 0
1 0 0
11 0
1 2 0
ORG
ENT
LD
L D
OR
RET
LD
LD
INC
JR
43700
43700
H L , # C 0 0 0
A,H
L
Z
A,%01011100
( H L )
,
A
HL
LOOP
Pass 2 errors : 0 0
Sumas de comprobaci ón : 040E, 010F.
Figur a 8.3
OPERACIONES LÓGICAS 77
Para terminar de rizar el rizo, el orden en que se controla la pantalla no
es el que uno pudiera esperar (salvo si se tiene la mente algo retorcida).
El programa de la figura 8.3 da otro ejemplo de manejo de la pantalla.
Su efecto es dividir la pantalla del modo 1 en columnas cuya anchura es de
un punto, coloreadas alternativamente de las cuatro tintas posibles. Aclare-
mos que los códigos de las cuatro tintas se almacenan con el bit más signifi-
cativo del código en la posicn menos significativa de las dos que correspon-
den al punto. Desde luego, quien diseñó esta pantalla debía tener algo de
dico.
El apéndice F explica detenidamente lo que se refiere al mapa de la
pantalla.
La última de las instrucciones lógicas es la instrucción NEG (negacn).
El efecto que tiene es cambiar de signo el contenido del registro A, tomando
el complemento a 2. En otras palabras, transforma A en la diferencia 0-A.
Esta instrucción afecta a los indicadores como si se tratase de una instruc-
ción SUB de 8 bits. Quedan afectados los indicadores C, Z, S y P/V, este
último en el sentido de sobrepasamiento.
Los códigos de CPL y NEG son:
ENS AM BLAD O R DE CI M A L HE X B I N A R I O
NEG 237 68 E D 44 11 101 101 01 000 100
CPL 47 2F 00 101 111
Resumen
Vamos a resumir las instrucciones explicadas en este catulo. Utilizaremos
los símbolos:
r = cualquiera de los registros de 8 bits (A, B, C, D, E, H o L)
rr = cualquier par de registros que se utilicen como uno de 16 bits
n - u n número de 8 bits, o sea, entre 0 y 255
NN = un número de 16 bits, o sea, entre 0 y 65535
( ) rodeando un número o un par de registros =el contenido de la
dirección.
PC = contador de programa
SP = puntero de pila
Todas las instrucciones lógicas trabajan con el valor que haya en A.
AND, OR y XOR se pueden utilizar con r o con n.
Con AND se ponen a 1 ios bits que estaban a 1 a la vez en el acumulador
y en el operando; los demás se ponen a 0.
78 DIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
Con OR se ponen a 1 los bits que estaban a 1 en el acumulador o en el
operando; los demás se ponen a 0.
Con XOR se ponen a 1 los bits que estaban a 1 en el acumulador o en el
operando; pero no en ambos; los demás se ponen a 0.
AND, OR y XOR ponen a 0 el indicador de arrastre y afectan a los restan-
tes de acuerdo con el resultado que quede en el registro A. El indicador P/V
tiene el sentido de indicador de paridad.
CLP y NEG no llevan operandos.
CLP cambia cada bit de A a su valor contrario. No afecta a los indicadores.
NEG devuelve el complemento a 2 del valor de A. Los indicadores quedan
afectados como si se tratase de una instrucc n SUB que restase 0-A.
9
Utilización de la pila
Ya hemos introducido brevemente en el capítulo 5 el funcionamiento de la
pila (stack), motivados por la necesidad de comprender el funcionamiento
de las instrucciones CALL y RET. La instrucción CALL deposita en la pila
la dirección de la instrucción siguiente (que es previsiblemente la dirección
de la vuelta); la instrucción RET recupera de la pila dicha dirección. Adverti-
mos asimismo sobre la necesidad de cuidar el equilibrio entre la información
que se almacena en la pila y la que sale de ella.
Existen instrucciones que permiten utilizar la pila como un almacén tem-
poral de datos para el usuario. Se trata de una utilización compartida, ya
que, simultáneamente, el programa continua almacenando en ella sus direc-
ciones de retorno de las subrutinas. Por ello es necesario manejar con cuida-
do este tipo de instrucciones. Bien es verdad que en ocasiones se provoca de-
liberadamente el que una instrucción RET devuelva el programa a un punto
diferente del de partida. Pero cuando de forma inadvertida se obtiene este
resultado, es casi seguro que se provoque un fracaso irreparable del progra-
ma, cuya consecuencia inmediata será tener que apagar y volver a encender
el ordenador. Viene al caso ahora recomendarle que grabe previamente el
programa antes de ejecutarlo. Así, en caso de castrofe, pod al menos re-
cuperar el programa para corregirlo.
Las instrucciones que permiten guardar datos en la pila y recuperarlos
son, respectivamente, PUSH y POP. La instrucción PUSH rr coloca e n la
pila el contenido del par de registros rr y disminuye en dos unidades el punte-
ro de pila SP para que siga apuntando al extremo de la pila. Por el contrario,
la instrucción POP rr almacena en el par rr el contenido del extremo de la
pila y aumenta en dos unidades el puntero de pila. La mecánica es la misma
que ya estudiamos en la figura 5.8, pero el trasvase no se realiza al contador
del programa, PC , sino a un par de registros.
Los códigos de estas instrucciones son
ENSAMBL ADOR B I N A R IO
PUSH rr 11 rr0 101
POP r r 11 rr0 001
79
8 0 CÓDIGO MÁQUIN A PARA PRINCIPIANTES CON AMSTRA D
donde hay que sustituir rr por un par de registros y por el código binario de
dicho par. Estos códigos binarios eran
BC = 00 DE=01 HL=10
Pero ahora se puede utilizar también el digo 11b, que indica el pa r AF for-
mado por el acumulador A y el registro de estado F.
Los códigos de PUSH y POP tienen gran semejanza (no casual) con
CALL y RET:
CALL 11 001 101 RET 11 001 001
PUS H 11 rr0 101 POP 11 rr0 001
En la figura 9.1 presentamos un programa que sirve para conocer la direc-
ción a !a que apunta el puntero de pila y el dat o situado en el extremo de
la pila (el que se obtendría haciendo una extracción de la pila).
Hisoft GENA3 Assembler. Pag e 1 .
Pass 1 errors: 00
1 ; FIG 9,1
2
3
4
10
20
30
60
70
80
70
J 00
110
1 20
130
140
150
16 0
170
1 80
190
2 00
2 1 0
2 20
i PROGRAMA PARA CONOCER A
DONDE APUNTA E L PUNTERO
; DE P I L A Y EL VALOR QUE
SE OBTENDRA EN LA
S I G U I EN TE EX TRA CC ION DE
; LA P I L A
P R IN
PROG1
PROG2
ORG
ENT
EQU
POP
PUSH
LD
CALL
C AL L
LD
C AL L
LD
CAL L
LD
C AL L
LD
C AL L
LD
CAL L
LD
OR
4 2 0 0 0
4 2 0 00
4 7 9 6 2
HL
HL
( 4 3 8 2 8 ) , H L
PMESS1
PR0G2
( 4 3 8 2 8 ) , S P
PMESS 2
D E , - 1 0 0 0 0
RED N
D E , - 1 0 0 0
REDN
D E , - 1 0 0
REDN
E , - 1 0
RED N
A,(43828)
# 3 0
A 4 10
A 4 10
BB5A
A 4 1 0
A 4 1 1
A 4 12
A 4 15
A 4 1 8
A 4 1B
A 4 1 F
A 4 22
A 4 25
A 4 28
A42B
A 4 2E
A 4 3 1
A 4 34
A 4 36
A 4 39
A43 C
E l
E5
2 2 3 4 AB
CD5AA4
CD2 2 A4
E D 7 33 4 A B
CD61A 4
11F0D8
CD41A 4
1 1 18 F C
CD4 1 A4
119 C F F
CD41A 4
1 EF 6
CD41A 4
3 A 3 4 AB
F 6 3 0
UTILIZACN DE LA PILA 81
A43E
A441
A443
A444
A447
A44 S
A44B
A44D
A45 0
A452
A455
A45 6
A459
A45A
A45C
A45F
A461
A46 3
A466
A467
A46A
A46B
A46D
A46E
A47 0
A475
Pasa
C35AB B
3E3 0
3C
2A34AB
19
2234AB
3BF6
2A34A B
ED52
2234A B
3 D
CD5ABB
C 9
0607
216EA 4
1805
0604
2175A 4
7E
CD5AB B
23
10F9
C9
0A0 D
285350293D
2053503 D
2 errors : 0
230
240
250
260
270
280
290
300
310
320
330
340
350
360
370
3B0
390
400
410
420
430
440
450
460
470
480
0
REDN
FNUM
PMESS1
PMESS2
MLOOP
MESS1
MESS 2
JP
LD
INC
LD
ADD
LD
JR
LD
SBC
LD
DEC
CALL
RET
LD
LD
JR
LD
LD
LD
CAL L
INC
DJNZ
RET
DEFW
DEFM
DEFM
PRIN
A,«30
A
HL,(43828)
HL,DE
( 4 3 8 28 , H L
'C,FNUM
HL,(43828)
HL,DE
(43828),HL
A
PRI N
B,7
HL,MESS1
MLOOP
B,4
HL,MESS2
A,(HL )
PRIN
HL
MLOOP
#0D0A
"(5P)="
" SP="
T a b l e u s e d : 1 32 f r o m 1 96
E x e c u t e s : 4 2 0 0 0
Sumas de comprobación: 0581, 05B6, 0561, 0580, 04F9, 02C7. 047C, 0403,
03A9, 0300, 013D
Figura 9.!
No necesitaremos explicar muchas cosas del programa, ya que, en su ma-
yor parre, le será familiar.
Se ha cambiado algo la forma de imprimir los números. Para conseguir
a partir de una cifra su código ASCII se carga con #30 el acumulador desde
el comienzo, excepto para la última cifra, pues en este caso se carga la cifra
y luego se utiliza la instrucción OR.
La instrucción de la línea 110 es nueva, pero es fácilmente comprensible
a través de su código nemocnico por ser similar al de instrucciones ya expli-
cadas: las del tipo LD (nn),rr. Ahora, sin embargo, en lugar de un par de
registros se emplea el registro SP de 16 bits. Además, el digo de
LD (nn),SP es 1110 1101 01 110 011 n n, completamente análogo a los de
la figura 5.7 utilizando 11b como código de 2 bits para SP. Cabe preguntarse
qué representa el código 10b en este tipo de instrucciones. Parece lógico que
represente a HL como en otros casos y de hecho así ocurre, si bien las ins-
trucciones LD HL,(nn) y LD(nn),HL tienen además otros códigos s bre-
8 2 CÓDIGO MÁQUIN A PARA PRINCIPIANTES CON AMSTRAD
ves que ya explicamos. Puede comprobar que este otro digo funciona tam-
bién, sustituyendo la línea 80 (de 3 bytes) por las cuatro líneas
80 DEFB #ED
81 DEFB %01100011
82 DEFB #34
83 DEFB #AB
volviendo a ensamblar el programa y observando que el programa sigue fun-
cionando exactamente igual.
El programa comienza por extraer el valor (de 2 bytes) que hay en el extre-
mo de la pila y lo carga en HL; a continuación devuelve este valor a ¡a pila
para dejarla inalterada, pero HL guarda ya una copia de dicho valor. HL
se carga en la posición de memoria 43828. Luego, la rutina PMESS1 impri-
me el mensaje '(SP) = ' y a continuación la rutina PROG2 se encarga de im-
primir el valor del extremo de la pila. En este momento se llevan realizados
dos CALL y dos RET, por lo que el puntero de pila estará como al comienzo
del programa. El contenido de SP se deposita ahora en memoria para ser im-
preso después. Previamente la rutina PMESS2 imprime el mensaje ' SP = '
Inmediatamente se entra en la rutina PROG2, que es la que imprime el nú-
mero. Como se ha accedido a esta rutina sin un CALL, la instruccn RET
final provocará la vuelta a BASIC o al ensamblador, según el caso.
Puede usted comprobar mo se puede manipular la pila intencionada-
mente cargando las siguientes neas previas al programa anterior:
A409 5 ORG 41993
A409 6 ENT 41993
A409 2110A4 7 LD HL,PROGl
A40C E5 8PUSH HL
A40D E5 9 PUSH HL
A40E E5 10 PUSH HL
A40F E3 20 PUSH HL
Si se utiliza el CARGADOR HEX la dirección de HIMEM debe ser 41992
y la dirección inicial 41993. Vuelva a ensamblar el programa y ejecútelo. Si
ha utilizado nuestro cargador comience la ejecucn en A409h (41993).
Lo que hace ahora el programa es ejecutarse cinco veces. La culpa de los
cuatro retornos suplementarios es de las cuatro instrucciones PUSH, que ha-
cen que el RET pase el control a la direccn de PROGl en lugar de volver
al BASIC o al ensamblador.
Las instrucciones que hemos visto son las únicas que modifican implícita-
mente el puntero de pila cada vez que se las ejecuta. Pero hay otra serie de
instrucciones que hacen posible la manipulación de la pila , pasando infor-
mación desde y hacia la pila.
UTILIZACIÓN DE LA PILA 83
Un primer grupo de instrucciones está formado por las instrucciones de
carga que afectan al puntero de pila, SP; son las instrucciones más directas.
Al encender el Amstrad CPC464, el programa de arranque en frío del que
ya hemos hablado inicializa el puntero de pila en una dirección alta, la 49144
(BFF8h), desde donde irá creciendo hacia abajo. Normalmente no hará falta
modificar esta direccn de la base de ¡a pila, pero otras veces puede ser con-
veniente alterar la posición de la pila modificando el contenido de su puntero
SP.
Mantenga siempre el puntero de pila apuntado hacia una dirección par,
sobre todo en el Amstrad, donde puede intercambiarse áreas de memoria.
En caso contrario puede llegar a ocurrir que quede desactivada la mitad de
un valor almacenado, permaneciendo el byte restante en la pila. Lo mejor
es inicializar el puntero en una dirección que sea múltiplo de 256, ya que esto
permitirá el máximo crecimiento de la pila antes de cambiar de página de
memoria.
Existen para SP las instrucciones de carga que ya hemos visto para los pa-
res de registros. Los códigos de estas instrucciones se forman según las reglas
que ya explicamos, teniendo en cuenta que el código de 2 bits para SP es 11.
Estos códigos son:
ENSAMBLADOR HEX B I N A R I O
LD SP,nn 31 n n 00 110 001 n n
LD SP,(nn ) ED 76 n n 11 101 101 01 111 011 n n
LD (nn),SP ED 73 n n 11 101 101 01 110 01 1 n n
Como hemos dicho, hay ocasiones en que es necesario, o simplemente con-
veniente, cambiar el puntero de pila. Así ocurre, por ejemplo, cuando hay
alguna instrucción prioritaria sobre cualquier cosa se esté realizando. En ese
caso puede no existir la posibilidad de asegurarse de que la pila va a quedar
equilibrada y, por lo tanto , debe inicializarse la pila en una direccn
conocida.
Un buen ejemplo de situación en que es provechoso alterar el puntero de
pila, lo da el programa de la figura 9.2. En este caso se almacena el valor
de SP en memoria al comenzar el programa, para recuperarlo al final.
El programa es una modificación del de la figura 8.3, utilizando la instruc-
ción PUSH; se emplea así menos tiempo en rellenar la pantalla que de la ma-
nera original. En este programa se carga en SP el valor 0. Como la dirección
por debajo de 0 es - 1 , o sea FFFFh, la pila comienza a ocupar la parte supe-
rior del área de memoria reservada a la pantalla a medida que se ejecutan
las instrucciones PUSH. EN HL se carga el valor 5C5Ch, que es el mismo
84 CÓDIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
H i s o f t GENA 3 A s s e m b l e r . Pa g e
P a s s 1 e r r o r s : 00
88B8
8BBB
88BB
88BC
8 8 B F
8 8 C2
8 8 C4
8 8 C 6
88C7
BBC9
88CA
88CC
8 8 D0
88D 1
E D 7 3 D 1 8 8
3 1 0 0 0 0
2 1 5 C5 C
0E20
0 6 00
E 5
10FD
OD
2 0 F 8
ED7BD1B8
C9
0 0 0 0
1
2
10
20
30
10
50
60
70
80
90
1 00
11 0
12 0
13 0
1 40
;
FIG
9 , 2
; REL L ENO DE
BLOOP
SLOOP
SPWD
ORG
ENT
LD
LD
LD
LD
LD
PUSH
DJNZ
DEC
JR
LD
RET
DEFW
LA PANTAL LA
3 5 0 0 0
3 5 0 00
( S P W D ), S P
S P , # 0
H L , # 5 C 5C
C , # 2 0
B , # 0
HL
SLOOP
C
NZ,B L O OP
S P, ( SP WD )
0
P a ss 2 e r r o r s : 0 0
Table used: 48 from 127
Executes: 35000
Sumas de comprobacn: 03C3, 034B, 03BA
Figura 9.2
con que se cargaba A en el programa de la figura S.3 pero repetido dos veces;
ahora se llenarán cada vez dos posiciones de memoria.
Luego viene el cleo del programa, que es un doble bucle anidado. Es
una técnica muy corriente para superar las limitaciones de los valores que
pueden almacenar los contadores. El bucle externo, BLOOP, pasa 32 veces;
en cada una de ellas se ejecuta 256 veces el bucle interno, SLOOP. La ins-
trucción PUSH HL se ejecuta entonces 32*256 = 8192 veces y, como cada
vez se rellenan dos posiciones, se llena un total de 16384 (4000h) bytes. El
programa termina recuperando el valor inicial de SP y ejecutando un RET.
El puntero de pila, SP, se puede utilizar también en las operaciones arit-
méticas de 16 bits. Se emplea en ADD, ADC, SBC, INC y DEC del mismo
modo que los pares de registros. Los códigos binarios de las instrucciones
se forman de la misma manera, pero utilizando 11 en los bits 5 y 4 en el caso
de SP. Por ejemplo,
ADD HL,DE es 00 011 001
DEC BC es 00 001 011
luego
luego
ADD HL,S P es
DEC SP es
111 001
111 011
UTILIZACIÓN DE LA PILA 85
La siguiente instrucción permite intercambiar entre el valor del extremo
de la pila con el contenido de HL. Como se trata de un intercambio (exchan-
ge), el código nemotecnico de la instrucción será EX; esto se completará con
(SP) y HL, que son las dos cosas que se intercambian. Los códigos comple-
tos son:
E N S A M B L A D OR HEX B I N A R I O
EX (SP),H L E3 11 100 011
Es una de las instrucciones referentes a la pila que se utiliza más; se emplea
para cambiar la dirección de vuelta de una subrutina desde la propia subruti-
na, o incluso para añadir subrutinas adicionales.
Supongamos por ejemplo que tenemos una subrutina cuya finalidad es
realizar ciertos cálculos de 16 bits para el programa principal. Cada resulta-
do se almacena en HL, como ya sabemos. Si hay varios cálculos que hacer,
será preciso liberar HL para realizar otro de los cálculos. Luego hab que
guardar en memoria el contenido de HL para que lo recupere s tarde el
programa principal. La instrucción LD (nn),HL puede servir, pero emplea
3 bytes y otros 3 la instrucción que devuelve el valor a HL. Lo más económi-
co es almacenar el resultado en la pila, pero, si se hace directamente, se im-
posibilita la extraccn de la direccn de retorno de la subrutina. Lo que se
puede hacer entonces es almacenar el valor, pero de manera que intercambie
su posición con la dirección de la vuelta al programa. Esto se consigue con
las dos instrucciones
EX (SP),HL y PUSH HL
La primera almacena el resultado numérico y extrae la direccn de vuelta;
la segunda coloca de nuevo en la pila la dirección de vuelta. Se utilizan así
2 bytes, y otro más cuando el programa principal recupere el resultado.
Hay por fin una última instrucción. Es un poco rara para lo que hemos
visto hasta ahora, ya que permite cargar un registro de 16 bits con el conteni-
do de otro. S e trat a de
ENSAMBLADOR HEX B I N A R IO
LD SP,H L F9 11 111 001
que se utiliza cuando una dirección de vuelta proviene del resultado de un
cálculo
Aquí termina nuestra explicación, que puede haberle resultado pesada.
Ahora debe usted mismo experimentar con los ejemplos que hemos dado,
86 DIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
carndolos y ejecundolos en su Amstrad. No se olvide de grabar el pro-
grama antes de ejecutarlo; si algo sale mal podrá desconectar y volver a en-
cender el ordenador, y tendrá el programa a su disposición para corregirlo.
Vigile siempre que haya el mismo mero de PUSH que de POP, y que cada
CALL lleve aparejado un RET.
Resumen
Vamos a resumir las instrucciones explicadas en este capítulo. Utilizaremos
los símbolos:
r = cualquiera de los registros de 8 bits (A, B, C, D, E, H o L)
rr = cualquier par de registros que se utilicen como uno de 16 bits
n =un número de 8 bits, o sea, entre 0 y 255
nn - un número de 16 bits, o sea, entre 0 y 65535
( ) rodeando un número o un par de registros=el contenido de la
dirección.
PC = contador de programa
SP = puntero de pila
La pila va creciendo hacia posiciones más bajas de la memoria. Su extre-
mo es la direccn más baja de las que ocupa la pila; a él apunta SP.
PUSH coloca en el extremo de la pila el contenido de un par de registros,
y actualiza SP para que apunte al nuevo extremo.
POP hace justamente lo contrario.
Todo rr habitual y el par AF pueden ser utilizados con PUSH y POP.
Todas las instrucciones de carga y aritméticas de 16 bits, así como INC
y DEC , pueden utilizar SP.
EX (SP),HL intercambia el contenido del extremo de la pila con el conte-
nido de HL.
Cada PUS H debe ir acompañado del correspondiente POP. En la instruc-
ción POP se puede utilizar un rr diferente del empleado en PUSH.
Cada CALL debe llevar el correspondiente RET.
10
Instrucciones que trabajan con un solo bit
Entre los aspectos particulares que distinguen al Z80 de otros microprocesa-
dores de 8 bits está el hecho de poseer instrucciones que trabajan con un solo
bit. Con estas instrucciones se puede poner a i o ponerse a 0 un bit cualquie-
ra de un registro o de una posición de memoria (sin alterar los demás bits),
y tambn se puede averiguar el estado de un bit determinado.
Cabe preguntarse si son verdaderamente necesarias estas instrucciones, ya
que todos esos resultados se pueden obtener mediante otras.
Por ejemplo, podemos trabajar con el bit 5 de A de la manera siguiente:
para poner a 1 el bit basta utilizar
OR %00100000
para poner a 0 el bit basta utilizar
AND %11011111
y, finalmente, la instrucción
AND %00100000
activará el indicador de cero si el bit es 0 y desactiva el indicador de cero
si el bit es 1.
Claro que todo esto supone que el bit con el que se trabaja es un bit del
acumulador. Si no es así, las cosas son un poco más costosas. Vamos a ver
que habría que hacer para poner a 0 el bit 5 de una posición de memoria que
representaremos, por ejemplo, por 'tb'. La secuencia de operaciones sería
la siguiente:
1) Guardar el contenido de A PUSH AF
2) Cargar el byte en A LD A,(tb)
3) Poner a 0 el bit 5 AND % 11011111
4) Devolver el byte a su posición LD (tb),A
5) Recuperar el contenido de A POP AF
Se requieren, pues, 10 bytes de programa para una operacn tan sencilla.
87
88 DIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
Este número se puede reducir algo si se utiliza HL como puntero de la mane-
ra siguiente:
PUSH AF
LD HL,tb
LD A,(HL)
AND %11011111
LD (HL),A
POP AF
Así se reduce el programa a 9 bytes, lo que no representa un gran ahorro .
Para comprobar cuál es el valor de un bit hay que variar el procedimiento,
ya que la operación se basa en el examen del indicador de 0 y, al emplear
POP AF, los indicadores recuperan el estado que tean antes del programa.
El almacenamiento de A se puede hacer en otra posición de memoria que
denotaremos por 'sb'. El programa para comprobar el valor del bit 5 de la
posición de memoria tb sería el siguiente:
LD (sb),A
LD HL,tb
LD A,(HL)
AND %00100000
LD A,(sb)
El programa ocupa 12 bytes.
El objeto de desarrollar estos programas, que van a ser completamente
inútiles, es demostrar la conveniencia de disponer de operaciones directas
para tales tareas.
Las instrucciones que sirven para poner a 1 y a 0 un bit tienen por digo
SET y RES respectivamente. El bit puede ser de un registro de uso general,
de A o de la posición de memoria apuntada por HL. Sus códigos binarios
son
ENSAMBLADOR B I N A R I O
SET b,r 11 001 011 11 b r
RES b,r 11 001 011 10 b r
donde r se debe sustituir por el código usual de 3 bits, o sea, 000 para
B,. . . ,110 para (HL) y 111 para A. También b debe ser sustituido por el nú-
mero del bit que se deba alterar, o sea, b puede ser desde 000 para el bit 0
(el menos significativo) hasta 111 para el bit 7 (el más significativo).
Obsérvese que las instrucciones que trabajan con un bit ocupan 2 bytes,
de los que el primero es siempre 11 001 011 (CBh).
INSTRUCCIONES QUE TRABAJAN CON UN SOLO BIT S9
Por ejemplo, las instrucciones para poner a 1 el bit 5 del registro B y para
poner a 0 el bit 3 de la posición de memoria apuntada por HL son
ENSAMB LADOR HEX B I N A R I O
SET 5,B CB E8 11 001 O H 11 101 000
RES 3,(HL) CB 9E 11 001 011 10 011 110
Las instrucciones SET y RES no afectan a ningún indicador.
La instrucción que sirve para comprobar cl es el estado de un bit tiene
por digo nemotécnico BIT, y su código binario es similar a los
precedentes:
ENSAMBLADOR BINARIO
BIT b, r 11 001 011 01 b r
Por ejemplo, la instrucción para comprobar el bit 2 del registro H es:
ENSAMBLADOR DECI MAL BINARI O
BIT 2,H C8 54 11 001 011 01 010 100
Pero, ¿de qué manera nos dice la instruccn BIT cuál es el valor del bit?
Nos lo dice mediante el indicador de cero. Al ejecutar la instrucción BIT,
el indicador de cero se pondrá a 1 si el bit vale 0, y se pondrá a 0 si el bit
vale 1. La instrucción BIT no afecta al indicador de arrastre, pero los otros
indicadores, aparte del de cero, pueden verse afectados de manera
imprevisible.
Uno de los campos en que son útiles las instrucciones que trabajan con
un bit es el de la codificación de informaciones; sobre todo cuando se trata
de información alternativa que puede darse con un 'si' o un 'no'. Represen-
tando 'si' por un 1 y 'no' por un 0, cada una de las informaciones ocupará
un bit. Así, por ejemplo, consideremos los siguientes datos alternativos so-
bre cada empleado de una fábrica (que ponemos también en inglés para ayu-
darle a comprender el programa que introduciremos más adelante):
1) Male/Female Hombre/Mujer
2) Married/Singl e Casado/Soltero
3) ChIldren/Childless Con nos/Sin nos
90 DIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
4) Driving licence/No driving
licence
5) Salaried/Hourly paid
6) Key holder/Not key holder
7) Security cleared/Not Security
cleared
Permiso de conducir/No
permiso
Salario/Por horas
Tiene llave/No tiene llave
Seguridad comprobada/Dudosa
seguridad
Todos estos datos se pueden almacenar en siete bits de un byte, dejando el
bit restante para indicar si el byte está o no en uso.
H i s o f t GENA3 A s s e m b l e r . P age 1.
Pas s 1 e r r o r s : 0 0
88B8
88B8
BB5A
881B
88B8
B8BB
8BBE
B 8C 1
88C3
B 8C 6
BBC?
8BCB
88CD
88CF
8 8 D 0
BBD2
BBD4
B8D7
88DA
8 8 DB
88DD
8 B E 0
88E1
8BE4
8 8 E 6
88E8
8 8 E 9
88EA
8 8 EB
88ED
88EF
BBF 1
88F3
88F4
2 1 4 3 8A
C D 5 6 8 9
C D 5 689
0 6 0 9
CDFBB8
CD6 3 89
F E 66
2 B4 E
3 E 01
77
0 6 0 7
0 E 02
C D 5 689
CDFBB8
C5
0 6 0A
CDF888
C1
C D 6 389
FE7 9
2 0 05
7E
B1
77
1B 0 6
FE6E
2 8 02
1BE1
79
B 7
10
20
30
40
5 0
60
7 0
80
9 0
100
1 10
120
130
140
150
160
170
1B 0
190
2 00
2 10
2 20
2 3 0
2 40
2 50
2 6 0
2 70
2 8 0
2 9 0
3 0 0
3 1 0
3 2 0
3 3 0
3 4 0
3 5 0
3 60
3 7 0
; FIG 10.1 - PROGRAMA QUE MUESTR A
; LAS DIFICULTADES DE MANEJAR
; REGISTROS CON OR Y AND
P R I NT
GETKEY
NXTREC
N X T B I T
NO
SLA
ORG
ENT
EQU
EQU
LD
C AL L
CALL
LD
CALL
CALL
CP
JR
LD
LD
LD
LD
CAL L
CALL
PUSH
LD
CAL L
POP
CAL L
CP
J R
LD
OR
LD
J R
CP
J R
JR
LD
ADD
3 5 0 0 0
3 5 0 0 0
4 7 9 6 2
4 7 8 9 6
H L , F R E E
CR L F
CRLF
B ,9
PR_MSG
K E Y IN
Z,LSTREC
A , # 1
( H L ) , A
B , 7
C , 2
CRL F
PR_MSG
BC
B, 10
PR_MSG
B C
K E Y IN
" y "
NZ,N O
A , ( H L )
C
( H L ) , A
SL A
" n "
Z , S L A
N X T B I T
A ,C
A , A
INSTRUCCIONES QUE TRABAJAN CON UN SOLO BI T 91
88F 5
88F6
88F8
88F9
88F B
88FE
8901
B903
B904
B906
8908
890 B
B90E
B90 F
8910
8912
B915
B91 7
B918
891 9
B91B
891E
8921
8924
B92 6
B929
892B
892C
B92F
B932
8935
8936
B937
B938
B939
893fl
B93B
B93E
893F
8941
8943
B946
B94B
894A
B94D
B94E
8951
8952
B954
B956
8957
B95 9
B95C
895 E
8961
4F
10DC
23
18C0
CD6C8 9
217689
CB7E
23
28FB
10F9
CD0F89
CD718 9
C9
7E
E67F
CD3AB B
C87E
C0
23
18F4
21438A
CD56B9
CD56B 9
060 8
CDFB8 8
0601
E5
CD56B 9
CD56B9
CD18B B
El
7E
23
A7
C8
87
CDFB88
F5
3007
3E59
CD5ABB
1B05
3E4E
CD5ABB
04
CD568 9
Fl
28D5
1BE4
F5
3E0D
CD5AB B
3E0 A
CD5ABB
Fl
380
390
400
410
420
430
440
450
460
470
48 0
490
50 0
510
52 0
530
540
550
56 0
570
58 0
590
60 0
610
620
630
640
650
660
670
680
690
70 0
710
720
730
740
750
760
770
7B0
790
800
810
B20
830
840
850
B60
B70
880
B90
900
910
920
PR_MSG
FNDMSG
NXTCHR
LSTRE C
PR_REC
P_ITEM
NOT
NXTITM
CRLF
LD
DJNZ
INC
JR
CALL
LD
BIT
INC
JR
DJNZ
CALL
CALL
RET
LD
AND
CALL
BIT
RET
INC
JR
LD
CALL
CALL
LD
CALL
LD
PUSH
CALL
CALL
CALL
POP
LD
INC
AND
RET
ADD
CAL L
PUSH
JR
LD
CALL
JR
LD
CALL
INC
CALL
POP
JR
JR
PUSH
LD
CALL
LD
CAL L
POP
C,fl
NXTBI T
HL
NXTRE C
SAVREG
HL,MSG T
7,<NL>
HL
Z,FNDMSG
FNDMS G
NXTCHR
RESRE G
A,(HL)
%011111
PRINT
7,(HL)
NZ
HL
NXTCHR
HL,FRE E
CRLF
CRLF
B,8
PR_MSG
B,1
HL
CRLF
CRLF
GETKE Y
HL
A,(HL)
HL
A
Z
A,A
P R _ MSG
AF
NC,NOT
A , " Y "
PRINT
N X T I T M
A , " N "
PRINT
B
CRLF
AF
Z,PR RE(
P_ITEM
AF
A,#0D
PRINT
A,#0A
PRINT
AF
92 CÓDIG O MÁQUIN A PARA PRINCIPIANTES CO N AMSTRAD
8962
8963
8966
8969
896B
B96C
8960
896E
896F
8970
8971
8972
B973
8974
8975
8976
8977
B9B8
8989
899A
899B
89AC
C9
CD188B
CD5ABB
F620
C9
E3
C5
F5
E5
C9
El
Fl
Cl
E3
C9
A0
53154355
A0
4B45592 0
A0
53414C41
A0
930
940
950
96 8
970
980
99?
1000
1010
1020
1030
1040
1050
1060
1070
1080
1090
1100
1110
1120
1130
1 140
KEYIN
SAVREG
RESRE G
MSGTBL
RET
CALL
CALL
OR
RET
EX
PUSH
PUSH
PUSH
POP
POP
POP
EX
RET
DEFB
DEFM
DEFB
DEFM
DEFB
DEFM
DEF B
GETKEY
PRINT
#20
(SP),HL
BC
AF
HL
AF
BC
(SP),HL
#A0
"SECURITY C
#A0
"KEY HOLDER
#A8
"SALARIED ?
#A0
H i s o f t GENA3 As sem bL er . Page
B9AD
89BE
89BF
B9D0
B9D1
89E 2
89E3
89F4
89F5
89F7
8A14
BAló
SA32
SA3B
BA3D
8A41
8A43
44E34956
A0
4620544F
A0
4D415252
A0
4D414C4 5
A0
0A0A
464F5220
0788
4620544F
20544A20
07A0
20592F4E
A0A0
0000
1150
1160
1170
1180
1190
1200
1210
1220
1230
1 24 0
1250
1 26 0
1270
1280
1290
1300
1310 FREE
DEFB
DEFB
DEFM
DEFB
DEFM
DEFB
DEFB
DEFM
DEFW
DEFM
DE FM
DEFW
DEFM
DEFW
DEFW
"DRIVING LICENCE ?"
#A0
"MARRIED ?
#A0
"MALE ?
" FOR N E X T R E CO RD P R E S S AN
# 8 8 07
"F TO FINIS H OR ANY OT HE R
" TO GO ON"
# A 0 0 7
" Y/N
#A0A0
#0000
Pas s 2 e r r o r s : 00
T ab le u s e d : 25 7 f r o m 32 7
Executes: 35000
Figura 10.1
INSTRUCCIONE S QUE TRABAJAN CON UN SOLO BIT 93
Para crear registros de este tipo pueden servir perfectamente las instruc-
ciones AND y OR. Pero con ellas es verdaderamente complicado cambiar
un bit específico de un registro que ya está lleno. Para estos aspectos es pre-
ferible emplear las instrucciones que alteran un bit.
El programa de la figura 10.1 le ayudará a comprender estas dificultades.
No le sugerimos que lo introduzca ahora, pero puede hacerlo si quiere para
ver qué ocurre. El programa se debe cargar con un ensamblador; si usted lo
carga utilizando el código hexadecimal, debe advertir que el código de los
mensajes (líneas 1080 y siguientes) no está completo en ninguno de ellos,
puesto que en el listado aparecen sólo los 4 primeros bytes de cada uno.
El programa carga registros con las siete características de las que hemos
hablado antes; usted tendrá que introducir los datos pulsando 'Y' para 'si1
y 'N' para 'no'. Mediante 'el mensaje 'F TO FINISH OR ANY OTHER
KEY TO GO ON' el programa le pedirá si desea que los registros ya carga-
dos se impriman en la pantalla (pulse 'F' para esta opcn) o si desea cargar
nuevos registros (pulse cualquier otra tecla). Cuando se imprimen los regis-
tros en la pantalla, la impresn se detiene en cada registro, y el mensaje
'FOR NEXT RECORD PRESS ANY KEY' le recuerda que debe pulsar una
tecla para pasar al siguiente.
Se utilizan muchas de las técnicas e instrucciones que ya hemos comenta-
do, y también algunos trucos. Trate de ver por qué aparece la letra 'Y' des-
pués del mensaje 'FOR NEXT .. .' de la línea 1240.
Para poner a 1 el bit correspondiente cuando la respuest a es 'Y', se emplea
la instrucción lógica OR C con un byte C que contiene un 1 en la posicn
correspondiente. Como la posición del 1 debe ir variando, la subrutina SLA
emplea la instrucción ADD A,A para multiplicar por 2 el byte precedente,
lo que equivale a desplazar el 1. El mismo artificio se emplea para poner a
1 el indicador de arrastre cuando, en la impresión de los registros, se llega
a una cuestión que ha sido respondida con 'Y'.
11
Rotaciones y desplazamientos
En las últimas consideraciones que hicimos en el catulo precedente acerca
del programa de la figura 10.1, vimos que, para desplazar hacia la izquierda
todos los bits de un byte, lo que hay que hacer es multiplicar por 2 el valor
del byte. En ese programa la multiplicación por 2se llevaba a cabo sumando
el byte consigo mismo. La sección del programa que se ocupab a de esta tarea
llevaba la etiqueta SLA; el prosito de esta etiqueta es hacer notar que la
subrutina en cuestión realiza el mismo trabajo que una de las instrucciones
que veremos ahora: la que realiza el desplazamiento aritmético a la izquierda
(o Shift Left Arithmetic), que se denota por SLA.
En resumen, si un número binario se suma consigo mismo o, lo que es
igual, se multiplica por 2, el efecto es desplazar el número una posición hacia
la izquierda. Este efecto de la multiplicacn no es específico del sistema bi-
nario (sí el de la suma). Si se multiplica un número escrito en un sistema de
numeración por la base del sistema, el efecto es desplazar el número a la iz-
quierda. Por ejemplo:
en binario 1010110b*10b = 10101100b (10b es 2 en decimal)
en decimal 1234567*10=12345670
en hexadecimal 789ABCDh*10h = 789ABCD0h (10h es 16 en decimal)
Volviendo al programa, se observa que el hecho de tener que utilizar cons-
tantemente el acumulador para desplazar un byte no es modo ni
conveniente.
Otr o de los problemas es no poder hacer lo mismo para provocar un des-
plazamiento a la derecha, pues de esa manera se podría presentar la informa-
ción en el mismo orden en que fue introducida. Lo que hace el programa
es utilizar el mismo procedimiento que antes para ir activando el indicador
de arrastre cada vez que un dato archivado es 1. Se podría modificar el pro-
grama de varias maneras para que imprimiese la información en el mismo
orden de introducción. Por ejemplo, desplazando el byte en A a continua-
ción de la instrucción OR en lugar de actuar sobre el registro C. Pero esto
traería nuevos problemas, puesto que el desplazamiento debea hacerse
95
96 DIGO QUINA PARA PRINCIPIANTES CON AMSTRAD
Figura 11.1
donde hay que sustituir r por el código de 3 bits que se emplea para los regis-
tros de uso general, A y (HL).
En algunas ocasiones no tiene ninguna importancia el hecho de que la ins-
trucción SLA expulse del byte el bit 7; pero otras veces, sobre todo en las
operaciones de multiplicación, este bit es fundamental, pues es el más signi-
ficativo. Afortunadamente, este bit se guarda en el indicador de arrastre ya
que se activará justamente cuando el bit 7 sea 1. En el programa de la figura
6.8 vimos cómo se recuperaba el arrastre en una suma, incorporándolo al
tambn en caso de respuesta negativa y, en ese caso, el program a se bifurca
antes de la instrucción OR.
Lo que parece en todo caso necesario es disponer de un conjunto de ins-
trucciones de desplazamiento, y esto no sólo por los inconvenientes que he-
mos señalado, sino también para poder realizar divisiones de una manera
sencilla.
Ya hemos dicho que, cuando un número se multiplica por la base del siste-
ma de numeración en que está escrito, se desplaza una posición hacia la iz-
quierda. Pero, ¿qué sucede cuando se lo divide por la base? En ese caso se
desplaza una posición hacia la derecha y la cifra de la derecha sale fuera (a
la zona de los números fraccionarios). En el caso de un byte, el mero de
la derecha debe desaparecer; veremos que se lo puede recuperar en el indica-
dor de arrastre.
El Z80 dispone de instrucciones par a desplazar un byte a la izquierda o
a la derecha. Comenzaremos por explicar el desplazamiento a la izquierda.
El desplazamiento a la izquierda tiene como digo SLA (ya hemos expli-
cado que proviene de Shift Left Arithmetic). Realiza la misma operación que
ADD A,A, pero puede utilizar, además de A, los registros de uso general
y (HL). Su código binario se compone de 2 bytes; el primero es el prefijo
CBh, que se emplea para los desplazamientos y las rotaciones, así como para
las instrucciones que trabajan con un bit, como hemos visto en el capítulo
anterior. El código completo es
ENSAMBLADOR HEX B I NA R I O
SLA r CB 20-27 11 001 011 00 100 r
ROTACIONES Y DESPLAZAMIENTOS 97
siguiente byte con ADC; es exactamente lo que hay que hacer cuando se su-
man números sin signo. Veamos qué técnica hay que emplear en la multipli-
cacn. Para multiplicar por 2 el contenido de A se puede utilizar el pro-
grama
MULT SLA A
LD (RESULT),A
LD A,(RESULT+1)
ADC A,A
LD (RESULT+1),A
RET
RESULT DEFW 0
Figura 11.2
El resultado de la multiplicación queda almacenado en las posiciones
RESULT y RESULT+1 , con el byte más significativo en RESULT+1, o
sea, en la forma habitual de almacenamiento de un número de 16 bits.
Si se usa repetidamente esta rutina, puede servir para multiplicar por una
potencia de 2. Por ejemplo:
LD A, 1
CALL MULT ; e n RESULT hay ahora 2
LD A, (RESULT)
CALL MULT ; en RESULT hay ahora 4
LD A , ( R E S U LT )
CALL MULT ; e n RESULT hay ah or a 8
Figura 11.3
y así sucesivamente. El programa funciona hasta que el resultado exceda
de 65535, o sea, hasta que se realicen 16 llamadas a la rutina; además, el in-
dicador de arrastre quedará entonces a 1. El programa no es bueno, ni mu-
cho menos, pero ilustra el empleo del desplazamiento a la izquierda para
98 DIGO MÁQUINA PARA PRINCIPIANTE S CON AMSTRA D
multiplicar. Cuando se va a multiplicar un mero negativo con esta técnica,
el byte más significativo de RESULT se debe cargar con 11111111b antes de
comenzar los lculos; si no, el resultado final sería positivo. No nos ocupa-
remos ahora de mejorar el programa, sino que pasaremos a explicar el des-
plazamiento a la derecha.
Ha y dos tipos de desplazamiento a la derecha, que reciben los calificativos
de lógico y arittico.
El desplazamiento lógico a la derecha (o Shift Right Lógical) tiene por ne-
mocnico SRL. A pesar de su nombre, es la instrucción que se corresponde
con el desplazamiento aritmético a la izquierda. Su código y un esquema de
su funcionamiento son los siguientes:
ENSA MB LADO R HEX B I N A R I O
SRL r CB 38- 40 11 001 011 00 111 r
Figura 11.4
El código es similar al de SLA, con dos bytes, el primero de los cuales es
CBh. En las instrucciones que veremos en este capítulo, lo que distingue una
de otra son los bits 5, 4 y 3 del segundo byte, ades, claro es, de los 3
bits que corresponden al digo del registro.
A primera vista, esta instrucción parece que puede servir para transformar
nuestra rutina de multiplicación en otra de división por 2; para ello bastaría
con reemplazar SLA por SRL e invertir el orden de las operaciones, a fin
de empezar por el byte más significativo. El problema fundamental es que
no hay manera de utilizar el bit de arrastre que se origine en el byte más sig-
nificativo para incorporarlo a la operación que se realice con el siguiente
byte. Esto nos hace restringir la rutina a enteros de 8 bits, como muestra la
figura 11.5.
Si al comienzo del programa A contiene el número 100 {64h 01100100b),
después de la ejecución la posición RESULT+1 almacenará 50(00110010b),
que es lo correcto. Si se divide un mero impar, el resto queda en el indi-
cador de arrastre. Así, si la rutina se emplea para 101 (65h 01100101b), el
resultado en RESULT+1 será 50 y el indicador de arrastre queda acti-
vado.
¿Qué sucede si se divide un número negativo (o sea, interpretado con sig-
ROTACIONES Y DESPLAZAMIENTOS 99
DIVD SRL A
LD (RESULT+1),A
RET
RESULT DEFW 00
Figura 11.5
no)? Si nuestra rutina se emplea para -26 (E6h 11100110b), el resultado en
RESULT+ 1 será 01110011b o 73h o 115 decimal, que es totalmente inco-
rrecto. Así pues, la instrucción SRL no puede ser interpretada como despla-
zamiento aritmético, y por eso ha recibido otro calificativo.
El desplazamiento aritmético a la derecha (Shift Right Arithmetic) o SRA,
lo que hace es preservar el bit de signo. Si en el ejemplo anterior sustituimos
SRL por SRA, el resultado de la última operacn será 11110011b o - 1 3 o
F3h, que es lo correcto. Los códigos y el esquema de funcionamiento para
esta instruccn son:
Figura 11.6
Ahora que conocemos los desplazamientos y, por lo tanto, la multiplica-
ción y la división por 2, vamos a tratar de aprender a multiplicar y dividir
por números diferentes de 2. Por el momento supondremos que todos los
números empleados caben en un byte: así la cosas serán mas simples y podre-
mos concentrarnos en comprender los principios de la multiplicacn y la di-
visn, antes de entrar en cálculos más pesados. Para lculos con números
sin signo, esta suposición obliga a que el resultado de las multiplicaciones
sea inferior a 256, y a que el dividendo y el divisor de las divisiones sean infe-
riores a 256.
Una multiplicacn se puede realizar simplemente mediante un proceso
que sume el multiplicando tantas veces como indique el multiplicador. Pue-
de comprobar esto utilizando el programa de la figura 11.7, que realiza la
multiplicacn de los códigos de las dos teclas que usted pulse en el teclado .
10 0 DIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
Hisoft GENA3 Assembler. Page 1.
Pas s 1 e r r o r s : 00
10 ; FIG 11.7
20 ; MULTIPLICACIÓN DE 8 POR 8
BITS CON RESULTADO DE 8 BITS,
30 ; METODO DE LA SUMA REPETIDA
A7F8
A7F8
8818
A7F8
A7FB
A7FC
A7FF
A800
A801
A802
AB04
A807
Pas s
CD1888
4F
CD1BBB
47
AF
81
10FD
3278AB
C3B4AA
2 errors:
40
50
60
70
80
90
100
110
120
130
140
150
00
GETKEY
ADLOOP
ORG
ENT
EQU
CALL
LD
CALL
LD
XOR
ADD
DJNZ
LD
JP
43000
43000
4789 6
GETKEY
C,A
GETKEY
B,A
A ;A S E PONE A 0
A,C
ADLOOP
(43896),A
43700
Table used: 72
Executes: 4300 0
221
Figura 11.7. Sumas de comprobación: 0506, 0483.
Este programa está preparado para ser añadido al programa de la figura
6.13, que servía para imprimir un número en forma decimal (observe la ins-
trucción JP 43700).
Ejecute el programa con CALL 43000 o con el comando R del ensambla-
dor. El programa queda esperando y, cuando usted pulse dos teclas, im-
primirá el resultado. La mayor parte de las teclas posee códigos demasiado
altos para que su producto quepa en un byte; pero puede obtener códigos
pequos pulsando caracteres de control, es decir, manteniendo pulsada la
tecla [CONTROL] y pulsando entonces otra tecla. Por ejemplo, el carácter
[CONTROL]G es el código 7 (y proporciona un pitido) y el caracter [CON-
TROL]J es el digo 10(0Ah); su producto da 70 como respuesta. En el
apéndice 3 de la Guia del usuario encontra los códigos generados por las
distintas teclas.
El método del programa de 11.7 trabaja perfectamente para las multipli-
caciones que debe hacer, pero es verdaderament e rudimentario; el bucle me-
diante el que repite la suma puede tener que realizarse hasta 127 veces. Para
operaciones de 16 bits podría tener que hacer hasta 32767 veces la operación
en el peor de los casos (cuando se realiza 2*32767 en este orden); incluso con
ROTACIONES Y DESPLAZAMIENTOS 101
el convenio de introducir primero el mayor número podría tener que repetir
256 veces la operación.
Existe un método que en principio es mejor. Es el método que se aprende
en la escuela, y consiste en desplazar y sumar los productos simples. Observe
mo es este método, tanto en binario como en decimal:
BINARIO
00010011
00001011 *
10011
1 0 0 1 1 0
0
1 0 0 1 10 00
11010001
DECIMAL
19d
11d
1 9
1 7
209
En binario es muy sencillo: por cada cifra del multiplicador se desplaza a la
izquierda el multiplicando ; el multiplicando se suma si la cifra era un 1 y no
se suma si era un 0. De esta manera se realizan a lo sumo tantas sumas como
Hisoft GENA3 Assembler. Page 1.
Pas s 1 errors:
10 ; FIG 11,8
20 ; MULTIPLICACION DE 8 POR 8 BIT S
CON RESULTADO DE 8 BITS , METODO
30 ; DE DESPLAZAMIENTO Y SUMA
A7 F B
A7 F8
BB18
A 7 F 8
A7 F B
A7FC
A7FF
A 8 00
A 8 01
AB03
AB05
A 8 06
A 80 B
A80A
A8 0D
CD18BB
4F
CD18BB
47
AF
CB38
3 0 0 1
81
CB2 1
2 0 F 7
3 2 7 8 AB
C3B4 A A
40
50
60
70
80
90
10 0
11 0
120
130
140
150
160
170
180
GETKEY
ADLOOP
NOADD
ORG
ENT
EQU
CALL
LO
CALL
LD
XOR
SRL
J R
ADD
SLA
J R
LD
J P
4 3 0 00
4 3 0 0 0
47896
GETKEY
C, A
GETKEY
B , A
A ; A SE PONE A
B
NC,NOADD
A , C
C
N Z , A D L O O P
( 4 3 8 9 6 ) , A
43700
Pass 2 errors:
Table used: 84 from 230
Executes : 4300 0
Figura 11.8. Sumas de comprobación: 0550, 0397, 02CC.
102 DIG O MÁQUINA PAR A PRINCIPIANTES CON AMSTRAD
cifras tiene el multiplicador, aunque se ahorra una suma cada vez que una
cifra es 0. tese que esta circunstancia, que es rara en el sistema decimal,
es frecuente en el caso binario, pues las cifras son solamente 0 y 1. Por lo
tanto , este método exige un máximo de 8 sumas para números de 8 bits, y
de 16 para números de 16 bits.
El programa de la figura 11.8 utiliza este método para multiplicar, y se
lo puede enlazar con el de 6.13 para imprimir el resultado. Después de los
pasos iniciales y de poner A a 0, se comprueba cuánto vale el bit menos signi-
ficativo del multiplicador. La comprobación se hace mediante el desplaza-
miento a la derecha SRL que coloca dicho bit en el indicador de arrastre.
Si el bit es 1, se suma el multiplicando y luego se desplaza a la izquierda (eti-
queta ADLOOP). Si el bit es 0, sólo se desplaza a la izquierda, sin sumar
(etiqueta NOADD). Se comprueba si quedan bits en el multiplicador y, de
ser así, el proceso se repite. Finalmente se enlaza con la rutina de impresn.
La división es análoga a la multiplicación pero con el inconveniente de que
se puede prolongar indefinidamente sin ser nunca exacta. Ocurre como en
el cálculo de Pi ( ), que no puede terminar nunca. De hecho, hay divisiones
muy sencillas que dan un resultado perdico sin fin. La solución es calcular
el cociente y el resto (el cociente es el número de veces que el divisor puede
restarse del dividendo sin que dé un resultado negativo).
Para usted debería ser ya familiar el programa de división similar al de la
figura 11.7. De hecho, hemos empleado una rutina de divisn de este tipo
en todos los programas que servían para imprimir un número en decimal.
El procedimiento consiste en restar el divisor del dividendo y repetir este pro-
ceso contando las veces que puede hacerse hasta que el resultado dé negati-
vo; entonces se recupera la última resta (se suma el divisor) y el mero que
se obtiene actúa como dividendo en la siguiente división.
Lo que ahorraba mucho trabajo en la multiplicación era la eficacia de la
instrucción SLA de desplazamiento arittico a la izquierda, que además
permitía trabajar con números de cualquier tamaño. Esto se debía a que di-
cha instruccn sacaba el bit de arrastre al indicador y a que el bit de arrastre
podría incorporarse al bit menos significativo del byt e siguiente. El proceso
mezclaba una instrucción SLA y otra ADC en la forma siguiente:
Figura 11.9
ROTACIONES Y DESPLAZAMIENTOS 103
Se tiene la suerte de que la instrucción ADC permite realizar un desplaza-
miento a la izquierda del bit de arrastre. Hay que pensar tambn en que to-
do esto se podría haber hecho mediante las instrucciones ADD HL,HL
o ADC HL,HL, simulando así un desplazamiento a la izquierda de 16
bits.
Si se desea una división más eficaz, realizada mediante desplazamientos
y restas en lugar de restas repetidas, son necesarias nuevas instrucciones de
desplazamiento que permitan incorporar el bit de arrastre al bit más signifi-
cativo. Naturalmente, hay muchas otras razones para justificar las nuevas
instrucciones de desplazamiento. .
El Z80 dispone de un amplio catálogo de instrucciones de desplazamiento
que permiten la incorporación del bit de arrastre independientemente de los
acumuladores (A para 8 bits y HL para 16). Todas estas instrucciones utili-
zan el indicador de arrastre, tanto para recibir el bit desplazado como para
proporcionar el bit que rellene la posición liberada. Unas toman el bit del
indicador de arrastre antes de introducir en él el bit desplazado. Otras colo-
can el bit desplazado en el indicador de arrastre, antes de introducir este in-
dicador en la posición liberada. Todas ellas efectúan una rotación, ya sea a
través del indicador de arrastre o incluyendo este indicador.
Figura 11.10
Todas las rotaciones comienzan por la letra R; luego llevan la letra L (de
left), que indica izquierda, o la letra R (de right), que indica derecha, para
señalar el sentido de la rotación. Se tienen así las instrucciones RL de rota-
ción izquierda y RR de rotación derecha cuyo efecto se puede observar en
la figura 11.10. Realizan una rotación de 9 bits; el bit desplazado pasa al in-
dicador de arrastre, y el indicador de arrastre previo ocupa el lugar liberado.
Otras rotaciones son un poco diferentes y se llaman circulares: son la rota-
104 CÓDIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
Figura 11.11
ción circular izquierda, o RLC, y la rotación circular derecha, o RRC. Su
efecto se puede observar en la figura 11.11. Realizan una rotación de 8 bits;
el bit desplazad o pasa a la posición liberada, pero queda una copia de este
bit en el indicador de arrastre.
El acumulador A posee, como los otros registros, estas cuatro rotaciones,
pero ades tiene otras específicas con la ventaja de que su digo ocupa
sólo un byte. Po r lo demás se comportan com o las anteriores salvo en cómo
afectan a los indicadores Z, S y P/V).
Los digos de todas estas rotaciones son:
ENSAMBLADOR
RL r
RLA
RR r
RRA
RLC r
RLCA
RRC r
RRCA
HEX
CB 1 0 -
17
CB 18 -
1F
CB 00 -
0 7
CB 08 -
0F
- 17
- 1F
- 07
- 0 F
BINARIO
11 0 0 1 0 11
11 0 0 1 0 11
1 1 0 0 1 0 11
11 0 0 1 0 1 1
00
0 0
00
00
0 0
00
0 0
00
0 1 0
0 1 0
01 1
0 11
0 0 0
0 00
0 0 1
0 01
r
111
r
111
r
1 11
r
1 11
Con este conjunto de instrucciones, la puerta a una división rápida queda
abierta. En las divisiones que realizábamos en los programas que imprimían
un número en decimal se jugaba con dos ventajas. En primer lugar, el co-
ciente nunca podría pasar de 9; por lo tanto no se empleaba demasiado tiem-
po en hacer las restas. Además, los divisores eran conocidos, pues eran siem-
ROTACIONES Y DESPLAZAMIENTOS
H i s o f t GENA3 A s se m bl e r . Page
Pass 1 e r r o r s :
A7F B
A7F 8
BB1G
BB5A
A7F8
A7F A
A7FD
AB00
A802
A804
A805
A806
A807
A809
A80C
AB0F
ABI 0
A813
A81 4
A816
A818
A81B
A81C
A81E
AB2 0
A821
A823
AB2 5
AB26
AB2 9
A82B
A82E
A830
A83 3
A834
A836
A838
A83B
A83C
A840
A844
A848
AB4C
Pass
Table
Execu
0604
2178AB
CD18BB
FE80
2001
AF
77
23
10F4
CDB4AA
213CA8
7E
CD5ABB
23
FE00
20F7
217BAB
AF
CB3E
0603
2B
CB1E
10FB
F5
CDB4A A
3E20
CD5AB B
3E52
CD5AB B
Fl
CE0 0
F630
CD5ABB
C9
2044697 6
69646564
2062792 0
74776F3D
200 0
2 errors:
10
20
30
40
50
60
70
80
90
100
110
120
130
140
150
160
170
180
190
200
2Í0
220
230
240
250
260
270
280
290
300
310
320
330
340
350
360
370
3B0
390
400
410
420
430
440
00
;FIG.
11.
12
- DIVISION
USANDO DESPLAZAMIENTO Y
GETKEY
PRINT
INLOOP
NOT_0
MSG_LP
DIV_L P
D_MSG
ORG
ENT
EQU
EQU
LD
LD
CAL L
CP
JR
XOR
LD
INC
DJNZ
CALL
LD
LD
CAL L
INC
CP
JR
LD
XOR
SRL
LD
DEC
RR
DJN Z
PUSH
CALL
LD
CALL
LD
CALL
POP
ADC
OR
CAL L
RET
DEFM
DEFM
DEFM
DEFM
DEFW
used: 134 from 306
tes: 43000
4300 0
43000
47896
47962
B ,
4
HL,43896
GETKE Y
#80
NZ.NOT_ 0
A
(HL),A
HL
INLOOP
43700
HL,D_MS G
A,(HL )
PRINT
HL
#00
NZ,MSG_LP
HL,43899
A
(HL)
B,3
HL
(HL)
DIV LP
AF
43700
A, 32
PRINT
A , " R "
PRINT
AF
A,0
#30
PRINT
" D
i
v "
"ided"
" by "
"two="
#002 0
POR 2
ROTACIO N
ura 11.12.
Sumas 046C,0499,0486, 041F, 057D, 0565, 0503, 0390, 01B7.
106 DIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
pre los mismos. Cuando se realiza una rutina de división para números cua-
lesquiera, es esencial asegurarse de que no se va a producir ningún intento
de dividir por 0. Si no se toma esta precaucn, una división por 0 nunca
puede concluir, ya que el resultado es infinito.
Existen muchas formas de comprobar que el divisor no es 0. Para 8 bits,
se puede cargar el divisor en A y efectuar un AND A. Para 16 bits se puede
cargar un byte del divisor en A y efectuar un OR con el otro byte. Ambos
todos activarán el indicador de cero si el divisor es 0.
Ahora podemos realizar la división por 2 de un número del tamaño que
queramos. Habrá que usar SRL o SRA (según que el mero sea sin signo
o con signo) en el byte más significativo, seguido de RR en cada uno de los
siguientes bytes. Esto es lo que hemos hecho en el programa de la figura
11.12, preparado para utilizar también la rutina de impresión de 6.13.
Para permitirle que introduzca el dividendo, la rutina de entrada capta el
código ASCII de la tecla que se pulse y lo interpreta como un byte de un nú-
mero de 32 bits. Hay que pulsar, pues, 4 teclas. La primera se interpreta co-
mo el byte menos significativo y las siguientes van aumentando en significa-
ción. Existe un problema: el código ASCII 0 (NUL) no puede ser introduci-
do desde el teclado del Amstrad; lo hemos solucionado haciendo que se ob-
tenga el digo 0 cuando usted pulse la tecla '0' del teclado numérico. Puede
usted objetar que su Ga del usuario afirma que el código 0 se obtiene con
[CONTROL]A ; pero debe observar que, según la misma Guía, se obtienen
dos digos diferentes con [CONTROL]C. Lo que ocurre de hecho es que
[CONTROL]A corresponde al código 1, [CONTROL]B al 2, [CONTROL]C
al 3 y, a partir de ahí, todo sigue como dice la Ga.
El indicador de arrastre es fundamental, porque almacena los restos que
se van produciendo. Pero no es necesario preservar los indicadores antes de
ejecutar la instrucción DJNZ DIV_LP, ya que no les afecta para nada. Sin
embargo, al terminar la división, sí es necesario almacenar hasta después el
acumulador A (cargado con 0 y listo para la instrucción ADC posterior) y
los indicadores (el de arrastre, con el resto que se imprimirá al final).
Experimente con este programa hasta que esté seguro de comprender bien
mo se realiza la división mediante desplazamientos y rotaciones.
El programa de la figura 11.13 es el equivalente para la división del pro-
grama de la figura 11.8. Tambn utiliza la rutina de impresión de 6.13.
El program a realiza, como el de 11.8, una pasada de bucle por cada cifra
binaria del divisor. El dividendo se carga en el registro E y el divisor en el
C; el registro B es el contador, y se lo actualiza con la instrucción DJNZ.
En cada pasada del bucle, las rotaciones depositan en la posición menos sig-
nificativa de E (el dividendo) el bit de arrastre anterior, mientras que el bit
s significativo de E pasa al indicador de arrastre y de ahí a la posicn
menos significativa de A. Al principio, el indicador de arrastre está a 0 a
ROTACIONES Y DESPLAZAMIENTOS 107
H i s oft G E N A 3 A s s e m b l e r. P a ge 1 .
Pass 1 e r r o r s :
DIVISION USANDO DESPLAZAMIENT O
A7F8
A7FB
BB1B
BB5A
A7F8
A7FB
A7F E
A801
A804
A805
Asea
A80B
A80 E
A80F
A812
A815
A81 6
A818
A81A
A81 B
A81C
A81E
A81F
A821
A822
A823
A824
A825
AB2 8
A82 B
A82 E
AB2F
A832
A833
A834
A835
AB36
AB3 9
A83 C
A83D
A83 E
A83F
AB40
A843
A844
A84 7
A848
A84 9
AB4A
A84B
A84 C
210000
2278AB
227AAB
CD40AB
5F
--2156A8
CD4CA8
CD40A8
4F
2164A8
CD4CAB
AF
0608
C81 3
17
91
3001
81
10F7
47
7B
17
2F
CD33A 8
216BA8
CD4CA8
78
CD33A8
C9
E5
D5
C5
3278AB
CDB4AA
Cl
D1
El
C9
CD18BB
F5
CD33A 8
Fl
A7
ce
El
C9
7E
10
20
30
40
50
60
70
80
90
100
110
120
130
140
150
160
170
180
190
200
210
220
230
240
250
260
270
280
290
300
310
320
330
340
350
360
370
3B0
390
400
410
420
430
44C
450
460
470
480
490
500
510
520
; y ROTACION
GETKEY
PRINT
DIV_LP
NO_AD D
P_NUMB
GETVAL
MSG_LP
ORG
ENT
EQU
EQU
LD
LD
LD
CALI-
LO
LD
CALL
CALL
LD
LD
CALL
XOR
LD
RL
RLA
SUB
JR
ADD
DJNZ
LD
LD
RLA
CPL
CALL
LD
CAL L
LD
CAL L
RET
PUSH
PUSH
PUSH
LD
CALL
POP
POP
POP
RET
CALL
PUS H
CALL
POP
AND
RET
POP
RET
LD
43000
4300 0
47896
4796 2
HL,0
(43896),H L
(43898),HL
GETVA L
E,
A
HL,D_MSG
MSG_L P
GETVA L
C, A
HL,MSG2
MSG_L P
A
B,8
E
C
NC,NO_AD D
A,C
DIV_L P
B,
A
A,E
P_NUMB
HL,MSG3
MSG_LP
A,B
P_NUMB
HL
DE
BC
(43896),A
43700
BC
DE
HL
GETKEY
AF
P_NUMB
AF
A
NZ
HL
A,(HL)
108 CÓDIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
AB4D
A 8 50
A 8 5 1
A 8 53
A 8 5 5
A 8 56
A 85 A
AB5E
AB 62
A8 6 4
A 8 66
A8 6 B
AB6 A
CD5ABB
2 3
F E 00
2 0 F 7
C9
20446976
69646561
20627920
2000
3D 0 D
0 A 00
2 0 5 2
2000
5 3 6
5 46
5 5 0
5 60
5 7 0
5 80
5 9 0
600
6 1 0
620
6 3 0
6 4 0
6 5 0
D_MS G
MSG2
MSG3
CALL
INC
CP
J R
RET
DEF M
DEFM
DEFM
DEFW
DEFW
DEFW
DEFW
DEFW
PRINT
HL
#00
NZ,MSG_LP
" D i v "
" i d e d "
" by "
# 0 0 20
#0D3 D
#000A
# 3 2 2 0
#0020
Figura 11.13. Sumas: 037A, 04F4, 04D4, 0256, 0430, 0637, 06AC, 06B8,
0692, 03F0, 024E, 009C
consecuencia de la instrucción XOR A, que se emplea para poner A a 0. Tras
las rotaciones, se hace un intento de restar el divisor de A. Si se produce
arrastre, lo que significa que la resta es imposible, se restituye a A su valor
original sumando el divisor.
Como ocur a con la multiplicacn, se emplea también aquí el procedi-
miento de división que se aprende en la escuela para las divisiones largas.
En la figura 11.14 se puede ver cómo es este proceso en el caso de la división
de 85 por 2. Los bits de arrastre que salen o entran en los registros se indican
con flechas.
( 1
DIV_LP
NO_ADD
(2
DIV_LP
NO_ADD
)RL
RLA
SUB
JR
ADD
DJNZ
)
RL
RLA
SUB
JR
ADD
DJNZ
(3)
DIV_LP
NO_ADD
RL
RLA
SUB
JR
DJNZ
( 4 )
E
C
NC,NO_ADD
A, C
DIV_LP
E
C
NC,NO_ADD
A,C
DIV_LP
E
C
NC,NO_ADD
DIV_LP
0101010 1
0<- 1010 1 010 < - 0
1<-01010101<-1
0<-10101011<-1
00000000
0000000 0
0<-00000000<-0
1<-11111110
1<-00000000
0<-00000001<-1
1<-11111101
1<-00000001
0<-0 0 000 0 1 0<-0
0<-00000000
ROTACIONES Y DESPLAZAMIENTOS 109
DIV_L P RL E 1<-01010110<-0
RLA 0<-00000001<-1
SUB C 1<-11111101
JR NC,N0_ñDD
ADD ñ,C 1<-00000001
NO_ADD DJNZ DIV_LP
( 5 )
DIV_LP RL E 0<-10101101<-1l
RLA 0<-00000010<-0
SUB C 0<-00000000
JR NC,NO_ADD
N0_ADD DJNZ DIV_LP
(6)
DIV_LP RL E 1<-01011010<-0
RLA 0<-00000001<-1
SUB c 1<-11111101
JR NC,NO_ADD
ADD A, C 1<- 00 0000 0 1
NO_ADD DJNZ DIV_LP
(
7
)
DIV_LP RL E 0<-10110101<-1
RLA 0<-00000010<-0
SUB C 0<- 000000 0 0
JR NC,NO_ADD
N0_ADD DJNZ DIV_LP
(8)
DIV _LF RL E 1<-01101010<- 0
RLA 0<-00000001<-1
SUB C 1<-11111101
JR NC,NO_ADD
ADD A, C 1<-00000001
NO_ADD DJNZ DIV_LP
LD B,A & es ahora (0000000)
LD A,E 01101010
RLA 0<-11010100<-1
CPL 00101010
Figura 11.14
Conviene que vuelva una y otra vez sobre este proceso hasta que lo entien-
da perfectamente. Se conoce este método de división como método de res-
tauración (restoring), puesto que restaura el contenido previo a la resta
cuando se produce arrastre. Hay otros métodos de división, pero quedan
fuera del propósito del libro. El que hemos visto es eficaz y se adapta fácil-
mente para números de más de un byte, por lo que permite realizar cualquier
división.
Existe otra forma interesante de utilizar las rotaciones y los desplazamien-
tos. Introduzca el programa de la figura 11.15 y, tras haberlo grabado en
cinta, pong a el Amstrad e n modo 2 (si se es utilizando el ensamblador, el
comando W permite hacerlo) y llene la pantalla con muchos caracteres, por
110 DIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
ejemplo, listando el CARGADOR HEX o provocando mensajes de error.
Ejecute entonces el programa . Observará que el contenido de la pantalla
se desplaza a la derecha un punto (pixel) cada vez, hasta un total de un carác-
ter. Cambie la instrucción RR por alguna otra de las instrucciones vistas en
este capítulo y trate de predecir el resultado. Note que el registro de estado
se preserva cuidadosamente. ¿Qué ocurrirá si se suprimen las instrucciones
PUSH y POP? Compruébelo. Ensaye tambn con los otros modos y verá
mo se producen efectos curiosos.
H i s o f t GENA3 A s s e m bl e r . Paqe 1 .
Pass 1 e r r o r s : 0 0
A7F8
A7F8
A7F8
A7FA
A7FB
A7FE
A7FF
A801
A802
A803
AB04
A805
A807
A809
A80A
Pas s
Table
Execu
0608
F5
2100C0
Fl
CB1E
F5
23
7D
B4
20F7
10F 2
Fl
C9
2 errors :
used ;
10
20
30
40
50
60
70
80
90
100
110
120
130
140
150
160
170
00
; FIG.
11.
15
DERECHA DE
SCREEN
PIXEL
ORG
ENT
LD
PUS H
LD
POP
RR
PUS H
INC
LD
OR
JR
DJNZ
POP
RET
38 from 143
tes: 43000
-DESPLAZAMIENTO A LA
LA PANTALL A
43000
43000
B,8
AF
HL,#C000
AF
(HL)
AF
HL
A,L
H
NZ,PIXEL
SCREEN
AF
Figura 11.15. Sumas de comprobacn: 04B3, 0527.
La figura 11.16 proporciona el programa análogo para el desplazamiento
a la izquierda. Observe los cambios que hemos realizado.
Con la ayuda del mapa de pantalla del andice F, aprender á a realizar
programas que desplacen solamente ciertos trozos de la pantalla. Los dos
programas que hemos visto pueden parecer lentos, pero, si tiene en cuenta
que cada desplazamiento en un punto (pixel) lleva 16384 rotaciones y casi
132000 instrucciones, apreciará la velocidad a la que se realiza.
Existen, aún otras dos instrucciones de rotación, que podrá ver si lo desea
en el apéndice A. Se denominan rotaciones decimales. Quedan fuera del pro-
ROTACIONES Y DESPLAZAMIENTOS 111
H i s o f t GENA3 A s s e m b l e r . Page 1
P a s s 1 e r r o r s : 00
A7FB
A7FB
A7F B
A7FA
A7F B
A7FE
A7F F
A 8 0 1
A802
A803
A804
A805
A807
A808
A80A
A80C
A80E
A80 F
0 6 0 8
F5
2 1 F F F F
F1
CB16
F 5
2B
7D
A7
2 0 F 7
7C
FEC0
2 0 F2
10 E D
F l
C9
10
20
30
40
50
60
7 0
80
90
10 0
1 1 0
12 0
13 0
14 0
1 50
16 0
17 0
1 8 0
19 0
2 0 0
¡ DESPLAZAMIENTO A LA
IZQUIERDA DE LA PANTALLA
SCREE N
P I X EL
ORG
ENT
LD
PUS H
LD
POP
RL
PUSH
DEC
LD
AND
JR
LD
CP
J R
DJNZ
POP
RET
43000
43000
B, B
A F
H L , # F F FF
AF
( H L )
AF
HL
A , L
A
N Z , P I X E L
A ,H
#C0
N Z , P I X E L
SCREEN
A F
Pass 2 errors:
Table used: 38 from
Executes: 43000
141
Figura 1.1.16. Sumas de comprobación: 05E9, 05B2, 02B7.
sito de este libro y lo normal es que no tenga necesidad de utilizarlas, salvo
para algún trabajo de pantalla. Están pensadas para utilizar con meros
decimales codificados en binario, que se utilizan en sistemas antiguos como,
por ejemplo, las pantallas de los relojes digitales. El sistema de codificación
binaria de los números decimales (Binary Coded Decima! oBCD) utiliza un
digo de 4 bits para las cifras del 0 al 9. De esta manera sólo los números
comprendidos entre 0 y 99 pueden ser codificados en un byte, mientras en
la forma hexadecimal habitual se puede representar de 0 a 255. Si está intere-
sado en estas instrucciones, lo mejor es que asimile primero los conceptos
de este libro y luego pase a leer libros como el de R. Zaks 'Programming the
Z80' SYBEX (ISBN 0 89588 069 5).
1 1 2 CÓDIG O QUIN A PAR A PRINCIPIANTES CON AMSTRAD
Resumen
Vamos a resumir las instrucciones explicadas en este capítulo. Utilizaremos
los símbolos:
r = cualquiera de los registros de 8 bits (A, B, C, D, E, H o L)
m = cualquiera de los r y (HL)
rr = cualquier par de registros que se utilicen como uno de 16 bits
n =un número de 8 bits, o sea, entre 0 y 255
nn =un número de 16 bits, o sea, entre 0 y 65535
( ) rodeando un número o un par de registros = el contenido de la
dirección.
PC = contador de programa
SP = puntero de pila
Los desplazamientos y rotaciones pueden usar cualquier m.
Existen códigos especiales de 1 byte para las rotaciones del registro A. Es-
tas rotaciones especiales sólo afectan al indicador de paridad.
Todas las otras rotaciones y desplazamientos afectan a todos los indicado-
res, en el sentido que corresponda al valor almacenado en m tras la
operación.
El indicador P/V tiene el sentido de indicador de paridad.
Las rotaciones decimales no afectan al indicador de arrastre.
En la división de un número con signo se debe conservar el signo utilizan-
do la instrucción SRA.
Las rotaciones circulares no recogen el contenido que hubiera en el indica-
dor de arrastre antes de la operación.
Los movimientos a la derecha dividen por 2.
Los movimientos a la izquierda multiplican por 2.
12
Búsquedas y transferencias automáticas
Algunas instrucciones del Z80 ejercen, al ser ejecutadas, cierto control sobre
su propio efecto; por ello vamos a denominarlas "instrucciones automáti-
cas". Ya hemos visto una de ellas en capítulo s anteriores; se trata de la ins-
trucción DJNZ. Esta instrucción efectúa un salto condicionado a un NZ, pe-
ro al mismo tiempo se encarga de actualizar su contador, que es el registro B.
De las restantes instrucciones que poseen este cacter automático, unas
sirven para realizar búsquedas o transferir ciatos; son las que estudiaremos
en este capítulo. Las otras realizan las entradas y salidas de la información,
que es un tema que abordaremos en el catulo siguiente.
Supongamos que hay que almacenar el contenido de un área de la memo-
ria en otro área. Hay muchas ocasiones en que esto es necesario; por ejem-
plo, para crear huecos en una serie de registros de una base de datos, para
guardar el contenido de una pantalla o incluso para mover la pantalla de ma-
nera similar a como hemos hecho en las figuras 11.15 y 11.16, etc. Si el blo-
que de memoria que hay que mover es de tamaño conocido, el programa se-
rá más o menos como el de la figura 12.1.
La secuencia EX DE,HL LD (HL),A EX DE,HL es puramente gratuita
y se puede sustituir por LD (DE),A que hace lo mismo; la hemos incluido
para mostrar cómo se utilizan las instrucciones EX. Si no conviene utilizar
el registro A y hay que transferir menos de 257 bytes, se puede reescribir el
programa para que utilice el registro B y controle el bucle con la instruccn
DJNZ.
Como contador se usa el par BC (que se puede recordar como Binary
Counter o contador binario) y DE contiene la dirección de destino (DE re-
cuerda DEstino) del byte. HL desempa su papel tradicional de puntero,
en este caso de la dirección de origen.
El programa de 12.1 funcionará correctamente siempre que la dirección
de destino del bloque sea inferior a la de origen del bloque. En caso contra-
rio puede no dar el resultado apetecido. Por ejemplo, si el programa se com-
pleta haciendo
ORIGIN EQU #C000
DEST EQU #C100
COUNT EQU #3EFF
113
114 CÓDIGO MÁQUIN A PARA PRINCIPIANTES CON AMSTRAD
(con el CARGADOR HEX se completará convenientemente el código de las
neas 60, 70 y 80 y se utilizarán las sumas de comprobación 036F 04CC
00C9) el resultado será la repeticn varias veces del mismo trozo de la pan-
talla, que no era lo que se pretendía. La transferencia se hace en la forma
deseada para las primeras FFh posiciones, pero luego se repite constante-
mente este mismo trozo, ya que las posiciones de origen habrán sido altera-
das antes de la transferencia.
H i s o f t GENA3 A s s e m b l e r . Pa g e 1 .
Pass 1 e r r o r s ; 00
4 E 20
4E 2 0
0 0 0 0
0 0 0 0
0 0 0 0
4 E 2 0
4 E 23
4E 2 6
4 E 29
4E2 A
4E2 B
4E2 C
4E2D
4 E2 E
4E2F
4 E 3 0
4 E 31
4E 3 2
4 E 34
P a s s
Tab l e
E x e c u
2 1 0 0 0 0
1 1 0 0 0 0
0 1 0 0 0 0
7E
EB
77
EB
2 3
13
0B
78
B1
2 0 F 5
C9
2 e r r o r s :
u s e d :
t e s : 2 0 0 0 0
1
10
20
30
40
50
60
70
80
90
100
110
120
130
140
150
160
170
180
190
00
; F I G . 1 2 . i -
EN SENTIDO
ORG
ENT
O R I G I N EQU
DEST
COUNT
LOOP
60 from
EQU
EQU
LD
LD
LD
LD
EX
LD
EX
INC
INC
DEC
LD
OR
JR
RET
147
- TRANSFERENCIA DE BLOQUES
CRECIENTE
2 0 0 0 0
2 0 0 0 0
# ? ? ? ?
# ? ? ? ?
# ? ? ??
H L , O R I G I N
DE ,D ES T
BC,COÜN T
A , ( H L )
D E , H L
( H L ) ,A
D E , HL
HL
DE
BC
A , B
C
N Z , L O O P
Figura 12.1
Vamos a comentar esto con ayuda de un ejemplo elemental. Si para reme-
diar el error de la frase
Hacer una transferncia
realizamos la lógica transferencia de letras hacia adelante, que deje sitio para
intercalar la 'e', con origen nn+18, destino nn+19 y contador 4 (nn es la po-
sición de H), lo que obtendremos tras cada una de las pasadas del bucle se
BÚSQUEDAS Y TRANSFERENCIAS AUTOTICAS 115
Hacer una transfernnia
Hacer una transfernnna
Hacer una transfernnnn
Hacer una transfernnnnn
lo que empeora la situación.
Antes de ver cómo se pueden solucionar estos problemas, vamos a intro-
ducir la primera instrucción de transferencia automática de bloques. Ella so-
la puede reemplazar todas las instrucciones que figuran entre las lineas 90 a
180, ambas inclusive, del programa precedente. Es la instrucción LDIR (de
LoaDing Incrementing Repeating, o sea, carga incremento repeticn) y su
funcionamiento ha quedado explicado al decir qué instrucciones reemplaza en
12.1, Sus códigos son
ENSAMBLADOR HEX B I N A R I O
LDIR ED B0 11 101 101 10 110 000
Hisoft GENA3 Assembler. Page 1.
Pass 1 errors: 0 0
1 ; FIG. 12.2 - TRANSFERENCIA DE BLOQUES
EN SENTIDO DECRECIENTE
4E20
4E20
FEFF
FFFF
3EFF
4E20
4E23
4E26
4E29
4E2A
4E2B
4E2C
4E2D
4E2E
4E2F
4E30
4E31
4E32
4E34
Pass
Table
Execu
21FFFE
11FFFF
01FF3E
7E
EB
77
EB
2B
1B
0B
78
Bl
20F5
C9
2 errors:
used:
te
20
30
40
50
60
70
B0
90
100
1 10
120
130
140
150
160
170
180
190
00
0RIG1N
DEST
COUNT
LOOP
ORG
ENT
EQU
EQU
EQU
LD
LD
LD
LD
EX
LD
EX
DEC
DEC
DEC
LD
OR
JR
RET
60 from 147
tes: 20000
20000
20000
#FEFF
#FFFF
#3EFF
HL,ORIGIN
DE,DEST
BC,COUNT
A,(HL)
DE,HL
(HL), A
DE,
HL
HL
DE
BC
A, B
C
NZ,LOOP
Figura 12.2.
116 DIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
Cuando la dirección de destino del bloque es superior a la de origen, hay
que sustituir el programa de 12.1 por el de la figura 12.2, que realiza la trans-
ferencia en orden inverso, o sea, empezando por la dirección más alta del
bloque (tanto en origen como en destino).
La instrucción que reemplaza las que figuran en 12.2 entre las líneas 90
a 180 es ahora LDDR (de LoaDing Decrementing Repeating, o sea, carga
disminución repetición). Sus códigos son
ENS AMB LADOR HEX B I N A R I O
LDDR ED B8 11 101 101 10 111 000
Aunque las instrucciones LD1R y LDDR pueden servir para realizar las
mismas funciones, no operan de la misma manera. LDIR desplaza un blo-
que comenzando por las direcciones bajas de origen y destino; necesita que
HL y DE estén cargados al comienzo con las direcciones bajas del bloque
de origen y el bloque de destino respectivamente. Conviene emplear LDIR
cuando la direccn de destino es más baja que la de origen. LDDR desplaza
un bloque comenzando por las direcciones altas de origen y destino; necesita
que HL y DE estén cargados al comienzo con las direcciones altas del bloque
de origen y el bloque de destino respectivamente. Conviene emplear LDDR
cuando la dirección de destino es s alta que la de origen.
Bastantes cosas son comunes a LDIR y LDDR. No utilizan el registro A
Hisoft GENA3 A s s e m b le r . Page 1.
Pass 1 e r r o r s : 00
4E20
4E20
FFF F
FFF E
3FFF
4E20
4E23
4E2 6
4E29
4E2 B
Pass
Table
Execu
21FFFF
11FEFF
01FF3F
EDB8
C9
2 errors :
used;
00
49
tes: 2000 0
1
10
20
30
40
50
60
70
90
90
100
;FIG.
ORIGIN
DEST
COUNT
12.3 -
ORG
ENT
EQU
EQU
EQU
LD
LD
LD
LDDR
RET
from 132
LLENADO DE PANTALLA
2000 0
20000
#FFFF
«FFFE
#3FFF
HL,ORIGIN
DE,DEST
BC,COUNT
Figura 12.3. Sumas de comprobación: 0659, 0181.
BÚSQUEDAS y TRANSFERENCIAS AUTOMÁTICAS 117
en la transferencia. Utilizan el par BC como contador del número de bytes
del bloque, y disminuyen su valor después de cada transferencia de un byte.
Para comprobar si BC es cero (en cuyo caso se detiene la transferencia), no
utilizan el indicador de cero, sino P/V; este indicador queda siempre a 0 al
final de la instrucción. Estas instrucciones no afectan a los restantes indica-
dores accesibles.
Estas dos instrucciones pueden servir también para rellenar un área de me-
mori a con un mismo byte; para ello se emplea de manera deliberada la técni-
ca de 'sobrecopiado' desplazando el bloque 1 byte. Cada byte de destino se
vuelve así byte de origen del siguiente traslado. El programa 12.3 da un
ejemplo del empleo de esta técnica para rellenar la pantalla con un mismo
cacter (el que hubiese en la posición FFFFh de memoria); en 9.2 hicimos
algo parecido con otra técnica.
En los ejemplos anteriores se desplazaban bloques de longitud conocida,
pero en muchas ocasiones lo que interesa es transferir bytes en tanto no se
encuentre el límite deseado. El programa de la figura 12.4 realiza esta tarea
Hisof t GENA3 Assembler. Paqe 1.
Pass 1 errors: 00
4E20
4E2 0
FFF F
FFFE
3FF F
4E20
4E2 3
4E2¿
4E2 9
4E2A
4E2 B
4E2C
4E2 D
4E2E
4E2F
4E30
4E32
4E33
4E34
4E36
Pas s
Table
Execu
21FFFF
11FEFF
01FF3F
7E
12
2B
1B
0B
78
Bl
2804
AF
BE
20F3
C9
2errors:
used:
1
10
20
30
40
50
60
70
80
90
100
110
120
130
140
150
160
170
180
190
200
00
; TRANSFERIR
ORIGIN
DEST
COUNT
LOOP
LIMIT
ORG
ENT
EQU
EQU
EQU
LD
LD
LD
LD
LD
DEC
DEC
DEC
LD
OR
JR
XOR
CP
JR
RET
72 from 147
tes : 20000
HASTA ENCONTRAR UN0
20000
20000
#FFFF
#FFFE
#3FFF
HL,ORIGIN
DE,DEST
BC,COUNT
A,(HL)
(DE),A
HL
DE
BC
A,B
C
Z,LIMIT
A
(HL )
NZ,LOOP
118 DIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
y el final se alcanza cuando se encuentra un byt e 0. No obstante, se emplea
BC para colocar un límite a la cantidad xima de memoria que puede ser
transferida. Si no se tomase esta precaución, podría suceder que la transfe-
rencia no terminase nunca; o, lo que es peor, que el programa escribiera en-
cima de sí mismo, con la consecuencia que no es necesario describir.
Para esta finalidad, el Z80 dispone de dos instrucciones que son como
LDDR y LDIR pero sin la repetición autotica; son las instrucciones LDD
y LDI , como era fácil imaginar. Sus códigos son
ASEEMBLER HEX BINARY
LDD ED A 8 11 101 101 le 101 000
LDI ED A0 11 101 101 10 100 00 0
No es tan simple como parece a primera vista modificar el programa de
12.4 para incluir la instrucción LDD, ya que ahora hay que utilizar el indica-
dor P/V para detectar que el par BC ha llegado a 0, mientras que el progra-
ma original utilizaba el indicador de cero. La instrucción LDD pone a 0 el
indicador P/V (o sea, en PO) cuando BC se hace 0. Como un salto relativo
Hisoft GENA3 Assembler. Page 1.
Pass 1 errors : 00
4E20
4E20
FFF F
FFFE
3FF F
4E20
4E23
4E2 6
4E29
4E2B
4E2E
4E2F
4E30
4E32
Pass
Table
Execu
21FFFF
11FEFF
01FF3F
EDA8
E2324E
AF
BE
20F7
C9
2 errors:
used:
1
10
20
30
40
50
60
70
80
90
171
173
174
180
190
00
; TRANSFERIR
oRIGIN
DEST
COUNT
LOOP
LIMIT
ORG
ENT
EQU
EQU
EQU
LD
LD
LD
LDD
JP
XOR
CP
JR
RET
72 from 141
tes: 20000
HASTAENCONTRAR UN0
20000
20000
#FFFF
«FFFE
#3FFF
HL,ORIGIN
DE,DEST
BC,COUNT
PO,LIMIT
A
(HL)
NZ,LOOP
Figura 12.5
BÚSQUEDAS Y TRANSFERENCIAS AUTOTICAS 119
no se puede condicionar con P/V, hay que sustituir JR por JP. Tras los cam-
bios, el programa queda según se muestra en la figura 12.5.
Las siguientes instrucciones automáticas, que son las últimas que veremos
en este capítulo, son las de búsqueda en bloques. Sus códigos son semejantes
a los de transferencia de bloques pero, como indica su nombre, lo que hacen
es buscar un byte con determinado valor en un bloque de memoria. Para se-
guir el mismo proceso que antes, damos en la figura 12.6 un programa (sin
emplear estas instrucciones) que busca un byte con el valor 65 (el código de
'A' ) a partir de la posición FFFFh y a través de 3FFFh bytes recorridos en
sentido decreciente.
Hisoft GENA3 Assembler. Page 1.
Pass 1 errors : 00
10 ; BUSQUEDA DE UN BLOQUE
4E20
4E20
FFFF
3FFF
4E20
4E23
4E26
4E28
4E29
4E2A
4E2B
4E2 D
4E2E
4E2F
4E30
4E31
4E33
4E3 4
Pas s
Table
Execu
21FFFF
01FF3F
3E41
BE
2B
0B
2807
57
78
Bl
7A
20F5
3F
C9
2 errors:
used:
20
30
40
50
60
70
80
90
100
1 10
120
130
140
158
160
170
180
190
00
STAR T
COUNT
LOOP
DONE
59 from
tes: 20000
ORG
ENT
EQU
EQU
LD
LD
LD
CP
DEC
DEC
JR
LD
LD
OR
LD
JR
CCF
RET
143
20000
20000
#FFFF
#3FFF
HL,START
BC,COUNT
A,65
(HL)
HL
BC
Z,DONE
D,A
A,B
C
A, D
NZ,LOOP
Figura 12.6
Al terminar el bucle (en la etiqueta DONE) quedará activado el indicador
de cero si se ha encontrado el byte 65, y queda desactivado si no se lo ha
encontrado.
Mientras se realiza la comprobación de si BC es 0, es necesario almacenar
el valor de A. Esto no se puede hacer con PUSH en la pila, pues entonces
120 DIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
se almacenaa F simultáneamente y, al recuperar A y F con POP, la com-
probación posterior del indicador de cero sería inútil. Po r eso se utiliza el
registro D para almacenar el valor de A.
Hay una instrucción que realiza la misma tarea que este programa, o sea,
comparar, disminuir y repetir la operacn hasta que se termine el bloque
previsto. Al acabar, el indicador de cero es a 1 si se ha encontrado el byte
y está a 0 en caso contrario. La instrucción es CPDR y existe tambn la a-
loga CPIR (con incremento en lugar de disminucn) y las correspondientes
instrucciones sin repetición CPD y CPI. Sus códigos son:
ASSEMBLER
CPIR
CPDR
C P I
CPD
HEX
ED B1
ED B9
ED A1
ED A9
BINARY
11 10 1
1 1 10 1
1 1 101
1 1 101
10 1
101
10 1
101
10
10
10
10
110
1 1 1
100
101
0 0 1
001
0 0 1
0 01
En CPIR y CPDR el par HL marca el inicio del bloque en que se realiza
la búsqueda, BC el tamaño del bloque y A contiene el valor del byte que se
busca. CPIR incrementa HL en cada comparación; CDDR lo decrementa.
La búsqueda concluye cuando se encuentra el byte o cuando BC se hace 0.
A! terminar, el indicador de cero queda activado si se ha encontrado el byte.
Las instrucciones CPI y CPD funcionan de forma análoga, pero sin
repeticn.
Todas estas instrucciones utilizan el indicador P/V para indicar que BC
se ha hecho 0, de la misma manera que las instrucciones de transferencia.
La figura 12.7 muestra el programa de 12.6 modificado para utilizar la
instrucción CPDR.
El programa de la figura 12.7 puede a su vez ser transformado para reali-
zar la búsqueda de una serie de bytes consecutivos, en lugar de un solo byte.
Es frecuente usar esta técnica cuando se quiere encontrar una palabra o una
frase entre un conjunto de datos almacenados en memoria, o para encontrar
'palabras clave' que se hayan preparado en un juego de aventuras. La figura
12.8 presenta un programa que sirve para buscar en la memoria una cadena
literal que se le introduzca desde el teclado. Después de teclear los caracteres
se debe pulsar [ENTER]; el programa entrega la dirección de la memoria
en que comienza la cadena literal buscada, si ha podido encontrarla.
La rutina que permite la introducción de la cadena (líneas 120-190) se pue-
de cambiar por otra, si conviene. Al terminar el programa, el par HL contie-
ne la dirección donde comienza la cadena, si ha sido encontrada, o 0 en caso
contrario. Par a permitir comprobar el funcionamiento del programa, el con-
BÚSQUEDAS Y TRANSFERENCIAS AUTOTICAS 121
H i s o f t GENA3 As se mbl er. Page 1.
Pass 1 errors: 00
10 ; BUSOUEDA DE UN BLOQUE CON CPDR
4E20
4E20
FFFF
3FFF
1E2 0
4E23
4E26
4E28
4E2A
Pas s
21FFFF
01FF3F
3E41
EDB 9
C9
2errors:
Tabl e used:
20
30
40
50
60
70
80
90
190
00
59 f
Executes: 20000
START
COUNT
LOOP
DONE
rom
ORG
ENT
EQU
EQU
LD
LD
LD
CPDR
RET
132
20000
20000
#FFFF
#3FFF
HL,START
BC,COUNT
A,65
Figura 12.7. Sumas de comprobación: 0583, 00C9.
tenido final de HL se almacena tambn en la memoria. El siguiente progra-
ma BASIC le permitirá ejecutar el programa en digo de máquina y com-
probar los resultados; le sugerimos que ordene la búsqueda de la palabra
'HOLA' que figura en el programa BASIC.
10 PRINT "HOLA"
20 CALL 30000
30 N=PEEK(30069)+256*PEEK(30070):PRINT N
40 PRINT CHR$(PEEK(N));CHR*(PEEK(N+l));CHR
$(PEEK(N+2));CHR$(PEEK(N+3))
Conviene que reflexione un poco sobre el programa para asimilar entera-
mente su menica. La etiqueta FINÍ? no es necesaria, pero se la ha incluido
para señalar el lugar en que el programa comprueba que ha encontrado com-
pleta la cadena que buscaba. A veces puede ocurrir que lo que el programa
ha encontrado sea justamente la cadena introducida por el teclado, es decir,
la propia muestra. Hay que tener cuidado de evitar esa posibilidad.
Como las instrucciones autoticas realizan cierta cantidad de operacio-
nes simples, hay que tener claro el orden en que éstas se efectúan. Siempre
modifican HL y, cuando lo utilizan, DE antes de disminuir BC. En conse-
cuencia, la instruccn CPIR incrementa HL antes de disminuir BC; o sea,
al final de la instrucción, HL apunta ya a la siguiente posicn de memoria.
Por eso al comienzo de NXT_CH se incrementa DE pero no HL, que está
122 C Ó D I G O M Á Q U I N A P A R A P R I N C I P I A N T E S C O N A M S T R A D
H i s o f t 6ENA3 A s s e m b l e r . P a ge 1.
P a s s 1 e r r o r s ; 00
7530
7530
BB18
BB5A
0000
7530
7530
7533
7534
7535
7538
7339
753C
753D
733 F
7541
7544
7547
7548
7549
754B
754C
754D
754F
7550
7551
7552
7553
7555
7557
755S
7559
755fi
755C
755D
7560
7561
7562
7563
7564
7565
217575
E5
D1
CD1BBB
77
CD5ABB
23
FE0D
20F4
210000
013075
1A
D5
EDB1
C5
E5
2012
13
1A
BE
23
2BFA
FE0D
El
Cl
D1
20E8
2B
227575
C?
Cl
El
D1
23
18F5
10
20
30
40
50
60
70
B0
90
100
1 10
120
130
140
150
160
170
180
190
200
210
220
230
240
250
260
270
280
270
300
310
320
330
340
350
360
370
3B0
390
400
410
420
430
;FIG.
; EN UN
GETKEY
PRINT
START
COUNT
INPU T
LOOK
NXT_CH
FINI?
FOUND
NOFIND
12.8 -
BUSQUEDA D EUN ACADEN A
BLOQUE USANDO CPIR
ORG
ENT
EQU
EQU
EQU
EQU
LD
PUSH
POP
CALI-
LO
CALL
INC
CP
JR
LD
LD
LD
PUSH
CPIR
PUSH
PUSH
JR
INC
LD
CP
INC
JR
CP
POP
POP
POP
JR
DEC
LD
RET
POP
POP
POP
INC
JR
30000
3000 0
47996
47962
#0000
30000
HL,FRE E
HL
DE
GETKEY
(HL),fi
PRINT
HL
#0D
NZ,INPUT
HL,START
BC,COUN T
A,(DE)
DE
BC
HL
NZ,NOFIND
DE
A,(DE)
(HL)
HL
Z,NXT_CH
#0D
HL
BC
DE
NZ,LOOK
HL
(FREE),HL
BC
HL
DE
HL
FOUND
P a ss 2 e r r o r s : 00
T a b le u s e d : 145 fr o m 1 8 4
E x e c u t e s : 3 0 0 0 0
Figura 12.8. Sumas de comprobación : 05A5, 0378 , 04FD, 042E, 055E, 02E2.
BÚSQUEDAS Y TRANSFERENCIAS AUTOTICAS 1 23
ya apuntando a la posición siguiente. Por la misma razón parece la instruc-
ción DEC HL en la etiqueta FOUND. Si no se ha encontrado la cadena bus-
cada, la instruccn POP HL de la rutina NOFIND carga en HL el conteni-
do de BC, que será 0 en ese caso; la instrucción INC HL compensa entonces
la DEC HL que vendrá desps.
Pued e usted tratar de cambiar este programa para utilizar la instruccn
CPDR en lugar de CPIR.
Resumen
Vamos a resumir las instrucciones explicadas en este capítulo. Utilizaremos
los símbolos:
r = cualquiera de los registros de 8 bits (A, B, C, D, E, H o L)
rr = cualquier par de registros que se utilicen como uno de 16 bits
n =un número de 8 bits, o sea, entre 0 y 255
nn =un número de 16 bits, o sea, entre 0 y 65535
( ) rodeando un número o un par de registros=el contenido de la
dirección.
PC = contador de programa
SP = puntero de pila
LDIR carga el contenido de la dirección HL en la direccn DE, incremen-
ta DE y HL, disminuye BC y, si BC no es 0, repite la operacn (carga-
incremento-repeticn).
LDDR carga el contenido de la dirección HL en la dirección DE, disminu-
ye DE y HL, disminuye BC y, si BC no es 0, repite la operación (carga-
disminución-repeticn).
LDI y LDD son como las anteriores, pero sin repeticn,
CPI R compara el contenido de A con el contenido de la dirección HL, in-
crementa HL, disminuye BC y repite hasta que se produzca la igualdad o BC
sea 0 (comparacn-incremento-repetición). Si se ha producido la igualdad,
e! indicador de cero queda activado.
CPDR compara el contenido de A con el contenido de la dirección HL,
disminuye HL , disminuye BC y repite hasta que se produzca la igualdad o
BC sea 0 (comparacn-disminución-repetición). Si se ha producido la igual-
dad el indicador de cero queda activado.
CPI y CPD son como las anteriores, pero sin repeticn.
En todas estas instrucciones el indicador P/V se pone a 0 cuando BC se
hace 0; por lo tanto, si a continuación se hace JP PO, se efectuará el salto
cuando BC sea 0.
13
Comunicación con el exterior
Todas las instrucciones que hemos visto hasta ahora tenían como finalidad
modificar y transportar informacn, pero sin salir del ordenador, o sea, li-
mitándose a desplazamientos entre los registros y la memoria. Es posible que
usted haya pensado a veces en mo recoge el ordenador la información con
la que trabaja; o tal vez se haya dicho que, cuando usted pulsa una tecla,
el Amstrad se encargará de hacer lo que deba. De hecho, sí no necesitase in-
formación proveniente de fuera de ese mundo formado por la memoria, la
pantalla y el microprocesador, el ordenador podría perfectamente olvidarse
de usted y dedicarse a ejecutar sus programas, sin inmutarse aunque usted
se dedicase a pulsar todas las teclas. La única cosa que podría usted hacer
para perturbarle es desenchufar. Pero cuando el ordenador necesita infor-
macn exterior, tiene ios medios para conseguirla. El sistema operativo le
proporciona la forma de acceder a lugares como el teclado o el generador
de sonido, que no caen en el campo de acción directa del microprocesador.
Sin entrar demasiado en detalles técnicos que nos harían salir del tema, va-
mos a dar una explicación elemental de la forma en que se comunica el
microprocesador.
Hay dos cables perfectamente visibles que unen el ordenador y el monitor.
Uno tiene dos hilos y sirve para suministrar electricidad al ordenador. El
otro lleva dentro seis hilos, conectados a las seis clavijas del enchufe; por ese
cable, el microprocesador envía información al monitor sobre la imagen que
debe formar.
Pero lo que usted seguramente no ha visto es que el Z80 tiene 40 patillas,
cada una con una misión específica. Hay 16 que se emplean para proporcio-
nar la dirección con la que desea comunicarse el Z80. Otras 8 se utilizan para
enviar o recibir los datos. Las restantes sirven para transmitir informaciones
diversas como, por ejemplo, que se va a comunicar con la memoria, o con
el exterior, o si la comunicación va a ser de entrada o de salida.
El conjunt o de las 16 patillas que proporcionan las direcciones recibe el
nombre de bus de direcciones (address bus). Sus patillas se reperesentan me-
diante una A seguida del número que corresponde al bit que proporcionan.
Van de la A0, que proporciona el bit 0 (o sea, el número 1 cuando está acti-
125
126 CÓDIGO MÁQUINA PARA PRINCIPIANTE S CON AMSTRAD
vada) , a la A15, que proporciona el bit 15 (o sea, 32768 cuando está ac-
tivada).
El conjunto de las 8 patillas que se emplean para la trasmisn de datos
se denomina justamente bus de dalos (Data Bus). Las patillas llevan mbo-
los que van de D0 a D7, según el bit que representan.
En la figura 13.1 se dibujan esquemáticamente el bus de datos, el bus de
direcciones y algunas de las patillas restantes.
ALGUNAS DE LAS PATILLAS DEL
RD indica petición de lectura (de read). WR indic a petición de escritura (de wríte). MREQ indica
que se va a utilizar la memoria (de memory request), IORQ indic a petición de operación de entra-
da o de salida (de input or autput request). La raya qu e se pone sobre estas patillas significa que
esn activada s cuando están a nivel bajo (binario 0).
Figura 13.1
Por ejemplo, cuando el Z80 ejecuta una instrucción tal como LD
A,(3456), emite una señal para indicar que quiere usar la memoria y que
quiere leer información en la dirección que ha colocado en el bus de direccio-
nes. Entonces lee el contenido de dicha dirección de memoria a través del
bus de datos.
Si se desea realizar una comunicacn con otra cosa que no sea la memo-
ria, habrá que indicarle al Z80 con q debe comunicarse. Para ello esn
las instrucciones OUT (de output, salida) e IN (de input, entrada). El Z80
COMUNICACIÓN CON EL EXTERIOR 127
dispone de otras instrucciones de este tipo pero, debido a la forma en que
está diseñado el Amstrad, sólo estas dos tienen interés. Sus códigos son:
ENSAMB LADOR B I N A R I O
T (C),r 11 101 101 (EDh) 01 r 001
IN r, (C) 11 101 101 01 r 000
La dirección con la que se debe establecer la comunicación de entrada o sali-
da viene dada por el par BC. El registro B proporciona desde A8 a A15 y
el registro C desde A0 hasta A7. Por ejemplo, cargando 1234h en BC, se ten-
drá 00010010 00110100.
Las direcciones de los elementos externos del equipo no reciben habitual-
mente este nombre. Se suele hablar depuerta (en inglés es port, puerto, pero
en castellano se dice puerto o puerta, según los gustos). Así se evita cualquier
confusión sobre si una dirección es interna (de memoria) o externa (de un
dispositivo externo). Las operaciones realizadas a través de una puerta se lla-
man operaciones de E/S, o sea, entrada/salida (Í/O en inglés).
Debido al diseño del Amstrad, hay poco s valores con los que se pueda car-
gar BC en este caso. Lo más probable es que usted utilice estas instrucciones
para los distintos dispositivos periféricos. Los valores que quedan libres para
B son F8h F9h FAh o FBh. Con todos ellos AI0 está a 0 (a bajo nivel). Siem-
pre que la línea de A10 esté a bajo nivel y que los bits A0.. . A7 estén carga-
H i s o f t GENA 3 A s s e m b l e r . P a g e 1.
P a s e 1 e r r o r s ; 00
B B 18
7 5 30
7 5 30
7 5 3 0
7 5 33
7 5 35
7 5 3 7
7 5 3 A
7 5 3 B
7 5 3 D
P a s s
T a b l e
E x e c u
0 1 E 0 F 6
3 E 1 0
ED7 9
CD1BBB
A F
ED7 9
C9
2 e r r o r s :
used:
00
35
t e s : 3 0 0 0 0
10
20
30
40
50
60
70
80
90
1 0 0
1 10
12 0
f
Figura 13.2. Sumas de comprobación: 052B, 02DE.
;F I G . 13.2 -
; Y APAGA R EL
GETKEY
ON
EQU
ORG
ENT
LD
LD
OUT
CALL
XOR
OUT
RET
- PROGRAM A PARA ENCENDER
. MOTOR DE L MAGNETOFONO
47896
30000
3 0 0 00
BC,#F6E0
A , #10
(C) , A
GETKE Y
A
(C) , A
128 DIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
dos con valores entre E0h y FEh inclusive, no habrá posibilidad de interfe-
rencia con las direcciones reservadas por Amstrad para su uso actual o futu-
ro en el CPC464. El Manual de referencia del programador le proporcionará
detalles suplementarios sobre el equipamiento ligado al Amstrad.
El programa de la figura 13.2 muestra el uso de OUT para encender y apa-
gar el motor del magnetófono del Amstrad. El magnetófono está al otro la-
do de un circuito de interfase (UPD 8255) que posee tres canales de E/S. El
acceso para el canal A es la puerta F4xxh, para el canal B la puerta F5xxh
y para el canal C la puerta F6xxh. El control se realiza por la puerta F7xxh.
En todos los casos, xx puede ser cualquier valor (que será almacenado en el
registro C) salvo uno de los no utilizados por A 0.. . A7, que hemos mencio-
nad o antes, en cuyo caso tenda problemas.
14
Otras instrucciones
En el Z80, los registros B. . .L de uso general, el acumulador A y el registro
de estado F están duplicados y existen instrucciones para intercambiar valo-
res entre los registros y los registros alternativos. Puede encontrar estas ins-
trucciones en el Apéndice A, pero le aconsejamos vivamente que no las utili-
ce, al menos sin conocer a fondo el sistema operativo del Amstrad. Olvide,
pues, su existencia en tanto no domine completamente e l Manual de referen-
cia del programador.
La información que vamos a suministrarle en este capítulo le será muy útil
si llega a asimilarla bien y a adquirir un buen conocimiento del sistema ope-
rativo. Ahora bien, es difícil precisar exactamente el grado de conocimiento
que deberá poseer para sacar verdadero provecho de estas instrucciones.
Interrupciones
El Amstrad genera interrupciones a intervalos regulares; es así como se las
arregla para ejecutar instrucciones de EASIC tales como EVERY o AFTER.
El Z80 puede reaccionar ante una interrupción de tres maneras diferentes,
que son lo que se llama modos de interrupción (interrupt modes); estos mo-
dos se representan por IM1, IM2 y IM3. Hay formas de seleccionar el modo
de interrupcn; el andice A proporciona las instrucciones necesarias. El
program a de arranque en frío del Amstrad (recuerde que es el que se ejecuta
cuando se enciende) selecciona para las interrupciones el modo 1 (IM1).
Cuando se genera una interrupción en este modo, lo que se produce es una
llamada a la dirección 56 (38h), en la que comienza un programa que suele
recibir el nombre de rutina del servicio de interrupciones. Lógicamente, lo
primero que hace esta rutina es almacenar el contenido de los registros, para
poder devolver posteriormente los mismos valores cuando se vuelve al pro-
grama principal. Cuando una interrupcn produce esta llamada, se detiene
automáticamente cualquier otra interrupción que se esté llevando a cabo.
Antes de volver al programa principal hay que desbloquear las interrupcio-
nes, para que las futuras interrupciones no sean ignoradas. La instrucción
129
130 CÓDIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
que permite desbloquear las interrupciones es El (de Enable Iníerrupts).
Existe también la correspondiente instruccn que permite inhibir las inte-
rrupciones; es DI (de Disable Interrupts). Los códigos de estas instrucciones
son
ENSAMBLADO R HEX B I N A R I O
DI F3 11 110 011
EI FB 11 111 011
Afortunadamente, Locomotive Software ha pensado en el progrAmador de
digo de máquina y le ha proporcionado una manera sencilla de utilizar las
interrupciones. En otras quinas que utilizan el Z80, la gestión de interrup-
ciones se realiza a través del modo 2, que es menos sencillo. Si usted desea
utilizar su propia rutina de servicio para las interrupciones, lo que debe ha-
cer es escribirla y añadir al final la instrucción JP #B939 en lugar de RET .
A continuación debe ejecutar
LD HL,nn (código hex 21 nn )
LD (#39),HL (código hex 22 39 00)
A partir de este momento, cada interrupción llamará a su rutina. Par a desac-
tivar su rutina de interrupción y volver a la situación normal ejecute
LD HL,#B93 9 (código hex 21 39 B9)
LD (#39),HL (código hex 22 39 00)
No intente hacer el cambio de la dirección cargada en 39h en dos pasos sepa-
rados, ya que, si ocurre una interrupción entre ambos, se llamaría a una di-
reccn equivocada.
Vamos a dar una breve descripció n del modo IM2, aunque le recordamos
que no debe usar este modo ni IM0 sin asimilar previamente lo que dice acer-
ca de las interrupciones el Manual de referencia del programador. Con el
IM2 se pueden utilizar las interrupciones para ejecutar las rutinas que se de-
seen, siempre que se desbloqueen las interrupciones antes de volver al pro-
grama y que se termine con la instrucción RETI. Debe recordar también
que, antes de volver al BASIC, deberá restablecer el IM1 y desbloquear las
interrupciones, salvo que se utilice RST 56 (38H) en la rutina de interrup-
ción.
Al recibir una interrupción, el IM2 aca de la manera siguiente: almacena
el contenido del PC en la pila; inhibe las demás interrupciones; lee el valor
!bd' que haya en el bus de datos y el contenido del registro I (registro de inte-
rrupción); calcula la dirección bd+(256*I); por fin, salta a la direccn que
haya en dicha posic n y la siguiente. Po r ejemplo, si el registro I contiene
OTRAS INSTRUCCIONES 131
10 (0AH) y el dispositivo que realiza la interrupcn coloca en el bus de datos
el valor 200, entonces 10*256=2560, y 2560+200=2760; ahora, si la direc-
ción 2760 contiene el valor 90 y la direccn 2761 contiene 187, la dirección
de salto será 90+(256*187) que es 47962. O bien, si 1 contiene 187 y el dispo-
sitivo envía el valor 90, entonces 187*256=47872, y 47872+90=47962; si
47962 contiene 207 y 47963 contiene 0, entonces 0+(207*256) =52992 y el
salto se efectúa a 52992.
Una manera sencilla de comprender lo que sucede es imaginarse que exis-
te, justo en la posición anterior a la que se forma con I y con el valor del
bus de datos, una instruccn invisible que dijese DI y CALL; de esta forma
se saltaría a la dirección dada por las dos posiciones de memoria que vienen
tras el CALL (dirección que se calcula en la forma habitual del Z80). Como
la instrucción es invisible, no coloca la dirección de retorno en relacn a sí
misma; la que se almacena en la pila es la de la instrucción siguiente en el
program a principal, que es a donde se volverá tras la instrucción RETI de
la rutina de interrupción.
La instrucción RETI debe ir precedida de EI, como ya hemos dicho. La
razón es que la llamada a la rutina de interrupciones lleva incorporado un
DI para impedir que, como la rutina tardará en ejecutarse más tiempo del
que media entre dos interrupciones, el programa caiga en un bucle sin fin.
Cualquier rutina de interrupcn debe comenzar por preservar los valores
de los registros en el momento de la entrada, para restablecer estos valores
al volver al programa principal. No deben pasarse datos de la rutina por me-
dio de los registros.
La utilización más típica de las interrupciones es el control de los movi-
mientos en pantalla de figuras predefinidas (o sprites). La velocidad del mo-
vimiento de estas figuras se establece basándose en el conocimiento de la fre-
cuencia con que se genera una interrupción. Como esto es independiente de
cualquier otro aspecto del programa, se puede conseguir una velocidad cons-
tante de desplazamiento.
El programa de la figura 14.1 se compone de dos partes. La primera con-
tiene dos rutinas: la primera modifica y la segunda restablece la dirección de
la rutina del servicio de interrupciones. La segunda parte del programa es
la rutina de interrupcn alternativa; lo que hace es cargar 123 en la posicn
31100. Antes de ejecutar ninguna parte de este programa , vuelva al BASIC
y teclee
? PEEK (31100)
que le devolverá e l valor 0,
POKE 31100,10: ? PEEK (31100)
13 2 CÓDIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
que le devolverá 10 y
POKE 31100,0:?PEEK(31100)
que le devolverá 0 otra vez. Ejecute ahora CALL 30000 y teclee de nuevo
los mismos comandos. Ahora obtendr á siempre 123, ya que en cada inte-
rrupción se ejecuta la rutina final del programa. Ejecute CALL 30007 para
volver a la rutina normal de interrupción y teclee otra vez los comandos. To-
do habrá vuelto a la situación normal.
Hisoft GENA3 Assembler. Page 1.
Pass 1 errors: 0 0
1 ; FIG 11.1 - DESVIO DE LA S INTERRUPCIONES
7530
7530
7530
7533
7536
7537
753A
753D
7918
7919
791 9
791B
791E
791F
21 1879
223900
C9
2139B9
223900
C9
F5
3E7B
327C79
Fl
C339B9
10
20
30
40
50
60
70
80
90
100
110
120
130
140
IN1T
DISARM
ORG
ENT
LD
LD
RET
LD
LD
RET
ORG
PUSH
LD
LD
POP
JP
30000
30000
HL,31000
(#39),HL
HL,#B939
(#39),HL
31000
AF
A, 123
(31100),A
AF
#B939
Pas s 2 errors:
Table used: 37 from 142
Executes: 30000
Figura 14.1 . Sumas de comprobación: 02E9, 0124 y 057B para la segunda parle.
Una última consideración sobre las interrupciones. Un programa en di-
go de máquina irá s rápido si se inhiben las interrupciones con DI. Esto
inhibirá también los comandos AFTER y EVERY de BASIC, pero no afec-
tará prácticamente a nada más.
La siguiente instrucción nos será muy fácil de explicar después de lo ante-
rior. Se trata de
ENSAMBLADOR HE X B I N A R I O
HALT 76 01 110 110
OTRAS INSTRUCCIONES 133
que es la instrucción cuyo código es el único de este tipo que no utilizaban
las instrucciones LD r,r. La instruccn HALT detiene el Z80 en tanto no
se reciba la siguiente interrupcn. Si se ejecuta HALT cuando las interrup-
ciones esn inhibidas, provocará su detencn total, por lo que hay que ase-
gurarse de que las interrupciones están activadas cuando se las utiliza.
H i s o f t GENA3 A ss e m bl e r. Page i.
Pass 1 e r r o r s : 0 0
7530
753 0
7530
7531
7533
7534
7536
Pass
Table
Execu
FB
06C8
76
10FD
C9
2 errors :
used:
00
24
tes: 30000
10
20
30
40
50
60
70
80
FIG
LOO P
f rom
. 14.2 -
ORG
ENT
EI
LD
HALT
DJN Z
RET
136
RETARE
3000 0
3000 0
B , 200
LOO P
Figura 14.2. Suma de comprobacn: 0415.
Se usa normalmente esta instrucción en los programa s de retardo, para
conseguir grandes retrasos sin necesidad de recurrir a la utilización de bu-
cles. La figura 14.2 muestra un programa en el que se utiliza HALT con esta
intención. El retardo debido específicamente a la instruccn puede apreciar-
se probando también el programa con NOP en lugar de HALT; el cambio
de instruccn puede hacerse tecleando POKE &7533,0.
Reinicio (RST)
Existen ocho direcciones (todas ellas de la página 00h de memoria) que pue-
den ser llamadas mediante una instrucción de un lo byte en lugar de la lla-
mada habitual de tres bytes. Esta instruccn es conocida como reinicio {o
restart) y su código es RST.
134 CÓDIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
Las ocho direcciones posibles y los correspondientes códigos son:
ENSAMBLADOR BINARI O p t p t
RST p 1 1 t11 1 00h 000 20h 100
08h 001l 28h 101
RST 3 0 h 11 1 1 0 111 10h 010 30h 110
18h 011 38h 111
Lo que hace esta instrucción es realizar una llamada a la dirección corres-
pondiente, como si fuese una instrucción CALL; la rutina que empiece en
esa dirección debe terminar por RET.
De las ocho direcciones posibles, la mayor parte son utilizadas por el Ams-
Hisoft GENA3 Assembler. Page 1.
Pass 1 errors: 0 0
10 ; F1G. 14.3 - DESVIO DE RST 30
7530 2 0 ORG 30000
7530 30 ENT 30000
7530 3EC3 4 0 L D A,#C3
7532 215ABB 50
7535 32300 0 60
7538 22310 0 70
753B 3E4 8 B 0
753D F7 90
753E 3E6 5 100
7540 F7 110
7541 3E6 C 120
7543 F7 130
7544 3E6 C 140
7546 F 7 150
7547 3E6F 160
7549 F7 170
754A C9 180
Pass 2 errors: 00
Table used: 13 f r o m 160
Executes: 30000
LD
LD
LD
LD
RST
LD
RST
LD
RST
LD
RST
LD
RST
RET
HL,#BB5A
(#30),A
(#31),HL
A,72
#30
A, 101
#3 0
A, 10B
#30
A, 108
#30
A,111
#3 0
Figura 14.3. Sumas de comprobacn: 02EC, 04B8, 040E.
OTRAS INSTRUCCIONES 135
trad para sus propias necesidades. Por ejemplo, 56 (38h) es la direccn de
la rutina del servicio de interrupciones. Pero una de estas instrucciones, la
RST 30h, está a disposición del programador.
El programa de arranque en frio prepara la dirección 30h de maner a que
se salte al programa de arranque al utiliza RST 30h; esto se puede compro-
bar tecleando CALL 48 (30h).
Para cambiar esta finalidad hay que colocar en la direccn 30h la instruc-
ción de salto que convenga. Por ejemplo si usted utiliza con frecuencia la
rutina PRINT de 47962 (BB5Ah) y decide que es mejor llamarla con RST
30h para ahorrar 2 bytes cada vez, lo que debe hacer es colocar en 30h el
código de JP, y la correspondiente direccn en 31h y 32h (en la forma habi-
tual). Esto es lo que hace el programa de la figura 14.3. En realidad, bastaa
con lo que hay hasta la línea 50, colocando a continuación un RET; se ha
añadido otra parte al programa para demostrar cómo funciona.
Ninguna de las instrucciones que hemos explicado hasta el momento en es-
te capítulo afecta a los indicadores.
Direccionamiento indexado
Hay dos registros de los que no hemos hablado todaa; son los IX y IY.
Se llaman registros índice (de ahí la I), ya que se los utiliza para indicar direc-
ciones de determinados elementos de información. Además, cada uno de
ellos puede ser utilizado de la misma forma que el par HL.
Se pregunta usted cómo es posible que un sólo registro se pueda utilizar
como un par. Pues bien, lo que ocurre es que tanto IX como IY son pares
de registros que se utilizan al mismo tiempo como un registro de 16 bits. Los
disadores del Z80 fueron incapaces de conseguir resultados fiables para es-
tos pares cuando se los utilizaba separadamente. Por eso no publicaron las
instrucciones que permiten utilizar cada registro de 8 bit de forma indepen-
diente.
En cuanto se conocen las instrucciones que utilizan IX y IY, es fácil descu-
brir cuáles son las que permiten usar separadamente los correspondientes re-
gistros de 8 bits. Todas las que hemos introducido en el Amstrad que se ha
usado para el desarrollo de este libro han funcionado sin problemas. Claro
que ios ensambladores no recogen estas instrucciones, por lo que no pueden
se programadas con ellos. Ades, no se puede garantizar que vayan a fun-
cionar también en cualquier otro Amstrad CPC464, así que vamos a dejar
las cosas como están y a realizar la descripción de las instrucciones que utili-
zan los registros índices IX y IY.
A excepción de las instrucciones ADC y SBC, todas las instrucciones que
utilizan HL se pueden usar con IX y con IY. El código de una instrucc n
136 DIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
que utilice IX es el mismo que el de la correspondiente instrucción para HL,
pero debe llevar delante el byte DDh (221). Lo mismo ocurre cuando se em-
plea IY en lugar de HL; en este caso se añade el byte FDh (253). Por otr a
parte, cuando una instrucción utiliza HL en la forma (HL), la instrucción
correspondiente con IX o IY lleva delante el byte suplementario, y lleva de-
trás otro byte que señala un desplazamiento en la forma de un número con
signo; la instruccn afecta entonces a la posición apuntada por IX+d o
IY+d, donde d es el desplazamiento. Todo esto resulta de momento un
poco confuso, pero vamos a aclararlo con ejemplos.
El código para LD HL,nn es 21h seguido de los dos bytes que especifican
el mero nn de 16 bits. Cuando se utiliza IX hay que añadir el prefijo DDh,
luego la instruccn resultará
ENSAMBLADO R HEX
LD I X , n n D D 21 n n
Cuando se utiliza IY la instruccn resulta
ENSAMBLADOR HEX
LD I Y , n n FD 21 n n
Y de la misma forma todas las instrucciones que actúen directamente sobre
los registros índice. Otros ejemplos son
ENSAMBLADOR
LD ( n n ) , H L
PUSH HL
DEC H L
J P ( H L )
ADD H L , B C
HEX
22 n n
E 5
2B
E 9
09
CON I X '
DD 22 n n
DD E5
DD 2 B
DD E 9
DD 0 9
CON I Y
FD 22 n n
FD E 5
FD 2B
FD E 9
FD 09
La última de las instrucciones sugiere una pregunta interesante. ¿Qué ocu-
rre cuando en la instrucción ADD HL,HL se sustituye alguno de los HL
por IX o IY? (Recuerde que ésta era una instruccn empleada para produ-
cir un desplazamiento a la izquierda de 16 bits en los programas de multipli-
cación.) Lo que sucede es que no se puede sustituir uno sólo de los HL, sino
los dos simulneamente. Si la instrucción ADD HL,HL va precedida de
DDH, se convierte en ADD IX,IX; si va precedida de FDh, se convierte en
ADD IY,IY.
OTRAS INSTRUCCIONES 137
Vamos a explicar ahora la transformación de las instrucciones que utilizan
HL como puntero de una dirección e n instrucciones que utilicen IX+d o
lY+ d con el mismo prosito. Es lo que se llama direccionamiento indexa-
do. Será útil plantearse un caso práctico.
Supongamos que queremos tener almacenada la clásica agenda con direc-
ciones y teléfonos. Uno de los principales problemas que suscita el almace-
namiento y utilización de este tipo de datos es el de la diferente longitud de
un mismo campo en los diferentes registros. Hay nombres más largos que
otros, direcciones que ocupan diferente número de líneas, etc. Este tipo de
problemas admite soluciones de dos tipos:
1) Reservar a cada campo la longitud que corresponda a la más larga de
las que se van a necesitar.
2) Mantener en cada registro un índice con la longitud de cada línea, el
número de líneas y la longitud total del registro.
El primer método es cómodo, pero antieconómico. El segundo parece
muy difícil de realizar. Veamos que no es difícil con los registros índices.
Vamos a ver cómo se organizaría un registro que comenzase, por ejemplo,
en la dirección 10000:
DIRECCIÓN
10000
10001
10002
10003
10004
10005
10006
10007
10008
CONTENIDO
byte bajo y
byte alto de la longitud del registro, en 16 bits
longitud del nombr e
longitud nea 1 de la dirección
longitud línea 2 de la dirección
longitud línea 3 de la dirección
longitud línea 4 de la direccn
longitud línea 5 de la dirección
longitud del número de teléfono
Si el contenido del registro fuese
Jose Martínez López
Viriato 52
28010 MADRID
91 4458919
los contenidos de dichas direcciones serían
10000=51
10001=0
10002=19
10003 = 10
10004=12
longitud,byte bajo
longitud,byte alto
nombre
dirección 1
dirección 2
10005 = 0
10006 = 0
10007 = 0
10008 = 10
dirección 3
dirección 4
dirección 5
teléfono
13S CÓDIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
El índice ocupa 9 bytes (esto es lo mismo para todos los registros) y el regis-
tro ocupa 51. Como 9 + 51 =60, el índice del registro siguiente comenzará en
10060. Vamos a ver cómo se utilizan ahora los índices.
Si IX está cargado con 10000, entonces (IX+0) y (IX+1) darán la longitud
total del registro, (IX+2) la longitud del nombre, y así sucesivamente . El co-
mienzo del índice del siguiente registro se obtendrá siempre sumando 9,
(IX+0) y 256*(IX+1) a IX. Si se hace un programa que sirva para cargar
un registro, elaborar su índice y pasar al registro siguiente, el programa ser-
virá exactamente igual para cualquiera de los registros.
Las instrucciones que utilizan registros índice con desplazamiento tienen
digos nemotécnicos que resultan totalmente lógicos a estas alturas . A, a
LD A,(HL) le corresponden LD A,(IX+d) y LD A,(IY+d).
El desplazamiento es un número de 8 bits con signo, luego vaa entre
128 y +127; ocupa 1 byte en los códigos y es obligatorio en las instruccio-
nes que utilizan el registro para apuntar a una dirección de memoria, incluso
aunque el desplazamiento sea 0. El código del desplazamiento va inmediata-
mente después del primer byte del código original. Por ejemplo,
LD A,(HL) es 7Eh LD A (IX+d) es DDh 7Eh d
INC(HL) es 34h INC(IY+d) es FDh 34h d
RLC(HL) es CBh 06h RLC(IX + d) es DDh CBh d 06h
SET 4,(HL) es CBh E6h SET 4,(IY+d) es FDh CBh d E6h
LD (HL),n es 36h n LD (IX+d),n es DDh 36 d n
Otra de las posibles utilizaciones de los registros índice consiste en realizar
un cambio de los ejes de la pantalla, de manera que se pueda volcar el conte-
nido de ésta a la impresora. La impresora recibe en cada byte información
sobre una serie de puntos situados en vertical, mientras que para la pantalla
un byte contiene información sobre puntos situados en horizontal. En modo
2, cada byte almacena la informacn de 8 puntos consecutivos; otro tanto
ocurre con una impresora Epson, pero la direccn de la nea que forman
los puntos es justamente perpendicular a la anterior. Por lo tanto, hay que
hacer una rotación de 90 grados a la pantalla antes de copiarla directamente
a la impresora.
Lo más económico no es rotar toda la pantalla al mismo tiempo, sino ha-
cerlo con una línea de caracteres, mandarla a la impresora y hacer lo mismo
con la línea siguiente y las demás. El programa de la figura J4.4 hace esto
para la nea de pantalla de modo 2 que comienza en C000h. Como no todo
el mundo tiene impresora, y no todas las impresoras utilizan los mismos có-
digos de control para ponerse en modo gráfico (si es que pueden hacerlo),
hemos hecho que el programa actúe en la pantalla.
El mapa de pantalla cambia si se desplaza la pantalla hacia arriba. Par a
estar seguro de que comienza en C000h, utilice el comando MODE2 (o pulse
LD A,(HL)
INC(HL)
RLC(HL)
SET 4,(HL)
LD (HL),n
es 7Eh LD A
es 34h
es CBh 06h
es CBh E6h
es 36h n
(IX+d)
INC(IY+d)
RLC(IX + d)
SET 4,(IY+d)
LD (IX+d),n
es DDh 7Eh d
es FDh 34h d
es DDh CBh d 06h
es FDh CBh d E6h
es DDh 36 d n
OTRAS INSTRUCCIONES 139
Hisoft GENA3 Assembler. Page 1.
Pass 1 errors: 0 0
9C4 0
9C40
9C4 0
9C44
9C4 7
9C4A
9C4C
9C4E
9C4F
9C50
9C5 2
9C53
9C5 4
9C56
9C5B
9C5C
9C5 E
<?C5F
9C61
VC6 3
9C6 4
9C6 6
9C6 7
9C69
9C6fl
9C6B
9C6D
9C6 F
9C7 0
9C7 2
Pas s
Table
DD2100C0
2150C0
110000
0650
DDE5
E 5
C5
0608
C5
E 5
DDE5
0608
DDCB0006
CB1E
19
10F 7
DDE1
El
DD19
Cl
10E9
Cl
El
DDE1
DD23
23
10DA
C9
2 errors:
used :
1
2
10
20
30
40
50
60
70
80
9 0
100
110
120
130
140
150
160
170
180
190
200
210
220
230
240
250
260
270
280
290
300
00
i F1G.
14.4 -
; EN MODO 2
L0DP3
LG0P2
LOOP
48 from
OR G
ENT
LD
LD
LD
LD
PUSH
PUSH
PUSH
LD
PUSH
PUSH
PUSH
LD
RLC
RR
ADD
DJN7
POP
POP
ADD
POP
DJNZ
POP
POP
POP
INC
INC
DJNZ
RE T
147
ROTACION DE PANTALLA
40000
40000
IX,#C000
HL,#C05 0
DE,#0800
B, 80
IX
HL
BC
B,8
BC
HL
IX
B,8
( IX+00)
(HL)
HL,
DE
LOO P
IX
HL
IX,DE
BC
LOOP2
BC
HL
IX
IX
HL
LOOP3
Figura 14.4. Sumas de comprobación: 030B, 057A, 0467, 0586, 0656, 00C9.
W hasta conseguirlo, si est á utilizando el ensamblador). Mueva el cursor a
la primera línea y escriba en ella unos cuanto s caracteres; pulse luego [EN-
TER], sin preocuparse porque dé un mensaje de error. Ejecute ahora el pro-
grama. La primera línea de caracteres aparecerá copiada en la segunda línea,
pero cad a carácter aparecerá girado 90 grados en el sentido de gir o de las
agujas del reloj.
Podrá usted adaptar este programa a sus necesidades, si es que está escri-
140 CÓDIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
hiendo un programa para vuelco de pantalla o algo parecido. Hacer lo mis-
mo en modos 0 y 1 es sensiblemente más difícil, a causa de la manera más
complicada en que se almacena la información sobre cad a punto.
Con esto termina el libro propiamente dicho y ahora lo que deberá hacer
es practicar con lo que ha aprendido. En el siguiente catulo le damos una
idea sobre la utilizacn de las rutinas del sistema operativo y tambn algu-
nos consejos finales. Lo que más le ayudará para las consultas que deba rea-
lizar serán los apéndices. Si se ha tomado en serio la programación, no le
vendrá mal una plantilla para realizar diagramas de flujo. También podrá
serle bastante útil alguna calculadora que trabaje en hexadecimal y en binario
ades de en decimal.
15
Consejos sobre cómo utilizar el sistema
operativo
El sistema operativo del Amstrad utiliza una serie de rutinas que se encargan
del control de la pantalla, el magnetófono, el generador de sonidos, el mane-
jo del teclado, etc. Están agrupadas en áreas que engloban todas las que se
encargan de una misma tarea genérica.
No corresponde al propósito de este libro entrar en detalles sobre la confi-
guración de estas secciones, ni realizar una descripción del sistema operati-
vo; el Manual de referencia del programador cubre estos temas con gran
detalle. Sin embargo, vendrán bien algunas consideraciones para permitirle
iniciarse en el tema.
La forma en que el programador puede acceder al sistema operativo es
realizar llamadas a ciertas direcciones de la memoria ROM. Estas direccio-
nes están almacenadas en la memoria RAM, agrupadas en bloques de direc-
ciones conocidos como bloques de salto (jump-blocks). La figura 15.1 mues-
tra cuál es la técnica usual (y conveniente) para saltar a una de estas direccio-
nes.
La utilizacn de los bloques de salto para el acceso a las rutinas presenta
varias ventajas. Se puede cambiar la rutina a la que se llama de manera muy
sencilla, con sólo cambiar la correspondiente dirección en el bloque, y sin
necesidad de corregir el programa. También permite que el programa pueda
calcular sus propias acciones.
Un caso pico en que este sistema es ventajoso se presenta cuando el pro-
grama realiza una serie de salidas por impresora. Se puede utilizar la panta-
lla mientras se depura el programa y, posteriormente, desviar la salida a la
impresora. El coste del cambio consistiría sólamente en alterar una direccn
del bloque de salto. En BASIC se hace esto con mucha frecuencia, pero allí
es todaa más sencillo ya que el dispositivo de salida que se asocia a una
sentencia PRINT puede darse mediante una variable. En código de máquina
no se emplean variables, pero se puede proceder como hemos explicado.
El propio Amstrad no puede utilizar este sistema a causa de los problemas
de conmutacn de áreas de memoria entre la RA M y la ROM. No se puede
garantizar el acceso a la rutina correcta a menos que el programador cora-
141
142 CÓDIGO MÁQUINA PAR A PRINC I PIAN TES CON AMS TR A D
PROGRAMA P R I N C I P A L
LD A,ROUTNO ; numero (0...255) de la
rutina a la que se llama
CALL JUMP
RESTO DEL PROGRAMA PRINCIPAL
J U M P : AD D A , A
LD D , 0
L D E, A
LD HL,JBSTR T
ADD HL , D E ; H L c o n t i e n e ! a h o r a l a
d i r e c c i o n d e l a m e m o r i a
q ue c o n t i e n e l a
d i r e c c i ó n d e l a r u t i n a
LD
INC
LD
EX
jP
E,(HL)
HL
D,(HL)
DE,HL
(HL) ; s a l t o a l a r u t i n a c u y o
RET f i n a l v u e l v e a l
p r o g r a m a p r I n c i p a l
JBSTRT: ; aq ui e m p i e z a la l i sta de p a r e s d e b y t e s
que a l m a c e n a n 1 a s d i r e c c i o n e s de l a s
r u t i n a s e n la 'forma h a b i t u a l
Figura 15.1
pruebe que se encuentra activada el área de ROM que interesa, o la active
en caso contrario. Además, si se necesita leer la pantalla, hay que desactivar
la parte superior de la ROM, que se superpone a la pantalla.
La solución de Amstrad es reservar una cierta cantidad de instrucciones
RST para realizar llamadas a las rutinas de la ROM. Esto garantiza que se
activada la ROM que se necesite, y que la pantalla estará disponible si se re-
quiere. Se extrae de la pila la dirección de vuelta de la instrucción RST y se
la utiliza para examinar los bytes que siguen a la instrucción; en estos bytes
se encuentra la dirección de la rutina a la que se llama y así se puede activar
la ROM correspondiente. En el Manual de referencia del programador pue-
de encontrar más en detalle mo funcionan estas RST, pero es poco proba-
ble que esto le sea necesario por el momento.
Existen dos bloques de salto diferentes. Uno es el que utiliza el intérprete
CONSEJOS SOBRE CÓMO UTILIZAR EL SISTEMA OPERATIVO 143
de BASIC. El otro es el que constituye el sistema operativo o firmware. Se
puede cambiar el que está activado en ese momento mediante un cambio de
tres bytes, comenzando con la dirección RST. Si la nueva rutin a está en el
firmware, basta con copiar en la tabla de saltos los tres bytes correspondien-
tes a la nueva rutina, en sustitución de los de la antigua. Si la nueva rutina
es una desarrollada por usted, reemplácelos por un salto JP a la dirección
de la rutina y, siempre que la rutina termine con un RET, todo funcionará
normalmente. Mientras se cambie el bloque de salto principal, que se en-
cuentra entre las direcciones BB00h y BDCBh, no se afecta para nad a al fun-
cionamiento de ninguna de las rutinas del sistema operativo. Sin embargo,
si se altera el contenido de los bloques fuera de este área, se pueden producir
efectos inesperados. Esto se debe a que ciertas rutinas pueden utilizar estos
otros bloques de salto para realizar sus propias llamadas a rutinas que nece-
siten para su trabajo.
Si se encuentra en un apuro del que no sabe cómo salir, hay una rutina
que es fundamental; es la de la dirección BD37h, que restablece Jos bloques
de salto a su contenido original.
La pantalla y el sonido son tratados por hardware más que por software, lo
que convierte en casi imposible el acceso directo a las funciones que desee uti-
lizar, y lo mismo ocurre con el barrido del teclado. Afortunadamente, el firm-
ware proporciona bastantes facilidades que le permitirán realizar esas tareas.
Los mandos de juego (joysticks) se pueden leer combinando dirección y
botón de disparo, lo que permite detectar ocho direcciones de movimiento.
El andice G le proporciona las direcciones de llamada más usuales.
Cuando programe, utilice etiquetas alusivas al contenid o de la sección que
encabeza. Utilice también los comentarios, a pesar de que suponen un gasto
de espacio; lo agradecerá el a en que deba volver a repasar el programa
fuente y no recuerde ya la forma en que estaba organizado.
El libro no ha entrado en cierto aspectos más profundos del Z80, ni se ha
realizado ninguna consideración sobre los tiempos de ejecución. Su estudio
le habrá permitido simplemente iniciarse en la programación y comenzar a
utilizar el firmware. Para entrar en cosas más delicadas, o en lo que toca al
hardware, podemos recomendarle algunos libros. Lea
Rodney Zaks "Programming the Z80" de SYBEX
para lo tocante a la programación. Para lo que se refiere al hardware o al
desarrollo del Z80, puede interesarle
"Th e Z80 Tecnical Manual", de la propia casa ZILOG
o tambn
James Coffron "Z80 Applications " de SYBEX.
144 CÓDIGO MÁQUINA PAR A PRINCIPIANTE S CON AMSTRA D
Cuando ya domine la programación en ensamblador, quizá le interese
aprender otros lenguajes. Pascal es posiblemente el que le convenda apren-
der con vistas a programar en serio. Es parecido a BASIC en algunos aspec-
tos, pero ofrece muchas de las posibilidades del ensamblador. Es un lenguaje
compilado, como el ensamblador, pero tiene la ventaja de que un programa
fuente es válido casi sin modificaciones, en máquinas diferentes de la que lo
ha escrito. Existen muchos ordenadores para los que hay implementaciones
de este lenguaje. Las principales limitaciones son la velocidad y el espacio;
en ambos aspectos es peor que el ensamblador. Pero e l Pascal es mucho más
rápido que el BASIC y el código compilado ocupa mucho menos espacio que
un programa BASIC comparable. Muchos programadores utilizan una mez-
cla de código generado por Pascal y, para las parte s donde se pueden obtener
mejoras importantes de espacio y velocidad, verdadero código de máquina
obtenido a partir de ensamblador. Tanto Pascal como el ensamblador, una
vez compilados, permiten separar el programa fuente del digo objeto. El
primero se almacenará para utilización posterior, si es necesaria. El digo
objeto se grabará y se cargará siempre que se desee ejecutar el programa.
Para el Amstrad existe una implementacn de Pascal que suministra la
casa Highsoft.
Apéndice A
Conjunto de instrucciones del Z80
El microprocesador Z80 tiene uno de los conjuntos de instrucciones más po-
tentes y versátiles de los que existen en microprocesadores de 8 bits. Algunas
instrucciones, que no posee ninn otro, permiten realizar cambios rápidos
de bloques de memoria y transferencias entre la memoria y el exterior, de
manera sencilla y eficaz.
A continuación damos un resumen del conjunto de las instrucciones del
Z80 en el que se incluye el digo nemotécnico de cada una, la operación
que realiza, su interacción con los indicadores y algunos comentarios. Para
s detalles se pueden consultar los manuales 'Z80 CPU Technical Manual'
(03-0029-01) y 'Assembly Language Programmin g Manual' (03-0002-01).
Se han dividido las instrucciones en los siguientes grupos:
—carga de 8 bits
—carga de 16 bits
—intercambios, transferencia de bloques y squeda en bloques.
—operaciones aritméticas y lógicas de 8 bits.
—operaciones aritméticas y de control de aplicación general.
—operaciones aritticas de 16 bits.
—rotaciones y desplazamientos.
—operaciones que trabajan con 1 bit.
—saltos
—instrucciones de llamada vuelta y reinicio.
—operaciones de entrada y salida.
145
14 6 DIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
Grupo de carga de 8 bits
NOTAS: r,r' representan cualquiera de los registros A, B, C, D. E, H , L.
[FF signific a que el contenido ([FF) de la báscula de habilitación
de interrupciones se carga en P/V.
Para los diferentes símbolos que se emplean, véase la tabla que
figura al final del apéndice.
CONJUNTO DE INSTRUCCIONES DEL Z80 147
Grupo de carga de 16 bits
dd e s cualquiera de los pare s d e registros BC, DE, H L, SP .
qq e s cualquiera (le los pares de registros A F, BC, DE, HL
(par)h y (par) l se refiere n al byte alto y al byte bajo del
par; po r ejemplo , BCL= C, AFH= A.
148 CÓDIGO MÁQUINA PAR A PRINCIPIANTE S CON AMSTRA D
Grupo de intercambio, transferencia de bloques y
búsqueda de bloques
NOTAS P/ V a 0 si el resultado de BC-1 es 0; P/V .
P/V a 0si se ha completado el recorrido; ]'
a 1 en caso contrario.
Z a I si A = ( H L ) ; Z a 0 en caso contrario.
CONJUNTO DE INSTRUCCIONES DEL Z80 149
Grupo aritmético y lógico de 8 bits
NOTA S : (l) BCD : deci mal c odificado en b inario.
IFF represent a la báscul a de h á b i litación de interrupc iones .
CY r epre se nta el in d i cado r de a rrastre .
* indica q u e las in te rrupciones no son examin ada s al final de DI o EI.
Grupo aritmético y de control de aplicación general
150 DIG O MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
Grupo arittico de 16 bits
NOTA S : SS e s c ualq uier a de lo s pares de registros BC, DE,H L , S P -
pp es cualquiera d e los pa r es de regis tr os B C, DE , I X, S P .
rr e s cualquier a de los par es de regis tros B C , DE, IY , S P.
CONJUNT O DE INSTRUCCIONES DEL Z80 151
Grupo de rotación y desplazamiento
152 CÓDIGO MÁQUINA PARA PRINCIPIANTES CON A M S T R A D
Grupo de manipulación de bits
NOTA : mh representa el bit b ( 0 a 7) del registr o o la posi-
CONJUNT O DE INSTRUCCIONES DEL Z80 153
Grupo de salto
NOTA S: C es la ma gnitud del salt o relativo; es un mero
co n signo del intervalo -1 2 6 . . . 129
e n el código figura c-2 para provocar u n salto de
d e sumarle el desplazamiento
154 CÓDIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
Grupo de llamada y retorno
CONJUNT O DE INSTRUCCIONE S DEL Z80 155
Grupo de entrada y salida
156 CÓDIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
Resumen de los indicadores afectados
Notaciones empleadas
Apéndice B
1000 REM APENDICE B
1010 REM CARGADOR HEX
1020 MODE 1 : PAPER 0 : PEN 1
1030 ER% = 1 : L% = 4
1040 PAPER 0 : PEN 2: PRINT "PONER HIME
M EN";
1050 A% = 0 : B = 0 : GOSUB 1280
1060 IF B > 43900 OR B < 2000 THEN ER% =
1 : GOTO 1250
1070 MM = 43903 : MEMORY B
1080 PAPER 2 : PEN 0 : PRINT " HIMEM
EN "; HEX$(HIMEM,4); " HEX"
1090 L% = 4
1100 PAPER 0 : PEN 2 : PRINT "DIRECCION
INICIAL" ;
1110 A% = 0 : B = 0 : GOSUB 1280
1120 IF B <= HIMEM THEN ER% = 2 : GOTO 1
25 0
1130 IF B > 43903 THE N ER% = 5 : GOTO 12
50
1140 INIC = B : PAPER 2 : PEN 0 : PRINT
" DIR INIC "; HEX$(B,4); " HEX" : P
APER 3 : PEN 1 : PRINT "TECLEE LOS DATOS
" : PAPER 0
1150 IDIR = B
1160 ADIR = IDIR : SUMA = 0
1170 L% = 2
1180 WHILE ADIR < IDIR + 10
1190 GOSUB 1270 : POKE ADIR,B : PEN 2 :
PRINT HEX$(ADIR,4), HEX$(B,2) : PEN 1 :
SUMA = SUMA + B : ADIR = ADIR +1 : IF A
DIR >= MM - 2 THEN ADIR = IDIR + 20
1200 WEN D : IF ADIR = IDIR + 20 THEN ER%
= 4 : GOTO 1250
1210 PAPER 3 : PRINT "TECLEE LA SUMA ";
: PAPER 0 : L% = 4 : GOSUB 1270
1220 IF SUM A <> B THEN ER% = 3 : GOTO 1250
1230 IF FIN = 1 THEN PEN 2 : PAPER 3 : P
RINT " TERMINADO" : PEN 1 : INPUT " MAS?
S/N "; A$ : PAPER 0 : A$ = UPPER$(A$) :
IF ASC(A$) = 83 THEN FIN = 0 : GOTO 108
0 ELSE END
157
158 CÓDIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
1240 IDIR = ADIR : PEN 0 : PAPER 2 : PRI
NT "SUMA "; HEX$(B,4); " CORRECTA ; TECL
EE MAS DATOS" : PEN 1 : PAPER 0 : GOTO 1
160
1250 RESTORE 1390 : PEN 3 : PAPER 1 : FO
R N% = 1 TO ER% : READ D$ : NEXT : PRINT
D$; ", TECLEE OTRA VEZ"; CHR$(7)
1260 PEN 1 : PAPER 0 : ON ER% GOTO 1030,
1090,1160,1030,1090
1270A%=0:B=0:PEN1
1280 INPUT IN$ : PRINT CHR$(11); : IN$ =
UPPER$(IN$) : IF IN$ = "END" THEN 1370
129 0 IF LEN(IN$) <> L% THEN 136 0
130 0
FOR N% = 1 TO L%
1310 A$ = MID$(IN$,N%,1) : IF A$ > "F" O
R A$ < "0" OR ( A$ > "9" AND A$ < "A" )
TH EN 136 0
132 0 IF A$ > "9" THEN A% = ASC(A$) : A%
= ( A% AND &F) + 9 ELSE A% = VAL(A$)
133 0 IF N% <> L% THEN B = B + ( A% * 16
^(L%-N%))ELSEB=B+A%
134 0 NEX T
135 0 RETURN
136 0 PEN 3: PAPER 1 : PRINT "NO ES VALI
DO ,TECLEE OTRA VEZ"; CHR$(7) : PEN 1 :
PAPE R 0 : GOTO 1270
1370
REM
END
1380 FIN = 1 : GOTO 1210
1390 DATA DEMASIADO ALTO O BAJO , AREA D
E LA MEMORIA NO PROTEGIDA, LA SUMA NO C
OINCIDE; DEBE REEMPRENDER LA INTRODUCCIO
N A PARTIR DE LA ULTIMA SUMA , MEMORIA C
OMPLETA , DEMASIADO ALTO
Apéndice C
Conversn de HEX a DECIMAL para el
byíe más significativo
159
Apéndice D
Conversión de HEX a DECIMAL para el
byte menos significativo
HEX
0
1
2
3
4
5
6
7
DEC
0
1
2
3
4
5
6
7
SIN
0000
0001
0010
0011
0100
0101
0110
0111
HEX
8
9
A
B
c
D
E
F
DEC
8
9
10
11
12
13
14
15
BIN
1000
1001
1010
1011
neo
1101
1110
1111
161
Apéndice E
Conversión de HEX en complemento a 2 a
DECIMAL
Para el byte más significativo
Para calcular el valor decimal de un número negativo de 16 bits, se debe
sumar al valor del byte más significativo que proporciona esta tabla (y que
será negativo) el valor del byte menos significativo interpretado sin signo
(luego positivo).
163
1 64 CÓDIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
Para el byte menos significativo
Apéndice F
Mapa de pantalla del Amstrad
El mapa de pantalla del Amstrad CPC464 presenta cierta complejidad. Por
una parte, puede cambiar la dirección en que comienza. Pero, además, resul-
ta que un punto (pixel.) puede estar representado por bits diferentes, segun
el modo de pantalla que se seleccione.
La pantalla ocupa siempre 16K de memoria. Lo normal es que comience
en la posición C000h (49152), aunque también se puede hacer por programa
que comience en 4000h (16384). Para lo que sigue vamos a suponer que co-
mienza en C000h, ya que es poco probable que usted necesite cambiar esta
direccn.
La pantalla está siempre formada por 200 líneas de un punto de altura.
Cada una de estas líneas ocupa 80 bytes consecutivos de la memoria, que co-
menzarán en alguna dirección que será C000h s un múltiplo de 80. Cada
carácter ocupa 8 por 8 puntos. En el modo 2 de pantalla cada punto se co-
rresponde con un bit: si el bit está a 1 el punto será iluminado con el color
de la tinta 1 y, si es a 0, con la tinta 0.
Mientras la pantalla no se haya movido hacia arriba, su esquina superior
izquierda corresponderá a C000h. Los primeros 80 bytes forman la línea de
arriba, pero los segundos 80 bytes no forman la segunda, sino la nea de
arriba de la segunda fila de caracteres, que es la novena linea de puntos. Los
80 bytes siguientes corresponden a la línea 17, y así hasta completar las 25
filas de caracteres. Sólo entonces comienza la segunda línea de puntos. En
la figura de la página siguiente se muestran las direcciones del primero y últi-
mo byte de cada línea de puntos para las primeras 24 líneas (en la posicn
inicial de la pantalla).
El sistema operativo proporciona rutinas que permiten calcular la direc-
ción de un carácter o de un punto. Las direcciones de estas rutinas se dan
en el Apéndice G.
En los modos 1 y 0 se mantiene el orden de los bytes para las líneas de
puntos de la pantalla, pero cambia la forma en que un byte representa deter-
minados puntos . En modo 1 cada byte almacena la información de cuatro
puntos y en modo cero de lo dos puntos. El orden de la representación no
es directo en el interior de cada byte. Un byte representa los puntos en las
formas siguientes:
165
166 DIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
Linea n.º
1
2
3
4
5
6
7
8
9
10
11
12
Dir ección
Izda.
C000
C800
D000
DB00
E000
E800
F000
F80 0
C050
C850
D050
D850
Dch a .
C04F
C84F
D04F
DS4F
E04F
EB4F
F04F
F84F
C09F
ca?F
D09F
D89F
Línea n.°
13
14
15
16
17
18
19
20
2¡
22
23
24
Dir ecció n
Izda.
E05 0
E850
F05 0
FB50
C0A0
C8A0
D0A0
D8A0
E0A0
E8A0
F0A0
FBA0
Dch a.
E09 F
E89 F
F09F
F89 F
C0DF
C8DF
D0DF
D8DF
E0DF
E80F
F0DF
F8DF
Modo 1; puntos de izquierda a derecha
bits 3 y 7 2 y 6 1 y 5 0 y 4
Modo 0; puntos de izquierda a derech a
bits 1,5,3 y 7 0,4,2 y 6
Los bits de cada punto esn dados en orden de significación decreciente res-
pecto de la forma en que componen el código binario que representa el nú-
mero de tinta de cada punto.
Por ejemplo, la dirección C000h cargada con 01010011b representa en
modo 1 cuatro puntos, de los co!ores 0, 1, 2 y 3 respectivamente.
En modo 0, el mismo byte representaría dos puntos de tintas 8 y 13. Para
obtener en este modo cuatro puntos de tintas 0, 1, 2 y 3, se requerirían dos
bytes cargados con
01000000b 01001100b
Cuando la pantalla se desplaza, cambia la dirección del byte de la esquina
superior izquierda. Esta dirección puede oscilar de C000+80 a 80*25 MOD
2048. Afortunadamente, existen rutinas del firmware que establecen la di-
rección en que comienza la pantalla (véase el apéndice G).
Apéndice G
Dirección de las rutinas más usuales
sistema operativo
En los programas del libr o hemos utilizado algunas de las rutinas del sistema
operativo. La que hemos utilizado con la etiqueta GETKEY (BB18h) es la
que suele llamarse 'wait key'; corresponde al área del firmware llamada
'KEY MANAGER', que agrupa una serie de rutinas para el control del te-
clado. La que se utilizaba con la etiqueta PRINT (BB5Ah) es la rutina 'text
output' que corresponde a! área 'TEXT VDU' que agrupa rutinas relativas
a la pantalla de texto. Hay otras siete áreas, que llevan los nombres de
'GRAPHICS VDU', 'SCREEN PACK', 'CASSETTE MANAGER',
'SOUND MANAGER', 'KERNEL', 'MACHIN E PACK' y 'JUMPER'.
Este apéndice contiene la dirección de las rutinas del firmware que se utili-
zan con mayor frecuencia. La primera columna del texto contiene las direc-
ciones; la segunda, una breve descripcn del efecto de la rutina; la tercera,
los registros que modifica la rutina.
Dirección de
llamada
Geslor del teclado
BB00 Inicializa completamente el gestor del teclado
BB12 Lee un carácter de una cadena de expansión. Entrada: A
contiene el código del carácter expandible y L el número
carácter que se va a leer en la cadena. Salida: A contien e
el cacter ldo y arrastre a 1; o bien, A corrupt o y arras-
tre a 0 si el carácter no era expandible o la cadena no era
suficientemente larga.
BB18 Espera por una pulsación del teclado. Salida: A contien e
el carácter leído yarrastre a 1.
BB1B Examina el teclado sin espera r pulsacn. Salida: A con-
tiene el carácter leído y arrastre a 1; o bien, A corrupt o
y arrastr e a 0 sí no se había pulsad o ninguna tecla.
Registros
modificados
AF BC DE HL
AF D E
A F
A F
167
168 CÓDIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
Dirección de
llamada Función Registros
modificados
BI31E Examin a una tecla concreta . Entrada: A=n.° de tecla. AF H L
Salida: indicador Z a 0 si la tecla est á pulsada, y a 1 si no
lo está. Siempre: arrastre a 0 y el registro C contiene el
estad o actual de SHIFT y CTRL.
BB24 Examina e l estado de los joysticks. Salida: A y H contie- A F HL
nen el estado de JOY0; L contiene el estado de JOY1.
Significado de los bits : 0, arriba; 1, abajo; 2, izquierda;
3, derecha; 4, disparo 2; 5, disparo 1; 6, no asignado; 7,
siempre a 0.
Pantalla de text o
BB4E
BB5A
BB60
BB75
Inicialización completa . A F BC D E H L
En a un carácter o código de control a la pantalla. En- Ninguno
trada : A=código del carácter.
Lee en la pantalla el carácter que ha y e n la posición actua l A F
del cursor. Salida: si se encuentra un carácter legible, A
contiene e l código y arrastr e se pone a 1.
Coloc a el cursor en la columna señalad a por H y l a fila AF HL
señalad a por L.
La mayor parle de las restantes acciones sobr e la pantalla de texto se pueden realizar escri-
biendo e n ell a códigos de control. ase e l Manua l del Usuario.
Pantalla gráfica
A F BC D E HL
BBBA Inicialización completa
BBC9 Establece e l origen de coordenadas gráficas en e l punto AF BC DE HL
señalado por DE (x) y HL (y).
BBDE Asigna tinta a l a pluma gráfica. Entrada : A= n. ° de tinta. AF
BBEA Dibuja e l punto de coordenadas absolutas dadas por DE A F BC DE HL
(x) y HL (y).
BBF6 Dibuja una recta desde l a posición actual hast a la sala- AF BC D E HL
da por DE (x) y HL (y).
BBFC Escribe en la posicn actua l del cursor gráfico el carácter AF BC DE HL
cuyo código está contenido en A .
Gestor de la pantalla
BBFF Inicializació n completa A F BC D E HL
BC05 Establece l a dirección de comienzo de la memoria de la AF H L
pantalla. Entrada; H L=n . ° de bytes en que hay que des-
plazar es a dirección. Este número debe ser par; l a rutina
lo toma MOD 80.
DIRECCIÓN DE LAS RUTINAS MÁS USUALES DE L SISTEMA OPERATIVO 169
Dirección de Registros
llamada Funció n modificados
BC1A Convierte ¡a coordenadas físicas de entrada e n una direc- AF
ción de la memoria de l a pantalla. Entrada: H = número
de columna; L= númer o de fila. Salida: HL= dirección
del extremo superior izquierdo del carácter ; B = número
de bytes de memoria requerido para representar un cac-
ter en ¡a memoria de la pantalla.
Para las cuatro rutina s siguientes, el par HL debe contener la dirección de una posición de
la pantalla , y el resultado se entrega en e l propio par HL. Si el movimiento se va fuera de
la pantalla, las rutinas no advierten de ello.
BC20 Desplaza la dirección de memoria de la pantalla un byte AF
hacia la derecha.
BC23 Desplaza ¡a dirección de memoria de la pantalla un byte AF
hacia a izquierda.
BC26 Desplaza la dirección de memoria de la pantalla un byte A F
hacia abajo.
BC29 Desplaza la direcc n de memoria de la pantalla un byte Al-
nad a arriba.
BC38 Establece como colores para e l borde los contenidos e n B A F BC DE HL
y C
BC3E Establece periodos de parpadeo (el contenid o e n H para A F H L
el primer color y el de L para el segundo) .
Gestor del cassette
BC6 5 Inicialización completa A F BC DE H L
Par a manejar el magnetófono o el generado r de sonidos mediant e las rutinas del firmware,
ha y que conocerla s previamente muy a fondo . Le sugerimos que maneje estas cosas desde
BASIC, aunque vuelva posteriormente al digo de máquina con un CALL. Recuerde que
sól o podr á volver desde código de máquina a un programa BASIC cuando provenga de di-
cho programa .
BD2B Ena a la puerta Centronics (impresora ) el carácter con- AF
tenido en A (ignorando el i)il 7). Salida: arrastre a 1 si se
ha podido enviar el carácter, a 0 e n caso contrarío.
BS37 Restaura ¡as direcciones del grupo de saltos. AF BC DE H L
Las rutinas que hemos presentado son sólo algunas de entre los centenares
que existen. El 'Firmware Specification Manual (SOFT 158)' de Alustrad,
le proporciona el detalle de todas las rutinas del firmware y una ligera expli-
cacn del hardware. Debe adquirir este manual si desea programar seria-
mente en código de máquina.
índice
A 18, 20, 39-58, 80, 120, 123
a0 42
acumulador 18, 39-58, 80
ADC 39-58, 84
ADD 39-58, 61, 84
ADD A,A 96
ADD A,(HL) 44
ADD A,n 42
ADD A,r 43, 44
ADD HL,HL 103
ADD HL,SP 84
address bus 125-128
add/subtract 59-69
AF , par 80
AND 71-78
AND A 51, 56, 58
AND #DF 74
Aritmética 39-58, 84
operaciones 61
arranque en frío 29, 83, 129
arrastre 46, 71
bit de 58
indicador de 43, 58, 59-69, 78, 89,
96
ASCII 9
códigos 62
autoticas, instrucciones 113
B 18, 20, 27, 44
BASIC 141-144
BC 24, 25, 27, 80, 117, 120, 121, 123
BCD {Binary Coded Decimal) 111
binary counter 113
BIT 87-93
bit 7, 87-93
0 8, 88
7 88
más significativo 8, 28
menos significativo 28
bloques de salto 141-144
bus de datos 125-128
bus de direcciones 125-128
búsqueda, instrucción de 113-123
byte 7
C 18, 20, 27, 43, 44, 47, 59-69, 77
CALL 11, 29-33, 37, 69, 79-86
CALL 47876 65
carga 83
instrucciones de 17-29
CARGADOR HEX 11, 12, 44
carry 47
flag 43, 59-69
CCF 51, 69, 73
cero, indicador d e 42, 58, 59-69, 89,
117
CLP 71-78
codificacn binaria de los números
decimales 111
código{s)
ASCII 62
nemotécnicos 10
objeto 10
comparación 59-69
complementación 75
complementario, valor 51
complemento a dos 8, 67
representación en 8
171
172 DIGO QUINA PARA PRINCIPIANTES CON AMSTRAD
contador binario 113
contador de programa 18, 29-33
posición 36
CP 59-69
CPD 113-123
CPDR 113-123
CPI 113-123
CPIR 113-123
CPL 75, 77
D 18, 20, 27, 44
data bus 125-128
DE 25, 80, 113, 116, 121, 123
DEC 39-58, 61, 84
DEC (HL) 39
DEC SP 84
decima l 7
decisiones condicionadas 59
DEFB 11
DEF M 11
DEFS 11
DEF W 11
desplazamiento 95-112
arittico 95-112
lógico 95-112
DI 129-133
diagramas de flujo 13-15
dirección 9
direccionamiento indexado 135-140
dividir 99
división 102
DJNZ 59-69, 113
E 18, 20, 27, 4 4
editor 10
El 129-133
enmascarar 74
ensamblador 10
ENT 11
entrada 125-128
EQU 11
E/S 127
escritura transparente 7 5
estado, registro de 80
etiquetas 10
EX 36, 85
exchange 36, 85
EX DE,HL 36
EX (SP),H L 79-86
F 42, 80
firmware 3
flag 42, 59-69
flujo, diagram a de 13-15
fuente, programa 10
H 18, 20, 27, 28, 37, 44, 59, 69
half carry 59-69
HALT 129-133
hexadecimal , sistema 8
hexadecima l y binari o 7
high 37
HL 24, 25, 34, 37, 39, 80, 85, 113,
116, 120, 121, 123
IM 0 130
IM 1 129
IM2 129
IM3 129
IN 125-128
INC 39-58, 61, 84
IN C (HL) 39
indicador 42, 58, 59-69
de arrastre 43, 58, 59-69, 78, 89, 96
de cero 42, 58, 59-69, 89, 117
d e paridad 71 , 7 8
de paridad/sobrepasamiento 59-69
P/V 71, 78, 112, 120, 123
de semiarrastre 59-69
de signo 59-69
indicadores 71, 75, 77
índice, registros 135-140
indexado, direccionamiento 135-140
input 125-128
intercambio 36, 85
intérprete 3, 4
interrupción 129-133
modos de 129-133
interrupciones 129-133
instrucciones
aritticas 39-58
automáticas 113
de búsqueda 113-123
de carga 17, 29
lógicas 71
de salto 33-36
I/O 127
IX 135-140
IY 135-140
joysticks 143
JP 30, 33-36, 69
JP (HL) 37
JP nn 37
JR 30, 33-36, 69
JR n 37
jump 30, 33-36
jump-blocks 141-144
jump, relative 33-36
L 18, 20, 27, 28, 37, 44
LD 17-29, 36, 61, 69
LD A 17-29
LD A,{HL) 17-29, 37
LD A,(nn) 17-29, 37
LD A,(rr) 27
LD B 24
LD BC,(nn) 28
LD DE,(nn) 28
LD H L 24
LD (HL),A 17-29, 37
LD HL,(nn) 27
LD (HL),r 25
LD (nn),A 17-29, 37
LD (nn),BC 28
LD (nn),DE 28
LD (nn),HL 27
LD (nn),rr 17-29, 37
LD r,(HL) 25
LD r,n 17-29, 3 6
LD r,r' 17-29, 37
LD (rr),A 27
LD rr,n n 17-29, 37
LD rr,(nn) 17-29, 37
LDD 113-123
LDDR 113-123
LDI 113-123
LDIR 113-123
listados de ensamblador 12
llamada s 29-33
llamar 30
load 18
gicas, instrucciones 71
gicas , operaciones 71-78
low 37
M 59-69
m 112
mandos de juego 143
mapa de pantalla 75, 165-167
método de restauracn 109
microprocesado r Z80 2
minus sign 59-69
modo 0 75, 165-167
mod o 1 75, 165467
modo 2 75, 165-167
modos de interrupcn 129-133
multiplicación 99
multiplicar 99
N 59-69
n 36, 58, 69, 77, 86, 112, 123
NC 43, 59-69
nn 36, 58, 69, 77, 86, 112, 123
(nn) 22
NE G 71-78
negación 77
negativos, números 8
nemotécnicos, códigos 10
NOP 50, 72
no sobrepasamiento 59-69
número s negativos 8
NZ 59-69
objeto, programa 10
174 DIGO MÁQUINA PARA PRINCIPIANTES CON AMSTRAD
Operaciones
aritticas 61
de E/S 127
lógicas 71-78
OR 71-78
OR #20 73
OR #30 75
ORG 11
OUT 125-128
output 125-128
overflow 59-69
P 59-69
palabras 7
pantalla 143
mapa de 75
par AF 80
BC 25, 27 , 113
DE 25, 27, 36
HL 25, 27, 36
pares 24
parida d impa r 59-69
paridad, indicador de 71, 7 8
paridad par 59-69
paridad/sobrepasamiento, indicador
de 59-69
parity even 59-69
parity odd 59-69
parity/overflow fiag 59-69
Pascal 141-144
PC 18, 20, 29-33, 35, 36, 58, 69, 77,
86, 112, 123
PE 59-69
pila 31-79-86
pixels 75
plus sign 59-69
PO 59-69
POP 79-86
port 127
programa
contador de 29-33
fuente 10
objeto 10
program counter 29-33
puerta 127
puntero de pila 31, 79-86
punto de entrada 10
punto s 75
PUSH 79-86
P/V 59-69 , 77, 117, 118, 120, 123
indicador de 78
r 25, 36, 58, 69, 77, 86, 112, 123
RAM 141
registro (s) 133-135
acumulador 39-58
de destino 21
de estado 21
índice 135-140
de origen 21
reinicio 133-135
RES 87-93
restart 133-135
restauración, método de 109
restoring 109
RET 29-33, 37, 69, 79-86
retardo 133
RETI 130, 131
retum 30
RL 95-112
RLA 95-112
RLC 95-112
RLCA 95-112
ROM 141
rotación 95-112
circular 95-112
RR 95-112
rr 24, 27, 36, 58, 69, 77, 86, 112, 123
RRA 95-112
RRC 95-112
RRCA 95-112
RST 133-135, 142
RST 56 (38H) 130
rutina del servicio de
interrupciones 129-133
S 59-69, 77
salida 125-128
salto 30, 33-36
instrucciones de 33-36
Salto
magnitud 37
relativo 33-36, 37
SBC 39-58, 61, 84
SCF 51, 69
SET 87-93
seudo-operaciones 11
signflag 59-69
signo
indicador de 59-69
positivo 59-69
negativo 59-69
sin signo 8
sistema
hexadecimal 8
operativo 3, 141, 144
SLA 95-112
sobreescritura 74
sobrepasamienío 59-69, 71 , 77
indicador de 59-69
sonido 143
SP 31, 36, 58, 69, 77, 79-86, 112,
SRA 95-112
SRL 95-112
stack 79-86
stack pointer 31, 79-86
SUB 39-58
SUB (HL) 44
CONJUNT O DE INSTRUCCIONE S DEL Z80 175
SUB n 42
SUB r 43, 44
suma/resta, indicador de 59-69
transferencia de bloques 113-123
TXT OUTPU T 30
valor complementario 51
volver 30
vuelco de pantalla 138
WAIT KEY 65
XOR 71-78
XOR #FF 75
23 Z 59-69, 77
zero flag 42, 59-69
Z80, microprocesador 2
( ) 36, 58, 69, 77, 86, 112, 123
$ 36

Navigation menu