diff --git a/newlib/libc/sys/sh3eb/Makefile.am b/newlib/libc/sys/sh3eb/Makefile.am index cdb9a3edd..76e6f9cdb 100644 --- a/newlib/libc/sys/sh3eb/Makefile.am +++ b/newlib/libc/sys/sh3eb/Makefile.am @@ -8,7 +8,7 @@ AM_CCASFLAGS = $(INCLUDES) $(CFLAGS) noinst_LIBRARIES = lib.a -lib_a_SOURCES = syscalls.c trap.S creat.c ftruncate.c truncate.c calloc.c free.c malloc.c memcmp.c memcpy.c memmove.c memset.c realloc.c strcat.c strchr.c strcmp.c strlen.c strncat.c strncmp.c strncpy.c strrchr.c strstr.c casio_syscalls.c +lib_a_SOURCES = syscalls.c trap.S creat.c ftruncate.c truncate.c calloc.c free.c malloc.c memcmp.c memcpy.c memmove.c memset.c realloc.c strcat.c strchr.c strcmp.c strlen.c strncat.c strncmp.c strncpy.c strrchr.c strstr.c casio_syscalls.c console.c lib_a_CCASFLAGS = $(AM_CCASFLAGS) lib_a_CFLAGS = $(AM_CFLAGS) diff --git a/newlib/libc/sys/sh3eb/Makefile.in b/newlib/libc/sys/sh3eb/Makefile.in index f22c104f9..30b15079e 100644 --- a/newlib/libc/sys/sh3eb/Makefile.in +++ b/newlib/libc/sys/sh3eb/Makefile.in @@ -80,7 +80,7 @@ am_lib_a_OBJECTS = lib_a-syscalls.$(OBJEXT) lib_a-trap.$(OBJEXT) \ lib_a-strlen.$(OBJEXT) lib_a-strncat.$(OBJEXT) \ lib_a-strncmp.$(OBJEXT) lib_a-strncpy.$(OBJEXT) \ lib_a-strrchr.$(OBJEXT) lib_a-strstr.$(OBJEXT) \ - lib_a-casio_syscalls.$(OBJEXT) + lib_a-casio_syscalls.$(OBJEXT) lib_a-console.$(OBJEXT) lib_a_OBJECTS = $(am_lib_a_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ depcomp = @@ -207,7 +207,7 @@ AUTOMAKE_OPTIONS = cygnus INCLUDES = $(NEWLIB_CFLAGS) $(CROSS_CFLAGS) $(TARGET_CFLAGS) AM_CCASFLAGS = $(INCLUDES) $(CFLAGS) noinst_LIBRARIES = lib.a -lib_a_SOURCES = syscalls.c trap.S creat.c ftruncate.c truncate.c calloc.c free.c malloc.c memcmp.c memcpy.c memmove.c memset.c realloc.c strcat.c strchr.c strcmp.c strlen.c strncat.c strncmp.c strncpy.c strrchr.c strstr.c casio_syscalls.c +lib_a_SOURCES = syscalls.c trap.S creat.c ftruncate.c truncate.c calloc.c free.c malloc.c memcmp.c memcpy.c memmove.c memset.c realloc.c strcat.c strchr.c strcmp.c strlen.c strncat.c strncmp.c strncpy.c strrchr.c strstr.c casio_syscalls.c console.c lib_a_CCASFLAGS = $(AM_CCASFLAGS) lib_a_CFLAGS = $(AM_CFLAGS) ACLOCAL_AMFLAGS = -I ../../.. -I ../../../.. @@ -414,6 +414,12 @@ lib_a-casio_syscalls.o: casio_syscalls.c lib_a-casio_syscalls.obj: casio_syscalls.c $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-casio_syscalls.obj `if test -f 'casio_syscalls.c'; then $(CYGPATH_W) 'casio_syscalls.c'; else $(CYGPATH_W) '$(srcdir)/casio_syscalls.c'; fi` +lib_a-console.o: console.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-console.o `test -f 'console.c' || echo '$(srcdir)/'`console.c + +lib_a-console.obj: console.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-console.obj `if test -f 'console.c'; then $(CYGPATH_W) 'console.c'; else $(CYGPATH_W) '$(srcdir)/console.c'; fi` + ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ diff --git a/newlib/libc/sys/sh3eb/casio_syscalls.c b/newlib/libc/sys/sh3eb/casio_syscalls.c index bd3f88659..f2417bfba 100644 --- a/newlib/libc/sys/sh3eb/casio_syscalls.c +++ b/newlib/libc/sys/sh3eb/casio_syscalls.c @@ -1,6 +1,7 @@ #include #include +#include DEFINE_CASIO_SYSCALL_FN_PTR(GetKey, int, (unsigned int*), 0x90F) DEFINE_CASIO_SYSCALL_FN_PTR(PutKey, int, (int keycode, int mode), 0x910) @@ -36,7 +37,18 @@ void Print(const unsigned char* str) { } void locate(int x, int y) { + /* + * This call could be omitted, but to keep compatibility with the fxlib functions: + * locate(x, y); + * Print(str); + */ _locate_ptr(x, y); + + /* + * For use with stdio functions like printf + */ + _console_set_cursor(&_console_ctx, x, y); + } void wait_ms(unsigned int ms) { // TODO signature assumed diff --git a/newlib/libc/sys/sh3eb/console.c b/newlib/libc/sys/sh3eb/console.c new file mode 100644 index 000000000..7ea3e6e3e --- /dev/null +++ b/newlib/libc/sys/sh3eb/console.c @@ -0,0 +1,167 @@ +#include +#include + +/* + * Console instance for printf etc. + */ +_console _console_ctx = { + .cursor_x = 0, + .cursor_y = 0, + .buf_strlen = 0, + .buf = {0}, +}; + + +/* + * Sets the internal cursor position on the console. + * Note that the Casio cursor position will not be set until + * the console is flushed (automatically or manually). + */ +void _console_set_cursor(_console *ctx, unsigned char x, unsigned char y) { + /* + * No need to flush here, because the buffer already was flushed + * at the end of the _console_write() function. + */ + + if (x < _CONSOLE_WIDTH && y < _CONSOLE_HEIGHT) { + ctx->cursor_x = x; + ctx->cursor_y = y; + } +} + +/* + * Writes the (potentially but not necessarily null-terminated) + * string *ptr to the internal buffer. May flush and invoke + * the Casio "locate" and "Print" syscalls. + */ +int _console_write (_console *ctx, int file, char *ptr, int len) +{ + /* + * Start parsing + */ + while (len-- && *ptr) { + /* + * Filter out all control characters + */ + switch (*ptr) { + case '\a': + // ignore + ptr++; + continue; + case '\b': + // undo last char (if not first char in line) + // no wrapping + ctx->cursor_x -= !!ctx->cursor_x; + ctx->buf_strlen -= !!ctx->buf_strlen; + ctx->buf[ctx->buf_strlen] = '\0'; + ptr++; + continue; + case '\f': + case '\v': + _console_flush(ctx); + ctx->cursor_y = (ctx->cursor_y + 1) % _CONSOLE_HEIGHT; + ptr++; + continue; + case '\n': + _console_flush(ctx); + ctx->cursor_x = 0; + ctx->cursor_y = (ctx->cursor_y + (ctx->cursor_x < _CONSOLE_WIDTH)) % _CONSOLE_HEIGHT; + ptr++; + continue; + case '\r': + _console_flush(ctx); + ctx->cursor_x = 0; + ptr++; + continue; + case '\t': + ; + /* + * Go to next tab stop (or to the end of the line). + */ + /* + * Somehow the following statement (see int s) cannot be written directly inside + * the condition of the for loop (or the program will act strangely). + * Possibly due to signedness? TODO + */ + int s = _CONSOLE_TAB_LEN - (ctx->cursor_x % _CONSOLE_TAB_LEN); + for (int i = 0; i < s; i++) { + _console_write(ctx, file, " ", 1); + } + ptr++; + continue; + } + + + // Add char to the buffer (flushes before it overflows) + _console_putc(ctx, *ptr); + + // Flush buffer if there is a line wrap + if (ctx->cursor_x == _CONSOLE_WIDTH - 1) { + /* + * Temporarily increment cursor_x (without wrapping) + * because _console_flush expects the cursor to point + * to the position of the next char. + */ + ctx->cursor_x++; + _console_flush(ctx); + ctx->cursor_x--; + } + + // Move curser to the left (wrap if bounds are exceeded) + ctx->cursor_x = (ctx->cursor_x + 1) % _CONSOLE_WIDTH; + + // Move curser down if (ctx->cursor_x == 0) (wrap if bounds are exceeded) + ctx->cursor_y = (ctx->cursor_y + !ctx->cursor_x) % _CONSOLE_HEIGHT; + + ptr++; + } + + // Always flush in the end + _console_flush(ctx); + return len; +} + + +/* + * Adds a character to the internal buffer. + * Does not take care of the cursor position. + * May invoke _console_flush() to print the contents of the internal buffer. + * Use _console_flush() to manually flush the contents to the console output. + * Does not change the position of the internal cursor. + */ +void _console_putc(_console *ctx, char c) { + if (ctx->buf_strlen == _CONSOLE_BUF_WIDTH - 1) { + _console_flush(ctx); + } + + ctx->buf[ctx->buf_strlen++] = c; + ctx->buf[ctx->buf_strlen] = '\0'; +} + + +/* + * Prints the buffer out to the console and invokes + * the Casio "locate" and "Print" syscalls. + * Resets the internal buffer to "". + * Does not change the position of the internal cursor. + */ +void _console_flush(_console *ctx) { + /* + * Local syscall to Casio's locate + * because Casio's syscall is overwritten by _casio_set_cursor() + */ + typedef void (*console_locate_type)(int, int); + static const unsigned int console_locate_address[] = { _CASIO_SYSCALLS_SCA, _CASIO_SYSCALLS_SCB,_CASIO_SYSCALLS_SCE, 0x807 }; + static const console_locate_type console_locate_ptr = (console_locate_type) console_locate_address; + + if (!ctx->buf_strlen) { + return; + } + + // +1 because the CASIO cursor position is 1-based + console_locate_ptr(ctx->cursor_x - ctx->buf_strlen + 1, ctx->cursor_y + 1); + Print((unsigned char*) ctx->buf); + + ctx->buf[0] = '\0'; + ctx->buf_strlen = 0; +} \ No newline at end of file diff --git a/newlib/libc/sys/sh3eb/sys/console.h b/newlib/libc/sys/sh3eb/sys/console.h new file mode 100644 index 000000000..334794111 --- /dev/null +++ b/newlib/libc/sys/sh3eb/sys/console.h @@ -0,0 +1,69 @@ +#ifdef _CONSOLE_H +#define _CONSOLE_H +#else + +/* Width of display in characters */ +#define _CONSOLE_WIDTH 21 + +/* Height of the display in lines */ +#define _CONSOLE_HEIGHT 8 + +/* + * Size of the internal buffer in chars/bytes. + * Can be set arbitrarily (but must not be 0) + */ +#define _CONSOLE_BUF_WIDTH (_CONSOLE_WIDTH + 1) + + +/* Width of a tab (amount of spaces) */ +#define _CONSOLE_TAB_LEN 4 + + +/* + * Structure to store the state of the console. + * Contains the cursor position and an internal buffer. + */ +typedef struct { + /* + * Cursor position (column) of the next char to be written. + * Unlike the convention set by CASIO: + * the cursor position is 0-based! + * The actual Casio cursor will not be set until the + * consol is flushed! + */ + unsigned char cursor_x; + + /* + * Cursor position (row) of the next char to be written. + * Unlike the convention set by CASIO: + * the cursor position is 0-based! + * The actual Casio cursor will not be set until the + * consol is flushed! + */ + unsigned char cursor_y; + + /* + * Internal buffer of the console. + * All those characters will be consecutive and in the same line. + * If the cursor changes position, the buffer needs to be flushed. + */ + char buf[_CONSOLE_BUF_WIDTH]; + + /* + * Amount of characters in the internal buffer. + */ + unsigned char buf_strlen; +} _console; + +/* + * Console instance for the stdio functions like printf etc. + */ +extern _console _console_ctx; + +int _console_write(_console *ctx, int file, char *ptr, int len); +void _console_set_cursor(_console *ctx, unsigned char x, unsigned char y); +void _console_flush(_console *ctx); +void _console_putc(_console *ctx, char c); + + +#endif /* _CONSOLE_H */ \ No newline at end of file diff --git a/newlib/libc/sys/sh3eb/syscalls.c b/newlib/libc/sys/sh3eb/syscalls.c index d0beb8d3b..a627cd509 100644 --- a/newlib/libc/sys/sh3eb/syscalls.c +++ b/newlib/libc/sys/sh3eb/syscalls.c @@ -3,6 +3,7 @@ #include #include #include "sys/syscall.h" +#include "sys/console.h" int errno; /* This is used by _sbrk. */ @@ -29,7 +30,8 @@ _write ( int file, char *ptr, int len) { - return -1; + _console_write(&_console_ctx, file, ptr, len); + return len; } int