PROGRAMACION AVANZADA
     DEL ZX SPECTRUM
Rutinas de la ROM y Sistema Operativo

 Programación 
   avanzada del 
  ZX Spectrum

Rutinas de la ROM 
y Sistema Operativo
 Steve Kramer
ANAYA MULTIMEDIA

MICROINFORMATICA
Título de la obra original :
THE SPECTRUM OPERATING SYSTEM
Traducción de: Fernando García 
Diseño de colección: Antonio Lax 
Diseño de cubierta: Narcís Fernández
Reservados todos los derechos. Ni la 
totalidad ni parte de este libro puede 
reproducirse o transmitirse por ningún 
procedimiento electrónico o mecánico, 
incluyendo fotocopia, grabación magné-
tica o cualquier almacenamiento de in-
formación y sistema de recuperación, sin 
permiso escrito de Ediciones Anaya 
Multimedia, S. A.
© Steve Kramer, 1984
Primera edición, 1984
Micro Press
Castle House, 27 London Road 
Tunbridge Wells, Kent
© EDICIONES ANAYA MULTIMEDIA, S. A., 1985 
Villafranca, 22. 28028 Madrid
Depósito legal: M. 23.786-1985
ISBN: 84-7614-029-0
Imprime: Anzos, S. A. Fuenlabrada (Madrid)

1.   Introducción		7
2.   Direcciones de llamadas útiles y cómo usarlas: la ROM de 16K		11
3.   La ROM del Interfaz de 8K		31
4.   Las variables del sistema		45
5.   Puertos y canales de entrada y salida 		61
6.   Usando las interrupciones		69
7.   Extendiendo el BASIC con el Interfaz 1		75
8.   El calculador		81
Apéndice A. Conversión de hexadecimal a decimal	  	93
Apéndice B. Mapa de memoria del Spectrum	  	95
Apéndice C. Mapa de pantalla del Spectrum 		96
Apéndice D. El mapa del teclado 		98
Apéndice E. El juego de caracteres del Spectrum 		99
Apéndice F. Vectores de interrupción de la ROM		101
Apéndice G. Subrutinas útiles		103
Indice alfabético		126
_______
            5
 Indice

 

       1
Introducción
        Aunque este libro está dirigido, en principio, a aquellas personas que tienen 
ya algún conocimiento de la programación en lenguaje ensamblador, hay 
también una gran cantidad de información que podrá ser usada por los 
programadores inexpertos, a los que les gustaría poder tener acceso a la 
versatilidad del código máquina, aun sin conocerlo. Si usted pertenece al último 
grupo, yo espero que este libro le abra el apetito, y le sugiero que comience a 
aprender un poquito sobre la programación en lenguaje ensamblador. Con unos 
mínimos conocimientos y usando las rutinas de los capítulos siguientes se 
pueden escribir y usar fácilmente rutinas pequeñas en código máquina.
        Para aquellas personas no familiarizadas con el sistema operativo del 
Spectrum o que prefieran, como yo, seguir el sistema cómodo usando las 
rutinas de la ROM y otras facilidades existentes --en vez de reinventar la rueda 
cada vez que quieren escribir un programa- discutiré cómo usar las llamadas a 
la ROM en las dos, en la de 16K en el Spectrum y en la de 8K en el interfaz 
del microdrive.
        En algunos casos, daré ejemplos y descripciones de cómo usarlos, excepto 
donde sean una simple llamada (CALL).
        Examinaré también las variables del sistema, enseñaré cómo usarlas en 
nuestro beneficio y explicaré el uso de las rutinas basadas en interrupciones; que 
permiten que los sprites puedan ser usados en el Spectrum estándar.
        A no ser que usted desee convertir a mano las rutinas en ensamblador en 
números y los introduzca en la memoria de su ordenador a base de pokes,                	º
   _______
               7

 
existe un requisito necesario para ser capaz de usar este libro, es un programa 
ensamblador. Yo puedo recomendarle el Picturesque Editor Assembler y también 
sus programas monitor/desensamblador; son fáciles y rápidos de usar. También 
le puedo recomendar el Hisolft Devpack 3, que probablemente habrá sido 
mejorado cuando usted lea este libro. Para los usuarios más experimentados, el 
Devpack (que contiene el monitor/desensamblador y el editor/ensamblador) es, 
en mi opinión, el mejor hasta ahora. Las últimas versiones de ambos programas 
son compatibles con el Microdrive.
        No es mi intención enseñar a programar en lenguaje ensamblador, cuando 
hay gran cantidad de libros sobre este tema que lo cubren con detalle. Puedo 
recomendarle el siguiente, Programación del Z80, escrito por Rodnay Zaks y 
editado por Anaya Multimedia. El primero no está dirigido al Spectrum, pero va 
más lejos en detalles que el segundo y también tiene descripciones concisas de 
todos los códigos de operaciones disponibles.
        Para llamar a un programa en código máquina desde el BASIC usted 
puede usar una instrucción RANDOMIZE USR NN, un PRINT USR NN o 
un LET V = USR NN, donde NN es el punto de entrada en el programa de 
código máquina y V puede ser una variable numérica. A la vuelta de la rutina 
del código máquina, la variable en la instrucción LET será igual que el 
contenido del par de registros BC al salir de la rutina, y con la instrucción 
PRINT el valor de estos registros será impreso en la corriente actual. En todos 
los casos, el par de registros BC contendrá NN en la entrada a la rutina en 
código máquina.
        Siempre que un programa en código máquina es llamado, es conveniente 
salvar el contenido del par de registros H'L', pues el contenido de éstos será 
necesario para lograr que el control se devuelva al programa BASIC. El par de 
registros IY no deberá ser usado normalmente debido a que la ROM lo usa 
para indexar las variables del sistema, pero puede ser usado durante el tiempo 
en que estén desconectadas las interrupciones y ninguna de las rutinas ROM se 
use antes de que vuelva a contener 23610 (5C3Ah).
        Este libro tiene la intención de ser un manual de referencia, al que podrá 
acudir en busca de información mientras que utilice su Spectrum. He procurado 
no extenderme mucho en el texto principal, pero espero que encuentre en él la 
información que necesite. Obviamente, sería imposible detallar todas las rutinas 
de la ROM y todas sus utilidades, así que he seleccionado aquellas que 
considero de uso más frecuente y las más útiles. Más adelante, los programado-
res avanzados pueden leer el libro Complete Spectrum ROM Disassembly, del 
Dr. Ian Logan.
_______
8

 

2 
Direcciones 
de llamadas útiles 
y cómo usarlas: 
la ROM de 16K
        Es importante, antes de usar rutinas de la ROM, salvar siempre los 
registros H' y L' y devolverles su valor inicial antes de volver al BASIC. El 
registro IY debe contener siempre la dirección de la variable del sistema ERR 
NR 23610 (5C3Ah) cuando se usa una rutina de la ROM.
Impresión: RST 16 (10h)
        El carácter cuyo código está en el registro A será impreso en la corriente 
que actualmente esté abierta. También se pueden usar los códigos de control de 
impresión (TAB, INK, OVER, etc.). Ver el manual del Spectrum para más 
detalles).
Abriendo y cerrando corrientes
(para RST 16 (10h)) : CALL 5633 (1601h)
        CALL 5633 (1601h) hace que la dirección de salida usada por RST 16 (10h) 
sea el canal indicado por el contenido del registro A cuando se llama a esta 
rutina. Normalmente, A = 2 imprimirá en la pantalla principal, A = 3 lo hará 
por la impresora y A = 1 o imprimirá en la pantalla inferior. Con el Interfaz 1                    
_______
          11

 
conectado, otras corrientes pueden ser usadas para los Microdrives, red local u 
otros mecanismos. Los detalles de cómo desviar las corrientes para sus propios 
fines (por ejemplo: para controlar un interfaz con otros usos, tal como el 
Kempston u otro interfaz de impresora Centronics) los encontrará en la sección 
Expandiendo palabras clave para salida, en este mismo capítulo.
Detectando si la tecla Break está siendo pulsada : 
CALL 8020 (1F54h)
        Esta llamada volverá con la bandera de acarreo puesta si la tecla BREAK 
no está siendo pulsada, y bajada si está siendo pulsada. (Nota: Esto comprueba 
si CAPS SHIFT y SPACE están siendo pulsadas simultáneamente.) Si usted 
quiere comprobar si sólo se pulsa SPACE, vea la sección Tomando un carácter 
del teclado para obtener más detalles; de momento puede usar:
A047  3E7F 	10 	LD 	A, ,#7F
A049  DBFE 	20 	IN 	A,  (#OFE) 
A04B  1F 	30 	RRA
A04C  D24CAO 	40 	JP	NC, PULSADA
Colocando la posición de impresión para usar 
con RST 16(10h): CALL 3545 (DD;h)
        Esta rutina requiere que el registro B contenga el número de línea de la 
pantalla en la forma siguiente:

        B = 24 - número de línea
(por ejemplo si B = 24, esta es la línea superior de la pantalla; si B = 1 es la 
línea inferior). Desafortunadamente, debido a una omisión en la escritura de la 
ROM, usted no puede usar las líneas 23 y 24 para imprimir en la pantalla 
principal; de modo que para usar la sección inferior debe establecer la corriente 
de salida para que RST 16 (10h) sea 1 y usar las dos líneas superiores de la 
pantalla inferior .
C = 33 - número de columna
(por ejemplo: si C = 33, esta es la columna más a la izquierda; si C = 2, es la 
más a la derecha).
        Esta llamada actualiza automáticamente las variables del sistema con las 
posiciones de impresión en cualquier corriente que esté usando, como indicó al 
llamar a 5633 (1601h). Hay que tener cuidado al trabajar en la última línea de 
la pantalla principal, pues un mensaje scroIl será generado después de imprimir 
en la última posición disponible. Esto producirá un retorno al BASIC, si se 
pulsa "n" o SPACE. Además, todo intento para imprimir en la corriente 1 
causará un aumento de la pantalla inferior cuando el espacio disponible
_______
12

 
indicado por la variable del sistema DF SZ (23659) haya sido llenado. Esto 
puede producir algunos resultados inesperados.
        Obviamente, cuando se usa la impresora, uste no puede indicar un número 
de línea; por tanto, no se usa el registro B.
Borrando la pantalla (toda la pantalla): 
CALL 3435 (D6Bh)
        Esta llamada borrará toda la pantalla y reinicializará los atributos con los 
datos contenidos en la variable del sistema ATTR p para la pantalla principal y 
BORDCR para la pantalla inferior (23693 y 23624, respectivamente; ver el 
manual del Spectrum para más información).
Borrando la pantalla (pantalla inferior) : 
CALL 3438 (D6Eh)
        Esta rutina borrará solamente la pantalla inferior y reinicializa los atributos.                    
        Nota: 3435 (D6Bh) y 3438 (D6Eh) reinicializan DF SZ a 2 y pueden 
corromper los datos del canal usado actualmente por RST 16 (10h), que, por 
tanto, necesitará ser reinicializado. Las posiciones actuales de impresión se 
colocan en la parte superior izquierda de las respectivas pantallas.
Desplazamiento vertical de la pantalla : 
CALL 3582 (DFEh)
        Esta rutina desplazará la pantalla hacia arriba una línea, pero no afectará a 
la posición de la impresión actual. Por tanto, si imprime continuamente en la 
misma posición, desplazando el texto al final de cada línea, conseguirá un efecto 
parecido al de teclear en una máquina de escribir (la impresión tiene lugar en la 
parte inferior y el texto se desplaza hacia arriba cuando se hace un retorno de 
carro ).
Dibujando en la pantalla: CALL 8933 (22E5h)
        El punto indicado por el registro B (Y 0 - 175) y por el registro C (X 0 
- A255) será dibujado en la pantalla. los colores de la tinta y el papel (INK y 
PAPER) pueden ser colocados previamente cargando las variables del sistema 
correspondiente con los atributos de los colores requeridos, o si no se usarán 
los actuales. OVER 1 puede ser colocado con SET 0, (IY + 87) o quitado con 
RES 0, (IY = 87) y cualquier punto se puede borrar con SET 2, (IY + 87).
        Nota: Es perfectamente posible dibujar en la pantalla inferior, y esto puede 
ser anulado, si no se necesita, poniendo la corriente requerida con el CALL 
5633 (1601h).
_______
          13

 
Sacando un número por una corriente
        Esta es la rutina más complicada hasta ahora, y no hay una dirección de 
llamada única. Hay una rutina en la ROM que toma un número de 16 bits de 
dos direcciones y lo saca en forma decimal, pero esta rutina tiene la desventaja 
de que los bytes deben ser almacenados al contrario que como lo hace el Z80. 
Esto significa que debe cargar el número en un par de registros, y a continua-
ción volverlo a almacenar en memoria con el orden invertido (el byte más alto 
primero ). Un programa corto como el que sigue valdría :
A06C	ED5B6CA0	1 		LD	DE, (direccion_num) 
A070	2170A0	9 		LD	HL, MEMORIA_LIBRE 
A073	72 	17 		LD	(HL), D
A074	23 	25 		INC	HL
A075	73 	33 		LD	(HL), E
        La rutina de la ROM en 6696 (lA28h) puede ser llamada ahora con HL 
señalando a la dirección PALABRA TEMPORAL, que será sacada en ASCII 
por la corriente actual, pero hay dos inconvenientes :
     1. Sólo saldrá correctamente si es menos que 10.000 decimal, y debe ser 
          un entero.
2. El número saldrá con espacios por delante, de modo que si se intenta 
     unir todas las salidas para crear un número mayor, sólo funcionará si 
     cada número de salida está entre 1000 y 9999; de otro modo serán 
     introducidos espacios en medio.
        Aquellos que tengan el Spectrum Pocket Book y hayan leído algo sobre esta 
dirección de llamada, pero no la hayan usado, estarán llamándome idiota. En 
este libro, el autor indica que el registro E controla cómo se formatea el 
número; pero si usted ha usado la rutina, sabrá que esto no es cierto, ya que el 
registro E es ignorado. Hay dos soluciones a este problema.
        Primero podría escribir su propia rutina para saltarse la primera parte de 
la rutina de la ROM; de este modo:
A07B	D5	1 	PUSH	DE 
A07C	56	34 	LD	D,  (HL) 
A07D	23	67 	INC	HL 
A07E	5E	100 	LD	E,  (HL) 
A07F	E5 	133 	PUSH	HL 
A080	EB 	166 	EX	DE, HL 
A081	1E20 	199 	LD	E, #20 
A083	C3301A 	232 	JP	#1A30
        Nota: La última instrucción ha de ser un salto (JP), y la rutina que usted 
ha escrito ha de ser llamada con un CALL; de otro modo la pila se desorgani-
zará, ya que la dirección de retorno está almacenada en ella y la rutina extrae 
(POP) lo que haya introducido (PUSH). Puede ver que el registro E es cargado 
en su rutina (borrando previamente cualquier dato que hubiera), y como ésta es 
un duplicado del principio de la rutina en ROM, usted puede ver ahora por              
_______
14

 
qué el Spectrum Pocket Book está equivocado. Ahora puede cambiar la instruc-
ción LD E, de esta rutina para que sea 48 decimal, en cuyo caso se imprimirán 
ceros delante del número, ó 255, que hará que no se imprima ninguna cifra no 
significativa.
        "Pero, espere un minuto -estará diciendo usted-, ahora puedo ver por 
qué se debe cambiar el orden de los bytes." Correcto. Si se invierte el orden de 
carga del par de registros DE o, lo que es igual, se carga HL directamente, el 
número no ha de ser invertido; por tanto, vale la pena reescribir esta corta pieza 
de código para incorporarla, dentro de su propio programa, como una subrutina 
para imprimir números.
        Hay otra parte de esta rutina en la ROM que merece ser considerada en 
este punto, y es la parte que comienza en 1A1Bh. Esta simplemente toma el 
número del par de registros BC y lo imprime sin ceros ni espacios, mucho más 
útil en algunos casos.
        Con un pequeño trabajo adicional, estas rutinas le dan ahora la posibilidad 
de imprimir cualquier tipo de número desde su programa. Sin embargo, es 
probablemente más fácil usar las rutinas que toman un valor de la pila del 
calculador (para más detalles, ver el capítulo 8).
Tomando un carácter del teclado
        La instrucción RST 56 (38h) es usada por el Spectrum al examinar el 
teclado y actualizar las variables del sistema FRAMES, y es llamada por la 
rutina de la interrupción enmascarable. Si todo lo que se quiere es ver si se ha 
pulsado una tecla, puede examinar el bit 5 de FLAGS 23611 (5C3Bh); si el bit 
está a 1, una tecla ha sido pulsada desde que fue puesto a 0 la última vez. 
Téngase en cuenta que el bit 5 necesita ser puesto a 0 expresamente.
        El código de la última tecla pulsada puede encontrarse en 23560 (5C08h) 
LAST K, detallado en el capítulo 4. Esto es suficiente para conseguir entrada 
desde el teclado, pero tiene desventajas.
        Primero, es actualizado sólo 50 veces por segundo ( 60, si la frecuencia de la 
red es de 60 Hz, como en USA), de modo que usted no puede hacer una 
instrucción RES 5 y examinar inmediatamente el bit, ya que es casi seguro que el 
teclado no habrá sido examinado porque no se habrá producido una interrup-
ción; por otra parte, si las interrupciones están inhabilitadas, el teclado nunca 
será examinado, a no ser que usted lo haga. Esto se puede realizar así :
A177	213B5C 	10 		LD	HL,  23611  ; variable del sistema FLAGS
A17A	CBAE 	20 		RES	5,  (HL)
A17C 	3EFF 	30 		LD	A,  #FF
A17E 	32005C 	40 		LD	(23552),  A  ; 23552 es parte de la
 		       45	;	 		                variable del sistema KSTATE 
A181 	E5 	50 		PUSH	HL
A182 	FF 	60 		RST 	56
A183 	El 	70 		POP	HL
A184 	AF 	80 		XOR	A
A185 	CB6E 	90 		BIT 	5,  (HL)
A187 	CA8DA1	100 		JP	Z,  NINGUNA_TECLA
A18A	 3A085C 	110 		LD	A,  (23560)   ; variable del sistema LAST KEY 
A18D	 00 	120	NINGUN 	NOP	;  lo que se quiera poner
_______
          15

 
        Esta rutina devolverá en el registro A el código de la tecla que está siendo 
pulsada, o 0 si no hay ninguna. En la rutina anterior, la instrucción LD 
HL,23611 podría ser omitida, y en su lugar se podría examinar (IY + 1), ya que 
el registro IY contiene la dirección de la variable del sistema ERR NR (23610) 
(5C3Ah) y es usado por la ROM para direccionar las variables del sistema. 
Debido a esto, si usa el registro IY en sus programas, debe asegurarse de que 
las interrupciones están inhabilitadas o dirigidas a sus propias rutinas, y debe 
reinicializar también el registro IY a la dirección correcta antes de usar la ROM 
o de colocar las interrupciones en su estado normal.
        El segundo problema es que usted no puede examinar más de una tecla 
pulsada a la vez. Esto es debido a que si una combinación de teclas es 
pulsada, y no es ningún carácter válido, el Spectrum la ignorará.
        Para evitar esto, necesitará escribir su propia rutina para examinar el 
teclado. En primer lugar, si usted sólo quiere saber si una tecla está siendo 
pulsada, sin preocuparse de cuál o cuántas teclas son, podría hacer algo así :
	A16B	AF	10		XOR	A  ; 	  se asegura que A contiene
			15	; 			  0 para explorar todas las teclas
	A16C	DBFE 	20 		IN	A, (#FE)  ; FE es el puerto de
			25	;			  entrada del teclado y otros.
	A16E	161F	30 		LD	D, 31
	A170	A2	40		AND	D  ;	  elimina los otros (3 bits altos)
	A171	AA	50		XOR	D  ; 	  invierte los bits restantes
 	A172	28FE 	60 		JR	Z, NINGUNA_TECLA
        El teclado puede ser examinado más detalladamente, para descubrir qué 
teclas están siendo pulsadas, cargando el registro A con el valor de las líneas a 
examinar antes de la instrucción IN A, (FEH).
        El capítulo 23 del manual del Spectrum explica cómo está dispuesto el 
teclado, y también se señala en el apéndice D de este libro, pero el esquema 
resumido es el siguiente. El primer carácter, en todos los casos, es el BIT 0, y el 
último el BIT 4; el número hexadecimal ha de ponerse en el registro A para 
poner a 1 el bit de la línea que se quiere examinar :
CAPS SHIFT-V	FEH
A-G 	FDH
Q-T 	FBH
1-5 	F7H
0-6	 EFH
P-Y 	DFH
ENTER-H 	BFH
SPACE-B 	7FH
Así, por ejemplo, para comprobar si se está pulsando la tecla ENTER, se 
usaría el siguiente programa :
 A050	3EBF 	1 	LD 	A, #OBF
 A052	DBFE 	2 	IN 	A, (#0FE)
 A054	E601 	3 	AND	1
 A056	28FE 	4 	JR 	Z, ENTER_PULSADA
_______
16

 
        Para ver si se está pulsando más de una tecla, puede usar los operadores 
lógicos AND, OR, etc., si están en la misma línea, o las instrucciones, para 
comprobar bits. Vea a continuación CALL 5598 (15DEh) para conseguir 
fácilmente caracteres normales.
Esperar entrada: CALL 5598 (15DEh)
        Esta es una de las rutinas más útiles, permite la entrada desde cualquier 
corriente con dirección de entrada. Antes de usar la corriente desde la cual se 
pide entrada, debe abrirse con la rutina en 5633, descrita anteriormente. Cuando la 
rutina Esperar entrada es llamada (CALL), llama a continuación a la rutina de 
entrada del canal actual. Cuando se vuelve de ésta se comprueba la bandera de 
acarreo; si está puesta, el control se devuelve al programa principal. Si la 
bandera de acarreo no está puesta, se comprueba la bandera 0, y si está puesta, 
el proceso se repite.
        La rutina es usada por el Spectrum como control de la subrutina de 
entrada actual, normalmente la entrada por teclado; pero si CURCHL está 
puesto señalando a un canal con la dirección de entrada apuntando a su propia 
subrutina, esta será usada (cómo hacer esto se explica en el capítulo 5). Cuando 
se utiliza con la corriente 1 (el teclado y la pantalla inferior), la rutina esperará a 
que una tecla sea pulsada, y devuelve su código en el registro A. Este uso se 
demuestra en el programa DeBASE del apéndice G.
        Hay, sin embargo, un problema para leer el teclado cuando el modo está 
cambiado. Cada vez que la rutina es llamada, TV FLAG 23612 (5C3Ch) IY + 2 
es comprobada, y si el bit 3 está puesto, la memoria intermedia (buffer) de la 
entrada se copia en el área de edición de la pantalla. Esto se soluciona usando 
directamente la rutina Entrada de Tecla en 4264 (10A8h) y no por medio de la 
rutina Esperar Entrada, como se muestra en el programa DeBASE en el 
apéndice G en la etiqueta INPUT. El programa duplica la rutina Esperar 
Entrada, pero comprubea que la bandera se usa en la etiqueta INPUTF, y si ha 
introducido el programa (o esta sección del mismo) el problema puede demos-
trarse pulsando CAPS SHIFT y SYMBOL SHIFT para cambiar al MODO 
EXTENDIDO. La última línea que fue tecleada aparecerá en la parte inferior de 
la pantalla.
        Cuando se usan estas rutinas para leer el teclado, las interrupciones deben 
estar permitidas, y la rutina normalmente utilizada para las interrupciones en 56 
(38h) debe ser llamada dentro del ciclo de interrupción, si no, no se recibirá 
ningún dato de entrada.
Copia de la pantalla a impresora: 
CALL 3756 (EACh)
        Esta rutina no requiere inicialización, y con un simple CALL saldrá una 
copia de la pantalla en la impresora ZX.
_______
          17

 
Impresión de gráficos por impresora: 
CALL 3789 (ECDh)
        Esta rutina es similar a la de copia de pantalla, en que usa el contenido de 
la memoria intermedia de la impresora y lo imprime. Es usada por la rutina 
RST 16, la cual trata, normalmente, a la memoria intermedia como una línea de 
pantalla (ocho puntos de altura). Si usted coloca sus gráficos en la memoria 
intermedia una línea cada vez y después hace una llamada (CALL) a esta 
dirección, la rutina copiará la memoria intermedia por la impresora.
        Nota: El conjunto consta de 32 bytes por línea de puntos; la siguiente debe 
ir a continuación, y no como en la pantalla. La memoria intermedia es puesta a 
0 después de ejecutar esta rutina.
Borrando la memoria intermedia de la impresora: 
CALL 3807 (EDFh)
Simplemente, llena la memoria intermedia con ceros.
Usando el Beep: CALL 949 (3B5h)
        La pareja de registros DE contiene la duración, y HL la frecuencia; 0 es 
una frecuencia alta, y FFFFh es baja. El problema de esta rutina es que la 
duración depende de la frecuencia; por consiguiente, si divide por la mitad la 
frecuencia, se dobla la duración para un valor dado en DE. Los valores 
necesarios se calculan como sigue :
HL = (437 500/frecuencia) - 30,125 
DE = duración * frecuencia
(la duración deberá ser en segundos)
        La razón de que el 30,125 esté restado del cálculo de HL es que la rutina 
utiliza 120,5 T estados para generar la nota y modificar sus propios registros, 
etc.
        El Do medio es, aproximadamente, 261 hertzios; por tanto, el valor de HL 
sería, aproximadamente, 1.646 en decimal, y para que la duración fuera un 
segundo, DE sería 261 en decimal.
        Recuerde que las interrupciones de la ULA se producirán 50 veces por 
segundo (60 veces en Estados Unidos), y éstas distorsionarán la salida del 
sonido si la rutina está en los 16K inferiores de la RAM.
 _______
 18

 
Imprimiendo mensajes: CALL 3082 (COAh)
        En la entrada, la pareja de registros DE debe contener la dirección de la 
marca de inicio de la tabla de mensajes; dicha marca debe tener el BIT 7 alto y 
el registro A debe contener el número de entrada en la tabla de mensajes, cada 
uno de los cuales debe tener el BIT 7 a 1 en el último byte. El primer mensaje 
tiene el número 0.
        Si quiere imprimir el mensaje "yo soy" podría tener en su programa una 
línea tal como: MENSAJE DEFM "yo soy"; pero esto haría que se imprimiese 
todo lo que se encontrase a continuación, hasta que apareciese un byte con el 
bit 7 alto. Usted debe cambiar, por tanto, la línea por 'MENSAJE DEFB 80H: 
DEFM "yo soy": DEFB"" + 80H'. La rutina restará el 80H e imprimirá el 
último espacio correctamente, pero sabrá que ha llegado al final del texto y 
devolverá el control a la rutina que la ha llamado. Por tanto, el programa 
completo puede ser algo así :
	A14E 	3E00	10	 	LD 	A,O  ;	para imprimir el primer 
			15	;				mensaje de la tabla. 
	A150	CD53A1 	20 		CALL PR_MES
			30	;         . . .	
 			40	;   EL RESTO DEL PROGRAMA VA AQUI 
			50	;         . . .
	A153	115AA1	60	PR_MES	LD	DE, MENSAJE
	A156	CD0A0C	70		CALL	3082
	A159 	C9 	80	 	RET
	A15A 	80 	90	MENSAJ	DEFB	#80
	A15B	454E5452	100		DEFM 	"ENTRADA"
	A162	A0 	110 		DEFB	" "+#80
 	A163	454E5452 	120 		DEFM 	"ENTRADA 2"
	A16C	A0 	130 		DEFB	" "+#8O
        Esto imprimirá en la posición actual de la corriente en uso el mensaje 
<ENTRADA> . Para imprimir <ENTRADA 2> , el registro A debe contener 
1. Los símbolos mayor-menor marcan los límites de lo que se imprime, y no 
aparecerán cuando se ejecute el programa. Esta es la rutina usada por la ROM 
para expandir las palabras-clave y generar mensajes de error cuando desde otra 
rutina se llama a 2898 (B52h). El programa DeBASE (ver apéndice G) hace 
amplio uso de esta rutina.
Expandiendo claves para la salida : 
CALL 2898 (B52h)
        Siempe que el Spectrum encuentra un código especial (los que tienen el bit 
7 alto) tiene que decidir qué hace con él, ya que puede ser un gráfico definido 
por el usuario, un gráfico de bloques o una palabra del vocabulario BASIC. 
Normalmente, esto se realiza automáticamente cuando se usa RST 16 (10h) (la 
cual, a su vez, usa esta rutina). Si ha cambiado la dirección de la salida en una         
_______
          19

 
corriente (por ejemplo para enviar al interfaz de su propia impresora), cuando 
use su rutina y el registro A contenga el código de una clave y desee expandirlo 
tendrá que hacerlo usted mismo. Si lo deja como está, conseguirá algunos 
resultados sorprendentes en la impresora. Esta rutina puede usarse para 
expandir los comandos del BASIC, pero tendrá que manejar los gráficos por sí 
mismo y asegurarse de que los códigos correspondientes no sean enviados a la 
rutina; si no, la impresora quedaría bloqueada.
        Nota: Cuando está expandiendo, la rutina hace repetidas llamadas a la di-
rección apuntada por la corriente en uso y retorna sólo después de que todas las 
letras hayan sido sacadas. Esto significa que debe hacer un salto a la rutina (JP) 
para asegurarse de que el código en el registro A no es impreso cuando se 
devuelve el control al final de la impresión de una palabra BASIC. Esto se 
demuestra en el siguiente programa típico que envía la salida a una impresora :
 	A545	2A4F5C 	10 	INICIO 	LD 	HL,  (23631)   ; CHANS (direccion
 			15	; 				 del canal de datos)
A548	010FOO 	20 		LD 	BC, 15   ; incremento para el canal 3 (impresora) 
A54B 	09 	30 		ADD 	HL,  BC ; HL indica ahora la posicion
		 35	;			            que contiene la direccion 
			40	;		     	            a ser llamada cuando se realiza 
			45	; 			            la salida por este canal
	A54C 	0153A5 	50 		LD 	BC,  EMPIECE   ; EMPIECE=inicio de su
	 		55	;				      rutina de impresora
	A54F 	71 	60 		LD 	(HL), C
	A550	23 	70	 	INC 	HL
	A551	70 	80	 	LD 	(HL), B
	A552 	C9 	90 		RET 	; canal 3 inicializado hacia su rutina.
	A553	47 	100 	EMPIEC LD 	B, A   ; salva el codigo ASCII en B
	A554 	FEA5 	110 		CP 	165
	A556 	D2520B 	120 		JP 	NC,#B52  ;  rutina de expansion en ROM
	A559 	FE0D 	130 		CP 	13
	A55B 	28FE 	140 		JR 	Z, CRLF  ; salto de linea ( Carriage
	 		145	; 			             Return y Line Feed)
	A55D	FE20 	150 		CP	 32
	A55F 	D8 	160 		RET 	C  ; cualquier codigo inferior
	 		165	; 		        a 32 no es imprimible
	A560 	FE80 	170 		CP 	128
	A562	3800 	180 		JR 	C, IMPRIMIR  ; es un caracter normal
		185	;
190				190	; 				  cualquier cosa que llegue 
195		;				  aqui es un grafico 
197		;				  y lo debe tratar 
200		;				 como usted quiera.
A564	00 	210 	IMPRIM 	NOP 	;su rutina de impresion empieza aqui.
A565	C9 	220 		RET 	;vuelve a por el siguiente caracter,
		225	; 		 si no hay ninguno
		230	; 		 el control vuelve al programa original.
        Este programa es uno de los más elementales; si desea enviar cualquier 
código de control de la impresora, la rutina no lo enviará. Para evitar esto, 
deberá realizar más comprobaciones y actuar en consecuencia. La primera 
sección sólo necesita ser llamada una vez, pues modifica la dirección de la salida 
a la corriente 3. Sólo algunas veces necesita reinicialización después de un 
comando NEW desde el teclado o si la dirección de salida ha sido cambiada 
por otra parte del programa.
 _______
 20

 
Expansión de gráficos de bloque : 
CALL 2878 (B3Eh)
        Si tiene el código de un gráfico de bloques y quiere convertirlo en el gráfico 
en sí, la rutina en 2878 (B3Eh) lo hará por usted. Al llamarla, la dirección de 
base de los ocho bytes disponibles, donde quiere construir el gráfico, debe estar 
en la pareja de registros HL, y el registro B debe contener el código del gráfico 
de bloque. Se necesitan dos llamadas (CALL), la segunda inmediatamente 
después de la primera, ya que cada CALL construye cuatro bytes del carácter. 
El primer byte de su bloque de ocho será la parte superior del gráfico, y HL 
apuntará al byte siguiente después del último del gráfico. Las parejas de 
registros alteradas por esta rutina son AF, HL y BC; no usa ninguna otra.
Dibujando círculos: CALL 9005 (232Dh)
        La rutina, para dibujar un círculo, necesita que los parámetros de éste 
estén en la pila del calculador del Spectrum. De este modo, lo primero que hay 
que hacer es ponerlos en la pila del calculador. Una rutina localizada en 11560 
(2D28h) lo hará por nosotros si ponemos el número que deseamos apilar en el 
registro A (ver en capítulo 8 Uso del calculador). Todo lo que necesita saber 
ahora es que esta rutina reinicializa el registro IY para apuntar a ERR NR y 
que destruye el contenido de la mayoría de los otros registros, de forma que 
usted debe salvarlos antes de llamar esta rutina.
        Los parámetros deben ser salvados en la pila del calculador en el orden X, 
Y, Z, (Z = radio). La rutina para dibujar el círculo actualiza las variables del 
sistema COORDS, de modo que si usted no quiere que cambien debe salvarlas 
antes de dibujar el círculo y restituirlas después. De este modo, la rutina para 
dibujar un círculo quedaría así :
	A1D3	2A7D5C 	10 		LD 	HL, (23677)  ; COORDS (coordenadas)
	A1D6 	E5 	20 		PUSH	HL  ; salva coordenadas
	A1D7	3AD7A1 	30 		LD	A, (X_)  ; donde X esta entre 0 y 255 
A1DA	CD282D 	40 		CALL	#2D28  ; rutina en la ROM que apila 
A1DD 3ADDA1 	50 		LD 	A, (Y_)
	A1E0	CD282D 	60 		CALL 	#2D28
	A1E3	3AE3A1	70		LD 	A, (Z_)  ; Z=radio (debe caber en 
			75	; 			         la pantalla o tendra error) 
	A1E6 CD282D 	80 		CALL 	#2D28
	A1E9 CD2D23 	90		CALL 	#232D ;dibujar circulo
	A1EC	E1 	100 		POP 	HL
A1ED 227D5C 	110 		LD 	(23677), HL   ; devuelve las coordenadas
		120	; 				originales
        Si usted quiere dibujar su círculo en la posición actual indicada por 
COORDS, deberá colocarla en la pila del calculador, pero tendrá que volver a 
guardarla en la pila de la máquina si no quiere que se modifiquen.
_______
          21

 
Dibujando una línea: CALL 9146 (23BAh)
        La rutina para dibujar una línea empieza propiamente en 9399 (24B7h) y 
toma sus parámetros de la pila del calculador del mismo modo que la rutina 
del círculo. En este caso, es fácil evitar la parte que usa la pila del calculador. 
La rutina toma el punto de inicio en COORDS, así que si usted quiere partir 
desde alguna otra posición tendrá que cargar COORDS con su posición de 
inicio después de salvar su contenido, por si lo necesita posteriormente. De otro 
modo, COORDS contendrá la dirección del final de su línea. Al llamarla, el par 
de registros DE debe contener los signos de los parámetros del comando DRAW, 
que, a su vez, deben estar guardados en los registros BC. Deben ser - 1 (FFh) 
para negativo y + 1 (01h) para positivo. En los registros C y E se guarda X, 
mientras que en B y D se guarda Y.
        La rutina en lenguaje máquina equivalente a la línea DRAW 0,175 del 
BASIC, sería así:
	A0A7	0100AF 	1 		LD 	BC, #AF00  ; 175,0
	A0AA	110101 	2 		LD 	DE, #0101 ; +
	A0AD CDBA24 	3 		CALL #24BA
	 	4	; lo que es equivalente a DRAW -255,0 
A0B0	01FF00 	5 		LD 	BC, #00FF  ; 0,255 
A0B3	11FF01 	6 		LD 	DE, #01FF  ; +, -
        Fíjese que esta rutina dibujará desde la posición actual COORDS y que no 
se ha intentado modificarla o guardarla. Después de ejecutar la rutina, estos 
parámetros señalarán al último punto trazado mientras se dibujaba la línea. y 
se producirá un error si intenta dibujar fuera de la pantalla.
Encontrar la dirección de un punto de la pantalla: 
CALL 8874 (22AAh)
        Para encontrar la dirección del byte que contiene el punto de la pantalla 
usado por un comando PLOT se puede llamar a esta rutina con la pareja de 
registros BC conteniendo las coordenadas X e Y (Y 0 - 175 en B, y X 0 - 255 
en C) y volverá con la pareja de registros HL conteniendo la dirección y el 
registro A conteniendo la posición del bit.
Borrando parte de la pantalla: CALL 3652 (E44h)
        Esta rutina borrará el número de líneas indicado por el registro B desde la 
parte inferior de la pantalla (por ejemplo: si B contiene 1, entonces sólo se 
borra la línea inferior, y si B contiene 10, entonces se borran las diez líneas 
inferiores). La parte inferior de la pantalla es siempre la línea 24. no la línea 
más baja de la pantalla principal.
_______
22

Desplazando hacia arriba parte de la pantalla: 
CALL 3584 (E00h)
        Para desplazar hacia arriba parte de la pantalla se debe colocar primero en 
el registro B el número de líneas a desplazar menos uno. Después de esto se 
puede llamar a la rutina. Después de cada llamada, la línea inferior será 
borrada y se deben mover, al menos, dos líneas. De nuevo, las líneas se cuentan 
desde la parte inferior de la pantalla completa.
Entrada desde el canal actual: CALL 5606 (15E6h)
        Esta rutina coge la dirección del canal actual de la variable del sistema 
CURCHL, encuentra la dirección de la subrutina de entrada en el área de 
información del canal y entonces la llama.
Borrando la pila del calculador y el área 
de trabajo: CALL 5823 (16BFh)
        Esta rutina puede ser muy útil para asegurarse de que el calculador tiene la 
máxima área de trabajo y que no hay ningún dato inútil en la pila del 
calculador. Sólo usa la pareja de registros HL, y volverá con el contenido de la 
variable del sistema STKEND en ellos.
Salvando, cargando y verificando
        Las rutinas SAVE y LOAD del Spectrum son muy concretas y fáciles de 
usar si ambas operaciones, salvar y cargar, se van a realizar desde dentro de un 
programa, si la longitud exacta de los datos es conocida y si no importa si el 
control de la máquina se devuelve al BASIC en el caso de un error o de que se 
pulse BREAK. Si la longitud no se conoce o lo que se maneja es algo que no 
son datos, la cosa se vuelve más complicada.
        Normalmente, cuando está cargando, el Spectrum espera recibir una 
cabecera antes del bloque principal, y es esta cabecera la que dice al Spectrum 
cómo manejar el bloque principal de datos que viene a continuación. Es más 
fácil salvar y cargar sin la cabecera, pero, como señalamos anteriormente, esto 
sólo puede hacerse si los parámetros exactos son conocidos.
        La cabecera es de 19 bytes de largo (no 17, como muchos libros dicen), 
pero sólo los 17 bytes de en medio necesitan ser actualizados, ya que las rutinas 
que salvan y cargan crean el primero y el último ellas mismas.
        El byte 1 es siempre 00 para una cabecera, y el último byte es un byte de                
_______
          23

 
paridad, que es creado por la rutina, así que no hay necesidad de preocuparse 
de él. El byte 2 indica el tipo de bloque principal :

        0 para un programa BASIC 
        1 para una matriz numérica
        2 para una matriz alfanumérica
        3 para un bloque de bytes
        Los bytes del 3 al 12 almacenan el nombre. Los bytes 13 y 14 almacenan la 
longitud del bloque principal. En un programa BASIC ésta sería la diferencia 
entre las variables del sistema E LINE-PROG. Los bytes 15 y 16, en un bloque 
de bytes, almacenarán la dirección de inicio donde se carga el bloque. Estos, en 
un programa BASIC, almacenarán el número de línea de inicio automático si 
existe o la dirección de inicio si no existe. Para una matriz, el byte 16 almacena 
el nombre de la matriz en la forma de:
Bits del 0 al 4, el nombre (A = 1 a Z = 26). 
Bit 5 a 0, si la matriz es numérica.
Bit 6 a 1, si la matriz es alfanumérica.
Bit 7, siempre a 1.
        Los bytes 17 y 18 almacenan la longitud del programa, si lo que estamos 
tratando es un programa BASIC (es decir, la diferencia entre las variables del 
sistema VARS - PROG). El último byte es de paridad, y se crea al llamar a la 
rutina.

La cabecera

BYTES  1                    2  3.......            12  13                 14 15       16 17                 18  19

BANDERA	
TIPO	
NOMBRE
PROGRAMA
||||||||	
LONGITUD
DATOS
|	
  INICIO

|	
LONGITUD
PROGRAMA
|	
  PARIDAD	
IX+ 	            00      1........	           10 11                  12 13       14 15                  16 17

        Para salvar en cinta una cabecera, ésta debe ser creada como se ha dicho y 
salvada seguida por el bloque de datos principal, o si los parámetros del bloque 
de datos principal se conocen y siguen siendo conocidos cuando se vaya a 
cargar, sólo hace falta que se salve el bloque de datos.
        Hay varios puntos de entrada a la rutina SAVE que se pueden usar, 
teniendo cada uno sus pros y sus contras. El primero a tener en cuenta es 
quizás el más fácil, per también el más problemático. Para usarlo se debe 
almacenar en el registro IX el punto de inicio de la cabecera (con el byte 2, 
como se ha descrito en la información de cabecera anterior) y la pareja de
_______
24

registros HL debe señalar a la dirección de inicio del bloque principal que se va 
a salvar. Una vez que estos registros han sido modificados, se debe realizar una 
llamada (CALL) a la dirección 2416 (0970h), y entonces se salvarán ambos, la 
cabecera y el bloque principal. Los problemas son los siguientes :
        El siguiente punto de entrada puede considerarse similar al anterior, con la
excepción de que no pregunta ni espera a que se pulse una tecla. A éste se
accede mediante una subrutina en el programa principal, porque el funciona-
miento correcto depende de que se hayan introducido los valores adecuados en 
la pila de la máquina. Primero se inicializan las parejas de registro IX y HL, 
como hemos indicado antes, entonces se llama (CALL) a la siguiente rutina 
desde el programa principal :
A035  E5                   1 SAVE     PUSH  HL
A036  C38409           2                JP         2436  ; (#0984)
        Después de que se haya realizado la operación de salvar el control se 
devolverá a la dirección siguiente a la del punto en que se llamó a esta rutina. 
Este es un método sencillo de salvar bloques sucesivos completos con cabeceras, 
evitando repetir los mensajes start tape.
        Para realizar la operación sin que sea posible pararla y que se devuelva el 
control al BASIC, el comienzo normal debe ser evitado y la cabecera y el 
bloque de datos deben ser salvados como bloques separados. La rutina 
SA_BYTES, situada en 1218 (04C2h), se llama, normalmente, al hacer algún 
SAVE con el registro A conteniendo 00, para una cabecera, o FFh, para un 
bloque de datos. Lo primero que esta rutina hace es cargar la píla de máquina 
con la dirección de la rutina SAVE/LOAD RETURN. Esta rutina permite las 
interrupciones y mira si la tecla BREAK ha sido pulsada. La rutina de manejo 
de error es llamada por medio de un RST 8, si BREAK ha sido pulsada, 
volviendo el control, por tanto, al BASIC. Si BREAK no ha sido pulsada, el 
control se devolverá a la dirección original de RETORNO, introducida dentro 
de la pila por la rutina que ha realizado la llamada.
        Si no se ha colocado la dirección de retorno de la rutina SAVE/LOAD, la 
dirección de retorno que estará en la pila de la máquina es la del programa que 
ha realizado la llamada, y el control se le devolverá a la salida de la rutina 
SAVE, con la bandera de acarreo bajada, si se hubiera intentado parar el                          
   _______
             25
1.	El mensaje Start tape then press any key aparecerá. Si se pulsa
cualquier tecla, excepto BREAK, todo irá bien; pero si no, el control
será devuelto al BASIC mediante la rutina de manejo de error.
 2.	La tecla BREAK se comprueba periódicamente durante la ejecución de 
esta rutina SAVE. Si se pulsa, provoca un retorno prematuro a la 
rutina de manejo de error del BASIC, lo cual puede ser molesto.
 3.	La cabecera se salva de forma que asegure que la información salvada 
pueda ser vuelta a cargar desde el BASIC. Según las circunstancias, 
esto puede considerarse como una ventaja, no como un problema.

 
programa por medio de la tecla BREAK, y puesta a 1, en caso contrario, y las 
interrupciones estarán desconectadas: por tanto, éstas deben ser permitidas de 
nuevo. También deberá escribir algún tipo de mensaje para asegurarse de que la 
cinta ha sido puesta en marcha; por ejemplo, usando las rutinas de impresión 
de mensaje y Esperar Tecla detalladas en este mismo capítulo.
        Para salvar un bloque de código por este método, el registro IX debe 
señalar al inicio del bloque, y el registro DE debe contener la longitud. El 
registro A debe contener FFh, para un bloque de datos, ó 00, para una 
cabecera. A continuación se debe realizar una llamada directa a la dirección 
1222 (04C6h). Recuerde que la pareja de registros DE ha de contener 17 (11h) si 
se está salvando una cabecera estándar. Con este método se pueden salvar 
bloques de datos sin cabecera, pero sólo se pueden cargar posteriormente si se 
conoce la longitud.
        Si un retorno al BASIC no nos preocupa, o es una ventaja, entonces se 
puede usar la misma rutina, pero desde el inicio, que está en 1218 (04C2h). Si se 
pulsa BREAK, el control volverá al BASIC. De nuevo tendrá que asegurarse de 
que la cinta está funcionando.
Cargando y verificando
        Se pueden pasar datos de la cinta al Spectrum de dos formas: con
cabecera o sin ella. Cuando hay cabecera, ésta puede ser usada para proporcio-
nar todos los parámetros para la carga del bloque de datos principal que sigue 
o, como cuando se carga desde el BASIC, para averiguar los detalles que son 
desconocidos, para comprobar que los conocidos son correctos, o para asegu-
rarse de que se está cargando el bloque de datos correcto. Si no hay cabecera, 
todos los detalles que habían estado en esta sección deben ser conocidos antes 
de que el bloque de datos pueda ser cargado.
        Es posible crear un tipo diferente de cabecera del usado por el Spectrum 
para definir los parámetros del bloque que viene a continuación, salvando un 
bloque de datos de longitud fija y escribiendo su propia rutina de decodifica-
ción, la cual proporcionará los detalles para cargar el bloque principal. Esta es 
una buena idea que previene la posibilidad de perder un bloque, porque usted 
olvidó la longitud o dónde estaba en la cinta y, por tanto, no puede cargarlo. 
Esto también previene que el código sea cargado por un usuario "no autoriza-
do", a no ser que él se tome la molestia de escribir su propio programa para 
examinar qué ha hecho usted y logre interpretarlo. Una rutina que crea una 
cabecera especial se da en el programa DeBASE en el apéndice G.
        Para cargar un bloque de datos precedido por una cabecera normal, lo 
primero que se debe hacer es asignar un espacio de 34 bytes en la memoria. En 
los primeros 17 bytes se debe crear una cabecera "ficticia ". Esta define detalles 
que es necesario que coincidan antes de que el bloque de datos sea cargado. 
Una vez que estos detalles coinciden, cualquier información no coincidente será 
comparada con la cabecera real y, suponiendo que los cambios sean aceptables, 
estos detalles necesarios para la carga serán tomados de la cabecera "ficticia". Si
_______
26

 
las diferencias no son aceptables, se genera un error del BASIC por medio de 
un RST 8. Los segundos 17 bytes serán rellenados con la cabecera de la cinta, 
para comparar; sólo cuando coinciden, este área volverá a estar libre para su 
uso.
        La cabecera ficticia se construye de la misma manera que la cabecera 
salvada en la cinta, y de nuevo, el primero y el último byte del total de 19 se 
generan internamente, de modo que no están incluidos en los 17 bytes de la 
especificación. El primer byte debe ser igual al primer byte de la cabecera de 
datos que se va a cargar (el tipo debe coincidir). Este está contenido en el 
registro A cuando se llama a la subrutina LOAD BYTES, y sólo necesita ser 
puesto si la llamada se realiza directamente. Si los tipos no casan, se espera un 
nuevo bloque para repetir el proceso hasta que los tipos coincidan. El segundo 
byte (el primero de los 17 con los que se ha construido la cabecera ficticia) debe 
coincidir de nuevo: 0, para un programa en BASIC; 1, para una matriz 
numérica, etc. Si no coinciden, se esperará al próximo bloque. Los siguientes 10 
bytes son el nombre. Si no importa el nombre, entonces el primero de estos 
bytes debe ser FFh, los nombres deben coincidir. Los dos bytes siguientes son 
la longitud; si éstos están puestos a 0, la longitud será tomada desde la 
cabecera de la cinta; de otro modo, las dos longitudes deben coincidir. Para un 
bloque de códigos, los bytes 15 y 16 serán la dirección de inicio para cargar, 
mientras que para una matriz en BASIC el byte 15 será ignorado y el byte 16 
será el nombre de la matriz, de la misma forma que cuando se realizó el SAVE. 
Para un programa BASIC, el byte 15 será 0, y el byte 16 será 80h. El último 
byte puede ser ignorado.
        Antes de intentar usar la cabecera ficticia, el byte bajo de la variable del 
sistema T ADDR debe contener 0,1, para realizar un LOAD, o un 0,2, para un 
VERIFY.
        La pareja de registros HL debe contener la dirección a partir de la cual se 
va a almacenar el bloque principal ó 0 si se usa la información en la cabecera 
de la cinta. Para una matriz de BASIC, ésta será el inicio de la matriz de datos, 
a continuación el nombre de la matriz y la longirud en el área de variables de 
un programa BASIC.
        Finalmente, el registro IX ha de señalar a la dirección del primer byte de la 
cabecera ficticia. La rutina ROM, que empieza en 1889 (761h), puede ser 
llamada ahora para cargar o verificar tanto la cabecera como el bloque de 
datos principal que están en la cinta.
        La carga o verificación sin una cabecera pueden ser conseguidas sólo si 
todos los parámetros del bloque que se va a leer se conocen.
Primeramente, el registro A se carga con FFh, lo que indica que se va a 
cargar un bloque de datos. Después, la pareja de registros DE se cargan con la 
longitud total del bloque a leer. Entonces, el registro IX es colocado con la 
dirección en la que se van a almacenar los datos leídos o verificados. Esto debe 
ir acompañado por la bandera de acarreo puesta a 1, si se hace un LOAD, o a 
0, para un VERIFY. Finalmente, se llama a la rutina de la ROM en 1366 (556h) 
para realizar la operación.
        La parte inicial de esta rutina carga previamente de la pila de la máquina                  
   _______
             27

del mismo modo que la rutina SAVE ya comentada, volviendo con una indica-
ción de error si se pulsa la tecla BREAK. Esto puede ser evitado llamando la 
siguiente subrutina que debe estar almacenada en su propio programa :
	A1F7	14 	30	CARGA 	INC	D ; baja la bandera cero
	A1F8	08 	40 		EX 	AF,AF'
	A1F9	15 	50 		DEC 	D ; recupera el valor original de D
	A1FA 	F3 	60 		DI 	; 	    las interrupciones deben estar
			65	; 			    desconectadas para que los
 				70	;		 	     tiempos sean constantes,
				75	; 			     No son vueltas a conectar por la
				80 	; 			     rutina en ROM al terminar,
	A1FB 	3E0F 	90		LD 	A, #0F
A1FD 	D3FE 	100	 	OUT 	(#FE), A  ;  pone a 1 el borde y el conector EAR 
A1FF	C36205 	110	 	JP 	#562  ; salta a la rutina principal de carga.
        La instrucción OUT pone el color del borde blanco con los tres bits bajos; 
esto puede cambiarse cuando se requiera un color diferente. El bit 5 debe ser 
dejado a 1, ya que inicializa el puerto EAR para recibir las señales que vengan 
de la cinta.
        Si se produce un error en la carga de la cinta, puede ser detectado por la 
bandera de acarreo puesta a 0 cuando se devuelve el control a la rutina que 
efectúa la llamada, ya que, si se ha pulsado BREAK, produciría un retorno 
inmediato; si se quiere comprobar esto se debe llamar a la rutina de comproba-
ción de la tecla BREAK, después de comprobar si hay algún error.
        Nota: Las interrupciones estarán desconectadas al terminar la carga.
        La rutina puede ser usada también para leer una cabecera, en lugar de un 
bloque de datos, cargando el registro A con 0 antes de llamarla. Esto puede ser 
útil si desea crear un tipo diferente de cabecera y leerlo con su propia rutina, 
como se demuestra en el programa DeBASE en el apéndice G.
  _______
  28

 

3 
La ROM 
del Interfaz de 8K
        Con la adición de la ROM de 8K en el interfaz del microdrive, Sinclair ha 
presentado la posibilidad de expansión en la forma de una ROM suplementaria, 
como se usa en el microordenador BBC, así como una vía fácil de expansión 
del BASIC Sinclair. Lo primero que necesita comprender es el mecanismo por 
el cual la CPU Z80 puede direccionar la memoria situada fuera del rango 
normal de 64 kilo bytes.
        La CPU tiene dos grupos de líneas de información -A 1-16 (que usa para 
decirle a la memoria qué byte se va a emplear)- llamada bus de direcciones y 
D 0- 7, bus de datos, que se usan para leer y escribir a la dirección de memoria 
indicada por el bus de direcciones. Normalmente, es imposible el acceso fuera del 
rango de 64K, de modo que se debe realizar algún tipo de cambio que sustituya 
un banco de memoria en el mismo rango de direcciones.
        Esto se hace fácilmente eligiendo un byte de la memoria, mirando si 
aparece su dirección en el bus de direcciones y, cuando esto suceda, cambiando 
a la memoria alternativa. La ejecución continuará entonces en la dirección 
siguiente, ya que el contador del programa se incrementará para apuntar a la 
dirección siguiente, como es normal; pero el dato será cogido desde el nuevo 
banco de memoria.
        En el Spectrum esto se hace comprobando en el bus de direcciones si 
aparece la dirección 8, que es la rutina de manejo de errores. Dado que esta 
dirección sólo es generada por un RST 8, el tope de la pila contendrá siempre 
la dirección de la instrucción siguiente a la de llamada (es decir, la dirección de       
  _______
             31

 
retorno). La rutina de la ROM suplementaria toma esta dirección y examina su 
contenido. Los valores en el campo 00 al 1Ah causan un retorno a la ROM de 
16K, pues éstos son códigos normales de error, pero los números entre 1Bh y 
32h son usados como "código de enlace" (hook code). Estos llaman a las rutinas 
de la ROM suplementaia que se detallan ahora. Para usar un código de enlace, 
use RST 8 seguido por el código de enlace definido con DEFB. Todas las 
direcciones se refieren a la ROM suplementaria.
Entradas
Leer tecla: Código de enlace 1Bh, Dirección 6617 (19D9h)

        Es similar al comando GET en algunos BASIC (aunque el BASIC de 
Sinclair no tiene este comando). Espera hasta que una tecla es pulsada, y entonces 
vuelve con el código de ésta en el registro A. La interrupción enmascarable debe 
estar activa, ya que la que usa la rutina de la ROM de 16 K se utiliza para explorar 
el teclado.
Entrada por el RS 232: Código de enlace 1Dh, Dirección 2945 (B81h)

        Para usar esta rutina, primero se debe fijar la velocidad de transmisión 
usando la variable del sistema BAUD 23747/8 (5CC3/4h), calculada como 
3.500.000/(26 * velocidad de transmisión) - 2, siendo 3.500.000 la frecuencía del 
reloj del Spectrum. Después SER_FL 23 751 (5CC7h) ha de ponerse a 0, y 
entonces se puede llamar a la rutina de entrada. El registro A contendrá el 
código del carácter recibido, y la bandera de acarreo estará puesta a 1. La 
rutina esperará cierto tiempo para recibir un código. Si tiene que esperar mucho 
o si se pulsa la tecla de espacio volverá, pero sin la bandera de acarreo puesta.
Entrada de la red local: Código de enlace 2Fh, Dirección 6705 (lA31h)

        Antes de usar esta rutina se debe abrir y señalar como activo un canal de 
la red local usando la rutina de Abrir Canal descrita más tarde (ver sección 
Salida de la red local). Esta rutina leerá un paquete de la red local, a la entrada 
el registro IX debe señalar el inicio del área de la red local e IX + 11, IX + 12, 
y IX + 13 y 14 deberán contener los valores correctos para el bloque que se va 
a recibir (ver detalles sobre la cabecera empleada en la red local en la sección 
Salida de la red local, usando el código de enlace 30H). El número de bloque en 
IX + 13 y 14 se incrementa después de que cada bloque sea recibido correcta-
mente.
        Se pretendía que la bandera de acarreo indicara si se había leído un 
paquete o si había un error, cuando se devolviese el control a la rutina 
principal. Sin embargo, la bandera de acarreo puede ser destruida por la . 
modificación del color del borde al salir de la rutina. Se devolverá el control 
desde ésta cuando un paquete haya sido bien recibido, con la bandera de 
acarreo bajada. Si el tiempo concedido para que se reciba un paquete ha                   

_______
32