Artículo
publicado en el año 2021, en el número 3 de la revista
electrónica ATDT
Introduccion
Hace poco mas de 1 año, mas precisamente en febrero de
2020, comenzaba un pequeño experimento que se convirtio
en un proyecto que tuvo varios logros tecnicos
interesantes.
Retroterm es una terminal para Commodore 64, pero es una
terminal muy particular. Conectandose a un BBS estandar
es una terminal muy simple, que solo tiene envio y
recepcion de texto. Pero cuando se conecta a un BBS
especial, es capaz de hacer streaming de audio PCM
(digitalizado) con una calidad de 4 bits y un muestreo
de 11520 Hz, mostrar imagenes en 16 colores, o recibir
bloques de datos a maxima velocidad, para por ejemplo
descargar programas directamente a memoria RAM. Todo
esto es posible gracias a que Retroterm funciona siempre
a una velocidad de 57600 bps, y a un protocolo propio
que llamamos TURBO56K.
Commodore 64, procesadores y RS232
Pero volvamos al inicio. Cuatro años antes de la primera
version, en 2016, habiamos logrado enviar y recibir por
RS232 a 57600 bps, y enviar a 115200 bps. Para poner
esto en contexto, la Commodore 64 es una computadora de
1982, con 64K de memoria RAM y un procesador compatible
con el MOS 6502, corriendo a una velocidad de 1 MHz.
Analicemos esto. Un procesador hace todo al ritmo de una
señal de reloj que le marca la velocidad de ejecucion.
Cada operacion que realiza el procesador esta
sincronizada con ese reloj, y tener un reloj de 1 MHZ
implica que hay 1 millon de ciclos de reloj por segundo.
La mayoria de las instrucciones de este procesador se
ejecutan entre 2 y 4 ciclos de reloj. Suponiendo que las
instrucciones usaran 3 ciclos de reloj, esto
significaria que en 1 segundo podriamos ejecutar 1000000
de ciclos / 3, esto es 333333 instrucciones.
Y por que es importante esto? Veamos. 57600 bits por
segundo no parece mucho, uno pensaria que con un
procesador de 1 MHz podria manejarlo sin problemas. Pero
resulta que la Commodore 64 no tiene un chip encargado
del puerto RS232, entonces debe hacer tanto el envio
como la recepcion por software. En RS232 se envian bytes
en serie, un bit tras otro, donde cada bit tiene una
duracion exacta. Para recibir este byte, el procesador
debe detectar la llegada del dato, y empezar a
temporizar la duracion de cada bit, leyendo desde el
puerto cada uno de los bits en el momento exacto, y
almacenandolos en memoria hasta completar el byte. Esto
significa que el procesador debe estar dedicado a leer
los bits desde el puerto serie, mientras se mantiene
sincronizado con esos datos, por lo que en principio no
puede hacer nada mas.
Ahora volviendo a la velocidad, a 57600 bits por segundo
cada bit dura 17 ciclos de reloj, lo cual deja ejecutar
al procesador un promedio de casi 6 instrucciones por
bit. Este numero sale de dividir 1 millon de ciclos de
reloj que hay en 1 segundo, por 57600 bits que se pueden
enviar en ese mismo tiempo, esto es 1000000 / 57600 =
17,361 ciclos de reloj por bit. Ahora 1 MHz ya no parece
tanto. Sin embargo, a pesar de que el procesador tiene
el tiempo justo para recibir los datos, todavia puede
manejarlo sin problemas. La dificultad esta en que los
datos pueden llegar en cualquier momento, y esto impide
que el procesador pueda hacer otras tareas, ya que
siempre debe estar atento a la llegada de un byte.
Terminales, velocidad y recepcion
Ademas de enviar y recibir datos por el puerto serie,
una terminal debe como minimo leer el teclado e imprimir
en pantalla. Es necesario encontrar una manera de poder
realizar todas esas tareas repartiendo el tiempo de
procesador disponible. Algunas terminales realizan el
envio y recepcion "en simultaneo" con el resto de las
funciones, pero esto limita la comunicacion a un maximo
de 1200 o 2400 bps, ya que por encima de estas
velocidades la perdida de precision es muy grande. Otro
metodo consiste en modificar ligeramente el cableado de
los modems para usar asistencia de hardware tanto en
envio como en recepcion, pero esto solo funciona a 9600
bps y debe tener soporte especifico tanto del modem como
de la terminal. El metodo que elegimos para Retroterm es
el de la dedicacion exclusiva a la comunicacion, esto
es, que durante el envio y la recepcion el procesador no
hara otra cosa, lo que nos permite alcanzar los 57600
bps. Pero para lograr esto, tenemos que poder elegir el
momento en que enviamos y recibimos, y la solucion es
usar las lineas RTS y CTS del RS232. La funcion original
de RTS y CTS no era la misma que en la actualidad, ya
que eran señales pensadas para la comunicacion entre DTE
(computadora) y DCE (modem). Desde la decada de 1990
estas lineas se usan para la comunicacion entre
terminales. Hoy RTS es usada por la terminal para
indicar a la otra parte que esta lista para recibir
datos, y en caso de no poder recibir, simplemente
desactiva RTS. De esta manera, ya tenemos el mecanismo
para controlar cuando llegan los datos, pero ahora
debemos decidir cuando nos conviene recibirlos.
Muchas de las computadoras de la decada de 1980 estaban
diseñadas especificamente para un sistema de television,
ya que se pensaron para conectarse a un televisor en la
mayoria de los casos. De estas maquinas, algunas tenian
memoria de pantalla independiente de la RAM principal, y
otras tenian la memoria de video compartida con la RAM
del procesador. La Commodore 64 pertenece a estas
ultimas, tiene un chip de video que puede acceder a 16K
de memoria principal para almacenar los datos de
pantalla, sean graficos o texto. Si bien esto tiene
algunas ventajas, tambien tiene la desventaja de que el
procesador y el chip de video compiten por el uso de la
memoria. Cuando el chip de video debe generar una
imagen, algo que hace 50 o 60 veces por segundo
dependiendo del sistema de TV, debe detener al
procesador para poder leer los datos de texto o
graficos, ya que no pueden acceder ambos
simultaneamente. Esto ocurre varias veces durante la
generacion de la imagen, excepto cuando se esta
dibujando alguno de los bordes de la pantalla, o cuando
se deshabilita la generacion de video. Ya que durante
los bordes el procesador puede estar seguro de no tener
interrupciones por parte del chip de video, elegimos
comenzar la recepcion de datos apenas empieza a
dibujarse el borde inferior de la pantalla. De esta
manera, ya tenemos como indicar que estamos listos para
recibir datos, y tenemos decidido cuando recibirlos.
Primeras versiones y velocidad en modo normal
La primera version de Retroterm fue un ejecutable de 626
bytes, de los cuales los dos primeros bytes son la
direccion de carga, y del resto, 122 estan sin usar, ya
que corresponden al codigo de streaming de audio PCM que
aun no estaba habilitado. En esta version se definio la
estructura basica del programa, que con algunas
variaciones aun se mantiene. Una parte del codigo se
ejecuta sincronizado con el chip de video, el cual
permite disparar una interrupcion en una linea de video
determinada. Ya vimos que nos convenia comenzar la
recepcion cuando se empieza a dibujar el borde inferior
de la pantalla, por lo que configuramos el chip para
dispararla en la linea 251. En esta rutina de
interrupcion, se recibe 1 byte, se envia 1 byte, se
ingresa cualquier byte recibido a un buffer de
impresion, se envia cualquier caracter leido desde el
teclado, se procesa el parpadeo del cursor, y se termina
llamando a la rutina de la ROM encargada de leer el
teclado. En el programa principal, un bucle infinito se
encarga de imprimir cualquier caracter ingresado al
buffer. Tanto la lectura del teclado como la impresion
en pantalla se hacian con codigo propio de la ROM del
sistema.
Una caracteristica distintiva de Retroterm que tambien
se ejecuta durante la interrupcion es el sonido de
impresion en pantalla, que es un
homenaje a la pelicula War Games.
En este punto, ya teniamos una terminal basica capaz de
comunicarse a 57600 bps usando RTS/CTS, pero enviando y
recibiendo solo 1 caracter por cuadro de video, es decir
50 o 60 caracteres por segundo dependiendo del sistema
de TV de la maquina. Si tenemos en cuenta que cada byte
se compone de 10 bits (start, 8 bits de datos, stop), 50
caracteres por segundo seria equivalente a una velocidad
constante de 500 bits por segundo. Ya que la velocidad
mas usada en la Commodore 64 para modems modernos es de
1200 bps, elegimos recibir 3 caracteres por cuadro, lo
que nos da una velocidad equivalente a 1500 bps en PAL y
1800 bps en NTSC, suficiente para superar los 1200 bps.
Estos numeros salen de multiplicar 3 caracteres por
cuadro x 50 cuadros por segundo en PAL x 10 bits por
byte, que nos da 1500 bps. En NTSC el calculo seria: 3 x
60 x 10 = 1800 bps. Como Retroterm se penso como un
cliente donde en principio no se envian grandes
cantidades de datos, la transferencia no es simetrica,
siendo menor la velocidad de envio, que sigue siendo de
50 caracteres por segundo en PAL (equivalente a 500 bps)
y de 60 cps en NTSC (equivalente a 600 bps).
El protocolo TURBO56K entra en escena
Como ya explicamos, en la Commodore 64 tenemos la
desventaja de que el procesador sea interrumpido por el
chip de video durante la generacion de la imagen, lo
cual nos obliga a tener que hacer la recepcion durante
el dibujado del borde. Pero que pasaria si pudieramos
evitar esto? Podriamos disponer del 100% del tiempo del
procesador para recibir bytes en una transferencia
continua. Y que tan alta podria ser esta transferencia?
Veamos. A 57600 bps estariamos recibiendo 5760 bytes por
segundo, si quisieramos recibir 64 Kbytes de datos (la
cantidad total de memoria RAM que tiene la Commodore
64), podriamos hacerlo en 65536/5760 = 11,37 segundos.
Esta seria la velocidad maxima teorica, sin pausas entre
bytes. Ahora empiezan a verse las ventajas de trabajar
siempre a 57600 bps, pero para lograr esto deberiamos
eliminar la interferencia del chip de video, y esto solo
es posible deshabilitando la generacion de la imagen, es
decir, tendriamos que quedarnos sin video.
La primera decision que se tomo fue que Retroterm
tuviera dos modos de operacion, el que vimos hasta ahora
seria el modo normal, con 1 caracter enviado y 3
caracteres recibidos por cuadro. El otro modo de
operacion seria el modo turbo, donde se apagaria la
pantalla y se alcanzaria una transferencia maxima. Habia
que encontrar una manera de seleccionar el modo de
operacion, y la solucion fue crear un protocolo que
permitiera la navegacion en BBS PETSCII (con el juego de
caracteres de la Commodore 64) y a la vez posibilitara
activar funciones especiales de la terminal.
Despues de analizar el juego de caracteres, se eligio
reservar el codigo 255 para entrar a modo comando, por
ser un caracter duplicado y por lo tanto no utilizado.
Si la terminal recibe un caracter con ese valor,
automaticamente entra en modo comando, y comienza a
interpretar los bytes como comandos y parametros. Si
estando en este modo recibe un byte de valor 254,
volvera al modo normal, y comenzara a imprimir en
pantalla el texto recibido.
Comandos, parametros y modos de video
El primer comando implementado fue la transferencia de
un bloque de bytes directo a memoria, en principio para
poder mostrar pantallas graficas (bitmaps), ya que
Retroterm no iba a ser una terminal, sino un programa
para hacer presentaciones controladas remotamente. Ese
es el origen de la orientacion multimedia de la
terminal.
Para mostrar una imagen son necesarias 2 o 3
transferencias dependiendo del modo bitmap elegido, que
puede ser multicolor (3 transferencias) o alta
resolucion (2 transferencias), y luego configurar el
chip de video para activar el modo de video
correspondiente. Esto llevo a agregar 3 nuevos comandos,
uno para activar la pantalla de alta resolucion, otro
para activar la pantalla multicolor, y otro para volver
al modo texto.
El comando de transferencia originalmente requeria 4
bytes de parametros indicando la direccion de inicio en
la memoria donde se almacenaria el bloque de bytes
transferido, y otros dos bytes indicando la cantidad de
bytes a recibir. Con el tiempo esta operacion se dividio
en etapas, un comando que indicaria la direccion
inicial, que quedaria almacenada como un puntero interno
de la terminal, y otro comando que indicaria la cantidad
de bytes a transferir e iniciaria la transferencia.
Durante la transferencia se apaga automaticamente la
pantalla, y se vuelve a habilitar al finalizar. De esta
manera pueden convivir un modo de texto con una
transferencia razonable, y un modo de transferencia
rapida con la pantalla apagada por unos segundos.
Los comandos que seleccionan el modo de video tienen
como parametros los colores de fondo y borde de la
pantalla, por lo que no estamos limitados
a una terminal con texto sobre fondo negro.
Pensando en el futuro, se agregaron comandos
alternativos para ajustar el puntero a memoria para las
transfencias, sin especificar direcciones absolutas.
Esto se hizo para apuntar a las 3 areas de memoria que
maneja el chip de video: la memoria de texto, la memoria
de color, y la memoria de bitmap. De esta manera nos
independizamos de la implementacion de la terminal, ya
que la pantalla puede tener una direccion diferente en
distintas maquinas (una Commodore 128 en modo nativo,
por ejemplo), y nos abre la posibilidad de implementar
varias paginas de texto en el futuro.
Y por supuesto, el uso mas evidente de los comandos de
transferencias es la descarga de programas directamente
a memoria. Esto tiene la ventaja de poder ejecutar el
programa descargado simplemente saliendo de la terminal,
siempre que el programa no haya sobreescrito el espacio
de la misma.
Streaming de audio PCM, la transferencia llevada al
limite
Originalmente las transferencias de datos se hacian con
la maxima transferencia posible, pero esto apenas dejaba
tiempo para procesar el byte recibido, almacenarlo en
memoria, incrementar el puntero y decidir si se habia
transferido la cantidad de bytes especificada. Todas
esas tareas debian realizarse entre la recepcion del
ultimo bit y el comienzo del siguiente byte. Recordemos
que no habia pausas entre bytes. Debido a esta
dificultad y a algunos errores de recepcion ocasionales
se decidio hacer una transferencia byte por byte
activando y desactivando RTS. Esto hizo muy seguras las
transferencias pero tambien ligeramente mas lentas que
el maximo teorico.
La maxima transferencia posible de 5760 bytes por
segundo hizo que surgiera la pregunta: y si transferimos
audio digitalizado directamente al chip de sonido? 5760
bytes por segundo nos daria una calidad de 5760 Hz,
insuficiente para musica pero suficiente para
representar la voz. Si pudieramos recibir un byte y
colocarlo inmediatamente en la salida de sonido antes de
que llegue el siguiente, tendriamos una transmision en
vivo de audio digitalizado. En poco tiempo, luego de
crear una rutina de recepcion especifica para esa
funcion, se logro ajustar la temporizacion para recibir
el audio correctamente. El audio PCM es el que conocemos
como audio digitalizado, donde se representa el sonido
con muestras de determinada calidad. Por ejemplo el
audio de un CD tiene una calidad de 16 bits, con un
muestreo de 44100 Hz, es decir que en un segundo de
audio hay 44100 muestras, cada una representada por 2
bytes. El metodo mas comun que usa la Commodore 64 para
reproducir audio PCM es colocar cada muestra en el
control de volumen, que tiene 16 niveles, esto es, un
volumen de 4 bits. Si enviamos 5670 bytes por segundo,
cada una de esas muestras debe colocarse en el volumen
luego de recibidas. Pero si el volumen es de 4 bits,
estamos desperdiciando la mitad de cada byte.
El siguiente experimento fue compactar el audio de
manera de almacenar 2 muestras de 4 bits por byte, lo
cual duplicaba la transferencia, ya que ahora
transferiamos el doble de datos. Esto hizo que la
cantidad de muestras por segundo aumentara a 5760 x 2 =
11520. Que significa esto? Que ahora podiamos enviar
audio en vivo a una calidad de 4 bits y con un muestreo
de 11,5 KHz, exagerado para la voz y suficientemente
razonable para que la musica sea reconocible.
Ahora no solo habia que lograr recibir un byte, sino que
durante la propia recepcion habia que colocar 2 muestras
en la salida de sonido, una al empezar el byte y otra
por la mitad, de manera de tener un muestreo mas o menos
estable. Si bien requirio muchas pruebas y ajustes, esto
tambien se logro sin detener en ningun momento la
recepcion, que ocurre con la maxima transferencia
posible, sin pausas entre bytes.
Conclusion
Retroterm, como dije varias veces, fue un pequeño
experimento que se salio de control. Hoy es un proyecto
que genero una terminal multimedia, un nuevo tipo de BBS
para aprovechar esas caracteristicas, y un protocolo que
continuamente se sigue actualizando. Al momento de
escribir esto tenemos en las etapas finales de
desarrollo una nueva version de la terminal y otra del
BBS, con su correspondiente ampliacion del protocolo
TURBO56K. La nueva version abandona las rutinas de
impresion del sistema, implementando codigo propio. Esto
se hizo para poder definir una ventana de texto que
limite la region de pantalla donde se puede imprimir.
Hay comandos para definir estas ventanas, y ahora la
terminal tiene la capacidad de trabajar en pantalla
dividida, mostrando en la parte superior una imagen
grafica y en la inferior un texto, con el limite
divisorio definible por comando. Tambien se agrego un
comando para un nuevo tipo de streaming que envia en
vivo los valores a colocar en los registros del chip de
sonido, para poder reproducir musica ".sid" sin tener
que descargarla a memoria.
Cuando comence esto como un simple experimento, pense
que no pasaria mucho tiempo antes de perder el interes y
pasar a otro proyecto, pero un año despues todavia
surgen ideas interesantes para probar. Tambien hay que
decir que las cosas podian haber salido mal desde el
principio, y tal vez este proyecto no habria llegado muy
lejos. En el camino se fue sumando gente para las
pruebas, para poner los BBS en linea, y para la
programacion, tanto de la terminal como del BBS. Hace
mucho tiempo que este proyecto dejo de ser el trabajo de
una sola persona.
Y en el futuro, cuando no haya mucho mas que explorar en
una C64, puede que haya versiones para otras
plataformas, muy probablemente Commodore 128, y puede
que hasta maquinas tan diferentes como las MSX.
|