[arch][riscv] Add more defines and optimize fpu context switch

Add a few more #defines for the status register
Tweak the FPU context switch to not rewrite the entire status register,
      which may not be a generally safe thing to do.
This commit is contained in:
Travis Geiselbrecht
2023-02-18 16:39:45 -08:00
parent 92505637e8
commit 81d6014493
2 changed files with 36 additions and 14 deletions

View File

@@ -63,12 +63,28 @@
#define RISCV_CSR_XSTATUS_SPP (1ul << 8)
#define RISCV_CSR_XSTATUS_SUM (1ul << 18)
#define RISCV_CSR_XSTATUS_MXR (1ul << 19)
#define RISCV_CSR_XSTATUS_FS_SHIFT (13)
#define RISCV_CSR_XSTATUS_FS_MASK (3ul << RISCV_CSR_XSTATUS_FS_SHIFT)
#define RISCV_CSR_XSTATUS_FS_OFF (0ul << RISCV_CSR_XSTATUS_FS_SHIFT)
#define RISCV_CSR_XSTATUS_SD (1ul << (__riscv_xlen - 1))
// Vector state field
#define RISCV_CSR_XSTATUS_VS_SHIFT (9)
#define RISCV_CSR_XSTATUS_VS_MASK (3ul << RISCV_CSR_XSTATUS_VS_SHIFT)
#define RISCV_CSR_XSTATUS_VS_OFF (0ul << RISCV_CSR_XSTATUS_VS_SHIFT)
#define RISCV_CSR_XSTATUS_VS_INITIAL (1ul << RISCV_CSR_XSTATUS_VS_SHIFT)
#define RISCV_CSR_XSTATUS_VS_CLEAN (2ul << RISCV_CSR_XSTATUS_VS_SHIFT)
#define RISCV_CSR_XSTATUS_VS_DIRTY (3ul << RISCV_CSR_XSTATUS_VS_SHIFT)
// Floating point state field
#define RISCV_CSR_XSTATUS_FS_SHIFT (13)
#define RISCV_CSR_XSTATUS_FS_MASK (3ul << RISCV_CSR_XSTATUS_FS_SHIFT)
#define RISCV_CSR_XSTATUS_FS_OFF (0ul << RISCV_CSR_XSTATUS_FS_SHIFT)
#define RISCV_CSR_XSTATUS_FS_INITIAL (1ul << RISCV_CSR_XSTATUS_FS_SHIFT)
#define RISCV_CSR_XSTATUS_FS_CLEAN (2ul << RISCV_CSR_XSTATUS_FS_SHIFT)
#define RISCV_CSR_XSTATUS_FS_DIRTY (3ul << RISCV_CSR_XSTATUS_FS_SHIFT)
#define RISCV_CSR_XSTATUS_FS_CLEAN (2ul << RISCV_CSR_XSTATUS_FS_SHIFT)
#define RISCV_CSR_XSTATUS_FS_DIRTY (3ul << RISCV_CSR_XSTATUS_FS_SHIFT)
// Extended state field
#define RISCV_CSR_XSTATUS_XS_SHIFT (15)
#define RISCV_CSR_XSTATUS_XS_MASK (3ul << RISCV_CSR_XSTATUS_XS_SHIFT)
#define RISCV_CSR_XSTATUS_XS_OFF (0ul << RISCV_CSR_XSTATUS_XS_SHIFT)
#define RISCV_CSR_XSTATUS_XS_INITIAL (1ul << RISCV_CSR_XSTATUS_XS_SHIFT)
#define RISCV_CSR_XSTATUS_XS_CLEAN (2ul << RISCV_CSR_XSTATUS_XS_SHIFT)
#define RISCV_CSR_XSTATUS_XS_DIRTY (3ul << RISCV_CSR_XSTATUS_XS_SHIFT)
#define RISCV_CSR_XIE_SIE (1ul << (RISCV_XMODE_OFFSET + 0))
#define RISCV_CSR_XIE_TIE (1ul << (RISCV_XMODE_OFFSET + 4))

View File

@@ -68,10 +68,9 @@ void arch_context_switch(thread_t *oldthread, thread_t *newthread) {
ulong status = riscv_csr_read(RISCV_CSR_XSTATUS);
ulong hw_state = status & RISCV_CSR_XSTATUS_FS_MASK;
LTRACEF("old fpu dirty %d, new fpu dirty %d, status %#lx\n", oldthread->arch.cs_frame.fpu_dirty, newthread->arch.cs_frame.fpu_dirty,
hw_state >> RISCV_CSR_XSTATUS_FS_SHIFT);
status &= ~(RISCV_CSR_XSTATUS_FS_MASK);
LTRACEF("old fpu dirty %d, new fpu dirty %d, status %#lx, sd %d\n", oldthread->arch.cs_frame.fpu_dirty,
newthread->arch.cs_frame.fpu_dirty, hw_state >> RISCV_CSR_XSTATUS_FS_SHIFT,
(status & RISCV_CSR_XSTATUS_SD) ? 1 : 0);
/* hardware currently is in the dirty state, so save the state of the fpu regs
* and mark the thread as dirty.
@@ -93,18 +92,25 @@ void arch_context_switch(thread_t *oldthread, thread_t *newthread) {
/* if the new thread has dirty saved state, load it here and mark the cpu as in the
* clean state, which will transition to dirty if any regs are modified
*/
status |= RISCV_CSR_XSTATUS_FS_CLEAN;
riscv_fpu_restore(&newthread->arch.cs_frame.fpu);
/* at this point the FPU hardware should be in the dirty state because of the above routine */
/* TODO: see if it's totally safe to reduce to a single instruction based on moving from DIRTY -> CLEAN */
riscv_csr_clear(RISCV_CSR_XSTATUS, RISCV_CSR_XSTATUS_FS_MASK);
riscv_csr_set(RISCV_CSR_XSTATUS, RISCV_CSR_XSTATUS_FS_CLEAN);
} else {
/* if the thread previously hadn't dirtied the state, zero out the fpu
* state and mark hardware as initial.
*/
status |= RISCV_CSR_XSTATUS_FS_INITIAL;
riscv_fpu_zero();
}
/* writeback the modified state to hardware */
riscv_csr_write(RISCV_CSR_XSTATUS, status);
/* at this point the FPU hardware should be in the dirty state because of the above routine */
/* TODO: see if it's totally safe to reduce to a single instruction based on moving from DIRTY -> INITIAL */
riscv_csr_clear(RISCV_CSR_XSTATUS, RISCV_CSR_XSTATUS_FS_MASK);
riscv_csr_set(RISCV_CSR_XSTATUS, RISCV_CSR_XSTATUS_FS_INITIAL);
}
#endif
/* integer context switch.