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 2023/07/31 14:49:00 UTC

[nuttx] branch master updated (8f744592d5 -> c126ee8468)

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

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


    from 8f744592d5 Fix nuttx coding style
     new 3b5c0c885f riscv/swint: Give the full tcb to the context switch routine
     new b409d72e9d riscv/fpu: Restore correct lazy-FPU functionality
     new 0ea9debfce riscv/riscv_fpu: Clear the full FPU status/control register on boot
     new 4a468b8d3b riscv/saveusercontext: Fix FPU state save
     new 83105cfa49 sched/assert: Store table for all registers instead of buffer
     new d0fbf9883d riscv/lazyfpu: Add option to disable lazy FPU
     new 61460efe3c riscv/qemu-rv: Add FPU support back to qemu-rv
     new c126ee8468 sched/assert.c: Fix style check error

The 8 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 arch/Kconfig                                       |  41 ++++++++
 arch/risc-v/Kconfig                                |   2 +
 arch/risc-v/include/irq.h                          |  88 +++++++++-------
 arch/risc-v/src/common/riscv_cpupause.c            |   4 +-
 arch/risc-v/src/common/riscv_exception_common.S    |   4 -
 arch/risc-v/src/common/riscv_exit.c                |   2 +-
 arch/risc-v/src/common/riscv_fork.c                |  28 ++---
 arch/risc-v/src/common/riscv_fork.h                |   1 +
 arch/risc-v/src/common/riscv_fpu.S                 | 116 ++++++++++++++++++---
 arch/risc-v/src/common/riscv_internal.h            |  57 ++++++++--
 arch/risc-v/src/common/riscv_macros.S              |  30 ------
 arch/risc-v/src/common/riscv_saveusercontext.S     |   5 +-
 arch/risc-v/src/common/riscv_sigdeliver.c          |   4 +-
 arch/risc-v/src/common/riscv_swint.c               |  21 ++--
 arch/risc-v/src/common/riscv_switchcontext.c       |   6 +-
 arch/risc-v/src/common/supervisor/riscv_syscall.S  |   4 -
 .../qemu-rv/rv-virt/configs/citest/defconfig       |   1 -
 .../qemu-rv/rv-virt/configs/citest64/defconfig     |   1 -
 sched/misc/assert.c                                |  12 ++-
 19 files changed, 295 insertions(+), 132 deletions(-)


[nuttx] 08/08: sched/assert.c: Fix style check error

Posted by xi...@apache.org.
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/nuttx.git

commit c126ee8468a0beff8913bc522b1c80a7d5279bb8
Author: Ville Juven <vi...@unikie.com>
AuthorDate: Mon Jul 31 12:14:35 2023 +0300

    sched/assert.c: Fix style check error
---
 sched/misc/assert.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/sched/misc/assert.c b/sched/misc/assert.c
index 60cb14dc34..357ad7b814 100644
--- a/sched/misc/assert.c
+++ b/sched/misc/assert.c
@@ -238,10 +238,11 @@ static void dump_stacks(FAR struct tcb_s *rtcb, uintptr_t sp)
                  intstack_base,
                  intstack_size,
 #ifdef CONFIG_STACK_COLORATION
-                 up_check_intstack());
+                 up_check_intstack()
 #else
-                 0);
+                 0
 #endif
+                 );
 
       tcbstack_sp = up_getusrsp((FAR void *)CURRENT_REGS);
       if (tcbstack_sp < tcbstack_base || tcbstack_sp >= tcbstack_top)
@@ -271,10 +272,11 @@ static void dump_stacks(FAR struct tcb_s *rtcb, uintptr_t sp)
                  tcbstack_base,
                  tcbstack_size,
 #ifdef CONFIG_STACK_COLORATION
-                 up_check_tcbstack(rtcb));
+                 up_check_tcbstack(rtcb)
 #else
-                 0);
+                 0
 #endif
+                 );
     }
 }
 


[nuttx] 01/08: riscv/swint: Give the full tcb to the context switch routine

Posted by xi...@apache.org.
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/nuttx.git

commit 3b5c0c885f2607d781d7fd5f93a27cb888d93771
Author: Ville Juven <vi...@unikie.com>
AuthorDate: Tue May 16 18:03:53 2023 +0300

    riscv/swint: Give the full tcb to the context switch routine
    
    Why? The tcb can contain info that is needed by the context switch
    routine. One example is lazy-FPU handling; the integer registers can
    be stored into the stack, because they are always stored & restored.
    
    Lazy-FPU however needs a non-volatile location to store the FPU registers
    as the save feature will skip saving a clean FPU, but the restore must
    always restore the FPU registers if the thread uses FPU.
---
 arch/risc-v/src/common/riscv_exit.c          |  2 +-
 arch/risc-v/src/common/riscv_internal.h      | 25 +++++++++++++++++++------
 arch/risc-v/src/common/riscv_sigdeliver.c    |  4 +++-
 arch/risc-v/src/common/riscv_swint.c         | 21 +++++++++++++--------
 arch/risc-v/src/common/riscv_switchcontext.c |  6 +++---
 5 files changed, 39 insertions(+), 19 deletions(-)

diff --git a/arch/risc-v/src/common/riscv_exit.c b/arch/risc-v/src/common/riscv_exit.c
index c6177f29b7..143ffb438a 100644
--- a/arch/risc-v/src/common/riscv_exit.c
+++ b/arch/risc-v/src/common/riscv_exit.c
@@ -139,7 +139,7 @@ void up_exit(int status)
 
   /* Then switch contexts */
 
-  riscv_fullcontextrestore(tcb->xcp.regs);
+  riscv_fullcontextrestore(tcb);
 
   /* riscv_fullcontextrestore() should not return but could if the software
    * interrupts are disabled.
diff --git a/arch/risc-v/src/common/riscv_internal.h b/arch/risc-v/src/common/riscv_internal.h
index f3a50d4c95..6b385818cb 100644
--- a/arch/risc-v/src/common/riscv_internal.h
+++ b/arch/risc-v/src/common/riscv_internal.h
@@ -29,6 +29,7 @@
 
 #ifndef __ASSEMBLY__
 #  include <nuttx/compiler.h>
+#  include <nuttx/sched.h>
 #  include <sys/types.h>
 #  include <stdint.h>
 #  include <syscall.h>
@@ -207,6 +208,18 @@ void riscv_fpuconfig(void);
 #  define riscv_fpuconfig()
 #endif
 
+/* Save / restore context of task */
+
+static inline void riscv_savecontext(struct tcb_s *tcb)
+{
+  tcb->xcp.regs = (uintptr_t *)CURRENT_REGS;
+}
+
+static inline void riscv_restorecontext(struct tcb_s *tcb)
+{
+  CURRENT_REGS = (uintptr_t *)tcb->xcp.regs;
+}
+
 /* RISC-V PMP Config ********************************************************/
 
 int riscv_config_pmp_region(uintptr_t region, uintptr_t attr,
@@ -304,19 +317,19 @@ void *riscv_perform_syscall(uintptr_t *regs);
 
 /* SYS call 1:
  *
- * void riscv_fullcontextrestore(uintptr_t *restoreregs) noreturn_function;
+ * void riscv_fullcontextrestore(struct tcb_s *next) noreturn_function;
  */
 
-#define riscv_fullcontextrestore(restoreregs) \
-  sys_call1(SYS_restore_context, (uintptr_t)restoreregs)
+#define riscv_fullcontextrestore(next) \
+  sys_call1(SYS_restore_context, (uintptr_t)next)
 
 /* SYS call 2:
  *
- * void riscv_switchcontext(uintptr_t *saveregs, uintptr_t *restoreregs);
+ * riscv_switchcontext(struct tcb_s *prev, struct tcb_s *next);
  */
 
-#define riscv_switchcontext(saveregs, restoreregs) \
-  sys_call2(SYS_switch_context, (uintptr_t)saveregs, (uintptr_t)restoreregs)
+#define riscv_switchcontext(prev, next) \
+  sys_call2(SYS_switch_context, (uintptr_t)prev, (uintptr_t)next)
 
 #ifdef CONFIG_BUILD_KERNEL
 /* SYS call 3:
diff --git a/arch/risc-v/src/common/riscv_sigdeliver.c b/arch/risc-v/src/common/riscv_sigdeliver.c
index c9c84e65e5..6e1a70641a 100644
--- a/arch/risc-v/src/common/riscv_sigdeliver.c
+++ b/arch/risc-v/src/common/riscv_sigdeliver.c
@@ -161,5 +161,7 @@ retry:
   leave_critical_section(regs[REG_INT_CTX]);
   rtcb->irqcount--;
 #endif
-  riscv_fullcontextrestore(regs);
+
+  rtcb->xcp.regs = regs;
+  riscv_fullcontextrestore(rtcb);
 }
diff --git a/arch/risc-v/src/common/riscv_swint.c b/arch/risc-v/src/common/riscv_swint.c
index 8eae2db37c..dc2c11f00e 100644
--- a/arch/risc-v/src/common/riscv_swint.c
+++ b/arch/risc-v/src/common/riscv_swint.c
@@ -135,12 +135,12 @@ int riscv_swint(int irq, void *context, void *arg)
       /* A0=SYS_restore_context: This a restore context command:
        *
        * void
-       * riscv_fullcontextrestore(uintptr_t *restoreregs) noreturn_function;
+       * void riscv_fullcontextrestore(struct tcb_s *prev) noreturn_function;
        *
        * At this point, the following values are saved in context:
        *
        *   A0 = SYS_restore_context
-       *   A1 = restoreregs
+       *   A1 = next
        *
        * In this case, we simply need to set CURRENT_REGS to restore register
        * area referenced in the saved A1. context == CURRENT_REGS is the
@@ -150,21 +150,23 @@ int riscv_swint(int irq, void *context, void *arg)
 
       case SYS_restore_context:
         {
+          struct tcb_s *next = (struct tcb_s *)regs[REG_A1];
+
           DEBUGASSERT(regs[REG_A1] != 0);
-          CURRENT_REGS = (uintptr_t *)regs[REG_A1];
+          CURRENT_REGS = (uintptr_t *)next->xcp.regs;
         }
         break;
 
       /* A0=SYS_switch_context: This a switch context command:
        *
        * void
-       * riscv_switchcontext(uintptr_t *saveregs, uintptr_t *restoreregs);
+       * riscv_switchcontext(struct tcb_s *prev, struct tcb_s *next);
        *
        * At this point, the following values are saved in context:
        *
        *   A0 = SYS_switch_context
-       *   A1 = saveregs
-       *   A2 = restoreregs
+       *   A1 = prev
+       *   A2 = next
        *
        * In this case, we save the context registers to the save register
        * area referenced by the saved contents of R5 and then set
@@ -174,9 +176,12 @@ int riscv_swint(int irq, void *context, void *arg)
 
       case SYS_switch_context:
         {
+          struct tcb_s *prev = (struct tcb_s *)regs[REG_A1];
+          struct tcb_s *next = (struct tcb_s *)regs[REG_A2];
+
           DEBUGASSERT(regs[REG_A1] != 0 && regs[REG_A2] != 0);
-          *(uintptr_t **)regs[REG_A1] = (uintptr_t *)regs;
-          CURRENT_REGS = (uintptr_t *)regs[REG_A2];
+          prev->xcp.regs = (uintptr_t *)CURRENT_REGS;
+          CURRENT_REGS = (uintptr_t *)next->xcp.regs;
         }
         break;
 
diff --git a/arch/risc-v/src/common/riscv_switchcontext.c b/arch/risc-v/src/common/riscv_switchcontext.c
index 30ea84a00f..d39ad24b68 100644
--- a/arch/risc-v/src/common/riscv_switchcontext.c
+++ b/arch/risc-v/src/common/riscv_switchcontext.c
@@ -69,7 +69,7 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb)
        * Just copy the CURRENT_REGS into the OLD rtcb.
        */
 
-      riscv_savestate(rtcb->xcp.regs);
+      riscv_savecontext(rtcb);
 
       /* Update scheduler parameters */
 
@@ -79,7 +79,7 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb)
        * changes will be made when the interrupt returns.
        */
 
-      riscv_restorestate(tcb->xcp.regs);
+      riscv_restorecontext(tcb);
     }
 
   /* No, then we will need to perform the user context switch */
@@ -92,7 +92,7 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb)
 
       /* Then switch contexts */
 
-      riscv_switchcontext(&rtcb->xcp.regs, tcb->xcp.regs);
+      riscv_switchcontext(rtcb, tcb);
 
       /* riscv_switchcontext forces a context switch to the task at the
        * head of the ready-to-run list.  It does not 'return' in the


[nuttx] 05/08: sched/assert: Store table for all registers instead of buffer

Posted by xi...@apache.org.
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/nuttx.git

commit 83105cfa49b8659cd952ea63ada84d5db770b66f
Author: Ville Juven <vi...@unikie.com>
AuthorDate: Thu Jun 1 15:39:50 2023 +0300

    sched/assert: Store table for all registers instead of buffer
    
    This way the registers can be read easily
---
 sched/misc/assert.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sched/misc/assert.c b/sched/misc/assert.c
index 54c3be3f84..60cb14dc34 100644
--- a/sched/misc/assert.c
+++ b/sched/misc/assert.c
@@ -72,7 +72,7 @@
  * Private Data
  ****************************************************************************/
 
-static uint8_t g_last_regs[XCPTCONTEXT_SIZE] aligned_data(16);
+static uintptr_t g_last_regs[XCPTCONTEXT_REGS] aligned_data(16);
 
 #ifdef CONFIG_BOARD_COREDUMP
 static struct lib_syslogstream_s  g_syslogstream;


[nuttx] 04/08: riscv/saveusercontext: Fix FPU state save

Posted by xi...@apache.org.
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/nuttx.git

commit 4a468b8d3b8c4acedb0d94ac45d7b63a0d33d7af
Author: Ville Juven <vi...@unikie.com>
AuthorDate: Thu Jun 1 15:37:57 2023 +0300

    riscv/saveusercontext: Fix FPU state save
---
 arch/risc-v/src/common/riscv_saveusercontext.S | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/arch/risc-v/src/common/riscv_saveusercontext.S b/arch/risc-v/src/common/riscv_saveusercontext.S
index b89508b3dd..bbdeca21e0 100644
--- a/arch/risc-v/src/common/riscv_saveusercontext.S
+++ b/arch/risc-v/src/common/riscv_saveusercontext.S
@@ -56,7 +56,10 @@ up_saveusercontext:
   REGSTORE   sp, REG_X2(a0)       /* original SP */
   REGSTORE   x1, REG_EPC(a0)
 
-  riscv_savefpu   a0
+#ifdef CONFIG_ARCH_FPU
+  addi       a0, a0, INT_XCPT_SIZE /* Save FPU after integer regs */
+  riscv_savefpu a0
+#endif
 
   li         a0, 0
   jr         ra


[nuttx] 06/08: riscv/lazyfpu: Add option to disable lazy FPU

Posted by xi...@apache.org.
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/nuttx.git

commit d0fbf9883d2e16785829a5d8f75b9d6122ad2b69
Author: Ville Juven <vi...@unikie.com>
AuthorDate: Wed Jun 7 14:02:48 2023 +0300

    riscv/lazyfpu: Add option to disable lazy FPU
    
    Adds option to use the old implementation where FPU is stored into
    the process stack.
---
 arch/Kconfig                            | 41 +++++++++++++++++++++++++++++++++
 arch/risc-v/include/irq.h               |  8 ++++++-
 arch/risc-v/src/common/riscv_fork.c     | 28 ++++++++++++----------
 arch/risc-v/src/common/riscv_fpu.S      |  4 ++++
 arch/risc-v/src/common/riscv_internal.h | 20 ++++++++++++++--
 5 files changed, 86 insertions(+), 15 deletions(-)

diff --git a/arch/Kconfig b/arch/Kconfig
index 232e32ca10..673ff57771 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -93,6 +93,7 @@ config ARCH_RISCV
 	select ARCH_HAVE_RDWR_MEM_CPU_RUN
 	select ARCH_HAVE_TCBINFO
 	select ARCH_HAVE_THREAD_LOCAL
+	select ARCH_HAVE_LAZYFPU if ARCH_HAVE_FPU
 	---help---
 		RISC-V 32 and 64-bit RV32 / RV64 architectures.
 
@@ -416,6 +417,11 @@ config ARCH_HAVE_DPFPU
 	default n
 	select ARCH_HAVE_FPU
 
+config ARCH_HAVE_LAZYFPU
+	bool
+	default n
+	depends on ARCH_HAVE_FPU
+
 config ARCH_HAVE_MMU
 	bool
 	default n
@@ -516,6 +522,41 @@ config ARCH_DPFPU
 		Enable toolchain support for double precision (64-bit) floating
 		point if both the toolchain and the hardware support it.
 
+config ARCH_LAZYFPU
+	bool "Enable lazy FPU state save / restore"
+	default n
+	depends on ARCH_FPU && ARCH_HAVE_LAZYFPU
+	---help---
+		Enable lazy FPU state save and restore. Normally FPU state is saved
+		and restored with the integer context registers, if the task is using
+		FPU. The state is typically saved into the task's user stack upon
+		exception entry or context switch out, and restored when the
+		exception returns or context switches back in.
+
+		As the kernel does not use FPU, this can be optimized with the help
+		of the FPU hardware status and a bit of code logic inside the kernel.
+		The logic keeps track of the FPU state, which can be "unused",
+		"dirty"	or "clean". A clean state means the FPU has not been used
+		since the last state save, while the dirty state indicates that the
+		FPU has been used.
+
+		The optimization saves / restores FPU registers only if:
+		- A context change has happened, save and restore does not happen
+		  during exception entry / return to the same task
+		- FPU is in use (state is not unused) and
+		- FPU status is dirty, i.e. FPU has been used after the last
+		- FPU restore happens when status is in dirty or clean
+
+		This saves CPU time as the FPU registers do not have to be moved in
+		and out when handling an exception that does not result in a context
+		switch.
+
+		The tradeoff with the lazy FPU feature is that it requires a static
+		memory allocation from the task's TCB to store the FPU registers,
+		while the non-lazy style can use stack memory for storing the FPU
+		registers, saving memory as the stack frame for the FPU registers can
+		be skipped if the FPU is not in use.
+
 config ARCH_USE_MMU
 	bool "Enable MMU"
 	default n
diff --git a/arch/risc-v/include/irq.h b/arch/risc-v/include/irq.h
index 5941d7057b..54f0febbba 100644
--- a/arch/risc-v/include/irq.h
+++ b/arch/risc-v/include/irq.h
@@ -247,9 +247,15 @@
 
 #define XCPTCONTEXT_REGS    (INT_XCPT_REGS + FPU_XCPT_REGS)
 
+#ifdef CONFIG_ARCH_LAZYFPU
 /* Save only integer regs. FPU is handled separately */
 
 #define XCPTCONTEXT_SIZE    (INT_XCPT_SIZE)
+#else
+/* Save FPU registers with the integer registers */
+
+#define XCPTCONTEXT_SIZE    (INT_XCPT_SIZE + FPU_XCPT_SIZE)
+#endif
 
 /* In assembly language, values have to be referenced as byte address
  * offsets.  But in C, it is more convenient to reference registers as
@@ -570,7 +576,7 @@ struct xcptcontext
 
   /* FPU register save area */
 
-#ifdef CONFIG_ARCH_FPU
+#if defined(CONFIG_ARCH_FPU) && defined(CONFIG_ARCH_LAZYFPU)
   uintptr_t fregs[FPU_XCPT_REGS];
 #endif
 };
diff --git a/arch/risc-v/src/common/riscv_fork.c b/arch/risc-v/src/common/riscv_fork.c
index b1d96598e0..0dd41aecdc 100644
--- a/arch/risc-v/src/common/riscv_fork.c
+++ b/arch/risc-v/src/common/riscv_fork.c
@@ -109,6 +109,9 @@ pid_t riscv_fork(const struct fork_s *context)
   uintptr_t newtop;
   uintptr_t stacktop;
   uintptr_t stackutil;
+#ifdef CONFIG_ARCH_FPU
+  uintptr_t *fregs;
+#endif
 
   sinfo("s0:%" PRIxREG " s1:%" PRIxREG " s2:%" PRIxREG " s3:%" PRIxREG ""
         " s4:%" PRIxREG "\n",
@@ -228,18 +231,19 @@ pid_t riscv_fork(const struct fork_s *context)
   child->cmn.xcp.regs[REG_GP]   = newsp;        /* Global pointer */
 #endif
 #ifdef CONFIG_ARCH_FPU
-  child->cmn.xcp.fregs[REG_FS0]  = context->fs0;  /* Saved register fs1 */
-  child->cmn.xcp.fregs[REG_FS1]  = context->fs1;  /* Saved register fs1 */
-  child->cmn.xcp.fregs[REG_FS2]  = context->fs2;  /* Saved register fs2 */
-  child->cmn.xcp.fregs[REG_FS3]  = context->fs3;  /* Saved register fs3 */
-  child->cmn.xcp.fregs[REG_FS4]  = context->fs4;  /* Saved register fs4 */
-  child->cmn.xcp.fregs[REG_FS5]  = context->fs5;  /* Saved register fs5 */
-  child->cmn.xcp.fregs[REG_FS6]  = context->fs6;  /* Saved register fs6 */
-  child->cmn.xcp.fregs[REG_FS7]  = context->fs7;  /* Saved register fs7 */
-  child->cmn.xcp.fregs[REG_FS8]  = context->fs8;  /* Saved register fs8 */
-  child->cmn.xcp.fregs[REG_FS9]  = context->fs9;  /* Saved register fs9 */
-  child->cmn.xcp.fregs[REG_FS10] = context->fs10; /* Saved register fs10 */
-  child->cmn.xcp.fregs[REG_FS11] = context->fs11; /* Saved register fs11 */
+  fregs                         = riscv_fpuregs(&child->cmn);
+  fregs[REG_FS0]                = context->fs0;  /* Saved register fs1 */
+  fregs[REG_FS1]                = context->fs1;  /* Saved register fs1 */
+  fregs[REG_FS2]                = context->fs2;  /* Saved register fs2 */
+  fregs[REG_FS3]                = context->fs3;  /* Saved register fs3 */
+  fregs[REG_FS4]                = context->fs4;  /* Saved register fs4 */
+  fregs[REG_FS5]                = context->fs5;  /* Saved register fs5 */
+  fregs[REG_FS6]                = context->fs6;  /* Saved register fs6 */
+  fregs[REG_FS7]                = context->fs7;  /* Saved register fs7 */
+  fregs[REG_FS8]                = context->fs8;  /* Saved register fs8 */
+  fregs[REG_FS9]                = context->fs9;  /* Saved register fs9 */
+  fregs[REG_FS10]               = context->fs10; /* Saved register fs10 */
+  fregs[REG_FS11]               = context->fs11; /* Saved register fs11 */
 #endif
 
 #ifdef CONFIG_LIB_SYSCALL
diff --git a/arch/risc-v/src/common/riscv_fpu.S b/arch/risc-v/src/common/riscv_fpu.S
index cc88e769dd..11f24b90ca 100644
--- a/arch/risc-v/src/common/riscv_fpu.S
+++ b/arch/risc-v/src/common/riscv_fpu.S
@@ -102,7 +102,11 @@ riscv_savefpu:
   li         t1, MSTATUS_FS
   and        t2, t0, t1
   li         t1, MSTATUS_FS_DIRTY
+#ifdef CONFIG_ARCH_LAZYFPU
   bne        t2, t1, 1f
+#else
+  blt        t2, t1, 1f
+#endif
   li         t1, ~MSTATUS_FS
   and        t0, t0, t1
   li         t1, MSTATUS_FS_CLEAN
diff --git a/arch/risc-v/src/common/riscv_internal.h b/arch/risc-v/src/common/riscv_internal.h
index 836d7354f5..ac16c0bd87 100644
--- a/arch/risc-v/src/common/riscv_internal.h
+++ b/arch/risc-v/src/common/riscv_internal.h
@@ -206,10 +206,26 @@ void riscv_exception_attach(void);
 void riscv_fpuconfig(void);
 void riscv_savefpu(uintptr_t *regs, uintptr_t *fregs);
 void riscv_restorefpu(uintptr_t *regs, uintptr_t *fregs);
+
+/* Get FPU register save area */
+
+static inline uintptr_t *riscv_fpuregs(struct tcb_s *tcb)
+{
+#ifdef CONFIG_ARCH_LAZYFPU
+  /* With lazy FPU the registers are simply in tcb */
+
+  return tcb->xcp.fregs;
+#else
+  /* Otherwise they are after the integer registers */
+
+  return (uintptr_t *)((uintptr_t)tcb->xcp.regs + INT_XCPT_SIZE);
+#endif
+}
 #else
 #  define riscv_fpuconfig()
 #  define riscv_savefpu(regs, fregs)
 #  define riscv_restorefpu(regs, fregs)
+#  define riscv_fpuregs(tcb)
 #endif
 
 /* Save / restore context of task */
@@ -221,7 +237,7 @@ static inline void riscv_savecontext(struct tcb_s *tcb)
 #ifdef CONFIG_ARCH_FPU
   /* Save current process FPU state to TCB */
 
-  riscv_savefpu(tcb->xcp.regs, tcb->xcp.fregs);
+  riscv_savefpu(tcb->xcp.regs, riscv_fpuregs(tcb));
 #endif
 }
 
@@ -232,7 +248,7 @@ static inline void riscv_restorecontext(struct tcb_s *tcb)
 #ifdef CONFIG_ARCH_FPU
   /* Restore FPU state for next process */
 
-  riscv_restorefpu(tcb->xcp.regs, tcb->xcp.fregs);
+  riscv_restorefpu(tcb->xcp.regs, riscv_fpuregs(tcb));
 #endif
 }
 


[nuttx] 07/08: riscv/qemu-rv: Add FPU support back to qemu-rv

Posted by xi...@apache.org.
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/nuttx.git

commit 61460efe3ca7bd4f04d28d74e874060d279af7e8
Author: Ville Juven <vi...@unikie.com>
AuthorDate: Tue Jun 20 13:39:52 2023 +0300

    riscv/qemu-rv: Add FPU support back to qemu-rv
    
    The FPU restore issue does not show itself any longer, so FPU support
    can be re-enabled.
---
 arch/risc-v/Kconfig                                      | 2 ++
 boards/risc-v/qemu-rv/rv-virt/configs/citest/defconfig   | 1 -
 boards/risc-v/qemu-rv/rv-virt/configs/citest64/defconfig | 1 -
 3 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/risc-v/Kconfig b/arch/risc-v/Kconfig
index f6092dd94c..c6cd81377a 100644
--- a/arch/risc-v/Kconfig
+++ b/arch/risc-v/Kconfig
@@ -163,6 +163,8 @@ config ARCH_CHIP_RV32M1
 
 config ARCH_CHIP_QEMU_RV
 	bool "QEMU RV"
+	select ARCH_HAVE_FPU
+	select ARCH_HAVE_DPFPU
 	select ARCH_HAVE_MULTICPU
 	select ARCH_HAVE_MPU
 	select ARCH_HAVE_MMU
diff --git a/boards/risc-v/qemu-rv/rv-virt/configs/citest/defconfig b/boards/risc-v/qemu-rv/rv-virt/configs/citest/defconfig
index a080275da0..946b2bf7c4 100644
--- a/boards/risc-v/qemu-rv/rv-virt/configs/citest/defconfig
+++ b/boards/risc-v/qemu-rv/rv-virt/configs/citest/defconfig
@@ -49,7 +49,6 @@ CONFIG_INIT_ENTRYPOINT="nsh_main"
 CONFIG_INTELHEX_BINARY=y
 CONFIG_LIBC_ENVPATH=y
 CONFIG_LIBC_EXECFUNCS=y
-CONFIG_LIBC_FLOATINGPOINT=y
 CONFIG_LIBC_PERROR_STDOUT=y
 CONFIG_LIBC_STRERROR=y
 CONFIG_NET=y
diff --git a/boards/risc-v/qemu-rv/rv-virt/configs/citest64/defconfig b/boards/risc-v/qemu-rv/rv-virt/configs/citest64/defconfig
index e2a5d9e065..031389e0db 100644
--- a/boards/risc-v/qemu-rv/rv-virt/configs/citest64/defconfig
+++ b/boards/risc-v/qemu-rv/rv-virt/configs/citest64/defconfig
@@ -48,7 +48,6 @@ CONFIG_INIT_STACKSIZE=3072
 CONFIG_INTELHEX_BINARY=y
 CONFIG_LIBC_ENVPATH=y
 CONFIG_LIBC_EXECFUNCS=y
-CONFIG_LIBC_FLOATINGPOINT=y
 CONFIG_LIBC_PERROR_STDOUT=y
 CONFIG_LIBC_STRERROR=y
 CONFIG_NET=y


[nuttx] 02/08: riscv/fpu: Restore correct lazy-FPU functionality

Posted by xi...@apache.org.
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/nuttx.git

commit b409d72e9db206cbce0672755443e20531101875
Author: Ville Juven <vi...@unikie.com>
AuthorDate: Mon May 15 17:56:15 2023 +0300

    riscv/fpu: Restore correct lazy-FPU functionality
    
    - Save the FPU registers into the tcb so they don't get lost if the stack
      frame for xcp.regs moves (as it does)
    - Handle interger and FPU register save/load separately
    - Integer registers are saved/loaded always, like before
    - FPU registers are only saved during a context switch:
      - Save ONLY if FPU is dirty
      - Restore always if FPU has been used (not in FSTATE_OFF, FSTATE_INIT)
    - Remove all lazy-FPU related logic from the macros, it is not needed
---
 arch/risc-v/include/irq.h                         |  82 +++++++++-------
 arch/risc-v/src/common/riscv_cpupause.c           |   4 +-
 arch/risc-v/src/common/riscv_exception_common.S   |   4 -
 arch/risc-v/src/common/riscv_fork.c               |  24 ++---
 arch/risc-v/src/common/riscv_fork.h               |   1 +
 arch/risc-v/src/common/riscv_fpu.S                | 113 +++++++++++++++++++---
 arch/risc-v/src/common/riscv_internal.h           |  16 +++
 arch/risc-v/src/common/riscv_macros.S             |  30 ------
 arch/risc-v/src/common/riscv_swint.c              |   6 +-
 arch/risc-v/src/common/supervisor/riscv_syscall.S |   4 -
 10 files changed, 176 insertions(+), 108 deletions(-)

diff --git a/arch/risc-v/include/irq.h b/arch/risc-v/include/irq.h
index a566492e89..5941d7057b 100644
--- a/arch/risc-v/include/irq.h
+++ b/arch/risc-v/include/irq.h
@@ -204,50 +204,52 @@
 #endif
 
 #ifdef CONFIG_ARCH_FPU
-#  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 REG_F0_NDX        (FPU_REG_SIZE * 0)
+#  define REG_F1_NDX        (FPU_REG_SIZE * 1)
+#  define REG_F2_NDX        (FPU_REG_SIZE * 2)
+#  define REG_F3_NDX        (FPU_REG_SIZE * 3)
+#  define REG_F4_NDX        (FPU_REG_SIZE * 4)
+#  define REG_F5_NDX        (FPU_REG_SIZE * 5)
+#  define REG_F6_NDX        (FPU_REG_SIZE * 6)
+#  define REG_F7_NDX        (FPU_REG_SIZE * 7)
+#  define REG_F8_NDX        (FPU_REG_SIZE * 8)
+#  define REG_F9_NDX        (FPU_REG_SIZE * 9)
+#  define REG_F10_NDX       (FPU_REG_SIZE * 10)
+#  define REG_F11_NDX       (FPU_REG_SIZE * 11)
+#  define REG_F12_NDX       (FPU_REG_SIZE * 12)
+#  define REG_F13_NDX       (FPU_REG_SIZE * 13)
+#  define REG_F14_NDX       (FPU_REG_SIZE * 14)
+#  define REG_F15_NDX       (FPU_REG_SIZE * 15)
+#  define REG_F16_NDX       (FPU_REG_SIZE * 16)
+#  define REG_F17_NDX       (FPU_REG_SIZE * 17)
+#  define REG_F18_NDX       (FPU_REG_SIZE * 18)
+#  define REG_F19_NDX       (FPU_REG_SIZE * 19)
+#  define REG_F20_NDX       (FPU_REG_SIZE * 20)
+#  define REG_F21_NDX       (FPU_REG_SIZE * 21)
+#  define REG_F22_NDX       (FPU_REG_SIZE * 22)
+#  define REG_F23_NDX       (FPU_REG_SIZE * 23)
+#  define REG_F24_NDX       (FPU_REG_SIZE * 24)
+#  define REG_F25_NDX       (FPU_REG_SIZE * 25)
+#  define REG_F26_NDX       (FPU_REG_SIZE * 26)
+#  define REG_F27_NDX       (FPU_REG_SIZE * 27)
+#  define REG_F28_NDX       (FPU_REG_SIZE * 28)
+#  define REG_F29_NDX       (FPU_REG_SIZE * 29)
+#  define REG_F30_NDX       (FPU_REG_SIZE * 30)
+#  define REG_F31_NDX       (FPU_REG_SIZE * 31)
+#  define REG_FCSR_NDX      (FPU_REG_SIZE * 32)
 
 #  define FPU_XCPT_REGS     (FPU_REG_SIZE * 33)
-#  define FPU_REG_FULL_SIZE (INT_REG_SIZE * FPU_REG_SIZE)
+#  define FPU_XCPT_SIZE     (INT_REG_SIZE * FPU_XCPT_REGS)
 #else /* !CONFIG_ARCH_FPU */
 #  define FPU_XCPT_REGS     (0)
-#  define FPU_REG_FULL_SIZE (0)
+#  define FPU_XCPT_SIZE     (0)
 #endif /* CONFIG_ARCH_FPU */
 
 #define XCPTCONTEXT_REGS    (INT_XCPT_REGS + FPU_XCPT_REGS)
 
-#define XCPTCONTEXT_SIZE    (INT_REG_SIZE * XCPTCONTEXT_REGS)
+/* Save only integer regs. FPU is handled separately */
+
+#define XCPTCONTEXT_SIZE    (INT_XCPT_SIZE)
 
 /* In assembly language, values have to be referenced as byte address
  * offsets.  But in C, it is more convenient to reference registers as
@@ -562,9 +564,15 @@ struct xcptcontext
 #endif
 #endif
 
-  /* Register save area */
+  /* Integer register save area */
 
   uintptr_t *regs;
+
+  /* FPU register save area */
+
+#ifdef CONFIG_ARCH_FPU
+  uintptr_t fregs[FPU_XCPT_REGS];
+#endif
 };
 
 #endif /* __ASSEMBLY__ */
diff --git a/arch/risc-v/src/common/riscv_cpupause.c b/arch/risc-v/src/common/riscv_cpupause.c
index 7d30dc5543..87412f7ad4 100644
--- a/arch/risc-v/src/common/riscv_cpupause.c
+++ b/arch/risc-v/src/common/riscv_cpupause.c
@@ -129,7 +129,7 @@ int up_cpu_paused(int cpu)
    * of the assigned task list for this CPU.
    */
 
-  riscv_savestate(tcb->xcp.regs);
+  riscv_savecontext(tcb);
 
   /* Wait for the spinlock to be released */
 
@@ -161,7 +161,7 @@ int up_cpu_paused(int cpu)
    * will be made when the interrupt returns.
    */
 
-  riscv_restorestate(tcb->xcp.regs);
+  riscv_restorecontext(tcb);
 
   spin_unlock(&g_cpu_wait[cpu]);
   spin_unlock(&g_cpu_resumed[cpu]);
diff --git a/arch/risc-v/src/common/riscv_exception_common.S b/arch/risc-v/src/common/riscv_exception_common.S
index 1f1180d46b..9d78b65c09 100644
--- a/arch/risc-v/src/common/riscv_exception_common.S
+++ b/arch/risc-v/src/common/riscv_exception_common.S
@@ -113,8 +113,6 @@ exception_common:
   csrr       s0, CSR_EPC
   REGSTORE   s0, REG_EPC(sp)      /* exception PC */
 
-  riscv_savefpu   sp
-
   /* Setup arg0(exception cause), arg1(context) */
 
   csrr       a0, CSR_CAUSE        /* exception cause */
@@ -148,8 +146,6 @@ exception_common:
 
   mv         sp, a0
 
-  riscv_loadfpu   sp
-
   REGLOAD    s0, REG_EPC(sp)      /* restore sepc */
   csrw       CSR_EPC, s0
 
diff --git a/arch/risc-v/src/common/riscv_fork.c b/arch/risc-v/src/common/riscv_fork.c
index 53ac2f3740..b1d96598e0 100644
--- a/arch/risc-v/src/common/riscv_fork.c
+++ b/arch/risc-v/src/common/riscv_fork.c
@@ -228,18 +228,18 @@ pid_t riscv_fork(const struct fork_s *context)
   child->cmn.xcp.regs[REG_GP]   = newsp;        /* Global pointer */
 #endif
 #ifdef CONFIG_ARCH_FPU
-  child->cmn.xcp.regs[REG_FS0]  = context->fs0;  /* Saved register fs1 */
-  child->cmn.xcp.regs[REG_FS1]  = context->fs1;  /* Saved register fs1 */
-  child->cmn.xcp.regs[REG_FS2]  = context->fs2;  /* Saved register fs2 */
-  child->cmn.xcp.regs[REG_FS3]  = context->fs3;  /* Saved register fs3 */
-  child->cmn.xcp.regs[REG_FS4]  = context->fs4;  /* Saved register fs4 */
-  child->cmn.xcp.regs[REG_FS5]  = context->fs5;  /* Saved register fs5 */
-  child->cmn.xcp.regs[REG_FS6]  = context->fs6;  /* Saved register fs6 */
-  child->cmn.xcp.regs[REG_FS7]  = context->fs7;  /* Saved register fs7 */
-  child->cmn.xcp.regs[REG_FS8]  = context->fs8;  /* Saved register fs8 */
-  child->cmn.xcp.regs[REG_FS9]  = context->fs9;  /* Saved register fs9 */
-  child->cmn.xcp.regs[REG_FS10] = context->fs10; /* Saved register fs10 */
-  child->cmn.xcp.regs[REG_FS11] = context->fs11; /* Saved register fs11 */
+  child->cmn.xcp.fregs[REG_FS0]  = context->fs0;  /* Saved register fs1 */
+  child->cmn.xcp.fregs[REG_FS1]  = context->fs1;  /* Saved register fs1 */
+  child->cmn.xcp.fregs[REG_FS2]  = context->fs2;  /* Saved register fs2 */
+  child->cmn.xcp.fregs[REG_FS3]  = context->fs3;  /* Saved register fs3 */
+  child->cmn.xcp.fregs[REG_FS4]  = context->fs4;  /* Saved register fs4 */
+  child->cmn.xcp.fregs[REG_FS5]  = context->fs5;  /* Saved register fs5 */
+  child->cmn.xcp.fregs[REG_FS6]  = context->fs6;  /* Saved register fs6 */
+  child->cmn.xcp.fregs[REG_FS7]  = context->fs7;  /* Saved register fs7 */
+  child->cmn.xcp.fregs[REG_FS8]  = context->fs8;  /* Saved register fs8 */
+  child->cmn.xcp.fregs[REG_FS9]  = context->fs9;  /* Saved register fs9 */
+  child->cmn.xcp.fregs[REG_FS10] = context->fs10; /* Saved register fs10 */
+  child->cmn.xcp.fregs[REG_FS11] = context->fs11; /* Saved register fs11 */
 #endif
 
 #ifdef CONFIG_LIB_SYSCALL
diff --git a/arch/risc-v/src/common/riscv_fork.h b/arch/risc-v/src/common/riscv_fork.h
index 32cadba8d8..5fbd207af7 100644
--- a/arch/risc-v/src/common/riscv_fork.h
+++ b/arch/risc-v/src/common/riscv_fork.h
@@ -90,6 +90,7 @@
 #endif
 
 #ifdef CONFIG_ARCH_FPU
+#  define FPU_REG_FULL_SIZE (INT_REG_SIZE * FPU_REG_SIZE)
 #  define FORK_FS0_OFFSET  (FORK_INT_SIZE + 0*FPU_REG_FULL_SIZE)
 #  define FORK_FS1_OFFSET  (FORK_INT_SIZE + 1*FPU_REG_FULL_SIZE)
 #  define FORK_FS2_OFFSET  (FORK_INT_SIZE + 2*FPU_REG_FULL_SIZE)
diff --git a/arch/risc-v/src/common/riscv_fpu.S b/arch/risc-v/src/common/riscv_fpu.S
index 84989ccbf3..9d5feb9390 100644
--- a/arch/risc-v/src/common/riscv_fpu.S
+++ b/arch/risc-v/src/common/riscv_fpu.S
@@ -1,4 +1,4 @@
-/************************************************************************************
+/****************************************************************************
  * arch/risc-v/src/common/riscv_fpu.S
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -16,11 +16,11 @@
  * License for the specific language governing permissions and limitations
  * under the License.
  *
- ************************************************************************************/
+ ****************************************************************************/
 
-/************************************************************************************
+/****************************************************************************
  * Included Files
- ************************************************************************************/
+ ****************************************************************************/
 
 #include <nuttx/config.h>
 
@@ -29,20 +29,24 @@
 #include <arch/irq.h>
 #include <arch/mode.h>
 
+#include "riscv_macros.S"
+
 #ifdef CONFIG_ARCH_FPU
 
-/************************************************************************************
+/****************************************************************************
  * Public Symbols
- ************************************************************************************/
+ ****************************************************************************/
 
     .globl        riscv_fpuconfig
+    .globl        riscv_savefpu
+    .globl        riscv_restorefpu
     .file         "riscv_fpu.S"
 
-/************************************************************************************
+/****************************************************************************
  * Public Functions
- ************************************************************************************/
+ ****************************************************************************/
 
-/************************************************************************************
+/****************************************************************************
  * Name: riscv_fpuconfig
  *
  * Description:
@@ -57,18 +61,95 @@
  * Returned Value:
  *   This function does not return anything explicitly.
  *
- ************************************************************************************/
+ ****************************************************************************/
 
     .type        riscv_fpuconfig, function
 
 riscv_fpuconfig:
-    li           a0, MSTATUS_FS_INIT
-    csrs         CSR_STATUS, a0
+  li           a0, MSTATUS_FS_INIT
+  csrs         CSR_STATUS, a0
+
+  fsflags      zero
+  fsrm         zero
+
+  fence.i
+  ret
+
+/****************************************************************************
+ * Name: riscv_savefpu
+ *
+ * Description:
+ *   Given the pointer to a register save area (in A0), save the state of the
+ *   floating point registers.
+ *
+ * C Function Prototype:
+ *   void riscv_savefpu(uintptr_t *regs, uintptr_t *fregs);
+ *
+ * Input Parameters:
+ *   regs  - A pointer to the integer registers that contain the status
+ *   fregs - A pointer to the register save area in which to save the
+ *           floating point registers
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+    .type         riscv_savefpu, function
+
+riscv_savefpu:
+
+  REGLOAD    t0, REG_INT_CTX(a0)
+  li         t1, MSTATUS_FS
+  and        t2, t0, t1
+  li         t1, MSTATUS_FS_DIRTY
+  bne        t2, t1, 1f
+  li         t1, ~MSTATUS_FS
+  and        t0, t0, t1
+  li         t1, MSTATUS_FS_CLEAN
+  or         t0, t0, t1
+  REGSTORE   t0, REG_INT_CTX(a0)
+
+  riscv_savefpu a1
+
+1:
+  ret
+
+/****************************************************************************
+ * Name: riscv_restorefpu
+ *
+ * Description:
+ *   Given the pointer to a register save area (in A0), restore the state of
+ *   the floating point registers.
+ *
+ * C Function Prototype:
+ *   void riscv_restorefpu(uintptr_t *regs, uintptr_t *fregs);
+ *
+ * Input Parameters:
+ *   regs  - A pointer to the integer registers that contain the status
+ *   fregs - 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        riscv_restorefpu, function
+
+riscv_restorefpu:
+
+  REGLOAD      t0, REG_INT_CTX(a0)
+  li           t1, MSTATUS_FS
+  and          t2, t0, t1
+  li           t1, MSTATUS_FS_INIT
+  ble          t2, t1, 1f
 
-    fsflags      zero
-    fsrm         zero
+  riscv_loadfpu a1
 
-    fence.i
-    ret
+1:
+  ret
 
 #endif /* CONFIG_ARCH_FPU */
diff --git a/arch/risc-v/src/common/riscv_internal.h b/arch/risc-v/src/common/riscv_internal.h
index 6b385818cb..836d7354f5 100644
--- a/arch/risc-v/src/common/riscv_internal.h
+++ b/arch/risc-v/src/common/riscv_internal.h
@@ -204,8 +204,12 @@ void riscv_exception_attach(void);
 
 #ifdef CONFIG_ARCH_FPU
 void riscv_fpuconfig(void);
+void riscv_savefpu(uintptr_t *regs, uintptr_t *fregs);
+void riscv_restorefpu(uintptr_t *regs, uintptr_t *fregs);
 #else
 #  define riscv_fpuconfig()
+#  define riscv_savefpu(regs, fregs)
+#  define riscv_restorefpu(regs, fregs)
 #endif
 
 /* Save / restore context of task */
@@ -213,11 +217,23 @@ void riscv_fpuconfig(void);
 static inline void riscv_savecontext(struct tcb_s *tcb)
 {
   tcb->xcp.regs = (uintptr_t *)CURRENT_REGS;
+
+#ifdef CONFIG_ARCH_FPU
+  /* Save current process FPU state to TCB */
+
+  riscv_savefpu(tcb->xcp.regs, tcb->xcp.fregs);
+#endif
 }
 
 static inline void riscv_restorecontext(struct tcb_s *tcb)
 {
   CURRENT_REGS = (uintptr_t *)tcb->xcp.regs;
+
+#ifdef CONFIG_ARCH_FPU
+  /* Restore FPU state for next process */
+
+  riscv_restorefpu(tcb->xcp.regs, tcb->xcp.fregs);
+#endif
 }
 
 /* RISC-V PMP Config ********************************************************/
diff --git a/arch/risc-v/src/common/riscv_macros.S b/arch/risc-v/src/common/riscv_macros.S
index 83626b05b0..5f9bd12f65 100644
--- a/arch/risc-v/src/common/riscv_macros.S
+++ b/arch/risc-v/src/common/riscv_macros.S
@@ -100,13 +100,6 @@
 
 .macro riscv_savefpu in
 
-#ifdef CONFIG_ARCH_FPU
-  REGLOAD    t0, REG_INT_CTX(\in)
-  li         t1, MSTATUS_FS
-  and        t0, t0, t1
-  li         t1, MSTATUS_FS_INIT
-  ble        t0, t1, 1f
-
   /* Store all floating point registers */
 
   FSTORE     f0,  REG_F0(\in)
@@ -145,14 +138,6 @@
   frcsr      t0
   REGSTORE   t0, REG_FCSR(\in)
 
-1:
-
-  /* Restore what we have just destroyed (t0, t1) */
-
-  REGLOAD      t0, REG_T0(\in)
-  REGLOAD      t1, REG_T1(\in)
-#endif
-
 .endm
 
 /****************************************************************************
@@ -216,13 +201,6 @@
 
 .macro riscv_loadfpu out
 
-#ifdef CONFIG_ARCH_FPU
-  REGLOAD      t0, REG_INT_CTX(\out)
-  li           t1, MSTATUS_FS
-  and          t0, t0, t1
-  li           t1, MSTATUS_FS_INIT
-  ble          t0, t1, 1f
-
   /* Load all floating point registers */
 
   FLOAD        f0, REG_F0(\out)
@@ -263,14 +241,6 @@
   REGLOAD      t0, REG_FCSR(\out)
   fscsr        t0
 
-1:
-
-  /* Restore what we have just destroyed (t0, t1) */
-
-  REGLOAD      t0, REG_T0(\out)
-  REGLOAD      t1, REG_T1(\out)
-#endif
-
 .endm
 
 /****************************************************************************
diff --git a/arch/risc-v/src/common/riscv_swint.c b/arch/risc-v/src/common/riscv_swint.c
index dc2c11f00e..0a262fe700 100644
--- a/arch/risc-v/src/common/riscv_swint.c
+++ b/arch/risc-v/src/common/riscv_swint.c
@@ -153,7 +153,7 @@ int riscv_swint(int irq, void *context, void *arg)
           struct tcb_s *next = (struct tcb_s *)regs[REG_A1];
 
           DEBUGASSERT(regs[REG_A1] != 0);
-          CURRENT_REGS = (uintptr_t *)next->xcp.regs;
+          riscv_restorecontext(next);
         }
         break;
 
@@ -180,8 +180,8 @@ int riscv_swint(int irq, void *context, void *arg)
           struct tcb_s *next = (struct tcb_s *)regs[REG_A2];
 
           DEBUGASSERT(regs[REG_A1] != 0 && regs[REG_A2] != 0);
-          prev->xcp.regs = (uintptr_t *)CURRENT_REGS;
-          CURRENT_REGS = (uintptr_t *)next->xcp.regs;
+          riscv_savecontext(prev);
+          riscv_restorecontext(next);
         }
         break;
 
diff --git a/arch/risc-v/src/common/supervisor/riscv_syscall.S b/arch/risc-v/src/common/supervisor/riscv_syscall.S
index 18804a49f1..3e4515fea7 100644
--- a/arch/risc-v/src/common/supervisor/riscv_syscall.S
+++ b/arch/risc-v/src/common/supervisor/riscv_syscall.S
@@ -109,8 +109,6 @@ sys_call6:
   addi       s0, sp, XCPTCONTEXT_SIZE
   REGSTORE   s0, REG_SP(sp)            /* original SP */
 
-  riscv_savefpu sp
-
   mv         a0, sp                    /* a0 = context */
 
 #if CONFIG_ARCH_INTERRUPTSTACK > 15
@@ -127,8 +125,6 @@ sys_call6:
 
   mv         sp, a0                    /* use sp, as a0 gets wiped */
 
-  riscv_loadfpu sp
-
   REGLOAD    s0, REG_EPC(sp)           /* restore epc */
   csrw       CSR_EPC, s0
 


[nuttx] 03/08: riscv/riscv_fpu: Clear the full FPU status/control register on boot

Posted by xi...@apache.org.
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/nuttx.git

commit 0ea9debfceacb9e1989cdfc2572695a67a2a8116
Author: Ville Juven <vi...@unikie.com>
AuthorDate: Thu Jul 27 11:05:19 2023 +0300

    riscv/riscv_fpu: Clear the full FPU status/control register on boot
    
    Instead of clearing the fields individually, just wipe the whole register.
    This can be done because flags and rm are just parts of the fcsr.
    
    31             8        5           0
    +--------------+--------+-----------+
    |              |        |           |
    |   RESERVED   |  FRM   |  FSTATUS  |
    |              |        |           |
    +--------------+--------+-----------+
                    FCSR
---
 arch/risc-v/src/common/riscv_fpu.S | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/arch/risc-v/src/common/riscv_fpu.S b/arch/risc-v/src/common/riscv_fpu.S
index 9d5feb9390..cc88e769dd 100644
--- a/arch/risc-v/src/common/riscv_fpu.S
+++ b/arch/risc-v/src/common/riscv_fpu.S
@@ -69,8 +69,7 @@ riscv_fpuconfig:
   li           a0, MSTATUS_FS_INIT
   csrs         CSR_STATUS, a0
 
-  fsflags      zero
-  fsrm         zero
+  fscsr        zero
 
   fence.i
   ret