Capítulo 1. Curso de introducción

Parte 11: Introducción al gestor de bancos de memoria

Contenido:


El segundo bloque de 64K de memoria

EI CPC6128 está dotado de 128K de RAM (random access memory, memoria de acceso aleatorio) divididos en dos bloques de 64K cada uno. CP/M Plus utiliza todos los 128K, pero en cambio BASIC normalmente no se sirve más que de los 64K primeros. Sería una pena no aprovechar los otros 64K en los programas de BASIC, así que hemos incluido un programa que proporciona órdenes gracias a las cuales se puede utilizar esa memoria con dos usos específicos: como almacén de imágenes de pantalla o como espacio para almacenar cadenas de caracteres.

El programa se llama "gestor de bancos" ("banco" es un término técnico que significa "bloque de memoria").

Control de imágenes de pantalla con el gestor de bancos

El ordenador 6128 visualiza y mantiene constantemente actualizada una imagen de pantalla. Para ello necesita 16K de memoria en la que almacenar información acerca del color y el brillo de todos los pixels (puntos) de la pantalla. En la memoria del 6128 hay espacio suficiente para almacenar información sobre seis imágenes de pantalla simultáneamente (16K para cada una). El gestor de bancos proporciona las órdenes necesaria para manipular y visualizar desde BASIC cinco de las pantallas posibles.

Cuando se conecta el ordenador, la imagen que se observa en la pantalla está formada con los datos almacenados en el primer bloque de 16K (que denominaremos "bloque 1"), dentro del primer banco de 64K. Las otras cuatro pantallas están en el segundo banco de 64K y les llamaremos bloque 2, bloque 3, bloque 4 y bloque 5.

En realidad, el único bloque cuya información se consulta para formar la imagen es el bloque 1. Para visualizar los bloques del segundo banco (bloques 2, 3, 4 y 5) hay que transferirlos al bloque 1. El gestor de bancos proporciona las órdenes necesarias para realizar esas transferencias: |SCREENCOPY copia el contenido de un bloque en otro, borrando la información previamente grabada en el bloque destino; |SCREENSWAP intercambia el contenido de dos bloques.

Las órdenes del gestor de bancos son órdenes externas, similares a las de AMSDOS ya descritas en este capítulo, y van precedidas, por consiguiente, por el símbolo | (tecla @ con [MAYS]).

Utilización del gestor de bancos

Reinicialice el ordenador con [CONTROL] [MAYS] [ESC]. Inserte en la unidad de disco la cara 1 del juego de discos del sistema y escriba

RUN "BANKMAN"

El procedimiento de carga se explica en el capítulo 7, partes 14 y 15, en las que se habla de las RSX (Resident System eXtensions, ampliaciones del sistema residentes). Conviene tener cierta idea de cómo funcionan estas rutinas y de cómo reservarles espacio en la memoria antes de utilizarlas en los programas. No obstante, para probar los siguientes ejemplos no es necesario conocer el procedimiento de carga.

Escriba:

MODE 1
PRINT "ESTA ES LA PANTALLA IMPLICITA"
|SCREENSWAP,1,2

El texto debe haber desaparecido como consecuencia de la última orden (screenswap significa "intercambio de pantalla''). Lo que ahora hay en la pantalla es la información que antes estaba almacenada como "pantalla 2" (en el bloque 2). Si la máquina estaba recién encendida, será seguramente una imagen aleatoria. Para borrarla escriba:

MODE 1

y a continuación:

PRINT "ESTA ES LA PANTALLA 2"
|SCREENSWAP,1,2

Ha vuelto a aparecer el texto original. Al repetir la orden |SCREENSWAP,1,2 hemos vuelto a intercambiar las dos pantallas. Con la orden |SCREENSWAP se puede intercambiar cualquier pantalla de las cinco disponibles con cualquier otra; pero el efecto sólo será visible si una de las pantallas implicadas es la número 1.

La otra orden es |SCREENCOPY ("copia de pantallas"). Con ella se copia una pantalla sobre otra y se borra la que originalmente había en el bloque destino.

Escriba:

MODE 1
PRINT "VAMOS A COPIAR ESTA PANTALLA"
|SCREENCOPY,2,1

La pantalla fuente, la 1, se ha copiado en la pantalla destino, la 2. Si ahora invertimos el orden de los parámetros,

MODE 1
|SCREENCOPY,1, 2

el contenido de la pantalla actualmente visible (es decir, la 1) es sustituido por el de la pantalla 2.

Así pues, el primer parámetro representa la pantalla destino; el segundo, la pantalla fuente.

Al copiar pantallas se producen imágenes distorsionadas si los modos de pantalla son diferentes o si la pantalla visible ha sido desplazada hacia arriba después de la última ejecución de una orden MODE. Las órdenes de control de pantallas del gestor de bancos están pensadas para su utilización en pantallas gráficas más bien que en pantallas de texto, y en aquéllas el desplazamiento de la pantalla es más improbable.

Utilización del gestor de bancos en el almacenamiento de cadenas literales

El programa gestor de bancos proporciona otras cuatro órdenes externas mediante las cuales se puede convertir el segundo banco de memoria (64K) en un archivo de cadenas literales.

Casi todos los programas se pueden dividir en dos partes: las instrucciones del programa y los datos con los que opera. Un buen ejemplo sería un programa de base de datos, tal como una lista de nombres y direcciones. Un programa así utilizaría vectores literales para almacenar los nombres y las señas.

Las cadenas literales se pueden almacenar en el segundo banco de 64K de memoria, una tras otra. El espacio dedicado a almacenar las cadenas se puede dividir en una serie de compartimentos que denominaremos registros. Los registros son de longitud fija, entre 2 y 255 caracteres cada uno, mientras que la longitud de las cadenas literales de BASIC no es fija, sino que depende de los caracteres que las integren. El método de almacenamiento mediante registros proporciona compartimentos de tamaño uniforme: una especie de casillero en el que se guarda la información de forma bien organizada. Cada operación de escritura o lectura de datos de un registro va acompañada de un avance automático al registro siguiente, el cual queda dispuesto para la siguiente operación. El registro con el que se va a realizar la siguiente operación es el "registro actual", y es el que las órdenes del gestor de bancos utilizarán si no se especifica otro diferente.

A este sistema de gestión de la memoria le hemos dado el nombre de "RAMdisc" o "disco virtual" porque funciona de forma muy parecida a como lo hacen los sistemas de fichero de acceso aleatorio en disco, con la única diferencia de que el soporte físico es la RAM en lugar de un disco.

Lea las siguientes descripciones de las diversas órdenes; si no aprende a utilizarlas inmediatamente, al menos apreciará para que sirven. Después practique con los ejemplos.

La primera orden de RAMdisc es |BANKOPEN. Esta orden especifica el número de caracteres que va a tener cada registro. La sintaxis es:

|BANKOPEN,n

donde n es un número que especifica la longitud de los registros. El número n puede tener cualquier valor del margen de 0 a 255, pero los valores 0 y 1 producen efectos incontrolados.

|BANKWRITE almacena una cadena literal en el "registro actual". Al terminar la ejecución de la orden, el "puntero de registro" pasa a apuntar al registro siguiente a aquél en el que se ha escrito y lo convierte en el nuevo "registro actual". La sintaxis es:

|BANKWRITE,@r%,a$

o bien

|BANKWRITE,@r%,a$,n

donde r% es una variable entera que contiene, al terminar la orden, cierta información acerca de la operación que se acaba de realizar. a$ es una variable literal que contiene los caracteres que se han de almacenar en el registro. En el primero de estos dos ejemplos se escribe en el registro actual; en el segundo ejemplo el parámetro opcional n especifica el número de registro en el que se debe escribir.

|BANKREAD examina un registro y asigna su contenido a una cadena literal; al terminar la lectura, incrementa el puntero de registros y convierte en registro actual el siguiente a aquél en que se realizó la operación. El contenido de los registros no resulta modificado por las operaciones de lectura. La sintaxis de |BANKREAD es la siguiente:

|BANKREAD,@r%,a$

o bien

|BANKREAD,@r%,a$,n

donde r% es una variable entera que contiene, al terminar la orden, cierta información acerca de la operación que se acaba de realizar. a$ es una variable literal a la que se asigna los caracteres leídos en la operación. En el primero de estos dos ejemplos se lee el registro actual; en el segundo ejemplo el parámetro opcional n especifica el número de registro que se debe leer.

La última orden de este grupo es |BANKFIND. Esta orden examina los registros en busca de una cadena literal especificada. Si la encuentra, entrega el número de registro en el que la ha encontrado. La sintaxis de |BANKFIND es:

|BANKFIND,@r%,a$

o bien

|BANKFIND,@r%,a$,n

o bien

|BANKFIND,@r%,a$,n,m

donde r% es una variable entera que contiene, al terminar la orden, o bien el número de registro en el que se ha encontrado la cadena, o bien un código que indica que la cadena no ha sido encontrada. a$ es la cadena que se busca. El parámetro opcional n especifica el número de registro a partir del cual se debe empezar a buscar. Si no se especifica n, la búsqueda comienza a partir del registro actual. El segundo parámetro opcional, m, especifica el número de registro en el que se debe abandonar la búsqueda. Si se omite m, la búsqueda continúa hasta el final de los 64K de memoria, con lo que se puede sobrepasar el final de los datos escritos por el programa.

Pruebe ahora los siguientes ejemplos. Si ya ha ejecutado el programa para estudiar las órdenes de manipulación de pantallas y no ha reinicializado la máquina desde entonces, las órdenes de RAMdisc seguirán en la memoria. De lo contrario, inserte la unidad de discos la cara 1 del juego de discos del sistema y escriba lo siguiente:

RUN "BANKMAN"

Ahora escriba:

|BANKOPEN,20

Esta orden especifica que los registros van a ser de 20 caracteres cada uno y selecciona como registro actual el número 0.

Escriba:

a$="PRIMER REGISTRO"+SPACE$(5)

con lo que se forma la cadena a$ con longitud de 20 caracteres.

Escriba ahora:

r%=0

para inicializar r%.

Escriba:

|BANKWRITE,@r%,a$

Esta orden escribe a$ en el primer registro (el número 0). A continuación escriba:

d$=SPACE$(20)
|BANKREAD,@r%,d$,0
PRINT d$

La primera orden iguala d$ a una cadena de 20 espacios, longitud suficiente para poder asignarle el contenido del registro en la operación de lectura. La segunda orden lee el registro número 0 y asigna su contenido a la variable literal d$. Antes de la lectura el registro actual era el número 1 (actualizado por la anterior BANKWRITE); por eso hemos tenido que especificar que la lectura debía realizarse en el registro número 0. De no haberlo hecho así, se habría leído el registro actual. La última orden de este ejemplo escribe en la pantalla el resultado de la lectura; si todo ha ido bien, d$ debería ser igual a la cadena "PRIMER REGISTRO" seguida de 5 espacios.

Escriba lo siguiente:

b$="DOS"+SPACE$(17)
c$="TRES"+SPACE$(16) 
|BANKWRITE,@r%,b$,1
|BANKWRITE,@r%,c$

Estas órdenes escriben b$ y c$ en los registros 1 y 2. En la primera orden |BANKWRITE hemos incluido el parámetro opcional, con lo que b$ ha quedado almacenada en el registro 1. Esta misma orden ha incrementado el puntero de registro; al ejecutarse la segunda orden |BANKWRITE, el puntero apunta al registro 2, y es en él donde se almacena c$.

Escriba:

PRINT r%

El resultado debería ser 2. Este número se puede considerar como el número del último registro sobre el que se ha operado, o bien como el número del registro actual menos uno. En este ejemplo, el último registro utilizado es el 2; el registro actual (o sea, el registro sobre el que actuará la próxima orden de RAMdisc si no se especifica otra cosa) es el 3.

Esta variable, r%, proporciona siempre información acerca de cómo se ha desarrollado la última operación. Si la operación ha concluido con éxito, la variable toma un valor positivo que representa un número de registro. En caso contrario, el valor es negativo e indica un código de error. |BANKWRITE y |BANKREAD pueden generar los dos códigos de error siguientes:

CódigoDescripción
-1Indica que se ha alcanzado el final del fichero. Esto ocurre cuando ya se han utilizado todos los registros o cuando se especifica un número de registro que no existe.
-2Indica un fallo en la conmutación de bancos. No debería ocurrir nunca.

Pruebe los siguientes ejemplos:

d$=STRING$(20,"X")
|BANKOPEN,20
FOR n=1 TO 3:|BANKWRITE,@r%,d$:NEXT 

La primera orden asigna a la variable literal d$ una cadena formada por 20 letras "X". |BANKOPEN reinicializa el puntero de registros a 0, de modo que |BANKWRITE escribe la cadena d$ en los registros 0, 1 y 2, borrando su contenido anterior.

Ahora escriba:

a$="PRIMERO"
|BANKWRITE,@r%,a$,0

Estas órdenes escriben la palabra "PRIMERO" en el registro 0, superponiéndola a algunas de las 'X' que había antes en él. Vuelva a igualar d$ a una cadena de espacios con

d$=SPACE$(20)

y escriba

|BANKREAD,@r%,d$,0

Esta orden lee el registro 0 y asigna su contenido a d$.

Repasemos todo lo que hemos hecho hasta ahora. Hemos escrito en los tres primeros registros sendas cadenas formadas por 20 letras 'X' cada una. Hemos cambiado las letras 'X' del registro 0 por la palabra "PRIMERO". Finalmente, hemos vuelto a definir d$ como una cadena de 20 espacios. Si ahora escribimos

PRINT d$

el resultado debe ser "PRIMEROXXXXXXXXXXXXX". Este ejemplo ilustra una consideración importante que se debe tener presente al utilizar estas órdenes. Si la cadena que se escribe en un registro no lo llena completamente, los caracteres antiguos sobre los que no se ha escrito seguirán estando en el registro. Esto puede ser ventajoso en ocasiones, pero en general será conveniente escribir una cadena de espacios (o sea, de caracteres ASCII 32) en el registro antes de actualizar la información en él almacenada. Lo mismo se puede decir acerca de la cadena a la que se va a asignar los caracteres leídos en un registro: si la longitud de la cadena es mayor que la longitud del registro, al final de ella quedarán caracteres que no habrán resultado de la operación de lectura. Ésta es la razón por la que hemos borrado (o igualado a una cadena de espacios) la cadena d$ antes de asignar el contenido del registro 0.

Es posible escribir una cadena en un registro que sea demasiado corto para recibir la cadena completa. En tal caso se ignoran los caracteres de la cadena (los últimos por la derecha) que no quepan en el registro.

Análogamente, si se lee un registro y se asigna su contenido a una cadena demasiado corta, los caracteres que no quepan en ella serán ignorados. En las operaciones normales con cadenas, BASIC ampliaría automáticamente la cadena para aceptar todos los caracteres, pero esto no es así cuando se utilizan órdenes externas.

Finalmente, vamos a describir la orden |BANKFIND. Esta orden sirve para examinar los registros en busca de una sucesión de caracteres especificada. Por ejemplo, si el registro número 24 empieza con la palabra "DANIEL", la orden

|BANKFIND,@r%,"DANIEL"

la encontrará. Esta función es extremadamente útil en los programas de bases de datos, en los cuales se puede necesitar, por ejemplo, buscar un nombre a lo largo del fichero.

|BANKFIND inicia la búsqueda a partir del registro actual y la continúa hasta que encuentra la cadena o hasta el final de los 64K de memoria, si no se especifica otra cosa.

Se puede incluir un parámetro para especificar el número de registro a partir del cual se debe buscar. Después de éste se puede incluir otro parámetro para especificar en qué número de registro se debe interrumpir la búsqueda.

|BANKFIND también puede buscar una cadena que no esté al principio de registro. Para ello, al principio de la cadena buscada se incluyen tantos caracteres chr$(0) como posiciones haya en el registro antes de los buscados. Los caracteres chr$(0) actúan como "símbolos comodín" (como los ? en los nombres de ficheros de CP/M), con el significado de "cualquier carácter". Por ejemplo,

a$=STRING$(10,0)+"DANIEL"
|BANKFIND,@r%,a$,0

busca el primer registro en el que figure la palabra "DANIEL" en las posiciones 11ª a 16ª. Los diez primeros caracteres del registro podrían contener un número de teléfono o cualquier otra información que |BANKFIND ignoraría.

Al concluir la operación, la variable r% contiene el número del registro en el que se ha encontrado la cadena, o bien el código -3 si no se la ha encontrado.

Información adicional

En el capítulo 8 se puede encontrar más información sobre el gestor de bancos; estudie también las partes 13 y 14 del capítulo 7, en las que se describen las RSX.

Finalmente, antes de proseguir, asegúrese de que ha tenido en cuenta las advertencias que hemos hecho al principio de este manual, en la sección titulada IMPORTANTE:

Aquí termina este Curso de introducción al CPC6128. Es de esperar que usted haya aprendido para qué sirve la mayor parte de las teclas, cómo utilizar las instrucciones más sencillas de BASIC, cómo preparar un disco virgen, cómo realizar las funciones más elementales de manejo de discos, tales como LOAD, SAVE y CAT, y cómo utilizar unas cuantas órdenes de AMSDOS, CP/M y el gestor de bancos.

En el resto del manual abordaremos cuestiones más avanzadas. Estudiaremos el BASIC de AMSTRAD, el funcionamiento de la unidad de disco, con secciones dedica das a AMSDOS y CP/M, y daremos una introducción a un nuevo lenguaje: el DR. LOGO de Digital Research.

¡Buena suerte y que disfrute!