include/tcg/tcg-gvec-desc.h | 7 ++++-- target/riscv/cpu.c | 12 +++++----- target/riscv/cpu.h | 2 +- target/riscv/insn_trans/trans_rvv.c.inc | 3 ++- target/riscv/tcg/tcg-cpu.c | 4 +++- target/riscv/vector_helper.c | 30 ++++++++++++++++--------- 6 files changed, 36 insertions(+), 22 deletions(-)
The RISC-V V(ector) extension specification allows VLEN up to 65536 bits
(vlenb = 8192 bytes).
3 changes are needed to support this:
1. Widen simd_desc SIMD_MAXSZ_BITS from 8 to 10, raising the maxsz
encoding limit from 2048 to 8200 bytes. This costs 2 data bits
(22 to 20).
2. Raise RV_VLEN_MAX from 1024 to 65536. This increases the static
per-CPU vector register file from 4 KB to 256 KB.
3. Widen the vlen CPU property from uint16 to uint32 so that
vlen=65536 can be specified on the command line.
To ensure TCG emits instructions correctly, we, clamp the vl_eq_vlmax TB flag
so it is never set when the total register group size (vlmax << vsew)
exceeds the simd_desc maxsz limit. This forces the helper-based path for
very large register groups (e.g., VLEN=32768 with LMUL=4), preventing the
GVEC fast path from silently truncating the operation and zeroing tail
registers.
We also need to fix probe_pages() so that vector ld/st works due to larger
vector register sizes in regards of how many memory pages they span. This
enables larger memory operations to succeed since address calculations can
now properly span more than 2 pages.
To finish off, we add an additional check on trans_rvv.c.inc to properly
decide when to use the helper function or not; this ensures that we never
hit:
./build/qemu-riscv64: ../accel/tcg/translate-all.c:356: tb_gen_code: Assertion `max_insns > 1' failed;
On high VLEN configurations due to the amount of ld/st it generates (Where TCG
tries to halve the amount of emitted instructions so the generated machine code
fits on the buffer but fails to do so when a single vector load/store opcode fills
the entire buffer (Or overruns it...!).
Signed-off-by: joel.bueno <joel.bueno@openchip.com>
---
* Fix vext_ldst_us emitter. Wasn't able to trigger the wrong functionality from
within qemu-user but qemu-system with 16k VLEN crashed when context switching.
include/tcg/tcg-gvec-desc.h | 7 ++++--
target/riscv/cpu.c | 12 +++++-----
target/riscv/cpu.h | 2 +-
target/riscv/insn_trans/trans_rvv.c.inc | 3 ++-
target/riscv/tcg/tcg-cpu.c | 4 +++-
target/riscv/vector_helper.c | 30 ++++++++++++++++---------
6 files changed, 36 insertions(+), 22 deletions(-)
diff --git a/include/tcg/tcg-gvec-desc.h b/include/tcg/tcg-gvec-desc.h
index 704bd86454..6c277fedad 100644
--- a/include/tcg/tcg-gvec-desc.h
+++ b/include/tcg/tcg-gvec-desc.h
@@ -21,7 +21,7 @@
#define TCG_TCG_GVEC_DESC_H
/*
- * This configuration allows MAXSZ to represent 2048 bytes, and
+ * This configuration allows MAXSZ to represent up to 8200 bytes, and
* OPRSZ to match MAXSZ, or represent the smaller values 8, 16, or 32.
*
* Encode this with:
@@ -29,9 +29,12 @@
* 2 -> maxsz
*
* This steals the input that would otherwise map to 24 to match maxsz.
+ *
+ * MAXSZ uses 10 bits to support RISC-V VLEN up to 65536 bits
+ * (vlenb = 8192 bytes). This leaves 20 DATA bits (was 22).
*/
#define SIMD_MAXSZ_SHIFT 0
-#define SIMD_MAXSZ_BITS 8
+#define SIMD_MAXSZ_BITS 10
#define SIMD_OPRSZ_SHIFT (SIMD_MAXSZ_SHIFT + SIMD_MAXSZ_BITS)
#define SIMD_OPRSZ_BITS 2
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index fa497e5e8a..b5c2139810 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1637,10 +1637,10 @@ static void prop_vlen_set(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
RISCVCPU *cpu = RISCV_CPU(obj);
- uint16_t cpu_vlen = cpu->cfg.vlenb << 3;
- uint16_t value;
+ uint32_t cpu_vlen = cpu->cfg.vlenb << 3;
+ uint32_t value;
- if (!visit_type_uint16(v, name, &value, errp)) {
+ if (!visit_type_uint32(v, name, &value, errp)) {
return;
}
@@ -1663,13 +1663,13 @@ static void prop_vlen_set(Object *obj, Visitor *v, const char *name,
static void prop_vlen_get(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- uint16_t value = RISCV_CPU(obj)->cfg.vlenb << 3;
+ uint32_t value = RISCV_CPU(obj)->cfg.vlenb << 3;
- visit_type_uint16(v, name, &value, errp);
+ visit_type_uint32(v, name, &value, errp);
}
static const PropertyInfo prop_vlen = {
- .type = "uint16",
+ .type = "uint32",
.description = "vlen",
.get = prop_vlen_get,
.set = prop_vlen_set,
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 7582874c35..5796aaf04b 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -186,7 +186,7 @@ extern RISCVCPUImpliedExtsRule *riscv_multi_ext_implied_rules[];
#include "pmp.h"
#endif
-#define RV_VLEN_MAX 1024
+#define RV_VLEN_MAX 65536
#define RV_MAX_MHPMEVENTS 32
#define RV_MAX_MHPMCOUNTERS 32
#define RV_MAX_TRIGGERS 2
diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc
index 23262b1d03..f34fea3407 100644
--- a/target/riscv/insn_trans/trans_rvv.c.inc
+++ b/target/riscv/insn_trans/trans_rvv.c.inc
@@ -1190,9 +1190,10 @@ static bool ldst_whole_trans(uint32_t vd, uint32_t rs1, uint32_t nf,
* Update vstart with the number of processed elements.
* Use the helper function if either:
* - vstart is not 0.
+ * - total transfer size potentially exceeding emittable buffer length.
*/
- bool use_helper_fn = !s->vstart_eq_zero;
+ bool use_helper_fn = !s->vstart_eq_zero || ((s->cfg_ptr->vlenb * nf) > 512);
if (!use_helper_fn) {
uint32_t size = s->cfg_ptr->vlenb * nf;
diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index b73e3e9dd4..021f9c60bd 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -33,6 +33,7 @@
#include "accel/accel-cpu-target.h"
#include "accel/tcg/cpu-ops.h"
#include "tcg/tcg.h"
+#include "tcg/tcg-gvec-desc.h"
#ifndef CONFIG_USER_ONLY
#include "hw/core/boards.h"
#include "system/tcg.h"
@@ -125,7 +126,8 @@ static TCGTBCPUState riscv_get_tb_cpu_state(CPUState *cs)
uint32_t vlmax = vext_get_vlmax(cpu->cfg.vlenb, vsew, lmul);
uint32_t maxsz = vlmax << vsew;
bool vl_eq_vlmax = (env->vstart == 0) && (vlmax == env->vl) &&
- (maxsz >= 8);
+ (maxsz >= 8) &&
+ (maxsz <= (8 << SIMD_MAXSZ_BITS));
flags = FIELD_DP32(flags, TB_FLAGS, VILL, env->vill);
flags = FIELD_DP32(flags, TB_FLAGS, SEW, vsew);
flags = FIELD_DP32(flags, TB_FLAGS, LMUL,
diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c
index e321ca2616..1254a7b9c4 100644
--- a/target/riscv/vector_helper.c
+++ b/target/riscv/vector_helper.c
@@ -176,13 +176,15 @@ static void probe_pages(CPURISCVState *env, target_ulong addr, target_ulong len,
mmu_index, ra);
}
- if (len > curlen) {
+ while (len > curlen) {
addr += curlen;
- curlen = len - curlen;
+ len -= curlen;
+ curlen = MIN(-(addr | TARGET_PAGE_MASK), len);
if (flags != NULL) {
+ void *page_host;
*flags |= probe_access_flags(env, adjust_addr(env, addr), curlen,
access_type, mmu_index, nonfault,
- host, ra);
+ &page_host, ra);
} else {
probe_access(env, adjust_addr(env, addr), curlen, access_type,
mmu_index, ra);
@@ -480,8 +482,8 @@ vext_ldst_us(void *vd, target_ulong base, CPURISCVState *env, uint32_t desc,
}
/* Load/store elements in the second page */
- if (unlikely(env->vstart < evl)) {
- /* Cross page element */
+ while (unlikely(env->vstart < evl)) {
+ /* Element crossing the page boundary */
if (unlikely(page_split % msize)) {
for (k = 0; k < nf; k++) {
addr = base + ((env->vstart * nf + k) << log2_esz);
@@ -489,15 +491,21 @@ vext_ldst_us(void *vd, target_ulong base, CPURISCVState *env, uint32_t desc,
env->vstart + k * max_elems, vd, ra);
}
env->vstart++;
+ if (env->vstart >= evl) {
+ break;
+ }
}
addr = base + ((env->vstart * nf) << log2_esz);
- /* Get number of elements of second page */
- elems = evl - env->vstart;
-
- /* Load/store elements in the second page */
- vext_page_ldst_us(env, vd, addr, elems, nf, max_elems, log2_esz,
- is_load, mmu_index, ldst_tlb, ldst_host, ra);
+ page_split = -(addr | TARGET_PAGE_MASK);
+ elems = page_split / msize;
+ if (env->vstart + elems >= evl) {
+ elems = evl - env->vstart;
+ }
+ if (likely(elems)) {
+ vext_page_ldst_us(env, vd, addr, elems, nf, max_elems, log2_esz,
+ is_load, mmu_index, ldst_tlb, ldst_host, ra);
+ }
}
env->vstart = 0;
--
2.43.0
© 2016 - 2026 Red Hat, Inc.