crt0.rel
file and making stdio work with the CPUville monitor.To simplify compiling programs the first thing to do is replace the standard
crt0.rel
with the one described in the previous post.This is as simple as backing up the standard file found in
$SDCC_HOME/lib/z80
and replacing it with the crt0.rel
assembled from the modified source.Now the compiler does not need the
--no-std-crt0
flag and single source file programs do not require a separate link step so crt0.rel
can be placed first in the list of files to be linked.A simple program can be compiled with a command such as
"sdcc -mz80 --code-loc 0x0809 --data-loc 0 test.c"
. The --code-loc
and --data-loc
flags are still required so the linker adjusts the relocatable area correctly.Adding CPUville appropriate getchar and putchar functions into the standard library is also pretty simple. The file to change is
$SDCC_HOME/lib/src/z80/putchar.s
. Replace all the code in that file with:
; CPUville ROM entry points.
write_char = 0x0109
get_char = 0x037c
.area _CODE
_putchar::
ld hl, #2
add hl, sp
ld a, (hl)
call write_char
ret
_getchar::
call get_char
ld l,a
ret
This calls the appropriate CPUville monitor functions to write and read single characters via the serial port.
Compile this with
"sdcc -mz80 -c putchar.c"
$SDCC_HOME/lib/z80/z80.lib
z80.lib
with the newly compiled one: "sdar rv /d/sdcc/lib/z80/z80.lib putchar.rel".
At this point your code can use puts and gets from
stdio.h
. I'm still using the CPUville 2K RAM so I cannot call printf yet - the binary file was more than 3K! However SDCC ships with code for smaller/faster variations of printf and I with some editing of the source code I was able to get printf_small to compile. The modifications were mostly removing data storage keywords which the Z80 does not support. I also removed the conditional compilation code just to make things easier to see. Here is the modified code, in $SDCC_HOME/lib/src/printfl.c:
/*-----------------------------------------------------------------
printfl.c - source file for reduced version of printf
Copyright (C) 1999, Sandeep Dutta . sandeep.dutta@usa.net
2001060401: Improved by was@icb.snz.chel.su
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this library; see the file COPYING. If not, write to the
Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
As a special exception, if you link this library with other files,
some of which are compiled with SDCC, to produce an executable,
this library does not by itself cause the resulting executable to
be covered by the GNU General Public License. This exception does
not however invalidate any other reasons why the executable file
might be covered by the GNU General Public License.
-------------------------------------------------------------------------*/
/* following formats are supported :-
format output type argument-type
%d decimal int
%ld decimal long
%hd decimal char
%x hexadecimal int
%lx hexadecimal long
%hx hexadecimal char
%o octal int
%lo octal long
%ho octal char
%c character char
%s character generic pointer*/
#include <stdarg.h>#include <stdio.h>#include <stdlib.h>
static char radix ;static long_flag = 0;static string_flag =0;static char_flag = 0;static char * str ;static long val;
void printf_small (char * fmt, ... ){
va_list ap ;
va_start(ap,fmt);
for (; *fmt ; fmt++ ) {
if (*fmt == '%') {
long_flag = string_flag = char_flag = 0;
fmt++ ;
switch (*fmt) {
case 'l':
long_flag = 1;
fmt++;
break;
case 'h':
char_flag = 1;
fmt++;
}
switch (*fmt) {
case 's':
string_flag = 1;
break;
case 'd':
radix = 10;
break;
case 'x':
radix = 16;
break;
case 'c':
radix = 0;
break;
case 'o':
radix = 8;
break;
}
if (string_flag) {
str = va_arg(ap, char *);
while (*str) putchar(*str++);
continue ;
}
if (long_flag)
val = va_arg(ap,long);
else
if (char_flag)
val = va_arg(ap,char);
else
val = va_arg(ap,int);
if (radix)
{
static char buffer[12]; /* 37777777777(oct) */
char * stri;
_ltoa (val, buffer, radix);
stri = buffer;
while (*stri)
{
putchar (*stri);
stri++;
}
}
else
putchar((char)val);
} else
putchar(*fmt);
}
}
Using the same commands as for
putchar.c
this code can be compiled and added into z80.lib
: "sdcc -mz80 -c printfl.c"
"sdar rv /d/sdcc/lib/z80/z80.lib printfl.rel"
printf_small is already declared in
stdio.h
, and is now ready to use:
#include <stdio.h>
static char clear_screen[] = { 0x1b, '[', '2', 'J', 0x00 };
static char cursor_home[] = { 0x1b, '[', 'H', 0x00 };
static char buffer[33];
void main(void) {
printf_small("%s%s%s", clear_screen, cursor_home, "Hello world.\r\nEnter a string up to 32 characters long: ");
gets(buffer);
printf_small("\rYou entered: %s\r\n", buffer);
}
This code compiles to 1467 bytes, so it's still pushing the limits of my 2K system, but it does fit!
No comments:
Post a Comment