Copy some software code from the original Milkymist SoC.
authorSebastien Bourdeauducq <sebastien@milkymist.org>
Fri, 3 Feb 2012 11:08:17 +0000 (12:08 +0100)
committerSebastien Bourdeauducq <sebastien@milkymist.org>
Fri, 3 Feb 2012 11:08:17 +0000 (12:08 +0100)
Libbase should keep its RAM usage to a minimum as it is meant to
be executed before the SDRAM is up and running. (Having lots of
code is OK though as we XIP from the flash)

44 files changed:
software/include.mak [new file with mode: 0644]
software/include/base/assert.h [new file with mode: 0644]
software/include/base/board.h [new file with mode: 0644]
software/include/base/console.h [new file with mode: 0644]
software/include/base/ctype.h [new file with mode: 0644]
software/include/base/endian.h [new file with mode: 0644]
software/include/base/irq.h [new file with mode: 0644]
software/include/base/limits.h [new file with mode: 0644]
software/include/base/stdarg.h [new file with mode: 0644]
software/include/base/stdio.h [new file with mode: 0644]
software/include/base/stdlib.h [new file with mode: 0644]
software/include/base/string.h [new file with mode: 0644]
software/include/base/system.h [new file with mode: 0644]
software/include/base/uart.h [new file with mode: 0644]
software/include/base/version.h [new file with mode: 0644]
software/include/extra/blockdev.h [new file with mode: 0644]
software/include/extra/crc.h [new file with mode: 0644]
software/include/extra/fatfs.h [new file with mode: 0644]
software/include/hw/capabilities.h [new file with mode: 0644]
software/include/hw/common.h [new file with mode: 0644]
software/include/hw/flash.h [new file with mode: 0644]
software/include/hw/gpio.h [new file with mode: 0644]
software/include/hw/interrupts.h [new file with mode: 0644]
software/include/hw/sysctl.h [new file with mode: 0644]
software/include/hw/uart.h [new file with mode: 0644]
software/libbase/Makefile [new file with mode: 0644]
software/libbase/atof.c [new file with mode: 0644]
software/libbase/board.c [new file with mode: 0644]
software/libbase/console.c [new file with mode: 0644]
software/libbase/divsi3.c [new file with mode: 0644]
software/libbase/libc.c [new file with mode: 0644]
software/libbase/milieu.h [new file with mode: 0644]
software/libbase/softfloat-glue.c [new file with mode: 0644]
software/libbase/softfloat-macros.h [new file with mode: 0644]
software/libbase/softfloat-specialize.h [new file with mode: 0644]
software/libbase/softfloat.c [new file with mode: 0644]
software/libbase/softfloat.h [new file with mode: 0644]
software/libbase/system.c [new file with mode: 0644]
software/libbase/uart.c [new file with mode: 0644]
software/libbase/vsnprintf.c [new file with mode: 0644]
software/libextra/blockdev.c [new file with mode: 0644]
software/libextra/crc16.c [new file with mode: 0644]
software/libextra/crc32.c [new file with mode: 0644]
software/libextra/fatfs.c [new file with mode: 0644]

diff --git a/software/include.mak b/software/include.mak
new file mode 100644 (file)
index 0000000..b0a774a
--- /dev/null
@@ -0,0 +1,45 @@
+# Mico32 toolchain
+#
+CROSS_COMPILER=lm32-rtems4.11-
+
+CC_normal := $(CROSS_COMPILER)gcc
+AR_normal := $(CROSS_COMPILER)ar
+AS_normal := $(CROSS_COMPILER)as
+LD_normal := $(CROSS_COMPILER)ld
+OBJCOPY_normal := $(CROSS_COMPILER)objcopy
+RANLIB_normal  := $(CROSS_COMPILER)ranlib
+
+CC_quiet = @echo " CC " $@ && $(CROSS_COMPILER)gcc
+AR_quiet = @echo " AR " $@ && $(CROSS_COMPILER)ar
+AS_quiet = @echo " AS " $@ && $(CROSS_COMPILER)as
+LD_quiet = @echo " LD " $@ && $(CROSS_COMPILER)ld
+OBJCOPY_quiet = @echo " OBJCOPY " $@ && $(CROSS_COMPILER)objcopy
+RANLIB_quiet  = @echo " RANLIB  " $@ && $(CROSS_COMPILER)ranlib
+
+ifeq ($(V),1)
+    CC = $(CC_normal)
+    AR = $(AR_normal)
+    AS = $(AS_normal)
+    LD = $(LD_normal)
+    OBJCOPY = $(OBJCOPY_normal)
+    RANLIB  = $(RANLIB_normal)
+else
+    CC = $(CC_quiet)
+    AR = $(AR_quiet)
+    AS = $(AS_quiet)
+    LD = $(LD_quiet)
+    OBJCOPY = $(OBJCOPY_quiet)
+    RANLIB  = $(RANLIB_quiet)
+endif
+
+# Toolchain options
+#
+INCLUDES_NOLIBC ?= -nostdinc -I$(MMDIR)/software/include/base
+INCLUDES = $(INCLUDES_NOLIBC) -I$(MMDIR)/software/include -I$(MMDIR)/tools
+ASFLAGS = $(INCLUDES) -nostdinc
+# later: -Wmissing-prototypes
+CFLAGS = -O9 -Wall -Wstrict-prototypes -Wold-style-definition -Wshadow \
+        -mbarrel-shift-enabled -mmultiply-enabled -mdivide-enabled \
+        -msign-extend-enabled -fno-builtin -fsigned-char \
+        -fsingle-precision-constant $(INCLUDES)
+LDFLAGS = -nostdlib -nodefaultlibs
diff --git a/software/include/base/assert.h b/software/include/base/assert.h
new file mode 100644 (file)
index 0000000..6bfaba6
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
+ * Copyright (C) Linux kernel developers
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ASSERT_H
+#define __ASSERT_H
+
+#define assert(x)
+
+#endif /* __ASSERT_H */
diff --git a/software/include/base/board.h b/software/include/base/board.h
new file mode 100644 (file)
index 0000000..3227314
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009, 2010, 2011 Sebastien Bourdeauducq
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __BOARD_H
+#define __BOARD_H
+
+#define BOARD_NAME_LEN 32
+
+struct board_desc {
+       unsigned short int id;
+       char name[BOARD_NAME_LEN];
+       unsigned int ethernet_phyadr;
+};
+
+const struct board_desc *get_board_desc_id(unsigned short int id);
+const struct board_desc *get_board_desc(void);
+int get_pcb_revision(void);
+void get_soc_version(unsigned int *major, unsigned int *minor, unsigned int *subminor, unsigned int *rc);
+void get_soc_version_formatted(char *version);
+
+#endif /* __BOARD_H */
diff --git a/software/include/base/console.h b/software/include/base/console.h
new file mode 100644 (file)
index 0000000..d89f0a1
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __CONSOLE_H
+#define __CONSOLE_H
+
+typedef void (*console_write_hook)(char);
+typedef char (*console_read_hook)(void);
+typedef int (*console_read_nonblock_hook)(void);
+
+void console_set_write_hook(console_write_hook h);
+void console_set_read_hook(console_read_hook r, console_read_nonblock_hook rn);
+
+char readchar(void);
+int readchar_nonblock(void);
+
+int puts(const char *s);
+void putsnonl(const char *s);
+
+#endif /* __CONSOLE_H */
diff --git a/software/include/base/ctype.h b/software/include/base/ctype.h
new file mode 100644 (file)
index 0000000..926b761
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __CTYPE_H
+#define __CTYPE_H
+
+static inline int isdigit(char c)
+{
+       return (c >= '0') && (c <= '9');
+}
+
+static inline int isxdigit(char c)
+{
+       return isdigit(c) || ((c >= 'a') && (c <= 'f')) || ((c >= 'A') && (c <= 'F'));
+}
+
+static inline int isupper(char c)
+{
+       return (c >= 'A') && (c <= 'Z');
+}
+
+static inline int islower(char c)
+{
+       return (c >= 'a') && (c <= 'z');
+}
+
+static inline unsigned char tolower(unsigned char c)
+{
+       if (isupper(c))
+               c -= 'A'-'a';
+       return c;
+}
+
+static inline unsigned char toupper(unsigned char c)
+{
+       if (islower(c))
+               c -= 'a'-'A';
+       return c;
+}
+
+static inline char isspace(unsigned char c)
+{
+       if(c == ' '
+               || c == '\f'
+               || c == '\n'
+               || c == '\r'
+               || c == '\t'
+               || c == '\v')
+               return 1;
+
+       return 0;
+}
+
+#endif /* __CTYPE_H */
diff --git a/software/include/base/endian.h b/software/include/base/endian.h
new file mode 100644 (file)
index 0000000..9cdf98c
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
+ * 
+ * This program 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, version 3 of the License.
+ * 
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ENDIAN_H
+#define __ENDIAN_H
+
+#define __LITTLE_ENDIAN 0
+#define __BIG_ENDIAN 1
+#define __BYTE_ORDER __BIG_ENDIAN
+
+static inline unsigned int le32toh(unsigned int val)
+{
+       return (val & 0xff) << 24 |
+               (val & 0xff00) << 8 |
+               (val & 0xff0000) >> 8 |
+               (val & 0xff000000) >> 24;
+}
+
+static inline unsigned short le16toh(unsigned short val)
+{
+       return (val & 0xff) << 8 |
+               (val & 0xff00) >> 8;
+}
+
+#endif /* __ENDIAN_H */
diff --git a/software/include/base/irq.h b/software/include/base/irq.h
new file mode 100644 (file)
index 0000000..43e4473
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __IRQ_H
+#define __IRQ_H
+
+static inline void irq_enable(unsigned int en)
+{
+       __asm__ __volatile__("wcsr IE, %0" : : "r" (en));
+}
+
+static inline unsigned int irq_getmask(void)
+{
+       unsigned int mask;
+       __asm__ __volatile__("rcsr %0, IM" : "=r" (mask));
+       return mask;
+}
+
+static inline void irq_setmask(unsigned int mask)
+{
+       __asm__ __volatile__("wcsr IM, %0" : : "r" (mask));
+}
+
+static inline unsigned int irq_pending(void)
+{
+       unsigned int pending;
+       __asm__ __volatile__("rcsr %0, IP" : "=r" (pending));
+       return pending;
+}
+
+static inline void irq_ack(unsigned int mask)
+{
+       __asm__ __volatile__("wcsr IP, %0" : : "r" (mask));
+}
+
+static inline unsigned int irq_getie(void)
+{
+       unsigned int ie;
+       __asm__ __volatile__("rcsr %0, IE" : "=r" (ie));
+       return ie;
+}
+
+static inline void irq_setie(unsigned int ie)
+{
+       __asm__ __volatile__("wcsr IE, %0" : : "r" (ie));
+}
+
+#endif /* __IRQ_H */
diff --git a/software/include/base/limits.h b/software/include/base/limits.h
new file mode 100644 (file)
index 0000000..aaf9721
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
+ * Copyright (C) Linux kernel developers
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIMITS_H
+#define __LIMITS_H
+
+#define INT_MIN ((((unsigned long)-1) >> 1) + 1)
+#define INT_MAX (((unsigned long)-1) >> 1)
+
+#endif /* __LIMITS_H */
diff --git a/software/include/base/stdarg.h b/software/include/base/stdarg.h
new file mode 100644 (file)
index 0000000..7729b7e
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
+ * Copyright (C) Linux kernel developers
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __STDARG_H
+#define __STDARG_H
+
+#include <stdlib.h>
+
+#if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4))
+#define va_start(v,l) __builtin_va_start((v),l)
+#else
+#define va_start(v,l) __builtin_stdarg_start((v),l)
+#endif
+
+#define va_arg(ap, type) \
+       __builtin_va_arg((ap), type)
+
+#define va_end(ap) \
+       __builtin_va_end(ap)
+
+#define va_list \
+       __builtin_va_list
+
+int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
+int vscnprintf(char *buf, size_t size, const char *fmt, va_list args);
+int vsprintf(char *buf, const char *fmt, va_list args);
+
+#endif /* __STDARG_H */
diff --git a/software/include/base/stdio.h b/software/include/base/stdio.h
new file mode 100644 (file)
index 0000000..5fb35a5
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __STDIO_H
+#define __STDIO_H
+
+#include <stdlib.h>
+
+int snprintf(char *buf, size_t size, const char *fmt, ...);
+int scnprintf(char *buf, size_t size, const char *fmt, ...);
+int sprintf(char *buf, const char *fmt, ...);
+
+int printf(const char *fmt, ...);
+
+#endif /* __STDIO_H */
diff --git a/software/include/base/stdlib.h b/software/include/base/stdlib.h
new file mode 100644 (file)
index 0000000..ed22bdd
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009, 2011 Sebastien Bourdeauducq
+ * Copyright (C) Linux kernel developers
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __STDLIB_H
+#define __STDLIB_H
+
+#define PRINTF_ZEROPAD 1               /* pad with zero */
+#define PRINTF_SIGN    2               /* unsigned/signed long */
+#define PRINTF_PLUS    4               /* show plus */
+#define PRINTF_SPACE   8               /* space if plus */
+#define PRINTF_LEFT    16              /* left justified */
+#define PRINTF_SPECIAL 32              /* 0x */
+#define PRINTF_LARGE   64              /* use 'ABCDEF' instead of 'abcdef' */
+
+typedef int size_t;
+typedef int ptrdiff_t;
+
+#define NULL ((void *)0)
+
+#define likely(x) x
+#define unlikely(x) x
+
+#define abs(x) ((x) > 0 ? (x) : -(x))
+
+unsigned long strtoul(const char *nptr, char **endptr, int base);
+int skip_atoi(const char **s);
+static inline int atoi(const char *nptr) {
+       return strtoul(nptr, NULL, 0);
+}
+static inline long atol(const char *nptr) {
+       return (long)atoi(nptr);
+}
+char *number(char *buf, char *end, unsigned long num, int base, int size, int precision, int type);
+long strtol(const char *nptr, char **endptr, int base);
+float atof(const char *s);
+
+unsigned int rand(void);
+void abort(void);
+
+#endif /* __STDLIB_H */
diff --git a/software/include/base/string.h b/software/include/base/string.h
new file mode 100644 (file)
index 0000000..667d2d8
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
+ * Copyright (C) Linus Torvalds and Linux kernel developers
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __STRING_H
+#define __STRING_H
+
+#include <stdlib.h>
+
+char *strchr(const char *s, int c);
+char *strrchr(const char *s, int c);
+char *strnchr(const char *s, size_t count, int c);
+char *strcpy(char *dest, const char *src);
+char *strncpy(char *dest, const char *src, size_t count);
+int strcmp(const char *cs, const char *ct);
+int strncmp(const char *cs, const char *ct, size_t count);
+size_t strlen(const char *s);
+size_t strnlen(const char *s, size_t count);
+int memcmp(const void *cs, const void *ct, size_t count);
+void *memset(void *s, int c, size_t count);
+void *memcpy(void *to, const void *from, size_t n);
+void *memmove(void *dest, const void *src, size_t count);
+char *strstr(const char *s1, const char *s2);
+
+#endif /* __STRING_H */
diff --git a/software/include/base/system.h b/software/include/base/system.h
new file mode 100644 (file)
index 0000000..5eb6a21
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SYSTEM_H
+#define __SYSTEM_H
+
+void flush_cpu_icache(void);
+void flush_cpu_dcache(void);
+__attribute__((noreturn)) void reboot(void);
+__attribute__((noreturn)) void reconf(void);
+
+#endif /* __SYSTEM_H */
diff --git a/software/include/base/uart.h b/software/include/base/uart.h
new file mode 100644 (file)
index 0000000..0c03c02
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UART_H
+#define __UART_H
+
+void uart_init(void);
+void uart_isr(void);
+void uart_sync(void);
+
+void uart_write(char c);
+char uart_read(void);
+int uart_read_nonblock(void);
+
+#endif
diff --git a/software/include/base/version.h b/software/include/base/version.h
new file mode 100644 (file)
index 0000000..3f70d0e
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __VERSION_H
+#define __VERSION_H
+
+#define VERSION "2.0-X"
+
+#endif /* __VERSION_H */
diff --git a/software/include/extra/blockdev.h b/software/include/extra/blockdev.h
new file mode 100644 (file)
index 0000000..6252d1d
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __BLOCKDEV_H
+#define __BLOCKDEV_H
+
+enum {
+       BLOCKDEV_MEMORY_CARD
+};
+
+int bd_init(int devnr);
+int bd_readblock(unsigned int block, void *buffer);
+void bd_done(void);
+
+int bd_has_part_table(int devnr);
+
+#endif /* __BLOCKDEV_H */
diff --git a/software/include/extra/crc.h b/software/include/extra/crc.h
new file mode 100644 (file)
index 0000000..3f23954
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __CRC_H
+#define __CRC_H
+
+unsigned short crc16(const unsigned char *buffer, int len);
+unsigned int crc32(const unsigned char *buffer, unsigned int len);
+
+#endif
diff --git a/software/include/extra/fatfs.h b/software/include/extra/fatfs.h
new file mode 100644 (file)
index 0000000..a6a71a8
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __FATFS_H
+#define __FATFS_H
+
+typedef int (*fatfs_dir_callback)(const char *, const char *, void *);
+
+int fatfs_init(int devnr);
+int fatfs_list_files(fatfs_dir_callback cb, void *param);
+int fatfs_load(const char *filename, char *buffer, int size, int *realsize);
+void fatfs_done(void);
+
+#endif /* __FATFS_H */
diff --git a/software/include/hw/capabilities.h b/software/include/hw/capabilities.h
new file mode 100644 (file)
index 0000000..a6dba08
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __HW_CAPABILITIES
+#define __HW_CAPABILITIES
+
+#define CAP_MEMORYCARD         (0x00000001)
+#define CAP_AC97               (0x00000002)
+#define CAP_PFPU               (0x00000004)
+#define CAP_TMU                        (0x00000008)
+#define CAP_ETHERNET           (0x00000010)
+#define CAP_FMLMETER           (0x00000020)
+#define CAP_VIDEOIN            (0x00000040)
+#define CAP_MIDI               (0x00000080)
+#define CAP_DMX                        (0x00000100)
+#define CAP_IR                 (0x00000200)
+#define CAP_USB                        (0x00000400)
+#define CAP_MEMTEST            (0x00000800)
+
+#endif /* __HW_CAPABILITIES */
diff --git a/software/include/hw/common.h b/software/include/hw/common.h
new file mode 100644 (file)
index 0000000..5d9c61a
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __HW_COMMON_H
+#define __HW_COMMON_H
+
+#ifdef __ASSEMBLER__
+#define MMPTR(x) x
+#else
+#define MMPTR(x) (*((volatile unsigned int *)(x)))
+#endif
+
+#endif
diff --git a/software/include/hw/flash.h b/software/include/hw/flash.h
new file mode 100644 (file)
index 0000000..f09de41
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __HW_FLASH_H
+#define __HW_FLASH_H
+
+#define FLASH_OFFSET_STANDBY_BITSTREAM (0x00000000) /* 640k */
+
+#define FLASH_OFFSET_RESCUE_BITSTREAM  (0x000A0000) /* 1536k */
+#define FLASH_OFFSET_RESCUE_BIOS       (0x00220000) /* 128k */
+#define FLASH_OFFSET_MAC_ADDRESS       (0x002200E0) /* within rescue BIOS */
+#define FLASH_OFFSET_RESCUE_SPLASH     (0x00240000) /* 640k */
+#define FLASH_OFFSET_RESCUE_APP                (0x002E0000) /* 4096k */
+
+#define FLASH_OFFSET_REGULAR_BITSTREAM (0x006E0000) /* 1536k */
+#define FLASH_OFFSET_REGULAR_BIOS      (0x00860000) /* 128k */
+#define FLASH_OFFSET_REGULAR_SPLASH    (0x00880000) /* 640k */
+#define FLASH_OFFSET_REGULAR_APP       (0x00920000) /* remaining space (23424k) */
+
+#endif /* __HW_FLASH_H */
diff --git a/software/include/hw/gpio.h b/software/include/hw/gpio.h
new file mode 100644 (file)
index 0000000..7ebb0c8
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __HW_GPIO_H
+#define __HW_GPIO_H
+
+/* Inputs */
+#define GPIO_BTN1      (0x00000001)
+#define GPIO_BTN2      (0x00000002)
+#define GPIO_BTN3      (0x00000004)
+
+#define GPIO_PCBREV0   (0x00000008)
+#define GPIO_PCBREV1   (0x00000010)
+#define GPIO_PCBREV2   (0x00000020)
+#define GPIO_PCBREV3   (0x00000040)
+
+/* Outputs */
+#define GPIO_LED1      (0x00000001)
+#define GPIO_LED2      (0x00000002)
+
+#endif /* __HW_GPIO_H */
diff --git a/software/include/hw/interrupts.h b/software/include/hw/interrupts.h
new file mode 100644 (file)
index 0000000..2f48cee
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __HW_INTERRUPTS_H
+#define __HW_INTERRUPTS_H
+
+#define IRQ_UART               (0x00000001) /* 0 */
+
+#endif /* __HW_INTERRUPTS_H */
diff --git a/software/include/hw/sysctl.h b/software/include/hw/sysctl.h
new file mode 100644 (file)
index 0000000..d00471b
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __HW_SYSCTL_H
+#define __HW_SYSCTL_H
+
+#include <hw/common.h>
+
+#define CSR_GPIO_IN            MMPTR(0xe0001000)
+#define CSR_GPIO_OUT           MMPTR(0xe0001004)
+#define CSR_GPIO_INTEN         MMPTR(0xe0001008)
+
+#define CSR_TIMER0_CONTROL     MMPTR(0xe0001010)
+#define CSR_TIMER0_COMPARE     MMPTR(0xe0001014)
+#define CSR_TIMER0_COUNTER     MMPTR(0xe0001018)
+
+#define CSR_TIMER1_CONTROL     MMPTR(0xe0001020)
+#define CSR_TIMER1_COMPARE     MMPTR(0xe0001024)
+#define CSR_TIMER1_COUNTER     MMPTR(0xe0001028)
+
+#define TIMER_ENABLE           (0x01)
+#define TIMER_AUTORESTART      (0x02)
+
+#define CSR_ICAP               MMPTR(0xe0001040)
+
+#define ICAP_READY             (0x01)
+
+#define ICAP_CE                        (0x10000)
+#define ICAP_WRITE             (0x20000)
+
+#define CSR_DBG_SCRATCHPAD     MMPTR(0xe0001050)
+#define CSR_DBG_CTRL           MMPTR(0xe0001054)
+
+#define DBG_CTRL_GDB_ROM_LOCK  (0x01)
+#define DBG_CTRL_BUS_ERR_EN    (0x02)
+
+#define CSR_FREQUENCY          MMPTR(0xe0001074)
+#define CSR_CAPABILITIES       MMPTR(0xe0001078)
+#define CSR_SYSTEM_ID          MMPTR(0xe000107c)
+
+#endif /* __HW_SYSCTL_H */
diff --git a/software/include/hw/uart.h b/software/include/hw/uart.h
new file mode 100644 (file)
index 0000000..5540ca4
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __HW_UART_H
+#define __HW_UART_H
+
+#include <hw/common.h>
+
+#define CSR_UART_RXTX          MMPTR(0xe0000000)
+#define CSR_UART_DIVISOR       MMPTR(0xe0000004)
+#define CSR_UART_STAT          MMPTR(0xe0000008)
+#define CSR_UART_CTRL          MMPTR(0xe000000c)
+#define CSR_UART_DEBUG         MMPTR(0xe0000010)
+
+#define UART_STAT_THRE         (0x1)
+#define UART_STAT_RX_EVT       (0x2)
+#define UART_STAT_TX_EVT       (0x4)
+
+#define UART_CTRL_RX_INT       (0x1)
+#define UART_CTRL_TX_INT       (0x2)
+#define UART_CTRL_THRU         (0x4)
+
+#define UART_DEBUG_BREAK_EN    (0x1)
+
+#endif /* __HW_UART_H */
diff --git a/software/libbase/Makefile b/software/libbase/Makefile
new file mode 100644 (file)
index 0000000..a9027a2
--- /dev/null
@@ -0,0 +1,15 @@
+MMDIR=../..
+include $(MMDIR)/software/include.mak
+
+OBJECTS=divsi3.o libc.o console.o system.o board.o uart.o softfloat.o softfloat-glue.o vsnprintf.o atof.o
+
+all: libbase.a
+
+libbase.a: $(OBJECTS)
+       $(AR) clr libbase.a $(OBJECTS)
+       $(RANLIB) libbase.a
+
+.PHONY: clean
+
+clean:
+       rm -f *.o libbase.a .*~ *~ Makefile.bak
diff --git a/software/libbase/atof.c b/software/libbase/atof.c
new file mode 100644 (file)
index 0000000..19075c9
--- /dev/null
@@ -0,0 +1,84 @@
+/*  atof.c: converts an ASCII string to float
+
+    Copyright (C) 2003  Jesus Calvino-Fraga, jesusc@ieee.org
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, 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
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA */
+
+#include <stdlib.h>
+#include <ctype.h>
+
+float atof(const char * s)
+{
+       float value, fraction;
+       char iexp;
+       char sign;
+
+       //Skip leading blanks
+       while (isspace(*s)) s++;
+
+       //Get the sign
+       if (*s == '-')
+       {
+               sign=1;
+               s++;
+       }
+       else
+       {
+               sign=0;
+               if (*s == '+') s++;
+       }
+
+       //Get the integer part
+       for (value=0.0f; isdigit(*s); s++)
+       {
+               value=10.0f*value+(*s-'0');
+       }
+
+       //Get the fraction
+       if (*s == '.')
+       {
+               s++;
+               for (fraction=0.1f; isdigit(*s); s++)
+               {
+                       value+=(*s-'0')*fraction;
+                       fraction*=0.1f;
+               }
+       }
+
+       //Finally, the exponent (not very efficient, but enough for now)
+       if (toupper(*s)=='E')
+       {
+               s++;
+               iexp=(char)atoi(s);
+               {
+                       while(iexp!=0)
+                       {
+                               if(iexp<0)
+                               {
+                                       value*=0.1f;
+                                       iexp++;
+                               }
+                               else
+                               {
+                                       value*=10.0f;
+                                       iexp--;
+                               }
+                       }
+               }
+       }
+
+       if(sign) value*=-1.0f;
+       return (value);
+}
diff --git a/software/libbase/board.c b/software/libbase/board.c
new file mode 100644 (file)
index 0000000..b81779e
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009, 2011 Sebastien Bourdeauducq
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <hw/sysctl.h>
+#include <hw/gpio.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <board.h>
+
+static const struct board_desc boards[1] = {
+       {
+               .id = 0x4D31, /* M1 */
+               .name = "Milkymist One",
+               .ethernet_phyadr = 1
+       },
+};
+
+const struct board_desc *get_board_desc_id(unsigned short int id)
+{
+       unsigned int i;
+
+       for(i=0;i<sizeof(boards)/sizeof(boards[0]);i++)
+               if(boards[i].id == id)
+                       return &boards[i];
+       return NULL;
+}
+
+const struct board_desc *get_board_desc(void)
+{
+       return get_board_desc_id(CSR_SYSTEM_ID & 0xffff);
+}
+
+int get_pcb_revision(void)
+{
+       int r;
+       unsigned int io;
+
+       io = CSR_GPIO_IN;
+       r = 0;
+       if(io & GPIO_PCBREV0)
+               r |= 0x1;
+       if(io & GPIO_PCBREV1)
+               r |= 0x2;
+       if(io & GPIO_PCBREV2)
+               r |= 0x4;
+       if(io & GPIO_PCBREV3)
+               r |= 0x8;
+       return r;
+}
+
+void get_soc_version(unsigned int *major, unsigned int *minor, unsigned int *subminor, unsigned int *rc)
+{
+       unsigned int id;
+
+       id = CSR_SYSTEM_ID;
+       *major = (id & 0xf0000000) >> 28;
+       *minor = (id & 0x0f000000) >> 24;
+       *subminor = (id & 0x00f00000) >> 20;
+       *rc = (id & 0x000f0000) >> 16;
+}
+
+void get_soc_version_formatted(char *version)
+{
+       unsigned int major, minor, subminor, rc;
+
+       get_soc_version(&major, &minor, &subminor, &rc);
+
+       version += sprintf(version, "%u.%u", major, minor);
+       if(subminor != 0)
+               version += sprintf(version, ".%u", subminor);
+       if(rc != 0)
+               sprintf(version, "RC%u", rc);
+}
diff --git a/software/libbase/console.c b/software/libbase/console.c
new file mode 100644 (file)
index 0000000..d27bff3
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <uart.h>
+#include <console.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <irq.h>
+#include <hw/interrupts.h>
+
+static console_write_hook write_hook;
+static console_read_hook read_hook;
+static console_read_nonblock_hook read_nonblock_hook;
+
+void console_set_write_hook(console_write_hook h)
+{
+       write_hook = h;
+}
+
+void console_set_read_hook(console_read_hook r, console_read_nonblock_hook rn)
+{
+       read_hook = r;
+       read_nonblock_hook = rn;
+}
+
+static void writechar(char c)
+{
+       uart_write(c);
+       if(write_hook != NULL)
+               write_hook(c);
+}
+
+char readchar(void)
+{
+       while(1) {
+               if(uart_read_nonblock())
+                       return uart_read();
+               if((read_nonblock_hook != NULL) && read_nonblock_hook())
+                       return read_hook();
+       }
+}
+
+int readchar_nonblock(void)
+{
+       return (uart_read_nonblock()
+               || ((read_nonblock_hook != NULL) && read_nonblock_hook()));
+}
+
+int puts(const char *s)
+{
+       unsigned int oldmask;
+
+       oldmask = irq_getmask();
+       irq_setmask(IRQ_UART); // HACK: prevent UART data loss
+
+       while(*s) {
+               writechar(*s);
+               s++;
+       }
+       writechar('\n');
+       
+       irq_setmask(oldmask);
+       return 1;
+}
+
+void putsnonl(const char *s)
+{
+       unsigned int oldmask;
+
+       oldmask = irq_getmask();
+       irq_setmask(IRQ_UART); // HACK: prevent UART data loss
+       
+       while(*s) {
+               writechar(*s);
+               s++;
+       }
+       
+       irq_setmask(oldmask);
+}
+
+int printf(const char *fmt, ...)
+{
+       va_list args;
+       int len;
+       char outbuf[256];
+
+       va_start(args, fmt);
+       len = vscnprintf(outbuf, sizeof(outbuf), fmt, args);
+       va_end(args);
+       outbuf[len] = 0;
+       putsnonl(outbuf);
+
+       return len;
+}
diff --git a/software/libbase/divsi3.c b/software/libbase/divsi3.c
new file mode 100644 (file)
index 0000000..35d171e
--- /dev/null
@@ -0,0 +1,53 @@
+#define divnorm(num, den, sign)                \
+{                                              \
+  if(num < 0)                                  \
+    {                                          \
+      num = -num;                              \
+      sign = 1;                                        \
+    }                                          \
+  else                                                 \
+    {                                          \
+      sign = 0;                                        \
+    }                                          \
+                                               \
+  if(den < 0)                                  \
+    {                                          \
+      den = - den;                             \
+      sign = 1 - sign;                         \
+    }                                          \
+}
+
+#define exitdiv(sign, res) if (sign) { res = - res;} return res;
+
+long __divsi3 (long numerator, long denominator)
+{
+       int sign;
+       long dividend;
+
+       divnorm(numerator, denominator, sign);
+
+       dividend = (unsigned int)numerator/(unsigned int)denominator;
+       exitdiv(sign, dividend);
+}
+
+long __modsi3 (long numerator, long denominator)
+{
+       int sign;
+       long res;
+
+       if(numerator < 0) {
+               numerator = -numerator;
+               sign = 1;
+       } else
+               sign = 0;
+
+       if(denominator < 0)
+               denominator = -denominator;
+
+       res = (unsigned int)numerator % (unsigned int)denominator;
+
+       if(sign)
+               return -res;
+       else
+               return res;
+}
diff --git a/software/libbase/libc.c b/software/libbase/libc.c
new file mode 100644 (file)
index 0000000..565927a
--- /dev/null
@@ -0,0 +1,577 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009, 2010, 2011 Sebastien Bourdeauducq
+ * Copyright (C) Linus Torvalds and Linux kernel developers
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <limits.h>
+
+/**
+ * strchr - Find the first occurrence of a character in a string
+ * @s: The string to be searched
+ * @c: The character to search for
+ */
+char *strchr(const char *s, int c)
+{
+       for (; *s != (char)c; ++s)
+               if (*s == '\0')
+                       return NULL;
+       return (char *)s;
+}
+
+/**
+ * strrchr - Find the last occurrence of a character in a string
+ * @s: The string to be searched
+ * @c: The character to search for
+ */
+char *strrchr(const char *s, int c)
+{
+       const char *p = s + strlen(s);
+       do {
+           if (*p == (char)c)
+               return (char *)p;
+       } while (--p >= s);
+       return NULL;
+}
+
+/**
+ * strnchr - Find a character in a length limited string
+ * @s: The string to be searched
+ * @count: The number of characters to be searched
+ * @c: The character to search for
+ */
+char *strnchr(const char *s, size_t count, int c)
+{
+       for (; count-- && *s != '\0'; ++s)
+               if (*s == (char)c)
+                       return (char *)s;
+       return NULL;
+}
+
+/**
+ * strcpy - Copy a %NUL terminated string
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ */
+char *strcpy(char *dest, const char *src)
+{
+       char *tmp = dest;
+
+       while ((*dest++ = *src++) != '\0')
+               /* nothing */;
+       return tmp;
+}
+
+/**
+ * strncpy - Copy a length-limited, %NUL-terminated string
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ * @count: The maximum number of bytes to copy
+ *
+ * The result is not %NUL-terminated if the source exceeds
+ * @count bytes.
+ *
+ * In the case where the length of @src is less than  that  of
+ * count, the remainder of @dest will be padded with %NUL.
+ *
+ */
+char *strncpy(char *dest, const char *src, size_t count)
+{
+       char *tmp = dest;
+       
+       while (count) {
+               if ((*tmp = *src) != 0)
+                       src++;
+               tmp++;
+               count--;
+       }
+       return dest;
+}
+
+/**
+ * strcmp - Compare two strings
+ * @cs: One string
+ * @ct: Another string
+ */
+int strcmp(const char *cs, const char *ct)
+{
+       signed char __res;
+
+       while (1) {
+               if ((__res = *cs - *ct++) != 0 || !*cs++)
+                       break;
+       }
+       return __res;
+}
+
+/**
+ * strncmp - Compare two strings using the first characters only
+ * @cs: One string
+ * @ct: Another string
+ * @count: Number of characters
+ */
+int strncmp(const char *cs, const char *ct, size_t count)
+{
+       signed char __res;
+       size_t n;
+
+       n = 0;
+       __res = 0;
+       while (n < count) {
+               if ((__res = *cs - *ct++) != 0 || !*cs++)
+                       break;
+               n++;
+       }
+       return __res;
+}
+
+/**
+ * strlen - Find the length of a string
+ * @s: The string to be sized
+ */
+size_t strlen(const char *s)
+{
+       const char *sc;
+
+       for (sc = s; *sc != '\0'; ++sc)
+               /* nothing */;
+       return sc - s;
+}
+
+/**
+ * strnlen - Find the length of a length-limited string
+ * @s: The string to be sized
+ * @count: The maximum number of bytes to search
+ */
+size_t strnlen(const char *s, size_t count)
+{
+       const char *sc;
+
+       for (sc = s; count-- && *sc != '\0'; ++sc)
+               /* nothing */;
+       return sc - s;
+}
+
+/**
+ * memcmp - Compare two areas of memory
+ * @cs: One area of memory
+ * @ct: Another area of memory
+ * @count: The size of the area.
+ */
+int memcmp(const void *cs, const void *ct, size_t count)
+{
+       const unsigned char *su1, *su2;
+       int res = 0;
+
+       for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
+               if ((res = *su1 - *su2) != 0)
+                       break;
+       return res;
+}
+
+/**
+ * memset - Fill a region of memory with the given value
+ * @s: Pointer to the start of the area.
+ * @c: The byte to fill the area with
+ * @count: The size of the area.
+ */
+void *memset(void *s, int c, size_t count)
+{
+       char *xs = s;
+
+       while (count--)
+               *xs++ = c;
+       return s;
+}
+
+/**
+ * memcpy - Copies one area of memory to another
+ * @dest: Destination
+ * @src: Source
+ * @n: The size to copy.
+ */
+void *memcpy(void *to, const void *from, size_t n)
+{
+       void *xto = to;
+       size_t temp;
+
+       if(!n)
+               return xto;
+       if((long)to & 1) {
+               char *cto = to;
+               const char *cfrom = from;
+               *cto++ = *cfrom++;
+               to = cto;
+               from = cfrom;
+               n--;
+       }
+       if(n > 2 && (long)to & 2) {
+               short *sto = to;
+               const short *sfrom = from;
+               *sto++ = *sfrom++;
+               to = sto;
+               from = sfrom;
+               n -= 2;
+       }
+       temp = n >> 2;
+       if(temp) {
+               long *lto = to;
+               const long *lfrom = from;
+               for(; temp; temp--)
+               *lto++ = *lfrom++;
+               to = lto;
+               from = lfrom;
+       }
+       if(n & 2) {
+               short *sto = to;
+               const short *sfrom = from;
+               *sto++ = *sfrom++;
+               to = sto;
+               from = sfrom;
+       }
+       if(n & 1) {
+               char *cto = to;
+               const char *cfrom = from;
+               *cto = *cfrom;
+       }
+       return xto;
+}
+
+/**
+ * memmove - Copies one area of memory to another, overlap possible
+ * @dest: Destination
+ * @src: Source
+ * @n: The size to copy.
+ */
+void *memmove(void *dest, const void *src, size_t count)
+{
+       char *tmp, *s;
+
+       if(dest <= src) {
+               tmp = (char *) dest;
+               s = (char *) src;
+               while(count--)
+                       *tmp++ = *s++;
+       } else {
+               tmp = (char *)dest + count;
+               s = (char *)src + count;
+               while(count--)
+                       *--tmp = *--s;
+       }
+
+       return dest;
+}
+
+/**
+ * strstr - Find the first substring in a %NUL terminated string
+ * @s1: The string to be searched
+ * @s2: The string to search for
+ */
+char *strstr(const char *s1, const char *s2)
+{
+       size_t l1, l2;
+
+       l2 = strlen(s2);
+       if (!l2)
+               return (char *)s1;
+       l1 = strlen(s1);
+       while (l1 >= l2) {
+               l1--;
+               if (!memcmp(s1, s2, l2))
+                       return (char *)s1;
+               s1++;
+       }
+       return NULL;
+}
+
+/**
+ * strtoul - convert a string to an unsigned long
+ * @nptr: The start of the string
+ * @endptr: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+unsigned long strtoul(const char *nptr, char **endptr, int base)
+{
+       unsigned long result = 0,value;
+
+       if (!base) {
+               base = 10;
+               if (*nptr == '0') {
+                       base = 8;
+                       nptr++;
+                       if ((toupper(*nptr) == 'X') && isxdigit(nptr[1])) {
+                               nptr++;
+                               base = 16;
+                       }
+               }
+       } else if (base == 16) {
+               if (nptr[0] == '0' && toupper(nptr[1]) == 'X')
+                       nptr += 2;
+       }
+       while (isxdigit(*nptr) &&
+              (value = isdigit(*nptr) ? *nptr-'0' : toupper(*nptr)-'A'+10) < base) {
+               result = result*base + value;
+               nptr++;
+       }
+       if (endptr)
+               *endptr = (char *)nptr;
+       return result;
+}
+
+/**
+ * strtol - convert a string to a signed long
+ * @nptr: The start of the string
+ * @endptr: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+long strtol(const char *nptr, char **endptr, int base)
+{
+       if(*nptr=='-')
+               return -strtoul(nptr+1,endptr,base);
+       return strtoul(nptr,endptr,base);
+}
+
+int skip_atoi(const char **s)
+{
+       int i=0;
+
+       while (isdigit(**s))
+               i = i*10 + *((*s)++) - '0';
+       return i;
+}
+
+char *number(char *buf, char *end, unsigned long num, int base, int size, int precision, int type)
+{
+       char c,sign,tmp[66];
+       const char *digits;
+       static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+       static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+       int i;
+
+       digits = (type & PRINTF_LARGE) ? large_digits : small_digits;
+       if (type & PRINTF_LEFT)
+               type &= ~PRINTF_ZEROPAD;
+       if (base < 2 || base > 36)
+               return NULL;
+       c = (type & PRINTF_ZEROPAD) ? '0' : ' ';
+       sign = 0;
+       if (type & PRINTF_SIGN) {
+               if ((signed long) num < 0) {
+                       sign = '-';
+                       num = - (signed long) num;
+                       size--;
+               } else if (type & PRINTF_PLUS) {
+                       sign = '+';
+                       size--;
+               } else if (type & PRINTF_SPACE) {
+                       sign = ' ';
+                       size--;
+               }
+       }
+       if (type & PRINTF_SPECIAL) {
+               if (base == 16)
+                       size -= 2;
+               else if (base == 8)
+                       size--;
+       }
+       i = 0;
+       if (num == 0)
+               tmp[i++]='0';
+       else while (num != 0) {
+               tmp[i++] = digits[num % base];
+               num = num / base;
+       }
+       if (i > precision)
+               precision = i;
+       size -= precision;
+       if (!(type&(PRINTF_ZEROPAD+PRINTF_LEFT))) {
+               while(size-->0) {
+                       if (buf < end)
+                               *buf = ' ';
+                       ++buf;
+               }
+       }
+       if (sign) {
+               if (buf < end)
+                       *buf = sign;
+               ++buf;
+       }
+       if (type & PRINTF_SPECIAL) {
+               if (base==8) {
+                       if (buf < end)
+                               *buf = '0';
+                       ++buf;
+               } else if (base==16) {
+                       if (buf < end)
+                               *buf = '0';
+                       ++buf;
+                       if (buf < end)
+                               *buf = digits[33];
+                       ++buf;
+               }
+       }
+       if (!(type & PRINTF_LEFT)) {
+               while (size-- > 0) {
+                       if (buf < end)
+                               *buf = c;
+                       ++buf;
+               }
+       }
+       while (i < precision--) {
+               if (buf < end)
+                       *buf = '0';
+               ++buf;
+       }
+       while (i-- > 0) {
+               if (buf < end)
+                       *buf = tmp[i];
+               ++buf;
+       }
+       while (size-- > 0) {
+               if (buf < end)
+                       *buf = ' ';
+               ++buf;
+       }
+       return buf;
+}
+
+/**
+ * vscnprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @args: Arguments for the format string
+ *
+ * The return value is the number of characters which have been written into
+ * the @buf not including the trailing '\0'. If @size is <= 0 the function
+ * returns 0.
+ *
+ * Call this function if you are already dealing with a va_list.
+ * You probably want scnprintf() instead.
+ */
+int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
+{
+       int i;
+
+       i=vsnprintf(buf,size,fmt,args);
+       return (i >= size) ? (size - 1) : i;
+}
+
+
+/**
+ * snprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @...: Arguments for the format string
+ *
+ * The return value is the number of characters which would be
+ * generated for the given input, excluding the trailing null,
+ * as per ISO C99.  If the return is greater than or equal to
+ * @size, the resulting string is truncated.
+ */
+int snprintf(char * buf, size_t size, const char *fmt, ...)
+{
+       va_list args;
+       int i;
+
+       va_start(args, fmt);
+       i=vsnprintf(buf,size,fmt,args);
+       va_end(args);
+       return i;
+}
+
+/**
+ * scnprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @...: Arguments for the format string
+ *
+ * The return value is the number of characters written into @buf not including
+ * the trailing '\0'. If @size is <= 0 the function returns 0.
+ */
+
+int scnprintf(char * buf, size_t size, const char *fmt, ...)
+{
+       va_list args;
+       int i;
+
+       va_start(args, fmt);
+       i = vsnprintf(buf, size, fmt, args);
+       va_end(args);
+       return (i >= size) ? (size - 1) : i;
+}
+
+/**
+ * vsprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @fmt: The format string to use
+ * @args: Arguments for the format string
+ *
+ * The function returns the number of characters written
+ * into @buf. Use vsnprintf() or vscnprintf() in order to avoid
+ * buffer overflows.
+ *
+ * Call this function if you are already dealing with a va_list.
+ * You probably want sprintf() instead.
+ */
+int vsprintf(char *buf, const char *fmt, va_list args)
+{
+       return vsnprintf(buf, INT_MAX, fmt, args);
+}
+
+/**
+ * sprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @fmt: The format string to use
+ * @...: Arguments for the format string
+ *
+ * The function returns the number of characters written
+ * into @buf. Use snprintf() or scnprintf() in order to avoid
+ * buffer overflows.
+ */
+int sprintf(char * buf, const char *fmt, ...)
+{
+       va_list args;
+       int i;
+
+       va_start(args, fmt);
+       i=vsnprintf(buf, INT_MAX, fmt, args);
+       va_end(args);
+       return i;
+}
+
+/**
+ * rand - Returns a pseudo random number
+ */
+
+static unsigned int seed;
+unsigned int rand(void)
+{
+       seed = 129 * seed + 907633385;
+       return seed;
+}
+
+void abort(void)
+{
+       printf("Aborted.");
+       while(1);
+}
diff --git a/software/libbase/milieu.h b/software/libbase/milieu.h
new file mode 100644 (file)
index 0000000..58d688d
--- /dev/null
@@ -0,0 +1,126 @@
+
+/*
+===============================================================================
+
+This C header file is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2.
+
+Written by John R. Hauser.  This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704.  Funding was partially provided by the
+National Science Foundation under grant MIP-9311980.  The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek.  More information
+is available through the Web page `http://http.cs.berkeley.edu/~jhauser/
+arithmetic/softfloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR.  USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these three paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+/*
+-------------------------------------------------------------------------------
+Common integer types and flags.
+-------------------------------------------------------------------------------
+*/
+
+/*
+-------------------------------------------------------------------------------
+One of the macros `BIGENDIAN' or `LITTLEENDIAN' must be defined.
+-------------------------------------------------------------------------------
+*/
+#define BIGENDIAN
+
+/*
+-------------------------------------------------------------------------------
+The macro `BITS64' can be defined to indicate that 64-bit integer types are
+supported by the compiler.
+-------------------------------------------------------------------------------
+*/
+//#define BITS64
+
+/*
+-------------------------------------------------------------------------------
+Each of the following `typedef's defines the most convenient type that holds
+integers of at least as many bits as specified.  For example, `uint8' should
+be the most convenient type that can hold unsigned integers of as many as
+8 bits.  The `flag' type must be able to hold either a 0 or 1.  For most
+implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed
+to the same as `int'.
+-------------------------------------------------------------------------------
+*/
+typedef int flag;
+typedef int uint8;
+typedef int int8;
+typedef int uint16;
+typedef int int16;
+typedef unsigned int uint32;
+typedef signed int int32;
+#ifdef BITS64
+typedef unsigned long long int bits64;
+typedef signed long long int sbits64;
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Each of the following `typedef's defines a type that holds integers
+of _exactly_ the number of bits specified.  For instance, for most
+implementation of C, `bits16' and `sbits16' should be `typedef'ed to
+`unsigned short int' and `signed short int' (or `short int'), respectively.
+-------------------------------------------------------------------------------
+*/
+typedef unsigned char bits8;
+typedef signed char sbits8;
+typedef unsigned short int bits16;
+typedef signed short int sbits16;
+typedef unsigned int bits32;
+typedef signed int sbits32;
+#ifdef BITS64
+typedef unsigned long long int uint64;
+typedef signed long long int int64;
+#endif
+
+#ifdef BITS64
+/*
+-------------------------------------------------------------------------------
+The `LIT64' macro takes as its argument a textual integer literal and if
+necessary ``marks'' the literal as having a 64-bit integer type.  For
+example, the Gnu C Compiler (`gcc') requires that 64-bit literals be
+appended with the letters `LL' standing for `long long', which is `gcc's
+name for the 64-bit integer type.  Some compilers may allow `LIT64' to be
+defined as the identity macro:  `#define LIT64( a ) a'.
+-------------------------------------------------------------------------------
+*/
+#define LIT64( a ) a##LL
+#endif
+
+/*
+-------------------------------------------------------------------------------
+The macro `INLINE' can be used before functions that should be inlined.  If
+a compiler does not support explicit inlining, this macro should be defined
+to be `static'.
+-------------------------------------------------------------------------------
+*/
+#define INLINE extern inline
+
+/*
+-------------------------------------------------------------------------------
+Symbolic Boolean literals.
+-------------------------------------------------------------------------------
+*/
+enum {
+    FALSE = 0,
+    TRUE  = 1
+};
+
diff --git a/software/libbase/softfloat-glue.c b/software/libbase/softfloat-glue.c
new file mode 100644 (file)
index 0000000..2d7f205
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "softfloat.h"
+
+/*
+ * 'Equal' wrapper. This returns 0 if the numbers are equal, or (1 | -1)
+ * otherwise. So we need to invert the output.
+ */
+int __eqsf2(float32 a, float32 b)
+{
+       return !float32_eq(a, b);
+}
+
+/*
+ * 'Not Equal' wrapper. This returns -1 or 1 (say, 1!) if the numbers are
+ * not equal, 0 otherwise. However no not equal call is provided, so we have
+ * to use an 'equal' call and invert the result. The result is already
+ * inverted though! Confusing?!
+ */
+int __nesf2(float32 a, float32 b)
+{
+       return !float32_eq(a, b);
+}
+
+/*
+ * 'Greater Than' wrapper. This returns 1 if the number is greater, 0
+ * or -1 otherwise. Unfortunately, no such function exists. We have to
+ * instead compare the numbers using the 'less than' calls in order to
+ * make up our mind. This means that we can call 'less than or equal' and
+ * invert the result.
+ */
+int __gtsf2(float32 a, float32 b)
+{
+       return !float32_le(a, b);
+}
+
+/*
+ * 'Greater Than or Equal' wrapper. We emulate this by inverting the result
+ * of a 'less than' call.
+ */
+int __gesf2(float32 a, float32 b)
+{
+       return !float32_lt(a, b);
+}
+
+/*
+ * 'Less Than' wrapper.
+ */
+int __ltsf2(float32 a, float32 b)
+{
+       return float32_lt(a, b);
+}
+
+/*
+ * 'Less Than or Equal' wrapper. A 0 must turn into a 1, and a 1 into a 0.
+ */
+int __lesf2(float32 a, float32 b)
+{
+       return !float32_le(a, b);
+}
+
+/*
+ * Float negate... This isn't provided by the library, but it's hardly the
+ * hardest function in the world to write... :) In fact, because of the
+ * position in the registers of arguments, the double precision version can
+ * go here too ;-)
+ */
+float32 __negsf2(float32 x)
+{
+       return x ^ 0x80000000;
+}
+
+/*
+ * 32-bit operations.
+ */
+float32 __addsf3(float32 a, float32 b)
+{
+       return float32_add(a, b);
+}
+
+float32 __subsf3(float32 a, float32 b)
+{
+       return float32_sub(a, b);
+}
+
+float32 __mulsf3(float32 a, float32 b)
+{
+       return float32_mul(a, b);
+}
+
+float32 __divsf3(float32 a, float32 b)
+{
+       return float32_div(a, b);
+}
+
+float32 __floatsisf(int x)
+{
+       return int32_to_float32(x);
+}
+
+int __fixsfsi(float32 x)
+{
+       return float32_to_int32_round_to_zero(x);
+}
+
+unsigned int __fixunssfsi(float32 x)
+{
+       return float32_to_int32_round_to_zero(x); // XXX
+}
+
diff --git a/software/libbase/softfloat-macros.h b/software/libbase/softfloat-macros.h
new file mode 100644 (file)
index 0000000..40d1182
--- /dev/null
@@ -0,0 +1,646 @@
+
+/*
+===============================================================================
+
+This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2.
+
+Written by John R. Hauser.  This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704.  Funding was partially provided by the
+National Science Foundation under grant MIP-9311980.  The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek.  More information
+is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/softfloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR.  USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these three paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+/*
+-------------------------------------------------------------------------------
+Shifts `a' right by the number of bits given in `count'.  If any nonzero
+bits are shifted off, they are ``jammed'' into the least significant bit of
+the result by setting the least significant bit to 1.  The value of `count'
+can be arbitrarily large; in particular, if `count' is greater than 32, the
+result will be either 0 or 1, depending on whether `a' is zero or nonzero.
+The result is stored in the location pointed to by `zPtr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void shift32RightJamming( bits32 a, int16 count, bits32 *zPtr )
+{
+    bits32 z;
+
+    if ( count == 0 ) {
+        z = a;
+    }
+    else if ( count < 32 ) {
+        z = ( a>>count ) | ( ( a<<( ( - count ) & 31 ) ) != 0 );
+    }
+    else {
+        z = ( a != 0 );
+    }
+    *zPtr = z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Shifts the 64-bit value formed by concatenating `a0' and `a1' right by the
+number of bits given in `count'.  Any bits shifted off are lost.  The value
+of `count' can be arbitrarily large; in particular, if `count' is greater
+than 64, the result will be 0.  The result is broken into two 32-bit pieces
+which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ shift64Right(
+     bits32 a0, bits32 a1, int16 count, bits32 *z0Ptr, bits32 *z1Ptr )
+{
+    bits32 z0, z1;
+    int8 negCount = ( - count ) & 31;
+
+    if ( count == 0 ) {
+        z1 = a1;
+        z0 = a0;
+    }
+    else if ( count < 32 ) {
+        z1 = ( a0<<negCount ) | ( a1>>count );
+        z0 = a0>>count;
+    }
+    else {
+        z1 = ( count < 64 ) ? ( a0>>( count & 31 ) ) : 0;
+        z0 = 0;
+    }
+    *z1Ptr = z1;
+    *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Shifts the 64-bit value formed by concatenating `a0' and `a1' right by the
+number of bits given in `count'.  If any nonzero bits are shifted off, they
+are ``jammed'' into the least significant bit of the result by setting the
+least significant bit to 1.  The value of `count' can be arbitrarily large;
+in particular, if `count' is greater than 64, the result will be either 0
+or 1, depending on whether the concatenation of `a0' and `a1' is zero or
+nonzero.  The result is broken into two 32-bit pieces which are stored at
+the locations pointed to by `z0Ptr' and `z1Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ shift64RightJamming(
+     bits32 a0, bits32 a1, int16 count, bits32 *z0Ptr, bits32 *z1Ptr )
+{
+    bits32 z0, z1;
+    int8 negCount = ( - count ) & 31;
+
+    if ( count == 0 ) {
+        z1 = a1;
+        z0 = a0;
+    }
+    else if ( count < 32 ) {
+        z1 = ( a0<<negCount ) | ( a1>>count ) | ( ( a1<<negCount ) != 0 );
+        z0 = a0>>count;
+    }
+    else {
+        if ( count == 32 ) {
+            z1 = a0 | ( a1 != 0 );
+        }
+        else if ( count < 64 ) {
+            z1 = ( a0>>( count & 31 ) ) | ( ( ( a0<<negCount ) | a1 ) != 0 );
+        }
+        else {
+            z1 = ( ( a0 | a1 ) != 0 );
+        }
+        z0 = 0;
+    }
+    *z1Ptr = z1;
+    *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Shifts the 96-bit value formed by concatenating `a0', `a1', and `a2' right
+by 32 _plus_ the number of bits given in `count'.  The shifted result is
+at most 64 nonzero bits; these are broken into two 32-bit pieces which are
+stored at the locations pointed to by `z0Ptr' and `z1Ptr'.  The bits shifted
+off form a third 32-bit result as follows:  The _last_ bit shifted off is
+the most-significant bit of the extra result, and the other 31 bits of the
+extra result are all zero if and only if _all_but_the_last_ bits shifted off
+were all zero.  This extra result is stored in the location pointed to by
+`z2Ptr'.  The value of `count' can be arbitrarily large.
+    (This routine makes more sense if `a0', `a1', and `a2' are considered
+to form a fixed-point value with binary point between `a1' and `a2'.  This
+fixed-point value is shifted right by the number of bits given in `count',
+and the integer part of the result is returned at the locations pointed to
+by `z0Ptr' and `z1Ptr'.  The fractional part of the result may be slightly
+corrupted as described above, and is returned at the location pointed to by
+`z2Ptr'.)
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ shift64ExtraRightJamming(
+     bits32 a0,
+     bits32 a1,
+     bits32 a2,
+     int16 count,
+     bits32 *z0Ptr,
+     bits32 *z1Ptr,
+     bits32 *z2Ptr
+ )
+{
+    bits32 z0, z1, z2;
+    int8 negCount = ( - count ) & 31;
+
+    if ( count == 0 ) {
+        z2 = a2;
+        z1 = a1;
+        z0 = a0;
+    }
+    else {
+        if ( count < 32 ) {
+            z2 = a1<<negCount;
+            z1 = ( a0<<negCount ) | ( a1>>count );
+            z0 = a0>>count;
+        }
+        else {
+            if ( count == 32 ) {
+                z2 = a1;
+                z1 = a0;
+            }
+            else {
+                a2 |= a1;
+                if ( count < 64 ) {
+                    z2 = a0<<negCount;
+                    z1 = a0>>( count & 31 );
+                }
+                else {
+                    z2 = ( count == 64 ) ? a0 : ( a0 != 0 );
+                    z1 = 0;
+                }
+            }
+            z0 = 0;
+        }
+        z2 |= ( a2 != 0 );
+    }
+    *z2Ptr = z2;
+    *z1Ptr = z1;
+    *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Shifts the 64-bit value formed by concatenating `a0' and `a1' left by the
+number of bits given in `count'.  Any bits shifted off are lost.  The value
+of `count' must be less than 32.  The result is broken into two 32-bit
+pieces which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ shortShift64Left(
+     bits32 a0, bits32 a1, int16 count, bits32 *z0Ptr, bits32 *z1Ptr )
+{
+
+    *z1Ptr = a1<<count;
+    *z0Ptr =
+        ( count == 0 ) ? a0 : ( a0<<count ) | ( a1>>( ( - count ) & 31 ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Shifts the 96-bit value formed by concatenating `a0', `a1', and `a2' left by
+the number of bits given in `count'.  Any bits shifted off are lost.  The
+value of `count' must be less than 32.  The result is broken into three
+32-bit pieces which are stored at the locations pointed to by `z0Ptr',
+`z1Ptr', and `z2Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ shortShift96Left(
+     bits32 a0,
+     bits32 a1,
+     bits32 a2,
+     int16 count,
+     bits32 *z0Ptr,
+     bits32 *z1Ptr,
+     bits32 *z2Ptr
+ )
+{
+    bits32 z0, z1, z2;
+    int8 negCount;
+
+    z2 = a2<<count;
+    z1 = a1<<count;
+    z0 = a0<<count;
+    if ( 0 < count ) {
+        negCount = ( ( - count ) & 31 );
+        z1 |= a2>>negCount;
+        z0 |= a1>>negCount;
+    }
+    *z2Ptr = z2;
+    *z1Ptr = z1;
+    *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Adds the 64-bit value formed by concatenating `a0' and `a1' to the 64-bit
+value formed by concatenating `b0' and `b1'.  Addition is modulo 2^64, so
+any carry out is lost.  The result is broken into two 32-bit pieces which
+are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ add64(
+     bits32 a0, bits32 a1, bits32 b0, bits32 b1, bits32 *z0Ptr, bits32 *z1Ptr )
+{
+    bits32 z1;
+
+    z1 = a1 + b1;
+    *z1Ptr = z1;
+    *z0Ptr = a0 + b0 + ( z1 < a1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Adds the 96-bit value formed by concatenating `a0', `a1', and `a2' to the
+96-bit value formed by concatenating `b0', `b1', and `b2'.  Addition is
+modulo 2^96, so any carry out is lost.  The result is broken into three
+32-bit pieces which are stored at the locations pointed to by `z0Ptr',
+`z1Ptr', and `z2Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ add96(
+     bits32 a0,
+     bits32 a1,
+     bits32 a2,
+     bits32 b0,
+     bits32 b1,
+     bits32 b2,
+     bits32 *z0Ptr,
+     bits32 *z1Ptr,
+     bits32 *z2Ptr
+ )
+{
+    bits32 z0, z1, z2;
+    int8 carry0, carry1;
+
+    z2 = a2 + b2;
+    carry1 = ( z2 < a2 );
+    z1 = a1 + b1;
+    carry0 = ( z1 < a1 );
+    z0 = a0 + b0;
+    z1 += carry1;
+    z0 += ( z1 < carry1 );
+    z0 += carry0;
+    *z2Ptr = z2;
+    *z1Ptr = z1;
+    *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Subtracts the 64-bit value formed by concatenating `b0' and `b1' from the
+64-bit value formed by concatenating `a0' and `a1'.  Subtraction is modulo
+2^64, so any borrow out (carry out) is lost.  The result is broken into two
+32-bit pieces which are stored at the locations pointed to by `z0Ptr' and
+`z1Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ sub64(
+     bits32 a0, bits32 a1, bits32 b0, bits32 b1, bits32 *z0Ptr, bits32 *z1Ptr )
+{
+
+    *z1Ptr = a1 - b1;
+    *z0Ptr = a0 - b0 - ( a1 < b1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Subtracts the 96-bit value formed by concatenating `b0', `b1', and `b2' from
+the 96-bit value formed by concatenating `a0', `a1', and `a2'.  Subtraction
+is modulo 2^96, so any borrow out (carry out) is lost.  The result is broken
+into three 32-bit pieces which are stored at the locations pointed to by
+`z0Ptr', `z1Ptr', and `z2Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ sub96(
+     bits32 a0,
+     bits32 a1,
+     bits32 a2,
+     bits32 b0,
+     bits32 b1,
+     bits32 b2,
+     bits32 *z0Ptr,
+     bits32 *z1Ptr,
+     bits32 *z2Ptr
+ )
+{
+    bits32 z0, z1, z2;
+    int8 borrow0, borrow1;
+
+    z2 = a2 - b2;
+    borrow1 = ( a2 < b2 );
+    z1 = a1 - b1;
+    borrow0 = ( a1 < b1 );
+    z0 = a0 - b0;
+    z0 -= ( z1 < borrow1 );
+    z1 -= borrow1;
+    z0 -= borrow0;
+    *z2Ptr = z2;
+    *z1Ptr = z1;
+    *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Multiplies `a' by `b' to obtain a 64-bit product.  The product is broken
+into two 32-bit pieces which are stored at the locations pointed to by
+`z0Ptr' and `z1Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void mul32To64( bits32 a, bits32 b, bits32 *z0Ptr, bits32 *z1Ptr )
+{
+    bits16 aHigh, aLow, bHigh, bLow;
+    bits32 z0, zMiddleA, zMiddleB, z1;
+
+    aLow = a;
+    aHigh = a>>16;
+    bLow = b;
+    bHigh = b>>16;
+    z1 = ( (bits32) aLow ) * bLow;
+    zMiddleA = ( (bits32) aLow ) * bHigh;
+    zMiddleB = ( (bits32) aHigh ) * bLow;
+    z0 = ( (bits32) aHigh ) * bHigh;
+    zMiddleA += zMiddleB;
+    z0 += ( ( (bits32) ( zMiddleA < zMiddleB ) )<<16 ) + ( zMiddleA>>16 );
+    zMiddleA <<= 16;
+    z1 += zMiddleA;
+    z0 += ( z1 < zMiddleA );
+    *z1Ptr = z1;
+    *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Multiplies the 64-bit value formed by concatenating `a0' and `a1' by `b' to
+obtain a 96-bit product.  The product is broken into three 32-bit pieces
+which are stored at the locations pointed to by `z0Ptr', `z1Ptr', and
+`z2Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ mul64By32To96(
+     bits32 a0,
+     bits32 a1,
+     bits32 b,
+     bits32 *z0Ptr,
+     bits32 *z1Ptr,
+     bits32 *z2Ptr
+ )
+{
+    bits32 z0, z1, z2, more1;
+
+    mul32To64( a1, b, &z1, &z2 );
+    mul32To64( a0, b, &z0, &more1 );
+    add64( z0, more1, 0, z1, &z0, &z1 );
+    *z2Ptr = z2;
+    *z1Ptr = z1;
+    *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Multiplies the 64-bit value formed by concatenating `a0' and `a1' to the
+64-bit value formed by concatenating `b0' and `b1' to obtain a 128-bit
+product.  The product is broken into four 32-bit pieces which are stored at
+the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'.
+-------------------------------------------------------------------------------
+*/
+INLINE void
+ mul64To128(
+     bits32 a0,
+     bits32 a1,
+     bits32 b0,
+     bits32 b1,
+     bits32 *z0Ptr,
+     bits32 *z1Ptr,
+     bits32 *z2Ptr,
+     bits32 *z3Ptr
+ )
+{
+    bits32 z0, z1, z2, z3;
+    bits32 more1, more2;
+
+    mul32To64( a1, b1, &z2, &z3 );
+    mul32To64( a1, b0, &z1, &more2 );
+    add64( z1, more2, 0, z2, &z1, &z2 );
+    mul32To64( a0, b0, &z0, &more1 );
+    add64( z0, more1, 0, z1, &z0, &z1 );
+    mul32To64( a0, b1, &more1, &more2 );
+    add64( more1, more2, 0, z2, &more1, &z2 );
+    add64( z0, z1, 0, more1, &z0, &z1 );
+    *z3Ptr = z3;
+    *z2Ptr = z2;
+    *z1Ptr = z1;
+    *z0Ptr = z0;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns an approximation to the 32-bit integer quotient obtained by dividing
+`b' into the 64-bit value formed by concatenating `a0' and `a1'.  The divisor
+`b' must be at least 2^31.  If q is the exact quotient truncated toward
+zero, the approximation returned lies between q and q + 2 inclusive.  If
+the exact quotient q is larger than 32 bits, the maximum positive 32-bit
+unsigned integer is returned.
+-------------------------------------------------------------------------------
+*/
+static bits32 estimateDiv64To32( bits32 a0, bits32 a1, bits32 b )
+{
+    bits32 b0, b1;
+    bits32 rem0, rem1, term0, term1;
+    bits32 z;
+
+    if ( b <= a0 ) return 0xFFFFFFFF;
+    b0 = b>>16;
+    z = ( b0<<16 <= a0 ) ? 0xFFFF0000 : ( a0 / b0 )<<16;
+    mul32To64( b, z, &term0, &term1 );
+    sub64( a0, a1, term0, term1, &rem0, &rem1 );
+    while ( ( (sbits32) rem0 ) < 0 ) {
+        z -= 0x10000;
+        b1 = b<<16;
+        add64( rem0, rem1, b0, b1, &rem0, &rem1 );
+    }
+    rem0 = ( rem0<<16 ) | ( rem1>>16 );
+    z |= ( b0<<16 <= rem0 ) ? 0xFFFF : rem0 / b0;
+    return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns an approximation to the square root of the 32-bit significand given
+by `a'.  Considered as an integer, `a' must be at least 2^31.  If bit 0 of
+`aExp' (the least significant bit) is 1, the integer returned approximates
+2^31*sqrt(`a'/2^31), where `a' is considered an integer.  If bit 0 of `aExp'
+is 0, the integer returned approximates 2^31*sqrt(`a'/2^30).  In either
+case, the approximation returned lies strictly within +/-2 of the exact
+value.
+-------------------------------------------------------------------------------
+*/
+static bits32 estimateSqrt32( int16 aExp, bits32 a )
+{
+    static const bits16 sqrtOddAdjustments[] = {
+        0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0,
+        0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67
+    };
+    static const bits16 sqrtEvenAdjustments[] = {
+        0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E,
+        0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002
+    };
+    int8 index;
+    bits32 z;
+
+    index = ( a>>27 ) & 15;
+    if ( aExp & 1 ) {
+        z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ index ];
+        z = ( ( a / z )<<14 ) + ( z<<15 );
+        a >>= 1;
+    }
+    else {
+        z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ index ];
+        z = a / z + z;
+        z = ( 0x20000 <= z ) ? 0xFFFF8000 : ( z<<15 );
+        if ( z <= a ) return (bits32) ( ( (sbits32) a )>>1 );
+    }
+    return ( ( estimateDiv64To32( a, 0, z ) )>>1 ) + ( z>>1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the number of leading 0 bits before the most-significant 1 bit
+of `a'.  If `a' is zero, 32 is returned.
+-------------------------------------------------------------------------------
+*/
+static int8 countLeadingZeros32( bits32 a )
+{
+    static const int8 countLeadingZerosHigh[] = {
+        8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+        2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+        2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+    };
+    int8 shiftCount;
+
+    shiftCount = 0;
+    if ( a < 0x10000 ) {
+        shiftCount += 16;
+        a <<= 16;
+    }
+    if ( a < 0x1000000 ) {
+        shiftCount += 8;
+        a <<= 8;
+    }
+    shiftCount += countLeadingZerosHigh[ a>>24 ];
+    return shiftCount;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the 64-bit value formed by concatenating `a0' and `a1' is equal
+to the 64-bit value formed by concatenating `b0' and `b1'.  Otherwise,
+returns 0.
+-------------------------------------------------------------------------------
+*/
+INLINE flag eq64( bits32 a0, bits32 a1, bits32 b0, bits32 b1 )
+{
+
+    return ( a0 == b0 ) && ( a1 == b1 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the 64-bit value formed by concatenating `a0' and `a1' is less
+than or equal to the 64-bit value formed by concatenating `b0' and `b1'.
+Otherwise, returns 0.
+-------------------------------------------------------------------------------
+*/
+INLINE flag le64( bits32 a0, bits32 a1, bits32 b0, bits32 b1 )
+{
+
+    return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 <= b1 ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the 64-bit value formed by concatenating `a0' and `a1' is less
+than the 64-bit value formed by concatenating `b0' and `b1'.  Otherwise,
+returns 0.
+-------------------------------------------------------------------------------
+*/
+INLINE flag lt64( bits32 a0, bits32 a1, bits32 b0, bits32 b1 )
+{
+
+    return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 < b1 ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the 64-bit value formed by concatenating `a0' and `a1' is not
+equal to the 64-bit value formed by concatenating `b0' and `b1'.  Otherwise,
+returns 0.
+-------------------------------------------------------------------------------
+*/
+INLINE flag ne64( bits32 a0, bits32 a1, bits32 b0, bits32 b1 )
+{
+
+    return ( a0 != b0 ) || ( a1 != b1 );
+
+}
+
diff --git a/software/libbase/softfloat-specialize.h b/software/libbase/softfloat-specialize.h
new file mode 100644 (file)
index 0000000..9f3466f
--- /dev/null
@@ -0,0 +1,125 @@
+
+/*
+===============================================================================
+
+This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2.
+
+Written by John R. Hauser.  This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704.  Funding was partially provided by the
+National Science Foundation under grant MIP-9311980.  The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek.  More information
+is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/softfloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR.  USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these three paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+/*
+-------------------------------------------------------------------------------
+Underflow tininess-detection mode, statically initialized to default value.
+(The declaration in `softfloat.h' must match the `int8' type here.)
+-------------------------------------------------------------------------------
+*/
+int8 float_detect_tininess = float_tininess_after_rounding;
+
+/*
+-------------------------------------------------------------------------------
+Raises the exceptions specified by `flags'.  Floating-point traps can be
+defined here if desired.  It is currently not possible for such a trap to
+substitute a result value.  If traps are not implemented, this routine
+should be simply `float_exception_flags |= flags;'.
+-------------------------------------------------------------------------------
+*/
+void float_raise( int8 flags )
+{
+
+    float_exception_flags |= flags;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Internal canonical NaN format.
+-------------------------------------------------------------------------------
+*/
+typedef struct {
+    flag sign;
+    bits32 high, low;
+} commonNaNT;
+
+/*
+-------------------------------------------------------------------------------
+The pattern for a default generated single-precision NaN.
+-------------------------------------------------------------------------------
+*/
+enum {
+    float32_default_nan = 0xFFFFFFFF
+};
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is a NaN;
+otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+flag float32_is_nan( float32 a )
+{
+
+    return ( 0xFF000000 < (bits32) ( a<<1 ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is a signaling
+NaN; otherwise returns 0.
+-------------------------------------------------------------------------------
+*/
+flag float32_is_signaling_nan( float32 a )
+{
+
+    return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes two single-precision floating-point values `a' and `b', one of which
+is a NaN, and returns the appropriate NaN result.  If either `a' or `b' is a
+signaling NaN, the invalid exception is raised.
+-------------------------------------------------------------------------------
+*/
+static float32 propagateFloat32NaN( float32 a, float32 b )
+{
+    flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
+
+    aIsNaN = float32_is_nan( a );
+    aIsSignalingNaN = float32_is_signaling_nan( a );
+    bIsNaN = float32_is_nan( b );
+    bIsSignalingNaN = float32_is_signaling_nan( b );
+    a |= 0x00400000;
+    b |= 0x00400000;
+    if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
+    if ( aIsNaN ) {
+        return ( aIsSignalingNaN & bIsNaN ) ? b : a;
+    }
+    else {
+        return b;
+    }
+
+}
diff --git a/software/libbase/softfloat.c b/software/libbase/softfloat.c
new file mode 100644 (file)
index 0000000..9ab4f0b
--- /dev/null
@@ -0,0 +1,1030 @@
+
+/*
+===============================================================================
+
+This C source file is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2.
+
+Written by John R. Hauser.  This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704.  Funding was partially provided by the
+National Science Foundation under grant MIP-9311980.  The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek.  More information
+is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/softfloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR.  USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these three paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+#include "milieu.h"
+#include "softfloat.h"
+
+/*
+-------------------------------------------------------------------------------
+Floating-point rounding mode and exception flags.
+-------------------------------------------------------------------------------
+*/
+int8 float_rounding_mode = float_round_nearest_even;
+int8 float_exception_flags = 0;
+
+/*
+-------------------------------------------------------------------------------
+Primitive arithmetic functions, including multi-word arithmetic, and
+division and square root approximations.  (Can be specialized to target if
+desired.)
+-------------------------------------------------------------------------------
+*/
+#include "softfloat-macros.h"
+
+/*
+-------------------------------------------------------------------------------
+Functions and definitions to determine:  (1) whether tininess for underflow
+is detected before or after rounding by default, (2) what (if anything)
+happens when exceptions are raised, (3) how signaling NaNs are distinguished
+from quiet NaNs, (4) the default generated quiet NaNs, and (4) how NaNs
+are propagated from function inputs to output.  These details are target-
+specific.
+-------------------------------------------------------------------------------
+*/
+#include "softfloat-specialize.h"
+
+/*
+-------------------------------------------------------------------------------
+Returns the fraction bits of the single-precision floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE bits32 extractFloat32Frac( float32 a )
+{
+
+    return a & 0x007FFFFF;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the exponent bits of the single-precision floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE int16 extractFloat32Exp( float32 a )
+{
+
+    return ( a>>23 ) & 0xFF;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the sign bit of the single-precision floating-point value `a'.
+-------------------------------------------------------------------------------
+*/
+INLINE flag extractFloat32Sign( float32 a )
+{
+
+    return a>>31;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Normalizes the subnormal single-precision floating-point value represented
+by the denormalized significand `aSig'.  The normalized exponent and
+significand are stored at the locations pointed to by `zExpPtr' and
+`zSigPtr', respectively.
+-------------------------------------------------------------------------------
+*/
+static void
+ normalizeFloat32Subnormal( bits32 aSig, int16 *zExpPtr, bits32 *zSigPtr )
+{
+    int8 shiftCount;
+
+    shiftCount = countLeadingZeros32( aSig ) - 8;
+    *zSigPtr = aSig<<shiftCount;
+    *zExpPtr = 1 - shiftCount;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Packs the sign `zSign', exponent `zExp', and significand `zSig' into a
+single-precision floating-point value, returning the result.  After being
+shifted into the proper positions, the three fields are simply added
+together to form the result.  This means that any integer portion of `zSig'
+will be added into the exponent.  Since a properly normalized significand
+will have an integer portion equal to 1, the `zExp' input should be 1 less
+than the desired result exponent whenever `zSig' is a complete, normalized
+significand.
+-------------------------------------------------------------------------------
+*/
+INLINE float32 packFloat32( flag zSign, int16 zExp, bits32 zSig )
+{
+
+    return ( ( (bits32) zSign )<<31 ) + ( ( (bits32) zExp )<<23 ) + zSig;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+and significand `zSig', and returns the proper single-precision floating-
+point value corresponding to the abstract input.  Ordinarily, the abstract
+value is simply rounded and packed into the single-precision format, with
+the inexact exception raised if the abstract input cannot be represented
+exactly.  If the abstract value is too large, however, the overflow and
+inexact exceptions are raised and an infinity or maximal finite value is
+returned.  If the abstract value is too small, the input value is rounded to
+a subnormal number, and the underflow and inexact exceptions are raised if
+the abstract input cannot be represented exactly as a subnormal single-
+precision floating-point number.
+    The input significand `zSig' has its binary point between bits 30
+and 29, which is 7 bits to the left of the usual location.  This shifted
+significand must be normalized or smaller.  If `zSig' is not normalized,
+`zExp' must be 0; in that case, the result returned is a subnormal number,
+and it must not require rounding.  In the usual case that `zSig' is
+normalized, `zExp' must be 1 less than the ``true'' floating-point exponent.
+The handling of underflow and overflow follows the IEC/IEEE Standard for
+Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float32 roundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig )
+{
+    int8 roundingMode;
+    flag roundNearestEven;
+    int8 roundIncrement, roundBits;
+    flag isTiny;
+
+    roundingMode = float_rounding_mode;
+    roundNearestEven = roundingMode == float_round_nearest_even;
+    roundIncrement = 0x40;
+    if ( ! roundNearestEven ) {
+        if ( roundingMode == float_round_to_zero ) {
+            roundIncrement = 0;
+        }
+        else {
+            roundIncrement = 0x7F;
+            if ( zSign ) {
+                if ( roundingMode == float_round_up ) roundIncrement = 0;
+            }
+            else {
+                if ( roundingMode == float_round_down ) roundIncrement = 0;
+            }
+        }
+    }
+    roundBits = zSig & 0x7F;
+    if ( 0xFD <= (bits16) zExp ) {
+        if (    ( 0xFD < zExp )
+             || (    ( zExp == 0xFD )
+                  && ( (sbits32) ( zSig + roundIncrement ) < 0 ) )
+           ) {
+            float_raise( float_flag_overflow | float_flag_inexact );
+            return packFloat32( zSign, 0xFF, 0 ) - ( roundIncrement == 0 );
+        }
+        if ( zExp < 0 ) {
+            isTiny =
+                   ( float_detect_tininess == float_tininess_before_rounding )
+                || ( zExp < -1 )
+                || ( zSig + roundIncrement < 0x80000000 );
+            shift32RightJamming( zSig, - zExp, &zSig );
+            zExp = 0;
+            roundBits = zSig & 0x7F;
+            if ( isTiny && roundBits ) float_raise( float_flag_underflow );
+        }
+    }
+    if ( roundBits ) float_exception_flags |= float_flag_inexact;
+    zSig = ( zSig + roundIncrement )>>7;
+    zSig &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven );
+    if ( zSig == 0 ) zExp = 0;
+    return packFloat32( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+and significand `zSig', and returns the proper single-precision floating-
+point value corresponding to the abstract input.  This routine is just like
+`roundAndPackFloat32' except that `zSig' does not have to be normalized in
+any way.  In all cases, `zExp' must be 1 less than the ``true'' floating-
+point exponent.
+-------------------------------------------------------------------------------
+*/
+static float32
+ normalizeRoundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig )
+{
+    int8 shiftCount;
+
+    shiftCount = countLeadingZeros32( zSig ) - 1;
+    return roundAndPackFloat32( zSign, zExp - shiftCount, zSig<<shiftCount );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the 32-bit two's complement integer `a' to
+the single-precision floating-point format.  The conversion is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 int32_to_float32( int32 a )
+{
+    flag zSign;
+
+    if ( a == 0 ) return 0;
+    if ( a == 0x80000000 ) return packFloat32( 1, 0x9E, 0 );
+    zSign = ( a < 0 );
+    return normalizeRoundAndPackFloat32( zSign, 0x9C, zSign ? - a : a );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the single-precision floating-point value
+`a' to the 32-bit two's complement integer format.  The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic---which means in particular that the conversion is rounded
+according to the current rounding mode.  If `a' is a NaN, the largest
+positive integer is returned.  Otherwise, if the conversion overflows, the
+largest integer with the same sign as `a' is returned.
+-------------------------------------------------------------------------------
+*/
+int32 float32_to_int32( float32 a )
+{
+    flag aSign;
+    int16 aExp, shiftCount;
+    bits32 aSig, zExtra;
+    int32 z;
+    int8 roundingMode;
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+    shiftCount = aExp - 0x96;
+    if ( 0 <= shiftCount ) {
+        if ( 0x9E <= aExp ) {
+            if ( a == 0xCF000000 ) return 0x80000000;
+            float_raise( float_flag_invalid );
+            if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) return 0x7FFFFFFF;
+            return 0x80000000;
+        }
+        z = ( aSig | 0x00800000 )<<shiftCount;
+        if ( aSign ) z = - z;
+    }
+    else {
+        if ( aExp < 0x7E ) {
+            zExtra = aExp | aSig;
+            z = 0;
+        }
+        else {
+            aSig |= 0x00800000;
+            zExtra = aSig<<( shiftCount & 31 );
+            z = aSig>>( - shiftCount );
+        }
+        if ( zExtra ) float_exception_flags |= float_flag_inexact;
+        roundingMode = float_rounding_mode;
+        if ( roundingMode == float_round_nearest_even ) {
+            if ( (sbits32) zExtra < 0 ) {
+                ++z;
+                if ( (bits32) ( zExtra<<1 ) == 0 ) z &= ~1;
+            }
+            if ( aSign ) z = - z;
+        }
+        else {
+            zExtra = ( zExtra != 0 );
+            if ( aSign ) {
+                z += ( roundingMode == float_round_down ) & zExtra;
+                z = - z;
+            }
+            else {
+                z += ( roundingMode == float_round_up ) & zExtra;
+            }
+        }
+    }
+    return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of converting the single-precision floating-point value
+`a' to the 32-bit two's complement integer format.  The conversion is
+performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic, except that the conversion is always rounded toward zero.  If
+`a' is a NaN, the largest positive integer is returned.  Otherwise, if the
+conversion overflows, the largest integer with the same sign as `a' is
+returned.
+-------------------------------------------------------------------------------
+*/
+int32 float32_to_int32_round_to_zero( float32 a )
+{
+    flag aSign;
+    int16 aExp, shiftCount;
+    bits32 aSig;
+    int32 z;
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+    shiftCount = aExp - 0x9E;
+    if ( 0 <= shiftCount ) {
+        if ( a == 0xCF000000 ) return 0x80000000;
+        float_raise( float_flag_invalid );
+        if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) return 0x7FFFFFFF;
+        return 0x80000000;
+    }
+    else if ( aExp <= 0x7E ) {
+        if ( aExp | aSig ) float_exception_flags |= float_flag_inexact;
+        return 0;
+    }
+    aSig = ( aSig | 0x00800000 )<<8;
+    z = aSig>>( - shiftCount );
+    if ( (bits32) ( aSig<<( shiftCount & 31 ) ) ) {
+        float_exception_flags |= float_flag_inexact;
+    }
+    return aSign ? - z : z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Rounds the single-precision floating-point value `a' to an integer, and
+returns the result as a single-precision floating-point value.  The
+operation is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_round_to_int( float32 a )
+{
+    flag aSign;
+    int16 aExp;
+    bits32 lastBitMask, roundBitsMask;
+    int8 roundingMode;
+    float32 z;
+
+    aExp = extractFloat32Exp( a );
+    if ( 0x96 <= aExp ) {
+        if ( ( aExp == 0xFF ) && extractFloat32Frac( a ) ) {
+            return propagateFloat32NaN( a, a );
+        }
+        return a;
+    }
+    if ( aExp <= 0x7E ) {
+        if ( (bits32) ( a<<1 ) == 0 ) return a;
+        float_exception_flags |= float_flag_inexact;
+        aSign = extractFloat32Sign( a );
+        switch ( float_rounding_mode ) {
+         case float_round_nearest_even:
+            if ( ( aExp == 0x7E ) && extractFloat32Frac( a ) ) {
+                return packFloat32( aSign, 0x7F, 0 );
+            }
+            break;
+         case float_round_down:
+            return aSign ? 0xBF800000 : 0;
+         case float_round_up:
+            return aSign ? 0x80000000 : 0x3F800000;
+        }
+        return packFloat32( aSign, 0, 0 );
+    }
+    lastBitMask = 1;
+    lastBitMask <<= 0x96 - aExp;
+    roundBitsMask = lastBitMask - 1;
+    z = a;
+    roundingMode = float_rounding_mode;
+    if ( roundingMode == float_round_nearest_even ) {
+        z += lastBitMask>>1;
+        if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask;
+    }
+    else if ( roundingMode != float_round_to_zero ) {
+        if ( extractFloat32Sign( z ) ^ ( roundingMode == float_round_up ) ) {
+            z += roundBitsMask;
+        }
+    }
+    z &= ~ roundBitsMask;
+    if ( z != a ) float_exception_flags |= float_flag_inexact;
+    return z;
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of adding the absolute values of the single-precision
+floating-point values `a' and `b'.  If `zSign' is true, the sum is negated
+before being returned.  `zSign' is ignored if the result is a NaN.  The
+addition is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float32 addFloat32Sigs( float32 a, float32 b, flag zSign )
+{
+    int16 aExp, bExp, zExp;
+    bits32 aSig, bSig, zSig;
+    int16 expDiff;
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    bSig = extractFloat32Frac( b );
+    bExp = extractFloat32Exp( b );
+    expDiff = aExp - bExp;
+    aSig <<= 6;
+    bSig <<= 6;
+    if ( 0 < expDiff ) {
+        if ( aExp == 0xFF ) {
+            if ( aSig ) return propagateFloat32NaN( a, b );
+            return a;
+        }
+        if ( bExp == 0 ) {
+            --expDiff;
+        }
+        else {
+            bSig |= 0x20000000;
+        }
+        shift32RightJamming( bSig, expDiff, &bSig );
+        zExp = aExp;
+    }
+    else if ( expDiff < 0 ) {
+        if ( bExp == 0xFF ) {
+            if ( bSig ) return propagateFloat32NaN( a, b );
+            return packFloat32( zSign, 0xFF, 0 );
+        }
+        if ( aExp == 0 ) {
+            ++expDiff;
+        }
+        else {
+            aSig |= 0x20000000;
+        }
+        shift32RightJamming( aSig, - expDiff, &aSig );
+        zExp = bExp;
+    }
+    else {
+        if ( aExp == 0xFF ) {
+            if ( aSig | bSig ) return propagateFloat32NaN( a, b );
+            return a;
+        }
+        if ( aExp == 0 ) return packFloat32( zSign, 0, ( aSig + bSig )>>6 );
+        zSig = 0x40000000 + aSig + bSig;
+        zExp = aExp;
+        goto roundAndPack;
+    }
+    aSig |= 0x20000000;
+    zSig = ( aSig + bSig )<<1;
+    --zExp;
+    if ( (sbits32) zSig < 0 ) {
+        zSig = aSig + bSig;
+        ++zExp;
+    }
+ roundAndPack:
+    return roundAndPackFloat32( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of subtracting the absolute values of the single-
+precision floating-point values `a' and `b'.  If `zSign' is true, the
+difference is negated before being returned.  `zSign' is ignored if the
+result is a NaN.  The subtraction is performed according to the IEC/IEEE
+Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+static float32 subFloat32Sigs( float32 a, float32 b, flag zSign )
+{
+    int16 aExp, bExp, zExp;
+    bits32 aSig, bSig, zSig;
+    int16 expDiff;
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    bSig = extractFloat32Frac( b );
+    bExp = extractFloat32Exp( b );
+    expDiff = aExp - bExp;
+    aSig <<= 7;
+    bSig <<= 7;
+    if ( 0 < expDiff ) goto aExpBigger;
+    if ( expDiff < 0 ) goto bExpBigger;
+    if ( aExp == 0xFF ) {
+        if ( aSig | bSig ) return propagateFloat32NaN( a, b );
+        float_raise( float_flag_invalid );
+        return float32_default_nan;
+    }
+    if ( aExp == 0 ) {
+        aExp = 1;
+        bExp = 1;
+    }
+    if ( bSig < aSig ) goto aBigger;
+    if ( aSig < bSig ) goto bBigger;
+    return packFloat32( float_rounding_mode == float_round_down, 0, 0 );
+ bExpBigger:
+    if ( bExp == 0xFF ) {
+        if ( bSig ) return propagateFloat32NaN( a, b );
+        return packFloat32( zSign ^ 1, 0xFF, 0 );
+    }
+    if ( aExp == 0 ) {
+        ++expDiff;
+    }
+    else {
+        aSig |= 0x40000000;
+    }
+    shift32RightJamming( aSig, - expDiff, &aSig );
+    bSig |= 0x40000000;
+ bBigger:
+    zSig = bSig - aSig;
+    zExp = bExp;
+    zSign ^= 1;
+    goto normalizeRoundAndPack;
+ aExpBigger:
+    if ( aExp == 0xFF ) {
+        if ( aSig ) return propagateFloat32NaN( a, b );
+        return a;
+    }
+    if ( bExp == 0 ) {
+        --expDiff;
+    }
+    else {
+        bSig |= 0x40000000;
+    }
+    shift32RightJamming( bSig, expDiff, &bSig );
+    aSig |= 0x40000000;
+ aBigger:
+    zSig = aSig - bSig;
+    zExp = aExp;
+ normalizeRoundAndPack:
+    --zExp;
+    return normalizeRoundAndPackFloat32( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of adding the single-precision floating-point values `a'
+and `b'.  The operation is performed according to the IEC/IEEE Standard for
+Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_add( float32 a, float32 b )
+{
+    flag aSign, bSign;
+
+    aSign = extractFloat32Sign( a );
+    bSign = extractFloat32Sign( b );
+    if ( aSign == bSign ) {
+        return addFloat32Sigs( a, b, aSign );
+    }
+    else {
+        return subFloat32Sigs( a, b, aSign );
+    }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of subtracting the single-precision floating-point values
+`a' and `b'.  The operation is performed according to the IEC/IEEE Standard
+for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_sub( float32 a, float32 b )
+{
+    flag aSign, bSign;
+
+    aSign = extractFloat32Sign( a );
+    bSign = extractFloat32Sign( b );
+    if ( aSign == bSign ) {
+        return subFloat32Sigs( a, b, aSign );
+    }
+    else {
+        return addFloat32Sigs( a, b, aSign );
+    }
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of multiplying the single-precision floating-point values
+`a' and `b'.  The operation is performed according to the IEC/IEEE Standard
+for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_mul( float32 a, float32 b )
+{
+    flag aSign, bSign, zSign;
+    int16 aExp, bExp, zExp;
+    bits32 aSig, bSig, zSig0, zSig1;
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+    bSig = extractFloat32Frac( b );
+    bExp = extractFloat32Exp( b );
+    bSign = extractFloat32Sign( b );
+    zSign = aSign ^ bSign;
+    if ( aExp == 0xFF ) {
+        if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) {
+            return propagateFloat32NaN( a, b );
+        }
+        if ( ( bExp | bSig ) == 0 ) {
+            float_raise( float_flag_invalid );
+            return float32_default_nan;
+        }
+        return packFloat32( zSign, 0xFF, 0 );
+    }
+    if ( bExp == 0xFF ) {
+        if ( bSig ) return propagateFloat32NaN( a, b );
+        if ( ( aExp | aSig ) == 0 ) {
+            float_raise( float_flag_invalid );
+            return float32_default_nan;
+        }
+        return packFloat32( zSign, 0xFF, 0 );
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return packFloat32( zSign, 0, 0 );
+        normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+    }
+    if ( bExp == 0 ) {
+        if ( bSig == 0 ) return packFloat32( zSign, 0, 0 );
+        normalizeFloat32Subnormal( bSig, &bExp, &bSig );
+    }
+    zExp = aExp + bExp - 0x7F;
+    aSig = ( aSig | 0x00800000 )<<7;
+    bSig = ( bSig | 0x00800000 )<<8;
+    mul32To64( aSig, bSig, &zSig0, &zSig1 );
+    zSig0 |= ( zSig1 != 0 );
+    if ( 0 <= (sbits32) ( zSig0<<1 ) ) {
+        zSig0 <<= 1;
+        --zExp;
+    }
+    return roundAndPackFloat32( zSign, zExp, zSig0 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the result of dividing the single-precision floating-point value `a'
+by the corresponding value `b'.  The operation is performed according to
+the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_div( float32 a, float32 b )
+{
+    flag aSign, bSign, zSign;
+    int16 aExp, bExp, zExp;
+    bits32 aSig, bSig, zSig;
+    bits32 rem0, rem1;
+    bits32 term0, term1;
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+    bSig = extractFloat32Frac( b );
+    bExp = extractFloat32Exp( b );
+    bSign = extractFloat32Sign( b );
+    zSign = aSign ^ bSign;
+    if ( aExp == 0xFF ) {
+        if ( aSig ) return propagateFloat32NaN( a, b );
+        if ( bExp == 0xFF ) {
+            if ( bSig ) return propagateFloat32NaN( a, b );
+            float_raise( float_flag_invalid );
+            return float32_default_nan;
+        }
+        return packFloat32( zSign, 0xFF, 0 );
+    }
+    if ( bExp == 0xFF ) {
+        if ( bSig ) return propagateFloat32NaN( a, b );
+        return packFloat32( zSign, 0, 0 );
+    }
+    if ( bExp == 0 ) {
+        if ( bSig == 0 ) {
+            if ( ( aExp | aSig ) == 0 ) {
+                float_raise( float_flag_invalid );
+                return float32_default_nan;
+            }
+            float_raise( float_flag_divbyzero );
+            return packFloat32( zSign, 0xFF, 0 );
+        }
+        normalizeFloat32Subnormal( bSig, &bExp, &bSig );
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return packFloat32( zSign, 0, 0 );
+        normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+    }
+    zExp = aExp - bExp + 0x7D;
+    aSig = ( aSig | 0x00800000 )<<7;
+    bSig = ( bSig | 0x00800000 )<<8;
+    if ( bSig <= ( aSig + aSig ) ) {
+        aSig >>= 1;
+        ++zExp;
+    }
+    zSig = estimateDiv64To32( aSig, 0, bSig );
+    if ( ( zSig & 0x3F ) <= 2 ) {
+        mul32To64( bSig, zSig, &term0, &term1 );
+        sub64( aSig, 0, term0, term1, &rem0, &rem1 );
+        while ( (sbits32) rem0 < 0 ) {
+            --zSig;
+            add64( rem0, rem1, 0, bSig, &rem0, &rem1 );
+        }
+        zSig |= ( rem1 != 0 );
+    }
+    return roundAndPackFloat32( zSign, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the remainder of the single-precision floating-point value `a'
+with respect to the corresponding value `b'.  The operation is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_rem( float32 a, float32 b )
+{
+    flag aSign, bSign, zSign;
+    int16 aExp, bExp, expDiff;
+    bits32 aSig, bSig;
+    bits32 q, alternateASig;
+    sbits32 sigMean;
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+    bSig = extractFloat32Frac( b );
+    bExp = extractFloat32Exp( b );
+    bSign = extractFloat32Sign( b );
+    if ( aExp == 0xFF ) {
+        if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) {
+            return propagateFloat32NaN( a, b );
+        }
+        float_raise( float_flag_invalid );
+        return float32_default_nan;
+    }
+    if ( bExp == 0xFF ) {
+        if ( bSig ) return propagateFloat32NaN( a, b );
+        return a;
+    }
+    if ( bExp == 0 ) {
+        if ( bSig == 0 ) {
+            float_raise( float_flag_invalid );
+            return float32_default_nan;
+        }
+        normalizeFloat32Subnormal( bSig, &bExp, &bSig );
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return a;
+        normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+    }
+    expDiff = aExp - bExp;
+    aSig = ( aSig | 0x00800000 )<<8;
+    bSig = ( bSig | 0x00800000 )<<8;
+    if ( expDiff < 0 ) {
+        if ( expDiff < -1 ) return a;
+        aSig >>= 1;
+    }
+    q = ( bSig <= aSig );
+    if ( q ) aSig -= bSig;
+    expDiff -= 32;
+    while ( 0 < expDiff ) {
+        q = estimateDiv64To32( aSig, 0, bSig );
+        q = ( 2 < q ) ? q - 2 : 0;
+        aSig = - ( ( bSig>>2 ) * q );
+        expDiff -= 30;
+    }
+    expDiff += 32;
+    if ( 0 < expDiff ) {
+        q = estimateDiv64To32( aSig, 0, bSig );
+        q = ( 2 < q ) ? q - 2 : 0;
+        q >>= 32 - expDiff;
+        bSig >>= 2;
+        aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q;
+    }
+    else {
+        aSig >>= 2;
+        bSig >>= 2;
+    }
+    do {
+        alternateASig = aSig;
+        ++q;
+        aSig -= bSig;
+    } while ( 0 <= (sbits32) aSig );
+    sigMean = aSig + alternateASig;
+    if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) {
+        aSig = alternateASig;
+    }
+    zSign = ( (sbits32) aSig < 0 );
+    if ( zSign ) aSig = - aSig;
+    return normalizeRoundAndPackFloat32( aSign ^ zSign, bExp, aSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns the square root of the single-precision floating-point value `a'.
+The operation is performed according to the IEC/IEEE Standard for Binary
+Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+float32 float32_sqrt( float32 a )
+{
+    flag aSign;
+    int16 aExp, zExp;
+    bits32 aSig, zSig;
+    bits32 rem0, rem1;
+    bits32 term0, term1;
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+    if ( aExp == 0xFF ) {
+        if ( aSig ) return propagateFloat32NaN( a, 0 );
+        if ( ! aSign ) return a;
+        float_raise( float_flag_invalid );
+        return float32_default_nan;
+    }
+    if ( aSign ) {
+        if ( ( aExp | aSig ) == 0 ) return a;
+        float_raise( float_flag_invalid );
+        return float32_default_nan;
+    }
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return 0;
+        normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+    }
+    zExp = ( ( aExp - 0x7F )>>1 ) + 0x7E;
+    aSig = ( aSig | 0x00800000 )<<8;
+    zSig = estimateSqrt32( aExp, aSig ) + 2;
+    if ( ( zSig & 0x7F ) <= 5 ) {
+        if ( zSig < 2 ) {
+            zSig = 0xFFFFFFFF;
+        }
+        else {
+            aSig >>= aExp & 1;
+            mul32To64( zSig, zSig, &term0, &term1 );
+            sub64( aSig, 0, term0, term1, &rem0, &rem1 );
+            while ( (sbits32) rem0 < 0 ) {
+                --zSig;
+                shortShift64Left( 0, zSig, 1, &term0, &term1 );
+                term1 |= 1;
+                add64( rem0, rem1, term0, term1, &rem0, &rem1 );
+            }
+            zSig |= ( ( rem0 | rem1 ) != 0 );
+        }
+    }
+    shift32RightJamming( zSig, 1, &zSig );
+    return roundAndPackFloat32( 0, zExp, zSig );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is equal to the
+corresponding value `b', and 0 otherwise.  The comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float32_eq( float32 a, float32 b )
+{
+
+    if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+         || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+       ) {
+        if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid );
+        }
+        return 0;
+    }
+    return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is less than or
+equal to the corresponding value `b', and 0 otherwise.  The comparison is
+performed according to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float32_le( float32 a, float32 b )
+{
+    flag aSign, bSign;
+
+    if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+         || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+       ) {
+        float_raise( float_flag_invalid );
+        return 0;
+    }
+    aSign = extractFloat32Sign( a );
+    bSign = extractFloat32Sign( b );
+    if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 );
+    return ( a == b ) || ( aSign ^ ( a < b ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is less than
+the corresponding value `b', and 0 otherwise.  The comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float32_lt( float32 a, float32 b )
+{
+    flag aSign, bSign;
+
+    if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+         || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+       ) {
+        float_raise( float_flag_invalid );
+        return 0;
+    }
+    aSign = extractFloat32Sign( a );
+    bSign = extractFloat32Sign( b );
+    if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 );
+    return ( a != b ) && ( aSign ^ ( a < b ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is equal to the
+corresponding value `b', and 0 otherwise.  The invalid exception is raised
+if either operand is a NaN.  Otherwise, the comparison is performed
+according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float32_eq_signaling( float32 a, float32 b )
+{
+
+    if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+         || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+       ) {
+        float_raise( float_flag_invalid );
+        return 0;
+    }
+    return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is less than or
+equal to the corresponding value `b', and 0 otherwise.  Quiet NaNs do not
+cause an exception.  Otherwise, the comparison is performed according to the
+IEC/IEEE Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float32_le_quiet( float32 a, float32 b )
+{
+    flag aSign, bSign;
+
+    if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+         || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+       ) {
+        if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid );
+        }
+        return 0;
+    }
+    aSign = extractFloat32Sign( a );
+    bSign = extractFloat32Sign( b );
+    if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 );
+    return ( a == b ) || ( aSign ^ ( a < b ) );
+
+}
+
+/*
+-------------------------------------------------------------------------------
+Returns 1 if the single-precision floating-point value `a' is less than
+the corresponding value `b', and 0 otherwise.  Quiet NaNs do not cause an
+exception.  Otherwise, the comparison is performed according to the IEC/IEEE
+Standard for Binary Floating-point Arithmetic.
+-------------------------------------------------------------------------------
+*/
+flag float32_lt_quiet( float32 a, float32 b )
+{
+    flag aSign, bSign;
+
+    if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
+         || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+       ) {
+        if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
+            float_raise( float_flag_invalid );
+        }
+        return 0;
+    }
+    aSign = extractFloat32Sign( a );
+    bSign = extractFloat32Sign( b );
+    if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 );
+    return ( a != b ) && ( aSign ^ ( a < b ) );
+
+}
+
diff --git a/software/libbase/softfloat.h b/software/libbase/softfloat.h
new file mode 100644 (file)
index 0000000..29454c0
--- /dev/null
@@ -0,0 +1,119 @@
+
+/*
+===============================================================================
+
+This C header file is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2.
+
+Written by John R. Hauser.  This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704.  Funding was partially provided by the
+National Science Foundation under grant MIP-9311980.  The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek.  More information
+is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/softfloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR.  USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these three paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point types.
+-------------------------------------------------------------------------------
+*/
+typedef unsigned int float32;
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point underflow tininess-detection mode.
+-------------------------------------------------------------------------------
+*/
+extern int float_detect_tininess;
+enum {
+    float_tininess_after_rounding  = 0,
+    float_tininess_before_rounding = 1
+};
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point rounding mode.
+-------------------------------------------------------------------------------
+*/
+extern int float_rounding_mode;
+enum {
+    float_round_nearest_even = 0,
+    float_round_to_zero      = 1,
+    float_round_up           = 2,
+    float_round_down         = 3
+};
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point exception flags.
+-------------------------------------------------------------------------------
+*/
+extern int float_exception_flags;
+enum {
+    float_flag_inexact   =  1,
+    float_flag_divbyzero =  2,
+    float_flag_underflow =  4,
+    float_flag_overflow  =  8,
+    float_flag_invalid   = 16
+};
+
+/*
+-------------------------------------------------------------------------------
+Routine to raise any or all of the software IEC/IEEE floating-point
+exception flags.
+-------------------------------------------------------------------------------
+*/
+void float_raise( int );
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE integer-to-floating-point conversion routines.
+-------------------------------------------------------------------------------
+*/
+float32 int32_to_float32( int );
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE single-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+int float32_to_int32( float32 );
+int float32_to_int32_round_to_zero( float32 );
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE single-precision operations.
+-------------------------------------------------------------------------------
+*/
+float32 float32_round_to_int( float32 );
+float32 float32_add( float32, float32 );
+float32 float32_sub( float32, float32 );
+float32 float32_mul( float32, float32 );
+float32 float32_div( float32, float32 );
+float32 float32_rem( float32, float32 );
+float32 float32_sqrt( float32 );
+int float32_eq( float32, float32 );
+int float32_le( float32, float32 );
+int float32_lt( float32, float32 );
+int float32_eq_signaling( float32, float32 );
+int float32_le_quiet( float32, float32 );
+int float32_lt_quiet( float32, float32 );
+int float32_is_signaling_nan( float32 );
+
diff --git a/software/libbase/system.c b/software/libbase/system.c
new file mode 100644 (file)
index 0000000..0edcb81
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009, 2012 Sebastien Bourdeauducq
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <irq.h>
+#include <uart.h>
+#include <hw/sysctl.h>
+
+#include <system.h>
+
+void flush_cpu_icache(void)
+{
+       asm volatile(
+               "wcsr ICC, r0\n"
+               "nop\n"
+               "nop\n"
+               "nop\n"
+               "nop\n"
+       );
+}
+
+void flush_cpu_dcache(void)
+{
+       asm volatile(
+               "wcsr DCC, r0\n"
+               "nop\n"
+       );
+}
+
+__attribute__((noreturn)) void reboot(void)
+{
+       uart_sync();
+       irq_setmask(0);
+       irq_enable(0);
+       CSR_SYSTEM_ID = 1; /* Writing to CSR_SYSTEM_ID causes a system reset */
+       while(1);
+}
+
+static void icap_write(int val, unsigned int w)
+{
+       while(!(CSR_ICAP & ICAP_READY));
+       if(!val)
+               w |= ICAP_CE|ICAP_WRITE;
+       CSR_ICAP = w;
+}
+
+__attribute__((noreturn)) void reconf(void)
+{
+       uart_sync();
+       irq_setmask(0);
+       irq_enable(0);
+       icap_write(0, 0xffff); /* dummy word */
+       icap_write(0, 0xffff); /* dummy word */
+       icap_write(0, 0xffff); /* dummy word */
+       icap_write(0, 0xffff); /* dummy word */
+       icap_write(1, 0xaa99); /* sync word part 1 */
+       icap_write(1, 0x5566); /* sync word part 2 */
+       icap_write(1, 0x30a1); /* write to command register */
+       icap_write(1, 0x0000); /* null command */
+       icap_write(1, 0x30a1); /* write to command register */
+       icap_write(1, 0x000e); /* reboot command */
+       icap_write(1, 0x2000); /* NOP */
+       icap_write(1, 0x2000); /* NOP */
+       icap_write(1, 0x2000); /* NOP */
+       icap_write(1, 0x2000); /* NOP */
+       icap_write(0, 0x1111); /* NULL */
+       icap_write(0, 0xffff); /* dummy word */
+       while(1);
+}
diff --git a/software/libbase/uart.c b/software/libbase/uart.c
new file mode 100644 (file)
index 0000000..9ec12ab
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009, 2010, 2012 Sebastien Bourdeauducq
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <uart.h>
+#include <irq.h>
+#include <hw/uart.h>
+#include <hw/interrupts.h>
+
+/*
+ * Buffer sizes must be a power of 2 so that modulos can be computed
+ * with logical AND.
+ * RX functions are written in such a way that they do not require locking.
+ * TX functions already implement locking.
+ */
+
+#define UART_RINGBUFFER_SIZE_RX 128
+#define UART_RINGBUFFER_MASK_RX (UART_RINGBUFFER_SIZE_RX-1)
+
+static char rx_buf[UART_RINGBUFFER_SIZE_RX];
+static volatile unsigned int rx_produce;
+static volatile unsigned int rx_consume;
+
+#define UART_RINGBUFFER_SIZE_TX 128
+#define UART_RINGBUFFER_MASK_TX (UART_RINGBUFFER_SIZE_TX-1)
+
+static char tx_buf[UART_RINGBUFFER_SIZE_TX];
+static unsigned int tx_produce;
+static unsigned int tx_consume;
+static volatile int tx_cts;
+
+void uart_isr(void)
+{
+       unsigned int stat = CSR_UART_STAT;
+
+       if(stat & UART_STAT_RX_EVT) {
+               rx_buf[rx_produce] = CSR_UART_RXTX;
+               rx_produce = (rx_produce + 1) & UART_RINGBUFFER_MASK_RX;
+       }
+
+       if(stat & UART_STAT_TX_EVT) {
+               if(tx_produce != tx_consume) {
+                       CSR_UART_RXTX = tx_buf[tx_consume];
+                       tx_consume = (tx_consume + 1) & UART_RINGBUFFER_MASK_TX;
+               } else
+                       tx_cts = 1;
+       }
+
+       CSR_UART_STAT = stat;
+       irq_ack(IRQ_UART);
+}
+
+/* Do not use in interrupt handlers! */
+char uart_read(void)
+{
+       char c;
+       
+       while(rx_consume == rx_produce);
+       c = rx_buf[rx_consume];
+       rx_consume = (rx_consume + 1) & UART_RINGBUFFER_MASK_RX;
+       return c;
+}
+
+int uart_read_nonblock(void)
+{
+       return (rx_consume != rx_produce);
+}
+
+void uart_write(char c)
+{
+       unsigned int oldmask;
+       
+       oldmask = irq_getmask();
+       irq_setmask(0);
+
+       if(tx_cts) {
+               tx_cts = 0;
+               CSR_UART_RXTX = c;
+       } else {
+               tx_buf[tx_produce] = c;
+               tx_produce = (tx_produce + 1) & UART_RINGBUFFER_MASK_TX;
+       }
+       irq_setmask(oldmask);
+}
+
+void uart_init(void)
+{
+       unsigned int mask;
+       
+       rx_produce = 0;
+       rx_consume = 0;
+       tx_produce = 0;
+       tx_consume = 0;
+       tx_cts = 1;
+
+       irq_ack(IRQ_UART);
+
+       /* ack any events */
+       CSR_UART_STAT = CSR_UART_STAT;
+
+       /* enable interrupts */
+       CSR_UART_CTRL = UART_CTRL_TX_INT | UART_CTRL_RX_INT;
+
+       mask = irq_getmask();
+       mask |= IRQ_UART;
+       irq_setmask(mask);
+}
+
+void uart_sync(void)
+{
+       while(!tx_cts);
+}
diff --git a/software/libbase/vsnprintf.c b/software/libbase/vsnprintf.c
new file mode 100644 (file)
index 0000000..102ee8c
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
+ * Copyright (C) Linux kernel developers
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+
+#define fabsf(x) ((x) > 0.0 ? x : -x)
+
+/**
+ * vsnprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @args: Arguments for the format string
+ *
+ * The return value is the number of characters which would
+ * be generated for the given input, excluding the trailing
+ * '\0', as per ISO C99. If you want to have the exact
+ * number of characters written into @buf as return value
+ * (not including the trailing '\0'), use vscnprintf(). If the
+ * return is greater than or equal to @size, the resulting
+ * string is truncated.
+ *
+ * Call this function if you are already dealing with a va_list.
+ * You probably want snprintf() instead.
+ */
+int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
+{
+       int len;
+       unsigned long long num;
+       int i, base;
+       char *str, *end, c;
+       const char *s;
+
+       int flags;              /* flags to number() */
+
+       int field_width;        /* width of output field */
+       int precision;          /* min. # of digits for integers; max
+                                  number of chars for from string */
+       int qualifier;          /* 'h', 'l', or 'L' for integer fields */
+                               /* 'z' support added 23/7/1999 S.H.    */
+                               /* 'z' changed to 'Z' --davidm 1/25/99 */
+                               /* 't' added for ptrdiff_t */
+
+       /* Reject out-of-range values early.  Large positive sizes are
+          used for unknown buffer sizes. */
+       if (unlikely((int) size < 0))
+               return 0;
+
+       str = buf;
+       end = buf + size;
+
+       /* Make sure end is always >= buf */
+       if (end < buf) {
+               end = ((void *)-1);
+               size = end - buf;
+       }
+
+       for (; *fmt ; ++fmt) {
+               if (*fmt != '%') {
+                       if (str < end)
+                               *str = *fmt;
+                       ++str;
+                       continue;
+               }
+
+               /* process flags */
+               flags = 0;
+               repeat:
+                       ++fmt;          /* this also skips first '%' */
+                       switch (*fmt) {
+                               case '-': flags |= PRINTF_LEFT; goto repeat;
+                               case '+': flags |= PRINTF_PLUS; goto repeat;
+                               case ' ': flags |= PRINTF_SPACE; goto repeat;
+                               case '#': flags |= PRINTF_SPECIAL; goto repeat;
+                               case '0': flags |= PRINTF_ZEROPAD; goto repeat;
+                       }
+
+               /* get field width */
+               field_width = -1;
+               if (isdigit(*fmt))
+                       field_width = skip_atoi(&fmt);
+               else if (*fmt == '*') {
+                       ++fmt;
+                       /* it's the next argument */
+                       field_width = va_arg(args, int);
+                       if (field_width < 0) {
+                               field_width = -field_width;
+                               flags |= PRINTF_LEFT;
+                       }
+               }
+
+               /* get the precision */
+               precision = -1;
+               if (*fmt == '.') {
+                       ++fmt;  
+                       if (isdigit(*fmt))
+                               precision = skip_atoi(&fmt);
+                       else if (*fmt == '*') {
+                               ++fmt;
+                               /* it's the next argument */
+                               precision = va_arg(args, int);
+                       }
+                       if (precision < 0)
+                               precision = 0;
+               }
+
+               /* get the conversion qualifier */
+               qualifier = -1;
+               if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
+                   *fmt =='Z' || *fmt == 'z' || *fmt == 't') {
+                       qualifier = *fmt;
+                       ++fmt;
+                       if (qualifier == 'l' && *fmt == 'l') {
+                               qualifier = 'L';
+                               ++fmt;
+                       }
+               }
+
+               /* default base */
+               base = 10;
+
+               switch (*fmt) {
+                       case 'c':
+                               if (!(flags & PRINTF_LEFT)) {
+                                       while (--field_width > 0) {
+                                               if (str < end)
+                                                       *str = ' ';
+                                               ++str;
+                                       }
+                               }
+                               c = (unsigned char) va_arg(args, int);
+                               if (str < end)
+                                       *str = c;
+                               ++str;
+                               while (--field_width > 0) {
+                                       if (str < end)
+                                               *str = ' ';
+                                       ++str;
+                               }
+                               continue;
+
+                       case 's':
+                               s = va_arg(args, char *);
+                               if (s == NULL)
+                                       s = "<NULL>";
+
+                               len = strnlen(s, precision);
+
+                               if (!(flags & PRINTF_LEFT)) {
+                                       while (len < field_width--) {
+                                               if (str < end)
+                                                       *str = ' ';
+                                               ++str;
+                                       }
+                               }
+                               for (i = 0; i < len; ++i) {
+                                       if (str < end)
+                                               *str = *s;
+                                       ++str; ++s;
+                               }
+                               while (len < field_width--) {
+                                       if (str < end)
+                                               *str = ' ';
+                                       ++str;
+                               }
+                               continue;
+
+                       case 'p':
+                               if (field_width == -1) {
+                                       field_width = 2*sizeof(void *);
+                                       flags |= PRINTF_ZEROPAD;
+                               }
+                               str = number(str, end,
+                                               (unsigned long) va_arg(args, void *),
+                                               16, field_width, precision, flags);
+                               continue;
+
+                       case 'f': {
+                               int m;
+                               float f;
+                               int integer;
+                               
+                               /* until I sort out how to disable this stupid promotion to double ... */
+                               f = *(va_arg(args, float *));
+                               if((f <= 0.0f) && (f != 0.0f)) { /* TODO: fix that |[#{'"é! '<' operator */
+                                       *str = '-';
+                                       str++;
+                                       f = -f;
+                               }
+
+                               integer = f;
+                               if(integer > 0) {
+                                       m = 1;
+                                       while(integer > (m*10)) m *= 10;
+                                       while((m >= 1) && (str < end)) {
+                                               int n;
+                                               n = integer/m;
+                                               *str = '0' + n;
+                                               str++;
+                                               f = f - m*n;
+                                               integer = integer - m*n;
+                                               m /= 10;
+                                       }
+                               } else if(str < end) {
+                                       *str = '0';
+                                       str++;
+                               }
+
+                               if(str < end) {
+                                       *str = '.';
+                                       str++;
+                               }
+
+                               for(i=0;i<6;i++) {
+                                       int n;
+
+                                       f = f*10.0f;
+                                       n = f;
+                                       f = f - n;
+                                       if(str >= end) break;
+                                       *str = '0' + n;
+                                       str++;
+                               }
+                               
+                               continue;
+                       }
+
+                       case 'n':
+                               /* FIXME:
+                                * What does C99 say about the overflow case here? */
+                               if (qualifier == 'l') {
+                                       long * ip = va_arg(args, long *);
+                                       *ip = (str - buf);
+                               } else if (qualifier == 'Z' || qualifier == 'z') {
+                                       size_t * ip = va_arg(args, size_t *);
+                                       *ip = (str - buf);
+                               } else {
+                                       int * ip = va_arg(args, int *);
+                                       *ip = (str - buf);
+                               }
+                               continue;
+
+                       case '%':
+                               if (str < end)
+                                       *str = '%';
+                               ++str;
+                               continue;
+
+                               /* integer number formats - set up the flags and "break" */
+                       case 'o':
+                               base = 8;
+                               break;
+
+                       case 'X':
+                               flags |= PRINTF_LARGE;
+                       case 'x':
+                               base = 16;
+                               break;
+
+                       case 'd':
+                       case 'i':
+                               flags |= PRINTF_SIGN;
+                       case 'u':
+                               break;
+
+                       default:
+                               if (str < end)
+                                       *str = '%';
+                               ++str;
+                               if (*fmt) {
+                                       if (str < end)
+                                               *str = *fmt;
+                                       ++str;
+                               } else {
+                                       --fmt;
+                               }
+                               continue;
+               }
+               if (qualifier == 'L')
+                       num = va_arg(args, long long);
+               else if (qualifier == 'l') {
+                       num = va_arg(args, unsigned long);
+                       if (flags & PRINTF_SIGN)
+                               num = (signed long) num;
+               } else if (qualifier == 'Z' || qualifier == 'z') {
+                       num = va_arg(args, size_t);
+               } else if (qualifier == 't') {
+                       num = va_arg(args, ptrdiff_t);
+               } else if (qualifier == 'h') {
+                       num = (unsigned short) va_arg(args, int);
+                       if (flags & PRINTF_SIGN)
+                               num = (signed short) num;
+               } else {
+                       num = va_arg(args, unsigned int);
+                       if (flags & PRINTF_SIGN)
+                               num = (signed int) num;
+               }
+               str = number(str, end, num, base,
+                               field_width, precision, flags);
+       }
+       if (size > 0) {
+               if (str < end)
+                       *str = '\0';
+               else
+                       end[-1] = '\0';
+       }
+       /* the trailing null byte doesn't count towards the total */
+       return str-buf;
+}
diff --git a/software/libextra/blockdev.c b/software/libextra/blockdev.c
new file mode 100644 (file)
index 0000000..75963c0
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <hw/flash.h>
+#include <hw/memcard.h>
+#include <string.h>
+
+#include <blockdev.h>
+
+//#define MEMCARD_DEBUG
+
+static void memcard_start_cmd_tx(void)
+{
+       CSR_MEMCARD_ENABLE = MEMCARD_ENABLE_CMD_TX;
+}
+
+static void memcard_start_cmd_rx(void)
+{
+       CSR_MEMCARD_PENDING = MEMCARD_PENDING_CMD_RX;
+       CSR_MEMCARD_START = MEMCARD_START_CMD_RX;
+       CSR_MEMCARD_ENABLE = MEMCARD_ENABLE_CMD_RX;
+}
+
+static void memcard_start_cmd_dat_rx(void)
+{
+       CSR_MEMCARD_PENDING = MEMCARD_PENDING_CMD_RX|MEMCARD_PENDING_DAT_RX;
+       CSR_MEMCARD_START = MEMCARD_START_CMD_RX|MEMCARD_START_DAT_RX;
+       CSR_MEMCARD_ENABLE = MEMCARD_ENABLE_CMD_RX|MEMCARD_ENABLE_DAT_RX;
+}
+
+static void memcard_send_command(unsigned char cmd, unsigned int arg)
+{
+       unsigned char packet[6];
+       int a;
+       int i;
+       unsigned char data;
+       unsigned char crc;
+
+       packet[0] = cmd | 0x40;
+       packet[1] = ((arg >> 24) & 0xff);
+       packet[2] = ((arg >> 16) & 0xff);
+       packet[3] = ((arg >> 8) & 0xff);
+       packet[4] = (arg & 0xff);
+
+       crc = 0;
+       for(a=0;a<5;a++) {
+               data = packet[a];
+               for(i=0;i<8;i++) {
+                       crc <<= 1;
+                       if((data & 0x80) ^ (crc & 0x80))
+                               crc ^= 0x09;
+                       data <<= 1;
+               }
+       }
+       crc = (crc<<1) | 1;
+
+       packet[5] = crc;
+
+#ifdef MEMCARD_DEBUG
+       printf(">> %02x %02x %02x %02x %02x %02x\n", packet[0], packet[1], packet[2], packet[3], packet[4], packet[5]);
+#endif
+
+       for(i=0;i<6;i++) {
+               CSR_MEMCARD_CMD = packet[i];
+               while(CSR_MEMCARD_PENDING & MEMCARD_PENDING_CMD_TX);
+       }
+}
+
+static void memcard_send_dummy(void)
+{
+       CSR_MEMCARD_CMD = 0xff;
+       while(CSR_MEMCARD_PENDING & MEMCARD_PENDING_CMD_TX);
+}
+
+static int memcard_receive_command(unsigned char *buffer, int len)
+{
+       int i;
+       int timeout;
+
+       for(i=0;i<len;i++) {
+               timeout = 2000000;
+               while(!(CSR_MEMCARD_PENDING & MEMCARD_PENDING_CMD_RX)) {
+                       timeout--;
+                       if(timeout == 0) {
+                               #ifdef MEMCARD_DEBUG
+                               printf("Command receive timeout\n");
+                               #endif
+                               return 0;
+                       }
+               }
+               buffer[i] = CSR_MEMCARD_CMD;
+               CSR_MEMCARD_PENDING = MEMCARD_PENDING_CMD_RX;
+       }
+
+       while(!(CSR_MEMCARD_PENDING & MEMCARD_PENDING_CMD_RX));
+
+       #ifdef MEMCARD_DEBUG
+       printf("<< ");
+       for(i=0;i<len;i++)
+               printf("%02x ", buffer[i]);
+       printf("\n");
+       #endif
+
+       return 1;
+}
+
+static int memcard_receive_command_data(unsigned char *command, unsigned int *data)
+{
+       int i, j;
+       int timeout;
+
+       i = 0;
+       j = 0;
+       while(j < 128) {
+               timeout = 2000000;
+               while(!(CSR_MEMCARD_PENDING & (MEMCARD_PENDING_CMD_RX|MEMCARD_PENDING_DAT_RX))) {
+                       timeout--;
+                       if(timeout == 0) {
+                               #ifdef MEMCARD_DEBUG
+                               printf("Command receive timeout\n");
+                               #endif
+                               return 0;
+                       }
+               }
+               if(CSR_MEMCARD_PENDING & MEMCARD_PENDING_CMD_RX) {
+                       command[i++] = CSR_MEMCARD_CMD;
+                       CSR_MEMCARD_PENDING = MEMCARD_PENDING_CMD_RX;
+                       if(i == 6)
+                               CSR_MEMCARD_ENABLE = MEMCARD_ENABLE_DAT_RX; /* disable command RX */
+               }
+               if(CSR_MEMCARD_PENDING & MEMCARD_PENDING_DAT_RX) {
+                       data[j++] = CSR_MEMCARD_DAT;
+                       CSR_MEMCARD_PENDING = MEMCARD_PENDING_DAT_RX;
+               }
+       }
+
+       /* Get CRC (ignored) */
+       for(i=0;i<2;i++) {
+               while(!(CSR_MEMCARD_PENDING & MEMCARD_PENDING_DAT_RX));
+               #ifdef MEMCARD_DEBUG
+               printf("CRC: %08x\n", CSR_MEMCARD_DAT);
+               #endif
+               CSR_MEMCARD_PENDING = MEMCARD_PENDING_DAT_RX;
+       }
+
+       while(!(CSR_MEMCARD_PENDING & MEMCARD_PENDING_DAT_RX));
+
+       #ifdef MEMCARD_DEBUG
+       printf("<< %02x %02x %02x %02x %02x %02x\n", command[0], command[1], command[2], command[3], command[4], command[5]);
+       #endif
+
+       //for(i=0;i<128;i++)
+       //      printf("%08x ", data[i]);
+       //printf("\n");
+
+       return 1;
+}
+
+static int memcard_init(void)
+{
+       unsigned char b[17];
+       unsigned int rca;
+
+       CSR_MEMCARD_CLK2XDIV = 250;
+
+       /* CMD0 */
+       memcard_start_cmd_tx();
+       memcard_send_command(0, 0);
+
+       memcard_send_dummy();
+
+       /* CMD8 */
+       memcard_send_command(8, 0x1aa);
+       memcard_start_cmd_rx();
+       if(!memcard_receive_command(b, 6)) return 0;
+
+       /* ACMD41 - initialize */
+       while(1) {
+               memcard_start_cmd_tx();
+               memcard_send_command(55, 0);
+               memcard_start_cmd_rx();
+               if(!memcard_receive_command(b, 6)) return 0;
+               memcard_start_cmd_tx();
+               memcard_send_command(41, 0x00300000);
+               memcard_start_cmd_rx();
+               if(!memcard_receive_command(b, 6)) return 0;
+               if(b[1] & 0x80) break;
+               #ifdef MEMCARD_DEBUG
+               printf("Card is busy, retrying\n");
+               #endif
+       }
+
+       /* CMD2 - get CID */
+       memcard_start_cmd_tx();
+       memcard_send_command(2, 0);
+       memcard_start_cmd_rx();
+       if(!memcard_receive_command(b, 17)) return 0;
+
+       /* CMD3 - get RCA */
+       memcard_start_cmd_tx();
+       memcard_send_command(3, 0);
+       memcard_start_cmd_rx();
+       if(!memcard_receive_command(b, 6)) return 0;
+       rca = (((unsigned int)b[1]) << 8)|((unsigned int)b[2]);
+       #ifdef MEMCARD_DEBUG
+       printf("RCA: %04x\n", rca);
+       #endif
+
+       /* CMD7 - select card */
+       memcard_start_cmd_tx();
+       memcard_send_command(7, rca << 16);
+       memcard_start_cmd_rx();
+       if(!memcard_receive_command(b, 6)) return 0;
+
+       /* ACMD6 - set bus width */
+       memcard_start_cmd_tx();
+       memcard_send_command(55, rca << 16);
+       memcard_start_cmd_rx();
+       if(!memcard_receive_command(b, 6)) return 0;
+       memcard_start_cmd_tx();
+       memcard_send_command(6, 2);
+       memcard_start_cmd_rx();
+       if(!memcard_receive_command(b, 6)) return 0;
+
+       CSR_MEMCARD_CLK2XDIV = 3;
+
+       return 1;
+}
+
+static int memcard_readblock(unsigned int block, void *buffer)
+{
+       unsigned char b[6];
+
+       /* CMD17 - read block */
+       memcard_start_cmd_tx();
+       memcard_send_command(17, block*512);
+       memcard_start_cmd_dat_rx();
+       if(!memcard_receive_command_data(b, (unsigned int *)buffer)) return 0;
+       return 1;
+}
+
+int bd_init(int devnr)
+{
+       return memcard_init();
+}
+
+int bd_readblock(unsigned int block, void *buffer)
+{
+       return memcard_readblock(block, buffer);
+}
+
+void bd_done(void)
+{
+}
+
+int bd_has_part_table(int devnr)
+{
+       return 1;
+}
diff --git a/software/libextra/crc16.c b/software/libextra/crc16.c
new file mode 100644 (file)
index 0000000..a1222e8
--- /dev/null
@@ -0,0 +1,47 @@
+#include <crc.h>
+
+static const unsigned int crc16_table[256] = {
+       0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
+       0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
+       0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
+       0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
+       0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
+       0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
+       0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
+       0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
+       0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
+       0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
+       0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
+       0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
+       0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
+       0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
+       0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
+       0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
+       0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
+       0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
+       0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
+       0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
+       0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
+       0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+       0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
+       0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
+       0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
+       0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
+       0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
+       0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
+       0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
+       0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
+       0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
+       0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
+};
+
+unsigned short crc16(const unsigned char *buffer, int len)
+{
+       unsigned short crc;
+       
+       crc = 0;
+       while(len-- > 0)
+           crc = crc16_table[((crc >> 8) ^ (*buffer++)) & 0xFF] ^ (crc << 8);
+       
+       return crc;
+}
diff --git a/software/libextra/crc32.c b/software/libextra/crc32.c
new file mode 100644 (file)
index 0000000..29b9b99
--- /dev/null
@@ -0,0 +1,81 @@
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include <crc.h>
+
+static const unsigned int crc_table[256] = {
+       0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+       0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+       0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+       0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+       0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+       0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+       0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+       0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+       0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+       0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+       0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+       0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+       0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+       0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+       0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+       0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+       0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+       0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+       0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+       0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+       0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+       0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+       0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+       0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+       0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+       0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+       0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+       0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+       0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+       0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+       0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+       0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+       0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+       0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+       0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+       0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+       0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+       0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+       0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+       0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+       0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+       0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+       0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+       0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+       0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+       0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+       0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+       0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+       0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+       0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+       0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+       0x2d02ef8dL
+};
+
+#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
+#define DO2(buf)  DO1(buf); DO1(buf);
+#define DO4(buf)  DO2(buf); DO2(buf);
+#define DO8(buf)  DO4(buf); DO4(buf);
+
+unsigned int crc32(const unsigned char *buffer, unsigned int len)
+{
+       unsigned int crc;
+       crc = 0;
+       crc = crc ^ 0xffffffffL;
+       while(len >= 8) {
+               DO8(buffer);
+               len -= 8;
+       }
+       if(len) do {
+               DO1(buffer);
+       } while(--len);
+       return crc ^ 0xffffffffL;
+}
diff --git a/software/libextra/fatfs.c b/software/libextra/fatfs.c
new file mode 100644 (file)
index 0000000..92510cb
--- /dev/null
@@ -0,0 +1,440 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
+ *
+ * This program 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, version 3 of the License.
+ *
+ * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <endian.h>
+#include <console.h>
+#include <blockdev.h>
+
+#include <fatfs.h>
+
+//#define DEBUG
+
+#define BLOCK_SIZE 512
+
+struct partition_descriptor {
+       unsigned char flags;
+       unsigned char start_head;
+       unsigned short start_cylinder;
+       unsigned char type;
+       unsigned char end_head;
+       unsigned short end_cylinder;
+       unsigned int start_sector;
+       unsigned int end_sector;
+} __attribute__((packed));
+
+struct firstsector {
+       unsigned char bootsector[446];
+       struct partition_descriptor partitions[4];
+       unsigned char signature[2];
+} __attribute__((packed));
+
+
+struct fat16_firstsector {
+       /* Common to FATxx */
+       char jmp[3];
+       char oem[8];
+       unsigned short bytes_per_sector;
+       unsigned char sectors_per_cluster;
+       unsigned short reserved_sectors;
+       unsigned char number_of_fat;
+       unsigned short max_root_entries;
+       unsigned short total_sectors_short;
+       unsigned char media_descriptor;
+       unsigned short sectors_per_fat;
+       unsigned short sectors_per_track;
+       unsigned short head_count;
+       unsigned int hidden_sectors;
+       unsigned int total_sectors;
+       
+       /* FAT16 specific */
+       unsigned char drive_nr;
+       unsigned char reserved;
+       unsigned char ext_boot_signature;
+       unsigned int id;
+       unsigned char volume_label[11];
+       unsigned char fstype[8];
+       unsigned char bootcode[448];
+       unsigned char signature[2];
+} __attribute__((packed));
+
+struct directory_entry {
+       unsigned char filename[8];
+       unsigned char extension[3];
+       unsigned char attributes;
+       unsigned char reserved;
+       unsigned char create_time_ms;
+       unsigned short create_time;
+       unsigned short create_date;
+       unsigned short last_access;
+       unsigned short ea_index;
+       unsigned short lastm_time;
+       unsigned short lastm_date;
+       unsigned short first_cluster;
+       unsigned int file_size;
+} __attribute__((packed));
+
+struct directory_entry_lfn {
+       unsigned char seq;
+       unsigned short name1[5]; /* UTF16 */
+       unsigned char attributes;
+       unsigned char reserved;
+       unsigned char checksum;
+       unsigned short name2[6];
+       unsigned short first_cluster;
+       unsigned short name3[2];
+} __attribute__((packed));
+
+#define PARTITION_TYPE_FAT16           0x06
+#define PARTITION_TYPE_FAT32           0x0b
+
+static int fatfs_partition_start_sector;       /* Sector# of the beginning of the FAT16 partition */
+
+static int fatfs_sectors_per_cluster;
+static int fatfs_fat_sector;                   /* Sector of the first FAT */
+static int fatfs_fat_entries;                  /* Number of entries in the FAT */
+static int fatfs_max_root_entries;
+static int fatfs_root_table_sector;            /* Sector# of the beginning of the root table */
+
+static int fatfs_fat_cached_sector;
+static unsigned short int fatfs_fat_sector_cache[BLOCK_SIZE/2];
+
+static int fatfs_dir_cached_sector;
+static struct directory_entry fatfs_dir_sector_cache[BLOCK_SIZE/sizeof(struct directory_entry)];
+
+static int fatfs_data_start_sector;
+
+int fatfs_init(int devnr)
+{
+       struct firstsector s0;
+       struct fat16_firstsector s;
+       int i;
+
+       if(!bd_init(devnr)) {
+               printf("E: Unable to initialize memory card driver\n");
+               return 0;
+       }
+
+       if(bd_has_part_table(devnr)) {
+               /* Read sector 0, with partition table */
+               if(!bd_readblock(0, (void *)&s0)) {
+                       printf("E: Unable to read block 0\n");
+                       return 0;
+               }
+
+               fatfs_partition_start_sector = -1;
+               for(i=0;i<4;i++)
+                       if((s0.partitions[i].type == PARTITION_TYPE_FAT16)
+                       ||(s0.partitions[i].type == PARTITION_TYPE_FAT32)) {
+#ifdef DEBUG
+                               printf("I: Using partition #%d: start sector %08x, end sector %08x\n", i,
+                                       le32toh(s0.partitions[i].start_sector), le32toh(s0.partitions[i].end_sector));
+#endif
+                               fatfs_partition_start_sector = le32toh(s0.partitions[i].start_sector);
+                               break;
+                       }
+               if(fatfs_partition_start_sector == -1) {
+                       printf("E: No FAT partition was found\n");
+                       return 0;
+               }
+       } else
+               fatfs_partition_start_sector = 0;
+       
+       /* Read first FAT16 sector */
+       if(!bd_readblock(fatfs_partition_start_sector, (void *)&s)) {
+               printf("E: Unable to read first FAT sector\n");
+               return 0;
+       }
+       
+#ifdef DEBUG
+       {
+               char oem[9];
+               char volume_label[12];
+               memcpy(oem, s.oem, 8);
+               oem[8] = 0;
+               memcpy(volume_label, s.volume_label, 11);
+               volume_label[11] = 0;
+               printf("I: OEM name: %s\n", oem);
+               printf("I: Volume label: %s\n", volume_label);
+       }
+#endif
+       
+       if(le16toh(s.bytes_per_sector) != BLOCK_SIZE) {
+               printf("E: Unexpected number of bytes per sector (%d)\n", le16toh(s.bytes_per_sector));
+               return 0;
+       }
+       fatfs_sectors_per_cluster = s.sectors_per_cluster;
+       
+       fatfs_fat_entries = (le16toh(s.sectors_per_fat)*BLOCK_SIZE)/2;
+       fatfs_fat_sector = fatfs_partition_start_sector + 1;
+       fatfs_fat_cached_sector = -1;
+       
+       fatfs_max_root_entries = le16toh(s.max_root_entries);
+       fatfs_root_table_sector = fatfs_fat_sector + s.number_of_fat*le16toh(s.sectors_per_fat);
+       fatfs_dir_cached_sector = -1;
+       
+       fatfs_data_start_sector = fatfs_root_table_sector + (fatfs_max_root_entries*sizeof(struct directory_entry))/BLOCK_SIZE;
+
+       if(fatfs_max_root_entries == 0) {
+               printf("E: Your memory card uses FAT32, which is not supported.\n");
+               printf("E: Please reformat your card using FAT16, e.g. use mkdosfs -F 16\n");
+               printf("E: FAT32 support would be an appreciated contribution.\n");
+               return 0;
+       }
+       
+#ifdef DEBUG
+       printf("I: Cluster is %d sectors, FAT has %d entries, FAT 1 is at sector %d,\nI: root table is at sector %d (max %d), data is at sector %d, nb of fat: %d\n",
+               fatfs_sectors_per_cluster, fatfs_fat_entries, fatfs_fat_sector,
+               fatfs_root_table_sector, fatfs_max_root_entries,
+               fatfs_data_start_sector, s.number_of_fat);
+#endif
+       return 1;
+}
+
+static int fatfs_read_fat(int offset)
+{
+       int wanted_sector;
+       
+       if((offset < 0) || (offset >= fatfs_fat_entries)) {
+               printf("E: Incorrect offset %d in fatfs_read_fat\n", offset);
+               return -1;
+       }
+               
+       wanted_sector = fatfs_fat_sector + (offset*2)/BLOCK_SIZE;
+       if(wanted_sector != fatfs_fat_cached_sector) {
+               if(!bd_readblock(wanted_sector, (void *)&fatfs_fat_sector_cache)) {
+                       printf("E: Memory card failed (FAT), sector %d\n", wanted_sector);
+                       return -1;
+               }
+               fatfs_fat_cached_sector = wanted_sector;
+       }
+       
+       return le16toh(fatfs_fat_sector_cache[offset % (BLOCK_SIZE/2)]);
+}
+
+static const struct directory_entry *fatfs_read_root_directory(int offset)
+{
+       int wanted_sector;
+       
+       if((offset < 0) || (offset >= fatfs_max_root_entries))
+               return NULL;
+
+       wanted_sector = fatfs_root_table_sector + (offset*sizeof(struct directory_entry))/BLOCK_SIZE;
+
+       if(wanted_sector != fatfs_dir_cached_sector) {
+               if(!bd_readblock(wanted_sector, (void *)&fatfs_dir_sector_cache)) {
+                       printf("E: Memory card failed (Rootdir), sector %d\n", wanted_sector);
+                       return NULL;
+               }
+               fatfs_dir_cached_sector = wanted_sector;
+       }
+       return &fatfs_dir_sector_cache[offset % (BLOCK_SIZE/sizeof(struct directory_entry))];
+}
+
+static void lfn_to_ascii(const struct directory_entry_lfn *entry, char *name, int terminate)
+{
+       int i;
+       unsigned short c;
+
+       for(i=0;i<5;i++) {
+               c = le16toh(entry->name1[i]);
+               if(c <= 255) {
+                       *name = c;
+                       name++;
+                       if(c == 0) return;
+               }
+       }
+       for(i=0;i<6;i++) {
+               c = le16toh(entry->name2[i]);
+               if(c <= 255) {
+                       *name = c;
+                       name++;
+                       if(c == 0) return;
+               }
+       }
+       for(i=0;i<2;i++) {
+               c = le16toh(entry->name3[i]);
+               if(c <= 255) {
+                       *name = c;
+                       name++;
+                       if(c == 0) return;
+               }
+       }
+
+       if(terminate)
+               *name = 0;
+}
+
+static int fatfs_is_regular(const struct directory_entry *entry)
+{
+       return ((entry->attributes & 0x10) == 0)
+               && ((entry->attributes & 0x08) == 0)
+               && (entry->filename[0] != 0xe5);
+}
+
+int fatfs_list_files(fatfs_dir_callback cb, void *param)
+{
+       const struct directory_entry *entry;
+       char fmtbuf[8+1+3+1];
+       char longname[131];
+       int has_longname;
+       int i, j, k;
+
+       has_longname = 0;
+       longname[sizeof(longname)-1] = 0; /* avoid crashing when reading a corrupt FS */
+       for(k=0;k<fatfs_max_root_entries;k++) {
+               entry = fatfs_read_root_directory(k);
+#ifdef DEBUG
+               printf("I: Read entry with attribute %02x\n", entry->attributes);
+#endif
+               if(entry->attributes == 0x0f) {
+                       const struct directory_entry_lfn *entry_lfn;
+                       unsigned char frag;
+                       int terminate;
+
+                       entry_lfn = (const struct directory_entry_lfn *)entry;
+                       frag = entry_lfn->seq & 0x3f;
+                       terminate = entry_lfn->seq & 0x40;
+                       if(frag*13 < sizeof(longname)) {
+                               lfn_to_ascii((const struct directory_entry_lfn *)entry, &longname[(frag-1)*13], terminate);
+                               if(frag == 1) has_longname = 1;
+                       }
+                       continue;
+               } else {
+                       if(!fatfs_is_regular(entry)) {
+                               has_longname = 0;
+                               continue;
+                       }
+               }
+               if(entry == NULL) return 0;
+               if(entry->filename[0] == 0) {
+                       has_longname = 0;
+                       break;
+               }
+               j = 0;
+               for(i=0;i<8;i++) {
+                       if(entry->filename[i] == ' ') break;
+                       fmtbuf[j++] = entry->filename[i];
+               }
+               fmtbuf[j++] = '.';
+               for(i=0;i<3;i++) {
+                       if(entry->extension[i] == ' ') break;
+                       fmtbuf[j++] = entry->extension[i];
+               }
+               fmtbuf[j++] = 0;
+               if(!cb(fmtbuf, has_longname ? longname : fmtbuf, param)) return 0;
+               has_longname = 0;
+       }
+       return 1;
+}
+
+static const struct directory_entry *fatfs_find_file_by_name(const char *filename)
+{
+       char searched_filename[8];
+       char searched_extension[3];
+       char *dot;
+       const char *c;
+       int i;
+       const struct directory_entry *entry;
+       
+       dot = strrchr(filename, '.');
+       if(dot == NULL)
+               return NULL;
+       
+       memset(searched_filename, ' ', 8);
+       memset(searched_extension, ' ', 3);
+       i = 0;
+       for(c=filename;c<dot;c++)
+               searched_filename[i++] = toupper(*c);
+               
+       i = 0;
+       for(c=dot+1;*c!=0;c++)
+               searched_extension[i++] = toupper(*c);
+               
+       for(i=0;i<fatfs_max_root_entries;i++) {
+               entry = fatfs_read_root_directory(i);
+               if(entry == NULL) break;
+               if(entry->filename[0] == 0) break;
+               if(!fatfs_is_regular(entry)) continue;
+               if(!memcmp(searched_filename, entry->filename, 8)
+                &&!memcmp(searched_extension, entry->extension, 3))
+                       return entry;
+       }
+       return NULL;
+}
+
+static int fatfs_load_cluster(int clustern, char *buffer, int maxsectors)
+{
+       int startsector;
+       int i;
+       int toread;
+       
+       clustern = clustern - 2;
+       startsector = fatfs_data_start_sector + clustern*fatfs_sectors_per_cluster;
+       if(maxsectors < fatfs_sectors_per_cluster)
+               toread = maxsectors;
+       else
+               toread = fatfs_sectors_per_cluster;
+       for(i=0;i<toread;i++)
+               if(!bd_readblock(startsector+i, (unsigned char *)buffer+i*BLOCK_SIZE)) {
+                       printf("E: Memory card failed (Cluster), sector %d\n", startsector+i);
+                       return 0;
+               }
+       return 1;
+}
+
+int fatfs_load(const char *filename, char *buffer, int size, int *realsize)
+{
+       const struct directory_entry *entry;
+       int cluster_size;
+       int cluster;
+       int n;
+       
+       cluster_size = fatfs_sectors_per_cluster*BLOCK_SIZE;
+       size /= BLOCK_SIZE;
+       
+       entry = fatfs_find_file_by_name(filename);
+       if(entry == NULL) {
+               printf("E: File not found: %s\n", filename);
+               return 0;
+       }
+       
+       if(realsize != NULL) *realsize = le32toh(entry->file_size);
+       
+       n = 0;
+       cluster = le16toh(entry->first_cluster);
+       while(size > 0) {
+               if(!fatfs_load_cluster(cluster, buffer+n*cluster_size, size))
+                       return 0;
+               size -= fatfs_sectors_per_cluster;
+               n++;
+               cluster = fatfs_read_fat(cluster);
+               if(cluster >= 0xFFF8) break;
+               if(cluster == -1) return 0;
+       }
+       //putsnonl("\n");
+       
+       return n*cluster_size;
+}
+
+void fatfs_done(void)
+{
+       bd_done();
+}