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;