You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2021/03/11 02:34:57 UTC

[incubator-nuttx] branch master updated: arch:rv64:c906:enable DP FPU support.

This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new d898bc4  arch:rv64:c906:enable DP FPU support.
d898bc4 is described below

commit d898bc445c0e181d0ce763ceb0cec169b8fde143
Author: hotislandn <ho...@hotmail.com>
AuthorDate: Wed Mar 10 23:31:29 2021 +0800

    arch:rv64:c906:enable DP FPU support.
    
    Signed-off-by: hotislandn <ho...@hotmail.com>
---
 arch/risc-v/include/rv64gc/irq.h                   | 173 ++++++++++++---
 arch/risc-v/include/rv64gc/syscall.h               |  13 +-
 arch/risc-v/src/c906/Kconfig                       |   8 +
 arch/risc-v/src/c906/Make.defs                     |   4 +
 arch/risc-v/src/c906/c906_irq.c                    |   4 +
 arch/risc-v/src/common/riscv_internal.h            |   5 +
 arch/risc-v/src/rv64gc/riscv_copystate.c           |  17 +-
 arch/risc-v/src/rv64gc/riscv_fpu.S                 | 236 +++++++++++++++++++++
 .../risc-v/c906/smartl-c906/configs/fpu/defconfig  |  62 ++++++
 boards/risc-v/c906/smartl-c906/scripts/Make.defs   |   7 +-
 boards/risc-v/c906/smartl-c906/src/Makefile        |   4 +
 boards/risc-v/c906/smartl-c906/src/c906_ostest.c   |  92 ++++++++
 12 files changed, 591 insertions(+), 34 deletions(-)

diff --git a/arch/risc-v/include/rv64gc/irq.h b/arch/risc-v/include/rv64gc/irq.h
index 0e1aebb..c9e51ed 100644
--- a/arch/risc-v/include/rv64gc/irq.h
+++ b/arch/risc-v/include/rv64gc/irq.h
@@ -1,37 +1,20 @@
 /****************************************************************************
  * arch/risc-v/include/rv64gc/irq.h
  *
- *   Copyright (C) 2011, 2013, 2015 Gregory Nutt. All rights reserved.
- *   Author: Gregory Nutt <gn...@nuttx.org>
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
  *
- *   Modified for RISC-V:
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- *   Copyright (C) 2016 Ken Pettit. All rights reserved.
- *   Author: Ken Pettit <pe...@gmail.com>
- *
- * 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 COPYRIGHT HOLDERS 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
- * COPYRIGHT OWNER 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.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
  *
  ****************************************************************************/
 
@@ -132,9 +115,63 @@
 
 #define REG_INT_CTX_NDX     32
 
-#define XCPTCONTEXT_REGS    33
+#define INT_XCPT_REGS       33
+
+#define INT_XCPT_SIZE       (8 * INT_XCPT_REGS)
+
+/* FPU REG size in uint64_t */
+
+#ifdef CONFIG_ARCH_FPU
+#if defined(CONFIG_ARCH_DPFPU)
+#  define FPU_REG_SIZE      1
+#elif defined(CONFIG_ARCH_QPFPU)
+#  define FPU_REG_SIZE      2
+#else
+#  error not supported !!!
+#endif
 
-#define XCPTCONTEXT_SIZE    (8*XCPTCONTEXT_REGS)
+#  define REG_F0_NDX        (INT_XCPT_REGS + FPU_REG_SIZE * 0)
+#  define REG_F1_NDX        (INT_XCPT_REGS + FPU_REG_SIZE * 1)
+#  define REG_F2_NDX        (INT_XCPT_REGS + FPU_REG_SIZE * 2)
+#  define REG_F3_NDX        (INT_XCPT_REGS + FPU_REG_SIZE * 3)
+#  define REG_F4_NDX        (INT_XCPT_REGS + FPU_REG_SIZE * 4)
+#  define REG_F5_NDX        (INT_XCPT_REGS + FPU_REG_SIZE * 5)
+#  define REG_F6_NDX        (INT_XCPT_REGS + FPU_REG_SIZE * 6)
+#  define REG_F7_NDX        (INT_XCPT_REGS + FPU_REG_SIZE * 7)
+#  define REG_F8_NDX        (INT_XCPT_REGS + FPU_REG_SIZE * 8)
+#  define REG_F9_NDX        (INT_XCPT_REGS + FPU_REG_SIZE * 9)
+#  define REG_F10_NDX       (INT_XCPT_REGS + FPU_REG_SIZE * 10)
+#  define REG_F11_NDX       (INT_XCPT_REGS + FPU_REG_SIZE * 11)
+#  define REG_F12_NDX       (INT_XCPT_REGS + FPU_REG_SIZE * 12)
+#  define REG_F13_NDX       (INT_XCPT_REGS + FPU_REG_SIZE * 13)
+#  define REG_F14_NDX       (INT_XCPT_REGS + FPU_REG_SIZE * 14)
+#  define REG_F15_NDX       (INT_XCPT_REGS + FPU_REG_SIZE * 15)
+#  define REG_F16_NDX       (INT_XCPT_REGS + FPU_REG_SIZE * 16)
+#  define REG_F17_NDX       (INT_XCPT_REGS + FPU_REG_SIZE * 17)
+#  define REG_F18_NDX       (INT_XCPT_REGS + FPU_REG_SIZE * 18)
+#  define REG_F19_NDX       (INT_XCPT_REGS + FPU_REG_SIZE * 19)
+#  define REG_F20_NDX       (INT_XCPT_REGS + FPU_REG_SIZE * 20)
+#  define REG_F21_NDX       (INT_XCPT_REGS + FPU_REG_SIZE * 21)
+#  define REG_F22_NDX       (INT_XCPT_REGS + FPU_REG_SIZE * 22)
+#  define REG_F23_NDX       (INT_XCPT_REGS + FPU_REG_SIZE * 23)
+#  define REG_F24_NDX       (INT_XCPT_REGS + FPU_REG_SIZE * 24)
+#  define REG_F25_NDX       (INT_XCPT_REGS + FPU_REG_SIZE * 25)
+#  define REG_F26_NDX       (INT_XCPT_REGS + FPU_REG_SIZE * 26)
+#  define REG_F27_NDX       (INT_XCPT_REGS + FPU_REG_SIZE * 27)
+#  define REG_F28_NDX       (INT_XCPT_REGS + FPU_REG_SIZE * 28)
+#  define REG_F29_NDX       (INT_XCPT_REGS + FPU_REG_SIZE * 29)
+#  define REG_F30_NDX       (INT_XCPT_REGS + FPU_REG_SIZE * 30)
+#  define REG_F31_NDX       (INT_XCPT_REGS + FPU_REG_SIZE * 31)
+#  define REG_FCSR_NDX      (INT_XCPT_REGS + FPU_REG_SIZE * 32)
+
+#  define FPU_XCPT_REGS     (FPU_REG_SIZE * 33)
+#else /* !CONFIG_ARCH_FPU */
+#  define FPU_XCPT_REGS     0
+#endif /* CONFIG_ARCH_FPU */
+
+#define XCPTCONTEXT_REGS    (INT_XCPT_REGS + FPU_XCPT_REGS)
+
+#define XCPTCONTEXT_SIZE    (8 * XCPTCONTEXT_REGS)
 
 /* In assembly language, values have to be referenced as byte address
  * offsets.  But in C, it is more convenient to reference registers as
@@ -175,6 +212,43 @@
 #  define REG_X30           (8*REG_X30_NDX)
 #  define REG_X31           (8*REG_X31_NDX)
 #  define REG_INT_CTX       (8*REG_INT_CTX_NDX)
+
+#ifdef CONFIG_ARCH_FPU
+#  define REG_F0            (8*REG_F0_NDX)
+#  define REG_F1            (8*REG_F1_NDX)
+#  define REG_F2            (8*REG_F2_NDX)
+#  define REG_F3            (8*REG_F3_NDX)
+#  define REG_F4            (8*REG_F4_NDX)
+#  define REG_F5            (8*REG_F5_NDX)
+#  define REG_F6            (8*REG_F6_NDX)
+#  define REG_F7            (8*REG_F7_NDX)
+#  define REG_F8            (8*REG_F8_NDX)
+#  define REG_F9            (8*REG_F9_NDX)
+#  define REG_F10           (8*REG_F10_NDX)
+#  define REG_F11           (8*REG_F11_NDX)
+#  define REG_F12           (8*REG_F12_NDX)
+#  define REG_F13           (8*REG_F13_NDX)
+#  define REG_F14           (8*REG_F14_NDX)
+#  define REG_F15           (8*REG_F15_NDX)
+#  define REG_F16           (8*REG_F16_NDX)
+#  define REG_F17           (8*REG_F17_NDX)
+#  define REG_F18           (8*REG_F18_NDX)
+#  define REG_F19           (8*REG_F19_NDX)
+#  define REG_F20           (8*REG_F20_NDX)
+#  define REG_F21           (8*REG_F21_NDX)
+#  define REG_F22           (8*REG_F22_NDX)
+#  define REG_F23           (8*REG_F23_NDX)
+#  define REG_F24           (8*REG_F24_NDX)
+#  define REG_F25           (8*REG_F25_NDX)
+#  define REG_F26           (8*REG_F26_NDX)
+#  define REG_F27           (8*REG_F27_NDX)
+#  define REG_F28           (8*REG_F28_NDX)
+#  define REG_F29           (8*REG_F29_NDX)
+#  define REG_F30           (8*REG_F30_NDX)
+#  define REG_F31           (8*REG_F31_NDX)
+#  define REG_FCSR          (8*REG_FCSR_NDX)
+#endif
+
 #else
 #  define REG_EPC           REG_EPC_NDX
 #  define REG_X1            REG_X1_NDX
@@ -209,6 +283,43 @@
 #  define REG_X30           REG_X30_NDX
 #  define REG_X31           REG_X31_NDX
 #  define REG_INT_CTX       REG_INT_CTX_NDX
+
+#ifdef CONFIG_ARCH_FPU
+#  define REG_F0            REG_F0_NDX
+#  define REG_F1            REG_F1_NDX
+#  define REG_F2            REG_F2_NDX
+#  define REG_F3            REG_F3_NDX
+#  define REG_F4            REG_F4_NDX
+#  define REG_F5            REG_F5_NDX
+#  define REG_F6            REG_F6_NDX
+#  define REG_F7            REG_F7_NDX
+#  define REG_F8            REG_F8_NDX
+#  define REG_F9            REG_F9_NDX
+#  define REG_F10           REG_F10_NDX
+#  define REG_F11           REG_F11_NDX
+#  define REG_F12           REG_F12_NDX
+#  define REG_F13           REG_F13_NDX
+#  define REG_F14           REG_F14_NDX
+#  define REG_F15           REG_F15_NDX
+#  define REG_F16           REG_F16_NDX
+#  define REG_F17           REG_F17_NDX
+#  define REG_F18           REG_F18_NDX
+#  define REG_F19           REG_F19_NDX
+#  define REG_F20           REG_F20_NDX
+#  define REG_F21           REG_F21_NDX
+#  define REG_F22           REG_F22_NDX
+#  define REG_F23           REG_F23_NDX
+#  define REG_F24           REG_F24_NDX
+#  define REG_F25           REG_F25_NDX
+#  define REG_F26           REG_F26_NDX
+#  define REG_F27           REG_F27_NDX
+#  define REG_F28           REG_F28_NDX
+#  define REG_F29           REG_F29_NDX
+#  define REG_F30           REG_F30_NDX
+#  define REG_F31           REG_F31_NDX
+#  define REG_FCSR          REG_FCSR_NDX
+#endif
+
 #endif
 
 /* Now define more user friendly alternative name that can be used either
diff --git a/arch/risc-v/include/rv64gc/syscall.h b/arch/risc-v/include/rv64gc/syscall.h
index 93f8ea5..bc8c9ad 100644
--- a/arch/risc-v/include/rv64gc/syscall.h
+++ b/arch/risc-v/include/rv64gc/syscall.h
@@ -88,7 +88,18 @@
 
 /* Context switching system calls *******************************************/
 
-/* SYS call 0: (not used) */
+/* SYS call 0:
+ *
+ * int up_saveusercontext(uint64_t *saveregs);
+ *
+ * Return:
+ * 0: Normal Return
+ * 1: Context Switch Return
+ */
+
+#define SYS_save_context (0)
+#define up_saveusercontext(saveregs) \
+  (int)sys_call1(SYS_save_context, (uintptr_t)saveregs)
 
 /* SYS call 1:
  *
diff --git a/arch/risc-v/src/c906/Kconfig b/arch/risc-v/src/c906/Kconfig
index 412f809..edf77f6 100644
--- a/arch/risc-v/src/c906/Kconfig
+++ b/arch/risc-v/src/c906/Kconfig
@@ -5,6 +5,14 @@
 
 comment "C906 Configuration Options"
 
+config C906_ENABLE_DPFPU
+	bool "C906 DP_FPU Support"
+	default n
+	select ARCH_HAVE_FPU
+	select ARCH_HAVE_DPFPU
+	---help---
+		Enable the RISC-V Double-Precision Floating Point Unit (DP-FPU).
+
 menu "C906 Peripheral Support"
 
 # These "hidden" settings determine whether a peripheral option is available
diff --git a/arch/risc-v/src/c906/Make.defs b/arch/risc-v/src/c906/Make.defs
index 44b193d..5b4e69c 100644
--- a/arch/risc-v/src/c906/Make.defs
+++ b/arch/risc-v/src/c906/Make.defs
@@ -39,6 +39,10 @@ ifeq ($(CONFIG_STACK_COLORATION),y)
 CMN_CSRCS += riscv_checkstack.c
 endif
 
+ifeq ($(CONFIG_ARCH_FPU),y)
+CMN_ASRCS  += riscv_fpu.S
+endif
+
 ifeq ($(CONFIG_ARCH_HAVE_VFORK),y)
 CMN_CSRCS  += riscv_vfork.c
 endif
diff --git a/arch/risc-v/src/c906/c906_irq.c b/arch/risc-v/src/c906/c906_irq.c
index 57977eb..9d2449e 100644
--- a/arch/risc-v/src/c906/c906_irq.c
+++ b/arch/risc-v/src/c906/c906_irq.c
@@ -215,7 +215,11 @@ uint32_t up_get_newintctx(void)
    * user code. Also set machine previous interrupt enable.
    */
 
+#ifdef CONFIG_ARCH_FPU
   return (MSTATUS_FS_INIT | MSTATUS_MPPM | MSTATUS_MPIE);
+#else
+  return (MSTATUS_MPPM | MSTATUS_MPIE);
+#endif
 }
 
 /****************************************************************************
diff --git a/arch/risc-v/src/common/riscv_internal.h b/arch/risc-v/src/common/riscv_internal.h
index ed583cd..88b1ceb 100644
--- a/arch/risc-v/src/common/riscv_internal.h
+++ b/arch/risc-v/src/common/riscv_internal.h
@@ -197,8 +197,13 @@ int up_swint(int irq, FAR void *context, FAR void *arg);
 uint32_t up_get_newintctx(void);
 
 #ifdef CONFIG_ARCH_FPU
+#ifdef CONFIG_ARCH_RV64GC
+void up_savefpu(uint64_t *regs);
+void up_restorefpu(const uint64_t *regs);
+#else /* !CONFIG_ARCH_RV64GC */
 void up_savefpu(uint32_t *regs);
 void up_restorefpu(const uint32_t *regs);
+#endif /* CONFIG_ARCH_RV64GC */
 #else
 #  define up_savefpu(regs)
 #  define up_restorefpu(regs)
diff --git a/arch/risc-v/src/rv64gc/riscv_copystate.c b/arch/risc-v/src/rv64gc/riscv_copystate.c
index 37df1b8..3d60870 100644
--- a/arch/risc-v/src/rv64gc/riscv_copystate.c
+++ b/arch/risc-v/src/rv64gc/riscv_copystate.c
@@ -70,6 +70,10 @@ void up_copystate(uint64_t *dest, uint64_t *src)
 {
   int i;
 
+#ifdef CONFIG_ARCH_FPU
+  uint64_t *regs = dest;
+#endif
+
   /* In the RISC-V model, the state is copied from the stack to the TCB,
    * but only a reference is passed to get the state from the TCB.  So the
    * following check avoids copying the TCB save area onto itself:
@@ -77,9 +81,20 @@ void up_copystate(uint64_t *dest, uint64_t *src)
 
   if (src != dest)
     {
-      for (i = 0; i < XCPTCONTEXT_REGS; i++)
+      /* save integer registers first */
+
+      for (i = 0; i < INT_XCPT_REGS; i++)
         {
           *dest++ = *src++;
         }
+
+      /* Save the floating point registers: This will initialize the floating
+       * registers at indices INT_XCPT_REGS through (XCPTCONTEXT_REGS-1).
+       * Do this after saving REG_INT_CTX with the ORIGINAL context pointer.
+       */
+
+#ifdef CONFIG_ARCH_FPU
+      up_savefpu(regs);
+#endif
     }
 }
diff --git a/arch/risc-v/src/rv64gc/riscv_fpu.S b/arch/risc-v/src/rv64gc/riscv_fpu.S
new file mode 100644
index 0000000..07c0b74
--- /dev/null
+++ b/arch/risc-v/src/rv64gc/riscv_fpu.S
@@ -0,0 +1,236 @@
+/************************************************************************************
+ * arch/risc-v/src/rv64gc/riscv_fpu.S
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ************************************************************************************/
+
+/************************************************************************************
+ * Included Files
+ ************************************************************************************/
+
+#include <nuttx/config.h>
+#include <arch/rv64gc/irq.h>
+
+#ifdef CONFIG_ARCH_FPU
+
+/************************************************************************************
+ * Pre-processor Definitions
+ ************************************************************************************/
+
+/************************************************************************************
+ * Public Symbols
+ ************************************************************************************/
+
+    .globl        up_fpuconfig
+    .globl        up_savefpu
+    .globl        up_restorefpu
+
+    .file         "riscv_fpu.S"
+
+#define FS_MASK     0x6000
+#define FS_OFF      0x0000
+#define FS_INITIAL  0x2000
+#define FS_CLEAN    0x4000
+#define FS_DIRTY    0x6000
+
+#if defined(CONFIG_ARCH_DPFPU)
+#  define FLOAD     fld
+#  define FSTORE    fsd
+#elif defined(CONFIG_ARCH_QPFPU)
+#  define FLOAD     flq
+#  define FSTORE    fsq
+#else
+#  define FLOAD     flw
+#  define FSTORE    fsw
+#endif
+
+/************************************************************************************
+ * Public Functions
+ ************************************************************************************/
+
+/************************************************************************************
+ * Name: up_fpuconfig
+ *
+ * Description:
+ *   init fpu
+ *
+ * C Function Prototype:
+ *   void up_fpuconfig(void);
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   This function does not return anything explicitly.
+ *
+ ************************************************************************************/
+
+    .type        up_fpuconfig, function
+
+up_fpuconfig:
+    li           a0, FS_INITIAL
+    csrs         mstatus, a0
+    csrwi        fcsr, 0
+    ret
+
+/************************************************************************************
+ * Name: up_savefpu
+ *
+ * Description:
+ *   Given the pointer to a register save area (in A0), save the state of the
+ *   floating point registers.
+ *
+ * C Function Prototype:
+ *   void up_savefpu(uint32_t *regs);
+ *
+ * Input Parameters:
+ *   regs - A pointer to the register save area in which to save the floating point
+ *     registers
+ *
+ * Returned Value:
+ *   None
+ *
+ ************************************************************************************/
+
+    .type         up_savefpu, function
+
+up_savefpu:
+    lw            t0, REG_INT_CTX(a0)
+    li            t1, FS_MASK
+    and           t2, t0, t1
+    li            t1, FS_DIRTY
+    bne           t2, t1, 1f
+    li            t1, ~FS_MASK
+    and           t0, t0, t1
+    li            t1, FS_CLEAN
+    or            t0, t0, t1
+    sw            t0, REG_INT_CTX(a0)
+
+    /* Store all floating point registers */
+
+    FSTORE        f0,  REG_F0(a0)
+    FSTORE        f1,  REG_F1(a0)
+    FSTORE        f2,  REG_F2(a0)
+    FSTORE        f3,  REG_F3(a0)
+    FSTORE        f4,  REG_F4(a0)
+    FSTORE        f5,  REG_F5(a0)
+    FSTORE        f6,  REG_F6(a0)
+    FSTORE        f7,  REG_F7(a0)
+    FSTORE        f8,  REG_F8(a0)
+    FSTORE        f9,  REG_F9(a0)
+    FSTORE        f10, REG_F10(a0)
+    FSTORE        f11, REG_F11(a0)
+    FSTORE        f12, REG_F12(a0)
+    FSTORE        f13, REG_F13(a0)
+    FSTORE        f14, REG_F14(a0)
+    FSTORE        f15, REG_F15(a0)
+    FSTORE        f16, REG_F16(a0)
+    FSTORE        f17, REG_F17(a0)
+    FSTORE        f18, REG_F18(a0)
+    FSTORE        f19, REG_F19(a0)
+    FSTORE        f20, REG_F20(a0)
+    FSTORE        f21, REG_F21(a0)
+    FSTORE        f22, REG_F22(a0)
+    FSTORE        f23, REG_F23(a0)
+    FSTORE        f24, REG_F24(a0)
+    FSTORE        f25, REG_F25(a0)
+    FSTORE        f26, REG_F26(a0)
+    FSTORE        f27, REG_F27(a0)
+    FSTORE        f28, REG_F28(a0)
+    FSTORE        f29, REG_F29(a0)
+    FSTORE        f30, REG_F30(a0)
+    FSTORE        f31, REG_F31(a0)
+
+    frcsr         t0
+    sw            t0, REG_FCSR(a0)
+
+1:
+    ret
+
+/************************************************************************************
+ * Name: up_restorefpu
+ *
+ * Description:
+ *   Given the pointer to a register save area (in A0), restore the state of the
+ *   floating point registers.
+ *
+ * C Function Prototype:
+ *   void up_restorefpu(const uint32_t *regs);
+ *
+ * Input Parameters:
+ *   regs - A pointer to the register save area containing the floating point
+ *     registers.
+ *
+ * Returned Value:
+ *   This function does not return anything explicitly.  However, it is called from
+ *   interrupt level assembly logic that assumes that r0 is preserved.
+ *
+ ************************************************************************************/
+
+    .type        up_restorefpu, function
+
+up_restorefpu:
+    lw           t0, REG_INT_CTX(a0)
+    li           t1, FS_MASK
+    and          t2, t0, t1
+    li           t1, FS_INITIAL
+    ble          t2, t1, 1f
+
+    /* Load all floating point registers */
+
+    FLOAD        f0, REG_F0(a0)
+    FLOAD        f1, REG_F1(a0)
+    FLOAD        f2, REG_F2(a0)
+    FLOAD        f3, REG_F3(a0)
+    FLOAD        f4, REG_F4(a0)
+    FLOAD        f5, REG_F5(a0)
+    FLOAD        f6, REG_F6(a0)
+    FLOAD        f7, REG_F7(a0)
+    FLOAD        f8, REG_F8(a0)
+    FLOAD        f9, REG_F9(a0)
+    FLOAD        f10, REG_F10(a0)
+    FLOAD        f11, REG_F11(a0)
+    FLOAD        f12, REG_F12(a0)
+    FLOAD        f13, REG_F13(a0)
+    FLOAD        f14, REG_F14(a0)
+    FLOAD        f15, REG_F15(a0)
+    FLOAD        f16, REG_F16(a0)
+    FLOAD        f17, REG_F17(a0)
+    FLOAD        f18, REG_F18(a0)
+    FLOAD        f19, REG_F19(a0)
+    FLOAD        f20, REG_F20(a0)
+    FLOAD        f21, REG_F21(a0)
+    FLOAD        f22, REG_F22(a0)
+    FLOAD        f23, REG_F23(a0)
+    FLOAD        f24, REG_F24(a0)
+    FLOAD        f25, REG_F25(a0)
+    FLOAD        f26, REG_F26(a0)
+    FLOAD        f27, REG_F27(a0)
+    FLOAD        f28, REG_F28(a0)
+    FLOAD        f29, REG_F29(a0)
+    FLOAD        f30, REG_F30(a0)
+    FLOAD        f31, REG_F31(a0)
+
+    /* Store the floating point control and status register */
+
+    lw           t0, REG_FCSR(a0)
+    fscsr        t0
+
+1:
+    ret
+
+#endif /* CONFIG_ARCH_FPU */
diff --git a/boards/risc-v/c906/smartl-c906/configs/fpu/defconfig b/boards/risc-v/c906/smartl-c906/configs/fpu/defconfig
new file mode 100644
index 0000000..6a10336
--- /dev/null
+++ b/boards/risc-v/c906/smartl-c906/configs/fpu/defconfig
@@ -0,0 +1,62 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed .config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that includes your
+# modifications.
+#
+# CONFIG_NSH_DISABLE_LOSMART is not set
+# CONFIG_STANDARD_SERIAL is not set
+CONFIG_ARCH="risc-v"
+CONFIG_ARCH_BOARD="smartl-c906"
+CONFIG_ARCH_BOARD_SMARTL_C906=y
+CONFIG_ARCH_CHIP="c906"
+CONFIG_ARCH_CHIP_C906=y
+CONFIG_ARCH_INTERRUPTSTACK=2048
+CONFIG_ARCH_RISCV=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_BOARD_LOOPSPERMSEC=46000
+CONFIG_BUILTIN=y
+CONFIG_C906_ENABLE_DPFPU=y
+CONFIG_C906_WITH_QEMU=y
+CONFIG_DEBUG_FULLOPT=y
+CONFIG_DEBUG_SYMBOLS=y
+CONFIG_DEV_ZERO=y
+CONFIG_EXAMPLES_HELLO=y
+CONFIG_FS_PROCFS=y
+CONFIG_FS_ROMFS=y
+CONFIG_IDLETHREAD_STACKSIZE=2048
+CONFIG_INTELHEX_BINARY=y
+CONFIG_LIBC_PERROR_STDOUT=y
+CONFIG_LIBC_STRERROR=y
+CONFIG_MAX_TASKS=64
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_DISABLE_IFUPDOWN=y
+CONFIG_NSH_DISABLE_MKDIR=y
+CONFIG_NSH_DISABLE_RM=y
+CONFIG_NSH_DISABLE_RMDIR=y
+CONFIG_NSH_DISABLE_UMOUNT=y
+CONFIG_NSH_READLINE=y
+CONFIG_NSH_STRERROR=y
+CONFIG_PREALLOC_TIMERS=4
+CONFIG_RAM_SIZE=262144
+CONFIG_RAM_START=0x00180000
+CONFIG_RAW_BINARY=y
+CONFIG_READLINE_CMD_HISTORY=y
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_HPWORK=y
+CONFIG_SCHED_LPWORK=y
+CONFIG_SCHED_WAITPID=y
+CONFIG_STACK_COLORATION=y
+CONFIG_START_DAY=7
+CONFIG_START_MONTH=3
+CONFIG_START_YEAR=2021
+CONFIG_SYSTEM_NSH=y
+CONFIG_TASK_NAME_SIZE=20
+CONFIG_TESTING_GETPRIME=y
+CONFIG_TESTING_OSTEST=y
+CONFIG_TESTING_OSTEST_FPUSIZE=264
+CONFIG_UART0_SERIAL_CONSOLE=y
+CONFIG_USERMAIN_STACKSIZE=3072
+CONFIG_USER_ENTRYPOINT="nsh_main"
diff --git a/boards/risc-v/c906/smartl-c906/scripts/Make.defs b/boards/risc-v/c906/smartl-c906/scripts/Make.defs
index 55fbf39..5b55ce1 100644
--- a/boards/risc-v/c906/smartl-c906/scripts/Make.defs
+++ b/boards/risc-v/c906/smartl-c906/scripts/Make.defs
@@ -50,7 +50,12 @@ endif
 # ARCHCPUFLAGS = -march=rv64gcxthead -mabi=lp64d -mtune=c906 -mcmodel=medany
 # TODO: We are not going to enable this at this time for the CI compatiblity.
 
-ARCHCPUFLAGS = -march=rv64gc -mabi=lp64d -mcmodel=medany
+ifeq ($(CONFIG_ARCH_HAVE_DPFPU),y)
+  ARCHCPUFLAGS = -march=rv64gc -mabi=lp64d -mcmodel=medany
+else
+  ARCHCPUFLAGS = -march=rv64imac -mabi=lp64 -mcmodel=medany
+endif
+
 ARCHCFLAGS = -fno-builtin -ffunction-sections -fdata-sections -fno-omit-frame-pointer
 ARCHCXXFLAGS = -fno-builtin -fno-exceptions -fcheck-new -fno-rtti
 ARCHWARNINGS = -Wall -Wstrict-prototypes -Wshadow -Wundef
diff --git a/boards/risc-v/c906/smartl-c906/src/Makefile b/boards/risc-v/c906/smartl-c906/src/Makefile
index a616176..4b5f2c7 100644
--- a/boards/risc-v/c906/smartl-c906/src/Makefile
+++ b/boards/risc-v/c906/smartl-c906/src/Makefile
@@ -30,4 +30,8 @@ ifeq ($(CONFIG_ARCH_LEDS),y)
 CSRCS += c906_leds.c
 endif
 
+ifeq ($(CONFIG_ARCH_FPU),y)
+CSRCS += c906_ostest.c
+endif
+
 include $(TOPDIR)/boards/Board.mk
diff --git a/boards/risc-v/c906/smartl-c906/src/c906_ostest.c b/boards/risc-v/c906/smartl-c906/src/c906_ostest.c
new file mode 100644
index 0000000..e4529c4
--- /dev/null
+++ b/boards/risc-v/c906/smartl-c906/src/c906_ostest.c
@@ -0,0 +1,92 @@
+/****************************************************************************
+ * boards/risc-v/c906/smartl-c906/src/c906_ostest.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <syscall.h>
+
+#include <nuttx/irq.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Configuration ************************************************************/
+
+#undef HAVE_FPU
+#if defined(CONFIG_ARCH_FPU) && \
+    !defined(CONFIG_TESTING_OSTEST_FPUTESTDISABLE) && \
+    defined(CONFIG_TESTING_OSTEST_FPUSIZE) && \
+    defined(CONFIG_SCHED_WAITPID)
+#    define HAVE_FPU 1
+#endif
+
+#ifdef HAVE_FPU
+
+#if CONFIG_TESTING_OSTEST_FPUSIZE != (8 * FPU_XCPT_REGS)
+#  error "CONFIG_TESTING_OSTEST_FPUSIZE has the wrong size"
+#endif
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static uint64_t g_saveregs[XCPTCONTEXT_REGS];
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/* Given an array of size CONFIG_TESTING_OSTEST_FPUSIZE, this function will
+ * return the current FPU registers.
+ */
+
+void arch_getfpu(FAR uint32_t *fpusave)
+{
+  irqstate_t flags;
+
+  /* Take a snapshot of the thread context right now */
+
+  flags = enter_critical_section();
+  up_saveusercontext(g_saveregs);
+
+  /* Return only the floating register values */
+
+  memcpy(fpusave, &g_saveregs[INT_XCPT_REGS], (8 * FPU_XCPT_REGS));
+  leave_critical_section(flags);
+}
+
+/* Given two arrays of size CONFIG_TESTING_OSTEST_FPUSIZE this function
+ * will compare them and return true if they are identical.
+ */
+
+bool arch_cmpfpu(FAR const uint32_t *fpusave1, FAR const uint32_t *fpusave2)
+{
+  return memcmp(fpusave1, fpusave2, (8 * FPU_XCPT_REGS)) == 0;
+}
+
+#endif /* HAVE_FPU */