Sinclair QL Programación Avanzada
Anterior Siguiente

10. SuperBASIC

10.1 Introducción

Este capítulo es ligeramente diferente del resto del libro, ya que está dedicado exclusivamente al SuperBASIC. Puede haber considerables ventajas al usar el BASIC, ya que toda la estructura del lenguaje, el editor, etc. están ya ahí. Por lo tanto, crear funciones especializadas de BASIC, así como procedimientos para aplicaciones particulares, puede ser una tarea muy interesante.

Antes de comenzar a ver como añadir utilidades al SuperBASIC, es necesario tener una idea general de las estructuras para almacenar variables y otros nombres.

Cuando se introduce desde el teclado, un nombre dentro del programa BASIC, se crea una entrada para él en la memoria. Todo lo que se almacena en el propio programa es un apuntador ala entrada correspondiente. Este método de asignación de variables es muy eficiente en el manejo de espacio cuando se usa una variable particular una y otra vez. De esta forma no tenemos una carga extra de almacenamiento para nombres largos de variables, que hace a los programas más fáciles de entender.

Hay cuatro áreas distintas en las que se almacena la información. Son la tabla de nombres, la lista de nombres, la lista de valores variables y la pila aritmética. A diferencia de los ordenadores menos sofisticados, toda el área de trabajo es susceptible de moverse sin peligro. Por esta razón, todas las referencias en BASIC se realizan relativas al registro A6 que apunta siempre a la base del área.

10.2 La tabla de nombres

El SuperBASIC maneja las variables y las cadenas en modo indirecto. Como se mencionó en la sección 10.1, cada referencia a una variable dentro del fichero de programas BASIC, es un simple apuntador a una entrada en la tabla de nombres. Esta tabla no contiene en sí misma los valores de las variables, sino un apuntador al nombre en la lista de nombres y un valor en el área de valores de variables. Cada entrada en la tabla de nombres es de ocho octetos de longitud y tiene el siguiente formato:

palabra 1 código describiendo el uso del nombre
palabra 2 apuntador al nombre en la lista de nombres
palabra 3 apuntador al valor

Figura 10.1 - Almacenamiento de variables en BASIC

Código de tipo

Es la primera palabra del bloque en la tabla de nombres. Hay varios tipos diferentes:

Variable Código
cadena no usada 0001
número de coma flotante no usado 0002
entero no usado 0003
variable de cadena 0201
número de coma flotante 0202
entero 0203
índice de bucle REPEAT 0602
índice de bucle FOR 0702

Matrices Código
matriz de subcadena 0300 (interno solamente)
matriz de cadena 0301
matriz de coma flotante 0302
matriz de enteros 0303

Los procedimientos y las funciones no tienen tipo. Por otro lado, las funciones BASIC tienen un tipo que se define por el último carácter del nombre de la función ($ ó % o ninguno).

Tipo de módulo Código
procedimiento BASIC 0400
función de cadena BASIC 0501
función de coma flotante BASIC 0502
función entera BASIC 0503
procedimiento en código máquina 0800
función en código máquina 0900

También hay algunos códigos que se refieren a valores en pila aritmética, dentro del evaluador de expresiones.

Expresiones Código
cadena 0101
coma flotante 0102
entero 0103

El apuntador de nombre

Es 1a segunda palabra de 1a entrada en la tabla de nombres. Contiene el desplazamiento del nombre dentro de la lista, a menos que 1a entrada sea el valor de una expresión, en cuyo caso contiene -1. Alternativamente, si la entrada es una copia de otra, se incluye un apuntador a esa entrada.

Apuntador al valor

Es una palabra larga y es el tercer argumento en la tabla de nombres. Si es negativo, el valor es indefinido. Si es positivo, es el desplazamiento desde la base del área VV (valor de variable) en el caso de variables, o el desplazamiento del descriptor de matriz en caso de matrices. La palabra más significativa es el número de línea del DEF PROC o del DEF FN de un procedimiento o función del BASIC. El apuntador es la dirección absoluta de un procedimiento o una función en código máquina. El apuntador al valor no se define para las entradas de nombre internas que se refieren a un valor en la pila aritmética.

10.3 La lista de nombres

Los nombres de variables y matrices se almacenan en una lista de nombres. Cada nombre se almacena como un octeto seguido por los caracteres ASCII del nombre. Las entradas en la lista son apuntadas por la tabla de nombres descrita en la sección 10.2.

10.4 El área de valores de variables

Esta es el área donde se almacenan los valores reales de las variables. El área está construida como una pila entradas, asignadas en múltiplos de 8 octetos.

Las variables de cadena se almacenan como una palabra (que contiene el número de caracteres de la cadena) seguida por los caracteres de la cadena. El espacio ocupado por una cadena se redondea al número par más cercano, de forma que termine en frontera de palabra.

Los números de coma flotante se almacenan con dos octetos de exponente y cuatro de mantisa. Ver la sección 8.5.4 para más detalles sobre el almacenamiento de números de coma flotante .

Los enteros se almacenan como una palabra.

Almacenamiento de matrices

El descriptor de matriz , que es apuntado desde la tabla de nombres, tiene el siguiente formato (ver figura 10.2); comienza con una palabra larga que contiene el desplazamiento de los valores de la matriz desde la base del área de valores de variables. Va seguida por una palabra que contiene el número de dimensiones. Después de cada dimensión va un par de palabras; la primera es el índice máximo, y la segunda es el índice multiplicador para esa dimensión.

Las matrices de coma flotante y de enteros se almacenan en una forma regular. La primera toma hasta 6 octetos por elemento y 1a de entero ocupa 2 octetos por elemento.

Las matrices de cadena no son tan regulares, debido a la longitud variable de sus entradas. Estas matrices se almacenan como una matriz de caracteres. El elemento cero de la última dimensión es una palabra que contiene la longitud máxima de la cadena. Esta dimensión se redondea siempre al valor par más cercano (de forma que cada cadena empiece en frontera de palabra).

Las operaciones de troceado de cadenas producen subcadenas, que son matrices normales de caracteres. La base a que se refiere el índice es distinta de cero. Se debe tener en cuenta que el descriptor de la subcadena de una subcadena de una matriz es incorrecta en la versión actual del BASIC.

10.5 Ejemplos de almacenamiento de variables

Variables de coma flotante (en hex)
almacenadas como: representan:
0000 0000 0000 0.0
0801 4000 0000 1.0
0800 8000 0000 -1.0
0804 5000 0000 10.0
ver también sección 8.5.4
Matrices de coma flotante
base, 2,3,3,2,1 DIM A (3,2)

Almacenamiento de cadenas (números en decimal )
4; 65, 66, 67, 68 'ABCD'

Matrices de cadena
base, 2,3,12, 10,1 DIM A$ (3,10)
4; 65, 66, 67, 68, x, x, x, x, x, x "ABCD"
9; 49, 5(), 51, 52, 53, 54, 55, 56, 57, x "123456789"
0; x, x, x, x, x, x, x, x, x, x ""
1;32, x, x, x, x, x, x, x, x, x " "

Matrices de subcadena
base, 1, 3, 1 A$ (0, 1 TO 3)
65, 66, 67 "ABC"

Figura 10.2 - Almacenamiento de matrices en BASIC

10.6 Pasando parámetros a procedimientos/funciones

Antes de entrar en más detalles sobre como escribir procedimientos, es necesario entender como se transfieren parámetros entre los diferentes tipos de operaciones.

Variables locales

Las variables locales dentro de los procedimientos y funciones, son las más fáciles de entender, porque no sucede prácticamente nada. Cuando se encuentra una sentencia LOCAL, la entrada de la variable dada se copia en lo alto de 1a tabla de nombres. El contenido de 1a entrada original se reemplaza por el nuevo valor de la variable vacía. Esta nueva entrada vacía es 1a que se usa dentro del procedimiento. Al final, no se requiere más la variable LOCAL, por lo que la vieja entrada se copia de vuelta desde lo alto de la pila, borrando la entrada LOCAL en proceso.

Parámetros de llamada a procedimientos y funciones BASIC

El método que se sigue para pasar parámetros a un procedimiento es ligeramente más complejo que con las variables LOCAL. Cuando se llama al procedimiento se crea una entrada completa por cada parámetro, en lo alto de la tabla de nombres. Para las funciones BASIC y procedimientos, se crean entradas nulas para los parámetros omitidos. El contenido de cada nueva entrada debe ser intercambiado con el contenido de cada entrada apuntada en la lista de parámetros. Todas las referencias dentro de la rutina, a los parámetros omitidos, usarán las nuevas definiciones.

Cuando se llega al final de un procedimiento, se vuelven a copiar los valores antiguos. Después de esto, se borran de la tabla de variables todas las entradas de parámetros y las entradas temporales. El mismo proceso ocurre con las rutinas en código máquina.

Los parámetros de llamada tienen el mismo formato que las variables ordinarias en la tabla de nombres, pero contienen información extra enmascarada dentro del octeto de código (el segundo) de la entrada de la tabla de nombres. La forma de este segundo octeto es:

hsssvvvv
h=1 si el parámetro va precedido por #
sss es el siguiente separador
000 sin separador
001 ,
010 ;
011 Ñ
100 !
101 TO
vvvv es el tipo
0000 nulo
0001 cadena
0010 coma flotante
0011 entero

10.7 Escribiendo procedimientos en código máquina

10.7.1 Introducción

Esta sección reúne todas las ideas que se han ido presentando en este capítulo. Una vez que lo haya leído, será capaz de producir procedimientos simples y funciones para el SuperBASIC. La sección 10.8 incluye un ejemplo comprensible para poner facilidades para las pantallas 0 y 1.

Las siguientes reglas pueden serle útiles para escribir procedimientos en código máquina:

· Recuerde en todo momento que el área del programa SuperBASIC es susceptible de moverse mientras se ejecuta en modo USUARIO. Por esta razón, es muy importante asegurarse que todas las referencias a este área se hacen usando A6 o A7 como índices. Ya que A6 y A7 son susceptibles de cambiar en cualquier momento, nunca se deben salvar, alterar (excepto metiendo o sacando A7 de la pila) o usar en cálculos aritméticos o de direcciones. Una vez dicho esto, es posible entrar en modo SUPERVISOR (usando el TRAP#O) para que la acción sea atómica. Si se hace así, asegúrese que ni A6 ni USP(A7) son alterados antes de entrar en modo supervisor, y que son restaurados completamente antes de volver al modo usuario y retornar.

10.7.2 Creando entradas en la tabla de nombres

Antes de que un procedimiento pueda ser totalmente accesible desde BASIC, debe estar debidamente conectado en la tabla de nombres. Los procedimientos BASIC en la ROM se conectan

automáticamente (ver apéndice C) . Es bastante simple conectar los procedimientos que están en la RAM. Generalmente, estos procedimientos están en el área de procedimientos residentes. Esto es debido a que no se pueden borrar, excepto rearrancando el QL. Si se quita un procedimiento, una vez que se ha puesto su nombre en la tabla de nombres, cualquier intento de acceso haría que fallara el sistema entero.

Para conectar un procedimiento en RAM, A1 debe ponerse apuntando al principio de la lista de definición del procedimiento, y se debe hacer una llamada a BP.INIT (utilidad por vector $110). Se puede usar un código como este:

LEA PROCDEF(PC),Al
MOVE.W $110,A2
JSR (A2)

PROCDEF es una lista de definición de procedimiento en formato estándar:

1 palabra número de procedimientos

…por cada procedimiento:

1 palabra apuntador a la rutina
1 octeto longitud del nombre del procedimiento
x caracteres del nombre del procedimiento

…por cada función:

1 palabra apuntador a la rutina
1 octeto longitud del nombre de la función
x caracteres del nombre de la función
1 palabra 0 fin de la lista de definición

Los apuntadores a las rutinas son todos relativos a la dirección donde está asignado el apuntador.

El espacio interno de la tabla se reserva por el número de funciones o procedimientos. Si la longitud del nombre del procedimiento o función excede de 7, esta debe ser (número total de caracteres + número de funciones o procedimientos + 7)/8

BP.INIT preserva todos los registros excepto A1, y usa un máximo de 46 octetos en la pila del usuario.

10.7.3 La pila aritmética

El paquete de rutinas aritméticas requiere un poco de área de trabajo, para contener los argumentos y resultados de la evaluación de expresiones. La pila aritmética proporciona este área. Esta pila está normalmente referenciada por A1. Se puede usar en código máquina para evaluar la llamada o retornar parámetros, o simplemente como espacio general de trabajo.

Las rutinas que toman argumentos, reservan espacio suficiente en la pila aritmética, para su propio uso. Si un procedimiento diseñado por el usuario quiere utilizar espacio en la pila aritmética, lo debe reservar con una llamada a BV.CHRIX (utilidad por vector $11A). El número de octetos requeridos se pasa en D1.L. La pila aritmética se puede mover cuando se efectúa esta llamada. Por lo tanto, el apuntador a la pila aritmética, se debe salvar (en BV.RIP(A6)), si hubiera algo en la ella. BV.RIP debe volver a su valor original, al terminar.

La pila aritmética se limpia automáticamente por las rutinas de interconexión de los procedimientos y funciones, después de los procedimientos y funciones en error.

10.7.4 Tomando argumentos de los procedimientos

Se puede obtener un número indeterminado de argumentos de procedimiento, usando una de las rutinas CA.GTINT, CA.GTFP, CA.GTSTR y CA.GTLIN que obtienen palabras enteras, números de coma flotante , cadena y palabras largas enteras, respectivamente

A3 apunta a los argumentos (el primer parámetro en la tabla de nombres) y A5 (el último parámetro en la lista). Las rutinas convierten los parámetros entre estos limites a la forma requerida, poniendo los resultados dentro de la pila aritmética. El primer argumento está en la dirección más baja apuntada por (A6, A1.L). D3 contiene el número de argumentos que son recogidos al retorno. El # y los indicadores del separador en la entrada de la tabla de nombres, son destruidos. Los argumentos se pueden procesar de uno en uno extrayendo el # y el indicador de separador. A4 debe cargarse con 8 octetos más que A3 y se debe llamar a la rutina adecuada para obtener un argumento.

Las rutinas se pueden encontrar en la sección de las utilidades por vector:

$112 CA.GTINT obtiene palabras de enteros
$114 CA.GTFP obtiene números de coma flotante
$116 CA.GTSTR obtiene cadenas
$118 CA.GTLIN obtiene palabras largas de enteros

10.7.5 Retorno de valores de variables

Se pueden devolver valores de variables desde las funciones, poniendo el valor en la pila aritmética con (A6,A1.L) apuntándolo. El valor de A1 se debe almacenar en el área de variables BASIC en BV.RIP(A6) que está situada en ($58(A6)). D4 debe contener el tipo del argumento retornado. Los argumentos posibles son:

D4=1 argumento de cadena
D4=2 argumento de coma flotante
D4=3 argumento entero (palabra)

Las enteros de palabra larga se deben convertir en formato de coma flotante. Sólo se debe hacer un retorno bueno desde una función, si la pila está limpia. Esta significa que el argumento de retorno debe estar en lo alto de la pila, y la función no debe dejar nada debajo.

10.7.6 Retorno de valores de parámetros

Hay una rutina especial de utilidad, llamada BP.LET, que permite retornar valores a través de la lista de parámetros de un procedimiento o función. Para hacerlo, se debe poner el valor a retornar en la pila aritmética (BV.RIP(A6) debe contenerlo). El argumento debe estar en la forma requerida por el parámetro de llamada, ej. cadena, entera o coma flotante. La entrada apropiada de parámetro en la tabla de nombres, debe ser apuntada por A3. Después se debe llamar a la rutina BP.LET (vector $120). Ver la sección 8.5.3 para más detalles sobre esta llamada.

Si el valor de retorno es una expresión y no una variable con nombre, el valor retornado se perderá. Si se devuelven cadenas, se debe tener cuidado en asegurarse que el contador de octetos de la cadena está en frontera de palabra. Esto se puede hacer rellenando la longitud impar con un octeto a ceros al final.

10.8 Cambiando entre las pantallas 0 y 1

En el QL, hay dos diferentes áreas de memoria que se pueden usar para generar una imagen en la pantalla. La pantalla normal se llama pantalla 0 y está situada en los 32K inferiores de la RAM, debajo de las variables del sistema. La segunda pantalla está situada en los 32K de RAM por encima de la primera. Desgraciadamente, las variables del sistema están situadas por encima de la pantalla 0. Esto significa que están realmente dentro de la pantalla l.

Sin embargo, no todo está perdido. Hay todavía una posibilidad de usar la mayoría de la pantalla 1 (quitando los 5K asignados a las variables del sistema). Para hacerlo, la pantalla 0 se debe usar solamente para mostrar la quinta parte superior de la pantalla. La pantalla 1 se vuelca a la pantalla, bajo control de las interrupciones, cada cuadro. La parte inferior de la pantalla se puede usar entonces para gráficos rápidos. El dibujo ocurre en una pantalla mientras que se muestra en 1a otra, y viceversa.

Ahora puede usted pensar que el cambio de pantallas se debe hacer mediante procedimientos y funciones añadidas al BASIC. En esta sección se presenta un paquete completo de utilidad para el manejo de pantallas. Se añaden tres nuevos procedimientos al BASIC. SCR0 pone la pantalla 0, SCR1 pone la pantalla 1 (con la parte superior enmascarada) y SCRA pone el modo de auto-cambio de forma que al pulsar CTRL-F5, se cambiará de una pantalla a otra. Para que el programa nos indique que pantalla está usándose en cada momento, se proporciona una función llamada SCRNUM.

10.8.1 Programa de soporte de dos pantallas

*
* Utilidad de soporte de dos pantallas
*
MT.ALCHP EQU $18
MT.LPOLL EQU $1C
BP.INIT EQU $110
SV_SCRST EQU $33
SV_MCSTA EQU $34
SV_SER1C EQU $98
SV_SER2C EQU $9C
SV_MDRUN EQU $EE
MC_STAT EQU $18063
MC..SCRN EQU $7
BV_RIP EQU $58
*
* Primero inicia los procedimientos extra de BASIC
*
MOVE.W BP.INIT,A2
LEA PROC_DEF(PC),A1
JSR (A2)
*
* Ahora reserva la segunda pantalla
*
MOVEQ #MT.ALCHP,D0
MOVE.L #$6BE0,D1
TRAP #1
TST.L D0
BNE.S EXIT
*
* Ahora conéctalo al gestor de interrupciones
*
LEA INT_SERVE(PC),A1 Dirección de entrada
MOVEQ #MT.LPOLL,D0
LEA INT_LINK(PC),A0 Dirección de conexión
MOVE.L A1,4(A0) Poner entrada en conexión
TRAP #1 Conectarla
EXIT
RTS
*
* Definición de procedimientos BASIC
*
PROC_DEF
DC.W 3
DC.W SCRA-*
DC.B 4,'SCRA'
DC.W SCR0-*
DC.B 4,'SCR0'
DC.W SCR1-*
DC.B 4,'SCR1'
DC.W 0
DC.W 1
DC.W SCRNUM-*
DC.B 6,'SCRNUM'
DC.W 0
*
* Poner auto-cambio de pantallas
*
SCRA
LES SCR_AUTO(PC),A1
ST (A1) Poner auto-cambio
BRA.S EXIT_OK
*
* Poner pantalla 0
*
SCR0
LEA SCR_AUTO(PC),A1
CLR.W (A1) Pantalla 0, no auto-cambio
BRA.S EXIT_OK
*
* Poner pantalla 1
*
SCR1
LEA SCR_AUTO(PC),A1
MOVE.W #$00FF,(A1) Pantalla 1, no auto-cambio
BRA.S EXIT_OK
*
* Ver qué pantalla está mostrándose
*
SCRNUM
MOVE.L BV_RIP(A6),A1 Debe haber sitio para dos octetos
SUBQ #2,A1
MOVE.L A1,BV_RIP(A6)
MOVEQ #1,D1 Retorno 1
AND.B SCR_1(PC),D1 … ó 0
MOVE.W D1,(A6,A1.L)
MOVEQ #3,D4 Es tipo entero
EXIT_OK
MOVEQ #0,D0
RTS
*
*
* Servicio de interrupciones
*
SCR_AUTO DS.B 1
SCR_1 DS.B 1
INT_LINK DS.L 2 Dirección conex. y entrada
INT_BASE EQU INT_LINK-8 Tabla conex. (a3 a entrada)
INT_SERVE
MOVE.B SV_MCSTA(A6),D1 Devolver pantalla 0
MOVE.B D1,MC_STAT
*
TST.B SCR_1-INT_BASE(A3) ¿Requiere pantalla 1?
BEQ.S INT_TOGGLE … no,
TST.L SV_SER1C(A6) ¿Está abierta serie 1?
BNE.S EXIT_INIT … si, error temporiz.
TST.L SV_SER2C(A6) ¿Está abierta serie 2?
BNE.S EXIT_INT … si, error temporiz.
TST.B SV_MDRUN(A6) ¿Está funcionando microdrive?
BNE.S EXIT_INT … si, error temporiz.
*
MOVE.W #1360,D0 Esperar a pasar las
DBRA D0,* … variables del sistema
*
BSET #MC..SCRN,D1
MOVE.B D1,MC_STAT
*
INT_TOGGLE
TST.B SCR_AUTO-INT_BASE(A3) ¿CTRL F5 cambiando?
BEQ.S EXIT_INT … no
TST.B SV_SCRST(A6) ¿Se ha pulsado CTRL F5?
BEQ.S EXIT_INT … no
SF SV_SCRST(A6)
NOT.B SCR_1-INT_BASE(A3) Cambiar pantalla
EXIT.INT
RTS

10.8.2 Cómo funciona el programa

La primera parte del programa se encarga de la iniciación. BP.INIT se usa para preparar las entradas de la tabla de nombres de los procedimientos y las funciones (ver sección 10.7.2 para más información). Después se llama al TRAP del gestor MT.ALCHP para reservar memoria en el área común ($6BE0 octetos). Esto se hace para que no pueda escribir sobre la pantalla 1 ninguna otra asignación del área común. Finalmente, se conecta el director de interrupciones a la lista encadenada de interrupciones 50/60Hz. Esta es la rutina que cambia de la pantalla 0 a la 1, controlando cuidadosamente la posición en que ocurre el cambio.

El código de cada procedimiento es bastante simple. Cada uno contiene un octeto en SCR_AUTO. El gestor de interrupciones lee esta posición para determinar cuando debe cambiar de pantalla o poner la 0 ó la 1.

SCRNUM es una función que devuelve el número de la pantalla actual como 0 ó 1. Retorna el valor al BASIC usando el mecanismo que se describe en la sección 10.7.5. El valor devuelto se convierte en tipo entero.

La rutina de servicio de interrupciones comprueba el contenido de SCR_AUTO para determinar que acción (si hay alguna) se debe tomar. La pantalla 1 sólo se puede seleccionar después de las variables del sistema (de otro modo aparecería la imagen de las variables del sistema). La temporización para este periodo se hace usando DBRA D0,* que pone el 68008 en un bucle interno temporizado. Esto sólo puede funcionar si no se están usando las interrupciones de alta prioridad de las puertas serie o los microdrives. Si va a ocurrir alguna de estas interrupciones, la pantalla 1 es retenida.

10.9 Implementación de BPUT# como procedimiento

Este ejemplo prepara un procedimiento BASIC que permite mandar octetos individuales a un canal (como un microdrive).

*
* Utilidad de sacar un octeto simple
*
MT.LPOLL EQU $1C
CA.GTINT EQU $112
IO.SBYTE EQU $05
ERR.BP EQU -15
ERR.NO EQU -6
BP.INIT EQU $110
BV_CHBAS EQU $30
BV_CHP EQU $34
*
* Primero inicia el procedimiento BASIC BPUT#n,dato
*
MOVE.W BP.INIT,A2
LEA PROC_DEF(PC),A1
JSR (A2)
MOVEQ #0,D0
RTS
*
* Definición del procedimiento BASIC
*
PROC_DEF
DC.W 1
DC.W BPUT-*
DC.B 4,'BPUT'
DC.W 0
DC.W 0
DC.W 0
*
* Rutina BPUT
*
BPUT
BSR.S CHANNEL
MOVE.W CA.GTINT,A2
JSR (A2)
SUBQ.W #1,D3 ¿Sólo un argumento?
BNE.S ERR_BP
MOVE.B 1(A6,A1.L)D1
MOVEQ IO.SBYTE,D0 Mandar el octeto al canal
MOVEQ #-1,D3
TRAP #3
RTS

*
ERR_BP
MOVEQ #ERR.BP,D0 Parámetros inválidos
RTS
*
* Pone el canal dado o el defecto
* Parámetros de llamada:
*
* A3 y A5 apuntadores estándar a la tabla de nombres para los parámetros
*
* Parámetros retornados:
*
* D6 apuntador a la tabla de canales
* A0 ID del canal
*
CHANNEL
MOVEQ #1,D6 Canal #1 por defecto
CMPA.L A3,A5 ¿Algún parámetro?
BEQ.S CHAN_LOOK … no
*
BTST #7,1(A6,A3.L) ¿Es # el 1er parámetro?
BEQ.S CHAN_LOOK … no
*
MOVE.L A5,-(A7) Salvar apuntador a 1er parám.
MOVE.L A3,A5 Poner nuevo tope
ADDQ #8,A5 a 8 octetos desde abajo
MOVE.L A5,-(A7) (ahora es la nueva base)
MOVE.W CA.GTINT,A2 Tomar un entero
JSR (A2)
MOVE.L (A7)+,A3 Restaurar apunt. parámetros
MOVE.L (A7)+,A5 (No altera códigos condición)
BNE.S CHAN_EXIT ¿Está bien?
MOVE.W 0(A6,A1.L),D6 Reemplazar defecto con D6
*
CHAN_LOOK
MULU #$28,D6 D6 apunta a tabla canales
ADD.L BV_CHBAS(A6),D6
CMP.L BV_CHP(A6),D6 ¿Está dentro de la tabla?
BHI.S ERR_NO … no
MOVE.L 0(A6,D6.L),A0 Poner ID del canal
MOVEQ #0,D0 Sin error
CHAN_EXIT
RTS
ERR_NO
MOVEQ #ERR.N0,D0 Canal no abierto
RTS

10.9.1 Cómo funciona el programa

La primera parte del programa se encarga de la iniciación. BP.INIT se usa para preparar la entrada del procedimiento BPUT, en la tabla de nombres.

Después, la rutina CHANNEL, busca el número del canal precedido por '#'. Si lo encuentra, el registro A0 nos devuelve el ID del canal con un apuntador a la tabla de canales en D6. El octeto que se va a mandar a este canal se obtiene usando CA.GTINT. Finalmente, se manda el octeto con IO.SBYTE.

En la sección 8.5.5 podemos ver otro ejemplo de conexión de una función al BASIC.


Anterior Tabla de contenidos Siguiente
Controladores de dispositivo   Mapa de la memoria