Sinclair QL Programación Avanzada
Anterior Siguiente

9. Controladores de dispositivo

9.1 Introducción

Nota: Documento por revisar

En este capítulo se tratan las formas en las que los dispositivos típicos se conectan al sistema operativo del QL. Como hemos podido apreciar en los primeros capítulos, el QL tiene un sistema de E/S redireccionable, bastante potente. Para que este sistema de E/S funcione igualmente bien con una gran variedad de dispositivos físicos, es necesario tener un mecanismo de interconexión eficaz. Este mecanismo de interconexión lo proporcionan los controladores de dispositivo.

El controlador de dispositivo se sitúa en medio de dos procesos. En una parte está el QL IOSS (subsistema de E/S). Este espera que el controlador de dispositivo abra y cierre los canales y mande o reciba datos por ellos. En la otra parte, el controlador de dispositivo debe ser capaz de controlar ciertas piezas de 'hardware'. El control se pasa normalmente siguiendo la interrupción de un dispositivo, o la interrupción de los 50/60 Hz del QL, o cuando lo invoca el planificador.

El controlador de dispositivo se puede considerar como un sistema de comunicación entre dos medios separados. El mediador de acceso, comunica con el IOSS. Se deben proporcionar tres puntos de entrada al IOSS. Uno para abrir un canal, uno para cerrarlo, y uno bidireccional que permite transferir datos entre el dispositivo y el IOSS. El otro mediador se llama el mediador físico, y su función esencial es el control del dispositivo físico y la comunicación de datos con él.

El mediador físico debe ser un dispositivo altamente especializado, ya que la mayoría de los dispositivos físicos son bastante similares. Sin embargo el procedimiento de interconexión del mediador de acceso es muy específico y debe seguir unas normas muy rígidas, independientemente del dispositivo que esté controlando.

El controlador de dispositivo debe mantener espacio en la RAM para almacenar cierto tipo de información. A cada controlador de dispositivo se le asigna un bloque de definición de controlador de dispositivo, que puede estar en el bloque de variables para los controladores de dispositivos integrados, o en otra parte de la memoria (con algunas restricciones en su localización) para los controladores adicionales. Este bloque de RAM está disponible como área de trabajo estática del controlador de dispositivo, y contiene información, como el número de canales abiertos a ese controlador, la dirección de estos canales (o un apuntador a una lista encadenada de canales - si el número puede ser infinito), el estado actual del dispositivo de E/S, etc. Este área es propiedad del controlador de dispositivo, y por lo tanto del sistema operativo del que forma parte.

Es posible abrir un mismo dispositivo por varios canales a la vez. En este caso, el controlador del dispositivo debe ser re-entrante. Lógicamente, si el controlador del dispositivo intenta mantener el estado de cada canal por sí mismo, se hará un verdadero lío. Por esta razón, cada canal asigna un bloque de definición de canal, que se crea al abrirlo con IO.OPEN (TRAP#2 D0=l), y que es propiedad del Job que lo ha creado.

Ahora se tratarán más en profundidad los conceptos básicos que acabamos de ver.

9.2 Bloques de definición de controlador de dispositivo

Los controladores de dispositivo se suelen conectar al sistema operativo cuando se enciende la máquina. Disponemos de una serie de TRAPS del gestor (TRAP#1 con D0=1A al 23), para poder hacerlo. No es imprescindible conectar los controladores de dispositivo al sistema operativo a tiempo de encendido - se pueden añadir después si se requieren. El gestor mantiene varias listas encadenadas, para distintas operaciones, que siguen el formato estándar que se vio en detalle en la sección 5.4.5.

Existen cinco listas encadenadas. Tres de ellas son para el mediador físico que se invoca por:

1.     interrupciones externas
2.     interrupciones de los 50/60Hz
3.     bucle del planificador

Como se describió en la sección 5.4.5, una lista encadenada se produce reservando dos palabras largas. La primera forma la conexión a la lista, la segunda debe ser la dirección del código del controlador del dispositivo físico. Estas dos palabras largas se encuentran normalmente al principio de un bloque de memoria. El resto de los bloques están disponibles para que las use por el controlador del dispositivo. Alguno de estos usos son: almacenamiento de indicadores, apuntadores, memoria intermedia, etc.

El sistema operativo pasa, del dispositivo físico al controlador, varias piezas de información útiles. Estas van en los registros del 68008 como sigue:

  D3

número de interrupciones de 50/60Hz desde la última llamada del planificador (sólo bucle planificador)

  A3 apuntador bloque de definición del controlador del dispositivo
  A6 apuntador a las variables del sistema
  A7 pila del supervisor (se pueden usar 64 octetos)

A6 y A7 deben ser preservadas por el controlador del dispositivo.

Para las llamadas del mediador de acceso, A3, A6 y A7 tienen el mismo significado, pero los otros registros son diferentes (ver 9.4).

A3 apunta a la dirección base del bloque de definición. Este se refiere a una definición de un controlador de dispositivo estándar (ver debajo). Sin embargo, es posible tener una definición no estándar diferente (por ejemplo, algunas direcciones de entrada y apuntadores de conexión se pueden eliminar). Si se usa una definición no estándar, A3 no tendrá un valor adecuado.

  $00(A3) conecta la siguiente rutina de interrupción externa
  $04(A3) dirección de la rutina de interrupción externa
  $08(A3) conecta la siguiente rutina de interrupción 50/60Hz
  $0C(A3) dirección de la siguiente rutina de interrupción 50/60Hz
  $10(A3) conecta la siguiente rutina de bucle del planificador
  $14(A3) dirección de la rutina de bucle del planificador
  $18(A3) conecta el mediador de acceso del siguiente controlador de dispositivo
  $1C(A3) dirección de la rutina de entrada/salida
  $20(A3) dirección de la rutina de abrir canal
  $24(A3) dirección de la rutina de cerrar canal
  $28(A3) espacio de trabajo del controlador de dispositivo físico

9.3 Mediador de acceso

Para inicializar el mediador de acceso, se debe conectar un bloque de memoria en el IOSS, mediante MT.LIOD (TRAP#l con D0=20). Este bloque de memoria debe estar en el área de procedimientos residentes o en el área común. Debe tener cuatro palabras de longitud, desde el principio del bloque.

El gestor usa la primera, para formar la lista encadenada, la segunda, tercera y cuarta palabras largas son las direcciones de entrada para entrada/salida, abrir y cerrar el canal. El resto del bloque se puede usar para almacenar apuntadores, memoria intermedia, etc.

El formato del bloque es:

  palabra larga 1 apuntador de conexión a la siguiente rutina encadenada
  palabra larga 2 dirección de entrada para entrada/salida
  palabra larga 3 dirección de entrada para abrir un canal
  palabra larga 4 dirección de entrada para cerrar un canal

Todas las llamadas del mediador de acceso se hacen en modo supervisor.

9.3.1 Abrir un canal

Cuando se hace una llamada para abrir un canal, A0 contiene un apuntador al nombre del dispositivo y D3 contiene una clave. En A3 está la base del bloque de definición del controlador del dispositivo. A6 apunta al área de variables del sistema y A7 contiene el apuntador a la pila del supervisor. Los registros D0 a D7 y A1 a A6 se pueden tratar como volátiles.

La secuencia a seguir para una operación de OPEN es:

- Decodificar el nombre del dispositivo
- Asignar un bloque de definición de canal y memoria intermedia en el área común
- Inicializar el bloque de definición de canal (excepto las 6 primeras palabras largas)
- Devolver la dirección del bloque de definición del canal en el registro A0.

Todos los canales son bidireccionales. Es responsabilidad del controlador del dispositivo, el detectar las operaciones ilegales. Cuando se hace OPEN a un canal, pueden ocurrir cuatro tipos comunes de error, que se pasan en el registro D0. ERR.NF significa que el nombre del dispositivo no ha sido reconocido. ERR.IU significa que el dispositivo de E/S está siendo usado por otro Job y no se puede compartir. ERR.BN significa que se ha reconocido el nombre del dispositivo pero es incorrecta parte de la información que se ha pasado. ERR.OM significa que todo es correcto, pero el bloque de definición de canal o la memoria intermedia no se pueden asignar, debido a falta de memoria.

9.3.2 Entrada y salida de un canal

La llamada de entrada/salida se realiza primero durante el TRAP de E/S. Si el TRAP ha sido especificado como de esperar hasta completarlo, la llamada se hace una vez cada bucle del planificador. Esta operación continúa hasta que se ha completado, o hasta que se cumpla el tiempo de espera.

A0 debe apuntar al bloque de definición de canal, antes de hacer la llamada de E/S. D0 define la operación requerida (es una clave de un octeto y el I0SS limpia los tres octetos superiores). En D1, D2, A1 y A2 se pasa información adicional. El registro D1 lo pone el IOSS a ceros para las operaciones de cadena (IO.FSTRG, IO.FLINE, IO.SSTRG, FS.HEADS, FS.HEADR, FS. LOAD y FS.SAVE). Si una operación no se completa, se deben poner a la salida los valores de D1 y A1 de modo que se puedan usar en los siguientes reintentos. Para ayudar en este proceso, se pone D3 a ceros en la primera entrada, pero se va modificando a -1 en la segunda y siguientes. D0, D2 y A2 mantienen sus valores originales a través del proceso.

D0 define siempre la operación, A3 apunta a la base del bloque de definición de controlador de dispositivo, A6 apunta al área de variables del sistema y A7 es el apuntador a la pila del supervisor.

Dentro del controlador de dispositivo, se pueden modificar los registros D2 a D7 y A2 a A6.

9.3.3 Cerrar un canal

Una operación de CLOSE de un canal comprueba que todo está limpio y después libera el espacio que fue asignado para el bloque de definición del canal y la memoria intermedia. Si quedan todavía algunos octetos que transmitir, no es posible liberar el espacio inmediatamente. En estos casos, el bloque será borrado en una llamada posterior del planificador, cuando los datos hayan sido transmitidos.

A la rutina de CLOSE se le pasa la dirección del bloque de definición de canal, en el registro A0. La base del bloque de definición de controlador de dispositivo se pasa en el registro A3. A6 apunta al área de variables del sistema y A7 es el apuntador a la pila del supervisor. Los registros D1 a D3 y A0 a A3 pueden ser modificados. En D0 se debe pasar el código de error. Normalmente este debe ser cero (ej. sin errores) ya que la mayor parte del sistema asume que el CLOSE nunca falla.

9.4 Mediador físico

Como ya mencionamos en la sección 9.1, el mediador físico tiene como función el interconectar el controlador del dispositivo y el 'hardware' externo. Esta interconexión se puede realizar en cualquiera de los siguientes eventos:

1. Interrupciones externas

Las interrupciones externas son generadas por dispositivos externos particulares. Si un controlador de dispositivo espera interrupciones externas mientras se está ejecutando, primero debe comprobar el estado del 'hardware' para ver si la interrupción la ha mandado él. Si la interrupción no viene del dispositivo correcto, se debe hacer un retorno mediante la instrucción RTS. Si la interrupción es para él, se debe servir al 'hardware' y limpiar la fuente de la interrupción. Se debe retornar a la fuente de la interrupción mediante una instrucción RTS. Las operaciones atómicas (como las llamadas del mediador de acceso al mismo controlador) pueden ser interrumpidas por esta interrupción.

2. Interrupciones de 50/60Hz

Esta interrupción solo debe ser usada para operaciones de temporización crítica, u operaciones que no se deban mantener por periodos largos. Un ejemplo de operación de temporización crítica puede ser el incremento de un registro para controlar el tiempo, o la generación de envolventes de sonido. Si el 'hardware' externo no puede interrumpir al sistema cuando necesita servicio, se puede usar la interrupción de 50/60 Hz para comprobar si un dispositivo necesita servicio. Las operaciones atómicas (como las llamadas del mediador de acceso al mismo controlador) pueden ser interrumpidas por esta interrupción.

3. Bucle del planificador

Las llamadas del bucle del planificador llegan a intervalos irregulares (dependiendo de la carga de trabajo del sistema), por lo que no pueden usar este bucle las operaciones que que deban ser procesadas inmediatamente. Las operaciones atómicas no pueden ser interrumpidas por el planificador, por lo que las operaciones de asignación y liberación de memoria se pueden realizar, para mayor seguridad, con rutinas que se ejecuten fuera del planificador.

Notas generales sobre el mediador físico.

El mediador físico permite trasferir datos dentro o fuera de las colas o ejecutar funciones de control asíncronas con un Job que requiera E/S. Todas las rutinas del mediador físico son llamadas en modo supervisor, de forma que todo está en condiciones para que puedan inhabilitar las interrupciones. Cualquier error debe ser tratado mediante un indicador que entienda el mediador de acceso. Sin embargo, es posible usar las rutinas de utilidad UT.ERR y UT.MTEXT con A0=0. Después se hará un intento de escribir un mensaje al canal 0, o, si esto falla, al canal 1. El mensaje aparecerá en uno de estos canales si no están esperando por entrada. Si ambos están esperando por entrada, no aparecerá ningún mensaje. Las rutinas de manejo de colas han sido diseñadas para que puedan trasferir datos desde/hacia una cola asíncronamente.

9.5 Decodificación del nombre de dispositivo

La rutina de utilidad IO.NAME (vector $122) es muy útil para ayudarnos en la decodificación de nombres de dispositivos. Realiza dos operaciones, comprobar el nombre del dispositivo y evaluar cualquier parámetro opcional.

El nombre completo del dispositivo contiene cuatro componentes:

  1. Nombre Caracteres ASCII, normalmente letras independientemente de si son mayúsculas o minúsculas.
  2. Separador Caracteres ASCII, si es una letra no importa si es mayúscula o minúscula.
  3. Número Número decimal en el rango 0 a 2^15-1
  4. Código Uno de una lista de caracteres ASCII

Cuando se llama a IO.NAME, A0 debe contener un apuntador al nombre real del dispositivo. A3 debe contener un apuntador a un bloque de memoria suficientemente grande para almacenar los valores de los parámetros. Si la rutina se ejecuta satisfactoriamente, el bloque se llenará con los parámetros dados o los asignados por defecto.

IO.NAME tiene tres posibles retornos:

  retorno D0 (+SR)
  estándar ERR.NF nombre no reconocido
  estándar+2 ERR.BN nombre reconocido, parámetro malo
  estándar+4 0 retorno satisfactorio

La descripción del nombre de dispositivo comienza 6 octetos después de la llamada.

9.5.1 Descripción del nombre del dispositivo

La descripción está en la siguiente forma:

- Número de caracteres en el nombre, caracteres del nombre
- Número de parámetros

Por cada parámetro uno de:

- Espacio + separadores, valor por defecto (numérico)
- Número negativo, valor por defecto (número, no separ)
- Número de códigos, lista de códigos ASCII.

Todos los ítems se definen como palabras y todas las letras deben ir en mayúsculas. Ya que los códigos ASCII de los caracteres caben realmente en octetos, cualquier octeto impar al final, se rellena con cero. Por ejemplo:

DC.W  'ABC'

aparece en memoria así:

palabra 1   $00   03
palabra 2   $41   42
palabra 3   $43   00

Por cada parámetro numérico de la descripción, la rutina devolverá el valor dado o el asignado por defecto. Por cada lista de códigos en la descripción, la rutina devolverá la posición del código en la lista o cero.

Ejemplos

La descripción CON es:

DC.W  3,'CON'

consola

DC.W  5

cinco parámetros

DC.W  '_',448,'X',200

tamaño ventana

DC.W  'A',32,'X',16

posición ventana

DC.W  '_',128

longitud memoria intermedia teclado


Nombre de dispositivo

parámetros devueltos

   
CON

448,200,32,16,128

CON_256

256,200,32,16,128

Con_60

448,200,32,16,60

Cona0x12

440,200,0,12,128

Con_256x64a64x 28_20

226,64,64,128,20

La descripción de SER es:

DC.W  3,'SER'

dispositivo serie RS232

DC.W  3

tres parámetros

DC.W  -1,1

número de puerta (1 por defecto)

DC.W  4,'EOMS'

paridad impar, par, marca o espacio

DC.W  2,'1H'

ignorar/usar ‘handshaking


Nombre de dispositivo

parámetros devueltos

   
SER

1,0,0

sere

1,1,0

ser2mi

2,3,1

9.6 Asignación de memoria

Es esencial que los controladores del mediador de acceso sean totalmente reentrantes. Esto significa que la información especifica del canal debe almacenarse en el bloque de definición de canal y no en el bloque de definición del controlador del dispositivo. Los bloques de definición de canal requieren dejar 6 palabras largas al principio para que las use el IOSS. El resto del espacio en el bloque lo puede usar el controlador de dispositivo.

El controlador del mediador físico nunca debe asignar ni liberar recursos de la máquina, a menos que lo haga en una llamada al planificador.

El espacio se debe asignar siempre en el área común. Se puede usar para ello la rutina MM.ALCHP. Este espacio se puede liberar con la rutina MM.RECHP.

9.7 Colas de E/S

Hay cinco rutinas residentes para el manejo de colas. Estas controlan la entrada y salida de datos de la cola, y comprueban el contenido de los bloques de definición, y las condiciones de fin de fichero. IO.QSET pone los apuntadores de las colas. IO.QIN pone un octeto en una cola. IO.QOUT saca un octeto de una cola. IO.QEOF pone el indicador de fin de fichero IO.TEST comprueba si hay algo en la cola, devuelve el espacio libre y el valor del siguiente octeto que va a sacar sin quitarlo de la cola.

Las colas se definen por bloques de 4 palabras largas al principio. El octeto más significativo de la primera palabra larga la usan las rutinas de las colas para identificar el fin del fichero. IO.QSET limpia la palabra larga completa. El resto (ej. sin bit más significativo) se puede usar para el controlador de dispositivos, para conectar colas, etc.

La longitud usable de una cola es un octeto menos de la longitud real. El mínimo espacio ocupado por una cola y su cabecera es por la tanto de 18 octetos.

9.8 E/S serie simple

La E/S serie simple se puede manejar con IO.SERQ. Para esta rutina, la séptima y octava palabra larga en el bloque de definición de canal deben apuntar a las colas de entrada y salida. Si una de ellas está prohibida, el apuntador correspondiente se pondrá a cero. Nos devolverá el error ERR.BP para las acciones indefinidas. Ver la descripción de IO.SERQ en el capitulo 8 para más detalles.

En los casos en que las operaciones de entrada y salida no sean tan simples se puede llamar a la rutina IO.SERIO. A la instrucción de llamada le deben seguir tres palabras largas, que son las direcciones de entrada para:

1. Comprobación de entrada pendiente (D1=siguiente octeto)
2. Tomar un octeto (octeto en D1)
3. Mandar un octeto (octeto en D1)

9.9 Controladores de dispositivo de directorio

Los controladores de dispositivos de directorio son más potentes en sus aplicaciones que los controladores de dispositivo puros. Los normales son responsables de las comunicaciones con otro dispositivo. Los de dispositivo de directorio son responsables de las comunicaciones con ficheros particulares dentro del dispositivo, como un disco duro winchester. El IOSS tiene un rango de operaciones extendido para estos controladores.

9.9.1 Bloque de definición de controlador de directorio

Los bloques de definición para controladores de dispositivo de directorio son similares a los de los controladores de dispositivos. Sin embargo, hay tres partes; el bloque de conexión del controlador de directorio (uno por controlador de directorio), el bloque de definición física (uno por controlador) y el bloque de definición de canal. El IOSS asigna los dos últimos.

El bloque de conexión

La forma estándar es una versión extendida de la que usan los controladores de dispositivo. La conexión del mediador de acceso es por lo menos de 10 palabras de longitud, y tiene el siguiente formato estándar:

  $00(A3) conecta la siguiente rutina de interrupción externa
  $04(A3) dirección de la rutina de interrupción externa
  $08(A3) conecta la siguiente rutina de interrupción 50/60Hz
  $0C(A3) dirección de la rutina de interrupción 50/60Hz
  $10(A3) conecta la siguiente rutina de bucle del planificador
  $14(A3) dirección de la rutina de bucle de planificador
  $18(A3) conecta el mediador de acceso del siguiente controlador de directorio
  $1C(A3) dirección la rutina de entrada/salida
  $20(A3) dirección de la rutina de OPEN
  $24(A3) dirección de la rutina de CLOSE
  $28(A3) dirección de entrada de dependencia forzada
  $2C(A3) reservada
  $30(A3) reservada
  $34(A3) dirección de entrada de formateo de medio
  $38(A3) longitud del bloque de definición física
  $3C(A3) palabra - longitud del nombre del controlador
  $3E(A3) caracteres del nombre del controlador (ej. mdv)

9.9.2 Mediador de acceso de controlador de directorio

Como en los controladores de dispositivo, el mediador de acceso debe abrir, cerrar y sacar y recibir datos de los ficheros. Las rutinas de CLOSE y entrada/salida son las mismas que las de los controladores de dispositivo. Refiérase a las secciones 9.3.2 y 9.3.3 para más detalles. Sin embargo, abrir canales en un controlador de dispositivo de directorio es un poco más complejo.

Abriendo un canal

Antes de llamar a la rutina de abrir un canal, se deben asignar el bloque de definición de canal y el bloque de definición física. En este punto, el IOSS debe haber llenado parcialmente estos bloques. A la entrada de la rutina de OPEN, A0 apuntará al bloque de definición de canal y A1 al bloque de definición física. A3 apuntará a la base del bloque de conexión. El bloque de definición física puede haber sido asignado ya. Los ficheros se componen de bloques de 512 octetos de longitud cada uno. La posición real de un octeto es por lo tanto 512*número de bloque+número de octeto.

Bloque de definición de canal

Cabecera de definición de canal para todos los canales

$00

CH.LEN

4

longitud del bloque

$04

CH.DRIVR

4

dirección del controlador

$08

CH.OWNER

4

job propietario

$0C

CH.RFLAG

4

dirección cuando se libera el espacio

$10

CH.TAG

2

etiqueta de canal

$12

CH.STAT

1

estado:

   0 = OK

   -1 = A1 absoluto

   $80 = A1 relativo a A6

   negativo = esperando

$13

CH.ACTN

1

acción almacenada para el Job en espera

$14

CH.JOBWT

4

ID del Job esperando por ES

Bloque de definición de canal del sistema de ficheros

$18

FS.NEXT*

4

conecta al siguiente canal de fichero

$1C

FS.ACCES*

1

modo de acceso (D3 en llamada OPEN)

$1D

FS.DR1VE*

1

ID de la unidad

$1E

FS.FILNR+

2

# de fichero en la unidad

$20

FS.NBLOK

2

# de bloque que contiene siguiente octeto

$22

FS.NBYTE+

2

siguiente octeto en el bloque

$24

FS.EBLOK+

2

# bloque que contiene el octeto después del EOF

$26

FS.BYTE+

2

octeto después del EOF

$28

FS.CBLOK

4

apuntador a la tabla de bloques

dependiente para el bloque dependiente actual que puede contener el octeto actual/siguiente

$2C

FS.UPDT

 

puesto si se ha actual izado el fichero

$32

FS.NAME*

2+36

nombre del fichero

$58

FS.8PARE

72

libres


Bloque de definición física

$10

FS.DRIVR*

4

apuntador a la conexión del mediador de acceso para el controlador

$14

FS.DRIVN*

1

número de unidad

$15

 

1

reservado

$16

FS.MNAME

2+10

nombre del medio

$22

FS.SPARE

1

número de ficheros abiertos

La longitud viene determinada por la conexión del mediador de acceso.

Claves

* Inicialmente los bloques están llenos de ceros excepto los marcados con * que los llena el IOSS.

+ La rutina de OPEN no es llamada para abrir un fichero compartido a más de un canal. En este caso, FS.NBYTE se pone a $40 y la información fija se copia desde el primer canal abierto al fichero.

El ID de la unidad es un índice a la tabla de bloques de definición física, empezando en $100 desde la base de las de variables del sistema.

El borrado de ficheros es parte de la operación de apertura de ficheros. Los dos procesos se distinguen por la clave de acceso que es negativa para el borrado. Los bloques de definición se asignan de la forma usual para apertura de ficheros, pero el IOSS libera el bloque de definición del canal a su retorno. El bloque de definición de canal es liberado también por el IOSS si devuelve algún código de error en el registro D0.

9.10 Bloques dependientes

Toda la interacción con los dispositivos de almacenamiento se lleva a cabo a través de la memoria del QL, usándola como memoria intermedia. Este proceso pasa totalmente inadvertido al usuario. Si se accede a un fichero en microdrive, algunos sectores se leerán en memoria. Si se reescribe un sector al microdrive, no es necesario que se haga justo después del salvado, los datos pueden permanecer en memoria algún tiempo hasta que se vuelcan al dispositivo. A medida que el espacio usado por los programas transitorios, procedimientos residentes y el área común, aumenta, el área de bloques dependientes disminuye de tamaño.

El espacio en los bloques dependientes está definido en la tabla de bloques dependientes. Esta tabla es de tamaño variable, y depende de la cantidad de memoria disponible. Hay tres apuntadores a la tabla de bloques dependientes.

$54(A6)

SV.BTPNT

4

apuntador a la entrada asignada más recientemente en la tabla

$58(A6)

SV.BTBAS

4

apuntador a la base de la tabla

$5C(A6)

SV.BTTOP

4

apuntador a lo alto de la tabla

Cada entrada de la tabla tiene 8 octetos de longitud. El sistema operativo usa solamente el primer octeto como octeto de estado. Los otros octetos no son usados por el sistema operativo.

$00

BT.STAT

oct.

octeto de estado

 

00

imposible llenar el sistema

01

bloque vacío

X3

bloques representación del fichero

X7

bloque modificado (esperando escribir)

X9

bloque esperando lectura

XB

bloque esperando verificación

X

el ID de la unidad del fichero

$01

BT.PRIOR

1

disponible para algoritmos dependientes

$02

BT.SECTR

2

sector físico en el medio

$04

BT.FILNR

2

número de fichero

$06

BT.BLOCK

2

número del bloque contenido en este bloque dependiente

Ya que la asignación de bloques dependientes, es una forma muy simple de asignar memoria, sólo se debe realizar con llamadas al mediador de acceso o al bucle del planificador.

Será necesario buscar un bloque dependiente para usarlo como memoria intermedia de un bloque de fichero. Solamente se pueden usar los bloques vacíos o las representaciones auténticas. Cuando se asigna un bloque nuevo a un fichero, SV.BTPNT debe ser modificado.

¡No asuma nunca que los bloques que fueron asignados en una llamada están asignados aún en la siguiente, porque pueden no estarlo!. FS.CBLOK es una variable de aviso solamente. Comprueba siempre la entrada de la tabla de bloques dependientes, antes de proceder.

Algunas veces el gestor de memoria requiere el espacio asignado a un bloque actualizado o esperando por lectura o verificación. Si ocurre esto, la rutina dependiente de forzado es llamada para convertirla en una copia auténtica. La rutina no comprueba si el bloque es una copia auténtica,

pero inicia el proceso que lo hace. A la entrada de la rutina dependiente de forzado, A1 apunta al bloque depen­diente, A2 apunta al de definición física y A3 a la base del bloque de conexión (definición de controlador). Los registros D0 a D3 y A0 a A4 pueden ser alterados si se desea.

9.11 Un ejemplo con un controlador de impresora paralela

9.11.1 Introducción

Esta sección ilustra muchos de los puntos que se han explicado en las partes anteriores de este capitulo. Un ejemplo completo de un controlador de dispositivo para construir un interfaces Centronics estándar para impresora. El diagrama completo del circuito está en el Apéndice U.

Este controlador de dispositivo ha sido diseñado para contenerlo en una ROM en una tarjeta periférica. Esta tarjeta (con una ROM) se conecta al QL. En el momento de encender el ordenador. aparecerá en la pantalla el mensaje 'Interface Centronics Simple'. Desde este momento, existirá un nuevo canal llamado 'PAR'. Para listar un fichero de microdrive en la impresora, sólo debe teclear:

COPY MDV1_textfile TO PAR

Ya que es un simple ejemplo de controlador de dispositivo, no se ha previsto una memoria intermedia de impresora, por lo que el controlador intentará sacar un octeto y devolverá un 'ERR.NC' si no se puede mandar (debido a que a impresora está ocupada). Un controlador más sofisticado puede operar una memoria intermedia y mandar interrupciones generadas por el circuito de interfaces.

9.11.2 El programa controlador de dispositivo

*

* Interfaces Paralelo Centronics (sin interrupciones)

*

ERR.NC

EQU

-1

ERR.BP

EQU

-15

MT.ALCHP

EQU

$18

MT.LIOD

EQU

$20

IO.SSTRG

EQU

$7

MM.ALCHP

EQU

$C0

MM.RECHP

EQU

$C2

IO.SERIO

EQU

$EA

IO.NAME

EQU

$122

*

DATA

EQU

$0800

dirección separador de datos

STROBE

EQU

$1000

dirección ‘strobe’

BUSY

EQU

$1800

dirección memoria de BUSY

*

BASE

 

DC.L

$4AFB0001

 

DC.W

0

 

DC.W

INIT-BASE

 

DC.B

0,28,’Interface Centronics Simple’,$A

*

INIT

 

MOVEM.L

A0/A3,-(A7)

A0&A3 usado para inic. cód.

 

MOVEQ

#MT.ALCHP,D0

asignación bloque conexión

 

MOVEQ

#$36,D1

$28+3 palabras largas+1 pal.l.

 

MOVEQ

#0,D2

propiedad del Job 0

 

TRAP

#1

 
 

TST.L

D0

ver si OK

 

BNE.S

INIT_EXIT

 

*

 

LEA

$1C(A0),A3

empieza a llenar bloque

 

LEA

IO(PC),A2

entrada/salida

 

MOVE.L

A2,(A3)+

…en $1C

 

LEA

OPEN(PC),A2

abrir

 

MOVE.L

A2,(A3)+

…en $20

 

LEA

CLOSE(PC),A2

cerrar

 

MOVE.L

A2,(A3)+

…en $24

 

LEA

ERR_BP(PC),A2

comprob. pend. + tomar octeto

 

MOVE.L

A2,(A3)+

…en $28

 

MOVE.L

A2,(A3)+

…y en $2C

 

LEA

OUT_BYTE(PC),A2

manda un octeto

 

MOVE.L

A2,(A3)+

…en $30

 

MOVE.W

#$4E75,(A3)+

RTS en $34

*

 

LEA

$18(A0),A0

conectar en

 

MOVEQ

#MT.LIOD,D0

lista controlador ES

 

TRAP

#1

 

INIT–EXIT

 

MOVEM.L

(A7)+,A0/A3

 

RTS

 

*

*

OPEN

 

MOVE.W

IO.NAME,A4

decodifica nombre dispositi.

 

JSR

(A4)

 
 

BRA.S

EXIT

mal

 

BRA.S

EXIT

mal

 

BRA.S

ALCHP

nombre es ‘PAR’

 

DC.W

3,’PAR’

definición nombre PAR

 

DC.W

0

sin parámetros

ALCHP

 

MOVEQ

#$18,D1

reserva el canal mínimo

 

MOVE.W

MM.ALCHP,A4

 
 

JMP

(A4)

 

CLOSE

 

MOVE.W

MM.RECHP,A4

elimina el canal

 

JMP

(A4)

 

IO

 

CMP.B

#IO.SSTRG,D0

trap operación fichero (ej.

 

BHI.S

ERR_BP

…poner cabecera), porque

*

   

…no tiene sentido en una

*

   

…impresora

 

PEA

$28(A3)

debemos tener una llamada

 

MOVE.W

IO.SERIO,A4

…en $24(a3) a SERIO

 

JMP

(A4)

 

*

*

OUT–BYTE

 

LEA

BASE(PC),A3

toma direc. base periférico

 

TST.B

BUSY(A3)

impresora BUSY?

 

BMI.S

ERR_NC

señalar ocupada

 

MOVE.B

D1,DATA(A3)

mandar octeto

 

SF

STROBE(A3)

y STROBE (>500ns)

 

MOVE.Q

#0,D0

 

EXIT

 

RTS

   

ERR_NC

     
 

MOVEQ

#ERR.NC,D0

octeto mandado

 

RTS

   

ERR_BP

     
 

MOVEQ

#ERR.BP,D0

no puede conseguir octeto y

 

RTS

 

…no puede almacenar oper.

9.11.3 Funcionamiento del programa

Para entender cómo funciona el controlador de dispositivo, es importante comprender cómo aparece el dispositivo físico en el mapa de memoria del QL. La puerta de salida de 8 bits a la impresora está situada en la posición $0800, desde la dirección base del periférico. La salida de 'strobe' está en el desplazamiento $1000, y la entrada 'BUSY' en el $1800.

Para los que no están familiarizados con el mecanismo de decodificación de las direcciones de periféricos (Apéndice F), aquí le damos una pequeña explicación. Se pueden conectar hasta 16 tarjetas periféricas en el QL. A cada una de estas se le asignan 16K octetos de memoria en la parte superior del mapa de memoria. La dirección base particular de cada tarjeta viene determinada por su posición. Por lo tanto, todas las direcciones de periféricos vienen especificadas en relación con la dirección base de la tarjeta. Cuando se enciende el QL, se comprueba si existe la identificación $4AFB0001 al principio de la dirección de cada periférico. Si se encuentra el código, asume que hay una ROM presente, conteniendo el controlador del dispositivo, funciones y/o procedimientos.

Para indicar al QDOS que la ROM contiene un controlador de dispositivo, debe tener unos datos de reconocimiento al principio (ver Apéndice C). Los datos que aparecen desde la etiqueta 'BASE' en adelante se deben colocar en los primeros octetos. La primera palabra larga identifica que es una ROM y no 'espacio libre'. La palabra que sigue indica que no hay procedimientos o funciones en esta ROM. La siguiente palabra apunta a la rutina de iniciación de la ROM, que debe ser ejecutada una vez, a tiempo de encendido. Finalmente, la longitud del nombre del controlador del dispositivo, suponiendo que lo tenga.

La rutina de iniciación 'INIT' asigna espacio en el área común para los bloques de conexión, rellena las direcciones y los datos importantes y encadena el bloque en la lista de controladores de E/S. A0 y A3 se salvan a la entrada de INIT, y son restaurados a la salida, ya que se modifican en la rutina.

Como en los controladores de dispositivo estándar, se proporcionan las tres rutinas de OPEN, CLOSE y entrada/salida.

OPEN

Abrir un canal consta de dos operaciones principales. Lo primero que hay que hacer es decodificar el nombre del canal. En este caso se ha usado IO.NAME para simplificarlo. Después, una vez que se ha reconocido el nombre, se asignan $18 octetos en el área común. Será necesario asignar más para ciertas aplicaciones, pero aquí usamos el mínimo. El canal está ahora abierto.

CLOSE

Cerrar un canal es muy sencillo. La operación consiste en eliminar el espacio asignado en el área común. En este caso se ha usado MM.ALCHP para hacerlo.

Entrada/Salida

Esta rutina usa las direcciones almacenadas desde $28(A3) en adelante, que apuntan a las rutinas de comprobación de entrada pendiente, recoger un octeto y mandar un octeto, respectivamente. La rutina de manejo general de cadenas, IO.SERIO, se usa para manejar la ES. La mayoría de las operaciones de E/S son válidas, excepto IO.SSTRG (ésta trata las operaciones con ficheros, pero no es importante para la impresora).

En nuestro controlador, las rutinas de entrada pendiente y de recoger un octeto devuelven el error 'Parámetros inválidos'. Sólo es válida la rutina de mandar un octeto a la impresora (OUT_BYTE)

OUT_BYTE comprueba, primero, si la impresora está ocupada (BUSY); si lo está, devuelve un error ERR.NC. Si la impresora no está ocupada, se escribe un octeto de datos. Después lo manda a la impresora y pone el STROBE durante >500ns. Después de esta secuencia de operaciones, los datos han sido transferidos a la impresora.


Anterior Tabla de contenidos Siguiente
Utilidades por vector   SuperBASIC