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
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.