Close

First C program for the Messy80

A project log for Messy 80

A Z80 single board computer, just because.

oliverdOliver.D 03/21/2018 at 23:420 Comments

I just got SDCC to compile a Hello World program for the Messy80. Writing a putchar function to get printf working was a little more tricky than I thought. I had to have a look at the list file produced by SDCC to figure out how to get the function parameter.

#include <stdio.h>
#define UART_LINE_STATUS               0x05
#define UART_LINE_STATUS_THRE        0x05
#define UART_TX_BUFF                0x00


/**
putchar (char c)
Needed for printf
*/
void putchar (char c)
{
__asm

_wait_tx_ready:        // Wait until uart is ready to send
    IN A,(UART_LINE_STATUS)
    bit UART_LINE_STATUS_THRE,A
    jr Z,_wait_tx_ready


    // Get the parameter (char c) from the stack
    // There must be a better way of doing this
    // This is insane :[
    pop DE
    dec sp        // Looks like SDCC saves some space by using inc
            // when pushing 8bit values onto the stack
    pop AF
    // Put everything back the way it was.
    push AF
    inc sp
    push DE


    out (UART_TX_BUFF),A     // At long last, send the byte

__endasm;
}



void main(void)
{
    putchar(':');
    putchar(')');
    putchar('\r');
    putchar('\n');
    printf("Hello world!\r\n");
}


 One thing is for sure, now that the C compiler is set up. writing C programs feels like cheating in comparison to using assembler.

Edit:

I really should have read the SDCC manual a little more. There is a section called "Z80/Z180 intrinsic named address spaces" that explains how write to input/output registers.

This is what the new putchar function looks like.

#define UART_LINE_STATUS_THRE        0x05
__sfr __at 0x00 UART_TX_BUFF;
__sfr __at 0x05 UART_LINE_STATUS;

void putchar (char c)
{
    while( (UART_LINE_STATUS & (1 << UART_LINE_STATUS_THRE)) == 0 );
    UART_TX_BUFF = c;
}

Having a look at the list file is also quite enlightening  as to how the function can be implemented in assembler

_putchar::
00101$:
     in    a,(_UART_LINE_STATUS)
     and    a, #0x20
     jr    Z,00101$
     ld    hl, #2+0
     add    hl, sp
     ld    a, (hl)
     out    (_UART_TX_BUFF),a
     ret 

Much nicer than what I've done above.

Discussions