Mediante esta página pretendo dar a conocer algunos de mis proyectos de programación con el MSX
El compilador SDCC es un compilador cruzado para pequeños dispositivos, que se ejecuta tanto en Windows como en Unix/Linux y que permite generar código para una gran variedad de plataformas de 8 y 16 bits. Entre las plataformas que soporta se encuentra el Z80 y el Z80 con las extensiones de GameBoy (GBZ80).
El código Z80 que genera este compilador por defecto no está destinado para ser ejecutado en un MSX y la salida que genera es un fichero en formato IntelHex. Mediante el uso de este backend para MSXDOS conseguiremos que los ficheros de salida sean fácilmente convertibles a .COM. Los requisitos del sistema Windows o Unix/Linux donde vayamos a realizar la compilación son:
Ambas herramientas pueden ser instaladas tanto en forma binaria como partiendo de los fuentes y compilándolas. Los ficheros básicos para genererar código compatible MSXDOS mediante el SDCC son los siguientes:
main (int main(char **argv, int argc)) y que añade un poco de overheadin y out para facilitar la compatibilidad con código Hitechmemcpy y memsetLo primero que debemos hacer es ensamblar los ficheros .s anteriores mediante el ensamblador sdasz80 y compilar los ficheros .c anteriores con el sdcc incluido en el paquete SDCC:
$ sdasz80 -o crt0msx_msxdos.s ó $ sdasz80 -o crt0msx_msxdos_advanced.s$ sdasz80 -o putchar.s$ sdasz80 -o getchar.s$ sdasz80 -o dos.s$ sdasz80 -o dos2.s$ sdasz80 -o interrupt.s$ sdasz80 -o ioport.s$ sdasz80 -o keyboard.s$ sdasz80 -o vdp.s$ sdcc -mz80 -c -o conio.rel conio.c$ sdcc -mz80 -c -o heap.rel heap.c$ sdcc -mz80 -c -o mem.rel mem.cDespués de esta operación obtendremos 11 ficheros objeto con extensión .rel y con el mismo nombre que los originales. Para hacer una pequeña prueba partimos de un fichero fuente de ejemplo ej.c:
#include "conio.h"
#include "dos.h"
void main(void) {
puts("Hello, world :-)\r\n");
exit(0);
}
Compilamos de la siguiente manera:
$ sdcc -mz80 --code-loc XXXX --data-loc 0 --no-std-crt0 crt0msx_msxdos.rel putchar.rel getchar.rel dos.rel conio.rel ej.c
Nótese el parámetro --no-std-crt0 que le indica al compilador que no utilice el código de inicialización (startup) que trae por defecto para el Z80, sino que nosotros suministramos el nuestro por línea de comandos. XXXX le indica al compilador la localización del código (si usamos crt0msx_msxdos.s XXXX = 0x0107 y si usamos crt0msx_msxdos_advanced.s XXXX = 0x0178). Las variables globales serán alojadas justo a continuación del código.
Si no hay errores de compilación, entre los ficheros resultantes habrá uno llamado ej.ihx, el cual pasaremos por parámetros a la utilidad hex2bin para que lo convierta a binario:
$ hex2bin ej.ihx
Después de esta sentencia tendremos en el directorio actual un fichero ej.bin que podremos renombrar sin problemas a ej.com y ejecutarlo en el MSXDOS.
$ mv ej.bin ej.com
#include "types.h"
#include "mem.h"
#include "dos.h"
#include "vdp.h"
uint8_t scratch[128];
uint8_t ge5_load(char *file_name, uint8_t vramh, uint16_t vraml) {
fcb f;
uint8_t i;
memset((uint8_t *) &f, 0, sizeof(fcb));
f.record_size = 128;
f.drive = 0;
memcpy(f.name, file_name, 11);
if (open(&f) != 0)
return 0;
vdp_set_write_address(vramh, vraml);
for (i = 0; i < 213; i++) {
if (block_set_data_ptr(scratch) != 0)
return 0;
if (block_read(&f) != 0)
return 0;
if (i == 0)
vdp_load_screen(scratch + 7, 121); // to skip GE5 header
else
vdp_load_screen(scratch, 128);
}
close(&f);
return 1;
}
int main(void) {
vdp_set_screen5();
ge5_load("EXAMPLE GE5", 0, 0x0000); // load at visible VRAM
getchar();
vdp_set_text();
exit(0);
}
main (crt0msx_msxdos_advanced.s).main.interrupt.h actualizado para versiones recientes de SDCC. Gracias a Jan P. Schümann.memcpy, memset, algunas rutinas VDP y un ejemplo de acceso a ficheros.files.s y files.h ya que la función lseek no tenía los parámetros en el orden lógico. Ahora ya cumple con la recomendación POSIX.out(dirección, dato) y in(dirección).read y write de files.h de "unsigned int" a "int" para poder detectar valores negativos.main y arreglado el bug que afectaba a la inicialización de variables globales.La diferencia entre hacer ROMs y ficheros COM en MSX con SDCC radica, básicamente, en el fichero crt0. Recomiendo la lectura de la sección anterior.
En la web de Nerlaska (que recomiendo) hay información abundante sobre este asunto a la que iremos aportando tanto yo como Alberto Orante código fuente e información adicional. Por ahora dejo una modificación hecha por Alberto de las rutinas de interrupción de MSXDOS para que funcionen en ROMs.
A continuación se muestra un sencillo proyecto para crear ficheros .CAS (escribibles en un cassette y cargables desde BASIC). La principal diferencia con los anteriores es, de nuevo, el fichero crt0:
.module crt0msx
.globl _main
.globl _vblank_isr
.area _HEADER (ABS)
.org 0x81F9
.db #0xFE
.dw #0x8200
.dw end - 1
.dw #0x8200
init:
; init global variables
call gsinit
; call main function
call _main
inf_loop:
jp inf_loop
; ordering of segments for the linker.
.area _CODE
.area _HOME
.area _INITIALIZER
.area _GSINIT
.area _GSFINAL
.area _DATA
.area _INITIALIZED
.area _BSEG
.area _BSS
.area _HEAP
.area _CODE
.area _GSINIT
gsinit::
.area _GSFINAL
ret
end:
Este fichero lo creamos con el nombre crt0msxcas.s. A continuación hacemos un sencillo main.c que muestre un mensaje en pantalla e instale una rutina de servicio de interrupción para el retrazo vertical.
#include#define H_TIMI_HOOK ((volatile uint8_t *) 0xFD9F) void putchar(char c) { __asm__ ( "call #0x00A2" ); } void putstr(char *s) { while (*s != 0) { putchar(*s); s++; } } volatile uint8_t counter; volatile uint8_t counter2; void vblank_isr(void) { counter++; if (counter == 60) { counter = 0; putchar((counter2 & 0x0F) + '0'); counter2++; } } void vblank_isr_set(void (*function_ptr)()) { H_TIMI_HOOK[0] = 0xC3; // JP instruction H_TIMI_HOOK[1] = (uint8_t) (((uint16_t) function_ptr) & 0x00FF); H_TIMI_HOOK[2] = (uint8_t) (((uint16_t) function_ptr) >> 8); } void main(void) { counter = 0; counter2 = 0; vblank_isr_set(vblank_isr); putstr("\r\nHola desde SDCC\r\n"); while (1) ; }
Como se puede ver, simplemente mostramos una cadena e instalamos una rutina de servicio de interrupción que va mostrando caracteres en pantalla cada 60 interrupciones de retrazo vertical.
Para compilar hacemos los siguientes pasos:
sdasz80 -o crt0msxcas.rel crt0msxcas.ssdcc -mz80 --std-c23 --stack-auto -c -o main.rel main.csdcc -mz80 --std-c23 --stack-auto --code-loc 0x8209 --no-std-crt0 -o main.ihx crt0msxcas.rel main.relobjcopy -I ihex -O binary main.ihx main.binmkcas.py --name MAIN --addr 0x81F9 --exec 0x8200 main.cas binary main.binLa utilidad objcopy suele estar ya preinstalada en muchos sistemas Linux, si no es el caso, se debe instalar el paquete binutils. La utilidad mkcas.py en una sencilla utilidad desarrollada en Python por Juan J. Martínez y que está disponible en su servidor Git. Como resultado de los pasos anteriores se obtiene un fichero main.cas que puede ser cargando en un emulador o en un MSX real:
openmsx -machine Philips_NMS_8245 -cassetteplayer main.casMSX2Cas en un móvil con Android.main.cas al móvil.BLOAD"CAS:",RMSX2Cas en el móvil Android y esperar a que cargue el programa.MSX2Cas).El programa muestra un mensaje usando la BIOS y va imprimiendo caracteres a razón de 1 cada 60 interrupciones de retrazo vertical:

Todo el código fuente está disponible en sdcc-cas-example.tar.gz.
A partir de este proyecto se ha desarrollado un sencillo juego de Sudoku:

Cuyo código tambié está disponible en sudoku.tar.gz.
En esta sección iré publicando código fuente C para MSX relacionado con la programación de la Moonsound. Los códigos publicados están relacionados con la serie de dos artículos que he escrito para la revista Call MSX, en concreto para sus números 3 y 4 sobre la programación de la Moonsound.
sbiload:En esta sección iré publicando código fuente y datos relacionados con la implementación del algoritmo de compresión/descompresión Huffman en el MSX.
huffman.tar.gz contiene una implementación ANSI-C de los algoritmos de compresión y descompresión Huffman así como una versión específica para MSX del algoritmo de descompresión. La versión específica para MSX requiere, para ser compilada:
Ver fichero README en la subcarpeta huffman/msx.
En esta sección iré publicando código fuente, utilidades y datos relacionados con la programación del VDP.
á é í ó ú ü Á É Í Ó Ú Ü ñ Ñ ¡ ¿ así como algún que otro símbolo. Aquí está:
screen 2 (1 bit por pixel, blanco = 1, negro = 0). Este es el resultado de aplicar este programa a la tabla de caracteres Latin1 anterior.En esta sección iré publicando código fuente, utilidades y datos relacionados con la programación del PSG.
psg_sample anterior. Utiliza la tabla de conversión logarítmica indicada en http://map.tni.nl/articles/psg_sample.php.Sección dedicada al uso de aritmética de punto fijo en en Z80 y/o en el MSX en particular.

This work is licensed under a Creative Commons License.
Página mantenida por Avelino Herrera Morales