Sinclair QL Programación Avanzada | ||
---|---|---|
Anterior | Siguiente |
Este capítulo trata de la asignación de los recursos disponibles en el QL. Si no ha leído y comprendido el capítulo de introducción al QDOS (capítulo 3), este es un buen momento para hacerlo.
Los recursos disponibles en el QL se dividen en dos áreas. La primera es la memoria, y la segunda está constituida por las otras piezas de 'hardware' que están disponibles para el QL, incluyendo la CPU 68008. Todos los programas que se ejecuten en el QL necesitan memoria en la que almacenar los datos asociados con la tarea que se ejecuta. Para esto hay una serie de rutinas que asignan memoria a los programas para el uso del programa y/o almacenamiento de datos. Estas rutinas se tratan en la sección 5.2. Hay otro grupo de rutinas para la gestión de los dispositivos 'hardware' que no sean la memoria. Estos dispositivos pueden ser los componentes internos estándar, como el reloj, IPC (controlador inteligente de la periferia), o dispositivos externos como disco duro o puertas paralelas para impresora. El 'hardware' interno se trata con una serie de 'controladores de dispositivos' que se encuentran dentro del QDOS. El 'hardware' externo puede ser conectado fácilmente al sistema por un grupo de vías bien definidas. Este aspecto del gestor del sistema se trata en la sección 5.3.
Generalmente, la mayoría de la gestión de los recursos del sistema se realiza mediante los TRAPs del gestor, a los que se accede mediante el TRAP #1. Se puede realizar, también, una cierta cantidad de manejo de recursos mediante las rutinas de utilidad por vector que se describen en el capítulo 8. Éstas las pueden usar los 'controladores de dispositivos' llamados con el TRAP #2 o el TRAP #3, pero NO se deben usar directamente desde el código del usuario.
La gestión de memoria se ocupa generalmente de la protección y asignación de la memoria. En el QL, sólo se encarga de la asignación. En la práctica, esto significa que se puede hacer fallar al sistema entero mediante la introducción de datos en el área de memoria usada como espacio de trabajo del QDOS (en un sistema de 'hardware' más sofisticado no se podría hacer). Ya que pueden existir bloques importantes de programa y datos en cualquier parte de la memoria del QL, es esencial que se use la memoria solamente de la forma requerida por el QDOS. Tenemos gran cantidad de potentes TRAPs para realizar la asignación de memoria. El tipo particular de asignación depende de las demandas exactas del programa y/o datos almacenados en memoria. Las siguientes secciones nos explican los diferentes tipos de asignación de memoria que se pueden usar.
Ya hablamos, en el capítulo 3, de los procedimientos residentes como una forma muy potente de programar. Se sitúan en la parte alta del mapa de memoria (ver figura 3.1). La razón de su potencia reside en que la memoria en la que se sitúan se asigna solamente en el momento de puesta en marcha del QL. Una vez que se ha asignado el área de procedimientos, no se puede borrar ni extender. La razón para esto es que inmediatamente debajo está el área de programas transitorios. Esta área no puede ser reasignada, y por lo tanto no puede moverse, como se requeriría para cambiar el tamaño del área de procedimientos residentes. Solamente en la circunstancia excepcional de que no hubiera procedimientos transitorios, se podría cambiar el área de procedimientos residentes.
Como se explicó en el capítulo 3, el área de memoria de programas transitorios se puede alterar dinámicamente. Se pueden añadir nuevos programas (en cuyo caso se expande el área) o borrar programas viejos (contrayéndose el área). Los programas que se pueden introducir en esta área se suelen llamar jobs.
Durante la vida de un job pueden suceder una gran cantidad de eventos. Algunos de éstos son esenciales e inherentes al hecho de la existencia del job (ej. creación del job), otros son opcionales (como cambiar el job de prioridad o borrarlo).
El área de memoria asignada a un job se puede considerar en dos partes. El código del job ocupa la primera parte de la memoria asignada a él. Los datos usados por el job ocupan el resto, desde la parte superior del código hasta la parte superior del área. Estas áreas se especifican cuando se crea el job inicialmente. A tiempo de creación del job se puede definir éste como una unidad independiente por sí mismo o como una subunidad de otro job. Los jobs que son propiedad de otros jobs serán borrados cuando lo sea su propietario.
Para permitir al usuario seguir el desarrollo de todos estos jobs, a cada una se le asigna un marcador único llamado Job ID. El primer job que se crea es el job 0, y siempre es el intérprete de BASIC. A los jobs posteriores se les asigna su propio número. La numeración de los jobs es totalmente automática, y el número particular de un job depende exclusivamente del número de jobs que haya en el QL cuando se crea. La palabra inferior del 'Job ID' contiene el número de job y se usa como un índice dentro de la tabla de jobs. La palabra superior del 'Job ID' es una etiqueta. Cada nuevo job se distingue con su propia etiqueta, que es uno mayor que la última asignada.
Una vez que se ha creado el job, puede estar en uno de tres estados claramente diferenciados. Puede estar activo, suspendido o inactivo.
Un job activo comparte los recursos de la CPU con otros jobs. Para determinar la cantidad de tiempo de CPU que se debe asignar a un job particular, a cada uno se le asigna una prioridad entre 1 y 127. La mayor es 127 y la menor (para un job activo) es 1. De esta forma, el planificador decide cuál de los jobs activos debe disponer de la CPU por un tiempo determinado.
Un job suspendido es uno que está activo todavía, pero está suspendido mientras espera por entrada, salida u otro job que no está aún preparado. Por lo tanto, el planificador no asigna tiempo de CPU a un job suspendido hasta que el proceso por el que está esperando se ha completado. Entonces se reactiva el job.
Un job inactivo es aquel cuya prioridad ha sido puesta a 0. A este tipo de job no se le asigna tiempo de CPU. Un job inactivo está presente en el área de programas transitorios, y puede ser reactivado en cualquier momento por otro job.
Finalmente, un job puede ser borrado del área de programas transitorios. Hay dos tipos básicos de borrado. El primer tipo sólo permite borrar un job si está inactivo. El otro permite forzar el borrado del job (aunque esté activo). Cuando se borra un job, se borran también todos aquellos de los que es propietario.
El intérprete de BASIC se inicia como Job 0. Como en los demás jobs, se requiere memoria para almacenar el programa (en este caso un programa BASIC) y los datos. A diferencia de otros jobs, a los que se les asigna una cantidad fija de memoria, al Job 0 se le permite asignar más espacio de memoria por sí mismo. NINGÚN otro job puede expandirse dinámicamente como éste. Existen dos TRAPs del gestor (D0=16 y 17) para expandir y contraer la memoria disponible para el BASIC.
Si un job requiere más memoria extra (sobre la que se le asignó cuando fue creado), se le puede asignar en el área común. El espacio en esta área pertenece a este job hasta que es liberada, o el job es borrado. El área común se usa también para almacenar bloques de definición de canal, datos, y almacenamiento de trabajo para el IOSS (subsistema de E/S).
La secuencia de la figura 5.1 ilustra una progresión típica del almacenamiento en el área común. Inicialmente, esta área se encuentra vacía (fig 5.1a). El Job 'A' decide entonces que le gustaría usar parte de esta área, así que le dice al QDOS que le asigne una parte usando MT.ALCHP (TRAP #1 con D0=$18). El área asignada aparece sombreada en la figura 5.1b. Ahora el Job 'B' pide otra parte de esta área. De nuevo, el QDOS aloca algo de memoria a este job, justo encima del área perteneciente al Job 'A' (ver fig 5.1c). Otro job (Job 'C') requiere ahora algo de memoria. Ésta es alocada justo encima de la del Job 'B' (ver fig 5.1d).
Algún tiempo después, el Job 'B' es borrado del sistema. El QDOS conoce exactamente a quién pertenece cada bit del área común, así que sabe que el área asignada al Job 'B' no se va a necesitar más. El área de este job es borrada para que pueda ser usada por otro job (ver fig 5.1e). Otro job (Job 'D') hace una petición de memoria en el área común. El QDOS encuentra la parte que le perteneció al Job 'B' disponible, de modo que se la asigna al Job 'D' (ver fig 5.1f). El Job 'E' hace una petición de un área más grande. El QDOS se da cuenta que el único espacio suficientemente grande está sobre la del Job 'C' por lo que se la asigna al Job 'E'. El Job 'A' ha llegado a un punto en el que necesita más memoria. Hace una nueva petición usando MT.ALCHP. El QDOS busca por el área común y encuentra que puede caber entre la parte alta de 'D' y la baja de 'C'. Consecuentemente el nuevo espacio se asigna ahí.
Figura 5.1 - Uso del área común
Este proceso continúa mientras la máquina permanece encendida. Se puede apreciar que el área común se fragmenta terriblemente si los jobs la asignan continuamente, devolviendo y reasignando espacio. Hay una considerable sobrecarga por cada espacio asignado, ya que el sistema operativo mantiene 16 octetos de información de cada sección (para poder disponer de las áreas de los jobs que son borrados). Un modo más eficiente de asignar área común es tomar la mayor cantidad de memoria que se va a necesitar. El job puede preparar su propia área común en este espacio, sin recargar al sistema operativo.
Hay un gran número de TRAPs y utilidades que ayudan a los programas del usuario a gestionar sus propias áreas.
Figura 5.2a - Área de usuario nueva (vacía)
Figura 5.2b - Área de usuario (parcialmente usada)
La figura 5.2 muestra cómo se maneja el área de usuario, con la ayuda de MT.ALLOC (TRAP #1, D0=$0C) y MT.LNKFR (TRAP #1, D0=$0D). El área de usuario se prepara inicialmente conectando un área de RAM a un área inexistente (con el apuntador al espacio libre = 0). Esto se ve en la figura 5.2a.
El job asigna espacio por sí mismo dentro del área de usuario; todos los espacios se encadenan juntos en un formato de lista encadenada. A medida que se va asignando y liberando, el área de usuario se va fragmentando. En un cierto momento, habrá muchos espacios libres dentro del área. Para encontrar el que se va a usar a continuación, las rutinas de utilidad recorren la lista para encontrar un espacio de tamaño adecuado, que es asignado. Esto se ve en la figura 5.2b. Tenga en cuenta que el área de usuario se puede extender dentro de otra área de memoria (área de trabajo del job del área común) simplemente enganchándola al final de la lista de espacio libre.
Así como gestiona el 'hardware' estándar del QL, el QDOS ha sido diseñado para permitir una fácil expansión del sistema.
Hay cuatro bloques de 'hardware' que tienen relación con TRAPs del gestor. Éstos son la pantalla, el IPC (incluye el teclado y el sonido), las puertas serie y el reloj. El control de pantalla selecciona alta resolución 512x512 modo de cuatro colores, o baja resolución 256x512 modo de ocho colores más modo parpadeo. El control del IPC es más complejo, ya que el 68008 tiene que comunicarse con el segundo procesador 8049 (el IPC). El IPC puede leer información del teclado y hacer sonar el altavoz. El IPC se encarga de todos los parámetros del sonido programable, de forma que el 68008 no tiene que perder tiempo controlándolo. Se puede cambiar la velocidad de transmisión de las puertas serie mediante un TRAP del gestor. Se puede leer el reloj, ponerlo en hora o ajustarlo, usando los TRAPs $13, $14 y $15 del gestor.
El QDOS se puede extender añadiéndole rutinas para servir interrupciones y controladores de dispositivos. Este tipo de rutinas adicionales se suele asociar (no necesariamente) con dispositivos 'hardware' que se han añadido al QL estándar. Todas las interrupciones se desarrollan mediante listas encadenadas. Una lista encadenada consiste en una serie de apuntadores. Entra la primera rutina de la lista, a su retorno pasa el control a la siguiente de la lista, y así sucesivamente hasta que todas las rutinas se han ejecutado. Claramente, cuanto más cerca esté una rutina del principio de la lista, mayor prioridad tiene, ya que puede decidir si pasa o no a la siguiente rutina. Ya que las llamadas a rutinas del sistema están realacionadas con las últimas, es posible reemplazar rutinas del sistema con las nuevas creadas para aplicaciones específicas, según se necesiten.
Las cinco listas encadenadas sirven para:
En esta sección se proporciona toda la información sobre los TRAPs del gestor. Se accede a ellos mediante el TRAP #1, la función concreta se selecciona mediante el contenido del registro D0. La siguiente tabla es una lista de todas las funciones en orden numérico. Para obtener una descripción más completa de cada una, así como una explicación del código de llamada, se debe referir a las secciones posteriores del capítulo.
D0 | Nombre | Descripción |
---|---|---|
00 | MT.INF | Da información del job actual y sistema |
01 | MT.CJOB | Crea job en área de programas transitorios |
02 | MT.JINF | Proporciona información de un job |
04 | MT.RJOB | Borra job de área de programas transitorios |
05 | MT.FRJOB | Fuerza borrado de job del área de programas transitorios |
06 | MT.FREE | Busca el área libre mayor en el espacio de programas transitorios |
07 | MT.TRAPV | Pone un vector de TRAP para un job |
08 | MT.SUSJB | Suspende un job |
09 | MT.RELJB | Libera un job |
0A | MT.ACTIV | Activa un job |
0B | MT.PRIOR | Cambia la prioridad de un job |
0C | MT.ALLOC | Asigna memoria en el área común |
0D | MT.LNKFR | Encadena un espacio libre en el área común |
0E | MT.ALRES | Asigna área de procedimientos residentes |
0F | MT.RERES | Libera área de procedimientos residentes |
10 | MT.DMODE | Pone y lee el modo de pantalla |
11 | MT.IPCOM | Manda un comando al IPC |
12 | MT.BAUD | Pone la velocidad de trasmisión |
13 | MT.RCLCK | Lee el reloj |
14 | MT.SCLCK | Pone el reloj |
15 | MT.ACLCK | Ajusta el reloj |
16 | MT.ALBAS | Asigna área de programa BASIC |
17 | MT.REBAS | Libera área de programa BASIC |
18 | MT.ALCHP | Asigna área común |
19 | MT.RECHP | Libera área común |
1A | MT.LXINT | Encadena rutina de interrupción externa al QDOS |
1B | MT.RXINT | Elimina una rutina de interrupción externa |
1C | MT.LPOLL | Encadena una rutina de 'polling' 50/60 Hz al QDOS |
1D | MT.RPOLL | Elimina rutina de 'polling' 50/60 Hz |
1E | MT.LSCHD | Encadena tarea de bucle del planificador al QDOS |
1F | MT.RSCHD | Elimina tarea de bucle del planificador |
20 | MT.LIOD | Encadena al QDOS un controlador de dispositivos de E/S |
21 | MT.RIOD | Elimina un controlador de dispositivo E/S |
22 | MT.LDD | Encadena un controlador de dispositivos con directorio al QDOS |
23 | MT.RDD | Elimina un controlador de dispositivos con directorio |
MT.INF | TRAP #1 | D0=0 | |||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Obtiene información del sistema | |||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||
Error devuelto: | |||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||
Descripción: | |||||||||||||||||||||||||||||||||||
Este TRAP nos proporciona información sobre el estado actual del sistema, el Job ID del job actual y su número de versión. También nos proporciona el apuntador a la base de las variables del sistema. |
Los jobs se crean en el área de programas transitorios de la memoria del QL. Es esencial que la memoria asignada al job sea suficiente para contener el código ejecutable, una pila y espacio de trabajo. Si se activa un job, la ejecución comenzará en la dirección base, a menos que se le especifique una dirección distinta de comienzo. La dirección de principio se da como dirección absoluta. No es necesario que el job tenga código ejecutable, se puede haber creado para contener un área de trabajo de otro job. Sin embargo, si el job no tiene código ejecutable, no debe ser activado. Si lo activáramos, haríamos fallar al sistema completo.
El área del job se divide en dos partes. El código comienza en la base del job, el resto del espacio sobre el código, hasta lo alto del área del job es espacio de datos. Cuando se activa un job por primera vez, (A6) apunta a la base de su área, (A6,A4) a la parte inferior del espacio de datos, y (A6,A5) a lo alto de su área. Al activar un job de formato estándar, se le puede pasar información en la pila. En lo alto de la pila se coloca una palabra que contiene el número de canales abiertos para el job. Ésta va seguida del número de identificación de canal (palabras largas), para entrada básica, salida y reporte de canales, respectivamente, y finalmente una cadena de comandos del job en formato estándar.
MT.CJOB | TRAP #1 | D0=1 | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Crea un job en el área de programas transitorios | ||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||
Este TRAP de creación de job tiene dos efectos. Asigna espacio para el job en el área de programas transitorios, y prepara una entrada de job en las tablas del planificador. Sin embargo, esto no hace que el job se inicie totalmente. La única iniciación que ocurre es que pone dos palabras a ceros en la pila. El Job 'padre' carga normalmente el nuevo job en el área de memoria asignada después de esta llamada al sistema. El apuntador de la pila (en el área de control del job) se pone inicialmente apuntando a las dos palabras a ceros de la pila. Éstas se colocan en la dirección más alta del área de datos del job. Si el job va a tener algún canal abierto, o se le va a pasar una cadena de comandos, se puede hacer antes de que sea activado. El Job ID propietario, pasado en D1, debe ser cero si el job va a ser independiente. Si el job actual va a ser el propietario del nuevo, D1 debe pasar un valor negativo. En el sistema operativo versión 1.03 y anteriores, A1 debe ser puesto siempre a cero a la entrada. |
MT.JINF | TRAP #1 | D0=2 | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Obtiene información de un job | ||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||
Este TRAP devuelve el estado actual del job. Se puede usar para comprobar el estado de una cadena completa de jobs. Si se va a usar de esta forma, D2 debe contener siempre el ID del job en lo alto de la cadena. Para poder analizar la cadena completa, se prepara el TRAP con D1 conteniendo el valor devuelto por el TRAP anterior. Cuando se ha alcanzado al último job de la cadena, D1 devuelve cero. |
MT.RJOB | TRAP #1 | D0=4 | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Borra un job del área de programas transitorios | ||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||
Este TRAP borra un job y todos sus subsidiarios del área de programas transitorios. Este TRAP borrará solamente jobs inactivos. Los jobs activos pueden ser borrados forzándolos mediante MT.FRJOB D0=5. Tenga en cuenta que este TRAP no está garantizado como atómico y no puede borrar el Job 0. |
MT.FRJOB | TRAP #1 | D0=5 | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Fuerza borrado de un job del área de programas transitorios | ||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||
Este TRAP inactiva una cadena completa de jobs y borra todos los jobs de la cadena. Si D1 es una palabra negativa, se borra el job actual. Si hay un job esperando que se complete el job que se va a borrar, ese job se libera con D0 conteniendo un código de error (ver MT.ACTIV D0=A). Tenga en cuenta que este TRAP no está garantizado como atómico y por lo tanto no puede borrar el Job 0. |
MT.FREE | TRAP #1 | D0=6 | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Busca el mayor espacio libre en el área de transitoria | ||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||
Este TRAP busca el mayor espacio libre contiguo que puede ser asignado en el área de programas transitorios. La longitud del espacio es devuelta en el registro D1. |
MT.TRAPV | TRAP #1 | D0=7 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Pone un vector de TRAP para un job | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
A un job le es posible redireccionar TRAPs y vectores de excepción que no usa el QDOS. Esta redirección se define en una tabla (ver abajo). Si el job prepara una tabla de vectores de TRAP para él mismo, se usará automáticamente siempre que se ejecute el job. Un job usará inicialmente la tabla del que lo ha creado, aunque no le pertenezca. Este estado de de cosas persiste hasta que otro job prepare su propia tabla. Las tablas de vectores usadas por otros jobs no son afectadas. Si el Job ID es una palabra negativa, la tabla la preparará el job llamado. La tabla consiste en una dirección de una palabra larga de longitud por cada TRAP o excepción, en el siguiente orden:
|
Los jobs están siempre en uno de tres estados definidos. Pueden estar activos (compartiendo los recursos de la CPU con otros jobs), suspendidos (esperando por E/S o por otros jobs) o inactivos (ocupando memoria pero sin poder hacer uso de los recursos de la CPU). La única diferencia práctica entre un job inactivo y uno que ha sido suspendido indefinidamente es que el último no puede borrarse con MT.RJOB D0=4.
La información sobre un job, su estado actual, prioridad, propietario, tamaño, etc. está contenida en el área de control del job. Esta área está en la región de memoria de programas transitorios y precede al área asignada para el job. En QDOS v1.03, la base del área de control está $68 octetos antes que el job. Esto es susceptible de cambio en versiones futuras. Para el QDOS v1.03, la organización de memoria es:
dir. | long. | nombre | descripción | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
$00 | 4 | LEN* | Longitud total control job + área job. | ||||||||||||||||
$04 | 4 | START | Dirección de principio en activación. | ||||||||||||||||
$08 | 4 | OWNER? | Job ID del propietario. | ||||||||||||||||
$0C | 4 | HOLD? | Apuntador a un octeto que se limpiará cuando el planificador libere al job (ver MT.SUSJB D0=8). | ||||||||||||||||
$10 | 2 | TAG* | Etiqueta del job asignada por MT.CJOB. | ||||||||||||||||
$12 | 1 | PRIOR? | Prioridad acumulada actual. Se incrementa cuando el job está activo pero no ejecutándose. El planificador permite ejecutarse al job con mayor prioridad acumulada. | ||||||||||||||||
$13 | 1 | PRINC? | Ésta es la prioridad inicial del job. El BASIC activa jobs con prioridad $20. | ||||||||||||||||
$14 | 2 | STAT* | Estado del job:
| ||||||||||||||||
$16 | 1 | RELA6? | Bit superior puesto si el siguiente TRAP #2 ó #3 tiene direccionamiento relativo (como lo puso el TRAP #4). | ||||||||||||||||
$17 | 1 | WFLAG? | Puesto si hay otro job esperando por éste. | ||||||||||||||||
$18 | 4 | WJOB? | ID del job que espera por éste. | ||||||||||||||||
$1C | 4 | TRAPV? | Apuntador a los vectores de TRAP. | ||||||||||||||||
$20 | 32 | Valores de D0 a D7 salvados. | |||||||||||||||||
$40 | 32 | Valores de A0 a A7 salvados. | |||||||||||||||||
$60 | 2 | Valor del registro de estado salvado. | |||||||||||||||||
$62 | 4 | Valor del contador de programa salvado. |
* | significa valor que no debe ser cambiado | |
? | significa valor que puede ser cambiado por un TRAP, o directamente (¡pero con cuidado!) |
long | longitud en octetos: | |
1 | un octeto | |
2 | una palabra | |
4 | una palabra larga | |
32 | 8 palabras largas |
MT.SUSJB | TRAP #1 | D0=8 | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Suspende un job | ||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||
Este TRAP suspende un job. El periodo de suspensión puede ser indefinido, o por un periodo de tiempo especificado. El periodo de espera se define como el número de cuadros, por lo que la suspensión puede ser hasta un periodo de 32K cuadros (unos 10 minutos). Si se le especifica el periodo de espera como -1, la suspensión será indefinida. No se puede usar otro valor negativo. Si el Job ID es una palabra negativa, se suspende el job actual. El octeto de indicadores se limpiará cuando se libere el job. Si no hay octeto de indicadores, A1 debe ponerse a cero. Si el job ya estaba suspendido, se quita la suspensión. Todos los jobs son replanificados. Tenga en cuenta que este TRAP no es totalmente atómico, ya que invoca al planificador. |
MT.RELJB | TRAP #1 | D0=9 | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Libera un job | ||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||
Este TRAP hace que se libere un job que se encuentra suspendido. Todos los jobs pueden ser replanificados después de esta llamada. Tenga en cuenta que este TRAP no es totalmente atómico, ya que invoca al planificador. |
MT.ACTIV | TRAP #1 | D0=A | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Activa un job | ||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||
Este TRAP hace que un job determinado en el área de programas transitorios sea activado. La ejecución comenzará desde la dirección de comienzo que fue definida cuando se creó. La actividad de un job se puede controlar también ajustando su nivel de prioridad (MT.PRIOR D0=B). Si la prioridad se pone a cero, el job se pone inactivo. Si el periodo de espera se pone a cero, la ejecución del job actual continúa, si se pone otro valor, el job será suspendido hasta que el job activo termine. Este TRAP volverá entonces con un código de error de ese job. Este TRAP no es totalmente atómico ya que invoca al planificador. |
MT.PRIOR | TRAP #1 | D0=B | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Cambia la prioridad de un job | ||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||
Este TRAP cambia la prioridad de un job. Si D1 es una palabra negativa, cambiará la prioridad del job actual. Si se pone prioridad 0, el job será inactivado. Este job reentra el planificador, de modo que si el job pone su prioridad a 0, se inactivará instantáneamente. Esta llamada no es totalmente atómica, ya que invoca al planificador. |
Bajo ciertas circunstancias, la gestión del área de usuario puede ser atómica. Hay dos TRAPs que lo hacen.
El área de usuario es asignada en múltiplos de 8 octetos. El espacio libre se encadena usando dos palabras largas por espacio. La primera palabra larga contiene la longitud del espacio y la segunda el apuntador relativo al siguiente espacio libre. Esta área de usuario es totalmente reubicable, ya que los apuntadores son relativos. Se puede usar toda el área asignada por el código de usuario, asumiendo que en el programa esté previsto mantener control de la longitud de los items dentro del área. Cuando se asigna el área, la primera palabra larga contiene la longitud del área, de modo que pueda ser retenida por el código del usuario si lo desea.
El código del usuario debe mantener un apuntador al espacio libre. En la sección 5.2.5 se explica claramente este punto. El apuntador al espacio libre debe ser relativo (una palabra larga). Si el área no tiene espacio libre, porque se ha llenado o no existe, este apuntador será cero.
Estas áreas se preparan encadenando un área de RAM dentro de un área no existente (con el apuntador al espacio libre = 0). Se pueden expandir encadenándose a otra área de RAM. Para que su uso sea óptimo deberían ser contiguas.
MT.ALLOC | TRAP #1 | D0=C | |||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Asigna espacio en el área común | |||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||
Error devuelto: | |||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||
Descripción: | |||||||||||||||||||||||||||||||||||||||||||||||
Este TRAP asigna memoria en el área común para usarla con el código de usuario. El TRAP es totalmente atómico. A6 se usa como dirección base para este TRAP, de forma que A0 debe ser relativo a A6. |
MT.LNKFR | TRAP #1 | D0=D | |||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Encadena espacio libre (devuelto) en el área común | |||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||
Error devuelto: | |||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||
Descripción: | |||||||||||||||||||||||||||||||||||||||||||||||
Este TRAP encadena un espacio libre de memoria (devuelto) en el área común. A6 se usa como dirección base para esta llamada, así que A0 y A1 deben ser relativas a A6. |
MT.ALRES | TRAP #1 | D0=E | ||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Asigna área de procedimientos residentes | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||||||||||
El área de procedimientos residentes está situada en lo alto de la memoria, y se asigna normalmente a tiempo de encendido. La razón para ello es que todos los procedimientos transitorios se sitúan debajo de los procedimientos residentes en la memoria. Si se expande el espacio de procedimientos residentes cuando hay procedimientos transitorios, éstos deberían ser reubicables, como normalmente no lo son, esto resulta imposible. Sin embargo, en el caso excepcional de que no haya procedimientos transitorios en la máquina, sería posible extenderla o reducirla. Los TRAPs que se encargan de ello son MT.ALRES D0=E y MT.RERES D0=F. La asignación se hace por un número de octetos. La función RESPR(n) del BASIC puede usarse para asignar octetos a la memoria de procedimientos residentes. |
MT.RERES | TRAP #1 | D0=F | ||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Libera área de procedimientos residentes | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||||||||||
Este TRAP libera memoria de procedimientos residentes para su uso por el sistema. Solamente se puede usar cuando el área de programas transitorios está completamente vacía. Ver también MT.ALRES D0=E para la asignación de memoria de procedimientos residentes. |
MT.DMODE | TRAP #1 | D0=10 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Pone y lee el modo de pantalla | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Error devuelto: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Descripción: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Este TRAP pone o lee el modo actual de pantalla. Se suele seleccionar a tiempo de iniciación del sistema, para decirle al QL si está usando un televisor o un monitor. Este TRAP afecta a todas las ventanas, por lo que no se debe usar a menos que la máquina esté completamente vacía, ya que los programas pueden requerir una pantalla diferente a la que le estamos forzando a usar. Si se usa para leer el modo de pantalla, no hay ningún peligro. |
El IPC (controlador inteligente de periféricos) es un microprocesador de un solo chip 8049. Este segundo procesador se encarga de los datos de entrada del teclado y de los de salida al canal de sonido. El 68008 se comunica con el 8049 mediante medios octetos (nibble).
Los comandos se mandan al IPC mediante los 'nibbles' de comando. Éstos van seguidos por los parámetros del comando, que son una cadena de 'nibbles' y/u octetos. Toda la información devuelta por el IPC (como la lectura de una fila de teclas) viene en formato de octeto.
El comando que se manda al IPC (usando MT.IPCOM) debe almacenarse en memoria en el siguiente formato. Consiste en una cabecera que describe el comando, seguida por el número de parámetros requeridos por el comando, terminando en un octeto que indica si se espera respuesta.
1 oct | el comando va en los cuatro bits inferiores |
1 oct | contiene el número de octetos de parámetros |
2 oct | número de bits a mandar de cada octeto de parámetro: bits 1,0 = cantidad a mandar del primer octeto bits 3,2 = cantidad a mandar del segundo octeto etc. |
n oct | octetos de los parámetros |
1 oct | longitud de la respuesta codificada en bits 1,0 |
Se pueden transferir 0, 4 u 8 bits de cada octeto de parámetro. El número de bits que se van a transferir está codificado en una palabra larga. El cádigo de dos bits es como sigue:
00 | mandar los 4 bits inferiores |
01 | no mandar nada |
10 | mandar los 8 bits del octeto |
11 | no mandar nada |
La comunicación con el IPC está completamente desprotegida, por lo que los comandos no deben contener errores. Si hay errores, el QL entero fallará. La comunicación con el IPC es un proceso muy lento, por lo tanto es esencial no hacer excesivo uso de él. Por ejemplo, es más eficiente leer solamente las teclas del cursor (están todas en una misma fila del teclado) que leer el teclado entero. Si se lee todo el teclado regularmente, resultará excesivamente caro en tiempo de proceso.
La mayoría de los comandos del IPC están diseñados para ser usados por el sistema operativo, y no se debe intentar usarlos desde los programas de usuario. Este tipo de intento puede resultar en pérdida de datos o fallos del sistema. Sin embargo, hay tres comandos que han sido diseñados para usarse en programas de aplicación. Éstos son:
comando 9 | lee el teclado (requiere un parámetro) 4 bits para el número de fila 8 bits para la respuesta (ver fig. 5.3 con el esquema del teclado) |
comando A | inicia la generación de sonido (8 parámetros) 8 bits para tono 1 (1 mayor que en BASIC) 8 bits para tono 2 (1 mayor que en BASIC) 16 bits intervalo entre pasos 16 bits duración sonido 4 bits paso en tonos 4 bits repetición 4 bits paso aleatorio 4 bits ruido no necesita respuesta (ver "QL User Guide" para la descripción de los parámetros de sonido) |
comando B | cortar sonido - sin parámetros - sin respuesta |
Figura 5.3 - Esquema del teclado de la versión inglesa (para la versión española, ver el Apéndice X)
MT.IPCOM | TRAP #1 | D0=11 | ||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Manda comandos al IPC | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||||||||||
Este TRAP manda un comando al IPC. El formato del comando debe ajustarse a lo descrito en las páginas anteriores, ya que no se realiza comprobación de los parámetros. Cualquier fallo en la definición de los comandos puede ser desastroso, desembocando en un fallo de todo el sistema. |
MT.BAUD | TRAP #1 | D0=12 | ||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Pone la velocidad de transmisión | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||||||||||
Las dos puertas serie del QL operan a la misma velocidad, tanto en transmisión como en recepción. MT.BAUD se usa para seleccionar la velocidad requerida. Las siguientes velocidades son válidas:
Tenga en cuenta que la paridad y el número de bits de parada se ponen independientemente de la velocidad. Para más detalles, vea el capítulo 6 (IO.OPEN e IO.CLOSE). |
MT.RCLCK | TRAP #1 | D0=13 | ||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Lee el reloj | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||||||||||
Con este TRAP se puede leer el reloj de tiempo real. El tiempo viene en una palabra larga conteniendo el número de segundos desde 00:00 1 Enero 1961. Esto significa que el QL puede dar la fecha hasta el ¡año 2029! Para convertir el tiempo en segundos a una cadena con la fecha, la hora y/o el día de la semana, se pueden usar las utilidades por vector CN.DATE y CN.DAY. |
MT.SCLCK | TRAP #1 | D0=14 | ||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Pone en hora el reloj | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||||||||||
Este TRAP permite poner la hora y día del reloj de tiempo real. |
MT.ACLCK | TRAP #1 | D0=15 | ||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Ajusta el reloj | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||||||||||
Con este TRAP se puede ajustar el reloj. Tenga en cuenta que el poner el reloj en hora lleva su tiempo, por lo tanto si llama a MT.ACLCK con D1=0, el QDOS no intentará ajustar el tiempo. |
MT.ALBAS | TRAP #1 | D0=16 | ||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Asigna área para el programa BASIC | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
MT.ALBAS asigna más memoria para que la use el intérprete de comandos BASIC. Esta memoria puede usarse para líneas de programa adicionales o para almacenamiento de datos. El intérprete de comandos es un job muy especial, ya que es el único que se le permite expandir su memoria de esta forma. El intérprete de comandos se ejecuta en modo usuario como Job 0. |
MT.REBAS | TRAP #1 | D0=17 | ||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Libera área del programa BASIC | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
MT.REBAS libera área de programa de usuario para que la usen otros jobs. El espacio sólo se libera cuando se ejecuta un comando NEW o CLEAR. |
MT.ALCHP | TRAP #1 | D0=18 | ||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Asigna área común | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||||||||||
MT.ALCHP permite a un job asignar por sí mismo espacio en el área común. El espacio asignado no debe ser propiedad del job creado. Cuando se borra el job que posee el espacio, todo el espacio que le ha sido asignado es limpiado y puesto a disposición del sistema para que lo pueda asignar a otra aplicación. |
MT.RECHP | TRAP #1 | D0=19 | ||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Libera área común | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||||||||||
MT.RECHP libera espacio del área común que se asignó con el TRAP MT.ALCHP. |
Es posible extender el QDOS añadiéndole rutinas para servicio de interrupciones o controlar dispositivos. Esto se realiza uniendo las nuevas rutinas en una lista encadenada que mantiene el QDOS. El diagrama y la explicación que le sigue nos muestra cómo funciona.
Figura 5.4a - Lista encadenada original
Un ítem en una lista encadenada consiste en un apuntador de unión que contiene la dirección del siguiente elemento en la lista. Con cada apuntador de unión hay asociada una (o varias) direcciones, que apuntan a las rutinas de servicio. La lista se examina por medio del apuntador de unión, que tiene asociada la dirección de la primera rutina de servicio que se ha de llamar (rutina 1 en el diagrama). Cuando devuelve control esta rutina, el QDOS usa el viejo apuntador de unión para encontrar el nuevo, desechándolo después. El nuevo apuntador tiene otra rutina asociada (rutina 2), que es llamada. A su retorno, se repite el proceso completo hasta que se llega al final de la lista.
Figura 5.4b - Desconexión de un item de la lista
En la figura 5.4b se muestra cómo se borra un ítem de la lista. El apuntador de unión del que se va a borrar (el que estaba asociado a la rutina 2) se pone en el apuntador del anterior. Al hacer esto, forzamos a que la lista vaya de la rutina 1 a la 3, perdiendo la rutina 2 como si no hubiera existido nunca. A este proceso se le llama desconectar un ítem de la lista.
Figura 5.4c - Conectando un ítem a la lista
Cuando se va a conectar un nuevo ítem en la lista, el apuntador de unión del ítem anterior debe ponerse apuntando al nuevo. En nuestro ejemplo, el apuntador viejo del ítem 1 se ha puesto apuntando al nuevo (ítem 4), y en el nuevo se pone el apuntador que había antes en el anterior. Esto nos asegura que la lista permanece completa y se puede extender a cualquier tamaño (dentro de los límites de memoria de la máquina).
Hay cinco listas encadenadas en el QL:
Para cada una de éstas, hay un TRAP que conecta una rutina a su lista, y otro que borra una rutina.
Para la lista encadenada de interrupciones, se deben asignar 8 octetos de RAM. Los primeros 4 octetos forman el apuntador de unión (puesto por MT.LXINT, MT.LPOLL y MT.LSCHD). Los otros 4 octetos forman una palabra larga que contiene la dirección de la rutina conectada.
Para los controladores de dispositivos, se han de asignar 16 octetos de RAM. La primera palabra larga es el apuntador de unión, las segunda, tercera y cuarta palabras largas apuntan respectivamente a las rutinas de entrada/salida, abrir y cerrar. Para los controladores de directorio se requieren 40 octetos de RAM como mínimo.
Antes de añadir un elemento a una lista encadenada, es esencial que la RAM en la que se va a conectar esté asignada al job. La memoria asignada debe estar en el área de procedimientos residentes, si hace falta (código controlador de dispositivos en RAM), o alternativamente en el área común (código controlador de dispositivos en ROM). Si se usa el área común, el espacio debe ser propiedad del Job 0. Si es propiedad de otro job y éste es forzado a borrarse antes de que se hayan desconectado las rutinas correspondientes de la lista, se puede garantizar que fallará el sistema operativo.
MT.LXINT | TRAP #1 | D0=1A | ||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Conecta una rutina de servicio de interrupciones al QDOS | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||||||||||
Ver sección 5.4.5 para la descripción de lista encadenada. |
MT.RXINT | TRAP #1 | D0=1B | ||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Borra una rutina de servicio de interrupciones del QDOS | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||||||||||
Ver sección 5.4.5 para la descripción de lista encadenada. |
MT.LPOLL | TRAP #1 | D0=1C | ||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Conecta al QDOS una rutina de servicio de 'polling' 50/60 Hz | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||||||||||
Ver sección 5.4.5 para la descripción de lista encadenada. |
MT.RPOLL | TRAP #1 | D0=1D | ||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Borra del QDOS una rutina de servicio de 'polling' 50/60 Hz | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||||||||||
Ver sección 5.4.5 para la descripción de lista encadenada. |
MT.LSCHD | TRAP #1 | D0=1E | ||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Conecta al QDOS una tarea de bucle del planificador | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||||||||||
Ver sección 5.4.5 para la descripción de lista encadenada. |
MT.RSCHD | TRAP #1 | D0=1F | ||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Borra del QDOS una tarea de bucle del planificador | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||||||||||
Ver sección 5.4.5 para la descripción de lista encadenada. |
MT.LIOD | TRAP #1 | D0=20 | ||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Conecta al QDOS un controlador de dispositivos E/S | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||||||||||
Ver sección 5.4.5 para la descripción de lista encadenada. |
MT.RIOD | TRAP #1 | D0=21 | ||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Borra del QDOS un controlador de dispositivos E/S | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||||||||||
Ver sección 5.4.5 para la descripción de lista encadenada. |
MT.LDD | TRAP #1 | D0=22 | ||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Conecta al QDOS un controlador de dispositivos de directorio | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||||||||||
Ver sección 5.4.5 para la descripción de lista encadenada. |
MT.RDD | TRAP #1 | D0=23 | ||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Borra del QDOS un controlador de dispositivos de directorio | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Error devuelto: | ||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||
Descripción: | ||||||||||||||||||||||||||||||||||||||||||
Ver sección 5.4.5 para la descripción de lista encadenada. |
Anterior | Tabla de contenidos | Siguiente |
Experimentando con QDOS | Asignación de Entrada/Salida |