arch/risc-v: add support of save/restore vector registers
Reference: https://github.com/riscv/riscv-v-spec/blob/master/v-spec.adoc https://github.com/torvalds/linux/blob/master/arch/riscv/include/asm/vector.h Signed-off-by: chao an <anchao@lixiang.com>
This commit is contained in:
parent
c093514cea
commit
28044f7d5a
@ -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
|
||||
|
@ -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.
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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__ */
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
);
|
||||
}
|
||||
|
@ -30,6 +30,7 @@
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/tls.h>
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <arch/irq.h>
|
||||
|
||||
#include "addrenv.h"
|
||||
@ -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
|
||||
@ -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)
|
||||
|
@ -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)
|
||||
@ -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)
|
||||
@ -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 ********************************************************/
|
||||
|
@ -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
|
||||
*
|
||||
@ -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
|
||||
*
|
||||
|
@ -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
|
||||
}
|
||||
|
156
arch/risc-v/src/common/riscv_vpu.S
Normal file
156
arch/risc-v/src/common/riscv_vpu.S
Normal file
@ -0,0 +1,156 @@
|
||||
/****************************************************************************
|
||||
* arch/risc-v/src/common/riscv_vpu.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/arch.h>
|
||||
#include <arch/csr.h>
|
||||
#include <arch/irq.h>
|
||||
#include <arch/mode.h>
|
||||
|
||||
#include "riscv_macros.S"
|
||||
|
||||
#ifdef CONFIG_ARCH_RV_ISA_V
|
||||
|
||||
/****************************************************************************
|
||||
* Public Symbols
|
||||
****************************************************************************/
|
||||
|
||||
.globl riscv_vpuconfig
|
||||
.globl riscv_savevpu
|
||||
.globl riscv_restorevpu
|
||||
.file "riscv_vpu.S"
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: riscv_vpuconfig
|
||||
*
|
||||
* Description:
|
||||
* init vpu
|
||||
*
|
||||
* C Function Prototype:
|
||||
* void riscv_vpuconfig(void);
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
* Returned Value:
|
||||
* This function does not return anything explicitly.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
.type riscv_vpuconfig, function
|
||||
|
||||
riscv_vpuconfig:
|
||||
li a0, MSTATUS_VS_INIT
|
||||
csrs CSR_STATUS, a0
|
||||
|
||||
fence.i
|
||||
ret
|
||||
|
||||
/****************************************************************************
|
||||
* Name: riscv_savevpu
|
||||
*
|
||||
* Description:
|
||||
* Given the pointer to a register save area (in A0), save the state of the
|
||||
* floating point registers.
|
||||
*
|
||||
* C Function Prototype:
|
||||
* void riscv_savevpu(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_savevpu, function
|
||||
|
||||
riscv_savevpu:
|
||||
|
||||
REGLOAD t0, REG_INT_CTX(a0)
|
||||
li t1, MSTATUS_VS
|
||||
and t2, t0, t1
|
||||
li t1, MSTATUS_VS_DIRTY
|
||||
#ifdef CONFIG_ARCH_LAZYVPU
|
||||
bne t2, t1, 1f
|
||||
#else
|
||||
blt t2, t1, 1f
|
||||
#endif
|
||||
li t1, ~MSTATUS_VS
|
||||
and t0, t0, t1
|
||||
li t1, MSTATUS_VS_CLEAN
|
||||
or t0, t0, t1
|
||||
REGSTORE t0, REG_INT_CTX(a0)
|
||||
|
||||
riscv_savevpu a1
|
||||
|
||||
1:
|
||||
ret
|
||||
|
||||
/****************************************************************************
|
||||
* Name: riscv_restorevpu
|
||||
*
|
||||
* Description:
|
||||
* Given the pointer to a register save area (in A0), restore the state of
|
||||
* the floating point registers.
|
||||
*
|
||||
* C Function Prototype:
|
||||
* void riscv_restorevpu(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_restorevpu, function
|
||||
|
||||
riscv_restorevpu:
|
||||
|
||||
REGLOAD t0, REG_INT_CTX(a0)
|
||||
li t1, MSTATUS_VS
|
||||
and t2, t0, t1
|
||||
li t1, MSTATUS_VS_INIT
|
||||
ble t2, t1, 1f
|
||||
|
||||
riscv_loadvpu a1
|
||||
|
||||
1:
|
||||
ret
|
||||
|
||||
#endif /* CONFIG_ARCH_RV_ISA_V */
|
@ -35,4 +35,9 @@ config ARCH_CHIP_QEMU_RV_ISA_C
|
||||
default n
|
||||
select ARCH_RV_ISA_C
|
||||
|
||||
config ARCH_CHIP_QEMU_RV_ISA_V
|
||||
bool "Standard Extension for Vector Instructions"
|
||||
default n
|
||||
select ARCH_RV_ISA_V
|
||||
|
||||
endif
|
||||
|
@ -43,6 +43,7 @@ CONFIG_ARCH_CHIP_QEMU_RV=y
|
||||
CONFIG_ARCH_CHIP_QEMU_RV_ISA_A=y
|
||||
CONFIG_ARCH_CHIP_QEMU_RV_ISA_C=y
|
||||
CONFIG_ARCH_CHIP_QEMU_RV_ISA_M=y
|
||||
CONFIG_ARCH_CHIP_QEMU_RV_ISA_V=y
|
||||
CONFIG_ARCH_INTERRUPTSTACK=2048
|
||||
CONFIG_ARCH_RISCV=y
|
||||
CONFIG_ARCH_STACKDUMP=y
|
||||
|
Loading…
x
Reference in New Issue
Block a user