Introducción a la programación en C con SDCC: Compilando y probando un "Hola mundo"

Click here to see in English

En el momento de escribir este documento la última versión estable de SDCC liberada es la v3.1.0, que es de noviembre de 2011, aunque podemos bajar un snapshot con todo lo último, ya que se generan automáticamente todos los días. Bajamos la instalación de su web. La instalación en windows es automática y para cualquier otra plataforma o dudas podemos leer la documentación. Una vez instalado básicamente podemos invocar el compilador desde cualquier directorio del pc. Como el compilador genera código en formato hexadecimal de Intel (Intel Hex file) vamos a necesitar también la utilidad hex2bin (ejecutable windows) para convertirlo a binario.

Como ya dijimos en "Programación en c y en ensamblador: Compiladores y alternativas para PC", SDCC es un compilador genérico, que no sabe de Amstrad o spectrum. Para que el compilador genere binarios que se ejecuten en nuestro cpc hay que hacer unos pequeños ajustes. En CPCWiki hay un tutorial muy completo al respecto llamado SDCC and CPC, pero que a día de hoy parece obsoleto, aunque vamos a tomarlo de referencia.

Por defecto SDCC genera código para z80 que se ejecuta en la dirección 0, esto no es valido para Amstrad, así que tenemos que suministrarle un fichero de 'startup' con unas directrices para el inicio/ejecución de los programas. Para ello vamos a usar el mismo fichero que hay el el tutorial de CPCWiki, que escribió Hans Hansen en 2003:

Con cualquier editor de texto o código (con el mismo notepad de Windows vale) generamos un fichero crt0_cpc.s con el siguiente contenido (al final del tutorial se puede descargar todo en un zip):

;; FILE: crt0.s
;; Generic crt0.s for a Z80
;; From SDCC..
;; Modified to suit execution on the Amstrad CPC!
;; by H. Hansen 2003
;; Original lines has been marked out!

  .module crt0
  .globl  _main

  .area _HEADER (ABS)
;; Reset vector
  .org  0x100 ;; Start from address &100
  jp  init
  
  .org  0x110

init:

;; Stack at the top of memory.
;;  ld  sp,#0xffff        
;;  I will use the Basic stack, so the program can return to basic!

;; Initialise global variables
  call    gsinit
  call  _main
  jp  _exit

  ;; Ordering of segments for the linker.
  .area _HOME
  .area _CODE
  .area   _GSINIT
  .area   _GSFINAL
        
  .area _DATA
  .area   _BSS
  .area   _HEAP

  .area   _CODE
__clock::
  ret
  
_exit::
  ret
  
  .area   _GSINIT
gsinit::  

.area   _GSFINAL
  ret

Básicamente con esto indicaríamos que nuestro programa ejecuta en la dirección 0x0100 (podemos modificarlo a nuestro gusto, lógicamente). Para poder usarlo, tenemos que compilarlo de la siguiente manera:

sdasz80 -o crt0_cpc.s

Con esto se nos genera un fichero crt0_cpc.rel, que luego usaremos al compilar nuestro código en c. Como ya hemos dicho, SDCC no sabe de Amstrad, por lo que no sabe como pintar un carácter en pantalla, si queremos usar por ejemplo printf, debemos primero indicarle como hacerlo, para eso necesitamos decirle como hacer un putchar (printf lo llama internamente). Con cualquier editor de texto o código (con el mismo notepad de Windows vale) generamos un fichero putchar_cpc.s con el siguiente contenido (al final del tutorial se puede descargar todo en un zip):

;; FILE: putchar.s
;; Modified to suit execution on the Amstrad CPC
;; by H. Hansen 2003
;; Original lines has been marked out!

  .area _CODE
_putchar::       
_putchar_rr_s:: 
          ld      hl,#2
          add     hl,sp
        
          ld      a,(hl)
          call    0xBB5A
          ret
           
_putchar_rr_dbs::

          ld      a,e
          call    0xBB5A
          ret

Básicamente, le decimos que para pintar un carácter llame a la función del firmware 0xBB5A. Para poder usarlo, tenemos que compilarlo de la siguiente manera:

sdasz80 -o putchar_cpc.s

Ahora que ya estamos preparados, con cualquier editor de texto o código (con el mismo notepad de Windows vale) generamos un fichero sdcc01.c con el siguiente contenido:

#include <stdio.h>

main()
{
  printf("Hola mundo");
  while(1) {};
}

Para compilarlo, desde la línea de comandos (o mejor hacemos un fichero bat) en el mismo directorio donde tenemos los tres ficheros (sdcc01.c, crt0_cpc.s y putchar_cpc.s) ejecutamos:

sdcc -mz80 --code-loc 0x0138 --data-loc 0 --no-std-crt0 crt0_cpc.rel putchar_cpc.rel sdcc01.c
hex2bin sdcc01.ihx

Si todo ha ido bien, se nos habrá generado un nuevo fichero sdcc01.bin, que ya se puede ejecutar en el Amstrad CPC. Para las pruebas, vamos a cargar los binarios generados en un emulador, para ello tendremos que generar un fichero dsk (imagen de disco) con el binario que hemos compilado, para poder cargarlo/ejecutarlo en el emulador. Para ello podemos utilizar por ejemplo ManageDSK o CPCDiskXP.

Para generar un Dsk con CPCDiskXP, ejecutamos el programa, pulsamos en "Dsk Editor", luego pulsamos en "New" seleccionamos el formato por defecto "CPC Data" y pulsamos Ok. Ahora pulsamos "Add Files" para añadir nuestro binario, buscamos el directorio donde hemos compilado y seleccionamos el fichero sdcc01.bin, ahora CPCDiskXP nos preguntará si queremos añadir la cabecera Amsdos, pulsamos Sí, ponemos 0x0100 en Address y Entry Address y pulsamos Ok. Ahora pulsamos el botón "Save" para guardar nuestro Dsk, yo lo he llamado "sdcc01.dsk" en el mismo directorio. Con la última versión de CPCDiskXP también podemos generar un dsk desde la línea de comandos (o un bat) de la siguiente forma:

CPCDiskXP -File sdcc01.bin -AddAmsdosHeader 100 -AddToNewDsk sdcc01.dsk

Cargamos el Dsk en nuestro emulador favorito (Yo suelo usar CPCE y Winape) y lo ejecutamos con run"sdcc01 y veremos lo siguiente:

 

Podéis bajar un zip con todos ficheros aquí: Introduccion_a_la_programacion_en_SDCC_Compilando_y_probando_un_Hola_mundo.zip

 

www.CPCMania.com 2012