Módulos de SMSQ

Le Grand Pressigny, FRANCIA - Tony Tebby
(Artículo original: revista “International QL Report” V5i5, Enero de 1996)
Traducción: Juan José Ruiz Leo - Febrero de 2008

Principios

SMSQ/E se distribuye como un solo fichero que provee un sistema operativo, un procesador de comandos de línea / intérprete de programas (SBASIC), varios módulos de idioma y un conjunto completo de controladores de dispositivos para el sistema objetivo. SMSQ/E no es, sin embargo, una unidad monolítica, sino una colección de módulos que proveen diferentes funciones. Es posible, por ejemplo, quitar el intérprete de SBASIC y substituirlo por una concha UNIX, o quitar módulos de idioma no queridos o substituirlos por otros idiomas.

En las versiones actuales, SMSQ no está muy finamente dividido: para evitar la duplicación de rutinas de utilidad, los controladores de dispositivos están enlazados juntos en grandes módulos y el sistema operativo en si mismo está dispuesto como un solo módulo. La versión de QXL tiene 14 módulos, la de Gold Card tiene 20 módulos y la de Atari 17 módulos.

No todos los módulos están cargados. Para la versión de Atari, por ejemplo, hay dos módulos de sistema operativo diferentes para permitir dos esquemas de manejo de memoria diferentes. Sólo se carga uno de estos, el otro es desechado durante la carga.

Estructura de módulo

La estructura de módulo estándar comprende una cabecera estandarizada, código de preproceso del módulo y el código del módulo en sí.

Cabecera de Módulo

La cabecera de módulo estándar comienza con un bloque de tamaño fijo obligatorio con información de cabecera: 24 octetos.

Palabra larga

mbase

El desplazamiento desde el comienzo de la cabecera a la base del módulo = la longitud de la cabecera

Palabra larga

mlength

La longitud del módulo en sí (sin incluir la cabecera)

Palabra larga

rlength

La longitud máxima después de recolocación (puede que el módulo encoja)

Palabra larga

cksum

La suma de comprobación del módulo

Palabra larga

select

El desplazamiento desde el comienzo de la cabecera al “código de seleccionar” que será llamado antes de que se cargue el módulo

Octeto

level

El nivel de módulo (para carga automática)

Octeto

spare


Palabra

name

Apuntador relativo al nombre del módulo

Todas las longitudes y apuntadores relativos deben ser pares.

El “nivel” está reservado para uso futuro. Debería ser siempre 1. El nombre debería definirse siempre. Es una cadena QDOS (longitud en una palabra seguida por los caracteres, que deberían estar ajustados a un número par). Como el nombre normalmente seguirá a la cabecera directamente, el apuntador relativo normalmente será 2. Como convenio el nombre debería estar seguido por una identificación de versión de 4 caracteres (a menudo ésta es simplemente cuatro espacios). La suma de comprobación se calcula normalmente de la siguiente forma.

Inicializar la palabra larga de suma a cero.
Por cada palabra en el módulo
Sumar la palabra a la palabra larga de suma
Rotar la palabra larga de suma a la derecha por (palabra MOD 7)

moveq #0,d0
moveq #0,d1
loop
move.w (a1)+,d0 siguiente palabra larga
add.l d0,d1 acumulada
and.w #7,d0 MOD 7
ror.l d0,d1 rotar
subq.l #2,d3 decrementar el octeto de cuenta por 2
bgt.s loop

Una suma de comprobación de cero es siempre aceptable y es más fácil de calcular.

Como un módulo tiene una suma de comprobación, no es posible incorporar datos configurables. Para esquivar este problema, cualquier bloque de configuración debería ponerse en la cabecera y una rutina de “seleccionar” incorporada para copiar la información al módulo. (Esto también asegura que el módulo no está abarrotado de texto de configuración.)

Aunque la rutina de seleccionar se puede usar para efectuar mucho más que una simple selección, el propósito principal de la rutina de selección es determinar si un módulo en particular debería ser cargado.

El primer módulo “activo” de cada versión del sistema operativo es el cargador. Éste es el módulo que explora el resto de los módulos cargando el código en los lugares “correctos”, etc. Por cada módulo, llama a la rutina de “seleccionar” (si el desplazamiento no es cero) en modo supervisor. La rutina de seleccionar debe devolver un código en D0:

D0 0 no cargar este módulo
D0 1 cargar este módulo

Así, por ejemplo, el controlador de visualización monocroma del Atari comprueba si hay una pantalla monocroma conectada y, si la hay, devuelve 1 (cargar) para asegurar que se carga el controlador de pantalla monocroma. En cambio, los controladores de pantalla del emulador QL del Atari devuelven 0 (no cargar) si hay una pantalla monocroma adjunta y por lo tanto, a no ser que tenga una versión de SMSQ/E que incluya un controlador monocromo, no obtendrá ningún controlador de consola en absoluto.

Las rutinas de seleccionar pueden, naturalmente, hacer más que eso. Los módulos de manejo de caché, por ejemplo, no tienen un módulo real: el código de manejo de caché para los diversos procesadores MC680x0 está construido en la cabecera y el código requerido para el procesador en particular es copiado en el área de vectores de SMSQ. Las rutinas de seleccionar del manejo de caché, por tanto, siempre devuelven 0 (no cargar).

El cargador pasa la dirección de un “bloque de comunicación de rutina de seleccionar” a cada rutina de seleccionar. Este bloque es inicializado con una cierta cantidad de datos útiles por el cargador, pero las rutinas de seleccionar pueden usarlo para pasar información de una a otra. Este bloque de comunicación está apuntado por A5.

Palabra larga

family

ID de familia de máquina (ATST, QXL, GOLD)

Palabra larga

mtype

Tipo de máquina (depende de la familia pero el MSB siempre es el tipo de procesador: $00=68000, $40=68040)

Palabra

lang

Identificador de idioma (ó 0)

Palabra

spare


Palabra larga

facility

32 bits, cada uno de los cuales puede ser activado para indicar que una utilidad particular ya ha sido cargada (para prevenir, por ejemplo, que se carguen dos controladores CON contradictorios). SMSQ actualmente sólo usa los bits 30 y 31. Otros suministradores de software deberían usar del bit 0 hacia arriba.

Las rutinas de seleccionar pueden usar hasta $30 octetos tras este bloque definido. Note, sin embargo, que estos $30 octetos no son inicializados. Las rutinas de seleccionar no pueden usar ningún servicio del sistema operativo (son llamadas antes de que el sistema operativo sea inicializado).

Código del Módulo

Cuando todos los módulos han sido cargados, SMSQ llama al propio código de cada módulo, en modo usuario, para inicializar los módulos (enlazar controladores, añadir procedimientos SBASIC y Things). El código del módulo debería terminar con RTS. Tiene la misma forma que un fichero que se pretenda cargar con LRESPR. Note, sin embargo, que cuando los módulos con inicializados, el canal 0 no está abierto.

Módulo Anfitrión

Habría sido muy conveniente tener una estructura de módulo que fuera la misma para todos los módulos, pero, como SMSQ/E tiene que empezar como un programa que se ejecuta bajo un sistema operativo diferente, el fichero entero del sistema operativo SMSQ/E tiene que parecer un programa válido en ese sistema. Por esta razón , hay un módulo especial: el MÓDULO ANFITRIÓN.

El módulo anfitrión no incluye ningún código que sea cargado. Es el programa que será ejecutado por el sistema operativo ANFITRIÓN. Para la Gold Card simplemente entra en modo supervisor y espera 2,5 segundos antes de saltar al módulo cargador de la Gold Card.

Está claro que es imposible tener una cabecera en un módulo anfitrión. El módulo anfitrión, por tanto, ¡tiene un remolque! A fin de ser capaz de encontrar el remolque, siempre se pone al final del fichero – todos los otros módulos se insertan entre el módulo anfitrión y el remolque. Este remolque es de $18 octetos y tiene la misma forma que una cabecera de módulo estándar. Hay, sin embargo, algunas ligeras diferencias en el contenido.

Palabra larga

mbase

0

Palabra larga

mlength

La longitud del módulo en sí (sin incluir el remolque)

Palabra larga

rlength

0

Palabra larga

cksum

La suma de comprobación del módulo

Palabra larga

flength

El desplazamiento desde el comienzo del módulo a la “tabla de arreglo de longitud de fichero”

Palabra larga

oslen

Longitud del fichero de sistema operativo ó 0

La tabla de arreglo de longitud de fichero es requerida para decirle al sistema operativo anfitrión cuánto mide el fichero poniendo la longitud (más o menos un bit) en el programa anfitrión (¡¡SÍ, ALGUNOS SISTEMAS OPERATIVOS NO SABEN CUÁNTO MIDE UN PROGRAMA!!). Si este apuntador no es cero apunta a una tabla de asientos de dos palabras largas de la forma:

Apuntador relativo a la palabra larga a ser sobreescrita
Ajuste a añadir a la longitud antes de sobreescribir

La tabla está terminada por una palabra larga con valor cero.

La vida es incluso peor para la QXL. El fichero entero está precedido por un programa MS-DOS. A fin de encontrar el “verdadero” comienzo del fichero del sistema operativo, la longitud del fichero del sistema operativo está almacenada en la última palabra larga. Es más, si se cambia la longitud del fichero SMSQE.EXE no sólo es necesario actualizar esta longitud, sino que se requiere un parche complejo para el programa MS-DOS (el cálculo parece ilógico, pero me han asegurado que es correcto). Esto se puede hacer después de que todas las operaciones se hayan completado.

OPEN #5,"SMSQE.EXE"
lenf = FLEN(#5)
lens% = INT((lenf + 511) / 512)
lenb% = lenf – lens% * 512
IF lenb% = lenb% = lenb% + 512
BPUT #5\2,lenb% MOD 256,lenb% DIV 256,lens% MOD 256,lens% DIV 256
CLOSE #5

Exploración de un Fichero de Sistema Operativo SMSQ

Un fichero SMSQ puede ser explorado bastante fácilmente con un simple programa SBASIC:

100 REMark – scan bootloader file
110 DIM version$(4): version$(0)=4
120 OPEN #0,CON: CLS: BORDER 1,4
130 height = 17
140 INPUT 'SMSQ file>';f$
150 OPEN_IN #3,f$
160 fln = FLEN(#3)
170 LGET #3\fln–$18+$4,mod_ptr : REMark – get length of host module
180 LGET #3\fln–$18+$14,bln : REMark – length of bootloader file
190 IF bln: mod_ptr = mod_ptr + fln – bln
200 FOR i=1 TO 9999
210 LGET #3\(mod_ptr),mbase,mlength
220 IF NOT mbase: EXIT : REMark – end of file
230 IF NOT i MOD height: INPUT a$; : REMark – pause at screen full
240 WGET #3\(mod_ptr+$16),name_rel : REMark – relative pointer to name
250 GET #3\(mod_ptr+$16+name_rel),name$ : REMark – fetch module name
260 IF LEN(name$) && 1: BGET #3,a : REMark – odd length name is padded
270 BGET #3,version$(1 TO 4) : REMark – get version, if any
280 PRINT HEX$(mlength,24) !! version$ ! name$
290 mod_ptr = mod_ptr + mbase + mlength
300 END FOR i
310 CLOSE #3
320 INPUT a$

Esto imprimirá la longitud (en hexadecimal), la versión y el nombre de todo excepto el módulo anfitrión.

Añadir un Módulo

Si tiene un módulo (por ejemplo una tabla de teclado como las descritas en la edición de Mayo/Junio) que quiera incorporar, normalmente lo más fácil es añadirla al final. Para hacer esto necesitará quitar el remolque y añadir el nuevo módulo y añadir el remolque de nuevo. Puede que entonces necesite actualizar la longitud en el módulo anfitrión, o como se ha descrito arriba para la QXL o “apropiadamente”.

100 REMark – add module to bootloader file
110 OPEN #0,CON: CLS: BORDER 1,4
120 height = 17
130 INPUT 'SMSQ file>';f$
140 OPEN #3,f$
150 fln = FLEN(#3)
160 INPUT 'New module file>';m$
170 OPEN_IN #4,m$
180 mln = FLEN(#4)
190 DIM mod$(mln)
200 BGET #4,mod$(1 TO mln):mod$(0) = mln
210 INPUT 'Module name>';mn$
220 mnlen = LEN(mn$)
230 mnlen2 = mnlen + (mnlen && 1) : REMark – round up module name len
240 mhead = $18 + 2 + mnlen2 + 4 : REMark – total module header length
250 :
260 LGET #3\fln–$18+$4,mod_ptr : REMark – get length of host module
270 LGET #3\fln–$18+$10,fix_up,bln : REMark – length of bootloader file
280 IF bln: bln = bln + mhead + mln
290 LPUT #3\fln–$18,mhead,mln,mln,0,0,$01000002 : REMark – $18 byte header
300 PUT #3,mn$: IF mnlen && 1: BPUT #3,0 : REMark – name and pad
310 BPUT 'VERS' : REMark – 4 character version
320 BPUT #3,mod$ : REMark – add module
330 LPUT #3,0,mod_ptr,fix_up,0,0,bln : REMark – replace trailer
340 fln = fln + mhead + mln
350 :
360 IF fix_up
370 REPeat
380 LGET #3\(fix_up),addr,offset : REMark – next fixup address/offset
390 IF addr=0: EXIT
400 LPUT #4\(addr+fix_up),fln+offset
410 fix_up = fix_up + 8
420 END REPeat
430 END IF
Ver también: Módulos de SMSQ dependientes del idioma


Sinclair QL Recursos en Castellano Alojado en / Hosted at:
Sinclair QL Recursos en Castellano
Sinclair QL Spanish Resources