Skip to content

Commit

Permalink
arch/risc-v: add support of save/restore vector registers
Browse files Browse the repository at this point in the history
  • Loading branch information
anchao authored and acassis committed Apr 23, 2024
1 parent c093514 commit 28044f7
Show file tree
Hide file tree
Showing 12 changed files with 388 additions and 0 deletions.
17 changes: 17 additions & 0 deletions arch/risc-v/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,23 @@ config ARCH_RV_ISA_V
default n
depends on ARCH_FPU

if ARCH_RV_ISA_V

config ARCH_RV_VECTOR_BYTE_LENGTH
int "Vector Register Length in bytes"
default 32
---help---
Predefined vector register length. If CSR vlenb is greater than the
current reserved value, appropriate memory will be allocated to
save/restore the vector registers.
The XLEN-bit-wide read-only CSR vlenb holds the value VLEN/8, i.e.,
the vector register length in bytes. The value in vlenb is a
design-time constant in any implementation. Without this CSR, several
instructions are needed to calculate VLEN in bytes. The code has to
disturb current vl and vtype settings which require them to be saved and restored.

endif

config ARCH_RV_ISA_ZICSR_ZIFENCEI
bool
default y
Expand Down
49 changes: 49 additions & 0 deletions arch/risc-v/include/irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,29 @@
#define XCPTCONTEXT_SIZE (INT_XCPT_SIZE + FPU_XCPT_SIZE)
#endif

#ifdef CONFIG_ARCH_RV_ISA_V
# define REG_VSTART_NDX (0)
# define REG_VTYPE_NDX (1)
# define REG_VL_NDX (2)
# define REG_VCSR_NDX (3)
# define REG_VLENB_NDX (4)

# define VPU_XCPT_REGS (5)
# define VPU_XCPT_SIZE (INT_REG_SIZE * VPU_XCPT_REGS)

# if CONFIG_ARCH_RV_VECTOR_BYTE_LENGTH > 0

/* There are 32 vector registers(v0 - v31) with vlenb length. */

# define VPU_XCPTC_SIZE (CONFIG_ARCH_RV_VECTOR_BYTE_LENGTH * 32 + VPU_XCPT_SIZE)

# endif
#else /* !CONFIG_ARCH_RV_ISA_V */
# define VPU_XCPT_REGS (0)
# define VPU_XCPT_SIZE (0)
# define VPU_XCPTC_SIZE (0)
#endif /* CONFIG_ARCH_RV_ISA_V */

/* In assembly language, values have to be referenced as byte address
* offsets. But in C, it is more convenient to reference registers as
* register save table offsets.
Expand Down Expand Up @@ -333,6 +356,14 @@
# define REG_FCSR (INT_REG_SIZE*REG_FCSR_NDX)
#endif

#ifdef CONFIG_ARCH_RV_ISA_V
# define REG_VSTART (INT_REG_SIZE*REG_VSTART_NDX)
# define REG_VTYPE (INT_REG_SIZE*REG_VTYPE_NDX)
# define REG_VL (INT_REG_SIZE*REG_VL_NDX)
# define REG_VCSR (INT_REG_SIZE*REG_VCSR_NDX)
# define REG_VLENB (INT_REG_SIZE*REG_VLENB_NDX)
#endif

#else
# define REG_EPC REG_EPC_NDX
# define REG_X1 REG_X1_NDX
Expand Down Expand Up @@ -404,6 +435,14 @@
# define REG_FCSR REG_FCSR_NDX
#endif

#ifdef CONFIG_ARCH_RV_ISA_V
# define REG_VSTART REG_VSTART_NDX
# define REG_VTYPE REG_VTYPE_NDX
# define REG_VL REG_VL_NDX
# define REG_VCSR REG_VCSR_NDX
# define REG_VLENB REG_VLENB_NDX
#endif

#endif

/* Now define more user friendly alternative name that can be used either
Expand Down Expand Up @@ -579,6 +618,16 @@ struct xcptcontext
#if defined(CONFIG_ARCH_FPU) && defined(CONFIG_ARCH_LAZYFPU)
uintptr_t fregs[FPU_XCPT_REGS];
#endif

#ifdef CONFIG_ARCH_RV_ISA_V
# if CONFIG_ARCH_RV_VECTOR_BYTE_LENGTH > 0
/* There are 32 vector registers(v0 - v31) with vlenb length. */

uintptr_t vregs[VPU_XCPTC_SIZE];
# else
uintptr_t *vregs;
# endif
#endif
};

#endif /* __ASSEMBLY__ */
Expand Down
4 changes: 4 additions & 0 deletions arch/risc-v/src/common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ if(CONFIG_ARCH_FPU)
list(APPEND SRCS riscv_fpu.S riscv_fpucmp.c)
endif()

if(CONFIG_ARCH_RV_ISA_V)
list(APPEND SRCS riscv_vpu.S)
endif()

if(CONFIG_ARCH_RV_ISA_A)
list(APPEND SRCS riscv_testset.S)
endif()
Expand Down
4 changes: 4 additions & 0 deletions arch/risc-v/src/common/Make.defs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ CMN_ASRCS += riscv_fpu.S
CMN_CSRCS += riscv_fpucmp.c
endif

ifeq ($(CONFIG_ARCH_RV_ISA_V),y)
CMN_ASRCS += riscv_vpu.S
endif

ifeq ($(CONFIG_ARCH_RV_ISA_A),y)
CMN_ASRCS += riscv_testset.S
endif
Expand Down
3 changes: 3 additions & 0 deletions arch/risc-v/src/common/riscv_getnewintctx.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ uintptr_t riscv_get_newintctx(void)
return (status | STATUS_PPP | STATUS_SUM | STATUS_PIE
#ifdef CONFIG_ARCH_FPU
| MSTATUS_FS_INIT
#endif
#ifdef CONFIG_ARCH_RV_ISA_V
| MSTATUS_VS_INIT
#endif
);
}
Expand Down
27 changes: 27 additions & 0 deletions arch/risc-v/src/common/riscv_initialstate.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#include <nuttx/arch.h>
#include <nuttx/tls.h>
#include <nuttx/kmalloc.h>
#include <arch/irq.h>

#include "addrenv.h"
Expand All @@ -56,6 +57,9 @@
void up_initial_state(struct tcb_s *tcb)
{
struct xcptcontext *xcp = &tcb->xcp;
#if defined(CONFIG_ARCH_RV_ISA_V) && (CONFIG_ARCH_RV_VECTOR_BYTE_LENGTH == 0)
uintptr_t *vregs = tcb->vregs;
#endif
uintptr_t regval;
uintptr_t topstack;
#ifdef CONFIG_ARCH_KERNEL_STACK
Expand All @@ -66,6 +70,29 @@ void up_initial_state(struct tcb_s *tcb)

memset(xcp, 0, sizeof(struct xcptcontext));

#if defined(CONFIG_ARCH_RV_ISA_V) && (CONFIG_ARCH_RV_VECTOR_BYTE_LENGTH == 0)

/* Initialize vector registers */

if (vregs == NULL)
{
regval = READ_CSR(CSR_VLENB);
if (regval != 0)
{
/* There are 32 vector registers(v0 - v31) with vlenb length. */

xcp->vregs = kmm_calloc(1, regval * 32 + VPU_XCPT_SIZE);
DEBUGASSERT(xcp->vregs != NULL);
}
}
else
{
/* Keep the vector region if task restart */

xcp->vregs = vregs;
}
#endif

/* Initialize the idle thread stack */

if (tcb->pid == IDLE_PROCESS_ID)
Expand Down
30 changes: 30 additions & 0 deletions arch/risc-v/src/common/riscv_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,24 @@ static inline uintptr_t *riscv_fpuregs(struct tcb_s *tcb)
# define riscv_fpuregs(tcb)
#endif

#ifdef CONFIG_ARCH_RV_ISA_V
void riscv_vpuconfig(void);
void riscv_savevpu(uintptr_t *regs, uintptr_t *vregs);
void riscv_restorevpu(uintptr_t *regs, uintptr_t *vregs);

/* Get VPU register save area */

static inline uintptr_t *riscv_vpuregs(struct tcb_s *tcb)
{
return tcb->xcp.vregs;
}
#else
# define riscv_vpuconfig()
# define riscv_savevpu(regs, vregs)
# define riscv_restorevpu(regs, vregs)
# define riscv_vpuregs(tcb)
#endif

/* Save / restore context of task */

static inline void riscv_savecontext(struct tcb_s *tcb)
Expand All @@ -242,6 +260,12 @@ static inline void riscv_savecontext(struct tcb_s *tcb)

riscv_savefpu(tcb->xcp.regs, riscv_fpuregs(tcb));
#endif

#ifdef CONFIG_ARCH_RV_ISA_V
/* Save current process VPU state to TCB */

riscv_savevpu(tcb->xcp.regs, riscv_vpuregs(tcb));
#endif
}

static inline void riscv_restorecontext(struct tcb_s *tcb)
Expand All @@ -253,6 +277,12 @@ static inline void riscv_restorecontext(struct tcb_s *tcb)

riscv_restorefpu(tcb->xcp.regs, riscv_fpuregs(tcb));
#endif

#ifdef CONFIG_ARCH_RV_ISA_V
/* Restore VPU state for next process */

riscv_restorevpu(tcb->xcp.regs, riscv_vpuregs(tcb));
#endif
}

/* RISC-V PMP Config ********************************************************/
Expand Down
83 changes: 83 additions & 0 deletions arch/risc-v/src/common/riscv_macros.S
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,48 @@

.endm

/****************************************************************************
* Name: riscv_savevpu
*
* Parameter:
* in - Pointer to where the save is performed (e.g. sp)
*
* Description:
* Save the VPU context registers (i.e. work / temp / etc).
*
****************************************************************************/

.macro riscv_savevpu in

/* Store all vector registers */

mv t1, \in

csrr t0, CSR_VSTART
REGSTORE t0, REG_VSTART(t1)
csrr t0, CSR_VTYPE
REGSTORE t0, REG_VTYPE(t1)
csrr t0, CSR_VL
REGSTORE t0, REG_VL(t1)
csrr t0, CSR_VCSR
REGSTORE t0, REG_VCSR(t1)
csrr t0, CSR_VLENB
REGSTORE t0, REG_VLENB(t1)

addi t1, t1, VPU_XCPT_SIZE

vsetvli t2, x0, e8, m8, ta, ma

vse8.v v0, (t1)
add t1, t1, t2
vse8.v v8, (t1)
add t1, t1, t2
vse8.v v16, (t1)
add t1, t1, t2
vse8.v v24, (t1)

.endm

/****************************************************************************
* Name: load_ctx
*
Expand Down Expand Up @@ -243,6 +285,47 @@

.endm

/****************************************************************************
* Name: riscv_loadvpu
*
* Parameter:
* out - Pointer to where the load is performed (e.g. sp)
*
* Description:
* Load the VPU context registers (i.e. work / temp / etc).
*
****************************************************************************/

.macro riscv_loadvpu out

/* Load all vector registers */

mv t0, \out
addi t1, t0, VPU_XCPT_SIZE

vsetvli t2, x0, e8, m8, ta, ma

vle8.v v0, (t1)
add t1, t1, t2
vle8.v v8, (t1)
add t1, t1, t2
vle8.v v16, (t1)
add t1, t1, t2
vle8.v v24, (t1)

mv t1, t0

REGLOAD t0, REG_VTYPE(t1)
REGLOAD t3, REG_VL(t1)
vsetvl x0, t3, t0

REGLOAD t0, REG_VSTART(t1)
csrw CSR_VSTART, t0
REGLOAD t0, REG_VCSR(t1)
csrw CSR_VCSR, t0

.endm

/****************************************************************************
* Name: setintstack
*
Expand Down
9 changes: 9 additions & 0 deletions arch/risc-v/src/common/riscv_releasestack.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,13 @@ void up_release_stack(struct tcb_s *dtcb, uint8_t ttype)
dtcb->stack_alloc_ptr = NULL;
dtcb->stack_base_ptr = NULL;
dtcb->adj_stack_size = 0;

/* Release vector register context */

#if defined(CONFIG_ARCH_RV_ISA_V) && (CONFIG_ARCH_RV_VECTOR_BYTE_LENGTH == 0)
if (dtcb->xcp.vregs != NULL)
{
kmm_free(dtcb->xcp.vregs);
}
#endif
}
Loading

0 comments on commit 28044f7

Please sign in to comment.