8 de Febrero, 2015

Hola mundo 6502

Ayer pude ejecutar mi primer programa en código para el 6502 en mi proyecto. El programa lo escribí en ensamblador y se puede compilar con CC65.

; hello.s
; Hello World example for D64 using syscalls
;
.segment "CODE"

.macro  sys         ; syscall
.byte   $02
.endmacro

main:
        tsx         ; save the stack pointer
        lda #>message
        pha
        lda #<message
        pha
        lda #$11    ; put string
        sys
        txs         ; restore the stack

        lda #$00    ; terminate program
        pha         ; also: success (0)
        sys

        jmp *       ; never gets here

message:
        .asciiz "Hello world from 6502!"

Mi máquina virtual que ejecuta código del 6502 tiene una configuración estándar para este tipo de CPU, con el siguiente mapa de memoria:

0x0000 - 0x00ffZero page
0x0100 - 0x01ffStack
0x0200 - 0x19ffVídeo
0x1a00 - 0xffffPrograma

No sé todavía si intentaré ejecutar programas existentes para esta CPU porque normalmente dependerán de un interfaz que cambia con la máquina que lo usa (no es lo mismo un Commodore 64 que un Appel II), pero sí quería ser lo más fiel posible al diseño del 6502 para poder usar compiladores existentes sin mucho trabajo.

Además está claro que los programas que ejecute estarán compilados expresamente para mi máquina, así que puedo añadir una instrucción extra para usar funciones de la máquina virtual implementadas en código nativo del ATmega328p (¡más rápido!).

La instrucción extra es SYS (de syscall, o llamada al sistema) que usa el opcode 0x02 (que es una operación ilegal en el 6502), y el intefaz es sencillo: la función se indica en el acumulador, los parámetros en la pila, y es el origen el responsable de desapilar (porque la función puede devolver valores usando la pila). Más o menos es el mecanismo que usa FreeBSD (Linux usa registros para los parámetros, y el 6502 solo tiene tres, así que no es práctico).

En el hola mundo estoy usando dos funciones: imprimir una cadena de texto acabada en un cero (función 0x11) y terminar programa (función 0x00).

Aún quedan muchas cosas por hacer, pero este era un paso importante en el proyecto. El resultado se puede ver en este vídeo.

Hay 0 comentarios, anotación clasificada en: avr, arduino.

31 de Enero, 2015

»Algunos cálculos · Al generar vídeo compuesto (PAL) hay que procesar una linea (scanline) cada 64 µs, 312.5 lineas por cuadro y 50 cuadros por segundo (en vídeo ¿desentrelazado?, en realidad son 625 lineas cada a 25 Hz). El microcontrolador del Arduino trabaja a 16 MHz, y tenemos unas 52 lineas desde que la sincronización vertical empieza hasta que toca dibujar. La sincronización vertical tiene un coste de unos 10 µs, así que nos quedan unos 2.2464 MHz libres para hacer cosas aparte de dibujar la pantalla. No es mucho, ¿verdad? :(

Hay 0 comentarios, anotación clasificada en: avr, arduino.

27 de Enero, 2015

La arquitectura Harvard

Una de las características de la familia de microcontroladores AVR de Atmel es que siguen una arquitectura Harvard modificada.

Esto es muy importante porque en la arquitectura Harvard los datos y el código se acceden vía buses diferentes. El microcontrolador (MCU de ahora en adelante) lleva incorportadas tres tipos de memoria:

  • Flash: contiene el código ejecutable, y el MCU no puede ejecutar código desde otro tipo de memoria. Esta memoria se puede re-escribir (lentamente), y mantiene su contenido cuando no hay electricidad (esto es: no volátil). Gracias a ser una arquitectura Harvard modificada se puede leer esta memoria como si fueran datos (aunque es algo más lento que la SRAM).
  • SRAM: memoria estática volátil.
  • EEPROM: memoria solo lectura que se puede re-escribir en determinadas condiciones.

Así que un microcontrolador no puede cargar código a memoria externa y ejecutarlo; no ha sido diseñado para trabajar así (ese funcionamiento hace referencia a una arquitectura Von Neumann).

Parece que mucha gente empezando con Arduino no termina de enterarse de este detalle hasta que es algo tarde, y es fuente de bastantes confusiones.

Es por esto que una de las partes de mi proyecto para aprender electrónica necesita implementar un intérprete o máquina virtual para poder ejecutar los programas que pretendo cargar en memoria externa.

¿Qué opciones tengo? Bueno, hay que recordar las características del MCU. Estoy trabajando con un Arduino Uno que viene con un ATmega328p, que nos proporciona:

Flash: 32 KB (programa, datos)
SRAM: 2KB (memoria lectura/escritura)
EEPROM: 1KB (memoria solo lectura)

Y además... con un cristal que nos da una velocidad de 16MHz (se puede llegar a 20MHz, pero no podría seguir usando la comodidad de usar el Arduino como placa de desarrollo), y con muchas cosas que hacer al mismo tiempo :S.

Así que el tema es complicado, no solo por los 2048 bytes de memoria :D, sino porque lo que sea... tiene que entrar en 32KB de código (incluyendo el driver de vídeo, del teclado, etc).

Es cierto que estoy usando 64KB de SRAM externa (por ahora solo como memoria de vídeo, 256x192 en monocromo ya son 6144 bytes que no caben en el Arduino), pero no puedo usarla cuando estoy refrescando la pantalla, así que no es todo lo rápido que se podría esperar.

Llevo un par de semanas dándole vueltas, saltando desde la idea de hacer un intérprete de BASIC a la idea de implementar una máquina virtual sencilla (el 6502 parece sencillo, y existen compiladores cruzados), pero todavía no tengo nada decidido. Lo que no se puede negar es que estoy aprendiendo muchas cosas nuevas ;).

Hay 0 comentarios, anotación clasificada en: avr, arduino.

24 de Enero, 2015

»El teclado funciona · Aún queda bastante trabajo hasta tener un controlador de teclado que haga todo lo que tiene que hacer (en realidad se trata de implementar diferentes capas que normalmente se encuentan en el sistema operativo), pero ya se puede introducir texto con un teclado PS2. En esa demo se siguen usando los componentes que ya estaban "listos" (video generado desde la SRAM externa, etc).

Hay 0 comentarios, anotación clasificada en: avr, arduino.

17 de Enero, 2015

»¡Video bajo control! · O eso parece al menos viendo mis resultados capturando con EasyCap, que es una capturadora de vídeo USB. Parece que la tele de 15" que tengo para pruebas es más permisible cuando el vídeo generado no es muy bueno, pero esa misma señal no funcionaría en la capturadora. Ahora que la señal es suficientemente buena para EasyCap, es bastante cómodo tener la salida en una ventana (por ejemplo, con VLC); aunque es cierto que si no hubiera tenido la tele seguramente no hubiera llegado a generar nada visible ;).

Hay 0 comentarios, anotación clasificada en: avr, arduino.

12 de Enero, 2015

Video compuesto con Arduino Uno, desde SRAM externa

Este pasado fin de semana le eché un rato al tema y decidí empezar desde cero, más que nada porque no entendía el código que estaba usando y eso me impedía seguir adelante con el proyecto.

He encontrado bastante documentación, y ha sido cosa de leerla hasta entender cómo funciona PAL:

He repetido con la idea de usar SPI para enviar bytes a 8MHz (lo más rápido que se puede con el micro a 16MHz), y consigo salida de vídeo 32x24 en blanco y negro.

En mis pruebas he podido llegar a 40x24 caracteres, pero es un poco extremo para el microcontrolador y al final he decidido quedarme en 32x24 caracteres (que es la resolución del Spectrum, ¿casualidad?). Estoy usando code page 437, que es la codificación de caracteres para DOS; en una fuente bitmap de 256 caracteres, 8x8 pixeles.

En el ejemplo estoy usando un "modo texto", con lo que solo necesito 768 bytes de memoria de video (1 byte por caracter para saber los 8 bytes de nuestra fuente hay que mandar a la memoria de vídeo).

Para soportar gráficos, aunque sea con tiles, debería almacenar 6144 bytes de memoria de vídeo, así que decidí probar una experimento que consiste en usar memoria externa SRAM.

Estoy usando 23LCV512 de Microchip, que es bastante más de lo que necesito (64KB), pero tiene la ventaja de soportar SPI y además 5.5v (Microchip tiene chips de 32KB, pero funcionan a 3.3v, y no se pueden usar con las señales del Arduino a 5v).

La idea básica es escribir en la SRAM la memoria de vídeo, y al leer la memoria de nuevo, la salida de la SRAM iría a parar al DAC para generar la señal de vídeo.

El microcontrolador sigue generando los pulsos de sincronización y dirige el envío de datos (hay que enviar un byte desde el microcontrolador por cada byte que sale de la SRAM), pero podemos manejar mucha más memoria de vídeo a la misma velocidad: usando SRAM externa como memoria de vídeo.

El "problema" que tengo ahora es que la SRAM gestionada con SPI es muy lenta, y usando el interfaz SPI no podemos estar actualizando la pantalla y actualizando la memoria de vídeo al mismo tiempo, y en las 310 lineas de PAL que tenemos antes de empezar a dibujar (cada una es solo 64µs), no da tiempo a escribir gran cosa en la memoria de vídeo (un caracter son 8 bytes no consecutivos y SPI es muy lento: seleccionar el chip, enviar WRITE, enviar la dirección de 16-bits, enviar datos, deseleccionar el chip).

Tengo varias ideas para probar y creo que me estoy acercando a un diseño que puede valer. En ese momento publicaré esquemas y puede que algo de código.

Hay 0 comentarios, anotación clasificada en: arduino, avr.

4 de Enero, 2015

»Vídeo compuesto con Arduino Uno · Estoy haciendo experimentos generando vídeo con Arduino Uno (Atmega328p a 16MHz). La librería Arduino TV Out es genial, pero hace más cosas de lo que quiero (usa más memoria, en general) y me gustaría conseguir más resolución. He probado con esta técnica (usando el interfaz SPI para ir más rápido), y tras portar el código a AVR C contemporáneo (tal cual no compila), consigo los 38 x 20 caracteres de texto, que es más bien lo que tenía en mente. La idea de Serasidis es interesante, pero no queda tiempo para mucho más (y además nos deja sin SPI).

Hay 0 comentarios, anotación clasificada en: arduino, avr.

26 de Diciembre, 2014

»¿Y ahora qué? · Pues en realidad... poca cosa. Valga esta entrada corta como respuestas a preguntas frecuentes ;). Seguiré programando juegos, incluso participando en alguna jam, pero desde luego que no será uno al mes. Tampoco estoy seguro que serán juegos más grandes, porque esas cosas no se me dan bien. Puede que repita para el ZX Spectrum, puede que no.

Aparte estoy volviendo a la carga con mi idea de aprender electrónica, que dejé apartada hace un par de años porque soldar algunos componentes en superficie se me hacía cuesta arriba, pero... ¡ya sabemos soldar! (un poco), así que parece que la cosa vuelve a avanzar. Iremos comentando los progresos ;).

Hay 1 comentario

16 de Diciembre, 2014

»One Game a Month · Anoche escribí mi post-mortem de one game a month (en inglés). Traduciendo las conclusiones:

El reto 1GAM ha sido intenso y duro, muy duro. He aprendido muchas cosas nuevas y he acabado 12 juegos. Eso es parte del reto: acabar proyectos. Es posible que haya cometido los mismos errores una y otra vez, pero perseverar es lo importante.

Hay 0 comentarios, anotación clasificada en: 1gam.

14 de Diciembre, 2014

Micro INC

Ya está, he finalizado mi reto de un juego al mes durante 2014; algo antes porque se acercan las vacaciones y no tendré mucho tiempo libre para programar :).

El último juego de la serie es Micro INC, otro juego tipo puzzle en la categoría match-3.

Pantalla del juego

La idea no es muy excitante, pero como acabé completamente agotado con el juego anterior, y dado que tenía unas dos semanas para hacer el juego (que al final ha sido una semana solo), no tenía más remedio que ir a por un objetivo relativamente sencillo. Al final el juego no está mal del todo y se deja jugar, aunque no sea muy original.

Intentaré escribir un post-mortem de la experiencia que ha sido programar un juego cada mes, pero eso será más adelante :).

Hay 0 comentarios, anotación clasificada en: programming, 1gam, speccy.

Entradas antiguasEntradas nuevas