From: Sebastien Bourdeauducq Date: Fri, 3 Feb 2012 11:08:17 +0000 (+0100) Subject: Copy some software code from the original Milkymist SoC. X-Git-Tag: 24jan2021_ls180~3268 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=1a4a6eb445a51eb8953ba5285ca07be9d70b7572;p=litex.git Copy some software code from the original Milkymist SoC. 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) --- diff --git a/software/include.mak b/software/include.mak new file mode 100644 index 00000000..b0a774a1 --- /dev/null +++ b/software/include.mak @@ -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 index 00000000..6bfaba6c --- /dev/null +++ b/software/include/base/assert.h @@ -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 . + */ + +#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 index 00000000..3227314c --- /dev/null +++ b/software/include/base/board.h @@ -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 . + */ + +#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 index 00000000..d89f0a15 --- /dev/null +++ b/software/include/base/console.h @@ -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 . + */ + +#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 index 00000000..926b761a --- /dev/null +++ b/software/include/base/ctype.h @@ -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 . + */ + +#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 index 00000000..9cdf98c5 --- /dev/null +++ b/software/include/base/endian.h @@ -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 . + */ + +#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 index 00000000..43e44734 --- /dev/null +++ b/software/include/base/irq.h @@ -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 . + */ + +#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 index 00000000..aaf97213 --- /dev/null +++ b/software/include/base/limits.h @@ -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 . + */ + +#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 index 00000000..7729b7e5 --- /dev/null +++ b/software/include/base/stdarg.h @@ -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 . + */ + +#ifndef __STDARG_H +#define __STDARG_H + +#include + +#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 index 00000000..5fb35a59 --- /dev/null +++ b/software/include/base/stdio.h @@ -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 . + */ + +#ifndef __STDIO_H +#define __STDIO_H + +#include + +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 index 00000000..ed22bdd9 --- /dev/null +++ b/software/include/base/stdlib.h @@ -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 . + */ + +#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 index 00000000..667d2d88 --- /dev/null +++ b/software/include/base/string.h @@ -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 . + */ + +#ifndef __STRING_H +#define __STRING_H + +#include + +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 index 00000000..5eb6a219 --- /dev/null +++ b/software/include/base/system.h @@ -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 . + */ + +#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 index 00000000..0c03c02a --- /dev/null +++ b/software/include/base/uart.h @@ -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 . + */ + +#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 index 00000000..3f70d0eb --- /dev/null +++ b/software/include/base/version.h @@ -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 index 00000000..6252d1dc --- /dev/null +++ b/software/include/extra/blockdev.h @@ -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 . + */ + +#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 index 00000000..3f239546 --- /dev/null +++ b/software/include/extra/crc.h @@ -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 . + */ + +#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 index 00000000..a6a71a8a --- /dev/null +++ b/software/include/extra/fatfs.h @@ -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 . + */ + +#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 index 00000000..a6dba088 --- /dev/null +++ b/software/include/hw/capabilities.h @@ -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 . + */ + +#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 index 00000000..5d9c61a5 --- /dev/null +++ b/software/include/hw/common.h @@ -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 . + */ + +#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 index 00000000..f09de41b --- /dev/null +++ b/software/include/hw/flash.h @@ -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 . + */ + +#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 index 00000000..7ebb0c83 --- /dev/null +++ b/software/include/hw/gpio.h @@ -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 . + */ + +#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 index 00000000..2f48cee2 --- /dev/null +++ b/software/include/hw/interrupts.h @@ -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 . + */ + +#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 index 00000000..d00471b2 --- /dev/null +++ b/software/include/hw/sysctl.h @@ -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 . + */ + +#ifndef __HW_SYSCTL_H +#define __HW_SYSCTL_H + +#include + +#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 index 00000000..5540ca44 --- /dev/null +++ b/software/include/hw/uart.h @@ -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 . + */ + +#ifndef __HW_UART_H +#define __HW_UART_H + +#include + +#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 index 00000000..a9027a27 --- /dev/null +++ b/software/libbase/Makefile @@ -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 index 00000000..19075c9d --- /dev/null +++ b/software/libbase/atof.c @@ -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 +#include + +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 index 00000000..b81779ef --- /dev/null +++ b/software/libbase/board.c @@ -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 . + */ + +#include +#include +#include +#include +#include + +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> 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 index 00000000..d27bff3d --- /dev/null +++ b/software/libbase/console.c @@ -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 . + */ + +#include +#include +#include +#include +#include +#include + +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 index 00000000..35d171e7 --- /dev/null +++ b/software/libbase/divsi3.c @@ -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 index 00000000..565927a5 --- /dev/null +++ b/software/libbase/libc.c @@ -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 . + */ + +#include +#include +#include +#include +#include +#include + +/** + * 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 index 00000000..58d688d0 --- /dev/null +++ b/software/libbase/milieu.h @@ -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 index 00000000..2d7f2055 --- /dev/null +++ b/software/libbase/softfloat-glue.c @@ -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 . + */ + +#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 index 00000000..40d1182b --- /dev/null +++ b/software/libbase/softfloat-macros.h @@ -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<>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<>count ) | ( ( a1<>count; + } + else { + if ( count == 32 ) { + z1 = a0 | ( a1 != 0 ); + } + else if ( count < 64 ) { + z1 = ( a0>>( count & 31 ) ) | ( ( ( a0<>count ); + z0 = a0>>count; + } + else { + if ( count == 32 ) { + z2 = a1; + z1 = a0; + } + else { + a2 |= a1; + if ( count < 64 ) { + z2 = 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 ) & 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<>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 index 00000000..9f3466f1 --- /dev/null +++ b/software/libbase/softfloat-specialize.h @@ -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 index 00000000..9ab4f0bd --- /dev/null +++ b/software/libbase/softfloat.c @@ -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<>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 ); + } + 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 index 00000000..29454c0e --- /dev/null +++ b/software/libbase/softfloat.h @@ -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 index 00000000..0edcb818 --- /dev/null +++ b/software/libbase/system.c @@ -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 . + */ + +#include +#include +#include + +#include + +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 index 00000000..9ec12ab1 --- /dev/null +++ b/software/libbase/uart.c @@ -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 . + */ + +#include +#include +#include +#include + +/* + * 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 index 00000000..102ee8cb --- /dev/null +++ b/software/libbase/vsnprintf.c @@ -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 . + */ + +#include +#include +#include +#include +#include + +#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 = ""; + + 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 index 00000000..75963c07 --- /dev/null +++ b/software/libextra/blockdev.c @@ -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 . + */ + +#include +#include +#include + +#include + +//#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 + +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 index 00000000..29b9b994 --- /dev/null +++ b/software/libextra/crc32.c @@ -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 + +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 index 00000000..92510cb5 --- /dev/null +++ b/software/libextra/fatfs.c @@ -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 . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +//#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;kattributes); +#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;cfilename[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;ifile_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(); +}