diff --git a/Makefile b/Makefile
index 5904a3f967e3..7e76ac915fc7 100644
--- a/Makefile
+++ b/Makefile
@@ -239,7 +239,7 @@ _MAKE+= MK_META_MODE=no
_TARGET_ARCH= ${TARGET:S/pc98/i386/:S/arm64/aarch64/}
.elif !defined(TARGET) && defined(TARGET_ARCH) && \
${TARGET_ARCH} != ${MACHINE_ARCH}
-_TARGET= ${TARGET_ARCH:C/mips(n32|64)?(el)?(hf)?/mips/:C/arm(v6)?(eb)?/arm/:C/aarch64/arm64/:C/powerpc64/powerpc/:C/powerpcspe/powerpc/:C/riscv64/riscv/}
+_TARGET= ${TARGET_ARCH:C/mips(n32|64)?(el)?(hf)?/mips/:C/arm(v6)?(eb)?/arm/:C/aarch64/arm64/:C/powerpc64/powerpc/:C/powerpcspe/powerpc/:C/riscv64(sf)?/riscv/}
.endif
.if defined(TARGET) && !defined(_TARGET)
_TARGET=${TARGET}
diff --git a/Makefile.inc1 b/Makefile.inc1
index d78cfd26a162..a5b44cb6c8b9 100644
--- a/Makefile.inc1
+++ b/Makefile.inc1
@@ -364,6 +364,7 @@ KNOWN_ARCHES?= aarch64/arm64 \
powerpc64/powerpc \
powerpcspe/powerpc \
riscv64/riscv \
+ riscv64sf/riscv \
sparc64
.if ${TARGET} == ${TARGET_ARCH}
diff --git a/gnu/usr.bin/cc/Makefile.tgt b/gnu/usr.bin/cc/Makefile.tgt
index 3acd4d7c9295..eb8ee7b4db8e 100644
--- a/gnu/usr.bin/cc/Makefile.tgt
+++ b/gnu/usr.bin/cc/Makefile.tgt
@@ -4,7 +4,7 @@
# MACHINE_CPUARCH, but there's no easy way to export make functions...
.if defined(TARGET_ARCH)
-TARGET_CPUARCH=${TARGET_ARCH:C/mips(n32|64)?(el)?(hf)?/mips/:C/arm(v6)?(eb)?/arm/:C/powerpc(64|spe)/powerpc/}
+TARGET_CPUARCH=${TARGET_ARCH:C/mips(n32|64)?(el)?(hf)?/mips/:C/arm(v6)?(eb)?/arm/:C/powerpc(64|spe)/powerpc/:C/riscv64(sf)?/riscv64/}
.else
TARGET_CPUARCH=${MACHINE_CPUARCH}
.endif
diff --git a/lib/libc/Makefile b/lib/libc/Makefile
index 99ddfc2e8f7f..377a6ee6cd11 100644
--- a/lib/libc/Makefile
+++ b/lib/libc/Makefile
@@ -111,7 +111,8 @@ NOASM=
.include "${LIBC_SRCTOP}/xdr/Makefile.inc"
.if (${LIBC_ARCH} == "arm" && \
(${MACHINE_ARCH:Marmv6*} == "" || (defined(CPUTYPE) && ${CPUTYPE:M*soft*}))) || \
- (${LIBC_ARCH} == "mips" && ${MACHINE_ARCH:Mmips*hf} == "")
+ (${LIBC_ARCH} == "mips" && ${MACHINE_ARCH:Mmips*hf} == "") || \
+ (${LIBC_ARCH} == "riscv" && ${MACHINE_ARCH:Mriscv*sf} != "")
.include "${LIBC_SRCTOP}/softfloat/Makefile.inc"
.endif
.if ${LIBC_ARCH} == "i386" || ${LIBC_ARCH} == "amd64"
diff --git a/lib/libc/riscv/Makefile.inc b/lib/libc/riscv/Makefile.inc
index b22190353e32..105839021b96 100644
--- a/lib/libc/riscv/Makefile.inc
+++ b/lib/libc/riscv/Makefile.inc
@@ -3,6 +3,10 @@
# Machine dependent definitions for the RISC-V architecture.
#
+.if ${MACHINE_ARCH:Mriscv*sf} != ""
+CFLAGS+=-DSOFTFLOAT
+.endif
+
# Long double is quad precision
GDTOASRCS+=strtorQ.c
MDSRCS+=machdep_ldisQ.c
diff --git a/lib/libc/riscv/Symbol.map b/lib/libc/riscv/Symbol.map
index 669dad37983f..b959072e7e0c 100644
--- a/lib/libc/riscv/Symbol.map
+++ b/lib/libc/riscv/Symbol.map
@@ -35,4 +35,22 @@ FBSDprivate_1.0 {
_set_tp;
_end;
__makecontext;
+
+ /* softfloat */
+ __addsf3;
+ __adddf3;
+ __subsf3;
+ __subdf3;
+ __mulsf3;
+ __muldf3;
+ __divsf3;
+ __divdf3;
+ __floatsisf;
+ __floatsidf;
+ __fixsfsi;
+ __fixdfsi;
+ __fixunssfsi;
+ __fixunsdfsi;
+ __extendsfdf2;
+ __truncdfsf2;
};
diff --git a/lib/libc/riscv/gen/_setjmp.S b/lib/libc/riscv/gen/_setjmp.S
index 1fa064d2ecf2..4e82ae420850 100644
--- a/lib/libc/riscv/gen/_setjmp.S
+++ b/lib/libc/riscv/gen/_setjmp.S
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2015 Ruslan Bukin
+ * Copyright (c) 2015-2016 Ruslan Bukin
* All rights reserved.
*
* Portions of this software were developed by SRI International and the
@@ -61,24 +61,21 @@ ENTRY(_setjmp)
sd ra, (12 * 8)(a0)
addi a0, a0, (13 * 8)
-#ifndef _STANDALONE
-#if 0
- /* RISCVTODO */
- /* Store the vfp registers */
- fsq fs0, (0 * 16)(a0)
- fsq fs1, (1 * 16)(a0)
- fsq fs2, (2 * 16)(a0)
- fsq fs3, (3 * 16)(a0)
- fsq fs4, (4 * 16)(a0)
- fsq fs5, (5 * 16)(a0)
- fsq fs6, (6 * 16)(a0)
- fsq fs7, (7 * 16)(a0)
- fsq fs8, (8 * 16)(a0)
- fsq fs9, (9 * 16)(a0)
- fsq fs10, (10 * 16)(a0)
- fsq fs11, (11 * 16)(a0)
+#if !defined(_STANDALONE) && !defined(SOFTFLOAT)
+ /* Store the fpe registers */
+ fsd fs0, (0 * 16)(a0)
+ fsd fs1, (1 * 16)(a0)
+ fsd fs2, (2 * 16)(a0)
+ fsd fs3, (3 * 16)(a0)
+ fsd fs4, (4 * 16)(a0)
+ fsd fs5, (5 * 16)(a0)
+ fsd fs6, (6 * 16)(a0)
+ fsd fs7, (7 * 16)(a0)
+ fsd fs8, (8 * 16)(a0)
+ fsd fs9, (9 * 16)(a0)
+ fsd fs10, (10 * 16)(a0)
+ fsd fs11, (11 * 16)(a0)
addi a0, a0, (12 * 16)
-#endif
#endif
/* Return value */
@@ -117,24 +114,21 @@ ENTRY(_longjmp)
ld ra, (12 * 8)(a0)
addi a0, a0, (13 * 8)
-#ifndef _STANDALONE
-#if 0
- /* RISCVTODO */
- /* Restore the vfp registers */
- flq fs0, (0 * 16)(a0)
- flq fs1, (1 * 16)(a0)
- flq fs2, (2 * 16)(a0)
- flq fs3, (3 * 16)(a0)
- flq fs4, (4 * 16)(a0)
- flq fs5, (5 * 16)(a0)
- flq fs6, (6 * 16)(a0)
- flq fs7, (7 * 16)(a0)
- flq fs8, (8 * 16)(a0)
- flq fs9, (9 * 16)(a0)
- flq fs10, (10 * 16)(a0)
- flq fs11, (11 * 16)(a0)
+#if !defined(_STANDALONE) && !defined(SOFTFLOAT)
+ /* Restore the fpe registers */
+ fld fs0, (0 * 16)(a0)
+ fld fs1, (1 * 16)(a0)
+ fld fs2, (2 * 16)(a0)
+ fld fs3, (3 * 16)(a0)
+ fld fs4, (4 * 16)(a0)
+ fld fs5, (5 * 16)(a0)
+ fld fs6, (6 * 16)(a0)
+ fld fs7, (7 * 16)(a0)
+ fld fs8, (8 * 16)(a0)
+ fld fs9, (9 * 16)(a0)
+ fld fs10, (10 * 16)(a0)
+ fld fs11, (11 * 16)(a0)
addi a0, a0, (12 * 16)
-#endif
#endif
/* Load the return value */
diff --git a/lib/libc/riscv/gen/flt_rounds.c b/lib/libc/riscv/gen/flt_rounds.c
index 179963cfa29e..13bb8b2a1796 100644
--- a/lib/libc/riscv/gen/flt_rounds.c
+++ b/lib/libc/riscv/gen/flt_rounds.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2015 Ruslan Bukin
+ * Copyright (c) 2015-2016 Ruslan Bukin
* All rights reserved.
*
* Portions of this software were developed by SRI International and the
@@ -40,23 +40,24 @@ __FBSDID("$FreeBSD$");
#include
#include
+#ifdef SOFTFLOAT
+#include "softfloat-for-gcc.h"
+#include "milieu.h"
+#include "softfloat.h"
+#endif
+
int
__flt_rounds(void)
{
-#if 0
- uint64_t fcsr;
-#endif
- int mode;
+ uint64_t mode;
-#if 0
- __asm __volatile("csrr %0, fcsr" : "=r" (fcsr));
- mode = (fcsr & _ROUND_MASK);
+#ifdef SOFTFLOAT
+ mode = __softfloat_float_rounding_mode;
+#else
+ __asm __volatile("csrr %0, fcsr" : "=r" (mode));
#endif
- /* RISCVTODO */
- mode = FE_TOWARDZERO; /* softfloat rounding mode */
-
- switch (mode) {
+ switch (mode & _ROUND_MASK) {
case FE_TOWARDZERO:
return (0);
case FE_TONEAREST:
diff --git a/lib/libc/riscv/gen/setjmp.S b/lib/libc/riscv/gen/setjmp.S
index de8d7b5d5190..9d97b51de6b6 100644
--- a/lib/libc/riscv/gen/setjmp.S
+++ b/lib/libc/riscv/gen/setjmp.S
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2015 Ruslan Bukin
+ * Copyright (c) 2015-2016 Ruslan Bukin
* All rights reserved.
*
* Portions of this software were developed by SRI International and the
@@ -75,21 +75,20 @@ ENTRY(setjmp)
sd ra, (12 * 8)(a0)
addi a0, a0, (13 * 8)
-#if 0
- /* RISCVTODO */
- /* Store the vfp registers */
- fsq fs0, (0 * 16)(a0)
- fsq fs1, (1 * 16)(a0)
- fsq fs2, (2 * 16)(a0)
- fsq fs3, (3 * 16)(a0)
- fsq fs4, (4 * 16)(a0)
- fsq fs5, (5 * 16)(a0)
- fsq fs6, (6 * 16)(a0)
- fsq fs7, (7 * 16)(a0)
- fsq fs8, (8 * 16)(a0)
- fsq fs9, (9 * 16)(a0)
- fsq fs10, (10 * 16)(a0)
- fsq fs11, (11 * 16)(a0)
+#ifndef SOFTFLOAT
+ /* Store the fpe registers */
+ fsd fs0, (0 * 16)(a0)
+ fsd fs1, (1 * 16)(a0)
+ fsd fs2, (2 * 16)(a0)
+ fsd fs3, (3 * 16)(a0)
+ fsd fs4, (4 * 16)(a0)
+ fsd fs5, (5 * 16)(a0)
+ fsd fs6, (6 * 16)(a0)
+ fsd fs7, (7 * 16)(a0)
+ fsd fs8, (8 * 16)(a0)
+ fsd fs9, (9 * 16)(a0)
+ fsd fs10, (10 * 16)(a0)
+ fsd fs11, (11 * 16)(a0)
addi a0, a0, (12 * 16)
#endif
@@ -145,21 +144,20 @@ ENTRY(longjmp)
ld ra, (12 * 8)(a0)
addi a0, a0, (13 * 8)
-#if 0
- /* RISCVTODO */
- /* Restore the vfp registers */
- flq fs0, (0 * 16)(a0)
- flq fs1, (1 * 16)(a0)
- flq fs2, (2 * 16)(a0)
- flq fs3, (3 * 16)(a0)
- flq fs4, (4 * 16)(a0)
- flq fs5, (5 * 16)(a0)
- flq fs6, (6 * 16)(a0)
- flq fs7, (7 * 16)(a0)
- flq fs8, (8 * 16)(a0)
- flq fs9, (9 * 16)(a0)
- flq fs10, (10 * 16)(a0)
- flq fs11, (11 * 16)(a0)
+#ifndef SOFTFLOAT
+ /* Restore the fpe registers */
+ fld fs0, (0 * 16)(a0)
+ fld fs1, (1 * 16)(a0)
+ fld fs2, (2 * 16)(a0)
+ fld fs3, (3 * 16)(a0)
+ fld fs4, (4 * 16)(a0)
+ fld fs5, (5 * 16)(a0)
+ fld fs6, (6 * 16)(a0)
+ fld fs7, (7 * 16)(a0)
+ fld fs8, (8 * 16)(a0)
+ fld fs9, (9 * 16)(a0)
+ fld fs10, (10 * 16)(a0)
+ fld fs11, (11 * 16)(a0)
addi a0, a0, (12 * 16)
#endif
diff --git a/lib/libc/riscv/softfloat/milieu.h b/lib/libc/riscv/softfloat/milieu.h
new file mode 100644
index 000000000000..e97437bdc2d1
--- /dev/null
+++ b/lib/libc/riscv/softfloat/milieu.h
@@ -0,0 +1,48 @@
+/* $FreeBSD$ */
+
+/*
+===============================================================================
+
+This C header file is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2a.
+
+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 four paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+/*
+-------------------------------------------------------------------------------
+Include common integer types and flags.
+-------------------------------------------------------------------------------
+*/
+#include "riscv-gcc.h"
+
+/*
+-------------------------------------------------------------------------------
+Symbolic Boolean literals.
+-------------------------------------------------------------------------------
+*/
+enum {
+ FALSE = 0,
+ TRUE = 1
+};
diff --git a/lib/libc/riscv/softfloat/riscv-gcc.h b/lib/libc/riscv/softfloat/riscv-gcc.h
new file mode 100644
index 000000000000..3fe1767e63cc
--- /dev/null
+++ b/lib/libc/riscv/softfloat/riscv-gcc.h
@@ -0,0 +1,86 @@
+/* $NetBSD: arm-gcc.h,v 1.2 2001/02/21 18:09:25 bjh21 Exp $ */
+/* $FreeBSD$ */
+
+/*
+-------------------------------------------------------------------------------
+One of the macros `BIGENDIAN' or `LITTLEENDIAN' must be defined.
+-------------------------------------------------------------------------------
+*/
+#define LITTLEENDIAN
+
+/*
+-------------------------------------------------------------------------------
+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 uint64;
+typedef signed long long int int64;
+#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 bits64;
+typedef signed long long int sbits64;
+#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 static __inline
+
+#if defined(SOFTFLOAT_FOR_GCC)
+#define FLOAT64_DEMANGLE(a) (a)
+#define FLOAT64_MANGLE(a) (a)
+#endif
diff --git a/lib/libc/riscv/softfloat/softfloat.h b/lib/libc/riscv/softfloat/softfloat.h
new file mode 100644
index 000000000000..6aef49975a38
--- /dev/null
+++ b/lib/libc/riscv/softfloat/softfloat.h
@@ -0,0 +1,315 @@
+/* $NetBSD: softfloat.h,v 1.6 2002/05/12 13:12:46 bjh21 Exp $ */
+/* $FreeBSD$ */
+
+/* This is a derivative work. */
+
+/*
+===============================================================================
+
+This C header file is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2a.
+
+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 four paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+/*
+-------------------------------------------------------------------------------
+The macro `FLOATX80' must be defined to enable the extended double-precision
+floating-point format `floatx80'. If this macro is not defined, the
+`floatx80' type will not be defined, and none of the functions that either
+input or output the `floatx80' type will be defined. The same applies to
+the `FLOAT128' macro and the quadruple-precision format `float128'.
+-------------------------------------------------------------------------------
+*/
+/* #define FLOATX80 */
+/* #define FLOAT128 */
+
+#include
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point types.
+-------------------------------------------------------------------------------
+*/
+typedef unsigned int float32;
+typedef unsigned long long float64;
+#ifdef FLOATX80
+typedef struct {
+ unsigned short high;
+ unsigned long long low;
+} floatx80;
+#endif
+#ifdef FLOAT128
+typedef struct {
+ unsigned long long high, low;
+} float128;
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point underflow tininess-detection mode.
+-------------------------------------------------------------------------------
+*/
+#ifndef SOFTFLOAT_FOR_GCC
+extern int float_detect_tininess;
+#endif
+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 = FE_TONEAREST,
+ float_round_to_zero = FE_TOWARDZERO,
+ float_round_down = FE_DOWNWARD,
+ float_round_up = FE_UPWARD
+};
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE floating-point exception flags.
+-------------------------------------------------------------------------------
+*/
+extern int float_exception_flags;
+extern int float_exception_mask;
+enum {
+ float_flag_inexact = FE_INEXACT,
+ float_flag_underflow = FE_UNDERFLOW,
+ float_flag_overflow = FE_OVERFLOW,
+ float_flag_divbyzero = FE_DIVBYZERO,
+ float_flag_invalid = FE_INVALID
+};
+
+/*
+-------------------------------------------------------------------------------
+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 );
+float64 int32_to_float64( int );
+#ifdef FLOATX80
+floatx80 int32_to_floatx80( int );
+#endif
+#ifdef FLOAT128
+float128 int32_to_float128( int );
+#endif
+#ifndef SOFTFLOAT_FOR_GCC /* __floatdi?f is in libgcc2.c */
+float32 int64_to_float32( long long );
+float64 int64_to_float64( long long );
+#ifdef FLOATX80
+floatx80 int64_to_floatx80( long long );
+#endif
+#ifdef FLOAT128
+float128 int64_to_float128( long long );
+#endif
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE single-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+int float32_to_int32( float32 );
+int float32_to_int32_round_to_zero( float32 );
+#if defined(SOFTFLOAT_FOR_GCC) && defined(SOFTFLOAT_NEED_FIXUNS)
+unsigned int float32_to_uint32_round_to_zero( float32 );
+#endif
+#ifndef SOFTFLOAT_FOR_GCC /* __fix?fdi provided by libgcc2.c */
+long long float32_to_int64( float32 );
+long long float32_to_int64_round_to_zero( float32 );
+#endif
+float64 float32_to_float64( float32 );
+#ifdef FLOATX80
+floatx80 float32_to_floatx80( float32 );
+#endif
+#ifdef FLOAT128
+float128 float32_to_float128( float32 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+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 );
+#ifndef SOFTFLOAT_FOR_GCC
+int float32_is_signaling_nan( float32 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE double-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+int float64_to_int32( float64 );
+int float64_to_int32_round_to_zero( float64 );
+#if defined(SOFTFLOAT_FOR_GCC) && defined(SOFTFLOAT_NEED_FIXUNS)
+unsigned int float64_to_uint32_round_to_zero( float64 );
+#endif
+#ifndef SOFTFLOAT_FOR_GCC /* __fix?fdi provided by libgcc2.c */
+long long float64_to_int64( float64 );
+long long float64_to_int64_round_to_zero( float64 );
+#endif
+float32 float64_to_float32( float64 );
+#ifdef FLOATX80
+floatx80 float64_to_floatx80( float64 );
+#endif
+#ifdef FLOAT128
+float128 float64_to_float128( float64 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE double-precision operations.
+-------------------------------------------------------------------------------
+*/
+float64 float64_round_to_int( float64 );
+float64 float64_add( float64, float64 );
+float64 float64_sub( float64, float64 );
+float64 float64_mul( float64, float64 );
+float64 float64_div( float64, float64 );
+float64 float64_rem( float64, float64 );
+float64 float64_sqrt( float64 );
+int float64_eq( float64, float64 );
+int float64_le( float64, float64 );
+int float64_lt( float64, float64 );
+int float64_eq_signaling( float64, float64 );
+int float64_le_quiet( float64, float64 );
+int float64_lt_quiet( float64, float64 );
+#ifndef SOFTFLOAT_FOR_GCC
+int float64_is_signaling_nan( float64 );
+#endif
+
+#ifdef FLOATX80
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE extended double-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+int floatx80_to_int32( floatx80 );
+int floatx80_to_int32_round_to_zero( floatx80 );
+long long floatx80_to_int64( floatx80 );
+long long floatx80_to_int64_round_to_zero( floatx80 );
+float32 floatx80_to_float32( floatx80 );
+float64 floatx80_to_float64( floatx80 );
+#ifdef FLOAT128
+float128 floatx80_to_float128( floatx80 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE extended double-precision rounding precision. Valid
+values are 32, 64, and 80.
+-------------------------------------------------------------------------------
+*/
+extern int floatx80_rounding_precision;
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE extended double-precision operations.
+-------------------------------------------------------------------------------
+*/
+floatx80 floatx80_round_to_int( floatx80 );
+floatx80 floatx80_add( floatx80, floatx80 );
+floatx80 floatx80_sub( floatx80, floatx80 );
+floatx80 floatx80_mul( floatx80, floatx80 );
+floatx80 floatx80_div( floatx80, floatx80 );
+floatx80 floatx80_rem( floatx80, floatx80 );
+floatx80 floatx80_sqrt( floatx80 );
+int floatx80_eq( floatx80, floatx80 );
+int floatx80_le( floatx80, floatx80 );
+int floatx80_lt( floatx80, floatx80 );
+int floatx80_eq_signaling( floatx80, floatx80 );
+int floatx80_le_quiet( floatx80, floatx80 );
+int floatx80_lt_quiet( floatx80, floatx80 );
+int floatx80_is_signaling_nan( floatx80 );
+
+#endif
+
+#ifdef FLOAT128
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE quadruple-precision conversion routines.
+-------------------------------------------------------------------------------
+*/
+int float128_to_int32( float128 );
+int float128_to_int32_round_to_zero( float128 );
+long long float128_to_int64( float128 );
+long long float128_to_int64_round_to_zero( float128 );
+float32 float128_to_float32( float128 );
+float64 float128_to_float64( float128 );
+#ifdef FLOATX80
+floatx80 float128_to_floatx80( float128 );
+#endif
+
+/*
+-------------------------------------------------------------------------------
+Software IEC/IEEE quadruple-precision operations.
+-------------------------------------------------------------------------------
+*/
+float128 float128_round_to_int( float128 );
+float128 float128_add( float128, float128 );
+float128 float128_sub( float128, float128 );
+float128 float128_mul( float128, float128 );
+float128 float128_div( float128, float128 );
+float128 float128_rem( float128, float128 );
+float128 float128_sqrt( float128 );
+int float128_eq( float128, float128 );
+int float128_le( float128, float128 );
+int float128_lt( float128, float128 );
+int float128_eq_signaling( float128, float128 );
+int float128_le_quiet( float128, float128 );
+int float128_lt_quiet( float128, float128 );
+int float128_is_signaling_nan( float128 );
+
+#endif
+
diff --git a/lib/libc/softfloat/Makefile.inc b/lib/libc/softfloat/Makefile.inc
index f15e4d2a5a41..fa0ee9d2977f 100644
--- a/lib/libc/softfloat/Makefile.inc
+++ b/lib/libc/softfloat/Makefile.inc
@@ -12,8 +12,11 @@ CFLAGS+= -DSOFTFLOAT_FOR_GCC
SRCS+= softfloat.c
+# Deprecated FPU control interface
+.if ${LIBC_ARCH} != "riscv"
SRCS+= fpgetround.c fpsetround.c fpgetmask.c fpsetmask.c \
fpgetsticky.c
+.endif
SRCS+= eqsf2.c nesf2.c gtsf2.c gesf2.c ltsf2.c lesf2.c negsf2.c \
eqdf2.c nedf2.c gtdf2.c gedf2.c ltdf2.c ledf2.c negdf2.c \
diff --git a/lib/libcompiler_rt/Makefile.inc b/lib/libcompiler_rt/Makefile.inc
index 27a5879dd24a..5913faab838b 100644
--- a/lib/libcompiler_rt/Makefile.inc
+++ b/lib/libcompiler_rt/Makefile.inc
@@ -125,7 +125,7 @@ SRCF+= umodti3
#
# 128-bit quad precision long double support,
-# only used on arm64 and riscv.
+# only used on some architectures.
#
.if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "riscv"
SRCF+= addtf3
@@ -146,8 +146,9 @@ SRCF+= trunctfdf2
SRCF+= trunctfsf2
.endif
-# These are already shipped by libc.a on arm and mips
-.if ${MACHINE_CPUARCH} != "arm" && ${MACHINE_CPUARCH} != "mips"
+# These are already shipped by libc.a on some architectures.
+.if ${MACHINE_CPUARCH} != "arm" && ${MACHINE_CPUARCH} != "mips" && \
+ ${MACHINE_CPUARCH} != "riscv"
SRCF+= adddf3
SRCF+= addsf3
SRCF+= divdf3
diff --git a/lib/msun/riscv/Makefile.inc b/lib/msun/riscv/Makefile.inc
index 97d3302b96da..cd624918bed1 100644
--- a/lib/msun/riscv/Makefile.inc
+++ b/lib/msun/riscv/Makefile.inc
@@ -1,3 +1,8 @@
# $FreeBSD$
+.if ${MACHINE_ARCH:Mriscv*sf} != ""
+CFLAGS+=-DSOFTFLOAT
+.endif
+
LDBL_PREC = 113
+SYM_MAPS += ${.CURDIR}/riscv/Symbol.map
diff --git a/lib/msun/riscv/Symbol.map b/lib/msun/riscv/Symbol.map
new file mode 100644
index 000000000000..081294cf5562
--- /dev/null
+++ b/lib/msun/riscv/Symbol.map
@@ -0,0 +1,21 @@
+/*
+ * $FreeBSD$
+ */
+FBSD_1.0 {
+};
+
+FBSD_1.3 {
+ feclearexcept;
+ fegetexceptflag;
+ fesetexceptflag;
+ feraiseexcept;
+ fetestexcept;
+ fegetround;
+ fesetround;
+ fegetenv;
+ feholdexcept;
+ feupdateenv;
+ feenableexcept;
+ fedisableexcept;
+ fegetexcept;
+};
diff --git a/lib/msun/riscv/fenv.c b/lib/msun/riscv/fenv.c
index a5a5c03d3a74..9bc0d7e35740 100644
--- a/lib/msun/riscv/fenv.c
+++ b/lib/msun/riscv/fenv.c
@@ -39,6 +39,14 @@
*/
const fenv_t __fe_dfl_env = 0;
+#ifdef SOFTFLOAT
+#define __set_env(env, flags, mask, rnd) env = ((flags) | (rnd) << 5)
+#define __env_flags(env) ((env) & FE_ALL_EXCEPT)
+#define __env_mask(env) (0) /* No exception traps. */
+#define __env_round(env) (((env) >> 5) & _ROUND_MASK)
+#include "fenv-softfloat.h"
+#endif
+
extern inline int feclearexcept(int __excepts);
extern inline int fegetexceptflag(fexcept_t *__flagp, int __excepts);
extern inline int fesetexceptflag(const fexcept_t *__flagp, int __excepts);
@@ -50,3 +58,6 @@ extern inline int fegetenv(fenv_t *__envp);
extern inline int feholdexcept(fenv_t *__envp);
extern inline int fesetenv(const fenv_t *__envp);
extern inline int feupdateenv(const fenv_t *__envp);
+extern inline int feenableexcept(int __mask);
+extern inline int fedisableexcept(int __mask);
+extern inline int fegetexcept(void);
diff --git a/lib/msun/riscv/fenv.h b/lib/msun/riscv/fenv.h
index 3eae6c2ed164..e66aa1c57753 100644
--- a/lib/msun/riscv/fenv.h
+++ b/lib/msun/riscv/fenv.h
@@ -1,6 +1,6 @@
/*-
* Copyright (c) 2004-2005 David Schultz
- * Copyright (c) 2015 Ruslan Bukin
+ * Copyright (c) 2015-2016 Ruslan Bukin
* All rights reserved.
*
* Portions of this software were developed by SRI International and the
@@ -59,11 +59,11 @@ typedef __uint64_t fexcept_t;
/*
* RISC-V Rounding modes
*/
-#define FE_TONEAREST (0x00 << 5)
-#define FE_TOWARDZERO (0x01 << 5)
-#define FE_DOWNWARD (0x02 << 5)
-#define FE_UPWARD (0x03 << 5)
#define _ROUND_SHIFT 5
+#define FE_TONEAREST (0x00 << _ROUND_SHIFT)
+#define FE_TOWARDZERO (0x01 << _ROUND_SHIFT)
+#define FE_DOWNWARD (0x02 << _ROUND_SHIFT)
+#define FE_UPWARD (0x03 << _ROUND_SHIFT)
#define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \
FE_UPWARD | FE_TOWARDZERO)
@@ -73,96 +73,117 @@ __BEGIN_DECLS
extern const fenv_t __fe_dfl_env;
#define FE_DFL_ENV (&__fe_dfl_env)
-/* We need to be able to map status flag positions to mask flag positions */
-#define _FPUSW_SHIFT 0
-#define _ENABLE_MASK (FE_ALL_EXCEPT << _FPUSW_SHIFT)
-
-#define __rfs(__fpsr) __asm __volatile("csrr %0, fcsr" : "=r" (*(__fpsr)))
-#define __wfs(__fpsr) __asm __volatile("csrw fcsr, %0" :: "r" (__fpsr))
+#ifndef SOFTFLOAT
+#define __rfs(__fcsr) __asm __volatile("csrr %0, fcsr" : "=r" (__fcsr))
+#define __wfs(__fcsr) __asm __volatile("csrw fcsr, %0" :: "r" (__fcsr))
+#endif
+#ifdef SOFTFLOAT
+int feclearexcept(int __excepts);
+int fegetexceptflag(fexcept_t *__flagp, int __excepts);
+int fesetexceptflag(const fexcept_t *__flagp, int __excepts);
+int feraiseexcept(int __excepts);
+int fetestexcept(int __excepts);
+int fegetround(void);
+int fesetround(int __round);
+int fegetenv(fenv_t *__envp);
+int feholdexcept(fenv_t *__envp);
+int fesetenv(const fenv_t *__envp);
+int feupdateenv(const fenv_t *__envp);
+#else
__fenv_static inline int
feclearexcept(int __excepts)
{
- fexcept_t __fpsr;
- __rfs(&__fpsr);
- __fpsr &= ~__excepts;
- __wfs(__fpsr);
+ __asm __volatile("csrc fflags, %0" :: "r"(__excepts));
+
return (0);
}
__fenv_static inline int
fegetexceptflag(fexcept_t *__flagp, int __excepts)
{
- fexcept_t __fpsr;
+ fexcept_t __fcsr;
+
+ __rfs(__fcsr);
+ *__flagp = __fcsr & __excepts;
- __rfs(&__fpsr);
- *__flagp = __fpsr & __excepts;
return (0);
}
__fenv_static inline int
fesetexceptflag(const fexcept_t *__flagp, int __excepts)
{
- fexcept_t __fpsr;
+ fexcept_t __fcsr;
+
+ __fcsr = *__flagp;
+ __asm __volatile("csrc fflags, %0" :: "r"(__excepts));
+ __asm __volatile("csrs fflags, %0" :: "r"(__fcsr & __excepts));
- __rfs(&__fpsr);
- __fpsr &= ~__excepts;
- __fpsr |= *__flagp & __excepts;
- __wfs(__fpsr);
return (0);
}
__fenv_static inline int
feraiseexcept(int __excepts)
{
- fexcept_t __ex = __excepts;
- fesetexceptflag(&__ex, __excepts); /* XXX */
+ __asm __volatile("csrs fflags, %0" :: "r"(__excepts));
+
return (0);
}
__fenv_static inline int
fetestexcept(int __excepts)
{
- fexcept_t __fpsr;
+ fexcept_t __fcsr;
- __rfs(&__fpsr);
- return (__fpsr & __excepts);
+ __rfs(__fcsr);
+
+ return (__fcsr & __excepts);
}
__fenv_static inline int
fegetround(void)
{
+ fexcept_t __fcsr;
- return (-1);
+ __rfs(__fcsr);
+
+ return (__fcsr & _ROUND_MASK);
}
__fenv_static inline int
fesetround(int __round)
{
+ fexcept_t __fcsr;
- return (-1);
+ if (__round & ~_ROUND_MASK)
+ return (-1);
+
+ __rfs(__fcsr);
+ __fcsr &= ~_ROUND_MASK;
+ __fcsr |= __round;
+ __wfs(__fcsr);
+
+ return (0);
}
__fenv_static inline int
fegetenv(fenv_t *__envp)
{
- __rfs(__envp);
+ __rfs(*__envp);
+
return (0);
}
__fenv_static inline int
feholdexcept(fenv_t *__envp)
{
- fenv_t __env;
- __rfs(&__env);
- *__envp = __env;
- __env &= ~(FE_ALL_EXCEPT | _ENABLE_MASK);
- __wfs(__env);
- return (0);
+ /* No exception traps. */
+
+ return (-1);
}
__fenv_static inline int
@@ -170,56 +191,59 @@ fesetenv(const fenv_t *__envp)
{
__wfs(*__envp);
+
return (0);
}
__fenv_static inline int
feupdateenv(const fenv_t *__envp)
{
- fexcept_t __fpsr;
+ fexcept_t __fcsr;
- __rfs(&__fpsr);
+ __rfs(__fcsr);
__wfs(*__envp);
- feraiseexcept(__fpsr & FE_ALL_EXCEPT);
+ feraiseexcept(__fcsr & FE_ALL_EXCEPT);
+
return (0);
}
+#endif /* !SOFTFLOAT */
#if __BSD_VISIBLE
/* We currently provide no external definitions of the functions below. */
+#ifdef SOFTFLOAT
+int feenableexcept(int __mask);
+int fedisableexcept(int __mask);
+int fegetexcept(void);
+#else
static inline int
feenableexcept(int __mask)
{
- fenv_t __old_fpsr;
- fenv_t __new_fpsr;
- __rfs(&__old_fpsr);
- __new_fpsr = __old_fpsr | (__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT;
- __wfs(__new_fpsr);
- return ((__old_fpsr >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
+ /* No exception traps. */
+
+ return (-1);
}
static inline int
fedisableexcept(int __mask)
{
- fenv_t __old_fpsr;
- fenv_t __new_fpsr;
- __rfs(&__old_fpsr);
- __new_fpsr = __old_fpsr & ~((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
- __wfs(__new_fpsr);
- return ((__old_fpsr >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
+ /* No exception traps. */
+
+ return (0);
}
static inline int
fegetexcept(void)
{
- fenv_t __fpsr;
- __rfs(&__fpsr);
- return ((__fpsr & _ENABLE_MASK) >> _FPUSW_SHIFT);
+ /* No exception traps. */
+
+ return (0);
}
+#endif /* !SOFTFLOAT */
#endif /* __BSD_VISIBLE */
diff --git a/share/mk/bsd.cpu.mk b/share/mk/bsd.cpu.mk
index 874beed525ad..79c37664849f 100644
--- a/share/mk/bsd.cpu.mk
+++ b/share/mk/bsd.cpu.mk
@@ -155,8 +155,6 @@ _CPUCFLAGS = -march=${CPUTYPE}
# sb1, xlp, xlr
_CPUCFLAGS = -march=${CPUTYPE:S/^mips//}
. endif
-. elif ${MACHINE_CPUARCH} == "riscv"
-_CPUCFLAGS = -mno-float -march="IMAFD"
. elif ${MACHINE_ARCH} == "sparc64"
. if ${CPUTYPE} == "v9"
_CPUCFLAGS = -mcpu=v9
@@ -350,9 +348,11 @@ CFLAGS += -mcpu=8540 -Wa,-me500 -mspe=yes -mabi=spe -mfloat-gprs=double
.endif
.if ${MACHINE_CPUARCH} == "riscv"
+.if ${TARGET_ARCH:Mriscv*sf}
CFLAGS += -mno-float
ACFLAGS += -mno-float
.endif
+.endif
# NB: COPTFLAGS is handled in /usr/src/sys/conf/kern.pre.mk
diff --git a/share/mk/local.meta.sys.mk b/share/mk/local.meta.sys.mk
index 49f625ccefa9..3a4e8f1352bd 100644
--- a/share/mk/local.meta.sys.mk
+++ b/share/mk/local.meta.sys.mk
@@ -48,7 +48,7 @@ TARGET_ARCHES_arm64?= aarch64
TARGET_ARCHES_mips?= mipsel mips mips64el mips64 mipsn32 mipsn32el
TARGET_ARCHES_powerpc?= powerpc powerpc64 powerpcspe
TARGET_ARCHES_pc98?= i386
-TARGET_ARCHES_riscv?= riscv64
+TARGET_ARCHES_riscv?= riscv64 riscv64sf
# some corner cases
BOOT_MACHINE_DIR.amd64 = boot/i386
diff --git a/share/mk/src.opts.mk b/share/mk/src.opts.mk
index 89125d695130..64ffbe50ded8 100644
--- a/share/mk/src.opts.mk
+++ b/share/mk/src.opts.mk
@@ -236,16 +236,16 @@ __DEFAULT_YES_OPTIONS+=GCC GCC_BOOTSTRAP GNUCXX
__DEFAULT_NO_OPTIONS+=CLANG CLANG_BOOTSTRAP CLANG_FULL CLANG_IS_CC
.endif
# In-tree binutils/gcc are older versions without modern architecture support.
-.if ${__T} == "aarch64" || ${__T} == "riscv64"
+.if ${__T} == "aarch64" || ${__T:Mriscv*} != ""
BROKEN_OPTIONS+=BINUTILS BINUTILS_BOOTSTRAP GCC GCC_BOOTSTRAP GDB
.endif
-.if ${__T} == "riscv64"
+.if ${__T:Mriscv*} != ""
BROKEN_OPTIONS+=PROFILE # "sorry, unimplemented: profiler support for RISC-V"
BROKEN_OPTIONS+=TESTS # "undefined reference to `_Unwind_Resume'"
BROKEN_OPTIONS+=CXX # "libcxxrt.so: undefined reference to `_Unwind_Resume_or_Rethrow'"
.endif
.if ${__T} == "aarch64" || ${__T} == "amd64" || ${__T} == "i386" || \
- ${__T} == "riscv64"
+ ${__T:Mriscv*} != ""
__DEFAULT_YES_OPTIONS+=LLVM_LIBUNWIND
.else
__DEFAULT_NO_OPTIONS+=LLVM_LIBUNWIND
diff --git a/share/mk/sys.mk b/share/mk/sys.mk
index 2c3743342018..04c342c134f0 100644
--- a/share/mk/sys.mk
+++ b/share/mk/sys.mk
@@ -13,7 +13,7 @@ unix ?= We run FreeBSD, not UNIX.
# and/or endian. This is called MACHINE_CPU in NetBSD, but that's used
# for something different in FreeBSD.
#
-MACHINE_CPUARCH=${MACHINE_ARCH:C/mips(n32|64)?(el)?(hf)?/mips/:C/arm(v6)?(eb|hf)?/arm/:C/powerpc(64|spe)/powerpc/:C/riscv64/riscv/}
+MACHINE_CPUARCH=${MACHINE_ARCH:C/mips(n32|64)?(el)?(hf)?/mips/:C/arm(v6)?(eb|hf)?/arm/:C/powerpc(64|spe)/powerpc/:C/riscv64(sf)?/riscv/}
.endif
diff --git a/sys/conf/options.riscv b/sys/conf/options.riscv
index c263bd860875..af6a89e80f19 100644
--- a/sys/conf/options.riscv
+++ b/sys/conf/options.riscv
@@ -1,4 +1,4 @@
# $FreeBSD$
RISCV opt_global.h
-VFP opt_global.h
+FPE opt_global.h
diff --git a/sys/modules/dtrace/dtrace/Makefile b/sys/modules/dtrace/dtrace/Makefile
index 543be8c20191..0889646f88c0 100644
--- a/sys/modules/dtrace/dtrace/Makefile
+++ b/sys/modules/dtrace/dtrace/Makefile
@@ -60,7 +60,11 @@ assym.o: assym.s
.if ${MACHINE_CPUARCH} == "riscv"
assym.o: assym.s
+.if ${TARGET_ARCH:Mriscv*sf}
${AS} -mfloat-abi=soft -o assym.o assym.s
+.else
+ ${AS} -mfloat-abi=double -o assym.o assym.s
+.endif
.endif
.include
diff --git a/sys/riscv/conf/GENERIC b/sys/riscv/conf/GENERIC
index ad23c6647e73..a9c3c6fbdad0 100644
--- a/sys/riscv/conf/GENERIC
+++ b/sys/riscv/conf/GENERIC
@@ -69,7 +69,7 @@ options CAPABILITIES # Capsicum capabilities
options MAC # TrustedBSD MAC Framework
options KDTRACE_FRAME # Ensure frames are compiled in
options KDTRACE_HOOKS # Kernel DTrace hooks
-# options VFP # Floating-point support
+options FPE # Floating-point extension support
options RACCT # Resource accounting framework
options RACCT_DEFAULT_TO_DISABLED # Set kern.racct.enable=0 by default
options RCTL # Resource limits
diff --git a/sys/riscv/include/fpe.h b/sys/riscv/include/fpe.h
new file mode 100644
index 000000000000..1294ab0de8fa
--- /dev/null
+++ b/sys/riscv/include/fpe.h
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 2016 Ruslan Bukin
+ * All rights reserved.
+ *
+ * This software was developed by SRI International and the University of
+ * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
+ * ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_FPE_H_
+#define _MACHINE_FPE_H_
+
+void fpe_state_save(struct thread *td);
+
+#endif /* !_MACHINE_FPE_H_ */
diff --git a/sys/riscv/include/pcb.h b/sys/riscv/include/pcb.h
index a6cecb73434c..27737a4bdf24 100644
--- a/sys/riscv/include/pcb.h
+++ b/sys/riscv/include/pcb.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2015 Ruslan Bukin
+ * Copyright (c) 2015-2016 Ruslan Bukin
* All rights reserved.
*
* Portions of this software were developed by SRI International and the
@@ -42,16 +42,21 @@
struct trapframe;
struct pcb {
- uint64_t pcb_ra;
- uint64_t pcb_sp;
- uint64_t pcb_gp;
- uint64_t pcb_tp;
- uint64_t pcb_t[7];
- uint64_t pcb_s[12];
- uint64_t pcb_a[8];
- uint64_t pcb_sepc;
+ uint64_t pcb_ra; /* Return address */
+ uint64_t pcb_sp; /* Stack pointer */
+ uint64_t pcb_gp; /* Global pointer */
+ uint64_t pcb_tp; /* Thread pointer */
+ uint64_t pcb_t[7]; /* Temporary registers */
+ uint64_t pcb_s[12]; /* Saved registers */
+ uint64_t pcb_a[8]; /* Argument registers */
+ uint64_t pcb_x[32][2]; /* Floating point registers */
+ uint64_t pcb_fcsr; /* Floating point control reg */
+ uint64_t pcb_fpflags; /* Floating point flags */
+#define PCB_FP_STARTED 0x1
+#define PCB_FP_USERMASK 0x1
+ uint64_t pcb_sepc; /* Supervisor exception pc */
vm_offset_t pcb_l1addr; /* L1 page tables base address */
- vm_offset_t pcb_onfault;
+ vm_offset_t pcb_onfault; /* Copyinout fault handler */
};
#ifdef _KERNEL
diff --git a/sys/riscv/include/reg.h b/sys/riscv/include/reg.h
index 35d79f10a8f5..9e94b4a5768d 100644
--- a/sys/riscv/include/reg.h
+++ b/sys/riscv/include/reg.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2015 Ruslan Bukin
+ * Copyright (c) 2015-2016 Ruslan Bukin
* All rights reserved.
*
* Portions of this software were developed by SRI International and the
@@ -50,7 +50,8 @@ struct reg {
};
struct fpreg {
- int dummy;
+ uint64_t fp_x[32][2]; /* Floating point registers */
+ uint64_t fp_fcsr; /* Floating point control reg */
};
struct dbreg {
diff --git a/sys/riscv/include/riscvreg.h b/sys/riscv/include/riscvreg.h
index 2e3a4a2e9f5d..77f35bfa64b0 100644
--- a/sys/riscv/include/riscvreg.h
+++ b/sys/riscv/include/riscvreg.h
@@ -60,10 +60,14 @@
#define SSTATUS_SPIE_SHIFT 5
#define SSTATUS_SPP (1 << 8)
#define SSTATUS_SPP_SHIFT 8
-#define SSTATUS_FS_MASK 0x3
#define SSTATUS_FS_SHIFT 13
-#define SSTATUS_XS_MASK 0x3
+#define SSTATUS_FS_OFF (0x0 << SSTATUS_FS_SHIFT)
+#define SSTATUS_FS_INITIAL (0x1 << SSTATUS_FS_SHIFT)
+#define SSTATUS_FS_CLEAN (0x2 << SSTATUS_FS_SHIFT)
+#define SSTATUS_FS_DIRTY (0x3 << SSTATUS_FS_SHIFT)
+#define SSTATUS_FS_MASK (0x3 << SSTATUS_FS_SHIFT)
#define SSTATUS_XS_SHIFT 15
+#define SSTATUS_XS_MASK (0x3 << SSTATUS_XS_SHIFT)
#define SSTATUS_PUM (1 << 18)
#define SSTATUS32_SD (1 << 63)
#define SSTATUS64_SD (1 << 31)
diff --git a/sys/riscv/riscv/genassym.c b/sys/riscv/riscv/genassym.c
index c9e9bc1c991a..33f1d41750a7 100644
--- a/sys/riscv/riscv/genassym.c
+++ b/sys/riscv/riscv/genassym.c
@@ -72,6 +72,8 @@ ASSYM(PCB_TP, offsetof(struct pcb, pcb_tp));
ASSYM(PCB_T, offsetof(struct pcb, pcb_t));
ASSYM(PCB_S, offsetof(struct pcb, pcb_s));
ASSYM(PCB_A, offsetof(struct pcb, pcb_a));
+ASSYM(PCB_X, offsetof(struct pcb, pcb_x));
+ASSYM(PCB_FCSR, offsetof(struct pcb, pcb_fcsr));
ASSYM(SF_UC, offsetof(struct sigframe, sf_uc));
diff --git a/sys/riscv/riscv/machdep.c b/sys/riscv/riscv/machdep.c
index 7bc4402597de..f08527a7f2f3 100644
--- a/sys/riscv/riscv/machdep.c
+++ b/sys/riscv/riscv/machdep.c
@@ -84,8 +84,8 @@ __FBSDID("$FreeBSD$");
#include
-#ifdef VFP
-#include
+#ifdef FPE
+#include
#endif
#ifdef FDT
@@ -203,17 +203,39 @@ set_regs(struct thread *td, struct reg *regs)
int
fill_fpregs(struct thread *td, struct fpreg *regs)
{
+#ifdef FPE
+ struct pcb *pcb;
+
+ pcb = td->td_pcb;
+
+ if ((pcb->pcb_fpflags & PCB_FP_STARTED) != 0) {
+ /*
+ * If we have just been running FPE instructions we will
+ * need to save the state to memcpy it below.
+ */
+ fpe_state_save(td);
+
+ memcpy(regs->fp_x, pcb->pcb_x, sizeof(regs->fp_x));
+ regs->fp_fcsr = pcb->pcb_fcsr;
+ } else
+#endif
+ memset(regs->fp_x, 0, sizeof(regs->fp_x));
- /* TODO */
- bzero(regs, sizeof(*regs));
return (0);
}
int
set_fpregs(struct thread *td, struct fpreg *regs)
{
+#ifdef FPE
+ struct pcb *pcb;
+
+ pcb = td->td_pcb;
+
+ memcpy(pcb->pcb_x, regs->fp_x, sizeof(regs->fp_x));
+ pcb->pcb_fcsr = regs->fp_fcsr;
+#endif
- /* TODO */
return (0);
}
@@ -259,8 +281,10 @@ void
exec_setregs(struct thread *td, struct image_params *imgp, u_long stack)
{
struct trapframe *tf;
+ struct pcb *pcb;
tf = td->td_frame;
+ pcb = td->td_pcb;
memset(tf, 0, sizeof(struct trapframe));
@@ -273,6 +297,8 @@ exec_setregs(struct thread *td, struct image_params *imgp, u_long stack)
tf->tf_sp = STACKALIGN(stack);
tf->tf_ra = imgp->entry_addr;
tf->tf_sepc = imgp->entry_addr;
+
+ pcb->pcb_fpflags &= ~PCB_FP_STARTED;
}
/* Sanity check these are the same size, they will be memcpy'd to and fro */
@@ -337,13 +363,54 @@ set_mcontext(struct thread *td, mcontext_t *mcp)
static void
get_fpcontext(struct thread *td, mcontext_t *mcp)
{
- /* TODO */
+#ifdef FPE
+ struct pcb *curpcb;
+
+ critical_enter();
+
+ curpcb = curthread->td_pcb;
+
+ KASSERT(td->td_pcb == curpcb, ("Invalid fpe pcb"));
+
+ if ((curpcb->pcb_fpflags & PCB_FP_STARTED) != 0) {
+ /*
+ * If we have just been running FPE instructions we will
+ * need to save the state to memcpy it below.
+ */
+ fpe_state_save(td);
+
+ KASSERT((curpcb->pcb_fpflags & ~PCB_FP_USERMASK) == 0,
+ ("Non-userspace FPE flags set in get_fpcontext"));
+ memcpy(mcp->mc_fpregs.fp_x, curpcb->pcb_x,
+ sizeof(mcp->mc_fpregs));
+ mcp->mc_fpregs.fp_fcsr = curpcb->pcb_fcsr;
+ mcp->mc_fpregs.fp_flags = curpcb->pcb_fpflags;
+ mcp->mc_flags |= _MC_FP_VALID;
+ }
+
+ critical_exit();
+#endif
}
static void
set_fpcontext(struct thread *td, mcontext_t *mcp)
{
- /* TODO */
+#ifdef FPE
+ struct pcb *curpcb;
+
+ critical_enter();
+
+ if ((mcp->mc_flags & _MC_FP_VALID) != 0) {
+ curpcb = curthread->td_pcb;
+ /* FPE usage is enabled, override registers. */
+ memcpy(curpcb->pcb_x, mcp->mc_fpregs.fp_x,
+ sizeof(mcp->mc_fpregs));
+ curpcb->pcb_fcsr = mcp->mc_fpregs.fp_fcsr;
+ curpcb->pcb_fpflags = mcp->mc_fpregs.fp_flags & PCB_FP_USERMASK;
+ }
+
+ critical_exit();
+#endif
}
void
@@ -572,6 +639,7 @@ init_proc0(vm_offset_t kstack)
proc_linkup0(&proc0, &thread0);
thread0.td_kstack = kstack;
thread0.td_pcb = (struct pcb *)(thread0.td_kstack) - 1;
+ thread0.td_pcb->pcb_fpflags = 0;
thread0.td_frame = &proc0_tf;
pcpup->pc_curpcb = thread0.td_pcb;
}
diff --git a/sys/riscv/riscv/mp_machdep.c b/sys/riscv/riscv/mp_machdep.c
index 33353ac2a3c8..adad7b4b533b 100644
--- a/sys/riscv/riscv/mp_machdep.c
+++ b/sys/riscv/riscv/mp_machdep.c
@@ -62,9 +62,6 @@ __FBSDID("$FreeBSD$");
#include
#include
#include
-#ifdef VFP
-#include
-#endif
#ifdef FDT
#include
@@ -242,10 +239,6 @@ init_secondary(uint64_t cpu)
/* Start per-CPU event timers. */
cpu_initclocks_ap();
-#ifdef VFP
- /* TODO: init FPU */
-#endif
-
/* Enable interrupts */
intr_enable();
diff --git a/sys/riscv/riscv/swtch.S b/sys/riscv/riscv/swtch.S
index b5cced30d8f7..5cc1edd69a02 100644
--- a/sys/riscv/riscv/swtch.S
+++ b/sys/riscv/riscv/swtch.S
@@ -42,6 +42,117 @@
__FBSDID("$FreeBSD$");
+#ifdef FPE
+.macro __fpe_state_save p
+ /*
+ * Enable FPE usage in supervisor mode,
+ * so we can access registers.
+ */
+ li t0, SSTATUS_FS_INITIAL
+ csrs sstatus, t0
+
+ /* Store registers */
+ frcsr t0
+ sd t0, (PCB_FCSR)(\p)
+ fsd f0, (PCB_X + 0 * 16)(\p)
+ fsd f1, (PCB_X + 1 * 16)(\p)
+ fsd f2, (PCB_X + 2 * 16)(\p)
+ fsd f3, (PCB_X + 3 * 16)(\p)
+ fsd f4, (PCB_X + 4 * 16)(\p)
+ fsd f5, (PCB_X + 5 * 16)(\p)
+ fsd f6, (PCB_X + 6 * 16)(\p)
+ fsd f7, (PCB_X + 7 * 16)(\p)
+ fsd f8, (PCB_X + 8 * 16)(\p)
+ fsd f9, (PCB_X + 9 * 16)(\p)
+ fsd f10, (PCB_X + 10 * 16)(\p)
+ fsd f11, (PCB_X + 11 * 16)(\p)
+ fsd f12, (PCB_X + 12 * 16)(\p)
+ fsd f13, (PCB_X + 13 * 16)(\p)
+ fsd f14, (PCB_X + 14 * 16)(\p)
+ fsd f15, (PCB_X + 15 * 16)(\p)
+ fsd f16, (PCB_X + 16 * 16)(\p)
+ fsd f17, (PCB_X + 17 * 16)(\p)
+ fsd f18, (PCB_X + 18 * 16)(\p)
+ fsd f19, (PCB_X + 19 * 16)(\p)
+ fsd f20, (PCB_X + 20 * 16)(\p)
+ fsd f21, (PCB_X + 21 * 16)(\p)
+ fsd f22, (PCB_X + 22 * 16)(\p)
+ fsd f23, (PCB_X + 23 * 16)(\p)
+ fsd f24, (PCB_X + 24 * 16)(\p)
+ fsd f25, (PCB_X + 25 * 16)(\p)
+ fsd f26, (PCB_X + 26 * 16)(\p)
+ fsd f27, (PCB_X + 27 * 16)(\p)
+ fsd f28, (PCB_X + 28 * 16)(\p)
+ fsd f29, (PCB_X + 29 * 16)(\p)
+ fsd f30, (PCB_X + 30 * 16)(\p)
+ fsd f31, (PCB_X + 31 * 16)(\p)
+
+ /* Disable FPE usage in supervisor mode. */
+ li t0, SSTATUS_FS_MASK
+ csrc sstatus, t0
+.endm
+
+.macro __fpe_state_load p
+ /*
+ * Enable FPE usage in supervisor mode,
+ * so we can access registers.
+ */
+ li t0, SSTATUS_FS_INITIAL
+ csrs sstatus, t0
+
+ /* Restore registers */
+ ld t0, (PCB_FCSR)(\p)
+ fscsr t0
+ fld f0, (PCB_X + 0 * 16)(\p)
+ fld f1, (PCB_X + 1 * 16)(\p)
+ fld f2, (PCB_X + 2 * 16)(\p)
+ fld f3, (PCB_X + 3 * 16)(\p)
+ fld f4, (PCB_X + 4 * 16)(\p)
+ fld f5, (PCB_X + 5 * 16)(\p)
+ fld f6, (PCB_X + 6 * 16)(\p)
+ fld f7, (PCB_X + 7 * 16)(\p)
+ fld f8, (PCB_X + 8 * 16)(\p)
+ fld f9, (PCB_X + 9 * 16)(\p)
+ fld f10, (PCB_X + 10 * 16)(\p)
+ fld f11, (PCB_X + 11 * 16)(\p)
+ fld f12, (PCB_X + 12 * 16)(\p)
+ fld f13, (PCB_X + 13 * 16)(\p)
+ fld f14, (PCB_X + 14 * 16)(\p)
+ fld f15, (PCB_X + 15 * 16)(\p)
+ fld f16, (PCB_X + 16 * 16)(\p)
+ fld f17, (PCB_X + 17 * 16)(\p)
+ fld f18, (PCB_X + 18 * 16)(\p)
+ fld f19, (PCB_X + 19 * 16)(\p)
+ fld f20, (PCB_X + 20 * 16)(\p)
+ fld f21, (PCB_X + 21 * 16)(\p)
+ fld f22, (PCB_X + 22 * 16)(\p)
+ fld f23, (PCB_X + 23 * 16)(\p)
+ fld f24, (PCB_X + 24 * 16)(\p)
+ fld f25, (PCB_X + 25 * 16)(\p)
+ fld f26, (PCB_X + 26 * 16)(\p)
+ fld f27, (PCB_X + 27 * 16)(\p)
+ fld f28, (PCB_X + 28 * 16)(\p)
+ fld f29, (PCB_X + 29 * 16)(\p)
+ fld f30, (PCB_X + 30 * 16)(\p)
+ fld f31, (PCB_X + 31 * 16)(\p)
+
+ /* Disable FPE usage in supervisor mode. */
+ li t0, SSTATUS_FS_MASK
+ csrc sstatus, t0
+.endm
+
+/*
+ * void
+ * fpe_state_save(struct thread *td)
+ */
+ENTRY(fpe_state_save)
+ /* Get pointer to PCB */
+ ld a0, TD_PCB(a0)
+ __fpe_state_save a0
+ ret
+END(fpe_state_save)
+#endif /* FPE */
+
/*
* void cpu_throw(struct thread *old, struct thread *new)
*/
@@ -81,8 +192,20 @@ ENTRY(cpu_throw)
ld s10, (PCB_S + 10 * 8)(x13)
ld s11, (PCB_S + 11 * 8)(x13)
- ret
+#ifdef FPE
+ /* Is FPE enabled for new thread? */
+ ld t0, TD_FRAME(a1)
+ ld t1, (TF_SSTATUS)(t0)
+ li t2, SSTATUS_FS_MASK
+ and t3, t1, t2
+ beqz t3, 1f /* No, skip. */
+ /* Restore registers. */
+ __fpe_state_load x13
+1:
+#endif
+
+ ret
.Lcpu_throw_panic_str:
.asciz "cpu_throw: %p\0"
END(cpu_throw)
@@ -123,6 +246,29 @@ ENTRY(cpu_switch)
sd s10, (PCB_S + 10 * 8)(x13)
sd s11, (PCB_S + 11 * 8)(x13)
+#ifdef FPE
+ /*
+ * Is FPE enabled and is it in dirty state
+ * for the old thread?
+ */
+ ld t0, TD_FRAME(a0)
+ ld t1, (TF_SSTATUS)(t0)
+ li t2, SSTATUS_FS_MASK
+ and t3, t1, t2
+ li t2, SSTATUS_FS_DIRTY
+ bne t3, t2, 1f /* No, skip. */
+
+ /* Yes, mark FPE state clean and save registers. */
+ li t2, ~SSTATUS_FS_MASK
+ and t3, t1, t2
+ li t2, SSTATUS_FS_CLEAN
+ or t3, t3, t2
+ sd t3, (TF_SSTATUS)(t0)
+
+ __fpe_state_save x13
+1:
+#endif
+
/*
* Restore the saved context.
*/
@@ -171,6 +317,20 @@ ENTRY(cpu_switch)
ld s9, (PCB_S + 9 * 8)(x13)
ld s10, (PCB_S + 10 * 8)(x13)
ld s11, (PCB_S + 11 * 8)(x13)
+
+#ifdef FPE
+ /* Is FPE enabled for new thread? */
+ ld t0, TD_FRAME(a1)
+ ld t1, (TF_SSTATUS)(t0)
+ li t2, SSTATUS_FS_MASK
+ and t3, t1, t2
+ beqz t3, 1f /* No, skip. */
+
+ /* Restore registers. */
+ __fpe_state_load x13
+1:
+#endif
+
ret
.Lcpu_switch_panic_str:
.asciz "cpu_switch: %p\0"
@@ -269,9 +429,8 @@ ENTRY(savectx)
sd s10, (PCB_S + 10 * 8)(a0)
sd s11, (PCB_S + 11 * 8)(a0)
- /* Store the VFP registers */
-#ifdef VFP
- /* TODO */
+#ifdef FPE
+ __fpe_state_save a0
#endif
ret
END(savectx)
diff --git a/sys/riscv/riscv/trap.c b/sys/riscv/riscv/trap.c
index 97d9a2c1efdd..cd2b7c4bfb74 100644
--- a/sys/riscv/riscv/trap.c
+++ b/sys/riscv/riscv/trap.c
@@ -328,9 +328,11 @@ do_trap_user(struct trapframe *frame)
uint64_t exception;
struct thread *td;
uint64_t sstatus;
+ struct pcb *pcb;
td = curthread;
td->td_frame = frame;
+ pcb = td->td_pcb;
/* Ensure we came from usermode, interrupts disabled */
__asm __volatile("csrr %0, sstatus" : "=&r" (sstatus));
@@ -358,6 +360,17 @@ do_trap_user(struct trapframe *frame)
svc_handler(frame);
break;
case EXCP_ILLEGAL_INSTRUCTION:
+#ifdef FPE
+ if ((pcb->pcb_fpflags & PCB_FP_STARTED) == 0) {
+ /*
+ * May be a FPE trap. Enable FPE usage
+ * for this thread and try again.
+ */
+ frame->tf_sstatus |= SSTATUS_FS_INITIAL;
+ pcb->pcb_fpflags |= PCB_FP_STARTED;
+ break;
+ }
+#endif
call_trapsignal(td, SIGILL, ILL_ILLTRP, (void *)frame->tf_sepc);
userret(td, frame);
break;
diff --git a/sys/riscv/riscv/vm_machdep.c b/sys/riscv/riscv/vm_machdep.c
index d2d4c6e3d3ec..c5c62fe24db2 100644
--- a/sys/riscv/riscv/vm_machdep.c
+++ b/sys/riscv/riscv/vm_machdep.c
@@ -87,8 +87,8 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags)
/* Arguments for child */
tf->tf_a[0] = 0;
tf->tf_a[1] = 0;
- tf->tf_sstatus = (SSTATUS_SPIE);
- tf->tf_sstatus |= (MSTATUS_PRV_U << MSTATUS_SPP_SHIFT);
+ tf->tf_sstatus |= (SSTATUS_SPIE); /* Enable interrupts. */
+ tf->tf_sstatus &= ~(SSTATUS_SPP); /* User mode. */
td2->td_frame = tf;