diff --git a/.cproject b/.cproject
index 096d23a..6d797d4 100644
--- a/.cproject
+++ b/.cproject
@@ -51,7 +51,12 @@
-
+
+
+
+
+
+
@@ -62,11 +67,20 @@
+
+
+
+
+
+
@@ -78,28 +92,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.project b/.project
index 2f0d4f5..745a6cd 100644
--- a/.project
+++ b/.project
@@ -9,6 +9,10 @@
org.eclipse.cdt.managedbuilder.core.genmakebuilder
clean,full,incremental,
+
+ ?children?
+ ?name?=outputEntries\|?children?=?name?=entry\\\\\\\|\\\|?name?=entry\\\\\\\|\\\|\||
+
?name?
diff --git a/Makefile b/Makefile
index cf10d34..7967bcd 100644
--- a/Makefile
+++ b/Makefile
@@ -39,11 +39,13 @@ RAM_EXEC=ram.s19
CSRCS= \
$(SRCDIR)/sysinit.c \
$(SRCDIR)/init_fpga.c \
+ $(SRCDIR)/printf.c \
$(SRCDIR)/BaS.c \
$(SRCDIR)/cache.c \
$(SRCDIR)/sd_card.c
ASRCS= \
+ $(SRCDIR)/printf_helper.S \
$(SRCDIR)/mmu.S \
$(SRCDIR)/sd_card_asm.S \
$(SRCDIR)/exceptions.S \
@@ -76,6 +78,9 @@ $(FLASH_EXEC) $(RAM_EXEC): $(STRT_OBJ) $(OBJS)
# compile init_fpga with -mbitfield for testing purposes
$(OBJDIR)/init_fpga.o: CFLAGS += -mbitfield
+# compile printf pc-relative so it can be used as well before and after copy of BaS
+$(OBJDIR)/printf.o: CFLAGS += -mpcrel
+
$(OBJDIR)/%.o:$(SRCDIR)/%.c
$(CC) -c $(CFLAGS) $(INCLUDE) $< -o $@
diff --git a/bas.lk.in b/bas.lk.in
index 52a25de..88357a4 100644
--- a/bas.lk.in
+++ b/bas.lk.in
@@ -76,6 +76,8 @@ SECTIONS {
objs/BaS.o(.text)
/* put other routines into the same segment (RAM) as BaS.o */
objs/sd_card_asm.o(.text)
+ objs/printf.o(.text)
+ objs/printf_helper.o(.text)
objs/sd_card.o(.text)
objs/mmu.o(.text)
objs/exceptions.o(.text)
diff --git a/include/printf.h b/include/printf.h
new file mode 100644
index 0000000..d242a39
--- /dev/null
+++ b/include/printf.h
@@ -0,0 +1,9 @@
+#ifndef _PRINTF_H_
+#define _PRINTF_H_
+
+extern void xvsnprintf(char *str, size_t size, const char *fmt, va_list va);
+extern void xvprintf(const char *fmt, va_list va);
+extern void xprintf(const char *fmt, ...);
+extern void xsnprintf(char *str, size_t size, const char *fmt, ...);
+
+#endif /* _PRINTF_H_ */
diff --git a/sources/printf.c b/sources/printf.c
new file mode 100644
index 0000000..fa624c6
--- /dev/null
+++ b/sources/printf.c
@@ -0,0 +1,376 @@
+/*
+ * tc.printf.c: A public-domain, minimal printf/sprintf routine that prints
+ * through the putchar() routine. Feel free to use for
+ * anything... -- 7/17/87 Paul Placeway
+ */
+/*-
+ * Copyright (c) 1980, 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "MCF5475.h"
+
+#include
+#include
+
+/*
+ * Lexical definitions.
+ *
+ * All lexical space is allocated dynamically.
+ * The eighth/sixteenth bit of characters is used to prevent recognition,
+ * and eventually stripped.
+ */
+#define META 0200
+#define ASCII 0177
+# define QUOTE ((char) 0200) /* Eighth char bit used for 'ing */
+# define TRIM 0177 /* Mask to strip quote bit */
+# define UNDER 0000000 /* No extra bits to do both */
+# define BOLD 0000000 /* Bold flag */
+# define STANDOUT META /* Standout flag */
+# define LITERAL 0000000 /* Literal character flag */
+# define ATTRIBUTES 0200 /* The bits used for attributes */
+# define CHAR 0000177 /* Mask to mask out the character */
+
+#define INF 32766 /* should be bigger than any field to print */
+
+static char buf[128];
+static char snil[] = "(nil)";
+
+static void xputchar(int c)
+{
+ __asm__ __volatile__
+ (
+ ".extern printf_helper\n\t"
+ "move.b %0,d0\n\t"
+ "bsr printf_helper\n\t"
+ /* output */:
+ /* input */: "r" (c)
+ /* clobber */ : "d0","a0"
+ );
+}
+
+#define isdigit(c) (((c) >= '0') && ((c) <= '9'))
+#define isupper(c) ((c) >= 'A' && ((c) <= 'Z'))
+#define islower(c) ((c) >= 'a' && ((c) <= 'z'))
+#define isalpha(c) (isupper((c)) || islower(c))
+#define tolower(c) (isupper(c) ? ((c) + 'a' - 'A') : (c))
+
+static int atoi(const char *c)
+{
+ int value = 0;
+ while (isdigit(*c) ) {
+ value *= 10;
+ value += (int) (*c-'0');
+ c++;
+ }
+ return value;
+}
+
+size_t strlen(const char *s)
+{
+ int length = 0;
+
+ while (*s++) {
+ length++;
+ }
+ return length;
+}
+
+
+static void doprnt(void (*addchar) (int), const char *sfmt, va_list ap)
+{
+ char *bp;
+ const char *f;
+ long l;
+ unsigned long u;
+ int i;
+ int fmt;
+ unsigned char pad = ' ';
+ int flush_left = 0;
+ int f_width = 0;
+ int prec = INF;
+ int hash = 0;
+ int do_long = 0;
+ int sign = 0;
+ int attributes = 0;
+
+ f = sfmt;
+ for (; *f; f++) {
+ if (*f != '%') {
+ /* then just out the char */
+ (*addchar) ((int)(((unsigned char)*f) | attributes));
+ } else {
+ f++; /* skip the % */
+
+ if (*f == '-') { /* minus: flush left */
+ flush_left = 1;
+ f++;
+ }
+
+ if (*f == '0' || *f == '.') {
+ /* padding with 0 rather than blank */
+ pad = '0';
+ f++;
+ }
+ if (*f == '*') {
+ /* field width */
+ f_width = va_arg(ap, int);
+ f++;
+ } else if (isdigit((unsigned char)*f)) {
+ f_width = atoi(f);
+ while (isdigit((unsigned char)*f))
+ f++; /* skip the digits */
+ }
+
+ if (*f == '.') { /* precision */
+ f++;
+ if (*f == '*') {
+ prec = va_arg(ap, int);
+ f++;
+ } else if (isdigit((unsigned char)*f)) {
+ prec = atoi(f);
+ while (isdigit((unsigned char)*f))
+ f++; /* skip the digits */
+ }
+ }
+
+ if (*f == '#') { /* alternate form */
+ hash = 1;
+ f++;
+ }
+
+ if (*f == 'l') { /* long format */
+ do_long++;
+ f++;
+ if (*f == 'l') {
+ do_long++;
+ f++;
+ }
+ }
+
+ fmt = (unsigned char)*f;
+ if (fmt != 'S' && fmt != 'Q' && isupper(fmt)) {
+ do_long = 1;
+ fmt = tolower(fmt);
+ }
+ bp = buf;
+ switch (fmt) { /* do the format */
+ case 'd':
+ switch (do_long) {
+ case 0:
+ l = (long)(va_arg(ap, int));
+ break;
+ case 1:
+#ifndef HAVE_LONG_LONG
+ default:
+#endif
+ l = va_arg(ap, long);
+ break;
+#ifdef HAVE_LONG_LONG
+ default:
+ l = va_arg(ap, long long);
+ break;
+#endif
+ }
+
+ if (l < 0) {
+ sign = 1;
+ l = -l;
+ }
+ do {
+ *bp++ = (char)(l % 10) + '0';
+ } while ((l /= 10) > 0);
+ if (sign)
+ *bp++ = '-';
+ f_width = f_width - (int)(bp - buf);
+ if (!flush_left)
+ while (f_width-- > 0)
+ (*addchar) ((int)
+ (pad | attributes));
+ for (bp--; bp >= buf; bp--)
+ (*addchar) ((int)
+ (((unsigned char)*bp) |
+ attributes));
+ if (flush_left)
+ while (f_width-- > 0)
+ (*addchar) ((int)
+ (' ' | attributes));
+ break;
+
+ case 'p':
+ do_long = 1;
+ hash = 1;
+ fmt = 'x';
+ /*FALLTHROUGH*/
+ case 'o':
+ case 'x':
+ case 'u':
+ switch (do_long) {
+ case 0:
+ u = (unsigned
+ long)(va_arg(ap, unsigned int));
+ break;
+ case 1:
+#ifndef HAVE_LONG_LONG
+ default:
+#endif
+ u = va_arg(ap, unsigned long);
+ break;
+#ifdef HAVE_LONG_LONG
+ default:
+ u = va_arg(ap, unsigned long long);
+ break;
+#endif
+ }
+ if (fmt == 'u') { /* unsigned decimal */
+ do {
+ *bp++ = (char)(u % 10) + '0';
+ } while ((u /= 10) > 0);
+ } else if (fmt == 'o') { /* octal */
+ do {
+ *bp++ = (char)(u % 8) + '0';
+ } while ((u /= 8) > 0);
+ if (hash)
+ *bp++ = '0';
+ } else if (fmt == 'x') { /* hex */
+ do {
+ i = (int)(u % 16);
+ if (i < 10)
+ *bp++ = i + '0';
+ else
+ *bp++ = i - 10 + 'a';
+ } while ((u /= 16) > 0);
+ if (hash) {
+ *bp++ = 'x';
+ *bp++ = '0';
+ }
+ }
+ i = f_width - (int)(bp - buf);
+ if (!flush_left)
+ while (i-- > 0)
+ (*addchar) ((int)
+ (pad | attributes));
+ for (bp--; bp >= buf; bp--)
+ (*addchar) ((int)
+ (((unsigned char)*bp) |
+ attributes));
+ if (flush_left)
+ while (i-- > 0)
+ (*addchar) ((int)
+ (' ' | attributes));
+ break;
+
+ case 'c':
+ i = va_arg(ap, int);
+ (*addchar) ((int)(i | attributes));
+ break;
+
+ case 'S':
+ case 'Q':
+ case 's':
+ case 'q':
+ bp = va_arg(ap, char *);
+ if (!bp)
+ bp = snil;
+ f_width = f_width - strlen((char *)bp);
+ if (!flush_left)
+ while (f_width-- > 0)
+ (*addchar) ((int)(pad | attributes));
+ for (i = 0; *bp && i < prec; i++) {
+ if (fmt == 'q' && *bp & QUOTE)
+ (*addchar) ((int)('\\' | attributes));
+ (*addchar) ((int)(((unsigned char)*bp & TRIM) | attributes));
+ bp++;
+ }
+ if (flush_left)
+ while (f_width-- > 0)
+ (*addchar) ((int)(' ' | attributes));
+ break;
+
+ case 'a':
+ attributes = va_arg(ap, int);
+ break;
+
+ case '%':
+ (*addchar) ((int)('%' | attributes));
+ break;
+
+ default:
+ break;
+ }
+ flush_left = 0, f_width = 0, prec = INF, hash =
+ 0, do_long = 0;
+ sign = 0;
+ pad = ' ';
+ }
+ }
+}
+
+static char *xstring, *xestring;
+
+static void xaddchar(int c)
+{
+ if (xestring == xstring)
+ *xstring = '\0';
+ else
+ *xstring++ = (char)c;
+}
+
+void xsnprintf(char *str, size_t size, const char *fmt, ...)
+{
+ va_list va;
+ va_start(va, fmt);
+
+ xstring = str;
+ xestring = str + size - 1;
+ doprnt(xaddchar, fmt, va);
+ va_end(va);
+ *xstring++ = '\0';
+}
+
+void xprintf(const char *fmt, ...)
+{
+ va_list va;
+ va_start(va, fmt);
+ doprnt(xputchar, fmt, va);
+ va_end(va);
+}
+
+void xvprintf(const char *fmt, va_list va)
+{
+ doprnt(xputchar, fmt, va);
+}
+
+void xvsnprintf(char *str, size_t size, const char *fmt, va_list va)
+{
+ xstring = str;
+ xestring = str + size - 1;
+ doprnt(xaddchar, fmt, va);
+ *xstring++ = '\0';
+}
+
+
diff --git a/sources/printf_helper.S b/sources/printf_helper.S
new file mode 100644
index 0000000..964952e
--- /dev/null
+++ b/sources/printf_helper.S
@@ -0,0 +1,8 @@
+// assembler trampoline to let printf (compiled -mpcrel) indirectly reference __MBAR
+
+ .global printf_helper
+printf_helper:
+ .extern __MBAR
+ lea __MBAR+0x860C,a0
+ move.b d0,(a0)
+ rts