QL-VGA es un conversor RGB a VGA basado en una FPGA y desarrollado por Marcel Kilgus específicamente para Sinclair QL. La señal de entrada se almacena en un búfer de memoria en un chip RAM y se emite como una señal de video estándar VESA 1024×768 a 60Hz. La señal de 512×256 pixels del QL se duplica en la dirección X y se triplica en la dirección Y, lo que da una pantalla exacta de 1024×768. Este formato es tan común que básicamente todos los monitores lo aceptan y además se puede convertir a HDMI usando cualquier convertidor.

He conectado mi QL a un pequeño monitor VGA de 15 pulgadas y el resultado es excelente. El conversor no requiere ajuste alguno y la conexión ha sido «plug & play». Me ha sorprendido gratamente la calidad de la imagen, la visualización es muy nítida y clara. Además, el típico problema del QL con el «overscan» lateral ya es algo superado con esta placa.

Os dejo algunas imágenes (sobre los detalles de las imagen que muestran la pantalla del QL, la realidad supera en calidad a lo mostrado en esas foto).

Preámbulo

El inicio en el aprendizaje de un nuevo lenguaje de programación suele ser algo desconcertante en las etapas iniciales. En muchas ocasiones, y por supuesto dependiendo de tus conocimientos previos, tu mente se debe adaptar a pensar de un modo diferente, debes aprender un montón de palabras reservadas nuevas, debes tener conocimientos del entorno de programación, del compilador, del sistema operativo sobre el que te desenvuelves, etc. Es frecuente también que no encuentres la documentación adecuada adaptada a tu nivel, o que los ejemplos disponibles requieran de unos conocimientos previos elevados. Estas cosas hacen que frecuentemente tiremos la toalla incluso antes de comenzar.

Todo esto es espacialmente cierto si el lenguaje del que estamos hablando es a bajo nivel tal como el lenguaje ensamblador del Motorola 68000, y además en una plataforma extremadamente rara en nuestros días como es el Sinclair QL y su sistema operativo QDOS.

La mejor manera de superar estas dificultades iniciales es a base del estudio y prácticas con ejemplos muy simples de pequeños programas «funcionales», es decir que se puedan compilar y ejecutar ¡sin errores! desconcertantes (sobre todo para no perder la auto-confianza). Debemos empezar con lo simple y poco a poco escalar en dificultad. Después de todo, como se dice frecuentemente, la mejor manera de aprender a programa es … ¡copiar! … (bueno, mejor dicho, tomar prestado) el código que ha han escrito otros.

El presente artículo recoge esos «primeros pasos» que he dado a la hora de enfrentarme a este lenguaje y tiene la única pretensión de facilitar un poco la tarea a aquellos aficionados al Sinclair QL que tengan interés en adentrarse en el apasionante mundo de la programación a bajo nivel. Después de todo, esto es otra forma de «dar vida» y «desempolvar» nuestras viejas máquinas, sobre todo para aquellas personas entusiastas de la retro-informática que, como yo, no sean muy dados a los videojuegos. (¿Acaso no es más divertido programar estas viejas máquinas que jugar con ellas?).

El presente artículo no pretende ser un tutorial ni un manual del lenguaje ensamblador o del QDOS , para ello ya existe documentación que nos explica con todo lujo de detalles tanto el lenguaje ensamblador del Motorola 68000 como del sistema operativo del Sinclair QL (ver la sección de manuales y artículos en http://www.sinclairql.es).

La mayor parte del contenido de este artículo y los ejemplos es material rescatado de distintas fuentes, entre ellas:

– Foro http://sinclairql.es
– Revista Qlave
– Manual del Assembler Development Kit de Metacomco
– 68000, 68010 /68020 Arquitectura y programación en ensamblador. Stan Kelly-Bootle y Bob. Fowler. (Anaya Multimedia)
– Sinclair QL Programación Avanzada, Adrian Dickens.

A todo este material se puede acceder a través de la web http://www.sinclairql.es.

Se acompaña a este artículo, un fichero zip con el código fuente de los ejemplos analizados, listos para ser ensamblados con el “Assembler Developtment Kit” de la casa Metacomco. Los ejemplos han sido probados en un QL real con ampliación de disquetera y en el emulador Q-Emulator (¡ahora es “free” la emulación básica!). Además de todo esto podrías necesitar un editor de textos para elaborar tus propios programas en ensamblador o modificar los que aquí se proponen, QED es un buen editor, compacto y rápido).

Los recursos mencionados los puedes encontrar en:

Bueno, basta de preámbulos, empecemos a dar esos primeros pasos.

El primer paso, «hola mundo»

“Hola mundo” se ha convertido en un término muy familiar par cualquier persona aficionada o profesional en la programación de ordenadores. Miren si no la definición que nos propone la Wikipedia de ésta expresión:

“En informática, un programa Hola mundo (o Hello World, en inglés) es el que imprime el texto «¡Hola, mundo!» en un dispositivo de visualización (generalmente una pantalla de monitor). Se suele usar como introducción al estudio de un lenguaje de programación, siendo un primer ejercicio típico.

El Hola Mundo se caracteriza por su sencillez, especialmente cuando se utiliza en programas de línea de comandos. En interfaces gráficas este programa suele tener una complejidad mayor.

Un programa Hola Mundo puede ser útil como prueba de configuración para asegurar que el compilador, que el entorno de desarrollo, y que el entorno de ejecución están instalados correctamente y funcionando. Configurar un conjunto de herramientas básicas completo desde cero hasta el punto donde hasta los programas triviales puedan ser compilados y ejecutados, puede involucrar una cantidad de trabajo sustancial. Por esta razón, generalmente es usado un programa muy simple para probar un conjunto de herramientas nuevo.” ( www.wikipedia.org ).

Cualquier comentario adicional a esta descripción sobra (¡ni Cervantes lo redactaría tan bien!). Resulta también muy curioso la gran cantidad de lenguajes en los que se ofrece el código “Hola mundo” en Wikipedia, pero si lo miráis veréis que al menos ¡falta uno!, el “hola mundo” en ensamblador 68000. Pues pongamos remedio a eso, a continuación va ese primero programa extraído del foro de www.sinclaiql.es (gracias Zerover).

Listado 1, Hola_asm.

*
* Códigos de llamadas al QDOS
*
MT_FRJOB EQU $05
IO_SSTRG EQU $07
*
* Programa principal
*
         LEA.L     SALUDO,A3       apuntamos a la frase a escribir con A3
         MOVE.W    (A3),D2         numero de octetos a mandar
         MOVEQ.L   #-1,D3          periodo de espera infinito
         MOVEA.L   #$00010001,A0   identificador del canal #1
         LEA.L     2(A3),A1        apuntar a la cadena de octetos
         MOVEQ.L   #IO_SSTRG,D0    enviar la cadena de octetos
         TRAP #3                   Traps de E/S

         MOVEQ.L   #-1,D1          tarea actual
         MOVEQ.L   #0,D3           ningún error
         MOVEQ.L   #MT_FRJOB,D0    forzar el final de la tarea
*                                  (Force Release JOB)
         TRAP #1                   Traps de gestión de procesos

*
* En caso de ser llamado desde el SuperBASIC (CALL)
         MOVEQ     #0,D0           poner retorno de error a 0 para SuperBasic
         RTS                       vuelve a SuperBASIC
*
* Sección de datos
*
SALUDO   DC.W 11                 las cadenas precedidas de DW longitud
         DC.B 'Hola mundo.'

         END

Algunos comentarios al programa:

El código comienza definiendo una serie de constantes con EQU, muy cómodas para no estar recordando valores concretos, cosa que no forma parte del lenguaje máquina del 68000 propiamente dicho sino que son directivas del ensamblador. Por ejemplo IO_SSTRG EQU $07 al principio del programa provoca que el ensamblador sustituya $07 cada vez que encuentre IO_SSTRG. El $ indica que el numero es expresado en hexadeciamal (y no significa dinero).

A continuación viene la secuencia principal del programa donde vemos muy pocas instrucciones realmente diferentes (MOVE, LEA, MOVEQ) que llevan aparejada un punto y una letra. A esta letra se le llama código de tamaño del dato, porque indica cuantos bits de origen (fuente) y del destino están involucradas en la operación. Las reglas son muy simples:

L significa doble palabra: opera sobre 32 bits.
W significa palabra: opera sobre 16 bits.
B significa byte: opera sobre 8 bits inferiores.

Estas son las descripciones breves de algunas instrucciones empleadas en nuestro primer programa.

LEA (Load Effective Address), coloca una dirección de memoria especificada en un registro de direcciones (An)

MOVE mueve el contenido de la fuente al destino.

MOVEQ (MOVE Quick) mueve un dato de 8 bits con signo de forma rápida al destino. El dato especificado que va a ser movido es extendido a 32 bits antes de ser movido al destino.

MOVEA (MOVE Address) mueve el contenido desde el origen a un registro de direcciones.

TRAP el procesador inicia una excepción. Se ejecuta una llamada al sistema.

Vemos también que en algunas instrucciones se emplean los registros de direcciones entre paréntesis, (A3) por ejemplo. Esto significa que estamos tratando con el contenido de la dirección a la que apunta el registro, en nuestro caso podemos leerlo como el contenido de la posición de memoria a la que apunta A3. 2(A3) significa que tenemos que sumar dos bytes más a la posición apuntada por A3 y tomar el valor de esa posición de memoria.

Finalmente el código finaliza con la sección de datos. En una zona de memoria etiquetada como SALUDO se deposita una palabra (16 bits) con el número 11 y a continuación una secuencia de 11 caracteres que ocupan un byte cada uno de ellos.

Bien, todo esto simplemente para ver en pantalla lo siguiente.

gráficos1

Paso 2, el ensamblado con “Assembler Development Kit” de Metacomco

En el paso anterior vimos el código fuente de nuestro primer programa y el resultado final tras ejecutar el código objeto del programa en un emulador del Sinclair QL, pero ¿cómo pasamos del código fuente al código ejecutable?, … pues en nuestro caso ensamblando el programa fuente con el “Assembler Development Kit” de la casa Metacomco (la misma que fabricó el sistema operativo del Amiga).

Para ejecutar el compilador es preciso teclear «exec flp1_asm» (yo he renombrado asm_metacomco por asm del paquete citado). Al iniciarse el programa se nos hace las siguientes preguntas:

En primer lugar debemos indicar cuál es el nombre del fichero que anteriormente salvamos y que contiene el programa. Después debemos indicar si deseamos listado del programa ensamblado, si pulsamos ENTER se asume que no; si hemos respondido ‘Y’ entonces de nos pregunta el nombre del fichero al que dirige el listado, se pulsa ENTER se dirige a la pantalla, podemos redirigir también a ser1, flp2_ … En este listado aparece las líneas que contiene algún error con una E por delante y con signos = las partes que se refieran a macros.

Posteriormente se nos pregunta por el nombre del fichero que contendrá el código objeto. Si tecleamos ENTER no se genera código y el compilado sólo nos servirá para comprobar si hemos cometido errores en la redacción del programa.

Se nos pregunta también por el espacio de trabajo del programa, si se pulsa ENTER se toma el espacio reservado por defecto. De igual forma se nos interroga sobre la alteración del tamaño de la ventana de forma que un ENTER o ‘N’ implican dejarla igual. La alteración de tamaño es con ALT+cursores y su situación se controla por los cursores sin ALT.

En las primeras versiones los programas venían instalados para trabajar en el mdv1_ y los ficheros a compilar en el mdv2_, esto era alterable por el fichero install de forma que aquellos que dispongan de una ampliación de memoria puedan cargar los programas en disco ram y dirigir los ficheros compilados ahí, luego bastará hacer un copy a un mdv_ o disco del compilado definitivo. En nuestros ejemplos usaremos una versión adaptada para ser ejecutada en flp1_

Dependiendo del fichero que hayamos deseado compilar se nos generará un código independiente de la dirección de carga o no, así si no hemos incluido ORG por lo general será independiente y ejecutable vía EXEC que suele ser lo deseable, en caso contrario el programa se ejecuta con CALL tras cargarlo con LBYTES. En nuestros ejemplos cargaremos siempre los programas directamente desde el QDOS con EXEC.

Al final se nos pregunta si deseamos compilar más programas, debemos responder ‘Y’ o ‘N’.

A continuación vemos algunas pantallas con el ensamblador en acción, su uso es extremadamente fácil.

gráficos2

gráficos3

Paso 3, mostrar la versión del QDOS

Veamos nuestro segundo ejemplo. Éste pequeño programa está extraído de uno de los primeros números de la revista Qlave. Veremos cómo interrogar a un TRAP del sistema para obtener la versión del QDOS que se está ejecutando en nuestro sistema. Ya en un artículo previo en www.sinclairql.es veíamos que el comando PRINT VER$ del SuperBasic lo que nos da en realidad es la versión del SuperBASIC en sí mismo y no la versión del QDOS (que son dos cosas diferentes). Podría ser necesario conocer esto ya que existen versiones antiguas que no aceptan algunas «llamadas» ya implantadas en las nuevas versiones, de esta forma se puede garantizar el correcto funcionamiento de un programa independientemente de la versión del QDOS instalada. Para saber la versión del QDOS debemos emplear una rutina en lenguaje ensamblador como la detallada en el del listado 2.

Algunos comentarios del autor del ejemplo (Isidro Asin, revista Qlave número 1, volumen 1).

“El programa tiene cuatro bloques básicos, estos cuatro bloques son etiquetas de llamadas al QDOS, macros definidas, el código ejecutable en sí, zona de memoria de datos.

El primer bloque se refiere al valor que se debe pasar en el registro de datos D0 al realizar el TRAP (orden en ensamblador que se refiere a una excepción y que es la forma habitual de trabajo del QDOS) correspondiente. He usado dos Macros, algo bastante recomendable si se dispone de un ensamblador que lo permita. La primera nos sirve para pasar las llamadas al QDOS (el parámetro en D0 y el número de TRAP que corresponda). La segunda se encarga de finalizar el programa y devolvernos al BASIC.

El programa comienza con una llamada para obtener la información de la versión, esto se hace con el TRAP 1 y MT_INF en D0, el resultado se saca en D2 que guardamos en la zona de memoria reservada para ello, la zona etiquetada como MENSAJE donde con 4 bytes habrá bastado en lugar de 10.

Ahora para sacar estos datos podemos hacerlo por pantalla o por impresora, nosotros lo haremos por pantalla de ahí que DISPOSITIVO sea ‘SCR_’. Abrimos un canal para efectuar la salida, para ello usamos un TRAP 2 con IO_OPEN en D0, en D1 el número de job que se trate (en este caso -1 para indicar el actual), en D3 un 2 para indicar que es nuevo, y A0 apunto al DISPOSITIVO, que aunque aquí sea SCR_ podríamos colocar SER1 para impresora por ejemplo.

Para sacar los datos se usa un TRAP 3 con IO_STRING en D0, hay que especificar el número de octetos a mandar en D2 y el tiempo de espera en D3, A1 debe de apuntar a la zona de memoria que contiene los octetos a mandar.

Para finalizar se invoca la Macro FINAL que cierra el canal abierto con un TRAP 2 conteniendo IO_CLOSE en D0. Posteriormente forzamos la clausura del job y como éste es activo lo hacemos con un TRAP 1 conteniendo D0 MT_FRJOB, en D1 está el número de job y en D3 el código de error.”

Listado 2, Infor_asm.

*
* Códigos de llamadas al QDOS
*
MT_INF      EQU     0           Obtener la versión del QDOS
IO_OPEN     EQU     1           Abrir canales
IO_CLOSE    EQU     2           Cerrar canales
IO_SSTRG    EQU     7           Presenta datos por un canal de salida
MT_FRJOB    EQU     5           Cancela el job
*
* Macros
*
QDOS        MACRO               Macro de asignación de Traps
            MOVEQ   #\1,D0      Parámetro en D0
            TRAP    #\2         Parámetro del Trap
            ENDM
FINAL       MACRO               Macro de cancelación de canales y job
            QDOS    IO_CLOSE,2  Cierra canal
            MOVEQ   #-1,D1      del job actual
            MOVEQ   #0,D3       Código de error
            QDOS    MT_FRJOB,1  Llamada QDOS
            ENDM
*
* Programa pincipal
*
            QDOS    MT_INF,1    Obtengo información
            LEA.L   MENSAJE,A3  Apunto A3 a la zona donde guardo infor.
            MOVE.L  D2,(A3)     Llevo A3 el num. de versión
            MOVEQ   #-1,D1      Job actual
            MOVEQ   #2,D3       Nuevo fichero
            LEA.L   DISPOSITIVO,A0  Tipo de dispositivo asociado
            QDOS    IO_OPEN,2   Llamada al QDOS
            MOVEQ   #10,D2      Mando octetos de más
            MOVEQ   #-1,D3      Tiempo de espera infinito
            LEA.L   MENSAJE,A1  apunto a la base de la memoria
            QDOS    IO_SSTRG,3  Llamada al QDOS
*
            FINAL
* 
* Sección de datos
*
DISPOSITIVO     DC.W 4
                DC.B 'SCR_'     Dispositivo de salida en la pantalla
MENSAJE         DS.B 10         Base de la memoria

                END

Más comentarios:

Vemos que prácticamente se emplean el mismo juego de instrucciones que en el ejemplo anterior, la novedad más importante tal como nos comenta su autor, es el uso de macros. Las macros no forman parte del juego de instrucciones del 68000 sino que son construcciones del ensamblador que nos ahorran el empleo de código repetitivo (sustituyéndose por la macro). Estas macros aceptan una especie de parámetros para flexibilizar y generalizar su uso. Fijémonos también en la sección de datos, una zona donde se reserva memoria DS.B, no para almacenar constantes (DC.z) sino datos generados por nuestro programa, en este caso una cadena de bytes indicativos de la versión del QDOS.

A continuación vemos el resultado de ejecutar el programa en nuestro emulador. Vemos que estamos usando una ROM con la versión 1.10 del sistema operativo.

gráficos4

Paso 4, entrada / salida por consola

Sigamos avanzando en nuestro recorrido y demos el siguiente “pasito”… Ahora le toca el turno a un pequeño programa que hace algo más, pide por consola la entrada de una cadena y luego imprime dicha cadena en la misma consola. El programa lo he tomado del manual de Metacomco y lo podemos ver en el “Listado 3”.

Listado 3, rwstr_asm.

*
* Códigos de llamadas al QDOS
*
MT_FRJOB        EQU         $05
IO_OPEN         EQU         $01
IO_CLOSE        EQU         $02
IO_FLINE        EQU         $02
IO_SSTRG        EQU         $07
*
* Macros
*
QDOS            MACRO
                MOVEQ       #\1,D0
                TRAP        #\2
                ENDM
*
TIDYUP          MACRO
                QDOS        IO_CLOSE,2      Cerrar el canal
                MOVEQ       #-1,D1
                MOVEQ       #0,D3           Cancelar este job
                QDOS        MT_FRJOB,1
*
* En caso de CALL desde SuperBASIC
                MOVEQ       #0,D0           Código de retorno - todo OK
                RTS
                ENDM
*
* Programa principal
*
                MOVEQ       #-1,D1          Job actual
                MOVEQ       #2,D3           Dispositivo exclusivo
                LEA.L       DEVNAME,A0      Puntero a nombre de dispositivo
                QDOS        IO_OPEN,2       Abrir stream
*
* Imprimir etiqueta
*
                MOVEQ       #18,D2          Longitud del string
                MOVEQ       #-1,D3          Timeout infinito
                LEA.L       PROMPT,A1       Puntero a string
                QDOS        IO_SSTRG,3      Imprimir la etiqueta

*
* Leer entrada
*
                LEA.L       BUFFER,A3       Puntero al buffer de entrada
                LEA.L       2(A3),A1        Saltar la primera palabra
                MOVEQ       #30,D2          Longitud del buffer
                QDOS        IO_FLINE,3      Leer input, d1 obt. / estab.
*                                           nbytes leidos
                MOVE.W      D1,(A3)         Grabar los n bytes de la lectura
*
* Print message
*
                MOVEQ       #6,D2           Longitud del texto
                MOVEQ       #-1,D3          Timeout infinito
                LEA.L       MESS,A1         Puntero al mensaje
                QDOS        IO_SSTRG,3      Imprimir mensaje
                MOVEQ       #0,D2           Borrar D2
                MOVE.W      (A3),D2         Longitud del nombre
                LEA.L       2(A3),A1        Puntero al nombre
                QDOS        IO_SSTRG,3      Imprimir nombre
*
* Hacer limpieza
*
                TIDYUP
*
* Sección de datos
*
BUFFER          DS.W            1
                DS.B            30
DEVNAME         DC.W            4
                DC.B            'CON_'
MESS            DC.B            'Hello '
PROMPT          DC.B            'Enter your name : '
*
                END

Comentarios:

Como veis, prácticamente sigue el mismo esquema que el ejemplo anterior, hace el uso de macros para llamadas estándar al QDOS y una macro para la limpieza y finalización del programa. El juego de instrucciones del 68000 empleadas en este ejemplo son las mismas que en los ejemplos anteriores.

Para la salida de la cadena por pantalla usa:

  • TRAP 3 con IO_SSTRG ($07) en D0, la longitud de la cadena en D2 y el puntero del string a imprimir en A1.

Para la entrada por teclado de nuestro “input” usa:

  • TRAP 3 con IO_FLINE ($02) en D0, la longitud del buffer en D” y el puntero al buffer de entrada en A3. Este TRAP nos deposita en la dirección de memoria apuntada por A3 el número de bytes leídos y a continuación los bytes de la cadena que hemos tecleado.

La siguiente figura nos muestra la ejecución de este ejemplo.

gráficos5

Paso 5, un volcado de la memoria

Ya hemos visto en los anteriores ejemplos como mostrar cadenas de texto, cómo llamar al QDOS y cómo realizar la entrada salida por consola. En el siguiente programa, también extraído del manual de Metacomo veremos cómo realizar otra función típica en todo programa, esto es la iteración de un bucle un número determinado de veces.

El programa consiste en mostrar por pantalla el contenido de una zona de la memoria de nuestro sistema. Comencemos mostrando el listado del programa (listado 4)

Listado 4, impmem_asm.

*
* Códigos de llamadas al QDOS
*
MT_FRJOB        EQU         $05
IO_OPEN         EQU         $01
IO_CLOSE        EQU         $02
IO_SBYTE        EQU         $05
IO_SSTRG        EQU         $07
NADDR           EQU         100
*
* Macros
*
QDOS            MACRO
                MOVEQ       #\1,D0
                TRAP        #\2
                ENDM
*
TIDYUP          MACRO
                QDOS        IO_CLOSE,2      Cerrar canal
                MOVEQ       #-1,D1
                MOVEQ       #0,D3           Cancelar este job
                QDOS        MT_FRJOB,1
*
* En caso de  CALL desde SuperBASIC
                MOVEQ       #0,D0           C–digo de retorno - todo OK
                RTS
                ENDM
*
* Programa principal
*
* Abrir stream
                MOVEQ       #-1,D1          Job actual
                MOVEQ       #2,D3           Dispositivo exclusivo
                LEA.L       DEVNAME,A0      Puntero a nombre de dispositivo
                QDOS        IO_OPEN,2       Abrir stream
*
                LEA.L       $28000,A4       Dirección de comienzo
                MOVEQ       #(NADDR-1),D4   (no. de direcciones a ser
*                                            examinadas -1)
*
* Bucle principal
*
LOOP
*
* Imprimir dirección con 8 dígitos en hexadecimal
                MOVEQ       #10,D2          Longitud del string
                MOVEQ       #-1,D3          Tiempo de espera infinito
                LEA.L       MESS1,A1        Puntero al stream
                QDOS        IO_SSTRG,3      Imprimir string
*
                MOVE.L      A4,D1           Dirección en D1
                BSR         WRITE32BITS     Imprimir dirección
*
* Imprimir contenido de esa dirección de memoria
                MOVEQ       #14,D2          Longitud del texto
                MOVEQ       #-1,D3          Timeout infinito
                LEA.L       MESS2,A1        Puntero al string
                QDOS        IO_SSTRG,3      Imprimir string
*
                MOVE.L      (A4)+,D1        Puntero a D1 e inc. puntero
*
                BSR         WRITE32BITS     Imprimir contenido
*
* Salida L/F
                MOVEQ       #$0A,D1         L/F en D1
                BSR         WRITECHAR       Escribir el carŒcter
*
* ´Se han examinado todas las direcciones? si no, ir a LOOP
                DBRA        D4,LOOP
*
* Hacer limpieza
*
                TIDYUP
*
*
WRITE32BITS
                SWAP        D1
                BSR.S       WRITE16BITS     Escribir los 16 bit sup. y bajar
                SWAP        D1              a los 16 bits inferiores
*
WRITE16BITS     ROR.W       #8,D1
                BSR.S       WRITE8BITS      Escribir 8 bits (de 16) y bajar
                ROL.W       #8,D1           hasta escribir los 8 bits más
*                                           bajos
*
WRITE8BITS      ROR.B       #4,D1
                BSR.S       WRITE4BITS      Escribir 4 bit sup (de 8) y bajar
                ROL.B       #4,D1           hasta escribir 4 bits inferiores
*
*
WRITE4BITS      MOVE.L      D1,-(SP)        Grabar D1 en la pila
                ANDI.B      #$0F,D1         Máscara para ret. 4 bits inf.
                ADDI.B      #'0',D1         Añadir carácter cero
                CMPI.B      #'9',D1         Si > qué carácter 9
                BLS.S       WRITE4BITS1     No, entonces escribir carácter
                ADDI.B      #'A'-'9'-1,D1   Si, convertir a rango A-F
WRITE4BITS1
                BSR.S       WRITECHAR
                MOVE.L      (SP)+,D1        Restablecer D1
                RTS
*
*
WRITECHAR
                MOVEM.L     D0/D3/A1,-(SP) Grabar registros en la pila
                MOVE.L      #-1,D3          Timeout infinito
                MOVEQ       #IO_SBYTE,D0    Code a enviar 1 byte
                TRAP        #3              Byte a ser enviado en D1
                MOVEM.L     (SP)+,D0/D3/A1 Restablecer registros
                RTS
*
*
* Sección de datos
*
DEVNAME         DC.W            4
                DC.B            'CON_'
MESS1           DC.B            'Address : '
MESS2           DC.B            '   Contents : '
*
                END

Comentarios:

Este nuevo programa emplea básicamente todo lo que hemos estudiado hasta estos momentos pero introduce dos construcciones importantísimas para el desarrollo de programas en ensamblador.

La primera de las construcciones es el equivalente a los bucles FOR (aunque se pueden hacer todo tipo de bucles con esta construcciones WHILE, …). Estos bucles tienen el siguiente esqueleto:

            MOVEQ       #N,D4       “Contador” de iteraciones
ETIQUETA

            . . . Sección1
            . . .
 
            DBRA        D4,ETIQUETA

La instrucción fundamental en este recorte de código es la sentencia DBRA que en la mayoría de los ensambladores equivale también a DBF. Esta instrucción y otras pertenecen a la familia de instrucciones tipo DBcc donde cc hace referencia al código de condición del registro de estado del 68000. Estos códigos de condición pueden ser por ejemplo CC (acarreo a cero), EQ (igual a), LE (menor que), RA- (falso), …

En nuestro recorte de código anterior, la sentencia DBRA D4,ETIQUETA provoca que la ejecución del programa salte a ETIQUETA hasta que D4 sea igual a -1, si no es así entonces D4 se decrementa (D4 -1). En nuestro ejemplo el trozo de código “Sección1” (localizado entre ETIQUETA y DBRA) se ejecutará N veces.

La segunda construcción de interés en nuestro ejemplo es la construcción equivalente a llamar a una subrutina (algo así como el DEFine PROCedure de SuperBASIC). Esta construcción tiene el siguiente esqueleto.

            BSR         ETIQUETA
            . . . sección_1 
            . . .

ETIQUETA
            . . . sección_2
            . . .
            RTS

En nuestro recorte de código, el programa cuando llega a la instrucción BSR (Branch to SubRoutine) deriva el hilo de la ejecución a la zona de código marcada como ETIQUETA y ejecutará la seccion_2. Una vez que la ejecución llegue a RTS (ReTurn from Subroutine) el hilo de ejecución retornará a la línea siguiente a la instrucción que hizo la llamada y continuará en sección_1. Es responsabilidad del programador conservar el estado de los registros en la llamada y recuperarlos cuando se retorna (para ello nos ayudaremos de la pila del usuario).

Existen variantes de la instrucción RTS que restauran de forma automática el registro de estado, también el 68000 nos ofrece facilidades para almacenar en una sola instrucción los registros deseados en la pila, así como facilidades para recuperar dichos datos de la pila posteriormente.

La siguiente imagen muestra el programa en acción.

gráficos6

Paso 6, control del teclado

Le llega el turno al último programa de ejemplo en este recorrido por el lenguaje ensamblador para el 68000. Es un ejemplo extraído del manual del Assembler Development Kit de Metacomco (como no). El programa nos muestra una caja en la pantalla en cuyo interior se muestra una cadena de texto que va haciendo scroll horizontal cuando dicho cuadro no está en movimiento. Con las teclas cursor arriba, cursor abajo, cursos derecha y cursor izquierda podemos desplazar la caja sobre la pantalla. Empleando las teclas ALT-cursor arriba, ALT-cursor abajo, ALT-cursos derecha y ALT-cursor izquierda podemos alterar el tamaño de la caja en altura y anchura. También se lleva un control sobre los límites del área de dibujo para que los desplazamientos no se salgan del área preestablecida para el movimiento de la caja.

Veamos el listado de este programa.

Listado 5, cajascr_asm.

*
* Sección de constantes
*
*
                TTL             Demostración - constantes
*
* Llamadas QDOS
*
* Códigos Trap #1
*
MT_FRJOB        EQU     5
*
* Códigos Trap #2
*
IO_OPEN         EQU     1
IO_CLOSE        EQU     2
*
* Códigos Trap #3
*
IO_FBYTE        EQU     1
IO_SBYTE        EQU     5
SD_BORDR        EQU     $C
SD_WDEF         EQU     $D
SD_CURE         EQU     $E
SD_PIXP         EQU     $17
SD_PAN          EQU     $1B
SD_CLEAR        EQU     $20
SD_SETIN        EQU     $29
SD_SETSZ        EQU     $2D
*
* Colores
*
C_GREEN         EQU     4
C_WHITE         EQU     7
C_CHAR1         EQU     C_GREEN
C_CHAR2         EQU     C_WHITE
*
* Códigos de teclas
*
K_ENTER         EQU     $0A
K_SPACE         EQU     $20
K_UP                EQU     $D0
K_DOWN          EQU     $D8
K_LEFT          EQU     $C0
K_RIGHT         EQU     $C8
K_ALT_UP        EQU     $D1
K_ALT_DOWN      EQU     $D9
K_ALT_LEFT      EQU     $C1
K_ALT_RIGHT     EQU     $C9
*
* Algunas constantes útiles
*
CHWIDTH         EQU     16
CHHEIGHT        EQU     20
MINH            EQU     CHHEIGHT+2
MINW            EQU     CHWIDTH*6+4
MAXX            EQU     512-CHWIDTH-4
MAXY            EQU     256-CHHEIGHT-2
BWIDTH          EQU     1           Ancho del borde de la ventana
WIDTH           EQU     MINW
HEIGHT          EQU     MINH
X               EQU     304
Y               EQU     200
*
* Nombres para registro
*
WW          EQUR        D4          Ancho y alto de la ventana
WH          EQUR        D5          actual
WX          EQUR        D6          Posición X,Y de la esquina
WY          EQUR        D7          superior izquierda
            PAGE
            TTL     Demostración - Macros
            SPC     2
*
* Macros
*
            SPC     2
*
* Una llamada genƒrica para el posicionamiento del cursor, scrolling
* panning, etc. El timeout es infinito y se asume que A1 contiene
* el canal a la pantalla
*
SCROPS      MACRO
            MOVEQ       #\1,D1
            MOVEQ       #\2,D2
            MOVEQ       #\3,D0      Opcode en D0
            MOVEQ       #-1,D3      Timeout
            LEA.L       WINDOW,A1   Dirección del bloque de ventana
            TRAP        #3          Hacerlo
            ENDM
            SPC         2
*
* Una llamada generalizada para peticiones al QDOS
*
QDOS        MACRO
            MOVEQ       #\1,D0      Código del trap
            TRAP        #\2
            ENDM
*
TIDYUP      MACRO
            QDOS        IO_CLOSE,2  Cerrar el canal de la consola
            MOVEQ       #-1,D1
            MOVEQ       #0,D3       Cancelar este job
            QDOS        MT_FRJOB,1  Terminar este job
*
* En caso de uso de CALL
            MOVEQ       #0,D0
            RTS
            ENDM
*
            PAGE
            TTL         Demotración - Programa principal
*
* Programa principal
*
INIT
*
* Abrir el stream de consola
*
            MOVEQ       #-1,D1      Job actual
            MOVEQ       #2,D3       Dispositivo exclusivo
            LEA.L       DEVNAME,A0  Puntero al nombre del dispositivo
            QDOS        IO_OPEN,2   Abrir canal, ID en A0
*
* Establecer la ventana por defecto

            SCROPS      3,1,SD_SETSZ    Caracteres grandes
            SCROPS      0,0,SD_CURE     Activar cursor
*
* Inicializar la sección de ventana
*
            MOVE.W      (A1)+,WW        Ancho
            MOVE.W      (A1)+,WH        Alto
            MOVE.W      (A1)+,WX        X
            MOVE.W      (A1)+,WY        Y
            LEA.L       LOGO,A4         Uar A4 para apuntar al carŒcter acutal
            LEA.L       LOGOE,A5        y A5 para mantener el final
            BRA         SETWIN9         Mostrar ventana y entrar en el bucle
*
* Bucle principal
*
SETWINDOW
            BSR         VDU_RDCH        Obtener carácter o espera
            BEQ.S       SETWIN0         Carácter leído, tratarlo
*
* No se ha tecleado carácter todavía, manejar el scroll del texto
*
            SCROPS      -CHWIDTH,0,SD_PAN
            MOVE.B      10(A4),D1       Obtener color para este carácter
            QDOS        SD_SETIN,3      Cambiar color
            MOVE.B      (A4)+,D1        Obtener carácter
            QDOS        IO_SBYTE,3      Imprimir carácter (A0 tiene Id canal)
            BSR         SETCURSOR       Cursor atrás
            CMPA.L      A4,A5           Se ha alcanzado el final?
            BNE.S       SETWINDOW       No, fantástico
            LEA.L       LOGO,A4
*
* Manejar el movimiento de la ventana
*
SETWIN0
            CMPI.B      #K_ENTER,D1     Tecla ENTER?
            BEQ         FINISH          Fin de programa
            CMPI.B      #K_SPACE,D1     Tecla ESPACIO?
            BEQ         SETWIN9         Si, redibujar la ventana
SETWIN1
            CMPI.B      #K_UP,D1        Tecla arriba?
            BNE.S       SETWIN2
            CMPI.W      #CHHEIGHT,WY    Comprobar Y <= CHHEIGT             BLT.S       SETWINDOW       Si es as“ no alterar, esperar sig. car.             SUBI.W      #CHHEIGHT,WY    En caso contrario, tomar CHHEIGHT             BRA         SETWIN9         Redibujar ventana SETWIN2             CMPI.B      #K_DOWN,D1      Tecla abajo?             BNE.S       SETWIN3             MOVE.W      WH,D3           D3 = Alto             ADD.W       WY,D3           Añadirle a la Y             CMPI.W      #MAXY,D3        Es Y + Alto >= MAXY ?
            BGE         SETWINDOW       Si, espera por siguiente carácter
            ADDI.W      #CHHEIGHT,WY    No, añadir CHHEIGHT a Y
            BRA         SETWIN9         Redibujar ventana
SETWIN3
            CMPI.B      #K_LEFT,D1      Tecla izquierda?
            BNE.S       SETWIN4
            CMPI.L      #CHWIDTH,WX     Es X < ancho ?
            BLT         SETWINDOW       Si, entonces ignorar
            SUBI.W      #CHWIDTH,WX     X=X-ancho
            BRA.S       SETWIN9         Redibujar ventana
SETWIN4
            CMPI.B      #K_RIGHT,D1     Tecla derecha?
            BNE.S       SETWIN5
            MOVE.W      WW,D3           Ancho
            ADD.W       WX,D3           sumar X
            CMPI.W      #MAXX,D3        Es el final de la pantalla?
            BGE         SETWINDOW       Si, ignorar
            ADD.W       #CHWIDTH,WX     X=X+ancho
            BRA.S       SETWIN9         Redibujar ventana
SETWIN5
            CMPI.B      #K_ALT_UP,D1    ALT+tecla arriba?
            BNE.S       SETWIN6
            CMPI.W      #MINH,WH        Es alto<=MINH?             BLE         SETWINDOW       Si, ignorar             SUB.W       #CHHEIGHT,WH    Alto=Alto-CHHEIGHT             BRA.S       SETWIN9         Redibujar la ventana SETWIN6             CMPI.B      #K_ALT_DOWN,D1   ALT+tecla abajo?             BNE.S       SETWIN7             MOVE.W      WH,D3           Alto             ADD.W       WY,D3           Añadir Y             CMPI.W      #MAXY,D3        Es Alto + Y >= MAXY ?
            BGE         SETWINDOW       Si, ignorar
            ADD.W       #CHHEIGHT,WH    Alto = alto = CHHEIGHT
            BRA.S       SETWIN9
SETWIN7
            CMPI.B      #K_ALT_LEFT,D1   ALT+tecla izquierda ?
            BNE.S       SETWIN8
            MOVE.W      WW,D3           Ancho
            SUB.W       #CHWIDTH,D3     Menos CHWIDTH
            CMPI.W      #MINW,D3        Es <= MINW ?             BLT         SETWINDOW       Si, ignorar             SUB.W       #CHWIDTH,WW     Reducir ancho             BRA.S       SETWIN9         Redibujar ventana SETWIN8             CMPI.B      #K_ALT_RIGHT,D1  ALT+tecla derecha ?             BNE         SETWINDOW             MOVE.W      WW,D3           Ancho             ADD.W       WX,D3           Sumar X             CMPI.W      #MAXX,D3        Es >= MAXX
            BGE         SETWINDOW       Si, ignorar
            ADD.W       #CHWIDTH,WW     Incrementar ancho
SETWIN9
            SCROPS      0,1,SD_BORDR    Elimiar borde antiguo
            SCROPS      0,0,SD_CLEAR    Y borrar ventana antigua
            LEA.L       WINDOW,A1       Obtener la dirección del buffer
            MOVE.W      WW,(A1)+        Restablecer ancho
            MOVE.W      WH,(A1)+        Restablecer alto
            MOVE.W      WX,(A1)+        Restablecer X
            MOVE.W      WY,(A1)         Restablecer Y
            SCROPS      C_WHITE,BWIDTH,SD_WDEF    Redefinir ventana
            SCROPS      0,0,SD_CLEAR    Borrar
            BSR.S       SETCURSOR       Cursor a la posición correcta
            LEA.L       LOGO,A4         Reset puntero a carácter
            BRA         SETWINDOW       Regresar y obtener siguiente tecla
*
* Limpieza
*
FINISH
            TIDYUP
*
* Posición del cursos al lugar estándar (PIXP especifica ventana relativa)
*
SETCURSOR
            MOVEQ       #0,D2           Cursor en posición superior
            MOVE.W      WW,D1           Borde derecho coordenadas-x
            SUBI.W      #CHWIDTH*2+5,D1 Dos car. separado del borde
            MOVEQ       #-1,D3          Timeout
            QDOS        SD_PIXP,3       Posición del cursor
            RTS
*
* Leer un carácter del teclado
*
VDU_RDCH
            MOVEQ       #30,D3          Algún tiempo de espera
            QDOS        IO_FBYTE,3      Obteher carácter en D1.B (A0 id canal)
            TST.L       D0              Comprobar timeout=0 si car. tecleado
            RTS
*
* Area de datos
*
* Window co-ordinates
*
WINDOW      DC.W            WIDTH
            DC.W            HEIGHT
            DC.W            X
            DC.W            Y
*
DEVNAME     DC.W            22
            DC.B            'CON_100x22a304x200_128'
LOGO        DC.B            'MetaComCo'
LOGOE       DC.B            C_CHAR1,C_CHAR2,C_CHAR2,C_CHAR2
            DC.B            C_CHAR1,C_CHAR2,C_CHAR2
            DC.B            C_CHAR1,C_CHAR2,C_CHAR2
*
            END

Comentarios:

Este programa es bastante más largo pero más completo. Nos muestra cómo controlar las teclas del cursor del teclado. Hace uso extensivo de subrutinas y macros ya comentados en ejemplos anteriores y además incluye algunos nemotécnicos nuevos con el fin de sumar y restar valores. Entre estos nemotécnicos nuevos están:

ADD y sus variantes ADDI, empleadas para operaciones de suma.

SUB y sus variantes SBBI, empleadas para operaciones de resta

CMP y CMPI, empleadas para ejecutar comparaciones entre registros y/o posiciones de memoria.

Otro aspecto a destacar en éste último ejemplo es el empleo de ciertas directivas del compilador, como por ejemplo PAGE, TTL, SPC, … Estas directivas no forman parte del juego de instrucciones del 68000 sino que son propias del ensamblador. Sirve para dirigir las acciones del propio ensamblador y muchas de ellas son de uso común.

A continuación una imagen del programa en acción.

gráficos7

Para terminar se detallan una lista casi completa de las directivas del ensamblador a modo de resumen (no forman parte del juego de instrucciones del 68000). Se muestran con ejemplos, algunas ya han sido comentadas, otras son nuevas. Esta relación ha sido extraída de la revista Qlave en uno de sus primeros números donde se hacía un análisis en profundidad del ensamblador de Metacomco.

ORG #30000 Indica origen absoluto del programa o los datos en #30000. Será preciso cargar lo etiquetado así con LBYTES.

RORG O Indica origen relativo del programa, de forma que el contador de programa es colocado a ese valor y las instrucciones que le siguen se sitúan de forma relativa a éste. Si no indicamos nada es como si hubiésemos colocado este RORG 0 con lo que el PC tiene el valor 0 inicialmente. Los programas que contienen éste son ejecutables vía EXEC. Habitualmente no se suele colocar ORG ni RORG con lo que el programa es ejecutable tanto vía EXEC como por CALL (previo LBYTES).

SIZE 1000 Indica el espacio de datos a reservar como interno al programa, recordar que todo programa ejecutable por EXEC debe contener espacio necesario para sus datos y el stack. Si no se incluye se supone un espacio de 500 octetos.

END Se coloca para indicar el fin del programa, si no se coloca genera un mensaje tipo Warning al finalizar el compilado.

EQU Asigna el valor de la expresión del campo a la etiqueta colocada en la instrucción. La asignación es permanente y la expresión no debe contener referencia a otras zonas del programa (ejemplo CASA EQU 12000, CASA tiene el valor 12000 en toda la ejecución del programa, dicho valor no se puede cambiar).

EQUR Permite asignar a un nombre creado por nosotros uno de los registros del procesador, no es posible renombrar SR, CCR, USP. La asignación es permanente y no es redefinible en ninguna otra zona del programa. En el ejemplo se asigna el nombre DATO a D0, Ej: DATO EQU D0.

SET Permite asignar a una etiqueta una expresión de igual forma que lo hace EQU con la diferencia de que el valor puede ser alterado a lo largo del programa. La expresión no deberá contener referencia a otras zonas del programa. Ej: CASA SET 12000, asigna 12000 a CASA.

DC Defina valores constantes en un programa, pueden tener un número indefinido de operandos separados por comas. Son semejantes a los DATAS de un programa BASIC Es preciso asignarles la especificación de Byte, Palabra o Palabra Larga. Se les puede colocar una etiqueta de forma que una referencia a este espacio de datos desde el programa se hace por medio de la etiqueta.
CASA DC.B 6,7,8,9,4
MESA DC.W 240, 300
ASA DC.L 70000
De esta forma si sitúo el registro A0 en CASA, con LEA CASA,A0 la celdilla de memoria a la que apunta A0 contendrá 6, la celdilla a la que apunta A0+1 contendrá 7, A0+2 8 … De igual modo si hago LEA MESA,A0 , la celdilla a la que apunta A0 contendrá 240, A0+2 contendrá 300.

DS Permiten reservar zonas de memoria vacías que posteriormente serán rellenadas con datos. Igual que las anteriores las referencias a las mismas se realizarán vía la etiqueta.
CASA DS.B 5 Reserva 5 octetos de memoria
MESA DS.W 4 Reserva 4 palabras (8 octetos)
ASA DS.L 2 Reserva 2 palabras largas (8 octetos)

PAGE Avanza el listado en ensamblador hasta la siguiente página. Este comando no aparece en los listados generados.

LIST Hace que a partir de donde esté los comandos sean listados. Por defecto se genera siempre listado.

NOLIST Desactiva el listado de forma que los comandos que le siguen no son listados hasta que aparezca LIST.

SPC Hace que aparezcan las líneas en blanco que se deseen en un listado. Ej: SPC 10 , si deseamos 10 líneas en blanco.

NOPAGE Desactiva el avance de página y la colocación de cabecera en los listados.

LLEN Coloca la longitud de na liena en listado ensamblador, la longitud debe estar entre 60 y 132. El defecto es 132. Ej: LLEN 90.

PLEN Coloca la longitud de la página de listado. El valor debe estar entre 24 y 100. El defecto es 60.

TTL Asigna una cadena como título de un programa. Será reproducida cada avance de página. La cadena no deberá tener más de 40 caracteres. Ej: TTL Programa ensamblador.

NOOBJ Desactiva la generación de código objeto hasta el fin del programa aun cuando se haya indicado un fichero en el inicio de la ejecución del compilador.

FAIL Genera un error de usuario.

CNOP Permite que una sección de código sea alineada a un límite determinado. En particular permitirá que una estructura de datos se alinee a un límite de palabra larga.
CNOP 0,4 alinea el código al límite de la próxima palabra larga.
CNOP 2,4 alinea el código a un límite de palabra de 2 bytes antes de la más cercana alineación de palabra larga.

IFEQ
IFNE Permite activar o desactivar el ensamblado dependiendo del valor de la expresión. Así si el operando es cero (EQUAL), IFEQ activa el ensamblado si no lo fuera lo desactivaría. IFNE se comporta de modo contrario.

ENDC Marca el fin del un ensamblado condicional de las características mencionadas arriba.

MACRO Marca el comienzo de una macro-definición, ejemplos de ellas se pueden ver en los ejemplos de este artículo. Contienen un conjunto de instrucciones que se ejecutan cada vez que se la llama tecleando la etiqueta que se coloca a su comienzo. Son semejantes a las funciones y procedimientos del SuperBasic. De igual forma admiten parámetros. Para indicar un parámetro se coloca un símbolo #seguido por el número del parámetro que llevemos usados; 1 o 2 o … Dentro de una macro definición no se puede comenzar la definición de otra macro, es preciso definirlas separadamente y es posible que una macro use otras macros, ahora bien hay un límite en el nivel de anidación que se puede usar, este nivel es de diez.

ENDM Indica el fin de la macro-definición.

MEXIT Permite forzar la salida de una macro durante su ejecucion. Se suele usar conjuntamente con IFEQ y IFNE.

XDEF Nos ayuda a crear ficheros que pueden ser lincados entre si por el lincador incluido en el paquete. Así podemos encontrarnos un fichero:
XDEF DECIMAL,SIST,EV
Esto nos indica que este fichero contiene las definiciones de tres subrutinas que podrán ser usadas por otros programas. DECIMAL, SIST, EV son las etiquetas que habremos colocado al comiento de la subrutinas.

XREF Es el comando que debemos incluir en el caso de que en un fichero vayamos a usar subrutinas que no estén escritas en el programa y que se incluirán más tarde al enlazar éste fichero con el que contenga esas rutinas.

GET Permite insertar ficheros externos en el fichero fuente actual. Ver que esto es completamente distinto a las referencias anteriores ya que aquí se inserta código fuente mientras que antes enlazábamos código objeto. Este comando es útil para insertar ficheros.


Aunque jamás se pudieron terminar, las máquinas de este matemático inglés fueron las precursoras del ordenador moderno

“¡Por amor de Dios, desearía que estos cálculos se hubiesen efectuado a vapor!”, exclamó Carles Babbage mientras se afanaba con las tablas del Calendario Náutico. El siglo XIX había desarrollado la energía de vapor, pero la navegación marítima precisa continuaba siendo un problema. La posición de un navío se determinaba observando la luna y utilizando luego tablas matemáticas que con frecuencia eran inexactas.

Fue en 1812 cuando Babbage pensó por primera vez en construir una máquina, que él denominó ingenio diferencial, que pudiera efectuar los laboriosos cálculos que requerían las tablas náuticas. Hacia 1823 había completado un pequeño modelo y le solicitó al gobierno una subvención para construir una máquina que funcionara. El ministro de Hacienda le entregó 1500 libras y Babbage se propuso crear una máquina que eliminara los errores mediante la impresión automática de los resultados de sus propios cálculos.

Babbage se entregó en cuerpo y alma a cumplir el objetivo fijado. El proyecto consumió enormes cantidades de dinero, pues sus expectativas se hallaban drásticamente limitadas por la insuficiencia de los conocimientos de ingeniería de aquel entonces. Obtuvo el dinero necesario gracias a la ayuda del primer ministro, su amigo el duque de Wellington. A pesar de la confianza de Babbage en que “lo que hiciera la máquina, lo haría con precisión”, el gobierno decidió, finalmente, retirar su subvención al proyecto, luego de haber invertido 17000 libras en él. El ingeniero que colaboraba con Babbage, Joseph Clement, también dimitió al poco tiempo, a raíz de una controversia, y se llevó consigo todas las herramientas que se habían diseñado específicamente para el ingenio.

Babbage se abocó rápidamente a un proyecto más ambicioso, el ingenio analítico, con el que esperaba alcanzar todos los objetivos para los cuales había construido el ingenio diferencial y muchos otros más aparte de ellos. En muchos sentidos su diseño se parecía al del ordenador moderno. Contenía un almacén de memoria y un “molino” aritmético (equivalente a una CPU), proporcionaba una salida impresa e incluso era posible programarla, mediante el empleo de bifurcaciones condicionales.
Al principio las instrucciones se controlaban mediante clavos largos, como en un organillo; posteriormente se adaptó el sistema de tarjeta perforada que Joseph Jacquard había introducido en la industria textil. Babbage también experimentó con distintas bases numéricas pero, como todas sus máquinas eran mecánicas, la utilización del sistema binario no suponía ventaja alguna.

La compañera de Babbage, la condesa Ada Lovelace, matemática genial, se unió al proyecto. Ambos se hallaban abrumados por las dificultades, entre las cuales las económicas no eran las menores. Ella perdió gran parte de su patrimonio apostando en las carreras de caballos, aplicando a este juego un sistema “infalible”, según ella. Después del fallecimiento de la condesa, acaecido cuando sólo contaba 36 años, Babbage continuó en solitario su labor.

Hombre de portentosa energía, también inventó el oftalmoscopio médico para examinar el fondo del ojo, hizo una coreografía de ballet, ideó un sistema para la iluminación del escenario e inventó una técnica para la señalización marítima.

En los últimos años de su vida se volvió irascible. Rechazó el título de barón que se le ofreció en reconocimiento de su trabajo, debido a que no coincidía con sus aspiraciones.

Con su trabajo Babbage anticipó la estructura del ordenador electrónico moderno, pero fracasó en convertir en realidad su visión global. Su ingenio analítico jamás llegó a terminarse, coartada su realización en razón de las limitaciones técnicas de la ingeniería del siglo XIX.

Cronología:

– 1792. Nace en Totnes, condado de Devon (Gra Bretaña), el 26 de diciembre.
– 1810. Ingresa en el Trinity Collage, Cambridge, para estudiar matemáticas.
– 1814. Se casa con Georgina Whitemore.
– 1822. Publica el trabajo titulado “Observation on the Applications of Machinery to the computation of Mathematical Tables (Observaciones sobre las aplicaciones de maquinaria al cálculo de tablas matemáticas). Recibe la primera medalla de oro de la Astronomical Society, que él contibuyó a fundar.
– 1827. Cambridge lo designa Lucasian Professor, cátedra que anteriormente ejerciera Newton, con un sueldo de 80 libras al año, aunque no resida allí ni imparta clase alguna..
– 1833. Candidato al parlamento por Finsbury.
– 1834. Se suspende el trabajo sobre el ingenio diferencial después de la dimisión del ingeniero Joseph Clement.
– 1862. El ingenio diferencial, parcialmente completo se exhibe en South Kensington (Londres).
– 1871. Muere el 18 de octubre.

(Fuente: Enciclopedia Mi Computer. Editorial Delta, 1984.)

El desarrollo de QLUB sigue avanzando. Martyn Hill, su creador, ha liberado recientemente el driver nativo QDOS y SMSQ/E para permitir integrar un PC con un emulador QL en la red QLNET.

A modo de resumen, el adaptador QLUB es una solución híbrida de hardware y software para permitir que un emulador QL en un PC con un puerto USB se pueda conectar a la red QLNET de Sinclair, la cual está disponible de serie en cualquier QL.

Además del QL, se pueden conectar máquinas compatibles con él que dispongan del hardware de red QLNET (por ejemplo Aurora, QXL, Q68, …) así como el ZX Spectrum con Interface-1 instalado.

Al vincular el emulador QL y el hardware QL «real» mediante QLNET y Toolkit II, es un asunto trivial transferir archivos con comodidad desde un entorno emulado al hardware retro original. Obviamente, la transferencia es de de “ida y vuelta”, pudiendo actuar como cliente o como servidor tanto el emulador como la máquina retro original.

La transferencia de archivos es solo el caso de uso más obvio: los juegos en red y la «computación distribuida» también se convierten en una propuesta práctica e interesante. Adicionalmente, dada la flexibilidad del sistema operativo QDOS, QLNET permite compartir los distintos dispositivos de cada estación a través de la red, por ejemplo impresoras, puertos serie, puerto paralelo y hasta la propia consola.

El dispositivo hardware es el siguiente:

Como se ve en las imágenes, QLUB consta de una placa Teensy++2.0 que se conecta a una pequeña placa adaptadora la cual alberga los conectores jac para la conexión de cableado QLNET.

Todos los componentes son libres y en los hilos del proyecto en qforum se pueden obtener el software necesario y las instrucciones para la construcción del dispositivo.

He realizado bastantes pruebas en mi red QLNET y el resultado es muy satisfactorio. Mi red QLNET está formada por tres estaciones: un QL real con SuperGoldCard, la FPGA Q68 y el PC con el emulador QL (QemuLator o QPC2). Las tres estaciones están configuradas como cliente y como servidor lo cual me permite la transferencia de ficheros desde-hasta cualquier estación así como la la ejecución de programas ubicados en cualquier estación servidora. En la siguiente imagen se puede observar como el QL original muestra el contenido de una carpeta del PC gestionada por QPC2 y el contenido de una de las unidades de almacenamiento de la FPGA-Q68. (En mi red QLNET: «n3» es el identificador del emulador PC que es la «estación 3», «n2» es el identificador de la FPGA-Q68 que es la «estación 2»).

La solución es perfectamente funcional y sólo existen algunas incidencias menores en las que está trabajando Martin Hill y que se corregirán en la siguiente versión del producto.

Referencias:

https://qlforum.co.uk/viewtopic.php?t=3590

https://qlforum.co.uk/viewtopic.php?t=4278

El peligro de tener una alimentación dual 5V/9V es que puedes meter 9V en una tarjeta configurada para 5V. Eso me pasó a mí con mi QubIDE. Vi claramente cómo salía humo de uno de los chips. Pues nada, esta QubIDE hay que arreglarla.

Lo primero que pensé fue cambiar los chips GAL, que eran los que estaban más cerca de donde salió el humo. Por fortuna el contenido de los GAL está publicado en Internet, así que me compré unos chips Lattice GAL16V8D-15 y un grabador TL866 II PLUS, grabé los chips y a probar. Aquello no funcionó. Probé con varias versiones de ficheros Jedec que encontré para los GAL, pero ninguna funcionó.

Lo siguiente fue comprar el resto de chips de la QubIDE. Mirando las datasheets, en todas más o menos se decía que los chips soportaban instantáneamente una tensión máxima de 7V, luego con unos 9V durante varios segundos va a ser que se han quemado todos. Conseguí todos los chips (los 74HCT646 me salieron muy caros, pero no había otra) y a probar. Tampoco funcionó. Empecé a pensar que se había quemado alguna pista o alguna otra parte que no veía.

Si tuviera una QubIDE funcionando podría comprobar cada uno de los chips por separado hasta encontrar el problema, pero no tengo. Así que pensé: como están publicados los esquemas y los jedec, pues me la fabrico.

Cogí el esquema publicado por Zeljko Nastasic, el autor del hardware de la QubIDE, y me puse a dibujarlo en KiCad.

Se trataba de hacerlo lo más parecido posible al original, si no idéntico. En algunos detalles me tuve que fijar en la QubIDE real para ponerlos iguales. En el proceso dibujé símbolos especiales para los GAL, como si fueran componentes por sí mismos, y también dibujé símbolos especiales para los conectores de bus ATA y de bus QL.

Después pasé a dibujar el PCB, posicionando los componentes y fijándome en las pistas tal y como están en la QubIDE real, pero la placa original es de cuatro capas y las pistas interiores no se ven, así que tuve que tirar de FreeRouting para colocar el resto de pistas en mi dibujo, por supuesto, también de cuatro capas.

Aquí disponía de todas las huellas necesarias para el dibujo de la placa, pero también quise verla en 3D porque me apetecía, y los modelos 3D no estaban todos, de modo que tuve que modelar los conectores DIN 41612 para ver la infografía a gusto.

Los modelos 3D los he hecho con OpenSCAD, de OpenSCAD los he pasado por partes como STL a FreeCAD, y de FreeCAD los he exportado a WRL para finalmente importarlos en KiCad.

El siguiente paso es hacer un pedido de componentes a Mouser y un lote de placas a JLCPCB. Las placas han de ser como mínimo cinco, y los componentes, cuantos más mejor para ahorrar, y, bueno, compré componentes suficientes para montarme dos, por si metía la pata con una de ellas. Un tiempo después llegaron los componentes, y un poco más tarde las placas.

Hora de ponerse a soldar.

Mientras tanto grabo las EPROM con el nuevo driver que hizo Alain Haoui, para esto también me vino bien el grabador que compré al principio de esta historia.

Estando ya todo en su sitio la enciendo por primera vez sin conectar ningún dispositivo y esto es lo que sale:

Hasta ahora todo bien. Me alegro de que no hubo ningún error en el PCB. Conecto una tarjeta SD con un adaptador ATA de 40 pines y la reconoce, bien. Pruebo con varios dispositivos más y todos los reconoce, bien.

Escribo unos comandos para formatear una tarjeta y empezar a usarla.

WIN_FORMAT 1

WIN_DISK “INITIALIZE”,1

WIN_DISK “CREATE”,1,1,121

FORMAT “WIN1_SD128M”

WIN_FORMAT 0

Aparentemente va todo bien. Escribo algunos ficheros y parece funcionar. Reseteo el ordenador y no lee bien la tarjeta SD, no reconoce la FAT. A veces sí, a veces no. Tiene un funcionamiento errático.

Repaso los GAL, tengo tres versiones diferentes, la versión 1 que sólo sirve para las versiones 1.xx de la ROM; y la versión 2 de varias formas, para las versiones 2.xx y 3.xx de la ROM. Pruebo con todas las versiones, usando los diferentes chip GAL que tengo, pero nunca consigo un funcionamiento estable. Ya empiezo a desesperar y me pongo a mirar el código fuente y además descompilo a mano los ficheros Jedec para comparar, y después repaso la lógica y trato de entender lo que hace, lo reescribo en CUPL y lo compilo. Y sigue fallando esporádicamente.

Entonces repaso todo lo que he realizado hasta el más mínimo detalle y me doy cuenta de que los chip GAL originales no son iguales, los originales son AMD PALCE16V8H-15 para el GAL1 y AMD PALCE16V8H-25 para el GAL2, los míos son todos de 15, así que por si acaso compro unos de 25. Y regrabo de nuevo y al final pongo Lattice GAL16V8D-15 para GAL1 y Lattice GAL16V8D-25 para GAL2. Ya todo en su sitio vuelvo a probar y voilá, funciona.

Ya tengo QubIDE que funciona. Ahora puedo probar los chips originales de la QubIDE original, voy probando uno por uno y resulta que sólo los GAL están mal, con lo cual volvemos a mi primera opción, que era cambiar sólo los chips GAL, que en su momento no funcionó y no sé por qué. Incluso el chip de ROM funciona bien, así que le dejo la versión 2.01, que es la que tenía.

Bueno, ahora con la tontería tengo tres QubIDEs. Y además con todo esto he aprendido…

A dibujar esquemas, nuevos símbolos y circuitos impresos en KiCad,

A trazar rutas de forma automática con FreeRouting,

A modelar en 3D con OpenSCAD y FreeCAD para KiCad,

A programar GALs con WinCUPL.

Y como final quiero dar las…

Gracias a Zeljko Nastasic, por diseñar el hardware de la QubIDE y publicarlo en Internet.

Gracias a Andrew Reed y Phil Borman por programar el driver y liberarlo con licencia GPL.

Gracias a Alain Haoui por hacer un nuevo driver mejorado y publicarlo para que podamos utilizarlo.

Cartel anunciador

Con un stand llamativo cuyas paredes estaban formadas por las siglas QL, Investrónica presenta en la feria Informat de 1985 el nuevo ordenador, destacando la ausencia total de Spectrum en este lanzamiento.

El precio definitivo de salida al mercado español fue de 125.000 Ptas. (751,27 €), incluyendo los programas de PSION notablemente mejorados y en castellano.

El año anterior, motivada por la demanda del mercado, la compañía ya había puesto en venta la versión inglesa con unas cifras que arrojaban las 2.000 unidades hasta la campaña de navidad de 1984.

Investrónica estaba a la expectativa. Quería ver como se desenvolvía el nuevo ordenador en el mercado español. Lo que sí tenía claro es que se trataba de una máquina distinta con otra orientación, y que no haría sombra al afianzado Spectrum, como demuestra este comentario de un representante de la compañía:

«El QL, lo que no cabe duda es de que va dirigido a un público muy determinado, que se va a comprar un ordenador para darle una aplicación concreta, incluso en algunos casos para una única aplicación, como pueda ser, por ejemplo, para llevar un tratamiento de textos«

Un año después, en 1986, Investrónica vendería a precio de saldo su stock de QLs y dejaría de darle soporte.

Pueden conocer lo que publicó la revista MicroHobby a este respecto del lanzamiento, y remontándonos un año atrás, lo que opinaba Investrónica sobre esta máquina.

Conmemorando

Pues bien, aprovechando que el Pisuerga pasa por Valladolid, en el día de ayer, 16 de abril, nos reunimos los tres mosqueteros y D’Artagnan (Afx, Zerover, Badaman y Salvador Merino) para hablar de nuestras cosas y conocernos todos. Aquí el testimonio de ese encuentro.

Durante cerca de dos horas Salvador nos puso al corriente de algunas curiosidades que desconocíamos sobre el club QLave que el dirigió, y le contamos las peripecias y novedades del mundillo del QL.

Fue un gusto estar en esa reunión.

Salvador Merino

Para quienes no conozcan a Salvador Merino todavía, deciros que es quien mantuvo vivo el club casi hasta los albores del año 2000, y que tuve la suerte de conocerlo allá por el 2002, siendo el germen y el sustento del proyecto de la web de SinclairQl.es que inicié entonces. Casi todo el material disponible en la web se lo debemos a sus aportes, abriendo así la posibilidad a conocernos varios locos del QL décadas después de que este ordenador dejara de estar vivo comercialmente.

Al respecto del cierre del Club, Salvador nos cuenta: «Cuando decidí cerrar el club, todos teníamos un PC y sabíamos el futuro de Internet. El problema es que nos dimos cuenta que era imposible actualizar los programas QL de aplicaciones Internet, y para qué perder tiempo en actualizar esas aplicaciones para un emulador si esas aplicaciones estaban en Linux y Windows actualizadas, y para colmo eran gratis.

En Quanta ya se hizo lo imposible desde 1991 para conseguir todo el código fuente necesario para empezar a escribir las primeras aplicaciones en el lenguaje ‘C’, pero era imposible por nuestros medios mantener el ritmo de actualizaciones (Lo más difícil era obtener el código fuente para mantener la compatibilidad).»

HOTKEYS es una extensión que forma parte de «Pointer Environment» (PE), el entorno de ventanas creado por Tony Tebby para el Sinclair QL. Podríamos definirlo como un sistema para declarar combinaciones de teclas que cuando se pulsan dan lugar a una acción que es independiente de la tarea que se está realizando.

Lo primero que tenemos que tener presente es que, para poder disfrutar de las facilidades de HOTKEYS en nuestro QL, necesitamos cargar en nuestro sistema el «Pointer Environment» completo. Este entorno de ventanas consta específicamente de tres módulos residentes PTR_GEN, WMAN y HOT_REXT. Otro componente que podríamos catalogar de indispensable en el QL sería también el Toolkit 2, el cual viene de una manera u otra en la mayoría de los QL que incorporan expansiones de disquetera y ampliaciones RAM.

El programa más simple para cargar en nuestro QL un entorno mínimo para empezar a trabajar con HOTKEYS sería el siguiente:

100 TK2_EXT : REMark en algunos sistemas esta línea es esencial
110 LRESPR FLP1_PTR_GEN
120 LRESPR FLP1_WMAN
130 LRESPR FLP1_HOT_REXT
140 HOT_GO

Comentemos brevemente el las líneas del programa SuperBASIC anterior.

En la línea 100 se ejecuta el comando TK2_EXT que es usado para activar el Toolkit 2 en algunos sistemas. Esto nos permitirá usar a su vez el comando LRESPR, empleado en las líneas siguientes para cargar cómodamente el resto de extensiones necesarias para usar el PE. Si no tuviéramos el Toolkit 2 (que es el que aporta el comando LRESPR) tendríamos que cargar el resto de módulos averiguando primero el tamaños del archivos, y con los comandos LBYTES y CALL cargar cada uno de los módulos en modo residente. LRESPR nos ahorra esfuerzo ya que nos permite cargar las extensiones que necesitemos de una forma más automática.

En la línea 110 cargamos el primer módulo del PE llamado PTR_GEN. Este módulo controla la interfaz de puntero; una flecha en pantalla a modo de cursor que es controlada por un ratón o por las teclas del cursor del teclado. Al igual que otros sistemas GUI, podemos indicarle al ordenador lo que debe hacer desplazando el puntero hasta los «comandos» representados en la pantalla y haciendo «clic» sobre ellos.

El ratón en los QL tiene generalmente 2 botones. La presión sobre el botón izquierdo se llama HIT, y la presión sobre el botón derecho se llama DO. Esas acciones (HIT y DO) tienen equivalentes también en el teclado. Como hemos mencionado anteriormente el puntero se puede mover con las teclas del cursor del teclado, HIT se ejecuta con la barra espaciadora y la acción DO con la tecla ENTER.

WMAN es una abreviatura de «Window Manager» (el gestor de ventanas). Este gestor de ventanas es un sistema mediante el cual se proporciona un aspecto ‘estandarizado’ a la apariencia y funcionamiento de los menús, desplazamiento de las ventanas, etc. En la línea 120 de nuestro ejemplo cargamos WMAN con el comento LRESPR FLP1_WMAN.

HOT_REXT es la parte que controla las «Hotkeys», las teclas de acceso rápido, que formalmente se denomina «Hotkey System II». En nuestro ejemplo cargamos este módulo en la línea 130 con LRESPR FLP1_HOT_REXT, lo cual ejecuta un pequeño Job (o tarea residente) llamado Hotkey el cual se ocupa de controlar teclas de acceso rápido.

El comando HOT_GO de la línea 140 es el encargado de activar las teclas de acceso rápido (Hotkeys). En otras palabras, una vez que un comando HOT_GO ha sido ejecutado, las teclas de acceso rápido que se hayan programado comenzarán a funcionar.

Existe también un comando relacionado llamado HOT_STOP el cual desactiva las teclas de acceso rápido que se hayan definido. Es importante recordar este comando porque hay ocasiones en las que no podemos cargar extensiones adicionales mientras Hotkey está funcionando y una forma de hacerlo es desactivando temporalmente las Hotkeys con HOT_STOP y luego volverlo a activar una vez cargadas las extensiones necesarias.

Otra cosa importante a tener en cuenta es el uso de CTRL C (la pulsación conjunta de las teclas CTRL y la letra C). Este combinación de teclas permite conmutar el foco entre varios programas que están ejecutándose al mismo tiempo. Esta es una de las formas más habituales de conmutar entre los distintos programas que están ejecutándose en nuestro QL.

Para comprender la importancia de la Hotkeys en un sistema de la época del QL pongamos un ejemplo. Supongamos que estamos tecleando algo en un procesador de textos y queremos comprobar algo en nuestra base de datos sin tener que salir del procesador de textos. En un ordenador personal de principios de los años 80, nosotros tendríamos que grabar en un fichero el trabajo que estuviéramos haciendo en nuestro procesador de textos, a continuación salir del procesador, arrancar la base de datos, chequear la información, salir del sistema de base de datos y volver a arrancar el procesador de textos con el fichero en el que estuviéramos trabajando.

Pero en un QL con su multitarea y el Hotkeys, las cosas se podrían hacer de otra manera.

Supongamos que hemos definido una combinación de teclas como la vía para arrancar un programa, sin tener que parar el programa actual sobre el cual estamos trabajado. Más aún, si ese segundo programa ya estuviera en ejecución, nuestra combinación de teclas provocaría que se activara ese programa que aún está en memoria. Luego, mediante otra combinación de teclas (Hotkeys) que también hayamos definido, podríamos regresar al primer programa en el que estábamos anteriormente.

Todo esto puede sonar muy complicado al principio, pero podemos acostumbrarnos rápidamente después de verlo en acción.

Este es el principio básico detrás de las Hotkeys: definimos teclas para realizar «acciones». Independientemente de lo que estábamos haciendo, estas teclas permiten que hagamos algo más al instante sin tener que pasar por la molestia de grabar el programa actual, salir de él e ir al SuperBASIC, teclear comandos para ejecutar otras acciones y así sucesivamente. Lo bueno de este sistema es que una vez que hayamos configurado la pulsación de una determinada acción según nuestras necesidades, podemos ir y definirlas en el programa de arranque de nuestro QL (boot) para que se ejecuten cada vez que arrancáramos el sistema.

En la definición de Hotkey anterior hemos hecho referencia al término «acciones», pero ¿Qué son exactamente esas acciones?

Las acciones pueden ser:
– Cargar un programa en memoria para iniciarlo de forma rápida posteriormente.
– Cargar un programa desde disco.
– Seleccionar un programa (saltar directamente a él desde otro programa)
– Relleno de texto, o lo que sea, en un búfer especial (como una especie de portapapeles) para pasar en otro programa
– Enviar comandos al SuperBASIC
– Listar las teclas que se han definido
– Activar o desactivar definición de teclas individuales

Exploraremos esta acciones a medida que avancemos en el tema.

Las Hotkeys se definen como una pulsación de varias teclas donde se usa siempre la tecla ALT junto con otra tecla. Esto no es nuevo en el QL y de hecho el Toolkit II tiene algo muy parecido llamado ALTEKEYs. Veamos cual es la diferencia mediante un ejemplo sencillo.

Supongamos que hemos definido un ALT key del Toolkit II para cargar un programa llamado MIPROGRAMA_BAS desde la unidad de disco flp1_. Para ello utilizaremos el siguiente comando:

ALTKEY 'a','LOAD FLP1_MIPROGRAMA_BAS'

Bien, supongamos que estamos en SuperBASIC y pulsamos ALT junto con la tecla ‘a’. Efectivamente, aparecerá en el canal #0 (area de comando en la zona inferior de la pantalla) la orden LOAD FLP1_MIPROGRAMA_BAS. Pero supongamos que estamos editando un documento con el procesador de textos Quill, ¡vaya …!, ahora aparece LOAD FLP1_MIPROGRAMA_BAS como parte del documento que estábamos editando y esto no es lo que queremos. Tendríamos que regresar al SuperBASIC para que este altkey sea de utilidad.

El sistema HOTKEY nos permite hacer esto mucho mejor. Por ejemplo, con el comando HOT_CMD de HOTKEY podemos definir una combinación de teclas para indicarle al ordenador que queremos un comando destinado al SuperBASIC. Esto nos aseguraría que el control del ordenador «salta» al BASIC primero y luego ejecutal el comando por nosotros. El proceso de saltar al BASIC o a otro programa se conoce como «PICKING» en la terminología del sistma de Entorno de Ventanas del QL (PE). Esto evitaría el incoveniente de ALTKEY que hemos mencionado anteriormente.

Así podemos ver que el sistema HOTEKY nos da más versatilidad y potencia que el sistema ALTKEY usado por el Toolkit II.

Podemos elegir cualquier tecla a la hora de definir una acción con HOTEKY pero hay algunas teclas reservadas que deberíamos evitar.

Las letras y números son buenos candidatos. Las teclas de función se pueden definir también pero son más difíciles de recordar. Entre las teclas a evitar están la tecla ENTER (ALT ENTER tiene un significado especial para HOTKEY, nos recupera la última línea de ordenes que hemos tecleado), las teclas de cursor, la tecla CAPS LOCK y la telca TAB. Tampoco es buena idea usar las teclas de apóstrofe o las teclas de símbolos (por ejemplo \).

¿Cómo definir combinaciones de teclas y acciones?

Veamos ahora cómo definir combinaciones de teclas y sus correspondientes acciones.

Los comandos para definir HOTEKYs están incluidos como extensiones SuperBASIC para hacer uso de ellos. La mayoría son funciones en lugar de comandos, esto significa que al ejecutar esas funciones nos devolverá un valor de retorno el cual nos indica si todo se ha ejecutado bien o si ha habido algún error.

Por ejemplo, ejecuta los siguiente desde la línea de comandos SuperBASIC:

PRINT HOT_CMD('a','LOAD flp1_MIPROGRAMA_bas')

Esto imprime el número 0 si todo ha ido bien en la definición del HOTEKY. Si ha habido algún error entonces la función retornará un valor distinto de 0 que representa al código de error, por ejemplo «In Use» error (-9).

Existe un pequeño comando para manejar esos números de retorno pasados por la función que define el HOTEKY, llamado ERT, que significa Error ReporT. Si todo ha ido bien no hace nada, pero si algo ha fallado ese comando emite un sonido o nos da un mensaje descriptivo del error. Un ejemplo de cómo usarlo sería el siguiente:

ERT HOT_CMD('a','LOAD flp1_MIPROGRAMA_bas')

El primer parámetro de la función HOT_CMD define la tecla a la cual será asociada el comando. Presionando la tecla ALT junto con esa tecla (en nuestro ejemplo la tecla 'a') se ejecutará el comando especificado en el segundo parámetro (en el ejemplo, 'LOAD flp1_MIPROGRAMA_bas'). Un aspecto importante a tener en cuanta es que HOTEKY es sensible a las mayúsculas y minúsculas. Se puede definir una acción distinta para la tecla en mayúscula con lo cual tendremos dos definiciones para la misma tecla, pero existen particularidades y ciertas reglas en su uso.

Si defines una HOTEKEY con una tecla en minúscula y no existe otra definición para esa tecla en mayúsculas entonces ambas teclas provocarán en mismo resultado (en el ejemplo anterior ALT a , SHIFT ALT a , o ALT A producirán el mismo efecto).

Los usuarios QL suelen aplicar patrones en la definición de las teclas que resultan útiles.

Por ejemplo, para acciones que involucren la carga o la selección (picking) de programa:

a) usa teclas en mayúsculas para la carga de programa.
b) usa la tecla en minúscula para la selección de programa.

Esto parece lógico, la carga de un programa desde disco es una acción típicamente menos común durante una sesión de trabajo, así usamos las teclas SHIFT ALT y la tecla deseada (tenemos que pulsar tres teclas). Sin embargo, una vez cargado los programas en memoria podría ser muy habitual conmutar entre ellos con una combinación más simple de teclas, la tecla ALT y la tecla deseada (sólo pulsamos dos teclas).

Bien, veamos ahora cómo cargar y seleccionar programas.

Hay varias formas de cargar un programa. Puede cargarse en la memoria y posteriormente ejecutarlo desde la memoria. Esto es muy útil en sistemas sin disco duro ya que podemos para evitar tener que insertar su disquete cada vez que necesite iniciar cualquier programa frecuente y que no esté disponible en el disquete en esos momentos. Sin embargo, siendo muy útil para los programas de uso común, nos ata un poco en cuanto al uso óptimo de la memoria. El más simple de entender es el comando que simplemente carga un programa desde el sistema de almacenamiento (un disquete por ejemplo). Asumiré que mi programa se llama PROGRAM_EXE en este ejemplo:

ERT HOT_LOAD('p','flp1_program_exe')

Cuando mantienes presionada la tecla ALT y pulsas la tecla p, el sistema intenta cargar PROGRAM_EXE desde FLP1_. Sencillo. Pero, de nuevo, hay un par de puntos menores a tener en cuenta.

He puesto el texto entre comillas en el ejemplo anterior, pero en la mayoría de los casos, podría haberse escrito los parámetros del comando de esta forma:

ERT HOT_LOAD(p,flp1_program_exe)

En caso de duda, usa las comillas. Además, el nombre de archivo del programa está escrito en minúsculas, no importa ¡el QL maneja los nombres de archivo en mayúsculas y minúsculas! Ten en cuenta que si omites el nombre de la unidad, HOTKEY intentarán agregar el nombre de la unidad predeterminada por DATA_USE o PROG_USE (las unidades predeterminadas de Toolkit 2 para datos y programas).

Con HOTKEY hay dos extensiones para cargar programas en la memoria para que, posteriormente, puedan iniciarse rápidamente sin tener que tener tus discos en las unidades (esto es bastante similar en principio a usar RESPR o LRESPR para cargar extensiones SuperBasic).

Las dos extensiones son: HOT_RES y HOT_CHP. ¡Ahora las cosas se vuelven un poco más complejas! De hecho, hay otras variaciones llamadas HOT_RES1, HOT_CHP1 y HOT_LOAD1 para casos especiales en los que no te atreves a ejecutar dos copias del mismo programa al mismo tiempo. (A tener en cuenta que en QDOS podrían haber programas que se modifican a sí mismos cuando se cargan en memoria, lo cual podría tener efectos no deseados. Ignoraremos esto por ahora, pero ten en cuenta que existen razones para estas variantes del mismo comando).

HOT_RES se utiliza para cargar programas RESIDENTES. Eso significa que se cargan en la memoria para que posteriormente podamos iniciarlos rápidamente (una o más copias de ellos). Este comando tiene un problema: si hay otros programas ejecutándose o el Job del HOTKEY está activo, este comando podría no funcionar. En estos casos se debe utilizar HOT_CHP. En algunas versiones del sistema HOTKEY, la función HOT_RES parece convertirse automáticamente en HOT_CHP cuando sucede este problema.

¿Cuándo debes utilizar HOT_RES o HOT_CHP en lugar de HOT_LOAD?

Fácil. Reserva el uso de HOT_RES o HOT_CHP para los programas que utilizas con más frecuencia para evitar tener que insertar sus disquetes cada vez que inicies una copia. HOT_LOAD está bien para programas usados ocasionalmente en los que no quieres que acaparen memoria todo el tiempo mientras están cargados de forma residentes.

La secuencia real de eventos cuando se emite un comando HOT_RES o HOT_CHP es la siguiente:

1. Cuando el sistema interpreta el comando, agrega el programa pasado como parámtro al sistema de teclas de acceso directo. Esto significa que, en esencia, cuando se ejecuta la línea que define la tecla de acceso directo, se busca el programa y se carga en la memoria.

2. Cuando más tarde se pulsa la tecla de acceso directo definida como HOT_CHP o HOT_RES, busca el programa en la memoria e intenta iniciar su ejecución.

HOT_LOAD es esencialmente sólo el equivalente del paso (2) – sólo carga el programa nombrado cuando se pulsan las teclas indicadas, en lugar de almacenar una copia en la memoria. Es importante entender la diferencia entre estos comandos. HOT_LOAD iniciará un programa desde el disco sólo cuando se lo indicas. HOT_CHP y HOT_RES harán inmediatamente una copia del programa desde la unidad de almacenamiento a la memoria cuando se definan sus parámetros (tecla de acceso y nombre del programa). Posteriormente, al pulsar la tecla definida por HOT_RES o HOT_CHP, se ejecuta una copia del programa ya cargado en memoria. De hecho, es bastante inteligente, si usas HOT_CHP o HOT_RES, sólo una copia del programa se mantiene en memoria incluso si tiene dos de esos programas en ejecución. Es bastante complejo de explicar, pero básicamente los programas definidos como ‘puros’ pueden tener más de una instancia de sí mismos ejecutándose al mismo tiempo, aunque de hecho sólo hay una copia en la memoria – ¡el sistema está siendo bastante inteligente al ejecutar más de una instancia del mismo código a partir de una sola copia de él!

Estos programas ‘puros’ incluyen a Quill, Archive, Abacus, Easel y los programas QPAC1, por ejemplo. Pero hay otros programas (llamados ‘no puros’) que modifican su propio código de tal manera que no es prudente hacer que un programa en memoria se ejecute como si se tratara de dos instancias separadas. En caso de que una copia modificara su propio código al mismo tiempo que la otra instancia de sí misma intentara hacer algo podría producir el caos. Los programas compilados por Turbo entran en esta categoría – tiene que usar las versiones HOT_CHP1 y HOT_RES1 de estos comandos para asegurarse de que hay el mismo número de copias físicas del programa en la memoria como instancias de si mismo en ejecución. (Esto no es fácil de explicar pero espero que puedas seguirlo).

HOT_LOAD no hace esa distinción. Siempre carga una copia del disco y la ejecuta cuando la necesita. Si tienes problemas para entender HOT_CHP y HOT_RES y sus variaciones, ignóralos, usa HOT_LOAD solo por ahora hasta que entiendas estos conceptos.

Una vez que un programa se en memoria y se está ejecutando, se necesita una forma de saltar a y desde él. Supongamos que nuestro pequeño programa de ejemplo llamado PROGRAM_EXE tiene un nombre simplemente «PROGRAM» (es decir, el nombre que muestra cuando se está ejecutando y que emite el comando JOBS desde BASIC). Hay una función llamada HOT_PICK cuya función es encontrar el programa llamado, y traerlo para que sea el trabajo (o ‘Job’) actual. Esta acción se llama PICKING.

Por ejemplo:

ERT HOT_PICK('a','PROGRAM')

Una vez ejecutado el comando anterior, cuando presiones ALT a, el sistema busca un programa con ese nombre que se esté ejecutando en la memoria y lo «activa» para que puedas trabajar en él.

Todo esto está muy bien, pero como de costumbre con las teclas de acceso rápido (HOTKEYS), la historia no es tan simple.

Los nombres de los «Jobs» (de las tareas o trabajos en QDos) no son simples y pueden no ser obvios, por lo que el sistema HOTKEYS ofrece otra opción relacionada con esos nombres de «Jobs».

Para elegir un «Job» o incluso eliminarlo, es posible que necesites saber su nombre. Muchas veces, el nombre del «Job» es igual al nombre del programa que cargaste, pero esto no siempre es así; ¡peor aún, algunos programas cambian sus propios nombres mientras se ejecutan por razones que se nos escapan a la mayoría de nosotros!

Para resolver esto, puedes usar la siguiente opción en algunos comandos HOTKEYS para establecer los nombres que desees darle al «Job» que representa tu programa. Estos comandos tienen la siguiente forma que incluye la especificación de un tercer parámetro:

ERT HOT_xxx('key','nombre del archivo','nombre del programa')

HOT_xxx puede ser, por supuesto, HOT_RES, HOT_CHP, etc.

El ‘nombre del archivo’ es el mismo que en los ejemplos anteriores. El ‘nombre del programa’ es cualquier nombre razonable que quieras dar al «Job» (o a la tarea). Por ejemplo, si el programa fuera una aplicación de base de datos llamado DATABASE_EXE y quisiéramos darle al «Job» (o a la tarea) el nombre de ‘mydbase’, entonces el comando debería ser este:

ERT HOT_LOAD('D','FLP1_DATABASE_EXE','mydbase')

Una vez que el programa se está ejecutando, verás el nombre de ‘mydbase’ si tecleas el comando JOBS o si has utilizado el menú de tareas del QPAC2. (Una tarea o un «Job» es simplemente un programa en código máquina, uno que se puede iniciar con EXEC, por ejemplo).

A partir de ese momento, podemos definir un HOTKEYS (una tecla de acceso directo) para que elijamos ese programa, por ejemplo así:

ERT HOT_PICK('d','mydbase')

De modo que al pulsar ALT d el sistema busca un programa que tenga el nombre de ‘mydbase’, y si lo encuentra lo traerá al primer plano como programa activo o programa seleccionado.

Aquí dejamos la primera parte de la descripción del sistema HOTKEYS, seguiremos profundizando en la segunda parte de este artículo.

—-
Fuente :
CAUTION: HOTKEYS – Don’t Burn Your Fingers
By David Denham, 1999
QL Today.

—-

La red del Sinclair QL es realmente impresionante a pesar de su antigüedad y muy fácil de usar una vez que te acostumbras a los principios que están detrás de ella.

Como todos los QL tienen dos conectores de red (también las placas Aurora o las QXL), puedes encadenar hasta 63 máquinas en una misma red. Las dos máquinas de los extremos de la red deben tener uno de los dos conectores desconectados. Seguramente éstos tendrán una resistencia o algo parecido para establecer el final de la red cuando no hay un cable conectado. (Es decir, los dos extremos no necesitan conectarse a modo de red circular, esto si es necesario en SERNET y en MIDINET tal como diremos más abajo).

El cableado de la red QL es extremadamente simple. Un cable de dos hilos con conectores de audio mono de 3,5 mm en ambos extremos es todo lo que necesitas para unir dos QL, un cable de altavoces es perfectamente adecuado. Cualquier longitud razonable de cable debería funcionar, aunque no sé cual es la distancia máxima recomendada entre máquinas.

Antes de pensar en usar la red del QL asegúrate de usar Toolkit 2, el uso se hace mucho más simple y divertido. La red básica es usable sin Taoolkit 2, pero es necesario tener Toolkit 2 para aprovechar al máximo la red.

Número de estación.

Para identificar los ordenadores dentro de la red es necesario asignar a cada uno de un número entre 1 y 63. Esto se hace con el comando NET y un número entre 1 y 63 (por defecto el número de estación es la 1 si al comando NET no se suministramos número alguno). Por ejemplo, con el comando «NET 2» asignamos al ordenador la estación número 2 dentro de la red.

En una simple red con 2 estaciones (sólo dos QL conectados entre ellos) ambos ordenadores pueden tener el mismo número de estación. En estos casos la configuración es mucho más simple ya que no haría falta el comando NET ni asignar a cada ellos un número distinto. Como el valor 1 es el defecto, en cada uno de los QL nos referiríamos al otro como estación n1.

En una red con más de dos QL, la numeración de las estaciones no es automática y se debe realizar estación a estación con el comando NET y asignando a cada máquina de la red un número distinto entre 1 y 63. Puede ser una buena estrategia ir numerando secuencialmente las estaciones de la red, pero hay que tener en cuenta que para que una estación actúe como «servidor de dispositivos», el número de dicha estación tienen que estar comprendido entre 1 y 8 (ambos inclusive). Esto implica que en una res QL NET sólo pueden existir 8 servidores de dispositivos.

Tal como acabamos de comentar, una de las facilidades más importantes que nos aporta el Toolkit 2 es que podemos configurar en la red hasta 8 estaciones que actúen como servidores. Esto simplemente se hace con el comando «FSERVE». De forma general las estaciones en las que hemos cargado el job FSERVE pueden compartir con el resto de la red, no sólo su sistema de almacenamiento, sino también impresoras, puerto serie, puerto paralelo (si tienes Super GoldCard), su propia consola, etc.

Algunos ejemplos.

Supongamos que tenemos una red de tres QL (los tres con Toolkit 2) y queremos configurar una red donde queremos que dos de los QL actúen como cliente y como servidor y el último de ellos sólo como estación que consume recursos de los anteriores. Lo que podríamos hacer es configurar la red con los siguientes comandos:

En el QL 1 tecleamos el siguiente comando:

  FSERVE

En el QL 2 tecleamos el siguiente los comandos:

  NET 2
  FSERVE

En el QL 3 tecleamos el siguiente los comandos:

  NET 3

Eso es todo, pero resaltemos algunos detalles:

– En el QL 1 no hace falta especificar un número de estación ya que por defecto el valor de la estación es 1 (el comando NET sólo sirve para especificar el número de estación cuando ésta es distinta de 1).

– Como tenemos dos máquinas actuando como «servidores» de dispositivos, a esas máquinas (QL 1 y QL 2) les tenemos que asignar números de estación comprendidos entre 1 y 8. Al QL 3 le hemos asignado la estación 3, pero podría haber sido cualquier otro número entre 3 y 63.

Una vez configurada la red, pongamos algunos ejemplos de uso. En el QL 3 podríamos teclear los siguientes comandos:

DIR n1_FLP2:
  (Nos mostrará el pantalla el directorio raíz de la segunda disquetera
   de la estación 1). 

DIR n2_WIN1_programas_
  (Nos mostrará el pantalla el directorio WIN1_programas_ 
   de la estación 2). 

COPY win1_boot to n2_PAR             
  (Copiará el fichero boot de la unidad win1_ en la impresora
   paralelo de la estación 2)

COPY win1_boot to n2_SCR
  (Copiará el fichero boot de la unidad win1_ en la consola
   de la estación 2)

WCOPY flp1_games_ to n1_win1_games1_ 
  (Copiará todos los ficheros de la disquetera 1 al subdirectorio
   win1_Games1_ de la estación 1)

OPEN #5, n2_ser1: list #5: close#5
  (Listará el programa que tengamos cargado en memoria en la
   impresora serie de la estación 2)

EXEC n1_win1_games_chess
  (Ejecutará el programa chess desde el subdirectorio win1_games_
   de la estación 1). 

Una caractarística curiosa es que podemos abrir una ventana en la consola de otro usuario, imprimir un mensaje y esperar de él una respuesta. Por ejemplo, Afx (que está en la estación 1) podría ejecutar el siguiente programa para hacer una pregunta a Badaman que está en la estación 2:

10 OPEN #4, n2_con_200x200a0x0
20 INPUT #4, "Hola, aquí afx ¿podemos almorzar juntos?", r$
30 PRINT r$
40 CLOSE #4

Otra versión del mismo programa.

10 ch = FOPEN(n2_con_200x200a0x0): CLS #ch
20 INPUT #ch, "Hola aquí afx, ¿podemos almorzar juntos?", r$
30 PRINT r$
40 CLS #ch: CLOSE #ch

Una configuración interesante dentro de QL NET es hacer uso del sistema de dispositivos por defecto incorporado en el sistema operativo, proporcionado por los comandos DATA_USE, PROG_USE, SPL_USE y DEST_USE.

DATA_USE [nombre]    
  (selecciona el directorio de omisión para ficheros de datos)

PROG_USE [nombre]
  (selecciona el directorio de omisión para programas ejecutables)

DEST_USE [nombre]
  (selecciona el directorio de omisión de destino (COPY, WCOPY)) 

SPL_USE  [nombre]
  (selecciona el spooler de impresión por omisión (SPL))

El uso de estos nombres de directorio por omisión hace nos hace el trabajo bastante más fácil. Por ejemplo, con la siguiente instrucción todos los programas serán cargados por defecto desde el directorio «progs» del disco win1_ de la estación 1 cuando no indiquemos expresamente una unidad de almacenamiento.

PROG_USE n1_win1_progs 

Una vez introducido el comando anterior, podríamos ejecutar cualquier programa ubicado en esta estación de trabajo y subdirectorio simplemente con EXEC y el nombre del programa.

Pongamos otro ejemplo, con la siguiente instrucción se selecciona el dispositivo PAR (puerto paralelo) de la estación 2 como destino del «spooler» de omisión.

SPL_USE  n2_par

Y partir de la línea anterior, podemos imprimir en segundo plano cualquier fichero como el ejemplo siguiente:

SPL flp1_myFile_txt    
  (imprime myFile_txt en el puerto paralelo de la estación 2)

NFS_USE

Además del uso de dispositivos por defecto, podemos también «mapear» rutas de una red a un dispositivo cualquiera, esto lo hacemos con el comando NFS_USE que nos aporta el Toolkit 2. Veámoslo.

Mediante el comando NFS_USE es posible ocultar la red local a las aplicaciones escogiendo un nombre especial para el servidor de ficheros en red local. La sintaxis es la siguiente:

NFS_USE "nombre", "ubicaciones de la red local", ...

Los «nombres de red local» deben ser nombres de directorio completos, pudiéndose dar hasta 8 en un comando. Cada uno de estos nombres estará asociado con uno de los 8 posibles dispositivos de directorio («nombre_1» a «nombre_8»). Pongamos un ejemplo.

NFS_USE mdv,n2_win1_,n2_flp1_,n2_flp2_

La anterior sentencia asigna distintas ubicaciones de la estación 2 que actúa como servidor de ficheros a los dispositivos mdv1_, mdv2_ y mdv3_ de la estación cliente. En el ejemplo, «mdv1_» es asignada a la unidad win1_ en la estación 2, «mdv2_» será tomado como «flp1_» en estación 2 y «mdv3_» será tomado como «flp2_ «también en la estación 2.

Una cosa que también se suele hacer es «reasignar» un nuevo nombre a los dispositivos existentes si queremos «mapear» éstos a otras rutas de la red local. En nuestro ejemplo anterior haríamos lo siguiente:

MDV_USE MDD
NFS_USE mdv,n2_win1_,n2_flp1_,n2_flp2_

De esta manera mantendremos los accesos a las unidades de microdrive como MDD1_ y MDD2_ en lugar de MDV1_ y MDV2_.

El controlador de dispositivos DEV (DEV_USE).

En la primera versión de QDOS no existía la posibilidad de crear subdirectorios reales dentro de un dispositivo de almacenamiento. Debido a esto muchos programas de QL fueron escritos sin tener en cuenta la posibilidad de almacenar archivos en subdirectorios. En la siguientes versiones de QDOS, y por supuesto de SMSQ/E, apareció el soporte a lo que se llaman «nivel 2» del sistema de almacenamiento donde el soporte de subdirectorios es completo. Este «nivel 2» del sistema de almacenamiento se extendió con la (Super)GoldCard, dispositivos de disco duro y unidades de disquete de alta densidad. En este contexto, para facilitar la compatibilidad de los programas antiguos que no daban soporte a los subdirectorios, se creó una extensión que aporta un dispositivo virtual llamado DEV. En si, el dispositivo DEV es un dispositivo genérico por defecto (no sólo acotado al uso de la red local) y es una especie de «engaño» para permitir que el software antiguo (como Quill, Archive, Abacus y Easel) hagan uso de subdirectorios.

Además de lo expuesto anteriormente, y en el contexto que nos ocupa, los dispositivos DEV también tienen la capacidad de «mapear» dispositivos lógicos a rutas reales dentro de la red local.

Como de costumbre, hay hasta 8 dispositivos DEV; DEV1_ a DEV8_. Cada dispositivo DEV está conectado a un dispositivo real particular o a un directorio por defecto particular en un dispositivo real. Los archivos en un dispositivo DEV pueden ser abiertos, usados y borrados de la misma manera que en un dispositivo real.

Cada unidad «DEV» está conectada a un dispositivo mediante el comando DEV_USE. La sintaxis es la siguientes.

DEV_USE NúmeroDisp, DirectorioReal

Pongamos un ejemplo.

DEV_USE 4, n2_win1_sys_

A partir de la introducción de comando anterior podemos hacer referencia al contenido del directorio win1_sys_ de la estación 2 como dispositivo DEV4_ de nuestra estación.

A tener en cuenta que el sistema QDOS y SMSQ/E puede manejar también dispositivos distintos a los dispositivos de almacenamiento. Estos dispositivos son:

SER1 y SER2  (puertos serie RS232)
PAR          (puerto paralelo (sólo a partir de SuperGoldCard))
SCR,         (pantalla como dispositivo de salida)  
CON          (consola como dispositivo de entrada/salida)

Esto significa que podemos mapear una unidad DEV a uno de estos dispositivos. Por ejemplo:

DEV_USE 8, n1_par

La orden anterior asigna la unidad lógica «DEV8_» al puerto paralelo de la estación 1.

Otro ejemplo interesante:

NFS_USE "ser",n1_par, n2_par 
PAR_USE "ser"
COPY_N "flp1_myfile" TO "ser2"

Las líneas anteriores reasignan los identificadores de los puertos serie de mi estación, concretamente, SER1_ se reasigna al puerto paralelo el la estación 1 y SER2_ se reasigna al puerto paralelo de la estación 2.

SERNET y MIDINET

Tanto SERNET como MIDINET son controladores de red que aparecieron posteriormente y te permiten montar redes de bajo costo como la QL NET original del Toolkit 2. SERNET permite conectar dos o más máquinas que ejecutan SMSQ/E a través de los puertos serie, mientras que MIDINET permite conectar dos o más ordenares ATARI con SMSQ/E a través de los puertos MIDI. SERNET fue desarrollado a partir del software MIDINET de Phil Borman. Bernd Reinhardt modificó el software para usar los puertos seriales en lugar de los puertos MIDI.

Con estos controladores podemos ampliar las «fronteras» extendiendo la red QL, por ejemplo, permitiendo que las máquinas sin conectores net 1 / net 2 del QL se unan a la red.

Tanto el SERNET como el MIDINET están organizados como una red circular. En el caso de MIDI, el puerto MIDI OUT de cada máquina tiene que estar conectado al puerto MIDI IN de la siguiente máquina. Todos los cables tienen que formar un círculo completo. Cada máquina en el círculo tiene que estar funcionando y el controlador tiene que cargarse para tener una red en funcionamiento. Lo mismo se aplica a SERNET: con dos máquinas, puede usar un cable de módem nulo. Con tres o más máquinas, debes cablear tus propios cables para que todas las señales de salida de una máquina estén conectadas a las señales de entrada de la siguiente máquina y así sucesivamente, para formar un círculo completo también.

SERNET tiene que configurarse para que sepa qué puerto usar como puerto de comunicación. Como es habitual en muchos programas y controladores de dispositivo del QL esto se hace mediante el uso de MenuConfig para configurar los parámetros dentro del binario del propio controlador (SERNET_REXT).

Una vez configurado podemos cargar el controlador con una instrucción similar a la siguiente (suponemos que el controlador está en el directorio raíz de la unidad win1_.

LRESPR win1_SERNET_REXT

Sernet enlaza los ordenadores a través del puerto serie y utiliza el nombre de dispositivo «S» de forma similar a la «N» para la red QL.

Y por último, una vez cargado el controlador, sólo tenemos que definir el número de estación y activar los servicios de la estación como servidora dentro de la red. Las instrucciones serían como el siguiente ejemplo:

Estación 1:
  SNET_USE 1
  SERNET 

Estación 2:
  SNET_USE 2
  SERNET 

A partir de este momento estas dos estaciones pueden compartir sus recursos. Por ejemplo con la siguiente instrucción en la estación s1.

DIR s2_FLP2_            

Nos mostrará el pantalla el directorio raíz de la segunda disquetera de la estación 2.

Enlazando las dos redes, QLNET y SERNET.

Para finalizar, el último paso de nuestro experimento es configurar un entorno, en el cual puedan convivir dos redes: QL NET y SERNET. Por un lado QL NET nos permitiría conectar QL originales (BBQL) en nuestro entorno, y por otro lado podríamos añadir a esta «red QL» sistemas modernos que tengan disponible al menos un puerto RS232 (por ejemplo el emulador QPC2 en un PC con Windows 10 o la FPGA Q68).

El punto de unión de estas dos redes la hemos resuelto con una combinación hardware-software relativamente reciente. El hardware no es otro que la FPGA Q68 que incluye de serie un puerto RS232 y a la cual se la he aplicado un «modding» para incluir dos conectores QL NET. En cuanto al software, lo único que necesitamos ejecutar en la Q68 es el driver SERNET que hemos mencionado anteriormente y el nuevo driver QLNET de Martyn Hill que te permite conectar en red el Q68 con otras máquinas compatibles con QL a través de los puertos QLNET estándar. Los comandos a incluir en el boot de arranque de la Q68 sólo debe incluir los siguientes comandos:

LRESPR win1_sernet_rext     (Carga el controlador SERNET)
BAUD 115200                 (Establece la velocidad en baudios) 
SERNET 2                    (Establece s2 como número de estación SERNET)
SERNET                      (Activa los servicios SERNET) 

LRESPR win1_ndq68_dvr_v305  (Carga el driver de red QL NET para Q68)
NET 2                       (Establece n2 como estación QL NET) 
FSERVE                      (Activa las funciones de servidor QL NET). 

Descrito todo esto, la primera parte de este artículo seguramente tendrá más sentido.

—-
Fuentes:
– SUPERTOOLKIT II, MANUAL DEL USUARIO (Tony Tebby, Qjump, Reino Unido. 1985).
– The QL Network. QL Today, Volume 9 Issue 4. (David Denham).
– SERNET on QDOS? QL Today, Volume 6 Issue 6. (Dilwyn Jones).
– Announcing availability of a QLNET driver for the Q68 (ND-Q68) (https://qlforum.co.uk/viewtopic.php?f=3&t=2881&p=28393) (Martyn Hill).

El domingo 24 de mayo estuvimos invitados al programa de AmigaWave especial sobre QL, algo que veníamos acariciando largo tiempo, y nos dieron dos horas para contaros todo acerca del QL de hoy, Comienza en el minuto 45.

Nosotros sentimos el QL como algo vivo que sigue evolucionando, y aquí hemos querido contar hasta dónde ha llegado. Hablar del QL original para nosotros es como hablar del PC y contar las bondades o inconvenientes del MS-DOS, obviando los Windows y Linux que hoy día podemos tener instalados en ellos. Para los que tienen un QL «pelado», una única ampliación, la de José Leandro, le cambia la cara a la máquina de forma espectacular, y luego, ya si uno quiere aventuras, pues tiene todo el abanico de ampliaciones posibles y la Q68 (FPGA). El QL no le tiene que gustar a todo el mundo. Es un sistema diferente, con sus cosas buenas y malas, como todos, y que tiene su propia historia.

Espero que lo disfrutéis. Nosotros hemos pasado un rato muy bueno. ¡Feliz día del orgullo friki!

Algunos enlaces de interés:

Emuladores

uQLx http://www.dilwyn.me.uk/emu/index.html#uQLx_for_Linux_etc.
Q-emuLator http://www.terdina.net/ql/q-emulator.html
SMSQmulator https://www.wlenerz.com/SMSQmulator/
QPCII https://www.kilgus.net/

SMSQ/E https://www.wlenerz.com/smsqe/

Documentación

Sinclair QL Recursos en Castellano https://sinclairql.es
QBlog https://sinclairqles.wordpress.com/
QReino https://www.qreino.es/

Dilwin Jones (inglés) http://www.dilwyn.me.uk/

Foros

Speccy.org https://foro.speccy.org/viewforum.php?f=15

Retrowiki http://retrowiki.es/viewforum.php?f=98

QLForum (inglés) https://qlforum.co.uk/

Noticias

Sinclair QL Planet (inglés) https://badaman.badared.com/ql/planet/