summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPiyush Patle <[email protected]>2026-10-14 06:43:49 +0530
committerGitHub <[email protected]>2026-10-14 09:13:49 +0800
commitf9436bb5bdabb9670792b22f79467b0ef16bff47 (patch)
tree909f5655d07898cdce5b07e17903c92b9408eb31
parent270a18d29239b92f21b4c8c0ac18d3a89e660da9 (diff)
[risc-v][vector] Restore vstart after vector configuration
-rw-r--r--bsp/qemu-virt64-riscv/.ci/attachconfig/ci.attachconfig.yml20
-rw-r--r--bsp/qemu-virt64-riscv/SConstruct3
-rw-r--r--bsp/qemu-virt64-riscv/applications/test/test_vector/SConscript7
-rw-r--r--bsp/qemu-virt64-riscv/applications/test/test_vector/test_vector.c4
-rw-r--r--bsp/qemu-virt64-riscv/applications/test/test_vector/vector_context_gcc.S43
-rw-r--r--bsp/qemu-virt64-riscv/applications/utest/SConscript10
-rw-r--r--bsp/qemu-virt64-riscv/applications/utest/rvv_vstart_probe_gcc.S46
-rw-r--r--bsp/qemu-virt64-riscv/applications/utest/rvv_vstart_tc.c121
-rw-r--r--libcpu/risc-v/vector/rvv-1.0/rvv_context.h16
9 files changed, 262 insertions, 8 deletions
diff --git a/bsp/qemu-virt64-riscv/.ci/attachconfig/ci.attachconfig.yml b/bsp/qemu-virt64-riscv/.ci/attachconfig/ci.attachconfig.yml
new file mode 100644
index 0000000000..9385b3498f
--- /dev/null
+++ b/bsp/qemu-virt64-riscv/.ci/attachconfig/ci.attachconfig.yml
@@ -0,0 +1,20 @@
+utest.rvv.vlen128:
+ scons_arg:
+ - '--strict'
+ kconfig:
+ - CONFIG_ENABLE_VECTOR=y
+ - CONFIG_RT_USING_HEAP=y
+ - CONFIG_RT_USING_UTEST=y
+ - CONFIG_ARCH_VECTOR_VLEN_128=y
+ - CONFIG_ARCH_VECTOR_VLEN_256=n
+ - CONFIG_RT_USING_SMP=n
+utest.rvv.vlen256:
+ scons_arg:
+ - '--strict'
+ kconfig:
+ - CONFIG_ENABLE_VECTOR=y
+ - CONFIG_RT_USING_HEAP=y
+ - CONFIG_RT_USING_UTEST=y
+ - CONFIG_ARCH_VECTOR_VLEN_128=n
+ - CONFIG_ARCH_VECTOR_VLEN_256=y
+ - CONFIG_RT_USING_SMP=n
diff --git a/bsp/qemu-virt64-riscv/SConstruct b/bsp/qemu-virt64-riscv/SConstruct
index ae0e3375e1..06d2a468df 100644
--- a/bsp/qemu-virt64-riscv/SConstruct
+++ b/bsp/qemu-virt64-riscv/SConstruct
@@ -27,6 +27,9 @@ rtconfig.ARCH='risc-v'
# prepare building environment
objs = PrepareBuilding(env, RTT_ROOT, has_libcpu = False)
+if GetDepend('ENABLE_VECTOR'):
+ env['ASFLAGS'] = str(env['ASFLAGS']).replace('-march=rv64imafdc ', '-march=rv64imafdcv ')
+
stack_size = 4096
if GetDepend('RT_USING_SMART'):
diff --git a/bsp/qemu-virt64-riscv/applications/test/test_vector/SConscript b/bsp/qemu-virt64-riscv/applications/test/test_vector/SConscript
index 0827b048b2..0a287adadb 100644
--- a/bsp/qemu-virt64-riscv/applications/test/test_vector/SConscript
+++ b/bsp/qemu-virt64-riscv/applications/test/test_vector/SConscript
@@ -3,7 +3,12 @@ from building import *
cwd = GetCurrentDir()
src = Glob('*.c') + Glob('*.cpp')
CPPPATH = [cwd]
+LOCAL_CCFLAGS = ''
-group = DefineGroup('Vector', src, depend = [''], CPPPATH = CPPPATH)
+if GetDepend(['RT_USING_UTEST', 'ENABLE_VECTOR']):
+ src += ['vector_context_gcc.S']
+ LOCAL_CCFLAGS = ' -march=rv64gcv'
+
+group = DefineGroup('Vector', src, depend = [''], CPPPATH = CPPPATH, LOCAL_CCFLAGS = LOCAL_CCFLAGS)
Return('group')
diff --git a/bsp/qemu-virt64-riscv/applications/test/test_vector/test_vector.c b/bsp/qemu-virt64-riscv/applications/test/test_vector/test_vector.c
index 50aae80248..b84e1c42b3 100644
--- a/bsp/qemu-virt64-riscv/applications/test/test_vector/test_vector.c
+++ b/bsp/qemu-virt64-riscv/applications/test/test_vector/test_vector.c
@@ -55,8 +55,8 @@ static void test_feature(void)
* not modified by each other
* ==============================================================
*/
-#define TEST_THREAD 2
-#define VECTOR_CTX_BYTES (CTX_VECTOR_REG_NR * REGBYTES)
+#define TEST_THREAD 2
+#define VECTOR_CTX_BYTES (CTX_VECTOR_REG_NR * sizeof(rt_ubase_t))
void *ctx_vector[TEST_THREAD * 2];
static rt_sem_t sem;
diff --git a/bsp/qemu-virt64-riscv/applications/test/test_vector/vector_context_gcc.S b/bsp/qemu-virt64-riscv/applications/test/test_vector/vector_context_gcc.S
new file mode 100644
index 0000000000..42e60f323d
--- /dev/null
+++ b/bsp/qemu-virt64-riscv/applications/test/test_vector/vector_context_gcc.S
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef __ASSEMBLY__
+#define __ASSEMBLY__
+#endif
+#define REGBYTES 8
+#define STORE sd
+#define LOAD ld
+
+#include <rtconfig.h>
+#include "vector_encoding.h"
+#include "rvv_context.h"
+
+ .text
+ .align 2
+
+ /* Test-only helpers; SAVE_VECTOR must not change the caller's controls. */
+ .globl rt_hw_vector_ctx_save
+ .type rt_hw_vector_ctx_save, @function
+rt_hw_vector_ctx_save:
+ csrrci a3, sstatus, 2
+ li t0, SSTATUS_VS
+ csrs sstatus, t0
+ SAVE_VECTOR a0
+ RESTORE_VECTOR a0
+ csrw sstatus, a3
+ ret
+ .size rt_hw_vector_ctx_save, . - rt_hw_vector_ctx_save
+
+ .globl rt_hw_vector_ctx_restore
+ .type rt_hw_vector_ctx_restore, @function
+rt_hw_vector_ctx_restore:
+ csrrci a3, sstatus, 2
+ li t0, SSTATUS_VS
+ csrs sstatus, t0
+ RESTORE_VECTOR a0
+ csrw sstatus, a3
+ ret
+ .size rt_hw_vector_ctx_restore, . - rt_hw_vector_ctx_restore
diff --git a/bsp/qemu-virt64-riscv/applications/utest/SConscript b/bsp/qemu-virt64-riscv/applications/utest/SConscript
new file mode 100644
index 0000000000..8e56d71ed7
--- /dev/null
+++ b/bsp/qemu-virt64-riscv/applications/utest/SConscript
@@ -0,0 +1,10 @@
+from building import *
+
+cwd = GetCurrentDir()
+src = ['rvv_vstart_tc.c', 'rvv_vstart_probe_gcc.S']
+
+group = DefineGroup('RVV utestcases', src,
+ depend = ['RT_USING_UTEST', 'ENABLE_VECTOR', 'RT_USING_HEAP'],
+ CPPPATH = [cwd])
+
+Return('group')
diff --git a/bsp/qemu-virt64-riscv/applications/utest/rvv_vstart_probe_gcc.S b/bsp/qemu-virt64-riscv/applications/utest/rvv_vstart_probe_gcc.S
new file mode 100644
index 0000000000..e02cbaf393
--- /dev/null
+++ b/bsp/qemu-virt64-riscv/applications/utest/rvv_vstart_probe_gcc.S
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2026-10-10 Piyush Patle Add RVV restore regression probe
+ */
+
+#ifndef __ASSEMBLY__
+#define __ASSEMBLY__
+#endif
+#define REGBYTES 8
+#define STORE sd
+#define LOAD ld
+
+#include <rtconfig.h>
+#include "vector_encoding.h"
+#include "rvv_context.h"
+
+ .text
+ .align 2
+ .option push
+ .option arch, +v
+
+ /* a0: expected frame, a1: observed frame, a2: caller's vector frame. */
+ .globl rvv_vstart_probe
+ .type rvv_vstart_probe, @function
+rvv_vstart_probe:
+ /* Keep interrupts masked until the caller's complete state is restored. */
+ csrrci a3, sstatus, 2
+ li t0, SSTATUS_VS
+ csrs sstatus, t0
+ SAVE_VECTOR a2
+
+ RESTORE_VECTOR a0
+ /* SAVE_VECTOR records vstart before issuing any vector instruction. */
+ SAVE_VECTOR a1
+
+ RESTORE_VECTOR a2
+ csrw sstatus, a3
+ ret
+ .size rvv_vstart_probe, . - rvv_vstart_probe
+
+ .option pop
diff --git a/bsp/qemu-virt64-riscv/applications/utest/rvv_vstart_tc.c b/bsp/qemu-virt64-riscv/applications/utest/rvv_vstart_tc.c
new file mode 100644
index 0000000000..1377644718
--- /dev/null
+++ b/bsp/qemu-virt64-riscv/applications/utest/rvv_vstart_tc.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2026-10-10 Piyush Patle Test zero and nonzero RVV restart indices
+ */
+
+#include <rtthread.h>
+
+/* Run with: utest_run testcases.libcpu.rvv_vstart */
+#if defined(ENABLE_VECTOR) && defined(RT_USING_HEAP) && defined(RT_USING_UTEST)
+#include "rvv_context.h"
+
+/* RV64 vector frames contain four control words followed by v0 through v31. */
+#define VECTOR_CONTROL_WORDS 4
+#define VECTOR_GUARD 0x5a5a5a5aUL
+
+struct vector_test_frame
+{
+ rt_ubase_t before[2];
+ rt_ubase_t image[CTX_VECTOR_REG_NR];
+ rt_ubase_t after[2];
+};
+
+void rvv_vstart_probe(const rt_ubase_t *input, rt_ubase_t *output, rt_ubase_t *backup);
+
+static void frame_init(struct vector_test_frame *frame)
+{
+ rt_memset(frame, 0, sizeof(*frame));
+ frame->before[0] = frame->before[1] = VECTOR_GUARD;
+ frame->after[0] = frame->after[1] = VECTOR_GUARD;
+}
+
+static rt_bool_t frame_guards_valid(const struct vector_test_frame *frame)
+{
+ return frame->before[0] == VECTOR_GUARD && frame->before[1] == VECTOR_GUARD &&
+ frame->after[0] == VECTOR_GUARD && frame->after[1] == VECTOR_GUARD;
+}
+
+static int rvv_vstart_test(void)
+{
+ rt_ubase_t vlenb;
+ rt_ubase_t starts[3];
+ struct vector_test_frame *frames;
+ struct vector_test_frame *expected;
+ struct vector_test_frame *observed;
+ struct vector_test_frame *saved;
+ rt_uint8_t *payload;
+ rt_size_t payload_size = sizeof(expected->image) - VECTOR_CONTROL_WORDS * sizeof(rt_ubase_t);
+ rt_size_t i;
+ rt_size_t j;
+
+ __asm__ volatile("csrr %0, vlenb" : "=r"(vlenb));
+ if (payload_size != 32 * vlenb)
+ {
+ rt_kprintf("RVV test: configured frame does not match vlenb=%lu\n", vlenb);
+ return -RT_ERROR;
+ }
+
+ /* Each invocation owns its frames, including the caller-state backup. */
+ frames = rt_malloc(3 * sizeof(*frames));
+ if (frames == RT_NULL)
+ {
+ return -RT_ENOMEM;
+ }
+ expected = &frames[0];
+ observed = &frames[1];
+ saved = &frames[2];
+ payload = (rt_uint8_t *)&expected->image[VECTOR_CONTROL_WORDS];
+ frame_init(expected);
+ for (i = 0; i < payload_size; i++)
+ {
+ payload[i] = (rt_uint8_t)(i * 37 + i / vlenb + 0x5a);
+ }
+
+ starts[0] = 0;
+ starts[1] = 1;
+ starts[2] = vlenb - 1;
+
+ for (i = 0; i < sizeof(starts) / sizeof(starts[0]); i++)
+ {
+ for (j = 0; j < 3; j++)
+ {
+ expected->image[0] = starts[i];
+ expected->image[1] = 0; /* e8, m1, tail/mask undisturbed */
+ expected->image[2] = vlenb;
+ expected->image[3] = j * 3; /* Exercise vxrm and vxsat through vcsr. */
+ frame_init(observed);
+ frame_init(saved);
+
+ rvv_vstart_probe(expected->image, observed->image, saved->image);
+
+ if (!frame_guards_valid(expected) || !frame_guards_valid(observed) ||
+ !frame_guards_valid(saved) ||
+ rt_memcmp(expected->image, observed->image, sizeof(expected->image)) != 0)
+ {
+ rt_kprintf("RVV restore failed: vstart expected=%lu observed=%lu\n",
+ starts[i], observed->image[0]);
+ rt_free(frames);
+ return -RT_ERROR;
+ }
+ }
+ }
+
+ rt_free(frames);
+ rt_kprintf("RVV restore passed: vlenb=%lu, 9 control/register checks\n", vlenb);
+ return RT_EOK;
+}
+
+#include <utest.h>
+
+static void testcase(void)
+{
+ uassert_int_equal(rvv_vstart_test(), RT_EOK);
+}
+
+UTEST_TC_EXPORT(testcase, "testcases.libcpu.rvv_vstart", RT_NULL, RT_NULL, 10);
+#endif
diff --git a/libcpu/risc-v/vector/rvv-1.0/rvv_context.h b/libcpu/risc-v/vector/rvv-1.0/rvv_context.h
index 4466b3aeff..f5ec4d4ae8 100644
--- a/libcpu/risc-v/vector/rvv-1.0/rvv_context.h
+++ b/libcpu/risc-v/vector/rvv-1.0/rvv_context.h
@@ -12,17 +12,20 @@
#define __RVV_CONTEXT_1_0_H__
#if defined(ARCH_VECTOR_VLEN_128)
- #define CTX_VECTOR_REGS 64
+#define CTX_VECTOR_REGS 64
#elif defined(ARCH_VECTOR_VLEN_256)
- #define CTX_VECTOR_REGS 128
+#define CTX_VECTOR_REGS 128
#else
#error "No supported VLEN"
#endif /* VLEN */
-#define CTX_VECTOR_REG_NR (CTX_VECTOR_REGS + 4)
+#define CTX_VECTOR_REG_NR (CTX_VECTOR_REGS + 4)
#ifdef __ASSEMBLY__
+/* The following macros contain assembler, not C. */
+/* clang-format off */
+
/**
* ==================================
* VECTOR EXTENSION
@@ -97,16 +100,19 @@
mv t1, t0
- LOAD t0, VEC_FRAME_VSTART(t1)
- csrw vstart, t0
LOAD t0, VEC_FRAME_VCSR(t1)
csrw vcsr, t0
LOAD t0, VEC_FRAME_VTYPE(t1)
LOAD t3, VEC_FRAME_VL(t1)
VEC_CONFIG_SET_VL_VTYPE(t3, t0)
+
+ /* vsetvl resets vstart, so restore the restart index last. */
+ LOAD t0, VEC_FRAME_VSTART(t1)
+ csrw vstart, t0
.endm
+/* clang-format on */
#endif
#endif /* __RVV_CONTEXT_H__ */